experimental-agent 0.2.1 → 0.3.0

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