@ozaiya/openclaw-channel 0.10.4 → 0.10.6

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.
@@ -0,0 +1,382 @@
1
+ /**
2
+ * Desktop container lifecycle and AT-SPI proxy for gateway mode.
3
+ *
4
+ * Manages Docker containers running Xvfb + AT-SPI for desktop automation.
5
+ * Each container provides a virtual display, VNC access, and an AT-SPI HTTP agent.
6
+ * Containers are labeled with `ozaiya.desktop=1` for easy filtering.
7
+ */
8
+ import fs from "node:fs";
9
+ import os from "node:os";
10
+ import { execSync } from "node:child_process";
11
+ /** True when running inside the desktop Docker container (not on host). */
12
+ export const isInContainer = fs.existsSync("/.dockerenv") || process.env.IN_CONTAINER === "1";
13
+ // ── Docker binary detection ──────────────────────────────────────────────────
14
+ export const dockerEnv = {
15
+ ...process.env,
16
+ PATH: `${process.env.PATH}:/usr/local/bin:/Applications/Docker.app/Contents/Resources/bin`,
17
+ };
18
+ let dockerPath = null;
19
+ function getDockerPath() {
20
+ if (dockerPath)
21
+ return dockerPath;
22
+ const candidates = [
23
+ "docker",
24
+ "/usr/local/bin/docker",
25
+ "/Applications/Docker.app/Contents/Resources/bin/docker",
26
+ ];
27
+ for (const candidate of candidates) {
28
+ try {
29
+ execSync(`${candidate} --version`, { env: dockerEnv, timeout: 5000 });
30
+ dockerPath = candidate;
31
+ return candidate;
32
+ }
33
+ catch {
34
+ // try next
35
+ }
36
+ }
37
+ throw new Error("Docker not found. Please install Docker or Docker Desktop.");
38
+ }
39
+ export function docker(args, timeout = 30_000) {
40
+ const bin = getDockerPath();
41
+ return execSync(`${bin} ${args}`, { timeout, env: dockerEnv }).toString().trim();
42
+ }
43
+ /**
44
+ * Run `docker exec <containerId> <cmd>` and return stdout trimmed.
45
+ * When running inside the container, executes the command directly.
46
+ */
47
+ export function dockerExec(containerId, cmd, timeout = 30_000) {
48
+ if (isInContainer) {
49
+ return execSync(cmd, { timeout, env: process.env }).toString().trim();
50
+ }
51
+ return docker(`exec ${containerId} ${cmd}`, timeout);
52
+ }
53
+ // ── Container lifecycle ──────────────────────────────────────────────────────
54
+ export function createContainer(params) {
55
+ const { name, image = "ozaiya-desktop:latest", app, appArgs, resolution = "1280x800x24", vncPassword = Math.random().toString(36).slice(2, 10), } = params;
56
+ const containerName = `ozaiya-desktop-${name}`;
57
+ const envArgs = [
58
+ `-e VNC_PASSWORD=${vncPassword}`,
59
+ `-e RESOLUTION=${resolution}`,
60
+ ];
61
+ if (app)
62
+ envArgs.push(`-e TARGET_APP=${app}`);
63
+ if (appArgs)
64
+ envArgs.push(`-e TARGET_APP_ARGS='${appArgs}'`);
65
+ const containerId = docker([
66
+ "run -d",
67
+ `--name ${containerName}`,
68
+ "--label ozaiya.desktop=1",
69
+ "-p 0:5900 -p 0:6080 -p 0:8080",
70
+ ...envArgs,
71
+ image,
72
+ ].join(" "));
73
+ const ports = getContainerPorts(containerId.slice(0, 12));
74
+ return {
75
+ id: containerId.slice(0, 12),
76
+ name,
77
+ image,
78
+ status: "running",
79
+ ports,
80
+ vncPassword,
81
+ app,
82
+ appArgs,
83
+ resolution,
84
+ createdAt: new Date().toISOString(),
85
+ };
86
+ }
87
+ export function startContainer(idOrName) {
88
+ docker(`start ${idOrName}`);
89
+ return { ok: true };
90
+ }
91
+ export function stopContainer(idOrName) {
92
+ docker(`stop ${idOrName}`, 15_000);
93
+ return { ok: true };
94
+ }
95
+ export function removeContainer(idOrName) {
96
+ docker(`rm -f ${idOrName}`);
97
+ return { ok: true };
98
+ }
99
+ export function listContainers() {
100
+ if (isInContainer) {
101
+ return [{
102
+ id: "local",
103
+ name: os.hostname(),
104
+ status: "running",
105
+ image: "ozaiya-desktop:latest",
106
+ ports: "5900->5900/tcp, 6080->6080/tcp, 8080->8080/tcp",
107
+ created: new Date().toISOString(),
108
+ }];
109
+ }
110
+ const formatStr = "{{.ID}}\\t{{.Names}}\\t{{.Status}}\\t{{.Image}}\\t{{.Ports}}\\t{{.CreatedAt}}";
111
+ let output;
112
+ try {
113
+ output = docker(`ps -a --filter label=ozaiya.desktop=1 --format '${formatStr}'`);
114
+ }
115
+ catch {
116
+ return [];
117
+ }
118
+ if (!output)
119
+ return [];
120
+ return output.split("\n").filter(Boolean).map(line => {
121
+ const [id, name, status, image, ports, created] = line.split("\t");
122
+ return { id, name, status, image, ports, created };
123
+ });
124
+ }
125
+ export function getContainerLogs(idOrName, tail = 100) {
126
+ return docker(`logs --tail ${tail} ${idOrName}`, 10_000);
127
+ }
128
+ // ── Port discovery ───────────────────────────────────────────────────────────
129
+ function getContainerPorts(idOrName) {
130
+ const ports = { vnc: null, novnc: null, agent: null };
131
+ try {
132
+ const output = docker(`port ${idOrName}`);
133
+ for (const line of output.split("\n")) {
134
+ const match = line.match(/^(\d+)\/tcp\s+->\s+.*:(\d+)$/);
135
+ if (!match)
136
+ continue;
137
+ const [, containerPort, hostPort] = match;
138
+ const port = parseInt(hostPort, 10);
139
+ if (containerPort === "5900")
140
+ ports.vnc = port;
141
+ else if (containerPort === "6080")
142
+ ports.novnc = port;
143
+ else if (containerPort === "8080")
144
+ ports.agent = port;
145
+ }
146
+ }
147
+ catch {
148
+ // ports not available yet
149
+ }
150
+ return ports;
151
+ }
152
+ /**
153
+ * Find the host-mapped port for a given container port.
154
+ */
155
+ export function findContainerPort(idOrName, containerPort) {
156
+ if (isInContainer) {
157
+ return containerPort; // no port mapping inside the container
158
+ }
159
+ try {
160
+ const output = docker(`port ${idOrName} ${containerPort}`);
161
+ const lastLine = output.split("\n").pop() || output;
162
+ const hostPort = lastLine.split(":").pop();
163
+ return hostPort ? parseInt(hostPort, 10) : null;
164
+ }
165
+ catch {
166
+ return null;
167
+ }
168
+ }
169
+ // ── App management inside containers ─────────────────────────────────────────
170
+ export function launchApp(idOrName, app, appArgs = "") {
171
+ // Get the D-Bus address from the agent inside the container
172
+ const agentPort = findContainerPort(idOrName, 8080);
173
+ if (!agentPort) {
174
+ throw new Error("AT-SPI agent port not found");
175
+ }
176
+ const envOutput = execSync(`curl -sS --max-time 5 http://localhost:${agentPort}/env`, { timeout: 10_000, env: dockerEnv }).toString();
177
+ const env = JSON.parse(envOutput);
178
+ const envStr = Object.entries(env)
179
+ .map(([k, v]) => `export ${k}="${v}"`)
180
+ .join(" && ");
181
+ const bin = getDockerPath();
182
+ execSync(`${bin} exec -d ${idOrName} bash -c '${envStr} && ${app} ${appArgs}'`, { timeout: 10_000, env: dockerEnv });
183
+ return { ok: true };
184
+ }
185
+ // ── AT-SPI proxy API ─────────────────────────────────────────────────────────
186
+ function agentGet(agentPort, path) {
187
+ const stdout = execSync(`curl -sS --max-time 10 "http://localhost:${agentPort}${path}"`, { timeout: 15_000, env: dockerEnv }).toString();
188
+ return JSON.parse(stdout);
189
+ }
190
+ function agentPost(agentPort, path, body) {
191
+ const jsonBody = JSON.stringify(body).replace(/'/g, "'\\''");
192
+ const stdout = execSync(`curl -sS --max-time 10 -X POST "http://localhost:${agentPort}${path}" -H "Content-Type: application/json" -d '${jsonBody}'`, { timeout: 15_000, env: dockerEnv }).toString();
193
+ return JSON.parse(stdout);
194
+ }
195
+ function agentGetBinary(agentPort, path) {
196
+ const stdout = execSync(`curl -sS --max-time 10 "http://localhost:${agentPort}${path}"`, { timeout: 15_000, encoding: "latin1", env: dockerEnv });
197
+ return Buffer.from(stdout, "latin1");
198
+ }
199
+ export function atspiHealth(agentPort) {
200
+ return agentGet(agentPort, "/health");
201
+ }
202
+ export function atspiApps(agentPort) {
203
+ return agentGet(agentPort, "/apps");
204
+ }
205
+ export function atspiTree(agentPort, opts) {
206
+ const params = new URLSearchParams();
207
+ if (opts?.app)
208
+ params.set("app", opts.app);
209
+ if (opts?.maxDepth !== undefined)
210
+ params.set("max_depth", String(opts.maxDepth));
211
+ const qs = params.toString();
212
+ return agentGet(agentPort, `/tree${qs ? `?${qs}` : ""}`);
213
+ }
214
+ export function atspiFind(agentPort, criteria) {
215
+ return agentPost(agentPort, "/find", criteria);
216
+ }
217
+ export function atspiAction(agentPort, path, action = "click") {
218
+ return agentPost(agentPort, "/action", { path, action });
219
+ }
220
+ export function atspiType(agentPort, path, text) {
221
+ return agentPost(agentPort, "/type", { path, text });
222
+ }
223
+ export function atspiKey(agentPort, key, modifiers) {
224
+ return agentPost(agentPort, "/key", { key, modifiers });
225
+ }
226
+ export function atspiClick(agentPort, x, y, button = 1) {
227
+ return agentPost(agentPort, "/click", { x, y, button });
228
+ }
229
+ export function atspiScreenshot(agentPort, opts) {
230
+ const params = new URLSearchParams();
231
+ if (opts?.bounds)
232
+ params.set("bounds", opts.bounds);
233
+ if (opts?.quality !== undefined)
234
+ params.set("quality", String(opts.quality));
235
+ const qs = params.toString();
236
+ const buf = agentGetBinary(agentPort, `/screenshot${qs ? `?${qs}` : ""}`);
237
+ return buf.toString("base64");
238
+ }
239
+ // ── Port parsing helper (for server-side port string parsing) ────────────────
240
+ export function parseAgentPort(portsStr) {
241
+ const match = portsStr?.match(/(\d+)->8080\/tcp/);
242
+ return match ? parseInt(match[1], 10) : null;
243
+ }
244
+ export function parseNoVncPort(portsStr) {
245
+ const match = portsStr?.match(/(\d+)->6080\/tcp/);
246
+ return match ? parseInt(match[1], 10) : null;
247
+ }
248
+ /**
249
+ * Resolve the AT-SPI agent port for a container by ID or name substring.
250
+ */
251
+ export function resolveAgentPort(containerId) {
252
+ if (isInContainer) {
253
+ return parseInt(process.env.AGENT_PORT || "8080", 10);
254
+ }
255
+ const containers = listContainers();
256
+ const container = containers.find(c => c.id === containerId || c.name.includes(containerId));
257
+ if (!container) {
258
+ throw new Error("Container not found");
259
+ }
260
+ const agentPort = parseAgentPort(container.ports);
261
+ if (!agentPort) {
262
+ throw new Error("Agent port not available");
263
+ }
264
+ return agentPort;
265
+ }
266
+ // ── xdotool helpers (clipboard paste + key simulation) ───────────────────────
267
+ /**
268
+ * Get DISPLAY and DBUS_SESSION_BUS_ADDRESS from the AT-SPI agent process.
269
+ * Cached per container to avoid repeated lookups.
270
+ */
271
+ const envCache = new Map();
272
+ function getContainerEnvPrefix(idOrName) {
273
+ if (isInContainer) {
274
+ // Environment is already set in the container process
275
+ const vars = [];
276
+ if (process.env.DISPLAY)
277
+ vars.push(`export DISPLAY=${process.env.DISPLAY}`);
278
+ if (process.env.DBUS_SESSION_BUS_ADDRESS)
279
+ vars.push(`export DBUS_SESSION_BUS_ADDRESS="${process.env.DBUS_SESSION_BUS_ADDRESS}"`);
280
+ return vars.join(" && ");
281
+ }
282
+ const cached = envCache.get(idOrName);
283
+ if (cached)
284
+ return cached;
285
+ // Read env from agent process (PID is usually low, find it via /env endpoint or proc)
286
+ const bin = getDockerPath();
287
+ const output = execSync(`${bin} exec ${idOrName} bash -c "cat /proc/*/environ 2>/dev/null | tr '\\0' '\\n' | grep -E 'DISPLAY=|DBUS_SESSION_BUS_ADDRESS=' | sort -u"`, { timeout: 10_000, env: dockerEnv }).toString().trim();
288
+ const vars = [];
289
+ for (const line of output.split("\n")) {
290
+ if (line.startsWith("DISPLAY=") || line.startsWith("DBUS_SESSION_BUS_ADDRESS=")) {
291
+ vars.push(`export ${line}`);
292
+ }
293
+ }
294
+ const prefix = vars.join(" && ");
295
+ if (prefix)
296
+ envCache.set(idOrName, prefix);
297
+ return prefix;
298
+ }
299
+ /**
300
+ * Paste text into the currently focused window via clipboard.
301
+ * Uses xclip to set clipboard, then xdotool to simulate Ctrl+V.
302
+ * Reliable for apps like WeChat that don't support AT-SPI text input.
303
+ */
304
+ export function clipboardType(idOrName, text) {
305
+ const envPrefix = getContainerEnvPrefix(idOrName);
306
+ // Escape single quotes for shell
307
+ const escaped = text.replace(/'/g, "'\\''");
308
+ const cmd = `bash -c '${envPrefix} && echo -n '"'"'${escaped}'"'"' | xclip -selection clipboard && xdotool key ctrl+v'`;
309
+ if (isInContainer) {
310
+ execSync(cmd, { timeout: 10_000, env: process.env });
311
+ }
312
+ else {
313
+ const bin = getDockerPath();
314
+ execSync(`${bin} exec ${idOrName} ${cmd}`, { timeout: 10_000, env: dockerEnv });
315
+ }
316
+ return { ok: true };
317
+ }
318
+ /**
319
+ * Type text character-by-character via clipboard paste with random delays.
320
+ * Simulates human typing rhythm. Each character is pasted individually
321
+ * with a randomized delay (80–200ms) between keystrokes.
322
+ */
323
+ export function humanType(idOrName, text) {
324
+ const envPrefix = getContainerEnvPrefix(idOrName);
325
+ // Build a shell script that pastes one char at a time with random sleep
326
+ const chars = [...text]; // spread to handle CJK properly
327
+ const cmds = chars.map(ch => {
328
+ const escaped = ch.replace(/'/g, "'\\''");
329
+ // Random delay 80-200ms, expressed as 0.08-0.20
330
+ return `echo -n '${escaped}' | xclip -selection clipboard && xdotool key ctrl+v && sleep 0.$(shuf -i 8-20 -n 1)`;
331
+ });
332
+ // Execute in batches of 20 to avoid command-line length limits
333
+ const batchSize = 20;
334
+ for (let i = 0; i < cmds.length; i += batchSize) {
335
+ const batch = cmds.slice(i, i + batchSize).join(" && ");
336
+ const cmd = `bash -c '${envPrefix} && ${batch}'`;
337
+ if (isInContainer) {
338
+ execSync(cmd, { timeout: 60_000, env: process.env });
339
+ }
340
+ else {
341
+ const bin = getDockerPath();
342
+ execSync(`${bin} exec ${idOrName} ${cmd}`, { timeout: 60_000, env: dockerEnv });
343
+ }
344
+ }
345
+ return { ok: true };
346
+ }
347
+ /**
348
+ * Send key combination via xdotool (e.g. "Return", "ctrl+a", "BackSpace").
349
+ */
350
+ export function xdotoolKey(idOrName, keys) {
351
+ const envPrefix = getContainerEnvPrefix(idOrName);
352
+ const cmd = `bash -c '${envPrefix} && xdotool key ${keys}'`;
353
+ if (isInContainer) {
354
+ execSync(cmd, { timeout: 10_000, env: process.env });
355
+ }
356
+ else {
357
+ const bin = getDockerPath();
358
+ execSync(`${bin} exec ${idOrName} ${cmd}`, { timeout: 10_000, env: dockerEnv });
359
+ }
360
+ return { ok: true };
361
+ }
362
+ /**
363
+ * Read VNC_PASSWORD from a desktop container's env.
364
+ */
365
+ export function getVncPassword(containerId) {
366
+ if (isInContainer) {
367
+ return process.env.VNC_PASSWORD || process.env.OPENCLAW_BROWSER_NOVNC_PASSWORD || "";
368
+ }
369
+ try {
370
+ const output = docker(`inspect ${containerId} -f '{{range .Config.Env}}{{println .}}{{end}}'`);
371
+ for (const line of output.split("\n")) {
372
+ if (line.startsWith("VNC_PASSWORD=")) {
373
+ return line.slice("VNC_PASSWORD=".length).trim();
374
+ }
375
+ }
376
+ }
377
+ catch {
378
+ // ignore
379
+ }
380
+ return "";
381
+ }
382
+ //# sourceMappingURL=desktopContainer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"desktopContainer.js","sourceRoot":"","sources":["../../src/desktopContainer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Desktop control agent tool — exposes container desktop automation to OpenClaw agents.
3
+ *
4
+ * Single tool with `action` parameter that dispatches to AT-SPI / xdotool operations
5
+ * on Docker containers running Xvfb desktops.
6
+ */
7
+ import type { ChannelAgentTool } from "openclaw/plugin-sdk";
8
+ export declare function createDesktopTool(): ChannelAgentTool;
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Desktop control agent tool — exposes container desktop automation to OpenClaw agents.
3
+ *
4
+ * Single tool with `action` parameter that dispatches to AT-SPI / xdotool operations
5
+ * on Docker containers running Xvfb desktops.
6
+ */
7
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+ import { isInContainer, listContainers, resolveAgentPort, atspiScreenshot, atspiClick, atspiApps, humanType, xdotoolKey, } from "./desktopContainer.js";
10
+ const text = (t) => ({ content: [{ type: "text", text: t }] });
11
+ export function createDesktopTool() {
12
+ return {
13
+ label: "Desktop Control",
14
+ name: "desktop",
15
+ ownerOnly: true,
16
+ description: isInContainer
17
+ ? "Control the desktop (Xvfb). " +
18
+ "Actions: screenshot (capture screen), click (x,y coordinates), type (input text char-by-char), " +
19
+ "key (send key combo like Return/ctrl+a), apps (list running applications). " +
20
+ "No containerId needed — running inside the desktop container."
21
+ : "Control desktop containers (Docker with Xvfb). " +
22
+ "Actions: screenshot (capture screen), click (x,y coordinates), type (input text char-by-char), " +
23
+ "key (send key combo like Return/ctrl+a), list_containers (discover available containers), " +
24
+ "apps (list running applications). " +
25
+ "Use list_containers first to find containerId, then use other actions with that containerId.",
26
+ parameters: {
27
+ type: "object",
28
+ properties: {
29
+ action: {
30
+ type: "string",
31
+ enum: ["screenshot", "click", "type", "key", "list_containers", "apps"],
32
+ description: "The action to perform.",
33
+ },
34
+ containerId: {
35
+ type: "string",
36
+ description: "Container ID or name substring. Required for all actions except list_containers.",
37
+ },
38
+ x: { type: "number", description: "X coordinate for click action." },
39
+ y: { type: "number", description: "Y coordinate for click action." },
40
+ button: { type: "number", description: "Mouse button for click (1=left, 2=middle, 3=right). Default: 1." },
41
+ text: { type: "string", description: "Text to type for type action." },
42
+ keys: { type: "string", description: "Key combo for key action, e.g. 'Return', 'ctrl+a', 'BackSpace'." },
43
+ },
44
+ required: ["action"],
45
+ },
46
+ execute: async (_toolCallId, rawArgs) => {
47
+ const args = rawArgs;
48
+ // In-container mode: containerId is optional, default to "local"
49
+ const containerId = args.containerId || (isInContainer ? "local" : undefined);
50
+ try {
51
+ switch (args.action) {
52
+ case "list_containers": {
53
+ const containers = listContainers();
54
+ if (containers.length === 0) {
55
+ return text("No desktop containers found.");
56
+ }
57
+ const lines = containers.map((c) => `${c.id} | ${c.name} | ${c.status} | ${c.image}`);
58
+ return text("ID | Name | Status | Image\n" + lines.join("\n"));
59
+ }
60
+ case "screenshot": {
61
+ if (!containerId)
62
+ return text("Error: containerId is required.");
63
+ const agentPort = resolveAgentPort(containerId);
64
+ const base64 = atspiScreenshot(agentPort, { quality: 70 });
65
+ const filename = `desktop-screenshot-${Date.now()}.jpg`;
66
+ const filepath = path.join("/tmp", filename);
67
+ fs.writeFileSync(filepath, Buffer.from(base64, "base64"));
68
+ return text(`Screenshot saved to ${filepath}`);
69
+ }
70
+ case "click": {
71
+ if (!containerId)
72
+ return text("Error: containerId is required.");
73
+ if (args.x == null || args.y == null)
74
+ return text("Error: x and y coordinates are required.");
75
+ const agentPort = resolveAgentPort(containerId);
76
+ atspiClick(agentPort, args.x, args.y, args.button ?? 1);
77
+ return text(`Clicked (${args.x}, ${args.y})`);
78
+ }
79
+ case "type": {
80
+ if (!containerId)
81
+ return text("Error: containerId is required.");
82
+ if (!args.text)
83
+ return text("Error: text is required.");
84
+ humanType(containerId, args.text);
85
+ return text(`Typed ${args.text.length} characters.`);
86
+ }
87
+ case "key": {
88
+ if (!containerId)
89
+ return text("Error: containerId is required.");
90
+ if (!args.keys)
91
+ return text("Error: keys is required.");
92
+ xdotoolKey(containerId, args.keys);
93
+ return text(`Sent key: ${args.keys}`);
94
+ }
95
+ case "apps": {
96
+ if (!containerId)
97
+ return text("Error: containerId is required.");
98
+ const agentPort = resolveAgentPort(containerId);
99
+ const apps = atspiApps(agentPort);
100
+ return text(JSON.stringify(apps, null, 2));
101
+ }
102
+ default:
103
+ return text(`Error: unknown action "${args.action}". Use: screenshot, click, type, key, list_containers, apps.`);
104
+ }
105
+ }
106
+ catch (err) {
107
+ return text(`Error: ${err?.message ?? String(err)}`);
108
+ }
109
+ },
110
+ };
111
+ }
112
+ //# sourceMappingURL=desktopTool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"desktopTool.js","sourceRoot":"","sources":["../../src/desktopTool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EACL,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,SAAS,EACT,SAAS,EACT,UAAU,GACX,MAAM,uBAAuB,CAAC;AAE/B,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAEhF,MAAM,UAAU,iBAAiB;IAC/B,OAAO;QACL,KAAK,EAAE,iBAAiB;QACxB,IAAI,EAAE,SAAS;QACf,SAAS,EAAE,IAAI;QACf,WAAW,EAAE,aAAa;YACxB,CAAC,CAAC,8BAA8B;gBAC9B,iGAAiG;gBACjG,6EAA6E;gBAC7E,+DAA+D;YACjE,CAAC,CAAC,iDAAiD;gBACjD,iGAAiG;gBACjG,4FAA4F;gBAC5F,oCAAoC;gBACpC,8FAA8F;QAClG,UAAU,EAAE;YACV,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,MAAM,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,CAAC;oBACvE,WAAW,EAAE,wBAAwB;iBACtC;gBACD,WAAW,EAAE;oBACX,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,kFAAkF;iBAChG;gBACD,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,gCAAgC,EAAE;gBACpE,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,gCAAgC,EAAE;gBACpE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iEAAiE,EAAE;gBAC1G,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,+BAA+B,EAAE;gBACtE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iEAAiE,EAAE;aACzG;YACD,QAAQ,EAAE,CAAC,QAAQ,CAAC;SACwB;QAE9C,OAAO,EAAE,KAAK,EAAE,WAAmB,EAAE,OAAgB,EAAE,EAAE;YACvD,MAAM,IAAI,GAAG,OAQZ,CAAC;YAEF,iEAAiE;YACjE,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAE9E,IAAI,CAAC;gBACH,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;oBACpB,KAAK,iBAAiB,CAAC,CAAC,CAAC;wBACvB,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;wBACpC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;4BAC5B,OAAO,IAAI,CAAC,8BAA8B,CAAC,CAAC;wBAC9C,CAAC;wBACD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAC1B,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,KAAK,EAAE,CACxD,CAAC;wBACF,OAAO,IAAI,CAAC,8BAA8B,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;oBACjE,CAAC;oBAED,KAAK,YAAY,CAAC,CAAC,CAAC;wBAClB,IAAI,CAAC,WAAW;4BAAE,OAAO,IAAI,CAAC,iCAAiC,CAAC,CAAC;wBACjE,MAAM,SAAS,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;wBAChD,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;wBAC3D,MAAM,QAAQ,GAAG,sBAAsB,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC;wBACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;wBAC7C,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;wBAC1D,OAAO,IAAI,CAAC,uBAAuB,QAAQ,EAAE,CAAC,CAAC;oBACjD,CAAC;oBAED,KAAK,OAAO,CAAC,CAAC,CAAC;wBACb,IAAI,CAAC,WAAW;4BAAE,OAAO,IAAI,CAAC,iCAAiC,CAAC,CAAC;wBACjE,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI;4BAAE,OAAO,IAAI,CAAC,0CAA0C,CAAC,CAAC;wBAC9F,MAAM,SAAS,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;wBAChD,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;wBACxD,OAAO,IAAI,CAAC,YAAY,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;oBAChD,CAAC;oBAED,KAAK,MAAM,CAAC,CAAC,CAAC;wBACZ,IAAI,CAAC,WAAW;4BAAE,OAAO,IAAI,CAAC,iCAAiC,CAAC,CAAC;wBACjE,IAAI,CAAC,IAAI,CAAC,IAAI;4BAAE,OAAO,IAAI,CAAC,0BAA0B,CAAC,CAAC;wBACxD,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;wBAClC,OAAO,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,MAAM,cAAc,CAAC,CAAC;oBACvD,CAAC;oBAED,KAAK,KAAK,CAAC,CAAC,CAAC;wBACX,IAAI,CAAC,WAAW;4BAAE,OAAO,IAAI,CAAC,iCAAiC,CAAC,CAAC;wBACjE,IAAI,CAAC,IAAI,CAAC,IAAI;4BAAE,OAAO,IAAI,CAAC,0BAA0B,CAAC,CAAC;wBACxD,UAAU,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;wBACnC,OAAO,IAAI,CAAC,aAAa,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;oBACxC,CAAC;oBAED,KAAK,MAAM,CAAC,CAAC,CAAC;wBACZ,IAAI,CAAC,WAAW;4BAAE,OAAO,IAAI,CAAC,iCAAiC,CAAC,CAAC;wBACjE,MAAM,SAAS,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;wBAChD,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;wBAClC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;oBAC7C,CAAC;oBAED;wBACE,OAAO,IAAI,CAAC,0BAA0B,IAAI,CAAC,MAAM,8DAA8D,CAAC,CAAC;gBACrH,CAAC;YACH,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAClB,OAAO,IAAI,CAAC,UAAU,GAAG,EAAE,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}