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