experimental-agent 0.0.0 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +118 -55
  2. package/dist/agent-workflow.d.mts +1 -1
  3. package/dist/agent-workflow.d.ts +1 -1
  4. package/dist/agent-workflow.js +474 -66
  5. package/dist/agent-workflow.mjs +1 -1
  6. package/dist/{chunk-DPPQO7DA.mjs → chunk-24DJSI7C.mjs} +34 -3
  7. package/dist/chunk-4RGMKC2M.mjs +755 -0
  8. package/dist/{chunk-2YI7MQGZ.mjs → chunk-6ICYKNCC.mjs} +24 -1
  9. package/dist/chunk-PGYYQ3WZ.mjs +1088 -0
  10. package/dist/{client-FCFZYOOB.mjs → client-4Y3UPWFR.mjs} +3 -3
  11. package/dist/client-BBpD9kKL.d.ts +193 -0
  12. package/dist/client-BGJViybU.d.mts +193 -0
  13. package/dist/{client-RRX3GDQD.mjs → client-HUG4HT5L.mjs} +1 -1
  14. package/dist/index.d.mts +5 -106
  15. package/dist/index.d.ts +5 -106
  16. package/dist/index.js +526 -77
  17. package/dist/index.mjs +57 -16
  18. package/dist/{lifecycle-workflow-steps-6BLGTYVB.mjs → lifecycle-workflow-steps-HHN46ZAD.mjs} +2 -2
  19. package/dist/lifecycle-workflow.d.mts +2 -2
  20. package/dist/lifecycle-workflow.d.ts +2 -2
  21. package/dist/lifecycle-workflow.js +217 -19
  22. package/dist/lifecycle-workflow.mjs +1 -1
  23. package/dist/{local-J6QFWSWB.mjs → local-BYPFRMLZ.mjs} +42 -4
  24. package/dist/{sandbox-Y3ENCNUA.mjs → sandbox-BFA4ECEQ.mjs} +3 -3
  25. package/dist/{storage-QSTSE2ZB.mjs → storage-2U2QFNWI.mjs} +2 -2
  26. package/dist/{types-vRxN1Qz1.d.mts → types-DPXFq_r6.d.mts} +110 -1
  27. package/dist/{types-vRxN1Qz1.d.ts → types-DPXFq_r6.d.ts} +110 -1
  28. package/package.json +13 -12
  29. package/dist/chunk-JQPR6M7D.mjs +0 -649
  30. package/dist/chunk-MR4UWCJT.mjs +0 -878
  31. package/dist/types-Lwut_0_u.d.mts +0 -80
  32. package/dist/types-ctZeJ3iQ.d.ts +0 -80
@@ -1,878 +0,0 @@
1
- // src/agent-workflow.ts
2
- import { defineHook, FatalError as FatalError2, getWritable } from "workflow";
3
-
4
- // src/agent-workflow-steps.ts
5
- import {
6
- convertToModelMessages,
7
- streamText
8
- } from "ai";
9
- import { ulid } from "ulid";
10
- import { FatalError } from "workflow";
11
-
12
- // src/skills/parser.ts
13
- function parseSkillFrontmatter(content) {
14
- const trimmed = content.trim();
15
- if (!trimmed.startsWith("---")) {
16
- return null;
17
- }
18
- const endMarkerIndex = trimmed.indexOf("---", 3);
19
- if (endMarkerIndex === -1) {
20
- return null;
21
- }
22
- const frontmatterBlock = trimmed.slice(3, endMarkerIndex).trim();
23
- const parsed = parseSimpleYaml(frontmatterBlock);
24
- if (!(parsed.name && parsed.description)) {
25
- return null;
26
- }
27
- return {
28
- name: String(parsed.name),
29
- description: String(parsed.description)
30
- };
31
- }
32
- function parseSimpleYaml(yaml) {
33
- const result = {};
34
- for (const line of yaml.split("\n")) {
35
- const trimmedLine = line.trim();
36
- if (!trimmedLine || trimmedLine.startsWith("#")) {
37
- continue;
38
- }
39
- const colonIndex = trimmedLine.indexOf(":");
40
- if (colonIndex === -1) {
41
- continue;
42
- }
43
- const key = trimmedLine.slice(0, colonIndex).trim();
44
- let value = trimmedLine.slice(colonIndex + 1).trim();
45
- if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
46
- value = value.slice(1, -1);
47
- }
48
- if (key) {
49
- result[key] = value;
50
- }
51
- }
52
- return result;
53
- }
54
- function normalizeSkillsDirs(skillsDir) {
55
- if (!skillsDir) {
56
- return [];
57
- }
58
- return Array.isArray(skillsDir) ? skillsDir : [skillsDir];
59
- }
60
-
61
- // src/skills/discover.ts
62
- async function discoverSkillsInSandbox(opts) {
63
- const { sandbox, skillsDirs, debug } = opts;
64
- const summaries = [];
65
- const seenNames = /* @__PURE__ */ new Set();
66
- for (const skillsDir of skillsDirs) {
67
- const dirSummaries = await discoverSkillsInDirectory({
68
- sandbox,
69
- skillsDir,
70
- debug
71
- });
72
- for (const summary of dirSummaries) {
73
- if (!seenNames.has(summary.name)) {
74
- seenNames.add(summary.name);
75
- summaries.push(summary);
76
- }
77
- }
78
- }
79
- return summaries;
80
- }
81
- async function discoverSkillsInDirectory(opts) {
82
- const { sandbox, skillsDir, debug } = opts;
83
- const skillPaths = await findSkillFiles({ sandbox, skillsDir, debug });
84
- if (skillPaths.length === 0) {
85
- return [];
86
- }
87
- const summaries = [];
88
- for (const skillMdPath of skillPaths) {
89
- const summary = await parseSkillFile({ sandbox, skillMdPath, debug });
90
- if (summary) {
91
- summaries.push(summary);
92
- }
93
- }
94
- return summaries;
95
- }
96
- async function findSkillFiles(opts) {
97
- const { sandbox, skillsDir, debug } = opts;
98
- if (debug) {
99
- console.log(`[discover] Finding skills in: ${skillsDir}`);
100
- }
101
- const execResult = await sandbox.exec({
102
- command: "find",
103
- args: [skillsDir, "-name", "SKILL.md", "-type", "f"]
104
- });
105
- if (execResult instanceof Error) {
106
- if (debug) {
107
- console.warn(
108
- `[discover] Failed to scan skills directory "${skillsDir}": ${execResult.message}`
109
- );
110
- }
111
- return [];
112
- }
113
- const { stdout, stderr, exitCode } = await execResult.result;
114
- if (debug) {
115
- console.log(
116
- `[discover] find result: exitCode=${exitCode}, stdout="${stdout.trim()}", stderr="${stderr.trim()}"`
117
- );
118
- }
119
- if (exitCode !== 0) {
120
- if (debug) {
121
- console.warn(
122
- `[discover] Skills directory not found or inaccessible: ${skillsDir}`
123
- );
124
- }
125
- return [];
126
- }
127
- const paths = stdout.trim().split("\n").filter((p) => p.length > 0);
128
- if (debug) {
129
- console.log("[discover] Found skill paths:", paths);
130
- }
131
- return paths;
132
- }
133
- async function parseSkillFile(opts) {
134
- const { sandbox, skillMdPath, debug } = opts;
135
- const execResult = await sandbox.exec({
136
- command: "cat",
137
- args: [skillMdPath]
138
- });
139
- if (execResult instanceof Error) {
140
- if (debug) {
141
- console.warn(
142
- `[discover] Failed to read skill file "${skillMdPath}": ${execResult.message}`
143
- );
144
- }
145
- return null;
146
- }
147
- const { stdout, exitCode } = await execResult.result;
148
- if (exitCode !== 0) {
149
- if (debug) {
150
- console.warn(`[discover] Could not read skill file: ${skillMdPath}`);
151
- }
152
- return null;
153
- }
154
- const parsed = parseSkillFrontmatter(stdout);
155
- if (!parsed) {
156
- if (debug) {
157
- console.warn(
158
- `[discover] Invalid or missing frontmatter in: ${skillMdPath}`
159
- );
160
- }
161
- return null;
162
- }
163
- return {
164
- name: parsed.name,
165
- description: parsed.description,
166
- skillMdPath
167
- };
168
- }
169
-
170
- // src/tools/index.ts
171
- import { tool } from "ai";
172
- import { z } from "zod";
173
- function getTools(context) {
174
- return {
175
- Read: tool({
176
- 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.",
177
- inputSchema: z.object({
178
- path: z.string().describe("Path to the file relative to workspace root"),
179
- startLine: z.number().optional().describe(
180
- "Starting line number (1-indexed). If provided with endLine, reads exact range regardless of file size."
181
- ),
182
- endLine: z.number().optional().describe(
183
- "Ending line number (1-indexed, inclusive). If provided with startLine, reads exact range regardless of file size."
184
- )
185
- }),
186
- outputSchema: z.object({
187
- content: z.string().describe("File content"),
188
- metadata: z.object({
189
- totalLines: z.number().describe("Total number of lines in the file"),
190
- linesShown: z.number().describe("Number of lines included in this response"),
191
- startLine: z.number().describe("First line number shown (1-indexed)"),
192
- endLine: z.number().describe("Last line number shown (1-indexed)"),
193
- isPaginated: z.boolean().describe("Whether this is a partial view of the file"),
194
- fileSize: z.string().describe("Human-readable file size (e.g., '2.5K', '1.2M')"),
195
- path: z.string().describe("Path to the file relative to workspace root")
196
- })
197
- }),
198
- execute: async ({ path, startLine, endLine }) => {
199
- const filePath = path.startsWith("/") ? path.slice(1) : path;
200
- const result = await context.sandbox.exec({
201
- command: "bash",
202
- args: [
203
- "-c",
204
- `
205
- set -e
206
- FILE="$1"
207
- START_LINE="$2"
208
- END_LINE="$3"
209
-
210
- # Resolve symlinks and check file exists
211
- if [ -L "$FILE" ]; then
212
- RESOLVED=$(readlink -f "$FILE" 2>/dev/null || echo "")
213
- if [ -z "$RESOLVED" ] || [ ! -e "$RESOLVED" ]; then
214
- echo "Error: Broken symlink - $FILE points to non-existent target" >&2
215
- exit 1
216
- fi
217
- FILE="$RESOLVED"
218
- elif [ ! -e "$FILE" ]; then
219
- echo "Error: File not found - $FILE" >&2
220
- exit 1
221
- fi
222
-
223
- # Get metadata (count actual lines, not just newlines)
224
- TOTAL_LINES=$(awk 'END{print NR}' "$FILE")
225
- FILE_SIZE=$(ls -lh "$FILE" | awk '{print $5}')
226
-
227
- # Determine range
228
- PAGE_SIZE=100
229
- if [ -n "$START_LINE" ] && [ -n "$END_LINE" ]; then
230
- # Both provided - use exact range
231
- ACTUAL_START=$START_LINE
232
- ACTUAL_END=$END_LINE
233
- elif [ -n "$START_LINE" ]; then
234
- # Only startLine - read PAGE_SIZE lines from there
235
- ACTUAL_START=$START_LINE
236
- ACTUAL_END=$((START_LINE + PAGE_SIZE - 1))
237
- [ "$ACTUAL_END" -gt "$TOTAL_LINES" ] && ACTUAL_END=$TOTAL_LINES
238
- elif [ -n "$END_LINE" ]; then
239
- # Only endLine - read from beginning to endLine
240
- ACTUAL_START=1
241
- ACTUAL_END=$END_LINE
242
- elif [ "$TOTAL_LINES" -gt 200 ]; then
243
- # No range, large file - paginate
244
- ACTUAL_START=1
245
- ACTUAL_END=$PAGE_SIZE
246
- else
247
- # No range, small file - show all
248
- ACTUAL_START=1
249
- ACTUAL_END=$TOTAL_LINES
250
- fi
251
-
252
- # Output metadata first (separated by ||| for parsing)
253
- echo "$TOTAL_LINES|$FILE_SIZE|$ACTUAL_START|$ACTUAL_END"
254
- echo "|||CONTENT|||"
255
-
256
- # Read content
257
- if [ "$ACTUAL_START" -eq 1 ] && [ "$ACTUAL_END" -eq "$TOTAL_LINES" ]; then
258
- cat "$FILE"
259
- else
260
- sed -n "\${ACTUAL_START},\${ACTUAL_END}p" "$FILE"
261
- fi
262
- `,
263
- "--",
264
- filePath,
265
- startLine?.toString() || "",
266
- endLine?.toString() || ""
267
- ]
268
- });
269
- if (result instanceof Error) {
270
- console.error("[Read Tool]", result);
271
- throw result;
272
- }
273
- const { stdout, stderr } = await result.result;
274
- if (stderr) {
275
- console.error(`[Read Tool] Error: ${stderr}`);
276
- return {
277
- content: `Error: ${stderr}`,
278
- metadata: {
279
- totalLines: 0,
280
- linesShown: 0,
281
- startLine: 0,
282
- endLine: 0,
283
- isPaginated: false,
284
- fileSize: "0",
285
- path: filePath
286
- }
287
- };
288
- }
289
- const [metadataLine, ...rest] = stdout.split("|||CONTENT|||");
290
- const content = rest.join("|||CONTENT|||").trimStart();
291
- const [totalLinesStr, fileSize, actualStartStr, actualEndStr] = metadataLine.trim().split("|");
292
- const totalLines = Number.parseInt(totalLinesStr, 10);
293
- const actualStart = Number.parseInt(actualStartStr, 10);
294
- const actualEnd = Number.parseInt(actualEndStr, 10);
295
- if (Number.isNaN(totalLines) || Number.isNaN(actualStart) || Number.isNaN(actualEnd)) {
296
- console.error(
297
- `[Read Tool] Failed to parse metadata: ${metadataLine}`
298
- );
299
- return {
300
- content: `Error: Failed to parse file metadata. Raw output: ${stdout.slice(
301
- 0,
302
- 500
303
- )}`,
304
- metadata: {
305
- totalLines: 0,
306
- linesShown: 0,
307
- startLine: 0,
308
- endLine: 0,
309
- isPaginated: false,
310
- fileSize: "unknown",
311
- path: filePath
312
- }
313
- };
314
- }
315
- return {
316
- content,
317
- metadata: {
318
- totalLines,
319
- linesShown: Math.max(0, actualEnd - actualStart + 1),
320
- startLine: actualStart,
321
- endLine: actualEnd,
322
- isPaginated: actualEnd < totalLines,
323
- fileSize: fileSize || "unknown",
324
- path: filePath
325
- }
326
- };
327
- }
328
- }),
329
- Grep: tool({
330
- description: "Search for patterns in files using ripgrep. Supports regex patterns, file type filtering, and context lines. Returns matching lines with file paths and line numbers. Use this to find code patterns, function definitions, imports, etc.",
331
- inputSchema: z.object({
332
- pattern: z.string().describe("Regex pattern to search for (ripgrep syntax)"),
333
- path: z.string().optional().describe(
334
- "Path to search in (defaults to workspace root). Can be a file or directory."
335
- ),
336
- fileType: z.string().optional().describe(
337
- "File type to filter by (e.g., 'ts', 'js', 'py', 'md'). Uses ripgrep's built-in type filters."
338
- ),
339
- glob: z.string().optional().describe(
340
- "Glob pattern to filter files (e.g., '*.tsx', 'src/**/*.ts')"
341
- ),
342
- caseSensitive: z.boolean().optional().default(true).describe("Whether search is case-sensitive (default: true)"),
343
- contextLines: z.number().optional().describe(
344
- "Number of context lines to show before and after each match"
345
- ),
346
- maxCount: z.number().optional().describe(
347
- "Maximum number of matches per file (useful for limiting output)"
348
- ),
349
- filesWithMatches: z.boolean().optional().default(false).describe(
350
- "Only show file paths that contain matches, not the matching lines themselves"
351
- )
352
- }),
353
- outputSchema: z.object({
354
- matches: z.string().describe(
355
- "Search results with file paths, line numbers, and matching content"
356
- ),
357
- summary: z.object({
358
- matchCount: z.number().describe("Number of matches found"),
359
- fileCount: z.number().describe("Number of files containing matches"),
360
- searchPath: z.string().describe("Path that was searched"),
361
- pattern: z.string().describe("Pattern that was searched for")
362
- })
363
- }),
364
- execute: async ({
365
- pattern,
366
- path,
367
- fileType,
368
- glob,
369
- caseSensitive,
370
- contextLines,
371
- maxCount,
372
- filesWithMatches
373
- }) => {
374
- let searchPath = path ?? ".";
375
- if (searchPath.startsWith("/")) {
376
- searchPath = searchPath.slice(1);
377
- }
378
- const args = [];
379
- args.push("--line-number");
380
- args.push("--heading");
381
- args.push("--color", "never");
382
- if (!caseSensitive) {
383
- args.push("-i");
384
- }
385
- if (fileType) {
386
- args.push("--type", fileType);
387
- }
388
- if (glob) {
389
- args.push("--glob", glob);
390
- }
391
- if (contextLines !== void 0) {
392
- args.push("-C", String(contextLines));
393
- }
394
- if (maxCount !== void 0) {
395
- args.push("--max-count", String(maxCount));
396
- }
397
- if (filesWithMatches) {
398
- args.push("--files-with-matches");
399
- }
400
- args.push("--", pattern, searchPath);
401
- const result = await context.sandbox.exec({ command: "rg", args });
402
- if (result instanceof Error) {
403
- console.error("[Grep Tool]", result);
404
- throw result;
405
- }
406
- const { stdout, stderr } = await result.result;
407
- if (stderr && !stderr.toLowerCase().includes("no matches")) {
408
- console.error(`[Grep Tool] Warning: ${stderr}`);
409
- }
410
- const MAX_GREP_OUTPUT_CHARS = 5e4;
411
- let finalOutput = stdout;
412
- let wasTruncated = false;
413
- if (finalOutput.length > MAX_GREP_OUTPUT_CHARS) {
414
- finalOutput = finalOutput.slice(0, MAX_GREP_OUTPUT_CHARS) + "\n\n[Output truncated - use more specific pattern or path]";
415
- wasTruncated = true;
416
- }
417
- const lines = finalOutput.trim().split("\n").filter((l) => l.length > 0);
418
- const fileCount = filesWithMatches ? lines.length : new Set(
419
- lines.filter((l) => !l.startsWith(" ") && l.includes(":")).map((l) => l.split(":")[0])
420
- ).size;
421
- return {
422
- matches: finalOutput || "(no matches found)",
423
- summary: {
424
- matchCount: filesWithMatches ? 0 : lines.filter((l) => l.includes(":")).length,
425
- fileCount,
426
- searchPath,
427
- pattern,
428
- wasTruncated
429
- }
430
- };
431
- }
432
- }),
433
- List: tool({
434
- 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.",
435
- inputSchema: z.object({
436
- path: z.string().optional().describe("Path to list (defaults to workspace root)"),
437
- depth: z.number().optional().describe(
438
- "Maximum depth to traverse. Choose based on context: 1-2 for quick overview, 3-4 for detailed exploration, 5+ for comprehensive mapping"
439
- ),
440
- includeHidden: z.boolean().optional().default(false).describe(
441
- "Include hidden files and directories (those starting with '.')"
442
- ),
443
- filesOnly: z.boolean().optional().default(false).describe("Only show files, not directories"),
444
- pattern: z.string().optional().describe("Glob pattern to filter results (e.g., '*.ts', '*test*')")
445
- }),
446
- outputSchema: z.object({
447
- listing: z.string().describe(
448
- "Directory tree listing showing paths relative to search root"
449
- ),
450
- summary: z.object({
451
- totalItems: z.number().describe("Total number of items found"),
452
- totalFiles: z.number().describe("Total number of files found"),
453
- totalDirs: z.number().describe("Total number of directories found"),
454
- searchPath: z.string().describe("Path that was listed"),
455
- depth: z.number().optional().describe("Maximum depth used (if specified)")
456
- })
457
- }),
458
- execute: async ({ path, depth, includeHidden, filesOnly, pattern }) => {
459
- const searchPath = path ?? ".";
460
- const result = await context.sandbox.exec({
461
- command: "bash",
462
- args: [
463
- "-c",
464
- `
465
- set -e
466
- SEARCH_PATH="$1"
467
- DEPTH="$2"
468
- INCLUDE_HIDDEN="$3"
469
- FILES_ONLY="$4"
470
- PATTERN="$5"
471
-
472
- # Build find command arguments
473
- FIND_ARGS=""
474
- [ -n "$DEPTH" ] && FIND_ARGS="$FIND_ARGS -maxdepth $DEPTH"
475
- [ "$INCLUDE_HIDDEN" != "true" ] && FIND_ARGS="$FIND_ARGS ! -path '*/.*'"
476
- [ "$FILES_ONLY" = "true" ] && FIND_ARGS="$FIND_ARGS -type f"
477
- [ -n "$PATTERN" ] && FIND_ARGS="$FIND_ARGS -name '$PATTERN'"
478
-
479
- # Get listing
480
- LISTING=$(eval "find '$SEARCH_PATH' $FIND_ARGS" 2>/dev/null | sort)
481
-
482
- # Get counts
483
- COUNT_ARGS=""
484
- [ -n "$DEPTH" ] && COUNT_ARGS="$COUNT_ARGS -maxdepth $DEPTH"
485
- [ "$INCLUDE_HIDDEN" != "true" ] && COUNT_ARGS="$COUNT_ARGS ! -path '*/.*'"
486
-
487
- FILE_COUNT=$(eval "find '$SEARCH_PATH' $COUNT_ARGS -type f" 2>/dev/null | wc -l)
488
- DIR_COUNT=$(eval "find '$SEARCH_PATH' $COUNT_ARGS -type d" 2>/dev/null | wc -l)
489
-
490
- # Output: counts first, then listing
491
- echo "$FILE_COUNT|$DIR_COUNT"
492
- echo "|||LISTING|||"
493
- echo "$LISTING" | sed "s|^$SEARCH_PATH|.|"
494
- `,
495
- "--",
496
- searchPath,
497
- depth?.toString() || "",
498
- includeHidden ? "true" : "false",
499
- filesOnly ? "true" : "false",
500
- pattern || ""
501
- ]
502
- });
503
- if (result instanceof Error) {
504
- console.error("[List Tool]", result);
505
- throw result;
506
- }
507
- const { stdout, stderr } = await result.result;
508
- if (stderr) {
509
- console.warn(`[List Tool] stderr: ${stderr}`);
510
- }
511
- const [countsLine, ...rest] = stdout.split("|||LISTING|||");
512
- const listing = rest.join("|||LISTING|||").trim();
513
- const [fileCountStr, dirCountStr] = countsLine.trim().split("|");
514
- const totalFiles = Number.parseInt(fileCountStr, 10) || 0;
515
- const totalDirs = Number.parseInt(dirCountStr, 10) || 0;
516
- const lines = listing.split("\n").filter((l) => l.length > 0);
517
- return {
518
- listing,
519
- summary: {
520
- totalItems: lines.length,
521
- totalFiles,
522
- totalDirs,
523
- searchPath,
524
- depth
525
- }
526
- };
527
- }
528
- }),
529
- Bash: tool({
530
- description: "Executes a bash command inside the workspace. CWD persists between commands within a session. Use waitUntil:0 for background processes (dev servers).",
531
- inputSchema: z.object({
532
- command: z.string().describe("The shell command to execute"),
533
- waitUntil: z.number().optional().describe(
534
- "Max ms to wait for completion (default: 30000). Use 0 to run in background and return immediately."
535
- )
536
- }),
537
- outputSchema: z.object({
538
- pid: z.number().describe(
539
- "System PID (0 for foreground, >0 for background - use to kill)"
540
- ),
541
- output: z.string().describe("Command stdout+stderr combined (empty for background)"),
542
- exitCode: z.number().describe("Exit code (-1 for background/running)"),
543
- status: z.enum(["running", "completed", "failed"]).describe("Process status"),
544
- cwd: z.string().describe("Current working directory after command"),
545
- outputFile: z.string().describe("Path to output log (for background processes)")
546
- }),
547
- execute: async ({ command, waitUntil }) => {
548
- const { createProcessManager } = await import("./process-manager-H2HF6G4G.mjs");
549
- const processManager = createProcessManager({
550
- sandbox: context.sandbox,
551
- sessionId: context.input.sessionId,
552
- generateId: () => crypto.randomUUID()
553
- });
554
- await processManager.init();
555
- return processManager.run({ command, waitUntil });
556
- }
557
- }),
558
- ExecuteMCPTool: tool({
559
- description: "Execute a tool from an MCP server. Use this to call custom tools provided by the application.",
560
- inputSchema: z.object({
561
- server: z.string().describe("MCP server name"),
562
- tool: z.string().describe("Tool name to execute"),
563
- input: z.unknown().describe("Tool input matching the tool's schema")
564
- }),
565
- outputSchema: z.object({
566
- result: z.unknown().describe("Tool execution result"),
567
- truncated: z.boolean().optional().describe("Whether the result was truncated due to size"),
568
- totalChars: z.number().optional().describe("Total characters in full output (only if truncated)"),
569
- returnedChars: z.number().optional().describe("Characters returned in this response (only if truncated)"),
570
- fullOutputPath: z.string().optional().describe("Path to full output file if truncated")
571
- }),
572
- execute: async ({ server, tool: toolName, input }) => {
573
- const serverConfig = context.mcp?.find((s) => s.name === server);
574
- if (!serverConfig) {
575
- throw new Error(`Unknown MCP server: ${server}`);
576
- }
577
- const parsedInput = typeof input === "string" ? JSON.parse(input) : input;
578
- const timestamp = Date.now();
579
- const outputDir = `.agent/mcp/${server}/.outputs`;
580
- const outputFile = `${outputDir}/${timestamp}-${toolName}.txt`;
581
- const [res] = await Promise.all([
582
- fetch(serverConfig.url, {
583
- method: "POST",
584
- headers: { "Content-Type": "application/json" },
585
- body: JSON.stringify({
586
- server,
587
- tool: toolName,
588
- input: parsedInput,
589
- sessionId: context.input.sessionId,
590
- messageId: context.event.assistantMessageId,
591
- hookToken: context.event.hookToken
592
- })
593
- }),
594
- context.sandbox.exec({ command: "mkdir", args: ["-p", outputDir] })
595
- ]);
596
- if (!res.ok) {
597
- const error = await res.text();
598
- throw new Error(`MCP tool call failed: ${error}`);
599
- }
600
- const json = await res.json();
601
- if (json.error) {
602
- throw new Error(`MCP tool call failed: ${json.error.message}`);
603
- }
604
- if (json.result === void 0) {
605
- throw new Error("MCP tool call failed: No result in response");
606
- }
607
- const result = json.result;
608
- const MAX_OUTPUT_CHARS = 24e3;
609
- const resultStr = JSON.stringify(result, null, 2);
610
- if (resultStr.length <= MAX_OUTPUT_CHARS) {
611
- return { result };
612
- }
613
- await context.sandbox.writeFiles({
614
- files: [{ path: `${timestamp}-${toolName}.txt`, content: resultStr }],
615
- destPath: outputDir
616
- });
617
- const truncatedResult = resultStr.slice(0, MAX_OUTPUT_CHARS) + `
618
-
619
- [Output truncated at ~6k tokens. Full output saved to: ${outputFile}]`;
620
- return {
621
- result: truncatedResult,
622
- truncated: true,
623
- totalChars: resultStr.length,
624
- returnedChars: MAX_OUTPUT_CHARS,
625
- fullOutputPath: outputFile
626
- };
627
- }
628
- })
629
- };
630
- }
631
-
632
- // src/utils/ui.ts
633
- function assembleUIMessages(opts) {
634
- const partsByMessage = /* @__PURE__ */ new Map();
635
- for (const part of opts.parts) {
636
- const existing = partsByMessage.get(part.messageId) ?? [];
637
- existing.push(part);
638
- partsByMessage.set(part.messageId, existing);
639
- }
640
- return opts.messages.map((m) => {
641
- const messageParts = partsByMessage.get(m.id) ?? [];
642
- messageParts.sort((a, b) => a.index - b.index);
643
- return {
644
- id: m.id,
645
- role: m.role,
646
- parts: messageParts.map((p) => p.part)
647
- };
648
- });
649
- }
650
-
651
- // src/agent-workflow-steps.ts
652
- var BASE_SYSTEM_PROMPT = "You are an AI assistant with basic tools to interact with your environment. Explore and work freely.";
653
- function joinPromptSections(...sections) {
654
- return sections.filter((s) => s?.trim()).join("\n\n");
655
- }
656
- function buildSkillsContext(skills) {
657
- if (skills.length === 0) {
658
- return "";
659
- }
660
- const skillLines = skills.map((s) => `- ${s.name}: ${s.description}
661
- Path: ${s.skillMdPath}`).join("\n");
662
- return `## Available Skills
663
- ${skillLines}
664
-
665
- You can use the Read tool to read any skill's SKILL.md file to learn more about it.`;
666
- }
667
- function buildMcpToolsContext(mcp) {
668
- if (!mcp || mcp.length === 0) {
669
- return "";
670
- }
671
- const serverDocs = mcp.filter(
672
- (s) => Array.isArray(s.tools) && s.tools.length > 0
673
- ).map((server) => {
674
- const toolDocs = server.tools.map((t) => {
675
- let doc = ` - ${t.name}: ${t.description}
676
- Input: ${JSON.stringify(t.inputSchema)}`;
677
- if (t.outputSchema) {
678
- doc += `
679
- Output: ${JSON.stringify(t.outputSchema)}`;
680
- }
681
- return doc;
682
- }).join("\n");
683
- return `### ${server.name}
684
- ${server.description ?? ""}
685
- ${toolDocs}`;
686
- }).join("\n\n");
687
- if (!serverDocs) {
688
- return "";
689
- }
690
- return `## MCP Tools
691
- Use the ExecuteMCPTool to call these custom tools:
692
-
693
- ${serverDocs}`;
694
- }
695
- async function completeMessageStep({
696
- assistantMessageId,
697
- input,
698
- writable
699
- }) {
700
- "use step";
701
- const { getStorage } = await import("./storage-QSTSE2ZB.mjs");
702
- const storage = getStorage(input.storageConfig);
703
- const message = await storage.message.get(assistantMessageId);
704
- if (message instanceof Error) {
705
- throw message;
706
- }
707
- if (!message) {
708
- throw new Error(`Message ${assistantMessageId} not found`);
709
- }
710
- const result = await storage.message.set({
711
- ...message,
712
- completedAt: Date.now()
713
- });
714
- if (result instanceof Error) {
715
- throw result;
716
- }
717
- await writable.close();
718
- }
719
- async function streamTextStep({
720
- assistantMessageId,
721
- input,
722
- event,
723
- writable,
724
- lastPartIndex
725
- }) {
726
- "use step";
727
- const { getStorage } = await import("./client-RRX3GDQD.mjs");
728
- const { getSandbox } = await import("./sandbox-Y3ENCNUA.mjs");
729
- const storage = getStorage(input.storageConfig);
730
- const session = await storage.session.get(input.sessionId);
731
- if (session instanceof Error) {
732
- throw session;
733
- }
734
- session;
735
- const sandboxRecord = session.sandboxId ? await storage.sandbox.get(session.sandboxId) : null;
736
- if (sandboxRecord instanceof Error) {
737
- throw sandboxRecord;
738
- }
739
- if (!sandboxRecord) {
740
- throw new FatalError(`Sandbox not found for session ${input.sessionId}`);
741
- }
742
- const sandbox = getSandbox({
743
- sandboxRecord,
744
- storageConfig: input.storageConfig
745
- });
746
- const [messagesResult, partsResult, skills] = await Promise.all([
747
- storage.message.list(input.sessionId),
748
- storage.part.listBySession(input.sessionId),
749
- session.skillsDir && session.skillsDir.length > 0 ? discoverSkillsInSandbox({ sandbox, skillsDirs: session.skillsDir }) : Promise.resolve([])
750
- ]);
751
- if (messagesResult instanceof Error) {
752
- throw messagesResult;
753
- }
754
- if (partsResult instanceof Error) {
755
- throw partsResult;
756
- }
757
- const uiMessages = assembleUIMessages({
758
- messages: messagesResult.items,
759
- parts: partsResult.items
760
- });
761
- const mcp = session.mcp;
762
- const systemPrompt = joinPromptSections(
763
- BASE_SYSTEM_PROMPT,
764
- session.instructions,
765
- buildSkillsContext(skills),
766
- buildMcpToolsContext(mcp)
767
- );
768
- if (!session.model) {
769
- throw new FatalError("Session model is not set");
770
- }
771
- const result = streamText({
772
- messages: await convertToModelMessages(uiMessages),
773
- tools: getTools({ input, event, mcp, sandbox }),
774
- system: systemPrompt,
775
- model: session.model
776
- });
777
- const stepParts = [];
778
- await result.toUIMessageStream({
779
- generateMessageId: () => assistantMessageId,
780
- onFinish: ({ messages }) => {
781
- for (const m of messages) {
782
- if (m.role === "assistant") {
783
- stepParts.push(...m.parts);
784
- }
785
- }
786
- }
787
- }).pipeTo(writable, { preventClose: true });
788
- await Promise.all(
789
- stepParts.map(async (uiPart, index) => {
790
- const result2 = await storage.part.set({
791
- id: `part_${ulid()}`,
792
- index: lastPartIndex + index,
793
- messageId: assistantMessageId,
794
- sessionId: input.sessionId,
795
- part: uiPart
796
- });
797
- if (result2 instanceof Error) {
798
- throw result2;
799
- }
800
- return result2;
801
- })
802
- );
803
- return {
804
- finishReason: await result.finishReason,
805
- lastPartIndex: lastPartIndex + stepParts.length
806
- };
807
- }
808
-
809
- // src/agent-workflow.ts
810
- var agentMessageHook = defineHook();
811
- async function agentWorkflow({
812
- input,
813
- event
814
- }) {
815
- "use workflow";
816
- const messageHook = agentMessageHook.create({ token: input.sessionId });
817
- const iterator = messageHook[Symbol.asyncIterator]();
818
- let pendingNext = iterator.next();
819
- await onMessage({ event, input }).catch((e) => {
820
- if (FatalError2.is(e)) {
821
- console.error("Message processing failed permanently:", e.message);
822
- return;
823
- }
824
- throw e;
825
- });
826
- while (true) {
827
- const result = await pendingNext;
828
- if (result.done) {
829
- console.error("Unexpected: message hook iterator done");
830
- break;
831
- }
832
- await onMessage({ event: result.value, input }).catch((e) => {
833
- if (FatalError2.is(e)) {
834
- console.error("Message processing failed permanently:", e.message);
835
- return;
836
- }
837
- throw e;
838
- });
839
- pendingNext = iterator.next();
840
- }
841
- }
842
- async function onMessage({
843
- event,
844
- input
845
- }) {
846
- const writable = getWritable({ namespace: event.assistantMessageId });
847
- let finishReason;
848
- let lastPartIndex = 0;
849
- while (finishReason !== "stop") {
850
- try {
851
- const result = await streamTextStep({
852
- assistantMessageId: event.assistantMessageId,
853
- writable,
854
- input,
855
- event,
856
- lastPartIndex
857
- });
858
- finishReason = result.finishReason;
859
- lastPartIndex = result.lastPartIndex;
860
- } catch (err) {
861
- console.error(err);
862
- throw err;
863
- }
864
- }
865
- await completeMessageStep({
866
- assistantMessageId: event.assistantMessageId,
867
- input,
868
- writable
869
- });
870
- }
871
-
872
- export {
873
- normalizeSkillsDirs,
874
- assembleUIMessages,
875
- agentMessageHook,
876
- agentWorkflow
877
- };
878
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL2FnZW50LXdvcmtmbG93LnRzIiwgIi4uL3NyYy9hZ2VudC13b3JrZmxvdy1zdGVwcy50cyIsICIuLi9zcmMvc2tpbGxzL3BhcnNlci50cyIsICIuLi9zcmMvc2tpbGxzL2Rpc2NvdmVyLnRzIiwgIi4uL3NyYy90b29scy9pbmRleC50cyIsICIuLi9zcmMvdXRpbHMvdWkudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImltcG9ydCB0eXBlIHsgRmluaXNoUmVhc29uIH0gZnJvbSBcImFpXCI7XG5pbXBvcnQgeyBkZWZpbmVIb29rLCBGYXRhbEVycm9yLCBnZXRXcml0YWJsZSB9IGZyb20gXCJ3b3JrZmxvd1wiO1xuaW1wb3J0IHsgY29tcGxldGVNZXNzYWdlU3RlcCwgc3RyZWFtVGV4dFN0ZXAgfSBmcm9tIFwiLi9hZ2VudC13b3JrZmxvdy1zdGVwc1wiO1xuaW1wb3J0IHR5cGUgeyBTdG9yYWdlQ29uZmlnIH0gZnJvbSBcIi4vc3RvcmFnZVwiO1xuXG5leHBvcnQgdHlwZSBBZ2VudElucHV0ID0ge1xuICBzZXNzaW9uSWQ6IHN0cmluZztcbiAgc3RvcmFnZUNvbmZpZzogU3RvcmFnZUNvbmZpZztcbn07XG5cbmV4cG9ydCB0eXBlIEFnZW50TWVzc2FnZUlucHV0ID0ge1xuICBhc3Npc3RhbnRNZXNzYWdlSWQ6IHN0cmluZztcbiAgaG9va1Rva2VuOiBzdHJpbmc7XG59O1xuXG5leHBvcnQgY29uc3QgYWdlbnRNZXNzYWdlSG9vayA9IGRlZmluZUhvb2s8QWdlbnRNZXNzYWdlSW5wdXQ+KCk7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBhZ2VudFdvcmtmbG93KHtcbiAgaW5wdXQsXG4gIGV2ZW50LFxufToge1xuICBpbnB1dDogQWdlbnRJbnB1dDtcbiAgZXZlbnQ6IEFnZW50TWVzc2FnZUlucHV0O1xufSkge1xuICBcInVzZSB3b3JrZmxvd1wiO1xuXG4gIGNvbnN0IG1lc3NhZ2VIb29rID0gYWdlbnRNZXNzYWdlSG9vay5jcmVhdGUoeyB0b2tlbjogaW5wdXQuc2Vzc2lvbklkIH0pO1xuICBjb25zdCBpdGVyYXRvciA9IG1lc3NhZ2VIb29rW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSgpO1xuICBsZXQgcGVuZGluZ05leHQgPSBpdGVyYXRvci5uZXh0KCk7XG5cbiAgYXdhaXQgb25NZXNzYWdlKHsgZXZlbnQsIGlucHV0IH0pLmNhdGNoKChlKSA9PiB7XG4gICAgaWYgKEZhdGFsRXJyb3IuaXMoZSkpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoXCJNZXNzYWdlIHByb2Nlc3NpbmcgZmFpbGVkIHBlcm1hbmVudGx5OlwiLCBlLm1lc3NhZ2UpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aHJvdyBlO1xuICB9KTtcblxuICB3aGlsZSAodHJ1ZSkge1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBlbmRpbmdOZXh0O1xuXG4gICAgaWYgKHJlc3VsdC5kb25lKSB7XG4gICAgICBjb25zb2xlLmVycm9yKFwiVW5leHBlY3RlZDogbWVzc2FnZSBob29rIGl0ZXJhdG9yIGRvbmVcIik7XG4gICAgICBicmVhaztcbiAgICB9XG5cbiAgICBhd2FpdCBvbk1lc3NhZ2UoeyBldmVudDogcmVzdWx0LnZhbHVlLCBpbnB1dCB9KS5jYXRjaCgoZSkgPT4ge1xuICAgICAgaWYgKEZhdGFsRXJyb3IuaXMoZSkpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcIk1lc3NhZ2UgcHJvY2Vzc2luZyBmYWlsZWQgcGVybWFuZW50bHk6XCIsIGUubWVzc2FnZSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHRocm93IGU7XG4gICAgfSk7XG4gICAgcGVuZGluZ05leHQgPSBpdGVyYXRvci5uZXh0KCk7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gb25NZXNzYWdlKHtcbiAgZXZlbnQsXG4gIGlucHV0LFxufToge1xuICBldmVudDogQWdlbnRNZXNzYWdlSW5wdXQ7XG4gIGlucHV0OiBBZ2VudElucHV0O1xufSkge1xuICBjb25zdCB3cml0YWJsZSA9IGdldFdyaXRhYmxlKHsgbmFtZXNwYWNlOiBldmVudC5hc3Npc3RhbnRNZXNzYWdlSWQgfSk7XG5cbiAgbGV0IGZpbmlzaFJlYXNvbjogRmluaXNoUmVhc29uIHwgdW5kZWZpbmVkO1xuICBsZXQgbGFzdFBhcnRJbmRleCA9IDA7XG5cbiAgd2hpbGUgKGZpbmlzaFJlYXNvbiAhPT0gXCJzdG9wXCIpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgc3RyZWFtVGV4dFN0ZXAoe1xuICAgICAgICBhc3Npc3RhbnRNZXNzYWdlSWQ6IGV2ZW50LmFzc2lzdGFudE1lc3NhZ2VJZCxcbiAgICAgICAgd3JpdGFibGUsXG4gICAgICAgIGlucHV0LFxuICAgICAgICBldmVudCxcbiAgICAgICAgbGFzdFBhcnRJbmRleCxcbiAgICAgIH0pO1xuICAgICAgZmluaXNoUmVhc29uID0gcmVzdWx0LmZpbmlzaFJlYXNvbjtcbiAgICAgIGxhc3RQYXJ0SW5kZXggPSByZXN1bHQubGFzdFBhcnRJbmRleDtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTtcbiAgICAgIHRocm93IGVycjtcbiAgICB9XG4gIH1cblxuICBhd2FpdCBjb21wbGV0ZU1lc3NhZ2VTdGVwKHtcbiAgICBhc3Npc3RhbnRNZXNzYWdlSWQ6IGV2ZW50LmFzc2lzdGFudE1lc3NhZ2VJZCxcbiAgICBpbnB1dCxcbiAgICB3cml0YWJsZSxcbiAgfSk7XG59XG4iLCAiaW1wb3J0IHtcbiAgY29udmVydFRvTW9kZWxNZXNzYWdlcyxcbiAgdHlwZSBGaW5pc2hSZWFzb24sXG4gIHN0cmVhbVRleHQsXG4gIHR5cGUgVUlNZXNzYWdlLFxufSBmcm9tIFwiYWlcIjtcbmltcG9ydCB7IHVsaWQgfSBmcm9tIFwidWxpZFwiO1xuaW1wb3J0IHsgRmF0YWxFcnJvciB9IGZyb20gXCJ3b3JrZmxvd1wiO1xuaW1wb3J0IHR5cGUgeyBNY3BTZXJ2ZXJTY2hlbWEgfSBmcm9tIFwiLi9tY3BcIjtcbmltcG9ydCB7IGRpc2NvdmVyU2tpbGxzSW5TYW5kYm94IH0gZnJvbSBcIi4vc2tpbGxzL2Rpc2NvdmVyXCI7XG5pbXBvcnQgdHlwZSB7IFNraWxsU3VtbWFyeSB9IGZyb20gXCIuL3NraWxscy90eXBlc1wiO1xuaW1wb3J0IHR5cGUgeyBTdG9yYWdlQ29uZmlnIH0gZnJvbSBcIi4vc3RvcmFnZVwiO1xuaW1wb3J0IHsgZ2V0VG9vbHMgfSBmcm9tIFwiLi90b29sc1wiO1xuaW1wb3J0IHsgYXNzZW1ibGVVSU1lc3NhZ2VzIH0gZnJvbSBcIi4vdXRpbHMvdWlcIjtcblxuY29uc3QgQkFTRV9TWVNURU1fUFJPTVBUID1cbiAgXCJZb3UgYXJlIGFuIEFJIGFzc2lzdGFudCB3aXRoIGJhc2ljIHRvb2xzIHRvIGludGVyYWN0IHdpdGggeW91ciBlbnZpcm9ubWVudC4gRXhwbG9yZSBhbmQgd29yayBmcmVlbHkuXCI7XG5cbmZ1bmN0aW9uIGpvaW5Qcm9tcHRTZWN0aW9ucyhcbiAgLi4uc2VjdGlvbnM6IChzdHJpbmcgfCB1bmRlZmluZWQgfCBudWxsKVtdXG4pOiBzdHJpbmcge1xuICByZXR1cm4gc2VjdGlvbnMuZmlsdGVyKChzKSA9PiBzPy50cmltKCkpLmpvaW4oXCJcXG5cXG5cIik7XG59XG5cbmZ1bmN0aW9uIGJ1aWxkU2tpbGxzQ29udGV4dChza2lsbHM6IFNraWxsU3VtbWFyeVtdKTogc3RyaW5nIHtcbiAgaWYgKHNraWxscy5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gXCJcIjtcbiAgfVxuXG4gIGNvbnN0IHNraWxsTGluZXMgPSBza2lsbHNcbiAgICAubWFwKChzKSA9PiBgLSAke3MubmFtZX06ICR7cy5kZXNjcmlwdGlvbn1cXG4gIFBhdGg6ICR7cy5za2lsbE1kUGF0aH1gKVxuICAgIC5qb2luKFwiXFxuXCIpO1xuXG4gIHJldHVybiBgIyMgQXZhaWxhYmxlIFNraWxsc1xuJHtza2lsbExpbmVzfVxuXG5Zb3UgY2FuIHVzZSB0aGUgUmVhZCB0b29sIHRvIHJlYWQgYW55IHNraWxsJ3MgU0tJTEwubWQgZmlsZSB0byBsZWFybiBtb3JlIGFib3V0IGl0LmA7XG59XG5cbmZ1bmN0aW9uIGJ1aWxkTWNwVG9vbHNDb250ZXh0KG1jcDogTWNwU2VydmVyU2NoZW1hW10gfCBudWxsIHwgdW5kZWZpbmVkKTogc3RyaW5nIHtcbiAgaWYgKCFtY3AgfHwgbWNwLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBcIlwiO1xuICB9XG5cbiAgY29uc3Qgc2VydmVyRG9jcyA9IG1jcFxuICAgIC5maWx0ZXIoXG4gICAgICAoXG4gICAgICAgIHNcbiAgICAgICk6IHMgaXMgTWNwU2VydmVyU2NoZW1hICYge1xuICAgICAgICB0b29sczogTm9uTnVsbGFibGU8TWNwU2VydmVyU2NoZW1hW1widG9vbHNcIl0+O1xuICAgICAgfSA9PiBBcnJheS5pc0FycmF5KHMudG9vbHMpICYmIHMudG9vbHMubGVuZ3RoID4gMFxuICAgIClcbiAgICAubWFwKChzZXJ2ZXIpID0+IHtcbiAgICAgIGNvbnN0IHRvb2xEb2NzID0gc2VydmVyLnRvb2xzXG4gICAgICAgIC5tYXAoKHQpID0+IHtcbiAgICAgICAgICBsZXQgZG9jID0gYCAgLSAke3QubmFtZX06ICR7XG4gICAgICAgICAgICB0LmRlc2NyaXB0aW9uXG4gICAgICAgICAgfVxcbiAgICBJbnB1dDogJHtKU09OLnN0cmluZ2lmeSh0LmlucHV0U2NoZW1hKX1gO1xuICAgICAgICAgIGlmICh0Lm91dHB1dFNjaGVtYSkge1xuICAgICAgICAgICAgZG9jICs9IGBcXG4gICAgT3V0cHV0OiAke0pTT04uc3RyaW5naWZ5KHQub3V0cHV0U2NoZW1hKX1gO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gZG9jO1xuICAgICAgICB9KVxuICAgICAgICAuam9pbihcIlxcblwiKTtcbiAgICAgIHJldHVybiBgIyMjICR7c2VydmVyLm5hbWV9XFxuJHtzZXJ2ZXIuZGVzY3JpcHRpb24gPz8gXCJcIn1cXG4ke3Rvb2xEb2NzfWA7XG4gICAgfSlcbiAgICAuam9pbihcIlxcblxcblwiKTtcblxuICBpZiAoIXNlcnZlckRvY3MpIHtcbiAgICByZXR1cm4gXCJcIjtcbiAgfVxuXG4gIHJldHVybiBgIyMgTUNQIFRvb2xzXG5Vc2UgdGhlIEV4ZWN1dGVNQ1BUb29sIHRvIGNhbGwgdGhlc2UgY3VzdG9tIHRvb2xzOlxuXG4ke3NlcnZlckRvY3N9YDtcbn1cblxuZXhwb3J0IHR5cGUgQWdlbnRJbnB1dCA9IHtcbiAgc2Vzc2lvbklkOiBzdHJpbmc7XG4gIHN0b3JhZ2VDb25maWc6IFN0b3JhZ2VDb25maWc7XG59O1xuXG5leHBvcnQgdHlwZSBBZ2VudE1lc3NhZ2VJbnB1dCA9IHtcbiAgYXNzaXN0YW50TWVzc2FnZUlkOiBzdHJpbmc7XG4gIGhvb2tUb2tlbjogc3RyaW5nO1xufTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNvbXBsZXRlTWVzc2FnZVN0ZXAoe1xuICBhc3Npc3RhbnRNZXNzYWdlSWQsXG4gIGlucHV0LFxuICB3cml0YWJsZSxcbn06IHtcbiAgYXNzaXN0YW50TWVzc2FnZUlkOiBzdHJpbmc7XG4gIGlucHV0OiBBZ2VudElucHV0O1xuICB3cml0YWJsZTogV3JpdGFibGVTdHJlYW07XG59KSB7XG4gIFwidXNlIHN0ZXBcIjtcblxuICBjb25zdCB7IGdldFN0b3JhZ2UgfSA9IGF3YWl0IGltcG9ydChcIi4vc3RvcmFnZVwiKTtcbiAgY29uc3Qgc3RvcmFnZSA9IGdldFN0b3JhZ2UoaW5wdXQuc3RvcmFnZUNvbmZpZyk7XG5cbiAgY29uc3QgbWVzc2FnZSA9IGF3YWl0IHN0b3JhZ2UubWVzc2FnZS5nZXQoYXNzaXN0YW50TWVzc2FnZUlkKTtcbiAgaWYgKG1lc3NhZ2UgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgIHRocm93IG1lc3NhZ2U7XG4gIH1cbiAgaWYgKCFtZXNzYWdlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBNZXNzYWdlICR7YXNzaXN0YW50TWVzc2FnZUlkfSBub3QgZm91bmRgKTtcbiAgfVxuXG4gIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHN0b3JhZ2UubWVzc2FnZS5zZXQoe1xuICAgIC4uLm1lc3NhZ2UsXG4gICAgY29tcGxldGVkQXQ6IERhdGUubm93KCksXG4gIH0pO1xuICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICB0aHJvdyByZXN1bHQ7XG4gIH1cblxuICBhd2FpdCB3cml0YWJsZS5jbG9zZSgpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RyZWFtVGV4dFN0ZXAoe1xuICBhc3Npc3RhbnRNZXNzYWdlSWQsXG4gIGlucHV0LFxuICBldmVudCxcbiAgd3JpdGFibGUsXG4gIGxhc3RQYXJ0SW5kZXgsXG59OiB7XG4gIGFzc2lzdGFudE1lc3NhZ2VJZDogc3RyaW5nO1xuICBpbnB1dDogQWdlbnRJbnB1dDtcbiAgZXZlbnQ6IEFnZW50TWVzc2FnZUlucHV0O1xuICB3cml0YWJsZTogV3JpdGFibGVTdHJlYW07XG4gIGxhc3RQYXJ0SW5kZXg6IG51bWJlcjtcbn0pOiBQcm9taXNlPHsgZmluaXNoUmVhc29uOiBGaW5pc2hSZWFzb247IGxhc3RQYXJ0SW5kZXg6IG51bWJlciB9PiB7XG4gIFwidXNlIHN0ZXBcIjtcblxuICBjb25zdCB7IGdldFN0b3JhZ2UgfSA9IGF3YWl0IGltcG9ydChcIi4vc3RvcmFnZS9jbGllbnRcIik7XG4gIGNvbnN0IHsgZ2V0U2FuZGJveCB9ID0gYXdhaXQgaW1wb3J0KFwiLi9zYW5kYm94XCIpO1xuXG4gIGNvbnN0IHN0b3JhZ2UgPSBnZXRTdG9yYWdlKGlucHV0LnN0b3JhZ2VDb25maWcpO1xuICBjb25zdCBzZXNzaW9uID0gYXdhaXQgc3RvcmFnZS5zZXNzaW9uLmdldChpbnB1dC5zZXNzaW9uSWQpO1xuXG4gIGlmIChzZXNzaW9uIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICB0aHJvdyBzZXNzaW9uO1xuICB9XG4gIHNlc3Npb247XG5cbiAgY29uc3Qgc2FuZGJveFJlY29yZCA9IHNlc3Npb24uc2FuZGJveElkXG4gICAgPyBhd2FpdCBzdG9yYWdlLnNhbmRib3guZ2V0KHNlc3Npb24uc2FuZGJveElkKVxuICAgIDogbnVsbDtcbiAgaWYgKHNhbmRib3hSZWNvcmQgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgIHRocm93IHNhbmRib3hSZWNvcmQ7XG4gIH1cbiAgaWYgKCFzYW5kYm94UmVjb3JkKSB7XG4gICAgdGhyb3cgbmV3IEZhdGFsRXJyb3IoYFNhbmRib3ggbm90IGZvdW5kIGZvciBzZXNzaW9uICR7aW5wdXQuc2Vzc2lvbklkfWApO1xuICB9XG5cbiAgY29uc3Qgc2FuZGJveCA9IGdldFNhbmRib3goe1xuICAgIHNhbmRib3hSZWNvcmQsXG4gICAgc3RvcmFnZUNvbmZpZzogaW5wdXQuc3RvcmFnZUNvbmZpZyxcbiAgfSk7XG5cbiAgY29uc3QgW21lc3NhZ2VzUmVzdWx0LCBwYXJ0c1Jlc3VsdCwgc2tpbGxzXSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICBzdG9yYWdlLm1lc3NhZ2UubGlzdChpbnB1dC5zZXNzaW9uSWQpLFxuICAgIHN0b3JhZ2UucGFydC5saXN0QnlTZXNzaW9uKGlucHV0LnNlc3Npb25JZCksXG4gICAgc2Vzc2lvbi5za2lsbHNEaXIgJiYgc2Vzc2lvbi5za2lsbHNEaXIubGVuZ3RoID4gMFxuICAgICAgPyBkaXNjb3ZlclNraWxsc0luU2FuZGJveCh7IHNhbmRib3gsIHNraWxsc0RpcnM6IHNlc3Npb24uc2tpbGxzRGlyIH0pXG4gICAgICA6IFByb21pc2UucmVzb2x2ZShbXSksXG4gIF0pO1xuXG4gIGlmIChtZXNzYWdlc1Jlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgdGhyb3cgbWVzc2FnZXNSZXN1bHQ7XG4gIH1cbiAgaWYgKHBhcnRzUmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICB0aHJvdyBwYXJ0c1Jlc3VsdDtcbiAgfVxuXG4gIGNvbnN0IHVpTWVzc2FnZXMgPSBhc3NlbWJsZVVJTWVzc2FnZXMoe1xuICAgIG1lc3NhZ2VzOiBtZXNzYWdlc1Jlc3VsdC5pdGVtcyxcbiAgICBwYXJ0czogcGFydHNSZXN1bHQuaXRlbXMsXG4gIH0pO1xuXG4gIGNvbnN0IG1jcCA9IHNlc3Npb24ubWNwIGFzIE1jcFNlcnZlclNjaGVtYVtdIHwgbnVsbDtcblxuICBjb25zdCBzeXN0ZW1Qcm9tcHQgPSBqb2luUHJvbXB0U2VjdGlvbnMoXG4gICAgQkFTRV9TWVNURU1fUFJPTVBULFxuICAgIHNlc3Npb24uaW5zdHJ1Y3Rpb25zLFxuICAgIGJ1aWxkU2tpbGxzQ29udGV4dChza2lsbHMpLFxuICAgIGJ1aWxkTWNwVG9vbHNDb250ZXh0KG1jcClcbiAgKTtcblxuICBpZiAoIXNlc3Npb24ubW9kZWwpIHtcbiAgICB0aHJvdyBuZXcgRmF0YWxFcnJvcihcIlNlc3Npb24gbW9kZWwgaXMgbm90IHNldFwiKTtcbiAgfVxuXG4gIGNvbnN0IHJlc3VsdCA9IHN0cmVhbVRleHQoe1xuICAgIG1lc3NhZ2VzOiBhd2FpdCBjb252ZXJ0VG9Nb2RlbE1lc3NhZ2VzKHVpTWVzc2FnZXMpLFxuICAgIHRvb2xzOiBnZXRUb29scyh7IGlucHV0LCBldmVudCwgbWNwLCBzYW5kYm94IH0pLFxuICAgIHN5c3RlbTogc3lzdGVtUHJvbXB0LFxuICAgIG1vZGVsOiBzZXNzaW9uLm1vZGVsLFxuICB9KTtcblxuICBjb25zdCBzdGVwUGFydHM6IFVJTWVzc2FnZVtcInBhcnRzXCJdID0gW107XG4gIGF3YWl0IHJlc3VsdFxuICAgIC50b1VJTWVzc2FnZVN0cmVhbSh7XG4gICAgICBnZW5lcmF0ZU1lc3NhZ2VJZDogKCkgPT4gYXNzaXN0YW50TWVzc2FnZUlkLFxuICAgICAgb25GaW5pc2g6ICh7IG1lc3NhZ2VzIH0pID0+IHtcbiAgICAgICAgZm9yIChjb25zdCBtIG9mIG1lc3NhZ2VzKSB7XG4gICAgICAgICAgaWYgKG0ucm9sZSA9PT0gXCJhc3Npc3RhbnRcIikge1xuICAgICAgICAgICAgc3RlcFBhcnRzLnB1c2goLi4ubS5wYXJ0cyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9LFxuICAgIH0pXG4gICAgLnBpcGVUbyh3cml0YWJsZSwgeyBwcmV2ZW50Q2xvc2U6IHRydWUgfSk7XG5cbiAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgc3RlcFBhcnRzLm1hcChhc3luYyAodWlQYXJ0LCBpbmRleCkgPT4ge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgc3RvcmFnZS5wYXJ0LnNldCh7XG4gICAgICAgIGlkOiBgcGFydF8ke3VsaWQoKX1gLFxuICAgICAgICBpbmRleDogbGFzdFBhcnRJbmRleCArIGluZGV4LFxuICAgICAgICBtZXNzYWdlSWQ6IGFzc2lzdGFudE1lc3NhZ2VJZCxcbiAgICAgICAgc2Vzc2lvbklkOiBpbnB1dC5zZXNzaW9uSWQsXG4gICAgICAgIHBhcnQ6IHVpUGFydCxcbiAgICAgIH0pO1xuICAgICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICAgIHRocm93IHJlc3VsdDtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSlcbiAgKTtcblxuICByZXR1cm4ge1xuICAgIGZpbmlzaFJlYXNvbjogYXdhaXQgcmVzdWx0LmZpbmlzaFJlYXNvbixcbiAgICBsYXN0UGFydEluZGV4OiBsYXN0UGFydEluZGV4ICsgc3RlcFBhcnRzLmxlbmd0aCxcbiAgfTtcbn1cbiIsICJpbXBvcnQgdHlwZSB7IFNraWxsc0RpciB9IGZyb20gXCIuL3R5cGVzXCI7XG5cbi8qKlxuICogUGFyc2VkIGZyb250bWF0dGVyIGZyb20gYSBTS0lMTC5tZCBmaWxlLlxuICovXG5leHBvcnQgdHlwZSBTa2lsbEZyb250bWF0dGVyID0ge1xuICBuYW1lOiBzdHJpbmc7XG4gIGRlc2NyaXB0aW9uOiBzdHJpbmc7XG59O1xuXG4vKipcbiAqIFBhcnNlcyBZQU1MIGZyb250bWF0dGVyIGZyb20gYSBTS0lMTC5tZCBmaWxlIGNvbnRlbnQuXG4gKiBGcm9udG1hdHRlciBtdXN0IGJlIGF0IHRoZSBzdGFydCBvZiB0aGUgZmlsZSwgZGVsaW1pdGVkIGJ5IGAtLS1gIG1hcmtlcnMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYG1hcmtkb3duXG4gKiAtLS1cbiAqIG5hbWU6IGNzdlxuICogZGVzY3JpcHRpb246IEFuYWx5emUgQ1NWIGRhdGFcbiAqIC0tLVxuICogIyBDU1YgU2tpbGxcbiAqIC4uLlxuICogYGBgXG4gKlxuICogQHJldHVybnMgUGFyc2VkIG5hbWUgYW5kIGRlc2NyaXB0aW9uLCBvciBudWxsIGlmIGZyb250bWF0dGVyIGlzIG1pc3NpbmcvaW52YWxpZFxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VTa2lsbEZyb250bWF0dGVyKFxuICBjb250ZW50OiBzdHJpbmdcbik6IFNraWxsRnJvbnRtYXR0ZXIgfCBudWxsIHtcbiAgY29uc3QgdHJpbW1lZCA9IGNvbnRlbnQudHJpbSgpO1xuXG4gIGlmICghdHJpbW1lZC5zdGFydHNXaXRoKFwiLS0tXCIpKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCBlbmRNYXJrZXJJbmRleCA9IHRyaW1tZWQuaW5kZXhPZihcIi0tLVwiLCAzKTtcbiAgaWYgKGVuZE1hcmtlckluZGV4ID09PSAtMSkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3QgZnJvbnRtYXR0ZXJCbG9jayA9IHRyaW1tZWQuc2xpY2UoMywgZW5kTWFya2VySW5kZXgpLnRyaW0oKTtcbiAgY29uc3QgcGFyc2VkID0gcGFyc2VTaW1wbGVZYW1sKGZyb250bWF0dGVyQmxvY2spO1xuXG4gIGlmICghKHBhcnNlZC5uYW1lICYmIHBhcnNlZC5kZXNjcmlwdGlvbikpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgbmFtZTogU3RyaW5nKHBhcnNlZC5uYW1lKSxcbiAgICBkZXNjcmlwdGlvbjogU3RyaW5nKHBhcnNlZC5kZXNjcmlwdGlvbiksXG4gIH07XG59XG5cbi8qKlxuICogUGFyc2VzIHNpbXBsZSBZQU1MIGtleS12YWx1ZSBwYWlycyAoc2luZ2xlLWxpbmUgdmFsdWVzIG9ubHkpLlxuICogVGhpcyBhdm9pZHMgYWRkaW5nIGEgZnVsbCBZQU1MIHBhcnNlciBkZXBlbmRlbmN5IGZvciBiYXNpYyBmcm9udG1hdHRlci5cbiAqL1xuZnVuY3Rpb24gcGFyc2VTaW1wbGVZYW1sKHlhbWw6IHN0cmluZyk6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4ge1xuICBjb25zdCByZXN1bHQ6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcblxuICBmb3IgKGNvbnN0IGxpbmUgb2YgeWFtbC5zcGxpdChcIlxcblwiKSkge1xuICAgIGNvbnN0IHRyaW1tZWRMaW5lID0gbGluZS50cmltKCk7XG4gICAgaWYgKCF0cmltbWVkTGluZSB8fCB0cmltbWVkTGluZS5zdGFydHNXaXRoKFwiI1wiKSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgY29uc3QgY29sb25JbmRleCA9IHRyaW1tZWRMaW5lLmluZGV4T2YoXCI6XCIpO1xuICAgIGlmIChjb2xvbkluZGV4ID09PSAtMSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgY29uc3Qga2V5ID0gdHJpbW1lZExpbmUuc2xpY2UoMCwgY29sb25JbmRleCkudHJpbSgpO1xuICAgIGxldCB2YWx1ZSA9IHRyaW1tZWRMaW5lLnNsaWNlKGNvbG9uSW5kZXggKyAxKS50cmltKCk7XG5cbiAgICAvLyBSZW1vdmUgc3Vycm91bmRpbmcgcXVvdGVzIGlmIHByZXNlbnRcbiAgICBpZiAoXG4gICAgICAodmFsdWUuc3RhcnRzV2l0aCgnXCInKSAmJiB2YWx1ZS5lbmRzV2l0aCgnXCInKSkgfHxcbiAgICAgICh2YWx1ZS5zdGFydHNXaXRoKFwiJ1wiKSAmJiB2YWx1ZS5lbmRzV2l0aChcIidcIikpXG4gICAgKSB7XG4gICAgICB2YWx1ZSA9IHZhbHVlLnNsaWNlKDEsIC0xKTtcbiAgICB9XG5cbiAgICBpZiAoa2V5KSB7XG4gICAgICByZXN1bHRba2V5XSA9IHZhbHVlO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKlxuICogTm9ybWFsaXplcyBza2lsbHNEaXIgdG8gYW4gYXJyYXkgb2Ygc3RyaW5ncy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5vcm1hbGl6ZVNraWxsc0RpcnMoc2tpbGxzRGlyPzogU2tpbGxzRGlyKTogc3RyaW5nW10ge1xuICBpZiAoIXNraWxsc0Rpcikge1xuICAgIHJldHVybiBbXTtcbiAgfVxuICByZXR1cm4gQXJyYXkuaXNBcnJheShza2lsbHNEaXIpID8gc2tpbGxzRGlyIDogW3NraWxsc0Rpcl07XG59XG4iLCAiaW1wb3J0IHR5cGUgeyBTYW5kYm94IH0gZnJvbSBcIi4uL3NhbmRib3hcIjtcbmltcG9ydCB7IHBhcnNlU2tpbGxGcm9udG1hdHRlciB9IGZyb20gXCIuL3BhcnNlclwiO1xuaW1wb3J0IHR5cGUgeyBTa2lsbFN1bW1hcnkgfSBmcm9tIFwiLi90eXBlc1wiO1xuXG4vKipcbiAqIERpc2NvdmVycyBza2lsbHMgZnJvbSBkaXJlY3RvcmllcyBpbnNpZGUgdGhlIHNhbmRib3ggYnkgZmluZGluZyBhbmQgcGFyc2luZyBTS0lMTC5tZCBmaWxlcy5cbiAqIFNjYW5zIGVhY2ggZGlyZWN0b3J5IGZvciBzdWJkaXJlY3RvcmllcyBjb250YWluaW5nIFNLSUxMLm1kLCBleHRyYWN0cyBmcm9udG1hdHRlciBtZXRhZGF0YSxcbiAqIGFuZCByZXR1cm5zIHN1bW1hcmllcyBmb3IgdXNlIGluIHRoZSBzeXN0ZW0gcHJvbXB0LlxuICpcbiAqIEByZXR1cm5zIEFycmF5IG9mIHNraWxsIHN1bW1hcmllcyAoZGVkdXBsaWNhdGVkIGJ5IG5hbWUsIGZpcnN0IG9jY3VycmVuY2Ugd2lucylcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGRpc2NvdmVyU2tpbGxzSW5TYW5kYm94KG9wdHM6IHtcbiAgc2FuZGJveDogU2FuZGJveDtcbiAgc2tpbGxzRGlyczogc3RyaW5nW107XG4gIGRlYnVnPzogYm9vbGVhbjtcbn0pOiBQcm9taXNlPFNraWxsU3VtbWFyeVtdPiB7XG4gIGNvbnN0IHsgc2FuZGJveCwgc2tpbGxzRGlycywgZGVidWcgfSA9IG9wdHM7XG4gIGNvbnN0IHN1bW1hcmllczogU2tpbGxTdW1tYXJ5W10gPSBbXTtcbiAgY29uc3Qgc2Vlbk5hbWVzID0gbmV3IFNldDxzdHJpbmc+KCk7XG5cbiAgZm9yIChjb25zdCBza2lsbHNEaXIgb2Ygc2tpbGxzRGlycykge1xuICAgIGNvbnN0IGRpclN1bW1hcmllcyA9IGF3YWl0IGRpc2NvdmVyU2tpbGxzSW5EaXJlY3Rvcnkoe1xuICAgICAgc2FuZGJveCxcbiAgICAgIHNraWxsc0RpcixcbiAgICAgIGRlYnVnLFxuICAgIH0pO1xuXG4gICAgZm9yIChjb25zdCBzdW1tYXJ5IG9mIGRpclN1bW1hcmllcykge1xuICAgICAgaWYgKCFzZWVuTmFtZXMuaGFzKHN1bW1hcnkubmFtZSkpIHtcbiAgICAgICAgc2Vlbk5hbWVzLmFkZChzdW1tYXJ5Lm5hbWUpO1xuICAgICAgICBzdW1tYXJpZXMucHVzaChzdW1tYXJ5KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gc3VtbWFyaWVzO1xufVxuXG5hc3luYyBmdW5jdGlvbiBkaXNjb3ZlclNraWxsc0luRGlyZWN0b3J5KG9wdHM6IHtcbiAgc2FuZGJveDogU2FuZGJveDtcbiAgc2tpbGxzRGlyOiBzdHJpbmc7XG4gIGRlYnVnPzogYm9vbGVhbjtcbn0pOiBQcm9taXNlPFNraWxsU3VtbWFyeVtdPiB7XG4gIGNvbnN0IHsgc2FuZGJveCwgc2tpbGxzRGlyLCBkZWJ1ZyB9ID0gb3B0cztcbiAgY29uc3Qgc2tpbGxQYXRocyA9IGF3YWl0IGZpbmRTa2lsbEZpbGVzKHsgc2FuZGJveCwgc2tpbGxzRGlyLCBkZWJ1ZyB9KTtcblxuICBpZiAoc2tpbGxQYXRocy5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gW107XG4gIH1cblxuICBjb25zdCBzdW1tYXJpZXM6IFNraWxsU3VtbWFyeVtdID0gW107XG5cbiAgZm9yIChjb25zdCBza2lsbE1kUGF0aCBvZiBza2lsbFBhdGhzKSB7XG4gICAgY29uc3Qgc3VtbWFyeSA9IGF3YWl0IHBhcnNlU2tpbGxGaWxlKHsgc2FuZGJveCwgc2tpbGxNZFBhdGgsIGRlYnVnIH0pO1xuICAgIGlmIChzdW1tYXJ5KSB7XG4gICAgICBzdW1tYXJpZXMucHVzaChzdW1tYXJ5KTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gc3VtbWFyaWVzO1xufVxuXG5hc3luYyBmdW5jdGlvbiBmaW5kU2tpbGxGaWxlcyhvcHRzOiB7XG4gIHNhbmRib3g6IFNhbmRib3g7XG4gIHNraWxsc0Rpcjogc3RyaW5nO1xuICBkZWJ1Zz86IGJvb2xlYW47XG59KTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICBjb25zdCB7IHNhbmRib3gsIHNraWxsc0RpciwgZGVidWcgfSA9IG9wdHM7XG4gIGlmIChkZWJ1Zykge1xuICAgIGNvbnNvbGUubG9nKGBbZGlzY292ZXJdIEZpbmRpbmcgc2tpbGxzIGluOiAke3NraWxsc0Rpcn1gKTtcbiAgfVxuICBjb25zdCBleGVjUmVzdWx0ID0gYXdhaXQgc2FuZGJveC5leGVjKHtcbiAgICBjb21tYW5kOiBcImZpbmRcIixcbiAgICBhcmdzOiBbc2tpbGxzRGlyLCBcIi1uYW1lXCIsIFwiU0tJTEwubWRcIiwgXCItdHlwZVwiLCBcImZcIl0sXG4gIH0pO1xuXG4gIGlmIChleGVjUmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICBpZiAoZGVidWcpIHtcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgYFtkaXNjb3Zlcl0gRmFpbGVkIHRvIHNjYW4gc2tpbGxzIGRpcmVjdG9yeSBcIiR7c2tpbGxzRGlyfVwiOiAke2V4ZWNSZXN1bHQubWVzc2FnZX1gXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gW107XG4gIH1cblxuICBjb25zdCB7IHN0ZG91dCwgc3RkZXJyLCBleGl0Q29kZSB9ID0gYXdhaXQgZXhlY1Jlc3VsdC5yZXN1bHQ7XG4gIGlmIChkZWJ1Zykge1xuICAgIGNvbnNvbGUubG9nKFxuICAgICAgYFtkaXNjb3Zlcl0gZmluZCByZXN1bHQ6IGV4aXRDb2RlPSR7ZXhpdENvZGV9LCBzdGRvdXQ9XCIke3N0ZG91dC50cmltKCl9XCIsIHN0ZGVycj1cIiR7c3RkZXJyLnRyaW0oKX1cImBcbiAgICApO1xuICB9XG5cbiAgaWYgKGV4aXRDb2RlICE9PSAwKSB7XG4gICAgaWYgKGRlYnVnKSB7XG4gICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgIGBbZGlzY292ZXJdIFNraWxscyBkaXJlY3Rvcnkgbm90IGZvdW5kIG9yIGluYWNjZXNzaWJsZTogJHtza2lsbHNEaXJ9YFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgY29uc3QgcGF0aHMgPSBzdGRvdXRcbiAgICAudHJpbSgpXG4gICAgLnNwbGl0KFwiXFxuXCIpXG4gICAgLmZpbHRlcigocCkgPT4gcC5sZW5ndGggPiAwKTtcbiAgaWYgKGRlYnVnKSB7XG4gICAgY29uc29sZS5sb2coXCJbZGlzY292ZXJdIEZvdW5kIHNraWxsIHBhdGhzOlwiLCBwYXRocyk7XG4gIH1cbiAgcmV0dXJuIHBhdGhzO1xufVxuXG5hc3luYyBmdW5jdGlvbiBwYXJzZVNraWxsRmlsZShvcHRzOiB7XG4gIHNhbmRib3g6IFNhbmRib3g7XG4gIHNraWxsTWRQYXRoOiBzdHJpbmc7XG4gIGRlYnVnPzogYm9vbGVhbjtcbn0pOiBQcm9taXNlPFNraWxsU3VtbWFyeSB8IG51bGw+IHtcbiAgY29uc3QgeyBzYW5kYm94LCBza2lsbE1kUGF0aCwgZGVidWcgfSA9IG9wdHM7XG4gIGNvbnN0IGV4ZWNSZXN1bHQgPSBhd2FpdCBzYW5kYm94LmV4ZWMoe1xuICAgIGNvbW1hbmQ6IFwiY2F0XCIsXG4gICAgYXJnczogW3NraWxsTWRQYXRoXSxcbiAgfSk7XG5cbiAgaWYgKGV4ZWNSZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgIGlmIChkZWJ1Zykge1xuICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICBgW2Rpc2NvdmVyXSBGYWlsZWQgdG8gcmVhZCBza2lsbCBmaWxlIFwiJHtza2lsbE1kUGF0aH1cIjogJHtleGVjUmVzdWx0Lm1lc3NhZ2V9YFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCB7IHN0ZG91dCwgZXhpdENvZGUgfSA9IGF3YWl0IGV4ZWNSZXN1bHQucmVzdWx0O1xuXG4gIGlmIChleGl0Q29kZSAhPT0gMCkge1xuICAgIGlmIChkZWJ1Zykge1xuICAgICAgY29uc29sZS53YXJuKGBbZGlzY292ZXJdIENvdWxkIG5vdCByZWFkIHNraWxsIGZpbGU6ICR7c2tpbGxNZFBhdGh9YCk7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3QgcGFyc2VkID0gcGFyc2VTa2lsbEZyb250bWF0dGVyKHN0ZG91dCk7XG5cbiAgaWYgKCFwYXJzZWQpIHtcbiAgICBpZiAoZGVidWcpIHtcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgYFtkaXNjb3Zlcl0gSW52YWxpZCBvciBtaXNzaW5nIGZyb250bWF0dGVyIGluOiAke3NraWxsTWRQYXRofWBcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBuYW1lOiBwYXJzZWQubmFtZSxcbiAgICBkZXNjcmlwdGlvbjogcGFyc2VkLmRlc2NyaXB0aW9uLFxuICAgIHNraWxsTWRQYXRoLFxuICB9O1xufVxuIiwgImltcG9ydCB7IHR5cGUgVG9vbFNldCwgdG9vbCB9IGZyb20gXCJhaVwiO1xuaW1wb3J0IHsgeiB9IGZyb20gXCJ6b2RcIjtcbmltcG9ydCB0eXBlIHsgQWdlbnRJbnB1dCwgQWdlbnRNZXNzYWdlSW5wdXQgfSBmcm9tIFwiLi4vYWdlbnQtd29ya2Zsb3dcIjtcbmltcG9ydCB0eXBlIHsgTWNwU2VydmVyU2NoZW1hIH0gZnJvbSBcIi4uL21jcFwiO1xuaW1wb3J0IHR5cGUgeyBTYW5kYm94IH0gZnJvbSBcIi4uL3NhbmRib3hcIjtcblxuZXhwb3J0IHR5cGUgVG9vbENvbnRleHQgPSB7XG4gIGlucHV0OiBBZ2VudElucHV0O1xuICBldmVudDogQWdlbnRNZXNzYWdlSW5wdXQ7XG4gIG1jcDogTWNwU2VydmVyU2NoZW1hW10gfCBudWxsO1xuICBzYW5kYm94OiBTYW5kYm94O1xuICB3YWl0VW50aWw/OiAocHJvbWlzZTogUHJvbWlzZTx1bmtub3duPikgPT4gdm9pZDtcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRUb29scyhjb250ZXh0OiBUb29sQ29udGV4dCkge1xuICByZXR1cm4ge1xuICAgIFJlYWQ6IHRvb2woe1xuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgIFwiUmVhZHMgYSBmaWxlIGFuZCByZXR1cm5zIGl0cyBjb250ZW50cyB3aXRoIG1ldGFkYXRhLiBGb3IgZmlsZXMgb3ZlciAyMDAgbGluZXMsIGF1dG9tYXRpY2FsbHkgc2hvd3MgZmlyc3QgMTAwIGxpbmVzIHVubGVzcyBhIHNwZWNpZmljIGxpbmUgcmFuZ2UgaXMgcHJvdmlkZWQuIFVzZSBzdGFydExpbmUgYW5kIGVuZExpbmUgcGFyYW1ldGVycyB0byByZWFkIHNwZWNpZmljIHBvcnRpb25zIG9mIGxhcmdlIGZpbGVzLlwiLFxuICAgICAgaW5wdXRTY2hlbWE6IHoub2JqZWN0KHtcbiAgICAgICAgcGF0aDogelxuICAgICAgICAgIC5zdHJpbmcoKVxuICAgICAgICAgIC5kZXNjcmliZShcIlBhdGggdG8gdGhlIGZpbGUgcmVsYXRpdmUgdG8gd29ya3NwYWNlIHJvb3RcIiksXG4gICAgICAgIHN0YXJ0TGluZTogelxuICAgICAgICAgIC5udW1iZXIoKVxuICAgICAgICAgIC5vcHRpb25hbCgpXG4gICAgICAgICAgLmRlc2NyaWJlKFxuICAgICAgICAgICAgXCJTdGFydGluZyBsaW5lIG51bWJlciAoMS1pbmRleGVkKS4gSWYgcHJvdmlkZWQgd2l0aCBlbmRMaW5lLCByZWFkcyBleGFjdCByYW5nZSByZWdhcmRsZXNzIG9mIGZpbGUgc2l6ZS5cIlxuICAgICAgICAgICksXG4gICAgICAgIGVuZExpbmU6IHpcbiAgICAgICAgICAubnVtYmVyKClcbiAgICAgICAgICAub3B0aW9uYWwoKVxuICAgICAgICAgIC5kZXNjcmliZShcbiAgICAgICAgICAgIFwiRW5kaW5nIGxpbmUgbnVtYmVyICgxLWluZGV4ZWQsIGluY2x1c2l2ZSkuIElmIHByb3ZpZGVkIHdpdGggc3RhcnRMaW5lLCByZWFkcyBleGFjdCByYW5nZSByZWdhcmRsZXNzIG9mIGZpbGUgc2l6ZS5cIlxuICAgICAgICAgICksXG4gICAgICB9KSxcbiAgICAgIG91dHB1dFNjaGVtYTogei5vYmplY3Qoe1xuICAgICAgICBjb250ZW50OiB6LnN0cmluZygpLmRlc2NyaWJlKFwiRmlsZSBjb250ZW50XCIpLFxuICAgICAgICBtZXRhZGF0YTogei5vYmplY3Qoe1xuICAgICAgICAgIHRvdGFsTGluZXM6IHoubnVtYmVyKCkuZGVzY3JpYmUoXCJUb3RhbCBudW1iZXIgb2YgbGluZXMgaW4gdGhlIGZpbGVcIiksXG4gICAgICAgICAgbGluZXNTaG93bjogelxuICAgICAgICAgICAgLm51bWJlcigpXG4gICAgICAgICAgICAuZGVzY3JpYmUoXCJOdW1iZXIgb2YgbGluZXMgaW5jbHVkZWQgaW4gdGhpcyByZXNwb25zZVwiKSxcbiAgICAgICAgICBzdGFydExpbmU6IHoubnVtYmVyKCkuZGVzY3JpYmUoXCJGaXJzdCBsaW5lIG51bWJlciBzaG93biAoMS1pbmRleGVkKVwiKSxcbiAgICAgICAgICBlbmRMaW5lOiB6Lm51bWJlcigpLmRlc2NyaWJlKFwiTGFzdCBsaW5lIG51bWJlciBzaG93biAoMS1pbmRleGVkKVwiKSxcbiAgICAgICAgICBpc1BhZ2luYXRlZDogelxuICAgICAgICAgICAgLmJvb2xlYW4oKVxuICAgICAgICAgICAgLmRlc2NyaWJlKFwiV2hldGhlciB0aGlzIGlzIGEgcGFydGlhbCB2aWV3IG9mIHRoZSBmaWxlXCIpLFxuICAgICAgICAgIGZpbGVTaXplOiB6XG4gICAgICAgICAgICAuc3RyaW5nKClcbiAgICAgICAgICAgIC5kZXNjcmliZShcIkh1bWFuLXJlYWRhYmxlIGZpbGUgc2l6ZSAoZS5nLiwgJzIuNUsnLCAnMS4yTScpXCIpLFxuICAgICAgICAgIHBhdGg6IHpcbiAgICAgICAgICAgIC5zdHJpbmcoKVxuICAgICAgICAgICAgLmRlc2NyaWJlKFwiUGF0aCB0byB0aGUgZmlsZSByZWxhdGl2ZSB0byB3b3Jrc3BhY2Ugcm9vdFwiKSxcbiAgICAgICAgfSksXG4gICAgICB9KSxcbiAgICAgIGV4ZWN1dGU6IGFzeW5jICh7IHBhdGgsIHN0YXJ0TGluZSwgZW5kTGluZSB9KSA9PiB7XG4gICAgICAgIGNvbnN0IGZpbGVQYXRoID0gcGF0aC5zdGFydHNXaXRoKFwiL1wiKSA/IHBhdGguc2xpY2UoMSkgOiBwYXRoO1xuXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNvbnRleHQuc2FuZGJveC5leGVjKHtcbiAgICAgICAgICBjb21tYW5kOiBcImJhc2hcIixcbiAgICAgICAgICBhcmdzOiBbXG4gICAgICAgICAgICBcIi1jXCIsXG4gICAgICAgICAgICBgXG4gICAgICAgICAgICBzZXQgLWVcbiAgICAgICAgICAgIEZJTEU9XCIkMVwiXG4gICAgICAgICAgICBTVEFSVF9MSU5FPVwiJDJcIlxuICAgICAgICAgICAgRU5EX0xJTkU9XCIkM1wiXG5cbiAgICAgICAgICAgICMgUmVzb2x2ZSBzeW1saW5rcyBhbmQgY2hlY2sgZmlsZSBleGlzdHNcbiAgICAgICAgICAgIGlmIFsgLUwgXCIkRklMRVwiIF07IHRoZW5cbiAgICAgICAgICAgICAgUkVTT0xWRUQ9JChyZWFkbGluayAtZiBcIiRGSUxFXCIgMj4vZGV2L251bGwgfHwgZWNobyBcIlwiKVxuICAgICAgICAgICAgICBpZiBbIC16IFwiJFJFU09MVkVEXCIgXSB8fCBbICEgLWUgXCIkUkVTT0xWRURcIiBdOyB0aGVuXG4gICAgICAgICAgICAgICAgZWNobyBcIkVycm9yOiBCcm9rZW4gc3ltbGluayAtICRGSUxFIHBvaW50cyB0byBub24tZXhpc3RlbnQgdGFyZ2V0XCIgPiYyXG4gICAgICAgICAgICAgICAgZXhpdCAxXG4gICAgICAgICAgICAgIGZpXG4gICAgICAgICAgICAgIEZJTEU9XCIkUkVTT0xWRURcIlxuICAgICAgICAgICAgZWxpZiBbICEgLWUgXCIkRklMRVwiIF07IHRoZW5cbiAgICAgICAgICAgICAgZWNobyBcIkVycm9yOiBGaWxlIG5vdCBmb3VuZCAtICRGSUxFXCIgPiYyXG4gICAgICAgICAgICAgIGV4aXQgMVxuICAgICAgICAgICAgZmlcblxuICAgICAgICAgICAgIyBHZXQgbWV0YWRhdGEgKGNvdW50IGFjdHVhbCBsaW5lcywgbm90IGp1c3QgbmV3bGluZXMpXG4gICAgICAgICAgICBUT1RBTF9MSU5FUz0kKGF3ayAnRU5Ee3ByaW50IE5SfScgXCIkRklMRVwiKVxuICAgICAgICAgICAgRklMRV9TSVpFPSQobHMgLWxoIFwiJEZJTEVcIiB8IGF3ayAne3ByaW50ICQ1fScpXG5cbiAgICAgICAgICAgICMgRGV0ZXJtaW5lIHJhbmdlXG4gICAgICAgICAgICBQQUdFX1NJWkU9MTAwXG4gICAgICAgICAgICBpZiBbIC1uIFwiJFNUQVJUX0xJTkVcIiBdICYmIFsgLW4gXCIkRU5EX0xJTkVcIiBdOyB0aGVuXG4gICAgICAgICAgICAgICMgQm90aCBwcm92aWRlZCAtIHVzZSBleGFjdCByYW5nZVxuICAgICAgICAgICAgICBBQ1RVQUxfU1RBUlQ9JFNUQVJUX0xJTkVcbiAgICAgICAgICAgICAgQUNUVUFMX0VORD0kRU5EX0xJTkVcbiAgICAgICAgICAgIGVsaWYgWyAtbiBcIiRTVEFSVF9MSU5FXCIgXTsgdGhlblxuICAgICAgICAgICAgICAjIE9ubHkgc3RhcnRMaW5lIC0gcmVhZCBQQUdFX1NJWkUgbGluZXMgZnJvbSB0aGVyZVxuICAgICAgICAgICAgICBBQ1RVQUxfU1RBUlQ9JFNUQVJUX0xJTkVcbiAgICAgICAgICAgICAgQUNUVUFMX0VORD0kKChTVEFSVF9MSU5FICsgUEFHRV9TSVpFIC0gMSkpXG4gICAgICAgICAgICAgIFsgXCIkQUNUVUFMX0VORFwiIC1ndCBcIiRUT1RBTF9MSU5FU1wiIF0gJiYgQUNUVUFMX0VORD0kVE9UQUxfTElORVNcbiAgICAgICAgICAgIGVsaWYgWyAtbiBcIiRFTkRfTElORVwiIF07IHRoZW5cbiAgICAgICAgICAgICAgIyBPbmx5IGVuZExpbmUgLSByZWFkIGZyb20gYmVnaW5uaW5nIHRvIGVuZExpbmVcbiAgICAgICAgICAgICAgQUNUVUFMX1NUQVJUPTFcbiAgICAgICAgICAgICAgQUNUVUFMX0VORD0kRU5EX0xJTkVcbiAgICAgICAgICAgIGVsaWYgWyBcIiRUT1RBTF9MSU5FU1wiIC1ndCAyMDAgXTsgdGhlblxuICAgICAgICAgICAgICAjIE5vIHJhbmdlLCBsYXJnZSBmaWxlIC0gcGFnaW5hdGVcbiAgICAgICAgICAgICAgQUNUVUFMX1NUQVJUPTFcbiAgICAgICAgICAgICAgQUNUVUFMX0VORD0kUEFHRV9TSVpFXG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICMgTm8gcmFuZ2UsIHNtYWxsIGZpbGUgLSBzaG93IGFsbFxuICAgICAgICAgICAgICBBQ1RVQUxfU1RBUlQ9MVxuICAgICAgICAgICAgICBBQ1RVQUxfRU5EPSRUT1RBTF9MSU5FU1xuICAgICAgICAgICAgZmlcblxuICAgICAgICAgICAgIyBPdXRwdXQgbWV0YWRhdGEgZmlyc3QgKHNlcGFyYXRlZCBieSB8fHwgZm9yIHBhcnNpbmcpXG4gICAgICAgICAgICBlY2hvIFwiJFRPVEFMX0xJTkVTfCRGSUxFX1NJWkV8JEFDVFVBTF9TVEFSVHwkQUNUVUFMX0VORFwiXG4gICAgICAgICAgICBlY2hvIFwifHx8Q09OVEVOVHx8fFwiXG5cbiAgICAgICAgICAgICMgUmVhZCBjb250ZW50XG4gICAgICAgICAgICBpZiBbIFwiJEFDVFVBTF9TVEFSVFwiIC1lcSAxIF0gJiYgWyBcIiRBQ1RVQUxfRU5EXCIgLWVxIFwiJFRPVEFMX0xJTkVTXCIgXTsgdGhlblxuICAgICAgICAgICAgICBjYXQgXCIkRklMRVwiXG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgIHNlZCAtbiBcIlxcJHtBQ1RVQUxfU1RBUlR9LFxcJHtBQ1RVQUxfRU5EfXBcIiBcIiRGSUxFXCJcbiAgICAgICAgICAgIGZpXG4gICAgICAgICAgYCxcbiAgICAgICAgICAgIFwiLS1cIixcbiAgICAgICAgICAgIGZpbGVQYXRoLFxuICAgICAgICAgICAgc3RhcnRMaW5lPy50b1N0cmluZygpIHx8IFwiXCIsXG4gICAgICAgICAgICBlbmRMaW5lPy50b1N0cmluZygpIHx8IFwiXCIsXG4gICAgICAgICAgXSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcIltSZWFkIFRvb2xdXCIsIHJlc3VsdCk7XG4gICAgICAgICAgdGhyb3cgcmVzdWx0O1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgeyBzdGRvdXQsIHN0ZGVyciB9ID0gYXdhaXQgcmVzdWx0LnJlc3VsdDtcblxuICAgICAgICBpZiAoc3RkZXJyKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihgW1JlYWQgVG9vbF0gRXJyb3I6ICR7c3RkZXJyfWApO1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBjb250ZW50OiBgRXJyb3I6ICR7c3RkZXJyfWAsXG4gICAgICAgICAgICBtZXRhZGF0YToge1xuICAgICAgICAgICAgICB0b3RhbExpbmVzOiAwLFxuICAgICAgICAgICAgICBsaW5lc1Nob3duOiAwLFxuICAgICAgICAgICAgICBzdGFydExpbmU6IDAsXG4gICAgICAgICAgICAgIGVuZExpbmU6IDAsXG4gICAgICAgICAgICAgIGlzUGFnaW5hdGVkOiBmYWxzZSxcbiAgICAgICAgICAgICAgZmlsZVNpemU6IFwiMFwiLFxuICAgICAgICAgICAgICBwYXRoOiBmaWxlUGF0aCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IFttZXRhZGF0YUxpbmUsIC4uLnJlc3RdID0gc3Rkb3V0LnNwbGl0KFwifHx8Q09OVEVOVHx8fFwiKTtcbiAgICAgICAgY29uc3QgY29udGVudCA9IHJlc3Quam9pbihcInx8fENPTlRFTlR8fHxcIikudHJpbVN0YXJ0KCk7XG4gICAgICAgIGNvbnN0IFt0b3RhbExpbmVzU3RyLCBmaWxlU2l6ZSwgYWN0dWFsU3RhcnRTdHIsIGFjdHVhbEVuZFN0cl0gPVxuICAgICAgICAgIG1ldGFkYXRhTGluZS50cmltKCkuc3BsaXQoXCJ8XCIpO1xuXG4gICAgICAgIGNvbnN0IHRvdGFsTGluZXMgPSBOdW1iZXIucGFyc2VJbnQodG90YWxMaW5lc1N0ciwgMTApO1xuICAgICAgICBjb25zdCBhY3R1YWxTdGFydCA9IE51bWJlci5wYXJzZUludChhY3R1YWxTdGFydFN0ciwgMTApO1xuICAgICAgICBjb25zdCBhY3R1YWxFbmQgPSBOdW1iZXIucGFyc2VJbnQoYWN0dWFsRW5kU3RyLCAxMCk7XG5cbiAgICAgICAgaWYgKFxuICAgICAgICAgIE51bWJlci5pc05hTih0b3RhbExpbmVzKSB8fFxuICAgICAgICAgIE51bWJlci5pc05hTihhY3R1YWxTdGFydCkgfHxcbiAgICAgICAgICBOdW1iZXIuaXNOYU4oYWN0dWFsRW5kKVxuICAgICAgICApIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgICAgYFtSZWFkIFRvb2xdIEZhaWxlZCB0byBwYXJzZSBtZXRhZGF0YTogJHttZXRhZGF0YUxpbmV9YFxuICAgICAgICAgICk7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGNvbnRlbnQ6IGBFcnJvcjogRmFpbGVkIHRvIHBhcnNlIGZpbGUgbWV0YWRhdGEuIFJhdyBvdXRwdXQ6ICR7c3Rkb3V0LnNsaWNlKFxuICAgICAgICAgICAgICAwLFxuICAgICAgICAgICAgICA1MDBcbiAgICAgICAgICAgICl9YCxcbiAgICAgICAgICAgIG1ldGFkYXRhOiB7XG4gICAgICAgICAgICAgIHRvdGFsTGluZXM6IDAsXG4gICAgICAgICAgICAgIGxpbmVzU2hvd246IDAsXG4gICAgICAgICAgICAgIHN0YXJ0TGluZTogMCxcbiAgICAgICAgICAgICAgZW5kTGluZTogMCxcbiAgICAgICAgICAgICAgaXNQYWdpbmF0ZWQ6IGZhbHNlLFxuICAgICAgICAgICAgICBmaWxlU2l6ZTogXCJ1bmtub3duXCIsXG4gICAgICAgICAgICAgIHBhdGg6IGZpbGVQYXRoLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBjb250ZW50LFxuICAgICAgICAgIG1ldGFkYXRhOiB7XG4gICAgICAgICAgICB0b3RhbExpbmVzLFxuICAgICAgICAgICAgbGluZXNTaG93bjogTWF0aC5tYXgoMCwgYWN0dWFsRW5kIC0gYWN0dWFsU3RhcnQgKyAxKSxcbiAgICAgICAgICAgIHN0YXJ0TGluZTogYWN0dWFsU3RhcnQsXG4gICAgICAgICAgICBlbmRMaW5lOiBhY3R1YWxFbmQsXG4gICAgICAgICAgICBpc1BhZ2luYXRlZDogYWN0dWFsRW5kIDwgdG90YWxMaW5lcyxcbiAgICAgICAgICAgIGZpbGVTaXplOiBmaWxlU2l6ZSB8fCBcInVua25vd25cIixcbiAgICAgICAgICAgIHBhdGg6IGZpbGVQYXRoLFxuICAgICAgICAgIH0sXG4gICAgICAgIH07XG4gICAgICB9LFxuICAgIH0pLFxuICAgIEdyZXA6IHRvb2woe1xuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgIFwiU2VhcmNoIGZvciBwYXR0ZXJucyBpbiBmaWxlcyB1c2luZyByaXBncmVwLiBTdXBwb3J0cyByZWdleCBwYXR0ZXJucywgZmlsZSB0eXBlIGZpbHRlcmluZywgYW5kIGNvbnRleHQgbGluZXMuIFJldHVybnMgbWF0Y2hpbmcgbGluZXMgd2l0aCBmaWxlIHBhdGhzIGFuZCBsaW5lIG51bWJlcnMuIFVzZSB0aGlzIHRvIGZpbmQgY29kZSBwYXR0ZXJucywgZnVuY3Rpb24gZGVmaW5pdGlvbnMsIGltcG9ydHMsIGV0Yy5cIixcbiAgICAgIGlucHV0U2NoZW1hOiB6Lm9iamVjdCh7XG4gICAgICAgIHBhdHRlcm46IHpcbiAgICAgICAgICAuc3RyaW5nKClcbiAgICAgICAgICAuZGVzY3JpYmUoXCJSZWdleCBwYXR0ZXJuIHRvIHNlYXJjaCBmb3IgKHJpcGdyZXAgc3ludGF4KVwiKSxcbiAgICAgICAgcGF0aDogelxuICAgICAgICAgIC5zdHJpbmcoKVxuICAgICAgICAgIC5vcHRpb25hbCgpXG4gICAgICAgICAgLmRlc2NyaWJlKFxuICAgICAgICAgICAgXCJQYXRoIHRvIHNlYXJjaCBpbiAoZGVmYXVsdHMgdG8gd29ya3NwYWNlIHJvb3QpLiBDYW4gYmUgYSBmaWxlIG9yIGRpcmVjdG9yeS5cIlxuICAgICAgICAgICksXG4gICAgICAgIGZpbGVUeXBlOiB6XG4gICAgICAgICAgLnN0cmluZygpXG4gICAgICAgICAgLm9wdGlvbmFsKClcbiAgICAgICAgICAuZGVzY3JpYmUoXG4gICAgICAgICAgICBcIkZpbGUgdHlwZSB0byBmaWx0ZXIgYnkgKGUuZy4sICd0cycsICdqcycsICdweScsICdtZCcpLiBVc2VzIHJpcGdyZXAncyBidWlsdC1pbiB0eXBlIGZpbHRlcnMuXCJcbiAgICAgICAgICApLFxuICAgICAgICBnbG9iOiB6XG4gICAgICAgICAgLnN0cmluZygpXG4gICAgICAgICAgLm9wdGlvbmFsKClcbiAgICAgICAgICAuZGVzY3JpYmUoXG4gICAgICAgICAgICBcIkdsb2IgcGF0dGVybiB0byBmaWx0ZXIgZmlsZXMgKGUuZy4sICcqLnRzeCcsICdzcmMvKiovKi50cycpXCJcbiAgICAgICAgICApLFxuICAgICAgICBjYXNlU2Vuc2l0aXZlOiB6XG4gICAgICAgICAgLmJvb2xlYW4oKVxuICAgICAgICAgIC5vcHRpb25hbCgpXG4gICAgICAgICAgLmRlZmF1bHQodHJ1ZSlcbiAgICAgICAgICAuZGVzY3JpYmUoXCJXaGV0aGVyIHNlYXJjaCBpcyBjYXNlLXNlbnNpdGl2ZSAoZGVmYXVsdDogdHJ1ZSlcIiksXG4gICAgICAgIGNvbnRleHRMaW5lczogelxuICAgICAgICAgIC5udW1iZXIoKVxuICAgICAgICAgIC5vcHRpb25hbCgpXG4gICAgICAgICAgLmRlc2NyaWJlKFxuICAgICAgICAgICAgXCJOdW1iZXIgb2YgY29udGV4dCBsaW5lcyB0byBzaG93IGJlZm9yZSBhbmQgYWZ0ZXIgZWFjaCBtYXRjaFwiXG4gICAgICAgICAgKSxcbiAgICAgICAgbWF4Q291bnQ6IHpcbiAgICAgICAgICAubnVtYmVyKClcbiAgICAgICAgICAub3B0aW9uYWwoKVxuICAgICAgICAgIC5kZXNjcmliZShcbiAgICAgICAgICAgIFwiTWF4aW11bSBudW1iZXIgb2YgbWF0Y2hlcyBwZXIgZmlsZSAodXNlZnVsIGZvciBsaW1pdGluZyBvdXRwdXQpXCJcbiAgICAgICAgICApLFxuICAgICAgICBmaWxlc1dpdGhNYXRjaGVzOiB6XG4gICAgICAgICAgLmJvb2xlYW4oKVxuICAgICAgICAgIC5vcHRpb25hbCgpXG4gICAgICAgICAgLmRlZmF1bHQoZmFsc2UpXG4gICAgICAgICAgLmRlc2NyaWJlKFxuICAgICAgICAgICAgXCJPbmx5IHNob3cgZmlsZSBwYXRocyB0aGF0IGNvbnRhaW4gbWF0Y2hlcywgbm90IHRoZSBtYXRjaGluZyBsaW5lcyB0aGVtc2VsdmVzXCJcbiAgICAgICAgICApLFxuICAgICAgfSksXG4gICAgICBvdXRwdXRTY2hlbWE6IHoub2JqZWN0KHtcbiAgICAgICAgbWF0Y2hlczogelxuICAgICAgICAgIC5zdHJpbmcoKVxuICAgICAgICAgIC5kZXNjcmliZShcbiAgICAgICAgICAgIFwiU2VhcmNoIHJlc3VsdHMgd2l0aCBmaWxlIHBhdGhzLCBsaW5lIG51bWJlcnMsIGFuZCBtYXRjaGluZyBjb250ZW50XCJcbiAgICAgICAgICApLFxuICAgICAgICBzdW1tYXJ5OiB6Lm9iamVjdCh7XG4gICAgICAgICAgbWF0Y2hDb3VudDogei5udW1iZXIoKS5kZXNjcmliZShcIk51bWJlciBvZiBtYXRjaGVzIGZvdW5kXCIpLFxuICAgICAgICAgIGZpbGVDb3VudDogei5udW1iZXIoKS5kZXNjcmliZShcIk51bWJlciBvZiBmaWxlcyBjb250YWluaW5nIG1hdGNoZXNcIiksXG4gICAgICAgICAgc2VhcmNoUGF0aDogei5zdHJpbmcoKS5kZXNjcmliZShcIlBhdGggdGhhdCB3YXMgc2VhcmNoZWRcIiksXG4gICAgICAgICAgcGF0dGVybjogei5zdHJpbmcoKS5kZXNjcmliZShcIlBhdHRlcm4gdGhhdCB3YXMgc2VhcmNoZWQgZm9yXCIpLFxuICAgICAgICB9KSxcbiAgICAgIH0pLFxuICAgICAgZXhlY3V0ZTogYXN5bmMgKHtcbiAgICAgICAgcGF0dGVybixcbiAgICAgICAgcGF0aCxcbiAgICAgICAgZmlsZVR5cGUsXG4gICAgICAgIGdsb2IsXG4gICAgICAgIGNhc2VTZW5zaXRpdmUsXG4gICAgICAgIGNvbnRleHRMaW5lcyxcbiAgICAgICAgbWF4Q291bnQsXG4gICAgICAgIGZpbGVzV2l0aE1hdGNoZXMsXG4gICAgICB9KSA9PiB7XG4gICAgICAgIGxldCBzZWFyY2hQYXRoID0gcGF0aCA/PyBcIi5cIjtcbiAgICAgICAgaWYgKHNlYXJjaFBhdGguc3RhcnRzV2l0aChcIi9cIikpIHtcbiAgICAgICAgICBzZWFyY2hQYXRoID0gc2VhcmNoUGF0aC5zbGljZSgxKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGFyZ3M6IHN0cmluZ1tdID0gW107XG5cbiAgICAgICAgYXJncy5wdXNoKFwiLS1saW5lLW51bWJlclwiKTtcbiAgICAgICAgYXJncy5wdXNoKFwiLS1oZWFkaW5nXCIpO1xuICAgICAgICBhcmdzLnB1c2goXCItLWNvbG9yXCIsIFwibmV2ZXJcIik7XG5cbiAgICAgICAgaWYgKCFjYXNlU2Vuc2l0aXZlKSB7XG4gICAgICAgICAgYXJncy5wdXNoKFwiLWlcIik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZmlsZVR5cGUpIHtcbiAgICAgICAgICBhcmdzLnB1c2goXCItLXR5cGVcIiwgZmlsZVR5cGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGdsb2IpIHtcbiAgICAgICAgICBhcmdzLnB1c2goXCItLWdsb2JcIiwgZ2xvYik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY29udGV4dExpbmVzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBhcmdzLnB1c2goXCItQ1wiLCBTdHJpbmcoY29udGV4dExpbmVzKSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobWF4Q291bnQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIGFyZ3MucHVzaChcIi0tbWF4LWNvdW50XCIsIFN0cmluZyhtYXhDb3VudCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGZpbGVzV2l0aE1hdGNoZXMpIHtcbiAgICAgICAgICBhcmdzLnB1c2goXCItLWZpbGVzLXdpdGgtbWF0Y2hlc1wiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGFyZ3MucHVzaChcIi0tXCIsIHBhdHRlcm4sIHNlYXJjaFBhdGgpO1xuXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNvbnRleHQuc2FuZGJveC5leGVjKHsgY29tbWFuZDogXCJyZ1wiLCBhcmdzIH0pO1xuXG4gICAgICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJbR3JlcCBUb29sXVwiLCByZXN1bHQpO1xuICAgICAgICAgIHRocm93IHJlc3VsdDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHsgc3Rkb3V0LCBzdGRlcnIgfSA9IGF3YWl0IHJlc3VsdC5yZXN1bHQ7XG5cbiAgICAgICAgaWYgKHN0ZGVyciAmJiAhc3RkZXJyLnRvTG93ZXJDYXNlKCkuaW5jbHVkZXMoXCJubyBtYXRjaGVzXCIpKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihgW0dyZXAgVG9vbF0gV2FybmluZzogJHtzdGRlcnJ9YCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBUcnVuY2F0ZSBvdXRwdXQgdG8gcHJldmVudCBcImlucHV0IHRvbyBsb25nXCIgZXJyb3JzICg1MGsgY2hhcnMgXHUyMjQ4IDEyLjVrIHRva2VucylcbiAgICAgICAgY29uc3QgTUFYX0dSRVBfT1VUUFVUX0NIQVJTID0gNTBfMDAwO1xuICAgICAgICBsZXQgZmluYWxPdXRwdXQgPSBzdGRvdXQ7XG4gICAgICAgIGxldCB3YXNUcnVuY2F0ZWQgPSBmYWxzZTtcbiAgICAgICAgaWYgKGZpbmFsT3V0cHV0Lmxlbmd0aCA+IE1BWF9HUkVQX09VVFBVVF9DSEFSUykge1xuICAgICAgICAgIGZpbmFsT3V0cHV0ID1cbiAgICAgICAgICAgIGZpbmFsT3V0cHV0LnNsaWNlKDAsIE1BWF9HUkVQX09VVFBVVF9DSEFSUykgK1xuICAgICAgICAgICAgXCJcXG5cXG5bT3V0cHV0IHRydW5jYXRlZCAtIHVzZSBtb3JlIHNwZWNpZmljIHBhdHRlcm4gb3IgcGF0aF1cIjtcbiAgICAgICAgICB3YXNUcnVuY2F0ZWQgPSB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgbGluZXMgPSBmaW5hbE91dHB1dFxuICAgICAgICAgIC50cmltKClcbiAgICAgICAgICAuc3BsaXQoXCJcXG5cIilcbiAgICAgICAgICAuZmlsdGVyKChsKSA9PiBsLmxlbmd0aCA+IDApO1xuICAgICAgICBjb25zdCBmaWxlQ291bnQgPSBmaWxlc1dpdGhNYXRjaGVzXG4gICAgICAgICAgPyBsaW5lcy5sZW5ndGhcbiAgICAgICAgICA6IG5ldyBTZXQoXG4gICAgICAgICAgICAgIGxpbmVzXG4gICAgICAgICAgICAgICAgLmZpbHRlcigobCkgPT4gIWwuc3RhcnRzV2l0aChcIiBcIikgJiYgbC5pbmNsdWRlcyhcIjpcIikpXG4gICAgICAgICAgICAgICAgLm1hcCgobCkgPT4gbC5zcGxpdChcIjpcIilbMF0pXG4gICAgICAgICAgICApLnNpemU7XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBtYXRjaGVzOiBmaW5hbE91dHB1dCB8fCBcIihubyBtYXRjaGVzIGZvdW5kKVwiLFxuICAgICAgICAgIHN1bW1hcnk6IHtcbiAgICAgICAgICAgIG1hdGNoQ291bnQ6IGZpbGVzV2l0aE1hdGNoZXNcbiAgICAgICAgICAgICAgPyAwXG4gICAgICAgICAgICAgIDogbGluZXMuZmlsdGVyKChsKSA9PiBsLmluY2x1ZGVzKFwiOlwiKSkubGVuZ3RoLFxuICAgICAgICAgICAgZmlsZUNvdW50LFxuICAgICAgICAgICAgc2VhcmNoUGF0aCxcbiAgICAgICAgICAgIHBhdHRlcm4sXG4gICAgICAgICAgICB3YXNUcnVuY2F0ZWQsXG4gICAgICAgICAgfSxcbiAgICAgICAgfTtcbiAgICAgIH0sXG4gICAgfSksXG4gICAgTGlzdDogdG9vbCh7XG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgXCJSZWN1cnNpdmVseSBsaXN0IGRpcmVjdG9yeSBjb250ZW50cy4gVXNlIHRoaXMgdG8gdW5kZXJzdGFuZCB0aGUgY29kZWJhc2Ugc3RydWN0dXJlLCBmaW5kIGZpbGVzLCBvciBleHBsb3JlIGRpcmVjdG9yaWVzLiBDb250cm9sIGRlcHRoIHRvIGJhbGFuY2UgZGV0YWlsIHZzLiBvdmVydmlldy4gRGVwdGggMSBzaG93cyBpbW1lZGlhdGUgY2hpbGRyZW4sIGRlcHRoIDIgaW5jbHVkZXMgc3ViZGlyZWN0b3JpZXMsIGV0Yy5cIixcbiAgICAgIGlucHV0U2NoZW1hOiB6Lm9iamVjdCh7XG4gICAgICAgIHBhdGg6IHpcbiAgICAgICAgICAuc3RyaW5nKClcbiAgICAgICAgICAub3B0aW9uYWwoKVxuICAgICAgICAgIC5kZXNjcmliZShcIlBhdGggdG8gbGlzdCAoZGVmYXVsdHMgdG8gd29ya3NwYWNlIHJvb3QpXCIpLFxuICAgICAgICBkZXB0aDogelxuICAgICAgICAgIC5udW1iZXIoKVxuICAgICAgICAgIC5vcHRpb25hbCgpXG4gICAgICAgICAgLmRlc2NyaWJlKFxuICAgICAgICAgICAgXCJNYXhpbXVtIGRlcHRoIHRvIHRyYXZlcnNlLiBDaG9vc2UgYmFzZWQgb24gY29udGV4dDogMS0yIGZvciBxdWljayBvdmVydmlldywgMy00IGZvciBkZXRhaWxlZCBleHBsb3JhdGlvbiwgNSsgZm9yIGNvbXByZWhlbnNpdmUgbWFwcGluZ1wiXG4gICAgICAgICAgKSxcbiAgICAgICAgaW5jbHVkZUhpZGRlbjogelxuICAgICAgICAgIC5ib29sZWFuKClcbiAgICAgICAgICAub3B0aW9uYWwoKVxuICAgICAgICAgIC5kZWZhdWx0KGZhbHNlKVxuICAgICAgICAgIC5kZXNjcmliZShcbiAgICAgICAgICAgIFwiSW5jbHVkZSBoaWRkZW4gZmlsZXMgYW5kIGRpcmVjdG9yaWVzICh0aG9zZSBzdGFydGluZyB3aXRoICcuJylcIlxuICAgICAgICAgICksXG4gICAgICAgIGZpbGVzT25seTogelxuICAgICAgICAgIC5ib29sZWFuKClcbiAgICAgICAgICAub3B0aW9uYWwoKVxuICAgICAgICAgIC5kZWZhdWx0KGZhbHNlKVxuICAgICAgICAgIC5kZXNjcmliZShcIk9ubHkgc2hvdyBmaWxlcywgbm90IGRpcmVjdG9yaWVzXCIpLFxuICAgICAgICBwYXR0ZXJuOiB6XG4gICAgICAgICAgLnN0cmluZygpXG4gICAgICAgICAgLm9wdGlvbmFsKClcbiAgICAgICAgICAuZGVzY3JpYmUoXCJHbG9iIHBhdHRlcm4gdG8gZmlsdGVyIHJlc3VsdHMgKGUuZy4sICcqLnRzJywgJyp0ZXN0KicpXCIpLFxuICAgICAgfSksXG4gICAgICBvdXRwdXRTY2hlbWE6IHoub2JqZWN0KHtcbiAgICAgICAgbGlzdGluZzogelxuICAgICAgICAgIC5zdHJpbmcoKVxuICAgICAgICAgIC5kZXNjcmliZShcbiAgICAgICAgICAgIFwiRGlyZWN0b3J5IHRyZWUgbGlzdGluZyBzaG93aW5nIHBhdGhzIHJlbGF0aXZlIHRvIHNlYXJjaCByb290XCJcbiAgICAgICAgICApLFxuICAgICAgICBzdW1tYXJ5OiB6Lm9iamVjdCh7XG4gICAgICAgICAgdG90YWxJdGVtczogei5udW1iZXIoKS5kZXNjcmliZShcIlRvdGFsIG51bWJlciBvZiBpdGVtcyBmb3VuZFwiKSxcbiAgICAgICAgICB0b3RhbEZpbGVzOiB6Lm51bWJlcigpLmRlc2NyaWJlKFwiVG90YWwgbnVtYmVyIG9mIGZpbGVzIGZvdW5kXCIpLFxuICAgICAgICAgIHRvdGFsRGlyczogei5udW1iZXIoKS5kZXNjcmliZShcIlRvdGFsIG51bWJlciBvZiBkaXJlY3RvcmllcyBmb3VuZFwiKSxcbiAgICAgICAgICBzZWFyY2hQYXRoOiB6LnN0cmluZygpLmRlc2NyaWJlKFwiUGF0aCB0aGF0IHdhcyBsaXN0ZWRcIiksXG4gICAgICAgICAgZGVwdGg6IHpcbiAgICAgICAgICAgIC5udW1iZXIoKVxuICAgICAgICAgICAgLm9wdGlvbmFsKClcbiAgICAgICAgICAgIC5kZXNjcmliZShcIk1heGltdW0gZGVwdGggdXNlZCAoaWYgc3BlY2lmaWVkKVwiKSxcbiAgICAgICAgfSksXG4gICAgICB9KSxcbiAgICAgIGV4ZWN1dGU6IGFzeW5jICh7IHBhdGgsIGRlcHRoLCBpbmNsdWRlSGlkZGVuLCBmaWxlc09ubHksIHBhdHRlcm4gfSkgPT4ge1xuICAgICAgICBjb25zdCBzZWFyY2hQYXRoID0gcGF0aCA/PyBcIi5cIjtcblxuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBjb250ZXh0LnNhbmRib3guZXhlYyh7XG4gICAgICAgICAgY29tbWFuZDogXCJiYXNoXCIsXG4gICAgICAgICAgYXJnczogW1xuICAgICAgICAgICAgXCItY1wiLFxuICAgICAgICAgICAgYFxuICAgICAgICAgICAgc2V0IC1lXG4gICAgICAgICAgICBTRUFSQ0hfUEFUSD1cIiQxXCJcbiAgICAgICAgICAgIERFUFRIPVwiJDJcIlxuICAgICAgICAgICAgSU5DTFVERV9ISURERU49XCIkM1wiXG4gICAgICAgICAgICBGSUxFU19PTkxZPVwiJDRcIlxuICAgICAgICAgICAgUEFUVEVSTj1cIiQ1XCJcblxuICAgICAgICAgICAgIyBCdWlsZCBmaW5kIGNvbW1hbmQgYXJndW1lbnRzXG4gICAgICAgICAgICBGSU5EX0FSR1M9XCJcIlxuICAgICAgICAgICAgWyAtbiBcIiRERVBUSFwiIF0gJiYgRklORF9BUkdTPVwiJEZJTkRfQVJHUyAtbWF4ZGVwdGggJERFUFRIXCJcbiAgICAgICAgICAgIFsgXCIkSU5DTFVERV9ISURERU5cIiAhPSBcInRydWVcIiBdICYmIEZJTkRfQVJHUz1cIiRGSU5EX0FSR1MgISAtcGF0aCAnKi8uKidcIlxuICAgICAgICAgICAgWyBcIiRGSUxFU19PTkxZXCIgPSBcInRydWVcIiBdICYmIEZJTkRfQVJHUz1cIiRGSU5EX0FSR1MgLXR5cGUgZlwiXG4gICAgICAgICAgICBbIC1uIFwiJFBBVFRFUk5cIiBdICYmIEZJTkRfQVJHUz1cIiRGSU5EX0FSR1MgLW5hbWUgJyRQQVRURVJOJ1wiXG5cbiAgICAgICAgICAgICMgR2V0IGxpc3RpbmdcbiAgICAgICAgICAgIExJU1RJTkc9JChldmFsIFwiZmluZCAnJFNFQVJDSF9QQVRIJyAkRklORF9BUkdTXCIgMj4vZGV2L251bGwgfCBzb3J0KVxuXG4gICAgICAgICAgICAjIEdldCBjb3VudHNcbiAgICAgICAgICAgIENPVU5UX0FSR1M9XCJcIlxuICAgICAgICAgICAgWyAtbiBcIiRERVBUSFwiIF0gJiYgQ09VTlRfQVJHUz1cIiRDT1VOVF9BUkdTIC1tYXhkZXB0aCAkREVQVEhcIlxuICAgICAgICAgICAgWyBcIiRJTkNMVURFX0hJRERFTlwiICE9IFwidHJ1ZVwiIF0gJiYgQ09VTlRfQVJHUz1cIiRDT1VOVF9BUkdTICEgLXBhdGggJyovLionXCJcblxuICAgICAgICAgICAgRklMRV9DT1VOVD0kKGV2YWwgXCJmaW5kICckU0VBUkNIX1BBVEgnICRDT1VOVF9BUkdTIC10eXBlIGZcIiAyPi9kZXYvbnVsbCB8IHdjIC1sKVxuICAgICAgICAgICAgRElSX0NPVU5UPSQoZXZhbCBcImZpbmQgJyRTRUFSQ0hfUEFUSCcgJENPVU5UX0FSR1MgLXR5cGUgZFwiIDI+L2Rldi9udWxsIHwgd2MgLWwpXG5cbiAgICAgICAgICAgICMgT3V0cHV0OiBjb3VudHMgZmlyc3QsIHRoZW4gbGlzdGluZ1xuICAgICAgICAgICAgZWNobyBcIiRGSUxFX0NPVU5UfCRESVJfQ09VTlRcIlxuICAgICAgICAgICAgZWNobyBcInx8fExJU1RJTkd8fHxcIlxuICAgICAgICAgICAgZWNobyBcIiRMSVNUSU5HXCIgfCBzZWQgXCJzfF4kU0VBUkNIX1BBVEh8LnxcIlxuICAgICAgICAgIGAsXG4gICAgICAgICAgICBcIi0tXCIsXG4gICAgICAgICAgICBzZWFyY2hQYXRoLFxuICAgICAgICAgICAgZGVwdGg/LnRvU3RyaW5nKCkgfHwgXCJcIixcbiAgICAgICAgICAgIGluY2x1ZGVIaWRkZW4gPyBcInRydWVcIiA6IFwiZmFsc2VcIixcbiAgICAgICAgICAgIGZpbGVzT25seSA/IFwidHJ1ZVwiIDogXCJmYWxzZVwiLFxuICAgICAgICAgICAgcGF0dGVybiB8fCBcIlwiLFxuICAgICAgICAgIF0sXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJbTGlzdCBUb29sXVwiLCByZXN1bHQpO1xuICAgICAgICAgIHRocm93IHJlc3VsdDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHsgc3Rkb3V0LCBzdGRlcnIgfSA9IGF3YWl0IHJlc3VsdC5yZXN1bHQ7XG5cbiAgICAgICAgaWYgKHN0ZGVycikge1xuICAgICAgICAgIGNvbnNvbGUud2FybihgW0xpc3QgVG9vbF0gc3RkZXJyOiAke3N0ZGVycn1gKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IFtjb3VudHNMaW5lLCAuLi5yZXN0XSA9IHN0ZG91dC5zcGxpdChcInx8fExJU1RJTkd8fHxcIik7XG4gICAgICAgIGNvbnN0IGxpc3RpbmcgPSByZXN0LmpvaW4oXCJ8fHxMSVNUSU5HfHx8XCIpLnRyaW0oKTtcbiAgICAgICAgY29uc3QgW2ZpbGVDb3VudFN0ciwgZGlyQ291bnRTdHJdID0gY291bnRzTGluZS50cmltKCkuc3BsaXQoXCJ8XCIpO1xuXG4gICAgICAgIGNvbnN0IHRvdGFsRmlsZXMgPSBOdW1iZXIucGFyc2VJbnQoZmlsZUNvdW50U3RyLCAxMCkgfHwgMDtcbiAgICAgICAgY29uc3QgdG90YWxEaXJzID0gTnVtYmVyLnBhcnNlSW50KGRpckNvdW50U3RyLCAxMCkgfHwgMDtcbiAgICAgICAgY29uc3QgbGluZXMgPSBsaXN0aW5nLnNwbGl0KFwiXFxuXCIpLmZpbHRlcigobCkgPT4gbC5sZW5ndGggPiAwKTtcblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGxpc3RpbmcsXG4gICAgICAgICAgc3VtbWFyeToge1xuICAgICAgICAgICAgdG90YWxJdGVtczogbGluZXMubGVuZ3RoLFxuICAgICAgICAgICAgdG90YWxGaWxlcyxcbiAgICAgICAgICAgIHRvdGFsRGlycyxcbiAgICAgICAgICAgIHNlYXJjaFBhdGgsXG4gICAgICAgICAgICBkZXB0aCxcbiAgICAgICAgICB9LFxuICAgICAgICB9O1xuICAgICAgfSxcbiAgICB9KSxcbiAgICBCYXNoOiB0b29sKHtcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICBcIkV4ZWN1dGVzIGEgYmFzaCBjb21tYW5kIGluc2lkZSB0aGUgd29ya3NwYWNlLiBDV0QgcGVyc2lzdHMgYmV0d2VlbiBjb21tYW5kcyB3aXRoaW4gYSBzZXNzaW9uLiBVc2Ugd2FpdFVudGlsOjAgZm9yIGJhY2tncm91bmQgcHJvY2Vzc2VzIChkZXYgc2VydmVycykuXCIsXG4gICAgICBpbnB1dFNjaGVtYTogei5vYmplY3Qoe1xuICAgICAgICBjb21tYW5kOiB6LnN0cmluZygpLmRlc2NyaWJlKFwiVGhlIHNoZWxsIGNvbW1hbmQgdG8gZXhlY3V0ZVwiKSxcbiAgICAgICAgd2FpdFVudGlsOiB6XG4gICAgICAgICAgLm51bWJlcigpXG4gICAgICAgICAgLm9wdGlvbmFsKClcbiAgICAgICAgICAuZGVzY3JpYmUoXG4gICAgICAgICAgICBcIk1heCBtcyB0byB3YWl0IGZvciBjb21wbGV0aW9uIChkZWZhdWx0OiAzMDAwMCkuIFVzZSAwIHRvIHJ1biBpbiBiYWNrZ3JvdW5kIGFuZCByZXR1cm4gaW1tZWRpYXRlbHkuXCJcbiAgICAgICAgICApLFxuICAgICAgfSksXG4gICAgICBvdXRwdXRTY2hlbWE6IHoub2JqZWN0KHtcbiAgICAgICAgcGlkOiB6XG4gICAgICAgICAgLm51bWJlcigpXG4gICAgICAgICAgLmRlc2NyaWJlKFxuICAgICAgICAgICAgXCJTeXN0ZW0gUElEICgwIGZvciBmb3JlZ3JvdW5kLCA+MCBmb3IgYmFja2dyb3VuZCAtIHVzZSB0byBraWxsKVwiXG4gICAgICAgICAgKSxcbiAgICAgICAgb3V0cHV0OiB6XG4gICAgICAgICAgLnN0cmluZygpXG4gICAgICAgICAgLmRlc2NyaWJlKFwiQ29tbWFuZCBzdGRvdXQrc3RkZXJyIGNvbWJpbmVkIChlbXB0eSBmb3IgYmFja2dyb3VuZClcIiksXG4gICAgICAgIGV4aXRDb2RlOiB6Lm51bWJlcigpLmRlc2NyaWJlKFwiRXhpdCBjb2RlICgtMSBmb3IgYmFja2dyb3VuZC9ydW5uaW5nKVwiKSxcbiAgICAgICAgc3RhdHVzOiB6XG4gICAgICAgICAgLmVudW0oW1wicnVubmluZ1wiLCBcImNvbXBsZXRlZFwiLCBcImZhaWxlZFwiXSlcbiAgICAgICAgICAuZGVzY3JpYmUoXCJQcm9jZXNzIHN0YXR1c1wiKSxcbiAgICAgICAgY3dkOiB6LnN0cmluZygpLmRlc2NyaWJlKFwiQ3VycmVudCB3b3JraW5nIGRpcmVjdG9yeSBhZnRlciBjb21tYW5kXCIpLFxuICAgICAgICBvdXRwdXRGaWxlOiB6XG4gICAgICAgICAgLnN0cmluZygpXG4gICAgICAgICAgLmRlc2NyaWJlKFwiUGF0aCB0byBvdXRwdXQgbG9nIChmb3IgYmFja2dyb3VuZCBwcm9jZXNzZXMpXCIpLFxuICAgICAgfSksXG4gICAgICBleGVjdXRlOiBhc3luYyAoeyBjb21tYW5kLCB3YWl0VW50aWwgfSkgPT4ge1xuICAgICAgICBjb25zdCB7IGNyZWF0ZVByb2Nlc3NNYW5hZ2VyIH0gPSBhd2FpdCBpbXBvcnQoXG4gICAgICAgICAgXCIuLi9zYW5kYm94L3Byb2Nlc3MtbWFuYWdlclwiXG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3QgcHJvY2Vzc01hbmFnZXIgPSBjcmVhdGVQcm9jZXNzTWFuYWdlcih7XG4gICAgICAgICAgc2FuZGJveDogY29udGV4dC5zYW5kYm94LFxuICAgICAgICAgIHNlc3Npb25JZDogY29udGV4dC5pbnB1dC5zZXNzaW9uSWQsXG4gICAgICAgICAgZ2VuZXJhdGVJZDogKCkgPT4gY3J5cHRvLnJhbmRvbVVVSUQoKSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgYXdhaXQgcHJvY2Vzc01hbmFnZXIuaW5pdCgpO1xuICAgICAgICByZXR1cm4gcHJvY2Vzc01hbmFnZXIucnVuKHsgY29tbWFuZCwgd2FpdFVudGlsIH0pO1xuICAgICAgfSxcbiAgICB9KSxcbiAgICBFeGVjdXRlTUNQVG9vbDogdG9vbCh7XG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgXCJFeGVjdXRlIGEgdG9vbCBmcm9tIGFuIE1DUCBzZXJ2ZXIuIFVzZSB0aGlzIHRvIGNhbGwgY3VzdG9tIHRvb2xzIHByb3ZpZGVkIGJ5IHRoZSBhcHBsaWNhdGlvbi5cIixcbiAgICAgIGlucHV0U2NoZW1hOiB6Lm9iamVjdCh7XG4gICAgICAgIHNlcnZlcjogei5zdHJpbmcoKS5kZXNjcmliZShcIk1DUCBzZXJ2ZXIgbmFtZVwiKSxcbiAgICAgICAgdG9vbDogei5zdHJpbmcoKS5kZXNjcmliZShcIlRvb2wgbmFtZSB0byBleGVjdXRlXCIpLFxuICAgICAgICBpbnB1dDogei51bmtub3duKCkuZGVzY3JpYmUoXCJUb29sIGlucHV0IG1hdGNoaW5nIHRoZSB0b29sJ3Mgc2NoZW1hXCIpLFxuICAgICAgfSksXG4gICAgICBvdXRwdXRTY2hlbWE6IHoub2JqZWN0KHtcbiAgICAgICAgcmVzdWx0OiB6LnVua25vd24oKS5kZXNjcmliZShcIlRvb2wgZXhlY3V0aW9uIHJlc3VsdFwiKSxcbiAgICAgICAgdHJ1bmNhdGVkOiB6XG4gICAgICAgICAgLmJvb2xlYW4oKVxuICAgICAgICAgIC5vcHRpb25hbCgpXG4gICAgICAgICAgLmRlc2NyaWJlKFwiV2hldGhlciB0aGUgcmVzdWx0IHdhcyB0cnVuY2F0ZWQgZHVlIHRvIHNpemVcIiksXG4gICAgICAgIHRvdGFsQ2hhcnM6IHpcbiAgICAgICAgICAubnVtYmVyKClcbiAgICAgICAgICAub3B0aW9uYWwoKVxuICAgICAgICAgIC5kZXNjcmliZShcIlRvdGFsIGNoYXJhY3RlcnMgaW4gZnVsbCBvdXRwdXQgKG9ubHkgaWYgdHJ1bmNhdGVkKVwiKSxcbiAgICAgICAgcmV0dXJuZWRDaGFyczogelxuICAgICAgICAgIC5udW1iZXIoKVxuICAgICAgICAgIC5vcHRpb25hbCgpXG4gICAgICAgICAgLmRlc2NyaWJlKFwiQ2hhcmFjdGVycyByZXR1cm5lZCBpbiB0aGlzIHJlc3BvbnNlIChvbmx5IGlmIHRydW5jYXRlZClcIiksXG4gICAgICAgIGZ1bGxPdXRwdXRQYXRoOiB6XG4gICAgICAgICAgLnN0cmluZygpXG4gICAgICAgICAgLm9wdGlvbmFsKClcbiAgICAgICAgICAuZGVzY3JpYmUoXCJQYXRoIHRvIGZ1bGwgb3V0cHV0IGZpbGUgaWYgdHJ1bmNhdGVkXCIpLFxuICAgICAgfSksXG4gICAgICBleGVjdXRlOiBhc3luYyAoeyBzZXJ2ZXIsIHRvb2w6IHRvb2xOYW1lLCBpbnB1dCB9KSA9PiB7XG4gICAgICAgIGNvbnN0IHNlcnZlckNvbmZpZyA9IGNvbnRleHQubWNwPy5maW5kKChzKSA9PiBzLm5hbWUgPT09IHNlcnZlcik7XG4gICAgICAgIGlmICghc2VydmVyQ29uZmlnKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIE1DUCBzZXJ2ZXI6ICR7c2VydmVyfWApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcGFyc2VkSW5wdXQgPVxuICAgICAgICAgIHR5cGVvZiBpbnB1dCA9PT0gXCJzdHJpbmdcIiA/IEpTT04ucGFyc2UoaW5wdXQpIDogaW5wdXQ7XG5cbiAgICAgICAgY29uc3QgdGltZXN0YW1wID0gRGF0ZS5ub3coKTtcbiAgICAgICAgY29uc3Qgb3V0cHV0RGlyID0gYC5hZ2VudC9tY3AvJHtzZXJ2ZXJ9Ly5vdXRwdXRzYDtcbiAgICAgICAgY29uc3Qgb3V0cHV0RmlsZSA9IGAke291dHB1dERpcn0vJHt0aW1lc3RhbXB9LSR7dG9vbE5hbWV9LnR4dGA7XG5cbiAgICAgICAgY29uc3QgW3Jlc10gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICAgICAgZmV0Y2goc2VydmVyQ29uZmlnLnVybCwge1xuICAgICAgICAgICAgbWV0aG9kOiBcIlBPU1RcIixcbiAgICAgICAgICAgIGhlYWRlcnM6IHsgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIgfSxcbiAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgc2VydmVyLFxuICAgICAgICAgICAgICB0b29sOiB0b29sTmFtZSxcbiAgICAgICAgICAgICAgaW5wdXQ6IHBhcnNlZElucHV0LFxuICAgICAgICAgICAgICBzZXNzaW9uSWQ6IGNvbnRleHQuaW5wdXQuc2Vzc2lvbklkLFxuICAgICAgICAgICAgICBtZXNzYWdlSWQ6IGNvbnRleHQuZXZlbnQuYXNzaXN0YW50TWVzc2FnZUlkLFxuICAgICAgICAgICAgICBob29rVG9rZW46IGNvbnRleHQuZXZlbnQuaG9va1Rva2VuLFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgfSksXG4gICAgICAgICAgY29udGV4dC5zYW5kYm94LmV4ZWMoeyBjb21tYW5kOiBcIm1rZGlyXCIsIGFyZ3M6IFtcIi1wXCIsIG91dHB1dERpcl0gfSksXG4gICAgICAgIF0pO1xuXG4gICAgICAgIGlmICghcmVzLm9rKSB7XG4gICAgICAgICAgY29uc3QgZXJyb3IgPSBhd2FpdCByZXMudGV4dCgpO1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgTUNQIHRvb2wgY2FsbCBmYWlsZWQ6ICR7ZXJyb3J9YCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBqc29uID0gKGF3YWl0IHJlcy5qc29uKCkpIGFzIHtcbiAgICAgICAgICByZXN1bHQ/OiB1bmtub3duO1xuICAgICAgICAgIGVycm9yPzogeyBjb2RlOiBzdHJpbmc7IG1lc3NhZ2U6IHN0cmluZyB9O1xuICAgICAgICB9O1xuXG4gICAgICAgIGlmIChqc29uLmVycm9yKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBNQ1AgdG9vbCBjYWxsIGZhaWxlZDogJHtqc29uLmVycm9yLm1lc3NhZ2V9YCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoanNvbi5yZXN1bHQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk1DUCB0b29sIGNhbGwgZmFpbGVkOiBObyByZXN1bHQgaW4gcmVzcG9uc2VcIik7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZXN1bHQgPSBqc29uLnJlc3VsdDtcbiAgICAgICAgY29uc3QgTUFYX09VVFBVVF9DSEFSUyA9IDI0XzAwMDtcbiAgICAgICAgY29uc3QgcmVzdWx0U3RyID0gSlNPTi5zdHJpbmdpZnkocmVzdWx0LCBudWxsLCAyKTtcblxuICAgICAgICBpZiAocmVzdWx0U3RyLmxlbmd0aCA8PSBNQVhfT1VUUFVUX0NIQVJTKSB7XG4gICAgICAgICAgcmV0dXJuIHsgcmVzdWx0IH07XG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCBjb250ZXh0LnNhbmRib3gud3JpdGVGaWxlcyh7XG4gICAgICAgICAgZmlsZXM6IFt7IHBhdGg6IGAke3RpbWVzdGFtcH0tJHt0b29sTmFtZX0udHh0YCwgY29udGVudDogcmVzdWx0U3RyIH1dLFxuICAgICAgICAgIGRlc3RQYXRoOiBvdXRwdXREaXIsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbnN0IHRydW5jYXRlZFJlc3VsdCA9XG4gICAgICAgICAgcmVzdWx0U3RyLnNsaWNlKDAsIE1BWF9PVVRQVVRfQ0hBUlMpICtcbiAgICAgICAgICBgXFxuXFxuW091dHB1dCB0cnVuY2F0ZWQgYXQgfjZrIHRva2Vucy4gRnVsbCBvdXRwdXQgc2F2ZWQgdG86ICR7b3V0cHV0RmlsZX1dYDtcblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHJlc3VsdDogdHJ1bmNhdGVkUmVzdWx0LFxuICAgICAgICAgIHRydW5jYXRlZDogdHJ1ZSxcbiAgICAgICAgICB0b3RhbENoYXJzOiByZXN1bHRTdHIubGVuZ3RoLFxuICAgICAgICAgIHJldHVybmVkQ2hhcnM6IE1BWF9PVVRQVVRfQ0hBUlMsXG4gICAgICAgICAgZnVsbE91dHB1dFBhdGg6IG91dHB1dEZpbGUsXG4gICAgICAgIH07XG4gICAgICB9LFxuICAgIH0pLFxuICB9IHNhdGlzZmllcyBUb29sU2V0O1xufVxuXG5leHBvcnQgdHlwZSBBZ2VudFRvb2xzID0gUmV0dXJuVHlwZTx0eXBlb2YgZ2V0VG9vbHM+O1xuZXhwb3J0IHR5cGUgQWdlbnRUb29sTmFtZSA9IGtleW9mIEFnZW50VG9vbHM7XG4iLCAiaW1wb3J0IHR5cGUgeyBVSU1lc3NhZ2UgfSBmcm9tIFwiYWlcIjtcbmltcG9ydCB0eXBlIHsgTWVzc2FnZSwgUGFydCB9IGZyb20gXCIuLi9zdG9yYWdlXCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBhc3NlbWJsZVVJTWVzc2FnZXMob3B0czoge1xuICBtZXNzYWdlczogTWVzc2FnZVtdO1xuICBwYXJ0czogUGFydFtdO1xufSk6IFVJTWVzc2FnZVtdIHtcbiAgY29uc3QgcGFydHNCeU1lc3NhZ2UgPSBuZXcgTWFwPHN0cmluZywgUGFydFtdPigpO1xuICBmb3IgKGNvbnN0IHBhcnQgb2Ygb3B0cy5wYXJ0cykge1xuICAgIGNvbnN0IGV4aXN0aW5nID0gcGFydHNCeU1lc3NhZ2UuZ2V0KHBhcnQubWVzc2FnZUlkKSA/PyBbXTtcbiAgICBleGlzdGluZy5wdXNoKHBhcnQpO1xuICAgIHBhcnRzQnlNZXNzYWdlLnNldChwYXJ0Lm1lc3NhZ2VJZCwgZXhpc3RpbmcpO1xuICB9XG5cbiAgcmV0dXJuIG9wdHMubWVzc2FnZXMubWFwKChtKSA9PiB7XG4gICAgY29uc3QgbWVzc2FnZVBhcnRzID0gcGFydHNCeU1lc3NhZ2UuZ2V0KG0uaWQpID8/IFtdO1xuICAgIG1lc3NhZ2VQYXJ0cy5zb3J0KChhLCBiKSA9PiBhLmluZGV4IC0gYi5pbmRleCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGlkOiBtLmlkLFxuICAgICAgcm9sZTogbS5yb2xlLFxuICAgICAgcGFydHM6IG1lc3NhZ2VQYXJ0cy5tYXAoKHApID0+IHAucGFydCksXG4gICAgfSBzYXRpc2ZpZXMgVUlNZXNzYWdlO1xuICB9KTtcbn1cbiJdLAogICJtYXBwaW5ncyI6ICI7QUFDQSxTQUFTLFlBQVksY0FBQUEsYUFBWSxtQkFBbUI7OztBQ0RwRDtBQUFBLEVBQ0U7QUFBQSxFQUVBO0FBQUEsT0FFSztBQUNQLFNBQVMsWUFBWTtBQUNyQixTQUFTLGtCQUFrQjs7O0FDbUJwQixTQUFTLHNCQUNkLFNBQ3lCO0FBQ3pCLFFBQU0sVUFBVSxRQUFRLEtBQUs7QUFFN0IsTUFBSSxDQUFDLFFBQVEsV0FBVyxLQUFLLEdBQUc7QUFDOUIsV0FBTztBQUFBLEVBQ1Q7QUFFQSxRQUFNLGlCQUFpQixRQUFRLFFBQVEsT0FBTyxDQUFDO0FBQy9DLE1BQUksbUJBQW1CLElBQUk7QUFDekIsV0FBTztBQUFBLEVBQ1Q7QUFFQSxRQUFNLG1CQUFtQixRQUFRLE1BQU0sR0FBRyxjQUFjLEVBQUUsS0FBSztBQUMvRCxRQUFNLFNBQVMsZ0JBQWdCLGdCQUFnQjtBQUUvQyxNQUFJLEVBQUUsT0FBTyxRQUFRLE9BQU8sY0FBYztBQUN4QyxXQUFPO0FBQUEsRUFDVDtBQUVBLFNBQU87QUFBQSxJQUNMLE1BQU0sT0FBTyxPQUFPLElBQUk7QUFBQSxJQUN4QixhQUFhLE9BQU8sT0FBTyxXQUFXO0FBQUEsRUFDeEM7QUFDRjtBQU1BLFNBQVMsZ0JBQWdCLE1BQXNDO0FBQzdELFFBQU0sU0FBaUMsQ0FBQztBQUV4QyxhQUFXLFFBQVEsS0FBSyxNQUFNLElBQUksR0FBRztBQUNuQyxVQUFNLGNBQWMsS0FBSyxLQUFLO0FB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