opencode-speaker 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +281 -0
- package/dist/api.d.ts +14 -0
- package/dist/api.js +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +1326 -0
- package/package.json +91 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1326 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import "source-map-support/register.js";
|
|
3
|
+
|
|
4
|
+
// src/config.ts
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
// src/ai-sdk/models.ts
|
|
8
|
+
import { openai } from "@ai-sdk/openai";
|
|
9
|
+
import { anthropic } from "@ai-sdk/anthropic";
|
|
10
|
+
import { elevenlabs } from "@ai-sdk/elevenlabs";
|
|
11
|
+
var ConfigError = class extends Error {
|
|
12
|
+
constructor(message) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = "ConfigError";
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var SLUG_RE = /^[a-z][a-z0-9-]*\/[A-Za-z0-9._-]+$/;
|
|
18
|
+
function parseSlug(slug, field) {
|
|
19
|
+
if (!SLUG_RE.test(slug)) {
|
|
20
|
+
throw new ConfigError(
|
|
21
|
+
`${field} must be 'provider/model' (e.g. 'openai/gpt-5'), got '${slug}'`
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
const idx = slug.indexOf("/");
|
|
25
|
+
return [slug.slice(0, idx), slug.slice(idx + 1)];
|
|
26
|
+
}
|
|
27
|
+
function resolveLanguageModel(slug) {
|
|
28
|
+
const [provider, modelId] = parseSlug(slug, "narrator.model");
|
|
29
|
+
switch (provider) {
|
|
30
|
+
case "openai":
|
|
31
|
+
return openai(modelId);
|
|
32
|
+
case "anthropic":
|
|
33
|
+
return anthropic(modelId);
|
|
34
|
+
default:
|
|
35
|
+
throw new ConfigError(
|
|
36
|
+
`Unknown narrator provider '${provider}' in '${slug}'. Supported: openai, anthropic`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function resolveSpeechModel(slug) {
|
|
41
|
+
const [provider, modelId] = parseSlug(slug, "tts.model");
|
|
42
|
+
switch (provider) {
|
|
43
|
+
case "openai":
|
|
44
|
+
return { provider: "openai", model: openai.speech(modelId) };
|
|
45
|
+
case "elevenlabs":
|
|
46
|
+
return { provider: "elevenlabs", model: elevenlabs.speech(modelId) };
|
|
47
|
+
default:
|
|
48
|
+
throw new ConfigError(
|
|
49
|
+
`Unknown TTS provider '${provider}' in '${slug}'. Supported: openai, elevenlabs`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/events/catalog.ts
|
|
55
|
+
var enabled = (normal, minimal = normal) => ({
|
|
56
|
+
minimal,
|
|
57
|
+
normal,
|
|
58
|
+
verbose: normal
|
|
59
|
+
});
|
|
60
|
+
var EVENT_SPECS = {
|
|
61
|
+
"session.idle": { mode: "narrate", queuePriority: 2 /* NORMAL */, defaultEnabled: enabled(true, true) },
|
|
62
|
+
"session.error": { mode: "template", priority: "urgent", queuePriority: 3 /* URGENT */, defaultEnabled: enabled(true, true) },
|
|
63
|
+
"session.compacted": { mode: "template", queuePriority: 2 /* NORMAL */, defaultEnabled: enabled(true, false) },
|
|
64
|
+
"session.created": { mode: "template", queuePriority: 2 /* NORMAL */, defaultEnabled: enabled(true, false) },
|
|
65
|
+
"permission.asked": { mode: "template", priority: "urgent", queuePriority: 3 /* URGENT */, defaultEnabled: enabled(true, true) },
|
|
66
|
+
"permission.replied": { mode: "template", queuePriority: 2 /* NORMAL */, defaultEnabled: enabled(true, false) },
|
|
67
|
+
"tool.execute.before": { mode: "template", priority: "chatty", queuePriority: 1 /* CHATTY */, defaultEnabled: enabled(true, false) },
|
|
68
|
+
"tool.execute.after": { mode: "template", priority: "chatty", queuePriority: 1 /* CHATTY */, defaultEnabled: enabled(true, false) },
|
|
69
|
+
"file.edited": { mode: "template", priority: "chatty", queuePriority: 1 /* CHATTY */, defaultEnabled: enabled(true, false) },
|
|
70
|
+
"command.executed": { mode: "template", queuePriority: 2 /* NORMAL */, defaultEnabled: enabled(true, false) },
|
|
71
|
+
"message.updated": { mode: "verbatim", priority: "chatty", queuePriority: 1 /* CHATTY */, defaultEnabled: enabled(false, false) },
|
|
72
|
+
"message.reasoning.delta": { mode: "verbatim", priority: "chatty", queuePriority: 1 /* CHATTY */, defaultEnabled: enabled(true, false), synthetic: true },
|
|
73
|
+
"message.text.delta": { mode: "verbatim", priority: "chatty", queuePriority: 1 /* CHATTY */, defaultEnabled: enabled(false, false), synthetic: true },
|
|
74
|
+
"todo.completed.item": { mode: "template", priority: "chatty", queuePriority: 1 /* CHATTY */, defaultEnabled: enabled(true, false), synthetic: true },
|
|
75
|
+
"todo.completed.all": { mode: "narrate", queuePriority: 2 /* NORMAL */, defaultEnabled: enabled(true, true), synthetic: true, narrationOccasion: "The user has finished all todos." }
|
|
76
|
+
};
|
|
77
|
+
function defaultEventsForVerbosity(verbosity) {
|
|
78
|
+
return Object.fromEntries(
|
|
79
|
+
Object.entries(EVENT_SPECS).map(([type, spec]) => [
|
|
80
|
+
type,
|
|
81
|
+
{
|
|
82
|
+
enabled: spec.defaultEnabled[verbosity],
|
|
83
|
+
mode: spec.mode,
|
|
84
|
+
...spec.priority ? { priority: spec.priority } : {}
|
|
85
|
+
}
|
|
86
|
+
])
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
function queuePriorityForEvent(type) {
|
|
90
|
+
return EVENT_SPECS[type]?.queuePriority ?? 2 /* NORMAL */;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/config.ts
|
|
94
|
+
var PLUGIN_NAME = "opencode-speaker";
|
|
95
|
+
var DEFAULT_TTS_MODEL = "openai/gpt-4o-mini-tts";
|
|
96
|
+
var DEFAULT_NARRATOR_MODEL = "openai/gpt-4.1-mini";
|
|
97
|
+
var DEFAULT_GREETING = "Welcome to OpenCode Speaker!";
|
|
98
|
+
var ENV_DISABLED = "OPENCODE_VOICE_DISABLED";
|
|
99
|
+
var ENV_MUTE = "OPENCODE_VOICE_MUTE";
|
|
100
|
+
var PrioritySchema = z.enum(["urgent", "normal", "chatty"]).optional();
|
|
101
|
+
var ModeSchema = z.enum(["template", "narrate", "verbatim"]);
|
|
102
|
+
var VerbositySchema = z.enum(["minimal", "normal", "verbose"]);
|
|
103
|
+
var EventConfigSchema = z.object({
|
|
104
|
+
enabled: z.boolean().default(false),
|
|
105
|
+
mode: ModeSchema.default("template"),
|
|
106
|
+
priority: PrioritySchema
|
|
107
|
+
});
|
|
108
|
+
var SLUG_MSG = `must be 'provider/model' (e.g. '${DEFAULT_TTS_MODEL}')`;
|
|
109
|
+
var TTSSchema = z.object({
|
|
110
|
+
model: z.string().regex(SLUG_RE, `tts.model ${SLUG_MSG}`).default(DEFAULT_TTS_MODEL),
|
|
111
|
+
voice: z.string().optional(),
|
|
112
|
+
rate: z.number().min(0.5).max(2).default(1),
|
|
113
|
+
pitch: z.number().min(0.5).max(2).default(1)
|
|
114
|
+
}).default({});
|
|
115
|
+
var NarratorSchema = z.object({
|
|
116
|
+
model: z.string().regex(SLUG_RE, `narrator.model ${SLUG_MSG}`).default(DEFAULT_NARRATOR_MODEL),
|
|
117
|
+
timeoutMs: z.number().int().positive().default(5e3),
|
|
118
|
+
minIntervalMs: z.number().int().min(0).default(3e3)
|
|
119
|
+
}).default({});
|
|
120
|
+
var QueueSchema = z.object({
|
|
121
|
+
staleMs: z.number().int().min(0).default(8e3)
|
|
122
|
+
}).default({});
|
|
123
|
+
var EventsSchema = z.record(z.string(), EventConfigSchema).default({});
|
|
124
|
+
var VoiceConfigSchema = z.object({
|
|
125
|
+
enabled: z.boolean().default(true),
|
|
126
|
+
verbosity: VerbositySchema.default("normal"),
|
|
127
|
+
startMuted: z.boolean().default(false),
|
|
128
|
+
greeting: z.string().default(DEFAULT_GREETING),
|
|
129
|
+
tts: TTSSchema,
|
|
130
|
+
narrator: NarratorSchema,
|
|
131
|
+
events: EventsSchema,
|
|
132
|
+
queue: QueueSchema
|
|
133
|
+
});
|
|
134
|
+
function presetEvents(verbosity) {
|
|
135
|
+
return defaultEventsForVerbosity(verbosity);
|
|
136
|
+
}
|
|
137
|
+
var DEFAULT_CONFIG = VoiceConfigSchema.parse({
|
|
138
|
+
events: defaultEventsForVerbosity("normal")
|
|
139
|
+
});
|
|
140
|
+
function parseConfig(raw, env = process.env) {
|
|
141
|
+
const userObj = raw && typeof raw === "object" ? raw : {};
|
|
142
|
+
const userEvents = userObj.events && typeof userObj.events === "object" ? userObj.events : {};
|
|
143
|
+
const rawVerbosity = userObj.verbosity;
|
|
144
|
+
const verbosity = rawVerbosity === "minimal" || rawVerbosity === "verbose" || rawVerbosity === "normal" ? rawVerbosity : "normal";
|
|
145
|
+
const defaultsForVerbosity = presetEvents(verbosity);
|
|
146
|
+
const mergedEvents = { ...defaultsForVerbosity };
|
|
147
|
+
for (const [key, val] of Object.entries(userEvents)) {
|
|
148
|
+
const defaultEvent = defaultsForVerbosity[key] ?? {};
|
|
149
|
+
if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
150
|
+
mergedEvents[key] = { ...defaultEvent, ...val };
|
|
151
|
+
} else {
|
|
152
|
+
mergedEvents[key] = val;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const merged = { ...userObj, events: mergedEvents };
|
|
156
|
+
const parsed = VoiceConfigSchema.safeParse(merged);
|
|
157
|
+
if (!parsed.success) {
|
|
158
|
+
return {
|
|
159
|
+
ok: false,
|
|
160
|
+
errors: parsed.error.issues.map((i) => ({
|
|
161
|
+
path: i.path.join("."),
|
|
162
|
+
message: i.message
|
|
163
|
+
}))
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const cfg = parsed.data;
|
|
167
|
+
if (env[ENV_DISABLED] === "1") cfg.enabled = false;
|
|
168
|
+
if (env[ENV_MUTE] === "1") cfg.startMuted = true;
|
|
169
|
+
return { ok: true, config: cfg };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// src/log.ts
|
|
173
|
+
var SENSITIVE_KEYS = /* @__PURE__ */ new Set([
|
|
174
|
+
"apiKey",
|
|
175
|
+
"api_key",
|
|
176
|
+
"apikey",
|
|
177
|
+
"authorization",
|
|
178
|
+
"Authorization",
|
|
179
|
+
"secret",
|
|
180
|
+
"token",
|
|
181
|
+
"password"
|
|
182
|
+
]);
|
|
183
|
+
function redact(value) {
|
|
184
|
+
return redactInner(value, /* @__PURE__ */ new WeakSet());
|
|
185
|
+
}
|
|
186
|
+
function redactInner(value, seen) {
|
|
187
|
+
if (value === null || typeof value !== "object") return value;
|
|
188
|
+
if (seen.has(value)) return "[Circular]";
|
|
189
|
+
seen.add(value);
|
|
190
|
+
if (Array.isArray(value)) return value.map((v) => redactInner(v, seen));
|
|
191
|
+
const out = {};
|
|
192
|
+
for (const [k, v] of Object.entries(value)) {
|
|
193
|
+
out[k] = SENSITIVE_KEYS.has(k) ? "***" : redactInner(v, seen);
|
|
194
|
+
}
|
|
195
|
+
return out;
|
|
196
|
+
}
|
|
197
|
+
var MAX_FIELD_BYTES = 4096;
|
|
198
|
+
function truncatePayload(value) {
|
|
199
|
+
return truncateInner(value, /* @__PURE__ */ new WeakSet(), false);
|
|
200
|
+
}
|
|
201
|
+
function truncateInner(value, seen, insideErrorStack) {
|
|
202
|
+
if (typeof value === "string") {
|
|
203
|
+
if (insideErrorStack) return value;
|
|
204
|
+
const bytes = Buffer.byteLength(value, "utf8");
|
|
205
|
+
if (bytes <= MAX_FIELD_BYTES) return value;
|
|
206
|
+
const head = Buffer.from(value, "utf8").subarray(0, MAX_FIELD_BYTES).toString("utf8");
|
|
207
|
+
return `${head}\u2026<truncated:${bytes - MAX_FIELD_BYTES} bytes>`;
|
|
208
|
+
}
|
|
209
|
+
if (value === null || typeof value !== "object") return value;
|
|
210
|
+
if (seen.has(value)) return value;
|
|
211
|
+
seen.add(value);
|
|
212
|
+
if (Array.isArray(value)) return value.map((v) => truncateInner(v, seen, insideErrorStack));
|
|
213
|
+
const out = {};
|
|
214
|
+
for (const [k, v] of Object.entries(value)) {
|
|
215
|
+
const exempt = k === "stack";
|
|
216
|
+
out[k] = truncateInner(v, seen, exempt);
|
|
217
|
+
}
|
|
218
|
+
return out;
|
|
219
|
+
}
|
|
220
|
+
var FRAME_RE = /^\s*at (?:(.+?) \()?(.+?):(\d+):(\d+)\)?$/;
|
|
221
|
+
function isInternalFile(file) {
|
|
222
|
+
return file.startsWith("node:") || file.includes("/internal/") || file.endsWith("/log.js") || file.endsWith("/log.ts");
|
|
223
|
+
}
|
|
224
|
+
function parseTopFrame(stack) {
|
|
225
|
+
if (!stack) return {};
|
|
226
|
+
const lines = stack.split("\n");
|
|
227
|
+
for (const raw of lines) {
|
|
228
|
+
const m = FRAME_RE.exec(raw);
|
|
229
|
+
if (!m) continue;
|
|
230
|
+
const file = m[2];
|
|
231
|
+
if (isInternalFile(file)) continue;
|
|
232
|
+
return {
|
|
233
|
+
function: m[1] || void 0,
|
|
234
|
+
file,
|
|
235
|
+
line: Number(m[3]),
|
|
236
|
+
column: Number(m[4])
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
return {};
|
|
240
|
+
}
|
|
241
|
+
function nonErrorMessage(value) {
|
|
242
|
+
try {
|
|
243
|
+
if (typeof value === "string") return value;
|
|
244
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
245
|
+
return JSON.stringify(value);
|
|
246
|
+
} catch {
|
|
247
|
+
return Object.prototype.toString.call(value);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function serializeError(err) {
|
|
251
|
+
if (!(err instanceof Error)) {
|
|
252
|
+
return { name: "NonError", message: nonErrorMessage(err) };
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
return serializeErrorDepth(err, 2);
|
|
256
|
+
} catch {
|
|
257
|
+
return { name: err.name ?? "Error", message: err.message ?? "" };
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function serializeErrorDepth(err, depth) {
|
|
261
|
+
const stack = err.stack;
|
|
262
|
+
const out = {
|
|
263
|
+
name: err.name,
|
|
264
|
+
message: err.message,
|
|
265
|
+
...stack ? { stack } : {},
|
|
266
|
+
...parseTopFrame(stack)
|
|
267
|
+
};
|
|
268
|
+
const code = err.code;
|
|
269
|
+
if (code !== void 0) out.code = code;
|
|
270
|
+
const cause = err.cause;
|
|
271
|
+
if (depth > 0 && cause instanceof Error) {
|
|
272
|
+
out.cause = serializeErrorDepth(cause, depth - 1);
|
|
273
|
+
}
|
|
274
|
+
return out;
|
|
275
|
+
}
|
|
276
|
+
function createLogger(client, service) {
|
|
277
|
+
return makeLogger(client, service, void 0);
|
|
278
|
+
}
|
|
279
|
+
function makeLogger(client, service, bindings) {
|
|
280
|
+
async function emit(level, message, ctx) {
|
|
281
|
+
try {
|
|
282
|
+
const body = { service, level, message };
|
|
283
|
+
const extra = buildExtra(ctx, bindings);
|
|
284
|
+
if (extra !== void 0) body.extra = extra;
|
|
285
|
+
await client.app.log({ body });
|
|
286
|
+
} catch {
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const logger = {
|
|
290
|
+
debug: (m, e) => emit("debug", m, e),
|
|
291
|
+
info: (m, e) => emit("info", m, e),
|
|
292
|
+
warn: (m, e) => emit("warn", m, e),
|
|
293
|
+
error: (m, e) => emit("error", m, e),
|
|
294
|
+
child(b) {
|
|
295
|
+
const merged = { ...bindings ?? {}, ...b };
|
|
296
|
+
return makeLogger(client, service, merged);
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
return logger;
|
|
300
|
+
}
|
|
301
|
+
function buildExtra(ctx, bindings) {
|
|
302
|
+
try {
|
|
303
|
+
let normalized;
|
|
304
|
+
if (ctx instanceof Error) {
|
|
305
|
+
normalized = { error: serializeError(ctx) };
|
|
306
|
+
} else if (ctx !== void 0 && ctx !== null && typeof ctx === "object") {
|
|
307
|
+
const obj = ctx;
|
|
308
|
+
normalized = { ...obj };
|
|
309
|
+
if (obj.error instanceof Error) {
|
|
310
|
+
normalized.error = serializeError(obj.error);
|
|
311
|
+
}
|
|
312
|
+
} else if (ctx !== void 0) {
|
|
313
|
+
normalized = { value: ctx };
|
|
314
|
+
}
|
|
315
|
+
if (bindings && Object.keys(bindings).length > 0) {
|
|
316
|
+
normalized = { ...normalized ?? {}, bindings: { ...bindings } };
|
|
317
|
+
}
|
|
318
|
+
if (normalized === void 0) return void 0;
|
|
319
|
+
return truncatePayload(redact(normalized));
|
|
320
|
+
} catch {
|
|
321
|
+
return bindings ? { bindings: { ...bindings } } : void 0;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// src/queue/speech-queue.ts
|
|
326
|
+
var SpeechQueue = class {
|
|
327
|
+
constructor(opts) {
|
|
328
|
+
this.opts = opts;
|
|
329
|
+
}
|
|
330
|
+
opts;
|
|
331
|
+
queue = [];
|
|
332
|
+
current = null;
|
|
333
|
+
muted = false;
|
|
334
|
+
idleResolvers = [];
|
|
335
|
+
pumpRunning = false;
|
|
336
|
+
push(req) {
|
|
337
|
+
if (this.muted) return;
|
|
338
|
+
if (this.current && req.priority > this.current.req.priority) {
|
|
339
|
+
this.queue.unshift(req);
|
|
340
|
+
this.current.abort.abort();
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
if (req.dedupKey) {
|
|
344
|
+
const idx = this.queue.findIndex((q) => q.dedupKey === req.dedupKey);
|
|
345
|
+
if (idx >= 0) {
|
|
346
|
+
this.queue[idx] = req;
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
let i = 0;
|
|
351
|
+
while (i < this.queue.length && this.queue[i].priority >= req.priority) i++;
|
|
352
|
+
this.queue.splice(i, 0, req);
|
|
353
|
+
void this.pump();
|
|
354
|
+
}
|
|
355
|
+
mute() {
|
|
356
|
+
this.muted = true;
|
|
357
|
+
this.queue = [];
|
|
358
|
+
if (this.current) this.current.abort.abort();
|
|
359
|
+
}
|
|
360
|
+
unmute() {
|
|
361
|
+
this.muted = false;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Interrupt the current utterance and drop the pending queue WITHOUT
|
|
365
|
+
* changing the muted state. Use this for "stop speaking right now" while
|
|
366
|
+
* leaving future events free to speak.
|
|
367
|
+
*/
|
|
368
|
+
stop() {
|
|
369
|
+
this.queue = [];
|
|
370
|
+
if (this.current) this.current.abort.abort();
|
|
371
|
+
}
|
|
372
|
+
isMuted() {
|
|
373
|
+
return this.muted;
|
|
374
|
+
}
|
|
375
|
+
size() {
|
|
376
|
+
return this.queue.length + (this.current ? 1 : 0);
|
|
377
|
+
}
|
|
378
|
+
/** Resolves when queue is empty and nothing is speaking. */
|
|
379
|
+
async idle() {
|
|
380
|
+
if (!this.current && this.queue.length === 0 && !this.pumpRunning) return;
|
|
381
|
+
return new Promise((resolve) => {
|
|
382
|
+
this.idleResolvers.push(resolve);
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
async pump() {
|
|
386
|
+
if (this.pumpRunning || this.current) return;
|
|
387
|
+
this.pumpRunning = true;
|
|
388
|
+
try {
|
|
389
|
+
while (this.queue.length > 0 && !this.muted) {
|
|
390
|
+
const next = this.queue.shift();
|
|
391
|
+
if (next.priority <= 2 /* NORMAL */ && this.opts.now() - next.enqueuedAt > this.opts.staleMs) {
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
const abort = new AbortController();
|
|
395
|
+
this.current = { req: next, abort };
|
|
396
|
+
try {
|
|
397
|
+
await this.opts.speak(next, abort.signal);
|
|
398
|
+
} catch (err) {
|
|
399
|
+
this.opts.onError?.(err, next);
|
|
400
|
+
} finally {
|
|
401
|
+
this.current = null;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
} finally {
|
|
405
|
+
this.pumpRunning = false;
|
|
406
|
+
if (!this.current && this.queue.length === 0) {
|
|
407
|
+
const resolvers = this.idleResolvers;
|
|
408
|
+
this.idleResolvers = [];
|
|
409
|
+
for (const r of resolvers) r();
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
// src/tts/ai-sdk.ts
|
|
416
|
+
import { experimental_generateSpeech as generateSpeech } from "ai";
|
|
417
|
+
function createAiSdkProvider(config) {
|
|
418
|
+
const { model, provider: providerName, voice: defaultVoice } = config;
|
|
419
|
+
return {
|
|
420
|
+
name: providerName,
|
|
421
|
+
async synthesize(text, opts, signal) {
|
|
422
|
+
const voice = opts.voice ?? defaultVoice ?? (providerName === "openai" ? "alloy" : void 0);
|
|
423
|
+
const result = await generateSpeech({
|
|
424
|
+
model,
|
|
425
|
+
text,
|
|
426
|
+
voice,
|
|
427
|
+
outputFormat: "mp3",
|
|
428
|
+
speed: opts.rate,
|
|
429
|
+
abortSignal: signal
|
|
430
|
+
});
|
|
431
|
+
return {
|
|
432
|
+
audio: Buffer.from(result.audio.uint8Array),
|
|
433
|
+
contentType: result.audio.mediaType ?? "audio/mpeg"
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// src/audio/player.ts
|
|
440
|
+
import { writeFile, mkdtemp, rm } from "fs/promises";
|
|
441
|
+
import { tmpdir } from "os";
|
|
442
|
+
import { join } from "path";
|
|
443
|
+
var LINUX_PLAYERS = ["paplay", "aplay", "ffplay"];
|
|
444
|
+
function createPlayer(opts) {
|
|
445
|
+
const platform = opts.platform ?? process.platform;
|
|
446
|
+
let binary = null;
|
|
447
|
+
async function buffer(stream, signal) {
|
|
448
|
+
if (Buffer.isBuffer(stream)) return stream;
|
|
449
|
+
const chunks = [];
|
|
450
|
+
const reader = stream.getReader();
|
|
451
|
+
try {
|
|
452
|
+
while (true) {
|
|
453
|
+
if (signal.aborted) throw new DOMException("aborted", "AbortError");
|
|
454
|
+
const { done, value } = await reader.read();
|
|
455
|
+
if (done) break;
|
|
456
|
+
if (value) chunks.push(value);
|
|
457
|
+
}
|
|
458
|
+
} finally {
|
|
459
|
+
if (signal.aborted) await reader.cancel().catch(() => void 0);
|
|
460
|
+
}
|
|
461
|
+
return Buffer.concat(chunks.map((c) => Buffer.from(c)));
|
|
462
|
+
}
|
|
463
|
+
async function writeTemp(buf, contentType) {
|
|
464
|
+
const ext = contentType.includes("mpeg") ? "mp3" : contentType.includes("wav") ? "wav" : "bin";
|
|
465
|
+
const dir = await mkdtemp(join(tmpdir(), `${PLUGIN_NAME}-`));
|
|
466
|
+
const path = join(dir, `audio.${ext}`);
|
|
467
|
+
await writeFile(path, buf);
|
|
468
|
+
return { dir, path };
|
|
469
|
+
}
|
|
470
|
+
function powershellEncodedCommand(path) {
|
|
471
|
+
const safePath = JSON.stringify(path.replace(/\\/g, "/"));
|
|
472
|
+
const script = [
|
|
473
|
+
"Add-Type -AssemblyName presentationCore",
|
|
474
|
+
"$p = New-Object System.Windows.Media.MediaPlayer",
|
|
475
|
+
`$p.Open([Uri]${safePath})`,
|
|
476
|
+
"$p.Play()",
|
|
477
|
+
"Start-Sleep -Seconds 30"
|
|
478
|
+
].join("; ");
|
|
479
|
+
return Buffer.from(script, "utf16le").toString("base64");
|
|
480
|
+
}
|
|
481
|
+
return {
|
|
482
|
+
async init() {
|
|
483
|
+
if (platform === "darwin") {
|
|
484
|
+
if (!await opts.runner.has("afplay")) {
|
|
485
|
+
throw new Error("No audio player available (need `afplay`)");
|
|
486
|
+
}
|
|
487
|
+
binary = "afplay";
|
|
488
|
+
} else if (platform === "linux") {
|
|
489
|
+
for (const b of LINUX_PLAYERS) {
|
|
490
|
+
if (await opts.runner.has(b)) {
|
|
491
|
+
binary = b;
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
if (!binary) {
|
|
496
|
+
throw new Error(
|
|
497
|
+
"No audio player available (need one of: paplay, aplay, ffplay)"
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
} else if (platform === "win32") {
|
|
501
|
+
if (!await opts.runner.has("powershell")) {
|
|
502
|
+
throw new Error("No audio player available (need `powershell`)");
|
|
503
|
+
}
|
|
504
|
+
binary = "powershell";
|
|
505
|
+
} else {
|
|
506
|
+
throw new Error(`Unsupported platform for audio playback: ${platform}`);
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
async play(audio, contentType, signal) {
|
|
510
|
+
if (!binary) throw new Error("Audio player not initialized");
|
|
511
|
+
if (signal.aborted) throw new DOMException("aborted", "AbortError");
|
|
512
|
+
const buf = await buffer(audio, signal);
|
|
513
|
+
const tmp = await writeTemp(buf, contentType);
|
|
514
|
+
let cmd;
|
|
515
|
+
if (binary === "powershell") {
|
|
516
|
+
cmd = [
|
|
517
|
+
"powershell",
|
|
518
|
+
"-NoProfile",
|
|
519
|
+
"-EncodedCommand",
|
|
520
|
+
powershellEncodedCommand(tmp.path)
|
|
521
|
+
];
|
|
522
|
+
} else if (binary === "ffplay") {
|
|
523
|
+
cmd = ["ffplay", "-autoexit", "-nodisp", "-loglevel", "quiet", tmp.path];
|
|
524
|
+
} else {
|
|
525
|
+
cmd = [binary, tmp.path];
|
|
526
|
+
}
|
|
527
|
+
try {
|
|
528
|
+
const result = await opts.runner.run(cmd, signal);
|
|
529
|
+
if (result.exitCode !== 0) {
|
|
530
|
+
throw new Error(`audio playback failed with exit code ${result.exitCode}`);
|
|
531
|
+
}
|
|
532
|
+
} finally {
|
|
533
|
+
await rm(tmp.dir, { recursive: true, force: true });
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// src/audio/runner.ts
|
|
540
|
+
async function defaultRunner() {
|
|
541
|
+
const { spawn } = await import("child_process");
|
|
542
|
+
const { access, constants } = await import("fs/promises");
|
|
543
|
+
const { delimiter, sep } = await import("path");
|
|
544
|
+
async function has(binary) {
|
|
545
|
+
const PATH = process.env.PATH ?? "";
|
|
546
|
+
const exts = process.platform === "win32" ? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";") : [""];
|
|
547
|
+
for (const dir of PATH.split(delimiter)) {
|
|
548
|
+
for (const ext of exts) {
|
|
549
|
+
try {
|
|
550
|
+
await access(`${dir}${sep}${binary}${ext}`, constants.X_OK);
|
|
551
|
+
return true;
|
|
552
|
+
} catch {
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
const ABORT_KILL_MS = 1e3;
|
|
559
|
+
async function run(cmd, signal) {
|
|
560
|
+
if (signal.aborted) throw new DOMException("aborted", "AbortError");
|
|
561
|
+
return await new Promise((resolve, reject) => {
|
|
562
|
+
const child = spawn(cmd[0], cmd.slice(1), { stdio: "ignore" });
|
|
563
|
+
let killTimer;
|
|
564
|
+
const cleanup = () => {
|
|
565
|
+
signal.removeEventListener("abort", onAbort);
|
|
566
|
+
if (killTimer) clearTimeout(killTimer);
|
|
567
|
+
};
|
|
568
|
+
const onAbort = () => {
|
|
569
|
+
child.kill("SIGTERM");
|
|
570
|
+
killTimer = setTimeout(() => child.kill("SIGKILL"), ABORT_KILL_MS);
|
|
571
|
+
};
|
|
572
|
+
signal.addEventListener("abort", onAbort);
|
|
573
|
+
child.on("error", (e) => {
|
|
574
|
+
cleanup();
|
|
575
|
+
reject(e);
|
|
576
|
+
});
|
|
577
|
+
child.on("exit", (code) => {
|
|
578
|
+
cleanup();
|
|
579
|
+
if (signal.aborted) reject(new DOMException("aborted", "AbortError"));
|
|
580
|
+
else if ((code ?? 0) !== 0) reject(new Error(`process exited with code ${code ?? 0}`));
|
|
581
|
+
else resolve({ exitCode: 0 });
|
|
582
|
+
});
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
return { has, run };
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// src/handlers/index.ts
|
|
589
|
+
import { randomUUID } from "crypto";
|
|
590
|
+
|
|
591
|
+
// src/handlers/template.ts
|
|
592
|
+
function truncate(s, max) {
|
|
593
|
+
if (s.length <= max) return s;
|
|
594
|
+
return s.slice(0, max) + "\u2026";
|
|
595
|
+
}
|
|
596
|
+
function stripMarkdown(text) {
|
|
597
|
+
return text.replace(/```[\s\S]*?```/g, "").replace(/`([^`]+)`/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/\*([^*]+)\*/g, "$1").replace(/__([^_]+)__/g, "$1").replace(/_([^_]+)_/g, "$1").replace(/!\[[^\]]*\]\([^)]*\)/g, "").replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").replace(/^#+\s+/gm, "").replace(/^\s*[-*+]\s+/gm, "").replace(/\s+/g, " ").trim();
|
|
598
|
+
}
|
|
599
|
+
function basename(p) {
|
|
600
|
+
const trimmed = p.replace(/[\\/]+$/, "");
|
|
601
|
+
const i = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
|
|
602
|
+
return i >= 0 ? trimmed.slice(i + 1) : trimmed;
|
|
603
|
+
}
|
|
604
|
+
function asString(v) {
|
|
605
|
+
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
606
|
+
}
|
|
607
|
+
var templates = {
|
|
608
|
+
// --- Real OpenCode events ---
|
|
609
|
+
"session.idle": () => "I'm idle now and waiting for your next instruction.",
|
|
610
|
+
"session.error": (e) => `I hit a session error: ${truncate(String(e.message ?? "unknown"), 200)}. Check the log for details.`,
|
|
611
|
+
"session.compacted": () => "I compacted the session, so older context is summarized and I have more room to continue.",
|
|
612
|
+
"session.created": () => "I'm starting a new session and getting ready to work.",
|
|
613
|
+
"permission.asked": (e) => `I need your approval before I use ${asString(e.tool) ?? "an operation"}.`,
|
|
614
|
+
"permission.replied": (e) => {
|
|
615
|
+
const raw = String(e.decision ?? "responded").toLowerCase();
|
|
616
|
+
const verb = raw === "allow" || raw === "approve" || raw === "accept" || raw === "yes" || raw === "once" || raw === "always" ? "granted" : raw === "deny" || raw === "reject" || raw === "no" ? "denied" : raw;
|
|
617
|
+
const tool = asString(e.tool) ?? "the operation";
|
|
618
|
+
if (verb === "granted") return `I got approval to use ${tool}.`;
|
|
619
|
+
if (verb === "denied") return `I was denied permission to use ${tool}.`;
|
|
620
|
+
if (verb === "responded") return `I got a response for ${tool}.`;
|
|
621
|
+
return `I got a permission response for ${tool}: ${verb}.`;
|
|
622
|
+
},
|
|
623
|
+
"tool.execute.before": (e) => `I'm running ${asString(e.tool) ?? "tool"} now.`,
|
|
624
|
+
"tool.execute.after": (e) => `I finished running ${asString(e.tool) ?? "tool"}.`,
|
|
625
|
+
"file.edited": (e) => {
|
|
626
|
+
const raw = String(e.file ?? "");
|
|
627
|
+
return raw ? `I edited ${basename(raw)}.` : "I edited a file.";
|
|
628
|
+
},
|
|
629
|
+
"command.executed": (e) => {
|
|
630
|
+
const name = String(e.command ?? "").trim();
|
|
631
|
+
return name ? `I ran ${name}.` : "I ran a command.";
|
|
632
|
+
},
|
|
633
|
+
// Note: `message.updated` carries `{ sessionID, info: Message }` — the
|
|
634
|
+
// message text lives in `info.parts`, not at the top level. Live narration
|
|
635
|
+
// is handled by the synthesized `message.text.delta` events derived from
|
|
636
|
+
// `message.part.updated`, so there is intentionally no template here.
|
|
637
|
+
// --- Synthesized by src/dispatcher.ts ---
|
|
638
|
+
"message.text.delta": (e) => truncate(stripMarkdown(String(e.text ?? "")), 600),
|
|
639
|
+
"message.reasoning.delta": (e) => truncate(stripMarkdown(String(e.text ?? "")), 600),
|
|
640
|
+
"todo.completed.all": (e) => {
|
|
641
|
+
const n = Number(e.count ?? 0);
|
|
642
|
+
return n > 0 ? `I've completed all ${n} todos. Nice work.` : "I've completed all todos. Nice work.";
|
|
643
|
+
},
|
|
644
|
+
"todo.completed.item": (e) => `I finished this task: ${truncate(stripMarkdown(String(e.content ?? "")), 80)}.`
|
|
645
|
+
};
|
|
646
|
+
function renderTemplate(event) {
|
|
647
|
+
const fn = templates[event.type];
|
|
648
|
+
if (!fn) return null;
|
|
649
|
+
const out = fn(event);
|
|
650
|
+
return out.length === 0 ? null : out;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// src/handlers/index.ts
|
|
654
|
+
var MODE_RENDERERS = {
|
|
655
|
+
template: (event) => renderTemplate(event),
|
|
656
|
+
narrate: async (event, ctx) => {
|
|
657
|
+
const text = await ctx.narrator.summarize(event, ctx.getContext());
|
|
658
|
+
return text ?? renderTemplate(event);
|
|
659
|
+
},
|
|
660
|
+
verbatim: (event) => truncate(stripMarkdown(String(event.text ?? "")), 300)
|
|
661
|
+
};
|
|
662
|
+
function priorityFromName(name) {
|
|
663
|
+
if (name === "urgent") return 3 /* URGENT */;
|
|
664
|
+
if (name === "normal") return 2 /* NORMAL */;
|
|
665
|
+
if (name === "chatty") return 1 /* CHATTY */;
|
|
666
|
+
return null;
|
|
667
|
+
}
|
|
668
|
+
function createHandlerRegistry(opts) {
|
|
669
|
+
return {
|
|
670
|
+
async handle(event) {
|
|
671
|
+
const cfg = opts.events[event.type];
|
|
672
|
+
if (!cfg || !cfg.enabled) return null;
|
|
673
|
+
const text = await MODE_RENDERERS[cfg.mode](event, opts);
|
|
674
|
+
if (!text) return null;
|
|
675
|
+
const priority = priorityFromName(cfg.priority) ?? queuePriorityForEvent(event.type);
|
|
676
|
+
const overrideKey = event.dedupKey;
|
|
677
|
+
const dedupKey = typeof overrideKey === "string" ? overrideKey : event.type;
|
|
678
|
+
return {
|
|
679
|
+
id: randomUUID(),
|
|
680
|
+
priority,
|
|
681
|
+
text,
|
|
682
|
+
dedupKey,
|
|
683
|
+
enqueuedAt: Date.now()
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// src/handlers/narrator.ts
|
|
690
|
+
import { generateText } from "ai";
|
|
691
|
+
var SYSTEM_PROMPT = [
|
|
692
|
+
"You are the coding agent. Your words are read aloud by a text-to-speech engine while the",
|
|
693
|
+
"user looks away from the screen, so speak as yourself in natural spoken English.",
|
|
694
|
+
"",
|
|
695
|
+
"happened: what you attempted and changed, the outcome, and any blocker, error, or decision",
|
|
696
|
+
"that needs the user's attention. Add an obvious next step only if there is one.",
|
|
697
|
+
"",
|
|
698
|
+
"Style:",
|
|
699
|
+
"- First person \u2014 I, me, my. You did the work; never describe yourself in third person or as an AI.",
|
|
700
|
+
"- Plain prose only: no markdown, code blocks, quotes, bullet points, or headings.",
|
|
701
|
+
'- Refer to code by purpose ("the auth module", "the new check") rather than identifier.',
|
|
702
|
+
" When a specific file name or the exact error message is the key fact, say it plainly.",
|
|
703
|
+
"- Avoid file paths, type names, and command flags unless one of them is the point.",
|
|
704
|
+
"- Only describe what the context below shows. Do not invent files, tools, or outcomes.",
|
|
705
|
+
"- No greetings, sign-offs, or restating these instructions.",
|
|
706
|
+
"",
|
|
707
|
+
'Example: "I refactored the credentials loader and its tests pass. No blockers."'
|
|
708
|
+
].join("\n");
|
|
709
|
+
var FACT_FIELDS = ["tool", "file", "command", "message", "errorName", "content"];
|
|
710
|
+
function eventFacts(event) {
|
|
711
|
+
const lines = [];
|
|
712
|
+
for (const key of FACT_FIELDS) {
|
|
713
|
+
const value = event[key];
|
|
714
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
715
|
+
lines.push(`- ${key}: ${truncate(value, 200)}`);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
if (typeof event.count === "number") lines.push(`- count: ${event.count}`);
|
|
719
|
+
return lines.join("\n");
|
|
720
|
+
}
|
|
721
|
+
function buildContext(event, ctx) {
|
|
722
|
+
const text = truncate(ctx.assistantText, 1e4);
|
|
723
|
+
const tools = ctx.recentTools.slice(-5).map((t) => `- ${t}`).join("\n") || "(none)";
|
|
724
|
+
const occasion = EVENT_SPECS[event.type]?.narrationOccasion ?? "I just finished a turn.";
|
|
725
|
+
return [
|
|
726
|
+
occasion,
|
|
727
|
+
"",
|
|
728
|
+
"What I produced recently:",
|
|
729
|
+
text || "(none)",
|
|
730
|
+
"",
|
|
731
|
+
"Tools I recently used:",
|
|
732
|
+
tools,
|
|
733
|
+
"",
|
|
734
|
+
"Event details:",
|
|
735
|
+
eventFacts(event) || "(no extra detail)"
|
|
736
|
+
].join("\n");
|
|
737
|
+
}
|
|
738
|
+
function createNarrator(model, config, logger) {
|
|
739
|
+
let lastFinishedAt = 0;
|
|
740
|
+
return {
|
|
741
|
+
async summarize(event, ctx) {
|
|
742
|
+
const now = Date.now();
|
|
743
|
+
if (now - lastFinishedAt < config.minIntervalMs) return null;
|
|
744
|
+
const hasContext = ctx.assistantText.trim().length > 0 || ctx.recentTools.length > 0 || eventFacts(event).length > 0;
|
|
745
|
+
if (!hasContext) return null;
|
|
746
|
+
const ac = new AbortController();
|
|
747
|
+
const timer = setTimeout(() => ac.abort(), config.timeoutMs);
|
|
748
|
+
try {
|
|
749
|
+
const { text } = await generateText({
|
|
750
|
+
model,
|
|
751
|
+
system: SYSTEM_PROMPT,
|
|
752
|
+
temperature: 0.2,
|
|
753
|
+
prompt: buildContext(event, ctx),
|
|
754
|
+
abortSignal: ac.signal
|
|
755
|
+
});
|
|
756
|
+
const trimmed = text.trim();
|
|
757
|
+
if (trimmed.length === 0) return null;
|
|
758
|
+
lastFinishedAt = Date.now();
|
|
759
|
+
return trimmed;
|
|
760
|
+
} catch (err) {
|
|
761
|
+
if (logger) {
|
|
762
|
+
await logger.warn("narrator summary failed", {
|
|
763
|
+
error: err,
|
|
764
|
+
operation: "summarizing event for narration",
|
|
765
|
+
input: {
|
|
766
|
+
eventType: event.type,
|
|
767
|
+
assistantTextLen: ctx.assistantText.length,
|
|
768
|
+
recentToolsCount: ctx.recentTools.length
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
return null;
|
|
773
|
+
} finally {
|
|
774
|
+
clearTimeout(timer);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// src/events/normalize.ts
|
|
781
|
+
function objectRecord(value) {
|
|
782
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
783
|
+
}
|
|
784
|
+
function firstString(...values) {
|
|
785
|
+
for (const value of values) {
|
|
786
|
+
if (typeof value === "string" && value.trim().length > 0) return value;
|
|
787
|
+
}
|
|
788
|
+
return void 0;
|
|
789
|
+
}
|
|
790
|
+
var TYPE_ALIASES = {
|
|
791
|
+
"permission.updated": "permission.asked",
|
|
792
|
+
// v1 SDK name
|
|
793
|
+
"session.next.tool.called": "tool.execute.before",
|
|
794
|
+
// v2 SDK
|
|
795
|
+
"session.next.tool.success": "tool.execute.after",
|
|
796
|
+
// v2 SDK
|
|
797
|
+
"session.next.tool.failed": "tool.execute.after"
|
|
798
|
+
// v2 SDK
|
|
799
|
+
};
|
|
800
|
+
function normalizeEvent(raw) {
|
|
801
|
+
const props = objectRecord(raw.properties);
|
|
802
|
+
const propType = typeof props.type === "string" ? props.type : void 0;
|
|
803
|
+
const canonicalType = TYPE_ALIASES[raw.type] ?? raw.type;
|
|
804
|
+
const merged = { ...raw, ...props, type: canonicalType };
|
|
805
|
+
if (canonicalType === "permission.asked" || canonicalType === "permission.replied") {
|
|
806
|
+
const meta = objectRecord(merged.metadata);
|
|
807
|
+
const toolName = firstString(
|
|
808
|
+
typeof merged.tool === "string" ? merged.tool : void 0,
|
|
809
|
+
merged.permission,
|
|
810
|
+
// v2 PermissionRequest.permission
|
|
811
|
+
propType,
|
|
812
|
+
// v1 Permission.type (rescued from properties)
|
|
813
|
+
meta.tool,
|
|
814
|
+
// older shape: permission metadata
|
|
815
|
+
merged.title
|
|
816
|
+
// last-resort v1 fallback (often long-form like "Run a shell command")
|
|
817
|
+
);
|
|
818
|
+
const next = { ...merged, tool: toolName };
|
|
819
|
+
if (canonicalType === "permission.replied") {
|
|
820
|
+
next.decision = firstString(merged.decision, merged.response, merged.reply, merged.result) ?? "responded";
|
|
821
|
+
}
|
|
822
|
+
return next;
|
|
823
|
+
}
|
|
824
|
+
if (canonicalType === "tool.execute.before" || canonicalType === "tool.execute.after") {
|
|
825
|
+
return {
|
|
826
|
+
...merged,
|
|
827
|
+
tool: firstString(merged.tool, merged.name),
|
|
828
|
+
callID: firstString(merged.callID, merged.callId, merged.id)
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
if (canonicalType === "session.error") {
|
|
832
|
+
const err = objectRecord(merged.error);
|
|
833
|
+
const errData = objectRecord(err.data);
|
|
834
|
+
return {
|
|
835
|
+
...merged,
|
|
836
|
+
// Real shape: properties.error.data.message. Fall back to a top-level
|
|
837
|
+
// `message` only because old/synthesized events sometimes use it.
|
|
838
|
+
message: firstString(merged.message, errData.message, err.message),
|
|
839
|
+
errorName: firstString(err.name, errData.name)
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
if (canonicalType === "file.edited") {
|
|
843
|
+
return {
|
|
844
|
+
...merged,
|
|
845
|
+
file: firstString(merged.file, merged.path, merged.filePath)
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
if (canonicalType === "command.executed" || canonicalType === "tui.command.execute") {
|
|
849
|
+
return {
|
|
850
|
+
...merged,
|
|
851
|
+
command: firstString(merged.command, merged.name, merged.id)
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
return merged;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// src/dispatcher.ts
|
|
858
|
+
var SENTENCE_RE = /[\s\S]*?[.!?]+(?:["')\]]?)(?:\s+|$)/g;
|
|
859
|
+
function createDispatcher(opts) {
|
|
860
|
+
const textWindow = opts.textWindow ?? 4e3;
|
|
861
|
+
const toolWindow = opts.toolWindow ?? 10;
|
|
862
|
+
const reasoningFlushChars = opts.reasoningFlushChars ?? 240;
|
|
863
|
+
let assistantText = "";
|
|
864
|
+
const recentTools = [];
|
|
865
|
+
const toolByCallId = /* @__PURE__ */ new Map();
|
|
866
|
+
const todoStatus = /* @__PURE__ */ new Map();
|
|
867
|
+
const partSeen = /* @__PURE__ */ new Map();
|
|
868
|
+
const reasoningBuffer = /* @__PURE__ */ new Map();
|
|
869
|
+
let deltaSequence = 0;
|
|
870
|
+
function appendText(t) {
|
|
871
|
+
assistantText = (assistantText + " " + t).slice(-textWindow);
|
|
872
|
+
}
|
|
873
|
+
function trackTool(tool) {
|
|
874
|
+
recentTools.push(tool);
|
|
875
|
+
while (recentTools.length > toolWindow) recentTools.shift();
|
|
876
|
+
}
|
|
877
|
+
function resetTurnState() {
|
|
878
|
+
assistantText = "";
|
|
879
|
+
recentTools.length = 0;
|
|
880
|
+
partSeen.clear();
|
|
881
|
+
reasoningBuffer.clear();
|
|
882
|
+
toolByCallId.clear();
|
|
883
|
+
}
|
|
884
|
+
async function fire(event) {
|
|
885
|
+
try {
|
|
886
|
+
const sr = await opts.handler.handle(event);
|
|
887
|
+
if (sr) opts.queue.push(sr);
|
|
888
|
+
} catch (err) {
|
|
889
|
+
if (opts.logger) {
|
|
890
|
+
await opts.logger.warn("handler failed", {
|
|
891
|
+
error: err,
|
|
892
|
+
operation: "dispatching opencode event",
|
|
893
|
+
input: { eventType: event.type }
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
opts.onError?.(err, event);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
async function handleTodoUpdated(props) {
|
|
900
|
+
const todos = props.todos ?? [];
|
|
901
|
+
let transitionsToCompleted = 0;
|
|
902
|
+
for (const t of todos) {
|
|
903
|
+
const prev = todoStatus.get(t.id);
|
|
904
|
+
if (prev !== "completed" && t.status === "completed") {
|
|
905
|
+
transitionsToCompleted++;
|
|
906
|
+
await fire({ type: "todo.completed.item", content: t.content });
|
|
907
|
+
}
|
|
908
|
+
todoStatus.set(t.id, t.status);
|
|
909
|
+
}
|
|
910
|
+
if (todos.length > 0 && todos.every((t) => t.status === "completed") && transitionsToCompleted > 0) {
|
|
911
|
+
await fire({ type: "todo.completed.all", count: todos.length });
|
|
912
|
+
}
|
|
913
|
+
await fire({ type: "todo.updated", todos });
|
|
914
|
+
}
|
|
915
|
+
function computeDelta(partId, fullText) {
|
|
916
|
+
const prev = partSeen.get(partId) ?? 0;
|
|
917
|
+
if (fullText.length < prev) {
|
|
918
|
+
partSeen.set(partId, fullText.length);
|
|
919
|
+
return null;
|
|
920
|
+
}
|
|
921
|
+
if (fullText.length === prev) return null;
|
|
922
|
+
const delta = fullText.slice(prev);
|
|
923
|
+
partSeen.set(partId, fullText.length);
|
|
924
|
+
return delta;
|
|
925
|
+
}
|
|
926
|
+
async function handleTextPart(part) {
|
|
927
|
+
if (!part.id || typeof part.text !== "string") return;
|
|
928
|
+
const delta = computeDelta(part.id, part.text);
|
|
929
|
+
if (!delta) return;
|
|
930
|
+
appendText(delta);
|
|
931
|
+
await fire({
|
|
932
|
+
type: "message.text.delta",
|
|
933
|
+
text: delta,
|
|
934
|
+
partID: part.id,
|
|
935
|
+
dedupKey: `message.text.delta:${part.id}:${++deltaSequence}`
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
async function handleReasoningPart(part) {
|
|
939
|
+
if (!part.id || typeof part.text !== "string") return;
|
|
940
|
+
const delta = computeDelta(part.id, part.text);
|
|
941
|
+
if (!delta) return;
|
|
942
|
+
let buffered = (reasoningBuffer.get(part.id) ?? "") + delta;
|
|
943
|
+
const sentences = [];
|
|
944
|
+
let cursor = 0;
|
|
945
|
+
SENTENCE_RE.lastIndex = 0;
|
|
946
|
+
let m;
|
|
947
|
+
while ((m = SENTENCE_RE.exec(buffered)) !== null) {
|
|
948
|
+
sentences.push(m[0].trim());
|
|
949
|
+
cursor = SENTENCE_RE.lastIndex;
|
|
950
|
+
}
|
|
951
|
+
buffered = buffered.slice(cursor);
|
|
952
|
+
if (buffered.length >= reasoningFlushChars) {
|
|
953
|
+
sentences.push(buffered.trim());
|
|
954
|
+
buffered = "";
|
|
955
|
+
}
|
|
956
|
+
reasoningBuffer.set(part.id, buffered);
|
|
957
|
+
for (const sentence of sentences) {
|
|
958
|
+
if (!sentence) continue;
|
|
959
|
+
await fire({
|
|
960
|
+
type: "message.reasoning.delta",
|
|
961
|
+
text: sentence,
|
|
962
|
+
partID: part.id,
|
|
963
|
+
dedupKey: `message.reasoning.delta:${part.id}:${++deltaSequence}`
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
async function handleMessagePart(props) {
|
|
968
|
+
const part = props.part;
|
|
969
|
+
if (!part || typeof part !== "object") return;
|
|
970
|
+
if (part.type === "text") {
|
|
971
|
+
await handleTextPart(part);
|
|
972
|
+
} else if (part.type === "reasoning") {
|
|
973
|
+
await handleReasoningPart(part);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
return {
|
|
977
|
+
async onEvent(event) {
|
|
978
|
+
const normalized = normalizeEvent(event);
|
|
979
|
+
if (normalized.type === "todo.updated") {
|
|
980
|
+
const todos = normalized.todos;
|
|
981
|
+
return handleTodoUpdated({ todos });
|
|
982
|
+
}
|
|
983
|
+
if (normalized.type === "message.part.updated") {
|
|
984
|
+
const part = normalized.part;
|
|
985
|
+
return handleMessagePart({ part });
|
|
986
|
+
}
|
|
987
|
+
if (normalized.type === "tool.execute.before") {
|
|
988
|
+
const tool = normalized.tool;
|
|
989
|
+
const callID = normalized.callID;
|
|
990
|
+
if (typeof tool === "string") {
|
|
991
|
+
trackTool(tool);
|
|
992
|
+
if (typeof callID === "string") toolByCallId.set(callID, tool);
|
|
993
|
+
}
|
|
994
|
+
} else if (normalized.type === "tool.execute.after") {
|
|
995
|
+
if (typeof normalized.tool !== "string") {
|
|
996
|
+
const callID2 = normalized.callID;
|
|
997
|
+
const remembered = callID2 ? toolByCallId.get(callID2) : void 0;
|
|
998
|
+
if (remembered) normalized.tool = remembered;
|
|
999
|
+
}
|
|
1000
|
+
const callID = normalized.callID;
|
|
1001
|
+
if (callID) toolByCallId.delete(callID);
|
|
1002
|
+
}
|
|
1003
|
+
try {
|
|
1004
|
+
await fire(normalized);
|
|
1005
|
+
} finally {
|
|
1006
|
+
if (normalized.type === "session.idle" || normalized.type === "session.created") {
|
|
1007
|
+
resetTurnState();
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
},
|
|
1011
|
+
getContext() {
|
|
1012
|
+
return { assistantText, recentTools: [...recentTools] };
|
|
1013
|
+
}
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
// src/commands/index.ts
|
|
1018
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
1019
|
+
function createCommands(opts) {
|
|
1020
|
+
function makeRequest(text, priority) {
|
|
1021
|
+
return { id: randomUUID2(), priority, text, enqueuedAt: Date.now() };
|
|
1022
|
+
}
|
|
1023
|
+
return {
|
|
1024
|
+
mute() {
|
|
1025
|
+
opts.queue.mute();
|
|
1026
|
+
},
|
|
1027
|
+
unmute() {
|
|
1028
|
+
opts.queue.unmute();
|
|
1029
|
+
},
|
|
1030
|
+
/** Toggle mute state. Returns the new muted state. */
|
|
1031
|
+
toggle() {
|
|
1032
|
+
if (opts.queue.isMuted()) {
|
|
1033
|
+
opts.queue.unmute();
|
|
1034
|
+
} else {
|
|
1035
|
+
opts.queue.mute();
|
|
1036
|
+
}
|
|
1037
|
+
return opts.queue.isMuted();
|
|
1038
|
+
},
|
|
1039
|
+
/** Interrupt the current utterance (and drop the pending queue). */
|
|
1040
|
+
stop() {
|
|
1041
|
+
opts.queue.stop();
|
|
1042
|
+
},
|
|
1043
|
+
isMuted() {
|
|
1044
|
+
return opts.queue.isMuted();
|
|
1045
|
+
},
|
|
1046
|
+
say(text) {
|
|
1047
|
+
opts.queue.push(makeRequest(text, 2 /* NORMAL */));
|
|
1048
|
+
},
|
|
1049
|
+
test() {
|
|
1050
|
+
opts.queue.push(
|
|
1051
|
+
makeRequest(
|
|
1052
|
+
"opencode voice test. If you hear this, audio is working.",
|
|
1053
|
+
2 /* NORMAL */
|
|
1054
|
+
)
|
|
1055
|
+
);
|
|
1056
|
+
},
|
|
1057
|
+
status() {
|
|
1058
|
+
return {
|
|
1059
|
+
provider: opts.providerName,
|
|
1060
|
+
voice: opts.voiceName,
|
|
1061
|
+
muted: opts.queue.isMuted(),
|
|
1062
|
+
queueSize: opts.queue.size()
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
// src/notify.ts
|
|
1069
|
+
var TOAST_MAX_LEN = 200;
|
|
1070
|
+
var TOAST_PREFIX = "opencode-speaker: ";
|
|
1071
|
+
var TOAST_DEFER_MS = 2500;
|
|
1072
|
+
var TOAST_DURATION_MS = 1e4;
|
|
1073
|
+
function buildMessage(summary) {
|
|
1074
|
+
const raw = TOAST_PREFIX + summary;
|
|
1075
|
+
if (raw.length <= TOAST_MAX_LEN) return raw;
|
|
1076
|
+
return raw.slice(0, TOAST_MAX_LEN - 1) + "\u2026";
|
|
1077
|
+
}
|
|
1078
|
+
async function showToastSafe(client, message, variant, logger) {
|
|
1079
|
+
const tui = client?.tui;
|
|
1080
|
+
if (!tui || typeof tui.showToast !== "function") {
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
try {
|
|
1084
|
+
await tui.showToast({
|
|
1085
|
+
body: { message, variant, duration: TOAST_DURATION_MS }
|
|
1086
|
+
});
|
|
1087
|
+
} catch (error) {
|
|
1088
|
+
void logger.debug("toast failed", {
|
|
1089
|
+
error,
|
|
1090
|
+
operation: "showing toast",
|
|
1091
|
+
input: { message, variant }
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
function tryShowToast(client, message, variant, logger) {
|
|
1096
|
+
setTimeout(() => void showToastSafe(client, message, variant, logger), TOAST_DEFER_MS);
|
|
1097
|
+
}
|
|
1098
|
+
function createNotifier(client, logger) {
|
|
1099
|
+
return {
|
|
1100
|
+
fatal(summary, detail) {
|
|
1101
|
+
void logger.error(summary, detail);
|
|
1102
|
+
tryShowToast(client, buildMessage(summary), "error", logger);
|
|
1103
|
+
},
|
|
1104
|
+
warn(summary, detail) {
|
|
1105
|
+
void logger.warn(summary, detail);
|
|
1106
|
+
tryShowToast(client, buildMessage(summary), "warning", logger);
|
|
1107
|
+
}
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// src/ai-sdk/credentials.ts
|
|
1112
|
+
var ENV_VAR_BY_PROVIDER = {
|
|
1113
|
+
openai: "OPENAI_API_KEY",
|
|
1114
|
+
anthropic: "ANTHROPIC_API_KEY",
|
|
1115
|
+
elevenlabs: "ELEVENLABS_API_KEY"
|
|
1116
|
+
};
|
|
1117
|
+
function requiredEnvVar(slug) {
|
|
1118
|
+
const slash = slug.indexOf("/");
|
|
1119
|
+
if (slash <= 0) return null;
|
|
1120
|
+
const provider = slug.slice(0, slash);
|
|
1121
|
+
return ENV_VAR_BY_PROVIDER[provider] ?? null;
|
|
1122
|
+
}
|
|
1123
|
+
function checkCredentials(check, env) {
|
|
1124
|
+
const required = /* @__PURE__ */ new Set();
|
|
1125
|
+
for (const slug of [check.narratorSlug, check.ttsSlug]) {
|
|
1126
|
+
const v = requiredEnvVar(slug);
|
|
1127
|
+
if (v) required.add(v);
|
|
1128
|
+
}
|
|
1129
|
+
const missing = [];
|
|
1130
|
+
for (const name of required) {
|
|
1131
|
+
const val = env[name];
|
|
1132
|
+
if (val === void 0 || val.trim().length === 0) missing.push(name);
|
|
1133
|
+
}
|
|
1134
|
+
missing.sort();
|
|
1135
|
+
return missing.length === 0 ? { ok: true } : { ok: false, missing };
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
// src/index.ts
|
|
1139
|
+
function formatSchemaErrors(errors) {
|
|
1140
|
+
const parts = errors.map((e) => e.path ? `${e.path}: ${e.message}` : e.message);
|
|
1141
|
+
return `invalid config \u2014 ${parts.join("; ")}`;
|
|
1142
|
+
}
|
|
1143
|
+
function oneLine(err) {
|
|
1144
|
+
const s = err instanceof Error ? err.message : String(err);
|
|
1145
|
+
return s.replace(/\s+/g, " ").trim();
|
|
1146
|
+
}
|
|
1147
|
+
var OpencodeSpeaker = async (ctx, options) => {
|
|
1148
|
+
try {
|
|
1149
|
+
return await initPlugin(ctx, options);
|
|
1150
|
+
} catch (err) {
|
|
1151
|
+
try {
|
|
1152
|
+
const logger = createLogger(ctx.client, PLUGIN_NAME).child({ module: "init" });
|
|
1153
|
+
const notifier = createNotifier(ctx.client, logger);
|
|
1154
|
+
notifier.fatal("failed to initialize; plugin disabled", {
|
|
1155
|
+
error: err,
|
|
1156
|
+
operation: "initializing plugin"
|
|
1157
|
+
});
|
|
1158
|
+
} catch {
|
|
1159
|
+
}
|
|
1160
|
+
return {};
|
|
1161
|
+
}
|
|
1162
|
+
};
|
|
1163
|
+
async function initPlugin(ctx, options) {
|
|
1164
|
+
const logger = createLogger(ctx.client, PLUGIN_NAME);
|
|
1165
|
+
const initLog = logger.child({ module: "init" });
|
|
1166
|
+
const dispatchLog = logger.child({ module: "dispatcher" });
|
|
1167
|
+
const queueLog = logger.child({ module: "queue" });
|
|
1168
|
+
const narratorLog = logger.child({ module: "narrator" });
|
|
1169
|
+
const audioLog = logger.child({ module: "audio" });
|
|
1170
|
+
const ttsLog = logger.child({ module: "tts" });
|
|
1171
|
+
const notifier = createNotifier(ctx.client, initLog);
|
|
1172
|
+
const config = loadConfig(options, notifier);
|
|
1173
|
+
if (!config) {
|
|
1174
|
+
return {};
|
|
1175
|
+
}
|
|
1176
|
+
if (!config.enabled) {
|
|
1177
|
+
await initLog.info(`${PLUGIN_NAME} disabled by config or env`, {
|
|
1178
|
+
operation: "starting plugin"
|
|
1179
|
+
});
|
|
1180
|
+
return {};
|
|
1181
|
+
}
|
|
1182
|
+
const models = resolveModelsOrDisable(config, notifier);
|
|
1183
|
+
if (!models) {
|
|
1184
|
+
return {};
|
|
1185
|
+
}
|
|
1186
|
+
const { languageModel, resolvedSpeech } = models;
|
|
1187
|
+
const credCheck = checkCredentials(
|
|
1188
|
+
{ narratorSlug: config.narrator.model, ttsSlug: config.tts.model },
|
|
1189
|
+
process.env
|
|
1190
|
+
);
|
|
1191
|
+
if (!credCheck.ok) {
|
|
1192
|
+
notifier.fatal(
|
|
1193
|
+
`${credCheck.missing.join(", ")} not set; plugin disabled`,
|
|
1194
|
+
{
|
|
1195
|
+
operation: "checking provider credentials",
|
|
1196
|
+
input: { missing: credCheck.missing }
|
|
1197
|
+
}
|
|
1198
|
+
);
|
|
1199
|
+
return {};
|
|
1200
|
+
}
|
|
1201
|
+
const provider = createAiSdkProvider({
|
|
1202
|
+
model: resolvedSpeech.model,
|
|
1203
|
+
provider: resolvedSpeech.provider,
|
|
1204
|
+
voice: config.tts.voice
|
|
1205
|
+
});
|
|
1206
|
+
const player = await initPlayer(audioLog);
|
|
1207
|
+
const ttsConfig = config.tts;
|
|
1208
|
+
async function speak(req, signal) {
|
|
1209
|
+
if (!player) return;
|
|
1210
|
+
const result = await provider.synthesize(
|
|
1211
|
+
req.text,
|
|
1212
|
+
{
|
|
1213
|
+
voice: ttsConfig.voice,
|
|
1214
|
+
rate: ttsConfig.rate
|
|
1215
|
+
},
|
|
1216
|
+
signal
|
|
1217
|
+
);
|
|
1218
|
+
await player.play(result.audio, result.contentType, signal);
|
|
1219
|
+
}
|
|
1220
|
+
const queue = new SpeechQueue({
|
|
1221
|
+
speak,
|
|
1222
|
+
staleMs: config.queue.staleMs,
|
|
1223
|
+
now: () => Date.now(),
|
|
1224
|
+
logger: queueLog,
|
|
1225
|
+
onError: (err, req) => {
|
|
1226
|
+
void queueLog.warn("speak failed", {
|
|
1227
|
+
error: err,
|
|
1228
|
+
operation: "speaking queued request",
|
|
1229
|
+
input: { textPreview: req.text.slice(0, 80), priority: req.priority }
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
});
|
|
1233
|
+
const narrator = createNarrator(languageModel, config.narrator, narratorLog);
|
|
1234
|
+
const dispatcher = createDispatcher({
|
|
1235
|
+
logger: dispatchLog,
|
|
1236
|
+
handler: createHandlerRegistry({
|
|
1237
|
+
events: config.events,
|
|
1238
|
+
narrator,
|
|
1239
|
+
getContext: () => dispatcher.getContext()
|
|
1240
|
+
}),
|
|
1241
|
+
queue,
|
|
1242
|
+
onError: (err, e) => {
|
|
1243
|
+
void dispatchLog.warn("handler error at boundary", {
|
|
1244
|
+
error: err,
|
|
1245
|
+
operation: "dispatcher onError boundary",
|
|
1246
|
+
input: { eventType: e.type }
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
});
|
|
1250
|
+
const commands = createCommands({
|
|
1251
|
+
queue,
|
|
1252
|
+
providerName: resolvedSpeech.provider,
|
|
1253
|
+
voiceName: config.tts.voice
|
|
1254
|
+
});
|
|
1255
|
+
if (config.startMuted) commands.mute();
|
|
1256
|
+
await initLog.info(`${PLUGIN_NAME} ready`, {
|
|
1257
|
+
operation: "plugin ready",
|
|
1258
|
+
input: { provider: resolvedSpeech.provider, voice: config.tts.voice }
|
|
1259
|
+
});
|
|
1260
|
+
if (config.greeting.trim().length > 0 && !config.startMuted) {
|
|
1261
|
+
commands.say(config.greeting);
|
|
1262
|
+
}
|
|
1263
|
+
return {
|
|
1264
|
+
event: async ({
|
|
1265
|
+
event
|
|
1266
|
+
}) => {
|
|
1267
|
+
try {
|
|
1268
|
+
await dispatcher.onEvent(event);
|
|
1269
|
+
} catch (err) {
|
|
1270
|
+
await dispatchLog.warn("event handler crashed", {
|
|
1271
|
+
error: err,
|
|
1272
|
+
operation: "dispatching opencode event",
|
|
1273
|
+
input: { eventType: event.type }
|
|
1274
|
+
});
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
function loadConfig(options, notifier) {
|
|
1280
|
+
const parsed = parseConfig(options ?? {});
|
|
1281
|
+
if (!parsed.ok) {
|
|
1282
|
+
notifier.fatal(formatSchemaErrors(parsed.errors), {
|
|
1283
|
+
operation: "parsing plugin config",
|
|
1284
|
+
input: { errors: parsed.errors }
|
|
1285
|
+
});
|
|
1286
|
+
return null;
|
|
1287
|
+
}
|
|
1288
|
+
return parsed.config;
|
|
1289
|
+
}
|
|
1290
|
+
function resolveModelsOrDisable(config, notifier) {
|
|
1291
|
+
try {
|
|
1292
|
+
return {
|
|
1293
|
+
languageModel: resolveLanguageModel(config.narrator.model),
|
|
1294
|
+
resolvedSpeech: resolveSpeechModel(config.tts.model)
|
|
1295
|
+
};
|
|
1296
|
+
} catch (err) {
|
|
1297
|
+
const summary = err instanceof ConfigError ? `invalid model slug \u2014 ${err.message}` : `failed to resolve models \u2014 ${oneLine(err)}`;
|
|
1298
|
+
notifier.fatal(summary, {
|
|
1299
|
+
error: err,
|
|
1300
|
+
operation: "resolving model slugs",
|
|
1301
|
+
input: { narrator: config.narrator.model, tts: config.tts.model }
|
|
1302
|
+
});
|
|
1303
|
+
return null;
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
async function initPlayer(audioLog) {
|
|
1307
|
+
try {
|
|
1308
|
+
const runner = await defaultRunner();
|
|
1309
|
+
const player = createPlayer({ runner });
|
|
1310
|
+
await player.init();
|
|
1311
|
+
return player;
|
|
1312
|
+
} catch (err) {
|
|
1313
|
+
await audioLog.warn("Audio player unavailable; speech output disabled", {
|
|
1314
|
+
error: err,
|
|
1315
|
+
operation: "initializing audio player",
|
|
1316
|
+
input: { platform: process.platform }
|
|
1317
|
+
});
|
|
1318
|
+
return null;
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
var index_default = OpencodeSpeaker;
|
|
1322
|
+
export {
|
|
1323
|
+
OpencodeSpeaker,
|
|
1324
|
+
index_default as default
|
|
1325
|
+
};
|
|
1326
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL2luZGV4LnRzIiwgIi4uL3NyYy9jb25maWcudHMiLCAiLi4vc3JjL2FpLXNkay9tb2RlbHMudHMiLCAiLi4vc3JjL2V2ZW50cy9jYXRhbG9nLnRzIiwgIi4uL3NyYy9sb2cudHMiLCAiLi4vc3JjL3F1ZXVlL3NwZWVjaC1xdWV1ZS50cyIsICIuLi9zcmMvdHRzL2FpLXNkay50cyIsICIuLi9zcmMvYXVkaW8vcGxheWVyLnRzIiwgIi4uL3NyYy9hdWRpby9ydW5uZXIudHMiLCAiLi4vc3JjL2hhbmRsZXJzL2luZGV4LnRzIiwgIi4uL3NyYy9oYW5kbGVycy90ZW1wbGF0ZS50cyIsICIuLi9zcmMvaGFuZGxlcnMvbmFycmF0b3IudHMiLCAiLi4vc3JjL2V2ZW50cy9ub3JtYWxpemUudHMiLCAiLi4vc3JjL2Rpc3BhdGNoZXIudHMiLCAiLi4vc3JjL2NvbW1hbmRzL2luZGV4LnRzIiwgIi4uL3NyYy9ub3RpZnkudHMiLCAiLi4vc3JjL2FpLXNkay9jcmVkZW50aWFscy50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiaW1wb3J0IFwic291cmNlLW1hcC1zdXBwb3J0L3JlZ2lzdGVyLmpzXCJcbmltcG9ydCB7IHBhcnNlQ29uZmlnLCBQTFVHSU5fTkFNRSwgdHlwZSBWb2ljZUNvbmZpZyB9IGZyb20gXCIuL2NvbmZpZy5qc1wiXG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIsIHR5cGUgTG9nZ2VyIH0gZnJvbSBcIi4vbG9nLmpzXCJcbmltcG9ydCB7IFNwZWVjaFF1ZXVlIH0gZnJvbSBcIi4vcXVldWUvc3BlZWNoLXF1ZXVlLmpzXCJcbmltcG9ydCB7IHR5cGUgU3BlZWNoUmVxdWVzdCB9IGZyb20gXCIuL3F1ZXVlL3R5cGVzLmpzXCJcbmltcG9ydCB7IGNyZWF0ZUFpU2RrUHJvdmlkZXIgfSBmcm9tIFwiLi90dHMvYWktc2RrLmpzXCJcbmltcG9ydCB7IGNyZWF0ZVBsYXllciwgdHlwZSBQbGF5ZXIgfSBmcm9tIFwiLi9hdWRpby9wbGF5ZXIuanNcIlxuaW1wb3J0IHsgZGVmYXVsdFJ1bm5lciB9IGZyb20gXCIuL2F1ZGlvL3J1bm5lci5qc1wiXG5pbXBvcnQgeyBjcmVhdGVIYW5kbGVyUmVnaXN0cnkgfSBmcm9tIFwiLi9oYW5kbGVyc1wiXG5pbXBvcnQgeyBjcmVhdGVOYXJyYXRvciB9IGZyb20gXCIuL2hhbmRsZXJzL25hcnJhdG9yLmpzXCJcbmltcG9ydCB7XG4gIHJlc29sdmVMYW5ndWFnZU1vZGVsLFxuICByZXNvbHZlU3BlZWNoTW9kZWwsXG4gIENvbmZpZ0Vycm9yLFxufSBmcm9tIFwiLi9haS1zZGsvbW9kZWxzLmpzXCJcbmltcG9ydCB7IGNyZWF0ZURpc3BhdGNoZXIgfSBmcm9tIFwiLi9kaXNwYXRjaGVyLmpzXCJcbmltcG9ydCB7IGNyZWF0ZUNvbW1hbmRzIH0gZnJvbSBcIi4vY29tbWFuZHNcIlxuaW1wb3J0IHsgY3JlYXRlTm90aWZpZXIgfSBmcm9tIFwiLi9ub3RpZnkuanNcIlxuaW1wb3J0IHsgY2hlY2tDcmVkZW50aWFscyB9IGZyb20gXCIuL2FpLXNkay9jcmVkZW50aWFscy5qc1wiXG5cbi8vIElNUE9SVEFOVDogZG8gbm90IHJlLWV4cG9ydCBhbnl0aGluZyB0aGF0IG9wZW5jb2RlJ3MgcGx1Z2luIGxvYWRlciBtaWdodFxuLy8gbWlzdGFrZSBmb3IgYSBzZXJ2ZXIgcGx1Z2luLiBUaGUgbG9hZGVyIHVzZXMgdGhlIHYxIGRlZmF1bHQtZXhwb3J0IGNvbnRyYWN0XG4vLyBgeyBpZCwgc2VydmVyIH1gIChzZWUgYGRlZmF1bHRgIGJlbG93KSBcdTIwMTQgdGhhdCBwYXRoIHNraXBzIHRoZSBsZWdhY3kgc2NhblxuLy8gdGhhdCB3b3VsZCBvdGhlcndpc2UgaXRlcmF0ZSBldmVyeSBtb2R1bGUgZXhwb3J0LiBQdXR0aW5nIHB1YmxpYyBBUElcbi8vIChyZWdpc3RlclByb3ZpZGVyLCB0eXBlcykgaGVyZSB3b3VsZCBwdXQgdGhlbSBpbiBgT2JqZWN0LnZhbHVlcyhtb2QpYCBhbmRcbi8vIGNvdWxkIGJyZWFrIG9sZGVyIGxvYWRlcnMuIFRoZXkgbGl2ZSBpbiBgLi9hcGkudHNgIGluc3RlYWQuXG5cbnR5cGUgUGx1Z2luQ3R4ID0ge1xuICBjbGllbnQ6IHtcbiAgICBhcHA6IHsgbG9nOiAoLi4uYXJnczogYW55W10pID0+IFByb21pc2U8dW5rbm93bj4gfVxuICB9XG4gIGRpcmVjdG9yeTogc3RyaW5nXG4gIHdvcmt0cmVlPzogc3RyaW5nXG4gIHByb2plY3Q/OiB1bmtub3duXG4gICQ6IHVua25vd25cbn1cblxudHlwZSBQbHVnaW5PcHRpb25zID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWRcbnR5cGUgTm90aWZpZXIgPSBSZXR1cm5UeXBlPHR5cGVvZiBjcmVhdGVOb3RpZmllcj5cblxuZnVuY3Rpb24gZm9ybWF0U2NoZW1hRXJyb3JzKGVycm9yczogeyBwYXRoOiBzdHJpbmc7IG1lc3NhZ2U6IHN0cmluZyB9W10pOiBzdHJpbmcge1xuICBjb25zdCBwYXJ0cyA9IGVycm9ycy5tYXAoKGUpID0+IChlLnBhdGggPyBgJHtlLnBhdGh9OiAke2UubWVzc2FnZX1gIDogZS5tZXNzYWdlKSlcbiAgcmV0dXJuIGBpbnZhbGlkIGNvbmZpZyBcdTIwMTQgJHtwYXJ0cy5qb2luKFwiOyBcIil9YFxufVxuXG5mdW5jdGlvbiBvbmVMaW5lKGVycjogdW5rbm93bik6IHN0cmluZyB7XG4gIGNvbnN0IHMgPSBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogU3RyaW5nKGVycilcbiAgcmV0dXJuIHMucmVwbGFjZSgvXFxzKy9nLCBcIiBcIikudHJpbSgpXG59XG5cbmV4cG9ydCBjb25zdCBPcGVuY29kZVNwZWFrZXIgPSBhc3luYyAoY3R4OiBQbHVnaW5DdHgsIG9wdGlvbnM/OiBQbHVnaW5PcHRpb25zKSA9PiB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIGF3YWl0IGluaXRQbHVnaW4oY3R4LCBvcHRpb25zKVxuICB9IGNhdGNoIChlcnIpIHtcbiAgICAvLyBMYXN0LWxpbmUtb2YtZGVmZW5zZTogbmV2ZXIgbGV0IHBsdWdpbiBmYWlsdXJlIGNyYXNoIG9wZW5jb2RlIHN0YXJ0dXAuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcihjdHguY2xpZW50IGFzIGFueSwgUExVR0lOX05BTUUpLmNoaWxkKHsgbW9kdWxlOiBcImluaXRcIiB9KVxuICAgICAgY29uc3Qgbm90aWZpZXIgPSBjcmVhdGVOb3RpZmllcihjdHguY2xpZW50IGFzIGFueSwgbG9nZ2VyKVxuICAgICAgbm90aWZpZXIuZmF0YWwoXCJmYWlsZWQgdG8gaW5pdGlhbGl6ZTsgcGx1Z2luIGRpc2FibGVkXCIsIHtcbiAgICAgICAgZXJyb3I6IGVycixcbiAgICAgICAgb3BlcmF0aW9uOiBcImluaXRpYWxpemluZyBwbHVnaW5cIixcbiAgICAgIH0pXG4gICAgfSBjYXRjaCB7XG4gICAgICAvKiBsb2dnZXIvbm90aWZpZXIgaXRzZWxmIGZhaWxlZDsgbm90aGluZyB3ZSBjYW4gc2FmZWx5IGRvICovXG4gICAgfVxuICAgIHJldHVybiB7fVxuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGluaXRQbHVnaW4oY3R4OiBQbHVnaW5DdHgsIG9wdGlvbnM/OiBQbHVnaW5PcHRpb25zKSB7XG4gIGNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcihjdHguY2xpZW50IGFzIGFueSwgUExVR0lOX05BTUUpXG4gIGNvbnN0IGluaXRMb2cgICAgID0gbG9nZ2VyLmNoaWxkKHsgbW9kdWxlOiBcImluaXRcIiB9KVxuICBjb25zdCBkaXNwYXRjaExvZyA9IGxvZ2dlci5jaGlsZCh7IG1vZHVsZTogXCJkaXNwYXRjaGVyXCIgfSlcbiAgY29uc3QgcXVldWVMb2cgICAgPSBsb2dnZXIuY2hpbGQoeyBtb2R1bGU6IFwicXVldWVcIiB9KVxuICBjb25zdCBuYXJyYXRvckxvZyA9IGxvZ2dlci5jaGlsZCh7IG1vZHVsZTogXCJuYXJyYXRvclwiIH0pXG4gIGNvbnN0IGF1ZGlvTG9nICAgID0gbG9nZ2VyLmNoaWxkKHsgbW9kdWxlOiBcImF1ZGlvXCIgfSlcbiAgY29uc3QgdHRzTG9nICAgICAgPSBsb2dnZXIuY2hpbGQoeyBtb2R1bGU6IFwidHRzXCIgfSlcbiAgY29uc3Qgbm90aWZpZXIgPSBjcmVhdGVOb3RpZmllcihjdHguY2xpZW50IGFzIGFueSwgaW5pdExvZylcbiAgLy8gb3BlbmNvZGUgcGFzc2VzIHBlci1wbHVnaW4gY29uZmlnIGFzIHRoZSBzZWNvbmQgYXJndW1lbnQgd2hlbiB0aGUgdXNlclxuICAvLyBkZWNsYXJlcyB0aGUgcGx1Z2luIGluIHR1cGxlIGZvcm06IFtcIm9wZW5jb2RlLXNwZWFrZXJcIiwgeyAuLi5vcHRpb25zIH1dLlxuICAvLyBXZSBhY2NlcHQgYW55IHVzZXIgb2JqZWN0IGFuZCBsZXQgcGFyc2VDb25maWcgdmFsaWRhdGUgKyBhcHBseSBkZWZhdWx0cy5cbiAgY29uc3QgY29uZmlnID0gbG9hZENvbmZpZyhvcHRpb25zLCBub3RpZmllcilcbiAgaWYgKCFjb25maWcpIHtcbiAgICByZXR1cm4ge31cbiAgfVxuXG4gIGlmICghY29uZmlnLmVuYWJsZWQpIHtcbiAgICBhd2FpdCBpbml0TG9nLmluZm8oYCR7UExVR0lOX05BTUV9IGRpc2FibGVkIGJ5IGNvbmZpZyBvciBlbnZgLCB7XG4gICAgICBvcGVyYXRpb246IFwic3RhcnRpbmcgcGx1Z2luXCIsXG4gICAgfSlcbiAgICByZXR1cm4ge31cbiAgfVxuXG4gIC8vIDEuIFJlc29sdmUgbmFycmF0b3IgKyBUVFMgbW9kZWxzIGZyb20gY29uZmlnIHNsdWdzLlxuICBjb25zdCBtb2RlbHMgPSByZXNvbHZlTW9kZWxzT3JEaXNhYmxlKGNvbmZpZywgbm90aWZpZXIpXG4gIGlmICghbW9kZWxzKSB7XG4gICAgcmV0dXJuIHt9XG4gIH1cbiAgY29uc3QgeyBsYW5ndWFnZU1vZGVsLCByZXNvbHZlZFNwZWVjaCB9ID0gbW9kZWxzXG5cbiAgY29uc3QgY3JlZENoZWNrID0gY2hlY2tDcmVkZW50aWFscyhcbiAgICB7IG5hcnJhdG9yU2x1ZzogY29uZmlnLm5hcnJhdG9yLm1vZGVsLCB0dHNTbHVnOiBjb25maWcudHRzLm1vZGVsIH0sXG4gICAgcHJvY2Vzcy5lbnYsXG4gIClcbiAgaWYgKCFjcmVkQ2hlY2sub2spIHtcbiAgICBub3RpZmllci5mYXRhbChcbiAgICAgIGAke2NyZWRDaGVjay5taXNzaW5nLmpvaW4oXCIsIFwiKX0gbm90IHNldDsgcGx1Z2luIGRpc2FibGVkYCxcbiAgICAgIHtcbiAgICAgICAgb3BlcmF0aW9uOiBcImNoZWNraW5nIHByb3ZpZGVyIGNyZWRlbnRpYWxzXCIsXG4gICAgICAgIGlucHV0OiB7IG1pc3Npbmc6IGNyZWRDaGVjay5taXNzaW5nIH0sXG4gICAgICB9LFxuICAgIClcbiAgICByZXR1cm4ge31cbiAgfVxuXG4gIC8vIDIuIEJ1aWxkIHRoZSBBSSBTREsgVFRTIHByb3ZpZGVyLlxuICBjb25zdCBwcm92aWRlciA9IGNyZWF0ZUFpU2RrUHJvdmlkZXIoe1xuICAgIG1vZGVsOiByZXNvbHZlZFNwZWVjaC5tb2RlbCxcbiAgICBwcm92aWRlcjogcmVzb2x2ZWRTcGVlY2gucHJvdmlkZXIsXG4gICAgdm9pY2U6IGNvbmZpZy50dHMudm9pY2UsXG4gIH0pXG5cbiAgLy8gMy4gU2V0IHVwIGF1ZGlvIHBsYXllci4gVGhlIEFJIFNESyBwcm92aWRlciByZXR1cm5zIHJhdyBhdWRpbyBieXRlcyB0aGF0XG4gIC8vIHdlIG5lZWQgdG8gaGFuZCBvZmYgdG8gdGhlIE9TJ3MgYXVkaW8gcGxheWJhY2sgYmluYXJ5LlxuICBjb25zdCBwbGF5ZXIgPSBhd2FpdCBpbml0UGxheWVyKGF1ZGlvTG9nKVxuXG4gIC8vIDQuIEJ1aWxkIHRoZSBzcGVhayBmdW5jdGlvbiB1c2VkIGJ5IHRoZSBxdWV1ZS5cbiAgY29uc3QgdHRzQ29uZmlnID0gY29uZmlnLnR0c1xuICBhc3luYyBmdW5jdGlvbiBzcGVhayhyZXE6IFNwZWVjaFJlcXVlc3QsIHNpZ25hbDogQWJvcnRTaWduYWwpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXBsYXllcikgcmV0dXJuXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHJvdmlkZXIuc3ludGhlc2l6ZShcbiAgICAgIHJlcS50ZXh0LFxuICAgICAge1xuICAgICAgICB2b2ljZTogdHRzQ29uZmlnLnZvaWNlLFxuICAgICAgICByYXRlOiB0dHNDb25maWcucmF0ZSxcbiAgICAgIH0sXG4gICAgICBzaWduYWwsXG4gICAgKVxuICAgIGF3YWl0IHBsYXllci5wbGF5KHJlc3VsdC5hdWRpbywgcmVzdWx0LmNvbnRlbnRUeXBlLCBzaWduYWwpXG4gIH1cblxuICAvLyA1LiBXaXJlIHF1ZXVlLlxuICBjb25zdCBxdWV1ZSA9IG5ldyBTcGVlY2hRdWV1ZSh7XG4gICAgc3BlYWssXG4gICAgc3RhbGVNczogY29uZmlnLnF1ZXVlLnN0YWxlTXMsXG4gICAgbm93OiAoKSA9PiBEYXRlLm5vdygpLFxuICAgIGxvZ2dlcjogcXVldWVMb2csXG4gICAgb25FcnJvcjogKGVyciwgcmVxKSA9PiB7XG4gICAgICB2b2lkIHF1ZXVlTG9nLndhcm4oXCJzcGVhayBmYWlsZWRcIiwge1xuICAgICAgICBlcnJvcjogZXJyLFxuICAgICAgICBvcGVyYXRpb246IFwic3BlYWtpbmcgcXVldWVkIHJlcXVlc3RcIixcbiAgICAgICAgaW5wdXQ6IHsgdGV4dFByZXZpZXc6IHJlcS50ZXh0LnNsaWNlKDAsIDgwKSwgcHJpb3JpdHk6IHJlcS5wcmlvcml0eSB9LFxuICAgICAgfSlcbiAgICB9LFxuICB9KVxuXG4gIC8vIDYuIE5hcnJhdG9yICsgaGFuZGxlciByZWdpc3RyeS5cbiAgY29uc3QgbmFycmF0b3IgPSBjcmVhdGVOYXJyYXRvcihsYW5ndWFnZU1vZGVsLCBjb25maWcubmFycmF0b3IsIG5hcnJhdG9yTG9nKVxuXG4gIGNvbnN0IGRpc3BhdGNoZXIgPSBjcmVhdGVEaXNwYXRjaGVyKHtcbiAgICBsb2dnZXI6IGRpc3BhdGNoTG9nLFxuICAgIGhhbmRsZXI6IGNyZWF0ZUhhbmRsZXJSZWdpc3RyeSh7XG4gICAgICBldmVudHM6IGNvbmZpZy5ldmVudHMgYXMgYW55LFxuICAgICAgbmFycmF0b3IsXG4gICAgICBnZXRDb250ZXh0OiAoKSA9PiBkaXNwYXRjaGVyLmdldENvbnRleHQoKSxcbiAgICB9KSxcbiAgICBxdWV1ZSxcbiAgICBvbkVycm9yOiAoZXJyLCBlKSA9PiB7XG4gICAgICB2b2lkIGRpc3BhdGNoTG9nLndhcm4oXCJoYW5kbGVyIGVycm9yIGF0IGJvdW5kYXJ5XCIsIHtcbiAgICAgICAgZXJyb3I6IGVycixcbiAgICAgICAgb3BlcmF0aW9uOiBcImRpc3BhdGNoZXIgb25FcnJvciBib3VuZGFyeVwiLFxuICAgICAgICBpbnB1dDogeyBldmVudFR5cGU6IGUudHlwZSB9LFxuICAgICAgfSlcbiAgICB9LFxuICB9KVxuXG4gIC8vIDcuIENvbW1hbmRzICsgY3VzdG9tIHRvb2wuXG4gIGNvbnN0IGNvbW1hbmRzID0gY3JlYXRlQ29tbWFuZHMoe1xuICAgIHF1ZXVlLFxuICAgIHByb3ZpZGVyTmFtZTogcmVzb2x2ZWRTcGVlY2gucHJvdmlkZXIsXG4gICAgdm9pY2VOYW1lOiBjb25maWcudHRzLnZvaWNlLFxuICB9KVxuICBpZiAoY29uZmlnLnN0YXJ0TXV0ZWQpIGNvbW1hbmRzLm11dGUoKVxuXG4gIGF3YWl0IGluaXRMb2cuaW5mbyhgJHtQTFVHSU5fTkFNRX0gcmVhZHlgLCB7XG4gICAgb3BlcmF0aW9uOiBcInBsdWdpbiByZWFkeVwiLFxuICAgIGlucHV0OiB7IHByb3ZpZGVyOiByZXNvbHZlZFNwZWVjaC5wcm92aWRlciwgdm9pY2U6IGNvbmZpZy50dHMudm9pY2UgfSxcbiAgfSlcblxuICBpZiAoY29uZmlnLmdyZWV0aW5nLnRyaW0oKS5sZW5ndGggPiAwICYmICFjb25maWcuc3RhcnRNdXRlZCkge1xuICAgIGNvbW1hbmRzLnNheShjb25maWcuZ3JlZXRpbmcpXG4gIH1cblxuICByZXR1cm4ge1xuICAgIGV2ZW50OiBhc3luYyAoe1xuICAgICAgZXZlbnQsXG4gICAgfToge1xuICAgICAgZXZlbnQ6IHsgdHlwZTogc3RyaW5nOyBbazogc3RyaW5nXTogdW5rbm93biB9XG4gICAgfSkgPT4ge1xuICAgICAgLy8gVGhlIGRpc3BhdGNoZXIgaXMgdGhlIHNpbmdsZSBlbnRyeSBwb2ludDogaXQga25vd3MgaG93IHRvIHVud3JhcFxuICAgICAgLy8gT3BlbkNvZGUncyBgeyBpZCwgdHlwZSwgcHJvcGVydGllcyB9YCBzaGFwZSwgZmFuIG91dCBzeW50aGVzaXplZFxuICAgICAgLy8gZXZlbnRzICh0b2RvLmNvbXBsZXRlZC4qLCBtZXNzYWdlLnJlYXNvbmluZy5kZWx0YSwgbWVzc2FnZS50ZXh0LmRlbHRhKSxcbiAgICAgIC8vIGFuZCBrZWVwIG5hcnJhdGlvbiBjb250ZXh0IGZyZXNoLlxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgZGlzcGF0Y2hlci5vbkV2ZW50KGV2ZW50KVxuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGF3YWl0IGRpc3BhdGNoTG9nLndhcm4oXCJldmVudCBoYW5kbGVyIGNyYXNoZWRcIiwge1xuICAgICAgICAgIGVycm9yOiBlcnIsXG4gICAgICAgICAgb3BlcmF0aW9uOiBcImRpc3BhdGNoaW5nIG9wZW5jb2RlIGV2ZW50XCIsXG4gICAgICAgICAgaW5wdXQ6IHsgZXZlbnRUeXBlOiBldmVudC50eXBlIH0sXG4gICAgICAgIH0pXG4gICAgICB9XG4gICAgfSxcbiAgfVxufVxuXG5mdW5jdGlvbiBsb2FkQ29uZmlnKG9wdGlvbnM6IFBsdWdpbk9wdGlvbnMsIG5vdGlmaWVyOiBOb3RpZmllcik6IFZvaWNlQ29uZmlnIHwgbnVsbCB7XG4gIGNvbnN0IHBhcnNlZCA9IHBhcnNlQ29uZmlnKG9wdGlvbnMgPz8ge30pXG5cbiAgaWYgKCFwYXJzZWQub2spIHtcbiAgICBub3RpZmllci5mYXRhbChmb3JtYXRTY2hlbWFFcnJvcnMocGFyc2VkLmVycm9ycyksIHtcbiAgICAgIG9wZXJhdGlvbjogXCJwYXJzaW5nIHBsdWdpbiBjb25maWdcIixcbiAgICAgIGlucHV0OiB7IGVycm9yczogcGFyc2VkLmVycm9ycyB9LFxuICAgIH0pXG4gICAgcmV0dXJuIG51bGxcbiAgfVxuXG4gIHJldHVybiBwYXJzZWQuY29uZmlnXG59XG5cbmZ1bmN0aW9uIHJlc29sdmVNb2RlbHNPckRpc2FibGUoY29uZmlnOiBWb2ljZUNvbmZpZywgbm90aWZpZXI6IE5vdGlmaWVyKSB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGxhbmd1YWdlTW9kZWw6IHJlc29sdmVMYW5ndWFnZU1vZGVsKGNvbmZpZy5uYXJyYXRvci5tb2RlbCksXG4gICAgICByZXNvbHZlZFNwZWVjaDogcmVzb2x2ZVNwZWVjaE1vZGVsKGNvbmZpZy50dHMubW9kZWwpLFxuICAgIH1cbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgY29uc3Qgc3VtbWFyeSA9IGVyciBpbnN0YW5jZW9mIENvbmZpZ0Vycm9yXG4gICAgICA/IGBpbnZhbGlkIG1vZGVsIHNsdWcgXHUyMDE0ICR7ZXJyLm1lc3NhZ2V9YFxuICAgICAgOiBgZmFpbGVkIHRvIHJlc29sdmUgbW9kZWxzIFx1MjAxNCAke29uZUxpbmUoZXJyKX1gXG4gICAgbm90aWZpZXIuZmF0YWwoc3VtbWFyeSwge1xuICAgICAgZXJyb3I6IGVycixcbiAgICAgIG9wZXJhdGlvbjogXCJyZXNvbHZpbmcgbW9kZWwgc2x1Z3NcIixcbiAgICAgIGlucHV0OiB7IG5hcnJhdG9yOiBjb25maWcubmFycmF0b3IubW9kZWwsIHR0czogY29uZmlnLnR0cy5tb2RlbCB9LFxuICAgIH0pXG4gICAgcmV0dXJuIG51bGxcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBpbml0UGxheWVyKGF1ZGlvTG9nOiBMb2dnZXIpOiBQcm9taXNlPFBsYXllciB8IG51bGw+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBydW5uZXIgPSBhd2FpdCBkZWZhdWx0UnVubmVyKClcbiAgICBjb25zdCBwbGF5ZXIgPSBjcmVhdGVQbGF5ZXIoeyBydW5uZXIgfSlcbiAgICBhd2FpdCBwbGF5ZXIuaW5pdCgpXG4gICAgcmV0dXJuIHBsYXllclxuICB9IGNhdGNoIChlcnIpIHtcbiAgICBhd2FpdCBhdWRpb0xvZy53YXJuKFwiQXVkaW8gcGxheWVyIHVuYXZhaWxhYmxlOyBzcGVlY2ggb3V0cHV0IGRpc2FibGVkXCIsIHtcbiAgICAgIGVycm9yOiBlcnIsXG4gICAgICBvcGVyYXRpb246IFwiaW5pdGlhbGl6aW5nIGF1ZGlvIHBsYXllclwiLFxuICAgICAgaW5wdXQ6IHsgcGxhdGZvcm06IHByb2Nlc3MucGxhdGZvcm0gfSxcbiAgICB9KVxuICAgIHJldHVybiBudWxsXG4gIH1cbn1cblxuLyoqXG4gKiBEZWZhdWx0IGV4cG9ydCBpcyB0aGUgcGx1Z2luIGZ1bmN0aW9uIGl0c2VsZiwgbWF0Y2hpbmcgdGhlIGN1cnJlbnRcbiAqIGBAb3BlbmNvZGUtYWkvcGx1Z2luYCBjb250cmFjdCAoc2VlIEV4YW1wbGVQbHVnaW4gLyBGb2xkZXJXb3Jrc3BhY2VQbHVnaW4pLlxuICpcbiAqIEhpc3Rvcnk6IHRoaXMgdXNlZCB0byBiZSBgeyBpZCwgc2VydmVyOiBPcGVuY29kZVNwZWFrZXIgfWAgdG8gc2F0aXNmeSBhblxuICogb2xkZXIgXCJ2MVwiIGxvYWRlciBzaGFwZS4gTmV3ZXIgb3BlbmNvZGUgcmVsZWFzZXMgcmVqZWN0IHRoYXQgYXNcbiAqIFwiZG9lcyBub3QgZXhwb3NlIGEgc2VydmVyIGVudHJ5cG9pbnRcIiBcdTIwMTQgdGhlIGxvYWRlciBleHBlY3RzIHRoZSBkZWZhdWx0XG4gKiBleHBvcnQgdG8gYmUgdGhlIGFzeW5jIHBsdWdpbiBmdW5jdGlvbiBkaXJlY3RseS5cbiAqXG4gKiBgaW5kZXgudHNgIGRlbGliZXJhdGVseSBoYXMgbm8gb3RoZXIgZXhwb3J0cyBiZXlvbmQgYE9wZW5jb2RlU3BlYWtlcmAgYW5kXG4gKiB0aGlzIGRlZmF1bHQsIHNvIHRoZSBsb2FkZXIncyBuYW1lZC1leHBvcnQgc2NhbiAoaWYgYW55KSBkb2VzIG5vdCBpbnZva2VcbiAqIGEgc2Vjb25kIHBsdWdpbiBpbnN0YW5jZS4gUHVibGljIEFQSSBsaXZlcyBpbiBgLi9hcGkudHNgLlxuICovXG5leHBvcnQgZGVmYXVsdCBPcGVuY29kZVNwZWFrZXJcbiIsICJpbXBvcnQgeyB6IH0gZnJvbSBcInpvZFwiXG5pbXBvcnQgeyBTTFVHX1JFIH0gZnJvbSBcIi4vYWktc2RrL21vZGVscy5qc1wiXG5pbXBvcnQgeyBkZWZhdWx0RXZlbnRzRm9yVmVyYm9zaXR5LCB0eXBlIFZlcmJvc2l0eSB9IGZyb20gXCIuL2V2ZW50cy9jYXRhbG9nLmpzXCJcblxuLyoqIFBsdWdpbiBpZGVudGl0eS4gVXNlZCBhcyB0aGUgbG9nIHNjb3BlLCB0bXBkaXIgcHJlZml4LCBhbmQgZXJyb3IgbGFiZWxzLiAqL1xuZXhwb3J0IGNvbnN0IFBMVUdJTl9OQU1FID0gXCJvcGVuY29kZS1zcGVha2VyXCJcblxuLyoqIERlZmF1bHQgVFRTIG1vZGVsIHNsdWcgKHVzZWQgYnkgc2NoZW1hICsgdGVzdHMgKyBkZW1vIHNjcmlwdHMpLiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfVFRTX01PREVMID0gXCJvcGVuYWkvZ3B0LTRvLW1pbmktdHRzXCJcblxuLyoqIERlZmF1bHQgbmFycmF0b3IgKExMTSkgbW9kZWwgc2x1Zy4gKi9cbmV4cG9ydCBjb25zdCBERUZBVUxUX05BUlJBVE9SX01PREVMID0gXCJvcGVuYWkvZ3B0LTQuMS1taW5pXCJcblxuLyoqIERlZmF1bHQgc3RhcnR1cCBncmVldGluZyAoc3Bva2VuIG9uY2Ugd2hlbiB0aGUgcGx1Z2luIGlzIHJlYWR5KS4gKi9cbmV4cG9ydCBjb25zdCBERUZBVUxUX0dSRUVUSU5HID0gXCJXZWxjb21lIHRvIE9wZW5Db2RlIFNwZWFrZXIhXCJcblxuLyoqIEVudmlyb25tZW50IHZhcmlhYmxlIG5hbWU6IHdoZW4gXCIxXCIsIGRpc2FibGVzIHRoZSBwbHVnaW4gZW50aXJlbHkuICovXG5leHBvcnQgY29uc3QgRU5WX0RJU0FCTEVEID0gXCJPUEVOQ09ERV9WT0lDRV9ESVNBQkxFRFwiXG5cbi8qKiBFbnZpcm9ubWVudCB2YXJpYWJsZSBuYW1lOiB3aGVuIFwiMVwiLCBzdGFydHMgdGhlIHBsdWdpbiBtdXRlZC4gKi9cbmV4cG9ydCBjb25zdCBFTlZfTVVURSA9IFwiT1BFTkNPREVfVk9JQ0VfTVVURVwiXG5cbmNvbnN0IFByaW9yaXR5U2NoZW1hID0gei5lbnVtKFtcInVyZ2VudFwiLCBcIm5vcm1hbFwiLCBcImNoYXR0eVwiXSkub3B0aW9uYWwoKVxuY29uc3QgTW9kZVNjaGVtYSA9IHouZW51bShbXCJ0ZW1wbGF0ZVwiLCBcIm5hcnJhdGVcIiwgXCJ2ZXJiYXRpbVwiXSlcbmNvbnN0IFZlcmJvc2l0eVNjaGVtYSA9IHouZW51bShbXCJtaW5pbWFsXCIsIFwibm9ybWFsXCIsIFwidmVyYm9zZVwiXSlcblxuY29uc3QgRXZlbnRDb25maWdTY2hlbWEgPSB6Lm9iamVjdCh7XG4gIGVuYWJsZWQ6IHouYm9vbGVhbigpLmRlZmF1bHQoZmFsc2UpLFxuICBtb2RlOiBNb2RlU2NoZW1hLmRlZmF1bHQoXCJ0ZW1wbGF0ZVwiKSxcbiAgcHJpb3JpdHk6IFByaW9yaXR5U2NoZW1hLFxufSlcblxuY29uc3QgU0xVR19NU0cgPSBgbXVzdCBiZSAncHJvdmlkZXIvbW9kZWwnIChlLmcuICcke0RFRkFVTFRfVFRTX01PREVMfScpYFxuXG5jb25zdCBUVFNTY2hlbWEgPSB6Lm9iamVjdCh7XG4gIG1vZGVsOiB6LnN0cmluZygpLnJlZ2V4KFNMVUdfUkUsIGB0dHMubW9kZWwgJHtTTFVHX01TR31gKS5kZWZhdWx0KERFRkFVTFRfVFRTX01PREVMKSxcbiAgdm9pY2U6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcbiAgcmF0ZTogIHoubnVtYmVyKCkubWluKDAuNSkubWF4KDIuMCkuZGVmYXVsdCgxLjApLFxuICBwaXRjaDogei5udW1iZXIoKS5taW4oMC41KS5tYXgoMi4wKS5kZWZhdWx0KDEuMCksXG59KS5kZWZhdWx0KHt9KVxuXG5jb25zdCBOYXJyYXRvclNjaGVtYSA9IHoub2JqZWN0KHtcbiAgbW9kZWw6IHouc3RyaW5nKCkucmVnZXgoU0xVR19SRSwgYG5hcnJhdG9yLm1vZGVsICR7U0xVR19NU0d9YCkuZGVmYXVsdChERUZBVUxUX05BUlJBVE9SX01PREVMKSxcbiAgdGltZW91dE1zOiAgICAgei5udW1iZXIoKS5pbnQoKS5wb3NpdGl2ZSgpLmRlZmF1bHQoNTAwMCksXG4gIG1pbkludGVydmFsTXM6IHoubnVtYmVyKCkuaW50KCkubWluKDApLmRlZmF1bHQoMzAwMCksXG59KS5kZWZhdWx0KHt9KVxuXG5jb25zdCBRdWV1ZVNjaGVtYSA9IHoub2JqZWN0KHtcbiAgc3RhbGVNczogei5udW1iZXIoKS5pbnQoKS5taW4oMCkuZGVmYXVsdCg4MDAwKSxcbn0pLmRlZmF1bHQoe30pXG5cbmNvbnN0IEV2ZW50c1NjaGVtYSA9IHoucmVjb3JkKHouc3RyaW5nKCksIEV2ZW50Q29uZmlnU2NoZW1hKS5kZWZhdWx0KHt9KVxuXG5jb25zdCBWb2ljZUNvbmZpZ1NjaGVtYSA9IHoub2JqZWN0KHtcbiAgZW5hYmxlZDogei5ib29sZWFuKCkuZGVmYXVsdCh0cnVlKSxcbiAgdmVyYm9zaXR5OiBWZXJib3NpdHlTY2hlbWEuZGVmYXVsdChcIm5vcm1hbFwiKSxcbiAgc3RhcnRNdXRlZDogei5ib29sZWFuKCkuZGVmYXVsdChmYWxzZSksXG4gIGdyZWV0aW5nOiB6LnN0cmluZygpLmRlZmF1bHQoREVGQVVMVF9HUkVFVElORyksXG4gIHR0czogVFRTU2NoZW1hLFxuICBuYXJyYXRvcjogTmFycmF0b3JTY2hlbWEsXG4gIGV2ZW50czogRXZlbnRzU2NoZW1hLFxuICBxdWV1ZTogUXVldWVTY2hlbWEsXG59KVxuXG5leHBvcnQgdHlwZSBWb2ljZUNvbmZpZyA9IHouaW5mZXI8dHlwZW9mIFZvaWNlQ29uZmlnU2NoZW1hPlxuZXhwb3J0IHR5cGUgRXZlbnRDb25maWcgPSB6LmluZmVyPHR5cGVvZiBFdmVudENvbmZpZ1NjaGVtYT5cblxuLy8gRXZlbnQga2V5cyBjb21lIGluIHR3byBmbGF2b3JzOlxuLy8gICAxLiBSZWFsIE9wZW5Db2RlIHBsdWdpbiBldmVudHMgYXMgZG9jdW1lbnRlZCBhdFxuLy8gICAgICBodHRwczovL29wZW5jb2RlLmFpL2RvY3MvcGx1Z2lucy8jZXZlbnRzIFx1MjAxNCB0aGVzZSBhcmUgZGlzcGF0Y2hlZCBieVxuLy8gICAgICBvcGVuY29kZSBpdHNlbGYgYW5kIHJlYWNoIHVzIHZpYSB0aGUgYGV2ZW50YCBob29rIGluIHNyYy9pbmRleC50cy5cbi8vICAgMi4gUGx1Z2luLWludGVybmFsIHN5bnRoZXNpemVkIGV2ZW50cyBcdTIwMTQgZmlyZWQgYnkgc3JjL2Rpc3BhdGNoZXIudHMgd2hlblxuLy8gICAgICBpdCBkZXJpdmVzIGhpZ2hlci1sZXZlbCBzaWduYWxzIGZyb20gcmF3IGV2ZW50cy4gVGhlc2UgYXJlIE5PVCBpbiB0aGVcbi8vICAgICAgb3BlbmNvZGUgZG9jcyBidXQgYXJlIHZhbGlkIGNvbmZpZ3VyYXRpb24ga2V5cyBmb3IgdGhpcyBwbHVnaW4uXG4vLyAgICAgIEN1cnJlbnRseSBzeW50aGVzaXplZDpcbi8vICAgICAgICAtIFwidG9kby5jb21wbGV0ZWQuaXRlbVwiIC8gXCJ0b2RvLmNvbXBsZXRlZC5hbGxcIiAoZnJvbSBgdG9kby51cGRhdGVkYClcbi8vICAgICAgICAtIFwibWVzc2FnZS50ZXh0LmRlbHRhXCIgLyBcIm1lc3NhZ2UucmVhc29uaW5nLmRlbHRhXCIgKGZyb20gcGVyLXNlbnRlbmNlXG4vLyAgICAgICAgICBkZWx0YXMgb2YgYG1lc3NhZ2UucGFydC51cGRhdGVkYCB0ZXh0IGFuZCByZWFzb25pbmcgcGFydHMpLlxuZnVuY3Rpb24gcHJlc2V0RXZlbnRzKHZlcmJvc2l0eTogVmVyYm9zaXR5KSB7XG4gIHJldHVybiBkZWZhdWx0RXZlbnRzRm9yVmVyYm9zaXR5KHZlcmJvc2l0eSlcbn1cblxuZXhwb3J0IGNvbnN0IERFRkFVTFRfQ09ORklHOiBWb2ljZUNvbmZpZyA9IFZvaWNlQ29uZmlnU2NoZW1hLnBhcnNlKHtcbiAgZXZlbnRzOiBkZWZhdWx0RXZlbnRzRm9yVmVyYm9zaXR5KFwibm9ybWFsXCIpLFxufSlcblxuZXhwb3J0IHR5cGUgUGFyc2VSZXN1bHQgPVxuICB8IHsgb2s6IHRydWU7IGNvbmZpZzogVm9pY2VDb25maWcgfVxuICB8IHsgb2s6IGZhbHNlOyBlcnJvcnM6IHsgcGF0aDogc3RyaW5nOyBtZXNzYWdlOiBzdHJpbmcgfVtdIH1cblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlQ29uZmlnKFxuICByYXc6IHVua25vd24sXG4gIGVudjogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgdW5kZWZpbmVkPiA9IHByb2Nlc3MuZW52LFxuKTogUGFyc2VSZXN1bHQge1xuICBjb25zdCB1c2VyT2JqID0gcmF3ICYmIHR5cGVvZiByYXcgPT09IFwib2JqZWN0XCIgPyAocmF3IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA6IHt9XG5cbiAgLy8gTWVyZ2UgcmF3IHVzZXIgaW5wdXQgb3ZlciBkZWZhdWx0cyAoZXZlbnQtbGV2ZWwgZGVlcCBtZXJnZSkuXG4gIGNvbnN0IHVzZXJFdmVudHMgPVxuICAgIHVzZXJPYmouZXZlbnRzICYmIHR5cGVvZiB1c2VyT2JqLmV2ZW50cyA9PT0gXCJvYmplY3RcIlxuICAgICAgPyAodXNlck9iai5ldmVudHMgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pXG4gICAgICA6IHt9XG4gIGNvbnN0IHJhd1ZlcmJvc2l0eSA9IHVzZXJPYmoudmVyYm9zaXR5XG4gIGNvbnN0IHZlcmJvc2l0eSA9IHJhd1ZlcmJvc2l0eSA9PT0gXCJtaW5pbWFsXCIgfHwgcmF3VmVyYm9zaXR5ID09PSBcInZlcmJvc2VcIiB8fCByYXdWZXJib3NpdHkgPT09IFwibm9ybWFsXCJcbiAgICA/IHJhd1ZlcmJvc2l0eVxuICAgIDogXCJub3JtYWxcIlxuICBjb25zdCBkZWZhdWx0c0ZvclZlcmJvc2l0eSA9IHByZXNldEV2ZW50cyh2ZXJib3NpdHkpXG4gIGNvbnN0IG1lcmdlZEV2ZW50czogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7IC4uLmRlZmF1bHRzRm9yVmVyYm9zaXR5IH1cbiAgZm9yIChjb25zdCBba2V5LCB2YWxdIG9mIE9iamVjdC5lbnRyaWVzKHVzZXJFdmVudHMpKSB7XG4gICAgY29uc3QgZGVmYXVsdEV2ZW50ID0gZGVmYXVsdHNGb3JWZXJib3NpdHlba2V5XSA/PyB7fVxuICAgIGlmICh2YWwgJiYgdHlwZW9mIHZhbCA9PT0gXCJvYmplY3RcIiAmJiAhQXJyYXkuaXNBcnJheSh2YWwpKSB7XG4gICAgICBtZXJnZWRFdmVudHNba2V5XSA9IHsgLi4uZGVmYXVsdEV2ZW50LCAuLi4odmFsIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KSB9XG4gICAgfSBlbHNlIHtcbiAgICAgIG1lcmdlZEV2ZW50c1trZXldID0gdmFsXG4gICAgfVxuICB9XG5cbiAgY29uc3QgbWVyZ2VkID0geyAuLi51c2VyT2JqLCBldmVudHM6IG1lcmdlZEV2ZW50cyB9XG4gIGNvbnN0IHBhcnNlZCA9IFZvaWNlQ29uZmlnU2NoZW1hLnNhZmVQYXJzZShtZXJnZWQpXG4gIGlmICghcGFyc2VkLnN1Y2Nlc3MpIHtcbiAgICByZXR1cm4ge1xuICAgICAgb2s6IGZhbHNlLFxuICAgICAgZXJyb3JzOiBwYXJzZWQuZXJyb3IuaXNzdWVzLm1hcCgoaSkgPT4gKHtcbiAgICAgICAgcGF0aDogaS5wYXRoLmpvaW4oXCIuXCIpLFxuICAgICAgICBtZXNzYWdlOiBpLm1lc3NhZ2UsXG4gICAgICB9KSksXG4gICAgfVxuICB9XG4gIGNvbnN0IGNmZyA9IHBhcnNlZC5kYXRhXG5cbiAgLy8gRW52IG92ZXJyaWRlcyAodGhlIG9ubHkgb25lcyB3ZSBzdGlsbCBuZWVkIFx1MjAxNCBBUEkga2V5cyBhcmUgQUkgU0RLJ3Mgam9iKS5cbiAgaWYgKGVudltFTlZfRElTQUJMRURdID09PSBcIjFcIikgY2ZnLmVuYWJsZWQgPSBmYWxzZVxuICBpZiAoZW52W0VOVl9NVVRFXSA9PT0gXCIxXCIpIGNmZy5zdGFydE11dGVkID0gdHJ1ZVxuXG4gIHJldHVybiB7IG9rOiB0cnVlLCBjb25maWc6IGNmZyB9XG59XG4iLCAiaW1wb3J0IHsgb3BlbmFpIH0gZnJvbSBcIkBhaS1zZGsvb3BlbmFpXCJcbmltcG9ydCB7IGFudGhyb3BpYyB9IGZyb20gXCJAYWktc2RrL2FudGhyb3BpY1wiXG5pbXBvcnQgeyBlbGV2ZW5sYWJzIH0gZnJvbSBcIkBhaS1zZGsvZWxldmVubGFic1wiXG5pbXBvcnQgdHlwZSB7IExhbmd1YWdlTW9kZWwsIFNwZWVjaE1vZGVsIH0gZnJvbSBcImFpXCJcblxuZXhwb3J0IGNsYXNzIENvbmZpZ0Vycm9yIGV4dGVuZHMgRXJyb3Ige1xuICBjb25zdHJ1Y3RvcihtZXNzYWdlOiBzdHJpbmcpIHtcbiAgICBzdXBlcihtZXNzYWdlKVxuICAgIHRoaXMubmFtZSA9IFwiQ29uZmlnRXJyb3JcIlxuICB9XG59XG5cbi8qKlxuICogU2x1ZyByZWdleCBzaGFyZWQgd2l0aCBgc3JjL2NvbmZpZy50c2AuIEV4cG9ydGVkIHNvIGJvdGggdGhlIFpvZCBzY2hlbWFcbiAqIHZhbGlkYXRpb24gYW5kIHRoZSBydW50aW1lIHJlc29sdmVyIGFncmVlIG9uIHdoYXQgXCJwcm92aWRlci9tb2RlbFwiIG1lYW5zLlxuICovXG5leHBvcnQgY29uc3QgU0xVR19SRSA9IC9eW2Etel1bYS16MC05LV0qXFwvW0EtWmEtejAtOS5fLV0rJC9cblxuZnVuY3Rpb24gcGFyc2VTbHVnKHNsdWc6IHN0cmluZywgZmllbGQ6IHN0cmluZyk6IFtzdHJpbmcsIHN0cmluZ10ge1xuICBpZiAoIVNMVUdfUkUudGVzdChzbHVnKSkge1xuICAgIHRocm93IG5ldyBDb25maWdFcnJvcihcbiAgICAgIGAke2ZpZWxkfSBtdXN0IGJlICdwcm92aWRlci9tb2RlbCcgKGUuZy4gJ29wZW5haS9ncHQtNScpLCBnb3QgJyR7c2x1Z30nYCxcbiAgICApXG4gIH1cbiAgY29uc3QgaWR4ID0gc2x1Zy5pbmRleE9mKFwiL1wiKVxuICByZXR1cm4gW3NsdWcuc2xpY2UoMCwgaWR4KSwgc2x1Zy5zbGljZShpZHggKyAxKV1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVMYW5ndWFnZU1vZGVsKHNsdWc6IHN0cmluZyk6IExhbmd1YWdlTW9kZWwge1xuICBjb25zdCBbcHJvdmlkZXIsIG1vZGVsSWRdID0gcGFyc2VTbHVnKHNsdWcsIFwibmFycmF0b3IubW9kZWxcIilcbiAgc3dpdGNoIChwcm92aWRlcikge1xuICAgIGNhc2UgXCJvcGVuYWlcIjpcbiAgICAgIHJldHVybiBvcGVuYWkobW9kZWxJZClcbiAgICBjYXNlIFwiYW50aHJvcGljXCI6XG4gICAgICByZXR1cm4gYW50aHJvcGljKG1vZGVsSWQpXG4gICAgZGVmYXVsdDpcbiAgICAgIHRocm93IG5ldyBDb25maWdFcnJvcihcbiAgICAgICAgYFVua25vd24gbmFycmF0b3IgcHJvdmlkZXIgJyR7cHJvdmlkZXJ9JyBpbiAnJHtzbHVnfScuIFN1cHBvcnRlZDogb3BlbmFpLCBhbnRocm9waWNgLFxuICAgICAgKVxuICB9XG59XG5cbmV4cG9ydCB0eXBlIFJlc29sdmVkU3BlZWNoID0geyBwcm92aWRlcjogXCJvcGVuYWlcIiB8IFwiZWxldmVubGFic1wiOyBtb2RlbDogU3BlZWNoTW9kZWwgfVxuXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZVNwZWVjaE1vZGVsKHNsdWc6IHN0cmluZyk6IFJlc29sdmVkU3BlZWNoIHtcbiAgY29uc3QgW3Byb3ZpZGVyLCBtb2RlbElkXSA9IHBhcnNlU2x1ZyhzbHVnLCBcInR0cy5tb2RlbFwiKVxuICBzd2l0Y2ggKHByb3ZpZGVyKSB7XG4gICAgY2FzZSBcIm9wZW5haVwiOlxuICAgICAgcmV0dXJuIHsgcHJvdmlkZXI6IFwib3BlbmFpXCIsIG1vZGVsOiBvcGVuYWkuc3BlZWNoKG1vZGVsSWQpIH1cbiAgICBjYXNlIFwiZWxldmVubGFic1wiOlxuICAgICAgcmV0dXJuIHsgcHJvdmlkZXI6IFwiZWxldmVubGFic1wiLCBtb2RlbDogZWxldmVubGFicy5zcGVlY2gobW9kZWxJZCkgfVxuICAgIGRlZmF1bHQ6XG4gICAgICB0aHJvdyBuZXcgQ29uZmlnRXJyb3IoXG4gICAgICAgIGBVbmtub3duIFRUUyBwcm92aWRlciAnJHtwcm92aWRlcn0nIGluICcke3NsdWd9Jy4gU3VwcG9ydGVkOiBvcGVuYWksIGVsZXZlbmxhYnNgLFxuICAgICAgKVxuICB9XG59XG4iLCAiaW1wb3J0IHsgUHJpb3JpdHkgfSBmcm9tIFwiLi4vcXVldWUvdHlwZXMuanNcIlxuXG5leHBvcnQgdHlwZSBFdmVudE1vZGUgPSBcInRlbXBsYXRlXCIgfCBcIm5hcnJhdGVcIiB8IFwidmVyYmF0aW1cIlxuZXhwb3J0IHR5cGUgRXZlbnRQcmlvcml0eU5hbWUgPSBcInVyZ2VudFwiIHwgXCJub3JtYWxcIiB8IFwiY2hhdHR5XCJcbmV4cG9ydCB0eXBlIFZlcmJvc2l0eSA9IFwibWluaW1hbFwiIHwgXCJub3JtYWxcIiB8IFwidmVyYm9zZVwiXG5cbmV4cG9ydCBpbnRlcmZhY2UgRXZlbnRTcGVjIHtcbiAgbW9kZTogRXZlbnRNb2RlXG4gIHByaW9yaXR5PzogRXZlbnRQcmlvcml0eU5hbWVcbiAgcXVldWVQcmlvcml0eTogUHJpb3JpdHlcbiAgZGVmYXVsdEVuYWJsZWQ6IFJlY29yZDxWZXJib3NpdHksIGJvb2xlYW4+XG4gIHN5bnRoZXRpYz86IHRydWVcbiAgbmFycmF0aW9uT2NjYXNpb24/OiBzdHJpbmdcbn1cblxuY29uc3QgZW5hYmxlZCA9IChub3JtYWw6IGJvb2xlYW4sIG1pbmltYWwgPSBub3JtYWwpOiBSZWNvcmQ8VmVyYm9zaXR5LCBib29sZWFuPiA9PiAoe1xuICBtaW5pbWFsLFxuICBub3JtYWwsXG4gIHZlcmJvc2U6IG5vcm1hbCxcbn0pXG5cbmV4cG9ydCBjb25zdCBFVkVOVF9TUEVDUyA9IHtcbiAgXCJzZXNzaW9uLmlkbGVcIjogeyBtb2RlOiBcIm5hcnJhdGVcIiwgcXVldWVQcmlvcml0eTogUHJpb3JpdHkuTk9STUFMLCBkZWZhdWx0RW5hYmxlZDogZW5hYmxlZCh0cnVlLCB0cnVlKSB9LFxuICBcInNlc3Npb24uZXJyb3JcIjogeyBtb2RlOiBcInRlbXBsYXRlXCIsIHByaW9yaXR5OiBcInVyZ2VudFwiLCBxdWV1ZVByaW9yaXR5OiBQcmlvcml0eS5VUkdFTlQsIGRlZmF1bHRFbmFibGVkOiBlbmFibGVkKHRydWUsIHRydWUpIH0sXG4gIFwic2Vzc2lvbi5jb21wYWN0ZWRcIjogeyBtb2RlOiBcInRlbXBsYXRlXCIsIHF1ZXVlUHJpb3JpdHk6IFByaW9yaXR5Lk5PUk1BTCwgZGVmYXVsdEVuYWJsZWQ6IGVuYWJsZWQodHJ1ZSwgZmFsc2UpIH0sXG4gIFwic2Vzc2lvbi5jcmVhdGVkXCI6IHsgbW9kZTogXCJ0ZW1wbGF0ZVwiLCBxdWV1ZVByaW9yaXR5OiBQcmlvcml0eS5OT1JNQUwsIGRlZmF1bHRFbmFibGVkOiBlbmFibGVkKHRydWUsIGZhbHNlKSB9LFxuICBcInBlcm1pc3Npb24uYXNrZWRcIjogeyBtb2RlOiBcInRlbXBsYXRlXCIsIHByaW9yaXR5OiBcInVyZ2VudFwiLCBxdWV1ZVByaW9yaXR5OiBQcmlvcml0eS5VUkdFTlQsIGRlZmF1bHRFbmFibGVkOiBlbmFibGVkKHRydWUsIHRydWUpIH0sXG4gIFwicGVybWlzc2lvbi5yZXBsaWVkXCI6IHsgbW9kZTogXCJ0ZW1wbGF0ZVwiLCBxdWV1ZVByaW9yaXR5OiBQcmlvcml0eS5OT1JNQUwsIGRlZmF1bHRFbmFibGVkOiBlbmFibGVkKHRydWUsIGZhbHNlKSB9LFxuICBcInRvb2wuZXhlY3V0ZS5iZWZvcmVcIjogeyBtb2RlOiBcInRlbXBsYXRlXCIsIHByaW9yaXR5OiBcImNoYXR0eVwiLCBxdWV1ZVByaW9yaXR5OiBQcmlvcml0eS5DSEFUVFksIGRlZmF1bHRFbmFibGVkOiBlbmFibGVkKHRydWUsIGZhbHNlKSB9LFxuICBcInRvb2wuZXhlY3V0ZS5hZnRlclwiOiB7IG1vZGU6IFwidGVtcGxhdGVcIiwgcHJpb3JpdHk6IFwiY2hhdHR5XCIsIHF1ZXVlUHJpb3JpdHk6IFByaW9yaXR5LkNIQVRUWSwgZGVmYXVsdEVuYWJsZWQ6IGVuYWJsZWQodHJ1ZSwgZmFsc2UpIH0sXG4gIFwiZmlsZS5lZGl0ZWRcIjogeyBtb2RlOiBcInRlbXBsYXRlXCIsIHByaW9yaXR5OiBcImNoYXR0eVwiLCBxdWV1ZVByaW9yaXR5OiBQcmlvcml0eS5DSEFUVFksIGRlZmF1bHRFbmFibGVkOiBlbmFibGVkKHRydWUsIGZhbHNlKSB9LFxuICBcImNvbW1hbmQuZXhlY3V0ZWRcIjogeyBtb2RlOiBcInRlbXBsYXRlXCIsIHF1ZXVlUHJpb3JpdHk6IFByaW9yaXR5Lk5PUk1BTCwgZGVmYXVsdEVuYWJsZWQ6IGVuYWJsZWQodHJ1ZSwgZmFsc2UpIH0sXG4gIFwibWVzc2FnZS51cGRhdGVkXCI6IHsgbW9kZTogXCJ2ZXJiYXRpbVwiLCBwcmlvcml0eTogXCJjaGF0dHlcIiwgcXVldWVQcmlvcml0eTogUHJpb3JpdHkuQ0hBVFRZLCBkZWZhdWx0RW5hYmxlZDogZW5hYmxlZChmYWxzZSwgZmFsc2UpIH0sXG4gIFwibWVzc2FnZS5yZWFzb25pbmcuZGVsdGFcIjogeyBtb2RlOiBcInZlcmJhdGltXCIsIHByaW9yaXR5OiBcImNoYXR0eVwiLCBxdWV1ZVByaW9yaXR5OiBQcmlvcml0eS5DSEFUVFksIGRlZmF1bHRFbmFibGVkOiBlbmFibGVkKHRydWUsIGZhbHNlKSwgc3ludGhldGljOiB0cnVlIH0sXG4gIFwibWVzc2FnZS50ZXh0LmRlbHRhXCI6IHsgbW9kZTogXCJ2ZXJiYXRpbVwiLCBwcmlvcml0eTogXCJjaGF0dHlcIiwgcXVldWVQcmlvcml0eTogUHJpb3JpdHkuQ0hBVFRZLCBkZWZhdWx0RW5hYmxlZDogZW5hYmxlZChmYWxzZSwgZmFsc2UpLCBzeW50aGV0aWM6IHRydWUgfSxcbiAgXCJ0b2RvLmNvbXBsZXRlZC5pdGVtXCI6IHsgbW9kZTogXCJ0ZW1wbGF0ZVwiLCBwcmlvcml0eTogXCJjaGF0dHlcIiwgcXVldWVQcmlvcml0eTogUHJpb3JpdHkuQ0hBVFRZLCBkZWZhdWx0RW5hYmxlZDogZW5hYmxlZCh0cnVlLCBmYWxzZSksIHN5bnRoZXRpYzogdHJ1ZSB9LFxuICBcInRvZG8uY29tcGxldGVkLmFsbFwiOiB7IG1vZGU6IFwibmFycmF0ZVwiLCBxdWV1ZVByaW9yaXR5OiBQcmlvcml0eS5OT1JNQUwsIGRlZmF1bHRFbmFibGVkOiBlbmFibGVkKHRydWUsIHRydWUpLCBzeW50aGV0aWM6IHRydWUsIG5hcnJhdGlvbk9jY2FzaW9uOiBcIlRoZSB1c2VyIGhhcyBmaW5pc2hlZCBhbGwgdG9kb3MuXCIgfSxcbn0gYXMgY29uc3Qgc2F0aXNmaWVzIFJlY29yZDxzdHJpbmcsIEV2ZW50U3BlYz5cblxuZXhwb3J0IHR5cGUgRXZlbnRUeXBlID0ga2V5b2YgdHlwZW9mIEVWRU5UX1NQRUNTXG5cbmV4cG9ydCBmdW5jdGlvbiBkZWZhdWx0RXZlbnRzRm9yVmVyYm9zaXR5KHZlcmJvc2l0eTogVmVyYm9zaXR5KSB7XG4gIHJldHVybiBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgKE9iamVjdC5lbnRyaWVzKEVWRU5UX1NQRUNTKSBhcyBBcnJheTxbc3RyaW5nLCBFdmVudFNwZWNdPikubWFwKChbdHlwZSwgc3BlY10pID0+IFtcbiAgICAgIHR5cGUsXG4gICAgICB7XG4gICAgICAgIGVuYWJsZWQ6IHNwZWMuZGVmYXVsdEVuYWJsZWRbdmVyYm9zaXR5XSxcbiAgICAgICAgbW9kZTogc3BlYy5tb2RlLFxuICAgICAgICAuLi4oc3BlYy5wcmlvcml0eSA/IHsgcHJpb3JpdHk6IHNwZWMucHJpb3JpdHkgfSA6IHt9KSxcbiAgICAgIH0sXG4gICAgXSksXG4gIClcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHF1ZXVlUHJpb3JpdHlGb3JFdmVudCh0eXBlOiBzdHJpbmcpOiBQcmlvcml0eSB7XG4gIHJldHVybiBFVkVOVF9TUEVDU1t0eXBlIGFzIEV2ZW50VHlwZV0/LnF1ZXVlUHJpb3JpdHkgPz8gUHJpb3JpdHkuTk9STUFMXG59XG4iLCAiY29uc3QgU0VOU0lUSVZFX0tFWVMgPSBuZXcgU2V0KFtcbiAgXCJhcGlLZXlcIiwgXCJhcGlfa2V5XCIsIFwiYXBpa2V5XCIsXG4gIFwiYXV0aG9yaXphdGlvblwiLCBcIkF1dGhvcml6YXRpb25cIixcbiAgXCJzZWNyZXRcIiwgXCJ0b2tlblwiLCBcInBhc3N3b3JkXCIsXG5dKVxuXG5leHBvcnQgZnVuY3Rpb24gcmVkYWN0KHZhbHVlOiB1bmtub3duKTogdW5rbm93biB7XG4gIHJldHVybiByZWRhY3RJbm5lcih2YWx1ZSwgbmV3IFdlYWtTZXQoKSlcbn1cblxuZnVuY3Rpb24gcmVkYWN0SW5uZXIodmFsdWU6IHVua25vd24sIHNlZW46IFdlYWtTZXQ8b2JqZWN0Pik6IHVua25vd24ge1xuICBpZiAodmFsdWUgPT09IG51bGwgfHwgdHlwZW9mIHZhbHVlICE9PSBcIm9iamVjdFwiKSByZXR1cm4gdmFsdWVcbiAgaWYgKHNlZW4uaGFzKHZhbHVlIGFzIG9iamVjdCkpIHJldHVybiBcIltDaXJjdWxhcl1cIlxuICBzZWVuLmFkZCh2YWx1ZSBhcyBvYmplY3QpXG4gIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkgcmV0dXJuIHZhbHVlLm1hcCgodikgPT4gcmVkYWN0SW5uZXIodiwgc2VlbikpXG4gIGNvbnN0IG91dDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fVxuICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyh2YWx1ZSkpIHtcbiAgICBvdXRba10gPSBTRU5TSVRJVkVfS0VZUy5oYXMoaykgPyBcIioqKlwiIDogcmVkYWN0SW5uZXIodiwgc2VlbilcbiAgfVxuICByZXR1cm4gb3V0XG59XG5cbmNvbnN0IE1BWF9GSUVMRF9CWVRFUyA9IDQwOTZcblxuZXhwb3J0IGZ1bmN0aW9uIHRydW5jYXRlUGF5bG9hZCh2YWx1ZTogdW5rbm93bik6IHVua25vd24ge1xuICByZXR1cm4gdHJ1bmNhdGVJbm5lcih2YWx1ZSwgbmV3IFdlYWtTZXQoKSwgZmFsc2UpXG59XG5cbmZ1bmN0aW9uIHRydW5jYXRlSW5uZXIoXG4gIHZhbHVlOiB1bmtub3duLFxuICBzZWVuOiBXZWFrU2V0PG9iamVjdD4sXG4gIGluc2lkZUVycm9yU3RhY2s6IGJvb2xlYW4sXG4pOiB1bmtub3duIHtcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIikge1xuICAgIGlmIChpbnNpZGVFcnJvclN0YWNrKSByZXR1cm4gdmFsdWVcbiAgICBjb25zdCBieXRlcyA9IEJ1ZmZlci5ieXRlTGVuZ3RoKHZhbHVlLCBcInV0ZjhcIilcbiAgICBpZiAoYnl0ZXMgPD0gTUFYX0ZJRUxEX0JZVEVTKSByZXR1cm4gdmFsdWVcbiAgICBjb25zdCBoZWFkID0gQnVmZmVyLmZyb20odmFsdWUsIFwidXRmOFwiKS5zdWJhcnJheSgwLCBNQVhfRklFTERfQllURVMpLnRvU3RyaW5nKFwidXRmOFwiKVxuICAgIHJldHVybiBgJHtoZWFkfVx1MjAyNjx0cnVuY2F0ZWQ6JHtieXRlcyAtIE1BWF9GSUVMRF9CWVRFU30gYnl0ZXM+YFxuICB9XG4gIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB0eXBlb2YgdmFsdWUgIT09IFwib2JqZWN0XCIpIHJldHVybiB2YWx1ZVxuICBpZiAoc2Vlbi5oYXModmFsdWUgYXMgb2JqZWN0KSkgcmV0dXJuIHZhbHVlXG4gIHNlZW4uYWRkKHZhbHVlIGFzIG9iamVjdClcbiAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSByZXR1cm4gdmFsdWUubWFwKCh2KSA9PiB0cnVuY2F0ZUlubmVyKHYsIHNlZW4sIGluc2lkZUVycm9yU3RhY2spKVxuICBjb25zdCBvdXQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge31cbiAgZm9yIChjb25zdCBbaywgdl0gb2YgT2JqZWN0LmVudHJpZXModmFsdWUpKSB7XG4gICAgY29uc3QgZXhlbXB0ID0gayA9PT0gXCJzdGFja1wiXG4gICAgb3V0W2tdID0gdHJ1bmNhdGVJbm5lcih2LCBzZWVuLCBleGVtcHQpXG4gIH1cbiAgcmV0dXJuIG91dFxufVxuXG5leHBvcnQgdHlwZSBMb2dMZXZlbCA9IFwiZGVidWdcIiB8IFwiaW5mb1wiIHwgXCJ3YXJuXCIgfCBcImVycm9yXCJcblxuZXhwb3J0IGludGVyZmFjZSBTZXJpYWxpemVkRXJyb3Ige1xuICBuYW1lOiBzdHJpbmdcbiAgbWVzc2FnZTogc3RyaW5nXG4gIGNvZGU/OiBzdHJpbmcgfCBudW1iZXJcbiAgc3RhY2s/OiBzdHJpbmdcbiAgZmlsZT86IHN0cmluZ1xuICBsaW5lPzogbnVtYmVyXG4gIGNvbHVtbj86IG51bWJlclxuICBmdW5jdGlvbj86IHN0cmluZ1xuICBjYXVzZT86IFNlcmlhbGl6ZWRFcnJvclxufVxuXG5leHBvcnQgaW50ZXJmYWNlIExvZ0NvbnRleHQge1xuICBlcnJvcj86IHVua25vd25cbiAgb3BlcmF0aW9uPzogc3RyaW5nXG4gIGlucHV0PzogdW5rbm93blxuICBba2V5OiBzdHJpbmddOiB1bmtub3duXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTG9nZ2VyIHtcbiAgZGVidWcobXNnOiBzdHJpbmcsIGN0eD86IExvZ0NvbnRleHQgfCB1bmtub3duKTogUHJvbWlzZTx2b2lkPlxuICBpbmZvKG1zZzogc3RyaW5nLCBjdHg/OiBMb2dDb250ZXh0IHwgdW5rbm93bik6IFByb21pc2U8dm9pZD5cbiAgd2Fybihtc2c6IHN0cmluZywgY3R4PzogTG9nQ29udGV4dCB8IHVua25vd24pOiBQcm9taXNlPHZvaWQ+XG4gIGVycm9yKG1zZzogc3RyaW5nLCBjdHg/OiBMb2dDb250ZXh0IHwgdW5rbm93bik6IFByb21pc2U8dm9pZD5cbiAgY2hpbGQoYmluZGluZ3M6IHsgbW9kdWxlOiBzdHJpbmc7IFtrOiBzdHJpbmddOiB1bmtub3duIH0pOiBMb2dnZXJcbn1cblxuY29uc3QgRlJBTUVfUkUgPSAvXlxccyphdCAoPzooLis/KSBcXCgpPyguKz8pOihcXGQrKTooXFxkKylcXCk/JC9cblxuZnVuY3Rpb24gaXNJbnRlcm5hbEZpbGUoZmlsZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiAoXG4gICAgZmlsZS5zdGFydHNXaXRoKFwibm9kZTpcIikgfHxcbiAgICBmaWxlLmluY2x1ZGVzKFwiL2ludGVybmFsL1wiKSB8fFxuICAgIGZpbGUuZW5kc1dpdGgoXCIvbG9nLmpzXCIpIHx8XG4gICAgZmlsZS5lbmRzV2l0aChcIi9sb2cudHNcIilcbiAgKVxufVxuXG5mdW5jdGlvbiBwYXJzZVRvcEZyYW1lKHN0YWNrOiBzdHJpbmcgfCB1bmRlZmluZWQpOiB7XG4gIGZpbGU/OiBzdHJpbmdcbiAgbGluZT86IG51bWJlclxuICBjb2x1bW4/OiBudW1iZXJcbiAgZnVuY3Rpb24/OiBzdHJpbmdcbn0ge1xuICBpZiAoIXN0YWNrKSByZXR1cm4ge31cbiAgY29uc3QgbGluZXMgPSBzdGFjay5zcGxpdChcIlxcblwiKVxuICBmb3IgKGNvbnN0IHJhdyBvZiBsaW5lcykge1xuICAgIGNvbnN0IG0gPSBGUkFNRV9SRS5leGVjKHJhdylcbiAgICBpZiAoIW0pIGNvbnRpbnVlXG4gICAgY29uc3QgZmlsZSA9IG1bMl1cbiAgICBpZiAoaXNJbnRlcm5hbEZpbGUoZmlsZSkpIGNvbnRpbnVlXG4gICAgcmV0dXJuIHtcbiAgICAgIGZ1bmN0aW9uOiBtWzFdIHx8IHVuZGVmaW5lZCxcbiAgICAgIGZpbGUsXG4gICAgICBsaW5lOiBOdW1iZXIobVszXSksXG4gICAgICBjb2x1bW46IE51bWJlcihtWzRdKSxcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHt9XG59XG5cbmZ1bmN0aW9uIG5vbkVycm9yTWVzc2FnZSh2YWx1ZTogdW5rbm93bik6IHN0cmluZyB7XG4gIHRyeSB7XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIikgcmV0dXJuIHZhbHVlXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJudW1iZXJcIiB8fCB0eXBlb2YgdmFsdWUgPT09IFwiYm9vbGVhblwiKSByZXR1cm4gU3RyaW5nKHZhbHVlKVxuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeSh2YWx1ZSlcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh2YWx1ZSlcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gc2VyaWFsaXplRXJyb3IoZXJyOiB1bmtub3duKTogU2VyaWFsaXplZEVycm9yIHtcbiAgaWYgKCEoZXJyIGluc3RhbmNlb2YgRXJyb3IpKSB7XG4gICAgcmV0dXJuIHsgbmFtZTogXCJOb25FcnJvclwiLCBtZXNzYWdlOiBub25FcnJvck1lc3NhZ2UoZXJyKSB9XG4gIH1cbiAgdHJ5IHtcbiAgICByZXR1cm4gc2VyaWFsaXplRXJyb3JEZXB0aChlcnIsIDIpXG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB7IG5hbWU6IGVyci5uYW1lID8/IFwiRXJyb3JcIiwgbWVzc2FnZTogZXJyLm1lc3NhZ2UgPz8gXCJcIiB9XG4gIH1cbn1cblxuZnVuY3Rpb24gc2VyaWFsaXplRXJyb3JEZXB0aChlcnI6IEVycm9yLCBkZXB0aDogbnVtYmVyKTogU2VyaWFsaXplZEVycm9yIHtcbiAgY29uc3Qgc3RhY2sgPSBlcnIuc3RhY2tcbiAgY29uc3Qgb3V0OiBTZXJpYWxpemVkRXJyb3IgPSB7XG4gICAgbmFtZTogZXJyLm5hbWUsXG4gICAgbWVzc2FnZTogZXJyLm1lc3NhZ2UsXG4gICAgLi4uKHN0YWNrID8geyBzdGFjayB9IDoge30pLFxuICAgIC4uLnBhcnNlVG9wRnJhbWUoc3RhY2spLFxuICB9XG4gIGNvbnN0IGNvZGUgPSAoZXJyIGFzIHsgY29kZT86IHN0cmluZyB8IG51bWJlciB9KS5jb2RlXG4gIGlmIChjb2RlICE9PSB1bmRlZmluZWQpIG91dC5jb2RlID0gY29kZVxuICBjb25zdCBjYXVzZSA9IChlcnIgYXMgeyBjYXVzZT86IHVua25vd24gfSkuY2F1c2VcbiAgaWYgKGRlcHRoID4gMCAmJiBjYXVzZSBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgb3V0LmNhdXNlID0gc2VyaWFsaXplRXJyb3JEZXB0aChjYXVzZSwgZGVwdGggLSAxKVxuICB9XG4gIHJldHVybiBvdXRcbn1cblxuaW50ZXJmYWNlIE9wZW5jb2RlQ2xpZW50IHtcbiAgYXBwOiB7XG4gICAgbG9nOiAocmVxOiB7XG4gICAgICBib2R5OiB7IHNlcnZpY2U6IHN0cmluZzsgbGV2ZWw6IExvZ0xldmVsOyBtZXNzYWdlOiBzdHJpbmc7IGV4dHJhPzogdW5rbm93biB9XG4gICAgfSkgPT4gUHJvbWlzZTx1bmtub3duPlxuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVMb2dnZXIoY2xpZW50OiBPcGVuY29kZUNsaWVudCwgc2VydmljZTogc3RyaW5nKTogTG9nZ2VyIHtcbiAgcmV0dXJuIG1ha2VMb2dnZXIoY2xpZW50LCBzZXJ2aWNlLCB1bmRlZmluZWQpXG59XG5cbmZ1bmN0aW9uIG1ha2VMb2dnZXIoXG4gIGNsaWVudDogT3BlbmNvZGVDbGllbnQsXG4gIHNlcnZpY2U6IHN0cmluZyxcbiAgYmluZGluZ3M6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkLFxuKTogTG9nZ2VyIHtcbiAgYXN5bmMgZnVuY3Rpb24gZW1pdChcbiAgICBsZXZlbDogTG9nTGV2ZWwsXG4gICAgbWVzc2FnZTogc3RyaW5nLFxuICAgIGN0eD86IExvZ0NvbnRleHQgfCB1bmtub3duLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgYm9keToge1xuICAgICAgICBzZXJ2aWNlOiBzdHJpbmdcbiAgICAgICAgbGV2ZWw6IExvZ0xldmVsXG4gICAgICAgIG1lc3NhZ2U6IHN0cmluZ1xuICAgICAgICBleHRyYT86IHVua25vd25cbiAgICAgIH0gPSB7IHNlcnZpY2UsIGxldmVsLCBtZXNzYWdlIH1cbiAgICAgIGNvbnN0IGV4dHJhID0gYnVpbGRFeHRyYShjdHgsIGJpbmRpbmdzKVxuICAgICAgaWYgKGV4dHJhICE9PSB1bmRlZmluZWQpIGJvZHkuZXh0cmEgPSBleHRyYVxuICAgICAgYXdhaXQgY2xpZW50LmFwcC5sb2coeyBib2R5IH0pXG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBMb2dnZXIgbXVzdCBuZXZlciB0aHJvdy5cbiAgICB9XG4gIH1cbiAgY29uc3QgbG9nZ2VyOiBMb2dnZXIgPSB7XG4gICAgZGVidWc6IChtLCBlKSA9PiBlbWl0KFwiZGVidWdcIiwgbSwgZSksXG4gICAgaW5mbzogIChtLCBlKSA9PiBlbWl0KFwiaW5mb1wiLCAgbSwgZSksXG4gICAgd2FybjogIChtLCBlKSA9PiBlbWl0KFwid2FyblwiLCAgbSwgZSksXG4gICAgZXJyb3I6IChtLCBlKSA9PiBlbWl0KFwiZXJyb3JcIiwgbSwgZSksXG4gICAgY2hpbGQoYikge1xuICAgICAgY29uc3QgbWVyZ2VkID0geyAuLi4oYmluZGluZ3MgPz8ge30pLCAuLi5iIH1cbiAgICAgIHJldHVybiBtYWtlTG9nZ2VyKGNsaWVudCwgc2VydmljZSwgbWVyZ2VkKVxuICAgIH0sXG4gIH1cbiAgcmV0dXJuIGxvZ2dlclxufVxuXG5mdW5jdGlvbiBidWlsZEV4dHJhKFxuICBjdHg6IExvZ0NvbnRleHQgfCB1bmtub3duLFxuICBiaW5kaW5nczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWQsXG4pOiB1bmtub3duIHtcbiAgdHJ5IHtcbiAgICBsZXQgbm9ybWFsaXplZDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWRcbiAgICBpZiAoY3R4IGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgIG5vcm1hbGl6ZWQgPSB7IGVycm9yOiBzZXJpYWxpemVFcnJvcihjdHgpIH1cbiAgICB9IGVsc2UgaWYgKGN0eCAhPT0gdW5kZWZpbmVkICYmIGN0eCAhPT0gbnVsbCAmJiB0eXBlb2YgY3R4ID09PSBcIm9iamVjdFwiKSB7XG4gICAgICBjb25zdCBvYmogPSBjdHggYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj5cbiAgICAgIG5vcm1hbGl6ZWQgPSB7IC4uLm9iaiB9XG4gICAgICBpZiAob2JqLmVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgbm9ybWFsaXplZC5lcnJvciA9IHNlcmlhbGl6ZUVycm9yKG9iai5lcnJvcilcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGN0eCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBub3JtYWxpemVkID0geyB2YWx1ZTogY3R4IH1cbiAgICB9XG4gICAgaWYgKGJpbmRpbmdzICYmIE9iamVjdC5rZXlzKGJpbmRpbmdzKS5sZW5ndGggPiAwKSB7XG4gICAgICBub3JtYWxpemVkID0geyAuLi4obm9ybWFsaXplZCA/PyB7fSksIGJpbmRpbmdzOiB7IC4uLmJpbmRpbmdzIH0gfVxuICAgIH1cbiAgICBpZiAobm9ybWFsaXplZCA9PT0gdW5kZWZpbmVkKSByZXR1cm4gdW5kZWZpbmVkXG4gICAgcmV0dXJuIHRydW5jYXRlUGF5bG9hZChyZWRhY3Qobm9ybWFsaXplZCkpXG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBiaW5kaW5ncyA/IHsgYmluZGluZ3M6IHsgLi4uYmluZGluZ3MgfSB9IDogdW5kZWZpbmVkXG4gIH1cbn1cbiIsICJpbXBvcnQgeyBQcmlvcml0eSwgdHlwZSBTcGVlY2hSZXF1ZXN0IH0gZnJvbSBcIi4vdHlwZXMuanNcIlxuaW1wb3J0IHR5cGUgeyBMb2dnZXIgfSBmcm9tIFwiLi4vbG9nLmpzXCJcblxuZXhwb3J0IHR5cGUgU3BlYWtGbiA9IChyZXE6IFNwZWVjaFJlcXVlc3QsIHNpZ25hbDogQWJvcnRTaWduYWwpID0+IFByb21pc2U8dm9pZD5cblxuZXhwb3J0IGludGVyZmFjZSBTcGVlY2hRdWV1ZU9wdGlvbnMge1xuICBzcGVhazogU3BlYWtGblxuICBzdGFsZU1zOiBudW1iZXJcbiAgbm93OiAoKSA9PiBudW1iZXJcbiAgb25FcnJvcj86IChlcnI6IHVua25vd24sIHJlcTogU3BlZWNoUmVxdWVzdCkgPT4gdm9pZFxuICBsb2dnZXI/OiBMb2dnZXJcbn1cblxuZXhwb3J0IGNsYXNzIFNwZWVjaFF1ZXVlIHtcbiAgcHJpdmF0ZSBxdWV1ZTogU3BlZWNoUmVxdWVzdFtdID0gW11cbiAgcHJpdmF0ZSBjdXJyZW50OiB7IHJlcTogU3BlZWNoUmVxdWVzdDsgYWJvcnQ6IEFib3J0Q29udHJvbGxlciB9IHwgbnVsbCA9IG51bGxcbiAgcHJpdmF0ZSBtdXRlZCA9IGZhbHNlXG4gIHByaXZhdGUgaWRsZVJlc29sdmVyczogQXJyYXk8KCkgPT4gdm9pZD4gPSBbXVxuICBwcml2YXRlIHB1bXBSdW5uaW5nID0gZmFsc2VcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IG9wdHM6IFNwZWVjaFF1ZXVlT3B0aW9ucykge31cblxuICBwdXNoKHJlcTogU3BlZWNoUmVxdWVzdCk6IHZvaWQge1xuICAgIGlmICh0aGlzLm11dGVkKSByZXR1cm5cblxuICAgIC8vIFJ1bGUgMjogaW50ZXJydXB0IGlmIGhpZ2hlciBwcmlvcml0eSB0aGFuIGN1cnJlbnQuXG4gICAgaWYgKHRoaXMuY3VycmVudCAmJiByZXEucHJpb3JpdHkgPiB0aGlzLmN1cnJlbnQucmVxLnByaW9yaXR5KSB7XG4gICAgICB0aGlzLnF1ZXVlLnVuc2hpZnQocmVxKVxuICAgICAgdGhpcy5jdXJyZW50LmFib3J0LmFib3J0KClcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIC8vIFJ1bGUgMzogZGVkdXAgYnkga2V5IGFnYWluc3QgcXVldWVkIChub3QgY3VycmVudCkgaXRlbXMuXG4gICAgaWYgKHJlcS5kZWR1cEtleSkge1xuICAgICAgY29uc3QgaWR4ID0gdGhpcy5xdWV1ZS5maW5kSW5kZXgoKHEpID0+IHEuZGVkdXBLZXkgPT09IHJlcS5kZWR1cEtleSlcbiAgICAgIGlmIChpZHggPj0gMCkge1xuICAgICAgICB0aGlzLnF1ZXVlW2lkeF0gPSByZXEgLy8gbmV3ZXIgd2luc1xuICAgICAgICByZXR1cm5cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBSdWxlIDQ6IGluc2VydCBieSBwcmlvcml0eSAoc3RhYmxlIEZJRk8gd2l0aGluIHByaW9yaXR5KS5cbiAgICBsZXQgaSA9IDBcbiAgICB3aGlsZSAoaSA8IHRoaXMucXVldWUubGVuZ3RoICYmIHRoaXMucXVldWVbaV0ucHJpb3JpdHkgPj0gcmVxLnByaW9yaXR5KSBpKytcbiAgICB0aGlzLnF1ZXVlLnNwbGljZShpLCAwLCByZXEpXG5cbiAgICB2b2lkIHRoaXMucHVtcCgpXG4gIH1cblxuICBtdXRlKCk6IHZvaWQge1xuICAgIHRoaXMubXV0ZWQgPSB0cnVlXG4gICAgdGhpcy5xdWV1ZSA9IFtdXG4gICAgaWYgKHRoaXMuY3VycmVudCkgdGhpcy5jdXJyZW50LmFib3J0LmFib3J0KClcbiAgfVxuXG4gIHVubXV0ZSgpOiB2b2lkIHtcbiAgICB0aGlzLm11dGVkID0gZmFsc2VcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnRlcnJ1cHQgdGhlIGN1cnJlbnQgdXR0ZXJhbmNlIGFuZCBkcm9wIHRoZSBwZW5kaW5nIHF1ZXVlIFdJVEhPVVRcbiAgICogY2hhbmdpbmcgdGhlIG11dGVkIHN0YXRlLiBVc2UgdGhpcyBmb3IgXCJzdG9wIHNwZWFraW5nIHJpZ2h0IG5vd1wiIHdoaWxlXG4gICAqIGxlYXZpbmcgZnV0dXJlIGV2ZW50cyBmcmVlIHRvIHNwZWFrLlxuICAgKi9cbiAgc3RvcCgpOiB2b2lkIHtcbiAgICB0aGlzLnF1ZXVlID0gW11cbiAgICBpZiAodGhpcy5jdXJyZW50KSB0aGlzLmN1cnJlbnQuYWJvcnQuYWJvcnQoKVxuICB9XG5cbiAgaXNNdXRlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5tdXRlZFxuICB9XG5cbiAgc2l6ZSgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnF1ZXVlLmxlbmd0aCArICh0aGlzLmN1cnJlbnQgPyAxIDogMClcbiAgfVxuXG4gIC8qKiBSZXNvbHZlcyB3aGVuIHF1ZXVlIGlzIGVtcHR5IGFuZCBub3RoaW5nIGlzIHNwZWFraW5nLiAqL1xuICBhc3luYyBpZGxlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICghdGhpcy5jdXJyZW50ICYmIHRoaXMucXVldWUubGVuZ3RoID09PSAwICYmICF0aGlzLnB1bXBSdW5uaW5nKSByZXR1cm5cbiAgICByZXR1cm4gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUpID0+IHtcbiAgICAgIHRoaXMuaWRsZVJlc29sdmVycy5wdXNoKHJlc29sdmUpXG4gICAgfSlcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcHVtcCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5wdW1wUnVubmluZyB8fCB0aGlzLmN1cnJlbnQpIHJldHVyblxuICAgIHRoaXMucHVtcFJ1bm5pbmcgPSB0cnVlXG4gICAgdHJ5IHtcbiAgICAgIHdoaWxlICh0aGlzLnF1ZXVlLmxlbmd0aCA+IDAgJiYgIXRoaXMubXV0ZWQpIHtcbiAgICAgICAgY29uc3QgbmV4dCA9IHRoaXMucXVldWUuc2hpZnQoKSFcbiAgICAgICAgLy8gUnVsZSA1OiBzdGFsZSBkcm9wIGZvciBub24tdXJnZW50IGl0ZW1zLlxuICAgICAgICBpZiAoXG4gICAgICAgICAgbmV4dC5wcmlvcml0eSA8PSBQcmlvcml0eS5OT1JNQUwgJiZcbiAgICAgICAgICB0aGlzLm9wdHMubm93KCkgLSBuZXh0LmVucXVldWVkQXQgPiB0aGlzLm9wdHMuc3RhbGVNc1xuICAgICAgICApIHtcbiAgICAgICAgICBjb250aW51ZVxuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGFib3J0ID0gbmV3IEFib3J0Q29udHJvbGxlcigpXG4gICAgICAgIHRoaXMuY3VycmVudCA9IHsgcmVxOiBuZXh0LCBhYm9ydCB9XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgdGhpcy5vcHRzLnNwZWFrKG5leHQsIGFib3J0LnNpZ25hbClcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgdGhpcy5vcHRzLm9uRXJyb3I/LihlcnIsIG5leHQpXG4gICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgdGhpcy5jdXJyZW50ID0gbnVsbFxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMucHVtcFJ1bm5pbmcgPSBmYWxzZVxuICAgICAgaWYgKCF0aGlzLmN1cnJlbnQgJiYgdGhpcy5xdWV1ZS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgY29uc3QgcmVzb2x2ZXJzID0gdGhpcy5pZGxlUmVzb2x2ZXJzXG4gICAgICAgIHRoaXMuaWRsZVJlc29sdmVycyA9IFtdXG4gICAgICAgIGZvciAoY29uc3QgciBvZiByZXNvbHZlcnMpIHIoKVxuICAgICAgfVxuICAgIH1cbiAgfVxufVxuIiwgImltcG9ydCB7IGV4cGVyaW1lbnRhbF9nZW5lcmF0ZVNwZWVjaCBhcyBnZW5lcmF0ZVNwZWVjaCwgdHlwZSBTcGVlY2hNb2RlbCB9IGZyb20gXCJhaVwiXG5pbXBvcnQgdHlwZSB7IFRUU1Byb3ZpZGVyLCBTeW50aGVzaXNPcHRpb25zLCBTeW50aGVzaXNSZXN1bHQgfSBmcm9tIFwiLi9wcm92aWRlci5qc1wiXG5cbmludGVyZmFjZSBBaVNka1Byb3ZpZGVyQ29uZmlnIHtcbiAgbW9kZWw6IFNwZWVjaE1vZGVsXG4gIHByb3ZpZGVyOiBcIm9wZW5haVwiIHwgXCJlbGV2ZW5sYWJzXCJcbiAgdm9pY2U/OiBzdHJpbmdcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUFpU2RrUHJvdmlkZXIoY29uZmlnOiBBaVNka1Byb3ZpZGVyQ29uZmlnKTogVFRTUHJvdmlkZXIge1xuICBjb25zdCB7IG1vZGVsLCBwcm92aWRlcjogcHJvdmlkZXJOYW1lLCB2b2ljZTogZGVmYXVsdFZvaWNlIH0gPSBjb25maWdcblxuICByZXR1cm4ge1xuICAgIG5hbWU6IHByb3ZpZGVyTmFtZSxcblxuICAgIGFzeW5jIHN5bnRoZXNpemUoXG4gICAgICB0ZXh0OiBzdHJpbmcsXG4gICAgICBvcHRzOiBTeW50aGVzaXNPcHRpb25zLFxuICAgICAgc2lnbmFsOiBBYm9ydFNpZ25hbCxcbiAgICApOiBQcm9taXNlPFN5bnRoZXNpc1Jlc3VsdD4ge1xuICAgICAgY29uc3Qgdm9pY2UgPVxuICAgICAgICBvcHRzLnZvaWNlID8/XG4gICAgICAgIGRlZmF1bHRWb2ljZSA/P1xuICAgICAgICAocHJvdmlkZXJOYW1lID09PSBcIm9wZW5haVwiID8gXCJhbGxveVwiIDogdW5kZWZpbmVkKVxuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBnZW5lcmF0ZVNwZWVjaCh7XG4gICAgICAgIG1vZGVsLFxuICAgICAgICB0ZXh0LFxuICAgICAgICB2b2ljZSxcbiAgICAgICAgb3V0cHV0Rm9ybWF0OiBcIm1wM1wiLFxuICAgICAgICBzcGVlZDogb3B0cy5yYXRlLFxuICAgICAgICBhYm9ydFNpZ25hbDogc2lnbmFsLFxuICAgICAgfSlcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGF1ZGlvOiBCdWZmZXIuZnJvbShyZXN1bHQuYXVkaW8udWludDhBcnJheSksXG4gICAgICAgIGNvbnRlbnRUeXBlOiByZXN1bHQuYXVkaW8ubWVkaWFUeXBlID8/IFwiYXVkaW8vbXBlZ1wiLFxuICAgICAgfVxuICAgIH0sXG4gIH1cbn1cbiIsICJpbXBvcnQgdHlwZSB7IFJ1bm5lciB9IGZyb20gXCIuL3J1bm5lci5qc1wiXG5pbXBvcnQgeyBQTFVHSU5fTkFNRSB9IGZyb20gXCIuLi9jb25maWcuanNcIlxuaW1wb3J0IHsgd3JpdGVGaWxlLCBta2R0ZW1wLCBybSB9IGZyb20gXCJub2RlOmZzL3Byb21pc2VzXCJcbmltcG9ydCB7IHRtcGRpciB9IGZyb20gXCJub2RlOm9zXCJcbmltcG9ydCB7IGpvaW4gfSBmcm9tIFwibm9kZTpwYXRoXCJcblxuZXhwb3J0IGludGVyZmFjZSBQbGF5ZXJPcHRpb25zIHtcbiAgcGxhdGZvcm0/OiBOb2RlSlMuUGxhdGZvcm1cbiAgcnVubmVyOiBSdW5uZXJcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQbGF5ZXIge1xuICBpbml0KCk6IFByb21pc2U8dm9pZD5cbiAgcGxheShcbiAgICBhdWRpbzogQnVmZmVyIHwgUmVhZGFibGVTdHJlYW08VWludDhBcnJheT4sXG4gICAgY29udGVudFR5cGU6IHN0cmluZyxcbiAgICBzaWduYWw6IEFib3J0U2lnbmFsLFxuICApOiBQcm9taXNlPHZvaWQ+XG59XG5cbmNvbnN0IExJTlVYX1BMQVlFUlMgPSBbXCJwYXBsYXlcIiwgXCJhcGxheVwiLCBcImZmcGxheVwiXSBhcyBjb25zdFxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlUGxheWVyKG9wdHM6IFBsYXllck9wdGlvbnMpOiBQbGF5ZXIge1xuICBjb25zdCBwbGF0Zm9ybSA9IG9wdHMucGxhdGZvcm0gPz8gcHJvY2Vzcy5wbGF0Zm9ybVxuICBsZXQgYmluYXJ5OiBzdHJpbmcgfCBudWxsID0gbnVsbFxuXG4gIGFzeW5jIGZ1bmN0aW9uIGJ1ZmZlcihzdHJlYW06IEJ1ZmZlciB8IFJlYWRhYmxlU3RyZWFtPFVpbnQ4QXJyYXk+LCBzaWduYWw6IEFib3J0U2lnbmFsKTogUHJvbWlzZTxCdWZmZXI+IHtcbiAgICBpZiAoQnVmZmVyLmlzQnVmZmVyKHN0cmVhbSkpIHJldHVybiBzdHJlYW1cbiAgICBjb25zdCBjaHVua3M6IFVpbnQ4QXJyYXlbXSA9IFtdXG4gICAgY29uc3QgcmVhZGVyID0gc3RyZWFtLmdldFJlYWRlcigpXG4gICAgdHJ5IHtcbiAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgIGlmIChzaWduYWwuYWJvcnRlZCkgdGhyb3cgbmV3IERPTUV4Y2VwdGlvbihcImFib3J0ZWRcIiwgXCJBYm9ydEVycm9yXCIpXG4gICAgICAgIGNvbnN0IHsgZG9uZSwgdmFsdWUgfSA9IGF3YWl0IHJlYWRlci5yZWFkKClcbiAgICAgICAgaWYgKGRvbmUpIGJyZWFrXG4gICAgICAgIGlmICh2YWx1ZSkgY2h1bmtzLnB1c2godmFsdWUpXG4gICAgICB9XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGlmIChzaWduYWwuYWJvcnRlZCkgYXdhaXQgcmVhZGVyLmNhbmNlbCgpLmNhdGNoKCgpID0+IHVuZGVmaW5lZClcbiAgICB9XG4gICAgcmV0dXJuIEJ1ZmZlci5jb25jYXQoY2h1bmtzLm1hcCgoYykgPT4gQnVmZmVyLmZyb20oYykpKVxuICB9XG5cbiAgYXN5bmMgZnVuY3Rpb24gd3JpdGVUZW1wKGJ1ZjogQnVmZmVyLCBjb250ZW50VHlwZTogc3RyaW5nKTogUHJvbWlzZTx7IGRpcjogc3RyaW5nOyBwYXRoOiBzdHJpbmcgfT4ge1xuICAgIGNvbnN0IGV4dCA9IGNvbnRlbnRUeXBlLmluY2x1ZGVzKFwibXBlZ1wiKVxuICAgICAgPyBcIm1wM1wiXG4gICAgICA6IGNvbnRlbnRUeXBlLmluY2x1ZGVzKFwid2F2XCIpXG4gICAgICAgID8gXCJ3YXZcIlxuICAgICAgICA6IFwiYmluXCJcbiAgICBjb25zdCBkaXIgPSBhd2FpdCBta2R0ZW1wKGpvaW4odG1wZGlyKCksIGAke1BMVUdJTl9OQU1FfS1gKSlcbiAgICBjb25zdCBwYXRoID0gam9pbihkaXIsIGBhdWRpby4ke2V4dH1gKVxuICAgIGF3YWl0IHdyaXRlRmlsZShwYXRoLCBidWYpXG4gICAgcmV0dXJuIHsgZGlyLCBwYXRoIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIHBvd2Vyc2hlbGxFbmNvZGVkQ29tbWFuZChwYXRoOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IHNhZmVQYXRoID0gSlNPTi5zdHJpbmdpZnkocGF0aC5yZXBsYWNlKC9cXFxcL2csIFwiL1wiKSlcbiAgICBjb25zdCBzY3JpcHQgPSBbXG4gICAgICBcIkFkZC1UeXBlIC1Bc3NlbWJseU5hbWUgcHJlc2VudGF0aW9uQ29yZVwiLFxuICAgICAgXCIkcCA9IE5ldy1PYmplY3QgU3lzdGVtLldpbmRvd3MuTWVkaWEuTWVkaWFQbGF5ZXJcIixcbiAgICAgIGAkcC5PcGVuKFtVcmldJHtzYWZlUGF0aH0pYCxcbiAgICAgIFwiJHAuUGxheSgpXCIsXG4gICAgICBcIlN0YXJ0LVNsZWVwIC1TZWNvbmRzIDMwXCIsXG4gICAgXS5qb2luKFwiOyBcIilcbiAgICByZXR1cm4gQnVmZmVyLmZyb20oc2NyaXB0LCBcInV0ZjE2bGVcIikudG9TdHJpbmcoXCJiYXNlNjRcIilcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgYXN5bmMgaW5pdCgpIHtcbiAgICAgIGlmIChwbGF0Zm9ybSA9PT0gXCJkYXJ3aW5cIikge1xuICAgICAgICBpZiAoIShhd2FpdCBvcHRzLnJ1bm5lci5oYXMoXCJhZnBsYXlcIikpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTm8gYXVkaW8gcGxheWVyIGF2YWlsYWJsZSAobmVlZCBgYWZwbGF5YClcIilcbiAgICAgICAgfVxuICAgICAgICBiaW5hcnkgPSBcImFmcGxheVwiXG4gICAgICB9IGVsc2UgaWYgKHBsYXRmb3JtID09PSBcImxpbnV4XCIpIHtcbiAgICAgICAgZm9yIChjb25zdCBiIG9mIExJTlVYX1BMQVlFUlMpIHtcbiAgICAgICAgICBpZiAoYXdhaXQgb3B0cy5ydW5uZXIuaGFzKGIpKSB7XG4gICAgICAgICAgICBiaW5hcnkgPSBiXG4gICAgICAgICAgICBicmVha1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoIWJpbmFyeSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIFwiTm8gYXVkaW8gcGxheWVyIGF2YWlsYWJsZSAobmVlZCBvbmUgb2Y6IHBhcGxheSwgYXBsYXksIGZmcGxheSlcIixcbiAgICAgICAgICApXG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAocGxhdGZvcm0gPT09IFwid2luMzJcIikge1xuICAgICAgICBpZiAoIShhd2FpdCBvcHRzLnJ1bm5lci5oYXMoXCJwb3dlcnNoZWxsXCIpKSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk5vIGF1ZGlvIHBsYXllciBhdmFpbGFibGUgKG5lZWQgYHBvd2Vyc2hlbGxgKVwiKVxuICAgICAgICB9XG4gICAgICAgIGJpbmFyeSA9IFwicG93ZXJzaGVsbFwiXG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIHBsYXRmb3JtIGZvciBhdWRpbyBwbGF5YmFjazogJHtwbGF0Zm9ybX1gKVxuICAgICAgfVxuICAgIH0sXG5cbiAgICBhc3luYyBwbGF5KGF1ZGlvLCBjb250ZW50VHlwZSwgc2lnbmFsKSB7XG4gICAgICBpZiAoIWJpbmFyeSkgdGhyb3cgbmV3IEVycm9yKFwiQXVkaW8gcGxheWVyIG5vdCBpbml0aWFsaXplZFwiKVxuICAgICAgaWYgKHNpZ25hbC5hYm9ydGVkKSB0aHJvdyBuZXcgRE9NRXhjZXB0aW9uKFwiYWJvcnRlZFwiLCBcIkFib3J0RXJyb3JcIilcbiAgICAgIGNvbnN0IGJ1ZiA9IGF3YWl0IGJ1ZmZlcihhdWRpbywgc2lnbmFsKVxuICAgICAgY29uc3QgdG1wID0gYXdhaXQgd3JpdGVUZW1wKGJ1ZiwgY29udGVudFR5cGUpXG4gICAgICBsZXQgY21kOiBzdHJpbmdbXVxuICAgICAgaWYgKGJpbmFyeSA9PT0gXCJwb3dlcnNoZWxsXCIpIHtcbiAgICAgICAgY21kID0gW1xuICAgICAgICAgIFwicG93ZXJzaGVsbFwiLFxuICAgICAgICAgIFwiLU5vUHJvZmlsZVwiLFxuICAgICAgICAgIFwiLUVuY29kZWRDb21tYW5kXCIsXG4gICAgICAgICAgcG93ZXJzaGVsbEVuY29kZWRDb21tYW5kKHRtcC5wYXRoKSxcbiAgICAgICAgXVxuICAgICAgfSBlbHNlIGlmIChiaW5hcnkgPT09IFwiZmZwbGF5XCIpIHtcbiAgICAgICAgY21kID0gW1wiZmZwbGF5XCIsIFwiLWF1dG9leGl0XCIsIFwiLW5vZGlzcFwiLCBcIi1sb2dsZXZlbFwiLCBcInF1aWV0XCIsIHRtcC5wYXRoXVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY21kID0gW2JpbmFyeSwgdG1wLnBhdGhdXG4gICAgICB9XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBvcHRzLnJ1bm5lci5ydW4oY21kLCBzaWduYWwpXG4gICAgICAgIGlmIChyZXN1bHQuZXhpdENvZGUgIT09IDApIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGF1ZGlvIHBsYXliYWNrIGZhaWxlZCB3aXRoIGV4aXQgY29kZSAke3Jlc3VsdC5leGl0Q29kZX1gKVxuICAgICAgICB9XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBhd2FpdCBybSh0bXAuZGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSlcbiAgICAgIH1cbiAgICB9LFxuICB9XG59XG4iLCAiLyoqXG4gKiBTaGFyZWQgYFJ1bm5lcmAgYWJzdHJhY3Rpb24gdXNlZCBieSB0aGUgYXVkaW8gcGxheWVyLiBBIFJ1bm5lciBrbm93cyBob3cgdG86XG4gKiAgIC0gcHJvYmUgdGhlIFBBVEggZm9yIGFuIGV4ZWN1dGFibGVcbiAqICAgLSBzcGF3biBhIHByb2Nlc3Mgd2l0aCBhYm9ydCBzdXBwb3J0XG4gKlxuICogVGhlIGF1ZGlvIHBsYXllciB1c2VzIHRoaXMgdG8gaW52b2tlIGBhZnBsYXlgIC8gYHBhcGxheWAgLyBgYXBsYXlgIC9cbiAqIGBmZnBsYXlgIC8gUG93ZXJTaGVsbCB0byBwbGF5IHRoZSBhdWRpbyBieXRlcyByZXR1cm5lZCBieSB0aGUgVFRTXG4gKiBwcm92aWRlci4gYHNyYy9pbmRleC50c2AgY29uc3RydWN0cyBvbmUgdmlhIGBkZWZhdWx0UnVubmVyKClgIGFuZCBoYW5kc1xuICogaXQgdG8gYGNyZWF0ZVBsYXllcigpYC5cbiAqL1xuXG5leHBvcnQgaW50ZXJmYWNlIFJ1bm5lciB7XG4gIGhhcyhiaW5hcnk6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj5cbiAgcnVuKGNtZDogc3RyaW5nW10sIHNpZ25hbDogQWJvcnRTaWduYWwpOiBQcm9taXNlPHsgZXhpdENvZGU6IG51bWJlciB9PlxufVxuXG4vKiogRGVmYXVsdCBydW5uZXI6IHVzZXMgTm9kZSdzIGNoaWxkX3Byb2Nlc3MgYW5kIFBBVEgtYmFzZWQgYmluYXJ5IGxvb2t1cC4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBkZWZhdWx0UnVubmVyKCk6IFByb21pc2U8UnVubmVyPiB7XG4gIGNvbnN0IHsgc3Bhd24gfSA9IGF3YWl0IGltcG9ydChcIm5vZGU6Y2hpbGRfcHJvY2Vzc1wiKVxuICBjb25zdCB7IGFjY2VzcywgY29uc3RhbnRzIH0gPSBhd2FpdCBpbXBvcnQoXCJub2RlOmZzL3Byb21pc2VzXCIpXG4gIGNvbnN0IHsgZGVsaW1pdGVyLCBzZXAgfSA9IGF3YWl0IGltcG9ydChcIm5vZGU6cGF0aFwiKVxuXG4gIGFzeW5jIGZ1bmN0aW9uIGhhcyhiaW5hcnk6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IFBBVEggPSBwcm9jZXNzLmVudi5QQVRIID8/IFwiXCJcbiAgICBjb25zdCBleHRzID1cbiAgICAgIHByb2Nlc3MucGxhdGZvcm0gPT09IFwid2luMzJcIlxuICAgICAgICA/IChwcm9jZXNzLmVudi5QQVRIRVhUID8/IFwiLkVYRTsuQ01EOy5CQVRcIikuc3BsaXQoXCI7XCIpXG4gICAgICAgIDogW1wiXCJdXG4gICAgZm9yIChjb25zdCBkaXIgb2YgUEFUSC5zcGxpdChkZWxpbWl0ZXIpKSB7XG4gICAgICBmb3IgKGNvbnN0IGV4dCBvZiBleHRzKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgYWNjZXNzKGAke2Rpcn0ke3NlcH0ke2JpbmFyeX0ke2V4dH1gLCBjb25zdGFudHMuWF9PSylcbiAgICAgICAgICByZXR1cm4gdHJ1ZVxuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAvKiBrZWVwIHNlYXJjaGluZyAqL1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBmYWxzZVxuICB9XG5cbiAgY29uc3QgQUJPUlRfS0lMTF9NUyA9IDEwMDBcblxuICBhc3luYyBmdW5jdGlvbiBydW4oY21kOiBzdHJpbmdbXSwgc2lnbmFsOiBBYm9ydFNpZ25hbCk6IFByb21pc2U8eyBleGl0Q29kZTogbnVtYmVyIH0+IHtcbiAgICBpZiAoc2lnbmFsLmFib3J0ZWQpIHRocm93IG5ldyBET01FeGNlcHRpb24oXCJhYm9ydGVkXCIsIFwiQWJvcnRFcnJvclwiKVxuICAgIHJldHVybiBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBjaGlsZCA9IHNwYXduKGNtZFswXSwgY21kLnNsaWNlKDEpLCB7IHN0ZGlvOiBcImlnbm9yZVwiIH0pXG4gICAgICBsZXQga2lsbFRpbWVyOiBOb2RlSlMuVGltZW91dCB8IHVuZGVmaW5lZFxuICAgICAgY29uc3QgY2xlYW51cCA9ICgpID0+IHtcbiAgICAgICAgc2lnbmFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCBvbkFib3J0KVxuICAgICAgICBpZiAoa2lsbFRpbWVyKSBjbGVhclRpbWVvdXQoa2lsbFRpbWVyKVxuICAgICAgfVxuICAgICAgY29uc3Qgb25BYm9ydCA9ICgpID0+IHtcbiAgICAgICAgY2hpbGQua2lsbChcIlNJR1RFUk1cIilcbiAgICAgICAga2lsbFRpbWVyID0gc2V0VGltZW91dCgoKSA9PiBjaGlsZC5raWxsKFwiU0lHS0lMTFwiKSwgQUJPUlRfS0lMTF9NUylcbiAgICAgIH1cbiAgICAgIHNpZ25hbC5hZGRFdmVudExpc3RlbmVyKFwiYWJvcnRcIiwgb25BYm9ydClcbiAgICAgIGNoaWxkLm9uKFwiZXJyb3JcIiwgKGUpID0+IHtcbiAgICAgICAgY2xlYW51cCgpXG4gICAgICAgIHJlamVjdChlKVxuICAgICAgfSlcbiAgICAgIGNoaWxkLm9uKFwiZXhpdFwiLCAoY29kZSkgPT4ge1xuICAgICAgICBjbGVhbnVwKClcbiAgICAgICAgaWYgKHNpZ25hbC5hYm9ydGVkKSByZWplY3QobmV3IERPTUV4Y2VwdGlvbihcImFib3J0ZWRcIiwgXCJBYm9ydEVycm9yXCIpKVxuICAgICAgICBlbHNlIGlmICgoY29kZSA/PyAwKSAhPT0gMCkgcmVqZWN0KG5ldyBFcnJvcihgcHJvY2VzcyBleGl0ZWQgd2l0aCBjb2RlICR7Y29kZSA/PyAwfWApKVxuICAgICAgICBlbHNlIHJlc29sdmUoeyBleGl0Q29kZTogMCB9KVxuICAgICAgfSlcbiAgICB9KVxuICB9XG5cbiAgcmV0dXJuIHsgaGFzLCBydW4gfVxufVxuIiwgImltcG9ydCB7IHJhbmRvbVVVSUQgfSBmcm9tIFwibm9kZTpjcnlwdG9cIlxuaW1wb3J0IHsgUHJpb3JpdHksIHR5cGUgU3BlZWNoUmVxdWVzdCB9IGZyb20gXCIuLi9xdWV1ZS90eXBlcy5qc1wiXG5pbXBvcnQgeyByZW5kZXJUZW1wbGF0ZSwgc3RyaXBNYXJrZG93biwgdHJ1bmNhdGUgfSBmcm9tIFwiLi90ZW1wbGF0ZS5qc1wiXG5pbXBvcnQgdHlwZSB7IE5hcnJhdG9yLCBOYXJyYXRpb25Db250ZXh0IH0gZnJvbSBcIi4vbmFycmF0b3IuanNcIlxuaW1wb3J0IHsgcXVldWVQcmlvcml0eUZvckV2ZW50IH0gZnJvbSBcIi4uL2V2ZW50cy9jYXRhbG9nLmpzXCJcblxuZXhwb3J0IGludGVyZmFjZSBFdmVudENvbmZpZyB7XG4gIGVuYWJsZWQ6IGJvb2xlYW5cbiAgbW9kZTogXCJ0ZW1wbGF0ZVwiIHwgXCJuYXJyYXRlXCIgfCBcInZlcmJhdGltXCJcbiAgcHJpb3JpdHk/OiBcInVyZ2VudFwiIHwgXCJub3JtYWxcIiB8IFwiY2hhdHR5XCJcbn1cblxuZXhwb3J0IGludGVyZmFjZSBIYW5kbGVyUmVnaXN0cnlPcHRpb25zIHtcbiAgZXZlbnRzOiBSZWNvcmQ8c3RyaW5nLCBFdmVudENvbmZpZz5cbiAgbmFycmF0b3I6IE5hcnJhdG9yXG4gIGdldENvbnRleHQ6ICgpID0+IE5hcnJhdGlvbkNvbnRleHRcbn1cblxuZXhwb3J0IGludGVyZmFjZSBIYW5kbGVyUmVnaXN0cnkge1xuICBoYW5kbGUoZXZlbnQ6IHsgdHlwZTogc3RyaW5nOyBbazogc3RyaW5nXTogdW5rbm93biB9KTogUHJvbWlzZTxTcGVlY2hSZXF1ZXN0IHwgbnVsbD5cbn1cblxudHlwZSBSZW5kZXJNb2RlID0gRXZlbnRDb25maWdbXCJtb2RlXCJdXG50eXBlIFJlbmRlckNvbnRleHQgPSBQaWNrPEhhbmRsZXJSZWdpc3RyeU9wdGlvbnMsIFwibmFycmF0b3JcIiB8IFwiZ2V0Q29udGV4dFwiPlxudHlwZSBNb2RlUmVuZGVyZXIgPSAoXG4gIGV2ZW50OiB7IHR5cGU6IHN0cmluZzsgW2s6IHN0cmluZ106IHVua25vd24gfSxcbiAgY3R4OiBSZW5kZXJDb250ZXh0LFxuKSA9PiBQcm9taXNlPHN0cmluZyB8IG51bGw+IHwgc3RyaW5nIHwgbnVsbFxuXG5jb25zdCBNT0RFX1JFTkRFUkVSUzogUmVjb3JkPFJlbmRlck1vZGUsIE1vZGVSZW5kZXJlcj4gPSB7XG4gIHRlbXBsYXRlOiAoZXZlbnQpID0+IHJlbmRlclRlbXBsYXRlKGV2ZW50KSxcbiAgbmFycmF0ZTogYXN5bmMgKGV2ZW50LCBjdHgpID0+IHtcbiAgICBjb25zdCB0ZXh0ID0gYXdhaXQgY3R4Lm5hcnJhdG9yLnN1bW1hcml6ZShldmVudCwgY3R4LmdldENvbnRleHQoKSlcbiAgICByZXR1cm4gdGV4dCA/PyByZW5kZXJUZW1wbGF0ZShldmVudClcbiAgfSxcbiAgdmVyYmF0aW06IChldmVudCkgPT4gdHJ1bmNhdGUoc3RyaXBNYXJrZG93bihTdHJpbmcoZXZlbnQudGV4dCA/PyBcIlwiKSksIDMwMCksXG59XG5cbmZ1bmN0aW9uIHByaW9yaXR5RnJvbU5hbWUobmFtZT86IHN0cmluZyk6IFByaW9yaXR5IHwgbnVsbCB7XG4gIGlmIChuYW1lID09PSBcInVyZ2VudFwiKSByZXR1cm4gUHJpb3JpdHkuVVJHRU5UXG4gIGlmIChuYW1lID09PSBcIm5vcm1hbFwiKSByZXR1cm4gUHJpb3JpdHkuTk9STUFMXG4gIGlmIChuYW1lID09PSBcImNoYXR0eVwiKSByZXR1cm4gUHJpb3JpdHkuQ0hBVFRZXG4gIHJldHVybiBudWxsXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVIYW5kbGVyUmVnaXN0cnkob3B0czogSGFuZGxlclJlZ2lzdHJ5T3B0aW9ucyk6IEhhbmRsZXJSZWdpc3RyeSB7XG4gIHJldHVybiB7XG4gICAgYXN5bmMgaGFuZGxlKGV2ZW50KSB7XG4gICAgICBjb25zdCBjZmcgPSBvcHRzLmV2ZW50c1tldmVudC50eXBlXVxuICAgICAgaWYgKCFjZmcgfHwgIWNmZy5lbmFibGVkKSByZXR1cm4gbnVsbFxuXG4gICAgICBjb25zdCB0ZXh0ID0gYXdhaXQgTU9ERV9SRU5ERVJFUlNbY2ZnLm1vZGVdKGV2ZW50LCBvcHRzKVxuICAgICAgaWYgKCF0ZXh0KSByZXR1cm4gbnVsbFxuXG4gICAgICBjb25zdCBwcmlvcml0eSA9XG4gICAgICAgIHByaW9yaXR5RnJvbU5hbWUoY2ZnLnByaW9yaXR5KSA/P1xuICAgICAgICBxdWV1ZVByaW9yaXR5Rm9yRXZlbnQoZXZlbnQudHlwZSlcbiAgICAgIGNvbnN0IG92ZXJyaWRlS2V5ID0gKGV2ZW50IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KS5kZWR1cEtleVxuICAgICAgY29uc3QgZGVkdXBLZXkgPSB0eXBlb2Ygb3ZlcnJpZGVLZXkgPT09IFwic3RyaW5nXCIgPyBvdmVycmlkZUtleSA6IGV2ZW50LnR5cGVcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGlkOiByYW5kb21VVUlEKCksXG4gICAgICAgIHByaW9yaXR5LFxuICAgICAgICB0ZXh0LFxuICAgICAgICBkZWR1cEtleSxcbiAgICAgICAgZW5xdWV1ZWRBdDogRGF0ZS5ub3coKSxcbiAgICAgIH1cbiAgICB9LFxuICB9XG59XG4iLCAiZXhwb3J0IGludGVyZmFjZSBBbnlFdmVudCB7XG4gIHR5cGU6IHN0cmluZ1xuICBba2V5OiBzdHJpbmddOiB1bmtub3duXG59XG5cbmV4cG9ydCBmdW5jdGlvbiB0cnVuY2F0ZShzOiBzdHJpbmcsIG1heDogbnVtYmVyKTogc3RyaW5nIHtcbiAgaWYgKHMubGVuZ3RoIDw9IG1heCkgcmV0dXJuIHNcbiAgcmV0dXJuIHMuc2xpY2UoMCwgbWF4KSArIFwiXHUyMDI2XCJcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHN0cmlwTWFya2Rvd24odGV4dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIHRleHRcbiAgICAucmVwbGFjZSgvYGBgW1xcc1xcU10qP2BgYC9nLCBcIlwiKSAgICAgICAgICAvLyBmZW5jZWQgY29kZVxuICAgIC5yZXBsYWNlKC9gKFteYF0rKWAvZywgXCIkMVwiKSAgICAgICAgICAgICAvLyBpbmxpbmUgY29kZVxuICAgIC5yZXBsYWNlKC9cXCpcXCooW14qXSspXFwqXFwqL2csIFwiJDFcIikgICAgICAgLy8gYm9sZFxuICAgIC5yZXBsYWNlKC9cXCooW14qXSspXFwqL2csIFwiJDFcIikgICAgICAgICAgIC8vIGl0YWxpY1xuICAgIC5yZXBsYWNlKC9fXyhbXl9dKylfXy9nLCBcIiQxXCIpICAgICAgICAgICAvLyBib2xkXG4gICAgLnJlcGxhY2UoL18oW15fXSspXy9nLCBcIiQxXCIpICAgICAgICAgICAgIC8vIGl0YWxpY1xuICAgIC5yZXBsYWNlKC8hXFxbW15cXF1dKlxcXVxcKFteKV0qXFwpL2csIFwiXCIpICAgIC8vIGltYWdlc1xuICAgIC5yZXBsYWNlKC9cXFsoW15cXF1dKylcXF1cXChbXildKlxcKS9nLCBcIiQxXCIpIC8vIGxpbmtzXG4gICAgLnJlcGxhY2UoL14jK1xccysvZ20sIFwiXCIpICAgICAgICAgICAgICAgICAvLyBoZWFkaW5nc1xuICAgIC5yZXBsYWNlKC9eXFxzKlstKitdXFxzKy9nbSwgXCJcIikgICAgICAgICAgIC8vIGxpc3QgYnVsbGV0c1xuICAgIC5yZXBsYWNlKC9cXHMrL2csIFwiIFwiKVxuICAgIC50cmltKClcbn1cblxudHlwZSBSZW5kZXJlciA9IChlOiBBbnlFdmVudCkgPT4gc3RyaW5nXG5cbmZ1bmN0aW9uIGJhc2VuYW1lKHA6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IHRyaW1tZWQgPSBwLnJlcGxhY2UoL1tcXFxcL10rJC8sIFwiXCIpXG4gIGNvbnN0IGkgPSBNYXRoLm1heCh0cmltbWVkLmxhc3RJbmRleE9mKFwiL1wiKSwgdHJpbW1lZC5sYXN0SW5kZXhPZihcIlxcXFxcIikpXG4gIHJldHVybiBpID49IDAgPyB0cmltbWVkLnNsaWNlKGkgKyAxKSA6IHRyaW1tZWRcbn1cblxuZnVuY3Rpb24gYXNTdHJpbmcodjogdW5rbm93bik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIHJldHVybiB0eXBlb2YgdiA9PT0gXCJzdHJpbmdcIiAmJiB2Lmxlbmd0aCA+IDAgPyB2IDogdW5kZWZpbmVkXG59XG5cbmNvbnN0IHRlbXBsYXRlczogUmVjb3JkPHN0cmluZywgUmVuZGVyZXI+ID0ge1xuICAvLyAtLS0gUmVhbCBPcGVuQ29kZSBldmVudHMgLS0tXG4gIFwic2Vzc2lvbi5pZGxlXCI6ICAgICAgICAgKCkgID0+IFwiSSdtIGlkbGUgbm93IGFuZCB3YWl0aW5nIGZvciB5b3VyIG5leHQgaW5zdHJ1Y3Rpb24uXCIsXG4gIFwic2Vzc2lvbi5lcnJvclwiOiAgICAgICAgKGUpID0+XG4gICAgYEkgaGl0IGEgc2Vzc2lvbiBlcnJvcjogJHt0cnVuY2F0ZShTdHJpbmcoZS5tZXNzYWdlID8/IFwidW5rbm93blwiKSwgMjAwKX0uIENoZWNrIHRoZSBsb2cgZm9yIGRldGFpbHMuYCxcbiAgXCJzZXNzaW9uLmNvbXBhY3RlZFwiOiAgICAoKSAgPT5cbiAgICBcIkkgY29tcGFjdGVkIHRoZSBzZXNzaW9uLCBzbyBvbGRlciBjb250ZXh0IGlzIHN1bW1hcml6ZWQgYW5kIEkgaGF2ZSBtb3JlIHJvb20gdG8gY29udGludWUuXCIsXG4gIFwic2Vzc2lvbi5jcmVhdGVkXCI6ICAgICAgKCkgPT4gXCJJJ20gc3RhcnRpbmcgYSBuZXcgc2Vzc2lvbiBhbmQgZ2V0dGluZyByZWFkeSB0byB3b3JrLlwiLFxuICBcInBlcm1pc3Npb24uYXNrZWRcIjogICAgIChlKSA9PlxuICAgIGBJIG5lZWQgeW91ciBhcHByb3ZhbCBiZWZvcmUgSSB1c2UgJHthc1N0cmluZyhlLnRvb2wpID8/IFwiYW4gb3BlcmF0aW9uXCJ9LmAsXG4gIFwicGVybWlzc2lvbi5yZXBsaWVkXCI6ICAgKGUpID0+IHtcbiAgICBjb25zdCByYXcgPSBTdHJpbmcoZS5kZWNpc2lvbiA/PyBcInJlc3BvbmRlZFwiKS50b0xvd2VyQ2FzZSgpXG4gICAgY29uc3QgdmVyYiA9XG4gICAgICByYXcgPT09IFwiYWxsb3dcIiB8fCByYXcgPT09IFwiYXBwcm92ZVwiIHx8IHJhdyA9PT0gXCJhY2NlcHRcIiB8fCByYXcgPT09IFwieWVzXCIgfHxcbiAgICAgIHJhdyA9PT0gXCJvbmNlXCIgfHwgcmF3ID09PSBcImFsd2F5c1wiXG4gICAgICAgID8gXCJncmFudGVkXCJcbiAgICAgICAgOiByYXcgPT09IFwiZGVueVwiIHx8IHJhdyA9PT0gXCJyZWplY3RcIiB8fCByYXcgPT09IFwibm9cIlxuICAgICAgICAgID8gXCJkZW5pZWRcIlxuICAgICAgICAgIDogcmF3XG4gICAgY29uc3QgdG9vbCA9IGFzU3RyaW5nKGUudG9vbCkgPz8gXCJ0aGUgb3BlcmF0aW9uXCJcbiAgICBpZiAodmVyYiA9PT0gXCJncmFudGVkXCIpIHJldHVybiBgSSBnb3QgYXBwcm92YWwgdG8gdXNlICR7dG9vbH0uYFxuICAgIGlmICh2ZXJiID09PSBcImRlbmllZFwiKSByZXR1cm4gYEkgd2FzIGRlbmllZCBwZXJtaXNzaW9uIHRvIHVzZSAke3Rvb2x9LmBcbiAgICBpZiAodmVyYiA9PT0gXCJyZXNwb25kZWRcIikgcmV0dXJuIGBJIGdvdCBhIHJlc3BvbnNlIGZvciAke3Rvb2x9LmBcbiAgICByZXR1cm4gYEkgZ290IGEgcGVybWlzc2lvbiByZXNwb25zZSBmb3IgJHt0b29sfTogJHt2ZXJifS5gXG4gIH0sXG4gIFwidG9vbC5leGVjdXRlLmJlZm9yZVwiOiAgKGUpID0+IGBJJ20gcnVubmluZyAke2FzU3RyaW5nKGUudG9vbCkgPz8gXCJ0b29sXCJ9IG5vdy5gLFxuICBcInRvb2wuZXhlY3V0ZS5hZnRlclwiOiAgIChlKSA9PiBgSSBmaW5pc2hlZCBydW5uaW5nICR7YXNTdHJpbmcoZS50b29sKSA/PyBcInRvb2xcIn0uYCxcbiAgXCJmaWxlLmVkaXRlZFwiOiAgICAgICAgICAoZSkgPT4ge1xuICAgIGNvbnN0IHJhdyA9IFN0cmluZyhlLmZpbGUgPz8gXCJcIilcbiAgICByZXR1cm4gcmF3ID8gYEkgZWRpdGVkICR7YmFzZW5hbWUocmF3KX0uYCA6IFwiSSBlZGl0ZWQgYSBmaWxlLlwiXG4gIH0sXG4gIFwiY29tbWFuZC5leGVjdXRlZFwiOiAgICAgKGUpID0+IHtcbiAgICBjb25zdCBuYW1lID0gU3RyaW5nKGUuY29tbWFuZCA/PyBcIlwiKS50cmltKClcbiAgICByZXR1cm4gbmFtZSA/IGBJIHJhbiAke25hbWV9LmAgOiBcIkkgcmFuIGEgY29tbWFuZC5cIlxuICB9LFxuICAvLyBOb3RlOiBgbWVzc2FnZS51cGRhdGVkYCBjYXJyaWVzIGB7IHNlc3Npb25JRCwgaW5mbzogTWVzc2FnZSB9YCBcdTIwMTQgdGhlXG4gIC8vIG1lc3NhZ2UgdGV4dCBsaXZlcyBpbiBgaW5mby5wYXJ0c2AsIG5vdCBhdCB0aGUgdG9wIGxldmVsLiBMaXZlIG5hcnJhdGlvblxuICAvLyBpcyBoYW5kbGVkIGJ5IHRoZSBzeW50aGVzaXplZCBgbWVzc2FnZS50ZXh0LmRlbHRhYCBldmVudHMgZGVyaXZlZCBmcm9tXG4gIC8vIGBtZXNzYWdlLnBhcnQudXBkYXRlZGAsIHNvIHRoZXJlIGlzIGludGVudGlvbmFsbHkgbm8gdGVtcGxhdGUgaGVyZS5cblxuICAvLyAtLS0gU3ludGhlc2l6ZWQgYnkgc3JjL2Rpc3BhdGNoZXIudHMgLS0tXG4gIFwibWVzc2FnZS50ZXh0LmRlbHRhXCI6ICAgICAgKGUpID0+IHRydW5jYXRlKHN0cmlwTWFya2Rvd24oU3RyaW5nKGUudGV4dCA/PyBcIlwiKSksIDYwMCksXG4gIFwibWVzc2FnZS5yZWFzb25pbmcuZGVsdGFcIjogKGUpID0+IHRydW5jYXRlKHN0cmlwTWFya2Rvd24oU3RyaW5nKGUudGV4dCA/PyBcIlwiKSksIDYwMCksXG4gIFwidG9kby5jb21wbGV0ZWQuYWxsXCI6ICAgKGUpID0+IHtcbiAgICBjb25zdCBuID0gTnVtYmVyKGUuY291bnQgPz8gMClcbiAgICByZXR1cm4gbiA+IDBcbiAgICAgID8gYEkndmUgY29tcGxldGVkIGFsbCAke259IHRvZG9zLiBOaWNlIHdvcmsuYFxuICAgICAgOiBcIkkndmUgY29tcGxldGVkIGFsbCB0b2Rvcy4gTmljZSB3b3JrLlwiXG4gIH0sXG4gIFwidG9kby5jb21wbGV0ZWQuaXRlbVwiOiAgKGUpID0+XG4gICAgYEkgZmluaXNoZWQgdGhpcyB0YXNrOiAke3RydW5jYXRlKHN0cmlwTWFya2Rvd24oU3RyaW5nKGUuY29udGVudCA/PyBcIlwiKSksIDgwKX0uYCxcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlbmRlclRlbXBsYXRlKGV2ZW50OiBBbnlFdmVudCk6IHN0cmluZyB8IG51bGwge1xuICBjb25zdCBmbiA9IHRlbXBsYXRlc1tldmVudC50eXBlXVxuICBpZiAoIWZuKSByZXR1cm4gbnVsbFxuICBjb25zdCBvdXQgPSBmbihldmVudClcbiAgcmV0dXJuIG91dC5sZW5ndGggPT09IDAgPyBudWxsIDogb3V0XG59XG4iLCAiaW1wb3J0IHsgZ2VuZXJhdGVUZXh0LCB0eXBlIExhbmd1YWdlTW9kZWwgfSBmcm9tIFwiYWlcIlxuaW1wb3J0IHsgdHJ1bmNhdGUgfSBmcm9tIFwiLi90ZW1wbGF0ZS5qc1wiXG5pbXBvcnQgdHlwZSB7IExvZ2dlciB9IGZyb20gXCIuLi9sb2cuanNcIlxuaW1wb3J0IHsgRVZFTlRfU1BFQ1MsIHR5cGUgRXZlbnRTcGVjLCB0eXBlIEV2ZW50VHlwZSB9IGZyb20gXCIuLi9ldmVudHMvY2F0YWxvZy5qc1wiXG5cbmV4cG9ydCBpbnRlcmZhY2UgTmFycmF0aW9uQ29udGV4dCB7XG4gIGFzc2lzdGFudFRleHQ6IHN0cmluZ1xuICByZWNlbnRUb29sczogc3RyaW5nW11cbn1cblxuZXhwb3J0IGludGVyZmFjZSBOYXJyYXRvckNvbmZpZyB7XG4gIHRpbWVvdXRNczogbnVtYmVyXG4gIG1pbkludGVydmFsTXM6IG51bWJlclxufVxuXG5leHBvcnQgaW50ZXJmYWNlIE5hcnJhdG9yIHtcbiAgc3VtbWFyaXplKFxuICAgIGV2ZW50OiB7IHR5cGU6IHN0cmluZzsgW2s6IHN0cmluZ106IHVua25vd24gfSxcbiAgICBjdHg6IE5hcnJhdGlvbkNvbnRleHQsXG4gICk6IFByb21pc2U8c3RyaW5nIHwgbnVsbD5cbn1cblxuLy8gU3RhYmxlIGluc3RydWN0aW9ucy4gS2VwdCBzZXBhcmF0ZSBmcm9tIHRoZSBwZXItZXZlbnQgY29udGV4dCBzbyB0aGUgbW9kZWxcbi8vIHRyZWF0cyB0aGUgY29udGV4dCBhcyBkYXRhIChub3QgaW5zdHJ1Y3Rpb25zKSBhbmQgc28gdGhpcyBibG9jayBjYW4gYmVcbi8vIHByb21wdC1jYWNoZWQuIFdyaXR0ZW4gaW4gYSBzaW5nbGUgdm9pY2U6IHRoZSBtb2RlbCAqaXMqIHRoZSBhZ2VudC5cbmNvbnN0IFNZU1RFTV9QUk9NUFQgPSBbXG4gIFwiWW91IGFyZSB0aGUgY29kaW5nIGFnZW50LiBZb3VyIHdvcmRzIGFyZSByZWFkIGFsb3VkIGJ5IGEgdGV4dC10by1zcGVlY2ggZW5naW5lIHdoaWxlIHRoZVwiLFxuICBcInVzZXIgbG9va3MgYXdheSBmcm9tIHRoZSBzY3JlZW4sIHNvIHNwZWFrIGFzIHlvdXJzZWxmIGluIG5hdHVyYWwgc3Bva2VuIEVuZ2xpc2guXCIsXG4gIFwiXCIsXG4gIFwiaGFwcGVuZWQ6IHdoYXQgeW91IGF0dGVtcHRlZCBhbmQgY2hhbmdlZCwgdGhlIG91dGNvbWUsIGFuZCBhbnkgYmxvY2tlciwgZXJyb3IsIG9yIGRlY2lzaW9uXCIsXG4gIFwidGhhdCBuZWVkcyB0aGUgdXNlcidzIGF0dGVudGlvbi4gQWRkIGFuIG9idmlvdXMgbmV4dCBzdGVwIG9ubHkgaWYgdGhlcmUgaXMgb25lLlwiLFxuICBcIlwiLFxuICBcIlN0eWxlOlwiLFxuICBcIi0gRmlyc3QgcGVyc29uIFx1MjAxNCBJLCBtZSwgbXkuIFlvdSBkaWQgdGhlIHdvcms7IG5ldmVyIGRlc2NyaWJlIHlvdXJzZWxmIGluIHRoaXJkIHBlcnNvbiBvciBhcyBhbiBBSS5cIixcbiAgXCItIFBsYWluIHByb3NlIG9ubHk6IG5vIG1hcmtkb3duLCBjb2RlIGJsb2NrcywgcXVvdGVzLCBidWxsZXQgcG9pbnRzLCBvciBoZWFkaW5ncy5cIixcbiAgXCItIFJlZmVyIHRvIGNvZGUgYnkgcHVycG9zZSAoXFxcInRoZSBhdXRoIG1vZHVsZVxcXCIsIFxcXCJ0aGUgbmV3IGNoZWNrXFxcIikgcmF0aGVyIHRoYW4gaWRlbnRpZmllci5cIixcbiAgXCIgIFdoZW4gYSBzcGVjaWZpYyBmaWxlIG5hbWUgb3IgdGhlIGV4YWN0IGVycm9yIG1lc3NhZ2UgaXMgdGhlIGtleSBmYWN0LCBzYXkgaXQgcGxhaW5seS5cIixcbiAgXCItIEF2b2lkIGZpbGUgcGF0aHMsIHR5cGUgbmFtZXMsIGFuZCBjb21tYW5kIGZsYWdzIHVubGVzcyBvbmUgb2YgdGhlbSBpcyB0aGUgcG9pbnQuXCIsXG4gIFwiLSBPbmx5IGRlc2NyaWJlIHdoYXQgdGhlIGNvbnRleHQgYmVsb3cgc2hvd3MuIERvIG5vdCBpbnZlbnQgZmlsZXMsIHRvb2xzLCBvciBvdXRjb21lcy5cIixcbiAgXCItIE5vIGdyZWV0aW5ncywgc2lnbi1vZmZzLCBvciByZXN0YXRpbmcgdGhlc2UgaW5zdHJ1Y3Rpb25zLlwiLFxuICBcIlwiLFxuICBcIkV4YW1wbGU6IFxcXCJJIHJlZmFjdG9yZWQgdGhlIGNyZWRlbnRpYWxzIGxvYWRlciBhbmQgaXRzIHRlc3RzIHBhc3MuIE5vIGJsb2NrZXJzLlxcXCJcIixcbl0uam9pbihcIlxcblwiKVxuXG4vLyBOb3JtYWxpemVkIGZpZWxkcyB3b3J0aCBzdXJmYWNpbmcgdG8gdGhlIG1vZGVsLiBUaGVzZSBuYW1lcyBhcmUgcHJvZHVjZWQgYnlcbi8vIHNyYy9ldmVudHMvbm9ybWFsaXplLnRzLCBzbyB0aGV5J3JlIHJlbGlhYmxlIHdoZW4gcHJlc2VudC5cbmNvbnN0IEZBQ1RfRklFTERTID0gW1widG9vbFwiLCBcImZpbGVcIiwgXCJjb21tYW5kXCIsIFwibWVzc2FnZVwiLCBcImVycm9yTmFtZVwiLCBcImNvbnRlbnRcIl0gYXMgY29uc3RcblxuZnVuY3Rpb24gZXZlbnRGYWN0cyhldmVudDogeyB0eXBlOiBzdHJpbmc7IFtrOiBzdHJpbmddOiB1bmtub3duIH0pOiBzdHJpbmcge1xuICBjb25zdCBsaW5lczogc3RyaW5nW10gPSBbXVxuICBmb3IgKGNvbnN0IGtleSBvZiBGQUNUX0ZJRUxEUykge1xuICAgIGNvbnN0IHZhbHVlID0gZXZlbnRba2V5XVxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCIgJiYgdmFsdWUudHJpbSgpLmxlbmd0aCA+IDApIHtcbiAgICAgIGxpbmVzLnB1c2goYC0gJHtrZXl9OiAke3RydW5jYXRlKHZhbHVlLCAyMDApfWApXG4gICAgfVxuICB9XG4gIGlmICh0eXBlb2YgZXZlbnQuY291bnQgPT09IFwibnVtYmVyXCIpIGxpbmVzLnB1c2goYC0gY291bnQ6ICR7ZXZlbnQuY291bnR9YClcbiAgcmV0dXJuIGxpbmVzLmpvaW4oXCJcXG5cIilcbn1cblxuZnVuY3Rpb24gYnVpbGRDb250ZXh0KFxuICBldmVudDogeyB0eXBlOiBzdHJpbmc7IFtrOiBzdHJpbmddOiB1bmtub3duIH0sXG4gIGN0eDogTmFycmF0aW9uQ29udGV4dCxcbik6IHN0cmluZyB7XG4gIC8vIFRoZSBkaXNwYXRjaGVyIGFscmVhZHkgYm91bmRzIGFzc2lzdGFudFRleHQgdG8gaXRzIHRleHRXaW5kb3cgKDQwMDApLCBidXRcbiAgLy8gdGhlIG5hcnJhdG9yIGNhbiBiZSBjYWxsZWQgZGlyZWN0bHkgKHRlc3RzLCBkZW1vIHNjcmlwdHMpLCBzbyBjYXAgaGVyZSB0b28uXG4gIGNvbnN0IHRleHQgPSB0cnVuY2F0ZShjdHguYXNzaXN0YW50VGV4dCwgMTAwMDApXG4gIGNvbnN0IHRvb2xzID1cbiAgICBjdHgucmVjZW50VG9vbHMuc2xpY2UoLTUpLm1hcCgodCkgPT4gYC0gJHt0fWApLmpvaW4oXCJcXG5cIikgfHwgXCIobm9uZSlcIlxuICBjb25zdCBvY2Nhc2lvbiA9XG4gICAgKEVWRU5UX1NQRUNTW2V2ZW50LnR5cGUgYXMgRXZlbnRUeXBlXSBhcyBFdmVudFNwZWMgfCB1bmRlZmluZWQpPy5uYXJyYXRpb25PY2Nhc2lvbiA/P1xuICAgIFwiSSBqdXN0IGZpbmlzaGVkIGEgdHVybi5cIlxuICByZXR1cm4gW1xuICAgIG9jY2FzaW9uLFxuICAgIFwiXCIsXG4gICAgXCJXaGF0IEkgcHJvZHVjZWQgcmVjZW50bHk6XCIsXG4gICAgdGV4dCB8fCBcIihub25lKVwiLFxuICAgIFwiXCIsXG4gICAgXCJUb29scyBJIHJlY2VudGx5IHVzZWQ6XCIsXG4gICAgdG9vbHMsXG4gICAgXCJcIixcbiAgICBcIkV2ZW50IGRldGFpbHM6XCIsXG4gICAgZXZlbnRGYWN0cyhldmVudCkgfHwgXCIobm8gZXh0cmEgZGV0YWlsKVwiLFxuICBdLmpvaW4oXCJcXG5cIilcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZU5hcnJhdG9yKFxuICBtb2RlbDogTGFuZ3VhZ2VNb2RlbCxcbiAgY29uZmlnOiBOYXJyYXRvckNvbmZpZyxcbiAgbG9nZ2VyPzogTG9nZ2VyLFxuKTogTmFycmF0b3Ige1xuICBsZXQgbGFzdEZpbmlzaGVkQXQgPSAwXG5cbiAgcmV0dXJuIHtcbiAgICBhc3luYyBzdW1tYXJpemUoZXZlbnQsIGN0eCkge1xuICAgICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKVxuICAgICAgaWYgKG5vdyAtIGxhc3RGaW5pc2hlZEF0IDwgY29uZmlnLm1pbkludGVydmFsTXMpIHJldHVybiBudWxsXG5cbiAgICAgIC8vIE5vdGhpbmcgY29uY3JldGUgdG8gc3VtbWFyaXplIFx1MjAxNCBza2lwIHRoZSBMTE0gY2FsbCAoYW5kIGRvbid0IGFkdmFuY2VcbiAgICAgIC8vIHRoZSB0aHJvdHRsZSkgc28gd2UgbmV2ZXIgc3BlYWsgaW52ZW50ZWQgZmlsbGVyLiBUaGUgbmFycmF0ZSByZW5kZXJlclxuICAgICAgLy8gaW4gaGFuZGxlcnMvaW5kZXgudHMgZmFsbHMgYmFjayB0byB0aGUgZXZlbnQgdGVtcGxhdGUgaW4gdGhpcyBjYXNlLlxuICAgICAgY29uc3QgaGFzQ29udGV4dCA9XG4gICAgICAgIGN0eC5hc3Npc3RhbnRUZXh0LnRyaW0oKS5sZW5ndGggPiAwIHx8XG4gICAgICAgIGN0eC5yZWNlbnRUb29scy5sZW5ndGggPiAwIHx8XG4gICAgICAgIGV2ZW50RmFjdHMoZXZlbnQpLmxlbmd0aCA+IDBcbiAgICAgIGlmICghaGFzQ29udGV4dCkgcmV0dXJuIG51bGxcblxuICAgICAgY29uc3QgYWMgPSBuZXcgQWJvcnRDb250cm9sbGVyKClcbiAgICAgIGNvbnN0IHRpbWVyID0gc2V0VGltZW91dCgoKSA9PiBhYy5hYm9ydCgpLCBjb25maWcudGltZW91dE1zKVxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgeyB0ZXh0IH0gPSBhd2FpdCBnZW5lcmF0ZVRleHQoe1xuICAgICAgICAgIG1vZGVsLFxuICAgICAgICAgIHN5c3RlbTogU1lTVEVNX1BST01QVCxcbiAgICAgICAgICB0ZW1wZXJhdHVyZTogMC4yLFxuICAgICAgICAgIHByb21wdDogYnVpbGRDb250ZXh0KGV2ZW50LCBjdHgpLFxuICAgICAgICAgIGFib3J0U2lnbmFsOiBhYy5zaWduYWwsXG4gICAgICAgIH0pXG4gICAgICAgIGNvbnN0IHRyaW1tZWQgPSB0ZXh0LnRyaW0oKVxuICAgICAgICBpZiAodHJpbW1lZC5sZW5ndGggPT09IDApIHJldHVybiBudWxsXG4gICAgICAgIGxhc3RGaW5pc2hlZEF0ID0gRGF0ZS5ub3coKVxuICAgICAgICByZXR1cm4gdHJpbW1lZFxuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGlmIChsb2dnZXIpIHtcbiAgICAgICAgICBhd2FpdCBsb2dnZXIud2FybihcIm5hcnJhdG9yIHN1bW1hcnkgZmFpbGVkXCIsIHtcbiAgICAgICAgICAgIGVycm9yOiBlcnIsXG4gICAgICAgICAgICBvcGVyYXRpb246IFwic3VtbWFyaXppbmcgZXZlbnQgZm9yIG5hcnJhdGlvblwiLFxuICAgICAgICAgICAgaW5wdXQ6IHtcbiAgICAgICAgICAgICAgZXZlbnRUeXBlOiBldmVudC50eXBlLFxuICAgICAgICAgICAgICBhc3Npc3RhbnRUZXh0TGVuOiBjdHguYXNzaXN0YW50VGV4dC5sZW5ndGgsXG4gICAgICAgICAgICAgIHJlY2VudFRvb2xzQ291bnQ6IGN0eC5yZWNlbnRUb29scy5sZW5ndGgsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGxcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aW1lcilcbiAgICAgIH1cbiAgICB9LFxuICB9XG59XG4iLCAiZXhwb3J0IGludGVyZmFjZSBSYXdFdmVudCB7XG4gIHR5cGU6IHN0cmluZ1xuICBwcm9wZXJ0aWVzPzogdW5rbm93blxuICBba2V5OiBzdHJpbmddOiB1bmtub3duXG59XG5cbmV4cG9ydCB0eXBlIENhbm9uaWNhbEV2ZW50ID0geyB0eXBlOiBzdHJpbmc7IFtrZXk6IHN0cmluZ106IHVua25vd24gfVxuXG5mdW5jdGlvbiBvYmplY3RSZWNvcmQodmFsdWU6IHVua25vd24pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gIHJldHVybiB2YWx1ZSAmJiB0eXBlb2YgdmFsdWUgPT09IFwib2JqZWN0XCIgJiYgIUFycmF5LmlzQXJyYXkodmFsdWUpXG4gICAgPyB2YWx1ZSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPlxuICAgIDoge31cbn1cblxuZnVuY3Rpb24gZmlyc3RTdHJpbmcoLi4udmFsdWVzOiB1bmtub3duW10pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBmb3IgKGNvbnN0IHZhbHVlIG9mIHZhbHVlcykge1xuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCIgJiYgdmFsdWUudHJpbSgpLmxlbmd0aCA+IDApIHJldHVybiB2YWx1ZVxuICB9XG4gIHJldHVybiB1bmRlZmluZWRcbn1cblxuLy8gT3BlbkNvZGUgcmVuYW1lZC9yZXN0cnVjdHVyZWQgYSBmZXcgZXZlbnRzIGJldHdlZW4gU0RLIGdlbmVyYXRpb25zLiBXZSBwaW5cbi8vIHRoZSByZXN0IG9mIHRoZSBwbHVnaW4gdG8gYSBzbWFsbCBzZXQgb2YgY2Fub25pY2FsIG5hbWVzIGFuZCBsZXQgbm9ybWFsaXplXG4vLyB0cmFuc2xhdGUgd2hhdGV2ZXIgdGhlIHJ1bnRpbWUgY3VycmVudGx5IGVtaXRzIGludG8gdGhhdCB2b2NhYnVsYXJ5LlxuY29uc3QgVFlQRV9BTElBU0VTOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICBcInBlcm1pc3Npb24udXBkYXRlZFwiOiBcInBlcm1pc3Npb24uYXNrZWRcIiwgICAgICAgICAgLy8gdjEgU0RLIG5hbWVcbiAgXCJzZXNzaW9uLm5leHQudG9vbC5jYWxsZWRcIjogXCJ0b29sLmV4ZWN1dGUuYmVmb3JlXCIsIC8vIHYyIFNES1xuICBcInNlc3Npb24ubmV4dC50b29sLnN1Y2Nlc3NcIjogXCJ0b29sLmV4ZWN1dGUuYWZ0ZXJcIiwgLy8gdjIgU0RLXG4gIFwic2Vzc2lvbi5uZXh0LnRvb2wuZmFpbGVkXCI6IFwidG9vbC5leGVjdXRlLmFmdGVyXCIsICAvLyB2MiBTREtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG5vcm1hbGl6ZUV2ZW50KHJhdzogUmF3RXZlbnQpOiBDYW5vbmljYWxFdmVudCB7XG4gIGNvbnN0IHByb3BzID0gb2JqZWN0UmVjb3JkKHJhdy5wcm9wZXJ0aWVzKVxuICAvLyB2MSBgcGVybWlzc2lvbi51cGRhdGVkYCBwYXlsb2FkIGlzIGEgUGVybWlzc2lvbiwgd2hvc2Ugb3duIGB0eXBlYCBmaWVsZFxuICAvLyAodGhlIGFjdGlvbiwgZS5nLiBcImJhc2hcIikgY29sbGlkZXMgd2l0aCB0aGUgZXZlbnQgdHlwZSB3aGVuIHNwcmVhZC4gUHVsbFxuICAvLyBpdCBvdXQgYmVmb3JlIHRoZSBtZXJnZSBzbyB3ZSBkb24ndCBsb3NlIGl0LlxuICBjb25zdCBwcm9wVHlwZSA9IHR5cGVvZiBwcm9wcy50eXBlID09PSBcInN0cmluZ1wiID8gcHJvcHMudHlwZSA6IHVuZGVmaW5lZFxuXG4gIGNvbnN0IGNhbm9uaWNhbFR5cGUgPSBUWVBFX0FMSUFTRVNbcmF3LnR5cGVdID8/IHJhdy50eXBlXG4gIGNvbnN0IG1lcmdlZDogQ2Fub25pY2FsRXZlbnQgPSB7IC4uLnJhdywgLi4ucHJvcHMsIHR5cGU6IGNhbm9uaWNhbFR5cGUgfVxuXG4gIGlmIChjYW5vbmljYWxUeXBlID09PSBcInBlcm1pc3Npb24uYXNrZWRcIiB8fCBjYW5vbmljYWxUeXBlID09PSBcInBlcm1pc3Npb24ucmVwbGllZFwiKSB7XG4gICAgY29uc3QgbWV0YSA9IG9iamVjdFJlY29yZChtZXJnZWQubWV0YWRhdGEpXG4gICAgLy8gdjIgUGVybWlzc2lvblJlcXVlc3QudG9vbCBpcyBgeyBtZXNzYWdlSUQsIGNhbGxJRCB9YCBcdTIwMTQgdXNlbGVzcyBhcyBhXG4gICAgLy8gc3Bva2VuIG5hbWUuIFRoZSBmcmllbmRseSBhY3Rpb24gaXMgaW4gYHBlcm1pc3Npb25gICh2MiksIGBtZXRhZGF0YS50b29sYFxuICAgIC8vIChvbGRlciBzaGFwZSksIGB0aXRsZWAgKHYxIFBlcm1pc3Npb24pLCBvciBgdHlwZWAgKHYxIFBlcm1pc3Npb24sIHdoaWNoXG4gICAgLy8gd2UgcmVzY3VlZCBpbnRvIGBwcm9wVHlwZWAgYWJvdmUpLlxuICAgIGNvbnN0IHRvb2xOYW1lID0gZmlyc3RTdHJpbmcoXG4gICAgICB0eXBlb2YgbWVyZ2VkLnRvb2wgPT09IFwic3RyaW5nXCIgPyBtZXJnZWQudG9vbCA6IHVuZGVmaW5lZCxcbiAgICAgIG1lcmdlZC5wZXJtaXNzaW9uLCAvLyB2MiBQZXJtaXNzaW9uUmVxdWVzdC5wZXJtaXNzaW9uXG4gICAgICBwcm9wVHlwZSwgICAgICAgICAgLy8gdjEgUGVybWlzc2lvbi50eXBlIChyZXNjdWVkIGZyb20gcHJvcGVydGllcylcbiAgICAgIG1ldGEudG9vbCwgICAgICAgICAvLyBvbGRlciBzaGFwZTogcGVybWlzc2lvbiBtZXRhZGF0YVxuICAgICAgbWVyZ2VkLnRpdGxlLCAgICAgIC8vIGxhc3QtcmVzb3J0IHYxIGZhbGxiYWNrIChvZnRlbiBsb25nLWZvcm0gbGlrZSBcIlJ1biBhIHNoZWxsIGNvbW1hbmRcIilcbiAgICApXG4gICAgY29uc3QgbmV4dDogQ2Fub25pY2FsRXZlbnQgPSB7IC4uLm1lcmdlZCwgdG9vbDogdG9vbE5hbWUgfVxuICAgIGlmIChjYW5vbmljYWxUeXBlID09PSBcInBlcm1pc3Npb24ucmVwbGllZFwiKSB7XG4gICAgICBuZXh0LmRlY2lzaW9uID1cbiAgICAgICAgZmlyc3RTdHJpbmcobWVyZ2VkLmRlY2lzaW9uLCBtZXJnZWQucmVzcG9uc2UsIG1lcmdlZC5yZXBseSwgbWVyZ2VkLnJlc3VsdCkgPz8gXCJyZXNwb25kZWRcIlxuICAgIH1cbiAgICByZXR1cm4gbmV4dFxuICB9XG5cbiAgaWYgKGNhbm9uaWNhbFR5cGUgPT09IFwidG9vbC5leGVjdXRlLmJlZm9yZVwiIHx8IGNhbm9uaWNhbFR5cGUgPT09IFwidG9vbC5leGVjdXRlLmFmdGVyXCIpIHtcbiAgICByZXR1cm4ge1xuICAgICAgLi4ubWVyZ2VkLFxuICAgICAgdG9vbDogZmlyc3RTdHJpbmcobWVyZ2VkLnRvb2wsIG1lcmdlZC5uYW1lKSxcbiAgICAgIGNhbGxJRDogZmlyc3RTdHJpbmcobWVyZ2VkLmNhbGxJRCwgbWVyZ2VkLmNhbGxJZCwgbWVyZ2VkLmlkKSxcbiAgICB9XG4gIH1cblxuICBpZiAoY2Fub25pY2FsVHlwZSA9PT0gXCJzZXNzaW9uLmVycm9yXCIpIHtcbiAgICBjb25zdCBlcnIgPSBvYmplY3RSZWNvcmQobWVyZ2VkLmVycm9yKVxuICAgIGNvbnN0IGVyckRhdGEgPSBvYmplY3RSZWNvcmQoZXJyLmRhdGEpXG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLm1lcmdlZCxcbiAgICAgIC8vIFJlYWwgc2hhcGU6IHByb3BlcnRpZXMuZXJyb3IuZGF0YS5tZXNzYWdlLiBGYWxsIGJhY2sgdG8gYSB0b3AtbGV2ZWxcbiAgICAgIC8vIGBtZXNzYWdlYCBvbmx5IGJlY2F1c2Ugb2xkL3N5bnRoZXNpemVkIGV2ZW50cyBzb21ldGltZXMgdXNlIGl0LlxuICAgICAgbWVzc2FnZTogZmlyc3RTdHJpbmcobWVyZ2VkLm1lc3NhZ2UsIGVyckRhdGEubWVzc2FnZSwgZXJyLm1lc3NhZ2UpLFxuICAgICAgZXJyb3JOYW1lOiBmaXJzdFN0cmluZyhlcnIubmFtZSwgZXJyRGF0YS5uYW1lKSxcbiAgICB9XG4gIH1cblxuICBpZiAoY2Fub25pY2FsVHlwZSA9PT0gXCJmaWxlLmVkaXRlZFwiKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLm1lcmdlZCxcbiAgICAgIGZpbGU6IGZpcnN0U3RyaW5nKG1lcmdlZC5maWxlLCBtZXJnZWQucGF0aCwgbWVyZ2VkLmZpbGVQYXRoKSxcbiAgICB9XG4gIH1cblxuICBpZiAoY2Fub25pY2FsVHlwZSA9PT0gXCJjb21tYW5kLmV4ZWN1dGVkXCIgfHwgY2Fub25pY2FsVHlwZSA9PT0gXCJ0dWkuY29tbWFuZC5leGVjdXRlXCIpIHtcbiAgICByZXR1cm4ge1xuICAgICAgLi4ubWVyZ2VkLFxuICAgICAgY29tbWFuZDogZmlyc3RTdHJpbmcobWVyZ2VkLmNvbW1hbmQsIG1lcmdlZC5uYW1lLCBtZXJnZWQuaWQpLFxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBtZXJnZWRcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNvbW1hbmROYW1lRnJvbUV2ZW50KHJhdzogUmF3RXZlbnQpOiBzdHJpbmcgfCBudWxsIHtcbiAgY29uc3QgZXZlbnQgPSBub3JtYWxpemVFdmVudChyYXcpXG4gIHJldHVybiB0eXBlb2YgZXZlbnQuY29tbWFuZCA9PT0gXCJzdHJpbmdcIlxuICAgID8gZXZlbnQuY29tbWFuZC5yZXBsYWNlKC9eXFwvKy8sIFwiXCIpLnRvTG93ZXJDYXNlKClcbiAgICA6IG51bGxcbn1cbiIsICJpbXBvcnQgdHlwZSB7IFNwZWVjaFJlcXVlc3QgfSBmcm9tIFwiLi9xdWV1ZS90eXBlcy5qc1wiXG5pbXBvcnQgdHlwZSB7IEhhbmRsZXJSZWdpc3RyeSB9IGZyb20gXCIuL2hhbmRsZXJzL2luZGV4LmpzXCJcbmltcG9ydCB0eXBlIHsgTmFycmF0aW9uQ29udGV4dCB9IGZyb20gXCIuL2hhbmRsZXJzL25hcnJhdG9yLmpzXCJcbmltcG9ydCB0eXBlIHsgTG9nZ2VyIH0gZnJvbSBcIi4vbG9nLmpzXCJcbmltcG9ydCB7IG5vcm1hbGl6ZUV2ZW50LCB0eXBlIFJhd0V2ZW50IH0gZnJvbSBcIi4vZXZlbnRzL25vcm1hbGl6ZS5qc1wiXG5cbmludGVyZmFjZSBRdWV1ZUlmYyB7XG4gIHB1c2gocmVxOiBTcGVlY2hSZXF1ZXN0KTogdm9pZFxufVxuXG5leHBvcnQgaW50ZXJmYWNlIERpc3BhdGNoZXJPcHRpb25zIHtcbiAgaGFuZGxlcjogSGFuZGxlclJlZ2lzdHJ5XG4gIHF1ZXVlOiBRdWV1ZUlmY1xuICBsb2dnZXI/OiBMb2dnZXJcbiAgb25FcnJvcj86IChlcnI6IHVua25vd24sIGV2ZW50OiB7IHR5cGU6IHN0cmluZyB9KSA9PiB2b2lkXG4gIC8qKiBNYXggY2hhcnMgb2YgcmVjZW50IGFzc2lzdGFudCB0ZXh0IHRvIGtlZXAuICovXG4gIHRleHRXaW5kb3c/OiBudW1iZXJcbiAgLyoqIE1heCByZWNlbnQgdG9vbCBjYWxscyB0byByZW1lbWJlci4gKi9cbiAgdG9vbFdpbmRvdz86IG51bWJlclxuICAvKiogTWF4IGNoYXJzIG9mIHJlYXNvbmluZyBidWZmZXIgYmVmb3JlIGZvcmNlZCBmbHVzaCB3aGVuIG5vIHNlbnRlbmNlIGVuZCBpcyBmb3VuZC4gKi9cbiAgcmVhc29uaW5nRmx1c2hDaGFycz86IG51bWJlclxufVxuXG5pbnRlcmZhY2UgVG9kb1NuYXBzaG90IHtcbiAgaWQ6IHN0cmluZ1xuICBjb250ZW50OiBzdHJpbmdcbiAgc3RhdHVzOiBzdHJpbmdcbn1cblxuaW50ZXJmYWNlIFBhcnRMaWtlIHtcbiAgaWQ/OiBzdHJpbmdcbiAgdHlwZT86IHN0cmluZ1xuICB0ZXh0Pzogc3RyaW5nXG4gIFtrOiBzdHJpbmddOiB1bmtub3duXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRGlzcGF0Y2hlciB7XG4gIG9uRXZlbnQoZXZlbnQ6IFJhd0V2ZW50KTogUHJvbWlzZTx2b2lkPlxuICBnZXRDb250ZXh0KCk6IE5hcnJhdGlvbkNvbnRleHRcbn1cblxuLy8gTWF0Y2hlcyBhIHNlbnRlbmNlIGVuZGluZyB3aXRoIC4gISBvciA/IG9wdGlvbmFsbHkgZm9sbG93ZWQgYnkgYSBjbG9zaW5nXG4vLyBxdW90ZS9icmFja2V0IGFuZCBlaXRoZXIgd2hpdGVzcGFjZSBvciBlbmQtb2Ytc3RyaW5nLiBUaGUgbG9va2FoZWFkLWZyZWVcbi8vIGZvcm0ga2VlcHMgdGhlIHJlZ2V4IGNvbXBhdGlibGUgd2l0aCBvbGRlciBlbmdpbmVzIGFuZCBlYXN5IHRvIHJlYXNvbiBhYm91dC5cbmNvbnN0IFNFTlRFTkNFX1JFID0gL1tcXHNcXFNdKj9bLiE/XSsoPzpbXCInKVxcXV0/KSg/Olxccyt8JCkvZ1xuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRGlzcGF0Y2hlcihvcHRzOiBEaXNwYXRjaGVyT3B0aW9ucyk6IERpc3BhdGNoZXIge1xuICBjb25zdCB0ZXh0V2luZG93ID0gb3B0cy50ZXh0V2luZG93ID8/IDQwMDBcbiAgY29uc3QgdG9vbFdpbmRvdyA9IG9wdHMudG9vbFdpbmRvdyA/PyAxMFxuICBjb25zdCByZWFzb25pbmdGbHVzaENoYXJzID0gb3B0cy5yZWFzb25pbmdGbHVzaENoYXJzID8/IDI0MFxuXG4gIGxldCBhc3Npc3RhbnRUZXh0ID0gXCJcIlxuICBjb25zdCByZWNlbnRUb29sczogc3RyaW5nW10gPSBbXVxuICAvLyB2MiBgc2Vzc2lvbi5uZXh0LnRvb2wuc3VjY2Vzc2AvYC5mYWlsZWRgIG9ubHkgY2FycnkgYGNhbGxJRGAsIG5vdCB0aGVcbiAgLy8gdG9vbCBuYW1lLiBXZSByZW1lbWJlciB0aGUgY2FsbElEIC0+IHRvb2wgbWFwcGluZyB3aGVuIHRoZSBtYXRjaGluZ1xuICAvLyBgdG9vbC5leGVjdXRlLmJlZm9yZWAgKG5vcm1hbGl6ZWQgZnJvbSBgc2Vzc2lvbi5uZXh0LnRvb2wuY2FsbGVkYCkgZmlyZXNcbiAgLy8gc28gdGhlIGFmdGVyLWV2ZW50IHRlbXBsYXRlIGNhbiBzdGlsbCBzYXkgXCJJIGZpbmlzaGVkIHJ1bm5pbmcgWC5cIlxuICBjb25zdCB0b29sQnlDYWxsSWQgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpXG4gIGNvbnN0IHRvZG9TdGF0dXMgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpIC8vIGlkIC0+IGxhc3Qgc2VlbiBzdGF0dXNcblxuICAvLyBGb3Igc3RyZWFtaW5nIG1lc3NhZ2UgcGFydHMgKHRleHQgKyByZWFzb25pbmcpOiBob3cgbXVjaCBvZiBlYWNoIHBhcnQnc1xuICAvLyB0ZXh0IHdlIGhhdmUgYWxyZWFkeSBwcm9jZXNzZWQuIEVhY2ggYG1lc3NhZ2UucGFydC51cGRhdGVkYCBjYXJyaWVzIHRoZVxuICAvLyBGVUxMIGN1cnJlbnQgc3RhdGUgb2YgYSBwYXJ0LCBzbyB0aGUgZGVsdGEgaXMgYHBhcnQudGV4dC5zbGljZShzZWVuTGVuKWAuXG4gIGNvbnN0IHBhcnRTZWVuID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKVxuICAvLyBGb3IgcmVhc29uaW5nIHNwZWNpZmljYWxseSwgd2UgYnVmZmVyIHRyYWlsaW5nIHRleHQgd2l0aG91dCBhIHNlbnRlbmNlXG4gIC8vIGJvdW5kYXJ5IHNvIHdlIGRvbid0IHNwZWFrIGhhbGYtdGhvdWdodHMgbGlrZSBcIkxldCBtZVwiIC8gXCJ0aGluayBhYm91dFwiLlxuICBjb25zdCByZWFzb25pbmdCdWZmZXIgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpXG4gIC8vIE1vbm90b25pYyBjb3VudGVyIHNvIGVhY2ggc3ludGhlc2l6ZWQgc3RyZWFtaW5nIGRlbHRhIGhhcyBpdHMgb3duIGRlZHVwXG4gIC8vIGtleSBcdTIwMTQgb3RoZXJ3aXNlIHN1Y2Nlc3NpdmUgcmVhc29uaW5nIGRlbHRhcyB3b3VsZCBjb2xsYXBzZSBhZ2FpbnN0IGVhY2hcbiAgLy8gb3RoZXIgaW4gdGhlIHNwZWVjaCBxdWV1ZSBhbmQgd2UnZCBsb3NlIGNvbnRlbnQuXG4gIGxldCBkZWx0YVNlcXVlbmNlID0gMFxuXG4gIGZ1bmN0aW9uIGFwcGVuZFRleHQodDogc3RyaW5nKSB7XG4gICAgYXNzaXN0YW50VGV4dCA9IChhc3Npc3RhbnRUZXh0ICsgXCIgXCIgKyB0KS5zbGljZSgtdGV4dFdpbmRvdylcbiAgfVxuXG4gIGZ1bmN0aW9uIHRyYWNrVG9vbCh0b29sOiBzdHJpbmcpIHtcbiAgICByZWNlbnRUb29scy5wdXNoKHRvb2wpXG4gICAgd2hpbGUgKHJlY2VudFRvb2xzLmxlbmd0aCA+IHRvb2xXaW5kb3cpIHJlY2VudFRvb2xzLnNoaWZ0KClcbiAgfVxuXG4gIC8vIEEgXCJ0dXJuXCIgaXMgb25lIHVzZXIgcHJvbXB0ICsgdGhlIGFnZW50IHJlc3BvbnNlIHRoYXQgZm9sbG93cyBpdCwgZW5kZWQgYnlcbiAgLy8gc2Vzc2lvbi5pZGxlLiBXaXRob3V0IHRoaXMgcmVzZXQsIGFzc2lzdGFudFRleHQvcmVjZW50VG9vbHMgYWNjdW11bGF0ZVxuICAvLyBhY3Jvc3MgZXZlcnkgdHVybiBpbiBhIHNlc3Npb24sIHNvIHRoZSBuYXJyYXRvcidzIGVuZC1vZi10dXJuIHN1bW1hcnlcbiAgLy8gd291bGQgZGVzY3JpYmUgZXZlcnl0aGluZyBzaW5jZSB0aGUgc2Vzc2lvbiBiZWdhbiBpbnN0ZWFkIG9mIGp1c3QgdGhpc1xuICAvLyB0dXJuLiBNdXN0IHJ1biBBRlRFUiBzZXNzaW9uLmlkbGUncyBoYW5kbGVyIGNoYWluIHNvIHRoZSBuYXJyYXRvciBzdGlsbFxuICAvLyBzZWVzIHRoZSBmdWxsIHR1cm4ncyBjb250ZXh0LlxuICBmdW5jdGlvbiByZXNldFR1cm5TdGF0ZSgpIHtcbiAgICBhc3Npc3RhbnRUZXh0ID0gXCJcIlxuICAgIHJlY2VudFRvb2xzLmxlbmd0aCA9IDBcbiAgICBwYXJ0U2Vlbi5jbGVhcigpXG4gICAgcmVhc29uaW5nQnVmZmVyLmNsZWFyKClcbiAgICB0b29sQnlDYWxsSWQuY2xlYXIoKVxuICB9XG5cbiAgYXN5bmMgZnVuY3Rpb24gZmlyZShldmVudDogeyB0eXBlOiBzdHJpbmc7IFtrOiBzdHJpbmddOiB1bmtub3duIH0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3Qgc3IgPSBhd2FpdCBvcHRzLmhhbmRsZXIuaGFuZGxlKGV2ZW50KVxuICAgICAgaWYgKHNyKSBvcHRzLnF1ZXVlLnB1c2goc3IpXG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAob3B0cy5sb2dnZXIpIHtcbiAgICAgICAgYXdhaXQgb3B0cy5sb2dnZXIud2FybihcImhhbmRsZXIgZmFpbGVkXCIsIHtcbiAgICAgICAgICBlcnJvcjogZXJyLFxuICAgICAgICAgIG9wZXJhdGlvbjogXCJkaXNwYXRjaGluZyBvcGVuY29kZSBldmVudFwiLFxuICAgICAgICAgIGlucHV0OiB7IGV2ZW50VHlwZTogZXZlbnQudHlwZSB9LFxuICAgICAgICB9KVxuICAgICAgfVxuICAgICAgb3B0cy5vbkVycm9yPy4oZXJyLCBldmVudClcbiAgICB9XG4gIH1cblxuICBhc3luYyBmdW5jdGlvbiBoYW5kbGVUb2RvVXBkYXRlZChwcm9wczogeyB0b2Rvcz86IFRvZG9TbmFwc2hvdFtdIH0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB0b2RvcyA9IHByb3BzLnRvZG9zID8/IFtdXG4gICAgbGV0IHRyYW5zaXRpb25zVG9Db21wbGV0ZWQgPSAwXG4gICAgZm9yIChjb25zdCB0IG9mIHRvZG9zKSB7XG4gICAgICBjb25zdCBwcmV2ID0gdG9kb1N0YXR1cy5nZXQodC5pZClcbiAgICAgIGlmIChwcmV2ICE9PSBcImNvbXBsZXRlZFwiICYmIHQuc3RhdHVzID09PSBcImNvbXBsZXRlZFwiKSB7XG4gICAgICAgIHRyYW5zaXRpb25zVG9Db21wbGV0ZWQrK1xuICAgICAgICBhd2FpdCBmaXJlKHsgdHlwZTogXCJ0b2RvLmNvbXBsZXRlZC5pdGVtXCIsIGNvbnRlbnQ6IHQuY29udGVudCB9KVxuICAgICAgfVxuICAgICAgdG9kb1N0YXR1cy5zZXQodC5pZCwgdC5zdGF0dXMpXG4gICAgfVxuICAgIGlmIChcbiAgICAgIHRvZG9zLmxlbmd0aCA+IDAgJiZcbiAgICAgIHRvZG9zLmV2ZXJ5KCh0KSA9PiB0LnN0YXR1cyA9PT0gXCJjb21wbGV0ZWRcIikgJiZcbiAgICAgIHRyYW5zaXRpb25zVG9Db21wbGV0ZWQgPiAwXG4gICAgKSB7XG4gICAgICBhd2FpdCBmaXJlKHsgdHlwZTogXCJ0b2RvLmNvbXBsZXRlZC5hbGxcIiwgY291bnQ6IHRvZG9zLmxlbmd0aCB9KVxuICAgIH1cbiAgICBhd2FpdCBmaXJlKHsgdHlwZTogXCJ0b2RvLnVwZGF0ZWRcIiwgdG9kb3MgfSlcbiAgfVxuXG4gIGZ1bmN0aW9uIGNvbXB1dGVEZWx0YShwYXJ0SWQ6IHN0cmluZywgZnVsbFRleHQ6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuICAgIGNvbnN0IHByZXYgPSBwYXJ0U2Vlbi5nZXQocGFydElkKSA/PyAwXG4gICAgLy8gRGVmZW5zaXZlOiB0ZXh0IHNob3VsZG4ndCBzaHJpbmssIGJ1dCBpZiBhIHN0cmVhbSByZXNldHMgd2UgcmUtYW5jaG9yLlxuICAgIGlmIChmdWxsVGV4dC5sZW5ndGggPCBwcmV2KSB7XG4gICAgICBwYXJ0U2Vlbi5zZXQocGFydElkLCBmdWxsVGV4dC5sZW5ndGgpXG4gICAgICByZXR1cm4gbnVsbFxuICAgIH1cbiAgICBpZiAoZnVsbFRleHQubGVuZ3RoID09PSBwcmV2KSByZXR1cm4gbnVsbFxuICAgIGNvbnN0IGRlbHRhID0gZnVsbFRleHQuc2xpY2UocHJldilcbiAgICBwYXJ0U2Vlbi5zZXQocGFydElkLCBmdWxsVGV4dC5sZW5ndGgpXG4gICAgcmV0dXJuIGRlbHRhXG4gIH1cblxuICBhc3luYyBmdW5jdGlvbiBoYW5kbGVUZXh0UGFydChwYXJ0OiBQYXJ0TGlrZSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICghcGFydC5pZCB8fCB0eXBlb2YgcGFydC50ZXh0ICE9PSBcInN0cmluZ1wiKSByZXR1cm5cbiAgICBjb25zdCBkZWx0YSA9IGNvbXB1dGVEZWx0YShwYXJ0LmlkLCBwYXJ0LnRleHQpXG4gICAgaWYgKCFkZWx0YSkgcmV0dXJuXG4gICAgLy8gVXBkYXRlIGFzc2lzdGFudCBjb250ZXh0IGZvciB0aGUgbmFycmF0b3IgcmVnYXJkbGVzcyBvZiB3aGV0aGVyIHRoZVxuICAgIC8vIHVzZXIgaGFzIGVuYWJsZWQgbGl2ZSB0ZXh0IG5hcnJhdGlvbi5cbiAgICBhcHBlbmRUZXh0KGRlbHRhKVxuICAgIGF3YWl0IGZpcmUoe1xuICAgICAgdHlwZTogXCJtZXNzYWdlLnRleHQuZGVsdGFcIixcbiAgICAgIHRleHQ6IGRlbHRhLFxuICAgICAgcGFydElEOiBwYXJ0LmlkLFxuICAgICAgZGVkdXBLZXk6IGBtZXNzYWdlLnRleHQuZGVsdGE6JHtwYXJ0LmlkfTokeysrZGVsdGFTZXF1ZW5jZX1gLFxuICAgIH0pXG4gIH1cblxuICBhc3luYyBmdW5jdGlvbiBoYW5kbGVSZWFzb25pbmdQYXJ0KHBhcnQ6IFBhcnRMaWtlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKCFwYXJ0LmlkIHx8IHR5cGVvZiBwYXJ0LnRleHQgIT09IFwic3RyaW5nXCIpIHJldHVyblxuICAgIGNvbnN0IGRlbHRhID0gY29tcHV0ZURlbHRhKHBhcnQuaWQsIHBhcnQudGV4dClcbiAgICBpZiAoIWRlbHRhKSByZXR1cm5cblxuICAgIGxldCBidWZmZXJlZCA9IChyZWFzb25pbmdCdWZmZXIuZ2V0KHBhcnQuaWQpID8/IFwiXCIpICsgZGVsdGFcblxuICAgIGNvbnN0IHNlbnRlbmNlczogc3RyaW5nW10gPSBbXVxuICAgIGxldCBjdXJzb3IgPSAwXG4gICAgU0VOVEVOQ0VfUkUubGFzdEluZGV4ID0gMFxuICAgIGxldCBtOiBSZWdFeHBFeGVjQXJyYXkgfCBudWxsXG4gICAgd2hpbGUgKChtID0gU0VOVEVOQ0VfUkUuZXhlYyhidWZmZXJlZCkpICE9PSBudWxsKSB7XG4gICAgICBzZW50ZW5jZXMucHVzaChtWzBdLnRyaW0oKSlcbiAgICAgIGN1cnNvciA9IFNFTlRFTkNFX1JFLmxhc3RJbmRleFxuICAgIH1cbiAgICBidWZmZXJlZCA9IGJ1ZmZlcmVkLnNsaWNlKGN1cnNvcilcblxuICAgIC8vIElmIHRoZSB0cmFpbGluZyBmcmFnbWVudCBncm93cyBsYXJnZSB3aXRob3V0IGEgc2VudGVuY2UgZW5kLCBmb3JjZS1mbHVzaFxuICAgIC8vIGl0IHNvIHZlcnkgbG9uZyByZWFzb25pbmcgYmxvY2tzIHdpdGhvdXQgcHVuY3R1YXRpb24gc3RpbGwgZ2V0IGhlYXJkLlxuICAgIGlmIChidWZmZXJlZC5sZW5ndGggPj0gcmVhc29uaW5nRmx1c2hDaGFycykge1xuICAgICAgc2VudGVuY2VzLnB1c2goYnVmZmVyZWQudHJpbSgpKVxuICAgICAgYnVmZmVyZWQgPSBcIlwiXG4gICAgfVxuXG4gICAgcmVhc29uaW5nQnVmZmVyLnNldChwYXJ0LmlkLCBidWZmZXJlZClcblxuICAgIGZvciAoY29uc3Qgc2VudGVuY2Ugb2Ygc2VudGVuY2VzKSB7XG4gICAgICBpZiAoIXNlbnRlbmNlKSBjb250aW51ZVxuICAgICAgYXdhaXQgZmlyZSh7XG4gICAgICAgIHR5cGU6IFwibWVzc2FnZS5yZWFzb25pbmcuZGVsdGFcIixcbiAgICAgICAgdGV4dDogc2VudGVuY2UsXG4gICAgICAgIHBhcnRJRDogcGFydC5pZCxcbiAgICAgICAgZGVkdXBLZXk6IGBtZXNzYWdlLnJlYXNvbmluZy5kZWx0YToke3BhcnQuaWR9OiR7KytkZWx0YVNlcXVlbmNlfWAsXG4gICAgICB9KVxuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGZ1bmN0aW9uIGhhbmRsZU1lc3NhZ2VQYXJ0KHByb3BzOiB7IHBhcnQ/OiBQYXJ0TGlrZSB9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcGFydCA9IHByb3BzLnBhcnRcbiAgICBpZiAoIXBhcnQgfHwgdHlwZW9mIHBhcnQgIT09IFwib2JqZWN0XCIpIHJldHVyblxuICAgIGlmIChwYXJ0LnR5cGUgPT09IFwidGV4dFwiKSB7XG4gICAgICBhd2FpdCBoYW5kbGVUZXh0UGFydChwYXJ0KVxuICAgIH0gZWxzZSBpZiAocGFydC50eXBlID09PSBcInJlYXNvbmluZ1wiKSB7XG4gICAgICBhd2FpdCBoYW5kbGVSZWFzb25pbmdQYXJ0KHBhcnQpXG4gICAgfVxuICAgIC8vIE90aGVyIHBhcnQgdHlwZXMgKHRvb2wsIGZpbGUsIHN0ZXAtc3RhcnQsIFx1MjAyNikgYXJlIHN1cmZhY2VkIHZpYSB0aGVpclxuICAgIC8vIGRlZGljYXRlZCBldmVudHM7IG5vdGhpbmcgZnVydGhlciB0byBmb3J3YXJkIGhlcmUuXG4gIH1cblxuICByZXR1cm4ge1xuICAgIGFzeW5jIG9uRXZlbnQoZXZlbnQpIHtcbiAgICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSBub3JtYWxpemVFdmVudChldmVudClcblxuICAgICAgaWYgKG5vcm1hbGl6ZWQudHlwZSA9PT0gXCJ0b2RvLnVwZGF0ZWRcIikge1xuICAgICAgICBjb25zdCB0b2RvcyA9IG5vcm1hbGl6ZWQudG9kb3MgYXMgVG9kb1NuYXBzaG90W10gfCB1bmRlZmluZWRcbiAgICAgICAgcmV0dXJuIGhhbmRsZVRvZG9VcGRhdGVkKHsgdG9kb3MgfSlcbiAgICAgIH1cblxuICAgICAgaWYgKG5vcm1hbGl6ZWQudHlwZSA9PT0gXCJtZXNzYWdlLnBhcnQudXBkYXRlZFwiKSB7XG4gICAgICAgIGNvbnN0IHBhcnQgPSBub3JtYWxpemVkLnBhcnQgYXMgUGFydExpa2UgfCB1bmRlZmluZWRcbiAgICAgICAgcmV0dXJuIGhhbmRsZU1lc3NhZ2VQYXJ0KHsgcGFydCB9KVxuICAgICAgfVxuXG4gICAgICBpZiAobm9ybWFsaXplZC50eXBlID09PSBcInRvb2wuZXhlY3V0ZS5iZWZvcmVcIikge1xuICAgICAgICBjb25zdCB0b29sID0gbm9ybWFsaXplZC50b29sIGFzIHN0cmluZyB8IHVuZGVmaW5lZFxuICAgICAgICBjb25zdCBjYWxsSUQgPSBub3JtYWxpemVkLmNhbGxJRCBhcyBzdHJpbmcgfCB1bmRlZmluZWRcbiAgICAgICAgaWYgKHR5cGVvZiB0b29sID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgdHJhY2tUb29sKHRvb2wpXG4gICAgICAgICAgaWYgKHR5cGVvZiBjYWxsSUQgPT09IFwic3RyaW5nXCIpIHRvb2xCeUNhbGxJZC5zZXQoY2FsbElELCB0b29sKVxuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKG5vcm1hbGl6ZWQudHlwZSA9PT0gXCJ0b29sLmV4ZWN1dGUuYWZ0ZXJcIikge1xuICAgICAgICAvLyB2MiBzdWNjZXNzL2ZhaWxlZCBldmVudHMgbG9zZSB0aGUgdG9vbCBuYW1lIFx1MjAxNCByZWNvdmVyIGl0IGZyb20gdGhlXG4gICAgICAgIC8vIG1hdGNoaW5nIGBiZWZvcmVgIGV2ZW50IHNvIHRoZSB0ZW1wbGF0ZSBjYW4gc2F5IFwiSSBmaW5pc2hlZCBYLlwiXG4gICAgICAgIGlmICh0eXBlb2Ygbm9ybWFsaXplZC50b29sICE9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgY29uc3QgY2FsbElEID0gbm9ybWFsaXplZC5jYWxsSUQgYXMgc3RyaW5nIHwgdW5kZWZpbmVkXG4gICAgICAgICAgY29uc3QgcmVtZW1iZXJlZCA9IGNhbGxJRCA/IHRvb2xCeUNhbGxJZC5nZXQoY2FsbElEKSA6IHVuZGVmaW5lZFxuICAgICAgICAgIGlmIChyZW1lbWJlcmVkKSBub3JtYWxpemVkLnRvb2wgPSByZW1lbWJlcmVkXG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgY2FsbElEID0gbm9ybWFsaXplZC5jYWxsSUQgYXMgc3RyaW5nIHwgdW5kZWZpbmVkXG4gICAgICAgIGlmIChjYWxsSUQpIHRvb2xCeUNhbGxJZC5kZWxldGUoY2FsbElEKVxuICAgICAgfVxuXG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBmaXJlKG5vcm1hbGl6ZWQpXG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgbm9ybWFsaXplZC50eXBlID09PSBcInNlc3Npb24uaWRsZVwiIHx8XG4gICAgICAgICAgbm9ybWFsaXplZC50eXBlID09PSBcInNlc3Npb24uY3JlYXRlZFwiXG4gICAgICAgICkge1xuICAgICAgICAgIHJlc2V0VHVyblN0YXRlKClcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gICAgZ2V0Q29udGV4dCgpIHtcbiAgICAgIHJldHVybiB7IGFzc2lzdGFudFRleHQsIHJlY2VudFRvb2xzOiBbLi4ucmVjZW50VG9vbHNdIH1cbiAgICB9LFxuICB9XG59XG4iLCAiaW1wb3J0IHsgcmFuZG9tVVVJRCB9IGZyb20gXCJub2RlOmNyeXB0b1wiXG5pbXBvcnQgeyBQcmlvcml0eSwgdHlwZSBTcGVlY2hSZXF1ZXN0IH0gZnJvbSBcIi4uL3F1ZXVlL3R5cGVzLmpzXCJcblxuZXhwb3J0IGludGVyZmFjZSBDb21tYW5kc09wdGlvbnMge1xuICBxdWV1ZToge1xuICAgIHB1c2gocmVxOiBTcGVlY2hSZXF1ZXN0KTogdm9pZFxuICAgIG11dGUoKTogdm9pZFxuICAgIHVubXV0ZSgpOiB2b2lkXG4gICAgc3RvcCgpOiB2b2lkXG4gICAgc2l6ZSgpOiBudW1iZXJcbiAgICBpc011dGVkKCk6IGJvb2xlYW5cbiAgfVxuICBwcm92aWRlck5hbWU6IHN0cmluZ1xuICB2b2ljZU5hbWU/OiBzdHJpbmdcbn1cblxuZXhwb3J0IGludGVyZmFjZSBWb2ljZVN0YXR1cyB7XG4gIHByb3ZpZGVyOiBzdHJpbmdcbiAgdm9pY2U/OiBzdHJpbmdcbiAgbXV0ZWQ6IGJvb2xlYW5cbiAgcXVldWVTaXplOiBudW1iZXJcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDb21tYW5kcyB7XG4gIG11dGUoKTogdm9pZFxuICB1bm11dGUoKTogdm9pZFxuICB0b2dnbGUoKTogYm9vbGVhblxuICBzdG9wKCk6IHZvaWRcbiAgc2F5KHRleHQ6IHN0cmluZyk6IHZvaWRcbiAgdGVzdCgpOiB2b2lkXG4gIHN0YXR1cygpOiBWb2ljZVN0YXR1c1xuICBpc011dGVkKCk6IGJvb2xlYW5cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUNvbW1hbmRzKG9wdHM6IENvbW1hbmRzT3B0aW9ucyk6IENvbW1hbmRzIHtcbiAgZnVuY3Rpb24gbWFrZVJlcXVlc3QodGV4dDogc3RyaW5nLCBwcmlvcml0eTogUHJpb3JpdHkpOiBTcGVlY2hSZXF1ZXN0IHtcbiAgICByZXR1cm4geyBpZDogcmFuZG9tVVVJRCgpLCBwcmlvcml0eSwgdGV4dCwgZW5xdWV1ZWRBdDogRGF0ZS5ub3coKSB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIG11dGUoKSB7XG4gICAgICBvcHRzLnF1ZXVlLm11dGUoKVxuICAgIH0sXG4gICAgdW5tdXRlKCkge1xuICAgICAgb3B0cy5xdWV1ZS51bm11dGUoKVxuICAgIH0sXG4gICAgLyoqIFRvZ2dsZSBtdXRlIHN0YXRlLiBSZXR1cm5zIHRoZSBuZXcgbXV0ZWQgc3RhdGUuICovXG4gICAgdG9nZ2xlKCkge1xuICAgICAgaWYgKG9wdHMucXVldWUuaXNNdXRlZCgpKSB7XG4gICAgICAgIG9wdHMucXVldWUudW5tdXRlKClcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG9wdHMucXVldWUubXV0ZSgpXG4gICAgICB9XG4gICAgICByZXR1cm4gb3B0cy5xdWV1ZS5pc011dGVkKClcbiAgICB9LFxuICAgIC8qKiBJbnRlcnJ1cHQgdGhlIGN1cnJlbnQgdXR0ZXJhbmNlIChhbmQgZHJvcCB0aGUgcGVuZGluZyBxdWV1ZSkuICovXG4gICAgc3RvcCgpIHtcbiAgICAgIG9wdHMucXVldWUuc3RvcCgpXG4gICAgfSxcbiAgICBpc011dGVkKCkge1xuICAgICAgcmV0dXJuIG9wdHMucXVldWUuaXNNdXRlZCgpXG4gICAgfSxcbiAgICBzYXkodGV4dDogc3RyaW5nKSB7XG4gICAgICBvcHRzLnF1ZXVlLnB1c2gobWFrZVJlcXVlc3QodGV4dCwgUHJpb3JpdHkuTk9STUFMKSlcbiAgICB9LFxuICAgIHRlc3QoKSB7XG4gICAgICBvcHRzLnF1ZXVlLnB1c2goXG4gICAgICAgIG1ha2VSZXF1ZXN0KFxuICAgICAgICAgIFwib3BlbmNvZGUgdm9pY2UgdGVzdC4gSWYgeW91IGhlYXIgdGhpcywgYXVkaW8gaXMgd29ya2luZy5cIixcbiAgICAgICAgICBQcmlvcml0eS5OT1JNQUwsXG4gICAgICAgICksXG4gICAgICApXG4gICAgfSxcbiAgICBzdGF0dXMoKTogVm9pY2VTdGF0dXMge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgcHJvdmlkZXI6IG9wdHMucHJvdmlkZXJOYW1lLFxuICAgICAgICB2b2ljZTogb3B0cy52b2ljZU5hbWUsXG4gICAgICAgIG11dGVkOiBvcHRzLnF1ZXVlLmlzTXV0ZWQoKSxcbiAgICAgICAgcXVldWVTaXplOiBvcHRzLnF1ZXVlLnNpemUoKSxcbiAgICAgIH1cbiAgICB9LFxuICB9XG59XG4iLCAiaW1wb3J0IHR5cGUgeyBMb2dnZXIgfSBmcm9tIFwiLi9sb2cuanNcIlxuXG5jb25zdCBUT0FTVF9NQVhfTEVOID0gMjAwXG5jb25zdCBUT0FTVF9QUkVGSVggPSBcIm9wZW5jb2RlLXNwZWFrZXI6IFwiXG5jb25zdCBUT0FTVF9ERUZFUl9NUyA9IDI1MDBcbmNvbnN0IFRPQVNUX0RVUkFUSU9OX01TID0gMTAwMDBcblxuZXhwb3J0IHR5cGUgVG9hc3RWYXJpYW50ID0gXCJlcnJvclwiIHwgXCJ3YXJuaW5nXCIgfCBcImluZm9cIiB8IFwic3VjY2Vzc1wiXG5cbmV4cG9ydCBpbnRlcmZhY2UgTm90aWZpZXJDbGllbnQge1xuICB0dWk/OiB7XG4gICAgc2hvd1RvYXN0PzogKHJlcToge1xuICAgICAgYm9keToge1xuICAgICAgICBtZXNzYWdlOiBzdHJpbmdcbiAgICAgICAgdmFyaWFudDogVG9hc3RWYXJpYW50XG4gICAgICAgIGR1cmF0aW9uPzogbnVtYmVyXG4gICAgICB9XG4gICAgfSkgPT4gUHJvbWlzZTx1bmtub3duPlxuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTm90aWZpZXIge1xuICBmYXRhbChzdW1tYXJ5OiBzdHJpbmcsIGRldGFpbD86IHVua25vd24pOiB2b2lkXG4gIHdhcm4oc3VtbWFyeTogc3RyaW5nLCBkZXRhaWw/OiB1bmtub3duKTogdm9pZFxufVxuXG50eXBlIE5vdGlmeUxvZ2dlciA9IFBpY2s8TG9nZ2VyLCBcImVycm9yXCIgfCBcIndhcm5cIiB8IFwiaW5mb1wiIHwgXCJkZWJ1Z1wiPlxuXG5mdW5jdGlvbiBidWlsZE1lc3NhZ2Uoc3VtbWFyeTogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgcmF3ID0gVE9BU1RfUFJFRklYICsgc3VtbWFyeVxuICBpZiAocmF3Lmxlbmd0aCA8PSBUT0FTVF9NQVhfTEVOKSByZXR1cm4gcmF3XG4gIHJldHVybiByYXcuc2xpY2UoMCwgVE9BU1RfTUFYX0xFTiAtIDEpICsgXCJcdTIwMjZcIlxufVxuXG5hc3luYyBmdW5jdGlvbiBzaG93VG9hc3RTYWZlKFxuICBjbGllbnQ6IE5vdGlmaWVyQ2xpZW50IHwgdW5kZWZpbmVkLFxuICBtZXNzYWdlOiBzdHJpbmcsXG4gIHZhcmlhbnQ6IFRvYXN0VmFyaWFudCxcbiAgbG9nZ2VyOiBOb3RpZnlMb2dnZXIsXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgLy8gVGhlIFNESydzIHNob3dUb2FzdCB1c2VzIGB0aGlzLl9jbGllbnRgIGludGVybmFsbHkuIENhbGxpbmcgaXQgYXMgYVxuICAvLyBkZXRhY2hlZCBmdW5jdGlvbiBsb3NlcyBgdGhpc2AgYW5kIHRocm93cyBUeXBlRXJyb3IuIFdlIGNhbGwgaXQgYXMgYVxuICAvLyBtZXRob2Qgb24gYHR1aWAgdG8gcHJlc2VydmUgdGhlIGJpbmRpbmcuXG4gIGNvbnN0IHR1aSA9IGNsaWVudD8udHVpXG4gIGlmICghdHVpIHx8IHR5cGVvZiB0dWkuc2hvd1RvYXN0ICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICByZXR1cm5cbiAgfVxuICB0cnkge1xuICAgIGF3YWl0IHR1aS5zaG93VG9hc3Qoe1xuICAgICAgYm9keTogeyBtZXNzYWdlLCB2YXJpYW50LCBkdXJhdGlvbjogVE9BU1RfRFVSQVRJT05fTVMgfSxcbiAgICB9KVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHZvaWQgbG9nZ2VyLmRlYnVnKFwidG9hc3QgZmFpbGVkXCIsIHtcbiAgICAgIGVycm9yLFxuICAgICAgb3BlcmF0aW9uOiBcInNob3dpbmcgdG9hc3RcIixcbiAgICAgIGlucHV0OiB7IG1lc3NhZ2UsIHZhcmlhbnQgfSxcbiAgICB9KVxuICB9XG59XG5cbmZ1bmN0aW9uIHRyeVNob3dUb2FzdChcbiAgY2xpZW50OiBOb3RpZmllckNsaWVudCB8IHVuZGVmaW5lZCxcbiAgbWVzc2FnZTogc3RyaW5nLFxuICB2YXJpYW50OiBUb2FzdFZhcmlhbnQsXG4gIGxvZ2dlcjogTm90aWZ5TG9nZ2VyLFxuKTogdm9pZCB7XG4gIC8vIERlZmVyIHRvIGxldCB0aGUgVFVJIHN1YnNjcmliZSB0byB0aGUgZXZlbnQgc3RyZWFtIGZpcnN0LiBUaGUgcGx1Z2luJ3NcbiAgLy8gZnVuY3Rpb24gbWF5IGhhdmUgYWxyZWFkeSByZXR1cm5lZCBieSB0aGUgdGltZSB0aGlzIGZpcmVzIFx1MjAxNCB0aGF0IGlzIGZpbmUsXG4gIC8vIHNpbmNlIHRoZSBob3N0IGtlZXBzIHRoZSBwbHVnaW4ncyBKUyBydW50aW1lIGFsaXZlIGZvciB0aGUgc2Vzc2lvbi5cbiAgc2V0VGltZW91dCgoKSA9PiB2b2lkIHNob3dUb2FzdFNhZmUoY2xpZW50LCBtZXNzYWdlLCB2YXJpYW50LCBsb2dnZXIpLCBUT0FTVF9ERUZFUl9NUylcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZU5vdGlmaWVyKFxuICBjbGllbnQ6IE5vdGlmaWVyQ2xpZW50IHwgdW5kZWZpbmVkLFxuICBsb2dnZXI6IE5vdGlmeUxvZ2dlcixcbik6IE5vdGlmaWVyIHtcbiAgcmV0dXJuIHtcbiAgICBmYXRhbChzdW1tYXJ5LCBkZXRhaWwpIHtcbiAgICAgIHZvaWQgbG9nZ2VyLmVycm9yKHN1bW1hcnksIGRldGFpbClcbiAgICAgIHRyeVNob3dUb2FzdChjbGllbnQsIGJ1aWxkTWVzc2FnZShzdW1tYXJ5KSwgXCJlcnJvclwiLCBsb2dnZXIpXG4gICAgfSxcbiAgICB3YXJuKHN1bW1hcnksIGRldGFpbCkge1xuICAgICAgdm9pZCBsb2dnZXIud2FybihzdW1tYXJ5LCBkZXRhaWwpXG4gICAgICB0cnlTaG93VG9hc3QoY2xpZW50LCBidWlsZE1lc3NhZ2Uoc3VtbWFyeSksIFwid2FybmluZ1wiLCBsb2dnZXIpXG4gICAgfSxcbiAgfVxufVxuIiwgImNvbnN0IEVOVl9WQVJfQllfUFJPVklERVI6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gIG9wZW5haTogXCJPUEVOQUlfQVBJX0tFWVwiLFxuICBhbnRocm9waWM6IFwiQU5USFJPUElDX0FQSV9LRVlcIixcbiAgZWxldmVubGFiczogXCJFTEVWRU5MQUJTX0FQSV9LRVlcIixcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVkRW52VmFyKHNsdWc6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuICBjb25zdCBzbGFzaCA9IHNsdWcuaW5kZXhPZihcIi9cIilcbiAgaWYgKHNsYXNoIDw9IDApIHJldHVybiBudWxsXG4gIGNvbnN0IHByb3ZpZGVyID0gc2x1Zy5zbGljZSgwLCBzbGFzaClcbiAgcmV0dXJuIEVOVl9WQVJfQllfUFJPVklERVJbcHJvdmlkZXJdID8/IG51bGxcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDcmVkZW50aWFsQ2hlY2sge1xuICBuYXJyYXRvclNsdWc6IHN0cmluZ1xuICB0dHNTbHVnOiBzdHJpbmdcbn1cblxuZXhwb3J0IHR5cGUgQ3JlZGVudGlhbFJlc3VsdCA9XG4gIHwgeyBvazogdHJ1ZSB9XG4gIHwgeyBvazogZmFsc2U7IG1pc3Npbmc6IHN0cmluZ1tdIH1cblxuZXhwb3J0IGZ1bmN0aW9uIGNoZWNrQ3JlZGVudGlhbHMoXG4gIGNoZWNrOiBDcmVkZW50aWFsQ2hlY2ssXG4gIGVudjogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgdW5kZWZpbmVkPixcbik6IENyZWRlbnRpYWxSZXN1bHQge1xuICBjb25zdCByZXF1aXJlZCA9IG5ldyBTZXQ8c3RyaW5nPigpXG4gIGZvciAoY29uc3Qgc2x1ZyBvZiBbY2hlY2submFycmF0b3JTbHVnLCBjaGVjay50dHNTbHVnXSkge1xuICAgIGNvbnN0IHYgPSByZXF1aXJlZEVudlZhcihzbHVnKVxuICAgIGlmICh2KSByZXF1aXJlZC5hZGQodilcbiAgfVxuICBjb25zdCBtaXNzaW5nOiBzdHJpbmdbXSA9IFtdXG4gIGZvciAoY29uc3QgbmFtZSBvZiByZXF1aXJlZCkge1xuICAgIGNvbnN0IHZhbCA9IGVudltuYW1lXVxuICAgIGlmICh2YWwgPT09IHVuZGVmaW5lZCB8fCB2YWwudHJpbSgpLmxlbmd0aCA9PT0gMCkgbWlzc2luZy5wdXNoKG5hbWUpXG4gIH1cbiAgbWlzc2luZy5zb3J0KClcbiAgcmV0dXJuIG1pc3NpbmcubGVuZ3RoID09PSAwID8geyBvazogdHJ1ZSB9IDogeyBvazogZmFsc2UsIG1pc3NpbmcgfVxufVxuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUFBLE9BQU87OztBQ0FQLFNBQVMsU0FBUzs7O0FDQWxCLFNBQVMsY0FBYztBQUN2QixTQUFTLGlCQUFpQjtBQUMxQixTQUFTLGtCQUFrQjtBQUdwQixJQUFNLGNBQU4sY0FBMEIsTUFBTTtBQUFBLEVBQ3JDLFlBQVksU0FBaUI7QUFDM0IsVUFBTSxPQUFPO0FBQ2IsU0FBSyxPQUFPO0FBQUEsRUFDZDtBQUNGO0FBTU8sSUFBTSxVQUFVO0FBRXZCLFNBQVMsVUFBVSxNQUFjLE9BQWlDO0FBQ2hFLE1BQUksQ0FBQyxRQUFRLEtBQUssSUFBSSxHQUFHO0FBQ3ZCLFVBQU0sSUFBSTtBQUFBLE1BQ1IsR0FBRyxLQUFLLHlEQUF5RCxJQUFJO0FBQUEsSUFDdkU7QUFBQSxFQUNGO0FBQ0EsUUFBTSxNQUFNLEtBQUssUUFBUSxHQUFHO0FBQzVCLFNBQU8sQ0FBQyxLQUFLLE1BQU0sR0FBRyxHQUFHLEdBQUcsS0FBSyxNQUFNLE1BQU0sQ0FBQyxDQUFDO0FBQ2pEO0FBRU8sU0FBUyxxQkFBcUIsTUFBNkI7QUFDaEUsUUFBTSxDQUFDLFVBQVUsT0FBTyxJQUFJLFVBQVUsTUFBTSxnQkFBZ0I7QUFDNUQsVUFBUSxVQUFVO0FBQUEsSUFDaEIsS0FBSztBQUNILGFBQU8sT0FBTyxPQUFPO0FBQUEsSUFDdkIsS0FBSztBQUNILGFBQU8sVUFBVSxPQUFPO0FBQUEsSUFDMUI7QUFDRSxZQUFNLElBQUk7QUFBQSxRQUNSLDhCQUE4QixRQUFRLFNBQVMsSUFBSTtBQUFBLE1BQ3JEO0FBQUEsRUFDSjtBQUNGO0FBSU8sU0FBUyxtQkFBbUIsTUFBOEI7QUFDL0QsUUFBTSxDQUFDLFVBQVUsT0FBTyxJQUFJLFVBQVUsTUFBTSxXQUFXO0FBQ3ZELFVBQVEsVUFBVTtBQUFBLElBQ2hC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
|