experimental-agent 0.1.3 → 0.2.0
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/dist/agent-workflow.d.mts +2 -1
- package/dist/agent-workflow.d.ts +2 -1
- package/dist/agent-workflow.js +1382 -552
- package/dist/agent-workflow.mjs +3 -2
- package/dist/chunk-FQ67QZOI.mjs +75 -0
- package/dist/{chunk-RXPVLORL.mjs → chunk-GL7Q3MDU.mjs} +3 -7
- package/dist/{chunk-24UDM5XV.mjs → chunk-NXDVNJRS.mjs} +1 -1
- package/dist/chunk-OCF5I43X.mjs +2367 -0
- package/dist/chunk-OZZVS6L5.mjs +139 -0
- package/dist/{chunk-2ZXHR6T6.mjs → chunk-SJVFFE5D.mjs} +18 -17
- package/dist/chunk-TGNVXSMX.mjs +399 -0
- package/dist/chunk-UCVXI7LW.mjs +1287 -0
- package/dist/chunk-ZIAHPXOJ.mjs +595 -0
- package/dist/{client-SNN3XDKO.mjs → client-BKA7XBGW.mjs} +1 -1
- package/dist/{client-Bkuq-Dfa.d.mts → client-CSTexnLF.d.mts} +158 -122
- package/dist/{client-Bkuq-Dfa.d.ts → client-CSTexnLF.d.ts} +158 -122
- package/dist/{sandbox-IFK5MVRM.mjs → docker-FB2MJTHJ.mjs} +6 -4
- package/dist/{handler-WFNQWR6V.mjs → handler-FRUPZ4LX.mjs} +1 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1555 -596
- package/dist/index.mjs +140 -36
- package/dist/lifecycle-workflow.d.mts +2 -1
- package/dist/lifecycle-workflow.d.ts +2 -1
- package/dist/lifecycle-workflow.js +29 -18
- package/dist/lifecycle-workflow.mjs +1 -1
- package/dist/{local-fs-handlers-ESZBRAWK.mjs → local-fs-handlers-SYOCKTPN.mjs} +10 -2
- package/dist/next/loader.js +16 -12
- package/dist/next/loader.mjs +15 -7
- package/dist/next.d.mts +1 -1
- package/dist/next.d.ts +1 -1
- package/dist/next.js +3 -10
- package/dist/next.mjs +2 -5
- package/dist/{process-manager-ZCET3VD2.mjs → process-manager-JDUJDYGU.mjs} +1 -1
- package/dist/sandbox-HRGGTEHF.mjs +21 -0
- package/dist/{storage-FCSHTDLC.mjs → storage-LSDMRW73.mjs} +2 -2
- package/package.json +2 -6
- package/dist/chunk-4WDKWMVB.mjs +0 -389
- package/dist/chunk-64THY7Y7.mjs +0 -155
- package/dist/chunk-IACG26TC.mjs +0 -2212
- package/dist/chunk-NGLND33F.mjs +0 -1247
|
@@ -0,0 +1,2367 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createLogger
|
|
3
|
+
} from "./chunk-OZZVS6L5.mjs";
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_WAIT_UNTIL
|
|
6
|
+
} from "./chunk-FQ67QZOI.mjs";
|
|
7
|
+
|
|
8
|
+
// src/agent-workflow.ts
|
|
9
|
+
import { defineHook, FatalError as FatalError2, getWritable } from "workflow";
|
|
10
|
+
|
|
11
|
+
// src/agent-workflow-steps.ts
|
|
12
|
+
import {
|
|
13
|
+
convertToModelMessages,
|
|
14
|
+
createUIMessageStream,
|
|
15
|
+
stepCountIs,
|
|
16
|
+
streamText
|
|
17
|
+
} from "ai";
|
|
18
|
+
import { ulid } from "ulid";
|
|
19
|
+
import { FatalError } from "workflow";
|
|
20
|
+
|
|
21
|
+
// src/skills/parser.ts
|
|
22
|
+
function parseSkillFrontmatter(content) {
|
|
23
|
+
const trimmed = content.trim();
|
|
24
|
+
if (!trimmed.startsWith("---")) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const endMarkerIndex = trimmed.indexOf("---", 3);
|
|
28
|
+
if (endMarkerIndex === -1) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const frontmatterBlock = trimmed.slice(3, endMarkerIndex).trim();
|
|
32
|
+
const parsed = parseSimpleYaml(frontmatterBlock);
|
|
33
|
+
if (!(parsed.name && parsed.description)) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
name: String(parsed.name),
|
|
38
|
+
description: String(parsed.description)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function parseSimpleYaml(yaml) {
|
|
42
|
+
const result = {};
|
|
43
|
+
for (const line of yaml.split("\n")) {
|
|
44
|
+
const trimmedLine = line.trim();
|
|
45
|
+
if (!trimmedLine || trimmedLine.startsWith("#")) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const colonIndex = trimmedLine.indexOf(":");
|
|
49
|
+
if (colonIndex === -1) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const key = trimmedLine.slice(0, colonIndex).trim();
|
|
53
|
+
let value = trimmedLine.slice(colonIndex + 1).trim();
|
|
54
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
55
|
+
value = value.slice(1, -1);
|
|
56
|
+
}
|
|
57
|
+
if (key) {
|
|
58
|
+
result[key] = value;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
function normalizeSkillsDirs(skillsDir) {
|
|
64
|
+
if (!skillsDir) {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
return Array.isArray(skillsDir) ? skillsDir : [skillsDir];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/skills/discover.ts
|
|
71
|
+
var baseLog = createLogger({ subsystem: "skills" });
|
|
72
|
+
async function discoverSkillsInSandbox(opts) {
|
|
73
|
+
const { sandbox, skillsDirs, sessionId } = opts;
|
|
74
|
+
const log4 = sessionId ? baseLog.withContext({ sessionId }) : baseLog;
|
|
75
|
+
const done = log4.time("discoverSkillsInSandbox");
|
|
76
|
+
const summaries = [];
|
|
77
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
78
|
+
for (const skillsDir of skillsDirs) {
|
|
79
|
+
const dirDone = log4.time("scan directory", { dir: skillsDir });
|
|
80
|
+
const dirSummaries = await discoverSkillsInDirectory({
|
|
81
|
+
sandbox,
|
|
82
|
+
skillsDir,
|
|
83
|
+
log: log4
|
|
84
|
+
});
|
|
85
|
+
dirDone({ count: dirSummaries.length });
|
|
86
|
+
for (const summary of dirSummaries) {
|
|
87
|
+
if (!seenNames.has(summary.name)) {
|
|
88
|
+
seenNames.add(summary.name);
|
|
89
|
+
summaries.push(summary);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
done({ totalSkills: summaries.length });
|
|
94
|
+
return summaries;
|
|
95
|
+
}
|
|
96
|
+
async function discoverSkillsInDirectory(opts) {
|
|
97
|
+
const { sandbox, skillsDir, log: log4 } = opts;
|
|
98
|
+
const skillPaths = await findSkillFiles({ sandbox, skillsDir, log: log4 });
|
|
99
|
+
if (skillPaths.length === 0) {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
const summaries = [];
|
|
103
|
+
for (const skillMdPath of skillPaths) {
|
|
104
|
+
const summary = await parseSkillFile({ sandbox, skillMdPath, log: log4 });
|
|
105
|
+
if (summary) {
|
|
106
|
+
summaries.push(summary);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return summaries;
|
|
110
|
+
}
|
|
111
|
+
async function findSkillFiles(opts) {
|
|
112
|
+
const { sandbox, skillsDir, log: log4 } = opts;
|
|
113
|
+
const execResult = await sandbox.exec({
|
|
114
|
+
command: "find",
|
|
115
|
+
args: [skillsDir, "-name", "SKILL.md", "-type", "f"]
|
|
116
|
+
});
|
|
117
|
+
if (execResult instanceof Error) {
|
|
118
|
+
log4.warn("failed to scan skills directory", {
|
|
119
|
+
dir: skillsDir,
|
|
120
|
+
error: execResult.message
|
|
121
|
+
});
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
const { stdout, exitCode } = await execResult.result;
|
|
125
|
+
if (exitCode !== 0) {
|
|
126
|
+
log4.warn("skills directory not found or inaccessible", { dir: skillsDir });
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
return stdout.trim().split("\n").filter((p) => p.length > 0);
|
|
130
|
+
}
|
|
131
|
+
async function parseSkillFile(opts) {
|
|
132
|
+
const { sandbox, skillMdPath, log: log4 } = opts;
|
|
133
|
+
const execResult = await sandbox.exec({
|
|
134
|
+
command: "cat",
|
|
135
|
+
args: [skillMdPath]
|
|
136
|
+
});
|
|
137
|
+
if (execResult instanceof Error) {
|
|
138
|
+
log4.warn("failed to read skill file", {
|
|
139
|
+
path: skillMdPath,
|
|
140
|
+
error: execResult.message
|
|
141
|
+
});
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
const { stdout, exitCode } = await execResult.result;
|
|
145
|
+
if (exitCode !== 0) {
|
|
146
|
+
log4.warn("could not read skill file", { path: skillMdPath });
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
const parsed = parseSkillFrontmatter(stdout);
|
|
150
|
+
if (!parsed) {
|
|
151
|
+
log4.warn("invalid or missing frontmatter", { path: skillMdPath });
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
name: parsed.name,
|
|
156
|
+
description: parsed.description,
|
|
157
|
+
skillMdPath
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// src/tools/index.ts
|
|
162
|
+
import * as pathPosix from "path/posix";
|
|
163
|
+
import { jsonSchema, tool as tool2 } from "ai";
|
|
164
|
+
import { z as z2 } from "zod";
|
|
165
|
+
|
|
166
|
+
// src/tools/javascript.ts
|
|
167
|
+
import { tool } from "ai";
|
|
168
|
+
import { z } from "zod";
|
|
169
|
+
var REQUEST_MARKER_START = "__TOOL_REQUEST__";
|
|
170
|
+
var REQUEST_MARKER_END = "__TOOL_REQUEST_END__";
|
|
171
|
+
var EXECUTION_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
172
|
+
var RUNNER_SCRIPT = `
|
|
173
|
+
import { readFileSync, existsSync, unlinkSync, mkdirSync } from 'node:fs';
|
|
174
|
+
import { join, dirname } from 'node:path';
|
|
175
|
+
import { fileURLToPath } from 'node:url';
|
|
176
|
+
|
|
177
|
+
const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
|
|
178
|
+
const TOOL_CALL_TIMEOUT_MS = 300_000;
|
|
179
|
+
|
|
180
|
+
let reqCounter = 0;
|
|
181
|
+
|
|
182
|
+
async function callTool(name, input) {
|
|
183
|
+
const id = 'req_' + (++reqCounter) + '_' + Date.now();
|
|
184
|
+
const responseFile = join(SCRIPT_DIR, id + '.response.json');
|
|
185
|
+
|
|
186
|
+
const request = JSON.stringify({ id, tool: name, input });
|
|
187
|
+
process.stderr.write('${REQUEST_MARKER_START}' + request + '${REQUEST_MARKER_END}' + '\\n');
|
|
188
|
+
|
|
189
|
+
const start = Date.now();
|
|
190
|
+
while (!existsSync(responseFile)) {
|
|
191
|
+
if (Date.now() - start > TOOL_CALL_TIMEOUT_MS) {
|
|
192
|
+
throw new Error('Tool call ' + name + ' timed out waiting for response');
|
|
193
|
+
}
|
|
194
|
+
await new Promise(r => setTimeout(r, 30));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
let raw;
|
|
198
|
+
try {
|
|
199
|
+
raw = readFileSync(responseFile, 'utf8');
|
|
200
|
+
} catch {
|
|
201
|
+
await new Promise(r => setTimeout(r, 50));
|
|
202
|
+
raw = readFileSync(responseFile, 'utf8');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const response = JSON.parse(raw);
|
|
206
|
+
try { unlinkSync(responseFile); } catch {}
|
|
207
|
+
|
|
208
|
+
if (response.error) {
|
|
209
|
+
throw new Error(response.error);
|
|
210
|
+
}
|
|
211
|
+
return response.result;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const code = readFileSync(join(SCRIPT_DIR, 'code.js'), 'utf8');
|
|
215
|
+
const toolNames = JSON.parse(readFileSync(join(SCRIPT_DIR, 'tools.json'), 'utf8'));
|
|
216
|
+
|
|
217
|
+
const ctx = { tools: {} };
|
|
218
|
+
for (const name of toolNames) {
|
|
219
|
+
ctx.tools[name] = (input) => callTool(name, input);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const logs = [];
|
|
223
|
+
const customConsole = {
|
|
224
|
+
log: (...args) => logs.push(args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ')),
|
|
225
|
+
error: (...args) => logs.push('[error] ' + args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ')),
|
|
226
|
+
warn: (...args) => logs.push('[warn] ' + args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ')),
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
const AsyncFunction = Object.getPrototypeOf(async function() {}).constructor;
|
|
231
|
+
const fn = new AsyncFunction('ctx', 'console', code);
|
|
232
|
+
const result = await fn(ctx, customConsole);
|
|
233
|
+
|
|
234
|
+
const output = { success: true, result: result !== undefined ? result : null };
|
|
235
|
+
if (logs.length > 0) output.logs = logs;
|
|
236
|
+
process.stdout.write(JSON.stringify(output));
|
|
237
|
+
} catch (err) {
|
|
238
|
+
const output = {
|
|
239
|
+
success: false,
|
|
240
|
+
error: err instanceof Error ? err.message : String(err),
|
|
241
|
+
};
|
|
242
|
+
if (logs.length > 0) output.logs = logs;
|
|
243
|
+
process.stdout.write(JSON.stringify(output));
|
|
244
|
+
}
|
|
245
|
+
`;
|
|
246
|
+
function extractJsonSchema(schema) {
|
|
247
|
+
if (!schema || typeof schema !== "object") {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
if ("_def" in schema && typeof schema._def === "object") {
|
|
251
|
+
try {
|
|
252
|
+
return z.toJSONSchema(schema);
|
|
253
|
+
} catch {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
const s = schema;
|
|
258
|
+
if (/* @__PURE__ */ Symbol.for("vercel.ai.schema") in s && "jsonSchema" in s) {
|
|
259
|
+
return s.jsonSchema;
|
|
260
|
+
}
|
|
261
|
+
if ("type" in s || "properties" in s) {
|
|
262
|
+
return s;
|
|
263
|
+
}
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
function jsonSchemaToTs(schema, indent = 0) {
|
|
267
|
+
if (!schema) {
|
|
268
|
+
return "unknown";
|
|
269
|
+
}
|
|
270
|
+
if (schema.enum && Array.isArray(schema.enum)) {
|
|
271
|
+
return schema.enum.map((v) => JSON.stringify(v)).join(" | ");
|
|
272
|
+
}
|
|
273
|
+
if (schema.anyOf && Array.isArray(schema.anyOf)) {
|
|
274
|
+
return schema.anyOf.map((s) => jsonSchemaToTs(s, indent)).join(" | ");
|
|
275
|
+
}
|
|
276
|
+
if (schema.oneOf && Array.isArray(schema.oneOf)) {
|
|
277
|
+
return schema.oneOf.map((s) => jsonSchemaToTs(s, indent)).join(" | ");
|
|
278
|
+
}
|
|
279
|
+
const type = schema.type;
|
|
280
|
+
switch (type) {
|
|
281
|
+
case "string":
|
|
282
|
+
return "string";
|
|
283
|
+
case "number":
|
|
284
|
+
case "integer":
|
|
285
|
+
return "number";
|
|
286
|
+
case "boolean":
|
|
287
|
+
return "boolean";
|
|
288
|
+
case "null":
|
|
289
|
+
return "null";
|
|
290
|
+
case "array": {
|
|
291
|
+
const items = schema.items ? jsonSchemaToTs(schema.items, indent) : "unknown";
|
|
292
|
+
return `Array<${items}>`;
|
|
293
|
+
}
|
|
294
|
+
case "object": {
|
|
295
|
+
const properties = schema.properties;
|
|
296
|
+
if (!properties) {
|
|
297
|
+
return "Record<string, unknown>";
|
|
298
|
+
}
|
|
299
|
+
const required = new Set(schema.required || []);
|
|
300
|
+
const pad = " ".repeat(indent + 1);
|
|
301
|
+
const closePad = " ".repeat(indent);
|
|
302
|
+
const props = Object.entries(properties).map(([key, value]) => {
|
|
303
|
+
const opt = required.has(key) ? "" : "?";
|
|
304
|
+
return `${pad}${key}${opt}: ${jsonSchemaToTs(value, indent + 1)}`;
|
|
305
|
+
});
|
|
306
|
+
return `{
|
|
307
|
+
${props.join(";\n")};
|
|
308
|
+
${closePad}}`;
|
|
309
|
+
}
|
|
310
|
+
default:
|
|
311
|
+
return "unknown";
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
function generateContextTypeString(tools) {
|
|
315
|
+
const sigs = [];
|
|
316
|
+
for (const [name, t] of Object.entries(tools)) {
|
|
317
|
+
const raw = t;
|
|
318
|
+
const inputSchema = extractJsonSchema(raw.inputSchema ?? raw.parameters);
|
|
319
|
+
const outputSchema = extractJsonSchema(raw.outputSchema);
|
|
320
|
+
const inputType = inputSchema ? jsonSchemaToTs(inputSchema, 2) : "{}";
|
|
321
|
+
const outputType = outputSchema ? jsonSchemaToTs(outputSchema, 2) : "unknown";
|
|
322
|
+
sigs.push(` ${name}(input: ${inputType}): Promise<${outputType}>`);
|
|
323
|
+
}
|
|
324
|
+
return `type Context = {
|
|
325
|
+
tools: {
|
|
326
|
+
${sigs.join(";\n")};
|
|
327
|
+
}
|
|
328
|
+
}`;
|
|
329
|
+
}
|
|
330
|
+
async function executeInSandbox({
|
|
331
|
+
code,
|
|
332
|
+
rpcDir,
|
|
333
|
+
abortController,
|
|
334
|
+
sandbox,
|
|
335
|
+
availableTools,
|
|
336
|
+
onSubToolCall
|
|
337
|
+
}) {
|
|
338
|
+
const mkdirResult = await sandbox.exec({
|
|
339
|
+
command: "mkdir",
|
|
340
|
+
args: ["-p", rpcDir]
|
|
341
|
+
});
|
|
342
|
+
if (mkdirResult instanceof Error) {
|
|
343
|
+
return { success: false, error: mkdirResult.message };
|
|
344
|
+
}
|
|
345
|
+
await mkdirResult.result;
|
|
346
|
+
await sandbox.writeFiles({
|
|
347
|
+
files: [
|
|
348
|
+
{ path: "runner.mjs", content: RUNNER_SCRIPT },
|
|
349
|
+
{ path: "code.js", content: code },
|
|
350
|
+
{
|
|
351
|
+
path: "tools.json",
|
|
352
|
+
content: JSON.stringify(Object.keys(availableTools))
|
|
353
|
+
}
|
|
354
|
+
],
|
|
355
|
+
destPath: rpcDir
|
|
356
|
+
});
|
|
357
|
+
const nodeMajor = Number.parseInt(process.versions.node.split(".")[0], 10);
|
|
358
|
+
const permissionFlag = nodeMajor >= 22 ? "--permission" : "--experimental-permission";
|
|
359
|
+
const execResult = await sandbox.exec({
|
|
360
|
+
command: "node",
|
|
361
|
+
args: [
|
|
362
|
+
permissionFlag,
|
|
363
|
+
`--allow-fs-read=${rpcDir}`,
|
|
364
|
+
`--allow-fs-write=${rpcDir}`,
|
|
365
|
+
`${rpcDir}/runner.mjs`
|
|
366
|
+
],
|
|
367
|
+
signal: abortController.signal
|
|
368
|
+
});
|
|
369
|
+
if (execResult instanceof Error) {
|
|
370
|
+
return { success: false, error: execResult.message };
|
|
371
|
+
}
|
|
372
|
+
const fatal = { error: null };
|
|
373
|
+
const abort = (error) => {
|
|
374
|
+
if (!fatal.error) {
|
|
375
|
+
fatal.error = error;
|
|
376
|
+
abortController.abort();
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
const handleToolRequest = async (requestJson) => {
|
|
380
|
+
let parsed;
|
|
381
|
+
try {
|
|
382
|
+
parsed = JSON.parse(requestJson);
|
|
383
|
+
} catch {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
const { id, tool: toolName, input } = parsed;
|
|
387
|
+
let response;
|
|
388
|
+
try {
|
|
389
|
+
const t = availableTools[toolName];
|
|
390
|
+
if (!t?.execute) {
|
|
391
|
+
throw new Error(
|
|
392
|
+
`Tool ${toolName} not found or has no execute function`
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
const exec = t.execute.bind(t);
|
|
396
|
+
if (onSubToolCall) {
|
|
397
|
+
response = await onSubToolCall(
|
|
398
|
+
toolName,
|
|
399
|
+
input,
|
|
400
|
+
() => exec(input, {
|
|
401
|
+
toolCallId: `js_${toolName}_${Date.now()}`,
|
|
402
|
+
messages: []
|
|
403
|
+
})
|
|
404
|
+
);
|
|
405
|
+
} else {
|
|
406
|
+
const result = await exec(input, {
|
|
407
|
+
toolCallId: `js_${toolName}_${Date.now()}`,
|
|
408
|
+
messages: []
|
|
409
|
+
});
|
|
410
|
+
response = { result };
|
|
411
|
+
}
|
|
412
|
+
} catch (err) {
|
|
413
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
414
|
+
response = { error: msg };
|
|
415
|
+
}
|
|
416
|
+
try {
|
|
417
|
+
await sandbox.writeFiles({
|
|
418
|
+
files: [
|
|
419
|
+
{
|
|
420
|
+
path: `${id}.response.json`,
|
|
421
|
+
content: JSON.stringify(response)
|
|
422
|
+
}
|
|
423
|
+
],
|
|
424
|
+
destPath: rpcDir
|
|
425
|
+
});
|
|
426
|
+
} catch (err) {
|
|
427
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
428
|
+
abort(new Error(`Failed to write RPC response for ${toolName}: ${msg}`));
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
const toolCallPromises = [];
|
|
432
|
+
let stderrBuffer = "";
|
|
433
|
+
let nonMarkerStderr = "";
|
|
434
|
+
const timeout = setTimeout(() => {
|
|
435
|
+
abort(
|
|
436
|
+
new Error(
|
|
437
|
+
`JavaScript execution timed out after ${EXECUTION_TIMEOUT_MS / 1e3}s`
|
|
438
|
+
)
|
|
439
|
+
);
|
|
440
|
+
}, EXECUTION_TIMEOUT_MS);
|
|
441
|
+
try {
|
|
442
|
+
for await (const entry of execResult.logs()) {
|
|
443
|
+
if (fatal.error) {
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
if (entry.stream === "stderr") {
|
|
447
|
+
stderrBuffer += entry.data;
|
|
448
|
+
while (true) {
|
|
449
|
+
const startIdx = stderrBuffer.indexOf(REQUEST_MARKER_START);
|
|
450
|
+
if (startIdx === -1) {
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
const beforeMarker = stderrBuffer.slice(0, startIdx);
|
|
454
|
+
if (beforeMarker.trim()) {
|
|
455
|
+
nonMarkerStderr += beforeMarker;
|
|
456
|
+
}
|
|
457
|
+
const contentStart = startIdx + REQUEST_MARKER_START.length;
|
|
458
|
+
const endIdx = stderrBuffer.indexOf(REQUEST_MARKER_END, contentStart);
|
|
459
|
+
if (endIdx === -1) {
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
const requestJson = stderrBuffer.slice(contentStart, endIdx);
|
|
463
|
+
stderrBuffer = stderrBuffer.slice(endIdx + REQUEST_MARKER_END.length);
|
|
464
|
+
toolCallPromises.push(handleToolRequest(requestJson));
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
} finally {
|
|
469
|
+
clearTimeout(timeout);
|
|
470
|
+
}
|
|
471
|
+
if (stderrBuffer.trim()) {
|
|
472
|
+
nonMarkerStderr += stderrBuffer;
|
|
473
|
+
}
|
|
474
|
+
await Promise.allSettled(toolCallPromises);
|
|
475
|
+
if (fatal.error) {
|
|
476
|
+
execResult.result.catch(() => void 0);
|
|
477
|
+
return {
|
|
478
|
+
success: false,
|
|
479
|
+
error: fatal.error.message,
|
|
480
|
+
...nonMarkerStderr ? { stderr: nonMarkerStderr.slice(0, 2e3) } : {}
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
const { stdout, stderr, exitCode } = await execResult.result;
|
|
484
|
+
try {
|
|
485
|
+
return JSON.parse(stdout);
|
|
486
|
+
} catch {
|
|
487
|
+
return {
|
|
488
|
+
success: false,
|
|
489
|
+
error: `Runner failed (exit ${exitCode}).`,
|
|
490
|
+
stderr: (nonMarkerStderr + stderr).slice(0, 2e3),
|
|
491
|
+
stdout: stdout.slice(0, 1e3)
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
function createJavaScriptTool(opts) {
|
|
496
|
+
const { session, sandbox, onSubToolCall } = opts;
|
|
497
|
+
const activeSet = session.activeTools ? new Set(session.activeTools) : null;
|
|
498
|
+
const availableTools = {};
|
|
499
|
+
for (const [name, t] of Object.entries(opts.tools)) {
|
|
500
|
+
if (!activeSet || activeSet.has(name)) {
|
|
501
|
+
availableTools[name] = t;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
const contextType = generateContextTypeString(availableTools);
|
|
505
|
+
return tool({
|
|
506
|
+
...builtInTools.JavaScript,
|
|
507
|
+
description: `Execute JavaScript to orchestrate multiple tool calls in a single step. Use this when you need to run several tools in sequence, transform intermediate results, or parallelize independent operations with Promise.all.
|
|
508
|
+
|
|
509
|
+
The code runs as an async function body with \`ctx\` in scope:
|
|
510
|
+
|
|
511
|
+
\`\`\`typescript
|
|
512
|
+
${contextType}
|
|
513
|
+
\`\`\`
|
|
514
|
+
|
|
515
|
+
Examples:
|
|
516
|
+
- Sequential: \`const file = await ctx.tools.Read({ path: "package.json" }); return JSON.parse(file.content);\`
|
|
517
|
+
- Parallel: \`const [a, b] = await Promise.all([ctx.tools.Read({ path: "a.ts" }), ctx.tools.Read({ path: "b.ts" })]); return { a: a.content, b: b.content };\`
|
|
518
|
+
- Transform: \`const grep = await ctx.tools.Grep({ pattern: "TODO" }); return grep.matches.split("\\n").length;\`
|
|
519
|
+
- Bash: \`const r = await ctx.tools.Bash({ command: "node -e \\"console.log(JSON.stringify({v:1}))\\"" }); return JSON.parse(r.stdout);\`
|
|
520
|
+
|
|
521
|
+
Return a value to pass results back. Use console.log() for debug output.
|
|
522
|
+
Important: Each tool returns a structured object matching its output schema \u2014 not a raw string. Access the specific field you need (e.g. Bash's result.stdout, Read's result.content) rather than trying to parse the entire result.`,
|
|
523
|
+
execute: ({ code }) => {
|
|
524
|
+
const runId = `run_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
525
|
+
const rpcDir = `.agent/js-rpc/${runId}`;
|
|
526
|
+
const abortController = new AbortController();
|
|
527
|
+
return executeInSandbox({
|
|
528
|
+
code,
|
|
529
|
+
rpcDir,
|
|
530
|
+
abortController,
|
|
531
|
+
sandbox,
|
|
532
|
+
availableTools,
|
|
533
|
+
onSubToolCall
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// src/tools/index.ts
|
|
540
|
+
var log = createLogger({ subsystem: "tools" });
|
|
541
|
+
var AGENT_PROTOCOL_VERSION = "v1";
|
|
542
|
+
function formatFileSize(bytes) {
|
|
543
|
+
if (bytes < 1024) {
|
|
544
|
+
return `${bytes}`;
|
|
545
|
+
}
|
|
546
|
+
if (bytes < 1024 * 1024) {
|
|
547
|
+
return `${(bytes / 1024).toFixed(1)}K`;
|
|
548
|
+
}
|
|
549
|
+
if (bytes < 1024 * 1024 * 1024) {
|
|
550
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}M`;
|
|
551
|
+
}
|
|
552
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}G`;
|
|
553
|
+
}
|
|
554
|
+
function isRgNotFoundError(err) {
|
|
555
|
+
const parts = [err.message];
|
|
556
|
+
const anyErr = err;
|
|
557
|
+
if (typeof anyErr.reason === "string") {
|
|
558
|
+
parts.push(anyErr.reason);
|
|
559
|
+
}
|
|
560
|
+
if (anyErr.cause instanceof Error) {
|
|
561
|
+
parts.push(anyErr.cause.message);
|
|
562
|
+
const anyCause = anyErr.cause;
|
|
563
|
+
if (typeof anyCause.text === "string") {
|
|
564
|
+
parts.push(anyCause.text);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
const msg = parts.join(" ").toLowerCase();
|
|
568
|
+
return msg.includes("executable file not found") || msg.includes("executable_not_found") || msg.includes("enoent") && msg.includes("rg");
|
|
569
|
+
}
|
|
570
|
+
var builtInTools = {
|
|
571
|
+
Read: tool2({
|
|
572
|
+
description: "Reads a file and returns its contents with metadata. For files over 200 lines, automatically shows first 100 lines unless a specific line range is provided. Use startLine and endLine parameters to read specific portions of large files.",
|
|
573
|
+
inputSchema: z2.object({
|
|
574
|
+
label: z2.string().describe("A label that describes the action being performed"),
|
|
575
|
+
path: z2.string().describe("Absolute path to the file"),
|
|
576
|
+
startLine: z2.number().optional().describe(
|
|
577
|
+
"Starting line number (1-indexed). If provided with endLine, reads exact range regardless of file size."
|
|
578
|
+
),
|
|
579
|
+
endLine: z2.number().optional().describe(
|
|
580
|
+
"Ending line number (1-indexed, inclusive). If provided with startLine, reads exact range regardless of file size."
|
|
581
|
+
)
|
|
582
|
+
}),
|
|
583
|
+
outputSchema: z2.object({
|
|
584
|
+
content: z2.string().describe("File content"),
|
|
585
|
+
metadata: z2.object({
|
|
586
|
+
totalLines: z2.number().describe("Total number of lines in the file"),
|
|
587
|
+
linesShown: z2.number().describe("Number of lines included in this response"),
|
|
588
|
+
startLine: z2.number().describe("First line number shown (1-indexed)"),
|
|
589
|
+
endLine: z2.number().describe("Last line number shown (1-indexed)"),
|
|
590
|
+
isPaginated: z2.boolean().describe("Whether this is a partial view of the file"),
|
|
591
|
+
fileSize: z2.string().describe("Human-readable file size (e.g., '2.5K', '1.2M')"),
|
|
592
|
+
path: z2.string().describe("Path to the file relative to workspace root")
|
|
593
|
+
})
|
|
594
|
+
})
|
|
595
|
+
}),
|
|
596
|
+
Grep: tool2({
|
|
597
|
+
description: "Search for patterns in files using ripgrep. Use this to find code patterns, function definitions, imports, etc.",
|
|
598
|
+
inputSchema: z2.object({
|
|
599
|
+
label: z2.string().describe("A label that describes the action being performed"),
|
|
600
|
+
pattern: z2.string().describe("Regex pattern to search for (ripgrep syntax)"),
|
|
601
|
+
path: z2.string().optional().describe(
|
|
602
|
+
"Absolute path to search in (defaults to working directory). Can be a file or directory."
|
|
603
|
+
),
|
|
604
|
+
fileType: z2.string().optional().describe(
|
|
605
|
+
"File type to filter by (e.g., 'ts', 'js', 'py', 'md'). Uses ripgrep's built-in type filters."
|
|
606
|
+
),
|
|
607
|
+
glob: z2.string().optional().describe(
|
|
608
|
+
"Glob pattern to filter files (e.g., '*.tsx', 'src/**/*.ts')"
|
|
609
|
+
),
|
|
610
|
+
caseSensitive: z2.boolean().optional().default(true).describe("Whether search is case-sensitive (default: true)"),
|
|
611
|
+
contextLines: z2.number().optional().describe(
|
|
612
|
+
"Number of context lines to show before and after each match"
|
|
613
|
+
),
|
|
614
|
+
maxCount: z2.number().optional().describe(
|
|
615
|
+
"Maximum number of matches per file (useful for limiting output)"
|
|
616
|
+
),
|
|
617
|
+
filesWithMatches: z2.boolean().optional().default(false).describe(
|
|
618
|
+
"Only show file paths that contain matches, not the matching lines themselves"
|
|
619
|
+
)
|
|
620
|
+
}),
|
|
621
|
+
outputSchema: z2.object({
|
|
622
|
+
matches: z2.string().describe(
|
|
623
|
+
"Search results with file paths, line numbers, and matching content"
|
|
624
|
+
),
|
|
625
|
+
summary: z2.object({
|
|
626
|
+
matchCount: z2.number().describe("Number of matches found"),
|
|
627
|
+
fileCount: z2.number().describe("Number of files containing matches"),
|
|
628
|
+
searchPath: z2.string().describe("Path that was searched"),
|
|
629
|
+
pattern: z2.string().describe("Pattern that was searched for")
|
|
630
|
+
})
|
|
631
|
+
})
|
|
632
|
+
}),
|
|
633
|
+
List: tool2({
|
|
634
|
+
description: "Recursively list directory contents. Use this to understand the codebase structure, find files, or explore directories. Control depth to balance detail vs. overview. Depth 1 shows immediate children, depth 2 includes subdirectories, etc.",
|
|
635
|
+
inputSchema: z2.object({
|
|
636
|
+
label: z2.string().describe("A label that describes the action being performed"),
|
|
637
|
+
path: z2.string().optional().describe("Absolute path to list (defaults to working directory)"),
|
|
638
|
+
depth: z2.number().optional().describe(
|
|
639
|
+
"Maximum depth to traverse. Choose based on context: 1-2 for quick overview, 3-4 for detailed exploration, 5+ for comprehensive mapping"
|
|
640
|
+
),
|
|
641
|
+
includeHidden: z2.boolean().optional().default(false).describe(
|
|
642
|
+
"Include hidden files and directories (those starting with '.')"
|
|
643
|
+
),
|
|
644
|
+
filesOnly: z2.boolean().optional().default(false).describe("Only show files, not directories"),
|
|
645
|
+
pattern: z2.string().optional().describe("Glob pattern to filter results (e.g., '*.ts', '*test*')")
|
|
646
|
+
}),
|
|
647
|
+
outputSchema: z2.object({
|
|
648
|
+
listing: z2.string().describe(
|
|
649
|
+
"Directory tree listing showing paths relative to search root"
|
|
650
|
+
),
|
|
651
|
+
summary: z2.object({
|
|
652
|
+
totalItems: z2.number().describe("Total number of items found"),
|
|
653
|
+
totalFiles: z2.number().describe("Total number of files found"),
|
|
654
|
+
totalDirs: z2.number().describe("Total number of directories found"),
|
|
655
|
+
searchPath: z2.string().describe("Path that was listed"),
|
|
656
|
+
depth: z2.number().optional().describe("Maximum depth used (if specified)")
|
|
657
|
+
})
|
|
658
|
+
})
|
|
659
|
+
}),
|
|
660
|
+
Write: tool2({
|
|
661
|
+
description: "Write content to a file. Creates parent directories automatically. Overwrites existing files.",
|
|
662
|
+
inputSchema: z2.object({
|
|
663
|
+
label: z2.string().describe("A label that describes the action being performed"),
|
|
664
|
+
path: z2.string().describe("Absolute path to the file"),
|
|
665
|
+
content: z2.string().describe("Content to write to the file")
|
|
666
|
+
}),
|
|
667
|
+
outputSchema: z2.object({
|
|
668
|
+
success: z2.boolean().describe("Whether the write succeeded"),
|
|
669
|
+
path: z2.string().describe("Path to the written file"),
|
|
670
|
+
bytesWritten: z2.number().describe("Number of bytes written"),
|
|
671
|
+
error: z2.string().optional().describe("Error message if write failed")
|
|
672
|
+
})
|
|
673
|
+
}),
|
|
674
|
+
Edit: tool2({
|
|
675
|
+
description: "Edit a file by replacing an exact string. Fails if old_string is not found or appears multiple times (not unique). For multiple replacements, call this tool multiple times with unique context.",
|
|
676
|
+
inputSchema: z2.object({
|
|
677
|
+
label: z2.string().describe("A label that describes the action being performed"),
|
|
678
|
+
path: z2.string().describe("Absolute path to the file"),
|
|
679
|
+
old_string: z2.string().describe("Exact string to find and replace (must be unique in file)"),
|
|
680
|
+
new_string: z2.string().describe("String to replace old_string with")
|
|
681
|
+
}),
|
|
682
|
+
outputSchema: z2.object({
|
|
683
|
+
success: z2.boolean().describe("Whether the edit succeeded"),
|
|
684
|
+
path: z2.string().describe("Path to the edited file"),
|
|
685
|
+
error: z2.string().optional().describe("Error message if edit failed")
|
|
686
|
+
})
|
|
687
|
+
}),
|
|
688
|
+
Bash: tool2({
|
|
689
|
+
description: "Executes a bash command. Returns stdout and stderr separately. Use waitUntil to control how long to wait (0 = return immediately, process keeps running). Large outputs are tail-truncated; full output in outputDir.",
|
|
690
|
+
inputSchema: z2.object({
|
|
691
|
+
label: z2.string().describe("A label that describes the action being performed"),
|
|
692
|
+
command: z2.string().describe("The shell command to execute"),
|
|
693
|
+
waitUntil: z2.number().optional().describe(
|
|
694
|
+
`Max ms to wait for completion (default: ${DEFAULT_WAIT_UNTIL}). Use 0 to return immediately while the process keeps running.`
|
|
695
|
+
)
|
|
696
|
+
}),
|
|
697
|
+
outputSchema: z2.object({
|
|
698
|
+
commandId: z2.string().describe("Command ID. Use to reference or kill running processes."),
|
|
699
|
+
stdout: z2.string().describe(
|
|
700
|
+
"Command stdout. Tail-truncated if large; full content in outputDir/stdout.txt."
|
|
701
|
+
),
|
|
702
|
+
stderr: z2.string().describe(
|
|
703
|
+
"Command stderr. Tail-truncated if large; full content in outputDir/stderr.txt."
|
|
704
|
+
),
|
|
705
|
+
exitCode: z2.number().describe("Exit code (-1 if still running)"),
|
|
706
|
+
status: z2.enum(["running", "completed", "failed"]).describe("Process status"),
|
|
707
|
+
outputDir: z2.string().describe(
|
|
708
|
+
"Path to output directory containing stdout.txt, stderr.txt, and metadata.json. Empty if still running."
|
|
709
|
+
)
|
|
710
|
+
})
|
|
711
|
+
}),
|
|
712
|
+
Skill: tool2({
|
|
713
|
+
description: "Load a skill's full instructions by name. Call this before following a skill.",
|
|
714
|
+
inputSchema: z2.object({
|
|
715
|
+
label: z2.string().describe("A label that describes the action being performed"),
|
|
716
|
+
name: z2.string().describe("Skill name from the Available Skills list")
|
|
717
|
+
}),
|
|
718
|
+
outputSchema: z2.object({
|
|
719
|
+
name: z2.string(),
|
|
720
|
+
description: z2.string(),
|
|
721
|
+
content: z2.string().describe("Full SKILL.md content"),
|
|
722
|
+
path: z2.string().describe("Path to the skill directory in the sandbox")
|
|
723
|
+
})
|
|
724
|
+
}),
|
|
725
|
+
JavaScript: tool2({
|
|
726
|
+
inputSchema: z2.object({
|
|
727
|
+
label: z2.string().describe("A label that describes the action being performed"),
|
|
728
|
+
code: z2.string().describe(
|
|
729
|
+
"JavaScript async function body. `ctx` is in scope. Must use `return` to produce output."
|
|
730
|
+
)
|
|
731
|
+
})
|
|
732
|
+
})
|
|
733
|
+
};
|
|
734
|
+
var builtinToolNames = Object.fromEntries(
|
|
735
|
+
Object.entries(builtInTools).map(([name]) => [name, name])
|
|
736
|
+
);
|
|
737
|
+
var SKILL_MD_SUFFIX = /\/?SKILL\.md$/;
|
|
738
|
+
function getTools(context) {
|
|
739
|
+
const tools = {
|
|
740
|
+
[builtinToolNames.Read]: tool2({
|
|
741
|
+
...builtInTools.Read,
|
|
742
|
+
execute: async ({ path, startLine, endLine }) => {
|
|
743
|
+
const filePath = path;
|
|
744
|
+
const result = await context.sandbox.readFile({ path: filePath });
|
|
745
|
+
if (result instanceof Error) {
|
|
746
|
+
log.error("Read failed", { error: result.message });
|
|
747
|
+
throw result;
|
|
748
|
+
}
|
|
749
|
+
if (result === null) {
|
|
750
|
+
return {
|
|
751
|
+
content: `Error: File not found - ${filePath}`,
|
|
752
|
+
metadata: {
|
|
753
|
+
totalLines: 0,
|
|
754
|
+
linesShown: 0,
|
|
755
|
+
startLine: 0,
|
|
756
|
+
endLine: 0,
|
|
757
|
+
isPaginated: false,
|
|
758
|
+
fileSize: "0",
|
|
759
|
+
path: filePath
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
const fullContent = result.toString("utf-8");
|
|
764
|
+
const lines = fullContent.split("\n");
|
|
765
|
+
if (lines.length > 0 && lines.at(-1) === "") {
|
|
766
|
+
lines.pop();
|
|
767
|
+
}
|
|
768
|
+
const totalLines = lines.length;
|
|
769
|
+
const fileBytes = Buffer.byteLength(fullContent);
|
|
770
|
+
const fileSize = formatFileSize(fileBytes);
|
|
771
|
+
const PAGE_SIZE = 100;
|
|
772
|
+
let actualStart;
|
|
773
|
+
let actualEnd;
|
|
774
|
+
if (startLine !== void 0 && endLine !== void 0) {
|
|
775
|
+
actualStart = startLine;
|
|
776
|
+
actualEnd = endLine;
|
|
777
|
+
} else if (startLine !== void 0) {
|
|
778
|
+
actualStart = startLine;
|
|
779
|
+
actualEnd = Math.min(startLine + PAGE_SIZE - 1, totalLines);
|
|
780
|
+
} else if (endLine !== void 0) {
|
|
781
|
+
actualStart = 1;
|
|
782
|
+
actualEnd = endLine;
|
|
783
|
+
} else if (totalLines > 200) {
|
|
784
|
+
actualStart = 1;
|
|
785
|
+
actualEnd = PAGE_SIZE;
|
|
786
|
+
} else {
|
|
787
|
+
actualStart = 1;
|
|
788
|
+
actualEnd = totalLines;
|
|
789
|
+
}
|
|
790
|
+
const slicedLines = lines.slice(actualStart - 1, actualEnd);
|
|
791
|
+
const content = slicedLines.join("\n");
|
|
792
|
+
return {
|
|
793
|
+
metadata: {
|
|
794
|
+
totalLines,
|
|
795
|
+
linesShown: Math.max(0, actualEnd - actualStart + 1),
|
|
796
|
+
startLine: actualStart,
|
|
797
|
+
endLine: actualEnd,
|
|
798
|
+
isPaginated: actualEnd < totalLines,
|
|
799
|
+
fileSize,
|
|
800
|
+
path: filePath
|
|
801
|
+
},
|
|
802
|
+
content
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
}),
|
|
806
|
+
[builtinToolNames.Grep]: tool2({
|
|
807
|
+
...builtInTools.Grep,
|
|
808
|
+
execute: async ({
|
|
809
|
+
pattern,
|
|
810
|
+
path,
|
|
811
|
+
fileType,
|
|
812
|
+
glob,
|
|
813
|
+
caseSensitive,
|
|
814
|
+
contextLines,
|
|
815
|
+
maxCount,
|
|
816
|
+
filesWithMatches
|
|
817
|
+
}) => {
|
|
818
|
+
const searchPath = path ?? ".";
|
|
819
|
+
const args = [];
|
|
820
|
+
args.push("--line-number");
|
|
821
|
+
args.push("--heading");
|
|
822
|
+
args.push("--color", "never");
|
|
823
|
+
if (!caseSensitive) {
|
|
824
|
+
args.push("-i");
|
|
825
|
+
}
|
|
826
|
+
if (fileType) {
|
|
827
|
+
args.push("--type", fileType);
|
|
828
|
+
}
|
|
829
|
+
if (glob) {
|
|
830
|
+
args.push("--glob", glob);
|
|
831
|
+
}
|
|
832
|
+
if (contextLines !== void 0) {
|
|
833
|
+
args.push("-C", String(contextLines));
|
|
834
|
+
}
|
|
835
|
+
if (maxCount !== void 0) {
|
|
836
|
+
args.push("--max-count", String(maxCount));
|
|
837
|
+
}
|
|
838
|
+
if (filesWithMatches) {
|
|
839
|
+
args.push("--files-with-matches");
|
|
840
|
+
}
|
|
841
|
+
args.push("--", pattern, searchPath);
|
|
842
|
+
let result = await context.sandbox.exec({ command: "rg", args });
|
|
843
|
+
if (result instanceof Error && isRgNotFoundError(result)) {
|
|
844
|
+
log.warn("rg not found, installing ripgrep");
|
|
845
|
+
const installResult = await context.sandbox.exec({
|
|
846
|
+
command: "bash",
|
|
847
|
+
args: [
|
|
848
|
+
"-c",
|
|
849
|
+
[
|
|
850
|
+
"command -v rg >/dev/null 2>&1 && exit 0",
|
|
851
|
+
"dnf install -y ripgrep 2>/dev/null && exit 0",
|
|
852
|
+
"(apt-get update -qq && apt-get install -y -qq ripgrep) 2>/dev/null && exit 0",
|
|
853
|
+
"apk add --no-cache ripgrep 2>/dev/null && exit 0",
|
|
854
|
+
"curl -sL https://github.com/BurntSushi/ripgrep/releases/download/14.1.1/ripgrep-14.1.1-x86_64-unknown-linux-musl.tar.gz | tar xz -C /tmp && install /tmp/ripgrep-14.1.1-x86_64-unknown-linux-musl/rg /usr/local/bin/rg && rm -rf /tmp/ripgrep-14.1.1-x86_64-unknown-linux-musl"
|
|
855
|
+
].join("\n")
|
|
856
|
+
],
|
|
857
|
+
sudo: true
|
|
858
|
+
});
|
|
859
|
+
if (!(installResult instanceof Error)) {
|
|
860
|
+
const installOutput = await installResult.result;
|
|
861
|
+
if (installOutput.exitCode !== 0) {
|
|
862
|
+
log.warn("ripgrep install failed", {
|
|
863
|
+
stderr: installOutput.stderr
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
result = await context.sandbox.exec({ command: "rg", args });
|
|
868
|
+
}
|
|
869
|
+
if (result instanceof Error && isRgNotFoundError(result)) {
|
|
870
|
+
log.warn("rg unavailable, falling back to grep");
|
|
871
|
+
const grepArgs = ["-rn", "--color=never"];
|
|
872
|
+
if (!caseSensitive) {
|
|
873
|
+
grepArgs.push("-i");
|
|
874
|
+
}
|
|
875
|
+
if (contextLines !== void 0) {
|
|
876
|
+
grepArgs.push("-C", String(contextLines));
|
|
877
|
+
}
|
|
878
|
+
if (maxCount !== void 0) {
|
|
879
|
+
grepArgs.push("-m", String(maxCount));
|
|
880
|
+
}
|
|
881
|
+
if (filesWithMatches) {
|
|
882
|
+
grepArgs.push("-l");
|
|
883
|
+
}
|
|
884
|
+
if (glob) {
|
|
885
|
+
grepArgs.push(`--include=${glob}`);
|
|
886
|
+
}
|
|
887
|
+
if (fileType) {
|
|
888
|
+
const includeMap = {
|
|
889
|
+
ts: ["*.ts", "*.tsx", "*.mts", "*.cts"],
|
|
890
|
+
js: ["*.js", "*.jsx", "*.mjs", "*.cjs"],
|
|
891
|
+
py: ["*.py"],
|
|
892
|
+
rust: ["*.rs"],
|
|
893
|
+
go: ["*.go"],
|
|
894
|
+
java: ["*.java"],
|
|
895
|
+
md: ["*.md"],
|
|
896
|
+
json: ["*.json"],
|
|
897
|
+
css: ["*.css"],
|
|
898
|
+
html: ["*.html"],
|
|
899
|
+
yaml: ["*.yml", "*.yaml"]
|
|
900
|
+
};
|
|
901
|
+
for (const ext of includeMap[fileType] ?? [`*.${fileType}`]) {
|
|
902
|
+
grepArgs.push(`--include=${ext}`);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
grepArgs.push("--", pattern, searchPath);
|
|
906
|
+
result = await context.sandbox.exec({
|
|
907
|
+
command: "grep",
|
|
908
|
+
args: grepArgs
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
if (result instanceof Error) {
|
|
912
|
+
log.error("Grep failed", { error: result.message });
|
|
913
|
+
throw result;
|
|
914
|
+
}
|
|
915
|
+
const { stdout, stderr } = await result.result;
|
|
916
|
+
if (stderr && !stderr.toLowerCase().includes("no matches")) {
|
|
917
|
+
log.warn("Grep stderr", { stderr });
|
|
918
|
+
}
|
|
919
|
+
const MAX_GREP_OUTPUT_CHARS = 5e4;
|
|
920
|
+
let finalOutput = stdout;
|
|
921
|
+
let wasTruncated = false;
|
|
922
|
+
if (finalOutput.length > MAX_GREP_OUTPUT_CHARS) {
|
|
923
|
+
finalOutput = finalOutput.slice(0, MAX_GREP_OUTPUT_CHARS) + "\n\n[Output truncated - use more specific pattern or path]";
|
|
924
|
+
wasTruncated = true;
|
|
925
|
+
}
|
|
926
|
+
const lines = finalOutput.trim().split("\n").filter((l) => l.length > 0);
|
|
927
|
+
const fileCount = filesWithMatches ? lines.length : new Set(
|
|
928
|
+
lines.filter((l) => !l.startsWith(" ") && l.includes(":")).map((l) => l.split(":")[0])
|
|
929
|
+
).size;
|
|
930
|
+
return {
|
|
931
|
+
summary: {
|
|
932
|
+
matchCount: filesWithMatches ? 0 : lines.filter((l) => l.includes(":")).length,
|
|
933
|
+
fileCount,
|
|
934
|
+
searchPath,
|
|
935
|
+
pattern,
|
|
936
|
+
wasTruncated
|
|
937
|
+
},
|
|
938
|
+
matches: finalOutput || "(no matches found)"
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
}),
|
|
942
|
+
[builtinToolNames.List]: tool2({
|
|
943
|
+
...builtInTools.List,
|
|
944
|
+
execute: async ({ path, depth, includeHidden, filesOnly, pattern }) => {
|
|
945
|
+
const searchPath = path ?? ".";
|
|
946
|
+
const result = await context.sandbox.exec({
|
|
947
|
+
command: "bash",
|
|
948
|
+
args: [
|
|
949
|
+
"-c",
|
|
950
|
+
`
|
|
951
|
+
set -e
|
|
952
|
+
SEARCH_PATH="$1"
|
|
953
|
+
DEPTH="$2"
|
|
954
|
+
INCLUDE_HIDDEN="$3"
|
|
955
|
+
FILES_ONLY="$4"
|
|
956
|
+
PATTERN="$5"
|
|
957
|
+
|
|
958
|
+
# Build find command arguments
|
|
959
|
+
FIND_ARGS=""
|
|
960
|
+
[ -n "$DEPTH" ] && FIND_ARGS="$FIND_ARGS -maxdepth $DEPTH"
|
|
961
|
+
[ "$INCLUDE_HIDDEN" != "true" ] && FIND_ARGS="$FIND_ARGS ! -path '*/.*'"
|
|
962
|
+
[ "$FILES_ONLY" = "true" ] && FIND_ARGS="$FIND_ARGS -type f"
|
|
963
|
+
[ -n "$PATTERN" ] && FIND_ARGS="$FIND_ARGS -name '$PATTERN'"
|
|
964
|
+
|
|
965
|
+
# Get listing
|
|
966
|
+
LISTING=$(eval "find '$SEARCH_PATH' $FIND_ARGS" 2>/dev/null | sort)
|
|
967
|
+
|
|
968
|
+
# Get counts
|
|
969
|
+
COUNT_ARGS=""
|
|
970
|
+
[ -n "$DEPTH" ] && COUNT_ARGS="$COUNT_ARGS -maxdepth $DEPTH"
|
|
971
|
+
[ "$INCLUDE_HIDDEN" != "true" ] && COUNT_ARGS="$COUNT_ARGS ! -path '*/.*'"
|
|
972
|
+
|
|
973
|
+
FILE_COUNT=$(eval "find '$SEARCH_PATH' $COUNT_ARGS -type f" 2>/dev/null | wc -l)
|
|
974
|
+
DIR_COUNT=$(eval "find '$SEARCH_PATH' $COUNT_ARGS -type d" 2>/dev/null | wc -l)
|
|
975
|
+
|
|
976
|
+
# Output: counts first, then listing
|
|
977
|
+
echo "$FILE_COUNT|$DIR_COUNT"
|
|
978
|
+
echo "|||LISTING|||"
|
|
979
|
+
echo "$LISTING" | sed "s|^$SEARCH_PATH|.|"
|
|
980
|
+
`,
|
|
981
|
+
"--",
|
|
982
|
+
searchPath,
|
|
983
|
+
depth?.toString() || "",
|
|
984
|
+
includeHidden ? "true" : "false",
|
|
985
|
+
filesOnly ? "true" : "false",
|
|
986
|
+
pattern || ""
|
|
987
|
+
]
|
|
988
|
+
});
|
|
989
|
+
if (result instanceof Error) {
|
|
990
|
+
log.error("List failed", { error: result.message });
|
|
991
|
+
throw result;
|
|
992
|
+
}
|
|
993
|
+
const { stdout, stderr } = await result.result;
|
|
994
|
+
if (stderr) {
|
|
995
|
+
log.warn("List stderr", { stderr });
|
|
996
|
+
}
|
|
997
|
+
const [countsLine, ...rest] = stdout.split("|||LISTING|||");
|
|
998
|
+
const listing = rest.join("|||LISTING|||").trim();
|
|
999
|
+
const [fileCountStr, dirCountStr] = countsLine.trim().split("|");
|
|
1000
|
+
const totalFiles = Number.parseInt(fileCountStr, 10) || 0;
|
|
1001
|
+
const totalDirs = Number.parseInt(dirCountStr, 10) || 0;
|
|
1002
|
+
const lines = listing.split("\n").filter((l) => l.length > 0);
|
|
1003
|
+
return {
|
|
1004
|
+
summary: {
|
|
1005
|
+
totalItems: lines.length,
|
|
1006
|
+
totalFiles,
|
|
1007
|
+
totalDirs,
|
|
1008
|
+
searchPath,
|
|
1009
|
+
depth
|
|
1010
|
+
},
|
|
1011
|
+
listing
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
}),
|
|
1015
|
+
[builtinToolNames.Write]: tool2({
|
|
1016
|
+
...builtInTools.Write,
|
|
1017
|
+
execute: async ({ path, content }) => {
|
|
1018
|
+
const filePath = path;
|
|
1019
|
+
const dir = pathPosix.dirname(filePath);
|
|
1020
|
+
const fileName = pathPosix.basename(filePath);
|
|
1021
|
+
try {
|
|
1022
|
+
if (dir !== ".") {
|
|
1023
|
+
await context.sandbox.exec({ command: "mkdir", args: ["-p", dir] });
|
|
1024
|
+
}
|
|
1025
|
+
await context.sandbox.writeFiles({
|
|
1026
|
+
files: [{ path: fileName, content }],
|
|
1027
|
+
destPath: dir
|
|
1028
|
+
});
|
|
1029
|
+
return {
|
|
1030
|
+
success: true,
|
|
1031
|
+
path: filePath,
|
|
1032
|
+
bytesWritten: Buffer.byteLength(content, "utf8")
|
|
1033
|
+
};
|
|
1034
|
+
} catch (err) {
|
|
1035
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
1036
|
+
return {
|
|
1037
|
+
success: false,
|
|
1038
|
+
path: filePath,
|
|
1039
|
+
bytesWritten: 0,
|
|
1040
|
+
error: errorMsg
|
|
1041
|
+
};
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
}),
|
|
1045
|
+
[builtinToolNames.Edit]: tool2({
|
|
1046
|
+
...builtInTools.Edit,
|
|
1047
|
+
execute: async ({ path, old_string, new_string }) => {
|
|
1048
|
+
const filePath = path;
|
|
1049
|
+
const result = await context.sandbox.readFile({ path: filePath });
|
|
1050
|
+
if (result instanceof Error) {
|
|
1051
|
+
return { success: false, path: filePath, error: result.message };
|
|
1052
|
+
}
|
|
1053
|
+
if (result === null) {
|
|
1054
|
+
return {
|
|
1055
|
+
success: false,
|
|
1056
|
+
path: filePath,
|
|
1057
|
+
error: `File not found: ${filePath}`
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
const content = result.toString("utf-8");
|
|
1061
|
+
const occurrences = content.split(old_string).length - 1;
|
|
1062
|
+
if (occurrences === 0) {
|
|
1063
|
+
return {
|
|
1064
|
+
success: false,
|
|
1065
|
+
path: filePath,
|
|
1066
|
+
error: "old_string not found in file"
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
if (occurrences > 1) {
|
|
1070
|
+
return {
|
|
1071
|
+
success: false,
|
|
1072
|
+
path: filePath,
|
|
1073
|
+
error: `old_string appears ${occurrences} times in file (must be unique). Include more surrounding context to make the match unique.`
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
const newContent = content.replace(old_string, new_string);
|
|
1077
|
+
const dir = pathPosix.dirname(filePath);
|
|
1078
|
+
const fileName = pathPosix.basename(filePath);
|
|
1079
|
+
try {
|
|
1080
|
+
await context.sandbox.writeFiles({
|
|
1081
|
+
files: [{ path: fileName, content: newContent }],
|
|
1082
|
+
destPath: dir
|
|
1083
|
+
});
|
|
1084
|
+
return { success: true, path: filePath };
|
|
1085
|
+
} catch (err) {
|
|
1086
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
1087
|
+
return { success: false, path: filePath, error: errorMsg };
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
}),
|
|
1091
|
+
[builtinToolNames.Bash]: tool2({
|
|
1092
|
+
...builtInTools.Bash,
|
|
1093
|
+
execute: async ({ command, waitUntil }) => {
|
|
1094
|
+
const { createProcessManager } = await import("./process-manager-JDUJDYGU.mjs");
|
|
1095
|
+
const processManager = createProcessManager({
|
|
1096
|
+
sandbox: context.sandbox
|
|
1097
|
+
});
|
|
1098
|
+
const result = await processManager.run({ command, waitUntil });
|
|
1099
|
+
const MAX_STDOUT = 5e4;
|
|
1100
|
+
const MAX_STDERR = 1e4;
|
|
1101
|
+
let { stdout, stderr } = result;
|
|
1102
|
+
if (stdout.length > MAX_STDOUT) {
|
|
1103
|
+
stdout = `[truncated \u2014 showing last ${MAX_STDOUT} chars. Full: ${result.outputDir}/stdout.txt]
|
|
1104
|
+
|
|
1105
|
+
` + stdout.slice(-MAX_STDOUT);
|
|
1106
|
+
}
|
|
1107
|
+
if (stderr.length > MAX_STDERR) {
|
|
1108
|
+
stderr = `[truncated \u2014 showing last ${MAX_STDERR} chars. Full: ${result.outputDir}/stderr.txt]
|
|
1109
|
+
|
|
1110
|
+
` + stderr.slice(-MAX_STDERR);
|
|
1111
|
+
}
|
|
1112
|
+
return { ...result, stdout, stderr };
|
|
1113
|
+
}
|
|
1114
|
+
})
|
|
1115
|
+
};
|
|
1116
|
+
if (context.session.skillsDir?.length) {
|
|
1117
|
+
tools[builtinToolNames.Skill] = tool2({
|
|
1118
|
+
...builtInTools.Skill,
|
|
1119
|
+
execute: async ({ name }) => {
|
|
1120
|
+
const skills = context.skillsRef.current;
|
|
1121
|
+
const skill = skills.find(
|
|
1122
|
+
(s) => s.name.toLowerCase() === name.toLowerCase()
|
|
1123
|
+
);
|
|
1124
|
+
if (!skill) {
|
|
1125
|
+
throw new Error(
|
|
1126
|
+
`Skill not found: "${name}". Available: ${skills.map((s) => s.name).join(", ")}`
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
const result = await context.sandbox.readFile({
|
|
1130
|
+
path: skill.skillMdPath
|
|
1131
|
+
});
|
|
1132
|
+
if (result instanceof Error) {
|
|
1133
|
+
throw result;
|
|
1134
|
+
}
|
|
1135
|
+
if (result === null) {
|
|
1136
|
+
throw new Error(`Skill file not found: ${skill.skillMdPath}`);
|
|
1137
|
+
}
|
|
1138
|
+
const raw = typeof result === "string" ? result : result.toString("utf-8");
|
|
1139
|
+
const endMarker = raw.indexOf("---", 3);
|
|
1140
|
+
const content = endMarker === -1 ? raw : raw.slice(endMarker + 3).trim();
|
|
1141
|
+
const skillDir = skill.skillMdPath.replace(SKILL_MD_SUFFIX, "");
|
|
1142
|
+
return {
|
|
1143
|
+
name: skill.name,
|
|
1144
|
+
description: skill.description,
|
|
1145
|
+
content,
|
|
1146
|
+
path: skillDir
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
if (context.apiToolsMetadata.length > 0) {
|
|
1152
|
+
const apiTools = buildApiTools({
|
|
1153
|
+
rpc: context.input.rpc,
|
|
1154
|
+
metadata: context.apiToolsMetadata,
|
|
1155
|
+
session: context.session,
|
|
1156
|
+
sandboxRecord: context.sandboxRecord,
|
|
1157
|
+
context: context.event.context
|
|
1158
|
+
});
|
|
1159
|
+
Object.assign(tools, apiTools);
|
|
1160
|
+
}
|
|
1161
|
+
tools[builtinToolNames.JavaScript] = createJavaScriptTool({
|
|
1162
|
+
tools,
|
|
1163
|
+
session: context.session,
|
|
1164
|
+
sandbox: context.sandbox,
|
|
1165
|
+
onSubToolCall: context.onSubToolCall
|
|
1166
|
+
});
|
|
1167
|
+
return tools;
|
|
1168
|
+
}
|
|
1169
|
+
async function fetchApiToolsMetadata(opts) {
|
|
1170
|
+
const { rpc } = opts;
|
|
1171
|
+
const result = await rpc({ method: "tools.list", params: {} });
|
|
1172
|
+
if ("error" in result) {
|
|
1173
|
+
log.error("failed to fetch tools", { error: result.error?.message });
|
|
1174
|
+
return [];
|
|
1175
|
+
}
|
|
1176
|
+
return result.result ?? [];
|
|
1177
|
+
}
|
|
1178
|
+
function buildApiTools(opts) {
|
|
1179
|
+
const { rpc, metadata, session, sandboxRecord, context } = opts;
|
|
1180
|
+
const tools = {};
|
|
1181
|
+
for (const meta of metadata) {
|
|
1182
|
+
tools[meta.name] = tool2({
|
|
1183
|
+
description: meta.description ?? `Custom tool: ${meta.name}`,
|
|
1184
|
+
inputSchema: meta.inputSchema ? jsonSchema(meta.inputSchema) : z2.object({}),
|
|
1185
|
+
execute: async (input) => {
|
|
1186
|
+
const result = await rpc({
|
|
1187
|
+
method: "tools.execute",
|
|
1188
|
+
params: {
|
|
1189
|
+
name: meta.name,
|
|
1190
|
+
input,
|
|
1191
|
+
session,
|
|
1192
|
+
sandboxRecord,
|
|
1193
|
+
context
|
|
1194
|
+
}
|
|
1195
|
+
});
|
|
1196
|
+
if ("error" in result) {
|
|
1197
|
+
throw new Error(`Tool execution failed: ${result.error?.message}`);
|
|
1198
|
+
}
|
|
1199
|
+
return result.result;
|
|
1200
|
+
}
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
return tools;
|
|
1204
|
+
}
|
|
1205
|
+
function resolveApiUrl(opts) {
|
|
1206
|
+
let origin = "";
|
|
1207
|
+
let path = `/.well-known/agent/${AGENT_PROTOCOL_VERSION}`;
|
|
1208
|
+
if (opts.api) {
|
|
1209
|
+
if (opts.api.startsWith("/")) {
|
|
1210
|
+
path = opts.api;
|
|
1211
|
+
} else {
|
|
1212
|
+
try {
|
|
1213
|
+
const url = new URL(opts.api);
|
|
1214
|
+
origin = url.origin;
|
|
1215
|
+
const fullPath = url.pathname + url.search + url.hash;
|
|
1216
|
+
if (fullPath.startsWith("/") && fullPath !== "/") {
|
|
1217
|
+
path = fullPath;
|
|
1218
|
+
}
|
|
1219
|
+
} catch {
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
if (!origin) {
|
|
1224
|
+
if (process.env.NODE_ENV === "development") {
|
|
1225
|
+
origin = `http://localhost:${process.env.PORT ?? process.env.NEXT_PUBLIC_PORT ?? 3e3}`;
|
|
1226
|
+
}
|
|
1227
|
+
const vercelUrl = process.env.VERCEL_URL ?? process.env.NEXT_PUBLIC_VERCEL_URL;
|
|
1228
|
+
if (vercelUrl) {
|
|
1229
|
+
origin = `https://${vercelUrl}`;
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
if (!origin) {
|
|
1233
|
+
throw new Error(
|
|
1234
|
+
"[agent] Couldn't determine API origin (no origin detected in `api` option and no VERCEL_URL set)"
|
|
1235
|
+
);
|
|
1236
|
+
}
|
|
1237
|
+
return `${origin}${path}`;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
// src/utils/prompt-cache.ts
|
|
1241
|
+
var ANTHROPIC_MAX_CACHE_BREAKPOINTS_PER_REQUEST = 4;
|
|
1242
|
+
var CLAUDE_LIKE_MODEL_MATCHERS = ["claude", "anthropic"];
|
|
1243
|
+
var CLAUDE_PROMPT_CACHING_PROVIDER_OPTIONS = {
|
|
1244
|
+
anthropic: {
|
|
1245
|
+
cacheControl: { type: "ephemeral" }
|
|
1246
|
+
},
|
|
1247
|
+
openrouter: {
|
|
1248
|
+
cacheControl: { type: "ephemeral" }
|
|
1249
|
+
},
|
|
1250
|
+
bedrock: {
|
|
1251
|
+
cachePoint: { type: "default" }
|
|
1252
|
+
},
|
|
1253
|
+
openaiCompatible: {
|
|
1254
|
+
cache_control: { type: "ephemeral" }
|
|
1255
|
+
},
|
|
1256
|
+
copilot: {
|
|
1257
|
+
copilot_cache_control: { type: "ephemeral" }
|
|
1258
|
+
}
|
|
1259
|
+
};
|
|
1260
|
+
function getGatewayProvider(model) {
|
|
1261
|
+
const slashIndex = model.indexOf("/");
|
|
1262
|
+
if (slashIndex === -1) {
|
|
1263
|
+
return null;
|
|
1264
|
+
}
|
|
1265
|
+
return model.slice(0, slashIndex);
|
|
1266
|
+
}
|
|
1267
|
+
function countAnthropicCacheBreakpoints(messages) {
|
|
1268
|
+
let count = 0;
|
|
1269
|
+
for (const message of messages) {
|
|
1270
|
+
const providerOptions = message.providerOptions;
|
|
1271
|
+
if (providerOptions?.anthropic?.cacheControl) {
|
|
1272
|
+
count += 1;
|
|
1273
|
+
}
|
|
1274
|
+
if (Array.isArray(message.content)) {
|
|
1275
|
+
for (const part of message.content) {
|
|
1276
|
+
const partProviderOptions = part.providerOptions;
|
|
1277
|
+
if (partProviderOptions?.anthropic?.cacheControl) {
|
|
1278
|
+
count += 1;
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
return count;
|
|
1284
|
+
}
|
|
1285
|
+
function isClaudeLikeModel(model) {
|
|
1286
|
+
const lower = model.toLowerCase();
|
|
1287
|
+
return CLAUDE_LIKE_MODEL_MATCHERS.some((m) => lower.includes(m));
|
|
1288
|
+
}
|
|
1289
|
+
function mergeProviderOptions(opts) {
|
|
1290
|
+
const next = { ...opts.current ?? {} };
|
|
1291
|
+
for (const [key, value] of Object.entries(opts.patch)) {
|
|
1292
|
+
next[key] = { ...next[key] ?? {}, ...value };
|
|
1293
|
+
}
|
|
1294
|
+
return next;
|
|
1295
|
+
}
|
|
1296
|
+
function isCacheableClaudePart(part) {
|
|
1297
|
+
if (!part || typeof part !== "object") {
|
|
1298
|
+
return false;
|
|
1299
|
+
}
|
|
1300
|
+
if ("type" in part && part.type === "text") {
|
|
1301
|
+
const text = part.text;
|
|
1302
|
+
if (typeof text === "string") {
|
|
1303
|
+
return text.trim().length > 0;
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
if ("type" in part) {
|
|
1307
|
+
const type = part.type;
|
|
1308
|
+
if (type === "thinking" || type === "reasoning") {
|
|
1309
|
+
return false;
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
return true;
|
|
1313
|
+
}
|
|
1314
|
+
function hasCacheableContent(message) {
|
|
1315
|
+
if (typeof message.content === "string") {
|
|
1316
|
+
return message.content.trim().length > 0;
|
|
1317
|
+
}
|
|
1318
|
+
if (Array.isArray(message.content)) {
|
|
1319
|
+
return message.content.some((part) => isCacheableClaudePart(part));
|
|
1320
|
+
}
|
|
1321
|
+
return false;
|
|
1322
|
+
}
|
|
1323
|
+
function findLastCacheablePartIndex(content) {
|
|
1324
|
+
for (let i = content.length - 1; i >= 0; i -= 1) {
|
|
1325
|
+
if (isCacheableClaudePart(content[i])) {
|
|
1326
|
+
return i;
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
return null;
|
|
1330
|
+
}
|
|
1331
|
+
function selectClaudeCachingTargets(messages) {
|
|
1332
|
+
const systemIndices = [];
|
|
1333
|
+
const finalIndices = [];
|
|
1334
|
+
for (let i = 0; i < messages.length && systemIndices.length < 2; i += 1) {
|
|
1335
|
+
const message = messages[i];
|
|
1336
|
+
if (message.role === "system" && hasCacheableContent(message)) {
|
|
1337
|
+
systemIndices.push(i);
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
for (let i = messages.length - 1; i >= 0 && finalIndices.length < 2; i -= 1) {
|
|
1341
|
+
const message = messages[i];
|
|
1342
|
+
if (message.role !== "system" && hasCacheableContent(message)) {
|
|
1343
|
+
finalIndices.push(i);
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
finalIndices.reverse();
|
|
1347
|
+
return [...systemIndices, ...finalIndices];
|
|
1348
|
+
}
|
|
1349
|
+
function applyClaudePromptCaching(opts) {
|
|
1350
|
+
const existingBreakpoints = countAnthropicCacheBreakpoints(opts.messages);
|
|
1351
|
+
const remainingBudget = Math.max(
|
|
1352
|
+
0,
|
|
1353
|
+
opts.maxBreakpointsPerRequest - existingBreakpoints
|
|
1354
|
+
);
|
|
1355
|
+
if (remainingBudget === 0) {
|
|
1356
|
+
return opts.messages;
|
|
1357
|
+
}
|
|
1358
|
+
const targetIndices = selectClaudeCachingTargets(opts.messages).slice(
|
|
1359
|
+
0,
|
|
1360
|
+
remainingBudget
|
|
1361
|
+
);
|
|
1362
|
+
if (targetIndices.length === 0) {
|
|
1363
|
+
return opts.messages;
|
|
1364
|
+
}
|
|
1365
|
+
const useMessageLevelOptions = opts.providerId === "anthropic" || Boolean(opts.providerId?.includes("bedrock"));
|
|
1366
|
+
const nextMessages = opts.messages.slice();
|
|
1367
|
+
for (const messageIndex of targetIndices) {
|
|
1368
|
+
const message = nextMessages[messageIndex];
|
|
1369
|
+
const shouldUseContentOptions = !useMessageLevelOptions && Array.isArray(message.content) && message.content.length > 0;
|
|
1370
|
+
if (shouldUseContentOptions && Array.isArray(message.content)) {
|
|
1371
|
+
const partIndex = findLastCacheablePartIndex(message.content);
|
|
1372
|
+
if (partIndex !== null) {
|
|
1373
|
+
const part = message.content[partIndex];
|
|
1374
|
+
if (part && typeof part === "object") {
|
|
1375
|
+
const partProviderOptions = part.providerOptions;
|
|
1376
|
+
const nextContent = message.content.slice();
|
|
1377
|
+
nextContent[partIndex] = {
|
|
1378
|
+
...part,
|
|
1379
|
+
providerOptions: mergeProviderOptions({
|
|
1380
|
+
current: partProviderOptions,
|
|
1381
|
+
patch: CLAUDE_PROMPT_CACHING_PROVIDER_OPTIONS
|
|
1382
|
+
})
|
|
1383
|
+
};
|
|
1384
|
+
nextMessages[messageIndex] = {
|
|
1385
|
+
...message,
|
|
1386
|
+
content: nextContent
|
|
1387
|
+
};
|
|
1388
|
+
continue;
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
const messageProviderOptions = message.providerOptions;
|
|
1393
|
+
nextMessages[messageIndex] = {
|
|
1394
|
+
...message,
|
|
1395
|
+
providerOptions: mergeProviderOptions({
|
|
1396
|
+
current: messageProviderOptions,
|
|
1397
|
+
patch: CLAUDE_PROMPT_CACHING_PROVIDER_OPTIONS
|
|
1398
|
+
})
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
return nextMessages;
|
|
1402
|
+
}
|
|
1403
|
+
function applyPromptCachingToModelRequest(opts) {
|
|
1404
|
+
const provider = getGatewayProvider(opts.model);
|
|
1405
|
+
const providerOptions = {};
|
|
1406
|
+
if ((provider === "openai" || provider === "azure") && opts.openai?.setPromptCacheKey !== false) {
|
|
1407
|
+
providerOptions.openai = { promptCacheKey: opts.sessionId };
|
|
1408
|
+
}
|
|
1409
|
+
const maxBreakpointsPerRequest = opts.anthropic?.maxBreakpointsPerRequest ?? ANTHROPIC_MAX_CACHE_BREAKPOINTS_PER_REQUEST;
|
|
1410
|
+
const cachedMessages = isClaudeLikeModel(opts.model) ? applyClaudePromptCaching({
|
|
1411
|
+
messages: opts.messages,
|
|
1412
|
+
providerId: provider,
|
|
1413
|
+
maxBreakpointsPerRequest
|
|
1414
|
+
}) : opts.messages;
|
|
1415
|
+
return {
|
|
1416
|
+
messages: cachedMessages,
|
|
1417
|
+
providerOptions
|
|
1418
|
+
};
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
// src/utils/ui.ts
|
|
1422
|
+
function isSubToolPart(part) {
|
|
1423
|
+
const p = part.part;
|
|
1424
|
+
return typeof p?.toolCallId === "string" && p.toolCallId.startsWith("js_tc_");
|
|
1425
|
+
}
|
|
1426
|
+
function isStreamingContent(part) {
|
|
1427
|
+
return typeof part === "object" && part !== null && "type" in part && (part.type === "text" || part.type === "reasoning");
|
|
1428
|
+
}
|
|
1429
|
+
function applyInterruptCutoff({
|
|
1430
|
+
parts,
|
|
1431
|
+
lastPart
|
|
1432
|
+
}) {
|
|
1433
|
+
return parts.filter((p) => p.index <= lastPart.index).map((p) => {
|
|
1434
|
+
if (p.index !== lastPart.index) {
|
|
1435
|
+
return p;
|
|
1436
|
+
}
|
|
1437
|
+
if (isStreamingContent(lastPart.part)) {
|
|
1438
|
+
return { ...p, part: lastPart.part };
|
|
1439
|
+
}
|
|
1440
|
+
return p;
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
function assembleUIMessages(opts) {
|
|
1444
|
+
let filtered = opts.messages;
|
|
1445
|
+
if (opts.until !== void 0) {
|
|
1446
|
+
const until = opts.until;
|
|
1447
|
+
filtered = filtered.filter((m) => m.createdAt <= until);
|
|
1448
|
+
}
|
|
1449
|
+
if (!opts.includeQueued) {
|
|
1450
|
+
filtered = filtered.filter((m) => m.startedAt !== null);
|
|
1451
|
+
}
|
|
1452
|
+
const parts = opts.excludeSubToolParts ? opts.parts.filter((p) => !isSubToolPart(p)) : opts.parts;
|
|
1453
|
+
const partsByMessage = /* @__PURE__ */ new Map();
|
|
1454
|
+
for (const part of parts) {
|
|
1455
|
+
const existing = partsByMessage.get(part.messageId) ?? [];
|
|
1456
|
+
existing.push(part);
|
|
1457
|
+
partsByMessage.set(part.messageId, existing);
|
|
1458
|
+
}
|
|
1459
|
+
return filtered.map((m) => {
|
|
1460
|
+
let messageParts = partsByMessage.get(m.id) ?? [];
|
|
1461
|
+
messageParts.sort((a, b) => a.index - b.index);
|
|
1462
|
+
if (m.interruptedLastPart != null) {
|
|
1463
|
+
messageParts = applyInterruptCutoff({
|
|
1464
|
+
parts: messageParts,
|
|
1465
|
+
lastPart: m.interruptedLastPart
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
return {
|
|
1469
|
+
id: m.id,
|
|
1470
|
+
role: m.role,
|
|
1471
|
+
parts: messageParts.map((p) => p.part)
|
|
1472
|
+
};
|
|
1473
|
+
}).filter((m) => m.parts.length > 0);
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
// src/utils/usage.ts
|
|
1477
|
+
function sum(items, key) {
|
|
1478
|
+
return items.reduce((acc, item) => {
|
|
1479
|
+
const value = item[key];
|
|
1480
|
+
return acc + (typeof value === "number" ? value : 0);
|
|
1481
|
+
}, 0);
|
|
1482
|
+
}
|
|
1483
|
+
function computeUsageSummary(steps) {
|
|
1484
|
+
return {
|
|
1485
|
+
model: steps[0]?.model ?? "unknown",
|
|
1486
|
+
inputTokens: sum(steps, "inputTokens"),
|
|
1487
|
+
outputTokens: sum(steps, "outputTokens"),
|
|
1488
|
+
totalTokens: sum(steps, "totalTokens"),
|
|
1489
|
+
cacheReadTokens: sum(steps, "cacheReadTokens"),
|
|
1490
|
+
cacheWriteTokens: sum(steps, "cacheWriteTokens"),
|
|
1491
|
+
reasoningTokens: sum(steps, "reasoningTokens"),
|
|
1492
|
+
stepCount: steps.length
|
|
1493
|
+
};
|
|
1494
|
+
}
|
|
1495
|
+
function computeSessionUsage(messages) {
|
|
1496
|
+
const byMessageId = {};
|
|
1497
|
+
for (const m of messages) {
|
|
1498
|
+
byMessageId[m.id] = m.usage?.summary ?? null;
|
|
1499
|
+
}
|
|
1500
|
+
const summaries = messages.map((m) => m.usage?.summary).filter((s) => s !== void 0);
|
|
1501
|
+
const total = {
|
|
1502
|
+
model: summaries[0]?.model ?? "unknown",
|
|
1503
|
+
inputTokens: summaries.reduce((acc, s) => acc + s.inputTokens, 0),
|
|
1504
|
+
outputTokens: summaries.reduce((acc, s) => acc + s.outputTokens, 0),
|
|
1505
|
+
totalTokens: summaries.reduce((acc, s) => acc + s.totalTokens, 0),
|
|
1506
|
+
cacheReadTokens: summaries.reduce((acc, s) => acc + s.cacheReadTokens, 0),
|
|
1507
|
+
cacheWriteTokens: summaries.reduce((acc, s) => acc + s.cacheWriteTokens, 0),
|
|
1508
|
+
reasoningTokens: summaries.reduce((acc, s) => acc + s.reasoningTokens, 0),
|
|
1509
|
+
stepCount: summaries.reduce((acc, s) => acc + s.stepCount, 0),
|
|
1510
|
+
messageCount: summaries.length
|
|
1511
|
+
};
|
|
1512
|
+
return { total, byMessageId };
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
// src/agent-workflow-steps.ts
|
|
1516
|
+
var log2 = createLogger({ subsystem: "workflow" });
|
|
1517
|
+
function emitStatus({
|
|
1518
|
+
writer,
|
|
1519
|
+
status,
|
|
1520
|
+
rpc
|
|
1521
|
+
}) {
|
|
1522
|
+
writer?.({ type: "data-status", data: status, transient: true });
|
|
1523
|
+
rpc({ method: "hook.status", params: { status } }).catch(() => {
|
|
1524
|
+
});
|
|
1525
|
+
}
|
|
1526
|
+
var STATUS_THROTTLE_MS = 500;
|
|
1527
|
+
function createThrottledEmitStatus(rpc) {
|
|
1528
|
+
let timer = null;
|
|
1529
|
+
let pending = null;
|
|
1530
|
+
function throttled({
|
|
1531
|
+
writer,
|
|
1532
|
+
status
|
|
1533
|
+
}) {
|
|
1534
|
+
pending = { writer, status };
|
|
1535
|
+
if (timer !== null) {
|
|
1536
|
+
return;
|
|
1537
|
+
}
|
|
1538
|
+
flush();
|
|
1539
|
+
timer = setTimeout(() => {
|
|
1540
|
+
timer = null;
|
|
1541
|
+
if (pending) {
|
|
1542
|
+
flush();
|
|
1543
|
+
}
|
|
1544
|
+
}, STATUS_THROTTLE_MS);
|
|
1545
|
+
}
|
|
1546
|
+
function flush() {
|
|
1547
|
+
if (!pending) {
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1550
|
+
const { writer, status } = pending;
|
|
1551
|
+
pending = null;
|
|
1552
|
+
emitStatus({ writer, status, rpc });
|
|
1553
|
+
}
|
|
1554
|
+
throttled.dispose = () => {
|
|
1555
|
+
if (timer !== null) {
|
|
1556
|
+
clearTimeout(timer);
|
|
1557
|
+
timer = null;
|
|
1558
|
+
}
|
|
1559
|
+
flush();
|
|
1560
|
+
};
|
|
1561
|
+
return throttled;
|
|
1562
|
+
}
|
|
1563
|
+
var BASE_SYSTEM_PROMPT = "You are an AI assistant with basic tools to interact with your environment. Explore and work freely.";
|
|
1564
|
+
function joinPromptSections(...sections) {
|
|
1565
|
+
return sections.filter((s) => s?.trim()).join("\n\n");
|
|
1566
|
+
}
|
|
1567
|
+
var backgroundProcessPrompt = `## Background Processes
|
|
1568
|
+
These background process instructions are for you to manipulate the processes, do not be to verbose to the user about the response details like "how to debug the process output" the user will have an UI.
|
|
1569
|
+
|
|
1570
|
+
Use \`waitUntil: 0\` for dev servers that should run indefinitely.
|
|
1571
|
+
It is a good practice to check the output log after running processes like dev servers to make sure they started correctly.
|
|
1572
|
+
|
|
1573
|
+
To run a background process:
|
|
1574
|
+
Bash({ command: "npm run dev", waitUntil: 0 })
|
|
1575
|
+
Returns immediately with \`commandId\`. The process keeps running in the sandbox.
|
|
1576
|
+
|
|
1577
|
+
To kill a process:
|
|
1578
|
+
Bash({ command: "ps aux | grep node" }) // Find the PID
|
|
1579
|
+
Bash({ command: "kill {pid}" }) // Graceful
|
|
1580
|
+
Bash({ command: "kill -9 {pid}" }) // Force
|
|
1581
|
+
`;
|
|
1582
|
+
function buildSkillsContext(skills) {
|
|
1583
|
+
if (skills.length === 0) {
|
|
1584
|
+
return "";
|
|
1585
|
+
}
|
|
1586
|
+
const skillLines = skills.map((s) => `- ${s.name}: ${s.description}`).join("\n");
|
|
1587
|
+
return `## Available Skills
|
|
1588
|
+
${skillLines}
|
|
1589
|
+
|
|
1590
|
+
${backgroundProcessPrompt}
|
|
1591
|
+
|
|
1592
|
+
Use the Skill tool to load a skill's full instructions before following it.`;
|
|
1593
|
+
}
|
|
1594
|
+
async function completeMessageStep({
|
|
1595
|
+
assistantMessageId,
|
|
1596
|
+
input,
|
|
1597
|
+
writable,
|
|
1598
|
+
usageSteps
|
|
1599
|
+
}) {
|
|
1600
|
+
"use step";
|
|
1601
|
+
const msgLog = log2.withContext({
|
|
1602
|
+
sessionId: input.sessionId,
|
|
1603
|
+
messageId: assistantMessageId
|
|
1604
|
+
});
|
|
1605
|
+
const { getStorage } = await import("./client-BKA7XBGW.mjs");
|
|
1606
|
+
const storage = getStorage({ config: input.storageConfig, rpc: input.rpc });
|
|
1607
|
+
const message = await storage.message.get(assistantMessageId);
|
|
1608
|
+
if (message instanceof Error) {
|
|
1609
|
+
throw message;
|
|
1610
|
+
}
|
|
1611
|
+
if (!message) {
|
|
1612
|
+
throw new Error(`Message ${assistantMessageId} not found`);
|
|
1613
|
+
}
|
|
1614
|
+
const usage = usageSteps.length > 0 ? {
|
|
1615
|
+
steps: usageSteps,
|
|
1616
|
+
summary: computeUsageSummary(usageSteps)
|
|
1617
|
+
} : null;
|
|
1618
|
+
const result = await storage.message.set({
|
|
1619
|
+
...message,
|
|
1620
|
+
completedAt: Date.now(),
|
|
1621
|
+
usage
|
|
1622
|
+
});
|
|
1623
|
+
if (result instanceof Error) {
|
|
1624
|
+
throw result;
|
|
1625
|
+
}
|
|
1626
|
+
msgLog.info("message completed", {
|
|
1627
|
+
steps: usageSteps.length,
|
|
1628
|
+
totalTokens: usage?.summary.totalTokens
|
|
1629
|
+
});
|
|
1630
|
+
await writable.close();
|
|
1631
|
+
}
|
|
1632
|
+
var INTERRUPT_POLL_INTERVAL_MS = 250;
|
|
1633
|
+
function pollForInterrupt({
|
|
1634
|
+
storage,
|
|
1635
|
+
messageId,
|
|
1636
|
+
signal,
|
|
1637
|
+
abortController
|
|
1638
|
+
}) {
|
|
1639
|
+
let resolveFirstCheck;
|
|
1640
|
+
const firstCheck = new Promise((resolve) => {
|
|
1641
|
+
resolveFirstCheck = resolve;
|
|
1642
|
+
});
|
|
1643
|
+
const interruptedLastPartRef = {
|
|
1644
|
+
current: null
|
|
1645
|
+
};
|
|
1646
|
+
const poll = async () => {
|
|
1647
|
+
let isFirst = true;
|
|
1648
|
+
while (!signal.aborted) {
|
|
1649
|
+
const message = await storage.message.get(messageId);
|
|
1650
|
+
if (message instanceof Error) {
|
|
1651
|
+
if (isFirst) {
|
|
1652
|
+
resolveFirstCheck();
|
|
1653
|
+
}
|
|
1654
|
+
return;
|
|
1655
|
+
}
|
|
1656
|
+
if (message.interruptedAt !== null) {
|
|
1657
|
+
log2.info("interrupt detected", { messageId });
|
|
1658
|
+
interruptedLastPartRef.current = message.interruptedLastPart;
|
|
1659
|
+
abortController.abort();
|
|
1660
|
+
if (isFirst) {
|
|
1661
|
+
resolveFirstCheck();
|
|
1662
|
+
}
|
|
1663
|
+
return;
|
|
1664
|
+
}
|
|
1665
|
+
if (isFirst) {
|
|
1666
|
+
isFirst = false;
|
|
1667
|
+
resolveFirstCheck();
|
|
1668
|
+
}
|
|
1669
|
+
await new Promise(
|
|
1670
|
+
(resolve) => setTimeout(resolve, INTERRUPT_POLL_INTERVAL_MS)
|
|
1671
|
+
);
|
|
1672
|
+
}
|
|
1673
|
+
};
|
|
1674
|
+
poll();
|
|
1675
|
+
return { firstCheck, interruptedLastPartRef };
|
|
1676
|
+
}
|
|
1677
|
+
async function streamTextStep({
|
|
1678
|
+
assistantMessageId,
|
|
1679
|
+
input,
|
|
1680
|
+
event,
|
|
1681
|
+
writable,
|
|
1682
|
+
lastPartIndex,
|
|
1683
|
+
stepIndexOffset,
|
|
1684
|
+
discoveredSkills
|
|
1685
|
+
}) {
|
|
1686
|
+
"use step";
|
|
1687
|
+
const { getStorage } = await import("./client-BKA7XBGW.mjs");
|
|
1688
|
+
const { getSandbox } = await import("./sandbox-HRGGTEHF.mjs");
|
|
1689
|
+
const stepLog = log2.withContext({
|
|
1690
|
+
sessionId: input.sessionId,
|
|
1691
|
+
messageId: assistantMessageId
|
|
1692
|
+
});
|
|
1693
|
+
const doneStep = stepLog.time("streamTextStep");
|
|
1694
|
+
const rpc = input.rpc;
|
|
1695
|
+
const throttledEmitStatus = createThrottledEmitStatus(rpc);
|
|
1696
|
+
const storage = getStorage({ config: input.storageConfig, rpc });
|
|
1697
|
+
const pollStorage = getStorage({
|
|
1698
|
+
config: input.storageConfig,
|
|
1699
|
+
rpc: (p) => rpc({ ...p, _quiet: true })
|
|
1700
|
+
});
|
|
1701
|
+
const abortController = new AbortController();
|
|
1702
|
+
const pollController = new AbortController();
|
|
1703
|
+
const { firstCheck, interruptedLastPartRef } = pollForInterrupt({
|
|
1704
|
+
storage: pollStorage,
|
|
1705
|
+
messageId: assistantMessageId,
|
|
1706
|
+
signal: pollController.signal,
|
|
1707
|
+
abortController
|
|
1708
|
+
});
|
|
1709
|
+
const doneLoad = stepLog.time("load session + messages + parts + sandbox");
|
|
1710
|
+
const [
|
|
1711
|
+
,
|
|
1712
|
+
messagesResult,
|
|
1713
|
+
partsResult,
|
|
1714
|
+
{ session, sandbox, sandboxRecord },
|
|
1715
|
+
apiToolsMetadata
|
|
1716
|
+
] = await Promise.all([
|
|
1717
|
+
firstCheck,
|
|
1718
|
+
storage.message.list(input.sessionId),
|
|
1719
|
+
storage.part.listBySession(input.sessionId),
|
|
1720
|
+
storage.session.get(input.sessionId).then(async (session2) => {
|
|
1721
|
+
if (session2 instanceof Error) {
|
|
1722
|
+
throw session2;
|
|
1723
|
+
}
|
|
1724
|
+
const sandboxRecord2 = session2.sandboxId ? await storage.sandbox.get(session2.sandboxId) : null;
|
|
1725
|
+
if (sandboxRecord2 instanceof Error) {
|
|
1726
|
+
throw sandboxRecord2;
|
|
1727
|
+
}
|
|
1728
|
+
if (!sandboxRecord2) {
|
|
1729
|
+
throw new FatalError(
|
|
1730
|
+
`Sandbox not found for session ${input.sessionId}`
|
|
1731
|
+
);
|
|
1732
|
+
}
|
|
1733
|
+
const sandbox2 = getSandbox({
|
|
1734
|
+
sandboxRecord: sandboxRecord2,
|
|
1735
|
+
storageConfig: input.storageConfig,
|
|
1736
|
+
storage,
|
|
1737
|
+
rpc
|
|
1738
|
+
});
|
|
1739
|
+
return { session: session2, sandbox: sandbox2, sandboxRecord: sandboxRecord2 };
|
|
1740
|
+
}),
|
|
1741
|
+
fetchApiToolsMetadata({
|
|
1742
|
+
rpc
|
|
1743
|
+
})
|
|
1744
|
+
]);
|
|
1745
|
+
doneLoad();
|
|
1746
|
+
if (abortController.signal.aborted) {
|
|
1747
|
+
pollController.abort();
|
|
1748
|
+
return {
|
|
1749
|
+
finishReason: "stop",
|
|
1750
|
+
lastPartIndex,
|
|
1751
|
+
usageSteps: [],
|
|
1752
|
+
pendingApprovals: [],
|
|
1753
|
+
maxSteps: void 0,
|
|
1754
|
+
discoveredSkills
|
|
1755
|
+
};
|
|
1756
|
+
}
|
|
1757
|
+
if (messagesResult instanceof Error) {
|
|
1758
|
+
throw messagesResult;
|
|
1759
|
+
}
|
|
1760
|
+
if (partsResult instanceof Error) {
|
|
1761
|
+
throw partsResult;
|
|
1762
|
+
}
|
|
1763
|
+
const setStartedPromise = lastPartIndex === 0 ? (async () => {
|
|
1764
|
+
const now = Date.now();
|
|
1765
|
+
const pendingMessages = messagesResult.items.filter(
|
|
1766
|
+
(m) => m.createdAt <= event.createdAt && m.startedAt === null
|
|
1767
|
+
);
|
|
1768
|
+
if (pendingMessages.length > 0) {
|
|
1769
|
+
return await Promise.all(
|
|
1770
|
+
pendingMessages.map(
|
|
1771
|
+
(m) => storage.message.set({
|
|
1772
|
+
...m,
|
|
1773
|
+
startedAt: now,
|
|
1774
|
+
completedAt: m.role === "assistant" ? null : now
|
|
1775
|
+
})
|
|
1776
|
+
)
|
|
1777
|
+
);
|
|
1778
|
+
}
|
|
1779
|
+
})() : null;
|
|
1780
|
+
const streamWriterRef = { current: null };
|
|
1781
|
+
const subToolPartIds = [];
|
|
1782
|
+
let nextPartIndex = lastPartIndex;
|
|
1783
|
+
const onSubToolCall = async (toolName, toolInput, execute) => {
|
|
1784
|
+
const res = await rpc({
|
|
1785
|
+
method: "tools.needsApproval",
|
|
1786
|
+
params: {
|
|
1787
|
+
toolName,
|
|
1788
|
+
input: toolInput,
|
|
1789
|
+
toolCallId: `js_${toolName}_${Date.now()}`,
|
|
1790
|
+
messages: []
|
|
1791
|
+
}
|
|
1792
|
+
});
|
|
1793
|
+
if ("error" in res || res.result !== true) {
|
|
1794
|
+
try {
|
|
1795
|
+
const result2 = await execute();
|
|
1796
|
+
return { result: result2 };
|
|
1797
|
+
} catch (err) {
|
|
1798
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
const approvalId = `js_approval_${ulid()}`;
|
|
1802
|
+
const toolCallId = `js_tc_${ulid()}`;
|
|
1803
|
+
const partId = `part_${ulid()}`;
|
|
1804
|
+
subToolPartIds.push(partId);
|
|
1805
|
+
await storage.part.set({
|
|
1806
|
+
id: partId,
|
|
1807
|
+
index: nextPartIndex++,
|
|
1808
|
+
messageId: assistantMessageId,
|
|
1809
|
+
sessionId: input.sessionId,
|
|
1810
|
+
part: {
|
|
1811
|
+
type: `tool-${toolName}`,
|
|
1812
|
+
toolCallId,
|
|
1813
|
+
state: "approval-requested",
|
|
1814
|
+
input: toolInput,
|
|
1815
|
+
approval: { id: approvalId }
|
|
1816
|
+
}
|
|
1817
|
+
});
|
|
1818
|
+
streamWriterRef.current?.({
|
|
1819
|
+
type: "tool-input-start",
|
|
1820
|
+
toolCallId,
|
|
1821
|
+
toolName
|
|
1822
|
+
});
|
|
1823
|
+
streamWriterRef.current?.({
|
|
1824
|
+
type: "tool-input-available",
|
|
1825
|
+
toolCallId,
|
|
1826
|
+
toolName,
|
|
1827
|
+
input: toolInput
|
|
1828
|
+
});
|
|
1829
|
+
streamWriterRef.current?.({
|
|
1830
|
+
type: "tool-approval-request",
|
|
1831
|
+
approvalId,
|
|
1832
|
+
toolCallId
|
|
1833
|
+
});
|
|
1834
|
+
const POLL_MS = 500;
|
|
1835
|
+
const TIMEOUT_MS = 5 * 60 * 1e3;
|
|
1836
|
+
const start = Date.now();
|
|
1837
|
+
while (Date.now() - start < TIMEOUT_MS && !abortController.signal.aborted) {
|
|
1838
|
+
const parts = await storage.part.listBySession(input.sessionId);
|
|
1839
|
+
if (!(parts instanceof Error)) {
|
|
1840
|
+
const updated = parts.items.find(
|
|
1841
|
+
(p) => p.id === partId && "state" in p.part && (p.part.state === "approval-responded" || p.part.state === "output-denied")
|
|
1842
|
+
);
|
|
1843
|
+
if (updated) {
|
|
1844
|
+
const state = updated.part.state;
|
|
1845
|
+
if (state === "output-denied") {
|
|
1846
|
+
const reason = updated.part.approval?.reason;
|
|
1847
|
+
return {
|
|
1848
|
+
error: `Tool "${toolName}" denied: ${reason || "user denied"}`
|
|
1849
|
+
};
|
|
1850
|
+
}
|
|
1851
|
+
const approval = updated.part.approval;
|
|
1852
|
+
if (approval?.approved) {
|
|
1853
|
+
try {
|
|
1854
|
+
const result2 = await execute();
|
|
1855
|
+
streamWriterRef.current?.({
|
|
1856
|
+
type: "tool-output-available",
|
|
1857
|
+
toolCallId,
|
|
1858
|
+
output: result2
|
|
1859
|
+
});
|
|
1860
|
+
return { result: result2 };
|
|
1861
|
+
} catch (err) {
|
|
1862
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
1863
|
+
streamWriterRef.current?.({
|
|
1864
|
+
type: "tool-output-error",
|
|
1865
|
+
toolCallId,
|
|
1866
|
+
errorText: error
|
|
1867
|
+
});
|
|
1868
|
+
return { error };
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
streamWriterRef.current?.({
|
|
1872
|
+
type: "tool-output-denied",
|
|
1873
|
+
toolCallId
|
|
1874
|
+
});
|
|
1875
|
+
return {
|
|
1876
|
+
error: `Tool "${toolName}" denied: ${approval?.reason || "user denied"}`
|
|
1877
|
+
};
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
await new Promise((r) => setTimeout(r, POLL_MS));
|
|
1881
|
+
}
|
|
1882
|
+
return {
|
|
1883
|
+
error: abortController.signal.aborted ? "interrupted" : "Approval timed out"
|
|
1884
|
+
};
|
|
1885
|
+
};
|
|
1886
|
+
const skillsRef = {
|
|
1887
|
+
current: discoveredSkills ?? []
|
|
1888
|
+
};
|
|
1889
|
+
const rawTools = getTools({
|
|
1890
|
+
input,
|
|
1891
|
+
event,
|
|
1892
|
+
sandbox,
|
|
1893
|
+
session,
|
|
1894
|
+
sandboxRecord,
|
|
1895
|
+
skillsRef,
|
|
1896
|
+
apiToolsMetadata,
|
|
1897
|
+
onSubToolCall
|
|
1898
|
+
});
|
|
1899
|
+
if (!session.model) {
|
|
1900
|
+
throw new FatalError("Session model is not set");
|
|
1901
|
+
}
|
|
1902
|
+
const allParts = partsResult.items;
|
|
1903
|
+
const usageSteps = [];
|
|
1904
|
+
let internalStepIndex = 0;
|
|
1905
|
+
const tools = Object.fromEntries(
|
|
1906
|
+
Object.entries(rawTools).map(([name, t]) => {
|
|
1907
|
+
const originalExecute = t.execute;
|
|
1908
|
+
const wrappedExecute = originalExecute ? async (...args) => {
|
|
1909
|
+
const done = stepLog.time(`tool:${name}`);
|
|
1910
|
+
try {
|
|
1911
|
+
const result2 = await originalExecute(...args);
|
|
1912
|
+
done();
|
|
1913
|
+
return result2;
|
|
1914
|
+
} catch (e) {
|
|
1915
|
+
done({ error: e instanceof Error ? e.message : String(e) });
|
|
1916
|
+
throw e;
|
|
1917
|
+
}
|
|
1918
|
+
} : void 0;
|
|
1919
|
+
return [
|
|
1920
|
+
name,
|
|
1921
|
+
{
|
|
1922
|
+
...t,
|
|
1923
|
+
...wrappedExecute ? { execute: wrappedExecute } : {},
|
|
1924
|
+
needsApproval: async (toolInput, opts) => {
|
|
1925
|
+
const res = await rpc({
|
|
1926
|
+
method: "tools.needsApproval",
|
|
1927
|
+
params: {
|
|
1928
|
+
toolName: name,
|
|
1929
|
+
input: toolInput,
|
|
1930
|
+
toolCallId: opts.toolCallId,
|
|
1931
|
+
messages: opts.messages
|
|
1932
|
+
}
|
|
1933
|
+
});
|
|
1934
|
+
if ("error" in res) {
|
|
1935
|
+
throw new Error(
|
|
1936
|
+
`tools.needsApproval RPC failed for ${name}: ${res.error.message}`
|
|
1937
|
+
);
|
|
1938
|
+
}
|
|
1939
|
+
return res.result;
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
];
|
|
1943
|
+
})
|
|
1944
|
+
);
|
|
1945
|
+
const result = streamText({
|
|
1946
|
+
// Placeholder to pass validation — prepareStep replaces messages entirely.
|
|
1947
|
+
messages: [{ role: "user", content: "." }],
|
|
1948
|
+
tools,
|
|
1949
|
+
model: session.model,
|
|
1950
|
+
abortSignal: abortController.signal,
|
|
1951
|
+
stopWhen: stepCountIs(1),
|
|
1952
|
+
temperature: session.generation?.temperature,
|
|
1953
|
+
topK: session.generation?.topK,
|
|
1954
|
+
topP: session.generation?.topP,
|
|
1955
|
+
frequencyPenalty: session.generation?.frequencyPenalty,
|
|
1956
|
+
presencePenalty: session.generation?.presencePenalty,
|
|
1957
|
+
maxOutputTokens: session.generation?.maxOutputTokens,
|
|
1958
|
+
headers: session.generation?.headers,
|
|
1959
|
+
experimental_context: {
|
|
1960
|
+
session,
|
|
1961
|
+
sandbox,
|
|
1962
|
+
storage,
|
|
1963
|
+
context: event.context
|
|
1964
|
+
},
|
|
1965
|
+
prepareStep: async ({ model }) => {
|
|
1966
|
+
if (lastPartIndex === 0) {
|
|
1967
|
+
const isFirstAssistantMessage = !messagesResult.items.some(
|
|
1968
|
+
(m) => m.role === "assistant" && m.id !== assistantMessageId && m.startedAt !== null
|
|
1969
|
+
);
|
|
1970
|
+
const onReady = sandbox._onReady;
|
|
1971
|
+
if (isFirstAssistantMessage && onReady) {
|
|
1972
|
+
throttledEmitStatus({
|
|
1973
|
+
writer: streamWriterRef.current,
|
|
1974
|
+
status: { type: "sandbox-setup" }
|
|
1975
|
+
});
|
|
1976
|
+
}
|
|
1977
|
+
if (!discoveredSkills) {
|
|
1978
|
+
const skillsDirs = session.skillsDir?.length ? session.skillsDir : [];
|
|
1979
|
+
if (skillsDirs.length > 0) {
|
|
1980
|
+
const doneSkills = stepLog.time("discover skills", { skillsDirs });
|
|
1981
|
+
skillsRef.current = await discoverSkillsInSandbox({
|
|
1982
|
+
sandbox,
|
|
1983
|
+
skillsDirs,
|
|
1984
|
+
sessionId: input.sessionId
|
|
1985
|
+
});
|
|
1986
|
+
doneSkills({ count: skillsRef.current.length });
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
const approvedParts = allParts.filter(
|
|
1991
|
+
(p) => p.part && "state" in p.part && p.part.state === "approval-responded" && "approval" in p.part && p.part.approval?.approved === true
|
|
1992
|
+
);
|
|
1993
|
+
if (approvedParts.length > 0) {
|
|
1994
|
+
stepLog.info("executing approved tools", {
|
|
1995
|
+
count: approvedParts.length
|
|
1996
|
+
});
|
|
1997
|
+
throttledEmitStatus({
|
|
1998
|
+
writer: streamWriterRef.current,
|
|
1999
|
+
status: { type: "processing-approvals" }
|
|
2000
|
+
});
|
|
2001
|
+
const preExecMessages = await convertToModelMessages(
|
|
2002
|
+
assembleUIMessages({
|
|
2003
|
+
messages: messagesResult.items,
|
|
2004
|
+
parts: allParts,
|
|
2005
|
+
until: event.createdAt,
|
|
2006
|
+
includeQueued: true,
|
|
2007
|
+
excludeSubToolParts: true
|
|
2008
|
+
}),
|
|
2009
|
+
{ ignoreIncompleteToolCalls: true }
|
|
2010
|
+
);
|
|
2011
|
+
await Promise.all(
|
|
2012
|
+
approvedParts.map(async (ap) => {
|
|
2013
|
+
if (!ap.part.type.startsWith("tool-")) {
|
|
2014
|
+
return;
|
|
2015
|
+
}
|
|
2016
|
+
const part = ap.part;
|
|
2017
|
+
const toolName = part.type.replace("tool-", "");
|
|
2018
|
+
const toolDef = rawTools[toolName];
|
|
2019
|
+
if (toolDef?.execute && part.input !== void 0) {
|
|
2020
|
+
try {
|
|
2021
|
+
const toolOutput = await toolDef.execute(part.input, {
|
|
2022
|
+
toolCallId: part.toolCallId,
|
|
2023
|
+
messages: preExecMessages,
|
|
2024
|
+
abortSignal: abortController.signal,
|
|
2025
|
+
experimental_context: {
|
|
2026
|
+
session,
|
|
2027
|
+
sandbox,
|
|
2028
|
+
storage,
|
|
2029
|
+
context: event.context
|
|
2030
|
+
}
|
|
2031
|
+
});
|
|
2032
|
+
part.state = "output-available";
|
|
2033
|
+
part.output = toolOutput;
|
|
2034
|
+
streamWriterRef.current?.({
|
|
2035
|
+
type: "tool-output-available",
|
|
2036
|
+
toolCallId: part.toolCallId,
|
|
2037
|
+
output: toolOutput
|
|
2038
|
+
});
|
|
2039
|
+
} catch (err) {
|
|
2040
|
+
part.state = "output-error";
|
|
2041
|
+
part.errorText = err instanceof Error ? err.message : String(err);
|
|
2042
|
+
streamWriterRef.current?.({
|
|
2043
|
+
type: "tool-output-error",
|
|
2044
|
+
toolCallId: part.toolCallId,
|
|
2045
|
+
errorText: part.errorText
|
|
2046
|
+
});
|
|
2047
|
+
}
|
|
2048
|
+
await storage.part.set({ ...ap, part });
|
|
2049
|
+
}
|
|
2050
|
+
})
|
|
2051
|
+
);
|
|
2052
|
+
}
|
|
2053
|
+
throttledEmitStatus({
|
|
2054
|
+
writer: streamWriterRef.current,
|
|
2055
|
+
status: { type: "thinking" }
|
|
2056
|
+
});
|
|
2057
|
+
const skillsContext = buildSkillsContext(skillsRef.current);
|
|
2058
|
+
const cwdPrompt = `Your working directory is ${sandbox.cwd}. All file paths should be absolute.`;
|
|
2059
|
+
const systemHeader = joinPromptSections(
|
|
2060
|
+
BASE_SYSTEM_PROMPT,
|
|
2061
|
+
cwdPrompt,
|
|
2062
|
+
session.system
|
|
2063
|
+
);
|
|
2064
|
+
const systemContext = joinPromptSections(skillsContext);
|
|
2065
|
+
const systemMessages = [
|
|
2066
|
+
...systemHeader.trim() ? [{ role: "system", content: systemHeader }] : [],
|
|
2067
|
+
...systemContext.trim() ? [{ role: "system", content: systemContext }] : []
|
|
2068
|
+
];
|
|
2069
|
+
const uiMessages = assembleUIMessages({
|
|
2070
|
+
messages: messagesResult.items,
|
|
2071
|
+
parts: allParts,
|
|
2072
|
+
until: event.createdAt,
|
|
2073
|
+
includeQueued: true,
|
|
2074
|
+
excludeSubToolParts: true
|
|
2075
|
+
});
|
|
2076
|
+
const modelMessages = [
|
|
2077
|
+
...systemMessages,
|
|
2078
|
+
...await convertToModelMessages(uiMessages, {
|
|
2079
|
+
ignoreIncompleteToolCalls: true
|
|
2080
|
+
})
|
|
2081
|
+
];
|
|
2082
|
+
const promptCaching = applyPromptCachingToModelRequest({
|
|
2083
|
+
model: typeof model === "string" ? model : model.modelId,
|
|
2084
|
+
sessionId: input.sessionId,
|
|
2085
|
+
messages: modelMessages
|
|
2086
|
+
});
|
|
2087
|
+
let activeTools = session.activeTools ?? void 0;
|
|
2088
|
+
if (skillsRef.current.length === 0 && activeTools) {
|
|
2089
|
+
activeTools = activeTools.filter(
|
|
2090
|
+
(t) => t !== "Skill"
|
|
2091
|
+
);
|
|
2092
|
+
}
|
|
2093
|
+
return {
|
|
2094
|
+
messages: promptCaching.messages,
|
|
2095
|
+
providerOptions: promptCaching.providerOptions,
|
|
2096
|
+
activeTools
|
|
2097
|
+
};
|
|
2098
|
+
},
|
|
2099
|
+
onStepFinish: ({ usage }) => {
|
|
2100
|
+
if (usage) {
|
|
2101
|
+
usageSteps.push({
|
|
2102
|
+
stepIndex: stepIndexOffset + internalStepIndex,
|
|
2103
|
+
model: session.model ?? "unknown",
|
|
2104
|
+
inputTokens: usage.inputTokens ?? 0,
|
|
2105
|
+
outputTokens: usage.outputTokens ?? 0,
|
|
2106
|
+
totalTokens: usage.totalTokens ?? 0,
|
|
2107
|
+
cacheReadTokens: usage.inputTokenDetails?.cacheReadTokens ?? 0,
|
|
2108
|
+
cacheWriteTokens: usage.inputTokenDetails?.cacheWriteTokens ?? 0,
|
|
2109
|
+
reasoningTokens: usage.outputTokenDetails?.reasoningTokens ?? 0
|
|
2110
|
+
});
|
|
2111
|
+
}
|
|
2112
|
+
internalStepIndex++;
|
|
2113
|
+
}
|
|
2114
|
+
});
|
|
2115
|
+
const stepParts = [];
|
|
2116
|
+
let wasAborted = false;
|
|
2117
|
+
try {
|
|
2118
|
+
const stream = createUIMessageStream({
|
|
2119
|
+
execute: ({ writer }) => {
|
|
2120
|
+
streamWriterRef.current = (event2) => writer.write(event2);
|
|
2121
|
+
writer.merge(
|
|
2122
|
+
result.toUIMessageStream({
|
|
2123
|
+
generateMessageId: () => assistantMessageId,
|
|
2124
|
+
onFinish: ({ messages }) => {
|
|
2125
|
+
let hasApprovals = false;
|
|
2126
|
+
for (const m of messages) {
|
|
2127
|
+
if (m.role === "assistant") {
|
|
2128
|
+
stepParts.push(...m.parts);
|
|
2129
|
+
for (const p of m.parts) {
|
|
2130
|
+
if ("state" in p && p.state === "approval-requested") {
|
|
2131
|
+
hasApprovals = true;
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
if (hasApprovals) {
|
|
2137
|
+
throttledEmitStatus({
|
|
2138
|
+
writer: streamWriterRef.current,
|
|
2139
|
+
status: { type: "needs-approval" }
|
|
2140
|
+
});
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
})
|
|
2144
|
+
);
|
|
2145
|
+
}
|
|
2146
|
+
});
|
|
2147
|
+
await stream.pipeTo(writable, {
|
|
2148
|
+
preventClose: true,
|
|
2149
|
+
preventAbort: true
|
|
2150
|
+
});
|
|
2151
|
+
} catch (err) {
|
|
2152
|
+
if (abortController.signal.aborted) {
|
|
2153
|
+
wasAborted = true;
|
|
2154
|
+
} else {
|
|
2155
|
+
throw err;
|
|
2156
|
+
}
|
|
2157
|
+
} finally {
|
|
2158
|
+
pollController.abort();
|
|
2159
|
+
throttledEmitStatus.dispose();
|
|
2160
|
+
}
|
|
2161
|
+
if (abortController.signal.aborted) {
|
|
2162
|
+
wasAborted = true;
|
|
2163
|
+
}
|
|
2164
|
+
const lastPart = interruptedLastPartRef.current;
|
|
2165
|
+
if (wasAborted) {
|
|
2166
|
+
const terminalStates = /* @__PURE__ */ new Set([
|
|
2167
|
+
"output-available",
|
|
2168
|
+
"output-error",
|
|
2169
|
+
"output-denied",
|
|
2170
|
+
"done"
|
|
2171
|
+
]);
|
|
2172
|
+
for (const part of stepParts) {
|
|
2173
|
+
if ("type" in part && typeof part.type === "string" && part.type.startsWith("tool-") && "state" in part && !terminalStates.has(part.state)) {
|
|
2174
|
+
part.state = "output-error";
|
|
2175
|
+
part.errorText = "interrupted";
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
try {
|
|
2180
|
+
const basePartIndex = nextPartIndex;
|
|
2181
|
+
await Promise.all(
|
|
2182
|
+
stepParts.map(async (uiPart, i) => {
|
|
2183
|
+
const index = basePartIndex + i;
|
|
2184
|
+
if (lastPart != null && index > lastPart.index) {
|
|
2185
|
+
return;
|
|
2186
|
+
}
|
|
2187
|
+
const useClientPart = lastPart != null && index === lastPart.index;
|
|
2188
|
+
const content = useClientPart ? lastPart.part : uiPart;
|
|
2189
|
+
const result2 = await storage.part.set({
|
|
2190
|
+
id: `part_${ulid()}`,
|
|
2191
|
+
index,
|
|
2192
|
+
messageId: assistantMessageId,
|
|
2193
|
+
sessionId: input.sessionId,
|
|
2194
|
+
part: content
|
|
2195
|
+
});
|
|
2196
|
+
if (result2 instanceof Error) {
|
|
2197
|
+
throw result2;
|
|
2198
|
+
}
|
|
2199
|
+
return result2;
|
|
2200
|
+
})
|
|
2201
|
+
);
|
|
2202
|
+
nextPartIndex = lastPart != null ? Math.min(basePartIndex + stepParts.length, lastPart.index + 1) : basePartIndex + stepParts.length;
|
|
2203
|
+
if (setStartedPromise) {
|
|
2204
|
+
const setStartedResult = await setStartedPromise;
|
|
2205
|
+
if (setStartedResult instanceof Error) {
|
|
2206
|
+
throw setStartedResult;
|
|
2207
|
+
}
|
|
2208
|
+
for (const m of setStartedResult ?? []) {
|
|
2209
|
+
if (m instanceof Error) {
|
|
2210
|
+
throw m;
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
} catch (err) {
|
|
2215
|
+
if (abortController.signal.aborted) {
|
|
2216
|
+
wasAborted = true;
|
|
2217
|
+
} else {
|
|
2218
|
+
throw err;
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
const pendingApprovals = stepParts.filter(
|
|
2222
|
+
(p) => "state" in p && p.state === "approval-requested" && "approval" in p && !!p.approval?.id
|
|
2223
|
+
).map((p) => ({
|
|
2224
|
+
approvalId: p.approval.id,
|
|
2225
|
+
toolName: "type" in p ? String(p.type).replace("tool-", "") : "unknown"
|
|
2226
|
+
}));
|
|
2227
|
+
const finalFinishReason = wasAborted || lastPart != null ? "stop" : await result.finishReason;
|
|
2228
|
+
doneStep({
|
|
2229
|
+
finishReason: finalFinishReason,
|
|
2230
|
+
wasAborted,
|
|
2231
|
+
partsCount: stepParts.length,
|
|
2232
|
+
pendingApprovals: pendingApprovals.length
|
|
2233
|
+
});
|
|
2234
|
+
return {
|
|
2235
|
+
finishReason: finalFinishReason,
|
|
2236
|
+
lastPartIndex: nextPartIndex,
|
|
2237
|
+
usageSteps,
|
|
2238
|
+
pendingApprovals,
|
|
2239
|
+
maxSteps: session.generation?.maxSteps,
|
|
2240
|
+
discoveredSkills: skillsRef.current
|
|
2241
|
+
};
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
// src/agent-workflow.ts
|
|
2245
|
+
var log3 = createLogger({ subsystem: "workflow" });
|
|
2246
|
+
var agentMessageHook = defineHook();
|
|
2247
|
+
var approvalHook = defineHook();
|
|
2248
|
+
async function agentWorkflow({
|
|
2249
|
+
input,
|
|
2250
|
+
event
|
|
2251
|
+
}) {
|
|
2252
|
+
"use workflow";
|
|
2253
|
+
const wfLog = log3.withContext({ sessionId: input.sessionId });
|
|
2254
|
+
wfLog.info("workflow started", { messageId: event.assistantMessageId });
|
|
2255
|
+
const messageHook = agentMessageHook.create({ token: input.sessionId });
|
|
2256
|
+
const iterator = messageHook[Symbol.asyncIterator]();
|
|
2257
|
+
let pendingNext = iterator.next();
|
|
2258
|
+
let discoveredSkills = null;
|
|
2259
|
+
await onMessage({ event, input, discoveredSkills }).then((result) => {
|
|
2260
|
+
discoveredSkills = result?.discoveredSkills ?? discoveredSkills;
|
|
2261
|
+
}).catch((e) => {
|
|
2262
|
+
if (FatalError2.is(e)) {
|
|
2263
|
+
wfLog.error("message processing failed permanently", {
|
|
2264
|
+
error: e.message
|
|
2265
|
+
});
|
|
2266
|
+
return;
|
|
2267
|
+
}
|
|
2268
|
+
throw e;
|
|
2269
|
+
});
|
|
2270
|
+
while (true) {
|
|
2271
|
+
const result = await pendingNext;
|
|
2272
|
+
if (result.done) {
|
|
2273
|
+
wfLog.error("unexpected: message hook iterator done");
|
|
2274
|
+
break;
|
|
2275
|
+
}
|
|
2276
|
+
wfLog.info("processing new message", {
|
|
2277
|
+
messageId: result.value.assistantMessageId
|
|
2278
|
+
});
|
|
2279
|
+
await onMessage({ event: result.value, input, discoveredSkills }).then((result2) => {
|
|
2280
|
+
discoveredSkills = result2?.discoveredSkills ?? discoveredSkills;
|
|
2281
|
+
}).catch((e) => {
|
|
2282
|
+
if (FatalError2.is(e)) {
|
|
2283
|
+
wfLog.error("message processing failed permanently", {
|
|
2284
|
+
error: e.message
|
|
2285
|
+
});
|
|
2286
|
+
return;
|
|
2287
|
+
}
|
|
2288
|
+
throw e;
|
|
2289
|
+
});
|
|
2290
|
+
pendingNext = iterator.next();
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
async function onMessage({
|
|
2294
|
+
event,
|
|
2295
|
+
input,
|
|
2296
|
+
discoveredSkills
|
|
2297
|
+
}) {
|
|
2298
|
+
const msgLog = log3.withContext({
|
|
2299
|
+
sessionId: input.sessionId,
|
|
2300
|
+
messageId: event.assistantMessageId
|
|
2301
|
+
});
|
|
2302
|
+
const doneMessage = msgLog.time("onMessage");
|
|
2303
|
+
const writable = getWritable({ namespace: event.assistantMessageId });
|
|
2304
|
+
let finishReason;
|
|
2305
|
+
let lastPartIndex = 0;
|
|
2306
|
+
const usageSteps = [];
|
|
2307
|
+
while (finishReason !== "stop") {
|
|
2308
|
+
try {
|
|
2309
|
+
const result = await streamTextStep({
|
|
2310
|
+
assistantMessageId: event.assistantMessageId,
|
|
2311
|
+
writable,
|
|
2312
|
+
input,
|
|
2313
|
+
event,
|
|
2314
|
+
lastPartIndex,
|
|
2315
|
+
stepIndexOffset: usageSteps.length,
|
|
2316
|
+
discoveredSkills
|
|
2317
|
+
});
|
|
2318
|
+
finishReason = result.finishReason;
|
|
2319
|
+
lastPartIndex = result.lastPartIndex;
|
|
2320
|
+
usageSteps.push(...result.usageSteps);
|
|
2321
|
+
discoveredSkills = result.discoveredSkills;
|
|
2322
|
+
if (result.maxSteps != null && usageSteps.length >= result.maxSteps) {
|
|
2323
|
+
msgLog.info("reached maxSteps limit", { maxSteps: result.maxSteps });
|
|
2324
|
+
break;
|
|
2325
|
+
}
|
|
2326
|
+
if (result.pendingApprovals.length > 0) {
|
|
2327
|
+
msgLog.info("waiting for approvals", {
|
|
2328
|
+
count: result.pendingApprovals.length,
|
|
2329
|
+
tools: result.pendingApprovals.map((p) => p.toolName)
|
|
2330
|
+
});
|
|
2331
|
+
await Promise.all(
|
|
2332
|
+
result.pendingApprovals.map((pending) => {
|
|
2333
|
+
const hook = approvalHook.create({ token: pending.approvalId });
|
|
2334
|
+
const iter = hook[Symbol.asyncIterator]();
|
|
2335
|
+
return iter.next();
|
|
2336
|
+
})
|
|
2337
|
+
);
|
|
2338
|
+
}
|
|
2339
|
+
} catch (err) {
|
|
2340
|
+
msgLog.error("streamTextStep failed", {
|
|
2341
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2342
|
+
});
|
|
2343
|
+
throw err;
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
doneMessage({ totalSteps: usageSteps.length });
|
|
2347
|
+
await completeMessageStep({
|
|
2348
|
+
assistantMessageId: event.assistantMessageId,
|
|
2349
|
+
input,
|
|
2350
|
+
writable,
|
|
2351
|
+
usageSteps
|
|
2352
|
+
});
|
|
2353
|
+
return { discoveredSkills };
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
export {
|
|
2357
|
+
normalizeSkillsDirs,
|
|
2358
|
+
builtInTools,
|
|
2359
|
+
builtinToolNames,
|
|
2360
|
+
resolveApiUrl,
|
|
2361
|
+
assembleUIMessages,
|
|
2362
|
+
computeSessionUsage,
|
|
2363
|
+
agentMessageHook,
|
|
2364
|
+
approvalHook,
|
|
2365
|
+
agentWorkflow
|
|
2366
|
+
};
|
|
2367
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL2FnZW50LXdvcmtmbG93LnRzIiwgIi4uL3NyYy9hZ2VudC13b3JrZmxvdy1zdGVwcy50cyIsICIuLi9zcmMvc2tpbGxzL3BhcnNlci50cyIsICIuLi9zcmMvc2tpbGxzL2Rpc2NvdmVyLnRzIiwgIi4uL3NyYy90b29scy9pbmRleC50cyIsICIuLi9zcmMvdG9vbHMvamF2YXNjcmlwdC50cyIsICIuLi9zcmMvdXRpbHMvcHJvbXB0LWNhY2hlLnRzIiwgIi4uL3NyYy91dGlscy91aS50cyIsICIuLi9zcmMvdXRpbHMvdXNhZ2UudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImltcG9ydCB0eXBlIHsgRmluaXNoUmVhc29uIH0gZnJvbSBcImFpXCI7XG5pbXBvcnQgeyBkZWZpbmVIb29rLCBGYXRhbEVycm9yLCBnZXRXcml0YWJsZSB9IGZyb20gXCJ3b3JrZmxvd1wiO1xuaW1wb3J0IHsgY29tcGxldGVNZXNzYWdlU3RlcCwgc3RyZWFtVGV4dFN0ZXAgfSBmcm9tIFwiLi9hZ2VudC13b3JrZmxvdy1zdGVwc1wiO1xuaW1wb3J0IHR5cGUgeyBScGNQYXlsb2FkLCBScGNSZXN1bHQgfSBmcm9tIFwiLi9jbGllbnRcIjtcbmltcG9ydCB0eXBlIHsgU2tpbGxTdW1tYXJ5IH0gZnJvbSBcIi4vc2tpbGxzL3R5cGVzXCI7XG5pbXBvcnQgdHlwZSB7IFN0b3JhZ2VDb25maWcgfSBmcm9tIFwiLi9zdG9yYWdlXCI7XG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIgfSBmcm9tIFwiLi91dGlscy9sb2dnZXJcIjtcbmltcG9ydCB0eXBlIHsgU3RlcFVzYWdlIH0gZnJvbSBcIi4vdXRpbHMvdXNhZ2VcIjtcblxuY29uc3QgbG9nID0gY3JlYXRlTG9nZ2VyKHsgc3Vic3lzdGVtOiBcIndvcmtmbG93XCIgfSk7XG5cbmV4cG9ydCB0eXBlIEFnZW50SW5wdXQgPSB7XG4gIHNlc3Npb25JZDogc3RyaW5nO1xuICBzdG9yYWdlQ29uZmlnOiBTdG9yYWdlQ29uZmlnO1xuICBycGM6IChwYXJhbXM6IFJwY1BheWxvYWQpID0+IFByb21pc2U8UnBjUmVzdWx0Pjtcbn07XG5cbmV4cG9ydCB0eXBlIEFnZW50TWVzc2FnZUlucHV0ID0ge1xuICBhc3Npc3RhbnRNZXNzYWdlSWQ6IHN0cmluZztcbiAgaG9va1Rva2VuOiBzdHJpbmc7XG4gIGNyZWF0ZWRBdDogbnVtYmVyO1xuICBjb250ZXh0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbn07XG5cbmV4cG9ydCB0eXBlIEFwcHJvdmFsUmVzcG9uc2UgPSB7XG4gIGFwcHJvdmVkOiBib29sZWFuO1xuICByZWFzb24/OiBzdHJpbmc7XG59O1xuXG5leHBvcnQgY29uc3QgYWdlbnRNZXNzYWdlSG9vayA9IGRlZmluZUhvb2s8QWdlbnRNZXNzYWdlSW5wdXQ+KCk7XG5leHBvcnQgY29uc3QgYXBwcm92YWxIb29rID0gZGVmaW5lSG9vazxBcHByb3ZhbFJlc3BvbnNlPigpO1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYWdlbnRXb3JrZmxvdyh7XG4gIGlucHV0LFxuICBldmVudCxcbn06IHtcbiAgaW5wdXQ6IEFnZW50SW5wdXQ7XG4gIGV2ZW50OiBBZ2VudE1lc3NhZ2VJbnB1dDtcbn0pIHtcbiAgXCJ1c2Ugd29ya2Zsb3dcIjtcblxuICBjb25zdCB3ZkxvZyA9IGxvZy53aXRoQ29udGV4dCh7IHNlc3Npb25JZDogaW5wdXQuc2Vzc2lvbklkIH0pO1xuICB3ZkxvZy5pbmZvKFwid29ya2Zsb3cgc3RhcnRlZFwiLCB7IG1lc3NhZ2VJZDogZXZlbnQuYXNzaXN0YW50TWVzc2FnZUlkIH0pO1xuXG4gIGNvbnN0IG1lc3NhZ2VIb29rID0gYWdlbnRNZXNzYWdlSG9vay5jcmVhdGUoeyB0b2tlbjogaW5wdXQuc2Vzc2lvbklkIH0pO1xuICBjb25zdCBpdGVyYXRvciA9IG1lc3NhZ2VIb29rW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSgpO1xuICBsZXQgcGVuZGluZ05leHQgPSBpdGVyYXRvci5uZXh0KCk7XG4gIGxldCBkaXNjb3ZlcmVkU2tpbGxzOiBTa2lsbFN1bW1hcnlbXSB8IG51bGwgPSBudWxsO1xuXG4gIGF3YWl0IG9uTWVzc2FnZSh7IGV2ZW50LCBpbnB1dCwgZGlzY292ZXJlZFNraWxscyB9KVxuICAgIC50aGVuKChyZXN1bHQpID0+IHtcbiAgICAgIGRpc2NvdmVyZWRTa2lsbHMgPSByZXN1bHQ/LmRpc2NvdmVyZWRTa2lsbHMgPz8gZGlzY292ZXJlZFNraWxscztcbiAgICB9KVxuICAgIC5jYXRjaCgoZSkgPT4ge1xuICAgICAgaWYgKEZhdGFsRXJyb3IuaXMoZSkpIHtcbiAgICAgICAgd2ZMb2cuZXJyb3IoXCJtZXNzYWdlIHByb2Nlc3NpbmcgZmFpbGVkIHBlcm1hbmVudGx5XCIsIHtcbiAgICAgICAgICBlcnJvcjogZS5tZXNzYWdlLFxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgdGhyb3cgZTtcbiAgICB9KTtcblxuICB3aGlsZSAodHJ1ZSkge1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBlbmRpbmdOZXh0O1xuXG4gICAgaWYgKHJlc3VsdC5kb25lKSB7XG4gICAgICB3ZkxvZy5lcnJvcihcInVuZXhwZWN0ZWQ6IG1lc3NhZ2UgaG9vayBpdGVyYXRvciBkb25lXCIpO1xuICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgd2ZMb2cuaW5mbyhcInByb2Nlc3NpbmcgbmV3IG1lc3NhZ2VcIiwge1xuICAgICAgbWVzc2FnZUlkOiByZXN1bHQudmFsdWUuYXNzaXN0YW50TWVzc2FnZUlkLFxuICAgIH0pO1xuICAgIGF3YWl0IG9uTWVzc2FnZSh7IGV2ZW50OiByZXN1bHQudmFsdWUsIGlucHV0LCBkaXNjb3ZlcmVkU2tpbGxzIH0pXG4gICAgICAudGhlbigocmVzdWx0KSA9PiB7XG4gICAgICAgIGRpc2NvdmVyZWRTa2lsbHMgPSByZXN1bHQ/LmRpc2NvdmVyZWRTa2lsbHMgPz8gZGlzY292ZXJlZFNraWxscztcbiAgICAgIH0pXG4gICAgICAuY2F0Y2goKGUpID0+IHtcbiAgICAgICAgaWYgKEZhdGFsRXJyb3IuaXMoZSkpIHtcbiAgICAgICAgICB3ZkxvZy5lcnJvcihcIm1lc3NhZ2UgcHJvY2Vzc2luZyBmYWlsZWQgcGVybWFuZW50bHlcIiwge1xuICAgICAgICAgICAgZXJyb3I6IGUubWVzc2FnZSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH0pO1xuICAgIHBlbmRpbmdOZXh0ID0gaXRlcmF0b3IubmV4dCgpO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG9uTWVzc2FnZSh7XG4gIGV2ZW50LFxuICBpbnB1dCxcbiAgZGlzY292ZXJlZFNraWxscyxcbn06IHtcbiAgZXZlbnQ6IEFnZW50TWVzc2FnZUlucHV0O1xuICBpbnB1dDogQWdlbnRJbnB1dDtcbiAgZGlzY292ZXJlZFNraWxsczogU2tpbGxTdW1tYXJ5W10gfCBudWxsO1xufSk6IFByb21pc2U8eyBkaXNjb3ZlcmVkU2tpbGxzOiBTa2lsbFN1bW1hcnlbXSB8IG51bGwgfSB8IG51bGw+IHtcbiAgY29uc3QgbXNnTG9nID0gbG9nLndpdGhDb250ZXh0KHtcbiAgICBzZXNzaW9uSWQ6IGlucHV0LnNlc3Npb25JZCxcbiAgICBtZXNzYWdlSWQ6IGV2ZW50LmFzc2lzdGFudE1lc3NhZ2VJZCxcbiAgfSk7XG4gIGNvbnN0IGRvbmVNZXNzYWdlID0gbXNnTG9nLnRpbWUoXCJvbk1lc3NhZ2VcIik7XG4gIGNvbnN0IHdyaXRhYmxlID0gZ2V0V3JpdGFibGUoeyBuYW1lc3BhY2U6IGV2ZW50LmFzc2lzdGFudE1lc3NhZ2VJZCB9KTtcblxuICBsZXQgZmluaXNoUmVhc29uOiBGaW5pc2hSZWFzb24gfCB1bmRlZmluZWQ7XG4gIGxldCBsYXN0UGFydEluZGV4ID0gMDtcbiAgY29uc3QgdXNhZ2VTdGVwczogU3RlcFVzYWdlW10gPSBbXTtcblxuICB3aGlsZSAoZmluaXNoUmVhc29uICE9PSBcInN0b3BcIikge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBzdHJlYW1UZXh0U3RlcCh7XG4gICAgICAgIGFzc2lzdGFudE1lc3NhZ2VJZDogZXZlbnQuYXNzaXN0YW50TWVzc2FnZUlkLFxuICAgICAgICB3cml0YWJsZSxcbiAgICAgICAgaW5wdXQsXG4gICAgICAgIGV2ZW50LFxuICAgICAgICBsYXN0UGFydEluZGV4LFxuICAgICAgICBzdGVwSW5kZXhPZmZzZXQ6IHVzYWdlU3RlcHMubGVuZ3RoLFxuICAgICAgICBkaXNjb3ZlcmVkU2tpbGxzLFxuICAgICAgfSk7XG4gICAgICBmaW5pc2hSZWFzb24gPSByZXN1bHQuZmluaXNoUmVhc29uO1xuICAgICAgbGFzdFBhcnRJbmRleCA9IHJlc3VsdC5sYXN0UGFydEluZGV4O1xuICAgICAgdXNhZ2VTdGVwcy5wdXNoKC4uLnJlc3VsdC51c2FnZVN0ZXBzKTtcbiAgICAgIGRpc2NvdmVyZWRTa2lsbHMgPSByZXN1bHQuZGlzY292ZXJlZFNraWxscztcblxuICAgICAgaWYgKHJlc3VsdC5tYXhTdGVwcyAhPSBudWxsICYmIHVzYWdlU3RlcHMubGVuZ3RoID49IHJlc3VsdC5tYXhTdGVwcykge1xuICAgICAgICBtc2dMb2cuaW5mbyhcInJlYWNoZWQgbWF4U3RlcHMgbGltaXRcIiwgeyBtYXhTdGVwczogcmVzdWx0Lm1heFN0ZXBzIH0pO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cblxuICAgICAgaWYgKHJlc3VsdC5wZW5kaW5nQXBwcm92YWxzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgbXNnTG9nLmluZm8oXCJ3YWl0aW5nIGZvciBhcHByb3ZhbHNcIiwge1xuICAgICAgICAgIGNvdW50OiByZXN1bHQucGVuZGluZ0FwcHJvdmFscy5sZW5ndGgsXG4gICAgICAgICAgdG9vbHM6IHJlc3VsdC5wZW5kaW5nQXBwcm92YWxzLm1hcCgocCkgPT4gcC50b29sTmFtZSksXG4gICAgICAgIH0pO1xuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgICByZXN1bHQucGVuZGluZ0FwcHJvdmFscy5tYXAoKHBlbmRpbmcpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGhvb2sgPSBhcHByb3ZhbEhvb2suY3JlYXRlKHsgdG9rZW46IHBlbmRpbmcuYXBwcm92YWxJZCB9KTtcbiAgICAgICAgICAgIGNvbnN0IGl0ZXIgPSBob29rW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSgpO1xuICAgICAgICAgICAgcmV0dXJuIGl0ZXIubmV4dCgpO1xuICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBtc2dMb2cuZXJyb3IoXCJzdHJlYW1UZXh0U3RlcCBmYWlsZWRcIiwge1xuICAgICAgICBlcnJvcjogZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpLFxuICAgICAgfSk7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuICB9XG5cbiAgZG9uZU1lc3NhZ2UoeyB0b3RhbFN0ZXBzOiB1c2FnZVN0ZXBzLmxlbmd0aCB9KTtcblxuICBhd2FpdCBjb21wbGV0ZU1lc3NhZ2VTdGVwKHtcbiAgICBhc3Npc3RhbnRNZXNzYWdlSWQ6IGV2ZW50LmFzc2lzdGFudE1lc3NhZ2VJZCxcbiAgICBpbnB1dCxcbiAgICB3cml0YWJsZSxcbiAgICB1c2FnZVN0ZXBzLFxuICB9KTtcblxuICByZXR1cm4geyBkaXNjb3ZlcmVkU2tpbGxzIH07XG59XG4iLCAiaW1wb3J0IHtcbiAgY29udmVydFRvTW9kZWxNZXNzYWdlcyxcbiAgY3JlYXRlVUlNZXNzYWdlU3RyZWFtLFxuICB0eXBlIEZpbmlzaFJlYXNvbixcbiAgc3RlcENvdW50SXMsXG4gIHN0cmVhbVRleHQsXG4gIHR5cGUgVUlNZXNzYWdlLFxufSBmcm9tIFwiYWlcIjtcbmltcG9ydCB7IHVsaWQgfSBmcm9tIFwidWxpZFwiO1xuaW1wb3J0IHsgRmF0YWxFcnJvciB9IGZyb20gXCJ3b3JrZmxvd1wiO1xuaW1wb3J0IHR5cGUgeyBBZ2VudElucHV0LCBBZ2VudE1lc3NhZ2VJbnB1dCB9IGZyb20gXCIuL2FnZW50LXdvcmtmbG93XCI7XG5pbXBvcnQgdHlwZSB7IEFnZW50U3RhdHVzLCBScGNQYXlsb2FkLCBScGNSZXN1bHQgfSBmcm9tIFwiLi9jbGllbnRcIjtcbmltcG9ydCB7IGRpc2NvdmVyU2tpbGxzSW5TYW5kYm94IH0gZnJvbSBcIi4vc2tpbGxzL2Rpc2NvdmVyXCI7XG5pbXBvcnQgdHlwZSB7IFNraWxsU3VtbWFyeSB9IGZyb20gXCIuL3NraWxscy90eXBlc1wiO1xuaW1wb3J0IHR5cGUgeyBTYW5kYm94UmVjb3JkLCBTdG9yYWdlIH0gZnJvbSBcIi4vc3RvcmFnZVwiO1xuaW1wb3J0IHsgdHlwZSBCdWlsdEluVG9vbE5hbWUsIGZldGNoQXBpVG9vbHNNZXRhZGF0YSwgZ2V0VG9vbHMgfSBmcm9tIFwiLi90b29sc1wiO1xuaW1wb3J0IHR5cGUgeyBPblN1YlRvb2xDYWxsIH0gZnJvbSBcIi4vdG9vbHMvamF2YXNjcmlwdFwiO1xuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSBcIi4vdXRpbHMvbG9nZ2VyXCI7XG5pbXBvcnQgeyBhcHBseVByb21wdENhY2hpbmdUb01vZGVsUmVxdWVzdCB9IGZyb20gXCIuL3V0aWxzL3Byb21wdC1jYWNoZVwiO1xuaW1wb3J0IHsgYXNzZW1ibGVVSU1lc3NhZ2VzIH0gZnJvbSBcIi4vdXRpbHMvdWlcIjtcbmltcG9ydCB7IGNvbXB1dGVVc2FnZVN1bW1hcnksIHR5cGUgU3RlcFVzYWdlIH0gZnJvbSBcIi4vdXRpbHMvdXNhZ2VcIjtcblxuY29uc3QgbG9nID0gY3JlYXRlTG9nZ2VyKHsgc3Vic3lzdGVtOiBcIndvcmtmbG93XCIgfSk7XG5cbi8qKlxuICogRmlyZS1hbmQtZm9yZ2V0IHN0YXR1cyBlbWlzc2lvbi4gV3JpdGVzIGEgdHJhbnNpZW50IGBkYXRhLXN0YXR1c2AgY2h1bmtcbiAqIHRvIHRoZSBzdHJlYW0gYW5kIGNhbGxzIHRoZSBgaG9vay5zdGF0dXNgIFJQQy4gTmVpdGhlciBibG9ja3MgdGhlIGNhbGxlci5cbiAqL1xuZnVuY3Rpb24gZW1pdFN0YXR1cyh7XG4gIHdyaXRlcixcbiAgc3RhdHVzLFxuICBycGMsXG59OiB7XG4gIHdyaXRlcjogKChldmVudDogdW5rbm93bikgPT4gdm9pZCkgfCBudWxsO1xuICBzdGF0dXM6IEFnZW50U3RhdHVzO1xuICBycGM6IChwYXJhbXM6IFJwY1BheWxvYWQpID0+IFByb21pc2U8UnBjUmVzdWx0Pjtcbn0pIHtcbiAgd3JpdGVyPy4oeyB0eXBlOiBcImRhdGEtc3RhdHVzXCIsIGRhdGE6IHN0YXR1cywgdHJhbnNpZW50OiB0cnVlIH0pO1xuICAvLyBiaW9tZS1pZ25vcmUgbGludC9zdXNwaWNpb3VzL25vRW1wdHlCbG9ja1N0YXRlbWVudHM6IGZpcmUtYW5kLWZvcmdldFxuICBycGMoeyBtZXRob2Q6IFwiaG9vay5zdGF0dXNcIiwgcGFyYW1zOiB7IHN0YXR1cyB9IH0pLmNhdGNoKCgpID0+IHt9KTtcbn1cblxuY29uc3QgU1RBVFVTX1RIUk9UVExFX01TID0gNTAwO1xuXG4vKipcbiAqIENyZWF0ZXMgYSB0aHJvdHRsZWQgZW1pdFN0YXR1cyB0aGF0IGZpcmVzIGltbWVkaWF0ZWx5IG9uIHRoZSBmaXJzdCBjYWxsLFxuICogdGhlbiBzdXBwcmVzc2VzIGZ1cnRoZXIgZW1pc3Npb25zIHdpdGhpbiBhbiBOLW1zIHdpbmRvdy4gV2hlbiB0aGUgd2luZG93XG4gKiBleHBpcmVzLCB0aGUgbW9zdCByZWNlbnQgcGVuZGluZyBzdGF0dXMgaXMgZmx1c2hlZCBzbyB0aGUgVUkgYWx3YXlzXG4gKiBjb252ZXJnZXMgdG8gdGhlIGNvcnJlY3Qgc3RhdGUuIENhbGwgYC5kaXNwb3NlKClgIHRvIGZsdXNoIGFuZCBjbGVhbiB1cC5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlVGhyb3R0bGVkRW1pdFN0YXR1cyhcbiAgcnBjOiAocGFyYW1zOiBScGNQYXlsb2FkKSA9PiBQcm9taXNlPFJwY1Jlc3VsdD5cbikge1xuICBsZXQgdGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgbnVsbCA9IG51bGw7XG4gIGxldCBwZW5kaW5nOiB7XG4gICAgd3JpdGVyOiAoKGV2ZW50OiB1bmtub3duKSA9PiB2b2lkKSB8IG51bGw7XG4gICAgc3RhdHVzOiBBZ2VudFN0YXR1cztcbiAgfSB8IG51bGwgPSBudWxsO1xuXG4gIGZ1bmN0aW9uIHRocm90dGxlZCh7XG4gICAgd3JpdGVyLFxuICAgIHN0YXR1cyxcbiAgfToge1xuICAgIHdyaXRlcjogKChldmVudDogdW5rbm93bikgPT4gdm9pZCkgfCBudWxsO1xuICAgIHN0YXR1czogQWdlbnRTdGF0dXM7XG4gIH0pIHtcbiAgICBwZW5kaW5nID0geyB3cml0ZXIsIHN0YXR1cyB9O1xuICAgIGlmICh0aW1lciAhPT0gbnVsbCkge1xuICAgICAgLy8gd2l0aGluIHRocm90dGxlIHdpbmRvdyBcdTIwMTQgcXVldWVkXG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGZsdXNoKCk7XG4gICAgdGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRpbWVyID0gbnVsbDtcbiAgICAgIGlmIChwZW5kaW5nKSB7XG4gICAgICAgIGZsdXNoKCk7XG4gICAgICB9XG4gICAgfSwgU1RBVFVTX1RIUk9UVExFX01TKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGZsdXNoKCkge1xuICAgIGlmICghcGVuZGluZykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCB7IHdyaXRlciwgc3RhdHVzIH0gPSBwZW5kaW5nO1xuICAgIHBlbmRpbmcgPSBudWxsO1xuICAgIGVtaXRTdGF0dXMoeyB3cml0ZXIsIHN0YXR1cywgcnBjIH0pO1xuICB9XG5cbiAgdGhyb3R0bGVkLmRpc3Bvc2UgPSAoKSA9PiB7XG4gICAgaWYgKHRpbWVyICE9PSBudWxsKSB7XG4gICAgICBjbGVhclRpbWVvdXQodGltZXIpO1xuICAgICAgdGltZXIgPSBudWxsO1xuICAgIH1cbiAgICBmbHVzaCgpO1xuICB9O1xuXG4gIHJldHVybiB0aHJvdHRsZWQ7XG59XG5cbmNvbnN0IEJBU0VfU1lTVEVNX1BST01QVCA9XG4gIFwiWW91IGFyZSBhbiBBSSBhc3Npc3RhbnQgd2l0aCBiYXNpYyB0b29scyB0byBpbnRlcmFjdCB3aXRoIHlvdXIgZW52aXJvbm1lbnQuIEV4cGxvcmUgYW5kIHdvcmsgZnJlZWx5LlwiO1xuXG5mdW5jdGlvbiBqb2luUHJvbXB0U2VjdGlvbnMoXG4gIC4uLnNlY3Rpb25zOiAoc3RyaW5nIHwgdW5kZWZpbmVkIHwgbnVsbClbXVxuKTogc3RyaW5nIHtcbiAgcmV0dXJuIHNlY3Rpb25zLmZpbHRlcigocykgPT4gcz8udHJpbSgpKS5qb2luKFwiXFxuXFxuXCIpO1xufVxuXG5jb25zdCBiYWNrZ3JvdW5kUHJvY2Vzc1Byb21wdCA9IGAjIyBCYWNrZ3JvdW5kIFByb2Nlc3Nlc1xuVGhlc2UgYmFja2dyb3VuZCBwcm9jZXNzIGluc3RydWN0aW9ucyBhcmUgZm9yIHlvdSB0byBtYW5pcHVsYXRlIHRoZSBwcm9jZXNzZXMsIGRvIG5vdCBiZSB0byB2ZXJib3NlIHRvIHRoZSB1c2VyIGFib3V0IHRoZSByZXNwb25zZSBkZXRhaWxzIGxpa2UgXCJob3cgdG8gZGVidWcgdGhlIHByb2Nlc3Mgb3V0cHV0XCIgdGhlIHVzZXIgd2lsbCBoYXZlIGFuIFVJLlxuXG5Vc2UgXFxgd2FpdFVudGlsOiAwXFxgIGZvciBkZXYgc2VydmVycyB0aGF0IHNob3VsZCBydW4gaW5kZWZpbml0ZWx5LlxuSXQgaXMgYSBnb29kIHByYWN0aWNlIHRvIGNoZWNrIHRoZSBvdXRwdXQgbG9nIGFmdGVyIHJ1bm5pbmcgcHJvY2Vzc2VzIGxpa2UgZGV2IHNlcnZlcnMgdG8gbWFrZSBzdXJlIHRoZXkgc3RhcnRlZCBjb3JyZWN0bHkuXG5cblRvIHJ1biBhIGJhY2tncm91bmQgcHJvY2VzczpcbkJhc2goeyBjb21tYW5kOiBcIm5wbSBydW4gZGV2XCIsIHdhaXRVbnRpbDogMCB9KVxuUmV0dXJucyBpbW1lZGlhdGVseSB3aXRoIFxcYGNvbW1hbmRJZFxcYC4gVGhlIHByb2Nlc3Mga2VlcHMgcnVubmluZyBpbiB0aGUgc2FuZGJveC5cblxuVG8ga2lsbCBhIHByb2Nlc3M6XG5CYXNoKHsgY29tbWFuZDogXCJwcyBhdXggfCBncmVwIG5vZGVcIiB9KSAgIC8vIEZpbmQgdGhlIFBJRFxuQmFzaCh7IGNvbW1hbmQ6IFwia2lsbCB7cGlkfVwiIH0pICAgICAgICAgICAgLy8gR3JhY2VmdWxcbkJhc2goeyBjb21tYW5kOiBcImtpbGwgLTkge3BpZH1cIiB9KSAgICAgICAgIC8vIEZvcmNlXG5gO1xuXG5mdW5jdGlvbiBidWlsZFNraWxsc0NvbnRleHQoc2tpbGxzOiBTa2lsbFN1bW1hcnlbXSk6IHN0cmluZyB7XG4gIGlmIChza2lsbHMubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIFwiXCI7XG4gIH1cblxuICBjb25zdCBza2lsbExpbmVzID0gc2tpbGxzXG4gICAgLm1hcCgocykgPT4gYC0gJHtzLm5hbWV9OiAke3MuZGVzY3JpcHRpb259YClcbiAgICAuam9pbihcIlxcblwiKTtcblxuICByZXR1cm4gYCMjIEF2YWlsYWJsZSBTa2lsbHNcbiR7c2tpbGxMaW5lc31cblxuJHtiYWNrZ3JvdW5kUHJvY2Vzc1Byb21wdH1cblxuVXNlIHRoZSBTa2lsbCB0b29sIHRvIGxvYWQgYSBza2lsbCdzIGZ1bGwgaW5zdHJ1Y3Rpb25zIGJlZm9yZSBmb2xsb3dpbmcgaXQuYDtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNvbXBsZXRlTWVzc2FnZVN0ZXAoe1xuICBhc3Npc3RhbnRNZXNzYWdlSWQsXG4gIGlucHV0LFxuICB3cml0YWJsZSxcbiAgdXNhZ2VTdGVwcyxcbn06IHtcbiAgYXNzaXN0YW50TWVzc2FnZUlkOiBzdHJpbmc7XG4gIGlucHV0OiBBZ2VudElucHV0O1xuICB3cml0YWJsZTogV3JpdGFibGVTdHJlYW07XG4gIHVzYWdlU3RlcHM6IFN0ZXBVc2FnZVtdO1xufSkge1xuICBcInVzZSBzdGVwXCI7XG5cbiAgY29uc3QgbXNnTG9nID0gbG9nLndpdGhDb250ZXh0KHtcbiAgICBzZXNzaW9uSWQ6IGlucHV0LnNlc3Npb25JZCxcbiAgICBtZXNzYWdlSWQ6IGFzc2lzdGFudE1lc3NhZ2VJZCxcbiAgfSk7XG5cbiAgY29uc3QgeyBnZXRTdG9yYWdlIH0gPSBhd2FpdCBpbXBvcnQoXCIuL3N0b3JhZ2UvY2xpZW50XCIpO1xuICBjb25zdCBzdG9yYWdlID0gZ2V0U3RvcmFnZSh7IGNvbmZpZzogaW5wdXQuc3RvcmFnZUNvbmZpZywgcnBjOiBpbnB1dC5ycGMgfSk7XG5cbiAgY29uc3QgbWVzc2FnZSA9IGF3YWl0IHN0b3JhZ2UubWVzc2FnZS5nZXQoYXNzaXN0YW50TWVzc2FnZUlkKTtcbiAgaWYgKG1lc3NhZ2UgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgIHRocm93IG1lc3NhZ2U7XG4gIH1cbiAgaWYgKCFtZXNzYWdlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBNZXNzYWdlICR7YXNzaXN0YW50TWVzc2FnZUlkfSBub3QgZm91bmRgKTtcbiAgfVxuXG4gIGNvbnN0IHVzYWdlID1cbiAgICB1c2FnZVN0ZXBzLmxlbmd0aCA+IDBcbiAgICAgID8ge1xuICAgICAgICAgIHN0ZXBzOiB1c2FnZVN0ZXBzLFxuICAgICAgICAgIHN1bW1hcnk6IGNvbXB1dGVVc2FnZVN1bW1hcnkodXNhZ2VTdGVwcyksXG4gICAgICAgIH1cbiAgICAgIDogbnVsbDtcblxuICBjb25zdCByZXN1bHQgPSBhd2FpdCBzdG9yYWdlLm1lc3NhZ2Uuc2V0KHtcbiAgICAuLi5tZXNzYWdlLFxuICAgIGNvbXBsZXRlZEF0OiBEYXRlLm5vdygpLFxuICAgIHVzYWdlLFxuICB9KTtcbiAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgdGhyb3cgcmVzdWx0O1xuICB9XG5cbiAgbXNnTG9nLmluZm8oXCJtZXNzYWdlIGNvbXBsZXRlZFwiLCB7XG4gICAgc3RlcHM6IHVzYWdlU3RlcHMubGVuZ3RoLFxuICAgIHRvdGFsVG9rZW5zOiB1c2FnZT8uc3VtbWFyeS50b3RhbFRva2VucyxcbiAgfSk7XG5cbiAgYXdhaXQgd3JpdGFibGUuY2xvc2UoKTtcbn1cblxuY29uc3QgSU5URVJSVVBUX1BPTExfSU5URVJWQUxfTVMgPSAyNTA7XG5cbmZ1bmN0aW9uIHBvbGxGb3JJbnRlcnJ1cHQoe1xuICBzdG9yYWdlLFxuICBtZXNzYWdlSWQsXG4gIHNpZ25hbCxcbiAgYWJvcnRDb250cm9sbGVyLFxufToge1xuICBzdG9yYWdlOiBTdG9yYWdlO1xuICBtZXNzYWdlSWQ6IHN0cmluZztcbiAgc2lnbmFsOiBBYm9ydFNpZ25hbDtcbiAgYWJvcnRDb250cm9sbGVyOiBBYm9ydENvbnRyb2xsZXI7XG59KToge1xuICBmaXJzdENoZWNrOiBQcm9taXNlPHZvaWQ+O1xuICBpbnRlcnJ1cHRlZExhc3RQYXJ0UmVmOiB7IGN1cnJlbnQ6IHsgaW5kZXg6IG51bWJlcjsgcGFydDogdW5rbm93biB9IHwgbnVsbCB9O1xufSB7XG4gIGxldCByZXNvbHZlRmlyc3RDaGVjazogKCkgPT4gdm9pZDtcbiAgY29uc3QgZmlyc3RDaGVjayA9IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlKSA9PiB7XG4gICAgcmVzb2x2ZUZpcnN0Q2hlY2sgPSByZXNvbHZlO1xuICB9KTtcbiAgY29uc3QgaW50ZXJydXB0ZWRMYXN0UGFydFJlZiA9IHtcbiAgICBjdXJyZW50OiBudWxsIGFzIHsgaW5kZXg6IG51bWJlcjsgcGFydDogdW5rbm93biB9IHwgbnVsbCxcbiAgfTtcblxuICBjb25zdCBwb2xsID0gYXN5bmMgKCkgPT4ge1xuICAgIGxldCBpc0ZpcnN0ID0gdHJ1ZTtcbiAgICB3aGlsZSAoIXNpZ25hbC5hYm9ydGVkKSB7XG4gICAgICBjb25zdCBtZXNzYWdlID0gYXdhaXQgc3RvcmFnZS5tZXNzYWdlLmdldChtZXNzYWdlSWQpO1xuICAgICAgaWYgKG1lc3NhZ2UgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICBpZiAoaXNGaXJzdCkge1xuICAgICAgICAgIHJlc29sdmVGaXJzdENoZWNrKCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgaWYgKG1lc3NhZ2UuaW50ZXJydXB0ZWRBdCAhPT0gbnVsbCkge1xuICAgICAgICBsb2cuaW5mbyhcImludGVycnVwdCBkZXRlY3RlZFwiLCB7IG1lc3NhZ2VJZCB9KTtcbiAgICAgICAgaW50ZXJydXB0ZWRMYXN0UGFydFJlZi5jdXJyZW50ID0gbWVzc2FnZS5pbnRlcnJ1cHRlZExhc3RQYXJ0O1xuICAgICAgICBhYm9ydENvbnRyb2xsZXIuYWJvcnQoKTtcbiAgICAgICAgaWYgKGlzRmlyc3QpIHtcbiAgICAgICAgICByZXNvbHZlRmlyc3RDaGVjaygpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGlmIChpc0ZpcnN0KSB7XG4gICAgICAgIGlzRmlyc3QgPSBmYWxzZTtcbiAgICAgICAgcmVzb2x2ZUZpcnN0Q2hlY2soKTtcbiAgICAgIH1cbiAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PlxuICAgICAgICBzZXRUaW1lb3V0KHJlc29sdmUsIElOVEVSUlVQVF9QT0xMX0lOVEVSVkFMX01TKVxuICAgICAgKTtcbiAgICB9XG4gIH07XG5cbiAgcG9sbCgpO1xuICByZXR1cm4geyBmaXJzdENoZWNrLCBpbnRlcnJ1cHRlZExhc3RQYXJ0UmVmIH07XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdHJlYW1UZXh0U3RlcCh7XG4gIGFzc2lzdGFudE1lc3NhZ2VJZCxcbiAgaW5wdXQsXG4gIGV2ZW50LFxuICB3cml0YWJsZSxcbiAgbGFzdFBhcnRJbmRleCxcbiAgc3RlcEluZGV4T2Zmc2V0LFxuICBkaXNjb3ZlcmVkU2tpbGxzLFxufToge1xuICBhc3Npc3RhbnRNZXNzYWdlSWQ6IHN0cmluZztcbiAgaW5wdXQ6IEFnZW50SW5wdXQ7XG4gIGV2ZW50OiBBZ2VudE1lc3NhZ2VJbnB1dDtcbiAgd3JpdGFibGU6IFdyaXRhYmxlU3RyZWFtO1xuICBsYXN0UGFydEluZGV4OiBudW1iZXI7XG4gIHN0ZXBJbmRleE9mZnNldDogbnVtYmVyO1xuICBkaXNjb3ZlcmVkU2tpbGxzOiBTa2lsbFN1bW1hcnlbXSB8IG51bGw7XG59KTogUHJvbWlzZTx7XG4gIGZpbmlzaFJlYXNvbjogRmluaXNoUmVhc29uO1xuICBsYXN0UGFydEluZGV4OiBudW1iZXI7XG4gIHVzYWdlU3RlcHM6IFN0ZXBVc2FnZVtdO1xuICBwZW5kaW5nQXBwcm92YWxzOiB7IGFwcHJvdmFsSWQ6IHN0cmluZzsgdG9vbE5hbWU6IHN0cmluZyB9W107XG4gIG1heFN0ZXBzOiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gIGRpc2NvdmVyZWRTa2lsbHM6IFNraWxsU3VtbWFyeVtdIHwgbnVsbDtcbn0+IHtcbiAgXCJ1c2Ugc3RlcFwiO1xuXG4gIGNvbnN0IHsgZ2V0U3RvcmFnZSB9ID0gYXdhaXQgaW1wb3J0KFwiLi9zdG9yYWdlL2NsaWVudFwiKTtcbiAgY29uc3QgeyBnZXRTYW5kYm94IH0gPSBhd2FpdCBpbXBvcnQoXCIuL3NhbmRib3hcIik7XG5cbiAgY29uc3Qgc3RlcExvZyA9IGxvZy53aXRoQ29udGV4dCh7XG4gICAgc2Vzc2lvbklkOiBpbnB1dC5zZXNzaW9uSWQsXG4gICAgbWVzc2FnZUlkOiBhc3Npc3RhbnRNZXNzYWdlSWQsXG4gIH0pO1xuICBjb25zdCBkb25lU3RlcCA9IHN0ZXBMb2cudGltZShcInN0cmVhbVRleHRTdGVwXCIpO1xuXG4gIGNvbnN0IHJwYyA9IGlucHV0LnJwYztcbiAgY29uc3QgdGhyb3R0bGVkRW1pdFN0YXR1cyA9IGNyZWF0ZVRocm90dGxlZEVtaXRTdGF0dXMocnBjKTtcbiAgY29uc3Qgc3RvcmFnZSA9IGdldFN0b3JhZ2UoeyBjb25maWc6IGlucHV0LnN0b3JhZ2VDb25maWcsIHJwYyB9KTtcbiAgY29uc3QgcG9sbFN0b3JhZ2UgPSBnZXRTdG9yYWdlKHtcbiAgICBjb25maWc6IGlucHV0LnN0b3JhZ2VDb25maWcsXG4gICAgcnBjOiAocCkgPT4gcnBjKHsgLi4ucCwgX3F1aWV0OiB0cnVlIH0pLFxuICB9KTtcblxuICBjb25zdCBhYm9ydENvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gIGNvbnN0IHBvbGxDb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuXG4gIGNvbnN0IHsgZmlyc3RDaGVjaywgaW50ZXJydXB0ZWRMYXN0UGFydFJlZiB9ID0gcG9sbEZvckludGVycnVwdCh7XG4gICAgc3RvcmFnZTogcG9sbFN0b3JhZ2UsXG4gICAgbWVzc2FnZUlkOiBhc3Npc3RhbnRNZXNzYWdlSWQsXG4gICAgc2lnbmFsOiBwb2xsQ29udHJvbGxlci5zaWduYWwsXG4gICAgYWJvcnRDb250cm9sbGVyLFxuICB9KTtcblxuICBjb25zdCBkb25lTG9hZCA9IHN0ZXBMb2cudGltZShcImxvYWQgc2Vzc2lvbiArIG1lc3NhZ2VzICsgcGFydHMgKyBzYW5kYm94XCIpO1xuICBjb25zdCBbXG4gICAgLFxuICAgIG1lc3NhZ2VzUmVzdWx0LFxuICAgIHBhcnRzUmVzdWx0LFxuICAgIHsgc2Vzc2lvbiwgc2FuZGJveCwgc2FuZGJveFJlY29yZCB9LFxuICAgIGFwaVRvb2xzTWV0YWRhdGEsXG4gIF0gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgZmlyc3RDaGVjayxcbiAgICBzdG9yYWdlLm1lc3NhZ2UubGlzdChpbnB1dC5zZXNzaW9uSWQpLFxuICAgIHN0b3JhZ2UucGFydC5saXN0QnlTZXNzaW9uKGlucHV0LnNlc3Npb25JZCksXG4gICAgc3RvcmFnZS5zZXNzaW9uLmdldChpbnB1dC5zZXNzaW9uSWQpLnRoZW4oYXN5bmMgKHNlc3Npb24pID0+IHtcbiAgICAgIGlmIChzZXNzaW9uIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgdGhyb3cgc2Vzc2lvbjtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHNhbmRib3hSZWNvcmQgPSBzZXNzaW9uLnNhbmRib3hJZFxuICAgICAgICA/IGF3YWl0IHN0b3JhZ2Uuc2FuZGJveC5nZXQoc2Vzc2lvbi5zYW5kYm94SWQpXG4gICAgICAgIDogbnVsbDtcbiAgICAgIGlmIChzYW5kYm94UmVjb3JkIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgdGhyb3cgc2FuZGJveFJlY29yZDtcbiAgICAgIH1cbiAgICAgIGlmICghc2FuZGJveFJlY29yZCkge1xuICAgICAgICB0aHJvdyBuZXcgRmF0YWxFcnJvcihcbiAgICAgICAgICBgU2FuZGJveCBub3QgZm91bmQgZm9yIHNlc3Npb24gJHtpbnB1dC5zZXNzaW9uSWR9YFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgY29uc3Qgc2FuZGJveCA9IGdldFNhbmRib3goe1xuICAgICAgICBzYW5kYm94UmVjb3JkLFxuICAgICAgICBzdG9yYWdlQ29uZmlnOiBpbnB1dC5zdG9yYWdlQ29uZmlnLFxuICAgICAgICBzdG9yYWdlLFxuICAgICAgICBycGMsXG4gICAgICB9KTtcblxuICAgICAgcmV0dXJuIHsgc2Vzc2lvbiwgc2FuZGJveCwgc2FuZGJveFJlY29yZCB9O1xuICAgIH0pLFxuICAgIGZldGNoQXBpVG9vbHNNZXRhZGF0YSh7XG4gICAgICBycGMsXG4gICAgfSksXG4gIF0pO1xuICBkb25lTG9hZCgpO1xuXG4gIGlmIChhYm9ydENvbnRyb2xsZXIuc2lnbmFsLmFib3J0ZWQpIHtcbiAgICBwb2xsQ29udHJvbGxlci5hYm9ydCgpO1xuICAgIHJldHVybiB7XG4gICAgICBmaW5pc2hSZWFzb246IFwic3RvcFwiIGFzIEZpbmlzaFJlYXNvbixcbiAgICAgIGxhc3RQYXJ0SW5kZXgsXG4gICAgICB1c2FnZVN0ZXBzOiBbXSxcbiAgICAgIHBlbmRpbmdBcHByb3ZhbHM6IFtdLFxuICAgICAgbWF4U3RlcHM6IHVuZGVmaW5lZCxcbiAgICAgIGRpc2NvdmVyZWRTa2lsbHMsXG4gICAgfTtcbiAgfVxuXG4gIGlmIChtZXNzYWdlc1Jlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgdGhyb3cgbWVzc2FnZXNSZXN1bHQ7XG4gIH1cbiAgaWYgKHBhcnRzUmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICB0aHJvdyBwYXJ0c1Jlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBPbiBmaXJzdCBpdGVyYXRpb24sIG1hcmsgYWxsIG1lc3NhZ2VzIGluIHRoaXMgYmF0Y2ggYXMgc3RhcnRlZC5cbiAgICogVXNlciBtZXNzYWdlcyBhcmUgYWxzbyBtYXJrZWQgYXMgY29tcGxldGVkICh0aGV5J3JlIGRvbmUpLlxuICAgKiBUaGUgYXNzaXN0YW50IG1lc3NhZ2UgaXMgb25seSBtYXJrZWQgYXMgc3RhcnRlZCAoc3RyZWFtaW5nIGluIHByb2dyZXNzKS5cbiAgICovXG4gIGNvbnN0IHNldFN0YXJ0ZWRQcm9taXNlID1cbiAgICBsYXN0UGFydEluZGV4ID09PSAwXG4gICAgICA/IChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICBjb25zdCBwZW5kaW5nTWVzc2FnZXMgPSBtZXNzYWdlc1Jlc3VsdC5pdGVtcy5maWx0ZXIoXG4gICAgICAgICAgICAobSkgPT4gbS5jcmVhdGVkQXQgPD0gZXZlbnQuY3JlYXRlZEF0ICYmIG0uc3RhcnRlZEF0ID09PSBudWxsXG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAocGVuZGluZ01lc3NhZ2VzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgICAgICAgcGVuZGluZ01lc3NhZ2VzLm1hcCgobSkgPT5cbiAgICAgICAgICAgICAgICBzdG9yYWdlLm1lc3NhZ2Uuc2V0KHtcbiAgICAgICAgICAgICAgICAgIC4uLm0sXG4gICAgICAgICAgICAgICAgICBzdGFydGVkQXQ6IG5vdyxcbiAgICAgICAgICAgICAgICAgIGNvbXBsZXRlZEF0OiBtLnJvbGUgPT09IFwiYXNzaXN0YW50XCIgPyBudWxsIDogbm93LFxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9KSgpXG4gICAgICA6IG51bGw7XG5cbiAgLy8gTXV0YWJsZSByZWYgc28gb25TdWJUb29sQ2FsbCBjYW4gd3JpdGUgdG8gdGhlIHN0cmVhbSBvbmNlIGF2YWlsYWJsZVxuICBjb25zdCBzdHJlYW1Xcml0ZXJSZWY6IHtcbiAgICBjdXJyZW50OiAoKGV2ZW50OiB1bmtub3duKSA9PiB2b2lkKSB8IG51bGw7XG4gIH0gPSB7IGN1cnJlbnQ6IG51bGwgfTtcblxuICBjb25zdCBzdWJUb29sUGFydElkczogc3RyaW5nW10gPSBbXTtcbiAgLy8gU2hhcmVkIGNvdW50ZXIgZm9yIHBhcnQgaW5kaWNlcyBcdTIwMTQgc3ViLXRvb2wgcGFydHMgaW5jcmVtZW50IHRoaXMgZHVyaW5nXG4gIC8vIHRoZSBzdHJlYW0sIHRoZW4gc3RlcFBhcnRzIGNvbnRpbnVlIGZyb20gd2hlcmUgaXQgbGVmdCBvZmYuXG4gIGxldCBuZXh0UGFydEluZGV4ID0gbGFzdFBhcnRJbmRleDtcblxuICBjb25zdCBvblN1YlRvb2xDYWxsOiBPblN1YlRvb2xDYWxsID0gYXN5bmMgKHRvb2xOYW1lLCB0b29sSW5wdXQsIGV4ZWN1dGUpID0+IHtcbiAgICAvLyBDaGVjayBpZiB0aGlzIHRvb2wgbmVlZHMgYXBwcm92YWwgdmlhIFJQQ1xuICAgIGNvbnN0IHJlcyA9IGF3YWl0IHJwYyh7XG4gICAgICBtZXRob2Q6IFwidG9vbHMubmVlZHNBcHByb3ZhbFwiLFxuICAgICAgcGFyYW1zOiB7XG4gICAgICAgIHRvb2xOYW1lLFxuICAgICAgICBpbnB1dDogdG9vbElucHV0LFxuICAgICAgICB0b29sQ2FsbElkOiBganNfJHt0b29sTmFtZX1fJHtEYXRlLm5vdygpfWAsXG4gICAgICAgIG1lc3NhZ2VzOiBbXSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBpZiAoXCJlcnJvclwiIGluIHJlcyB8fCByZXMucmVzdWx0ICE9PSB0cnVlKSB7XG4gICAgICAvLyBObyBhcHByb3ZhbCBuZWVkZWQgXHUyMDE0IGp1c3QgZXhlY3V0ZVxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZXhlY3V0ZSgpO1xuICAgICAgICByZXR1cm4geyByZXN1bHQgfTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICByZXR1cm4geyBlcnJvcjogZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpIH07XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQXBwcm92YWwgbmVlZGVkIFx1MjAxNCBzdXJmYWNlIHRvIHVzZXIgdmlhIHN0cmVhbSBldmVudHNcbiAgICBjb25zdCBhcHByb3ZhbElkID0gYGpzX2FwcHJvdmFsXyR7dWxpZCgpfWA7XG4gICAgY29uc3QgdG9vbENhbGxJZCA9IGBqc190Y18ke3VsaWQoKX1gO1xuICAgIGNvbnN0IHBhcnRJZCA9IGBwYXJ0XyR7dWxpZCgpfWA7XG4gICAgc3ViVG9vbFBhcnRJZHMucHVzaChwYXJ0SWQpO1xuXG4gICAgLy8gU3RvcmUgYXBwcm92YWwtcmVxdWVzdCBwYXJ0XG4gICAgYXdhaXQgc3RvcmFnZS5wYXJ0LnNldCh7XG4gICAgICBpZDogcGFydElkLFxuICAgICAgaW5kZXg6IG5leHRQYXJ0SW5kZXgrKyxcbiAgICAgIG1lc3NhZ2VJZDogYXNzaXN0YW50TWVzc2FnZUlkLFxuICAgICAgc2Vzc2lvbklkOiBpbnB1dC5zZXNzaW9uSWQsXG4gICAgICBwYXJ0OiB7XG4gICAgICAgIHR5cGU6IGB0b29sLSR7dG9vbE5hbWV9YCxcbiAgICAgICAgdG9vbENhbGxJZCxcbiAgICAgICAgc3RhdGU6IFwiYXBwcm92YWwtcmVxdWVzdGVkXCIsXG4gICAgICAgIGlucHV0OiB0b29sSW5wdXQsXG4gICAgICAgIGFwcHJvdmFsOiB7IGlkOiBhcHByb3ZhbElkIH0sXG4gICAgICB9IGFzIHVua25vd24gYXMgVUlNZXNzYWdlW1wicGFydHNcIl1bbnVtYmVyXSxcbiAgICB9KTtcblxuICAgIC8vIFdyaXRlIHN0cmVhbSBldmVudHMgZm9yIHRoZSBVSVxuICAgIC8vIHRvb2wtaW5wdXQtc3RhcnQgaXMgcmVxdWlyZWQgXHUyMDE0IHRoZSBBSSBTREsgY2xpZW50IGNyZWF0ZXMgdGhlIHRvb2wgcGFydFxuICAgIC8vIHdoZW4gaXQgc2VlcyB0aGlzIGV2ZW50LiBXaXRob3V0IGl0LCBzdWJzZXF1ZW50IGV2ZW50cyBhcmUgaWdub3JlZC5cbiAgICBzdHJlYW1Xcml0ZXJSZWYuY3VycmVudD8uKHtcbiAgICAgIHR5cGU6IFwidG9vbC1pbnB1dC1zdGFydFwiLFxuICAgICAgdG9vbENhbGxJZCxcbiAgICAgIHRvb2xOYW1lLFxuICAgIH0pO1xuICAgIHN0cmVhbVdyaXRlclJlZi5jdXJyZW50Py4oe1xuICAgICAgdHlwZTogXCJ0b29sLWlucHV0LWF2YWlsYWJsZVwiLFxuICAgICAgdG9vbENhbGxJZCxcbiAgICAgIHRvb2xOYW1lLFxuICAgICAgaW5wdXQ6IHRvb2xJbnB1dCxcbiAgICB9KTtcbiAgICBzdHJlYW1Xcml0ZXJSZWYuY3VycmVudD8uKHtcbiAgICAgIHR5cGU6IFwidG9vbC1hcHByb3ZhbC1yZXF1ZXN0XCIsXG4gICAgICBhcHByb3ZhbElkLFxuICAgICAgdG9vbENhbGxJZCxcbiAgICB9KTtcblxuICAgIC8vIFBvbGwgc3RvcmFnZSBmb3IgYXBwcm92YWwgcmVzcG9uc2VcbiAgICBjb25zdCBQT0xMX01TID0gNTAwO1xuICAgIGNvbnN0IFRJTUVPVVRfTVMgPSA1ICogNjAgKiAxMDAwO1xuICAgIGNvbnN0IHN0YXJ0ID0gRGF0ZS5ub3coKTtcblxuICAgIHdoaWxlIChEYXRlLm5vdygpIC0gc3RhcnQgPCBUSU1FT1VUX01TICYmICFhYm9ydENvbnRyb2xsZXIuc2lnbmFsLmFib3J0ZWQpIHtcbiAgICAgIGNvbnN0IHBhcnRzID0gYXdhaXQgc3RvcmFnZS5wYXJ0Lmxpc3RCeVNlc3Npb24oaW5wdXQuc2Vzc2lvbklkKTtcbiAgICAgIGlmICghKHBhcnRzIGluc3RhbmNlb2YgRXJyb3IpKSB7XG4gICAgICAgIGNvbnN0IHVwZGF0ZWQgPSBwYXJ0cy5pdGVtcy5maW5kKFxuICAgICAgICAgIChwKSA9PlxuICAgICAgICAgICAgcC5pZCA9PT0gcGFydElkICYmXG4gICAgICAgICAgICBcInN0YXRlXCIgaW4gcC5wYXJ0ICYmXG4gICAgICAgICAgICAoKHAucGFydCBhcyB7IHN0YXRlOiBzdHJpbmcgfSkuc3RhdGUgPT09IFwiYXBwcm92YWwtcmVzcG9uZGVkXCIgfHxcbiAgICAgICAgICAgICAgKHAucGFydCBhcyB7IHN0YXRlOiBzdHJpbmcgfSkuc3RhdGUgPT09IFwib3V0cHV0LWRlbmllZFwiKVxuICAgICAgICApO1xuICAgICAgICBpZiAodXBkYXRlZCkge1xuICAgICAgICAgIGNvbnN0IHN0YXRlID0gKHVwZGF0ZWQucGFydCBhcyB7IHN0YXRlOiBzdHJpbmcgfSkuc3RhdGU7XG5cbiAgICAgICAgICBpZiAoc3RhdGUgPT09IFwib3V0cHV0LWRlbmllZFwiKSB7XG4gICAgICAgICAgICBjb25zdCByZWFzb24gPSAodXBkYXRlZC5wYXJ0IGFzIHsgYXBwcm92YWw/OiB7IHJlYXNvbj86IHN0cmluZyB9IH0pXG4gICAgICAgICAgICAgIC5hcHByb3ZhbD8ucmVhc29uO1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgZXJyb3I6IGBUb29sIFwiJHt0b29sTmFtZX1cIiBkZW5pZWQ6ICR7cmVhc29uIHx8IFwidXNlciBkZW5pZWRcIn1gLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCBhcHByb3ZhbCA9IChcbiAgICAgICAgICAgIHVwZGF0ZWQucGFydCBhcyB7XG4gICAgICAgICAgICAgIGFwcHJvdmFsPzogeyBhcHByb3ZlZDogYm9vbGVhbjsgcmVhc29uPzogc3RyaW5nIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgKS5hcHByb3ZhbDtcbiAgICAgICAgICBpZiAoYXBwcm92YWw/LmFwcHJvdmVkKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBleGVjdXRlKCk7XG4gICAgICAgICAgICAgIHN0cmVhbVdyaXRlclJlZi5jdXJyZW50Py4oe1xuICAgICAgICAgICAgICAgIHR5cGU6IFwidG9vbC1vdXRwdXQtYXZhaWxhYmxlXCIsXG4gICAgICAgICAgICAgICAgdG9vbENhbGxJZCxcbiAgICAgICAgICAgICAgICBvdXRwdXQ6IHJlc3VsdCxcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIHJldHVybiB7IHJlc3VsdCB9O1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGVycm9yID0gZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpO1xuICAgICAgICAgICAgICBzdHJlYW1Xcml0ZXJSZWYuY3VycmVudD8uKHtcbiAgICAgICAgICAgICAgICB0eXBlOiBcInRvb2wtb3V0cHV0LWVycm9yXCIsXG4gICAgICAgICAgICAgICAgdG9vbENhbGxJZCxcbiAgICAgICAgICAgICAgICBlcnJvclRleHQ6IGVycm9yLFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgcmV0dXJuIHsgZXJyb3IgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gRGVuaWVkXG4gICAgICAgICAgc3RyZWFtV3JpdGVyUmVmLmN1cnJlbnQ/Lih7XG4gICAgICAgICAgICB0eXBlOiBcInRvb2wtb3V0cHV0LWRlbmllZFwiLFxuICAgICAgICAgICAgdG9vbENhbGxJZCxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgZXJyb3I6IGBUb29sIFwiJHt0b29sTmFtZX1cIiBkZW5pZWQ6ICR7YXBwcm92YWw/LnJlYXNvbiB8fCBcInVzZXIgZGVuaWVkXCJ9YCxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocikgPT4gc2V0VGltZW91dChyLCBQT0xMX01TKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGVycm9yOiBhYm9ydENvbnRyb2xsZXIuc2lnbmFsLmFib3J0ZWRcbiAgICAgICAgPyBcImludGVycnVwdGVkXCJcbiAgICAgICAgOiBcIkFwcHJvdmFsIHRpbWVkIG91dFwiLFxuICAgIH07XG4gIH07XG5cbiAgY29uc3Qgc2tpbGxzUmVmOiB7IGN1cnJlbnQ6IFNraWxsU3VtbWFyeVtdIH0gPSB7XG4gICAgY3VycmVudDogZGlzY292ZXJlZFNraWxscyA/PyBbXSxcbiAgfTtcblxuICBjb25zdCByYXdUb29scyA9IGdldFRvb2xzKHtcbiAgICBpbnB1dCxcbiAgICBldmVudCxcbiAgICBzYW5kYm94LFxuICAgIHNlc3Npb24sXG4gICAgc2FuZGJveFJlY29yZDogc2FuZGJveFJlY29yZCBhcyBTYW5kYm94UmVjb3JkLFxuICAgIHNraWxsc1JlZixcbiAgICBhcGlUb29sc01ldGFkYXRhLFxuICAgIG9uU3ViVG9vbENhbGwsXG4gIH0pO1xuXG4gIGlmICghc2Vzc2lvbi5tb2RlbCkge1xuICAgIHRocm93IG5ldyBGYXRhbEVycm9yKFwiU2Vzc2lvbiBtb2RlbCBpcyBub3Qgc2V0XCIpO1xuICB9XG5cbiAgY29uc3QgYWxsUGFydHMgPSBwYXJ0c1Jlc3VsdC5pdGVtcztcbiAgY29uc3QgdXNhZ2VTdGVwczogU3RlcFVzYWdlW10gPSBbXTtcbiAgbGV0IGludGVybmFsU3RlcEluZGV4ID0gMDtcblxuICBjb25zdCB0b29scyA9IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICBPYmplY3QuZW50cmllcyhyYXdUb29scykubWFwKChbbmFtZSwgdF0pID0+IHtcbiAgICAgIGNvbnN0IG9yaWdpbmFsRXhlY3V0ZSA9IHQuZXhlY3V0ZTtcbiAgICAgIGNvbnN0IHdyYXBwZWRFeGVjdXRlID0gb3JpZ2luYWxFeGVjdXRlXG4gICAgICAgID8gYXN5bmMgKC4uLmFyZ3M6IFBhcmFtZXRlcnM8dHlwZW9mIG9yaWdpbmFsRXhlY3V0ZT4pID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGRvbmUgPSBzdGVwTG9nLnRpbWUoYHRvb2w6JHtuYW1lfWApO1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgb3JpZ2luYWxFeGVjdXRlKC4uLmFyZ3MpO1xuICAgICAgICAgICAgICBkb25lKCk7XG4gICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgIGRvbmUoeyBlcnJvcjogZSBpbnN0YW5jZW9mIEVycm9yID8gZS5tZXNzYWdlIDogU3RyaW5nKGUpIH0pO1xuICAgICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgOiB1bmRlZmluZWQ7XG4gICAgICByZXR1cm4gW1xuICAgICAgICBuYW1lLFxuICAgICAgICB7XG4gICAgICAgICAgLi4udCxcbiAgICAgICAgICAuLi4od3JhcHBlZEV4ZWN1dGUgPyB7IGV4ZWN1dGU6IHdyYXBwZWRFeGVjdXRlIH0gOiB7fSksXG4gICAgICAgICAgbmVlZHNBcHByb3ZhbDogYXN5bmMgKFxuICAgICAgICAgICAgdG9vbElucHV0OiB1bmtub3duLFxuICAgICAgICAgICAgb3B0czogeyB0b29sQ2FsbElkOiBzdHJpbmc7IG1lc3NhZ2VzOiB1bmtub3duW10gfVxuICAgICAgICAgICkgPT4ge1xuICAgICAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgcnBjKHtcbiAgICAgICAgICAgICAgbWV0aG9kOiBcInRvb2xzLm5lZWRzQXBwcm92YWxcIixcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XG4gICAgICAgICAgICAgICAgdG9vbE5hbWU6IG5hbWUsXG4gICAgICAgICAgICAgICAgaW5wdXQ6IHRvb2xJbnB1dCxcbiAgICAgICAgICAgICAgICB0b29sQ2FsbElkOiBvcHRzLnRvb2xDYWxsSWQsXG4gICAgICAgICAgICAgICAgbWVzc2FnZXM6IG9wdHMubWVzc2FnZXMsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGlmIChcImVycm9yXCIgaW4gcmVzKSB7XG4gICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgICBgdG9vbHMubmVlZHNBcHByb3ZhbCBSUEMgZmFpbGVkIGZvciAke25hbWV9OiAke3Jlcy5lcnJvci5tZXNzYWdlfWBcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZXMucmVzdWx0IGFzIGJvb2xlYW47XG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIF07XG4gICAgfSlcbiAgKTtcblxuICBjb25zdCByZXN1bHQgPSBzdHJlYW1UZXh0KHtcbiAgICAvLyBQbGFjZWhvbGRlciB0byBwYXNzIHZhbGlkYXRpb24gXHUyMDE0IHByZXBhcmVTdGVwIHJlcGxhY2VzIG1lc3NhZ2VzIGVudGlyZWx5LlxuICAgIG1lc3NhZ2VzOiBbeyByb2xlOiBcInVzZXJcIiBhcyBjb25zdCwgY29udGVudDogXCIuXCIgfV0sXG4gICAgdG9vbHMsXG4gICAgbW9kZWw6IHNlc3Npb24ubW9kZWwsXG4gICAgYWJvcnRTaWduYWw6IGFib3J0Q29udHJvbGxlci5zaWduYWwsXG4gICAgc3RvcFdoZW46IHN0ZXBDb3VudElzKDEpLFxuICAgIHRlbXBlcmF0dXJlOiBzZXNzaW9uLmdlbmVyYXRpb24/LnRlbXBlcmF0dXJlLFxuICAgIHRvcEs6IHNlc3Npb24uZ2VuZXJhdGlvbj8udG9wSyxcbiAgICB0b3BQOiBzZXNzaW9uLmdlbmVyYXRpb24/LnRvcFAsXG4gICAgZnJlcXVlbmN5UGVuYWx0eTogc2Vzc2lvbi5nZW5lcmF0aW9uPy5mcmVxdWVuY3lQZW5hbHR5LFxuICAgIHByZXNlbmNlUGVuYWx0eTogc2Vzc2lvbi5nZW5lcmF0aW9uPy5wcmVzZW5jZVBlbmFsdHksXG4gICAgbWF4T3V0cHV0VG9rZW5zOiBzZXNzaW9uLmdlbmVyYXRpb24/Lm1heE91dHB1dFRva2VucyxcbiAgICBoZWFkZXJzOiBzZXNzaW9uLmdlbmVyYXRpb24/LmhlYWRlcnMsXG4gICAgZXhwZXJpbWVudGFsX2NvbnRleHQ6IHtcbiAgICAgIHNlc3Npb24sXG4gICAgICBzYW5kYm94LFxuICAgICAgc3RvcmFnZSxcbiAgICAgIGNvbnRleHQ6IGV2ZW50LmNvbnRleHQsXG4gICAgfSxcbiAgICBwcmVwYXJlU3RlcDogYXN5bmMgKHsgbW9kZWwgfSkgPT4ge1xuICAgICAgaWYgKGxhc3RQYXJ0SW5kZXggPT09IDApIHtcbiAgICAgICAgLy8gT25seSBzaG93IHNhbmRib3ggc3RhdHVzIG9uIHRoZSBmaXJzdCBhc3Npc3RhbnQgbWVzc2FnZS5cbiAgICAgICAgLy8gSWYgYW5vdGhlciBhc3Npc3RhbnQgbWVzc2FnZSBoYXMgYWxyZWFkeSBzdGFydGVkLCB0aGUgc2FuZGJveFxuICAgICAgICAvLyBpcyB3YXJtIGFuZCBkb2Vzbid0IG5lZWQgYW4gaW5kaWNhdG9yLlxuICAgICAgICBjb25zdCBpc0ZpcnN0QXNzaXN0YW50TWVzc2FnZSA9ICFtZXNzYWdlc1Jlc3VsdC5pdGVtcy5zb21lKFxuICAgICAgICAgIChtKSA9PlxuICAgICAgICAgICAgbS5yb2xlID09PSBcImFzc2lzdGFudFwiICYmXG4gICAgICAgICAgICBtLmlkICE9PSBhc3Npc3RhbnRNZXNzYWdlSWQgJiZcbiAgICAgICAgICAgIG0uc3RhcnRlZEF0ICE9PSBudWxsXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IG9uUmVhZHkgPSBzYW5kYm94Ll9vblJlYWR5O1xuICAgICAgICBpZiAoaXNGaXJzdEFzc2lzdGFudE1lc3NhZ2UgJiYgb25SZWFkeSkge1xuICAgICAgICAgIHRocm90dGxlZEVtaXRTdGF0dXMoe1xuICAgICAgICAgICAgd3JpdGVyOiBzdHJlYW1Xcml0ZXJSZWYuY3VycmVudCxcbiAgICAgICAgICAgIHN0YXR1czogeyB0eXBlOiBcInNhbmRib3gtc2V0dXBcIiB9LFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFkaXNjb3ZlcmVkU2tpbGxzKSB7XG4gICAgICAgICAgY29uc3Qgc2tpbGxzRGlycyA9IHNlc3Npb24uc2tpbGxzRGlyPy5sZW5ndGggPyBzZXNzaW9uLnNraWxsc0RpciA6IFtdO1xuICAgICAgICAgIGlmIChza2lsbHNEaXJzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGNvbnN0IGRvbmVTa2lsbHMgPSBzdGVwTG9nLnRpbWUoXCJkaXNjb3ZlciBza2lsbHNcIiwgeyBza2lsbHNEaXJzIH0pO1xuICAgICAgICAgICAgc2tpbGxzUmVmLmN1cnJlbnQgPSBhd2FpdCBkaXNjb3ZlclNraWxsc0luU2FuZGJveCh7XG4gICAgICAgICAgICAgIHNhbmRib3gsXG4gICAgICAgICAgICAgIHNraWxsc0RpcnMsXG4gICAgICAgICAgICAgIHNlc3Npb25JZDogaW5wdXQuc2Vzc2lvbklkLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBkb25lU2tpbGxzKHsgY291bnQ6IHNraWxsc1JlZi5jdXJyZW50Lmxlbmd0aCB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gRXhlY3V0ZSBhcHByb3ZlZCB0b29scyBzbyB0aGUgbW9kZWwgc2VlcyBjb21wbGV0ZSB0b29sIGNhbGwgKyByZXN1bHRcbiAgICAgIC8vIHBhaXJzLiBUaGlzIHJ1bnMgb3V0c2lkZSB0aGUgbGFzdFBhcnRJbmRleCA9PT0gMCBnYXRlIGJlY2F1c2VcbiAgICAgIC8vIGFwcHJvdmFscyBhcnJpdmUgb24gc3Vic2VxdWVudCBtZXNzYWdlcyAobGFzdFBhcnRJbmRleCA+IDApLlxuICAgICAgY29uc3QgYXBwcm92ZWRQYXJ0cyA9IGFsbFBhcnRzLmZpbHRlcihcbiAgICAgICAgKHApID0+XG4gICAgICAgICAgcC5wYXJ0ICYmXG4gICAgICAgICAgXCJzdGF0ZVwiIGluIHAucGFydCAmJlxuICAgICAgICAgIChwLnBhcnQgYXMgeyBzdGF0ZTogc3RyaW5nIH0pLnN0YXRlID09PSBcImFwcHJvdmFsLXJlc3BvbmRlZFwiICYmXG4gICAgICAgICAgXCJhcHByb3ZhbFwiIGluIHAucGFydCAmJlxuICAgICAgICAgIChwLnBhcnQgYXMgeyBhcHByb3ZhbD86IHsgYXBwcm92ZWQ6IGJvb2xlYW4gfSB9KS5hcHByb3ZhbFxuICAgICAgICAgICAgPy5hcHByb3ZlZCA9PT0gdHJ1ZVxuICAgICAgKTtcblxuICAgICAgaWYgKGFwcHJvdmVkUGFydHMubGVuZ3RoID4gMCkge1xuICAgICAgICBzdGVwTG9nLmluZm8oXCJleGVjdXRpbmcgYXBwcm92ZWQgdG9vbHNcIiwge1xuICAgICAgICAgIGNvdW50OiBhcHByb3ZlZFBhcnRzLmxlbmd0aCxcbiAgICAgICAgfSk7XG4gICAgICAgIHRocm90dGxlZEVtaXRTdGF0dXMoe1xuICAgICAgICAgIHdyaXRlcjogc3RyZWFtV3JpdGVyUmVmLmN1cnJlbnQsXG4gICAgICAgICAgc3RhdHVzOiB7IHR5cGU6IFwicHJvY2Vzc2luZy1hcHByb3ZhbHNcIiB9LFxuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCBwcmVFeGVjTWVzc2FnZXMgPSBhd2FpdCBjb252ZXJ0VG9Nb2RlbE1lc3NhZ2VzKFxuICAgICAgICAgIGFzc2VtYmxlVUlNZXNzYWdlcyh7XG4gICAgICAgICAgICBtZXNzYWdlczogbWVzc2FnZXNSZXN1bHQuaXRlbXMsXG4gICAgICAgICAgICBwYXJ0czogYWxsUGFydHMsXG4gICAgICAgICAgICB1bnRpbDogZXZlbnQuY3JlYXRlZEF0LFxuICAgICAgICAgICAgaW5jbHVkZVF1ZXVlZDogdHJ1ZSxcbiAgICAgICAgICAgIGV4Y2x1ZGVTdWJUb29sUGFydHM6IHRydWUsXG4gICAgICAgICAgfSksXG4gICAgICAgICAgeyBpZ25vcmVJbmNvbXBsZXRlVG9vbENhbGxzOiB0cnVlIH1cbiAgICAgICAgKTtcblxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgICBhcHByb3ZlZFBhcnRzLm1hcChhc3luYyAoYXApID0+IHtcbiAgICAgICAgICAgIGlmICghYXAucGFydC50eXBlLnN0YXJ0c1dpdGgoXCJ0b29sLVwiKSkge1xuICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBwYXJ0ID0gYXAucGFydCBhcyBFeHRyYWN0PFxuICAgICAgICAgICAgICBVSU1lc3NhZ2VbXCJwYXJ0c1wiXVtudW1iZXJdLFxuICAgICAgICAgICAgICB7IHR5cGU6IGB0b29sLSR7c3RyaW5nfWAgfVxuICAgICAgICAgICAgPjtcbiAgICAgICAgICAgIGNvbnN0IHRvb2xOYW1lID0gcGFydC50eXBlLnJlcGxhY2UoXCJ0b29sLVwiLCBcIlwiKTtcbiAgICAgICAgICAgIGNvbnN0IHRvb2xEZWYgPSByYXdUb29sc1t0b29sTmFtZV07XG5cbiAgICAgICAgICAgIGlmICh0b29sRGVmPy5leGVjdXRlICYmIHBhcnQuaW5wdXQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHRvb2xPdXRwdXQgPSBhd2FpdCB0b29sRGVmLmV4ZWN1dGUocGFydC5pbnB1dCwge1xuICAgICAgICAgICAgICAgICAgdG9vbENhbGxJZDogcGFydC50b29sQ2FsbElkLFxuICAgICAgICAgICAgICAgICAgbWVzc2FnZXM6IHByZUV4ZWNNZXNzYWdlcyxcbiAgICAgICAgICAgICAgICAgIGFib3J0U2lnbmFsOiBhYm9ydENvbnRyb2xsZXIuc2lnbmFsLFxuICAgICAgICAgICAgICAgICAgZXhwZXJpbWVudGFsX2NvbnRleHQ6IHtcbiAgICAgICAgICAgICAgICAgICAgc2Vzc2lvbixcbiAgICAgICAgICAgICAgICAgICAgc2FuZGJveCxcbiAgICAgICAgICAgICAgICAgICAgc3RvcmFnZSxcbiAgICAgICAgICAgICAgICAgICAgY29udGV4dDogZXZlbnQuY29udGV4dCxcbiAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcGFydC5zdGF0ZSA9IFwib3V0cHV0LWF2YWlsYWJsZVwiO1xuICAgICAgICAgICAgICAgIHBhcnQub3V0cHV0ID0gdG9vbE91dHB1dDtcbiAgICAgICAgICAgICAgICBzdHJlYW1Xcml0ZXJSZWYuY3VycmVudD8uKHtcbiAgICAgICAgICAgICAgICAgIHR5cGU6IFwidG9vbC1vdXRwdXQtYXZhaWxhYmxlXCIsXG4gICAgICAgICAgICAgICAgICB0b29sQ2FsbElkOiBwYXJ0LnRvb2xDYWxsSWQsXG4gICAgICAgICAgICAgICAgICBvdXRwdXQ6IHRvb2xPdXRwdXQsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgIHBhcnQuc3RhdGUgPSBcIm91dHB1dC1lcnJvclwiO1xuICAgICAgICAgICAgICAgIHBhcnQuZXJyb3JUZXh0ID1cbiAgICAgICAgICAgICAgICAgIGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKTtcbiAgICAgICAgICAgICAgICBzdHJlYW1Xcml0ZXJSZWYuY3VycmVudD8uKHtcbiAgICAgICAgICAgICAgICAgIHR5cGU6IFwidG9vbC1vdXRwdXQtZXJyb3JcIixcbiAgICAgICAgICAgICAgICAgIHRvb2xDYWxsSWQ6IHBhcnQudG9vbENhbGxJZCxcbiAgICAgICAgICAgICAgICAgIGVycm9yVGV4dDogcGFydC5lcnJvclRleHQsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgYXdhaXQgc3RvcmFnZS5wYXJ0LnNldCh7IC4uLmFwLCBwYXJ0IH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIHRocm90dGxlZEVtaXRTdGF0dXMoe1xuICAgICAgICB3cml0ZXI6IHN0cmVhbVdyaXRlclJlZi5jdXJyZW50LFxuICAgICAgICBzdGF0dXM6IHsgdHlwZTogXCJ0aGlua2luZ1wiIH0sXG4gICAgICB9KTtcblxuICAgICAgY29uc3Qgc2tpbGxzQ29udGV4dCA9IGJ1aWxkU2tpbGxzQ29udGV4dChza2lsbHNSZWYuY3VycmVudCk7XG4gICAgICBjb25zdCBjd2RQcm9tcHQgPSBgWW91ciB3b3JraW5nIGRpcmVjdG9yeSBpcyAke3NhbmRib3guY3dkfS4gQWxsIGZpbGUgcGF0aHMgc2hvdWxkIGJlIGFic29sdXRlLmA7XG4gICAgICBjb25zdCBzeXN0ZW1IZWFkZXIgPSBqb2luUHJvbXB0U2VjdGlvbnMoXG4gICAgICAgIEJBU0VfU1lTVEVNX1BST01QVCxcbiAgICAgICAgY3dkUHJvbXB0LFxuICAgICAgICBzZXNzaW9uLnN5c3RlbVxuICAgICAgKTtcbiAgICAgIGNvbnN0IHN5c3RlbUNvbnRleHQgPSBqb2luUHJvbXB0U2VjdGlvbnMoc2tpbGxzQ29udGV4dCk7XG4gICAgICBjb25zdCBzeXN0ZW1NZXNzYWdlcyA9IFtcbiAgICAgICAgLi4uKHN5c3RlbUhlYWRlci50cmltKClcbiAgICAgICAgICA/IFt7IHJvbGU6IFwic3lzdGVtXCIgYXMgY29uc3QsIGNvbnRlbnQ6IHN5c3RlbUhlYWRlciB9XVxuICAgICAgICAgIDogW10pLFxuICAgICAgICAuLi4oc3lzdGVtQ29udGV4dC50cmltKClcbiAgICAgICAgICA/IFt7IHJvbGU6IFwic3lzdGVtXCIgYXMgY29uc3QsIGNvbnRlbnQ6IHN5c3RlbUNvbnRleHQgfV1cbiAgICAgICAgICA6IFtdKSxcbiAgICAgIF07XG5cbiAgICAgIGNvbnN0IHVpTWVzc2FnZXMgPSBhc3NlbWJsZVVJTWVzc2FnZXMoe1xuICAgICAgICBtZXNzYWdlczogbWVzc2FnZXNSZXN1bHQuaXRlbXMsXG4gICAgICAgIHBhcnRzOiBhbGxQYXJ0cyxcbiAgICAgICAgdW50aWw6IGV2ZW50LmNyZWF0ZWRBdCxcbiAgICAgICAgaW5jbHVkZVF1ZXVlZDogdHJ1ZSxcbiAgICAgICAgZXhjbHVkZVN1YlRvb2xQYXJ0czogdHJ1ZSxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBtb2RlbE1lc3NhZ2VzID0gW1xuICAgICAgICAuLi5zeXN0ZW1NZXNzYWdlcyxcbiAgICAgICAgLi4uKGF3YWl0IGNvbnZlcnRUb01vZGVsTWVzc2FnZXModWlNZXNzYWdlcywge1xuICAgICAgICAgIGlnbm9yZUluY29tcGxldGVUb29sQ2FsbHM6IHRydWUsXG4gICAgICAgIH0pKSxcbiAgICAgIF07XG5cbiAgICAgIGNvbnN0IHByb21wdENhY2hpbmcgPSBhcHBseVByb21wdENhY2hpbmdUb01vZGVsUmVxdWVzdCh7XG4gICAgICAgIG1vZGVsOiB0eXBlb2YgbW9kZWwgPT09IFwic3RyaW5nXCIgPyBtb2RlbCA6IG1vZGVsLm1vZGVsSWQsXG4gICAgICAgIHNlc3Npb25JZDogaW5wdXQuc2Vzc2lvbklkLFxuICAgICAgICBtZXNzYWdlczogbW9kZWxNZXNzYWdlcyxcbiAgICAgIH0pO1xuXG4gICAgICBsZXQgYWN0aXZlVG9vbHMgPSBzZXNzaW9uLmFjdGl2ZVRvb2xzID8/IHVuZGVmaW5lZDtcbiAgICAgIGlmIChza2lsbHNSZWYuY3VycmVudC5sZW5ndGggPT09IDAgJiYgYWN0aXZlVG9vbHMpIHtcbiAgICAgICAgYWN0aXZlVG9vbHMgPSBhY3RpdmVUb29scy5maWx0ZXIoXG4gICAgICAgICAgKHQpID0+IHQgIT09IChcIlNraWxsXCIgc2F0aXNmaWVzIEJ1aWx0SW5Ub29sTmFtZSlcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbWVzc2FnZXM6IHByb21wdENhY2hpbmcubWVzc2FnZXMsXG4gICAgICAgIHByb3ZpZGVyT3B0aW9uczogcHJvbXB0Q2FjaGluZy5wcm92aWRlck9wdGlvbnMsXG4gICAgICAgIGFjdGl2ZVRvb2xzLFxuICAgICAgfTtcbiAgICB9LFxuICAgIG9uU3RlcEZpbmlzaDogKHsgdXNhZ2UgfSkgPT4ge1xuICAgICAgaWYgKHVzYWdlKSB7XG4gICAgICAgIHVzYWdlU3RlcHMucHVzaCh7XG4gICAgICAgICAgc3RlcEluZGV4OiBzdGVwSW5kZXhPZmZzZXQgKyBpbnRlcm5hbFN0ZXBJbmRleCxcbiAgICAgICAgICBtb2RlbDogc2Vzc2lvbi5tb2RlbCA/PyBcInVua25vd25cIixcbiAgICAgICAgICBpbnB1dFRva2VuczogdXNhZ2UuaW5wdXRUb2tlbnMgPz8gMCxcbiAgICAgICAgICBvdXRwdXRUb2tlbnM6IHVzYWdlLm91dHB1dFRva2VucyA/PyAwLFxuICAgICAgICAgIHRvdGFsVG9rZW5zOiB1c2FnZS50b3RhbFRva2VucyA/PyAwLFxuICAgICAgICAgIGNhY2hlUmVhZFRva2VuczogdXNhZ2UuaW5wdXRUb2tlbkRldGFpbHM/LmNhY2hlUmVhZFRva2VucyA/PyAwLFxuICAgICAgICAgIGNhY2hlV3JpdGVUb2tlbnM6IHVzYWdlLmlucHV0VG9rZW5EZXRhaWxzPy5jYWNoZVdyaXRlVG9rZW5zID8/IDAsXG4gICAgICAgICAgcmVhc29uaW5nVG9rZW5zOiB1c2FnZS5vdXRwdXRUb2tlbkRldGFpbHM/LnJlYXNvbmluZ1Rva2VucyA/PyAwLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIGludGVybmFsU3RlcEluZGV4Kys7XG4gICAgfSxcbiAgfSk7XG5cbiAgY29uc3Qgc3RlcFBhcnRzOiBVSU1lc3NhZ2VbXCJwYXJ0c1wiXSA9IFtdO1xuICBsZXQgd2FzQWJvcnRlZCA9IGZhbHNlO1xuXG4gIHRyeSB7XG4gICAgY29uc3Qgc3RyZWFtID0gY3JlYXRlVUlNZXNzYWdlU3RyZWFtKHtcbiAgICAgIGV4ZWN1dGU6ICh7IHdyaXRlciB9KSA9PiB7XG4gICAgICAgIHN0cmVhbVdyaXRlclJlZi5jdXJyZW50ID0gKGV2ZW50OiB1bmtub3duKSA9PlxuICAgICAgICAgIHdyaXRlci53cml0ZShldmVudCBhcyBQYXJhbWV0ZXJzPHR5cGVvZiB3cml0ZXIud3JpdGU+WzBdKTtcblxuICAgICAgICAvLyBNZXJnZSB0aGUgc3RyZWFtVGV4dCBzdHJlYW0uIHByZXBhcmVTdGVwIGhhbmRsZXMgc2FuZGJveCBzZXR1cCxcbiAgICAgICAgLy8gc2tpbGxzIGxvYWRpbmcsIGFwcHJvdmFsIGV4ZWN1dGlvbiwgYW5kIHN0YXR1cyBlbWlzc2lvbiBiZWZvcmVcbiAgICAgICAgLy8gdGhlIG1vZGVsIHN0YXJ0cyBnZW5lcmF0aW5nLlxuICAgICAgICB3cml0ZXIubWVyZ2UoXG4gICAgICAgICAgcmVzdWx0LnRvVUlNZXNzYWdlU3RyZWFtKHtcbiAgICAgICAgICAgIGdlbmVyYXRlTWVzc2FnZUlkOiAoKSA9PiBhc3Npc3RhbnRNZXNzYWdlSWQsXG4gICAgICAgICAgICBvbkZpbmlzaDogKHsgbWVzc2FnZXMgfSkgPT4ge1xuICAgICAgICAgICAgICBsZXQgaGFzQXBwcm92YWxzID0gZmFsc2U7XG4gICAgICAgICAgICAgIGZvciAoY29uc3QgbSBvZiBtZXNzYWdlcykge1xuICAgICAgICAgICAgICAgIGlmIChtLnJvbGUgPT09IFwiYXNzaXN0YW50XCIpIHtcbiAgICAgICAgICAgICAgICAgIHN0ZXBQYXJ0cy5wdXNoKC4uLm0ucGFydHMpO1xuICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCBwIG9mIG0ucGFydHMpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKFwic3RhdGVcIiBpbiBwICYmIHAuc3RhdGUgPT09IFwiYXBwcm92YWwtcmVxdWVzdGVkXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICBoYXNBcHByb3ZhbHMgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGlmIChoYXNBcHByb3ZhbHMpIHtcbiAgICAgICAgICAgICAgICB0aHJvdHRsZWRFbWl0U3RhdHVzKHtcbiAgICAgICAgICAgICAgICAgIHdyaXRlcjogc3RyZWFtV3JpdGVyUmVmLmN1cnJlbnQsXG4gICAgICAgICAgICAgICAgICBzdGF0dXM6IHsgdHlwZTogXCJuZWVkcy1hcHByb3ZhbFwiIH0sXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSlcbiAgICAgICAgKTtcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBhd2FpdCBzdHJlYW0ucGlwZVRvKHdyaXRhYmxlLCB7XG4gICAgICBwcmV2ZW50Q2xvc2U6IHRydWUsXG4gICAgICBwcmV2ZW50QWJvcnQ6IHRydWUsXG4gICAgfSk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGlmIChhYm9ydENvbnRyb2xsZXIuc2lnbmFsLmFib3J0ZWQpIHtcbiAgICAgIHdhc0Fib3J0ZWQgPSB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuICB9IGZpbmFsbHkge1xuICAgIHBvbGxDb250cm9sbGVyLmFib3J0KCk7XG4gICAgdGhyb3R0bGVkRW1pdFN0YXR1cy5kaXNwb3NlKCk7XG4gIH1cblxuICBpZiAoYWJvcnRDb250cm9sbGVyLnNpZ25hbC5hYm9ydGVkKSB7XG4gICAgd2FzQWJvcnRlZCA9IHRydWU7XG4gIH1cblxuICBjb25zdCBsYXN0UGFydCA9IGludGVycnVwdGVkTGFzdFBhcnRSZWYuY3VycmVudDtcblxuICBpZiAod2FzQWJvcnRlZCkge1xuICAgIGNvbnN0IHRlcm1pbmFsU3RhdGVzID0gbmV3IFNldChbXG4gICAgICBcIm91dHB1dC1hdmFpbGFibGVcIixcbiAgICAgIFwib3V0cHV0LWVycm9yXCIsXG4gICAgICBcIm91dHB1dC1kZW5pZWRcIixcbiAgICAgIFwiZG9uZVwiLFxuICAgIF0pO1xuICAgIGZvciAoY29uc3QgcGFydCBvZiBzdGVwUGFydHMpIHtcbiAgICAgIGlmIChcbiAgICAgICAgXCJ0eXBlXCIgaW4gcGFydCAmJlxuICAgICAgICB0eXBlb2YgcGFydC50eXBlID09PSBcInN0cmluZ1wiICYmXG4gICAgICAgIHBhcnQudHlwZS5zdGFydHNXaXRoKFwidG9vbC1cIikgJiZcbiAgICAgICAgXCJzdGF0ZVwiIGluIHBhcnQgJiZcbiAgICAgICAgIXRlcm1pbmFsU3RhdGVzLmhhcyhwYXJ0LnN0YXRlIGFzIHN0cmluZylcbiAgICAgICkge1xuICAgICAgICAocGFydCBhcyB7IHN0YXRlOiBzdHJpbmcgfSkuc3RhdGUgPSBcIm91dHB1dC1lcnJvclwiO1xuICAgICAgICAocGFydCBhcyB7IGVycm9yVGV4dD86IHN0cmluZyB9KS5lcnJvclRleHQgPSBcImludGVycnVwdGVkXCI7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgdHJ5IHtcbiAgICBjb25zdCBiYXNlUGFydEluZGV4ID0gbmV4dFBhcnRJbmRleDtcbiAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIHN0ZXBQYXJ0cy5tYXAoYXN5bmMgKHVpUGFydCwgaSkgPT4ge1xuICAgICAgICBjb25zdCBpbmRleCA9IGJhc2VQYXJ0SW5kZXggKyBpO1xuICAgICAgICBpZiAobGFzdFBhcnQgIT0gbnVsbCAmJiBpbmRleCA+IGxhc3RQYXJ0LmluZGV4KSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHVzZUNsaWVudFBhcnQgPSBsYXN0UGFydCAhPSBudWxsICYmIGluZGV4ID09PSBsYXN0UGFydC5pbmRleDtcbiAgICAgICAgY29uc3QgY29udGVudCA9IHVzZUNsaWVudFBhcnQgPyBsYXN0UGFydC5wYXJ0IDogdWlQYXJ0O1xuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBzdG9yYWdlLnBhcnQuc2V0KHtcbiAgICAgICAgICBpZDogYHBhcnRfJHt1bGlkKCl9YCxcbiAgICAgICAgICBpbmRleCxcbiAgICAgICAgICBtZXNzYWdlSWQ6IGFzc2lzdGFudE1lc3NhZ2VJZCxcbiAgICAgICAgICBzZXNzaW9uSWQ6IGlucHV0LnNlc3Npb25JZCxcbiAgICAgICAgICBwYXJ0OiBjb250ZW50IGFzICh0eXBlb2Ygc3RlcFBhcnRzKVtudW1iZXJdLFxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICAgICAgdGhyb3cgcmVzdWx0O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICB9KVxuICAgICk7XG4gICAgbmV4dFBhcnRJbmRleCA9XG4gICAgICBsYXN0UGFydCAhPSBudWxsXG4gICAgICAgID8gTWF0aC5taW4oYmFzZVBhcnRJbmRleCArIHN0ZXBQYXJ0cy5sZW5ndGgsIGxhc3RQYXJ0LmluZGV4ICsgMSlcbiAgICAgICAgOiBiYXNlUGFydEluZGV4ICsgc3RlcFBhcnRzLmxlbmd0aDtcblxuICAgIGlmIChzZXRTdGFydGVkUHJvbWlzZSkge1xuICAgICAgY29uc3Qgc2V0U3RhcnRlZFJlc3VsdCA9IGF3YWl0IHNldFN0YXJ0ZWRQcm9taXNlO1xuICAgICAgaWYgKHNldFN0YXJ0ZWRSZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICB0aHJvdyBzZXRTdGFydGVkUmVzdWx0O1xuICAgICAgfVxuICAgICAgZm9yIChjb25zdCBtIG9mIHNldFN0YXJ0ZWRSZXN1bHQgPz8gW10pIHtcbiAgICAgICAgaWYgKG0gaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICAgIHRocm93IG07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGlmIChhYm9ydENvbnRyb2xsZXIuc2lnbmFsLmFib3J0ZWQpIHtcbiAgICAgIHdhc0Fib3J0ZWQgPSB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuICB9XG5cbiAgY29uc3QgcGVuZGluZ0FwcHJvdmFscyA9IHN0ZXBQYXJ0c1xuICAgIC5maWx0ZXIoXG4gICAgICAocCk6IHAgaXMgdHlwZW9mIHAgJiB7IGFwcHJvdmFsOiB7IGlkOiBzdHJpbmcgfSB9ID0+XG4gICAgICAgIFwic3RhdGVcIiBpbiBwICYmXG4gICAgICAgIHAuc3RhdGUgPT09IFwiYXBwcm92YWwtcmVxdWVzdGVkXCIgJiZcbiAgICAgICAgXCJhcHByb3ZhbFwiIGluIHAgJiZcbiAgICAgICAgISEocCBhcyB7IGFwcHJvdmFsPzogeyBpZDogc3RyaW5nIH0gfSkuYXBwcm92YWw/LmlkXG4gICAgKVxuICAgIC5tYXAoKHApID0+ICh7XG4gICAgICBhcHByb3ZhbElkOiBwLmFwcHJvdmFsLmlkLFxuICAgICAgdG9vbE5hbWU6IFwidHlwZVwiIGluIHAgPyBTdHJpbmcocC50eXBlKS5yZXBsYWNlKFwidG9vbC1cIiwgXCJcIikgOiBcInVua25vd25cIixcbiAgICB9KSk7XG5cbiAgY29uc3QgZmluYWxGaW5pc2hSZWFzb246IEZpbmlzaFJlYXNvbiA9XG4gICAgd2FzQWJvcnRlZCB8fCBsYXN0UGFydCAhPSBudWxsXG4gICAgICA/IChcInN0b3BcIiBhcyBGaW5pc2hSZWFzb24pXG4gICAgICA6IGF3YWl0IHJlc3VsdC5maW5pc2hSZWFzb247XG5cbiAgZG9uZVN0ZXAoe1xuICAgIGZpbmlzaFJlYXNvbjogZmluYWxGaW5pc2hSZWFzb24sXG4gICAgd2FzQWJvcnRlZCxcbiAgICBwYXJ0c0NvdW50OiBzdGVwUGFydHMubGVuZ3RoLFxuICAgIHBlbmRpbmdBcHByb3ZhbHM6IHBlbmRpbmdBcHByb3ZhbHMubGVuZ3RoLFxuICB9KTtcblxuICByZXR1cm4ge1xuICAgIGZpbmlzaFJlYXNvbjogZmluYWxGaW5pc2hSZWFzb24sXG4gICAgbGFzdFBhcnRJbmRleDogbmV4dFBhcnRJbmRleCxcbiAgICB1c2FnZVN0ZXBzLFxuICAgIHBlbmRpbmdBcHByb3ZhbHMsXG4gICAgbWF4U3RlcHM6IHNlc3Npb24uZ2VuZXJhdGlvbj8ubWF4U3RlcHMsXG4gICAgZGlzY292ZXJlZFNraWxsczogc2tpbGxzUmVmLmN1cnJlbnQsXG4gIH07XG59XG4iLCAiaW1wb3J0IHR5cGUgeyBTa2lsbHNEaXIgfSBmcm9tIFwiLi90eXBlc1wiO1xuXG4vKipcbiAqIFBhcnNlZCBmcm9udG1hdHRlciBmcm9tIGEgU0tJTEwubWQgZmlsZS5cbiAqL1xuZXhwb3J0IHR5cGUgU2tpbGxGcm9udG1hdHRlciA9IHtcbiAgbmFtZTogc3RyaW5nO1xuICBkZXNjcmlwdGlvbjogc3RyaW5nO1xufTtcblxuLyoqXG4gKiBQYXJzZXMgWUFNTCBmcm9udG1hdHRlciBmcm9tIGEgU0tJTEwubWQgZmlsZSBjb250ZW50LlxuICogRnJvbnRtYXR0ZXIgbXVzdCBiZSBhdCB0aGUgc3RhcnQgb2YgdGhlIGZpbGUsIGRlbGltaXRlZCBieSBgLS0tYCBtYXJrZXJzLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGBtYXJrZG93blxuICogLS0tXG4gKiBuYW1lOiBjc3ZcbiAqIGRlc2NyaXB0aW9uOiBBbmFseXplIENTViBkYXRhXG4gKiAtLS1cbiAqICMgQ1NWIFNraWxsXG4gKiAuLi5cbiAqIGBgYFxuICpcbiAqIEByZXR1cm5zIFBhcnNlZCBuYW1lIGFuZCBkZXNjcmlwdGlvbiwgb3IgbnVsbCBpZiBmcm9udG1hdHRlciBpcyBtaXNzaW5nL2ludmFsaWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlU2tpbGxGcm9udG1hdHRlcihcbiAgY29udGVudDogc3RyaW5nXG4pOiBTa2lsbEZyb250bWF0dGVyIHwgbnVsbCB7XG4gIGNvbnN0IHRyaW1tZWQgPSBjb250ZW50LnRyaW0oKTtcblxuICBpZiAoIXRyaW1tZWQuc3RhcnRzV2l0aChcIi0tLVwiKSkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3QgZW5kTWFya2VySW5kZXggPSB0cmltbWVkLmluZGV4T2YoXCItLS1cIiwgMyk7XG4gIGlmIChlbmRNYXJrZXJJbmRleCA9PT0gLTEpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGNvbnN0IGZyb250bWF0dGVyQmxvY2sgPSB0cmltbWVkLnNsaWNlKDMsIGVuZE1hcmtlckluZGV4KS50cmltKCk7XG4gIGNvbnN0IHBhcnNlZCA9IHBhcnNlU2ltcGxlWWFtbChmcm9udG1hdHRlckJsb2NrKTtcblxuICBpZiAoIShwYXJzZWQubmFtZSAmJiBwYXJzZWQuZGVzY3JpcHRpb24pKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIG5hbWU6IFN0cmluZyhwYXJzZWQubmFtZSksXG4gICAgZGVzY3JpcHRpb246IFN0cmluZyhwYXJzZWQuZGVzY3JpcHRpb24pLFxuICB9O1xufVxuXG4vKipcbiAqIFBhcnNlcyBzaW1wbGUgWUFNTCBrZXktdmFsdWUgcGFpcnMgKHNpbmdsZS1saW5lIHZhbHVlcyBvbmx5KS5cbiAqIFRoaXMgYXZvaWRzIGFkZGluZyBhIGZ1bGwgWUFNTCBwYXJzZXIgZGVwZW5kZW5jeSBmb3IgYmFzaWMgZnJvbnRtYXR0ZXIuXG4gKi9cbmZ1bmN0aW9uIHBhcnNlU2ltcGxlWWFtbCh5YW1sOiBzdHJpbmcpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgY29uc3QgcmVzdWx0OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG5cbiAgZm9yIChjb25zdCBsaW5lIG9mIHlhbWwuc3BsaXQoXCJcXG5cIikpIHtcbiAgICBjb25zdCB0cmltbWVkTGluZSA9IGxpbmUudHJpbSgpO1xuICAgIGlmICghdHJpbW1lZExpbmUgfHwgdHJpbW1lZExpbmUuc3RhcnRzV2l0aChcIiNcIikpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGNvbnN0IGNvbG9uSW5kZXggPSB0cmltbWVkTGluZS5pbmRleE9mKFwiOlwiKTtcbiAgICBpZiAoY29sb25JbmRleCA9PT0gLTEpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGNvbnN0IGtleSA9IHRyaW1tZWRMaW5lLnNsaWNlKDAsIGNvbG9uSW5kZXgpLnRyaW0oKTtcbiAgICBsZXQgdmFsdWUgPSB0cmltbWVkTGluZS5zbGljZShjb2xvbkluZGV4ICsgMSkudHJpbSgpO1xuXG4gICAgLy8gUmVtb3ZlIHN1cnJvdW5kaW5nIHF1b3RlcyBpZiBwcmVzZW50XG4gICAgaWYgKFxuICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ1wiJykgJiYgdmFsdWUuZW5kc1dpdGgoJ1wiJykpIHx8XG4gICAgICAodmFsdWUuc3RhcnRzV2l0aChcIidcIikgJiYgdmFsdWUuZW5kc1dpdGgoXCInXCIpKVxuICAgICkge1xuICAgICAgdmFsdWUgPSB2YWx1ZS5zbGljZSgxLCAtMSk7XG4gICAgfVxuXG4gICAgaWYgKGtleSkge1xuICAgICAgcmVzdWx0W2tleV0gPSB2YWx1ZTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKipcbiAqIE5vcm1hbGl6ZXMgc2tpbGxzRGlyIHRvIGFuIGFycmF5IG9mIHN0cmluZ3MuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBub3JtYWxpemVTa2lsbHNEaXJzKHNraWxsc0Rpcj86IFNraWxsc0Rpcik6IHN0cmluZ1tdIHtcbiAgaWYgKCFza2lsbHNEaXIpIHtcbiAgICByZXR1cm4gW107XG4gIH1cbiAgcmV0dXJuIEFycmF5LmlzQXJyYXkoc2tpbGxzRGlyKSA/IHNraWxsc0RpciA6IFtza2lsbHNEaXJdO1xufVxuIiwgImltcG9ydCB0eXBlIHsgU2FuZGJveCB9IGZyb20gXCIuLi9zYW5kYm94XCI7XG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIsIHR5cGUgTG9nZ2VyIH0gZnJvbSBcIi4uL3V0aWxzL2xvZ2dlclwiO1xuaW1wb3J0IHsgcGFyc2VTa2lsbEZyb250bWF0dGVyIH0gZnJvbSBcIi4vcGFyc2VyXCI7XG5pbXBvcnQgdHlwZSB7IFNraWxsU3VtbWFyeSB9IGZyb20gXCIuL3R5cGVzXCI7XG5cbmNvbnN0IGJhc2VMb2cgPSBjcmVhdGVMb2dnZXIoeyBzdWJzeXN0ZW06IFwic2tpbGxzXCIgfSk7XG5cbi8qKlxuICogRGlzY292ZXJzIHNraWxscyBmcm9tIGRpcmVjdG9yaWVzIGluc2lkZSB0aGUgc2FuZGJveCBieSBmaW5kaW5nIGFuZCBwYXJzaW5nIFNLSUxMLm1kIGZpbGVzLlxuICogU2NhbnMgZWFjaCBkaXJlY3RvcnkgZm9yIHN1YmRpcmVjdG9yaWVzIGNvbnRhaW5pbmcgU0tJTEwubWQsIGV4dHJhY3RzIGZyb250bWF0dGVyIG1ldGFkYXRhLFxuICogYW5kIHJldHVybnMgc3VtbWFyaWVzIGZvciB1c2UgaW4gdGhlIHN5c3RlbSBwcm9tcHQuXG4gKlxuICogQHJldHVybnMgQXJyYXkgb2Ygc2tpbGwgc3VtbWFyaWVzIChkZWR1cGxpY2F0ZWQgYnkgbmFtZSwgZmlyc3Qgb2NjdXJyZW5jZSB3aW5zKVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZGlzY292ZXJTa2lsbHNJblNhbmRib3gob3B0czoge1xuICBzYW5kYm94OiBTYW5kYm94O1xuICBza2lsbHNEaXJzOiBzdHJpbmdbXTtcbiAgc2Vzc2lvbklkPzogc3RyaW5nO1xufSk6IFByb21pc2U8U2tpbGxTdW1tYXJ5W10+IHtcbiAgY29uc3QgeyBzYW5kYm94LCBza2lsbHNEaXJzLCBzZXNzaW9uSWQgfSA9IG9wdHM7XG4gIGNvbnN0IGxvZyA9IHNlc3Npb25JZCA/IGJhc2VMb2cud2l0aENvbnRleHQoeyBzZXNzaW9uSWQgfSkgOiBiYXNlTG9nO1xuICBjb25zdCBkb25lID0gbG9nLnRpbWUoXCJkaXNjb3ZlclNraWxsc0luU2FuZGJveFwiKTtcblxuICBjb25zdCBzdW1tYXJpZXM6IFNraWxsU3VtbWFyeVtdID0gW107XG4gIGNvbnN0IHNlZW5OYW1lcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4gIGZvciAoY29uc3Qgc2tpbGxzRGlyIG9mIHNraWxsc0RpcnMpIHtcbiAgICBjb25zdCBkaXJEb25lID0gbG9nLnRpbWUoXCJzY2FuIGRpcmVjdG9yeVwiLCB7IGRpcjogc2tpbGxzRGlyIH0pO1xuICAgIGNvbnN0IGRpclN1bW1hcmllcyA9IGF3YWl0IGRpc2NvdmVyU2tpbGxzSW5EaXJlY3Rvcnkoe1xuICAgICAgc2FuZGJveCxcbiAgICAgIHNraWxsc0RpcixcbiAgICAgIGxvZyxcbiAgICB9KTtcbiAgICBkaXJEb25lKHsgY291bnQ6IGRpclN1bW1hcmllcy5sZW5ndGggfSk7XG5cbiAgICBmb3IgKGNvbnN0IHN1bW1hcnkgb2YgZGlyU3VtbWFyaWVzKSB7XG4gICAgICBpZiAoIXNlZW5OYW1lcy5oYXMoc3VtbWFyeS5uYW1lKSkge1xuICAgICAgICBzZWVuTmFtZXMuYWRkKHN1bW1hcnkubmFtZSk7XG4gICAgICAgIHN1bW1hcmllcy5wdXNoKHN1bW1hcnkpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGRvbmUoeyB0b3RhbFNraWxsczogc3VtbWFyaWVzLmxlbmd0aCB9KTtcblxuICByZXR1cm4gc3VtbWFyaWVzO1xufVxuXG5hc3luYyBmdW5jdGlvbiBkaXNjb3ZlclNraWxsc0luRGlyZWN0b3J5KG9wdHM6IHtcbiAgc2FuZGJveDogU2FuZGJveDtcbiAgc2tpbGxzRGlyOiBzdHJpbmc7XG4gIGxvZzogTG9nZ2VyO1xufSk6IFByb21pc2U8U2tpbGxTdW1tYXJ5W10+IHtcbiAgY29uc3QgeyBzYW5kYm94LCBza2lsbHNEaXIsIGxvZyB9ID0gb3B0cztcbiAgY29uc3Qgc2tpbGxQYXRocyA9IGF3YWl0IGZpbmRTa2lsbEZpbGVzKHsgc2FuZGJveCwgc2tpbGxzRGlyLCBsb2cgfSk7XG5cbiAgaWYgKHNraWxsUGF0aHMubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgY29uc3Qgc3VtbWFyaWVzOiBTa2lsbFN1bW1hcnlbXSA9IFtdO1xuXG4gIGZvciAoY29uc3Qgc2tpbGxNZFBhdGggb2Ygc2tpbGxQYXRocykge1xuICAgIGNvbnN0IHN1bW1hcnkgPSBhd2FpdCBwYXJzZVNraWxsRmlsZSh7IHNhbmRib3gsIHNraWxsTWRQYXRoLCBsb2cgfSk7XG4gICAgaWYgKHN1bW1hcnkpIHtcbiAgICAgIHN1bW1hcmllcy5wdXNoKHN1bW1hcnkpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBzdW1tYXJpZXM7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZpbmRTa2lsbEZpbGVzKG9wdHM6IHtcbiAgc2FuZGJveDogU2FuZGJveDtcbiAgc2tpbGxzRGlyOiBzdHJpbmc7XG4gIGxvZzogTG9nZ2VyO1xufSk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgY29uc3QgeyBzYW5kYm94LCBza2lsbHNEaXIsIGxvZyB9ID0gb3B0cztcblxuICBjb25zdCBleGVjUmVzdWx0ID0gYXdhaXQgc2FuZGJveC5leGVjKHtcbiAgICBjb21tYW5kOiBcImZpbmRcIixcbiAgICBhcmdzOiBbc2tpbGxzRGlyLCBcIi1uYW1lXCIsIFwiU0tJTEwubWRcIiwgXCItdHlwZVwiLCBcImZcIl0sXG4gIH0pO1xuXG4gIGlmIChleGVjUmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICBsb2cud2FybihcImZhaWxlZCB0byBzY2FuIHNraWxscyBkaXJlY3RvcnlcIiwge1xuICAgICAgZGlyOiBza2lsbHNEaXIsXG4gICAgICBlcnJvcjogZXhlY1Jlc3VsdC5tZXNzYWdlLFxuICAgIH0pO1xuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIGNvbnN0IHsgc3Rkb3V0LCBleGl0Q29kZSB9ID0gYXdhaXQgZXhlY1Jlc3VsdC5yZXN1bHQ7XG5cbiAgaWYgKGV4aXRDb2RlICE9PSAwKSB7XG4gICAgbG9nLndhcm4oXCJza2lsbHMgZGlyZWN0b3J5IG5vdCBmb3VuZCBvciBpbmFjY2Vzc2libGVcIiwgeyBkaXI6IHNraWxsc0RpciB9KTtcbiAgICByZXR1cm4gW107XG4gIH1cblxuICByZXR1cm4gc3Rkb3V0XG4gICAgLnRyaW0oKVxuICAgIC5zcGxpdChcIlxcblwiKVxuICAgIC5maWx0ZXIoKHApID0+IHAubGVuZ3RoID4gMCk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHBhcnNlU2tpbGxGaWxlKG9wdHM6IHtcbiAgc2FuZGJveDogU2FuZGJveDtcbiAgc2tpbGxNZFBhdGg6IHN0cmluZztcbiAgbG9nOiBMb2dnZXI7XG59KTogUHJvbWlzZTxTa2lsbFN1bW1hcnkgfCBudWxsPiB7XG4gIGNvbnN0IHsgc2FuZGJveCwgc2tpbGxNZFBhdGgsIGxvZyB9ID0gb3B0cztcbiAgY29uc3QgZXhlY1Jlc3VsdCA9IGF3YWl0IHNhbmRib3guZXhlYyh7XG4gICAgY29tbWFuZDogXCJjYXRcIixcbiAgICBhcmdzOiBbc2tpbGxNZFBhdGhdLFxuICB9KTtcblxuICBpZiAoZXhlY1Jlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgbG9nLndhcm4oXCJmYWlsZWQgdG8gcmVhZCBza2lsbCBmaWxlXCIsIHtcbiAgICAgIHBhdGg6IHNraWxsTWRQYXRoLFxuICAgICAgZXJyb3I6IGV4ZWNSZXN1bHQubWVzc2FnZSxcbiAgICB9KTtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGNvbnN0IHsgc3Rkb3V0LCBleGl0Q29kZSB9ID0gYXdhaXQgZXhlY1Jlc3VsdC5yZXN1bHQ7XG5cbiAgaWYgKGV4aXRDb2RlICE9PSAwKSB7XG4gICAgbG9nLndhcm4oXCJjb3VsZCBub3QgcmVhZCBza2lsbCBmaWxlXCIsIHsgcGF0aDogc2tpbGxNZFBhdGggfSk7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCBwYXJzZWQgPSBwYXJzZVNraWxsRnJvbnRtYXR0ZXIoc3Rkb3V0KTtcblxuICBpZiAoIXBhcnNlZCkge1xuICAgIGxvZy53YXJuKFwiaW52YWxpZCBvciBtaXNzaW5nIGZyb250bWF0dGVyXCIsIHsgcGF0aDogc2tpbGxNZFBhdGggfSk7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIG5hbWU6IHBhcnNlZC5uYW1lLFxuICAgIGRlc2NyaXB0aW9uOiBwYXJzZWQuZGVzY3JpcHRpb24sXG4gICAgc2tpbGxNZFBhdGgsXG4gIH07XG59XG4iLCAiaW1wb3J0ICogYXMgcGF0aFBvc2l4IGZyb20gXCJub2RlOnBhdGgvcG9zaXhcIjtcbmltcG9ydCB7IGpzb25TY2hlbWEsIHR5cGUgVG9vbFNldCwgdG9vbCB9IGZyb20gXCJhaVwiO1xuaW1wb3J0IHsgeiB9IGZyb20gXCJ6b2RcIjtcbmltcG9ydCB0eXBlIHsgQWdlbnRJbnB1dCwgQWdlbnRNZXNzYWdlSW5wdXQgfSBmcm9tIFwiLi4vYWdlbnQtd29ya2Zsb3dcIjtcbmltcG9ydCB0eXBlIHsgUnBjUGF5bG9hZCwgUnBjUmVzdWx0IH0gZnJvbSBcIi4uL2NsaWVudFwiO1xuaW1wb3J0IHR5cGUgeyBTYW5kYm94IH0gZnJvbSBcIi4uL3NhbmRib3hcIjtcbmltcG9ydCB7IERFRkFVTFRfV0FJVF9VTlRJTCB9IGZyb20gXCIuLi9zYW5kYm94L3Byb2Nlc3MtbWFuYWdlclwiO1xuaW1wb3J0IHR5cGUgeyBTa2lsbFN1bW1hcnkgfSBmcm9tIFwiLi4vc2tpbGxzL3R5cGVzXCI7XG5pbXBvcnQgdHlwZSB7IFNhbmRib3hSZWNvcmQsIFNlc3Npb24sIFN0b3JhZ2UgfSBmcm9tIFwiLi4vc3RvcmFnZVwiO1xuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSBcIi4uL3V0aWxzL2xvZ2dlclwiO1xuaW1wb3J0IHsgY3JlYXRlSmF2YVNjcmlwdFRvb2wsIHR5cGUgT25TdWJUb29sQ2FsbCB9IGZyb20gXCIuL2phdmFzY3JpcHRcIjtcblxuY29uc3QgbG9nID0gY3JlYXRlTG9nZ2VyKHsgc3Vic3lzdGVtOiBcInRvb2xzXCIgfSk7XG5cbmNvbnN0IEFHRU5UX1BST1RPQ09MX1ZFUlNJT04gPSBcInYxXCI7XG5cbmZ1bmN0aW9uIGZvcm1hdEZpbGVTaXplKGJ5dGVzOiBudW1iZXIpOiBzdHJpbmcge1xuICBpZiAoYnl0ZXMgPCAxMDI0KSB7XG4gICAgcmV0dXJuIGAke2J5dGVzfWA7XG4gIH1cbiAgaWYgKGJ5dGVzIDwgMTAyNCAqIDEwMjQpIHtcbiAgICByZXR1cm4gYCR7KGJ5dGVzIC8gMTAyNCkudG9GaXhlZCgxKX1LYDtcbiAgfVxuICBpZiAoYnl0ZXMgPCAxMDI0ICogMTAyNCAqIDEwMjQpIHtcbiAgICByZXR1cm4gYCR7KGJ5dGVzIC8gKDEwMjQgKiAxMDI0KSkudG9GaXhlZCgxKX1NYDtcbiAgfVxuICByZXR1cm4gYCR7KGJ5dGVzIC8gKDEwMjQgKiAxMDI0ICogMTAyNCkpLnRvRml4ZWQoMSl9R2A7XG59XG5cbnR5cGUgSW50ZXJuYWxUb29sQ29udGV4dCA9IHtcbiAgaW5wdXQ6IEFnZW50SW5wdXQ7XG4gIGV2ZW50OiBBZ2VudE1lc3NhZ2VJbnB1dDtcbiAgc2FuZGJveDogU2FuZGJveDtcbiAgc2Vzc2lvbjogU2Vzc2lvbjtcbiAgc2FuZGJveFJlY29yZDogU2FuZGJveFJlY29yZDtcbiAgLyoqIFJlZiBwb3B1bGF0ZWQgaW4gcHJlcGFyZVN0ZXAgd2hlbiBza2lsbHNEaXIgaXMgc2V0OyBTa2lsbCB0b29sIHJlYWRzIGZyb20gLmN1cnJlbnQgYXQgZXhlY3V0ZSB0aW1lICovXG4gIHNraWxsc1JlZjogeyBjdXJyZW50OiBTa2lsbFN1bW1hcnlbXSB9O1xuICBhcGlUb29sc01ldGFkYXRhOiB7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuICAgIGlucHV0U2NoZW1hPzogdW5rbm93bjtcbiAgfVtdO1xuICBvblN1YlRvb2xDYWxsPzogT25TdWJUb29sQ2FsbDtcbn07XG5cbmV4cG9ydCB0eXBlIFRvb2xDb250ZXh0PFRDb250ZXh0ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4+ID0ge1xuICBzZXNzaW9uOiBTZXNzaW9uO1xuICBzYW5kYm94OiBTYW5kYm94O1xuICBzdG9yYWdlOiBTdG9yYWdlO1xuICBjb250ZXh0OiBUQ29udGV4dDtcbn07XG5cbmZ1bmN0aW9uIGlzUmdOb3RGb3VuZEVycm9yKGVycjogRXJyb3IpOiBib29sZWFuIHtcbiAgY29uc3QgcGFydHMgPSBbZXJyLm1lc3NhZ2VdO1xuXG4gIGNvbnN0IGFueUVyciA9IGVyciBhcyB1bmtub3duIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBpZiAodHlwZW9mIGFueUVyci5yZWFzb24gPT09IFwic3RyaW5nXCIpIHtcbiAgICBwYXJ0cy5wdXNoKGFueUVyci5yZWFzb24pO1xuICB9XG4gIGlmIChhbnlFcnIuY2F1c2UgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgIHBhcnRzLnB1c2goYW55RXJyLmNhdXNlLm1lc3NhZ2UpO1xuICAgIGNvbnN0IGFueUNhdXNlID0gYW55RXJyLmNhdXNlIGFzIHVua25vd24gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgaWYgKHR5cGVvZiBhbnlDYXVzZS50ZXh0ID09PSBcInN0cmluZ1wiKSB7XG4gICAgICBwYXJ0cy5wdXNoKGFueUNhdXNlLnRleHQpO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IG1zZyA9IHBhcnRzLmpvaW4oXCIgXCIpLnRvTG93ZXJDYXNlKCk7XG4gIHJldHVybiAoXG4gICAgbXNnLmluY2x1ZGVzKFwiZXhlY3V0YWJsZSBmaWxlIG5vdCBmb3VuZFwiKSB8fFxuICAgIG1zZy5pbmNsdWRlcyhcImV4ZWN1dGFibGVfbm90X2ZvdW5kXCIpIHx8XG4gICAgKG1zZy5pbmNsdWRlcyhcImVub2VudFwiKSAmJiBtc2cuaW5jbHVkZXMoXCJyZ1wiKSlcbiAgKTtcbn1cblxuZXhwb3J0IGNvbnN0IGJ1aWx0SW5Ub29scyA9IHtcbiAgUmVhZDogdG9vbCh7XG4gICAgZGVzY3JpcHRpb246XG4gICAgICBcIlJlYWRzIGEgZmlsZSBhbmQgcmV0dXJucyBpdHMgY29udGVudHMgd2l0aCBtZXRhZGF0YS4gRm9yIGZpbGVzIG92ZXIgMjAwIGxpbmVzLCBhdXRvbWF0aWNhbGx5IHNob3dzIGZpcnN0IDEwMCBsaW5lcyB1bmxlc3MgYSBzcGVjaWZpYyBsaW5lIHJhbmdlIGlzIHByb3ZpZGVkLiBVc2Ugc3RhcnRMaW5lIGFuZCBlbmRMaW5lIHBhcmFtZXRlcnMgdG8gcmVhZCBzcGVjaWZpYyBwb3J0aW9ucyBvZiBsYXJnZSBmaWxlcy5cIixcbiAgICBpbnB1dFNjaGVtYTogei5vYmplY3Qoe1xuICAgICAgbGFiZWw6IHpcbiAgICAgICAgLnN0cmluZygpXG4gICAgICAgIC5kZXNjcmliZShcIkEgbGFiZWwgdGhhdCBkZXNjcmliZXMgdGhlIGFjdGlvbiBiZWluZyBwZXJmb3JtZWRcIiksXG4gICAgICBwYXRoOiB6LnN0cmluZygpLmRlc2NyaWJlKFwiQWJzb2x1dGUgcGF0aCB0byB0aGUgZmlsZVwiKSxcbiAgICAgIHN0YXJ0TGluZTogelxuICAgICAgICAubnVtYmVyKClcbiAgICAgICAgLm9wdGlvbmFsKClcbiAgICAgICAgLmRlc2NyaWJlKFxuICAgICAgICAgIFwiU3RhcnRpbmcgbGluZSBudW1iZXIgKDEtaW5kZXhlZCkuIElmIHByb3ZpZGVkIHdpdGggZW5kTGluZSwgcmVhZHMgZXhhY3QgcmFuZ2UgcmVnYXJkbGVzcyBvZiBmaWxlIHNpemUuXCJcbiAgICAgICAgKSxcbiAgICAgIGVuZExpbmU6IHpcbiAgICAgICAgLm51bWJlcigpXG4gICAgICAgIC5vcHRpb25hbCgpXG4gICAgICAgIC5kZXNjcmliZShcbiAgICAgICAgICBcIkVuZGluZyBsaW5lIG51bWJlciAoMS1pbmRleGVkLCBpbmNsdXNpdmUpLiBJZiBwcm92aWRlZCB3aXRoIHN0YXJ0TGluZSwgcmVhZHMgZXhhY3QgcmFuZ2UgcmVnYXJkbGVzcyBvZiBmaWxlIHNpemUuXCJcbiAgICAgICAgKSxcbiAgICB9KSxcbiAgICBvdXRwdXRTY2hlbWE6IHoub2JqZWN0KHtcbiAgICAgIGNvbnRlbnQ6IHouc3RyaW5nKCkuZGVzY3JpYmUoXCJGaWxlIGNvbnRlbnRcIiksXG4gICAgICBtZXRhZGF0YTogei5vYmplY3Qoe1xuICAgICAgICB0b3RhbExpbmVzOiB6Lm51bWJlcigpLmRlc2NyaWJlKFwiVG90YWwgbnVtYmVyIG9mIGxpbmVzIGluIHRoZSBmaWxlXCIpLFxuICAgICAgICBsaW5lc1Nob3duOiB6XG4gICAgICAgICAgLm51bWJlcigpXG4gICAgICAgICAgLmRlc2NyaWJlKFwiTnVtYmVyIG9mIGxpbmVzIGluY2x1ZGVkIGluIHRoaXMgcmVzcG9uc2VcIiksXG4gICAgICAgIHN0YXJ0TGluZTogei5udW1iZXIoKS5kZXNjcmliZShcIkZpcnN0IGxpbmUgbnVtYmVyIHNob3duICgxLWluZGV4ZWQpXCIpLFxuICAgICAgICBlbmRMaW5lOiB6Lm51bWJlcigpLmRlc2NyaWJlKFwiTGFzdCBsaW5lIG51bWJlciBzaG93biAoMS1pbmRleGVkKVwiKSxcbiAgICAgICAgaXNQYWdpbmF0ZWQ6IHpcbiAgICAgICAgICAuYm9vbGVhbigpXG4gICAgICAgICAgLmRlc2NyaWJlKFwiV2hldGhlciB0aGlzIGlzIGEgcGFydGlhbCB2aWV3IG9mIHRoZSBmaWxlXCIpLFxuICAgICAgICBmaWxlU2l6ZTogelxuICAgICAgICAgIC5zdHJpbmcoKVxuICAgICAgICAgIC5kZXNjcmliZShcIkh1bWFuLXJlYWRhYmxlIGZpbGUgc2l6ZSAoZS5nLiwgJzIuNUsnLCAnMS4yTScpXCIpLFxuICAgICAgICBwYXRoOiB6XG4gICAgICAgICAgLnN0cmluZygpXG4gICAgICAgICAgLmRlc2NyaWJlKFwiUGF0aCB0byB0aGUgZmlsZSByZWxhdGl2ZSB0byB3b3Jrc3BhY2Ugcm9vdFwiKSxcbiAgICAgIH0pLFxuICAgIH0pLFxuICB9KSxcbiAgR3JlcDogdG9vbCh7XG4gICAgZGVzY3JpcHRpb246XG4gICAgICBcIlNlYXJjaCBmb3IgcGF0dGVybnMgaW4gZmlsZXMgdXNpbmcgcmlwZ3JlcC4gVXNlIHRoaXMgdG8gZmluZCBjb2RlIHBhdHRlcm5zLCBmdW5jdGlvbiBkZWZpbml0aW9ucywgaW1wb3J0cywgZXRjLlwiLFxuICAgIGlucHV0U2NoZW1hOiB6Lm9iamVjdCh7XG4gICAgICBsYWJlbDogelxuICAgICAgICAuc3RyaW5nKClcbiAgICAgICAgLmRlc2NyaWJlKFwiQSBsYWJlbCB0aGF0IGRlc2NyaWJlcyB0aGUgYWN0aW9uIGJlaW5nIHBlcmZvcm1lZFwiKSxcbiAgICAgIHBhdHRlcm46IHpcbiAgICAgICAgLnN0cmluZygpXG4gICAgICAgIC5kZXNjcmliZShcIlJlZ2V4IHBhdHRlcm4gdG8gc2VhcmNoIGZvciAocmlwZ3JlcCBzeW50YXgpXCIpLFxuICAgICAgcGF0aDogelxuICAgICAgICAuc3RyaW5nKClcbiAgICAgICAgLm9wdGlvbmFsKClcbiAgICAgICAgLmRlc2NyaWJlKFxuICAgICAgICAgIFwiQWJzb2x1dGUgcGF0aCB0byBzZWFyY2ggaW4gKGRlZmF1bHRzIHRvIHdvcmtpbmcgZGlyZWN0b3J5KS4gQ2FuIGJlIGEgZmlsZSBvciBkaXJlY3RvcnkuXCJcbiAgICAgICAgKSxcbiAgICAgIGZpbGVUeXBlOiB6XG4gICAgICAgIC5zdHJpbmcoKVxuICAgICAgICAub3B0aW9uYWwoKVxuICAgICAgICAuZGVzY3JpYmUoXG4gICAgICAgICAgXCJGaWxlIHR5cGUgdG8gZmlsdGVyIGJ5IChlLmcuLCAndHMnLCAnanMnLCAncHknLCAnbWQnKS4gVXNlcyByaXBncmVwJ3MgYnVpbHQtaW4gdHlwZSBmaWx0ZXJzLlwiXG4gICAgICAgICksXG4gICAgICBnbG9iOiB6XG4gICAgICAgIC5zdHJpbmcoKVxuICAgICAgICAub3B0aW9uYWwoKVxuICAgICAgICAuZGVzY3JpYmUoXG4gICAgICAgICAgXCJHbG9iIHBhdHRlcm4gdG8gZmlsdGVyIGZpbGVzIChlLmcuLCAnKi50c3gnLCAnc3JjLyoqLyoudHMnKVwiXG4gICAgICAgICksXG4gICAgICBjYXNlU2Vuc2l0aXZlOiB6XG4gICAgICAgIC5ib29sZWFuKClcbiAgICAgICAgLm9wdGlvbmFsKClcbiAgICAgICAgLmRlZmF1bHQodHJ1ZSlcbiAgICAgICAgLmRlc2NyaWJlKFwiV2hldGhlciBzZWFyY2ggaXMgY2FzZS1zZW5zaXRpdmUgKGRlZmF1bHQ6IHRydWUpXCIpLFxuICAgICAgY29udGV4dExpbmVzOiB6XG4gICAgICAgIC5udW1iZXIoKVxuICAgICAgICAub3B0aW9uYWwoKVxuICAgICAgICAuZGVzY3JpYmUoXG4gICAgICAgICAgXCJOdW1iZXIgb2YgY29udGV4dCBsaW5lcyB0byBzaG93IGJlZm9yZSBhbmQgYWZ0ZXIgZWFjaCBtYXRjaFwiXG4gICAgICAgICksXG4gICAgICBtYXhDb3VudDogelxuICAgICAgICAubnVtYmVyKClcbiAgICAgICAgLm9wdGlvbmFsKClcbiAgICAgICAgLmRlc2NyaWJlKFxuICAgICAgICAgIFwiTWF4aW11bSBudW1iZXIgb2YgbWF0Y2hlcyBwZXIgZmlsZSAodXNlZnVsIGZvciBsaW1pdGluZyBvdXRwdXQpXCJcbiAgICAgICAgKSxcbiAgICAgIGZpbGVzV2l0aE1hdGNoZXM6IHpcbiAgICAgICAgLmJvb2xlYW4oKVxuICAgICAgICAub3B0aW9uYWwoKVxuICAgICAgICAuZGVmYXVsdChmYWxzZSlcbiAgICAgICAgLmRlc2NyaWJlKFxuICAgICAgICAgIFwiT25seSBzaG93IGZpbGUgcGF0aHMgdGhhdCBjb250YWluIG1hdGNoZXMsIG5vdCB0aGUgbWF0Y2hpbmcgbGluZXMgdGhlbXNlbHZlc1wiXG4gICAgICAgICksXG4gICAgfSksXG4gICAgb3V0cHV0U2NoZW1hOiB6Lm9iamVjdCh7XG4gICAgICBtYXRjaGVzOiB6XG4gICAgICAgIC5zdHJpbmcoKVxuICAgICAgICAuZGVzY3JpYmUoXG4gICAgICAgICAgXCJTZWFyY2ggcmVzdWx0cyB3aXRoIGZpbGUgcGF0aHMsIGxpbmUgbnVtYmVycywgYW5kIG1hdGNoaW5nIGNvbnRlbnRcIlxuICAgICAgICApLFxuICAgICAgc3VtbWFyeTogei5vYmplY3Qoe1xuICAgICAgICBtYXRjaENvdW50OiB6Lm51bWJlcigpLmRlc2NyaWJlKFwiTnVtYmVyIG9mIG1hdGNoZXMgZm91bmRcIiksXG4gICAgICAgIGZpbGVDb3VudDogei5udW1iZXIoKS5kZXNjcmliZShcIk51bWJlciBvZiBmaWxlcyBjb250YWluaW5nIG1hdGNoZXNcIiksXG4gICAgICAgIHNlYXJjaFBhdGg6IHouc3RyaW5nKCkuZGVzY3JpYmUoXCJQYXRoIHRoYXQgd2FzIHNlYXJjaGVkXCIpLFxuICAgICAgICBwYXR0ZXJuOiB6LnN0cmluZygpLmRlc2NyaWJlKFwiUGF0dGVybiB0aGF0IHdhcyBzZWFyY2hlZCBmb3JcIiksXG4gICAgICB9KSxcbiAgICB9KSxcbiAgfSksXG4gIExpc3Q6IHRvb2woe1xuICAgIGRlc2NyaXB0aW9uOlxuICAgICAgXCJSZWN1cnNpdmVseSBsaXN0IGRpcmVjdG9yeSBjb250ZW50cy4gVXNlIHRoaXMgdG8gdW5kZXJzdGFuZCB0aGUgY29kZWJhc2Ugc3RydWN0dXJlLCBmaW5kIGZpbGVzLCBvciBleHBsb3JlIGRpcmVjdG9yaWVzLiBDb250cm9sIGRlcHRoIHRvIGJhbGFuY2UgZGV0YWlsIHZzLiBvdmVydmlldy4gRGVwdGggMSBzaG93cyBpbW1lZGlhdGUgY2hpbGRyZW4sIGRlcHRoIDIgaW5jbHVkZXMgc3ViZGlyZWN0b3JpZXMsIGV0Yy5cIixcbiAgICBpbnB1dFNjaGVtYTogei5vYmplY3Qoe1xuICAgICAgbGFiZWw6IHpcbiAgICAgICAgLnN0cmluZygpXG4gICAgICAgIC5kZXNjcmliZShcIkEgbGFiZWwgdGhhdCBkZXNjcmliZXMgdGhlIGFjdGlvbiBiZWluZyBwZXJmb3JtZWRcIiksXG4gICAgICBwYXRoOiB6XG4gICAgICAgIC5zdHJpbmcoKVxuICAgICAgICAub3B0aW9uYWwoKVxuICAgICAgICAuZGVzY3JpYmUoXCJBYnNvbHV0ZSBwYXRoIHRvIGxpc3QgKGRlZmF1bHRzIHRvIHdvcmtpbmcgZGlyZWN0b3J5KVwiKSxcbiAgICAgIGRlcHRoOiB6XG4gICAgICAgIC5udW1iZXIoKVxuICAgICAgICAub3B0aW9uYWwoKVxuICAgICAgICAuZGVzY3JpYmUoXG4gICAgICAgICAgXCJNYXhpbXVtIGRlcHRoIHRvIHRyYXZlcnNlLiBDaG9vc2UgYmFzZWQgb24gY29udGV4dDogMS0yIGZvciBxdWljayBvdmVydmlldywgMy00IGZvciBkZXRhaWxlZCBleHBsb3JhdGlvbiwgNSsgZm9yIGNvbXByZWhlbnNpdmUgbWFwcGluZ1wiXG4gICAgICAgICksXG4gICAgICBpbmNsdWRlSGlkZGVuOiB6XG4gICAgICAgIC5ib29sZWFuKClcbiAgICAgICAgLm9wdGlvbmFsKClcbiAgICAgICAgLmRlZmF1bHQoZmFsc2UpXG4gICAgICAgIC5kZXNjcmliZShcbiAgICAgICAgICBcIkluY2x1ZGUgaGlkZGVuIGZpbGVzIGFuZCBkaXJlY3RvcmllcyAodGhvc2Ugc3RhcnRpbmcgd2l0aCAnLicpXCJcbiAgICAgICAgKSxcbiAgICAgIGZpbGVzT25seTogelxuICAgICAgICAuYm9vbGVhbigpXG4gICAgICAgIC5vcHRpb25hbCgpXG4gICAgICAgIC5kZWZhdWx0KGZhbHNlKVxuICAgICAgICAuZGVzY3JpYmUoXCJPbmx5IHNob3cgZmlsZXMsIG5vdCBkaXJlY3Rvcmllc1wiKSxcbiAgICAgIHBhdHRlcm46IHpcbiAgICAgICAgLnN0cmluZygpXG4gICAgICAgIC5vcHRpb25hbCgpXG4gICAgICAgIC5kZXNjcmliZShcIkdsb2IgcGF0dGVybiB0byBmaWx0ZXIgcmVzdWx0cyAoZS5nLiwgJyoudHMnLCAnKnRlc3QqJylcIiksXG4gICAgfSksXG4gICAgb3V0cHV0U2NoZW1hOiB6Lm9iamVjdCh7XG4gICAgICBsaXN0aW5nOiB6XG4gICAgICAgIC5zdHJpbmcoKVxuICAgICAgICAuZGVzY3JpYmUoXG4gICAgICAgICAgXCJEaXJlY3RvcnkgdHJlZSBsaXN0aW5nIHNob3dpbmcgcGF0aHMgcmVsYXRpdmUgdG8gc2VhcmNoIHJvb3RcIlxuICAgICAgICApLFxuICAgICAgc3VtbWFyeTogei5vYmplY3Qoe1xuICAgICAgICB0b3RhbEl0ZW1zOiB6Lm51bWJlcigpLmRlc2NyaWJlKFwiVG90YWwgbnVtYmVyIG9mIGl0ZW1zIGZvdW5kXCIpLFxuICAgICAgICB0b3RhbEZpbGVzOiB6Lm51bWJlcigpLmRlc2NyaWJlKFwiVG90YWwgbnVtYmVyIG9mIGZpbGVzIGZvdW5kXCIpLFxuICAgICAgICB0b3RhbERpcnM6IHoubnVtYmVyKCkuZGVzY3JpYmUoXCJUb3RhbCBudW1iZXIgb2YgZGlyZWN0b3JpZXMgZm91bmRcIiksXG4gICAgICAgIHNlYXJjaFBhdGg6IHouc3RyaW5nKCkuZGVzY3JpYmUoXCJQYXRoIHRoYXQgd2FzIGxpc3RlZFwiKSxcbiAgICAgICAgZGVwdGg6IHpcbiAgICAgICAgICAubnVtYmVyKClcbiAgICAgICAgICAub3B0aW9uYWwoKVxuICAgICAgICAgIC5kZXNjcmliZShcIk1heGltdW0gZGVwdGggdXNlZCAoaWYgc3BlY2lmaWVkKVwiKSxcbiAgICAgIH0pLFxuICAgIH0pLFxuICB9KSxcbiAgV3JpdGU6IHRvb2woe1xuICAgIGRlc2NyaXB0aW9uOlxuICAgICAgXCJXcml0ZSBjb250ZW50IHRvIGEgZmlsZS4gQ3JlYXRlcyBwYXJlbnQgZGlyZWN0b3JpZXMgYXV0b21hdGljYWxseS4gT3ZlcndyaXRlcyBleGlzdGluZyBmaWxlcy5cIixcbiAgICBpbnB1dFNjaGVtYTogei5vYmplY3Qoe1xuICAgICAgbGFiZWw6IHpcbiAgICAgICAgLnN0cmluZygpXG4gICAgICAgIC5kZXNjcmliZShcIkEgbGFiZWwgdGhhdCBkZXNjcmliZXMgdGhlIGFjdGlvbiBiZWluZyBwZXJmb3JtZWRcIiksXG4gICAgICBwYXRoOiB6LnN0cmluZygpLmRlc2NyaWJlKFwiQWJzb2x1dGUgcGF0aCB0byB0aGUgZmlsZVwiKSxcbiAgICAgIGNvbnRlbnQ6IHouc3RyaW5nKCkuZGVzY3JpYmUoXCJDb250ZW50IHRvIHdyaXRlIHRvIHRoZSBmaWxlXCIpLFxuICAgIH0pLFxuICAgIG91dHB1dFNjaGVtYTogei5vYmplY3Qoe1xuICAgICAgc3VjY2Vzczogei5ib29sZWFuKCkuZGVzY3JpYmUoXCJXaGV0aGVyIHRoZSB3cml0ZSBzdWNjZWVkZWRcIiksXG4gICAgICBwYXRoOiB6LnN0cmluZygpLmRlc2NyaWJlKFwiUGF0aCB0byB0aGUgd3JpdHRlbiBmaWxlXCIpLFxuICAgICAgYnl0ZXNXcml0dGVuOiB6Lm51bWJlcigpLmRlc2NyaWJlKFwiTnVtYmVyIG9mIGJ5dGVzIHdyaXR0ZW5cIiksXG4gICAgICBlcnJvcjogei5zdHJpbmcoKS5vcHRpb25hbCgpLmRlc2NyaWJlKFwiRXJyb3IgbWVzc2FnZSBpZiB3cml0ZSBmYWlsZWRcIiksXG4gICAgfSksXG4gIH0pLFxuICBFZGl0OiB0b29sKHtcbiAgICBkZXNjcmlwdGlvbjpcbiAgICAgIFwiRWRpdCBhIGZpbGUgYnkgcmVwbGFjaW5nIGFuIGV4YWN0IHN0cmluZy4gRmFpbHMgaWYgb2xkX3N0cmluZyBpcyBub3QgZm91bmQgb3IgYXBwZWFycyBtdWx0aXBsZSB0aW1lcyAobm90IHVuaXF1ZSkuIEZvciBtdWx0aXBsZSByZXBsYWNlbWVudHMsIGNhbGwgdGhpcyB0b29sIG11bHRpcGxlIHRpbWVzIHdpdGggdW5pcXVlIGNvbnRleHQuXCIsXG4gICAgaW5wdXRTY2hlbWE6IHoub2JqZWN0KHtcbiAgICAgIGxhYmVsOiB6XG4gICAgICAgIC5zdHJpbmcoKVxuICAgICAgICAuZGVzY3JpYmUoXCJBIGxhYmVsIHRoYXQgZGVzY3JpYmVzIHRoZSBhY3Rpb24gYmVpbmcgcGVyZm9ybWVkXCIpLFxuICAgICAgcGF0aDogei5zdHJpbmcoKS5kZXNjcmliZShcIkFic29sdXRlIHBhdGggdG8gdGhlIGZpbGVcIiksXG4gICAgICBvbGRfc3RyaW5nOiB6XG4gICAgICAgIC5zdHJpbmcoKVxuICAgICAgICAuZGVzY3JpYmUoXCJFeGFjdCBzdHJpbmcgdG8gZmluZCBhbmQgcmVwbGFjZSAobXVzdCBiZSB1bmlxdWUgaW4gZmlsZSlcIiksXG4gICAgICBuZXdfc3RyaW5nOiB6LnN0cmluZygpLmRlc2NyaWJlKFwiU3RyaW5nIHRvIHJlcGxhY2Ugb2xkX3N0cmluZyB3aXRoXCIpLFxuICAgIH0pLFxuICAgIG91dHB1dFNjaGVtYTogei5vYmplY3Qoe1xuICAgICAgc3VjY2Vzczogei5ib29sZWFuKCkuZGVzY3JpYmUoXCJXaGV0aGVyIHRoZSBlZGl0IHN1Y2NlZWRlZFwiKSxcbiAgICAgIHBhdGg6IHouc3RyaW5nKCkuZGVzY3JpYmUoXCJQYXRoIHRvIHRoZSBlZGl0ZWQgZmlsZVwiKSxcbiAgICAgIGVycm9yOiB6LnN0cmluZygpLm9wdGlvbmFsKCkuZGVzY3JpYmUoXCJFcnJvciBtZXNzYWdlIGlmIGVkaXQgZmFpbGVkXCIpLFxuICAgIH0pLFxuICB9KSxcbiAgQmFzaDogdG9vbCh7XG4gICAgZGVzY3JpcHRpb246XG4gICAgICBcIkV4ZWN1dGVzIGEgYmFzaCBjb21tYW5kLiBSZXR1cm5zIHN0ZG91dCBhbmQgc3RkZXJyIHNlcGFyYXRlbHkuIFVzZSB3YWl0VW50aWwgdG8gY29udHJvbCBob3cgbG9uZyB0byB3YWl0ICgwID0gcmV0dXJuIGltbWVkaWF0ZWx5LCBwcm9jZXNzIGtlZXBzIHJ1bm5pbmcpLiBMYXJnZSBvdXRwdXRzIGFyZSB0YWlsLXRydW5jYXRlZDsgZnVsbCBvdXRwdXQgaW4gb3V0cHV0RGlyLlwiLFxuICAgIGlucHV0U2NoZW1hOiB6Lm9iamVjdCh7XG4gICAgICBsYWJlbDogelxuICAgICAgICAuc3RyaW5nKClcbiAgICAgICAgLmRlc2NyaWJlKFwiQSBsYWJlbCB0aGF0IGRlc2NyaWJlcyB0aGUgYWN0aW9uIGJlaW5nIHBlcmZvcm1lZFwiKSxcbiAgICAgIGNvbW1hbmQ6IHouc3RyaW5nKCkuZGVzY3JpYmUoXCJUaGUgc2hlbGwgY29tbWFuZCB0byBleGVjdXRlXCIpLFxuICAgICAgd2FpdFVudGlsOiB6XG4gICAgICAgIC5udW1iZXIoKVxuICAgICAgICAub3B0aW9uYWwoKVxuICAgICAgICAuZGVzY3JpYmUoXG4gICAgICAgICAgYE1heCBtcyB0byB3YWl0IGZvciBjb21wbGV0aW9uIChkZWZhdWx0OiAke0RFRkFVTFRfV0FJVF9VTlRJTH0pLiBVc2UgMCB0byByZXR1cm4gaW1tZWRpYXRlbHkgd2hpbGUgdGhlIHByb2Nlc3Mga2VlcHMgcnVubmluZy5gXG4gICAgICAgICksXG4gICAgfSksXG4gICAgb3V0cHV0U2NoZW1hOiB6Lm9iamVjdCh7XG4gICAgICBjb21tYW5kSWQ6IHpcbiAgICAgICAgLnN0cmluZygpXG4gICAgICAgIC5kZXNjcmliZShcIkNvbW1hbmQgSUQuIFVzZSB0byByZWZlcmVuY2Ugb3Iga2lsbCBydW5uaW5nIHByb2Nlc3Nlcy5cIiksXG4gICAgICBzdGRvdXQ6IHpcbiAgICAgICAgLnN0cmluZygpXG4gICAgICAgIC5kZXNjcmliZShcbiAgICAgICAgICBcIkNvbW1hbmQgc3Rkb3V0LiBUYWlsLXRydW5jYXRlZCBpZiBsYXJnZTsgZnVsbCBjb250ZW50IGluIG91dHB1dERpci9zdGRvdXQudHh0LlwiXG4gICAgICAgICksXG4gICAgICBzdGRlcnI6IHpcbiAgICAgICAgLnN0cmluZygpXG4gICAgICAgIC5kZXNjcmliZShcbiAgICAgICAgICBcIkNvbW1hbmQgc3RkZXJyLiBUYWlsLXRydW5jYXRlZCBpZiBsYXJnZTsgZnVsbCBjb250ZW50IGluIG91dHB1dERpci9zdGRlcnIudHh0LlwiXG4gICAgICAgICksXG4gICAgICBleGl0Q29kZTogei5udW1iZXIoKS5kZXNjcmliZShcIkV4aXQgY29kZSAoLTEgaWYgc3RpbGwgcnVubmluZylcIiksXG4gICAgICBzdGF0dXM6IHpcbiAgICAgICAgLmVudW0oW1wicnVubmluZ1wiLCBcImNvbXBsZXRlZFwiLCBcImZhaWxlZFwiXSlcbiAgICAgICAgLmRlc2NyaWJlKFwiUHJvY2VzcyBzdGF0dXNcIiksXG4gICAgICBvdXRwdXREaXI6IHpcbiAgICAgICAgLnN0cmluZygpXG4gICAgICAgIC5kZXNjcmliZShcbiAgICAgICAgICBcIlBhdGggdG8gb3V0cHV0IGRpcmVjdG9yeSBjb250YWluaW5nIHN0ZG91dC50eHQsIHN0ZGVyci50eHQsIGFuZCBtZXRhZGF0YS5qc29uLiBFbXB0eSBpZiBzdGlsbCBydW5uaW5nLlwiXG4gICAgICAgICksXG4gICAgfSksXG4gIH0pLFxuICBTa2lsbDogdG9vbCh7XG4gICAgZGVzY3JpcHRpb246XG4gICAgICBcIkxvYWQgYSBza2lsbCdzIGZ1bGwgaW5zdHJ1Y3Rpb25zIGJ5IG5hbWUuIENhbGwgdGhpcyBiZWZvcmUgZm9sbG93aW5nIGEgc2tpbGwuXCIsXG4gICAgaW5wdXRTY2hlbWE6IHoub2JqZWN0KHtcbiAgICAgIGxhYmVsOiB6XG4gICAgICAgIC5zdHJpbmcoKVxuICAgICAgICAuZGVzY3JpYmUoXCJBIGxhYmVsIHRoYXQgZGVzY3JpYmVzIHRoZSBhY3Rpb24gYmVpbmcgcGVyZm9ybWVkXCIpLFxuICAgICAgbmFtZTogei5zdHJpbmcoKS5kZXNjcmliZShcIlNraWxsIG5hbWUgZnJvbSB0aGUgQXZhaWxhYmxlIFNraWxscyBsaXN0XCIpLFxuICAgIH0pLFxuICAgIG91dHB1dFNjaGVtYTogei5vYmplY3Qoe1xuICAgICAgbmFtZTogei5zdHJpbmcoKSxcbiAgICAgIGRlc2NyaXB0aW9uOiB6LnN0cmluZygpLFxuICAgICAgY29udGVudDogei5zdHJpbmcoKS5kZXNjcmliZShcIkZ1bGwgU0tJTEwubWQgY29udGVudFwiKSxcbiAgICAgIHBhdGg6IHouc3RyaW5nKCkuZGVzY3JpYmUoXCJQYXRoIHRvIHRoZSBza2lsbCBkaXJlY3RvcnkgaW4gdGhlIHNhbmRib3hcIiksXG4gICAgfSksXG4gIH0pLFxuICBKYXZhU2NyaXB0OiB0b29sKHtcbiAgICBpbnB1dFNjaGVtYTogei5vYmplY3Qoe1xuICAgICAgbGFiZWw6IHpcbiAgICAgICAgLnN0cmluZygpXG4gICAgICAgIC5kZXNjcmliZShcIkEgbGFiZWwgdGhhdCBkZXNjcmliZXMgdGhlIGFjdGlvbiBiZWluZyBwZXJmb3JtZWRcIiksXG4gICAgICBjb2RlOiB6XG4gICAgICAgIC5zdHJpbmcoKVxuICAgICAgICAuZGVzY3JpYmUoXG4gICAgICAgICAgXCJKYXZhU2NyaXB0IGFzeW5jIGZ1bmN0aW9uIGJvZHkuIGBjdHhgIGlzIGluIHNjb3BlLiBNdXN0IHVzZSBgcmV0dXJuYCB0byBwcm9kdWNlIG91dHB1dC5cIlxuICAgICAgICApLFxuICAgIH0pLFxuICB9KSxcbn0gc2F0aXNmaWVzIFRvb2xTZXQ7XG5cbmV4cG9ydCB0eXBlIEJ1aWx0SW5Ub29sTmFtZSA9IGtleW9mIHR5cGVvZiBidWlsdEluVG9vbHM7XG5leHBvcnQgY29uc3QgYnVpbHRpblRvb2xOYW1lcyA9IE9iamVjdC5mcm9tRW50cmllcyhcbiAgT2JqZWN0LmVudHJpZXMoYnVpbHRJblRvb2xzKS5tYXAoKFtuYW1lXSkgPT4gW25hbWUsIG5hbWVdKVxuKSBhcyB7IFtLIGluIEJ1aWx0SW5Ub29sTmFtZV06IEsgfTtcblxuY29uc3QgU0tJTExfTURfU1VGRklYID0gL1xcLz9TS0lMTFxcLm1kJC87XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRUb29scyhjb250ZXh0OiBJbnRlcm5hbFRvb2xDb250ZXh0KSB7XG4gIGNvbnN0IHRvb2xzOiBUb29sU2V0ID0ge1xuICAgIFtidWlsdGluVG9vbE5hbWVzLlJlYWRdOiB0b29sKHtcbiAgICAgIC4uLmJ1aWx0SW5Ub29scy5SZWFkLFxuICAgICAgZXhlY3V0ZTogYXN5bmMgKHsgcGF0aCwgc3RhcnRMaW5lLCBlbmRMaW5lIH0pID0+IHtcbiAgICAgICAgY29uc3QgZmlsZVBhdGggPSBwYXRoO1xuXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNvbnRleHQuc2FuZGJveC5yZWFkRmlsZSh7IHBhdGg6IGZpbGVQYXRoIH0pO1xuXG4gICAgICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICAgIGxvZy5lcnJvcihcIlJlYWQgZmFpbGVkXCIsIHsgZXJyb3I6IHJlc3VsdC5tZXNzYWdlIH0pO1xuICAgICAgICAgIHRocm93IHJlc3VsdDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChyZXN1bHQgPT09IG51bGwpIHtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgY29udGVudDogYEVycm9yOiBGaWxlIG5vdCBmb3VuZCAtICR7ZmlsZVBhdGh9YCxcbiAgICAgICAgICAgIG1ldGFkYXRhOiB7XG4gICAgICAgICAgICAgIHRvdGFsTGluZXM6IDAsXG4gICAgICAgICAgICAgIGxpbmVzU2hvd246IDAsXG4gICAgICAgICAgICAgIHN0YXJ0TGluZTogMCxcbiAgICAgICAgICAgICAgZW5kTGluZTogMCxcbiAgICAgICAgICAgICAgaXNQYWdpbmF0ZWQ6IGZhbHNlLFxuICAgICAgICAgICAgICBmaWxlU2l6ZTogXCIwXCIsXG4gICAgICAgICAgICAgIHBhdGg6IGZpbGVQYXRoLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZnVsbENvbnRlbnQgPSByZXN1bHQudG9TdHJpbmcoXCJ1dGYtOFwiKTtcbiAgICAgICAgY29uc3QgbGluZXMgPSBmdWxsQ29udGVudC5zcGxpdChcIlxcblwiKTtcbiAgICAgICAgLy8gQSB0cmFpbGluZyBuZXdsaW5lIHByb2R1Y2VzIGFuIGVtcHR5IGxhc3QgZWxlbWVudCBcdTIwMTQgcmVtb3ZlIGl0XG4gICAgICAgIC8vIHNvIGxpbmUgY291bnQgbWF0Y2hlcyBgd2MgLWxgIC8gYGF3ayAnRU5Ee3ByaW50IE5SfSdgIGJlaGF2aW9yLlxuICAgICAgICBpZiAobGluZXMubGVuZ3RoID4gMCAmJiBsaW5lcy5hdCgtMSkgPT09IFwiXCIpIHtcbiAgICAgICAgICBsaW5lcy5wb3AoKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB0b3RhbExpbmVzID0gbGluZXMubGVuZ3RoO1xuICAgICAgICBjb25zdCBmaWxlQnl0ZXMgPSBCdWZmZXIuYnl0ZUxlbmd0aChmdWxsQ29udGVudCk7XG4gICAgICAgIGNvbnN0IGZpbGVTaXplID0gZm9ybWF0RmlsZVNpemUoZmlsZUJ5dGVzKTtcblxuICAgICAgICAvLyBEZXRlcm1pbmUgcmFuZ2VcbiAgICAgICAgY29uc3QgUEFHRV9TSVpFID0gMTAwO1xuICAgICAgICBsZXQgYWN0dWFsU3RhcnQ6IG51bWJlcjtcbiAgICAgICAgbGV0IGFjdHVhbEVuZDogbnVtYmVyO1xuXG4gICAgICAgIGlmIChzdGFydExpbmUgIT09IHVuZGVmaW5lZCAmJiBlbmRMaW5lICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBhY3R1YWxTdGFydCA9IHN0YXJ0TGluZTtcbiAgICAgICAgICBhY3R1YWxFbmQgPSBlbmRMaW5lO1xuICAgICAgICB9IGVsc2UgaWYgKHN0YXJ0TGluZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgYWN0dWFsU3RhcnQgPSBzdGFydExpbmU7XG4gICAgICAgICAgYWN0dWFsRW5kID0gTWF0aC5taW4oc3RhcnRMaW5lICsgUEFHRV9TSVpFIC0gMSwgdG90YWxMaW5lcyk7XG4gICAgICAgIH0gZWxzZSBpZiAoZW5kTGluZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgYWN0dWFsU3RhcnQgPSAxO1xuICAgICAgICAgIGFjdHVhbEVuZCA9IGVuZExpbmU7XG4gICAgICAgIH0gZWxzZSBpZiAodG90YWxMaW5lcyA+IDIwMCkge1xuICAgICAgICAgIGFjdHVhbFN0YXJ0ID0gMTtcbiAgICAgICAgICBhY3R1YWxFbmQgPSBQQUdFX1NJWkU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgYWN0dWFsU3RhcnQgPSAxO1xuICAgICAgICAgIGFjdHVhbEVuZCA9IHRvdGFsTGluZXM7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFeHRyYWN0IHRoZSBsaW5lIHJhbmdlICgxLWluZGV4ZWQpXG4gICAgICAgIGNvbnN0IHNsaWNlZExpbmVzID0gbGluZXMuc2xpY2UoYWN0dWFsU3RhcnQgLSAxLCBhY3R1YWxFbmQpO1xuICAgICAgICBjb25zdCBjb250ZW50ID0gc2xpY2VkTGluZXMuam9pbihcIlxcblwiKTtcblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIG1ldGFkYXRhOiB7XG4gICAgICAgICAgICB0b3RhbExpbmVzLFxuICAgICAgICAgICAgbGluZXNTaG93bjogTWF0aC5tYXgoMCwgYWN0dWFsRW5kIC0gYWN0dWFsU3RhcnQgKyAxKSxcbiAgICAgICAgICAgIHN0YXJ0TGluZTogYWN0dWFsU3RhcnQsXG4gICAgICAgICAgICBlbmRMaW5lOiBhY3R1YWxFbmQsXG4gICAgICAgICAgICBpc1BhZ2luYXRlZDogYWN0dWFsRW5kIDwgdG90YWxMaW5lcyxcbiAgICAgICAgICAgIGZpbGVTaXplLFxuICAgICAgICAgICAgcGF0aDogZmlsZVBhdGgsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBjb250ZW50LFxuICAgICAgICB9O1xuICAgICAgfSxcbiAgICB9KSxcbiAgICBbYnVpbHRpblRvb2xOYW1lcy5HcmVwXTogdG9vbCh7XG4gICAgICAuLi5idWlsdEluVG9vbHMuR3JlcCxcbiAgICAgIGV4ZWN1dGU6IGFzeW5jICh7XG4gICAgICAgIHBhdHRlcm4sXG4gICAgICAgIHBhdGgsXG4gICAgICAgIGZpbGVUeXBlLFxuICAgICAgICBnbG9iLFxuICAgICAgICBjYXNlU2Vuc2l0aXZlLFxuICAgICAgICBjb250ZXh0TGluZXMsXG4gICAgICAgIG1heENvdW50LFxuICAgICAgICBmaWxlc1dpdGhNYXRjaGVzLFxuICAgICAgfSkgPT4ge1xuICAgICAgICBjb25zdCBzZWFyY2hQYXRoID0gcGF0aCA/PyBcIi5cIjtcblxuICAgICAgICBjb25zdCBhcmdzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgICAgIGFyZ3MucHVzaChcIi0tbGluZS1udW1iZXJcIik7XG4gICAgICAgIGFyZ3MucHVzaChcIi0taGVhZGluZ1wiKTtcbiAgICAgICAgYXJncy5wdXNoKFwiLS1jb2xvclwiLCBcIm5ldmVyXCIpO1xuXG4gICAgICAgIGlmICghY2FzZVNlbnNpdGl2ZSkge1xuICAgICAgICAgIGFyZ3MucHVzaChcIi1pXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGZpbGVUeXBlKSB7XG4gICAgICAgICAgYXJncy5wdXNoKFwiLS10eXBlXCIsIGZpbGVUeXBlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChnbG9iKSB7XG4gICAgICAgICAgYXJncy5wdXNoKFwiLS1nbG9iXCIsIGdsb2IpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNvbnRleHRMaW5lcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgYXJncy5wdXNoKFwiLUNcIiwgU3RyaW5nKGNvbnRleHRMaW5lcykpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG1heENvdW50ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBhcmdzLnB1c2goXCItLW1heC1jb3VudFwiLCBTdHJpbmcobWF4Q291bnQpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChmaWxlc1dpdGhNYXRjaGVzKSB7XG4gICAgICAgICAgYXJncy5wdXNoKFwiLS1maWxlcy13aXRoLW1hdGNoZXNcIik7XG4gICAgICAgIH1cblxuICAgICAgICBhcmdzLnB1c2goXCItLVwiLCBwYXR0ZXJuLCBzZWFyY2hQYXRoKTtcblxuICAgICAgICBsZXQgcmVzdWx0ID0gYXdhaXQgY29udGV4dC5zYW5kYm94LmV4ZWMoeyBjb21tYW5kOiBcInJnXCIsIGFyZ3MgfSk7XG5cbiAgICAgICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yICYmIGlzUmdOb3RGb3VuZEVycm9yKHJlc3VsdCkpIHtcbiAgICAgICAgICBsb2cud2FybihcInJnIG5vdCBmb3VuZCwgaW5zdGFsbGluZyByaXBncmVwXCIpO1xuICAgICAgICAgIGNvbnN0IGluc3RhbGxSZXN1bHQgPSBhd2FpdCBjb250ZXh0LnNhbmRib3guZXhlYyh7XG4gICAgICAgICAgICBjb21tYW5kOiBcImJhc2hcIixcbiAgICAgICAgICAgIGFyZ3M6IFtcbiAgICAgICAgICAgICAgXCItY1wiLFxuICAgICAgICAgICAgICBbXG4gICAgICAgICAgICAgICAgXCJjb21tYW5kIC12IHJnID4vZGV2L251bGwgMj4mMSAmJiBleGl0IDBcIixcbiAgICAgICAgICAgICAgICBcImRuZiBpbnN0YWxsIC15IHJpcGdyZXAgMj4vZGV2L251bGwgJiYgZXhpdCAwXCIsXG4gICAgICAgICAgICAgICAgXCIoYXB0LWdldCB1cGRhdGUgLXFxICYmIGFwdC1nZXQgaW5zdGFsbCAteSAtcXEgcmlwZ3JlcCkgMj4vZGV2L251bGwgJiYgZXhpdCAwXCIsXG4gICAgICAgICAgICAgICAgXCJhcGsgYWRkIC0tbm8tY2FjaGUgcmlwZ3JlcCAyPi9kZXYvbnVsbCAmJiBleGl0IDBcIixcbiAgICAgICAgICAgICAgICBcImN1cmwgLXNMIGh0dHBzOi8vZ2l0aHViLmNvbS9CdXJudFN1c2hpL3JpcGdyZXAvcmVsZWFzZXMvZG93bmxvYWQvMTQuMS4xL3JpcGdyZXAtMTQuMS4xLXg4Nl82NC11bmtub3duLWxpbnV4LW11c2wudGFyLmd6IHwgdGFyIHh6IC1DIC90bXAgJiYgaW5zdGFsbCAvdG1wL3JpcGdyZXAtMTQuMS4xLXg4Nl82NC11bmtub3duLWxpbnV4LW11c2wvcmcgL3Vzci9sb2NhbC9iaW4vcmcgJiYgcm0gLXJmIC90bXAvcmlwZ3JlcC0xNC4xLjEteDg2XzY0LXVua25vd24tbGludXgtbXVzbFwiLFxuICAgICAgICAgICAgICBdLmpvaW4oXCJcXG5cIiksXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgc3VkbzogdHJ1ZSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBpZiAoIShpbnN0YWxsUmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpKSB7XG4gICAgICAgICAgICBjb25zdCBpbnN0YWxsT3V0cHV0ID0gYXdhaXQgaW5zdGFsbFJlc3VsdC5yZXN1bHQ7XG4gICAgICAgICAgICBpZiAoaW5zdGFsbE91dHB1dC5leGl0Q29kZSAhPT0gMCkge1xuICAgICAgICAgICAgICBsb2cud2FybihcInJpcGdyZXAgaW5zdGFsbCBmYWlsZWRcIiwge1xuICAgICAgICAgICAgICAgIHN0ZGVycjogaW5zdGFsbE91dHB1dC5zdGRlcnIsXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICByZXN1bHQgPSBhd2FpdCBjb250ZXh0LnNhbmRib3guZXhlYyh7IGNvbW1hbmQ6IFwicmdcIiwgYXJncyB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBFcnJvciAmJiBpc1JnTm90Rm91bmRFcnJvcihyZXN1bHQpKSB7XG4gICAgICAgICAgbG9nLndhcm4oXCJyZyB1bmF2YWlsYWJsZSwgZmFsbGluZyBiYWNrIHRvIGdyZXBcIik7XG4gICAgICAgICAgY29uc3QgZ3JlcEFyZ3MgPSBbXCItcm5cIiwgXCItLWNvbG9yPW5ldmVyXCJdO1xuICAgICAgICAgIGlmICghY2FzZVNlbnNpdGl2ZSkge1xuICAgICAgICAgICAgZ3JlcEFyZ3MucHVzaChcIi1pXCIpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoY29udGV4dExpbmVzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGdyZXBBcmdzLnB1c2goXCItQ1wiLCBTdHJpbmcoY29udGV4dExpbmVzKSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChtYXhDb3VudCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBncmVwQXJncy5wdXNoKFwiLW1cIiwgU3RyaW5nKG1heENvdW50KSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChmaWxlc1dpdGhNYXRjaGVzKSB7XG4gICAgICAgICAgICBncmVwQXJncy5wdXNoKFwiLWxcIik7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChnbG9iKSB7XG4gICAgICAgICAgICBncmVwQXJncy5wdXNoKGAtLWluY2x1ZGU9JHtnbG9ifWApO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoZmlsZVR5cGUpIHtcbiAgICAgICAgICAgIGNvbnN0IGluY2x1ZGVNYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZ1tdPiA9IHtcbiAgICAgICAgICAgICAgdHM6IFtcIioudHNcIiwgXCIqLnRzeFwiLCBcIioubXRzXCIsIFwiKi5jdHNcIl0sXG4gICAgICAgICAgICAgIGpzOiBbXCIqLmpzXCIsIFwiKi5qc3hcIiwgXCIqLm1qc1wiLCBcIiouY2pzXCJdLFxuICAgICAgICAgICAgICBweTogW1wiKi5weVwiXSxcbiAgICAgICAgICAgICAgcnVzdDogW1wiKi5yc1wiXSxcbiAgICAgICAgICAgICAgZ286IFtcIiouZ29cIl0sXG4gICAgICAgICAgICAgIGphdmE6IFtcIiouamF2YVwiXSxcbiAgICAgICAgICAgICAgbWQ6IFtcIioubWRcIl0sXG4gICAgICAgICAgICAgIGpzb246IFtcIiouanNvblwiXSxcbiAgICAgICAgICAgICAgY3NzOiBbXCIqLmNzc1wiXSxcbiAgICAgICAgICAgICAgaHRtbDogW1wiKi5odG1sXCJdLFxuICAgICAgICAgICAgICB5YW1sOiBbXCIqLnltbFwiLCBcIioueWFtbFwiXSxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGV4dCBvZiBpbmNsdWRlTWFwW2ZpbGVUeXBlXSA/PyBbYCouJHtmaWxlVHlwZX1gXSkge1xuICAgICAgICAgICAgICBncmVwQXJncy5wdXNoKGAtLWluY2x1ZGU9JHtleHR9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGdyZXBBcmdzLnB1c2goXCItLVwiLCBwYXR0ZXJuLCBzZWFyY2hQYXRoKTtcbiAgICAgICAgICByZXN1bHQgPSBhd2FpdCBjb250ZXh0LnNhbmRib3guZXhlYyh7XG4gICAgICAgICAgICBjb21tYW5kOiBcImdyZXBcIixcbiAgICAgICAgICAgIGFyZ3M6IGdyZXBBcmdzLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICAgICAgbG9nLmVycm9yKFwiR3JlcCBmYWlsZWRcIiwgeyBlcnJvcjogcmVzdWx0Lm1lc3NhZ2UgfSk7XG4gICAgICAgICAgdGhyb3cgcmVzdWx0O1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgeyBzdGRvdXQsIHN0ZGVyciB9ID0gYXdhaXQgcmVzdWx0LnJlc3VsdDtcblxuICAgICAgICBpZiAoc3RkZXJyICYmICFzdGRlcnIudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhcIm5vIG1hdGNoZXNcIikpIHtcbiAgICAgICAgICBsb2cud2FybihcIkdyZXAgc3RkZXJyXCIsIHsgc3RkZXJyIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gVHJ1bmNhdGUgb3V0cHV0IHRvIHByZXZlbnQgXCJpbnB1dCB0b28gbG9uZ1wiIGVycm9ycyAoNTBrIGNoYXJzIFx1MjI0OCAxMi41ayB0b2tlbnMpXG4gICAgICAgIGNvbnN0IE1BWF9HUkVQX09VVFBVVF9DSEFSUyA9IDUwXzAwMDtcbiAgICAgICAgbGV0IGZpbmFsT3V0cHV0ID0gc3Rkb3V0O1xuICAgICAgICBsZXQgd2FzVHJ1bmNhdGVkID0gZmFsc2U7XG4gICAgICAgIGlmIChmaW5hbE91dHB1dC5sZW5ndGggPiBNQVhfR1JFUF9PVVRQVVRfQ0hBUlMpIHtcbiAgICAgICAgICBmaW5hbE91dHB1dCA9XG4gICAgICAgICAgICBmaW5hbE91dHB1dC5zbGljZSgwLCBNQVhfR1JFUF9PVVRQVVRfQ0hBUlMpICtcbiAgICAgICAgICAgIFwiXFxuXFxuW091dHB1dCB0cnVuY2F0ZWQgLSB1c2UgbW9yZSBzcGVjaWZpYyBwYXR0ZXJuIG9yIHBhdGhdXCI7XG4gICAgICAgICAgd2FzVHJ1bmNhdGVkID0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGxpbmVzID0gZmluYWxPdXRwdXRcbiAgICAgICAgICAudHJpbSgpXG4gICAgICAgICAgLnNwbGl0KFwiXFxuXCIpXG4gICAgICAgICAgLmZpbHRlcigobCkgPT4gbC5sZW5ndGggPiAwKTtcbiAgICAgICAgY29uc3QgZmlsZUNvdW50ID0gZmlsZXNXaXRoTWF0Y2hlc1xuICAgICAgICAgID8gbGluZXMubGVuZ3RoXG4gICAgICAgICAgOiBuZXcgU2V0KFxuICAgICAgICAgICAgICBsaW5lc1xuICAgICAgICAgICAgICAgIC5maWx0ZXIoKGwpID0+ICFsLnN0YXJ0c1dpdGgoXCIgXCIpICYmIGwuaW5jbHVkZXMoXCI6XCIpKVxuICAgICAgICAgICAgICAgIC5tYXAoKGwpID0+IGwuc3BsaXQoXCI6XCIpWzBdKVxuICAgICAgICAgICAgKS5zaXplO1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc3VtbWFyeToge1xuICAgICAgICAgICAgbWF0Y2hDb3VudDogZmlsZXNXaXRoTWF0Y2hlc1xuICAgICAgICAgICAgICA/IDBcbiAgICAgICAgICAgICAgOiBsaW5lcy5maWx0ZXIoKGwpID0+IGwuaW5jbHVkZXMoXCI6XCIpKS5sZW5ndGgsXG4gICAgICAgICAgICBmaWxlQ291bnQsXG4gICAgICAgICAgICBzZWFyY2hQYXRoLFxuICAgICAgICAgICAgcGF0dGVybixcbiAgICAgICAgICAgIHdhc1RydW5jYXRlZCxcbiAgICAgICAgICB9LFxuICAgICAgICAgIG1hdGNoZXM6IGZpbmFsT3V0cHV0IHx8IFwiKG5vIG1hdGNoZXMgZm91bmQpXCIsXG4gICAgICAgIH07XG4gICAgICB9LFxuICAgIH0pLFxuICAgIFtidWlsdGluVG9vbE5hbWVzLkxpc3RdOiB0b29sKHtcbiAgICAgIC4uLmJ1aWx0SW5Ub29scy5MaXN0LFxuICAgICAgZXhlY3V0ZTogYXN5bmMgKHsgcGF0aCwgZGVwdGgsIGluY2x1ZGVIaWRkZW4sIGZpbGVzT25seSwgcGF0dGVybiB9KSA9PiB7XG4gICAgICAgIGNvbnN0IHNlYXJjaFBhdGggPSBwYXRoID8/IFwiLlwiO1xuXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNvbnRleHQuc2FuZGJveC5leGVjKHtcbiAgICAgICAgICBjb21tYW5kOiBcImJhc2hcIixcbiAgICAgICAgICBhcmdzOiBbXG4gICAgICAgICAgICBcIi1jXCIsXG4gICAgICAgICAgICBgXG4gICAgICAgICAgICBzZXQgLWVcbiAgICAgICAgICAgIFNFQVJDSF9QQVRIPVwiJDFcIlxuICAgICAgICAgICAgREVQVEg9XCIkMlwiXG4gICAgICAgICAgICBJTkNMVURFX0hJRERFTj1cIiQzXCJcbiAgICAgICAgICAgIEZJTEVTX09OTFk9XCIkNFwiXG4gICAgICAgICAgICBQQVRURVJOPVwiJDVcIlxuXG4gICAgICAgICAgICAjIEJ1aWxkIGZpbmQgY29tbWFuZCBhcmd1bWVudHNcbiAgICAgICAgICAgIEZJTkRfQVJHUz1cIlwiXG4gICAgICAgICAgICBbIC1uIFwiJERFUFRIXCIgXSAmJiBGSU5EX0FSR1M9XCIkRklORF9BUkdTIC1tYXhkZXB0aCAkREVQVEhcIlxuICAgICAgICAgICAgWyBcIiRJTkNMVURFX0hJRERFTlwiICE9IFwidHJ1ZVwiIF0gJiYgRklORF9BUkdTPVwiJEZJTkRfQVJHUyAhIC1wYXRoICcqLy4qJ1wiXG4gICAgICAgICAgICBbIFwiJEZJTEVTX09OTFlcIiA9IFwidHJ1ZVwiIF0gJiYgRklORF9BUkdTPVwiJEZJTkRfQVJHUyAtdHlwZSBmXCJcbiAgICAgICAgICAgIFsgLW4gXCIkUEFUVEVSTlwiIF0gJiYgRklORF9BUkdTPVwiJEZJTkRfQVJHUyAtbmFtZSAnJFBBVFRFUk4nXCJcblxuICAgICAgICAgICAgIyBHZXQgbGlzdGluZ1xuICAgICAgICAgICAgTElTVElORz0kKGV2YWwgXCJmaW5kICckU0VBUkNIX1BBVEgnICRGSU5EX0FSR1NcIiAyPi9kZXYvbnVsbCB8IHNvcnQpXG5cbiAgICAgICAgICAgICMgR2V0IGNvdW50c1xuICAgICAgICAgICAgQ09VTlRfQVJHUz1cIlwiXG4gICAgICAgICAgICBbIC1uIFwiJERFUFRIXCIgXSAmJiBDT1VOVF9BUkdTPVwiJENPVU5UX0FSR1MgLW1heGRlcHRoICRERVBUSFwiXG4gICAgICAgICAgICBbIFwiJElOQ0xVREVfSElEREVOXCIgIT0gXCJ0cnVlXCIgXSAmJiBDT1VOVF9BUkdTPVwiJENPVU5UX0FSR1MgISAtcGF0aCAnKi8uKidcIlxuXG4gICAgICAgICAgICBGSUxFX0NPVU5UPSQoZXZhbCBcImZpbmQgJyRTRUFSQ0hfUEFUSCcgJENPVU5UX0FSR1MgLXR5cGUgZlwiIDI+L2Rldi9udWxsIHwgd2MgLWwpXG4gICAgICAgICAgICBESVJfQ09VTlQ9JChldmFsIFwiZmluZCAnJFNFQVJDSF9QQVRIJyAkQ09VTlRfQVJHUyAtdHlwZSBkXCIgMj4vZGV2L251bGwgfCB3YyAtbClcblxuICAgICAgICAgICAgIyBPdXRwdXQ6IGNvdW50cyBmaXJzdCwgdGhlbiBsaXN0aW5nXG4gICAgICAgICAgICBlY2hvIFwiJEZJTEVfQ09VTlR8JERJUl9DT1VOVFwiXG4gICAgICAgICAgICBlY2hvIFwifHx8TElTVElOR3x8fFwiXG4gICAgICAgICAgICBlY2hvIFwiJExJU1RJTkdcIiB8IHNlZCBcInN8XiRTRUFSQ0hfUEFUSHwufFwiXG4gICAgICAgICAgYCxcbiAgICAgICAgICAgIFwiLS1cIixcbiAgICAgICAgICAgIHNlYXJjaFBhdGgsXG4gICAgICAgICAgICBkZXB0aD8udG9TdHJpbmcoKSB8fCBcIlwiLFxuICAgICAgICAgICAgaW5jbHVkZUhpZGRlbiA/IFwidHJ1ZVwiIDogXCJmYWxzZVwiLFxuICAgICAgICAgICAgZmlsZXNPbmx5ID8gXCJ0cnVlXCIgOiBcImZhbHNlXCIsXG4gICAgICAgICAgICBwYXR0ZXJuIHx8IFwiXCIsXG4gICAgICAgICAgXSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICAgICAgbG9nLmVycm9yKFwiTGlzdCBmYWlsZWRcIiwgeyBlcnJvcjogcmVzdWx0Lm1lc3NhZ2UgfSk7XG4gICAgICAgICAgdGhyb3cgcmVzdWx0O1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgeyBzdGRvdXQsIHN0ZGVyciB9ID0gYXdhaXQgcmVzdWx0LnJlc3VsdDtcblxuICAgICAgICBpZiAoc3RkZXJyKSB7XG4gICAgICAgICAgbG9nLndhcm4oXCJMaXN0IHN0ZGVyclwiLCB7IHN0ZGVyciB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IFtjb3VudHNMaW5lLCAuLi5yZXN0XSA9IHN0ZG91dC5zcGxpdChcInx8fExJU1RJTkd8fHxcIik7XG4gICAgICAgIGNvbnN0IGxpc3RpbmcgPSByZXN0LmpvaW4oXCJ8fHxMSVNUSU5HfHx8XCIpLnRyaW0oKTtcbiAgICAgICAgY29uc3QgW2ZpbGVDb3VudFN0ciwgZGlyQ291bnRTdHJdID0gY291bnRzTGluZS50cmltKCkuc3BsaXQoXCJ8XCIpO1xuXG4gICAgICAgIGNvbnN0IHRvdGFsRmlsZXMgPSBOdW1iZXIucGFyc2VJbnQoZmlsZUNvdW50U3RyLCAxMCkgfHwgMDtcbiAgICAgICAgY29uc3QgdG90YWxEaXJzID0gTnVtYmVyLnBhcnNlSW50KGRpckNvdW50U3RyLCAxMCkgfHwgMDtcbiAgICAgICAgY29uc3QgbGluZXMgPSBsaXN0aW5nLnNwbGl0KFwiXFxuXCIpLmZpbHRlcigobCkgPT4gbC5sZW5ndGggPiAwKTtcblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHN1bW1hcnk6IHtcbiAgICAgICAgICAgIHRvdGFsSXRlbXM6IGxpbmVzLmxlbmd0aCxcbiAgICAgICAgICAgIHRvdGFsRmlsZXMsXG4gICAgICAgICAgICB0b3RhbERpcnMsXG4gICAgICAgICAgICBzZWFyY2hQYXRoLFxuICAgICAgICAgICAgZGVwdGgsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBsaXN0aW5nLFxuICAgICAgICB9O1xuICAgICAgfSxcbiAgICB9KSxcbiAgICBbYnVpbHRpblRvb2xOYW1lcy5Xcml0ZV06IHRvb2woe1xuICAgICAgLi4uYnVpbHRJblRvb2xzLldyaXRlLFxuICAgICAgZXhlY3V0ZTogYXN5bmMgKHsgcGF0aCwgY29udGVudCB9KSA9PiB7XG4gICAgICAgIGNvbnN0IGZpbGVQYXRoID0gcGF0aDtcbiAgICAgICAgY29uc3QgZGlyID0gcGF0aFBvc2l4LmRpcm5hbWUoZmlsZVBhdGgpO1xuICAgICAgICBjb25zdCBmaWxlTmFtZSA9IHBhdGhQb3NpeC5iYXNlbmFtZShmaWxlUGF0aCk7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBpZiAoZGlyICE9PSBcIi5cIikge1xuICAgICAgICAgICAgYXdhaXQgY29udGV4dC5zYW5kYm94LmV4ZWMoeyBjb21tYW5kOiBcIm1rZGlyXCIsIGFyZ3M6IFtcIi1wXCIsIGRpcl0gfSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgYXdhaXQgY29udGV4dC5zYW5kYm94LndyaXRlRmlsZXMoe1xuICAgICAgICAgICAgZmlsZXM6IFt7IHBhdGg6IGZpbGVOYW1lLCBjb250ZW50IH1dLFxuICAgICAgICAgICAgZGVzdFBhdGg6IGRpcixcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgICAgcGF0aDogZmlsZVBhdGgsXG4gICAgICAgICAgICBieXRlc1dyaXR0ZW46IEJ1ZmZlci5ieXRlTGVuZ3RoKGNvbnRlbnQsIFwidXRmOFwiKSxcbiAgICAgICAgICB9O1xuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICBjb25zdCBlcnJvck1zZyA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICBwYXRoOiBmaWxlUGF0aCxcbiAgICAgICAgICAgIGJ5dGVzV3JpdHRlbjogMCxcbiAgICAgICAgICAgIGVycm9yOiBlcnJvck1zZyxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9LFxuICAgIH0pLFxuICAgIFtidWlsdGluVG9vbE5hbWVzLkVkaXRdOiB0b29sKHtcbiAgICAgIC4uLmJ1aWx0SW5Ub29scy5FZGl0LFxuICAgICAgZXhlY3V0ZTogYXN5bmMgKHsgcGF0aCwgb2xkX3N0cmluZywgbmV3X3N0cmluZyB9KSA9PiB7XG4gICAgICAgIGNvbnN0IGZpbGVQYXRoID0gcGF0aDtcblxuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBjb250ZXh0LnNhbmRib3gucmVhZEZpbGUoeyBwYXRoOiBmaWxlUGF0aCB9KTtcblxuICAgICAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgcGF0aDogZmlsZVBhdGgsIGVycm9yOiByZXN1bHQubWVzc2FnZSB9O1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHJlc3VsdCA9PT0gbnVsbCkge1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgIHBhdGg6IGZpbGVQYXRoLFxuICAgICAgICAgICAgZXJyb3I6IGBGaWxlIG5vdCBmb3VuZDogJHtmaWxlUGF0aH1gLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjb250ZW50ID0gcmVzdWx0LnRvU3RyaW5nKFwidXRmLThcIik7XG4gICAgICAgIGNvbnN0IG9jY3VycmVuY2VzID0gY29udGVudC5zcGxpdChvbGRfc3RyaW5nKS5sZW5ndGggLSAxO1xuXG4gICAgICAgIGlmIChvY2N1cnJlbmNlcyA9PT0gMCkge1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgIHBhdGg6IGZpbGVQYXRoLFxuICAgICAgICAgICAgZXJyb3I6IFwib2xkX3N0cmluZyBub3QgZm91bmQgaW4gZmlsZVwiLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICBpZiAob2NjdXJyZW5jZXMgPiAxKSB7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgcGF0aDogZmlsZVBhdGgsXG4gICAgICAgICAgICBlcnJvcjogYG9sZF9zdHJpbmcgYXBwZWFycyAke29jY3VycmVuY2VzfSB0aW1lcyBpbiBmaWxlIChtdXN0IGJlIHVuaXF1ZSkuIEluY2x1ZGUgbW9yZSBzdXJyb3VuZGluZyBjb250ZXh0IHRvIG1ha2UgdGhlIG1hdGNoIHVuaXF1ZS5gLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBuZXdDb250ZW50ID0gY29udGVudC5yZXBsYWNlKG9sZF9zdHJpbmcsIG5ld19zdHJpbmcpO1xuICAgICAgICBjb25zdCBkaXIgPSBwYXRoUG9zaXguZGlybmFtZShmaWxlUGF0aCk7XG4gICAgICAgIGNvbnN0IGZpbGVOYW1lID0gcGF0aFBvc2l4LmJhc2VuYW1lKGZpbGVQYXRoKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IGNvbnRleHQuc2FuZGJveC53cml0ZUZpbGVzKHtcbiAgICAgICAgICAgIGZpbGVzOiBbeyBwYXRoOiBmaWxlTmFtZSwgY29udGVudDogbmV3Q29udGVudCB9XSxcbiAgICAgICAgICAgIGRlc3RQYXRoOiBkaXIsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICByZXR1cm4geyBzdWNjZXNzOiB0cnVlLCBwYXRoOiBmaWxlUGF0aCB9O1xuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICBjb25zdCBlcnJvck1zZyA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKTtcbiAgICAgICAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgcGF0aDogZmlsZVBhdGgsIGVycm9yOiBlcnJvck1zZyB9O1xuICAgICAgICB9XG4gICAgICB9LFxuICAgIH0pLFxuICAgIFtidWlsdGluVG9vbE5hbWVzLkJhc2hdOiB0b29sKHtcbiAgICAgIC4uLmJ1aWx0SW5Ub29scy5CYXNoLFxuICAgICAgZXhlY3V0ZTogYXN5bmMgKHsgY29tbWFuZCwgd2FpdFVudGlsIH0pID0+IHtcbiAgICAgICAgY29uc3QgeyBjcmVhdGVQcm9jZXNzTWFuYWdlciB9ID0gYXdhaXQgaW1wb3J0KFxuICAgICAgICAgIFwiLi4vc2FuZGJveC9wcm9jZXNzLW1hbmFnZXJcIlxuICAgICAgICApO1xuXG4gICAgICAgIGNvbnN0IHByb2Nlc3NNYW5hZ2VyID0gY3JlYXRlUHJvY2Vzc01hbmFnZXIoe1xuICAgICAgICAgIHNhbmRib3g6IGNvbnRleHQuc2FuZGJveCxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHJvY2Vzc01hbmFnZXIucnVuKHsgY29tbWFuZCwgd2FpdFVudGlsIH0pO1xuXG4gICAgICAgIGNvbnN0IE1BWF9TVERPVVQgPSA1MF8wMDA7XG4gICAgICAgIGNvbnN0IE1BWF9TVERFUlIgPSAxMF8wMDA7XG5cbiAgICAgICAgbGV0IHsgc3Rkb3V0LCBzdGRlcnIgfSA9IHJlc3VsdDtcbiAgICAgICAgaWYgKHN0ZG91dC5sZW5ndGggPiBNQVhfU1RET1VUKSB7XG4gICAgICAgICAgc3Rkb3V0ID1cbiAgICAgICAgICAgIGBbdHJ1bmNhdGVkIFx1MjAxNCBzaG93aW5nIGxhc3QgJHtNQVhfU1RET1VUfSBjaGFycy4gRnVsbDogJHtyZXN1bHQub3V0cHV0RGlyfS9zdGRvdXQudHh0XVxcblxcbmAgK1xuICAgICAgICAgICAgc3Rkb3V0LnNsaWNlKC1NQVhfU1RET1VUKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoc3RkZXJyLmxlbmd0aCA+IE1BWF9TVERFUlIpIHtcbiAgICAgICAgICBzdGRlcnIgPVxuICAgICAgICAgICAgYFt0cnVuY2F0ZWQgXHUyMDE0IHNob3dpbmcgbGFzdCAke01BWF9TVERFUlJ9IGNoYXJzLiBGdWxsOiAke3Jlc3VsdC5vdXRwdXREaXJ9L3N0ZGVyci50eHRdXFxuXFxuYCArXG4gICAgICAgICAgICBzdGRlcnIuc2xpY2UoLU1BWF9TVERFUlIpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHsgLi4ucmVzdWx0LCBzdGRvdXQsIHN0ZGVyciB9O1xuICAgICAgfSxcbiAgICB9KSxcbiAgfTtcblxuICBpZiAoY29udGV4dC5zZXNzaW9uLnNraWxsc0Rpcj8ubGVuZ3RoKSB7XG4gICAgdG9vbHNbYnVpbHRpblRvb2xOYW1lcy5Ta2lsbF0gPSB0b29sKHtcbiAgICAgIC4uLmJ1aWx0SW5Ub29scy5Ta2lsbCxcbiAgICAgIGV4ZWN1dGU6IGFzeW5jICh7IG5hbWUgfSkgPT4ge1xuICAgICAgICBjb25zdCBza2lsbHMgPSBjb250ZXh0LnNraWxsc1JlZi5jdXJyZW50O1xuICAgICAgICBjb25zdCBza2lsbCA9IHNraWxscy5maW5kKFxuICAgICAgICAgIChzKSA9PiBzLm5hbWUudG9Mb3dlckNhc2UoKSA9PT0gbmFtZS50b0xvd2VyQ2FzZSgpXG4gICAgICAgICk7XG4gICAgICAgIGlmICghc2tpbGwpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICBgU2tpbGwgbm90IGZvdW5kOiBcIiR7bmFtZX1cIi4gQXZhaWxhYmxlOiAke3NraWxscy5tYXAoKHMpID0+IHMubmFtZSkuam9pbihcIiwgXCIpfWBcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNvbnRleHQuc2FuZGJveC5yZWFkRmlsZSh7XG4gICAgICAgICAgcGF0aDogc2tpbGwuc2tpbGxNZFBhdGgsXG4gICAgICAgIH0pO1xuICAgICAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgICB0aHJvdyByZXN1bHQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHJlc3VsdCA9PT0gbnVsbCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgU2tpbGwgZmlsZSBub3QgZm91bmQ6ICR7c2tpbGwuc2tpbGxNZFBhdGh9YCk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgcmF3ID1cbiAgICAgICAgICB0eXBlb2YgcmVzdWx0ID09PSBcInN0cmluZ1wiID8gcmVzdWx0IDogcmVzdWx0LnRvU3RyaW5nKFwidXRmLThcIik7XG4gICAgICAgIGNvbnN0IGVuZE1hcmtlciA9IHJhdy5pbmRleE9mKFwiLS0tXCIsIDMpO1xuICAgICAgICBjb25zdCBjb250ZW50ID1cbiAgICAgICAgICBlbmRNYXJrZXIgPT09IC0xID8gcmF3IDogcmF3LnNsaWNlKGVuZE1hcmtlciArIDMpLnRyaW0oKTtcbiAgICAgICAgY29uc3Qgc2tpbGxEaXIgPSBza2lsbC5za2lsbE1kUGF0aC5yZXBsYWNlKFNLSUxMX01EX1NVRkZJWCwgXCJcIik7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgbmFtZTogc2tpbGwubmFtZSxcbiAgICAgICAgICBkZXNjcmlwdGlvbjogc2tpbGwuZGVzY3JpcHRpb24sXG4gICAgICAgICAgY29udGVudCxcbiAgICAgICAgICBwYXRoOiBza2lsbERpcixcbiAgICAgICAgfTtcbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cblxuICBpZiAoY29udGV4dC5hcGlUb29sc01ldGFkYXRhLmxlbmd0aCA+IDApIHtcbiAgICBjb25zdCBhcGlUb29scyA9IGJ1aWxkQXBpVG9vbHMoe1xuICAgICAgcnBjOiBjb250ZXh0LmlucHV0LnJwYyxcbiAgICAgIG1ldGFkYXRhOiBjb250ZXh0LmFwaVRvb2xzTWV0YWRhdGEsXG4gICAgICBzZXNzaW9uOiBjb250ZXh0LnNlc3Npb24sXG4gICAgICBzYW5kYm94UmVjb3JkOiBjb250ZXh0LnNhbmRib3hSZWNvcmQsXG4gICAgICBjb250ZXh0OiBjb250ZXh0LmV2ZW50LmNvbnRleHQsXG4gICAgfSk7XG4gICAgT2JqZWN0LmFzc2lnbih0b29scywgYXBpVG9vbHMpO1xuICB9XG5cbiAgdG9vbHNbYnVpbHRpblRvb2xOYW1lcy5KYXZhU2NyaXB0XSA9IGNyZWF0ZUphdmFTY3JpcHRUb29sKHtcbiAgICB0b29scyxcbiAgICBzZXNzaW9uOiBjb250ZXh0LnNlc3Npb24sXG4gICAgc2FuZGJveDogY29udGV4dC5zYW5kYm94LFxuICAgIG9uU3ViVG9vbENhbGw6IGNvbnRleHQub25TdWJUb29sQ2FsbCxcbiAgfSk7XG5cbiAgcmV0dXJuIHRvb2xzO1xufVxuXG50eXBlIEFwaVRvb2xNZXRhZGF0YSA9IHtcbiAgbmFtZTogc3RyaW5nO1xuICBkZXNjcmlwdGlvbj86IHN0cmluZztcbiAgaW5wdXRTY2hlbWE/OiB1bmtub3duO1xufTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGZldGNoQXBpVG9vbHNNZXRhZGF0YShvcHRzOiB7XG4gIHJwYzogKHBhcmFtczogUnBjUGF5bG9hZCkgPT4gUHJvbWlzZTxScGNSZXN1bHQ+O1xufSk6IFByb21pc2U8QXBpVG9vbE1ldGFkYXRhW10+IHtcbiAgY29uc3QgeyBycGMgfSA9IG9wdHM7XG5cbiAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcnBjKHsgbWV0aG9kOiBcInRvb2xzLmxpc3RcIiwgcGFyYW1zOiB7fSB9KTtcblxuICBpZiAoXCJlcnJvclwiIGluIHJlc3VsdCkge1xuICAgIGxvZy5lcnJvcihcImZhaWxlZCB0byBmZXRjaCB0b29sc1wiLCB7IGVycm9yOiByZXN1bHQuZXJyb3I/Lm1lc3NhZ2UgfSk7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgcmV0dXJuIChyZXN1bHQucmVzdWx0IGFzIEFwaVRvb2xNZXRhZGF0YVtdKSA/PyBbXTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkQXBpVG9vbHMob3B0czoge1xuICBycGM6IChwYXJhbXM6IFJwY1BheWxvYWQpID0+IFByb21pc2U8UnBjUmVzdWx0PjtcbiAgbWV0YWRhdGE6IEFwaVRvb2xNZXRhZGF0YVtdO1xuICBzZXNzaW9uOiBTZXNzaW9uO1xuICBzYW5kYm94UmVjb3JkOiBTYW5kYm94UmVjb3JkO1xuICBjb250ZXh0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbn0pOiBUb29sU2V0IHtcbiAgY29uc3QgeyBycGMsIG1ldGFkYXRhLCBzZXNzaW9uLCBzYW5kYm94UmVjb3JkLCBjb250ZXh0IH0gPSBvcHRzO1xuICBjb25zdCB0b29sczogVG9vbFNldCA9IHt9O1xuXG4gIGZvciAoY29uc3QgbWV0YSBvZiBtZXRhZGF0YSkge1xuICAgIHRvb2xzW21ldGEubmFtZV0gPSB0b29sKHtcbiAgICAgIGRlc2NyaXB0aW9uOiBtZXRhLmRlc2NyaXB0aW9uID8/IGBDdXN0b20gdG9vbDogJHttZXRhLm5hbWV9YCxcbiAgICAgIGlucHV0U2NoZW1hOiBtZXRhLmlucHV0U2NoZW1hXG4gICAgICAgID8ganNvblNjaGVtYShtZXRhLmlucHV0U2NoZW1hIGFzIFBhcmFtZXRlcnM8dHlwZW9mIGpzb25TY2hlbWE+WzBdKVxuICAgICAgICA6IHoub2JqZWN0KHt9KSxcbiAgICAgIGV4ZWN1dGU6IGFzeW5jIChpbnB1dCkgPT4ge1xuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBycGMoe1xuICAgICAgICAgIG1ldGhvZDogXCJ0b29scy5leGVjdXRlXCIsXG4gICAgICAgICAgcGFyYW1zOiB7XG4gICAgICAgICAgICBuYW1lOiBtZXRhLm5hbWUsXG4gICAgICAgICAgICBpbnB1dCxcbiAgICAgICAgICAgIHNlc3Npb24sXG4gICAgICAgICAgICBzYW5kYm94UmVjb3JkLFxuICAgICAgICAgICAgY29udGV4dCxcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoXCJlcnJvclwiIGluIHJlc3VsdCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVG9vbCBleGVjdXRpb24gZmFpbGVkOiAke3Jlc3VsdC5lcnJvcj8ubWVzc2FnZX1gKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXN1bHQucmVzdWx0O1xuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiB0b29scztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVBcGlVcmwob3B0czogeyBhcGk6IHN0cmluZyB8IHVuZGVmaW5lZCB9KTogc3RyaW5nIHtcbiAgbGV0IG9yaWdpbiA9IFwiXCI7XG4gIGxldCBwYXRoID0gYC8ud2VsbC1rbm93bi9hZ2VudC8ke0FHRU5UX1BST1RPQ09MX1ZFUlNJT059YDtcblxuICBpZiAob3B0cy5hcGkpIHtcbiAgICBpZiAob3B0cy5hcGkuc3RhcnRzV2l0aChcIi9cIikpIHtcbiAgICAgIHBhdGggPSBvcHRzLmFwaTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gc2VlIGlmIGl0J3MgZnVsbFxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgdXJsID0gbmV3IFVSTChvcHRzLmFwaSk7XG4gICAgICAgIG9yaWdpbiA9IHVybC5vcmlnaW47XG4gICAgICAgIGNvbnN0IGZ1bGxQYXRoID0gdXJsLnBhdGhuYW1lICsgdXJsLnNlYXJjaCArIHVybC5oYXNoO1xuICAgICAgICBpZiAoZnVsbFBhdGguc3RhcnRzV2l0aChcIi9cIikgJiYgZnVsbFBhdGggIT09IFwiL1wiKSB7XG4gICAgICAgICAgcGF0aCA9IGZ1bGxQYXRoO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLy8gbm9vcFxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGlmICghb3JpZ2luKSB7XG4gICAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSBcImRldmVsb3BtZW50XCIpIHtcbiAgICAgIG9yaWdpbiA9IGBodHRwOi8vbG9jYWxob3N0OiR7XG4gICAgICAgIHByb2Nlc3MuZW52LlBPUlQgPz8gcHJvY2Vzcy5lbnYuTkVYVF9QVUJMSUNfUE9SVCA/PyAzMDAwXG4gICAgICB9YDtcbiAgICB9XG4gICAgY29uc3QgdmVyY2VsVXJsID1cbiAgICAgIHByb2Nlc3MuZW52LlZFUkNFTF9VUkwgPz8gcHJvY2Vzcy5lbnYuTkVYVF9QVUJMSUNfVkVSQ0VMX1VSTDtcbiAgICBpZiAodmVyY2VsVXJsKSB7XG4gICAgICBvcmlnaW4gPSBgaHR0cHM6Ly8ke3ZlcmNlbFVybH1gO1xuICAgIH1cbiAgfVxuXG4gIGlmICghb3JpZ2luKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgXCJbYWdlbnRdIENvdWxkbid0IGRldGVybWluZSBBUEkgb3JpZ2luIChubyBvcmlnaW4gZGV0ZWN0ZWQgaW4gYGFwaWAgb3B0aW9uIGFuZCBubyBWRVJDRUxfVVJMIHNldClcIlxuICAgICk7XG4gIH1cblxuICByZXR1cm4gYCR7b3JpZ2lufSR7cGF0aH1gO1xufVxuIiwgImltcG9ydCB7IHR5cGUgVG9vbFNldCwgdG9vbCB9IGZyb20gXCJhaVwiO1xuaW1wb3J0IHsgeiB9IGZyb20gXCJ6b2RcIjtcbmltcG9ydCB0eXBlIHsgU2FuZGJveCB9IGZyb20gXCIuLi9zYW5kYm94XCI7XG5pbXBvcnQgdHlwZSB7IFNlc3Npb24gfSBmcm9tIFwiLi4vc3RvcmFnZVwiO1xuaW1wb3J0IHsgYnVpbHRJblRvb2xzIH0gZnJvbSBcIi5cIjtcblxuZXhwb3J0IGNvbnN0IEpBVkFTQ1JJUFRfVE9PTF9OQU1FID0gXCJKYXZhU2NyaXB0XCI7XG5cbmV4cG9ydCB0eXBlIFN1YlRvb2xDYWxsUmVzdWx0ID0geyByZXN1bHQ/OiB1bmtub3duOyBlcnJvcj86IHN0cmluZyB9O1xuZXhwb3J0IHR5cGUgT25TdWJUb29sQ2FsbCA9IChcbiAgdG9vbE5hbWU6IHN0cmluZyxcbiAgaW5wdXQ6IHVua25vd24sXG4gIGV4ZWN1dGU6ICgpID0+IFByb21pc2U8dW5rbm93bj5cbikgPT4gUHJvbWlzZTxTdWJUb29sQ2FsbFJlc3VsdD47XG5cbmNvbnN0IFJFUVVFU1RfTUFSS0VSX1NUQVJUID0gXCJfX1RPT0xfUkVRVUVTVF9fXCI7XG5jb25zdCBSRVFVRVNUX01BUktFUl9FTkQgPSBcIl9fVE9PTF9SRVFVRVNUX0VORF9fXCI7XG5jb25zdCBFWEVDVVRJT05fVElNRU9VVF9NUyA9IDUgKiA2MCAqIDEwMDA7XG5cbi8qKlxuICogVGhlIHJ1bm5lciBzY3JpcHQgaXMgd3JpdHRlbiB0byB0aGUgc2FuZGJveCBhbmQgZXhlY3V0ZWQgdmlhIE5vZGUuanMuXG4gKiBJdCByZWFkcyB0aGUgbW9kZWwncyBjb2RlIGZyb20gY29kZS5qcywgc2V0cyB1cCBjdHgudG9vbHMgYXMgUlBDIHByb3hpZXNcbiAqIChyZXF1ZXN0cyBzZW50IHZpYSBzdGRlcnIgbWFya2VycywgcmVzcG9uc2VzIHBvbGxlZCBmcm9tIGZpbGVzKSwgZXhlY3V0ZXNcbiAqIHRoZSBjb2RlLCBhbmQgd3JpdGVzIHRoZSByZXN1bHQgdG8gc3Rkb3V0IGFzIEpTT04uXG4gKi9cbmNvbnN0IFJVTk5FUl9TQ1JJUFQgPSBgXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIGV4aXN0c1N5bmMsIHVubGlua1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ25vZGU6ZnMnO1xuaW1wb3J0IHsgam9pbiwgZGlybmFtZSB9IGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAnbm9kZTp1cmwnO1xuXG5jb25zdCBTQ1JJUFRfRElSID0gZGlybmFtZShmaWxlVVJMVG9QYXRoKGltcG9ydC5tZXRhLnVybCkpO1xuY29uc3QgVE9PTF9DQUxMX1RJTUVPVVRfTVMgPSAzMDBfMDAwO1xuXG5sZXQgcmVxQ291bnRlciA9IDA7XG5cbmFzeW5jIGZ1bmN0aW9uIGNhbGxUb29sKG5hbWUsIGlucHV0KSB7XG4gIGNvbnN0IGlkID0gJ3JlcV8nICsgKCsrcmVxQ291bnRlcikgKyAnXycgKyBEYXRlLm5vdygpO1xuICBjb25zdCByZXNwb25zZUZpbGUgPSBqb2luKFNDUklQVF9ESVIsIGlkICsgJy5yZXNwb25zZS5qc29uJyk7XG5cbiAgY29uc3QgcmVxdWVzdCA9IEpTT04uc3RyaW5naWZ5KHsgaWQsIHRvb2w6IG5hbWUsIGlucHV0IH0pO1xuICBwcm9jZXNzLnN0ZGVyci53cml0ZSgnJHtSRVFVRVNUX01BUktFUl9TVEFSVH0nICsgcmVxdWVzdCArICcke1JFUVVFU1RfTUFSS0VSX0VORH0nICsgJ1xcXFxuJyk7XG5cbiAgY29uc3Qgc3RhcnQgPSBEYXRlLm5vdygpO1xuICB3aGlsZSAoIWV4aXN0c1N5bmMocmVzcG9uc2VGaWxlKSkge1xuICAgIGlmIChEYXRlLm5vdygpIC0gc3RhcnQgPiBUT09MX0NBTExfVElNRU9VVF9NUykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdUb29sIGNhbGwgJyArIG5hbWUgKyAnIHRpbWVkIG91dCB3YWl0aW5nIGZvciByZXNwb25zZScpO1xuICAgIH1cbiAgICBhd2FpdCBuZXcgUHJvbWlzZShyID0+IHNldFRpbWVvdXQociwgMzApKTtcbiAgfVxuXG4gIGxldCByYXc7XG4gIHRyeSB7XG4gICAgcmF3ID0gcmVhZEZpbGVTeW5jKHJlc3BvbnNlRmlsZSwgJ3V0ZjgnKTtcbiAgfSBjYXRjaCB7XG4gICAgYXdhaXQgbmV3IFByb21pc2UociA9PiBzZXRUaW1lb3V0KHIsIDUwKSk7XG4gICAgcmF3ID0gcmVhZEZpbGVTeW5jKHJlc3BvbnNlRmlsZSwgJ3V0ZjgnKTtcbiAgfVxuXG4gIGNvbnN0IHJlc3BvbnNlID0gSlNPTi5wYXJzZShyYXcpO1xuICB0cnkgeyB1bmxpbmtTeW5jKHJlc3BvbnNlRmlsZSk7IH0gY2F0Y2gge31cblxuICBpZiAocmVzcG9uc2UuZXJyb3IpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IocmVzcG9uc2UuZXJyb3IpO1xuICB9XG4gIHJldHVybiByZXNwb25zZS5yZXN1bHQ7XG59XG5cbmNvbnN0IGNvZGUgPSByZWFkRmlsZVN5bmMoam9pbihTQ1JJUFRfRElSLCAnY29kZS5qcycpLCAndXRmOCcpO1xuY29uc3QgdG9vbE5hbWVzID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoam9pbihTQ1JJUFRfRElSLCAndG9vbHMuanNvbicpLCAndXRmOCcpKTtcblxuY29uc3QgY3R4ID0geyB0b29sczoge30gfTtcbmZvciAoY29uc3QgbmFtZSBvZiB0b29sTmFtZXMpIHtcbiAgY3R4LnRvb2xzW25hbWVdID0gKGlucHV0KSA9PiBjYWxsVG9vbChuYW1lLCBpbnB1dCk7XG59XG5cbmNvbnN0IGxvZ3MgPSBbXTtcbmNvbnN0IGN1c3RvbUNvbnNvbGUgPSB7XG4gIGxvZzogKC4uLmFyZ3MpID0+IGxvZ3MucHVzaChhcmdzLm1hcChhID0+IHR5cGVvZiBhID09PSAnc3RyaW5nJyA/IGEgOiBKU09OLnN0cmluZ2lmeShhKSkuam9pbignICcpKSxcbiAgZXJyb3I6ICguLi5hcmdzKSA9PiBsb2dzLnB1c2goJ1tlcnJvcl0gJyArIGFyZ3MubWFwKGEgPT4gdHlwZW9mIGEgPT09ICdzdHJpbmcnID8gYSA6IEpTT04uc3RyaW5naWZ5KGEpKS5qb2luKCcgJykpLFxuICB3YXJuOiAoLi4uYXJncykgPT4gbG9ncy5wdXNoKCdbd2Fybl0gJyArIGFyZ3MubWFwKGEgPT4gdHlwZW9mIGEgPT09ICdzdHJpbmcnID8gYSA6IEpTT04uc3RyaW5naWZ5KGEpKS5qb2luKCcgJykpLFxufTtcblxudHJ5IHtcbiAgY29uc3QgQXN5bmNGdW5jdGlvbiA9IE9iamVjdC5nZXRQcm90b3R5cGVPZihhc3luYyBmdW5jdGlvbigpIHt9KS5jb25zdHJ1Y3RvcjtcbiAgY29uc3QgZm4gPSBuZXcgQXN5bmNGdW5jdGlvbignY3R4JywgJ2NvbnNvbGUnLCBjb2RlKTtcbiAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZm4oY3R4LCBjdXN0b21Db25zb2xlKTtcblxuICBjb25zdCBvdXRwdXQgPSB7IHN1Y2Nlc3M6IHRydWUsIHJlc3VsdDogcmVzdWx0ICE9PSB1bmRlZmluZWQgPyByZXN1bHQgOiBudWxsIH07XG4gIGlmIChsb2dzLmxlbmd0aCA+IDApIG91dHB1dC5sb2dzID0gbG9ncztcbiAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoSlNPTi5zdHJpbmdpZnkob3V0cHV0KSk7XG59IGNhdGNoIChlcnIpIHtcbiAgY29uc3Qgb3V0cHV0ID0ge1xuICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgIGVycm9yOiBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogU3RyaW5nKGVyciksXG4gIH07XG4gIGlmIChsb2dzLmxlbmd0aCA+IDApIG91dHB1dC5sb2dzID0gbG9ncztcbiAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoSlNPTi5zdHJpbmdpZnkob3V0cHV0KSk7XG59XG5gO1xuXG4vKipcbiAqIEV4dHJhY3RzIGEgcGxhaW4gSlNPTiBTY2hlbWEgZnJvbSB3aGF0ZXZlciBmb3JtYXQgdGhlIEFJIFNESyB0b29sIHVzZXNcbiAqIChab2Qgc2NoZW1hLCBBSSBTREsgd3JhcHBlZCBzY2hlbWEsIG9yIHJhdyBKU09OIFNjaGVtYSkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0SnNvblNjaGVtYShcbiAgc2NoZW1hOiB1bmtub3duXG4pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IG51bGwge1xuICBpZiAoIXNjaGVtYSB8fCB0eXBlb2Ygc2NoZW1hICE9PSBcIm9iamVjdFwiKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBpZiAoXG4gICAgXCJfZGVmXCIgaW4gc2NoZW1hICYmXG4gICAgdHlwZW9mIChzY2hlbWEgYXMgeyBfZGVmOiB1bmtub3duIH0pLl9kZWYgPT09IFwib2JqZWN0XCJcbiAgKSB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiB6LnRvSlNPTlNjaGVtYShzY2hlbWEgYXMgei5ab2RUeXBlKSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IHMgPSBzY2hlbWEgYXMgUmVjb3JkPHN0cmluZyB8IHN5bWJvbCwgdW5rbm93bj47XG4gIGlmIChTeW1ib2wuZm9yKFwidmVyY2VsLmFpLnNjaGVtYVwiKSBpbiBzICYmIFwianNvblNjaGVtYVwiIGluIHMpIHtcbiAgICByZXR1cm4gcy5qc29uU2NoZW1hIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICB9XG5cbiAgaWYgKFwidHlwZVwiIGluIHMgfHwgXCJwcm9wZXJ0aWVzXCIgaW4gcykge1xuICAgIHJldHVybiBzIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICB9XG5cbiAgcmV0dXJuIG51bGw7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBqc29uU2NoZW1hVG9UcyhcbiAgc2NoZW1hOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgaW5kZW50ID0gMFxuKTogc3RyaW5nIHtcbiAgaWYgKCFzY2hlbWEpIHtcbiAgICByZXR1cm4gXCJ1bmtub3duXCI7XG4gIH1cblxuICBpZiAoc2NoZW1hLmVudW0gJiYgQXJyYXkuaXNBcnJheShzY2hlbWEuZW51bSkpIHtcbiAgICByZXR1cm4gc2NoZW1hLmVudW0ubWFwKCh2KSA9PiBKU09OLnN0cmluZ2lmeSh2KSkuam9pbihcIiB8IFwiKTtcbiAgfVxuXG4gIGlmIChzY2hlbWEuYW55T2YgJiYgQXJyYXkuaXNBcnJheShzY2hlbWEuYW55T2YpKSB7XG4gICAgcmV0dXJuIHNjaGVtYS5hbnlPZlxuICAgICAgLm1hcCgoczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pID0+IGpzb25TY2hlbWFUb1RzKHMsIGluZGVudCkpXG4gICAgICAuam9pbihcIiB8IFwiKTtcbiAgfVxuICBpZiAoc2NoZW1hLm9uZU9mICYmIEFycmF5LmlzQXJyYXkoc2NoZW1hLm9uZU9mKSkge1xuICAgIHJldHVybiBzY2hlbWEub25lT2ZcbiAgICAgIC5tYXAoKHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA9PiBqc29uU2NoZW1hVG9UcyhzLCBpbmRlbnQpKVxuICAgICAgLmpvaW4oXCIgfCBcIik7XG4gIH1cblxuICBjb25zdCB0eXBlID0gc2NoZW1hLnR5cGUgYXMgc3RyaW5nO1xuXG4gIHN3aXRjaCAodHlwZSkge1xuICAgIGNhc2UgXCJzdHJpbmdcIjpcbiAgICAgIHJldHVybiBcInN0cmluZ1wiO1xuICAgIGNhc2UgXCJudW1iZXJcIjpcbiAgICBjYXNlIFwiaW50ZWdlclwiOlxuICAgICAgcmV0dXJuIFwibnVtYmVyXCI7XG4gICAgY2FzZSBcImJvb2xlYW5cIjpcbiAgICAgIHJldHVybiBcImJvb2xlYW5cIjtcbiAgICBjYXNlIFwibnVsbFwiOlxuICAgICAgcmV0dXJuIFwibnVsbFwiO1xuICAgIGNhc2UgXCJhcnJheVwiOiB7XG4gICAgICBjb25zdCBpdGVtcyA9IHNjaGVtYS5pdGVtc1xuICAgICAgICA/IGpzb25TY2hlbWFUb1RzKHNjaGVtYS5pdGVtcyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiwgaW5kZW50KVxuICAgICAgICA6IFwidW5rbm93blwiO1xuICAgICAgcmV0dXJuIGBBcnJheTwke2l0ZW1zfT5gO1xuICAgIH1cbiAgICBjYXNlIFwib2JqZWN0XCI6IHtcbiAgICAgIGNvbnN0IHByb3BlcnRpZXMgPSBzY2hlbWEucHJvcGVydGllcyBhc1xuICAgICAgICB8IFJlY29yZDxzdHJpbmcsIFJlY29yZDxzdHJpbmcsIHVua25vd24+PlxuICAgICAgICB8IHVuZGVmaW5lZDtcbiAgICAgIGlmICghcHJvcGVydGllcykge1xuICAgICAgICByZXR1cm4gXCJSZWNvcmQ8c3RyaW5nLCB1bmtub3duPlwiO1xuICAgICAgfVxuICAgICAgY29uc3QgcmVxdWlyZWQgPSBuZXcgU2V0KChzY2hlbWEucmVxdWlyZWQgYXMgc3RyaW5nW10pIHx8IFtdKTtcbiAgICAgIGNvbnN0IHBhZCA9IFwiICBcIi5yZXBlYXQoaW5kZW50ICsgMSk7XG4gICAgICBjb25zdCBjbG9zZVBhZCA9IFwiICBcIi5yZXBlYXQoaW5kZW50KTtcbiAgICAgIGNvbnN0IHByb3BzID0gT2JqZWN0LmVudHJpZXMocHJvcGVydGllcykubWFwKChba2V5LCB2YWx1ZV0pID0+IHtcbiAgICAgICAgY29uc3Qgb3B0ID0gcmVxdWlyZWQuaGFzKGtleSkgPyBcIlwiIDogXCI/XCI7XG4gICAgICAgIHJldHVybiBgJHtwYWR9JHtrZXl9JHtvcHR9OiAke2pzb25TY2hlbWFUb1RzKHZhbHVlLCBpbmRlbnQgKyAxKX1gO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gYHtcXG4ke3Byb3BzLmpvaW4oXCI7XFxuXCIpfTtcXG4ke2Nsb3NlUGFkfX1gO1xuICAgIH1cbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIFwidW5rbm93blwiO1xuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZUNvbnRleHRUeXBlU3RyaW5nKHRvb2xzOiBUb29sU2V0KTogc3RyaW5nIHtcbiAgY29uc3Qgc2lnczogc3RyaW5nW10gPSBbXTtcblxuICBmb3IgKGNvbnN0IFtuYW1lLCB0XSBvZiBPYmplY3QuZW50cmllcyh0b29scykpIHtcbiAgICBjb25zdCByYXcgPSB0IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgIGNvbnN0IGlucHV0U2NoZW1hID0gZXh0cmFjdEpzb25TY2hlbWEocmF3LmlucHV0U2NoZW1hID8/IHJhdy5wYXJhbWV0ZXJzKTtcbiAgICBjb25zdCBvdXRwdXRTY2hlbWEgPSBleHRyYWN0SnNvblNjaGVtYShyYXcub3V0cHV0U2NoZW1hKTtcblxuICAgIGNvbnN0IGlucHV0VHlwZSA9IGlucHV0U2NoZW1hID8ganNvblNjaGVtYVRvVHMoaW5wdXRTY2hlbWEsIDIpIDogXCJ7fVwiO1xuICAgIGNvbnN0IG91dHB1dFR5cGUgPSBvdXRwdXRTY2hlbWFcbiAgICAgID8ganNvblNjaGVtYVRvVHMob3V0cHV0U2NoZW1hLCAyKVxuICAgICAgOiBcInVua25vd25cIjtcblxuICAgIHNpZ3MucHVzaChgICAgICR7bmFtZX0oaW5wdXQ6ICR7aW5wdXRUeXBlfSk6IFByb21pc2U8JHtvdXRwdXRUeXBlfT5gKTtcbiAgfVxuXG4gIHJldHVybiBgdHlwZSBDb250ZXh0ID0ge1xcbiAgdG9vbHM6IHtcXG4ke3NpZ3Muam9pbihcIjtcXG5cIil9O1xcbiAgfVxcbn1gO1xufVxuXG5hc3luYyBmdW5jdGlvbiBleGVjdXRlSW5TYW5kYm94KHtcbiAgY29kZSxcbiAgcnBjRGlyLFxuICBhYm9ydENvbnRyb2xsZXIsXG4gIHNhbmRib3gsXG4gIGF2YWlsYWJsZVRvb2xzLFxuICBvblN1YlRvb2xDYWxsLFxufToge1xuICBjb2RlOiBzdHJpbmc7XG4gIHJwY0Rpcjogc3RyaW5nO1xuICBhYm9ydENvbnRyb2xsZXI6IEFib3J0Q29udHJvbGxlcjtcbiAgc2FuZGJveDogU2FuZGJveDtcbiAgYXZhaWxhYmxlVG9vbHM6IFRvb2xTZXQ7XG4gIG9uU3ViVG9vbENhbGw/OiBPblN1YlRvb2xDYWxsO1xufSk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgdW5rbm93bj4+IHtcbiAgY29uc3QgbWtkaXJSZXN1bHQgPSBhd2FpdCBzYW5kYm94LmV4ZWMoe1xuICAgIGNvbW1hbmQ6IFwibWtkaXJcIixcbiAgICBhcmdzOiBbXCItcFwiLCBycGNEaXJdLFxuICB9KTtcbiAgaWYgKG1rZGlyUmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgZXJyb3I6IG1rZGlyUmVzdWx0Lm1lc3NhZ2UgfTtcbiAgfVxuICBhd2FpdCBta2RpclJlc3VsdC5yZXN1bHQ7XG5cbiAgYXdhaXQgc2FuZGJveC53cml0ZUZpbGVzKHtcbiAgICBmaWxlczogW1xuICAgICAgeyBwYXRoOiBcInJ1bm5lci5tanNcIiwgY29udGVudDogUlVOTkVSX1NDUklQVCB9LFxuICAgICAgeyBwYXRoOiBcImNvZGUuanNcIiwgY29udGVudDogY29kZSB9LFxuICAgICAge1xuICAgICAgICBwYXRoOiBcInRvb2xzLmpzb25cIixcbiAgICAgICAgY29udGVudDogSlNPTi5zdHJpbmdpZnkoT2JqZWN0LmtleXMoYXZhaWxhYmxlVG9vbHMpKSxcbiAgICAgIH0sXG4gICAgXSxcbiAgICBkZXN0UGF0aDogcnBjRGlyLFxuICB9KTtcblxuICBjb25zdCBub2RlTWFqb3IgPSBOdW1iZXIucGFyc2VJbnQocHJvY2Vzcy52ZXJzaW9ucy5ub2RlLnNwbGl0KFwiLlwiKVswXSwgMTApO1xuICBjb25zdCBwZXJtaXNzaW9uRmxhZyA9XG4gICAgbm9kZU1ham9yID49IDIyID8gXCItLXBlcm1pc3Npb25cIiA6IFwiLS1leHBlcmltZW50YWwtcGVybWlzc2lvblwiO1xuXG4gIGNvbnN0IGV4ZWNSZXN1bHQgPSBhd2FpdCBzYW5kYm94LmV4ZWMoe1xuICAgIGNvbW1hbmQ6IFwibm9kZVwiLFxuICAgIGFyZ3M6IFtcbiAgICAgIHBlcm1pc3Npb25GbGFnLFxuICAgICAgYC0tYWxsb3ctZnMtcmVhZD0ke3JwY0Rpcn1gLFxuICAgICAgYC0tYWxsb3ctZnMtd3JpdGU9JHtycGNEaXJ9YCxcbiAgICAgIGAke3JwY0Rpcn0vcnVubmVyLm1qc2AsXG4gICAgXSxcbiAgICBzaWduYWw6IGFib3J0Q29udHJvbGxlci5zaWduYWwsXG4gIH0pO1xuXG4gIGlmIChleGVjUmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgZXJyb3I6IGV4ZWNSZXN1bHQubWVzc2FnZSB9O1xuICB9XG5cbiAgY29uc3QgZmF0YWw6IHsgZXJyb3I6IEVycm9yIHwgbnVsbCB9ID0geyBlcnJvcjogbnVsbCB9O1xuXG4gIGNvbnN0IGFib3J0ID0gKGVycm9yOiBFcnJvcikgPT4ge1xuICAgIGlmICghZmF0YWwuZXJyb3IpIHtcbiAgICAgIGZhdGFsLmVycm9yID0gZXJyb3I7XG4gICAgICBhYm9ydENvbnRyb2xsZXIuYWJvcnQoKTtcbiAgICB9XG4gIH07XG5cbiAgY29uc3QgaGFuZGxlVG9vbFJlcXVlc3QgPSBhc3luYyAocmVxdWVzdEpzb246IHN0cmluZykgPT4ge1xuICAgIGxldCBwYXJzZWQ6IHsgaWQ6IHN0cmluZzsgdG9vbDogc3RyaW5nOyBpbnB1dDogdW5rbm93biB9O1xuICAgIHRyeSB7XG4gICAgICBwYXJzZWQgPSBKU09OLnBhcnNlKHJlcXVlc3RKc29uKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCB7IGlkLCB0b29sOiB0b29sTmFtZSwgaW5wdXQgfSA9IHBhcnNlZDtcblxuICAgIGxldCByZXNwb25zZTogeyByZXN1bHQ/OiB1bmtub3duOyBlcnJvcj86IHN0cmluZyB9O1xuICAgIHRyeSB7XG4gICAgICBjb25zdCB0ID0gYXZhaWxhYmxlVG9vbHNbdG9vbE5hbWVdO1xuICAgICAgaWYgKCF0Py5leGVjdXRlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgVG9vbCAke3Rvb2xOYW1lfSBub3QgZm91bmQgb3IgaGFzIG5vIGV4ZWN1dGUgZnVuY3Rpb25gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBjb25zdCBleGVjID0gdC5leGVjdXRlLmJpbmQodCk7XG4gICAgICBpZiAob25TdWJUb29sQ2FsbCkge1xuICAgICAgICByZXNwb25zZSA9IGF3YWl0IG9uU3ViVG9vbENhbGwodG9vbE5hbWUsIGlucHV0LCAoKSA9PlxuICAgICAgICAgIGV4ZWMoaW5wdXQsIHtcbiAgICAgICAgICAgIHRvb2xDYWxsSWQ6IGBqc18ke3Rvb2xOYW1lfV8ke0RhdGUubm93KCl9YCxcbiAgICAgICAgICAgIG1lc3NhZ2VzOiBbXSxcbiAgICAgICAgICB9KVxuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZXhlYyhpbnB1dCwge1xuICAgICAgICAgIHRvb2xDYWxsSWQ6IGBqc18ke3Rvb2xOYW1lfV8ke0RhdGUubm93KCl9YCxcbiAgICAgICAgICBtZXNzYWdlczogW10sXG4gICAgICAgIH0pO1xuICAgICAgICByZXNwb25zZSA9IHsgcmVzdWx0IH07XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zdCBtc2cgPSBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogU3RyaW5nKGVycik7XG4gICAgICByZXNwb25zZSA9IHsgZXJyb3I6IG1zZyB9O1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCBzYW5kYm94LndyaXRlRmlsZXMoe1xuICAgICAgICBmaWxlczogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIHBhdGg6IGAke2lkfS5yZXNwb25zZS5qc29uYCxcbiAgICAgICAgICAgIGNvbnRlbnQ6IEpTT04uc3RyaW5naWZ5KHJlc3BvbnNlKSxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgICBkZXN0UGF0aDogcnBjRGlyLFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAvKipcbiAgICAgICAqIElmIHdyaXRpbmcgdGhlIHJlc3BvbnNlIGZpbGUgZmFpbHMsIHRoZSBydW5uZXIgd2lsbCBwb2xsIGZvcmV2ZXJcbiAgICAgICAqIHdhaXRpbmcgZm9yIGl0LiBBYm9ydCB0aGUgcnVubmVyIHByb2Nlc3Mgc28gd2UgZG9uJ3QgZGVhZGxvY2suXG4gICAgICAgKi9cbiAgICAgIGNvbnN0IG1zZyA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKTtcbiAgICAgIGFib3J0KG5ldyBFcnJvcihgRmFpbGVkIHRvIHdyaXRlIFJQQyByZXNwb25zZSBmb3IgJHt0b29sTmFtZX06ICR7bXNnfWApKTtcbiAgICB9XG4gIH07XG5cbiAgY29uc3QgdG9vbENhbGxQcm9taXNlczogUHJvbWlzZTx2b2lkPltdID0gW107XG4gIGxldCBzdGRlcnJCdWZmZXIgPSBcIlwiO1xuICBsZXQgbm9uTWFya2VyU3RkZXJyID0gXCJcIjtcblxuICBjb25zdCB0aW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgYWJvcnQoXG4gICAgICBuZXcgRXJyb3IoXG4gICAgICAgIGBKYXZhU2NyaXB0IGV4ZWN1dGlvbiB0aW1lZCBvdXQgYWZ0ZXIgJHtFWEVDVVRJT05fVElNRU9VVF9NUyAvIDEwMDB9c2BcbiAgICAgIClcbiAgICApO1xuICB9LCBFWEVDVVRJT05fVElNRU9VVF9NUyk7XG5cbiAgdHJ5IHtcbiAgICBmb3IgYXdhaXQgKGNvbnN0IGVudHJ5IG9mIGV4ZWNSZXN1bHQubG9ncygpKSB7XG4gICAgICBpZiAoZmF0YWwuZXJyb3IpIHtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG5cbiAgICAgIGlmIChlbnRyeS5zdHJlYW0gPT09IFwic3RkZXJyXCIpIHtcbiAgICAgICAgc3RkZXJyQnVmZmVyICs9IGVudHJ5LmRhdGE7XG5cbiAgICAgICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgICBjb25zdCBzdGFydElkeCA9IHN0ZGVyckJ1ZmZlci5pbmRleE9mKFJFUVVFU1RfTUFSS0VSX1NUQVJUKTtcbiAgICAgICAgICBpZiAoc3RhcnRJZHggPT09IC0xKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCBiZWZvcmVNYXJrZXIgPSBzdGRlcnJCdWZmZXIuc2xpY2UoMCwgc3RhcnRJZHgpO1xuICAgICAgICAgIGlmIChiZWZvcmVNYXJrZXIudHJpbSgpKSB7XG4gICAgICAgICAgICBub25NYXJrZXJTdGRlcnIgKz0gYmVmb3JlTWFya2VyO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IGNvbnRlbnRTdGFydCA9IHN0YXJ0SWR4ICsgUkVRVUVTVF9NQVJLRVJfU1RBUlQubGVuZ3RoO1xuICAgICAgICAgIGNvbnN0IGVuZElkeCA9IHN0ZGVyckJ1ZmZlci5pbmRleE9mKFJFUVVFU1RfTUFSS0VSX0VORCwgY29udGVudFN0YXJ0KTtcbiAgICAgICAgICBpZiAoZW5kSWR4ID09PSAtMSkge1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgcmVxdWVzdEpzb24gPSBzdGRlcnJCdWZmZXIuc2xpY2UoY29udGVudFN0YXJ0LCBlbmRJZHgpO1xuICAgICAgICAgIHN0ZGVyckJ1ZmZlciA9IHN0ZGVyckJ1ZmZlci5zbGljZShlbmRJZHggKyBSRVFVRVNUX01BUktFUl9FTkQubGVuZ3RoKTtcblxuICAgICAgICAgIHRvb2xDYWxsUHJvbWlzZXMucHVzaChoYW5kbGVUb29sUmVxdWVzdChyZXF1ZXN0SnNvbikpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9IGZpbmFsbHkge1xuICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgfVxuXG4gIGlmIChzdGRlcnJCdWZmZXIudHJpbSgpKSB7XG4gICAgbm9uTWFya2VyU3RkZXJyICs9IHN0ZGVyckJ1ZmZlcjtcbiAgfVxuXG4gIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZCh0b29sQ2FsbFByb21pc2VzKTtcblxuICBpZiAoZmF0YWwuZXJyb3IpIHtcbiAgICBleGVjUmVzdWx0LnJlc3VsdC5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICAgIHJldHVybiB7XG4gICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgIGVycm9yOiBmYXRhbC5lcnJvci5tZXNzYWdlLFxuICAgICAgLi4uKG5vbk1hcmtlclN0ZGVyciA/IHsgc3RkZXJyOiBub25NYXJrZXJTdGRlcnIuc2xpY2UoMCwgMjAwMCkgfSA6IHt9KSxcbiAgICB9O1xuICB9XG5cbiAgY29uc3QgeyBzdGRvdXQsIHN0ZGVyciwgZXhpdENvZGUgfSA9IGF3YWl0IGV4ZWNSZXN1bHQucmVzdWx0O1xuXG4gIHRyeSB7XG4gICAgcmV0dXJuIEpTT04ucGFyc2Uoc3Rkb3V0KTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgZXJyb3I6IGBSdW5uZXIgZmFpbGVkIChleGl0ICR7ZXhpdENvZGV9KS5gLFxuICAgICAgc3RkZXJyOiAobm9uTWFya2VyU3RkZXJyICsgc3RkZXJyKS5zbGljZSgwLCAyMDAwKSxcbiAgICAgIHN0ZG91dDogc3Rkb3V0LnNsaWNlKDAsIDEwMDApLFxuICAgIH07XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUphdmFTY3JpcHRUb29sKG9wdHM6IHtcbiAgdG9vbHM6IFRvb2xTZXQ7XG4gIHNlc3Npb246IFNlc3Npb247XG4gIHNhbmRib3g6IFNhbmRib3g7XG4gIG9uU3ViVG9vbENhbGw/OiBPblN1YlRvb2xDYWxsO1xufSkge1xuICBjb25zdCB7IHNlc3Npb24sIHNhbmRib3gsIG9uU3ViVG9vbENhbGwgfSA9IG9wdHM7XG4gIGNvbnN0IGFjdGl2ZVNldCA9IHNlc3Npb24uYWN0aXZlVG9vbHMgPyBuZXcgU2V0KHNlc3Npb24uYWN0aXZlVG9vbHMpIDogbnVsbDtcbiAgY29uc3QgYXZhaWxhYmxlVG9vbHM6IFRvb2xTZXQgPSB7fTtcbiAgZm9yIChjb25zdCBbbmFtZSwgdF0gb2YgT2JqZWN0LmVudHJpZXMob3B0cy50b29scykpIHtcbiAgICBpZiAoIWFjdGl2ZVNldCB8fCBhY3RpdmVTZXQuaGFzKG5hbWUpKSB7XG4gICAgICBhdmFpbGFibGVUb29sc1tuYW1lXSA9IHQ7XG4gICAgfVxuICB9XG4gIGNvbnN0IGNvbnRleHRUeXBlID0gZ2VuZXJhdGVDb250ZXh0VHlwZVN0cmluZyhhdmFpbGFibGVUb29scyk7XG5cbiAgcmV0dXJuIHRvb2woe1xuICAgIC4uLmJ1aWx0SW5Ub29scy5KYXZhU2NyaXB0LFxuICAgIGRlc2NyaXB0aW9uOiBgRXhlY3V0ZSBKYXZhU2NyaXB0IHRvIG9yY2hlc3RyYXRlIG11bHRpcGxlIHRvb2wgY2FsbHMgaW4gYSBzaW5nbGUgc3RlcC4gVXNlIHRoaXMgd2hlbiB5b3UgbmVlZCB0byBydW4gc2V2ZXJhbCB0b29scyBpbiBzZXF1ZW5jZSwgdHJhbnNmb3JtIGludGVybWVkaWF0ZSByZXN1bHRzLCBvciBwYXJhbGxlbGl6ZSBpbmRlcGVuZGVudCBvcGVyYXRpb25zIHdpdGggUHJvbWlzZS5hbGwuXG5cblRoZSBjb2RlIHJ1bnMgYXMgYW4gYXN5bmMgZnVuY3Rpb24gYm9keSB3aXRoIFxcYGN0eFxcYCBpbiBzY29wZTpcblxuXFxgXFxgXFxgdHlwZXNjcmlwdFxuJHtjb250ZXh0VHlwZX1cblxcYFxcYFxcYFxuXG5FeGFtcGxlczpcbi0gU2VxdWVudGlhbDogXFxgY29uc3QgZmlsZSA9IGF3YWl0IGN0eC50b29scy5SZWFkKHsgcGF0aDogXCJwYWNrYWdlLmpzb25cIiB9KTsgcmV0dXJuIEpTT04ucGFyc2UoZmlsZS5jb250ZW50KTtcXGBcbi0gUGFyYWxsZWw6IFxcYGNvbnN0IFthLCBiXSA9IGF3YWl0IFByb21pc2UuYWxsKFtjdHgudG9vbHMuUmVhZCh7IHBhdGg6IFwiYS50c1wiIH0pLCBjdHgudG9vbHMuUmVhZCh7IHBhdGg6IFwiYi50c1wiIH0pXSk7IHJldHVybiB7IGE6IGEuY29udGVudCwgYjogYi5jb250ZW50IH07XFxgXG4tIFRyYW5zZm9ybTogXFxgY29uc3QgZ3JlcCA9IGF3YWl0IGN0eC50b29scy5HcmVwKHsgcGF0dGVybjogXCJUT0RPXCIgfSk7IHJldHVybiBncmVwLm1hdGNoZXMuc3BsaXQoXCJcXFxcblwiKS5sZW5ndGg7XFxgXG4tIEJhc2g6IFxcYGNvbnN0IHIgPSBhd2FpdCBjdHgudG9vbHMuQmFzaCh7IGNvbW1hbmQ6IFwibm9kZSAtZSBcXFxcXCJjb25zb2xlLmxvZyhKU09OLnN0cmluZ2lmeSh7djoxfSkpXFxcXFwiXCIgfSk7IHJldHVybiBKU09OLnBhcnNlKHIuc3Rkb3V0KTtcXGBcblxuUmV0dXJuIGEgdmFsdWUgdG8gcGFzcyByZXN1bHRzIGJhY2suIFVzZSBjb25zb2xlLmxvZygpIGZvciBkZWJ1ZyBvdXRwdXQuXG5JbXBvcnRhbnQ6IEVhY2ggdG9vbCByZXR1cm5zIGEgc3RydWN0dXJlZCBvYmplY3QgbWF0Y2hpbmcgaXRzIG91dHB1dCBzY2hlbWEgXHUyMDE0IG5vdCBhIHJhdyBzdHJpbmcuIEFjY2VzcyB0aGUgc3BlY2lmaWMgZmllbGQgeW91IG5lZWQgKGUuZy4gQmFzaCdzIHJlc3VsdC5zdGRvdXQsIFJlYWQncyByZXN1bHQuY29udGVudCkgcmF0aGVyIHRoYW4gdHJ5aW5nIHRvIHBhcnNlIHRoZSBlbnRpcmUgcmVzdWx0LmAsXG4gICAgZXhlY3V0ZTogKHsgY29kZSB9KSA9PiB7XG4gICAgICBjb25zdCBydW5JZCA9IGBydW5fJHtEYXRlLm5vdygpfV8ke01hdGgucmFuZG9tKClcbiAgICAgICAgLnRvU3RyaW5nKDM2KVxuICAgICAgICAuc2xpY2UoMiwgOCl9YDtcbiAgICAgIGNvbnN0IHJwY0RpciA9IGAuYWdlbnQvanMtcnBjLyR7cnVuSWR9YDtcbiAgICAgIGNvbnN0IGFib3J0Q29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcblxuICAgICAgcmV0dXJuIGV4ZWN1dGVJblNhbmRib3goe1xuICAgICAgICBjb2RlLFxuICAgICAgICBycGNEaXIsXG4gICAgICAgIGFib3J0Q29udHJvbGxlcixcbiAgICAgICAgc2FuZGJveCxcbiAgICAgICAgYXZhaWxhYmxlVG9vbHMsXG4gICAgICAgIG9uU3ViVG9vbENhbGwsXG4gICAgICB9KTtcbiAgICB9LFxuICB9KTtcbn1cbiIsICJpbXBvcnQgdHlwZSB7IEpTT05WYWx1ZSwgTW9kZWxNZXNzYWdlIH0gZnJvbSBcImFpXCI7XG5cbnR5cGUgUHJvdmlkZXJPcHRpb25zID0gUmVjb3JkPHN0cmluZywgUmVjb3JkPHN0cmluZywgSlNPTlZhbHVlPj47XG5cbmNvbnN0IEFOVEhST1BJQ19NQVhfQ0FDSEVfQlJFQUtQT0lOVFNfUEVSX1JFUVVFU1QgPSA0O1xuXG5jb25zdCBDTEFVREVfTElLRV9NT0RFTF9NQVRDSEVSUyA9IFtcImNsYXVkZVwiLCBcImFudGhyb3BpY1wiXTtcblxuY29uc3QgQ0xBVURFX1BST01QVF9DQUNISU5HX1BST1ZJREVSX09QVElPTlM6IFByb3ZpZGVyT3B0aW9ucyA9IHtcbiAgYW50aHJvcGljOiB7XG4gICAgY2FjaGVDb250cm9sOiB7IHR5cGU6IFwiZXBoZW1lcmFsXCIgfSxcbiAgfSxcbiAgb3BlbnJvdXRlcjoge1xuICAgIGNhY2hlQ29udHJvbDogeyB0eXBlOiBcImVwaGVtZXJhbFwiIH0sXG4gIH0sXG4gIGJlZHJvY2s6IHtcbiAgICBjYWNoZVBvaW50OiB7IHR5cGU6IFwiZGVmYXVsdFwiIH0sXG4gIH0sXG4gIG9wZW5haUNvbXBhdGlibGU6IHtcbiAgICBjYWNoZV9jb250cm9sOiB7IHR5cGU6IFwiZXBoZW1lcmFsXCIgfSxcbiAgfSxcbiAgY29waWxvdDoge1xuICAgIGNvcGlsb3RfY2FjaGVfY29udHJvbDogeyB0eXBlOiBcImVwaGVtZXJhbFwiIH0sXG4gIH0sXG59O1xuXG5mdW5jdGlvbiBnZXRHYXRld2F5UHJvdmlkZXIobW9kZWw6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuICBjb25zdCBzbGFzaEluZGV4ID0gbW9kZWwuaW5kZXhPZihcIi9cIik7XG4gIGlmIChzbGFzaEluZGV4ID09PSAtMSkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIHJldHVybiBtb2RlbC5zbGljZSgwLCBzbGFzaEluZGV4KTtcbn1cblxuZnVuY3Rpb24gY291bnRBbnRocm9waWNDYWNoZUJyZWFrcG9pbnRzKG1lc3NhZ2VzOiBNb2RlbE1lc3NhZ2VbXSk6IG51bWJlciB7XG4gIGxldCBjb3VudCA9IDA7XG4gIGZvciAoY29uc3QgbWVzc2FnZSBvZiBtZXNzYWdlcykge1xuICAgIGNvbnN0IHByb3ZpZGVyT3B0aW9ucyA9IChtZXNzYWdlIGFzIHsgcHJvdmlkZXJPcHRpb25zPzogUHJvdmlkZXJPcHRpb25zIH0pXG4gICAgICAucHJvdmlkZXJPcHRpb25zO1xuICAgIGlmIChwcm92aWRlck9wdGlvbnM/LmFudGhyb3BpYz8uY2FjaGVDb250cm9sKSB7XG4gICAgICBjb3VudCArPSAxO1xuICAgIH1cbiAgICBpZiAoQXJyYXkuaXNBcnJheShtZXNzYWdlLmNvbnRlbnQpKSB7XG4gICAgICBmb3IgKGNvbnN0IHBhcnQgb2YgbWVzc2FnZS5jb250ZW50KSB7XG4gICAgICAgIGNvbnN0IHBhcnRQcm92aWRlck9wdGlvbnMgPSAoXG4gICAgICAgICAgcGFydCBhcyB7IHByb3ZpZGVyT3B0aW9ucz86IFByb3ZpZGVyT3B0aW9ucyB9XG4gICAgICAgICkucHJvdmlkZXJPcHRpb25zO1xuICAgICAgICBpZiAocGFydFByb3ZpZGVyT3B0aW9ucz8uYW50aHJvcGljPy5jYWNoZUNvbnRyb2wpIHtcbiAgICAgICAgICBjb3VudCArPSAxO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiBjb3VudDtcbn1cblxuZnVuY3Rpb24gaXNDbGF1ZGVMaWtlTW9kZWwobW9kZWw6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBjb25zdCBsb3dlciA9IG1vZGVsLnRvTG93ZXJDYXNlKCk7XG4gIHJldHVybiBDTEFVREVfTElLRV9NT0RFTF9NQVRDSEVSUy5zb21lKChtKSA9PiBsb3dlci5pbmNsdWRlcyhtKSk7XG59XG5cbmZ1bmN0aW9uIG1lcmdlUHJvdmlkZXJPcHRpb25zKG9wdHM6IHtcbiAgY3VycmVudDogUHJvdmlkZXJPcHRpb25zIHwgdW5kZWZpbmVkO1xuICBwYXRjaDogUHJvdmlkZXJPcHRpb25zO1xufSk6IFByb3ZpZGVyT3B0aW9ucyB7XG4gIGNvbnN0IG5leHQ6IFByb3ZpZGVyT3B0aW9ucyA9IHsgLi4uKG9wdHMuY3VycmVudCA/PyB7fSkgfTtcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMob3B0cy5wYXRjaCkpIHtcbiAgICBuZXh0W2tleV0gPSB7IC4uLihuZXh0W2tleV0gPz8ge30pLCAuLi52YWx1ZSB9O1xuICB9XG4gIHJldHVybiBuZXh0O1xufVxuXG5mdW5jdGlvbiBpc0NhY2hlYWJsZUNsYXVkZVBhcnQocGFydDogdW5rbm93bik6IGJvb2xlYW4ge1xuICBpZiAoIXBhcnQgfHwgdHlwZW9mIHBhcnQgIT09IFwib2JqZWN0XCIpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBpZiAoXCJ0eXBlXCIgaW4gcGFydCAmJiAocGFydCBhcyB7IHR5cGU/OiB1bmtub3duIH0pLnR5cGUgPT09IFwidGV4dFwiKSB7XG4gICAgY29uc3QgdGV4dCA9IChwYXJ0IGFzIHsgdGV4dD86IHVua25vd24gfSkudGV4dDtcbiAgICBpZiAodHlwZW9mIHRleHQgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHJldHVybiB0ZXh0LnRyaW0oKS5sZW5ndGggPiAwO1xuICAgIH1cbiAgfVxuXG4gIGlmIChcInR5cGVcIiBpbiBwYXJ0KSB7XG4gICAgY29uc3QgdHlwZSA9IChwYXJ0IGFzIHsgdHlwZT86IHVua25vd24gfSkudHlwZTtcbiAgICBpZiAodHlwZSA9PT0gXCJ0aGlua2luZ1wiIHx8IHR5cGUgPT09IFwicmVhc29uaW5nXCIpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn1cblxuZnVuY3Rpb24gaGFzQ2FjaGVhYmxlQ29udGVudChtZXNzYWdlOiBNb2RlbE1lc3NhZ2UpOiBib29sZWFuIHtcbiAgaWYgKHR5cGVvZiBtZXNzYWdlLmNvbnRlbnQgPT09IFwic3RyaW5nXCIpIHtcbiAgICByZXR1cm4gbWVzc2FnZS5jb250ZW50LnRyaW0oKS5sZW5ndGggPiAwO1xuICB9XG5cbiAgaWYgKEFycmF5LmlzQXJyYXkobWVzc2FnZS5jb250ZW50KSkge1xuICAgIHJldHVybiBtZXNzYWdlLmNvbnRlbnQuc29tZSgocGFydCkgPT4gaXNDYWNoZWFibGVDbGF1ZGVQYXJ0KHBhcnQpKTtcbiAgfVxuXG4gIHJldHVybiBmYWxzZTtcbn1cblxuZnVuY3Rpb24gZmluZExhc3RDYWNoZWFibGVQYXJ0SW5kZXgoY29udGVudDogdW5rbm93bltdKTogbnVtYmVyIHwgbnVsbCB7XG4gIGZvciAobGV0IGkgPSBjb250ZW50Lmxlbmd0aCAtIDE7IGkgPj0gMDsgaSAtPSAxKSB7XG4gICAgaWYgKGlzQ2FjaGVhYmxlQ2xhdWRlUGFydChjb250ZW50W2ldKSkge1xuICAgICAgcmV0dXJuIGk7XG4gICAgfVxuICB9XG4gIHJldHVybiBudWxsO1xufVxuXG5mdW5jdGlvbiBzZWxlY3RDbGF1ZGVDYWNoaW5nVGFyZ2V0cyhtZXNzYWdlczogTW9kZWxNZXNzYWdlW10pOiBudW1iZXJbXSB7XG4gIGNvbnN0IHN5c3RlbUluZGljZXM6IG51bWJlcltdID0gW107XG4gIGNvbnN0IGZpbmFsSW5kaWNlczogbnVtYmVyW10gPSBbXTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IG1lc3NhZ2VzLmxlbmd0aCAmJiBzeXN0ZW1JbmRpY2VzLmxlbmd0aCA8IDI7IGkgKz0gMSkge1xuICAgIGNvbnN0IG1lc3NhZ2UgPSBtZXNzYWdlc1tpXTtcbiAgICBpZiAobWVzc2FnZS5yb2xlID09PSBcInN5c3RlbVwiICYmIGhhc0NhY2hlYWJsZUNvbnRlbnQobWVzc2FnZSkpIHtcbiAgICAgIHN5c3RlbUluZGljZXMucHVzaChpKTtcbiAgICB9XG4gIH1cblxuICBmb3IgKGxldCBpID0gbWVzc2FnZXMubGVuZ3RoIC0gMTsgaSA+PSAwICYmIGZpbmFsSW5kaWNlcy5sZW5ndGggPCAyOyBpIC09IDEpIHtcbiAgICBjb25zdCBtZXNzYWdlID0gbWVzc2FnZXNbaV07XG4gICAgaWYgKG1lc3NhZ2Uucm9sZSAhPT0gXCJzeXN0ZW1cIiAmJiBoYXNDYWNoZWFibGVDb250ZW50KG1lc3NhZ2UpKSB7XG4gICAgICBmaW5hbEluZGljZXMucHVzaChpKTtcbiAgICB9XG4gIH1cblxuICBmaW5hbEluZGljZXMucmV2ZXJzZSgpO1xuXG4gIHJldHVybiBbLi4uc3lzdGVtSW5kaWNlcywgLi4uZmluYWxJbmRpY2VzXTtcbn1cblxuZnVuY3Rpb24gYXBwbHlDbGF1ZGVQcm9tcHRDYWNoaW5nKG9wdHM6IHtcbiAgbWVzc2FnZXM6IE1vZGVsTWVzc2FnZVtdO1xuICBwcm92aWRlcklkOiBzdHJpbmcgfCBudWxsO1xuICBtYXhCcmVha3BvaW50c1BlclJlcXVlc3Q6IG51bWJlcjtcbn0pOiBNb2RlbE1lc3NhZ2VbXSB7XG4gIGNvbnN0IGV4aXN0aW5nQnJlYWtwb2ludHMgPSBjb3VudEFudGhyb3BpY0NhY2hlQnJlYWtwb2ludHMob3B0cy5tZXNzYWdlcyk7XG4gIGNvbnN0IHJlbWFpbmluZ0J1ZGdldCA9IE1hdGgubWF4KFxuICAgIDAsXG4gICAgb3B0cy5tYXhCcmVha3BvaW50c1BlclJlcXVlc3QgLSBleGlzdGluZ0JyZWFrcG9pbnRzXG4gICk7XG5cbiAgaWYgKHJlbWFpbmluZ0J1ZGdldCA9PT0gMCkge1xuICAgIHJldHVybiBvcHRzLm1lc3NhZ2VzO1xuICB9XG5cbiAgY29uc3QgdGFyZ2V0SW5kaWNlcyA9IHNlbGVjdENsYXVkZUNhY2hpbmdUYXJnZXRzKG9wdHMubWVzc2FnZXMpLnNsaWNlKFxuICAgIDAsXG4gICAgcmVtYWluaW5nQnVkZ2V0XG4gICk7XG4gIGlmICh0YXJnZXRJbmRpY2VzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBvcHRzLm1lc3NhZ2VzO1xuICB9XG5cbiAgY29uc3QgdXNlTWVzc2FnZUxldmVsT3B0aW9ucyA9XG4gICAgb3B0cy5wcm92aWRlcklkID09PSBcImFudGhyb3BpY1wiIHx8XG4gICAgQm9vbGVhbihvcHRzLnByb3ZpZGVySWQ/LmluY2x1ZGVzKFwiYmVkcm9ja1wiKSk7XG5cbiAgY29uc3QgbmV4dE1lc3NhZ2VzID0gb3B0cy5tZXNzYWdlcy5zbGljZSgpO1xuXG4gIGZvciAoY29uc3QgbWVzc2FnZUluZGV4IG9mIHRhcmdldEluZGljZXMpIHtcbiAgICBjb25zdCBtZXNzYWdlID0gbmV4dE1lc3NhZ2VzW21lc3NhZ2VJbmRleF07XG5cbiAgICBjb25zdCBzaG91bGRVc2VDb250ZW50T3B0aW9ucyA9XG4gICAgICAhdXNlTWVzc2FnZUxldmVsT3B0aW9ucyAmJlxuICAgICAgQXJyYXkuaXNBcnJheShtZXNzYWdlLmNvbnRlbnQpICYmXG4gICAgICBtZXNzYWdlLmNvbnRlbnQubGVuZ3RoID4gMDtcblxuICAgIGlmIChzaG91bGRVc2VDb250ZW50T3B0aW9ucyAmJiBBcnJheS5pc0FycmF5KG1lc3NhZ2UuY29udGVudCkpIHtcbiAgICAgIGNvbnN0IHBhcnRJbmRleCA9IGZpbmRMYXN0Q2FjaGVhYmxlUGFydEluZGV4KG1lc3NhZ2UuY29udGVudCk7XG4gICAgICBpZiAocGFydEluZGV4ICE9PSBudWxsKSB7XG4gICAgICAgIGNvbnN0IHBhcnQgPSBtZXNzYWdlLmNvbnRlbnRbcGFydEluZGV4XTtcbiAgICAgICAgaWYgKHBhcnQgJiYgdHlwZW9mIHBhcnQgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgICBjb25zdCBwYXJ0UHJvdmlkZXJPcHRpb25zID0gKFxuICAgICAgICAgICAgcGFydCBhcyB7IHByb3ZpZGVyT3B0aW9ucz86IFByb3ZpZGVyT3B0aW9ucyB9XG4gICAgICAgICAgKS5wcm92aWRlck9wdGlvbnM7XG5cbiAgICAgICAgICBjb25zdCBuZXh0Q29udGVudCA9IG1lc3NhZ2UuY29udGVudC5zbGljZSgpO1xuICAgICAgICAgIG5leHRDb250ZW50W3BhcnRJbmRleF0gPSB7XG4gICAgICAgICAgICAuLi4ocGFydCBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiksXG4gICAgICAgICAgICBwcm92aWRlck9wdGlvbnM6IG1lcmdlUHJvdmlkZXJPcHRpb25zKHtcbiAgICAgICAgICAgICAgY3VycmVudDogcGFydFByb3ZpZGVyT3B0aW9ucyxcbiAgICAgICAgICAgICAgcGF0Y2g6IENMQVVERV9QUk9NUFRfQ0FDSElOR19QUk9WSURFUl9PUFRJT05TLFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgfSBhcyAodHlwZW9mIG1lc3NhZ2UuY29udGVudClbbnVtYmVyXTtcblxuICAgICAgICAgIG5leHRNZXNzYWdlc1ttZXNzYWdlSW5kZXhdID0ge1xuICAgICAgICAgICAgLi4ubWVzc2FnZSxcbiAgICAgICAgICAgIGNvbnRlbnQ6IG5leHRDb250ZW50LFxuICAgICAgICAgIH0gYXMgTW9kZWxNZXNzYWdlO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgbWVzc2FnZVByb3ZpZGVyT3B0aW9ucyA9IChcbiAgICAgIG1lc3NhZ2UgYXMgeyBwcm92aWRlck9wdGlvbnM/OiBQcm92aWRlck9wdGlvbnMgfVxuICAgICkucHJvdmlkZXJPcHRpb25zO1xuXG4gICAgbmV4dE1lc3NhZ2VzW21lc3NhZ2VJbmRleF0gPSB7XG4gICAgICAuLi5tZXNzYWdlLFxuICAgICAgcHJvdmlkZXJPcHRpb25zOiBtZXJnZVByb3ZpZGVyT3B0aW9ucyh7XG4gICAgICAgIGN1cnJlbnQ6IG1lc3NhZ2VQcm92aWRlck9wdGlvbnMsXG4gICAgICAgIHBhdGNoOiBDTEFVREVfUFJPTVBUX0NBQ0hJTkdfUFJPVklERVJfT1BUSU9OUyxcbiAgICAgIH0pLFxuICAgIH07XG4gIH1cblxuICByZXR1cm4gbmV4dE1lc3NhZ2VzO1xufVxuXG5leHBvcnQgdHlwZSBQcm9tcHRDYWNoaW5nUmVzdWx0ID0ge1xuICBtZXNzYWdlczogTW9kZWxNZXNzYWdlW107XG4gIHByb3ZpZGVyT3B0aW9uczogUHJvdmlkZXJPcHRpb25zO1xufTtcblxuZXhwb3J0IGZ1bmN0aW9uIGFwcGx5UHJvbXB0Q2FjaGluZ1RvTW9kZWxSZXF1ZXN0KG9wdHM6IHtcbiAgbW9kZWw6IHN0cmluZztcbiAgc2Vzc2lvbklkOiBzdHJpbmc7XG4gIG1lc3NhZ2VzOiBNb2RlbE1lc3NhZ2VbXTtcbiAgYW50aHJvcGljPzogeyBtYXhCcmVha3BvaW50c1BlclJlcXVlc3Q/OiBudW1iZXIgfTtcbiAgb3BlbmFpPzogeyBzZXRQcm9tcHRDYWNoZUtleT86IGJvb2xlYW4gfTtcbn0pOiBQcm9tcHRDYWNoaW5nUmVzdWx0IHtcbiAgY29uc3QgcHJvdmlkZXIgPSBnZXRHYXRld2F5UHJvdmlkZXIob3B0cy5tb2RlbCk7XG5cbiAgY29uc3QgcHJvdmlkZXJPcHRpb25zOiBQcm92aWRlck9wdGlvbnMgPSB7fTtcblxuICBpZiAoXG4gICAgKHByb3ZpZGVyID09PSBcIm9wZW5haVwiIHx8IHByb3ZpZGVyID09PSBcImF6dXJlXCIpICYmXG4gICAgb3B0cy5vcGVuYWk/LnNldFByb21wdENhY2hlS2V5ICE9PSBmYWxzZVxuICApIHtcbiAgICBwcm92aWRlck9wdGlvbnMub3BlbmFpID0geyBwcm9tcHRDYWNoZUtleTogb3B0cy5zZXNzaW9uSWQgfTtcbiAgfVxuXG4gIGNvbnN0IG1heEJyZWFrcG9pbnRzUGVyUmVxdWVzdCA9XG4gICAgb3B0cy5hbnRocm9waWM/Lm1heEJyZWFrcG9pbnRzUGVyUmVxdWVzdCA/P1xuICAgIEFOVEhST1BJQ19NQVhfQ0FDSEVfQlJFQUtQT0lOVFNfUEVSX1JFUVVFU1Q7XG5cbiAgY29uc3QgY2FjaGVkTWVzc2FnZXMgPSBpc0NsYXVkZUxpa2VNb2RlbChvcHRzLm1vZGVsKVxuICAgID8gYXBwbHlDbGF1ZGVQcm9tcHRDYWNoaW5nKHtcbiAgICAgICAgbWVzc2FnZXM6IG9wdHMubWVzc2FnZXMsXG4gICAgICAgIHByb3ZpZGVySWQ6IHByb3ZpZGVyLFxuICAgICAgICBtYXhCcmVha3BvaW50c1BlclJlcXVlc3QsXG4gICAgICB9KVxuICAgIDogb3B0cy5tZXNzYWdlcztcblxuICByZXR1cm4ge1xuICAgIG1lc3NhZ2VzOiBjYWNoZWRNZXNzYWdlcyxcbiAgICBwcm92aWRlck9wdGlvbnMsXG4gIH07XG59XG4iLCAiaW1wb3J0IHR5cGUgeyBSZWFzb25pbmdVSVBhcnQsIFRleHRVSVBhcnQsIFVJTWVzc2FnZSB9IGZyb20gXCJhaVwiO1xuaW1wb3J0IHR5cGUgeyBNZXNzYWdlLCBQYXJ0IH0gZnJvbSBcIi4uL3N0b3JhZ2VcIjtcblxuLyoqIFN1Yi10b29sIHBhcnRzIChmcm9tIEphdmFTY3JpcHQgbWV0YS10b29sKSB1c2UgdGhpcyB0b29sQ2FsbElkIHByZWZpeC4gKi9cbmZ1bmN0aW9uIGlzU3ViVG9vbFBhcnQocGFydDogUGFydCk6IGJvb2xlYW4ge1xuICBjb25zdCBwID0gcGFydC5wYXJ0IGFzIHsgdG9vbENhbGxJZD86IHN0cmluZyB9O1xuICByZXR1cm4gdHlwZW9mIHA/LnRvb2xDYWxsSWQgPT09IFwic3RyaW5nXCIgJiYgcC50b29sQ2FsbElkLnN0YXJ0c1dpdGgoXCJqc190Y19cIik7XG59XG5cbmZ1bmN0aW9uIGlzU3RyZWFtaW5nQ29udGVudChcbiAgcGFydDogdW5rbm93blxuKTogcGFydCBpcyBUZXh0VUlQYXJ0IHwgUmVhc29uaW5nVUlQYXJ0IHtcbiAgcmV0dXJuIChcbiAgICB0eXBlb2YgcGFydCA9PT0gXCJvYmplY3RcIiAmJlxuICAgIHBhcnQgIT09IG51bGwgJiZcbiAgICBcInR5cGVcIiBpbiBwYXJ0ICYmXG4gICAgKHBhcnQudHlwZSA9PT0gXCJ0ZXh0XCIgfHwgcGFydC50eXBlID09PSBcInJlYXNvbmluZ1wiKVxuICApO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gYXBwbHlJbnRlcnJ1cHRDdXRvZmYoe1xuICBwYXJ0cyxcbiAgbGFzdFBhcnQsXG59OiB7XG4gIHBhcnRzOiBQYXJ0W107XG4gIGxhc3RQYXJ0OiB7IGluZGV4OiBudW1iZXI7IHBhcnQ6IHVua25vd24gfTtcbn0pOiBQYXJ0W10ge1xuICByZXR1cm4gcGFydHNcbiAgICAuZmlsdGVyKChwKSA9PiBwLmluZGV4IDw9IGxhc3RQYXJ0LmluZGV4KVxuICAgIC5tYXAoKHApID0+IHtcbiAgICAgIGlmIChwLmluZGV4ICE9PSBsYXN0UGFydC5pbmRleCkge1xuICAgICAgICByZXR1cm4gcDtcbiAgICAgIH1cbiAgICAgIC8qKlxuICAgICAgICogT25seSByZXBsYWNlIGNvbnRlbnQgZm9yIHN0cmVhbWluZyBwYXJ0cyAodGV4dCwgcmVhc29uaW5nKSB3aGVyZSB0aGVcbiAgICAgICAqIGNsaWVudCdzIHRydW5jYXRlZCB2ZXJzaW9uIGlzIG1vcmUgYWNjdXJhdGUgdGhhbiB0aGUgc2VydmVyJ3MgZnVsbFxuICAgICAgICogdmVyc2lvbi4gRm9yIHN0YXRlZnVsIHBhcnRzICh0b29scyksIHRoZSBzZXJ2ZXIncyB2ZXJzaW9uIGlzXG4gICAgICAgKiBhdXRob3JpdGF0aXZlIFx1MjAxNCBpdCBtYXkgaGF2ZSBldm9sdmVkIChlLmcuIGFwcHJvdmFsLXJlcXVlc3RlZCBcdTIxOTJcbiAgICAgICAqIG91dHB1dC1kZW5pZWQpIGFmdGVyIHRoZSBjbGllbnQgc25hcHNob3Qgd2FzIHRha2VuLlxuICAgICAgICovXG4gICAgICBpZiAoaXNTdHJlYW1pbmdDb250ZW50KGxhc3RQYXJ0LnBhcnQpKSB7XG4gICAgICAgIHJldHVybiB7IC4uLnAsIHBhcnQ6IGxhc3RQYXJ0LnBhcnQgfSBhcyBQYXJ0O1xuICAgICAgfVxuICAgICAgcmV0dXJuIHA7XG4gICAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhc3NlbWJsZVVJTWVzc2FnZXMob3B0czoge1xuICBtZXNzYWdlczogTWVzc2FnZVtdO1xuICBwYXJ0czogUGFydFtdO1xuICB1bnRpbD86IG51bWJlcjtcbiAgaW5jbHVkZVF1ZXVlZD86IGJvb2xlYW47XG4gIC8qKiBXaGVuIHRydWUsIGZpbHRlcnMgb3V0IHN1Yi10b29sIHBhcnRzIHNvIHRoZSBMTE0gZG9lc24ndCBzZWUgdGhlbS4gKi9cbiAgZXhjbHVkZVN1YlRvb2xQYXJ0cz86IGJvb2xlYW47XG59KTogVUlNZXNzYWdlW10ge1xuICBsZXQgZmlsdGVyZWQgPSBvcHRzLm1lc3NhZ2VzO1xuXG4gIGlmIChvcHRzLnVudGlsICE9PSB1bmRlZmluZWQpIHtcbiAgICBjb25zdCB1bnRpbCA9IG9wdHMudW50aWw7XG4gICAgZmlsdGVyZWQgPSBmaWx0ZXJlZC5maWx0ZXIoKG0pID0+IG0uY3JlYXRlZEF0IDw9IHVudGlsKTtcbiAgfVxuXG4gIGlmICghb3B0cy5pbmNsdWRlUXVldWVkKSB7XG4gICAgZmlsdGVyZWQgPSBmaWx0ZXJlZC5maWx0ZXIoKG0pID0+IG0uc3RhcnRlZEF0ICE9PSBudWxsKTtcbiAgfVxuXG4gIGNvbnN0IHBhcnRzID0gb3B0cy5leGNsdWRlU3ViVG9vbFBhcnRzXG4gICAgPyBvcHRzLnBhcnRzLmZpbHRlcigocCkgPT4gIWlzU3ViVG9vbFBhcnQocCkpXG4gICAgOiBvcHRzLnBhcnRzO1xuXG4gIGNvbnN0IHBhcnRzQnlNZXNzYWdlID0gbmV3IE1hcDxzdHJpbmcsIFBhcnRbXT4oKTtcbiAgZm9yIChjb25zdCBwYXJ0IG9mIHBhcnRzKSB7XG4gICAgY29uc3QgZXhpc3RpbmcgPSBwYXJ0c0J5TWVzc2FnZS5nZXQocGFydC5tZXNzYWdlSWQpID8/IFtdO1xuICAgIGV4aXN0aW5nLnB1c2gocGFydCk7XG4gICAgcGFydHNCeU1lc3NhZ2Uuc2V0KHBhcnQubWVzc2FnZUlkLCBleGlzdGluZyk7XG4gIH1cblxuICByZXR1cm4gZmlsdGVyZWRcbiAgICAubWFwKChtKSA9PiB7XG4gICAgICBsZXQgbWVzc2FnZVBhcnRzID0gcGFydHNCeU1lc3NhZ2UuZ2V0KG0uaWQpID8/IFtdO1xuICAgICAgbWVzc2FnZVBhcnRzLnNvcnQoKGEsIGIpID0+IGEuaW5kZXggLSBiLmluZGV4KTtcblxuICAgICAgaWYgKG0uaW50ZXJydXB0ZWRMYXN0UGFydCAhPSBudWxsKSB7XG4gICAgICAgIG1lc3NhZ2VQYXJ0cyA9IGFwcGx5SW50ZXJydXB0Q3V0b2ZmKHtcbiAgICAgICAgICBwYXJ0czogbWVzc2FnZVBhcnRzLFxuICAgICAgICAgIGxhc3RQYXJ0OiBtLmludGVycnVwdGVkTGFzdFBhcnQsXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBpZDogbS5pZCxcbiAgICAgICAgcm9sZTogbS5yb2xlLFxuICAgICAgICBwYXJ0czogbWVzc2FnZVBhcnRzLm1hcCgocCkgPT4gcC5wYXJ0KSxcbiAgICAgIH0gc2F0aXNmaWVzIFVJTWVzc2FnZTtcbiAgICB9KVxuICAgIC5maWx0ZXIoKG0pID0+IG0ucGFydHMubGVuZ3RoID4gMCk7XG59XG4iLCAiaW1wb3J0IHR5cGUgeyBTdGVwVXNhZ2UsIFVzYWdlU3VtbWFyeSB9IGZyb20gXCIuLi9zdG9yYWdlL3JwY1wiO1xuXG5leHBvcnQgdHlwZSB7IFN0ZXBVc2FnZSwgVXNhZ2VTdW1tYXJ5IH07XG5cbmZ1bmN0aW9uIHN1bShpdGVtczogU3RlcFVzYWdlW10sIGtleToga2V5b2YgU3RlcFVzYWdlKTogbnVtYmVyIHtcbiAgcmV0dXJuIGl0ZW1zLnJlZHVjZSgoYWNjLCBpdGVtKSA9PiB7XG4gICAgY29uc3QgdmFsdWUgPSBpdGVtW2tleV07XG4gICAgcmV0dXJuIGFjYyArICh0eXBlb2YgdmFsdWUgPT09IFwibnVtYmVyXCIgPyB2YWx1ZSA6IDApO1xuICB9LCAwKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNvbXB1dGVVc2FnZVN1bW1hcnkoc3RlcHM6IFN0ZXBVc2FnZVtdKTogVXNhZ2VTdW1tYXJ5IHtcbiAgcmV0dXJuIHtcbiAgICBtb2RlbDogc3RlcHNbMF0/Lm1vZGVsID8/IFwidW5rbm93blwiLFxuICAgIGlucHV0VG9rZW5zOiBzdW0oc3RlcHMsIFwiaW5wdXRUb2tlbnNcIiksXG4gICAgb3V0cHV0VG9rZW5zOiBzdW0oc3RlcHMsIFwib3V0cHV0VG9rZW5zXCIpLFxuICAgIHRvdGFsVG9rZW5zOiBzdW0oc3RlcHMsIFwidG90YWxUb2tlbnNcIiksXG4gICAgY2FjaGVSZWFkVG9rZW5zOiBzdW0oc3RlcHMsIFwiY2FjaGVSZWFkVG9rZW5zXCIpLFxuICAgIGNhY2hlV3JpdGVUb2tlbnM6IHN1bShzdGVwcywgXCJjYWNoZVdyaXRlVG9rZW5zXCIpLFxuICAgIHJlYXNvbmluZ1Rva2Vuczogc3VtKHN0ZXBzLCBcInJlYXNvbmluZ1Rva2Vuc1wiKSxcbiAgICBzdGVwQ291bnQ6IHN0ZXBzLmxlbmd0aCxcbiAgfTtcbn1cblxuZXhwb3J0IHR5cGUgU2Vzc2lvblVzYWdlID0ge1xuICB0b3RhbDogVXNhZ2VTdW1tYXJ5ICYgeyBtZXNzYWdlQ291bnQ6IG51bWJlciB9O1xuICBieU1lc3NhZ2VJZDogUmVjb3JkPHN0cmluZywgVXNhZ2VTdW1tYXJ5IHwgbnVsbD47XG59O1xuXG5leHBvcnQgZnVuY3Rpb24gY29tcHV0ZVNlc3Npb25Vc2FnZShcbiAgbWVzc2FnZXM6IEFycmF5PHtcbiAgICBpZDogc3RyaW5nO1xuICAgIHVzYWdlOiB7IHN0ZXBzOiBTdGVwVXNhZ2VbXTsgc3VtbWFyeTogVXNhZ2VTdW1tYXJ5IH0gfCBudWxsO1xuICB9PlxuKTogU2Vzc2lvblVzYWdlIHtcbiAgY29uc3QgYnlNZXNzYWdlSWQ6IFJlY29yZDxzdHJpbmcsIFVzYWdlU3VtbWFyeSB8IG51bGw+ID0ge307XG4gIGZvciAoY29uc3QgbSBvZiBtZXNzYWdlcykge1xuICAgIGJ5TWVzc2FnZUlkW20uaWRdID0gbS51c2FnZT8uc3VtbWFyeSA/PyBudWxsO1xuICB9XG5cbiAgY29uc3Qgc3VtbWFyaWVzID0gbWVzc2FnZXNcbiAgICAubWFwKChtKSA9PiBtLnVzYWdlPy5zdW1tYXJ5KVxuICAgIC5maWx0ZXIoKHMpOiBzIGlzIFVzYWdlU3VtbWFyeSA9PiBzICE9PSB1bmRlZmluZWQpO1xuXG4gIGNvbnN0IHRvdGFsID0ge1xuICAgIG1vZGVsOiBzdW1tYXJpZXNbMF0/Lm1vZGVsID8/IFwidW5rbm93blwiLFxuICAgIGlucHV0VG9rZW5zOiBzdW1tYXJpZXMucmVkdWNlKChhY2MsIHMpID0+IGFjYyArIHMuaW5wdXRUb2tlbnMsIDApLFxuICAgIG91dHB1dFRva2Vuczogc3VtbWFyaWVzLnJlZHVjZSgoYWNjLCBzKSA9PiBhY2MgKyBzLm91dHB1dFRva2VucywgMCksXG4gICAgdG90YWxUb2tlbnM6IHN1bW1hcmllcy5yZWR1Y2UoKGFjYywgcykgPT4gYWNjICsgcy50b3RhbFRva2VucywgMCksXG4gICAgY2FjaGVSZWFkVG9rZW5zOiBzdW1tYXJpZXMucmVkdWNlKChhY2MsIHMpID0+IGFjYyArIHMuY2FjaGVSZWFkVG9rZW5zLCAwKSxcbiAgICBjYWNoZVdyaXRlVG9rZW5zOiBzdW1tYXJpZXMucmVkdWNlKChhY2MsIHMpID0+IGFjYyArIHMuY2FjaGVXcml0ZVRva2VucywgMCksXG4gICAgcmVhc29uaW5nVG9rZW5zOiBzdW1tYXJpZXMucmVkdWNlKChhY2MsIHMpID0+IGFjYyArIHMucmVhc29uaW5nVG9rZW5zLCAwKSxcbiAgICBzdGVwQ291bnQ6IHN1bW1hcmllcy5yZWR1Y2UoKGFjYywgcykgPT4gYWNjICsgcy5zdGVwQ291bnQsIDApLFxuICAgIG1lc3NhZ2VDb3VudDogc3VtbWFyaWVzLmxlbmd0aCxcbiAgfTtcblxuICByZXR1cm4geyB0b3RhbCwgYnlNZXNzYWdlSWQgfTtcbn1cbiJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7O0FBQ0EsU0FBUyxZQUFZLGNBQUFBLGFBQVksbUJBQW1COzs7QUNEcEQ7QUFBQSxFQUNFO0FBQUEsRUFDQTtBQUFBLEVBRUE7QUFBQSxFQUNBO0FBQUEsT0FFSztBQUNQLFNBQVMsWUFBWTtBQUNyQixTQUFTLGtCQUFrQjs7O0FDaUJwQixTQUFTLHNCQUNkLFNBQ3lCO0FBQ3pCLFFBQU0sVUFBVSxRQUFRLEtBQUs7QUFFN0IsTUFBSSxDQUFDLFFBQVEsV0FBVyxLQUFLLEdBQUc7QUFDOUIsV0FBTztBQUFBLEVBQ1Q7QUFFQSxRQUFNLGlCQUFpQixRQUFRLFFBQVEsT0FBTyxDQUFDO0FBQy9DLE1BQUksbUJBQW1CLElBQUk7QUFDekIsV0FBTztBQUFBLEVBQ1Q7QUFFQSxRQUFNLG1CQUFtQixRQUFRLE1BQU0sR0FBRyxjQUFjLEVBQUUsS0FBSztBQUMvRCxRQUFNLFNBQVMsZ0JBQWdCLGdCQUFnQjtBQUUvQyxNQUFJLEVBQUUsT0FBTyxRQUFRLE9BQU8sY0FBYztBQUN4QyxXQUFPO0FBQUEsRUFDVDtBQUVBLFNBQU87QUFBQSxJQUNMLE1BQU0sT0FBTyxPQUFPLElBQUk7QUFBQSxJQUN4QixhQUFhLE9BQU8sT0FBTyxXQUFXO0FBQUEsRUFDeEM7QUFDRjtBQU1BLFNBQVMsZ0JBQWdCLE1BQXNDO0FBQzdELFFBQU0sU0FBaUMsQ0FBQztBQUV4QyxhQUFXLFFBQVEsS0FBSyxNQUFNLElBQUksR0FBRztBQUNuQyxVQUFNLGNBQWMsS0FBSyxLQUFLO0FBQzlCLFFBQUksQ0FBQyxlQUFlLFlBQVksV0FBVyxHQUFHLEdBQUc7QUFDL0M7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L0IsT0FBTyxPQUFPLGlCQUFpQixJQUFJLENBQUMsTUFBTSxFQUFFLFFBQVE7QUFBQSxRQUN0RCxDQUFDO0FBQ0QsY0FBTSxRQUFRO0FBQUEsVUFDWixPQUFPLGlCQUFpQixJQUFJLENBQUMsWUFBWTtBQUN2QyxrQkFBTSxPQUFPLGFBQWEsT0FBTyxFQUFFLE9BQU8sUUFBUSxXQUFXLENBQUM7QUFDOUQsa0JBQU0sT0FBTyxLQUFLLE9BQU8sYUFBYSxFQUFFO0FBQ3hDLG1CQUFPLEtBQUssS0FBSztBQUFBLFVBQ25CLENBQUM7QUFBQSxRQUNIO0FBQUEsTUFDRjtBQUFBLElBQ0YsU0FBUyxLQUFLO0FBQ1osYUFBTyxNQUFNLHlCQUF5QjtBQUFBLFFBQ3BDLE9BQU8sZUFBZSxRQUFRLElBQUksVUFBVSxPQUFPLEdBQUc7QUFBQSxNQUN4RCxDQUFDO0FBQ0QsWUFBTTtBQUFBLElBQ1I7QUFBQSxFQUNGO0FBRUEsY0FBWSxFQUFFLFlBQVksV0FBVyxPQUFPLENBQUM7QUFFN0MsUUFBTSxvQkFBb0I7QUFBQSxJQUN4QixvQkFBb0IsTUFBTTtBQUFBLElBQzFCO0FBQUEsSUFDQTtBQUFBLElBQ0E7QUFBQSxFQUNGLENBQUM7QUFFRCxTQUFPLEVBQUUsaUJBQWlCO0FBQzVCOyIsCiAgIm5hbWVzIjogWyJGYXRhbEVycm9yIiwgImxvZyIsICJ0b29sIiwgInoiLCAidG9vbCIsICJ6IiwgImxvZyIsICJzZXNzaW9uIiwgInNhbmRib3hSZWNvcmQiLCAic2FuZGJveCIsICJyZXN1bHQiLCAiZXZlbnQiLCAibG9nIiwgIkZhdGFsRXJyb3IiLCAicmVzdWx0Il0KfQo=
|