podwatch 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.
- package/LICENSE +28 -0
- package/README.md +92 -0
- package/bin/podwatch.js +10 -0
- package/dist/classifier.d.ts +22 -0
- package/dist/classifier.d.ts.map +1 -0
- package/dist/classifier.js +157 -0
- package/dist/classifier.js.map +1 -0
- package/dist/hooks/cost.d.ts +26 -0
- package/dist/hooks/cost.d.ts.map +1 -0
- package/dist/hooks/cost.js +107 -0
- package/dist/hooks/cost.js.map +1 -0
- package/dist/hooks/lifecycle.d.ts +16 -0
- package/dist/hooks/lifecycle.d.ts.map +1 -0
- package/dist/hooks/lifecycle.js +273 -0
- package/dist/hooks/lifecycle.js.map +1 -0
- package/dist/hooks/security.d.ts +19 -0
- package/dist/hooks/security.d.ts.map +1 -0
- package/dist/hooks/security.js +128 -0
- package/dist/hooks/security.js.map +1 -0
- package/dist/hooks/sessions.d.ts +10 -0
- package/dist/hooks/sessions.d.ts.map +1 -0
- package/dist/hooks/sessions.js +53 -0
- package/dist/hooks/sessions.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +120 -0
- package/dist/index.js.map +1 -0
- package/dist/redact.d.ts +35 -0
- package/dist/redact.d.ts.map +1 -0
- package/dist/redact.js +372 -0
- package/dist/redact.js.map +1 -0
- package/dist/scanner.d.ts +27 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +117 -0
- package/dist/scanner.js.map +1 -0
- package/dist/transmitter.d.ts +58 -0
- package/dist/transmitter.d.ts.map +1 -0
- package/dist/transmitter.js +654 -0
- package/dist/transmitter.js.map +1 -0
- package/dist/types.d.ts +116 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/updater.d.ts +168 -0
- package/dist/updater.d.ts.map +1 -0
- package/dist/updater.js +579 -0
- package/dist/updater.js.map +1 -0
- package/lib/installer.js +599 -0
- package/openclaw.plugin.json +59 -0
- package/package.json +56 -0
- package/skills/podwatch/SKILL.md +112 -0
package/dist/updater.js
ADDED
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Auto-updater for the Podwatch plugin.
|
|
4
|
+
*
|
|
5
|
+
* On plugin startup (called from register()), schedules a non-blocking update
|
|
6
|
+
* check after a 30-second delay. If a new version is available on npm (or the
|
|
7
|
+
* Podwatch dashboard fallback), it downloads via `npm pack`, extracts to the
|
|
8
|
+
* extensions directory, writes a restart sentinel, and triggers a gateway
|
|
9
|
+
* restart via the OS service manager (systemd / launchctl).
|
|
10
|
+
*
|
|
11
|
+
* Safety:
|
|
12
|
+
* - 30s startup delay (don't slow boot)
|
|
13
|
+
* - 24-hour cooldown between checks (cached in a local file)
|
|
14
|
+
* - 5s timeout on all HTTP requests
|
|
15
|
+
* - 120s timeout on npm pack command
|
|
16
|
+
* - All errors caught — never bricks the running plugin
|
|
17
|
+
* - Logs all activity for debugging
|
|
18
|
+
*/
|
|
19
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
20
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.AUTO_UPDATE_CACHE_FILE = void 0;
|
|
24
|
+
exports.resolveStateDir = resolveStateDir;
|
|
25
|
+
exports.resolveGatewaySystemdServiceName = resolveGatewaySystemdServiceName;
|
|
26
|
+
exports.resolveGatewayLaunchAgentLabel = resolveGatewayLaunchAgentLabel;
|
|
27
|
+
exports.normalizeSystemdUnit = normalizeSystemdUnit;
|
|
28
|
+
exports.compareVersions = compareVersions;
|
|
29
|
+
exports.shouldCheckForUpdate = shouldCheckForUpdate;
|
|
30
|
+
exports.writeCacheTimestamp = writeCacheTimestamp;
|
|
31
|
+
exports.checkForUpdate = checkForUpdate;
|
|
32
|
+
exports.writeRestartSentinel = writeRestartSentinel;
|
|
33
|
+
exports.verifyTarballIntegrity = verifyTarballIntegrity;
|
|
34
|
+
exports.downloadTarball = downloadTarball;
|
|
35
|
+
exports.installFromTarball = installFromTarball;
|
|
36
|
+
exports.executeUpdate = executeUpdate;
|
|
37
|
+
exports.triggerGatewayRestart = triggerGatewayRestart;
|
|
38
|
+
exports.scheduleUpdateCheck = scheduleUpdateCheck;
|
|
39
|
+
exports.runUpdateCheck = runUpdateCheck;
|
|
40
|
+
const node_child_process_1 = require("node:child_process");
|
|
41
|
+
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
42
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
43
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
44
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Constants
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
const NPM_REGISTRY_URL = "https://registry.npmjs.org/podwatch/latest";
|
|
49
|
+
const CHECK_TIMEOUT_MS = 5_000;
|
|
50
|
+
const NPM_PACK_TIMEOUT_MS = 120_000;
|
|
51
|
+
const SPAWN_TIMEOUT_MS = 15_000;
|
|
52
|
+
const STARTUP_DELAY_MS = 30_000;
|
|
53
|
+
const COOLDOWN_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
54
|
+
const CACHE_DIR = node_path_1.default.join(process.env.HOME ?? process.env.USERPROFILE ?? "/tmp", ".openclaw", "extensions", "podwatch");
|
|
55
|
+
exports.AUTO_UPDATE_CACHE_FILE = node_path_1.default.join(CACHE_DIR, ".last-update-check");
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// State dir resolution (mirrors OpenClaw's resolveStateDir)
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
/**
|
|
60
|
+
* Resolve the OpenClaw state directory.
|
|
61
|
+
* Checks OPENCLAW_STATE_DIR / CLAWDBOT_STATE_DIR env, then defaults to ~/.openclaw.
|
|
62
|
+
*/
|
|
63
|
+
function resolveStateDir() {
|
|
64
|
+
const override = process.env.OPENCLAW_STATE_DIR?.trim() || process.env.CLAWDBOT_STATE_DIR?.trim();
|
|
65
|
+
if (override)
|
|
66
|
+
return override;
|
|
67
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? node_os_1.default.homedir();
|
|
68
|
+
return node_path_1.default.join(home, ".openclaw");
|
|
69
|
+
}
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// Service name resolution (mirrors OpenClaw's constants)
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
/**
|
|
74
|
+
* Normalize a gateway profile string. Returns null for empty/default.
|
|
75
|
+
*/
|
|
76
|
+
function normalizeGatewayProfile(profile) {
|
|
77
|
+
const trimmed = profile?.trim();
|
|
78
|
+
if (!trimmed || trimmed.toLowerCase() === "default")
|
|
79
|
+
return null;
|
|
80
|
+
return trimmed;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Resolve the systemd service name for the gateway.
|
|
84
|
+
*/
|
|
85
|
+
function resolveGatewaySystemdServiceName(profile) {
|
|
86
|
+
const normalized = normalizeGatewayProfile(profile);
|
|
87
|
+
const suffix = normalized ? `-${normalized}` : "";
|
|
88
|
+
if (!suffix)
|
|
89
|
+
return "openclaw-gateway";
|
|
90
|
+
return `openclaw-gateway${suffix}`;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Resolve the launchd label for the gateway.
|
|
94
|
+
*/
|
|
95
|
+
function resolveGatewayLaunchAgentLabel(profile) {
|
|
96
|
+
const normalized = normalizeGatewayProfile(profile);
|
|
97
|
+
if (!normalized)
|
|
98
|
+
return "ai.openclaw.gateway";
|
|
99
|
+
return `ai.openclaw.${normalized}`;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Normalize a systemd unit name. Appends .service if missing.
|
|
103
|
+
*/
|
|
104
|
+
function normalizeSystemdUnit(raw, profile) {
|
|
105
|
+
const unit = raw?.trim();
|
|
106
|
+
if (!unit)
|
|
107
|
+
return `${resolveGatewaySystemdServiceName(profile)}.service`;
|
|
108
|
+
return unit.endsWith(".service") ? unit : `${unit}.service`;
|
|
109
|
+
}
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
// Version comparison
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
/**
|
|
114
|
+
* Compare two semver-like version strings.
|
|
115
|
+
* Returns positive if remote > local, negative if local > remote, 0 if equal.
|
|
116
|
+
*/
|
|
117
|
+
function compareVersions(local, remote) {
|
|
118
|
+
const parse = (v) => v
|
|
119
|
+
.replace(/^v/, "")
|
|
120
|
+
.split(".")
|
|
121
|
+
.map((n) => parseInt(n, 10) || 0);
|
|
122
|
+
const l = parse(local);
|
|
123
|
+
const r = parse(remote);
|
|
124
|
+
const len = Math.max(l.length, r.length);
|
|
125
|
+
for (let i = 0; i < len; i++) {
|
|
126
|
+
const lv = l[i] ?? 0;
|
|
127
|
+
const rv = r[i] ?? 0;
|
|
128
|
+
if (rv !== lv)
|
|
129
|
+
return rv - lv;
|
|
130
|
+
}
|
|
131
|
+
return 0;
|
|
132
|
+
}
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
// Cache (24-hour cooldown)
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
/**
|
|
137
|
+
* Check if we should perform a version check (respects 24h cooldown).
|
|
138
|
+
*/
|
|
139
|
+
function shouldCheckForUpdate() {
|
|
140
|
+
try {
|
|
141
|
+
if (!node_fs_1.default.existsSync(exports.AUTO_UPDATE_CACHE_FILE))
|
|
142
|
+
return true;
|
|
143
|
+
const raw = node_fs_1.default.readFileSync(exports.AUTO_UPDATE_CACHE_FILE, "utf-8");
|
|
144
|
+
const data = JSON.parse(raw);
|
|
145
|
+
if (typeof data.lastCheckTs !== "number")
|
|
146
|
+
return true;
|
|
147
|
+
return Date.now() - data.lastCheckTs > COOLDOWN_MS;
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return true; // On any error, allow the check
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Persist the current timestamp as last-check time.
|
|
155
|
+
*/
|
|
156
|
+
function writeCacheTimestamp() {
|
|
157
|
+
try {
|
|
158
|
+
node_fs_1.default.mkdirSync(CACHE_DIR, { recursive: true });
|
|
159
|
+
node_fs_1.default.writeFileSync(exports.AUTO_UPDATE_CACHE_FILE, JSON.stringify({ lastCheckTs: Date.now() }));
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
console.warn("[podwatch/updater] Failed to write cache:", err);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Check for a newer version. Tries npm registry first, then dashboard API.
|
|
167
|
+
* Returns null if both checks fail.
|
|
168
|
+
*/
|
|
169
|
+
async function checkForUpdate(currentVersion, endpoint) {
|
|
170
|
+
// 1. Try npm registry
|
|
171
|
+
try {
|
|
172
|
+
const resp = await fetch(NPM_REGISTRY_URL, {
|
|
173
|
+
signal: AbortSignal.timeout(CHECK_TIMEOUT_MS),
|
|
174
|
+
});
|
|
175
|
+
if (resp.ok) {
|
|
176
|
+
const data = (await resp.json());
|
|
177
|
+
if (typeof data.version === "string" && data.version) {
|
|
178
|
+
const cmp = compareVersions(currentVersion, data.version);
|
|
179
|
+
return {
|
|
180
|
+
available: cmp > 0,
|
|
181
|
+
remoteVersion: data.version,
|
|
182
|
+
source: "npm",
|
|
183
|
+
sha256: typeof data.sha256 === "string" ? data.sha256 : undefined,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
// Fall through to dashboard
|
|
190
|
+
}
|
|
191
|
+
// 2. Fallback: dashboard API
|
|
192
|
+
try {
|
|
193
|
+
const dashboardUrl = `${endpoint}/plugin-version`;
|
|
194
|
+
const resp = await fetch(dashboardUrl, {
|
|
195
|
+
signal: AbortSignal.timeout(CHECK_TIMEOUT_MS),
|
|
196
|
+
});
|
|
197
|
+
if (resp.ok) {
|
|
198
|
+
const data = (await resp.json());
|
|
199
|
+
if (typeof data.version === "string" && data.version) {
|
|
200
|
+
const cmp = compareVersions(currentVersion, data.version);
|
|
201
|
+
return {
|
|
202
|
+
available: cmp > 0,
|
|
203
|
+
remoteVersion: data.version,
|
|
204
|
+
source: "dashboard",
|
|
205
|
+
sha256: typeof data.sha256 === "string" ? data.sha256 : undefined,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
// Both failed
|
|
212
|
+
}
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Write a restart sentinel file so the gateway knows why it was restarted.
|
|
217
|
+
* Mirrors OpenClaw's writeRestartSentinel from src/infra/restart-sentinel.ts.
|
|
218
|
+
*/
|
|
219
|
+
function writeRestartSentinel(version) {
|
|
220
|
+
const stateDir = resolveStateDir();
|
|
221
|
+
const sentinelPath = node_path_1.default.join(stateDir, "state", "restart-sentinel.json");
|
|
222
|
+
const data = {
|
|
223
|
+
version: 1,
|
|
224
|
+
payload: {
|
|
225
|
+
kind: "update",
|
|
226
|
+
status: "ok",
|
|
227
|
+
ts: Date.now(),
|
|
228
|
+
message: `Podwatch plugin updated to v${version}`,
|
|
229
|
+
doctorHint: "Run: openclaw doctor --non-interactive",
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
try {
|
|
233
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(sentinelPath), { recursive: true });
|
|
234
|
+
node_fs_1.default.writeFileSync(sentinelPath, `${JSON.stringify(data, null, 2)}\n`, "utf-8");
|
|
235
|
+
return sentinelPath;
|
|
236
|
+
}
|
|
237
|
+
catch (err) {
|
|
238
|
+
console.warn("[podwatch/updater] Failed to write restart sentinel:", err);
|
|
239
|
+
return sentinelPath;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Verify the SHA-256 hash of a tarball against an expected hash.
|
|
244
|
+
*/
|
|
245
|
+
function verifyTarballIntegrity(tarballPath, expectedHash) {
|
|
246
|
+
try {
|
|
247
|
+
const content = node_fs_1.default.readFileSync(tarballPath);
|
|
248
|
+
const actualHash = node_crypto_1.default.createHash("sha256").update(content).digest("hex");
|
|
249
|
+
return {
|
|
250
|
+
valid: actualHash === expectedHash,
|
|
251
|
+
actualHash,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
catch (err) {
|
|
255
|
+
return {
|
|
256
|
+
valid: false,
|
|
257
|
+
error: err instanceof Error ? err.message : String(err),
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Download the latest podwatch tarball via npm pack.
|
|
263
|
+
* Returns the tarball path on success for integrity verification.
|
|
264
|
+
*/
|
|
265
|
+
function downloadTarball() {
|
|
266
|
+
let tmpDir = null;
|
|
267
|
+
try {
|
|
268
|
+
// 1. Create temp dir for npm pack
|
|
269
|
+
tmpDir = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), "podwatch-update-"));
|
|
270
|
+
// 2. npm pack podwatch (downloads latest from registry)
|
|
271
|
+
const packResult = (0, node_child_process_1.spawnSync)("npm", ["pack", "podwatch", "--pack-destination", tmpDir], {
|
|
272
|
+
encoding: "utf8",
|
|
273
|
+
timeout: NPM_PACK_TIMEOUT_MS,
|
|
274
|
+
cwd: tmpDir,
|
|
275
|
+
});
|
|
276
|
+
if (packResult.error || packResult.status !== 0) {
|
|
277
|
+
return {
|
|
278
|
+
success: false,
|
|
279
|
+
stdout: packResult.stdout,
|
|
280
|
+
stderr: packResult.stderr,
|
|
281
|
+
error: packResult.error?.message ?? `npm pack exited with status ${packResult.status}`,
|
|
282
|
+
tmpDir,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
// Find the tarball filename from stdout (npm pack prints the filename)
|
|
286
|
+
const tarballName = packResult.stdout.trim().split("\n").pop()?.trim();
|
|
287
|
+
if (!tarballName) {
|
|
288
|
+
return {
|
|
289
|
+
success: false,
|
|
290
|
+
stdout: packResult.stdout,
|
|
291
|
+
error: "npm pack did not output a tarball filename",
|
|
292
|
+
tmpDir,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
const tarballPath = node_path_1.default.join(tmpDir, tarballName);
|
|
296
|
+
return {
|
|
297
|
+
success: true,
|
|
298
|
+
stdout: `Downloaded ${tarballName}`,
|
|
299
|
+
tarballPath,
|
|
300
|
+
tmpDir,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
catch (err) {
|
|
304
|
+
return {
|
|
305
|
+
success: false,
|
|
306
|
+
error: err instanceof Error ? err.message : String(err),
|
|
307
|
+
tmpDir: tmpDir ?? undefined,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Install from a previously downloaded tarball by extracting to the extensions dir.
|
|
313
|
+
*/
|
|
314
|
+
function installFromTarball(tarballPath) {
|
|
315
|
+
const extensionsDir = node_path_1.default.join(process.env.HOME ?? process.env.USERPROFILE ?? "/tmp", ".openclaw", "extensions", "podwatch");
|
|
316
|
+
try {
|
|
317
|
+
// 1. Clean old dist before extracting
|
|
318
|
+
const distDir = node_path_1.default.join(extensionsDir, "dist");
|
|
319
|
+
if (node_fs_1.default.existsSync(distDir)) {
|
|
320
|
+
node_fs_1.default.rmSync(distDir, { recursive: true, force: true });
|
|
321
|
+
}
|
|
322
|
+
// 2. Ensure extensions dir exists
|
|
323
|
+
node_fs_1.default.mkdirSync(extensionsDir, { recursive: true });
|
|
324
|
+
// 3. Extract tarball — npm pack creates tarballs with a "package/" prefix
|
|
325
|
+
const extractResult = (0, node_child_process_1.spawnSync)("tar", ["xzf", tarballPath, "--strip-components=1", "-C", extensionsDir], {
|
|
326
|
+
encoding: "utf8",
|
|
327
|
+
timeout: 30_000,
|
|
328
|
+
});
|
|
329
|
+
if (extractResult.error || extractResult.status !== 0) {
|
|
330
|
+
return {
|
|
331
|
+
success: false,
|
|
332
|
+
stdout: extractResult.stdout,
|
|
333
|
+
stderr: extractResult.stderr,
|
|
334
|
+
error: extractResult.error?.message ?? `tar extract exited with status ${extractResult.status}`,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
const tarballName = node_path_1.default.basename(tarballPath);
|
|
338
|
+
return {
|
|
339
|
+
success: true,
|
|
340
|
+
stdout: `Updated podwatch from ${tarballName}`,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
catch (err) {
|
|
344
|
+
return {
|
|
345
|
+
success: false,
|
|
346
|
+
error: err instanceof Error ? err.message : String(err),
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Download and install the latest podwatch plugin via npm pack + extract.
|
|
352
|
+
* Legacy single-step function — delegates to downloadTarball + installFromTarball.
|
|
353
|
+
*
|
|
354
|
+
* Steps:
|
|
355
|
+
* 1. `npm pack podwatch` in a temp dir to get the tarball
|
|
356
|
+
* 2. Clean old dist in the extensions directory
|
|
357
|
+
* 3. Extract tarball contents to ~/.openclaw/extensions/podwatch/
|
|
358
|
+
*/
|
|
359
|
+
function executeUpdate() {
|
|
360
|
+
const download = downloadTarball();
|
|
361
|
+
try {
|
|
362
|
+
if (!download.success || !download.tarballPath) {
|
|
363
|
+
return {
|
|
364
|
+
success: false,
|
|
365
|
+
stdout: download.stdout,
|
|
366
|
+
stderr: download.stderr,
|
|
367
|
+
error: download.error ?? "Download failed",
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
return installFromTarball(download.tarballPath);
|
|
371
|
+
}
|
|
372
|
+
finally {
|
|
373
|
+
// Cleanup temp dir
|
|
374
|
+
if (download.tmpDir) {
|
|
375
|
+
try {
|
|
376
|
+
node_fs_1.default.rmSync(download.tmpDir, { recursive: true, force: true });
|
|
377
|
+
}
|
|
378
|
+
catch {
|
|
379
|
+
// Best-effort cleanup
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Trigger a gateway restart using the OS service manager directly.
|
|
386
|
+
* Mirrors OpenClaw's triggerOpenClawRestart logic.
|
|
387
|
+
*
|
|
388
|
+
* Linux: systemctl --user restart <unit> (user first, then system fallback)
|
|
389
|
+
* macOS: launchctl kickstart -k gui/<uid>/<label>
|
|
390
|
+
* Fallback: log a manual restart message
|
|
391
|
+
*/
|
|
392
|
+
function triggerGatewayRestart(logger) {
|
|
393
|
+
const tried = [];
|
|
394
|
+
if (process.platform === "linux") {
|
|
395
|
+
const unit = normalizeSystemdUnit(process.env.OPENCLAW_SYSTEMD_UNIT, process.env.OPENCLAW_PROFILE);
|
|
396
|
+
// Try user-level systemctl first
|
|
397
|
+
const userArgs = ["--user", "restart", unit];
|
|
398
|
+
tried.push(`systemctl ${userArgs.join(" ")}`);
|
|
399
|
+
const userRestart = (0, node_child_process_1.spawnSync)("systemctl", userArgs, {
|
|
400
|
+
encoding: "utf8",
|
|
401
|
+
timeout: SPAWN_TIMEOUT_MS,
|
|
402
|
+
});
|
|
403
|
+
if (!userRestart.error && userRestart.status === 0) {
|
|
404
|
+
logger.info("[podwatch/updater] Gateway restarted via systemctl --user.");
|
|
405
|
+
return { ok: true, method: "systemd", tried };
|
|
406
|
+
}
|
|
407
|
+
// Fall back to system-level systemctl
|
|
408
|
+
const systemArgs = ["restart", unit];
|
|
409
|
+
tried.push(`systemctl ${systemArgs.join(" ")}`);
|
|
410
|
+
const systemRestart = (0, node_child_process_1.spawnSync)("systemctl", systemArgs, {
|
|
411
|
+
encoding: "utf8",
|
|
412
|
+
timeout: SPAWN_TIMEOUT_MS,
|
|
413
|
+
});
|
|
414
|
+
if (!systemRestart.error && systemRestart.status === 0) {
|
|
415
|
+
logger.info("[podwatch/updater] Gateway restarted via systemctl (system).");
|
|
416
|
+
return { ok: true, method: "systemd", tried };
|
|
417
|
+
}
|
|
418
|
+
// Both failed
|
|
419
|
+
const detail = [
|
|
420
|
+
`user: ${userRestart.error?.message ?? `exit ${userRestart.status}`}`,
|
|
421
|
+
`system: ${systemRestart.error?.message ?? `exit ${systemRestart.status}`}`,
|
|
422
|
+
].join("; ");
|
|
423
|
+
logger.error(`[podwatch/updater] systemctl restart failed: ${detail}. Please restart the gateway manually.`);
|
|
424
|
+
return { ok: false, method: "systemd", detail, tried };
|
|
425
|
+
}
|
|
426
|
+
if (process.platform === "darwin") {
|
|
427
|
+
const label = process.env.OPENCLAW_LAUNCHD_LABEL ||
|
|
428
|
+
resolveGatewayLaunchAgentLabel(process.env.OPENCLAW_PROFILE);
|
|
429
|
+
const uid = typeof process.getuid === "function" ? process.getuid() : undefined;
|
|
430
|
+
const target = uid !== undefined ? `gui/${uid}/${label}` : label;
|
|
431
|
+
const args = ["kickstart", "-k", target];
|
|
432
|
+
tried.push(`launchctl ${args.join(" ")}`);
|
|
433
|
+
const res = (0, node_child_process_1.spawnSync)("launchctl", args, {
|
|
434
|
+
encoding: "utf8",
|
|
435
|
+
timeout: SPAWN_TIMEOUT_MS,
|
|
436
|
+
});
|
|
437
|
+
if (!res.error && res.status === 0) {
|
|
438
|
+
logger.info("[podwatch/updater] Gateway restarted via launchctl.");
|
|
439
|
+
return { ok: true, method: "launchctl", tried };
|
|
440
|
+
}
|
|
441
|
+
const detail = res.error?.message ?? `exit ${res.status}`;
|
|
442
|
+
logger.error(`[podwatch/updater] launchctl restart failed: ${detail}. Please restart the gateway manually.`);
|
|
443
|
+
return { ok: false, method: "launchctl", detail, tried };
|
|
444
|
+
}
|
|
445
|
+
// Unsupported platform
|
|
446
|
+
logger.warn(`[podwatch/updater] Unsupported platform "${process.platform}" for auto-restart. Please restart the gateway manually.`);
|
|
447
|
+
return {
|
|
448
|
+
ok: false,
|
|
449
|
+
method: "unsupported",
|
|
450
|
+
detail: `unsupported platform: ${process.platform}`,
|
|
451
|
+
tried,
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
// ---------------------------------------------------------------------------
|
|
455
|
+
// Main entry point (called from register())
|
|
456
|
+
// ---------------------------------------------------------------------------
|
|
457
|
+
/**
|
|
458
|
+
* Schedule a non-blocking update check 30s after startup.
|
|
459
|
+
* Safe to call synchronously — it sets a timer and returns immediately.
|
|
460
|
+
*
|
|
461
|
+
* Auto-update is opt-in: only runs if options.autoUpdate is explicitly true.
|
|
462
|
+
*
|
|
463
|
+
* @param currentVersion The plugin's current version from package.json
|
|
464
|
+
* @param endpoint The Podwatch API endpoint (for dashboard fallback)
|
|
465
|
+
* @param logger The plugin logger (api.logger)
|
|
466
|
+
* @param options Update options (autoUpdate, etc.)
|
|
467
|
+
*/
|
|
468
|
+
function scheduleUpdateCheck(currentVersion, endpoint, logger, options = {}) {
|
|
469
|
+
const timer = setTimeout(() => {
|
|
470
|
+
void runUpdateCheck(currentVersion, endpoint, logger, options);
|
|
471
|
+
}, STARTUP_DELAY_MS);
|
|
472
|
+
// Don't hold the process open for this timer
|
|
473
|
+
if (timer && typeof timer === "object" && "unref" in timer) {
|
|
474
|
+
timer.unref();
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Internal: perform the actual update check + install + restart.
|
|
479
|
+
*
|
|
480
|
+
* Flow:
|
|
481
|
+
* 1. Check autoUpdate opt-in (default false)
|
|
482
|
+
* 2. Respect 24h cooldown
|
|
483
|
+
* 3. Check for newer version (npm → dashboard fallback)
|
|
484
|
+
* 4. Require integrity hash from server (skip if missing)
|
|
485
|
+
* 5. Download tarball via npm pack
|
|
486
|
+
* 6. Verify tarball SHA-256 against server hash
|
|
487
|
+
* 7. Extract and install
|
|
488
|
+
* 8. Write restart sentinel + trigger gateway restart
|
|
489
|
+
*/
|
|
490
|
+
async function runUpdateCheck(currentVersion, endpoint, logger, options = {}) {
|
|
491
|
+
try {
|
|
492
|
+
// 1. Check opt-in — auto-update must be explicitly enabled
|
|
493
|
+
if (options.autoUpdate !== true) {
|
|
494
|
+
logger.info("[podwatch/updater] Auto-update is disabled. Set autoUpdate: true in plugin config to enable.");
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
// 2. Respect 24h cooldown
|
|
498
|
+
if (!shouldCheckForUpdate()) {
|
|
499
|
+
console.log("[podwatch/updater] Skipping check — within 24h cooldown.");
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
logger.info("[podwatch/updater] Checking for updates...");
|
|
503
|
+
const result = await checkForUpdate(currentVersion, endpoint);
|
|
504
|
+
// Always write cache timestamp after a check attempt (even if no update)
|
|
505
|
+
writeCacheTimestamp();
|
|
506
|
+
if (!result) {
|
|
507
|
+
logger.warn("[podwatch/updater] Could not determine latest version (both sources failed).");
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
if (!result.available) {
|
|
511
|
+
logger.info(`[podwatch/updater] Up to date (v${currentVersion}, latest: v${result.remoteVersion} via ${result.source}).`);
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
// 3. Require integrity hash from server
|
|
515
|
+
if (!result.sha256) {
|
|
516
|
+
logger.warn(`[podwatch/updater] No integrity hash available for v${result.remoteVersion} (via ${result.source}). ` +
|
|
517
|
+
"Skipping update for security. The server must provide a sha256 hash.");
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
// New version available with integrity hash!
|
|
521
|
+
logger.info(`[podwatch/updater] Update available: v${currentVersion} → v${result.remoteVersion} (via ${result.source}). Downloading...`);
|
|
522
|
+
// 4. Download tarball
|
|
523
|
+
const download = downloadTarball();
|
|
524
|
+
if (!download.success || !download.tarballPath) {
|
|
525
|
+
logger.error(`[podwatch/updater] Update failed: ${download.error}. Continuing with current version.`);
|
|
526
|
+
if (download.stderr) {
|
|
527
|
+
console.error("[podwatch/updater] stderr:", download.stderr);
|
|
528
|
+
}
|
|
529
|
+
// Cleanup temp dir
|
|
530
|
+
if (download.tmpDir) {
|
|
531
|
+
try {
|
|
532
|
+
node_fs_1.default.rmSync(download.tmpDir, { recursive: true, force: true });
|
|
533
|
+
}
|
|
534
|
+
catch { /* best-effort */ }
|
|
535
|
+
}
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
try {
|
|
539
|
+
// 5. Verify tarball integrity
|
|
540
|
+
const integrity = verifyTarballIntegrity(download.tarballPath, result.sha256);
|
|
541
|
+
logger.info(`[podwatch/updater] Package sha256: ${integrity.actualHash ?? "unknown"}`);
|
|
542
|
+
if (!integrity.valid) {
|
|
543
|
+
logger.error(`[podwatch/updater] Tarball integrity check failed! ` +
|
|
544
|
+
`Expected: ${result.sha256}, Got: ${integrity.actualHash ?? integrity.error}. ` +
|
|
545
|
+
"Update aborted — possible supply chain attack.");
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
logger.info(`[podwatch/updater] Integrity verified (sha256: ${integrity.actualHash}). Installing v${result.remoteVersion}...`);
|
|
549
|
+
// 6. Extract and install
|
|
550
|
+
const installResult = installFromTarball(download.tarballPath);
|
|
551
|
+
if (!installResult.success) {
|
|
552
|
+
logger.error(`[podwatch/updater] Update failed: ${installResult.error}. Continuing with current version.`);
|
|
553
|
+
if (installResult.stderr) {
|
|
554
|
+
console.error("[podwatch/updater] stderr:", installResult.stderr);
|
|
555
|
+
}
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
logger.info(`[podwatch/updater] Update installed successfully (v${currentVersion} → v${result.remoteVersion}). Writing sentinel and triggering restart...`);
|
|
559
|
+
// 7. Write restart sentinel so the gateway knows why it restarted
|
|
560
|
+
writeRestartSentinel(result.remoteVersion);
|
|
561
|
+
// 8. Trigger restart via OS service manager
|
|
562
|
+
triggerGatewayRestart(logger);
|
|
563
|
+
}
|
|
564
|
+
finally {
|
|
565
|
+
// Cleanup temp dir
|
|
566
|
+
if (download.tmpDir) {
|
|
567
|
+
try {
|
|
568
|
+
node_fs_1.default.rmSync(download.tmpDir, { recursive: true, force: true });
|
|
569
|
+
}
|
|
570
|
+
catch { /* best-effort */ }
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
catch (err) {
|
|
575
|
+
// Catch-all: never let the updater crash the plugin
|
|
576
|
+
console.error("[podwatch/updater] Unexpected error:", err);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
//# sourceMappingURL=updater.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updater.js","sourceRoot":"","sources":["../src/updater.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;;;;;AAoCH,0CAKC;AAkBD,4EAKC;AAKD,wEAIC;AAKD,oDAIC;AAUD,0CAiBC;AASD,oDAYC;AAKD,kDAUC;AAkBD,wCAgDC;AAkBD,oDAsBC;AAeD,wDAcC;AAmBD,0CAkDC;AAKD,gDAgDC;AAWD,sCAuBC;AAqBD,sDAsFC;AA0BD,kDAcC;AAeD,wCA0HC;AA9sBD,2DAAyD;AACzD,8DAAiC;AACjC,sDAAyB;AACzB,0DAA6B;AAC7B,sDAAyB;AAEzB,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,MAAM,gBAAgB,GAAG,4CAA4C,CAAC;AACtE,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAC/B,MAAM,mBAAmB,GAAG,OAAO,CAAC;AACpC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAChC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAChC,MAAM,WAAW,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW;AAEpD,MAAM,SAAS,GAAG,mBAAI,CAAC,IAAI,CACzB,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,MAAM,EACrD,WAAW,EACX,YAAY,EACZ,UAAU,CACX,CAAC;AAEW,QAAA,sBAAsB,GAAG,mBAAI,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;AAEjF,8EAA8E;AAC9E,4DAA4D;AAC5D,8EAA8E;AAE9E;;;GAGG;AACH,SAAgB,eAAe;IAC7B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,CAAC;IAClG,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,iBAAE,CAAC,OAAO,EAAE,CAAC;IACzE,OAAO,mBAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;AACtC,CAAC;AAED,8EAA8E;AAC9E,yDAAyD;AACzD,8EAA8E;AAE9E;;GAEG;AACH,SAAS,uBAAuB,CAAC,OAA2B;IAC1D,MAAM,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,CAAC;IAChC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,WAAW,EAAE,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACjE,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAgB,gCAAgC,CAAC,OAA2B;IAC1E,MAAM,UAAU,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAClD,IAAI,CAAC,MAAM;QAAE,OAAO,kBAAkB,CAAC;IACvC,OAAO,mBAAmB,MAAM,EAAE,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,SAAgB,8BAA8B,CAAC,OAA2B;IACxE,MAAM,UAAU,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACpD,IAAI,CAAC,UAAU;QAAE,OAAO,qBAAqB,CAAC;IAC9C,OAAO,eAAe,UAAU,EAAE,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,SAAgB,oBAAoB,CAAC,GAAuB,EAAE,OAA2B;IACvF,MAAM,IAAI,GAAG,GAAG,EAAE,IAAI,EAAE,CAAC;IACzB,IAAI,CAAC,IAAI;QAAE,OAAO,GAAG,gCAAgC,CAAC,OAAO,CAAC,UAAU,CAAC;IACzE,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,UAAU,CAAC;AAC9D,CAAC;AAED,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E;;;GAGG;AACH,SAAgB,eAAe,CAAC,KAAa,EAAE,MAAc;IAC3D,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAC1B,CAAC;SACE,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;SACjB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEtC,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IACvB,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IACxB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IAEzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACrB,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACrB,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,EAAE,GAAG,EAAE,CAAC;IAChC,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,8EAA8E;AAC9E,2BAA2B;AAC3B,8EAA8E;AAE9E;;GAEG;AACH,SAAgB,oBAAoB;IAClC,IAAI,CAAC;QACH,IAAI,CAAC,iBAAE,CAAC,UAAU,CAAC,8BAAsB,CAAC;YAAE,OAAO,IAAI,CAAC;QAExD,MAAM,GAAG,GAAG,iBAAE,CAAC,YAAY,CAAC,8BAAsB,EAAE,OAAO,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA6B,CAAC;QACzD,IAAI,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAEtD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,CAAC,gCAAgC;IAC/C,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,mBAAmB;IACjC,IAAI,CAAC;QACH,iBAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,iBAAE,CAAC,aAAa,CACd,8BAAsB,EACtB,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAC5C,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,2CAA2C,EAAE,GAAG,CAAC,CAAC;IACjE,CAAC;AACH,CAAC;AAcD;;;GAGG;AACI,KAAK,UAAU,cAAc,CAClC,cAAsB,EACtB,QAAgB;IAEhB,sBAAsB;IACtB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,gBAAgB,EAAE;YACzC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,gBAAgB,CAAC;SAC9C,CAAC,CAAC;QACH,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAA0C,CAAC;YAC1E,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACrD,MAAM,GAAG,GAAG,eAAe,CAAC,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC1D,OAAO;oBACL,SAAS,EAAE,GAAG,GAAG,CAAC;oBAClB,aAAa,EAAE,IAAI,CAAC,OAAO;oBAC3B,MAAM,EAAE,KAAK;oBACb,MAAM,EAAE,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;iBAClE,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,4BAA4B;IAC9B,CAAC;IAED,6BAA6B;IAC7B,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,GAAG,QAAQ,iBAAiB,CAAC;QAClD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,YAAY,EAAE;YACrC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,gBAAgB,CAAC;SAC9C,CAAC,CAAC;QACH,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAA0C,CAAC;YAC1E,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACrD,MAAM,GAAG,GAAG,eAAe,CAAC,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC1D,OAAO;oBACL,SAAS,EAAE,GAAG,GAAG,CAAC;oBAClB,aAAa,EAAE,IAAI,CAAC,OAAO;oBAC3B,MAAM,EAAE,WAAW;oBACnB,MAAM,EAAE,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;iBAClE,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,cAAc;IAChB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAcD;;;GAGG;AACH,SAAgB,oBAAoB,CAAC,OAAe;IAClD,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,MAAM,YAAY,GAAG,mBAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,uBAAuB,CAAC,CAAC;IAC3E,MAAM,IAAI,GAAG;QACX,OAAO,EAAE,CAAC;QACV,OAAO,EAAE;YACP,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,IAAI;YACZ,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;YACd,OAAO,EAAE,+BAA+B,OAAO,EAAE;YACjD,UAAU,EAAE,wCAAwC;SACrD;KACF,CAAC;IAEF,IAAI,CAAC;QACH,iBAAE,CAAC,SAAS,CAAC,mBAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,iBAAE,CAAC,aAAa,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC9E,OAAO,YAAY,CAAC;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,sDAAsD,EAAE,GAAG,CAAC,CAAC;QAC1E,OAAO,YAAY,CAAC;IACtB,CAAC;AACH,CAAC;AAYD;;GAEG;AACH,SAAgB,sBAAsB,CAAC,WAAmB,EAAE,YAAoB;IAC9E,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,iBAAE,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;QAC7C,MAAM,UAAU,GAAG,qBAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7E,OAAO;YACL,KAAK,EAAE,UAAU,KAAK,YAAY;YAClC,UAAU;SACX,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACxD,CAAC;IACJ,CAAC;AACH,CAAC;AAeD;;;GAGG;AACH,SAAgB,eAAe;IAC7B,IAAI,MAAM,GAAkB,IAAI,CAAC;IAEjC,IAAI,CAAC;QACH,kCAAkC;QAClC,MAAM,GAAG,iBAAE,CAAC,WAAW,CAAC,mBAAI,CAAC,IAAI,CAAC,iBAAE,CAAC,MAAM,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC;QAEpE,wDAAwD;QACxD,MAAM,UAAU,GAAG,IAAA,8BAAS,EAAC,KAAK,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,CAAC,EAAE;YACtF,QAAQ,EAAE,MAAM;YAChB,OAAO,EAAE,mBAAmB;YAC5B,GAAG,EAAE,MAAM;SACZ,CAAC,CAAC;QAEH,IAAI,UAAU,CAAC,KAAK,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChD,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,OAAO,IAAI,+BAA+B,UAAU,CAAC,MAAM,EAAE;gBACtF,MAAM;aACP,CAAC;QACJ,CAAC;QAED,uEAAuE;QACvE,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC;QACvE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,KAAK,EAAE,4CAA4C;gBACnD,MAAM;aACP,CAAC;QACJ,CAAC;QAED,MAAM,WAAW,GAAG,mBAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QAEnD,OAAO;YACL,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,cAAc,WAAW,EAAE;YACnC,WAAW;YACX,MAAM;SACP,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;YACvD,MAAM,EAAE,MAAM,IAAI,SAAS;SAC5B,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,kBAAkB,CAAC,WAAmB;IACpD,MAAM,aAAa,GAAG,mBAAI,CAAC,IAAI,CAC7B,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,MAAM,EACrD,WAAW,EACX,YAAY,EACZ,UAAU,CACX,CAAC;IAEF,IAAI,CAAC;QACH,sCAAsC;QACtC,MAAM,OAAO,GAAG,mBAAI,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QACjD,IAAI,iBAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,iBAAE,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,CAAC;QAED,kCAAkC;QAClC,iBAAE,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEjD,0EAA0E;QAC1E,MAAM,aAAa,GAAG,IAAA,8BAAS,EAC7B,KAAK,EACL,CAAC,KAAK,EAAE,WAAW,EAAE,sBAAsB,EAAE,IAAI,EAAE,aAAa,CAAC,EACjE;YACE,QAAQ,EAAE,MAAM;YAChB,OAAO,EAAE,MAAM;SAChB,CACF,CAAC;QAEF,IAAI,aAAa,CAAC,KAAK,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtD,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,aAAa,CAAC,MAAM;gBAC5B,MAAM,EAAE,aAAa,CAAC,MAAM;gBAC5B,KAAK,EAAE,aAAa,CAAC,KAAK,EAAE,OAAO,IAAI,kCAAkC,aAAa,CAAC,MAAM,EAAE;aAChG,CAAC;QACJ,CAAC;QAED,MAAM,WAAW,GAAG,mBAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC/C,OAAO;YACL,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,yBAAyB,WAAW,EAAE;SAC/C,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACxD,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,aAAa;IAC3B,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,IAAI,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;YAC/C,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,iBAAiB;aAC3C,CAAC;QACJ,CAAC;QAED,OAAO,kBAAkB,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAClD,CAAC;YAAS,CAAC;QACT,mBAAmB;QACnB,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;YACpB,IAAI,CAAC;gBACH,iBAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/D,CAAC;YAAC,MAAM,CAAC;gBACP,sBAAsB;YACxB,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAaD;;;;;;;GAOG;AACH,SAAgB,qBAAqB,CACnC,MAAkG;IAElG,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,oBAAoB,CAC/B,OAAO,CAAC,GAAG,CAAC,qBAAqB,EACjC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAC7B,CAAC;QAEF,iCAAiC;QACjC,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QAC7C,KAAK,CAAC,IAAI,CAAC,aAAa,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC9C,MAAM,WAAW,GAAG,IAAA,8BAAS,EAAC,WAAW,EAAE,QAAQ,EAAE;YACnD,QAAQ,EAAE,MAAM;YAChB,OAAO,EAAE,gBAAgB;SAC1B,CAAC,CAAC;QAEH,IAAI,CAAC,WAAW,CAAC,KAAK,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnD,MAAM,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;YAC1E,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QAChD,CAAC;QAED,sCAAsC;QACtC,MAAM,UAAU,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,aAAa,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChD,MAAM,aAAa,GAAG,IAAA,8BAAS,EAAC,WAAW,EAAE,UAAU,EAAE;YACvD,QAAQ,EAAE,MAAM;YAChB,OAAO,EAAE,gBAAgB;SAC1B,CAAC,CAAC;QAEH,IAAI,CAAC,aAAa,CAAC,KAAK,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvD,MAAM,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAC;YAC5E,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QAChD,CAAC;QAED,cAAc;QACd,MAAM,MAAM,GAAG;YACb,SAAS,WAAW,CAAC,KAAK,EAAE,OAAO,IAAI,QAAQ,WAAW,CAAC,MAAM,EAAE,EAAE;YACrE,WAAW,aAAa,CAAC,KAAK,EAAE,OAAO,IAAI,QAAQ,aAAa,CAAC,MAAM,EAAE,EAAE;SAC5E,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,MAAM,CAAC,KAAK,CACV,gDAAgD,MAAM,wCAAwC,CAC/F,CAAC;QACF,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACzD,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,KAAK,GACT,OAAO,CAAC,GAAG,CAAC,sBAAsB;YAClC,8BAA8B,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAE/D,MAAM,GAAG,GAAG,OAAO,OAAO,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAChF,MAAM,MAAM,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;QACjE,MAAM,IAAI,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QACzC,KAAK,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAE1C,MAAM,GAAG,GAAG,IAAA,8BAAS,EAAC,WAAW,EAAE,IAAI,EAAE;YACvC,QAAQ,EAAE,MAAM;YAChB,OAAO,EAAE,gBAAgB;SAC1B,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;YACnE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;QAClD,CAAC;QAED,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,EAAE,OAAO,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC;QAC1D,MAAM,CAAC,KAAK,CACV,gDAAgD,MAAM,wCAAwC,CAC/F,CAAC;QACF,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC3D,CAAC;IAED,uBAAuB;IACvB,MAAM,CAAC,IAAI,CACT,4CAA4C,OAAO,CAAC,QAAQ,0DAA0D,CACvH,CAAC;IACF,OAAO;QACL,EAAE,EAAE,KAAK;QACT,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,yBAAyB,OAAO,CAAC,QAAQ,EAAE;QACnD,KAAK;KACN,CAAC;AACJ,CAAC;AAWD,8EAA8E;AAC9E,4CAA4C;AAC5C,8EAA8E;AAE9E;;;;;;;;;;GAUG;AACH,SAAgB,mBAAmB,CACjC,cAAsB,EACtB,QAAgB,EAChB,MAAkG,EAClG,UAAyB,EAAE;IAE3B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;QAC5B,KAAK,cAAc,CAAC,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACjE,CAAC,EAAE,gBAAgB,CAAC,CAAC;IAErB,6CAA6C;IAC7C,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;QAC3D,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACI,KAAK,UAAU,cAAc,CAClC,cAAsB,EACtB,QAAgB,EAChB,MAAkG,EAClG,UAAyB,EAAE;IAE3B,IAAI,CAAC;QACH,2DAA2D;QAC3D,IAAI,OAAO,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAChC,MAAM,CAAC,IAAI,CAAC,8FAA8F,CAAC,CAAC;YAC5G,OAAO;QACT,CAAC;QAED,0BAA0B;QAC1B,IAAI,CAAC,oBAAoB,EAAE,EAAE,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAC;YACxE,OAAO;QACT,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QAE1D,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;QAE9D,yEAAyE;QACzE,mBAAmB,EAAE,CAAC;QAEtB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,CAAC,IAAI,CAAC,8EAA8E,CAAC,CAAC;YAC5F,OAAO;QACT,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YACtB,MAAM,CAAC,IAAI,CACT,mCAAmC,cAAc,cAAc,MAAM,CAAC,aAAa,QAAQ,MAAM,CAAC,MAAM,IAAI,CAC7G,CAAC;YACF,OAAO;QACT,CAAC;QAED,wCAAwC;QACxC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,CAAC,IAAI,CACT,uDAAuD,MAAM,CAAC,aAAa,SAAS,MAAM,CAAC,MAAM,KAAK;gBACpG,sEAAsE,CACzE,CAAC;YACF,OAAO;QACT,CAAC;QAED,6CAA6C;QAC7C,MAAM,CAAC,IAAI,CACT,yCAAyC,cAAc,OAAO,MAAM,CAAC,aAAa,SAAS,MAAM,CAAC,MAAM,mBAAmB,CAC5H,CAAC;QAEF,sBAAsB;QACtB,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;QAEnC,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;YAC/C,MAAM,CAAC,KAAK,CACV,qCAAqC,QAAQ,CAAC,KAAK,oCAAoC,CACxF,CAAC;YACF,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;gBACpB,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC/D,CAAC;YACD,mBAAmB;YACnB,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;gBACpB,IAAI,CAAC;oBAAC,iBAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;YACnG,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,8BAA8B;YAC9B,MAAM,SAAS,GAAG,sBAAsB,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAE9E,MAAM,CAAC,IAAI,CACT,sCAAsC,SAAS,CAAC,UAAU,IAAI,SAAS,EAAE,CAC1E,CAAC;YAEF,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;gBACrB,MAAM,CAAC,KAAK,CACV,qDAAqD;oBACnD,aAAa,MAAM,CAAC,MAAM,UAAU,SAAS,CAAC,UAAU,IAAI,SAAS,CAAC,KAAK,IAAI;oBAC/E,gDAAgD,CACnD,CAAC;gBACF,OAAO;YACT,CAAC;YAED,MAAM,CAAC,IAAI,CACT,kDAAkD,SAAS,CAAC,UAAU,kBAAkB,MAAM,CAAC,aAAa,KAAK,CAClH,CAAC;YAEF,yBAAyB;YACzB,MAAM,aAAa,GAAG,kBAAkB,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAE/D,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;gBAC3B,MAAM,CAAC,KAAK,CACV,qCAAqC,aAAa,CAAC,KAAK,oCAAoC,CAC7F,CAAC;gBACF,IAAI,aAAa,CAAC,MAAM,EAAE,CAAC;oBACzB,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;gBACpE,CAAC;gBACD,OAAO;YACT,CAAC;YAED,MAAM,CAAC,IAAI,CACT,sDAAsD,cAAc,OAAO,MAAM,CAAC,aAAa,+CAA+C,CAC/I,CAAC;YAEF,kEAAkE;YAClE,oBAAoB,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;YAE3C,4CAA4C;YAC5C,qBAAqB,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC;gBAAS,CAAC;YACT,mBAAmB;YACnB,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;gBACpB,IAAI,CAAC;oBAAC,iBAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;YACnG,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,oDAAoD;QACpD,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,GAAG,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC"}
|