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.
- package/README.md +118 -55
- package/dist/agent-workflow.d.mts +1 -1
- package/dist/agent-workflow.d.ts +1 -1
- package/dist/agent-workflow.js +474 -66
- package/dist/agent-workflow.mjs +1 -1
- package/dist/{chunk-DPPQO7DA.mjs → chunk-24DJSI7C.mjs} +34 -3
- package/dist/chunk-4RGMKC2M.mjs +755 -0
- package/dist/{chunk-2YI7MQGZ.mjs → chunk-6ICYKNCC.mjs} +24 -1
- package/dist/chunk-PGYYQ3WZ.mjs +1088 -0
- package/dist/{client-FCFZYOOB.mjs → client-4Y3UPWFR.mjs} +3 -3
- package/dist/client-BBpD9kKL.d.ts +193 -0
- package/dist/client-BGJViybU.d.mts +193 -0
- package/dist/{client-RRX3GDQD.mjs → client-HUG4HT5L.mjs} +1 -1
- package/dist/index.d.mts +5 -106
- package/dist/index.d.ts +5 -106
- package/dist/index.js +526 -77
- package/dist/index.mjs +57 -16
- package/dist/{lifecycle-workflow-steps-6BLGTYVB.mjs → lifecycle-workflow-steps-HHN46ZAD.mjs} +2 -2
- package/dist/lifecycle-workflow.d.mts +2 -2
- package/dist/lifecycle-workflow.d.ts +2 -2
- package/dist/lifecycle-workflow.js +217 -19
- package/dist/lifecycle-workflow.mjs +1 -1
- package/dist/{local-J6QFWSWB.mjs → local-BYPFRMLZ.mjs} +42 -4
- package/dist/{sandbox-Y3ENCNUA.mjs → sandbox-BFA4ECEQ.mjs} +3 -3
- package/dist/{storage-QSTSE2ZB.mjs → storage-2U2QFNWI.mjs} +2 -2
- package/dist/{types-vRxN1Qz1.d.mts → types-DPXFq_r6.d.mts} +110 -1
- package/dist/{types-vRxN1Qz1.d.ts → types-DPXFq_r6.d.ts} +110 -1
- package/package.json +13 -12
- package/dist/chunk-JQPR6M7D.mjs +0 -649
- package/dist/chunk-MR4UWCJT.mjs +0 -878
- package/dist/types-Lwut_0_u.d.mts +0 -80
- package/dist/types-ctZeJ3iQ.d.ts +0 -80
package/dist/chunk-MR4UWCJT.mjs
DELETED
|
@@ -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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
|