diff --git a/README.md b/README.md index 7bdf6c4a..9fb2e151 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ The MiniMax Code Agent communicates through the host MCP client. Business reques | MiniApp | What it does | Author | | --- | --- | --- | +| [MiniMax Photo](plugins/webguhui/minimax-photo/) | Layered image editing with an in-app AI assistant, local recovery and programmatic editing tools | [WebGuHui](https://github.com/WebGuHui) | | [AI Office](plugins/cristinamadureira353-svg/ai-office/) | Manage five model-powered employees in a pixel office: client tasks, chats, breaks, meetings and quota-aware offline states; uses your own API keys | [最爱双皮奶](https://github.com/cristinamadureira353-svg) | | [Token Usage Board](plugins/amszuidas/mcode-token-usage-board/) | Explore local Token usage by date, model, and session, including input, output, and cache usage | [amszuidas](https://github.com/amszuidas) | | [Token Usage Board](plugins/yanhy2000/mcode-usage-monitor/) | Watch local Token usage, output speed, and cache hit rate in near real time; filter by time range, model, and session | [yanhy2000](https://github.com/yanhy2000) | diff --git a/README.zh-CN.md b/README.zh-CN.md index dd0c744f..3338cfd1 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -62,6 +62,7 @@ MiniMax Code Agent 通过宿主 MCP 客户端与 MiniApp 协作。业务请求 | MiniApp | 功能 | 作者 | | --- | --- | --- | +| [MiniMax Photo](plugins/webguhui/minimax-photo/) | 图层图片编辑、应用内 AI 助手、本地恢复与程序化编辑工具 | [WebGuHui](https://github.com/WebGuHui) | | [AI 事务所](plugins/cristinamadureira353-svg/ai-office/README.zh-CN.md) | 五位真实模型员工的像素事务所:接单、聊天、休息和开会,额度耗尽时角色暂停;使用玩家自己的 API Key | [最爱双皮奶](https://github.com/cristinamadureira353-svg) | | [Token 用量看板](plugins/amszuidas/mcode-token-usage-board/README.zh-CN.md) | 按时间、模型和会话查看本机 Token 用量,包含输入、输出和缓存用量 | [amszuidas](https://github.com/amszuidas) | | [Token 用量看板](plugins/yanhy2000/mcode-usage-monitor/README.zh-CN.md) | 近实时查看本机 Token 用量、输出速度与缓存命中率,可按时间范围、模型和会话筛选 | [yanhy2000](https://github.com/yanhy2000) | diff --git a/plugins/webguhui/minimax-photo/.gitattributes b/plugins/webguhui/minimax-photo/.gitattributes new file mode 100644 index 00000000..1ac2886f --- /dev/null +++ b/plugins/webguhui/minimax-photo/.gitattributes @@ -0,0 +1,2 @@ +# Unified patches contain single-space context lines for blank source lines. +docs/photocraft/*.patch whitespace=-blank-at-eol diff --git a/plugins/webguhui/minimax-photo/.gitignore b/plugins/webguhui/minimax-photo/.gitignore new file mode 100644 index 00000000..6cb98d96 --- /dev/null +++ b/plugins/webguhui/minimax-photo/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +releases/ +__pycache__/ +*.log +evidence/ diff --git a/plugins/webguhui/minimax-photo/.minimax-plugin/plugin.json b/plugins/webguhui/minimax-photo/.minimax-plugin/plugin.json new file mode 100644 index 00000000..6a57553f --- /dev/null +++ b/plugins/webguhui/minimax-photo/.minimax-plugin/plugin.json @@ -0,0 +1,20 @@ +{ + "schemaVersion": 1, + "name": "minimax-photo", + "displayName": "MiniMax Photo", + "version": "0.2.35", + "description": "本地图像编辑、图层、选区、调色与工程管理。", + "author": "WebGuHui", + "icon": "icon.png", + "category": "Design & Sites", + "exampleQueries": [ + "打开 MiniMax Photo,编辑一张图片" + ], + "apps": [], + "mcpServers": [ + "servers.mcp.json" + ], + "skills": [ + "skills/minimax-photo/SKILL.md" + ] +} diff --git a/plugins/webguhui/minimax-photo/LICENSE b/plugins/webguhui/minimax-photo/LICENSE new file mode 100644 index 00000000..cf0a2a0e --- /dev/null +++ b/plugins/webguhui/minimax-photo/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 WebGuHui and MiniMax Photo contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/plugins/webguhui/minimax-photo/README.md b/plugins/webguhui/minimax-photo/README.md new file mode 100644 index 00000000..458a5986 --- /dev/null +++ b/plugins/webguhui/minimax-photo/README.md @@ -0,0 +1,76 @@ +# MiniMax Photo + +[简体中文](README.zh-CN.md) + +An image-editing MiniApp for MiniMax Code. Edit layers, selections and colors yourself, or ask the in-app assistant to inspect the canvas, perform reversible edits and generate images with the tools available in your Host. + +The main editor is an adapted [PhotoCraft](https://github.com/storytold/photocraft) WebAssembly build. The MiniApp adds onboarding examples, a movable and collapsible assistant, recovery snapshots, image-result handling and programmatic tool composition. It does not bundle Electron, model weights or API keys. This is a community project, not an Adobe product or an official MiniMax app. + +![MiniMax Photo welcome page with generated example images](docs/preview.png) + +## Features + +- Layered editing with import, undo/redo, project saving and flattened PNG export. +- Three bundled AI-generated examples: product photography, portrait and coffee poster. +- In-app Agent chat with tool progress, permission prompts, cancellation, retained drafts and conversation continuation. +- MCP tools for image requests, canvas inspection, editor commands and programmatic composition in an isolated QuickJS worker. See [tool guide](docs/agent-tools.zh-CN.md). +- Local recovery of the active artwork and assistant state. +- Simplified Chinese, Traditional Chinese, English and Japanese in the main interface and help. The optional legacy editor remains Chinese. + +## Install and open + +Requires MiniMax Code **3.1.2 or later**. Copy this entire directory, including `.minimax-plugin`, to `/plugins/minimax-photo/` while the client is closed. The default data directory is `~/.minimax`; use your configured directory if different. Do not copy the `webguhui` author directory. Restart the client, enable the plugin and ask it to open **MiniMax Photo**. + +No dependency installation or compilation is needed to use the committed runtime files. The GitHub plugin-import flow does not install these MiniApp packages; follow the repository's manual installation instructions. + +Open an image or example, edit it, then use **More → Save project** to retain layers, or **Export PNG** for a flattened image. The `.pcraft` project format is inherited from PhotoCraft. Open the AI assistant and send a request inside the app. Generated results open as new artworks; they do not replace the original automatically. + +When updating, save important projects, stop active AI work and close the client before replacing the complete plugin directory. This public `minimax-photo` package is a separate installation from the development `retouch-lab` package: it does not migrate that package's private state. Saved `.pcraft` and legacy `.retouch.json` files remain supported. Uninstalling the plugin may leave its Host-managed private data behind. + +The bundled [editing skill](skills/minimax-photo/SKILL.md) guides command discovery, batched edits, preview checks and recovery. It uses task-dependent strategies rather than subject-specific drawing templates. + +## Tested environment + +Tested on macOS Apple Silicon in MiniMax Code, initially with client **3.1.3-preview.4675**. Package **0.2.35** was installed on 2026-10-20; all 98 installed files matched the release. The runtime ZIP is **14,263,623 bytes**, without Electron or model weights. + +- A single in-app request generated an image, returned it automatically and opened it as a new artwork. Semantic image editing also has a successful native Host test. +- Layered project reopening, recovery, four-language help, examples, draft retention and assistant collapse were exercised. Version-specific evidence is in [validation notes](docs/validation.md). +- A 4000×3000 canvas completed 100 strokes, one-stroke undo and PNG export. One export took about 1.33 seconds; drawing included display delays, so this is not a rendering benchmark or competitor comparison. +- In 0.2.34, AI opened a layered PSD through `editor_open_file`, preserving editable text and a vector shape. Invalid pixel coordinates were rejected without changing the document. +- In 0.2.31, unsupported export paths fail before a job is queued; valid exports return usable PNG paths. Package, PTC, drawing and all 69 community checks pass. + +One historical open failure required a restart; its cause is unresolved. Natural-language tasks can still misuse tools and are not guaranteed to finish autonomously. The latest single-request reference sketch on 0.2.34 took 15 minutes 45 seconds; eye details and shading still need improvement. The 0.2.35 Skill changes have not yet been measured for drawing speed. Windows, stable-client compatibility, complex PSD fidelity and every editor command have not been fully tested. This is not a claim of Photoshop parity or better performance than PhotoCraft. + +## Data & access + +The editor_open_file tool reads an explicitly supplied local PNG/JPEG/WebP/PSD/pcraft file (up to 32 MB), checks its header, and sends a private copy to the connected editor as a new document. It does not scan directories or modify the original file. The task payload is stored under the plugin data directory; tool replies omit the file bytes. + +- The Node service binds only to the Host-provided loopback address. It reads bundled assets from the plugin directory and stores projects, recovery snapshots, assistant drafts/replies/session IDs, image requests/results, editor jobs and exports under opaque `context.dataDir` paths. It does not read Host configuration, credentials or conversation databases. +- Images selected through file inputs are read in the page. Save/export uses the browser download dialog. The backend can read a PNG path supplied to `submit_image_result`; this is a privileged Agent tool, not an arbitrary-file HTTP endpoint. The Agent may write generated files into its working directory before returning them. +- This package declares `agentAccess: ["session.run"]`. Sending a request runs a Host Agent that can access files, shell and MCP tools under Host permissions. Requests include the user's instructions and current artwork context; image tasks may include a reference image. Model/provider traffic is handled by the Host and its selected tools, not by an embedded API key. +- The MiniApp backend makes no direct external service requests. Provider destinations depend on the Host's enabled services; there is no fixed provider-host list in this package. The app does not automatically approve permission requests. +- PTC uses a Node worker thread with a QuickJS VM and a bounded editing API. It has no direct filesystem or network API. The MiniApp itself starts no shell subprocess; Host Agent tools may do so after a user request. +- Browser storage holds language/window preferences. Domain state is stored in the Node private directory. Recovery checks only the active document every few seconds and does not replace saving a project. Avoid editing the same assistant conversation in two windows; stale writes are rejected. +- Recovery and generated files are retained locally with no automatic retention cleanup. Back up important projects independently. A stopped or unknown-result request is not automatically resent. + +![MiniMax Photo editor showing a generated product photograph](docs/editor.png) + +## Development + +See [build instructions](docs/build.md), [user guide](docs/user-guide.zh-CN.md) and [validation notes](docs/validation.md). A normal browser preview supports editing but cannot run Host Agent tasks. + +## License and attribution + +Original MiniApp code is MIT licensed; see [LICENSE](LICENSE). PhotoCraft is MIT OR Apache-2.0 and retains its own credits. Its pinned source and our patch are documented in [build instructions](docs/build.md). Third-party fonts, icons, UI dependencies and QuickJS retain their licenses in [licenses/](licenses/). The example images were generated with Codex's image-generation tool, not supplied by PhotoCraft or Adobe. They are illustrative single-layer images, not editable design templates. No proprietary RetouchPi source or assets are included. + +AI edits show a short completion replay: brush paths and their bounding area, or a canvas highlight for other edits. Toggle it in More → Show AI edit activity. This is a visual overlay after an edit succeeds, not an animated mouse or incremental pixel execution; it does not enter exports or undo history. + +### Visible drawing + +PTC `await editor.draw({strokes, intervalMs:550})` draws an array of `paint.stroke` parameters in order (1–96 strokes, 100–600 ms between strokes). Every stroke updates the real canvas and has its own undo step. Failures preserve completed strokes. `editor.edit` continues to commit atomically. The bundled Skill covers reference composition and tonal drawing. + +Strokes also accept absolute SVG-style path command arrays (`M`, `L`, `Q`, `C`, `Z`), sampled by the tool. This avoids repeatedly implementing curve interpolation in Agent scripts. + +### Canvas recording + +More → Record drawing process records the editor's own canvas at up to 20 fps, including its editor controls, without desktop capture permissions or other windows. Stop recording, then use More → Save recording to download a WebM video. The recording stays in memory so a cancelled save can be retried; clear the buffer after saving to begin another recording. Closing/reloading the app loses unsaved video and prompts before leaving. Recording stops at 60 minutes or 256 MiB. Browser background throttling can reduce frame rate. It records actual rendered changes; it does not reconstruct missed strokes or turn atomic edits into animation. diff --git a/plugins/webguhui/minimax-photo/README.zh-CN.md b/plugins/webguhui/minimax-photo/README.zh-CN.md new file mode 100644 index 00000000..214e9d1d --- /dev/null +++ b/plugins/webguhui/minimax-photo/README.zh-CN.md @@ -0,0 +1,55 @@ +# MiniMax Photo + +[English](README.md) + +运行在 MiniMax Code 中的图片编辑器。你可以手动编辑图层、选区和颜色,也可以直接在应用里的 AI 助手输入需求,让 Agent 读图、改图或调用宿主提供的生图工具。 + +编辑器基于开源 PhotoCraft 的 WebAssembly 版本,增加了示例引导、可拖动和收起的助手、作品恢复、图片回传,以及程序化组合调用。没有打包 Electron、模型权重或 API 密钥。这是社区作品,不是 Adobe 产品,也不是 MiniMax 官方应用。 + +![MiniMax Photo welcome page with generated example images](docs/preview.png) + +附带 [图片编辑 Skill](skills/minimax-photo/SKILL.md),指导 Agent 按需发现命令、组合批量编辑、检查预览和从失败处继续。策略不绑定特定题材,用户可以直接附图描述需求。 + +## 安装与使用 + +需要 MiniMax Code 3.1.2 或更新版本。退出客户端,将本目录完整复制到 `/plugins/minimax-photo/`,保留隐藏的 `.minimax-plugin` 目录;默认 `` 为 `~/.minimax`。不要多套一层 `webguhui` 目录。重启并启用插件,向 Agent 说“打开 MiniMax Photo”。无需安装 npm 依赖。客户端的 GitHub 插件导入不支持此类包,请按社区仓库的手动安装流程操作。 + +打开图片或示例后即可编辑。“更多 → 保存工程”保留图层,“导出 PNG”保存合并图片。AI 返回的图片会作为新作品打开。工程格式 `.pcraft` 来自 PhotoCraft。 + +开源版使用新插件 ID `minimax-photo`,与开发版 `retouch-lab` 分开安装,不自动迁移旧版的内部备份和 AI 对话。已有 `.pcraft` 和旧版 `.retouch.json` 文件仍可打开。升级前先保存工程、停止 AI 并退出客户端,再替换完整插件目录。 + +## 已验证环境 + +在 macOS Apple Silicon 的 MiniMax Code 中验收,初始客户端版本为 3.1.3-preview.4675。当前包 **0.2.35** 已于 2026-10-20 实际安装,98 个文件与发布包一致,运行 ZIP **14,263,623 字节**,不含 Electron 或模型权重。 + +- 应用内一句需求完成文生图、自动回传和新画布打开;语义改图也已有真实宿主成功记录。 +- 旧版分层工程重开与自动保存恢复、四语言帮助、示例打开、草稿保留和助手收起已验证;不同项目与版本详见 [验收说明](docs/validation.md)。 +- 4000×3000 画布完成 100 笔、单笔撤销和 PNG 导出。单次导出约 1.33 秒;绘制包含展示间隔,不作为纯渲染或竞品性能结论。 +- 0.2.34 AI 通过文件导入工具打开分层 PSD,可编辑文字与矢量形状保留;无效取色坐标明确拒绝,文档版本不变。 +- 0.2.31 错误导出路径参数会在入队前被拒绝;正常导出返回可用 PNG 路径。打包、PTC、逐笔与社区 69 项检查通过。 + +仍存在一次历史打开失败后需重启恢复的记录,根因未确认。自然语言任务可能出现工具误用,不能保证每次都自主完成;最近一次 0.2.34 附图素描单轮耗时 15 分 45 秒,眼睛和排线仍需改善;0.2.35 Skill 修订的提速效果尚未验证。Windows、稳定客户端、复杂 PSD 和全部编辑命令未全面验证,不声称完整兼容 Photoshop 或性能全面超过 PhotoCraft。 + +## 数据与权限 + +`editor_open_file` 读取明确提供的本机 PNG/JPEG/WebP/PSD/pcraft 文件(最多 32 MB),检查文件头后交给编辑器作为新文档打开。不扫描目录、不修改原文件。任务内容保存在插件数据目录,工具回复不含文件字节。 + +应用在宿主分配的本机端口运行,工程备份、草稿、回复、会话编号、图片和编辑任务存入宿主提供的 `context.dataDir`。不读取宿主配置、密钥或会话数据库。选择文件在页面中完成,保存使用下载对话框。图片回传 MCP 工具可读取 Agent 指定的 PNG 路径;不是任意文件下载接口。 + +发送需求会运行宿主 Agent,它可以按宿主权限使用文件、Shell 和 MCP;需求和参考图片可能交给用户配置的模型服务。应用不自带密钥,不自动批准权限。后台不直接请求外部服务,也不自行启动 Shell 子进程;Agent 工具可能执行这些操作。PTC 运行于独立 QuickJS 工作线程,仅暴露编辑 API。 + +自动备份只覆盖当前活动作品,存在几秒间隔;不要替代手动保存。不要同时在两个窗口修改同一 AI 会话,过期写入会被拒绝。本地备份和生成文件暂不自动清理;卸载插件后宿主私有数据可能仍然保留。 + +## 文档与许可 + +[用户手册](docs/user-guide.zh-CN.md) · [构建说明](docs/build.md) · [Agent 工具](docs/agent-tools.zh-CN.md) + +新增 MiniApp 代码采用 MIT;PhotoCraft、字体、图标和 QuickJS 的原许可证保留在 `licenses/`。展示图片由 Codex 生图工具制作,是单层示例图片。没有包含修图派的专有源码或素材。 + +AI 编辑成功后会短暂回放画笔轨迹和范围框;其他修改显示画布高亮。可在“更多 → 显示 AI 操作轨迹”关闭。提示层不进入图片导出或撤销记录;这是操作完成后的回放,不是逐像素执行动画。 + +### 逐笔绘制 + +PTC 的 `await editor.draw({strokes, intervalMs:550})` 按顺序绘制 `paint.stroke` 参数数组(1–96 笔,间隔 100–600 ms)。每笔真实更新画布并单独撤销;失败时保留已完成笔触。`editor.edit` 仍是整批提交。素描构图和明暗指导见插件 Skill。 + +笔触支持 SVG 风格的绝对路径命令数组(`M`、`L`、`Q`、`C`、`Z`),由工具采样曲线,避免 Agent 反复编写插值算法。 diff --git a/plugins/webguhui/minimax-photo/docs/agent-tools.zh-CN.md b/plugins/webguhui/minimax-photo/docs/agent-tools.zh-CN.md new file mode 100644 index 00000000..8d487808 --- /dev/null +++ b/plugins/webguhui/minimax-photo/docs/agent-tools.zh-CN.md @@ -0,0 +1,77 @@ +# Agent 工具与组合调用 + +应用提供 13 个 MCP 工具。主编辑器为 PhotoCraft WASM;旧版轻量工作台仍可从“打开旧版工程”进入。两者的命令结构不同,不要把旧版操作名称直接传给 PhotoCraft。 + +## 用户入口 + +在右下角助手输入需求并发送,直接运行宿主 Agent,无需复制到主聊天。权限和补充问题由用户回答。助手可停止、收起或新建对话;生成图片回传后可打开为新作品。页面必须保持打开,当前没有脱离页面的后台渲染器。 + +## 工具目录 + +| 工具 | 用途 | +| --- | --- | +| `editor_list` | 列出已连接页面及工程,明确目标 editorId | +| `editor_inspect` | 读取页面最后报告的文档、图层和版本 | +| `editor_capabilities` | 获取旧版轻量工作台的操作目录 | +| `photo_call` | 查询 PhotoCraft 命令,执行单步或批次,预览和导出 | +| `editor_preview` | 旧版轻量工作台预览;主编辑器用 photo_call preview | +| `editor_create` | 旧版轻量工作台新建;主编辑器用 PTC editor.create | +| `editor_batch` | 旧版轻量工作台的结构化批量编辑 | +| `editor_export` | 旧版轻量工作台导出;主编辑器用 photo_call export | +| `editor_job` | 查询任务状态与返回文件 | +| `editor_run_code` | 提交 QuickJS 组合脚本 | +| `editor_code_result` | 查询脚本结果和逐步记录 | +| `get_image_request` | 读取生成/修改图片需求及参考 PNG | +| `submit_image_result` | 将真实图片工具生成的本机 PNG 回传 | + +先使用 `editor_list` 和 `editor_inspect`,然后使用 `photo_call` 的 `commands` 方法查询实际命令和参数,再调用 `execute` 或 `batch`。`photo_call` 支持 `commands`、`execute`、`batch`、`preview`、`export`。不要猜命令名称;返回任务编号后必须查询 `editor_job`,只有 `succeeded` 表示页面已确认。 + +## 程序化组合(PTC) + +`editor_run_code({editorId, expectedVersion, requestId, code})` 返回 runId。脚本在包内 QuickJS 中运行,支持变量、函数、循环、条件、await 和顶层 return。工具必须逐个 await。 + +```js +const before = await editor.inspect(); +const commands = await editor.commands({filter: 'blackWhite'}); +return {before, commands}; +``` + +可调用 `editor.inspect()`、`capabilities()`、`commands({filter})`、`execute({command,params})`、`edit([{command,params}])`、`draw({strokes,intervalMs})`、`preview(options)`、`create({width,height,name})`、`export({format})`。PhotoCraft 使用其真实命令;旧版的 `edit` 使用 `{op,...}` 操作,示例见 `examples/ptc-script.js`。 + +每次最多 32 KB 代码、32 MB VM 堆、64 次工具调用和 120 秒。没有 Node、文件或网络 API。QuickJS 位于 Node worker thread,库的 stdout/stderr 被单独接收,不写入宿主协议输出。语义识图由 Agent 查看 MCP 图片完成,脚本不会自己调用模型。 + +每批编辑可以整体撤销;整个脚本不是一个事务,后面的失败不会撤销前面已成功的步骤。用 `editor_code_result` 查看逐步记录,再查询相应 `editor_job`。在结果未知、超时或断线后不要直接重放。 + +## 一致性和边界 + +写操作携带 editorId、expectedVersion 和新的 UUID requestId。旧版本被拒绝;同一请求重复提交返回已有任务,不重复修改;不同内容不能复用编号。PhotoCraft 在页面应用后持久化回执,因此可能出现“已应用但尚未确认”。服务不会自动重放中断任务。 + +PhotoCraft 的批量操作在独立文档副本执行,成功后提交一次历史记录;并非所有引擎命令都允许进入批次。旧版轻量工作台先持久化检查点再让页面应用;其 `.retouch.json` 检查点可在旧版打开。主编辑器保存 `.pcraft`。 + +`sdk/editor.mjs` 和 `examples/compose-edit.mjs` 提供传输无关的旧版组合调用示例;实际 MCP 传输由调用者提供,不假设宿主有某个全局 PTC 对象。 + +工具存在不代表所有命令和模型理解都经过验证。编辑后查看预览;重要作品先保存工程。记录和结果暂不自动清理,长期运行会占用本地磁盘。 + +## 逐笔绘制和参考图 + +`await editor.draw({strokes, intervalMs:550})` 顺序执行 1–96 笔,每笔真实更新画布且可以单独撤销。每笔可以使用点数组或绝对路径命令 M/L/Q/C/Z;同段脚本内可循环分组,但总耗时仍须小于 120 秒。整笔 `pressure:0..1` 对路径和点数组均生效;逐点压力优先,未指定时保留引擎默认值,不改变倾角、旋转等扩展采样字段。绘画展示建议间隔 500–600 ms。`editor.edit` 的批量提交不等于逐笔绘制。 + +Skill 附带通用参考图轮廓脚本,适合边界清楚的插画和标志,需要 Python 3 与 Pillow,由 Agent 按需调用。它不识别语义,不自带图片模型,也不适合直接提取照片的所有色块。参见 [参考图轮廓转笔触](../skills/minimax-photo/references/reference-tracing.md)。 + +PTC 支持 `console.log/info/warn/error/debug`,结果中最多保留 50 条、总计 10000 字符的日志。日志不是任务成功证明;仍应查询运行结果并查看预览。 + + +### 压力笔刷参数(0.2.24 宿主实测) + +压力不一定改变笔宽,取决于笔刷设置。使用内置 `Hard Round Pressure Size` 或明确启用 `brush.shapeDynamics.enabled=true`、`brush.shapeDynamics.size.control="penPressure"`;线性 curve `[[0,0],[1,1]]`、minimum 为 0 时,30px 笔刷的压力 0.2 对应约 6px,压力 1 对应 30px。`transfer.opacity.control="penPressure"` 控制的是不透明度,不是笔宽。可通过 `brush.presets.list` 的 `full:true` 获取完整预设,在 PTC 内筛选所需预设再返回,避免整份结果被截断。 + + +### 多会话编辑器识别 + +先在当前会话打开插件 ID `minimax-photo`,再读取当前 MiniApp 页面 `html` 的 `data-photo-editor-id`,与 `editor_list` 的 ID 精确匹配。页面会报告 `page.visibility`(visible/hidden/unknown)和 `page.focused`(布尔或 null);旧页面不报告时返回 unknown/null。这两个值只作提示,不是会话归属或访问权限证明。工具不会自动选择最新、首个或可见实例。任务运行中的可见状态更新不会覆盖任务持有的文档版本。 + +## 打开本机文件 + +`editor_open_file({editorId,expectedVersion,requestId,filePath})` 读取已知附件或导出文件路径,将 PNG/JPEG/WebP/PSD/pcraft(最多 32 MB)作为新文档打开。使用 editor_job 等待完成,再 inspect 核对尺寸和图层。旧文档保留;无需在上下文传 base64,也不通过 Web 引擎的 file.openAs 访问本机路径。原文件不修改,工具结果省略文件字节。 + +`execute`/`batch` 的 params 必须是 JSON 对象。`document.pixel` 的 x、y 必须明确传入 32 位整数;字符串、小数、缺失坐标和越界值在任务入队前拒绝,不再落到默认的 (0,0) 像素。该检查用于取色命令,不表示所有引擎命令参数均有完整类型校验。 diff --git a/plugins/webguhui/minimax-photo/docs/build.md b/plugins/webguhui/minimax-photo/docs/build.md new file mode 100644 index 00000000..2edea005 --- /dev/null +++ b/plugins/webguhui/minimax-photo/docs/build.md @@ -0,0 +1,62 @@ +# 构建 MiniMax Photo + +仓库提交的 `miniapp/client`、`miniapp/node` 已可运行。下面的命令仅供修改源码后重建,不是安装步骤。旧工程格式标识 `retouch-lab` 为内部兼容名称,不是插件 ID。 + +## 前端与 PTC + +在本插件目录运行,需要 Node.js 22+ 和 npm: + +```sh +npm ci --prefix ui-src +node ui-src/build.mjs +npm ci --prefix ptc-src +node ptc-src/build.mjs +node scripts/check.mjs +node scripts/check-ptc.mjs +node scripts/check-recovery.mjs +``` + +React / shadcn 界面源码在 `ui-src/`。输出 `workbench-ui.js` 和 `components.css`。QuickJS 工作线程源码在 `ptc-src/worker.mjs`;构建同时复制对应版本的 WASM。依赖锁文件随源码提供,`node_modules` 不提交。 + +## PhotoCraft 编辑器 + +上游:[storytold/photocraft](https://github.com/storytold/photocraft),固定提交 `5f65579ecb44047c2a619036c18ff273202e1389`。修改源码完整保存在 `photocraft/miniapp.patch`,包括浏览器编辑桥接、欢迎页和标题调整,以及该提交的 `Persisted.export_presets` 初始化修正。第三方来源和许可证位于 `../licenses/`。 + +需要 Rust、`wasm32-unknown-unknown` target、`wasm-bindgen-cli 0.2.129`。把下面两个路径替换为插件与独立构建目录的绝对路径: + +```sh +export PHOTO_PACKAGE=/absolute/path/to/minimax-photo +git clone https://github.com/storytold/photocraft.git /absolute/path/to/photocraft-build +cd /absolute/path/to/photocraft-build +git checkout 5f65579ecb44047c2a619036c18ff273202e1389 +git apply "$PHOTO_PACKAGE/docs/photocraft/miniapp.patch" +rustup target add wasm32-unknown-unknown +cargo build --locked -p photocraft-web --target wasm32-unknown-unknown --profile wasm-release +wasm-bindgen target/wasm32-unknown-unknown/wasm-release/photocraft-web.wasm --target web --out-name photocraft --out-dir "$PHOTO_PACKAGE/miniapp/client/photocraft" +gzip -n -9 -f "$PHOTO_PACKAGE/miniapp/client/photocraft/photocraft_bg.wasm" +``` + +服务端以 `Content-Encoding: gzip` 提供压缩 WASM,避免超过社区单文件 16 MiB 限制。不要把未压缩 WASM 一起提交。无需 Electron、Trunk 或模型权重。此构建未开启 HEIF feature。 + +`frame.js`、`frame.css` 和 `index.html` 是本包维护的页面适配文件,不由 wasm-bindgen 生成。iframe 使用同源资源以支持宿主的本机认证,通过固定方法集合、来源窗口检查和请求标识传递编辑操作;不要将其当作不可信代码的安全隔离边界。PTC 则在单独 QuickJS VM 中执行。 + +`cjk-ui.otf` 是 Noto Sans CJK JP Regular 的 UI 字符子集(SIL OFL 1.1),原字体来自 [noto-cjk](https://github.com/notofonts/noto-cjk)。该文件作为可分发字体资源直接提交;新增 UI 字符时需要用 fonttools `pyftsubset` 重新生成,保留三份 CJK 翻译目录使用的字符、假名和标点。它不是完整的中文排版字体,作品的特殊字形需另行导入对应字体。 + +## 本地预览与打包 + +```sh +node scripts/preview.mjs +python3 scripts/package-preview.py +``` + +预览端口可用 `RETOUCH_PREVIEW_PORT` 设置,预览数据根目录可用 `RETOUCH_DATA_DIR` 设置。普通浏览器没有宿主 Agent API,不会伪造 AI 回复。打包脚本生成运行 ZIP 和独立开发资料 ZIP;生成物不提交仓库。运行包不包含 npm 依赖目录、测试记录或原始重复图片。 + +生成后,在社区仓库根目录运行 `npm run check`,再按官方说明在 MiniMax Code 中手动安装。不能用构建通过代替真实宿主 AI 验收。 + +0.2.15 新增只读 `viewport` 桥接,用编辑器坐标映射显示 AI 操作轨迹。修改引擎后需重新编译 WASM,并同步 `docs/photocraft/miniapp.patch`。轨迹检查:`node scripts/check-activity.mjs`。 + +逐笔显示验证:`node scripts/check-draw.mjs`。`miniapp/client/photocraft/draw.js` 顺序提交真实笔触并让出渲染时间;不修改原有原子批量命令。 + +## 示例图压缩 + +0.2.27 的三张示例图保留 1122×1402 尺寸,使用 WebP 有损编码 quality=90、method=6,总大小由 4,294,712 降为 535,320 字节。它们是教学示例,不是无损原片。后续更换素材请从原始图片重新编码,避免反复压缩已压缩的 WebP;检查人像纹理、海报文字及商品渐变,再检查解码尺寸。 diff --git a/plugins/webguhui/minimax-photo/docs/editor.png b/plugins/webguhui/minimax-photo/docs/editor.png new file mode 100644 index 00000000..844ed366 Binary files /dev/null and b/plugins/webguhui/minimax-photo/docs/editor.png differ diff --git a/plugins/webguhui/minimax-photo/docs/photocraft/miniapp.patch b/plugins/webguhui/minimax-photo/docs/photocraft/miniapp.patch new file mode 100644 index 00000000..826e9cfa --- /dev/null +++ b/plugins/webguhui/minimax-photo/docs/photocraft/miniapp.patch @@ -0,0 +1,328 @@ +diff --git a/Cargo.lock b/Cargo.lock +index 0167dea..213c764 100644 +--- a/Cargo.lock ++++ b/Cargo.lock +@@ -5061,8 +5061,10 @@ dependencies = [ + "js-sys", + "log", + "photocraft-codecs", ++ "photocraft-compose", + "photocraft-doc", + "photocraft-engine", ++ "photocraft-format", + "photocraft-io", + "photocraft-paint", + "photocraft-psd", +diff --git a/apps/photocraft-web/Cargo.toml b/apps/photocraft-web/Cargo.toml +index 786165b..3018c56 100644 +--- a/apps/photocraft-web/Cargo.toml ++++ b/apps/photocraft-web/Cargo.toml +@@ -19,6 +19,10 @@ name = "photocraft-web" + path = "src/main.rs" + + [dependencies] ++serde_json = { workspace = true } ++photocraft-compose = { workspace = true } ++photocraft-format = { workspace = true } ++photocraft-paint = { workspace = true } + photocraft-engine = { workspace = true } + photocraft-io = { workspace = true } + photocraft-codecs = { workspace = true } +diff --git a/apps/photocraft-web/src/main.rs b/apps/photocraft-web/src/main.rs +index 0802a02..dc38fbd 100644 +--- a/apps/photocraft-web/src/main.rs ++++ b/apps/photocraft-web/src/main.rs +@@ -25,6 +25,9 @@ mod indexed_presets; + #[cfg(target_arch = "wasm32")] + mod web; + ++#[cfg(target_arch = "wasm32")] ++mod miniapp; ++ + #[cfg(target_arch = "wasm32")] + fn main() { + web::start(); +diff --git a/apps/photocraft-web/src/miniapp.rs b/apps/photocraft-web/src/miniapp.rs +new file mode 100644 +index 0000000..31c5154 +--- /dev/null ++++ b/apps/photocraft-web/src/miniapp.rs +@@ -0,0 +1,134 @@ ++//! MiniMax Photo browser adapter. JSON requests are processed on the UI thread. ++use std::cell::RefCell; ++use serde_json::{Value, json}; ++use wasm_bindgen::prelude::*; ++use photocraft_ui_egui::PhotocraftApp; ++struct Request { input: Value, resolve: js_sys::Function, reject: js_sys::Function } ++thread_local! { ++ static QUEUE: RefCell> = const { RefCell::new(Vec::new()) }; ++ static CONTEXT: RefCell> = const { RefCell::new(None) }; ++} ++pub fn init(ctx: egui::Context) { CONTEXT.with(|v| *v.borrow_mut() = Some(ctx)); } ++#[wasm_bindgen] ++pub fn miniapp_call(input: &str) -> Result { ++ if input.len() > 96 * 1024 * 1024 { return Err(JsValue::from_str("request too large")); } ++ let value: Value = serde_json::from_str(input).map_err(|e| JsValue::from_str(&e.to_string()))?; ++ if !CONTEXT.with(|v| v.borrow().is_some()) { return Err(JsValue::from_str("editor not ready")); } ++ if QUEUE.with(|q| q.borrow().len() >= 8) { return Err(JsValue::from_str("editor busy")); } ++ Ok(js_sys::Promise::new(&mut |resolve, reject| { ++ QUEUE.with(|q| q.borrow_mut().push(Request { input: value.clone(), resolve, reject })); ++ CONTEXT.with(|v| { if let Some(ctx) = v.borrow().as_ref() {ctx.request_repaint();} }); ++ })) ++} ++fn inspect(app: &PhotocraftApp) -> Value { ++ let doc = app.session.active(); ++ json!({"version": doc.map(|d| format!("{}:{}",d.doc.id.0,d.revision)).unwrap_or_else(|| "empty".into()), ++ "document":doc.map(photocraft_engine::inspect::document)}) ++} ++fn dispatch(app: &mut PhotocraftApp, input: &Value) -> Result { ++ let method = input.get("method").and_then(Value::as_str).ok_or("missing method")?; ++ let args = input.get("args").cloned().unwrap_or(json!({})); ++ if let Some(expected) = input.get("expectedVersion").and_then(Value::as_str) { ++ if inspect(app).get("version").and_then(Value::as_str) != Some(expected) { return Err("document changed; inspect again".into()); } ++ } ++ match method { ++ "inspect" => Ok(inspect(app)), ++ "viewport" => { ++ let view=photocraft_ui_egui::canvas::ViewXform::active(app).ok_or("no canvas")?; ++ let origin=view.to_screen(0.0,0.0); ++ let x=view.map_vec(egui::vec2(1.0,0.0)); ++ let y=view.map_vec(egui::vec2(0.0,1.0)); ++ let size=CONTEXT.with(|v|v.borrow().as_ref().map(|ctx|ctx.content_rect().size())).ok_or("no viewport")?; ++ Ok(json!({"origin":[origin.x,origin.y],"xAxis":[x.x,x.y],"yAxis":[y.x,y.y], ++ "clip":[view.rect.min.x,view.rect.min.y,view.rect.width(),view.rect.height()], ++ "size":[size.x,size.y]})) ++ }, ++ "font" => { ++ let data=args.get("data").and_then(Value::as_str).ok_or("missing font")?; ++ let bytes=photocraft_paint::tile::b64_decode(data).ok_or("invalid font")?; ++ if bytes.len()>8*1024*1024 {return Err("font too large".into());} ++ CONTEXT.with(|v| { ++ if let Some(ctx)=v.borrow().as_ref() { ++ let families=ctx.fonts(|f|f.definitions().families.keys().cloned().map(|family|egui::epaint::text::InsertFontFamily{family,priority:egui::epaint::text::FontPriority::Lowest}).collect()); ++ ctx.add_font(egui::epaint::text::FontInsert{name:"MiniMax Photo CJK".into(),data:egui::FontData::from_owned(bytes),families}); ++ ctx.request_repaint(); ++ } ++ }); ++ Ok(json!({"loaded":true})) ++ }, ++ "language" => { ++ let code=args.get("code").and_then(Value::as_str).ok_or("missing language")?; ++ if !["en","zh-hans","zh-hant","ja"].contains(&code) {return Err("unsupported language".into());} ++ app.run("prefs.set",json!({"path":"interface.language","value":code}))?; ++ Ok(json!({"language":code})) ++ }, ++ "commands" => Ok(Value::Array(photocraft_engine::commands::command_specs().iter() ++ .filter(|c| args.get("filter").and_then(Value::as_str).map(|f| c.id.to_lowercase().contains(&f.to_lowercase())).unwrap_or(true)) ++ .map(|c| photocraft_engine::commands::list_entry(&app.session,c,app.session.disabled_reason(c.id))).collect())), ++ "batch" => { ++ let steps=args.as_array().ok_or("batch requires an array")?; ++ if steps.is_empty() || steps.len()>64 {return Err("batch requires 1..64 commands".into());} ++ let original=app.session.active().ok_or("no document")?.clone(); ++ let mut staged=photocraft_engine::Session::new(); ++ staged.add_document((*original.doc).clone(),None); ++ *staged.active_mut().unwrap()=original.clone(); ++ staged.tools=app.session.tools.clone(); ++ // Batch commands may only modify this detached document; nested commands use the same gate. ++ staged.authorize=Some(|id,_| { ++ if ["layer.","select.","paint.","filter.","adjust.","image.","transform.","text.","shape.","path.","mask."].iter().any(|p|id.starts_with(p)) { ++ Ok(()) ++ } else {Err(photocraft_engine::EngineError::Other(format!("command {id} is not allowed in a document batch; use execute")))} ++ }); ++ let mut values=Vec::new(); ++ for step in steps { ++ let id=step.get("command").and_then(Value::as_str).ok_or("missing command")?; ++ values.push(staged.execute(id,step.get("params").cloned().unwrap_or(json!({}))).map_err(|e|e.to_string())?); ++ if staged.documents().len()!=1 || staged.active().map(|d|d.doc.id)!=Some(original.doc.id) {return Err("batch cannot switch documents".into());} ++ } ++ let final_doc=staged.active().ok_or("no staged document")?.clone(); ++ app.session.edit("AI batch",|doc,active| { *doc=(*final_doc.doc).clone(); *active=final_doc.active_layer; Ok(()) }).map_err(|e|e.to_string())?; ++ Ok(json!({"value":values,"state":inspect(app)})) ++ }, ++ "execute" => { ++ let id=args.get("command").and_then(Value::as_str).ok_or("missing command")?; ++ // Only engine commands, never browser file pickers or arbitrary UI script actions. ++ if photocraft_engine::commands::find(id).is_none() {return Err("unknown engine command".into());} ++ let result=app.session.execute(id,args.get("params").cloned().unwrap_or(json!({}))).map_err(|e|e.to_string())?; ++ Ok(json!({"value":result,"state":inspect(app)})) ++ }, ++ "preview" | "export" => { ++ let d=app.session.active().ok_or("no document")?; ++ let max=args.get("maxEdge").and_then(Value::as_u64).unwrap_or(1280).clamp(64,2048) as u32; ++ let (bytes,warnings)=if method=="preview" { ++ let img=photocraft_compose::thumbnail(&d.doc,max); ++ let image=photocraft_codecs::Image::from_u8(img.width,img.height,photocraft_codecs::ChannelLayout::Rgba,img.pixels).map_err(|e|e.to_string())?; ++ (photocraft_codecs::encode(&image,photocraft_codecs::Format::Png,&Default::default()).map_err(|e|e.to_string())?,vec![]) ++ } else { ++ let format=args.get("format").and_then(Value::as_str).unwrap_or("png"); ++ if format=="pcraft" {(photocraft_format::save_to_bytes(&d.doc,&Default::default()).map_err(|e|e.to_string())?,vec![])} ++ else {let result=photocraft_io::export(&d.doc,format,&Default::default()).map_err(|e|e.to_string())?;(result.bytes,result.warnings)} ++ }; ++ if bytes.len()>64*1024*1024 {return Err("export exceeds 64 MB".into());} ++ Ok(json!({"data":photocraft_paint::tile::b64_encode(&bytes),"warnings":warnings,"state":inspect(app)})) ++ }, ++ "open" => { ++ let name=args.get("name").and_then(Value::as_str).ok_or("missing file name")?; ++ let data=args.get("data").and_then(Value::as_str).ok_or("missing file data")?; ++ let bytes=photocraft_paint::tile::b64_decode(data).ok_or("invalid base64")?; ++ let (doc,warnings)=if name.ends_with(".pcraft") {(photocraft_format::load_from_bytes(&bytes).map_err(|e|e.to_string())?,vec![])} ++ else {let imported=photocraft_io::import(name,&bytes).map_err(|e|e.to_string())?;(imported.document,imported.warnings)}; ++ app.session.add_document(doc,None); ++ Ok(json!({"warnings":warnings,"state":inspect(app)})) ++ }, ++ _ => Err("unsupported Mini App method".into()), ++ } ++} ++pub fn drain(app: &mut PhotocraftApp) { ++ let pending=QUEUE.with(|q|std::mem::take(&mut *q.borrow_mut())); ++ for request in pending { ++ match dispatch(app,&request.input) { ++ Ok(value)=>{let _=request.resolve.call1(&JsValue::NULL,&JsValue::from_str(&value.to_string()));}, ++ Err(error)=>{let _=request.reject.call1(&JsValue::NULL,&JsValue::from_str(&error));}, ++ } ++ } ++} +diff --git a/apps/photocraft-web/src/web.rs b/apps/photocraft-web/src/web.rs +index eb350d1..17481d7 100644 +--- a/apps/photocraft-web/src/web.rs ++++ b/apps/photocraft-web/src/web.rs +@@ -78,6 +78,7 @@ pub fn start() { + options, + Box::new(move |cc| { + PhotocraftApp::setup_context(&cc.egui_ctx, ThemeKind::Pro); ++ crate::miniapp::init(cc.egui_ctx.clone()); + let inbox: Inbox = Arc::default(); + let served: Served = Arc::default(); + load_font_manifest(served.clone(), cc.egui_ctx.clone()); +@@ -299,6 +300,7 @@ impl eframe::App for WebShell { + } + }); + } ++ crate::miniapp::drain(&mut self.app); + self.serve_fonts(ctx); + self.app.logic(ctx, frame); + self.save_presets(ctx); +@@ -385,8 +387,8 @@ fn services(inbox: Inbox) -> Services { + })), + inbox: Some(inbox), + // Preferences live in the browser's localStorage. +- load_prefs: Some(Box::new(|| local_storage()?.get_item(PREFS_KEY).ok().flatten())), +- save_prefs: Some(Box::new(|text: &str| local_storage().ok_or("no localStorage")?.set_item(PREFS_KEY, text).map_err(|e| format!("{e:?}")))), ++ load_prefs: None, // Mini App iframe has an opaque origin; preferences are session-only. ++ save_prefs: None, + ..Default::default() + } + } +diff --git a/crates/engine/src/presets/mod.rs b/crates/engine/src/presets/mod.rs +index 0369629..81382b4 100644 +--- a/crates/engine/src/presets/mod.rs ++++ b/crates/engine/src/presets/mod.rs +@@ -186,6 +186,7 @@ impl Session { + tool_presets: take(&mut m, "tool_presets"), + documents: take(&mut m, "documents"), + recent_documents: take(&mut m, "recent_documents"), ++ export_presets: take(&mut m, "export_presets"), + custom_shapes: take(&mut m, "custom_shapes"), + layer_defaults: take(&mut m, "layer_defaults"), + swatches: take(&mut m, "swatches"), +diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs +index 914d395..0887f7d 100644 +--- a/crates/ui-egui/src/canvas.rs ++++ b/crates/ui-egui/src/canvas.rs +@@ -2760,7 +2760,7 @@ fn start_screen(app: &mut PhotocraftApp, ui: &mut egui::Ui) { + ui.scope_builder(egui::UiBuilder::new().max_rect(card), |ui| { + ui.vertical_centered(|ui| { + ui.horizontal(|ui| { +- let title = ui.painter().layout_no_wrap(tl!("PhotoCraft").into(), crate::theme::semibold(38.0), t.text); ++ let title = ui.painter().layout_no_wrap("MiniMax Photo".into(), crate::theme::semibold(38.0), t.text); + let by = ui.painter().layout_no_wrap(tl!("open source").into(), egui::FontId::proportional(13.0), t.text_faint); + let total = title.size().x + by.size().x + 10.0; + ui.add_space(((card.width() - total) / 2.0).max(0.0)); +@@ -2796,10 +2796,7 @@ fn start_screen(app: &mut PhotocraftApp, ui: &mut egui::Ui) { + ui.add_space(22.0); + home_recent(app, ui, &recent); + } +- ui.add_space(26.0); +- crate::links::discord_button(app, ui, 190.0); +- ui.add_space(10.0); +- crate::links::link_row(app, ui); ++ + }); + }); + } +diff --git a/crates/ui-egui/src/panels.rs b/crates/ui-egui/src/panels.rs +index 6fc8e2d..4a2424c 100644 +--- a/crates/ui-egui/src/panels.rs ++++ b/crates/ui-egui/src/panels.rs +@@ -602,7 +602,7 @@ pub fn title_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui) { + let max = ui.ctx().input(|i| i.viewport().maximized.unwrap_or(false)); + ui.ctx().send_viewport_cmd(egui::ViewportCommand::Maximized(!max)); + } +- let title = app.session.active().map(|d| format!("{}{}", d.doc.name, if d.is_dirty() { " •" } else { "" })).unwrap_or_else(|| "PhotoCraft".into()); ++ let title = app.session.active().map(|d| format!("{}{}", d.doc.name, if d.is_dirty() { " •" } else { "" })).unwrap_or_else(|| "MiniMax Photo".into()); + // The menus and the far-end controls are laid out first; the title is centred in + // whatever room is left between them (`free`, left to right: menus then controls, or + // controls then menus in a right-to-left UI), shortened or dropped rather than drawn +@@ -695,7 +695,7 @@ pub fn title_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui) { + return; + } + // A right-to-left document name in display order (the OS title keeps the logical text), +- // in a left-to-right line: "— PhotoCraft" stays after the name, at the right. ++ // in a left-to-right line: "— MiniMax Photo" stays after the name, at the right. + let title = crate::bidi_text::visual_ltr(&title).into_owned(); + let font = theme::medium(13.0); + let galley = ui.painter().layout_no_wrap(title.clone(), font.clone(), t.text_dim); +@@ -730,7 +730,7 @@ pub fn system_title_bar(app: &PhotocraftApp) -> bool { + /// marks unsaved changes, like the `•` in the app-drawn title), or just the app name with no + /// document open. + pub fn window_title(app: &PhotocraftApp) -> String { +- app.session.active().map(|d| format!("{}{} \u{2014} PhotoCraft", if d.is_dirty() { "*" } else { "" }, d.doc.name)).unwrap_or_else(|| "PhotoCraft".into()) ++ app.session.active().map(|d| format!("{}{} \u{2014} MiniMax Photo", if d.is_dirty() { "*" } else { "" }, d.doc.name)).unwrap_or_else(|| "MiniMax Photo".into()) + } + + /// Keep the OS window title (and the taskbar / Alt-Tab entry) on the active file. Sends +@@ -805,19 +805,19 @@ mod title_tests { + + #[test] + fn window_title_with_no_document_is_the_app_name() { +- assert_eq!(window_title(&app(true)), "PhotoCraft"); ++ assert_eq!(window_title(&app(true)), "MiniMax Photo"); + } + + #[test] + fn window_title_follows_the_active_file() { + let mut app = app(true); + open_named(&mut app, "foo.psd"); +- assert_eq!(window_title(&app), "foo.psd \u{2014} PhotoCraft"); ++ assert_eq!(window_title(&app), "foo.psd \u{2014} MiniMax Photo"); + // Unsaved changes gain a `*` prefix, like the `•` in the app-drawn title. + if let Some(st) = app.session.active_mut() { + st.revision += 1; + } +- assert_eq!(window_title(&app), "*foo.psd \u{2014} PhotoCraft"); ++ assert_eq!(window_title(&app), "*foo.psd \u{2014} MiniMax Photo"); + } + + #[test] +@@ -855,11 +855,11 @@ mod title_tests { + let ctx = egui::Context::default(); + crate::PhotocraftApp::setup_context(&ctx, crate::theme::ThemeKind::ALL[0]); + super::sync_window_title(&mut app, &ctx); +- assert_eq!(app.last_window_title, "PhotoCraft"); ++ assert_eq!(app.last_window_title, "MiniMax Photo"); + let mut out = ctx.run_ui(egui::RawInput::default(), |_| {}); + out.textures_delta.clear(); + let cmds = out.viewport_output.remove(&egui::ViewportId::ROOT).map(|v| v.commands).unwrap_or_default(); +- assert!(cmds.iter().any(|c| matches!(c, egui::ViewportCommand::Title(t) if t == "PhotoCraft")), "{cmds:?}"); ++ assert!(cmds.iter().any(|c| matches!(c, egui::ViewportCommand::Title(t) if t == "MiniMax Photo")), "{cmds:?}"); + // Same document state again: the cached title stops a repeat command. + super::sync_window_title(&mut app, &ctx); + let mut out = ctx.run_ui(egui::RawInput::default(), |_| {}); +@@ -868,6 +868,6 @@ mod title_tests { + assert!(!cmds.iter().any(|c| matches!(c, egui::ViewportCommand::Title(_))), "repeat Title: {cmds:?}"); + open_named(&mut app, "foo.psd"); + super::sync_window_title(&mut app, &ctx); +- assert_eq!(app.last_window_title, "foo.psd \u{2014} PhotoCraft"); ++ assert_eq!(app.last_window_title, "foo.psd \u{2014} MiniMax Photo"); + } + } diff --git a/plugins/webguhui/minimax-photo/docs/preview.png b/plugins/webguhui/minimax-photo/docs/preview.png new file mode 100644 index 00000000..6aefadec Binary files /dev/null and b/plugins/webguhui/minimax-photo/docs/preview.png differ diff --git a/plugins/webguhui/minimax-photo/docs/user-guide.zh-CN.md b/plugins/webguhui/minimax-photo/docs/user-guide.zh-CN.md new file mode 100644 index 00000000..58ebc97a --- /dev/null +++ b/plugins/webguhui/minimax-photo/docs/user-guide.zh-CN.md @@ -0,0 +1,51 @@ +# MiniMax Photo 用户手册 + +## 开始创作 + +欢迎页可打开图片、新建画布或试用示例作品。商品、肖像和海报示例均可继续编辑。 + +## 保存与恢复 + +“更多 → 保存工程”保留图层,下载的 .pcraft 文件可以再次打开。“导出 PNG”保存合并图片。应用每隔几秒检查当前作品的变化并在本机备份,可从“更多 → 恢复作品”找回。刚完成的修改可能还未备份;关闭前请保存重要作品。 + +## 与 AI 协作 + +打开右下角的 AI 助手,直接输入需求并发送。AI 会按需要读取画面、编辑图层或生成图片。标题栏可以拖动,减号收起面板。窄窗口下显示在底部,不会占用固定侧栏。 + +## 在 MiniMax Code 聊天中使用 + +也可以新建聊天,选择模型,输入 `@` 选择 MiniMax Photo,再附上参考图片。例如:“照这张图画简单的铅笔素描,尽量像原图,逐笔画给我看。”参考图应作为图片附件添加,无需把本机路径写进请求。 + +Agent 会自行打开 Mini App、选择工具、检查画面并做必要修正。一条请求可以包含多次工具调用,不代表一次调用就画完。复杂任务可能需要数分钟;相似度和细节仍需要检查。 + +## 让 AI 打开和检查工程 + +可以说:“打开这份 PSD,检查尺寸和图层。”把文件作为附件提供;如果文件由 AI 刚刚导出,也可以说“重新打开刚才的 PSD”。AI 使用文件导入工具在新文档中打开,保留当前作品。 + +目前 AI 文件导入支持 PNG、JPEG、WebP、PSD 和 .pcraft,单个文件最多 32 MB。更大的文件可尝试编辑器“文件 → 打开”,但仍受设备内存限制。PSD 的复杂效果和特殊字体可能有差异,打开后检查画面;保存重要工程时同时保留原文件。 + +## 查看图片与进度 + +生成的图片显示在“AI 返回的图片”,点击“打开图片”会打开新作品,原作品保留。发送过程中可以停止;需要许可或补充信息时,在面板里操作。读取结果失败时可点击重试。 + +## 继续上次对话 + +草稿和最近回复会自动保存在本机。重新打开后继续使用原会话。标题栏的加号可新建对话,保留尚未发送的草稿。若上次任务结果不确定,请先“查看完整会话”,不要重复发送。请不要同时在两个窗口修改同一份 AI 会话。 + +## 语言与兼容性 + +“更多 → 语言”支持简体中文、繁体中文、English 和日本語。旧 .retouch.json 文件从“打开旧版工程”打开。复杂 PSD、特殊字体和部分滤镜可能与桌面软件有差异;重要作品请检查导出结果。 + +自动备份保存当前活动作品,切换后才会检查其他作品;不代替工程文件备份。AI 生图和改图使用 MiniMax Code 当前可用的模型与权限。 + +## 查看 AI 编辑过程 + +执行时显示处理提示。画笔、铅笔和混色画笔完成后,会短暂回放轨迹并标出路径范围;连续批量笔画最多显示最后 8 条。混合操作的批次仅高亮画布,避免变换后轨迹对不齐。 + +“更多 → 显示 AI 操作轨迹”可以关闭,设置会保留。拖动画布、缩放、键盘操作或下一次编辑会立即收起提示。系统开启减少动态效果时显示静态轨迹。回放不写入作品、不增加撤销步骤;现有撤销仍撤销真实编辑。AI 停止按钮不会强行中断已提交到编辑器的同步命令。 + +## 录制绘画过程 + +在“更多”中选择“录制绘画过程”,顶部出现“停止录制”。结束后,在“更多”中选择“保存录制视频”,得到 WebM 文件。录制范围是编辑器自己的画布(含编辑器工具栏),不包含 MiniMax Code 的聊天和模型回复,也不会拍到桌面或其他窗口,不需要屏幕录制权限。要展示从附图、发送请求到最终回复的整个流程,请在发送前使用外部录屏工具录制 MiniMax Code 窗口;应用内录制无法补回聊天过程。 + +保存窗口取消后可以再次保存;保存完再“清除录制缓存”即可开始下一次录制。未保存视频只在当前页面内存中,刷新或关闭会丢失。达到 60 分钟或 256 MiB 时自动结束,仍可保存。后台窗口可能被浏览器降帧。录制保留真实画面变化,不会把一次提交的整幅图自动变成逐笔动画;让 AI 展示过程时仍需使用逐笔绘制。 diff --git a/plugins/webguhui/minimax-photo/docs/validation.md b/plugins/webguhui/minimax-photo/docs/validation.md new file mode 100644 index 00000000..d3691ed4 --- /dev/null +++ b/plugins/webguhui/minimax-photo/docs/validation.md @@ -0,0 +1,149 @@ +# 验收说明 + +## 已完成的功能验收 + +2026-10-19,macOS Apple Silicon、MiniMax Code 3.1.3-preview.4675,在开发版 0.2.12–0.2.13 中完成: + +- 安装、打开、作品备份和恢复;升级后草稿、最近回复、结果图片保留。 +- AI 添加可撤销黑白调整图层,保留原图;真实模型将示例商品背景改为浅蓝色,回传 PNG 并打开为新作品。 +- 保存 `.pcraft`(ZIP 完整性检查通过),导出 1122 × 1402 PNG(解码检查通过)。 +- 0.2.13 在应用内完成对话、新建对话、停止长文字请求、保留草稿、收起再打开助手。 +- 浏览器检查四语言帮助和窄窗口助手布局。 + +真实模型改图原始输出为 928 × 1152,由 Agent 缩放为 1122 × 1402 后提交,保留生成标识,不代表模型原生支持任意尺寸。 + +## 开源版 + +本次以 `minimax-photo` 作为新插件 ID,界面统一为 MiniMax Photo;对应前端和编辑器 WASM 从源码重建。没有迁移开发安装的数据或真实会话记录。发布目录只保留通用文档、源码和合成示例。 + +运行现有包检查、PTC 检查、恢复存储检查,以及社区仓库 `npm run check`。具体本轮结果以 PR 描述为准。新插件 ID 与开发版分开,原开发版的宿主验收不等于新 ID 在所有客户端都通过。 + +## 未覆盖 + +没有全面验证 Windows、稳定客户端、复杂 PSD、大图性能、所有编辑器命令、所有模型配置,完整聊天演示只验证了 macOS 上的低帧率窗口采集,不代表内置录制支持聊天。自动备份只检查活动作品,几秒内的新修改可能尚未保存;重要作品需手动保存。 + +## 社区静态检查提示 + +`ENTRY_STDOUT` 命中了打包的 QuickJS/Emscripten 库中的默认日志代码。该文件只在 worker thread 中运行;创建线程时启用独立 stdout/stderr 并消费其流,不会写入宿主入口进程的标准输出。结构化错误仍经 worker 消息返回。此提示在 PR 中保留说明,不修改检查器或隐藏第三方代码。 + +本次改名版已完成 React 构建与 PhotoCraft WASM 重编译,并在浏览器打开真实示例画布;标题与作品名称为 MiniMax Photo。预览见 `preview.png` 和 `editor.png`。 + +0.2.14:公开名称改为 MiniMax Photo,插件 ID 改为 `minimax-photo`;前端重新构建,编辑器使用与 MiniMax Photo 源码补丁对应的已构建 WASM,原工程格式不变。 + +## 0.2.15 操作提示 + +浏览器使用真实 WASM 和 MCP 任务链验证画笔画圆、轨迹与范围框、编辑撤销、两笔批量编辑一次撤销,以及关闭轨迹后刷新保留设置。新增坐标测试覆盖旋转映射、无效坐标、长轨迹采样、完整范围和混合批次降级。PTC、恢复存储、包检查与社区检查通过。此次未重新安装到 MiniMax Code,不能将浏览器结果视为新版本宿主或模型验收。 + +## 0.2.21:真实宿主单轮参考绘画 + +2026-10-20,在 macOS 的 MiniMax Code 中安装 `minimax-photo` 0.2.21,使用 M3.1-Flash,新建无项目会话。用户消息包含 MiniMax Photo 引用、一句自然语言绘画要求和实际图片附件,未用本机路径替代附件。 + +- 会话记录确认只有 1 条用户消息;中途没有补充绘画指令、替换模型或更新包。 +- Agent 读取了插件 Skill 和通用轮廓脚本,创建画布、逐笔绘制、分层处理明暗、自行修正右眼和高光,并导出 PNG。 +- 宿主显示总耗时 13 分 30 秒;约 6 分钟才开始落笔。单轮完成已验证,不能宣称速度已优化到位。 +- 结果能够识别参考图,但轮廓偏硬、灰面与排线不够自然,质量仍不如此前人工纠正后的示例。 +- 从请求发送前到最终回复采集整个应用窗口,约 2 fps,工具调用间有少量采集间隔。编辑后的 GIF 为 1600×932、215 秒、约 5.9 MB,压缩等待、保留绘画及 8 秒结尾。完整聊天录制由外部采集完成,不是应用内录制能力。真实会话与窗口录制留在本机,不随公开包发布。 + +本次包为 17,956,523 字节。包检查、PTC、draw 和社区 69 项检查通过;轮廓辅助脚本另检查了随机蒙版、孔洞、闭合性、平滑位置、笔触连续性和画布比例。这些结果不覆盖所有图片类型或模型行为。 + +## 0.2.22:版本报告与文档修正 + +MCP 初始化原先固定返回 0.2.16,现读取当前安装包的插件声明,避免工具报告与实际安装版本不一致。现有初始化检查增加与声明的比对。此修正不改变绘图或会话行为;0.2.21 的单轮录像不作为 0.2.22 的真实宿主验收。 + +2026-10-20:0.2.22 已通过宿主发布并打开欢迎页,editor_list / editor_inspect 确认连接;本次没有绘画或修改已有作品。更新前已保存单轮绘画工程,并检查 ZIP 完整性。 + +0.2.23:应用内四语言帮助页同步附图绘画、逐笔撤销、录制范围和未保存视频的生命周期说明;运行逻辑不变。 + +2026-10-20:0.2.23 已在真实宿主安装并打开。实际切换简中、繁中、英文、日文,新增三段帮助均正常渲染,完成后恢复跟随浏览器。普通浏览器标签无法直接读取受宿主保护的地址;通过 Mini App 内的入口验证正常。 + + +2026-10-20,0.2.24:修复 editor.draw 的 points 模式丢失整笔 pressure。完整包 17,958,892 字节,SHA-256 `94bad29ec302258e8ecc454a1c18e1e269f3b4c6a3832dc965601f3a8116d25b`。打包检查、PTC、逐笔检查和社区 69 项检查通过。已在 MiniMax Code 安装,安装后的 draw-path.js 和 Skill 与包内文件一致。M3.1-Flash 通过真实 PTC 在新建画布绘制三条对照线:整笔压力 0.2 明显较细,整笔 1 与逐点 1 覆盖整笔 0.2 的两条线视觉一致;未修改旧作品。此项验证压力传递,不代表素描质量或全功能验收。 + + +0.2.25 单轮展示复测未通过:真实附图、短 query、M3.1-Flash。约 25 分钟后停止此轮验收。模型先在编辑器外多次准备笔触,之后选中了已有会话的编辑器,当前聊天未自动显示其画布;@ 引用详情还暴露了同名旧插件入口。绘画展开参数又超过单次 65536 字符限制,模型进行了拆批。原始录制保留,但不作为完整绘画 showcase。后续 Skill 已补充准确插件 ID、当前会话编辑器确认、先画轻稿和展开参数大小检查;这些说明尚未重新打包验收。 + + +0.2.26 已安装并在 MiniMax Code 做跨会话只读验收:第一会话页面 ID `35cd3e33-f54c-4789-ab97-b44589376d0c`;第二会话 DOM 的 `data-photo-editor-id` 为 `ac14631e-2150-498f-9450-bd94bab9fad1`,与 editor_list 和 editor_inspect 精确一致。工具列表中两个实例同时在线,旧实例排在首位,且二者均报告 visible;这证实不能用首项或 visibility 推断归属。新实例 focused=true,旧实例 false,仅作为提示。未修改作品。安装后的 client/photo.js、editor-service.mjs、editor-mcp.mjs 与发布包逐字节一致;包 17,960,306 字节。编辑事务与压力/PTC 检查、社区 69 项检查通过。新素描 showcase 仍待重录;不将本项只读验收扩大为全部绘画流程通过。 + + +## 0.2.26:单轮附图绘画与完整窗口录制 + +2026-10-20,在同一 macOS 客户端以 M3.1-Flash 完成复测。会话记录确认只有一条用户消息,包含 MiniMax Photo 引用、实际图片附件和简短绘画需求;没有用路径替代附件,也没有中途补充绘画指令或更新插件。 + +- 首次打开失败,Agent 自行重启插件后恢复;随后当前聊天中正确显示编辑器,绘画过程可见。不能据此声称首次打开稳定性已解决。 +- 实际使用 PTC 分层逐笔绘制轮廓、明暗、瞳孔和高光;自行修正越界瞳孔、纸飞机边缘和两次路径参数错误,最终导出 1000×840 PNG。 +- 宿主显示总耗时 **27 分 25 秒**。约十分钟才出现正式轮廓,准备和反复检查仍过长。单轮完成不等于快速完成。 +- 成品可识别且整体轮廓接近参考图,但右眼角度、瞳孔比例和灰面自然度仍有不足;没有宣称达到此前人工纠正示例的质量。 +- 录制范围包括附图请求、聊天、编辑器画布和最终回复,共采集 1681 帧;工具调用之间存在间隔。成片 1600×932、184.88 秒、7,218,981 字节,缩短等待并保留实际绘画阶段及结尾 8 秒。原始录制和成片只保存在本机,不打入插件。 + +同版前一次测试因本机磁盘耗尽导致宿主会话写入失败,界面仍显示运行;这不是成功的绘画验收,也没有作为完成结果。清理本次构建临时文件后才开始上述复测。 + +本轮证据覆盖真实附图、单次请求、当前编辑器选择、逐笔画布更新及 PNG 导出;不覆盖全部编辑命令、所有模型或跨平台功能。 + + +0.2.26 追加宿主验收:通过“保存工程”下载本轮分层作品,384,417 字节、41 个 ZIP 条目,CRC 完整。应用内助手直接读取当前画布并返回 1000×840 尺寸和 5 个正确图层;无需复制到聊天。模型识别出章鱼,但误称纸飞机为支架,不能将接口成功等同于语义判断正确。收起再打开助手,测试草稿和回复仍保留;测试后清除该测试草稿。 + +0.2.27 仅压缩三张示例 WebP,保持尺寸和示例入口不变。对照检查人像纹理、海报文字与商品渐变;相对旧图 PSNR 为 41.26–41.91 dB,此指标只用于压缩对比,不作为观感保证。本次未重新验证宿主 AI,0.2.26 的结果不冒充新版本完整验收。 + +0.2.27 实际运行 ZIP 为 14,206,899 字节,较 0.2.26 的 17,960,306 字节减少 3,753,407 字节(20.9%)。SHA-256:`a1ee2281000cb8084c6ffec8b05fa1e3461a33ed3cfb77911dd29fb6e10a935a`。打包、PTC 和逐笔检查通过;宿主仍安装 0.2.26,未在已完成的录像中升级。 + +2026-10-20:0.2.27 已通过宿主 publish 更新安装并打开,安装后的 96 个文件与发布包逐字节一致。实际依次打开商品、人像、海报示例,editor_inspect 确认三份文档均为 1122×1402;商品界面的属性栏和状态栏也显示一致尺寸。每次关闭示例均返回欢迎页,最终停在欢迎页,未做生图或改图。此次首次打开成功,不能据一次成功宣布此前偶发打开失败已修复。 + +0.2.27 应用内生图复测发现流程问题:宿主模型成功生成 2048×2048 PNG,但 Agent 未回传图片任务,反而尝试编辑器文件读取和系统剪贴板导入。已停止该次错误流程,不记作应用内生图完成。自动模式指引现明确生成结果必须 submit_image_result,Skill 同步说明结果列表入口及无需剪贴板导入;修改后的真实模型复测仍待完成。 + +0.2.28 已安装,安装文件与发布包一致。应用内真实生图生成 2048×2048 咖啡杯照片,但模型因“不要文字”自行反复处理生成标识,出现处理脚本错误,验收人员停止该轮。补充“保留原图与生成标识,直接回传”后,submit_image_result 返回 ready、2048×2048;应用出现结果缩略图和“打开图片”,点击后画布属性与状态栏均显示 2048×2048。这证明回传与打开链路可用,但不构成首次请求自动完成的验收。 + +0.2.28 语义改图复测通过:应用内新对话发送一次“杯子左侧加草莓、保留原图和生成标识”的需求,自动读取当前图片并调用宿主图生图模型。约 91 秒后 submit_image_result 返回 edit / ready / 2048×2048;结果列表新增缩略图,“打开图片”创建第二个作品标签,原图保留。本机原图 SHA-256 与上轮回传摘要一致。成品视觉上保留杯子、背景、画幅和生成标识,但图生图重新编码或生成影响其他像素,不能宣称局部之外逐像素不变。此轮未补充指令,也未手工导入结果。 + +0.2.29 修复 AI 回复将标题、列表、表格与代码块原样显示的问题,采用 react-markdown + remark-gfm。关闭原始 HTML;不从回复加载图片,图片继续使用结果列表;只允许 HTTP(S) 链接。组件渲染检查覆盖上述格式、脚本标签、危险链接和外部图片;浏览器实际展示标题、表格和列表通过。该浏览器组件检查不是新版宿主验收。 + +0.2.29 运行包 14,259,699 字节,比 0.2.28 增加 52,200 字节;打包、PTC、逐笔与社区 69 项检查通过。新增 Markdown 依赖及传递依赖的许可证保存在 licenses/markdown-dependencies.txt。宿主仍安装 0.2.28,新版原生回复显示待验收。 + +2026-10-20:0.2.29 已在 MiniMax Code 通过成品包流程安装并打开;97 个安装文件与发布包逐字节一致。真实应用内保留的上一轮 AI 回复已渲染为表格、粗体和行内代码,原始 Markdown 标记不再直接展示;无须重新生图。欢迎页正常,图片结果列表仍保留。此项验证安装和回复渲染,不代表此前首次打开偶发问题已修复。 + +0.2.29 工程回归:通过原生文件选择器打开 0.2.26 保存的 .pcraft 工程,画布状态栏为 1000×840;Detail、Shading、Wash、Outline、Background 五个图层及完整素描均可见。再经“更多 → 恢复作品”选中同名自动保存项目,恢复为第二个文档标签,画布和五层结构保持可见。本次未覆盖工程、未绘画;验证的是该工程的跨版本打开和自动保存恢复,不覆盖所有 PSD 或损坏工程。 + +0.2.29 大画布实测:在真实宿主新建 4000×3000 文档(514 ms),分两批各绘制 50 笔(29,140 / 29,468 ms),撤销末笔(314 ms),导出 PNG(1,331 ms);文件头尺寸验证通过。绘制含每笔 550 ms 展示间隔,不能当纯渲染基准。末笔撤销后像素恢复白色、前一笔保留;两个旧文档未修改。仅单次观测,Agent 准备阶段发生参数错误且需一次提醒加载 Skill,不代表无人干预速度或相对 PhotoCraft 的性能优势。 + +0.2.30 调整工具发现指引:入口提示加载现有 Skill,按相关 filter 查询命令,保持 JSON 入参类型并限制 PTC 返回字段。依据 0.2.29 大画布测试中的全目录读取、字符串参数和超大返回值失败;未改变绘图实现。此指引能否减少真实模型错误仍需新会话验证。 + +0.2.30 原生安装完成,97 个文件与发布包一致。独立 M3.1-Flash 会话用短请求新建白底蓝圆并导出 PNG:先加载 Skill 且正确匹配当前编辑器,但仍经历过大目录返回;首次导出误传自定义 path,参数被忽略后又搜索本机文件。经一次提醒使用完成任务返回路径后成功交付 800×600 PNG。因此本轮不算无人干预通过,需进一步处理导出参数误用,不能仅凭提示调整宣称可靠性改善。 + +0.2.31 修复 PhotoCraft 导出静默忽略未知参数:Node 在提交任务前拒绝自定义路径、未知键与无效格式,提示使用完成任务的 exportPath;PTC 与 photo_call 共用此校验。既有事务检查补充非法导出无任务落盘的断言,正常格式继续由现有导出链路处理。Skill 同步说明结果路径,不搜索本机目录。真实模型复测尚未完成。 + +0.2.31 原生导出验收通过:97 个安装文件与发布包一致。真实 PTC 对独立 320×240 画布传自定义 path,3 ms 内明确拒绝,对应任务 JSON 不存在;仅传 format:png 后导出成功,返回实际 exportPath,PNG 文件头尺寸正确,画布版本保持 1:1。此为针对导出校验的指定场景,不扩大为全部自然语言任务无人干预通过。 + +0.2.31 应用内单次生图请求通过:新对话输入“生成一张橘猫趴在窗台晒太阳的方形照片。”,没有补充指令。模型识别当前白底测试画布无需作为参考,调用文生图并自动 submit_image_result;任务约 63.66 秒后 ready,PNG 文件头为 1024×1024、1,560,731 字节。点击结果列表“打开图片”后,新文档显示橘猫照片及正确尺寸,原测试画布保留。任务因已有画布登记为 edit,但实际为模型文生图,不能把登记模式当作图生图证据。原生截图与成品留在本机,不包含在公开包。 + +未发布的 Skill 辅助脚本改进:trace_reference.py 新增可选 --preview,一次运行同时输出原有笔触 JSON 与有界白底 PNG,免去 Agent 临时编写预览程序。合成带孔蒙版检查确认笔触 JSON 与未传选项时完全一致、预览最长边 1024、已有文件拒绝覆盖;实际参考图也生成并查看了轮廓预览。社区检查 69 项通过。仅优化准备工具,不声称已改善真实模型耗时或素描质量;当前已安装和交付的 0.2.31 包尚不包含此改动。 + +0.2.32 交付包:14,260,915 字节,比 0.2.31 增加 424 字节。SHA-256 `3e1a4dd12a4642ba2f68942e833322c454900cee4adba73ee838934fa52ae7d9`。97 个条目 CRC 与文件摘要检查通过,包内包含 --preview 辅助脚本。打包、PTC、逐笔与压力检查通过。尚未安装宿主;当前真实宿主验收版本仍为 0.2.31。 + +0.2.32 已在真实 MiniMax Code 新会话发布并打开:publish / inspect / open 均成功,运行实例 `209ecb10-e69d-467e-82e6-ce8284095864`。独立比较 ZIP 与安装目录,97 个文件逐字节一致,版本为 0.2.32。欢迎页显示三张展示图及 AI 助手入口,未打开文档时没有导出按钮。宿主 Agent 另用合成蒙版验证 --preview 实际输出 600×450 PNG;此次未画图,不作为模型绘画质量或速度验证。 + +0.2.32 基础编辑与 PSD 往返:M3.1-Flash 根据一次需求创建 640×480 白底海报,独立 Circle 形状层与 Title 文字层(HELLO PHOTO),导出 PNG 10,090 字节及 PSD 71,958 字节,文件头尺寸独立校验通过。Agent 在图层返回值、导出结果截断和 Web 不支持的 file.openAs / placeEmbedded 上反复尝试;约 6 分 25 秒后停止,不算 AI 全流程自主通过。随后验收人员通过编辑器“文件 → 打开”的系统文件选择器打开同一 PSD,形成第二文档;原海报保留,三层名称、文字类型图标、圆形与标题、640×480 状态栏均可见。此证据仅覆盖该简单分层 PSD,不覆盖复杂 Photoshop 文件。需要补齐 AI 可发现的文件打开工具路径,避免它研究 HTTP 或浏览器隐藏输入。 + +未发布的 AI 导入修复:新增 editor_open_file,读取明确提供的图片/工程路径,经类型、大小和文件头检查后复用既有 open 任务路径。工具回复省略 base64,页面领取任务仍获得完整文件。现有事务检查覆盖 PNG 读取、相对路径与错误类型拒绝、重复请求不重放、回复不包含文件内容而领取任务仍完整;包检查通过。尚未安装到宿主,不声明 PSD 自主打开已通过真实模型验证。 + +0.2.33 AI 文件导入原生通过:安装 98 文件与发布 ZIP 逐字节一致(14,262,678 字节,SHA-256 `53cdb4e6289631d083750e934c3cf8182b31e3205fd6f9d30e76e2383e81c72d`)。发布当轮工具未刷新,下一轮 M3.1-Flash 实际调用 editor_open_file,任务 `3e5a7c91-6b28-4d0f-9a3c-7e14b62d8f04` succeeded,1792453193245 → 1792453193456(211ms 为任务耗时,不是整轮耗时)。打开 640×480 PSD,Title/Type、Circle/Shape、Background/Pixel 三层保留,Title 文本 HELLO PHOTO、字体 Inter、40pt。进一步 PTC 核对可编辑文字、ellipse 矢量及圆心蓝色;history 仅 Open,未重画,也未手动文件选择。首次像素查询的字符串入参错误由模型自行纠正。此项只证明该分层 PSD 的工具导入,不代替完整创作任务独立完成。包、PTC、逐笔及社区 69 项检查通过;此前磁盘不足导致的检查中断已在清理本项目 Rust 编译缓存后解决。 + +未发布的取色参数修复:原生记录显示 photo_call 入参为 x:"320",y:"210";底层 document.pixel 将非整数默认成 0,造成假成功。Node 现明确拒绝该命令的字符串、小数、缺失或越界坐标,同时要求 execute/batch 的 params 为对象。既有事务检查覆盖非法请求不落盘、有效整数与 i32 边界入队保留数值;PTC 检查通过。尚未在真实宿主安装,当前 0.2.33 不含此修复。 + +0.2.34 原生取色验证通过:98 个安装文件与发布 ZIP 一致,包 14,262,978 字节,SHA-256 `71845c81cda1d99db5f896698afac37de2e35099625011218ad51897b105af62`。通过 editor_open_file 打开既有 PSD 后,photo_call execute 传 x:"320",y:"210" 直接报 32 位整数类型错误;PTC 传数字 x:320,y:210 成功读到 RGBA [0.145098,0.388235,0.921569,1],即 #2563eb。任务 `6b059e34-56a4-4fe4-a224-563d553bb4e6` 状态 succeeded,appliedVersion=1:1;前后 inspect 均为 1:1,history 仅 Open。未重画、未修改原 PSD。包、PTC、逐笔和社区 69 项检查通过。此为明确指定输入的验证,不宣称所有命令已有类型校验。 + + +0.2.34 单请求绘画录制:M3.1-Flash,真实参考图附件及 MiniMax Photo 引用,一条 user 消息,原生界面显示 15 分 45 秒完成,约 7 分钟开始正式落笔;未追加人工绘画指令。窗口采样 312 帧,导出完整聊天加画布 GIF 85 秒(等待压缩、绘画段放慢、最后停留 8 秒),并校验全部 82 帧可解码。原始采样约 2.8 秒且有调用间隔,不宣称逐笔全部捕获或连续视频。PNG 为 1000×840、115,097 字节。轮廓接近参考,但瞳孔粗糙、排线机械,不能当作高质量素描通过。模型误称主体承载物,并反复修复重复缩放、分笔与插值错误,之后才正式绘制。录制和原图留在本机,不加入公开包。 + +基于此次记录修订通用 Skill:明确 trace_reference 的 points/bounds 已是 canvasSize 像素坐标,脚本已完成平滑与按路径长度分笔;优先直接画轻稿,手工曲线使用既有 Q/C 支持。未改变脚本或绘图引擎,未加入参考图专用参数;本修订尚未重新打包或在宿主模型验证,因此不声称已降低下一轮耗时。 + + +AI 文件导入扩展名修复(未打包):readEditorFile 校验时忽略大小写,但 PhotoCraft 的 open 分支用 ends_with(".pcraft") 识别工程,导致 .PCRAFT 被交给普通图片导入。现在只把传给编辑器的扩展名改为小写,保留文件名主体、文件内容和原始路径。现有检查新增大写工程后缀的名称和字节不变验证;使用最小文件头验证转换,不将其描述为真实工程打开测试。当前已安装 0.2.34 尚不含修复。 + + +0.2.35 原生安装及大写工程导入通过:ZIP 14,263,623 字节,SHA-256 `0a2c243449c0f65a4a2c64d3b2509d023164b7110e92c98b29588d7b12f95f66`,98 个安装文件逐字节一致。M3.1-Flash 使用 editor_open_file 导入真实 `Import-Check.PCRAFT`,任务 `07c0473e-66dc-40fc-aac9-a515e88860b7` succeeded,1000×840,Detail/Shading/Wash/Outline/Background 五层保留;inspect 为 1:1,history 仅 Open。预览任务也成功,原工程与测试副本 SHA-256 均为 `c109c3b2c18517323b1ced0c1cc03100632e05e64658fdc3cce0209a058598e9`。没有重画或改写原文件。包、PTC、逐笔和社区 69 项检查通过。新 Skill 已随安装交付,其对绘画准备速度的影响尚未验证。 + + +0.2.35 基础编辑组合验证:新会话一条请求完成 800×600 白底与独立蓝矩形图层、居中裁剪至 600×400、缩放至 300×200、图层隐藏/显示、移动后撤销、PNG 导出。页面 editorId 匹配当前空实例,旧工程在另一实例保留。模型第一次把 edit.fill 放入 batch 被拒绝后自行改为 execute。导出 PNG 独立解码为 300×200、745 字节,非白色范围 (75,50,225,150),中心 #1e6bff、角落白色,缩放边缘含正常抗锯齿。前一尝试遇到宿主磁盘 ENOSPC,turn 状态 failed 但 UI 仍显示运行;释放测试缓存并确认终止后才新建验收会话,不计为插件功能失败或自主恢复通过。 + + +0.2.35 应用内 AI 编辑验证:从浮动助手新建对话,输入“把当前图片转成灰度,保留尺寸和图层,导出 PNG”。没有主聊天补充,Agent 使用 image.mode.grayscale 修改当前测试文档;尺寸 300×200、Background/Blue 两层及边界保留,历史新增 Mode Change,可撤销。导出任务 4e6b8d21-9f0a-4c73-b5d8-2a3e7f1c6094 succeeded;独立解码 PNG 为 L 模式、300×200、868 字节,中心灰度 91、背景 255。浮窗正常展示中文结果表格并恢复输入;中间过程说明部分为英文。此项覆盖应用内直接编辑,不涉及图片模型生成或图片回传请求。 diff --git a/plugins/webguhui/minimax-photo/examples/compose-edit.mjs b/plugins/webguhui/minimax-photo/examples/compose-edit.mjs new file mode 100644 index 00000000..30ef281a --- /dev/null +++ b/plugins/webguhui/minimax-photo/examples/compose-edit.mjs @@ -0,0 +1,38 @@ +import { createEditorClient } from '../sdk/editor.mjs'; + +// callTool must be supplied by the actual Agent runtime, returning MCP content. +// editorId is explicitly selected from client.list(); never choose a random tab. +export async function drawSwatches(callTool, editorId) { + const client = createEditorClient(callTool); + const job = await client.edit(editorId, (doc) => { + const colors = ['#0f172a', '#2563eb', '#38bdf8', '#f8fafc']; + const margin = Math.round(doc.width * 0.06), + size = Math.max(1, Math.round(doc.width * 0.12)); + return [ + { op: 'add_layer', name: '配色方案', as: 'swatches' }, + ...colors.map((color, index) => ({ + op: 'shape', + layerId: '$swatches', + kind: 'rect', + x: margin + index * (size + 12), + y: margin, + width: size, + height: size, + color, + })), + { op: 'update_layer', layerId: '$swatches', opacity: 0.9 }, + ]; + }); + // Do not resubmit on timeout/interruption: keep this jobId and query it. + return client.wait(job.jobId); +} + +export async function recolorNamedLayers(callTool, editorId, names) { + const client = createEditorClient(callTool); + const job = await client.edit(editorId, (doc) => + doc.layers + .filter((layer) => names.includes(layer.name) && !layer.locked && !layer.adjustment) + .map((layer) => ({ op: 'filter', layerId: layer.id, type: 'saturation', value: -30 })), + ); + return client.wait(job.jobId); +} diff --git a/plugins/webguhui/minimax-photo/examples/ptc-script.js b/plugins/webguhui/minimax-photo/examples/ptc-script.js new file mode 100644 index 00000000..837653ab --- /dev/null +++ b/plugins/webguhui/minimax-photo/examples/ptc-script.js @@ -0,0 +1,58 @@ +// Submit this file's text as editor_run_code.code. Top-level return is supported. +const before = await editor.inspect(); +await editor.create({ name: 'PTC · 读图后决定怎么画', width: 960, height: 640 }); +await editor.edit([{ op: 'fill', color: '#142033' }]); +const sample = await editor.preview({ points: [[10, 10]] }); +const [r, g, b] = sample.result.pixels[0].rgba; +const dark = (r + g + b) / 3 < 128; +const foreground = dark ? '#ffffff' : '#142033'; +for (let i = 0; i < 3; i++) { + await editor.edit([ + { op: 'add_layer', name: `步骤 ${i + 1}`, as: 'card' }, + { + op: 'shape', + layerId: '$card', + kind: 'rect', + x: 60 + i * 290, + y: 250, + width: 260, + height: 190, + color: ['#246b8e', '#306e66', '#735387'][i], + }, + { + op: 'text', + value: ['读取像素', '判断明暗', '循环绘制'][i], + x: 80 + i * 290, + y: 330, + size: 32, + color: foreground, + }, + ]); +} +await editor.edit([ + { op: 'text', value: 'AI 用代码完成编辑', x: 60, y: 115, size: 52, color: foreground }, + { + op: 'text', + value: '一次提交,读取真实结果,再决定下一步。', + x: 60, + y: 175, + size: 26, + color: '#a7bacd', + }, + { + op: 'text', + value: `检测到${dark ? '深色' : '浅色'}背景,自动选择${dark ? '白色' : '深色'}文字`, + x: 60, + y: 535, + size: 25, + color: '#a7bacd', + }, +]); +const output = await editor.export(); +return { + sampledRGBA: sample.result.pixels[0].rgba, + dark, + layers: output.result.layers.length, + exportPath: output.exportPath, + originalDocumentId: before.document?.id, +}; diff --git a/plugins/webguhui/minimax-photo/icon.png b/plugins/webguhui/minimax-photo/icon.png new file mode 100644 index 00000000..294d7ba8 Binary files /dev/null and b/plugins/webguhui/minimax-photo/icon.png differ diff --git a/plugins/webguhui/minimax-photo/licenses/FONT-LICENSE.txt b/plugins/webguhui/minimax-photo/licenses/FONT-LICENSE.txt new file mode 100644 index 00000000..d952d62c --- /dev/null +++ b/plugins/webguhui/minimax-photo/licenses/FONT-LICENSE.txt @@ -0,0 +1,92 @@ +This Font Software is licensed under the SIL Open Font License, +Version 1.1. + +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font +creation efforts of academic and linguistic communities, and to +provide a free and open framework in which fonts may be shared and +improved in partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply to +any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software +components as distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, +deleting, or substituting -- in part or in whole -- any of the +components of the Original Version, by changing formats or by porting +the Font Software to a new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, +modify, redistribute, and sell modified and unmodified copies of the +Font Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, in +Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the +corresponding Copyright Holder. This restriction only applies to the +primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created using +the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/plugins/webguhui/minimax-photo/licenses/LICENSE-APACHE b/plugins/webguhui/minimax-photo/licenses/LICENSE-APACHE new file mode 100644 index 00000000..f433b1a5 --- /dev/null +++ b/plugins/webguhui/minimax-photo/licenses/LICENSE-APACHE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/plugins/webguhui/minimax-photo/licenses/LICENSE-MIT b/plugins/webguhui/minimax-photo/licenses/LICENSE-MIT new file mode 100644 index 00000000..68facca4 --- /dev/null +++ b/plugins/webguhui/minimax-photo/licenses/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 ArtCraft Team and the PhotoCraft contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/plugins/webguhui/minimax-photo/licenses/LICENSE-SCOWL.txt b/plugins/webguhui/minimax-photo/licenses/LICENSE-SCOWL.txt new file mode 100644 index 00000000..44efb0fb --- /dev/null +++ b/plugins/webguhui/minimax-photo/licenses/LICENSE-SCOWL.txt @@ -0,0 +1,258 @@ +en_US-scowl-50.txt.gz: English word list for Edit > Check Spelling. +Source: SCOWL (Spell Checker Oriented Word Lists) 2020.12.07 by Kevin Atkinson, +http://wordlist.aspell.net/ (downloads.sourceforge.net/project/wordlist/SCOWL/2020.12.07/scowl-2020.12.07.tar.gz). +Built from final/{english,american}-{words,upper,contractions,proper-names,abbreviations}.{10,20,35,40,50} +(size 50, en_US spelling), converted Latin-1 -> UTF-8, possessives ("'s") removed (the checker strips them), +grouped by SCOWL level ("#10", "#20", "#35", "#40", "#50" header lines; each word under the most common level it appears in), sorted within a level, one word per line, gzip -9. 72,403 words. + +SCOWL licence (verbatim from the distribution's Copyright file): +----------------------------------------------------------------- + +The collective work is Copyright 2000-2018 by Kevin Atkinson as well +as any of the copyrights mentioned below: + + Copyright 2000-2018 by Kevin Atkinson + + Permission to use, copy, modify, distribute and sell these word + lists, the associated scripts, the output created from the scripts, + and its documentation for any purpose is hereby granted without fee, + provided that the above copyright notice appears in all copies and + that both that copyright notice and this permission notice appear in + supporting documentation. Kevin Atkinson makes no representations + about the suitability of this array for any purpose. It is provided + "as is" without express or implied warranty. + +Alan Beale also deserves special credit as he has, +in addition to providing the 12Dicts package and being a major +contributor to the ENABLE word list, given me an incredible amount of +feedback and created a number of special lists (those found in the +Supplement) in order to help improve the overall quality of SCOWL. + +The 10 level includes the 1000 most common English words (according to +the Moby (TM) Words II [MWords] package), a subset of the 1000 most +common words on the Internet (again, according to Moby Words II), and +frequently class 16 from Brian Kelk's "UK English Wordlist +with Frequency Classification". + +The MWords package was explicitly placed in the public domain: + + The Moby lexicon project is complete and has + been place into the public domain. Use, sell, + rework, excerpt and use in any way on any platform. + + Placing this material on internal or public servers is + also encouraged. The compiler is not aware of any + export restrictions so freely distribute world-wide. + + You can verify the public domain status by contacting + + Grady Ward + 3449 Martha Ct. + Arcata, CA 95521-4884 + + grady@netcom.com + grady@northcoast.com + +The "UK English Wordlist With Frequency Classification" is also in the +Public Domain: + + Date: Sat, 08 Jul 2000 20:27:21 +0100 + From: Brian Kelk + + > I was wondering what the copyright status of your "UK English + > Wordlist With Frequency Classification" word list as it seems to + > be lacking any copyright notice. + + There were many many sources in total, but any text marked + "copyright" was avoided. Locally-written documentation was one + source. An earlier version of the list resided in a filespace called + PUBLIC on the University mainframe, because it was considered public + domain. + + Date: Tue, 11 Jul 2000 19:31:34 +0100 + + > So are you saying your word list is also in the public domain? + + That is the intention. + +The 20 level includes frequency classes 7-15 from Brian's word list. + +The 35 level includes frequency classes 2-6 and words appearing in at +least 11 of 12 dictionaries as indicated in the 12Dicts package. All +words from the 12Dicts package have had likely inflections added via +my inflection database. + +The 12Dicts package and Supplement is in the Public Domain. + +The WordNet database, which was used in the creation of the +Inflections database, is under the following copyright: + + This software and database is being provided to you, the LICENSEE, + by Princeton University under the following license. By obtaining, + using and/or copying this software and database, you agree that you + have read, understood, and will comply with these terms and + conditions.: + + Permission to use, copy, modify and distribute this software and + database and its documentation for any purpose and without fee or + royalty is hereby granted, provided that you agree to comply with + the following copyright notice and statements, including the + disclaimer, and that the same appear on ALL copies of the software, + database and documentation, including modifications that you make + for internal use or for distribution. + + WordNet 1.6 Copyright 1997 by Princeton University. All rights + reserved. + + THIS SOFTWARE AND DATABASE IS PROVIDED "AS IS" AND PRINCETON + UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR + IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PRINCETON + UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES OF MERCHANT- + ABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE + LICENSED SOFTWARE, DATABASE OR DOCUMENTATION WILL NOT INFRINGE ANY + THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + + The name of Princeton University or Princeton may not be used in + advertising or publicity pertaining to distribution of the software + and/or database. Title to copyright in this software, database and + any associated documentation shall at all times remain with + Princeton University and LICENSEE agrees to preserve same. + +The 40 level includes words from Alan's 3esl list found in version 4.0 +of his 12dicts package. Like his other stuff the 3esl list is also in the +public domain. + +The 50 level includes Brian's frequency class 1, words appearing +in at least 5 of 12 of the dictionaries as indicated in the 12Dicts +package, and uppercase words in at least 4 of the previous 12 +dictionaries. A decent number of proper names is also included: The +top 1000 male, female, and Last names from the 1990 Census report; a +list of names sent to me by Alan Beale; and a few names that I added +myself. Finally a small list of abbreviations not commonly found in +other word lists is included. + +The name files form the Census report is a government document which I +don't think can be copyrighted. + +The file special-jargon.50 uses common.lst and word.lst from the +"Unofficial Jargon File Word Lists" which is derived from "The Jargon +File". All of which is in the Public Domain. This file also contain +a few extra UNIX terms which are found in the file "unix-terms" in the +special/ directory. + +The 55 level includes words from Alan's 2of4brif list found in version +4.0 of his 12dicts package. Like his other stuff the 2of4brif is also +in the public domain. + +The 60 level includes all words appearing in at least 2 of the 12 +dictionaries as indicated by the 12Dicts package. + +The 70 level includes Brian's frequency class 0 and the 74,550 common +dictionary words from the MWords package. The common dictionary words, +like those from the 12Dicts package, have had all likely inflections +added. The 70 level also included the 5desk list from version 4.0 of +the 12Dics package which is in the public domain. + +The 80 level includes the ENABLE word list, all the lists in the +ENABLE supplement package (except for ABLE), the "UK Advanced Cryptics +Dictionary" (UKACD), the list of signature words from the YAWL package, +and the 10,196 places list from the MWords package. + +The ENABLE package, mainted by M\Cooper , +is in the Public Domain: + + The ENABLE master word list, WORD.LST, is herewith formally released + into the Public Domain. Anyone is free to use it or distribute it in + any manner they see fit. No fee or registration is required for its + use nor are "contributions" solicited (if you feel you absolutely + must contribute something for your own peace of mind, the authors of + the ENABLE list ask that you make a donation on their behalf to your + favorite charity). This word list is our gift to the Scrabble + community, as an alternate to "official" word lists. Game designers + may feel free to incorporate the WORD.LST into their games. Please + mention the source and credit us as originators of the list. Note + that if you, as a game designer, use the WORD.LST in your product, + you may still copyright and protect your product, but you may *not* + legally copyright or in any way restrict redistribution of the + WORD.LST portion of your product. This *may* under law restrict your + rights to restrict your users' rights, but that is only fair. + +UKACD, by J Ross Beresford , is under the +following copyright: + + Copyright (c) J Ross Beresford 1993-1999. All Rights Reserved. + + The following restriction is placed on the use of this publication: + if The UK Advanced Cryptics Dictionary is used in a software package + or redistributed in any form, the copyright notice must be + prominently displayed and the text of this document must be included + verbatim. + + There are no other restrictions: I would like to see the list + distributed as widely as possible. + +The 95 level includes the 354,984 single words, 256,772 compound +words, 4,946 female names and the 3,897 male names, and 21,986 names +from the MWords package, ABLE.LST from the ENABLE Supplement, and some +additional words found in my part-of-speech database that were not +found anywhere else. + +Accent information was taken from UKACD. + +The VarCon package was used to create the American, British, Canadian, +and Australian word list. It is under the following copyright: + + Copyright 2000-2016 by Kevin Atkinson + + Permission to use, copy, modify, distribute and sell this array, the + associated software, and its documentation for any purpose is hereby + granted without fee, provided that the above copyright notice appears + in all copies and that both that copyright notice and this permission + notice appear in supporting documentation. Kevin Atkinson makes no + representations about the suitability of this array for any + purpose. It is provided "as is" without express or implied warranty. + + Copyright 2016 by Benjamin Titze + + Permission to use, copy, modify, distribute and sell this array, the + associated software, and its documentation for any purpose is hereby + granted without fee, provided that the above copyright notice appears + in all copies and that both that copyright notice and this permission + notice appear in supporting documentation. Benjamin Titze makes no + representations about the suitability of this array for any + purpose. It is provided "as is" without express or implied warranty. + + Since the original words lists come from the Ispell distribution: + + Copyright 1993, Geoff Kuenning, Granada Hills, CA + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. All modifications to the source code must be clearly marked as + such. Binary redistributions based on modified source code + must be clearly marked as modified versions in the documentation + and/or other materials provided with the distribution. + (clause 4 removed with permission from Geoff Kuenning) + 5. The name of Geoff Kuenning may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. diff --git a/plugins/webguhui/minimax-photo/licenses/LICENSE-libfacedetection.txt b/plugins/webguhui/minimax-photo/licenses/LICENSE-libfacedetection.txt new file mode 100644 index 00000000..33abd64f --- /dev/null +++ b/plugins/webguhui/minimax-photo/licenses/LICENSE-libfacedetection.txt @@ -0,0 +1,35 @@ +By downloading, copying, installing or using the software you agree to this license. +If you do not agree to this license, do not download, install, +copy or use the software. + + + License Agreement For libfacedetection + (3-clause BSD License) + +Copyright (c) 2015-2019, Shiqi Yu, all rights reserved. +shiqi.yu@gmail.com + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the names of the copyright holders nor the names of the contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +This software is provided by the copyright holders and contributors "as is" and +any express or implied warranties, including, but not limited to, the implied +warranties of merchantability and fitness for a particular purpose are disclaimed. +In no event shall copyright holders or contributors be liable for any direct, +indirect, incidental, special, exemplary, or consequential damages +(including, but not limited to, procurement of substitute goods or services; +loss of use, data, or profits; or business interruption) however caused +and on any theory of liability, whether in contract, strict liability, +or tort (including negligence or otherwise) arising in any way out of +the use of this software, even if advised of the possibility of such damage. \ No newline at end of file diff --git a/plugins/webguhui/minimax-photo/licenses/LICENSE-lucide.txt b/plugins/webguhui/minimax-photo/licenses/LICENSE-lucide.txt new file mode 100644 index 00000000..718bb3f0 --- /dev/null +++ b/plugins/webguhui/minimax-photo/licenses/LICENSE-lucide.txt @@ -0,0 +1,43 @@ +ISC License + +Copyright (c) 2026 Lucide Icons and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +--- + +The following Lucide icons are derived from the Feather project: + +airplay, alert-circle, alert-octagon, alert-triangle, aperture, arrow-down-circle, arrow-down-left, arrow-down-right, arrow-down, arrow-left-circle, arrow-left, arrow-right-circle, arrow-right, arrow-up-circle, arrow-up-left, arrow-up-right, arrow-up, at-sign, calendar, cast, check, chevron-down, chevron-left, chevron-right, chevron-up, chevrons-down, chevrons-left, chevrons-right, chevrons-up, circle, clipboard, clock, code, columns, command, compass, corner-down-left, corner-down-right, corner-left-down, corner-left-up, corner-right-down, corner-right-up, corner-up-left, corner-up-right, crosshair, database, divide-circle, divide-square, dollar-sign, download, external-link, feather, frown, hash, headphones, help-circle, info, italic, key, layout, life-buoy, link-2, link, loader, lock, log-in, log-out, maximize, meh, minimize, minimize-2, minus-circle, minus-square, minus, monitor, moon, more-horizontal, more-vertical, move, music, navigation-2, navigation, octagon, pause-circle, percent, plus-circle, plus-square, plus, power, radio, rss, search, server, share, shopping-bag, sidebar, smartphone, smile, square, table-2, tablet, target, terminal, trash-2, trash, triangle, tv, type, upload, x-circle, x-octagon, x-square, x, zoom-in, zoom-out + +The MIT License (MIT) (for the icons listed above) + +Copyright (c) 2013-present Cole Bemis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/plugins/webguhui/minimax-photo/licenses/LICENSE-photocraft-icon.txt b/plugins/webguhui/minimax-photo/licenses/LICENSE-photocraft-icon.txt new file mode 100644 index 00000000..b28ccee0 --- /dev/null +++ b/plugins/webguhui/minimax-photo/licenses/LICENSE-photocraft-icon.txt @@ -0,0 +1,13 @@ +PhotoCraft app icon (photocraft.svg, photocraft-small.svg and every file derived from them in +this directory: photocraft-1024.png, photocraft.icns, photocraft.ico, hicolor/). + +Original artwork made for this project by the project owner: an engraving-style drawing created +in ArtCraft, then vectorised. No third-party material. Licensed like the rest of PhotoCraft, +under either of + + * Apache License, Version 2.0 (https://www.apache.org/licenses/LICENSE-2.0) + * MIT license (https://opensource.org/licenses/MIT) + +at your option. + +Regenerate the derived files with packaging/icons.sh. diff --git a/plugins/webguhui/minimax-photo/licenses/LICENSE-translations.txt b/plugins/webguhui/minimax-photo/licenses/LICENSE-translations.txt new file mode 100644 index 00000000..93a609f9 --- /dev/null +++ b/plugins/webguhui/minimax-photo/licenses/LICENSE-translations.txt @@ -0,0 +1,39 @@ +PhotoCraft's Korean, German, Spanish, Brazilian Portuguese, Italian, Ukrainian, Dutch, Czech, +Turkish, Hungarian and Serbian UI translation catalogs are licensed under MIT OR Apache-2.0, +at your option. +The full license texts are in ../../../../LICENSE-MIT and ../../../../LICENSE-APACHE. + +Korean translations: PhotoCraft contributors, original translations of +PhotoCraft's English labels; no proprietary translation resources were used. + +German translations: PhotoCraft contributors, original translations of +PhotoCraft's English labels; no proprietary translation resources were used. + +Spanish translations: contributed by @gorevyoneticisi with OpenAI Codex as an AI contributor. +The resulting catalog is licensed under MIT OR Apache-2.0 as stated above; the translations are +original translations of PhotoCraft's English labels, and no proprietary translation resources +were used. + +Brazilian Portuguese translations: PhotoCraft contributors, original translations of +PhotoCraft's English labels; no proprietary translation resources were used. + +Italian translations: PhotoCraft contributors, original translations of +PhotoCraft's English labels; no proprietary translation resources were used. + +Ukrainian translations: PhotoCraft contributors, original translations of +PhotoCraft's English labels; no proprietary translation resources were used. + +Dutch translations: PhotoCraft contributors, original translations of +PhotoCraft's English labels; no proprietary translation resources were used. + +Czech translations: PhotoCraft contributors, original translations of +PhotoCraft's English labels; no proprietary translation resources were used. + +Turkish translations: PhotoCraft contributors, original translations of +PhotoCraft's English labels; no proprietary translation resources were used. + +Hungarian translations: PhotoCraft contributors, original translations of +PhotoCraft's English labels; no proprietary translation resources were used. + +Serbian translations: PhotoCraft contributors, original translations of +PhotoCraft's English labels; no proprietary translation resources were used. diff --git a/plugins/webguhui/minimax-photo/licenses/OFL-Inter.txt b/plugins/webguhui/minimax-photo/licenses/OFL-Inter.txt new file mode 100644 index 00000000..9b2ca37b --- /dev/null +++ b/plugins/webguhui/minimax-photo/licenses/OFL-Inter.txt @@ -0,0 +1,92 @@ +Copyright (c) 2016 The Inter Project Authors (https://github.com/rsms/inter) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION AND CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/plugins/webguhui/minimax-photo/licenses/OFL-JetBrainsMono.txt b/plugins/webguhui/minimax-photo/licenses/OFL-JetBrainsMono.txt new file mode 100644 index 00000000..675d198b --- /dev/null +++ b/plugins/webguhui/minimax-photo/licenses/OFL-JetBrainsMono.txt @@ -0,0 +1,93 @@ +Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/plugins/webguhui/minimax-photo/licenses/markdown-dependencies.txt b/plugins/webguhui/minimax-photo/licenses/markdown-dependencies.txt new file mode 100644 index 00000000..66597ab9 --- /dev/null +++ b/plugins/webguhui/minimax-photo/licenses/markdown-dependencies.txt @@ -0,0 +1,2507 @@ +node_modules/@types/debug 4.1.13 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +node_modules/@types/estree 1.0.9 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +node_modules/@types/estree-jsx 1.0.5 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +node_modules/@types/hast 3.0.5 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +node_modules/@types/mdast 4.0.4 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +node_modules/@types/ms 2.1.0 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +node_modules/@types/react 19.3.0 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +node_modules/@types/unist 3.0.3 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +node_modules/@ungap/structured-clone 1.4.0 +ISC License + +Copyright (c) 2021, Andrea Giammarchi, @WebReflection + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + + +node_modules/bail 2.0.2 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/ccount 2.0.1 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/character-entities 2.0.2 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/character-entities-html4 2.1.0 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/character-entities-legacy 3.0.0 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/character-reference-invalid 2.0.1 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/comma-separated-tokens 2.0.3 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/csstype 3.2.3 +Copyright (c) 2017-2018 Fredrik Nicol + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +node_modules/debug 4.4.3 +(The MIT License) + +Copyright (c) 2014-2017 TJ Holowaychuk +Copyright (c) 2018-2021 Josh Junon + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software +and associated documentation files (the 'Software'), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +node_modules/decode-named-character-reference 1.3.0 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/dequal 2.0.3 +The MIT License (MIT) + +Copyright (c) Luke Edwards (lukeed.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +node_modules/devlop 1.1.0 +(The MIT License) + +Copyright (c) 2023 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/escape-string-regexp 5.0.0 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/estree-util-is-identifier-name 3.0.0 +(The MIT License) + +Copyright (c) 2020 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/extend 3.0.2 +The MIT License (MIT) + +Copyright (c) 2014 Stefan Thomas + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +node_modules/hast-util-to-jsx-runtime 2.3.6 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/hast-util-whitespace 3.0.0 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/html-url-attributes 3.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +node_modules/inline-style-parser 0.2.7 +(The MIT License) + +Copyright (c) 2012 TJ Holowaychuk + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/is-alphabetical 2.0.1 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/is-alphanumerical 2.0.1 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/is-decimal 2.0.1 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/is-hexadecimal 2.0.1 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/is-plain-obj 4.1.0 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/longest-streak 3.1.0 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/markdown-table 3.0.4 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/mdast-util-find-and-replace 3.0.3 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/mdast-util-from-markdown 2.1.0 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/mdast-util-gfm 3.1.0 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/mdast-util-gfm-autolink-literal 2.0.1 +(The MIT License) + +Copyright (c) 2020 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/mdast-util-gfm-footnote 2.1.0 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/mdast-util-gfm-strikethrough 2.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/mdast-util-gfm-table 2.0.0 +(The MIT License) + +Copyright (c) 2020 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/mdast-util-gfm-task-list-item 2.0.0 +(The MIT License) + +Copyright (c) 2020 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/mdast-util-mdx-expression 2.0.1 +(The MIT License) + +Copyright (c) 2020 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/mdast-util-mdx-jsx 3.2.0 +(The MIT License) + +Copyright (c) 2020 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/mdast-util-mdxjs-esm 2.0.1 +(The MIT License) + +Copyright (c) 2020 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/mdast-util-phrasing 4.1.0 +(The MIT License) + +Copyright (c) 2017 Titus Wormer +Copyright (c) 2017 Victor Felder + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/mdast-util-to-hast 13.2.1 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/mdast-util-to-markdown 2.2.0 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/mdast-util-to-string 4.0.0 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark 4.0.3 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-core-commonmark 2.0.4 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-extension-gfm 3.0.0 +(The MIT License) + +Copyright (c) 2020 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-extension-gfm-autolink-literal 2.1.0 +(The MIT License) + +Copyright (c) 2020 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-extension-gfm-footnote 2.1.0 +(The MIT License) + +Copyright (c) 2021 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-extension-gfm-strikethrough 2.1.0 +(The MIT License) + +Copyright (c) 2020 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-extension-gfm-table 2.1.2 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-extension-gfm-tagfilter 2.0.0 +(The MIT License) + +Copyright (c) 2020 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-extension-gfm-task-list-item 2.1.0 +(The MIT License) + +Copyright (c) 2020 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-factory-destination 2.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-factory-label 2.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-factory-space 2.1.0 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-factory-title 2.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-factory-whitespace 2.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-util-character 2.1.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-util-chunked 2.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-util-classify-character 2.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-util-combine-extensions 2.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-util-decode-numeric-character-reference 2.0.2 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-util-decode-string 2.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-util-edit-map 1.0.0 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-util-encode 2.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-util-html-tag-name 2.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-util-normalize-identifier 2.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-util-resolve-all 2.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-util-sanitize-uri 2.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-util-subtokenize 2.1.0 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-util-symbol 2.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/micromark-util-types 2.0.3 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/ms 2.1.3 +The MIT License (MIT) + +Copyright (c) 2020 Vercel, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +node_modules/parse-entities 4.0.2 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/parse-entities/node_modules/@types/unist 2.0.11 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +node_modules/property-information 7.2.0 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/react-markdown 10.1.0 +The MIT License (MIT) + +Copyright (c) Espen Hovlandsdal + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +node_modules/remark-gfm 4.0.1 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/remark-parse 11.0.0 +(The MIT License) + +Copyright (c) 2014 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +node_modules/remark-rehype 11.1.2 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/remark-stringify 11.0.0 +(The MIT License) + +Copyright (c) 2014 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +node_modules/space-separated-tokens 2.0.2 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/stringify-entities 4.0.4 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/style-to-js 1.1.21 +The MIT License (MIT) + +Copyright (c) 2020 Menglin "Mark" Xu + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/style-to-object 1.0.14 +The MIT License (MIT) + +Copyright (c) 2017 Menglin "Mark" Xu + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/trim-lines 3.0.1 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/trough 2.2.0 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +node_modules/unified 11.0.5 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +node_modules/unist-util-is 6.0.1 +(The MIT license) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/unist-util-position 5.0.0 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/unist-util-stringify-position 4.0.0 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/unist-util-visit 5.1.0 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/unist-util-visit-parents 6.0.2 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/vfile 6.0.3 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +node_modules/vfile-message 4.0.3 +(The MIT License) + +Copyright (c) Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +node_modules/zwitch 2.0.4 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/plugins/webguhui/minimax-photo/licenses/photocraft-ATTRIBUTION.md b/plugins/webguhui/minimax-photo/licenses/photocraft-ATTRIBUTION.md new file mode 100644 index 00000000..1ae19efa --- /dev/null +++ b/plugins/webguhui/minimax-photo/licenses/photocraft-ATTRIBUTION.md @@ -0,0 +1,120 @@ +# Attribution + +Every non-code asset in this repository, with its author, source and license. PhotoCraft's own +code and original assets are MIT OR Apache-2.0 (see [`LICENSE-MIT`](LICENSE-MIT), +[`LICENSE-APACHE`](LICENSE-APACHE) and [`NOTICE`](NOTICE)). When you add an asset, add a row here +in the same change; third-party assets must be permissively licensed and keep their license file +next to them. + +## Bundled in the app + +| Path | Title | Author | Source | License | +|---|---|---|---|---| +| `crates/codecs/src/codecs/xpm/x11_colors.rs` | X11 `rgb.txt` color-name lookup table (normalized X.Org RGB values) | X.Org Foundation and X11 contributors | | MIT (X.Org app/rgb) | +| `crates/ui-egui/src/i18n/el.tsv` | Greek UI translations | PhotoCraft contributors | Original translations of PhotoCraft's English labels | MIT OR Apache-2.0, [`LICENSE-translations.txt`](crates/ui-egui/src/i18n/LICENSE-translations.txt) | +| `crates/ui-egui/src/i18n/de.tsv` | German UI translations | PhotoCraft contributors | Original translations of PhotoCraft's English labels | MIT OR Apache-2.0, [`LICENSE-translations.txt`](crates/ui-egui/src/i18n/LICENSE-translations.txt) | +| `crates/ui-egui/src/i18n/es.tsv` | Spanish UI translations | @gorevyoneticisi; AI contributor: OpenAI Codex | Original translations of PhotoCraft's English labels | MIT OR Apache-2.0, [`LICENSE-translations.txt`](crates/ui-egui/src/i18n/LICENSE-translations.txt) | +| `crates/ui-egui/src/i18n/it.tsv` | Italian UI translations | PhotoCraft contributors | Original translations of PhotoCraft's English labels | MIT OR Apache-2.0, [`LICENSE-translations.txt`](crates/ui-egui/src/i18n/LICENSE-translations.txt) | +| `crates/ui-egui/src/i18n/ko.tsv` | Korean UI translations | PhotoCraft contributors | Original translations of PhotoCraft's English labels | MIT OR Apache-2.0, [`LICENSE-translations.txt`](crates/ui-egui/src/i18n/LICENSE-translations.txt) | +| `crates/ui-egui/src/i18n/nl.tsv` | Dutch UI translations | PhotoCraft contributors | Original translations of PhotoCraft's English labels | MIT OR Apache-2.0, [`LICENSE-translations.txt`](crates/ui-egui/src/i18n/LICENSE-translations.txt) | +| `crates/ui-egui/src/i18n/pl.tsv` | Polish UI translations | PhotoCraft contributors | Original translations of PhotoCraft's English labels | MIT OR Apache-2.0, [`LICENSE-translations.txt`](crates/ui-egui/src/i18n/LICENSE-translations.txt) | +| `crates/ui-egui/src/i18n/pt-br.tsv` | Brazilian Portuguese UI translations | PhotoCraft contributors | Original translations of PhotoCraft's English labels | MIT OR Apache-2.0, [`LICENSE-translations.txt`](crates/ui-egui/src/i18n/LICENSE-translations.txt) | +| `crates/ui-egui/src/i18n/uk.tsv` | Ukrainian UI translations | PhotoCraft contributors | Original translations of PhotoCraft's English labels | MIT OR Apache-2.0, [`LICENSE-translations.txt`](crates/ui-egui/src/i18n/LICENSE-translations.txt) | +| `crates/ui-egui/src/i18n/cs.tsv` | Czech UI translations | PhotoCraft contributors | Original translations of PhotoCraft's English labels | MIT OR Apache-2.0, [`LICENSE-translations.txt`](crates/ui-egui/src/i18n/LICENSE-translations.txt) | +| `crates/ui-egui/src/i18n/hu.tsv` | Hungarian UI translations | PhotoCraft contributors | Original translations of PhotoCraft's English labels | MIT OR Apache-2.0, [`LICENSE-translations.txt`](crates/ui-egui/src/i18n/LICENSE-translations.txt) | +| `crates/ui-egui/src/i18n/vi.tsv` | Vietnamese UI translations | PhotoCraft contributors | Original translations of PhotoCraft's English labels | MIT OR Apache-2.0, [`LICENSE-translations.txt`](crates/ui-egui/src/i18n/LICENSE-translations.txt) | +| `crates/ui-egui/src/i18n/tr.tsv` | Turkish UI translations | PhotoCraft contributors | Original translations of PhotoCraft's English labels | MIT OR Apache-2.0, [`LICENSE-translations.txt`](crates/ui-egui/src/i18n/LICENSE-translations.txt) | +| `crates/ui-egui/src/i18n/sr.tsv` | Serbian (Latin, Ekavian) UI translations | PhotoCraft contributors | Original translations of PhotoCraft's English labels | MIT OR Apache-2.0, [`LICENSE-translations.txt`](crates/ui-egui/src/i18n/LICENSE-translations.txt) | +| `assets/fonts/Inter-Regular.ttf`, `Inter-Medium.ttf`, `Inter-SemiBold.ttf` | Inter 4.001 (UI font) | The Inter Project Authors (Rasmus Andersson) | | SIL OFL 1.1, [`assets/fonts/OFL-Inter.txt`](assets/fonts/OFL-Inter.txt) | +| `assets/fonts/JetBrainsMono-Regular.ttf` | JetBrains Mono 2.305 (numeric font) | The JetBrains Mono Project Authors | | SIL OFL 1.1, [`assets/fonts/OFL-JetBrainsMono.txt`](assets/fonts/OFL-JetBrainsMono.txt) | +| `assets/icons/*.svg` except `slice-knife.svg`, `sampler.svg`, `artboard.svg`, `perspective-crop.svg`, `frame-placeholder.svg`, `gradient.svg`, `type-mask.svg`, `type-mask-vertical.svg`, `clip-below.svg`, `clip-release.svg`, `layer-mask.svg`, `adjustment-layer.svg`, `brush-replace.svg`, `quick-selection.svg`, `eraser-background.svg`, `eraser-magic.svg`, `lasso-magnetic.svg`, `direct-select.svg`, `convert-point.svg`, `pen-add-anchor.svg`, `pen-delete-anchor.svg`, `pen-freeform.svg`, `pen-curvature.svg`, `bandage-sparkle.svg`, `painting-symmetry.svg`, `symmetry-*.svg` and `marquee-{row,column}.svg` (113 files; `star-filled.svg` is `star.svg` with a solid fill) | Lucide icons | Lucide Icons and Contributors | (`icons/.svg`; `align-*` are now named `text-align-*` upstream) | ISC, [`assets/icons/LICENSE-lucide.txt`](assets/icons/LICENSE-lucide.txt) | +| `assets/icons/{check,chevron-down,chevron-left,chevron-right,chevron-up,chevrons-left,chevrons-right,circle,clock,compass,info,link,link-2,lock,minus,monitor,moon,move,navigation,plus,search,square,trash,triangle,type,x,zoom-in}.svg` | Lucide icons derived from Feather (subset of the row above) | Cole Bemis (Feather), Lucide Contributors | via Lucide | MIT (Feather) and ISC (Lucide), [`assets/icons/LICENSE-lucide.txt`](assets/icons/LICENSE-lucide.txt) | +| `assets/icons/slice-knife.svg` | Slice tool glyph | PhotoCraft contributors | Original work | MIT OR Apache-2.0 | +| `assets/icons/sampler.svg` | Color Sampler tool glyph: a target reticle marking a sampled pixel | PhotoCraft contributors | Original work | MIT OR Apache-2.0 | +| `assets/icons/convert-point.svg` | Convert Point tool glyph: an angle with a square anchor on its apex, drawn on Lucide's 24 px grid and stroke | PhotoCraft contributors | Original work | MIT OR Apache-2.0 | +| `assets/icons/artboard.svg` | Artboard tool glyph: a board with a tick at each end of its edges | PhotoCraft contributors | Original work | MIT OR Apache-2.0 | +| `assets/icons/perspective-crop.svg` | Perspective Crop tool glyph: a crop frame in perspective with its grid and crop-mark ticks | PhotoCraft contributors | Original work | MIT OR Apache-2.0 | +| `assets/icons/type-mask.svg`, `assets/icons/type-mask-vertical.svg` | Horizontal and Vertical Type Mask tool glyphs: a T drawn as marching ants (the vertical one beside a downward arrow), on Lucide's 24 px grid and stroke | PhotoCraft contributors | Original work | MIT OR Apache-2.0 | +| `assets/icons/marquee-row.svg`, `assets/icons/marquee-column.svg` | Single Row and Single Column Marquee tool glyphs: a dashed row (column) between two edge bars, drawn on Lucide's 24 px grid and stroke | PhotoCraft contributors | Original work | MIT OR Apache-2.0 | +| `assets/icons/clip-below.svg`, `assets/icons/clip-release.svg` | Clipping-mask cursors (⌥ over the line between two layers): a hooked arrow onto the layer below; the same with a small "no" badge to release | PhotoCraft contributors | Original work | MIT OR Apache-2.0 | +| `assets/icons/layer-mask.svg`, `assets/icons/adjustment-layer.svg` | Layers panel footer glyphs: Add a mask (a frame around a solid disc) and New Fill or Adjustment Layer (a circle, one half solid), drawn on Lucide's 24 px grid and stroke | PhotoCraft contributors | Original work | MIT OR Apache-2.0 | +| `assets/icons/frame-placeholder.svg` | Frame tool glyph: an empty placeholder frame, crossed corner to corner | PhotoCraft contributors | Original work | MIT OR Apache-2.0 | +| `assets/icons/gradient.svg` | Gradient tool glyph: a rounded rectangle filled with a left-to-right linear ramp, drawn on Lucide's 24 px grid and stroke | PhotoCraft contributors | Original work | MIT OR Apache-2.0 | +| `assets/icons/eraser-background.svg`, `assets/icons/eraser-magic.svg` | Background Eraser and Magic Eraser tool glyphs: Lucide `eraser` plus added marks | Lucide Icons and Contributors; marks by PhotoCraft contributors | Derived from `icons/eraser.svg` | ISC, [`assets/icons/LICENSE-lucide.txt`](assets/icons/LICENSE-lucide.txt) | +| `assets/icons/brush-replace.svg` | Color Replacement tool glyph: Lucide `brush` plus two swap arrows | Lucide Icons and Contributors; arrows by PhotoCraft contributors | Derived from `icons/brush.svg` | ISC, [`assets/icons/LICENSE-lucide.txt`](assets/icons/LICENSE-lucide.txt) | +| `assets/icons/quick-selection.svg` | Quick Selection tool glyph: Lucide `brush` plus a dashed selection arc around the bristles | Lucide Icons and Contributors; arc by PhotoCraft contributors | Derived from `icons/brush.svg` | ISC, [`assets/icons/LICENSE-lucide.txt`](assets/icons/LICENSE-lucide.txt) | +| `assets/icons/bandage-sparkle.svg` | Remove tool glyph: Lucide `bandage` moved down, plus a sparkle mark | Lucide Icons and Contributors; mark by PhotoCraft contributors | Derived from `icons/bandage.svg` | ISC, [`assets/icons/LICENSE-lucide.txt`](assets/icons/LICENSE-lucide.txt) | +| `assets/icons/direct-select.svg` | Direct Selection tool glyph: Lucide `mouse-pointer-2` plus an anchor square | Lucide Icons and Contributors; square by PhotoCraft contributors | Derived from `icons/mouse-pointer-2.svg` | ISC, [`assets/icons/LICENSE-lucide.txt`](assets/icons/LICENSE-lucide.txt) | +| `assets/icons/pen-freeform.svg`, `assets/icons/pen-curvature.svg` | Freeform Pen and Curvature Pen tool glyphs: Lucide `pen-tool` scaled down, plus a freehand squiggle or a curve through two points | Lucide Icons and Contributors; marks by PhotoCraft contributors | Derived from `icons/pen-tool.svg` | ISC, [`assets/icons/LICENSE-lucide.txt`](assets/icons/LICENSE-lucide.txt) | +| `assets/icons/pen-add-anchor.svg`, `assets/icons/pen-delete-anchor.svg` | Add Anchor Point and Delete Anchor Point tool glyphs: Lucide `pen-tool` plus a + or − mark | Lucide Icons and Contributors; marks by PhotoCraft contributors | Derived from `icons/pen-tool.svg` | ISC, [`assets/icons/LICENSE-lucide.txt`](assets/icons/LICENSE-lucide.txt) | +| `assets/icons/painting-symmetry.svg` | Painting symmetry glyph: Lucide `heart` with a central axis | Lucide Icons and Contributors; adapted by @shorbank | Derived from `icons/heart.svg` | ISC, [`assets/icons/LICENSE-lucide.txt`](assets/icons/LICENSE-lucide.txt) | +| `assets/icons/symmetry-{vertical,horizontal,dual,diagonal}.svg` | Painting symmetry axis glyphs | @shorbank | Original work; supplied SVG line geometry centred on a common square canvas, stroke adjusted to match the painting-symmetry glyph | MIT OR Apache-2.0, [`assets/icons/LICENSE-symmetry-axes.txt`](assets/icons/LICENSE-symmetry-axes.txt) | +| `assets/icons/lasso-magnetic.svg` | Magnetic Lasso tool glyph, adapted from "Magnetic Lasso Tool" (redrawn on the 24 px toolbar grid) | Lil' Seal (Noun Project); adapted by PhotoCraft contributors | | CC BY 3.0, [`assets/icons/LICENSE-noun-magnetic-lasso.txt`](assets/icons/LICENSE-noun-magnetic-lasso.txt) | +| `assets/dict/en_US-scowl-50.txt.gz` | English word list for Check Spelling (SCOWL 2020.12.07, size 50, en_US; 72,403 words) | Kevin Atkinson and the SCOWL contributors | | SCOWL license (permissive, keep the notice), [`assets/dict/LICENSE-SCOWL.txt`](assets/dict/LICENSE-SCOWL.txt), which also has the build recipe | +| `crates/cms/profiles/photocraft-coated-cmyk.icc` | PhotoCraft Coated CMYK (synthetic) ICC profile | PhotoCraft contributors (generated by `photocraft-cms`, `src/synth.rs`) | Original work, see [`crates/cms/README.md`](crates/cms/README.md) | CC0-1.0 | +| `assets/app-icon/` (all files) | PhotoCraft app icon (nine-tailed kitsune) | The project owner (drawn in ArtCraft, vectorised) | Original work, see [`assets/app-icon/README.md`](assets/app-icon/README.md) | MIT OR Apache-2.0, [`assets/app-icon/LICENSE.txt`](assets/app-icon/LICENSE.txt) | +| `packaging/macos/dmg/` (all files) | PhotoCraft DMG window background and layout | @XusBadia, from the PhotoCraft app icon | Original work, see [`packaging/macos/dmg/README.md`](packaging/macos/dmg/README.md) | MIT OR Apache-2.0, like the code | +| `crates/ui-egui/src/theme.rs` (Solarized Dark palette) | Solarized colour scheme used by the Solarized Dark theme | Ethan Schoonover | | MIT, [`LICENSE-solarized.txt`](crates/ui-egui/src/LICENSE-solarized.txt) | +| `crates/ui-egui/src/theme.rs` (Breeze Light and Breeze Dark themes) | The Breeze Light and Breeze Dark themes are original colour values on PhotoCraft's Studio layout, chosen to look close to KDE Plasma's Breeze (cool blue-greys, blue accent, 5 px frame radius) so the app blends into a Plasma desktop. None of Breeze's colour values, files or code are copied; the values are a few levels away from its schemes and tuned for text contrast | PhotoCraft contributors | Inspired by the look of KDE Breeze, (its colour schemes are LGPL-2.0-or-later) | Original work | +| `crates/ui-egui/src/theme.rs` (Soft Dark and Soft Light themes) | Original colour values and radii for two low-contrast themes on PhotoCraft's Studio layout; no third-party palette, file or code is used | PhotoCraft contributors | Original | Original work | +| `crates/algo/data/libfacedetection.bin` (face detection weights, read by `crates/algo/src/faces.rs`, whose network code is a port of the library's) | libfacedetection CNN (YuNet design) weights and inference code, weights converted to half precision | Shiqi Yu | [ShiqiYu/libfacedetection](https://github.com/ShiqiYu/libfacedetection) (`src/facedetectcnn-data.cpp`, `facedetectcnn.cpp`, `facedetectcnn-model.cpp`) | BSD-3-Clause, [`LICENSE-libfacedetection.txt`](crates/algo/data/LICENSE-libfacedetection.txt) | + +### Optional build input: craft-fonts (not files in this repo) + +Builds made with `CRAFT_FONTS_DIR` (all official releases) embed fonts from +[storytold/craft-fonts](https://github.com/storytold/craft-fonts) at a pinned commit; no font file +from it is committed here. Per-file authors, sources and licences: +[craft-fonts `ATTRIBUTION.md`](https://github.com/storytold/craft-fonts/blob/main/ATTRIBUTION.md). + +| Font (embedded at build time) | Use | License | +|---|---|---| +| BIZ UDPGothic Regular, Bold (Morisawa) | Japanese UI and sans Type fallback (desktop) | SIL OFL 1.1, shipped as `OFL-biz-ud-pgothic.txt` | +| Shippori Mincho Regular (FONTDASU) | Japanese serif Type fallback (desktop) | SIL OFL 1.1, shipped as `OFL-shippori-mincho.txt` | +| BIZ UDMincho Regular (Morisawa) | Japanese serif Type fallback (desktop) | SIL OFL 1.1, shipped as `OFL-biz-ud-mincho.txt` | + +The other built-in ICC profiles and the generated LUT looks are produced by code at runtime +(`crates/cms/src/builtin.rs`, `crates/cms/src/lutfile.rs`) and dedicated to the public domain +(CC0-1.0); they are not separate files. + +## Documentation and README + +| Path | Title | Author | Source | License | +|---|---|---|---|---| +| `docs/brand/` (all files) | ArtCraft name, wordmark and mark | ArtCraft Team | getartcraft.com | Not open source; trademarks of the ArtCraft Team, [`docs/brand/LICENSE-brand.txt`](docs/brand/LICENSE-brand.txt) | +| `docs/images/photocraft-*.jpg` | PhotoCraft screenshots | PhotoCraft contributors (UI) | Rendered offscreen with the `snapshot` example | MIT OR Apache-2.0 (UI); the artwork in each is public domain, listed below | +| `docs/images/preferences-apply-*.png` | Preferences before and after adding Apply (no artwork) | PhotoCraft contributors | PhotoCraft control-channel capture and offscreen `snapshot` example | MIT OR Apache-2.0 | + +Artwork shown in the screenshots (all public domain, via Wikimedia Commons; details in +[`docs/images/SOURCES.md`](docs/images/SOURCES.md)): + +| Screenshot | Artwork | Source | +|---|---|---| +| `photocraft-demo.jpg` | *The Great Wave off Kanagawa*, Katsushika Hokusai, c. 1831 | [Commons](https://commons.wikimedia.org/wiki/File:Tsunami_by_hokusai_19th_century.jpg) | +| `photocraft-layer-styles.jpg` | *Earthrise*, William Anders, Apollo 8, 1968 (NASA) | [Commons](https://commons.wikimedia.org/wiki/File:NASA-Apollo8-Dec24-Earthrise.jpg) | +| `photocraft-masks.jpg` | *Girl with a Pearl Earring*, Johannes Vermeer, c. 1665 | [Commons](https://commons.wikimedia.org/wiki/File:1665_Girl_with_a_Pearl_Earring.jpg) | +| `photocraft-vector.jpg` | *Water Lilies*, Claude Monet, 1906 | [Commons](https://commons.wikimedia.org/wiki/File:Claude_Monet_-_Water_Lilies_-_1906,_Ryerson.jpg) | +| `photocraft-filters.jpg` | *The Starry Night*, Vincent van Gogh, 1889 | [Commons](https://commons.wikimedia.org/wiki/File:Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg) | +| `photocraft-adjustments.jpg` | *Impression, Sunrise*, Claude Monet, 1872 | [Commons](https://commons.wikimedia.org/wiki/File:Monet_-_Impression,_Sunrise.jpg) | +| `photocraft-transform.jpg` | *The Tetons and the Snake River*, Ansel Adams, 1942 (U.S. National Archives) | [Commons](https://commons.wikimedia.org/wiki/File:Adams_The_Tetons_and_the_Snake_River.jpg) | +| `photocraft-type.jpg` | *Among the Sierra Nevada, California*, Albert Bierstadt, 1868 | [Commons](https://commons.wikimedia.org/wiki/File:Albert_Bierstadt_-_Among_the_Sierra_Nevada,_California_-_Google_Art_Project.jpg) | +| `photocraft-export-light.jpg` | *The Kiss*, Gustav Klimt, 1907–1908 | [Commons](https://commons.wikimedia.org/wiki/File:Gustav_Klimt_016.jpg) | + +## Test data (not committed, not shipped) + +`corpus/` is gitignored and no test fixtures are committed to the repository. +`cargo xtask corpus --all` fetches every corpus at the pinned commits in `xtask/src/corpus_pins.rs` +and verifies each file against the sha256 lists in `xtask/*.sha256`, with the upstream licence +next to the files: + +| Path (fetched) | Title | Author | Source | License | +|---|---|---|---|---| +| `corpus/photoshop/` (256 PSDs) | Photoshop oracle corpus: smart filters, layer-style effects, type, adjustments in every mode and depth | PhotoCraft contributors (authored with Adobe Photoshop 2026 by a script) | [https://github.com/storytold/photocraft-corpus](https://github.com/storytold/photocraft-corpus) (`photoshop/`, with its generator and README) | MIT OR Apache-2.0 | +| `corpus/psd-tools/` (309 files) | psd-tools test set | Kota Yamaguchi and contributors | [psd-tools `tests/psd_files`](https://github.com/psd-tools/psd-tools/tree/main/tests/psd_files) | MIT, Copyright (c) 2019 Kota Yamaguchi | +| `corpus/psd/` (170 files) | Small selection of the psd-tools and ag-psd test files | Kota Yamaguchi; Agamnentzar | psd-tools (above) and [ag-psd `test/`](https://github.com/Agamnentzar/ag-psd/tree/master/test) | MIT (both) | +| `corpus/heif/` (9 files, 0.1 MB) | HEIC/HEIF test files: `heic-rs/` checkerboards, RGB strips and a grid-tiled photo with EXIF and XMP (synthetic pixels encoded by macOS `sips`, each `.ref.png` Apple's decode); `pillow-heif/` the 10-bit RGBA `RGBA_10__29x100.heif` and its source `RGBA_16__29x100.png` | Thomas Braun (heic-rs); Pillow-Heif contributors | [heic-rs `tests/fixtures`](https://github.com/tbraun96/heic-rs/tree/main/tests/fixtures), [pillow-heif `tests/images`](https://github.com/bigcat88/pillow_heif/tree/master/tests/images) | MIT OR Apache-2.0 (heic-rs); BSD-3-Clause (pillow-heif) | +| `corpus/exr/` (5 files, 2.3 MB) | The deep OpenEXR test images `11`, `42`, `64`, `multivariate` and `objectid.deep.exr` | Contributors to the OpenEXR Project | [openexr `src/test/bin/test_images`](https://github.com/AcademySoftwareFoundation/openexr/tree/main/src/test/bin/test_images) | BSD-3-Clause | +| `corpus/affinity/` (60 files) | Public Affinity documents and PNG references: `vector-art/` (9 documents), `afdesignload/` (9), `jac21/` (2), `asset-store-template/` (1), and `affinity-samples/` (18 CC0 documents plus exported references) | samuel-etver; Nick Beeuwsaert; Jeremy Cantu; DAIKI (eviltwo); satoshoe-dev | [vector-art `simple/`](https://github.com/samuel-etver/vector-art/tree/255f8add3c8f0740196e22bd59502b811b532f0b/simple), [AFDesignLoad `testDesigns/`](https://github.com/NickBeeuwsaert/AFDesignLoad/tree/a18dd50a7079fb861a28835eeefa0d015f03f4a1/testDesigns), [Jac21/Branding `Logos/JC/DesignerFiles/Affinity`](https://github.com/Jac21/Branding/tree/57ae3f45bf4637f6927c0b07de25b922c55f944f/Logos/JC/DesignerFiles/Affinity), [AssetStoreTemplate `AssetStoreTemplate/`](https://github.com/eviltwo/AssetStoreTemplate/tree/f671981ee89d15526285b3cc87b4393d3defe644/AssetStoreTemplate), [affinity-samples](https://github.com/satoshoe-dev/affinity-samples/tree/96aca6bd86bbe7a677f1cf0630bd832d23943be8) | CC0-1.0 (vector-art and affinity-samples); MIT, Copyright (c) 2015 Nick Beeuwsaert; MIT, Copyright (c) 2018 Jeremy Cantu; MIT, Copyright (c) 2024 DAIKI | +| `corpus/pngsuite/` | PngSuite | Willem van Schaik | | Public domain | +| `corpus/pixls/` (11 files) | Real camera raws, one per decode path: Canon PowerShot SX50 HS (CR2 and its DNG conversion), Nikon D3 uncompressed NEF and Z6 paired 12/14-bit lossy and packed NEFs, Sony DSC-RX0 cRAW ARW, Panasonic DC-G9 high-res RW2, Olympus E-1 GRBG ORF, plus the E-5 packed ORF as the documented known-unsupported case. Per file (each CC0, per its database entry): [IMG_4059.CR2](https://raw.pixls.us/data/Canon/PowerShot%20SX50%20HS/IMG_4059.CR2), [CRW_4061.DNG](https://raw.pixls.us/data/Canon/PowerShot%20SX50%20HS/CRW_4061.DNG), [JD1_8203.NEF](https://raw.pixls.us/data/Nikon/D3/JD1_8203.NEF), [DSC00009.ARW](https://raw.pixls.us/data/Sony/DSC-RX0/DSC00009.ARW), [P1000475.RW2](https://raw.pixls.us/data/Panasonic/DC-G9/P1000475.RW2), [E_1__C106743_gredos.ORF](https://raw.pixls.us/data/Olympus/E-1/E_1__C106743_gredos.ORF), [_7061961_copy.ORF](https://raw.pixls.us/data/Olympus/E-5/_7061961_copy.ORF), [DSC_0750.NEF](https://raw.pixls.us/data/Nikon/Z%206/DSC_0750.NEF), [DSC_0751.NEF](https://raw.pixls.us/data/Nikon/Z%206/DSC_0751.NEF), [DSC_0753.NEF](https://raw.pixls.us/data/Nikon/Z%206/DSC_0753.NEF), [DSC_0754.NEF](https://raw.pixls.us/data/Nikon/Z%206/DSC_0754.NEF) | The photographers of the pixls.us raw samples database | [raw.pixls.us](https://raw.pixls.us) `data/`, fetched per [xtask/src/corpus_pins.rs](xtask/src/corpus_pins.rs) | CC0 / public domain, per file as linked | + +Files copied into `corpus/` by hand (tiff, exr, raw) must be MIT, BSD or CC0. diff --git a/plugins/webguhui/minimax-photo/licenses/photocraft-NOTICE b/plugins/webguhui/minimax-photo/licenses/photocraft-NOTICE new file mode 100644 index 00000000..a7302a94 --- /dev/null +++ b/plugins/webguhui/minimax-photo/licenses/photocraft-NOTICE @@ -0,0 +1,24 @@ +PhotoCraft +Copyright (c) 2026 ArtCraft Team and the PhotoCraft contributors. +Licensed under the MIT License or the Apache License, Version 2.0, at your option +(LICENSE-MIT, LICENSE-APACHE). + +The ArtCraft name, wordmark and logos in docs/brand/ are trademarks of the ArtCraft Team. They are +not open source and are not covered by the license above; their terms are in +docs/brand/LICENSE-brand.txt. + +Third-party material + +This product bundles third-party material under its own licenses, listed below. The per-file +list (author, source, license) is in ATTRIBUTION.md. + +Inter font (assets/fonts/Inter-*.ttf) — SIL Open Font License 1.1. See assets/fonts/OFL-Inter.txt. +JetBrains Mono font (assets/fonts/JetBrainsMono-Regular.ttf) — SIL Open Font License 1.1. See assets/fonts/OFL-JetBrainsMono.txt. +Lucide icons (assets/icons/*.svg, except slice-knife.svg) — ISC; icons derived from Feather also MIT. See assets/icons/LICENSE-lucide.txt. +SCOWL English word list (assets/dict/en_US-scowl-50.txt.gz) — SCOWL license. See assets/dict/LICENSE-SCOWL.txt. +libfacedetection face detection weights and network (crates/algo/data/libfacedetection.bin, crates/algo/src/faces/cnn.rs) — BSD-3-Clause, Copyright (c) 2015-2019, Shiqi Yu, all rights reserved. See crates/algo/data/LICENSE-libfacedetection.txt. + +Builds made with craft-fonts (CRAFT_FONTS_DIR; all official releases) also embed the fonts listed in +https://github.com/storytold/craft-fonts/blob/main/ATTRIBUTION.md (today BIZ UDPGothic, Shippori Mincho and +BIZ UDMincho; not the web build), under the SIL Open Font License 1.1. Their licence texts +ship with the package as OFL-.txt. diff --git a/plugins/webguhui/minimax-photo/licenses/third-party-licenses.txt b/plugins/webguhui/minimax-photo/licenses/third-party-licenses.txt new file mode 100644 index 00000000..ffca94b5 --- /dev/null +++ b/plugins/webguhui/minimax-photo/licenses/third-party-licenses.txt @@ -0,0 +1,3673 @@ +shadcn/ui https://github.com/shadcn-ui/ui +MIT License + +Copyright (c) 2023 shadcn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@floating-ui/core/LICENSE +MIT License + +Copyright (c) 2021-present Floating UI contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +@floating-ui/dom/LICENSE +MIT License + +Copyright (c) 2021-present Floating UI contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +@floating-ui/react-dom/LICENSE +MIT License + +Copyright (c) 2021-present Floating UI contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +@floating-ui/utils/LICENSE +MIT License + +Copyright (c) 2021-present Floating UI contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +@isaacs/fs-minipass/LICENSE +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +@jridgewell/gen-mapping/LICENSE +Copyright 2024 Justin Ridgewell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@jridgewell/remapping/LICENSE +Copyright 2024 Justin Ridgewell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@jridgewell/resolve-uri/LICENSE +Copyright 2019 Justin Ridgewell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +@jridgewell/sourcemap-codec/LICENSE +Copyright 2024 Justin Ridgewell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@jridgewell/trace-mapping/LICENSE +Copyright 2024 Justin Ridgewell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@parcel/watcher/LICENSE +MIT License + +Copyright (c) 2017-present Devon Govett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@parcel/watcher-darwin-arm64/LICENSE +MIT License + +Copyright (c) 2017-present Devon Govett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/primitive/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-accessible-icon/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-accordion/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-alert-dialog/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-arrow/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-aspect-ratio/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-avatar/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-checkbox/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-collapsible/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-collection/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-context-menu/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-dialog/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-dismissable-layer/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-dropdown-menu/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-focus-guards/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-focus-scope/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-form/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-hover-card/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-label/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-menu/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-menubar/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-navigation-menu/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-one-time-password-field/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-password-toggle-field/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-popover/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-popper/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-portal/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-presence/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-primitive/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-progress/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-radio-group/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-roving-focus/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-scroll-area/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-select/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-separator/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-slider/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-slot/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-switch/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-tabs/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-toast/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-toggle/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-toggle-group/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-toolbar/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-tooltip/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-use-controllable-state/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-use-effect-event/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-use-is-hydrated/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@radix-ui/react-visually-hidden/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@tailwindcss/cli/LICENSE +MIT License + +Copyright (c) Tailwind Labs, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@tailwindcss/node/LICENSE +MIT License + +Copyright (c) Tailwind Labs, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@tailwindcss/oxide/LICENSE +MIT License + +Copyright (c) Tailwind Labs, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +@tailwindcss/oxide-darwin-arm64/LICENSE +MIT License + +Copyright (c) Tailwind Labs, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +aria-hidden/LICENSE +MIT License + +Copyright (c) 2017 Anton Korzunov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +chownr/LICENSE.md +All packages under `src/` are licensed according to the terms in +their respective `LICENSE` or `LICENSE.md` files. + +The remainder of this project is licensed under the Blue Oak +Model License, as follows: + +----- + +# Blue Oak Model License + +Version 1.0.0 + +## Purpose + +This license gives everyone as much permission to work with +this software as possible, while protecting contributors +from liability. + +## Acceptance + +In order to receive this license, you must agree to its +rules. The rules of this license are both obligations +under that agreement and conditions to your license. +You must not do anything with this software that triggers +a rule that you cannot or will not follow. + +## Copyright + +Each contributor licenses you to do everything with this +software that would otherwise infringe that contributor's +copyright in it. + +## Notices + +You must ensure that everyone who gets a copy of +any part of this software from you, with or without +changes, also gets the text of this license or a link to +. + +## Excuse + +If anyone notifies you in writing that you have not +complied with [Notices](#notices), you can keep your +license by taking all practical steps to comply within 30 +days after the notice. If you do not do so, your license +ends immediately. + +## Patent + +Each contributor licenses you to do everything with this +software that would otherwise infringe any patent claims +they can license or become able to license. + +## Reliability + +No contributor can revoke this license. + +## No Liability + +***As far as the law allows, this software comes as is, +without any warranty or condition, and no contributor +will be liable to anyone for any damages related to this +software or this license, under any kind of legal claim.*** + + +class-variance-authority/LICENSE + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2022 Joe Bell + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +clsx/license +MIT License + +Copyright (c) Luke Edwards (lukeed.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +detect-libc/LICENSE + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +detect-node-es/LICENSE +MIT License + +Copyright (c) 2017 Ilya Kantor + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +enhanced-resolve/LICENSE +Copyright JS Foundation and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +esbuild/LICENSE.md +MIT License + +Copyright (c) 2020 Evan Wallace + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +get-nonce/LICENSE +MIT License + +Copyright (c) 2020 Anton Korzunov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +graceful-fs/LICENSE +The ISC License + +Copyright (c) 2011-2022 Isaac Z. Schlueter, Ben Noordhuis, and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +is-extglob/LICENSE +The MIT License (MIT) + +Copyright (c) 2014-2016, Jon Schlinkert + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +is-glob/LICENSE +The MIT License (MIT) + +Copyright (c) 2014-2017, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +jiti/LICENSE +MIT License + +Copyright (c) Pooya Parsa + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +lightningcss/LICENSE + Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" +means each individual or legal entity that creates, contributes to +the creation of, or owns Covered Software. + +1.2. "Contributor Version" +means the combination of the Contributions of others (if any) used +by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" +means Covered Software of a particular Contributor. + +1.4. "Covered Software" +means Source Code Form to which the initial Contributor has attached +the notice in Exhibit A, the Executable Form of such Source Code +Form, and Modifications of such Source Code Form, in each case +including portions thereof. + +1.5. "Incompatible With Secondary Licenses" +means + +(a) that the initial Contributor has attached the notice described +in Exhibit B to the Covered Software; or + +(b) that the Covered Software was made available under the terms of +version 1.1 or earlier of the License, but not also under the +terms of a Secondary License. + +1.6. "Executable Form" +means any form of the work other than Source Code Form. + +1.7. "Larger Work" +means a work that combines Covered Software with other material, in +a separate file or files, that is not Covered Software. + +1.8. "License" +means this document. + +1.9. "Licensable" +means having the right to grant, to the maximum extent possible, +whether at the time of the initial grant or subsequently, any and +all of the rights conveyed by this License. + +1.10. "Modifications" +means any of the following: + +(a) any file in Source Code Form that results from an addition to, +deletion from, or modification of the contents of Covered +Software; or + +(b) any new file in Source Code Form that contains any Covered +Software. + +1.11. "Patent Claims" of a Contributor +means any patent claim(s), including without limitation, method, +process, and apparatus claims, in any patent Licensable by such +Contributor that would be infringed, but for the grant of the +License, by the making, using, selling, offering for sale, having +made, import, or transfer of either its Contributions or its +Contributor Version. + +1.12. "Secondary License" +means either the GNU General Public License, Version 2.0, the GNU +Lesser General Public License, Version 2.1, the GNU Affero General +Public License, Version 3.0, or any later versions of those +licenses. + +1.13. "Source Code Form" +means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") +means an individual or a legal entity exercising rights under this +License. For legal entities, "You" includes any entity that +controls, is controlled by, or is under common control with You. For +purposes of this definition, "control" means (a) the power, direct +or indirect, to cause the direction or management of such entity, +whether by contract or otherwise, or (b) ownership of more than +fifty percent (50%) of the outstanding shares or beneficial +ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) +Licensable by such Contributor to use, reproduce, make available, +modify, display, perform, distribute, and otherwise exploit its +Contributions, either on an unmodified basis, with Modifications, or +as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer +for sale, have made, import, and otherwise transfer either its +Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; +or + +(b) for infringements caused by: (i) Your and any other third party's +modifications of Covered Software, or (ii) the combination of its +Contributions with other software (except as part of its Contributor +Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of +its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code +Form, as described in Section 3.1, and You must inform recipients of +the Executable Form how they can obtain a copy of such Source Code +Form by reasonable means in a timely manner, at a charge no more +than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this +License, or sublicense it under different terms, provided that the +license for the Executable Form does not attempt to limit or alter +the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + +This Source Code Form is "Incompatible With Secondary Licenses", as +defined by the Mozilla Public License, v. 2.0. + + +lightningcss-darwin-arm64/LICENSE + Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" +means each individual or legal entity that creates, contributes to +the creation of, or owns Covered Software. + +1.2. "Contributor Version" +means the combination of the Contributions of others (if any) used +by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" +means Covered Software of a particular Contributor. + +1.4. "Covered Software" +means Source Code Form to which the initial Contributor has attached +the notice in Exhibit A, the Executable Form of such Source Code +Form, and Modifications of such Source Code Form, in each case +including portions thereof. + +1.5. "Incompatible With Secondary Licenses" +means + +(a) that the initial Contributor has attached the notice described +in Exhibit B to the Covered Software; or + +(b) that the Covered Software was made available under the terms of +version 1.1 or earlier of the License, but not also under the +terms of a Secondary License. + +1.6. "Executable Form" +means any form of the work other than Source Code Form. + +1.7. "Larger Work" +means a work that combines Covered Software with other material, in +a separate file or files, that is not Covered Software. + +1.8. "License" +means this document. + +1.9. "Licensable" +means having the right to grant, to the maximum extent possible, +whether at the time of the initial grant or subsequently, any and +all of the rights conveyed by this License. + +1.10. "Modifications" +means any of the following: + +(a) any file in Source Code Form that results from an addition to, +deletion from, or modification of the contents of Covered +Software; or + +(b) any new file in Source Code Form that contains any Covered +Software. + +1.11. "Patent Claims" of a Contributor +means any patent claim(s), including without limitation, method, +process, and apparatus claims, in any patent Licensable by such +Contributor that would be infringed, but for the grant of the +License, by the making, using, selling, offering for sale, having +made, import, or transfer of either its Contributions or its +Contributor Version. + +1.12. "Secondary License" +means either the GNU General Public License, Version 2.0, the GNU +Lesser General Public License, Version 2.1, the GNU Affero General +Public License, Version 3.0, or any later versions of those +licenses. + +1.13. "Source Code Form" +means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") +means an individual or a legal entity exercising rights under this +License. For legal entities, "You" includes any entity that +controls, is controlled by, or is under common control with You. For +purposes of this definition, "control" means (a) the power, direct +or indirect, to cause the direction or management of such entity, +whether by contract or otherwise, or (b) ownership of more than +fifty percent (50%) of the outstanding shares or beneficial +ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) +Licensable by such Contributor to use, reproduce, make available, +modify, display, perform, distribute, and otherwise exploit its +Contributions, either on an unmodified basis, with Modifications, or +as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer +for sale, have made, import, and otherwise transfer either its +Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; +or + +(b) for infringements caused by: (i) Your and any other third party's +modifications of Covered Software, or (ii) the combination of its +Contributions with other software (except as part of its Contributor +Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of +its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code +Form, as described in Section 3.1, and You must inform recipients of +the Executable Form how they can obtain a copy of such Source Code +Form by reasonable means in a timely manner, at a charge no more +than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this +License, or sublicense it under different terms, provided that the +license for the Executable Form does not attempt to limit or alter +the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + +This Source Code Form is "Incompatible With Secondary Licenses", as +defined by the Mozilla Public License, v. 2.0. + + +lucide-react/LICENSE +ISC License + +Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part of Feather (MIT). All other copyright (c) for Lucide are held by Lucide Contributors 2022. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +magic-string/LICENSE +Copyright 2018 Rich Harris + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +minipass/LICENSE.md +# Blue Oak Model License + +Version 1.0.0 + +## Purpose + +This license gives everyone as much permission to work with +this software as possible, while protecting contributors +from liability. + +## Acceptance + +In order to receive this license, you must agree to its +rules. The rules of this license are both obligations +under that agreement and conditions to your license. +You must not do anything with this software that triggers +a rule that you cannot or will not follow. + +## Copyright + +Each contributor licenses you to do everything with this +software that would otherwise infringe that contributor's +copyright in it. + +## Notices + +You must ensure that everyone who gets a copy of +any part of this software from you, with or without +changes, also gets the text of this license or a link to +. + +## Excuse + +If anyone notifies you in writing that you have not +complied with [Notices](#notices), you can keep your +license by taking all practical steps to comply within 30 +days after the notice. If you do not do so, your license +ends immediately. + +## Patent + +Each contributor licenses you to do everything with this +software that would otherwise infringe any patent claims +they can license or become able to license. + +## Reliability + +No contributor can revoke this license. + +## No Liability + +***As far as the law allows, this software comes as is, +without any warranty or condition, and no contributor +will be liable to anyone for any damages related to this +software or this license, under any kind of legal claim.*** + + +minizlib/LICENSE +Minizlib was created by Isaac Z. Schlueter. +It is a derivative work of the Node.js project. + +""" +Copyright (c) 2017-2023 Isaac Z. Schlueter and Contributors +Copyright (c) 2017-2023 Node.js contributors. All rights reserved. +Copyright (c) 2017-2023 Joyent, Inc. and other Node contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" + + +mri/license.md +The MIT License (MIT) + +Copyright (c) Luke Edwards (lukeed.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +node-addon-api/LICENSE.md +The MIT License (MIT) + +Copyright (c) 2017 [Node.js API collaborators](https://github.com/nodejs/node-addon-api#collaborators) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +picocolors/LICENSE +ISC License + +Copyright (c) 2021-2024 Oleksii Raspopov, Kostiantyn Denysov, Anton Verinov + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +picomatch/LICENSE +The MIT License (MIT) + +Copyright (c) 2017-present, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +radix-ui/LICENSE +MIT License + +Copyright (c) 2022 WorkOS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +react/LICENSE +MIT License + +Copyright (c) Meta Platforms, Inc. and affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +react-dom/LICENSE +MIT License + +Copyright (c) Meta Platforms, Inc. and affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +react-remove-scroll/LICENSE +MIT License + +Copyright (c) 2017 Anton Korzunov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +react-style-singleton/LICENSE +MIT License + +Copyright (c) 2017 Anton Korzunov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +scheduler/LICENSE +MIT License + +Copyright (c) Meta Platforms, Inc. and affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +source-map-js/LICENSE + +Copyright (c) 2009-2011, Mozilla Foundation and contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the names of the Mozilla Foundation nor the names of project + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +tailwind-merge/LICENSE.md +MIT License + +Copyright (c) 2021 Dany Castillo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +tailwindcss/LICENSE +MIT License + +Copyright (c) Tailwind Labs, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +tapable/LICENSE +The MIT License + +Copyright JS Foundation and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +tar/LICENSE.md +# Blue Oak Model License + +Version 1.0.0 + +## Purpose + +This license gives everyone as much permission to work with +this software as possible, while protecting contributors +from liability. + +## Acceptance + +In order to receive this license, you must agree to its +rules. The rules of this license are both obligations +under that agreement and conditions to your license. +You must not do anything with this software that triggers +a rule that you cannot or will not follow. + +## Copyright + +Each contributor licenses you to do everything with this +software that would otherwise infringe that contributor's +copyright in it. + +## Notices + +You must ensure that everyone who gets a copy of +any part of this software from you, with or without +changes, also gets the text of this license or a link to +. + +## Excuse + +If anyone notifies you in writing that you have not +complied with [Notices](#notices), you can keep your +license by taking all practical steps to comply within 30 +days after the notice. If you do not do so, your license +ends immediately. + +## Patent + +Each contributor licenses you to do everything with this +software that would otherwise infringe any patent claims +they can license or become able to license. + +## Reliability + +No contributor can revoke this license. + +## No Liability + +***As far as the law allows, this software comes as is, +without any warranty or condition, and no contributor +will be liable to anyone for any damages related to this +software or this license, under any kind of legal claim.*** + + +tslib/LICENSE.txt +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +use-callback-ref/LICENSE +MIT License + +Copyright (c) 2017 Anton Korzunov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +use-sidecar/LICENSE +MIT License + +Copyright (c) 2017 Anton Korzunov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +use-sync-external-store/LICENSE +MIT License + +Copyright (c) Meta Platforms, Inc. and affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +yallist/LICENSE.md +All packages under `src/` are licensed according to the terms in +their respective `LICENSE` or `LICENSE.md` files. + +The remainder of this project is licensed under the Blue Oak +Model License, as follows: + +----- + +# Blue Oak Model License + +Version 1.0.0 + +## Purpose + +This license gives everyone as much permission to work with +this software as possible, while protecting contributors +from liability. + +## Acceptance + +In order to receive this license, you must agree to its +rules. The rules of this license are both obligations +under that agreement and conditions to your license. +You must not do anything with this software that triggers +a rule that you cannot or will not follow. + +## Copyright + +Each contributor licenses you to do everything with this +software that would otherwise infringe that contributor's +copyright in it. + +## Notices + +You must ensure that everyone who gets a copy of +any part of this software from you, with or without +changes, also gets the text of this license or a link to +. + +## Excuse + +If anyone notifies you in writing that you have not +complied with [Notices](#notices), you can keep your +license by taking all practical steps to comply within 30 +days after the notice. If you do not do so, your license +ends immediately. + +## Patent + +Each contributor licenses you to do everything with this +software that would otherwise infringe any patent claims +they can license or become able to license. + +## Reliability + +No contributor can revoke this license. + +## No Liability + +***As far as the law allows, this software comes as is, +without any warranty or condition, and no contributor +will be liable to anyone for any damages related to this +software or this license, under any kind of legal claim.*** + + +PTC runtime: quickjs-emscripten / quickjs-emscripten-core / @jitl/quickjs-wasmfile-release-sync 0.32.0 +quickjs-emscripten: +The MIT License + +quickjs-emscripten copyright (c) 2019-2024 Jake Teton-Landis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +quickjs: +QuickJS Javascript Engine + +Copyright (c) 2017-2021 Fabrice Bellard +Copyright (c) 2017-2021 Charlie Gordon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/plugins/webguhui/minimax-photo/miniapp/client/adjustment-layers.js b/plugins/webguhui/minimax-photo/miniapp/client/adjustment-layers.js new file mode 100644 index 00000000..544034eb --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/adjustment-layers.js @@ -0,0 +1,85 @@ +import { adjustments } from './catalog.js'; +import { filterPixels } from './filters.js'; +import { curveLUT } from './tone.js'; +import { blendPixel, dissolveCoverage } from './blending.js'; + +export function clippingBase(layers, index) { + let base = index - 1; + while (base >= 0 && layers[base].adjustment && layers[base].clipToBelow) base--; + return base >= 0 && !layers[base].adjustment ? base : -1; +} + +// Consecutive clipped adjustments belong to the ordinary layer immediately below. +// Orphan clipped adjustments are inert, never silently applied to the whole document. +export function compositionGroups(layers) { + const groups = []; + for (let i = 0; i < layers.length; i++) { + const base = layers[i]; + if (base.adjustment) { + if (!base.clipToBelow) groups.push({ base, adjustments: [] }); + continue; + } + const adjustments = []; + while (layers[i + 1]?.adjustment && layers[i + 1].clipToBelow) adjustments.push(layers[++i]); + groups.push({ base, adjustments }); + } + return groups; +} + +export function normalizeAdjustment(value) { + if (value?.type === 'curves') { + if (!value.value?.curves || typeof value.value.curves !== 'object') + throw Error('曲线调整参数无效'); + const curves = {}; + for (const channel of ['rgb', 'red', 'green', 'blue']) { + const points = value.value.curves[channel] || [ + [0, 0], + [64, 64], + [128, 128], + [192, 192], + [255, 255], + ]; + curveLUT(points); + curves[channel] = points.map(([x, y]) => [x, y]); + } + return { type: 'curves', value: { curves } }; + } + const item = adjustments.find((a) => a[0] === value?.type); + if (!item || !Number.isFinite(value.value)) throw Error('调整图层参数无效'); + return { type: item[0], value: Math.max(item[3], Math.min(item[4], value.value)) }; +} + +// Adjustment layers transform the already-composited layers below them. +// Interpolate color instead of source-over, which would incorrectly increase alpha. +export function adjustedPixels( + source, + width, + height, + adjustment, + opacity = 1, + mask = null, + blend = 'source-over', + originX = 0, + originY = 0, +) { + const setting = normalizeAdjustment(adjustment); + const changed = filterPixels(source, width, height, setting.type, setting.value); + const output = new Uint8ClampedArray(source); + const mixed = new Float64Array(3); + for (let i = 0; i < source.length; i += 4) { + let weight = opacity * (mask ? mask[i + 3] / 255 : 1); + if (blend === 'dissolve') + weight = dissolveCoverage( + weight, + originX + ((i / 4) % width), + originY + Math.floor(i / 4 / width), + ); + if (blend !== 'source-over') blendPixel(blend, source, changed, i, mixed); + for (let channel = 0; channel < 3; channel++) + output[i + channel] = + source[i + channel] + + ((blend === 'source-over' ? changed[i + channel] : mixed[channel]) - source[i + channel]) * + weight; + } + return output; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/agent-dialog.js b/plugins/webguhui/minimax-photo/miniapp/client/agent-dialog.js new file mode 100644 index 00000000..a0911a28 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/agent-dialog.js @@ -0,0 +1,49 @@ +import { composite } from './model.js'; + +export function createAgentRequest(state, getEditor) { + let prepared = null; + return async (mode, request) => { + const editor = getEditor(); + request = request.trim(); + if (!request) throw Error('请填写修图需求'); + if (mode === 'edit' && !state.doc) throw Error('请先打开图片'); + let text; + if (mode === 'workbench') { + if (!editor) throw Error('编辑器尚未连接'); + text = `请在修图工作台直接完成编辑。需求:${request}\n目标 editorId:${editor.editorId}。先调用 editor_capabilities 和 editor_inspect。多步任务可调用 editor_run_code 提交 JavaScript:用 await editor.inspect()、preview(options)、edit(operations)、create({width,height,name})、export(),根据真实结果使用循环和条件;必须逐个 await。用 editor_code_result 查询 runId 并查看最终预览。脚本整体不回滚,错误时查 trace 和 editor_job,不能换编号重复执行。简单编辑也可用 editor_batch。保留用户已有内容,除非需求明确要求删除。`; + } else { + const doc = state.doc; + const key = JSON.stringify([mode, request, doc?.id]); + if (!prepared || prepared.key !== key) { + const response = await fetch('/api/agent/requests', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + mode: mode, + prompt: request, + name: doc?.name || 'Agent 图片', + reference: mode === 'edit' ? composite(doc).toDataURL('image/png') : undefined, + }), + }); + const record = await response.json(); + if (!response.ok) throw Error(record.error || '保存图片需求失败'); + prepared = { key, id: record.id }; + } + text = `\n请处理修图工作台图片任务 ${prepared.id}。\n需求:${request}\n先调用 retouch-images 的 get_image_request,requestId 为 ${prepared.id},读取任务和参考图路径。使用可用的生图或改图工具生成 PNG,再调用 submit_image_result,以同一 requestId 和生成文件的本机绝对路径 imagePath 交回结果。不要改写原工程。若工具不可用,请说明限制并提供可下载图片,供手动导入。\n`; + } + + const message = window.mcode?.miniapp?.message; + if (typeof message?.append !== 'function') return { text }; + try { + await message.append(text); + return { delivered: true }; + } catch (error) { + const messages = { + user_cancelled: '已取消,需求未加入聊天', + result_unknown: '结果未确认,请先检查聊天输入框,避免重复添加', + target_unavailable: '当前没有可用的目标聊天,请从聊天中打开 Mini App 后重试', + }; + throw Error(messages[error?.message] || '未能加入聊天,请检查目标聊天后重试'); + } + }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/agent-results.js b/plugins/webguhui/minimax-photo/miniapp/client/agent-results.js new file mode 100644 index 00000000..c2b7c92a --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/agent-results.js @@ -0,0 +1,39 @@ +import { note } from './dialogs.js'; +export function installAgentResults({ modal, button, importFiles, status }) { + const events = new EventSource('/api/agent/events'); + events.addEventListener('result', () => status('Agent 图片已返回,点击“Agent 图片”查看')); + window.addEventListener('pagehide', () => events.close(), { once: true }); + return async function showResults() { + const response = await fetch('/api/agent/requests'); + if (!response.ok) throw Error('读取 Agent 图片失败'); + const { requests } = await response.json(); + const rows = requests.map((record) => { + const row = document.createElement('div'); + row.className = 'project-row'; + const label = document.createElement('span'); + label.textContent = record.prompt; + label.title = record.prompt; + row.append(label); + if (record.status === 'ready') + row.append( + button('打开图片', async () => { + const response = await fetch(`/api/agent/requests/${record.id}/result`); + if (!response.ok) throw Error('读取返回图片失败'); + const file = new File([await response.blob()], record.name + ' — Agent.png', { + type: 'image/png', + }); + await importFiles([file]); + document.querySelector('#dialog').close(); + }), + ); + else row.append(note('等待 Agent 返回')); + return row; + }); + modal( + 'Agent 图片', + rows.length ? rows : [note('还没有图片任务,点击“交给 Agent”创建。')], + () => {}, + '关闭', + ); + }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/app.js b/plugins/webguhui/minimax-photo/miniapp/client/app.js new file mode 100644 index 00000000..8639a788 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/app.js @@ -0,0 +1,1207 @@ +import { installEditorBridge } from './editor-bridge.js'; +import { installAgentResults } from './agent-results.js'; +import { mountActions, mountTools, mountAgentPanel } from './workbench-ui.js'; +import { createAgentRequest } from './agent-dialog.js'; +import { runOutline } from './selection-outline.js'; +import { createDialogs, field, note } from './dialogs.js'; +import { showCurvesDialog } from './curves-dialog.js'; +import { showFilterDialog } from './filter-dialog.js'; +import { showStylesDialog } from './styles-dialog.js'; +import { clippingBase } from './adjustment-layers.js'; +import { toggleRecording } from './recording.js'; +import { tools, adjustments, filters } from './catalog.js'; +import { installCanvasTools } from './canvas-tools.js'; +import { createFileActions } from './files.js'; +import { + canvas, + cloneCanvas, + layer, + documentModel, + active, + begin, + undo, + redo, + composite, + clipSelection, + selectionPath, + serialize, + deserialize, + imageFrom, + download, + blends, + blendNames, +} from './model.js'; +import { readPSD, writePSD, exportPDF } from './codecs.js'; +mountActions(); +const $ = (s) => document.querySelector(s), + image = $('#image'), + overlay = $('#overlay'), + stage = $('#stage'), + wrap = $('#canvas-wrap'), + dialog = $('#dialog'); +const state = { + docs: [], + doc: null, + tool: 'move', + zoom: 1, + pan: { x: 0, y: 0 }, + drag: null, + raf: 0, + needsRender: false, + clipboard: null, + cloneSource: null, + filterJob: 0, + busy: false, + maskEditing: false, + grid: false, + viewRotation: 0, + penPoints: [], +}; +const worker = new Worker('/filter-worker.js', { type: 'module' }), + pending = new Map(); +worker.onmessage = ({ data }) => { + const p = pending.get(data.id); + if (!p) return; + pending.delete(data.id); + data.error ? p.reject(Error(data.error)) : p.resolve(new Uint8ClampedArray(data.buffer)); +}; +worker.onerror = () => { + for (const p of pending.values()) p.reject(Error('图像处理进程异常,请刷新后重试')); + pending.clear(); + state.busy = false; +}; +function status(text, error = false) { + $('#status').textContent = text; + $('#status').classList.toggle('error', error); +} +function safe(fn) { + return async (...args) => { + try { + await fn(...args); + } catch (e) { + status(e.message || '操作失败', true); + console.error(e); + } + }; +} +function requireDoc() { + if (!state.doc) throw Error('请先打开图片或新建画布'); + if (state.busy) throw Error('正在处理图像,请稍候'); + return state.doc; +} +function editable() { + requireDoc(); + const l = active(state.doc); + if (l.locked) throw Error('当前图层已锁定'); + return l; +} +function pixelEditable(allowMask = false) { + const l = editable(); + if (l.adjustment && !(allowMask && state.maskEditing && l.mask)) + throw Error('调整图层没有可绘制像素,请编辑调整参数或选择普通图层'); + return l; +} +function button(text, fn) { + const b = document.createElement('button'); + b.type = 'button'; + b.textContent = text; + b.addEventListener('click', safe(fn)); + return b; +} +const { modal } = createDialogs(dialog, status); +function setDoc(d) { + state.polygonDraft = null; + state.doc = d; + state.maskEditing = false; + state.viewRotation = 0; + $('#welcome').hidden = true; + refresh(); + fit(); +} +function addDoc(d) { + state.docs.push(d); + setDoc(d); +} +let editorChanged = () => {}; +let agentPanel; +function refresh() { + editorChanged(); + agentPanel?.refresh(); + if (!state.doc) return; + $('#tabs').replaceChildren( + ...state.docs.map((d) => { + const b = button(d.name + (d.dirty ? ' •' : ''), () => setDoc(d)); + b.setAttribute('role', 'tab'); + b.setAttribute('aria-selected', String(d === state.doc)); + return b; + }), + ); + renderLayers(); + $('#dimensions').textContent = + `${state.doc.width} × ${state.doc.height} · ${state.doc.layers.length} 图层`; + $('#undo').disabled = !state.doc.history.length; + $('#redo').disabled = !state.doc.future.length; + $('#history').replaceChildren( + ...state.doc.history.slice(-12).map((e) => { + const li = document.createElement('li'); + li.textContent = e.label; + return li; + }), + ); + schedule(); +} +function schedule(renderContent = true) { + state.needsRender ||= renderContent; + if (state.raf) return; + state.raf = requestAnimationFrame(() => { + state.raf = 0; + const render = state.needsRender; + state.needsRender = false; + if (render) draw(); + else if (state.doc) { + drawOverlay(); + position(); + } + }); +} +function draw() { + if (!state.doc) return; + composite(state.doc, image); + if (overlay.width !== state.doc.width) overlay.width = state.doc.width; + if (overlay.height !== state.doc.height) overlay.height = state.doc.height; + drawOverlay(); + position(); +} +function drawOverlay() { + if (!state.doc) return; + const ctx = overlay.getContext('2d'); + ctx.clearRect(0, 0, overlay.width, overlay.height); + ctx.save(); + ctx.lineWidth = 1 / state.zoom; + ctx.strokeStyle = '#ffffff'; + ctx.setLineDash([5 / state.zoom, 4 / state.zoom]); + const s = state.drag?.selection || state.doc.selection; + if (s) { + let outline = selectionPath(s); + if (s.kind === 'runs') { + outline = new Path2D(); + for (const [x1, y1, x2, y2] of runOutline(s.runs)) { + outline.moveTo(x1, y1); + outline.lineTo(x2, y2); + } + } + ctx.stroke(outline); + ctx.strokeStyle = '#101010'; + ctx.lineDashOffset = 5 / state.zoom; + ctx.stroke(outline); + } + ctx.setLineDash([]); + if (state.grid) { + ctx.strokeStyle = '#8885'; + for (let x = 0; x < state.doc.width; x += 50) { + ctx.beginPath(); + ctx.moveTo(x, 0); + ctx.lineTo(x, state.doc.height); + ctx.stroke(); + } + for (let y = 0; y < state.doc.height; y += 50) { + ctx.beginPath(); + ctx.moveTo(0, y); + ctx.lineTo(state.doc.width, y); + ctx.stroke(); + } + } + if (state.polygonDraft) { + const { points, hover } = state.polygonDraft; + ctx.strokeStyle = '#fff'; + ctx.lineWidth = 1.5 / state.zoom; + ctx.beginPath(); + points.forEach((p, i) => (i ? ctx.lineTo(p.x, p.y) : ctx.moveTo(p.x, p.y))); + if (hover) ctx.lineTo(hover.x, hover.y); + ctx.stroke(); + ctx.fillStyle = '#227fa8'; + for (const p of points) { + ctx.fillRect(p.x - 3 / state.zoom, p.y - 3 / state.zoom, 6 / state.zoom, 6 / state.zoom); + ctx.strokeRect(p.x - 3 / state.zoom, p.y - 3 / state.zoom, 6 / state.zoom, 6 / state.zoom); + } + } + if (state.penPoints.length) { + ctx.strokeStyle = $('#color').value; + ctx.lineWidth = 2 / state.zoom; + ctx.beginPath(); + state.penPoints.forEach((p, i) => (i ? ctx.lineTo(p.x, p.y) : ctx.moveTo(p.x, p.y))); + ctx.stroke(); + for (const p of state.penPoints) { + ctx.fillStyle = '#fff'; + ctx.fillRect(p.x - 3 / state.zoom, p.y - 3 / state.zoom, 6 / state.zoom, 6 / state.zoom); + } + } + ctx.restore(); +} +function position() { + wrap.style.width = state.doc.width + 'px'; + wrap.style.height = state.doc.height + 'px'; + wrap.style.transform = `translate(${state.pan.x}px,${state.pan.y}px) scale(${state.zoom}) rotate(${state.viewRotation}deg)`; + $('#zoom-value').textContent = Math.round(state.zoom * 100) + '%'; +} +function fit() { + if (!state.doc) return; + state.viewRotation = 0; + state.zoom = Math.min( + 1, + (stage.clientWidth - 70) / state.doc.width, + (stage.clientHeight - 70) / state.doc.height, + ); + state.zoom = Math.max(0.02, state.zoom); + state.pan = { + x: (stage.clientWidth - state.doc.width * state.zoom) / 2, + y: (stage.clientHeight - state.doc.height * state.zoom) / 2, + }; + schedule(false); +} +function changeZoom(factor) { + if (!state.doc) return; + const old = state.zoom; + state.zoom = Math.max(0.02, Math.min(16, state.zoom * factor)); + state.pan.x = stage.clientWidth / 2 - ((stage.clientWidth / 2 - state.pan.x) * state.zoom) / old; + state.pan.y = + stage.clientHeight / 2 - ((stage.clientHeight / 2 - state.pan.y) * state.zoom) / old; + schedule(false); +} +function renderLayers() { + const current = active(state.doc); + $('#blend').value = current.blend; + $('#blend').disabled = false; + $('#layer-opacity').value = Math.round(current.opacity * 100); + $('#layers').replaceChildren( + ...[...state.doc.layers].reverse().map((l) => { + const row = document.createElement('div'); + row.className = 'layer' + (l.id === state.doc.activeId ? ' selected' : ''); + row.onclick = () => { + state.doc.activeId = l.id; + state.maskEditing = false; + refresh(); + }; + const eye = document.createElement('input'); + eye.type = 'checkbox'; + eye.checked = l.visible; + eye.setAttribute('aria-label', '可见 ' + l.name); + eye.onclick = (e) => e.stopPropagation(); + eye.onchange = safe(() => { + requireDoc(); + begin(state.doc, '图层可见性'); + state.doc.layers.find((x) => x.id === l.id).visible = eye.checked; + refresh(); + }); + const thumb = canvas(32, 26); + thumb.getContext('2d').drawImage(l.canvas, 0, 0, 32, 26); + const name = document.createElement('input'); + name.type = 'text'; + name.value = l.name; + name.setAttribute('aria-label', '图层名称'); + name.onclick = (e) => { + e.stopPropagation(); + state.doc.activeId = l.id; + state.maskEditing = false; + for (const other of $('#layers').children) + other.classList.toggle('selected', other === row); + $('#blend').value = l.blend; + $('#blend').disabled = false; + $('#layer-opacity').value = Math.round(l.opacity * 100); + }; + name.onchange = safe(() => { + requireDoc(); + begin(state.doc, '重命名图层'); + state.doc.layers.find((x) => x.id === l.id).name = name.value.slice(0, 200) || '图层'; + refresh(); + }); + const lock = button(l.locked ? '已锁' : '锁定', (e) => { + e.stopPropagation(); + requireDoc(); + begin(state.doc, '图层锁定'); + state.doc.layers.find((x) => x.id === l.id).locked = !l.locked; + refresh(); + }); + lock.setAttribute('aria-label', (l.locked ? '解锁 ' : '锁定 ') + l.name); + row.append(eye, thumb, name, lock); + if (l.adjustment) { + const edit = button(l.clipToBelow ? '↳ 调整' : '调整', (e) => { + e.stopPropagation(); + editAdjustment(l); + }); + edit.className = 'adjustment-thumb'; + edit.setAttribute('aria-label', '编辑 ' + l.name); + edit.title = l.clipToBelow ? '只调整下方图层' : '调整下方所有图层'; + row.replaceChild(edit, thumb); + } + if (l.mask) { + const m = button(state.maskEditing && current.id === l.id ? '绘制蒙版' : '蒙版', (e) => { + e.stopPropagation(); + state.doc.activeId = l.id; + state.maskEditing = !state.maskEditing; + setTool('brush'); + refresh(); + status(state.maskEditing ? '正在绘制蒙版:橡皮擦隐藏,画笔恢复' : '正在绘制图层'); + }); + row.append(m); + } + return row; + }), + ); +} +function setTool(id) { + state.polygonDraft = null; + state.tool = id; + $('#tolerance-option').hidden = ![ + 'fill', + 'wand', + 'magicEraser', + 'backgroundEraser', + 'colorReplace', + ].includes(id); + const t = tools.find((t) => t[0] === id); + $('#tool-name').textContent = t[1]; + $('#hint').textContent = t[3]; + $('#tool-help').textContent = t[3]; + for (const b of $('#tools').querySelectorAll('[data-tool]')) + b.setAttribute('aria-pressed', String(b.dataset.tool === id)); + overlay.style.cursor = ['hand', 'move'].includes(id) + ? 'grab' + : id === 'text' + ? 'text' + : 'crosshair'; + state.penPoints = []; + schedule(false); +} +mountTools($('#tools'), tools, setTool); +blends.forEach((v, i) => { + const o = document.createElement('option'); + o.value = v; + o.textContent = blendNames[i]; + $('#blend').append(o); +}); +function mutate(label, fn, ids = []) { + requireDoc(); + begin(state.doc, label, ids); + fn(); + refresh(); + status(label + '完成'); +} +function newLayer() { + requireDoc(); + if (state.doc.layers.length >= 100) throw Error('最多 100 个图层'); + mutate('新建图层', () => { + const l = layer(state.doc.width, state.doc.height, '图层 ' + (state.doc.layers.length + 1)); + state.doc.layers.push(l); + state.doc.activeId = l.id; + }); +} +function newAdjustment() { + requireDoc(); + if (state.doc.layers.length >= 100) throw Error('最多 100 个图层'); + const select = document.createElement('select'); + select.setAttribute('aria-label', '调整类型'); + for (const item of [...adjustments, ['curves', '曲线']]) { + const option = document.createElement('option'); + option.value = item[0]; + option.textContent = item[1]; + select.append(option); + } + modal( + '新建调整图层', + [select, note('调整图层影响它下方的所有可见图层,原始像素保持不变。')], + () => configureAdjustment(select.value), + '下一步', + ); +} +function editAdjustment(l) { + requireDoc(); + if (!l?.adjustment) throw Error('请选择调整图层'); + if (l.locked) throw Error('当前图层已锁定'); + configureAdjustment(l.adjustment.type, l); +} +function configureAdjustment(type, existing = null) { + const d = requireDoc(), + item = type === 'curves' ? ['curves', '曲线'] : [...adjustments.find((a) => a[0] === type)]; + const index = existing + ? d.layers.indexOf(existing) + : d.layers.findIndex((l) => l.id === d.activeId) + 1; + const clippedBase = existing?.clipToBelow ? clippingBase(d.layers, index) : -1; + const source = + existing?.clipToBelow && clippedBase < 0 + ? canvas(d.width, d.height) + : composite({ ...d, layers: d.layers.slice(clippedBase >= 0 ? clippedBase : 0, index) }); + if (existing) item[2] = existing.adjustment.value; + const options = { + modal, + runFilter, + description: existing?.clipToBelow + ? '只调整下方普通图层。预览显示该图层;已有蒙版、强度和混合模式在应用后生效。' + : '预览显示下方图层的合成图。调整参数可再次编辑;已有蒙版、不透明度和混合模式在应用后生效。', + applyFilter: (type, value) => + mutate(existing ? '编辑调整图层' : '新建调整图层', () => { + let target = existing ? d.layers.find((l) => l.id === existing.id) : null; + if (!target) { + target = layer(d.width, d.height, item[1] + ' · 调整'); + if (d.selection) { + target.mask = canvas(d.width, d.height); + const ctx = target.mask.getContext('2d'); + ctx.save(); + clipSelection(ctx, d, target); + ctx.fillStyle = '#fff'; + ctx.fillRect(0, 0, d.width, d.height); + ctx.restore(); + } + d.layers.splice(index, 0, target); + } + target.adjustment = { type, value }; + d.activeId = target.id; + state.maskEditing = false; + }), + }; + if (type === 'curves') + showCurvesDialog(source, { ...options, initialCurves: existing?.adjustment.value.curves }); + else showFilterDialog(source, item, options); +} +function toggleAdjustmentClipping() { + const l = editable(); + if (!l.adjustment) throw Error('请选择调整图层'); + const index = state.doc.layers.indexOf(l); + if (!l.clipToBelow && clippingBase(state.doc.layers, index) < 0) + throw Error('下方需要普通图层,或已剪贴到同一图层的调整层'); + mutate(l.clipToBelow ? '调整下方所有图层' : '只调整下方图层', () => { + active(state.doc).clipToBelow = !l.clipToBelow; + }); +} +function duplicate() { + const l = editable(); + mutate('复制图层', () => { + const n = { + ...l, + id: crypto.randomUUID(), + name: l.name + ' 副本', + canvas: cloneCanvas(l.canvas), + mask: l.mask ? cloneCanvas(l.mask) : null, + }; + state.doc.layers.splice(state.doc.layers.indexOf(active(state.doc)) + 1, 0, n); + state.doc.activeId = n.id; + }); +} +function deleteLayer() { + editable(); + if (state.doc.layers.length === 1) throw Error('至少保留一个图层'); + mutate('删除图层', () => { + state.doc.layers = state.doc.layers.filter((l) => l.id !== state.doc.activeId); + state.doc.activeId = state.doc.layers.at(-1).id; + }); +} +function moveLayer(delta) { + editable(); + const i = state.doc.layers.findIndex((l) => l.id === state.doc.activeId), + j = i + delta; + if (j < 0 || j >= state.doc.layers.length) return; + mutate('调整图层顺序', () => { + [state.doc.layers[i], state.doc.layers[j]] = [state.doc.layers[j], state.doc.layers[i]]; + }); +} +function mergeDown() { + const l = editable(), + i = state.doc.layers.indexOf(l); + if (i < 1) throw Error('没有下方图层'); + if (l.adjustment || state.doc.layers[i - 1].adjustment) + throw Error('调整图层作用于下方合成图像,请使用“拼合图像”保留完整效果'); + if (state.doc.layers[i - 1].locked) throw Error('下方图层已锁定'); + const merged = composite({ ...state.doc, layers: state.doc.layers.slice(i - 1, i + 1) }); + mutate('向下合并', () => { + const n = layer(state.doc.width, state.doc.height, state.doc.layers[i - 1].name); + n.canvas = merged; + state.doc.layers.splice(i - 1, 2, n); + state.doc.activeId = n.id; + }); +} +function flatten() { + requireDoc(); + const c = composite(state.doc); + mutate('拼合图像', () => { + const l = layer(state.doc.width, state.doc.height, '合并图层'); + l.canvas = c; + state.doc.layers = [l]; + state.doc.activeId = l.id; + }); +} +function addMask() { + const l = editable(); + mutate('添加选区蒙版', () => { + const a = active(state.doc); + a.mask = canvas(a.canvas.width, a.canvas.height); + const ctx = a.mask.getContext('2d'); + ctx.save(); + clipSelection(ctx, state.doc, a); + ctx.fillStyle = '#fff'; + ctx.fillRect(0, 0, a.mask.width, a.mask.height); + ctx.restore(); + state.maskEditing = true; + }); + status('蒙版已添加,画笔恢复可见区域,橡皮擦隐藏区域'); +} +function resizeDocument(w, h, resize = true) { + requireDoc(); + canvas(w, h); + const sx = w / state.doc.width, + sy = h / state.doc.height; + mutate(resize ? '调整图像大小' : '调整画布大小', () => { + state.doc.layers = state.doc.layers.map((l) => { + const c = canvas(w, h), + ctx = c.getContext('2d'); + if (resize) + ctx.drawImage(l.canvas, l.x * sx, l.y * sy, l.canvas.width * sx, l.canvas.height * sy); + else ctx.drawImage(l.canvas, l.x, l.y); + let mask = null; + if (l.mask) { + mask = canvas(w, h); + const m = mask.getContext('2d'); + if (resize) m.drawImage(l.mask, l.x * sx, l.y * sy, l.mask.width * sx, l.mask.height * sy); + else m.drawImage(l.mask, l.x, l.y); + } + return { ...l, canvas: c, mask, x: 0, y: 0, text: null }; + }); + state.doc.width = w; + state.doc.height = h; + state.doc.selection = null; + }); + fit(); +} +function sizeDialog(resize) { + requireDoc(); + const [wr, w] = field('宽度', state.doc.width), + [hr, h] = field('高度', state.doc.height); + modal( + resize ? '图像大小' : '画布大小', + [wr, hr, note('最多 3200 万像素;图像大小会同步缩放全部图层。')], + () => resizeDocument(Number(w.value), Number(h.value), resize), + ); +} +function crop(s = state.doc?.selection) { + requireDoc(); + if (!s || !['rect', 'ellipse'].includes(s.kind)) throw Error('请先框选矩形裁剪范围'); + const x = Math.max(0, Math.floor(s.x)), + y = Math.max(0, Math.floor(s.y)), + w = Math.min(state.doc.width - x, Math.round(s.w)), + h = Math.min(state.doc.height - y, Math.round(s.h)); + canvas(w, h); + mutate('裁剪图像', () => { + state.doc.layers = state.doc.layers.map((l) => { + const c = canvas(w, h); + c.getContext('2d').drawImage(l.canvas, l.x - x, l.y - y); + let mask = null; + if (l.mask) { + mask = canvas(w, h); + mask.getContext('2d').drawImage(l.mask, l.x - x, l.y - y); + } + return { ...l, canvas: c, mask, x: 0, y: 0, text: null }; + }); + state.doc.width = w; + state.doc.height = h; + state.doc.selection = null; + }); + fit(); +} +function transformDocument(kind) { + requireDoc(); + const rotate = kind === 'cw' || kind === 'ccw', + w = rotate ? state.doc.height : state.doc.width, + h = rotate ? state.doc.width : state.doc.height; + const apply = (src, x, y) => { + const c = canvas(w, h), + ctx = c.getContext('2d'); + if (kind === 'h') { + ctx.translate(w, 0); + ctx.scale(-1, 1); + } + if (kind === 'v') { + ctx.translate(0, h); + ctx.scale(1, -1); + } + if (kind === 'cw') { + ctx.translate(w, 0); + ctx.rotate(Math.PI / 2); + } + if (kind === 'ccw') { + ctx.translate(0, h); + ctx.rotate(-Math.PI / 2); + } + ctx.drawImage(src, x, y); + return c; + }; + mutate('变换图像', () => { + state.doc.layers = state.doc.layers.map((l) => ({ + ...l, + canvas: apply(l.canvas, l.x, l.y), + mask: l.mask ? apply(l.mask, l.x, l.y) : null, + x: 0, + y: 0, + text: null, + })); + state.doc.width = w; + state.doc.height = h; + state.doc.selection = null; + }); + fit(); +} +async function newDocument() { + const [nr, n] = field('名称', '未命名', 'text'), + [wr, w] = field('宽度', 1280), + [hr, h] = field('高度', 800); + modal('新建画布', [nr, wr, hr], () => + addDoc(documentModel(Number(w.value), Number(h.value), n.value || '未命名')), + ); +} +function demo() { + const d = documentModel(1280, 800, '海岸 · 示例'); + const bg = d.layers[0].canvas.getContext('2d'), + g = bg.createLinearGradient(0, 0, 0, 800); + g.addColorStop(0, '#b5d4dc'); + g.addColorStop(0.55, '#e7d5b8'); + g.addColorStop(0.551, '#417e8c'); + g.addColorStop(1, '#173f58'); + bg.fillStyle = g; + bg.fillRect(0, 0, 1280, 800); + bg.fillStyle = '#f9e3ab'; + bg.beginPath(); + bg.arc(890, 240, 70, 0, Math.PI * 2); + bg.fill(); + bg.fillStyle = '#224c59'; + bg.beginPath(); + bg.moveTo(0, 800); + bg.lineTo(0, 580); + bg.bezierCurveTo(220, 400, 350, 720, 580, 800); + bg.fill(); + const l = layer(1280, 800, '文字 · COAST'); + l.text = { value: 'COAST', size: 128, color: '#ffffff', x: 90, y: 290 }; + const ctx = l.canvas.getContext('2d'); + ctx.fillStyle = '#fff'; + ctx.font = '500 128px sans-serif'; + ctx.fillText('COAST', 90, 290); + ctx.font = '22px sans-serif'; + ctx.fillText('A quiet place, a little closer.', 98, 340); + d.layers.push(l); + d.activeId = l.id; + addDoc(d); + status('示例已打开:试试图层移动、调色和导出'); +} +const { importFiles, save, exportProject, projects, exportImage } = createFileActions(state, { + requireDoc, + addDoc, + setDoc, + refresh, + status, + button, + modal, + note, +}); +function runFilter(data, w, h, type, value) { + const id = ++state.filterJob; + return new Promise((resolve, reject) => { + pending.set(id, { resolve, reject }); + worker.postMessage({ id, buffer: data.buffer, width: w, height: h, type, value }, [ + data.buffer, + ]); + }); +} +async function applyFilter(type, value, label) { + const l = pixelEditable(), + d = state.doc; + state.busy = true; + status('正在处理 ' + label + '…'); + try { + const data = l.canvas.getContext('2d').getImageData(0, 0, l.canvas.width, l.canvas.height); + const out = await runFilter(data.data, data.width, data.height, type, value); + begin(d, label, [l.id]); + const target = d.layers.find((x) => x.id === l.id), + c = canvas(data.width, data.height); + c.getContext('2d').putImageData(new ImageData(out, data.width, data.height), 0, 0); + const ctx = target.canvas.getContext('2d'); + ctx.save(); + clipSelection(ctx, d, target); + ctx.clearRect(0, 0, c.width, c.height); + ctx.drawImage(c, 0, 0); + ctx.restore(); + refresh(); + status(label + '完成'); + } finally { + state.busy = false; + } +} +function filterDialog(item) { + const source = pixelEditable().canvas; + const [type, label, value, min, max] = item; + if (min === max || max === 1) return applyFilter(type, value, label); + showFilterDialog(source, item, { modal, runFilter, applyFilter }); +} +for (const key of ['enhance', 'brightness', 'contrast', 'saturation', 'warmth', 'grayscale']) { + const item = adjustments.find((a) => a[0] === key); + $('#quick').append(button(item[1], () => filterDialog(item))); +} +function fillAll(clear = false) { + const l = pixelEditable(true); + mutate( + clear ? '清除选区' : '填充选区', + () => { + const a = active(state.doc), + ctx = (state.maskEditing && a.mask ? a.mask : a.canvas).getContext('2d'); + ctx.save(); + clipSelection(ctx, state.doc, a); + if (clear) ctx.clearRect(0, 0, a.canvas.width, a.canvas.height); + else { + ctx.fillStyle = $('#color').value; + ctx.fillRect(0, 0, a.canvas.width, a.canvas.height); + } + ctx.restore(); + }, + [l.id], + ); +} +function copy(merged = false, cut = false) { + const l = merged ? editable() : pixelEditable(), + src = merged ? composite(state.doc) : l.canvas, + c = canvas(state.doc.width, state.doc.height), + ctx = c.getContext('2d'); + ctx.save(); + clipSelection(ctx, state.doc, { x: 0, y: 0 }); + ctx.drawImage(src, merged ? 0 : l.x, merged ? 0 : l.y); + ctx.restore(); + state.clipboard = c; + if (cut) fillAll(true); + status('已复制到工作台剪贴板'); +} +function paste() { + requireDoc(); + if (!state.clipboard) throw Error('请先复制图像区域'); + mutate('粘贴图层', () => { + const l = layer(state.clipboard.width, state.clipboard.height, '粘贴'); + l.canvas = cloneCanvas(state.clipboard); + state.doc.layers.push(l); + state.doc.activeId = l.id; + }); +} +function transformLayer() { + const l = pixelEditable(), + [xr, x] = field('X', l.x), + [yr, y] = field('Y', l.y), + [sr, s] = field('缩放 %', 100), + [rr, r] = field('旋转角度', 0); + modal('变换图层', [xr, yr, sr, rr, note('以图层中心旋转;转换后文字成为像素。')], () => { + const scale = Number(s.value) / 100, + angle = (Number(r.value) * Math.PI) / 180; + if (!(scale > 0 && scale <= 10)) throw Error('缩放范围为 1% 到 1000%'); + mutate('变换图层', () => { + const a = active(state.doc), + c = canvas(state.doc.width, state.doc.height), + ctx = c.getContext('2d'); + ctx.translate(Number(x.value) + a.canvas.width / 2, Number(y.value) + a.canvas.height / 2); + ctx.rotate(angle); + ctx.scale(scale, scale); + ctx.drawImage(a.canvas, -a.canvas.width / 2, -a.canvas.height / 2); + a.canvas = c; + a.x = 0; + a.y = 0; + a.mask = null; + a.text = null; + }); + }); +} +function textDialog(point, edit = false) { + const l = pixelEditable(), + previous = edit ? l.text : null; + if (edit && !previous) throw Error('当前图层不是可编辑文字'); + const input = document.createElement('textarea'); + input.setAttribute('aria-label', '文字内容'); + input.value = previous?.value || '新的文字'; + const [sr, size] = field('字号', previous?.size || 64), + [cr, color] = field('颜色', previous?.color || $('#color').value, 'color'); + modal(edit ? '编辑文字' : '添加文字', [input, sr, cr], () => { + const value = input.value, + n = Number(size.value); + if (!value.trim() || n < 1 || n > 1000) throw Error('请输入文字,字号范围为 1–1000'); + mutate(edit ? '编辑文字' : '新建文字图层', () => { + const a = edit + ? active(state.doc) + : layer(state.doc.width, state.doc.height, '文字 · ' + value.slice(0, 12)); + a.canvas = canvas(state.doc.width, state.doc.height); + a.text = { + value, + size: n, + color: color.value, + x: previous?.x ?? point.x, + y: previous?.y ?? point.y, + }; + const ctx = a.canvas.getContext('2d'); + ctx.fillStyle = a.text.color; + ctx.font = `${n}px sans-serif`; + value.split('\n').forEach((line, i) => ctx.fillText(line, a.text.x, a.text.y + i * n * 1.3)); + if (!edit) { + state.doc.layers.push(a); + state.doc.activeId = a.id; + } + }); + }); +} +const menuData = { + 文件: [ + ['新建画布', newDocument], + ['打开图片 / PSD / TIFF / 工程', () => $('#file-input').click()], + ['本地工程', projects], + ['保存工程', save], + ['导出工程文件', exportProject], + null, + ...['png', 'jpeg', 'webp', 'tiff', 'psd', 'pdf', 'svg'].map((t) => [ + '导出 ' + t.toUpperCase(), + () => exportImage(t), + ]), + ], + 编辑: [ + [ + '撤销', + () => { + requireDoc(); + undo(state.doc); + refresh(); + }, + ], + [ + '重做', + () => { + requireDoc(); + redo(state.doc); + refresh(); + }, + ], + null, + ['剪切', () => copy(false, true)], + ['复制', () => copy()], + ['合并复制', () => copy(true)], + ['粘贴', paste], + ['清除', () => fillAll(true)], + ['填充', () => fillAll()], + ['变换图层', transformLayer], + ], + 图像: [ + ['图像大小', () => sizeDialog(true)], + ['画布大小', () => sizeDialog(false)], + ['按选区裁剪', () => crop()], + ['水平翻转', () => transformDocument('h')], + ['垂直翻转', () => transformDocument('v')], + ['顺时针旋转 90°', () => transformDocument('cw')], + ['逆时针旋转 90°', () => transformDocument('ccw')], + ['拼合图像', flatten], + ], + 图层: [ + ['新建图层', newLayer], + ['新建调整图层', newAdjustment], + ['编辑调整图层', () => editAdjustment(active(requireDoc()))], + ['切换只调整下方图层', toggleAdjustmentClipping], + [ + '图层样式', + () => { + const l = pixelEditable(); + showStylesDialog(l, { + modal, + apply: (styles) => + mutate('图层样式', () => { + active(state.doc).styles = styles; + }), + }); + }, + ], + [ + '清除图层样式', + () => { + editable(); + mutate('清除图层样式', () => { + active(state.doc).styles = null; + }); + }, + ], + ['复制图层', duplicate], + ['删除图层', deleteLayer], + ['向下合并', mergeDown], + ['上移一层', () => moveLayer(1)], + ['下移一层', () => moveLayer(-1)], + ['添加选区蒙版', addMask], + [ + '移除蒙版', + () => + mutate('移除蒙版', () => { + active(state.doc).mask = null; + state.maskEditing = false; + }), + ], + ['编辑文字', () => textDialog(null, true)], + ], + 选择: [ + [ + '全选', + () => { + requireDoc(); + state.doc.selection = { kind: 'rect', x: 0, y: 0, w: state.doc.width, h: state.doc.height }; + schedule(); + }, + ], + [ + '取消选择', + () => { + requireDoc(); + state.doc.selection = null; + schedule(); + }, + ], + [ + '反选', + () => { + requireDoc(); + if (state.doc.selection) + state.doc.selection = { ...state.doc.selection, invert: !state.doc.selection.invert }; + schedule(); + }, + ], + ], + 调整: [ + [ + '曲线', + () => { + const layer = pixelEditable(); + showCurvesDialog(layer.canvas, { modal, applyFilter }); + }, + ], + ...adjustments.map((a) => [a[1], () => filterDialog(a)]), + ], + 滤镜: filters.map((a) => [a[1], () => filterDialog(a)]), + 视图: [ + ['适合窗口', fit], + ['实际大小', () => changeZoom(1 / state.zoom)], + ['放大', () => changeZoom(1.25)], + ['缩小', () => changeZoom(0.8)], + [ + '显示 / 隐藏网格', + () => { + state.grid = !state.grid; + schedule(); + }, + ], + [ + '重置视图旋转', + () => { + state.viewRotation = 0; + schedule(); + }, + ], + ], + 帮助: [ + ['录制 / 停止录屏', () => toggleRecording(status)], + ['使用说明', manual], + ['功能范围', capabilities], + ], +}; +for (const [title, items] of Object.entries(menuData)) { + const details = document.createElement('details'), + summary = document.createElement('summary'), + menu = document.createElement('div'); + summary.textContent = title; + menu.className = 'menu'; + for (const item of items) { + if (!item) { + menu.append(document.createElement('hr')); + continue; + } + menu.append( + button(item[0], () => { + details.open = false; + return item[1](); + }), + ); + } + details.append(summary, menu); + details.addEventListener('toggle', () => { + if (details.open) + for (const other of $('#menus').children) if (other !== details) other.open = false; + }); + $('#menus').append(details); +} +document.addEventListener('pointerdown', (e) => { + if (!e.target.closest('details')) for (const d of $('#menus').children) d.open = false; +}); +function manual() { + modal( + '使用说明', + [ + note('1. 打开图片或点击试用示例。左侧选择工具,顶部调整颜色、大小与不透明度。'), + note('2. 图层在右侧。点击选择图层,勾选显示,点击锁定防止误改。'), + note('3. 先框选再调色,可只修改局部。Ctrl/⌘ Z 撤销,Shift Ctrl/⌘ Z 重做。'), + note( + '4. 保存工程会保存到本机 Mini App 数据目录;导出工程文件可以迁移。PNG 保留透明,JPEG 使用白底。', + ), + note('5. 仿制图章先 Alt 点击取样。文字点击添加,已有文字从图层菜单编辑。'), + note('6. PSD 仅支持 8-bit RGB 普通像素图层;不支持 PSB、智能对象、调整层和专业色彩管理。'), + note( + '7. 图层菜单可创建调整图层、编辑图层样式。调整图层可剪贴到下方单层,并设置混合模式;保存工程保留参数。含调整层的 PSD 会合并为像素图像。', + ), + ], + () => {}, + '知道了', + ); +} +function capabilities() { + modal( + '当前功能范围', + [ + note( + `已实现:多文档、图层、${blends.length} 种混合模式、蒙版、${adjustments.length + 1} 种可编辑调整层(含曲线)、剪贴调整、10 种基础图层样式、选区、绘制、文字、局部修图、${filters.length} 种滤镜、本地工程、PNG/JPEG/WebP/TIFF/PSD/PDF/SVG 导出。`, + ), + note( + '尚未实现:原站全部 52 种工具、图层组、样式高级参数、完整 PSD、RAW/HEIF、完整 TIFF、内容识别、AI 生图、Google Drive。当前属于独立重写版本,并非原站完整复制。', + ), + note('参考:RetouchPi 公开界面。本包不包含原站代码或模型。'), + ], + () => {}, + '关闭', + ); +} +function bind(id, fn) { + $(id).addEventListener('click', safe(fn)); +} +bind('#save', save); +bind('#export', () => exportImage()); +bind('#ask-agent', () => agentPanel?.open()); +bind('#agent-results', installAgentResults({ modal, button, importFiles, status })); +bind('#open-start', () => $('#file-input').click()); +bind('#new-start', newDocument); +bind('#demo', demo); +bind('#undo', () => { + requireDoc(); + undo(state.doc); + refresh(); +}); +bind('#redo', () => { + requireDoc(); + redo(state.doc); + refresh(); +}); +bind('#add-layer', newLayer); +bind('#duplicate-layer', duplicate); +bind('#delete-layer', deleteLayer); +bind('#layer-up', () => moveLayer(1)); +bind('#layer-down', () => moveLayer(-1)); +bind('#projects', projects); +bind('#manual', manual); +bind('#fit', fit); +bind('#actual', () => changeZoom(1 / state.zoom)); +bind('#zoom-in', () => changeZoom(1.25)); +bind('#zoom-out', () => changeZoom(0.8)); +$('#blend').onchange = safe((e) => { + editable(); + mutate('混合模式', () => (active(state.doc).blend = e.target.value)); +}); +$('#layer-opacity').onchange = safe((e) => { + editable(); + mutate('图层不透明度', () => (active(state.doc).opacity = Number(e.target.value) / 100)); +}); +$('#file-input').onchange = safe(async (e) => { + await importFiles([...e.target.files]); + e.target.value = ''; +}); +stage.addEventListener('dragover', (e) => e.preventDefault()); +stage.addEventListener( + 'drop', + safe(async (e) => { + e.preventDefault(); + await importFiles([...e.dataTransfer.files]); + }), +); +installCanvasTools(state, { + $, + requireDoc, + editable: () => pixelEditable(true), + status, + schedule, + drawOverlay, + refresh, + crop, + textDialog, + changeZoom, + safe, +}); +window.addEventListener( + 'keydown', + safe((e) => { + if (state.busy || dialog.open || e.target.matches('input,textarea,select')) return; + const key = e.key.toLowerCase(), + mod = e.ctrlKey || e.metaKey; + if (mod) { + if (['z', 's', 'o', 'n', 'a', 'd', 'c', 'v', 'x', 'j', '0', '1'].includes(key)) + e.preventDefault(); + if (key === 'o') return $('#file-input').click(); + if (key === 'n') return newDocument(); + if (!state.doc) return; + if (key === 'z') { + e.shiftKey ? redo(state.doc) : undo(state.doc); + refresh(); + } + if (key === 's') return save(); + if (key === 'a') { + state.doc.selection = { kind: 'rect', x: 0, y: 0, w: state.doc.width, h: state.doc.height }; + schedule(); + } + if (key === 'd') { + state.doc.selection = null; + schedule(); + } + if (key === 'c') copy(e.shiftKey); + if (key === 'x') copy(false, true); + if (key === 'v') paste(); + if (key === 'j') duplicate(); + if (key === '0') fit(); + if (key === '1') changeZoom(1 / state.zoom); + return; + } + if (key === 'escape') { + state.penPoints = []; + if (state.doc) state.doc.selection = null; + schedule(); + return; + } + if ((key === 'delete' || key === 'backspace') && state.doc) { + e.preventDefault(); + return fillAll(true); + } + const found = tools.find((t) => t[2].toLowerCase() === key); + if (found) setTool(found[0]); + if (state.doc && state.tool === 'move' && key.startsWith('arrow')) { + e.preventDefault(); + editable(); + begin(state.doc, '移动图层'); + const l = active(state.doc), + delta = e.shiftKey ? 10 : 1; + if (key === 'arrowleft') l.x -= delta; + if (key === 'arrowright') l.x += delta; + if (key === 'arrowup') l.y -= delta; + if (key === 'arrowdown') l.y += delta; + refresh(); + } + }), +); +window.addEventListener('beforeunload', (e) => { + if (state.docs.some((d) => d.dirty)) { + e.preventDefault(); + e.returnValue = ''; + } +}); +new ResizeObserver(() => { + if (state.doc) schedule(); +}).observe(stage); +setTool('move'); + +editorChanged = installEditorBridge(state, { refresh, status, runFilter, addDoc }); +agentPanel = mountAgentPanel({ + context: () => ({ name: state.doc?.name, supported: typeof window.mcode?.miniapp?.message?.append === 'function' }), + submit: createAgentRequest(state, () => editorChanged.context?.()), +}); diff --git a/plugins/webguhui/minimax-photo/miniapp/client/artistic-filters.js b/plugins/webguhui/minimax-photo/miniapp/client/artistic-filters.js new file mode 100644 index 00000000..a951c0fb --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/artistic-filters.js @@ -0,0 +1,87 @@ +// Independent pixel implementations. No original-site code or assets are used. +const bounded = (v, max) => Math.max(0, Math.min(max - 1, v)); +const luminance = (data, i) => 0.2126 * data[i] + 0.7152 * data[i + 1] + 0.0722 * data[i + 2]; +export function artisticFilter(src, w, h, type, value) { + const out = new Uint8ClampedArray(src); + const amount = Number.isFinite(Number(value)) ? Number(value) : 1; + if (type === 'halftone') { + const size = Math.max(2, Math.min(64, Math.round(amount))); + for (let by = 0; by < h; by += size) + for (let bx = 0; bx < w; bx += size) { + const right = Math.min(w, bx + size), + bottom = Math.min(h, by + size); + let weighted = 0, + alpha = 0; + for (let y = by; y < bottom; y++) + for (let x = bx; x < right; x++) { + const i = (y * w + x) * 4; + weighted += luminance(src, i) * src[i + 3]; + alpha += src[i + 3]; + } + const dark = alpha ? 1 - weighted / (255 * alpha) : 0; + const radius = Math.sqrt((dark * (right - bx) * (bottom - by)) / Math.PI); + const cx = (bx + right) / 2, + cy = (by + bottom) / 2; + for (let y = by; y < bottom; y++) + for (let x = bx; x < right; x++) { + const i = (y * w + x) * 4; + const coverage = + dark <= 0.001 + ? 0 + : dark >= 0.999 + ? 1 + : Math.max(0, Math.min(1, radius + 0.5 - Math.hypot(x + 0.5 - cx, y + 0.5 - cy))); + out[i] = out[i + 1] = out[i + 2] = 255 * (1 - coverage); + } + } + return out; + } + if (type === 'diffuse') { + const radius = Math.max(1, Math.min(20, Math.round(amount))); + for (let y = 0; y < h; y++) + for (let x = 0; x < w; x++) { + // Coordinate hash keeps repeated previews and exports reproducible. + let hash = Math.imul(x + 1, 374761393) ^ Math.imul(y + 1, 668265263); + hash = Math.imul(hash ^ (hash >>> 13), 1274126177) >>> 0; + const sx = bounded(x + (hash % (2 * radius + 1)) - radius, w); + const sy = bounded(y + ((hash >>> 16) % (2 * radius + 1)) - radius, h); + const i = (y * w + x) * 4, + j = (sy * w + sx) * 4; + // Retain geometry/alpha and avoid importing hidden RGB from transparent pixels. + if (src[j + 3]) for (let c = 0; c < 3; c++) out[i + c] = src[j + c]; + } + return out; + } + for (let y = 0; y < h; y++) + for (let x = 0; x < w; x++) { + const i = (y * w + x) * 4; + if (type === 'traceContour') { + const high = luminance(src, i) >= amount; + let edge = false; + for (const [dx, dy] of [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1], + ]) { + const j = (bounded(y + dy, h) * w + bounded(x + dx, w)) * 4; + if (src[j + 3] && luminance(src, j) >= amount !== high) edge = true; + } + out[i] = out[i + 1] = out[i + 2] = edge ? 0 : 255; + } else if (type === 'glowingEdges') { + for (let c = 0; c < 3; c++) { + let gx = 0, + gy = 0; + for (let dy = -1; dy <= 1; dy++) + for (let dx = -1; dx <= 1; dx++) { + const j = (bounded(y + dy, h) * w + bounded(x + dx, w)) * 4; + const v = (src[j + c] * src[j + 3]) / 255; + gx += v * dx * (dy === 0 ? 2 : 1); + gy += v * dy * (dx === 0 ? 2 : 1); + } + out[i + c] = (Math.hypot(gx, gy) * Math.max(1, Math.min(10, amount))) / 4; + } + } + } + return out; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/background-eraser.js b/plugins/webguhui/minimax-photo/miniapp/client/background-eraser.js new file mode 100644 index 00000000..c610cd59 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/background-eraser.js @@ -0,0 +1,39 @@ +// Coverage mask for a sampled-color brush swept along a line segment. +export function backgroundEraseMask( + data, + width, + height, + originX, + originY, + from, + to, + radius, + sampled, + tolerance, +) { + const mask = new Uint8ClampedArray(data.length); + const dx = to.x - from.x, + dy = to.y - from.y, + length2 = dx * dx + dy * dy; + for (let y = 0; y < height; y++) + for (let x = 0; x < width; x++) { + const i = (y * width + x) * 4; + if ( + !data[i + 3] || + Math.max( + Math.abs(data[i] - sampled[0]), + Math.abs(data[i + 1] - sampled[1]), + Math.abs(data[i + 2] - sampled[2]), + ) > tolerance + ) + continue; + const px = originX + x + 0.5, + py = originY + y + 0.5; + const t = length2 + ? Math.max(0, Math.min(1, ((px - from.x) * dx + (py - from.y) * dy) / length2)) + : 0; + const distance = Math.hypot(px - from.x - t * dx, py - from.y - t * dy); + mask[i + 3] = 255 * Math.max(0, Math.min(1, radius + 0.5 - distance)); + } + return mask; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/blending.js b/plugins/webguhui/minimax-photo/miniapp/client/blending.js new file mode 100644 index 00000000..b9f86311 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/blending.js @@ -0,0 +1,131 @@ +// Canvas-standard RGB modes follow W3C Compositing Level 1, section 10. +// https://www.w3.org/TR/compositing-1/#blending +// Extended modes follow Adobe mode descriptions; external pixel parity is unverified. +// Alpha/coverage belongs to the caller, not this color-only operation. +const lum = (c) => 0.3 * c[0] + 0.59 * c[1] + 0.11 * c[2]; +const sat = (c) => Math.max(...c) - Math.min(...c); +function setLum(c, value) { + const delta = value - lum(c); + let result = c.map((v) => v + delta); + const low = Math.min(...result), + high = Math.max(...result); + if (low < 0) result = result.map((v) => value + ((v - value) * value) / (value - low)); + if (high > 1) result = result.map((v) => value + ((v - value) * (1 - value)) / (high - value)); + return result; +} +function setSat(c, value) { + const order = [0, 1, 2].sort((a, b) => c[a] - c[b]); + const [lo, mid, hi] = order, + out = [0, 0, 0]; + if (c[hi] > c[lo]) { + out[mid] = ((c[mid] - c[lo]) * value) / (c[hi] - c[lo]); + out[hi] = value; + } + return out; +} +export const pixelBlendModes = [ + 'dissolve', + 'linear-burn', + 'linear-dodge', + 'subtract', + 'divide', + 'vivid-light', + 'linear-light', + 'pin-light', + 'hard-mix', + 'darker-color', + 'lighter-color', +]; +const scalar = { + 'vivid-light': (b, s) => + s <= 0.5 ? scalar['color-burn'](b, 2 * s) : scalar['color-dodge'](b, 2 * s - 1), + 'linear-light': (b, s) => Math.max(0, Math.min(1, b + 2 * s - 1)), + 'pin-light': (b, s) => (s <= 0.5 ? Math.min(b, 2 * s) : Math.max(b, 2 * s - 1)), + 'hard-mix': (b, s) => (b + s >= 1 ? 1 : 0), + 'linear-burn': (b, s) => Math.max(0, b + s - 1), + 'linear-dodge': (b, s) => Math.min(1, b + s), + subtract: (b, s) => Math.max(0, b - s), + divide: (b, s) => (s === 0 ? 1 : Math.min(1, b / s)), + 'source-over': (_b, s) => s, + dissolve: (_b, s) => s, + multiply: (b, s) => b * s, + screen: (b, s) => b + s - b * s, + overlay: (b, s) => (b <= 0.5 ? 2 * b * s : 1 - 2 * (1 - b) * (1 - s)), + darken: Math.min, + lighten: Math.max, + 'color-dodge': (b, s) => (b === 0 ? 0 : s === 1 ? 1 : Math.min(1, b / (1 - s))), + 'color-burn': (b, s) => (b === 1 ? 1 : s === 0 ? 0 : 1 - Math.min(1, (1 - b) / s)), + 'hard-light': (b, s) => (s <= 0.5 ? 2 * b * s : 1 - 2 * (1 - b) * (1 - s)), + 'soft-light': (b, s) => + s <= 0.5 + ? b - (1 - 2 * s) * b * (1 - b) + : b + (2 * s - 1) * ((b <= 0.25 ? ((16 * b - 12) * b + 4) * b : Math.sqrt(b)) - b), + difference: (b, s) => Math.abs(b - s), + exclusion: (b, s) => b + s - 2 * b * s, +}; +export function blendPixel(mode, backdrop, source, offset, out) { + // Whole-color comparisons choose a complete triplet, never a per-channel minimum. + if (mode === 'darker-color' || mode === 'lighter-color') { + const b = backdrop[offset] + backdrop[offset + 1] + backdrop[offset + 2]; + const s = source[offset] + source[offset + 1] + source[offset + 2]; + const chosen = (mode === 'darker-color' ? s < b : s > b) ? source : backdrop; + for (let c = 0; c < 3; c++) out[c] = chosen[offset + c]; + return out; + } + const formula = scalar[mode]; + if (formula) { + for (let c = 0; c < 3; c++) + out[c] = 255 * formula(backdrop[offset + c] / 255, source[offset + c] / 255); + return out; + } + const b = [backdrop[offset] / 255, backdrop[offset + 1] / 255, backdrop[offset + 2] / 255]; + const s = [source[offset] / 255, source[offset + 1] / 255, source[offset + 2] / 255]; + let result; + if (mode === 'hue') result = setLum(setSat(s, sat(b)), lum(b)); + else if (mode === 'saturation') result = setLum(setSat(b, sat(s)), lum(b)); + else if (mode === 'color') result = setLum(s, lum(b)); + else if (mode === 'luminosity') result = setLum(b, lum(s)); + else throw Error('不支持的混合模式'); + for (let c = 0; c < 3; c++) out[c] = result[c] * 255; + return out; +} + +// Source-over coverage, with blending restricted to the overlap of both layers. +// Coordinate hashing keeps the grain deterministic across repaint, clipping and save/reopen. +export function dissolveCoverage(coverage, x, y) { + if (coverage <= 0) return 0; + if (coverage >= 1) return 1; + let hash = + Math.imul(Math.floor(x), 0x1f123bb5) ^ Math.imul(Math.floor(y), 0x5f356495) ^ 0x6d2b79f5; + hash = Math.imul(hash ^ (hash >>> 16), 0x7feb352d); + hash = Math.imul(hash ^ (hash >>> 15), 0x846ca68b); + hash ^= hash >>> 16; + return (hash >>> 0) / 4294967296 < coverage ? 1 : 0; +} +export function compositePixels( + backdrop, + source, + mode, + opacity = 1, + width = backdrop.length / 4, + originX = 0, + originY = 0, +) { + const out = new Uint8ClampedArray(backdrop.length); + const mixed = new Float64Array(3); + for (let i = 0; i < out.length; i += 4) { + const ab = backdrop[i + 3] / 255; + let as = (source[i + 3] / 255) * opacity; + if (mode === 'dissolve') + as = dissolveCoverage(as, originX + ((i / 4) % width), originY + Math.floor(i / 4 / width)); + const alpha = as + ab * (1 - as); + if (!alpha) continue; + blendPixel(mode, backdrop, source, i, mixed); + for (let c = 0; c < 3; c++) + out[i + c] = + ((1 - as) * ab * backdrop[i + c] + as * (1 - ab) * source[i + c] + as * ab * mixed[c]) / + alpha; + out[i + 3] = alpha * 255; + } + return out; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/canvas-tools.js b/plugins/webguhui/minimax-photo/miniapp/client/canvas-tools.js new file mode 100644 index 00000000..f27b72f3 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/canvas-tools.js @@ -0,0 +1,499 @@ +import { colorReplacementPatch } from './color-replace.js'; +import { backgroundEraseMask } from './background-eraser.js'; +import { floodRegion } from './flood-region.js'; +import { filterPixels } from './filters.js'; +import { canvas, cloneCanvas, active, begin, clipSelection, invalidateLayer } from './model.js'; +import { tools } from './catalog.js'; +export function installCanvasTools(state, ui) { + const { + $, + requireDoc, + editable, + status, + schedule, + drawOverlay, + refresh, + crop, + textDialog, + changeZoom, + safe, + } = ui; + const image = $('#image'), + overlay = $('#overlay'), + stage = $('#stage'); + function point(e) { + const bounds = stage.getBoundingClientRect(), + x = (e.clientX - bounds.left - state.pan.x) / state.zoom, + y = (e.clientY - bounds.top - state.pan.y) / state.zoom, + a = (-state.viewRotation * Math.PI) / 180; + return { x: x * Math.cos(a) - y * Math.sin(a), y: x * Math.sin(a) + y * Math.cos(a) }; + } + function rect(a, b) { + return { + kind: 'rect', + x: Math.min(a.x, b.x), + y: Math.min(a.y, b.y), + w: Math.abs(a.x - b.x), + h: Math.abs(a.y - b.y), + }; + } + function contextFor(l) { + return (state.maskEditing && l.mask ? l.mask : l.canvas).getContext('2d'); + } + function stroke(p, last, pressure = 1) { + const l = active(state.doc), + ctx = contextFor(l), + size = Math.max(1, Math.min(500, Number($('#size').value) || 1)), + opacity = Number($('#flow').value) / 100; + ctx.save(); + clipSelection(ctx, state.doc, l); + ctx.globalAlpha = state.tool === 'pencil' ? 1 : opacity; + ctx.lineCap = 'round'; + ctx.lineJoin = 'round'; + ctx.lineWidth = (state.tool === 'pencil' ? 1 : size) * Math.max(0.15, pressure); + ctx.strokeStyle = state.maskEditing ? '#fff' : $('#color').value; + ctx.fillStyle = ctx.strokeStyle; + ctx.globalCompositeOperation = state.tool === 'eraser' ? 'destination-out' : 'source-over'; + if (['backgroundEraser', 'colorReplace'].includes(state.tool)) { + if (state.drag.backgroundSample) { + const radius = (size * Math.max(0.15, pressure)) / 2; + const from = { x: last.x - l.x, y: last.y - l.y }, + to = { x: p.x - l.x, y: p.y - l.y }; + const x = Math.max(0, Math.floor(Math.min(from.x, to.x) - radius - 1)); + const y = Math.max(0, Math.floor(Math.min(from.y, to.y) - radius - 1)); + const w = Math.min(l.canvas.width, Math.ceil(Math.max(from.x, to.x) + radius + 1)) - x; + const h = Math.min(l.canvas.height, Math.ceil(Math.max(from.y, to.y) + radius + 1)) - y; + if (w > 0 && h > 0) { + const pixels = ctx.getImageData(x, y, w, h); + const mask = backgroundEraseMask( + state.tool === 'colorReplace' + ? state.drag.source.getContext('2d').getImageData(x, y, w, h).data + : pixels.data, + w, + h, + x, + y, + from, + to, + radius, + state.drag.backgroundSample, + Math.max(0, Math.min(255, Number($('#tolerance').value) || 0)), + ); + const patch = canvas(w, h); + let content = mask; + if (state.tool === 'colorReplace') { + const hex = $('#color').value; + const color = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16)); + content = colorReplacementPatch(pixels.data, mask, color); + } + patch.getContext('2d').putImageData(new ImageData(content, w, h), 0, 0); + ctx.globalCompositeOperation = + state.tool === 'colorReplace' ? 'source-atop' : 'destination-out'; + ctx.drawImage(patch, x, y); + } + } + } else if (['clone', 'heal'].includes(state.tool)) { + if (!state.cloneSource) { + ctx.restore(); + return; + } + const offset = { + x: state.cloneSource.x - state.drag.start.x, + y: state.cloneSource.y - state.drag.start.y, + }; + ctx.beginPath(); + ctx.arc(p.x - l.x, p.y - l.y, size / 2, 0, Math.PI * 2); + ctx.clip(); + if (state.tool === 'heal') ctx.filter = 'blur(2px)'; + ctx.drawImage(state.drag.source, offset.x * -1, offset.y * -1); + } else if (['blur', 'sharpen', 'smudge', 'dodge', 'burn', 'sponge'].includes(state.tool)) { + const x = Math.max(0, Math.round(p.x - l.x - size / 2)), + y = Math.max(0, Math.round(p.y - l.y - size / 2)), + w = Math.min(l.canvas.width - x, Math.round(size)), + h = Math.min(l.canvas.height - y, Math.round(size)); + if (w > 0 && h > 0) { + const patch = canvas(w, h), + pc = patch.getContext('2d'); + pc.drawImage(l.canvas, x, y, w, h, 0, 0, w, h); + ctx.beginPath(); + ctx.arc(p.x - l.x, p.y - l.y, size / 2, 0, Math.PI * 2); + ctx.clip(); + if (state.tool === 'blur') ctx.filter = 'blur(2px)'; + if (state.tool === 'dodge') ctx.filter = 'brightness(1.12)'; + if (state.tool === 'burn') ctx.filter = 'brightness(.88)'; + if (state.tool === 'sponge') ctx.filter = 'saturate(.7)'; + if (state.tool === 'sharpen') { + const pixels = pc.getImageData(0, 0, w, h); + pc.putImageData( + new ImageData(filterPixels(pixels.data, w, h, 'unsharp', 20), w, h), + 0, + 0, + ); + } + ctx.drawImage( + patch, + x + (state.tool === 'smudge' ? (p.x - last.x) * 0.7 : 0), + y + (state.tool === 'smudge' ? (p.y - last.y) * 0.7 : 0), + ); + } + } else { + ctx.beginPath(); + ctx.moveTo(last.x - l.x, last.y - l.y); + ctx.lineTo(p.x - l.x, p.y - l.y); + ctx.stroke(); + if (last.x === p.x && last.y === p.y) { + ctx.beginPath(); + ctx.arc(p.x - l.x, p.y - l.y, ctx.lineWidth / 2, 0, Math.PI * 2); + ctx.fill(); + } + } + ctx.restore(); + invalidateLayer(l); + schedule(); + } + function shape(a, b) { + const l = active(state.doc), + ctx = contextFor(l), + r = rect(a, b); + ctx.save(); + clipSelection(ctx, state.doc, l); + ctx.translate(-l.x, -l.y); + ctx.fillStyle = $('#color').value; + ctx.strokeStyle = $('#color').value; + ctx.lineWidth = Math.max(1, Number($('#size').value)); + ctx.globalAlpha = Number($('#flow').value) / 100; + ctx.beginPath(); + if (state.tool === 'rect') ctx.rect(r.x, r.y, r.w, r.h); + if (state.tool === 'ellipse') + ctx.ellipse(r.x + r.w / 2, r.y + r.h / 2, r.w / 2, r.h / 2, 0, 0, Math.PI * 2); + if (state.tool === 'line') { + ctx.moveTo(a.x, a.y); + ctx.lineTo(b.x, b.y); + } + if (state.tool === 'star') { + const cx = r.x + r.w / 2, + cy = r.y + r.h / 2; + for (let i = 0; i < 10; i++) { + const theta = -Math.PI / 2 + (i * Math.PI) / 5, + f = i % 2 ? 0.42 : 1, + x = cx + ((Math.cos(theta) * r.w) / 2) * f, + y = cy + ((Math.sin(theta) * r.h) / 2) * f; + i ? ctx.lineTo(x, y) : ctx.moveTo(x, y); + } + ctx.closePath(); + } + if (state.tool === 'gradient') { + const g = ctx.createLinearGradient(a.x, a.y, b.x, b.y); + g.addColorStop(0, $('#color').value); + g.addColorStop(1, $('#color').value + '00'); + ctx.fillStyle = g; + ctx.fillRect(l.x, l.y, l.canvas.width, l.canvas.height); + } else if ($('#fill-shape').checked && state.tool !== 'line') ctx.fill(); + else ctx.stroke(); + ctx.restore(); + } + function flood(p, select = false, erase = false) { + const l = editable(), + w = l.canvas.width, + h = l.canvas.height, + x = Math.floor(p.x - l.x), + y = Math.floor(p.y - l.y); + if (x < 0 || y < 0 || x >= w || y >= h) return; + const ctx = contextFor(l), + data = ctx.getImageData(0, 0, w, h).data; + const tolerance = Math.max(0, Math.min(255, Number($('#tolerance').value) || 0)); + const { mask: region, bounds } = floodRegion(data, w, h, x, y, tolerance); + if (!bounds) return; + const { minX, minY, maxX, maxY } = bounds; + if (select) { + const runs = []; + for (let yy = minY; yy <= maxY; yy++) { + let start = -1; + for (let xx = minX; xx <= maxX + 1; xx++) { + const hit = xx <= maxX && region[yy * w + xx] === 2; + if (hit && start < 0) start = xx; + if (!hit && start >= 0) { + runs.push([start + l.x, yy + l.y, xx - start]); + start = -1; + } + } + } + state.doc.selection = { kind: 'runs', runs }; + status('已选择相近颜色的连通区域'); + schedule(); + return; + } + const output = canvas(w, h), + octx = output.getContext('2d'), + mask = octx.createImageData(w, h); + const color = $('#color') + .value.match(/[a-f0-9]{2}/gi) + .map((s) => parseInt(s, 16)); + for (let i = 0; i < region.length; i++) + if (region[i] === 2) { + mask.data[i * 4] = color[0]; + mask.data[i * 4 + 1] = color[1]; + mask.data[i * 4 + 2] = color[2]; + mask.data[i * 4 + 3] = 255; + } + octx.putImageData(mask, 0, 0); + begin(state.doc, erase ? '魔术橡皮擦' : '油漆桶填充', [l.id]); + const a = active(state.doc), + c = contextFor(a); + c.save(); + clipSelection(c, state.doc, a); + c.globalAlpha = Number($('#flow').value) / 100; + c.globalCompositeOperation = erase ? 'destination-out' : 'source-over'; + c.drawImage(output, 0, 0); + c.restore(); + invalidateLayer(a); + status(erase ? '已擦除相近颜色的连通区域' : '已填充连通区域'); + refresh(); + } + function finishPolygon() { + const draft = state.polygonDraft; + if (!draft || draft.points.length < 3) { + status('至少需要三个点才能闭合选区'); + return; + } + state.doc.selection = { kind: 'polygon', points: draft.points.map((p) => [p.x, p.y]) }; + state.polygonDraft = null; + status('多边形选区已创建'); + schedule(false); + } + window.addEventListener( + 'keydown', + safe((e) => { + if ( + !state.polygonDraft || + state.tool !== 'polyLasso' || + document.querySelector('#dialog').open || + e.target.matches('input,textarea,select') + ) + return; + if (!['Enter', 'Escape', 'Backspace', 'Delete'].includes(e.key)) return; + e.preventDefault(); + e.stopImmediatePropagation(); + if (e.key === 'Enter') finishPolygon(); + else if (e.key === 'Escape') { + state.polygonDraft = null; + status('已取消绘制,保留原选区'); + } else { + state.polygonDraft.points.pop(); + if (!state.polygonDraft.points.length) state.polygonDraft = null; + status('已撤销最后一个点'); + } + schedule(false); + }), + true, + ); + overlay.addEventListener( + 'pointerdown', + safe((e) => { + requireDoc(); + if (e.button !== 0) return; + const p = point(e); + if (state.tool === 'polyLasso') { + if (e.detail >= 2) return; + const draft = state.polygonDraft; + if ( + draft && + draft.points.length >= 3 && + Math.hypot(p.x - draft.points[0].x, p.y - draft.points[0].y) * state.zoom <= 7 + ) { + finishPolygon(); + return; + } + if (!draft) state.polygonDraft = { points: [p], hover: p }; + else if ( + Math.hypot(p.x - draft.points.at(-1).x, p.y - draft.points.at(-1).y) * state.zoom > + 1 + ) + draft.points.push(p); + status('点击添加顶点,Enter 闭合,Backspace 撤点,Esc 取消'); + schedule(false); + return; + } + if (state.tool === 'zoom') { + changeZoom(e.altKey ? 0.8 : 1.25); + return; + } + if (state.tool === 'eyedropper') { + const c = image + .getContext('2d') + .getImageData( + Math.max(0, Math.min(state.doc.width - 1, p.x)), + Math.max(0, Math.min(state.doc.height - 1, p.y)), + 1, + 1, + ).data; + $('#color').value = + '#' + [...c.slice(0, 3)].map((n) => n.toString(16).padStart(2, '0')).join(''); + status('颜色 ' + $('#color').value); + return; + } + if (state.tool === 'text') { + textDialog(p); + return; + } + if (['fill', 'wand', 'magicEraser'].includes(state.tool)) { + flood(p, state.tool === 'wand', state.tool === 'magicEraser'); + return; + } + if (state.tool === 'pen') { + state.penPoints.push(p); + schedule(); + return; + } + if (['clone', 'heal'].includes(state.tool) && e.altKey) { + state.cloneSource = p; + status('已设置取样点'); + return; + } + if (['clone', 'heal'].includes(state.tool) && !state.cloneSource) + throw Error('请先按住 Alt 点击设置取样点'); + if (state.tool === 'colorReplace' && state.maskEditing) + throw Error('颜色替换用于图层像素,请先退出蒙版编辑'); + overlay.setPointerCapture(e.pointerId); + state.drag = { + start: p, + last: p, + client: { x: e.clientX, y: e.clientY }, + pan: { ...state.pan }, + rotation: state.viewRotation, + selection: null, + points: [[p.x, p.y]], + }; + if ( + ['hand', 'rotateView', 'ruler', 'marquee', 'ellipseSelect', 'lasso', 'crop'].includes( + state.tool, + ) + ) + return; + const l = editable(); + state.drag.original = { x: l.x, y: l.y }; + if (['backgroundEraser', 'colorReplace'].includes(state.tool)) { + const x = Math.floor(p.x - l.x), + y = Math.floor(p.y - l.y); + if (x >= 0 && y >= 0 && x < l.canvas.width && y < l.canvas.height) { + const sample = contextFor(l).getImageData(x, y, 1, 1).data; + if (sample[3]) state.drag.backgroundSample = sample; + } + if (!state.drag.backgroundSample) status('请从有颜色的区域开始取样'); + if (state.tool === 'colorReplace') state.drag.source = cloneCanvas(l.canvas); + } else if (state.tool !== 'move') state.drag.source = cloneCanvas(l.canvas); + begin( + state.doc, + tools.find((t) => t[0] === state.tool)[1], + state.tool === 'move' ? [] : [l.id], + ); + if (!['move', 'rect', 'ellipse', 'line', 'star', 'gradient'].includes(state.tool)) + stroke(p, p, e.pointerType === 'pen' ? e.pressure : 1); + }), + ); + overlay.addEventListener( + 'pointermove', + safe((e) => { + if (state.doc && state.tool === 'polyLasso' && state.polygonDraft) { + state.polygonDraft.hover = point(e); + drawOverlay(); + return; + } + if (!state.drag || !state.doc) return; + const p = point(e); + if (state.tool === 'hand') { + state.pan = { + x: state.drag.pan.x + e.clientX - state.drag.client.x, + y: state.drag.pan.y + e.clientY - state.drag.client.y, + }; + schedule(false); + } else if (state.tool === 'rotateView') { + state.viewRotation = state.drag.rotation + (e.clientX - state.drag.client.x) / 2; + schedule(false); + } else if (state.tool === 'move') { + const l = active(state.doc); + l.x = Math.round(state.drag.original.x + p.x - state.drag.start.x); + l.y = Math.round(state.drag.original.y + p.y - state.drag.start.y); + schedule(); + } else if (['marquee', 'ellipseSelect', 'crop'].includes(state.tool)) { + state.drag.selection = { + ...rect(state.drag.start, p), + kind: state.tool === 'ellipseSelect' ? 'ellipse' : 'rect', + }; + drawOverlay(); + } else if (state.tool === 'lasso') { + state.drag.points.push([p.x, p.y]); + state.drag.selection = { kind: 'polygon', points: state.drag.points }; + drawOverlay(); + } else if (state.tool === 'ruler') { + const dx = p.x - state.drag.start.x, + dy = p.y - state.drag.start.y; + status( + `距离 ${Math.hypot(dx, dy).toFixed(1)} px · 角度 ${((Math.atan2(dy, dx) * 180) / Math.PI).toFixed(1)}°`, + ); + } else if (['rect', 'ellipse', 'line', 'star', 'gradient'].includes(state.tool)) { + const l = active(state.doc), + ctx = l.canvas.getContext('2d'); + ctx.clearRect(0, 0, l.canvas.width, l.canvas.height); + ctx.drawImage(state.drag.source, 0, 0); + shape(state.drag.start, p); + invalidateLayer(l); + schedule(); + } else stroke(p, state.drag.last, e.pointerType === 'pen' ? e.pressure : 1); + state.drag.last = p; + }), + ); + function finish(e) { + if (!state.drag) return; + const d = state.drag; + state.drag = null; + if (['marquee', 'ellipseSelect', 'lasso'].includes(state.tool)) { + state.doc.selection = d.selection; + status('选区已创建'); + } + if (state.tool === 'crop' && d.selection && d.selection.w > 1 && d.selection.h > 1) + crop(d.selection); + if (['hand', 'rotateView', 'ruler', 'marquee', 'ellipseSelect', 'lasso'].includes(state.tool)) + schedule(false); + else refresh(); + if (overlay.hasPointerCapture(e.pointerId)) overlay.releasePointerCapture(e.pointerId); + } + overlay.addEventListener('pointerup', safe(finish)); + overlay.addEventListener('pointercancel', safe(finish)); + overlay.addEventListener( + 'dblclick', + safe(() => { + if (state.tool === 'polyLasso') { + if (state.polygonDraft) finishPolygon(); + return; + } + if (state.tool !== 'pen' || state.penPoints.length < 3) return; + const l = editable(); + begin(state.doc, '绘制路径', [l.id]); + const ctx = active(state.doc).canvas.getContext('2d'); + ctx.save(); + clipSelection(ctx, state.doc, active(state.doc)); + ctx.translate(-l.x, -l.y); + ctx.fillStyle = $('#color').value; + ctx.strokeStyle = $('#color').value; + ctx.lineWidth = Number($('#size').value); + ctx.beginPath(); + state.penPoints.forEach((p, i) => (i ? ctx.lineTo(p.x, p.y) : ctx.moveTo(p.x, p.y))); + ctx.closePath(); + $('#fill-shape').checked ? ctx.fill() : ctx.stroke(); + ctx.restore(); + state.doc.paths.push(state.penPoints.map((p) => ({ ...p }))); + state.penPoints = []; + refresh(); + }), + ); + stage.addEventListener( + 'wheel', + (e) => { + if (!state.doc) return; + e.preventDefault(); + changeZoom(e.deltaY < 0 ? 1.08 : 1 / 1.08); + }, + { passive: false }, + ); +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/catalog.js b/plugins/webguhui/minimax-photo/miniapp/client/catalog.js new file mode 100644 index 00000000..02170090 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/catalog.js @@ -0,0 +1,97 @@ +export const tools = [ + ['move', '移动', 'V', '拖动移动当前图层;方向键微调'], + ['marquee', '选框', 'M', '拖动创建矩形选区;选区内编辑'], + ['ellipseSelect', '椭圆选区', '', '拖动创建椭圆选区'], + [ + 'polyLasso', + '多边形套索', + '', + '逐点点击;双击、回到起点或 Enter 闭合;Backspace 撤点,Esc 取消', + ], + ['lasso', '套索', 'L', '按住并拖动圈出选区'], + ['wand', '魔棒', 'W', '点击选择相近颜色;容差控制颜色范围'], + ['crop', '裁剪', 'C', '拖动选定区域后立即裁剪'], + ['brush', '画笔', 'B', '按住绘制;支持触控笔压力'], + ['pencil', '铅笔', '', '不透明硬边线条'], + [ + 'colorReplace', + '颜色替换画笔', + '', + '按下取样,拖动替换近似颜色;保留明暗与透明度,容差控制范围', + ], + [ + 'magicEraser', + '魔术橡皮擦', + '', + '点击擦除相连的近似颜色;容差控制颜色范围,不透明度控制擦除强度', + ], + [ + 'backgroundEraser', + '背景橡皮擦', + '', + '按下取样背景色,拖动擦除相近颜色;大小控制笔刷,容差控制颜色范围', + ], + ['eraser', '橡皮擦', 'E', '擦除当前图层像素'], + ['fill', '油漆桶', 'G', '点击填充相连的近似颜色'], + ['gradient', '渐变', '', '拖动绘制前景色到透明的渐变'], + ['clone', '仿制图章', 'S', '按住 Alt 点击设置来源,再绘制复制'], + ['heal', '修复', '', 'Alt 点击取样;绘制平滑覆盖'], + ['blur', '模糊', '', '涂抹区域模糊'], + ['sharpen', '锐化', '', '涂抹区域增强细节'], + ['smudge', '涂抹', '', '拖动推移附近颜色'], + ['dodge', '减淡', 'O', '涂抹提亮'], + ['burn', '加深', '', '涂抹压暗'], + ['sponge', '海绵', '', '涂抹降低饱和度'], + ['rect', '矩形', 'U', '拖动绘制矩形;可切换填充'], + ['ellipse', '椭圆', '', '拖动绘制椭圆'], + ['line', '直线', '', '拖动绘制直线'], + ['star', '星形', '', '拖动绘制五角星'], + ['text', '文字', 'T', '点击画布添加文字;图层菜单可编辑'], + ['pen', '钢笔', 'P', '逐点点击添加折线路径,双击闭合绘制'], + ['eyedropper', '吸管', 'I', '点击画面读取颜色'], + ['ruler', '标尺', '', '拖动测量距离和角度'], + ['hand', '抓手', 'H', '拖动画布;滚轮缩放'], + ['rotateView', '旋转视图', 'R', '拖动旋转查看,不改变图像'], + ['zoom', '缩放', 'Z', '点击放大;Alt 点击缩小'], +]; +export const adjustments = [ + ['brightness', '亮度', 20, -100, 100], + ['contrast', '对比度', 20, -100, 100], + ['exposure', '曝光', 10, -60, 60], + ['saturation', '饱和度', 20, -100, 100], + ['hue', '色相', 30, -180, 180], + ['vibrance', '自然饱和度', 25, -100, 100], + ['levels', '色阶', 15, 0, 100], + ['gamma', '中间调', 120, 10, 300], + ['warmth', '色温', 15, -100, 100], + ['grayscale', '黑白', 0, 0, 1], + ['invert', '反相', 0, 0, 1], + ['threshold', '阈值', 128, 0, 255], + ['posterize', '色调分离', 6, 2, 32], + ['sepia', '复古', 0, 0, 1], + ['enhance', '自动优化', 0, 0, 1], + ['redEye', '红眼修正', 0, 0, 1], +]; +export const filters = [ + ['oilPaint', '油画', 4, 1, 12], + ['halftone', '半调网纹', 10, 2, 64], + ['diffuse', '扩散', 3, 1, 20], + ['traceContour', '等高线', 128, 0, 255], + ['glowingEdges', '发光边缘', 2, 1, 10], + ['gaussian', '高斯模糊', 3, 0, 30], + ['blur', '方框模糊', 4, 1, 30], + ['sharpen', '锐化', 1, 1, 1], + ['unsharp', 'USM 锐化', 30, 1, 100], + ['pixelate', '马赛克', 12, 2, 100], + ['noise', '添加杂色', 20, 1, 100], + ['emboss', '浮雕', 1, 1, 1], + ['edges', '查找边缘', 1, 1, 1], + ['solarize', '曝光过度', 1, 1, 1], + ['twirl', '旋转扭曲', 60, -180, 180], + ['pinch', '挤压', 50, -90, 200], + ['spherize', '球面化', 50, 1, 100], + ['ripple', '波纹', 25, 1, 100], + ['wave', '波浪', 25, 1, 100], + ['polar', '极坐标', 1, 1, 1], + ['shear', '切变', 30, -200, 200], +]; diff --git a/plugins/webguhui/minimax-photo/miniapp/client/client-api.ts b/plugins/webguhui/minimax-photo/miniapp/client/client-api.ts new file mode 100644 index 00000000..e261a6be --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/client-api.ts @@ -0,0 +1,301 @@ +/** + * Copyable Mini App Client declarations for TypeScript and JavaScript/JSDoc authoring. + * No Host implementation or runtime import: Electron preload provides window.mcode. + * Keep the .ts filename because Electron dependency packaging filters out .d.ts assets. + * Node start(context) uses miniapp-api.ts instead. See client-api.md for usage and errors. + */ +export interface MiniAppMessageAPI { + /** + * Ask the user to append plain text to this Mini App's conversation input. + * Accepts at most 100,000 UTF-16 code units and preserves spaces, tabs, and newlines. + * An empty string still requires confirmation and leaves the draft unchanged. + * Resolves after the confirmed append; rejects on cancellation or failure. + * Does not send a message or insert, edit, or delete sent chat history. + */ + append(text: string): Promise; +} + +export type MiniAppAgentQuestionMode = 'questionnaire' | 'feature-enable' | 'plan'; + +export interface MiniAppAgentQuestionOption { + readonly id: string; + readonly label: string; + readonly description?: string; +} + +export interface MiniAppAgentQuestionStep { + readonly id: string; + readonly header?: string; + readonly question: string; + readonly description?: string; + readonly selectionMode: 'single' | 'multiple'; + readonly options: readonly MiniAppAgentQuestionOption[]; + /** Free-text "other" is always accepted; see `MiniAppAgentQuestionAnswer.otherText`. */ + readonly allowOther: true; +} + +/** Same questionnaire the Host chat renders; render every step and answer each one. */ +export interface MiniAppAgentQuestionnaire { + readonly schemaVersion: 2; + readonly id: string; + readonly title?: string; + readonly steps: readonly MiniAppAgentQuestionStep[]; + readonly mode?: MiniAppAgentQuestionMode; + /** Plan review Markdown and other mode-specific data. */ + readonly modePayload?: { readonly [key: string]: unknown }; + /** Unix ms; the request is withdrawn after this. */ + readonly expiresAt?: number; +} + +export interface MiniAppAgentQuestionAnswer { + readonly stepId: string; + readonly selectedOptionIds: readonly string[]; + readonly selectedOther: boolean; + readonly otherText?: string; + readonly skipped?: boolean; +} + +/** Final outcome of one Agent turn. */ +export interface MiniAppAgentRunResult { + /** Pass back in `run({ sessionId })` to continue the same conversation. */ + readonly sessionId: string; + /** Absent when no turn ran: an `answer` accepted without starting a continuation. */ + readonly turnId?: string; + /** `aborted` only when the Host confirmed the abort; an unconfirmed cancel rejects with `result_unknown`. */ + readonly status: 'finished' | 'error' | 'aborted'; + /** Final assistant reply; absent when the turn produced none or did not finish. */ + readonly text?: string; + readonly error?: { readonly code: string; readonly message: string }; + /** Set when the turn ended waiting on a questionnaire; render `request` and continue with `agent.answer`. */ + readonly pendingQuestion?: { + readonly requestId: string; + readonly mode: MiniAppAgentQuestionMode; + readonly request: MiniAppAgentQuestionnaire; + }; +} + +/** + * Progress of one run. `turnId` matches the result's, except that a `permission.requested` raised + * by a delegated child session carries that child's own `sessionId` and `turnId`; `reply` with + * those, and do not filter events by the root turn. Ignore unknown `type` values: new event + * types may be added without notice. + * - `turn.started`: the Agent began the turn. + * - `text.delta`: a piece of the reply as it streams. + * - `message.committed`: one complete assistant message (a turn can have several). + * - `tool.started` / `tool.finished`: a tool call by name; `ok` is false when it failed. + * - `permission.requested`: a tool call waits for approval; decide it with `agent.reply`. + * - `question.requested`: the turn paused on a questionnaire; continue with `agent.answer`. + * - `turn.finished`: always last; same `status`, `text`, and `error` as the run result. + * Every event names its `sessionId`, so `reply` works before the `run` that created the session + * has returned. `answer` does not: call it after the paused `run` resolves, or it rejects as busy. + */ +export type MiniAppAgentRunEvent = + | { readonly type: 'turn.started'; readonly sessionId: string; readonly turnId: string } + | { + readonly type: 'text.delta'; + readonly sessionId: string; + readonly turnId: string; + readonly text: string; + } + | { + readonly type: 'message.committed'; + readonly sessionId: string; + readonly turnId: string; + readonly text: string; + } + | { + readonly type: 'tool.started'; + readonly sessionId: string; + readonly turnId: string; + readonly name: string; + } + | { + readonly type: 'tool.finished'; + readonly sessionId: string; + readonly turnId: string; + readonly name: string; + readonly ok: boolean; + } + | { + readonly type: 'permission.requested'; + readonly sessionId: string; + /** Absent when the runtime did not attribute the ask to a turn. */ + readonly turnId?: string; + readonly requestId: string; + readonly toolName: string; + readonly toolInput?: string; + readonly reason: string; + } + | { + readonly type: 'question.requested'; + readonly sessionId: string; + readonly turnId?: string; + readonly requestId: string; + readonly mode: MiniAppAgentQuestionMode; + readonly request: MiniAppAgentQuestionnaire; + } + | { + readonly type: 'turn.finished'; + readonly sessionId: string; + readonly turnId: string; + readonly status: 'finished' | 'error' | 'aborted'; + readonly text?: string; + readonly error?: { readonly code: string; readonly message: string }; + }; + +export interface MiniAppAgentRunInput { + /** Plain text, at most 100,000 UTF-16 code units. */ + readonly text: string; + /** Continue a session this Mini App created earlier; omit to start a new one. */ + readonly sessionId?: string; + /** Your id for `cancel(requestId)`; 1-128 characters, unique among this page's active runs. */ + readonly requestId?: string; +} + +export interface MiniAppAgentReplyInput { + readonly sessionId: string; + /** `requestId` of the `permission.requested` event. */ + readonly requestId: string; + /** No `allowAlways`: a Mini App never writes the user's global rules. */ + readonly decision: 'allowOnce' | 'deny'; +} + +export interface MiniAppAgentAnswerInput { + readonly sessionId: string; + /** `requestId` of the `question.requested` event or of `result.pendingQuestion`. */ + readonly questionId: string; + /** One answer per questionnaire step. */ + readonly answers: readonly MiniAppAgentQuestionAnswer[]; + /** Your id for `cancel(requestId)`, as in `run`. */ + readonly requestId?: string; +} + +export interface MiniAppAgentRunOptions { + readonly onEvent?: (event: MiniAppAgentRunEvent) => void; +} + +/** + * Absent on older Hosts. Calls reject with `not_permitted` unless the manifest declares + * `agentAccess: ["session.run"]`. A new session uses the Agent of the chat this page is open in; + * a page without a host chat uses the primary Agent. Continuing a session keeps its Agent. + * It runs one turn with that Agent's full capabilities (files, shell, Skills, MCP including this + * Mini App's own), and resolves when it ends. + * + * Interaction is yours to render: handle `permission.requested` with `reply` and + * `question.requested` with `answer`. A permission request waits only while this run passed + * `onEvent` or the session is open in a chat side panel through `open`; otherwise it is denied + * and the model is told why. A run with `onEvent` that does not handle the request waits until + * `cancel` or the page closes; there is no timeout. Up to 4 concurrent runs per Mini App, one per + * session. + * Failures reject with an `Error` whose `message` is `invalid_request`, `not_permitted`, `busy`, + * `session_not_found`, `runtime_unavailable`, `cancelled`, `result_unknown`, or + * `request_not_found`. `runtime_unavailable` means nothing was started; `result_unknown` means + * the turn may have run (or ended without the Host knowing whether a question is pending), so + * never repeat it automatically. + */ +export interface MiniAppAgentAPI { + run( + input: MiniAppAgentRunInput, + options?: MiniAppAgentRunOptions, + ): Promise; + /** Decide a pending permission request; `request_not_found` when it is unknown or settled. */ + reply(input: MiniAppAgentReplyInput): Promise; + /** + * Answer a questionnaire; the continuation turn is observed like `run`. Rejects with + * `result_unknown` when the answer was recorded but the continuation turn was not observed. + */ + answer( + input: MiniAppAgentAnswerInput, + options?: MiniAppAgentRunOptions, + ): Promise; + /** Ask the Host to stop an active run or answer; unknown or finished ids are ignored. */ + cancel(requestId: string): void; + /** + * Show one of this Mini App's sessions as a tab in the side panel of the chat the + * Mini App is open in, where the user can read the conversation and answer + * permission and question cards themselves. Permission requests wait for the tab only + * while it stays open; once the user closes it, handle `permission.requested` yourself + * or call `open` again. Any session this Mini App owns can be opened, whichever chat + * created it; `session_not_found` otherwise. + */ + open(sessionId: string): Promise; +} + +export interface MiniAppClientAPI { + readonly message: MiniAppMessageAPI; + readonly agent?: MiniAppAgentAPI; + /** + * Proposed: shape may still change. Feature-detect with + * `window.mcode?.miniapp?.window` before use. + */ + readonly window?: MiniAppWindowHandle; +} + +/** Live state of the popped-out window: current position, size, and flags — not the manifest declaration. */ +export interface MiniAppWindowOptions { + readonly width: number; + readonly height: number; + readonly minWidth: number; + readonly minHeight: number; + readonly x: number; + readonly y: number; + readonly visible: boolean; + readonly resizable: boolean; + readonly frame: boolean; + readonly transparent: boolean; + readonly alwaysOnTop: boolean; + readonly clickThrough: boolean; + readonly skipTaskbar: boolean; +} + +export type MiniAppWindowState = + | { readonly mode: 'inline' } + | { readonly mode: 'window'; readonly window: MiniAppWindowOptions }; + +/** Every field is optional; omitted fields are left unchanged. */ +export type MiniAppWindowPatch = Partial<{ + mode: 'inline' | 'window'; + width: number; + height: number; + x: number; + y: number; + visible: boolean; + resizable: boolean; + alwaysOnTop: boolean; + clickThrough: boolean; + skipTaskbar: boolean; +}>; + +export interface MiniAppWindowDisposable { + dispose(): void; +} + +/** + * Page-side handle for this Mini App's own window (proposed). Separate from + * `message`; the Host injects both under the same `mcode.miniapp` namespace. + */ +export interface MiniAppWindowHandle { + /** Opaque and stable across pop-out and return; never a Session or launch identifier. */ + readonly id: string; + getState(): Promise; + /** + * `update({ mode: ... })` or `focus()` require the call to originate from a + * user gesture (`navigator.userActivation.isActive`); otherwise they reject + * with `not_permitted` before any Host round trip. + */ + update(patch: MiniAppWindowPatch): Promise; + focus(): Promise; + /** Returns a disposable; call `dispose()` to stop receiving updates. */ + onDidChangeState(listener: (state: MiniAppWindowState) => void): MiniAppWindowDisposable; +} + +export interface McodeClientAPI { + readonly miniapp: MiniAppClientAPI; +} + +declare global { + interface Window { + /** Absent outside a supported managed Mini App main page. Check before use. */ + readonly mcode?: McodeClientAPI; + } +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/codecs.js b/plugins/webguhui/minimax-photo/miniapp/client/codecs.js new file mode 100644 index 00000000..b2fd1fd7 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/codecs.js @@ -0,0 +1,362 @@ +import { readBlendKey, writeBlendKey } from './psd-blends.js'; +import { canvas, documentModel, layer, composite, renderedLayer } from './model.js'; +// Minimal PSD v1 codec: 8-bit RGB, raw/RLE pixels. Unsupported modes fail explicitly. +class Reader { + constructor(buffer) { + this.view = new DataView(buffer); + this.bytes = new Uint8Array(buffer); + this.p = 0; + } + u16() { + const n = this.view.getUint16(this.p); + this.p += 2; + return n; + } + i16() { + const n = this.view.getInt16(this.p); + this.p += 2; + return n; + } + u32() { + const n = this.view.getUint32(this.p); + this.p += 4; + return n; + } + i32() { + const n = this.view.getInt32(this.p); + this.p += 4; + return n; + } + str(n) { + const s = String.fromCharCode(...this.bytes.subarray(this.p, this.p + n)); + this.p += n; + return s; + } + skip(n) { + if (n < 0 || this.p + n > this.bytes.length) throw Error('PSD 文件不完整'); + this.p += n; + } +} +function channel(r, w, h) { + const compression = r.u16(), + out = new Uint8Array(w * h); + if (compression === 0) { + out.set(r.bytes.subarray(r.p, r.p + w * h)); + r.skip(w * h); + return out; + } + if (compression !== 1) throw Error('暂不支持 ZIP 压缩 PSD,请另存为 RLE 或 PNG'); + const lengths = Array.from({ length: h }, () => r.u16()); + for (let y = 0; y < h; y++) { + const end = r.p + lengths[y]; + let x = 0; + while (r.p < end) { + let n = r.bytes[r.p++]; + if (n > 127) n -= 256; + if (n >= 0) { + for (let i = 0; i <= n; i++) { + if (x < w) out[y * w + x] = r.bytes[r.p]; + x++; + r.p++; + } + } else if (n !== -128) { + const v = r.bytes[r.p++]; + for (let i = 0; i < 1 - n; i++) { + if (x < w) out[y * w + x] = v; + x++; + } + } + } + if (x !== w) throw Error('PSD 行数据无效'); + } + return out; +} +export function readPSD(buffer, name) { + const r = new Reader(buffer); + if (r.str(4) !== '8BPS' || r.u16() !== 1) throw Error('仅支持 PSD v1,PSB 尚未支持'); + r.skip(6); + const channels = r.u16(), + h = r.u32(), + w = r.u32(), + depth = r.u16(), + mode = r.u16(); + if (depth !== 8 || mode !== 3) throw Error('仅支持 8-bit RGB PSD,请先转换颜色模式'); + canvas(w, h); + r.skip(r.u32()); + r.skip(r.u32()); + const section = r.u32(), + sectionEnd = r.p + section; + const d = documentModel(w, h, name); + if (section) { + const length = r.u32(), + end = r.p + length; + if (length) { + const count = Math.abs(r.i16()); + if (count > 100) throw Error('PSD 图层超过 100 层'); + const records = []; + let pixels = 0; + for (let i = 0; i < count; i++) { + const top = r.i32(), + left = r.i32(), + bottom = r.i32(), + right = r.i32(), + n = r.u16(), + ch = []; + const lw = right - left, + lh = bottom - top; + if (lw < 0 || lh < 0 || (pixels += lw * lh) > 128e6) throw Error('PSD 图层尺寸过大'); + for (let k = 0; k < n; k++) ch.push({ id: r.i16(), length: r.u32() }); + if (r.str(4) !== '8BIM') throw Error('PSD 图层格式无效'); + const blend = r.str(4), + opacity = r.bytes[r.p++] / 255; + r.p++; + const flags = r.bytes[r.p++]; + r.p++; + const extra = r.u32(), + extraEnd = r.p + extra; + r.skip(r.u32()); + r.skip(r.u32()); + const namelen = r.bytes[r.p++]; + let layerName = r.str(namelen); + r.skip((4 - ((namelen + 1) % 4)) % 4); + while (r.p + 12 <= extraEnd) { + const signature = r.str(4), + key = r.str(4), + size = r.u32(), + end = r.p + size; + if (signature !== '8BIM' || end > extraEnd) break; + if (key === 'luni') { + const count = r.u32(); + if (count * 2 > end - r.p || count > 10000) throw Error('PSD 图层名称无效'); + layerName = new TextDecoder('utf-16be').decode(r.bytes.subarray(r.p, r.p + count * 2)); + } + r.p = end + (size % 2); + } + r.p = extraEnd; + records.push({ + top, + left, + w: lw, + h: lh, + ch, + blend, + opacity, + visible: !(flags & 2), + name: layerName, + }); + } + const layers = []; + for (const rec of records) { + const maps = {}; + for (const c of rec.ch) { + const stop = r.p + c.length; + if (c.id >= -1 && c.id <= 2 && rec.w && rec.h) maps[c.id] = channel(r, rec.w, rec.h); + r.p = stop; + } + if (!rec.w || !rec.h) continue; + const l = layer(rec.w, rec.h, rec.name || '图层'); + l.x = rec.left; + l.y = rec.top; + l.opacity = rec.opacity; + l.visible = rec.visible; + l.blend = readBlendKey(rec.blend); + const ctx = l.canvas.getContext('2d'), + img = ctx.createImageData(rec.w, rec.h); + for (let i = 0; i < rec.w * rec.h; i++) { + for (let c = 0; c < 3; c++) img.data[i * 4 + c] = maps[c]?.[i] ?? 0; + img.data[i * 4 + 3] = maps[-1]?.[i] ?? 255; + } + ctx.putImageData(img, 0, 0); + layers.unshift(l); + } + if (layers.length) { + d.layers = layers; + d.activeId = layers.at(-1).id; + d.dirty = true; + return d; + } + r.p = end; + } + r.p = sectionEnd; + } + const compression = r.u16(), + maps = []; + if (compression === 0) + for (let c = 0; c < channels; c++) { + maps.push(r.bytes.slice(r.p, r.p + w * h)); + r.skip(w * h); + } + else if (compression === 1) { + const lengths = Array.from({ length: channels * h }, () => r.u16()); + for (let c = 0; c < channels; c++) { + const arr = new Uint8Array(w * h); + for (let y = 0; y < h; y++) { + const end = r.p + lengths[c * h + y]; + let x = 0; + while (r.p < end) { + let n = r.bytes[r.p++]; + if (n > 127) n -= 256; + if (n >= 0) { + for (let j = 0; j <= n; j++) arr[y * w + x++] = r.bytes[r.p++]; + } else if (n !== -128) { + const v = r.bytes[r.p++]; + for (let j = 0; j < 1 - n; j++) arr[y * w + x++] = v; + } + } + } + maps.push(arr); + } + } else throw Error('PSD 压缩方式不支持'); + const ctx = d.layers[0].canvas.getContext('2d'), + img = ctx.createImageData(w, h); + for (let i = 0; i < w * h; i++) { + for (let c = 0; c < 3; c++) img.data[i * 4 + c] = maps[c]?.[i] ?? 0; + img.data[i * 4 + 3] = maps[3]?.[i] ?? 255; + } + ctx.putImageData(img, 0, 0); + d.dirty = true; + return d; +} +class Writer { + constructor() { + this.parts = []; + this.length = 0; + } + bytes(a) { + const b = a instanceof Uint8Array ? a : new Uint8Array(a); + this.parts.push(b); + this.length += b.length; + } + n(v, size, signed = false) { + const a = new Uint8Array(size), + view = new DataView(a.buffer); + if (size === 2) signed ? view.setInt16(0, v) : view.setUint16(0, v); + else signed ? view.setInt32(0, v) : view.setUint32(0, v); + this.bytes(a); + } + str(s) { + this.bytes(Uint8Array.from(s, (c) => c.charCodeAt(0))); + } + finish() { + const out = new Uint8Array(this.length); + let p = 0; + for (const a of this.parts) { + out.set(a, p); + p += a.length; + } + return out; + } +} +export function writePSD(d) { + const out = new Writer(); + out.str('8BPS'); + out.n(1, 2); + out.bytes(new Uint8Array(6)); + out.n(4, 2); + out.n(d.height, 4); + out.n(d.width, 4); + out.n(8, 2); + out.n(3, 2); + out.n(0, 4); + out.n(0, 4); + const records = new Writer(), + pixels = new Writer(); + records.n(d.layers.length, 2, true); + for (const l of [...d.layers].reverse()) { + const rendered = renderedLayer(l); + const w = rendered.image.width, + h = rendered.image.height; + records.n(Math.round(l.y + rendered.offset), 4, true); + records.n(Math.round(l.x + rendered.offset), 4, true); + records.n(Math.round(l.y + rendered.offset) + h, 4, true); + records.n(Math.round(l.x + rendered.offset) + w, 4, true); + records.n(4, 2); + for (const id of [0, 1, 2, -1]) { + records.n(id, 2, true); + records.n(w * h + 2, 4); + } + records.str('8BIM'); + records.str(writeBlendKey(l.blend)); + records.bytes([Math.round(l.opacity * 255), 0, l.visible ? 0 : 2, 0]); + const extra = new Writer(); + extra.n(0, 4); + extra.n(0, 4); + const name = String(l.name) + .replace(/[^\x20-\x7e]/g, '_') + .slice(0, 255); + extra.bytes([name.length]); + extra.str(name); + extra.bytes(new Uint8Array((4 - ((name.length + 1) % 4)) % 4)); + const unicode = String(l.name).slice(0, 200); + extra.str('8BIM'); + extra.str('luni'); + extra.n(4 + unicode.length * 2, 4); + extra.n(unicode.length, 4); + for (let i = 0; i < unicode.length; i++) extra.n(unicode.charCodeAt(i), 2); + records.n(extra.length, 4); + records.bytes(extra.finish()); + const ctx = rendered.image.getContext('2d'), + data = ctx.getImageData(0, 0, w, h).data; + for (const c of [0, 1, 2, 3]) { + pixels.n(0, 2); + const p = new Uint8Array(w * h); + for (let i = 0; i < p.length; i++) p[i] = data[i * 4 + c]; + pixels.bytes(p); + } + } + const layerInfo = new Writer(); + layerInfo.bytes(records.finish()); + layerInfo.bytes(pixels.finish()); + if (layerInfo.length % 2) layerInfo.bytes([0]); + const section = new Writer(); + section.n(layerInfo.length, 4); + section.bytes(layerInfo.finish()); + section.n(0, 4); + out.n(section.length, 4); + out.bytes(section.finish()); + out.n(0, 2); + const merged = composite(d).getContext('2d').getImageData(0, 0, d.width, d.height).data; + for (let c = 0; c < 4; c++) { + const p = new Uint8Array(d.width * d.height); + for (let i = 0; i < p.length; i++) p[i] = merged[i * 4 + c]; + out.bytes(p); + } + return new Blob([out.finish()], { type: 'image/vnd.adobe.photoshop' }); +} +export async function exportPDF(c) { + const jpeg = await new Promise((ok) => c.toBlob(ok, 'image/jpeg', 0.95)); + const image = new Uint8Array(await jpeg.arrayBuffer()), + enc = new TextEncoder(), + parts = [], + offsets = [0]; + let length = 0; + const add = (s) => { + const b = typeof s === 'string' ? enc.encode(s) : s; + parts.push(b); + length += b.length; + }; + add('%PDF-1.4\n'); + const obj = (n, s) => { + offsets[n] = length; + add(n + ' 0 obj\n' + s + '\nendobj\n'); + }; + obj(1, '<< /Type /Catalog /Pages 2 0 R >>'); + obj(2, '<< /Type /Pages /Kids [3 0 R] /Count 1 >>'); + obj( + 3, + `<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${c.width} ${c.height}] /Resources << /XObject << /Im0 4 0 R >> >> /Contents 5 0 R >>`, + ); + offsets[4] = length; + add( + `4 0 obj\n<< /Type /XObject /Subtype /Image /Width ${c.width} /Height ${c.height} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode /Length ${image.length} >>\nstream\n`, + ); + add(image); + add('\nendstream\nendobj\n'); + const content = `q ${c.width} 0 0 ${c.height} 0 0 cm /Im0 Do Q`; + obj(5, `<< /Length ${content.length} >>\nstream\n${content}\nendstream`); + const xref = length; + add('xref\n0 6\n0000000000 65535 f \n'); + for (let i = 1; i <= 5; i++) add(String(offsets[i]).padStart(10, '0') + ' 00000 n \n'); + add(`trailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n${xref}\n%%EOF`); + return new Blob(parts, { type: 'application/pdf' }); +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/color-replace.js b/plugins/webguhui/minimax-photo/miniapp/client/color-replace.js new file mode 100644 index 00000000..a43c9d0e --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/color-replace.js @@ -0,0 +1,16 @@ +import { blendPixel } from './blending.js'; +// The patch carries brush coverage. Drawing with source-atop preserves the +// destination alpha while the color blend retains its original luminance. +export function colorReplacementPatch(pixels, coverage, color) { + const result = new Uint8ClampedArray(coverage); + const rgb = [0, 0, 0]; + for (let i = 0; i < result.length; i += 4) { + if (!result[i + 3]) continue; + result.set(color, i); + blendPixel('color', pixels, result, i, rgb); + result[i] = rgb[0]; + result[i + 1] = rgb[1]; + result[i + 2] = rgb[2]; + } + return result; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/components.css b/plugins/webguhui/minimax-photo/miniapp/client/components.css new file mode 100644 index 00000000..798cfd4c --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/components.css @@ -0,0 +1,2 @@ +/*! tailwindcss v4.1.14 | MIT License | https://tailwindcss.com */ +@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--font-weight-medium:500;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1)}}@layer utilities{.z-50{z-index:50}.hidden{display:none}.inline-flex{display:inline-flex}.table{display:table}.size-2\.5{width:calc(var(--spacing)*2.5);height:calc(var(--spacing)*2.5)}.size-6{width:calc(var(--spacing)*6);height:calc(var(--spacing)*6)}.size-8{width:calc(var(--spacing)*8);height:calc(var(--spacing)*8)}.size-9{width:calc(var(--spacing)*9);height:calc(var(--spacing)*9)}.size-10{width:calc(var(--spacing)*10);height:calc(var(--spacing)*10)}.h-6{height:calc(var(--spacing)*6)}.h-8{height:calc(var(--spacing)*8)}.h-9{height:calc(var(--spacing)*9)}.h-10{height:calc(var(--spacing)*10)}.w-fit{width:fit-content}.shrink-0{flex-shrink:0}.origin-\(--radix-tooltip-content-transform-origin\){transform-origin:var(--radix-tooltip-content-transform-origin)}.translate-y-\[calc\(-50\%_-_2px\)\]{--tw-translate-y:calc(-50% - 2px);translate:var(--tw-translate-x)var(--tw-translate-y)}.rotate-45{rotate:45deg}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.resize{resize:both}.items-center{align-items:center}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.rounded-\[2px\]{border-radius:2px}.rounded-md{border-radius:8px}.border{border-style:var(--tw-border-style);border-width:1px}.bg-background{background-color:var(--mcode-bg)}.bg-destructive{background-color:var(--mcode-danger)}.bg-foreground{background-color:var(--mcode-text)}.bg-primary{background-color:var(--mcode-primary-action-bg)}.bg-secondary{background-color:var(--mcode-surface-muted)}.fill-foreground{fill:var(--mcode-text)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.text-balance{text-wrap:balance}.whitespace-nowrap{white-space:nowrap}.text-background{color:var(--mcode-bg)}.text-primary{color:var(--mcode-primary-action-bg)}.text-primary-foreground{color:var(--mcode-primary-action-text)}.text-secondary-foreground{color:var(--mcode-text)}.text-white{color:var(--color-white)}.underline-offset-4{text-underline-offset:4px}.shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.outline-none{--tw-outline-style:none;outline-style:none}@media (hover:hover){.hover\:bg-accent:hover{background-color:var(--mcode-surface-muted)}.hover\:bg-destructive\/90:hover{background-color:var(--mcode-danger)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-destructive\/90:hover{background-color:color-mix(in oklab,var(--mcode-danger)90%,transparent)}}.hover\:bg-primary\/90:hover{background-color:var(--mcode-primary-action-bg)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--mcode-primary-action-bg)90%,transparent)}}.hover\:bg-secondary\/80:hover{background-color:var(--mcode-surface-muted)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab,var(--mcode-surface-muted)80%,transparent)}}.hover\:text-accent-foreground:hover{color:var(--mcode-text)}.hover\:underline:hover{text-decoration-line:underline}}.focus-visible\:border-ring:focus-visible{border-color:var(--mcode-accent)}.focus-visible\:ring-\[3px\]:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(3px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:var(--mcode-danger)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:color-mix(in oklab,var(--mcode-danger)20%,transparent)}}.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:var(--mcode-accent)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:color-mix(in oklab,var(--mcode-accent)50%,transparent)}}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}.has-\[\>svg\]\:px-1\.5:has(>svg){padding-inline:calc(var(--spacing)*1.5)}.has-\[\>svg\]\:px-2\.5:has(>svg){padding-inline:calc(var(--spacing)*2.5)}.has-\[\>svg\]\:px-3:has(>svg){padding-inline:calc(var(--spacing)*3)}.has-\[\>svg\]\:px-4:has(>svg){padding-inline:calc(var(--spacing)*4)}.aria-invalid\:border-destructive[aria-invalid=true]{border-color:var(--mcode-danger)}.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:var(--mcode-danger)}@supports (color:color-mix(in lab, red, red)){.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--mcode-danger)20%,transparent)}}@media (prefers-color-scheme:dark){.dark\:border-input{border-color:var(--mcode-border)}.dark\:bg-destructive\/60{background-color:var(--mcode-danger)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-destructive\/60{background-color:color-mix(in oklab,var(--mcode-danger)60%,transparent)}}.dark\:bg-input\/30{background-color:var(--mcode-border)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-input\/30{background-color:color-mix(in oklab,var(--mcode-border)30%,transparent)}}@media (hover:hover){.dark\:hover\:bg-accent\/50:hover{background-color:var(--mcode-surface-muted)}@supports (color:color-mix(in lab, red, red)){.dark\:hover\:bg-accent\/50:hover{background-color:color-mix(in oklab,var(--mcode-surface-muted)50%,transparent)}}.dark\:hover\:bg-input\/50:hover{background-color:var(--mcode-border)}@supports (color:color-mix(in lab, red, red)){.dark\:hover\:bg-input\/50:hover{background-color:color-mix(in oklab,var(--mcode-border)50%,transparent)}}}.dark\:focus-visible\:ring-destructive\/40:focus-visible{--tw-ring-color:var(--mcode-danger)}@supports (color:color-mix(in lab, red, red)){.dark\:focus-visible\:ring-destructive\/40:focus-visible{--tw-ring-color:color-mix(in oklab,var(--mcode-danger)40%,transparent)}}.dark\:aria-invalid\:ring-destructive\/40[aria-invalid=true]{--tw-ring-color:var(--mcode-danger)}@supports (color:color-mix(in lab, red, red)){.dark\:aria-invalid\:ring-destructive\/40[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--mcode-danger)40%,transparent)}}}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-3 svg:not([class*=size-]){width:calc(var(--spacing)*3);height:calc(var(--spacing)*3)}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-4 svg:not([class*=size-]){width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false} \ No newline at end of file diff --git a/plugins/webguhui/minimax-photo/miniapp/client/curves-dialog.js b/plugins/webguhui/minimax-photo/miniapp/client/curves-dialog.js new file mode 100644 index 00000000..99ff7e91 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/curves-dialog.js @@ -0,0 +1,127 @@ +import { canvas } from './model.js'; +import { curveLUT, applyCurves } from './tone.js'; +const inputs = [0, 64, 128, 192, 255]; +const identity = () => inputs.map((x) => [x, x]); +export function showCurvesDialog(source, { modal, applyFilter, initialCurves, description }) { + const curves = Object.fromEntries( + ['rgb', 'red', 'green', 'blue'].map((key) => [ + key, + structuredClone(initialCurves?.[key] || identity()), + ]), + ); + const channel = document.createElement('select'); + channel.setAttribute('aria-label', '曲线通道'); + for (const [value, label] of [ + ['rgb', 'RGB 总通道'], + ['red', '红色'], + ['green', '绿色'], + ['blue', '蓝色'], + ]) { + const option = document.createElement('option'); + option.value = value; + option.textContent = label; + channel.append(option); + } + const graph = canvas(320, 200); + graph.setAttribute('aria-label', '曲线图:横轴输入亮度,纵轴输出亮度'); + graph.style.width = '100%'; + graph.style.height = '160px'; + const preview = canvas( + Math.max(1, Math.round(source.width * Math.min(1, 360 / source.width, 220 / source.height))), + Math.max(1, Math.round(source.height * Math.min(1, 360 / source.width, 220 / source.height))), + ); + preview.style.maxWidth = '100%'; + preview.style.margin = 'auto'; + preview.style.background = '#aaa'; + preview.setAttribute('aria-label', '当前图层曲线预览'); + const ctx = preview.getContext('2d'); + ctx.drawImage(source, 0, 0, preview.width, preview.height); + const original = ctx.getImageData(0, 0, preview.width, preview.height); + const rows = document.createElement('div'); + rows.className = 'curve-controls'; + function redraw() { + const lut = curveLUT(curves[channel.value]), + g = graph.getContext('2d'), + width = graph.width, + height = graph.height; + g.fillStyle = '#191b1e'; + g.fillRect(0, 0, width, height); + g.strokeStyle = '#42464d'; + g.lineWidth = 1; + for (let i = 0; i <= 4; i++) { + g.beginPath(); + g.moveTo((i * width) / 4, 0); + g.lineTo((i * width) / 4, height); + g.moveTo(0, (i * height) / 4); + g.lineTo(width, (i * height) / 4); + g.stroke(); + } + g.strokeStyle = '#767c86'; + g.beginPath(); + g.moveTo(0, height); + g.lineTo(width, 0); + g.stroke(); + g.strokeStyle = { rgb: '#dce7ef', red: '#ef9292', green: '#8dce9b', blue: '#8daef0' }[ + channel.value + ]; + g.lineWidth = 2; + g.beginPath(); + for (let i = 0; i < 256; i++) { + const x = (i / 255) * width, + y = height - (lut[i] / 255) * height; + i ? g.lineTo(x, y) : g.moveTo(x, y); + } + g.stroke(); + for (const [x, y] of curves[channel.value]) { + g.fillStyle = g.strokeStyle; + g.beginPath(); + g.arc((x / 255) * width, height - (y / 255) * height, 4, 0, Math.PI * 2); + g.fill(); + } + ctx.putImageData( + new ImageData(applyCurves(original.data, curves), original.width, original.height), + 0, + 0, + ); + } + function controls() { + rows.replaceChildren(); + curves[channel.value].forEach(([x, y], i) => { + const label = document.createElement('label'); + label.textContent = `输入 ${x} → 输出`; + const input = document.createElement('input'); + input.type = 'range'; + input.min = '0'; + input.max = '255'; + input.value = y; + input.setAttribute('aria-label', `输入 ${x} 的输出`); + const output = document.createElement('output'); + output.textContent = y; + input.oninput = () => { + curves[channel.value][i][1] = Number(input.value); + output.textContent = input.value; + redraw(); + }; + label.append(input, output); + rows.append(label); + }); + redraw(); + } + const reset = document.createElement('button'); + reset.type = 'button'; + reset.textContent = '重置当前通道'; + reset.onclick = () => { + curves[channel.value] = identity(); + controls(); + }; + channel.onchange = controls; + const note = document.createElement('p'); + note.textContent = description || '预览只显示当前图层。应用时尊重选区;可撤销。'; + modal( + '曲线', + [channel, graph, rows, reset, preview, note], + () => applyFilter('curves', { curves }, '曲线'), + '应用', + ); + controls(); +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/dialogs.js b/plugins/webguhui/minimax-photo/miniapp/client/dialogs.js new file mode 100644 index 00000000..73523760 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/dialogs.js @@ -0,0 +1,66 @@ +export function createDialogs(dialog, status) { + let generation = 0; + function modal(title, fields, onOk, ok = '确定') { + const current = ++generation; + dialog.close(); + // A successful action can open the next dialog while old controls are disabled. + for (const control of dialog.querySelectorAll('button')) control.disabled = false; + dialog.querySelector('#dialog-title').textContent = title; + const body = dialog.querySelector('#dialog-body'), + apply = dialog.querySelector('#dialog-ok'); + const error = document.createElement('p'); + error.setAttribute('role', 'alert'); + error.hidden = true; + body.replaceChildren(...fields, error); + apply.textContent = ok; + apply.disabled = false; + let pending = false; + dialog.oncancel = (e) => { + if (pending) e.preventDefault(); + }; + apply.onclick = async () => { + if (pending) return; + pending = true; + error.hidden = true; + const controls = [...dialog.querySelectorAll('button,input,select,textarea')].map( + (element) => [element, element.disabled], + ); + controls.forEach(([element]) => (element.disabled = true)); + apply.textContent = '处理中…'; + try { + const result = await onOk(); + if (current === generation && result !== false) dialog.close(); + } catch (e) { + if (current === generation) { + error.textContent = e.message || '操作失败,请重试'; + error.hidden = false; + status(error.textContent, true); + } + } finally { + if (current === generation) { + pending = false; + controls.forEach(([element, disabled]) => (element.disabled = disabled)); + apply.textContent = ok; + } + } + }; + dialog.showModal(); + } + return { modal }; +} +export function field(label, value, type = 'number', attrs = {}) { + const row = document.createElement('label'); + row.textContent = label; + const input = document.createElement('input'); + input.type = type; + Object.assign(input, attrs); + // Range inputs clamp and round immediately; configure their bounds before setting the value. + input.value = value; + row.append(input); + return [row, input]; +} +export function note(text) { + const p = document.createElement('p'); + p.textContent = text; + return p; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/editor-bridge.js b/plugins/webguhui/minimax-photo/miniapp/client/editor-bridge.js new file mode 100644 index 00000000..142a5ec4 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/editor-bridge.js @@ -0,0 +1,150 @@ +import { readEditorImage } from './editor-read.js'; +import { executeEditorBatch, describeDocument } from './editor-commands.js'; +import { serialize, documentModel } from './model.js'; + +export function installEditorBridge(state, { refresh, status, runFilter, addDoc }) { + const editorId = crypto.randomUUID(); + let version = crypto.randomUUID(), + events, + timer, + closed = false, + running = false, + reportTimer; + const post = async (path, body) => { + const response = await fetch(path, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body), + }); + const result = await response.json(); + if (!response.ok) throw Error(result.error || 'Agent 编辑连接失败'); + return result; + }; + async function report() { + if (closed) return; + await post('/api/editor/register', { + editorId, + version, + document: state.doc ? describeDocument(state.doc) : null, + }); + } + const changed = () => { + version = crypto.randomUUID(); + clearTimeout(reportTimer); + reportTimer = setTimeout(() => { + report().catch(() => {}); + }, 100); + }; + async function handle(jobId) { + let job, + committed = false; + try { + job = await post(`/api/editor/${editorId}/claim`, { jobId }); + if ( + running || + state.busy || + state.drag || + state.polygonDraft || + document.querySelector('#dialog').open + ) + throw Error('用户正在编辑或有弹窗,请结束当前操作再试'); + if (job.expectedVersion !== version) throw Error('工程已变化,请重新读取状态'); + if (!state.doc && job.kind !== 'create') throw Error('没有打开工程'); + running = true; + state.busy = true; + document.body.inert = true; + status(job.kind === 'preview' ? 'Agent 正在读取画面…' : 'Agent 正在编辑,完成后可整体撤销…'); + const original = + job.kind === 'create' + ? documentModel(job.newDocument.width, job.newDocument.height, job.newDocument.name) + : state.doc; + const result = + job.kind === 'batch' + ? await executeEditorBatch(original, job.operations, { runFilter }) + : { document: original, results: [], description: describeDocument(original) }; + const { preview, full, scale, region, pixels } = readEditorImage( + result.document, + job.options, + ); + const checkpoint = ['batch', 'export', 'create'].includes(job.kind) + ? await serialize(result.document) + : undefined; + const finish = { + jobId, + claim: job.claim, + preview: preview.toDataURL('image/png'), + checkpoint, + exportImage: job.kind === 'export' ? full.toDataURL('image/png') : undefined, + result: { + ...result.description, + steps: result.results, + previewScale: scale, + region, + pixels, + }, + }; + // Durable checkpoint first. A lost response must not cause a new plan to run. + await post(`/api/editor/${editorId}/finish`, finish); + if (job.kind === 'batch') { + const index = state.docs.indexOf(original); + state.docs[index] = result.document; + state.doc = result.document; + state.maskEditing = false; + refresh(); + } + if (job.kind === 'create') addDoc(result.document); + committed = true; + await post(`/api/editor/${editorId}/ack`, { jobId, claim: job.claim, version }); + status( + job.kind === 'create' + ? 'Agent 已新建工程 · 原工程保留' + : ['batch'].includes(job.kind) + ? 'Agent 编辑完成 · 可撤销整批操作 · 检查点已保存' + : 'Agent 已读取画面', + ); + } catch (error) { + if (job && !committed) + await post(`/api/editor/${editorId}/finish`, { + jobId, + claim: job.claim, + error: error.message, + }).catch(() => {}); + status( + committed ? '编辑已应用,但回执未确认;请检查当前工程,不要重复执行' : error.message, + true, + ); + } finally { + if (running) { + state.busy = false; + running = false; + document.body.inert = false; + } + await report().catch(() => {}); + } + } + report() + .then(() => { + if (closed) return; + events = new EventSource(`/api/editor/${editorId}/events`); + events.addEventListener('command', (event) => { + const { jobId } = JSON.parse(event.data); + void handle(jobId); + }); + }) + .catch(() => status('Agent 编辑连接未建立;手动修图仍可使用', true)); + timer = setInterval(() => { + report().catch(() => {}); + }, 15000); + window.addEventListener( + 'pagehide', + () => { + closed = true; + events?.close(); + clearInterval(timer); + clearTimeout(reportTimer); + }, + { once: true }, + ); + changed.context = () => ({ editorId, version }); + return changed; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/editor-commands.js b/plugins/webguhui/minimax-photo/miniapp/client/editor-commands.js new file mode 100644 index 00000000..8403a5ce --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/editor-commands.js @@ -0,0 +1,569 @@ +// Both Agent transactions and UI can use these model-level operations. +// No eval, DOM events, network access or arbitrary code in a submitted plan. +import { + canvas, + cloneCanvas, + layer, + active, + blends, + composite, + clipSelection, + imageFrom, + begin, + undo, + redo, +} from './model.js'; +import { adjustments, filters } from './catalog.js'; +import { normalizeAdjustment } from './adjustment-layers.js'; +import { normalizeStyles } from './layer-styles.js'; + +const number = (v, min, max, name) => { + if (!Number.isFinite(v) || v < min || v > max) throw Error(`${name} 必须在 ${min}–${max} 之间`); + return v; +}; +const text = (v, name, max = 200) => { + if (typeof v !== 'string' || !v.trim() || v.length > max) throw Error(`${name} 无效`); + return v; +}; +const color = (v) => { + if (typeof v !== 'string' || !/^#[0-9a-f]{6}([0-9a-f]{2})?$/i.test(v)) + throw Error('颜色须为 #RRGGBB 或 #RRGGBBAA'); + return v; +}; +const integer = (v, min, max, name) => { + number(v, min, max, name); + if (!Number.isInteger(v)) throw Error(`${name} 必须是整数`); + return v; +}; +const point = (v) => { + if (!Array.isArray(v) || v.length !== 2) throw Error('坐标必须为 [x,y]'); + return v.map((n) => number(n, -32000, 32000, '坐标')); +}; +const fields = (op, allowed) => { + if (Object.keys(op).some((k) => !['op', 'as', ...allowed].includes(k))) + throw Error(`操作 ${op.op} 包含未知参数`); +}; +export function describeDocument(d) { + return { + id: d.id, + name: d.name, + width: d.width, + height: d.height, + savedRevision: d.revision, + activeLayerId: d.activeId, + dirty: d.dirty, + undoCount: d.history.length, + redoCount: d.future.length, + selection: d.selection, + layers: d.layers.map((l, index) => ({ + id: l.id, + index, + name: l.name, + width: l.canvas.width, + height: l.canvas.height, + x: l.x, + y: l.y, + opacity: l.opacity, + blend: l.blend, + visible: l.visible, + locked: l.locked, + hasMask: !!l.mask, + text: l.text, + adjustment: l.adjustment, + styles: l.styles, + clipToBelow: !!l.clipToBelow, + })), + }; +} +export const editorCapabilities = { + coordinates: '画布像素坐标,原点左上;图层顺序从底到顶;颜色为 #RRGGBB 或 #RRGGBBAA。', + composition: + 'operations 按顺序运行,最多 64 步。创建或选择图层的步骤可用 as 命名,后续 layerId:"$名字" 引用;省略 layerId 使用当前图层。整批成功后成为一次撤销;任一步失败则不修改工程。', + operations: { + select_layer: { layerId: '已有图层 ID 或 $引用' }, + add_layer: { name: '名称' }, + duplicate_layer: { layerId: '可选', name: '可选名称' }, + update_layer: { + layerId: '可选', + name: '可选', + x: '可选坐标', + y: '可选坐标', + opacity: '0–1', + blend: '混合模式 ID', + visible: '布尔', + locked: '布尔', + }, + reorder_layer: { layerId: '可选', index: '从底部开始的目标索引' }, + delete_layer: { layerId: '可选;保留至少一层' }, + selection: { + kind: 'none / rect / ellipse / polygon', + x: '矩形位置', + y: '矩形位置', + width: '正整数', + height: '正整数', + points: 'polygon 的 [x,y] 数组', + }, + fill: { layerId: '可选', color: '#RRGGBB', opacity: '可选 0–1' }, + stroke: { + layerId: '可选', + points: '最多 4096 个 [x,y]', + color: '#RRGGBB', + size: '1–1000', + opacity: '可选 0–1', + erase: '可选布尔', + }, + shape: { + layerId: '可选', + kind: 'rect / ellipse / line', + x: '坐标', + y: '坐标', + width: '1–32000', + height: '1–32000', + color: '#RRGGBB', + fill: '布尔,默认 true', + size: '描边宽度', + }, + text: { + value: '文字,最多 2000 字', + x: '坐标', + y: '基线坐标', + size: '1–1000', + color: '#RRGGBB', + font: 'sans-serif / serif / monospace', + name: '新图层名称', + }, + filter: { layerId: '可选', type: 'filters 或 adjustments 中的 ID', value: '对应数值范围' }, + adjustment: { + type: 'adjustments 中的 ID', + value: '对应数值范围', + name: '可选', + clipToBelow: '可选布尔', + }, + styles: { layerId: '可选', styles: '与工程中 styles 相同的参数;从 inspect 获取' }, + mask_selection: { layerId: '可选;当前选区作为蒙版' }, + remove_mask: { layerId: '可选' }, + image_result: { + requestId: '已完成生图任务编号', + name: '可选图层名', + x: '可选坐标', + y: '可选坐标', + }, + transform_layer: { + layerId: '可选', + scale: '0.01–10', + angle: '-360–360 度', + flipX: '可选布尔', + flipY: '可选布尔', + }, + crop: { x: '裁剪左上角', y: '裁剪左上角', width: '正整数', height: '正整数' }, + flatten: { name: '可选合并图层名' }, + undo: { note: '必须单独作为一个 batch' }, + redo: { note: '必须单独作为一个 batch' }, + }, + adjustments: adjustments.map(([id, name, defaultValue, min, max]) => ({ + id, + name, + defaultValue, + min, + max, + })), + filters: filters.map(([id, name, defaultValue, min, max]) => ({ + id, + name, + defaultValue, + min, + max, + })), + blends, +}; + +export async function executeEditorBatch(original, operations, { runFilter }) { + if (!Array.isArray(operations) || !operations.length || operations.length > 64) + throw Error('每批需要 1–64 个操作'); + // Copy-on-write: unchanged canvases are shared; edited pixels are cloned once. + const d = { + ...original, + layers: original.layers.map((l) => ({ ...l })), + history: [...original.history], + future: [...original.future], + selection: structuredClone(original.selection), + paths: structuredClone(original.paths), + }; + if (operations.length === 1 && ['undo', 'redo'].includes(operations[0]?.op)) { + fields(operations[0], []); + if (!(operations[0].op === 'undo' ? undo(d) : redo(d))) throw Error('没有可撤销或重做的操作'); + return { document: d, results: [{ op: operations[0].op }], description: describeDocument(d) }; + } + if (operations.some((op) => ['undo', 'redo'].includes(op?.op))) + throw Error('撤销与重做必须独立执行'); + begin(d, 'Agent 批量编辑'); + const refs = new Map(), + copied = new Set(), + results = []; + function target(op, pixels = false) { + let id = op.layerId; + if (typeof id === 'string' && id.startsWith('$')) { + if (!refs.has(id.slice(1))) throw Error('未定义的图层引用'); + id = refs.get(id.slice(1)); + } + const l = id === undefined ? active(d) : d.layers.find((l) => l.id === id); + if (!l) throw Error('图层不存在'); + if (l.locked && op.op !== 'select_layer' && !(op.op === 'update_layer' && op.locked === false)) + throw Error('图层已锁定'); + if (pixels && l.adjustment) throw Error('调整图层不能直接绘制像素'); + if (pixels && !copied.has(l.id)) { + l.canvas = cloneCanvas(l.canvas); + copied.add(l.id); + } + return l; + } + function add(l) { + if (d.layers.length >= 100) throw Error('最多 100 个图层'); + if ( + d.layers.reduce((sum, l) => sum + l.canvas.width * l.canvas.height, 0) + + l.canvas.width * l.canvas.height > + 128e6 + ) + throw Error('图层总像素超过限制'); + d.layers.splice(d.layers.findIndex((x) => x.id === d.activeId) + 1, 0, l); + d.activeId = l.id; + return l; + } + function draw(l, fn) { + const ctx = l.canvas.getContext('2d'); + ctx.save(); + try { + clipSelection(ctx, d, l); + ctx.translate(-l.x, -l.y); + fn(ctx); + } finally { + ctx.restore(); + } + l.text = null; + } + for (let index = 0; index < operations.length; index++) { + const op = operations[index]; + if ( + !op || + typeof op !== 'object' || + Array.isArray(op) || + !Object.hasOwn(editorCapabilities.operations, op.op) + ) + throw Error(`第 ${index + 1} 步操作无效`); + if ( + op.as !== undefined && + (typeof op.as !== 'string' || !/^[a-zA-Z][\w-]{0,39}$/.test(op.as) || refs.has(op.as)) + ) + throw Error('引用名称无效或重复'); + let l; + switch (op.op) { + case 'select_layer': + fields(op, ['layerId']); + l = target(op); + d.activeId = l.id; + break; + case 'add_layer': + fields(op, ['name']); + l = add(layer(d.width, d.height, text(op.name || 'Agent 图层', '图层名'))); + break; + case 'duplicate_layer': + fields(op, ['layerId', 'name']); + l = target(op); + l = add({ + ...l, + id: crypto.randomUUID(), + name: text(op.name || l.name + ' 副本', '图层名'), + canvas: cloneCanvas(l.canvas), + mask: l.mask ? cloneCanvas(l.mask) : null, + }); + break; + case 'update_layer': + fields(op, ['layerId', 'name', 'x', 'y', 'opacity', 'blend', 'visible', 'locked']); + l = target(op); + for (const key of ['visible', 'locked']) + if (op[key] !== undefined) { + if (typeof op[key] !== 'boolean') throw Error(`${key} 必须是布尔值`); + l[key] = op[key]; + } + if (op.name !== undefined) l.name = text(op.name, '图层名'); + for (const key of ['x', 'y']) + if (op[key] !== undefined) l[key] = number(op[key], -32000, 32000, key); + if (op.opacity !== undefined) l.opacity = number(op.opacity, 0, 1, '不透明度'); + if (op.blend !== undefined) { + if (!blends.includes(op.blend)) throw Error('未知混合模式'); + l.blend = op.blend; + } + break; + case 'reorder_layer': + fields(op, ['layerId', 'index']); + l = target(op); + integer(op.index, 0, d.layers.length - 1, '图层索引'); + d.layers.splice(d.layers.indexOf(l), 1); + d.layers.splice(op.index, 0, l); + break; + case 'delete_layer': + fields(op, ['layerId']); + l = target(op); + if (d.layers.length === 1) throw Error('至少保留一个图层'); + d.layers = d.layers.filter((x) => x.id !== l.id); + if (d.activeId === l.id) d.activeId = d.layers.at(-1).id; + break; + case 'selection': + fields(op, ['kind', 'x', 'y', 'width', 'height', 'points']); + if (op.kind === 'none') d.selection = null; + else if (['rect', 'ellipse'].includes(op.kind)) + d.selection = { + kind: op.kind, + x: number(op.x, -32000, 32000, 'x'), + y: number(op.y, -32000, 32000, 'y'), + w: integer(op.width, 1, 32000, '宽'), + h: integer(op.height, 1, 32000, '高'), + }; + else if ( + op.kind === 'polygon' && + Array.isArray(op.points) && + op.points.length >= 3 && + op.points.length <= 4096 + ) + d.selection = { kind: 'polygon', points: op.points.map(point) }; + else throw Error('选区无效'); + break; + case 'fill': + fields(op, ['layerId', 'color', 'opacity']); + l = target(op, true); + color(op.color); + number(op.opacity ?? 1, 0, 1, '不透明度'); + draw(l, (c) => { + c.fillStyle = op.color; + c.globalAlpha = op.opacity ?? 1; + c.fillRect(l.x, l.y, l.canvas.width, l.canvas.height); + }); + break; + case 'stroke': + fields(op, ['layerId', 'points', 'color', 'size', 'opacity', 'erase']); + l = target(op, true); + if (!Array.isArray(op.points) || op.points.length < 1 || op.points.length > 4096) + throw Error('笔划需要 1–4096 个点'); + { + const points = op.points.map(point), + size = number(op.size ?? 16, 1, 1000, '笔刷大小'); + color(op.color ?? '#000000'); + number(op.opacity ?? 1, 0, 1, '不透明度'); + if (op.erase !== undefined && typeof op.erase !== 'boolean') + throw Error('erase 必须是布尔值'); + draw(l, (c) => { + c.strokeStyle = c.fillStyle = op.color ?? '#000000'; + c.lineWidth = size; + c.lineCap = c.lineJoin = 'round'; + c.globalAlpha = op.opacity ?? 1; + c.globalCompositeOperation = op.erase ? 'destination-out' : 'source-over'; + c.beginPath(); + if (points.length === 1) { + c.arc(...points[0], size / 2, 0, Math.PI * 2); + c.fill(); + } else { + c.moveTo(...points[0]); + for (const p of points.slice(1)) c.lineTo(...p); + c.stroke(); + } + }); + } + break; + case 'shape': + fields(op, ['layerId', 'kind', 'x', 'y', 'width', 'height', 'color', 'fill', 'size']); + l = target(op, true); + { + const x = number(op.x, -32000, 32000, 'x'), + y = number(op.y, -32000, 32000, 'y'), + w = number(op.width, 1, 32000, '宽'), + h = number(op.height, 1, 32000, '高'); + color(op.color); + number(op.size ?? 2, 1, 1000, '线宽'); + if (!['rect', 'ellipse', 'line'].includes(op.kind)) throw Error('形状无效'); + if (op.fill !== undefined && typeof op.fill !== 'boolean') + throw Error('fill 必须是布尔值'); + draw(l, (c) => { + c.fillStyle = c.strokeStyle = op.color; + c.lineWidth = op.size ?? 2; + c.beginPath(); + if (op.kind === 'rect') c.rect(x, y, w, h); + else if (op.kind === 'ellipse') + c.ellipse(x + w / 2, y + h / 2, w / 2, h / 2, 0, 0, Math.PI * 2); + else { + c.moveTo(x, y); + c.lineTo(x + w, y + h); + } + if (op.fill !== false && op.kind !== 'line') c.fill(); + else c.stroke(); + }); + } + break; + case 'text': + fields(op, ['value', 'x', 'y', 'size', 'color', 'font', 'name']); + text(op.value, '文字', 2000); + number(op.x, -32000, 32000, 'x'); + number(op.y, -32000, 32000, 'y'); + number(op.size ?? 48, 1, 1000, '字号'); + color(op.color ?? '#000000'); + if (!['sans-serif', 'serif', 'monospace'].includes(op.font ?? 'sans-serif')) + throw Error('字体无效'); + l = add(layer(d.width, d.height, text(op.name || op.value.slice(0, 40), '图层名'))); + draw(l, (c) => { + c.font = `${op.size ?? 48}px ${op.font ?? 'sans-serif'}`; + c.fillStyle = op.color ?? '#000000'; + op.value + .split('\n') + .forEach((line, i) => c.fillText(line, op.x, op.y + i * (op.size ?? 48) * 1.3)); + }); + l.text = { + value: op.value, + x: op.x, + y: op.y, + size: op.size ?? 48, + color: op.color ?? '#000000', + font: op.font ?? 'sans-serif', + }; + break; + case 'image_result': + fields(op, ['requestId', 'name', 'x', 'y']); + if (typeof op.requestId !== 'string' || !/^[a-f0-9-]{36}$/.test(op.requestId)) + throw Error('图片任务编号无效'); + { + const img = await imageFrom('/api/agent/requests/' + op.requestId + '/result'); + l = add(layer(img.width, img.height, text(op.name || 'Agent 图片', '图层名'))); + l.canvas.getContext('2d').drawImage(img, 0, 0); + l.x = number(op.x ?? 0, -32000, 32000, 'x'); + l.y = number(op.y ?? 0, -32000, 32000, 'y'); + } + break; + case 'transform_layer': + fields(op, ['layerId', 'scale', 'angle', 'flipX', 'flipY']); + l = target(op, true); + { + const scale = number(op.scale ?? 1, 0.01, 10, '缩放'), + angle = (number(op.angle ?? 0, -360, 360, '角度') * Math.PI) / 180; + for (const key of ['flipX', 'flipY']) + if (op[key] !== undefined && typeof op[key] !== 'boolean') + throw Error('翻转参数必须为布尔值'); + const w = l.canvas.width, + h = l.canvas.height, + nw = Math.max( + 1, + Math.ceil((Math.abs(w * Math.cos(angle)) + Math.abs(h * Math.sin(angle))) * scale), + ), + nh = Math.max( + 1, + Math.ceil((Math.abs(w * Math.sin(angle)) + Math.abs(h * Math.cos(angle))) * scale), + ); + const transform = (source) => { + const result = canvas(nw, nh), + c = result.getContext('2d'); + c.translate(nw / 2, nh / 2); + c.rotate(angle); + c.scale(scale * (op.flipX ? -1 : 1), scale * (op.flipY ? -1 : 1)); + c.drawImage(source, -w / 2, -h / 2); + return result; + }; + l.canvas = transform(l.canvas); + if (l.mask) l.mask = transform(l.mask); + l.x += (w - nw) / 2; + l.y += (h - nh) / 2; + l.text = null; + } + break; + case 'crop': + fields(op, ['x', 'y', 'width', 'height']); + { + const x = integer(op.x, 0, d.width - 1, 'x'), + y = integer(op.y, 0, d.height - 1, 'y'), + w = integer(op.width, 1, d.width - x, '宽'), + h = integer(op.height, 1, d.height - y, '高'); + if (d.layers.some((l) => l.locked)) throw Error('包含锁定图层,不能裁剪'); + d.width = w; + d.height = h; + for (const item of d.layers) { + item.x -= x; + item.y -= y; + } + d.selection = null; + } + break; + case 'filter': + case 'adjustment': + fields( + op, + op.op === 'filter' + ? ['layerId', 'type', 'value'] + : ['type', 'value', 'name', 'clipToBelow'], + ); + { + const spec = (op.op === 'filter' ? [...adjustments, ...filters] : adjustments).find( + (a) => a[0] === op.type, + ); + if (!spec) throw Error('未知滤镜或调整'); + const value = number(op.value ?? spec[2], spec[3], spec[4], '参数'); + if (op.op === 'adjustment') { + if (op.clipToBelow !== undefined && typeof op.clipToBelow !== 'boolean') + throw Error('clipToBelow 必须是布尔值'); + l = add(layer(d.width, d.height, text(op.name || spec[1], '图层名'))); + l.adjustment = normalizeAdjustment({ type: op.type, value }); + l.clipToBelow = !!op.clipToBelow; + } else { + l = target(op, true); + const c = l.canvas, + ctx = c.getContext('2d'), + data = ctx.getImageData(0, 0, c.width, c.height); + const out = await runFilter(data.data, c.width, c.height, op.type, value); + const result = canvas(c.width, c.height); + result.getContext('2d').putImageData(new ImageData(out, c.width, c.height), 0, 0); + draw(l, (ctx) => { + ctx.clearRect(l.x, l.y, c.width, c.height); + ctx.drawImage(result, l.x, l.y); + }); + } + } + break; + case 'styles': + fields(op, ['layerId', 'styles']); + l = target(op); + if (!op.styles || typeof op.styles !== 'object' || Array.isArray(op.styles)) + throw Error('样式无效'); + l.styles = normalizeStyles(op.styles); + break; + case 'mask_selection': + fields(op, ['layerId']); + l = target(op); + if (!d.selection) throw Error('请先建立选区'); + l.mask = canvas(l.canvas.width, l.canvas.height); + { + const c = l.mask.getContext('2d'); + clipSelection(c, d, l); + c.fillStyle = '#ffffff'; + c.fillRect(0, 0, l.mask.width, l.mask.height); + } + break; + case 'remove_mask': + fields(op, ['layerId']); + l = target(op); + l.mask = null; + break; + case 'flatten': + fields(op, ['name']); + if (d.layers.some((l) => l.locked)) throw Error('包含锁定图层,不能拼合'); + { + const image = composite(d); + l = layer(d.width, d.height, text(op.name || '合并图像', '图层名')); + l.canvas = image; + d.layers = [l]; + d.activeId = l.id; + } + break; + } + if (op.as) { + if (!l || op.op === 'delete_layer') throw Error('该操作不能命名图层引用'); + refs.set(op.as, l.id); + } + results.push({ index, op: op.op, ...(l ? { layerId: l.id } : {}) }); + } + return { document: d, results, description: describeDocument(d) }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/editor-read.js b/plugins/webguhui/minimax-photo/miniapp/client/editor-read.js new file mode 100644 index 00000000..99c587e5 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/editor-read.js @@ -0,0 +1,66 @@ +import { canvas, composite } from './model.js'; +export function readEditorImage(d, options = {}) { + if ( + !options || + typeof options !== 'object' || + Array.isArray(options) || + Object.keys(options).some((k) => !['layerId', 'region', 'maxEdge', 'points'].includes(k)) + ) + throw Error('读图参数无效'); + let layers = d.layers; + if (options.layerId !== undefined) { + const l = layers.find((l) => l.id === options.layerId); + if (!l || l.adjustment) throw Error('请选择普通图层,调整层请读取合并图像'); + layers = [l]; + } + const full = composite({ ...d, layers }); + let region = options.region || { x: 0, y: 0, width: d.width, height: d.height }; + if ( + Object.keys(region).some((k) => !['x', 'y', 'width', 'height'].includes(k)) || + !['x', 'y', 'width', 'height'].every((k) => Number.isInteger(region[k])) || + region.x < 0 || + region.y < 0 || + region.width < 1 || + region.height < 1 || + region.x + region.width > d.width || + region.y + region.height > d.height + ) + throw Error('读取区域必须在画布范围内'); + const maxEdge = options.maxEdge ?? 1280; + if (!Number.isInteger(maxEdge) || maxEdge < 64 || maxEdge > 4096) + throw Error('maxEdge 范围为 64–4096'); + const scale = Math.min(1, maxEdge / Math.max(region.width, region.height)); + const preview = canvas( + Math.max(1, Math.round(region.width * scale)), + Math.max(1, Math.round(region.height * scale)), + ); + preview + .getContext('2d') + .drawImage( + full, + region.x, + region.y, + region.width, + region.height, + 0, + 0, + preview.width, + preview.height, + ); + const points = options.points ?? []; + if (!Array.isArray(points) || points.length > 256) throw Error('最多取样 256 个像素'); + const pixels = points.map((p) => { + if ( + !Array.isArray(p) || + p.length !== 2 || + !p.every(Number.isInteger) || + p[0] < 0 || + p[1] < 0 || + p[0] >= d.width || + p[1] >= d.height + ) + throw Error('取样点必须在画布范围内'); + return { point: p, rgba: [...full.getContext('2d').getImageData(...p, 1, 1).data] }; + }); + return { preview, full, scale, region, pixels }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/files.js b/plugins/webguhui/minimax-photo/miniapp/client/files.js new file mode 100644 index 00000000..4117b889 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/files.js @@ -0,0 +1,174 @@ +import { readTIFF } from './tiff-reader.js'; +import { writeTIFF } from './tiff.js'; +import { + canvas, + layer, + documentModel, + composite, + serialize, + deserialize, + imageFrom, + download, +} from './model.js'; +import { readPSD, writePSD, exportPDF } from './codecs.js'; +export function createFileActions(state, ui) { + const { requireDoc, addDoc, setDoc, refresh, status, button, modal, note } = ui; + const dialog = document.querySelector('#dialog'); + async function importFiles(files) { + for (const file of files) { + if (file.size > 128 * 1024 * 1024) throw Error('单个文件不能超过 128 MB'); + if (file.name.endsWith('.json')) { + addDoc(await deserialize(JSON.parse(await file.text()))); + continue; + } + if (/\.psd$/i.test(file.name)) { + addDoc(readPSD(await file.arrayBuffer(), file.name.replace(/\.psd$/i, ''))); + status('PSD 已打开;当前导入仅保留普通像素图层'); + continue; + } + if (/\.tiff?$/i.test(file.name) || file.type === 'image/tiff') { + const image = readTIFF(await file.arrayBuffer()); + const d = documentModel(image.width, image.height, file.name.replace(/\.[^.]+$/, '')); + d.layers[0].canvas + .getContext('2d') + .putImageData(new ImageData(image.data, image.width, image.height), 0, 0); + addDoc(d); + continue; + } + const url = URL.createObjectURL(file); + try { + const img = await imageFrom(url); + const d = documentModel(img.width, img.height, file.name.replace(/\.[^.]+$/, '')); + const ctx = d.layers[0].canvas.getContext('2d'); + ctx.clearRect(0, 0, d.width, d.height); + ctx.drawImage(img, 0, 0); + addDoc(d); + } finally { + URL.revokeObjectURL(url); + } + } + status('已打开 ' + files.length + ' 个文件'); + } + async function save() { + requireDoc(); + const d = state.doc; + state.busy = true; + status('正在保存工程…'); + try { + const p = await serialize(d); + const res = await fetch('/api/projects/' + d.id, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(p), + }), + r = await res.json(); + if (!res.ok) throw Error(r.error); + d.revision = r.revision; + d.dirty = false; + refresh(); + status('已保存到本机 · 保留全部图层'); + } finally { + state.busy = false; + } + } + async function exportProject() { + requireDoc(); + const p = await serialize(state.doc); + download( + new Blob([JSON.stringify(p)], { type: 'application/json' }), + state.doc.name + '.retouch.json', + ); + status('工程文件已导出'); + } + async function projects() { + const res = await fetch('/api/projects'); + if (!res.ok) throw Error('无法读取本地工程'); + const { projects } = await res.json(); + const rows = projects.map((p) => { + const row = document.createElement('div'); + row.className = 'project-row'; + const text = document.createElement('span'); + text.textContent = `${p.name} · ${p.width} × ${p.height}`; + row.append( + text, + button('打开', async () => { + const res = await fetch('/api/projects/' + p.id); + if (!res.ok) throw Error('无法打开工程'); + const d = await deserialize(await res.json()); + const existing = state.docs.find((x) => x.id === d.id); + if (existing) { + if (existing.dirty) throw Error('该工程已打开且有未保存修改,请先保存或导出'); + setDoc(existing); + } else addDoc(d); + dialog.close(); + status('已恢复工程和图层'); + }), + ); + return row; + }); + modal( + '本地工程', + rows.length ? rows : [note('还没有保存的工程。打开图片后点击“保存工程”。')], + () => {}, + '关闭', + ); + } + async function exportImage(type = 'png') { + requireDoc(); + const d = state.doc; + if (type === 'psd') { + const hasAdjustments = d.layers.some((l) => l.adjustment); + let exported = d; + if (hasAdjustments) { + const flattened = layer(d.width, d.height, '合并图像'); + flattened.canvas = composite(d); + exported = { ...d, layers: [flattened] }; + } + download(writePSD(exported), d.name + '.psd'); + status( + hasAdjustments + ? 'PSD 已导出为合并图像;请另存工程以保留调整参数和混合模式' + : 'PSD 已导出:文字、蒙版和样式会转换为像素图层', + ); + return; + } + const c = composite(d); + if (type === 'tiff') { + download( + writeTIFF(c.getContext('2d').getImageData(0, 0, c.width, c.height)), + d.name + '.tiff', + ); + status('已导出 TIFF:合并图像,保留透明度;图层请另存工程'); + return; + } + if (type === 'pdf') { + const white = canvas(c.width, c.height), + ctx = white.getContext('2d'); + ctx.fillStyle = '#fff'; + ctx.fillRect(0, 0, c.width, c.height); + ctx.drawImage(c, 0, 0); + download(await exportPDF(white), d.name + '.pdf'); + return; + } + if (type === 'svg') { + const body = ``; + download(new Blob([body], { type: 'image/svg+xml' }), d.name + '.svg'); + status('已导出 SVG(内嵌合并位图)'); + return; + } + let target = c; + if (type === 'jpeg') { + target = canvas(c.width, c.height); + const ctx = target.getContext('2d'); + ctx.fillStyle = '#fff'; + ctx.fillRect(0, 0, c.width, c.height); + ctx.drawImage(c, 0, 0); + } + const blob = await new Promise((ok) => target.toBlob(ok, 'image/' + type, 0.94)); + if (!blob) throw Error('图片导出失败'); + download(blob, d.name + '.' + (type === 'jpeg' ? 'jpg' : type)); + status('已导出 ' + type.toUpperCase()); + } + + return { importFiles, save, exportProject, projects, exportImage }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/filter-dialog.js b/plugins/webguhui/minimax-photo/miniapp/client/filter-dialog.js new file mode 100644 index 00000000..53743457 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/filter-dialog.js @@ -0,0 +1,86 @@ +import { canvas } from './model.js'; +import { field, note } from './dialogs.js'; + +export function showFilterDialog(source, item, { modal, runFilter, applyFilter, description }) { + const [type, label, initial, min, max] = item; + const [row, input] = field(label, initial, 'range', { min, max, step: 1 }); + row.hidden = min === 0 && max === 1; + const output = document.createElement('output'); + output.textContent = initial; + row.append(output); + const ratio = Math.min(1, 400 / source.width, 240 / source.height); + const preview = canvas( + Math.max(1, Math.round(source.width * ratio)), + Math.max(1, Math.round(source.height * ratio)), + ); + preview.setAttribute('aria-label', `${label}效果预览`); + preview.style.maxWidth = '100%'; + preview.style.margin = 'auto'; + preview.style.background = 'var(--mcode-bg-secondary)'; + const ctx = preview.getContext('2d'); + ctx.drawImage(source, 0, 0, preview.width, preview.height); + const original = ctx.getImageData(0, 0, preview.width, preview.height); + const feedback = document.createElement('p'); + feedback.setAttribute('role', 'status'); + const compareLabel = document.createElement('label'); + const compare = document.createElement('input'); + compare.type = 'checkbox'; + compareLabel.append(compare, '显示原图'); + let requested = 0, + running = false, + result = original; + function paint() { + ctx.putImageData(compare.checked ? original : result, 0, 0); + } + async function update() { + requested++; + if (running) return; + running = true; + try { + while (preview.isConnected) { + const version = requested; + feedback.textContent = '正在更新预览…'; + let value = Number(input.value); + // Blur radii are measured in source pixels; account for the smaller preview. + if (['blur', 'gaussian', 'halftone', 'diffuse', 'oilPaint'].includes(type)) value *= ratio; + const pixels = await runFilter( + original.data.slice(), + original.width, + original.height, + type, + value, + ); + if (!preview.isConnected) break; + if (version !== requested) continue; + result = new ImageData(pixels, original.width, original.height); + paint(); + feedback.textContent = '预览已更新'; + break; + } + } catch (error) { + if (preview.isConnected) feedback.textContent = `预览失败:${error.message}`; + } finally { + running = false; + } + } + input.oninput = () => { + output.textContent = input.value; + void update(); + }; + compare.onchange = paint; + modal( + label, + [ + row, + compareLabel, + preview, + feedback, + note( + description || '缩略图仅预览当前图层,细节以应用结果为准。应用时仅修改选区内像素,可撤销。', + ), + ], + () => applyFilter(type, Number(input.value), label), + '应用', + ); + void update(); +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/filter-worker.js b/plugins/webguhui/minimax-photo/miniapp/client/filter-worker.js new file mode 100644 index 00000000..4740548c --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/filter-worker.js @@ -0,0 +1,9 @@ +import { filterPixels } from './filters.js'; +self.onmessage = ({ data: { id, buffer, width, height, type, value } }) => { + try { + const out = filterPixels(new Uint8ClampedArray(buffer), width, height, type, value); + self.postMessage({ id, buffer: out.buffer }, [out.buffer]); + } catch (e) { + self.postMessage({ id, error: e.message }); + } +}; diff --git a/plugins/webguhui/minimax-photo/miniapp/client/filters.js b/plugins/webguhui/minimax-photo/miniapp/client/filters.js new file mode 100644 index 00000000..1b7979a5 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/filters.js @@ -0,0 +1,283 @@ +import { oilPaint } from './oil-paint.js'; +import { artisticFilter } from './artistic-filters.js'; +import { applyCurves } from './tone.js'; +import { gaussianBlur } from './gaussian.js'; +const clamp = (v) => Math.max(0, Math.min(255, v)); +function hsl(r, g, b) { + r /= 255; + g /= 255; + b /= 255; + const max = Math.max(r, g, b), + min = Math.min(r, g, b), + d = max - min, + l = (max + min) / 2; + let h = 0, + s = 0; + if (d) { + s = d / (1 - Math.abs(2 * l - 1)); + h = max === r ? ((g - b) / d) % 6 : max === g ? (b - r) / d + 2 : (r - g) / d + 4; + h /= 6; + } + return [(h + 1) % 1, s, l]; +} +function rgb(h, s, l) { + const c = (1 - Math.abs(2 * l - 1)) * s, + x = c * (1 - Math.abs(((h * 6) % 2) - 1)), + m = l - c / 2; + const a = + h < 1 / 6 + ? [c, x, 0] + : h < 2 / 6 + ? [x, c, 0] + : h < 3 / 6 + ? [0, c, x] + : h < 4 / 6 + ? [0, x, c] + : h < 5 / 6 + ? [x, 0, c] + : [c, 0, x]; + return a.map((v) => (v + m) * 255); +} +export function filterPixels(data, w, h, type, value = 20) { + if (['halftone', 'diffuse', 'traceContour', 'glowingEdges'].includes(type)) + return artisticFilter(data, w, h, type, value); + if (type === 'oilPaint') return oilPaint(data, w, h, value); + if (type === 'curves') return applyCurves(data, value?.curves); + if (type === 'gaussian') return gaussianBlur(data, w, h, Number(value)); + const src = new Uint8ClampedArray(data), + out = new Uint8ClampedArray(src); + const amount = Number(value); + if (['blur', 'sharpen', 'emboss', 'edges', 'unsharp'].includes(type)) { + const radius = type === 'blur' ? Math.max(1, Math.min(30, Math.round(amount))) : 1; + if (type === 'blur' || type === 'unsharp') { + // Sliding window, O(width * height), independent of blur radius. + const tmp = new Float32Array(src.length), + r = type === 'unsharp' ? 2 : radius, + span = 2 * r + 1; + for (let y = 0; y < h; y++) + for (let c = 0; c < 4; c++) { + let sum = 0; + for (let k = -r; k <= r; k++) + sum += src[(y * w + Math.max(0, Math.min(w - 1, k))) * 4 + c]; + for (let x = 0; x < w; x++) { + tmp[(y * w + x) * 4 + c] = sum / span; + sum += + src[(y * w + Math.min(w - 1, x + r + 1)) * 4 + c] - + src[(y * w + Math.max(0, x - r)) * 4 + c]; + } + } + for (let x = 0; x < w; x++) + for (let c = 0; c < 4; c++) { + let sum = 0; + for (let k = -r; k <= r; k++) + sum += tmp[(Math.max(0, Math.min(h - 1, k)) * w + x) * 4 + c]; + for (let y = 0; y < h; y++) { + const i = (y * w + x) * 4 + c; + out[i] = + type === 'unsharp' && c < 3 + ? clamp(src[i] + ((src[i] - sum / span) * amount) / 20) + : type === 'unsharp' + ? src[i] + : sum / span; + sum += + tmp[(Math.min(h - 1, y + r + 1) * w + x) * 4 + c] - + tmp[(Math.max(0, y - r) * w + x) * 4 + c]; + } + } + return out; + } + const kernel = + type === 'sharpen' + ? [0, -1, 0, -1, 5, -1, 0, -1, 0] + : type === 'emboss' + ? [-2, -1, 0, -1, 1, 1, 0, 1, 2] + : [-1, -1, -1, -1, 8, -1, -1, -1, -1]; + for (let y = 0; y < h; y++) + for (let x = 0; x < w; x++) + for (let c = 0; c < 3; c++) { + let sum = 0; + for (let dy = -1; dy <= 1; dy++) + for (let dx = -1; dx <= 1; dx++) + sum += + src[ + (Math.max(0, Math.min(h - 1, y + dy)) * w + + Math.max(0, Math.min(w - 1, x + dx))) * + 4 + + c + ] * kernel[(dy + 1) * 3 + dx + 1]; + out[(y * w + x) * 4 + c] = clamp(sum + (type === 'emboss' ? 128 : 0)); + } + return out; + } + if (type === 'pixelate') { + const size = Math.max(2, Math.round(amount)); + for (let y = 0; y < h; y += size) + for (let x = 0; x < w; x += size) { + const sums = [0, 0, 0, 0]; + let n = 0; + for (let yy = y; yy < Math.min(y + size, h); yy++) + for (let xx = x; xx < Math.min(x + size, w); xx++) { + for (let c = 0; c < 4; c++) sums[c] += src[(yy * w + xx) * 4 + c]; + n++; + } + for (let yy = y; yy < Math.min(y + size, h); yy++) + for (let xx = x; xx < Math.min(x + size, w); xx++) + for (let c = 0; c < 4; c++) out[(yy * w + xx) * 4 + c] = sums[c] / n; + } + return out; + } + if (['twirl', 'pinch', 'spherize', 'ripple', 'wave', 'polar', 'shear'].includes(type)) { + const cx = w / 2, + cy = h / 2, + radius = Math.min(w, h) / 2; + for (let y = 0; y < h; y++) + for (let x = 0; x < w; x++) { + let sx = x, + sy = y; + const dx = x - cx, + dy = y - cy, + r = Math.hypot(dx, dy), + a = Math.atan2(dy, dx); + if (type === 'twirl' && r < radius) { + const angle = a + ((1 - r / radius) * amount) / 30; + sx = cx + Math.cos(angle) * r; + sy = cy + Math.sin(angle) * r; + } + if ((type === 'pinch' || type === 'spherize') && r < radius && r > 0) { + const q = + type === 'pinch' + ? Math.pow(r / radius, 1 + amount / 100) + : Math.sin(((r / radius) * Math.PI) / 2); + sx = cx + (dx * q * radius) / r; + sy = cy + (dy * q * radius) / r; + } + if (type === 'wave') sx = x + Math.sin(y / 20) * amount; + if (type === 'ripple' && r > 0) { + sx = x + ((dx / r) * Math.sin(r / 10) * amount) / 5; + sy = y + ((dy / r) * Math.sin(r / 10) * amount) / 5; + } + if (type === 'shear') sx = x + (y / h - 0.5) * amount; + if (type === 'polar') { + sx = ((a + Math.PI) / (2 * Math.PI)) * w; + sy = (r / radius) * h; + } + const si = + (Math.max(0, Math.min(h - 1, Math.round(sy))) * w + + Math.max(0, Math.min(w - 1, Math.round(sx)))) * + 4; + out.set(src.subarray(si, si + 4), (y * w + x) * 4); + } + return out; + } + for (let i = 0; i < src.length; i += 4) { + let r = src[i], + g = src[i + 1], + b = src[i + 2], + lum = 0.2126 * r + 0.7152 * g + 0.0722 * b; + switch (type) { + case 'brightness': + r += amount; + g += amount; + b += amount; + break; + case 'contrast': { + const f = (259 * (amount + 255)) / (255 * (259 - amount)); + r = f * (r - 128) + 128; + g = f * (g - 128) + 128; + b = f * (b - 128) + 128; + break; + } + case 'exposure': { + const f = 2 ** (amount / 20); + r *= f; + g *= f; + b *= f; + break; + } + case 'grayscale': + r = g = b = lum; + break; + case 'invert': + r = 255 - r; + g = 255 - g; + b = 255 - b; + break; + case 'threshold': + r = g = b = lum >= amount ? 255 : 0; + break; + case 'posterize': { + const n = Math.max(2, Math.round(amount)); + r = (Math.round((r / 255) * (n - 1)) / (n - 1)) * 255; + g = (Math.round((g / 255) * (n - 1)) / (n - 1)) * 255; + b = (Math.round((b / 255) * (n - 1)) / (n - 1)) * 255; + break; + } + case 'saturation': + case 'vibrance': { + const factor = + 1 + + (amount / 100) * + (type === 'vibrance' ? 1 - (Math.max(r, g, b) - Math.min(r, g, b)) / 255 : 1); + r = lum + (r - lum) * factor; + g = lum + (g - lum) * factor; + b = lum + (b - lum) * factor; + break; + } + case 'hue': { + let [hh, s, l] = hsl(r, g, b); + [r, g, b] = rgb((hh + amount / 360 + 1) % 1, s, l); + break; + } + case 'warmth': + r += amount; + b -= amount; + break; + case 'sepia': + r = 0.393 * src[i] + 0.769 * src[i + 1] + 0.189 * src[i + 2]; + g = 0.349 * src[i] + 0.686 * src[i + 1] + 0.168 * src[i + 2]; + b = 0.272 * src[i] + 0.534 * src[i + 1] + 0.131 * src[i + 2]; + break; + case 'noise': { + const n = (Math.random() - 0.5) * amount; + r += n; + g += n; + b += n; + break; + } + case 'solarize': + r = r > 128 ? 255 - r : r; + g = g > 128 ? 255 - g : g; + b = b > 128 ? 255 - b : b; + break; + case 'levels': { + const black = Math.max(0, Math.min(100, amount)), + f = 255 / (255 - 2 * black); + r = (r - black) * f; + g = (g - black) * f; + b = (b - black) * f; + break; + } + case 'gamma': { + const gamma = Math.max(0.1, amount / 100); + r = 255 * (r / 255) ** (1 / gamma); + g = 255 * (g / 255) ** (1 / gamma); + b = 255 * (b / 255) ** (1 / gamma); + break; + } + case 'redEye': + if (r > g * 1.4 && r > b * 1.4) r = (g + b) / 2; + break; + case 'enhance': { + const f = 1.12; + r = (r - 128) * f + 133; + g = (g - 128) * f + 133; + b = (b - 128) * f + 133; + break; + } + } + out[i] = clamp(r); + out[i + 1] = clamp(g); + out[i + 2] = clamp(b); + } + return out; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/flood-region.js b/plugins/webguhui/minimax-photo/miniapp/client/flood-region.js new file mode 100644 index 00000000..9f987e32 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/flood-region.js @@ -0,0 +1,50 @@ +// Four-neighbor color selection, shared by the bucket, wand and magic eraser. +// One visit per pixel; no per-pixel array allocation. +export function floodRegion(data, width, height, x, y, tolerance) { + const mask = new Uint8Array(width * height); + if (x < 0 || y < 0 || x >= width || y >= height) return { mask, bounds: null }; + const seed = y * width + x, + target = seed * 4; + const r = data[target], + g = data[target + 1], + b = data[target + 2], + a = data[target + 3]; + const queue = new Int32Array(width * height); + let head = 0, + tail = 1, + minX = x, + maxX = x, + minY = y, + maxY = y; + queue[0] = seed; + mask[seed] = 1; + const visit = (index) => { + if (!mask[index]) { + mask[index] = 1; + queue[tail++] = index; + } + }; + while (head < tail) { + const index = queue[head++], + offset = index * 4; + if ( + Math.abs(data[offset] - r) > tolerance || + Math.abs(data[offset + 1] - g) > tolerance || + Math.abs(data[offset + 2] - b) > tolerance || + Math.abs(data[offset + 3] - a) > tolerance + ) + continue; + mask[index] = 2; + const xx = index % width, + yy = Math.floor(index / width); + minX = Math.min(minX, xx); + maxX = Math.max(maxX, xx); + minY = Math.min(minY, yy); + maxY = Math.max(maxY, yy); + if (xx > 0) visit(index - 1); + if (xx + 1 < width) visit(index + 1); + if (yy > 0) visit(index - width); + if (yy + 1 < height) visit(index + width); + } + return { mask, bounds: { minX, minY, maxX, maxY } }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/gaussian.js b/plugins/webguhui/minimax-photo/miniapp/client/gaussian.js new file mode 100644 index 00000000..d11b8747 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/gaussian.js @@ -0,0 +1,40 @@ +// Separable Gaussian convolution in premultiplied RGBA avoids colored fringes at transparent edges. +export function gaussianBlur(data, width, height, sigma) { + if (!Number.isFinite(sigma) || sigma < 0 || sigma > 30) + throw Error('高斯模糊半径须在 0–30 范围内'); + if (sigma === 0) return new Uint8ClampedArray(data); + const radius = Math.ceil(3 * sigma), + weights = new Float64Array(radius * 2 + 1); + let total = 0; + for (let i = -radius; i <= radius; i++) { + weights[i + radius] = Math.exp(-(i * i) / (2 * sigma * sigma)); + total += weights[i + radius]; + } + for (let i = 0; i < weights.length; i++) weights[i] /= total; + const horizontal = new Float32Array(data.length), + out = new Uint8ClampedArray(data.length); + for (let y = 0; y < height; y++) + for (let x = 0; x < width; x++) { + const offset = (y * width + x) * 4; + for (let k = -radius; k <= radius; k++) { + const source = (y * width + Math.max(0, Math.min(width - 1, x + k))) * 4, + weight = weights[k + radius], + alpha = data[source + 3] / 255; + for (let c = 0; c < 3; c++) horizontal[offset + c] += data[source + c] * alpha * weight; + horizontal[offset + 3] += alpha * weight; + } + } + for (let y = 0; y < height; y++) + for (let x = 0; x < width; x++) { + const offset = (y * width + x) * 4, + sum = [0, 0, 0, 0]; + for (let k = -radius; k <= radius; k++) { + const source = (Math.max(0, Math.min(height - 1, y + k)) * width + x) * 4, + weight = weights[k + radius]; + for (let c = 0; c < 4; c++) sum[c] += horizontal[source + c] * weight; + } + out[offset + 3] = sum[3] * 255; + if (sum[3] > 1e-8) for (let c = 0; c < 3; c++) out[offset + c] = sum[c] / sum[3]; + } + return out; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/index.html b/plugins/webguhui/minimax-photo/miniapp/client/index.html new file mode 100644 index 00000000..6b16d9ef --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/index.html @@ -0,0 +1,102 @@ + + + + + + MiniMax Photo + + + + + +
+ MiniMax Photo Mini App + + +
+
+ 移动拖动移动当前图层 +
+
+ +
+
+
+
+ +
+
+

开始修图

+

打开图片,使用图层和调色工具完成编辑。

+ +

也可以把图片拖到这里

+
+
+
+ +
+
+ 就绪 · 所有修图在本机完成100% +
+ +
+
+

+ +
+
+
+ +
+
+
+ + + diff --git a/plugins/webguhui/minimax-photo/miniapp/client/layer-styles.js b/plugins/webguhui/minimax-photo/miniapp/client/layer-styles.js new file mode 100644 index 00000000..7a2e5b87 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/layer-styles.js @@ -0,0 +1,222 @@ +import { strokePixels, bevelPixels } from './style-pixels.js'; +// Styles are immutable layer metadata. Source pixels are never overwritten. +export const styleDefaults = { + shadow: { enabled: false, color: '#000000', opacity: 0.6, blur: 8, x: 8, y: 8 }, + glow: { enabled: false, color: '#ffffff', opacity: 0.7, blur: 12 }, + color: { enabled: false, color: '#227fa8', opacity: 1 }, + gradient: { enabled: false, color: '#227fa8', endColor: '#e8b36d', opacity: 1, angle: 90 }, + innerShadow: { enabled: false, color: '#000000', opacity: 0.6, blur: 6, x: 5, y: 5 }, + innerGlow: { enabled: false, color: '#ffffff', opacity: 0.8, blur: 8 }, + stroke: { enabled: false, color: '#ffffff', opacity: 1, size: 4, position: 'outside' }, + bevel: { + enabled: false, + color: '#ffffff', + endColor: '#000000', + opacity: 0.9, + size: 6, + depth: 2, + angle: 135, + elevation: 45, + }, + satin: { enabled: false, color: '#000000', opacity: 0.5, blur: 8, distance: 12, angle: 45 }, + pattern: { + enabled: false, + color: '#227fa8', + endColor: '#e8b36d', + opacity: 0.8, + size: 16, + pattern: 'checker', + }, +}; +export const styleNames = { + shadow: '投影', + glow: '外发光', + color: '颜色叠加', + gradient: '渐变叠加', + innerShadow: '内阴影', + innerGlow: '内发光', + stroke: '描边', + bevel: '斜面浮雕', + satin: '缎面', + pattern: '图案叠加', +}; +export function normalizeStyles(value) { + const out = structuredClone(styleDefaults); + for (const [key, defaults] of Object.entries(out)) { + const input = value?.[key]; + if (!input || typeof input !== 'object') continue; + defaults.enabled = input.enabled === true; + for (const prop of ['color', 'endColor']) + if (prop in defaults && /^#[a-f\d]{6}$/i.test(input[prop])) defaults[prop] = input[prop]; + for (const [prop, low, high] of [ + ['opacity', 0, 1], + ['blur', 0, 60], + ['x', -100, 100], + ['y', -100, 100], + ['angle', -180, 180], + ['size', 0.1, 60], + ['depth', 0.1, 10], + ['elevation', 1, 89], + ['distance', 0, 100], + ]) + if (prop in defaults && Number.isFinite(input[prop])) + defaults[prop] = Math.max(low, Math.min(high, input[prop])); + if ('position' in defaults && ['inside', 'outside', 'center'].includes(input.position)) + defaults.position = input.position; + if ('pattern' in defaults && ['checker', 'dots', 'stripes'].includes(input.pattern)) + defaults.pattern = input.pattern; + } + return out; +} + +export function stylePadding(styles) { + return Math.ceil( + Math.max( + styles.shadow.enabled + ? 3 * styles.shadow.blur + Math.max(Math.abs(styles.shadow.x), Math.abs(styles.shadow.y)) + : 0, + styles.glow.enabled ? 3 * styles.glow.blur : 0, + styles.stroke.enabled && styles.stroke.position !== 'inside' ? styles.stroke.size : 0, + styles.bevel.enabled || styles.stroke.enabled ? 1 : 0, + ...['innerShadow', 'innerGlow'].map((key) => + styles[key].enabled + ? 3 * styles[key].blur + + Math.max(Math.abs(styles[key].x || 0), Math.abs(styles[key].y || 0)) + + 2 + : 0, + ), + ), + ); +} +export function renderStyles(source, value, makeCanvas) { + if (!value || !Object.values(value).some((s) => s?.enabled)) return { image: source, offset: 0 }; + const styles = normalizeStyles(value); + const pad = stylePadding(styles); + const out = makeCanvas(source.width + 2 * pad, source.height + 2 * pad); + const ctx = out.getContext('2d'); + const tint = makeCanvas(source.width, source.height), + t = tint.getContext('2d'); + function silhouette(color) { + t.globalCompositeOperation = 'source-over'; + t.clearRect(0, 0, tint.width, tint.height); + t.drawImage(source, 0, 0); + t.globalCompositeOperation = 'source-in'; + t.fillStyle = color; + t.fillRect(0, 0, tint.width, tint.height); + } + for (const key of ['shadow', 'glow']) { + const effect = styles[key]; + if (!effect.enabled) continue; + silhouette(effect.color); + ctx.save(); + ctx.globalAlpha = effect.opacity; + ctx.filter = `blur(${effect.blur}px)`; + ctx.drawImage(tint, pad + (effect.x || 0), pad + (effect.y || 0)); + ctx.restore(); + } + // Compose overlays on the source first so they do not recolor the shadow/glow. + t.globalCompositeOperation = 'source-over'; + t.clearRect(0, 0, tint.width, tint.height); + t.drawImage(source, 0, 0); + t.globalCompositeOperation = 'source-atop'; + if (styles.color.enabled) { + t.globalAlpha = styles.color.opacity; + t.fillStyle = styles.color.color; + t.fillRect(0, 0, tint.width, tint.height); + } + if (styles.gradient.enabled) { + const effect = styles.gradient, + angle = (effect.angle * Math.PI) / 180; + const dx = Math.cos(angle), + dy = Math.sin(angle); + const radius = (Math.abs(dx) * tint.width + Math.abs(dy) * tint.height) / 2; + const gradient = t.createLinearGradient( + tint.width / 2 - dx * radius, + tint.height / 2 - dy * radius, + tint.width / 2 + dx * radius, + tint.height / 2 + dy * radius, + ); + gradient.addColorStop(0, effect.color); + gradient.addColorStop(1, effect.endColor); + t.globalAlpha = effect.opacity; + t.fillStyle = gradient; + t.fillRect(0, 0, tint.width, tint.height); + } + if (styles.pattern.enabled) { + const effect = styles.pattern, + size = Math.max(2, Math.round(effect.size)); + const tile = makeCanvas(size * 2, size * 2), + tileCtx = tile.getContext('2d'); + tileCtx.fillStyle = effect.endColor; + tileCtx.fillRect(0, 0, tile.width, tile.height); + tileCtx.fillStyle = effect.color; + if (effect.pattern === 'dots') { + tileCtx.beginPath(); + tileCtx.arc(size, size, size / 2, 0, Math.PI * 2); + tileCtx.fill(); + } else if (effect.pattern === 'stripes') tileCtx.fillRect(0, 0, size, tile.height); + else { + tileCtx.fillRect(0, 0, size, size); + tileCtx.fillRect(size, size, size, size); + } + t.globalAlpha = effect.opacity; + t.fillStyle = t.createPattern(tile, 'repeat'); + t.fillRect(0, 0, tint.width, tint.height); + } + // Inner effects use the inverse alpha silhouette; source-atop clips them to the layer. + for (const key of ['innerShadow', 'innerGlow']) { + const effect = styles[key]; + if (!effect.enabled) continue; + const margin = Math.ceil( + 3 * effect.blur + Math.max(Math.abs(effect.x || 0), Math.abs(effect.y || 0)) + 2, + ); + const inverse = makeCanvas(source.width + margin * 2, source.height + margin * 2), + inverseCtx = inverse.getContext('2d'); + inverseCtx.fillStyle = effect.color; + inverseCtx.fillRect(0, 0, inverse.width, inverse.height); + inverseCtx.globalCompositeOperation = 'destination-out'; + inverseCtx.drawImage(source, margin, margin); + t.save(); + t.globalAlpha = effect.opacity; + t.filter = `blur(${effect.blur}px)`; + t.drawImage(inverse, -margin + (effect.x || 0), -margin + (effect.y || 0)); + t.restore(); + } + if (styles.satin.enabled) { + const effect = styles.satin, + angle = (effect.angle * Math.PI) / 180; + const dx = Math.cos(angle) * effect.distance, + dy = Math.sin(angle) * effect.distance; + const folds = makeCanvas(source.width, source.height), + f = folds.getContext('2d'); + f.filter = `blur(${effect.blur}px)`; + f.drawImage(source, dx, dy); + f.globalCompositeOperation = 'xor'; + f.drawImage(source, -dx, -dy); + f.filter = 'none'; + f.globalCompositeOperation = 'source-in'; + f.fillStyle = effect.color; + f.fillRect(0, 0, folds.width, folds.height); + t.globalAlpha = effect.opacity; + t.drawImage(folds, 0, 0); + } + ctx.drawImage(tint, pad, pad); + if (styles.stroke.enabled || styles.bevel.enabled) { + const silhouette = makeCanvas(out.width, out.height), + s = silhouette.getContext('2d'); + s.drawImage(source, pad, pad); + const rgba = s.getImageData(0, 0, out.width, out.height).data; + const alpha = new Uint8Array(out.width * out.height); + for (let i = 0; i < alpha.length; i++) alpha[i] = rgba[i * 4 + 3]; + for (const [key, render] of [ + ['bevel', bevelPixels], + ['stroke', strokePixels], + ]) { + if (!styles[key].enabled) continue; + const pixels = render(alpha, out.width, out.height, styles[key]); + s.putImageData(new ImageData(pixels, out.width, out.height), 0, 0); + ctx.drawImage(silhouette, 0, 0); + } + } + return { image: out, offset: -pad }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/model.js b/plugins/webguhui/minimax-photo/miniapp/client/model.js new file mode 100644 index 00000000..17805e65 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/model.js @@ -0,0 +1,369 @@ +import { pixelBlendModes, compositePixels } from './blending.js'; +import { normalizeStyles, renderStyles, stylePadding } from './layer-styles.js'; +import { createRenderCache } from './render-cache.js'; +import { normalizeAdjustment, adjustedPixels, compositionGroups } from './adjustment-layers.js'; +export const layerRenderCache = createRenderCache(); +export const invalidateLayer = (l) => layerRenderCache.invalidate(l.canvas); +export const LIMIT_PIXELS = 32e6; +export const blends = [ + 'source-over', + 'multiply', + 'screen', + 'overlay', + 'darken', + 'lighten', + 'color-dodge', + 'color-burn', + 'hard-light', + 'soft-light', + 'difference', + 'exclusion', + 'hue', + 'saturation', + 'color', + 'luminosity', + ...pixelBlendModes, +]; +export const blendNames = [ + '正常', + '正片叠底', + '滤色', + '叠加', + '变暗', + '变亮', + '颜色减淡', + '颜色加深', + '强光', + '柔光', + '差值', + '排除', + '色相', + '饱和度', + '颜色', + '明度', + '溶解', + '线性加深', + '线性减淡(添加)', + '减去', + '划分', + '亮光', + '线性光', + '点光', + '实色混合', + '深色', + '浅色', +]; +export function canvas(w, h) { + if (!Number.isInteger(w) || !Number.isInteger(h) || w < 1 || h < 1 || w * h > LIMIT_PIXELS) + throw Error('画布尺寸须为正整数,最多 3200 万像素'); + const c = document.createElement('canvas'); + c.width = w; + c.height = h; + return c; +} +export function cloneCanvas(c) { + const n = canvas(c.width, c.height); + n.getContext('2d').drawImage(c, 0, 0); + return n; +} +export function layer(w, h, name = '图层') { + return { + id: crypto.randomUUID(), + name, + visible: true, + locked: false, + opacity: 1, + blend: 'source-over', + x: 0, + y: 0, + canvas: canvas(w, h), + mask: null, + text: null, + }; +} +export function documentModel(w = 1280, h = 800, name = '未命名') { + const l = layer(w, h, '背景'); + const ctx = l.canvas.getContext('2d'); + ctx.fillStyle = '#ffffff'; + ctx.fillRect(0, 0, w, h); + return { + id: crypto.randomUUID(), + name, + width: w, + height: h, + layers: [l], + activeId: l.id, + revision: 0, + dirty: false, + history: [], + future: [], + selection: null, + paths: [], + historyBytes: 0, + }; +} +export const active = (d) => d.layers.find((l) => l.id === d.activeId) || d.layers.at(-1); +export function snapshot(d) { + return { + width: d.width, + height: d.height, + layers: d.layers.map((l) => ({ ...l })), + activeId: d.activeId, + selection: d.selection, + paths: structuredClone(d.paths), + }; +} +function estimate(entries) { + const seen = new Set(); + let bytes = 0; + for (const entry of entries) + for (const l of entry.state.layers) + for (const c of [l.canvas, l.mask]) + if (c && !seen.has(c)) { + seen.add(c); + bytes += c.width * c.height * 4; + } + return bytes; +} +export function begin(d, label, editIds = []) { + d.history.push({ label, state: snapshot(d) }); + d.future = []; + d.layers = d.layers.map((l) => + editIds.includes(l.id) + ? { ...l, canvas: cloneCanvas(l.canvas), mask: l.mask ? cloneCanvas(l.mask) : null } + : { ...l }, + ); + while (d.history.length > 1 && (d.history.length > 40 || estimate(d.history) > 128 * 1024 * 1024)) + d.history.shift(); + d.dirty = true; +} +export function undo(d) { + const previous = d.history.pop(); + if (!previous) return false; + d.future.push({ label: previous.label, state: snapshot(d) }); + Object.assign(d, previous.state); + d.dirty = true; + return true; +} +export function redo(d) { + const next = d.future.pop(); + if (!next) return false; + d.history.push({ label: next.label, state: snapshot(d) }); + Object.assign(d, next.state); + d.dirty = true; + return true; +} +export function layerImage(l) { + if (!l.mask) return l.canvas; + const c = cloneCanvas(l.canvas), + ctx = c.getContext('2d'); + ctx.globalCompositeOperation = 'destination-in'; + ctx.drawImage(l.mask, 0, 0); + return c; +} +function applyAdjustmentTo(sourceCanvas, l, originX = 0, originY = 0) { + const ctx = sourceCanvas.getContext('2d'), + width = sourceCanvas.width, + height = sourceCanvas.height; + const source = ctx.getImageData(0, 0, width, height); + let mask = null; + if (l.mask) { + const m = canvas(width, height), + mc = m.getContext('2d'); + mc.drawImage(l.mask, l.x - originX, l.y - originY); + mask = mc.getImageData(0, 0, width, height).data; + } + const pixels = adjustedPixels( + source.data, + width, + height, + l.adjustment, + l.opacity, + mask, + l.blend, + originX, + originY, + ); + ctx.putImageData(new ImageData(pixels, width, height), 0, 0); +} +export function composite(d, target) { + const c = target || canvas(d.width, d.height); + if (c.width !== d.width) c.width = d.width; + if (c.height !== d.height) c.height = d.height; + const ctx = c.getContext('2d'); + ctx.clearRect(0, 0, c.width, c.height); + for (const { base: l, adjustments } of compositionGroups(d.layers)) { + if (!l.visible) continue; + if (l.adjustment) { + applyAdjustmentTo(c, l); + continue; + } + ctx.save(); + ctx.globalAlpha = l.opacity; + ctx.globalCompositeOperation = l.blend; + const rendered = renderedLayer(l); + const visibleAdjustments = adjustments.filter((a) => a.visible); + const image = visibleAdjustments.length ? cloneCanvas(rendered.image) : rendered.image; + for (const adjustment of visibleAdjustments) + applyAdjustmentTo(image, adjustment, l.x + rendered.offset, l.y + rendered.offset); + if (pixelBlendModes.includes(l.blend)) { + const x = Math.max(0, Math.floor(l.x + rendered.offset)); + const y = Math.max(0, Math.floor(l.y + rendered.offset)); + const w = Math.min(c.width, Math.ceil(l.x + rendered.offset + image.width)) - x; + const h = Math.min(c.height, Math.ceil(l.y + rendered.offset + image.height)) - y; + if (w > 0 && h > 0) { + const source = canvas(w, h), + sc = source.getContext('2d'); + sc.drawImage(image, l.x + rendered.offset - x, l.y + rendered.offset - y); + const pixels = compositePixels( + ctx.getImageData(x, y, w, h).data, + sc.getImageData(0, 0, w, h).data, + l.blend, + l.opacity, + w, + x, + y, + ); + ctx.putImageData(new ImageData(pixels, w, h), x, y); + } + } else ctx.drawImage(image, l.x + rendered.offset, l.y + rendered.offset); + ctx.restore(); + } + return c; +} +export function renderedLayer(l) { + if (!l.mask && !Object.values(l.styles || {}).some((s) => s?.enabled)) + return { image: l.canvas, offset: 0 }; + return layerRenderCache.get(l.canvas, l.mask, l.styles, () => + renderStyles(layerImage(l), l.styles, canvas), + ); +} +export function selectionPath(s) { + const p = new Path2D(); + if (!s) return p; + if (s.kind === 'runs') { + for (const [x, y, w] of s.runs) p.rect(x, y, w, 1); + } else if (s.kind === 'ellipse') + p.ellipse( + s.x + s.w / 2, + s.y + s.h / 2, + Math.abs(s.w / 2), + Math.abs(s.h / 2), + 0, + 0, + Math.PI * 2, + ); + else if (s.kind === 'polygon') { + s.points.forEach(([x, y], i) => (i ? p.lineTo(x, y) : p.moveTo(x, y))); + p.closePath(); + } else p.rect(s.x, s.y, s.w, s.h); + return p; +} +export function clipSelection(ctx, d, l) { + if (!d.selection) return; + ctx.translate(-l.x, -l.y); + if (d.selection.invert) { + const p = new Path2D(); + p.rect(0, 0, d.width, d.height); + p.addPath(selectionPath(d.selection)); + ctx.clip(p, 'evenodd'); + } else ctx.clip(selectionPath(d.selection)); + ctx.translate(l.x, l.y); +} +export async function imageFrom(src) { + const image = new Image(); + image.src = src; + await image.decode(); + return image; +} +export async function serialize(d) { + const layers = []; + for (const l of d.layers) { + const { canvas: c, mask, ...meta } = l; + layers.push({ ...meta, image: await dataURL(c), maskImage: mask ? await dataURL(mask) : null }); + } + return { + format: 'retouch-lab', + version: 1, + id: d.id, + name: d.name, + width: d.width, + height: d.height, + layers, + activeId: d.activeId, + revision: d.revision, + paths: d.paths, + }; +} +export function dataURL(c) { + return new Promise((ok, fail) => + c.toBlob((blob) => { + if (!blob) return fail(Error('图像编码失败')); + const r = new FileReader(); + r.onload = () => ok(r.result); + r.onerror = () => fail(r.error); + r.readAsDataURL(blob); + }, 'image/png'), + ); +} +export async function deserialize(p) { + if ( + p.format !== 'retouch-lab' || + p.version !== 1 || + !Array.isArray(p.layers) || + p.layers.length < 1 || + p.layers.length > 100 + ) + throw Error('不是支持的修图工作台工程'); + canvas(p.width, p.height); + const d = documentModel(p.width, p.height, String(p.name || '未命名').slice(0, 200)); + d.layers = []; + let pixels = 0; + for (const item of p.layers) { + if (typeof item.image !== 'string' || !item.image.startsWith('data:image/png;base64,')) + throw Error('工程包含不支持的图像'); + const img = await imageFrom(item.image); + pixels += img.width * img.height; + if (pixels > 128e6) throw Error('工程图层合计超过 1.28 亿像素'); + const l = layer(img.width, img.height, String(item.name || '图层').slice(0, 200)); + l.canvas.getContext('2d').drawImage(img, 0, 0); + l.id = typeof item.id === 'string' ? item.id : l.id; + l.x = Number.isFinite(item.x) ? item.x : 0; + l.y = Number.isFinite(item.y) ? item.y : 0; + l.visible = item.visible !== false; + l.locked = item.locked === true; + l.opacity = Number.isFinite(item.opacity) ? Math.max(0, Math.min(1, item.opacity)) : 1; + l.blend = blends.includes(item.blend) ? item.blend : 'source-over'; + l.text = item.text && typeof item.text.value === 'string' ? item.text : null; + l.adjustment = item.adjustment ? normalizeAdjustment(item.adjustment) : null; + l.clipToBelow = Boolean(l.adjustment && item.clipToBelow); + l.styles = item.styles ? normalizeStyles(item.styles) : null; + if (l.styles) { + const padding = stylePadding(l.styles); + if ((img.width + 2 * padding) * (img.height + 2 * padding) > LIMIT_PIXELS) + throw Error('工程图层含样式后的尺寸超过 3200 万像素'); + } + if (item.maskImage) { + if (!item.maskImage.startsWith('data:image/png;base64,')) throw Error('蒙版数据无效'); + const mask = await imageFrom(item.maskImage); + l.mask = canvas(l.canvas.width, l.canvas.height); + l.mask.getContext('2d').drawImage(mask, 0, 0); + } + d.layers.push(l); + } + d.id = /^[a-f0-9-]{36}$/.test(p.id) ? p.id : crypto.randomUUID(); + d.revision = Number.isInteger(p.revision) ? p.revision : 0; + d.activeId = d.layers.some((l) => l.id === p.activeId) ? p.activeId : d.layers.at(-1).id; + d.paths = Array.isArray(p.paths) ? p.paths : []; + return d; +} +export function download(blob, name) { + const url = URL.createObjectURL(blob), + a = document.createElement('a'); + a.href = url; + a.download = name; + document.body.append(a); + a.click(); + a.remove(); + setTimeout(() => URL.revokeObjectURL(url), 30000); +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/oil-paint.js b/plugins/webguhui/minimax-photo/miniapp/client/oil-paint.js new file mode 100644 index 00000000..052a1517 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/oil-paint.js @@ -0,0 +1,45 @@ +// Dominant-luminance neighborhood painting. Sliding columns avoid rebuilding +// the entire square histogram for every pixel; transparent colors carry no weight. +export function oilPaint(source, width, height, value) { + const radius = Math.max(1, Math.min(12, Math.round(Number(value) || 1))); + const output = new Uint8ClampedArray(source); + const bins = new Uint8Array(width * height); + for (let i = 0; i < bins.length; i++) + bins[i] = Math.min( + 15, + Math.floor( + (0.2126 * source[i * 4] + 0.7152 * source[i * 4 + 1] + 0.0722 * source[i * 4 + 2]) / 16, + ), + ); + const weights = new Float64Array(16), + colors = new Float64Array(48); + function column(x, y, direction) { + x = Math.max(0, Math.min(width - 1, x)); + for (let dy = -radius; dy <= radius; dy++) { + const yy = Math.max(0, Math.min(height - 1, y + dy)), + p = yy * width + x, + i = p * 4, + b = bins[p], + a = source[i + 3] * direction; + weights[b] += a; + for (let c = 0; c < 3; c++) colors[b * 3 + c] += source[i + c] * a; + } + } + for (let y = 0; y < height; y++) { + weights.fill(0); + colors.fill(0); + for (let x = -radius; x <= radius; x++) column(x, y, 1); + for (let x = 0; x < width; x++) { + const i = (y * width + x) * 4; + if (source[i + 3]) { + let dominant = 0; + for (let b = 1; b < 16; b++) if (weights[b] > weights[dominant]) dominant = b; + if (weights[dominant]) + for (let c = 0; c < 3; c++) output[i + c] = colors[dominant * 3 + c] / weights[dominant]; + } + column(x - radius, y, -1); + column(x + radius + 1, y, 1); + } + } + return output; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photo-activity.js b/plugins/webguhui/minimax-photo/miniapp/client/photo-activity.js new file mode 100644 index 00000000..dda7ff65 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photo-activity.js @@ -0,0 +1,234 @@ +import { t } from './photo-i18n.js'; +const NS = 'http://www.w3.org/2000/svg'; +const finitePoint = (p) => + Array.isArray(p) && p.length >= 2 && p.slice(0, 2).every(Number.isFinite); + +// These are command footprints, not a claim about precisely changed pixels. +export function operationPaths(method, args) { + const steps = + method === 'batch' && Array.isArray(args) ? args : method === 'execute' ? [args] : []; + // Mixed batches may transform coordinates after a stroke; show only a canvas highlight. + if (steps.some((step) => !/^paint\.(stroke|pencil|mixerBrush)$/.test(step?.command))) return []; + return steps + .slice(0, 64) + .flatMap((step) => { + const p = step?.params; + if (!/^paint\.(stroke|pencil|mixerBrush)$/.test(step?.command) || !Array.isArray(p?.points)) + return []; + if (!p.points.length || !p.points.every(finitePoint)) return []; + const stride = Math.max(1, Math.ceil(p.points.length / 512)); + const points = p.points + .filter((_, i) => i % stride === 0 || i === p.points.length - 1) + .map(([x, y]) => [x, y]); + const bounds = p.points.reduce( + (b, [x, y]) => [Math.min(b[0], x), Math.min(b[1], y), Math.max(b[2], x), Math.max(b[3], y)], + [Infinity, Infinity, -Infinity, -Infinity], + ); + return [ + { + points, + bounds, + radius: Math.min(4096, Math.max(1, Number(p.size) || 1)) / 2, + }, + ]; + }) + .slice(-8); +} +export function projectPoint([x, y], view) { + return [ + view.origin[0] + x * view.xAxis[0] + y * view.yAxis[0], + view.origin[1] + x * view.xAxis[1] + y * view.yAxis[1], + ]; +} +export function validViewport(v) { + return ( + v && + [v.origin, v.xAxis, v.yAxis, v.size].every(finitePoint) && + v.size.every((x) => x > 0) && + Array.isArray(v.clip) && + v.clip.length === 4 && + v.clip.every(Number.isFinite) && + v.clip[2] > 0 && + v.clip[3] > 0 + ); +} +export function createActivity({ frame, call }) { + const host = document.createElement('div'); + host.className = 'photo-activity'; + host.hidden = true; + host.setAttribute('aria-hidden', 'true'); + frame.parentElement.append(host); + let generation = 0, + timer, + enabled = true; + try { + enabled = localStorage.getItem('minimax-photo.activity') !== 'off'; + } catch {} + const toggle = document.querySelector('#photo-show-activity'); + toggle.checked = enabled; + toggle.onchange = () => { + enabled = toggle.checked; + try { + localStorage.setItem('minimax-photo.activity', enabled ? 'on' : 'off'); + } catch {} + clear(); + }; + function clear() { + generation++; + clearTimeout(timer); + host.getAnimations({ subtree: true }).forEach((a) => a.cancel()); + host.replaceChildren(); + host.hidden = true; + } + const svgNode = (name, attrs) => { + const el = document.createElementNS(NS, name); + for (const [k, v] of Object.entries(attrs)) el.setAttribute(k, String(v)); + return el; + }; + async function completed(method, args, before) { + if (!enabled || !['execute', 'batch'].includes(method) || !before?.document) return; + const ticket = generation; + try { + const after = await call('inspect'); + if ( + ticket !== generation || + after.version?.split(':')[0] !== before.version?.split(':')[0] || + after.version === before.version + ) + return; + // A geometry-changing command has no safe before/after footprint in the old coordinate system. + if ( + after.document.width !== before.document.width || + after.document.height !== before.document.height + ) + return; + const view = await call('viewport'); + if (ticket !== generation || !validViewport(view) || document.hidden) return; + const svg = svgNode('svg', { + viewBox: `0 0 ${view.size.join(' ')}`, + preserveAspectRatio: 'none', + }); + const defs = svgNode('defs', {}), + clip = svgNode('clipPath', { id: `activity-${ticket}` }); + clip.append( + svgNode('rect', { + x: view.clip[0], + y: view.clip[1], + width: view.clip[2], + height: view.clip[3], + }), + ); + defs.append(clip); + svg.append(defs); + const g = svgNode('g', { 'clip-path': `url(#activity-${ticket})` }); + svg.append(g); + const paths = operationPaths(method, args); + const width = before.document.width, + height = before.document.height; + if (!Number.isFinite(width) || !Number.isFinite(height)) return; + // Limit all highlights to the canvas; no overlay may cover editor controls. + const corners = [ + [0, 0], + [width, 0], + [width, height], + [0, height], + ].map((p) => projectPoint(p, view)); + const docClip = svgNode('clipPath', { + id: `activity-document-${ticket}`, + }); + docClip.append( + svgNode('polygon', { + points: corners.map((p) => p.join(',')).join(' '), + }), + ); + defs.append(docClip); + const content = svgNode('g', { + 'clip-path': `url(#activity-document-${ticket})`, + }); + g.append(content); + if (paths.length) { + for (const { points, bounds, radius } of paths) { + const screen = points.map((p) => projectPoint(p, view)); + const d = screen.map((p, i) => `${i ? 'L' : 'M'} ${p.join(' ')}`).join(' '); + const path = svgNode('path', { + d, + class: 'photo-activity-trail', + fill: 'none', + }); + content.append(path); + const length = path.getTotalLength(); + const reduced = matchMedia('(prefers-reduced-motion: reduce)').matches; + if (!reduced && length > 0) + path.animate( + [ + { strokeDasharray: `${length}`, strokeDashoffset: length }, + { strokeDasharray: `${length}`, strokeDashoffset: 0 }, + ], + { duration: 700, fill: 'forwards' }, + ); + const l = bounds[0] - radius, + r = bounds[2] + radius, + top = bounds[1] - radius, + bottom = bounds[3] + radius; + content.append( + svgNode('polygon', { + class: 'photo-activity-area', + points: [ + [l, top], + [r, top], + [r, bottom], + [l, bottom], + ] + .map((p) => projectPoint(p, view).join(',')) + .join(' '), + }), + ); + const end = screen.at(-1); + content.append( + svgNode('circle', { + cx: end[0], + cy: end[1], + r: 5, + class: 'photo-activity-tip', + }), + ); + } + } else + content.append( + svgNode('polygon', { + class: 'photo-activity-area', + points: corners.map((p) => p.join(',')).join(' '), + }), + ); + const label = document.createElement('span'); + label.className = 'photo-activity-label'; + label.textContent = t(paths.length ? '已完成 · 画笔轨迹回放' : '已完成 · 画布已更新'); + host.replaceChildren(svg, label); + host.hidden = false; + timer = setTimeout(clear, 1800); + } catch { + /* Visualization must never change the edit result or its acknowledgement. */ + } + } + const resize = new ResizeObserver(clear); + resize.observe(frame); + frame.addEventListener('pointerdown', clear); + // Wheel/keyboard events occur inside the iframe and may change its viewport. + frame.addEventListener('load', () => { + try { + frame.contentWindow.addEventListener('wheel', clear, { passive: true }); + frame.contentWindow.addEventListener('pointerdown', clear); + frame.contentWindow.addEventListener('keydown', clear); + } catch {} + }); + document.addEventListener('visibilitychange', clear); + window.addEventListener( + 'pagehide', + () => { + clear(); + resize.disconnect(); + }, + { once: true }, + ); + return { clear, completed }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photo-help.css b/plugins/webguhui/minimax-photo/miniapp/client/photo-help.css new file mode 100644 index 00000000..e66ef0e8 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photo-help.css @@ -0,0 +1 @@ +body{font:16px/1.8 system-ui;max-width:800px;margin:48px auto;padding:0 24px;color:#222}h1{font-size:28px}h2{font-size:20px;margin-top:32px}a{color:#087ac1}nav{display:flex;justify-content:space-between;gap:16px}select{font:inherit;max-width:45%;padding:4px;border:1px solid #ccc;border-radius:6px}footer{margin:32px 0;color:#666} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photo-help.html b/plugins/webguhui/minimax-photo/miniapp/client/photo-help.html new file mode 100644 index 00000000..c0e2404f --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photo-help.html @@ -0,0 +1 @@ +MiniMax Photo · Help
diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photo-help.js b/plugins/webguhui/minimax-photo/miniapp/client/photo-help.js new file mode 100644 index 00000000..5cdf5786 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photo-help.js @@ -0,0 +1,175 @@ +import { + t, + initLanguage, + getLanguage, + getPreference, + languages, + setLanguage, + subscribeLanguage, +} from './photo-i18n.js'; +const content = { + "zh-hans": [ + [ + "MiniMax Photo", + "打开照片,调整图层和色彩,或描述想法让 AI 帮你完成。" + ], + [ + "开始创作", + "欢迎页可打开图片、新建画布或试用示例作品。商品、肖像和海报示例均可继续编辑。" + ], + [ + "保存与恢复", + "“更多 → 保存工程”保留图层,下载的 .pcraft 文件可以再次打开。“导出 PNG”保存合并图片。应用每隔几秒检查当前作品的变化并在本机备份,可从“更多 → 恢复作品”找回。刚完成的修改可能还未备份;关闭前请保存重要作品。" + ], + [ + "与 AI 协作", + "打开右下角的 AI 助手,直接输入需求并发送。AI 会按需要读取画面、编辑图层或生成图片。标题栏可以拖动,减号收起面板。窄窗口下显示在底部,不会占用固定侧栏。" + ], + [ + "查看图片与进度", + "生成的图片显示在“AI 返回的图片”,点击“打开图片”会打开新作品,原作品保留。发送过程中可以停止;需要许可或补充信息时,在面板里操作。读取结果失败时可点击重试。" + ], + [ + "继续上次对话", + "草稿和最近回复会自动保存在本机。重新打开后继续使用原会话。若上次任务结果不确定,请先“查看完整会话”,不要重复发送。请不要同时在两个窗口修改同一份 AI 会话。" + ], + [ + "语言与兼容性", + "“更多 → 语言”支持简体中文、繁体中文、English 和日本語。旧 .retouch.json 文件从“打开旧版工程”打开。复杂 PSD、特殊字体和部分滤镜可能与桌面软件有差异;重要作品请检查导出结果。" + ] + ], + "en": [ + [ + "MiniMax Photo", + "Open a photo, edit layers and colors, or describe an idea to the AI assistant." + ], + [ + "Start creating", + "Open an image, create a canvas or try an editable product, portrait or poster example on the welcome page." + ], + [ + "Save and recover", + "More → Save project downloads an editable .pcraft file with layers. Export PNG saves a flattened image. Changed active artwork is backed up locally every few seconds and can be reopened from More → Recover artwork. Recent edits may not be backed up yet. Save important work before closing." + ], + [ + "Work with AI", + "Open AI assistant at the bottom right and send your request directly. AI can inspect the canvas, edit layers or generate images. Drag the heading to move it; use minus to minimize. On narrow windows it appears at the bottom." + ], + [ + "Images and progress", + "Returned images appear under AI returned images. Open image creates another document and preserves the original. Stop a running request or answer approvals and questions in the panel. Failed result loading has a retry button." + ], + [ + "Continue a conversation", + "Drafts and the latest reply are saved locally. Reopen the app to continue the same conversation. If the previous outcome is unknown, use View full conversation before sending again. Avoid editing the same conversation in two windows." + ], + [ + "Language and compatibility", + "More → Language supports Simplified Chinese, Traditional Chinese, English and Japanese. Open older .retouch.json files with Open legacy project. Complex PSDs, fonts and some filters may differ from desktop editors; check important exports." + ] + ], + "zh-hant": [ + [ + "MiniMax Photo", + "開啟照片,調整圖層和色彩,或描述想法讓 AI 協助完成。" + ], + [ + "開始創作", + "歡迎頁可開啟圖片、建立畫布,或試用可繼續編輯的商品、肖像與海報範例。" + ], + [ + "儲存與復原", + "「更多 → 儲存專案」下載保留圖層的 .pcraft 檔案;「匯出 PNG」儲存合併圖片。應用每隔幾秒檢查目前作品的變更並在本機備份,可從「更多 → 復原作品」找回。最新修改可能尚未備份,關閉前請儲存重要作品。" + ], + [ + "與 AI 協作", + "開啟右下角的 AI 助手,直接輸入需求並傳送。AI 可讀取畫面、編輯圖層或生成圖片。拖動標題列可移動面板,減號可收起;窄視窗會顯示於底部。" + ], + [ + "圖片與進度", + "生成圖片顯示於「AI 回傳的圖片」,開啟後會建立另一份作品,保留原作。處理中可停止;需要許可或補充資訊時可在面板中操作。讀取結果失敗時可重試。" + ], + [ + "繼續對話", + "草稿與最近回覆會儲存於本機,重新開啟後可繼續原對話。若上次結果不明,請先查看完整對話,勿重複傳送。避免同時在兩個視窗修改同一對話。" + ], + [ + "語言與相容性", + "語言選單支援簡體中文、繁體中文、English 與日本語。舊 .retouch.json 檔案請用「開啟舊版專案」。複雜 PSD、特殊字型與部分濾鏡可能與桌面軟體不同,請檢查重要匯出結果。" + ] + ], + "ja": [ + [ + "MiniMax Photo", + "写真を開いてレイヤーや色を編集したり、AI にアイデアを伝えて制作できます。" + ], + [ + "制作を始める", + "ホーム画面で画像を開く、新規キャンバスを作る、商品・ポートレート・ポスターの編集可能な作例を試すことができます。" + ], + [ + "保存と復元", + "「その他 → プロジェクトを保存」でレイヤーを含む .pcraft を保存します。PNG は統合画像です。編集中の作品の変更を数秒ごとに確認し、端末内にバックアップします。「作品を復元」から開けます。直前の変更は未保存の場合があります。重要な作品は閉じる前に保存してください。" + ], + [ + "AI と制作", + "右下の AI アシスタントに依頼を直接送信します。画像の確認、レイヤー編集、画像生成ができます。見出しをドラッグして移動し、マイナスで最小化します。狭いウィンドウでは下部に表示します。" + ], + [ + "画像と進行状況", + "返された画像を開くと別の作品が開き、元の作品は残ります。処理中は停止でき、許可や質問にもパネル内で回答できます。結果の読み込みに失敗した場合は再試行できます。" + ], + [ + "会話を続ける", + "下書きと直近の回答は端末内に保存します。再度開いて同じ会話を続けられます。前回の結果が不明な場合は、会話全体を確認してから送信してください。複数のウィンドウで同じ会話を同時に編集しないでください。" + ], + [ + "言語と互換性", + "簡体字中国語、繁体字中国語、英語、日本語に対応します。旧 .retouch.json は旧形式のプロジェクトとして開きます。複雑な PSD、フォント、一部のフィルターはデスクトップ版と異なる場合があります。重要な出力は確認してください。" + ] + ] +}; +content['zh-hans'].push( + ['附图绘画', '在 MiniMax Code 聊天中输入 @ 选择 MiniMax Photo,再添加图片附件。例如:“照这张图画简单的铅笔素描,逐笔画给我看。”无需填写文件路径或工具名。AI 会打开编辑器、绘制并检查结果;复杂任务可能需要几分钟。'], + ['查看逐笔过程', '要求逐笔展示时,每笔会真实更新画布,并可单独撤销。一条请求可以分阶段执行。完成后的短暂轨迹提示与逐笔绘制是两种不同效果。'], + ['录制与保存', '“更多 → 录制绘画过程”只录编辑器画布和工具栏,不含 MiniMax Code 聊天。停止后选择“保存录制视频”下载 WebM。要展示附图、聊天和回复,请在发送前用外部录屏工具录制整个应用窗口。取消保存后可重试;未保存的视频会在刷新或关闭页面后丢失。达到 60 分钟或 256 MiB 时自动结束,仍可保存。保存后清除录制缓存即可开始下一次录制。'], +); +content['zh-hant'].push( + ['附圖繪畫', '在 MiniMax Code 聊天中輸入 @ 選擇 MiniMax Photo,再加入圖片附件。例如:「照這張圖畫簡單的鉛筆素描,逐筆畫給我看。」不必提供檔案路徑或工具名稱。AI 會開啟編輯器、繪畫並檢查結果;複雜任務可能需要幾分鐘。'], + ['查看逐筆過程', '要求逐筆展示時,每筆會實際更新畫布,並可個別復原。一個請求可分階段執行。完成後的短暫軌跡提示與逐筆繪製是兩種不同效果。'], + ['錄製與儲存', '「更多 → 錄製繪畫過程」只錄編輯器畫布和工具列,不含 MiniMax Code 聊天。停止後選擇「儲存錄製影片」下載 WebM。若要展示附圖、聊天與回答,請在傳送前用外部錄影工具錄下整個應用視窗。取消儲存後可重試;未儲存影片會在重新整理或關閉頁面後遺失。達到 60 分鐘或 256 MiB 時自動結束,仍可儲存。儲存後清除錄製暫存即可開始下一次錄製。'], +); +content.en.push( + ['Draw from an attachment', 'In MiniMax Code chat, type @ and select MiniMax Photo, then attach your image. Try: “Draw a simple pencil sketch of this image and show each stroke.” No file paths or tool names are needed. AI opens the editor, draws and checks the result. Complex tasks may take several minutes.'], + ['Watch each stroke', 'Ask to see each stroke to update the real canvas step by step, with individual undo. One request may run in stages. The brief activity overlay shown after an edit is separate from incremental drawing.'], + ['Record and save', 'More → Record drawing process captures only the editor canvas and controls, not MiniMax Code chat. Stop, then choose Save recording to download WebM. To include attachments, chat and replies, use an external recorder for the whole app window before sending. A cancelled save can be retried; reload or close loses unsaved video. Recording stops at 60 minutes or 256 MiB and can still be saved. Clear the recording buffer after saving to start again.'], +); +content.ja.push( + ['添付画像をもとに描く', 'MiniMax Code のチャットで @ を入力して MiniMax Photo を選び、画像を添付します。例えば「この画像を簡単な鉛筆スケッチにして、一筆ずつ描く様子を見せて」。パスやツール名は不要です。AI がエディターを開き、描画して結果を確認します。複雑な作業には数分かかる場合があります。'], + ['一筆ずつ見る', '一筆ずつ描くよう依頼すると、実際のキャンバスが順次更新され、各筆を個別に取り消せます。一つの依頼を段階に分けて実行することがあります。編集後の短い軌跡表示とは別の機能です。'], + ['録画と保存', '描画録画はエディターのキャンバスと操作部のみを記録し、MiniMax Code のチャットは含みません。停止後、録画を保存して WebM をダウンロードします。添付画像、チャット、回答も含める場合は、送信前から外部の録画ツールでアプリ全体のウィンドウを記録してください。保存をキャンセルしても再試行できます。未保存の動画は再読み込みやページを閉じると失われます。60 分または 256 MiB で自動停止しますが、保存は可能です。保存後に録画キャッシュを消去すると次の録画を開始できます。'], +); +initLanguage(); +const select = document.querySelector('select'); +function render() { + document.title = 'MiniMax Photo · ' + t('使用说明'); + const back = document.querySelector('a'); + back.textContent = '← ' + t('返回工作台'); + select.setAttribute('aria-label', t('语言')); + select.replaceChildren( + ...languages.map(([code, label]) => new Option(code === 'auto' ? t(label) : label, code)), + ); + select.value = getPreference(); + const main = document.querySelector('main'); + main.replaceChildren(); + for (const [i, [heading, text]] of content[getLanguage()].entries()) { + const h = document.createElement(i ? 'h2' : 'h1'), + p = document.createElement('p'); + h.textContent = heading; + p.textContent = text; + main.append(h, p); + } +} +select.onchange = () => setLanguage(select.value); +subscribeLanguage(render); +render(); diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photo-i18n.js b/plugins/webguhui/minimax-photo/miniapp/client/photo-i18n.js new file mode 100644 index 00000000..54b09073 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photo-i18n.js @@ -0,0 +1,571 @@ +export const messages = { + en: { + '描述需求,交给 AI 助手': 'Describe your idea to the AI assistant', + '打开作品可直接编辑,也可以让 AI 助手帮你继续创作。': + 'Open artwork to edit, or ask the AI assistant to continue creating.', + + '正在处理图片…': 'Working on your image…', + '正在思考…': 'Thinking…', + '正在停止…': 'Stopping…', + 已停止: 'Stopped', + 停止: 'Stop', + 发送: 'Send', + 继续: 'Continue', + 需要你的确认: 'Your approval is needed', + 允许本次: 'Allow once', + 拒绝: 'Deny', + 请补充信息: 'More information needed', + 补充说明: 'Additional details', + 查看完整会话: 'View full conversation', + '请在 MiniMax Code 中打开此应用以使用 AI。': 'Open this app in MiniMax Code to use AI.', + 'AI 处理失败,请检查后重试。': 'AI could not finish. Check before retrying.', + '结果尚未确认,请先查看会话,不要重复发送。': + 'The outcome is unknown. Check the conversation before sending again.', + + 查看完整需求: 'View full request', + '支持图片、PSD 和可继续编辑的工程文件': 'Supports images, PSD and editable project files', + '需求已准备好,点击下方复制,再到 MiniMax Code 聊天中粘贴发送。': + 'Your request is ready. Copy it below, then paste and send it in MiniMax Code chat.', + '描述你的想法,我会连同当前图片信息一起放入 MiniMax Code 聊天。请在那里发送并查看回复。': + 'Describe your idea. Your request and image context will be placed in MiniMax Code chat. Send it there and view the reply.', + '当前是浏览器预览,无法直接连接 AI。可以先写好需求,再复制到 MiniMax Code 聊天中发送。': + 'This browser preview cannot connect directly to AI. Prepare a request, then copy it into MiniMax Code chat and send.', + 生成海报: 'Create a poster', + 改善照片: 'Improve a photo', + '帮我设计一张咖啡海报,奶油色背景,标题 COFFEE BREAK。': + 'Design a coffee poster with a cream background and the headline COFFEE BREAK.', + '请先让我选择一张照片,再改善曝光和色彩,保留自然细节。': + 'Ask me to choose a photo, then improve exposure and color while preserving natural details.', + '描述你想做的图片,或先打开一张照片…': 'Describe an image, or open a photo first…', + '在 MiniMax Code 中继续': 'Continue in MiniMax Code', + 准备需求: 'Prepare request', + 'AI 返回的图片': 'Images returned by AI', + + 作品展示: 'Showcase', + 'AI 生成 · 可打开编辑': 'AI generated · Open to edit', + 静物广告: 'Product campaign', + '砂岩、柔光与鼠尾草绿': 'Sandstone, soft light and sage green', + 落日人像: 'Golden hour portrait', + 暖色光线与自然肤色: 'Warm light and natural skin tones', + 咖啡海报: 'Coffee poster', + 配图与字体的完整画面: 'Imagery and typography together', + 打开作品: 'Open artwork', + '打开作品可直接编辑;试试这个会填入需求,由主聊天继续创作。': + 'Open artwork to edit directly. Try this fills a request for the main chat.', + + 开始创作: 'Start creating', + 让想法成为图片: 'Turn ideas into images', + '打开图片精细编辑,或把想法交给 AI。': + 'Edit an image with precision, or start with an AI idea.', + 新建画布: 'New canvas', + '支持图片、PSD 和 .pcraft 工程': 'Images, PSD and .pcraft projects supported', + 从一个想法开始: 'Start with an idea', + 商品图换背景: 'Product backgrounds', + '保留商品,换成干净的展示背景': 'Keep the product. Give it a clean backdrop.', + 照片调色: 'Photo color grading', + '自然肤色、暖色光线,保留细节': 'Natural skin tones, warm light, preserved detail', + 社交海报: 'Social poster', + '从主题开始,完成配图和文字排版': 'From a theme to images and typography', + 试试这个: 'Try this', + 打开图片或选择示例: 'Open an image or pick an idea', + '描述需求,在主聊天发送': 'Describe it and send in the main chat', + '查看结果,继续编辑和导出': 'Review, refine and export', + '示例会填入需求,不会自动生成图片。AI 由 MiniMax Code 主聊天完成。': + 'Examples fill in a request; they do not generate automatically. AI runs through MiniMax Code main chat.', + '请先让我上传商品图,保留商品主体,把背景换成干净的浅色摄影棚,保持自然阴影。': + 'Ask me to upload a product photo first. Keep the product and replace the background with a clean, light studio backdrop and natural shadows.', + '请先让我上传照片,调整曝光和白平衡,让光线更温暖,保留自然肤色和细节。': + 'Ask me to upload a photo first. Adjust exposure and white balance for warmer light while preserving natural skin tones and detail.', + '帮我制作一张社交海报。请先询问主题、标题和发布平台,再确定尺寸、配图和文字排版。': + 'Help me make a social poster. Ask about the theme, headline and platform first, then choose dimensions, imagery and typography.', + + 更多: 'More', + 打开旧版工程: 'Open classic project', + 高级选项: 'Advanced options', + 自动选择: 'Automatic', + 复制到聊天: 'Copy to chat', + 生成结果: 'Generated images', + 'Agent 图片已返回': 'Agent image is ready', + 生成后的图片会显示在这里: 'Generated images will appear here', + '读取结果失败,请点击重试': 'Could not load results. Click to retry.', + + 打开图片: 'Open image', + 保存工程: 'Save project', + '导出 PNG': 'Export PNG', + 'Agent 图片': 'Agent images', + 轻量工作台: 'Classic editor', + 使用说明: 'Help', + 关闭: 'Close', + 语言: 'Language', + 跟随浏览器: 'Follow browser', + '正在加载图片编辑器…': 'Loading image editor…', + 加载中: 'Loading', + 'PhotoCraft 图片编辑器': 'PhotoCraft image editor', + 'PhotoCraft 已就绪 · 图片在本机处理': 'PhotoCraft is ready · Images stay on this device', + '引擎响应超时;请检查画面和任务记录,勿重复提交': + 'Editor timed out. Check the image and task log before retrying.', + '编辑器忙,请稍后重试': 'Editor is busy. Please try again shortly.', + 'Agent 正在处理图片…': 'Agent is working on the image…', + 'Agent 已读取画面或导出结果': 'Agent has read the image or exported the result', + 'Agent 操作已完成 · 可在编辑器中撤销': 'Agent finished · You can undo in the editor', + '画面已处理,但任务回执未确认;请检查画面,勿重复执行': + 'Image updated, but confirmation is missing. Check the image before retrying.', + '已打开 {name}': 'Opened {name}', + '已导出 {format}': 'Exported {format}', + 尚未打开图片: 'No image open', + 请先打开图片: 'Open an image first', + 等待返回: 'Waiting for result', + 读取图片失败: 'Could not load image', + 'Agent 图片已打开': 'Agent image opened', + '还没有图片任务。可以在右下角描述你的需求。': + 'No image tasks yet. Describe what you need in the AI panel.', + 'AI 助手': 'AI assistant', + '打开 AI 助手': 'Open AI assistant', + '收起 AI 助手': 'Collapse AI assistant', + 'AI 修图助手': 'AI photo assistant', + 还没有打开图片: 'No image open', + '当前工程 · {name}': 'Current project · {name}', + '描述想法,或先打开一张图片': 'Describe an idea, or open an image', + 任务: 'Task', + 'AI 任务类型': 'AI task type', + 编辑工程: 'Edit project', + 生成图片: 'Generate image', + 修改图片: 'Edit image', + 'AI 修图需求': 'AI editing request', + '想怎么改?比如:背景调暖,加一个白色标题…': + 'What would you like to change? Try a warmer background and a white title…', + 放入主聊天后发送: 'Send from the main chat', + '复制到 MiniMax Code 聊天': 'Copy to MiniMax Code chat', + '正在准备…': 'Preparing…', + '交给 Agent': 'Send to Agent', + 生成需求: 'Prepare request', + '已放入主聊天输入框,请在那里点击发送。': + 'Added to the main chat input. Send it there to continue.', + '需求已准备好,复制到 MiniMax Code 聊天中发送。': + 'Request ready. Copy it to MiniMax Code chat and send.', + '给 Agent 的需求文本': 'Request text for Agent', + '已复制,请粘贴到 MiniMax Code 聊天中发送。': 'Copied. Paste into MiniMax Code chat and send.', + '无法自动复制,请选中文本手动复制。': + 'Could not copy automatically. Select the text and copy it manually.', + 复制需求: 'Copy request', + 切换语言失败: 'Could not change language', + '连接失败,请稍后重试': 'Connection failed. Please try again.', + '操作失败,请查看详细信息': 'Operation failed. See details.', + 返回工作台: 'Back to editor', + }, + 'zh-hant': { + '描述需求,交给 AI 助手': '描述需求,交給 AI 助手', + '打开作品可直接编辑,也可以让 AI 助手帮你继续创作。': + '開啟作品可直接編輯,也可以讓 AI 助手幫你繼續創作。', + + '正在处理图片…': '正在處理圖片…', + '正在思考…': '正在思考…', + '正在停止…': '正在停止…', + 已停止: '已停止', + 停止: '停止', + 发送: '傳送', + 继续: '繼續', + 需要你的确认: '需要你的確認', + 允许本次: '允許本次', + 拒绝: '拒絕', + 请补充信息: '請補充資訊', + 补充说明: '補充說明', + 查看完整会话: '查看完整對話', + '请在 MiniMax Code 中打开此应用以使用 AI。': '請在 MiniMax Code 中開啟此應用以使用 AI。', + 'AI 处理失败,请检查后重试。': 'AI 處理失敗,請檢查後重試。', + '结果尚未确认,请先查看会话,不要重复发送。': '結果尚未確認,請先查看對話,不要重複傳送。', + + 查看完整需求: '查看完整需求', + '支持图片、PSD 和可继续编辑的工程文件': '支援圖片、PSD 和可繼續編輯的專案檔案', + '需求已准备好,点击下方复制,再到 MiniMax Code 聊天中粘贴发送。': + '需求已準備好,點擊下方複製,再到 MiniMax Code 聊天中貼上傳送。', + '描述你的想法,我会连同当前图片信息一起放入 MiniMax Code 聊天。请在那里发送并查看回复。': + '描述你的想法,我會連同目前圖片資訊一起放入 MiniMax Code 聊天。請在那裡傳送並查看回覆。', + '当前是浏览器预览,无法直接连接 AI。可以先写好需求,再复制到 MiniMax Code 聊天中发送。': + '目前是瀏覽器預覽,無法直接連接 AI。可以先寫好需求,再複製到 MiniMax Code 聊天中傳送。', + 生成海报: '產生海報', + 改善照片: '改善照片', + '帮我设计一张咖啡海报,奶油色背景,标题 COFFEE BREAK。': + '幫我設計一張咖啡海報,奶油色背景,標題 COFFEE BREAK。', + '请先让我选择一张照片,再改善曝光和色彩,保留自然细节。': + '請先讓我選擇一張照片,再改善曝光和色彩,保留自然細節。', + '描述你想做的图片,或先打开一张照片…': '描述你想做的圖片,或先開啟一張照片…', + '在 MiniMax Code 中继续': '在 MiniMax Code 中繼續', + 准备需求: '準備需求', + 'AI 返回的图片': 'AI 回傳的圖片', + + 作品展示: '作品展示', + 'AI 生成 · 可打开编辑': 'AI 產生 · 可開啟編輯', + 静物广告: '靜物廣告', + '砂岩、柔光与鼠尾草绿': '砂岩、柔光與鼠尾草綠', + 落日人像: '落日人像', + 暖色光线与自然肤色: '暖色光線與自然膚色', + 咖啡海报: '咖啡海報', + 配图与字体的完整画面: '配圖與字體的完整畫面', + 打开作品: '開啟作品', + '打开作品可直接编辑;试试这个会填入需求,由主聊天继续创作。': + '開啟作品可直接編輯;試試這個會填入需求,由主聊天繼續創作。', + + 开始创作: '開始創作', + 让想法成为图片: '讓想法成為圖片', + '打开图片精细编辑,或把想法交给 AI。': '開啟圖片精細編輯,或把想法交給 AI。', + 新建画布: '新增畫布', + '支持图片、PSD 和 .pcraft 工程': '支援圖片、PSD 和 .pcraft 專案', + 从一个想法开始: '從一個想法開始', + 商品图换背景: '商品圖換背景', + '保留商品,换成干净的展示背景': '保留商品,換成乾淨的展示背景', + 照片调色: '照片調色', + '自然肤色、暖色光线,保留细节': '自然膚色、暖色光線,保留細節', + 社交海报: '社群海報', + '从主题开始,完成配图和文字排版': '從主題開始,完成配圖和文字排版', + 试试这个: '試試這個', + 打开图片或选择示例: '開啟圖片或選擇範例', + '描述需求,在主聊天发送': '描述需求,在主聊天傳送', + '查看结果,继续编辑和导出': '查看結果,繼續編輯和匯出', + '示例会填入需求,不会自动生成图片。AI 由 MiniMax Code 主聊天完成。': + '範例會填入需求,不會自動產生圖片。AI 由 MiniMax Code 主聊天完成。', + '请先让我上传商品图,保留商品主体,把背景换成干净的浅色摄影棚,保持自然阴影。': + '請先讓我上傳商品圖,保留商品主體,將背景換成乾淨的淺色攝影棚,保持自然陰影。', + '请先让我上传照片,调整曝光和白平衡,让光线更温暖,保留自然肤色和细节。': + '請先讓我上傳照片,調整曝光與白平衡,讓光線更溫暖,保留自然膚色與細節。', + '帮我制作一张社交海报。请先询问主题、标题和发布平台,再确定尺寸、配图和文字排版。': + '幫我製作一張社群海報。請先詢問主題、標題與發布平台,再確定尺寸、配圖與文字排版。', + + 更多: '更多', + 打开旧版工程: '開啟舊版專案', + 高级选项: '進階選項', + 自动选择: '自動選擇', + 复制到聊天: '複製到聊天', + 生成结果: '產生結果', + 'Agent 图片已返回': 'Agent 圖片已傳回', + 生成后的图片会显示在这里: '產生的圖片會顯示在這裡', + '读取结果失败,请点击重试': '讀取結果失敗,請點擊重試', + + 打开图片: '開啟圖片', + 保存工程: '儲存專案', + '导出 PNG': '匯出 PNG', + 'Agent 图片': 'Agent 圖片', + 轻量工作台: '輕量工作台', + 使用说明: '使用說明', + 关闭: '關閉', + 语言: '語言', + 跟随浏览器: '跟隨瀏覽器', + '正在加载图片编辑器…': '正在載入圖片編輯器…', + 加载中: '載入中', + 'PhotoCraft 图片编辑器': 'PhotoCraft 圖片編輯器', + 'PhotoCraft 已就绪 · 图片在本机处理': 'PhotoCraft 已就緒 · 圖片在本機處理', + '引擎响应超时;请检查画面和任务记录,勿重复提交': + '引擎回應逾時;請檢查畫面和任務記錄,勿重複提交', + '编辑器忙,请稍后重试': '編輯器忙碌中,請稍後重試', + 'Agent 正在处理图片…': 'Agent 正在處理圖片…', + 'Agent 已读取画面或导出结果': 'Agent 已讀取畫面或匯出結果', + 'Agent 操作已完成 · 可在编辑器中撤销': 'Agent 操作已完成 · 可在編輯器中復原', + '画面已处理,但任务回执未确认;请检查画面,勿重复执行': + '畫面已處理,但任務回執未確認;請檢查畫面,勿重複執行', + '已打开 {name}': '已開啟 {name}', + '已导出 {format}': '已匯出 {format}', + 尚未打开图片: '尚未開啟圖片', + 请先打开图片: '請先開啟圖片', + 等待返回: '等待回傳', + 读取图片失败: '讀取圖片失敗', + 'Agent 图片已打开': 'Agent 圖片已開啟', + '还没有图片任务。可以在右下角描述你的需求。': '還沒有圖片任務。可以在右下角描述你的需求。', + 'AI 助手': 'AI 助手', + '打开 AI 助手': '開啟 AI 助手', + '收起 AI 助手': '收起 AI 助手', + 'AI 修图助手': 'AI 修圖助手', + 还没有打开图片: '還沒有開啟圖片', + '当前工程 · {name}': '目前專案 · {name}', + '描述想法,或先打开一张图片': '描述想法,或先開啟一張圖片', + 任务: '任務', + 'AI 任务类型': 'AI 任務類型', + 编辑工程: '編輯專案', + 生成图片: '產生圖片', + 修改图片: '修改圖片', + 'AI 修图需求': 'AI 修圖需求', + '想怎么改?比如:背景调暖,加一个白色标题…': '想怎麼改?例如:背景調暖,加一個白色標題…', + 放入主聊天后发送: '放入主聊天後傳送', + '复制到 MiniMax Code 聊天': '複製到 MiniMax Code 聊天', + '正在准备…': '正在準備…', + '交给 Agent': '交給 Agent', + 生成需求: '產生需求', + '已放入主聊天输入框,请在那里点击发送。': '已放入主聊天輸入框,請在那裡點擊傳送。', + '需求已准备好,复制到 MiniMax Code 聊天中发送。': + '需求已準備好,複製到 MiniMax Code 聊天中傳送。', + '给 Agent 的需求文本': '給 Agent 的需求文字', + '已复制,请粘贴到 MiniMax Code 聊天中发送。': '已複製,請貼到 MiniMax Code 聊天中傳送。', + '无法自动复制,请选中文本手动复制。': '無法自動複製,請選取文字手動複製。', + 复制需求: '複製需求', + 切换语言失败: '切換語言失敗', + '连接失败,请稍后重试': '連線失敗,請稍後重試', + '操作失败,请查看详细信息': '操作失敗,請查看詳細資訊', + 返回工作台: '返回工作台', + }, + ja: { + '描述需求,交给 AI 助手': 'AI アシスタントに依頼する', + '打开作品可直接编辑,也可以让 AI 助手帮你继续创作。': + '作品を開いて編集したり、AI アシスタントに続きを依頼できます。', + + '正在处理图片…': '画像を処理中…', + '正在思考…': '考え中…', + '正在停止…': '停止中…', + 已停止: '停止しました', + 停止: '停止', + 发送: '送信', + 继续: '続ける', + 需要你的确认: '確認が必要です', + 允许本次: '今回のみ許可', + 拒绝: '拒否', + 请补充信息: '追加情報を入力してください', + 补充说明: '補足説明', + 查看完整会话: '会話全体を見る', + '请在 MiniMax Code 中打开此应用以使用 AI。': + 'AI を使うには MiniMax Code でこのアプリを開いてください。', + 'AI 处理失败,请检查后重试。': 'AI 処理に失敗しました。確認してから再試行してください。', + '结果尚未确认,请先查看会话,不要重复发送。': + '結果が未確認です。再送せず、先に会話を確認してください。', + + 查看完整需求: '依頼の全文を見る', + '支持图片、PSD 和可继续编辑的工程文件': '画像、PSD、再編集できるプロジェクトに対応', + '需求已准备好,点击下方复制,再到 MiniMax Code 聊天中粘贴发送。': + '依頼を用意しました。下でコピーし、MiniMax Code のチャットに貼り付けて送信してください。', + '描述你的想法,我会连同当前图片信息一起放入 MiniMax Code 聊天。请在那里发送并查看回复。': + 'アイデアと現在の画像情報を MiniMax Code のチャットに入力します。そこで送信し、返信を確認してください。', + '当前是浏览器预览,无法直接连接 AI。可以先写好需求,再复制到 MiniMax Code 聊天中发送。': + 'ブラウザプレビューでは AI に直接接続できません。依頼を作成してコピーし、MiniMax Code のチャットで送信してください。', + 生成海报: 'ポスターを作る', + 改善照片: '写真を整える', + '帮我设计一张咖啡海报,奶油色背景,标题 COFFEE BREAK。': + 'クリーム色の背景と COFFEE BREAK の見出しでコーヒーポスターを作ってください。', + '请先让我选择一张照片,再改善曝光和色彩,保留自然细节。': + 'まず写真を選ばせてから、自然なディテールを残して露出と色を調整してください。', + '描述你想做的图片,或先打开一张照片…': '作りたい画像を説明するか、写真を開いてください…', + '在 MiniMax Code 中继续': 'MiniMax Code で続ける', + 准备需求: '依頼を用意する', + 'AI 返回的图片': 'AI から届いた画像', + + 作品展示: '作品ギャラリー', + 'AI 生成 · 可打开编辑': 'AI 生成 · 開いて編集', + 静物广告: '商品広告', + '砂岩、柔光与鼠尾草绿': '砂岩、柔らかな光、セージグリーン', + 落日人像: '夕暮れのポートレート', + 暖色光线与自然肤色: '暖かい光と自然な肌色', + 咖啡海报: 'コーヒーポスター', + 配图与字体的完整画面: '写真と文字を組み合わせた一枚', + 打开作品: '作品を開く', + '打开作品可直接编辑;试试这个会填入需求,由主聊天继续创作。': + '作品を開くと直接編集できます。「試してみる」で依頼を入力し、メインチャットで続けられます。', + + 开始创作: '作成を始める', + 让想法成为图片: 'アイデアを画像に', + '打开图片精细编辑,或把想法交给 AI。': '画像を細かく編集するか、AI にアイデアを伝えましょう。', + 新建画布: '新規キャンバス', + '支持图片、PSD 和 .pcraft 工程': '画像、PSD、.pcraft に対応', + 从一个想法开始: 'アイデアから始める', + 商品图换背景: '商品写真の背景変更', + '保留商品,换成干净的展示背景': '商品を保ち、背景をすっきりと', + 照片调色: '写真の色調補正', + '自然肤色、暖色光线,保留细节': '自然な肌色と暖かい光、細部を保持', + 社交海报: 'SNS ポスター', + '从主题开始,完成配图和文字排版': 'テーマから画像と文字のレイアウトへ', + 试试这个: '試してみる', + 打开图片或选择示例: '画像を開くか例を選ぶ', + '描述需求,在主聊天发送': '要望をメインチャットで送信', + '查看结果,继续编辑和导出': '結果を確認、編集、書き出し', + '示例会填入需求,不会自动生成图片。AI 由 MiniMax Code 主聊天完成。': + '例を選ぶと依頼文が入力されます。自動生成は行いません。AI は MiniMax Code のメインチャットで実行します。', + '请先让我上传商品图,保留商品主体,把背景换成干净的浅色摄影棚,保持自然阴影。': + 'まず商品写真のアップロードを依頼してください。商品を保持し、背景を明るいスタジオに変え、自然な影を残してください。', + '请先让我上传照片,调整曝光和白平衡,让光线更温暖,保留自然肤色和细节。': + 'まず写真のアップロードを依頼してください。露出とホワイトバランスを調整し、自然な肌色と細部を保ちながら暖かい光にしてください。', + '帮我制作一张社交海报。请先询问主题、标题和发布平台,再确定尺寸、配图和文字排版。': + 'SNS ポスターを作ってください。まずテーマ、見出し、投稿先を確認し、サイズ、画像、文字レイアウトを決めてください。', + + 更多: 'その他', + 打开旧版工程: '旧形式のプロジェクトを開く', + 高级选项: '詳細設定', + 自动选择: '自動選択', + 复制到聊天: 'チャットにコピー', + 生成结果: '生成した画像', + 'Agent 图片已返回': 'Agent の画像が届きました', + 生成后的图片会显示在这里: '生成した画像がここに表示されます', + '读取结果失败,请点击重试': '結果を読み込めません。クリックして再試行してください。', + + 打开图片: '画像を開く', + 保存工程: 'プロジェクトを保存', + '导出 PNG': 'PNG を書き出す', + 'Agent 图片': 'Agent の画像', + 轻量工作台: '軽量エディター', + 使用说明: '使い方', + 关闭: '閉じる', + 语言: '言語', + 跟随浏览器: 'ブラウザーに合わせる', + '正在加载图片编辑器…': '画像エディターを読み込み中…', + 加载中: '読み込み中', + 'PhotoCraft 图片编辑器': 'PhotoCraft 画像エディター', + 'PhotoCraft 已就绪 · 图片在本机处理': + 'PhotoCraft の準備ができました · 画像は端末内で処理されます', + '引擎响应超时;请检查画面和任务记录,勿重复提交': + '応答がタイムアウトしました。再送信せず、画像とタスク履歴を確認してください。', + '编辑器忙,请稍后重试': 'エディターが処理中です。しばらくしてからお試しください。', + 'Agent 正在处理图片…': 'Agent が画像を処理中…', + 'Agent 已读取画面或导出结果': 'Agent が画像の読み取りまたは書き出しを完了しました', + 'Agent 操作已完成 · 可在编辑器中撤销': 'Agent の操作が完了しました · エディターで元に戻せます', + '画面已处理,但任务回执未确认;请检查画面,勿重复执行': + '画像は処理されましたが、完了確認がありません。再実行せず画像を確認してください。', + '已打开 {name}': '{name} を開きました', + '已导出 {format}': '{format} を書き出しました', + 尚未打开图片: '画像が開かれていません', + 请先打开图片: '先に画像を開いてください', + 等待返回: '結果を待っています', + 读取图片失败: '画像を読み込めませんでした', + 'Agent 图片已打开': 'Agent の画像を開きました', + '还没有图片任务。可以在右下角描述你的需求。': + '画像タスクはまだありません。右下の AI パネルにご要望を入力してください。', + 'AI 助手': 'AI アシスタント', + '打开 AI 助手': 'AI アシスタントを開く', + '收起 AI 助手': 'AI アシスタントを閉じる', + 'AI 修图助手': 'AI 画像アシスタント', + 还没有打开图片: '画像が開かれていません', + '当前工程 · {name}': '現在のプロジェクト · {name}', + '描述想法,或先打开一张图片': 'アイデアを入力するか、画像を開いてください', + 任务: 'タスク', + 'AI 任务类型': 'AI タスクの種類', + 编辑工程: 'プロジェクトを編集', + 生成图片: '画像を生成', + 修改图片: '画像を編集', + 'AI 修图需求': 'AI への編集依頼', + '想怎么改?比如:背景调暖,加一个白色标题…': + 'どのように編集しますか?例:背景を暖色にして白いタイトルを追加…', + 放入主聊天后发送: 'メインチャットから送信', + '复制到 MiniMax Code 聊天': 'MiniMax Code チャットにコピー', + '正在准备…': '準備中…', + '交给 Agent': 'Agent に依頼', + 生成需求: '依頼文を作成', + '已放入主聊天输入框,请在那里点击发送。': + 'メインチャットの入力欄に追加しました。そちらから送信してください。', + '需求已准备好,复制到 MiniMax Code 聊天中发送。': + '依頼文を作成しました。MiniMax Code チャットにコピーして送信してください。', + '给 Agent 的需求文本': 'Agent への依頼文', + '已复制,请粘贴到 MiniMax Code 聊天中发送。': + 'コピーしました。MiniMax Code チャットに貼り付けて送信してください。', + '无法自动复制,请选中文本手动复制。': + '自動コピーできませんでした。テキストを選択して手動でコピーしてください。', + 复制需求: '依頼文をコピー', + 切换语言失败: '言語を変更できませんでした', + '连接失败,请稍后重试': '接続に失敗しました。もう一度お試しください。', + '操作失败,请查看详细信息': '操作に失敗しました。詳細を確認してください。', + 返回工作台: 'エディターに戻る', + }, +}; +Object.assign(messages["en"], {"保存工程": "Save project", "恢复作品": "Recover artwork", "关闭": "Close", "暂无备份": "No backups yet", "自动备份失败,请保存工程文件": "Backup failed. Save a project file.", "恢复失败,请重试": "Recovery failed. Try again.", "读取会话失败,请重新打开应用": "Could not load the conversation. Reopen the app.", "会话已在其他窗口更新,请重新打开应用": "Conversation changed in another window. Reopen the app.", "会话保存失败,请保留当前页面": "Could not save the conversation. Keep this page open."}); +Object.assign(messages["zh-hant"], {"保存工程": "儲存專案", "恢复作品": "復原作品", "关闭": "關閉", "暂无备份": "暫無備份", "自动备份失败,请保存工程文件": "自動備份失敗,請儲存專案檔案", "恢复失败,请重试": "復原失敗,請重試", "读取会话失败,请重新打开应用": "讀取對話失敗,請重新開啟應用", "会话已在其他窗口更新,请重新打开应用": "對話已在其他視窗更新,請重新開啟應用", "会话保存失败,请保留当前页面": "對話儲存失敗,請保留目前頁面"}); +Object.assign(messages["ja"], {"保存工程": "プロジェクトを保存", "恢复作品": "作品を復元", "关闭": "閉じる", "暂无备份": "バックアップはありません", "自动备份失败,请保存工程文件": "バックアップに失敗しました。プロジェクトを保存してください。", "恢复失败,请重试": "復元に失敗しました。再試行してください。", "读取会话失败,请重新打开应用": "会話を読み込めません。アプリを開き直してください。", "会话已在其他窗口更新,请重新打开应用": "別のウィンドウで会話が更新されました。アプリを開き直してください。", "会话保存失败,请保留当前页面": "会話を保存できません。このページを閉じないでください。"}); +Object.assign(messages["en"], {"AI 连接暂不可用,请重新打开应用后再试。": "AI is temporarily unavailable. Reopen the app and try again.", "这段会话已不可用,请新建对话。": "This conversation is unavailable. Start a new conversation.", "AI 还在处理上一个请求,请稍后再试。": "AI is still working on the previous request. Try again later.", "当前应用无法使用 AI,请检查应用权限。": "AI is unavailable for this app. Check its permissions.", "新建对话": "New conversation"}); +Object.assign(messages["zh-hant"], {"AI 连接暂不可用,请重新打开应用后再试。": "AI 連線暫不可用,請重新開啟應用後再試。", "这段会话已不可用,请新建对话。": "這段對話已不可用,請建立新對話。", "AI 还在处理上一个请求,请稍后再试。": "AI 還在處理上一個請求,請稍後再試。", "当前应用无法使用 AI,请检查应用权限。": "目前應用無法使用 AI,請檢查應用權限。", "新建对话": "新增對話"}); +Object.assign(messages["ja"], {"AI 连接暂不可用,请重新打开应用后再试。": "AI に接続できません。アプリを開き直してください。", "这段会话已不可用,请新建对话。": "この会話は利用できません。新しい会話を開始してください。", "AI 还在处理上一个请求,请稍后再试。": "AI は前の依頼を処理中です。しばらくしてからお試しください。", "当前应用无法使用 AI,请检查应用权限。": "このアプリは AI を利用できません。権限を確認してください。", "新建对话": "新しい会話"}); +export const languages = [ + ['auto', '跟随浏览器'], + ['zh-hans', '简体中文'], + ['zh-hant', '繁體中文'], + ['en', 'English'], + ['ja', '日本語'], +]; +export function resolveLanguage(choice, browserLanguages = []) { + if (choice !== 'auto' && languages.some(([code]) => code === choice)) return choice; + for (const tag of browserLanguages) { + const code = tag.toLowerCase(); + if (code.startsWith('zh')) + return code.includes('hans') ? 'zh-hans' : /hant|tw|hk|mo/.test(code) ? 'zh-hant' : 'zh-hans'; + if (code.startsWith('ja')) return 'ja'; + if (code.startsWith('en')) return 'en'; + } + return 'en'; +} +let preference = 'auto', + locale = 'zh-hans'; +const listeners = new Set(); +export const subscribeLanguage = (fn) => { + listeners.add(fn); + return () => listeners.delete(fn); +}; +export const getLanguage = () => locale; +export const getPreference = () => preference; +export function setLanguage(choice, persist = true) { + preference = languages.some(([code]) => code === choice) ? choice : 'auto'; + locale = resolveLanguage(preference, navigator.languages || [navigator.language]); + document.documentElement.lang = { 'zh-hans': 'zh-CN', 'zh-hant': 'zh-TW', en: 'en', ja: 'ja' }[ + locale + ]; + if (persist) + try { + localStorage.setItem('minimax-photo.language', preference); + } catch {} + for (const fn of listeners) fn(); +} +export function initLanguage() { + let saved = 'auto'; + try { + saved = localStorage.getItem('minimax-photo.language') || 'auto'; + } catch {} + setLanguage(saved, false); +} +export function t(key, args = {}) { + const value = locale === 'zh-hans' ? key : (messages[locale]?.[key] ?? messages.en[key] ?? key); + return value.replace(/\{(\w+)\}/g, (all, k) => args[k] ?? all); +} + +Object.assign(messages["en"], { + "显示 AI 操作轨迹": "Show AI edit activity", + "已完成 · 画笔轨迹回放": "Done · Brush stroke replay", + "已完成 · 画布已更新": "Done · Canvas updated", + "AI 正在执行 {count} 步编辑…": "AI is applying {count} edits…", + "AI 正在编辑图片…": "AI is editing the image…", +}); + +Object.assign(messages["zh-hant"], { + "显示 AI 操作轨迹": "顯示 AI 操作軌跡", + "已完成 · 画笔轨迹回放": "已完成 · 畫筆軌跡回放", + "已完成 · 画布已更新": "已完成 · 畫布已更新", + "AI 正在执行 {count} 步编辑…": "AI 正在執行 {count} 步編輯…", + "AI 正在编辑图片…": "AI 正在編輯圖片…", +}); + +Object.assign(messages["ja"], { + "显示 AI 操作轨迹": "AI の編集動作を表示", + "已完成 · 画笔轨迹回放": "完了 · ブラシ軌跡の再生", + "已完成 · 画布已更新": "完了 · キャンバスを更新", + "AI 正在执行 {count} 步编辑…": "AI が {count} 件の編集を実行中…", + "AI 正在编辑图片…": "AI が画像を編集中…", +}); + +Object.assign(messages.en, { + '录制绘画过程': 'Record drawing process', + '停止录制': 'Stop recording', + '保存录制视频': 'Save recording', + '清除录制缓存': 'Clear recording buffer', + '清除尚未保存的录制视频?': 'Clear this recording? Save it first if you want to keep it.', + '录制已结束,可在更多菜单保存视频': 'Recording finished. Save the video from More.', + '正在录制编辑器画布,不会录到其他窗口': 'Recording the editor canvas only, not other windows.', + '录制失败': 'Recording failed', +}); +Object.assign(messages['zh-hant'], { + '录制绘画过程': '錄製繪畫過程', + '停止录制': '停止錄製', + '保存录制视频': '儲存錄製影片', + '清除录制缓存': '清除錄製暫存', + '清除尚未保存的录制视频?': '清除尚未儲存的錄製影片?', + '录制已结束,可在更多菜单保存视频': '錄製已結束,可在更多選單儲存影片', + '正在录制编辑器画布,不会录到其他窗口': '正在錄製編輯器畫布,不會錄到其他視窗', + '录制失败': '錄製失敗', +}); +Object.assign(messages.ja, { + '录制绘画过程': '描画の過程を録画', + '停止录制': '録画を停止', + '保存录制视频': '録画を保存', + '清除录制缓存': '録画データを消去', + '清除尚未保存的录制视频?': '未保存の録画を消去しますか?', + '录制已结束,可在更多菜单保存视频': '録画が終了しました。その他メニューから保存できます。', + '正在录制编辑器画布,不会录到其他窗口': 'エディターのキャンバスのみ録画中。他のウィンドウは含まれません。', + '录制失败': '録画に失敗しました', +}); diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photo-recording.js b/plugins/webguhui/minimax-photo/miniapp/client/photo-recording.js new file mode 100644 index 00000000..969b27c7 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photo-recording.js @@ -0,0 +1,69 @@ +// Records the editor's rendered canvas, never the desktop or other windows. +export function createCanvasRecording({ canvas, changed, failed }) { + let recorder, stream, chunks = [], bytes = 0, timer, blob; + let state = 'idle'; + const publish = () => changed(state); + const release = () => { + clearTimeout(timer); + stream?.getTracks().forEach(track => track.stop()); + stream = undefined; + }; + function stop() { + if (state !== 'recording') return; + state = 'stopping'; + publish(); + recorder.stop(); + } + return { + get pending() { return state !== 'idle'; }, + get state() { return state; }, + start() { + if (state !== 'idle') throw Error('Save the previous recording first'); + const source = canvas(); + if (!source?.captureStream || typeof MediaRecorder === 'undefined') + throw Error('Canvas recording is unavailable'); + try { + const mimeType = ['video/webm;codecs=vp9', 'video/webm;codecs=vp8', 'video/webm'] + .find(type => MediaRecorder.isTypeSupported(type)); + if (!mimeType) throw Error('WebM recording is unavailable'); + stream = source.captureStream(20); + recorder = new MediaRecorder(stream, { mimeType, videoBitsPerSecond: 1200000 }); + chunks = []; bytes = 0; + recorder.ondataavailable = ({ data }) => { + if (data.size) { chunks.push(data); bytes += data.size; } + // Keep a bounded recording in memory; the finished video stays available to save. + if (bytes >= 256 * 1024 * 1024) stop(); + }; + recorder.onerror = event => failed(event.error || Error('Recording failed')); + recorder.onstop = () => { + release(); + blob = new Blob(chunks, { type: recorder.mimeType }); + chunks = []; + state = blob.size ? 'ready' : 'idle'; + if (!blob.size) failed(Error('The recording is empty')); + publish(); + }; + recorder.start(1000); + state = 'recording'; publish(); + timer = setTimeout(stop, 60 * 60 * 1000); + } catch (error) { + release(); recorder = undefined; state = 'idle'; publish(); throw error; + } + }, + stop, + download() { + if (state !== 'ready') return; + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = 'MiniMax-Photo-process.webm'; + link.click(); + setTimeout(() => URL.revokeObjectURL(url), 60000); + // Keep the blob so a cancelled save can be retried. + }, + discard() { + if (state !== 'ready') return; + blob = undefined; recorder = undefined; state = 'idle'; publish(); + }, + }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photo-recovery.js b/plugins/webguhui/minimax-photo/miniapp/client/photo-recovery.js new file mode 100644 index 00000000..7b396b6a --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photo-recovery.js @@ -0,0 +1,52 @@ +import { t } from './photo-i18n.js'; +export function createRecovery({ call, status }) { + const documents = new Map(); + let saving = false, failed = false; + async function snapshot(state) { + if (saving || !state.document) return; + const docId = state.version.split(':')[0]; + let entry = documents.get(docId); + if (!entry) { entry = { id: 'document-' + crypto.randomUUID(), revision: 0 }; documents.set(docId, entry); } + if (entry.version === state.version) return; + saving = true; + try { + const result = await call('export', { format: 'pcraft' }, state.version); + const response = await fetch('/api/recovery/' + entry.id, { + method: 'POST', headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ revision: entry.revision, value: { name: state.document.name || 'MiniMax Photo', data: result.data } }), + }); + if (!response.ok) throw Error('save'); + const record = await response.json(); + entry.revision = record.revision; entry.version = state.version; failed = false; + } catch { failed = true; status('自动备份失败,请保存工程文件', {}, true); } + finally { saving = false; } + } + async function show() { + let dialog = document.querySelector('#recovery-dialog'); + if (dialog) dialog.remove(); + dialog = document.createElement('dialog'); dialog.id = 'recovery-dialog'; + const heading = document.createElement('h2'); heading.textContent = t('恢复作品'); + const close = document.createElement('button'); close.textContent = t('关闭'); close.onclick = () => dialog.close(); + dialog.append(heading, close); document.body.append(dialog); dialog.showModal(); + try { + const response = await fetch('/api/recovery'); if (!response.ok) throw Error('list'); + const { snapshots } = await response.json(); + if (!snapshots.length) { const p = document.createElement('p'); p.textContent = t('暂无备份'); dialog.append(p); } + for (const item of snapshots) { + const button = document.createElement('button'); button.textContent = item.name; + button.onclick = async () => { + button.disabled = true; + try { + const response = await fetch('/api/recovery/' + item.id); if (!response.ok) throw Error('read'); + const record = await response.json(); + const opened = await call('open', { name: record.value.name.replace(/\.pcraft$/i, '') + '.pcraft', data: record.value.data }); + documents.set(opened.state.version.split(':')[0], { id: item.id, revision: record.revision, version: opened.state.version }); + dialog.close(); + } catch { status('恢复失败,请重试', {}, true); button.disabled = false; } + }; + dialog.append(button); + } + } catch { const retry = document.createElement('button'); retry.textContent = t('读取结果失败,请点击重试'); retry.onclick = show; dialog.append(retry); } + } + return { snapshot, show, get pending() { return saving || failed; } }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photo.css b/plugins/webguhui/minimax-photo/miniapp/client/photo.css new file mode 100644 index 00000000..3bc7910d --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photo.css @@ -0,0 +1,707 @@ +body.photo-app { + display: flex; + flex-direction: column; + height: 100dvh; + overflow: hidden; + background: #202124; + color: #e6e6e8; + margin: 0; +} +.photo-header { + flex-wrap: nowrap; + min-height: 48px; + height: 48px; + flex-shrink: 0; + display: flex; + align-items: center; + gap: 12px; + padding: 0 16px; + border-bottom: 1px solid #393a3d; + background: #252629; +} +.photo-header strong { + font-size: 15px; + letter-spacing: -0.3px; +} +.photo-tag { + font-size: 11px; + color: #a6a7ad; +} +.photo-header nav { + flex-basis: auto; + margin-left: auto; + display: flex; + align-items: center; + gap: 8px; +} +.photo-header button, +.photo-header a, +#photo-results button { + font: inherit; + font-size: 12px; + color: inherit; + border: 1px solid #45464b; + border-radius: 6px; + padding: 5px 10px; + background: transparent; + text-decoration: none; + cursor: pointer; +} +.photo-header button:hover, +.photo-header a:hover { + background: #38393d; +} +.photo-main { + position: relative; + flex: 1; + min-height: 0; +} +#craft { + display: block; + width: 100%; + height: 100%; + border: 0; +} +#loading { + position: absolute; + inset: 0; + display: grid; + place-items: center; + background: #202124; + color: #a6a7ad; +} +#loading[hidden] { + display: none; +} + +#photo-status { + position: fixed; + bottom: 36px; + left: 16px; + max-width: min(520px, 80vw); + z-index: 60; + padding: 10px 14px; + background: #303136; + border: 1px solid #48494f; + border-radius: 8px; + font-size: 12px; + box-shadow: 0 4px 16px #0004; + pointer-events: none; +} +#photo-status[hidden] { + display: none; +} +.photo-app #agent-panel-root { + position: fixed; + inset: 0; + z-index: 30; + pointer-events: none; +} +.photo-app #agent-panel-root .agent-panel { + position: absolute; + left: auto; + right: 24px; + top: auto; + bottom: 24px; + transform: none; + width: 360px; + max-width: calc(100vw - 16px); + max-height: calc(100dvh - 104px); + height: auto; + overflow: auto; + border: 1px solid #45464b; + border-radius: 14px; + box-shadow: 0 12px 36px #0005; + padding: 14px; + pointer-events: auto; +} +.photo-app .agent-panel-heading { + cursor: grab; + touch-action: none; + user-select: none; +} +.photo-app .agent-panel-heading:active { + cursor: grabbing; +} +.photo-app .agent-panel-heading button { + cursor: pointer; +} +.photo-app .agent-launcher { + position: absolute; + left: auto; + right: 24px; + bottom: 24px; + transform: none; + pointer-events: auto; + border-radius: 24px; + background: #303136; + color: #d4d4d8; + border: 1px solid #45464b; + box-shadow: 0 4px 12px #0003; + padding: 8px 14px; +} +.photo-app .agent-results-area { + margin-top: 12px; + padding-top: 10px; +} +.photo-app .agent-results-area summary { + display: flex; + align-items: center; + gap: 8px; + cursor: pointer; + color: #a6a7ad; + font-size: 12px; +} +.photo-app .agent-panel form { + margin-top: 16px; +} +.agent-options { + margin-bottom: 12px; + font-size: 12px; + color: #a6a7ad; +} +.agent-options summary { + cursor: pointer; + padding: 4px 0; +} +.agent-options .agent-mode { + margin-top: 10px; +} +.agent-results-area { + margin-top: 24px; + padding-top: 16px; + border-top: 1px solid #393a3d; +} +#result-list { + font-size: 12px; + color: #a6a7ad; + margin-top: 12px; +} +#result-list > div { + display: flex; + align-items: center; + gap: 10px; + margin: 12px 0; +} +#result-list span { + flex: 1; + overflow-wrap: anywhere; +} +#result-list button { + flex-shrink: 0; + border: 1px solid #45464b; + border-radius: 6px; + padding: 6px 8px; + color: #eee; + background: #303136; + cursor: pointer; +} +#photo-actions { + display: flex; + align-items: center; + gap: 4px; +} +.photo-header #photo-actions button { + border: 0; + gap: 6px; +} +#photo-more { + position: relative; +} +#photo-more > summary { + list-style: none; + cursor: pointer; + padding: 6px 10px; + border-radius: 6px; + letter-spacing: 2px; +} +#photo-more > summary::-webkit-details-marker { + display: none; +} +#photo-more > summary:hover, +#photo-more[open] > summary { + background: #38393d; +} +.photo-more-content { + position: absolute; + top: 36px; + right: 0; + z-index: 50; + width: 240px; + padding: 8px; + background: #292a2e; + border: 1px solid #45464b; + border-radius: 8px; + box-shadow: 0 8px 24px #0005; +} +.photo-more-content label { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 8px; + font-size: 12px; +} +.photo-header .photo-more-content a { + display: block; + border: 0; + padding: 10px 8px; +} +#photo-language { + max-width: 150px; + background: #252629; + color: #ededed; + border-color: #45464b; + font-size: 12px; +} +@media (max-width: 900px) { + .photo-app #agent-panel-root .agent-panel, + .photo-app .agent-launcher { + left: auto; + right: 16px; + } + .photo-header #photo-actions button span { + display: none; + } + .photo-header nav { + gap: 4px; + } +} + +#photo-welcome { + position: absolute; + inset: 0; + overflow: auto; + background: #202124; + z-index: 2; +} +#photo-welcome[hidden] { + display: none; +} +.welcome-content { + max-width: 940px; + margin: 0 auto; + padding: 64px 40px 100px; + color: #e6e6e8; +} +.welcome-intro { + text-align: center; +} +.welcome-eyebrow { + display: inline-flex; + align-items: center; + gap: 8px; + color: #b2b3ba; + font-size: 13px; +} +.welcome-intro h1 { + font-size: 34px; + line-height: 1.3; + letter-spacing: -1px; + margin: 18px 0 12px; + font-weight: 600; +} +.welcome-intro p { + font-size: 14px; + color: #a6a7ad; + margin: 0 0 24px; +} +.welcome-actions { + display: flex; + gap: 12px; + justify-content: center; + margin-bottom: 12px; +} +.welcome-actions button { + gap: 8px; +} +.welcome-intro small { + font-size: 12px; + color: #85868e; +} +.welcome-section-title { + font-size: 13px; + color: #a6a7ad; + margin: 44px 0 14px; +} +.welcome-cases { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 16px; +} +.welcome-case { + display: flex; + flex-direction: column; + text-align: left; + padding: 16px; + border: 1px solid #38393f; + border-radius: 12px; + background: #27282c; + color: inherit; + cursor: pointer; + gap: 10px; +} +.welcome-case:hover { + border-color: #777984; + background: #2e2f34; +} +.welcome-case:focus-visible { + outline: 2px solid #a0a7ff; + outline-offset: 3px; +} +.welcome-case:disabled { + opacity: 0.5; + cursor: wait; +} +.welcome-case-art { + height: 96px; + display: grid; + place-items: center; + width: 100%; + border-radius: 7px; + background: linear-gradient(135deg, #303a39, #26302f); + color: #a7c9be; +} +.portrait .welcome-case-art { + background: linear-gradient(135deg, #443a30, #312e2c); + color: #d4b795; +} +.poster .welcome-case-art { + background: linear-gradient(135deg, #3b3549, #2c2a36); + color: #bfb2d9; +} +.welcome-case strong { + font-size: 15px; + font-weight: 500; +} +.welcome-case > span:not(.welcome-case-art) { + font-size: 12px; + color: #a6a7ad; + line-height: 1.6; +} +.welcome-case .welcome-case-cta { + margin-top: auto; + padding-top: 8px; + color: #d2d3da; +} +.welcome-steps { + display: flex; + justify-content: space-between; + gap: 16px; + margin-top: 30px; + font-size: 12px; + color: #b2b3ba; +} +.welcome-steps span { + display: flex; + gap: 8px; + align-items: center; +} +.welcome-steps b { + display: grid; + place-items: center; + border: 1px solid #45464b; + border-radius: 50%; + width: 22px; + height: 22px; + font-size: 11px; + font-weight: 400; + flex-shrink: 0; +} +.welcome-note { + text-align: center; + color: #85868e; + font-size: 11px; + margin-top: 20px; +} +@media (max-width: 700px) { + .welcome-content { + padding: 30px 20px 100px; + } + .welcome-cases { + grid-template-columns: 1fr; + } + .welcome-case-art { + height: 60px; + } + .welcome-steps { + flex-direction: column; + } + .welcome-intro h1 { + font-size: 28px; + } +} + +.welcome-content { + max-width: 1120px; + padding-top: 48px; +} +.welcome-section-title { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} +.welcome-section-title > span:last-child { + font-size: 11px; + color: #85868e; +} +.showcase-cases .welcome-case { + padding: 0; + overflow: hidden; + gap: 0; + cursor: default; +} +.showcase-image { + display: block; + border: 0; + padding: 0; + width: 100%; + aspect-ratio: 4/5; + background: #303136; + overflow: hidden; + cursor: pointer; +} +.showcase-image img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; + transition: transform 0.2s; +} +.showcase-image:hover img { + transform: scale(1.025); +} +.showcase-caption { + padding: 16px; +} +.showcase-caption p { + font-size: 12px; + color: #a6a7ad; + line-height: 1.6; + margin: 8px 0 14px; +} +.showcase-actions { + display: flex; + gap: 8px; + flex-wrap: wrap; +} +.showcase-actions button { + gap: 6px; +} +@media (prefers-reduced-motion: reduce) { + .showcase-image img { + transition: none; + } +} + +.photo-app .agent-explanation { + font-size: 12px; + line-height: 1.7; + color: #a6a7ad; + margin: 10px 0; +} +.photo-app .agent-context { + font-size: 12px; + color: #c5c6cd; + margin: 10px 0 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.photo-app .agent-suggestions { + display: flex; + gap: 8px; + margin-bottom: 12px; + flex-wrap: wrap; +} +.photo-app .agent-results-area[hidden] { + display: none; +} + +.agent-copy-details summary { + cursor: pointer; + font-size: 12px; + color: #a6a7ad; + margin-bottom: 10px; +} +.photo-ai-reply { + white-space: normal; + overflow-wrap: anywhere; + max-height: 260px; + overflow: auto; + font-size: 13px; + line-height: 1.7; + margin: 12px 0; + user-select: text; +} +.photo-ai-approval { + border: 1px solid #555; + border-radius: 8px; + padding: 10px; + margin: 10px 0; + font-size: 12px; +} +.photo-ai-approval button { + margin: 8px 8px 0 0; +} +.photo-ai-approval pre, +.agent-panel fieldset { + overflow-wrap: anywhere; + white-space: pre-wrap; + max-width: 100%; +} +.photo-ai-option { + display: flex; + gap: 8px; + align-items: baseline; + margin: 8px 0; + flex-wrap: wrap; +} +.photo-ai-option small { + color: #aaa; +} + +.photo-ai-results { + margin: 12px 0; +} +.photo-ai-results summary { + cursor: pointer; +} +.photo-ai-results #result-list { + display: grid; + gap: 12px; + max-height: 240px; + overflow: auto; + margin-top: 8px; +} +.photo-ai-results #result-list > div { + display: grid; + grid-template-columns: 64px 1fr; + gap: 8px; + align-items: center; +} +.photo-ai-results img { + width: 64px; + height: 64px; + object-fit: cover; + border-radius: 8px; +} +.photo-ai-results span { + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} +.photo-ai-results button { + grid-column: 2; + justify-self: start; +} + +#recovery-dialog { + color: #ededed; + background: #252629; + border: 1px solid #45464b; + border-radius: 14px; + width: min(440px, calc(100vw - 32px)); + max-height: 70dvh; + overflow: auto; + padding: 20px; +} +#recovery-dialog::backdrop { + background: #0008; +} +#recovery-dialog button { + display: block; + margin: 10px 0; + max-width: 100%; + overflow-wrap: anywhere; +} +@media (max-width: 520px) { + .photo-app #agent-panel-root .agent-panel { + left: 8px !important; + right: 8px !important; + top: auto !important; + bottom: 8px !important; + width: auto; + max-height: calc(100dvh - 72px); + } + .photo-app .agent-panel-heading { + cursor: default; + } + .photo-ai-reply { + max-height: 28dvh; + overflow: auto; + } +} + +.photo-activity { + position: absolute; + inset: 0; + pointer-events: none; + z-index: 8; + overflow: hidden; +} +.photo-activity[hidden] { + display: none; +} +.photo-activity svg { + width: 100%; + height: 100%; + display: block; +} +.photo-activity-trail { + stroke: #60a5fa; + stroke-width: 3; + stroke-linecap: round; + stroke-linejoin: round; + vector-effect: non-scaling-stroke; +} +.photo-activity-area { + fill: #60a5fa10; + stroke: #93c5fd; + stroke-width: 1.5; + stroke-dasharray: 5 5; + vector-effect: non-scaling-stroke; +} +.photo-activity-tip { + fill: #fff; + stroke: #3b82f6; + stroke-width: 2; + vector-effect: non-scaling-stroke; +} +.photo-activity-label { + position: absolute; + top: 10px; + left: 50%; + transform: translateX(-50%); + padding: 6px 12px; + border: 1px solid #ffffff28; + border-radius: 8px; + background: #18181be8; + color: #e4e4e7; + font: inherit; + white-space: nowrap; +} +#photo-show-activity { + width: auto; +} + +#photo-more label:has(#photo-show-activity) { justify-content: flex-start; gap: 8px; } + +.photo-ai-reply p { margin: 0 0 0.65em; } +.photo-ai-reply h1, .photo-ai-reply h2, .photo-ai-reply h3, +.photo-ai-reply h4, .photo-ai-reply h5, .photo-ai-reply h6 { + font-size: inherit; font-weight: 600; margin: 0.9em 0 0.4em; +} +.photo-ai-reply ul, .photo-ai-reply ol { padding-left: 1.5em; margin: 0.5em 0; } +.photo-ai-reply ul { list-style: disc; } +.photo-ai-reply ol { list-style: decimal; } +.photo-ai-reply pre { white-space: pre; overflow: auto; padding: 0.65em; background: #16171a; border-radius: 6px; } +.photo-ai-reply code { font-family: monospace; } +.photo-ai-reply a { text-decoration: underline; } +.photo-ai-table { overflow-x: auto; margin: 0.65em 0; } +.photo-ai-table table { border-collapse: collapse; width: 100%; } +.photo-ai-table th, .photo-ai-table td { border: 1px solid #484a50; padding: 0.35em 0.6em; text-align: left; } +.photo-ai-table th { font-weight: 600; } +.photo-ai-reply > :first-child, .photo-ai-reply > :first-child > :first-child { margin-top: 0; } diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photo.html b/plugins/webguhui/minimax-photo/miniapp/client/photo.html new file mode 100644 index 00000000..cb54d856 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photo.html @@ -0,0 +1,49 @@ + + + + + + MiniMax Photo + + + + + +
+ MiniMax Photo + +
+
+ +
正在加载图片编辑器…
+
+ + + + + diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photo.js b/plugins/webguhui/minimax-photo/miniapp/client/photo.js new file mode 100644 index 00000000..6f8ea351 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photo.js @@ -0,0 +1,468 @@ +import { createActivity } from './photo-activity.js'; +import { createRecovery } from './photo-recovery.js'; +import { createCanvasRecording } from './photo-recording.js'; +import { + t, + initLanguage, + setLanguage, + getLanguage, + getPreference, + languages, + subscribeLanguage, + resolveLanguage, +} from './photo-i18n.js'; +initLanguage(); +import { mountPhotoAssistant, mountPhotoToolbar, mountPhotoWelcome } from './workbench-ui.js'; +const frame = document.querySelector('#craft'), + statusEl = document.querySelector('#photo-status'); +const token = crypto.randomUUID(), + editorId = crypto.randomUUID(), + pending = new Map(); +// Lets the host's page inspection identify this exact instance, even when +// several conversations have an editor from the same plugin open. +document.documentElement.dataset.photoEditorId = editorId; +const pageState = () => ({ visibility: document.visibilityState, focused: document.hasFocus() }); +let current = { version: 'empty', document: null }, + running = false, + events, + panel, + prepared; +let statusTimer, + lastStatus = ['', {}], + reporting = false, + ready = false; +const status = (text, args = {}, persist = false) => { + lastStatus = [text, args, persist]; + statusEl.textContent = t(text, args); + statusEl.hidden = !text; + clearTimeout(statusTimer); + if (text && !persist) + statusTimer = setTimeout(() => { + statusEl.hidden = true; + lastStatus = ['', {}]; + }, 6000); +}; +const languageSelect = document.querySelector('#photo-language'); +function translatePage() { + document.querySelectorAll('[data-i18n]').forEach((el) => (el.textContent = t(el.dataset.i18n))); + frame.title = 'MiniMax Photo'; + languageSelect.setAttribute('aria-label', t('语言')); + languageSelect.replaceChildren( + ...languages.map(([code, label]) => new Option(code === 'auto' ? t(label) : label, code)), + ); + languageSelect.value = getPreference(); + status(...lastStatus); + panel?.refresh(); + const summary = document.querySelector('#photo-more summary'); + summary.setAttribute('aria-label', t('更多')); + summary.title = t('更多'); +} +subscribeLanguage(translatePage); +translatePage(); +languageSelect.onchange = async () => { + const choice = languageSelect.value; + languageSelect.disabled = true; + try { + if (ready) await call('language', { code: resolveChoice(choice) }); + setLanguage(choice); + } catch (error) { + languageSelect.value = getPreference(); + status(t('切换语言失败') + ': ' + error.message); + } finally { + languageSelect.disabled = false; + } +}; +function resolveChoice(choice) { + return resolveLanguage(choice, navigator.languages || [navigator.language]); +} +window.addEventListener('languagechange', () => { + if (getPreference() === 'auto') void languageSelect.onchange(); +}); +function call(method, args = {}, expectedVersion) { + const id = crypto.randomUUID(); + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + pending.delete(id); + reject( + Object.assign(Error(t('引擎响应超时;请检查画面和任务记录,勿重复提交')), { + unknown: true, + }), + ); + }, 110000); + pending.set(id, { resolve, reject, timeout }); + frame.contentWindow.postMessage( + { type: 'photo-request', token, id, method, args, expectedVersion }, + '*', + ); + }); +} +async function post(path, body) { + const r = await fetch(path, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body), + }); + const v = await r.json(); + if (!r.ok) throw Error(v.error); + return v; +} +const activity = createActivity({ frame, call }); +const recovery = createRecovery({ call, status }); +const recordStart = document.querySelector('#photo-record'); +const recordStop = document.querySelector('#photo-record-stop'); +const recordSave = document.querySelector('#photo-record-save'); +const recordDiscard = document.querySelector('#photo-record-discard'); +const recording = createCanvasRecording({ + canvas: () => frame.contentDocument?.querySelector('#photocraft_canvas'), + changed: state => { + recordStart.hidden = state !== 'idle'; + recordStop.hidden = !['recording', 'stopping'].includes(state); + recordStop.disabled = state === 'stopping'; + recordSave.hidden = recordDiscard.hidden = state !== 'ready'; + if (state === 'ready') status('录制已结束,可在更多菜单保存视频'); + }, + failed: error => status(t('录制失败') + ': ' + error.message), +}); +recordStart.onclick = () => { + try { + recording.start(); + document.querySelector('#photo-more').open = false; + status('正在录制编辑器画布,不会录到其他窗口'); + } catch (error) { status(t('录制失败') + ': ' + error.message); } +}; +recordStop.onclick = () => recording.stop(); +recordSave.onclick = () => recording.download(); +recordDiscard.onclick = () => { + if (confirm(t('清除尚未保存的录制视频?'))) recording.discard(); +}; +document.querySelector('#photo-recover').onclick = () => recovery.show(); +document.querySelector('#photo-save').onclick = () => exportPhoto('pcraft'); +window.addEventListener('beforeunload', (event) => { + if (recovery.pending || running || recording.pending) { event.preventDefault(); event.returnValue = ''; } +}); +async function report() { + if (reporting) return; + reporting = true; + try { + current = await call('inspect'); + await post('/api/editor/register', { editorId, engine: 'photocraft', ...current, page: pageState() }); + if (!running) await recovery.snapshot(current); + document.querySelector('#photo-save').hidden = !current.document; + panel?.refresh(); + welcome.refresh({ ready, hasDocument: !!current.document }); + toolbar.refresh(!!current.document); + recordStart.disabled = !ready; + frame.inert = running || !current.document; + } finally { + reporting = false; + } +} +const emptyPNG = () => { + const c = document.createElement('canvas'); + c.width = c.height = 1; + return c.toDataURL(); +}; +async function job(jobId) { + let j, + applied = false, + ownsLock = false, + before; + try { + j = await post(`/api/editor/${editorId}/claim`, { jobId }); + if (running) throw Error(t('编辑器忙,请稍后重试')); + running = true; + ownsLock = true; + frame.inert = true; + document.activeElement?.blur(); + activity.clear(); + before = await call('inspect'); + status( + j.options.method === 'batch' ? 'AI 正在执行 {count} 步编辑…' : 'AI 正在编辑图片…', + { count: Array.isArray(j.options.args) ? j.options.args.length : 1 }, + true, + ); + const value = await call(j.options.method, j.options.args, j.expectedVersion); + applied = true; + current = await call('inspect'); + const preview = current.document + ? 'data:image/png;base64,' + (await call('preview')).data + : emptyPNG(); + const data = value?.data; + if (data) delete value.data; + const result = { value, state: current }; + await post(`/api/editor/${editorId}/finish`, { + jobId, + claim: j.claim, + preview, + result, + craftExport: + j.options.method === 'export' + ? { format: j.options.args?.format || 'png', data } + : undefined, + }); + await post(`/api/editor/${editorId}/ack`, { jobId, claim: j.claim, version: current.version }); + status( + ['commands', 'preview', 'export'].includes(j.options.method) + ? 'Agent 已读取画面或导出结果' + : 'Agent 操作已完成 · 可在编辑器中撤销', + ); + } catch (error) { + if (j && !applied && !error.unknown) + await post(`/api/editor/${editorId}/finish`, { + jobId, + claim: j.claim, + error: error.message, + }).catch(() => {}); + status( + applied ? '画面已处理,但任务回执未确认;请检查画面,勿重复执行' : error.message, + {}, + true, + ); + } finally { + if (ownsLock) { + running = false; + frame.inert = false; + } + await report().catch(() => {}); + if (ownsLock && applied) void activity.completed(j.options.method, j.options.args, before); + } +} +window.addEventListener('message', async (e) => { + if (e.source !== frame.contentWindow) return; + if (e.data?.type === 'photo-response' && e.data.token === token) { + const p = pending.get(e.data.id); + if (!p) return; + clearTimeout(p.timeout); + pending.delete(e.data.id); + e.data.error ? p.reject(Error(e.data.error)) : p.resolve(e.data.value); + } + if (e.data?.type === 'photo-failed') { + status(e.data.error, {}, true); + document.querySelector('#loading').textContent = e.data.error; + } + if (e.data?.type === 'photo-ready') { + try { + await call('language', { code: getLanguage() }); + ready = true; + document.querySelector('#loading').hidden = true; + await report(); + events = new EventSource(`/api/editor/${editorId}/events`); + events.addEventListener('command', (e) => void job(JSON.parse(e.data).jobId)); + status(''); + } catch (error) { + status(error.message, {}, true); + } + } +}); +setInterval(() => { + if (!document.querySelector('#loading').hidden) return; + if (running && current) { + // Keep the connection alive during long, visibly paced drawing jobs. + // register ignores document/version changes while a job owns this editor. + post('/api/editor/register', { editorId, engine: 'photocraft', ...current, page: pageState() }).catch(() => {}); + } else report().catch(() => {}); +}, 3000); +document.addEventListener('visibilitychange', () => { + if (ready) post('/api/editor/register', { + editorId, engine: 'photocraft', ...current, page: pageState(), + }).catch(() => {}); +}); +window.addEventListener('pagehide', () => events?.close(), { once: true }); +async function action(fn) { + activity.clear(); + if (running) return; + running = true; + try { + await fn(); + await report(); + } catch (e) { + status(e.message, {}, true); + } finally { + running = false; + } +} +function download(data, name) { + const bytes = Uint8Array.from(atob(data), (c) => c.charCodeAt(0)); + const url = URL.createObjectURL(new Blob([bytes])); + const a = document.createElement('a'); + a.href = url; + a.download = name; + a.click(); + setTimeout(() => URL.revokeObjectURL(url), 10000); +} +const fileData = (file) => + new Promise((ok, no) => { + const r = new FileReader(); + r.onload = () => ok(r.result.split(',')[1]); + r.onerror = no; + r.readAsDataURL(file); + }); +document.querySelector('#photo-file').onchange = (e) => + void action(async () => { + const f = e.target.files[0]; + if (f) { + await call('open', { name: f.name, data: await fileData(f) }); + status('已打开 {name}', { name: f.name }); + } + e.target.value = ''; + }); +const exportPhoto = (format) => + void action(async () => { + const v = await call('export', { format }); + download(v.data, (current.document?.name || 'MiniMax Photo').replace(/\.(pcraft|png|jpe?g|webp|psd)$/i, '') + '.' + format); + status('已导出 {format}', { format: format.toUpperCase() }); + }); +panel = mountPhotoAssistant({ + dock: true, + showResults: () => showResults(), + context: () => ({ + name: current.document?.name || '', + supported: typeof window.mcode?.miniapp?.message?.append === 'function', + }), + prepare: async (mode, request) => { + if (!ready) throw Error(t('正在加载图片编辑器…')); + let text; + if (mode === 'workbench') + text = `请在 MiniMax Photo 的 PhotoCraft 编辑器完成:${request}\neditorId: ${editorId}。先 editor_inspect,再 photo_call(method="commands",args={filter:"关键词"}) 查询命令和参数;editor_job 读取结果。可用 editor_run_code:await editor.commands({filter})、execute({command,params})、edit([{command,params}])、preview()、create({width,height,name})、export({format})。每次调用逐个 await;结果在 .result.value,状态在 .result.state。用真实图层 ID;document.pixel 命令可读像素。每批 edit 整体提交,一次撤销;整段脚本不回滚。使用 editor_code_result 查询结果。版本冲突或中断先检查,禁止换编号盲目重试。`; + else { + if (mode === 'edit' && !current.document) throw Error(t('请先打开图片')); + const key = JSON.stringify([mode, request, current.version]); + if (prepared?.key !== key) { + const reference = + mode === 'edit' || (mode === 'auto' && current.document) + ? 'data:image/png;base64,' + (await call('preview')).data + : undefined; + const r = await post('/api/agent/requests', { + mode: mode === 'auto' ? (current.document ? 'edit' : 'generate') : mode, + prompt: request, + name: current.document?.name || t('Agent 图片'), + reference, + }); + prepared = { key, id: r.id }; + } + text = `请用当前 MiniMax Code Agent 提供的生图/改图能力完成图片任务 ${prepared.id}:${request}。先 get_image_request 读取任务与参考图,再用宿主提供的模型生成 PNG,最后 submit_image_result 提交同一 requestId 和 imagePath。没有模型工具时请明确说明,不要假装生成成功。结果在 Mini App 的 AI 助手“生成结果”中打开。`; + } + if (getLanguage() !== 'zh-hans') { + const instructions = { + en: [ + 'Please respond in English. Request:', + 'Inspect the editor, discover exact commands and parameters, then edit. Await each tool call in order. Each edit batch is atomic; the whole script is not. Check the original task after a conflict or unknown result; do not blindly retry.', + 'Read the image task, use the host image model and return a PNG with the same requestId. If no model is available, explain the limitation.', + ], + 'zh-hant': [ + '請使用繁體中文回覆。需求:', + '先讀取編輯器狀態並查詢命令參數,再執行編輯。每次工具呼叫必須依序 await。每批 edit 可整體復原;整段腳本不會整體回復。版本衝突或結果不明時請查詢原任務,勿盲目重試。', + '先讀取圖片任務,使用宿主提供的模型,再以相同 requestId 回傳 PNG。沒有可用模型時請明確說明。', + ], + ja: [ + '日本語で回答してください。依頼:', + '先にエディターの状態と命令の引数を確認してから編集してください。各ツールを順番に await してください。edit の各バッチは一括で反映されますが、スクリプト全体は一括で取り消せません。競合や結果不明の場合は元のタスクを確認し、むやみに再実行しないでください。', + '画像タスクを読み取り、ホストの画像モデルを使用して、同じ requestId で PNG を返してください。モデルが利用できない場合は、その制限を説明してください。', + ], + }[getLanguage()]; + text = + `${instructions[0]} ${request}\neditorId: ${editorId}\n` + + (mode === 'workbench' + ? `${instructions[1]}\neditor_inspect → photo_call(method="commands", args={filter:"…"}) → photo_call / editor_run_code → editor_code_result / editor_job.\nawait editor.commands({filter}); await editor.execute({command,params}); await editor.edit([{command,params}]); await editor.preview(); await editor.create({width,height,name}); await editor.export({format});` + : `${instructions[2]}\nrequestId: ${prepared.id}\nget_image_request → submit_image_result({requestId,imagePath})`); + } + if (mode === 'auto') + text = `\nAutomatically choose image generation/editing or direct editor tools based on the user's request. For direct editing, first editor_inspect(editorId="${editorId}"), then photo_call commands to discover parameters. Use editor_run_code for loops and atomic edit batches; query editor_code_result and editor_job. For model-generated images, first get_image_request(requestId="${prepared.id}"), use an available host image model, save its result as a local PNG, then REQUIRED: submit_image_result({requestId:"${prepared.id}",imagePath:localPngPath}). Wait for successful submission before reporting completion. This publishes the image to the Mini App result list; the user opens it there. Do not import the generated file through PhotoCraft file commands, clipboard, shell-driven UI, or browser automation. The image-request flow may be skipped ONLY for direct editor operations that do not generate an image with a model. Preserve original dimensions and content unless the user requests cropping or removal. Never silently crop a generated image. User request: ${request}. If intent is unclear, ask first. Respond in ${getLanguage()}.`; + return text; + }, +}); +const showResults = async () => { + try { + const r = await fetch('/api/agent/requests'); + if (!r.ok) throw Error('results'); + const { requests } = await r.json(); + const list = document.querySelector('#result-list'); + if (!list) return; + list.replaceChildren(); + list.closest('details').hidden = !requests.some((item) => item.status === 'ready'); + for (const item of requests.filter((item) => item.status === 'ready')) { + const row = document.createElement('div'), + label = document.createElement('span'); + const thumbnail = document.createElement('img'); + thumbnail.src = `/api/agent/requests/${item.id}/result`; + thumbnail.alt = item.prompt; + thumbnail.loading = 'lazy'; + label.textContent = item.prompt; + row.append(thumbnail, label); + const b = document.createElement('button'); + b.textContent = item.status === 'ready' ? t('打开图片') : t('等待返回'); + b.disabled = item.status !== 'ready'; + b.onclick = () => + void action(async () => { + const r = await fetch(`/api/agent/requests/${item.id}/result`); + if (!r.ok) throw Error(t('读取图片失败')); + await call('open', { + name: item.name.replace(/\.(png|jpe?g|webp)$/i, '') + '.png', + data: await fileData(await r.blob()), + }); + + status('Agent 图片已打开'); + }); + row.append(b); + list.append(row); + } + if (!list.childElementCount) list.textContent = t('生成后的图片会显示在这里'); + } catch { + const list = document.querySelector('#result-list'); + if (list) { list.closest('details').hidden = false; const retry = document.createElement('button'); retry.textContent = t('读取结果失败,请点击重试'); retry.onclick = showResults; list.replaceChildren(retry); } + } +}; + +const toolbar = mountPhotoToolbar({ + export: () => exportPhoto('png'), +}); + +const more = document.querySelector('#photo-more'); +more.addEventListener('keydown', (event) => { + if (event.key === 'Escape') { + more.open = false; + more.querySelector('summary').focus(); + event.stopPropagation(); + } +}); +document.addEventListener('pointerdown', (event) => { + if (more.open && !more.contains(event.target)) more.open = false; +}); +const imageEvents = new EventSource('/api/agent/events'); +imageEvents.addEventListener('result', () => { + status('Agent 图片已返回'); + if (document.querySelector('#result-list')) void showResults(); +}); +window.addEventListener('pagehide', () => imageEvents.close(), { once: true }); + +const welcome = mountPhotoWelcome({ + openShowcase: (id) => + void action(async () => { + if (!['product', 'portrait', 'poster'].includes(id)) return; + const response = await fetch('/showcase/' + id + '.webp'); + if (!response.ok) throw Error(t('读取图片失败')); + await call('open', { + name: 'MiniMax Photo · ' + id + '.webp', + data: await fileData(await response.blob()), + }); + }), + open: () => document.querySelector('#photo-file').click(), + create: () => + void action(async () => { + await call('execute', { + command: 'file.new', + params: { width: 1600, height: 1000, name: t('新建画布'), background: '#ffffff' }, + }); + }), + choose: (id) => + panel.compose( + t( + { + product: '请先让我上传商品图,保留商品主体,把背景换成干净的浅色摄影棚,保持自然阴影。', + portrait: '请先让我上传照片,调整曝光和白平衡,让光线更温暖,保留自然肤色和细节。', + poster: + '帮我制作一张社交海报。请先询问主题、标题和发布平台,再确定尺寸、配图和文字排版。', + }[id], + ), + ), +}); diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photocraft/cjk-ui.otf b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/cjk-ui.otf new file mode 100644 index 00000000..4f4d34ee Binary files /dev/null and b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/cjk-ui.otf differ diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photocraft/draw-path.js b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/draw-path.js new file mode 100644 index 00000000..6cae7b02 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/draw-path.js @@ -0,0 +1,67 @@ +// SVG-style absolute curve commands, converted to actual brush samples. +// One path is one continuous stroke; use another stroke for a disconnected path. +export function pathPoints(path, pressure = 1) { + if (!Array.isArray(path) || !path.length || path.length > 128) + throw Error('path requires 1..128 M/L/Q/C/Z commands'); + if (!Number.isFinite(pressure) || pressure < 0 || pressure > 1) + throw Error('pressure must be between 0 and 1'); + const points = []; + let current, start; + const append = (p) => { + if (points.length >= 4096) throw Error('path exceeds 4096 samples; split into strokes'); + points.push([p[0], p[1], pressure]); + current = p; + }; + for (const row of path) { + const length = { M: 3, L: 3, Q: 5, C: 7, Z: 1 }[row?.[0]]; + if (!Array.isArray(row) || row.length !== length || !row.slice(1).every(Number.isFinite)) + throw Error('Use absolute M x y, L x y, Q cx cy x y, C c1x c1y c2x c2y x y, Z'); + const [kind, ...v] = row; + if (kind === 'M') { + if (start) throw Error('One M per stroke; use separate strokes for disconnected paths'); + start = v; + append(v); + continue; + } + if (!current) throw Error('path must start with M'); + if (kind === 'L' || kind === 'Z') { append(kind === 'Z' ? start : v); continue; } + const controls = [current]; + for (let i = 0; i < v.length; i += 2) controls.push(v.slice(i, i + 2)); + const lengthPx = controls.slice(1).reduce((n, p, i) => n + Math.hypot(p[0]-controls[i][0],p[1]-controls[i][1]), 0); + const steps = Math.max(2, Math.min(1024, Math.ceil(lengthPx / 3))); + for (let i = 1; i <= steps; i++) { + const t = i / steps; + let work = controls.map(p => [...p]); + while (work.length > 1) work = work.slice(1).map((p, j) => [ + work[j][0] * (1-t) + p[0] * t, work[j][1] * (1-t) + p[1] * t, + ]); + append(work[0]); + } + } + return points; +} + +export function brushParameters(stroke) { + if (!stroke || typeof stroke !== 'object') throw Error('Each stroke must be an object'); + if (stroke.path !== undefined && stroke.points !== undefined) + throw Error('Choose path or points, not both'); + const { path, pressure, ...params } = stroke; + if (pressure !== undefined && (!Number.isFinite(pressure) || pressure < 0 || pressure > 1)) + throw Error('pressure must be between 0 and 1'); + if (path !== undefined) params.points = pathPoints(path, pressure); + if (!Array.isArray(params.points) || !params.points.length) + throw Error('Each stroke requires points or a path'); + if (path === undefined && pressure !== undefined) { + params.points = params.points.map(point => { + if (Array.isArray(point)) { + const sample = [...point]; + if (sample[2] == null) sample[2] = pressure; + return sample; + } + if (point && typeof point === 'object') + return { ...point, pressure: point.pressure ?? pressure }; + return point; + }); + } + return params; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photocraft/draw.js b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/draw.js new file mode 100644 index 00000000..900f3957 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/draw.js @@ -0,0 +1,26 @@ +import { brushParameters } from './draw-path.js'; +// Each stroke is an actual engine edit. Never simulate progress over a finished image. +export async function drawStrokes(args, expectedVersion, call, wait = ms => new Promise(r => setTimeout(r, ms))) { + const { strokes, intervalMs = 550 } = args || {}; + if (!Array.isArray(strokes) || strokes.length < 1 || strokes.length > 96) + throw Error(`draw requires 1..96 strokes; received ${strokes?.length}. Split the array with strokes.slice(i, i + 96).`); + if (!Number.isFinite(intervalMs) || intervalMs < 100 || intervalMs > 600) + throw Error('intervalMs must be between 100 and 600'); + // Validate and flatten all geometry before applying the first stroke. + const prepared = strokes.map(brushParameters); + let state = await call('inspect'); + if (state.version !== expectedVersion) throw Error('document changed; inspect again'); + let completed = 0; + try { + for (const params of prepared) { + const result = await call('execute', { command: 'paint.stroke', params }, state.version); + state = result.state; + completed++; + // Allow the WASM canvas to render before the next real stroke is submitted. + await wait(intervalMs); + } + } catch (error) { + throw Error(`draw stopped after ${completed}/${strokes.length} strokes; completed strokes remain. ${error}`); + } + return { value: { completed }, state }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photocraft/frame.css b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/frame.css new file mode 100644 index 00000000..98b7d0f5 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/frame.css @@ -0,0 +1 @@ +html,body{margin:0;width:100%;height:100%;overflow:hidden;background:#202124}canvas{width:100%;height:100%;display:block;touch-action:none} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photocraft/frame.js b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/frame.js new file mode 100644 index 00000000..7308c65c --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/frame.js @@ -0,0 +1,59 @@ +import { drawStrokes } from './draw.js'; +import init, { miniapp_call } from './photocraft.js'; +const allowed = new Set([ + 'inspect', + 'viewport', + 'language', + 'commands', + 'execute', + 'batch', + 'draw', + 'preview', + 'export', + 'open', +]); +let ready = false, + fontData; +window.addEventListener('message', async (event) => { + if (event.source !== parent || !event.data || event.data.type !== 'photo-request') return; + const { id, token, method, args, expectedVersion } = event.data; + if (!ready || !allowed.has(method)) return; + try { + const invoke = async (method, args, expectedVersion) => + JSON.parse(await miniapp_call(JSON.stringify({ method, args, expectedVersion }))); + const value = method === 'draw' + ? await drawStrokes(args, expectedVersion, invoke) + : await invoke(method, args, expectedVersion); + if (method === 'language' && fontData) + await miniapp_call(JSON.stringify({ method: 'font', args: { data: fontData } })); + parent.postMessage({ type: 'photo-response', id, token, value }, '*'); + } catch (error) { + parent.postMessage({ type: 'photo-response', id, token, error: String(error) }, '*'); + } +}); +try { + await init(); + for (let i = 0; i < 300; i++) { + try { + await miniapp_call('{"method":"inspect"}'); + ready = true; + break; + } catch { + await new Promise((r) => setTimeout(r, 100)); + } + } + if (!ready) throw Error('Image editor startup timed out'); + const response = await fetch('./cjk-ui.otf'); + if (!response.ok) throw Error('Could not load the offline UI font'); + const data = await new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result.split(',')[1]); + reader.onerror = reject; + response.blob().then((blob) => reader.readAsDataURL(blob), reject); + }); + fontData = data; + await miniapp_call(JSON.stringify({ method: 'font', args: { data } })); + parent.postMessage({ type: 'photo-ready' }, '*'); +} catch (error) { + parent.postMessage({ type: 'photo-failed', error: String(error) }, '*'); +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photocraft/index.html b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/index.html new file mode 100644 index 00000000..0ba24e69 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/index.html @@ -0,0 +1 @@ +MiniMax Photo diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photocraft/photocraft.d.ts b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/photocraft.d.ts new file mode 100644 index 00000000..4812be11 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/photocraft.d.ts @@ -0,0 +1,56 @@ +/* tslint:disable */ +/* eslint-disable */ + +export function miniapp_call(input: string): Promise; + +export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module; + +export interface InitOutput { + readonly memory: WebAssembly.Memory; + readonly miniapp_call: (a: number, b: number) => [number, number, number]; + readonly main: (a: number, b: number) => number; + readonly wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Function_fn_wasm_bindgen_54f023e2846dbff4___JsValue_____wasm_bindgen_54f023e2846dbff4___sys__Undefined___js_sys_526e9b82b0b84cf5___Function_fn_wasm_bindgen_54f023e2846dbff4___JsValue_____wasm_bindgen_54f023e2846dbff4___sys__Undefined_______true_: (a: number, b: number, c: any, d: any) => void; + readonly wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true_: (a: number, b: number, c: any) => [number, number]; + readonly wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true__10: (a: number, b: number, c: any) => [number, number]; + readonly wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true__11: (a: number, b: number, c: any) => [number, number]; + readonly wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true__6: (a: number, b: number, c: any) => [number, number]; + readonly wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsValue___true_: (a: number, b: number) => [number, number]; + readonly wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true_: (a: number, b: number, c: any) => void; + readonly wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true__4: (a: number, b: number, c: any) => void; + readonly wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true__5: (a: number, b: number, c: any) => void; + readonly wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true__9: (a: number, b: number, c: any) => void; + readonly wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuDeviceLostInfo__GpuDeviceLostInfo______true_: (a: number, b: number, c: any) => void; + readonly wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuDeviceLostInfo__GpuDeviceLostInfo______true__8: (a: number, b: number, c: any) => void; + readonly wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke_______true_: (a: number, b: number) => void; + readonly __wbindgen_malloc: (a: number, b: number) => number; + readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; + readonly __wbindgen_exn_store: (a: number) => void; + readonly __externref_table_alloc: () => number; + readonly __wbindgen_externrefs: WebAssembly.Table; + readonly __wbindgen_free: (a: number, b: number, c: number) => void; + readonly __wbindgen_destroy_closure: (a: number, b: number) => void; + readonly __externref_table_dealloc: (a: number) => void; + readonly __wbindgen_start: () => void; +} + +export type SyncInitInput = BufferSource | WebAssembly.Module; + +/** + * Instantiates the given `module`, which can either be bytes or + * a precompiled `WebAssembly.Module`. + * + * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated. + * + * @returns {InitOutput} + */ +export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput; + +/** + * If `module_or_path` is {RequestInfo} or {URL}, makes a request and + * for everything else, calls `WebAssembly.instantiate` directly. + * + * @param {{ module_or_path: InitInput | Promise }} module_or_path - Passing `InitInput` directly is deprecated. + * + * @returns {Promise} + */ +export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise } | InitInput | Promise): Promise; diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photocraft/photocraft.js b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/photocraft.js new file mode 100644 index 00000000..5944401c --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/photocraft.js @@ -0,0 +1,3675 @@ +/* @ts-self-types="./photocraft.d.ts" */ + +/** + * @param {string} input + * @returns {Promise} + */ +export function miniapp_call(input) { + const ptr0 = passStringToWasm0(input, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len0 = WASM_VECTOR_LEN; + const ret = wasm.miniapp_call(ptr0, len0); + if (ret[2]) { + throw takeFromExternrefTable0(ret[1]); + } + return takeFromExternrefTable0(ret[0]); +} +function __wbg_get_imports() { + const import0 = { + __proto__: null, + __wbg_Window_a2a6c4d665047b14: function(arg0) { + const ret = arg0.Window; + return ret; + }, + __wbg_WorkerGlobalScope_2664448a7c667d67: function(arg0) { + const ret = arg0.WorkerGlobalScope; + return ret; + }, + __wbg___wbindgen_boolean_get_5b446f51afd21013: function(arg0) { + const v = arg0; + const ret = typeof(v) === 'boolean' ? v : undefined; + return isLikeNone(ret) ? 0xFFFFFF : ret ? 1 : 0; + }, + __wbg___wbindgen_debug_string_4687d8d8c2017d52: function(arg0, arg1) { + const ret = debugString(arg1); + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg___wbindgen_in_92f62ee1427d9e49: function(arg0, arg1) { + const ret = arg0 in arg1; + return ret; + }, + __wbg___wbindgen_is_function_1f9d30630b8b1d3d: function(arg0) { + const ret = typeof(arg0) === 'function'; + return ret; + }, + __wbg___wbindgen_is_null_e343b7d08827ba72: function(arg0) { + const ret = arg0 === null; + return ret; + }, + __wbg___wbindgen_is_string_90b56bc79aad6f6c: function(arg0) { + const ret = typeof(arg0) === 'string'; + return ret; + }, + __wbg___wbindgen_is_undefined_8865fb403f8fe9d8: function(arg0) { + const ret = arg0 === undefined; + return ret; + }, + __wbg___wbindgen_number_get_2e0e7dee9f701a71: function(arg0, arg1) { + const obj = arg1; + const ret = typeof(obj) === 'number' ? obj : undefined; + getDataViewMemory0().setFloat64(arg0 + 8 * 1, isLikeNone(ret) ? 0 : ret, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true); + }, + __wbg___wbindgen_string_get_0380ccaa2f57f0d9: function(arg0, arg1) { + const obj = arg1; + const ret = typeof(obj) === 'string' ? obj : undefined; + var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg___wbindgen_throw_41e9ee4f547fc59a: function(arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); + }, + __wbg__wbg_cb_unref_dcc1a90847f04c41: function(arg0) { + arg0._wbg_cb_unref(); + }, + __wbg_abort_5b288d575f2b02d1: function() { return handleError(function (arg0) { + arg0.abort(); + }, arguments); }, + __wbg_abort_f78b99d80248bacb: function(arg0) { + arg0.abort(); + }, + __wbg_activeElement_1e45e0df6b6ac829: function(arg0) { + const ret = arg0.activeElement; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_activeElement_69b55e3697f14d9b: function(arg0) { + const ret = arg0.activeElement; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_activeTexture_11079673eac5c921: function(arg0, arg1) { + arg0.activeTexture(arg1 >>> 0); + }, + __wbg_activeTexture_2fad46c01cafe6b1: function(arg0, arg1) { + arg0.activeTexture(arg1 >>> 0); + }, + __wbg_addEventListener_4d0db17c671ea324: function() { return handleError(function (arg0, arg1, arg2, arg3) { + arg0.addEventListener(getStringFromWasm0(arg1, arg2), arg3); + }, arguments); }, + __wbg_addEventListener_8d3235978b9c69a8: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + arg0.addEventListener(getStringFromWasm0(arg1, arg2), arg3, arg4); + }, arguments); }, + __wbg_altKey_1e5fe17a42050103: function(arg0) { + const ret = arg0.altKey; + return ret; + }, + __wbg_altKey_cfb4c4fab9a7d0d0: function(arg0) { + const ret = arg0.altKey; + return ret; + }, + __wbg_appendChild_fb8c52e7dd8484ea: function() { return handleError(function (arg0, arg1) { + const ret = arg0.appendChild(arg1); + return ret; + }, arguments); }, + __wbg_arrayBuffer_0fe6e1300abcf908: function(arg0) { + const ret = arg0.arrayBuffer(); + return ret; + }, + __wbg_arrayBuffer_f07be74819944ea2: function() { return handleError(function (arg0) { + const ret = arg0.arrayBuffer(); + return ret; + }, arguments); }, + __wbg_at_31a66e62eefd72ad: function(arg0, arg1) { + const ret = arg0.at(arg1); + return ret; + }, + __wbg_attachShader_8920a5beea54aba7: function(arg0, arg1, arg2) { + arg0.attachShader(arg1, arg2); + }, + __wbg_attachShader_9567ae57af6746d5: function(arg0, arg1, arg2) { + arg0.attachShader(arg1, arg2); + }, + __wbg_beginQuery_eaee271e7ccd67d1: function(arg0, arg1, arg2) { + arg0.beginQuery(arg1 >>> 0, arg2); + }, + __wbg_beginRenderPass_3c53642423af50dc: function() { return handleError(function (arg0, arg1) { + const ret = arg0.beginRenderPass(arg1); + return ret; + }, arguments); }, + __wbg_bindAttribLocation_6a6f66cbe96ef24e: function(arg0, arg1, arg2, arg3, arg4) { + arg0.bindAttribLocation(arg1, arg2 >>> 0, getStringFromWasm0(arg3, arg4)); + }, + __wbg_bindAttribLocation_ade0ee986a734cdf: function(arg0, arg1, arg2, arg3, arg4) { + arg0.bindAttribLocation(arg1, arg2 >>> 0, getStringFromWasm0(arg3, arg4)); + }, + __wbg_bindBufferRange_a5aef3642afdabc8: function(arg0, arg1, arg2, arg3, arg4, arg5) { + arg0.bindBufferRange(arg1 >>> 0, arg2 >>> 0, arg3, arg4, arg5); + }, + __wbg_bindBuffer_0324f62b876c4403: function(arg0, arg1, arg2) { + arg0.bindBuffer(arg1 >>> 0, arg2); + }, + __wbg_bindBuffer_2195e89b585ce0c3: function(arg0, arg1, arg2) { + arg0.bindBuffer(arg1 >>> 0, arg2); + }, + __wbg_bindFramebuffer_22e4b8e6e6d8d0e8: function(arg0, arg1, arg2) { + arg0.bindFramebuffer(arg1 >>> 0, arg2); + }, + __wbg_bindFramebuffer_378eb18ef219d37a: function(arg0, arg1, arg2) { + arg0.bindFramebuffer(arg1 >>> 0, arg2); + }, + __wbg_bindRenderbuffer_db090531fb28de34: function(arg0, arg1, arg2) { + arg0.bindRenderbuffer(arg1 >>> 0, arg2); + }, + __wbg_bindRenderbuffer_e0c5aeef245a913a: function(arg0, arg1, arg2) { + arg0.bindRenderbuffer(arg1 >>> 0, arg2); + }, + __wbg_bindSampler_9b9743706aee71d1: function(arg0, arg1, arg2) { + arg0.bindSampler(arg1 >>> 0, arg2); + }, + __wbg_bindTexture_3cf008f256f3ed99: function(arg0, arg1, arg2) { + arg0.bindTexture(arg1 >>> 0, arg2); + }, + __wbg_bindTexture_613a47b8917a0ccd: function(arg0, arg1, arg2) { + arg0.bindTexture(arg1 >>> 0, arg2); + }, + __wbg_bindVertexArrayOES_3141815cb8234a6e: function(arg0, arg1) { + arg0.bindVertexArrayOES(arg1); + }, + __wbg_bindVertexArray_f58af0a346185ec5: function(arg0, arg1) { + arg0.bindVertexArray(arg1); + }, + __wbg_blendColor_68fc6d6454f2128d: function(arg0, arg1, arg2, arg3, arg4) { + arg0.blendColor(arg1, arg2, arg3, arg4); + }, + __wbg_blendColor_a6256f41d1925899: function(arg0, arg1, arg2, arg3, arg4) { + arg0.blendColor(arg1, arg2, arg3, arg4); + }, + __wbg_blendEquationSeparate_0a17fa4ea863d445: function(arg0, arg1, arg2) { + arg0.blendEquationSeparate(arg1 >>> 0, arg2 >>> 0); + }, + __wbg_blendEquationSeparate_fa2d4e5dde5ad8b3: function(arg0, arg1, arg2) { + arg0.blendEquationSeparate(arg1 >>> 0, arg2 >>> 0); + }, + __wbg_blendEquation_5fb8aee6a55cf900: function(arg0, arg1) { + arg0.blendEquation(arg1 >>> 0); + }, + __wbg_blendEquation_d21914e937b14896: function(arg0, arg1) { + arg0.blendEquation(arg1 >>> 0); + }, + __wbg_blendFuncSeparate_28abe082febb1a26: function(arg0, arg1, arg2, arg3, arg4) { + arg0.blendFuncSeparate(arg1 >>> 0, arg2 >>> 0, arg3 >>> 0, arg4 >>> 0); + }, + __wbg_blendFuncSeparate_2af9d47f7efc0452: function(arg0, arg1, arg2, arg3, arg4) { + arg0.blendFuncSeparate(arg1 >>> 0, arg2 >>> 0, arg3 >>> 0, arg4 >>> 0); + }, + __wbg_blendFunc_491ee1105079ce76: function(arg0, arg1, arg2) { + arg0.blendFunc(arg1 >>> 0, arg2 >>> 0); + }, + __wbg_blendFunc_589e4252bb396484: function(arg0, arg1, arg2) { + arg0.blendFunc(arg1 >>> 0, arg2 >>> 0); + }, + __wbg_blitFramebuffer_7b39bfec6cfece56: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) { + arg0.blitFramebuffer(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 >>> 0, arg10 >>> 0); + }, + __wbg_blockSize_1e07d486d3f2411b: function(arg0) { + const ret = arg0.blockSize; + return ret; + }, + __wbg_blur_cb8bd1ead8743f99: function() { return handleError(function (arg0) { + arg0.blur(); + }, arguments); }, + __wbg_body_e549239eaff082e1: function(arg0) { + const ret = arg0.body; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_bottom_29cd36a415d12885: function(arg0) { + const ret = arg0.bottom; + return ret; + }, + __wbg_bufferData_50f5eb06469330e4: function(arg0, arg1, arg2, arg3) { + arg0.bufferData(arg1 >>> 0, arg2, arg3 >>> 0); + }, + __wbg_bufferData_53e0f7a06b58fe81: function(arg0, arg1, arg2, arg3) { + arg0.bufferData(arg1 >>> 0, arg2, arg3 >>> 0); + }, + __wbg_bufferData_5fa44d94fe7a3878: function(arg0, arg1, arg2, arg3) { + arg0.bufferData(arg1 >>> 0, arg2, arg3 >>> 0); + }, + __wbg_bufferData_bad7ce562b6a9eac: function(arg0, arg1, arg2, arg3) { + arg0.bufferData(arg1 >>> 0, arg2, arg3 >>> 0); + }, + __wbg_bufferSubData_22c4c420e0f67cda: function(arg0, arg1, arg2, arg3) { + arg0.bufferSubData(arg1 >>> 0, arg2, arg3); + }, + __wbg_bufferSubData_8609cd8a2c013181: function(arg0, arg1, arg2, arg3) { + arg0.bufferSubData(arg1 >>> 0, arg2, arg3); + }, + __wbg_buffer_56ec2905a66f58b9: function(arg0) { + const ret = arg0.buffer; + return ret; + }, + __wbg_button_1aa380c7ca420cd1: function(arg0) { + const ret = arg0.button; + return ret; + }, + __wbg_buttons_de1e6c7f6de70736: function(arg0) { + const ret = arg0.buttons; + return ret; + }, + __wbg_call_187d372bd5fdd4aa: function() { return handleError(function (arg0, arg1, arg2) { + const ret = arg0.call(arg1, arg2); + return ret; + }, arguments); }, + __wbg_call_6137034ef55c9d0f: function() { return handleError(function (arg0, arg1) { + const ret = arg0.call(arg1); + return ret; + }, arguments); }, + __wbg_cancelAnimationFrame_6d30ac112c49342a: function() { return handleError(function (arg0, arg1) { + arg0.cancelAnimationFrame(arg1); + }, arguments); }, + __wbg_changedTouches_df984754af5ef0fa: function(arg0) { + const ret = arg0.changedTouches; + return ret; + }, + __wbg_clearBufferfv_05f7fc7252e623eb: function(arg0, arg1, arg2, arg3, arg4) { + arg0.clearBufferfv(arg1 >>> 0, arg2, getArrayF32FromWasm0(arg3, arg4)); + }, + __wbg_clearBufferiv_e8e740accbd0f2df: function(arg0, arg1, arg2, arg3, arg4) { + arg0.clearBufferiv(arg1 >>> 0, arg2, getArrayI32FromWasm0(arg3, arg4)); + }, + __wbg_clearBufferuiv_e7f50f91f2195e38: function(arg0, arg1, arg2, arg3, arg4) { + arg0.clearBufferuiv(arg1 >>> 0, arg2, getArrayU32FromWasm0(arg3, arg4)); + }, + __wbg_clearDepth_4840a5497ae51286: function(arg0, arg1) { + arg0.clearDepth(arg1); + }, + __wbg_clearDepth_5a119c24c5d193bc: function(arg0, arg1) { + arg0.clearDepth(arg1); + }, + __wbg_clearInterval_f1a050672da2658c: function(arg0, arg1) { + arg0.clearInterval(arg1); + }, + __wbg_clearStencil_1b8b8c727f598eec: function(arg0, arg1) { + arg0.clearStencil(arg1); + }, + __wbg_clearStencil_e4383e4a543e7997: function(arg0, arg1) { + arg0.clearStencil(arg1); + }, + __wbg_clearTimeout_c7bc4c3c7a7774af: function(arg0, arg1) { + arg0.clearTimeout(arg1); + }, + __wbg_clear_175cf3cb6d98d72b: function(arg0, arg1) { + arg0.clear(arg1 >>> 0); + }, + __wbg_clear_cb96796cc568b7c8: function(arg0, arg1) { + arg0.clear(arg1 >>> 0); + }, + __wbg_click_d990e70c576b7c54: function(arg0) { + arg0.click(); + }, + __wbg_clientWaitSync_73122aa040ce343d: function(arg0, arg1, arg2, arg3) { + const ret = arg0.clientWaitSync(arg1, arg2 >>> 0, arg3 >>> 0); + return ret; + }, + __wbg_clientX_5075231ed45e8ef5: function(arg0) { + const ret = arg0.clientX; + return ret; + }, + __wbg_clientX_80fda6c64299fd4d: function(arg0) { + const ret = arg0.clientX; + return ret; + }, + __wbg_clientY_0206292d4e8f94cb: function(arg0) { + const ret = arg0.clientY; + return ret; + }, + __wbg_clientY_846c39814ce02ab2: function(arg0) { + const ret = arg0.clientY; + return ret; + }, + __wbg_clipboardData_0048090643ed57a2: function(arg0) { + const ret = arg0.clipboardData; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_clipboard_9bf6a11ffd0b00a8: function(arg0) { + const ret = arg0.clipboard; + return ret; + }, + __wbg_close_4db7a0c12586beb7: function(arg0) { + arg0.close(); + }, + __wbg_code_422d539f5d7bacbb: function(arg0, arg1) { + const ret = arg1.code; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_colorMask_4d6afbbbc3022fbe: function(arg0, arg1, arg2, arg3, arg4) { + arg0.colorMask(arg1 !== 0, arg2 !== 0, arg3 !== 0, arg4 !== 0); + }, + __wbg_colorMask_8c903995f6f873be: function(arg0, arg1, arg2, arg3, arg4) { + arg0.colorMask(arg1 !== 0, arg2 !== 0, arg3 !== 0, arg4 !== 0); + }, + __wbg_compileShader_073a75409aaf96d2: function(arg0, arg1) { + arg0.compileShader(arg1); + }, + __wbg_compileShader_c2b53ff3a8851f60: function(arg0, arg1) { + arg0.compileShader(arg1); + }, + __wbg_compressedTexSubImage2D_4942a783e20221c2: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) { + arg0.compressedTexSubImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8); + }, + __wbg_compressedTexSubImage2D_4c408678ff5f3056: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { + arg0.compressedTexSubImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8, arg9); + }, + __wbg_compressedTexSubImage2D_80961cdbbd2b3aea: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) { + arg0.compressedTexSubImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8); + }, + __wbg_compressedTexSubImage3D_1e0f86237d82f8b9: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) { + arg0.compressedTexSubImage3D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 >>> 0, arg10); + }, + __wbg_compressedTexSubImage3D_682e402a0ac201ba: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11) { + arg0.compressedTexSubImage3D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 >>> 0, arg10, arg11); + }, + __wbg_configure_1e2c1c9edad07d26: function() { return handleError(function (arg0, arg1) { + arg0.configure(arg1); + }, arguments); }, + __wbg_construct_2cc135b78387ed16: function() { return handleError(function (arg0, arg1) { + const ret = Reflect.construct(arg0, arg1); + return ret; + }, arguments); }, + __wbg_contentBoxSize_1c91213ed1ddb06d: function(arg0) { + const ret = arg0.contentBoxSize; + return ret; + }, + __wbg_contentRect_65cd41b1e711b4e1: function(arg0) { + const ret = arg0.contentRect; + return ret; + }, + __wbg_continue_f83efa8d7e649e16: function() { return handleError(function (arg0) { + arg0.continue(); + }, arguments); }, + __wbg_copyBufferSubData_e82219c4834bd9ae: function(arg0, arg1, arg2, arg3, arg4, arg5) { + arg0.copyBufferSubData(arg1 >>> 0, arg2 >>> 0, arg3, arg4, arg5); + }, + __wbg_copyTexSubImage2D_455fba12cf4a776c: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) { + arg0.copyTexSubImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + }, + __wbg_copyTexSubImage2D_fe71e36efa520f37: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) { + arg0.copyTexSubImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + }, + __wbg_copyTexSubImage3D_717cd6c97934f2e6: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { + arg0.copyTexSubImage3D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + }, + __wbg_copyTextureToBuffer_1234b3210431ad05: function() { return handleError(function (arg0, arg1, arg2, arg3) { + arg0.copyTextureToBuffer(arg1, arg2, arg3); + }, arguments); }, + __wbg_copyTextureToTexture_d2e6a1eb3254b828: function() { return handleError(function (arg0, arg1, arg2, arg3) { + arg0.copyTextureToTexture(arg1, arg2, arg3); + }, arguments); }, + __wbg_createBindGroupLayout_b1bd63b4e88459d8: function() { return handleError(function (arg0, arg1) { + const ret = arg0.createBindGroupLayout(arg1); + return ret; + }, arguments); }, + __wbg_createBindGroup_f539b26ca341308f: function(arg0, arg1) { + const ret = arg0.createBindGroup(arg1); + return ret; + }, + __wbg_createBuffer_d1dd23bf8704564c: function(arg0) { + const ret = arg0.createBuffer(); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_createBuffer_d800e9b1d41b2ee5: function() { return handleError(function (arg0, arg1) { + const ret = arg0.createBuffer(arg1); + return ret; + }, arguments); }, + __wbg_createBuffer_ffe613371d42cfd3: function(arg0) { + const ret = arg0.createBuffer(); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_createCommandEncoder_3352d1ffc36c6fc0: function(arg0, arg1) { + const ret = arg0.createCommandEncoder(arg1); + return ret; + }, + __wbg_createElement_74049073a11f9c31: function() { return handleError(function (arg0, arg1, arg2) { + const ret = arg0.createElement(getStringFromWasm0(arg1, arg2)); + return ret; + }, arguments); }, + __wbg_createFramebuffer_2c6b5b0f49c88e5d: function(arg0) { + const ret = arg0.createFramebuffer(); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_createFramebuffer_d0969af4e9886297: function(arg0) { + const ret = arg0.createFramebuffer(); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_createObjectStore_84e0f5101158c82d: function() { return handleError(function (arg0, arg1, arg2) { + const ret = arg0.createObjectStore(getStringFromWasm0(arg1, arg2)); + return ret; + }, arguments); }, + __wbg_createObjectURL_2f3b38279fe61801: function() { return handleError(function (arg0, arg1) { + const ret = URL.createObjectURL(arg1); + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, arguments); }, + __wbg_createPipelineLayout_6eab52c327118937: function(arg0, arg1) { + const ret = arg0.createPipelineLayout(arg1); + return ret; + }, + __wbg_createProgram_cbf448e6f18a9402: function(arg0) { + const ret = arg0.createProgram(); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_createProgram_e0c81b0d2b8d0fd0: function(arg0) { + const ret = arg0.createProgram(); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_createQuery_ec241083d0b36197: function(arg0) { + const ret = arg0.createQuery(); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_createRenderPipeline_0ebb7ebc653e9207: function() { return handleError(function (arg0, arg1) { + const ret = arg0.createRenderPipeline(arg1); + return ret; + }, arguments); }, + __wbg_createRenderbuffer_2b17e9fe2e6fb4be: function(arg0) { + const ret = arg0.createRenderbuffer(); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_createRenderbuffer_c864095d6ebd60d0: function(arg0) { + const ret = arg0.createRenderbuffer(); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_createSampler_1b330d9da0c6523f: function(arg0) { + const ret = arg0.createSampler(); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_createSampler_9bd91d7e928c0060: function(arg0, arg1) { + const ret = arg0.createSampler(arg1); + return ret; + }, + __wbg_createShaderModule_cefa51336cb288ae: function(arg0, arg1) { + const ret = arg0.createShaderModule(arg1); + return ret; + }, + __wbg_createShader_6c1a2295587878a5: function(arg0, arg1) { + const ret = arg0.createShader(arg1 >>> 0); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_createShader_7c9d99a21ecb08c0: function(arg0, arg1) { + const ret = arg0.createShader(arg1 >>> 0); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_createTexture_01e8e591b64237de: function(arg0) { + const ret = arg0.createTexture(); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_createTexture_5f2583508ebe379b: function(arg0) { + const ret = arg0.createTexture(); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_createTexture_ed7e9fc04dd54d84: function() { return handleError(function (arg0, arg1) { + const ret = arg0.createTexture(arg1); + return ret; + }, arguments); }, + __wbg_createVertexArrayOES_a8dc8498b56df937: function(arg0) { + const ret = arg0.createVertexArrayOES(); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_createVertexArray_b223ea69dd08fcab: function(arg0) { + const ret = arg0.createVertexArray(); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_createView_da41c2d2cb212715: function() { return handleError(function (arg0, arg1) { + const ret = arg0.createView(arg1); + return ret; + }, arguments); }, + __wbg_ctrlKey_282349f48e6cb157: function(arg0) { + const ret = arg0.ctrlKey; + return ret; + }, + __wbg_ctrlKey_8b5101745e8782fa: function(arg0) { + const ret = arg0.ctrlKey; + return ret; + }, + __wbg_cullFace_12123c1c97f1ba2c: function(arg0, arg1) { + arg0.cullFace(arg1 >>> 0); + }, + __wbg_cullFace_1a01f0b6d5aeb687: function(arg0, arg1) { + arg0.cullFace(arg1 >>> 0); + }, + __wbg_dataTransfer_afa27477f2f9e0e6: function(arg0) { + const ret = arg0.dataTransfer; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_debug_349089a0d32e4c7b: function(arg0, arg1) { + console.debug(getStringFromWasm0(arg0, arg1)); + }, + __wbg_deleteBuffer_070e58aaaf2a7a8b: function(arg0, arg1) { + arg0.deleteBuffer(arg1); + }, + __wbg_deleteBuffer_7775ee9e248c8468: function(arg0, arg1) { + arg0.deleteBuffer(arg1); + }, + __wbg_deleteFramebuffer_3f8ab330098bf8e6: function(arg0, arg1) { + arg0.deleteFramebuffer(arg1); + }, + __wbg_deleteFramebuffer_570d3b214a509fa2: function(arg0, arg1) { + arg0.deleteFramebuffer(arg1); + }, + __wbg_deleteProgram_822906f0368175d0: function(arg0, arg1) { + arg0.deleteProgram(arg1); + }, + __wbg_deleteProgram_b524b30ad176cdb4: function(arg0, arg1) { + arg0.deleteProgram(arg1); + }, + __wbg_deleteQuery_266895df9763e0b3: function(arg0, arg1) { + arg0.deleteQuery(arg1); + }, + __wbg_deleteRenderbuffer_826c9b43b7ea68f5: function(arg0, arg1) { + arg0.deleteRenderbuffer(arg1); + }, + __wbg_deleteRenderbuffer_f4e121a3ab21c605: function(arg0, arg1) { + arg0.deleteRenderbuffer(arg1); + }, + __wbg_deleteSampler_f8afded8bf215d53: function(arg0, arg1) { + arg0.deleteSampler(arg1); + }, + __wbg_deleteShader_a70f6cc1918d67eb: function(arg0, arg1) { + arg0.deleteShader(arg1); + }, + __wbg_deleteShader_da18a294158c2d15: function(arg0, arg1) { + arg0.deleteShader(arg1); + }, + __wbg_deleteSync_4f0be28b03f50495: function(arg0, arg1) { + arg0.deleteSync(arg1); + }, + __wbg_deleteTexture_78c170241204a466: function(arg0, arg1) { + arg0.deleteTexture(arg1); + }, + __wbg_deleteTexture_9f42750adb092e4f: function(arg0, arg1) { + arg0.deleteTexture(arg1); + }, + __wbg_deleteVertexArrayOES_e01f31634d466176: function(arg0, arg1) { + arg0.deleteVertexArrayOES(arg1); + }, + __wbg_deleteVertexArray_ca9768805d051d49: function(arg0, arg1) { + arg0.deleteVertexArray(arg1); + }, + __wbg_delete_efcc1a7f91e815b8: function() { return handleError(function (arg0, arg1) { + const ret = arg0.delete(arg1); + return ret; + }, arguments); }, + __wbg_deltaMode_6280d8266d5520f5: function(arg0) { + const ret = arg0.deltaMode; + return ret; + }, + __wbg_deltaX_d330516e89f03877: function(arg0) { + const ret = arg0.deltaX; + return ret; + }, + __wbg_deltaY_7abc8fc9878d0002: function(arg0) { + const ret = arg0.deltaY; + return ret; + }, + __wbg_depthFunc_92e96d8f46a23300: function(arg0, arg1) { + arg0.depthFunc(arg1 >>> 0); + }, + __wbg_depthFunc_a41fb5adacb22e09: function(arg0, arg1) { + arg0.depthFunc(arg1 >>> 0); + }, + __wbg_depthMask_06ecff4d4514c38f: function(arg0, arg1) { + arg0.depthMask(arg1 !== 0); + }, + __wbg_depthMask_0d7c3dec3b8405ee: function(arg0, arg1) { + arg0.depthMask(arg1 !== 0); + }, + __wbg_depthRange_24c7969249461e8e: function(arg0, arg1, arg2) { + arg0.depthRange(arg1, arg2); + }, + __wbg_depthRange_6a4e169ccf314148: function(arg0, arg1, arg2) { + arg0.depthRange(arg1, arg2); + }, + __wbg_description_83b8a393160021b9: function(arg0, arg1) { + const ret = arg1.description; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_destroy_249478e98a7943d5: function(arg0) { + arg0.destroy(); + }, + __wbg_devicePixelContentBoxSize_83d4c55aa7829e7a: function(arg0) { + const ret = arg0.devicePixelContentBoxSize; + return ret; + }, + __wbg_devicePixelRatio_7d39e9af5448d3d4: function(arg0) { + const ret = arg0.devicePixelRatio; + return ret; + }, + __wbg_disableVertexAttribArray_11c9f11bee30c9d8: function(arg0, arg1) { + arg0.disableVertexAttribArray(arg1 >>> 0); + }, + __wbg_disableVertexAttribArray_c4c8af1f9e4120d4: function(arg0, arg1) { + arg0.disableVertexAttribArray(arg1 >>> 0); + }, + __wbg_disable_19fe787eccdf0272: function(arg0, arg1) { + arg0.disable(arg1 >>> 0); + }, + __wbg_disable_81b2cb5f8cea15ae: function(arg0, arg1) { + arg0.disable(arg1 >>> 0); + }, + __wbg_disconnect_1eac4c705724307d: function(arg0) { + arg0.disconnect(); + }, + __wbg_document_9854e03c05fc8834: function(arg0) { + const ret = arg0.document; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_drawArraysInstancedANGLE_b76512b5abba6668: function(arg0, arg1, arg2, arg3, arg4) { + arg0.drawArraysInstancedANGLE(arg1 >>> 0, arg2, arg3, arg4); + }, + __wbg_drawArraysInstanced_9b44aa78a087154d: function(arg0, arg1, arg2, arg3, arg4) { + arg0.drawArraysInstanced(arg1 >>> 0, arg2, arg3, arg4); + }, + __wbg_drawArrays_08872e02fb57b847: function(arg0, arg1, arg2, arg3) { + arg0.drawArrays(arg1 >>> 0, arg2, arg3); + }, + __wbg_drawArrays_741af5c3f8db636f: function(arg0, arg1, arg2, arg3) { + arg0.drawArrays(arg1 >>> 0, arg2, arg3); + }, + __wbg_drawBuffersWEBGL_c1bc0bbfd584c9b2: function(arg0, arg1) { + arg0.drawBuffersWEBGL(arg1); + }, + __wbg_drawBuffers_7a58bd4729f7a1fc: function(arg0, arg1) { + arg0.drawBuffers(arg1); + }, + __wbg_drawElementsInstancedANGLE_c3fc0cfa9e29a1bc: function(arg0, arg1, arg2, arg3, arg4, arg5) { + arg0.drawElementsInstancedANGLE(arg1 >>> 0, arg2, arg3 >>> 0, arg4, arg5); + }, + __wbg_drawElementsInstanced_d7c396aa034159b6: function(arg0, arg1, arg2, arg3, arg4, arg5) { + arg0.drawElementsInstanced(arg1 >>> 0, arg2, arg3 >>> 0, arg4, arg5); + }, + __wbg_drawIndexed_638959aae942557c: function(arg0, arg1, arg2, arg3, arg4, arg5) { + arg0.drawIndexed(arg1 >>> 0, arg2 >>> 0, arg3 >>> 0, arg4, arg5 >>> 0); + }, + __wbg_draw_086a9578fc9898c2: function(arg0, arg1, arg2, arg3, arg4) { + arg0.draw(arg1 >>> 0, arg2 >>> 0, arg3 >>> 0, arg4 >>> 0); + }, + __wbg_elementFromPoint_8f6f88cd3ac4b9e8: function(arg0, arg1, arg2) { + const ret = arg0.elementFromPoint(arg1, arg2); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_elementFromPoint_fb48b4624ec3dd6a: function(arg0, arg1, arg2) { + const ret = arg0.elementFromPoint(arg1, arg2); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_enableVertexAttribArray_1496b78a8dbab9fd: function(arg0, arg1) { + arg0.enableVertexAttribArray(arg1 >>> 0); + }, + __wbg_enableVertexAttribArray_d52693866bc8b8dd: function(arg0, arg1) { + arg0.enableVertexAttribArray(arg1 >>> 0); + }, + __wbg_enable_6eeb9c0e9b483cee: function(arg0, arg1) { + arg0.enable(arg1 >>> 0); + }, + __wbg_enable_cb4fc19b51148c37: function(arg0, arg1) { + arg0.enable(arg1 >>> 0); + }, + __wbg_endQuery_73863d04a795d520: function(arg0, arg1) { + arg0.endQuery(arg1 >>> 0); + }, + __wbg_end_b57473834b877409: function(arg0) { + arg0.end(); + }, + __wbg_error_3da0c81bd4184d52: function(arg0) { + const ret = arg0.error; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_error_5a019734875b3676: function(arg0, arg1) { + let deferred0_0; + let deferred0_1; + try { + deferred0_0 = arg0; + deferred0_1 = arg1; + console.error(getStringFromWasm0(arg0, arg1)); + } finally { + wasm.__wbindgen_free(deferred0_0, deferred0_1, 1); + } + }, + __wbg_error_6a23b57453026a47: function() { return handleError(function (arg0) { + const ret = arg0.error; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, arguments); }, + __wbg_error_8c8dff942c7c4f11: function(arg0) { + const ret = arg0.error; + return ret; + }, + __wbg_features_dec7bd2fd3d91bd6: function(arg0) { + const ret = arg0.features; + return ret; + }, + __wbg_fenceSync_330293024adb66bc: function(arg0, arg1, arg2) { + const ret = arg0.fenceSync(arg1 >>> 0, arg2 >>> 0); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_fetch_4178962c570137ca: function(arg0, arg1, arg2) { + const ret = arg0.fetch(getStringFromWasm0(arg1, arg2)); + return ret; + }, + __wbg_fetch_b322877f1ed6457d: function(arg0, arg1, arg2, arg3) { + const ret = arg0.fetch(getStringFromWasm0(arg1, arg2), arg3); + return ret; + }, + __wbg_files_cb1ce1b82f16c484: function(arg0) { + const ret = arg0.files; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_files_fe03006f0ba1a5f0: function(arg0) { + const ret = arg0.files; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_finish_09ec094c10f41e7b: function(arg0) { + const ret = arg0.finish(); + return ret; + }, + __wbg_finish_173a156040775de3: function(arg0) { + arg0.finish(); + }, + __wbg_finish_31ffb964be7e9749: function(arg0) { + arg0.finish(); + }, + __wbg_finish_ec1c191f66a895b1: function(arg0, arg1) { + const ret = arg0.finish(arg1); + return ret; + }, + __wbg_flush_13b162660ad850d2: function(arg0) { + arg0.flush(); + }, + __wbg_flush_a5ad38200881ac35: function(arg0) { + arg0.flush(); + }, + __wbg_focus_e1638be0df4aeb8f: function() { return handleError(function (arg0, arg1) { + arg0.focus(arg1); + }, arguments); }, + __wbg_force_7632bf44933b4388: function(arg0) { + const ret = arg0.force; + return ret; + }, + __wbg_framebufferRenderbuffer_1c6337e0030411f3: function(arg0, arg1, arg2, arg3, arg4) { + arg0.framebufferRenderbuffer(arg1 >>> 0, arg2 >>> 0, arg3 >>> 0, arg4); + }, + __wbg_framebufferRenderbuffer_f019e9231b142c0d: function(arg0, arg1, arg2, arg3, arg4) { + arg0.framebufferRenderbuffer(arg1 >>> 0, arg2 >>> 0, arg3 >>> 0, arg4); + }, + __wbg_framebufferTexture2D_73c52f23ec33aa22: function(arg0, arg1, arg2, arg3, arg4, arg5) { + arg0.framebufferTexture2D(arg1 >>> 0, arg2 >>> 0, arg3 >>> 0, arg4, arg5); + }, + __wbg_framebufferTexture2D_caddefa1f767646e: function(arg0, arg1, arg2, arg3, arg4, arg5) { + arg0.framebufferTexture2D(arg1 >>> 0, arg2 >>> 0, arg3 >>> 0, arg4, arg5); + }, + __wbg_framebufferTextureLayer_1d5c0f0e3234e521: function(arg0, arg1, arg2, arg3, arg4, arg5) { + arg0.framebufferTextureLayer(arg1 >>> 0, arg2 >>> 0, arg3, arg4, arg5); + }, + __wbg_framebufferTextureMultiviewOVR_77f19224ff7be6ef: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6) { + arg0.framebufferTextureMultiviewOVR(arg1 >>> 0, arg2 >>> 0, arg3, arg4, arg5, arg6); + }, + __wbg_frontFace_6751b4b97f997aeb: function(arg0, arg1) { + arg0.frontFace(arg1 >>> 0); + }, + __wbg_frontFace_b064adb15b6f3772: function(arg0, arg1) { + arg0.frontFace(arg1 >>> 0); + }, + __wbg_getBindGroupLayout_fb40c3b93d37f466: function(arg0, arg1) { + const ret = arg0.getBindGroupLayout(arg1 >>> 0); + return ret; + }, + __wbg_getBoundingClientRect_57152b1a20f3de34: function(arg0) { + const ret = arg0.getBoundingClientRect(); + return ret; + }, + __wbg_getBufferSubData_dd23246099b166d1: function(arg0, arg1, arg2, arg3) { + arg0.getBufferSubData(arg1 >>> 0, arg2, arg3); + }, + __wbg_getComputedStyle_dd0f456804795fd6: function() { return handleError(function (arg0, arg1) { + const ret = arg0.getComputedStyle(arg1); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, arguments); }, + __wbg_getContext_051324720aa5b7e8: function() { return handleError(function (arg0, arg1, arg2, arg3) { + const ret = arg0.getContext(getStringFromWasm0(arg1, arg2), arg3); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, arguments); }, + __wbg_getContext_189ce278aa985704: function() { return handleError(function (arg0, arg1, arg2, arg3) { + const ret = arg0.getContext(getStringFromWasm0(arg1, arg2), arg3); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, arguments); }, + __wbg_getContext_635e36719cad2623: function() { return handleError(function (arg0, arg1, arg2) { + const ret = arg0.getContext(getStringFromWasm0(arg1, arg2)); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, arguments); }, + __wbg_getContext_e567868594d2e0c6: function() { return handleError(function (arg0, arg1, arg2) { + const ret = arg0.getContext(getStringFromWasm0(arg1, arg2)); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, arguments); }, + __wbg_getCurrentTexture_9f3b84d0eaa6cd95: function() { return handleError(function (arg0) { + const ret = arg0.getCurrentTexture(); + return ret; + }, arguments); }, + __wbg_getData_bc58070c107b7d8a: function() { return handleError(function (arg0, arg1, arg2, arg3) { + const ret = arg1.getData(getStringFromWasm0(arg2, arg3)); + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, arguments); }, + __wbg_getElementById_cc94972b404e4eaa: function(arg0, arg1, arg2) { + const ret = arg0.getElementById(getStringFromWasm0(arg1, arg2)); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_getExtension_abfda2c5db286b07: function() { return handleError(function (arg0, arg1, arg2) { + const ret = arg0.getExtension(getStringFromWasm0(arg1, arg2)); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, arguments); }, + __wbg_getIndexedParameter_0f49864473e337fa: function() { return handleError(function (arg0, arg1, arg2) { + const ret = arg0.getIndexedParameter(arg1 >>> 0, arg2 >>> 0); + return ret; + }, arguments); }, + __wbg_getItem_4c80b7663197c7ff: function() { return handleError(function (arg0, arg1, arg2, arg3) { + const ret = arg1.getItem(getStringFromWasm0(arg2, arg3)); + var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, arguments); }, + __wbg_getMappedRange_fb54c6327b2d8d20: function() { return handleError(function (arg0, arg1, arg2) { + const ret = arg0.getMappedRange(arg1, arg2); + return ret; + }, arguments); }, + __wbg_getParameter_974595a6624c6c10: function() { return handleError(function (arg0, arg1) { + const ret = arg0.getParameter(arg1 >>> 0); + return ret; + }, arguments); }, + __wbg_getParameter_a97f491753b05668: function() { return handleError(function (arg0, arg1) { + const ret = arg0.getParameter(arg1 >>> 0); + return ret; + }, arguments); }, + __wbg_getPreferredCanvasFormat_0ef5034c8902201b: function(arg0) { + const ret = arg0.getPreferredCanvasFormat(); + return (__wbindgen_enum_GpuTextureFormat.indexOf(ret) + 1 || 102) - 1; + }, + __wbg_getProgramInfoLog_208fb1ff31006495: function(arg0, arg1, arg2) { + const ret = arg1.getProgramInfoLog(arg2); + var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_getProgramInfoLog_3276b294d6d42fe2: function(arg0, arg1, arg2) { + const ret = arg1.getProgramInfoLog(arg2); + var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_getProgramParameter_50bafab01cf88652: function(arg0, arg1, arg2) { + const ret = arg0.getProgramParameter(arg1, arg2 >>> 0); + return ret; + }, + __wbg_getProgramParameter_fc7124bb9fb7c675: function(arg0, arg1, arg2) { + const ret = arg0.getProgramParameter(arg1, arg2 >>> 0); + return ret; + }, + __wbg_getPropertyValue_e90a3628c2de4fb6: function() { return handleError(function (arg0, arg1, arg2, arg3) { + const ret = arg1.getPropertyValue(getStringFromWasm0(arg2, arg3)); + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, arguments); }, + __wbg_getQueryParameter_937ba13f77db778f: function(arg0, arg1, arg2) { + const ret = arg0.getQueryParameter(arg1, arg2 >>> 0); + return ret; + }, + __wbg_getRootNode_76c323f0bf80bdcd: function(arg0) { + const ret = arg0.getRootNode(); + return ret; + }, + __wbg_getShaderInfoLog_7e0cbba353ca95da: function(arg0, arg1, arg2) { + const ret = arg1.getShaderInfoLog(arg2); + var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_getShaderInfoLog_bb64c5a52df0b7a3: function(arg0, arg1, arg2) { + const ret = arg1.getShaderInfoLog(arg2); + var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_getShaderParameter_745acf10b8e45e31: function(arg0, arg1, arg2) { + const ret = arg0.getShaderParameter(arg1, arg2 >>> 0); + return ret; + }, + __wbg_getShaderParameter_e55ea9c456df5484: function(arg0, arg1, arg2) { + const ret = arg0.getShaderParameter(arg1, arg2 >>> 0); + return ret; + }, + __wbg_getSupportedExtensions_1459bad37860c0c3: function(arg0) { + const ret = arg0.getSupportedExtensions(); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_getSupportedProfiles_7b2acfa66b565d24: function(arg0) { + const ret = arg0.getSupportedProfiles(); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_getSyncParameter_bb4be47b67bfa2f8: function(arg0, arg1, arg2) { + const ret = arg0.getSyncParameter(arg1, arg2 >>> 0); + return ret; + }, + __wbg_getUniformBlockIndex_5e2252ceb34531a5: function(arg0, arg1, arg2, arg3) { + const ret = arg0.getUniformBlockIndex(arg1, getStringFromWasm0(arg2, arg3)); + return ret; + }, + __wbg_getUniformLocation_50ba45dade572703: function(arg0, arg1, arg2, arg3) { + const ret = arg0.getUniformLocation(arg1, getStringFromWasm0(arg2, arg3)); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_getUniformLocation_cb4e3e121235f91a: function(arg0, arg1, arg2, arg3) { + const ret = arg0.getUniformLocation(arg1, getStringFromWasm0(arg2, arg3)); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_get_31af05bd4842a84f: function() { return handleError(function (arg0, arg1) { + const ret = Reflect.get(arg0, arg1); + return ret; + }, arguments); }, + __wbg_get_5dde8a29f073d908: function(arg0, arg1) { + const ret = arg0[arg1 >>> 0]; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_get_9356b22e2a46465d: function(arg0, arg1) { + const ret = arg0[arg1 >>> 0]; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_get_b64ce72bb2abf052: function(arg0, arg1) { + const ret = arg0[arg1 >>> 0]; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_get_fd12a9100976c296: function(arg0, arg1) { + const ret = arg0[arg1 >>> 0]; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_get_unchecked_288889d017702237: function(arg0, arg1) { + const ret = arg0[arg1 >>> 0]; + return ret; + }, + __wbg_gpu_afdd4387c7afe5f9: function(arg0) { + const ret = arg0.gpu; + return ret; + }, + __wbg_has_eafa12e457ea88fb: function(arg0, arg1, arg2) { + const ret = arg0.has(getStringFromWasm0(arg1, arg2)); + return ret; + }, + __wbg_hash_c4083658cccb641b: function() { return handleError(function (arg0, arg1) { + const ret = arg1.hash; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, arguments); }, + __wbg_height_c9feb8f4a9a61abc: function(arg0) { + const ret = arg0.height; + return ret; + }, + __wbg_height_fc97e1a0c2e7331f: function(arg0) { + const ret = arg0.height; + return ret; + }, + __wbg_hidden_2ba371ecafe013fa: function(arg0) { + const ret = arg0.hidden; + return ret; + }, + __wbg_host_75aa3342c78db1a2: function() { return handleError(function (arg0, arg1) { + const ret = arg1.host; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, arguments); }, + __wbg_hostname_b9a71dd3c2da0eef: function() { return handleError(function (arg0, arg1) { + const ret = arg1.hostname; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, arguments); }, + __wbg_href_abc902beb29d526e: function() { return handleError(function (arg0, arg1) { + const ret = arg1.href; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, arguments); }, + __wbg_id_957842593c7d0e05: function(arg0, arg1) { + const ret = arg1.id; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_identifier_24ee7ee6118f12a7: function(arg0) { + const ret = arg0.identifier; + return ret; + }, + __wbg_includes_9b0dfa946c313621: function(arg0, arg1, arg2) { + const ret = arg0.includes(arg1, arg2); + return ret; + }, + __wbg_indexedDB_53d75531b7daa0cd: function() { return handleError(function (arg0) { + const ret = arg0.indexedDB; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, arguments); }, + __wbg_info_971d8b9db3dae69f: function(arg0) { + const ret = arg0.info; + return ret; + }, + __wbg_info_b6eef361105d0137: function(arg0, arg1) { + console.info(getStringFromWasm0(arg0, arg1)); + }, + __wbg_inlineSize_edbf0c52598aa763: function(arg0) { + const ret = arg0.inlineSize; + return ret; + }, + __wbg_inputType_bcd41e55691a33d9: function(arg0, arg1) { + const ret = arg1.inputType; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_insertBefore_f1ba67809033f6b1: function() { return handleError(function (arg0, arg1, arg2) { + const ret = arg0.insertBefore(arg1, arg2); + return ret; + }, arguments); }, + __wbg_instanceof_Blob_7c6191a4cd5834d3: function(arg0) { + let result; + try { + result = arg0 instanceof Blob; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_Document_b2a06e9deaeb61d1: function(arg0) { + let result; + try { + result = arg0 instanceof Document; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_DomException_550db3f9465a933f: function(arg0) { + let result; + try { + result = arg0 instanceof DOMException; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_Element_818e11074cdb63b5: function(arg0) { + let result; + try { + result = arg0 instanceof Element; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_GpuOutOfMemoryError_5c3b8a2499f59adb: function(arg0) { + let result; + try { + result = arg0 instanceof GPUOutOfMemoryError; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_GpuValidationError_7659e07b12d4e184: function(arg0) { + let result; + try { + result = arg0 instanceof GPUValidationError; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_HtmlAnchorElement_e2e601da36602959: function(arg0) { + let result; + try { + result = arg0 instanceof HTMLAnchorElement; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_HtmlButtonElement_bd67486d3501ad48: function(arg0) { + let result; + try { + result = arg0 instanceof HTMLButtonElement; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_HtmlCanvasElement_0a30c11fbbf41841: function(arg0) { + let result; + try { + result = arg0 instanceof HTMLCanvasElement; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_HtmlElement_32fb153a5a0e2349: function(arg0) { + let result; + try { + result = arg0 instanceof HTMLElement; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_HtmlInputElement_5c33d1de59c09c49: function(arg0) { + let result; + try { + result = arg0 instanceof HTMLInputElement; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_IdbCursorWithValue_824cba19af90f049: function(arg0) { + let result; + try { + result = arg0 instanceof IDBCursorWithValue; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_IdbDatabase_ee9e122a32a24d91: function(arg0) { + let result; + try { + result = arg0 instanceof IDBDatabase; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_Promise_e1dc6893aa1ece28: function(arg0) { + let result; + try { + result = arg0 instanceof Promise; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_ResizeObserverEntry_159abe6614a8e952: function(arg0) { + let result; + try { + result = arg0 instanceof ResizeObserverEntry; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_ResizeObserverSize_f9d47e3f8cfd50db: function(arg0) { + let result; + try { + result = arg0 instanceof ResizeObserverSize; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_Response_b8758567269c30b2: function(arg0) { + let result; + try { + result = arg0 instanceof Response; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_ShadowRoot_0ef114d846d9fd90: function(arg0) { + let result; + try { + result = arg0 instanceof ShadowRoot; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_WebGl2RenderingContext_64c994c14c0790fb: function(arg0) { + let result; + try { + result = arg0 instanceof WebGL2RenderingContext; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_instanceof_Window_82d71df4eddf88bc: function(arg0) { + let result; + try { + result = arg0 instanceof Window; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }, + __wbg_invalidateFramebuffer_4f576db65bb37d6a: function() { return handleError(function (arg0, arg1, arg2) { + arg0.invalidateFramebuffer(arg1 >>> 0, arg2); + }, arguments); }, + __wbg_isActive_c6868ea0a8a0dfaf: function(arg0) { + const ret = arg0.isActive; + return ret; + }, + __wbg_isComposing_600c9236938f8e5a: function(arg0) { + const ret = arg0.isComposing; + return ret; + }, + __wbg_isComposing_d03a4fd2d6155b14: function(arg0) { + const ret = arg0.isComposing; + return ret; + }, + __wbg_isFallbackAdapter_4c8cc3b18677460a: function(arg0) { + const ret = arg0.isFallbackAdapter; + return ret; + }, + __wbg_isSecureContext_e61363f740acf8de: function(arg0) { + const ret = arg0.isSecureContext; + return ret; + }, + __wbg_is_4b278c0bd3caba97: function(arg0, arg1) { + const ret = Object.is(arg0, arg1); + return ret; + }, + __wbg_item_0c8f652c0830e437: function(arg0, arg1) { + const ret = arg0.item(arg1 >>> 0); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_items_25f8ccc11891dbeb: function(arg0) { + const ret = arg0.items; + return ret; + }, + __wbg_keyCode_fbee6c8fd374ff5e: function(arg0) { + const ret = arg0.keyCode; + return ret; + }, + __wbg_key_1193871533b99ae5: function(arg0, arg1) { + const ret = arg1.key; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_key_46ce184affdc8d18: function() { return handleError(function (arg0) { + const ret = arg0.key; + return ret; + }, arguments); }, + __wbg_label_7add8cb37a6ef98f: function(arg0, arg1) { + const ret = arg1.label; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_languages_ec49d2aea5d0edc4: function(arg0) { + const ret = arg0.languages; + return ret; + }, + __wbg_left_e0a244490fe2f293: function(arg0) { + const ret = arg0.left; + return ret; + }, + __wbg_length_06ca2697fe194eac: function(arg0) { + const ret = arg0.length; + return ret; + }, + __wbg_length_357ad61f15f550be: function(arg0) { + const ret = arg0.length; + return ret; + }, + __wbg_length_78dac82682e59660: function(arg0) { + const ret = arg0.length; + return ret; + }, + __wbg_length_7f3c00c40364105e: function(arg0) { + const ret = arg0.length; + return ret; + }, + __wbg_length_d4bdea10311bd9cf: function(arg0) { + const ret = arg0.length; + return ret; + }, + __wbg_length_ff6b2e0dd257ad9a: function(arg0) { + const ret = arg0.length; + return ret; + }, + __wbg_limits_06bcb36c8409843b: function(arg0) { + const ret = arg0.limits; + return ret; + }, + __wbg_limits_601ad2e086ef8141: function(arg0) { + const ret = arg0.limits; + return ret; + }, + __wbg_linkProgram_571a9ea00d38ff83: function(arg0, arg1) { + arg0.linkProgram(arg1); + }, + __wbg_linkProgram_acdc299c43d734a0: function(arg0, arg1) { + arg0.linkProgram(arg1); + }, + __wbg_localStorage_567c24950edbc178: function() { return handleError(function (arg0) { + const ret = arg0.localStorage; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, arguments); }, + __wbg_location_9c46e8ada95d3174: function(arg0) { + const ret = arg0.location; + return ret; + }, + __wbg_lost_bb454eb62101af1a: function(arg0) { + const ret = arg0.lost; + return ret; + }, + __wbg_mapAsync_b0597127f5037286: function(arg0, arg1, arg2, arg3) { + const ret = arg0.mapAsync(arg1 >>> 0, arg2, arg3); + return ret; + }, + __wbg_matchMedia_8a4857f947f11f82: function() { return handleError(function (arg0, arg1, arg2) { + const ret = arg0.matchMedia(getStringFromWasm0(arg1, arg2)); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, arguments); }, + __wbg_matches_778d0873b064b1bf: function(arg0) { + const ret = arg0.matches; + return ret; + }, + __wbg_maxBindGroupsPlusVertexBuffers_52369f089736ef9d: function(arg0) { + const ret = arg0.maxBindGroupsPlusVertexBuffers; + return ret; + }, + __wbg_maxBindGroups_4e424afe6ce86ca2: function(arg0) { + const ret = arg0.maxBindGroups; + return ret; + }, + __wbg_maxBindingsPerBindGroup_7d035da36821c44f: function(arg0) { + const ret = arg0.maxBindingsPerBindGroup; + return ret; + }, + __wbg_maxBufferSize_423f4a084e32a195: function(arg0) { + const ret = arg0.maxBufferSize; + return ret; + }, + __wbg_maxColorAttachmentBytesPerSample_c4cd9126f6d287c6: function(arg0) { + const ret = arg0.maxColorAttachmentBytesPerSample; + return ret; + }, + __wbg_maxColorAttachments_d924670762b9e250: function(arg0) { + const ret = arg0.maxColorAttachments; + return ret; + }, + __wbg_maxComputeInvocationsPerWorkgroup_707a3868f7cebb59: function(arg0) { + const ret = arg0.maxComputeInvocationsPerWorkgroup; + return ret; + }, + __wbg_maxComputeWorkgroupSizeX_0a4d99463cbd6e5e: function(arg0) { + const ret = arg0.maxComputeWorkgroupSizeX; + return ret; + }, + __wbg_maxComputeWorkgroupSizeY_85123ea0587f7558: function(arg0) { + const ret = arg0.maxComputeWorkgroupSizeY; + return ret; + }, + __wbg_maxComputeWorkgroupSizeZ_a3186b4c5267d44f: function(arg0) { + const ret = arg0.maxComputeWorkgroupSizeZ; + return ret; + }, + __wbg_maxComputeWorkgroupStorageSize_57b297355cfb6204: function(arg0) { + const ret = arg0.maxComputeWorkgroupStorageSize; + return ret; + }, + __wbg_maxComputeWorkgroupsPerDimension_4158f95e673d54c4: function(arg0) { + const ret = arg0.maxComputeWorkgroupsPerDimension; + return ret; + }, + __wbg_maxDynamicStorageBuffersPerPipelineLayout_226b0b70910aa16c: function(arg0) { + const ret = arg0.maxDynamicStorageBuffersPerPipelineLayout; + return ret; + }, + __wbg_maxDynamicUniformBuffersPerPipelineLayout_0e835fda711fc7e6: function(arg0) { + const ret = arg0.maxDynamicUniformBuffersPerPipelineLayout; + return ret; + }, + __wbg_maxInterStageShaderVariables_8c4a1d727e2aa35a: function(arg0) { + const ret = arg0.maxInterStageShaderVariables; + return ret; + }, + __wbg_maxSampledTexturesPerShaderStage_6675f5e91d9a728a: function(arg0) { + const ret = arg0.maxSampledTexturesPerShaderStage; + return ret; + }, + __wbg_maxSamplersPerShaderStage_1910fa38a6ed1e1f: function(arg0) { + const ret = arg0.maxSamplersPerShaderStage; + return ret; + }, + __wbg_maxStorageBufferBindingSize_2e244bded070b18d: function(arg0) { + const ret = arg0.maxStorageBufferBindingSize; + return ret; + }, + __wbg_maxStorageBuffersPerShaderStage_a285f3ebca51ca0d: function(arg0) { + const ret = arg0.maxStorageBuffersPerShaderStage; + return ret; + }, + __wbg_maxStorageTexturesPerShaderStage_7aa946f0fc322a2b: function(arg0) { + const ret = arg0.maxStorageTexturesPerShaderStage; + return ret; + }, + __wbg_maxTextureArrayLayers_0e699147ad00502d: function(arg0) { + const ret = arg0.maxTextureArrayLayers; + return ret; + }, + __wbg_maxTextureDimension1D_aabf6add54decfe2: function(arg0) { + const ret = arg0.maxTextureDimension1D; + return ret; + }, + __wbg_maxTextureDimension2D_dd598b27e9c0c1c4: function(arg0) { + const ret = arg0.maxTextureDimension2D; + return ret; + }, + __wbg_maxTextureDimension3D_f944266c65dfd1a9: function(arg0) { + const ret = arg0.maxTextureDimension3D; + return ret; + }, + __wbg_maxUniformBufferBindingSize_59fa6be7cfbeeb53: function(arg0) { + const ret = arg0.maxUniformBufferBindingSize; + return ret; + }, + __wbg_maxUniformBuffersPerShaderStage_bee5f00a4d706c7f: function(arg0) { + const ret = arg0.maxUniformBuffersPerShaderStage; + return ret; + }, + __wbg_maxVertexAttributes_5cf6392c4e9033fe: function(arg0) { + const ret = arg0.maxVertexAttributes; + return ret; + }, + __wbg_maxVertexBufferArrayStride_548baa887375d865: function(arg0) { + const ret = arg0.maxVertexBufferArrayStride; + return ret; + }, + __wbg_maxVertexBuffers_75d881156591f5da: function(arg0) { + const ret = arg0.maxVertexBuffers; + return ret; + }, + __wbg_message_2aad50368e15e8f1: function(arg0, arg1) { + const ret = arg1.message; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_message_ab4cad9eeb386607: function(arg0, arg1) { + const ret = arg1.message; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_message_d988ea596c5f5c9a: function(arg0, arg1) { + const ret = arg1.message; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_metaKey_9c3be2ab835b0148: function(arg0) { + const ret = arg0.metaKey; + return ret; + }, + __wbg_metaKey_fb78da4d237d5bbb: function(arg0) { + const ret = arg0.metaKey; + return ret; + }, + __wbg_minStorageBufferOffsetAlignment_5ba9b77792bdadb3: function(arg0) { + const ret = arg0.minStorageBufferOffsetAlignment; + return ret; + }, + __wbg_minUniformBufferOffsetAlignment_ab7d52a5293b22bd: function(arg0) { + const ret = arg0.minUniformBufferOffsetAlignment; + return ret; + }, + __wbg_name_06fefa2542c6ce51: function(arg0, arg1) { + const ret = arg1.name; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_name_30c2cf5d3e6226e8: function(arg0, arg1) { + const ret = arg1.name; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_navigator_2156486643462a87: function(arg0) { + const ret = arg0.navigator; + return ret; + }, + __wbg_navigator_c9bce48d4b578c9c: function(arg0) { + const ret = arg0.navigator; + return ret; + }, + __wbg_new_1a8d2827bd9e1a2e: function() { return handleError(function (arg0) { + const ret = new ResizeObserver(arg0); + return ret; + }, arguments); }, + __wbg_new_1dbf7428bba60a42: function(arg0) { + const ret = new Uint8Array(arg0); + return ret; + }, + __wbg_new_2e41357094e99294: function() { return handleError(function () { + const ret = new AbortController(); + return ret; + }, arguments); }, + __wbg_new_5502aad30c185fc8: function(arg0, arg1) { + try { + var state0 = {a: arg0, b: arg1}; + var cb0 = (arg0, arg1) => { + const a = state0.a; + state0.a = 0; + try { + return wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Function_fn_wasm_bindgen_54f023e2846dbff4___JsValue_____wasm_bindgen_54f023e2846dbff4___sys__Undefined___js_sys_526e9b82b0b84cf5___Function_fn_wasm_bindgen_54f023e2846dbff4___JsValue_____wasm_bindgen_54f023e2846dbff4___sys__Undefined_______true_(a, state0.b, arg0, arg1); + } finally { + state0.a = a; + } + }; + const ret = new Promise(cb0); + return ret; + } finally { + state0.a = 0; + } + }, + __wbg_new_617a8cdb8bb1130e: function() { + const ret = new Object(); + return ret; + }, + __wbg_new_9090cad7737fef55: function() { + const ret = new Error(); + return ret; + }, + __wbg_new_a217df4351db4b9b: function() { return handleError(function (arg0, arg1) { + const ret = new OffscreenCanvas(arg0 >>> 0, arg1 >>> 0); + return ret; + }, arguments); }, + __wbg_new_ae4555a03ebb1118: function() { return handleError(function () { + const ret = new FileReader(); + return ret; + }, arguments); }, + __wbg_new_ee2291f50781bf1d: function() { + const ret = new Array(); + return ret; + }, + __wbg_new_from_slice_9a868026ffa4208a: function(arg0, arg1) { + const ret = new Uint8Array(getArrayU8FromWasm0(arg0, arg1)); + return ret; + }, + __wbg_new_typed_689a3a281a8d4da6: function() { + const ret = new Object(); + return ret; + }, + __wbg_new_with_byte_offset_and_length_2f5d7fc2a828b74d: function(arg0, arg1, arg2) { + const ret = new Uint8Array(arg0, arg1 >>> 0, arg2 >>> 0); + return ret; + }, + __wbg_new_with_record_from_str_to_blob_promise_d8b08e210be436ad: function() { return handleError(function (arg0) { + const ret = new ClipboardItem(arg0); + return ret; + }, arguments); }, + __wbg_new_with_u8_array_sequence_and_options_fccc08fe93f4b8fd: function() { return handleError(function (arg0, arg1) { + const ret = new Blob(arg0, arg1); + return ret; + }, arguments); }, + __wbg_new_with_u8_array_sequence_f380e3e783ae5617: function() { return handleError(function (arg0) { + const ret = new Blob(arg0); + return ret; + }, arguments); }, + __wbg_nextSibling_e5ecc9bf11c2365d: function(arg0) { + const ret = arg0.nextSibling; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_now_aa4ccb83129e9e55: function() { + const ret = Date.now(); + return ret; + }, + __wbg_now_d0b7f4bea9f38490: function(arg0) { + const ret = arg0.now(); + return ret; + }, + __wbg_now_e7c6795a7f81e10f: function(arg0) { + const ret = arg0.now(); + return ret; + }, + __wbg_objectStore_43178e7a3459e234: function() { return handleError(function (arg0, arg1, arg2) { + const ret = arg0.objectStore(getStringFromWasm0(arg1, arg2)); + return ret; + }, arguments); }, + __wbg_observe_d2d34ca6fcb958b1: function(arg0, arg1, arg2) { + arg0.observe(arg1, arg2); + }, + __wbg_of_20798cb14708764f: function(arg0, arg1) { + const ret = Array.of(arg0, arg1); + return ret; + }, + __wbg_of_d5dbecdc59e02e34: function(arg0) { + const ret = Array.of(arg0); + return ret; + }, + __wbg_offsetLeft_eef008f2ccb3b242: function(arg0) { + const ret = arg0.offsetLeft; + return ret; + }, + __wbg_offsetTop_c36b688834dcdce3: function(arg0) { + const ret = arg0.offsetTop; + return ret; + }, + __wbg_ok_125878a7db256ecb: function(arg0) { + const ret = arg0.ok; + return ret; + }, + __wbg_onSubmittedWorkDone_1190213cee1ecf7e: function(arg0) { + const ret = arg0.onSubmittedWorkDone(); + return ret; + }, + __wbg_openCursor_6efcf867fdf4e754: function() { return handleError(function (arg0) { + const ret = arg0.openCursor(); + return ret; + }, arguments); }, + __wbg_open_d426932d10a5f130: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + const ret = arg0.open(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, arguments); }, + __wbg_open_dbf85f9611885c1b: function() { return handleError(function (arg0, arg1, arg2, arg3) { + const ret = arg0.open(getStringFromWasm0(arg1, arg2), arg3 >>> 0); + return ret; + }, arguments); }, + __wbg_origin_96d72883773c6d82: function() { return handleError(function (arg0, arg1) { + const ret = arg1.origin; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, arguments); }, + __wbg_parentNode_32afd0d7ad7dca98: function(arg0) { + const ret = arg0.parentNode; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_performance_3fcf6e32a7e1ed0a: function(arg0) { + const ret = arg0.performance; + return ret; + }, + __wbg_performance_d0d7b03fc649b694: function(arg0) { + const ret = arg0.performance; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_pixelStorei_af18e636b3e7b725: function(arg0, arg1, arg2) { + arg0.pixelStorei(arg1 >>> 0, arg2); + }, + __wbg_pixelStorei_cb4e43466f5b8703: function(arg0, arg1, arg2) { + arg0.pixelStorei(arg1 >>> 0, arg2); + }, + __wbg_pointerType_2e8b8270da489520: function(arg0, arg1) { + const ret = arg1.pointerType; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_polygonOffset_81dc8ca84e29572b: function(arg0, arg1, arg2) { + arg0.polygonOffset(arg1, arg2); + }, + __wbg_polygonOffset_8f922d9173d8849d: function(arg0, arg1, arg2) { + arg0.polygonOffset(arg1, arg2); + }, + __wbg_popErrorScope_182b8e03671d81ef: function(arg0) { + const ret = arg0.popErrorScope(); + return ret; + }, + __wbg_port_73ba89eedf847423: function() { return handleError(function (arg0, arg1) { + const ret = arg1.port; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, arguments); }, + __wbg_pressure_0f845ab1b47c1eb9: function(arg0) { + const ret = arg0.pressure; + return ret; + }, + __wbg_preventDefault_af59afb0f0a02e20: function(arg0) { + arg0.preventDefault(); + }, + __wbg_protocol_c29b929bd710072b: function() { return handleError(function (arg0, arg1) { + const ret = arg1.protocol; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, arguments); }, + __wbg_prototypesetcall_bc27214492979395: function(arg0, arg1, arg2) { + Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), arg2); + }, + __wbg_pushErrorScope_fa7df784c43bdb51: function(arg0, arg1) { + arg0.pushErrorScope(__wbindgen_enum_GpuErrorFilter[arg1]); + }, + __wbg_push_2baf45db356cf468: function(arg0, arg1) { + const ret = arg0.push(arg1); + return ret; + }, + __wbg_put_378af428b16ba8f2: function() { return handleError(function (arg0, arg1, arg2) { + const ret = arg0.put(arg1, arg2); + return ret; + }, arguments); }, + __wbg_queryCounterEXT_9016a6ffa350b4b2: function(arg0, arg1, arg2) { + arg0.queryCounterEXT(arg1, arg2 >>> 0); + }, + __wbg_querySelectorAll_6aebfe3df1fb2014: function() { return handleError(function (arg0, arg1, arg2) { + const ret = arg0.querySelectorAll(getStringFromWasm0(arg1, arg2)); + return ret; + }, arguments); }, + __wbg_querySelector_ecbc2550705b235f: function() { return handleError(function (arg0, arg1, arg2) { + const ret = arg0.querySelector(getStringFromWasm0(arg1, arg2)); + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, arguments); }, + __wbg_queueMicrotask_9833f9a49df95a49: function(arg0) { + const ret = arg0.queueMicrotask; + return ret; + }, + __wbg_queueMicrotask_a72f977e97f23c5f: function(arg0) { + queueMicrotask(arg0); + }, + __wbg_queue_7b62c28143d44293: function(arg0) { + const ret = arg0.queue; + return ret; + }, + __wbg_race_a3adff39477a2837: function(arg0) { + const ret = Promise.race(arg0); + return ret; + }, + __wbg_readAsArrayBuffer_b7dbf754ec0fe4bc: function() { return handleError(function (arg0, arg1) { + arg0.readAsArrayBuffer(arg1); + }, arguments); }, + __wbg_readBuffer_b5d9a34a2f3d20d5: function(arg0, arg1) { + arg0.readBuffer(arg1 >>> 0); + }, + __wbg_readPixels_31e44e70558ac590: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) { + arg0.readPixels(arg1, arg2, arg3, arg4, arg5 >>> 0, arg6 >>> 0, arg7); + }, arguments); }, + __wbg_readPixels_3321086a7818a739: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) { + arg0.readPixels(arg1, arg2, arg3, arg4, arg5 >>> 0, arg6 >>> 0, arg7); + }, arguments); }, + __wbg_readPixels_eb030cd9976eeca5: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) { + arg0.readPixels(arg1, arg2, arg3, arg4, arg5 >>> 0, arg6 >>> 0, arg7); + }, arguments); }, + __wbg_reason_b4fa3af867fc4430: function(arg0) { + const ret = arg0.reason; + return (__wbindgen_enum_GpuDeviceLostReason.indexOf(ret) + 1 || 3) - 1; + }, + __wbg_removeChild_3745fc2545da50fa: function() { return handleError(function (arg0, arg1) { + const ret = arg0.removeChild(arg1); + return ret; + }, arguments); }, + __wbg_removeEventListener_6e68185345978771: function() { return handleError(function (arg0, arg1, arg2, arg3) { + arg0.removeEventListener(getStringFromWasm0(arg1, arg2), arg3); + }, arguments); }, + __wbg_removeItem_f7b602722ed566dd: function() { return handleError(function (arg0, arg1, arg2) { + arg0.removeItem(getStringFromWasm0(arg1, arg2)); + }, arguments); }, + __wbg_remove_9a5288388316028c: function(arg0) { + arg0.remove(); + }, + __wbg_renderbufferStorageMultisample_ed16f3ef446e3bc7: function(arg0, arg1, arg2, arg3, arg4, arg5) { + arg0.renderbufferStorageMultisample(arg1 >>> 0, arg2, arg3 >>> 0, arg4, arg5); + }, + __wbg_renderbufferStorage_52b131bbf3112b3a: function(arg0, arg1, arg2, arg3, arg4) { + arg0.renderbufferStorage(arg1 >>> 0, arg2 >>> 0, arg3, arg4); + }, + __wbg_renderbufferStorage_bca487b0dea425b8: function(arg0, arg1, arg2, arg3, arg4) { + arg0.renderbufferStorage(arg1 >>> 0, arg2 >>> 0, arg3, arg4); + }, + __wbg_requestAdapter_a539af006419f2e9: function(arg0, arg1) { + const ret = arg0.requestAdapter(arg1); + return ret; + }, + __wbg_requestAdapter_b35b01d9a8802935: function(arg0) { + const ret = arg0.requestAdapter(); + return ret; + }, + __wbg_requestAnimationFrame_7b526ab7aa550c74: function() { return handleError(function (arg0, arg1) { + const ret = arg0.requestAnimationFrame(arg1); + return ret; + }, arguments); }, + __wbg_requestDevice_5cb8a582e55d08cb: function(arg0, arg1) { + const ret = arg0.requestDevice(arg1); + return ret; + }, + __wbg_resolve_0076e10020304ede: function(arg0) { + const ret = Promise.resolve(arg0); + return ret; + }, + __wbg_result_66ae42c57a28369f: function() { return handleError(function (arg0) { + const ret = arg0.result; + return ret; + }, arguments); }, + __wbg_result_ea60156c5cd4726f: function() { return handleError(function (arg0) { + const ret = arg0.result; + return ret; + }, arguments); }, + __wbg_revokeObjectURL_479ff72c2d109d80: function() { return handleError(function (arg0, arg1) { + URL.revokeObjectURL(getStringFromWasm0(arg0, arg1)); + }, arguments); }, + __wbg_right_1dca6be6342de981: function(arg0) { + const ret = arg0.right; + return ret; + }, + __wbg_samplerParameterf_2d62cb907392e2d6: function(arg0, arg1, arg2, arg3) { + arg0.samplerParameterf(arg1, arg2 >>> 0, arg3); + }, + __wbg_samplerParameteri_a5615e67ed0b654b: function(arg0, arg1, arg2, arg3) { + arg0.samplerParameteri(arg1, arg2 >>> 0, arg3); + }, + __wbg_scissor_12ddc324094acd50: function(arg0, arg1, arg2, arg3, arg4) { + arg0.scissor(arg1, arg2, arg3, arg4); + }, + __wbg_scissor_a9468482697c2bdb: function(arg0, arg1, arg2, arg3, arg4) { + arg0.scissor(arg1, arg2, arg3, arg4); + }, + __wbg_search_31c06ba77ebf51f4: function() { return handleError(function (arg0, arg1) { + const ret = arg1.search; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, arguments); }, + __wbg_selectionEnd_582c88abcc45a9f3: function() { return handleError(function (arg0) { + const ret = arg0.selectionEnd; + return isLikeNone(ret) ? Number.MAX_SAFE_INTEGER : (ret) >>> 0; + }, arguments); }, + __wbg_selectionStart_b1db69e8858218c6: function() { return handleError(function (arg0) { + const ret = arg0.selectionStart; + return isLikeNone(ret) ? Number.MAX_SAFE_INTEGER : (ret) >>> 0; + }, arguments); }, + __wbg_setAttribute_9e7d603908f63705: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + arg0.setAttribute(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); + }, arguments); }, + __wbg_setBindGroup_11bdbb60cc8b54b9: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6) { + arg0.setBindGroup(arg1 >>> 0, arg2, getArrayU32FromWasm0(arg3, arg4), arg5, arg6 >>> 0); + }, arguments); }, + __wbg_setBindGroup_418c3e0eb6943ce0: function(arg0, arg1, arg2) { + arg0.setBindGroup(arg1 >>> 0, arg2); + }, + __wbg_setIndexBuffer_01327df91742b73e: function(arg0, arg1, arg2, arg3) { + arg0.setIndexBuffer(arg1, __wbindgen_enum_GpuIndexFormat[arg2], arg3); + }, + __wbg_setIndexBuffer_241097e303986c14: function(arg0, arg1, arg2, arg3, arg4) { + arg0.setIndexBuffer(arg1, __wbindgen_enum_GpuIndexFormat[arg2], arg3, arg4); + }, + __wbg_setInterval_aa4e3d3f590ce835: function() { return handleError(function (arg0, arg1, arg2) { + const ret = arg0.setInterval(arg1, arg2); + return ret; + }, arguments); }, + __wbg_setItem_c5fb0966b484ecd3: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + arg0.setItem(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); + }, arguments); }, + __wbg_setPipeline_b6f981027e02cd16: function(arg0, arg1) { + arg0.setPipeline(arg1); + }, + __wbg_setProperty_097bc3d55ce44513: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + arg0.setProperty(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); + }, arguments); }, + __wbg_setScissorRect_889235eeb784732b: function(arg0, arg1, arg2, arg3, arg4) { + arg0.setScissorRect(arg1 >>> 0, arg2 >>> 0, arg3 >>> 0, arg4 >>> 0); + }, + __wbg_setTimeout_db7bbc18a17e152a: function() { return handleError(function (arg0, arg1, arg2) { + const ret = arg0.setTimeout(arg1, arg2); + return ret; + }, arguments); }, + __wbg_setVertexBuffer_6db3b60e99280744: function(arg0, arg1, arg2, arg3) { + arg0.setVertexBuffer(arg1 >>> 0, arg2, arg3); + }, + __wbg_setVertexBuffer_cbf4ca1627c02f4c: function(arg0, arg1, arg2, arg3, arg4) { + arg0.setVertexBuffer(arg1 >>> 0, arg2, arg3, arg4); + }, + __wbg_setViewport_c0be08dcc8965ccf: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6) { + arg0.setViewport(arg1, arg2, arg3, arg4, arg5, arg6); + }, + __wbg_set_145a351398b48c65: function() { return handleError(function (arg0, arg1, arg2) { + const ret = Reflect.set(arg0, arg1, arg2); + return ret; + }, arguments); }, + __wbg_set_34d08fd992d43d61: function(arg0, arg1, arg2) { + arg0.set(arg1, arg2 >>> 0); + }, + __wbg_set_a_82818effc94f6256: function(arg0, arg1) { + arg0.a = arg1; + }, + __wbg_set_accept_06d626c479e21e36: function(arg0, arg1, arg2) { + arg0.accept = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_access_a099cfbbeec9b96f: function(arg0, arg1) { + arg0.access = __wbindgen_enum_GpuStorageTextureAccess[arg1]; + }, + __wbg_set_address_mode_u_a68737cf5d288f95: function(arg0, arg1) { + arg0.addressModeU = __wbindgen_enum_GpuAddressMode[arg1]; + }, + __wbg_set_address_mode_v_b1c3c45933f540d1: function(arg0, arg1) { + arg0.addressModeV = __wbindgen_enum_GpuAddressMode[arg1]; + }, + __wbg_set_address_mode_w_889c31cf7022c764: function(arg0, arg1) { + arg0.addressModeW = __wbindgen_enum_GpuAddressMode[arg1]; + }, + __wbg_set_alpha_106f21a936a85eba: function(arg0, arg1) { + arg0.alpha = arg1; + }, + __wbg_set_alpha_mode_5544568dbac50280: function(arg0, arg1) { + arg0.alphaMode = __wbindgen_enum_GpuCanvasAlphaMode[arg1]; + }, + __wbg_set_alpha_to_coverage_enabled_3372ce329447b8f1: function(arg0, arg1) { + arg0.alphaToCoverageEnabled = arg1 !== 0; + }, + __wbg_set_array_layer_count_22afa0a979e4ad55: function(arg0, arg1) { + arg0.arrayLayerCount = arg1 >>> 0; + }, + __wbg_set_array_stride_f64_6816040e5e7598c3: function(arg0, arg1) { + arg0.arrayStride = arg1; + }, + __wbg_set_aspect_a48d046965270281: function(arg0, arg1) { + arg0.aspect = __wbindgen_enum_GpuTextureAspect[arg1]; + }, + __wbg_set_aspect_b1a9909bf315433f: function(arg0, arg1) { + arg0.aspect = __wbindgen_enum_GpuTextureAspect[arg1]; + }, + __wbg_set_attributes_9e38cb1dde387a5b: function(arg0, arg1, arg2) { + arg0.attributes = getArrayJsValueViewFromWasm0(arg1, arg2); + }, + __wbg_set_b_a3297ee7e7cac3a8: function(arg0, arg1) { + arg0.b = arg1; + }, + __wbg_set_base_array_layer_2435ba92c80346ae: function(arg0, arg1) { + arg0.baseArrayLayer = arg1 >>> 0; + }, + __wbg_set_base_mip_level_8b6093e875e7c65d: function(arg0, arg1) { + arg0.baseMipLevel = arg1 >>> 0; + }, + __wbg_set_beginning_of_pass_write_index_e552c5e8b8bbf52f: function(arg0, arg1) { + arg0.beginningOfPassWriteIndex = arg1 >>> 0; + }, + __wbg_set_bind_group_layouts_458c44ba55100b82: function(arg0, arg1, arg2) { + arg0.bindGroupLayouts = getArrayJsValueViewFromWasm0(arg1, arg2); + }, + __wbg_set_binding_81b3fac7f7acaf8d: function(arg0, arg1) { + arg0.binding = arg1 >>> 0; + }, + __wbg_set_binding_b6cee57f35ac5190: function(arg0, arg1) { + arg0.binding = arg1 >>> 0; + }, + __wbg_set_blend_1a801617945f7945: function(arg0, arg1) { + arg0.blend = arg1; + }, + __wbg_set_box_921bf38648f10dfe: function(arg0, arg1) { + arg0.box = __wbindgen_enum_ResizeObserverBoxOptions[arg1]; + }, + __wbg_set_buffer_1548ae88a9188037: function(arg0, arg1) { + arg0.buffer = arg1; + }, + __wbg_set_buffer_8d0ac64ad20dfc84: function(arg0, arg1) { + arg0.buffer = arg1; + }, + __wbg_set_buffer_910a40a90f97cfca: function(arg0, arg1) { + arg0.buffer = arg1; + }, + __wbg_set_buffers_5d0e0c50791f710e: function(arg0, arg1, arg2) { + arg0.buffers = getArrayJsValueViewFromWasm0(arg1, arg2); + }, + __wbg_set_bytes_per_row_1e824a5502b54b3d: function(arg0, arg1) { + arg0.bytesPerRow = arg1 >>> 0; + }, + __wbg_set_bytes_per_row_c28583f0063160f1: function(arg0, arg1) { + arg0.bytesPerRow = arg1 >>> 0; + }, + __wbg_set_className_541fce5cd31918aa: function(arg0, arg1, arg2) { + arg0.className = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_clear_value_gpu_color_dict_a9f763e8372ac1de: function(arg0, arg1) { + arg0.clearValue = arg1; + }, + __wbg_set_code_5d5b0b9e2fd0dca7: function(arg0, arg1, arg2) { + arg0.code = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_color_8ecace4011f47d2e: function(arg0, arg1) { + arg0.color = arg1; + }, + __wbg_set_color_attachments_622fe2d5997fda7a: function(arg0, arg1, arg2) { + arg0.colorAttachments = getArrayJsValueViewFromWasm0(arg1, arg2); + }, + __wbg_set_compare_080c9e492ff36990: function(arg0, arg1) { + arg0.compare = __wbindgen_enum_GpuCompareFunction[arg1]; + }, + __wbg_set_compare_817cf3695599eaa6: function(arg0, arg1) { + arg0.compare = __wbindgen_enum_GpuCompareFunction[arg1]; + }, + __wbg_set_count_8ff0c9474e39a849: function(arg0, arg1) { + arg0.count = arg1 >>> 0; + }, + __wbg_set_cull_mode_85d2b4ab0ce3a564: function(arg0, arg1) { + arg0.cullMode = __wbindgen_enum_GpuCullMode[arg1]; + }, + __wbg_set_depth_bias_95abf479cae3f3cd: function(arg0, arg1) { + arg0.depthBias = arg1; + }, + __wbg_set_depth_bias_clamp_ba3d0b8348151350: function(arg0, arg1) { + arg0.depthBiasClamp = arg1; + }, + __wbg_set_depth_bias_slope_scale_6b2584d93f5b9cd2: function(arg0, arg1) { + arg0.depthBiasSlopeScale = arg1; + }, + __wbg_set_depth_clear_value_e30a4c754c6b3b26: function(arg0, arg1) { + arg0.depthClearValue = arg1; + }, + __wbg_set_depth_compare_a90de4e3714397ab: function(arg0, arg1) { + arg0.depthCompare = __wbindgen_enum_GpuCompareFunction[arg1]; + }, + __wbg_set_depth_fail_op_b5c64541d1b6b482: function(arg0, arg1) { + arg0.depthFailOp = __wbindgen_enum_GpuStencilOperation[arg1]; + }, + __wbg_set_depth_load_op_932888016d762d3e: function(arg0, arg1) { + arg0.depthLoadOp = __wbindgen_enum_GpuLoadOp[arg1]; + }, + __wbg_set_depth_or_array_layers_e2f074a0284e4806: function(arg0, arg1) { + arg0.depthOrArrayLayers = arg1 >>> 0; + }, + __wbg_set_depth_read_only_be790175a1c2db9a: function(arg0, arg1) { + arg0.depthReadOnly = arg1 !== 0; + }, + __wbg_set_depth_stencil_attachment_54a8922f5fbe08bf: function(arg0, arg1) { + arg0.depthStencilAttachment = arg1; + }, + __wbg_set_depth_stencil_b7cffc59ad4da529: function(arg0, arg1) { + arg0.depthStencil = arg1; + }, + __wbg_set_depth_store_op_9054814f164ab55d: function(arg0, arg1) { + arg0.depthStoreOp = __wbindgen_enum_GpuStoreOp[arg1]; + }, + __wbg_set_depth_write_enabled_31a821ee1fb3b0b3: function(arg0, arg1) { + arg0.depthWriteEnabled = arg1 !== 0; + }, + __wbg_set_device_210484a77b675c9c: function(arg0, arg1) { + arg0.device = arg1; + }, + __wbg_set_dimension_3da9d03131a9f446: function(arg0, arg1) { + arg0.dimension = __wbindgen_enum_GpuTextureDimension[arg1]; + }, + __wbg_set_dimension_56332450afa3e0c0: function(arg0, arg1) { + arg0.dimension = __wbindgen_enum_GpuTextureViewDimension[arg1]; + }, + __wbg_set_download_327e0fbad75893f0: function(arg0, arg1, arg2) { + arg0.download = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_dst_factor_865ba9aaf187890c: function(arg0, arg1) { + arg0.dstFactor = __wbindgen_enum_GpuBlendFactor[arg1]; + }, + __wbg_set_end_of_pass_write_index_8f164f9e60d4ad16: function(arg0, arg1) { + arg0.endOfPassWriteIndex = arg1 >>> 0; + }, + __wbg_set_entries_6f866302103b81e9: function(arg0, arg1, arg2) { + arg0.entries = getArrayJsValueViewFromWasm0(arg1, arg2); + }, + __wbg_set_entries_f26b77ab9548e906: function(arg0, arg1, arg2) { + arg0.entries = getArrayJsValueViewFromWasm0(arg1, arg2); + }, + __wbg_set_entry_point_71cef95c137b5774: function(arg0, arg1, arg2) { + arg0.entryPoint = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_entry_point_b70f98f5025a114d: function(arg0, arg1, arg2) { + arg0.entryPoint = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_external_texture_7f966c604c4f8098: function(arg0, arg1) { + arg0.externalTexture = arg1; + }, + __wbg_set_fail_op_d59d0187e4111dfe: function(arg0, arg1) { + arg0.failOp = __wbindgen_enum_GpuStencilOperation[arg1]; + }, + __wbg_set_format_23f7f32549751d43: function(arg0, arg1) { + arg0.format = __wbindgen_enum_GpuTextureFormat[arg1]; + }, + __wbg_set_format_283dca56552f07a3: function(arg0, arg1) { + arg0.format = __wbindgen_enum_GpuTextureFormat[arg1]; + }, + __wbg_set_format_5080a858117ad2c1: function(arg0, arg1) { + arg0.format = __wbindgen_enum_GpuVertexFormat[arg1]; + }, + __wbg_set_format_66735b94bd868ba2: function(arg0, arg1) { + arg0.format = __wbindgen_enum_GpuTextureFormat[arg1]; + }, + __wbg_set_format_7f2bdbfb101b1ae1: function(arg0, arg1) { + arg0.format = __wbindgen_enum_GpuTextureFormat[arg1]; + }, + __wbg_set_format_92732ea75d3b79f5: function(arg0, arg1) { + arg0.format = __wbindgen_enum_GpuTextureFormat[arg1]; + }, + __wbg_set_format_f009e603f7d4c28e: function(arg0, arg1) { + arg0.format = __wbindgen_enum_GpuTextureFormat[arg1]; + }, + __wbg_set_fragment_d2b0ec97d7cf8d47: function(arg0, arg1) { + arg0.fragment = arg1; + }, + __wbg_set_front_face_d3f8a2e07e7b25dd: function(arg0, arg1) { + arg0.frontFace = __wbindgen_enum_GpuFrontFace[arg1]; + }, + __wbg_set_g_b527ee8a9bed553d: function(arg0, arg1) { + arg0.g = arg1; + }, + __wbg_set_has_dynamic_offset_0c72ffa900c5a269: function(arg0, arg1) { + arg0.hasDynamicOffset = arg1 !== 0; + }, + __wbg_set_height_c9789c1c77eaedff: function(arg0, arg1) { + arg0.height = arg1 >>> 0; + }, + __wbg_set_height_f6619158e5735877: function(arg0, arg1) { + arg0.height = arg1 >>> 0; + }, + __wbg_set_height_fde391767df1ce27: function(arg0, arg1) { + arg0.height = arg1 >>> 0; + }, + __wbg_set_href_f7219c6cbf6bedc3: function(arg0, arg1, arg2) { + arg0.href = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_id_60955e6018d03b26: function(arg0, arg1, arg2) { + arg0.id = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_innerHTML_7af59a832a09a074: function(arg0, arg1, arg2) { + arg0.innerHTML = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_innerText_d46aad31465ed925: function(arg0, arg1, arg2) { + arg0.innerText = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_integrity_26f89e5d26fc7ef5: function(arg0, arg1, arg2) { + arg0.integrity = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_label_17202740051e9722: function(arg0, arg1, arg2) { + arg0.label = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_label_2fefb39c0e0dbbe8: function(arg0, arg1, arg2) { + arg0.label = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_label_3cb2322e6f6db14c: function(arg0, arg1, arg2) { + arg0.label = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_label_3f2ccaafef5ff7c9: function(arg0, arg1, arg2) { + arg0.label = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_label_612add98a4398f92: function(arg0, arg1, arg2) { + arg0.label = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_label_70a09ee68d6b1b26: function(arg0, arg1, arg2) { + arg0.label = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_label_92cd3811e96b487c: function(arg0, arg1, arg2) { + arg0.label = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_label_9c2a186152427ee0: function(arg0, arg1, arg2) { + arg0.label = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_label_c3eaf136aa464cba: function(arg0, arg1, arg2) { + arg0.label = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_label_c7987704d29f284b: function(arg0, arg1, arg2) { + arg0.label = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_label_cfe64bca8945ee30: function(arg0, arg1, arg2) { + arg0.label = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_label_e02179cf97e95763: function(arg0, arg1, arg2) { + arg0.label = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_label_ee172cd5f6a96961: function(arg0, arg1, arg2) { + arg0.label = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_layout_454e3a091b390cd4: function(arg0, arg1) { + arg0.layout = arg1; + }, + __wbg_set_layout_75dc1ca3f2421cff: function(arg0, arg1) { + arg0.layout = arg1; + }, + __wbg_set_layout_gpu_auto_layout_mode_06a2b95af1043098: function(arg0, arg1) { + arg0.layout = __wbindgen_enum_GpuAutoLayoutMode[arg1]; + }, + __wbg_set_load_op_c56b1269acc2d51f: function(arg0, arg1) { + arg0.loadOp = __wbindgen_enum_GpuLoadOp[arg1]; + }, + __wbg_set_lod_max_clamp_db24179f67f3aa31: function(arg0, arg1) { + arg0.lodMaxClamp = arg1; + }, + __wbg_set_lod_min_clamp_2bbce566e9fefa04: function(arg0, arg1) { + arg0.lodMinClamp = arg1; + }, + __wbg_set_mag_filter_db8e6b42d4f8846d: function(arg0, arg1) { + arg0.magFilter = __wbindgen_enum_GpuFilterMode[arg1]; + }, + __wbg_set_mapped_at_creation_3f320fef6761b02c: function(arg0, arg1) { + arg0.mappedAtCreation = arg1 !== 0; + }, + __wbg_set_mask_c1079e551ec360dc: function(arg0, arg1) { + arg0.mask = arg1 >>> 0; + }, + __wbg_set_max_anisotropy_84749fdcec362dc4: function(arg0, arg1) { + arg0.maxAnisotropy = arg1; + }, + __wbg_set_min_binding_size_f64_897e3cd4496ddec9: function(arg0, arg1) { + arg0.minBindingSize = arg1; + }, + __wbg_set_min_filter_d435bbfc5a637757: function(arg0, arg1) { + arg0.minFilter = __wbindgen_enum_GpuFilterMode[arg1]; + }, + __wbg_set_mip_level_count_047936c630acee7b: function(arg0, arg1) { + arg0.mipLevelCount = arg1 >>> 0; + }, + __wbg_set_mip_level_count_44bc46a1ae6f6daa: function(arg0, arg1) { + arg0.mipLevelCount = arg1 >>> 0; + }, + __wbg_set_mip_level_f3745730372683d5: function(arg0, arg1) { + arg0.mipLevel = arg1 >>> 0; + }, + __wbg_set_mipmap_filter_62fb49a84b0747ff: function(arg0, arg1) { + arg0.mipmapFilter = __wbindgen_enum_GpuMipmapFilterMode[arg1]; + }, + __wbg_set_mode_7edfbc344ef9c650: function(arg0, arg1) { + arg0.mode = __wbindgen_enum_GpuCanvasToneMappingMode[arg1]; + }, + __wbg_set_module_392eeaa269f203b0: function(arg0, arg1) { + arg0.module = arg1; + }, + __wbg_set_module_715d37652c4998ec: function(arg0, arg1) { + arg0.module = arg1; + }, + __wbg_set_multiple_fdd0574cdb0b0a1f: function(arg0, arg1) { + arg0.multiple = arg1 !== 0; + }, + __wbg_set_multisample_ff72a7a5456cbeb7: function(arg0, arg1) { + arg0.multisample = arg1; + }, + __wbg_set_multisampled_039f032dc4b67367: function(arg0, arg1) { + arg0.multisampled = arg1 !== 0; + }, + __wbg_set_offset_f64_127e8a0aa5c5485a: function(arg0, arg1) { + arg0.offset = arg1; + }, + __wbg_set_offset_f64_457756429ede426d: function(arg0, arg1) { + arg0.offset = arg1; + }, + __wbg_set_offset_f64_a903425d5a8e5815: function(arg0, arg1) { + arg0.offset = arg1; + }, + __wbg_set_offset_f64_d1d115dd438165b5: function(arg0, arg1) { + arg0.offset = arg1; + }, + __wbg_set_once_8c45bbbfb71d1b34: function(arg0, arg1) { + arg0.once = arg1 !== 0; + }, + __wbg_set_onclick_c978dc4919c3c885: function(arg0, arg1) { + arg0.onclick = arg1; + }, + __wbg_set_onload_a85e3f5ed3002dde: function(arg0, arg1) { + arg0.onload = arg1; + }, + __wbg_set_onuncapturederror_bb813f1102da2296: function(arg0, arg1) { + arg0.onuncapturederror = arg1; + }, + __wbg_set_operation_00a77386523b88f9: function(arg0, arg1) { + arg0.operation = __wbindgen_enum_GpuBlendOperation[arg1]; + }, + __wbg_set_origin_gpu_origin_3d_dict_0619d4860adb4eb6: function(arg0, arg1) { + arg0.origin = arg1; + }, + __wbg_set_pass_op_3cf10feb3d76ab97: function(arg0, arg1) { + arg0.passOp = __wbindgen_enum_GpuStencilOperation[arg1]; + }, + __wbg_set_power_preference_b42d00a8facfbade: function(arg0, arg1) { + arg0.powerPreference = __wbindgen_enum_GpuPowerPreference[arg1]; + }, + __wbg_set_prevent_scroll_aaa386836725b8b4: function(arg0, arg1) { + arg0.preventScroll = arg1 !== 0; + }, + __wbg_set_primitive_e796cf76f0ff89f3: function(arg0, arg1) { + arg0.primitive = arg1; + }, + __wbg_set_query_set_f030702f1b69199f: function(arg0, arg1) { + arg0.querySet = arg1; + }, + __wbg_set_r_6ece4d74af63364f: function(arg0, arg1) { + arg0.r = arg1; + }, + __wbg_set_required_features_bbab71414c45e621: function(arg0, arg1, arg2) { + arg0.requiredFeatures = getArrayJsValueViewFromWasm0(arg1, arg2); + }, + __wbg_set_required_limits_837f62d865e7cfac: function(arg0, arg1) { + arg0.requiredLimits = arg1; + }, + __wbg_set_resolve_target_gpu_texture_view_e4c1e3bbb8c27d87: function(arg0, arg1) { + arg0.resolveTarget = arg1; + }, + __wbg_set_resource_8fd8658b30d86ecf: function(arg0, arg1) { + arg0.resource = arg1; + }, + __wbg_set_resource_gpu_buffer_binding_33099b25da65b610: function(arg0, arg1) { + arg0.resource = arg1; + }, + __wbg_set_resource_gpu_texture_view_4cffe7bc7c8e5cbe: function(arg0, arg1) { + arg0.resource = arg1; + }, + __wbg_set_returnValue_60eab0a05ea68fbc: function(arg0, arg1, arg2) { + arg0.returnValue = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_rows_per_image_c6d50d227e634379: function(arg0, arg1) { + arg0.rowsPerImage = arg1 >>> 0; + }, + __wbg_set_rows_per_image_deb456502f23c260: function(arg0, arg1) { + arg0.rowsPerImage = arg1 >>> 0; + }, + __wbg_set_sample_count_481c255a12054e1d: function(arg0, arg1) { + arg0.sampleCount = arg1 >>> 0; + }, + __wbg_set_sample_type_ebc5fcd029513bda: function(arg0, arg1) { + arg0.sampleType = __wbindgen_enum_GpuTextureSampleType[arg1]; + }, + __wbg_set_sampler_89cb4a7efcfc6005: function(arg0, arg1) { + arg0.sampler = arg1; + }, + __wbg_set_shader_location_3fb9f6a012eba494: function(arg0, arg1) { + arg0.shaderLocation = arg1 >>> 0; + }, + __wbg_set_size_f64_2f591b0654540477: function(arg0, arg1) { + arg0.size = arg1; + }, + __wbg_set_size_f64_e844c985b8f95261: function(arg0, arg1) { + arg0.size = arg1; + }, + __wbg_set_size_gpu_extent_3d_dict_adf57388ab1d4f18: function(arg0, arg1) { + arg0.size = arg1; + }, + __wbg_set_src_factor_6f2c9ec8e4d3d979: function(arg0, arg1) { + arg0.srcFactor = __wbindgen_enum_GpuBlendFactor[arg1]; + }, + __wbg_set_stencil_back_c54d0443b8b6a957: function(arg0, arg1) { + arg0.stencilBack = arg1; + }, + __wbg_set_stencil_clear_value_a321b0e045bfd8c2: function(arg0, arg1) { + arg0.stencilClearValue = arg1 >>> 0; + }, + __wbg_set_stencil_front_3ff3f8385852efff: function(arg0, arg1) { + arg0.stencilFront = arg1; + }, + __wbg_set_stencil_load_op_37d20deccb26a0f1: function(arg0, arg1) { + arg0.stencilLoadOp = __wbindgen_enum_GpuLoadOp[arg1]; + }, + __wbg_set_stencil_read_mask_021ef4271b24352c: function(arg0, arg1) { + arg0.stencilReadMask = arg1 >>> 0; + }, + __wbg_set_stencil_read_only_75fe66a2356d6e92: function(arg0, arg1) { + arg0.stencilReadOnly = arg1 !== 0; + }, + __wbg_set_stencil_store_op_501f91638dd386e6: function(arg0, arg1) { + arg0.stencilStoreOp = __wbindgen_enum_GpuStoreOp[arg1]; + }, + __wbg_set_stencil_write_mask_ec1c12237e094bdd: function(arg0, arg1) { + arg0.stencilWriteMask = arg1 >>> 0; + }, + __wbg_set_step_mode_3cbbdeba1e5dfd62: function(arg0, arg1) { + arg0.stepMode = __wbindgen_enum_GpuVertexStepMode[arg1]; + }, + __wbg_set_storage_texture_786aea7c5773b6c1: function(arg0, arg1) { + arg0.storageTexture = arg1; + }, + __wbg_set_store_op_678f33376d741711: function(arg0, arg1) { + arg0.storeOp = __wbindgen_enum_GpuStoreOp[arg1]; + }, + __wbg_set_strip_index_format_70313df755145d5e: function(arg0, arg1) { + arg0.stripIndexFormat = __wbindgen_enum_GpuIndexFormat[arg1]; + }, + __wbg_set_tabIndex_6999832ea5d5197e: function(arg0, arg1) { + arg0.tabIndex = arg1; + }, + __wbg_set_targets_674b33931e512fb1: function(arg0, arg1, arg2) { + arg0.targets = getArrayJsValueViewFromWasm0(arg1, arg2); + }, + __wbg_set_texture_95f2bfdf7767e76f: function(arg0, arg1) { + arg0.texture = arg1; + }, + __wbg_set_texture_a33be3fe02ac6264: function(arg0, arg1) { + arg0.texture = arg1; + }, + __wbg_set_timestamp_writes_de6a09f299b71b76: function(arg0, arg1) { + arg0.timestampWrites = arg1; + }, + __wbg_set_tone_mapping_320c1aad31db2e7f: function(arg0, arg1) { + arg0.toneMapping = arg1; + }, + __wbg_set_topology_b92cfe523bd9653b: function(arg0, arg1) { + arg0.topology = __wbindgen_enum_GpuPrimitiveTopology[arg1]; + }, + __wbg_set_type_19b6e3a56c3fa1f1: function(arg0, arg1, arg2) { + arg0.type = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_type_43e0092f16775979: function(arg0, arg1) { + arg0.type = __wbindgen_enum_GpuSamplerBindingType[arg1]; + }, + __wbg_set_type_79cec55caf4cdb6d: function(arg0, arg1) { + arg0.type = __wbindgen_enum_GpuBufferBindingType[arg1]; + }, + __wbg_set_type_dcf75b2afa60c694: function(arg0, arg1, arg2) { + arg0.type = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_unclipped_depth_32b7caf29fa5633d: function(arg0, arg1) { + arg0.unclippedDepth = arg1 !== 0; + }, + __wbg_set_usage_1ee33d98267e787d: function(arg0, arg1) { + arg0.usage = arg1 >>> 0; + }, + __wbg_set_usage_2365e2704b1fdb10: function(arg0, arg1) { + arg0.usage = arg1 >>> 0; + }, + __wbg_set_usage_d53ee6f0c7aedbfa: function(arg0, arg1) { + arg0.usage = arg1 >>> 0; + }, + __wbg_set_usage_f3e34822998d2147: function(arg0, arg1) { + arg0.usage = arg1 >>> 0; + }, + __wbg_set_value_fbd659f94bfb9181: function(arg0, arg1, arg2) { + arg0.value = getStringFromWasm0(arg1, arg2); + }, + __wbg_set_vertex_77ed7a1229239b5a: function(arg0, arg1) { + arg0.vertex = arg1; + }, + __wbg_set_view_dimension_893e2d16561e56e8: function(arg0, arg1) { + arg0.viewDimension = __wbindgen_enum_GpuTextureViewDimension[arg1]; + }, + __wbg_set_view_dimension_f2c5fe4bf927c3fe: function(arg0, arg1) { + arg0.viewDimension = __wbindgen_enum_GpuTextureViewDimension[arg1]; + }, + __wbg_set_view_formats_427069064d8b7139: function(arg0, arg1, arg2) { + arg0.viewFormats = getArrayJsValueViewFromWasm0(arg1, arg2); + }, + __wbg_set_view_formats_9c2f01a6f3b365c7: function(arg0, arg1, arg2) { + arg0.viewFormats = getArrayJsValueViewFromWasm0(arg1, arg2); + }, + __wbg_set_view_gpu_texture_view_35f4655788535c4d: function(arg0, arg1) { + arg0.view = arg1; + }, + __wbg_set_view_gpu_texture_view_a532c825c52042c0: function(arg0, arg1) { + arg0.view = arg1; + }, + __wbg_set_visibility_d8a6821789538c25: function(arg0, arg1) { + arg0.visibility = arg1 >>> 0; + }, + __wbg_set_width_0ca908d167690992: function(arg0, arg1) { + arg0.width = arg1 >>> 0; + }, + __wbg_set_width_b0e1267db4b196b5: function(arg0, arg1) { + arg0.width = arg1 >>> 0; + }, + __wbg_set_width_b20525f5f4df4eb8: function(arg0, arg1) { + arg0.width = arg1 >>> 0; + }, + __wbg_set_write_mask_42d89f182ade6b2d: function(arg0, arg1) { + arg0.writeMask = arg1 >>> 0; + }, + __wbg_set_x_f470b03dd54724cd: function(arg0, arg1) { + arg0.x = arg1 >>> 0; + }, + __wbg_set_y_4c44eb40ebca5bfc: function(arg0, arg1) { + arg0.y = arg1 >>> 0; + }, + __wbg_set_z_2e6820ef0f5821ed: function(arg0, arg1) { + arg0.z = arg1 >>> 0; + }, + __wbg_shaderSource_06379dac249994dd: function(arg0, arg1, arg2, arg3) { + arg0.shaderSource(arg1, getStringFromWasm0(arg2, arg3)); + }, + __wbg_shaderSource_c8812639b47d87b9: function(arg0, arg1, arg2, arg3) { + arg0.shaderSource(arg1, getStringFromWasm0(arg2, arg3)); + }, + __wbg_shiftKey_be6d5295ee392b33: function(arg0) { + const ret = arg0.shiftKey; + return ret; + }, + __wbg_shiftKey_ecdc496db72e8a50: function(arg0) { + const ret = arg0.shiftKey; + return ret; + }, + __wbg_signal_e5a49a2d9c65b7f6: function(arg0) { + const ret = arg0.signal; + return ret; + }, + __wbg_size_00652f74c831ee7c: function(arg0) { + const ret = arg0.size; + return ret; + }, + __wbg_size_8f1c0b1a1fbb3810: function(arg0) { + const ret = arg0.size; + return ret; + }, + __wbg_stack_0e9ceb67ce7245b8: function(arg0, arg1) { + const ret = arg1.stack; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_static_accessor_GLOBAL_266715b9d96ba635: function() { + const ret = typeof global === 'undefined' ? null : global; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_static_accessor_GLOBAL_THIS_10fb7dc1ae063179: function() { + const ret = typeof globalThis === 'undefined' ? null : globalThis; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_static_accessor_SELF_0b583911f537483a: function() { + const ret = typeof self === 'undefined' ? null : self; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_static_accessor_WINDOW_d7f903d1508cbdc4: function() { + const ret = typeof window === 'undefined' ? null : window; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_status_ce0a98d3c57125f3: function(arg0) { + const ret = arg0.status; + return ret; + }, + __wbg_stencilFuncSeparate_3f31dcd12a0d4785: function(arg0, arg1, arg2, arg3, arg4) { + arg0.stencilFuncSeparate(arg1 >>> 0, arg2 >>> 0, arg3, arg4 >>> 0); + }, + __wbg_stencilFuncSeparate_f168b66c597aa85f: function(arg0, arg1, arg2, arg3, arg4) { + arg0.stencilFuncSeparate(arg1 >>> 0, arg2 >>> 0, arg3, arg4 >>> 0); + }, + __wbg_stencilMaskSeparate_b30c097ea6b98504: function(arg0, arg1, arg2) { + arg0.stencilMaskSeparate(arg1 >>> 0, arg2 >>> 0); + }, + __wbg_stencilMaskSeparate_ff739f8711e9fd42: function(arg0, arg1, arg2) { + arg0.stencilMaskSeparate(arg1 >>> 0, arg2 >>> 0); + }, + __wbg_stencilMask_9e18cc018897c747: function(arg0, arg1) { + arg0.stencilMask(arg1 >>> 0); + }, + __wbg_stencilMask_a22be64c66abd825: function(arg0, arg1) { + arg0.stencilMask(arg1 >>> 0); + }, + __wbg_stencilOpSeparate_7d01185cbdb89d99: function(arg0, arg1, arg2, arg3, arg4) { + arg0.stencilOpSeparate(arg1 >>> 0, arg2 >>> 0, arg3 >>> 0, arg4 >>> 0); + }, + __wbg_stencilOpSeparate_c5af5f5dbd237bea: function(arg0, arg1, arg2, arg3, arg4) { + arg0.stencilOpSeparate(arg1 >>> 0, arg2 >>> 0, arg3 >>> 0, arg4 >>> 0); + }, + __wbg_stopPropagation_effafbc3bc773f1c: function(arg0) { + arg0.stopPropagation(); + }, + __wbg_style_4bce24230e493a7c: function(arg0) { + const ret = arg0.style; + return ret; + }, + __wbg_subgroupMaxSize_b43be0aa16182403: function(arg0) { + const ret = arg0.subgroupMaxSize; + return ret; + }, + __wbg_subgroupMinSize_03feb6ee0cda6775: function(arg0) { + const ret = arg0.subgroupMinSize; + return ret; + }, + __wbg_submit_077c85cc28e36892: function(arg0, arg1, arg2) { + arg0.submit(getArrayJsValueViewFromWasm0(arg1, arg2)); + }, + __wbg_texImage2D_82bf2b4c8aa9a1db: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { + arg0.texImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, arg9); + }, arguments); }, + __wbg_texImage2D_a856af552acdc9d9: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { + arg0.texImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, arg9); + }, arguments); }, + __wbg_texImage2D_ca3d0fe24620ec85: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { + arg0.texImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, arg9); + }, arguments); }, + __wbg_texImage3D_29a847f33877ed12: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) { + arg0.texImage3D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7, arg8 >>> 0, arg9 >>> 0, arg10); + }, arguments); }, + __wbg_texImage3D_78fb39719c620063: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) { + arg0.texImage3D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7, arg8 >>> 0, arg9 >>> 0, arg10); + }, arguments); }, + __wbg_texParameteri_647fdb1426809cb5: function(arg0, arg1, arg2, arg3) { + arg0.texParameteri(arg1 >>> 0, arg2 >>> 0, arg3); + }, + __wbg_texParameteri_7864076abcdb03e0: function(arg0, arg1, arg2, arg3) { + arg0.texParameteri(arg1 >>> 0, arg2 >>> 0, arg3); + }, + __wbg_texStorage2D_cf2bd991072d9efb: function(arg0, arg1, arg2, arg3, arg4, arg5) { + arg0.texStorage2D(arg1 >>> 0, arg2, arg3 >>> 0, arg4, arg5); + }, + __wbg_texStorage3D_74b701c2b176380c: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6) { + arg0.texStorage3D(arg1 >>> 0, arg2, arg3 >>> 0, arg4, arg5, arg6); + }, + __wbg_texSubImage2D_07337d0974e99c39: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { + arg0.texSubImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, arg9); + }, arguments); }, + __wbg_texSubImage2D_196472d4111ce5b6: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { + arg0.texSubImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, arg9); + }, arguments); }, + __wbg_texSubImage2D_24cf5097ebaa84cc: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { + arg0.texSubImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, arg9); + }, arguments); }, + __wbg_texSubImage2D_31a0c2797aa04f32: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { + arg0.texSubImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, arg9); + }, arguments); }, + __wbg_texSubImage2D_5e90c7a719d40256: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { + arg0.texSubImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, arg9); + }, arguments); }, + __wbg_texSubImage2D_64e36398b8f046ac: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { + arg0.texSubImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, arg9); + }, arguments); }, + __wbg_texSubImage2D_bb322aae90f7657f: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { + arg0.texSubImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, arg9); + }, arguments); }, + __wbg_texSubImage2D_d7bffff06a3b8315: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { + arg0.texSubImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, arg9); + }, arguments); }, + __wbg_texSubImage3D_001f2e62ed945b72: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11) { + arg0.texSubImage3D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 >>> 0, arg10 >>> 0, arg11); + }, arguments); }, + __wbg_texSubImage3D_5143d5af7e182ddc: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11) { + arg0.texSubImage3D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 >>> 0, arg10 >>> 0, arg11); + }, arguments); }, + __wbg_texSubImage3D_53c6014e2d129891: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11) { + arg0.texSubImage3D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 >>> 0, arg10 >>> 0, arg11); + }, arguments); }, + __wbg_texSubImage3D_5d773fc7a8cd4d08: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11) { + arg0.texSubImage3D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 >>> 0, arg10 >>> 0, arg11); + }, arguments); }, + __wbg_texSubImage3D_adb96e37e6949ec9: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11) { + arg0.texSubImage3D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 >>> 0, arg10 >>> 0, arg11); + }, arguments); }, + __wbg_texSubImage3D_d4e74595e01f7f71: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11) { + arg0.texSubImage3D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 >>> 0, arg10 >>> 0, arg11); + }, arguments); }, + __wbg_texSubImage3D_e0d113b7047a5130: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11) { + arg0.texSubImage3D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 >>> 0, arg10 >>> 0, arg11); + }, arguments); }, + __wbg_then_c8a35d4ad59c6b8e: function(arg0, arg1) { + const ret = arg0.then(arg1); + return ret; + }, + __wbg_then_c949d5a25a4e78f8: function(arg0, arg1, arg2) { + const ret = arg0.then(arg1, arg2); + return ret; + }, + __wbg_then_e71170d78fcf8954: function(arg0, arg1) { + const ret = arg0.then(arg1); + return ret; + }, + __wbg_tiltX_58770dbd6959f31f: function(arg0) { + const ret = arg0.tiltX; + return ret; + }, + __wbg_tiltY_5bdc394d02de8b70: function(arg0) { + const ret = arg0.tiltY; + return ret; + }, + __wbg_top_ff4627294d2cdeb8: function(arg0) { + const ret = arg0.top; + return ret; + }, + __wbg_touches_7b36d35cdb1673fa: function(arg0) { + const ret = arg0.touches; + return ret; + }, + __wbg_transaction_3a02c7e8ef4fa771: function(arg0) { + const ret = arg0.transaction; + return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); + }, + __wbg_transaction_55a3a4e0134a0fd6: function() { return handleError(function (arg0, arg1, arg2, arg3) { + const ret = arg0.transaction(getStringFromWasm0(arg1, arg2), __wbindgen_enum_IdbTransactionMode[arg3]); + return ret; + }, arguments); }, + __wbg_twist_dd0a5c8ef065ec13: function(arg0) { + const ret = arg0.twist; + return ret; + }, + __wbg_type_b805b444107983c3: function(arg0, arg1) { + const ret = arg1.type; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_type_d44713a24aa37493: function(arg0, arg1) { + const ret = arg1.type; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_unconfigure_835307f58dc68d80: function(arg0) { + arg0.unconfigure(); + }, + __wbg_uniform1f_9cfecfaeb8cf43c1: function(arg0, arg1, arg2) { + arg0.uniform1f(arg1, arg2); + }, + __wbg_uniform1f_b5856e35a43b65a1: function(arg0, arg1, arg2) { + arg0.uniform1f(arg1, arg2); + }, + __wbg_uniform1i_531b98c4a7177366: function(arg0, arg1, arg2) { + arg0.uniform1i(arg1, arg2); + }, + __wbg_uniform1i_fc2dc8cadc49d8ec: function(arg0, arg1, arg2) { + arg0.uniform1i(arg1, arg2); + }, + __wbg_uniform1ui_353c67ec681b540c: function(arg0, arg1, arg2) { + arg0.uniform1ui(arg1, arg2 >>> 0); + }, + __wbg_uniform2fv_319c49f0ce340f26: function(arg0, arg1, arg2, arg3) { + arg0.uniform2fv(arg1, getArrayF32FromWasm0(arg2, arg3)); + }, + __wbg_uniform2fv_a7d3c1830d18c1b2: function(arg0, arg1, arg2, arg3) { + arg0.uniform2fv(arg1, getArrayF32FromWasm0(arg2, arg3)); + }, + __wbg_uniform2iv_65f36fc9777697d7: function(arg0, arg1, arg2, arg3) { + arg0.uniform2iv(arg1, getArrayI32FromWasm0(arg2, arg3)); + }, + __wbg_uniform2iv_ca9cb507409b9ad1: function(arg0, arg1, arg2, arg3) { + arg0.uniform2iv(arg1, getArrayI32FromWasm0(arg2, arg3)); + }, + __wbg_uniform2uiv_c95af5fb653ccb86: function(arg0, arg1, arg2, arg3) { + arg0.uniform2uiv(arg1, getArrayU32FromWasm0(arg2, arg3)); + }, + __wbg_uniform3fv_055ea5ac38af4fce: function(arg0, arg1, arg2, arg3) { + arg0.uniform3fv(arg1, getArrayF32FromWasm0(arg2, arg3)); + }, + __wbg_uniform3fv_58520ffe22a6e27c: function(arg0, arg1, arg2, arg3) { + arg0.uniform3fv(arg1, getArrayF32FromWasm0(arg2, arg3)); + }, + __wbg_uniform3iv_0590e8b7eff2a791: function(arg0, arg1, arg2, arg3) { + arg0.uniform3iv(arg1, getArrayI32FromWasm0(arg2, arg3)); + }, + __wbg_uniform3iv_e91b1410dc299f50: function(arg0, arg1, arg2, arg3) { + arg0.uniform3iv(arg1, getArrayI32FromWasm0(arg2, arg3)); + }, + __wbg_uniform3uiv_9992491000463a52: function(arg0, arg1, arg2, arg3) { + arg0.uniform3uiv(arg1, getArrayU32FromWasm0(arg2, arg3)); + }, + __wbg_uniform4f_22bfec882308eec2: function(arg0, arg1, arg2, arg3, arg4, arg5) { + arg0.uniform4f(arg1, arg2, arg3, arg4, arg5); + }, + __wbg_uniform4f_8dd8f311e656ca0d: function(arg0, arg1, arg2, arg3, arg4, arg5) { + arg0.uniform4f(arg1, arg2, arg3, arg4, arg5); + }, + __wbg_uniform4fv_3ef2f5121fcb78ae: function(arg0, arg1, arg2, arg3) { + arg0.uniform4fv(arg1, getArrayF32FromWasm0(arg2, arg3)); + }, + __wbg_uniform4fv_cf8ff646c36232c8: function(arg0, arg1, arg2, arg3) { + arg0.uniform4fv(arg1, getArrayF32FromWasm0(arg2, arg3)); + }, + __wbg_uniform4iv_6fc5436b4f876039: function(arg0, arg1, arg2, arg3) { + arg0.uniform4iv(arg1, getArrayI32FromWasm0(arg2, arg3)); + }, + __wbg_uniform4iv_99c2b07787d362d6: function(arg0, arg1, arg2, arg3) { + arg0.uniform4iv(arg1, getArrayI32FromWasm0(arg2, arg3)); + }, + __wbg_uniform4uiv_a6fb3237d9df7ed4: function(arg0, arg1, arg2, arg3) { + arg0.uniform4uiv(arg1, getArrayU32FromWasm0(arg2, arg3)); + }, + __wbg_uniformBlockBinding_07116582301fb019: function(arg0, arg1, arg2, arg3) { + arg0.uniformBlockBinding(arg1, arg2 >>> 0, arg3 >>> 0); + }, + __wbg_uniformMatrix2fv_34b2245136106a2f: function(arg0, arg1, arg2, arg3, arg4) { + arg0.uniformMatrix2fv(arg1, arg2 !== 0, getArrayF32FromWasm0(arg3, arg4)); + }, + __wbg_uniformMatrix2fv_611c7fcb378f057e: function(arg0, arg1, arg2, arg3, arg4) { + arg0.uniformMatrix2fv(arg1, arg2 !== 0, getArrayF32FromWasm0(arg3, arg4)); + }, + __wbg_uniformMatrix2x3fv_6b33a76d09b6c00f: function(arg0, arg1, arg2, arg3, arg4) { + arg0.uniformMatrix2x3fv(arg1, arg2 !== 0, getArrayF32FromWasm0(arg3, arg4)); + }, + __wbg_uniformMatrix2x4fv_66c787e2d0a5dd0a: function(arg0, arg1, arg2, arg3, arg4) { + arg0.uniformMatrix2x4fv(arg1, arg2 !== 0, getArrayF32FromWasm0(arg3, arg4)); + }, + __wbg_uniformMatrix3fv_472e7824735acce1: function(arg0, arg1, arg2, arg3, arg4) { + arg0.uniformMatrix3fv(arg1, arg2 !== 0, getArrayF32FromWasm0(arg3, arg4)); + }, + __wbg_uniformMatrix3fv_83fdc9c3c0d43204: function(arg0, arg1, arg2, arg3, arg4) { + arg0.uniformMatrix3fv(arg1, arg2 !== 0, getArrayF32FromWasm0(arg3, arg4)); + }, + __wbg_uniformMatrix3x2fv_33df849b78b8556e: function(arg0, arg1, arg2, arg3, arg4) { + arg0.uniformMatrix3x2fv(arg1, arg2 !== 0, getArrayF32FromWasm0(arg3, arg4)); + }, + __wbg_uniformMatrix3x4fv_8914dc5121a813b4: function(arg0, arg1, arg2, arg3, arg4) { + arg0.uniformMatrix3x4fv(arg1, arg2 !== 0, getArrayF32FromWasm0(arg3, arg4)); + }, + __wbg_uniformMatrix4fv_dff9738d995fd0b1: function(arg0, arg1, arg2, arg3, arg4) { + arg0.uniformMatrix4fv(arg1, arg2 !== 0, getArrayF32FromWasm0(arg3, arg4)); + }, + __wbg_uniformMatrix4fv_e691d7f14d3609f7: function(arg0, arg1, arg2, arg3, arg4) { + arg0.uniformMatrix4fv(arg1, arg2 !== 0, getArrayF32FromWasm0(arg3, arg4)); + }, + __wbg_uniformMatrix4x2fv_1c9ccf4427b82548: function(arg0, arg1, arg2, arg3, arg4) { + arg0.uniformMatrix4x2fv(arg1, arg2 !== 0, getArrayF32FromWasm0(arg3, arg4)); + }, + __wbg_uniformMatrix4x3fv_a84b16e0a7abee2c: function(arg0, arg1, arg2, arg3, arg4) { + arg0.uniformMatrix4x3fv(arg1, arg2 !== 0, getArrayF32FromWasm0(arg3, arg4)); + }, + __wbg_unmap_6a96b14c9ef5f7f5: function(arg0) { + arg0.unmap(); + }, + __wbg_usage_eb336a28af1c9fcf: function(arg0) { + const ret = arg0.usage; + return ret; + }, + __wbg_useProgram_5bdae58fd9f9826f: function(arg0, arg1) { + arg0.useProgram(arg1); + }, + __wbg_useProgram_e075c2902e420761: function(arg0, arg1) { + arg0.useProgram(arg1); + }, + __wbg_userActivation_25695ccbfe2622d4: function(arg0) { + const ret = arg0.userActivation; + return ret; + }, + __wbg_userAgent_cde4c65cc98db425: function() { return handleError(function (arg0, arg1) { + const ret = arg1.userAgent; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, arguments); }, + __wbg_valueOf_02fd4d101b7553c7: function(arg0) { + const ret = arg0.valueOf(); + return ret; + }, + __wbg_value_05305a761dfa3e0e: function(arg0, arg1) { + const ret = arg1.value; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbg_value_e6653e661698cb71: function() { return handleError(function (arg0) { + const ret = arg0.value; + return ret; + }, arguments); }, + __wbg_vertexAttribDivisorANGLE_659fb027198a47c3: function(arg0, arg1, arg2) { + arg0.vertexAttribDivisorANGLE(arg1 >>> 0, arg2 >>> 0); + }, + __wbg_vertexAttribDivisor_7575d382215322f7: function(arg0, arg1, arg2) { + arg0.vertexAttribDivisor(arg1 >>> 0, arg2 >>> 0); + }, + __wbg_vertexAttribIPointer_fc8057c62cfcc63c: function(arg0, arg1, arg2, arg3, arg4, arg5) { + arg0.vertexAttribIPointer(arg1 >>> 0, arg2, arg3 >>> 0, arg4, arg5); + }, + __wbg_vertexAttribPointer_24b495e18df325dc: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6) { + arg0.vertexAttribPointer(arg1 >>> 0, arg2, arg3 >>> 0, arg4 !== 0, arg5, arg6); + }, + __wbg_vertexAttribPointer_54d56b18f71a946d: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6) { + arg0.vertexAttribPointer(arg1 >>> 0, arg2, arg3 >>> 0, arg4 !== 0, arg5, arg6); + }, + __wbg_viewport_16936692526e2ce6: function(arg0, arg1, arg2, arg3, arg4) { + arg0.viewport(arg1, arg2, arg3, arg4); + }, + __wbg_viewport_e35d16c542d2ce70: function(arg0, arg1, arg2, arg3, arg4) { + arg0.viewport(arg1, arg2, arg3, arg4); + }, + __wbg_warn_0115be04778d8c8c: function(arg0, arg1) { + console.warn(getStringFromWasm0(arg0, arg1)); + }, + __wbg_width_3d0dce3d9892e35e: function(arg0) { + const ret = arg0.width; + return ret; + }, + __wbg_width_bf3733dbc880874d: function(arg0) { + const ret = arg0.width; + return ret; + }, + __wbg_writeBuffer_f4bb3f54adfe1330: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6) { + arg0.writeBuffer(arg1, arg2, getArrayU8FromWasm0(arg3, arg4), arg5, arg6); + }, arguments); }, + __wbg_writeText_79a2b37e525e9424: function(arg0, arg1, arg2) { + const ret = arg0.writeText(getStringFromWasm0(arg1, arg2)); + return ret; + }, + __wbg_writeTexture_30e592e8c061c3d9: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) { + arg0.writeTexture(arg1, getArrayU8FromWasm0(arg2, arg3), arg4, arg5); + }, arguments); }, + __wbg_write_f88c29d142d623bd: function(arg0, arg1) { + const ret = arg0.write(arg1); + return ret; + }, + __wbindgen_generic_0000000000000001: function(arg0, arg1) { + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 543, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true_); + return ret; + }, + __wbindgen_generic_0000000000000002: function(arg0, arg1) { + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Array")], shim_idx: 9, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true_); + return ret; + }, + __wbindgen_generic_0000000000000003: function(arg0, arg1) { + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("BeforeUnloadEvent")], shim_idx: 9, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true__4); + return ret; + }, + __wbindgen_generic_0000000000000004: function(arg0, arg1) { + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 9, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true__5); + return ret; + }, + __wbindgen_generic_0000000000000005: function(arg0, arg1) { + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUDevice")], shim_idx: 543, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true__6); + return ret; + }, + __wbindgen_generic_0000000000000006: function(arg0, arg1) { + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUDeviceLostInfo")], shim_idx: 4124, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuDeviceLostInfo__GpuDeviceLostInfo______true_); + return ret; + }, + __wbindgen_generic_0000000000000007: function(arg0, arg1) { + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUUncapturedErrorEvent")], shim_idx: 4124, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuDeviceLostInfo__GpuDeviceLostInfo______true__8); + return ret; + }, + __wbindgen_generic_0000000000000008: function(arg0, arg1) { + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("PointerEvent")], shim_idx: 9, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true__9); + return ret; + }, + __wbindgen_generic_0000000000000009: function(arg0, arg1) { + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("any")], shim_idx: 543, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true__10); + return ret; + }, + __wbindgen_generic_000000000000000a: function(arg0, arg1) { + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("undefined")], shim_idx: 543, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true__11); + return ret; + }, + __wbindgen_generic_000000000000000b: function(arg0, arg1) { + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 15, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke_______true_); + return ret; + }, + __wbindgen_generic_000000000000000c: function(arg0, arg1) { + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 221, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsValue___true_); + return ret; + }, + __wbindgen_generic_000000000000000d: function(arg0) { + // Cast intrinsic for `F64 -> Externref`. + const ret = arg0; + return ret; + }, + __wbindgen_generic_000000000000000e: function(arg0, arg1) { + // Cast intrinsic for `Ref(Slice(F32)) -> NamedExternref("Float32Array")`. + const ret = getArrayF32FromWasm0(arg0, arg1); + return ret; + }, + __wbindgen_generic_000000000000000f: function(arg0, arg1) { + // Cast intrinsic for `Ref(Slice(I16)) -> NamedExternref("Int16Array")`. + const ret = getArrayI16FromWasm0(arg0, arg1); + return ret; + }, + __wbindgen_generic_0000000000000010: function(arg0, arg1) { + // Cast intrinsic for `Ref(Slice(I32)) -> NamedExternref("Int32Array")`. + const ret = getArrayI32FromWasm0(arg0, arg1); + return ret; + }, + __wbindgen_generic_0000000000000011: function(arg0, arg1) { + // Cast intrinsic for `Ref(Slice(I8)) -> NamedExternref("Int8Array")`. + const ret = getArrayI8FromWasm0(arg0, arg1); + return ret; + }, + __wbindgen_generic_0000000000000012: function(arg0, arg1) { + // Cast intrinsic for `Ref(Slice(U16)) -> NamedExternref("Uint16Array")`. + const ret = getArrayU16FromWasm0(arg0, arg1); + return ret; + }, + __wbindgen_generic_0000000000000013: function(arg0, arg1) { + // Cast intrinsic for `Ref(Slice(U32)) -> NamedExternref("Uint32Array")`. + const ret = getArrayU32FromWasm0(arg0, arg1); + return ret; + }, + __wbindgen_generic_0000000000000014: function(arg0, arg1) { + // Cast intrinsic for `Ref(Slice(U8)) -> NamedExternref("Uint8Array")`. + const ret = getArrayU8FromWasm0(arg0, arg1); + return ret; + }, + __wbindgen_generic_0000000000000015: function(arg0, arg1) { + // Cast intrinsic for `Ref(String) -> Externref`. + const ret = getStringFromWasm0(arg0, arg1); + return ret; + }, + __wbindgen_init_externref_table: function() { + const table = wasm.__wbindgen_externrefs; + const offset = table.grow(4); + table.set(0, undefined); + table.set(offset + 0, undefined); + table.set(offset + 1, null); + table.set(offset + 2, true); + table.set(offset + 3, false); + }, + }; + return { + __proto__: null, + "./photocraft_bg.js": import0, + }; +} + +function wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke_______true_(arg0, arg1) { + wasm.wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke_______true_(arg0, arg1); +} + +function wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsValue___true_(arg0, arg1) { + const ret = wasm.wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsValue___true_(arg0, arg1); + if (ret[1]) { + throw takeFromExternrefTable0(ret[0]); + } +} + +function wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true_(arg0, arg1, arg2) { + wasm.wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true_(arg0, arg1, arg2); +} + +function wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true__4(arg0, arg1, arg2) { + wasm.wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true__4(arg0, arg1, arg2); +} + +function wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true__5(arg0, arg1, arg2) { + wasm.wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true__5(arg0, arg1, arg2); +} + +function wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuDeviceLostInfo__GpuDeviceLostInfo______true_(arg0, arg1, arg2) { + wasm.wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuDeviceLostInfo__GpuDeviceLostInfo______true_(arg0, arg1, arg2); +} + +function wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuDeviceLostInfo__GpuDeviceLostInfo______true__8(arg0, arg1, arg2) { + wasm.wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuDeviceLostInfo__GpuDeviceLostInfo______true__8(arg0, arg1, arg2); +} + +function wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true__9(arg0, arg1, arg2) { + wasm.wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true__9(arg0, arg1, arg2); +} + +function wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true_(arg0, arg1, arg2) { + const ret = wasm.wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true_(arg0, arg1, arg2); + if (ret[1]) { + throw takeFromExternrefTable0(ret[0]); + } +} + +function wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true__6(arg0, arg1, arg2) { + const ret = wasm.wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true__6(arg0, arg1, arg2); + if (ret[1]) { + throw takeFromExternrefTable0(ret[0]); + } +} + +function wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true__10(arg0, arg1, arg2) { + const ret = wasm.wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true__10(arg0, arg1, arg2); + if (ret[1]) { + throw takeFromExternrefTable0(ret[0]); + } +} + +function wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true__11(arg0, arg1, arg2) { + const ret = wasm.wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true__11(arg0, arg1, arg2); + if (ret[1]) { + throw takeFromExternrefTable0(ret[0]); + } +} + +function wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Function_fn_wasm_bindgen_54f023e2846dbff4___JsValue_____wasm_bindgen_54f023e2846dbff4___sys__Undefined___js_sys_526e9b82b0b84cf5___Function_fn_wasm_bindgen_54f023e2846dbff4___JsValue_____wasm_bindgen_54f023e2846dbff4___sys__Undefined_______true_(arg0, arg1, arg2, arg3) { + wasm.wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Function_fn_wasm_bindgen_54f023e2846dbff4___JsValue_____wasm_bindgen_54f023e2846dbff4___sys__Undefined___js_sys_526e9b82b0b84cf5___Function_fn_wasm_bindgen_54f023e2846dbff4___JsValue_____wasm_bindgen_54f023e2846dbff4___sys__Undefined_______true_(arg0, arg1, arg2, arg3); +} + + +const __wbindgen_enum_GpuAddressMode = ["clamp-to-edge", "repeat", "mirror-repeat"]; + + +const __wbindgen_enum_GpuAutoLayoutMode = ["auto"]; + + +const __wbindgen_enum_GpuBlendFactor = ["zero", "one", "src", "one-minus-src", "src-alpha", "one-minus-src-alpha", "dst", "one-minus-dst", "dst-alpha", "one-minus-dst-alpha", "src-alpha-saturated", "constant", "one-minus-constant", "src1", "one-minus-src1", "src1-alpha", "one-minus-src1-alpha"]; + + +const __wbindgen_enum_GpuBlendOperation = ["add", "subtract", "reverse-subtract", "min", "max"]; + + +const __wbindgen_enum_GpuBufferBindingType = ["uniform", "storage", "read-only-storage"]; + + +const __wbindgen_enum_GpuCanvasAlphaMode = ["opaque", "premultiplied"]; + + +const __wbindgen_enum_GpuCanvasToneMappingMode = ["standard", "extended"]; + + +const __wbindgen_enum_GpuCompareFunction = ["never", "less", "equal", "less-equal", "greater", "not-equal", "greater-equal", "always"]; + + +const __wbindgen_enum_GpuCullMode = ["none", "front", "back"]; + + +const __wbindgen_enum_GpuDeviceLostReason = ["unknown", "destroyed"]; + + +const __wbindgen_enum_GpuErrorFilter = ["validation", "out-of-memory", "internal"]; + + +const __wbindgen_enum_GpuFilterMode = ["nearest", "linear"]; + + +const __wbindgen_enum_GpuFrontFace = ["ccw", "cw"]; + + +const __wbindgen_enum_GpuIndexFormat = ["uint16", "uint32"]; + + +const __wbindgen_enum_GpuLoadOp = ["load", "clear"]; + + +const __wbindgen_enum_GpuMipmapFilterMode = ["nearest", "linear"]; + + +const __wbindgen_enum_GpuPowerPreference = ["low-power", "high-performance"]; + + +const __wbindgen_enum_GpuPrimitiveTopology = ["point-list", "line-list", "line-strip", "triangle-list", "triangle-strip"]; + + +const __wbindgen_enum_GpuSamplerBindingType = ["filtering", "non-filtering", "comparison"]; + + +const __wbindgen_enum_GpuStencilOperation = ["keep", "zero", "replace", "invert", "increment-clamp", "decrement-clamp", "increment-wrap", "decrement-wrap"]; + + +const __wbindgen_enum_GpuStorageTextureAccess = ["write-only", "read-only", "read-write"]; + + +const __wbindgen_enum_GpuStoreOp = ["store", "discard"]; + + +const __wbindgen_enum_GpuTextureAspect = ["all", "stencil-only", "depth-only"]; + + +const __wbindgen_enum_GpuTextureDimension = ["1d", "2d", "3d"]; + + +const __wbindgen_enum_GpuTextureFormat = ["r8unorm", "r8snorm", "r8uint", "r8sint", "r16unorm", "r16snorm", "r16uint", "r16sint", "r16float", "rg8unorm", "rg8snorm", "rg8uint", "rg8sint", "r32uint", "r32sint", "r32float", "rg16unorm", "rg16snorm", "rg16uint", "rg16sint", "rg16float", "rgba8unorm", "rgba8unorm-srgb", "rgba8snorm", "rgba8uint", "rgba8sint", "bgra8unorm", "bgra8unorm-srgb", "rgb9e5ufloat", "rgb10a2uint", "rgb10a2unorm", "rg11b10ufloat", "rg32uint", "rg32sint", "rg32float", "rgba16unorm", "rgba16snorm", "rgba16uint", "rgba16sint", "rgba16float", "rgba32uint", "rgba32sint", "rgba32float", "stencil8", "depth16unorm", "depth24plus", "depth24plus-stencil8", "depth32float", "depth32float-stencil8", "bc1-rgba-unorm", "bc1-rgba-unorm-srgb", "bc2-rgba-unorm", "bc2-rgba-unorm-srgb", "bc3-rgba-unorm", "bc3-rgba-unorm-srgb", "bc4-r-unorm", "bc4-r-snorm", "bc5-rg-unorm", "bc5-rg-snorm", "bc6h-rgb-ufloat", "bc6h-rgb-float", "bc7-rgba-unorm", "bc7-rgba-unorm-srgb", "etc2-rgb8unorm", "etc2-rgb8unorm-srgb", "etc2-rgb8a1unorm", "etc2-rgb8a1unorm-srgb", "etc2-rgba8unorm", "etc2-rgba8unorm-srgb", "eac-r11unorm", "eac-r11snorm", "eac-rg11unorm", "eac-rg11snorm", "astc-4x4-unorm", "astc-4x4-unorm-srgb", "astc-5x4-unorm", "astc-5x4-unorm-srgb", "astc-5x5-unorm", "astc-5x5-unorm-srgb", "astc-6x5-unorm", "astc-6x5-unorm-srgb", "astc-6x6-unorm", "astc-6x6-unorm-srgb", "astc-8x5-unorm", "astc-8x5-unorm-srgb", "astc-8x6-unorm", "astc-8x6-unorm-srgb", "astc-8x8-unorm", "astc-8x8-unorm-srgb", "astc-10x5-unorm", "astc-10x5-unorm-srgb", "astc-10x6-unorm", "astc-10x6-unorm-srgb", "astc-10x8-unorm", "astc-10x8-unorm-srgb", "astc-10x10-unorm", "astc-10x10-unorm-srgb", "astc-12x10-unorm", "astc-12x10-unorm-srgb", "astc-12x12-unorm", "astc-12x12-unorm-srgb"]; + + +const __wbindgen_enum_GpuTextureSampleType = ["float", "unfilterable-float", "depth", "sint", "uint"]; + + +const __wbindgen_enum_GpuTextureViewDimension = ["1d", "2d", "2d-array", "cube", "cube-array", "3d"]; + + +const __wbindgen_enum_GpuVertexFormat = ["uint8", "uint8x2", "uint8x4", "sint8", "sint8x2", "sint8x4", "unorm8", "unorm8x2", "unorm8x4", "snorm8", "snorm8x2", "snorm8x4", "uint16", "uint16x2", "uint16x4", "sint16", "sint16x2", "sint16x4", "unorm16", "unorm16x2", "unorm16x4", "snorm16", "snorm16x2", "snorm16x4", "float16", "float16x2", "float16x4", "float32", "float32x2", "float32x3", "float32x4", "uint32", "uint32x2", "uint32x3", "uint32x4", "sint32", "sint32x2", "sint32x3", "sint32x4", "unorm10-10-10-2", "unorm8x4-bgra"]; + + +const __wbindgen_enum_GpuVertexStepMode = ["vertex", "instance"]; + + +const __wbindgen_enum_IdbTransactionMode = ["readonly", "readwrite", "versionchange", "readwriteflush", "cleanup"]; + + +const __wbindgen_enum_ResizeObserverBoxOptions = ["border-box", "content-box", "device-pixel-content-box"]; + +function addToExternrefTable0(obj) { + const idx = wasm.__externref_table_alloc(); + wasm.__wbindgen_externrefs.set(idx, obj); + return idx; +} + +const CLOSURE_DTORS = (typeof FinalizationRegistry === 'undefined') + ? { register: () => {}, unregister: () => {} } + : new FinalizationRegistry(state => wasm.__wbindgen_destroy_closure(state.a, state.b)); + +function debugString(val) { + // primitive types + const type = typeof val; + if (type == 'number' || type == 'boolean' || val == null) { + return `${val}`; + } + if (type == 'string') { + return `"${val}"`; + } + if (type == 'symbol') { + const description = val.description; + if (description == null) { + return 'Symbol'; + } else { + return `Symbol(${description})`; + } + } + if (type == 'function') { + const name = val.name; + if (typeof name == 'string' && name.length > 0) { + return `Function(${name})`; + } else { + return 'Function'; + } + } + // objects + if (Array.isArray(val)) { + const length = val.length; + let debug = '['; + if (length > 0) { + debug += debugString(val[0]); + } + for(let i = 1; i < length; i++) { + debug += ', ' + debugString(val[i]); + } + debug += ']'; + return debug; + } + // Test for built-in + const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); + let className; + if (builtInMatches && builtInMatches.length > 1) { + className = builtInMatches[1]; + } else { + // Failed to match the standard '[object ClassName]' + return toString.call(val); + } + if (className == 'Object') { + // we're a user defined class or Object + // JSON.stringify avoids problems with cycles, and is generally much + // easier than looping through ownProperties of `val`. + try { + return 'Object(' + JSON.stringify(val) + ')'; + } catch (_) { + return 'Object'; + } + } + // errors + if (val instanceof Error) { + return `${val.name}: ${val.message}\n${val.stack}`; + } + // TODO we could test for more things here, like `Set`s and `Map`s. + return className; +} + +function getArrayF32FromWasm0(ptr, len) { + ptr = ptr >>> 0; + return getFloat32ArrayMemory0().subarray(ptr / 4, ptr / 4 + len); +} + +function getArrayI16FromWasm0(ptr, len) { + ptr = ptr >>> 0; + return getInt16ArrayMemory0().subarray(ptr / 2, ptr / 2 + len); +} + +function getArrayI32FromWasm0(ptr, len) { + ptr = ptr >>> 0; + return getInt32ArrayMemory0().subarray(ptr / 4, ptr / 4 + len); +} + +function getArrayI8FromWasm0(ptr, len) { + ptr = ptr >>> 0; + return getInt8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len); +} + +function getArrayJsValueViewFromWasm0(ptr, len) { + ptr = ptr >>> 0; + const mem = getDataViewMemory0(); + const result = []; + for (let i = ptr; i < ptr + 4 * len; i += 4) { + result.push(wasm.__wbindgen_externrefs.get(mem.getUint32(i, true))); + } + return result; +} + +function getArrayU16FromWasm0(ptr, len) { + ptr = ptr >>> 0; + return getUint16ArrayMemory0().subarray(ptr / 2, ptr / 2 + len); +} + +function getArrayU32FromWasm0(ptr, len) { + ptr = ptr >>> 0; + return getUint32ArrayMemory0().subarray(ptr / 4, ptr / 4 + len); +} + +function getArrayU8FromWasm0(ptr, len) { + ptr = ptr >>> 0; + return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len); +} + +let cachedDataViewMemory0 = null; +function getDataViewMemory0() { + if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) { + cachedDataViewMemory0 = new DataView(wasm.memory.buffer); + } + return cachedDataViewMemory0; +} + +let cachedFloat32ArrayMemory0 = null; +function getFloat32ArrayMemory0() { + if (cachedFloat32ArrayMemory0 === null || cachedFloat32ArrayMemory0.byteLength === 0) { + cachedFloat32ArrayMemory0 = new Float32Array(wasm.memory.buffer); + } + return cachedFloat32ArrayMemory0; +} + +let cachedInt16ArrayMemory0 = null; +function getInt16ArrayMemory0() { + if (cachedInt16ArrayMemory0 === null || cachedInt16ArrayMemory0.byteLength === 0) { + cachedInt16ArrayMemory0 = new Int16Array(wasm.memory.buffer); + } + return cachedInt16ArrayMemory0; +} + +let cachedInt32ArrayMemory0 = null; +function getInt32ArrayMemory0() { + if (cachedInt32ArrayMemory0 === null || cachedInt32ArrayMemory0.byteLength === 0) { + cachedInt32ArrayMemory0 = new Int32Array(wasm.memory.buffer); + } + return cachedInt32ArrayMemory0; +} + +let cachedInt8ArrayMemory0 = null; +function getInt8ArrayMemory0() { + if (cachedInt8ArrayMemory0 === null || cachedInt8ArrayMemory0.byteLength === 0) { + cachedInt8ArrayMemory0 = new Int8Array(wasm.memory.buffer); + } + return cachedInt8ArrayMemory0; +} + +function getStringFromWasm0(ptr, len) { + return decodeText(ptr >>> 0, len); +} + +let cachedUint16ArrayMemory0 = null; +function getUint16ArrayMemory0() { + if (cachedUint16ArrayMemory0 === null || cachedUint16ArrayMemory0.byteLength === 0) { + cachedUint16ArrayMemory0 = new Uint16Array(wasm.memory.buffer); + } + return cachedUint16ArrayMemory0; +} + +let cachedUint32ArrayMemory0 = null; +function getUint32ArrayMemory0() { + if (cachedUint32ArrayMemory0 === null || cachedUint32ArrayMemory0.byteLength === 0) { + cachedUint32ArrayMemory0 = new Uint32Array(wasm.memory.buffer); + } + return cachedUint32ArrayMemory0; +} + +let cachedUint8ArrayMemory0 = null; +function getUint8ArrayMemory0() { + if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) { + cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8ArrayMemory0; +} + +function handleError(f, args) { + try { + return f.apply(this, args); + } catch (e) { + const idx = addToExternrefTable0(e); + wasm.__wbindgen_exn_store(idx); + } +} + +function isLikeNone(x) { + return x === undefined || x === null; +} + +function makeMutClosure(arg0, arg1, f) { + const state = { a: arg0, b: arg1, cnt: 1 }; + const real = (...args) => { + + // First up with a closure we increment the internal reference + // count. This ensures that the Rust closure environment won't + // be deallocated while we're invoking it. + state.cnt++; + const a = state.a; + state.a = 0; + try { + return f(a, state.b, ...args); + } finally { + state.a = a; + real._wbg_cb_unref(); + } + }; + real._wbg_cb_unref = () => { + if (--state.cnt === 0) { + wasm.__wbindgen_destroy_closure(state.a, state.b); + state.a = 0; + CLOSURE_DTORS.unregister(state); + } + }; + CLOSURE_DTORS.register(real, state, state); + return real; +} + +function passStringToWasm0(arg, malloc, realloc) { + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length, 1) >>> 0; + getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len, 1) >>> 0; + + const mem = getUint8ArrayMemory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7F) break; + mem[ptr + offset] = code; + } + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; + const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len); + const ret = cachedTextEncoder.encodeInto(arg, view); + + offset += ret.written; + ptr = realloc(ptr, len, offset, 1) >>> 0; + } + + WASM_VECTOR_LEN = offset; + return ptr; +} + +function takeFromExternrefTable0(idx) { + const value = wasm.__wbindgen_externrefs.get(idx); + wasm.__externref_table_dealloc(idx); + return value; +} + +let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }); +cachedTextDecoder.decode(); +const MAX_SAFARI_DECODE_BYTES = 2146435072; +let numBytesDecoded = 0; +function decodeText(ptr, len) { + numBytesDecoded += len; + if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) { + cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }); + cachedTextDecoder.decode(); + numBytesDecoded = len; + } + return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len)); +} + +const cachedTextEncoder = new TextEncoder(); + +if (!('encodeInto' in cachedTextEncoder)) { + cachedTextEncoder.encodeInto = function (arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length + }; + }; +} + +let WASM_VECTOR_LEN = 0; + +let wasmModule, wasmInstance, wasm; +function __wbg_finalize_init(instance, module) { + wasmInstance = instance; + wasm = instance.exports; + wasmModule = module; + cachedDataViewMemory0 = null; + cachedFloat32ArrayMemory0 = null; + cachedInt16ArrayMemory0 = null; + cachedInt32ArrayMemory0 = null; + cachedInt8ArrayMemory0 = null; + cachedUint16ArrayMemory0 = null; + cachedUint32ArrayMemory0 = null; + cachedUint8ArrayMemory0 = null; + wasm.__wbindgen_start(); + return wasm; +} + +async function __wbg_load(module, imports) { + if (typeof Response === 'function' && module instanceof Response) { + if (!module.ok) { + throw new Error(`failed to fetch Wasm: ${module.status} ${module.statusText} fetching '${module.url}'`); + } + + if (typeof WebAssembly.instantiateStreaming === 'function') { + try { + return await WebAssembly.instantiateStreaming(module, imports); + } catch (e) { + const validResponse = expectedResponseType(module.type); + + if (validResponse && module.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", e); + + } else { throw e; } + } + } + + const bytes = await module.arrayBuffer(); + return await WebAssembly.instantiate(bytes, imports); + } else { + const instance = await WebAssembly.instantiate(module, imports); + + if (instance instanceof WebAssembly.Instance) { + return { instance, module }; + } else { + return instance; + } + } + + function expectedResponseType(type) { + switch (type) { + case 'basic': case 'cors': case 'default': return true; + } + return false; + } +} + +function initSync(module) { + if (wasm !== undefined) return wasm; + + + if (module !== undefined) { + if (Object.getPrototypeOf(module) === Object.prototype) { + ({module} = module) + } else { + console.warn('using deprecated parameters for `initSync()`; pass a single object instead') + } + } + + const imports = __wbg_get_imports(); + if (!(module instanceof WebAssembly.Module)) { + module = new WebAssembly.Module(module); + } + const instance = new WebAssembly.Instance(module, imports); + return __wbg_finalize_init(instance, module); +} + +async function __wbg_init(module_or_path) { + if (wasm !== undefined) return wasm; + + + if (module_or_path !== undefined) { + if (Object.getPrototypeOf(module_or_path) === Object.prototype) { + ({module_or_path} = module_or_path) + } else { + console.warn('using deprecated parameters for the initialization function; pass a single object instead') + } + } + + if (module_or_path === undefined) { + module_or_path = new URL('photocraft_bg.wasm', import.meta.url); + } + const imports = __wbg_get_imports(); + + if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) { + module_or_path = fetch(module_or_path); + } + + const { instance, module } = await __wbg_load(await module_or_path, imports); + + return __wbg_finalize_init(instance, module); +} + +export { initSync, __wbg_init as default }; diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photocraft/photocraft_bg.wasm.d.ts b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/photocraft_bg.wasm.d.ts new file mode 100644 index 00000000..7cbac8c5 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/photocraft_bg.wasm.d.ts @@ -0,0 +1,27 @@ +/* tslint:disable */ +/* eslint-disable */ +export const memory: WebAssembly.Memory; +export const miniapp_call: (a: number, b: number) => [number, number, number]; +export const main: (a: number, b: number) => number; +export const wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Function_fn_wasm_bindgen_54f023e2846dbff4___JsValue_____wasm_bindgen_54f023e2846dbff4___sys__Undefined___js_sys_526e9b82b0b84cf5___Function_fn_wasm_bindgen_54f023e2846dbff4___JsValue_____wasm_bindgen_54f023e2846dbff4___sys__Undefined_______true_: (a: number, b: number, c: any, d: any) => void; +export const wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true_: (a: number, b: number, c: any) => [number, number]; +export const wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true__10: (a: number, b: number, c: any) => [number, number]; +export const wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true__11: (a: number, b: number, c: any) => [number, number]; +export const wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wasm_bindgen_54f023e2846dbff4___sys__JsNullable_wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsError___true__6: (a: number, b: number, c: any) => [number, number]; +export const wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_54f023e2846dbff4___JsValue___true_: (a: number, b: number) => [number, number]; +export const wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true_: (a: number, b: number, c: any) => void; +export const wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true__4: (a: number, b: number, c: any) => void; +export const wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true__5: (a: number, b: number, c: any) => void; +export const wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___js_sys_526e9b82b0b84cf5___Array______true__9: (a: number, b: number, c: any) => void; +export const wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuDeviceLostInfo__GpuDeviceLostInfo______true_: (a: number, b: number, c: any) => void; +export const wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke___wgpu_9990bb6ea9135c56___backend__webgpu__webgpu_sys__gen_GpuDeviceLostInfo__GpuDeviceLostInfo______true__8: (a: number, b: number, c: any) => void; +export const wasm_bindgen_54f023e2846dbff4___convert__closures_____invoke_______true_: (a: number, b: number) => void; +export const __wbindgen_malloc: (a: number, b: number) => number; +export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; +export const __wbindgen_exn_store: (a: number) => void; +export const __externref_table_alloc: () => number; +export const __wbindgen_externrefs: WebAssembly.Table; +export const __wbindgen_free: (a: number, b: number, c: number) => void; +export const __wbindgen_destroy_closure: (a: number, b: number) => void; +export const __externref_table_dealloc: (a: number) => void; +export const __wbindgen_start: () => void; diff --git a/plugins/webguhui/minimax-photo/miniapp/client/photocraft/photocraft_bg.wasm.gz b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/photocraft_bg.wasm.gz new file mode 100644 index 00000000..7526e641 Binary files /dev/null and b/plugins/webguhui/minimax-photo/miniapp/client/photocraft/photocraft_bg.wasm.gz differ diff --git a/plugins/webguhui/minimax-photo/miniapp/client/psd-blends.js b/plugins/webguhui/minimax-photo/miniapp/client/psd-blends.js new file mode 100644 index 00000000..1de2982c --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/psd-blends.js @@ -0,0 +1,42 @@ +// Layer record keys from Adobe Photoshop File Formats Specification. +// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ +export const psdBlendKeys = Object.freeze({ + 'source-over': 'norm', + dissolve: 'diss', + multiply: 'mul ', + screen: 'scrn', + overlay: 'over', + darken: 'dark', + lighten: 'lite', + 'color-dodge': 'div ', + 'color-burn': 'idiv', + 'hard-light': 'hLit', + 'soft-light': 'sLit', + difference: 'diff', + exclusion: 'smud', + hue: 'hue ', + saturation: 'sat ', + color: 'colr', + luminosity: 'lum ', + 'linear-burn': 'lbrn', + 'linear-dodge': 'lddg', + subtract: 'fsub', + divide: 'fdiv', + 'vivid-light': 'vLit', + 'linear-light': 'lLit', + 'pin-light': 'pLit', + 'hard-mix': 'hMix', + 'darker-color': 'dkCl', + 'lighter-color': 'lgCl', +}); +const modes = new Map(Object.entries(psdBlendKeys).map(([mode, key]) => [key, mode])); +export function readBlendKey(key) { + const mode = modes.get(key); + if (!mode) throw Error(`PSD 混合模式暂不支持:${key}。请先在原软件转换图层。`); + return mode; +} +export function writeBlendKey(mode) { + const key = psdBlendKeys[mode]; + if (!key) throw Error(`无法导出混合模式:${mode}`); + return key; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/recording.js b/plugins/webguhui/minimax-photo/miniapp/client/recording.js new file mode 100644 index 00000000..e4fdf616 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/recording.js @@ -0,0 +1,78 @@ +import { download } from './model.js'; + +let recorder = null; +let requesting = false; + +export async function toggleRecording(status) { + if (requesting) { + status('正在等待屏幕共享选择,请在浏览器中选择或取消'); + return; + } + if (recorder) { + if (recorder.state === 'recording') recorder.stop(); + status('正在结束录屏,请稍候'); + return; + } + if (!navigator.mediaDevices?.getDisplayMedia || typeof MediaRecorder === 'undefined') + throw Error('当前浏览器不支持屏幕录制,请使用系统录屏工具'); + + requesting = true; + status('请选择要录制的修图工作台窗口或标签页'); + let stream; + try { + stream = await navigator.mediaDevices.getDisplayMedia({ + video: { frameRate: 20 }, + audio: false, + }); + const mime = ['video/webm;codecs=vp9', 'video/webm;codecs=vp8', 'video/webm'].find((type) => + MediaRecorder.isTypeSupported(type), + ); + const current = new MediaRecorder(stream, mime ? { mimeType: mime } : {}); + const chunks = []; + let failed = false; + const release = () => { + stream.getTracks().forEach((track) => track.stop()); + if (recorder === current) recorder = null; + }; + current.ondataavailable = (event) => { + if (event.data.size) chunks.push(event.data); + }; + current.onerror = () => { + failed = true; + release(); + status('录屏失败,已停止屏幕共享,请重试或使用系统录屏工具', true); + }; + current.onstop = () => { + release(); + if (failed) return; + if (!chunks.length) { + status('未收到录屏内容,请重试或使用系统录屏工具', true); + return; + } + try { + download(new Blob(chunks, { type: current.mimeType }), '修图操作录屏.webm'); + status('录屏已导出'); + } catch (error) { + status(error.message || '录屏导出失败', true); + } + }; + const video = stream.getVideoTracks()[0]; + if (!video || video.readyState === 'ended') throw Error('屏幕共享已经结束,请重新选择'); + video.onended = () => { + if (current.state === 'recording') current.stop(); + }; + recorder = current; + current.start(1000); + status('正在录屏 · 帮助菜单中再次点击“录制 / 停止录屏”结束'); + } catch (error) { + stream?.getTracks().forEach((track) => track.stop()); + recorder = null; + if (error.name === 'NotAllowedError' || error.name === 'AbortError') { + status('未开始录屏:屏幕共享已取消或未获授权'); + return; + } + throw error; + } finally { + requesting = false; + } +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/render-cache.js b/plugins/webguhui/minimax-photo/miniapp/client/render-cache.js new file mode 100644 index 00000000..6eb6601c --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/render-cache.js @@ -0,0 +1,46 @@ +// LRU budget includes retained source/mask pixels as well as the rendered output. +// Pixel edits must invalidate the source; immutable canvas replacements miss automatically. +export function createRenderCache(budget = 64 * 1024 * 1024) { + const entries = new Map(); + let bytes = 0, + hits = 0, + misses = 0; + function invalidate(source) { + const entry = entries.get(source); + if (entry) { + bytes -= entry.bytes; + entries.delete(source); + } + } + return { + invalidate, + clear() { + entries.clear(); + bytes = 0; + }, + stats() { + return { bytes, entries: entries.size, hits, misses, budget }; + }, + get(source, mask, styles, render) { + const entry = entries.get(source); + if (entry && entry.mask === mask && entry.styles === styles) { + hits++; + entries.delete(source); + entries.set(source, entry); + return entry.result; + } + misses++; + invalidate(source); + const result = render(); + const pixels = new Set([source, mask, result.image]); + let cost = 0; + for (const image of pixels) if (image) cost += image.width * image.height * 4; + if (cost <= budget) { + while (bytes + cost > budget && entries.size) invalidate(entries.keys().next().value); + entries.set(source, { mask, styles, result, bytes: cost }); + bytes += cost; + } + return result; + }, + }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/selection-outline.js b/plugins/webguhui/minimax-photo/miniapp/client/selection-outline.js new file mode 100644 index 00000000..f05ae51b --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/selection-outline.js @@ -0,0 +1,47 @@ +// Return boundary segments of scanline selections; interior row edges are omitted. +export function runOutline(runs) { + const rows = new Map(), + edges = []; + for (const [x, y, w] of runs) { + if (w <= 0) continue; + if (!rows.has(y)) rows.set(y, []); + rows.get(y).push([x, x + w]); + } + for (const [y, intervals] of rows) { + intervals.sort((a, b) => a[0] - b[0]); + const merged = []; + for (const interval of intervals) { + const last = merged.at(-1); + if (last && interval[0] <= last[1]) last[1] = Math.max(last[1], interval[1]); + else merged.push([...interval]); + } + rows.set(y, merged); + } + function horizontal(start, end, y, neighbors) { + let cursor = start; + const row = neighbors || []; + let low = 0, + high = row.length; + while (low < high) { + const mid = (low + high) >>> 1; + if (row[mid][1] <= cursor) low = mid + 1; + else high = mid; + } + for (let i = low; i < row.length; i++) { + const [a, b] = row[i]; + if (b <= cursor) continue; + if (a >= end) break; + if (a > cursor) edges.push([cursor, y, Math.min(a, end), y]); + cursor = Math.max(cursor, b); + if (cursor >= end) return; + } + if (cursor < end) edges.push([cursor, y, end, y]); + } + for (const [y, intervals] of rows) + for (const [a, b] of intervals) { + horizontal(a, b, y, rows.get(y - 1)); + horizontal(a, b, y + 1, rows.get(y + 1)); + edges.push([a, y, a, y + 1], [b, y, b, y + 1]); + } + return edges; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/showcase/portrait.webp b/plugins/webguhui/minimax-photo/miniapp/client/showcase/portrait.webp new file mode 100644 index 00000000..9009d899 Binary files /dev/null and b/plugins/webguhui/minimax-photo/miniapp/client/showcase/portrait.webp differ diff --git a/plugins/webguhui/minimax-photo/miniapp/client/showcase/poster.webp b/plugins/webguhui/minimax-photo/miniapp/client/showcase/poster.webp new file mode 100644 index 00000000..6fb6b120 Binary files /dev/null and b/plugins/webguhui/minimax-photo/miniapp/client/showcase/poster.webp differ diff --git a/plugins/webguhui/minimax-photo/miniapp/client/showcase/product.webp b/plugins/webguhui/minimax-photo/miniapp/client/showcase/product.webp new file mode 100644 index 00000000..1032d2fc Binary files /dev/null and b/plugins/webguhui/minimax-photo/miniapp/client/showcase/product.webp differ diff --git a/plugins/webguhui/minimax-photo/miniapp/client/style-pixels.js b/plugins/webguhui/minimax-photo/miniapp/client/style-pixels.js new file mode 100644 index 00000000..ca3791c2 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/style-pixels.js @@ -0,0 +1,101 @@ +// Exact squared Euclidean distance transform, two linear passes. +// Values refer to pixel centers. Callers add a transparent border for inside distances. +export function distanceMap(alpha, width, height, toOpaque) { + const count = width * height; + if (alpha.length !== count) throw Error('透明度尺寸不匹配'); + const result = new Float32Array(count); + const size = Math.max(width, height); + const f = new Float64Array(size), + d = new Float64Array(size); + const vertices = new Int32Array(size), + breaks = new Float64Array(size + 1); + function transform(n) { + let k = 0; + vertices[0] = 0; + breaks[0] = -Infinity; + breaks[1] = Infinity; + for (let q = 1; q < n; q++) { + let cross; + do { + const p = vertices[k]; + cross = (f[q] + q * q - (f[p] + p * p)) / (2 * (q - p)); + if (cross > breaks[k]) break; + k--; + } while (k >= 0); + k++; + vertices[k] = q; + breaks[k] = cross; + breaks[k + 1] = Infinity; + } + k = 0; + for (let q = 0; q < n; q++) { + while (breaks[k + 1] < q) k++; + d[q] = (q - vertices[k]) ** 2 + f[vertices[k]]; + } + } + for (let x = 0; x < width; x++) { + for (let y = 0; y < height; y++) f[y] = alpha[y * width + x] >= 128 === toOpaque ? 0 : 1e12; + transform(height); + for (let y = 0; y < height; y++) result[y * width + x] = d[y]; + } + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) f[x] = result[y * width + x]; + transform(width); + for (let x = 0; x < width; x++) result[y * width + x] = d[x]; + } + return result; +} +export const clamp01 = (v) => Math.max(0, Math.min(1, v)); +export const rgb = (hex) => [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16)); + +export function strokePixels(alpha, width, height, effect) { + const outer = effect.position !== 'inside' ? distanceMap(alpha, width, height, true) : null; + const inner = effect.position !== 'outside' ? distanceMap(alpha, width, height, false) : null; + const size = effect.position === 'center' ? effect.size / 2 : effect.size; + const color = rgb(effect.color), + out = new Uint8ClampedArray(alpha.length * 4); + for (let i = 0; i < alpha.length; i++) { + const a = alpha[i] / 255; + const coverage = + (outer ? clamp01(size + 0.5 - Math.sqrt(outer[i])) * (1 - a) : 0) + + (inner ? clamp01(size + 0.5 - Math.sqrt(inner[i])) * a : 0); + out.set(color, i * 4); + out[i * 4 + 3] = coverage * effect.opacity * 255; + } + return out; +} + +export function bevelPixels(alpha, width, height, effect) { + const distances = distanceMap(alpha, width, height, false); + const azimuth = (effect.angle * Math.PI) / 180, + elevation = (effect.elevation * Math.PI) / 180; + const light = [ + Math.cos(azimuth) * Math.cos(elevation), + -Math.sin(azimuth) * Math.cos(elevation), + Math.sin(elevation), + ]; + const highlight = rgb(effect.color), + shadow = rgb(effect.endColor); + const out = new Uint8ClampedArray(alpha.length * 4); + const heightAt = (x, y) => + Math.min( + effect.size, + Math.sqrt( + distances[ + Math.max(0, Math.min(height - 1, y)) * width + Math.max(0, Math.min(width - 1, x)) + ], + ), + ) * effect.depth; + for (let y = 0; y < height; y++) + for (let x = 0; x < width; x++) { + const i = y * width + x; + if (!alpha[i]) continue; + const nx = (heightAt(x - 1, y) - heightAt(x + 1, y)) / 2; + const ny = (heightAt(x, y - 1) - heightAt(x, y + 1)) / 2; + const lighting = + (nx * light[0] + ny * light[1] + light[2]) / Math.hypot(nx, ny, 1) - light[2]; + out.set(lighting >= 0 ? highlight : shadow, i * 4); + out[i * 4 + 3] = clamp01(Math.abs(lighting)) * alpha[i] * effect.opacity; + } + return out; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/style.css b/plugins/webguhui/minimax-photo/miniapp/client/style.css new file mode 100644 index 00000000..a1aab57a --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/style.css @@ -0,0 +1,924 @@ +/* Standalone Mini App mapping from the public MiniMax Code visual reference. */ +:root { + color-scheme: light; + --mcode-bg: #ffffff; + --mcode-bg-secondary: #f5f5f5; + --mcode-surface: #ffffff; + --mcode-surface-muted: #fafafa; + --mcode-text: #171717; + --mcode-text-muted: #666666; + --mcode-border: #0a0a0a14; + --mcode-accent: #0094fc; + --mcode-danger: #f73646; + --mcode-primary-action-bg: #171717; + --mcode-primary-action-text: #ffffff; + --mcode-selection: color-mix(in srgb, var(--mcode-accent) 10%, var(--mcode-bg)); + --mcode-shadow: #0a0a0a14; + --mcode-overlay: #0a0a0a66; + --checker-base: #fafafa; + --checker-grid: #dedede; + --bg: var(--mcode-bg); + --surface: var(--mcode-surface); + --panel: var(--mcode-bg); + --border: var(--mcode-border); + --text: var(--mcode-text); + --muted: var(--mcode-text-muted); + --accent: var(--mcode-accent); + --hover: var(--mcode-bg-secondary); + --danger: var(--mcode-danger); + font: + 13px/1.5 ui-sans-serif, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + sans-serif; + color: var(--text); + background: var(--bg); +} +* { + box-sizing: border-box; +} +body { + margin: 0; + height: 100vh; + display: flex; + flex-direction: column; + overflow: hidden; +} +button, +input, +select { + font: inherit; + color: inherit; +} +button, +select { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 5px; + padding: 5px 9px; + cursor: pointer; +} +button:hover { + background: var(--hover); +} +button:disabled { + opacity: 0.4; + cursor: default; +} +button:focus-visible, +input:focus-visible, +select:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} +.primary { + background: var(--mcode-primary-action-bg); + border-color: var(--mcode-primary-action-bg); + color: var(--mcode-primary-action-text); +} +.primary:hover { + background: var(--mcode-primary-action-bg); +} +input[type='number'], +input[type='text'], +textarea { + background: var(--bg); + border: 1px solid var(--border); + border-radius: 5px; + padding: 6px; + color: var(--text); + max-width: 100%; +} +input[type='range'] { + accent-color: var(--accent); + min-width: 40px; +} +input[type='color'] { + width: 32px; + height: 28px; + border: 0; + padding: 0; + background: transparent; +} +header { + display: flex; + align-items: center; + gap: 8px; + height: 48px; + flex-shrink: 0; + padding: 0 12px; + border-bottom: 1px solid var(--border); + background: var(--panel); +} +header strong { + white-space: nowrap; + font-size: 15px; + margin-right: 15px; +} +small { + font-size: 10px; + color: var(--muted); + font-weight: 400; + margin-left: 5px; +} +.spacer { + flex: 1; +} +nav { + display: flex; + gap: 2px; +} +nav details { + position: relative; +} +summary { + list-style: none; + cursor: pointer; + padding: 5px 8px; + border-radius: 4px; +} +summary:hover, +details[open] > summary { + background: var(--hover); +} +.menu { + position: absolute; + z-index: 20; + top: 32px; + left: 0; + width: 210px; + background: var(--surface); + border: 1px solid var(--border); + border-radius: 7px; + box-shadow: 0 8px 24px var(--mcode-overlay); + padding: 5px; + max-height: 75vh; + overflow: auto; +} +.menu button { + display: flex; + width: 100%; + border: 0; + text-align: left; + background: none; + padding: 6px 9px; +} +.menu button:hover { + background: var(--hover); +} +.menu hr { + border: 0; + border-top: 1px solid var(--border); +} +#options { + height: 43px; + display: flex; + align-items: center; + gap: 14px; + padding: 6px 12px; + background: var(--panel); + border-bottom: 1px solid var(--border); + flex-shrink: 0; +} +label { + display: flex; + gap: 6px; + align-items: center; + font-size: 12px; + color: var(--muted); +} +#size { + width: 60px; +} +#flow { + width: 85px; +} +#hint { + color: var(--muted); + font-size: 12px; + margin-left: 5px; +} +#workspace { + display: flex; + min-height: 0; + flex: 1; +} +#tools { + width: 58px; + flex-shrink: 0; + display: flex; + flex-direction: column; + gap: 3px; + padding: 7px 5px; + overflow-y: auto; + background: var(--panel); + border-right: 1px solid var(--border); +} +#tools button { + font-size: 11px; + min-height: 32px; + border-color: transparent; + background: transparent; + padding: 5px 1px; +} +#tools button[aria-pressed='true'] { + color: var(--accent); + border-color: var(--mcode-accent); + background: var(--mcode-selection); +} +#tools button:hover { + background: var(--hover); +} +main { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; +} +#tabs { + height: 34px; + background: var(--panel); + display: flex; + overflow-x: auto; + flex-shrink: 0; + border-bottom: 1px solid var(--border); +} +#tabs button { + border: 0; + border-radius: 0; + background: transparent; + color: var(--muted); + white-space: nowrap; + padding: 5px 18px; +} +#tabs button[aria-selected='true'] { + color: var(--text); + background: var(--bg); + box-shadow: inset 0 2px var(--accent); +} +#stage { + position: relative; + flex: 1; + overflow: hidden; + background: var(--mcode-bg-secondary); + touch-action: none; + outline: none; +} +#canvas-wrap { + position: absolute; + transform-origin: 0 0; + background-color: var(--checker-base); + background-image: conic-gradient( + var(--checker-grid) 25%, + transparent 0 50%, + var(--checker-grid) 0 75%, + transparent 0 + ); + background-size: 16px 16px; + box-shadow: 0 10px 50px var(--mcode-shadow); +} +canvas { + display: block; +} +#overlay { + position: absolute; + left: 0; + top: 0; + touch-action: none; +} +#right { + width: 246px; + flex-shrink: 0; + background: var(--panel); + border-left: 1px solid var(--border); + overflow: auto; +} +#right section { + padding: 12px; + border-bottom: 1px solid var(--border); +} +h2 { + font-size: 13px; + font-weight: 600; + margin: 0 0 10px; +} +.panel-title { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 8px; +} +.panel-title h2 { + margin: 0; +} +.row { + display: flex; + gap: 4px; + margin-top: 10px; +} +.row button { + padding: 4px 7px; + font-size: 11px; +} +.layer-controls { + display: grid; + gap: 8px; +} +.layer-controls label input { + width: 100px; + flex: 1; +} +.layer { + display: flex; + align-items: center; + gap: 7px; + padding: 7px 5px; + border: 1px solid transparent; + border-radius: 5px; + margin-top: 5px; + cursor: pointer; +} +.layer.selected { + background: var(--mcode-selection); + border-color: var(--mcode-border); +} +.layer canvas { + flex-shrink: 0; + width: 32px; + height: 26px; + object-fit: contain; + background: var(--mcode-bg-secondary); +} +.layer input[type='text'] { + flex: 1; + width: 90px; + min-width: 0; + background: transparent; + border: 0; + padding: 2px; + color: var(--text); +} +.layer input[type='checkbox'] { + margin: 0; + accent-color: var(--accent); +} +.layer button { + white-space: nowrap; + flex-shrink: 0; + font-size: 10px; + border: 0; + padding: 3px; + background: none; + color: var(--muted); +} +.layer .adjustment-thumb { + width: 32px; + height: 26px; + background: var(--mcode-surface-muted); + color: var(--text); +} +#quick { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 6px; +} +#quick button { + font-size: 12px; +} +#history { + padding-left: 20px; + color: var(--muted); + max-height: 140px; + overflow: auto; + margin: 0; + font-size: 12px; +} +.tips p { + color: var(--muted); + font-size: 12px; + margin: 0 0 12px; +} +.tips button { + margin-bottom: 5px; +} +footer { + display: flex; + align-items: center; + gap: 9px; + height: 34px; + padding: 4px 10px; + border-top: 1px solid var(--border); + background: var(--panel); + font-size: 11px; + flex-shrink: 0; +} +footer button { + padding: 1px 7px; + font-size: 11px; +} +#status.error { + color: var(--danger); +} +#welcome { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + gap: 12px; + background: var(--mcode-bg-secondary); +} +#welcome[hidden] { + display: none; +} +#welcome h1 { + font-size: 26px; + font-weight: 500; + letter-spacing: 1px; + margin: 0 0 6px; +} +#welcome p { + margin: 0 0 9px; + color: var(--muted); +} +#welcome button { + width: 180px; + padding: 9px; +} +.muted { + color: var(--muted); + font-size: 12px; +} +dialog { + background: var(--surface); + color: var(--text); + border: 1px solid var(--border); + border-radius: 12px; + padding: 20px; + width: min(520px, 90vw); + max-height: 85vh; + box-shadow: 0 20px 80px var(--mcode-shadow); +} +dialog::backdrop { + background: var(--mcode-overlay); +} +.dialog-head { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 16px; +} +.dialog-head h2 { + margin: 0; + font-size: 17px; +} +.dialog-head button { + background: none; + border: 0; + font-size: 22px; +} +.dialog-actions { + display: flex; + justify-content: flex-end; + gap: 8px; + margin-top: 20px; +} +#dialog-body { + display: grid; + gap: 12px; + overflow: auto; + max-height: 60vh; +} +#dialog-body label { + justify-content: space-between; + font-size: 13px; +} +#dialog-body input[type='range'] { + width: 65%; +} +#dialog-body textarea { + width: 100%; + min-height: 100px; + font: inherit; +} +#dialog-body p { + margin: 0; + color: var(--muted); +} +.project-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; +} +.project-row span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.checklist { + padding-left: 20px; + color: var(--muted); +} +@media (max-width: 1000px) { + header strong small { + display: none; + } + header strong { + margin-right: 2px; + } + nav summary { + padding: 5px; + } + #hint { + display: none; + } + #right { + width: 210px; + } + .layer input[type='text'] { + width: 65px; + } +} +@media (max-width: 760px) { + #right { + display: none; + } + header strong { + display: none; + } + #options { + gap: 7px; + overflow-x: auto; + white-space: nowrap; + } + header { + padding: 0 5px; + gap: 4px; + } + header > button { + font-size: 11px; + padding: 5px; + } + #tools { + width: 48px; + } + #options label { + font-size: 11px; + } + #options #flow { + width: 55px; + } + #status { + max-width: 45vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + #dimensions { + display: none; + } +} +@media (prefers-reduced-motion: reduce) { + * { + scroll-behavior: auto !important; + } +} + +#tolerance-option[hidden] { + display: none; +} + +[data-theme='dark'] { + color-scheme: dark; + --mcode-bg: #171717; + --mcode-bg-secondary: #1c1c1c; + --mcode-surface: #262626; + --mcode-surface-muted: #262626; + --mcode-text: #ededed; + --mcode-text-muted: #949494; + --mcode-border: #ffffff14; + --mcode-accent: #0077d9; + --mcode-danger: #e31937; + --mcode-primary-action-bg: #ffffff; + --mcode-primary-action-text: #171717; +} +.action-mount { + display: inline-flex; + flex-shrink: 0; + vertical-align: middle; +} +button[data-variant] { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 8px; + border-radius: 8px; + font-size: 13px; + font-weight: 500; + height: 32px; + padding: 0 12px; + white-space: nowrap; + transition: + background-color 150ms ease-out, + color 150ms ease-out; +} +button[data-variant] svg { + width: 16px; + height: 16px; + flex-shrink: 0; + pointer-events: none; +} +button[data-variant][data-variant='default'] { + background: var(--mcode-primary-action-bg); + color: var(--mcode-primary-action-text); + border-color: transparent; +} +button[data-variant][data-variant='default']:hover { + opacity: 0.85; +} +button[data-variant][data-variant='outline'] { + background: var(--bg); + border-color: var(--border); +} +button[data-variant][data-variant='ghost'] { + background: transparent; + border-color: transparent; +} +button[data-variant][data-variant='ghost']:hover, +button[data-variant][data-variant='outline']:hover { + background: var(--hover); +} +button[data-variant][data-size^='icon'] { + width: 32px; + padding: 0; +} +button[data-variant]:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} +[data-slot='tooltip-content'] { + z-index: 100; + background: var(--mcode-text); + color: var(--mcode-bg); + padding: 6px 10px; + border-radius: 8px; + font-size: 12px; + max-width: 240px; + box-shadow: 0 4px 16px var(--mcode-shadow); +} +[data-slot='tooltip-content'] svg { + fill: var(--mcode-text); +} +#tools { + width: 88px; + gap: 0; + padding: 8px; +} +.tool-group { + display: grid; + grid-template-columns: repeat(2, 32px); + gap: 4px; + padding: 8px 0; + border-bottom: 1px solid var(--border); +} +.tool-group:first-child { + padding-top: 0; +} +.tool-group:last-child { + border-bottom: 0; +} +#tools button { + min-height: 32px; +} +#tools button[aria-pressed='true'] { + background: var(--mcode-selection); + color: var(--accent); + border-color: var(--mcode-border); +} +#right { + width: 260px; +} +#right section { + padding: 16px; +} +header { + height: 56px; +} +header strong { + font-weight: 600; + margin-right: 8px; +} +#options { + height: 48px; + gap: 12px; +} +#tabs { + height: 40px; +} +#tabs button[aria-selected='true'] { + box-shadow: inset 0 -2px var(--accent); +} +#welcome { + gap: 12px; +} +#welcome h1 { + font-size: 20px; + line-height: 28px; + letter-spacing: 0; +} +#welcome p { + max-width: 360px; + text-align: center; +} +#welcome button { + width: 180px; + height: 36px; +} +select, +input[type='number'], +input[type='text'], +textarea { + border-radius: 8px; +} +.menu { + border-radius: 12px; + padding: 6px; + box-shadow: 0 4px 20px var(--mcode-shadow); +} +.menu button { + border-radius: 8px; + min-height: 32px; +} +.layer { + border-radius: 8px; + padding: 8px 4px; +} +.layer.selected { + background: var(--mcode-selection); + border-color: var(--mcode-border); +} +.row { + gap: 8px; +} +#dialog-body label:has(textarea) { + display: flex; + flex-direction: column; + align-items: stretch; + gap: 8px; +} +#dialog-body textarea { + padding: 10px; +} +@media (max-width: 1100px) { + header { + flex-wrap: wrap; + height: auto; + min-height: 56px; + padding: 8px 12px; + row-gap: 6px; + } + header nav { + order: 5; + flex-basis: 100%; + } + #right { + width: 224px; + } + #options { + overflow-x: auto; + white-space: nowrap; + } +} +@media (max-width: 760px) { + #tools { + width: 88px; + } + header strong { + display: block; + font-size: 14px; + } + header .action-mount button { + padding: 0 8px; + } +} +@media (prefers-reduced-motion: reduce) { + button[data-variant] { + transition: none; + } +} + +/* AI composer stays within the canvas edge so layer controls remain accessible. */ +#agent-panel-root { + position: fixed; + right: 276px; + bottom: 48px; + z-index: 25; +} +.agent-panel { + width: 348px; + max-width: calc(100vw - 40px); + max-height: calc(100dvh - 160px); + overflow: auto; + background: var(--mcode-surface); + color: var(--text); + border: 1px solid var(--border); + border-radius: 16px; + box-shadow: 0 12px 40px var(--mcode-shadow); + padding: 16px; +} +.agent-panel-heading, +.agent-panel-heading > span, +.agent-send-row { + display: flex; + align-items: center; + gap: 8px; +} +.agent-panel-heading, +.agent-send-row { + justify-content: space-between; +} +.agent-panel-heading strong { + font: inherit; + font-weight: 600; +} +.agent-context { + margin: 4px 0 12px; + color: var(--muted); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.agent-mode { + display: flex; + align-items: center; + gap: 8px; + color: var(--muted); + margin-bottom: 8px; +} +.agent-mode select { + flex: 1; + min-width: 0; +} +.agent-panel textarea { + display: block; + width: 100%; + resize: vertical; + min-height: 80px; + max-height: 160px; + padding: 12px; + font: inherit; + color: var(--text); + background: var(--mcode-surface-muted); + border: 1px solid var(--border); + border-radius: 8px; +} +.agent-panel textarea:focus-visible, +.agent-panel select:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} +.agent-panel textarea::placeholder { + color: var(--muted); +} +.agent-send-row { + margin-top: 12px; +} +.agent-send-row > span { + color: var(--muted); + font-size: inherit; +} +.agent-feedback { + margin: 12px 0 0; + color: var(--muted); + overflow-wrap: anywhere; +} +.agent-feedback.error { + color: var(--danger); +} +.agent-copy { + margin-top: 12px; + display: grid; + gap: 8px; +} +.agent-copy button { + justify-self: end; +} +.agent-launcher { + box-shadow: 0 8px 24px var(--mcode-shadow); +} +@media (max-width: 1000px) { + #agent-panel-root { + right: 24px; + } +} +@media (max-height: 600px) { + #agent-panel-root { + bottom: 40px; + } + .agent-panel { + max-height: calc(100dvh - 100px); + } +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/styles-dialog.js b/plugins/webguhui/minimax-photo/miniapp/client/styles-dialog.js new file mode 100644 index 00000000..932b7dc8 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/styles-dialog.js @@ -0,0 +1,149 @@ +import { canvas, layerImage, LIMIT_PIXELS } from './model.js'; +import { field, note } from './dialogs.js'; +import { normalizeStyles, renderStyles, stylePadding, styleNames } from './layer-styles.js'; + +export function showStylesDialog(layer, { modal, apply }) { + const styles = normalizeStyles(layer.styles); + const source = layerImage(layer); + const scale = Math.min(1, 360 / source.width, 200 / source.height); + const thumb = canvas( + Math.max(1, Math.round(source.width * scale)), + Math.max(1, Math.round(source.height * scale)), + ); + thumb.getContext('2d').drawImage(source, 0, 0, thumb.width, thumb.height); + const preview = canvas(420, 260); + preview.setAttribute('aria-label', '图层样式预览'); + preview.style.maxWidth = '100%'; + preview.style.background = '#3c4148'; + const tabs = document.createElement('select'); + tabs.setAttribute('aria-label', '样式类型'); + for (const [value, label] of Object.entries(styleNames)) { + const option = document.createElement('option'); + option.value = value; + option.textContent = label; + tabs.append(option); + } + const controls = document.createElement('div'); + let raf = 0; + function draw() { + if (raf) return; + raf = requestAnimationFrame(() => { + raf = 0; + const small = structuredClone(styles); + for (const key of Object.keys(small)) + for (const prop of ['blur', 'x', 'y', 'size', 'distance']) + if (prop in small[key]) small[key][prop] *= scale; + const result = renderStyles(thumb, small, canvas); + const ctx = preview.getContext('2d'); + ctx.clearRect(0, 0, preview.width, preview.height); + const fit = Math.min( + 1, + preview.width / result.image.width, + preview.height / result.image.height, + ); + ctx.drawImage( + result.image, + (preview.width - result.image.width * fit) / 2, + (preview.height - result.image.height * fit) / 2, + result.image.width * fit, + result.image.height * fit, + ); + }); + } + function fields() { + const effect = styles[tabs.value]; + const enabledLabel = document.createElement('label'), + enabled = document.createElement('input'); + enabled.type = 'checkbox'; + enabled.checked = effect.enabled; + enabledLabel.append(enabled, '启用此样式'); + enabled.onchange = () => { + effect.enabled = enabled.checked; + draw(); + }; + controls.replaceChildren(enabledLabel); + for (const [prop, label, type, attrs] of [ + ['color', '颜色', 'color', {}], + ['endColor', '结束颜色', 'color', {}], + ['opacity', '样式不透明度', 'range', { min: 0, max: 1, step: 0.01 }], + ['blur', '模糊半径', 'range', { min: 0, max: 60, step: 1 }], + ['x', '水平偏移', 'range', { min: -100, max: 100, step: 1 }], + ['y', '垂直偏移', 'range', { min: -100, max: 100, step: 1 }], + ['angle', '角度', 'range', { min: -180, max: 180, step: 1 }], + ['size', '大小', 'range', { min: 1, max: 60, step: 1 }], + ['depth', '深度', 'range', { min: 0.1, max: 10, step: 0.1 }], + ['elevation', '光源高度', 'range', { min: 1, max: 89, step: 1 }], + ['distance', '距离', 'range', { min: 0, max: 100, step: 1 }], + ]) { + if (!(prop in effect)) continue; + const [row, input] = field(label, effect[prop], type, attrs); + const output = document.createElement('output'); + output.textContent = effect[prop]; + row.append(output); + input.oninput = () => { + effect[prop] = type === 'color' ? input.value : Number(input.value); + output.textContent = input.value; + draw(); + }; + controls.append(row); + } + for (const [prop, label, options] of [ + [ + 'position', + '描边位置', + [ + ['outside', '外侧'], + ['inside', '内侧'], + ['center', '居中'], + ], + ], + [ + 'pattern', + '图案', + [ + ['checker', '棋盘'], + ['dots', '圆点'], + ['stripes', '条纹'], + ], + ], + ]) { + if (!(prop in effect)) continue; + const row = document.createElement('label'); + row.textContent = label; + const select = document.createElement('select'); + for (const [value, text] of options) { + const option = document.createElement('option'); + option.value = value; + option.textContent = text; + select.append(option); + } + select.value = effect[prop]; + select.onchange = () => { + effect[prop] = select.value; + draw(); + }; + row.append(select); + controls.append(row); + } + draw(); + } + tabs.onchange = fields; + modal( + '图层样式', + [ + tabs, + controls, + preview, + note('样式不改变原始像素,可随时重新编辑。工程保留参数;导出 PSD 时转换为像素。'), + ], + () => { + const normalized = normalizeStyles(styles), + padding = stylePadding(normalized); + if ((source.width + 2 * padding) * (source.height + 2 * padding) > LIMIT_PIXELS) + throw Error('样式扩展后的图层超过 3200 万像素,请缩小图片或减小投影、发光范围'); + return apply(normalized); + }, + '应用', + ); + fields(); +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/tiff-lzw.js b/plugins/webguhui/minimax-photo/miniapp/client/tiff-lzw.js new file mode 100644 index 00000000..862bfa1d --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/tiff-lzw.js @@ -0,0 +1,59 @@ +// TIFF 6.0 section 13: MSB-first codes with early width changes, unlike GIF LZW. +export function unpackLZW(source, size, fail) { + const out = new Uint8Array(size), + prefix = new Uint16Array(4096), + suffix = new Uint8Array(4096), + stack = new Uint8Array(4096); + let bit = 0, + width = 9, + next = 258, + previous = -1, + first = 0, + written = 0, + initialized = false; + function readCode() { + if (bit + width > source.length * 8) fail('LZW 数据不完整'); + let code = 0; + for (let i = 0; i < width; i++, bit++) + code = (code << 1) | ((source[bit >>> 3] >>> (7 - (bit & 7))) & 1); + return code; + } + while (true) { + let code = readCode(); + if (code === 256) { + width = 9; + next = 258; + previous = -1; + initialized = true; + continue; + } + if (!initialized) fail('LZW 缺少起始标记'); + if (code === 257) { + if (written !== size) fail('LZW 像素不足'); + return out; + } + const original = code; + let count = 0; + if (code === next && previous >= 0) { + stack[count++] = first; + code = previous; + } else if (code >= next) fail('LZW 字典索引无效'); + while (code >= 258) { + if (count >= stack.length - 1) fail('LZW 字典链无效'); + stack[count++] = suffix[code]; + code = prefix[code]; + } + if (code > 255) fail('LZW 字典内容无效'); + first = code; + stack[count++] = first; + if (written + count > size) fail('LZW 像素超过图像尺寸'); + while (count) out[written++] = stack[--count]; + if (previous >= 0 && next < 4096) { + prefix[next] = previous; + suffix[next] = first; + next++; + if (width < 12 && next === (1 << width) - 1) width++; + } + previous = original; + } +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/tiff-reader.js b/plugins/webguhui/minimax-photo/miniapp/client/tiff-reader.js new file mode 100644 index 00000000..0896d829 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/tiff-reader.js @@ -0,0 +1,176 @@ +import { unpackLZW } from './tiff-lzw.js'; +// Bounded TIFF 6.0 strip reader; unsupported encodings fail before pixel allocation. +export function readTIFF(buffer) { + const v = new DataView(buffer), + bytes = new Uint8Array(buffer); + const fail = (message) => { + throw Error('TIFF:' + message); + }; + const range = (offset, count) => { + if ( + !Number.isSafeInteger(offset) || + !Number.isSafeInteger(count) || + offset < 0 || + count < 0 || + offset + count > bytes.length + ) + fail('文件数据不完整'); + }; + range(0, 8); + const le = bytes[0] === 73 && bytes[1] === 73; + if (!le && !(bytes[0] === 77 && bytes[1] === 77)) fail('文件头无效'); + const u16 = (p) => { + range(p, 2); + return v.getUint16(p, le); + }; + const u32 = (p) => { + range(p, 4); + return v.getUint32(p, le); + }; + if (u16(2) !== 42) fail('暂不支持 BigTIFF 或此文件版本'); + const ifd = u32(4), + count = u16(ifd); + range(ifd + 2, count * 12 + 4); + if (u32(ifd + 2 + count * 12)) fail('暂不支持多页文件,请先导出单页'); + const wanted = new Set([ + 256, 257, 258, 259, 262, 266, 273, 274, 277, 278, 279, 284, 317, 338, 339, + ]); + const tags = new Map(); + for (let i = 0; i < count; i++) { + const p = ifd + 2 + i * 12, + tag = u16(p); + if (!wanted.has(tag)) continue; + if (tags.has(tag)) fail('重复的图像字段'); + const type = u16(p + 2), + n = u32(p + 4), + size = type === 3 ? 2 : type === 4 ? 4 : 0; + if (!size || n > 32e6) fail('图像字段格式暂不支持'); + const offset = n * size <= 4 ? p + 8 : u32(p + 8); + range(offset, n * size); + // Keep a view into the file rather than allocating potentially huge tag arrays. + tags.set(tag, { + n, + at: (index) => (size === 2 ? u16(offset + index * size) : u32(offset + index * size)), + }); + } + const scalar = (tag, fallback) => { + const field = tags.get(tag); + if (!field) return fallback; + if (field.n !== 1) fail('图像字段数量无效'); + return field.at(0); + }; + const width = scalar(256, 0), + height = scalar(257, 0); + if (!width || !height || width * height > 32e6) fail('尺寸无效或超过 3200 万像素'); + if (scalar(266, 1) !== 1) fail('暂不支持反转位序'); + const photo = scalar(262, -1), + samples = scalar(277, 1), + compression = scalar(259, 1); + if (![0, 1, 2].includes(photo)) fail('目前仅支持 RGB 和灰度图'); + const colors = photo === 2 ? 3 : 1; + const extra = tags.get(338), + alpha = extra?.n === 1 ? extra.at(0) : 0; + if (samples !== colors && !(samples === colors + 1 && [1, 2].includes(alpha))) + fail('颜色或透明度通道暂不支持'); + if (samples === colors && extra) fail('多余的透明度字段'); + const bits = tags.get(258), + format = tags.get(339); + if (!bits || bits.n !== samples) fail('仅支持每通道 8-bit 图像'); + for (let c = 0; c < samples; c++) if (bits.at(c) !== 8) fail('仅支持每通道 8-bit 图像'); + if (format && format.n !== samples) fail('像素格式字段数量无效'); + if (format) + for (let c = 0; c < format.n; c++) if (format.at(c) !== 1) fail('暂不支持浮点或有符号像素'); + if (scalar(284, 1) !== 1) fail('暂不支持分平面存储'); + const predictor = scalar(317, 1); + if (![1, 2].includes(predictor)) fail('暂不支持此预测编码'); + if (![1, 5, 32773].includes(compression)) fail('目前仅支持无压缩、LZW 或 PackBits 压缩'); + const rows = scalar(278, height), + orientation = scalar(274, 1); + if (!rows || orientation < 1 || orientation > 8) fail('条带或方向字段无效'); + const strips = Math.ceil(height / rows), + offsets = tags.get(273), + lengths = tags.get(279); + if (!offsets || !lengths || offsets.n !== strips || lengths.n !== strips) fail('条带数量无效'); + const outWidth = orientation >= 5 ? height : width, + outHeight = orientation >= 5 ? width : height; + const data = new Uint8ClampedArray(width * height * 4); + for (let strip = 0; strip < strips; strip++) { + const rowStart = strip * rows, + rowCount = Math.min(rows, height - rowStart); + const expected = rowCount * width * samples, + offset = offsets.at(strip), + length = lengths.at(strip); + range(offset, length); + let pixels = bytes.subarray(offset, offset + length); + if (compression === 5) pixels = unpackLZW(pixels, expected, fail); + else if (compression === 32773) pixels = unpack(pixels, expected, fail); + else if (length < expected) fail('条带像素不足'); + if (predictor === 2) { + if (compression === 1) pixels = pixels.slice(0, expected); + const stride = width * samples; + for (let row = 0; row < rowCount; row++) + for (let p = row * stride + samples; p < (row + 1) * stride; p++) + pixels[p] += pixels[p - samples]; + } + for (let y = 0; y < rowCount; y++) + for (let x = 0; x < width; x++) { + const sy = rowStart + y, + p = (y * width + x) * samples; + let dx = x, + dy = sy; + if (orientation === 2) dx = width - 1 - x; + if (orientation === 3) { + dx = width - 1 - x; + dy = height - 1 - sy; + } + if (orientation === 4) dy = height - 1 - sy; + if (orientation === 5) { + dx = sy; + dy = x; + } + if (orientation === 6) { + dx = height - 1 - sy; + dy = x; + } + if (orientation === 7) { + dx = height - 1 - sy; + dy = width - 1 - x; + } + if (orientation === 8) { + dx = sy; + dy = width - 1 - x; + } + const dest = (dy * outWidth + dx) * 4, + a = samples > colors ? pixels[p + colors] : 255; + for (let c = 0; c < 3; c++) { + let value = pixels[p + (colors === 3 ? c : 0)]; + if (photo === 0) value = 255 - value; + data[dest + c] = alpha === 1 ? (a ? (value * 255) / a : 0) : value; + } + data[dest + 3] = a; + } + } + return { width: outWidth, height: outHeight, data }; +} +function unpack(source, size, fail) { + const out = new Uint8Array(size); + let p = 0, + q = 0; + while (q < size && p < source.length) { + const control = source[p++]; + if (control === 128) continue; + const count = control < 128 ? control + 1 : 257 - control; + if (q + count > size) fail('PackBits 数据越界'); + if (control < 128) { + if (p + count > source.length) fail('PackBits 数据不完整'); + out.set(source.subarray(p, p + count), q); + p += count; + } else { + if (p >= source.length) fail('PackBits 数据不完整'); + out.fill(source[p++], q, q + count); + } + q += count; + } + if (q !== size) fail('PackBits 像素不足'); + return out; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/tiff.js b/plugins/webguhui/minimax-photo/miniapp/client/tiff.js new file mode 100644 index 00000000..6299be34 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/tiff.js @@ -0,0 +1,55 @@ +// TIFF 6.0: little-endian, one uncompressed chunky RGBA strip, straight alpha. +// https://www.itu.int/itudoc/itu-t/com16/tiff-fx/docs/tiff6.pdf +export function writeTIFF({ width, height, data }) { + if ( + !Number.isInteger(width) || + !Number.isInteger(height) || + width < 1 || + height < 1 || + width * height > 32e6 || + !(data instanceof Uint8ClampedArray || data instanceof Uint8Array) || + data.length !== width * height * 4 + ) + throw Error('TIFF 像素数据无效'); + const count = 15; + const bits = 8 + 2 + count * 12 + 4; + const xResolution = bits + 8, + yResolution = xResolution + 8, + pixels = yResolution + 8; + const bytes = new Uint8Array(pixels), + view = new DataView(bytes.buffer); + bytes.set([0x49, 0x49]); + view.setUint16(2, 42, true); + view.setUint32(4, 8, true); + view.setUint16(8, count, true); + let offset = 10; + function field(tag, type, length, value) { + view.setUint16(offset, tag, true); + view.setUint16(offset + 2, type, true); + view.setUint32(offset + 4, length, true); + if (type === 3 && length === 1) view.setUint16(offset + 8, value, true); + else view.setUint32(offset + 8, value, true); + offset += 12; + } + field(256, 4, 1, width); + field(257, 4, 1, height); + field(258, 3, 4, bits); + field(259, 3, 1, 1); // No compression. + field(262, 3, 1, 2); // RGB. + field(273, 4, 1, pixels); + field(274, 3, 1, 1); // Top-left origin. + field(277, 3, 1, 4); + field(278, 4, 1, height); + field(279, 4, 1, data.length); + field(282, 5, 1, xResolution); + field(283, 5, 1, yResolution); + field(284, 3, 1, 1); // Interleaved samples. + field(296, 3, 1, 2); // Inches; metadata only, no resampling. + field(338, 3, 1, 2); // Unassociated alpha, matching Canvas ImageData. + for (let c = 0; c < 4; c++) view.setUint16(bits + c * 2, 8, true); + for (const p of [xResolution, yResolution]) { + view.setUint32(p, 72, true); + view.setUint32(p + 4, 1, true); + } + return new Blob([bytes, data], { type: 'image/tiff' }); +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/tone.js b/plugins/webguhui/minimax-photo/miniapp/client/tone.js new file mode 100644 index 00000000..df476380 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/tone.js @@ -0,0 +1,55 @@ +// Shape-preserving cubic interpolation: a monotone segment cannot overshoot its endpoints. +export function curveLUT(points) { + if (!Array.isArray(points) || points.length < 2 || points.length > 32) + throw Error('曲线需要 2–32 个控制点'); + const p = points.map((point) => { + if ( + !Array.isArray(point) || + point.length !== 2 || + !point.every((v) => Number.isFinite(v) && v >= 0 && v <= 255) + ) + throw Error('曲线控制点须在 0–255 范围内'); + return [...point]; + }); + if (p[0][0] !== 0 || p.at(-1)[0] !== 255 || p.some((v, i) => i && v[0] <= p[i - 1][0])) + throw Error('曲线输入须从 0 到 255 严格递增'); + const widths = p.slice(1).map((v, i) => v[0] - p[i][0]); + const slopes = widths.map((w, i) => (p[i + 1][1] - p[i][1]) / w); + const tangent = [slopes[0]]; + for (let i = 1; i < p.length - 1; i++) { + const a = slopes[i - 1], + b = slopes[i]; + const w1 = 2 * widths[i] + widths[i - 1], + w2 = widths[i] + 2 * widths[i - 1]; + tangent.push(a * b <= 0 ? 0 : (w1 + w2) / (w1 / a + w2 / b)); + } + tangent.push(slopes.at(-1)); + const table = new Uint8ClampedArray(256); + let segment = 0; + for (let x = 0; x < 256; x++) { + while (segment < p.length - 2 && x > p[segment + 1][0]) segment++; + const h = widths[segment], + t = (x - p[segment][0]) / h, + t2 = t * t, + t3 = t2 * t; + table[x] = + (2 * t3 - 3 * t2 + 1) * p[segment][1] + + (t3 - 2 * t2 + t) * h * tangent[segment] + + (-2 * t3 + 3 * t2) * p[segment + 1][1] + + (t3 - t2) * h * tangent[segment + 1]; + } + return table; +} +export function applyCurves(data, curves) { + if (!curves || typeof curves !== 'object') throw Error('缺少曲线参数'); + const identity = [ + [0, 0], + [255, 255], + ], + master = curveLUT(curves.rgb || identity); + const channels = ['red', 'green', 'blue'].map((name) => curveLUT(curves[name] || identity)); + const out = new Uint8ClampedArray(data); + for (let i = 0; i < out.length; i += 4) + for (let c = 0; c < 3; c++) out[i + c] = channels[c][master[data[i + c]]]; + return out; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/client/workbench-ui.js b/plugins/webguhui/minimax-photo/miniapp/client/workbench-ui.js new file mode 100644 index 00000000..1dc1aeeb --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/workbench-ui.js @@ -0,0 +1,38 @@ +var Tw=Object.create;var bc=Object.defineProperty;var Mw=Object.getOwnPropertyDescriptor;var Rw=Object.getOwnPropertyNames;var Ew=Object.getPrototypeOf,Dw=Object.prototype.hasOwnProperty;var wt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),Ru=(e,t)=>{for(var a in t)bc(e,a,{get:t[a],enumerable:!0})},Ow=(e,t,a,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let l of Rw(t))!Dw.call(e,l)&&l!==a&&bc(e,l,{get:()=>t[l],enumerable:!(n=Mw(t,l))||n.enumerable});return e};var Y=(e,t,a)=>(a=e!=null?Tw(Ew(e)):{},Ow(t||!e||!e.__esModule?bc(a,"default",{value:e,enumerable:!0}):a,e));var Fg=wt(ne=>{"use strict";var kc=Symbol.for("react.transitional.element"),zw=Symbol.for("react.portal"),Bw=Symbol.for("react.fragment"),Pw=Symbol.for("react.strict_mode"),Uw=Symbol.for("react.profiler"),qw=Symbol.for("react.consumer"),Hw=Symbol.for("react.context"),Fw=Symbol.for("react.forward_ref"),_w=Symbol.for("react.suspense"),Nw=Symbol.for("react.memo"),zg=Symbol.for("react.lazy"),Vw=Symbol.for("react.activity"),Rg=Symbol.iterator;function Gw(e){return e===null||typeof e!="object"?null:(e=Rg&&e[Rg]||e["@@iterator"],typeof e=="function"?e:null)}var Bg={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},Pg=Object.assign,Ug={};function nr(e,t,a){this.props=e,this.context=t,this.refs=Ug,this.updater=a||Bg}nr.prototype.isReactComponent={};nr.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};nr.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function qg(){}qg.prototype=nr.prototype;function Ic(e,t,a){this.props=e,this.context=t,this.refs=Ug,this.updater=a||Bg}var Ac=Ic.prototype=new qg;Ac.constructor=Ic;Pg(Ac,nr.prototype);Ac.isPureReactComponent=!0;var Eg=Array.isArray;function wc(){}var Ee={H:null,A:null,T:null,S:null},Hg=Object.prototype.hasOwnProperty;function Tc(e,t,a){var n=a.ref;return{$$typeof:kc,type:e,key:t,ref:n!==void 0?n:null,props:a}}function jw(e,t){return Tc(e.type,t,e.props)}function Mc(e){return typeof e=="object"&&e!==null&&e.$$typeof===kc}function Xw(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(a){return t[a]})}var Dg=/\/+/g;function vc(e,t){return typeof e=="object"&&e!==null&&e.key!=null?Xw(""+e.key):t.toString(36)}function Yw(e){switch(e.status){case"fulfilled":return e.value;case"rejected":throw e.reason;default:switch(typeof e.status=="string"?e.then(wc,wc):(e.status="pending",e.then(function(t){e.status==="pending"&&(e.status="fulfilled",e.value=t)},function(t){e.status==="pending"&&(e.status="rejected",e.reason=t)})),e.status){case"fulfilled":return e.value;case"rejected":throw e.reason}}throw e}function ar(e,t,a,n,l){var r=typeof e;(r==="undefined"||r==="boolean")&&(e=null);var o=!1;if(e===null)o=!0;else switch(r){case"bigint":case"string":case"number":o=!0;break;case"object":switch(e.$$typeof){case kc:case zw:o=!0;break;case zg:return o=e._init,ar(o(e._payload),t,a,n,l)}}if(o)return l=l(e),o=n===""?"."+vc(e,0):n,Eg(l)?(a="",o!=null&&(a=o.replace(Dg,"$&/")+"/"),ar(l,t,a,"",function(s){return s})):l!=null&&(Mc(l)&&(l=jw(l,a+(l.key==null||e&&e.key===l.key?"":(""+l.key).replace(Dg,"$&/")+"/")+o)),t.push(l)),1;o=0;var i=n===""?".":n+":";if(Eg(e))for(var u=0;u{"use strict";_g.exports=Fg()});var Wg=wt(Be=>{"use strict";function Oc(e,t){var a=e.length;e.push(t);e:for(;0>>1,l=e[n];if(0>>1;nDu(i,a))uDu(s,i)?(e[n]=s,e[u]=a,n=u):(e[n]=i,e[o]=a,n=o);else if(uDu(s,a))e[n]=s,e[u]=a,n=u;else break e}}return t}function Du(e,t){var a=e.sortIndex-t.sortIndex;return a!==0?a:e.id-t.id}Be.unstable_now=void 0;typeof performance=="object"&&typeof performance.now=="function"?(Ng=performance,Be.unstable_now=function(){return Ng.now()}):(Rc=Date,Vg=Rc.now(),Be.unstable_now=function(){return Rc.now()-Vg});var Ng,Rc,Vg,Va=[],bn=[],Kw=1,na=null,Lt=3,zc=!1,vo=!1,wo=!1,Bc=!1,Xg=typeof setTimeout=="function"?setTimeout:null,Yg=typeof clearTimeout=="function"?clearTimeout:null,Gg=typeof setImmediate<"u"?setImmediate:null;function Ou(e){for(var t=Ta(bn);t!==null;){if(t.callback===null)zu(bn);else if(t.startTime<=e)zu(bn),t.sortIndex=t.expirationTime,Oc(Va,t);else break;t=Ta(bn)}}function Pc(e){if(wo=!1,Ou(e),!vo)if(Ta(Va)!==null)vo=!0,rr||(rr=!0,lr());else{var t=Ta(bn);t!==null&&Uc(Pc,t.startTime-e)}}var rr=!1,ko=-1,Qg=5,Zg=-1;function Kg(){return Bc?!0:!(Be.unstable_now()-Zge&&Kg());){var n=na.callback;if(typeof n=="function"){na.callback=null,Lt=na.priorityLevel;var l=n(na.expirationTime<=e);if(e=Be.unstable_now(),typeof l=="function"){na.callback=l,Ou(e),t=!0;break t}na===Ta(Va)&&zu(Va),Ou(e)}else zu(Va);na=Ta(Va)}if(na!==null)t=!0;else{var r=Ta(bn);r!==null&&Uc(Pc,r.startTime-e),t=!1}}break e}finally{na=null,Lt=a,zc=!1}t=void 0}}finally{t?lr():rr=!1}}}var lr;typeof Gg=="function"?lr=function(){Gg(Ec)}:typeof MessageChannel<"u"?(Dc=new MessageChannel,jg=Dc.port2,Dc.port1.onmessage=Ec,lr=function(){jg.postMessage(null)}):lr=function(){Xg(Ec,0)};var Dc,jg;function Uc(e,t){ko=Xg(function(){e(Be.unstable_now())},t)}Be.unstable_IdlePriority=5;Be.unstable_ImmediatePriority=1;Be.unstable_LowPriority=4;Be.unstable_NormalPriority=3;Be.unstable_Profiling=null;Be.unstable_UserBlockingPriority=2;Be.unstable_cancelCallback=function(e){e.callback=null};Be.unstable_forceFrameRate=function(e){0>e||125n?(e.sortIndex=a,Oc(bn,e),Ta(Va)===null&&e===Ta(bn)&&(wo?(Yg(ko),ko=-1):wo=!0,Uc(Pc,a-n))):(e.sortIndex=l,Oc(Va,e),vo||zc||(vo=!0,rr||(rr=!0,lr()))),e};Be.unstable_shouldYield=Kg;Be.unstable_wrapCallback=function(e){var t=Lt;return function(){var a=Lt;Lt=t;try{return e.apply(this,arguments)}finally{Lt=a}}}});var $g=wt((wO,Jg)=>{"use strict";Jg.exports=Wg()});var tx=wt(It=>{"use strict";var Ww=Ce();function ex(e){var t="https://react.dev/errors/"+e;if(1{"use strict";function ax(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(ax)}catch(e){console.error(e)}}ax(),nx.exports=tx()});var hS=wt(of=>{"use strict";var lt=$g(),My=Ce(),ek=sl();function M(e){var t="https://react.dev/errors/"+e;if(1dr||(e.current=bd[dr],bd[dr]=null,dr--)}function Me(e,t){dr++,bd[dr]=e.current,e.current=t}var Da=Oa(null),Jo=Oa(null),Bn=Oa(null),hs=Oa(null);function gs(e,t){switch(Me(Bn,t),Me(Jo,e),Me(Da,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?dy(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=dy(t),e=tS(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}ct(Da),Me(Da,e)}function Rr(){ct(Da),ct(Jo),ct(Bn)}function vd(e){e.memoizedState!==null&&Me(hs,e);var t=Da.current,a=tS(t,e.type);t!==a&&(Me(Jo,e),Me(Da,a))}function xs(e){Jo.current===e&&(ct(Da),ct(Jo)),hs.current===e&&(ct(hs),si._currentValue=hl)}var qc,ox;function cl(e){if(qc===void 0)try{throw Error()}catch(a){var t=a.stack.trim().match(/\n( *(at )?)/);qc=t&&t[1]||"",ox=-1)":-1l||u[n]!==s[l]){var f=` +`+u[n].replace(" at new "," at ");return e.displayName&&f.includes("")&&(f=f.replace("",e.displayName)),f}while(1<=n&&0<=l);break}}}finally{Hc=!1,Error.prepareStackTrace=a}return(a=e?e.displayName||e.name:"")?cl(a):""}function rk(e,t){switch(e.tag){case 26:case 27:case 5:return cl(e.type);case 16:return cl("Lazy");case 13:return e.child!==t&&t!==null?cl("Suspense Fallback"):cl("Suspense");case 19:return cl("SuspenseList");case 0:case 15:return Fc(e.type,!1);case 11:return Fc(e.type.render,!1);case 1:return Fc(e.type,!0);case 31:return cl("Activity");default:return""}}function ix(e){try{var t="",a=null;do t+=rk(e,a),a=e,e=e.return;while(e);return t}catch(n){return` +Error generating stack: `+n.message+` +`+n.stack}}var wd=Object.prototype.hasOwnProperty,mp=lt.unstable_scheduleCallback,_c=lt.unstable_cancelCallback,ok=lt.unstable_shouldYield,ik=lt.unstable_requestPaint,Kt=lt.unstable_now,uk=lt.unstable_getCurrentPriorityLevel,Py=lt.unstable_ImmediatePriority,Uy=lt.unstable_UserBlockingPriority,ys=lt.unstable_NormalPriority,sk=lt.unstable_LowPriority,qy=lt.unstable_IdlePriority,fk=lt.log,ck=lt.unstable_setDisableYieldValue,pi=null,Wt=null;function Rn(e){if(typeof fk=="function"&&ck(e),Wt&&typeof Wt.setStrictMode=="function")try{Wt.setStrictMode(pi,e)}catch{}}var Jt=Math.clz32?Math.clz32:mk,dk=Math.log,pk=Math.LN2;function mk(e){return e>>>=0,e===0?32:31-(dk(e)/pk|0)|0}var Uu=256,qu=262144,Hu=4194304;function dl(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Gs(e,t,a){var n=e.pendingLanes;if(n===0)return 0;var l=0,r=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var i=n&134217727;return i!==0?(n=i&~r,n!==0?l=dl(n):(o&=i,o!==0?l=dl(o):a||(a=i&~e,a!==0&&(l=dl(a))))):(i=n&~r,i!==0?l=dl(i):o!==0?l=dl(o):a||(a=n&~e,a!==0&&(l=dl(a)))),l===0?0:t!==0&&t!==l&&(t&r)===0&&(r=l&-l,a=t&-t,r>=a||r===32&&(a&4194048)!==0)?t:l}function mi(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function hk(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Hy(){var e=Hu;return Hu<<=1,(Hu&62914560)===0&&(Hu=4194304),e}function Nc(e){for(var t=[],a=0;31>a;a++)t.push(e);return t}function hi(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function gk(e,t,a,n,l,r){var o=e.pendingLanes;e.pendingLanes=a,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=a,e.entangledLanes&=a,e.errorRecoveryDisabledLanes&=a,e.shellSuspendCounter=0;var i=e.entanglements,u=e.expirationTimes,s=e.hiddenUpdates;for(a=o&~a;0"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var bk=/[\n"\\]/g;function ua(e){return e.replace(bk,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function Ad(e,t,a,n,l,r,o,i){e.name="",o!=null&&typeof o!="function"&&typeof o!="symbol"&&typeof o!="boolean"?e.type=o:e.removeAttribute("type"),t!=null?o==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+ra(t)):e.value!==""+ra(t)&&(e.value=""+ra(t)):o!=="submit"&&o!=="reset"||e.removeAttribute("value"),t!=null?Td(e,o,ra(t)):a!=null?Td(e,o,ra(a)):n!=null&&e.removeAttribute("value"),l==null&&r!=null&&(e.defaultChecked=!!r),l!=null&&(e.checked=l&&typeof l!="function"&&typeof l!="symbol"),i!=null&&typeof i!="function"&&typeof i!="symbol"&&typeof i!="boolean"?e.name=""+ra(i):e.removeAttribute("name")}function Qy(e,t,a,n,l,r,o,i){if(r!=null&&typeof r!="function"&&typeof r!="symbol"&&typeof r!="boolean"&&(e.type=r),t!=null||a!=null){if(!(r!=="submit"&&r!=="reset"||t!=null)){Id(e);return}a=a!=null?""+ra(a):"",t=t!=null?""+ra(t):a,i||t===e.value||(e.value=t),e.defaultValue=t}n=n??l,n=typeof n!="function"&&typeof n!="symbol"&&!!n,e.checked=i?e.checked:!!n,e.defaultChecked=!!n,o!=null&&typeof o!="function"&&typeof o!="symbol"&&typeof o!="boolean"&&(e.name=o),Id(e)}function Td(e,t,a){t==="number"&&Ls(e.ownerDocument)===e||e.defaultValue===""+a||(e.defaultValue=""+a)}function wr(e,t,a,n){if(e=e.options,t){t={};for(var l=0;l"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Rd=!1;if(nn)try{or={},Object.defineProperty(or,"passive",{get:function(){Rd=!0}}),window.addEventListener("test",or,or),window.removeEventListener("test",or,or)}catch{Rd=!1}var or,En=null,Sp=null,as=null;function $y(){if(as)return as;var e,t=Sp,a=t.length,n,l="value"in En?En.value:En.textContent,r=l.length;for(e=0;e=Ho),yx=" ",Lx=!1;function tL(e,t){switch(e){case"keyup":return Kk.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function aL(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var hr=!1;function Jk(e,t){switch(e){case"compositionend":return aL(t);case"keypress":return t.which!==32?null:(Lx=!0,yx);case"textInput":return e=t.data,e===yx&&Lx?null:e;default:return null}}function $k(e,t){if(hr)return e==="compositionend"||!bp&&tL(e,t)?(e=$y(),as=Sp=En=null,hr=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:a,offset:t-e};e=n}e:{for(;a;){if(a.nextSibling){a=a.nextSibling;break e}a=a.parentNode}a=void 0}a=vx(a)}}function oL(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?oL(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function iL(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Ls(e.document);t instanceof e.HTMLIFrameElement;){try{var a=typeof t.contentWindow.location.href=="string"}catch{a=!1}if(a)e=t.contentWindow;else break;t=Ls(e.document)}return t}function vp(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var iI=nn&&"documentMode"in document&&11>=document.documentMode,gr=null,Ed=null,_o=null,Dd=!1;function kx(e,t,a){var n=a.window===a?a.document:a.nodeType===9?a:a.ownerDocument;Dd||gr==null||gr!==Ls(n)||(n=gr,"selectionStart"in n&&vp(n)?n={start:n.selectionStart,end:n.selectionEnd}:(n=(n.ownerDocument&&n.ownerDocument.defaultView||window).getSelection(),n={anchorNode:n.anchorNode,anchorOffset:n.anchorOffset,focusNode:n.focusNode,focusOffset:n.focusOffset}),_o&&ti(_o,n)||(_o=n,n=Us(Ed,"onSelect"),0>=o,l-=o,Ma=1<<32-Jt(t)+l|a<I?(D=k,k=null):D=k.sibling;var w=p(m,k,x[I],S);if(w===null){k===null&&(k=D);break}e&&k&&w.alternate===null&&t(m,k),g=r(w,g,I),b===null?A=w:b.sibling=w,b=w,k=D}if(I===x.length)return a(m,k),pe&&Za(m,I),A;if(k===null){for(;II?(D=k,k=null):D=k.sibling;var H=p(m,k,w.value,S);if(H===null){k===null&&(k=D);break}e&&k&&H.alternate===null&&t(m,k),g=r(H,g,I),b===null?A=H:b.sibling=H,b=H,k=D}if(w.done)return a(m,k),pe&&Za(m,I),A;if(k===null){for(;!w.done;I++,w=x.next())w=c(m,w.value,S),w!==null&&(g=r(w,g,I),b===null?A=w:b.sibling=w,b=w);return pe&&Za(m,I),A}for(k=n(k);!w.done;I++,w=x.next())w=d(k,m,I,w.value,S),w!==null&&(e&&w.alternate!==null&&k.delete(w.key===null?I:w.key),g=r(w,g,I),b===null?A=w:b.sibling=w,b=w);return e&&k.forEach(function(Q){return t(m,Q)}),pe&&Za(m,I),A}function v(m,g,x,S){if(typeof x=="object"&&x!==null&&x.type===cr&&x.key===null&&(x=x.props.children),typeof x=="object"&&x!==null){switch(x.$$typeof){case Pu:e:{for(var A=x.key;g!==null;){if(g.key===A){if(A=x.type,A===cr){if(g.tag===7){a(m,g.sibling),S=l(g,x.props.children),S.return=m,m=S;break e}}else if(g.elementType===A||typeof A=="object"&&A!==null&&A.$$typeof===wn&&pl(A)===g.type){a(m,g.sibling),S=l(g,x.props),Mo(S,x),S.return=m,m=S;break e}a(m,g);break}else t(m,g);g=g.sibling}x.type===cr?(S=gl(x.props.children,m.mode,S,x.key),S.return=m,m=S):(S=ls(x.type,x.key,x.props,null,m.mode,S),Mo(S,x),S.return=m,m=S)}return o(m);case zo:e:{for(A=x.key;g!==null;){if(g.key===A)if(g.tag===4&&g.stateNode.containerInfo===x.containerInfo&&g.stateNode.implementation===x.implementation){a(m,g.sibling),S=l(g,x.children||[]),S.return=m,m=S;break e}else{a(m,g);break}else t(m,g);g=g.sibling}S=Kc(x,m.mode,S),S.return=m,m=S}return o(m);case wn:return x=pl(x),v(m,g,x,S)}if(Bo(x))return h(m,g,x,S);if(Ao(x)){if(A=Ao(x),typeof A!="function")throw Error(M(150));return x=A.call(x),y(m,g,x,S)}if(typeof x.then=="function")return v(m,g,ju(x),S);if(x.$$typeof===Wa)return v(m,g,Gu(m,x),S);Xu(m,x)}return typeof x=="string"&&x!==""||typeof x=="number"||typeof x=="bigint"?(x=""+x,g!==null&&g.tag===6?(a(m,g.sibling),S=l(g,x),S.return=m,m=S):(a(m,g),S=Zc(x,m.mode,S),S.return=m,m=S),o(m)):a(m,g)}return function(m,g,x,S){try{li=0;var A=v(m,g,x,S);return Ar=null,A}catch(k){if(k===Gr||k===Ks)throw k;var b=Qt(29,k,null,m.mode);return b.lanes=S,b.return=m,b}finally{}}}var bl=bL(!0),vL=bL(!1),kn=!1;function Dp(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Hd(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Un(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function qn(e,t,a){var n=e.updateQueue;if(n===null)return null;if(n=n.shared,(xe&2)!==0){var l=n.pending;return l===null?t.next=t:(t.next=l.next,l.next=t),n.pending=t,t=Cs(e),mL(e,null,a),t}return Zs(e,n,t,a),Cs(e)}function Vo(e,t,a){if(t=t.updateQueue,t!==null&&(t=t.shared,(a&4194048)!==0)){var n=t.lanes;n&=e.pendingLanes,a|=n,t.lanes=a,_y(e,a)}}function Jc(e,t){var a=e.updateQueue,n=e.alternate;if(n!==null&&(n=n.updateQueue,a===n)){var l=null,r=null;if(a=a.firstBaseUpdate,a!==null){do{var o={lane:a.lane,tag:a.tag,payload:a.payload,callback:null,next:null};r===null?l=r=o:r=r.next=o,a=a.next}while(a!==null);r===null?l=r=t:r=r.next=t}else l=r=t;a={baseState:n.baseState,firstBaseUpdate:l,lastBaseUpdate:r,shared:n.shared,callbacks:n.callbacks},e.updateQueue=a;return}e=a.lastBaseUpdate,e===null?a.firstBaseUpdate=t:e.next=t,a.lastBaseUpdate=t}var Fd=!1;function Go(){if(Fd){var e=Ir;if(e!==null)throw e}}function jo(e,t,a,n){Fd=!1;var l=e.updateQueue;kn=!1;var r=l.firstBaseUpdate,o=l.lastBaseUpdate,i=l.shared.pending;if(i!==null){l.shared.pending=null;var u=i,s=u.next;u.next=null,o===null?r=s:o.next=s,o=u;var f=e.alternate;f!==null&&(f=f.updateQueue,i=f.lastBaseUpdate,i!==o&&(i===null?f.firstBaseUpdate=s:i.next=s,f.lastBaseUpdate=u))}if(r!==null){var c=l.baseState;o=0,f=s=u=null,i=r;do{var p=i.lane&-536870913,d=p!==i.lane;if(d?(ce&p)===p:(n&p)===p){p!==0&&p===Or&&(Fd=!0),f!==null&&(f=f.next={lane:0,tag:i.tag,payload:i.payload,callback:null,next:null});e:{var h=e,y=i;p=t;var v=a;switch(y.tag){case 1:if(h=y.payload,typeof h=="function"){c=h.call(v,c,p);break e}c=h;break e;case 3:h.flags=h.flags&-65537|128;case 0:if(h=y.payload,p=typeof h=="function"?h.call(v,c,p):h,p==null)break e;c=ze({},c,p);break e;case 2:kn=!0}}p=i.callback,p!==null&&(e.flags|=64,d&&(e.flags|=8192),d=l.callbacks,d===null?l.callbacks=[p]:d.push(p))}else d={lane:p,tag:i.tag,payload:i.payload,callback:i.callback,next:null},f===null?(s=f=d,u=c):f=f.next=d,o|=p;if(i=i.next,i===null){if(i=l.shared.pending,i===null)break;d=i,i=d.next,d.next=null,l.lastBaseUpdate=d,l.shared.pending=null}}while(!0);f===null&&(u=c),l.baseState=u,l.firstBaseUpdate=s,l.lastBaseUpdate=f,r===null&&(l.shared.lanes=0),Yn|=o,e.lanes=o,e.memoizedState=c}}function wL(e,t){if(typeof e!="function")throw Error(M(191,e));e.call(t)}function kL(e,t){var a=e.callbacks;if(a!==null)for(e.callbacks=null,e=0;er?r:8;var o=ee.T,i={};ee.T=i,jp(e,!1,t,a);try{var u=l(),s=ee.S;if(s!==null&&s(i,u),u!==null&&typeof u=="object"&&typeof u.then=="function"){var f=gI(u,n);Xo(e,t,f,$t(e))}else Xo(e,t,n,$t(e))}catch(c){Xo(e,t,{then:function(){},status:"rejected",reason:c},$t())}finally{ye.p=r,o!==null&&i.types!==null&&(o.types=i.types),ee.T=o}}function bI(){}function jd(e,t,a,n){if(e.tag!==5)throw Error(M(476));var l=KL(e).queue;ZL(e,l,t,hl,a===null?bI:function(){return WL(e),a(n)})}function KL(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:hl,baseState:hl,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:rn,lastRenderedState:hl},next:null};var a={};return t.next={memoizedState:a,baseState:a,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:rn,lastRenderedState:a},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function WL(e){var t=KL(e);t.next===null&&(t=e.alternate.memoizedState),Xo(e,t.next.queue,{},$t())}function Gp(){return xt(si)}function JL(){return je().memoizedState}function $L(){return je().memoizedState}function vI(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var a=$t();e=Un(a);var n=qn(t,e,a);n!==null&&(Pt(n,t,a),Vo(n,t,a)),t={cache:Mp()},e.payload=t;return}t=t.return}}function wI(e,t,a){var n=$t();a={lane:n,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},ef(e)?t1(t,a):(a=kp(e,t,a,n),a!==null&&(Pt(a,e,n),a1(a,t,n)))}function e1(e,t,a){var n=$t();Xo(e,t,a,n)}function Xo(e,t,a,n){var l={lane:n,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null};if(ef(e))t1(t,l);else{var r=e.alternate;if(e.lanes===0&&(r===null||r.lanes===0)&&(r=t.lastRenderedReducer,r!==null))try{var o=t.lastRenderedState,i=r(o,a);if(l.hasEagerState=!0,l.eagerState=i,ea(i,o))return Zs(e,t,l,0),Ae===null&&Qs(),!1}catch{}finally{}if(a=kp(e,t,l,n),a!==null)return Pt(a,e,n),a1(a,t,n),!0}return!1}function jp(e,t,a,n){if(n={lane:2,revertLane:em(),gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},ef(e)){if(t)throw Error(M(479))}else t=kp(e,a,n,2),t!==null&&Pt(t,e,2)}function ef(e){var t=e.alternate;return e===le||t!==null&&t===le}function t1(e,t){Tr=As=!0;var a=e.pending;a===null?t.next=t:(t.next=a.next,a.next=t),e.pending=t}function a1(e,t,a){if((a&4194048)!==0){var n=t.lanes;n&=e.pendingLanes,a|=n,t.lanes=a,_y(e,a)}}var oi={readContext:xt,use:Js,useCallback:He,useContext:He,useEffect:He,useImperativeHandle:He,useLayoutEffect:He,useInsertionEffect:He,useMemo:He,useReducer:He,useRef:He,useState:He,useDebugValue:He,useDeferredValue:He,useTransition:He,useSyncExternalStore:He,useId:He,useHostTransitionStatus:He,useFormState:He,useActionState:He,useOptimistic:He,useMemoCache:He,useCacheRefresh:He};oi.useEffectEvent=He;var n1={readContext:xt,use:Js,useCallback:function(e,t){return At().memoizedState=[e,t===void 0?null:t],e},useContext:xt,useEffect:Fx,useImperativeHandle:function(e,t,a){a=a!=null?a.concat([e]):null,is(4194308,4,GL.bind(null,t,e),a)},useLayoutEffect:function(e,t){return is(4194308,4,e,t)},useInsertionEffect:function(e,t){is(4,2,e,t)},useMemo:function(e,t){var a=At();t=t===void 0?null:t;var n=e();if(vl){Rn(!0);try{e()}finally{Rn(!1)}}return a.memoizedState=[n,t],n},useReducer:function(e,t,a){var n=At();if(a!==void 0){var l=a(t);if(vl){Rn(!0);try{a(t)}finally{Rn(!1)}}}else l=t;return n.memoizedState=n.baseState=l,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:l},n.queue=e,e=e.dispatch=wI.bind(null,le,e),[n.memoizedState,e]},useRef:function(e){var t=At();return e={current:e},t.memoizedState=e},useState:function(e){e=Vd(e);var t=e.queue,a=e1.bind(null,le,t);return t.dispatch=a,[e.memoizedState,a]},useDebugValue:Np,useDeferredValue:function(e,t){var a=At();return Vp(a,e,t)},useTransition:function(){var e=Vd(!1);return e=ZL.bind(null,le,e.queue,!0,!1),At().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,a){var n=le,l=At();if(pe){if(a===void 0)throw Error(M(407));a=a()}else{if(a=t(),Ae===null)throw Error(M(349));(ce&127)!==0||RL(n,t,a)}l.memoizedState=a;var r={value:a,getSnapshot:t};return l.queue=r,Fx(DL.bind(null,n,r,e),[e]),n.flags|=2048,Br(9,{destroy:void 0},EL.bind(null,n,r,a,t),null),a},useId:function(){var e=At(),t=Ae.identifierPrefix;if(pe){var a=Ra,n=Ma;a=(n&~(1<<32-Jt(n)-1)).toString(32)+a,t="_"+t+"R_"+a,a=Ts++,0<\/script>",r=r.removeChild(r.firstChild);break;case"select":r=typeof n.is=="string"?o.createElement("select",{is:n.is}):o.createElement("select"),n.multiple?r.multiple=!0:n.size&&(r.size=n.size);break;default:r=typeof n.is=="string"?o.createElement(l,{is:n.is}):o.createElement(l)}}r[ht]=t,r[Ut]=n;e:for(o=t.child;o!==null;){if(o.tag===5||o.tag===6)r.appendChild(o.stateNode);else if(o.tag!==4&&o.tag!==27&&o.child!==null){o.child.return=o,o=o.child;continue}if(o===t)break e;for(;o.sibling===null;){if(o.return===null||o.return===t)break e;o=o.return}o.sibling.return=o.return,o=o.sibling}t.stateNode=r;e:switch(yt(r,l,n),l){case"button":case"input":case"select":case"textarea":n=!!n.autoFocus;break e;case"img":n=!0;break e;default:n=!1}n&&ja(t)}}return De(t),od(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,a),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==n&&ja(t);else{if(typeof n!="string"&&t.stateNode===null)throw Error(M(166));if(e=Bn.current,ir(t)){if(e=t.stateNode,a=t.memoizedProps,n=null,l=gt,l!==null)switch(l.tag){case 27:case 5:n=l.memoizedProps}e[ht]=t,e=!!(e.nodeValue===a||n!==null&&n.suppressHydrationWarning===!0||eS(e.nodeValue,a)),e||jn(t,!0)}else e=qs(e).createTextNode(n),e[ht]=t,t.stateNode=e}return De(t),null;case 31:if(a=t.memoizedState,e===null||e.memoizedState!==null){if(n=ir(t),a!==null){if(e===null){if(!n)throw Error(M(318));if(e=t.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(M(557));e[ht]=t}else Sl(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;De(t),e=!1}else a=Wc(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=a),e=!0;if(!e)return t.flags&256?(Yt(t),t):(Yt(t),null);if((t.flags&128)!==0)throw Error(M(558))}return De(t),null;case 13:if(n=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(l=ir(t),n!==null&&n.dehydrated!==null){if(e===null){if(!l)throw Error(M(318));if(l=t.memoizedState,l=l!==null?l.dehydrated:null,!l)throw Error(M(317));l[ht]=t}else Sl(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;De(t),l=!1}else l=Wc(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=l),l=!0;if(!l)return t.flags&256?(Yt(t),t):(Yt(t),null)}return Yt(t),(t.flags&128)!==0?(t.lanes=a,t):(a=n!==null,e=e!==null&&e.memoizedState!==null,a&&(n=t.child,l=null,n.alternate!==null&&n.alternate.memoizedState!==null&&n.alternate.memoizedState.cachePool!==null&&(l=n.alternate.memoizedState.cachePool.pool),r=null,n.memoizedState!==null&&n.memoizedState.cachePool!==null&&(r=n.memoizedState.cachePool.pool),r!==l&&(n.flags|=2048)),a!==e&&a&&(t.child.flags|=8192),Yu(t,t.updateQueue),De(t),null);case 4:return Rr(),e===null&&tm(t.stateNode.containerInfo),De(t),null;case 10:return tn(t.type),De(t),null;case 19:if(ct(Ge),n=t.memoizedState,n===null)return De(t),null;if(l=(t.flags&128)!==0,r=n.rendering,r===null)if(l)Ro(n,!1);else{if(Fe!==0||e!==null&&(e.flags&128)!==0)for(e=t.child;e!==null;){if(r=Is(e),r!==null){for(t.flags|=128,Ro(n,!1),e=r.updateQueue,t.updateQueue=e,Yu(t,e),t.subtreeFlags=0,e=a,a=t.child;a!==null;)hL(a,e),a=a.sibling;return Me(Ge,Ge.current&1|2),pe&&Za(t,n.treeForkCount),t.child}e=e.sibling}n.tail!==null&&Kt()>Ds&&(t.flags|=128,l=!0,Ro(n,!1),t.lanes=4194304)}else{if(!l)if(e=Is(r),e!==null){if(t.flags|=128,l=!0,e=e.updateQueue,t.updateQueue=e,Yu(t,e),Ro(n,!0),n.tail===null&&n.tailMode==="hidden"&&!r.alternate&&!pe)return De(t),null}else 2*Kt()-n.renderingStartTime>Ds&&a!==536870912&&(t.flags|=128,l=!0,Ro(n,!1),t.lanes=4194304);n.isBackwards?(r.sibling=t.child,t.child=r):(e=n.last,e!==null?e.sibling=r:t.child=r,n.last=r)}return n.tail!==null?(e=n.tail,n.rendering=e,n.tail=e.sibling,n.renderingStartTime=Kt(),e.sibling=null,a=Ge.current,Me(Ge,l?a&1|2:a&1),pe&&Za(t,n.treeForkCount),e):(De(t),null);case 22:case 23:return Yt(t),Op(),n=t.memoizedState!==null,e!==null?e.memoizedState!==null!==n&&(t.flags|=8192):n&&(t.flags|=8192),n?(a&536870912)!==0&&(t.flags&128)===0&&(De(t),t.subtreeFlags&6&&(t.flags|=8192)):De(t),a=t.updateQueue,a!==null&&Yu(t,a.retryQueue),a=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(a=e.memoizedState.cachePool.pool),n=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(n=t.memoizedState.cachePool.pool),n!==a&&(t.flags|=2048),e!==null&&ct(xl),null;case 24:return a=null,e!==null&&(a=e.memoizedState.cache),t.memoizedState.cache!==a&&(t.flags|=2048),tn($e),De(t),null;case 25:return null;case 30:return null}throw Error(M(156,t.tag))}function MI(e,t){switch(Tp(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return tn($e),Rr(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return xs(t),null;case 31:if(t.memoizedState!==null){if(Yt(t),t.alternate===null)throw Error(M(340));Sl()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(Yt(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(M(340));Sl()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return ct(Ge),null;case 4:return Rr(),null;case 10:return tn(t.type),null;case 22:case 23:return Yt(t),Op(),e!==null&&ct(xl),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return tn($e),null;case 25:return null;default:return null}}function h1(e,t){switch(Tp(t),t.tag){case 3:tn($e),Rr();break;case 26:case 27:case 5:xs(t);break;case 4:Rr();break;case 31:t.memoizedState!==null&&Yt(t);break;case 13:Yt(t);break;case 19:ct(Ge);break;case 10:tn(t.type);break;case 22:case 23:Yt(t),Op(),e!==null&&ct(xl);break;case 24:tn($e)}}function Si(e,t){try{var a=t.updateQueue,n=a!==null?a.lastEffect:null;if(n!==null){var l=n.next;a=l;do{if((a.tag&e)===e){n=void 0;var r=a.create,o=a.inst;n=r(),o.destroy=n}a=a.next}while(a!==l)}}catch(i){ve(t,t.return,i)}}function Xn(e,t,a){try{var n=t.updateQueue,l=n!==null?n.lastEffect:null;if(l!==null){var r=l.next;n=r;do{if((n.tag&e)===e){var o=n.inst,i=o.destroy;if(i!==void 0){o.destroy=void 0,l=t;var u=a,s=i;try{s()}catch(f){ve(l,u,f)}}}n=n.next}while(n!==r)}}catch(f){ve(t,t.return,f)}}function g1(e){var t=e.updateQueue;if(t!==null){var a=e.stateNode;try{kL(t,a)}catch(n){ve(e,e.return,n)}}}function x1(e,t,a){a.props=wl(e.type,e.memoizedProps),a.state=e.memoizedState;try{a.componentWillUnmount()}catch(n){ve(e,t,n)}}function Yo(e,t){try{var a=e.ref;if(a!==null){switch(e.tag){case 26:case 27:case 5:var n=e.stateNode;break;case 30:n=e.stateNode;break;default:n=e.stateNode}typeof a=="function"?e.refCleanup=a(n):a.current=n}}catch(l){ve(e,t,l)}}function Ea(e,t){var a=e.ref,n=e.refCleanup;if(a!==null)if(typeof n=="function")try{n()}catch(l){ve(e,t,l)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof a=="function")try{a(null)}catch(l){ve(e,t,l)}else a.current=null}function y1(e){var t=e.type,a=e.memoizedProps,n=e.stateNode;try{e:switch(t){case"button":case"input":case"select":case"textarea":a.autoFocus&&n.focus();break e;case"img":a.src?n.src=a.src:a.srcSet&&(n.srcset=a.srcSet)}}catch(l){ve(e,e.return,l)}}function id(e,t,a){try{var n=e.stateNode;ZI(n,e.type,a,t),n[Ut]=t}catch(l){ve(e,e.return,l)}}function L1(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Zn(e.type)||e.tag===4}function ud(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||L1(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&Zn(e.type)||e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Kd(e,t,a){var n=e.tag;if(n===5||n===6)e=e.stateNode,t?(a.nodeType===9?a.body:a.nodeName==="HTML"?a.ownerDocument.body:a).insertBefore(e,t):(t=a.nodeType===9?a.body:a.nodeName==="HTML"?a.ownerDocument.body:a,t.appendChild(e),a=a._reactRootContainer,a!=null||t.onclick!==null||(t.onclick=Ja));else if(n!==4&&(n===27&&Zn(e.type)&&(a=e.stateNode,t=null),e=e.child,e!==null))for(Kd(e,t,a),e=e.sibling;e!==null;)Kd(e,t,a),e=e.sibling}function Es(e,t,a){var n=e.tag;if(n===5||n===6)e=e.stateNode,t?a.insertBefore(e,t):a.appendChild(e);else if(n!==4&&(n===27&&Zn(e.type)&&(a=e.stateNode),e=e.child,e!==null))for(Es(e,t,a),e=e.sibling;e!==null;)Es(e,t,a),e=e.sibling}function S1(e){var t=e.stateNode,a=e.memoizedProps;try{for(var n=e.type,l=t.attributes;l.length;)t.removeAttributeNode(l[0]);yt(t,n,a),t[ht]=e,t[Ut]=a}catch(r){ve(e,e.return,r)}}var Ka=!1,Je=!1,sd=!1,$x=typeof WeakSet=="function"?WeakSet:Set,st=null;function RI(e,t){if(e=e.containerInfo,np=Ns,e=iL(e),vp(e)){if("selectionStart"in e)var a={start:e.selectionStart,end:e.selectionEnd};else e:{a=(a=e.ownerDocument)&&a.defaultView||window;var n=a.getSelection&&a.getSelection();if(n&&n.rangeCount!==0){a=n.anchorNode;var l=n.anchorOffset,r=n.focusNode;n=n.focusOffset;try{a.nodeType,r.nodeType}catch{a=null;break e}var o=0,i=-1,u=-1,s=0,f=0,c=e,p=null;t:for(;;){for(var d;c!==a||l!==0&&c.nodeType!==3||(i=o+l),c!==r||n!==0&&c.nodeType!==3||(u=o+n),c.nodeType===3&&(o+=c.nodeValue.length),(d=c.firstChild)!==null;)p=c,c=d;for(;;){if(c===e)break t;if(p===a&&++s===l&&(i=o),p===r&&++f===n&&(u=o),(d=c.nextSibling)!==null)break;c=p,p=c.parentNode}c=d}a=i===-1||u===-1?null:{start:i,end:u}}else a=null}a=a||{start:0,end:0}}else a=null;for(lp={focusedElem:e,selectionRange:a},Ns=!1,st=t;st!==null;)if(t=st,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,st=e;else for(;st!==null;){switch(t=st,r=t.alternate,e=t.flags,t.tag){case 0:if((e&4)!==0&&(e=t.updateQueue,e=e!==null?e.events:null,e!==null))for(a=0;a title"))),yt(r,n,a),r[ht]=e,ft(r),n=r;break e;case"link":var o=Cy("link","href",l).get(n+(a.href||""));if(o){for(var i=0;iv&&(o=v,v=y,y=o);var m=wx(i,y),g=wx(i,v);if(m&&g&&(d.rangeCount!==1||d.anchorNode!==m.node||d.anchorOffset!==m.offset||d.focusNode!==g.node||d.focusOffset!==g.offset)){var x=c.createRange();x.setStart(m.node,m.offset),d.removeAllRanges(),y>v?(d.addRange(x),d.extend(g.node,g.offset)):(x.setEnd(g.node,g.offset),d.addRange(x))}}}}for(c=[],d=i;d=d.parentNode;)d.nodeType===1&&c.push({element:d,left:d.scrollLeft,top:d.scrollTop});for(typeof i.focus=="function"&&i.focus(),i=0;ia?32:a,ee.T=null,a=$d,$d=null;var r=Fn,o=an;if(nt=0,Ur=Fn=null,an=0,(xe&6)!==0)throw Error(M(331));var i=xe;if(xe|=4,E1(r.current),T1(r,r.current,o,a),xe=i,Ci(0,!1),Wt&&typeof Wt.onPostCommitFiberRoot=="function")try{Wt.onPostCommitFiberRoot(pi,r)}catch{}return!0}finally{ye.p=l,ee.T=n,X1(e,t)}}function ny(e,t,a){t=sa(a,t),t=Yd(e.stateNode,t,2),e=qn(e,t,2),e!==null&&(hi(e,2),za(e))}function ve(e,t,a){if(e.tag===3)ny(e,e,a);else for(;t!==null;){if(t.tag===3){ny(t,e,a);break}else if(t.tag===1){var n=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof n.componentDidCatch=="function"&&(Hn===null||!Hn.has(n))){e=sa(a,e),a=u1(2),n=qn(t,a,2),n!==null&&(s1(a,n,t,e),hi(n,2),za(n));break}}t=t.return}}function cd(e,t,a){var n=e.pingCache;if(n===null){n=e.pingCache=new OI;var l=new Set;n.set(t,l)}else l=n.get(t),l===void 0&&(l=new Set,n.set(t,l));l.has(a)||(Wp=!0,l.add(a),e=qI.bind(null,e,t,a),t.then(e,e))}function qI(e,t,a){var n=e.pingCache;n!==null&&n.delete(t),e.pingedLanes|=e.suspendedLanes&a,e.warmLanes&=~a,Ae===e&&(ce&a)===a&&(Fe===4||Fe===3&&(ce&62914560)===ce&&300>Kt()-tf?(xe&2)===0&&qr(e,0):Jp|=a,Pr===ce&&(Pr=0)),za(e)}function Q1(e,t){t===0&&(t=Hy()),e=Tl(e,t),e!==null&&(hi(e,t),za(e))}function HI(e){var t=e.memoizedState,a=0;t!==null&&(a=t.retryLane),Q1(e,a)}function FI(e,t){var a=0;switch(e.tag){case 31:case 13:var n=e.stateNode,l=e.memoizedState;l!==null&&(a=l.retryLane);break;case 19:n=e.stateNode;break;case 22:n=e.stateNode._retryCache;break;default:throw Error(M(314))}n!==null&&n.delete(t),Q1(e,a)}function _I(e,t){return mp(e,t)}var Bs=null,fr=null,tp=!1,Ps=!1,dd=!1,zn=0;function za(e){e!==fr&&e.next===null&&(fr===null?Bs=fr=e:fr=fr.next=e),Ps=!0,tp||(tp=!0,VI())}function Ci(e,t){if(!dd&&Ps){dd=!0;do for(var a=!1,n=Bs;n!==null;){if(!t)if(e!==0){var l=n.pendingLanes;if(l===0)var r=0;else{var o=n.suspendedLanes,i=n.pingedLanes;r=(1<<31-Jt(42|e)+1)-1,r&=l&~(o&~i),r=r&201326741?r&201326741|1:r?r|2:0}r!==0&&(a=!0,ly(n,r))}else r=ce,r=Gs(n,n===Ae?r:0,n.cancelPendingCommit!==null||n.timeoutHandle!==-1),(r&3)===0||mi(n,r)||(a=!0,ly(n,r));n=n.next}while(a);dd=!1}}function NI(){Z1()}function Z1(){Ps=tp=!1;var e=0;zn!==0&&WI()&&(e=zn);for(var t=Kt(),a=null,n=Bs;n!==null;){var l=n.next,r=K1(n,t);r===0?(n.next=null,a===null?Bs=l:a.next=l,l===null&&(fr=a)):(a=n,(e!==0||(r&3)!==0)&&(Ps=!0)),n=l}nt!==0&&nt!==5||Ci(e,!1),zn!==0&&(zn=0)}function K1(e,t){for(var a=e.suspendedLanes,n=e.pingedLanes,l=e.expirationTimes,r=e.pendingLanes&-62914561;0i)break;var f=u.transferSize,c=u.initiatorType;f&&cy(c)&&(u=u.responseEnd,o+=f*(u"u"?null:document;function rS(e,t,a){var n=Xr;if(n&&typeof t=="string"&&t){var l=ua(t);l='link[rel="'+e+'"][href="'+l+'"]',typeof a=="string"&&(l+='[crossorigin="'+a+'"]'),yy.has(l)||(yy.add(l),e={rel:e,crossOrigin:a,href:t},n.querySelector(l)===null&&(t=n.createElement("link"),yt(t,"link",e),ft(t),n.head.appendChild(t)))}}function o2(e){sn.D(e),rS("dns-prefetch",e,null)}function i2(e,t){sn.C(e,t),rS("preconnect",e,t)}function u2(e,t,a){sn.L(e,t,a);var n=Xr;if(n&&e&&t){var l='link[rel="preload"][as="'+ua(t)+'"]';t==="image"&&a&&a.imageSrcSet?(l+='[imagesrcset="'+ua(a.imageSrcSet)+'"]',typeof a.imageSizes=="string"&&(l+='[imagesizes="'+ua(a.imageSizes)+'"]')):l+='[href="'+ua(e)+'"]';var r=l;switch(t){case"style":r=Hr(e);break;case"script":r=Yr(e)}pa.has(r)||(e=ze({rel:"preload",href:t==="image"&&a&&a.imageSrcSet?void 0:e,as:t},a),pa.set(r,e),n.querySelector(l)!==null||t==="style"&&n.querySelector(bi(r))||t==="script"&&n.querySelector(vi(r))||(t=n.createElement("link"),yt(t,"link",e),ft(t),n.head.appendChild(t)))}}function s2(e,t){sn.m(e,t);var a=Xr;if(a&&e){var n=t&&typeof t.as=="string"?t.as:"script",l='link[rel="modulepreload"][as="'+ua(n)+'"][href="'+ua(e)+'"]',r=l;switch(n){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":r=Yr(e)}if(!pa.has(r)&&(e=ze({rel:"modulepreload",href:e},t),pa.set(r,e),a.querySelector(l)===null)){switch(n){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(a.querySelector(vi(r)))return}n=a.createElement("link"),yt(n,"link",e),ft(n),a.head.appendChild(n)}}}function f2(e,t,a){sn.S(e,t,a);var n=Xr;if(n&&e){var l=vr(n).hoistableStyles,r=Hr(e);t=t||"default";var o=l.get(r);if(!o){var i={loading:0,preload:null};if(o=n.querySelector(bi(r)))i.loading=5;else{e=ze({rel:"stylesheet",href:e,"data-precedence":t},a),(a=pa.get(r))&&am(e,a);var u=o=n.createElement("link");ft(u),yt(u,"link",e),u._p=new Promise(function(s,f){u.onload=s,u.onerror=f}),u.addEventListener("load",function(){i.loading|=1}),u.addEventListener("error",function(){i.loading|=2}),i.loading|=4,cs(o,t,n)}o={type:"stylesheet",instance:o,count:1,state:i},l.set(r,o)}}}function c2(e,t){sn.X(e,t);var a=Xr;if(a&&e){var n=vr(a).hoistableScripts,l=Yr(e),r=n.get(l);r||(r=a.querySelector(vi(l)),r||(e=ze({src:e,async:!0},t),(t=pa.get(l))&&nm(e,t),r=a.createElement("script"),ft(r),yt(r,"link",e),a.head.appendChild(r)),r={type:"script",instance:r,count:1,state:null},n.set(l,r))}}function d2(e,t){sn.M(e,t);var a=Xr;if(a&&e){var n=vr(a).hoistableScripts,l=Yr(e),r=n.get(l);r||(r=a.querySelector(vi(l)),r||(e=ze({src:e,async:!0,type:"module"},t),(t=pa.get(l))&&nm(e,t),r=a.createElement("script"),ft(r),yt(r,"link",e),a.head.appendChild(r)),r={type:"script",instance:r,count:1,state:null},n.set(l,r))}}function Ly(e,t,a,n){var l=(l=Bn.current)?Hs(l):null;if(!l)throw Error(M(446));switch(e){case"meta":case"title":return null;case"style":return typeof a.precedence=="string"&&typeof a.href=="string"?(t=Hr(a.href),a=vr(l).hoistableStyles,n=a.get(t),n||(n={type:"style",instance:null,count:0,state:null},a.set(t,n)),n):{type:"void",instance:null,count:0,state:null};case"link":if(a.rel==="stylesheet"&&typeof a.href=="string"&&typeof a.precedence=="string"){e=Hr(a.href);var r=vr(l).hoistableStyles,o=r.get(e);if(o||(l=l.ownerDocument||l,o={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},r.set(e,o),(r=l.querySelector(bi(e)))&&!r._p&&(o.instance=r,o.state.loading=5),pa.has(e)||(a={rel:"preload",as:"style",href:a.href,crossOrigin:a.crossOrigin,integrity:a.integrity,media:a.media,hrefLang:a.hrefLang,referrerPolicy:a.referrerPolicy},pa.set(e,a),r||p2(l,e,a,o.state))),t&&n===null)throw Error(M(528,""));return o}if(t&&n!==null)throw Error(M(529,""));return null;case"script":return t=a.async,a=a.src,typeof a=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=Yr(a),a=vr(l).hoistableScripts,n=a.get(t),n||(n={type:"script",instance:null,count:0,state:null},a.set(t,n)),n):{type:"void",instance:null,count:0,state:null};default:throw Error(M(444,e))}}function Hr(e){return'href="'+ua(e)+'"'}function bi(e){return'link[rel="stylesheet"]['+e+"]"}function oS(e){return ze({},e,{"data-precedence":e.precedence,precedence:null})}function p2(e,t,a,n){e.querySelector('link[rel="preload"][as="style"]['+t+"]")?n.loading=1:(t=e.createElement("link"),n.preload=t,t.addEventListener("load",function(){return n.loading|=1}),t.addEventListener("error",function(){return n.loading|=2}),yt(t,"link",a),ft(t),e.head.appendChild(t))}function Yr(e){return'[src="'+ua(e)+'"]'}function vi(e){return"script[async]"+e}function Sy(e,t,a){if(t.count++,t.instance===null)switch(t.type){case"style":var n=e.querySelector('style[data-href~="'+ua(a.href)+'"]');if(n)return t.instance=n,ft(n),n;var l=ze({},a,{"data-href":a.href,"data-precedence":a.precedence,href:null,precedence:null});return n=(e.ownerDocument||e).createElement("style"),ft(n),yt(n,"style",l),cs(n,a.precedence,e),t.instance=n;case"stylesheet":l=Hr(a.href);var r=e.querySelector(bi(l));if(r)return t.state.loading|=4,t.instance=r,ft(r),r;n=oS(a),(l=pa.get(l))&&am(n,l),r=(e.ownerDocument||e).createElement("link"),ft(r);var o=r;return o._p=new Promise(function(i,u){o.onload=i,o.onerror=u}),yt(r,"link",n),t.state.loading|=4,cs(r,a.precedence,e),t.instance=r;case"script":return r=Yr(a.src),(l=e.querySelector(vi(r)))?(t.instance=l,ft(l),l):(n=a,(l=pa.get(r))&&(n=ze({},a),nm(n,l)),e=e.ownerDocument||e,l=e.createElement("script"),ft(l),yt(l,"link",n),e.head.appendChild(l),t.instance=l);case"void":return null;default:throw Error(M(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(n=t.instance,t.state.loading|=4,cs(n,a.precedence,e));return t.instance}function cs(e,t,a){for(var n=a.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),l=n.length?n[n.length-1]:null,r=l,o=0;o title"):null)}function m2(e,t,a){if(a===1||t.itemProp!=null)return!1;switch(e){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;switch(t.rel){case"stylesheet":return e=t.disabled,typeof t.precedence=="string"&&e==null;default:return!0}case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function iS(e){return!(e.type==="stylesheet"&&(e.state.loading&3)===0)}function h2(e,t,a,n){if(a.type==="stylesheet"&&(typeof n.media!="string"||matchMedia(n.media).matches!==!1)&&(a.state.loading&4)===0){if(a.instance===null){var l=Hr(n.href),r=t.querySelector(bi(l));if(r){t=r._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(e.count++,e=Fs.bind(e),t.then(e,e)),a.state.loading|=4,a.instance=r,ft(r);return}r=t.ownerDocument||t,n=oS(n),(l=pa.get(l))&&am(n,l),r=r.createElement("link"),ft(r);var o=r;o._p=new Promise(function(i,u){o.onload=i,o.onerror=u}),yt(r,"link",n),a.instance=r}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(a,t),(t=a.state.preload)&&(a.state.loading&3)===0&&(e.count++,a=Fs.bind(e),t.addEventListener("load",a),t.addEventListener("error",a))}}var gd=0;function g2(e,t){return e.stylesheets&&e.count===0&&ps(e,e.stylesheets),0gd?50:800)+t);return e.unsuspend=a,function(){e.unsuspend=null,clearTimeout(n),clearTimeout(l)}}:null}function Fs(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)ps(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var _s=null;function ps(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,_s=new Map,t.forEach(x2,e),_s=null,Fs.call(e))}function x2(e,t){if(!(t.state.loading&4)){var a=_s.get(e);if(a)var n=a.get(null);else{a=new Map,_s.set(e,a);for(var l=e.querySelectorAll("link[data-precedence],style[data-precedence]"),r=0;r{"use strict";function gS(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(gS)}catch(e){console.error(e)}}gS(),xS.exports=hS()});var FS=wt(df=>{"use strict";var nA=Symbol.for("react.transitional.element"),lA=Symbol.for("react.fragment");function HS(e,t,a){var n=null;if(a!==void 0&&(n=""+a),t.key!==void 0&&(n=""+t.key),"key"in t){a={};for(var l in t)l!=="key"&&(a[l]=t[l])}else a=t;return t=a.ref,{$$typeof:nA,type:e,key:n,ref:t!==void 0?t:null,props:a}}df.Fragment=lA;df.jsx=HS;df.jsxs=HS});var Xe=wt((qO,_S)=>{"use strict";_S.exports=FS()});var GC=wt((n5,VC)=>{"use strict";var HC=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//g,XT=/\n/g,YT=/^\s*/,QT=/^(\*?[-#/*\\\w]+(\[[0-9a-z_-]+\])?)\s*/,ZT=/^:\s*/,KT=/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};])+)/,WT=/^[;\s]*/,JT=/^\s+|\s+$/g,$T=` +`,FC="/",_C="*",Nl="",eM="comment",tM="declaration";function aM(e,t){if(typeof e!="string")throw new TypeError("First argument must be a string");if(!e)return[];t=t||{};var a=1,n=1;function l(h){var y=h.match(XT);y&&(a+=y.length);var v=h.lastIndexOf($T);n=~v?h.length-v:n+h.length}function r(){var h={line:a,column:n};return function(y){return y.position=new o(h),s(),y}}function o(h){this.start=h,this.end={line:a,column:n},this.source=t.source}o.prototype.content=e;function i(h){var y=new Error(t.source+":"+a+":"+n+": "+h);if(y.reason=h,y.filename=t.source,y.line=a,y.column=n,y.source=e,!t.silent)throw y}function u(h){var y=h.exec(e);if(y){var v=y[0];return l(v),e=e.slice(v.length),y}}function s(){u(YT)}function f(h){var y;for(h=h||[];y=c();)y!==!1&&h.push(y);return h}function c(){var h=r();if(!(FC!=e.charAt(0)||_C!=e.charAt(1))){for(var y=2;Nl!=e.charAt(y)&&(_C!=e.charAt(y)||FC!=e.charAt(y+1));)++y;if(y+=2,Nl===e.charAt(y-1))return i("End of comment missing");var v=e.slice(2,y-2);return n+=2,l(v),e=e.slice(y),n+=2,h({type:eM,comment:v})}}function p(){var h=r(),y=u(QT);if(y){if(c(),!u(ZT))return i("property missing ':'");var v=u(KT),m=h({type:tM,property:NC(y[0].replace(HC,Nl)),value:v?NC(v[0].replace(HC,Nl)):Nl});return u(WT),m}}function d(){var h=[];f(h);for(var y;y=p();)y!==!1&&(h.push(y),f(h));return h}return s(),d()}function NC(e){return e?e.replace(JT,Nl):Nl}VC.exports=aM});var jC=wt(gu=>{"use strict";var nM=gu&&gu.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(gu,"__esModule",{value:!0});gu.default=rM;var lM=nM(GC());function rM(e,t){let a=null;if(!e||typeof e!="string")return a;let n=(0,lM.default)(e),l=typeof t=="function";return n.forEach(r=>{if(r.type!=="declaration")return;let{property:o,value:i}=r;l?t(o,i,r):i&&(a=a||{},a[o]=i)}),a}});var YC=wt(_f=>{"use strict";Object.defineProperty(_f,"__esModule",{value:!0});_f.camelCase=void 0;var oM=/^--[a-zA-Z0-9_-]+$/,iM=/-([a-z])/g,uM=/^[^-]+$/,sM=/^-(webkit|moz|ms|o|khtml)-/,fM=/^-(ms)-/,cM=function(e){return!e||uM.test(e)||oM.test(e)},dM=function(e,t){return t.toUpperCase()},XC=function(e,t){return"".concat(t,"-")},pM=function(e,t){return t===void 0&&(t={}),cM(e)?e:(e=e.toLowerCase(),t.reactCompat?e=e.replace(fM,XC):e=e.replace(sM,XC),e.replace(iM,dM))};_f.camelCase=pM});var ZC=wt((eh,QC)=>{"use strict";var mM=eh&&eh.__importDefault||function(e){return e&&e.__esModule?e:{default:e}},hM=mM(jC()),gM=YC();function $m(e,t){var a={};return!e||typeof e!="string"||(0,hM.default)(e,function(n,l){n&&l&&(a[(0,gM.camelCase)(n,t)]=l)}),a}$m.default=$m;QC.exports=$m});var Sv=wt((HF,Lv)=>{"use strict";var cc=Object.prototype.hasOwnProperty,yv=Object.prototype.toString,dv=Object.defineProperty,pv=Object.getOwnPropertyDescriptor,mv=function(t){return typeof Array.isArray=="function"?Array.isArray(t):yv.call(t)==="[object Array]"},hv=function(t){if(!t||yv.call(t)!=="[object Object]")return!1;var a=cc.call(t,"constructor"),n=t.constructor&&t.constructor.prototype&&cc.call(t.constructor.prototype,"isPrototypeOf");if(t.constructor&&!a&&!n)return!1;var l;for(l in t);return typeof l>"u"||cc.call(t,l)},gv=function(t,a){dv&&a.name==="__proto__"?dv(t,a.name,{enumerable:!0,configurable:!0,value:a.newValue,writable:!0}):t[a.name]=a.newValue},xv=function(t,a){if(a==="__proto__")if(cc.call(t,a)){if(pv)return pv(t,a).value}else return;return t[a]};Lv.exports=function e(){var t,a,n,l,r,o,i=arguments[0],u=1,s=arguments.length,f=!1;for(typeof i=="boolean"&&(f=i,i=arguments[1]||{},u=2),(i==null||typeof i!="object"&&typeof i!="function")&&(i={});utypeof e=="boolean"?`${e}`:e===0?"0":e,SS=uf,CS=(e,t)=>a=>{var n;if(t?.variants==null)return SS(e,a?.class,a?.className);let{variants:l,defaultVariants:r}=t,o=Object.keys(l).map(s=>{let f=a?.[s],c=r?.[s];if(f===null)return null;let p=LS(f)||LS(c);return l[s][p]}),i=a&&Object.entries(a).reduce((s,f)=>{let[c,p]=f;return p===void 0||(s[c]=p),s},{}),u=t==null||(n=t.compoundVariants)===null||n===void 0?void 0:n.reduce((s,f)=>{let{class:c,className:p,...d}=f;return Object.entries(d).every(h=>{let[y,v]=h;return Array.isArray(v)?v.includes({...r,...i}[y]):{...r,...i}[y]===v})?[...s,c,p]:s},[]);return SS(e,o,u,a?.class,a?.className)};var k2=e=>{let t=A2(e),{conflictingClassGroups:a,conflictingClassGroupModifiers:n}=e;return{getClassGroupId:o=>{let i=o.split("-");return i[0]===""&&i.length!==1&&i.shift(),IS(i,t)||I2(o)},getConflictingClassGroupIds:(o,i)=>{let u=a[o]||[];return i&&n[o]?[...u,...n[o]]:u}}},IS=(e,t)=>{if(e.length===0)return t.classGroupId;let a=e[0],n=t.nextPart.get(a),l=n?IS(e.slice(1),n):void 0;if(l)return l;if(t.validators.length===0)return;let r=e.join("-");return t.validators.find(({validator:o})=>o(r))?.classGroupId},bS=/^\[(.+)\]$/,I2=e=>{if(bS.test(e)){let t=bS.exec(e)[1],a=t?.substring(0,t.indexOf(":"));if(a)return"arbitrary.."+a}},A2=e=>{let{theme:t,classGroups:a}=e,n={nextPart:new Map,validators:[]};for(let l in a)cm(a[l],n,l,t);return n},cm=(e,t,a,n)=>{e.forEach(l=>{if(typeof l=="string"){let r=l===""?t:vS(t,l);r.classGroupId=a;return}if(typeof l=="function"){if(T2(l)){cm(l(n),t,a,n);return}t.validators.push({validator:l,classGroupId:a});return}Object.entries(l).forEach(([r,o])=>{cm(o,vS(t,r),a,n)})})},vS=(e,t)=>{let a=e;return t.split("-").forEach(n=>{a.nextPart.has(n)||a.nextPart.set(n,{nextPart:new Map,validators:[]}),a=a.nextPart.get(n)}),a},T2=e=>e.isThemeGetter,M2=e=>{if(e<1)return{get:()=>{},set:()=>{}};let t=0,a=new Map,n=new Map,l=(r,o)=>{a.set(r,o),t++,t>e&&(t=0,n=a,a=new Map)};return{get(r){let o=a.get(r);if(o!==void 0)return o;if((o=n.get(r))!==void 0)return l(r,o),o},set(r,o){a.has(r)?a.set(r,o):l(r,o)}}};var R2=e=>{let{prefix:t,experimentalParseClassName:a}=e,n=l=>{let r=[],o=0,i=0,u=0,s;for(let h=0;hu?s-u:void 0;return{modifiers:r,hasImportantModifier:p,baseClassName:c,maybePostfixModifierPosition:d}};if(t){let l=t+":",r=n;n=o=>o.startsWith(l)?r(o.substring(l.length)):{isExternal:!0,modifiers:[],hasImportantModifier:!1,baseClassName:o,maybePostfixModifierPosition:void 0}}if(a){let l=n;n=r=>a({className:r,parseClassName:l})}return n},E2=e=>e.endsWith("!")?e.substring(0,e.length-1):e.startsWith("!")?e.substring(1):e,D2=e=>{let t=Object.fromEntries(e.orderSensitiveModifiers.map(n=>[n,!0]));return n=>{if(n.length<=1)return n;let l=[],r=[];return n.forEach(o=>{o[0]==="["||t[o]?(l.push(...r.sort(),o),r=[]):r.push(o)}),l.push(...r.sort()),l}},O2=e=>({cache:M2(e.cacheSize),parseClassName:R2(e),sortModifiers:D2(e),...k2(e)}),z2=/\s+/,B2=(e,t)=>{let{parseClassName:a,getClassGroupId:n,getConflictingClassGroupIds:l,sortModifiers:r}=t,o=[],i=e.trim().split(z2),u="";for(let s=i.length-1;s>=0;s-=1){let f=i[s],{isExternal:c,modifiers:p,hasImportantModifier:d,baseClassName:h,maybePostfixModifierPosition:y}=a(f);if(c){u=f+(u.length>0?" "+u:u);continue}let v=!!y,m=n(v?h.substring(0,y):h);if(!m){if(!v){u=f+(u.length>0?" "+u:u);continue}if(m=n(h),!m){u=f+(u.length>0?" "+u:u);continue}v=!1}let g=r(p).join(":"),x=d?g+"!":g,S=x+m;if(o.includes(S))continue;o.push(S);let A=l(m,v);for(let b=0;b0?" "+u:u)}return u};function P2(){let e=0,t,a,n="";for(;e{if(typeof e=="string")return e;let t,a="";for(let n=0;nc(f),e());return a=O2(s),n=a.cache.get,l=a.cache.set,r=i,i(u)}function i(u){let s=n(u);if(s)return s;let f=B2(u,a);return l(u,f),f}return function(){return r(P2.apply(null,arguments))}}var rt=e=>{let t=a=>a[e]||[];return t.isThemeGetter=!0,t},TS=/^\[(?:(\w[\w-]*):)?(.+)\]$/i,MS=/^\((?:(\w[\w-]*):)?(.+)\)$/i,q2=/^\d+\/\d+$/,H2=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,F2=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,_2=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,N2=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,V2=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,Qr=e=>q2.test(e),ie=e=>!!e&&!Number.isNaN(Number(e)),Kn=e=>!!e&&Number.isInteger(Number(e)),sm=e=>e.endsWith("%")&&ie(e.slice(0,-1)),fn=e=>H2.test(e),G2=()=>!0,j2=e=>F2.test(e)&&!_2.test(e),RS=()=>!1,X2=e=>N2.test(e),Y2=e=>V2.test(e),Q2=e=>!V(e)&&!G(e),Z2=e=>Zr(e,OS,RS),V=e=>TS.test(e),Rl=e=>Zr(e,zS,j2),fm=e=>Zr(e,eA,ie),wS=e=>Zr(e,ES,RS),K2=e=>Zr(e,DS,Y2),sf=e=>Zr(e,BS,X2),G=e=>MS.test(e),wi=e=>Kr(e,zS),W2=e=>Kr(e,tA),kS=e=>Kr(e,ES),J2=e=>Kr(e,OS),$2=e=>Kr(e,DS),ff=e=>Kr(e,BS,!0),Zr=(e,t,a)=>{let n=TS.exec(e);return n?n[1]?t(n[1]):a(n[2]):!1},Kr=(e,t,a=!1)=>{let n=MS.exec(e);return n?n[1]?t(n[1]):a:!1},ES=e=>e==="position"||e==="percentage",DS=e=>e==="image"||e==="url",OS=e=>e==="length"||e==="size"||e==="bg-size",zS=e=>e==="length",eA=e=>e==="number",tA=e=>e==="family-name",BS=e=>e==="shadow";var aA=()=>{let e=rt("color"),t=rt("font"),a=rt("text"),n=rt("font-weight"),l=rt("tracking"),r=rt("leading"),o=rt("breakpoint"),i=rt("container"),u=rt("spacing"),s=rt("radius"),f=rt("shadow"),c=rt("inset-shadow"),p=rt("text-shadow"),d=rt("drop-shadow"),h=rt("blur"),y=rt("perspective"),v=rt("aspect"),m=rt("ease"),g=rt("animate"),x=()=>["auto","avoid","all","avoid-page","page","left","right","column"],S=()=>["center","top","bottom","left","right","top-left","left-top","top-right","right-top","bottom-right","right-bottom","bottom-left","left-bottom"],A=()=>[...S(),G,V],b=()=>["auto","hidden","clip","visible","scroll"],k=()=>["auto","contain","none"],I=()=>[G,V,u],D=()=>[Qr,"full","auto",...I()],w=()=>[Kn,"none","subgrid",G,V],H=()=>["auto",{span:["full",Kn,G,V]},Kn,G,V],Q=()=>[Kn,"auto",G,V],P=()=>["auto","min","max","fr",G,V],F=()=>["start","end","center","between","around","evenly","stretch","baseline","center-safe","end-safe"],N=()=>["start","end","center","stretch","center-safe","end-safe"],j=()=>["auto",...I()],J=()=>[Qr,"auto","full","dvw","dvh","lvw","lvh","svw","svh","min","max","fit",...I()],E=()=>[e,G,V],q=()=>[...S(),kS,wS,{position:[G,V]}],L=()=>["no-repeat",{repeat:["","x","y","space","round"]}],Se=()=>["auto","cover","contain",J2,Z2,{size:[G,V]}],ut=()=>[sm,wi,Rl],C=()=>["","none","full",s,G,V],de=()=>["",ie,wi,Rl],Qe=()=>["solid","dashed","dotted","double"],aa=()=>["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"],me=()=>[ie,sm,kS,wS],Te=()=>["","none",h,G,V],bt=()=>["none",ie,G,V],Ze=()=>["none",ie,G,V],vt=()=>[ie,G,V],R=()=>[Qr,"full",...I()];return{cacheSize:500,theme:{animate:["spin","ping","pulse","bounce"],aspect:["video"],blur:[fn],breakpoint:[fn],color:[G2],container:[fn],"drop-shadow":[fn],ease:["in","out","in-out"],font:[Q2],"font-weight":["thin","extralight","light","normal","medium","semibold","bold","extrabold","black"],"inset-shadow":[fn],leading:["none","tight","snug","normal","relaxed","loose"],perspective:["dramatic","near","normal","midrange","distant","none"],radius:[fn],shadow:[fn],spacing:["px",ie],text:[fn],"text-shadow":[fn],tracking:["tighter","tight","normal","wide","wider","widest"]},classGroups:{aspect:[{aspect:["auto","square",Qr,V,G,v]}],container:["container"],columns:[{columns:[ie,V,G,i]}],"break-after":[{"break-after":x()}],"break-before":[{"break-before":x()}],"break-inside":[{"break-inside":["auto","avoid","avoid-page","avoid-column"]}],"box-decoration":[{"box-decoration":["slice","clone"]}],box:[{box:["border","content"]}],display:["block","inline-block","inline","flex","inline-flex","table","inline-table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row-group","table-row","flow-root","grid","inline-grid","contents","list-item","hidden"],sr:["sr-only","not-sr-only"],float:[{float:["right","left","none","start","end"]}],clear:[{clear:["left","right","both","none","start","end"]}],isolation:["isolate","isolation-auto"],"object-fit":[{object:["contain","cover","fill","none","scale-down"]}],"object-position":[{object:A()}],overflow:[{overflow:b()}],"overflow-x":[{"overflow-x":b()}],"overflow-y":[{"overflow-y":b()}],overscroll:[{overscroll:k()}],"overscroll-x":[{"overscroll-x":k()}],"overscroll-y":[{"overscroll-y":k()}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:D()}],"inset-x":[{"inset-x":D()}],"inset-y":[{"inset-y":D()}],start:[{start:D()}],end:[{end:D()}],top:[{top:D()}],right:[{right:D()}],bottom:[{bottom:D()}],left:[{left:D()}],visibility:["visible","invisible","collapse"],z:[{z:[Kn,"auto",G,V]}],basis:[{basis:[Qr,"full","auto",i,...I()]}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["nowrap","wrap","wrap-reverse"]}],flex:[{flex:[ie,Qr,"auto","initial","none",V]}],grow:[{grow:["",ie,G,V]}],shrink:[{shrink:["",ie,G,V]}],order:[{order:[Kn,"first","last","none",G,V]}],"grid-cols":[{"grid-cols":w()}],"col-start-end":[{col:H()}],"col-start":[{"col-start":Q()}],"col-end":[{"col-end":Q()}],"grid-rows":[{"grid-rows":w()}],"row-start-end":[{row:H()}],"row-start":[{"row-start":Q()}],"row-end":[{"row-end":Q()}],"grid-flow":[{"grid-flow":["row","col","dense","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":P()}],"auto-rows":[{"auto-rows":P()}],gap:[{gap:I()}],"gap-x":[{"gap-x":I()}],"gap-y":[{"gap-y":I()}],"justify-content":[{justify:[...F(),"normal"]}],"justify-items":[{"justify-items":[...N(),"normal"]}],"justify-self":[{"justify-self":["auto",...N()]}],"align-content":[{content:["normal",...F()]}],"align-items":[{items:[...N(),{baseline:["","last"]}]}],"align-self":[{self:["auto",...N(),{baseline:["","last"]}]}],"place-content":[{"place-content":F()}],"place-items":[{"place-items":[...N(),"baseline"]}],"place-self":[{"place-self":["auto",...N()]}],p:[{p:I()}],px:[{px:I()}],py:[{py:I()}],ps:[{ps:I()}],pe:[{pe:I()}],pt:[{pt:I()}],pr:[{pr:I()}],pb:[{pb:I()}],pl:[{pl:I()}],m:[{m:j()}],mx:[{mx:j()}],my:[{my:j()}],ms:[{ms:j()}],me:[{me:j()}],mt:[{mt:j()}],mr:[{mr:j()}],mb:[{mb:j()}],ml:[{ml:j()}],"space-x":[{"space-x":I()}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":I()}],"space-y-reverse":["space-y-reverse"],size:[{size:J()}],w:[{w:[i,"screen",...J()]}],"min-w":[{"min-w":[i,"screen","none",...J()]}],"max-w":[{"max-w":[i,"screen","none","prose",{screen:[o]},...J()]}],h:[{h:["screen","lh",...J()]}],"min-h":[{"min-h":["screen","lh","none",...J()]}],"max-h":[{"max-h":["screen","lh",...J()]}],"font-size":[{text:["base",a,wi,Rl]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:[n,G,fm]}],"font-stretch":[{"font-stretch":["ultra-condensed","extra-condensed","condensed","semi-condensed","normal","semi-expanded","expanded","extra-expanded","ultra-expanded",sm,V]}],"font-family":[{font:[W2,V,t]}],"fvn-normal":["normal-nums"],"fvn-ordinal":["ordinal"],"fvn-slashed-zero":["slashed-zero"],"fvn-figure":["lining-nums","oldstyle-nums"],"fvn-spacing":["proportional-nums","tabular-nums"],"fvn-fraction":["diagonal-fractions","stacked-fractions"],tracking:[{tracking:[l,G,V]}],"line-clamp":[{"line-clamp":[ie,"none",G,fm]}],leading:[{leading:[r,...I()]}],"list-image":[{"list-image":["none",G,V]}],"list-style-position":[{list:["inside","outside"]}],"list-style-type":[{list:["disc","decimal","none",G,V]}],"text-alignment":[{text:["left","center","right","justify","start","end"]}],"placeholder-color":[{placeholder:E()}],"text-color":[{text:E()}],"text-decoration":["underline","overline","line-through","no-underline"],"text-decoration-style":[{decoration:[...Qe(),"wavy"]}],"text-decoration-thickness":[{decoration:[ie,"from-font","auto",G,Rl]}],"text-decoration-color":[{decoration:E()}],"underline-offset":[{"underline-offset":[ie,"auto",G,V]}],"text-transform":["uppercase","lowercase","capitalize","normal-case"],"text-overflow":["truncate","text-ellipsis","text-clip"],"text-wrap":[{text:["wrap","nowrap","balance","pretty"]}],indent:[{indent:I()}],"vertical-align":[{align:["baseline","top","middle","bottom","text-top","text-bottom","sub","super",G,V]}],whitespace:[{whitespace:["normal","nowrap","pre","pre-line","pre-wrap","break-spaces"]}],break:[{break:["normal","words","all","keep"]}],wrap:[{wrap:["break-word","anywhere","normal"]}],hyphens:[{hyphens:["none","manual","auto"]}],content:[{content:["none",G,V]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:q()}],"bg-repeat":[{bg:L()}],"bg-size":[{bg:Se()}],"bg-image":[{bg:["none",{linear:[{to:["t","tr","r","br","b","bl","l","tl"]},Kn,G,V],radial:["",G,V],conic:[Kn,G,V]},$2,K2]}],"bg-color":[{bg:E()}],"gradient-from-pos":[{from:ut()}],"gradient-via-pos":[{via:ut()}],"gradient-to-pos":[{to:ut()}],"gradient-from":[{from:E()}],"gradient-via":[{via:E()}],"gradient-to":[{to:E()}],rounded:[{rounded:C()}],"rounded-s":[{"rounded-s":C()}],"rounded-e":[{"rounded-e":C()}],"rounded-t":[{"rounded-t":C()}],"rounded-r":[{"rounded-r":C()}],"rounded-b":[{"rounded-b":C()}],"rounded-l":[{"rounded-l":C()}],"rounded-ss":[{"rounded-ss":C()}],"rounded-se":[{"rounded-se":C()}],"rounded-ee":[{"rounded-ee":C()}],"rounded-es":[{"rounded-es":C()}],"rounded-tl":[{"rounded-tl":C()}],"rounded-tr":[{"rounded-tr":C()}],"rounded-br":[{"rounded-br":C()}],"rounded-bl":[{"rounded-bl":C()}],"border-w":[{border:de()}],"border-w-x":[{"border-x":de()}],"border-w-y":[{"border-y":de()}],"border-w-s":[{"border-s":de()}],"border-w-e":[{"border-e":de()}],"border-w-t":[{"border-t":de()}],"border-w-r":[{"border-r":de()}],"border-w-b":[{"border-b":de()}],"border-w-l":[{"border-l":de()}],"divide-x":[{"divide-x":de()}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":de()}],"divide-y-reverse":["divide-y-reverse"],"border-style":[{border:[...Qe(),"hidden","none"]}],"divide-style":[{divide:[...Qe(),"hidden","none"]}],"border-color":[{border:E()}],"border-color-x":[{"border-x":E()}],"border-color-y":[{"border-y":E()}],"border-color-s":[{"border-s":E()}],"border-color-e":[{"border-e":E()}],"border-color-t":[{"border-t":E()}],"border-color-r":[{"border-r":E()}],"border-color-b":[{"border-b":E()}],"border-color-l":[{"border-l":E()}],"divide-color":[{divide:E()}],"outline-style":[{outline:[...Qe(),"none","hidden"]}],"outline-offset":[{"outline-offset":[ie,G,V]}],"outline-w":[{outline:["",ie,wi,Rl]}],"outline-color":[{outline:E()}],shadow:[{shadow:["","none",f,ff,sf]}],"shadow-color":[{shadow:E()}],"inset-shadow":[{"inset-shadow":["none",c,ff,sf]}],"inset-shadow-color":[{"inset-shadow":E()}],"ring-w":[{ring:de()}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:E()}],"ring-offset-w":[{"ring-offset":[ie,Rl]}],"ring-offset-color":[{"ring-offset":E()}],"inset-ring-w":[{"inset-ring":de()}],"inset-ring-color":[{"inset-ring":E()}],"text-shadow":[{"text-shadow":["none",p,ff,sf]}],"text-shadow-color":[{"text-shadow":E()}],opacity:[{opacity:[ie,G,V]}],"mix-blend":[{"mix-blend":[...aa(),"plus-darker","plus-lighter"]}],"bg-blend":[{"bg-blend":aa()}],"mask-clip":[{"mask-clip":["border","padding","content","fill","stroke","view"]},"mask-no-clip"],"mask-composite":[{mask:["add","subtract","intersect","exclude"]}],"mask-image-linear-pos":[{"mask-linear":[ie]}],"mask-image-linear-from-pos":[{"mask-linear-from":me()}],"mask-image-linear-to-pos":[{"mask-linear-to":me()}],"mask-image-linear-from-color":[{"mask-linear-from":E()}],"mask-image-linear-to-color":[{"mask-linear-to":E()}],"mask-image-t-from-pos":[{"mask-t-from":me()}],"mask-image-t-to-pos":[{"mask-t-to":me()}],"mask-image-t-from-color":[{"mask-t-from":E()}],"mask-image-t-to-color":[{"mask-t-to":E()}],"mask-image-r-from-pos":[{"mask-r-from":me()}],"mask-image-r-to-pos":[{"mask-r-to":me()}],"mask-image-r-from-color":[{"mask-r-from":E()}],"mask-image-r-to-color":[{"mask-r-to":E()}],"mask-image-b-from-pos":[{"mask-b-from":me()}],"mask-image-b-to-pos":[{"mask-b-to":me()}],"mask-image-b-from-color":[{"mask-b-from":E()}],"mask-image-b-to-color":[{"mask-b-to":E()}],"mask-image-l-from-pos":[{"mask-l-from":me()}],"mask-image-l-to-pos":[{"mask-l-to":me()}],"mask-image-l-from-color":[{"mask-l-from":E()}],"mask-image-l-to-color":[{"mask-l-to":E()}],"mask-image-x-from-pos":[{"mask-x-from":me()}],"mask-image-x-to-pos":[{"mask-x-to":me()}],"mask-image-x-from-color":[{"mask-x-from":E()}],"mask-image-x-to-color":[{"mask-x-to":E()}],"mask-image-y-from-pos":[{"mask-y-from":me()}],"mask-image-y-to-pos":[{"mask-y-to":me()}],"mask-image-y-from-color":[{"mask-y-from":E()}],"mask-image-y-to-color":[{"mask-y-to":E()}],"mask-image-radial":[{"mask-radial":[G,V]}],"mask-image-radial-from-pos":[{"mask-radial-from":me()}],"mask-image-radial-to-pos":[{"mask-radial-to":me()}],"mask-image-radial-from-color":[{"mask-radial-from":E()}],"mask-image-radial-to-color":[{"mask-radial-to":E()}],"mask-image-radial-shape":[{"mask-radial":["circle","ellipse"]}],"mask-image-radial-size":[{"mask-radial":[{closest:["side","corner"],farthest:["side","corner"]}]}],"mask-image-radial-pos":[{"mask-radial-at":S()}],"mask-image-conic-pos":[{"mask-conic":[ie]}],"mask-image-conic-from-pos":[{"mask-conic-from":me()}],"mask-image-conic-to-pos":[{"mask-conic-to":me()}],"mask-image-conic-from-color":[{"mask-conic-from":E()}],"mask-image-conic-to-color":[{"mask-conic-to":E()}],"mask-mode":[{mask:["alpha","luminance","match"]}],"mask-origin":[{"mask-origin":["border","padding","content","fill","stroke","view"]}],"mask-position":[{mask:q()}],"mask-repeat":[{mask:L()}],"mask-size":[{mask:Se()}],"mask-type":[{"mask-type":["alpha","luminance"]}],"mask-image":[{mask:["none",G,V]}],filter:[{filter:["","none",G,V]}],blur:[{blur:Te()}],brightness:[{brightness:[ie,G,V]}],contrast:[{contrast:[ie,G,V]}],"drop-shadow":[{"drop-shadow":["","none",d,ff,sf]}],"drop-shadow-color":[{"drop-shadow":E()}],grayscale:[{grayscale:["",ie,G,V]}],"hue-rotate":[{"hue-rotate":[ie,G,V]}],invert:[{invert:["",ie,G,V]}],saturate:[{saturate:[ie,G,V]}],sepia:[{sepia:["",ie,G,V]}],"backdrop-filter":[{"backdrop-filter":["","none",G,V]}],"backdrop-blur":[{"backdrop-blur":Te()}],"backdrop-brightness":[{"backdrop-brightness":[ie,G,V]}],"backdrop-contrast":[{"backdrop-contrast":[ie,G,V]}],"backdrop-grayscale":[{"backdrop-grayscale":["",ie,G,V]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[ie,G,V]}],"backdrop-invert":[{"backdrop-invert":["",ie,G,V]}],"backdrop-opacity":[{"backdrop-opacity":[ie,G,V]}],"backdrop-saturate":[{"backdrop-saturate":[ie,G,V]}],"backdrop-sepia":[{"backdrop-sepia":["",ie,G,V]}],"border-collapse":[{border:["collapse","separate"]}],"border-spacing":[{"border-spacing":I()}],"border-spacing-x":[{"border-spacing-x":I()}],"border-spacing-y":[{"border-spacing-y":I()}],"table-layout":[{table:["auto","fixed"]}],caption:[{caption:["top","bottom"]}],transition:[{transition:["","all","colors","opacity","shadow","transform","none",G,V]}],"transition-behavior":[{transition:["normal","discrete"]}],duration:[{duration:[ie,"initial",G,V]}],ease:[{ease:["linear","initial",m,G,V]}],delay:[{delay:[ie,G,V]}],animate:[{animate:["none",g,G,V]}],backface:[{backface:["hidden","visible"]}],perspective:[{perspective:[y,G,V]}],"perspective-origin":[{"perspective-origin":A()}],rotate:[{rotate:bt()}],"rotate-x":[{"rotate-x":bt()}],"rotate-y":[{"rotate-y":bt()}],"rotate-z":[{"rotate-z":bt()}],scale:[{scale:Ze()}],"scale-x":[{"scale-x":Ze()}],"scale-y":[{"scale-y":Ze()}],"scale-z":[{"scale-z":Ze()}],"scale-3d":["scale-3d"],skew:[{skew:vt()}],"skew-x":[{"skew-x":vt()}],"skew-y":[{"skew-y":vt()}],transform:[{transform:[G,V,"","none","gpu","cpu"]}],"transform-origin":[{origin:A()}],"transform-style":[{transform:["3d","flat"]}],translate:[{translate:R()}],"translate-x":[{"translate-x":R()}],"translate-y":[{"translate-y":R()}],"translate-z":[{"translate-z":R()}],"translate-none":["translate-none"],accent:[{accent:E()}],appearance:[{appearance:["none","auto"]}],"caret-color":[{caret:E()}],"color-scheme":[{scheme:["normal","dark","light","light-dark","only-dark","only-light"]}],cursor:[{cursor:["auto","default","pointer","wait","text","move","help","not-allowed","none","context-menu","progress","cell","crosshair","vertical-text","alias","copy","no-drop","grab","grabbing","all-scroll","col-resize","row-resize","n-resize","e-resize","s-resize","w-resize","ne-resize","nw-resize","se-resize","sw-resize","ew-resize","ns-resize","nesw-resize","nwse-resize","zoom-in","zoom-out",G,V]}],"field-sizing":[{"field-sizing":["fixed","content"]}],"pointer-events":[{"pointer-events":["auto","none"]}],resize:[{resize:["none","","y","x"]}],"scroll-behavior":[{scroll:["auto","smooth"]}],"scroll-m":[{"scroll-m":I()}],"scroll-mx":[{"scroll-mx":I()}],"scroll-my":[{"scroll-my":I()}],"scroll-ms":[{"scroll-ms":I()}],"scroll-me":[{"scroll-me":I()}],"scroll-mt":[{"scroll-mt":I()}],"scroll-mr":[{"scroll-mr":I()}],"scroll-mb":[{"scroll-mb":I()}],"scroll-ml":[{"scroll-ml":I()}],"scroll-p":[{"scroll-p":I()}],"scroll-px":[{"scroll-px":I()}],"scroll-py":[{"scroll-py":I()}],"scroll-ps":[{"scroll-ps":I()}],"scroll-pe":[{"scroll-pe":I()}],"scroll-pt":[{"scroll-pt":I()}],"scroll-pr":[{"scroll-pr":I()}],"scroll-pb":[{"scroll-pb":I()}],"scroll-pl":[{"scroll-pl":I()}],"snap-align":[{snap:["start","end","center","align-none"]}],"snap-stop":[{snap:["normal","always"]}],"snap-type":[{snap:["none","x","y","both"]}],"snap-strictness":[{snap:["mandatory","proximity"]}],touch:[{touch:["auto","none","manipulation"]}],"touch-x":[{"touch-pan":["x","left","right"]}],"touch-y":[{"touch-pan":["y","up","down"]}],"touch-pz":["touch-pinch-zoom"],select:[{select:["none","text","all","auto"]}],"will-change":[{"will-change":["auto","scroll","contents","transform",G,V]}],fill:[{fill:["none",...E()]}],"stroke-w":[{stroke:[ie,wi,Rl,fm]}],stroke:[{stroke:["none",...E()]}],"forced-color-adjust":[{"forced-color-adjust":["auto","none"]}]},conflictingClassGroups:{overflow:["overflow-x","overflow-y"],overscroll:["overscroll-x","overscroll-y"],inset:["inset-x","inset-y","start","end","top","right","bottom","left"],"inset-x":["right","left"],"inset-y":["top","bottom"],flex:["basis","grow","shrink"],gap:["gap-x","gap-y"],p:["px","py","ps","pe","pt","pr","pb","pl"],px:["pr","pl"],py:["pt","pb"],m:["mx","my","ms","me","mt","mr","mb","ml"],mx:["mr","ml"],my:["mt","mb"],size:["w","h"],"font-size":["leading"],"fvn-normal":["fvn-ordinal","fvn-slashed-zero","fvn-figure","fvn-spacing","fvn-fraction"],"fvn-ordinal":["fvn-normal"],"fvn-slashed-zero":["fvn-normal"],"fvn-figure":["fvn-normal"],"fvn-spacing":["fvn-normal"],"fvn-fraction":["fvn-normal"],"line-clamp":["display","overflow"],rounded:["rounded-s","rounded-e","rounded-t","rounded-r","rounded-b","rounded-l","rounded-ss","rounded-se","rounded-ee","rounded-es","rounded-tl","rounded-tr","rounded-br","rounded-bl"],"rounded-s":["rounded-ss","rounded-es"],"rounded-e":["rounded-se","rounded-ee"],"rounded-t":["rounded-tl","rounded-tr"],"rounded-r":["rounded-tr","rounded-br"],"rounded-b":["rounded-br","rounded-bl"],"rounded-l":["rounded-tl","rounded-bl"],"border-spacing":["border-spacing-x","border-spacing-y"],"border-w":["border-w-x","border-w-y","border-w-s","border-w-e","border-w-t","border-w-r","border-w-b","border-w-l"],"border-w-x":["border-w-r","border-w-l"],"border-w-y":["border-w-t","border-w-b"],"border-color":["border-color-x","border-color-y","border-color-s","border-color-e","border-color-t","border-color-r","border-color-b","border-color-l"],"border-color-x":["border-color-r","border-color-l"],"border-color-y":["border-color-t","border-color-b"],translate:["translate-x","translate-y","translate-none"],"translate-none":["translate","translate-x","translate-y","translate-z"],"scroll-m":["scroll-mx","scroll-my","scroll-ms","scroll-me","scroll-mt","scroll-mr","scroll-mb","scroll-ml"],"scroll-mx":["scroll-mr","scroll-ml"],"scroll-my":["scroll-mt","scroll-mb"],"scroll-p":["scroll-px","scroll-py","scroll-ps","scroll-pe","scroll-pt","scroll-pr","scroll-pb","scroll-pl"],"scroll-px":["scroll-pr","scroll-pl"],"scroll-py":["scroll-pt","scroll-pb"],touch:["touch-x","touch-y","touch-pz"],"touch-x":["touch"],"touch-y":["touch"],"touch-pz":["touch"]},conflictingClassGroupModifiers:{"font-size":["leading"]},orderSensitiveModifiers:["*","**","after","backdrop","before","details-content","file","first-letter","first-line","marker","placeholder","selection"]}};var PS=U2(aA);var cf=(...e)=>PS(uf(...e));var YS=Y(Ce(),1);var VS=Y(Ce(),1),GS=Y(sl(),1);var hf={};Ru(hf,{Root:()=>rA,Slot:()=>rA,Slottable:()=>iA,createSlot:()=>pf,createSlottable:()=>mf});var ot=Y(Ce(),1);var qS=Y(Ce(),1);function US(e,t){if(typeof e=="function")return e(t);e!=null&&(e.current=t)}function dm(...e){return t=>{let a=!1,n=e.map(l=>{let r=US(l,t);return!a&&typeof r=="function"&&(a=!0),r});if(a)return()=>{for(let l=0;l{let{children:r,...o}=n,i=ot.Children.toArray(r),u=i.find(uA);if(u){let s=u.props.children,f=i.map(c=>c===u?ot.Children.count(s)>1?ot.Children.only(null):ot.isValidElement(s)?s.props.children:null:c);return(0,Wr.jsx)(t,{...o,ref:l,children:ot.isValidElement(s)?ot.cloneElement(s,void 0,f):null})}return(0,Wr.jsx)(t,{...o,ref:l,children:r})});return a.displayName=`${e}.Slot`,a}var rA=pf("Slot");function oA(e){let t=ot.forwardRef((a,n)=>{let{children:l,...r}=a;if(ot.isValidElement(l)){let o=fA(l),i=sA(r,l.props);return l.type!==ot.Fragment&&(i.ref=n?dm(n,o):o),ot.cloneElement(l,i)}return ot.Children.count(l)>1?ot.Children.only(null):null});return t.displayName=`${e}.SlotClone`,t}var NS=Symbol("radix.slottable");function mf(e){let t=({children:a})=>(0,Wr.jsx)(Wr.Fragment,{children:a});return t.displayName=`${e}.Slottable`,t.__radixId=NS,t}var iA=mf("Slottable");function uA(e){return ot.isValidElement(e)&&typeof e.type=="function"&&"__radixId"in e.type&&e.type.__radixId===NS}function sA(e,t){let a={...t};for(let n in t){let l=e[n],r=t[n];/^on[A-Z]/.test(n)?l&&r?a[n]=(...i)=>{let u=r(...i);return l(...i),u}:l&&(a[n]=l):n==="style"?a[n]={...l,...r}:n==="className"&&(a[n]=[l,r].filter(Boolean).join(" "))}return{...e,...a}}function fA(e){let t=Object.getOwnPropertyDescriptor(e.props,"ref")?.get,a=t&&"isReactWarning"in t&&t.isReactWarning;return a?e.ref:(t=Object.getOwnPropertyDescriptor(e,"ref")?.get,a=t&&"isReactWarning"in t&&t.isReactWarning,a?e.props.ref:e.props.ref||e.ref)}var jS=Y(Xe(),1),cA=["a","button","div","form","h2","h3","img","input","label","li","nav","ol","p","select","span","svg","ul"],Ht=cA.reduce((e,t)=>{let a=pf(`Primitive.${t}`),n=VS.forwardRef((l,r)=>{let{asChild:o,...i}=l,u=o?a:t;return typeof window<"u"&&(window[Symbol.for("radix-ui")]=!0),(0,jS.jsx)(u,{...i,ref:r})});return n.displayName=`Primitive.${t}`,{...e,[t]:n}},{});function XS(e,t){e&&GS.flushSync(()=>e.dispatchEvent(t))}var QS=Y(Xe(),1),dA=Object.freeze({position:"absolute",border:0,width:1,height:1,padding:0,margin:-1,overflow:"hidden",clip:"rect(0, 0, 0, 0)",whiteSpace:"nowrap",wordWrap:"normal"}),pA="VisuallyHidden",ZS=YS.forwardRef((e,t)=>(0,QS.jsx)(Ht.span,{...e,ref:t,style:{...dA,...e.style}}));ZS.displayName=pA;var KS=ZS;var cn=Y(Ce(),1),WS=Y(Xe(),1);function gf(e,t=[]){let a=[];function n(r,o){let i=cn.createContext(o),u=a.length;a=[...a,o];let s=c=>{let{scope:p,children:d,...h}=c,y=p?.[e]?.[u]||i,v=cn.useMemo(()=>h,Object.values(h));return(0,WS.jsx)(y.Provider,{value:v,children:d})};s.displayName=r+"Provider";function f(c,p){let d=p?.[e]?.[u]||i,h=cn.useContext(d);if(h)return h;if(o!==void 0)return o;throw new Error(`\`${c}\` must be used within \`${r}\``)}return[s,f]}let l=()=>{let r=a.map(o=>cn.createContext(o));return function(i){let u=i?.[e]||r;return cn.useMemo(()=>({[`__scope${e}`]:{...i,[e]:u}}),[i,u])}};return l.scopeName=e,[n,hA(l,...t)]}function hA(...e){let t=e[0];if(e.length===1)return t;let a=()=>{let n=e.map(l=>({useScope:l(),scopeName:l.scopeName}));return function(r){let o=n.reduce((i,{useScope:u,scopeName:s})=>{let c=u(r)[`__scope${s}`];return{...i,...c}},{});return cn.useMemo(()=>({[`__scope${t.scopeName}`]:o}),[o])}};return a.scopeName=t.scopeName,a}var GO=!!(typeof window<"u"&&window.document&&window.document.createElement);function Ca(e,t,{checkForDefaultPrevented:a=!0}={}){return function(l){if(e?.(l),a===!1||!l.defaultPrevented)return t?.(l)}}var ma=Y(Ce(),1);var JS=Y(Ce(),1),Ft=globalThis?.document?JS.useLayoutEffect:()=>{};var xf=Y(Ce(),1);var gA=ma[" useInsertionEffect ".trim().toString()]||Ft;function $S({prop:e,defaultProp:t,onChange:a=()=>{},caller:n}){let[l,r,o]=xA({defaultProp:t,onChange:a}),i=e!==void 0,u=i?e:l;{let f=ma.useRef(e!==void 0);ma.useEffect(()=>{let c=f.current;c!==i&&console.warn(`${n} is changing from ${c?"controlled":"uncontrolled"} to ${i?"controlled":"uncontrolled"}. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.`),f.current=i},[i,n])}let s=ma.useCallback(f=>{if(i){let c=yA(f)?f(e):f;c!==e&&o.current?.(c)}else r(f)},[i,e,r,o]);return[u,s]}function xA({defaultProp:e,onChange:t}){let[a,n]=ma.useState(e),l=ma.useRef(a),r=ma.useRef(t);return gA(()=>{r.current=t},[t]),ma.useEffect(()=>{l.current!==a&&(r.current?.(a),l.current=a)},[a,l]),[a,n,r]}function yA(e){return typeof e=="function"}var QO=Symbol("RADIX:SYNC_STATE");var _t=Y(Ce(),1);var e0=Y(Ce(),1);function LA(e,t){return e0.useReducer((a,n)=>t[a][n]??a,e)}var Lf=e=>{let{present:t,children:a}=e,n=SA(t),l=typeof a=="function"?a({present:n.isPresent}):_t.Children.only(a),r=Sa(n.ref,CA(l));return typeof a=="function"||n.isPresent?_t.cloneElement(l,{ref:r}):null};Lf.displayName="Presence";function SA(e){let[t,a]=_t.useState(),n=_t.useRef(null),l=_t.useRef(e),r=_t.useRef("none"),o=e?"mounted":"unmounted",[i,u]=LA(o,{mounted:{UNMOUNT:"unmounted",ANIMATION_OUT:"unmountSuspended"},unmountSuspended:{MOUNT:"mounted",ANIMATION_END:"unmounted"},unmounted:{MOUNT:"mounted"}});return _t.useEffect(()=>{let s=yf(n.current);r.current=i==="mounted"?s:"none"},[i]),Ft(()=>{let s=n.current,f=l.current;if(f!==e){let p=r.current,d=yf(s);e?u("MOUNT"):d==="none"||s?.display==="none"?u("UNMOUNT"):u(f&&p!==d?"ANIMATION_OUT":"UNMOUNT"),l.current=e}},[e,u]),Ft(()=>{if(t){let s,f=t.ownerDocument.defaultView??window,c=d=>{let y=yf(n.current).includes(CSS.escape(d.animationName));if(d.target===t&&y&&(u("ANIMATION_END"),!l.current)){let v=t.style.animationFillMode;t.style.animationFillMode="forwards",s=f.setTimeout(()=>{t.style.animationFillMode==="forwards"&&(t.style.animationFillMode=v)})}},p=d=>{d.target===t&&(r.current=yf(n.current))};return t.addEventListener("animationstart",p),t.addEventListener("animationcancel",c),t.addEventListener("animationend",c),()=>{f.clearTimeout(s),t.removeEventListener("animationstart",p),t.removeEventListener("animationcancel",c),t.removeEventListener("animationend",c)}}else u("ANIMATION_END")},[t,u]),{isPresent:["mounted","unmountSuspended"].includes(i),ref:_t.useCallback(s=>{n.current=s?getComputedStyle(s):null,a(s)},[])}}function yf(e){return e?.animationName||"none"}function CA(e){let t=Object.getOwnPropertyDescriptor(e.props,"ref")?.get,a=t&&"isReactWarning"in t&&t.isReactWarning;return a?e.ref:(t=Object.getOwnPropertyDescriptor(e,"ref")?.get,a=t&&"isReactWarning"in t&&t.isReactWarning,a?e.props.ref:e.props.ref||e.ref)}var pm=Y(Ce(),1);var bA=pm[" useId ".trim().toString()]||(()=>{}),vA=0;function t0(e){let[t,a]=pm.useState(bA());return Ft(()=>{e||a(n=>n??String(vA++))},[e]),e||(t?`radix-${t}`:"")}var qe=Y(Ce(),1);var Jr=Y(Ce(),1);function El(e){let t=Jr.useRef(e);return Jr.useEffect(()=>{t.current=e}),Jr.useMemo(()=>(...a)=>t.current?.(...a),[])}var a0=Y(Ce(),1);function n0(e,t=globalThis?.document){let a=El(e);a0.useEffect(()=>{let n=l=>{l.key==="Escape"&&a(l)};return t.addEventListener("keydown",n,{capture:!0}),()=>t.removeEventListener("keydown",n,{capture:!0})},[a,t])}var hm=Y(Xe(),1),wA="DismissableLayer",mm="dismissableLayer.update",kA="dismissableLayer.pointerDownOutside",IA="dismissableLayer.focusOutside",l0,o0=qe.createContext({layers:new Set,layersWithOutsidePointerEventsDisabled:new Set,branches:new Set}),gm=qe.forwardRef((e,t)=>{let{disableOutsidePointerEvents:a=!1,onEscapeKeyDown:n,onPointerDownOutside:l,onFocusOutside:r,onInteractOutside:o,onDismiss:i,...u}=e,s=qe.useContext(o0),[f,c]=qe.useState(null),p=f?.ownerDocument??globalThis?.document,[,d]=qe.useState({}),h=Sa(t,k=>c(k)),y=Array.from(s.layers),[v]=[...s.layersWithOutsidePointerEventsDisabled].slice(-1),m=y.indexOf(v),g=f?y.indexOf(f):-1,x=s.layersWithOutsidePointerEventsDisabled.size>0,S=g>=m,A=MA(k=>{let I=k.target,D=[...s.branches].some(w=>w.contains(I));!S||D||(l?.(k),o?.(k),k.defaultPrevented||i?.())},p),b=RA(k=>{let I=k.target;[...s.branches].some(w=>w.contains(I))||(r?.(k),o?.(k),k.defaultPrevented||i?.())},p);return n0(k=>{g===s.layers.size-1&&(n?.(k),!k.defaultPrevented&&i&&(k.preventDefault(),i()))},p),qe.useEffect(()=>{if(f)return a&&(s.layersWithOutsidePointerEventsDisabled.size===0&&(l0=p.body.style.pointerEvents,p.body.style.pointerEvents="none"),s.layersWithOutsidePointerEventsDisabled.add(f)),s.layers.add(f),r0(),()=>{a&&s.layersWithOutsidePointerEventsDisabled.size===1&&(p.body.style.pointerEvents=l0)}},[f,p,a,s]),qe.useEffect(()=>()=>{f&&(s.layers.delete(f),s.layersWithOutsidePointerEventsDisabled.delete(f),r0())},[f,s]),qe.useEffect(()=>{let k=()=>d({});return document.addEventListener(mm,k),()=>document.removeEventListener(mm,k)},[]),(0,hm.jsx)(Ht.div,{...u,ref:h,style:{pointerEvents:x?S?"auto":"none":void 0,...e.style},onFocusCapture:Ca(e.onFocusCapture,b.onFocusCapture),onBlurCapture:Ca(e.onBlurCapture,b.onBlurCapture),onPointerDownCapture:Ca(e.onPointerDownCapture,A.onPointerDownCapture)})});gm.displayName=wA;var AA="DismissableLayerBranch",TA=qe.forwardRef((e,t)=>{let a=qe.useContext(o0),n=qe.useRef(null),l=Sa(t,n);return qe.useEffect(()=>{let r=n.current;if(r)return a.branches.add(r),()=>{a.branches.delete(r)}},[a.branches]),(0,hm.jsx)(Ht.div,{...e,ref:l})});TA.displayName=AA;function MA(e,t=globalThis?.document){let a=El(e),n=qe.useRef(!1),l=qe.useRef(()=>{});return qe.useEffect(()=>{let r=i=>{if(i.target&&!n.current){let s=function(){i0(kA,a,f,{discrete:!0})};var u=s;let f={originalEvent:i};i.pointerType==="touch"?(t.removeEventListener("click",l.current),l.current=s,t.addEventListener("click",l.current,{once:!0})):s()}else t.removeEventListener("click",l.current);n.current=!1},o=window.setTimeout(()=>{t.addEventListener("pointerdown",r)},0);return()=>{window.clearTimeout(o),t.removeEventListener("pointerdown",r),t.removeEventListener("click",l.current)}},[t,a]),{onPointerDownCapture:()=>n.current=!0}}function RA(e,t=globalThis?.document){let a=El(e),n=qe.useRef(!1);return qe.useEffect(()=>{let l=r=>{r.target&&!n.current&&i0(IA,a,{originalEvent:r},{discrete:!1})};return t.addEventListener("focusin",l),()=>t.removeEventListener("focusin",l)},[t,a]),{onFocusCapture:()=>n.current=!0,onBlurCapture:()=>n.current=!1}}function r0(){let e=new CustomEvent(mm);document.dispatchEvent(e)}function i0(e,t,a,{discrete:n}){let l=a.originalEvent.target,r=new CustomEvent(e,{bubbles:!1,cancelable:!0,detail:a});t&&l.addEventListener(e,t,{once:!0}),n?XS(l,r):l.dispatchEvent(r)}var Sf=Y(Ce(),1),u0=Y(sl(),1);var s0=Y(Xe(),1),EA="Portal",xm=Sf.forwardRef((e,t)=>{let{container:a,...n}=e,[l,r]=Sf.useState(!1);Ft(()=>r(!0),[]);let o=a||l&&globalThis?.document?.body;return o?u0.default.createPortal((0,s0.jsx)(Ht.div,{...n,ref:t}),o):null});xm.displayName=EA;var f0=Y(Ce(),1);function c0(e){let[t,a]=f0.useState(void 0);return Ft(()=>{if(e){a({width:e.offsetWidth,height:e.offsetHeight});let n=new ResizeObserver(l=>{if(!Array.isArray(l)||!l.length)return;let r=l[0],o,i;if("borderBoxSize"in r){let u=r.borderBoxSize,s=Array.isArray(u)?u[0]:u;o=s.inlineSize,i=s.blockSize}else o=e.offsetWidth,i=e.offsetHeight;a({width:o,height:i})});return n.observe(e,{box:"border-box"}),()=>n.unobserve(e)}else a(void 0)},[e]),t}var Nt=Y(Ce(),1);var m0=["top","right","bottom","left"];var Ba=Math.min,ba=Math.max,Ii=Math.round,Ai=Math.floor,Pa=e=>({x:e,y:e}),DA={left:"right",right:"left",bottom:"top",top:"bottom"};function ym(e,t,a){return ba(e,Ba(t,a))}function Ua(e,t){return typeof e=="function"?e(t):e}function dn(e){return e.split("-")[0]}function Dl(e){return e.split("-")[1]}function bf(e){return e==="x"?"y":"x"}function vf(e){return e==="y"?"height":"width"}function va(e){let t=e[0];return t==="t"||t==="b"?"y":"x"}function wf(e){return bf(va(e))}function h0(e,t,a){a===void 0&&(a=!1);let n=Dl(e),l=wf(e),r=vf(l),o=l==="x"?n===(a?"end":"start")?"right":"left":n==="start"?"bottom":"top";return t.reference[r]>t.floating[r]&&(o=ki(o)),[o,ki(o)]}function g0(e){let t=ki(e);return[Cf(e),t,Cf(t)]}function Cf(e){return e.includes("start")?e.replace("start","end"):e.replace("end","start")}var d0=["left","right"],p0=["right","left"],OA=["top","bottom"],zA=["bottom","top"];function BA(e,t,a){switch(e){case"top":case"bottom":return a?t?p0:d0:t?d0:p0;case"left":case"right":return t?OA:zA;default:return[]}}function x0(e,t,a,n){let l=Dl(e),r=BA(dn(e),a==="start",n);return l&&(r=r.map(o=>o+"-"+l),t&&(r=r.concat(r.map(Cf)))),r}function ki(e){let t=dn(e);return DA[t]+e.slice(t.length)}function PA(e){var t,a,n,l;return{top:(t=e.top)!=null?t:0,right:(a=e.right)!=null?a:0,bottom:(n=e.bottom)!=null?n:0,left:(l=e.left)!=null?l:0}}function Lm(e){return typeof e!="number"?PA(e):{top:e,right:e,bottom:e,left:e}}function Ol(e){let{x:t,y:a,width:n,height:l}=e;return{width:n,height:l,top:a,left:t,right:t+n,bottom:a+l,x:t,y:a}}function y0(e,t,a){let{reference:n,floating:l}=e,r=va(t),o=wf(t),i=vf(o),u=dn(t),s=r==="y",f=n.x+n.width/2-l.width/2,c=n.y+n.height/2-l.height/2,p=n[i]/2-l[i]/2,d;switch(u){case"top":d={x:f,y:n.y-l.height};break;case"bottom":d={x:f,y:n.y+n.height};break;case"right":d={x:n.x+n.width,y:c};break;case"left":d={x:n.x-l.width,y:c};break;default:d={x:n.x,y:n.y}}let h=Dl(t);return h&&(d[o]+=p*(h==="end"?1:-1)*(a&&s?-1:1)),d}async function C0(e,t){var a;t===void 0&&(t={});let{x:n,y:l,platform:r,rects:o,elements:i,strategy:u}=e,{boundary:s="clippingAncestors",rootBoundary:f="viewport",elementContext:c="floating",altBoundary:p=!1,padding:d=0}=Ua(t,e),h=Lm(d),v=i[p?c==="floating"?"reference":"floating":c],m=Ol(await r.getClippingRect({element:(a=await(r.isElement==null?void 0:r.isElement(v)))==null||a?v:v.contextElement||await(r.getDocumentElement==null?void 0:r.getDocumentElement(i.floating)),boundary:s,rootBoundary:f,strategy:u})),g=c==="floating"?{x:n,y:l,width:o.floating.width,height:o.floating.height}:o.reference,x=await(r.getOffsetParent==null?void 0:r.getOffsetParent(i.floating)),S=await(r.isElement==null?void 0:r.isElement(x))&&await(r.getScale==null?void 0:r.getScale(x))||{x:1,y:1},A=Ol(r.convertOffsetParentRelativeRectToViewportRelativeRect?await r.convertOffsetParentRelativeRectToViewportRelativeRect({elements:i,rect:g,offsetParent:x,strategy:u}):g);return{top:(m.top-A.top+h.top)/S.y,bottom:(A.bottom-m.bottom+h.bottom)/S.y,left:(m.left-A.left+h.left)/S.x,right:(A.right-m.right+h.right)/S.x}}var UA=50,b0=async(e,t,a)=>{let{placement:n="bottom",strategy:l="absolute",middleware:r=[],platform:o}=a,i=o.detectOverflow?o:{...o,detectOverflow:C0},u=await(o.isRTL==null?void 0:o.isRTL(t)),s=await o.getElementRects({reference:e,floating:t,strategy:l}),{x:f,y:c}=y0(s,n,u),p=n,d=0,h={};for(let y=0;y({name:"arrow",options:e,async fn(t){let{x:a,y:n,placement:l,rects:r,platform:o,elements:i,middlewareData:u}=t,{element:s,padding:f=0}=Ua(e,t)||{};if(s==null)return{};let c=Lm(f),p={x:a,y:n},d=wf(l),h=vf(d),y=await o.getDimensions(s),v=d==="y",m=v?"top":"left",g=v?"bottom":"right",x=v?"clientHeight":"clientWidth",S=r.reference[h]+r.reference[d]-p[d]-r.floating[h],A=p[d]-r.reference[d],b=await(o.getOffsetParent==null?void 0:o.getOffsetParent(s)),k=b?b[x]:0;(!k||!await(o.isElement==null?void 0:o.isElement(b)))&&(k=i.floating[x]||r.floating[h]);let I=S/2-A/2,D=k/2-y[h]/2-1,w=Ba(c[m],D),H=Ba(c[g],D),Q=k-y[h]-H,P=k/2-y[h]/2+I,F=ym(w,P,Q),N=!u.arrow&&Dl(l)!=null&&P!==F&&r.reference[h]/2-(PF<=0)){var H,Q;let F=(((H=r.flip)==null?void 0:H.index)||0)+1,N=k[F];if(N&&(!(c==="alignment"?g!==va(N):!1)||w.every(E=>va(E.placement)===g?E.overflows[0]>0:!0)))return{data:{index:F,overflows:w},reset:{placement:N}};let j=(Q=w.filter(J=>J.overflows[0]<=0).sort((J,E)=>J.overflows[1]-E.overflows[1])[0])==null?void 0:Q.placement;if(!j)switch(d){case"bestFit":{var P;let J=(P=w.filter(E=>{if(b){let q=va(E.placement);return q===g||q==="y"}return!0}).map(E=>[E.placement,E.overflows.filter(q=>q>0).reduce((q,L)=>q+L,0)]).sort((E,q)=>E[1]-q[1])[0])==null?void 0:P[0];J&&(j=J);break}case"initialPlacement":j=i;break}if(l!==j)return{reset:{placement:j}}}return{}}}};function L0(e,t){return{top:e.top-t.height,right:e.right-t.width,bottom:e.bottom-t.height,left:e.left-t.width}}function S0(e){return m0.some(t=>e[t]>=0)}var k0=function(e){return e===void 0&&(e={}),{name:"hide",options:e,async fn(t){let{rects:a,platform:n}=t,{strategy:l="referenceHidden",...r}=Ua(e,t);switch(l){case"referenceHidden":{let o=await n.detectOverflow(t,{...r,elementContext:"reference"}),i=L0(o,a.reference);return{data:{referenceHiddenOffsets:i,referenceHidden:S0(i)}}}case"escaped":{let o=await n.detectOverflow(t,{...r,altBoundary:!0}),i=L0(o,a.floating);return{data:{escapedOffsets:i,escaped:S0(i)}}}default:return{}}}}};var I0=new Set(["left","top"]);async function qA(e,t){let{placement:a,platform:n,elements:l}=e,r=await(n.isRTL==null?void 0:n.isRTL(l.floating)),o=dn(a),i=Dl(a),u=va(a)==="y",s=I0.has(o)?-1:1,f=r&&u?-1:1,c=Ua(t,e),{mainAxis:p,crossAxis:d,alignmentAxis:h}=typeof c=="number"?{mainAxis:c,crossAxis:0,alignmentAxis:null}:{mainAxis:c.mainAxis||0,crossAxis:c.crossAxis||0,alignmentAxis:c.alignmentAxis};return i&&typeof h=="number"&&(d=i==="end"?h*-1:h),u?{x:d*f,y:p*s}:{x:p*s,y:d*f}}var A0=function(e){return e===void 0&&(e=0),{name:"offset",options:e,async fn(t){var a,n;let{x:l,y:r,placement:o,middlewareData:i}=t,u=await qA(t,e);return o===((a=i.offset)==null?void 0:a.placement)&&(n=i.arrow)!=null&&n.alignmentOffset?{}:{x:l+u.x,y:r+u.y,data:{...u,placement:o}}}}},T0=function(e){return e===void 0&&(e={}),{name:"shift",options:e,async fn(t){let{x:a,y:n,placement:l,platform:r}=t,{mainAxis:o=!0,crossAxis:i=!1,limiter:u={fn:g=>{let{x,y:S}=g;return{x,y:S}}},...s}=Ua(e,t),f={x:a,y:n},c=await r.detectOverflow(t,s),p=va(l),d=bf(p),h=f[d],y=f[p],v=(g,x)=>ym(x+c[g==="y"?"top":"left"],x,x-c[g==="y"?"bottom":"right"]);o&&(h=v(d,h)),i&&(y=v(p,y));let m=u.fn({...t,[d]:h,[p]:y});return{...m,data:{x:m.x-a,y:m.y-n,enabled:{[d]:o,[p]:i}}}}}},M0=function(e){return e===void 0&&(e={}),{options:e,fn(t){var a,n;let{x:l,y:r,placement:o,rects:i,middlewareData:u}=t,{offset:s=0,mainAxis:f=!0,crossAxis:c=!0}=Ua(e,t),p={x:l,y:r},d=va(o),h=bf(d),y=p[h],v=p[d],m=Ua(s,t),g=typeof m=="number"?{mainAxis:m,crossAxis:0}:{mainAxis:(a=m.mainAxis)!=null?a:0,crossAxis:(n=m.crossAxis)!=null?n:0};if(f){let A=h==="y"?"height":"width",b=i.reference[h]-i.floating[A]+g.mainAxis,k=i.reference[h]+i.reference[A]-g.mainAxis;yk&&(y=k)}if(c){var x,S;let A=h==="y"?"width":"height",b=I0.has(dn(o)),k=i.reference[d]-i.floating[A]+(b&&((x=u.offset)==null?void 0:x[d])||0)+(b?0:g.crossAxis),I=i.reference[d]+i.reference[A]+(b?0:((S=u.offset)==null?void 0:S[d])||0)-(b?g.crossAxis:0);vI&&(v=I)}return{[h]:y,[d]:v}}}},R0=function(e){return e===void 0&&(e={}),{name:"size",options:e,async fn(t){let{placement:a,rects:n,platform:l,elements:r}=t,{apply:o=()=>{},...i}=Ua(e,t),u=await l.detectOverflow(t,i),s=dn(a),f=Dl(a),c=va(a)==="y",{width:p,height:d}=n.floating,h,y;s==="top"||s==="bottom"?(h=s,y=f===(await(l.isRTL==null?void 0:l.isRTL(r.floating))?"start":"end")?"left":"right"):(y=s,h=f==="end"?"top":"bottom");let v=d-u.top-u.bottom,m=p-u.left-u.right,g=Ba(d-u[h],v),x=Ba(p-u[y],m),S=t.middlewareData.shift,A=!S,b=g,k=x;S!=null&&S.enabled.x&&(k=m),S!=null&&S.enabled.y&&(b=v),A&&!f&&(c?k=p-2*ba(u.left,u.right):b=d-2*ba(u.top,u.bottom)),await o({...t,availableWidth:k,availableHeight:b});let I=await l.getDimensions(r.floating);return p!==I.width||d!==I.height?{reset:{rects:!0}}:{}}}};function kf(){return typeof window<"u"}function Pl(e){return D0(e)?(e.nodeName||"").toLowerCase():"#document"}function Tt(e){var t;return(e==null||(t=e.ownerDocument)==null?void 0:t.defaultView)||window}function qa(e){var t;return(t=(D0(e)?e.ownerDocument:e.document)||window.document)==null?void 0:t.documentElement}function D0(e){return kf()?e instanceof Node||e instanceof Tt(e).Node:!1}function wa(e){return kf()?e instanceof Element||e instanceof Tt(e).Element:!1}function pn(e){return kf()?e instanceof HTMLElement||e instanceof Tt(e).HTMLElement:!1}function E0(e){return!kf()||typeof ShadowRoot>"u"?!1:e instanceof ShadowRoot||e instanceof Tt(e).ShadowRoot}function Ti(e){let{overflow:t,overflowX:a,overflowY:n,display:l}=ka(e);return/auto|scroll|overlay|hidden|clip/.test(t+n+a)&&l!=="inline"&&l!=="contents"}function O0(e){return/^(table|td|th)$/.test(Pl(e))}function Mi(e){try{if(e.matches(":popover-open"))return!0}catch{}try{return e.matches(":modal")}catch{return!1}}var HA=/transform|translate|scale|rotate|perspective|filter/,FA=/paint|layout|strict|content/,zl=e=>!!e&&e!=="none",Sm;function If(e){let t=wa(e)?ka(e):e;return zl(t.transform)||zl(t.translate)||zl(t.scale)||zl(t.rotate)||zl(t.perspective)||!Af()&&(zl(t.backdropFilter)||zl(t.filter))||HA.test(t.willChange||"")||FA.test(t.contain||"")}function z0(e){let t=Wn(e);for(;pn(t)&&!$r(t);){if(If(t))return t;if(Mi(t))return null;t=Wn(t)}return null}function Af(){return Sm==null&&(Sm=typeof CSS<"u"&&CSS.supports&&CSS.supports("-webkit-backdrop-filter","none")),Sm}function $r(e){return/^(html|body|#document)$/.test(Pl(e))}function ka(e){return Tt(e).getComputedStyle(e)}function Ri(e){return wa(e)?{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}:{scrollLeft:e.scrollX,scrollTop:e.scrollY}}function Wn(e){if(Pl(e)==="html")return e;let t=e.assignedSlot||e.parentNode||E0(e)&&e.host||qa(e);return E0(t)?t.host:t}function B0(e){let t=Wn(e);return $r(t)?(e.ownerDocument||e).body:pn(t)&&Ti(t)?t:B0(t)}function Bl(e,t,a){var n;t===void 0&&(t=[]),a===void 0&&(a=!0);let l=B0(e),r=l===((n=e.ownerDocument)==null?void 0:n.body),o=Tt(l);if(r){let i=Tf(o);return t.concat(o,o.visualViewport||[],Ti(l)?l:[],i&&a?Bl(i):[])}else return t.concat(l,Bl(l,[],a))}function Tf(e){return e.parent&&Object.getPrototypeOf(e.parent)?e.frameElement:null}function q0(e){let t=ka(e),a=parseFloat(t.width)||0,n=parseFloat(t.height)||0,l=pn(e),r=l?e.offsetWidth:a,o=l?e.offsetHeight:n,i=Ii(a)!==r||Ii(n)!==o;return i&&(a=r,n=o),{width:a,height:n,$:i}}function bm(e){return wa(e)?e:e.contextElement}function eo(e){let t=bm(e);if(!pn(t))return Pa(1);let a=t.getBoundingClientRect(),{width:n,height:l,$:r}=q0(t),o=(r?Ii(a.width):a.width)/n,i=(r?Ii(a.height):a.height)/l;return(!o||!Number.isFinite(o))&&(o=1),(!i||!Number.isFinite(i))&&(i=1),{x:o,y:i}}var _A=Pa(0);function H0(e){let t=Tt(e);return!Af()||!t.visualViewport?_A:{x:t.visualViewport.offsetLeft,y:t.visualViewport.offsetTop}}function NA(e,t,a){return t===void 0&&(t=!1),!!a&&t&&a===Tt(e)}function Ul(e,t,a,n){t===void 0&&(t=!1),a===void 0&&(a=!1);let l=e.getBoundingClientRect(),r=bm(e),o=Pa(1);t&&(n?wa(n)&&(o=eo(n)):o=eo(e));let i=NA(r,a,n)?H0(r):Pa(0),u=(l.left+i.x)/o.x,s=(l.top+i.y)/o.y,f=l.width/o.x,c=l.height/o.y;if(r&&n){let p=Tt(r),d=wa(n)?Tt(n):n,h=p,y=Tf(h);for(;y&&d!==h;){let v=eo(y),m=y.getBoundingClientRect(),g=ka(y),x=m.left+(y.clientLeft+parseFloat(g.paddingLeft))*v.x,S=m.top+(y.clientTop+parseFloat(g.paddingTop))*v.y;u*=v.x,s*=v.y,f*=v.x,c*=v.y,u+=x,s+=S,h=Tt(y),y=Tf(h)}}return Ol({width:f,height:c,x:u,y:s})}function Mf(e,t){let a=Ri(e).scrollLeft;return t?t.left+a:Ul(qa(e)).left+a}function F0(e,t){let a=e.getBoundingClientRect(),n=a.left+t.scrollLeft-Mf(e,a),l=a.top+t.scrollTop;return{x:n,y:l}}function VA(e){let{elements:t,rect:a,offsetParent:n,strategy:l}=e,r=l==="fixed",o=qa(n),i=t?Mi(t.floating):!1;if(n===o||i&&r)return a;let u={scrollLeft:0,scrollTop:0},s=Pa(1),f=Pa(0),c=pn(n);if((c||!r)&&((Pl(n)!=="body"||Ti(o))&&(u=Ri(n)),c)){let d=Ul(n);s=eo(n),f.x=d.x+n.clientLeft,f.y=d.y+n.clientTop}let p=o&&!c&&!r?F0(o,u):Pa(0);return{width:a.width*s.x,height:a.height*s.y,x:a.x*s.x-u.scrollLeft*s.x+f.x+p.x,y:a.y*s.y-u.scrollTop*s.y+f.y+p.y}}function GA(e){return e.getClientRects?Array.from(e.getClientRects()):[]}function jA(e){let t=Ri(e),a=e.ownerDocument.body,n=ba(e.scrollWidth,e.clientWidth,a.scrollWidth,a.clientWidth),l=ba(e.scrollHeight,e.clientHeight,a.scrollHeight,a.clientHeight),r=-t.scrollLeft+Mf(e),o=-t.scrollTop;return ka(a).direction==="rtl"&&(r+=ba(e.clientWidth,a.clientWidth)-n),{width:n,height:l,x:r,y:o}}var XA=25;function YA(e,t,a){a===void 0&&(a="viewport");let n=a==="layoutViewport",l=Tt(e),r=qa(e),o=l.visualViewport,i=r.clientWidth,u=r.clientHeight,s=0,f=0;if(o){let p=!Af()||t==="fixed";n?p||(s=-o.offsetLeft,f=-o.offsetTop):(i=o.width,u=o.height,p&&(s=o.offsetLeft,f=o.offsetTop))}if(Mf(r)<=0){let p=r.ownerDocument,d=p.body,h=getComputedStyle(d),y=p.compatMode==="CSS1Compat"&&parseFloat(h.marginLeft)+parseFloat(h.marginRight)||0,v=Math.abs(r.clientWidth-d.clientWidth-y),m=getComputedStyle(r).scrollbarGutter==="stable both-edges"?v/2:v;m<=XA&&(i-=m)}return{width:i,height:u,x:s,y:f}}function QA(e,t){let a=Ul(e,!0,t==="fixed"),n=a.top+e.clientTop,l=a.left+e.clientLeft,r=eo(e),o=e.clientWidth*r.x,i=e.clientHeight*r.y,u=l*r.x,s=n*r.y;return{width:o,height:i,x:u,y:s}}function P0(e,t,a){let n;if(t==="viewport"||t==="layoutViewport")n=YA(e,a,t);else if(t==="document")n=jA(qa(e));else if(wa(t))n=QA(t,a);else{let l=H0(e);n={x:t.x-l.x,y:t.y-l.y,width:t.width,height:t.height}}return Ol(n)}function ZA(e,t){let a=t.get(e);if(a)return a;let n=Bl(e,[],!1).filter(i=>wa(i)&&Pl(i)!=="body"),l=null,r=ka(e).position==="fixed",o=r?Wn(e):e;for(;wa(o)&&!$r(o);){let i=ka(o),u=If(o),s=l?l.position:r?"fixed":"";!u&&(s==="fixed"||s==="absolute"&&i.position==="static")?n=n.filter(c=>c!==o):l=i,o=Wn(o)}return t.set(e,n),n}function KA(e){let{element:t,boundary:a,rootBoundary:n,strategy:l}=e,o=[...a==="clippingAncestors"?Mi(t)?[]:ZA(t,this._c):[].concat(a),n],i=P0(t,o[0],l),u=i.top,s=i.right,f=i.bottom,c=i.left;for(let p=1;p{i(!1,1e-7)},1e3)}k=!1}try{n=new IntersectionObserver(I,{...b,root:r.ownerDocument})}catch{n=new IntersectionObserver(I,b)}n.observe(e)}let u=Tt(e),s=()=>i(a);return u.addEventListener("resize",s),i(!0),()=>{u.removeEventListener("resize",s),o()}}function vm(e,t,a,n){n===void 0&&(n={});let{ancestorScroll:l=!0,ancestorResize:r=!0,elementResize:o=typeof ResizeObserver=="function",layoutShift:i=typeof IntersectionObserver=="function",animationFrame:u=!1}=n,s=bm(e),f=l||r?[...s?Bl(s):[],...t?Bl(t):[]]:[];f.forEach(m=>{l&&m.addEventListener("scroll",a),r&&m.addEventListener("resize",a)});let c=s&&i?tT(s,a,r):null,p=-1,d=null;o&&(d=new ResizeObserver(m=>{let[g]=m;g&&g.target===s&&d&&t&&(d.unobserve(t),cancelAnimationFrame(p),p=requestAnimationFrame(()=>{var x;(x=d)==null||x.observe(t)})),a()}),s&&!u&&d.observe(s),t&&d.observe(t));let h,y=u?Ul(e):null;u&&v();function v(){let m=Ul(e);y&&!V0(y,m)&&a(),y=m,h=requestAnimationFrame(v)}return a(),()=>{var m;f.forEach(g=>{l&&g.removeEventListener("scroll",a),r&&g.removeEventListener("resize",a)}),c?.(),(m=d)==null||m.disconnect(),d=null,u&&cancelAnimationFrame(h)}}var G0=A0;var j0=T0,X0=w0,Y0=R0,Q0=k0,wm=v0;var Z0=M0,km=(e,t,a)=>{let n=new Map,l=a??{},r={...N0,...l.platform,_c:n};return b0(e,t,{...l,platform:r})};var tt=Y(Ce(),1),W0=Y(Ce(),1),J0=Y(sl(),1),aT=typeof document<"u",nT=function(){},Rf=aT?W0.useLayoutEffect:nT;function Ef(e,t){if(e===t)return!0;if(typeof e!=typeof t)return!1;if(typeof e=="function"&&e.toString()===t.toString())return!0;let a,n,l;if(e&&t&&typeof e=="object"){if(Array.isArray(e)){if(a=e.length,a!==t.length)return!1;for(n=a;n--!==0;)if(!Ef(e[n],t[n]))return!1;return!0}if(l=Object.keys(e),a=l.length,a!==Object.keys(t).length)return!1;for(n=a;n--!==0;)if(!{}.hasOwnProperty.call(t,l[n]))return!1;for(n=a;n--!==0;){let r=l[n];if(!(r==="_owner"&&e.$$typeof)&&!Ef(e[r],t[r]))return!1}return!0}return e!==e&&t!==t}function $0(e){return typeof window>"u"?1:(e.ownerDocument.defaultView||window).devicePixelRatio||1}function K0(e,t){let a=$0(e);return Math.round(t*a)/a}function Im(e){let t=tt.useRef(e);return Rf(()=>{t.current=e}),t}function eC(e){e===void 0&&(e={});let{placement:t="bottom",strategy:a="absolute",middleware:n=[],platform:l,elements:{reference:r,floating:o}={},transform:i=!0,whileElementsMounted:u,open:s}=e,[f,c]=tt.useState({x:0,y:0,strategy:a,placement:t,middlewareData:{},isPositioned:!1}),[p,d]=tt.useState(n);Ef(p,n)||d(n);let[h,y]=tt.useState(null),[v,m]=tt.useState(null),g=tt.useCallback(E=>{E!==b.current&&(b.current=E,y(E))},[]),x=tt.useCallback(E=>{E!==k.current&&(k.current=E,m(E))},[]),S=r||h,A=o||v,b=tt.useRef(null),k=tt.useRef(null),I=tt.useRef(f),D=u!=null,w=Im(u),H=Im(l),Q=Im(s),P=tt.useCallback(()=>{if(!b.current||!k.current)return;let E={placement:t,strategy:a,middleware:p};H.current&&(E.platform=H.current),km(b.current,k.current,E).then(q=>{let L={...q,isPositioned:Q.current!==!1};F.current&&!Ef(I.current,L)&&(I.current=L,J0.flushSync(()=>{c(L)}))})},[p,t,a,H,Q]);Rf(()=>{s===!1&&I.current.isPositioned&&(I.current.isPositioned=!1,c(E=>({...E,isPositioned:!1})))},[s]);let F=tt.useRef(!1);Rf(()=>(F.current=!0,()=>{F.current=!1}),[]),Rf(()=>{if(S&&(b.current=S),A&&(k.current=A),S&&A){if(w.current)return w.current(S,A,P);P()}},[S,A,P,w,D]);let N=tt.useMemo(()=>({reference:b,floating:k,setReference:g,setFloating:x}),[g,x]),j=tt.useMemo(()=>({reference:S,floating:A}),[S,A]),J=tt.useMemo(()=>{let E={position:a,left:0,top:0};if(!j.floating)return E;let q=K0(j.floating,f.x),L=K0(j.floating,f.y);return i?{...E,transform:"translate("+q+"px, "+L+"px)",...$0(j.floating)>=1.5&&{willChange:"transform"}}:{position:a,left:q,top:L}},[a,i,j.floating,f.x,f.y]);return tt.useMemo(()=>({...f,update:P,refs:N,elements:j,floatingStyles:J}),[f,P,N,j,J])}var lT=e=>{function t(a){return{}.hasOwnProperty.call(a,"current")}return{name:"arrow",options:e,fn(a){let{element:n,padding:l}=typeof e=="function"?e(a):e;return n&&t(n)?n.current!=null?wm({element:n.current,padding:l}).fn(a):{}:n?wm({element:n,padding:l}).fn(a):{}}}},tC=(e,t)=>{let a=G0(e);return{name:a.name,fn:a.fn,options:[e,t]}},aC=(e,t)=>{let a=j0(e);return{name:a.name,fn:a.fn,options:[e,t]}},nC=(e,t)=>({fn:Z0(e).fn,options:[e,t]}),lC=(e,t)=>{let a=X0(e);return{name:a.name,fn:a.fn,options:[e,t]}},rC=(e,t)=>{let a=Y0(e);return{name:a.name,fn:a.fn,options:[e,t]}};var oC=(e,t)=>{let a=Q0(e);return{name:a.name,fn:a.fn,options:[e,t]}};var iC=(e,t)=>{let a=lT(e);return{name:a.name,fn:a.fn,options:[e,t]}};var uC=Y(Ce(),1);var Am=Y(Xe(),1),rT="Arrow",sC=uC.forwardRef((e,t)=>{let{children:a,width:n=10,height:l=5,...r}=e;return(0,Am.jsx)(Ht.svg,{...r,ref:t,width:n,height:l,viewBox:"0 0 30 10",preserveAspectRatio:"none",children:e.asChild?a:(0,Am.jsx)("polygon",{points:"0,0 30,0 15,10"})})});sC.displayName=rT;var fC=sC;var Jn=Y(Xe(),1);var Tm="Popper",[cC,Mm]=gf(Tm),[iT,dC]=cC(Tm),pC=e=>{let{__scopePopper:t,children:a}=e,[n,l]=Nt.useState(null);return(0,Jn.jsx)(iT,{scope:t,anchor:n,onAnchorChange:l,children:a})};pC.displayName=Tm;var mC="PopperAnchor",hC=Nt.forwardRef((e,t)=>{let{__scopePopper:a,virtualRef:n,...l}=e,r=dC(mC,a),o=Nt.useRef(null),i=Sa(t,o),u=Nt.useRef(null);return Nt.useEffect(()=>{let s=u.current;u.current=n?.current||o.current,s!==u.current&&r.onAnchorChange(u.current)}),n?null:(0,Jn.jsx)(Ht.div,{...l,ref:i})});hC.displayName=mC;var Rm="PopperContent",[uT,sT]=cC(Rm),gC=Nt.forwardRef((e,t)=>{let{__scopePopper:a,side:n="bottom",sideOffset:l=0,align:r="center",alignOffset:o=0,arrowPadding:i=0,avoidCollisions:u=!0,collisionBoundary:s=[],collisionPadding:f=0,sticky:c="partial",hideWhenDetached:p=!1,updatePositionStrategy:d="optimized",onPlaced:h,...y}=e,v=dC(Rm,a),[m,g]=Nt.useState(null),x=Sa(t,me=>g(me)),[S,A]=Nt.useState(null),b=c0(S),k=b?.width??0,I=b?.height??0,D=n+(r!=="center"?"-"+r:""),w=typeof f=="number"?f:{top:0,right:0,bottom:0,left:0,...f},H=Array.isArray(s)?s:[s],Q=H.length>0,P={padding:w,boundary:H.filter(cT),altBoundary:Q},{refs:F,floatingStyles:N,placement:j,isPositioned:J,middlewareData:E}=eC({strategy:"fixed",placement:D,whileElementsMounted:(...me)=>vm(...me,{animationFrame:d==="always"}),elements:{reference:v.anchor},middleware:[tC({mainAxis:l+I,alignmentAxis:o}),u&&aC({mainAxis:!0,crossAxis:!1,limiter:c==="partial"?nC():void 0,...P}),u&&lC({...P}),rC({...P,apply:({elements:me,rects:Te,availableWidth:bt,availableHeight:Ze})=>{let{width:vt,height:R}=Te.reference,X=me.floating.style;X.setProperty("--radix-popper-available-width",`${bt}px`),X.setProperty("--radix-popper-available-height",`${Ze}px`),X.setProperty("--radix-popper-anchor-width",`${vt}px`),X.setProperty("--radix-popper-anchor-height",`${R}px`)}}),S&&iC({element:S,padding:i}),dT({arrowWidth:k,arrowHeight:I}),p&&oC({strategy:"referenceHidden",...P})]}),[q,L]=LC(j),Se=El(h);Ft(()=>{J&&Se?.()},[J,Se]);let ut=E.arrow?.x,C=E.arrow?.y,de=E.arrow?.centerOffset!==0,[Qe,aa]=Nt.useState();return Ft(()=>{m&&aa(window.getComputedStyle(m).zIndex)},[m]),(0,Jn.jsx)("div",{ref:F.setFloating,"data-radix-popper-content-wrapper":"",style:{...N,transform:J?N.transform:"translate(0, -200%)",minWidth:"max-content",zIndex:Qe,"--radix-popper-transform-origin":[E.transformOrigin?.x,E.transformOrigin?.y].join(" "),...E.hide?.referenceHidden&&{visibility:"hidden",pointerEvents:"none"}},dir:e.dir,children:(0,Jn.jsx)(uT,{scope:a,placedSide:q,onArrowChange:A,arrowX:ut,arrowY:C,shouldHideArrow:de,children:(0,Jn.jsx)(Ht.div,{"data-side":q,"data-align":L,...y,ref:x,style:{...y.style,animation:J?void 0:"none"}})})})});gC.displayName=Rm;var xC="PopperArrow",fT={top:"bottom",right:"left",bottom:"top",left:"right"},yC=Nt.forwardRef(function(t,a){let{__scopePopper:n,...l}=t,r=sT(xC,n),o=fT[r.placedSide];return(0,Jn.jsx)("span",{ref:r.onArrowChange,style:{position:"absolute",left:r.arrowX,top:r.arrowY,[o]:0,transformOrigin:{top:"",right:"0 0",bottom:"center 0",left:"100% 0"}[r.placedSide],transform:{top:"translateY(100%)",right:"translateY(50%) rotate(90deg) translateX(-50%)",bottom:"rotate(180deg)",left:"translateY(50%) rotate(-90deg) translateX(50%)"}[r.placedSide],visibility:r.shouldHideArrow?"hidden":void 0},children:(0,Jn.jsx)(fC,{...l,ref:a,style:{...l.style,display:"block"}})})});yC.displayName=xC;function cT(e){return e!==null}var dT=e=>({name:"transformOrigin",options:e,fn(t){let{placement:a,rects:n,middlewareData:l}=t,o=l.arrow?.centerOffset!==0,i=o?0:e.arrowWidth,u=o?0:e.arrowHeight,[s,f]=LC(a),c={start:"0%",center:"50%",end:"100%"}[f],p=(l.arrow?.x??0)+i/2,d=(l.arrow?.y??0)+u/2,h="",y="";return s==="bottom"?(h=o?c:`${p}px`,y=`${-u}px`):s==="top"?(h=o?c:`${p}px`,y=`${n.floating.height+u}px`):s==="right"?(h=`${-u}px`,y=o?c:`${d}px`):s==="left"&&(h=`${n.floating.width+u}px`,y=o?c:`${d}px`),{data:{x:h,y}}}});function LC(e){let[t,a="center"]=e.split("-");return[t,a]}var SC=pC,CC=hC,bC=gC,vC=yC;var mn={};Ru(mn,{Arrow:()=>BT,Content:()=>zT,Portal:()=>OT,Provider:()=>RT,Root:()=>ET,Tooltip:()=>Bm,TooltipArrow:()=>Fm,TooltipContent:()=>Hm,TooltipPortal:()=>qm,TooltipProvider:()=>zm,TooltipTrigger:()=>Pm,Trigger:()=>DT,createTooltipScope:()=>mT});var re=Y(Ce(),1);var at=Y(Xe(),1),[Df,mT]=gf("Tooltip",[Mm]),Of=Mm(),wC="TooltipProvider",hT=700,Em="tooltip.open",[gT,Om]=Df(wC),zm=e=>{let{__scopeTooltip:t,delayDuration:a=hT,skipDelayDuration:n=300,disableHoverableContent:l=!1,children:r}=e,o=re.useRef(!0),i=re.useRef(!1),u=re.useRef(0);return re.useEffect(()=>{let s=u.current;return()=>window.clearTimeout(s)},[]),(0,at.jsx)(gT,{scope:t,isOpenDelayedRef:o,delayDuration:a,onOpen:re.useCallback(()=>{window.clearTimeout(u.current),o.current=!1},[]),onClose:re.useCallback(()=>{window.clearTimeout(u.current),u.current=window.setTimeout(()=>o.current=!0,n)},[n]),isPointerInTransitRef:i,onPointerInTransitChange:re.useCallback(s=>{i.current=s},[]),disableHoverableContent:l,children:r})};zm.displayName=wC;var Ei="Tooltip",[xT,Di]=Df(Ei),Bm=e=>{let{__scopeTooltip:t,children:a,open:n,defaultOpen:l,onOpenChange:r,disableHoverableContent:o,delayDuration:i}=e,u=Om(Ei,e.__scopeTooltip),s=Of(t),[f,c]=re.useState(null),p=t0(),d=re.useRef(0),h=o??u.disableHoverableContent,y=i??u.delayDuration,v=re.useRef(!1),[m,g]=$S({prop:n,defaultProp:l??!1,onChange:k=>{k?(u.onOpen(),document.dispatchEvent(new CustomEvent(Em))):u.onClose(),r?.(k)},caller:Ei}),x=re.useMemo(()=>m?v.current?"delayed-open":"instant-open":"closed",[m]),S=re.useCallback(()=>{window.clearTimeout(d.current),d.current=0,v.current=!1,g(!0)},[g]),A=re.useCallback(()=>{window.clearTimeout(d.current),d.current=0,g(!1)},[g]),b=re.useCallback(()=>{window.clearTimeout(d.current),d.current=window.setTimeout(()=>{v.current=!0,g(!0),d.current=0},y)},[y,g]);return re.useEffect(()=>()=>{d.current&&(window.clearTimeout(d.current),d.current=0)},[]),(0,at.jsx)(SC,{...s,children:(0,at.jsx)(xT,{scope:t,contentId:p,open:m,stateAttribute:x,trigger:f,onTriggerChange:c,onTriggerEnter:re.useCallback(()=>{u.isOpenDelayedRef.current?b():S()},[u.isOpenDelayedRef,b,S]),onTriggerLeave:re.useCallback(()=>{h?A():(window.clearTimeout(d.current),d.current=0)},[A,h]),onOpen:S,onClose:A,disableHoverableContent:h,children:a})})};Bm.displayName=Ei;var Dm="TooltipTrigger",Pm=re.forwardRef((e,t)=>{let{__scopeTooltip:a,...n}=e,l=Di(Dm,a),r=Om(Dm,a),o=Of(a),i=re.useRef(null),u=Sa(t,i,l.onTriggerChange),s=re.useRef(!1),f=re.useRef(!1),c=re.useCallback(()=>s.current=!1,[]);return re.useEffect(()=>()=>document.removeEventListener("pointerup",c),[c]),(0,at.jsx)(CC,{asChild:!0,...o,children:(0,at.jsx)(Ht.button,{"aria-describedby":l.open?l.contentId:void 0,"data-state":l.stateAttribute,...n,ref:u,onPointerMove:Ca(e.onPointerMove,p=>{p.pointerType!=="touch"&&!f.current&&!r.isPointerInTransitRef.current&&(l.onTriggerEnter(),f.current=!0)}),onPointerLeave:Ca(e.onPointerLeave,()=>{l.onTriggerLeave(),f.current=!1}),onPointerDown:Ca(e.onPointerDown,()=>{l.open&&l.onClose(),s.current=!0,document.addEventListener("pointerup",c,{once:!0})}),onFocus:Ca(e.onFocus,()=>{s.current||l.onOpen()}),onBlur:Ca(e.onBlur,l.onClose),onClick:Ca(e.onClick,l.onClose)})})});Pm.displayName=Dm;var Um="TooltipPortal",[yT,LT]=Df(Um,{forceMount:void 0}),qm=e=>{let{__scopeTooltip:t,forceMount:a,children:n,container:l}=e,r=Di(Um,t);return(0,at.jsx)(yT,{scope:t,forceMount:a,children:(0,at.jsx)(Lf,{present:a||r.open,children:(0,at.jsx)(xm,{asChild:!0,container:l,children:n})})})};qm.displayName=Um;var to="TooltipContent",Hm=re.forwardRef((e,t)=>{let a=LT(to,e.__scopeTooltip),{forceMount:n=a.forceMount,side:l="top",...r}=e,o=Di(to,e.__scopeTooltip);return(0,at.jsx)(Lf,{present:n||o.open,children:o.disableHoverableContent?(0,at.jsx)(kC,{side:l,...r,ref:t}):(0,at.jsx)(ST,{side:l,...r,ref:t})})}),ST=re.forwardRef((e,t)=>{let a=Di(to,e.__scopeTooltip),n=Om(to,e.__scopeTooltip),l=re.useRef(null),r=Sa(t,l),[o,i]=re.useState(null),{trigger:u,onClose:s}=a,f=l.current,{onPointerInTransitChange:c}=n,p=re.useCallback(()=>{i(null),c(!1)},[c]),d=re.useCallback((h,y)=>{let v=h.currentTarget,m={x:h.clientX,y:h.clientY},g=wT(m,v.getBoundingClientRect()),x=kT(m,g),S=IT(y.getBoundingClientRect()),A=TT([...x,...S]);i(A),c(!0)},[c]);return re.useEffect(()=>()=>p(),[p]),re.useEffect(()=>{if(u&&f){let h=v=>d(v,f),y=v=>d(v,u);return u.addEventListener("pointerleave",h),f.addEventListener("pointerleave",y),()=>{u.removeEventListener("pointerleave",h),f.removeEventListener("pointerleave",y)}}},[u,f,d,p]),re.useEffect(()=>{if(o){let h=y=>{let v=y.target,m={x:y.clientX,y:y.clientY},g=u?.contains(v)||f?.contains(v),x=!AT(m,o);g?p():x&&(p(),s())};return document.addEventListener("pointermove",h),()=>document.removeEventListener("pointermove",h)}},[u,f,o,s,p]),(0,at.jsx)(kC,{...e,ref:r})}),[CT,bT]=Df(Ei,{isInside:!1}),vT=mf("TooltipContent"),kC=re.forwardRef((e,t)=>{let{__scopeTooltip:a,children:n,"aria-label":l,onEscapeKeyDown:r,onPointerDownOutside:o,...i}=e,u=Di(to,a),s=Of(a),{onClose:f}=u;return re.useEffect(()=>(document.addEventListener(Em,f),()=>document.removeEventListener(Em,f)),[f]),re.useEffect(()=>{if(u.trigger){let c=p=>{p.target?.contains(u.trigger)&&f()};return window.addEventListener("scroll",c,{capture:!0}),()=>window.removeEventListener("scroll",c,{capture:!0})}},[u.trigger,f]),(0,at.jsx)(gm,{asChild:!0,disableOutsidePointerEvents:!1,onEscapeKeyDown:r,onPointerDownOutside:o,onFocusOutside:c=>c.preventDefault(),onDismiss:f,children:(0,at.jsxs)(bC,{"data-state":u.stateAttribute,...s,...i,ref:t,style:{...i.style,"--radix-tooltip-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-tooltip-content-available-width":"var(--radix-popper-available-width)","--radix-tooltip-content-available-height":"var(--radix-popper-available-height)","--radix-tooltip-trigger-width":"var(--radix-popper-anchor-width)","--radix-tooltip-trigger-height":"var(--radix-popper-anchor-height)"},children:[(0,at.jsx)(vT,{children:n}),(0,at.jsx)(CT,{scope:a,isInside:!0,children:(0,at.jsx)(KS,{id:u.contentId,role:"tooltip",children:l||n})})]})})});Hm.displayName=to;var IC="TooltipArrow",Fm=re.forwardRef((e,t)=>{let{__scopeTooltip:a,...n}=e,l=Of(a);return bT(IC,a).isInside?null:(0,at.jsx)(vC,{...l,...n,ref:t})});Fm.displayName=IC;function wT(e,t){let a=Math.abs(t.top-e.y),n=Math.abs(t.bottom-e.y),l=Math.abs(t.right-e.x),r=Math.abs(t.left-e.x);switch(Math.min(a,n,l,r)){case r:return"left";case l:return"right";case a:return"top";case n:return"bottom";default:throw new Error("unreachable")}}function kT(e,t,a=5){let n=[];switch(t){case"top":n.push({x:e.x-a,y:e.y+a},{x:e.x+a,y:e.y+a});break;case"bottom":n.push({x:e.x-a,y:e.y-a},{x:e.x+a,y:e.y-a});break;case"left":n.push({x:e.x+a,y:e.y-a},{x:e.x+a,y:e.y+a});break;case"right":n.push({x:e.x-a,y:e.y-a},{x:e.x-a,y:e.y+a});break}return n}function IT(e){let{top:t,right:a,bottom:n,left:l}=e;return[{x:l,y:t},{x:a,y:t},{x:a,y:n},{x:l,y:n}]}function AT(e,t){let{x:a,y:n}=e,l=!1;for(let r=0,o=t.length-1;rn!=p>n&&a<(c-s)*(n-f)/(p-f)+s&&(l=!l)}return l}function TT(e){let t=e.slice();return t.sort((a,n)=>a.xn.x?1:a.yn.y?1:0),MT(t)}function MT(e){if(e.length<=1)return e.slice();let t=[];for(let n=0;n=2;){let r=t[t.length-1],o=t[t.length-2];if((r.x-o.x)*(l.y-o.y)>=(r.y-o.y)*(l.x-o.x))t.pop();else break}t.push(l)}t.pop();let a=[];for(let n=e.length-1;n>=0;n--){let l=e[n];for(;a.length>=2;){let r=a[a.length-1],o=a[a.length-2];if((r.x-o.x)*(l.y-o.y)>=(r.y-o.y)*(l.x-o.x))a.pop();else break}a.push(l)}return a.pop(),t.length===1&&a.length===1&&t[0].x===a[0].x&&t[0].y===a[0].y?t:t.concat(a)}var RT=zm,ET=Bm,DT=Pm,OT=qm,zT=Hm,BT=Fm;var AC=Y(Xe(),1),PT=CS("inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",{variants:{variant:{default:"bg-primary text-primary-foreground hover:bg-primary/90",destructive:"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",outline:"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",secondary:"bg-secondary text-secondary-foreground hover:bg-secondary/80",ghost:"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-9 px-4 py-2 has-[>svg]:px-3",xs:"h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",sm:"h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",lg:"h-10 rounded-md px-6 has-[>svg]:px-4",icon:"size-9","icon-xs":"size-6 rounded-md [&_svg:not([class*='size-'])]:size-3","icon-sm":"size-8","icon-lg":"size-10"}},defaultVariants:{variant:"default",size:"default"}});function Ue({className:e,variant:t="default",size:a="default",asChild:n=!1,...l}){let r=n?hf.Root:"button";return(0,AC.jsx)(r,{"data-slot":"button","data-variant":t,"data-size":a,className:cf(PT({variant:t,size:a,className:e})),...l})}var $n=Y(Xe(),1);function Oi({delayDuration:e=0,...t}){return(0,$n.jsx)(mn.Provider,{"data-slot":"tooltip-provider",delayDuration:e,...t})}function _m({...e}){return(0,$n.jsx)(mn.Root,{"data-slot":"tooltip",...e})}function Nm({...e}){return(0,$n.jsx)(mn.Trigger,{"data-slot":"tooltip-trigger",...e})}function Vm({className:e,sideOffset:t=0,children:a,...n}){return(0,$n.jsx)(mn.Portal,{children:(0,$n.jsxs)(mn.Content,{"data-slot":"tooltip-content",sideOffset:t,className:cf("z-50 w-fit origin-(--radix-tooltip-content-transform-origin) animate-in rounded-md bg-foreground px-3 py-1.5 text-xs text-balance text-background fade-in-0 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",e),...n,children:[a,(0,$n.jsx)(mn.Arrow,{className:"z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground"})]})})}var Bf=Y(Ce());var TC=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),zf=(...e)=>e.filter((t,a,n)=>!!t&&t.trim()!==""&&n.indexOf(t)===a).join(" ").trim();var zi=Y(Ce());var MC={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};var RC=(0,zi.forwardRef)(({color:e="currentColor",size:t=24,strokeWidth:a=2,absoluteStrokeWidth:n,className:l="",children:r,iconNode:o,...i},u)=>(0,zi.createElement)("svg",{ref:u,...MC,width:t,height:t,stroke:e,strokeWidth:n?Number(a)*24/Number(t):a,className:zf("lucide",l),...i},[...o.map(([s,f])=>(0,zi.createElement)(s,f)),...Array.isArray(r)?r:[r]]));var O=(e,t)=>{let a=(0,Bf.forwardRef)(({className:n,...l},r)=>(0,Bf.createElement)(RC,{ref:r,iconNode:t,className:zf(`lucide-${TC(e)}`,n),...l}));return a.displayName=`${e}`,a};var Bi=O("ArrowDown",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);var hn=O("ArrowUp",[["path",{d:"m5 12 7-7 7 7",key:"hav0vg"}],["path",{d:"M12 19V5",key:"x0mq9r"}]]);var Pi=O("Bandage",[["path",{d:"M10 10.01h.01",key:"1e9xi7"}],["path",{d:"M10 14.01h.01",key:"ac23bv"}],["path",{d:"M14 10.01h.01",key:"2wfrvf"}],["path",{d:"M14 14.01h.01",key:"8tw8yn"}],["path",{d:"M18 6v11.5",key:"dkbidh"}],["path",{d:"M6 6v12",key:"vkc79e"}],["rect",{x:"2",y:"6",width:"20",height:"12",rx:"2",key:"1wpnh2"}]]);var Ui=O("Blend",[["circle",{cx:"9",cy:"9",r:"7",key:"p2h5vp"}],["circle",{cx:"15",cy:"15",r:"7",key:"19ennj"}]]);var qi=O("BookOpen",[["path",{d:"M12 7v14",key:"1akyts"}],["path",{d:"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z",key:"ruj8y"}]]);var Hi=O("CircleDashed",[["path",{d:"M10.1 2.182a10 10 0 0 1 3.8 0",key:"5ilxe3"}],["path",{d:"M13.9 21.818a10 10 0 0 1-3.8 0",key:"11zvb9"}],["path",{d:"M17.609 3.721a10 10 0 0 1 2.69 2.7",key:"1iw5b2"}],["path",{d:"M2.182 13.9a10 10 0 0 1 0-3.8",key:"c0bmvh"}],["path",{d:"M20.279 17.609a10 10 0 0 1-2.7 2.69",key:"1ruxm7"}],["path",{d:"M21.818 10.1a10 10 0 0 1 0 3.8",key:"qkgqxc"}],["path",{d:"M3.721 6.391a10 10 0 0 1 2.7-2.69",key:"1mcia2"}],["path",{d:"M6.391 20.279a10 10 0 0 1-2.69-2.7",key:"1fvljs"}]]);var Fi=O("Circle",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]]);var _i=O("Contrast",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 18a6 6 0 0 0 0-12v12z",key:"j4l70d"}]]);var ao=O("Copy",[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]]);var Ni=O("Crop",[["path",{d:"M6 2v14a2 2 0 0 0 2 2h14",key:"ron5a4"}],["path",{d:"M18 22V8a2 2 0 0 0-2-2H2",key:"7s9ehn"}]]);var no=O("Download",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"7 10 12 15 17 10",key:"2ggqvy"}],["line",{x1:"12",x2:"12",y1:"15",y2:"3",key:"1vk2je"}]]);var Vi=O("Droplets",[["path",{d:"M7 16.3c2.2 0 4-1.83 4-4.05 0-1.16-.57-2.26-1.71-3.19S7.29 6.75 7 5.3c-.29 1.45-1.14 2.84-2.29 3.76S3 11.1 3 12.25c0 2.22 1.8 4.05 4 4.05z",key:"1ptgy4"}],["path",{d:"M12.56 6.6A10.97 10.97 0 0 0 14 3.02c.5 2.5 2 4.9 4 6.5s3 3.5 3 5.5a6.98 6.98 0 0 1-11.91 4.97",key:"1sl1rz"}]]);var Gi=O("Eraser",[["path",{d:"m7 21-4.3-4.3c-1-1-1-2.5 0-3.4l9.6-9.6c1-1 2.5-1 3.4 0l5.6 5.6c1 1 1 2.5 0 3.4L13 21",key:"182aya"}],["path",{d:"M22 21H7",key:"t4ddhn"}],["path",{d:"m5 11 9 9",key:"1mo9qw"}]]);var ji=O("Fingerprint",[["path",{d:"M12 10a2 2 0 0 0-2 2c0 1.02-.1 2.51-.26 4",key:"1nerag"}],["path",{d:"M14 13.12c0 2.38 0 6.38-1 8.88",key:"o46ks0"}],["path",{d:"M17.29 21.02c.12-.6.43-2.3.5-3.02",key:"ptglia"}],["path",{d:"M2 12a10 10 0 0 1 18-6",key:"ydlgp0"}],["path",{d:"M2 16h.01",key:"1gqxmh"}],["path",{d:"M21.8 16c.2-2 .131-5.354 0-6",key:"drycrb"}],["path",{d:"M5 19.5C5.5 18 6 15 6 12a6 6 0 0 1 .34-2",key:"1tidbn"}],["path",{d:"M8.65 22c.21-.66.45-1.32.57-2",key:"13wd9y"}],["path",{d:"M9 6.8a6 6 0 0 1 9 5.2v2",key:"1fr1j5"}]]);var lo=O("FolderOpen",[["path",{d:"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2",key:"usdka0"}]]);var Xi=O("Hand",[["path",{d:"M18 11V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2",key:"1fvzgz"}],["path",{d:"M14 10V4a2 2 0 0 0-2-2a2 2 0 0 0-2 2v2",key:"1kc0my"}],["path",{d:"M10 10.5V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2v8",key:"10h0bg"}],["path",{d:"M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15",key:"1s1gnw"}]]);var ql=O("ImagePlus",[["path",{d:"M16 5h6",key:"1vod17"}],["path",{d:"M19 2v6",key:"4bpg5p"}],["path",{d:"M21 11.5V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7.5",key:"1ue2ih"}],["path",{d:"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21",key:"1xmnt7"}],["circle",{cx:"9",cy:"9",r:"2",key:"af1f0g"}]]);var Yi=O("Lasso",[["path",{d:"M7 22a5 5 0 0 1-2-4",key:"umushi"}],["path",{d:"M3.3 14A6.8 6.8 0 0 1 2 10c0-4.4 4.5-8 10-8s10 3.6 10 8-4.5 8-10 8a12 12 0 0 1-5-1",key:"146dds"}],["path",{d:"M5 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4z",key:"bq3ynw"}]]);var Qi=O("Maximize",[["path",{d:"M8 3H5a2 2 0 0 0-2 2v3",key:"1dcmit"}],["path",{d:"M21 8V5a2 2 0 0 0-2-2h-3",key:"1e4gt3"}],["path",{d:"M3 16v3a2 2 0 0 0 2 2h3",key:"wsl5sc"}],["path",{d:"M16 21h3a2 2 0 0 0 2-2v-3",key:"18trek"}]]);var el=O("Minus",[["path",{d:"M5 12h14",key:"1ays0h"}]]);var Zi=O("Monitor",[["rect",{width:"20",height:"14",x:"2",y:"3",rx:"2",key:"48i651"}],["line",{x1:"8",x2:"16",y1:"21",y2:"21",key:"1svkeh"}],["line",{x1:"12",x2:"12",y1:"17",y2:"21",key:"vw1qmm"}]]);var ro=O("Moon",[["path",{d:"M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z",key:"a7tn18"}]]);var Ki=O("Move",[["path",{d:"M12 2v20",key:"t6zp3m"}],["path",{d:"m15 19-3 3-3-3",key:"11eu04"}],["path",{d:"m19 9 3 3-3 3",key:"1mg7y2"}],["path",{d:"M2 12h20",key:"9i4pu4"}],["path",{d:"m5 9-3 3 3 3",key:"j64kie"}],["path",{d:"m9 5 3-3 3 3",key:"l8vdw6"}]]);var Wi=O("PaintBucket",[["path",{d:"m19 11-8-8-8.6 8.6a2 2 0 0 0 0 2.8l5.2 5.2c.8.8 2 .8 2.8 0L19 11Z",key:"irua1i"}],["path",{d:"m5 2 5 5",key:"1lls2c"}],["path",{d:"M2 13h15",key:"1hkzvu"}],["path",{d:"M22 20a2 2 0 1 1-4 0c0-1.6 1.7-2.4 2-4 .3 1.6 2 2.4 2 4Z",key:"xk76lq"}]]);var tl=O("PaintbrushVertical",[["path",{d:"M10 2v2",key:"7u0qdc"}],["path",{d:"M14 2v4",key:"qmzblu"}],["path",{d:"M17 2a1 1 0 0 1 1 1v9H6V3a1 1 0 0 1 1-1z",key:"ycvu00"}],["path",{d:"M6 12a1 1 0 0 0-1 1v1a2 2 0 0 0 2 2h2a1 1 0 0 1 1 1v2.9a2 2 0 1 0 4 0V17a1 1 0 0 1 1-1h2a2 2 0 0 0 2-2v-1a1 1 0 0 0-1-1",key:"iw4wnp"}]]);var oo=O("Paintbrush",[["path",{d:"m14.622 17.897-10.68-2.913",key:"vj2p1u"}],["path",{d:"M18.376 2.622a1 1 0 1 1 3.002 3.002L17.36 9.643a.5.5 0 0 0 0 .707l.944.944a2.41 2.41 0 0 1 0 3.408l-.944.944a.5.5 0 0 1-.707 0L8.354 7.348a.5.5 0 0 1 0-.707l.944-.944a2.41 2.41 0 0 1 3.408 0l.944.944a.5.5 0 0 0 .707 0z",key:"18tc5c"}],["path",{d:"M9 8c-1.804 2.71-3.97 3.46-6.583 3.948a.507.507 0 0 0-.302.819l7.32 8.883a1 1 0 0 0 1.185.204C12.735 20.405 16 16.792 16 15",key:"ytzfxy"}]]);var Ji=O("PenTool",[["path",{d:"M15.707 21.293a1 1 0 0 1-1.414 0l-1.586-1.586a1 1 0 0 1 0-1.414l5.586-5.586a1 1 0 0 1 1.414 0l1.586 1.586a1 1 0 0 1 0 1.414z",key:"nt11vn"}],["path",{d:"m18 13-1.375-6.874a1 1 0 0 0-.746-.776L3.235 2.028a1 1 0 0 0-1.207 1.207L5.35 15.879a1 1 0 0 0 .776.746L13 18",key:"15qc1e"}],["path",{d:"m2.3 2.3 7.286 7.286",key:"1wuzzi"}],["circle",{cx:"11",cy:"11",r:"2",key:"xmgehs"}]]);var $i=O("Pencil",[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]]);var eu=O("Pipette",[["path",{d:"m2 22 1-1h3l9-9",key:"1sre89"}],["path",{d:"M3 21v-3l9-9",key:"hpe2y6"}],["path",{d:"m15 6 3.4-3.4a2.1 2.1 0 1 1 3 3L18 9l.4.4a2.1 2.1 0 1 1-3 3l-3.8-3.8a2.1 2.1 0 1 1 3-3l.4.4Z",key:"196du1"}]]);var gn=O("Plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);var tu=O("Redo2",[["path",{d:"m15 14 5-5-5-5",key:"12vg1m"}],["path",{d:"M20 9H9.5A5.5 5.5 0 0 0 4 14.5A5.5 5.5 0 0 0 9.5 20H13",key:"6uklza"}]]);var au=O("RotateCw",[["path",{d:"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8",key:"1p45f6"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}]]);var nu=O("Ruler",[["path",{d:"M21.3 15.3a2.4 2.4 0 0 1 0 3.4l-2.6 2.6a2.4 2.4 0 0 1-3.4 0L2.7 8.7a2.41 2.41 0 0 1 0-3.4l2.6-2.6a2.41 2.41 0 0 1 3.4 0Z",key:"icamh8"}],["path",{d:"m14.5 12.5 2-2",key:"inckbg"}],["path",{d:"m11.5 9.5 2-2",key:"fmmyf7"}],["path",{d:"m8.5 6.5 2-2",key:"vc6u1g"}],["path",{d:"m17.5 15.5 2-2",key:"wo5hmg"}]]);var lu=O("Save",[["path",{d:"M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z",key:"1c8476"}],["path",{d:"M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7",key:"1ydtos"}],["path",{d:"M7 3v4a1 1 0 0 0 1 1h7",key:"t51u73"}]]);var ru=O("ScanLine",[["path",{d:"M3 7V5a2 2 0 0 1 2-2h2",key:"aa7l1z"}],["path",{d:"M17 3h2a2 2 0 0 1 2 2v2",key:"4qcy5o"}],["path",{d:"M21 17v2a2 2 0 0 1-2 2h-2",key:"6vwrx8"}],["path",{d:"M7 21H5a2 2 0 0 1-2-2v-2",key:"ioqczr"}],["path",{d:"M7 12h10",key:"b7w52i"}]]);var Vt=O("Sparkles",[["path",{d:"M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z",key:"4pj2yx"}],["path",{d:"M20 3v4",key:"1olli1"}],["path",{d:"M22 5h-4",key:"1gvqau"}],["path",{d:"M4 17v2",key:"vumght"}],["path",{d:"M5 18H3",key:"zchphs"}]]);var ou=O("Spline",[["circle",{cx:"19",cy:"5",r:"2",key:"mhkx31"}],["circle",{cx:"5",cy:"19",r:"2",key:"v8kfzx"}],["path",{d:"M5 17A12 12 0 0 1 17 5",key:"1okkup"}]]);var al=O("SquareDashed",[["path",{d:"M5 3a2 2 0 0 0-2 2",key:"y57alp"}],["path",{d:"M19 3a2 2 0 0 1 2 2",key:"18rm91"}],["path",{d:"M21 19a2 2 0 0 1-2 2",key:"1j7049"}],["path",{d:"M5 21a2 2 0 0 1-2-2",key:"sbafld"}],["path",{d:"M9 3h1",key:"1yesri"}],["path",{d:"M9 21h1",key:"15o7lz"}],["path",{d:"M14 3h1",key:"1ec4yj"}],["path",{d:"M14 21h1",key:"v9vybs"}],["path",{d:"M3 9v1",key:"1r0deq"}],["path",{d:"M21 9v1",key:"mxsmne"}],["path",{d:"M3 14v1",key:"vnatye"}],["path",{d:"M21 14v1",key:"169vum"}]]);var Hl=O("Square",[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}]]);var iu=O("Stamp",[["path",{d:"M5 22h14",key:"ehvnwv"}],["path",{d:"M19.27 13.73A2.5 2.5 0 0 0 17.5 13h-11A2.5 2.5 0 0 0 4 15.5V17a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-1.5c0-.66-.26-1.3-.73-1.77Z",key:"1sy9ra"}],["path",{d:"M14 13V8.5C14 7 15 7 15 5a3 3 0 0 0-3-3c-1.66 0-3 1-3 3s1 2 1 3.5V13",key:"cnxgux"}]]);var uu=O("Star",[["path",{d:"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z",key:"r04s7s"}]]);var io=O("Sun",[["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}],["path",{d:"M12 2v2",key:"tus03m"}],["path",{d:"M12 20v2",key:"1lh1kg"}],["path",{d:"m4.93 4.93 1.41 1.41",key:"149t6j"}],["path",{d:"m17.66 17.66 1.41 1.41",key:"ptbguv"}],["path",{d:"M2 12h2",key:"1t8f8n"}],["path",{d:"M20 12h2",key:"1q8mjw"}],["path",{d:"m6.34 17.66-1.41 1.41",key:"1m8zz5"}],["path",{d:"m19.07 4.93-1.41 1.41",key:"1shlcs"}]]);var su=O("Trash2",[["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6",key:"4alrt4"}],["path",{d:"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2",key:"v07s0e"}],["line",{x1:"10",x2:"10",y1:"11",y2:"17",key:"1uufr5"}],["line",{x1:"14",x2:"14",y1:"11",y2:"17",key:"xtxkd"}]]);var fu=O("Triangle",[["path",{d:"M13.73 4a2 2 0 0 0-3.46 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z",key:"14u9p9"}]]);var cu=O("Type",[["polyline",{points:"4 7 4 4 20 4 20 7",key:"1nosan"}],["line",{x1:"9",x2:"15",y1:"20",y2:"20",key:"swin9y"}],["line",{x1:"12",x2:"12",y1:"4",y2:"20",key:"1tx1rr"}]]);var du=O("Undo2",[["path",{d:"M9 14 4 9l5-5",key:"102s5s"}],["path",{d:"M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11",key:"f3b9sd"}]]);var xn=O("WandSparkles",[["path",{d:"m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72",key:"ul74o6"}],["path",{d:"m14 7 3 3",key:"1r5n42"}],["path",{d:"M5 6v4",key:"ilb8ba"}],["path",{d:"M19 14v4",key:"blhpug"}],["path",{d:"M10 2v2",key:"7u0qdc"}],["path",{d:"M7 8H3",key:"zfb6yr"}],["path",{d:"M21 16h-4",key:"1cnmox"}],["path",{d:"M11 3H9",key:"1obp7u"}]]);var uo=O("ZoomIn",[["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}],["line",{x1:"21",x2:"16.65",y1:"21",y2:"16.65",key:"13gj7c"}],["line",{x1:"11",x2:"11",y1:"8",y2:"14",key:"1vmskp"}],["line",{x1:"8",x2:"14",y1:"11",y2:"11",key:"durymu"}]]);var pu=O("ZoomOut",[["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}],["line",{x1:"21",x2:"16.65",y1:"21",y2:"16.65",key:"13gj7c"}],["line",{x1:"8",x2:"14",y1:"11",y2:"11",key:"durymu"}]]);var we=Y(Ce(),1),Sw=Y(um(),1),Cw=Y(sl(),1);import{t as he,subscribeLanguage as hO,getLanguage as gO}from"./photo-i18n.js";function EC(e,t){let a=t||{};return(e[e.length-1]===""?[...e,""]:e).join((a.padRight?" ":"")+","+(a.padLeft===!1?"":" ")).trim()}var UT=/^[$_\p{ID_Start}][$_\u{200C}\u{200D}\p{ID_Continue}]*$/u,qT=/^[$_\p{ID_Start}][-$_\u{200C}\u{200D}\p{ID_Continue}]*$/u,HT={};function Pf(e,t){return((t||HT).jsx?qT:UT).test(e)}var FT=/[ \t\n\f\r]/g;function Gm(e){return typeof e=="object"?e.type==="text"?DC(e.value):!1:DC(e)}function DC(e){return e.replace(FT,"")===""}var yn=class{constructor(t,a,n){this.normal=a,this.property=t,n&&(this.space=n)}};yn.prototype.normal={};yn.prototype.property={};yn.prototype.space=void 0;function jm(e,t){let a={},n={};for(let l of e)Object.assign(a,l.property),Object.assign(n,l.normal);return new yn(a,n,t)}function mu(e){return e.toLowerCase()}var dt=class{constructor(t,a){this.attribute=a,this.property=t}};dt.prototype.attribute="";dt.prototype.booleanish=!1;dt.prototype.boolean=!1;dt.prototype.commaOrSpaceSeparated=!1;dt.prototype.commaSeparated=!1;dt.prototype.defined=!1;dt.prototype.mustUseProperty=!1;dt.prototype.number=!1;dt.prototype.overloadedBoolean=!1;dt.prototype.property="";dt.prototype.spaceSeparated=!1;dt.prototype.space=void 0;var hu={};Ru(hu,{boolean:()=>te,booleanish:()=>_e,commaOrSpaceSeparated:()=>Gt,commaSeparated:()=>Ln,number:()=>B,overloadedBoolean:()=>Uf,spaceSeparated:()=>Le});var _T=0,te=Fl(),_e=Fl(),Uf=Fl(),B=Fl(),Le=Fl(),Ln=Fl(),Gt=Fl();function Fl(){return 2**++_T}var Xm=Object.keys(hu),_l=class extends dt{constructor(t,a,n,l){let r=-1;if(super(t,a),OC(this,"space",l),typeof n=="number")for(;++r4&&a.slice(0,4)==="data"&&VT.test(t)){if(t.charAt(4)==="-"){let r=t.slice(5).replace(PC,jT);n="data"+r.charAt(0).toUpperCase()+r.slice(1)}else{let r=t.slice(4);if(!PC.test(r)){let o=r.replace(NT,GT);o.charAt(0)!=="-"&&(o="-"+o),t="data"+o}}l=_l}return new l(n,t)}function GT(e){return"-"+e.toLowerCase()}function jT(e){return e.charAt(1).toUpperCase()}var UC=jm([Ym,zC,Qm,Zm,Km],"html"),Ff=jm([Ym,BC,Qm,Zm,Km],"svg");function qC(e){return e.join(" ").trim()}var $C=Y(ZC(),1);var Nf=KC("end"),so=KC("start");function KC(e){return t;function t(a){let n=a&&a.position&&a.position[e]||{};if(typeof n.line=="number"&&n.line>0&&typeof n.column=="number"&&n.column>0)return{line:n.line,column:n.column,offset:typeof n.offset=="number"&&n.offset>-1?n.offset:void 0}}}function th(e){let t=so(e),a=Nf(e);if(t&&a)return{start:t,end:a}}function nl(e){return!e||typeof e!="object"?"":"position"in e||"type"in e?WC(e.position):"start"in e||"end"in e?WC(e):"line"in e||"column"in e?ah(e):""}function ah(e){return JC(e&&e.line)+":"+JC(e&&e.column)}function WC(e){return ah(e&&e.start)+"-"+ah(e&&e.end)}function JC(e){return e&&typeof e=="number"?e:1}var Ye=class extends Error{constructor(t,a,n){super(),typeof a=="string"&&(n=a,a=void 0);let l="",r={},o=!1;if(a&&("line"in a&&"column"in a?r={place:a}:"start"in a&&"end"in a?r={place:a}:"type"in a?r={ancestors:[a],place:a.position}:r={...a}),typeof t=="string"?l=t:!r.cause&&t&&(o=!0,l=t.message,r.cause=t),!r.ruleId&&!r.source&&typeof n=="string"){let u=n.indexOf(":");u===-1?r.ruleId=n:(r.source=n.slice(0,u),r.ruleId=n.slice(u+1))}if(!r.place&&r.ancestors&&r.ancestors){let u=r.ancestors[r.ancestors.length-1];u&&(r.place=u.position)}let i=r.place&&"start"in r.place?r.place.start:r.place;this.ancestors=r.ancestors||void 0,this.cause=r.cause||void 0,this.column=i?i.column:void 0,this.fatal=void 0,this.file="",this.message=l,this.line=i?i.line:void 0,this.name=nl(r.place)||"1:1",this.place=r.place||void 0,this.reason=this.message,this.ruleId=r.ruleId||void 0,this.source=r.source||void 0,this.stack=o&&r.cause&&typeof r.cause.stack=="string"?r.cause.stack:"",this.actual=void 0,this.expected=void 0,this.note=void 0,this.url=void 0}};Ye.prototype.file="";Ye.prototype.name="";Ye.prototype.reason="";Ye.prototype.message="";Ye.prototype.stack="";Ye.prototype.column=void 0;Ye.prototype.line=void 0;Ye.prototype.ancestors=void 0;Ye.prototype.cause=void 0;Ye.prototype.fatal=void 0;Ye.prototype.place=void 0;Ye.prototype.ruleId=void 0;Ye.prototype.source=void 0;var nh={}.hasOwnProperty,xM=new Map,yM=/[A-Z]/g,LM=new Set(["table","tbody","thead","tfoot","tr"]),SM=new Set(["td","th"]),eb="https://github.com/syntax-tree/hast-util-to-jsx-runtime";function lh(e,t){if(!t||t.Fragment===void 0)throw new TypeError("Expected `Fragment` in options");let a=t.filePath||void 0,n;if(t.development){if(typeof t.jsxDEV!="function")throw new TypeError("Expected `jsxDEV` in options when `development: true`");n=TM(a,t.jsxDEV)}else{if(typeof t.jsx!="function")throw new TypeError("Expected `jsx` in production options");if(typeof t.jsxs!="function")throw new TypeError("Expected `jsxs` in production options");n=AM(a,t.jsx,t.jsxs)}let l={Fragment:t.Fragment,ancestors:[],components:t.components||{},create:n,elementAttributeNameCase:t.elementAttributeNameCase||"react",evaluater:t.createEvaluater?t.createEvaluater():void 0,filePath:a,ignoreInvalidStyle:t.ignoreInvalidStyle||!1,passKeys:t.passKeys!==!1,passNode:t.passNode||!1,schema:t.space==="svg"?Ff:UC,stylePropertyNameCase:t.stylePropertyNameCase||"dom",tableCellAlignToStyle:t.tableCellAlignToStyle!==!1},r=tb(l,e,void 0);return r&&typeof r!="string"?r:l.create(e,l.Fragment,{children:r||void 0},void 0)}function tb(e,t,a){if(t.type==="element")return CM(e,t,a);if(t.type==="mdxFlowExpression"||t.type==="mdxTextExpression")return bM(e,t);if(t.type==="mdxJsxFlowElement"||t.type==="mdxJsxTextElement")return wM(e,t,a);if(t.type==="mdxjsEsm")return vM(e,t);if(t.type==="root")return kM(e,t,a);if(t.type==="text")return IM(e,t)}function CM(e,t,a){let n=e.schema,l=n;t.tagName.toLowerCase()==="svg"&&n.space==="html"&&(l=Ff,e.schema=l),e.ancestors.push(t);let r=nb(e,t.tagName,!1),o=MM(e,t),i=oh(e,t);return LM.has(t.tagName)&&(i=i.filter(function(u){return typeof u=="string"?!Gm(u):!0})),ab(e,o,r,t),rh(o,i),e.ancestors.pop(),e.schema=n,e.create(t,r,o,a)}function bM(e,t){if(t.data&&t.data.estree&&e.evaluater){let n=t.data.estree.body[0];return n.type,e.evaluater.evaluateExpression(n.expression)}xu(e,t.position)}function vM(e,t){if(t.data&&t.data.estree&&e.evaluater)return e.evaluater.evaluateProgram(t.data.estree);xu(e,t.position)}function wM(e,t,a){let n=e.schema,l=n;t.name==="svg"&&n.space==="html"&&(l=Ff,e.schema=l),e.ancestors.push(t);let r=t.name===null?e.Fragment:nb(e,t.name,!0),o=RM(e,t),i=oh(e,t);return ab(e,o,r,t),rh(o,i),e.ancestors.pop(),e.schema=n,e.create(t,r,o,a)}function kM(e,t,a){let n={};return rh(n,oh(e,t)),e.create(t,e.Fragment,n,a)}function IM(e,t){return t.value}function ab(e,t,a,n){typeof a!="string"&&a!==e.Fragment&&e.passNode&&(t.node=n)}function rh(e,t){if(t.length>0){let a=t.length>1?t:t[0];a&&(e.children=a)}}function AM(e,t,a){return n;function n(l,r,o,i){let s=Array.isArray(o.children)?a:t;return i?s(r,o,i):s(r,o)}}function TM(e,t){return a;function a(n,l,r,o){let i=Array.isArray(r.children),u=so(n);return t(l,r,o,i,{columnNumber:u?u.column-1:void 0,fileName:e,lineNumber:u?u.line:void 0},void 0)}}function MM(e,t){let a={},n,l;for(l in t.properties)if(l!=="children"&&nh.call(t.properties,l)){let r=EM(e,l,t.properties[l]);if(r){let[o,i]=r;e.tableCellAlignToStyle&&o==="align"&&typeof i=="string"&&SM.has(t.tagName)?n=i:a[o]=i}}if(n){let r=a.style||(a.style={});r[e.stylePropertyNameCase==="css"?"text-align":"textAlign"]=n}return a}function RM(e,t){let a={};for(let n of t.attributes)if(n.type==="mdxJsxExpressionAttribute")if(n.data&&n.data.estree&&e.evaluater){let r=n.data.estree.body[0];r.type;let o=r.expression;o.type;let i=o.properties[0];i.type,Object.assign(a,e.evaluater.evaluateExpression(i.argument))}else xu(e,t.position);else{let l=n.name,r;if(n.value&&typeof n.value=="object")if(n.value.data&&n.value.data.estree&&e.evaluater){let i=n.value.data.estree.body[0];i.type,r=e.evaluater.evaluateExpression(i.expression)}else xu(e,t.position);else r=n.value===null?!0:n.value;a[l]=r}return a}function oh(e,t){let a=[],n=-1,l=e.passKeys?new Map:xM;for(;++nl?0:l+t:t=t>l?l:t,a=a>0?a:0,n.length<1e4)o=Array.from(n),o.unshift(t,a),e.splice(...o);else for(a&&e.splice(t,a);r0?(pt(e,e.length,0,t),e):t}var ib={}.hasOwnProperty;function Vf(e){let t={},a=-1;for(;++a13&&a<32||a>126&&a<160||a>55295&&a<57344||a>64975&&a<65008||(a&65535)===65535||(a&65535)===65534||a>1114111?"\uFFFD":String.fromCodePoint(a)}function St(e){return e.replace(/[\t\n\r ]+/g," ").replace(/^ | $/g,"").toLowerCase().toUpperCase()}var it=ll(/[A-Za-z]/),Ne=ll(/[\dA-Za-z]/),ub=ll(/[#-'*+\--9=?A-Z^-~]/);function Gl(e){return e!==null&&(e<32||e===127)}var Lu=ll(/\d/),sb=ll(/[\dA-Fa-f]/),fb=ll(/[!-/:-@[-`{-~]/);function _(e){return e!==null&&e<-2}function ue(e){return e!==null&&(e<0||e===32)}function Z(e){return e===-2||e===-1||e===32}var jl=ll(/\p{P}|\p{S}/u),Ha=ll(/\s/);function ll(e){return t;function t(a){return a!==null&&a>-1&&e.test(String.fromCharCode(a))}}function ga(e){let t=[],a=-1,n=0,l=0;for(;++a55295&&r<57344){let i=e.charCodeAt(a+1);r<56320&&i>56319&&i<57344?(o=String.fromCharCode(r,i),l=1):o="\uFFFD"}else o=String.fromCharCode(r);o&&(t.push(e.slice(n,a),encodeURIComponent(o)),n=a+l+1,o=""),l&&(a+=l,l=0)}return t.join("")+e.slice(n)}function W(e,t,a,n){let l=n?n-1:1/0,r=0;return o;function o(u){return Z(u)?(e.enter(a),i(u)):t(u)}function i(u){return Z(u)&&r++0&&Z(f)?(e.enter(n),u(f)):s(f)}function u(f){return Z(f)&&o=l?t(f):a(f)}}var cb={tokenize:FM};function FM(e){let t=e.attempt(this.parser.constructs.contentInitial,n,l),a;return t;function n(i){if(i===null){e.consume(i);return}return e.enter("lineEnding"),e.consume(i),e.exit("lineEnding"),W(e,t,"linePrefix")}function l(i){return e.enter("paragraph"),r(i)}function r(i){let u=e.enter("chunkText",{contentType:"text",previous:a});return a&&(a.next=u),a=u,o(i)}function o(i){if(i===null){e.exit("chunkText"),e.exit("paragraph"),e.consume(i);return}return _(i)?(e.consume(i),e.exit("chunkText"),r):(e.consume(i),o)}}var Sn=class{constructor(){this.index=new Map,this.map=[]}add(t,a,n){db(this,t,a,n,!1)}addBefore(t,a,n){db(this,t,a,n,!0)}consume(t){if(this.map.sort(function(r,o){return r[0]-o[0]}),this.map.length===0)return;let a=this.map.length,n=[];for(;a>0;)a-=1,n.push(t.slice(this.map[a][0]+this.map[a][1]),this.map[a][2]),t.length=this.map[a][0];n.push(t.slice()),t.length=0;let l=n.pop();for(;l;){for(let r of l)t.push(r);l=n.pop()}this.map.length=0,this.index.clear()}};function db(e,t,a,n,l){if(a===0&&n.length===0)return;let r=e.index.get(t);if(r){r[1]+=a,l?(n.push(...r[2]),r[2]=n):r[2].push(...n);return}let o=[t,a,n];e.map.push(o),e.index.set(t,o)}var mb={tokenize:_M},pb={tokenize:NM};function _M(e){let t=this,a=[],n=0,l,r,o;return i;function i(x){if(no))return;let k=t.events.length,I=k,D,w;for(;I--;)if(t.events[I][0]==="exit"&&t.events[I][1].type==="chunkFlow"){if(D){w=t.events[I][1].end;break}D=!0}for(m(n),b=k;bx;){let A=a[S];t.containerState=A[1],A[0].exit.call(t,e)}a.length=x}function g(){l.write([null]),r=void 0,l=void 0,t.containerState._closeFlow=void 0}}function NM(e,t,a){return W(e,e.attempt(this.parser.constructs.document,t,a),"linePrefix",this.parser.constructs.disable.null.includes("codeIndented")?void 0:4)}function co(e){if(e===null||ue(e)||Ha(e))return 1;if(jl(e))return 2}function rl(e,t,a){let n=[],l=-1;for(;++l1&&e[a][1].end.offset-e[a][1].start.offset>1?2:1,o={...e[l][1].end},i={...e[a][1].start};hb(o,-r),hb(i,r);let u={type:r>1?"strongSequence":"emphasisSequence",start:o,end:{...e[l][1].end}},s={type:r>1?"strongSequence":"emphasisSequence",start:{...e[a][1].start},end:i},f={type:r>1?"strongText":"emphasisText",start:{...e[l][1].end},end:{...e[a][1].start}},c={type:r>1?"strong":"emphasis",start:{...u.start},end:{...s.end}};e[l][1].end={...u.start},e[a][1].start={...s.end},n=[],e[l][1].end.offset-e[l][1].start.offset&&(n=Mt(n,[["enter",e[l][1],t],["exit",e[l][1],t]])),n=Mt(n,[["enter",c,t],["enter",u,t],["exit",u,t],["enter",f,t]]),n=Mt(n,rl(t.parser.constructs.insideSpan.null,e.slice(l+1,a),t)),n=Mt(n,[["exit",f,t],["enter",s,t],["exit",s,t],["exit",c,t]]);let p=0;e[a][1].end.offset-e[a][1].start.offset&&(p=2,n=Mt(n,[["enter",e[a][1],t],["exit",e[a][1],t]])),pt(e,l-1,a-l+3,n),a=l+n.length-p-2;break}}for(a=-1;++a0&&Z(b)?W(e,g,"linePrefix",r+1)(b):g(b)}function g(b){return b===null||_(b)?e.check(Cu,y,S)(b):(e.enter("codeFlowValue"),x(b))}function x(b){return b===null||_(b)?(e.exit("codeFlowValue"),g(b)):(e.consume(b),x)}function S(b){return e.exit("codeFenced"),t(b)}function A(b,k,I){let D=0;return w;function w(N){return b.enter("lineEnding"),b.consume(N),b.exit("lineEnding"),H}function H(N){return b.enter("codeFencedFence"),Z(N)?W(b,Q,"linePrefix",n.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(N):Q(N)}function Q(N){return N===i?(b.enter("codeFencedFenceSequence"),P(N)):I(N)}function P(N){return N===i?(D++,b.consume(N),P):D>=o?(b.exit("codeFencedFenceSequence"),Z(N)?W(b,F,"whitespace")(N):F(N)):I(N)}function F(N){return N===null||_(N)?(b.exit("codeFencedFence"),k(N)):I(N)}}}var bu={name:"codeIndented",tokenize:tR},eR={partial:!0,tokenize:aR};function tR(e,t,a){return n;function n(i){return e.enter("codeIndented"),ih(e,l,a,"linePrefix",4,4)(i)}function l(i){return i===null?o(i):_(i)?e.attempt(eR,l,o)(i):(e.enter("codeFlowValue"),r(i))}function r(i){return i===null||_(i)?(e.exit("codeFlowValue"),l(i)):(e.consume(i),r)}function o(i){return e.exit("codeIndented"),t(i)}}function aR(e,t,a){let n=this;return l;function l(o){return n.parser.lazy[n.now().line]?a(o):_(o)?(e.enter("lineEnding"),e.consume(o),e.exit("lineEnding"),l):ih(e,t,r,"linePrefix",4,4)(o)}function r(o){return _(o)?l(o):a(o)}}var sh={name:"codeText",previous:lR,resolve:nR,tokenize:rR};function nR(e){let t=e.length-4,a=3,n,l;if((e[a][1].type==="lineEnding"||e[a][1].type==="space")&&(e[t][1].type==="lineEnding"||e[t][1].type==="space")){for(n=a;++n=this.left.length+this.right.length)throw new RangeError("Cannot access index `"+t+"` in a splice buffer of size `"+(this.left.length+this.right.length)+"`");return tthis.left.length?this.right.slice(this.right.length-n+this.left.length,this.right.length-t+this.left.length).reverse():this.left.slice(t).concat(this.right.slice(this.right.length-n+this.left.length).reverse())}splice(t,a,n){let l=a||0;this.setCursor(Math.trunc(t));let r=this.right.splice(this.right.length-l,Number.POSITIVE_INFINITY);return n&&vu(this.left,n),r.reverse()}pop(){return this.setCursor(Number.POSITIVE_INFINITY),this.left.pop()}push(t){this.setCursor(Number.POSITIVE_INFINITY),this.left.push(t)}pushMany(t){this.setCursor(Number.POSITIVE_INFINITY),vu(this.left,t)}unshift(t){this.setCursor(0),this.right.push(t)}unshiftMany(t){this.setCursor(0),vu(this.right,t.reverse())}setCursor(t){if(!(t===this.left.length||t>this.left.length&&this.right.length===0||t<0&&this.left.length===0))if(t=4?t(o):e.interrupt(n.parser.constructs.flow,a,t)(o)}}function Wf(e,t,a,n,l,r,o,i,u){let s=u||Number.POSITIVE_INFINITY,f=0;return c;function c(m){return m===60?(e.enter(n),e.enter(l),e.enter(r),e.consume(m),e.exit(r),p):m===null||m===32||m===41||Gl(m)?a(m):(e.enter(n),e.enter(o),e.enter(i),e.enter("chunkString",{contentType:"string"}),y(m))}function p(m){return m===62?(e.enter(r),e.consume(m),e.exit(r),e.exit(l),e.exit(n),t):(e.enter(i),e.enter("chunkString",{contentType:"string"}),d(m))}function d(m){return m===62?(e.exit("chunkString"),e.exit(i),p(m)):m===null||m===60||_(m)?a(m):(e.consume(m),m===92?h:d)}function h(m){return m===60||m===62||m===92?(e.consume(m),d):d(m)}function y(m){return!f&&(m===null||m===41||ue(m))?(e.exit("chunkString"),e.exit(i),e.exit(o),e.exit(n),t(m)):f999||d===null||d===91||d===93&&!u||d===94&&!i&&"_hiddenFootnoteSupport"in o.parser.constructs?a(d):d===93?(e.exit(r),e.enter(l),e.consume(d),e.exit(l),e.exit(n),t):_(d)?(e.enter("lineEnding"),e.consume(d),e.exit("lineEnding"),f):(e.enter("chunkString",{contentType:"string"}),c(d))}function c(d){return d===null||d===91||d===93||_(d)||i++>999?(e.exit("chunkString"),f(d)):(e.consume(d),u||(u=!Z(d)),d===92?p:c)}function p(d){return d===91||d===92||d===93?(e.consume(d),i++,c):c(d)}}function $f(e,t,a,n,l,r){let o;return i;function i(p){return p===34||p===39||p===40?(e.enter(n),e.enter(l),e.consume(p),e.exit(l),o=p===40?41:p,u):a(p)}function u(p){return p===o?(e.enter(l),e.consume(p),e.exit(l),e.exit(n),t):(e.enter(r),s(p))}function s(p){return p===o?(e.exit(r),u(o)):p===null?a(p):_(p)?(e.enter("lineEnding"),e.consume(p),e.exit("lineEnding"),W(e,s,"linePrefix")):(e.enter("chunkString",{contentType:"string"}),f(p))}function f(p){return p===o||p===null||_(p)?(e.exit("chunkString"),s(p)):(e.consume(p),p===92?c:f)}function c(p){return p===o||p===92?(e.consume(p),f):f(p)}}function Xl(e,t){let a;return n;function n(l){return _(l)?(e.enter("lineEnding"),e.consume(l),e.exit("lineEnding"),a=!0,n):Z(l)?W(e,n,a?"linePrefix":"lineSuffix")(l):t(l)}}var ch={name:"definition",tokenize:dR},cR={partial:!0,tokenize:pR};function dR(e,t,a){let n=this,l;return r;function r(d){return e.enter("definition"),o(d)}function o(d){return Jf.call(n,e,i,a,"definitionLabel","definitionLabelMarker","definitionLabelString")(d)}function i(d){return l=St(n.sliceSerialize(n.events[n.events.length-1][1]).slice(1,-1)),d===58?(e.enter("definitionMarker"),e.consume(d),e.exit("definitionMarker"),u):a(d)}function u(d){return ue(d)?Xl(e,s)(d):s(d)}function s(d){return Wf(e,f,a,"definitionDestination","definitionDestinationLiteral","definitionDestinationLiteralMarker","definitionDestinationRaw","definitionDestinationString")(d)}function f(d){return e.attempt(cR,c,c)(d)}function c(d){return Z(d)?W(e,p,"whitespace")(d):p(d)}function p(d){return d===null||_(d)?(e.exit("definition"),n.parser.defined.push(l),t(d)):a(d)}}function pR(e,t,a){return n;function n(i){return ue(i)?Xl(e,l)(i):a(i)}function l(i){return $f(e,r,a,"definitionTitle","definitionTitleMarker","definitionTitleString")(i)}function r(i){return Z(i)?W(e,o,"whitespace")(i):o(i)}function o(i){return i===null||_(i)?t(i):a(i)}}var dh={name:"hardBreakEscape",tokenize:mR};function mR(e,t,a){return n;function n(r){return e.enter("hardBreakEscape"),e.consume(r),l}function l(r){return _(r)?(e.exit("hardBreakEscape"),t(r)):a(r)}}var ph={name:"headingAtx",resolve:hR,tokenize:gR};function hR(e,t){let a=e.length-2,n=3;if(e[n][1].type==="whitespace"&&(n+=2),a-2>n&&e[a][1].type==="whitespace"&&(a-=2),e[a][1].type==="atxHeadingSequence"&&(n===a-1||a-4>n&&e[a-2][1].type==="whitespace")&&(a-=n+1===a?2:4),a>n){let l={type:"atxHeadingText",start:e[n][1].start,end:e[a][1].end},r={type:"chunkText",start:e[n][1].start,end:e[a][1].end,contentType:"text"};pt(e,n,a-n+1,[["enter",l,t],["enter",r,t],["exit",r,t],["exit",l,t]])}return e}function gR(e,t,a){let n=0;return l;function l(f){return e.enter("atxHeading"),r(f)}function r(f){return e.enter("atxHeadingSequence"),o(f)}function o(f){return f===35&&n++<6?(e.consume(f),o):f===null||ue(f)?(e.exit("atxHeadingSequence"),i(f)):a(f)}function i(f){return f===35?(e.enter("atxHeadingSequence"),u(f)):f===null||_(f)?(e.exit("atxHeading"),t(f)):Z(f)?W(e,i,"whitespace")(f):(e.enter("atxHeadingText"),s(f))}function u(f){return f===35?(e.consume(f),u):(e.exit("atxHeadingSequence"),i(f))}function s(f){return f===null||f===35||ue(f)?(e.exit("atxHeadingText"),i(f)):(e.consume(f),s)}}var gb=["address","article","aside","base","basefont","blockquote","body","caption","center","col","colgroup","dd","details","dialog","dir","div","dl","dt","fieldset","figcaption","figure","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hr","html","iframe","legend","li","link","main","menu","menuitem","nav","noframes","ol","optgroup","option","p","param","search","section","summary","table","tbody","td","tfoot","th","thead","title","tr","track","ul"],mh=["pre","script","style","textarea"];var hh={concrete:!0,name:"htmlFlow",resolveTo:yR,tokenize:LR},xR={partial:!0,tokenize:SR};function yR(e){let t=e.length;for(;t--&&!(e[t][0]==="enter"&&e[t][1].type==="htmlFlow"););return t>1&&e[t-2][1].type==="linePrefix"&&(e[t][1].start=e[t-2][1].start,e[t+1][1].start=e[t-2][1].start,e.splice(t-2,2)),e}function LR(e,t,a){let n=this,l,r,o,i,u;return s;function s(C){return f(C)}function f(C){return e.enter("htmlFlow"),e.enter("htmlFlowData"),e.consume(C),c}function c(C){return C===33?(e.consume(C),p):C===47?(e.consume(C),r=!0,y):C===63?(e.consume(C),l=3,n.interrupt?t:L):it(C)?(e.consume(C),o=String.fromCharCode(C),v):a(C)}function p(C){return C===45?(e.consume(C),l=2,d):C===91?(e.consume(C),l=5,i=0,h):it(C)?(e.consume(C),l=4,n.interrupt?t:L):a(C)}function d(C){return C===45?(e.consume(C),n.interrupt?t:L):a(C)}function h(C){let de="CDATA[";return C===de.charCodeAt(i++)?(e.consume(C),i===de.length?n.interrupt?t:Q:h):a(C)}function y(C){return it(C)?(e.consume(C),o=String.fromCharCode(C),v):a(C)}function v(C){if(C===null||C===47||C===62||ue(C)){let de=C===47,Qe=o.toLowerCase();return!de&&!r&&mh.includes(Qe)?(l=1,n.interrupt?t(C):Q(C)):gb.includes(o.toLowerCase())?(l=6,de?(e.consume(C),m):n.interrupt?t(C):Q(C)):(l=7,n.interrupt&&!n.parser.lazy[n.now().line]?a(C):r?g(C):x(C))}return C===45||Ne(C)?(e.consume(C),o+=String.fromCharCode(C),v):a(C)}function m(C){return C===62?(e.consume(C),n.interrupt?t:Q):a(C)}function g(C){return Z(C)?(e.consume(C),g):w(C)}function x(C){return C===47?(e.consume(C),w):C===58||C===95||it(C)?(e.consume(C),S):Z(C)?(e.consume(C),x):w(C)}function S(C){return C===45||C===46||C===58||C===95||Ne(C)?(e.consume(C),S):A(C)}function A(C){return C===61?(e.consume(C),b):Z(C)?(e.consume(C),A):x(C)}function b(C){return C===null||C===60||C===61||C===62||C===96?a(C):C===34||C===39?(e.consume(C),u=C,k):Z(C)?(e.consume(C),b):I(C)}function k(C){return C===u?(e.consume(C),u=null,D):C===null||_(C)?a(C):(e.consume(C),k)}function I(C){return C===null||C===34||C===39||C===47||C===60||C===61||C===62||C===96||ue(C)?A(C):(e.consume(C),I)}function D(C){return C===47||C===62||Z(C)?x(C):a(C)}function w(C){return C===62?(e.consume(C),H):a(C)}function H(C){return C===null||_(C)?Q(C):Z(C)?(e.consume(C),H):a(C)}function Q(C){return C===45&&l===2?(e.consume(C),j):C===60&&l===1?(e.consume(C),J):C===62&&l===4?(e.consume(C),Se):C===63&&l===3?(e.consume(C),L):C===93&&l===5?(e.consume(C),q):_(C)&&(l===6||l===7)?(e.exit("htmlFlowData"),e.check(xR,ut,P)(C)):C===null||_(C)?(e.exit("htmlFlowData"),P(C)):(e.consume(C),Q)}function P(C){return e.check(Cu,F,ut)(C)}function F(C){return e.enter("lineEnding"),e.consume(C),e.exit("lineEnding"),N}function N(C){return C===null||_(C)?P(C):(e.enter("htmlFlowData"),Q(C))}function j(C){return C===45?(e.consume(C),L):Q(C)}function J(C){return C===47?(e.consume(C),o="",E):Q(C)}function E(C){if(C===62){let de=o.toLowerCase();return mh.includes(de)?(e.consume(C),Se):Q(C)}return it(C)&&o.length<8?(e.consume(C),o+=String.fromCharCode(C),E):Q(C)}function q(C){return C===93?(e.consume(C),L):Q(C)}function L(C){return C===62?(e.consume(C),Se):C===45&&l===2?(e.consume(C),L):Q(C)}function Se(C){return C===null||_(C)?(e.exit("htmlFlowData"),ut(C)):(e.consume(C),Se)}function ut(C){return e.exit("htmlFlow"),t(C)}}function SR(e,t,a){return n;function n(l){return e.enter("lineEnding"),e.consume(l),e.exit("lineEnding"),e.attempt(Fa,t,a)}}var gh={name:"htmlText",tokenize:CR};function CR(e,t,a){let n=this,l,r,o;return i;function i(L){return e.enter("htmlText"),e.enter("htmlTextData"),e.consume(L),u}function u(L){return L===33?(e.consume(L),s):L===47?(e.consume(L),A):L===63?(e.consume(L),x):it(L)?(e.consume(L),I):a(L)}function s(L){return L===45?(e.consume(L),f):L===91?(e.consume(L),r=0,h):it(L)?(e.consume(L),g):a(L)}function f(L){return L===45?(e.consume(L),d):a(L)}function c(L){return L===null?a(L):L===45?(e.consume(L),p):_(L)?(o=c,J(L)):(e.consume(L),c)}function p(L){return L===45?(e.consume(L),d):c(L)}function d(L){return L===62?j(L):L===45?p(L):c(L)}function h(L){let Se="CDATA[";return L===Se.charCodeAt(r++)?(e.consume(L),r===Se.length?y:h):a(L)}function y(L){return L===null?a(L):L===93?(e.consume(L),v):_(L)?(o=y,J(L)):(e.consume(L),y)}function v(L){return L===93?(e.consume(L),m):y(L)}function m(L){return L===62?j(L):L===93?(e.consume(L),m):y(L)}function g(L){return L===null||L===62?j(L):_(L)?(o=g,J(L)):(e.consume(L),g)}function x(L){return L===null?a(L):L===63?(e.consume(L),S):_(L)?(o=x,J(L)):(e.consume(L),x)}function S(L){return L===62?j(L):x(L)}function A(L){return it(L)?(e.consume(L),b):a(L)}function b(L){return L===45||Ne(L)?(e.consume(L),b):k(L)}function k(L){return _(L)?(o=k,J(L)):Z(L)?(e.consume(L),k):j(L)}function I(L){return L===45||Ne(L)?(e.consume(L),I):L===47||L===62||ue(L)?D(L):a(L)}function D(L){return L===47?(e.consume(L),j):L===58||L===95||it(L)?(e.consume(L),w):_(L)?(o=D,J(L)):Z(L)?(e.consume(L),D):j(L)}function w(L){return L===45||L===46||L===58||L===95||Ne(L)?(e.consume(L),w):H(L)}function H(L){return L===61?(e.consume(L),Q):_(L)?(o=H,J(L)):Z(L)?(e.consume(L),H):D(L)}function Q(L){return L===null||L===60||L===61||L===62||L===96?a(L):L===34||L===39?(e.consume(L),l=L,P):_(L)?(o=Q,J(L)):Z(L)?(e.consume(L),Q):(e.consume(L),F)}function P(L){return L===l?(e.consume(L),l=void 0,N):L===null?a(L):_(L)?(o=P,J(L)):(e.consume(L),P)}function F(L){return L===null||L===34||L===39||L===60||L===61||L===96?a(L):L===47||L===62||ue(L)?D(L):(e.consume(L),F)}function N(L){return L===47||L===62||ue(L)?D(L):a(L)}function j(L){return L===62?(e.consume(L),e.exit("htmlTextData"),e.exit("htmlText"),t):a(L)}function J(L){return e.exit("htmlTextData"),e.enter("lineEnding"),e.consume(L),e.exit("lineEnding"),E}function E(L){return Z(L)?W(e,q,"linePrefix",n.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(L):q(L)}function q(L){return e.enter("htmlTextData"),o(L)}}var Yl={name:"labelEnd",resolveAll:kR,resolveTo:IR,tokenize:AR},bR={tokenize:TR},vR={tokenize:MR},wR={tokenize:RR};function kR(e){let t=-1,a=[];for(;++t0&&l[l.length-1]._balanced;)l.pop();r=l[l.length-1]}return i;function i(p){return r?r._inactive?c(p):(o=n.parser.defined.includes(St(n.sliceSerialize({start:r.end,end:n.now()}))),e.enter("labelEnd"),e.enter("labelMarker"),e.consume(p),e.exit("labelMarker"),e.exit("labelEnd"),u):a(p)}function u(p){return p===40?e.attempt(bR,f,o?f:c)(p):p===91?e.attempt(vR,f,o?s:c)(p):o?f(p):c(p)}function s(p){return e.attempt(wR,f,c)(p)}function f(p){return l.pop(),t(p)}function c(p){return r._balanced=!0,a(p)}}function TR(e,t,a){return n;function n(c){return e.enter("resource"),e.enter("resourceMarker"),e.consume(c),e.exit("resourceMarker"),l}function l(c){return ue(c)?Xl(e,r)(c):r(c)}function r(c){return c===41?f(c):Wf(e,o,i,"resourceDestination","resourceDestinationLiteral","resourceDestinationLiteralMarker","resourceDestinationRaw","resourceDestinationString",32)(c)}function o(c){return ue(c)?Xl(e,u)(c):f(c)}function i(c){return a(c)}function u(c){return c===34||c===39||c===40?$f(e,s,a,"resourceTitle","resourceTitleMarker","resourceTitleString")(c):f(c)}function s(c){return ue(c)?Xl(e,f)(c):f(c)}function f(c){return c===41?(e.enter("resourceMarker"),e.consume(c),e.exit("resourceMarker"),e.exit("resource"),t):a(c)}}function MR(e,t,a){let n=this;return l;function l(i){return Jf.call(n,e,r,o,"reference","referenceMarker","referenceString")(i)}function r(i){return n.parser.defined.includes(St(n.sliceSerialize(n.events[n.events.length-1][1]).slice(1,-1)))?t(i):a(i)}function o(i){return a(i)}}function RR(e,t,a){return n;function n(r){return e.enter("reference"),e.enter("referenceMarker"),e.consume(r),e.exit("referenceMarker"),l}function l(r){return r===93?(e.enter("referenceMarker"),e.consume(r),e.exit("referenceMarker"),e.exit("reference"),t):a(r)}}var xh={name:"labelStartImage",resolveAll:Yl.resolveAll,tokenize:ER};function ER(e,t,a){let n=this,l;return r;function r(u){return e.enter("labelImage"),e.enter("labelImageMarker"),e.consume(u),e.exit("labelImageMarker"),o}function o(u){return u===91?(e.enter("labelMarker"),e.consume(u),e.exit("labelMarker"),l=e.exit("labelImage"),i):a(u)}function i(u){return u===94&&"_hiddenFootnoteSupport"in n.parser.constructs?a(u):(n._labelStarts=n._labelStarts||[],n._labelStarts.push(l),t(u))}}var yh={name:"labelStartLink",resolveAll:Yl.resolveAll,tokenize:DR};function DR(e,t,a){let n=this,l;return r;function r(i){return e.enter("labelLink"),e.enter("labelMarker"),e.consume(i),e.exit("labelMarker"),l=e.exit("labelLink"),o}function o(i){return i===94&&"_hiddenFootnoteSupport"in n.parser.constructs?a(i):(n._labelStarts=n._labelStarts||[],n._labelStarts.push(l),t(i))}}var wu={name:"lineEnding",tokenize:OR};function OR(e,t){return a;function a(n){return e.enter("lineEnding"),e.consume(n),e.exit("lineEnding"),W(e,t,"linePrefix")}}var Ql={name:"thematicBreak",tokenize:zR};function zR(e,t,a){let n=0,l;return r;function r(s){return e.enter("thematicBreak"),o(s)}function o(s){return l=s,i(s)}function i(s){return s===l?(e.enter("thematicBreakSequence"),u(s)):n>=3&&(s===null||_(s))?(e.exit("thematicBreak"),t(s)):a(s)}function u(s){return s===l?(e.consume(s),n++,u):(e.exit("thematicBreakSequence"),Z(s)?W(e,i,"whitespace")(s):i(s))}}var Ct={continuation:{tokenize:qR},exit:FR,name:"list",tokenize:UR},BR={partial:!0,tokenize:_R},PR={partial:!0,tokenize:HR};function UR(e,t,a){let n=this,l=n.events[n.events.length-1],r=l&&l[1].type==="linePrefix"?l[2].sliceSerialize(l[1],!0).length:0,o=0;return i;function i(d){let h=n.containerState.type||(d===42||d===43||d===45?"listUnordered":"listOrdered");if(h==="listUnordered"?!n.containerState.marker||d===n.containerState.marker:Lu(d)){if(n.containerState.type||(n.containerState.type=h,e.enter(h,{_container:!0})),h==="listUnordered")return e.enter("listItemPrefix"),d===42||d===45?e.check(Ql,a,s)(d):s(d);if(!n.interrupt||d===49)return e.enter("listItemPrefix"),e.enter("listItemValue"),u(d)}return a(d)}function u(d){return Lu(d)&&++o<10?(e.consume(d),u):(!n.interrupt||o<2)&&(n.containerState.marker?d===n.containerState.marker:d===41||d===46)?(e.exit("listItemValue"),s(d)):a(d)}function s(d){return e.enter("listItemMarker"),e.consume(d),e.exit("listItemMarker"),n.containerState.marker=n.containerState.marker||d,e.check(Fa,n.interrupt?a:f,e.attempt(BR,p,c))}function f(d){return n.containerState.initialBlankLine=!0,r++,p(d)}function c(d){return Z(d)?(e.enter("listItemPrefixWhitespace"),e.consume(d),e.exit("listItemPrefixWhitespace"),p):a(d)}function p(d){return n.containerState.size=r+n.sliceSerialize(e.exit("listItemPrefix"),!0).length,t(d)}}function qR(e,t,a){let n=this;return n.containerState._closeFlow=void 0,e.check(Fa,l,r);function l(i){return n.containerState.furtherBlankLines=n.containerState.furtherBlankLines||n.containerState.initialBlankLine,W(e,t,"listItemIndent",n.containerState.size+1)(i)}function r(i){return n.containerState.furtherBlankLines||!Z(i)?(n.containerState.furtherBlankLines=void 0,n.containerState.initialBlankLine=void 0,o(i)):(n.containerState.furtherBlankLines=void 0,n.containerState.initialBlankLine=void 0,e.attempt(PR,t,o)(i))}function o(i){return n.containerState._closeFlow=!0,n.interrupt=void 0,W(e,e.attempt(Ct,t,a),"linePrefix",n.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(i)}}function HR(e,t,a){let n=this;return W(e,l,"listItemIndent",n.containerState.size+1);function l(r){let o=n.events[n.events.length-1];return o&&o[1].type==="listItemIndent"&&o[2].sliceSerialize(o[1],!0).length===n.containerState.size?t(r):a(r)}}function FR(e){e.exit(this.containerState.type)}function _R(e,t,a){let n=this;return W(e,l,"listItemPrefixWhitespace",n.parser.constructs.disable.null.includes("codeIndented")?void 0:5);function l(r){let o=n.events[n.events.length-1];return!Z(r)&&o&&o[1].type==="listItemPrefixWhitespace"?t(r):a(r)}}var ec={name:"setextUnderline",resolveTo:NR,tokenize:VR};function NR(e,t){let a=new Sn,n=e.length,l,r,o;for(;n--;)if(e[n][0]==="enter"){if(e[n][1].type==="content"){l=n;break}e[n][1].type==="paragraph"&&(r=n)}else e[n][1].type==="content"&&a.add(n,1,[]),!o&&e[n][1].type==="definition"&&(o=n);let i={type:"setextHeading",start:{...e[l][1].start},end:{...e[e.length-1][1].end}};return e[r][1].type="setextHeadingText",o?(a.add(r,0,[["enter",i,t]]),a.add(o+1,0,[["exit",e[l][1],t]]),e[l][1].end={...e[o][1].end}):e[l][1]=i,a.add(e.length,0,[["exit",i,t]]),a.consume(e),e}function VR(e,t,a){let n=this,l;return r;function r(s){let f=n.events.length,c;for(;f--;)if(n.events[f][1].type!=="lineEnding"&&n.events[f][1].type!=="linePrefix"&&n.events[f][1].type!=="content"){c=n.events[f][1].type==="paragraph";break}return!n.parser.lazy[n.now().line]&&(n.interrupt||c)?(e.enter("setextHeadingLine"),l=s,o(s)):a(s)}function o(s){return e.enter("setextHeadingLineSequence"),i(s)}function i(s){return s===l?(e.consume(s),i):(e.exit("setextHeadingLineSequence"),Z(s)?W(e,u,"lineSuffix")(s):u(s))}function u(s){return s===null||_(s)?(e.exit("setextHeadingLine"),t(s)):a(s)}}var xb={tokenize:GR};function GR(e){let t=this,a=e.attempt(Fa,n,e.attempt(this.parser.constructs.flowInitial,l,W(e,e.attempt(this.parser.constructs.flow,l,e.attempt(fh,l)),"linePrefix")));return a;function n(r){if(r===null){e.consume(r);return}return e.enter("lineEndingBlank"),e.consume(r),e.exit("lineEndingBlank"),t.currentConstruct=void 0,a}function l(r){if(r===null){e.consume(r);return}return e.enter("lineEnding"),e.consume(r),e.exit("lineEnding"),t.currentConstruct=void 0,a}}var yb={resolveAll:bb()},Lb=Cb("string"),Sb=Cb("text");function Cb(e){return{resolveAll:bb(e==="text"?jR:void 0),tokenize:t};function t(a){let n=this,l=this.parser.constructs[e],r=a.attempt(l,o,i);return o;function o(f){return s(f)?r(f):i(f)}function i(f){if(f===null){a.consume(f);return}return a.enter("data"),a.consume(f),u}function u(f){return s(f)?(a.exit("data"),r(f)):(a.consume(f),u)}function s(f){if(f===null)return!0;let c=l[f],p=-1;if(c)for(;++p$R,contentInitial:()=>YR,disable:()=>eE,document:()=>XR,flow:()=>ZR,flowInitial:()=>QR,insideSpan:()=>JR,string:()=>KR,text:()=>WR});var XR={42:Ct,43:Ct,45:Ct,48:Ct,49:Ct,50:Ct,51:Ct,52:Ct,53:Ct,54:Ct,55:Ct,56:Ct,57:Ct,62:jf},YR={91:ch},QR={[-2]:bu,[-1]:bu,32:bu},ZR={35:ph,42:Ql,45:[ec,Ql],60:hh,61:ec,95:Ql,96:Qf,126:Qf},KR={38:Yf,92:Xf},WR={[-5]:wu,[-4]:wu,[-3]:wu,33:xh,38:Yf,42:Su,60:[uh,gh],91:yh,92:[dh,Xf],93:Yl,95:Su,96:sh},JR={null:[Su,yb]},$R={null:[42,95]},eE={null:[]};function vb(e,t,a){let n={_bufferIndex:-1,_index:0,line:a&&a.line||1,column:a&&a.column||1,offset:a&&a.offset||0},l={},r=[],o=[],i=[],u=!0,s={attempt:D(k),check:D(I),consume:S,enter:A,exit:b,interrupt:D(I,{interrupt:!0})},f={code:null,containerState:{},defineSkip:m,events:[],now:v,parser:e,previous:null,sliceSerialize:h,sliceStream:y,write:d},c=t.tokenize.call(f,s),p;return t.resolveAll&&r.push(t),f;function d(P){return o=Mt(o,P),g(),o[o.length-1]!==null?[]:(w(t,0),f.events=rl(r,f.events,f),f.events)}function h(P,F){return aE(y(P),F)}function y(P){return tE(o,P)}function v(){let{_bufferIndex:P,_index:F,line:N,column:j,offset:J}=n;return{_bufferIndex:P,_index:F,line:N,column:j,offset:J}}function m(P){l[P.line]=P.column,Q()}function g(){for(;n._index-1){let i=o[0];typeof i=="string"?o[0]=i.slice(n):o.shift()}r>0&&o.push(e[l].slice(0,r))}return o}function aE(e,t){let a=-1,n=[],l;for(;++a0&&l(t.beforeEnter,{...ae,sliceSerialize:T[Re][2].sliceSerialize},T[Re][1]),Ab.call(Et,T[Re][1].type)&&Et[T[Re][1].type].call({...ae,sliceSerialize:T[Re][2].sliceSerialize},T[Re][1]),T[Re][0]==="exit"&&t.afterExit.length>0&&l(t.afterExit,{...ae,sliceSerialize:T[Re][2].sliceSerialize},T[Re][1])}if(ae.tokenStack.length>0){let Et=ae.tokenStack[ae.tokenStack.length-1];(Et[1]||Ib).call(ae,void 0,Et[0])}for(U.position={start:ol(T.length>0?T[0][1].start:{line:1,column:1,offset:0}),end:ol(T.length>0?T[T.length-2][1].end:{line:1,column:1,offset:0})},Re=-1;++Re0&&(n.className=["language-"+l[0]]);let r={type:"element",tagName:"code",properties:n,children:[{type:"text",value:a}]};return t.meta&&(r.data={meta:t.meta}),e.patch(t,r),r=e.applyData(t,r),r={type:"element",tagName:"pre",properties:{},children:[r]},e.patch(t,r),r}function Db(e,t){let a={type:"element",tagName:"del",properties:{},children:e.all(t)};return e.patch(t,a),e.applyData(t,a)}function Ob(e,t){let a={type:"element",tagName:"em",properties:{},children:e.all(t)};return e.patch(t,a),e.applyData(t,a)}function zb(e,t){let a=typeof e.options.clobberPrefix=="string"?e.options.clobberPrefix:"user-content-",n=String(t.identifier).toUpperCase(),l=ga(n.toLowerCase()),r=e.footnoteOrder.indexOf(n),o,i=e.footnoteCounts.get(n);i===void 0?(i=0,e.footnoteOrder.push(n),o=e.footnoteOrder.length):o=r+1,i+=1,e.footnoteCounts.set(n,i);let u={type:"element",tagName:"a",properties:{href:"#"+a+"fn-"+l,id:a+"fnref-"+l+(i>1?"-"+i:""),dataFootnoteRef:!0,ariaDescribedBy:["footnote-label"]},children:[{type:"text",value:String(o)}]};e.patch(t,u);let s={type:"element",tagName:"sup",properties:{},children:[u]};return e.patch(t,s),e.applyData(t,s)}function Bb(e,t){let a={type:"element",tagName:"h"+t.depth,properties:{},children:e.all(t)};return e.patch(t,a),e.applyData(t,a)}function Pb(e,t){if(e.options.allowDangerousHtml){let a={type:"raw",value:t.value};return e.patch(t,a),e.applyData(t,a)}}function ac(e,t){let a=t.referenceType,n="]";if(a==="collapsed"?n+="[]":a==="full"&&(n+="["+(t.label||t.identifier)+"]"),t.type==="imageReference")return[{type:"text",value:"!["+t.alt+n}];let l=e.all(t),r=l[0];r&&r.type==="text"?r.value="["+r.value:l.unshift({type:"text",value:"["});let o=l[l.length-1];return o&&o.type==="text"?o.value+=n:l.push({type:"text",value:n}),l}function Ub(e,t){let a=String(t.identifier).toUpperCase(),n=e.definitionById.get(a);if(!n)return ac(e,t);let l={src:ga(n.url||""),alt:t.alt};n.title!==null&&n.title!==void 0&&(l.title=n.title);let r={type:"element",tagName:"img",properties:l,children:[]};return e.patch(t,r),e.applyData(t,r)}function qb(e,t){let a={src:ga(t.url)};t.alt!==null&&t.alt!==void 0&&(a.alt=t.alt),t.title!==null&&t.title!==void 0&&(a.title=t.title);let n={type:"element",tagName:"img",properties:a,children:[]};return e.patch(t,n),e.applyData(t,n)}function Hb(e,t){let a={type:"text",value:t.value.replace(/\r?\n|\r/g," ")};e.patch(t,a);let n={type:"element",tagName:"code",properties:{},children:[a]};return e.patch(t,n),e.applyData(t,n)}function Fb(e,t){let a=String(t.identifier).toUpperCase(),n=e.definitionById.get(a);if(!n)return ac(e,t);let l={href:ga(n.url||"")};n.title!==null&&n.title!==void 0&&(l.title=n.title);let r={type:"element",tagName:"a",properties:l,children:e.all(t)};return e.patch(t,r),e.applyData(t,r)}function _b(e,t){let a={href:ga(t.url)};t.title!==null&&t.title!==void 0&&(a.title=t.title);let n={type:"element",tagName:"a",properties:a,children:e.all(t)};return e.patch(t,n),e.applyData(t,n)}function Nb(e,t,a){let n=e.all(t),l=a?iE(a):Vb(t),r={},o=[];if(typeof t.checked=="boolean"){let f=n[0],c;f&&f.type==="element"&&f.tagName==="p"?c=f:(c={type:"element",tagName:"p",properties:{},children:[]},n.unshift(c)),c.children.length>0&&c.children.unshift({type:"text",value:" "}),c.children.unshift({type:"element",tagName:"input",properties:{type:"checkbox",checked:t.checked,disabled:!0},children:[]}),r.className=["task-list-item"]}let i=-1;for(;++i1}function Gb(e,t){let a={},n=e.all(t),l=-1;for(typeof t.start=="number"&&t.start!==1&&(a.start=t.start);++l0){let o={type:"element",tagName:"tbody",properties:{},children:e.wrap(a,!0)},i=so(t.children[1]),u=Nf(t.children[t.children.length-1]);i&&u&&(o.position={start:i,end:u}),l.push(o)}let r={type:"element",tagName:"table",properties:{},children:e.wrap(l,!0)};return e.patch(t,r),e.applyData(t,r)}function Zb(e,t,a){let n=a?a.children:void 0,r=(n?n.indexOf(t):1)===0?"th":"td",o=a&&a.type==="table"?a.align:void 0,i=o?o.length:t.children.length,u=-1,s=[];for(;++u0,!0),n[0]),l=n.index+n[0].length,n=a.exec(t);return r.push(Wb(t.slice(l),l>0,!1)),r.join("")}function Wb(e,t,a){let n=0,l=e.length;if(t){let r=e.codePointAt(n);for(;r===9||r===32;)n++,r=e.codePointAt(n)}if(a){let r=e.codePointAt(l-1);for(;r===9||r===32;)l--,r=e.codePointAt(l-1)}return l>n?e.slice(n,l):""}function $b(e,t){let a={type:"text",value:Jb(String(t.value))};return e.patch(t,a),e.applyData(t,a)}function ev(e,t){let a={type:"element",tagName:"hr",properties:{},children:[]};return e.patch(t,a),e.applyData(t,a)}var tv={blockquote:Mb,break:Rb,code:Eb,delete:Db,emphasis:Ob,footnoteReference:zb,heading:Bb,html:Pb,imageReference:Ub,image:qb,inlineCode:Hb,linkReference:Fb,link:_b,listItem:Nb,list:Gb,paragraph:jb,root:Xb,strong:Yb,table:Qb,tableCell:Kb,tableRow:Zb,text:$b,thematicBreak:ev,toml:nc,yaml:nc,definition:nc,footnoteDefinition:nc};function nc(){}var{defineProperty:cE}=Object,iv=typeof self=="object"?self:globalThis,av=(e,t)=>{switch(e){case"Function":case"SharedWorker":case"Worker":case"eval":case"setInterval":case"setTimeout":throw new TypeError("unable to deserialize "+e)}return new iv[e](t)},dE=(e,t)=>{let a=(l,r)=>(e.set(r,l),l),n=l=>{if(e.has(l))return e.get(l);let[r,o]=t[l];switch(r){case 0:case-1:return a(o,l);case 1:{let i=a([],l);for(let u of o)i.push(n(u));return i}case 2:{let i=a({},l);for(let[u,s]of o){let f=n(u),c=n(s);f==="__proto__"?cE(i,f,{value:c,configurable:!0,enumerable:!0,writable:!0}):i[f]=c}return i}case 3:return a(new Date(o),l);case 4:{let{source:i,flags:u}=o;return a(new RegExp(i,u),l)}case 5:{let i=a(new Map,l);for(let[u,s]of o)i.set(n(u),n(s));return i}case 6:{let i=a(new Set,l);for(let u of o)i.add(n(u));return i}case 7:{let{name:i,message:u}=o;return a(typeof iv[i]=="function"?av(i,u):new Error(u),l)}case 8:return a(BigInt(o),l);case"BigInt":return a(Object(BigInt(o)),l);case"ArrayBuffer":return a(new Uint8Array(o).buffer,o);case"DataView":{let{buffer:i}=new Uint8Array(o);return a(new DataView(i),o)}case"-0":return-0}return a(av(r,o),l)};return n},Ih=e=>dE(new Map,e)(0);var Zl="",{toString:pE}={},{keys:mE,is:hE}=Object,ku=e=>{let t=typeof e;if(t!=="object"||!e)return[0,t];let a=pE.call(e).slice(8,-1);switch(a){case"Array":return[1,Zl];case"Object":return[2,Zl];case"Date":return[3,Zl];case"RegExp":return[4,Zl];case"Map":return[5,Zl];case"Set":return[6,Zl];case"DataView":return[1,a]}return a.includes("Array")?[1,a]:e instanceof Error?[7,e.name||"Error"]:[2,a]},rc=([e,t])=>e===0&&(t==="function"||t==="symbol"),gE=(e,t,a,n)=>{let l=(o,i)=>{let u=n.push(o)-1;return a.set(i,u),u},r=o=>{if(a.has(o))return a.get(o);let[i,u]=ku(o);switch(i){case 0:{let f=o;switch(u){case"bigint":i=8,f=o.toString();break;case"number":if(!o&&hE(o,-0))return n.push(["-0"])-1;break;case"function":case"symbol":if(e)throw new TypeError("unable to serialize "+u);f=null;break;case"undefined":return l([-1],o)}return l([i,f],o)}case 1:{if(u){let p=o;return u==="DataView"?p=new Uint8Array(o.buffer):u==="ArrayBuffer"&&(p=new Uint8Array(o)),l([u,[...p]],o)}let f=[],c=l([i,f],o);for(let p of o)f.push(r(p));return c}case 2:{if(u)switch(u){case"BigInt":return l([u,o.toString()],o);case"Boolean":case"Number":case"String":return l([u,o.valueOf()],o)}if(t&&"toJSON"in o)return r(o.toJSON());let f=[],c=l([i,f],o);for(let p of mE(o))(e||!rc(ku(o[p])))&&f.push([r(p),r(o[p])]);return c}case 3:return l([i,isNaN(o.getTime())?Zl:o.toISOString()],o);case 4:{let{source:f,flags:c}=o;return l([i,{source:f,flags:c}],o)}case 5:{let f=[],c=l([i,f],o);for(let[p,d]of o)(e||!(rc(ku(p))||rc(ku(d))))&&f.push([r(p),r(d)]);return c}case 6:{let f=[],c=l([i,f],o);for(let p of o)(e||!rc(ku(p)))&&f.push(r(p));return c}}let{message:s}=o;return l([i,{name:u,message:s}],o)};return r},Ah=(e,{json:t,lossy:a}={})=>{let n=[];return gE(!(t||a),!!t,new Map,n)(e),n};var po=typeof structuredClone=="function"?(e,t)=>t&&("json"in t||"lossy"in t)?Ih(Ah(e,t)):structuredClone(e):(e,t)=>Ih(Ah(e,t));function xE(e,t){let a=[{type:"text",value:"\u21A9"}];return t>1&&a.push({type:"element",tagName:"sup",properties:{},children:[{type:"text",value:String(t)}]}),a}function yE(e,t){return"Back to reference "+(e+1)+(t>1?"-"+t:"")}function uv(e){let t=typeof e.options.clobberPrefix=="string"?e.options.clobberPrefix:"user-content-",a=e.options.footnoteBackContent||xE,n=e.options.footnoteBackLabel||yE,l=e.options.footnoteLabel||"Footnotes",r=e.options.footnoteLabelTagName||"h2",o=e.options.footnoteLabelProperties||{className:["sr-only"]},i=[],u=-1;for(;++u0&&h.push({type:"text",value:" "});let g=typeof a=="string"?a:a(u,d);typeof g=="string"&&(g={type:"text",value:g}),h.push({type:"element",tagName:"a",properties:{href:"#"+t+"fnref-"+p+(d>1?"-"+d:""),dataFootnoteBackref:"",ariaLabel:typeof n=="string"?n:n(u,d),className:["data-footnote-backref"]},children:Array.isArray(g)?g:[g]})}let v=f[f.length-1];if(v&&v.type==="element"&&v.tagName==="p"){let g=v.children[v.children.length-1];g&&g.type==="text"?g.value+=" ":v.children.push({type:"text",value:" "}),v.children.push(...h)}else f.push(...h);let m={type:"element",tagName:"li",properties:{id:t+"fn-"+p},children:e.wrap(f,!0)};e.patch(s,m),i.push(m)}if(i.length!==0)return{type:"element",tagName:"section",properties:{dataFootnotes:!0,className:["footnotes"]},children:[{type:"element",tagName:r,properties:{...po(o),id:"footnote-label"},children:[{type:"text",value:l}]},{type:"text",value:` +`},{type:"element",tagName:"ol",properties:{},children:e.wrap(i,!0)},{type:"text",value:` +`}]}}var il=(function(e){if(e==null)return bE;if(typeof e=="function")return oc(e);if(typeof e=="object")return Array.isArray(e)?LE(e):SE(e);if(typeof e=="string")return CE(e);throw new Error("Expected function, string, or object as test")});function LE(e){let t=[],a=-1;for(;++a":""))+")"})}return p;function p(){let d=sv,h,y,v;if((!t||r(u,s,f[f.length-1]||void 0))&&(d=wE(a(u,f)),d[0]===Kl))return d;if("children"in u&&u.children){let m=u;if(m.children&&d[0]!==uc)for(y=(n?m.children.length:-1)+o,v=f.concat(m);y>-1&&y0&&a.push({type:"text",value:` +`}),a}function fv(e){let t=0,a=e.charCodeAt(t);for(;a===9||a===32;)t++,a=e.charCodeAt(t);return e.slice(t)}function sc(e,t){let a=cv(e,t),n=a.one(e,void 0),l=uv(a),r=Array.isArray(n)?{type:"root",children:n}:n||{type:"root",children:[]};return l&&("children"in r,r.children.push({type:"text",value:` +`},l)),r}function fc(e,t){return e&&"run"in e?async function(a,n){let l=sc(a,{file:n,...t});await e.run(l,n)}:function(a,n){return sc(a,{file:n,...e||t})}}function Mh(e){if(e)throw e}var pc=Y(Sv(),1);function Au(e){if(typeof e!="object"||e===null)return!1;let t=Object.getPrototypeOf(e);return(t===null||t===Object.prototype||Object.getPrototypeOf(t)===null)&&!(Symbol.toStringTag in e)&&!(Symbol.iterator in e)}function Rh(){let e=[],t={run:a,use:n};return t;function a(...l){let r=-1,o=l.pop();if(typeof o!="function")throw new TypeError("Expected function as last argument, not "+o);i(null,...l);function i(u,...s){let f=e[++r],c=-1;if(u){o(u);return}for(;++co.length,u;i&&o.push(l);try{u=e.apply(this,o)}catch(s){let f=s;if(i&&a)throw f;return l(f)}i||(u&&u.then&&typeof u.then=="function"?u.then(r,l):u instanceof Error?l(u):r(u))}function l(o,...i){a||(a=!0,t(o,...i))}function r(o){l(null,o)}}var Ia={basename:RE,dirname:EE,extname:DE,join:OE,sep:"/"};function RE(e,t){if(t!==void 0&&typeof t!="string")throw new TypeError('"ext" argument must be a string');Tu(e);let a=0,n=-1,l=e.length,r;if(t===void 0||t.length===0||t.length>e.length){for(;l--;)if(e.codePointAt(l)===47){if(r){a=l+1;break}}else n<0&&(r=!0,n=l+1);return n<0?"":e.slice(a,n)}if(t===e)return"";let o=-1,i=t.length-1;for(;l--;)if(e.codePointAt(l)===47){if(r){a=l+1;break}}else o<0&&(r=!0,o=l+1),i>-1&&(e.codePointAt(l)===t.codePointAt(i--)?i<0&&(n=l):(i=-1,n=o));return a===n?n=o:n<0&&(n=e.length),e.slice(a,n)}function EE(e){if(Tu(e),e.length===0)return".";let t=-1,a=e.length,n;for(;--a;)if(e.codePointAt(a)===47){if(n){t=a;break}}else n||(n=!0);return t<0?e.codePointAt(0)===47?"/":".":t===1&&e.codePointAt(0)===47?"//":e.slice(0,t)}function DE(e){Tu(e);let t=e.length,a=-1,n=0,l=-1,r=0,o;for(;t--;){let i=e.codePointAt(t);if(i===47){if(o){n=t+1;break}continue}a<0&&(o=!0,a=t+1),i===46?l<0?l=t:r!==1&&(r=1):l>-1&&(r=-1)}return l<0||a<0||r===0||r===1&&l===a-1&&l===n+1?"":e.slice(l,a)}function OE(...e){let t=-1,a;for(;++t0&&e.codePointAt(e.length-1)===47&&(a+="/"),t?"/"+a:a}function BE(e,t){let a="",n=0,l=-1,r=0,o=-1,i,u;for(;++o<=e.length;){if(o2){if(u=a.lastIndexOf("/"),u!==a.length-1){u<0?(a="",n=0):(a=a.slice(0,u),n=a.length-1-a.lastIndexOf("/")),l=o,r=0;continue}}else if(a.length>0){a="",n=0,l=o,r=0;continue}}t&&(a=a.length>0?a+"/..":"..",n=2)}else a.length>0?a+="/"+e.slice(l+1,o):a=e.slice(l+1,o),n=o-l-1;l=o,r=0}else i===46&&r>-1?r++:r=-1}return a}function Tu(e){if(typeof e!="string")throw new TypeError("Path must be a string. Received "+JSON.stringify(e))}var bv={cwd:PE};function PE(){return"/"}function mo(e){return!!(e!==null&&typeof e=="object"&&"href"in e&&e.href&&"protocol"in e&&e.protocol&&e.auth===void 0)}function vv(e){if(typeof e=="string")e=new URL(e);else if(!mo(e)){let t=new TypeError('The "path" argument must be of type string or an instance of URL. Received `'+e+"`");throw t.code="ERR_INVALID_ARG_TYPE",t}if(e.protocol!=="file:"){let t=new TypeError("The URL must be of scheme file");throw t.code="ERR_INVALID_URL_SCHEME",t}return UE(e)}function UE(e){if(e.hostname!==""){let n=new TypeError('File URL host must be "localhost" or empty on darwin');throw n.code="ERR_INVALID_FILE_URL_HOST",n}let t=e.pathname,a=-1;for(;++a0){let[d,...h]=f,y=n[p][1];Au(y)&&Au(d)&&(d=(0,pc.default)(!0,y,d)),n[p]=[s,d,...h]}}}},qh=new Uh().freeze();function zh(e,t){if(typeof t!="function")throw new TypeError("Cannot `"+e+"` without `parser`")}function Bh(e,t){if(typeof t!="function")throw new TypeError("Cannot `"+e+"` without `compiler`")}function Ph(e,t){if(t)throw new Error("Cannot call `"+e+"` on a frozen processor.\nCreate a new processor first, by calling it: use `processor()` instead of `processor`.")}function Iv(e){if(!Au(e)||typeof e.type!="string")throw new TypeError("Expected node, got `"+e+"`")}function Av(e,t,a){if(!a)throw new Error("`"+e+"` finished async. Use `"+t+"` instead")}function dc(e){return FE(e)?e:new Jl(e)}function FE(e){return!!(e&&typeof e=="object"&&"message"in e&&"messages"in e)}function _E(e){return typeof e=="string"||NE(e)}function NE(e){return!!(e&&typeof e=="object"&&"byteLength"in e&&"byteOffset"in e)}var VE="https://github.com/remarkjs/react-markdown/blob/main/changelog.md",Tv=[],Mv={allowDangerousHtml:!0},GE=/^(https?|ircs?|mailto|xmpp)$/i,jE=[{from:"astPlugins",id:"remove-buggy-html-in-markdown-parser"},{from:"allowDangerousHtml",id:"remove-buggy-html-in-markdown-parser"},{from:"allowNode",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"allowElement"},{from:"allowedTypes",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"allowedElements"},{from:"className",id:"remove-classname"},{from:"disallowedTypes",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"disallowedElements"},{from:"escapeHtml",id:"remove-buggy-html-in-markdown-parser"},{from:"includeElementIndex",id:"#remove-includeelementindex"},{from:"includeNodeIndex",id:"change-includenodeindex-to-includeelementindex"},{from:"linkTarget",id:"remove-linktarget"},{from:"plugins",id:"change-plugins-to-remarkplugins",to:"remarkPlugins"},{from:"rawSourcePos",id:"#remove-rawsourcepos"},{from:"renderers",id:"change-renderers-to-components",to:"components"},{from:"source",id:"change-source-to-children",to:"children"},{from:"sourcePos",id:"#remove-sourcepos"},{from:"transformImageUri",id:"#add-urltransform",to:"urlTransform"},{from:"transformLinkUri",id:"#add-urltransform",to:"urlTransform"}];function Hh(e){let t=XE(e),a=YE(e);return QE(t.runSync(t.parse(a),a),e)}function XE(e){let t=e.rehypePlugins||Tv,a=e.remarkPlugins||Tv,n=e.remarkRehypeOptions?{...e.remarkRehypeOptions,...Mv}:Mv;return qh().use(tc).use(a).use(fc,n).use(t)}function YE(e){let t=e.children||"",a=new Jl;return typeof t=="string"?a.value=t:(""+t,void 0),a}function QE(e,t){let a=t.allowedElements,n=t.allowElement,l=t.components,r=t.disallowedElements,o=t.skipHtml,i=t.unwrapDisallowed,u=t.urlTransform||Ev;for(let f of jE)Object.hasOwn(t,f.from)&&(""+f.from+(f.to?"use `"+f.to+"` instead":"remove it")+VE+f.id,void 0);return a&&r&&void 0,Wl(e,s),lh(e,{Fragment:ho.Fragment,components:l,ignoreInvalidStyle:!0,jsx:ho.jsx,jsxs:ho.jsxs,passKeys:!0,passNode:!0});function s(f,c,p){if(f.type==="raw"&&p&&typeof c=="number")return o?p.children.splice(c,1):p.children[c]={type:"text",value:f.value},c;if(f.type==="element"){let d;for(d in yu)if(Object.hasOwn(yu,d)&&Object.hasOwn(f.properties,d)){let h=f.properties[d],y=yu[d];(y===null||y.includes(f.tagName))&&(f.properties[d]=u(String(h||""),d,f))}}if(f.type==="element"){let d=a?!a.includes(f.tagName):r?r.includes(f.tagName):!1;if(!d&&n&&typeof c=="number"&&(d=!n(f,c,p)),d&&p&&typeof c=="number")return i&&f.children?p.children.splice(c,1,...f.children):p.children.splice(c,1),c}}}function Ev(e){let t=e.indexOf(":"),a=e.indexOf("?"),n=e.indexOf("#"),l=e.indexOf("/");return t===-1||l!==-1&&t>l||a!==-1&&t>a||n!==-1&&t>n||GE.test(e.slice(0,t))?e:""}function Fh(e,t){let a=String(e);if(typeof t!="string")throw new TypeError("Expected character");let n=0,l=a.indexOf(t);for(;l!==-1;)n++,l=a.indexOf(t,l+t.length);return n}function _h(e){if(typeof e!="string")throw new TypeError("Expected a string");return e.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&").replace(/-/g,"\\x2d")}function Nh(e,t,a){let l=il((a||{}).ignore||[]),r=ZE(t),o=-1;for(;++o0?{type:"text",value:k}:void 0),k===!1)p.lastIndex=A+1;else{if(h!==A&&S({type:"text",value:s.value.slice(h,A)}),Array.isArray(k))for(let I of k)S(I);else k&&S(k);h=A+x[0].length,m=!0}if(!p.global)break;x=p.exec(s.value)}return m?(h?\]}]+$/.exec(e);if(!t)return[e,void 0];e=e.slice(0,t.index);let a=t[0],n=a.indexOf(")"),l=Fh(e,"("),r=Fh(e,")");for(;n!==-1&&l>r;)e+=a.slice(0,n+1),a=a.slice(n+1),n=a.indexOf(")"),r++;return[e,a]}function Dv(e,t){let a=e.input.charCodeAt(e.index-1);return(e.index===0||Ha(a)||jl(a))&&(!t||a!==47)}Ov.peek=gD;function uD(){this.buffer()}function sD(e){this.enter({type:"footnoteReference",identifier:"",label:""},e)}function fD(){this.buffer()}function cD(e){this.enter({type:"footnoteDefinition",identifier:"",label:"",children:[]},e)}function dD(e){let t=this.resume(),a=this.stack[this.stack.length-1];a.type,a.identifier=St(this.sliceSerialize(e)).toLowerCase(),a.label=t}function pD(e){this.exit(e)}function mD(e){let t=this.resume(),a=this.stack[this.stack.length-1];a.type,a.identifier=St(this.sliceSerialize(e)).toLowerCase(),a.label=t}function hD(e){this.exit(e)}function gD(){return"["}function Ov(e,t,a,n){let l=a.createTracker(n),r=l.move("[^"),o=a.enter("footnoteReference"),i=a.enter("reference");return r+=l.move(a.safe(a.associationId(e),{after:"]",before:r})),i(),o(),r+=l.move("]"),r}function Qh(){return{enter:{gfmFootnoteCallString:uD,gfmFootnoteCall:sD,gfmFootnoteDefinitionLabelString:fD,gfmFootnoteDefinition:cD},exit:{gfmFootnoteCallString:dD,gfmFootnoteCall:pD,gfmFootnoteDefinitionLabelString:mD,gfmFootnoteDefinition:hD}}}function Zh(e){let t=!1;return e&&e.firstLineBlank&&(t=!0),{handlers:{footnoteDefinition:a,footnoteReference:Ov},unsafe:[{character:"[",inConstruct:["label","phrasing","reference"]}]};function a(n,l,r,o){let i=r.createTracker(o),u=i.move("[^"),s=r.enter("footnoteDefinition"),f=r.enter("label");return u+=i.move(r.safe(r.associationId(n),{before:u,after:"]"})),f(),u+=i.move("]:"),n.children&&n.children.length>0&&(i.shift(4),u+=i.move((t?` +`:" ")+r.indentLines(r.containerFlow(n,i.current()),t?zv:xD))),s(),u}}function xD(e,t,a){return t===0?e:zv(e,t,a)}function zv(e,t,a){return(a?"":" ")+e}var yD=["autolink","destinationLiteral","destinationRaw","reference","titleQuote","titleApostrophe"];Jh.attention=CD;Jh.peek=bD;function Kh(){return{canContainEols:["delete"],enter:{strikethrough:LD},exit:{strikethrough:SD}}}function Wh(){return{handlers:{delete:Jh},unsafe:[{character:"~",inConstruct:"phrasing",notInConstruct:yD}]}}function LD(e){this.enter({type:"delete",children:[],position:void 0},e)}function SD(e){this.exit(e)}function Jh(e,t,a,n){let l=a.createTracker(n),r=a.stack.includes("strikethrough")?"~":"~~",o=a.enter("strikethrough"),i=l.move(r);return i+=a.containerPhrasing(e,{...l.current(),before:i,after:"~"}),i+=l.move(r),o(),i}function CD(){return{construct:"strikethrough",markers:["~"],sizes:[2,1]}}function bD(){return"~"}function vD(e){return e.length}function Pv(e,t){let a=t||{},n=(a.align||[]).concat(),l=a.stringLength||vD,r=[],o=[],i=[],u=[],s=0,f=-1;for(;++fs&&(s=e[f].length);++mu[m])&&(u[m]=x)}y.push(g)}o[f]=y,i[f]=v}let c=-1;if(typeof n=="object"&&"length"in n)for(;++cu[c]&&(u[c]=g),d[c]=g),p[c]=x}o.splice(1,0,p),i.splice(1,0,d),f=-1;let h=[];for(;++f "),r.shift(2);let o=a.indentLines(a.containerFlow(e,r.current()),kD);return l(),o}function kD(e,t,a){return">"+(a?"":" ")+e}function Hv(e,t){return qv(e,t.inConstruct,!0)&&!qv(e,t.notInConstruct,!1)}function qv(e,t,a){if(typeof t=="string"&&(t=[t]),!t||t.length===0)return a;let n=-1;for(;++no&&(o=r):r=1,l=n+t.length,n=a.indexOf(t,l);return o}function _v(e,t){return!!(t.options.fences===!1&&e.value&&!e.lang&&/[^\n\r ]/.test(e.value)&&!/^[\t ]*(?:[\n\r]|$)|(?:^|[\n\r])[\t ]*$/.test(e.value))}function Nv(e){let t=e.options.fence||"`";if(t!=="`"&&t!=="~")throw new Error("Cannot serialize code with `"+t+"` for `options.fence`, expected `` ` `` or `~`");return t}function Vv(e,t,a,n){let l=Nv(a),r=e.value||"";if(_v(e,a)){let c=a.enter("codeIndented"),p=a.indentLines(r,ID);return c(),p}let o=a.createTracker(n),i=l.repeat(Math.max(Fv(r,l)+1,3)),u=a.enter("codeFenced"),s=l==="`"?"GraveAccent":"Tilde",f=o.move(i);if(e.lang){let c=a.enter(`codeFencedLang${s}`);f+=o.move(a.safe(e.lang,{before:f,after:" ",encode:["`"],...o.current()})),c()}if(e.lang&&e.meta){let c=a.enter(`codeFencedMeta${s}`);f+=o.move(" "),f+=o.move(a.safe(e.meta,{before:f,after:` +`,encode:["`"],...o.current()})),c()}return f+=o.move(` +`),r&&(f+=o.move(r+` +`)),f+=o.move(i),u(),f}function ID(e,t,a){return(a?"":" ")+e}function go(e){let t=e.options.quote||'"';if(t!=='"'&&t!=="'")throw new Error("Cannot serialize title with `"+t+"` for `options.quote`, expected `\"`, or `'`");return t}function Gv(e,t,a,n){let l=go(a),r=l==='"'?"Quote":"Apostrophe",o=a.enter("definition"),i=a.enter("label"),u=a.createTracker(n),s=u.move("[");return s+=u.move(a.safe(a.associationId(e),{before:s,after:"]",...u.current()})),s+=u.move("]: "),i(),!e.url||/[\0- \u007F]/.test(e.url)?(i=a.enter("destinationLiteral"),s+=u.move("<"),s+=u.move(a.safe(e.url,{before:s,after:">",...u.current()})),s+=u.move(">")):(i=a.enter("destinationRaw"),s+=u.move(a.safe(e.url,{before:s,after:e.title?" ":` +`,...u.current()}))),i(),e.title&&(i=a.enter(`title${r}`),s+=u.move(" "+l),s+=u.move(a.safe(e.title,{before:s,after:l,...u.current()})),s+=u.move(l),i()),o(),s}function jv(e){let t=e.options.emphasis||"*";if(t!=="*"&&t!=="_")throw new Error("Cannot serialize emphasis with `"+t+"` for `options.emphasis`, expected `*`, or `_`");return t}mc.attention=AD;mc.peek=TD;function mc(e,t,a,n){let l=a.enter("phrasing"),r=a.containerPhrasing({type:"root",children:[e]},n);return l(),r}function AD(e,t){return{construct:"emphasis",markers:jv(t)==="*"?["*","_"]:["_","*"],sizes:[1]}}function TD(e,t,a){return a.options.emphasis||"*"}function Xv(e){return"&#x"+e.toString(16).toUpperCase()+";"}function Yv(e,t){let a=!1;return Wl(e,function(n){if("value"in n&&/\r?\n|\r/.test(n.value)||n.type==="break")return a=!0,Kl}),!!((!e.depth||e.depth<3)&&Vl(e)&&(t.options.setext||a))}function Qv(e,t,a,n){let l=Math.max(Math.min(6,e.depth||1),1),r=a.createTracker(n);if(Yv(e,a)){let c=a.enter("headingSetext"),p=a.enter("phrasing"),d=a.containerPhrasing(e,{...r.current(),before:` +`,after:` +`});return p(),c(),d+` +`+(l===1?"=":"-").repeat(d.length-(Math.max(d.lastIndexOf("\r"),d.lastIndexOf(` +`))+1))}let o="#".repeat(l),i=a.enter("headingAtx"),u=a.enter("phrasing");r.move(o+" ");let s=a.containerPhrasing(e,{before:"# ",after:` +`,...r.current()}),f=s.charCodeAt(0);return(f===9||f===32)&&(s=Xv(f)+s.slice(1)),s=s?o+" "+s:o,a.options.closeAtx&&(s+=" "+o),u(),i(),s}tg.peek=MD;function tg(e){return e.value||""}function MD(){return"<"}ag.peek=RD;function ag(e,t,a,n){let l=go(a),r=l==='"'?"Quote":"Apostrophe",o=a.enter("image"),i=a.enter("label"),u=a.createTracker(n),s=u.move("![");return s+=u.move(a.safe(e.alt,{before:s,after:"]",...u.current()})),s+=u.move("]("),i(),!e.url&&e.title||/[\0- \u007F]/.test(e.url)?(i=a.enter("destinationLiteral"),s+=u.move("<"),s+=u.move(a.safe(e.url,{before:s,after:">",...u.current()})),s+=u.move(">")):(i=a.enter("destinationRaw"),s+=u.move(a.safe(e.url,{before:s,after:e.title?" ":")",...u.current()}))),i(),e.title&&(i=a.enter(`title${r}`),s+=u.move(" "+l),s+=u.move(a.safe(e.title,{before:s,after:l,...u.current()})),s+=u.move(l),i()),s+=u.move(")"),o(),s}function RD(){return"!"}ng.peek=ED;function ng(e,t,a,n){let l=e.referenceType,r=a.enter("imageReference"),o=a.enter("label"),i=a.createTracker(n),u=i.move("!["),s=a.safe(e.alt,{before:u,after:"]",...i.current()});u+=i.move(s+"]["),o();let f=a.stack;a.stack=f.filter(function(p){return p!=="phrasing"}),o=a.enter("reference");let c=a.safe(a.associationId(e),{before:u,after:"]",...i.current()});return o(),a.stack=f,r(),l==="full"||!s||s!==c?u+=i.move(c+"]"):l==="shortcut"?u=u.slice(0,-1):u+=i.move("]"),u}function ED(){return"!"}lg.peek=DD;function lg(e,t,a){let n=e.value||"",l="`",r=-1;for(;new RegExp("(^|[^`])"+l+"([^`]|$)").test(n);)l+="`";for(/[^\n\r ]/.test(n)&&(/^[\n\r ]/.test(n)&&/[\n\r ]$/.test(n)||/^`|`$/.test(n))&&(n=" "+n+" ");++r\u007F]/.test(e.url))}og.peek=OD;function og(e,t,a,n){let l=go(a),r=l==='"'?"Quote":"Apostrophe",o=a.createTracker(n);if(rg(e,a)){let f=a.stack;a.stack=f.filter(function(d){return d!=="phrasing"});let c=a.enter("autolink"),p=o.move("<");return p+=o.move(a.containerPhrasing(e,{before:p,after:">",...o.current()})),p+=o.move(">"),c(),a.stack=f,p}let i=a.enter("link"),u=a.enter("label"),s=o.move("[");return s+=o.move(a.containerPhrasing(e,{before:s,after:"](",...o.current()})),s+=o.move("]("),u(),!e.url&&e.title||/[\0- \u007F]/.test(e.url)?(u=a.enter("destinationLiteral"),s+=o.move("<"),s+=o.move(a.safe(e.url,{before:s,after:">",...o.current()})),s+=o.move(">")):(u=a.enter("destinationRaw"),s+=o.move(a.safe(e.url,{before:s,after:e.title?" ":")",...o.current()}))),u(),e.title&&(u=a.enter(`title${r}`),s+=o.move(" "+l),s+=o.move(a.safe(e.title,{before:s,after:l,...o.current()})),s+=o.move(l),u()),s+=o.move(")"),i(),s}function OD(e,t,a){return rg(e,a)?"<":"["}ig.peek=zD;function ig(e,t,a,n){let l=e.referenceType,r=a.enter("linkReference"),o=a.enter("label"),i=a.createTracker(n),u=i.move("["),s=a.containerPhrasing(e,{before:u,after:"]",...i.current()});u+=i.move(s+"]["),o();let f=a.stack;a.stack=f.filter(function(p){return p!=="phrasing"}),o=a.enter("reference");let c=a.safe(a.associationId(e),{before:u,after:"]",...i.current()});return o(),a.stack=f,r(),l==="full"||!s||s!==c?u+=i.move(c+"]"):l==="shortcut"?u=u.slice(0,-1):u+=i.move("]"),u}function zD(){return"["}function xo(e){let t=e.options.bullet||"*";if(t!=="*"&&t!=="+"&&t!=="-")throw new Error("Cannot serialize items with `"+t+"` for `options.bullet`, expected `*`, `+`, or `-`");return t}function Zv(e){let t=xo(e),a=e.options.bulletOther;if(!a)return t==="*"?"-":"*";if(a!=="*"&&a!=="+"&&a!=="-")throw new Error("Cannot serialize items with `"+a+"` for `options.bulletOther`, expected `*`, `+`, or `-`");if(a===t)throw new Error("Expected `bullet` (`"+t+"`) and `bulletOther` (`"+a+"`) to be different");return a}function Kv(e){let t=e.options.bulletOrdered||".";if(t!=="."&&t!==")")throw new Error("Cannot serialize items with `"+t+"` for `options.bulletOrdered`, expected `.` or `)`");return t}function hc(e){let t=e.options.rule||"*";if(t!=="*"&&t!=="-"&&t!=="_")throw new Error("Cannot serialize rules with `"+t+"` for `options.rule`, expected `*`, `-`, or `_`");return t}function Wv(e,t,a,n){let l=a.enter("list"),r=a.bulletCurrent,o=e.ordered?Kv(a):xo(a),i=e.ordered?o==="."?")":".":Zv(a),u=t&&a.bulletLastUsed?o===a.bulletLastUsed:!1;if(!e.ordered){let f=e.children?e.children[0]:void 0;if((o==="*"||o==="-")&&f&&(!f.children||!f.children[0])&&a.stack[a.stack.length-1]==="list"&&a.stack[a.stack.length-2]==="listItem"&&a.stack[a.stack.length-3]==="list"&&a.stack[a.stack.length-4]==="listItem"&&a.indexStack[a.indexStack.length-1]===0&&a.indexStack[a.indexStack.length-2]===0&&a.indexStack[a.indexStack.length-3]===0&&(u=!0),hc(a)===o&&f){let c=-1;for(;++c-1?t.start:1)+(a.options.incrementListMarker===!1?0:t.children.indexOf(e))+r);let o=r.length+1;(l==="tab"||l==="mixed"&&(t&&t.type==="list"&&t.spread||e.spread))&&(o=Math.ceil(o/4)*4);let i=a.createTracker(n);i.move(r+" ".repeat(o-r.length)),i.shift(o);let u=a.enter("listItem"),s=a.indentLines(a.containerFlow(e,i.current()),f);return u(),s;function f(c,p,d){return p?(d?"":" ".repeat(o))+c:(d?r:r+" ".repeat(o-r.length))+c}}function ew(e,t,a,n){let l=a.enter("paragraph"),r=a.enter("phrasing"),o=a.containerPhrasing(e,n);return r(),l(),o}function tw(e,t,a,n){if(!e.children.some(function(i){return $h(i)}))return a.containerFlow(e,n);let r=a.enter("phrasing"),o=a.containerPhrasing(e,n);return r(),o}function aw(e){let t=e.options.strong||"*";if(t!=="*"&&t!=="_")throw new Error("Cannot serialize strong with `"+t+"` for `options.strong`, expected `*`, or `_`");return t}gc.attention=BD;gc.peek=PD;function gc(e,t,a,n){let l=a.enter("phrasing"),r=a.containerPhrasing({type:"root",children:[e]},n);return l(),r}function BD(e,t){return{construct:"strong",markers:aw(t)==="*"?["*","_"]:["_","*"],sizes:[2]}}function PD(e,t,a){return a.options.strong||"*"}function nw(e,t,a,n){let l=t?t.children:[],r=l.indexOf(e);return a.safe(e.value,{...n,afterNode:l[r+1],beforeNode:l[r-1]})}function lw(e){let t=e.options.ruleRepetition||3;if(t<3)throw new Error("Cannot serialize rules with repetition `"+t+"` for `options.ruleRepetition`, expected `3` or more");return t}function rw(e,t,a){let n=(hc(a)+(a.options.ruleSpaces?" ":"")).repeat(lw(a));return a.options.ruleSpaces?n.slice(0,-1):n}var Mu={blockquote:Uv,break:eg,code:Vv,definition:Gv,emphasis:mc,hardBreak:eg,heading:Qv,html:tg,image:ag,imageReference:ng,inlineCode:lg,link:og,linkReference:ig,list:Wv,listItem:$v,paragraph:ew,root:tw,strong:gc,text:nw,thematicBreak:rw};function sg(){return{enter:{table:UD,tableData:ow,tableHeader:ow,tableRow:HD},exit:{codeText:FD,table:qD,tableData:ug,tableHeader:ug,tableRow:ug}}}function UD(e){let t=e._align;this.enter({type:"table",align:t.map(function(a){return a==="none"?null:a}),children:[]},e),this.data.inTable=!0}function qD(e){this.exit(e),this.data.inTable=void 0}function HD(e){this.enter({type:"tableRow",children:[]},e)}function ug(e){this.exit(e)}function ow(e){this.enter({type:"tableCell",children:[]},e)}function FD(e){let t=this.resume();this.data.inTable&&(t=t.replace(/\\([\\|])/g,_D));let a=this.stack[this.stack.length-1];a.type,a.value=t,this.exit(e)}function _D(e,t){return t==="|"?t:e}function fg(e){let t=e||{},a=t.tableCellPadding,n=t.tablePipeAlign,l=t.stringLength,r=a?" ":"|";return{unsafe:[{character:"\r",inConstruct:"tableCell"},{character:` +`,inConstruct:"tableCell"},{atBreak:!0,character:"|",after:"[ :-]"},{character:"|",inConstruct:"tableCell"},{atBreak:!0,character:":",after:"-"},{atBreak:!0,character:"-",after:"[:|-]"}],handlers:{inlineCode:p,table:o,tableCell:u,tableRow:i}};function o(d,h,y,v){return s(f(d,y,v),d.align)}function i(d,h,y,v){let m=c(d,y,v),g=s([m]);return g.slice(0,g.indexOf(` +`))}function u(d,h,y,v){let m=y.enter("tableCell"),g=y.enter("phrasing"),x=y.containerPhrasing(d,{...v,before:r,after:r});return g(),m(),x}function s(d,h){return Pv(d,{align:h,alignDelimiters:n,padding:a,stringLength:l})}function f(d,h,y){let v=d.children,m=-1,g=[],x=h.enter("table");for(;++m0&&!a&&(e[e.length-1][1]._gfmAutolinkLiteralWalkedInto=!0),a}var eO={tokenize:iO,partial:!0};function yg(){return{document:{91:{name:"gfmFootnoteDefinition",tokenize:lO,continuation:{tokenize:rO},exit:oO}},text:{91:{name:"gfmFootnoteCall",tokenize:nO},93:{name:"gfmPotentialFootnoteCall",add:"after",tokenize:tO,resolveTo:aO}}}}function tO(e,t,a){let n=this,l=n.events.length,r=n.parser.gfmFootnotes||(n.parser.gfmFootnotes=[]),o;for(;l--;){let u=n.events[l][1];if(u.type==="labelImage"){o=u;break}if(u.type==="gfmFootnoteCall"||u.type==="labelLink"||u.type==="label"||u.type==="image"||u.type==="link")break}return i;function i(u){if(!o||!o._balanced)return a(u);let s=St(n.sliceSerialize({start:o.end,end:n.now()}));return s.codePointAt(0)!==94||!r.includes(s.slice(1))?a(u):(e.enter("gfmFootnoteCallLabelMarker"),e.consume(u),e.exit("gfmFootnoteCallLabelMarker"),t(u))}}function aO(e,t){let a=e.length,n;for(;a--;)if(e[a][1].type==="labelImage"&&e[a][0]==="enter"){n=e[a][1];break}e[a+1][1].type="data",e[a+3][1].type="gfmFootnoteCallLabelMarker";let l={type:"gfmFootnoteCall",start:Object.assign({},e[a+3][1].start),end:Object.assign({},e[e.length-1][1].end)},r={type:"gfmFootnoteCallMarker",start:Object.assign({},e[a+3][1].end),end:Object.assign({},e[a+3][1].end)};r.end.column++,r.end.offset++,r.end._bufferIndex++;let o={type:"gfmFootnoteCallString",start:Object.assign({},r.end),end:Object.assign({},e[e.length-1][1].start)},i={type:"chunkString",contentType:"string",start:Object.assign({},o.start),end:Object.assign({},o.end)},u=[e[a+1],e[a+2],["enter",l,t],e[a+3],e[a+4],["enter",r,t],["exit",r,t],["enter",o,t],["enter",i,t],["exit",i,t],["exit",o,t],e[e.length-2],e[e.length-1],["exit",l,t]];return e.splice(a,e.length-a+1,...u),e}function nO(e,t,a){let n=this,l=n.parser.gfmFootnotes||(n.parser.gfmFootnotes=[]),r=0,o;return i;function i(c){return e.enter("gfmFootnoteCall"),e.enter("gfmFootnoteCallLabelMarker"),e.consume(c),e.exit("gfmFootnoteCallLabelMarker"),u}function u(c){return c!==94?a(c):(e.enter("gfmFootnoteCallMarker"),e.consume(c),e.exit("gfmFootnoteCallMarker"),e.enter("gfmFootnoteCallString"),e.enter("chunkString").contentType="string",s)}function s(c){if(r>999||c===93&&!o||c===null||c===91||ue(c))return a(c);if(c===93){e.exit("chunkString");let p=e.exit("gfmFootnoteCallString");return l.includes(St(n.sliceSerialize(p)))?(e.enter("gfmFootnoteCallLabelMarker"),e.consume(c),e.exit("gfmFootnoteCallLabelMarker"),e.exit("gfmFootnoteCall"),t):a(c)}return ue(c)||(o=!0),r++,e.consume(c),c===92?f:s}function f(c){return c===91||c===92||c===93?(e.consume(c),r++,s):s(c)}}function lO(e,t,a){let n=this,l=n.parser.gfmFootnotes||(n.parser.gfmFootnotes=[]),r,o=0,i;return u;function u(h){return e.enter("gfmFootnoteDefinition")._container=!0,e.enter("gfmFootnoteDefinitionLabel"),e.enter("gfmFootnoteDefinitionLabelMarker"),e.consume(h),e.exit("gfmFootnoteDefinitionLabelMarker"),s}function s(h){return h===94?(e.enter("gfmFootnoteDefinitionMarker"),e.consume(h),e.exit("gfmFootnoteDefinitionMarker"),e.enter("gfmFootnoteDefinitionLabelString"),e.enter("chunkString").contentType="string",f):a(h)}function f(h){if(o>999||h===93&&!i||h===null||h===91||ue(h))return a(h);if(h===93){e.exit("chunkString");let y=e.exit("gfmFootnoteDefinitionLabelString");return r=St(n.sliceSerialize(y)),e.enter("gfmFootnoteDefinitionLabelMarker"),e.consume(h),e.exit("gfmFootnoteDefinitionLabelMarker"),e.exit("gfmFootnoteDefinitionLabel"),p}return ue(h)||(i=!0),o++,e.consume(h),h===92?c:f}function c(h){return h===91||h===92||h===93?(e.consume(h),o++,f):f(h)}function p(h){return h===58?(e.enter("definitionMarker"),e.consume(h),e.exit("definitionMarker"),l.includes(r)||l.push(r),W(e,d,"gfmFootnoteDefinitionWhitespace")):a(h)}function d(h){return t(h)}}function rO(e,t,a){return e.check(Fa,t,e.attempt(eO,t,a))}function oO(e){e.exit("gfmFootnoteDefinition")}function iO(e,t,a){let n=this;return W(e,l,"gfmFootnoteDefinitionIndent",5);function l(r){let o=n.events[n.events.length-1];return o&&o[1].type==="gfmFootnoteDefinitionIndent"&&o[2].sliceSerialize(o[1],!0).length===4?t(r):a(r)}}function Lg(e){let a=(e||{}).singleTilde,n={name:"strikethrough",tokenize:r,resolveAll:l};return a==null&&(a=!0),{text:{126:n},insideSpan:{null:[n]},attentionMarkers:{null:[126]}};function l(o,i){let u=-1;for(;++u1?u(h):(o.consume(h),c++,d);if(c<2&&!a)return u(h);let v=o.exit("strikethroughSequenceTemporary"),m=co(h);return v._open=!m||m===2&&!!y,v._close=!y||y===2&&!!m,i(h)}}}var xc=class{constructor(){this.map=[],this.index=new Map}add(t,a,n){uO(this,t,a,n)}consume(t){if(this.map.sort(function(r,o){return r[0]-o[0]}),this.map.length===0)return;let a=this.map.length,n=[];for(;a>0;)a-=1,n.push(t.slice(this.map[a][0]+this.map[a][1]),this.map[a][2]),t.length=this.map[a][0];n.push(t.slice()),t.length=0;let l=n.pop();for(;l;){for(let r of l)t.push(r);l=n.pop()}this.map.length=0,this.index.clear()}};function uO(e,t,a,n){if(a===0&&n.length===0)return;let l=e.index.get(t);if(l){l[1]+=a,l[2].push(...n);return}let r=[t,a,n];e.map.push(r),e.index.set(t,r)}function gw(e,t){let a=!1,n=[];for(;t-1;){let{type:F}=n.events[H][1];if(F==="lineEnding"||F==="linePrefix")H--;else break}let Q=H>-1?n.events[H][1].type:null,P=Q==="tableHead"||Q==="tableRow"?b:u;return P===b&&n.parser.lazy[n.now().line]?a(w):P(w)}function u(w){return e.enter("tableHead"),e.enter("tableRow"),s(w)}function s(w){return w===124||(o=!0,r+=1),f(w)}function f(w){return w===null?a(w):_(w)?r>1?(r=0,n.interrupt=!0,e.exit("tableRow"),e.enter("lineEnding"),e.consume(w),e.exit("lineEnding"),d):a(w):Z(w)?W(e,f,"whitespace")(w):(r+=1,o&&(o=!1,l+=1),w===124?(e.enter("tableCellDivider"),e.consume(w),e.exit("tableCellDivider"),o=!0,f):(e.enter("data"),c(w)))}function c(w){return w===null||w===124||ue(w)?(e.exit("data"),f(w)):(e.consume(w),w===92?p:c)}function p(w){return w===92||w===124?(e.consume(w),c):c(w)}function d(w){return n.interrupt=!1,n.parser.lazy[n.now().line]?a(w):(e.enter("tableDelimiterRow"),o=!1,Z(w)?W(e,h,"linePrefix",n.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(w):h(w))}function h(w){return w===45||w===58?v(w):w===124?(o=!0,e.enter("tableCellDivider"),e.consume(w),e.exit("tableCellDivider"),y):A(w)}function y(w){return Z(w)?W(e,v,"whitespace")(w):v(w)}function v(w){return w===58?(r+=1,o=!0,e.enter("tableDelimiterMarker"),e.consume(w),e.exit("tableDelimiterMarker"),m):w===45?(r+=1,m(w)):w===null||_(w)?S(w):A(w)}function m(w){return w===45?(e.enter("tableDelimiterFiller"),g(w)):A(w)}function g(w){return w===45?(e.consume(w),g):w===58?(o=!0,e.exit("tableDelimiterFiller"),e.enter("tableDelimiterMarker"),e.consume(w),e.exit("tableDelimiterMarker"),x):(e.exit("tableDelimiterFiller"),x(w))}function x(w){return Z(w)?W(e,S,"whitespace")(w):S(w)}function S(w){return w===124?h(w):w===null||_(w)?!o||l!==r?A(w):(e.exit("tableDelimiterRow"),e.exit("tableHead"),t(w)):A(w)}function A(w){return a(w)}function b(w){return e.enter("tableRow"),k(w)}function k(w){return w===124?(e.enter("tableCellDivider"),e.consume(w),e.exit("tableCellDivider"),k):w===null||_(w)?(e.exit("tableRow"),t(w)):Z(w)?W(e,k,"whitespace")(w):(e.enter("data"),I(w))}function I(w){return w===null||w===124||ue(w)?(e.exit("data"),k(w)):(e.consume(w),w===92?D:I)}function D(w){return w===92||w===124?(e.consume(w),I):I(w)}}function fO(e,t){let a=-1,n=!0,l=0,r=[0,0,0,0],o=[0,0,0,0],i=!1,u=0,s,f,c,p=new xc;for(;++aa[2]+1){let h=a[2]+1,y=a[3]-a[2]-1;e.add(h,y,[])}}e.add(a[3]+1,0,[["exit",c,t]])}return l!==void 0&&(r.end=Object.assign({},yo(t.events,l)),e.add(l,0,[["exit",r,t]]),r=void 0),r}function xw(e,t,a,n,l){let r=[],o=yo(t.events,a);l&&(l.end=Object.assign({},o),r.push(["exit",l,t])),n.end=Object.assign({},o),r.push(["exit",n,t]),e.add(a+1,0,r)}function yo(e,t){let a=e[t],n=a[0]==="enter"?"start":"end";return a[1][n]}var cO={name:"tasklistCheck",tokenize:dO};function Cg(){return{text:{91:cO}}}function dO(e,t,a){let n=this;return l;function l(u){return n.previous!==null||!n._gfmTasklistFirstContentOfListItem?a(u):(e.enter("taskListCheck"),e.enter("taskListCheckMarker"),e.consume(u),e.exit("taskListCheckMarker"),r)}function r(u){return ue(u)?(e.enter("taskListCheckValueUnchecked"),e.consume(u),e.exit("taskListCheckValueUnchecked"),o):u===88||u===120?(e.enter("taskListCheckValueChecked"),e.consume(u),e.exit("taskListCheckValueChecked"),o):a(u)}function o(u){return u===93?(e.enter("taskListCheckMarker"),e.consume(u),e.exit("taskListCheckMarker"),e.exit("taskListCheck"),i):a(u)}function i(u){return _(u)?t(u):Z(u)?e.check({tokenize:pO},t,a)(u):a(u)}}function pO(e,t,a){return W(e,n,"whitespace");function n(l){return l===null?a(l):t(l)}}function yw(e){return Vf([gg(),yg(),Lg(e),Sg(),Cg()])}var mO={};function Lc(e){let t=this,a=e||mO,n=t.data(),l=n.micromarkExtensions||(n.micromarkExtensions=[]),r=n.fromMarkdownExtensions||(n.fromMarkdownExtensions=[]),o=n.toMarkdownExtensions||(n.toMarkdownExtensions=[]);l.push(yw(a)),r.push(pg()),o.push(mg(a))}var ul=Y(Xe(),1);function Lw({text:e}){let t=e.replace(/]*(?:>|$)/gi,"").trim();return(0,ul.jsx)("div",{className:"photo-ai-reply",children:(0,ul.jsx)(Hh,{remarkPlugins:[Lc],skipHtml:!0,urlTransform:a=>/^https?:\/\//i.test(a)?a:"",components:{img:({alt:a})=>(0,ul.jsx)("span",{children:a}),a:({href:a,children:n})=>a?(0,ul.jsx)("a",{href:a,target:"_blank",rel:"noopener noreferrer",children:n}):(0,ul.jsx)("span",{children:n}),table:({children:a})=>(0,ul.jsx)("div",{className:"photo-ai-table",children:(0,ul.jsx)("table",{children:a})})},children:t})})}var K=Y(Xe(),1);function xO({context:e,prepare:t,showResults:a}){let n="assistant-00000000-0000-4000-8000-000000000001",l=document.createElement("div");l.id="agent-panel-root",document.body.append(l);let r=()=>{},o=u=>{};function i(){we.default.useSyncExternalStore(hO,gO);let[u,s]=we.default.useState(!1),f=we.default.useRef(0),c=we.default.useRef(Promise.resolve()),p=we.default.useRef(!1),d=we.default.useRef(""),[h,y]=we.default.useState(!1),[v,m]=we.default.useState(""),[g,x]=we.default.useState(e),[S,A]=we.default.useState(!1),[b,k]=we.default.useState(""),[I,D]=we.default.useState(""),[w,H]=we.default.useState(""),[Q,P]=we.default.useState([]),[F,N]=we.default.useState(null),[j,J]=we.default.useState(null),E=we.default.useRef(null),q=we.default.useRef(!1),L=we.default.useRef(!1),Se=we.default.useRef(void 0),ut=we.default.useRef(null),C=we.default.useRef(null),de=we.default.useRef(null),Qe=()=>window.mcode?.miniapp?.agent;we.default.useEffect(()=>{fetch("/api/recovery/"+n).then(async R=>{if(!R.ok)throw Error("load");let X=await R.json();if(f.current=X.revision,X.value){let ge=X.value;m(ge.draft),k(ge.reply),Se.current=ge.sessionId,N(ge.question||null),!ge.busy&&ge.status&&D(ge.status),ge.busy&&D("\u7ED3\u679C\u5C1A\u672A\u786E\u8BA4\uFF0C\u8BF7\u5148\u67E5\u770B\u4F1A\u8BDD\uFF0C\u4E0D\u8981\u91CD\u590D\u53D1\u9001\u3002")}d.current=JSON.stringify(X.value||{draft:"",reply:"",busy:!1,question:null,status:""}),s(!0)}).catch(()=>H(he("\u8BFB\u53D6\u4F1A\u8BDD\u5931\u8D25\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u5E94\u7528")))},[]);let aa=R=>{let X=c.current.then(async()=>{let ge=JSON.stringify(R);if(ge===d.current)return;if(p.current)throw Error(he("\u4F1A\u8BDD\u5DF2\u5728\u5176\u4ED6\u7A97\u53E3\u66F4\u65B0\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u5E94\u7528"));let Ke=await fetch("/api/recovery/"+n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({revision:f.current,value:R})});if(Ke.status===409&&(p.current=!0),!Ke.ok)throw Error(he("\u4F1A\u8BDD\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u4FDD\u7559\u5F53\u524D\u9875\u9762"));f.current=(await Ke.json()).revision,d.current=ge});return c.current=X.catch(ge=>H(ge.message)),X};we.default.useEffect(()=>{if(!u)return;let R=setTimeout(()=>void aa({draft:v,reply:b,busy:S,sessionId:Se.current,question:F,status:I}).catch(()=>{}),200);return()=>clearTimeout(R)},[u,v,b,S,F,I]),we.default.useEffect(()=>{let R=X=>{S&&(X.preventDefault(),X.returnValue="")};return window.addEventListener("beforeunload",R),()=>window.removeEventListener("beforeunload",R)},[S]);async function me(){q.current=!0,D("\u6B63\u5728\u505C\u6B62\u2026");try{L.current&&await Qe().cancel(E.current)}catch(R){H(R.message)}}r=()=>x(e()),o=R=>{R&&m(R),y(!0)},we.default.useEffect(()=>{h&&(ut.current?.focus(),a())},[h]);let Te=(R,X)=>({left:Math.max(8,Math.min(R,innerWidth-(C.current?.offsetWidth||360)-8)),top:Math.max(56,Math.min(X,innerHeight-(C.current?.offsetHeight||360)-8))});we.default.useEffect(()=>{let R=()=>J(X=>X?Te(X.left,X.top):null);return window.addEventListener("resize",R),()=>window.removeEventListener("resize",R)},[]);function bt(R){R.type==="turn.started"&&(Se.current=R.sessionId),R.type==="text.delta"&&k(X=>(X+R.text).slice(-6e4)),R.type==="message.committed"&&k(R.text),R.type==="tool.started"&&D("\u6B63\u5728\u5904\u7406\u56FE\u7247\u2026"),R.type==="permission.requested"&&P(X=>[...X.filter(ge=>ge.requestId!==R.requestId),R])}async function Ze(R){if(!u||p.current||E.current||!R&&!v.trim())return;if(!Qe()?.run){H(he("\u8BF7\u5728 MiniMax Code \u4E2D\u6253\u5F00\u6B64\u5E94\u7528\u4EE5\u4F7F\u7528 AI\u3002"));return}let X=crypto.randomUUID();E.current=X,q.current=!1,L.current=!1,A(!0),H(""),k(""),D("\u6B63\u5728\u601D\u8003\u2026");try{await aa({draft:v,reply:b,busy:!0,sessionId:Se.current,question:F});let ge=R?void 0:await t("auto",v);if(q.current){D("\u5DF2\u505C\u6B62");return}L.current=!0;let Ke=R?await Qe().answer({sessionId:Se.current,questionId:F.requestId,answers:R,requestId:X},{onEvent:bt}):await Qe().run({text:ge,sessionId:Se.current,requestId:X},{onEvent:bt});Se.current=Ke.sessionId,N(Ke.pendingQuestion||null),Ke.text&&k(Ke.text),Ke.status==="error"&&H(Ke.error?.message||he("AI \u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002")),D(Ke.status==="aborted"?"\u5DF2\u505C\u6B62":Ke.pendingQuestion?"\u8BF7\u8865\u5145\u4FE1\u606F":""),Ke.status==="finished"&&!R&&m(""),await a()}catch(ge){let Ke=["result_unknown","AGENT_OUTCOME_UNKNOWN"].includes(ge.message);D(Ke?"\u7ED3\u679C\u5C1A\u672A\u786E\u8BA4\uFF0C\u8BF7\u5148\u67E5\u770B\u4F1A\u8BDD\uFF0C\u4E0D\u8981\u91CD\u590D\u53D1\u9001\u3002":""),H(Ke?"":he({runtime_unavailable:"AI \u8FDE\u63A5\u6682\u4E0D\u53EF\u7528\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u5E94\u7528\u540E\u518D\u8BD5\u3002",session_not_found:"\u8FD9\u6BB5\u4F1A\u8BDD\u5DF2\u4E0D\u53EF\u7528\uFF0C\u8BF7\u65B0\u5EFA\u5BF9\u8BDD\u3002",busy:"AI \u8FD8\u5728\u5904\u7406\u4E0A\u4E00\u4E2A\u8BF7\u6C42\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002",not_permitted:"\u5F53\u524D\u5E94\u7528\u65E0\u6CD5\u4F7F\u7528 AI\uFF0C\u8BF7\u68C0\u67E5\u5E94\u7528\u6743\u9650\u3002"}[ge.message]||"AI \u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002"))}finally{E.current=null,L.current=!1,A(!1)}}async function vt(R,X){try{await Qe().reply({sessionId:R.sessionId,requestId:R.requestId,decision:X}),P(ge=>ge.filter(Ke=>Ke.requestId!==R.requestId))}catch(ge){H(ge.message)}}return h?(0,K.jsxs)("section",{ref:C,className:"agent-panel","aria-label":he("AI \u4FEE\u56FE\u52A9\u624B"),style:j?{...j,right:"auto",bottom:"auto"}:void 0,onKeyDown:R=>{R.key==="Escape"&&(R.stopPropagation(),y(!1))},children:[(0,K.jsxs)("div",{className:"agent-panel-heading",onPointerDown:R=>{if(R.button!==0||R.target.closest("button"))return;let X=C.current.getBoundingClientRect();de.current={x:R.clientX,y:R.clientY,left:X.left,top:X.top},R.currentTarget.setPointerCapture(R.pointerId)},onPointerMove:R=>{let X=de.current;X&&J(Te(X.left+R.clientX-X.x,X.top+R.clientY-X.y))},onPointerUp:()=>de.current=null,onPointerCancel:()=>de.current=null,onLostPointerCapture:()=>de.current=null,children:[(0,K.jsxs)("span",{children:[(0,K.jsx)(Vt,{size:16}),(0,K.jsx)("strong",{children:he("AI \u52A9\u624B")})]}),(0,K.jsx)(Ue,{variant:"ghost",size:"icon-sm",disabled:S||!u||Q.length>0,"aria-label":he("\u65B0\u5EFA\u5BF9\u8BDD"),title:he("\u65B0\u5EFA\u5BF9\u8BDD"),onClick:()=>{Se.current=void 0,k(""),N(null),P([]),D(""),H("")},children:(0,K.jsx)(gn,{})}),(0,K.jsx)(Ue,{variant:"ghost",size:"icon-sm","aria-label":he("\u6536\u8D77 AI \u52A9\u624B"),onClick:()=>y(!1),children:(0,K.jsx)(el,{})})]}),(0,K.jsx)("p",{className:"agent-context",children:g.name?he("\u5F53\u524D\u5DE5\u7A0B \xB7 {name}",{name:g.name}):he("\u63CF\u8FF0\u60F3\u6CD5\uFF0C\u6216\u5148\u6253\u5F00\u4E00\u5F20\u56FE\u7247")}),b&&(0,K.jsx)(Lw,{text:b}),I&&(0,K.jsx)("p",{role:"status",className:"agent-feedback",children:he(I)}),w&&(0,K.jsx)("p",{role:"alert",className:"agent-feedback error",children:w}),Q.map(R=>(0,K.jsxs)("div",{className:"photo-ai-approval",children:[(0,K.jsx)("strong",{children:he("\u9700\u8981\u4F60\u7684\u786E\u8BA4")}),(0,K.jsx)("p",{children:R.reason}),(0,K.jsxs)("details",{children:[(0,K.jsx)("summary",{children:R.toolName}),(0,K.jsx)("pre",{children:R.toolInput})]}),(0,K.jsx)(Ue,{onClick:()=>void vt(R,"allowOnce"),children:he("\u5141\u8BB8\u672C\u6B21")}),(0,K.jsx)(Ue,{variant:"outline",onClick:()=>void vt(R,"deny"),children:he("\u62D2\u7EDD")})]},R.requestId)),F&&!S&&(0,K.jsxs)("form",{onSubmit:R=>{R.preventDefault();let X=new FormData(R.currentTarget);Ze(F.request.steps.map(ge=>({stepId:ge.id,selectedOptionIds:X.getAll("option-"+ge.id),selectedOther:!!String(X.get("other-"+ge.id)||"").trim(),otherText:String(X.get("other-"+ge.id)||"")})))},children:[(0,K.jsx)("strong",{children:F.request.title||he("\u8BF7\u8865\u5145\u4FE1\u606F")}),F.request.modePayload&&(0,K.jsx)("pre",{children:JSON.stringify(F.request.modePayload,null,2)}),F.request.steps.map(R=>(0,K.jsxs)("fieldset",{children:[(0,K.jsx)("legend",{children:R.question}),(0,K.jsx)("p",{children:R.description}),R.options.map(X=>(0,K.jsxs)("label",{className:"photo-ai-option",children:[(0,K.jsx)("input",{type:R.selectionMode==="multiple"?"checkbox":"radio",name:"option-"+R.id,value:X.id}),X.label,X.description&&(0,K.jsx)("small",{children:X.description})]},X.id)),(0,K.jsx)("input",{name:"other-"+R.id,"aria-label":R.question+" \xB7 "+he("\u8865\u5145\u8BF4\u660E"),placeholder:he("\u8865\u5145\u8BF4\u660E")})]},R.id)),(0,K.jsx)(Ue,{type:"submit",children:he("\u7EE7\u7EED")})]},F.requestId),!F&&(0,K.jsxs)("form",{onSubmit:R=>{R.preventDefault(),Ze()},children:[!v&&!S&&(0,K.jsx)("div",{className:"agent-suggestions",children:[["\u751F\u6210\u6D77\u62A5","\u5E2E\u6211\u8BBE\u8BA1\u4E00\u5F20\u5496\u5561\u6D77\u62A5\uFF0C\u5976\u6CB9\u8272\u80CC\u666F\uFF0C\u6807\u9898 COFFEE BREAK\u3002"],["\u6539\u5584\u7167\u7247","\u8BF7\u5148\u8BA9\u6211\u9009\u62E9\u4E00\u5F20\u7167\u7247\uFF0C\u518D\u6539\u5584\u66DD\u5149\u548C\u8272\u5F69\uFF0C\u4FDD\u7559\u81EA\u7136\u7EC6\u8282\u3002"]].map(([R,X])=>(0,K.jsx)(Ue,{type:"button",variant:"outline",size:"sm",onClick:()=>m(he(X)),children:he(R)},R))}),(0,K.jsx)("textarea",{ref:ut,rows:3,maxLength:8e3,"aria-label":he("AI \u4FEE\u56FE\u9700\u6C42"),placeholder:he("\u63CF\u8FF0\u4F60\u60F3\u505A\u7684\u56FE\u7247\uFF0C\u6216\u5148\u6253\u5F00\u4E00\u5F20\u7167\u7247\u2026"),value:v,disabled:S||!u,onChange:R=>m(R.target.value),onKeyDown:R=>{R.key==="Enter"&&(R.ctrlKey||R.metaKey)&&!R.nativeEvent.isComposing&&(R.preventDefault(),Ze())}}),(0,K.jsxs)("div",{className:"agent-send-row",children:[(0,K.jsx)("span",{children:"Ctrl / \u2318 + Enter"}),S?(0,K.jsxs)(Ue,{type:"button",variant:"outline",onClick:()=>void me(),children:[(0,K.jsx)(Hl,{size:14}),he("\u505C\u6B62")]}):(0,K.jsxs)(Ue,{type:"submit",disabled:!u||p.current||!v.trim(),children:[(0,K.jsx)(hn,{size:16}),he("\u53D1\u9001")]})]})]}),F&&S&&(0,K.jsx)(Ue,{onClick:()=>void me(),children:he("\u505C\u6B62")}),Se.current&&(0,K.jsx)(Ue,{variant:"ghost",size:"sm",onClick:()=>void Qe().open(Se.current).catch(R=>H(R.message)),children:he("\u67E5\u770B\u5B8C\u6574\u4F1A\u8BDD")}),(0,K.jsxs)("details",{className:"agent-results-area photo-ai-results",open:!0,hidden:!0,children:[(0,K.jsx)("summary",{children:he("AI \u8FD4\u56DE\u7684\u56FE\u7247")}),(0,K.jsx)("div",{id:"result-list"})]})]}):(0,K.jsxs)(Ue,{className:"agent-launcher","aria-label":he("\u6253\u5F00 AI \u52A9\u624B"),"aria-expanded":!1,onClick:()=>y(!0),children:[(0,K.jsx)(Vt,{size:16}),he(S?"\u6B63\u5728\u5904\u7406\u56FE\u7247\u2026":"AI \u52A9\u624B")]})}return(0,Cw.flushSync)(()=>(0,Sw.createRoot)(l).render((0,K.jsx)(i,{}))),{refresh:()=>r(),compose:u=>o(u),open:()=>o("")}}var z=Y(Xe(),1),yO={move:Ki,marquee:al,ellipseSelect:Hi,polyLasso:ou,lasso:Yi,wand:xn,crop:Ni,brush:oo,pencil:$i,colorReplace:tl,magicEraser:xn,backgroundEraser:ru,eraser:Gi,fill:Wi,gradient:Ui,clone:iu,heal:Pi,blur:Vi,sharpen:fu,smudge:ji,dodge:io,burn:ro,sponge:_i,rect:Hl,ellipse:Fi,line:el,star:uu,text:cu,pen:Ji,eyedropper:eu,ruler:nu,hand:Xi,rotateView:au,zoom:uo},LO=[7,8,8,6,5];function Z8({context:e,submit:t,dock:a=!1,showResults:n=()=>{}}){let l=document.createElement("div");l.id="agent-panel-root",document.body.append(l);let r=()=>{},o=()=>{},i=s=>{};function u(){let s=Ve.default.useSyncExternalStore(vg,wg),[f,c]=Ve.default.useState(!a),[p,d]=Ve.default.useState(null),h=Ve.default.useRef(null),y=Ve.default.useRef(null),v=(q,L)=>({x:Math.max(8,Math.min(q,window.innerWidth-(h.current?.offsetWidth||360)-8)),y:Math.max(56,Math.min(L,window.innerHeight-(h.current?.offsetHeight||260)-8))});Ve.default.useEffect(()=>{if(!a)return;let q=()=>d(L=>L?v(L.x,L.y):null);return window.addEventListener("resize",q),()=>window.removeEventListener("resize",q)},[]),Ve.default.useEffect(()=>{a&&f&&n()},[f,s]);let m=()=>{c(!1),requestAnimationFrame(()=>l.querySelector("button")?.focus())},[g,x]=Ve.default.useState(e),[S,A]=Ve.default.useState(a?"auto":"workbench"),[b,k]=Ve.default.useState(""),[I,D]=Ve.default.useState(!1),[w,H]=Ve.default.useState(""),[Q,P]=Ve.default.useState(""),[F,N]=Ve.default.useState(!1),j=Ve.default.useRef(null),J=Ve.default.useRef(!1);r=()=>{x(e()),c(!0),requestAnimationFrame(()=>j.current?.focus())},i=q=>{k(q),H(""),P(""),r()},o=()=>x(e());async function E(q){if(q.preventDefault(),!(J.current||!b.trim())){J.current=!0,D(!0),N(!1),H(""),P("");try{let L=await t(S,b);L.delivered?H("\u5DF2\u653E\u5165\u4E3B\u804A\u5929\u8F93\u5165\u6846\uFF0C\u8BF7\u5728\u90A3\u91CC\u70B9\u51FB\u53D1\u9001\u3002"):(P(L.text),H("\u9700\u6C42\u5DF2\u51C6\u5907\u597D\uFF0C\u70B9\u51FB\u4E0B\u65B9\u590D\u5236\uFF0C\u518D\u5230 MiniMax Code \u804A\u5929\u4E2D\u7C98\u8D34\u53D1\u9001\u3002"))}catch(L){N(!0),H(L.message)}finally{J.current=!1,D(!1)}}}return f?(0,z.jsxs)("section",{ref:h,style:a&&p?{left:p.x,top:p.y,bottom:"auto",transform:"none"}:void 0,className:"agent-panel","aria-label":$("AI \u4FEE\u56FE\u52A9\u624B"),onKeyDown:q=>{q.key==="Escape"&&(q.stopPropagation(),m())},children:[(0,z.jsxs)("div",{className:"agent-panel-heading",onPointerDown:q=>{if(!a||q.button!==0||q.target.closest("button"))return;let L=h.current.getBoundingClientRect();y.current={x:q.clientX,y:q.clientY,left:L.left,top:L.top},q.currentTarget.setPointerCapture(q.pointerId)},onPointerMove:q=>{if(y.current){let L=y.current;d(v(L.left+q.clientX-L.x,L.top+q.clientY-L.y))}},onPointerUp:q=>{y.current=null,q.currentTarget.hasPointerCapture(q.pointerId)&&q.currentTarget.releasePointerCapture(q.pointerId)},onPointerCancel:()=>{y.current=null},onLostPointerCapture:()=>{y.current=null},children:[(0,z.jsxs)("span",{children:[(0,z.jsx)(Vt,{size:16,"aria-hidden":"true"}),(0,z.jsx)("strong",{children:$("AI \u52A9\u624B")})]}),(0,z.jsx)(Ue,{variant:"ghost",size:"icon-sm","aria-label":$("\u6536\u8D77 AI \u52A9\u624B"),"aria-expanded":!0,onClick:m,children:(0,z.jsx)(el,{"aria-hidden":"true"})})]}),(0,z.jsx)("p",{className:"agent-context",title:g.name||$("\u8FD8\u6CA1\u6709\u6253\u5F00\u56FE\u7247"),children:g.name?$("\u5F53\u524D\u5DE5\u7A0B \xB7 {name}",{name:g.name}):$("\u63CF\u8FF0\u60F3\u6CD5\uFF0C\u6216\u5148\u6253\u5F00\u4E00\u5F20\u56FE\u7247")}),(0,z.jsxs)("form",{onSubmit:E,children:[!a&&(0,z.jsxs)("details",{className:"agent-options",open:!0,children:[(0,z.jsx)("summary",{children:$("\u9AD8\u7EA7\u9009\u9879")}),(0,z.jsxs)("label",{className:"agent-mode",children:[$("\u4EFB\u52A1"),(0,z.jsxs)("select",{"aria-label":$("AI \u4EFB\u52A1\u7C7B\u578B"),value:S,disabled:I,onChange:q=>{A(q.target.value),P(""),H("")},children:[a&&(0,z.jsx)("option",{value:"auto",children:$("\u81EA\u52A8\u9009\u62E9")}),(0,z.jsx)("option",{value:"workbench",children:$("\u7F16\u8F91\u5DE5\u7A0B")}),(0,z.jsx)("option",{value:"generate",children:$("\u751F\u6210\u56FE\u7247")}),(0,z.jsx)("option",{value:"edit",disabled:!g.name,children:$("\u4FEE\u6539\u56FE\u7247")})]})]})]}),a&&!b&&(0,z.jsx)("div",{className:"agent-suggestions",children:[["\u751F\u6210\u6D77\u62A5","\u5E2E\u6211\u8BBE\u8BA1\u4E00\u5F20\u5496\u5561\u6D77\u62A5\uFF0C\u5976\u6CB9\u8272\u80CC\u666F\uFF0C\u6807\u9898 COFFEE BREAK\u3002"],["\u6539\u5584\u7167\u7247","\u8BF7\u5148\u8BA9\u6211\u9009\u62E9\u4E00\u5F20\u7167\u7247\uFF0C\u518D\u6539\u5584\u66DD\u5149\u548C\u8272\u5F69\uFF0C\u4FDD\u7559\u81EA\u7136\u7EC6\u8282\u3002"]].map(([q,L])=>(0,z.jsx)(Ue,{type:"button",size:"sm",variant:"outline",onClick:()=>i($(L)),children:$(q)},q))}),(0,z.jsx)("textarea",{ref:j,"aria-label":$("AI \u4FEE\u56FE\u9700\u6C42"),placeholder:$(g.name?"\u60F3\u600E\u4E48\u6539\uFF1F\u6BD4\u5982\uFF1A\u80CC\u666F\u8C03\u6696\uFF0C\u52A0\u4E00\u4E2A\u767D\u8272\u6807\u9898\u2026":"\u63CF\u8FF0\u4F60\u60F3\u505A\u7684\u56FE\u7247\uFF0C\u6216\u5148\u6253\u5F00\u4E00\u5F20\u7167\u7247\u2026"),rows:3,maxLength:8e3,value:b,disabled:I,onChange:q=>{k(q.target.value),P(""),H("")},onKeyDown:q=>{q.key==="Enter"&&(q.metaKey||q.ctrlKey)&&!q.nativeEvent.isComposing&&(q.preventDefault(),E(q))}}),(0,z.jsxs)("div",{className:"agent-send-row",children:[(0,z.jsx)("span",{children:$("Ctrl / \u2318 + Enter")}),(0,z.jsxs)(Ue,{type:"submit",size:"sm",disabled:!b.trim()||I,children:[(0,z.jsx)(hn,{"aria-hidden":"true"}),I?$("\u6B63\u5728\u51C6\u5907\u2026"):g.supported?$("\u5728 MiniMax Code \u4E2D\u7EE7\u7EED"):$("\u51C6\u5907\u9700\u6C42")]})]})]}),w&&(0,z.jsx)("p",{className:F?"agent-feedback error":"agent-feedback",role:F?"alert":"status",children:$(w)}),Q&&(0,z.jsxs)("div",{className:"agent-copy",children:[(0,z.jsxs)("details",{className:"agent-copy-details",children:[(0,z.jsx)("summary",{children:$("\u67E5\u770B\u5B8C\u6574\u9700\u6C42")}),(0,z.jsx)("textarea",{"aria-label":$("\u7ED9 Agent \u7684\u9700\u6C42\u6587\u672C"),readOnly:!0,rows:4,value:Q,onFocus:q=>q.target.select()})]}),(0,z.jsxs)(Ue,{variant:"outline",size:"sm",onClick:async()=>{try{await navigator.clipboard.writeText(Q),H("\u5DF2\u590D\u5236\uFF0C\u8BF7\u7C98\u8D34\u5230 MiniMax Code \u804A\u5929\u4E2D\u53D1\u9001\u3002")}catch{N(!0),H("\u65E0\u6CD5\u81EA\u52A8\u590D\u5236\uFF0C\u8BF7\u9009\u4E2D\u6587\u672C\u624B\u52A8\u590D\u5236\u3002")}},children:[(0,z.jsx)(ao,{"aria-hidden":"true"}),$("\u590D\u5236\u9700\u6C42")]})]}),a&&(0,z.jsxs)("details",{className:"agent-results-area",hidden:!0,children:[(0,z.jsxs)("summary",{onClick:n,children:[(0,z.jsx)(ql,{size:14}),$("AI \u8FD4\u56DE\u7684\u56FE\u7247")]}),(0,z.jsx)("div",{id:"result-list"})]})]}):(0,z.jsxs)(Ue,{className:"agent-launcher","aria-label":$("\u6253\u5F00 AI \u52A9\u624B"),"aria-expanded":!1,onClick:r,children:[(0,z.jsx)(Vt,{"aria-hidden":"true"}),$("AI \u52A9\u624B")]})}return(0,Lo.flushSync)(()=>(0,er.createRoot)(l).render((0,z.jsx)(u,{}))),{open:()=>r(),refresh:()=>o(),compose:s=>i(s)}}function bg({label:e,icon:t,children:a,...n}){return(0,z.jsxs)(_m,{children:[(0,z.jsx)(Nm,{asChild:!0,children:(0,z.jsxs)(Ue,{"aria-label":e,...n,children:[(0,z.jsx)(t,{"aria-hidden":"true",strokeWidth:1.65}),a]})}),(0,z.jsx)(Vm,{side:"right",sideOffset:8,children:e})]})}function K8(e,t,a){let n=0;(0,Lo.flushSync)(()=>(0,er.createRoot)(e).render((0,z.jsx)(Oi,{delayDuration:350,children:LO.map((l,r)=>{let o=t.slice(n,n+=l);return(0,z.jsx)("div",{className:"tool-group",role:"group","aria-label":["\u9009\u62E9\u4E0E\u79FB\u52A8","\u7ED8\u753B\u4E0E\u64E6\u9664","\u4FEE\u9970","\u5F62\u72B6\u4E0E\u6587\u5B57","\u89C6\u56FE\u4E0E\u6D4B\u91CF"][r],children:o.map(([i,u,s])=>(0,z.jsx)(bg,{label:u+(s?` (${s})`:""),icon:yO[i],variant:"ghost",size:"icon","data-tool":i,"aria-pressed":i==="move",onClick:()=>a(i)},i))},r)})})))}function W8(){let e={"ask-agent":[Vt,"\u4EA4\u7ED9 Agent",!0],save:[lu,"\u4FDD\u5B58\u5DE5\u7A0B",!0],export:[no,"\u5BFC\u51FA\u56FE\u7247",!0],undo:[du,"\u64A4\u9500"],redo:[tu,"\u91CD\u505A"],"add-layer":[gn,"\u65B0\u5EFA\u900F\u660E\u56FE\u5C42"],"duplicate-layer":[ao,"\u590D\u5236\u56FE\u5C42"],"layer-up":[hn,"\u4E0A\u79FB\u56FE\u5C42"],"layer-down":[Bi,"\u4E0B\u79FB\u56FE\u5C42"],"delete-layer":[su,"\u5220\u9664\u56FE\u5C42"],"zoom-out":[pu,"\u7F29\u5C0F"],"zoom-in":[uo,"\u653E\u5927"],fit:[Qi,"\u9002\u5408\u7A97\u53E3",!0],"agent-results":[ql,"Agent \u56FE\u7247",!0],projects:[lo,"\u672C\u5730\u5DE5\u7A0B",!0],manual:[qi,"\u4F7F\u7528\u8BF4\u660E",!0],"open-start":[ql,"\u6253\u5F00\u56FE\u7247",!0],"new-start":[gn,"\u65B0\u5EFA\u753B\u5E03",!0],demo:[oo,"\u8BD5\u7528\u793A\u4F8B",!0]};for(let[o,[i,u,s]]of Object.entries(e)){let f=document.getElementById(o);if(!f)continue;let c=document.createElement("span");c.className="action-mount",f.replaceWith(c),(0,Lo.flushSync)(()=>(0,er.createRoot)(c).render((0,z.jsx)(Oi,{delayDuration:350,children:(0,z.jsx)(bg,{id:o,type:"button",label:u,icon:i,variant:["export","open-start"].includes(o)?"default":s?"outline":"ghost",size:s?"sm":"icon-sm",children:s?u:null})})))}let t=document.createElement("span");t.className="action-mount",document.querySelector("header").append(t);let a=matchMedia("(prefers-color-scheme: dark)"),n="system";try{n=localStorage.getItem("retouch-theme")||"system"}catch{}function l(){document.documentElement.dataset.theme=n==="system"?a.matches?"dark":"light":n}l(),a.addEventListener("change",l);function r(){let[o,i]=Ve.default.useState(n),u=`\u4E3B\u9898\uFF1A${{system:"\u8DDF\u968F\u7CFB\u7EDF",light:"\u6D45\u8272",dark:"\u6DF1\u8272"}[o]}\uFF0C\u70B9\u51FB\u5207\u6362`;return(0,z.jsx)(Oi,{delayDuration:350,children:(0,z.jsx)(bg,{label:u,icon:o==="system"?Zi:o==="light"?io:ro,variant:"ghost",size:"icon-sm",onClick:()=>{n={system:"light",light:"dark",dark:"system"}[o];try{localStorage.setItem("retouch-theme",n)}catch{}l(),i(n)}})})}(0,Lo.flushSync)(()=>(0,er.createRoot)(t).render((0,z.jsx)(r,{})))}function J8(e){let t=document.querySelector("#photo-actions"),a=[["export",no,"\u5BFC\u51FA PNG"]],n=r=>{};function l(){Ve.default.useSyncExternalStore(vg,wg);let[r,o]=Ve.default.useState(!1);return n=o,r?(0,z.jsx)(Oi,{delayDuration:300,children:a.map(([i,u,s])=>(0,z.jsxs)(_m,{children:[(0,z.jsx)(Nm,{asChild:!0,children:(0,z.jsxs)(Ue,{variant:"ghost",size:"sm","data-photo-action":i,onClick:e[i],"aria-label":$(s),children:[(0,z.jsx)(u,{size:16}),(0,z.jsx)("span",{children:$(s)})]})}),(0,z.jsx)(Vm,{children:$(s)})]},i))}):null}return(0,Lo.flushSync)(()=>(0,er.createRoot)(t).render((0,z.jsx)(l,{}))),{refresh:r=>n(r)}}function $8({open:e,create:t,choose:a,openShowcase:n}){let l=document.createElement("div");l.id="photo-welcome",document.querySelector(".photo-main").append(l);let r=i=>{};function o(){Ve.default.useSyncExternalStore(vg,wg);let[i,u]=Ve.default.useState({ready:!1,hasDocument:!1});return r=u,i.hasDocument?null:(0,z.jsxs)("section",{className:"welcome-content","aria-label":$("\u5F00\u59CB\u521B\u4F5C"),children:[(0,z.jsxs)("div",{className:"welcome-intro",children:[(0,z.jsxs)("span",{className:"welcome-eyebrow",children:[(0,z.jsx)(Vt,{size:14})," MiniMax Photo"]}),(0,z.jsx)("h1",{children:$("\u8BA9\u60F3\u6CD5\u6210\u4E3A\u56FE\u7247")}),(0,z.jsx)("p",{children:$("\u6253\u5F00\u56FE\u7247\u7CBE\u7EC6\u7F16\u8F91\uFF0C\u6216\u628A\u60F3\u6CD5\u4EA4\u7ED9 AI\u3002")}),(0,z.jsxs)("div",{className:"welcome-actions",children:[(0,z.jsxs)(Ue,{disabled:!i.ready,onClick:e,children:[(0,z.jsx)(lo,{size:16}),$("\u6253\u5F00\u56FE\u7247")]}),(0,z.jsxs)(Ue,{variant:"outline",disabled:!i.ready,onClick:t,children:[(0,z.jsx)(gn,{size:16}),$("\u65B0\u5EFA\u753B\u5E03")]})]}),(0,z.jsx)("small",{children:$("\u652F\u6301\u56FE\u7247\u3001PSD \u548C\u53EF\u7EE7\u7EED\u7F16\u8F91\u7684\u5DE5\u7A0B\u6587\u4EF6")})]}),(0,z.jsxs)("div",{className:"welcome-section-title",children:[(0,z.jsx)("span",{children:$("\u4F5C\u54C1\u5C55\u793A")}),(0,z.jsx)("span",{children:$("AI \u751F\u6210 \xB7 \u53EF\u6253\u5F00\u7F16\u8F91")})]}),(0,z.jsx)("div",{className:"welcome-cases showcase-cases",children:[["\u9759\u7269\u5E7F\u544A","\u7802\u5CA9\u3001\u67D4\u5149\u4E0E\u9F20\u5C3E\u8349\u7EFF","product"],["\u843D\u65E5\u4EBA\u50CF","\u6696\u8272\u5149\u7EBF\u4E0E\u81EA\u7136\u80A4\u8272","portrait"],["\u5496\u5561\u6D77\u62A5","\u914D\u56FE\u4E0E\u5B57\u4F53\u7684\u5B8C\u6574\u753B\u9762","poster"]].map(([s,f,c])=>(0,z.jsxs)("article",{className:"welcome-case "+c,children:[(0,z.jsx)("button",{className:"showcase-image",disabled:!i.ready,onClick:()=>n(c),"aria-label":$("\u6253\u5F00\u4F5C\u54C1")+" \xB7 "+$(s),children:(0,z.jsx)("img",{src:"/showcase/"+c+".webp",alt:$(s),loading:"lazy"})}),(0,z.jsxs)("div",{className:"showcase-caption",children:[(0,z.jsx)("strong",{children:$(s)}),(0,z.jsx)("p",{children:$(f)}),(0,z.jsxs)("div",{className:"showcase-actions",children:[(0,z.jsxs)(Ue,{size:"sm",variant:"outline",disabled:!i.ready,onClick:()=>n(c),children:[$("\u6253\u5F00\u4F5C\u54C1"),(0,z.jsx)(hn,{size:14})]}),(0,z.jsx)(Ue,{size:"sm",variant:"ghost",disabled:!i.ready,onClick:()=>a(c),children:$("\u8BD5\u8BD5\u8FD9\u4E2A")})]})]})]},c))}),(0,z.jsxs)("div",{className:"welcome-steps",children:[(0,z.jsxs)("span",{children:[(0,z.jsx)("b",{children:"1"}),$("\u6253\u5F00\u56FE\u7247\u6216\u9009\u62E9\u793A\u4F8B")]}),(0,z.jsxs)("span",{children:[(0,z.jsx)("b",{children:"2"}),$("\u63CF\u8FF0\u9700\u6C42\uFF0C\u4EA4\u7ED9 AI \u52A9\u624B")]}),(0,z.jsxs)("span",{children:[(0,z.jsx)("b",{children:"3"}),$("\u67E5\u770B\u7ED3\u679C\uFF0C\u7EE7\u7EED\u7F16\u8F91\u548C\u5BFC\u51FA")]})]}),(0,z.jsx)("p",{className:"welcome-note",children:$("\u6253\u5F00\u4F5C\u54C1\u53EF\u76F4\u63A5\u7F16\u8F91\uFF0C\u4E5F\u53EF\u4EE5\u8BA9 AI \u52A9\u624B\u5E2E\u4F60\u7EE7\u7EED\u521B\u4F5C\u3002")})]})}return(0,er.createRoot)(l).render((0,z.jsx)(o,{})),{refresh(i){l.hidden=i.hasDocument,r(i)}}}export{W8 as mountActions,Z8 as mountAgentPanel,xO as mountPhotoAssistant,J8 as mountPhotoToolbar,$8 as mountPhotoWelcome,K8 as mountTools}; +/*! For license information please see workbench-ui.js.LEGAL.txt */ diff --git a/plugins/webguhui/minimax-photo/miniapp/client/workbench-ui.js.LEGAL.txt b/plugins/webguhui/minimax-photo/miniapp/client/workbench-ui.js.LEGAL.txt new file mode 100644 index 00000000..a046cadc --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/client/workbench-ui.js.LEGAL.txt @@ -0,0 +1,117 @@ +Bundled license information: + +react/cjs/react.production.js: + /** + * @license React + * react.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +scheduler/cjs/scheduler.production.js: + /** + * @license React + * scheduler.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +react-dom/cjs/react-dom.production.js: + /** + * @license React + * react-dom.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +react-dom/cjs/react-dom-client.production.js: + /** + * @license React + * react-dom-client.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +react/cjs/react-jsx-runtime.production.js: + /** + * @license React + * react-jsx-runtime.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +lucide-react/dist/esm/shared/src/utils.js: +lucide-react/dist/esm/defaultAttributes.js: +lucide-react/dist/esm/Icon.js: +lucide-react/dist/esm/createLucideIcon.js: +lucide-react/dist/esm/icons/arrow-down.js: +lucide-react/dist/esm/icons/arrow-up.js: +lucide-react/dist/esm/icons/bandage.js: +lucide-react/dist/esm/icons/blend.js: +lucide-react/dist/esm/icons/book-open.js: +lucide-react/dist/esm/icons/circle-dashed.js: +lucide-react/dist/esm/icons/circle.js: +lucide-react/dist/esm/icons/contrast.js: +lucide-react/dist/esm/icons/copy.js: +lucide-react/dist/esm/icons/crop.js: +lucide-react/dist/esm/icons/download.js: +lucide-react/dist/esm/icons/droplets.js: +lucide-react/dist/esm/icons/eraser.js: +lucide-react/dist/esm/icons/fingerprint.js: +lucide-react/dist/esm/icons/folder-open.js: +lucide-react/dist/esm/icons/hand.js: +lucide-react/dist/esm/icons/image-plus.js: +lucide-react/dist/esm/icons/lasso.js: +lucide-react/dist/esm/icons/maximize.js: +lucide-react/dist/esm/icons/minus.js: +lucide-react/dist/esm/icons/monitor.js: +lucide-react/dist/esm/icons/moon.js: +lucide-react/dist/esm/icons/move.js: +lucide-react/dist/esm/icons/paint-bucket.js: +lucide-react/dist/esm/icons/paintbrush-vertical.js: +lucide-react/dist/esm/icons/paintbrush.js: +lucide-react/dist/esm/icons/pen-tool.js: +lucide-react/dist/esm/icons/pencil.js: +lucide-react/dist/esm/icons/pipette.js: +lucide-react/dist/esm/icons/plus.js: +lucide-react/dist/esm/icons/redo-2.js: +lucide-react/dist/esm/icons/rotate-cw.js: +lucide-react/dist/esm/icons/ruler.js: +lucide-react/dist/esm/icons/save.js: +lucide-react/dist/esm/icons/scan-line.js: +lucide-react/dist/esm/icons/sparkles.js: +lucide-react/dist/esm/icons/spline.js: +lucide-react/dist/esm/icons/square-dashed.js: +lucide-react/dist/esm/icons/square.js: +lucide-react/dist/esm/icons/stamp.js: +lucide-react/dist/esm/icons/star.js: +lucide-react/dist/esm/icons/sun.js: +lucide-react/dist/esm/icons/trash-2.js: +lucide-react/dist/esm/icons/triangle.js: +lucide-react/dist/esm/icons/type.js: +lucide-react/dist/esm/icons/undo-2.js: +lucide-react/dist/esm/icons/wand-sparkles.js: +lucide-react/dist/esm/icons/zoom-in.js: +lucide-react/dist/esm/icons/zoom-out.js: +lucide-react/dist/esm/lucide-react.js: + /** + * @license lucide-react v0.468.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */ diff --git a/plugins/webguhui/minimax-photo/miniapp/miniapp.json b/plugins/webguhui/minimax-photo/miniapp/miniapp.json new file mode 100644 index 00000000..76cfb9d5 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/miniapp.json @@ -0,0 +1,28 @@ +{ + "schemaVersion": 1, + "artifacts": { + "client": [ + "./miniapp/client" + ], + "node": [ + "./miniapp/node" + ] + }, + "runtime": { + "kind": "process", + "entry": "./miniapp/node/server.mjs", + "lifecycle": "on-demand" + }, + "surface": { + "path": "/" + }, + "mcpEndpoints": [ + { + "server": "retouch-images", + "path": "/mcp/retouch-images" + } + ], + "agentAccess": [ + "session.run" + ] +} diff --git a/plugins/webguhui/minimax-photo/miniapp/node/agent-mcp.mjs b/plugins/webguhui/minimax-photo/miniapp/node/agent-mcp.mjs new file mode 100644 index 00000000..bf4c7719 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/node/agent-mcp.mjs @@ -0,0 +1,114 @@ +import { editorTools, callEditorTool } from './editor-mcp.mjs'; +import { readJSON } from './agent-service.mjs'; +const idSchema = { type: 'string', description: '工作台给出的任务编号' }; +const tools = [ + { + name: 'get_image_request', + description: + '读取修图工作台任务。改图任务返回已由用户保存的参考 PNG 本机路径;用图片工具读取该路径。', + inputSchema: { + type: 'object', + properties: { requestId: idSchema }, + required: ['requestId'], + additionalProperties: false, + }, + annotations: { readOnlyHint: true }, + }, + { + name: 'submit_image_result', + description: + '将生成好的本机 PNG 交回修图工作台,用户可点击打开。不会改写原工程。相同结果重复提交安全;不同结果须新建任务。', + inputSchema: { + type: 'object', + properties: { + requestId: idSchema, + imagePath: { + type: 'string', + description: '生成 PNG 的本机绝对路径,最大 16 MB、3200 万像素', + }, + }, + required: ['requestId', 'imagePath'], + additionalProperties: false, + }, + annotations: { destructiveHint: false, idempotentHint: true }, + }, +]; +// Stateless Streamable HTTP, JSON responses; no server-initiated RPC or session IDs. +export async function handleAgentMCP(req, res, service, json, editor, serverInfo) { + if (req.method !== 'POST') { + res.setHeader('Allow', 'POST'); + return json(res, 405, { error: 'Use POST' }); + } + if (!req.headers['content-type']?.startsWith('application/json')) + return json(res, 415, { error: 'JSON required' }); + const accept = req.headers.accept || ''; + if (!accept.includes('application/json') || !accept.includes('text/event-stream')) + return json(res, 406, { error: 'Accept JSON and SSE' }); + let body; + try { + body = await readJSON(req, 64 * 1024); + } catch { + return json(res, 400, { + jsonrpc: '2.0', + id: null, + error: { code: -32700, message: 'Invalid JSON' }, + }); + } + const dispatch = async (message) => { + if (!message || message.jsonrpc !== '2.0' || typeof message.method !== 'string') + return { + jsonrpc: '2.0', + id: message?.id ?? null, + error: { code: -32600, message: 'Invalid request' }, + }; + if (message.id === undefined) return null; + const reply = (result) => ({ jsonrpc: '2.0', id: message.id, result }); + if (message.method === 'initialize') + return reply({ + protocolVersion: '2025-03-26', + capabilities: { tools: {} }, + serverInfo, + }); + if (message.method === 'ping') return reply({}); + if (message.method === 'tools/list') return reply({ tools: [...tools, ...editorTools] }); + if (message.method === 'tools/call') { + try { + const { name, arguments: args = {} } = message.params || {}; + if (!args || typeof args !== 'object' || Array.isArray(args)) throw Error('工具参数无效'); + if (editorTools.some((t) => t.name === name)) + return reply(await callEditorTool(name, args, editor)); + const allowed = name === 'get_image_request' ? ['requestId'] : ['requestId', 'imagePath']; + if (Object.keys(args).some((key) => !allowed.includes(key))) throw Error('包含未知参数'); + let result; + if (name === 'get_image_request') { + result = await service.get(args.requestId); + if (result.mode === 'edit') result = await service.reference(args.requestId); + } else if (name === 'submit_image_result') + result = await service.submit(args.requestId, args.imagePath); + else throw Error('未知工具'); + return reply({ content: [{ type: 'text', text: JSON.stringify(result) }] }); + } catch (error) { + const text = + error.code === 'ENOENT' + ? '任务或图片不存在' + : error.code + ? '读取或保存图片失败' + : error.message; + return reply({ isError: true, content: [{ type: 'text', text }] }); + } + } + return { jsonrpc: '2.0', id: message.id, error: { code: -32601, message: 'Method not found' } }; + }; + const messages = Array.isArray(body) ? body : [body]; + if (!messages.length || messages.length > 20) return json(res, 400, { error: 'Invalid batch' }); + const replies = []; + for (const message of messages) { + const reply = await dispatch(message); + if (reply) replies.push(reply); + } + if (!replies.length) { + res.writeHead(202); + return res.end(); + } + return json(res, 200, Array.isArray(body) ? replies : replies[0]); +} diff --git a/plugins/webguhui/minimax-photo/miniapp/node/agent-service.mjs b/plugins/webguhui/minimax-photo/miniapp/node/agent-service.mjs new file mode 100644 index 00000000..8a3430b6 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/node/agent-service.mjs @@ -0,0 +1,149 @@ +import { validatePNG } from './png-validation.mjs'; +import { mkdir, readFile, writeFile, rename, readdir, open } from 'node:fs/promises'; +import { join, isAbsolute } from 'node:path'; +import { randomUUID, createHash } from 'node:crypto'; +const MAX_IMAGE = 16 * 1024 * 1024; +const validId = (id) => typeof id === 'string' && /^[a-f0-9-]{36}$/.test(id); +export async function readJSON(req, limit = 24 * 1024 * 1024) { + const chunks = []; + let bytes = 0; + for await (const chunk of req) { + bytes += chunk.length; + if (bytes > limit) throw Error('请求过大'); + chunks.push(chunk); + } + return JSON.parse(Buffer.concat(chunks).toString('utf8')); +} +export async function createAgentService(dataDir) { + const root = join(dataDir, 'agent-requests'); + await mkdir(root, { recursive: true }); + const streams = new Set(), + locks = new Map(); + const path = (id, name) => { + if (!validId(id)) throw Error('任务编号无效'); + return join(root, id, name); + }; + async function atomic(file, data) { + const tmp = file + '.' + randomUUID() + '.tmp'; + await writeFile(tmp, data, { mode: 0o600 }); + await rename(tmp, file); + } + async function get(id) { + return JSON.parse(await readFile(path(id, 'request.json'), 'utf8')); + } + async function list() { + const results = []; + for (const id of await readdir(root)) + if (validId(id)) { + try { + const p = await get(id); + results.push(p); + } catch {} + } + return results.sort((a, b) => b.updatedAt - a.updatedAt); + } + async function create(input) { + if ( + !['generate', 'edit'].includes(input.mode) || + typeof input.prompt !== 'string' || + !input.prompt.trim() || + input.prompt.length > 8000 + ) + throw Error('图片需求无效'); + let reference; + if (input.mode === 'edit') { + if ( + typeof input.reference !== 'string' || + !/^data:image\/png;base64,[A-Za-z0-9+/=]+$/.test(input.reference) + ) + throw Error('缺少 PNG 参考图'); + reference = Buffer.from(input.reference.split(',')[1], 'base64'); + await validatePNG(reference); + } + const id = randomUUID(), + now = Date.now(); + const record = { + id, + mode: input.mode, + prompt: input.prompt.trim(), + name: typeof input.name === 'string' ? input.name.slice(0, 200) : 'Agent 图片', + status: 'pending', + createdAt: now, + updatedAt: now, + }; + await mkdir(join(root, id)); + if (reference) await atomic(path(id, 'reference.png'), reference); + await atomic(path(id, 'request.json'), JSON.stringify(record)); + return record; + } + async function submit(id, imagePath) { + if (typeof imagePath !== 'string' || !isAbsolute(imagePath) || imagePath.length > 4096) + throw Error('请提供生成图片的本机绝对路径'); + const previous = locks.get(id) || Promise.resolve(); + const next = previous + .catch(() => {}) + .then(async () => { + const record = await get(id); + const handle = await open(imagePath, 'r'); + let bytes; + try { + const info = await handle.stat(); + if (!info.isFile() || info.size > MAX_IMAGE) throw Error('图片不是普通文件或超过 16 MB'); + // Read a bounded buffer even if the file changes after stat. + bytes = Buffer.alloc(Math.min(MAX_IMAGE + 1, info.size + 1)); + let offset = 0; + while (offset < bytes.length) { + const read = await handle.read(bytes, offset, bytes.length - offset, offset); + if (!read.bytesRead) break; + offset += read.bytesRead; + } + bytes = bytes.subarray(0, offset); + } finally { + await handle.close(); + } + const dimensions = await validatePNG(bytes), + digest = createHash('sha256').update(bytes).digest('hex'); + if (record.status === 'ready') { + if (record.digest === digest) return record; + throw Error('此任务已有结果;请新建任务以免覆盖'); + } + await atomic(path(id, 'result.png'), bytes); + const ready = { ...record, ...dimensions, status: 'ready', digest, updatedAt: Date.now() }; + await atomic(path(id, 'request.json'), JSON.stringify(ready)); + for (const res of streams) + res.write('event: result\ndata: ' + JSON.stringify({ id }) + '\n\n'); + return ready; + }); + locks.set(id, next); + try { + return await next; + } finally { + if (locks.get(id) === next) locks.delete(id); + } + } + return { + create, + get, + list, + submit, + async reference(id) { + const record = await get(id); + if (record.mode !== 'edit') throw Error('此任务不需要参考图'); + return { path: path(id, 'reference.png'), ...record }; + }, + async result(id) { + if ((await get(id)).status !== 'ready') throw Error('图片尚未生成'); + return readFile(path(id, 'result.png')); + }, + subscribe(req, res) { + res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache' }); + res.write(': connected\n\n'); + streams.add(res); + req.on('close', () => streams.delete(res)); + }, + close() { + for (const res of streams) res.end(); + streams.clear(); + }, + }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/node/editor-code.mjs b/plugins/webguhui/minimax-photo/miniapp/node/editor-code.mjs new file mode 100644 index 00000000..378c6875 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/node/editor-code.mjs @@ -0,0 +1,241 @@ +import { Worker } from 'node:worker_threads'; +import { mkdir, readFile, writeFile, rename } from 'node:fs/promises'; +import { join } from 'node:path'; +import { randomUUID, createHash } from 'node:crypto'; +import { editorCapabilities } from '../client/editor-commands.js'; + +const validId = (v) => typeof v === 'string' && /^[a-f0-9-]{36}$/.test(v); +const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); +export async function createCodeService(dataDir, editor) { + const root = join(dataDir, 'editor-code'); + await mkdir(root, { recursive: true }); + const active = new Map(); + let submissions = Promise.resolve(); + const read = async (id) => { + if (!validId(id)) throw Error('运行编号无效'); + return JSON.parse(await readFile(join(root, id + '.json'), 'utf8')); + }; + const write = async (run) => { + const path = join(root, run.runId + '.json'), + tmp = path + '.' + randomUUID() + '.tmp'; + await writeFile(tmp, JSON.stringify(run), { mode: 0o600 }); + await rename(tmp, path); + }; + const visible = ({ fingerprint, code, ...run }) => run; + function launch(run) { + const deadline = Date.now() + 120000; + const worker = new Worker(new URL('./ptc-worker.mjs', import.meta.url), { + workerData: { code: run.code, deadline }, + stdout: true, + stderr: true, + resourceLimits: { maxOldGenerationSizeMb: 96, stackSizeMb: 4 }, + }); + // Keep vendored VM diagnostics away from the Host-owned process streams. + // Structured failures are reported through worker messages below. + worker.stdout.resume(); + worker.stderr.resume(); + const state = { run, worker, stopped: false, busy: false, inflight: Promise.resolve() }; + active.set(run.runId, state); + let version = run.expectedVersion; + const finish = async (error, result) => { + if (state.stopped) return; + state.stopped = true; + clearTimeout(timer); + await worker.terminate(); + await state.inflight.catch(() => {}); + run.status = error ? 'failed' : 'succeeded'; + run.error = error; + run.result = result; + run.finishedAt = Date.now(); + try { + await write(run); + } finally { + active.delete(run.runId); + } + }; + const timer = setTimeout( + () => void finish('执行超过 120 秒;已提交任务见 trace,请查询其最终结果'), + 120000, + ); + state.timer = timer; + worker.on('error', (error) => void finish(error.message)); + worker.on('exit', (code) => { + if (!state.stopped) void finish('执行器意外退出:' + code); + }); + worker.on('message', (message) => { + if (state.stopped) return; + if (message.type === 'done') { + run.logs = message.logs; + void finish(message.error, message.result); + return; + } + if (message.type !== 'call') return; + if (state.busy) { + worker.postMessage({ + id: message.id, + error: '工具调用必须逐个 await,不能并行或遗漏 await', + }); + return; + } + state.busy = true; + state.inflight = (async () => { + const step = { index: run.trace.length + 1, method: message.method, startedAt: Date.now() }; + try { + if (run.trace.length >= 64) throw Error('每次脚本最多调用 64 次工具'); + if ( + ![ + 'inspect', + 'capabilities', + 'preview', + 'edit', + 'create', + 'export', + 'commands', + 'execute', + 'draw', + ].includes(message.method) + ) + throw Error('未知脚本工具'); + run.trace.push(step); + const current = editor.inspect(run.editorId); + if (current.version !== version) + throw Error('用户或其他任务已修改工程,脚本停止,请重新读取'); + let result; + if (message.method === 'inspect') result = current; + else if (message.method === 'capabilities' && current.engine !== 'photocraft') + result = editorCapabilities; + else { + const craft = current.engine === 'photocraft'; + const kind = craft ? 'craft' : message.method === 'edit' ? 'batch' : message.method; + const args = message.args; + if ( + kind === 'create' && + (!args || Object.keys(args).some((k) => !['width', 'height', 'name'].includes(k))) + ) + throw Error('create 只接受 width、height、name'); + step.jobId = randomUUID(); + // Record the task identity before submitting: an interrupted script never retries it. + await write(run); + if (state.stopped) throw Error('脚本已停止'); + await editor.submit({ + ...(kind === 'create' ? args : {}), + requestId: step.jobId, + editorId: run.editorId, + expectedVersion: version, + kind, + ...(kind === 'batch' ? { operations: args } : {}), + ...(kind === 'preview' ? { options: args || {} } : {}), + ...(craft + ? { + options: { + method: + message.method === 'edit' + ? 'batch' + : ['commands', 'capabilities'].includes(message.method) + ? 'commands' + : message.method === 'create' + ? 'execute' + : message.method, + args: + message.method === 'create' + ? { command: 'file.new', params: args } + : args || {}, + }, + } + : {}), + }); + do { + if (state.stopped || Date.now() > deadline) + throw Error('脚本已停止;已提交任务仍需查询'); + await sleep(100); + result = await editor.result(step.jobId); + } while (['queued', 'running', 'prepared'].includes(result.status)); + if (result.status !== 'succeeded') throw Error(result.error || result.status); + version = result.appliedVersion; + if (!version) throw Error('编辑任务缺少已应用版本'); + } + step.status = 'succeeded'; + step.finishedAt = Date.now(); + await write(run); + if (!state.stopped) worker.postMessage({ id: message.id, result }); + } catch (error) { + step.status = 'failed'; + step.error = error.message; + step.finishedAt = Date.now(); + await write(run); + if (!state.stopped) worker.postMessage({ id: message.id, error: error.message }); + } finally { + state.busy = false; + } + })(); + state.inflight.catch((error) => void finish(error.message)); + }); + } + return { + async submit(input) { + const next = submissions + .catch(() => {}) + .then(async () => { + if ( + !validId(input.requestId) || + !validId(input.editorId) || + typeof input.expectedVersion !== 'string' || + typeof input.code !== 'string' || + !input.code.trim() || + Buffer.byteLength(input.code) > 32768 + ) + throw Error('需要有效 requestId、editorId、expectedVersion 和不超过 32 KB 的 code'); + const fingerprint = createHash('sha256') + .update(JSON.stringify([input.editorId, input.expectedVersion, input.code])) + .digest('hex'); + try { + const old = await read(input.requestId); + if (old.fingerprint !== fingerprint) throw Error('requestId 已用于不同脚本'); + return this.result(old.runId); + } catch (error) { + if (error.code !== 'ENOENT') throw error; + } + if ( + active.size >= 2 || + [...active.values()].some((s) => s.run.editorId === input.editorId) + ) + throw Error('已有脚本正在执行,请等待并查询结果'); + const current = editor.inspect(input.editorId); + if (current.busy) throw Error('编辑任务尚未完成,请查询原任务结果后继续'); + if (current.version !== input.expectedVersion) + throw Error('画布版本已变化,请重新 editor_inspect 后使用最新 version'); + const run = { + runId: input.requestId, + editorId: input.editorId, + expectedVersion: input.expectedVersion, + code: input.code, + fingerprint, + status: 'running', + createdAt: Date.now(), + trace: [], + }; + await write(run); + launch(run); + return visible(run); + }); + submissions = next; + return next; + }, + async result(runId) { + const run = await read(runId); + if (run.status === 'running' && !active.has(runId)) { + run.status = 'interrupted'; + run.error = '服务已重启;不会重放脚本。请查询 trace 中的任务并检查工程'; + } + return visible(run); + }, + close() { + for (const state of active.values()) { + state.stopped = true; + clearTimeout(state.timer); + void state.worker.terminate(); + } + active.clear(); + }, + }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/node/editor-file.mjs b/plugins/webguhui/minimax-photo/miniapp/node/editor-file.mjs new file mode 100644 index 00000000..ff57cef8 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/node/editor-file.mjs @@ -0,0 +1,36 @@ +import { open } from 'node:fs/promises'; +import { constants } from 'node:fs'; +import { basename, extname, isAbsolute } from 'node:path'; + +export async function readEditorFile(filePath) { + if (typeof filePath !== 'string' || !isAbsolute(filePath) || filePath.length > 4096) + throw Error('请提供用户指定文件或工具导出文件的本机绝对路径'); + const extension = extname(filePath).toLowerCase(); + if (!['.png', '.jpg', '.jpeg', '.webp', '.psd', '.pcraft'].includes(extension)) + throw Error('支持 PNG、JPEG、WebP、PSD 和 pcraft 工程'); + const handle = await open(filePath, constants.O_RDONLY | (constants.O_NONBLOCK || 0)); + let data; + try { + const info = await handle.stat(); + if (!info.isFile() || info.size < 12 || info.size > 32 * 1024 * 1024) + throw Error('需要 32 MB 以内的普通图片或工程文件'); + data = Buffer.alloc(info.size + 1); + let offset = 0; + while (offset < data.length) { + const { bytesRead } = await handle.read(data, offset, data.length - offset, offset); + if (!bytesRead) break; + offset += bytesRead; + } + if (offset !== info.size) throw Error('读取期间文件大小变化,请确认保存完成后重试'); + data = data.subarray(0, offset); + } finally { await handle.close(); } + const valid = extension === '.png' ? data.subarray(0, 8).equals(Buffer.from([137,80,78,71,13,10,26,10])) + : ['.jpg', '.jpeg'].includes(extension) ? data[0] === 255 && data[1] === 216 && data[2] === 255 + : extension === '.webp' ? data.toString('ascii', 0, 4) === 'RIFF' && data.toString('ascii', 8, 12) === 'WEBP' + : extension === '.psd' ? data.toString('ascii', 0, 4) === '8BPS' && data.readUInt16BE(4) === 1 + : data.subarray(0, 4).equals(Buffer.from([80,75,3,4])); + if (!valid) throw Error('文件内容与扩展名不符'); + // The editor dispatches project files by a case-sensitive extension. + const name = basename(filePath); + return { name: name.slice(0, -extname(name).length) + extension, data: data.toString('base64') }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/node/editor-mcp.mjs b/plugins/webguhui/minimax-photo/miniapp/node/editor-mcp.mjs new file mode 100644 index 00000000..ff0d335b --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/node/editor-mcp.mjs @@ -0,0 +1,215 @@ +import { readEditorFile } from './editor-file.mjs'; +import { editorCapabilities } from '../client/editor-commands.js'; +const uuid = { type: 'string', pattern: '^[a-f0-9-]{36}$' }; +const schema = (properties) => ({ + type: 'object', + properties, + required: Object.keys(properties), + additionalProperties: false, +}); +export const editorTools = [ + { + name: 'editor_open_file', + description: '在当前 PhotoCraft 编辑器以新文档打开用户指定的本机图片或工具返回的导出文件,保留现有文档。支持 PNG/JPEG/WebP/PSD/pcraft,最多32MB。filePath 只使用已知附件或导出路径,不扫描目录、不读取凭证。无需 base64、浏览器上传或 file.openAs。返回任务编号,用 editor_job 查询完成结果。', + inputSchema: schema({editorId: uuid, expectedVersion: {type: 'string'}, requestId: uuid, filePath: {type: 'string', maxLength: 4096}}), + annotations: {destructiveHint: false, idempotentHint: true}, + }, + { + name: 'photo_call', + description: + '首次编辑先加载 minimax-photo:minimax-photo Skill。调用 PhotoCraft WASM 编辑器。args/params 保持 JSON 对象与数字类型,不转字符串。先 commands({filter}) 查询真实命令与参数,再 execute({command,params});batch 接受 [{command,params}],在独立文档上执行并整体提交/撤销。draw({strokes:[paint.stroke参数],intervalMs:550}) 支持 points 或 SVG 风格绝对 path 命令数组 M/L/Q/C/Z(工具自动采样曲线)。实际逐笔绘制,每笔可见且单独撤销,1..96笔,间隔100..600ms;中断保留已画笔触。preview 返回画面;export 只接受 {format},支持 png/jpg/webp/pcraft/psd/ora/tif;完成任务的 exportPath 是文件位置,不接受自定义路径。使用 editor_job 查询结果,禁止盲目重放。', + inputSchema: schema({ + editorId: uuid, + expectedVersion: { type: 'string' }, + requestId: uuid, + method: { type: 'string', enum: ['commands', 'execute', 'batch', 'draw', 'preview', 'export'] }, + args: {}, + }), + annotations: { destructiveHint: false, idempotentHint: true }, + }, + { + name: 'editor_run_code', + description: + '首次使用先加载 minimax-photo:minimax-photo Skill 获取返回结构与示例。执行 JavaScript PTC 脚本。只返回本次需要的字段,避免完整命令目录或预览结果超过 64KB。PhotoCraft 支持 draw({strokes:[paint.stroke参数],intervalMs:550}) 逐笔显示绘画过程(1..96笔,100..600ms),commands({filter})、execute({command,params})、edit([{command,params}])、preview()、create()、export({format}),参数以 commands 查询为准。支持变量、循环、条件和 await。提供 editor.inspect()、capabilities()、preview(options)、edit(operations)、create({width,height,name})、export(),均须逐个 await;返回真实任务结果。preview 返回 result.pixels 及 previewPath,可按像素分支。32KB代码、32MB内存、120秒、64次调用。无文件、网络或 Node API。每批 edit 原子执行;脚本整体不回滚。返回 runId,用 editor_code_result 查询;相同 requestId 不重放。', + inputSchema: schema({ + editorId: uuid, + expectedVersion: { type: 'string' }, + requestId: uuid, + code: { type: 'string', maxLength: 32768 }, + }), + annotations: { destructiveHint: false, idempotentHint: true }, + }, + { + name: 'editor_code_result', + description: + '读取 PTC 执行状态、返回值和每一步任务编号。错误或中断不代表之前的操作回滚;用 editor_job 检查 trace 中已提交任务。', + inputSchema: schema({ runId: uuid }), + annotations: { readOnlyHint: true }, + }, + { + name: 'editor_capabilities', + description: + '仅用于旧版 canvas 引擎;photocraft 请用 photo_call(method:commands) 或 PTC editor.commands()。读取编辑操作目录、参数范围、混合模式和批量组合规则。旧版编辑前调用。支持命名图层引用,最多64步的事务;不是任意 JavaScript 执行环境。', + inputSchema: schema({}), + annotations: { readOnlyHint: true }, + }, + { + name: 'editor_list', + description: '列出连接的工作台、文档、版本和页面可见状态。首次使用先加载 minimax-photo:minimax-photo Skill。先在当前聊天打开 minimax-photo;多个实例时,通过当前页面 html 的 data-photo-editor-id 属性匹配 editorId。page.visibility/focused 仅为浏览器状态提示,不证明聊天归属;不自动选择首项或最新窗口。', + inputSchema: schema({}), + annotations: { readOnlyHint: true }, + }, + { + name: 'editor_inspect', + description: + '读取当前工程结构、图层、选区、版本。返回页面最后报告的状态;修改前使用 expectedVersion 防止覆盖用户的新操作。', + inputSchema: schema({ editorId: uuid }), + annotations: { readOnlyHint: true }, + }, + { + name: 'editor_preview', + description: + '仅用于旧版 canvas 引擎;photocraft 请用 photo_call(method:preview) 或 PTC editor.preview()。请求合并画面、单图层或局部区域 PNG 预览,并可取样像素 RGBA。返回任务编号;随后用 editor_job 查询,完成后得到 image 内容。需要页面打开。', + inputSchema: { + ...schema({ editorId: uuid, expectedVersion: { type: 'string' }, requestId: uuid }), + properties: { + editorId: uuid, + expectedVersion: { type: 'string' }, + requestId: uuid, + options: { + type: 'object', + properties: { + layerId: { type: 'string' }, + maxEdge: { type: 'integer', minimum: 64, maximum: 4096 }, + region: { + type: 'object', + properties: { + x: { type: 'integer' }, + y: { type: 'integer' }, + width: { type: 'integer' }, + height: { type: 'integer' }, + }, + required: ['x', 'y', 'width', 'height'], + additionalProperties: false, + }, + points: { + type: 'array', + maxItems: 256, + items: { type: 'array', items: { type: 'integer' }, minItems: 2, maxItems: 2 }, + }, + }, + additionalProperties: false, + }, + }, + }, + annotations: { readOnlyHint: true }, + }, + { + name: 'editor_batch', + description: + '仅用于旧版 canvas 引擎;photocraft 请用 photo_call(method:batch) 或 PTC editor.edit()。按顺序执行编辑计划,支持读到的图层ID及 $命名引用。整批失败不修改工程,成功可一次撤销。每次新计划用新 requestId;不确定结果时查询原任务,不重新提交不同编号。完成后生成持久化工程检查点和预览。', + inputSchema: schema({ + editorId: uuid, + expectedVersion: { type: 'string' }, + requestId: uuid, + operations: { + type: 'array', + minItems: 1, + maxItems: 64, + items: { + type: 'object', + required: ['op'], + properties: { op: { type: 'string', enum: Object.keys(editorCapabilities.operations) } }, + }, + }, + }), + annotations: { destructiveHint: false, idempotentHint: true }, + }, + { + name: 'editor_create', + description: + '仅用于旧版 canvas 引擎;photocraft 请用 PTC editor.create()。创建新的空白工程并显示,保留当前已打开工程。宽高为整数,最多3200万像素。创建后读取新文档再批量绘制。', + inputSchema: schema({ + editorId: uuid, + expectedVersion: { type: 'string' }, + requestId: uuid, + name: { type: 'string', maxLength: 200 }, + width: { type: 'integer', minimum: 1 }, + height: { type: 'integer', minimum: 1 }, + }), + annotations: { destructiveHint: false, idempotentHint: true }, + }, + { + name: 'editor_export', + description: + '仅用于旧版 canvas 引擎;photocraft 请用 photo_call(method:export) 或 PTC editor.export()。导出当前完整尺寸 PNG 和可编辑工程检查点到本机,返回任务编号。不会更改画布。用 editor_job 查询导出路径;PNG 最大16MB。', + inputSchema: schema({ editorId: uuid, expectedVersion: { type: 'string' }, requestId: uuid }), + annotations: { destructiveHint: false, idempotentHint: true }, + }, + { + name: 'editor_job', + description: + '查询编辑或预览任务。成功时返回预览图及本机 PNG、工程检查点路径。中断状态不会自动重放;检查当前工程后处理。', + inputSchema: schema({ jobId: uuid }), + annotations: { readOnlyHint: true }, + }, +]; +export async function callEditorTool(name, args, editor) { + const spec = editorTools.find((t) => t.name === name); + if (!spec) throw Error('未知编辑工具'); + if ( + !args || + typeof args !== 'object' || + Array.isArray(args) || + Object.keys(args).some((k) => !Object.hasOwn(spec.inputSchema.properties, k)) || + spec.inputSchema.required.some((k) => args[k] === undefined) + ) + throw Error('编辑工具参数无效'); + let result; + if (name === 'editor_open_file') { + const state = editor.inspect(args.editorId); + if (state.engine !== 'photocraft') throw Error('需要 PhotoCraft 工作台'); + const file = await readEditorFile(args.filePath); + result = await editor.submit({editorId: args.editorId, expectedVersion: args.expectedVersion, + requestId: args.requestId, kind: 'craft', options: {method: 'open', args: file}}); + } else if (name === 'photo_call') + result = await editor.submit({ + ...args, + kind: 'craft', + options: { method: args.method, args: args.args }, + }); + else if (name === 'editor_run_code') result = await editor.code.submit(args); + else if (name === 'editor_code_result') result = await editor.code.result(args.runId); + else if (name === 'editor_capabilities') result = editorCapabilities; + else if (name === 'editor_list') result = { editors: editor.list() }; + else if (name === 'editor_inspect') result = editor.inspect(args.editorId); + else if (['editor_preview', 'editor_batch', 'editor_export', 'editor_create'].includes(name)) + result = await editor.submit({ + ...args, + kind: + name === 'editor_create' + ? 'create' + : name === 'editor_preview' + ? 'preview' + : name === 'editor_export' + ? 'export' + : 'batch', + }); + else result = await editor.result(args.jobId); + const content = [{ type: 'text', text: JSON.stringify(result) }]; + if (name === 'editor_job' && result.status === 'succeeded') + content.push({ type: 'image', mimeType: 'image/png', data: await editor.preview(args.jobId) }); + if ( + name === 'editor_code_result' && + ['succeeded', 'failed', 'interrupted'].includes(result.status) + ) { + const last = result.trace.findLast((step) => step.jobId && step.status === 'succeeded'); + if (last) + content.push({ + type: 'image', + mimeType: 'image/png', + data: await editor.preview(last.jobId), + }); + } + return { content }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/node/editor-service.mjs b/plugins/webguhui/minimax-photo/miniapp/node/editor-service.mjs new file mode 100644 index 00000000..558e2f8d --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/node/editor-service.mjs @@ -0,0 +1,350 @@ +import { mkdir, readFile, writeFile, rename } from 'node:fs/promises'; +import { join } from 'node:path'; +import { randomUUID, createHash } from 'node:crypto'; +import { validatePNG } from './png-validation.mjs'; +const id = (v) => typeof v === 'string' && /^[a-f0-9-]{36}$/.test(v); +const canonical = (value) => + Array.isArray(value) + ? value.map(canonical) + : value && typeof value === 'object' + ? Object.fromEntries( + Object.keys(value) + .sort() + .map((key) => [key, canonical(value[key])]), + ) + : value; +const visible = (job) => { + const { checkpoint, preview, exportImage, craftExport, claim, fingerprint, ...summary } = job; + if (summary.options?.method === 'open') + summary.options = {method: 'open', args: {name: summary.options.args?.name}}; + return summary; +}; +export async function createEditorService(dataDir) { + const root = join(dataDir, 'editor-jobs'); + await mkdir(root, { recursive: true }); + const editors = new Map(), + locks = new Map(); + async function serial(key, fn) { + const next = (locks.get(key) || Promise.resolve()).catch(() => {}).then(fn); + locks.set(key, next); + try { + return await next; + } finally { + if (locks.get(key) === next) locks.delete(key); + } + } + async function write(job) { + const file = join(root, job.jobId + '.json'), + tmp = file + '.' + randomUUID() + '.tmp'; + await writeFile(tmp, JSON.stringify(job), { mode: 0o600 }); + await rename(tmp, file); + } + async function read(jobId) { + if (!id(jobId)) throw Error('任务编号无效'); + return JSON.parse(await readFile(join(root, jobId + '.json'), 'utf8')); + } + function live(editorId) { + const e = editors.get(editorId); + if (!e?.res || Date.now() - e.updatedAt > 45000) + throw Error('编辑器未连接,请打开 Mini App 后重新读取列表'); + return e; + } + return { + list() { + return [...editors.values()] + .filter((e) => e.res && Date.now() - e.updatedAt <= 45000) + .map((e) => ({ + editorId: e.id, + version: e.version, + engine: e.engine, + page: e.page, + updatedAt: e.updatedAt, + document: e.document, + busy: !!e.jobId, + })); + }, + inspect(editorId) { + const e = live(editorId); + return { + editorId, + version: e.version, + engine: e.engine, + page: e.page, + updatedAt: e.updatedAt, + document: e.document, + busy: !!e.jobId, + }; + }, + register(input) { + if (!id(input.editorId) || typeof input.version !== 'string' || input.version.length > 100) + throw Error('编辑器信息无效'); + const existing = editors.get(input.editorId); + const page = { + visibility: ['visible', 'hidden'].includes(input.page?.visibility) ? input.page.visibility : 'unknown', + focused: typeof input.page?.focused === 'boolean' ? input.page.focused : null, + }; + if (existing?.jobId) { + existing.page = page; + existing.updatedAt = Date.now(); + return { editorId: existing.id }; + } + const e = existing || { id: input.editorId }; + Object.assign(e, { + version: input.version, + engine: input.engine === 'photocraft' ? 'photocraft' : 'canvas', + page, + document: input.document, + updatedAt: Date.now(), + }); + editors.set(e.id, e); + return { editorId: e.id }; + }, + subscribe(editorId, req, res) { + const e = editors.get(editorId); + if (!e) throw Error('编辑器未注册'); + if (e.res) throw Error('编辑器连接重复'); + res.writeHead(200, { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-store', + Connection: 'keep-alive', + }); + res.write(': connected\n\n'); + e.res = res; + const timer = setInterval(() => { + res.write(': heartbeat\n\n'); + }, 15000); + req.on('close', () => { + clearInterval(timer); + if (e.res === res) e.res = null; + }); + }, + async submit(input) { + if (!id(input.requestId) || !id(input.editorId) || typeof input.expectedVersion !== 'string') + throw Error('需要 requestId、editorId、expectedVersion'); + if (!['preview', 'batch', 'export', 'create', 'craft'].includes(input.kind)) + throw Error('未知编辑任务'); + if ( + input.kind === 'batch' && + (!Array.isArray(input.operations) || + input.operations.length < 1 || + input.operations.length > 64) + ) + throw Error('每批需要 1–64 个操作'); + if ( + input.kind === 'create' && + (!Number.isInteger(input.width) || + !Number.isInteger(input.height) || + input.width < 1 || + input.height < 1 || + input.width * input.height > 32e6 || + typeof input.name !== 'string' || + !input.name.trim() || + input.name.length > 200) + ) + throw Error('新建工程参数无效'); + if (input.kind === 'craft' && ['execute', 'batch'].includes(input.options?.method)) { + const steps = input.options.method === 'batch' ? input.options.args : [input.options.args]; + if (!Array.isArray(steps) || !steps.length || steps.length > 64) + throw Error('batch 需要 1–64 个命令'); + for (const step of steps) { + if (!step || typeof step !== 'object' || Array.isArray(step) || + typeof step.command !== 'string' || !step.command.trim() || + (step.params !== undefined && (!step.params || typeof step.params !== 'object' || Array.isArray(step.params)))) + throw Error('execute/batch 需要 {command,params};params 必须是 JSON 对象'); + if (step.command === 'document.pixel' && !['x', 'y'].every(key => + Number.isInteger(step.params?.[key]) && step.params[key] >= -2147483648 && step.params[key] <= 2147483647)) + throw Error('document.pixel 的 x、y 必须是 32 位整数,例如 {x:320,y:210},不能使用字符串'); + } + } + if (input.kind === 'craft' && input.options?.method === 'export') { + const args = input.options.args ?? {}; + if (typeof args !== 'object' || Array.isArray(args)) + throw Error('export 参数必须为对象,例如 {format:"png"}'); + if (Object.keys(args).some((key) => key !== 'format')) + throw Error('export 只接受 format,不支持自定义路径。请使用 {format:"png"},从完成任务的 exportPath 获取文件;不要搜索本机目录。'); + if (args.format !== undefined && !['png', 'jpg', 'webp', 'pcraft', 'psd', 'ora', 'tif'].includes(args.format)) + throw Error('不支持的导出格式'); + } + const fingerprint = createHash('sha256') + .update(JSON.stringify(canonical(input))) + .digest('hex'); + return serial('submit', async () => { + try { + const old = await read(input.requestId); + if (old.fingerprint !== fingerprint) throw Error('requestId 已用于不同请求'); + return visible(old); + } catch (error) { + if (error.code !== 'ENOENT') throw error; + } + const e = live(input.editorId); + if (e.jobId) throw Error('编辑器正在执行另一任务'); + if (e.version !== input.expectedVersion) throw Error('工程版本已变化,请重新 inspect'); + if (input.kind === 'craft' && e.engine !== 'photocraft') + throw Error('需要 PhotoCraft 工作台'); + if ( + input.kind === 'craft' && + !['commands', 'execute', 'batch', 'draw', 'preview', 'export', 'open'].includes( + input.options?.method, + ) + ) + throw Error('未知 PhotoCraft 方法'); + if (e.engine === 'photocraft' && input.kind !== 'craft') + throw Error('PhotoCraft 请使用 photo_call 或 PTC'); + if (!e.document && !['create', 'craft'].includes(input.kind)) + throw Error('编辑器没有打开文档'); + const job = { + jobId: input.requestId, + editorId: e.id, + expectedVersion: input.expectedVersion, + kind: input.kind, + operations: input.operations || [], + options: input.options, + newDocument: + input.kind === 'create' + ? { width: input.width, height: input.height, name: input.name } + : undefined, + fingerprint, + status: 'queued', + createdAt: Date.now(), + }; + await write(job); + e.jobId = job.jobId; + e.res.write('event: command\ndata: ' + JSON.stringify({ jobId: job.jobId }) + '\n\n'); + return visible(job); + }); + }, + async claim(editorId, jobId) { + return serial(jobId, async () => { + const e = live(editorId), + j = await read(jobId); + if (e.jobId !== jobId || j.editorId !== editorId || j.status !== 'queued') + throw Error('任务不能重复领取'); + j.status = 'running'; + j.startedAt = Date.now(); + j.claim = randomUUID(); + await write(j); + return j; + }); + }, + async finish(editorId, jobId, input) { + return serial(jobId, async () => { + const j = await read(jobId); + if (j.editorId !== editorId || input.claim !== j.claim) throw Error('任务归属不匹配'); + if (['prepared', 'succeeded', 'failed'].includes(j.status)) return visible(j); + if (j.status !== 'running') throw Error('任务状态无效'); + if (input.error) { + j.status = 'failed'; + j.error = String(input.error).slice(0, 1000); + } else { + if ( + typeof input.preview !== 'string' || + !input.preview.startsWith('data:image/png;base64,') + ) + throw Error('缺少预览'); + const bytes = Buffer.from(input.preview.slice(22), 'base64'); + await validatePNG(bytes); + if ( + ['batch', 'export', 'create'].includes(j.kind) && + (input.checkpoint?.format !== 'retouch-lab' || + (j.kind === 'create' + ? !id(input.checkpoint?.id) + : input.checkpoint?.id !== editors.get(editorId)?.document?.id)) + ) + throw Error('缺少同一工程的检查点'); + if (j.kind === 'craft' && input.craftExport) { + const format = input.craftExport.format; + if (!['png', 'jpg', 'webp', 'pcraft', 'psd', 'ora', 'tif'].includes(format)) + throw Error('导出格式无效'); + const bytes = Buffer.from(input.craftExport.data, 'base64'); + if (!bytes.length || bytes.length > 64 * 1024 * 1024) throw Error('导出大小无效'); + j.craftExport = { format, data: input.craftExport.data }; + j.exportPath = join(root, jobId + '.' + format); + } + j.status = 'prepared'; + j.preview = input.preview; + if (j.kind === 'export') { + if ( + typeof input.exportImage !== 'string' || + !input.exportImage.startsWith('data:image/png;base64,') + ) + throw Error('导出图片无效'); + await validatePNG(Buffer.from(input.exportImage.slice(22), 'base64')); + j.exportImage = input.exportImage; + j.exportPath = join(root, jobId + '.full.png'); + } + j.checkpoint = input.checkpoint; + j.result = input.result; + j.previewPath = join(root, jobId + '.png'); + if (input.checkpoint) j.checkpointPath = join(root, jobId + '.retouch.json'); + } + j.finishedAt = Date.now(); + await write(j); + const e = editors.get(editorId); + if (e?.jobId === jobId && j.status === 'failed') e.jobId = null; + // The job JSON is the durable source of truth; artifacts can be regenerated after a crash. + return visible(j); + }); + }, + async acknowledge(editorId, jobId, input) { + return serial(jobId, async () => { + const j = await read(jobId); + if (j.editorId !== editorId || j.claim !== input.claim) throw Error('任务归属不匹配'); + if (j.status === 'succeeded') return visible(j); + if (j.status !== 'prepared') throw Error('任务尚未准备好'); + if (typeof input.version !== 'string' || input.version.length > 100) + throw Error('缺少编辑版本'); + j.status = 'succeeded'; + j.appliedVersion = input.version; + j.appliedAt = Date.now(); + await write(j); + const e = editors.get(editorId); + if (e?.jobId === jobId) { + e.jobId = null; + e.version = input.version; + e.updatedAt = Date.now(); + const { steps, previewScale, region, pixels, ...document } = j.result; + e.document = j.kind === 'craft' ? (j.result.state?.document ?? null) : document; + } + return visible(j); + }); + }, + async result(jobId) { + const j = await read(jobId); + if (['prepared', 'succeeded'].includes(j.status)) { + await writeFile(join(root, jobId + '.png'), Buffer.from(j.preview.slice(22), 'base64'), { + mode: 0o600, + }); + if (j.craftExport) + await writeFile(j.exportPath, Buffer.from(j.craftExport.data, 'base64'), { mode: 0o600 }); + if (j.exportImage) + await writeFile( + join(root, jobId + '.full.png'), + Buffer.from(j.exportImage.slice(22), 'base64'), + { mode: 0o600 }, + ); + if (j.checkpoint) + await writeFile(join(root, jobId + '.retouch.json'), JSON.stringify(j.checkpoint), { + mode: 0o600, + }); + } + const result = visible(j); + const e = editors.get(j.editorId); + if (['queued', 'running'].includes(j.status) && (!e?.res || e.jobId !== jobId)) + return { + ...result, + status: 'interrupted', + error: '页面或服务连接已断开;不自动重放。读取工程和已保存检查点后再决定下一步。', + }; + return result; + }, + async preview(jobId) { + const j = await read(jobId); + if (!['prepared', 'succeeded'].includes(j.status)) throw Error('预览尚不可用'); + return j.preview.slice(22); + }, + close() { + for (const e of editors.values()) e.res?.end(); + editors.clear(); + }, + }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/node/miniapp-api.ts b/plugins/webguhui/minimax-photo/miniapp/node/miniapp-api.ts new file mode 100644 index 00000000..7a0e0fd3 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/node/miniapp-api.ts @@ -0,0 +1,109 @@ +/** + * Agent-facing Mini App runtime authoring declarations. + * + * Copy this file into a generated plugin for type checking. It contains no Host implementation; + * the Host injects runtime values through start(context). + * Keep the .ts filename: Electron packaging excludes .d.ts files from dependency assets. + */ +export type JsonPrimitive = null | boolean | number | string; +export type JsonValue = JsonPrimitive | JsonObject | readonly JsonValue[]; +export type JsonObject = { readonly [key: string]: JsonValue }; + +declare const HOST_CONNECTOR_TOOL_REF: unique symbol; +export type HostConnectorToolRef = string & { + readonly [HOST_CONNECTOR_TOOL_REF]: 'HostConnectorToolRef'; +}; + +export interface HostConnectorTool { + readonly toolRef: HostConnectorToolRef; + readonly provider: string; + readonly name: string; + readonly description?: string; + readonly inputSchema: JsonValue; + readonly outputSchema?: JsonValue; +} + +export interface HostConnectorListResult { + readonly tools: readonly HostConnectorTool[]; + readonly partial: boolean; +} + +export interface HostConnectorCallOptions { + readonly signal?: AbortSignal; +} + +export interface HostConnectorCallResult { + readonly invocationId: string; + /** + * Raw provider result; it is not normalized by the Host and may be an object, array, or primitive. + * A single text-block array is one provider shape, not a global Host transport contract. + * Decode only a probe-observed envelope; preserve every other value, including direct strings. + */ + readonly value: JsonValue; +} + +export interface HostConnectorClient { + /** Candidate-safe inventory only; available before and after activation. */ + list(options?: HostConnectorCallOptions): Promise; + /** Activation-only business dispatch; call from request handling, never start(context). */ + call( + toolRef: HostConnectorToolRef, + arguments_: JsonObject, + options?: HostConnectorCallOptions, + ): Promise; +} + +export type HostConnectorErrorDisposition = + | 'not_dispatched' + | 'provider_reported' + | 'unknown_after_dispatch'; + +export type HostConnectorErrorCode = + | 'TOOL_REF_STALE' + | 'SERVICE_RESTARTED' + | 'REQUEST_CANCELLED' + | 'CONNECTOR_TIMEOUT' + | 'INVALID_ARGUMENTS' + | 'CONNECTOR_PROVIDER_ERROR' + | 'CONNECTOR_UNAVAILABLE' + | 'CONNECTOR_OUTCOME_UNKNOWN'; + +export interface HostConnectorError extends Error { + readonly code: HostConnectorErrorCode; + readonly disposition: HostConnectorErrorDisposition; + readonly retryable: boolean; + readonly invocationId?: string; + readonly diagnostic?: { + readonly issues: readonly { + readonly path: string; + readonly constraint: string; + readonly limit?: number; + }[]; + }; +} + +export interface MiniAppLogger { + debug(message: string, fields?: JsonObject): void; + info(message: string, fields?: JsonObject): void; + warn(message: string, fields?: JsonObject): void; + error(message: string, fields?: JsonObject): void; +} + +export interface MiniAppLifecycle { + dispose(): void | Promise; +} + +export interface MiniAppContext { + readonly pluginId: string; + readonly pluginRoot: string; + readonly dataDir: string; + readonly listen: Readonly<{ readonly host: '127.0.0.1'; readonly port: number }>; + readonly signal: AbortSignal; + readonly logger: MiniAppLogger; + readonly hostConnector?: HostConnectorClient; +} + +export interface MiniAppModule { + /** Resolve only after the listener accepts connections and every route is installed. */ + start(context: MiniAppContext): Promise; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/node/png-validation.mjs b/plugins/webguhui/minimax-photo/miniapp/node/png-validation.mjs new file mode 100644 index 00000000..023c6d27 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/node/png-validation.mjs @@ -0,0 +1,79 @@ +import { inflate } from 'node:zlib'; +import { promisify } from 'node:util'; +const unzip = promisify(inflate); +const table = Uint32Array.from({ length: 256 }, (_, n) => { + for (let k = 0; k < 8; k++) n = n & 1 ? 0xedb88320 ^ (n >>> 1) : n >>> 1; + return n >>> 0; +}); +function crc(bytes) { + let n = 0xffffffff; + for (const byte of bytes) n = table[(n ^ byte) & 255] ^ (n >>> 8); + return (n ^ 0xffffffff) >>> 0; +} +export async function validatePNG(buffer) { + if ( + buffer.length < 45 || + buffer.length > 16 * 1024 * 1024 || + buffer.subarray(0, 8).toString('hex') !== '89504e470d0a1a0a' + ) + throw Error('需要不超过 16 MB 的 PNG 图片'); + let offset = 8, + width, + height, + channels, + ended = false, + palette = false, + indexed = false, + dataEnded = false; + const compressed = []; + while (offset + 12 <= buffer.length) { + const size = buffer.readUInt32BE(offset), + end = offset + 12 + size; + if (end > buffer.length) throw Error('PNG 文件不完整'); + const type = buffer.toString('ascii', offset + 4, offset + 8), + data = buffer.subarray(offset + 8, offset + 8 + size); + if ( + crc(buffer.subarray(offset + 4, offset + 8 + size)) !== buffer.readUInt32BE(offset + 8 + size) + ) + throw Error('PNG 校验失败'); + if (!/^[A-Za-z]{4}$/.test(type)) throw Error('PNG 数据块名称无效'); + if (!['IHDR', 'PLTE', 'IDAT', 'IEND'].includes(type) && !(buffer[offset + 4] & 32)) + throw Error('PNG 包含无法识别的关键数据'); + if (compressed.length && type !== 'IDAT') dataEnded = true; + if (offset === 8 && type !== 'IHDR') throw Error('PNG 文件头无效'); + if (type === 'IHDR') { + if (offset !== 8 || size !== 13) throw Error('PNG 文件头无效'); + width = data.readUInt32BE(0); + height = data.readUInt32BE(4); + channels = { 0: 1, 2: 3, 3: 1, 4: 2, 6: 4 }[data[9]]; + if (!width || !height || width * height > 32e6) throw Error('图片尺寸超过限制'); + indexed = data[9] === 3; + if (data[8] !== 8 || !channels || data[10] !== 0 || data[11] !== 0 || data[12] !== 0) + throw Error('请返回 8 位非交错 PNG'); + } else if (type === 'PLTE') { + if (palette || compressed.length || !size || size > 768 || size % 3) + throw Error('PNG 调色板无效'); + palette = true; + } else if (type === 'IDAT') { + if (dataEnded || (indexed && !palette)) throw Error('PNG 数据块顺序无效'); + compressed.push(data); + } else if (type === 'IEND') { + if (size !== 0 || end !== buffer.length) throw Error('PNG 结尾无效'); + ended = true; + break; + } + offset = end; + } + if ((indexed && !palette) || !ended || !compressed.length) throw Error('PNG 缺少图像数据'); + const stride = width * channels + 1, + expected = stride * height; + let pixels; + try { + pixels = await unzip(Buffer.concat(compressed), { maxOutputLength: expected }); + } catch { + throw Error('PNG 图像数据无效'); + } + if (pixels.length !== expected) throw Error('PNG 图像数据长度无效'); + for (let y = 0; y < height; y++) if (pixels[y * stride] > 4) throw Error('PNG 行过滤无效'); + return { width, height }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/node/ptc-worker.mjs b/plugins/webguhui/minimax-photo/miniapp/node/ptc-worker.mjs new file mode 100644 index 00000000..d8666ab5 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/node/ptc-worker.mjs @@ -0,0 +1,24 @@ +var Wt=Object.defineProperty;var W=(e,r)=>()=>(e&&(r=e(e=0)),r);var ve=(e,r)=>{for(var t in r)Wt(e,t,{get:r[t],enumerable:!0})};var F,be,ee,C,$,te=W(()=>{F={JS_EVAL_TYPE_GLOBAL:0,JS_EVAL_TYPE_MODULE:1,JS_EVAL_TYPE_DIRECT:2,JS_EVAL_TYPE_INDIRECT:3,JS_EVAL_TYPE_MASK:3,JS_EVAL_FLAG_STRICT:8,JS_EVAL_FLAG_STRIP:16,JS_EVAL_FLAG_COMPILE_ONLY:32,JS_EVAL_FLAG_BACKTRACE_BARRIER:64},be={BaseObjects:1,Date:2,Eval:4,StringNormalize:8,RegExp:16,RegExpCompiler:32,JSON:64,Proxy:128,MapSet:256,TypedArrays:512,Promise:1024,BigInt:2048,BigFloat:4096,BigDecimal:8192,OperatorOverloading:16384,BignumExt:32768},ee={Pending:0,Fulfilled:1,Rejected:2},C={JS_GPN_STRING_MASK:1,JS_GPN_SYMBOL_MASK:2,JS_GPN_PRIVATE_MASK:4,JS_GPN_ENUM_ONLY:16,JS_GPN_SET_ENUM:32,QTS_GPN_NUMBER_MASK:64,QTS_STANDARD_COMPLIANT_NUMBER:128},$={IsStrictlyEqual:0,IsSameValue:1,IsSameValueZero:2}});function H(...e){Ee&&console.log("quickjs-emscripten:",...e)}function*wt(e){return yield e}function Kt(e){return wt(ke(e))}function rt(e,r){return(...t)=>{let i=r.call(e,Re,...t);return ke(i)}}function Yt(e,r){let t=r.call(e,Re);return ke(t)}function ke(e){function r(t){return t.done?t.value:t.value instanceof Promise?t.value.then(i=>r(e.next(i)),i=>r(e.throw(i))):r(e.next(t.value))}return r(e.next())}function Te(e,r){let t;try{e.dispose()}catch(i){t=i}if(r&&t)throw Object.assign(r,{message:`${r.message} + Then, failed to dispose scope: ${t.message}`,disposeError:t}),r;if(r||t)throw r||t}function yt(e){let r=e?Array.from(e):[];function t(){return r.forEach(u=>u.alive?u.dispose():void 0)}function i(){return r.some(u=>u.alive)}return Object.defineProperty(r,Me,{configurable:!0,enumerable:!1,value:t}),Object.defineProperty(r,"dispose",{configurable:!0,enumerable:!1,value:t}),Object.defineProperty(r,"alive",{configurable:!0,enumerable:!1,get:i}),r}function ne(e){return!!(e&&(typeof e=="object"||typeof e=="function")&&"alive"in e&&typeof e.alive=="boolean"&&"dispose"in e&&typeof e.dispose=="function")}function Zt(e){if(!e)return 0;let r=0;for(let[t,i]of Object.entries(e)){if(!(t in be))throw new dt(t);i&&(r|=be[t])}return r}function er(e){if(typeof e=="number")return e;if(e===void 0)return 0;let{type:r,strict:t,strip:i,compileOnly:u,backtraceBarrier:a}=e,l=0;return r==="global"&&(l|=F.JS_EVAL_TYPE_GLOBAL),r==="module"&&(l|=F.JS_EVAL_TYPE_MODULE),t&&(l|=F.JS_EVAL_FLAG_STRICT),i&&(l|=F.JS_EVAL_FLAG_STRIP),u&&(l|=F.JS_EVAL_FLAG_COMPILE_ONLY),a&&(l|=F.JS_EVAL_FLAG_BACKTRACE_BARRIER),l}function tr(e){if(typeof e=="number")return e;if(e===void 0)return 0;let{strings:r,symbols:t,quickjsPrivate:i,onlyEnumerable:u,numbers:a,numbersAsStrings:l}=e,m=0;return r&&(m|=C.JS_GPN_STRING_MASK),t&&(m|=C.JS_GPN_SYMBOL_MASK),i&&(m|=C.JS_GPN_PRIVATE_MASK),u&&(m|=C.JS_GPN_ENUM_ONLY),a&&(m|=C.QTS_GPN_NUMBER_MASK),l&&(m|=C.QTS_STANDARD_COMPLIANT_NUMBER),m}function rr(...e){let r=[];for(let t of e)t!==void 0&&(r=r.concat(t));return r}function Qe(e){return e>>8}function Je(e,r){r.interruptHandler&&e.setInterruptHandler(r.interruptHandler),r.maxStackSizeBytes!==void 0&&e.setMaxStackSize(r.maxStackSizeBytes),r.memoryLimitBytes!==void 0&&e.setMemoryLimit(r.memoryLimitBytes)}function Ne(e,r){r.moduleLoader&&e.setModuleLoader(r.moduleLoader),r.shouldInterrupt&&e.setInterruptHandler(r.shouldInterrupt),r.memoryLimitBytes!==void 0&&e.setMemoryLimit(r.memoryLimitBytes),r.maxStackSizeBytes!==void 0&&e.setMaxStackSize(r.maxStackSizeBytes)}var $t,qt,Ee,ut,xe,at,Pe,lt,mt,ht,ct,se,dt,ft,pt,St,I,Re,A,Me,it,b,L,Ae,M,Le,vt,bt,O,Tt,Qt,vr,Xt,ir,nt,st,ie,nr,ot,sr,xt,Pt,or,Ie,Fe,Ce=W(()=>{te();te();$t=Object.defineProperty,qt=(e,r)=>{for(var t in r)$t(e,t,{get:r[t],enumerable:!0})},Ee=!1;ut={};qt(ut,{QuickJSAsyncifyError:()=>mt,QuickJSAsyncifySuspended:()=>ht,QuickJSEmptyGetOwnPropertyNames:()=>pt,QuickJSEmscriptenModuleError:()=>se,QuickJSHostRefInvalid:()=>I,QuickJSHostRefRangeExceeded:()=>St,QuickJSMemoryLeakDetected:()=>ct,QuickJSNotImplemented:()=>lt,QuickJSPromisePending:()=>ft,QuickJSUnknownIntrinsic:()=>dt,QuickJSUnwrapError:()=>xe,QuickJSUseAfterFree:()=>Pe,QuickJSWrongOwner:()=>at});xe=class extends Error{constructor(e,r){let t=typeof e=="object"&&e&&"message"in e?String(e.message):String(e);super(t),this.cause=e,this.context=r,this.name="QuickJSUnwrapError"}},at=class extends Error{constructor(){super(...arguments),this.name="QuickJSWrongOwner"}},Pe=class extends Error{constructor(){super(...arguments),this.name="QuickJSUseAfterFree"}},lt=class extends Error{constructor(){super(...arguments),this.name="QuickJSNotImplemented"}},mt=class extends Error{constructor(){super(...arguments),this.name="QuickJSAsyncifyError"}},ht=class extends Error{constructor(){super(...arguments),this.name="QuickJSAsyncifySuspended"}},ct=class extends Error{constructor(){super(...arguments),this.name="QuickJSMemoryLeakDetected"}},se=class extends Error{constructor(){super(...arguments),this.name="QuickJSEmscriptenModuleError"}},dt=class extends TypeError{constructor(){super(...arguments),this.name="QuickJSUnknownIntrinsic"}},ft=class extends Error{constructor(){super(...arguments),this.name="QuickJSPromisePending"}},pt=class extends Error{constructor(){super(...arguments),this.name="QuickJSEmptyGetOwnPropertyNames"}},St=class extends Error{constructor(){super(...arguments),this.name="QuickJSHostRefRangeExceeded"}},I=class extends Error{constructor(){super(...arguments),this.name="QuickJSHostRefInvalid"}};Re=wt;Re.of=Kt;A=class{[Symbol.dispose](){return this.dispose()}},Me=Symbol.dispose??Symbol.for("Symbol.dispose"),it=A.prototype;it[Me]||(it[Me]=function(){return this.dispose()});b=class _t extends A{constructor(r,t,i,u){super(),this._value=r,this.copier=t,this.disposer=i,this._owner=u,this._alive=!0,this._constructorStack=Ee?new Error("Lifetime constructed").stack:void 0}get alive(){return this._alive}get value(){return this.assertAlive(),this._value}get owner(){return this._owner}get dupable(){return!!this.copier}dup(){if(this.assertAlive(),!this.copier)throw new Error("Non-dupable lifetime");return new _t(this.copier(this._value),this.copier,this.disposer,this._owner)}consume(r){this.assertAlive();let t=r(this);return this.dispose(),t}map(r){return this.assertAlive(),r(this)}tap(r){return r(this),this}dispose(){this.assertAlive(),this.disposer&&this.disposer(this._value),this._alive=!1}assertAlive(){if(!this.alive)throw this._constructorStack?new Pe(`Lifetime not alive +${this._constructorStack} +Lifetime used`):new Pe("Lifetime not alive")}},L=class extends b{constructor(e,r){super(e,void 0,void 0,r)}get dupable(){return!0}dup(){return this}dispose(){}},Ae=class extends b{constructor(e,r,t,i){super(e,r,t,i)}dispose(){this._alive=!1}};M=class re extends A{constructor(){super(...arguments),this._disposables=new b(new Set),this.manage=r=>(this._disposables.value.add(r),r)}static withScope(r){let t=new re,i;try{return r(t)}catch(u){throw i=u,u}finally{Te(t,i)}}static withScopeMaybeAsync(r,t){return Yt(void 0,function*(i){let u=new re,a;try{return yield*i.of(t.call(r,i,u))}catch(l){throw a=l,l}finally{Te(u,a)}})}static async withScopeAsync(r){let t=new re,i;try{return await r(t)}catch(u){throw i=u,u}finally{Te(t,i)}}get alive(){return this._disposables.alive}dispose(){let r=Array.from(this._disposables.value.values()).reverse();for(let t of r)t.alive&&t.dispose();this._disposables.dispose()}};Le=class gt extends A{static success(r){return new vt(r)}static fail(r,t){return new bt(r,t)}static is(r){return r instanceof gt}},vt=class extends Le{constructor(e){super(),this.value=e}get alive(){return ne(this.value)?this.value.alive:!0}dispose(){ne(this.value)&&this.value.dispose()}unwrap(){return this.value}unwrapOr(e){return this.value}},bt=class extends Le{constructor(e,r){super(),this.error=e,this.onUnwrap=r}get alive(){return ne(this.error)?this.error.alive:!0}dispose(){ne(this.error)&&this.error.dispose()}unwrap(){throw this.onUnwrap(this),this.error}unwrapOr(e){return e}},O=Le,Tt=class extends A{constructor(e){super(),this.resolve=r=>{this.resolveHandle.alive&&(this.context.unwrapResult(this.context.callFunction(this.resolveHandle,this.context.undefined,r||this.context.undefined)).dispose(),this.disposeResolvers(),this.onSettled())},this.reject=r=>{this.rejectHandle.alive&&(this.context.unwrapResult(this.context.callFunction(this.rejectHandle,this.context.undefined,r||this.context.undefined)).dispose(),this.disposeResolvers(),this.onSettled())},this.dispose=()=>{this.handle.alive&&this.handle.dispose(),this.disposeResolvers()},this.context=e.context,this.owner=e.context.runtime,this.handle=e.promiseHandle,this.settled=new Promise(r=>{this.onSettled=r}),this.resolveHandle=e.resolveHandle,this.rejectHandle=e.rejectHandle}get alive(){return this.handle.alive||this.resolveHandle.alive||this.rejectHandle.alive}disposeResolvers(){this.resolveHandle.alive&&this.resolveHandle.dispose(),this.rejectHandle.alive&&this.rejectHandle.dispose()}},Qt=class{constructor(e){this.module=e}toPointerArray(e){let r=new Int32Array(e.map(u=>u.value)),t=r.length*r.BYTES_PER_ELEMENT,i=this.module._malloc(t);return new Uint8Array(this.module.HEAPU8.buffer,i,t).set(new Uint8Array(r.buffer)),new b(i,void 0,u=>this.module._free(u))}newTypedArray(e,r){let t=new e(new Array(r).fill(0)),i=t.length*t.BYTES_PER_ELEMENT,u=this.module._malloc(i),a=new e(this.module.HEAPU8.buffer,u,r);return a.set(t),new b({typedArray:a,ptr:u},void 0,l=>this.module._free(l.ptr))}newMutablePointerArray(e){return this.newTypedArray(Int32Array,e)}newHeapCharPointer(e){let r=this.module.lengthBytesUTF8(e),t=r+1,i=this.module._malloc(t);return this.module.stringToUTF8(e,i,t),new b({ptr:i,strlen:r},void 0,u=>this.module._free(u.ptr))}newHeapBufferPointer(e){let r=e.byteLength,t=this.module._malloc(r);return this.module.HEAPU8.set(e,t),new b({pointer:t,numBytes:r},void 0,i=>this.module._free(i.pointer))}consumeHeapCharPointer(e){let r=this.module.UTF8ToString(e);return this.module._free(e),r}},vr=Symbol("Unstable"),Xt=Object.freeze({BaseObjects:!0,Date:!0,Eval:!0,StringNormalize:!0,RegExp:!0,JSON:!0,Proxy:!0,MapSet:!0,TypedArrays:!0,Promise:!0});ir=class extends A{constructor(e,r){super(),this.handle=e,this.context=r,this._isDone=!1,this.owner=r.runtime}[Symbol.iterator](){return this}next(e){if(!this.alive||this._isDone)return{done:!0,value:void 0};let r=this._next??(this._next=this.context.getProp(this.handle,"next"));return this.callIteratorMethod(r,e)}return(e){if(!this.alive)return{done:!0,value:void 0};let r=this.context.getProp(this.handle,"return");if(r===this.context.undefined&&e===void 0)return this.dispose(),{done:!0,value:void 0};let t=this.callIteratorMethod(r,e);return r.dispose(),this.dispose(),t}throw(e){if(!this.alive)return{done:!0,value:void 0};let r=e instanceof b?e:this.context.newError(e),t=this.context.getProp(this.handle,"throw"),i=this.callIteratorMethod(t,e);return r.alive&&r.dispose(),t.dispose(),this.dispose(),i}get alive(){return this.handle.alive}dispose(){this._isDone=!0,this.handle.dispose(),this._next?.dispose()}callIteratorMethod(e,r){let t=r?this.context.callFunction(e,this.handle,r):this.context.callFunction(e,this.handle);if(t.error)return this.dispose(),{value:t};let i=this.context.getProp(t.value,"done").consume(a=>this.context.dump(a)),u=this.context.getProp(t.value,"value");return t.value.dispose(),i&&this.dispose(),{value:O.success(u),done:i}}},nt=-2147483648,st=2147483647,ie=0;nr=class{constructor(){this.nextId=nt,this.freelist=[],this.groups=new Map}put(e){let r=this.allocateId(),t=Qe(r),i=this.groups.get(t);return i||(i=new Map,this.groups.set(t,i)),i.set(r,e),r}get(e){if(e===ie)throw new I("no host reference id defined");let r=Qe(e),t=this.groups.get(r);if(!t)throw new I(`host reference id ${e} is not defined`);let i=t.get(e);if(!i)throw new I(`host reference id ${e} is not defined`);return i}delete(e){if(e===ie)throw new I("no host reference id defined");let r=Qe(e),t=this.groups.get(r);if(!t)throw new I(`host reference id ${e} is not defined`);t.delete(e),t.size===0&&this.groups.delete(r),this.freelist.push(e)}allocateId(){if(this.freelist.length>0)return this.freelist.shift();if(this.nextId===ie&&this.nextId++,this.nextId>st)throw new St(`HostRefMap: too many host refs created without disposing. Max simultaneous host refs: ${st-nt}`);return this.nextId++}},ot=class extends A{constructor(e,r,t){if(t===ie)throw new I("cannot create HostRef with undefined id");super(),this.runtime=e,this.handle=r,this.id=t}get alive(){return this.handle.alive}dispose(){this.handle.dispose()}get value(){return this.runtime.hostRefs.get(this.id)}},sr=class extends Qt{constructor(e){super(e.module),this.scope=new M,this.copyJSValue=r=>this.ffi.QTS_DupValuePointer(this.ctx.value,r),this.freeJSValue=r=>{this.ffi.QTS_FreeValuePointer(this.ctx.value,r)},e.ownedLifetimes?.forEach(r=>this.scope.manage(r)),this.owner=e.owner,this.module=e.module,this.ffi=e.ffi,this.rt=e.rt,this.ctx=this.scope.manage(e.ctx)}get alive(){return this.scope.alive}dispose(){return this.scope.dispose()}[Symbol.dispose](){return this.dispose()}manage(e){return this.scope.manage(e)}consumeJSCharPointer(e){let r=this.module.UTF8ToString(e);return this.ffi.QTS_FreeCString(this.ctx.value,e),r}heapValueHandle(e,r){let t=r?i=>{r(),this.freeJSValue(i)}:this.freeJSValue;return new b(e,this.copyJSValue,t,this.owner)}staticHeapValueHandle(e){return this.manage(this.heapValueHandle(e)),new L(e,this.owner)}},xt=class extends A{constructor(e){super(),this._undefined=void 0,this._null=void 0,this._false=void 0,this._true=void 0,this._global=void 0,this._BigInt=void 0,this._Symbol=void 0,this._SymbolIterator=void 0,this._SymbolAsyncIterator=void 0,this.cToHostCallbacks={callFunction:(r,t,i,u,a)=>{if(r!==this.ctx.value)throw new Error("QuickJSContext instance received C -> JS call with mismatched ctx");let l=this.getFunction(a);return M.withScopeMaybeAsync(this,function*(m,d){let T=d.manage(new Ae(t,this.memory.copyJSValue,this.memory.freeJSValue,this.runtime)),y=new Array(i);for(let c=0;cthis.ffi.QTS_Throw(this.ctx.value,_.value))}})}},this.runtime=e.runtime,this.module=e.module,this.ffi=e.ffi,this.rt=e.rt,this.ctx=e.ctx,this.memory=new sr({...e,owner:this.runtime}),e.callbacks.setContextCallbacks(this.ctx.value,this.cToHostCallbacks),this.dump=this.dump.bind(this),this.getString=this.getString.bind(this),this.getNumber=this.getNumber.bind(this),this.resolvePromise=this.resolvePromise.bind(this),this.uint32Out=this.memory.manage(this.memory.newTypedArray(Uint32Array,1))}get alive(){return this.memory.alive}dispose(){this.memory.dispose()}get undefined(){if(this._undefined)return this._undefined;let e=this.ffi.QTS_GetUndefined();return this._undefined=new L(e)}get null(){if(this._null)return this._null;let e=this.ffi.QTS_GetNull();return this._null=new L(e)}get true(){if(this._true)return this._true;let e=this.ffi.QTS_GetTrue();return this._true=new L(e)}get false(){if(this._false)return this._false;let e=this.ffi.QTS_GetFalse();return this._false=new L(e)}get global(){if(this._global)return this._global;let e=this.ffi.QTS_GetGlobalObject(this.ctx.value);return this._global=this.memory.staticHeapValueHandle(e),this._global}newNumber(e){return this.memory.heapValueHandle(this.ffi.QTS_NewFloat64(this.ctx.value,e))}newString(e){let r=this.memory.newHeapCharPointer(e).consume(t=>this.ffi.QTS_NewString(this.ctx.value,t.value.ptr));return this.memory.heapValueHandle(r)}newUniqueSymbol(e){let r=(typeof e=="symbol"?e.description:e)??"",t=this.memory.newHeapCharPointer(r).consume(i=>this.ffi.QTS_NewSymbol(this.ctx.value,i.value.ptr,0));return this.memory.heapValueHandle(t)}newSymbolFor(e){let r=(typeof e=="symbol"?e.description:e)??"",t=this.memory.newHeapCharPointer(r).consume(i=>this.ffi.QTS_NewSymbol(this.ctx.value,i.value.ptr,1));return this.memory.heapValueHandle(t)}getWellKnownSymbol(e){return this._Symbol??(this._Symbol=this.memory.manage(this.getProp(this.global,"Symbol"))),this.getProp(this._Symbol,e)}newBigInt(e){if(!this._BigInt){let i=this.getProp(this.global,"BigInt");this.memory.manage(i),this._BigInt=new L(i.value,this.runtime)}let r=this._BigInt,t=String(e);return this.newString(t).consume(i=>this.unwrapResult(this.callFunction(r,this.undefined,i)))}newObject(e){e&&this.runtime.assertOwned(e);let r=e?this.ffi.QTS_NewObjectProto(this.ctx.value,e.value):this.ffi.QTS_NewObject(this.ctx.value);return this.memory.heapValueHandle(r)}newArray(){let e=this.ffi.QTS_NewArray(this.ctx.value);return this.memory.heapValueHandle(e)}newArrayBuffer(e){let r=new Uint8Array(e),t=this.memory.newHeapBufferPointer(r),i=this.ffi.QTS_NewArrayBuffer(this.ctx.value,t.value.pointer,r.length);return this.memory.heapValueHandle(i)}newPromise(e){let r=M.withScope(t=>{let i=t.manage(this.memory.newMutablePointerArray(2)),u=this.ffi.QTS_NewPromiseCapability(this.ctx.value,i.value.ptr),a=this.memory.heapValueHandle(u),[l,m]=Array.from(i.value.typedArray).map(d=>this.memory.heapValueHandle(d));return new Tt({context:this,promiseHandle:a,resolveHandle:l,rejectHandle:m})});return e&&typeof e=="function"&&(e=new Promise(e)),e&&Promise.resolve(e).then(r.resolve,t=>t instanceof b?r.reject(t):this.newError(t).consume(r.reject)),r}newFunction(e,r){let t=typeof e=="function"?e:r;if(!t)throw new TypeError("Expected a function");return this.newFunctionWithOptions({name:typeof e=="string"?e:void 0,length:t.length,isConstructor:!1,fn:t})}newConstructorFunction(e,r){let t=typeof e=="function"?e:r;if(!t)throw new TypeError("Expected a function");return this.newFunctionWithOptions({name:typeof e=="string"?e:void 0,length:t.length,isConstructor:!0,fn:t})}newFunctionWithOptions(e){let{name:r,length:t,isConstructor:i,fn:u}=e,a=this.runtime.hostRefs.put(u);try{return this.memory.heapValueHandle(this.ffi.QTS_NewFunction(this.ctx.value,r??"",t,i,a))}catch(l){throw this.runtime.hostRefs.delete(a),l}}newError(e){let r=this.memory.heapValueHandle(this.ffi.QTS_NewError(this.ctx.value));return e&&typeof e=="object"?(e.name!==void 0&&this.newString(e.name).consume(t=>this.setProp(r,"name",t)),e.message!==void 0&&this.newString(e.message).consume(t=>this.setProp(r,"message",t))):typeof e=="string"?this.newString(e).consume(t=>this.setProp(r,"message",t)):e!==void 0&&this.newString(String(e)).consume(t=>this.setProp(r,"message",t)),r}newHostRef(e){let r=this.runtime.hostRefs.put(e);try{let t=this.memory.heapValueHandle(this.ffi.QTS_NewHostRef(this.ctx.value,r));return new ot(this.runtime,t,r)}catch(t){throw this.runtime.hostRefs.delete(r),t}}toHostRef(e){let r=this.ffi.QTS_GetHostRefId(e.value);if(r!==0)return this.runtime.hostRefs.get(r),new ot(this.runtime,e.dup(),r)}unwrapHostRef(e){let r=this.ffi.QTS_GetHostRefId(e.value);if(r===0)throw new I("handle is not a HostRef");return this.runtime.hostRefs.get(r)}typeof(e){return this.runtime.assertOwned(e),this.memory.consumeHeapCharPointer(this.ffi.QTS_Typeof(this.ctx.value,e.value))}getNumber(e){return this.runtime.assertOwned(e),this.ffi.QTS_GetFloat64(this.ctx.value,e.value)}getString(e){return this.runtime.assertOwned(e),this.memory.consumeJSCharPointer(this.ffi.QTS_GetString(this.ctx.value,e.value))}getSymbol(e){this.runtime.assertOwned(e);let r=this.memory.consumeJSCharPointer(this.ffi.QTS_GetSymbolDescriptionOrKey(this.ctx.value,e.value));return this.ffi.QTS_IsGlobalSymbol(this.ctx.value,e.value)?Symbol.for(r):Symbol(r)}getBigInt(e){this.runtime.assertOwned(e);let r=this.getString(e);return BigInt(r)}getArrayBuffer(e){this.runtime.assertOwned(e);let r=this.ffi.QTS_GetArrayBufferLength(this.ctx.value,e.value),t=this.ffi.QTS_GetArrayBuffer(this.ctx.value,e.value);if(!t)throw new Error("Couldn't allocate memory to get ArrayBuffer");return new b(this.module.HEAPU8.subarray(t,t+r),void 0,()=>this.module._free(t))}getPromiseState(e){this.runtime.assertOwned(e);let r=this.ffi.QTS_PromiseState(this.ctx.value,e.value);if(r<0)return{type:"fulfilled",value:e,notAPromise:!0};if(r===ee.Pending)return{type:"pending",get error(){return new ft("Cannot unwrap a pending promise")}};let t=this.ffi.QTS_PromiseResult(this.ctx.value,e.value),i=this.memory.heapValueHandle(t);if(r===ee.Fulfilled)return{type:"fulfilled",value:i};if(r===ee.Rejected)return{type:"rejected",error:i};throw i.dispose(),new Error(`Unknown JSPromiseStateEnum: ${r}`)}resolvePromise(e){this.runtime.assertOwned(e);let r=M.withScope(t=>{let i=t.manage(this.getProp(this.global,"Promise")),u=t.manage(this.getProp(i,"resolve"));return this.callFunction(u,i,e)});return r.error?Promise.resolve(r):new Promise(t=>{M.withScope(i=>{let u=i.manage(this.newFunction("resolve",d=>{t(this.success(d&&d.dup()))})),a=i.manage(this.newFunction("reject",d=>{t(this.fail(d&&d.dup()))})),l=i.manage(r.value),m=i.manage(this.getProp(l,"then"));this.callFunction(m,l,u,a).unwrap().dispose()})})}isEqual(e,r,t=$.IsStrictlyEqual){if(e===r)return!0;this.runtime.assertOwned(e),this.runtime.assertOwned(r);let i=this.ffi.QTS_IsEqual(this.ctx.value,e.value,r.value,t);if(i===-1)throw new lt("WASM variant does not expose equality");return!!i}eq(e,r){return this.isEqual(e,r,$.IsStrictlyEqual)}sameValue(e,r){return this.isEqual(e,r,$.IsSameValue)}sameValueZero(e,r){return this.isEqual(e,r,$.IsSameValueZero)}getProp(e,r){this.runtime.assertOwned(e);let t;return typeof r=="number"&&r>=0?t=this.ffi.QTS_GetPropNumber(this.ctx.value,e.value,r):t=this.borrowPropertyKey(r).consume(i=>this.ffi.QTS_GetProp(this.ctx.value,e.value,i.value)),this.memory.heapValueHandle(t)}getLength(e){if(this.runtime.assertOwned(e),!(this.ffi.QTS_GetLength(this.ctx.value,this.uint32Out.value.ptr,e.value)<0))return this.uint32Out.value.typedArray[0]}getOwnPropertyNames(e,r={strings:!0,numbersAsStrings:!0}){this.runtime.assertOwned(e),e.value;let t=tr(r);if(t===0)throw new pt("No options set, will return an empty array");return M.withScope(i=>{let u=i.manage(this.memory.newMutablePointerArray(1)),a=this.ffi.QTS_GetOwnPropertyNames(this.ctx.value,u.value.ptr,this.uint32Out.value.ptr,e.value,t);if(a)return this.fail(this.memory.heapValueHandle(a));let l=this.uint32Out.value.typedArray[0],m=u.value.typedArray[0],d=new Uint32Array(this.module.HEAP8.buffer,m,l),T=Array.from(d).map(y=>this.memory.heapValueHandle(y));return this.ffi.QTS_FreeVoidPointer(this.ctx.value,m),this.success(yt(T))})}getIterator(e){let r=this._SymbolIterator??(this._SymbolIterator=this.memory.manage(this.getWellKnownSymbol("iterator")));return M.withScope(t=>{let i=t.manage(this.getProp(e,r)),u=this.callFunction(i,e);return u.error?u:this.success(new ir(u.value,this))})}setProp(e,r,t){this.runtime.assertOwned(e),this.borrowPropertyKey(r).consume(i=>this.ffi.QTS_SetProp(this.ctx.value,e.value,i.value,t.value))}defineProp(e,r,t){this.runtime.assertOwned(e),M.withScope(i=>{let u=i.manage(this.borrowPropertyKey(r)),a=t.value||this.undefined,l=!!t.configurable,m=!!t.enumerable,d=!!t.value,T=t.get?i.manage(this.newFunction(t.get.name,t.get)):this.undefined,y=t.set?i.manage(this.newFunction(t.set.name,t.set)):this.undefined;this.ffi.QTS_DefineProp(this.ctx.value,e.value,u.value,a.value,T.value,y.value,l,m,d)})}callFunction(e,r,...t){this.runtime.assertOwned(e);let i,u=t[0];u===void 0||Array.isArray(u)?i=u??[]:i=t;let a=this.memory.toPointerArray(i).consume(m=>this.ffi.QTS_Call(this.ctx.value,e.value,r.value,i.length,m.value)),l=this.ffi.QTS_ResolveException(this.ctx.value,a);return l?(this.ffi.QTS_FreeValuePointer(this.ctx.value,a),this.fail(this.memory.heapValueHandle(l))):this.success(this.memory.heapValueHandle(a))}callMethod(e,r,t=[]){return this.getProp(e,r).consume(i=>this.callFunction(i,e,t))}evalCode(e,r="eval.js",t){let i=t===void 0?1:0,u=er(t),a=this.memory.newHeapCharPointer(e).consume(m=>this.ffi.QTS_Eval(this.ctx.value,m.value.ptr,m.value.strlen,r,i,u)),l=this.ffi.QTS_ResolveException(this.ctx.value,a);return l?(this.ffi.QTS_FreeValuePointer(this.ctx.value,a),this.fail(this.memory.heapValueHandle(l))):this.success(this.memory.heapValueHandle(a))}throw(e){return this.errorToHandle(e).consume(r=>this.ffi.QTS_Throw(this.ctx.value,r.value))}borrowPropertyKey(e){return typeof e=="number"?this.newNumber(e):typeof e=="string"?this.newString(e):new L(e.value,this.runtime)}getMemory(e){if(e===this.rt.value)return this.memory;throw new Error("Private API. Cannot get memory from a different runtime")}dump(e){this.runtime.assertOwned(e);let r=this.typeof(e);if(r==="string")return this.getString(e);if(r==="number")return this.getNumber(e);if(r==="bigint")return this.getBigInt(e);if(r==="undefined")return;if(r==="symbol")return this.getSymbol(e);let t=this.getPromiseState(e);if(t.type==="fulfilled"&&!t.notAPromise)return e.dispose(),{type:t.type,value:t.value.consume(this.dump)};if(t.type==="pending")return e.dispose(),{type:t.type};if(t.type==="rejected")return e.dispose(),{type:t.type,error:t.error.consume(this.dump)};let i=this.memory.consumeJSCharPointer(this.ffi.QTS_Dump(this.ctx.value,e.value));try{return JSON.parse(i)}catch{return i}}unwrapResult(e){if(e.error){let r="context"in e.error?e.error.context:this,t=e.error.consume(i=>this.dump(i));if(t&&typeof t=="object"&&typeof t.message=="string"){let{message:i,name:u,stack:a,...l}=t,m=new xe(t,r);typeof u=="string"&&(m.name=t.name),m.message=i;let d=m.stack;throw typeof a=="string"&&(m.stack=`${u}: ${i} +${t.stack}Host: ${d}`),Object.assign(m,l),m}throw new xe(t)}return e.value}[Symbol.for("nodejs.util.inspect.custom")](){return this.alive?`${this.constructor.name} { ctx: ${this.ctx.value} rt: ${this.rt.value} }`:`${this.constructor.name} { disposed }`}getFunction(e){let r=this.runtime.hostRefs.get(e);if(typeof r!="function")throw new Error(`Host reference ${e} is not a function`);return r}errorToHandle(e){return e instanceof b?e:this.newError(e)}encodeBinaryJSON(e){let r=this.ffi.QTS_bjson_encode(this.ctx.value,e.value);return this.memory.heapValueHandle(r)}decodeBinaryJSON(e){let r=this.ffi.QTS_bjson_decode(this.ctx.value,e.value);return this.memory.heapValueHandle(r)}success(e){return O.success(e)}fail(e){return O.fail(e,r=>this.unwrapResult(r))}},Pt=class extends A{constructor(e){super(),this.scope=new M,this.contextMap=new Map,this.hostRefs=new nr,this._debugMode=!1,this.cToHostCallbacks={freeHostRef:(r,t)=>{if(r!==this.rt.value)throw new Error("Runtime pointer mismatch");this.hostRefs.delete(t)},shouldInterrupt:r=>{if(r!==this.rt.value)throw new Error("QuickJSContext instance received C -> JS interrupt with mismatched rt");let t=this.interruptHandler;if(!t)throw new Error("QuickJSContext had no interrupt handler");return t(this)?1:0},loadModuleSource:rt(this,function*(r,t,i,u){let a=this.moduleLoader;if(!a)throw new Error("Runtime has no module loader");if(t!==this.rt.value)throw new Error("Runtime pointer mismatch");let l=this.contextMap.get(i)??this.newContext({contextPointer:i});try{let m=yield*r(a(u,l));if(typeof m=="object"&&"error"in m&&m.error)throw this.debugLog("cToHostLoadModule: loader returned error",m.error),m.error;let d=typeof m=="string"?m:"value"in m?m.value:m;return this.memory.newHeapCharPointer(d).value.ptr}catch(m){return this.debugLog("cToHostLoadModule: caught error",m),l.throw(m),0}}),normalizeModule:rt(this,function*(r,t,i,u,a){let l=this.moduleNormalizer;if(!l)throw new Error("Runtime has no module normalizer");if(t!==this.rt.value)throw new Error("Runtime pointer mismatch");let m=this.contextMap.get(i)??this.newContext({contextPointer:i});try{let d=yield*r(l(u,a,m));if(typeof d=="object"&&"error"in d&&d.error)throw this.debugLog("cToHostNormalizeModule: normalizer returned error",d.error),d.error;let T=typeof d=="string"?d:d.value;return m.getMemory(this.rt.value).newHeapCharPointer(T).value.ptr}catch(d){return this.debugLog("normalizeModule: caught error",d),m.throw(d),0}})},e.ownedLifetimes?.forEach(r=>this.scope.manage(r)),this.module=e.module,this.memory=new Qt(this.module),this.ffi=e.ffi,this.rt=e.rt,this.callbacks=e.callbacks,this.scope.manage(this.rt),this.callbacks.setRuntimeCallbacks(this.rt.value,this.cToHostCallbacks),this.executePendingJobs=this.executePendingJobs.bind(this),Ee&&this.setDebugMode(!0)}get alive(){return this.scope.alive}dispose(){return this.scope.dispose()}newContext(e={}){let r=Zt(e.intrinsics),t=new b(e.contextPointer||this.ffi.QTS_NewContext(this.rt.value,r),void 0,u=>{this.contextMap.delete(u),this.callbacks.deleteContext(u),this.ffi.QTS_FreeContext(u)}),i=new xt({module:this.module,ctx:t,ffi:this.ffi,rt:this.rt,ownedLifetimes:e.ownedLifetimes,runtime:this,callbacks:this.callbacks});return this.contextMap.set(t.value,i),i}setModuleLoader(e,r){this.moduleLoader=e,this.moduleNormalizer=r,this.ffi.QTS_RuntimeEnableModuleLoader(this.rt.value,this.moduleNormalizer?1:0)}removeModuleLoader(){this.moduleLoader=void 0,this.ffi.QTS_RuntimeDisableModuleLoader(this.rt.value)}hasPendingJob(){return!!this.ffi.QTS_IsJobPending(this.rt.value)}setInterruptHandler(e){let r=this.interruptHandler;this.interruptHandler=e,r||this.ffi.QTS_RuntimeEnableInterruptHandler(this.rt.value)}removeInterruptHandler(){this.interruptHandler&&(this.ffi.QTS_RuntimeDisableInterruptHandler(this.rt.value),this.interruptHandler=void 0)}executePendingJobs(e=-1){let r=this.memory.newMutablePointerArray(1),t=this.ffi.QTS_ExecutePendingJob(this.rt.value,e??-1,r.value.ptr),i=r.value.typedArray[0];if(r.dispose(),i===0)return this.ffi.QTS_FreeValuePointerRuntime(this.rt.value,t),O.success(0);let u=this.contextMap.get(i)??this.newContext({contextPointer:i}),a=u.getMemory(this.rt.value).heapValueHandle(t);if(u.typeof(a)==="number"){let l=u.getNumber(a);return a.dispose(),O.success(l)}else{let l=Object.assign(a,{context:u});return O.fail(l,m=>u.unwrapResult(m))}}setMemoryLimit(e){if(e<0&&e!==-1)throw new Error("Cannot set memory limit to negative number. To unset, pass -1");this.ffi.QTS_RuntimeSetMemoryLimit(this.rt.value,e)}computeMemoryUsage(){let e=this.getSystemContext().getMemory(this.rt.value);return e.heapValueHandle(this.ffi.QTS_RuntimeComputeMemoryUsage(this.rt.value,e.ctx.value))}dumpMemoryUsage(){return this.memory.consumeHeapCharPointer(this.ffi.QTS_RuntimeDumpMemoryUsage(this.rt.value))}setMaxStackSize(e){if(e<0)throw new Error("Cannot set memory limit to negative number. To unset, pass 0.");this.ffi.QTS_RuntimeSetMaxStackSize(this.rt.value,e)}assertOwned(e){if(e.owner&&e.owner.rt!==this.rt)throw new at(`Handle is not owned by this runtime: ${e.owner.rt.value} != ${this.rt.value}`)}setDebugMode(e){this._debugMode=e,this.ffi.DEBUG&&this.rt.alive&&this.ffi.QTS_SetDebugLogEnabled(this.rt.value,e?1:0)}isDebugMode(){return this._debugMode}debugLog(...e){this._debugMode&&console.log("quickjs-emscripten:",...e)}[Symbol.for("nodejs.util.inspect.custom")](){return this.alive?`${this.constructor.name} { rt: ${this.rt.value} }`:`${this.constructor.name} { disposed }`}getSystemContext(){return this.context||(this.context=this.scope.manage(this.newContext())),this.context}},or=class{constructor(e){this.freeHostRef=e.freeHostRef,this.callFunction=e.callFunction,this.shouldInterrupt=e.shouldInterrupt,this.loadModuleSource=e.loadModuleSource,this.normalizeModule=e.normalizeModule}},Ie=class{constructor(e){this.contextCallbacks=new Map,this.runtimeCallbacks=new Map,this.suspendedCount=0,this.cToHostCallbacks=new or({freeHostRef:(r,t,i)=>{let u=this.runtimeCallbacks.get(t);if(!u)throw new Error(`QuickJSRuntime(rt = ${t}) not found when trying to free HostRef(id = ${i})`);u.freeHostRef(t,i)},callFunction:(r,t,i,u,a,l)=>this.handleAsyncify(r,()=>{try{let m=this.contextCallbacks.get(t);if(!m)throw new Error(`QuickJSContext(ctx = ${t}) not found for C function call "${l}"`);return m.callFunction(t,i,u,a,l)}catch(m){return console.error("[C to host error: returning null]",m),0}}),shouldInterrupt:(r,t)=>this.handleAsyncify(r,()=>{try{let i=this.runtimeCallbacks.get(t);if(!i)throw new Error(`QuickJSRuntime(rt = ${t}) not found for C interrupt`);return i.shouldInterrupt(t)}catch(i){return console.error("[C to host interrupt: returning error]",i),1}}),loadModuleSource:(r,t,i,u)=>this.handleAsyncify(r,()=>{try{let a=this.runtimeCallbacks.get(t);if(!a)throw new Error(`QuickJSRuntime(rt = ${t}) not found for C module loader`);let l=a.loadModuleSource;if(!l)throw new Error(`QuickJSRuntime(rt = ${t}) does not support module loading`);return l(t,i,u)}catch(a){return console.error("[C to host module loader error: returning null]",a),0}}),normalizeModule:(r,t,i,u,a)=>this.handleAsyncify(r,()=>{try{let l=this.runtimeCallbacks.get(t);if(!l)throw new Error(`QuickJSRuntime(rt = ${t}) not found for C module loader`);let m=l.normalizeModule;if(!m)throw new Error(`QuickJSRuntime(rt = ${t}) does not support module loading`);return m(t,i,u,a)}catch(l){return console.error("[C to host module loader error: returning null]",l),0}})}),this.module=e,this.module.callbacks=this.cToHostCallbacks}setRuntimeCallbacks(e,r){this.runtimeCallbacks.set(e,r)}deleteRuntime(e){this.runtimeCallbacks.delete(e)}setContextCallbacks(e,r){this.contextCallbacks.set(e,r)}deleteContext(e){this.contextCallbacks.delete(e)}handleAsyncify(e,r){if(e)return e.handleSleep(i=>{try{let u=r();if(!(u instanceof Promise)){H("asyncify.handleSleep: not suspending:",u),i(u);return}if(this.suspended)throw new mt(`Already suspended at: ${this.suspended.stack} +Attempted to suspend at:`);this.suspended=new ht(`(${this.suspendedCount++})`),H("asyncify.handleSleep: suspending:",this.suspended),u.then(a=>{this.suspended=void 0,H("asyncify.handleSleep: resolved:",a),i(a)},a=>{H("asyncify.handleSleep: rejected:",a),console.error("QuickJS: cannot handle error in suspended function",a),this.suspended=void 0})}catch(u){throw H("asyncify.handleSleep: error:",u),this.suspended=void 0,u}});let t=r();if(t instanceof Promise)throw new Error("Promise return value not supported in non-asyncify context.");return t}};Fe=class{constructor(e,r){this.module=e,this.ffi=r,this.callbacks=new Ie(e)}newRuntime(e={}){let r=new b(this.ffi.QTS_NewRuntime(),void 0,i=>{this.ffi.QTS_FreeRuntime(i),this.callbacks.deleteRuntime(i)}),t=new Pt({module:this.module,callbacks:this.callbacks,ffi:this.ffi,rt:r});return Je(t,e),e.moduleLoader&&t.setModuleLoader(e.moduleLoader),t}newContext(e={}){let r=this.newRuntime(),t=r.newContext({...e,ownedLifetimes:rr(r,e.ownedLifetimes)});return r.context=t,t}evalCode(e,r={}){return M.withScope(t=>{let i=t.manage(this.newContext());Ne(i.runtime,r);let u=i.evalCode(e,"eval.js");if(r.memoryLimitBytes!==void 0&&i.runtime.setMemoryLimit(-1),u.error)throw i.dump(t.manage(u.error));return i.dump(t.manage(u.value))})}getWasmMemory(){let e=this.module.quickjsEmscriptenInit?.(()=>{})?.getWasmMemory?.();if(!e)throw new Error("Variant does not support getting WebAssembly.Memory");return e}getFFI(){return this.ffi}}});var Mt={};ve(Mt,{QuickJSModuleCallbacks:()=>Ie,QuickJSWASMModule:()=>Fe,applyBaseRuntimeOptions:()=>Je,applyModuleEvalRuntimeOptions:()=>Ne});var At=W(()=>{Ce()});var kt={};ve(kt,{QuickJSFFI:()=>ar});var ar,Lt=W(()=>{ar=class{constructor(e){this.module=e,this.DEBUG=!1,this.QTS_Throw=this.module.cwrap("QTS_Throw","number",["number","number"]),this.QTS_NewError=this.module.cwrap("QTS_NewError","number",["number"]),this.QTS_RuntimeSetMemoryLimit=this.module.cwrap("QTS_RuntimeSetMemoryLimit",null,["number","number"]),this.QTS_RuntimeComputeMemoryUsage=this.module.cwrap("QTS_RuntimeComputeMemoryUsage","number",["number","number"]),this.QTS_RuntimeDumpMemoryUsage=this.module.cwrap("QTS_RuntimeDumpMemoryUsage","number",["number"]),this.QTS_RecoverableLeakCheck=this.module.cwrap("QTS_RecoverableLeakCheck","number",[]),this.QTS_BuildIsSanitizeLeak=this.module.cwrap("QTS_BuildIsSanitizeLeak","number",[]),this.QTS_RuntimeSetMaxStackSize=this.module.cwrap("QTS_RuntimeSetMaxStackSize",null,["number","number"]),this.QTS_GetUndefined=this.module.cwrap("QTS_GetUndefined","number",[]),this.QTS_GetNull=this.module.cwrap("QTS_GetNull","number",[]),this.QTS_GetFalse=this.module.cwrap("QTS_GetFalse","number",[]),this.QTS_GetTrue=this.module.cwrap("QTS_GetTrue","number",[]),this.QTS_NewHostRef=this.module.cwrap("QTS_NewHostRef","number",["number","number"]),this.QTS_GetHostRefId=this.module.cwrap("QTS_GetHostRefId","number",["number"]),this.QTS_NewRuntime=this.module.cwrap("QTS_NewRuntime","number",[]),this.QTS_FreeRuntime=this.module.cwrap("QTS_FreeRuntime",null,["number"]),this.QTS_NewContext=this.module.cwrap("QTS_NewContext","number",["number","number"]),this.QTS_FreeContext=this.module.cwrap("QTS_FreeContext",null,["number"]),this.QTS_FreeValuePointer=this.module.cwrap("QTS_FreeValuePointer",null,["number","number"]),this.QTS_FreeValuePointerRuntime=this.module.cwrap("QTS_FreeValuePointerRuntime",null,["number","number"]),this.QTS_FreeVoidPointer=this.module.cwrap("QTS_FreeVoidPointer",null,["number","number"]),this.QTS_FreeCString=this.module.cwrap("QTS_FreeCString",null,["number","number"]),this.QTS_DupValuePointer=this.module.cwrap("QTS_DupValuePointer","number",["number","number"]),this.QTS_NewObject=this.module.cwrap("QTS_NewObject","number",["number"]),this.QTS_NewObjectProto=this.module.cwrap("QTS_NewObjectProto","number",["number","number"]),this.QTS_NewArray=this.module.cwrap("QTS_NewArray","number",["number"]),this.QTS_NewArrayBuffer=this.module.cwrap("QTS_NewArrayBuffer","number",["number","number","number"]),this.QTS_NewFloat64=this.module.cwrap("QTS_NewFloat64","number",["number","number"]),this.QTS_GetFloat64=this.module.cwrap("QTS_GetFloat64","number",["number","number"]),this.QTS_NewString=this.module.cwrap("QTS_NewString","number",["number","number"]),this.QTS_GetString=this.module.cwrap("QTS_GetString","number",["number","number"]),this.QTS_GetArrayBuffer=this.module.cwrap("QTS_GetArrayBuffer","number",["number","number"]),this.QTS_GetArrayBufferLength=this.module.cwrap("QTS_GetArrayBufferLength","number",["number","number"]),this.QTS_NewSymbol=this.module.cwrap("QTS_NewSymbol","number",["number","number","number"]),this.QTS_GetSymbolDescriptionOrKey=this.module.cwrap("QTS_GetSymbolDescriptionOrKey","number",["number","number"]),this.QTS_IsGlobalSymbol=this.module.cwrap("QTS_IsGlobalSymbol","number",["number","number"]),this.QTS_IsJobPending=this.module.cwrap("QTS_IsJobPending","number",["number"]),this.QTS_ExecutePendingJob=this.module.cwrap("QTS_ExecutePendingJob","number",["number","number","number"]),this.QTS_GetProp=this.module.cwrap("QTS_GetProp","number",["number","number","number"]),this.QTS_GetPropNumber=this.module.cwrap("QTS_GetPropNumber","number",["number","number","number"]),this.QTS_SetProp=this.module.cwrap("QTS_SetProp",null,["number","number","number","number"]),this.QTS_DefineProp=this.module.cwrap("QTS_DefineProp",null,["number","number","number","number","number","number","boolean","boolean","boolean"]),this.QTS_GetOwnPropertyNames=this.module.cwrap("QTS_GetOwnPropertyNames","number",["number","number","number","number","number"]),this.QTS_Call=this.module.cwrap("QTS_Call","number",["number","number","number","number","number"]),this.QTS_ResolveException=this.module.cwrap("QTS_ResolveException","number",["number","number"]),this.QTS_Dump=this.module.cwrap("QTS_Dump","number",["number","number"]),this.QTS_Eval=this.module.cwrap("QTS_Eval","number",["number","number","number","string","number","number"]),this.QTS_GetModuleNamespace=this.module.cwrap("QTS_GetModuleNamespace","number",["number","number"]),this.QTS_Typeof=this.module.cwrap("QTS_Typeof","number",["number","number"]),this.QTS_GetLength=this.module.cwrap("QTS_GetLength","number",["number","number","number"]),this.QTS_IsEqual=this.module.cwrap("QTS_IsEqual","number",["number","number","number","number"]),this.QTS_GetGlobalObject=this.module.cwrap("QTS_GetGlobalObject","number",["number"]),this.QTS_NewPromiseCapability=this.module.cwrap("QTS_NewPromiseCapability","number",["number","number"]),this.QTS_PromiseState=this.module.cwrap("QTS_PromiseState","number",["number","number"]),this.QTS_PromiseResult=this.module.cwrap("QTS_PromiseResult","number",["number","number"]),this.QTS_TestStringArg=this.module.cwrap("QTS_TestStringArg",null,["string"]),this.QTS_GetDebugLogEnabled=this.module.cwrap("QTS_GetDebugLogEnabled","number",["number"]),this.QTS_SetDebugLogEnabled=this.module.cwrap("QTS_SetDebugLogEnabled",null,["number","number"]),this.QTS_BuildIsDebug=this.module.cwrap("QTS_BuildIsDebug","number",[]),this.QTS_BuildIsAsyncify=this.module.cwrap("QTS_BuildIsAsyncify","number",[]),this.QTS_NewFunction=this.module.cwrap("QTS_NewFunction","number",["number","string","number","boolean","number"]),this.QTS_ArgvGetJSValueConstPointer=this.module.cwrap("QTS_ArgvGetJSValueConstPointer","number",["number","number"]),this.QTS_RuntimeEnableInterruptHandler=this.module.cwrap("QTS_RuntimeEnableInterruptHandler",null,["number"]),this.QTS_RuntimeDisableInterruptHandler=this.module.cwrap("QTS_RuntimeDisableInterruptHandler",null,["number"]),this.QTS_RuntimeEnableModuleLoader=this.module.cwrap("QTS_RuntimeEnableModuleLoader",null,["number","number"]),this.QTS_RuntimeDisableModuleLoader=this.module.cwrap("QTS_RuntimeDisableModuleLoader",null,["number"]),this.QTS_bjson_encode=this.module.cwrap("QTS_bjson_encode","number",["number","number"]),this.QTS_bjson_decode=this.module.cwrap("QTS_bjson_decode","number",["number","number"])}}});var It={};ve(It,{default:()=>mr});async function lr(e={}){var r,t=e,i=!!globalThis.window,u=!!globalThis.WorkerGlobalScope,a=globalThis.process?.versions?.node&&globalThis.process?.type!="renderer";if(a){let{createRequire:n}=await import("node:module");var l=n(import.meta.url)}function m(n){n={log:n||function(){}};for(let o of m.Pa)o(n);return t.quickJSEmscriptenExtensions=n}m.Pa=[],t.quickjsEmscriptenInit=m,m.Pa.push(n=>{n.getWasmMemory=function(){return J}});var d="./this.program",T=(n,o)=>{throw o},y=import.meta.url,c="",_,Q;if(a){var j=l("node:fs");y.startsWith("file:")&&(c=l("node:path").dirname(l("node:url").fileURLToPath(y))+"/"),Q=n=>(n=Y(n)?new URL(n):n,j.readFileSync(n)),_=async n=>(n=Y(n)?new URL(n):n,j.readFileSync(n,void 0)),1{throw process.exitCode=n,o}}else if(i||u){try{c=new URL(".",y).href}catch{}u&&(Q=n=>{var o=new XMLHttpRequest;return o.open("GET",n,!1),o.responseType="arraybuffer",o.send(null),new Uint8Array(o.response)}),_=async n=>{if(Y(n))return new Promise((s,h)=>{var f=new XMLHttpRequest;f.open("GET",n,!0),f.responseType="arraybuffer",f.onload=()=>{f.status==200||f.status==0&&f.response?s(f.response):h(f.status)},f.onerror=h,f.send(null)});var o=await fetch(n,{credentials:"same-origin"});if(o.ok)return o.arrayBuffer();throw Error(o.status+" : "+o.url)}}var Ge=console.log.bind(console),G=console.error.bind(console),U,K=!1,ce,Y=n=>n.startsWith("file://"),De,Be,Ve,D,P,R,je=!1;function Ue(){var n=J.buffer;t.HEAP8=Ve=new Int8Array(n),new Int16Array(n),t.HEAPU8=D=new Uint8Array(n),new Uint16Array(n),P=new Int32Array(n),R=new Uint32Array(n),new Float32Array(n),new Float64Array(n),new BigInt64Array(n),new BigUint64Array(n)}function de(n){throw t.onAbort?.(n),n="Aborted("+n+")",G(n),K=!0,n=new WebAssembly.RuntimeError(n+". Build with -sASSERTIONS for more info."),Be?.(n),n}var fe;async function Ct(n){if(!U)try{var o=await _(n);return new Uint8Array(o)}catch{}if(n==fe&&U)n=new Uint8Array(U);else if(Q)n=Q(n);else throw"both async and sync fetching of the wasm failed";return n}async function Ht(n,o){try{var s=await Ct(n);return await WebAssembly.instantiate(s,o)}catch(h){G(`failed to asynchronously prepare wasm: ${h}`),de(h)}}async function Ot(n){var o=fe;if(!U&&!Y(o)&&!a)try{var s=fetch(o,{credentials:"same-origin"});return await WebAssembly.instantiateStreaming(s,n)}catch(h){G(`wasm streaming compile failed: ${h}`),G("falling back to ArrayBuffer instantiation")}return Ht(o,n)}class pe{name="ExitStatus";constructor(o){this.message=`Program terminated with exit(${o})`,this.status=o}}var ze=n=>{for(;0{var n=t.preRun.shift();$e.push(n)},X=!0,J,qe=new TextDecoder,Ke=(n,o,s,h)=>{if(s=o+s,h)return s;for(;n[o]&&!(o>=s);)++o;return o},k=(n,o,s)=>n?qe.decode(D.subarray(n,Ke(D,n,o,s))):"",Se=0,Dt=[0,31,60,91,121,152,182,213,244,274,305,335],Bt=[0,31,59,90,120,151,181,212,243,273,304,334],z={},Ye=n=>{ce=n,X||0{if(!K)try{n()}catch(o){o instanceof pe||o=="unwind"||T(1,o)}finally{if(!(X||0{var h=D;if(!(0=S){if(o>=s)break;h[o++]=S}else if(2047>=S){if(o+1>=s)break;h[o++]=192|S>>6,h[o++]=128|S&63}else if(65535>=S){if(o+2>=s)break;h[o++]=224|S>>12,h[o++]=128|S>>6&63,h[o++]=128|S&63}else{if(o+3>=s)break;h[o++]=240|S>>18,h[o++]=128|S>>12&63,h[o++]=128|S>>6&63,h[o++]=128|S&63,p++}}return h[o]=0,o-f},we={},Xe=()=>{if(!_e){var n={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:(globalThis.navigator?.language??"C").replace("-","_")+".UTF-8",_:d||"./this.program"},o;for(o in we)we[o]===void 0?delete n[o]:n[o]=we[o];var s=[];for(o in n)s.push(`${o}=${n[o]}`);_e=s}return _e},_e,ye=n=>{for(var o=0,s=0;s=h?o++:2047>=h?o+=2:55296<=h&&57343>=h?(o+=4,++s):o+=3}return o},jt=[null,[],[]],Ut=(n,o,s,h)=>{var f={string:g=>{var v=0;if(g!=null&&g!==0){v=ye(g)+1;var E=ge(v);N(g,E,v),v=E}return v},array:g=>{var v=ge(g.length);return Ve.set(g,v),v}};n=t["_"+n];var p=[],S=0;if(h)for(var x=0;x{var f=!s||s.every(p=>p==="number"||p==="boolean");return o!=="string"&&f&&!h?t["_"+n]:(...p)=>Ut(n,o,s,p)},t.UTF8ToString=k,t.stringToUTF8=(n,o,s)=>N(n,o,s),t.lengthBytesUTF8=ye;var Ze,et,ge,tt,zt={b:(n,o,s,h)=>de(`Assertion failed: ${k(n)}, at: `+[o?k(o):"unknown filename",s,h?k(h):"unknown function"]),q:()=>de(""),l:()=>{X=!1,Se=0},m:function(n,o){n=-9007199254740992>n||9007199254740992>2]=n.getSeconds(),P[o+4>>2]=n.getMinutes(),P[o+8>>2]=n.getHours(),P[o+12>>2]=n.getDate(),P[o+16>>2]=n.getMonth(),P[o+20>>2]=n.getFullYear()-1900,P[o+24>>2]=n.getDay();var s=n.getFullYear();P[o+28>>2]=(s%4!==0||s%100===0&&s%400!==0?Bt:Dt)[n.getMonth()]+n.getDate()-1|0,P[o+36>>2]=-(60*n.getTimezoneOffset()),s=new Date(n.getFullYear(),6,1).getTimezoneOffset();var h=new Date(n.getFullYear(),0,1).getTimezoneOffset();P[o+32>>2]=(s!=h&&n.getTimezoneOffset()==Math.min(h,s))|0},j:(n,o)=>{if(z[n]&&(clearTimeout(z[n].id),delete z[n]),!o)return 0;var s=setTimeout(()=>{delete z[n],Vt(()=>Ze(n,performance.now()))},o);return z[n]={id:s,Qa:o},0},n:(n,o,s,h)=>{var f=new Date().getFullYear(),p=new Date(f,0,1).getTimezoneOffset();f=new Date(f,6,1).getTimezoneOffset(),R[n>>2]=60*Math.max(p,f),P[o>>2]=+(p!=f),o=S=>{var x=Math.abs(S);return`UTC${0<=S?"-":"+"}${String(Math.floor(x/60)).padStart(2,"0")}${String(x%60).padStart(2,"0")}`},n=o(p),o=o(f),fDate.now(),k:n=>{var o=D.length;if(n>>>=0,2147483648=s;s*=2){var h=o*(1+.2/s);h=Math.min(h,n+100663296);e:{h=(Math.min(2147483648,65536*Math.ceil(Math.max(n,h)/65536))-J.buffer.byteLength+65535)/65536|0;try{J.grow(h),Ue();var f=1;break e}catch{}f=void 0}if(f)return!0}return!1},e:(n,o)=>{var s=0,h=0,f;for(f of Xe()){var p=o+s;R[n+h>>2]=p,s+=N(f,p,1/0)+1,h+=4}return 0},f:(n,o)=>{var s=Xe();R[n>>2]=s.length,n=0;for(var h of s)n+=ye(h)+1;return R[o>>2]=n,0},d:()=>52,o:function(){return 70},c:(n,o,s,h)=>{for(var f=0,p=0;p>2],x=R[o+4>>2];o+=8;for(var B=0;B>2]=f,0},a:J,r:Ye,s:function(n,o,s,h,f){return t.callbacks.callFunction(void 0,n,o,s,h,f)},i:function(n){return t.callbacks.shouldInterrupt(void 0,n)},h:function(n,o,s){return s=k(s),t.callbacks.loadModuleSource(void 0,n,o,s)},g:function(n,o,s,h){return s=k(s),h=k(h),t.callbacks.normalizeModule(void 0,n,o,s,h)},t:function(n,o){t.callbacks.freeHostRef(void 0,n,o)}},Z;return Z=await(async function(){function n(s){return s=Z=s.exports,t._malloc=s.v,t._QTS_Throw=s.w,t._QTS_NewError=s.x,t._QTS_RuntimeSetMemoryLimit=s.y,t._QTS_RuntimeComputeMemoryUsage=s.z,t._QTS_RuntimeDumpMemoryUsage=s.A,t._QTS_RecoverableLeakCheck=s.B,t._QTS_BuildIsSanitizeLeak=s.C,t._QTS_RuntimeSetMaxStackSize=s.D,t._QTS_GetUndefined=s.E,t._QTS_GetNull=s.F,t._QTS_GetFalse=s.G,t._QTS_GetTrue=s.H,t._QTS_NewHostRef=s.I,t._QTS_GetHostRefId=s.J,t._QTS_NewRuntime=s.K,t._QTS_FreeRuntime=s.L,t._free=s.M,t._QTS_NewContext=s.N,t._QTS_FreeContext=s.O,t._QTS_FreeValuePointer=s.P,t._QTS_FreeValuePointerRuntime=s.Q,t._QTS_FreeVoidPointer=s.R,t._QTS_FreeCString=s.S,t._QTS_DupValuePointer=s.T,t._QTS_NewObject=s.U,t._QTS_NewObjectProto=s.V,t._QTS_NewArray=s.W,t._QTS_NewArrayBuffer=s.X,t._QTS_NewFloat64=s.Y,t._QTS_GetFloat64=s.Z,t._QTS_NewString=s._,t._QTS_GetString=s.$,t._QTS_GetArrayBuffer=s.aa,t._QTS_GetArrayBufferLength=s.ba,t._QTS_NewSymbol=s.ca,t._QTS_GetSymbolDescriptionOrKey=s.da,t._QTS_IsGlobalSymbol=s.ea,t._QTS_IsJobPending=s.fa,t._QTS_ExecutePendingJob=s.ga,t._QTS_GetProp=s.ha,t._QTS_GetPropNumber=s.ia,t._QTS_SetProp=s.ja,t._QTS_DefineProp=s.ka,t._QTS_GetOwnPropertyNames=s.la,t._QTS_Call=s.ma,t._QTS_ResolveException=s.na,t._QTS_Dump=s.oa,t._QTS_Eval=s.pa,t._QTS_GetModuleNamespace=s.qa,t._QTS_Typeof=s.ra,t._QTS_GetLength=s.sa,t._QTS_IsEqual=s.ta,t._QTS_GetGlobalObject=s.ua,t._QTS_NewPromiseCapability=s.va,t._QTS_PromiseState=s.wa,t._QTS_PromiseResult=s.xa,t._QTS_TestStringArg=s.ya,t._QTS_GetDebugLogEnabled=s.za,t._QTS_SetDebugLogEnabled=s.Aa,t._QTS_BuildIsDebug=s.Ba,t._QTS_BuildIsAsyncify=s.Ca,t._QTS_NewFunction=s.Da,t._QTS_ArgvGetJSValueConstPointer=s.Ea,t._QTS_RuntimeEnableInterruptHandler=s.Fa,t._QTS_RuntimeDisableInterruptHandler=s.Ga,t._QTS_RuntimeEnableModuleLoader=s.Ha,t._QTS_RuntimeDisableModuleLoader=s.Ia,t._QTS_bjson_encode=s.Ja,t._QTS_bjson_decode=s.Ka,Ze=s.La,et=s.Ma,ge=s.Na,tt=s.Oa,Z}var o={a:zt};return t.instantiateWasm?new Promise(s=>{t.instantiateWasm(o,(h,f)=>{s(n(h,f))})}):(fe??=t.locateFile?t.locateFile?t.locateFile("emscripten-module.wasm",c):c+"emscripten-module.wasm":new URL("emscripten-module.wasm",import.meta.url).href,n((await Ot(o)).instance))})(),(function(){function n(){if(t.calledRun=!0,!K){if(je=!0,Z.u(),De?.(t),t.onRuntimeInitialized?.(),t.postRun)for(typeof t.postRun=="function"&&(t.postRun=[t.postRun]);t.postRun.length;){var o=t.postRun.shift();We.push(o)}ze(We)}}if(t.preRun)for(typeof t.preRun=="function"&&(t.preRun=[t.preRun]);t.preRun.length;)Gt();ze($e),t.setStatus?(t.setStatus("Running..."),setTimeout(()=>{setTimeout(()=>t.setStatus(""),1),n()},1)):n()})(),je?r=t:r=new Promise((n,o)=>{De=n,Be=o}),r}var mr,Jt=W(()=>{mr=lr});import{parentPort as he,workerData as Ft}from"node:worker_threads";import{readFile as cr}from"node:fs/promises";Ce();te();async function Et(e){let r=oe(await e),[t,i,{QuickJSWASMModule:u}]=await Promise.all([r.importModuleLoader().then(oe),r.importFFI(),Promise.resolve().then(()=>(At(),Mt)).then(oe)]),a=await t();a.type="sync";let l=new i(a);return new u(a,l)}function oe(e){return e&&"default"in e&&e.default?e.default&&"default"in e.default&&e.default.default?e.default.default:e.default:e}function Rt(e,r){return{...e,async importModuleLoader(){let t=oe(await e.importModuleLoader());return async function(){let i=r.emscriptenModule?{...r.emscriptenModule}:{},u=r.log??((...c)=>H("newVariant moduleLoader:",...c)),a=(c,_)=>(u(...c,_),_),l=c=>typeof c=="function"?c():c;(r.wasmLocation||r.wasmSourceMapLocation||r.locateFile)&&(i.locateFile=(c,_)=>{let Q={fileName:c,relativeTo:_};if(c.endsWith(".wasm")&&r.wasmLocation!==void 0)return a(["locateFile .wasm: provide wasmLocation",Q],r.wasmLocation);if(c.endsWith(".map")){if(r.wasmSourceMapLocation!==void 0)return a(["locateFile .map: provide wasmSourceMapLocation",Q],r.wasmSourceMapLocation);if(r.wasmLocation&&!r.locateFile)return a(["locateFile .map: infer from wasmLocation",Q],r.wasmLocation+".map")}return r.locateFile?a(["locateFile: use provided fn",Q],r.locateFile(c,_)):a(["locateFile: unhandled, passthrough",Q],c)}),r.wasmBinary&&(i.wasmBinary=await l(r.wasmBinary)),r.wasmMemory&&(i.wasmMemory=await l(r.wasmMemory));let m=r.wasmModule,d;m&&(i.instantiateWasm=async(c,_)=>{d??(d=Promise.resolve(l(m)));let Q=await d;if(!Q)throw new se(`options.wasmModule returned ${String(Q)}`);let j=await WebAssembly.instantiate(Q,c);return _(j),j.exports}),i.monitorRunDependencies=c=>{u("monitorRunDependencies:",c)},i.quickjsEmscriptenInit=()=>ur(u);let T=t(i),y=i.quickjsEmscriptenInit?.(u);if(m&&y?.receiveWasmOffsetConverter&&!y.existingWasmOffsetConverter){let c=await l(r.wasmBinary)??new ArrayBuffer(0);d??(d=Promise.resolve(l(m)));let _=await d;if(!_)throw new se(`options.wasmModule returned ${String(_)}`);y.receiveWasmOffsetConverter(c,_)}if(y?.receiveSourceMapJSON){let c=await l(r.wasmSourceMapData);typeof c=="string"?y.receiveSourceMapJSON(JSON.parse(c)):c?y.receiveSourceMapJSON(c):y.receiveSourceMapJSON({version:3,names:[],sources:[],mappings:""})}return T}}}}function ur(e){let r="mock called, emscripten module may not be initialized yet";return{mock:!0,removeRunDependency(t){e(`${r}: removeRunDependency called:`,t)},receiveSourceMapJSON(t){e(`${r}: receiveSourceMapJSON called:`,t)},WasmOffsetConverter:void 0,receiveWasmOffsetConverter(t,i){e(`${r}: receiveWasmOffsetConverter called:`,t,i)}}}var hr={type:"sync",importFFI:()=>Promise.resolve().then(()=>(Lt(),kt)).then(e=>e.QuickJSFFI),importModuleLoader:()=>Promise.resolve().then(()=>(Jt(),It)).then(e=>e.default)},Nt=hr;var dr=await cr(new URL("./quickjs.wasm",import.meta.url)),fr=await Et(Rt(Nt,{wasmBinary:dr})),q=fr.newRuntime();q.setMemoryLimit(32*1024*1024);q.setMaxStackSize(512*1024);q.setInterruptHandler(()=>Date.now()>Ft.deadline);var w=q.newContext(),pr=0,V=!1,ae=new Map,le=[],He=0;w.newFunction("__log",(e,r)=>{if(le.length>=50||He>=1e4)return;let t=w.getString(r).slice(0,Math.min(1e3,1e4-He));He+=t.length,le.push({level:w.getString(e),text:t})}).consume(e=>w.setProp(w.global,"__log",e));function me(e){V||(V=!0,he.postMessage({type:"done",error:String(e).slice(0,2e3),logs:le}))}function Oe(){if(V)return;let e=q.executePendingJobs(100);if(e.error){let r=w.dump(e.error);e.error.dispose(),me(r.message||JSON.stringify(r))}}w.newFunction("__call",(e,r)=>{let t=w.getString(e),i=w.getString(r);if(i.length>65536)return{error:w.newError("\u5DE5\u5177\u53C2\u6570\u8D85\u8FC7 64 KB")};let u=w.newPromise(),a=++pr;return ae.set(a,u),he.postMessage({type:"call",id:a,method:t,args:JSON.parse(i)}),u.handle}).consume(e=>w.setProp(w.global,"__call",e));w.newFunction("__done",(e,r)=>{if(ae.size)return me("\u5B58\u5728\u672A await \u7684\u5DE5\u5177\u8C03\u7528\uFF0C\u8BF7\u67E5\u8BE2 trace \u4E2D\u7684\u4EFB\u52A1\u7ED3\u679C");let t=w.getString(e);if(t.length>65536)return me("\u811A\u672C\u8FD4\u56DE\u503C\u8D85\u8FC7 64 KB");V||(V=!0,he.postMessage({type:"done",result:JSON.parse(t),error:w.getString(r)||void 0,logs:le}))}).consume(e=>w.setProp(w.global,"__done",e));he.on("message",e=>{if(V)return;let r=ae.get(e.id);if(!r)return;ae.delete(e.id);let t=e.error?w.newError(e.error):w.newString(JSON.stringify(e.result));e.error?r.reject(t):r.resolve(t),t.dispose(),r.dispose(),Oe()});var Sr=` +const console = Object.freeze(Object.fromEntries( + ['log','info','warn','error','debug'].map(level => [level, (...values) => { + const text = values.map(value => { + if (typeof value === 'string') return value; + try { return JSON.stringify(value) ?? String(value); } catch { return '[unserializable]'; } + }).join(' '); + __log(level, text); + }]) +)); +const editor = Object.freeze(Object.fromEntries( + ['inspect','capabilities','preview','edit','create','export','commands','execute','draw'].map(name => + [name, async (args) => JSON.parse(await __call(name, JSON.stringify(args ?? null)))]) +)); +(async () => { ${Ft.code} + })() + .then(value => __done(JSON.stringify(value ?? null), '')) + .catch(error => __done('null', String(error) + '\\n' + String(error?.stack || ''))); +`,ue=w.evalCode(Sr,"editor-script.js");if(ue.error){let e=w.dump(ue.error);ue.error.dispose(),me(e.message||JSON.stringify(e))}else ue.value.dispose();Oe();setInterval(Oe,10); diff --git a/plugins/webguhui/minimax-photo/miniapp/node/quickjs.wasm b/plugins/webguhui/minimax-photo/miniapp/node/quickjs.wasm new file mode 100644 index 00000000..1815757b Binary files /dev/null and b/plugins/webguhui/minimax-photo/miniapp/node/quickjs.wasm differ diff --git a/plugins/webguhui/minimax-photo/miniapp/node/recovery-store.mjs b/plugins/webguhui/minimax-photo/miniapp/node/recovery-store.mjs new file mode 100644 index 00000000..75246251 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/node/recovery-store.mjs @@ -0,0 +1,52 @@ +import { mkdir, readFile, writeFile, rename, readdir } from 'node:fs/promises'; +import { join } from 'node:path'; +import { randomUUID } from 'node:crypto'; + +// Each browser workspace owns its own snapshots. Revisions reject stale writers. +export async function createRecoveryStore(dataDir) { + const root = join(dataDir, 'recovery'); + await mkdir(root, { recursive: true }); + const locks = new Map(); + const path = id => { + if (!/^(assistant|document)-[a-f0-9-]{36}$/.test(id)) throw Error('Invalid snapshot ID'); + return join(root, id + '.json'); + }; + async function get(id) { + try { return JSON.parse(await readFile(path(id), 'utf8')); } + catch (e) { if (e.code === 'ENOENT') return { revision: 0, value: null }; throw e; } + } + return { + get, + async list() { + const values = []; + for (const file of await readdir(root)) { + if (!/^document-[a-f0-9-]{36}\.json$/.test(file)) continue; + const id = file.slice(0, -5), record = await get(id); + values.push({ id, revision: record.revision, name: record.value.name, updatedAt: record.updatedAt }); + } + return values.sort((a, b) => b.updatedAt - a.updatedAt); + }, + async put(id, input) { + path(id); + const previous = locks.get(id) || Promise.resolve(); + const next = previous.catch(() => {}).then(async () => { + const old = await get(id); + if (!Number.isSafeInteger(input.revision) || input.revision !== old.revision) + throw Object.assign(Error('Snapshot changed in another window'), { status: 409 }); + const v = input.value; + if (!v || typeof v !== 'object' || Array.isArray(v)) throw Error('Invalid snapshot'); + if (id.startsWith('document-') && (typeof v.name !== 'string' || v.name.length > 300 || + typeof v.data !== 'string' || !/^[A-Za-z0-9+/]+={0,2}$/.test(v.data))) throw Error('Invalid project'); + if (id.startsWith('assistant-') && (typeof v.draft !== 'string' || v.draft.length > 8000 || + typeof v.reply !== 'string' || v.reply.length > 60000)) throw Error('Invalid conversation'); + const record = { revision: old.revision + 1, updatedAt: Date.now(), value: v }; + const temp = path(id) + '.' + randomUUID() + '.tmp'; + await writeFile(temp, JSON.stringify(record)); + await rename(temp, path(id)); + return record; + }); + locks.set(id, next); + try { return await next; } finally { if (locks.get(id) === next) locks.delete(id); } + }, + }; +} diff --git a/plugins/webguhui/minimax-photo/miniapp/node/server.mjs b/plugins/webguhui/minimax-photo/miniapp/node/server.mjs new file mode 100644 index 00000000..eba3dfe5 --- /dev/null +++ b/plugins/webguhui/minimax-photo/miniapp/node/server.mjs @@ -0,0 +1,319 @@ +import { createRecoveryStore } from './recovery-store.mjs'; +import { createEditorService } from './editor-service.mjs'; +import { createCodeService } from './editor-code.mjs'; +import { createAgentService, readJSON } from './agent-service.mjs'; +import { handleAgentMCP } from './agent-mcp.mjs'; +import { createServer } from 'node:http'; +import { readFile, mkdir, readdir, rename, writeFile, stat } from 'node:fs/promises'; +import { resolve, join, extname, sep } from 'node:path'; +import { createHash, randomUUID } from 'node:crypto'; +import { createReadStream } from 'node:fs'; +import { createGunzip } from 'node:zlib'; +const MIME = { + '.wasm': 'application/wasm', + '.html': 'text/html; charset=utf-8', + '.js': 'text/javascript; charset=utf-8', + '.css': 'text/css; charset=utf-8', + '.png': 'image/png', + '.webp': 'image/webp', + '.md': 'text/plain; charset=utf-8', + '.svg': 'image/svg+xml', +}; +const MAX = 64 * 1024 * 1024; +export async function start(context) { + const manifest = JSON.parse(await readFile(join(context.pluginRoot, '.minimax-plugin/plugin.json'), 'utf8')); + const serverInfo = { name: manifest.name, version: manifest.version }; + const client = resolve(context.pluginRoot, 'miniapp/client'), + storage = join(context.dataDir, 'projects'); + await mkdir(storage, { recursive: true }); + const recovery = await createRecoveryStore(context.dataDir); + const agent = await createAgentService(context.dataDir); + const editor = await createEditorService(context.dataDir); + editor.code = await createCodeService(context.dataDir, editor); + const locks = new Map(); + async function serial(id, fn) { + const previous = locks.get(id) || Promise.resolve(); + const next = previous.catch(() => {}).then(fn); + locks.set(id, next); + try { + return await next; + } finally { + if (locks.get(id) === next) locks.delete(id); + } + } + const json = (res, status, value) => { + res.writeHead(status, { + 'content-type': 'application/json; charset=utf-8', + 'cache-control': 'no-store', + }); + res.end(JSON.stringify(value)); + }; + const server = createServer(async (req, res) => { + try { + const host = req.headers.host; + if ( + !host || + !['127.0.0.1', 'localhost', '[::1]'].some((h) => host === h || host.startsWith(h + ':')) + ) + return json(res, 403, { error: '不允许的访问地址' }); + const url = new URL(req.url, 'http://' + host); + res.setHeader('X-Content-Type-Options', 'nosniff'); + res.setHeader('Referrer-Policy', 'no-referrer'); + res.setHeader( + 'Content-Security-Policy', + "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self'; worker-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'self'", + ); + if (url.pathname === '/mcp/retouch-images') { + if (req.headers.origin && req.headers.origin !== url.origin) + return json(res, 403, { error: 'Origin rejected' }); + return await handleAgentMCP(req, res, agent, json, editor, serverInfo); + } + if (!['GET', 'HEAD'].includes(req.method) && req.headers.origin !== url.origin) + return json(res, 403, { error: '仅允许本页面保存工程' }); + if (url.pathname === '/api/recovery' && req.method === 'GET') + return json(res, 200, { snapshots: await recovery.list() }); + const recoveryId = url.pathname.match(/^\/api\/recovery\/((?:document|assistant)-[a-f0-9-]{36})$/); + if (recoveryId) { + try { + if (req.method === 'GET') return json(res, 200, await recovery.get(recoveryId[1])); + if (req.method === 'POST') return json(res, 200, await recovery.put(recoveryId[1], + await readJSON(req, recoveryId[1].startsWith('document-') ? 96 * 1024 * 1024 : 1024 * 1024))); + return json(res, 405, { error: 'Unsupported method' }); + } catch (error) { return json(res, error.status || 400, { error: error.message }); } + } + if (url.pathname === '/api/editor/register' && req.method === 'POST') { + try { + return json(res, 200, editor.register(await readJSON(req, 1024 * 1024))); + } catch (error) { + return json(res, 400, { error: error.message }); + } + } + const editorRoute = url.pathname.match( + /^\/api\/editor\/([a-f0-9-]{36})\/(events|claim|finish|ack)$/, + ); + if (editorRoute) { + try { + const [, editorId, action] = editorRoute; + if (action === 'events' && req.method === 'GET') + return editor.subscribe(editorId, req, res); + if (req.method !== 'POST') return json(res, 405, { error: 'Unsupported method' }); + const input = await readJSON(req, action === 'finish' ? 96 * 1024 * 1024 : 1024); + const result = + action === 'claim' + ? await editor.claim(editorId, input.jobId) + : action === 'finish' + ? await editor.finish(editorId, input.jobId, input) + : action === 'ack' + ? await editor.acknowledge(editorId, input.jobId, input) + : null; + if (!result) return json(res, 400, { error: 'Unknown action' }); + return json(res, 200, result); + } catch (error) { + return json(res, 400, { error: error.message }); + } + } + if (url.pathname === '/api/agent/events' && req.method === 'GET') + return agent.subscribe(req, res); + if (url.pathname === '/api/agent/requests') { + if (req.method === 'GET') return json(res, 200, { requests: await agent.list() }); + if (req.method === 'POST') { + try { + return json(res, 201, await agent.create(await readJSON(req))); + } catch { + return json(res, 400, { error: '图片需求或参考图无效;PNG 最大 16 MB' }); + } + } + return json(res, 405, { error: 'Unsupported method' }); + } + const resultId = url.pathname.match(/^\/api\/agent\/requests\/([a-f0-9-]{36})\/result$/); + if (resultId && req.method === 'GET') { + try { + const bytes = await agent.result(resultId[1]); + res.writeHead(200, { + 'Content-Type': 'image/png', + 'Cache-Control': 'no-store', + 'Content-Length': bytes.length, + }); + return res.end(bytes); + } catch { + return json(res, 404, { error: '图片尚未生成' }); + } + } + if (url.pathname === '/api/projects' && req.method === 'GET') { + const names = (await readdir(storage)).filter((n) => /^[a-f0-9-]+\.json$/.test(n)); + const projects = []; + for (const name of names) { + try { + const p = JSON.parse(await readFile(join(storage, name), 'utf8')); + projects.push({ + id: p.id, + name: p.name, + width: p.width, + height: p.height, + revision: p.revision, + updatedAt: p.updatedAt, + }); + } catch {} + } + return json(res, 200, { projects: projects.sort((a, b) => b.updatedAt - a.updatedAt) }); + } + const match = url.pathname.match(/^\/api\/projects\/([a-f0-9-]{36})$/); + if (match) { + const id = match[1], + path = join(storage, id + '.json'); + if (req.method === 'GET') { + try { + return json(res, 200, JSON.parse(await readFile(path, 'utf8'))); + } catch (e) { + if (e.code === 'ENOENT') return json(res, 404, { error: '工程不存在' }); + throw e; + } + } + if (req.method === 'PUT') { + if (!req.headers['content-type']?.startsWith('application/json')) + return json(res, 415, { error: '需要 JSON 工程' }); + const chunks = []; + let total = 0; + for await (const chunk of req) { + total += chunk.length; + if (total > MAX) { + json(res, 413, { error: '工程超过 64 MB,请导出工程文件保存' }); + req.resume(); + return; + } + chunks.push(chunk); + } + let p; + try { + p = JSON.parse(Buffer.concat(chunks).toString()); + } catch { + return json(res, 400, { error: '工程不是有效 JSON' }); + } + if ( + p.id !== id || + p.format !== 'retouch-lab' || + p.version !== 1 || + typeof p.name !== 'string' || + p.name.length > 200 || + !Number.isInteger(p.width) || + !Number.isInteger(p.height) || + p.width < 1 || + p.height < 1 || + p.width * p.height > 32e6 || + !Array.isArray(p.layers) || + p.layers.length < 1 || + p.layers.length > 100 || + !p.layers.every( + (l) => + typeof l.name === 'string' && + typeof l.image === 'string' && + l.image.startsWith('data:image/png;base64,'), + ) + ) + return json(res, 400, { error: '工程内容或尺寸无效' }); + return await serial(id, async () => { + let old = null; + try { + old = JSON.parse(await readFile(path, 'utf8')); + } catch (e) { + if (e.code !== 'ENOENT') throw e; + } + if ((old?.revision ?? 0) !== (p.revision ?? 0)) + return json(res, 409, { + error: '工程已被另一窗口修改,请先导出当前工程,再打开最新版本', + }); + p.revision = (old?.revision ?? 0) + 1; + p.updatedAt = Date.now(); + const tmp = path + '.' + randomUUID() + '.tmp'; + await writeFile(tmp, JSON.stringify(p), { mode: 0o600 }); + await rename(tmp, path); + return json(res, 200, { revision: p.revision, updatedAt: p.updatedAt }); + }); + } + return json(res, 405, { error: '不支持的操作' }); + } + if (url.pathname.startsWith('/api/')) return json(res, 404, { error: '接口不存在' }); + if (!['GET', 'HEAD'].includes(req.method)) return json(res, 405, { error: '不支持的操作' }); + let pathname; + try { + pathname = decodeURIComponent(url.pathname); + } catch { + return json(res, 400, { error: '地址无效' }); + } + const path = resolve(client, '.' + (pathname === '/' ? '/photo.html' : pathname)); + if (pathname.startsWith('/photocraft/')) res.setHeader('Access-Control-Allow-Origin', '*'); + if (!path.startsWith(client + sep)) return json(res, 403, { error: '路径不允许' }); + const compressed = pathname === '/photocraft/photocraft_bg.wasm'; + const diskPath = compressed ? path + '.gz' : path; + const acceptsGzip = (req.headers['accept-encoding'] || '').split(',').some((entry) => { + const [name, ...parameters] = entry.trim().toLowerCase().split(';'); + return ( + name === 'gzip' && + !parameters.some((parameter) => /^\s*q\s*=\s*0(?:\.0*)?\s*$/.test(parameter)) + ); + }); + let info; + try { + info = await stat(diskPath); + } catch { + return json(res, 404, { error: '文件不存在' }); + } + if (!info.isFile()) return json(res, 404, { error: '文件不存在' }); + const etag = + '"' + + createHash('sha256') + .update(String(info.size) + ':' + info.mtimeMs) + .digest('hex') + .slice(0, 20) + + '"'; + res.setHeader('ETag', etag); + res.setHeader('Cache-Control', 'no-cache'); + if (req.headers['if-none-match'] === etag) { + res.writeHead(304); + return res.end(); + } + if (compressed) res.setHeader('Vary', 'Accept-Encoding'); + if (compressed && acceptsGzip) res.setHeader('Content-Encoding', 'gzip'); + res.setHeader('Content-Type', MIME[extname(path)] || 'application/octet-stream'); + if (!compressed || acceptsGzip) res.setHeader('Content-Length', info.size); + res.writeHead(200); + if (req.method === 'HEAD') return res.end(); + const stream = createReadStream(diskPath); + stream.on('error', () => res.destroy()); + if (compressed && !acceptsGzip) { + const decoder = createGunzip(); + decoder.on('error', () => res.destroy()); + stream.pipe(decoder).pipe(res); + } else stream.pipe(res); + } catch (error) { + context.logger.error('retouch.request.failed', { code: error.code || 'unknown' }); + if (!res.headersSent) json(res, 500, { error: '保存或读取失败,请重试或导出工程文件' }); + else res.destroy(); + } + }); + await new Promise((ok, fail) => { + server.once('error', fail); + server.listen(context.listen.port, context.listen.host, () => { + server.off('error', fail); + ok(); + }); + }); + let disposed = false; + const dispose = async () => { + if (disposed) return; + disposed = true; + agent.close(); + editor.close(); + editor.code.close(); + context.signal.removeEventListener('abort', onAbort); + await new Promise((ok, fail) => { + server.close((e) => (e ? fail(e) : ok())); + server.closeIdleConnections(); + }); + }; + const onAbort = () => void dispose(); + context.signal.addEventListener('abort', onAbort, { once: true }); + if (context.signal.aborted) await dispose(); + context.logger.info('retouch.ready'); + return { dispose }; +} diff --git a/plugins/webguhui/minimax-photo/package.json b/plugins/webguhui/minimax-photo/package.json new file mode 100644 index 00000000..5cc780b5 --- /dev/null +++ b/plugins/webguhui/minimax-photo/package.json @@ -0,0 +1,15 @@ +{ + "name": "minimax-photo", + "version": "0.2.35", + "private": true, + "type": "module", + "description": "MiniMax Code 本地图像工作台", + "mcode": { + "schemaVersion": 2, + "miniApp": "./miniapp/miniapp.json" + }, + "scripts": { + "start": "node scripts/preview.mjs", + "check": "node scripts/check.mjs" + } +} diff --git a/plugins/webguhui/minimax-photo/ptc-src/.gitignore b/plugins/webguhui/minimax-photo/ptc-src/.gitignore new file mode 100644 index 00000000..c2658d7d --- /dev/null +++ b/plugins/webguhui/minimax-photo/ptc-src/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/plugins/webguhui/minimax-photo/ptc-src/build.mjs b/plugins/webguhui/minimax-photo/ptc-src/build.mjs new file mode 100644 index 00000000..e86cd00f --- /dev/null +++ b/plugins/webguhui/minimax-photo/ptc-src/build.mjs @@ -0,0 +1,18 @@ +import { build } from 'esbuild'; +import { copyFile } from 'node:fs/promises'; +await build({ + entryPoints: [new URL('./worker.mjs', import.meta.url).pathname], + bundle: true, + platform: 'node', + format: 'esm', + target: 'node20', + minify: true, + outfile: new URL('../miniapp/node/ptc-worker.mjs', import.meta.url).pathname, +}); +await copyFile( + new URL( + './node_modules/@jitl/quickjs-wasmfile-release-sync/dist/emscripten-module.wasm', + import.meta.url, + ), + new URL('../miniapp/node/quickjs.wasm', import.meta.url), +); diff --git a/plugins/webguhui/minimax-photo/ptc-src/package-lock.json b/plugins/webguhui/minimax-photo/ptc-src/package-lock.json new file mode 100644 index 00000000..841d685a --- /dev/null +++ b/plugins/webguhui/minimax-photo/ptc-src/package-lock.json @@ -0,0 +1,495 @@ +{ + "name": "ptc-src", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@jitl/quickjs-wasmfile-release-sync": "0.32.0", + "esbuild": "0.25.11", + "quickjs-emscripten-core": "0.32.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", + "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", + "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", + "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", + "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", + "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", + "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", + "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", + "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", + "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", + "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", + "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", + "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", + "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", + "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", + "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", + "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", + "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", + "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", + "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", + "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", + "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", + "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", + "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", + "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", + "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", + "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jitl/quickjs-ffi-types": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/@jitl/quickjs-ffi-types/-/quickjs-ffi-types-0.32.0.tgz", + "integrity": "sha512-v9T+GQpmk43VDJ7d72sf0Nexhk+ArvtUihW27dy7lqAl0zBObFKtSBBIm5RBjwIhE8VwsPPm9PNuvPvNqLWUEg==", + "license": "MIT" + }, + "node_modules/@jitl/quickjs-wasmfile-release-sync": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-release-sync/-/quickjs-wasmfile-release-sync-0.32.0.tgz", + "integrity": "sha512-BKNDI/TPBfGlLNGYpLrhcDGXmIk4xHm4MRAisOBnOzpXVn9HZWsfmMAc9WMBrAHjvvds6HOikKeaOBKdPdpVrg==", + "license": "MIT", + "dependencies": { + "@jitl/quickjs-ffi-types": "0.32.0" + } + }, + "node_modules/esbuild": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", + "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.11", + "@esbuild/android-arm": "0.25.11", + "@esbuild/android-arm64": "0.25.11", + "@esbuild/android-x64": "0.25.11", + "@esbuild/darwin-arm64": "0.25.11", + "@esbuild/darwin-x64": "0.25.11", + "@esbuild/freebsd-arm64": "0.25.11", + "@esbuild/freebsd-x64": "0.25.11", + "@esbuild/linux-arm": "0.25.11", + "@esbuild/linux-arm64": "0.25.11", + "@esbuild/linux-ia32": "0.25.11", + "@esbuild/linux-loong64": "0.25.11", + "@esbuild/linux-mips64el": "0.25.11", + "@esbuild/linux-ppc64": "0.25.11", + "@esbuild/linux-riscv64": "0.25.11", + "@esbuild/linux-s390x": "0.25.11", + "@esbuild/linux-x64": "0.25.11", + "@esbuild/netbsd-arm64": "0.25.11", + "@esbuild/netbsd-x64": "0.25.11", + "@esbuild/openbsd-arm64": "0.25.11", + "@esbuild/openbsd-x64": "0.25.11", + "@esbuild/openharmony-arm64": "0.25.11", + "@esbuild/sunos-x64": "0.25.11", + "@esbuild/win32-arm64": "0.25.11", + "@esbuild/win32-ia32": "0.25.11", + "@esbuild/win32-x64": "0.25.11" + } + }, + "node_modules/quickjs-emscripten-core": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/quickjs-emscripten-core/-/quickjs-emscripten-core-0.32.0.tgz", + "integrity": "sha512-QFnPfjFey8EqknSrSxe1hZrf1/8z7/6s1QzGOmKo6++02r7QRRX7ZoyNaZh7JuVjWsVW87KnQrbZqnHkOAzUyg==", + "license": "MIT", + "dependencies": { + "@jitl/quickjs-ffi-types": "0.32.0" + } + } + } +} diff --git a/plugins/webguhui/minimax-photo/ptc-src/package.json b/plugins/webguhui/minimax-photo/ptc-src/package.json new file mode 100644 index 00000000..a90304a9 --- /dev/null +++ b/plugins/webguhui/minimax-photo/ptc-src/package.json @@ -0,0 +1,7 @@ +{ + "dependencies": { + "@jitl/quickjs-wasmfile-release-sync": "0.32.0", + "esbuild": "0.25.11", + "quickjs-emscripten-core": "0.32.0" + } +} diff --git a/plugins/webguhui/minimax-photo/ptc-src/worker.mjs b/plugins/webguhui/minimax-photo/ptc-src/worker.mjs new file mode 100644 index 00000000..57bab359 --- /dev/null +++ b/plugins/webguhui/minimax-photo/ptc-src/worker.mjs @@ -0,0 +1,103 @@ +import { parentPort, workerData } from 'node:worker_threads'; +import { readFile } from 'node:fs/promises'; +import { newQuickJSWASMModuleFromVariant, newVariant } from 'quickjs-emscripten-core'; +import variant from '@jitl/quickjs-wasmfile-release-sync'; + +// User code only runs inside QuickJS. No Node objects enter that VM. +const bytes = await readFile(new URL('./quickjs.wasm', import.meta.url)); +const module = await newQuickJSWASMModuleFromVariant(newVariant(variant, { wasmBinary: bytes })); +const runtime = module.newRuntime(); +runtime.setMemoryLimit(32 * 1024 * 1024); +runtime.setMaxStackSize(512 * 1024); +runtime.setInterruptHandler(() => Date.now() > workerData.deadline); +const vm = runtime.newContext(); +let sequence = 0, + done = false; +const pending = new Map(); +const logs = []; +let logBytes = 0; +vm.newFunction('__log', (level, value) => { + if (logs.length >= 50 || logBytes >= 10000) return; + const text = vm.getString(value).slice(0, Math.min(1000, 10000 - logBytes)); + logBytes += text.length; + logs.push({ level: vm.getString(level), text }); +}).consume(handle => vm.setProp(vm.global, '__log', handle)); +function fail(error) { + if (!done) { + done = true; + parentPort.postMessage({ type: 'done', error: String(error).slice(0, 2000), logs }); + } +} +function pump() { + if (done) return; + const result = runtime.executePendingJobs(100); + if (result.error) { + const error = vm.dump(result.error); + result.error.dispose(); + fail(error.message || JSON.stringify(error)); + } +} +vm.newFunction('__call', (name, input) => { + const method = vm.getString(name), + json = vm.getString(input); + if (json.length > 65536) return { error: vm.newError('工具参数超过 64 KB') }; + const promise = vm.newPromise(), + id = ++sequence; + pending.set(id, promise); + parentPort.postMessage({ type: 'call', id, method, args: JSON.parse(json) }); + return promise.handle; +}).consume((handle) => vm.setProp(vm.global, '__call', handle)); +vm.newFunction('__done', (value, error) => { + if (pending.size) return fail('存在未 await 的工具调用,请查询 trace 中的任务结果'); + const json = vm.getString(value); + if (json.length > 65536) return fail('脚本返回值超过 64 KB'); + if (!done) { + done = true; + parentPort.postMessage({ + type: 'done', + result: JSON.parse(json), + error: vm.getString(error) || undefined, + logs, + }); + } +}).consume((handle) => vm.setProp(vm.global, '__done', handle)); +parentPort.on('message', (message) => { + if (done) return; + const promise = pending.get(message.id); + if (!promise) return; + pending.delete(message.id); + const value = message.error + ? vm.newError(message.error) + : vm.newString(JSON.stringify(message.result)); + if (message.error) promise.reject(value); + else promise.resolve(value); + value.dispose(); + promise.dispose(); + pump(); +}); +const source = ` +const console = Object.freeze(Object.fromEntries( + ['log','info','warn','error','debug'].map(level => [level, (...values) => { + const text = values.map(value => { + if (typeof value === 'string') return value; + try { return JSON.stringify(value) ?? String(value); } catch { return '[unserializable]'; } + }).join(' '); + __log(level, text); + }]) +)); +const editor = Object.freeze(Object.fromEntries( + ['inspect','capabilities','preview','edit','create','export','commands','execute','draw'].map(name => + [name, async (args) => JSON.parse(await __call(name, JSON.stringify(args ?? null)))]) +)); +(async () => { ${workerData.code}\n })() + .then(value => __done(JSON.stringify(value ?? null), '')) + .catch(error => __done('null', String(error) + '\\n' + String(error?.stack || ''))); +`; +const evaluated = vm.evalCode(source, 'editor-script.js'); +if (evaluated.error) { + const error = vm.dump(evaluated.error); + evaluated.error.dispose(); + fail(error.message || JSON.stringify(error)); +} else evaluated.value.dispose(); +pump(); +setInterval(pump, 10); diff --git a/plugins/webguhui/minimax-photo/scripts/browser-checks/blend-check.html b/plugins/webguhui/minimax-photo/scripts/browser-checks/blend-check.html new file mode 100644 index 00000000..fe6da3b2 --- /dev/null +++ b/plugins/webguhui/minimax-photo/scripts/browser-checks/blend-check.html @@ -0,0 +1,23 @@ +混合模式对照 +

混合模式对照

+

+ 16 种模式 × 12 对颜色,与浏览器 Canvas 的不透明颜色混合比较;允许最多 2 个 8-bit 色阶的舍入差异。 +

+ +
未开始
+ diff --git a/plugins/webguhui/minimax-photo/scripts/browser-checks/blend-check.js b/plugins/webguhui/minimax-photo/scripts/browser-checks/blend-check.js new file mode 100644 index 00000000..912ac35f --- /dev/null +++ b/plugins/webguhui/minimax-photo/scripts/browser-checks/blend-check.js @@ -0,0 +1,51 @@ +import { blends } from './model.js'; +import { blendPixel, pixelBlendModes } from './blending.js'; +const colors = [ + [0, 0, 0], + [255, 255, 255], + [255, 0, 0], + [0, 255, 0], + [0, 0, 255], + [128, 128, 128], + [20, 80, 230], + [240, 90, 10], + [64, 1, 254], + [1, 254, 64], + [17, 188, 120], + [230, 190, 51], +]; +document.querySelector('#run').onclick = () => { + const canvas = document.createElement('canvas'); + canvas.width = canvas.height = 1; + const ctx = canvas.getContext('2d', { willReadFrequently: true }), + modes = []; + const computed = new Float64Array(3); + for (const mode of blends.filter((mode) => !pixelBlendModes.includes(mode))) { + let maxError = 0; + for (let i = 0; i < colors.length; i++) { + const b = colors[i], + s = colors[(i * 5 + 3) % colors.length]; + ctx.globalCompositeOperation = 'copy'; + ctx.fillStyle = `rgb(${b})`; + ctx.fillRect(0, 0, 1, 1); + ctx.globalCompositeOperation = mode; + ctx.fillStyle = `rgb(${s})`; + ctx.fillRect(0, 0, 1, 1); + const expected = ctx.getImageData(0, 0, 1, 1).data; + blendPixel(mode, b, s, 0, computed); + for (let c = 0; c < 3; c++) + maxError = Math.max(maxError, Math.abs(Math.round(computed[c]) - expected[c])); + } + modes.push({ mode, maxError, pass: maxError <= 2 }); + } + document.querySelector('#result').textContent = JSON.stringify( + { + cases: modes.length * colors.length, + allPassed: modes.every((m) => m.pass), + modes, + note: '不透明 RGB 混合与当前浏览器 Canvas 的对照,不是 Photoshop 或原站文件兼容性证明', + }, + null, + 2, + ); +}; diff --git a/plugins/webguhui/minimax-photo/scripts/browser-checks/cache-check.html b/plugins/webguhui/minimax-photo/scripts/browser-checks/cache-check.html new file mode 100644 index 00000000..94459e61 --- /dev/null +++ b/plugins/webguhui/minimax-photo/scripts/browser-checks/cache-check.html @@ -0,0 +1,26 @@ +图层重绘检查 +

图层重绘检查

+

1280 × 800,文字图层,描边、浮雕和投影。同一浏览器、相同像素。

+ +
未开始
+
+ diff --git a/plugins/webguhui/minimax-photo/scripts/browser-checks/cache-check.js b/plugins/webguhui/minimax-photo/scripts/browser-checks/cache-check.js new file mode 100644 index 00000000..90dabf72 --- /dev/null +++ b/plugins/webguhui/minimax-photo/scripts/browser-checks/cache-check.js @@ -0,0 +1,89 @@ +import { + layer, + renderedLayer, + layerRenderCache, + invalidateLayer, + documentModel, + begin, + undo, + redo, +} from './model.js'; +import { normalizeStyles } from './layer-styles.js'; +const button = document.querySelector('#run'), + result = document.querySelector('#result'); +button.onclick = async () => { + button.disabled = true; + result.textContent = '检查中…'; + await new Promise(requestAnimationFrame); + try { + const l = layer(1280, 800, 'benchmark'), + ctx = l.canvas.getContext('2d'); + ctx.fillStyle = '#227fa8'; + ctx.font = 'bold 140px sans-serif'; + ctx.fillText('RETOUCH', 100, 400); + l.styles = normalizeStyles({ + stroke: { enabled: true }, + bevel: { enabled: true }, + shadow: { enabled: true }, + }); + const cold = [], + warm = []; + let baseline; + for (let i = 0; i < 5; i++) { + layerRenderCache.clear(); + const start = performance.now(); + baseline = renderedLayer(l); + cold.push(performance.now() - start); + await new Promise(requestAnimationFrame); + } + const pixels = (r) => + r.image.getContext('2d').getImageData(0, 0, r.image.width, r.image.height).data; + const original = pixels(baseline); + let hit; + for (let i = 0; i < 10; i++) { + const start = performance.now(); + hit = renderedLayer(l); + warm.push(performance.now() - start); + } + const cached = pixels(hit); + const same = original.length === cached.length && original.every((v, i) => v === cached[i]); + const d = documentModel(1280, 800); + d.layers = [l]; + d.activeId = l.id; + begin(d, '测试绘制', [l.id]); + const edited = d.layers[0]; + edited.canvas.getContext('2d').fillRect(200, 500, 100, 50); + invalidateLayer(edited); + const changed = pixels(renderedLayer(edited)); + const editVisible = original.some((v, i) => v !== changed[i]); + undo(d); + const undone = pixels(renderedLayer(d.layers[0])); + const undoRestored = original.every((v, i) => v === undone[i]); + redo(d); + const redone = pixels(renderedLayer(d.layers[0])); + const redoRestored = changed.every((v, i) => v === redone[i]); + const median = (a) => [...a].sort((a, b) => a - b)[Math.floor(a.length / 2)]; + result.textContent = JSON.stringify( + { + size: [1280, 800], + coldMs: cold, + warmMs: warm, + coldMedianMs: median(cold), + warmMedianMs: median(warm), + cachedPixelsEqual: same, + editVisible, + undoRestored, + redoRestored, + cache: layerRenderCache.stats(), + note: '仅本实现缓存前后;不代表原站对比、首帧或完整交互帧率', + }, + null, + 2, + ); + document.querySelector('#image').replaceChildren(hit.image); + } catch (e) { + result.textContent = 'FAIL ' + e.stack; + } finally { + button.disabled = false; + } +}; diff --git a/plugins/webguhui/minimax-photo/scripts/browser-checks/psd-check.html b/plugins/webguhui/minimax-photo/scripts/browser-checks/psd-check.html new file mode 100644 index 00000000..98b17362 --- /dev/null +++ b/plugins/webguhui/minimax-photo/scripts/browser-checks/psd-check.html @@ -0,0 +1,8 @@ +PSD 图层往返检查 +

PSD 图层往返检查

+

+ 27 种模式:导出再打开,检查图层、位置、透明度、中文名和合成像素。不是 Photoshop 外部兼容性证明。 +

+ +
未开始
+ diff --git a/plugins/webguhui/minimax-photo/scripts/browser-checks/psd-check.js b/plugins/webguhui/minimax-photo/scripts/browser-checks/psd-check.js new file mode 100644 index 00000000..3400fc7d --- /dev/null +++ b/plugins/webguhui/minimax-photo/scripts/browser-checks/psd-check.js @@ -0,0 +1,46 @@ +import { documentModel, layer, blends, composite } from './model.js'; +import { readPSD, writePSD } from './codecs.js'; +document.querySelector('#run').onclick = async () => { + const results = []; + for (const mode of blends) { + try { + const d = documentModel(8, 8, '混合测试'); + const base = layer(8, 8, '背景'), + top = layer(4, 4, '中文前景'); + base.canvas.getContext('2d').fillStyle = '#6496c8'; + base.canvas.getContext('2d').fillRect(0, 0, 8, 8); + const ctx = top.canvas.getContext('2d'); + ctx.fillStyle = '#3264c8'; + ctx.fillRect(0, 0, 4, 4); + ctx.clearRect(0, 0, 1, 1); + top.x = 2; + top.y = 3; + top.opacity = 0.6; + top.blend = mode; + d.layers = [base, top]; + const restored = readPSD(await writePSD(d).arrayBuffer(), '往返'); + const pixels = (doc) => composite(doc).getContext('2d').getImageData(0, 0, 8, 8).data; + const a = pixels(d), + b = pixels(restored); + let maxError = 0; + for (let i = 0; i < a.length; i++) maxError = Math.max(maxError, Math.abs(a[i] - b[i])); + const l = restored.layers[1]; + const pass = + restored.layers.length === 2 && + l.blend === mode && + l.x === 2 && + l.y === 3 && + l.name === '中文前景' && + l.opacity === 0.6 && + maxError === 0; + results.push({ mode, pass, maxError, layers: restored.layers.length }); + } catch (error) { + results.push({ mode, pass: false, error: error.message }); + } + } + document.querySelector('#result').textContent = JSON.stringify( + { allPassed: results.every((r) => r.pass), results }, + null, + 2, + ); +}; diff --git a/plugins/webguhui/minimax-photo/scripts/check-activity.mjs b/plugins/webguhui/minimax-photo/scripts/check-activity.mjs new file mode 100644 index 00000000..275c1089 --- /dev/null +++ b/plugins/webguhui/minimax-photo/scripts/check-activity.mjs @@ -0,0 +1,33 @@ +import assert from 'node:assert/strict'; +import { operationPaths, projectPoint, validViewport } from '../miniapp/client/photo-activity.js'; +const view = { + origin: [100, 200], + xAxis: [0, 2], + yAxis: [-2, 0], + size: [800, 600], + clip: [20, 20, 600, 500], +}; +assert.deepEqual(projectPoint([10, 20], view), [60, 220]); +assert.ok(validViewport(view)); +assert.ok(!validViewport({ ...view, size: [0, 600] })); +assert.deepEqual( + operationPaths('execute', { + command: 'paint.stroke', + params: { points: [[NaN, 0]] }, + }), + [], +); +assert.deepEqual(operationPaths('preview', {}), []); +const points = Array.from({ length: 5000 }, (_, i) => [i, i === 1 ? 9000 : 0]); +const input = { command: 'paint.stroke', params: { points, size: 20 } }; +const original = JSON.stringify(input); +const [path] = operationPaths('execute', input); +assert.ok(path.points.length <= 513); +assert.deepEqual(path.points.at(-1), points.at(-1)); +assert.deepEqual(path.bounds, [0, 0, 4999, 9000]); +assert.equal(JSON.stringify(input), original); +assert.equal(operationPaths('batch', Array(64).fill(input)).length, 8); +assert.deepEqual(operationPaths('batch', [input, { command: 'image.rotate', params: {} }]), []); +console.log( + 'PASS activity: rotated coordinates, invalid input, bounded replay, full bounds, unchanged commands', +); diff --git a/plugins/webguhui/minimax-photo/scripts/check-draw.mjs b/plugins/webguhui/minimax-photo/scripts/check-draw.mjs new file mode 100644 index 00000000..9acd6dfd --- /dev/null +++ b/plugins/webguhui/minimax-photo/scripts/check-draw.mjs @@ -0,0 +1,45 @@ +import assert from 'node:assert/strict'; +import { drawStrokes } from '../miniapp/client/photocraft/draw.js'; +const stroke = { points: [[0, 0, .2], [10, 10, .7]], size: 2 }; +let version = 'v0', count = 0; +const events = []; +const call = async (method, args, expected) => { + if (method === 'inspect') return { version }; + assert.equal(expected, version); + events.push('stroke'); + version = `v${++count}`; + return { state: { version } }; +}; +const result = await drawStrokes({ strokes: [stroke, stroke] }, 'v0', call, async () => events.push('render')); +assert.deepEqual(events, ['stroke', 'render', 'stroke', 'render']); +assert.equal(result.state.version, 'v2'); +await assert.rejects(drawStrokes({ strokes: [stroke] }, 'v0', call), /document changed/); +await assert.rejects(drawStrokes({ strokes: [] }, version, call), /1..96/); +await assert.rejects(drawStrokes({ strokes: [stroke], intervalMs: 0 }, version, call), /100 and 600/); +let executed = 0; +await assert.rejects(drawStrokes({ strokes: [stroke, stroke] }, version, async (...args) => { + if (args[0] === 'execute' && ++executed === 2) throw Error('invalid brush'); + return call(...args); +}, async () => {}), /after 1\/2 strokes; completed strokes remain/); +assert.equal(count, 3); +console.log('PASS draw: visible sequential edits, version tracking, validation and partial failure'); + +const { pathPoints, brushParameters } = await import('../miniapp/client/photocraft/draw-path.js'); +const samples = [[1,2], [3,4,0,12,13,14,15,16], {x:5,y:6}, {x:7,y:8,pressure:.8}]; +const originalSamples = structuredClone(samples); +assert.deepEqual(brushParameters({points:samples,pressure:.5}).points, + [[1,2,.5], [3,4,0,12,13,14,15,16], {x:5,y:6,pressure:.5}, {x:7,y:8,pressure:.8}]); +assert.deepEqual(samples, originalSamples); +assert.equal(brushParameters({points:samples}).points, samples); +await assert.rejects(drawStrokes({strokes:[stroke,{points:[[0,0]],pressure:2}]}, version, + async () => { throw Error('must validate before editing'); }), /pressure must/); +console.log('PASS pressure: stroke defaults, per-point override, extended samples and pre-edit validation'); +const curve = pathPoints([['M',0,0],['C',0,100,100,100,100,0]], .5); +assert.deepEqual(curve[0], [0,0,.5]); +assert.deepEqual(curve.at(-1), [100,0,.5]); +assert.ok(Math.max(...curve.map(p=>p[1])) > 74); +assert.ok(curve.every(p=>p[0]>=0 && p[0]<=100 && p[1]>=0 && p[1]<=75)); +assert.throws(()=>pathPoints([['L',0,0]]), /start with M/); +assert.throws(()=>pathPoints([['M',0,0],['C',1,2,3,NaN,4,5]]), /absolute/); +assert.deepEqual(pathPoints([['M',1,2],['L',3,4],['Z']]).at(-1), [1,2,1]); +console.log('PASS paths: curve endpoints, smooth bounds, closure and invalid geometry'); diff --git a/plugins/webguhui/minimax-photo/scripts/check-ptc.mjs b/plugins/webguhui/minimax-photo/scripts/check-ptc.mjs new file mode 100644 index 00000000..8677b141 --- /dev/null +++ b/plugins/webguhui/minimax-photo/scripts/check-ptc.mjs @@ -0,0 +1,55 @@ +import assert from 'node:assert/strict'; +import { Worker } from 'node:worker_threads'; + +async function execute(code, duration = 2000) { + const worker = new Worker(new URL('../miniapp/node/ptc-worker.mjs', import.meta.url), { + workerData: { code, deadline: Date.now() + duration }, + }); + let calls = 0; + try { + return await new Promise((resolve, reject) => { + const timer = setTimeout(() => reject(Error('PTC 未终止')), 5000); + worker.on('error', (error) => { + clearTimeout(timer); + reject(error); + }); + worker.on('message', (message) => { + if (message.type === 'call') { + calls++; + worker.postMessage({ id: message.id, result: { value: calls } }); + } else { + clearTimeout(timer); + resolve({ ...message, calls }); + } + }); + }); + } finally { + await worker.terminate(); + } +} +const composed = await execute( + 'let sum=0; for(let i=0;i<3;i++) { const v=await editor.inspect(); if(v.value>1) sum+=v.value; } return {sum,process:typeof process,fetch:typeof fetch,require:typeof require};', +); +assert.deepEqual(composed.result, { + sum: 5, + process: 'undefined', + fetch: 'undefined', + require: 'undefined', +}); +assert.equal(composed.calls, 3); +const logged = await execute('await editor.inspect(); console.log("done", {steps:1}); for(let i=0;i<100;i++) console.warn("x".repeat(1000)); return 7;'); +assert.equal(logged.result, 7); +assert.equal(logged.calls, 1); +assert.deepEqual(logged.logs[0], {level:'log', text:'done {"steps":1}'}); +assert.ok(logged.logs.length <= 50); +assert.ok(logged.logs.reduce((sum, item) => sum + item.text.length, 0) <= 10000); +assert.match((await execute('while(true){}', 150)).error, /interrupt/i); +assert.match( + (await execute('return new Uint8Array(64 * 1024 * 1024);')).error, + /memory|allocation/i, +); +assert.match( + (await execute('await editor.inspect(); throw Error("stop here")')).error, + /stop here/, +); +console.log('PASS PTC:真实 JS 异步循环、条件、环境隔离、死循环中止、内存上限、异常返回'); diff --git a/plugins/webguhui/minimax-photo/scripts/check-recovery.mjs b/plugins/webguhui/minimax-photo/scripts/check-recovery.mjs new file mode 100644 index 00000000..d6db07a4 --- /dev/null +++ b/plugins/webguhui/minimax-photo/scripts/check-recovery.mjs @@ -0,0 +1,21 @@ +import assert from 'node:assert/strict'; +import { mkdtemp, rm } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { createRecoveryStore } from '../miniapp/node/recovery-store.mjs'; +const root = await mkdtemp(join(tmpdir(), 'photo-recovery-')); +try { + const store = await createRecoveryStore(root); + const id = 'document-00000000-0000-4000-8000-000000000001'; + const value = { name: 'Layered work', data: 'YWJj' }; + const writes = await Promise.allSettled([store.put(id, { revision: 0, value }), store.put(id, { revision: 0, value })]); + assert.equal(writes.filter(x => x.status === 'fulfilled').length, 1); + assert.equal(writes.find(x => x.status === 'rejected').reason.status, 409); + const restarted = await createRecoveryStore(root); + assert.deepEqual((await restarted.get(id)).value, value); + assert.equal((await restarted.list())[0].name, value.name); + await assert.rejects(store.put(id, { revision: 1, value: { name: 'invalid', data: '!!' } })); + assert.equal((await store.get(id)).revision, 1); + await assert.rejects(store.get('../../outside')); + console.log('PASS Recovery: restart, concurrent stale writes, invalid data and path boundaries'); +} finally { await rm(root, { recursive: true, force: true }); } diff --git a/plugins/webguhui/minimax-photo/scripts/check.mjs b/plugins/webguhui/minimax-photo/scripts/check.mjs new file mode 100644 index 00000000..0c145704 --- /dev/null +++ b/plugins/webguhui/minimax-photo/scripts/check.mjs @@ -0,0 +1,748 @@ +import { readEditorFile } from '../miniapp/node/editor-file.mjs'; +import { callEditorTool } from '../miniapp/node/editor-mcp.mjs'; +import { createEditorService } from '../miniapp/node/editor-service.mjs'; +import { EventEmitter } from 'node:events'; +import { colorReplacementPatch } from '../miniapp/client/color-replace.js'; +import { validatePNG } from '../miniapp/node/png-validation.mjs'; +import { backgroundEraseMask } from '../miniapp/client/background-eraser.js'; +import { runOutline } from '../miniapp/client/selection-outline.js'; +import { floodRegion } from '../miniapp/client/flood-region.js'; +import { unpackLZW } from '../miniapp/client/tiff-lzw.js'; +import { readTIFF } from '../miniapp/client/tiff-reader.js'; +import { writeTIFF } from '../miniapp/client/tiff.js'; +import { compositePixels, blendPixel, pixelBlendModes } from '../miniapp/client/blending.js'; +import assert from 'node:assert/strict'; +import { mkdir, mkdtemp, readFile, rm, readdir, stat, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { randomUUID } from 'node:crypto'; +import { performance } from 'node:perf_hooks'; +import { start } from '../miniapp/node/server.mjs'; +import { curveLUT } from '../miniapp/client/tone.js'; +import { filterPixels } from '../miniapp/client/filters.js'; +import { distanceMap, strokePixels, bevelPixels } from '../miniapp/client/style-pixels.js'; +import { normalizeStyles } from '../miniapp/client/layer-styles.js'; +import { createRenderCache } from '../miniapp/client/render-cache.js'; +import { + adjustedPixels, + normalizeAdjustment, + compositionGroups, + clippingBase, +} from '../miniapp/client/adjustment-layers.js'; +const root = fileURLToPath(new URL('../', import.meta.url)); +const results = []; +const check = async (name, fn) => { + await fn(); + results.push({ name, status: 'PASS' }); + console.log('PASS', name); +}; +await check('Artistic filters: alpha, identity colors, contours and stable diffusion', () => { + const white = new Uint8ClampedArray([255, 255, 255, 255, 255, 255, 255, 80, 255, 255, 255, 0]); + assert.deepEqual(filterPixels(white, 3, 1, 'halftone', 3), white); + const black = new Uint8ClampedArray([0, 0, 0, 255, 0, 0, 0, 80, 0, 0, 0, 0]); + assert.deepEqual(filterPixels(black, 3, 1, 'halftone', 3), black); + const ramp = new Uint8ClampedArray([0, 0, 0, 255, 100, 100, 100, 80, 200, 200, 200, 255]); + const contour = filterPixels(ramp, 3, 1, 'traceContour', 128); + assert.deepEqual([...contour], [255, 255, 255, 255, 0, 0, 0, 80, 0, 0, 0, 255]); + for (const type of ['halftone', 'diffuse', 'traceContour', 'glowingEdges']) { + const result = filterPixels(ramp, 3, 1, type, 3); + assert.deepEqual([result[3], result[7], result[11]], [255, 80, 255]); + } + assert.deepEqual(filterPixels(ramp, 3, 1, 'diffuse', 2), filterPixels(ramp, 3, 1, 'diffuse', 2)); + assert.deepEqual([...ramp], [0, 0, 0, 255, 100, 100, 100, 80, 200, 200, 200, 255]); + const flat = new Uint8ClampedArray(5 * 5 * 4).fill(255); + assert.deepEqual(filterPixels(flat, 5, 5, 'oilPaint', 2), flat); + const isolated = new Uint8ClampedArray(flat); + isolated.set([255, 0, 0, 80], 48); + const painted = filterPixels(isolated, 5, 5, 'oilPaint', 1); + assert.deepEqual([...painted.slice(48, 52)], [255, 255, 255, 80]); + assert.deepEqual([...isolated.slice(48, 52)], [255, 0, 0, 80]); + const edges = filterPixels(flat, 5, 5, 'glowingEdges', 2); + assert.equal(edges[0], 0); + assert.equal(edges[3], 255); +}); +await check('Agent 编辑事务:归属、并发、重复、持久化与中断', async () => { + const dir = await mkdtemp(join(tmpdir(), 'retouch-editor-check-')); + const service = await createEditorService(dir), + request = new EventEmitter(); + const editorId = randomUUID(), + documentId = randomUUID(); + const response = { + writeHead() {}, + write() {}, + end() { + request.emit('close'); + }, + }; + try { + service.register({ editorId, version: 'v1', document: { id: documentId } }); + service.subscribe(editorId, request, response); + assert.deepEqual(service.inspect(editorId).page, { visibility: 'unknown', focused: null }); + const input = { editorId, expectedVersion: 'v1', requestId: randomUUID(), kind: 'preview' }; + await assert.rejects( + service.submit({ ...input, requestId: randomUUID(), expectedVersion: 'stale' }), + /版本/, + ); + // Invalid export options fail before creating a task or touching the canvas. + for (const args of [{format: 'png', path: '/tmp/ignored.png'}, {outputPath: '/tmp/ignored.png'}, {format: 'invalid'}]) { + const requestId = randomUUID(); + await assert.rejects(service.submit({...input, requestId, kind: 'craft', options: {method: 'export', args}}), /export|导出格式/); + await assert.rejects(service.result(requestId), {code: 'ENOENT'}); + } + for (const options of [ + {method:'execute', args:{command:'document.pixel', params:{x:'320',y:'210'}}}, + {method:'execute', args:{command:'document.pixel', params:{x:0,y:0.5}}}, + {method:'execute', args:{command:'document.pixel', params:{x:2147483648,y:0}}}, + {method:'execute', args:{command:'document.pixel', params:{x:0}}}, + {method:'execute', args:{command:'layer.select', params:'{}'}}, + {method:'batch', args:[{command:'document.pixel',params:{x:'0',y:0}}]}, + ]) { + const requestId = randomUUID(); + await assert.rejects(service.submit({...input, requestId, kind:'craft', options}), /整数|JSON 对象/); + await assert.rejects(service.result(requestId), {code:'ENOENT'}); + } + const jobs = await Promise.all([service.submit(input), service.submit(input)]); + assert.equal(jobs[0].jobId, jobs[1].jobId); + await assert.rejects( + service.submit({ ...input, kind: 'batch', operations: [{ op: 'undo' }] }), + /不同请求/, + ); + const claimed = await service.claim(editorId, input.requestId); + service.register({ editorId, version: 'stale', document: null, + page: { visibility: 'hidden', focused: false, sessionId: 'untrusted' } }); + assert.deepEqual(service.list()[0].page, { visibility: 'hidden', focused: false }); + assert.equal(service.inspect(editorId).version, 'v1'); + assert.deepEqual(service.inspect(editorId).document, { id: documentId }); + await assert.rejects(service.claim(editorId, input.requestId), /重复/); + await assert.rejects( + service.finish(editorId, input.requestId, { claim: randomUUID(), error: 'bad' }), + /归属/, + ); + const preview = + 'data:image/png;base64,' + (await readFile(join(root, 'icon.png'))).toString('base64'); + const prepared = await service.finish(editorId, input.requestId, { + claim: claimed.claim, + preview, + result: { id: documentId }, + }); + assert.equal(prepared.status, 'prepared'); + assert.equal(prepared.claim, undefined); + await service.acknowledge(editorId, input.requestId, { claim: claimed.claim, version: 'v2' }); + assert.equal(service.inspect(editorId).version, 'v2'); + const restored = await createEditorService(dir); + assert.equal((await restored.result(input.requestId)).status, 'succeeded'); + assert.deepEqual( + await readFile((await restored.result(input.requestId)).previewPath), + await readFile(join(root, 'icon.png')), + ); + restored.close(); + const pending = await service.submit({ + ...input, + requestId: randomUUID(), + expectedVersion: 'v2', + }); + request.emit('close'); + assert.equal((await service.result(pending.jobId)).status, 'interrupted'); + assert.equal(service.list().length, 0); + const craftEditorId = randomUUID(); + service.register({editorId: craftEditorId, version: 'v3', engine: 'photocraft', document: {id: documentId}}); + service.subscribe(craftEditorId, request, response); + const validExport = await service.submit({...input, editorId: craftEditorId, requestId: randomUUID(), expectedVersion: 'v3', kind: 'craft', options: {method: 'export', args: {format: 'png'}}}); + assert.equal(validExport.status, 'queued'); + assert.deepEqual(validExport.options.args, {format: 'png'}); + request.emit('close'); + const importId = randomUUID(); + service.register({editorId: importId, version: 'empty', engine: 'photocraft', document: null}); + service.subscribe(importId, request, response); + const filePath = join(root, 'icon.png'); + const file = await readEditorFile(filePath); + assert.equal(file.data, (await readFile(filePath)).toString('base64')); + const uppercaseProject = join(dir, 'Keep-My-Title.PCRAFT'); + const projectHeader = Buffer.concat([Buffer.from([80,75,3,4]), Buffer.alloc(12)]); + await writeFile(uppercaseProject, projectHeader); + const normalizedProject = await readEditorFile(uppercaseProject); + assert.equal(normalizedProject.name, 'Keep-My-Title.pcraft'); + assert.equal(normalizedProject.data, projectHeader.toString('base64')); + assert.deepEqual(await readFile(uppercaseProject), projectHeader); + + await assert.rejects(readEditorFile('relative.png'), /绝对路径/); + await assert.rejects(readEditorFile(join(root, 'package.json')), /支持/); + const fake = join(dir, 'fake.png'); + await writeFile(fake, 'this is not an image'); + await assert.rejects(readEditorFile(fake), /内容/); + const args = {editorId: importId, expectedVersion: 'empty', requestId: randomUUID(), filePath}; + const first = await callEditorTool('editor_open_file', args, service); + const again = await callEditorTool('editor_open_file', args, service); + assert.deepEqual(first, again); + const summary = JSON.parse(first.content[0].text); + assert.equal(summary.status, 'queued'); + assert.deepEqual(summary.options, {method: 'open', args: {name: 'icon.png'}}); + const importJob = await service.claim(importId, args.requestId); + assert.deepEqual(importJob.options.args, file); + request.emit('close'); + for (const coords of [{x:320,y:210}, {x:-2147483648,y:2147483647}]) { + const pixelEditor = randomUUID(); + service.register({editorId:pixelEditor,version:'p1',engine:'photocraft',document:{id:documentId}}); + service.subscribe(pixelEditor,request,response); + const pixel = await service.submit({editorId:pixelEditor,expectedVersion:'p1',requestId:randomUUID(), + kind:'craft',options:{method:'execute',args:{command:'document.pixel',params:coords}}}); + assert.equal(pixel.status,'queued'); + assert.deepEqual(pixel.options.args.params,coords); + request.emit('close'); + } + + + } finally { + service.close(); + await rm(dir, { recursive: true, force: true }); + } +}); +await check('Mini App manifest 与 payload 文件', async () => { + const p = JSON.parse(await readFile(join(root, 'package.json'))), + plugin = JSON.parse(await readFile(join(root, '.minimax-plugin/plugin.json'))), + app = JSON.parse(await readFile(join(root, 'miniapp/miniapp.json'))); + assert.equal(p.mcode.schemaVersion, 2); + assert.equal(plugin.name, 'minimax-photo'); + assert.equal(app.runtime.kind, 'process'); + for (const path of [ + ...app.artifacts.client, + ...app.artifacts.node, + app.runtime.entry, + plugin.icon, + ]) + assert((await stat(join(root, path))).isFile() || (await stat(join(root, path))).isDirectory()); +}); +await check('扩展混合模式:色值、透明覆盖、强度与零除边界', () => { + const b = new Uint8ClampedArray([100, 150, 200, 255]); + const s = new Uint8ClampedArray([50, 100, 200, 255]); + const expected = [ + [50, 100, 200, 255], + [0, 0, 145, 255], + [150, 250, 255, 255], + [50, 50, 0, 255], + [255, 255, 255, 255], + [0, 121, 255, 255], + [0, 95, 255, 255], + [100, 150, 200, 255], + [0, 0, 255, 255], + [50, 100, 200, 255], + [100, 150, 200, 255], + ]; + pixelBlendModes.forEach((mode, i) => { + assert.deepEqual([...compositePixels(b, s, mode)], expected[i]); + assert.deepEqual(compositePixels(b, s, mode, 0), b); + assert.deepEqual(compositePixels(new Uint8ClampedArray(4), s, mode), s); + assert.deepEqual(compositePixels(b, new Uint8ClampedArray(4), mode), b); + }); + // A channel-wise darken operation would produce [10, 20, 20], which is incorrect here. + assert.deepEqual( + [ + ...compositePixels( + new Uint8ClampedArray([10, 240, 10, 255]), + new Uint8ClampedArray([200, 20, 20, 255]), + 'darker-color', + ), + ], + [200, 20, 20, 255], + ); + const half = compositePixels( + new Uint8ClampedArray([100, 100, 100, 128]), + new Uint8ClampedArray([50, 50, 50, 128]), + 'subtract', + ); + assert.deepEqual([...half], [67, 67, 67, 192]); + const out = new Float64Array(3); + blendPixel('divide', [0, 0, 0], [0, 0, 0], 0, out); + assert.deepEqual([...out], [255, 255, 255]); +}); +await check('溶解:稳定颗粒、透明底、覆盖比例与调整层蒙版', () => { + const source = new Uint8ClampedArray(64 * 64 * 4).fill(255); + const empty = new Uint8ClampedArray(source.length); + const full = compositePixels(empty, source, 'dissolve', 1, 64); + assert.deepEqual(full, source); + const half = compositePixels(empty, source, 'dissolve', 0.5, 64); + assert.deepEqual(half, compositePixels(empty, source, 'dissolve', 0.5, 64)); + let count = 0; + for (let i = 3; i < half.length; i += 4) { + assert([0, 255].includes(half[i])); + count += half[i] === 255; + } + assert(count > 1900 && count < 2200); + const row = compositePixels( + new Uint8ClampedArray(32 * 4), + source.slice(0, 32 * 4), + 'dissolve', + 0.5, + 32, + 16, + 20, + ); + assert.deepEqual(row, half.slice((20 * 64 + 16) * 4, (20 * 64 + 48) * 4)); + const mask = new Uint8ClampedArray(source.length); + assert.deepEqual( + adjustedPixels(source, 64, 64, { type: 'invert', value: 0 }, 0.5, mask, 'dissolve'), + source, + ); + const adjusted = adjustedPixels( + source, + 64, + 64, + { type: 'invert', value: 0 }, + 0.5, + null, + 'dissolve', + ); + for (let i = 0; i < adjusted.length; i += 4) { + assert.equal(adjusted[i + 3], 255); + assert([0, 255].includes(adjusted[i])); + assert.equal(adjusted[i], half[i + 3] ? 0 : 255); + } +}); +await check('TIFF 导入拒绝截断、超大尺寸与不支持的压缩', async () => { + const fail = (message) => { + throw Error(message); + }; + assert.throws(() => unpackLZW(new Uint8Array(), 1, fail), /不完整/); + assert.throws(() => unpackLZW(new Uint8Array([0, 0]), 1, fail), /起始标记/); + const buffer = await writeTIFF({ + width: 2, + height: 1, + data: new Uint8ClampedArray([20, 40, 80, 128, 1, 2, 3, 255]), + }).arrayBuffer(); + assert.deepEqual([...readTIFF(buffer).data], [20, 40, 80, 128, 1, 2, 3, 255]); + assert.throws(() => readTIFF(buffer.slice(0, 12)), /不完整/); + assert.throws(() => readTIFF(buffer.slice(0, -1)), /不完整/); + const large = buffer.slice(0); + new DataView(large).setUint32(18, 0xffffffff, true); + assert.throws(() => readTIFF(large), /尺寸/); + const compressed = buffer.slice(0); + new DataView(compressed).setUint16(54, 7, true); + assert.throws(() => readTIFF(compressed), /PackBits/); +}); +await check('连通颜色区域:分离区域、容差和透明度边界', () => { + const edges = runOutline([ + [0, 0, 4], + [0, 1, 4], + [0, 2, 4], + ]); + assert.equal( + edges.reduce((n, [x, y, xx, yy]) => n + Math.abs(xx - x) + Math.abs(yy - y), 0), + 14, + ); + assert(edges.every(([x, y, xx, yy]) => x === xx || y === 0 || y === 3)); + const pixels = new Uint8ClampedArray([ + 255, 0, 0, 255, 0, 0, 255, 255, 255, 0, 0, 255, 250, 0, 0, 255, 0, 0, 255, 255, 255, 0, 0, 0, + ]); + const matched = (t) => [...floodRegion(pixels, 3, 2, 0, 0, t).mask].map((v) => v === 2); + assert.deepEqual(matched(0), [true, false, false, false, false, false]); + assert.deepEqual(matched(5), [true, false, false, true, false, false]); + assert.equal(floodRegion(pixels, 3, 2, -1, 0, 5).bounds, null); + assert.deepEqual( + [...floodRegion(pixels, 3, 2, 2, 0, 5).mask].map((v) => v === 2), + [false, false, true, false, false, false], + ); +}); +await check('背景擦除覆盖:取样颜色、容差、透明像素与笔划范围', () => { + const source = new Uint8ClampedArray([ + 20, 40, 80, 255, 200, 20, 20, 255, 22, 40, 80, 255, 20, 40, 80, 0, + ]); + const mask = backgroundEraseMask( + source, + 4, + 1, + 0, + 0, + { x: 0.5, y: 0.5 }, + { x: 3.5, y: 0.5 }, + 1, + [20, 40, 80], + 2, + ); + assert.deepEqual([mask[3], mask[7], mask[11], mask[15]], [255, 0, 255, 0]); + const tight = backgroundEraseMask( + source, + 4, + 1, + 0, + 0, + { x: 0.5, y: 0.5 }, + { x: 0.5, y: 0.5 }, + 0.5, + [20, 40, 80], + 2, + ); + assert.equal(tight[11], 0); + const recolored = colorReplacementPatch(source, mask, [0, 200, 0]); + assert.deepEqual([recolored[3], recolored[7], recolored[11], recolored[15]], [255, 0, 255, 0]); + const lum = (p, i) => 0.3 * p[i] + 0.59 * p[i + 1] + 0.11 * p[i + 2]; + assert(Math.abs(lum(recolored, 0) - lum(source, 0)) < 1); + assert(recolored[1] > recolored[0] && recolored[1] > recolored[2]); + assert.deepEqual([...source.slice(0, 4)], [20, 40, 80, 255]); +}); +await check('滤镜保留 alpha,反相可逆,模糊保持纯色', () => { + const input = new Uint8ClampedArray([20, 40, 80, 120, 200, 180, 160, 255]); + assert.deepEqual(filterPixels(filterPixels(input, 2, 1, 'invert'), 2, 1, 'invert'), input); + assert.equal(filterPixels(input, 2, 1, 'brightness', 20)[3], 120); + const solid = new Uint8ClampedArray(16 * 16 * 4).fill(87); + assert.deepEqual(filterPixels(solid, 16, 16, 'blur', 8), solid); +}); +await check('调整图层不修改源像素,保留透明度并尊重蒙版和强度', () => { + const source = new Uint8ClampedArray([20, 40, 80, 128, 100, 120, 140, 255]); + const before = source.slice(); + const adjustment = { type: 'invert', value: 0 }; + const mask = new Uint8ClampedArray([0, 0, 0, 255, 0, 0, 0, 0]); + const output = adjustedPixels(source, 2, 1, adjustment, 1, mask); + assert.deepEqual([...output], [235, 215, 175, 128, 100, 120, 140, 255]); + assert.deepEqual(source, before); + const multiplied = adjustedPixels(source, 2, 1, adjustment, 1, null, 'multiply'); + assert.deepEqual([...multiplied].slice(0, 4), [18, 34, 55, 128]); + assert.deepEqual(adjustedPixels(source, 2, 1, adjustment, 0), source); + assert.deepEqual( + [...adjustedPixels(source, 2, 1, adjustment, 0.5)].slice(0, 4), + [128, 128, 128, 128], + ); + assert.throws(() => normalizeAdjustment({ type: 'unknown', value: 1 })); + assert.throws(() => normalizeAdjustment({ type: 'brightness', value: NaN })); + const curves = { + red: [ + [0, 0], + [128, 210], + [255, 255], + ], + }; + const setting = normalizeAdjustment({ type: 'curves', value: { curves } }); + curves.red[1][1] = 0; + assert.equal(setting.value.curves.red[1][1], 210); + const toned = adjustedPixels(source, 2, 1, setting); + assert(toned[0] > source[0]); + assert.deepEqual( + [...toned].filter((_, i) => i % 4 !== 0), + [...source].filter((_, i) => i % 4 !== 0), + ); + assert.throws(() => + normalizeAdjustment({ + type: 'curves', + value: { + curves: { + red: [ + [0, 0], + [0, 255], + ], + }, + }, + }), + ); +}); +await check('剪贴调整只跟随相邻普通图层,失去目标不影响全图', () => { + const adjustment = { type: 'invert', value: 0 }; + const background = { id: 'background' }, + text = { id: 'text' }, + a = { adjustment, clipToBelow: true }, + b = { adjustment, clipToBelow: true }; + const groups = compositionGroups([background, text, a, b]); + assert.equal(groups.length, 2); + assert.equal(groups[1].base, text); + assert.deepEqual(groups[1].adjustments, [a, b]); + assert.equal(clippingBase([background, text, a, b], 3), 1); + assert.equal(compositionGroups([a, b]).length, 0); + assert.equal(compositionGroups([background, { adjustment }, a]).length, 2); +}); +await check('渲染缓存:命中、像素失效、样式替换与内存淘汰', () => { + const cache = createRenderCache(80), + source = { width: 2, height: 2 }, + styles = {}; + let calls = 0; + const render = () => ({ image: { width: 2, height: 2 }, offset: 0, version: ++calls }); + const first = cache.get(source, null, styles, render); + assert.equal(cache.get(source, null, styles, render), first); + cache.invalidate(source); + assert.notEqual(cache.get(source, null, styles, render), first); + assert.equal(cache.get(source, null, {}, render).version, 3); + const mask = { width: 2, height: 2 }; + assert.equal(cache.get(source, mask, styles, render).version, 4); + cache.get({ width: 3, height: 3 }, null, styles, render); + assert.equal(cache.stats().entries, 1); + assert(cache.stats().bytes <= 80); + cache.get({ width: 20, height: 20 }, null, styles, render); + assert.equal(cache.stats().entries, 1); +}); +await check('描边距离、透明区域、位置与浮雕平面不变', () => { + const alpha = new Uint8Array(49); + for (let y = 2; y <= 4; y++) for (let x = 2; x <= 4; x++) alpha[y * 7 + x] = 255; + const outside = distanceMap(alpha, 7, 7, true), + inside = distanceMap(alpha, 7, 7, false); + assert.equal(outside[0], 8); + assert.equal(outside[1 * 7 + 1], 2); + assert.equal(inside[3 * 7 + 3], 4); + const defaults = normalizeStyles(); + const stroke = strokePixels(alpha, 7, 7, { ...defaults.stroke, size: 1 }); + assert.equal(stroke[(3 * 7 + 3) * 4 + 3], 0); + assert(stroke[(3 * 7 + 1) * 4 + 3] > 0); + assert.equal(stroke[3], 0); + const inner = strokePixels(alpha, 7, 7, { ...defaults.stroke, size: 1, position: 'inside' }); + assert.equal(inner[(3 * 7 + 1) * 4 + 3], 0); + assert(inner[(3 * 7 + 2) * 4 + 3] > 0); + const bevel = bevelPixels(alpha, 7, 7, defaults.bevel); + assert.equal(bevel[(3 * 7 + 3) * 4 + 3], 0); + assert.equal(bevel[3], 0); + assert(bevel.some((v, i) => i % 4 === 3 && v > 0)); + assert.equal(normalizeStyles({ stroke: { size: 999, position: 'invalid' } }).stroke.size, 60); +}); +await check('曲线恒等、单通道调整、透明度与非法控制点', () => { + const ramp = new Uint8ClampedArray(256 * 4); + for (let i = 0; i < 256; i++) ramp.set([i, i, i, i], i * 4); + assert.deepEqual( + filterPixels(ramp, 256, 1, 'curves', { + curves: { + rgb: [ + [0, 0], + [64, 64], + [128, 128], + [192, 192], + [255, 255], + ], + }, + }), + ramp, + ); + const colored = filterPixels(new Uint8ClampedArray([80, 80, 80, 123]), 1, 1, 'curves', { + curves: { + red: [ + [0, 0], + [128, 200], + [255, 255], + ], + }, + }); + assert(colored[0] > 80); + assert.deepEqual([...colored.slice(1)], [80, 80, 123]); + const table = curveLUT([ + [0, 0], + [64, 180], + [128, 200], + [255, 255], + ]); + for (let i = 1; i < table.length; i++) assert(table[i] >= table[i - 1]); + assert.throws(() => + curveLUT([ + [0, 0], + [0, 100], + [255, 255], + ]), + ); +}); +await check('高斯模糊透明边缘不混入隐藏颜色,USM 保留 alpha', () => { + const hiddenRed = new Uint8ClampedArray([255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0]); + const blurred = filterPixels(hiddenRed, 3, 1, 'gaussian', 1); + assert(blurred[3] > 0 && blurred[3] < 255); + assert.equal(blurred[0], 0); + assert.equal(blurred[2], 255); + assert.deepEqual([...blurred.slice(0, 4)], [...blurred.slice(8, 12)]); + assert.deepEqual(filterPixels(hiddenRed, 3, 1, 'gaussian', 0), hiddenRed); + const sharpened = filterPixels(hiddenRed, 3, 1, 'unsharp', 20); + assert.deepEqual([sharpened[3], sharpened[7], sharpened[11]], [0, 255, 0]); +}); +const data = await mkdtemp(join(tmpdir(), 'retouch-check-')), + controller = new AbortController(), + port = 43201, + origin = `http://127.0.0.1:${port}`; +let service; +try { + service = await start({ + pluginRoot: root, + dataDir: data, + listen: { host: '127.0.0.1', port }, + signal: controller.signal, + logger: { info() {}, error() {} }, + }); + await check('静态资源、缓存和安全响应头', async () => { + const r = await fetch(origin); + assert.equal(r.status, 200); + assert((await r.text()).includes('MiniMax Photo')); + assert(r.headers.get('content-security-policy').includes("connect-src 'self'")); + const cached = await fetch(origin, { headers: { 'If-None-Match': r.headers.get('etag') } }); + assert.equal(cached.status, 304); + assert.equal((await fetch(origin + '/missing.js')).status, 404); + }); + const id = randomUUID(), + payload = { + format: 'retouch-lab', + version: 1, + id, + name: '验收工程', + width: 64, + height: 64, + layers: [ + { + name: '图层', + image: + 'data:image/png;base64,' + (await readFile(join(root, 'icon.png'))).toString('base64'), + }, + ], + revision: 0, + }; + const put = (value, extra = {}) => + fetch(origin + '/api/projects/' + id, { + method: 'PUT', + headers: { 'Content-Type': 'application/json', Origin: origin, ...extra }, + body: JSON.stringify(value), + }); + await check('保存、读取、并发版本冲突', async () => { + const saved = await put(payload); + assert.equal(saved.status, 200); + assert.equal((await saved.json()).revision, 1); + const recovered = await (await fetch(origin + '/api/projects/' + id)).json(); + assert.equal(recovered.name, payload.name); + assert.equal(recovered.layers[0].image, payload.layers[0].image); + assert.equal((await put(payload)).status, 409); + const list = await (await fetch(origin + '/api/projects')).json(); + assert.equal(list.projects.length, 1); + }); + await check('阻止跨站写入与无效工程', async () => { + assert.equal((await put(payload, { Origin: 'https://example.org' })).status, 403); + assert.equal((await put({ ...payload, width: -1 })).status, 400); + assert.equal((await fetch(origin + '/api/no-such-route')).status, 404); + }); + let agentId; + await check( + 'Agent MCP transport, reference, result, idempotency and origin boundaries', + async () => { + const rpc = async (method, params = {}, headers = {}) => { + const response = await fetch(origin + '/mcp/retouch-images', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json, text/event-stream', + ...headers, + }, + body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }), + }); + return { status: response.status, body: await response.json() }; + }; + const png = await readFile(join(root, 'icon.png')); + await assert.rejects(validatePNG(png.subarray(0, 33))); + const damaged = Buffer.from(png); + damaged[damaged.length - 1] ^= 1; + await assert.rejects(validatePNG(damaged)); + // Fixture chunk CRC generated independently with Python zlib.crc32. + const unknownCritical = Buffer.concat([ + png.subarray(0, 33), + Buffer.from('0000000446414b4574657374641be648', 'hex'), + png.subarray(33), + ]); + await assert.rejects(validatePNG(unknownCritical), /PNG/); + const initialized = (await rpc('initialize')).body.result; + assert.equal(initialized.protocolVersion, '2025-03-26'); + const manifest = JSON.parse(await readFile(join(root, '.minimax-plugin/plugin.json'), 'utf8')); + assert.deepEqual(initialized.serverInfo, { name: manifest.name, version: manifest.version }); + assert.deepEqual( + (await rpc('tools/list')).body.result.tools.map((t) => t.name).sort(), + [ + 'get_image_request', + 'submit_image_result', + 'editor_capabilities', + 'photo_call', + 'editor_list', + 'editor_inspect', + 'editor_preview', + 'editor_batch', + 'editor_job', + 'editor_run_code', + 'editor_code_result', + 'editor_export', + 'editor_create', + 'editor_open_file', + ].sort(), + ); + assert.equal((await rpc('tools/list', {}, { Origin: 'https://example.org' })).status, 403); + assert.equal((await fetch(origin + '/mcp/retouch-images')).status, 405); + const created = await fetch(origin + '/api/agent/requests', { + method: 'POST', + headers: { 'Content-Type': 'application/json', Origin: origin }, + body: JSON.stringify({ + mode: 'edit', + prompt: 'test edit', + name: 'test', + reference: payload.layers[0].image, + }), + }); + assert.equal(created.status, 201); + agentId = (await created.json()).id; + const reference = await rpc('tools/call', { + name: 'get_image_request', + arguments: { requestId: agentId }, + }); + const ref = JSON.parse(reference.body.result.content[0].text); + assert.deepEqual(await readFile(ref.path), await readFile(join(root, 'icon.png'))); + const submit = () => + rpc('tools/call', { + name: 'submit_image_result', + arguments: { requestId: agentId, imagePath: join(root, 'icon.png') }, + }); + for (const response of await Promise.all([submit(), submit()])) + assert.equal(response.body.result.isError, undefined); + const replacement = await rpc('tools/call', { + name: 'submit_image_result', + arguments: { requestId: agentId, imagePath: join(root, 'evidence/ui-light.png') }, + }); + assert.equal(replacement.body.result.isError, true); + const result = await fetch(origin + '/api/agent/requests/' + agentId + '/result'); + assert.deepEqual( + Buffer.from(await result.arrayBuffer()), + await readFile(join(root, 'icon.png')), + ); + const invalid = await rpc('tools/call', { + name: 'submit_image_result', + arguments: { requestId: agentId, imagePath: join(root, 'package.json') }, + }); + assert.equal(invalid.body.result.isError, true); + const traversal = await rpc('tools/call', { + name: 'get_image_request', + arguments: { requestId: '../../package' }, + }); + assert.equal(traversal.body.result.isError, true); + const denied = await fetch(origin + '/api/agent/requests', { + method: 'POST', + headers: { 'Content-Type': 'application/json', Origin: 'https://example.org' }, + body: '{}', + }); + assert.equal(denied.status, 403); + }, + ); + await service.dispose(); + service = null; + await check('停止服务后重新启动,工程仍存在', async () => { + service = await start({ + pluginRoot: root, + dataDir: data, + listen: { host: '127.0.0.1', port }, + signal: controller.signal, + logger: { info() {}, error() {} }, + }); + assert.equal((await (await fetch(origin + '/api/projects/' + id)).json()).revision, 1); + assert.equal( + (await (await fetch(origin + '/api/agent/requests')).json()).requests.find( + (r) => r.id === agentId, + ).status, + 'ready', + ); + }); + const pixels = new Uint8ClampedArray(1920 * 1080 * 4).fill(128), + times = []; + for (let i = 0; i < 3; i++) { + const start = performance.now(); + filterPixels(pixels, 1920, 1080, 'blur', 12); + times.push(performance.now() - start); + } + results.push({ name: '1920×1080 方框模糊(Node 算法计时,非浏览器帧率)', milliseconds: times }); + await mkdir(join(root, 'evidence'), { recursive: true }); + await writeFile( + join(root, 'evidence/check-results.json'), + JSON.stringify({ time: Date.now(), results }, null, 2), + ); + console.log('timing', times.map((t) => t.toFixed(1)).join(', '), 'ms'); +} finally { + await service?.dispose(); + await rm(data, { recursive: true, force: true }); +} diff --git a/plugins/webguhui/minimax-photo/scripts/package-preview.py b/plugins/webguhui/minimax-photo/scripts/package-preview.py new file mode 100644 index 00000000..c762b7e1 --- /dev/null +++ b/plugins/webguhui/minimax-photo/scripts/package-preview.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- +"""Create a reproducible preview ZIP, then verify its entries and SHA-256 hashes.""" +from pathlib import Path +import hashlib +import json +import re +import subprocess +import zipfile + +root = Path(__file__).resolve().parents[1] +manifest = json.loads((root / '.minimax-plugin/plugin.json').read_text(encoding='utf-8')) +package = json.loads((root / 'package.json').read_text(encoding='utf-8')) +app = json.loads((root / 'miniapp/miniapp.json').read_text(encoding='utf-8')) + +assert manifest['schemaVersion'] == 1 +assert re.fullmatch(r'[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*', manifest['name']) +assert len(manifest['name']) <= 80 +assert re.fullmatch(r'\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?', manifest['version']) +for key in ['description', 'author', 'category', 'icon']: + assert isinstance(manifest[key], str) and manifest[key].strip(), key +assert manifest['exampleQueries'] and all(isinstance(s, str) and s.strip() for s in manifest['exampleQueries']) +for key in ['apps', 'mcpServers', 'skills']: + assert isinstance(manifest[key], list), key +assert package['mcode'] == {'schemaVersion': 2, 'miniApp': './miniapp/miniapp.json'} +assert manifest['version'] == package['version'] +assert set(app) == {'schemaVersion', 'artifacts', 'runtime', 'surface', 'mcpEndpoints', 'agentAccess'} +assert app['schemaVersion'] == 1 +assert app['runtime']['kind'] == 'process' +assert app['runtime']['lifecycle'] == 'on-demand' +assert app['mcpEndpoints'] == [{'server':'retouch-images','path':'/mcp/retouch-images'}] +assert app['agentAccess'] == ['session.run'] +assert manifest['mcpServers'] == ['servers.mcp.json'] +assert app['surface'] == {'path': '/'} + +def inside(relative): + assert isinstance(relative, str) and '\\' not in relative + parts = Path(relative).parts + assert not Path(relative).is_absolute() and '..' not in parts + path = root / relative + assert path.exists() and not path.is_symlink(), relative + assert path.resolve().is_relative_to(root), relative + return path + +inside(manifest['icon']) +for skill in manifest['skills']: + assert skill.startswith('skills/') and skill.endswith('/SKILL.md'), skill + inside(skill) +for role in ['client', 'node']: + paths = app['artifacts'][role] + assert paths and len(paths) == len(set(paths)) + for path in paths: + assert path.startswith('./miniapp/'), path + inside(path) +entry = inside(app['runtime']['entry']) +assert entry.suffix in ['.mjs', '.js', '.cjs'] +assert any(entry.is_relative_to(inside(p)) for p in app['artifacts']['node']) + +subprocess.run(['node', 'scripts/check.mjs'], cwd=root, check=True) +subprocess.run(['node', 'scripts/check-ptc.mjs'], cwd=root, check=True) +subprocess.run(['node', 'scripts/check-draw.mjs'], cwd=root, check=True) +allowed = ['.minimax-plugin', 'miniapp', 'package.json', 'icon.png', 'servers.mcp.json', 'licenses', 'skills'] +files = [] +for relative in allowed: + path = inside(relative) + candidates = path.rglob('*') if path.is_dir() else [path] + for candidate in candidates: + if '__pycache__' in candidate.parts or 'node_modules' in candidate.parts or (candidate.parent.name == 'showcase' and candidate.suffix == '.png'): + continue + assert not candidate.is_symlink(), str(candidate) + if candidate.is_file(): + files.append(candidate) +files.sort(key=lambda p: p.relative_to(root).as_posix()) +name = manifest['name'] +out = root / 'releases' +out.mkdir(exist_ok=True) +archive = out / (name + '-' + manifest['version'] + '-preview.zip') +entries = [] +with zipfile.ZipFile(archive, 'w', compression=zipfile.ZIP_DEFLATED, compresslevel=9) as target: + for path in files: + relative = path.relative_to(root).as_posix() + data = path.read_bytes() + if relative == 'package.json': + runtime_package = json.loads(data) + runtime_package.pop('scripts', None) + data = (json.dumps(runtime_package, ensure_ascii=False, indent=2) + '\n').encode('utf-8') + info = zipfile.ZipInfo(name + '/' + relative, date_time=(2026, 1, 1, 0, 0, 0)) + info.compress_type = zipfile.ZIP_DEFLATED + info.external_attr = 0o100644 << 16 + target.writestr(info, data) + entries.append({'path': relative, 'bytes': len(data), 'sha256': hashlib.sha256(data).hexdigest()}) +with zipfile.ZipFile(archive) as check: + assert check.testzip() is None + assert len(check.namelist()) == len(entries) + for item in entries: + assert hashlib.sha256(check.read(name + '/' + item['path'])).hexdigest() == item['sha256'] +report = { + 'status': 'preview-host-unverified', + 'pluginId': name, + 'version': manifest['version'], + 'archive': archive.name, + 'bytes': archive.stat().st_size, + 'sha256': hashlib.sha256(archive.read_bytes()).hexdigest(), + 'files': entries, +} +(out / 'package-integrity.json').write_text(json.dumps(report, ensure_ascii=False, indent=2), encoding='utf-8') +# Source and acceptance evidence remain available separately from the install payload. +source_archive = out / (name + '-' + manifest['version'] + '-source.zip') +with zipfile.ZipFile(source_archive, 'w', compression=zipfile.ZIP_DEFLATED, compresslevel=9) as target: + for folder in ['ui-src', 'ptc-src', 'scripts', 'docs', 'evidence', 'sdk', 'examples']: + for path in sorted((root / folder).rglob('*')): + if path.is_file() and 'node_modules' not in path.parts and '__pycache__' not in path.parts: + target.write(path, name + '/' + path.relative_to(root).as_posix()) +print(json.dumps({key: report[key] for key in ['status', 'archive', 'bytes', 'sha256']}, indent=2)) diff --git a/plugins/webguhui/minimax-photo/scripts/preview-render-check.mjs b/plugins/webguhui/minimax-photo/scripts/preview-render-check.mjs new file mode 100644 index 00000000..81e7716f --- /dev/null +++ b/plugins/webguhui/minimax-photo/scripts/preview-render-check.mjs @@ -0,0 +1,46 @@ +import { mkdtemp, mkdir, cp, rm } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { start } from '../miniapp/node/server.mjs'; +const root = await mkdtemp(join(tmpdir(), 'retouch-render-check-')); +const port = Number(process.env.RETOUCH_CHECK_PORT || 43188); +let lifecycle; +try { + await mkdir(join(root, 'miniapp'), { recursive: true }); + const client = join(root, 'miniapp/client'); + await cp(fileURLToPath(new URL('../miniapp/client', import.meta.url)), client, { + recursive: true, + }); + for (const file of [ + 'cache-check.html', + 'cache-check.js', + 'blend-check.html', + 'blend-check.js', + 'psd-check.html', + 'psd-check.js', + ]) + await cp( + fileURLToPath(new URL('./browser-checks/' + file, import.meta.url)), + join(client, file), + ); + lifecycle = await start({ + pluginId: 'retouch-render-check', + pluginRoot: root, + dataDir: join(root, 'data'), + listen: { host: '127.0.0.1', port }, + signal: new AbortController().signal, + logger: console, + }); + console.log(`浏览器渲染检查:http://127.0.0.1:${port}/cache-check.html`); + console.log(`混合模式对照:http://127.0.0.1:${port}/blend-check.html`); +} catch (error) { + await rm(root, { recursive: true, force: true }); + throw error; +} +for (const signal of ['SIGINT', 'SIGTERM']) + process.once(signal, async () => { + await lifecycle.dispose(); + await rm(root, { recursive: true, force: true }); + process.exit(0); + }); diff --git a/plugins/webguhui/minimax-photo/scripts/preview.mjs b/plugins/webguhui/minimax-photo/scripts/preview.mjs new file mode 100644 index 00000000..f4188c20 --- /dev/null +++ b/plugins/webguhui/minimax-photo/scripts/preview.mjs @@ -0,0 +1,21 @@ +import { start } from '../miniapp/node/server.mjs'; +import { fileURLToPath } from 'node:url'; +import { resolve } from 'node:path'; +import { tmpdir } from 'node:os'; +const pluginRoot = fileURLToPath(new URL('../', import.meta.url)); +const port = Number(process.env.RETOUCH_PREVIEW_PORT || 43187); +const controller = new AbortController(); +const lifecycle = await start({ + pluginId: 'minimax-photo', + pluginRoot, + dataDir: resolve(process.env.RETOUCH_DATA_DIR || tmpdir(), 'minimax-photo-preview'), + listen: { host: '127.0.0.1', port }, + signal: controller.signal, + logger: { info: console.log, error: console.error }, +}); +console.log(`修图工作台预览:http://127.0.0.1:${port}`); +for (const signal of ['SIGINT', 'SIGTERM']) + process.once(signal, async () => { + await lifecycle.dispose(); + process.exit(0); + }); diff --git a/plugins/webguhui/minimax-photo/sdk/editor.mjs b/plugins/webguhui/minimax-photo/sdk/editor.mjs new file mode 100644 index 00000000..03636f82 --- /dev/null +++ b/plugins/webguhui/minimax-photo/sdk/editor.mjs @@ -0,0 +1,59 @@ +// Transport-independent programmatic client. The caller supplies the host's real +// MCP tool invocation function; this SDK never discovers private Host endpoints. +export function createEditorClient(callTool) { + if (typeof callTool !== 'function') throw Error('需要实际 MCP 工具调用函数'); + async function call(name, args = {}) { + const response = await callTool(name, args); + if (response.isError) + throw Error(response.content?.find((x) => x.type === 'text')?.text || '编辑工具失败'); + const text = response.content?.find((x) => x.type === 'text')?.text; + if (!text) throw Error('编辑工具返回格式无效'); + return { value: JSON.parse(text), images: response.content.filter((x) => x.type === 'image') }; + } + async function inspect(editorId) { + return (await call('editor_inspect', { editorId })).value; + } + async function wait(jobId, { timeoutMs = 30000 } = {}) { + const deadline = Date.now() + Math.min(60000, Math.max(0, timeoutMs)); + for (;;) { + const result = await call('editor_job', { jobId }); + if ( + !['queued', 'running', 'prepared'].includes(result.value.status) || + Date.now() >= deadline + ) + return result; + await new Promise((resolve) => setTimeout(resolve, 500)); + } + } + async function submit( + name, + editorId, + extra, + { requestId = crypto.randomUUID(), expectedVersion } = {}, + ) { + const version = expectedVersion ?? (await inspect(editorId)).version; + return (await call(name, { editorId, expectedVersion: version, requestId, ...extra })).value; + } + return { + capabilities: async () => (await call('editor_capabilities')).value, + list: async () => (await call('editor_list')).value.editors, + inspect, + wait, + job: (jobId) => call('editor_job', { jobId }), + preview: (editorId, options = {}, request = {}) => + submit('editor_preview', editorId, { options }, request), + create: (editorId, document, request = {}) => + submit('editor_create', editorId, document, request), + export: (editorId, request = {}) => submit('editor_export', editorId, {}, request), + async edit(editorId, plan, request = {}) { + const state = await inspect(editorId); + const operations = typeof plan === 'function' ? await plan(state.document) : plan; + return submit( + 'editor_batch', + editorId, + { operations }, + { ...request, expectedVersion: request.expectedVersion ?? state.version }, + ); + }, + }; +} diff --git a/plugins/webguhui/minimax-photo/servers.mcp.json b/plugins/webguhui/minimax-photo/servers.mcp.json new file mode 100644 index 00000000..4dc2a343 --- /dev/null +++ b/plugins/webguhui/minimax-photo/servers.mcp.json @@ -0,0 +1,12 @@ +{ + "schemaVersion": 1, + "mcpServers": { + "retouch-images": { + "type": "streamable-http", + "url": "http://127.0.0.1:9/mcp/retouch-images", + "headers": {}, + "description": "Read image requests and deliver generated PNG results to the Mini App.", + "timeout": 30000 + } + } +} \ No newline at end of file diff --git a/plugins/webguhui/minimax-photo/skills/minimax-photo/SKILL.md b/plugins/webguhui/minimax-photo/skills/minimax-photo/SKILL.md new file mode 100644 index 00000000..8f22e04e --- /dev/null +++ b/plugins/webguhui/minimax-photo/skills/minimax-photo/SKILL.md @@ -0,0 +1,120 @@ +--- +name: minimax-photo +description: 在 MiniMax Photo 中创建和编辑图片,包括参考图绘制、图层修改、选区和调色,以及用 PTC 组合编辑工具。用户要求使用此编辑器或修改其中的作品时使用。 +--- + +# MiniMax Photo + +把用户的自然语言需求转成可查看、可撤销的图片编辑。沿用用户选择的模型和输出要求;无需用户提供工具名、编辑器 ID 或脚本。 + +## 选择方法 + +- 先看用户附图和当前作品,识别需要保留和修改的部分。只有局部看不清、影响编辑决定时才裁切放大;风格化绘制通常不需要逐像素测量。 附件仅用于观察和参考绘制时,直接看图即可,不把导入画布或制作图片笔刷作为前置步骤;需要合成或修改原图像素时再导入。 +- 单个简单修改直接调用编辑工具。多个相关操作优先先规划,再用一段 PTC 脚本顺序执行,减少模型来回调用。需要看中间结果才能决定下一步时,再拆开执行。 +- 绘制路径、图层、选区和调色使用编辑器命令。用户要求模型生图或语义修图时,使用宿主实际提供的对应工具,再按下面的图片回传流程交付。不要用生成的成品代替用户要求展示的绘画过程。 +- 新作品使用新文档;修改已有作品时保留不相关内容,优先使用独立图层。根据画面选择构图、笔刷、路径和层次,不套固定题材模板。 + +## 模型生图与改图的结果回传 + +应用内请求带有图片任务 `requestId` 时,先 `get_image_request({requestId})` 读取需求与参考图,调用宿主可用的图片模型,将结果保存为本机 PNG,再 `submit_image_result({requestId,imagePath})`。两次调用使用同一图片任务编号;它不是编辑器命令的 UUID。成功回传后,图片会出现在应用的结果列表,由用户点击“打开图片”创建新作品。生成文件或在聊天中展示图片都不等于回传完成。 + +这条流程不需要 PhotoCraft 的本地文件读取命令、系统剪贴板或 UI 自动化导入。只有直接编辑图层、画笔等不经过图片模型的任务才可跳过图片回传。请求没有图片任务编号时,不编造编号;按现有编辑工具完成任务,或按宿主支持的附件方式交付生成文件。 + +## 连接和发现命令 + +查询命令时传入与当前操作相关的 `filter`,只读取需要的参数;完整目录很大,不作为常规起点。`params` 使用 JSON 对象,尺寸、压力等数字保持数字类型,不能用空字符串代替空对象。错误回显是什么类型就检查该次入参,不把自己传入的字符串误判为桥接层转换。PTC 返回值限制 64KB,返回所需字段或文件路径,不返回完整能力目录、状态或像素数据。 + +1. 先通过宿主的 Mini App 打开能力,在当前会话打开准确的插件 ID `minimax-photo`,再用 `editor_list` 和 `editor_inspect` 确认对应编辑器、当前作品及 `version`。显示名可能重复,旧插件 `retouch-lab` 不是本插件。列表里已有编辑器不代表它在当前会话可见;不能仅凭首项、最新更新时间或 `engine:photocraft` 选择其他会话的实例。多个实例时,用宿主浏览器检查当前 MiniApp 页面 `html` 元素的 `data-photo-editor-id` 属性,与列表中的 `editorId` 精确匹配;再核对文档。`page.visibility` 与 `page.focused` 仅反映浏览器状态,不证明会话归属。无法确定归属时先解决连接,不开始修改。 +2. 下面列出的基础用法可直接使用;其他命令用 `photo_call` 的 `commands` 方法按需查询命令,例如 `args: {filter: "paint"}`。参数以当前返回的 schema 为准。过滤查询可减少上下文,不必先读完整目录。 +3. 工具不可用时先确认插件已启用并打开;刚安装或更新后可能需要新会话刷新工具。不要通过搜索宿主源码、凭证或扫描端口绕过工具发现。 + +工具的宿主前缀可能变化,按当前工具列表匹配以下名称。`editor_capabilities`、`editor_batch`、`editor_preview`、`editor_create` 和 `editor_export` 是旧版 canvas 引擎接口。PhotoCraft 使用 `photo_call` 或下表的 PTC 方法;尤其预览用 `photo_call(method:"preview", args:{})` 或 `editor.preview()`,新建用 PTC `editor.create()`。 + +## 打开本机图片和分层工程 + +使用 `editor_open_file({editorId, expectedVersion, requestId, filePath})`,随后用 `editor_job` 查询完成结果。支持 PNG/JPEG/WebP/PSD/pcraft,最大 32 MB,以新文档打开并保留旧作品。只使用用户指定的附件文件或工具返回的导出路径;无需把文件转成 base64 放入模型上下文。Web 编辑器不能用 `file.openAs` 或 `file.placeEmbedded` 读取本机路径,不搜索 HTTP 接口或凭证。完成后 inspect 核对新文档与图层。 + +## 调用约定 + +直接调用:`photo_call({editorId, expectedVersion, requestId, method, args})`。 +使用刚读取的版本和新的 UUID 请求编号。它返回排队中的任务;用 `editor_job({jobId})` 查询至完成,不能把已提交当作已完成。下一次直接调用使用成功结果的 `appliedVersion`。 + +批量脚本:`editor_run_code({editorId, expectedVersion, requestId, code})`,再用 `editor_code_result({runId})` 查询结果。脚本只能通过 `editor` 对象调用: + +| 方法 | 用途与返回值 | +| --- | --- | +| `await editor.inspect()` | 直接返回当前状态,包括图层;不是任务包装对象 | +| `await editor.commands({filter})` | 完成的任务对象;命令数组在 `job.result.value` | +| `await editor.create({width,height,name})` | 新建文档,返回完成的任务对象 | +| `await editor.execute({command,params})` | 执行单个命令,返回完成的任务对象 | +| `await editor.edit([{command,params}, …])` | 执行一批命令,返回完成的任务对象 | +| `await editor.draw({strokes, intervalMs:550})` | 真实逐笔绘制;strokes 是 paint.stroke 的参数数组,1..96 笔,间隔 100..600ms;每笔单独撤销,中断保留已完成笔触 | +| `await editor.preview(options)` | 查看画面,返回完成的任务对象 | +| `await editor.export(options)` | 按查询到的导出参数保存,返回完成的任务对象 | + +编辑任务包含引擎结果包装,不要假设新图层 ID 在 `result.value.id`;创建后用 `editor.inspect()` 读取图层。`layer.select` 使用 `{layer: 图层ID}` 或 `{name: 唯一图层名}`,不是 `{id: …}`。`layer.setProps` 修改已选择的图层,其中 `name` 是重命名,不是选择器。先选图层再设属性;新建绘画层默认保持透明,纸底只画在底层。其他命令仍查询实际 schema,不猜参数。 + +`paint.stroke` 和 `draw` 每笔还可显式传 `layer: 图层ID`,跨图层绘制或擦除时优先指定,避免依赖当前选择。`erase:true` 或 `mode:"clear"` 擦除目标图层的像素,不会自动隔离同层的某一类笔触;锁定透明度的图层会改为涂背景色。擦除前检查目标层及锁定状态,不把露出的下层颜色直接判断为所有图层被擦除。 + +脚本内逐个 `await`,不能 `Promise.all` 或漏掉等待。可使用循环和辅助函数组织几何路径、重复笔触及条件分支。没有 Node、文件或网络 API。每段代码上限 32 KB、最多 64 次编辑 API 调用、120 秒;单次 API 参数和脚本返回值序列化后最多 65536 字符。压缩代码中的坐标不会缩小解码后的调用参数。用 `JSON.stringify({strokes:batch,intervalMs:550}).length` 检查每批,预留余量,超过时继续拆分;96 笔只是数量上限,不保证数据量合规。按工作量合理拆分,不为了“一次完成”超过限制。 + +`console.log/info/warn/error/debug` 可记录调试信息;完成后从 `editor_code_result` 的 `logs` 读取,最多 50 条、总计 10000 字符,超出截断。返回业务数据仍用 `return`,不要把日志当作编辑成功的证明。 + +## 执行与验收 + +- 一段脚本可以按实际编辑阶段多次 `editor.edit`,每批提交后画布更新。每批是一个撤销步骤;整段脚本不是一个事务。批次根据独立修改和耗时划分,不按固定数量拆分,也不为演示添加空操作或等待。 +- 用户要看绘画过程时,用 `editor.draw` 提交笔触,而不是 `edit` 一次提交整幅线稿。演示或录制时使用 500–600ms 间隔,确保每笔可辨;不要为追求快而压到 100ms。可以在同一段 PTC 中生成路径、分组逐笔绘制,不必每笔都请求模型。按总显示时间留出 120 秒脚本预算;阶段间查看预览后再继续。 +- 显示 AI 操作轨迹开启时,笔画在提交后短暂回放;这不是逐像素实时绘制,也不是系统鼠标移动。不要把轨迹回放描述成模型手动画笔。 +- 完成后查看预览,对照用户要求检查结构、边界、遮挡和可读性;需要时做局部修正。任务成功不等于视觉验收成功。按用户需要导出图片或保留图层的工程,只报告实际生成的文件。 +- 失败时先查运行 `trace` 和其中的任务编号,再读当前状态;前面成功的批次可能已保留。只修复失败部分,不盲目重放整段脚本。版本冲突可能来自自己上一段脚本的修改,不代表用户插手。独立脚本开始前重新 inspect;同一脚本内版本由工具自动跟踪。任务仍在执行时查询原任务,不提交新请求。 +- 请求结果未知时查询原请求;相同请求编号只用于同一份请求的重试。新操作使用新 UUID,避免重复绘制或误把旧结果当作新结果。 + +导出只传 `editor.export({format:"png"})` 等受支持格式;完成任务的顶层 `exportPath` 是实际文件位置(PNG 同时可能有 `previewPath`)。不传自定义 `path` 或 `outputPath`,也不在本机搜索猜测结果位置。需要交付到用户指定目录时,在宿主获得导出文件后再复制,保留原文件。 + +## 参考绘画与素描 + +- 简单插画、标志等色块边界清楚,且用户强调相似度时,优先使用随 Skill 提供的轮廓脚本,见 [参考图轮廓转笔触](references/reference-tracing.md)。它输出已按目标画布缩放、平滑并分笔的数据,直接绘制;不要再次缩放或临时重写边界遍历、样条插值和分笔算法。照片、复杂纹理不适合直接按颜色提取,改用观察后的简化曲线。 +- 用户要看逐笔过程时,轮廓提取通过基本检查就先在当前可见画布画轻稿,再补明暗;不要在编辑器外反复渲染整幅素描、调好全部细节后才开始落笔。 +- 一轮用户请求内完成观察、绘制、预览和必要的局部修正。可以分几次 PTC 调用,避免超时;不要把内部阶段变成要求用户继续发送的步骤。轻稿已像原图时,补少量明暗即可,不以反复加细节拖长简单素描。 + +- 先判断整体比例、轮廓曲率、遮挡和留白;信息足够就画轻稿并看预览,不反复裁图测坐标。轻稿阶段把预览与附件对照,确认主体类别、轮廓比例、关键部件和相互位置仍可识别,再铺明暗。允许自由发挥不等于替换主体或改变关键结构;用户更重视相似度时,简单准确优先于精细。 +- 用平滑曲线采样笔触,避免少量折线点把圆润形体变成多边形。先轻线确定形,再用少量重点线强调结构;不要给所有边缘同样粗黑的描边。 +- 素描先确定光源与大块明暗。用宽、淡的笔触铺体积,再用顺形排线和少量交叉排线丰富层次;接触阴影比普通暗部更深,高光留白。随机短线和颗粒不能代替体积。 +- 铺调子前,先按形体划分连贯的亮面、灰面、暗面,考虑前后遮挡;不要用孤立灰斑或等距同心弧线代替受光变化。轮廓、灰面和细节分层,灰面需要限制边界时先建立选区或蒙版,保留轮廓线所在层。蒙版的创建与编辑是不同命令,查询对应 schema 后使用。 +- 首次使用不熟悉的笔刷铺大面积调子时,在临时层画少量小样并查看实际效果,再选参数正式绘制,随后移除试笔层。笔宽、透明度、压力和预设会共同影响结果;不能仅凭传入的数字断言最终灰度。笔刷已验证时直接复用,不必每次试笔。 +- 小面积圆形留白或擦除可用圆笔刷单点、短笔触或椭圆选区;多条等长平行笔触会形成条带或方块,不能靠降低硬度改变整体形状。 +- 缩小预览检查构图和明暗,放大检查交接处、眼睛等视觉重点。比例歪、轮廓交叉、擦除残影或阴影像装饰条纹时先修正,再加细节;工具成功不等于作品完成。 +- 同一区域反复修改却没有改善时,先比较修改前后的预览,区分形体、遮挡、笔刷参数或图层状态问题,再更换方法;不要继续盲目加深或加密。完成时隐藏辅助线与试笔,确认画面没有意外穿插、溢出和未收尾的区域。 + +压力只在对应笔刷动态开启时影响笔宽:可取内置 `Hard Round Pressure Size`,或设 `brush.shapeDynamics.enabled=true`、`brush.shapeDynamics.size.control="penPressure"`。`brush.presets.list` 用 `full:true` 可取完整设置,在 PTC 内筛选所需预设再返回,避免完整列表截断。 + +`paint.stroke` 的 `opacity` 是 0–1,填充命令的 `opacity` 通常是百分比,以各自 schema 为准。排线只用于补充质感,先用低硬度、低透明度的宽笔触建立连续灰面。 + +### 曲线笔触 + +`editor.draw` 的每笔可使用 `points`,也可用 `path` 表达连续曲线,二者选一。`path` 使用绝对坐标,格式与 SVG 命令一致:`["M",x,y]` 起点,`["L",x,y]` 直线,`["Q",cx,cy,x,y]` 二次曲线,`["C",c1x,c1y,c2x,c2y,x,y]` 三次曲线,`["Z"]` 闭合。工具负责曲线采样,无需手写样条插值。每笔只含一个 M;断开的部分分为多笔。可额外设置 `pressure:0..1`,作为整笔的默认压力;`points` 中已有的第三个数值或对象的 `pressure` 优先,未设置时沿用引擎默认值。颜色、笔宽、透明度等仍为 paint.stroke 参数。 + +圆润轮廓用 C/Q,硬质折面用 L,不要把整个主体替换成一个圆。绘图前保留参照物之间的相对位置和遮挡,风格化不等于丢掉识别特征。笔触超过 96 条时,用循环按 96 条切片顺序调用 draw;展示间隔默认 550ms,估算总时长并在 120 秒预算内分阶段。 + +### 基础绘图用法(本包已验证) + +不用为了画简单线条先读完整画笔字段或预设目录。`editor.create({width,height,name})` 建画布后,新建透明图层: + +```js +await editor.execute({command:"layer.new.layer", params:{name:"Sketch"}}); +const layerId = (await editor.inspect()).document.activeLayer; +// 日后回到此层用 layerId,不依赖名称或图层顺序。 +await editor.execute({command:"layer.select", params:{layer:layerId}}); +await editor.draw({intervalMs:550, strokes:[{ + path:[["M",40,90],["C",70,20,150,20,180,90]], + size:2, color:"#555555", opacity:0.65, pressure:0.7 +}]}); +``` + +这只示范调用方式,不是作品模板。需要改可见性或不透明度时,`layer.setProps` 接受 `{layer:layerId, visible:true, opacity:0.8}`;不需要填写 name。宽、淡的柔和阴影可用 `paint.stroke` 的 `hardness:0..1`(低值软边)、`size`、`opacity:0..1`,不必引入随机纸纹来掩盖结构。 + +### 限制笔触范围(已在宿主验证) + +铺连续明暗时,可先调用 `select.lasso`:`params:{points:[[x,y],…], mode:"replace", antiAlias:true, feather:0}`。`points` 是沿目标边界排列的多边形顶点;`mode` 还支持 `add`、`subtract`、`intersect`。用 `subtract` 排除需要留白或被遮挡的部分,再在独立灰度层用宽软笔逐笔铺调子,笔触会被选区裁剪。范围由当前作品决定,不复用固定形状。结束后调用 `select.deselect`,参数 `{}`,避免后续笔触被旧选区意外截断。 + +局部修复先检查目标层:轮廓、阴影和纹理混在同层时,宽橡皮可能同时擦出断口或白块。优先回退失败笔触或在独立层修补;修后查看交接处,不只确认杂线消失。 diff --git a/plugins/webguhui/minimax-photo/skills/minimax-photo/references/reference-tracing.md b/plugins/webguhui/minimax-photo/skills/minimax-photo/references/reference-tracing.md new file mode 100644 index 00000000..af67aacb --- /dev/null +++ b/plugins/webguhui/minimax-photo/skills/minimax-photo/references/reference-tracing.md @@ -0,0 +1,31 @@ +# 参考图轮廓转笔触 + +适合边界清楚的插画和标志。先看附件,识别主体、关键部件与遮挡;脚本只按颜色或蒙版找边界,不理解图像语义。不能把提取成功等同于画得像。 + +## 使用 + +脚本位置相对本 Skill:`scripts/trace_reference.py`。需要 Python 3 和 Pillow;环境缺少时使用手工规划的曲线,不为此展开依赖安装。附件的本地文件只作为工具输入,不要求用户提供路径,不把路径替代为聊天附件。 + +```bash +python3 /scripts/trace_reference.py <参考图> --color '#4080c0' --tolerance 70 --width 1000 --preview outline-check.png > strokes.json +``` + +颜色从当前参考图选择,此示例值无题材含义。多个相邻颜色可能需要分别提取;也可以先创建白色前景、黑色背景的蒙版,再省略 `--color`。不要对照片直接提取所有小色块。 + +输出 `canvasSize`(保持长宽比)、`regions`、`contours` 和 `strokes`,每笔为 `{points:[[x,y],…]}`。`contours` 用 `firstStroke`(从 0 开始)和 `strokeCount` 标出同一闭合轮廓的笔触范围,并提供 `bounds:[左,上,右,下]` 与 `signedArea`(正数为外边界,负数为孔洞)。需要闭合选区时,按该范围连接各笔 points,跳过每笔重复的首点即可;无需按距离猜测分组或重新追踪边界。预览路径必须是新文件,不会覆盖原图或已有输出。正常使用直接执行脚本,无需先读源码或临时编写预览程序。JSON 已换行,可用脚本读取并筛选所需轮廓,避免把全部坐标打印到上下文。使用 `--preview` 同时输出白底轮廓检查图(最长边不超过 1024 像素),直接查看一次,检查是否误选背景、漏掉主体或提取到不需要的内部边缘;必要时调整颜色容差或蒙版,不重复放大已经清楚的局部。 + +`--min-area 12` 忽略碎片;`--smooth 1` 平滑轮廓,硬质拐角可设 0;`--epsilon 0.6` 简化点;`--stroke-length 100` 控制每笔长度。脚本最多分析 640×640 像素、64 个区域、512 笔,超限明确报错;不要在失败时原参数反复重试。 + +## 坐标与笔触可直接使用 + +`sourceSize` 是原图尺寸,`analysisSize` 是脚本分析时的尺寸;它们只用于说明来源。`strokes[].points`、`contours[].bounds` 已按 `canvasSize` 转成画布像素坐标,原点在左上角。按 `canvasSize` 创建文档后直接使用,不能再乘原图到画布的比例。只有用户要求改变文档尺寸或摆放位置时,才对这份画布坐标统一做一次缩放或平移。 + +脚本已经平滑、简化并按累计路径长度分笔,相邻笔触共享端点。`--smooth` 和 `--stroke-length` 控制这些步骤;无需拼回闭环再手写 Catmull–Rom、重新采样或按点距切分。硬边用 `--smooth 0` 保留。手工补充的曲线可直接使用 `editor.draw` 的 Q/C 路径,工具负责采样。 + +检查 `--preview` 中主体是否完整、遮挡是否合理后,先把需要的轮廓画成轻稿。简单素描通常只需少量宽淡灰面与关键细节;不用在编辑器外生成整幅校稿图才落笔。提取颜色边界不代表识别了物体类别,补画前仍要对照附件确认关键形状。 + +## 进入编辑器 + +按 `canvasSize` 新建文档,分别建立轮廓、灰面和细节层。给输出的每笔补上 `layer`、`size`、`color`、`opacity`、`pressure`,再传给 `editor.draw`。路径数据直接嵌入 PTC,PTC 无文件 API。每段代码不得超过 32 KB,draw 每次最多 96 笔,单段总执行时间小于 120 秒;按数据大小和实际显示时间拆分,逐笔间隔用 550ms。 + +轮廓先轻后重,关键部件和遮挡根据原图补充。颜色分割不能自动决定铅笔明暗;灰面用独立层、选区和宽淡笔触,保留高光,少量排线即可。预览与原图对照后只修正明显的形体、遮挡和溢出问题。不要将辅助预览直接导入,替代用户要求的逐笔过程。 diff --git a/plugins/webguhui/minimax-photo/skills/minimax-photo/scripts/trace_reference.py b/plugins/webguhui/minimax-photo/skills/minimax-photo/scripts/trace_reference.py new file mode 100644 index 00000000..658595bd --- /dev/null +++ b/plugins/webguhui/minimax-photo/skills/minimax-photo/scripts/trace_reference.py @@ -0,0 +1,171 @@ +"""Trace a supplied mask or color region into bounded, ordered drawing strokes. + +Requires Pillow; no network, model, editor or host access. Writes JSON to stdout. +""" +import argparse +import json +import math +from collections import defaultdict + +from PIL import Image, ImageColor, ImageDraw + + +def trace(mask, width, height): + edges = defaultdict(set) + def inside(x, y): + return 0 <= x < width and 0 <= y < height and mask[y * width + x] + for y in range(height): + for x in range(width): + if not inside(x, y): + continue + if not inside(x, y - 1): edges[x, y].add((x + 1, y)) + if not inside(x + 1, y): edges[x + 1, y].add((x + 1, y + 1)) + if not inside(x, y + 1): edges[x + 1, y + 1].add((x, y + 1)) + if not inside(x - 1, y): edges[x, y + 1].add((x, y)) + remaining = sum(map(len, edges.values())) + loops = [] + while edges: + start = current = next(iter(edges)) + previous = None + loop = [start] + while True: + candidates = edges.get(current) + if not candidates: + raise ValueError("Open boundary: mask contour could not be closed") + def order(point): + if previous is None: return (0, point) + ax, ay = current[0] - previous[0], current[1] - previous[1] + bx, by = point[0] - current[0], point[1] - current[1] + cross, dot = ax * by - ay * bx, ax * bx + ay * by + return (0 if cross > 0 else 1 if dot > 0 else 2 if cross < 0 else 3, point) + following = min(candidates, key=order) + candidates.remove(following) + if not candidates: + del edges[current] + remaining -= 1 + if remaining < 0: + raise ValueError("Boundary traversal exceeded its edge budget") + previous, current = current, following + loop.append(current) + if current == start: + break + loops.append(loop) + assert remaining == 0 + return loops + + +def area(loop): + return sum(a[0] * b[1] - b[0] * a[1] for a, b in zip(loop, loop[1:])) / 2 + + +def smooth(loop, radius): + points = loop[:-1] + if not radius: return loop + offsets = range(-radius, radius + 1) + result = [tuple(sum(points[(i + k) % len(points)][axis] for k in offsets) / len(offsets) + for axis in (0, 1)) for i in range(len(points))] + return result + [result[0]] + + +def simplify(points, epsilon): + keep = {0, len(points) - 1} + pending = [(0, len(points) - 1)] + while pending: + first, last = pending.pop() + a, b = points[first], points[last] + dx, dy = b[0] - a[0], b[1] - a[1] + length = dx * dx + dy * dy + farthest, index = epsilon, None + for i in range(first + 1, last): + p = points[i] + t = max(0, min(1, ((p[0] - a[0]) * dx + (p[1] - a[1]) * dy) / length)) if length else 0 + distance = math.hypot(p[0] - a[0] - t * dx, p[1] - a[1] - t * dy) + if distance > farthest: farthest, index = distance, i + if index is not None: + keep.add(index) + pending.extend(((first, index), (index, last))) + return [points[i] for i in sorted(keep)] + + +def strokes(points, maximum): + """Split by arc length, preserving endpoints and every connecting segment.""" + result, stroke, used = [], [points[0]], 0.0 + for target in points[1:]: + current = stroke[-1] + distance = math.dist(current, target) + while distance > maximum - used + 1e-8: + fraction = (maximum - used) / distance + end = tuple(a + (b - a) * fraction for a, b in zip(current, target)) + stroke.append(end) + result.append(stroke) + stroke, current, used = [end], end, 0.0 + distance = math.dist(current, target) + stroke.append(target) + used += distance + if used >= maximum - 1e-8: + result.append(stroke) + stroke, used = [target], 0.0 + if len(stroke) > 1: result.append(stroke) + return result + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("image", help="white foreground mask, or image when --color is used") + parser.add_argument("--color", help="foreground RGB color, e.g. '#4080c0'") + parser.add_argument("--tolerance", type=float, default=70, help="RGB distance, 0..442") + parser.add_argument("--width", type=int, default=1000, help="output canvas width; aspect ratio preserved") + parser.add_argument("--min-area", type=float, default=12, help="minimum region area in analysis pixels") + parser.add_argument("--smooth", type=int, default=1, help="circular smoothing radius, 0..4") + parser.add_argument("--epsilon", type=float, default=0.6, help="simplification tolerance in analysis pixels") + parser.add_argument("--stroke-length", type=float, default=100, help="maximum output pixels per stroke") + parser.add_argument("--preview", help="write a contour-check PNG to a new file (max 1024px)") + args = parser.parse_args() + values = (args.tolerance, args.min_area, args.epsilon, args.stroke_length) + if not all(math.isfinite(v) for v in values) or not (0 <= args.tolerance <= 442 and + 1 <= args.width <= 4096 and 0 <= args.smooth <= 4 and args.min_area >= 0 and + 0 <= args.epsilon <= 5 and 10 <= args.stroke_length <= 1000): + parser.error("parameters outside supported ranges") + with Image.open(args.image) as source: + original = source.size + image = source.convert("RGBA") + image.thumbnail((640, 640)) + width, height = image.size + target = ImageColor.getrgb(args.color) if args.color else None + mask = [a >= 128 and (sum((v - t) ** 2 for v, t in zip((r, g, b), target)) <= args.tolerance ** 2 + if target else (r + g + b) / 3 >= 128) for r, g, b, a in image.getdata()] + loops = sorted((loop for loop in trace(mask, width, height) if abs(area(loop)) >= args.min_area), + key=lambda loop: abs(area(loop)), reverse=True) + if not loops: parser.error("no matching region; inspect the mask/color selection") + if len(loops) > 64: parser.error("more than 64 regions; use a cleaner mask or increase --min-area") + scale = args.width / width + output, contours = [], [] + for loop in loops: + points = [(round(x * scale, 2), round(y * scale, 2)) + for x, y in simplify(smooth(loop, args.smooth), args.epsilon)] + first = len(output) + output.extend({"points": part} for part in strokes(points, args.stroke_length)) + contours.append({"firstStroke": first, "strokeCount": len(output) - first, + "signedArea": round(area(loop) * scale * scale, 2), + "bounds": [min(p[0] for p in points), min(p[1] for p in points), + max(p[0] for p in points), max(p[1] for p in points)]}) + if len(output) > 512: parser.error("more than 512 strokes; simplify the mask or increase --stroke-length") + if args.preview: + # Bound the preview independently of the requested drawing dimensions. + factor = min(1024 / args.width, 1024 / (height * scale), 1) + preview = Image.new("RGB", (max(1, round(args.width * factor)), + max(1, round(height * scale * factor))), "white") + pen = ImageDraw.Draw(preview) + for stroke in output: + pen.line([(x * factor, y * factor) for x, y in stroke["points"]], + fill="#444444", width=1) + # Never overwrite the reference image or an earlier output. + with open(args.preview, "xb") as destination: + preview.save(destination, format="PNG") + print(json.dumps({"sourceSize": original, "analysisSize": [width, height], + "canvasSize": [args.width, round(height * scale)], "regions": len(loops), + "contours": contours, "strokes": output}, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/plugins/webguhui/minimax-photo/ui-src/.gitignore b/plugins/webguhui/minimax-photo/ui-src/.gitignore new file mode 100644 index 00000000..c2658d7d --- /dev/null +++ b/plugins/webguhui/minimax-photo/ui-src/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/plugins/webguhui/minimax-photo/ui-src/assistant-reply.tsx b/plugins/webguhui/minimax-photo/ui-src/assistant-reply.tsx new file mode 100644 index 00000000..3a3d6ccf --- /dev/null +++ b/plugins/webguhui/minimax-photo/ui-src/assistant-reply.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import Markdown from 'react-markdown'; +import remarkGfm from 'remark-gfm'; + +export function AssistantReply({ text }: { text: string }) { + // Host media is delivered through the validated image-result list, not Markdown. + const readable = text.replace(/]*(?:>|$)/gi, '').trim(); + return
+ /^https?:\/\//i.test(url) ? url : ''} + components={{ + img: ({ alt }) => {alt}, + a: ({ href, children }) => href + ? {children} + : {children}, + table: ({ children }) =>
{children}
, + }}> + {readable} +
+
; +} diff --git a/plugins/webguhui/minimax-photo/ui-src/build.mjs b/plugins/webguhui/minimax-photo/ui-src/build.mjs new file mode 100644 index 00000000..ee3f0807 --- /dev/null +++ b/plugins/webguhui/minimax-photo/ui-src/build.mjs @@ -0,0 +1,27 @@ +import { build } from 'esbuild'; +import { execFileSync } from 'node:child_process'; +import { fileURLToPath } from 'node:url'; +const root = fileURLToPath(new URL('.', import.meta.url)); +await build({ + entryPoints: [root + 'workbench.tsx'], + outfile: root + '../miniapp/client/workbench-ui.js', + bundle: true, + external: ['./photo-i18n.js'], + format: 'esm', + minify: true, + jsx: 'automatic', + define: { 'process.env.NODE_ENV': '"production"' }, + legalComments: 'linked', +}); +execFileSync( + process.execPath, + [ + root + 'node_modules/@tailwindcss/cli/dist/index.mjs', + '-i', + root + 'theme.css', + '-o', + root + '../miniapp/client/components.css', + '--minify', + ], + { stdio: 'inherit', cwd: root }, +); diff --git a/plugins/webguhui/minimax-photo/ui-src/components/button.tsx b/plugins/webguhui/minimax-photo/ui-src/components/button.tsx new file mode 100644 index 00000000..ee4ecb6e --- /dev/null +++ b/plugins/webguhui/minimax-photo/ui-src/components/button.tsx @@ -0,0 +1,63 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" +import { cn } from "../utils" +import { Slot } from "radix-ui" + +const buttonVariants = cva( + "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40", + outline: + "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: + "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2 has-[>svg]:px-3", + xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3", + sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5", + lg: "h-10 rounded-md px-6 has-[>svg]:px-4", + icon: "size-9", + "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3", + "icon-sm": "size-8", + "icon-lg": "size-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +function Button({ + className, + variant = "default", + size = "default", + asChild = false, + ...props +}: React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean + }) { + const Comp = asChild ? Slot.Root : "button" + + return ( + + ) +} + +export { Button, buttonVariants } diff --git a/plugins/webguhui/minimax-photo/ui-src/components/tooltip.tsx b/plugins/webguhui/minimax-photo/ui-src/components/tooltip.tsx new file mode 100644 index 00000000..804e4f66 --- /dev/null +++ b/plugins/webguhui/minimax-photo/ui-src/components/tooltip.tsx @@ -0,0 +1,56 @@ +"use client" + +import * as React from "react" +import { cn } from "../utils" +import { Tooltip as TooltipPrimitive } from "radix-ui" + +function TooltipProvider({ + delayDuration = 0, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function Tooltip({ + ...props +}: React.ComponentProps) { + return +} + +function TooltipTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function TooltipContent({ + className, + sideOffset = 0, + children, + ...props +}: React.ComponentProps) { + return ( + + + {children} + + + + ) +} + +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } diff --git a/plugins/webguhui/minimax-photo/ui-src/package-lock.json b/plugins/webguhui/minimax-photo/ui-src/package-lock.json new file mode 100644 index 00000000..203c25f1 --- /dev/null +++ b/plugins/webguhui/minimax-photo/ui-src/package-lock.json @@ -0,0 +1,4952 @@ +{ + "name": "minimax-photo-ui", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "minimax-photo-ui", + "dependencies": { + "class-variance-authority": "0.7.1", + "clsx": "2.1.1", + "lucide-react": "0.468.0", + "radix-ui": "1.4.3", + "react": "19.2.0", + "react-dom": "19.2.0", + "react-markdown": "10.1.0", + "remark-gfm": "4.0.1", + "tailwind-merge": "3.3.1" + }, + "devDependencies": { + "@tailwindcss/cli": "4.1.14", + "esbuild": "0.25.11", + "tailwindcss": "4.1.14" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", + "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", + "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", + "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", + "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", + "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", + "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", + "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", + "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", + "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", + "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", + "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", + "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", + "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", + "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", + "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", + "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", + "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", + "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", + "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", + "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", + "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", + "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", + "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", + "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", + "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", + "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz", + "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.8.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "license": "MIT" + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz", + "integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.6.0", + "@parcel/watcher-darwin-arm64": "2.6.0", + "@parcel/watcher-darwin-x64": "2.6.0", + "@parcel/watcher-freebsd-x64": "2.6.0", + "@parcel/watcher-linux-arm-glibc": "2.6.0", + "@parcel/watcher-linux-arm-musl": "2.6.0", + "@parcel/watcher-linux-arm64-glibc": "2.6.0", + "@parcel/watcher-linux-arm64-musl": "2.6.0", + "@parcel/watcher-linux-x64-glibc": "2.6.0", + "@parcel/watcher-linux-x64-musl": "2.6.0", + "@parcel/watcher-win32-arm64": "2.6.0", + "@parcel/watcher-win32-x64": "2.6.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz", + "integrity": "sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.6.0.tgz", + "integrity": "sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.6.0.tgz", + "integrity": "sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.6.0.tgz", + "integrity": "sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.6.0.tgz", + "integrity": "sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.6.0.tgz", + "integrity": "sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.6.0.tgz", + "integrity": "sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.6.0.tgz", + "integrity": "sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.6.0.tgz", + "integrity": "sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.6.0.tgz", + "integrity": "sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.6.0.tgz", + "integrity": "sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz", + "integrity": "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accessible-icon": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.7.tgz", + "integrity": "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", + "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz", + "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-aspect-ratio": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.7.tgz", + "integrity": "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz", + "integrity": "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", + "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", + "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context-menu": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.16.tgz", + "integrity": "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", + "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-form": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.8.tgz", + "integrity": "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-label": "2.1.7", + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-hover-card": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz", + "integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz", + "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", + "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menubar": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.16.tgz", + "integrity": "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.14.tgz", + "integrity": "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-one-time-password-field": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-one-time-password-field/-/react-one-time-password-field-0.1.8.tgz", + "integrity": "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-password-toggle-field": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-password-toggle-field/-/react-password-toggle-field-0.1.3.tgz", + "integrity": "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-is-hydrated": "0.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", + "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.7.tgz", + "integrity": "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.8.tgz", + "integrity": "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", + "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", + "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz", + "integrity": "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.3.6.tgz", + "integrity": "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", + "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.15.tgz", + "integrity": "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", + "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.11.tgz", + "integrity": "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-toggle": "1.1.10", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toolbar": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-1.1.11.tgz", + "integrity": "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-separator": "1.1.7", + "@radix-ui/react-toggle-group": "1.1.11" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", + "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", + "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, + "node_modules/@tailwindcss/cli": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.1.14.tgz", + "integrity": "sha512-2cErQRcsI8jIObUMVwcd1H2AWgGxwzozHJk7AKM2KB1taOp7L15xQ8kEsZrvVbOjNrb8yXtnSvNtJ+mhCB7EBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/watcher": "^2.5.1", + "@tailwindcss/node": "4.1.14", + "@tailwindcss/oxide": "4.1.14", + "enhanced-resolve": "^5.18.3", + "mri": "^1.2.0", + "picocolors": "^1.1.1", + "tailwindcss": "4.1.14" + }, + "bin": { + "tailwindcss": "dist/index.mjs" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.14.tgz", + "integrity": "sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.0", + "lightningcss": "1.30.1", + "magic-string": "^0.30.19", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.14" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.14.tgz", + "integrity": "sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.5.1" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.14", + "@tailwindcss/oxide-darwin-arm64": "4.1.14", + "@tailwindcss/oxide-darwin-x64": "4.1.14", + "@tailwindcss/oxide-freebsd-x64": "4.1.14", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.14", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.14", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.14", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.14", + "@tailwindcss/oxide-linux-x64-musl": "4.1.14", + "@tailwindcss/oxide-wasm32-wasi": "4.1.14", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.14", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.14" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.14.tgz", + "integrity": "sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.14.tgz", + "integrity": "sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.14.tgz", + "integrity": "sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.14.tgz", + "integrity": "sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.14.tgz", + "integrity": "sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.14.tgz", + "integrity": "sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.14.tgz", + "integrity": "sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.14.tgz", + "integrity": "sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.14.tgz", + "integrity": "sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.14.tgz", + "integrity": "sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.0.5", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.14.tgz", + "integrity": "sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.14.tgz", + "integrity": "sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", + "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.3.0.tgz", + "integrity": "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==", + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", + "license": "ISC" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT", + "peer": true + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.26.0.tgz", + "integrity": "sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/esbuild": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", + "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.11", + "@esbuild/android-arm": "0.25.11", + "@esbuild/android-arm64": "0.25.11", + "@esbuild/android-x64": "0.25.11", + "@esbuild/darwin-arm64": "0.25.11", + "@esbuild/darwin-x64": "0.25.11", + "@esbuild/freebsd-arm64": "0.25.11", + "@esbuild/freebsd-x64": "0.25.11", + "@esbuild/linux-arm": "0.25.11", + "@esbuild/linux-arm64": "0.25.11", + "@esbuild/linux-ia32": "0.25.11", + "@esbuild/linux-loong64": "0.25.11", + "@esbuild/linux-mips64el": "0.25.11", + "@esbuild/linux-ppc64": "0.25.11", + "@esbuild/linux-riscv64": "0.25.11", + "@esbuild/linux-s390x": "0.25.11", + "@esbuild/linux-x64": "0.25.11", + "@esbuild/netbsd-arm64": "0.25.11", + "@esbuild/netbsd-x64": "0.25.11", + "@esbuild/openbsd-arm64": "0.25.11", + "@esbuild/openbsd-x64": "0.25.11", + "@esbuild/openharmony-arm64": "0.25.11", + "@esbuild/sunos-x64": "0.25.11", + "@esbuild/win32-arm64": "0.25.11", + "@esbuild/win32-ia32": "0.25.11", + "@esbuild/win32-x64": "0.25.11" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lucide-react": { + "version": "0.468.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.468.0.tgz", + "integrity": "sha512-6koYRhnM2N0GGZIdXzSeiNwguv1gt/FAjZOiPl76roBi3xKEXa4WmfpxgQwTTL4KipXjefrnf3oV4IsYhi4JFA==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.3.tgz", + "integrity": "sha512-xPgpDNl0/OXHsI7TlaIs22lWnH3KlpvZdXG1ET/m/YT2Hhdkx8lJV4kLphE6l9simyM4KPDFBwas08BgEob6Jw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.1.0.tgz", + "integrity": "sha512-KRLgmPaP2H1ul2bpoJkOS+9pAcDAAj9Nu1mqLnh8NLeJG5tlvj42TH80PIGBpROWlRXLk0lDrWNuZCFy/tsB4A==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.1.tgz", + "integrity": "sha512-OuJHqvr455pwu2OaOrir7dbzqs4jlWKOtlu9L6GjcIjjQwNyw02VntQsr/Ek6/A13vgnXfUhBekWRUP1OkNivw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.2.0.tgz", + "integrity": "sha512-2Jn/ADrHFFyyniBMi0bncTbJqU78K3/TEYvzvwrWWzD9MYPUa/Gm4r3nOeKFQg/PDM5BsbDYdc8ackW4NTY6NA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.3.tgz", + "integrity": "sha512-oGYfQzHSG5dOMovQcJ3fyTmZlWAWpi0XA0sJwJs+i6OT88o1+Jtw/8z0CmdowSLxGhhFK89rQ/oXph/wN02PNw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-edit-map": "^1.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.4.tgz", + "integrity": "sha512-wxEeE8v8XVvOrxn1TZj74qYhAtTQsSqufHVS3uNVyT1MupXxhyaHk8/9xDNPh9BmL77QNDgWTkZ3RsYHB2ry7w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.1.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-edit-map": "^1.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.3" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.2.tgz", + "integrity": "sha512-pRzm4kDTu0MjlmBkxmS9yYhw60nncfcEwu9NNdPFSQEFXS95ZKyIIyTSHu/o3ReBUrLKYEq+7YaXCRn/bPB4MA==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.1.0.tgz", + "integrity": "sha512-fS8hnLIjnjvdQIj39Geug8wWsR0HrYZ43KShKxNfwT7t2LOHo/LbWZEzEaSOjwtjdCsjoE6syHhonEzW0zv0+Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-edit-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-edit-map/-/micromark-util-edit-map-1.0.0.tgz", + "integrity": "sha512-Pa2ljlsEL6sVwFaYeyrOLSYbQt73JvGbPOYFq+9AElXiSnfI5Q4465RRZ1sHv7lDjDOnGRDDaqPXqClqWK/q1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.3.tgz", + "integrity": "sha512-oxB2Ik03hI0gv+VNn9tnh1t1YEe9MDPptViAEgfdf3YQHsn0pzGTgCdlSCJXcwhqm8phaEuM7zeEu3QQzVBrPg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/property-information": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/radix-ui": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.4.3.tgz", + "integrity": "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-accessible-icon": "1.1.7", + "@radix-ui/react-accordion": "1.2.12", + "@radix-ui/react-alert-dialog": "1.1.15", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-aspect-ratio": "1.1.7", + "@radix-ui/react-avatar": "1.1.10", + "@radix-ui/react-checkbox": "1.3.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-context-menu": "2.2.16", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-dropdown-menu": "2.1.16", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-form": "0.1.8", + "@radix-ui/react-hover-card": "1.1.15", + "@radix-ui/react-label": "2.1.7", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-menubar": "1.1.16", + "@radix-ui/react-navigation-menu": "1.2.14", + "@radix-ui/react-one-time-password-field": "0.1.8", + "@radix-ui/react-password-toggle-field": "0.1.3", + "@radix-ui/react-popover": "1.1.15", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-progress": "1.1.7", + "@radix-ui/react-radio-group": "1.3.8", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-scroll-area": "1.2.10", + "@radix-ui/react-select": "2.2.6", + "@radix-ui/react-separator": "1.1.7", + "@radix-ui/react-slider": "1.3.6", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-switch": "1.2.6", + "@radix-ui/react-tabs": "1.1.13", + "@radix-ui/react-toast": "1.2.15", + "@radix-ui/react-toggle": "1.1.10", + "@radix-ui/react-toggle-group": "1.1.11", + "@radix-ui/react-toolbar": "1.1.11", + "@radix-ui/react-tooltip": "1.2.8", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-escape-keydown": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/react": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", + "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", + "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.0" + } + }, + "node_modules/react-markdown": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", + "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/style-to-js": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" + } + }, + "node_modules/style-to-object": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" + } + }, + "node_modules/tailwind-merge": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz", + "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz", + "integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar": { + "version": "7.5.22", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz", + "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.7.0.tgz", + "integrity": "sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/plugins/webguhui/minimax-photo/ui-src/package.json b/plugins/webguhui/minimax-photo/ui-src/package.json new file mode 100644 index 00000000..099c0d36 --- /dev/null +++ b/plugins/webguhui/minimax-photo/ui-src/package.json @@ -0,0 +1,24 @@ +{ + "name": "minimax-photo-ui", + "private": true, + "type": "module", + "scripts": { + "build": "node build.mjs" + }, + "dependencies": { + "class-variance-authority": "0.7.1", + "clsx": "2.1.1", + "lucide-react": "0.468.0", + "radix-ui": "1.4.3", + "react": "19.2.0", + "react-dom": "19.2.0", + "react-markdown": "10.1.0", + "remark-gfm": "4.0.1", + "tailwind-merge": "3.3.1" + }, + "devDependencies": { + "@tailwindcss/cli": "4.1.14", + "esbuild": "0.25.11", + "tailwindcss": "4.1.14" + } +} diff --git a/plugins/webguhui/minimax-photo/ui-src/photo-assistant.tsx b/plugins/webguhui/minimax-photo/ui-src/photo-assistant.tsx new file mode 100644 index 00000000..e055e102 --- /dev/null +++ b/plugins/webguhui/minimax-photo/ui-src/photo-assistant.tsx @@ -0,0 +1,408 @@ +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import { flushSync } from 'react-dom'; +import { Sparkles, Minus, ArrowUp, Square, Plus } from 'lucide-react'; +import { Button } from './components/button'; +import { t, subscribeLanguage, getLanguage } from './photo-i18n.js'; + +import { AssistantReply } from './assistant-reply'; + +export function mountPhotoAssistant({ context, prepare, showResults }) { + const savedId = 'assistant-00000000-0000-4000-8000-000000000001'; + const host = document.createElement('div'); + host.id = 'agent-panel-root'; + document.body.append(host); + let refresh = () => {}, + compose = (_text: string) => {}; + function Assistant() { + React.useSyncExternalStore(subscribeLanguage, getLanguage); + const [hydrated, setHydrated] = React.useState(false); + const revision = React.useRef(0); + const writes = React.useRef(Promise.resolve()); + const conflicted = React.useRef(false); + const lastSaved = React.useRef(''); + const [open, setOpen] = React.useState(false); + const [draft, setDraft] = React.useState(''); + const [current, setCurrent] = React.useState(context); + const [busy, setBusy] = React.useState(false); + const [reply, setReply] = React.useState(''); + const [status, setStatus] = React.useState(''); + const [error, setError] = React.useState(''); + const [permissions, setPermissions] = React.useState([]); + const [question, setQuestion] = React.useState(null); + const [position, setPosition] = React.useState(null); + const active = React.useRef(null); + const stopRequested = React.useRef(false); + const dispatched = React.useRef(false); + const session = React.useRef(undefined); + const input = React.useRef(null); + const panel = React.useRef(null); + const drag = React.useRef(null); + const api = () => (window as any).mcode?.miniapp?.agent; + React.useEffect(() => { + fetch('/api/recovery/' + savedId).then(async response => { + if (!response.ok) throw Error('load'); + const record = await response.json(); + revision.current = record.revision; + if (record.value) { + const saved = record.value; + setDraft(saved.draft); setReply(saved.reply); session.current = saved.sessionId; + setQuestion(saved.question || null); + if (!saved.busy && saved.status) setStatus(saved.status); + if (saved.busy) setStatus('结果尚未确认,请先查看会话,不要重复发送。'); + } + lastSaved.current = JSON.stringify(record.value || { draft: '', reply: '', busy: false, question: null, status: '' }); + setHydrated(true); + }).catch(() => setError(t('读取会话失败,请重新打开应用'))); + }, []); + const persist = (value) => { + const next = writes.current.then(async () => { + const serialized = JSON.stringify(value); + if (serialized === lastSaved.current) return; + if (conflicted.current) throw Error(t('会话已在其他窗口更新,请重新打开应用')); + const response = await fetch('/api/recovery/' + savedId, { + method: 'POST', headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ revision: revision.current, value }), + }); + if (response.status === 409) conflicted.current = true; + if (!response.ok) throw Error(t('会话保存失败,请保留当前页面')); + revision.current = (await response.json()).revision; + lastSaved.current = serialized; + }); + writes.current = next.catch(e => setError(e.message)); + return next; + }; + React.useEffect(() => { + if (!hydrated) return; + const timer = setTimeout(() => void persist({ draft, reply, busy, + sessionId: session.current, question, status }).catch(() => {}), 200); + return () => clearTimeout(timer); + }, [hydrated, draft, reply, busy, question, status]); + React.useEffect(() => { + const protect = (event) => { if (busy) { event.preventDefault(); event.returnValue = ''; } }; + window.addEventListener('beforeunload', protect); + return () => window.removeEventListener('beforeunload', protect); + }, [busy]); + async function cancel() { + stopRequested.current = true; + setStatus('正在停止…'); + try { if (dispatched.current) await api().cancel(active.current); } + catch (e) { setError(e.message); } + } + refresh = () => setCurrent(context()); + compose = (text) => { + if (text) setDraft(text); + setOpen(true); + }; + React.useEffect(() => { + if (open) { + input.current?.focus(); + void showResults(); + } + }, [open]); + const clamp = (x, y) => ({ + left: Math.max(8, Math.min(x, innerWidth - (panel.current?.offsetWidth || 360) - 8)), + top: Math.max(56, Math.min(y, innerHeight - (panel.current?.offsetHeight || 360) - 8)), + }); + React.useEffect(() => { + const resize = () => setPosition((p) => (p ? clamp(p.left, p.top) : null)); + window.addEventListener('resize', resize); + return () => window.removeEventListener('resize', resize); + }, []); + function onEvent(event) { + if (event.type === 'turn.started') session.current = event.sessionId; + if (event.type === 'text.delta') setReply((text) => (text + event.text).slice(-60000)); + if (event.type === 'message.committed') setReply(event.text); + if (event.type === 'tool.started') setStatus('正在处理图片…'); + if (event.type === 'permission.requested') + setPermissions((items) => [...items.filter((p) => p.requestId !== event.requestId), event]); + } + async function run(answers?) { + if (!hydrated || conflicted.current || active.current || (!answers && !draft.trim())) return; + if (!api()?.run) { + setError(t('请在 MiniMax Code 中打开此应用以使用 AI。')); + return; + } + const requestId = crypto.randomUUID(); + active.current = requestId; + stopRequested.current = false; + dispatched.current = false; + setBusy(true); + setError(''); + setReply(''); + setStatus('正在思考…'); + try { + await persist({ draft, reply, busy: true, sessionId: session.current, question }); + const text = answers ? undefined : await prepare('auto', draft); + if (stopRequested.current) { setStatus('已停止'); return; } + dispatched.current = true; + const result = answers + ? await api().answer( + { sessionId: session.current, questionId: question.requestId, answers, requestId }, + { onEvent }, + ) + : await api().run( + { text, sessionId: session.current, requestId }, + { onEvent }, + ); + session.current = result.sessionId; + setQuestion(result.pendingQuestion || null); + if (result.text) setReply(result.text); + if (result.status === 'error') + setError(result.error?.message || t('AI 处理失败,请检查后重试。')); + setStatus( + result.status === 'aborted' ? '已停止' : result.pendingQuestion ? '请补充信息' : '', + ); + if (result.status === 'finished' && !answers) setDraft(''); + await showResults(); + } catch (e) { + const unknown = ['result_unknown', 'AGENT_OUTCOME_UNKNOWN'].includes(e.message); + setStatus(unknown ? '结果尚未确认,请先查看会话,不要重复发送。' : ''); + const messages = { + runtime_unavailable: 'AI 连接暂不可用,请重新打开应用后再试。', + session_not_found: '这段会话已不可用,请新建对话。', + busy: 'AI 还在处理上一个请求,请稍后再试。', + not_permitted: '当前应用无法使用 AI,请检查应用权限。', + }; + setError(unknown ? '' : t(messages[e.message] || 'AI 处理失败,请检查后重试。')); + + } finally { + active.current = null; + dispatched.current = false; + setBusy(false); + } + } + async function decide(p, decision) { + try { + await api().reply({ sessionId: p.sessionId, requestId: p.requestId, decision }); + setPermissions((items) => items.filter((i) => i.requestId !== p.requestId)); + } catch (e) { + setError(e.message); + } + } + if (!open) + return ( + + ); + return ( +
{ + if (e.key === 'Escape') { + e.stopPropagation(); + setOpen(false); + } + }} + > +
{ + if (e.button !== 0 || (e.target as HTMLElement).closest('button')) return; + const r = panel.current!.getBoundingClientRect(); + drag.current = { x: e.clientX, y: e.clientY, left: r.left, top: r.top }; + e.currentTarget.setPointerCapture(e.pointerId); + }} + onPointerMove={(e) => { + const d = drag.current; + if (d) setPosition(clamp(d.left + e.clientX - d.x, d.top + e.clientY - d.y)); + }} + onPointerUp={() => (drag.current = null)} + onPointerCancel={() => (drag.current = null)} + onLostPointerCapture={() => (drag.current = null)} + > + + + {t('AI 助手')} + + + +
+

+ {current.name + ? t('当前工程 · {name}', { name: current.name }) + : t('描述想法,或先打开一张图片')} +

+ {reply && } + {status && ( +

+ {t(status)} +

+ )} + {error && ( +

+ {error} +

+ )} + {permissions.map((p) => ( +
+ {t('需要你的确认')} +

{p.reason}

+
+ {p.toolName} +
{p.toolInput}
+
+ + +
+ ))} + {question && !busy && ( +
{ + e.preventDefault(); + const data = new FormData(e.currentTarget); + void run( + question.request.steps.map((step) => ({ + stepId: step.id, + selectedOptionIds: data.getAll('option-' + step.id), + selectedOther: !!String(data.get('other-' + step.id) || '').trim(), + otherText: String(data.get('other-' + step.id) || ''), + })), + ); + }} + > + {question.request.title || t('请补充信息')} + {question.request.modePayload && ( +
{JSON.stringify(question.request.modePayload, null, 2)}
+ )} + {question.request.steps.map((step) => ( +
+ {step.question} +

{step.description}

+ {step.options.map((option) => ( + + ))} + +
+ ))} + +
+ )} + {!question && ( +
{ + e.preventDefault(); + void run(); + }} + > + {!draft && !busy && ( +
+ {[ + ['生成海报', '帮我设计一张咖啡海报,奶油色背景,标题 COFFEE BREAK。'], + ['改善照片', '请先让我选择一张照片,再改善曝光和色彩,保留自然细节。'], + ].map(([label, text]) => ( + + ))} +
+ )} +