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/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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