image-vision-mcp 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,30 @@
1
1
  import axios, { AxiosError } from "axios";
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { fileURLToPath } from "url";
2
5
  import { API_BASE_URL, DEFAULT_MODEL, REQUEST_TIMEOUT_MS } from "../constants.js";
6
+ const PROJECT_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
7
+ const LOG_FILE = process.env.VISION_MCP_LOG_FILE ||
8
+ path.join(PROJECT_ROOT, "logs", "vision-mcp-proxy.log");
9
+ const LOG_MAX_SIZE = 10 * 1024 * 1024;
10
+ try {
11
+ fs.mkdirSync(path.dirname(LOG_FILE), { recursive: true });
12
+ }
13
+ catch {
14
+ // 日志不可写不影响正常调用。
15
+ }
16
+ function logMoonshot(msg) {
17
+ const line = `[${new Date().toISOString()}] ${msg}\n`;
18
+ console.error(line.trim());
19
+ fs.stat(LOG_FILE, (statErr, stats) => {
20
+ if (statErr || stats.size < LOG_MAX_SIZE) {
21
+ fs.appendFile(LOG_FILE, line, () => { });
22
+ }
23
+ else {
24
+ fs.writeFile(LOG_FILE, line, () => { });
25
+ }
26
+ });
27
+ }
3
28
  export function handleMoonshotError(error) {
4
29
  if (error instanceof AxiosError) {
5
30
  if (error.response) {
@@ -29,25 +54,83 @@ export function handleMoonshotError(error) {
29
54
  if (error.code === "ENOTFOUND" || error.code === "ECONNREFUSED") {
30
55
  return `Error: 无法连接 Moonshot API (${error.code})。请检查网络。`;
31
56
  }
57
+ if (error.code === "ERR_CANCELED" || error.message === "canceled") {
58
+ return "Error: Moonshot API 请求已取消。";
59
+ }
32
60
  }
33
61
  return `Error: 调用 Moonshot API 时发生意外错误: ${error instanceof Error ? error.message : String(error)}`;
34
62
  }
35
63
  const MAX_RETRIES = 2;
36
64
  const INITIAL_RETRY_DELAY_MS = 1000;
65
+ function summarizeContent(content) {
66
+ if (typeof content === "string") {
67
+ return { type: "text", chars: content.length, preview: content.slice(0, 120) };
68
+ }
69
+ if (!Array.isArray(content))
70
+ return { type: typeof content };
71
+ return content.map((block) => {
72
+ if (block.type === "text") {
73
+ return {
74
+ type: "text",
75
+ chars: block.text.length,
76
+ preview: block.text.slice(0, 120),
77
+ };
78
+ }
79
+ if (block.type === "image_url") {
80
+ const url = block.image_url.url;
81
+ const dataUrlMatch = url.match(/^data:(image\/[^;]+);base64,(.*)$/i);
82
+ if (dataUrlMatch) {
83
+ return {
84
+ type: "image_url",
85
+ mimeType: dataUrlMatch[1],
86
+ sizeKB: ((dataUrlMatch[2].length * 0.75) / 1024).toFixed(1),
87
+ };
88
+ }
89
+ return { type: "image_url", url };
90
+ }
91
+ const fallbackBlock = block;
92
+ return { type: fallbackBlock.type || typeof block };
93
+ });
94
+ }
95
+ // 重试退避也要响应取消,否则客户端已经中断时还会继续占着任务。
96
+ function sleep(ms, signal) {
97
+ if (!signal)
98
+ return new Promise((resolve) => setTimeout(resolve, ms));
99
+ if (signal.aborted)
100
+ return Promise.reject(new Error("Moonshot API 请求已取消"));
101
+ return new Promise((resolve, reject) => {
102
+ const timer = setTimeout(resolve, ms);
103
+ signal.addEventListener("abort", () => {
104
+ clearTimeout(timer);
105
+ reject(new Error("Moonshot API 请求已取消"));
106
+ }, { once: true });
107
+ });
108
+ }
37
109
  export async function callMoonshot(params) {
38
- const { apiKey, model = DEFAULT_MODEL, messages, maxTokens = 2048 } = params;
110
+ const { apiKey, model = DEFAULT_MODEL, messages, maxTokens = 2048, signal } = params;
39
111
  if (!apiKey) {
40
112
  throw new Error("MOONSHOT_API_KEY 未设置");
41
113
  }
114
+ const requestUrl = `${API_BASE_URL}/chat/completions`;
115
+ const requestSummary = {
116
+ model,
117
+ max_tokens: maxTokens,
118
+ messages: messages.map((message) => ({
119
+ role: message.role,
120
+ content: summarizeContent(message.content),
121
+ })),
122
+ };
123
+ logMoonshot(`[Moonshot] POST ${requestUrl} body=${JSON.stringify(requestSummary)}`);
42
124
  let lastError;
43
125
  for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
44
126
  try {
45
- const response = await axios.post(`${API_BASE_URL}/chat/completions`, {
127
+ const response = await axios.post(requestUrl, {
46
128
  model,
47
129
  messages,
48
130
  max_tokens: maxTokens,
49
131
  }, {
50
132
  timeout: REQUEST_TIMEOUT_MS,
133
+ signal,
51
134
  headers: {
52
135
  "Content-Type": "application/json",
53
136
  Authorization: `Bearer ${apiKey}`,
@@ -60,7 +143,7 @@ export async function callMoonshot(params) {
60
143
  // 仅对 429 限流重试,指数退避:1s, 2s
61
144
  if (err instanceof AxiosError && err.response?.status === 429 && attempt < MAX_RETRIES) {
62
145
  const delay = INITIAL_RETRY_DELAY_MS * Math.pow(2, attempt);
63
- await new Promise((resolve) => setTimeout(resolve, delay));
146
+ await sleep(delay, signal);
64
147
  continue;
65
148
  }
66
149
  throw err;
@@ -1 +1 @@
1
- {"version":3,"file":"moonshot.js","sourceRoot":"","sources":["../../src/services/moonshot.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"moonshot.js","sourceRoot":"","sources":["../../src/services/moonshot.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "image-vision-mcp",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "MCP server for image recognition via vision models (extensible to multiple providers), with an HTTP image-intercepting proxy that lets text-only LLMs accept image input in Claude Code.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -40,7 +40,6 @@
40
40
  "image-recognition",
41
41
  "moonshot",
42
42
  "kimi",
43
- "clipboard",
44
43
  "anthropic"
45
44
  ],
46
45
  "dependencies": {
@@ -1,16 +0,0 @@
1
- import type { ImageLoadResult } from "../types.js";
2
- /**
3
- * 跨平台读取剪贴板图片
4
- *
5
- * - Windows: PowerShell System.Windows.Forms.Clipboard
6
- * - macOS: pngpaste (优先) 或 osascript
7
- * - Linux: xclip (优先) 或 xsel
8
- */
9
- export declare function readClipboardImage(): Promise<ImageLoadResult>;
10
- /**
11
- * 清理上次进程异常退出残留的临时图片文件
12
- *
13
- * readClipboardImage 用 finally 清理临时文件,但进程被 SIGKILL 时来不及执行。
14
- * 启动时调一次,扫掉 os.tmpdir() 里所有 kimi_clipboard_*.png。
15
- */
16
- export declare function cleanupOldTempImages(): Promise<void>;
@@ -1,196 +0,0 @@
1
- import { execFile } from "child_process";
2
- import { promisify } from "util";
3
- import path from "path";
4
- import os from "os";
5
- import fs from "fs/promises";
6
- import { IMAGE_MAX_SIZE_BYTES } from "../constants.js";
7
- import { imageBufferToDataUrl, detectMimeTypeFromPath } from "./image.js";
8
- const execFileAsync = promisify(execFile);
9
- /**
10
- * 生成临时图片路径
11
- */
12
- function getTempImagePath() {
13
- const timestamp = Date.now();
14
- return path.join(os.tmpdir(), `kimi_clipboard_${timestamp}.png`);
15
- }
16
- /**
17
- * 从临时文件加载图片为 data URL,并清理临时文件
18
- */
19
- async function loadTempImage(tempPath) {
20
- let buffer;
21
- try {
22
- buffer = await fs.readFile(tempPath);
23
- }
24
- finally {
25
- // 无论成功与否都尝试清理临时文件
26
- fs.unlink(tempPath).catch(() => { });
27
- }
28
- if (buffer.length > IMAGE_MAX_SIZE_BYTES) {
29
- throw new Error(`剪贴板图片过大: ${(buffer.length / 1024 / 1024).toFixed(2)} MB,最大支持 ${IMAGE_MAX_SIZE_BYTES / 1024 / 1024} MB`);
30
- }
31
- const mimeType = detectMimeTypeFromPath(tempPath); // .png → image/png
32
- return {
33
- dataUrl: imageBufferToDataUrl(buffer, mimeType),
34
- mimeType,
35
- sizeBytes: buffer.length,
36
- };
37
- }
38
- // ────────────────────── Windows ──────────────────────
39
- async function readClipboardWindows() {
40
- const tempPath = getTempImagePath();
41
- // PowerShell 单引号字符串里所有字符都是字面量(含 \ $ 反引号),单引号本身转义为 ''
42
- // 这样避免路径含特殊字符时被 PowerShell 解释,比双引号 + 反斜杠转义更安全
43
- const safePath = tempPath.replace(/'/g, "''");
44
- const psScript = `
45
- Add-Type -AssemblyName System.Windows.Forms
46
- $img = [System.Windows.Forms.Clipboard]::GetImage()
47
- if ($img -eq $null) {
48
- exit 1
49
- }
50
- $img.Save('${safePath}')
51
- $img.Dispose()
52
- exit 0
53
- `.trim();
54
- try {
55
- await execFileAsync("powershell", [
56
- "-NoProfile",
57
- "-NonInteractive",
58
- "-Command",
59
- psScript,
60
- ]);
61
- }
62
- catch (err) {
63
- if (err.code === 1) {
64
- throw new Error("剪贴板中没有图片");
65
- }
66
- throw new Error(`PowerShell 读取剪贴板图片失败: ${err.message}`);
67
- }
68
- return loadTempImage(tempPath);
69
- }
70
- // ────────────────────── macOS ──────────────────────
71
- async function readClipboardMac() {
72
- const tempPath = getTempImagePath();
73
- // 优先尝试 pngpaste(brew install pngpaste)
74
- try {
75
- await execFileAsync("pngpaste", [tempPath]);
76
- return loadTempImage(tempPath);
77
- }
78
- catch (err) {
79
- // pngpaste 不可用或执行失败(如剪贴板无图片),回退到 osascript
80
- console.error(`[vision-mcp] pngpaste 不可用,回退到 osascript: ${err.message}`);
81
- }
82
- // 使用 AppleScript 从剪贴板读取 PNG 图片
83
- const appleScript = `
84
- try
85
- set theFile to (open for access POSIX file "${tempPath}" with write permission)
86
- try
87
- write (the clipboard as «class PNGf») to theFile
88
- on error
89
- close access theFile
90
- error "NoImage"
91
- end try
92
- close access theFile
93
- on error errMsg
94
- if errMsg is "NoImage" then
95
- error "NoImage"
96
- else
97
- error errMsg
98
- end if
99
- end try
100
- `.trim();
101
- try {
102
- await execFileAsync("osascript", ["-e", appleScript]);
103
- }
104
- catch (err) {
105
- const msg = err.message || "";
106
- if (msg.includes("NoImage") || msg.includes("clipboard")) {
107
- throw new Error("剪贴板中没有图片");
108
- }
109
- throw new Error(`osascript 读取剪贴板图片失败: ${msg}`);
110
- }
111
- return loadTempImage(tempPath);
112
- }
113
- // ────────────────────── Linux ──────────────────────
114
- async function readClipboardLinux() {
115
- const tempPath = getTempImagePath();
116
- // 尝试 xclip
117
- try {
118
- const { stdout } = await execFileAsync("xclip", [
119
- "-selection",
120
- "clipboard",
121
- "-t",
122
- "image/png",
123
- "-o",
124
- ], { encoding: "buffer" });
125
- if (!stdout || stdout.length === 0) {
126
- throw new Error("剪贴板中没有图片");
127
- }
128
- await fs.writeFile(tempPath, stdout);
129
- return loadTempImage(tempPath);
130
- }
131
- catch (err) {
132
- if (err.message?.includes("剪贴板中没有图片")) {
133
- throw err;
134
- }
135
- // xclip 不可用或执行失败,尝试 xsel
136
- }
137
- // 尝试 xsel
138
- try {
139
- const { stdout } = await execFileAsync("xsel", [
140
- "--clipboard",
141
- "--output",
142
- ], { encoding: "buffer" });
143
- if (!stdout || stdout.length === 0) {
144
- throw new Error("剪贴板中没有图片");
145
- }
146
- await fs.writeFile(tempPath, stdout);
147
- return loadTempImage(tempPath);
148
- }
149
- catch (err) {
150
- if (err.message?.includes("剪贴板中没有图片")) {
151
- throw err;
152
- }
153
- throw new Error("Linux 剪贴板读取失败,请安装 xclip 或 xsel: sudo apt install xclip");
154
- }
155
- }
156
- // ────────────────────── 统一入口 ──────────────────────
157
- /**
158
- * 跨平台读取剪贴板图片
159
- *
160
- * - Windows: PowerShell System.Windows.Forms.Clipboard
161
- * - macOS: pngpaste (优先) 或 osascript
162
- * - Linux: xclip (优先) 或 xsel
163
- */
164
- export async function readClipboardImage() {
165
- const platform = process.platform;
166
- switch (platform) {
167
- case "win32":
168
- return readClipboardWindows();
169
- case "darwin":
170
- return readClipboardMac();
171
- case "linux":
172
- return readClipboardLinux();
173
- default:
174
- throw new Error(`不支持的平台: ${platform}`);
175
- }
176
- }
177
- /**
178
- * 清理上次进程异常退出残留的临时图片文件
179
- *
180
- * readClipboardImage 用 finally 清理临时文件,但进程被 SIGKILL 时来不及执行。
181
- * 启动时调一次,扫掉 os.tmpdir() 里所有 kimi_clipboard_*.png。
182
- */
183
- export async function cleanupOldTempImages() {
184
- const tmpDir = os.tmpdir();
185
- try {
186
- const files = await fs.readdir(tmpDir);
187
- const pattern = /^kimi_clipboard_\d+\.png$/;
188
- await Promise.all(files
189
- .filter((f) => pattern.test(f))
190
- .map((f) => fs.unlink(path.join(tmpDir, f)).catch(() => { })));
191
- }
192
- catch {
193
- // 忽略错误
194
- }
195
- }
196
- //# sourceMappingURL=clipboard.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../src/services/clipboard.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- export declare function registerDescribeClipboardTool(server: McpServer, getApiKey: () => string): void;
@@ -1,121 +0,0 @@
1
- import fs from "fs";
2
- import os from "os";
3
- import path from "path";
4
- import { DescribeClipboardInputSchema } from "../schemas.js";
5
- import { DEFAULT_MODEL, CHARACTER_LIMIT } from "../constants.js";
6
- import { readClipboardImage } from "../services/clipboard.js";
7
- import { callMoonshot, handleMoonshotError } from "../services/moonshot.js";
8
- // 排查用日志:MCP 工具走 stdio,console 输出用户看不到,写文件方便排查耗时
9
- const LOG_FILE = path.join(os.tmpdir(), "vision-mcp-clipboard.log");
10
- function log(msg) {
11
- const line = `[${new Date().toISOString()}] ${msg}\n`;
12
- console.error(line.trim());
13
- fs.appendFile(LOG_FILE, line, () => { });
14
- }
15
- export function registerDescribeClipboardTool(server, getApiKey) {
16
- server.registerTool("kimi_describe_clipboard", {
17
- title: "Kimi 识别剪贴板图片",
18
- description: `使用 Moonshot Kimi 视觉模型 (kimi-k2.6) 识别剪贴板中的图片并返回文本描述。
19
-
20
- 直接从系统剪贴板读取图片,无需提供文件路径或 URL。
21
- 跨平台支持: Windows (PowerShell)、macOS (pngpaste/osascript)、Linux (xclip/xsel)。
22
-
23
- Args:
24
- - prompt (string, 可选): 询问图片的问题或识图指令,默认 "请详细描述这张图片的内容。"。最长 4000 字符
25
- - max_tokens (number, 可选): 返回描述的最大 token 数,1-8192,默认 2048
26
-
27
- Returns:
28
- 文本内容,包含图片描述和 token 使用情况元信息。
29
-
30
- Usage:
31
- 1. 用户先复制一张图片到剪贴板 (Ctrl+C)
32
- 2. 调用此工具即可自动从剪贴板读取并识别
33
-
34
- Examples:
35
- - 描述剪贴板截图: (无参数,使用默认 prompt)
36
- - 提取剪贴板图片中的文字: prompt="请提取图片中的所有文字"
37
- - 识别剪贴板中的图表: prompt="图表中显示的数据是什么"
38
-
39
- Error Handling:
40
- - "剪贴板中没有图片": 请先复制一张图片到剪贴板
41
- - "不支持的平台": 当前操作系统不支持
42
- - "Moonshot API 鉴权失败 (401)": API key 错误
43
- - "Moonshot API 限流 (429)": 请求过于频繁,请稍后重试`,
44
- inputSchema: DescribeClipboardInputSchema,
45
- annotations: {
46
- readOnlyHint: true,
47
- destructiveHint: false,
48
- idempotentHint: false,
49
- openWorldHint: true,
50
- },
51
- }, async (params) => {
52
- const apiKey = getApiKey();
53
- const t0 = Date.now();
54
- // 1. 从剪贴板读取图片
55
- let imageResult;
56
- try {
57
- imageResult = await readClipboardImage();
58
- log(`读取剪贴板耗时 ${Date.now() - t0}ms, 图片 ${(imageResult.sizeBytes / 1024).toFixed(1)} KB (${imageResult.mimeType})`);
59
- }
60
- catch (err) {
61
- return {
62
- content: [
63
- {
64
- type: "text",
65
- text: `Error: 读取剪贴板图片失败 - ${err.message}`,
66
- },
67
- ],
68
- };
69
- }
70
- // 2. 构造 Moonshot 请求
71
- const content = [
72
- { type: "image_url", image_url: { url: imageResult.dataUrl } },
73
- { type: "text", text: params.prompt },
74
- ];
75
- const messages = [{ role: "user", content }];
76
- // 3. 调用 Moonshot API
77
- const t1 = Date.now();
78
- let response;
79
- try {
80
- response = await callMoonshot({
81
- apiKey,
82
- model: DEFAULT_MODEL,
83
- messages,
84
- maxTokens: params.max_tokens,
85
- });
86
- log(`Moonshot 调用耗时 ${Date.now() - t1}ms, completion_tokens=${response.usage?.completion_tokens ?? "?"}`);
87
- }
88
- catch (err) {
89
- return {
90
- content: [{ type: "text", text: handleMoonshotError(err) }],
91
- };
92
- }
93
- // 4. 提取描述
94
- const description = response.choices?.[0]?.message?.content ?? "";
95
- if (!description) {
96
- return {
97
- content: [
98
- {
99
- type: "text",
100
- text: `Error: Moonshot API 返回空内容。完整响应: ${JSON.stringify(response)}`,
101
- },
102
- ],
103
- };
104
- }
105
- // 5. 构造输出
106
- const meta = [
107
- `模型: ${response.model}`,
108
- `图片大小: ${(imageResult.sizeBytes / 1024).toFixed(2)} KB (${imageResult.mimeType})`,
109
- `Token 使用: ${response.usage?.total_tokens ?? "未知"} (prompt: ${response.usage?.prompt_tokens ?? "?"}, completion: ${response.usage?.completion_tokens ?? "?"})`,
110
- ].join("\n");
111
- let text = `${description}\n\n---\n${meta}`;
112
- if (text.length > CHARACTER_LIMIT) {
113
- text = text.slice(0, CHARACTER_LIMIT) + `\n\n[已截断,原文长度 ${text.length} 字符]`;
114
- }
115
- log(`总耗时 ${Date.now() - t0}ms`);
116
- return {
117
- content: [{ type: "text", text }],
118
- };
119
- });
120
- }
121
- //# sourceMappingURL=describeClipboard.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"describeClipboard.js","sourceRoot":"","sources":["../../src/tools/describeClipboard.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,4BAA4B,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAI5E,gDAAgD;AAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,0BAA0B,CAAC,CAAC;AACpE,SAAS,GAAG,CAAC,GAAW;IACtB,MAAM,IAAI,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,GAAG,IAAI,CAAC;IACtD,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3B,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,MAAiB,EACjB,SAAuB;IAEvB,MAAM,CAAC,YAAY,CACjB,yBAAyB,EACzB;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;0CAyBuB;QACpC,WAAW,EAAE,4BAA4B;QACzC,WAAW,EAAE;YACX,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,KAAK;YACrB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,KAAK,EAAE,MAA8B,EAAE,EAAE;QACvC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEtB,cAAc;QACd,IAAI,WAAW,CAAC;QAChB,IAAI,CAAC;YACH,WAAW,GAAG,MAAM,kBAAkB,EAAE,CAAC;YACzC,GAAG,CAAC,WAAW,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,WAAW,CAAC,QAAQ,GAAG,CAAC,CAAC;QACpH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,sBAAuB,GAAa,CAAC,OAAO,EAAE;qBACrD;iBACF;aACF,CAAC;QACJ,CAAC;QAED,oBAAoB;QACpB,MAAM,OAAO,GAAsB;YACjC,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,WAAW,CAAC,OAAO,EAAE,EAAE;YAC9D,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE;SACtC,CAAC;QACF,MAAM,QAAQ,GAAsB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAEhE,qBAAqB;QACrB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,IAAI,QAAQ,CAAC;QACb,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,YAAY,CAAC;gBAC5B,MAAM;gBACN,KAAK,EAAE,aAAa;gBACpB,QAAQ;gBACR,SAAS,EAAE,MAAM,CAAC,UAAU;aAC7B,CAAC,CAAC;YACH,GAAG,CAAC,iBAAiB,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,yBAAyB,QAAQ,CAAC,KAAK,EAAE,iBAAiB,IAAI,GAAG,EAAE,CAAC,CAAC;QAC3G,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC;aAC5D,CAAC;QACJ,CAAC;QAED,UAAU;QACV,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;QAClE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,mCAAmC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE;qBACpE;iBACF;aACF,CAAC;QACJ,CAAC;QAED,UAAU;QACV,MAAM,IAAI,GAAG;YACX,OAAO,QAAQ,CAAC,KAAK,EAAE;YACvB,SAAS,CAAC,WAAW,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,WAAW,CAAC,QAAQ,GAAG;YACjF,aAAa,QAAQ,CAAC,KAAK,EAAE,YAAY,IAAI,IAAI,aAAa,QAAQ,CAAC,KAAK,EAAE,aAAa,IAAI,GAAG,iBAAiB,QAAQ,CAAC,KAAK,EAAE,iBAAiB,IAAI,GAAG,GAAG;SAC/J,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,IAAI,IAAI,GAAG,GAAG,WAAW,YAAY,IAAI,EAAE,CAAC;QAC5C,IAAI,IAAI,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;YAClC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,GAAG,iBAAiB,IAAI,CAAC,MAAM,MAAM,CAAC;QAC7E,CAAC;QAED,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QAChC,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;SAClC,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}