mulmoclaude 0.6.2 → 0.6.4
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/README.md +26 -0
- package/bin/mulmoclaude.js +11 -1
- package/client/assets/JsonEditor-D6WBWLoa.js +10 -0
- package/client/assets/JsonEditor-Di5xGeZY.css +1 -0
- package/client/assets/_plugin-vue_export-helper-BOai-rQB.js +1 -0
- package/client/assets/chunk-D8eiyYIV-LcKZGJv5.js +1 -0
- package/client/assets/{html2canvas-CDGcmOD3-Bkf2uOth.js → html2canvas-CDGcmOD3-XVrO-eyz.js} +1 -1
- package/client/assets/index-CyBr8Mkr.css +2 -0
- package/client/assets/index-zZIqEbNX.js +5106 -0
- package/client/assets/{index.es-DqtpmBm8-D9mAh_KQ.js → index.es-DqtpmBm8-DHT6q10o.js} +1 -1
- package/client/assets/material-symbols-outlined-DtIK7AQn.woff2 +0 -0
- package/client/assets/runtime-protocol-vue-D6kcV0wa.js +1 -0
- package/client/assets/{runtime-vue-BVUzgYGA.js → runtime-vue-fFYhnNg3.js} +1 -1
- package/client/assets/{vue-C8UuIO9J.js → vue-D4w8THF_.js} +1 -1
- package/client/assets/vue-i18n-CQbxVmNs.js +3 -0
- package/client/assets/vue.runtime.esm-bundler-BTyIdNAI.js +4 -0
- package/client/index.html +10 -10
- package/package.json +9 -8
- package/server/agent/backend/claude-code.ts +34 -0
- package/server/agent/backend/fake-echo.ts +370 -0
- package/server/agent/backend/index.ts +16 -1
- package/server/agent/config.ts +74 -24
- package/server/agent/index.ts +104 -80
- package/server/agent/mcpFailureMonitor.ts +167 -0
- package/server/agent/mcpPreflight.ts +185 -0
- package/server/agent/prompt.ts +50 -359
- package/server/agent/stdioHttpShim.ts +171 -0
- package/server/agent/stream.ts +12 -1
- package/server/api/routes/encore.ts +55 -0
- package/server/api/routes/files.ts +22 -0
- package/server/api/routes/mulmo-script.ts +19 -1
- package/server/api/routes/schedulerHandlers.ts +52 -4
- package/server/api/routes/sessions.ts +15 -0
- package/server/api/routes/skills.ts +263 -0
- package/server/build/dispatcher.mjs +299 -0
- package/server/encore/INVARIANTS.md +272 -0
- package/server/encore/boot.ts +39 -0
- package/server/encore/closure.ts +36 -0
- package/server/encore/cycle.ts +276 -0
- package/server/encore/dispatch.ts +103 -0
- package/server/encore/handlers/amend.ts +99 -0
- package/server/encore/handlers/appendNote.ts +74 -0
- package/server/encore/handlers/defineEncore.ts +42 -0
- package/server/encore/handlers/listTickets.ts +107 -0
- package/server/encore/handlers/markStepDone.ts +41 -0
- package/server/encore/handlers/markTargetSkipped.ts +33 -0
- package/server/encore/handlers/query.ts +138 -0
- package/server/encore/handlers/recordValues.ts +44 -0
- package/server/encore/handlers/resolveNotification.ts +121 -0
- package/server/encore/handlers/setup.ts +81 -0
- package/server/encore/handlers/shared.ts +137 -0
- package/server/encore/handlers/snooze.ts +87 -0
- package/server/encore/handlers/startObligationChat.ts +64 -0
- package/server/encore/handlers/startSetupChat.ts +50 -0
- package/server/encore/lock.ts +61 -0
- package/server/encore/notifier.ts +123 -0
- package/server/encore/obligation.ts +25 -0
- package/server/encore/paths.ts +78 -0
- package/server/encore/reconcile.ts +661 -0
- package/server/encore/tick.ts +191 -0
- package/server/encore/yaml-fm.ts +63 -0
- package/server/events/notifications.ts +19 -91
- package/server/index.ts +94 -9
- package/server/notifier/engine.ts +102 -1
- package/server/notifier/macosReminderAdapter.ts +30 -0
- package/server/notifier/runtime-api.ts +41 -1
- package/server/notifier/types.ts +15 -2
- package/server/plugins/runtime.ts +11 -2
- package/server/prompts/index.ts +39 -0
- package/server/prompts/system/journal-pointer.md +12 -0
- package/server/prompts/system/memory-management-atomic.md +33 -0
- package/server/prompts/system/memory-management-topic.md +60 -0
- package/server/prompts/system/news-concierge.md +24 -0
- package/server/prompts/system/sandbox-tools.md +10 -0
- package/server/prompts/system/sources-context.md +16 -0
- package/server/prompts/system/system.md +91 -0
- package/server/system/announceOptionalDeps.ts +57 -0
- package/server/system/appVersion.ts +34 -0
- package/server/system/config.ts +17 -1
- package/server/system/docker.ts +14 -6
- package/server/system/env.ts +18 -5
- package/server/system/optionalDeps.ts +129 -0
- package/server/utils/cli-flags.d.mts +14 -0
- package/server/utils/cli-flags.mjs +53 -0
- package/server/utils/files/encore-io.ts +111 -0
- package/server/utils/time.ts +6 -0
- package/server/workspace/helps/business.md +2 -2
- package/server/workspace/helps/encore-dsl.md +482 -0
- package/server/workspace/helps/index.md +15 -13
- package/server/workspace/helps/mulmoscript.md +3 -3
- package/server/workspace/helps/sandbox.md +2 -2
- package/server/workspace/hooks/dispatcher.ts +7 -5
- package/server/workspace/hooks/provision.ts +6 -3
- package/server/workspace/paths.ts +13 -4
- package/server/workspace/skills/catalog.ts +355 -0
- package/server/workspace/skills/external/catalog.ts +283 -0
- package/server/workspace/skills/external/clone.ts +129 -0
- package/server/workspace/skills/external/id.ts +194 -0
- package/server/workspace/skills/external/install.ts +417 -0
- package/server/workspace/skills/external/presets.ts +50 -0
- package/server/workspace/skills-preset.ts +29 -17
- package/server/workspace/workspace.ts +10 -5
- package/src/App.vue +37 -8
- package/src/components/FileContentRenderer.vue +102 -9
- package/src/components/JsonEditor.vue +160 -0
- package/src/components/NotificationBell.vue +35 -3
- package/src/components/PluginLauncher.vue +20 -41
- package/src/components/RightSidebar.vue +19 -0
- package/src/components/SettingsMcpTab.vue +58 -11
- package/src/components/SettingsModal.vue +22 -1
- package/src/components/StackView.vue +10 -1
- package/src/components/TodoExplorer.vue +16 -0
- package/src/components/todo/TodoKanbanView.vue +34 -6
- package/src/composables/useNotifications.ts +21 -1
- package/src/config/apiRoutes.ts +0 -6
- package/src/config/mcpCatalog.ts +12 -7
- package/src/config/mcpTypes.ts +5 -0
- package/src/config/roles.ts +52 -15
- package/src/config/systemFileDescriptors.ts +12 -0
- package/src/lang/de.ts +108 -12
- package/src/lang/en.ts +105 -11
- package/src/lang/es.ts +106 -11
- package/src/lang/fr.ts +106 -11
- package/src/lang/ja.ts +104 -11
- package/src/lang/ko.ts +105 -11
- package/src/lang/pt-BR.ts +106 -11
- package/src/lang/zh.ts +103 -11
- package/src/main.ts +1 -0
- package/src/plugins/_generated/metas.ts +4 -0
- package/src/plugins/_generated/registrations.ts +2 -0
- package/src/plugins/_generated/server-bindings.ts +5 -0
- package/src/plugins/encore/EncoreDashboard.vue +504 -0
- package/src/plugins/encore/EncoreRedirect.vue +116 -0
- package/src/plugins/encore/View.vue +36 -0
- package/src/plugins/encore/defineEncoreDefinition.ts +74 -0
- package/src/plugins/encore/defineEncoreMeta.ts +13 -0
- package/src/plugins/encore/index.ts +93 -0
- package/src/plugins/encore/manageEncoreDefinition.ts +100 -0
- package/src/plugins/encore/manageEncoreMeta.ts +36 -0
- package/src/plugins/manageSkills/View.vue +832 -30
- package/src/plugins/manageSkills/categories.ts +125 -0
- package/src/plugins/manageSkills/meta.ts +30 -0
- package/src/plugins/markdown/definition.ts +3 -3
- package/src/plugins/meta-types.ts +5 -0
- package/src/plugins/presentMulmoScript/Preview.vue +3 -3
- package/src/plugins/presentMulmoScript/View.vue +157 -33
- package/src/plugins/presentMulmoScript/meta.ts +4 -0
- package/src/plugins/scheduler/View.vue +45 -9
- package/src/plugins/scheduler/calendarDefinition.ts +6 -2
- package/src/plugins/scheduler/multiDayHelpers.ts +95 -0
- package/src/plugins/skill/View.vue +1 -5
- package/src/plugins/spreadsheet/View.vue +3 -3
- package/src/plugins/spreadsheet/definition.ts +1 -1
- package/src/plugins/textResponse/Preview.vue +14 -1
- package/src/plugins/textResponse/View.vue +39 -24
- package/src/plugins/wiki/components/WikiPageBody.vue +4 -0
- package/src/router/index.ts +11 -0
- package/src/router/pageRoutes.ts +1 -0
- package/src/types/encore-dsl/at-expression.ts +120 -0
- package/src/types/encore-dsl/at-resolver.ts +32 -0
- package/src/types/encore-dsl/cadence.ts +289 -0
- package/src/types/encore-dsl/schema.ts +288 -0
- package/src/types/notification.ts +2 -1
- package/src/types/session.ts +6 -0
- package/src/types/sse.ts +5 -0
- package/src/types/toolCallHistory.ts +7 -0
- package/src/utils/agent/eventDispatch.ts +26 -5
- package/src/utils/agent/mcpHint.ts +50 -0
- package/src/utils/image/htmlSrcAttrs.ts +117 -13
- package/src/utils/session/sessionEntries.ts +8 -32
- package/client/assets/PluginScopedRoot-YjvQq0Nn.js +0 -3
- package/client/assets/chunk-CernVdwh.js +0 -1
- package/client/assets/chunk-D8eiyYIV-CAXpUwLd.js +0 -1
- package/client/assets/index-BwrlMMHr.js +0 -5005
- package/client/assets/index-CvvNuegU.css +0 -2
- package/client/assets/material-symbols-outlined-BOZVWuR3.woff2 +0 -0
- package/client/assets/runtime-protocol-vue-C1To4M3t.js +0 -1
- package/client/assets/vue.runtime.esm-bundler-DQ8Kjjui.js +0 -4
- package/server/api/routes/notifications.ts +0 -195
- package/server/notifier/legacy-adapters.ts +0 -76
- package/server/workspace/hooks/dispatcher.mjs +0 -300
- package/src/composables/useSelectedResult.ts +0 -49
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// server/workspace/hooks/shared/sidecar.ts
|
|
4
|
-
import { readFileSync } from "node:fs";
|
|
5
|
-
import path2 from "node:path";
|
|
6
|
-
|
|
7
|
-
// server/utils/time.ts
|
|
8
|
-
var ONE_SECOND_MS = 1e3;
|
|
9
|
-
var ONE_MINUTE_MS = 6e4;
|
|
10
|
-
var SUBPROCESS_PROBE_TIMEOUT_MS = 5 * ONE_SECOND_MS;
|
|
11
|
-
var STARTUP_FAILURE_FORCE_EXIT_MS = 5 * ONE_SECOND_MS;
|
|
12
|
-
var CLI_SUBPROCESS_TIMEOUT_MS = 5 * ONE_MINUTE_MS;
|
|
13
|
-
|
|
14
|
-
// server/workspace/hooks/shared/workspace.ts
|
|
15
|
-
import { homedir } from "node:os";
|
|
16
|
-
import path from "node:path";
|
|
17
|
-
function workspaceRoot() {
|
|
18
|
-
return process.env.CLAUDE_PROJECT_DIR ?? path.join(homedir(), "mulmoclaude");
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// server/workspace/hooks/shared/sidecar.ts
|
|
22
|
-
var TOKEN_FILE = ".session-token";
|
|
23
|
-
var PORT_FILE = ".server-port";
|
|
24
|
-
function serverHost() {
|
|
25
|
-
return process.env.MULMOCLAUDE_HOST ?? "127.0.0.1";
|
|
26
|
-
}
|
|
27
|
-
function readSidecar(rel) {
|
|
28
|
-
try {
|
|
29
|
-
return readFileSync(path2.join(workspaceRoot(), rel), "utf-8").trim();
|
|
30
|
-
} catch {
|
|
31
|
-
return "";
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
function readToken() {
|
|
35
|
-
return readSidecar(TOKEN_FILE);
|
|
36
|
-
}
|
|
37
|
-
function readPort() {
|
|
38
|
-
const raw = readSidecar(PORT_FILE);
|
|
39
|
-
if (!raw) return null;
|
|
40
|
-
const port = Number.parseInt(raw, 10);
|
|
41
|
-
return Number.isInteger(port) && port > 0 && port < 65536 ? port : null;
|
|
42
|
-
}
|
|
43
|
-
function buildAuthPost(pathname, body) {
|
|
44
|
-
const token = readToken();
|
|
45
|
-
const port = readPort();
|
|
46
|
-
if (!token || port === null) return null;
|
|
47
|
-
const headers = {
|
|
48
|
-
Authorization: `Bearer ${token}`
|
|
49
|
-
};
|
|
50
|
-
const init = { method: "POST", headers };
|
|
51
|
-
if (body !== void 0) {
|
|
52
|
-
headers["Content-Type"] = "application/json";
|
|
53
|
-
init.body = JSON.stringify(body);
|
|
54
|
-
}
|
|
55
|
-
return {
|
|
56
|
-
url: `http://${serverHost()}:${port}${pathname}`,
|
|
57
|
-
init
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
var DEFAULT_TIMEOUT_MS = 2 * ONE_SECOND_MS;
|
|
61
|
-
async function safePost(req, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
62
|
-
if (!req) return;
|
|
63
|
-
const controller = new AbortController();
|
|
64
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
65
|
-
try {
|
|
66
|
-
await fetch(req.url, { ...req.init, signal: controller.signal });
|
|
67
|
-
} catch {
|
|
68
|
-
} finally {
|
|
69
|
-
clearTimeout(timer);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
var LOG_TIMEOUT_MS = ONE_SECOND_MS;
|
|
73
|
-
async function serverLog(namespace, message, options = {}) {
|
|
74
|
-
const body = {
|
|
75
|
-
namespace,
|
|
76
|
-
message,
|
|
77
|
-
level: options.level ?? "info",
|
|
78
|
-
...options.data ? { data: options.data } : {}
|
|
79
|
-
};
|
|
80
|
-
const req = buildAuthPost("/api/hooks/log", body);
|
|
81
|
-
await safePost(req, LOG_TIMEOUT_MS);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// server/workspace/hooks/shared/stdin.ts
|
|
85
|
-
async function readHookPayload() {
|
|
86
|
-
const chunks = [];
|
|
87
|
-
for await (const chunk of process.stdin) {
|
|
88
|
-
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
89
|
-
}
|
|
90
|
-
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
91
|
-
if (!raw.trim()) return null;
|
|
92
|
-
try {
|
|
93
|
-
return JSON.parse(raw);
|
|
94
|
-
} catch {
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
function extractFilePath(payload) {
|
|
99
|
-
const fromInput = payload.tool_input?.file_path;
|
|
100
|
-
if (typeof fromInput === "string") return fromInput;
|
|
101
|
-
const fromResponse = payload.tool_response?.filePath;
|
|
102
|
-
if (typeof fromResponse === "string") return fromResponse;
|
|
103
|
-
return "";
|
|
104
|
-
}
|
|
105
|
-
function extractCommand(payload) {
|
|
106
|
-
const command = payload.tool_input?.command;
|
|
107
|
-
return typeof command === "string" ? command : "";
|
|
108
|
-
}
|
|
109
|
-
function extractToolName(payload) {
|
|
110
|
-
return typeof payload.tool_name === "string" ? payload.tool_name : "";
|
|
111
|
-
}
|
|
112
|
-
function extractSessionId(payload) {
|
|
113
|
-
const sessionId = payload.session_id;
|
|
114
|
-
return typeof sessionId === "string" && sessionId.length > 0 ? sessionId : void 0;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// server/workspace/hooks/handlers/configRefresh.ts
|
|
118
|
-
var PATTERNS = [/[\\/]\.claude[\\/]skills[\\/][^\\/]+[\\/]SKILL\.md$/, /[\\/]config[\\/]scheduler[\\/]tasks\.json$/];
|
|
119
|
-
async function handleConfigRefresh(payload) {
|
|
120
|
-
const tool = extractToolName(payload);
|
|
121
|
-
if (tool !== "Write" && tool !== "Edit") return;
|
|
122
|
-
const filePath = extractFilePath(payload);
|
|
123
|
-
if (!filePath) return;
|
|
124
|
-
if (!PATTERNS.some((pattern) => pattern.test(filePath))) return;
|
|
125
|
-
const req = buildAuthPost("/api/config/refresh");
|
|
126
|
-
await safePost(req);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// server/workspace/hooks/handlers/skillBridge.ts
|
|
130
|
-
import { mkdirSync, readFileSync as readFileSync2, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
131
|
-
import path3 from "node:path";
|
|
132
|
-
|
|
133
|
-
// server/utils/errors.ts
|
|
134
|
-
function errorMessage(err, fallback) {
|
|
135
|
-
if (err instanceof Error) return err.message;
|
|
136
|
-
if (err !== null && typeof err === "object") {
|
|
137
|
-
const obj = err;
|
|
138
|
-
if (typeof obj.details === "string" && obj.details) return obj.details;
|
|
139
|
-
if (typeof obj.message === "string" && obj.message) return obj.message;
|
|
140
|
-
}
|
|
141
|
-
if (fallback !== void 0) return fallback;
|
|
142
|
-
return String(err);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// server/workspace/hooks/handlers/skillBridge.ts
|
|
146
|
-
var DATA_SKILLS_DIR = path3.join("data", "skills");
|
|
147
|
-
var CLAUDE_SKILLS_DIR = path3.join(".claude", "skills");
|
|
148
|
-
var SKILL_FILENAME = "SKILL.md";
|
|
149
|
-
var SLUG_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
150
|
-
var RM_RE = /^\s*rm\s+((?:-[a-zA-Z]+\s+)+)['"]?data\/skills\/([a-z0-9-]+)\/?['"]?\s*$/;
|
|
151
|
-
var RECURSIVE_FLAG_RE = /[rR]/;
|
|
152
|
-
function dataSkillDir(slug) {
|
|
153
|
-
return path3.join(workspaceRoot(), DATA_SKILLS_DIR, slug);
|
|
154
|
-
}
|
|
155
|
-
function dataSkillFilePath(slug) {
|
|
156
|
-
return path3.join(dataSkillDir(slug), SKILL_FILENAME);
|
|
157
|
-
}
|
|
158
|
-
function claudeSkillDir(slug) {
|
|
159
|
-
return path3.join(workspaceRoot(), CLAUDE_SKILLS_DIR, slug);
|
|
160
|
-
}
|
|
161
|
-
function claudeSkillFilePath(slug) {
|
|
162
|
-
return path3.join(claudeSkillDir(slug), SKILL_FILENAME);
|
|
163
|
-
}
|
|
164
|
-
function slugFromDataPath(filePath) {
|
|
165
|
-
const root = workspaceRoot();
|
|
166
|
-
const staging = path3.join(root, DATA_SKILLS_DIR);
|
|
167
|
-
const rel = path3.relative(staging, filePath);
|
|
168
|
-
if (!rel || rel.startsWith("..")) return null;
|
|
169
|
-
const segments = rel.split(path3.sep);
|
|
170
|
-
if (segments.length !== 2) return null;
|
|
171
|
-
const [slug, basename] = segments;
|
|
172
|
-
if (basename !== SKILL_FILENAME) return null;
|
|
173
|
-
return SLUG_RE.test(slug) ? slug : null;
|
|
174
|
-
}
|
|
175
|
-
function slugFromRmCommand(command) {
|
|
176
|
-
const match = RM_RE.exec(command);
|
|
177
|
-
if (!match) return null;
|
|
178
|
-
const [, flags, slug] = match;
|
|
179
|
-
if (!RECURSIVE_FLAG_RE.test(flags)) return null;
|
|
180
|
-
return SLUG_RE.test(slug) ? slug : null;
|
|
181
|
-
}
|
|
182
|
-
function mirrorWrite(slug) {
|
|
183
|
-
const content = readFileSync2(dataSkillFilePath(slug), "utf-8");
|
|
184
|
-
const destDir = claudeSkillDir(slug);
|
|
185
|
-
mkdirSync(destDir, { recursive: true });
|
|
186
|
-
const dest = claudeSkillFilePath(slug);
|
|
187
|
-
const tmp = path3.join(destDir, `.SKILL.md.${process.pid}.tmp`);
|
|
188
|
-
writeFileSync(tmp, content, "utf-8");
|
|
189
|
-
renameSync(tmp, dest);
|
|
190
|
-
}
|
|
191
|
-
function mirrorDelete(slug) {
|
|
192
|
-
rmSync(claudeSkillDir(slug), { recursive: true, force: true });
|
|
193
|
-
}
|
|
194
|
-
async function refreshConfig() {
|
|
195
|
-
await safePost(buildAuthPost("/api/config/refresh"));
|
|
196
|
-
}
|
|
197
|
-
async function handleWriteOrEdit(payload) {
|
|
198
|
-
const filePath = extractFilePath(payload);
|
|
199
|
-
if (!filePath) return;
|
|
200
|
-
const slug = slugFromDataPath(filePath);
|
|
201
|
-
if (slug === null) return;
|
|
202
|
-
try {
|
|
203
|
-
mirrorWrite(slug);
|
|
204
|
-
await refreshConfig();
|
|
205
|
-
await serverLog("skill-bridge", `mirrored ${dataSkillFilePath(slug)} \u2192 ${claudeSkillFilePath(slug)}`, { data: { slug, op: "write" } });
|
|
206
|
-
} catch (err) {
|
|
207
|
-
await serverLog("skill-bridge", `mirror write failed for slug=${slug}`, {
|
|
208
|
-
level: "error",
|
|
209
|
-
data: { slug, error: errorMessage(err) }
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
async function handleBash(payload) {
|
|
214
|
-
const command = extractCommand(payload);
|
|
215
|
-
if (!command) return;
|
|
216
|
-
const slug = slugFromRmCommand(command);
|
|
217
|
-
if (slug === null) return;
|
|
218
|
-
try {
|
|
219
|
-
mirrorDelete(slug);
|
|
220
|
-
await refreshConfig();
|
|
221
|
-
await serverLog("skill-bridge", `removed ${claudeSkillDir(slug)}`, { data: { slug, op: "delete" } });
|
|
222
|
-
} catch (err) {
|
|
223
|
-
await serverLog("skill-bridge", `mirror delete failed for slug=${slug}`, {
|
|
224
|
-
level: "error",
|
|
225
|
-
data: { slug, error: errorMessage(err) }
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
async function handleSkillBridge(payload) {
|
|
230
|
-
const tool = extractToolName(payload);
|
|
231
|
-
if (tool === "Write" || tool === "Edit") {
|
|
232
|
-
await handleWriteOrEdit(payload);
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
if (tool === "Bash") {
|
|
236
|
-
await handleBash(payload);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// server/workspace/hooks/handlers/wikiSnapshot.ts
|
|
241
|
-
import path5 from "node:path";
|
|
242
|
-
|
|
243
|
-
// src/lib/wiki-page/paths.ts
|
|
244
|
-
import path4 from "node:path";
|
|
245
|
-
|
|
246
|
-
// src/lib/wiki-page/slug.ts
|
|
247
|
-
function isSafeSlug(slug) {
|
|
248
|
-
if (slug.length === 0) return false;
|
|
249
|
-
if (slug === "." || slug === "..") return false;
|
|
250
|
-
if (slug.includes("/") || slug.includes("\\")) return false;
|
|
251
|
-
if (slug.includes("\0")) return false;
|
|
252
|
-
return true;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// src/lib/wiki-page/paths.ts
|
|
256
|
-
function wikiSlugFromAbsPath(absPath, pagesDir) {
|
|
257
|
-
const rel = path4.relative(pagesDir, absPath);
|
|
258
|
-
if (rel.length === 0) return null;
|
|
259
|
-
if (path4.isAbsolute(rel)) return null;
|
|
260
|
-
if (rel.includes(path4.sep)) return null;
|
|
261
|
-
if (!rel.endsWith(".md")) return null;
|
|
262
|
-
const slug = rel.slice(0, -".md".length);
|
|
263
|
-
if (!isSafeSlug(slug)) return null;
|
|
264
|
-
return slug;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// server/workspace/hooks/handlers/wikiSnapshot.ts
|
|
268
|
-
var WIKI_PAGES_REL = path5.join("data", "wiki", "pages");
|
|
269
|
-
async function handleWikiSnapshot(payload) {
|
|
270
|
-
const tool = extractToolName(payload);
|
|
271
|
-
if (tool !== "Write" && tool !== "Edit") return;
|
|
272
|
-
const filePath = extractFilePath(payload);
|
|
273
|
-
if (!filePath) return;
|
|
274
|
-
const wikiPagesDir = path5.join(workspaceRoot(), WIKI_PAGES_REL);
|
|
275
|
-
const slug = wikiSlugFromAbsPath(filePath, wikiPagesDir);
|
|
276
|
-
if (slug === null) return;
|
|
277
|
-
const envChatSessionId = process.env.MULMOCLAUDE_CHAT_SESSION_ID;
|
|
278
|
-
const payloadSessionId = extractSessionId(payload);
|
|
279
|
-
const sessionId = envChatSessionId && envChatSessionId.length > 0 ? envChatSessionId : payloadSessionId;
|
|
280
|
-
const body = sessionId === void 0 ? { slug } : { slug, sessionId };
|
|
281
|
-
const req = buildAuthPost("/api/wiki/internal/snapshot", body);
|
|
282
|
-
await safePost(req);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// server/workspace/hooks/dispatcher.ts
|
|
286
|
-
var HANDLERS = [handleWikiSnapshot, handleConfigRefresh, handleSkillBridge];
|
|
287
|
-
async function runHandler(handler, payload) {
|
|
288
|
-
try {
|
|
289
|
-
await handler(payload);
|
|
290
|
-
} catch {
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
async function main() {
|
|
294
|
-
const payload = await readHookPayload();
|
|
295
|
-
if (!payload) return;
|
|
296
|
-
await Promise.all(HANDLERS.map((handler) => runHandler(handler, payload)));
|
|
297
|
-
}
|
|
298
|
-
main().catch(() => {
|
|
299
|
-
});
|
|
300
|
-
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsic2hhcmVkL3NpZGVjYXIudHMiLCAiLi4vLi4vdXRpbHMvdGltZS50cyIsICJzaGFyZWQvd29ya3NwYWNlLnRzIiwgInNoYXJlZC9zdGRpbi50cyIsICJoYW5kbGVycy9jb25maWdSZWZyZXNoLnRzIiwgImhhbmRsZXJzL3NraWxsQnJpZGdlLnRzIiwgIi4uLy4uL3V0aWxzL2Vycm9ycy50cyIsICJoYW5kbGVycy93aWtpU25hcHNob3QudHMiLCAiLi4vLi4vLi4vc3JjL2xpYi93aWtpLXBhZ2UvcGF0aHMudHMiLCAiLi4vLi4vLi4vc3JjL2xpYi93aWtpLXBhZ2Uvc2x1Zy50cyIsICJkaXNwYXRjaGVyLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvLyBSZWFkIHRoZSBiZWFyZXIgdG9rZW4gYW5kIHNlcnZlciBwb3J0IGZyb20gc2lkZWNhciBmaWxlcyB0aGVcbi8vIHBhcmVudCBzZXJ2ZXIgd3JpdGVzIG9uIGVhY2ggc3RhcnR1cC4gSG9va3MgUE9TVCBiYWNrIHRvIHRoZVxuLy8gcGFyZW50IHNlcnZlciB1c2luZyB0aGVzZSBcdTIwMTQgdGhleSBuZWVkIHRvIHJ1biB3aXRob3V0IGFueVxuLy8gcnVudGltZSBjb25maWcgYmFrZWQgaW4uXG4vL1xuLy8gU3RyaWN0IGludGVnZXIgcGFyc2luZyBvbiB0aGUgcG9ydDogYSBjcmFmdGVkIGZpbGUgdmFsdWUgbGlrZVxuLy8gYDgwQGF0dGFja2VyLmV4YW1wbGVgIHdvdWxkIG90aGVyd2lzZSBjaGFuZ2UgdGhlIHJlcXVlc3Rcbi8vIGF1dGhvcml0eSBhbmQgZXhmaWx0cmF0ZSB0aGUgYmVhcmVyIHRva2VuIG9mZi1ob3N0LiBTYW1lXG4vLyBoYXJkZW5pbmcgYXBwbGllZCBhcyB0aGUgQ29kZXggcmV2aWV3IG9uIFBSICMxMjg0LlxuXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tIFwibm9kZTpmc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgT05FX1NFQ09ORF9NUyB9IGZyb20gXCIuLi8uLi8uLi91dGlscy90aW1lLmpzXCI7XG5pbXBvcnQgeyB3b3Jrc3BhY2VSb290IH0gZnJvbSBcIi4vd29ya3NwYWNlLmpzXCI7XG5cbmNvbnN0IFRPS0VOX0ZJTEUgPSBcIi5zZXNzaW9uLXRva2VuXCI7XG5jb25zdCBQT1JUX0ZJTEUgPSBcIi5zZXJ2ZXItcG9ydFwiO1xuXG4vLyBJbiBEb2NrZXIgbW9kZSB0aGUgcGFyZW50IHNlcnZlciBsaXZlcyBvbiB0aGUgaG9zdCdzIDEyNy4wLjAuMVxuLy8gd2hpY2ggdGhlIGNvbnRhaW5lciBjYW4ndCByZWFjaCB2aWEgcGxhaW4gbG9vcGJhY2suIFRoZSBEb2NrZXJcbi8vIHNwYXduIHBsdW1iaW5nIHNldHMgTVVMTU9DTEFVREVfSE9TVD1ob3N0LmRvY2tlci5pbnRlcm5hbCBzb1xuLy8gZmV0Y2goKSByZXNvbHZlcyB0byB0aGUgaG9zdCBzZXJ2ZXIuIE91dHNpZGUgRG9ja2VyIChvciB3aGVuIHRoZVxuLy8gdmFyIGlzIHVuc2V0KSB3ZSBmYWxsIGJhY2sgdG8gdGhlIGxvb3BiYWNrIGFkZHJlc3MuXG5leHBvcnQgZnVuY3Rpb24gc2VydmVySG9zdCgpOiBzdHJpbmcge1xuICByZXR1cm4gcHJvY2Vzcy5lbnYuTVVMTU9DTEFVREVfSE9TVCA/PyBcIjEyNy4wLjAuMVwiO1xufVxuXG5mdW5jdGlvbiByZWFkU2lkZWNhcihyZWw6IHN0cmluZyk6IHN0cmluZyB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIHJlYWRGaWxlU3luYyhwYXRoLmpvaW4od29ya3NwYWNlUm9vdCgpLCByZWwpLCBcInV0Zi04XCIpLnRyaW0oKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIFwiXCI7XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlYWRUb2tlbigpOiBzdHJpbmcge1xuICByZXR1cm4gcmVhZFNpZGVjYXIoVE9LRU5fRklMRSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWFkUG9ydCgpOiBudW1iZXIgfCBudWxsIHtcbiAgY29uc3QgcmF3ID0gcmVhZFNpZGVjYXIoUE9SVF9GSUxFKTtcbiAgaWYgKCFyYXcpIHJldHVybiBudWxsO1xuICBjb25zdCBwb3J0ID0gTnVtYmVyLnBhcnNlSW50KHJhdywgMTApO1xuICByZXR1cm4gTnVtYmVyLmlzSW50ZWdlcihwb3J0KSAmJiBwb3J0ID4gMCAmJiBwb3J0IDwgNjU1MzYgPyBwb3J0IDogbnVsbDtcbn1cblxuLy8gQnVpbGQgYW4gYXV0aGVudGljYXRlZCBQT1NUIHJlcXVlc3QgYWdhaW5zdCB0aGUgcGFyZW50IHNlcnZlci5cbi8vIFJldHVybnMgbnVsbCB3aGVuIHRva2VuIC8gcG9ydCBhcmUgbWlzc2luZyAoc2VydmVyIGlzbid0IHVwIHlldCk7XG4vLyBjYWxsZXIgdHJlYXRzIG51bGwgYXMgYSBzaWxlbnQgbm8tb3Agc28gYSBvbmUtb2ZmIGhvb2sgbWlzc1xuLy8gZHVyaW5nIHN0YXJ0dXAgZG9lc24ndCBzdXJmYWNlIGFzIGEgdG9vbCBlcnJvci5cbi8vIGBQYXJhbWV0ZXJzPHR5cGVvZiBmZXRjaD5bMV1gIGRlcml2ZXMgdGhlIHJlcXVlc3QtaW5pdCBzaGFwZVxuLy8gZnJvbSB0aGUgZ2xvYmFsIGBmZXRjaGAgdHlwZSByYXRoZXIgdGhhbiBuYW1pbmcgYFJlcXVlc3RJbml0YFxuLy8gZGlyZWN0bHkgXHUyMDE0IGtlZXBzIHRoZSBmaWxlIGxpbnQtY2xlYW4gdW5kZXIgb3VyIHNoYXJlZCBuby11bmRlZlxuLy8gY29uZmlnIHdpdGhvdXQgbmVlZGluZyBhIGN1c3RvbSBET00tdHlwZXMgdHNjb25maWcgZm9yIHRoZSBob29rXG4vLyBidW5kbGUuXG50eXBlIEZldGNoSW5pdCA9IFBhcmFtZXRlcnM8dHlwZW9mIGZldGNoPlsxXTtcblxuZXhwb3J0IGludGVyZmFjZSBQb3N0UmVxdWVzdCB7XG4gIHVybDogc3RyaW5nO1xuICBpbml0OiBGZXRjaEluaXQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBidWlsZEF1dGhQb3N0KHBhdGhuYW1lOiBzdHJpbmcsIGJvZHk/OiB1bmtub3duKTogUG9zdFJlcXVlc3QgfCBudWxsIHtcbiAgY29uc3QgdG9rZW4gPSByZWFkVG9rZW4oKTtcbiAgY29uc3QgcG9ydCA9IHJlYWRQb3J0KCk7XG4gIGlmICghdG9rZW4gfHwgcG9ydCA9PT0gbnVsbCkgcmV0dXJuIG51bGw7XG4gIGNvbnN0IGhlYWRlcnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgQXV0aG9yaXphdGlvbjogYEJlYXJlciAke3Rva2VufWAsXG4gIH07XG4gIGNvbnN0IGluaXQ6IEZldGNoSW5pdCA9IHsgbWV0aG9kOiBcIlBPU1RcIiwgaGVhZGVycyB9O1xuICBpZiAoYm9keSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgaGVhZGVyc1tcIkNvbnRlbnQtVHlwZVwiXSA9IFwiYXBwbGljYXRpb24vanNvblwiO1xuICAgIGluaXQuYm9keSA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xuICB9XG4gIHJldHVybiB7XG4gICAgdXJsOiBgaHR0cDovLyR7c2VydmVySG9zdCgpfToke3BvcnR9JHtwYXRobmFtZX1gLFxuICAgIGluaXQsXG4gIH07XG59XG5cbi8vIDIgcyBkZWZhdWx0IHRpbWVvdXQuIFBvc3RUb29sVXNlIGhvb2tzIGJsb2NrIENsYXVkZSBDTEkncyB0b29sXG4vLyB0dXJuIHVudGlsIHRoZSBzY3JpcHQgZXhpdHMsIHNvIGEgc2xvdyAvIGh1bmcgcGFyZW50IHNlcnZlclxuLy8gKHJlZnJlc2ggZGVhZGxvY2ssIEdDIHBhdXNlLCB1bnJlbGF0ZWQgbG9uZy1ydW5uaW5nIHJvdXRlKSB3b3VsZFxuLy8gbGVhdmUgdGhlIHVzZXIncyBXcml0ZS9FZGl0IGFwcGVhcmluZyBmcm96ZW4uIFRoZSByZWZyZXNoLXN0eWxlXG4vLyBQT1NUcyBhcmUgZmlyZS1hbmQtZm9yZ2V0IGFueXdheTsgaWYgdGhlIHNlcnZlciBjYW4ndCByZXNwb25kXG4vLyBpbnNpZGUgdGhhdCB3aW5kb3csIHRoZSBmaWxlIGlzIGFscmVhZHkgb24gZGlzayBhbmQgdGhlIG5leHRcbi8vIHJlc3RhcnQgcGlja3MgaXQgdXAuXG5jb25zdCBERUZBVUxUX1RJTUVPVVRfTVMgPSAyICogT05FX1NFQ09ORF9NUztcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNhZmVQb3N0KHJlcTogUG9zdFJlcXVlc3QgfCBudWxsLCB0aW1lb3V0TXMgPSBERUZBVUxUX1RJTUVPVVRfTVMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKCFyZXEpIHJldHVybjtcbiAgY29uc3QgY29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcbiAgY29uc3QgdGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IGNvbnRyb2xsZXIuYWJvcnQoKSwgdGltZW91dE1zKTtcbiAgdHJ5IHtcbiAgICBhd2FpdCBmZXRjaChyZXEudXJsLCB7IC4uLnJlcS5pbml0LCBzaWduYWw6IGNvbnRyb2xsZXIuc2lnbmFsIH0pO1xuICB9IGNhdGNoIHtcbiAgICAvLyBTZXJ2ZXIgbWlnaHQgYmUgcmVzdGFydGluZyAvIHVucmVhY2hhYmxlIC8gdGltZWQgb3V0IFx1MjAxNCBzaWxlbnRcbiAgICAvLyBmYWlsIGlzIGZpbmU7IHRoZSBmaWxlIGlzIG9uIGRpc2sgYW5kIHRoZSBuZXh0IG1hbnVhbCByZXN0YXJ0XG4gICAgLy8gcGlja3MgaXQgdXAuXG4gIH0gZmluYWxseSB7XG4gICAgY2xlYXJUaW1lb3V0KHRpbWVyKTtcbiAgfVxufVxuXG4vLyBGb3J3YXJkIGEgc3RydWN0dXJlZCBsb2cgbGluZSBpbnRvIHRoZSBzZXJ2ZXIncyBsb2dnZXIgdmlhXG4vLyBgUE9TVCAvYXBpL2hvb2tzL2xvZ2AuIEhhbmRsZXJzIGNhbGwgdGhpcyBhZnRlciBlYWNoIG1lYW5pbmdmdWxcbi8vIHNpZGUtZWZmZWN0IChtaXJyb3IgY29weSwgZGVsZXRlLCBldGMuKSBzbyB0aGUgdXNlciBjYW4gdmVyaWZ5XG4vLyBmcm9tIHNlcnZlciBsb2dzIHRoYXQgdGhlIGhvb2sgZmlyZWQgYW5kIHdoYXQgaXQgZGlkLiBUaGUgZW5kcG9pbnRcbi8vIGF1dGhlbnRpY2F0ZXMgdmlhIGJlYXJlciB0b2tlbiAoc2FtZSBhcyBldmVyeSBvdGhlciBpbnRlcm5hbCBob29rXG4vLyBQT1NUKTsgYSBtaXNzaW5nIHRva2VuIC8gcG9ydCBpcyB0aGUgc2lsZW50IG5vLW9wIHNhZmVQb3N0XG4vLyBhbHJlYWR5IGhhbmRsZXMuIDEgcyB0aW1lb3V0IFx1MjAxNCBsb2dnaW5nIHNob3VsZG4ndCBzdGFsbCB0aGUgdXNlcidzXG4vLyB0b29sIHR1cm4gZXZlbiBpZiB0aGUgc2VydmVyIGlzIGJyaWVmbHkgc2xvdy5cbmNvbnN0IExPR19USU1FT1VUX01TID0gT05FX1NFQ09ORF9NUztcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNlcnZlckxvZyhuYW1lc3BhY2U6IHN0cmluZywgbWVzc2FnZTogc3RyaW5nLCBvcHRpb25zOiB7IGxldmVsPzogXCJpbmZvXCIgfCBcIndhcm5cIiB8IFwiZXJyb3JcIjsgZGF0YT86IG9iamVjdCB9ID0ge30pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgYm9keSA9IHtcbiAgICBuYW1lc3BhY2UsXG4gICAgbWVzc2FnZSxcbiAgICBsZXZlbDogb3B0aW9ucy5sZXZlbCA/PyBcImluZm9cIixcbiAgICAuLi4ob3B0aW9ucy5kYXRhID8geyBkYXRhOiBvcHRpb25zLmRhdGEgfSA6IHt9KSxcbiAgfTtcbiAgY29uc3QgcmVxID0gYnVpbGRBdXRoUG9zdChcIi9hcGkvaG9va3MvbG9nXCIsIGJvZHkpO1xuICBhd2FpdCBzYWZlUG9zdChyZXEsIExPR19USU1FT1VUX01TKTtcbn1cbiIsICIvLyBDb21tb24gdGltZSBjb25zdGFudHMgaW4gbWlsbGlzZWNvbmRzLiBBdm9pZHMgbWFnaWMgbnVtYmVycyBsaWtlXG4vLyAzXzYwMF8wMDAgc2NhdHRlcmVkIGFjcm9zcyB0aGUgY29kZWJhc2UuXG4vL1xuLy8gQWxsIHNlcnZlci1zaWRlIGNvZGUgc2hvdWxkIGltcG9ydCBmcm9tIGhlcmUgaW5zdGVhZCBvZiB1c2luZyByYXdcbi8vIG51bWVyaWMgbGl0ZXJhbHMuIFdoZW4gYSBzcGVjaWZpYyBkdXJhdGlvbiBpcyBuZWVkZWQgKGUuZy4gYVxuLy8gNS1zZWNvbmQgdGltZW91dCksIGV4cHJlc3MgaXQgYXMgYDUgKiBPTkVfU0VDT05EX01TYC5cblxuZXhwb3J0IGNvbnN0IE9ORV9TRUNPTkRfTVMgPSAxXzAwMDtcbmV4cG9ydCBjb25zdCBPTkVfTUlOVVRFX01TID0gNjBfMDAwO1xuZXhwb3J0IGNvbnN0IE9ORV9IT1VSX01TID0gM182MDBfMDAwO1xuZXhwb3J0IGNvbnN0IE9ORV9EQVlfTVMgPSA4Nl80MDBfMDAwO1xuXG4vKiogTWFwIHRpbWUtdW5pdCBzdWZmaXhlcyAocy9tL2gpIHRvIG1pbGxpc2Vjb25kcy4gKi9cbmV4cG9ydCBjb25zdCBUSU1FX1VOSVRfTVM6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4gPSB7XG4gIHM6IE9ORV9TRUNPTkRfTVMsXG4gIG06IE9ORV9NSU5VVEVfTVMsXG4gIGg6IE9ORV9IT1VSX01TLFxufTtcblxuLy8gXHUyNTAwXHUyNTAwIENvbW1vbiB0aW1lb3V0IHByZXNldHMgXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXG4vLyBOYW1lZCB0aW1lb3V0cyBmb3IgcmVjdXJyaW5nIHBhdHRlcm5zLiBQcmVmZXIgdGhlc2Ugb3ZlciBpbmxpbmVcbi8vIGA1ICogT05FX1NFQ09ORF9NU2Agd2hlbiB0aGUgc2FtZSB2YWx1ZSBpcyB1c2VkIGluIDMrIHBsYWNlcy5cblxuLyoqIFF1aWNrIHN1YnByb2Nlc3MgcHJvYmUgKGRvY2tlciBwcywgbGlicmVvZmZpY2UgLS12ZXJzaW9uLCBldGMuKSAqL1xuZXhwb3J0IGNvbnN0IFNVQlBST0NFU1NfUFJPQkVfVElNRU9VVF9NUyA9IDUgKiBPTkVfU0VDT05EX01TO1xuXG4vKiogRGVib3VuY2Ugd2luZG93IGZvciBkZXYtcGx1Z2luIGBkaXN0L2Agd2F0Y2hlciAoIzExNTkgUFIzKS4gVml0ZVxuICogIHdyaXRlcyA0LTUgZmlsZXMgd2l0aGluIH4xMDBtcyBvbiBhIHNpbmdsZSByZWJ1aWxkOyAzMDBtcyBjb2xsYXBzZXNcbiAqICB0aGUgYnVyc3QgaW50byBvbmUgcHVibGlzaC4gKi9cbmV4cG9ydCBjb25zdCBERVZfUExVR0lOX1dBVENIX0RFQk9VTkNFX01TID0gMzAwO1xuXG4vKiogSGFyZCBjYXAgb24gaG93IGxvbmcgdGhlIHN0YXJ0dXAtZmFpbHVyZSBwYXRoIHdhaXRzIGZvclxuICogIGBodHRwU2VydmVyLmNsb3NlKClgIHRvIGRyYWluIGluLWZsaWdodCBjb25uZWN0aW9ucyBiZWZvcmVcbiAqICBmb3JjaW5nIGBwcm9jZXNzLmV4aXQoMSlgLiBTU0Ugc3RyZWFtcyArIFdlYlNvY2tldCB1cGdyYWRlcyBob2xkXG4gKiAgY29ubmVjdGlvbnMgb3BlbiBpbmRlZmluaXRlbHksIHNvIHRoZSBncmFjZWZ1bCBjbG9zZSBhbG9uZSBpc24ndFxuICogIGEgZmFpbC1mYXN0IGd1YXJhbnRlZS4gKi9cbmV4cG9ydCBjb25zdCBTVEFSVFVQX0ZBSUxVUkVfRk9SQ0VfRVhJVF9NUyA9IDUgKiBPTkVfU0VDT05EX01TO1xuXG4vKiogSGVhdnkgc3VicHJvY2VzcyB3b3JrIChsaWJyZW9mZmljZSBjb252ZXJzaW9uLCBldGMuKSAqL1xuZXhwb3J0IGNvbnN0IFNVQlBST0NFU1NfV09SS19USU1FT1VUX01TID0gT05FX01JTlVURV9NUztcblxuLyoqIENMSSBzdWJwcm9jZXNzIHRpbWVvdXQgKGNsYXVkZSAtcCBmb3Igc3VtbWFyaXphdGlvbiwgZXRjLikgKi9cbmV4cG9ydCBjb25zdCBDTElfU1VCUFJPQ0VTU19USU1FT1VUX01TID0gNSAqIE9ORV9NSU5VVEVfTVM7XG5cbi8qKiBNYXhpbXVtIG9uZS1zaG90IG5vdGlmaWNhdGlvbiBkZWxheSAqL1xuZXhwb3J0IGNvbnN0IE1BWF9OT1RJRklDQVRJT05fREVMQVlfU0VDID0gM182MDA7IC8vIDEgaG91ciBpbiBzZWNvbmRzXG4iLCAiLy8gV29ya3NwYWNlIHJvb3QgcmVzb2x1dGlvbiBmb3IgaG9vayBzY3JpcHRzLlxuLy9cbi8vIGBDTEFVREVfUFJPSkVDVF9ESVJgIGlzIHNldCBieSBDbGF1ZGUgQ0xJIHRvIHRoZSB3b3Jrc3BhY2Ugcm9vdFxuLy8gdGhlIGhvb2sgZmlyZWQgYWdhaW5zdCBcdTIwMTQgdGhpcyBpcyB0aGUgdmFsdWUgd2UgdHJ1c3QgYXQgcnVudGltZS5cbi8vIEZhbGxpbmcgYmFjayB0byBgfi9tdWxtb2NsYXVkZWAga2VlcHMgdGhlIHNjcmlwdCByb2J1c3Qgd2hlbiBydW5cbi8vIG91dHNpZGUgQ0xJIGNvbnRleHQgKHRlc3QgaGFybmVzcywgbWFudWFsIHJlcHJvZHVjdGlvbikuXG5cbmltcG9ydCB7IGhvbWVkaXIgfSBmcm9tIFwibm9kZTpvc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcIm5vZGU6cGF0aFwiO1xuXG5leHBvcnQgZnVuY3Rpb24gd29ya3NwYWNlUm9vdCgpOiBzdHJpbmcge1xuICByZXR1cm4gcHJvY2Vzcy5lbnYuQ0xBVURFX1BST0pFQ1RfRElSID8/IHBhdGguam9pbihob21lZGlyKCksIFwibXVsbW9jbGF1ZGVcIik7XG59XG4iLCAiLy8gUmVhZCB0aGUgSlNPTiBQb3N0VG9vbFVzZSBwYXlsb2FkIENsYXVkZSBDTEkgc3RyZWFtcyBvbiBzdGRpbi5cbi8vIFJldHVybnMgdGhlIHBhcnNlZCBwYXlsb2FkIG9yIG51bGwgd2hlbiB0aGUgaW5wdXQgaXMgZW1wdHkgL1xuLy8gbWFsZm9ybWVkIFx1MjAxNCB0aGUgZGlzcGF0Y2hlciB0cmVhdHMgbnVsbCBhcyBhIGZhc3Qgbm8tb3Agc28gYSBob29rXG4vLyBmaXJlZCB3aXRoIG5vIGJvZHkgbmV2ZXIgY3Jhc2hlcyB0aGUgdXNlcidzIHRvb2wgdHVybi5cblxuZXhwb3J0IGludGVyZmFjZSBIb29rUGF5bG9hZCB7XG4gIHRvb2xfbmFtZT86IHVua25vd247XG4gIHRvb2xfaW5wdXQ/OiB7XG4gICAgZmlsZV9wYXRoPzogdW5rbm93bjtcbiAgICBjb21tYW5kPzogdW5rbm93bjtcbiAgICBba2V5OiBzdHJpbmddOiB1bmtub3duO1xuICB9O1xuICB0b29sX3Jlc3BvbnNlPzoge1xuICAgIGZpbGVQYXRoPzogdW5rbm93bjtcbiAgICBba2V5OiBzdHJpbmddOiB1bmtub3duO1xuICB9O1xuICBzZXNzaW9uX2lkPzogdW5rbm93bjtcbiAgW2tleTogc3RyaW5nXTogdW5rbm93bjtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRIb29rUGF5bG9hZCgpOiBQcm9taXNlPEhvb2tQYXlsb2FkIHwgbnVsbD4ge1xuICBjb25zdCBjaHVua3M6IEJ1ZmZlcltdID0gW107XG4gIGZvciBhd2FpdCAoY29uc3QgY2h1bmsgb2YgcHJvY2Vzcy5zdGRpbikge1xuICAgIGNodW5rcy5wdXNoKHR5cGVvZiBjaHVuayA9PT0gXCJzdHJpbmdcIiA/IEJ1ZmZlci5mcm9tKGNodW5rKSA6IGNodW5rKTtcbiAgfVxuICBjb25zdCByYXcgPSBCdWZmZXIuY29uY2F0KGNodW5rcykudG9TdHJpbmcoXCJ1dGYtOFwiKTtcbiAgaWYgKCFyYXcudHJpbSgpKSByZXR1cm4gbnVsbDtcbiAgdHJ5IHtcbiAgICByZXR1cm4gSlNPTi5wYXJzZShyYXcpIGFzIEhvb2tQYXlsb2FkO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxufVxuXG4vLyBEaWZmZXJlbnQgdG9vbHMgc3VyZmFjZSB0aGUgcGF0aCB1bmRlciBkaWZmZXJlbnQga2V5cyAoV3JpdGUvRWRpdFxuLy8gdXNlIHRvb2xfaW5wdXQuZmlsZV9wYXRoOyB0aGUgcmVzcG9uc2Ugc2hhcGUgdXNlcyBmaWxlUGF0aCkuIFRoZVxuLy8gaGVscGVyIGNoZWNrcyBib3RoIGRlZmVuc2l2ZWx5IHNvIGhhbmRsZXJzIGRvbid0IG5lZWQgdG8uXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdEZpbGVQYXRoKHBheWxvYWQ6IEhvb2tQYXlsb2FkKTogc3RyaW5nIHtcbiAgY29uc3QgZnJvbUlucHV0ID0gcGF5bG9hZC50b29sX2lucHV0Py5maWxlX3BhdGg7XG4gIGlmICh0eXBlb2YgZnJvbUlucHV0ID09PSBcInN0cmluZ1wiKSByZXR1cm4gZnJvbUlucHV0O1xuICBjb25zdCBmcm9tUmVzcG9uc2UgPSBwYXlsb2FkLnRvb2xfcmVzcG9uc2U/LmZpbGVQYXRoO1xuICBpZiAodHlwZW9mIGZyb21SZXNwb25zZSA9PT0gXCJzdHJpbmdcIikgcmV0dXJuIGZyb21SZXNwb25zZTtcbiAgcmV0dXJuIFwiXCI7XG59XG5cbi8vIEJhc2ggdG9vbCBjYWxscyBwdXQgdGhlIHNoZWxsIGNvbW1hbmQgc3RyaW5nIGluIHRvb2xfaW5wdXQuY29tbWFuZC5cbi8vIEVtcHR5IHN0cmluZyB3aGVuIHRoZSBwYXlsb2FkIGlzIGEgbm9uLUJhc2ggdG9vbCBvciBtYWxmb3JtZWQuXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdENvbW1hbmQocGF5bG9hZDogSG9va1BheWxvYWQpOiBzdHJpbmcge1xuICBjb25zdCBjb21tYW5kID0gcGF5bG9hZC50b29sX2lucHV0Py5jb21tYW5kO1xuICByZXR1cm4gdHlwZW9mIGNvbW1hbmQgPT09IFwic3RyaW5nXCIgPyBjb21tYW5kIDogXCJcIjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3RUb29sTmFtZShwYXlsb2FkOiBIb29rUGF5bG9hZCk6IHN0cmluZyB7XG4gIHJldHVybiB0eXBlb2YgcGF5bG9hZC50b29sX25hbWUgPT09IFwic3RyaW5nXCIgPyBwYXlsb2FkLnRvb2xfbmFtZSA6IFwiXCI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0U2Vzc2lvbklkKHBheWxvYWQ6IEhvb2tQYXlsb2FkKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3Qgc2Vzc2lvbklkID0gcGF5bG9hZC5zZXNzaW9uX2lkO1xuICByZXR1cm4gdHlwZW9mIHNlc3Npb25JZCA9PT0gXCJzdHJpbmdcIiAmJiBzZXNzaW9uSWQubGVuZ3RoID4gMCA/IHNlc3Npb25JZCA6IHVuZGVmaW5lZDtcbn1cbiIsICIvLyBDb25maWctcmVmcmVzaCBoYW5kbGVyIFx1MjAxNCBmaXJlcyBhZnRlciBXcml0ZS9FZGl0IG9uIGZpbGVzIHRoYXRcbi8vIGRyaXZlIHdvcmtzcGFjZSBzdGF0ZSB0aGUgcGFyZW50IHNlcnZlciBob3QtcmVsb2Fkczpcbi8vXG4vLyAgIDx3cz4vLmNsYXVkZS9za2lsbHMvPHNsdWc+L1NLSUxMLm1kICAgKG1hbnVhbCBlZGl0cyB0byBjYW5vbmljYWwgc2tpbGxzKVxuLy8gICA8d3M+L2NvbmZpZy9zY2hlZHVsZXIvdGFza3MuanNvbiAgICAgICh1c2VyLXRhc2sgc2NoZWR1bGVyIGNvbmZpZylcbi8vXG4vLyBQT1NUcyAvYXBpL2NvbmZpZy9yZWZyZXNoIHNvIHRoZSBjaGFuZ2UgYWN0aXZhdGVzIHdpdGhvdXQgYSBzZXJ2ZXJcbi8vIHJlc3RhcnQuIE1pZ3JhdGVkIGZyb20gYHNlcnZlci93b3Jrc3BhY2UvY29uZmlnLXJlZnJlc2gvaG9vay5tanNgLlxuLy9cbi8vIE5PVEUgb24gc3RhZ2luZyBza2lsbHMgKGBkYXRhL3NraWxscy88c2x1Zz4vU0tJTEwubWRgKTpcbi8vIFRoZSBzdGFnaW5nIHBhdGggaXMgSU5URU5USU9OQUxMWSBleGNsdWRlZCBmcm9tIFBBVFRFUk5TIGhlcmUuXG4vLyBSZWZyZXNoaW5nIG9uIHRoZSBzdGFnaW5nIHdyaXRlIHdvdWxkIHJhY2Ugd2l0aCBgc2tpbGxCcmlkZ2VgJ3Ncbi8vIG1pcnJvciBjb3B5IFx1MjAxNCBgL2FwaS9jb25maWcvcmVmcmVzaGAgY291bGQgbGFuZCBiZWZvcmUgdGhlIGNhbm9uaWNhbFxuLy8gZmlsZSBpcyB3cml0dGVuLCBsZWF2aW5nIGEgZnJlc2ggc2tpbGwgdW5yZWdpc3RlcmVkIHVudGlsIHRoZSBuZXh0XG4vLyByZXN0YXJ0LiBgc2tpbGxCcmlkZ2VgIG93bnMgaXRzIG93biByZWZyZXNoIHRyaWdnZXIgYW5kIGZpcmVzIGl0XG4vLyBBRlRFUiB0aGUgbWlycm9yIHN1Y2NlZWRzLCBzbyB0aGUgb3JkZXJpbmcgaXMgZGV0ZXJtaW5pc3RpYy5cblxuaW1wb3J0IHsgYnVpbGRBdXRoUG9zdCwgc2FmZVBvc3QgfSBmcm9tIFwiLi4vc2hhcmVkL3NpZGVjYXIuanNcIjtcbmltcG9ydCB0eXBlIHsgSG9va1BheWxvYWQgfSBmcm9tIFwiLi4vc2hhcmVkL3N0ZGluLmpzXCI7XG5pbXBvcnQgeyBleHRyYWN0RmlsZVBhdGgsIGV4dHJhY3RUb29sTmFtZSB9IGZyb20gXCIuLi9zaGFyZWQvc3RkaW4uanNcIjtcblxuLy8gRWFjaCBwYXR0ZXJuIGlzIG1hdGNoZWQgYWdhaW5zdCB0aGUgYWJzb2x1dGUgcGF0aCB0aGUgQ0xJXG4vLyBkZWxpdmVyZWQuIFdpbmRvd3MgcGF0aCBzZXBhcmF0b3JzIGFyZSB0b2xlcmF0ZWQgZm9yIGNyb3NzLVxuLy8gcGxhdGZvcm0gcm9idXN0bmVzcyBldmVuIHRob3VnaCB0aGUgaG9zdCBpcyBjdXJyZW50bHkgZGFyd2luIC9cbi8vIGxpbnV4IG9ubHkuXG5jb25zdCBQQVRURVJOUyA9IFsvW1xcXFwvXVxcLmNsYXVkZVtcXFxcL11za2lsbHNbXFxcXC9dW15cXFxcL10rW1xcXFwvXVNLSUxMXFwubWQkLywgL1tcXFxcL11jb25maWdbXFxcXC9dc2NoZWR1bGVyW1xcXFwvXXRhc2tzXFwuanNvbiQvXTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZUNvbmZpZ1JlZnJlc2gocGF5bG9hZDogSG9va1BheWxvYWQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgdG9vbCA9IGV4dHJhY3RUb29sTmFtZShwYXlsb2FkKTtcbiAgaWYgKHRvb2wgIT09IFwiV3JpdGVcIiAmJiB0b29sICE9PSBcIkVkaXRcIikgcmV0dXJuO1xuXG4gIGNvbnN0IGZpbGVQYXRoID0gZXh0cmFjdEZpbGVQYXRoKHBheWxvYWQpO1xuICBpZiAoIWZpbGVQYXRoKSByZXR1cm47XG4gIGlmICghUEFUVEVSTlMuc29tZSgocGF0dGVybikgPT4gcGF0dGVybi50ZXN0KGZpbGVQYXRoKSkpIHJldHVybjtcblxuICBjb25zdCByZXEgPSBidWlsZEF1dGhQb3N0KFwiL2FwaS9jb25maWcvcmVmcmVzaFwiKTtcbiAgYXdhaXQgc2FmZVBvc3QocmVxKTtcbn1cbiIsICIvLyBTa2lsbC1icmlkZ2UgaGFuZGxlciBcdTIwMTQgYWdlbnQgd3JpdGVzIHNraWxsIGRyYWZ0cyB0b1xuLy8gYGRhdGEvc2tpbGxzLzxzbHVnPi9TS0lMTC5tZGAgKGEgcGxhaW4gZGF0YSBkaXIsIG5vIHBlcm1pc3Npb25cbi8vIHNwZWNpYWwgY2FzZSkgYW5kIHRoaXMgaG9vayBtaXJyb3JzIHRoZW0gaW50b1xuLy8gYC5jbGF1ZGUvc2tpbGxzLzxzbHVnPi9TS0lMTC5tZGAgc28gQ2xhdWRlIENMSSdzIHNraWxsIGRpc2NvdmVyeVxuLy8gcGlja3MgdGhlbSB1cC5cbi8vXG4vLyBXaHkgYSBicmlkZ2U6IENsYXVkZSBDb2RlJ3MgcGVybWlzc2lvbiBzeXN0ZW0gZ2l2ZXMgYC5jbGF1ZGUvYFxuLy8gc3RyaWN0ZXIgc2NydXRpbnkgdGhhbiBvcmRpbmFyeSBjd2Qgc3ViZGlycyAodGhlIGRpciBob2xkcyB0aGVcbi8vIGFnZW50J3Mgb3duIHNraWxscyAvIGhvb2tzIC8gc2V0dGluZ3MsIHNvIHdyaXRlcyB0aGVyZSBhcmUgYVxuLy8gc2VsZi1tb2RpZmljYXRpb24gcmlzaykuIEV2ZW4gd2l0aCBleHBsaWNpdCBgV3JpdGUoLmNsYXVkZS8qKilgXG4vLyBhbGxvdyBydWxlcyBpbiB3b3Jrc3BhY2Ugc2V0dGluZ3MuanNvbiwgd3JpdGVzIHByb21wdCBcdTIwMTQgYW5kIHRoZVxuLy8gaG9zdCBHVUkgaGFzIG5vIHN1cmZhY2UgdG8gYW5zd2VyIHRoZSBwcm9tcHQuIFJvdXRpbmcgd3JpdGVzXG4vLyB0aHJvdWdoIGBkYXRhL3NraWxscy9gIGF2b2lkcyB0aGUgZ2F0ZTsgdGhpcyBob29rIChhIHJlZ3VsYXJcbi8vIHN1YnByb2Nlc3MsIE5PVCBhIENsYXVkZSB0b29sIGNhbGwpIGRvZXMgdGhlIG1pcnJvciBjb3B5IGFuZCBpc1xuLy8gbm90IHN1YmplY3QgdG8gdGhlIGdhdGUuXG4vL1xuLy8gV2h5IG1pcnJvciBhcyBgPHNsdWc+L1NLSUxMLm1kYCAobm90IGZsYXQgYDxzbHVnPi5tZGApOiBDbGF1ZGVcbi8vIENMSSdzIGNhbm9uaWNhbCBza2lsbCBsYXlvdXQgSVMgdGhlIG5lc3RlZCBmb3JtLCBhbmQgdGhlIGFnZW50XG4vLyBuYXR1cmFsbHkgd3JpdGVzIHRoYXQgc2hhcGUuIEEgZmxhdCBzdGFnaW5nIHBhdGggZm9yY2VkIHRoZSBhZ2VudFxuLy8gdG8gcmVhc29uIGFnYWluc3QgaXRzIG93biB0cmFpbmluZywgbWlzc2VkIHRoZSByZWdleCwgYW5kIHRoZVxuLy8gbWlycm9yIHNpbGVudGx5IG5ldmVyIGZpcmVkLiBNaXJyb3JpbmcgMToxIGtlZXBzIHRoZSBwYXRoIG1hdGhcbi8vIHRyaXZpYWwgZm9yIGJvdGggc2lkZXMuXG4vL1xuLy8gTWlycm9yIG9wZXJhdGlvbnM6XG4vL1xuLy8gICBXcml0ZS9FZGl0IGRhdGEvc2tpbGxzLzxzbHVnPi9TS0lMTC5tZFxuLy8gICAgIFx1MjE5MiBjb3B5IGNvbnRlbnQgdG8gLmNsYXVkZS9za2lsbHMvPHNsdWc+L1NLSUxMLm1kXG4vLyAgICAgICAoY3JlYXRlcyB0aGUgcGFyZW50IGRpciBvbiBmaXJzdCBpbnN0YWxsKVxuLy9cbi8vICAgQmFzaCBcInJtIC1yZiBkYXRhL3NraWxscy88c2x1Zz4vXCIgb3IgXCJybSAtcmYgZGF0YS9za2lsbHMvPHNsdWc+XCJcbi8vICAgICBcdTIxOTIgcm0gLXJmIC5jbGF1ZGUvc2tpbGxzLzxzbHVnPi9cbi8vICAgICAgIChyZWdleC1tYXRjaGVkIHNvIHRoZSBhZ2VudCdzIGludGVudCBpcyB1bmFtYmlndW91cztcbi8vICAgICAgICBhIGJ1bGsgYHJtIC1yZiBkYXRhL3NraWxscy9gIG9yIHdpbGRjYXJkcyBhcmUgaW50ZW50aW9uYWxseVxuLy8gICAgICAgIE5PVCBtaXJyb3JlZCB0byBhdm9pZCBtYXNzIGRlbGV0aW9uIHN1cnByaXNlcylcblxuaW1wb3J0IHsgbWtkaXJTeW5jLCByZWFkRmlsZVN5bmMsIHJlbmFtZVN5bmMsIHJtU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwibm9kZTpwYXRoXCI7XG5pbXBvcnQgeyBidWlsZEF1dGhQb3N0LCBzYWZlUG9zdCwgc2VydmVyTG9nIH0gZnJvbSBcIi4uL3NoYXJlZC9zaWRlY2FyLmpzXCI7XG5pbXBvcnQgdHlwZSB7IEhvb2tQYXlsb2FkIH0gZnJvbSBcIi4uL3NoYXJlZC9zdGRpbi5qc1wiO1xuaW1wb3J0IHsgZXh0cmFjdENvbW1hbmQsIGV4dHJhY3RGaWxlUGF0aCwgZXh0cmFjdFRvb2xOYW1lIH0gZnJvbSBcIi4uL3NoYXJlZC9zdGRpbi5qc1wiO1xuaW1wb3J0IHsgd29ya3NwYWNlUm9vdCB9IGZyb20gXCIuLi9zaGFyZWQvd29ya3NwYWNlLmpzXCI7XG5pbXBvcnQgeyBlcnJvck1lc3NhZ2UgfSBmcm9tIFwiLi4vLi4vLi4vdXRpbHMvZXJyb3JzLmpzXCI7XG5cbmNvbnN0IERBVEFfU0tJTExTX0RJUiA9IHBhdGguam9pbihcImRhdGFcIiwgXCJza2lsbHNcIik7XG5jb25zdCBDTEFVREVfU0tJTExTX0RJUiA9IHBhdGguam9pbihcIi5jbGF1ZGVcIiwgXCJza2lsbHNcIik7XG5jb25zdCBTS0lMTF9GSUxFTkFNRSA9IFwiU0tJTEwubWRcIjtcblxuLy8gU2x1Z3MgZm9sbG93IENsYXVkZSBDb2RlJ3Mgc2tpbGwtbmFtZSBjb252ZW50aW9uOiBsb3dlcmNhc2UgQVNDSUlcbi8vIGxldHRlcnMgLyBkaWdpdHMgd2l0aCBzaW5nbGUtaHlwaGVuIHNlcGFyYXRvcnMuIE1hdGNoaW5nIGlzXG4vLyBzdHJpY3Qgc28gYSB0eXBvIG9yIHBhdGggdHJhdmVyc2FsIGF0dGVtcHQgKGAuLi9mb29gKSBuZXZlclxuLy8gcmVhY2hlcyB0aGUgZGVzdGluYXRpb24gcGF0aCBtYXRoLlxuLy9cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBzZWN1cml0eS9kZXRlY3QtdW5zYWZlLXJlZ2V4IC0tIGlucHV0IGlzIGFsd2F5cyBhIGJhc2VuYW1lIHNsaWNlIFx1MjI2NCA2NCBjaGFycywgc28gdGhlIHRoZW9yZXRpY2FsIHdvcnN0LWNhc2UgYmFja3RyYWNraW5nIGlzIGJvdW5kZWQ7IHRoaXMgaXMgdGhlIGNhbm9uaWNhbCBrZWJhYi1jYXNlIHBhdHRlcm4gdXNlZCBhY3Jvc3MgdGhlIHNraWxsIHRvb2xjaGFpbi5cbmNvbnN0IFNMVUdfUkUgPSAvXlthLXowLTldKygtW2EtejAtOV0rKSokLztcblxuLy8gYHJtIC1yZiBkYXRhL3NraWxscy88c2x1Zz5gIHJlZ2V4LiBDYXB0dXJlcyB0aGUgZmxhZyBydW4gYXNcbi8vIGBtYXRjaFsxXWAgc28gdGhlIGNhbGxlciBjYW4gcG9zdC12YWxpZGF0ZSB0aGF0IHRoZSB1c2VyIHBhc3NlZFxuLy8gYSByZWN1cnNpdmUgZmxhZyAoYC1yYCwgYC1SYCwgYC1yZmAsIGAtZnJgLCBcdTIwMjYpLiBUb2xlcmF0ZXMgb3B0aW9uYWxcbi8vIHRyYWlsaW5nIHNsYXNoIGFuZCBvcHRpb25hbCBxdW90aW5nIGFyb3VuZCB0aGUgcGF0aC4gQSBsaXRlcmFsXG4vLyBgcm0gLXJmIGRhdGEvc2tpbGxzYCAodGhlIHBhcmVudCBkaXIgaXRzZWxmKSBvciBwYXRocyB3aXRoXG4vLyB3aWxkY2FyZHMgLyBzaGVsbCBleHBhbnNpb24gYXJlIGludGVudGlvbmFsbHkgTk9UIG1hdGNoZWQuXG4vL1xuLy8gUmVjdXJzaXZlLWZsYWcgZW5mb3JjZW1lbnQgKENvZGV4IHJldmlldyBvbiB0aGlzIFBSKTogcGxhaW4gYHJtYFxuLy8gb3IgYHJtIC1mYCBjYW5ub3QgcmVtb3ZlIGEgZGlyZWN0b3J5LCBzbyB0aGUgc3RhZ2luZyBkZWxldGUgZmFpbHNcbi8vIHNpbGVudGx5IHdoaWxlIHRoZSBjYW5vbmljYWwgZGVsZXRlIHN0aWxsIHJ1bnMgXHUyMDE0IGRlc3luY2luZyB0aGVcbi8vIHR3byB0cmVlcy4gUmVxdWlyaW5nIGF0IGxlYXN0IG9uZSBgcmAgLyBgUmAgaW4gdGhlIGZsYWdzIHJlamVjdHNcbi8vIHRob3NlIGZvcm1zIG91dHJpZ2h0LlxuLy9cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBzZWN1cml0eS9kZXRlY3QtdW5zYWZlLXJlZ2V4IC0tIHRoZSBgKC1bYS16MC05XSspKmAgc2x1ZyBjbGF1c2UgaXMgYm91bmRlZCBieSB0aGUgcGF0aCB0YWlsIGFuZCB0aGUgaW5wdXQgaXMgYSBzaW5nbGUtbGluZSBCYXNoIGNvbW1hbmQgQ2xhdWRlIENMSSBjYXB0dXJlZDsgbm8gcGF0aG9sb2dpY2FsIGJhY2t0cmFja2luZyBzdXJmYWNlLlxuY29uc3QgUk1fUkUgPSAvXlxccypybVxccysoKD86LVthLXpBLVpdK1xccyspKylbJ1wiXT9kYXRhXFwvc2tpbGxzXFwvKFthLXowLTktXSspXFwvP1snXCJdP1xccyokLztcbmNvbnN0IFJFQ1VSU0lWRV9GTEFHX1JFID0gL1tyUl0vO1xuXG4vLyBQdXJlIGhlbHBlcnMgZXhwb3J0ZWQgZm9yIHVuaXQgdGVzdGluZy4gU291cmNlIHBhdGhzIHN0YXkgcmVsYXRpdmVcbi8vIHRvIHRoZSB3b3Jrc3BhY2Ugcm9vdCByZXNvbHZlZCBhdCBjYWxsIHRpbWUgc28gdGhlIGhhbmRsZXIgaXNcbi8vIHNhZmUgdG8gcnVuIGZyb20gYW55IGN3ZC5cblxuZXhwb3J0IGZ1bmN0aW9uIGRhdGFTa2lsbERpcihzbHVnOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gcGF0aC5qb2luKHdvcmtzcGFjZVJvb3QoKSwgREFUQV9TS0lMTFNfRElSLCBzbHVnKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRhdGFTa2lsbEZpbGVQYXRoKHNsdWc6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBwYXRoLmpvaW4oZGF0YVNraWxsRGlyKHNsdWcpLCBTS0lMTF9GSUxFTkFNRSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjbGF1ZGVTa2lsbERpcihzbHVnOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gcGF0aC5qb2luKHdvcmtzcGFjZVJvb3QoKSwgQ0xBVURFX1NLSUxMU19ESVIsIHNsdWcpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY2xhdWRlU2tpbGxGaWxlUGF0aChzbHVnOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gcGF0aC5qb2luKGNsYXVkZVNraWxsRGlyKHNsdWcpLCBTS0lMTF9GSUxFTkFNRSk7XG59XG5cbi8vIEV4dHJhY3QgdGhlIHNsdWcgZnJvbSBhIFdyaXRlL0VkaXQgb24gYVxuLy8gYGRhdGEvc2tpbGxzLzxzbHVnPi9TS0lMTC5tZGAgcGF0aC4gUmV0dXJucyBudWxsIHdoZW46XG4vLyAgIC0gdGhlIHBhdGggZG9lc24ndCBzaXQgZGlyZWN0bHkgdW5kZXIgZGF0YS9za2lsbHMvPHNsdWc+L1xuLy8gICAtIHRoZSBmaWxlbmFtZSBpc24ndCBTS0lMTC5tZFxuLy8gICAtIHRoZSBzbHVnIGlzbid0IGEgdmFsaWQga2ViYWItY2FzZSBpZGVudGlmaWVyXG4vL1xuLy8gU2libGluZyBmaWxlcyBpbiB0aGUgc2FtZSBkaXIgKGUuZy4gZGF0YS9za2lsbHMvPHNsdWc+L1JFQURNRS5tZFxuLy8gb3IgZGF0YS9za2lsbHMvPHNsdWc+L2Fzc2V0cy9mb28ucG5nKSBhcmUgaW50ZW50aW9uYWxseSBOT1Rcbi8vIGJyaWRnZWQgXHUyMDE0IG9ubHkgdGhlIGNhbm9uaWNhbCBTS0lMTC5tZCBjcm9zc2VzIG92ZXIuIFNraWxsIGF1dGhvcnNcbi8vIGNhbiBrZWVwIGV4dHJhIG1hdGVyaWFsIHN0YWdpbmctc2lkZSB1bnRpbCB0aGV5IGRlY2lkZSB3aGF0XG4vLyBiZWxvbmdzIGluIHRoZSBidW5kbGUuXG5leHBvcnQgZnVuY3Rpb24gc2x1Z0Zyb21EYXRhUGF0aChmaWxlUGF0aDogc3RyaW5nKTogc3RyaW5nIHwgbnVsbCB7XG4gIGNvbnN0IHJvb3QgPSB3b3Jrc3BhY2VSb290KCk7XG4gIGNvbnN0IHN0YWdpbmcgPSBwYXRoLmpvaW4ocm9vdCwgREFUQV9TS0lMTFNfRElSKTtcbiAgY29uc3QgcmVsID0gcGF0aC5yZWxhdGl2ZShzdGFnaW5nLCBmaWxlUGF0aCk7XG4gIGlmICghcmVsIHx8IHJlbC5zdGFydHNXaXRoKFwiLi5cIikpIHJldHVybiBudWxsO1xuICAvLyBFeHBlY3QgZXhhY3RseSBgPHNsdWc+L1NLSUxMLm1kYCBcdTIwMTQgdHdvIHNlZ21lbnRzIGRlZXAuXG4gIGNvbnN0IHNlZ21lbnRzID0gcmVsLnNwbGl0KHBhdGguc2VwKTtcbiAgaWYgKHNlZ21lbnRzLmxlbmd0aCAhPT0gMikgcmV0dXJuIG51bGw7XG4gIGNvbnN0IFtzbHVnLCBiYXNlbmFtZV0gPSBzZWdtZW50cztcbiAgaWYgKGJhc2VuYW1lICE9PSBTS0lMTF9GSUxFTkFNRSkgcmV0dXJuIG51bGw7XG4gIHJldHVybiBTTFVHX1JFLnRlc3Qoc2x1ZykgPyBzbHVnIDogbnVsbDtcbn1cblxuLy8gRXh0cmFjdCB0aGUgc2x1ZyBmcm9tIGEgQmFzaCBgcm0gLXJmIGRhdGEvc2tpbGxzLzxzbHVnPi9gIGNvbW1hbmQuXG4vLyBSZXR1cm5zIG51bGwgb24gYW55IG1pc21hdGNoIFx1MjAxNCB3aWxkY2FyZHMsIHBhdGhzIG91dHNpZGUgdGhlXG4vLyBzdGFnaW5nIGRpciwgb3Igbm9uLXJlY3Vyc2l2ZSBgcm1gIC8gYHJtIC1mYCAod2hpY2ggY2FuJ3QgZGVsZXRlXG4vLyB0aGUgc3RhZ2luZyBkaXIgYW55d2F5LCBzbyBtaXJyb3Jpbmcgd291bGQgZGVzeW5jKSBhcmUgYWxsXG4vLyBpbnRlbnRpb25hbGx5IHJlamVjdGVkLlxuZXhwb3J0IGZ1bmN0aW9uIHNsdWdGcm9tUm1Db21tYW5kKGNvbW1hbmQ6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuICBjb25zdCBtYXRjaCA9IFJNX1JFLmV4ZWMoY29tbWFuZCk7XG4gIGlmICghbWF0Y2gpIHJldHVybiBudWxsO1xuICBjb25zdCBbLCBmbGFncywgc2x1Z10gPSBtYXRjaDtcbiAgaWYgKCFSRUNVUlNJVkVfRkxBR19SRS50ZXN0KGZsYWdzKSkgcmV0dXJuIG51bGw7XG4gIHJldHVybiBTTFVHX1JFLnRlc3Qoc2x1ZykgPyBzbHVnIDogbnVsbDtcbn1cblxuLy8gQXRvbWljIG1pcnJvcjogd3JpdGUgdG8gYSB0bXAgZmlsZSBpbiB0aGUgZGVzdGluYXRpb24gZGlyLCB0aGVuXG4vLyByZW5hbWUgb250byB0aGUgY2Fub25pY2FsIHBhdGguIGBmcy5yZW5hbWVTeW5jYCBpcyBhdG9taWMgb24gUE9TSVhcbi8vIHdoZW4gc291cmNlICsgZGVzdGluYXRpb24gc2hhcmUgYSBmaWxlc3lzdGVtIChhbHdheXMgdHJ1ZSBoZXJlIFx1MjAxNFxuLy8gYm90aCBhcmUgaW5zaWRlIGAuY2xhdWRlL3NraWxscy88c2x1Zz4vYCkuIElmIHRoZSBob29rIGlzIGtpbGxlZFxuLy8gbWlkLXdyaXRlLCB0aGUgaGFsZi13cml0dGVuIHRtcCBmaWxlIGlzIGxlZnQgYmVoaW5kIChoYXJtbGVzcyxcbi8vIG5ldmVyIHJlYWQpIGFuZCBTS0lMTC5tZCBzdGlsbCBoYXMgaXRzIHByZXZpb3VzIGNvbnRlbnRzIFx1MjAxNCBDbGF1ZGVcbi8vIENMSSdzIHNraWxsIGRpc2NvdmVyeSBuZXZlciBzZWVzIGEgdG9ybiBmaWxlLiBDb2RlUmFiYml0IHJldmlld1xuLy8gb24gUFIgIzEyOTguXG5mdW5jdGlvbiBtaXJyb3JXcml0ZShzbHVnOiBzdHJpbmcpOiB2b2lkIHtcbiAgY29uc3QgY29udGVudCA9IHJlYWRGaWxlU3luYyhkYXRhU2tpbGxGaWxlUGF0aChzbHVnKSwgXCJ1dGYtOFwiKTtcbiAgY29uc3QgZGVzdERpciA9IGNsYXVkZVNraWxsRGlyKHNsdWcpO1xuICBta2RpclN5bmMoZGVzdERpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gIGNvbnN0IGRlc3QgPSBjbGF1ZGVTa2lsbEZpbGVQYXRoKHNsdWcpO1xuICBjb25zdCB0bXAgPSBwYXRoLmpvaW4oZGVzdERpciwgYC5TS0lMTC5tZC4ke3Byb2Nlc3MucGlkfS50bXBgKTtcbiAgd3JpdGVGaWxlU3luYyh0bXAsIGNvbnRlbnQsIFwidXRmLThcIik7XG4gIHJlbmFtZVN5bmModG1wLCBkZXN0KTtcbn1cblxuZnVuY3Rpb24gbWlycm9yRGVsZXRlKHNsdWc6IHN0cmluZyk6IHZvaWQge1xuICBybVN5bmMoY2xhdWRlU2tpbGxEaXIoc2x1ZyksIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbn1cblxuLy8gYGNvbmZpZ1JlZnJlc2hgIHVzZWQgdG8gZmFuIHRoaXMgb3V0IGZvciB1cyBhcyBhIHNpYmxpbmcgaGFuZGxlcixcbi8vIGJ1dCBydW5uaW5nIGl0IGluIHBhcmFsbGVsIHdpdGggdGhlIG1pcnJvciByYWNlJ2Q6IHRoZVxuLy8gYC9hcGkvY29uZmlnL3JlZnJlc2hgIFBPU1QgY291bGQgbGFuZCBiZWZvcmUgdGhlIGNhbm9uaWNhbFxuLy8gYC5jbGF1ZGUvc2tpbGxzLzxzbHVnPi9TS0lMTC5tZGAgZXhpc3RlZCBvbiBkaXNrLCBsZWF2aW5nIGEgZnJlc2hcbi8vIHNraWxsIHVucmVnaXN0ZXJlZCB1bnRpbCB0aGUgbmV4dCByZXN0YXJ0LiBgc2tpbGxCcmlkZ2VgIG5vd1xuLy8gZmlyZXMgdGhlIHJlZnJlc2ggaXRzZWxmLCBBTFdBWVMgYWZ0ZXIgYSBzdWNjZXNzZnVsIG1pcnJvciAob3Jcbi8vIGRlbGV0ZSksIHNvIG9yZGVyaW5nIGlzIGRldGVybWluaXN0aWMgKENvZGV4IHJldmlldyBvbiB0aGlzIFBSKS5cbmFzeW5jIGZ1bmN0aW9uIHJlZnJlc2hDb25maWcoKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IHNhZmVQb3N0KGJ1aWxkQXV0aFBvc3QoXCIvYXBpL2NvbmZpZy9yZWZyZXNoXCIpKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gaGFuZGxlV3JpdGVPckVkaXQocGF5bG9hZDogSG9va1BheWxvYWQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgZmlsZVBhdGggPSBleHRyYWN0RmlsZVBhdGgocGF5bG9hZCk7XG4gIGlmICghZmlsZVBhdGgpIHJldHVybjtcbiAgY29uc3Qgc2x1ZyA9IHNsdWdGcm9tRGF0YVBhdGgoZmlsZVBhdGgpO1xuICBpZiAoc2x1ZyA9PT0gbnVsbCkgcmV0dXJuO1xuICB0cnkge1xuICAgIG1pcnJvcldyaXRlKHNsdWcpO1xuICAgIC8vIE9yZGVyIG1hdHRlcnM6IG1pcnJvciBtdXN0IGNvbXBsZXRlIGJlZm9yZSByZWZyZXNoIHNvIHRoZVxuICAgIC8vIHNlcnZlcidzIHNraWxsIHNjYW4gc2VlcyB0aGUgbmV3IFNLSUxMLm1kLiBTZWUgcmVmcmVzaENvbmZpZ1xuICAgIC8vIGNvbW1lbnQgZm9yIHRoZSByYWNlIGhpc3RvcnkuXG4gICAgYXdhaXQgcmVmcmVzaENvbmZpZygpO1xuICAgIC8vIFNlcnZlci1zaWRlIGxvZyBsaW5lIHNvIHRoZSB1c2VyIGNhbiBzZWUgZnJvbVxuICAgIC8vIGBzZXJ2ZXItPGRhdGU+LmxvZ2AgdGhhdCB0aGUgaG9vayBmaXJlZCBhbmQgd2hhdCBpdCBkaWQuXG4gICAgLy8gV2l0aG91dCB0aGlzIHRoZSBtaXJyb3IgaXMgaW52aXNpYmxlIFx1MjAxNCBhIHN1Y2Nlc3NmdWwgY29weVxuICAgIC8vIGFuZCBcInRoZSBob29rIG5ldmVyIHJhblwiIGxvb2sgaWRlbnRpY2FsIGZyb20gdGhlIGNoYXQgVUkuXG4gICAgYXdhaXQgc2VydmVyTG9nKFwic2tpbGwtYnJpZGdlXCIsIGBtaXJyb3JlZCAke2RhdGFTa2lsbEZpbGVQYXRoKHNsdWcpfSBcdTIxOTIgJHtjbGF1ZGVTa2lsbEZpbGVQYXRoKHNsdWcpfWAsIHsgZGF0YTogeyBzbHVnLCBvcDogXCJ3cml0ZVwiIH0gfSk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIC8vIFRoZSBXcml0ZSBpdHNlbGYgc3VjY2VlZGVkOyBhIGZhaWxlZCBtaXJyb3Igd291bGQgbGVhdmUgdGhlXG4gICAgLy8gc3RhZ2luZyBjb3B5IGluIHBsYWNlLiBTdXJmYWNlIHRoZSBmYWlsdXJlIHRvIHNlcnZlciBsb2dzXG4gICAgLy8gKHNvIHRoZSB1c2VyIGhhcyBhIGNoYW5jZSB0byByZWFjdCkgYnV0IG5ldmVyIHRocm93IFx1MjAxNCB0aGVcbiAgICAvLyB1c2VyJ3MgdG9vbCB0dXJuIG11c3Qgc3RheSBjbGVhbi5cbiAgICBhd2FpdCBzZXJ2ZXJMb2coXCJza2lsbC1icmlkZ2VcIiwgYG1pcnJvciB3cml0ZSBmYWlsZWQgZm9yIHNsdWc9JHtzbHVnfWAsIHtcbiAgICAgIGxldmVsOiBcImVycm9yXCIsXG4gICAgICBkYXRhOiB7IHNsdWcsIGVycm9yOiBlcnJvck1lc3NhZ2UoZXJyKSB9LFxuICAgIH0pO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGhhbmRsZUJhc2gocGF5bG9hZDogSG9va1BheWxvYWQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgY29tbWFuZCA9IGV4dHJhY3RDb21tYW5kKHBheWxvYWQpO1xuICBpZiAoIWNvbW1hbmQpIHJldHVybjtcbiAgY29uc3Qgc2x1ZyA9IHNsdWdGcm9tUm1Db21tYW5kKGNvbW1hbmQpO1xuICBpZiAoc2x1ZyA9PT0gbnVsbCkgcmV0dXJuO1xuICB0cnkge1xuICAgIG1pcnJvckRlbGV0ZShzbHVnKTtcbiAgICAvLyBTYW1lIG9yZGVyaW5nIGludmFyaWFudCBhcyBoYW5kbGVXcml0ZU9yRWRpdCBcdTIwMTQgcmVmcmVzaCBtdXN0XG4gICAgLy8gcnVuIGFmdGVyIHRoZSBjYW5vbmljYWwgZGlyIGlzIGdvbmUgc28gdGhlIHNlcnZlcidzIHJlc2NhblxuICAgIC8vIGRlcmVnaXN0ZXJzIHRoZSBkZWxldGVkIHNraWxsLlxuICAgIGF3YWl0IHJlZnJlc2hDb25maWcoKTtcbiAgICBhd2FpdCBzZXJ2ZXJMb2coXCJza2lsbC1icmlkZ2VcIiwgYHJlbW92ZWQgJHtjbGF1ZGVTa2lsbERpcihzbHVnKX1gLCB7IGRhdGE6IHsgc2x1Zywgb3A6IFwiZGVsZXRlXCIgfSB9KTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgLy8gU2FtZSBzaWxlbnQtZmFpbCBkaXNjaXBsaW5lIFx1MjAxNCBhIG1pc3NlZCBkZWxldGUgbGVhdmVzIGFuXG4gICAgLy8gb3JwaGFuIGluIGAuY2xhdWRlL3NraWxscy9gIHRoYXQgdGhlIHVzZXIgY2FuIGNsZWFuIHVwXG4gICAgLy8gbWFudWFsbHksIHdoaWNoIGlzIGJldHRlciB0aGFuIGFib3J0aW5nIHRoZSB0b29sIHR1cm4uXG4gICAgYXdhaXQgc2VydmVyTG9nKFwic2tpbGwtYnJpZGdlXCIsIGBtaXJyb3IgZGVsZXRlIGZhaWxlZCBmb3Igc2x1Zz0ke3NsdWd9YCwge1xuICAgICAgbGV2ZWw6IFwiZXJyb3JcIixcbiAgICAgIGRhdGE6IHsgc2x1ZywgZXJyb3I6IGVycm9yTWVzc2FnZShlcnIpIH0sXG4gICAgfSk7XG4gIH1cbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZVNraWxsQnJpZGdlKHBheWxvYWQ6IEhvb2tQYXlsb2FkKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHRvb2wgPSBleHRyYWN0VG9vbE5hbWUocGF5bG9hZCk7XG4gIGlmICh0b29sID09PSBcIldyaXRlXCIgfHwgdG9vbCA9PT0gXCJFZGl0XCIpIHtcbiAgICBhd2FpdCBoYW5kbGVXcml0ZU9yRWRpdChwYXlsb2FkKTtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKHRvb2wgPT09IFwiQmFzaFwiKSB7XG4gICAgYXdhaXQgaGFuZGxlQmFzaChwYXlsb2FkKTtcbiAgfVxufVxuIiwgIi8vIFNoYXJlZCBlcnJvciBoZWxwZXJzLiBVc2UgYGVycm9yTWVzc2FnZShlcnIpYCBpbnN0ZWFkIG9mIGlubGluaW5nXG4vLyBgZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpYCBcdTIwMTQgc2VhcmNoaW5nIGZvclxuLy8gb25lIGNhbm9uaWNhbCBoZWxwZXIgaXMgZWFzaWVyIHRoYW4gZ3JlcHBpbmcgZm9yIHRoZSBpbmxpbmUgZm9ybS5cbi8vXG4vLyBOb24tRXJyb3Igb2JqZWN0cyB3aXRoIGEgYGRldGFpbHNgIChnUlBDIGNvbnZlbnRpb24pIG9yIGBtZXNzYWdlYFxuLy8gc3RyaW5nIGZpZWxkIGhhdmUgdGhhdCBmaWVsZCBzdXJmYWNlZCBcdTIwMTQgd2l0aG91dCB0aGlzLCBnUlBDIGVycm9yc1xuLy8gbGlrZSBgeyBjb2RlLCBkZXRhaWxzLCBtZXRhZGF0YSB9YCBzaG93IHVwIHRvIHVzZXJzIGFzXG4vLyBgW29iamVjdCBPYmplY3RdYC5cbi8vXG4vLyBUaGUgb3B0aW9uYWwgYGZhbGxiYWNrYCBjb3ZlcnMgdGhlIGNvbW1vbiByb3V0ZS1oYW5kbGVyIGlkaW9tIHdoZXJlXG4vLyBhIHRocm93IG9mIGEgcGxhaW4gbm9uLUVycm9yIHZhbHVlIHNob3VsZCBzdXJmYWNlIGFzIGEgZGVzY3JpcHRpdmVcbi8vIG1lc3NhZ2UgKFwicmVidWlsZCBmYWlsZWRcIikgcmF0aGVyIHRoYW4gYFN0cmluZyhlcnIpYCBub2lzZS4gUHJlZmVyXG4vLyBwYXNzaW5nIGEgZmFsbGJhY2sgYXQgZXJyb3ItcmVzcG9uc2UgYm91bmRhcmllcyBcdTIwMTQgb21pdCBpdCBmb3Jcbi8vIGxvZ2dpbmcgY29udGV4dHMgd2hlcmUgYFN0cmluZyhlcnIpYCBpcyBmaW5lLlxuXG5leHBvcnQgZnVuY3Rpb24gZXJyb3JNZXNzYWdlKGVycjogdW5rbm93biwgZmFsbGJhY2s/OiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAoZXJyIGluc3RhbmNlb2YgRXJyb3IpIHJldHVybiBlcnIubWVzc2FnZTtcbiAgaWYgKGVyciAhPT0gbnVsbCAmJiB0eXBlb2YgZXJyID09PSBcIm9iamVjdFwiKSB7XG4gICAgY29uc3Qgb2JqID0gZXJyIGFzIHsgZGV0YWlscz86IHVua25vd247IG1lc3NhZ2U/OiB1bmtub3duIH07XG4gICAgaWYgKHR5cGVvZiBvYmouZGV0YWlscyA9PT0gXCJzdHJpbmdcIiAmJiBvYmouZGV0YWlscykgcmV0dXJuIG9iai5kZXRhaWxzO1xuICAgIGlmICh0eXBlb2Ygb2JqLm1lc3NhZ2UgPT09IFwic3RyaW5nXCIgJiYgb2JqLm1lc3NhZ2UpIHJldHVybiBvYmoubWVzc2FnZTtcbiAgfVxuICBpZiAoZmFsbGJhY2sgIT09IHVuZGVmaW5lZCkgcmV0dXJuIGZhbGxiYWNrO1xuICByZXR1cm4gU3RyaW5nKGVycik7XG59XG4iLCAiLy8gV2lraSBwYWdlIHNuYXBzaG90IGhhbmRsZXIgXHUyMDE0IGZpcmVzIGFmdGVyIFdyaXRlL0VkaXQgb24gYSB3aWtpXG4vLyBwYWdlIHNvIHRoZSBzbmFwc2hvdCBwaXBlbGluZSAoIzc2MyBQUiAyKSByZWNvcmRzIHRoZSBuZXcgc3RhdGUuXG4vL1xuLy8gTWlncmF0ZWQgZnJvbSBgc2VydmVyL3dvcmtzcGFjZS93aWtpLWhpc3RvcnkvaG9vay9zbmFwc2hvdC50c2AuXG4vLyBTYW1lIGJlaGF2aW91ciwgbm93IHBhcnQgb2YgdGhlIHVuaWZpZWQgZGlzcGF0Y2hlciBzbyBzZXR0aW5ncy5qc29uXG4vLyBjYXJyaWVzIGEgc2luZ2xlIFBvc3RUb29sVXNlIGVudHJ5IGluc3RlYWQgb2Ygb25lIHBlciBob29rIHNvdXJjZS5cblxuaW1wb3J0IHBhdGggZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgd2lraVNsdWdGcm9tQWJzUGF0aCB9IGZyb20gXCIuLi8uLi8uLi8uLi9zcmMvbGliL3dpa2ktcGFnZS9wYXRocy5qc1wiO1xuaW1wb3J0IHsgYnVpbGRBdXRoUG9zdCwgc2FmZVBvc3QgfSBmcm9tIFwiLi4vc2hhcmVkL3NpZGVjYXIuanNcIjtcbmltcG9ydCB0eXBlIHsgSG9va1BheWxvYWQgfSBmcm9tIFwiLi4vc2hhcmVkL3N0ZGluLmpzXCI7XG5pbXBvcnQgeyBleHRyYWN0RmlsZVBhdGgsIGV4dHJhY3RTZXNzaW9uSWQsIGV4dHJhY3RUb29sTmFtZSB9IGZyb20gXCIuLi9zaGFyZWQvc3RkaW4uanNcIjtcbmltcG9ydCB7IHdvcmtzcGFjZVJvb3QgfSBmcm9tIFwiLi4vc2hhcmVkL3dvcmtzcGFjZS5qc1wiO1xuXG5jb25zdCBXSUtJX1BBR0VTX1JFTCA9IHBhdGguam9pbihcImRhdGFcIiwgXCJ3aWtpXCIsIFwicGFnZXNcIik7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBoYW5kbGVXaWtpU25hcHNob3QocGF5bG9hZDogSG9va1BheWxvYWQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgdG9vbCA9IGV4dHJhY3RUb29sTmFtZShwYXlsb2FkKTtcbiAgLy8gV2lraSBwYWdlcyBhcmUgd3JpdHRlbiB2aWEgV3JpdGUgb3IgRWRpdCBcdTIwMTQgQmFzaCBybSBvciBzaGVsbFxuICAvLyBtdXRhdGlvbnMgZG9uJ3QgZ28gdGhyb3VnaCB0aGUgc25hcHNob3QgcGlwZWxpbmUgKHRoZSB3aWtpXG4gIC8vIHJvdXRlIGRvZXMgdGhhdCBleHBsaWNpdGx5IHNlcnZlci1zaWRlIHdoZW4gbmVlZGVkKS5cbiAgaWYgKHRvb2wgIT09IFwiV3JpdGVcIiAmJiB0b29sICE9PSBcIkVkaXRcIikgcmV0dXJuO1xuXG4gIGNvbnN0IGZpbGVQYXRoID0gZXh0cmFjdEZpbGVQYXRoKHBheWxvYWQpO1xuICBpZiAoIWZpbGVQYXRoKSByZXR1cm47XG5cbiAgY29uc3Qgd2lraVBhZ2VzRGlyID0gcGF0aC5qb2luKHdvcmtzcGFjZVJvb3QoKSwgV0lLSV9QQUdFU19SRUwpO1xuICBjb25zdCBzbHVnID0gd2lraVNsdWdGcm9tQWJzUGF0aChmaWxlUGF0aCwgd2lraVBhZ2VzRGlyKTtcbiAgaWYgKHNsdWcgPT09IG51bGwpIHJldHVybjtcblxuICAvLyBQcmVmZXIgdGhlIHBhcmVudCBzZXJ2ZXIncyBjaGF0U2Vzc2lvbklkICgjOTYzKSBcdTIwMTQgdGhlIHNlcnZlcidzXG4gIC8vIHNlc3Npb24gc3RvcmUga2V5cyBieSBjaGF0U2Vzc2lvbklkLCBub3QgQ2xhdWRlIENMSSdzIGludGVybmFsXG4gIC8vIHNlc3Npb25faWQsIHNvIHRoZSB0b29sUmVzdWx0IHB1Ymxpc2ggb24gdGhlIHNlcnZlciBzaWRlIG9ubHlcbiAgLy8gbWF0Y2hlcyB3aGVuIHdlIGZvcndhcmQgb3VyIG93biBpZC4gRmFsbCBiYWNrIHRvIENsYXVkZSBDTEknc1xuICAvLyBzZXNzaW9uX2lkIHdoZW4gdGhlIGVudiB2YXIgaXMgYWJzZW50LlxuICBjb25zdCBlbnZDaGF0U2Vzc2lvbklkID0gcHJvY2Vzcy5lbnYuTVVMTU9DTEFVREVfQ0hBVF9TRVNTSU9OX0lEO1xuICBjb25zdCBwYXlsb2FkU2Vzc2lvbklkID0gZXh0cmFjdFNlc3Npb25JZChwYXlsb2FkKTtcbiAgY29uc3Qgc2Vzc2lvbklkID0gZW52Q2hhdFNlc3Npb25JZCAmJiBlbnZDaGF0U2Vzc2lvbklkLmxlbmd0aCA+IDAgPyBlbnZDaGF0U2Vzc2lvbklkIDogcGF5bG9hZFNlc3Npb25JZDtcbiAgY29uc3QgYm9keSA9IHNlc3Npb25JZCA9PT0gdW5kZWZpbmVkID8geyBzbHVnIH0gOiB7IHNsdWcsIHNlc3Npb25JZCB9O1xuXG4gIGNvbnN0IHJlcSA9IGJ1aWxkQXV0aFBvc3QoXCIvYXBpL3dpa2kvaW50ZXJuYWwvc25hcHNob3RcIiwgYm9keSk7XG4gIGF3YWl0IHNhZmVQb3N0KHJlcSk7XG59XG4iLCAiLy8gTm9kZS1vbmx5IHdpa2ktcGFnZSBoZWxwZXJzIFx1MjAxNCBhbnl0aGluZyB0aGF0IG5lZWRzIGBub2RlOnBhdGhgXG4vLyBsaXZlcyBoZXJlIHNvIHRoZSByZXN0IG9mIGBzcmMvbGliL3dpa2ktcGFnZS9gIHN0YXlzIHB1cmVcbi8vIChzdHJpbmctb25seSwgaW1wb3J0YWJsZSBmcm9tIGJvdGggYnJvd3NlciBhbmQgTm9kZSBidW5kbGVzKS5cbi8vIEZyb250ZW5kIGNvZGUgTVVTVCBOT1QgaW1wb3J0IHRoaXMgZmlsZSBkaXJlY3RseTsgdXNlIHRoZSBwdXJlXG4vLyBtb2R1bGVzIGluc3RlYWQuXG5cbmltcG9ydCBwYXRoIGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IGlzU2FmZVNsdWcgfSBmcm9tIFwiLi9zbHVnLmpzXCI7XG5cbi8qKiBHaXZlbiBhbiBhYnNvbHV0ZSBwYXRoIGFuZCB0aGUgYWJzb2x1dGUgYHBhZ2VzRGlyYCwgcmV0dXJuIHRoZVxuICogIHNsdWcgaWYgYGFic1BhdGhgIGlzIGEgZGlyZWN0IGAubWRgIGNoaWxkIG9mIGBwYWdlc0RpcmAsIGVsc2VcbiAqICBudWxsLiBQdXJlIHBhdGgtc3RyaW5nIG1hdGggXHUyMDE0IG5vIGZzIElPLCBubyBzeW1saW5rIHJlc29sdXRpb24uXG4gKlxuICogIENhbGxlciByZXNwb25zaWJpbGl0eTogcGFzcyBhbHJlYWR5LXJlYWxwYXRoJ2QgdmFsdWVzIGZvciBib3RoXG4gKiAgYXJndW1lbnRzLiBNaXhpbmcgYSByZWFscGF0aCdkIGBhYnNQYXRoYCB3aXRoIGEgc3ltbGlua2VkXG4gKiAgYHBhZ2VzRGlyYCAob3IgdmljZSB2ZXJzYSkgc2lsZW50bHkgbWlzbWF0Y2hlcyBiZWNhdXNlXG4gKiAgYHBhdGgucmVsYXRpdmVgIGlzIHBsYWluIHN0cmluZyBhcml0aG1ldGljLiBUaGUgdHJhcCBjYXVzZWRcbiAqICAjODgzIHJldmlldy1pdGVyLTEgXHUyMDE0IGEgc3ltbGlua2VkIHdvcmtzcGFjZSBzaWxlbnRseSByb3V0ZWRcbiAqICB3aWtpIHdyaXRlcyB0aHJvdWdoIHRoZSBnZW5lcmljIHdyaXRlci4gKi9cbmV4cG9ydCBmdW5jdGlvbiB3aWtpU2x1Z0Zyb21BYnNQYXRoKGFic1BhdGg6IHN0cmluZywgcGFnZXNEaXI6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuICBjb25zdCByZWwgPSBwYXRoLnJlbGF0aXZlKHBhZ2VzRGlyLCBhYnNQYXRoKTtcbiAgaWYgKHJlbC5sZW5ndGggPT09IDApIHJldHVybiBudWxsO1xuICBpZiAocGF0aC5pc0Fic29sdXRlKHJlbCkpIHJldHVybiBudWxsO1xuICAvLyBEaXJlY3QgY2hpbGQgb25seSBcdTIwMTQgbm8gbmVzdGVkIGxheW91dCB0b2RheS4gQW55IHNlcGFyYXRvclxuICAvLyBtZWFucyB0aGUgcGF0aCBlaXRoZXIgZXNjYXBlcyAoYC4uL3NlY3JldC5tZGApIG9yIGRlc2NlbmRzXG4gIC8vIChgc3ViZGlyL2Zvby5tZGApLiBBIGxpdGVyYWwgcGFnZSBuYW1lIGxpa2UgYC4uZm9vLm1kYCBpcyBhXG4gIC8vIHNpbmdsZSBzZWdtZW50IHdpdGhvdXQgYSBzZXBhcmF0b3IgYW5kIGlzIGFsbG93ZWQgKGNvZGV4XG4gIC8vIGl0ZXItMyAjODgzIFx1MjAxNCB0aGUgcHJpb3IgYHN0YXJ0c1dpdGgoXCIuLlwiKWAgcnVsZSB3cm9uZ2x5XG4gIC8vIHJlamVjdGVkIGl0KS5cbiAgaWYgKHJlbC5pbmNsdWRlcyhwYXRoLnNlcCkpIHJldHVybiBudWxsO1xuICBpZiAoIXJlbC5lbmRzV2l0aChcIi5tZFwiKSkgcmV0dXJuIG51bGw7XG4gIGNvbnN0IHNsdWcgPSByZWwuc2xpY2UoMCwgLVwiLm1kXCIubGVuZ3RoKTtcbiAgaWYgKCFpc1NhZmVTbHVnKHNsdWcpKSByZXR1cm4gbnVsbDtcbiAgcmV0dXJuIHNsdWc7XG59XG4iLCAiLy8gUHVyZSB3aWtpLXBhZ2Ugc2x1ZyBoZWxwZXJzIFx1MjAxNCBzdHJpbmctb25seSwgbm8gTm9kZSAvIGJyb3dzZXJcbi8vIGRlcGVuZGVuY2llcywgaW1wb3J0YWJsZSBmcm9tIGFueSBidW5kbGUuXG4vL1xuLy8gVXNlZCBieTpcbi8vICAgLSBzZXJ2ZXIvd29ya3NwYWNlL3dpa2ktcGFnZXMvaW8udHMgKHRoZSB3cml0ZSBjaG9rZXBvaW50KVxuLy8gICAtIHNlcnZlci93b3Jrc3BhY2UvaG9va3MvaGFuZGxlcnMvd2lraVNuYXBzaG90LnRzICh0aGVcbi8vICAgICBQb3N0VG9vbFVzZSBoYW5kbGVyIHRoYXQgZmlyZXMgb24gV3JpdGUvRWRpdCBvZiBhIHdpa2kgcGFnZSlcbi8vICAgLSBzZXJ2ZXIvYXBpL3JvdXRlcy93aWtpLnRzIChwYWdlIHJlc29sdmVyICsgbGludClcbi8vICAgLSBzZXJ2ZXIvYXBpL3JvdXRlcy93aWtpL2hpc3RvcnkudHMgKGhpc3Rvcnkgc2x1ZyBndWFyZClcbi8vICAgLSBzcmMvcGx1Z2lucy93aWtpL3JvdXRlLnRzIChyb3V0ZXIgc2x1ZyBndWFyZCBcdTIwMTQgcmVwbGFjZXMgdGhlXG4vLyAgICAgbG9jYWwgYGlzU2FmZVdpa2lTbHVnYCBkdXBsaWNhdGUgdGhhdCBleGlzdGVkIGJlZm9yZSB0aGVcbi8vICAgICBwdXJlLWxpYiByZWZhY3Rvcilcbi8vICAgLSBzcmMvcGx1Z2lucy93aWtpL2hlbHBlcnMudHMgKHJlbmRlcmVyIHNsdWdpZnkgZm9yIFtbXHUyMDI2XV0gbGlua3MpXG4vL1xuLy8gQW55IGhlbHBlciB0aGF0IG5lZWRzIGBub2RlOnBhdGhgIGxpdmVzIGluIGAuL3BhdGhzLnRzYCBzbyB0aGF0XG4vLyBpbXBvcnRpbmcgdGhpcyBmaWxlIGZyb20gZnJvbnRlbmQgY29kZSBuZXZlciBwdWxscyBpbiBOb2RlXG4vLyBidWlsdGlucy5cblxuLyoqIFJlamVjdCBzbHVncyB0aGF0IHdvdWxkIGVzY2FwZSBgZGF0YS93aWtpL3BhZ2VzL2Agb25jZVxuICogIGpvaW5lZCBiYWNrIGludG8gYSBwYXRoLCBvciB0aGF0IGFyZSBvdGhlcndpc2UgaW52YWxpZCBhc1xuICogIHBhZ2UgZmlsZW5hbWVzLiBUaGUgY2hva2Vwb2ludCBtdXN0IGRlZmVuZCBpdHNlbGYgZXZlbiB3aGVuXG4gKiAgY2FsbGVycyBkZXJpdmUgdGhlIHNsdWcgZnJvbSBhIHRydXN0ZWQgc291cmNlIFx1MjAxNCBhIHR5cG8gb3JcbiAqICBmdXR1cmUgY2FsbGVyIG1pc3Rha2Ugc2hvdWxkIGZhaWwgbG91ZCwgbm90IHNpbGVudGx5IHdyaXRlXG4gKiAgb3V0c2lkZSB0aGUgd2lraSB0cmVlLlxuICpcbiAqICBUaGUgcnVsZSBpcyBpbnRlbnRpb25hbGx5IG5hcnJvdyBcdTIwMTQgc2VwYXJhdG9ycyAvIGAuLmAgLyBOVUwgL1xuICogIGVtcHR5IFx1MjAxNCBzbyBpdCBvbmx5IHJlamVjdHMgdW5hbWJpZ3VvdXMgdmlvbGF0aW9ucy4gQWVzdGhldGljXG4gKiAgY29uY2VybnMgKGUuZy4gZG90LXByZWZpeGVkIGZpbGVuYW1lcykgYXJlIG91dCBvZiBzY29wZTogYVxuICogIHByZS1leGlzdGluZyBgZGF0YS93aWtpL3BhZ2VzLy5mb28ubWRgIHNob3VsZCByZW1haW4gd3JpdGFibGVcbiAqICB0aHJvdWdoIHRoZSBjaG9rZXBvaW50IChjb2RleCByZXZpZXcgaXRlci0yICM4ODMpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU2FmZVNsdWcoc2x1Zzogc3RyaW5nKTogYm9vbGVhbiB7XG4gIGlmIChzbHVnLmxlbmd0aCA9PT0gMCkgcmV0dXJuIGZhbHNlO1xuICBpZiAoc2x1ZyA9PT0gXCIuXCIgfHwgc2x1ZyA9PT0gXCIuLlwiKSByZXR1cm4gZmFsc2U7XG4gIGlmIChzbHVnLmluY2x1ZGVzKFwiL1wiKSB8fCBzbHVnLmluY2x1ZGVzKFwiXFxcXFwiKSkgcmV0dXJuIGZhbHNlO1xuICBpZiAoc2x1Zy5pbmNsdWRlcyhcIlxcMFwiKSkgcmV0dXJuIGZhbHNlO1xuICByZXR1cm4gdHJ1ZTtcbn1cblxuLyoqIFNsdWcgcnVsZXMgZm9yIGBbW3dpa2kgbGlua11dYCB0ZXh0IFx1MjE5MiBzbHVnIGRlcml2YXRpb246XG4gKiAgbG93ZXJjYXNlLCBzcGFjZXMgY29sbGFwc2VkIHRvIGh5cGhlbnMsIGV2ZXJ5IG5vbi1BU0NJSSAvXG4gKiAgbm9uLWFscGhhbnVtZXJpYyAvIG5vbi1oeXBoZW4gY2hhcmFjdGVyIHN0cmlwcGVkLlxuICpcbiAqICBQdXJlOiBubyBub3JtYWxpc2F0aW9uLCBubyB0cmFuc2xpdGVyYXRpb24gXHUyMDE0IHRoaXMgaXMgdGhlXG4gKiAgc2FtZSBzaGFwZSB0aGUgaW5kZXggcGFyc2VyLCBwYWdlIHJlc29sdmVyLCBhbmQgZnJvbnRlbmRcbiAqICByZW5kZXJlciBhbGwgbmVlZCB0byBhZ3JlZSBvbi4gTm9uLUFTQ0lJIHRpdGxlcyAoZS5nLlxuICogIEphcGFuZXNlKSBjb2xsYXBzZSB0byBhbiBlbXB0eSBzdHJpbmcgaGVyZTsgY2FsbGVycyBmYWxsIGJhY2tcbiAqICB0byBvdGhlciBzdHJhdGVnaWVzICh0aXRsZS1tYXRjaCBpbiB0aGUgaW5kZXgsIG9yIHRoZSBhZ2VudFxuICogIHByZS1yZXNvbHZpbmcgdG8gYSBzbHVnLWZvcm0gdGFyZ2V0IHZpYSBgW1tzbHVnfGRpc3BsYXldXWApLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHdpa2lTbHVnaWZ5KHRleHQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiB0ZXh0XG4gICAgLnRvTG93ZXJDYXNlKClcbiAgICAucmVwbGFjZSgvXFxzKy9nLCBcIi1cIilcbiAgICAucmVwbGFjZSgvW15hLXowLTktXS9nLCBcIlwiKTtcbn1cbiIsICIvLyBQb3N0VG9vbFVzZSBkaXNwYXRjaGVyIFx1MjAxNCBydW5zIGFmdGVyIGV2ZXJ5IENsYXVkZSBDTEkgV3JpdGUgLyBFZGl0XG4vLyAvIEJhc2ggdG9vbCBjYWxsIGFuZCBmYW5zIG91dCB0byB0aGUgcmVnaXN0ZXJlZCBoYW5kbGVycy4gRWFjaFxuLy8gaGFuZGxlciBkZWNpZGVzIGZvciBpdHNlbGYgd2hldGhlciB0aGUgY2FsbCBpcyByZWxldmFudCAoYnlcbi8vIHRvb2xfbmFtZSArIGZpbGVfcGF0aCAvIGNvbW1hbmQpLCBzbyBhZGRpbmcgYSBuZXcgYmVoYXZpb3VyIG1lYW5zXG4vLyBkcm9wcGluZyBhIG5ldyBmaWxlIHVuZGVyIGBoYW5kbGVycy9gIGFuZCByZWdpc3RlcmluZyBpdCBoZXJlIFx1MjAxNFxuLy8gc2V0dGluZ3MuanNvbiBuZXZlciBjaGFuZ2VzLlxuLy9cbi8vIFRISVMgRklMRSBJUyBUSEUgU09VUkNFIE9GIFRSVVRILiBFZGl0cyBoZXJlLCB0aGVuIHJ1blxuLy8gYHlhcm4gYnVpbGQ6aG9va3NgIChvciBgeWFybiBidWlsZGApIHRvIHJlZ2VuZXJhdGUgYC4vZGlzcGF0Y2hlci5tanNgLlxuLy8gVGhlIGJ1bmRsZWQgYC5tanNgIGlzIGNvbW1pdHRlZCB0byBnaXQgc28gYHByb3Zpc2lvbi50c2AgY2FuIHJlYWRcbi8vIGl0IGF0IHNlcnZlciBzdGFydHVwIHdpdGhvdXQgaW52b2tpbmcgZXNidWlsZCBvbiB0aGUgcnVudGltZSBwYXRoLlxuLy8gQ0kgcnVucyBgeWFybiBidWlsZDpob29rcyAmJiBnaXQgZGlmZiAtLWV4aXQtY29kZWAgdG8gY2F0Y2ggYVxuLy8gc3RhbGUgYnVuZGxlLlxuLy9cbi8vIFRoZSBob29rIGV4ZWN1dGVzIGluc2lkZSBDbGF1ZGUgQ0xJJ3MgcHJvY2VzcyBzcGFjZSBcdTIwMTQgbXVzdCBiZSBhXG4vLyBzZWxmLWNvbnRhaW5lZCBFU00gYnVuZGxlLiBlc2J1aWxkIHJvbGxzIGV2ZXJ5IGltcG9ydCAoaGFuZGxlcnMsXG4vLyBzaGFyZWQsIGFuZCB0aGUgd2lraS1zbHVnIGhlbHBlciBmcm9tIGBzcmMvbGliL2ApIGludG8gb25lIGZpbGUuXG5cbmltcG9ydCB7IGhhbmRsZUNvbmZpZ1JlZnJlc2ggfSBmcm9tIFwiLi9oYW5kbGVycy9jb25maWdSZWZyZXNoLmpzXCI7XG5pbXBvcnQgeyBoYW5kbGVTa2lsbEJyaWRnZSB9IGZyb20gXCIuL2hhbmRsZXJzL3NraWxsQnJpZGdlLmpzXCI7XG5pbXBvcnQgeyBoYW5kbGVXaWtpU25hcHNob3QgfSBmcm9tIFwiLi9oYW5kbGVycy93aWtpU25hcHNob3QuanNcIjtcbmltcG9ydCB7IHJlYWRIb29rUGF5bG9hZCwgdHlwZSBIb29rUGF5bG9hZCB9IGZyb20gXCIuL3NoYXJlZC9zdGRpbi5qc1wiO1xuXG50eXBlIEhhbmRsZXIgPSAocGF5bG9hZDogSG9va1BheWxvYWQpID0+IFByb21pc2U8dm9pZD47XG5cbi8vIE9yZGVyIGlzIGluZm9ybWF0aW9uYWwgb25seSBcdTIwMTQgaGFuZGxlcnMgZG9uJ3QgaW50ZXJhY3QuIEFkZCBuZXdcbi8vIGVudHJpZXMgaGVyZS4gRWFjaCBvbmUgaXMgd3JhcHBlZCBzbyBhbiBpbmRpdmlkdWFsIGZhaWx1cmVcbi8vIGRvZXNuJ3QgYmxvY2sgaXRzIHNpYmxpbmdzICh0aGUgdXNlcidzIHRvb2wgdHVybiB3b3VsZCB2aXNpYmx5XG4vLyBzdGFsbCBvdGhlcndpc2UpLlxuY29uc3QgSEFORExFUlM6IEhhbmRsZXJbXSA9IFtoYW5kbGVXaWtpU25hcHNob3QsIGhhbmRsZUNvbmZpZ1JlZnJlc2gsIGhhbmRsZVNraWxsQnJpZGdlXTtcblxuYXN5bmMgZnVuY3Rpb24gcnVuSGFuZGxlcihoYW5kbGVyOiBIYW5kbGVyLCBwYXlsb2FkOiBIb29rUGF5bG9hZCk6IFByb21pc2U8dm9pZD4ge1xuICB0cnkge1xuICAgIGF3YWl0IGhhbmRsZXIocGF5bG9hZCk7XG4gIH0gY2F0Y2gge1xuICAgIC8vIEhvb2tzIHJ1biBzeW5jaHJvbm91c2x5IHRvIHRoZSBMTE0gdG9vbCBmbG93IFx1MjAxNCBuZXZlciB0aHJvdy5cbiAgICAvLyBBIGJ1c3RlZCBoYW5kbGVyIHdvdWxkIG1ha2UgdGhlIHRvb2wgaXRzZWxmIGxvb2sgbGlrZSBpdFxuICAgIC8vIGZhaWxlZCB0byB0aGUgTExNLCB3aGljaCBpcyBtdWNoIHdvcnNlIHRoYW4gYSBtaXNzZWRcbiAgICAvLyBzaWRlLWVmZmVjdC5cbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBtYWluKCk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBwYXlsb2FkID0gYXdhaXQgcmVhZEhvb2tQYXlsb2FkKCk7XG4gIGlmICghcGF5bG9hZCkgcmV0dXJuO1xuICAvLyBSdW4gaGFuZGxlcnMgaW4gcGFyYWxsZWwgXHUyMDE0IHRoZXkgdG91Y2ggZGlzam9pbnQgcmVzb3VyY2VzXG4gIC8vICh3aWtpIHNuYXBzaG90IGVuZHBvaW50IHZzIGNvbmZpZy1yZWZyZXNoIGVuZHBvaW50IHZzIGxvY2FsXG4gIC8vIGZpbGUgY29weSkgYW5kIHNlcmlhbGlzaW5nIHRoZW0gd291bGQgcHVzaCB0aGUgcGVyLXR1cm5cbiAgLy8gbGF0ZW5jeSBwYXN0IHRoZSAyIHMgc2FmZVBvc3QgdGltZW91dCB1bmRlciBiYWQgY29uZGl0aW9ucy5cbiAgYXdhaXQgUHJvbWlzZS5hbGwoSEFORExFUlMubWFwKChoYW5kbGVyKSA9PiBydW5IYW5kbGVyKGhhbmRsZXIsIHBheWxvYWQpKSk7XG59XG5cbm1haW4oKS5jYXRjaCgoKSA9PiB7XG4gIC8vIE91dGVybW9zdCBzYWZldHkgbmV0IFx1MjAxNCBzZWUgcnVuSGFuZGxlciBjb21tZW50LlxufSk7XG4iXSwKICAibWFwcGluZ3MiOiAiOzs7QUFVQSxTQUFTLG9CQUFvQjtBQUM3QixPQUFPQSxXQUFVOzs7QUNKVixJQUFNLGdCQUFnQjtBQUN0QixJQUFNLGdCQUFnQjtBQWdCdEIsSUFBTSw4QkFBOEIsSUFBSTtBQVl4QyxJQUFNLGdDQUFnQyxJQUFJO0FBTTFDLElBQU0sNEJBQTRCLElBQUk7OztBQ25DN0MsU0FBUyxlQUFlO0FBQ3hCLE9BQU8sVUFBVTtBQUVWLFNBQVMsZ0JBQXdCO0FBQ3RDLFNBQU8sUUFBUSxJQUFJLHNCQUFzQixLQUFLLEtBQUssUUFBUSxHQUFHLGFBQWE7QUFDN0U7OztBRkdBLElBQU0sYUFBYTtBQUNuQixJQUFNLFlBQVk7QUFPWCxTQUFTLGFBQXFCO0FBQ25DLFNBQU8sUUFBUSxJQUFJLG9CQUFvQjtBQUN6QztBQUVBLFNBQVMsWUFBWSxLQUFxQjtBQUN4QyxNQUFJO0FBQ0YsV0FBTyxhQUFhQyxNQUFLLEtBQUssY0FBYyxHQUFHLEdBQUcsR0FBRyxPQUFPLEVBQUUsS0FBSztBQUFBLEVBQ3JFLFFBQVE7QUFDTixXQUFPO0FBQUEsRUFDVDtBQUNGO0FBRU8sU0FBUyxZQUFvQjtBQUNsQyxTQUFPLFlBQVksVUFBVTtBQUMvQjtBQUVPLFNBQVMsV0FBMEI7QUFDeEMsUUFBTSxNQUFNLFlBQVksU0FBUztBQUNqQyxNQUFJLENBQUMsSUFBSyxRQUFPO0FBQ2pCLFFBQU0sT0FBTyxPQUFPLFNBQVMsS0FBSyxFQUFFO0FBQ3BDLFNBQU8sT0FBTyxVQUFVLElBQUksS0FBSyxPQUFPLEtBQUssT0FBTyxRQUFRLE9BQU87QUFDckU7QUFrQk8sU0FBUyxjQUFjLFVBQWtCLE1BQW9D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QUFTLEtBQU07QUFPbkIsUUFBTSxtQkFBbUIsUUFBUSxJQUFJO0FBQ3JDLFFBQU0sbUJBQW1CLGlCQUFpQixPQUFPO0FBQ2pELFFBQU0sWUFBWSxvQkFBb0IsaUJBQWlCLFNBQVMsSUFBSSxtQkFBbUI7QUFDdkYsUUFBTSxPQUFPLGNBQWMsU0FBWSxFQUFFLEtBQUssSUFBSSxFQUFFLE1BQU0sVUFBVTtBQUVwRSxRQUFNLE1BQU0sY0FBYywrQkFBK0IsSUFBSTtBQUM3RCxRQUFNLFNBQVMsR0FBRztBQUNwQjs7O0FHYkEsSUFBTSxXQUFzQixDQUFDLG9CQUFvQixxQkFBcUIsaUJBQWlCO0FBRXZGLGVBQWUsV0FBVyxTQUFrQixTQUFxQztBQUMvRSxNQUFJO0FBQ0YsVUFBTSxRQUFRLE9BQU87QUFBQSxFQUN2QixRQUFRO0FBQUEsRUFLUjtBQUNGO0FBRUEsZUFBZSxPQUFzQjtBQUNuQyxRQUFNLFVBQVUsTUFBTSxnQkFBZ0I7QUFDdEMsTUFBSSxDQUFDLFFBQVM7QUFLZCxRQUFNLFFBQVEsSUFBSSxTQUFTLElBQUksQ0FBQyxZQUFZLFdBQVcsU0FBUyxPQUFPLENBQUMsQ0FBQztBQUMzRTtBQUVBLEtBQUssRUFBRSxNQUFNLE1BQU07QUFFbkIsQ0FBQzsiLAogICJuYW1lcyI6IFsicGF0aCIsICJwYXRoIiwgInJlYWRGaWxlU3luYyIsICJwYXRoIiwgInBhdGgiLCAicmVhZEZpbGVTeW5jIiwgInBhdGgiLCAicGF0aCIsICJwYXRoIiwgInBhdGgiXQp9Cg==
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
// Writable computed that bridges activeSession.selectedResultUuid
|
|
2
|
-
// with the URL's ?result= query parameter.
|
|
3
|
-
|
|
4
|
-
import { computed, watch, type ComputedRef, type WritableComputedRef } from "vue";
|
|
5
|
-
import { useRoute, useRouter, isNavigationFailure } from "vue-router";
|
|
6
|
-
import type { ActiveSession } from "../types/session";
|
|
7
|
-
|
|
8
|
-
export function useSelectedResult(opts: {
|
|
9
|
-
activeSession: ComputedRef<ActiveSession | undefined>;
|
|
10
|
-
sessionMap: Map<string, ActiveSession>;
|
|
11
|
-
currentSessionId: { readonly value: string };
|
|
12
|
-
}): {
|
|
13
|
-
selectedResultUuid: WritableComputedRef<string | null>;
|
|
14
|
-
} {
|
|
15
|
-
const { activeSession } = opts;
|
|
16
|
-
const route = useRoute();
|
|
17
|
-
const router = useRouter();
|
|
18
|
-
|
|
19
|
-
const selectedResultUuid = computed({
|
|
20
|
-
get: () => activeSession.value?.selectedResultUuid ?? null,
|
|
21
|
-
set: (val: string | null) => {
|
|
22
|
-
if (activeSession.value) activeSession.value.selectedResultUuid = val;
|
|
23
|
-
const { result: __result, ...restQuery } = route.query;
|
|
24
|
-
const nextQuery = val ? { ...restQuery, result: val } : restQuery;
|
|
25
|
-
router.replace({ query: nextQuery }).catch((err: unknown) => {
|
|
26
|
-
if (!isNavigationFailure(err)) {
|
|
27
|
-
console.error("[selectedResultUuid] navigation failed:", err);
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// External URL changes for ?result= → sync into the session.
|
|
34
|
-
watch(
|
|
35
|
-
() => route.query.result,
|
|
36
|
-
(newResult) => {
|
|
37
|
-
const session = opts.sessionMap.get(opts.currentSessionId.value);
|
|
38
|
-
if (!session) return;
|
|
39
|
-
// Ignore malformed (array) values rather than clobbering state.
|
|
40
|
-
if (Array.isArray(newResult)) return;
|
|
41
|
-
const resultId = typeof newResult === "string" ? newResult : null;
|
|
42
|
-
if (resultId !== session.selectedResultUuid) {
|
|
43
|
-
session.selectedResultUuid = resultId;
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
return { selectedResultUuid };
|
|
49
|
-
}
|