@pipeline-builder/pipeline-manager 4.1.23 → 4.1.25
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/agent/health.d.ts.map +1 -1
- package/dist/agent/health.js +4 -4
- package/dist/commands/provision-steps.d.ts +174 -0
- package/dist/commands/provision-steps.d.ts.map +1 -0
- package/dist/commands/provision-steps.js +597 -0
- package/dist/commands/provision.d.ts +7 -144
- package/dist/commands/provision.d.ts.map +1 -1
- package/dist/commands/provision.js +18 -593
- package/dist/utils/device-auth.d.ts.map +1 -1
- package/dist/utils/device-auth.js +3 -6
- package/package.json +4 -4
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { readFileSync, existsSync } from 'fs';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import * as readline from 'node:readline/promises';
|
|
6
|
+
import { diagnoseFailure, isAiConfigured } from '../agent/ai.js';
|
|
7
|
+
import { bootstrapCommand } from '../agent/bootstrap.js';
|
|
8
|
+
import { createEnvFile, envFileMissing } from '../agent/env-file.js';
|
|
9
|
+
import { entrypointExists, runScript } from '../agent/executor.js';
|
|
10
|
+
import { waitHealthy, ensureMinikubeGateway } from '../agent/health.js';
|
|
11
|
+
import { checkHostPorts, discoverHostPorts, stackRunning } from '../agent/ports.js';
|
|
12
|
+
import { resolvePostSteps } from '../agent/post-steps.js';
|
|
13
|
+
import { checkPrereqs, gitAvailable, prereqsSatisfied } from '../agent/prereqs.js';
|
|
14
|
+
import { assembleCommand, LOAD_STEPS, sparsePathsFor, teardownCommand, } from '../agent/targets.js';
|
|
15
|
+
import { TOOLS_DIR, fetchTool, isFetchable } from '../agent/tools.js';
|
|
16
|
+
import { matchIssues } from '../agent/troubleshoot.js';
|
|
17
|
+
import { shellQuote } from '../config/cli.constants.js';
|
|
18
|
+
import { printSection, printKeyValue, printInfo, printWarning, printError, printSuccess } from '../utils/output-utils.js';
|
|
19
|
+
export const INIT_MODES = ['auto', 'manual', 'skip'];
|
|
20
|
+
/**
|
|
21
|
+
* Resolve the init mode from `--init <mode>`, defaulting to `auto` when the flag is absent.
|
|
22
|
+
* Returns `null` when `--init` was given an invalid value (caller errors).
|
|
23
|
+
*/
|
|
24
|
+
export function resolveInitMode(options) {
|
|
25
|
+
if (typeof options.init === 'string') { // --init <mode>
|
|
26
|
+
const m = options.init.toLowerCase();
|
|
27
|
+
return INIT_MODES.includes(m) ? m : null;
|
|
28
|
+
}
|
|
29
|
+
return 'auto'; // default
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Read one line of trimmed input from the terminal, owning the readline
|
|
33
|
+
* lifecycle. Used directly for the destructive teardown gate (a y/N is too easy
|
|
34
|
+
* to fat-finger, so we require the operator to TYPE the target id back), and as
|
|
35
|
+
* the basis for `confirm`. Deliberately has no auto-accept.
|
|
36
|
+
*/
|
|
37
|
+
async function ask(question) {
|
|
38
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
39
|
+
try {
|
|
40
|
+
return (await rl.question(question)).trim();
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
rl.close();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Interactive y/N confirmation; auto-true when `autoYes` (the `--yes` flag). */
|
|
47
|
+
export async function confirm(question, autoYes) {
|
|
48
|
+
if (autoYes)
|
|
49
|
+
return true;
|
|
50
|
+
const answer = (await ask(`${question} [y/N] `)).toLowerCase();
|
|
51
|
+
return answer === 'y' || answer === 'yes';
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Host-port pre-flight (local/minikube). Ports are DERIVED from the target's cloned
|
|
55
|
+
* deploy source (compose / setup.sh) so the list can't drift — hence this runs AFTER
|
|
56
|
+
* the clone. A taken port makes a container/forward fail to bind mid-deploy (for the
|
|
57
|
+
* gateway, a silent unreachable hang). Prints a ✓/✗ summary and returns false ONLY
|
|
58
|
+
* when the caller must ABORT (a fatal local conflict). minikube ports are managed
|
|
59
|
+
* forwards (setup.sh pkills/restarts them), so a conflict there warns but proceeds.
|
|
60
|
+
* Remote targets (ec2/eks) bind nothing locally → returns true.
|
|
61
|
+
*/
|
|
62
|
+
export async function preflightPorts(spec, target, cwd) {
|
|
63
|
+
const ports = discoverHostPorts(target, cwd, spec);
|
|
64
|
+
if (ports.length === 0)
|
|
65
|
+
return true;
|
|
66
|
+
const portChecks = await checkHostPorts(ports);
|
|
67
|
+
const taken = portChecks.filter((c) => !c.available);
|
|
68
|
+
printSection('Port availability');
|
|
69
|
+
for (const c of portChecks)
|
|
70
|
+
printInfo(`${c.available ? '✓' : '✗'} ${String(c.port).padEnd(5)} — ${c.service}`);
|
|
71
|
+
if (taken.length === 0)
|
|
72
|
+
return true;
|
|
73
|
+
// local PUBLISHES these ports at `docker compose up` time, so a conflict is fatal.
|
|
74
|
+
// minikube's are kubectl port-forwards setup.sh pkills + restarts (and
|
|
75
|
+
// ensureMinikubeGateway recovers), so a stale forward must NOT block a re-run.
|
|
76
|
+
const fatal = target === 'docker';
|
|
77
|
+
// …UNLESS the local stack is already running: those ports are held by YOUR OWN
|
|
78
|
+
// stack, and `docker compose up` no-ops them — this is exactly how you re-run to
|
|
79
|
+
// add loads/options. Don't block (the would-be conflict is a self-conflict).
|
|
80
|
+
if (fatal && stackRunning(target, cwd, spec)) {
|
|
81
|
+
printWarning(`\n${taken.length} port(s) are held by your already-running ${spec.label} stack — re-running just resumes it (no real conflict), so continuing.`);
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
const lead = `${taken.length} required port(s) already in use: ${taken.map((c) => c.port).join(', ')}`;
|
|
85
|
+
(fatal ? printError : printWarning)(fatal
|
|
86
|
+
? `\n${lead} — the deploy can't bind them and would fail mid-way. Free them and re-run:`
|
|
87
|
+
: `\n${lead} — on minikube these are usually a previous run's port-forwards (setup.sh restarts them). Free any NON-minikube holder if the gateway stays unreachable:`);
|
|
88
|
+
for (const c of taken)
|
|
89
|
+
printInfo(` • port ${c.port} (${c.service}) — find the holder: lsof -i :${c.port}`);
|
|
90
|
+
if (taken.some((c) => c.port === 5000)) {
|
|
91
|
+
printInfo(' Note: on macOS, port 5000 is usually AirPlay Receiver — System Settings → General → AirDrop & Handoff → AirPlay Receiver (off).');
|
|
92
|
+
}
|
|
93
|
+
return !fatal;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Teardown mode — the destroy counterpart of provisioning, gated HARDER than deploy:
|
|
97
|
+
* AWS targets are irreversible, so the operator must TYPE the target id (--force
|
|
98
|
+
* bypasses for CI; --yes alone does NOT). Terminal: owns its output + exitCode.
|
|
99
|
+
*/
|
|
100
|
+
export async function runTeardown(spec, target, cwd, executionId, opts) {
|
|
101
|
+
const { command: downCommand, destructive } = teardownCommand(target, {
|
|
102
|
+
stackName: opts.stackName,
|
|
103
|
+
clusterName: opts.clusterName,
|
|
104
|
+
region: opts.region,
|
|
105
|
+
// eks teardown (bin/shutdown.sh) also cleans up the ACM cert + Route 53 alias for
|
|
106
|
+
// the domain, so forward them when present.
|
|
107
|
+
domain: opts.domain,
|
|
108
|
+
hostedZoneId: opts.hostedZoneId,
|
|
109
|
+
// Our typed gate IS the confirmation — assumeYes forwards a native `--yes` to any
|
|
110
|
+
// script-based teardown (ec2 delete-stack has no prompt; eks shutdown.sh skips its own).
|
|
111
|
+
assumeYes: true,
|
|
112
|
+
});
|
|
113
|
+
if (opts.json) {
|
|
114
|
+
console.log(JSON.stringify({ success: true, executionId, target, teardown: true, destructive, destroys: spec.destroys, command: downCommand }, null, 2));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
printSection(`Teardown plan — ${spec.label}`);
|
|
118
|
+
printKeyValue({ 'Target': target, 'Destroys': spec.destroys, 'Stops cost': spec.cost });
|
|
119
|
+
printSection('Command to run');
|
|
120
|
+
printInfo(downCommand);
|
|
121
|
+
if (destructive && !opts.force) {
|
|
122
|
+
// Bind the confirmation to the resource actually destroyed: a custom name (ec2
|
|
123
|
+
// --stack-name / eks --cluster-name) must be typed verbatim so a wrong name can't be
|
|
124
|
+
// confirmed by habit; otherwise the target id.
|
|
125
|
+
const resourceName = target === 'eks' ? opts.clusterName : opts.stackName;
|
|
126
|
+
const confirmToken = resourceName ?? target;
|
|
127
|
+
const noun = target === 'eks' ? (opts.clusterName ? 'cluster name' : 'target id') : (opts.stackName ? 'stack name' : 'target id');
|
|
128
|
+
const token = await ask(`\nThis is IRREVERSIBLE. Type "${confirmToken}" to confirm teardown: `);
|
|
129
|
+
if (token !== confirmToken) {
|
|
130
|
+
printWarning(`That didn't match, so nothing was destroyed — you have to type the exact ${noun} to confirm.`);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else if (!destructive && !opts.force && !(await confirm('\nProceed with teardown (stops the stack; on-disk data persists)?', opts.yes ?? false))) {
|
|
135
|
+
printWarning('No problem — nothing was changed.');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
printSection('Tearing down');
|
|
139
|
+
const { code: downCode } = await runScript(downCommand, cwd, { capture: false });
|
|
140
|
+
if (downCode !== 0) {
|
|
141
|
+
printError(`\nTeardown failed (exit ${downCode}). Inspect the stack/containers and retry.`);
|
|
142
|
+
process.exitCode = 1;
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
printSuccess('Teardown complete.');
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Run the deploy command (real, secrets unmasked, streamed + captured) with a
|
|
149
|
+
* bounded auto-fix + retry loop — the deploy scripts are idempotent, so a fixed
|
|
150
|
+
* re-run resumes rather than starting over. Returns whether it succeeded plus the
|
|
151
|
+
* (possibly fix-adjusted) params, which the caller needs for SES guidance.
|
|
152
|
+
*/
|
|
153
|
+
export async function runDeployWithRetry(spec, url, cwd, params, aiOpts, opts) {
|
|
154
|
+
// Bound retries so an unattended `--yes` run can't auto-re-run a 15–30 min
|
|
155
|
+
// deploy an unbounded number of times on a persistently-retryable signature.
|
|
156
|
+
const MAX_RETRIES = 5;
|
|
157
|
+
const requestedRetries = Math.max(0, parseInt(opts.retries ?? '', 10) || 0);
|
|
158
|
+
const maxAttempts = 1 + Math.min(requestedRetries, MAX_RETRIES);
|
|
159
|
+
let runParams = params;
|
|
160
|
+
let succeeded = false;
|
|
161
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
162
|
+
const realCommand = assembleCommand(spec, runParams, { mask: false }).command;
|
|
163
|
+
printSection(attempt === 1 ? 'Deploying' : `Deploying — retry ${attempt - 1}`);
|
|
164
|
+
if (attempt === 1) {
|
|
165
|
+
printInfo(`Deploying ${spec.label} → ${url}`);
|
|
166
|
+
printInfo(spec.deploys);
|
|
167
|
+
printInfo('Streaming the deploy below — first run is the slow one (image pulls + cert generation).');
|
|
168
|
+
}
|
|
169
|
+
const { code, tail } = await runScript(realCommand, cwd, { capture: true });
|
|
170
|
+
if (code === 0) {
|
|
171
|
+
succeeded = true;
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
printError(`\nDeploy failed (exit ${code}).`);
|
|
175
|
+
const issues = matchIssues(tail);
|
|
176
|
+
if (issues.length > 0) {
|
|
177
|
+
printSection('Likely cause');
|
|
178
|
+
for (const i of issues)
|
|
179
|
+
printInfo(`• ${i.cause}\n → ${i.suggestion}`);
|
|
180
|
+
}
|
|
181
|
+
if (isAiConfigured(aiOpts)) {
|
|
182
|
+
const diagnosis = await diagnoseFailure(redactSecrets(tail, spec, runParams), aiOpts);
|
|
183
|
+
if (diagnosis) {
|
|
184
|
+
printSection('Diagnosis');
|
|
185
|
+
printInfo(diagnosis);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (attempt >= maxAttempts)
|
|
189
|
+
break;
|
|
190
|
+
// Auto-fix: a retryable issue with a param we haven't already applied.
|
|
191
|
+
const fix = issues.find((i) => i.retryable && i.paramFix && runParams[i.paramFix.key] !== i.paramFix.value);
|
|
192
|
+
if (fix?.paramFix && await confirm(`\nApply fix and retry — ${fix.suggestion}`, opts.yes ?? false)) {
|
|
193
|
+
runParams = { ...runParams, [fix.paramFix.key]: fix.paramFix.value };
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
// Retryable but no param change (e.g. ACM DNS propagation) — offer a plain re-run.
|
|
197
|
+
if (!fix && issues.some((i) => i.retryable) && await confirm('\nRetry the deploy (safe to re-run — it resumes where it left off)?', opts.yes ?? false)) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
return { succeeded, runParams };
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Execute the post-install steps (register → loads → smoke → events → custom). On
|
|
206
|
+
* EC2/EKS the register step + the events bundle (store-token → setup-events) are
|
|
207
|
+
* SURFACED as ordered manual next-steps instead of auto-run: ec2 register must run
|
|
208
|
+
* ON the box (the minikube user owns the cluster), and the events bundle needs a
|
|
209
|
+
* registered platform + AWS creds. (eks register itself port-forwards, so it runs
|
|
210
|
+
* from anywhere with kubectl access.) Sets exitCode on a step failure.
|
|
211
|
+
*/
|
|
212
|
+
export async function runPostSteps(postSteps, skippedSteps, target, cwd, adminEnv, opts) {
|
|
213
|
+
// AWS targets with `--init auto`: the deploy self-runs init-platform, so there's no
|
|
214
|
+
// register/loads step to surface here — confirm it and point at where to watch.
|
|
215
|
+
if (opts.autoInit && target === 'ec2') {
|
|
216
|
+
printInfo('\n✓ Init mode: auto — the instance runs init-platform itself on first boot');
|
|
217
|
+
printInfo(' (register admin + build bootstrap image + load plugins/compliance/samples).');
|
|
218
|
+
printInfo(' It takes ~30-60 min; watch progress:');
|
|
219
|
+
printInfo(' aws ssm start-session --target <InstanceId> # InstanceId stack output');
|
|
220
|
+
printInfo(' sudo tail -f /var/log/user-data.log');
|
|
221
|
+
}
|
|
222
|
+
else if (opts.autoInit && target === 'eks') {
|
|
223
|
+
printInfo('\n✓ Init mode: auto — setup.sh runs init-platform in its final phase');
|
|
224
|
+
printInfo(' (register admin + build bootstrap image + load plugins/compliance/samples,');
|
|
225
|
+
printInfo(' over a kubectl port-forward). Pass --init manual to run it yourself instead.');
|
|
226
|
+
}
|
|
227
|
+
if (postSteps.length === 0)
|
|
228
|
+
return;
|
|
229
|
+
for (const s of skippedSteps)
|
|
230
|
+
printWarning(`Skipped post-step ${s.id}: ${s.reason}`);
|
|
231
|
+
const isRemote = (id) => (target === 'ec2' || target === 'eks') && (id === 'register' || id.startsWith('store-token') || id === 'events');
|
|
232
|
+
const runnable = postSteps.filter((s) => !isRemote(s.id));
|
|
233
|
+
const remote = postSteps.filter((s) => isRemote(s.id));
|
|
234
|
+
if (remote.length > 0) {
|
|
235
|
+
if (target === 'ec2') {
|
|
236
|
+
// EC2 runs the platform as a dedicated `minikube` user inside the instance: the
|
|
237
|
+
// cluster, its kubeconfig, and the jwt-secret all belong to that user, and the
|
|
238
|
+
// register step builds+pushes images against it. So it MUST run on the box as
|
|
239
|
+
// `minikube` — print the exact landing sequence rather than a bare command.
|
|
240
|
+
printInfo('\nNext — finish setup ON the instance (it builds images + reads the cluster, so it');
|
|
241
|
+
printInfo('cannot run from here). Land on the box, become the `minikube` user, then run it:');
|
|
242
|
+
printInfo(' aws ssm start-session --target <InstanceId> # InstanceId stack output');
|
|
243
|
+
printInfo(' sudo -iu minikube # owns the cluster + docker');
|
|
244
|
+
printInfo(' cd /opt/pipeline/pipeline-builder # the deployed checkout');
|
|
245
|
+
for (const s of remote)
|
|
246
|
+
printInfo(` ${s.command}`);
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
// eks: init-platform port-forwards to svc/nginx, so register runs from anywhere with
|
|
250
|
+
// kubectl access — no in-VPC requirement and no waiting on the ALB/DNS. (A --with-events
|
|
251
|
+
// bundle, if present, additionally needs AWS creds + a registered platform.)
|
|
252
|
+
printInfo('\nNext — run with kubectl access to the cluster (in this order):');
|
|
253
|
+
for (const s of remote)
|
|
254
|
+
printInfo(` • ${s.label} — ${s.command}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (runnable.length === 0)
|
|
258
|
+
return;
|
|
259
|
+
// When the loads were picked interactively (autoRun), the user already opted in — skip
|
|
260
|
+
// the redundant second confirm. Flag-driven / non-interactive runs still gate here.
|
|
261
|
+
if (opts.autoRun || await confirm(`\nRun ${runnable.length} post-install step(s) now?`, opts.yes ?? false)) {
|
|
262
|
+
if (opts.autoRun)
|
|
263
|
+
printInfo(`\nRunning the ${runnable.length} post-install step(s) you selected…`);
|
|
264
|
+
for (const s of runnable) {
|
|
265
|
+
printSection(`Post-step: ${s.label}`);
|
|
266
|
+
// register (local/minikube) logs into the platform, so it needs the admin creds
|
|
267
|
+
// (PLATFORM_IDENTIFIER / PLATFORM_PASSWORD) on top of its step env.
|
|
268
|
+
const needsCreds = s.id === 'register' || s.id.startsWith('store-token');
|
|
269
|
+
const env = needsCreds ? { ...s.env, ...adminEnv } : s.env;
|
|
270
|
+
// Loads/smoke are noisy + non-interactive → run QUIET (capture, show only on
|
|
271
|
+
// failure). Exception: a register with no admin creds prompts, so it must stream.
|
|
272
|
+
const interactiveRegister = s.id === 'register' && !adminEnv.PLATFORM_IDENTIFIER;
|
|
273
|
+
const quiet = !interactiveRegister;
|
|
274
|
+
if (quiet)
|
|
275
|
+
printInfo(`${s.command}\n …running (output shown only if it fails)`);
|
|
276
|
+
else
|
|
277
|
+
printInfo(s.command);
|
|
278
|
+
const { code, tail } = await runScript(s.command, cwd, { quiet, capture: false, env });
|
|
279
|
+
if (code !== 0) {
|
|
280
|
+
if (quiet && tail) {
|
|
281
|
+
printError('\n--- last output ---');
|
|
282
|
+
printInfo(tail);
|
|
283
|
+
}
|
|
284
|
+
printError(`\nPost-step '${s.id}' failed (exit ${code}). The platform is deployed; fix and re-run the step manually.`);
|
|
285
|
+
process.exitCode = 1;
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
printSuccess(`${s.id} ✓`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
printInfo('\nSkipped post-install steps. Run the commands above manually when ready.');
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Sparse-clone the platform repo (when --repo, or accepted via the interactive
|
|
297
|
+
* offer), repoint cwd into it, and verify the deploy entrypoint exists. Owns the
|
|
298
|
+
* cwd/bootstrapped state. Sets exitCode on a hard failure (clone error / missing
|
|
299
|
+
* entrypoint); a plain decline leaves exitCode
|
|
300
|
+
* untouched. Returns ok:false when the caller must abort.
|
|
301
|
+
*/
|
|
302
|
+
export async function bootstrapAndLocate(spec, bootstrap, bootstrapCmd, sparsePaths, startCwd, opts) {
|
|
303
|
+
let cwd = startCwd;
|
|
304
|
+
let bootstrapped = false;
|
|
305
|
+
// Shared by `--repo` and the interactive offer. Repoints cwd + sets bootstrapped;
|
|
306
|
+
// `bootstrapped` records whether we created the clone (vs. an existing checkout) —
|
|
307
|
+
// only then can the caller additively sparse-fetch load folders.
|
|
308
|
+
const bootstrapClone = async () => {
|
|
309
|
+
const cmd = bootstrapCommand(bootstrap);
|
|
310
|
+
printSection('Bootstrap');
|
|
311
|
+
printInfo(cmd);
|
|
312
|
+
const { code } = await runScript(cmd, cwd, { capture: false });
|
|
313
|
+
if (code !== 0) {
|
|
314
|
+
printError(`\nThe clone didn't finish (exit ${code}). Double-check the repo URL / ref (or your network) and give it another go.`);
|
|
315
|
+
process.exitCode = 1;
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
cwd = path.resolve(cwd, bootstrap.workdir);
|
|
319
|
+
bootstrapped = true;
|
|
320
|
+
printSuccess(`Repo is ready — continuing from ${cwd}`);
|
|
321
|
+
const absent = sparsePaths.filter((p) => !existsSync(path.join(cwd, p)));
|
|
322
|
+
if (absent.length > 0) {
|
|
323
|
+
printError(`\nThe sparse clone is missing ${absent.join(', ')} — that ref may not have those folders. Try a different --ref.`);
|
|
324
|
+
process.exitCode = 1;
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
return true;
|
|
328
|
+
};
|
|
329
|
+
// `--repo`: clone up front (must precede the entrypoint check).
|
|
330
|
+
if (bootstrapCmd) {
|
|
331
|
+
printInfo(`\nBootstrap → clone ${bootstrap.repo} @ ${bootstrap.ref} into ${bootstrap.workdir} (sparse).`);
|
|
332
|
+
if (!(await confirm('Go ahead with the clone?', opts.yes ?? false))) {
|
|
333
|
+
printWarning('No problem — nothing was changed. Re-run whenever you\'re ready.');
|
|
334
|
+
return { cwd, bootstrapped, ok: false };
|
|
335
|
+
}
|
|
336
|
+
if (!(await bootstrapClone()))
|
|
337
|
+
return { cwd, bootstrapped, ok: false };
|
|
338
|
+
}
|
|
339
|
+
// The deploy entrypoint must exist relative to cwd. If it doesn't and we haven't
|
|
340
|
+
// bootstrapped, gracefully OFFER to clone (interactive only) so a fresh machine can
|
|
341
|
+
// proceed without re-running with --repo.
|
|
342
|
+
if (!entrypointExists(spec, cwd)) {
|
|
343
|
+
const interactive = Boolean(process.stdin.isTTY) && !opts.yes;
|
|
344
|
+
if (!bootstrapCmd && interactive && gitAvailable()) {
|
|
345
|
+
printInfo(`\nLooks like you're not inside a pipeline-builder checkout, so the ${spec.label} deploy scripts aren't here yet.`);
|
|
346
|
+
if (await confirm(`Want me to sparse-clone them into ${bootstrap.workdir} and keep going?`, false)) {
|
|
347
|
+
if (!(await bootstrapClone()))
|
|
348
|
+
return { cwd, bootstrapped, ok: false };
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (!entrypointExists(spec, cwd)) {
|
|
352
|
+
printWarning(`\nI couldn't find ${spec.dir}/${spec.entrypoint} from ${cwd}.`);
|
|
353
|
+
printInfo('Two easy ways forward:');
|
|
354
|
+
printInfo(' • cd into your pipeline-builder checkout and re-run, or');
|
|
355
|
+
printInfo(` • add --repo and I'll bootstrap a fresh sparse clone for you${gitAvailable() ? '.' : ' (once git is installed).'}`);
|
|
356
|
+
process.exitCode = 1;
|
|
357
|
+
return { cwd, bootstrapped, ok: false };
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return { cwd, bootstrapped, ok: true };
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Interactive opt-in loads, offered AFTER the clone (so we only ask once the operator
|
|
364
|
+
* has agreed to proceed). Prompts per load, additively sparse-fetches the picked
|
|
365
|
+
* folders into a bootstrapped sparse clone, then re-resolves the post-install steps
|
|
366
|
+
* with the selections. Returns the chosen ids + the recomputed steps.
|
|
367
|
+
*/
|
|
368
|
+
export async function resolveLoadsInteractively(target, url, region, cwd, bootstrapped, bootstrap, postStepFlags) {
|
|
369
|
+
const prompts = {
|
|
370
|
+
plugins: 'Load plugins?',
|
|
371
|
+
samples: 'Load sample pipeline templates?',
|
|
372
|
+
compliance: 'Load compliance rules?',
|
|
373
|
+
};
|
|
374
|
+
printSection('Optional post-install loads');
|
|
375
|
+
const chosen = [];
|
|
376
|
+
for (const s of LOAD_STEPS) {
|
|
377
|
+
if (await confirm(prompts[s.id] ?? `Load ${s.id}?`, false))
|
|
378
|
+
chosen.push(s.id);
|
|
379
|
+
}
|
|
380
|
+
// Additive sparse re-sync: materialize ONLY the picked loads' folders (the partial
|
|
381
|
+
// clone fetches their blobs on demand). Only when we created a SPARSE clone — a
|
|
382
|
+
// normal checkout already has every folder, and the git<2.27 full-clone fallback
|
|
383
|
+
// (bootstrap.full) is non-sparse, where `sparse-checkout add` would switch it to
|
|
384
|
+
// cone mode and PRUNE the already-materialized deploy folders.
|
|
385
|
+
if (bootstrapped && !bootstrap.full) {
|
|
386
|
+
const absent = sparsePathsFor(target, chosen).filter((p) => !existsSync(path.join(cwd, p)));
|
|
387
|
+
if (absent.length > 0) {
|
|
388
|
+
printSection('Fetching selected load folders');
|
|
389
|
+
const addCmd = `git sparse-checkout add ${absent.map((p) => `'${p}'`).join(' ')} && git checkout ${shellQuote(bootstrap.ref)}`;
|
|
390
|
+
printInfo(addCmd);
|
|
391
|
+
const { code } = await runScript(addCmd, cwd, { capture: false });
|
|
392
|
+
if (code !== 0) {
|
|
393
|
+
printWarning(`Couldn't fetch ${absent.join(', ')} — the matching load step(s) may fail. Re-run with --repo to refresh the clone.`);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
const resolved = resolvePostSteps({
|
|
398
|
+
target,
|
|
399
|
+
url,
|
|
400
|
+
region,
|
|
401
|
+
enabledLoadIds: chosen,
|
|
402
|
+
...postStepFlags,
|
|
403
|
+
buildBootstrap: postStepFlags.buildBootstrap || chosen.includes('plugins'),
|
|
404
|
+
});
|
|
405
|
+
return { enabledLoadIds: chosen, steps: resolved.steps, skipped: resolved.skipped };
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Redact secret param values (e.g. the ghcr token) from captured deploy output
|
|
409
|
+
* before it is sent to the LLM for diagnosis. The deploy runs with secrets
|
|
410
|
+
* unmasked, so although the current scripts don't echo them, this keeps a future
|
|
411
|
+
* script's stray echo (or a verbose sub-tool) from crossing the third-party-LLM
|
|
412
|
+
* boundary.
|
|
413
|
+
*/
|
|
414
|
+
function redactSecrets(text, spec, params) {
|
|
415
|
+
let out = text;
|
|
416
|
+
for (const input of [...spec.required, ...spec.optional]) {
|
|
417
|
+
if (!input.secret)
|
|
418
|
+
continue;
|
|
419
|
+
const value = params[input.key];
|
|
420
|
+
if (typeof value === 'string' && value.length >= 4)
|
|
421
|
+
out = out.split(value).join('***');
|
|
422
|
+
}
|
|
423
|
+
return out;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Assemble deploy params from explicit flags (flags always win over the NL
|
|
427
|
+
* parse, which only fills gaps).
|
|
428
|
+
*/
|
|
429
|
+
export function buildParams(options, selfInit) {
|
|
430
|
+
return {
|
|
431
|
+
region: options.region,
|
|
432
|
+
domain: options.domain,
|
|
433
|
+
hostedZoneId: options.hostedZoneId,
|
|
434
|
+
deployMode: options.deployMode,
|
|
435
|
+
keyPair: options.keyPair,
|
|
436
|
+
instanceType: options.instanceType,
|
|
437
|
+
// ec2 LEAN mode (boolean) → assembleCommand emits `--lean`, which setup.sh
|
|
438
|
+
// forwards to the CFN `Lean` param. Only ec2's spec lists it; other targets ignore it.
|
|
439
|
+
lean: options.lean === true,
|
|
440
|
+
// Deploy-time resource identity: ec2 emits --stack-name (key stackName), eks emits
|
|
441
|
+
// --cluster-name (key clusterName). Both also drive teardown. Undefined → defaults.
|
|
442
|
+
stackName: options.stackName,
|
|
443
|
+
clusterName: options.clusterName,
|
|
444
|
+
ghcrToken: options.ghcrToken,
|
|
445
|
+
// email/noEmail are coerced AFTER the NL merge below — parseGoal can return
|
|
446
|
+
// `email`, so pre-coercing here (never-undefined) would let the merge's
|
|
447
|
+
// `=== undefined` guard silently drop an AI-parsed email choice. Left out of
|
|
448
|
+
// this literal on purpose; resolved a few lines down.
|
|
449
|
+
emailFrom: options.emailFrom,
|
|
450
|
+
emailFromName: options.emailFromName,
|
|
451
|
+
alertEmail: options.alertEmail,
|
|
452
|
+
noCreateSesIdentity: options.skipSesIdentity,
|
|
453
|
+
// The AWS deploys self-init by default (ec2 on first boot, eks in setup.sh's final
|
|
454
|
+
// phase), so we emit the load-bearing `--no-auto-init` when the mode is NOT auto
|
|
455
|
+
// (manual/skip = "don't let the deploy init itself"). `--auto-init` (a no-op reaffirm)
|
|
456
|
+
// is never emitted. Only ec2/eks carry these flags in their spec; other targets ignore it.
|
|
457
|
+
noAutoInit: !selfInit,
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* `--diagnose <file>`: explain a deploy failure with the configured model. A
|
|
462
|
+
* read-only inspection mode — the caller returns afterwards whether or not a
|
|
463
|
+
* target was given, so it never falls through into a (possibly --yes) deploy.
|
|
464
|
+
*/
|
|
465
|
+
export async function runDiagnose(file, json, aiOpts, executionId) {
|
|
466
|
+
let failureText;
|
|
467
|
+
try {
|
|
468
|
+
failureText = readFileSync(file, 'utf-8');
|
|
469
|
+
}
|
|
470
|
+
catch {
|
|
471
|
+
printError(`Cannot read --diagnose file: ${file}`);
|
|
472
|
+
process.exitCode = 1;
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
const diagnosis = isAiConfigured(aiOpts) ? await diagnoseFailure(failureText, aiOpts) : null;
|
|
476
|
+
// With --json, the diagnosis IS the machine-readable output — emit it
|
|
477
|
+
// alone (don't also print text, which would corrupt the JSON stream).
|
|
478
|
+
if (json) {
|
|
479
|
+
console.log(JSON.stringify({ success: true, executionId, diagnosis }, null, 2));
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
if (diagnosis) {
|
|
483
|
+
printSection('Failure diagnosis');
|
|
484
|
+
printInfo(diagnosis);
|
|
485
|
+
}
|
|
486
|
+
else {
|
|
487
|
+
printWarning('Diagnosis unavailable (no AI key configured or the model could not be reached).');
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
/** Print the provision plan (shown before the gated execution). */
|
|
491
|
+
export function printPlan(p) {
|
|
492
|
+
const { spec, target, prereqs, missing, bootstrap, bootstrapCmd, sparsePaths, command, postSteps, skippedSteps } = p;
|
|
493
|
+
printSection(`Provision plan — ${spec.label}`);
|
|
494
|
+
printKeyValue({ 'Target': target, 'Best for': spec.bestFor, 'Cost': spec.cost });
|
|
495
|
+
printSection('Prerequisites');
|
|
496
|
+
for (const c of prereqs)
|
|
497
|
+
printInfo(`${c.ok ? '✓' : '✗'} ${c.name} — ${c.detail}`);
|
|
498
|
+
if (!prereqsSatisfied(prereqs))
|
|
499
|
+
printWarning('Resolve the failing prerequisites above before deploying.');
|
|
500
|
+
if (missing.length > 0) {
|
|
501
|
+
printSection('Missing required inputs');
|
|
502
|
+
for (const m of missing)
|
|
503
|
+
printInfo(` --${m.flag} (${m.description})`);
|
|
504
|
+
}
|
|
505
|
+
if (bootstrapCmd) {
|
|
506
|
+
printSection('Bootstrap (sparse git clone, runs first)');
|
|
507
|
+
printInfo(`Clone ${bootstrap.repo} @ ${bootstrap.ref} → ${bootstrap.workdir}; folders: ${sparsePaths.join(', ')}`);
|
|
508
|
+
printInfo(bootstrapCmd);
|
|
509
|
+
}
|
|
510
|
+
printSection('Command to run');
|
|
511
|
+
printInfo(command);
|
|
512
|
+
if (postSteps.length > 0 || skippedSteps.length > 0) {
|
|
513
|
+
printSection('Post-install steps');
|
|
514
|
+
for (const s of postSteps)
|
|
515
|
+
printInfo(`• ${s.label}\n ${s.command}`);
|
|
516
|
+
for (const s of skippedSteps)
|
|
517
|
+
printWarning(`Skipped ${s.id}: ${s.reason}`);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Plugins were picked interactively: re-check the plugin-specific prereqs that
|
|
522
|
+
* were deliberately not hard-required up front (e.g. yq for minikube plugin
|
|
523
|
+
* builds). Offer to fetch any fetchable one; warn (don't block — the platform
|
|
524
|
+
* still deploys) if it can't be resolved, so the later plugin build doesn't
|
|
525
|
+
* fail opaquely.
|
|
526
|
+
*/
|
|
527
|
+
export async function recheckPluginPrereqs(target, wantBootstrap, prereqs, yes) {
|
|
528
|
+
const pluginPrereqs = checkPrereqs(target, { bootstrap: wantBootstrap, withPlugins: true });
|
|
529
|
+
const pluginGaps = pluginPrereqs.filter((c) => !c.ok && c.required && !prereqs.some((p) => p.name === c.name));
|
|
530
|
+
for (const c of pluginGaps) {
|
|
531
|
+
if (isFetchable(c.name) && await confirm(`\n${c.name} is needed to build plugins but isn't installed — fetch the static binary into ${TOOLS_DIR}?`, yes)) {
|
|
532
|
+
printInfo(`Fetching ${c.name}…`);
|
|
533
|
+
if (!fetchTool(c.name))
|
|
534
|
+
printWarning(`Couldn't fetch ${c.name} — install it before the plugin build runs.`);
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
printWarning(`${c.name} missing — the plugin load/build step may fail. ${c.detail}`);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* local/minikube's setup.sh REQUIRES a `.env` and aborts without it — create
|
|
543
|
+
* it from .env.example with generated secrets so the deploy is non-interactive.
|
|
544
|
+
* ec2 and eks don't need a local `.env`: ec2 bootstraps its secrets on the
|
|
545
|
+
* instance, and eks's setup.sh creates the k8s secrets itself.
|
|
546
|
+
*/
|
|
547
|
+
export async function ensureLocalEnvFile(target, spec, cwd, yes) {
|
|
548
|
+
if ((target !== 'docker' && target !== 'minikube') || !envFileMissing(cwd, spec.dir))
|
|
549
|
+
return;
|
|
550
|
+
if (await confirm(`\n${spec.dir}/.env not found — create it from .env.example (generates secrets; edit later for optional integrations like OAuth)?`, yes)) {
|
|
551
|
+
const n = createEnvFile(cwd, spec.dir);
|
|
552
|
+
printSuccess(`Created ${spec.dir}/.env — ${n} secret(s) generated.`);
|
|
553
|
+
}
|
|
554
|
+
else {
|
|
555
|
+
printWarning('Continuing without .env — setup.sh will abort if it stays missing.');
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Any missing required prereq that's a single static binary (e.g. yq) can be
|
|
560
|
+
* fetched into the tools cache instead of a system install — no brew/apt.
|
|
561
|
+
* Offer it, then re-check (the cache dir is already on PATH). Returns the
|
|
562
|
+
* (possibly refreshed) prereq list.
|
|
563
|
+
*/
|
|
564
|
+
export async function offerToolFetch(prereqs, yes, recheck) {
|
|
565
|
+
const fetchable = prereqs.filter((c) => !c.ok && c.required && isFetchable(c.name));
|
|
566
|
+
if (fetchable.length === 0)
|
|
567
|
+
return prereqs;
|
|
568
|
+
const names = fetchable.map((c) => c.name).join(', ');
|
|
569
|
+
if (!(await confirm(`\n${names} not installed — fetch the official static binary into ${TOOLS_DIR} (no system install)?`, yes)))
|
|
570
|
+
return prereqs;
|
|
571
|
+
for (const c of fetchable) {
|
|
572
|
+
printInfo(`Fetching ${c.name}…`);
|
|
573
|
+
if (!fetchTool(c.name))
|
|
574
|
+
printWarning(`Couldn't fetch ${c.name} — install it manually and re-run.`);
|
|
575
|
+
}
|
|
576
|
+
return recheck();
|
|
577
|
+
}
|
|
578
|
+
/** Verify health after the deploy (CREATE_COMPLETE != serving). */
|
|
579
|
+
export async function verifyHealth(target, url) {
|
|
580
|
+
printSection('Verifying health');
|
|
581
|
+
// Minikube reaches the gateway via a kubectl port-forward that setup.sh
|
|
582
|
+
// backgrounds and that can die/fail to bind — (re)start it before polling
|
|
583
|
+
// so we don't sit at the gate on a dead forward while the pods are fine.
|
|
584
|
+
if (target === 'minikube') {
|
|
585
|
+
await ensureMinikubeGateway(url, { onInfo: (m) => printInfo(m) });
|
|
586
|
+
}
|
|
587
|
+
printInfo(`Polling ${url}/health …`);
|
|
588
|
+
// Fresh EKS legitimately needs longer than the 300s default: Karpenter provisions
|
|
589
|
+
// nodes, ~10 services cold-pull images, the ALB provisions (~2-3 min), and the
|
|
590
|
+
// Route 53 alias propagates. Give it 15 min before surfacing the not-reachable note.
|
|
591
|
+
const healthTimeoutMs = target === 'eks' ? 900_000 : undefined;
|
|
592
|
+
const health = await waitHealthy(url, { timeoutMs: healthTimeoutMs, onTick: (m) => printInfo(m) });
|
|
593
|
+
// Green only when fully ready; a "health OK but /ready never came" proceed-
|
|
594
|
+
// anyway state is healthy:true but degraded → warn so it doesn't read as done.
|
|
595
|
+
(health.healthy && health.ready ? printSuccess : printWarning)(`${health.url} — ${health.detail}`);
|
|
596
|
+
}
|
|
597
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmlzaW9uLXN0ZXBzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRzL3Byb3Zpc2lvbi1zdGVwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQzlDLE9BQU8sS0FBSyxJQUFJLE1BQU0sV0FBVyxDQUFDO0FBQ2xDLE9BQU8sS0FBSyxRQUFRLE1BQU0sd0JBQXdCLENBQUM7QUFDbkQsT0FBTyxFQUFFLGVBQWUsRUFBRSxjQUFjLEVBQWtCLE1BQU0sZ0JBQWdCLENBQUM7QUFDakYsT0FBTyxFQUFFLGdCQUFnQixFQUFzQixNQUFNLHVCQUF1QixDQUFDO0FBQzdFLE9BQU8sRUFBRSxhQUFhLEVBQUUsY0FBYyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDckUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLFNBQVMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ25FLE9BQU8sRUFBRSxXQUFXLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN4RSxPQUFPLEVBQUUsY0FBYyxFQUFFLGlCQUFpQixFQUFFLFlBQVksRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3BGLE9BQU8sRUFBRSxnQkFBZ0IsRUFBbUMsTUFBTSx3QkFBd0IsQ0FBQztBQUMzRixPQUFPLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxnQkFBZ0IsRUFBb0IsTUFBTSxxQkFBcUIsQ0FBQztBQUNyRyxPQUFPLEVBQ0wsZUFBZSxFQUNmLFVBQVUsRUFDVixjQUFjLEVBQ2QsZUFBZSxHQUloQixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3RFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSwwQkFBMEIsQ0FB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cUIsQ0FBQyxHQUFHLEVBQUUsRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDcEUsQ0FBQztJQUNELFNBQVMsQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDLENBQUM7SUFDckMsa0ZBQWtGO0lBQ2xGLCtFQUErRTtJQUMvRSxxRkFBcUY7SUFDckYsTUFBTSxlQUFlLEdBQUcsTUFBTSxLQUFLLEtBQUssQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFDL0QsTUFBTSxNQUFNLEdBQUcsTUFBTSxXQUFXLENBQUMsR0FBRyxFQUFFLEVBQUUsU0FBUyxFQUFFLGVBQWUsRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDbkcsNEVBQTRFO0lBQzVFLCtFQUErRTtJQUMvRSxDQUFDLE1BQU0sQ0FBQyxPQUFPLElBQUksTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxHQUFHLE1BQU0sTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7QUFDckcsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIGV4aXN0c1N5bmMgfSBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQgKiBhcyByZWFkbGluZSBmcm9tICdub2RlOnJlYWRsaW5lL3Byb21pc2VzJztcbmltcG9ydCB7IGRpYWdub3NlRmFpbHVyZSwgaXNBaUNvbmZpZ3VyZWQsIHR5cGUgQWlPcHRpb25zIH0gZnJvbSAnLi4vYWdlbnQvYWkuanMnO1xuaW1wb3J0IHsgYm9vdHN0cmFwQ29tbWFuZCwgdHlwZSBCb290c3RyYXBTcGVjIH0gZnJvbSAnLi4vYWdlbnQvYm9vdHN0cmFwLmpzJztcbmltcG9ydCB7IGNyZWF0ZUVudkZpbGUsIGVudkZpbGVNaXNzaW5nIH0gZnJvbSAnLi4vYWdlbnQvZW52LWZpbGUuanMnO1xuaW1wb3J0IHsgZW50cnlwb2ludEV4aXN0cywgcnVuU2NyaXB0IH0gZnJvbSAnLi4vYWdlbnQvZXhlY3V0b3IuanMnO1xuaW1wb3J0IHsgd2FpdEhlYWx0aHksIGVuc3VyZU1pbmlrdWJlR2F0ZXdheSB9IGZyb20gJy4uL2FnZW50L2hlYWx0aC5qcyc7XG5pbXBvcnQgeyBjaGVja0hvc3RQb3J0cywgZGlzY292ZXJIb3N0UG9ydHMsIHN0YWNrUnVubmluZyB9IGZyb20gJy4uL2FnZW50L3BvcnRzLmpzJztcbmltcG9ydCB7IHJlc29sdmVQb3N0U3RlcHMsIHR5cGUgUG9zdFN0ZXAsIHR5cGUgU2tpcHBlZFN0ZXAgfSBmcm9tICcuLi9hZ2VudC9wb3N0LXN0ZXBzLmpzJztcbmltcG9ydCB7IGNoZWNrUHJlcmVxcywgZ2l0QXZhaWxhYmxlLCBwcmVyZXFzU2F0aXNmaWVkLCB0eXBlIFByZXJlcUNoZWNrIH0gZnJvbSAnLi4vYWdlbnQvcHJlcmVxcy5qcyc7XG5pbXBvcnQge1xuICBhc3NlbWJsZUNvbW1hbmQsXG4gIExPQURfU1RFUFMsXG4gIHNwYXJzZVBhdGhzRm9yLFxuICB0ZWFyZG93bkNvbW1hbmQsXG4gIHR5cGUgQXNzZW1ibGVSZXN1bHQsXG4gIHR5cGUgVGFyZ2V0SWQsXG4gIHR5cGUgVGFyZ2V0U3BlYyxcbn0gZnJvbSAnLi4vYWdlbnQvdGFyZ2V0cy5qcyc7XG5pbXBvcnQgeyBUT09MU19ESVIsIGZldGNoVG9vbCwgaXNGZXRjaGFibGUgfSBmcm9tICcuLi9hZ2VudC90b29scy5qcyc7XG5pbXBvcnQgeyBtYXRjaElzc3VlcyB9IGZyb20gJy4uL2FnZW50L3Ryb3VibGVzaG9vdC5qcyc7XG5pbXBvcnQgeyBzaGVsbFF1b3RlIH0gZnJvbSAnLi4vY29uZmlnL2NsaS5jb25zdGFudHMuanMnO1xuaW1wb3J0IHsgcHJpbnRTZWN0aW9uLCBwcmludEtleVZhbHVlLCBwcmludEluZm8sIHByaW50V2FybmluZywgcHJpbnRFcnJvciwgcHJpbnRTdWNjZXNzIH0gZnJvbSAnLi4vdXRpbHMvb3V0cHV0LXV0aWxzLmpzJztcblxuLyoqXG4gKiBUaGUgYHByb3Zpc2lvbmAgY29tbWFuZCdzIFNURVBTOiBvbmUgZXhwb3J0ZWQgZnVuY3Rpb24gcGVyIHBoYXNlIG9mIGFcbiAqIHByb3Zpc2lvbiBydW4gKHBvcnQgcHJlLWZsaWdodCwgdGVhcmRvd24sIGJvb3RzdHJhcCtsb2NhdGUsIHRoZSBkZXBsb3lcbiAqIHJldHJ5IGxvb3AsIHRoZSBpbnRlcmFjdGl2ZSBsb2FkIHBpY2tlciwgcG9zdC1zdGVwcywgaGVhbHRoLCBkaWFnbm9zZSxcbiAqIHBsYW4gcHJpbnRpbmcpLlxuICpcbiAqIFNwbGl0IG91dCBmcm9tIGBwcm92aXNpb24udHNgIHNvIHRoYXQgZmlsZSBob2xkcyBvbmx5IHdoYXQgaXQgaXMgYWJvdXQg4oCUIHRoZVxuICogfjQwLW9wdGlvbiB0YWJsZSBhbmQgdGhlIHNlcXVlbmNpbmcgbmFycmF0aXZlIHRoYXQgY2FsbHMgdGhlc2UgaW4gb3JkZXIuIFRoZVxuICogc3RlcHMgYXJlIHRoZSBwYXJ0IHdpdGggYmVoYXZpb3VyIHdvcnRoIHRlc3Rpbmcgb24gaXRzIG93biwgYW5kIHRoZSByZXBvXG4gKiBhbHJlYWR5IGNhbGxzIHRoZW0gdGhhdCAoYHRlc3QvcHJvdmlzaW9uLXNlYW1zLnRlc3QudHNgKS5cbiAqXG4gKiBFYWNoIHN0ZXAgdGFrZXMgd2hhdCBpdCBuZWVkcyBhbmQgcmV0dXJucyB3aGF0IHRoZSBuZXh0IG9uZSBuZWVkczogbm9cbiAqIG1vZHVsZS1sZXZlbCBtdXRhYmxlIHN0YXRlIGNyb3NzZXMgdGhpcyBib3VuZGFyeSwgc28gdGhlIHR3byBoYWx2ZXMgY2FuIGJlXG4gKiByZWFkIGluZGVwZW5kZW50bHkuXG4gKi9cblxuLyoqXG4gKiBQb3N0LWRlcGxveSBpbml0aWFsaXphdGlvbiBtb2RlICh0aGUgc2luZ2xlIGAtLWluaXQgPG1vZGU+YCBmbGFnKTpcbiAqICAgLSBgYXV0b2AgICDigJQgaW5pdC1wbGF0Zm9ybSBydW5zIG9uY2UgdGhlIHBsYXRmb3JtIGlzIHVwIChyZWdpc3RlciBhZG1pbiArIGxvYWQgcGx1Z2lucy9cbiAqICAgICAgICAgICAgICAgIGNvbXBsaWFuY2Uvc2FtcGxlcykuIE9uIGVjMiB0aGUgaW5zdGFuY2UgZG9lcyBpdCBpdHNlbGYgb24gZmlyc3QgYm9vdDsgb25cbiAqICAgICAgICAgICAgICAgIGxvY2FsL21pbmlrdWJlL2VrcyBgcHJvdmlzaW9uYCBydW5zIGl0IGZvciB5b3UuIFRoaXMgaXMgdGhlIERFRkFVTFQuXG4gKiAgIC0gYG1hbnVhbGAg4oCUIGRvbid0IHNlbGYtaW5pdDsgc3VyZmFjZSB0aGUgZXhhY3Qgc3RlcCBmb3IgeW91IHRvIHJ1biB5b3Vyc2VsZi5cbiAqICAgLSBgc2tpcGAgICDigJQgZG9uJ3QgaW5pdGlhbGl6ZSBhdCBhbGwgKG5vIHJlZ2lzdGVyLCBubyBsb2FkcykuXG4gKi9cbmV4cG9ydCB0eXBlIEluaXRNb2RlID0gJ2F1dG8nIHwgJ21hbnVhbCcgfCAnc2tpcCc7XG5leHBvcnQgY29uc3QgSU5JVF9NT0RFUzogcmVhZG9ubHkgSW5pdE1vZGVbXSA9IFsnYXV0bycsICdtYW51YWwnLCAnc2tpcCddO1xuXG4vKipcbiAqIFJlc29sdmUgdGhlIGluaXQgbW9kZSBmcm9tIGAtLWluaXQgPG1vZGU+YCwgZGVmYXVsdGluZyB0byBgYXV0b2Agd2hlbiB0aGUgZmxhZyBpcyBhYnNlbnQuXG4gKiBSZXR1cm5zIGBudWxsYCB3aGVuIGAtLWluaXRgIHdhcyBnaXZlbiBhbiBpbnZhbGlkIHZhbHVlIChjYWxsZXIgZXJyb3JzKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVJbml0TW9kZShvcHRpb25zOiB7IGluaXQ/OiB1bmtub3duIH0pOiBJbml0TW9kZSB8IG51bGwge1xuICBpZiAodHlwZW9mIG9wdGlvbnMuaW5pdCA9PT0gJ3N0cmluZycpIHsgLy8gLS1pbml0IDxtb2RlPlxuICAgIGNvbnN0IG0gPSBvcHRpb25zLmluaXQudG9Mb3dlckNhc2UoKSBhcyBJbml0TW9kZTtcbiAgICByZXR1cm4gSU5JVF9NT0RFUy5pbmNsdWRlcyhtKSA/IG0gOiBudWxsO1xuICB9XG4gIHJldHVybiAnYXV0byc7IC8vIGRlZmF1bHRcbn1cblxuLyoqXG4gKiBSZWFkIG9uZSBsaW5lIG9mIHRyaW1tZWQgaW5wdXQgZnJvbSB0aGUgdGVybWluYWwsIG93bmluZyB0aGUgcmVhZGxpbmVcbiAqIGxpZmVjeWNsZS4gVXNlZCBkaXJlY3RseSBmb3IgdGhlIGRlc3RydWN0aXZlIHRlYXJkb3duIGdhdGUgKGEgeS9OIGlzIHRvbyBlYXN5XG4gKiB0byBmYXQtZmluZ2VyLCBzbyB3ZSByZXF1aXJlIHRoZSBvcGVyYXRvciB0byBUWVBFIHRoZSB0YXJnZXQgaWQgYmFjayksIGFuZCBhc1xuICogdGhlIGJhc2lzIGZvciBgY29uZmlybWAuIERlbGliZXJhdGVseSBoYXMgbm8gYXV0by1hY2NlcHQuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGFzayhxdWVzdGlvbjogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgY29uc3QgcmwgPSByZWFkbGluZS5jcmVhdGVJbnRlcmZhY2UoeyBpbnB1dDogcHJvY2Vzcy5zdGRpbiwgb3V0cHV0OiBwcm9jZXNzLnN0ZG91dCB9KTtcbiAgdHJ5IHtcbiAgICByZXR1cm4gKGF3YWl0IHJsLnF1ZXN0aW9uKHF1ZXN0aW9uKSkudHJpbSgpO1xuICB9IGZpbmFsbHkge1xuICAgIHJsLmNsb3NlKCk7XG4gIH1cbn1cblxuLyoqIEludGVyYWN0aXZlIHkvTiBjb25maXJtYXRpb247IGF1dG8tdHJ1ZSB3aGVuIGBhdXRvWWVzYCAodGhlIGAtLXllc2AgZmxhZykuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY29uZmlybShxdWVzdGlvbjogc3RyaW5nLCBhdXRvWWVzOiBib29sZWFuKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGlmIChhdXRvWWVzKSByZXR1cm4gdHJ1ZTtcbiAgY29uc3QgYW5zd2VyID0gKGF3YWl0IGFzayhgJHtxdWVzdGlvbn0gW3kvTl0gYCkpLnRvTG93ZXJDYXNlKCk7XG4gIHJldHVybiBhbnN3ZXIgPT09ICd5JyB8fCBhbnN3ZXIgPT09ICd5ZXMnO1xufVxuXG4vKipcbiAqIEhvc3QtcG9ydCBwcmUtZmxpZ2h0IChsb2NhbC9taW5pa3ViZSkuIFBvcnRzIGFyZSBERVJJVkVEIGZyb20gdGhlIHRhcmdldCdzIGNsb25lZFxuICogZGVwbG95IHNvdXJjZSAoY29tcG9zZSAvIHNldHVwLnNoKSBzbyB0aGUgbGlzdCBjYW4ndCBkcmlmdCDigJQgaGVuY2UgdGhpcyBydW5zIEFGVEVSXG4gKiB0aGUgY2xvbmUuIEEgdGFrZW4gcG9ydCBtYWtlcyBhIGNvbnRhaW5lci9mb3J3YXJkIGZhaWwgdG8gYmluZCBtaWQtZGVwbG95IChmb3IgdGhlXG4gKiBnYXRld2F5LCBhIHNpbGVudCB1bnJlYWNoYWJsZSBoYW5nKS4gUHJpbnRzIGEg4pyTL+KclyBzdW1tYXJ5IGFuZCByZXR1cm5zIGZhbHNlIE9OTFlcbiAqIHdoZW4gdGhlIGNhbGxlciBtdXN0IEFCT1JUIChhIGZhdGFsIGxvY2FsIGNvbmZsaWN0KS4gbWluaWt1YmUgcG9ydHMgYXJlIG1hbmFnZWRcbiAqIGZvcndhcmRzIChzZXR1cC5zaCBwa2lsbHMvcmVzdGFydHMgdGhlbSksIHNvIGEgY29uZmxpY3QgdGhlcmUgd2FybnMgYnV0IHByb2NlZWRzLlxuICogUmVtb3RlIHRhcmdldHMgKGVjMi9la3MpIGJpbmQgbm90aGluZyBsb2NhbGx5IOKGkiByZXR1cm5zIHRydWUuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwcmVmbGlnaHRQb3J0cyhzcGVjOiBUYXJnZXRTcGVjLCB0YXJnZXQ6IFRhcmdldElkLCBjd2Q6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBjb25zdCBwb3J0cyA9IGRpc2NvdmVySG9zdFBvcnRzKHRhcmdldCwgY3dkLCBzcGVjKTtcbiAgaWYgKHBvcnRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHRydWU7XG4gIGNvbnN0IHBvcnRDaGVja3MgPSBhd2FpdCBjaGVja0hvc3RQb3J0cyhwb3J0cyk7XG4gIGNvbnN0IHRha2VuID0gcG9ydENoZWNrcy5maWx0ZXIoKGMpID0+ICFjLmF2YWlsYWJsZSk7XG4gIHByaW50U2VjdGlvbignUG9ydCBhdmFpbGFiaWxpdHknKTtcbiAgZm9yIChjb25zdCBjIG9mIHBvcnRDaGVja3MpIHByaW50SW5mbyhgJHtjLmF2YWlsYWJsZSA/ICfinJMnIDogJ+Kclyd9ICR7U3RyaW5nKGMucG9ydCkucGFkRW5kKDUpfSDigJQgJHtjLnNlcnZpY2V9YCk7XG4gIGlmICh0YWtlbi5sZW5ndGggPT09IDApIHJldHVybiB0cnVlO1xuICAvLyBsb2NhbCBQVUJMSVNIRVMgdGhlc2UgcG9ydHMgYXQgYGRvY2tlciBjb21wb3NlIHVwYCB0aW1lLCBzbyBhIGNvbmZsaWN0IGlzIGZhdGFsLlxuICAvLyBtaW5pa3ViZSdzIGFyZSBrdWJlY3RsIHBvcnQtZm9yd2FyZHMgc2V0dXAuc2ggcGtpbGxzICsgcmVzdGFydHMgKGFuZFxuICAvLyBlbnN1cmVNaW5pa3ViZUdhdGV3YXkgcmVjb3ZlcnMpLCBzbyBhIHN0YWxlIGZvcndhcmQgbXVzdCBOT1QgYmxvY2sgYSByZS1ydW4uXG4gIGNvbnN0IGZhdGFsID0gdGFyZ2V0ID09PSAnZG9ja2VyJztcbiAgLy8g4oCmVU5MRVNTIHRoZSBsb2NhbCBzdGFjayBpcyBhbHJlYWR5IHJ1bm5pbmc6IHRob3NlIHBvcnRzIGFyZSBoZWxkIGJ5IFlPVVIgT1dOXG4gIC8vIHN0YWNrLCBhbmQgYGRvY2tlciBjb21wb3NlIHVwYCBuby1vcHMgdGhlbSDigJQgdGhpcyBpcyBleGFjdGx5IGhvdyB5b3UgcmUtcnVuIHRvXG4gIC8vIGFkZCBsb2Fkcy9vcHRpb25zLiBEb24ndCBibG9jayAodGhlIHdvdWxkLWJlIGNvbmZsaWN0IGlzIGEgc2VsZi1jb25mbGljdCkuXG4gIGlmIChmYXRhbCAmJiBzdGFja1J1bm5pbmcodGFyZ2V0LCBjd2QsIHNwZWMpKSB7XG4gICAgcHJpbnRXYXJuaW5nKGBcXG4ke3Rha2VuLmxlbmd0aH0gcG9ydChzKSBhcmUgaGVsZCBieSB5b3VyIGFscmVhZHktcnVubmluZyAke3NwZWMubGFiZWx9IHN0YWNrIOKAlCByZS1ydW5uaW5nIGp1c3QgcmVzdW1lcyBpdCAobm8gcmVhbCBjb25mbGljdCksIHNvIGNvbnRpbnVpbmcuYCk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgY29uc3QgbGVhZCA9IGAke3Rha2VuLmxlbmd0aH0gcmVxdWlyZWQgcG9ydChzKSBhbHJlYWR5IGluIHVzZTogJHt0YWtlbi5tYXAoKGMpID0+IGMucG9ydCkuam9pbignLCAnKX1gO1xuICAoZmF0YWwgPyBwcmludEVycm9yIDogcHJpbnRXYXJuaW5nKShmYXRhbFxuICAgID8gYFxcbiR7bGVhZH0g4oCUIHRoZSBkZXBsb3kgY2FuJ3QgYmluZCB0aGVtIGFuZCB3b3VsZCBmYWlsIG1pZC13YXkuIEZyZWUgdGhlbSBhbmQgcmUtcnVuOmBcbiAgICA6IGBcXG4ke2xlYWR9IOKAlCBvbiBtaW5pa3ViZSB0aGVzZSBhcmUgdXN1YWxseSBhIHByZXZpb3VzIHJ1bidzIHBvcnQtZm9yd2FyZHMgKHNldHVwLnNoIHJlc3RhcnRzIHRoZW0pLiBGcmVlIGFueSBOT04tbWluaWt1YmUgaG9sZGVyIGlmIHRoZSBnYXRld2F5IHN0YXlzIHVucmVhY2hhYmxlOmApO1xuICBmb3IgKGNvbnN0IGMgb2YgdGFrZW4pIHByaW50SW5mbyhgICDigKIgcG9ydCAke2MucG9ydH0gKCR7Yy5zZXJ2aWNlfSkg4oCUIGZpbmQgdGhlIGhvbGRlcjogIGxzb2YgLWkgOiR7Yy5wb3J0fWApO1xuICBpZiAodGFrZW4uc29tZSgoYykgPT4gYy5wb3J0ID09PSA1MDAwKSkge1xuICAgIHByaW50SW5mbygnICBOb3RlOiBvbiBtYWNPUywgcG9ydCA1MDAwIGlzIHVzdWFsbHkgQWlyUGxheSBSZWNlaXZlciDigJQgU3lzdGVtIFNldHRpbmdzIOKGkiBHZW5lcmFsIOKGkiBBaXJEcm9wICYgSGFuZG9mZiDihpIgQWlyUGxheSBSZWNlaXZlciAob2ZmKS4nKTtcbiAgfVxuICByZXR1cm4gIWZhdGFsO1xufVxuXG4vKipcbiAqIFRlYXJkb3duIG1vZGUg4oCUIHRoZSBkZXN0cm95IGNvdW50ZXJwYXJ0IG9mIHByb3Zpc2lvbmluZywgZ2F0ZWQgSEFSREVSIHRoYW4gZGVwbG95OlxuICogQVdTIHRhcmdldHMgYXJlIGlycmV2ZXJzaWJsZSwgc28gdGhlIG9wZXJhdG9yIG11c3QgVFlQRSB0aGUgdGFyZ2V0IGlkICgtLWZvcmNlXG4gKiBieXBhc3NlcyBmb3IgQ0k7IC0teWVzIGFsb25lIGRvZXMgTk9UKS4gVGVybWluYWw6IG93bnMgaXRzIG91dHB1dCArIGV4aXRDb2RlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuVGVhcmRvd24oXG4gIHNwZWM6IFRhcmdldFNwZWMsXG4gIHRhcmdldDogVGFyZ2V0SWQsXG4gIGN3ZDogc3RyaW5nLFxuICBleGVjdXRpb25JZDogc3RyaW5nLFxuICBvcHRzOiB7IHN0YWNrTmFtZT86IHN0cmluZzsgY2x1c3Rlck5hbWU/OiBzdHJpbmc7IHJlZ2lvbj86IHN0cmluZzsgZG9tYWluPzogc3RyaW5nOyBob3N0ZWRab25lSWQ/OiBzdHJpbmc7IGZvcmNlPzogYm9vbGVhbjsgeWVzPzogYm9vbGVhbjsganNvbj86IGJvb2xlYW4gfSxcbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCB7IGNvbW1hbmQ6IGRvd25Db21tYW5kLCBkZXN0cnVjdGl2ZSB9ID0gdGVhcmRvd25Db21tYW5kKHRhcmdldCwge1xuICAgIHN0YWNrTmFtZTogb3B0cy5zdGFja05hbWUsXG4gICAgY2x1c3Rlck5hbWU6IG9wdHMuY2x1c3Rlck5hbWUsXG4gICAgcmVnaW9uOiBvcHRzLnJlZ2lvbixcbiAgICAvLyBla3MgdGVhcmRvd24gKGJpbi9zaHV0ZG93bi5zaCkgYWxzbyBjbGVhbnMgdXAgdGhlIEFDTSBjZXJ0ICsgUm91dGUgNTMgYWxpYXMgZm9yXG4gICAgLy8gdGhlIGRvbWFpbiwgc28gZm9yd2FyZCB0aGVtIHdoZW4gcHJlc2VudC5cbiAgICBkb21haW46IG9wdHMuZG9tYWluLFxuICAgIGhvc3RlZFpvbmVJZDogb3B0cy5ob3N0ZWRab25lSWQsXG4gICAgLy8gT3VyIHR5cGVkIGdhdGUgSVMgdGhlIGNvbmZpcm1hdGlvbiDigJQgYXNzdW1lWWVzIGZvcndhcmRzIGEgbmF0aXZlIGAtLXllc2AgdG8gYW55XG4gICAgLy8gc2NyaXB0LWJhc2VkIHRlYXJkb3duIChlYzIgZGVsZXRlLXN0YWNrIGhhcyBubyBwcm9tcHQ7IGVrcyBzaHV0ZG93bi5zaCBza2lwcyBpdHMgb3duKS5cbiAgICBhc3N1bWVZZXM6IHRydWUsXG4gIH0pO1xuICBpZiAob3B0cy5qc29uKSB7XG4gICAgY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkoeyBzdWNjZXNzOiB0cnVlLCBleGVjdXRpb25JZCwgdGFyZ2V0LCB0ZWFyZG93bjogdHJ1ZSwgZGVzdHJ1Y3RpdmUsIGRlc3Ryb3lzOiBzcGVjLmRlc3Ryb3lzLCBjb21tYW5kOiBkb3duQ29tbWFuZCB9LCBudWxsLCAyKSk7XG4gICAgcmV0dXJuO1xuICB9XG4gIHByaW50U2VjdGlvbihgVGVhcmRvd24gcGxhbiDigJQgJHtzcGVjLmxhYmVsfWApO1xuICBwcmludEtleVZhbHVlKHsgJ1RhcmdldCc6IHRhcmdldCwgJ0Rlc3Ryb3lzJzogc3BlYy5kZXN0cm95cywgJ1N0b3BzIGNvc3QnOiBzcGVjLmNvc3QgfSk7XG4gIHByaW50U2VjdGlvbignQ29tbWFuZCB0byBydW4nKTtcbiAgcHJpbnRJbmZvKGRvd25Db21tYW5kKTtcbiAgaWYgKGRlc3RydWN0aXZlICYmICFvcHRzLmZvcmNlKSB7XG4gICAgLy8gQmluZCB0aGUgY29uZmlybWF0aW9uIHRvIHRoZSByZXNvdXJjZSBhY3R1YWxseSBkZXN0cm95ZWQ6IGEgY3VzdG9tIG5hbWUgKGVjMlxuICAgIC8vIC0tc3RhY2stbmFtZSAvIGVrcyAtLWNsdXN0ZXItbmFtZSkgbXVzdCBiZSB0eXBlZCB2ZXJiYXRpbSBzbyBhIHdyb25nIG5hbWUgY2FuJ3QgYmVcbiAgICAvLyBjb25maXJtZWQgYnkgaGFiaXQ7IG90aGVyd2lzZSB0aGUgdGFyZ2V0IGlkLlxuICAgIGNvbnN0IHJlc291cmNlTmFtZSA9IHRhcmdldCA9PT0gJ2VrcycgPyBvcHRzLmNsdXN0ZXJOYW1lIDogb3B0cy5zdGFja05hbWU7XG4gICAgY29uc3QgY29uZmlybVRva2VuID0gcmVzb3VyY2VOYW1lID8/IHRhcmdldDtcbiAgICBjb25zdCBub3VuID0gdGFyZ2V0ID09PSAnZWtzJyA/IChvcHRzLmNsdXN0ZXJOYW1lID8gJ2NsdXN0ZXIgbmFtZScgOiAndGFyZ2V0IGlkJykgOiAob3B0cy5zdGFja05hbWUgPyAnc3RhY2sgbmFtZScgOiAndGFyZ2V0IGlkJyk7XG4gICAgY29uc3QgdG9rZW4gPSBhd2FpdCBhc2soYFxcblRoaXMgaXMgSVJSRVZFUlNJQkxFLiBUeXBlIFwiJHtjb25maXJtVG9rZW59XCIgdG8gY29uZmlybSB0ZWFyZG93bjogYCk7XG4gICAgaWYgKHRva2VuICE9PSBjb25maXJtVG9rZW4pIHtcbiAgICAgIHByaW50V2FybmluZyhgVGhhdCBkaWRuJ3QgbWF0Y2gsIHNvIG5vdGhpbmcgd2FzIGRlc3Ryb3llZCDigJQgeW91IGhhdmUgdG8gdHlwZSB0aGUgZXhhY3QgJHtub3VufSB0byBjb25maXJtLmApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgfSBlbHNlIGlmICghZGVzdHJ1Y3RpdmUgJiYgIW9wdHMuZm9yY2UgJiYgIShhd2FpdCBjb25maXJtKCdcXG5Qcm9jZWVkIHdpdGggdGVhcmRvd24gKHN0b3BzIHRoZSBzdGFjazsgb24tZGlzayBkYXRhIHBlcnNpc3RzKT8nLCBvcHRzLnllcyA/PyBmYWxzZSkpKSB7XG4gICAgcHJpbnRXYXJuaW5nKCdObyBwcm9ibGVtIOKAlCBub3RoaW5nIHdhcyBjaGFuZ2VkLicpO1xuICAgIHJldHVybjtcbiAgfVxuICBwcmludFNlY3Rpb24oJ1RlYXJpbmcgZG93bicpO1xuICBjb25zdCB7IGNvZGU6IGRvd25Db2RlIH0gPSBhd2FpdCBydW5TY3JpcHQoZG93bkNvbW1hbmQsIGN3ZCwgeyBjYXB0dXJlOiBmYWxzZSB9KTtcbiAgaWYgKGRvd25Db2RlICE9PSAwKSB7XG4gICAgcHJpbnRFcnJvcihgXFxuVGVhcmRvd24gZmFpbGVkIChleGl0ICR7ZG93bkNvZGV9KS4gSW5zcGVjdCB0aGUgc3RhY2svY29udGFpbmVycyBhbmQgcmV0cnkuYCk7XG4gICAgcHJvY2Vzcy5leGl0Q29kZSA9IDE7XG4gICAgcmV0dXJuO1xuICB9XG4gIHByaW50U3VjY2VzcygnVGVhcmRvd24gY29tcGxldGUuJyk7XG59XG5cbi8qKlxuICogUnVuIHRoZSBkZXBsb3kgY29tbWFuZCAocmVhbCwgc2VjcmV0cyB1bm1hc2tlZCwgc3RyZWFtZWQgKyBjYXB0dXJlZCkgd2l0aCBhXG4gKiBib3VuZGVkIGF1dG8tZml4ICsgcmV0cnkgbG9vcCDigJQgdGhlIGRlcGxveSBzY3JpcHRzIGFyZSBpZGVtcG90ZW50LCBzbyBhIGZpeGVkXG4gKiByZS1ydW4gcmVzdW1lcyByYXRoZXIgdGhhbiBzdGFydGluZyBvdmVyLiBSZXR1cm5zIHdoZXRoZXIgaXQgc3VjY2VlZGVkIHBsdXMgdGhlXG4gKiAocG9zc2libHkgZml4LWFkanVzdGVkKSBwYXJhbXMsIHdoaWNoIHRoZSBjYWxsZXIgbmVlZHMgZm9yIFNFUyBndWlkYW5jZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJ1bkRlcGxveVdpdGhSZXRyeShcbiAgc3BlYzogVGFyZ2V0U3BlYyxcbiAgdXJsOiBzdHJpbmcgfCBudWxsLFxuICBjd2Q6IHN0cmluZyxcbiAgcGFyYW1zOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgYWlPcHRzOiB7IHByb3ZpZGVyPzogc3RyaW5nOyBtb2RlbD86IHN0cmluZyB9LFxuICBvcHRzOiB7IHJldHJpZXM/OiBzdHJpbmc7IHllcz86IGJvb2xlYW4gfSxcbik6IFByb21pc2U8eyBzdWNjZWVkZWQ6IGJvb2xlYW47IHJ1blBhcmFtczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfT4ge1xuICAvLyBCb3VuZCByZXRyaWVzIHNvIGFuIHVuYXR0ZW5kZWQgYC0teWVzYCBydW4gY2FuJ3QgYXV0by1yZS1ydW4gYSAxNeKAkzMwIG1pblxuICAvLyBkZXBsb3kgYW4gdW5ib3VuZGVkIG51bWJlciBvZiB0aW1lcyBvbiBhIHBlcnNpc3RlbnRseS1yZXRyeWFibGUgc2lnbmF0dXJlLlxuICBjb25zdCBNQVhfUkVUUklFUyA9IDU7XG4gIGNvbnN0IHJlcXVlc3RlZFJldHJpZXMgPSBNYXRoLm1heCgwLCBwYXJzZUludChvcHRzLnJldHJpZXMgPz8gJycsIDEwKSB8fCAwKTtcbiAgY29uc3QgbWF4QXR0ZW1wdHMgPSAxICsgTWF0aC5taW4ocmVxdWVzdGVkUmV0cmllcywgTUFYX1JFVFJJRVMpO1xuICBsZXQgcnVuUGFyYW1zOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHBhcmFtcztcbiAgbGV0IHN1Y2NlZWRlZCA9IGZhbHNlO1xuICBmb3IgKGxldCBhdHRlbXB0ID0gMTsgYXR0ZW1wdCA8PSBtYXhBdHRlbXB0czsgYXR0ZW1wdCsrKSB7XG4gICAgY29uc3QgcmVhbENvbW1hbmQgPSBhc3NlbWJsZUNvbW1hbmQoc3BlYywgcnVuUGFyYW1zLCB7IG1hc2s6IGZhbHNlIH0pLmNvbW1hbmQ7XG4gICAgcHJpbnRTZWN0aW9uKGF0dGVtcHQgPT09IDEgPyAnRGVwbG95aW5nJyA6IGBEZXBsb3lpbmcg4oCUIHJldHJ5ICR7YXR0ZW1wdCAtIDF9YCk7XG4gICAgaWYgKGF0dGVtcHQgPT09IDEpIHtcbiAgICAgIHByaW50SW5mbyhgRGVwbG95aW5nICR7c3BlYy5sYWJlbH0g4oaSICR7dXJsfWApO1xuICAgICAgcHJpbnRJbmZvKHNwZWMuZGVwbG95cyk7XG4gICAgICBwcmludEluZm8oJ1N0cmVhbWluZyB0aGUgZGVwbG95IGJlbG93IOKAlCBmaXJzdCBydW4gaXMgdGhlIHNsb3cgb25lIChpbWFnZSBwdWxscyArIGNlcnQgZ2VuZXJhdGlvbikuJyk7XG4gICAgfVxuICAgIGNvbnN0IHsgY29kZSwgdGFpbCB9ID0gYXdhaXQgcnVuU2NyaXB0KHJlYWxDb21tYW5kLCBjd2QsIHsgY2FwdHVyZTogdHJ1ZSB9KTtcbiAgICBpZiAoY29kZSA9PT0gMCkgeyBzdWNjZWVkZWQgPSB0cnVlOyBicmVhazsgfVxuXG4gICAgcHJpbnRFcnJvcihgXFxuRGVwbG95IGZhaWxlZCAoZXhpdCAke2NvZGV9KS5gKTtcbiAgICBjb25zdCBpc3N1ZXMgPSBtYXRjaElzc3Vlcyh0YWlsKTtcbiAgICBpZiAoaXNzdWVzLmxlbmd0aCA+IDApIHtcbiAgICAgIHByaW50U2VjdGlvbignTGlrZWx5IGNhdXNlJyk7XG4gICAgICBmb3IgKGNvbnN0IGkgb2YgaXNzdWVzKSBwcmludEluZm8oYOKAoiAke2kuY2F1c2V9XFxuICDihpIgJHtpLnN1Z2dlc3Rpb259YCk7XG4gICAgfVxuICAgIGlmIChpc0FpQ29uZmlndXJlZChhaU9wdHMpKSB7XG4gICAgICBjb25zdCBkaWFnbm9zaXMgPSBhd2FpdCBkaWFnbm9zZUZhaWx1cmUocmVkYWN0U2VjcmV0cyh0YWlsLCBzcGVjLCBydW5QYXJhbXMpLCBhaU9wdHMpO1xuICAgICAgaWYgKGRpYWdub3NpcykgeyBwcmludFNlY3Rpb24oJ0RpYWdub3NpcycpOyBwcmludEluZm8oZGlhZ25vc2lzKTsgfVxuICAgIH1cbiAgICBpZiAoYXR0ZW1wdCA+PSBtYXhBdHRlbXB0cykgYnJlYWs7XG5cbiAgICAvLyBBdXRvLWZpeDogYSByZXRyeWFibGUgaXNzdWUgd2l0aCBhIHBhcmFtIHdlIGhhdmVuJ3QgYWxyZWFkeSBhcHBsaWVkLlxuICAgIGNvbnN0IGZpeCA9IGlzc3Vlcy5maW5kKChpKSA9PiBpLnJldHJ5YWJsZSAmJiBpLnBhcmFtRml4ICYmIHJ1blBhcmFtc1tpLnBhcmFtRml4LmtleV0gIT09IGkucGFyYW1GaXgudmFsdWUpO1xuICAgIGlmIChmaXg/LnBhcmFtRml4ICYmIGF3YWl0IGNvbmZpcm0oYFxcbkFwcGx5IGZpeCBhbmQgcmV0cnkg4oCUICR7Zml4LnN1Z2dlc3Rpb259YCwgb3B0cy55ZXMgPz8gZmFsc2UpKSB7XG4gICAgICBydW5QYXJhbXMgPSB7IC4uLnJ1blBhcmFtcywgW2ZpeC5wYXJhbUZpeC5rZXldOiBmaXgucGFyYW1GaXgudmFsdWUgfTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICAvLyBSZXRyeWFibGUgYnV0IG5vIHBhcmFtIGNoYW5nZSAoZS5nLiBBQ00gRE5TIHByb3BhZ2F0aW9uKSDigJQgb2ZmZXIgYSBwbGFpbiByZS1ydW4uXG4gICAgaWYgKCFmaXggJiYgaXNzdWVzLnNvbWUoKGkpID0+IGkucmV0cnlhYmxlKSAmJiBhd2FpdCBjb25maXJtKCdcXG5SZXRyeSB0aGUgZGVwbG95IChzYWZlIHRvIHJlLXJ1biDigJQgaXQgcmVzdW1lcyB3aGVyZSBpdCBsZWZ0IG9mZik/Jywgb3B0cy55ZXMgPz8gZmFsc2UpKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgYnJlYWs7XG4gIH1cbiAgcmV0dXJuIHsgc3VjY2VlZGVkLCBydW5QYXJhbXMgfTtcbn1cblxuLyoqXG4gKiBFeGVjdXRlIHRoZSBwb3N0LWluc3RhbGwgc3RlcHMgKHJlZ2lzdGVyIOKGkiBsb2FkcyDihpIgc21va2Ug4oaSIGV2ZW50cyDihpIgY3VzdG9tKS4gT25cbiAqIEVDMi9FS1MgdGhlIHJlZ2lzdGVyIHN0ZXAgKyB0aGUgZXZlbnRzIGJ1bmRsZSAoc3RvcmUtdG9rZW4g4oaSIHNldHVwLWV2ZW50cykgYXJlXG4gKiBTVVJGQUNFRCBhcyBvcmRlcmVkIG1hbnVhbCBuZXh0LXN0ZXBzIGluc3RlYWQgb2YgYXV0by1ydW46IGVjMiByZWdpc3RlciBtdXN0IHJ1blxuICogT04gdGhlIGJveCAodGhlIG1pbmlrdWJlIHVzZXIgb3ducyB0aGUgY2x1c3RlciksIGFuZCB0aGUgZXZlbnRzIGJ1bmRsZSBuZWVkcyBhXG4gKiByZWdpc3RlcmVkIHBsYXRmb3JtICsgQVdTIGNyZWRzLiAoZWtzIHJlZ2lzdGVyIGl0c2VsZiBwb3J0LWZvcndhcmRzLCBzbyBpdCBydW5zXG4gKiBmcm9tIGFueXdoZXJlIHdpdGgga3ViZWN0bCBhY2Nlc3MuKSBTZXRzIGV4aXRDb2RlIG9uIGEgc3RlcCBmYWlsdXJlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuUG9zdFN0ZXBzKFxuICBwb3N0U3RlcHM6IFBvc3RTdGVwW10sXG4gIHNraXBwZWRTdGVwczogU2tpcHBlZFN0ZXBbXSxcbiAgdGFyZ2V0OiBUYXJnZXRJZCxcbiAgY3dkOiBzdHJpbmcsXG4gIGFkbWluRW52OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+LFxuICBvcHRzOiB7IHllcz86IGJvb2xlYW47IGF1dG9SdW4/OiBib29sZWFuOyBhdXRvSW5pdD86IGJvb2xlYW4gfSxcbik6IFByb21pc2U8dm9pZD4ge1xuICAvLyBBV1MgdGFyZ2V0cyB3aXRoIGAtLWluaXQgYXV0b2A6IHRoZSBkZXBsb3kgc2VsZi1ydW5zIGluaXQtcGxhdGZvcm0sIHNvIHRoZXJlJ3Mgbm9cbiAgLy8gcmVnaXN0ZXIvbG9hZHMgc3RlcCB0byBzdXJmYWNlIGhlcmUg4oCUIGNvbmZpcm0gaXQgYW5kIHBvaW50IGF0IHdoZXJlIHRvIHdhdGNoLlxuICBpZiAob3B0cy5hdXRvSW5pdCAmJiB0YXJnZXQgPT09ICdlYzInKSB7XG4gICAgcHJpbnRJbmZvKCdcXG7inJMgSW5pdCBtb2RlOiBhdXRvIOKAlCB0aGUgaW5zdGFuY2UgcnVucyBpbml0LXBsYXRmb3JtIGl0c2VsZiBvbiBmaXJzdCBib290Jyk7XG4gICAgcHJpbnRJbmZvKCcgIChyZWdpc3RlciBhZG1pbiArIGJ1aWxkIGJvb3RzdHJhcCBpbWFnZSArIGxvYWQgcGx1Z2lucy9jb21wbGlhbmNlL3NhbXBsZXMpLicpO1xuICAgIHByaW50SW5mbygnICBJdCB0YWtlcyB+MzAtNjAgbWluOyB3YXRjaCBwcm9ncmVzczonKTtcbiAgICBwcmludEluZm8oJyAgICBhd3Mgc3NtIHN0YXJ0LXNlc3Npb24gLS10YXJnZXQgPEluc3RhbmNlSWQ+ICAgIyBJbnN0YW5jZUlkIHN0YWNrIG91dHB1dCcpO1xuICAgIHByaW50SW5mbygnICAgIHN1ZG8gdGFpbCAtZiAvdmFyL2xvZy91c2VyLWRhdGEubG9nJyk7XG4gIH0gZWxzZSBpZiAob3B0cy5hdXRvSW5pdCAmJiB0YXJnZXQgPT09ICdla3MnKSB7XG4gICAgcHJpbnRJbmZvKCdcXG7inJMgSW5pdCBtb2RlOiBhdXRvIOKAlCBzZXR1cC5zaCBydW5zIGluaXQtcGxhdGZvcm0gaW4gaXRzIGZpbmFsIHBoYXNlJyk7XG4gICAgcHJpbnRJbmZvKCcgIChyZWdpc3RlciBhZG1pbiArIGJ1aWxkIGJvb3RzdHJhcCBpbWFnZSArIGxvYWQgcGx1Z2lucy9jb21wbGlhbmNlL3NhbXBsZXMsJyk7XG4gICAgcHJpbnRJbmZvKCcgIG92ZXIgYSBrdWJlY3RsIHBvcnQtZm9yd2FyZCkuIFBhc3MgLS1pbml0IG1hbnVhbCB0byBydW4gaXQgeW91cnNlbGYgaW5zdGVhZC4nKTtcbiAgfVxuICBpZiAocG9zdFN0ZXBzLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuICBmb3IgKGNvbnN0IHMgb2Ygc2tpcHBlZFN0ZXBzKSBwcmludFdhcm5pbmcoYFNraXBwZWQgcG9zdC1zdGVwICR7cy5pZH06ICR7cy5yZWFzb259YCk7XG4gIGNvbnN0IGlzUmVtb3RlID0gKGlkOiBzdHJpbmcpOiBib29sZWFuID0+XG4gICAgKHRhcmdldCA9PT0gJ2VjMicgfHwgdGFyZ2V0ID09PSAnZWtzJykgJiYgKGlkID09PSAncmVnaXN0ZXInIHx8IGlkLnN0YXJ0c1dpdGgoJ3N0b3JlLXRva2VuJykgfHwgaWQgPT09ICdldmVudHMnKTtcbiAgY29uc3QgcnVubmFibGUgPSBwb3N0U3RlcHMuZmlsdGVyKChzKSA9PiAhaXNSZW1vdGUocy5pZCkpO1xuICBjb25zdCByZW1vdGUgPSBwb3N0U3RlcHMuZmlsdGVyKChzKSA9PiBpc1JlbW90ZShzLmlkKSk7XG4gIGlmIChyZW1vdGUubGVuZ3RoID4gMCkge1xuICAgIGlmICh0YXJnZXQgPT09ICdlYzInKSB7XG4gICAgICAvLyBFQzIgcnVucyB0aGUgcGxhdGZvcm0gYXMgYSBkZWRpY2F0ZWQgYG1pbmlrdWJlYCB1c2VyIGluc2lkZSB0aGUgaW5zdGFuY2U6IHRoZVxuICAgICAgLy8gY2x1c3RlciwgaXRzIGt1YmVjb25maWcsIGFuZCB0aGUgand0LXNlY3JldCBhbGwgYmVsb25nIHRvIHRoYXQgdXNlciwgYW5kIHRoZVxuICAgICAgLy8gcmVnaXN0ZXIgc3RlcCBidWlsZHMrcHVzaGVzIGltYWdlcyBhZ2FpbnN0IGl0LiBTbyBpdCBNVVNUIHJ1biBvbiB0aGUgYm94IGFzXG4gICAgICAvLyBgbWluaWt1YmVgIOKAlCBwcmludCB0aGUgZXhhY3QgbGFuZGluZyBzZXF1ZW5jZSByYXRoZXIgdGhhbiBhIGJhcmUgY29tbWFuZC5cbiAgICAgIHByaW50SW5mbygnXFxuTmV4dCDigJQgZmluaXNoIHNldHVwIE9OIHRoZSBpbnN0YW5jZSAoaXQgYnVpbGRzIGltYWdlcyArIHJlYWRzIHRoZSBjbHVzdGVyLCBzbyBpdCcpO1xuICAgICAgcHJpbnRJbmZvKCdjYW5ub3QgcnVuIGZyb20gaGVyZSkuIExhbmQgb24gdGhlIGJveCwgYmVjb21lIHRoZSBgbWluaWt1YmVgIHVzZXIsIHRoZW4gcnVuIGl0OicpO1xuICAgICAgcHJpbnRJbmZvKCcgIGF3cyBzc20gc3RhcnQtc2Vzc2lvbiAtLXRhcmdldCA8SW5zdGFuY2VJZD4gICAgICAjIEluc3RhbmNlSWQgc3RhY2sgb3V0cHV0Jyk7XG4gICAgICBwcmludEluZm8oJyAgc3VkbyAtaXUgbWluaWt1YmUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgb3ducyB0aGUgY2x1c3RlciArIGRvY2tlcicpO1xuICAgICAgcHJpbnRJbmZvKCcgIGNkIC9vcHQvcGlwZWxpbmUvcGlwZWxpbmUtYnVpbGRlciAgICAgICAgICAgICAgICAjIHRoZSBkZXBsb3llZCBjaGVja291dCcpO1xuICAgICAgZm9yIChjb25zdCBzIG9mIHJlbW90ZSkgcHJpbnRJbmZvKGAgICR7cy5jb21tYW5kfWApO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBla3M6IGluaXQtcGxhdGZvcm0gcG9ydC1mb3J3YXJkcyB0byBzdmMvbmdpbngsIHNvIHJlZ2lzdGVyIHJ1bnMgZnJvbSBhbnl3aGVyZSB3aXRoXG4gICAgICAvLyBrdWJlY3RsIGFjY2VzcyDigJQgbm8gaW4tVlBDIHJlcXVpcmVtZW50IGFuZCBubyB3YWl0aW5nIG9uIHRoZSBBTEIvRE5TLiAoQSAtLXdpdGgtZXZlbnRzXG4gICAgICAvLyBidW5kbGUsIGlmIHByZXNlbnQsIGFkZGl0aW9uYWxseSBuZWVkcyBBV1MgY3JlZHMgKyBhIHJlZ2lzdGVyZWQgcGxhdGZvcm0uKVxuICAgICAgcHJpbnRJbmZvKCdcXG5OZXh0IOKAlCBydW4gd2l0aCBrdWJlY3RsIGFjY2VzcyB0byB0aGUgY2x1c3RlciAoaW4gdGhpcyBvcmRlcik6Jyk7XG4gICAgICBmb3IgKGNvbnN0IHMgb2YgcmVtb3RlKSBwcmludEluZm8oYCAg4oCiICR7cy5sYWJlbH0g4oCUICR7cy5jb21tYW5kfWApO1xuICAgIH1cbiAgfVxuICBpZiAocnVubmFibGUubGVuZ3RoID09PSAwKSByZXR1cm47XG4gIC8vIFdoZW4gdGhlIGxvYWRzIHdlcmUgcGlja2VkIGludGVyYWN0aXZlbHkgKGF1dG9SdW4pLCB0aGUgdXNlciBhbHJlYWR5IG9wdGVkIGluIOKAlCBza2lwXG4gIC8vIHRoZSByZWR1bmRhbnQgc2Vjb25kIGNvbmZpcm0uIEZsYWctZHJpdmVuIC8gbm9uLWludGVyYWN0aXZlIHJ1bnMgc3RpbGwgZ2F0ZSBoZXJlLlxuICBpZiAob3B0cy5hdXRvUnVuIHx8IGF3YWl0IGNvbmZpcm0oYFxcblJ1biAke3J1bm5hYmxlLmxlbmd0aH0gcG9zdC1pbnN0YWxsIHN0ZXAocykgbm93P2AsIG9wdHMueWVzID8/IGZhbHNlKSkge1xuICAgIGlmIChvcHRzLmF1dG9SdW4pIHByaW50SW5mbyhgXFxuUnVubmluZyB0aGUgJHtydW5uYWJsZS5sZW5ndGh9IHBvc3QtaW5zdGFsbCBzdGVwKHMpIHlvdSBzZWxlY3RlZOKApmApO1xuICAgIGZvciAoY29uc3QgcyBvZiBydW5uYWJsZSkge1xuICAgICAgcHJpbnRTZWN0aW9uKGBQb3N0LXN0ZXA6ICR7cy5sYWJlbH1gKTtcbiAgICAgIC8vIHJlZ2lzdGVyIChsb2NhbC9taW5pa3ViZSkgbG9ncyBpbnRvIHRoZSBwbGF0Zm9ybSwgc28gaXQgbmVlZHMgdGhlIGFkbWluIGNyZWRzXG4gICAgICAvLyAoUExBVEZPUk1fSURFTlRJRklFUiAvIFBMQVRGT1JNX1BBU1NXT1JEKSBvbiB0b3Agb2YgaXRzIHN0ZXAgZW52LlxuICAgICAgY29uc3QgbmVlZHNDcmVkcyA9IHMuaWQgPT09ICdyZWdpc3RlcicgfHwgcy5pZC5zdGFydHNXaXRoKCdzdG9yZS10b2tlbicpO1xuICAgICAgY29uc3QgZW52ID0gbmVlZHNDcmVkcyA/IHsgLi4ucy5lbnYsIC4uLmFkbWluRW52IH0gOiBzLmVudjtcbiAgICAgIC8vIExvYWRzL3Ntb2tlIGFyZSBub2lzeSArIG5vbi1pbnRlcmFjdGl2ZSDihpIgcnVuIFFVSUVUIChjYXB0dXJlLCBzaG93IG9ubHkgb25cbiAgICAgIC8vIGZhaWx1cmUpLiBFeGNlcHRpb246IGEgcmVnaXN0ZXIgd2l0aCBubyBhZG1pbiBjcmVkcyBwcm9tcHRzLCBzbyBpdCBtdXN0IHN0cmVhbS5cbiAgICAgIGNvbnN0IGludGVyYWN0aXZlUmVnaXN0ZXIgPSBzLmlkID09PSAncmVnaXN0ZXInICYmICFhZG1pbkVudi5QTEFURk9STV9JREVOVElGSUVSO1xuICAgICAgY29uc3QgcXVpZXQgPSAhaW50ZXJhY3RpdmVSZWdpc3RlcjtcbiAgICAgIGlmIChxdWlldCkgcHJpbnRJbmZvKGAke3MuY29tbWFuZH1cXG4gIOKApnJ1bm5pbmcgKG91dHB1dCBzaG93biBvbmx5IGlmIGl0IGZhaWxzKWApO1xuICAgICAgZWxzZSBwcmludEluZm8ocy5jb21tYW5kKTtcbiAgICAgIGNvbnN0IHsgY29kZSwgdGFpbCB9ID0gYXdhaXQgcnVuU2NyaXB0KHMuY29tbWFuZCwgY3dkLCB7IHF1aWV0LCBjYXB0dXJlOiBmYWxzZSwgZW52IH0pO1xuICAgICAgaWYgKGNvZGUgIT09IDApIHtcbiAgICAgICAgaWYgKHF1aWV0ICYmIHRhaWwpIHsgcHJpbnRFcnJvcignXFxuLS0tIGxhc3Qgb3V0cHV0IC0tLScpOyBwcmludEluZm8odGFpbCk7IH1cbiAgICAgICAgcHJpbnRFcnJvcihgXFxuUG9zdC1zdGVwICcke3MuaWR9JyBmYWlsZWQgKGV4aXQgJHtjb2RlfSkuIFRoZSBwbGF0Zm9ybSBpcyBkZXBsb3llZDsgZml4IGFuZCByZS1ydW4gdGhlIHN0ZXAgbWFudWFsbHkuYCk7XG4gICAgICAgIHByb2Nlc3MuZXhpdENvZGUgPSAxO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIHByaW50U3VjY2VzcyhgJHtzLmlkfSDinJNgKTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgcHJpbnRJbmZvKCdcXG5Ta2lwcGVkIHBvc3QtaW5zdGFsbCBzdGVwcy4gUnVuIHRoZSBjb21tYW5kcyBhYm92ZSBtYW51YWxseSB3aGVuIHJlYWR5LicpO1xuICB9XG59XG5cbi8qKlxuICogU3BhcnNlLWNsb25lIHRoZSBwbGF0Zm9ybSByZXBvICh3aGVuIC0tcmVwbywgb3IgYWNjZXB0ZWQgdmlhIHRoZSBpbnRlcmFjdGl2ZVxuICogb2ZmZXIpLCByZXBvaW50IGN3ZCBpbnRvIGl0LCBhbmQgdmVyaWZ5IHRoZSBkZXBsb3kgZW50cnlwb2ludCBleGlzdHMuIE93bnMgdGhlXG4gKiBjd2QvYm9vdHN0cmFwcGVkIHN0YXRlLiBTZXRzIGV4aXRDb2RlIG9uIGEgaGFyZCBmYWlsdXJlIChjbG9uZSBlcnJvciAvIG1pc3NpbmdcbiAqIGVudHJ5cG9pbnQpOyBhIHBsYWluIGRlY2xpbmUgbGVhdmVzIGV4aXRDb2RlXG4gKiB1bnRvdWNoZWQuIFJldHVybnMgb2s6ZmFsc2Ugd2hlbiB0aGUgY2FsbGVyIG11c3QgYWJvcnQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBib290c3RyYXBBbmRMb2NhdGUoXG4gIHNwZWM6IFRhcmdldFNwZWMsXG4gIGJvb3RzdHJhcDogQm9vdHN0cmFwU3BlYyxcbiAgYm9vdHN0cmFwQ21kOiBzdHJpbmcgfCBudWxsLFxuICBzcGFyc2VQYXRoczogcmVhZG9ubHkgc3RyaW5nW10sXG4gIHN0YXJ0Q3dkOiBzdHJpbmcsXG4gIG9wdHM6IHsgeWVzPzogYm9vbGVhbiB9LFxuKTogUHJvbWlzZTx7IGN3ZDogc3RyaW5nOyBib290c3RyYXBwZWQ6IGJvb2xlYW47IG9rOiBib29sZWFuIH0+IHtcbiAgbGV0IGN3ZCA9IHN0YXJ0Q3dkO1xuICBsZXQgYm9vdHN0cmFwcGVkID0gZmFsc2U7XG4gIC8vIFNoYXJlZCBieSBgLS1yZXBvYCBhbmQgdGhlIGludGVyYWN0aXZlIG9mZmVyLiBSZXBvaW50cyBjd2QgKyBzZXRzIGJvb3RzdHJhcHBlZDtcbiAgLy8gYGJvb3RzdHJhcHBlZGAgcmVjb3JkcyB3aGV0aGVyIHdlIGNyZWF0ZWQgdGhlIGNsb25lICh2cy4gYW4gZXhpc3RpbmcgY2hlY2tvdXQpIOKAlFxuICAvLyBvbmx5IHRoZW4gY2FuIHRoZSBjYWxsZXIgYWRkaXRpdmVseSBzcGFyc2UtZmV0Y2ggbG9hZCBmb2xkZXJzLlxuICBjb25zdCBib290c3RyYXBDbG9uZSA9IGFzeW5jICgpOiBQcm9taXNlPGJvb2xlYW4+ID0+IHtcbiAgICBjb25zdCBjbWQgPSBib290c3RyYXBDb21tYW5kKGJvb3RzdHJhcCk7XG4gICAgcHJpbnRTZWN0aW9uKCdCb290c3RyYXAnKTtcbiAgICBwcmludEluZm8oY21kKTtcbiAgICBjb25zdCB7IGNvZGUgfSA9IGF3YWl0IHJ1blNjcmlwdChjbWQsIGN3ZCwgeyBjYXB0dXJlOiBmYWxzZSB9KTtcbiAgICBpZiAoY29kZSAhPT0gMCkge1xuICAgICAgcHJpbnRFcnJvcihgXFxuVGhlIGNsb25lIGRpZG4ndCBmaW5pc2ggKGV4aXQgJHtjb2RlfSkuIERvdWJsZS1jaGVjayB0aGUgcmVwbyBVUkwgLyByZWYgKG9yIHlvdXIgbmV0d29yaykgYW5kIGdpdmUgaXQgYW5vdGhlciBnby5gKTtcbiAgICAgIHByb2Nlc3MuZXhpdENvZGUgPSAxO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBjd2QgPSBwYXRoLnJlc29sdmUoY3dkLCBib290c3RyYXAud29ya2Rpcik7XG4gICAgYm9vdHN0cmFwcGVkID0gdHJ1ZTtcbiAgICBwcmludFN1Y2Nlc3MoYFJlcG8gaXMgcmVhZHkg4oCUIGNvbnRpbnVpbmcgZnJvbSAke2N3ZH1gKTtcbiAgICBjb25zdCBhYnNlbnQgPSBzcGFyc2VQYXRocy5maWx0ZXIoKHApID0+ICFleGlzdHNTeW5jKHBhdGguam9pbihjd2QsIHApKSk7XG4gICAgaWYgKGFic2VudC5sZW5ndGggPiAwKSB7XG4gICAgICBwcmludEVycm9yKGBcXG5UaGUgc3BhcnNlIGNsb25lIGlzIG1pc3NpbmcgJHthYnNlbnQuam9pbignLCAnKX0g4oCUIHRoYXQgcmVmIG1heSBub3QgaGF2ZSB0aG9zZSBmb2xkZXJzLiBUcnkgYSBkaWZmZXJlbnQgLS1yZWYuYCk7XG4gICAgICBwcm9jZXNzLmV4aXRDb2RlID0gMTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH07XG5cbiAgLy8gYC0tcmVwb2A6IGNsb25lIHVwIGZyb250IChtdXN0IHByZWNlZGUgdGhlIGVudHJ5cG9pbnQgY2hlY2spLlxuICBpZiAoYm9vdHN0cmFwQ21kKSB7XG4gICAgcHJpbnRJbmZvKGBcXG5Cb290c3RyYXAg4oaSIGNsb25lICR7Ym9vdHN0cmFwLnJlcG99IEAgJHtib290c3RyYXAucmVmfSBpbnRvICR7Ym9vdHN0cmFwLndvcmtkaXJ9IChzcGFyc2UpLmApO1xuICAgIGlmICghKGF3YWl0IGNvbmZpcm0oJ0dvIGFoZWFkIHdpdGggdGhlIGNsb25lPycsIG9wdHMueWVzID8/IGZhbHNlKSkpIHtcbiAgICAgIHByaW50V2FybmluZygnTm8gcHJvYmxlbSDigJQgbm90aGluZyB3YXMgY2hhbmdlZC4gUmUtcnVuIHdoZW5ldmVyIHlvdVxcJ3JlIHJlYWR5LicpO1xuICAgICAgcmV0dXJuIHsgY3dkLCBib290c3RyYXBwZWQsIG9rOiBmYWxzZSB9O1xuICAgIH1cbiAgICBpZiAoIShhd2FpdCBib290c3RyYXBDbG9uZSgpKSkgcmV0dXJuIHsgY3dkLCBib290c3RyYXBwZWQsIG9rOiBmYWxzZSB9O1xuICB9XG5cbiAgLy8gVGhlIGRlcGxveSBlbnRyeXBvaW50IG11c3QgZXhpc3QgcmVsYXRpdmUgdG8gY3dkLiBJZiBpdCBkb2Vzbid0IGFuZCB3ZSBoYXZlbid0XG4gIC8vIGJvb3RzdHJhcHBlZCwgZ3JhY2VmdWxseSBPRkZFUiB0byBjbG9uZSAoaW50ZXJhY3RpdmUgb25seSkgc28gYSBmcmVzaCBtYWNoaW5lIGNhblxuICAvLyBwcm9jZWVkIHdpdGhvdXQgcmUtcnVubmluZyB3aXRoIC0tcmVwby5cbiAgaWYgKCFlbnRyeXBvaW50RXhpc3RzKHNwZWMsIGN3ZCkpIHtcbiAgICBjb25zdCBpbnRlcmFjdGl2ZSA9IEJvb2xlYW4ocHJvY2Vzcy5zdGRpbi5pc1RUWSkgJiYgIW9wdHMueWVzO1xuICAgIGlmICghYm9vdHN0cmFwQ21kICYmIGludGVyYWN0aXZlICYmIGdpdEF2YWlsYWJsZSgpKSB7XG4gICAgICBwcmludEluZm8oYFxcbkxvb2tzIGxpa2UgeW91J3JlIG5vdCBpbnNpZGUgYSBwaXBlbGluZS1idWlsZGVyIGNoZWNrb3V0LCBzbyB0aGUgJHtzcGVjLmxhYmVsfSBkZXBsb3kgc2NyaXB0cyBhcmVuJ3QgaGVyZSB5ZXQuYCk7XG4gICAgICBpZiAoYXdhaXQgY29uZmlybShgV2FudCBtZSB0byBzcGFyc2UtY2xvbmUgdGhlbSBpbnRvICR7Ym9vdHN0cmFwLndvcmtkaXJ9IGFuZCBrZWVwIGdvaW5nP2AsIGZhbHNlKSkge1xuICAgICAgICBpZiAoIShhd2FpdCBib290c3RyYXBDbG9uZSgpKSkgcmV0dXJuIHsgY3dkLCBib290c3RyYXBwZWQsIG9rOiBmYWxzZSB9O1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoIWVudHJ5cG9pbnRFeGlzdHMoc3BlYywgY3dkKSkge1xuICAgICAgcHJpbnRXYXJuaW5nKGBcXG5JIGNvdWxkbid0IGZpbmQgJHtzcGVjLmRpcn0vJHtzcGVjLmVudHJ5cG9pbnR9IGZyb20gJHtjd2R9LmApO1xuICAgICAgcHJpbnRJbmZvKCdUd28gZWFzeSB3YXlzIGZvcndhcmQ6Jyk7XG4gICAgICBwcmludEluZm8oJyAg4oCiIGNkIGludG8geW91ciBwaXBlbGluZS1idWlsZGVyIGNoZWNrb3V0IGFuZCByZS1ydW4sIG9yJyk7XG4gICAgICBwcmludEluZm8oYCAg4oCiIGFkZCAtLXJlcG8gYW5kIEknbGwgYm9vdHN0cmFwIGEgZnJlc2ggc3BhcnNlIGNsb25lIGZvciB5b3Uke2dpdEF2YWlsYWJsZSgpID8gJy4nIDogJyAob25jZSBnaXQgaXMgaW5zdGFsbGVkKS4nfWApO1xuICAgICAgcHJvY2Vzcy5leGl0Q29kZSA9IDE7XG4gICAgICByZXR1cm4geyBjd2QsIGJvb3RzdHJhcHBlZCwgb2s6IGZhbHNlIH07XG4gICAgfVxuICB9XG4gIHJldHVybiB7IGN3ZCwgYm9vdHN0cmFwcGVkLCBvazogdHJ1ZSB9O1xufVxuXG4vKipcbiAqIEludGVyYWN0aXZlIG9wdC1pbiBsb2Fkcywgb2ZmZXJlZCBBRlRFUiB0aGUgY2xvbmUgKHNvIHdlIG9ubHkgYXNrIG9uY2UgdGhlIG9wZXJhdG9yXG4gKiBoYXMgYWdyZWVkIHRvIHByb2NlZWQpLiBQcm9tcHRzIHBlciBsb2FkLCBhZGRpdGl2ZWx5IHNwYXJzZS1mZXRjaGVzIHRoZSBwaWNrZWRcbiAqIGZvbGRlcnMgaW50byBhIGJvb3RzdHJhcHBlZCBzcGFyc2UgY2xvbmUsIHRoZW4gcmUtcmVzb2x2ZXMgdGhlIHBvc3QtaW5zdGFsbCBzdGVwc1xuICogd2l0aCB0aGUgc2VsZWN0aW9ucy4gUmV0dXJucyB0aGUgY2hvc2VuIGlkcyArIHRoZSByZWNvbXB1dGVkIHN0ZXBzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZUxvYWRzSW50ZXJhY3RpdmVseShcbiAgdGFyZ2V0OiBUYXJnZXRJZCxcbiAgdXJsOiBzdHJpbmcgfCBudWxsLFxuICByZWdpb246IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgY3dkOiBzdHJpbmcsXG4gIGJvb3RzdHJhcHBlZDogYm9vbGVhbixcbiAgYm9vdHN0cmFwOiBCb290c3RyYXBTcGVjLFxuICBwb3N0U3RlcEZsYWdzOiB7IGluaXQ6IGJvb2xlYW47IGF1dG9Jbml0OiBib29sZWFuOyBidWlsZEJvb3RzdHJhcDogYm9vbGVhbjsgc21va2VUZXN0OiBib29sZWFuOyBldmVudHM6IGJvb2xlYW47IHN0ZXBzOiBzdHJpbmdbXSB9LFxuKTogUHJvbWlzZTx7IGVuYWJsZWRMb2FkSWRzOiBzdHJpbmdbXTsgc3RlcHM6IFBvc3RTdGVwW107IHNraXBwZWQ6IFNraXBwZWRTdGVwW10gfT4ge1xuICBjb25zdCBwcm9tcHRzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgIHBsdWdpbnM6ICdMb2FkIHBsdWdpbnM/JyxcbiAgICBzYW1wbGVzOiAnTG9hZCBzYW1wbGUgcGlwZWxpbmUgdGVtcGxhdGVzPycsXG4gICAgY29tcGxpYW5jZTogJ0xvYWQgY29tcGxpYW5jZSBydWxlcz8nLFxuICB9O1xuICBwcmludFNlY3Rpb24oJ09wdGlvbmFsIHBvc3QtaW5zdGFsbCBsb2FkcycpO1xuICBjb25zdCBjaG9zZW46IHN0cmluZ1tdID0gW107XG4gIGZvciAoY29uc3QgcyBvZiBMT0FEX1NURVBTKSB7XG4gICAgaWYgKGF3YWl0IGNvbmZpcm0ocHJvbXB0c1tzLmlkXSA/PyBgTG9hZCAke3MuaWR9P2AsIGZhbHNlKSkgY2hvc2VuLnB1c2gocy5pZCk7XG4gIH1cbiAgLy8gQWRkaXRpdmUgc3BhcnNlIHJlLXN5bmM6IG1hdGVyaWFsaXplIE9OTFkgdGhlIHBpY2tlZCBsb2FkcycgZm9sZGVycyAodGhlIHBhcnRpYWxcbiAgLy8gY2xvbmUgZmV0Y2hlcyB0aGVpciBibG9icyBvbiBkZW1hbmQpLiBPbmx5IHdoZW4gd2UgY3JlYXRlZCBhIFNQQVJTRSBjbG9uZSDigJQgYVxuICAvLyBub3JtYWwgY2hlY2tvdXQgYWxyZWFkeSBoYXMgZXZlcnkgZm9sZGVyLCBhbmQgdGhlIGdpdDwyLjI3IGZ1bGwtY2xvbmUgZmFsbGJhY2tcbiAgLy8gKGJvb3RzdHJhcC5mdWxsKSBpcyBub24tc3BhcnNlLCB3aGVyZSBgc3BhcnNlLWNoZWNrb3V0IGFkZGAgd291bGQgc3dpdGNoIGl0IHRvXG4gIC8vIGNvbmUgbW9kZSBhbmQgUFJVTkUgdGhlIGFscmVhZHktbWF0ZXJpYWxpemVkIGRlcGxveSBmb2xkZXJzLlxuICBpZiAoYm9vdHN0cmFwcGVkICYmICFib290c3RyYXAuZnVsbCkge1xuICAgIGNvbnN0IGFic2VudCA9IHNwYXJzZVBhdGhzRm9yKHRhcmdldCwgY2hvc2VuKS5maWx0ZXIoKHApID0+ICFleGlzdHNTeW5jKHBhdGguam9pbihjd2QsIHApKSk7XG4gICAgaWYgKGFic2VudC5sZW5ndGggPiAwKSB7XG4gICAgICBwcmludFNlY3Rpb24oJ0ZldGNoaW5nIHNlbGVjdGVkIGxvYWQgZm9sZGVycycpO1xuICAgICAgY29uc3QgYWRkQ21kID0gYGdpdCBzcGFyc2UtY2hlY2tvdXQgYWRkICR7YWJzZW50Lm1hcCgocCkgPT4gYCcke3B9J2ApLmpvaW4oJyAnKX0gJiYgZ2l0IGNoZWNrb3V0ICR7c2hlbGxRdW90ZShib290c3RyYXAucmVmKX1gO1xuICAgICAgcHJpbnRJbmZvKGFkZENtZCk7XG4gICAgICBjb25zdCB7IGNvZGUgfSA9IGF3YWl0IHJ1blNjcmlwdChhZGRDbWQsIGN3ZCwgeyBjYXB0dXJlOiBmYWxzZSB9KTtcbiAgICAgIGlmIChjb2RlICE9PSAwKSB7XG4gICAgICAgIHByaW50V2FybmluZyhgQ291bGRuJ3QgZmV0Y2ggJHthYnNlbnQuam9pbignLCAnKX0g4oCUIHRoZSBtYXRjaGluZyBsb2FkIHN0ZXAocykgbWF5IGZhaWwuIFJlLXJ1biB3aXRoIC0tcmVwbyB0byByZWZyZXNoIHRoZSBjbG9uZS5gKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgY29uc3QgcmVzb2x2ZWQgPSByZXNvbHZlUG9zdFN0ZXBzKHtcbiAgICB0YXJnZXQsXG4gICAgdXJsLFxuICAgIHJlZ2lvbixcbiAgICBlbmFibGVkTG9hZElkczogY2hvc2VuLFxuICAgIC4uLnBvc3RTdGVwRmxhZ3MsXG4gICAgYnVpbGRCb290c3RyYXA6IHBvc3RTdGVwRmxhZ3MuYnVpbGRCb290c3RyYXAgfHwgY2hvc2VuLmluY2x1ZGVzKCdwbHVnaW5zJyksXG4gIH0pO1xuICByZXR1cm4geyBlbmFibGVkTG9hZElkczogY2hvc2VuLCBzdGVwczogcmVzb2x2ZWQuc3RlcHMsIHNraXBwZWQ6IHJlc29sdmVkLnNraXBwZWQgfTtcbn1cblxuLyoqXG4gKiBSZWRhY3Qgc2VjcmV0IHBhcmFtIHZhbHVlcyAoZS5nLiB0aGUgZ2hjciB0b2tlbikgZnJvbSBjYXB0dXJlZCBkZXBsb3kgb3V0cHV0XG4gKiBiZWZvcmUgaXQgaXMgc2VudCB0byB0aGUgTExNIGZvciBkaWFnbm9zaXMuIFRoZSBkZXBsb3kgcnVucyB3aXRoIHNlY3JldHNcbiAqIHVubWFza2VkLCBzbyBhbHRob3VnaCB0aGUgY3VycmVudCBzY3JpcHRzIGRvbid0IGVjaG8gdGhlbSwgdGhpcyBrZWVwcyBhIGZ1dHVyZVxuICogc2NyaXB0J3Mgc3RyYXkgZWNobyAob3IgYSB2ZXJib3NlIHN1Yi10b29sKSBmcm9tIGNyb3NzaW5nIHRoZSB0aGlyZC1wYXJ0eS1MTE1cbiAqIGJvdW5kYXJ5LlxuICovXG5mdW5jdGlvbiByZWRhY3RTZWNyZXRzKHRleHQ6IHN0cmluZywgc3BlYzogVGFyZ2V0U3BlYywgcGFyYW1zOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IHN0cmluZyB7XG4gIGxldCBvdXQgPSB0ZXh0O1xuICBmb3IgKGNvbnN0IGlucHV0IG9mIFsuLi5zcGVjLnJlcXVpcmVkLCAuLi5zcGVjLm9wdGlvbmFsXSkge1xuICAgIGlmICghaW5wdXQuc2VjcmV0KSBjb250aW51ZTtcbiAgICBjb25zdCB2YWx1ZSA9IHBhcmFtc1tpbnB1dC5rZXldO1xuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICYmIHZhbHVlLmxlbmd0aCA+PSA0KSBvdXQgPSBvdXQuc3BsaXQodmFsdWUpLmpvaW4oJyoqKicpO1xuICB9XG4gIHJldHVybiBvdXQ7XG59XG5cbi8qKlxuICogQXNzZW1ibGUgZGVwbG95IHBhcmFtcyBmcm9tIGV4cGxpY2l0IGZsYWdzIChmbGFncyBhbHdheXMgd2luIG92ZXIgdGhlIE5MXG4gKiBwYXJzZSwgd2hpY2ggb25seSBmaWxscyBnYXBzKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkUGFyYW1zKG9wdGlvbnM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LCBzZWxmSW5pdDogYm9vbGVhbik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgcmV0dXJuIHtcbiAgICByZWdpb246IG9wdGlvbnMucmVnaW9uLFxuICAgIGRvbWFpbjogb3B0aW9ucy5kb21haW4sXG4gICAgaG9zdGVkWm9uZUlkOiBvcHRpb25zLmhvc3RlZFpvbmVJZCxcbiAgICBkZXBsb3lNb2RlOiBvcHRpb25zLmRlcGxveU1vZGUsXG4gICAga2V5UGFpcjogb3B0aW9ucy5rZXlQYWlyLFxuICAgIGluc3RhbmNlVHlwZTogb3B0aW9ucy5pbnN0YW5jZVR5cGUsXG4gICAgLy8gZWMyIExFQU4gbW9kZSAoYm9vbGVhbikg4oaSIGFzc2VtYmxlQ29tbWFuZCBlbWl0cyBgLS1sZWFuYCwgd2hpY2ggc2V0dXAuc2hcbiAgICAvLyBmb3J3YXJkcyB0byB0aGUgQ0ZOIGBMZWFuYCBwYXJhbS4gT25seSBlYzIncyBzcGVjIGxpc3RzIGl0OyBvdGhlciB0YXJnZXRzIGlnbm9yZSBpdC5cbiAgICBsZWFuOiBvcHRpb25zLmxlYW4gPT09IHRydWUsXG4gICAgLy8gRGVwbG95LXRpbWUgcmVzb3VyY2UgaWRlbnRpdHk6IGVjMiBlbWl0cyAtLXN0YWNrLW5hbWUgKGtleSBzdGFja05hbWUpLCBla3MgZW1pdHNcbiAgICAvLyAtLWNsdXN0ZXItbmFtZSAoa2V5IGNsdXN0ZXJOYW1lKS4gQm90aCBhbHNvIGRyaXZlIHRlYXJkb3duLiBVbmRlZmluZWQg4oaSIGRlZmF1bHRzLlxuICAgIHN0YWNrTmFtZTogb3B0aW9ucy5zdGFja05hbWUsXG4gICAgY2x1c3Rlck5hbWU6IG9wdGlvbnMuY2x1c3Rlck5hbWUsXG4gICAgZ2hjclRva2VuOiBvcHRpb25zLmdoY3JUb2tlbixcbiAgICAvLyBlbWFpbC9ub0VtYWlsIGFyZSBjb2VyY2VkIEFGVEVSIHRoZSBOTCBtZXJnZSBiZWxvdyDigJQgcGFyc2VHb2FsIGNhbiByZXR1cm5cbiAgICAvLyBgZW1haWxgLCBzbyBwcmUtY29lcmNpbmcgaGVyZSAobmV2ZXItdW5kZWZpbmVkKSB3b3VsZCBsZXQgdGhlIG1lcmdlJ3NcbiAgICAvLyBgPT09IHVuZGVmaW5lZGAgZ3VhcmQgc2lsZW50bHkgZHJvcCBhbiBBSS1wYXJzZWQgZW1haWwgY2hvaWNlLiBMZWZ0IG91dCBvZlxuICAgIC8vIHRoaXMgbGl0ZXJhbCBvbiBwdXJwb3NlOyByZXNvbHZlZCBhIGZldyBsaW5lcyBkb3duLlxuICAgIGVtYWlsRnJvbTogb3B0aW9ucy5lbWFpbEZyb20sXG4gICAgZW1haWxGcm9tTmFtZTogb3B0aW9ucy5lbWFpbEZyb21OYW1lLFxuICAgIGFsZXJ0RW1haWw6IG9wdGlvbnMuYWxlcnRFbWFpbCxcbiAgICBub0NyZWF0ZVNlc0lkZW50aXR5OiBvcHRpb25zLnNraXBTZXNJZGVudGl0eSxcbiAgICAvLyBUaGUgQVdTIGRlcGxveXMgc2VsZi1pbml0IGJ5IGRlZmF1bHQgKGVjMiBvbiBmaXJzdCBib290LCBla3MgaW4gc2V0dXAuc2gncyBmaW5hbFxuICAgIC8vIHBoYXNlKSwgc28gd2UgZW1pdCB0aGUgbG9hZC1iZWFyaW5nIGAtLW5vLWF1dG8taW5pdGAgd2hlbiB0aGUgbW9kZSBpcyBOT1QgYXV0b1xuICAgIC8vIChtYW51YWwvc2tpcCA9IFwiZG9uJ3QgbGV0IHRoZSBkZXBsb3kgaW5pdCBpdHNlbGZcIikuIGAtLWF1dG8taW5pdGAgKGEgbm8tb3AgcmVhZmZpcm0pXG4gICAgLy8gaXMgbmV2ZXIgZW1pdHRlZC4gT25seSBlYzIvZWtzIGNhcnJ5IHRoZXNlIGZsYWdzIGluIHRoZWlyIHNwZWM7IG90aGVyIHRhcmdldHMgaWdub3JlIGl0LlxuICAgIG5vQXV0b0luaXQ6ICFzZWxmSW5pdCxcbiAgfTtcbn1cblxuLyoqXG4gKiBgLS1kaWFnbm9zZSA8ZmlsZT5gOiBleHBsYWluIGEgZGVwbG95IGZhaWx1cmUgd2l0aCB0aGUgY29uZmlndXJlZCBtb2RlbC4gQVxuICogcmVhZC1vbmx5IGluc3BlY3Rpb24gbW9kZSDigJQgdGhlIGNhbGxlciByZXR1cm5zIGFmdGVyd2FyZHMgd2hldGhlciBvciBub3QgYVxuICogdGFyZ2V0IHdhcyBnaXZlbiwgc28gaXQgbmV2ZXIgZmFsbHMgdGhyb3VnaCBpbnRvIGEgKHBvc3NpYmx5IC0teWVzKSBkZXBsb3kuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBydW5EaWFnbm9zZShmaWxlOiBzdHJpbmcsIGpzb246IGJvb2xlYW4sIGFpT3B0czogQWlPcHRpb25zLCBleGVjdXRpb25JZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIGxldCBmYWlsdXJlVGV4dDogc3RyaW5nO1xuICB0cnkge1xuICAgIGZhaWx1cmVUZXh0ID0gcmVhZEZpbGVTeW5jKGZpbGUsICd1dGYtOCcpO1xuICB9IGNhdGNoIHtcbiAgICBwcmludEVycm9yKGBDYW5ub3QgcmVhZCAtLWRpYWdub3NlIGZpbGU6ICR7ZmlsZX1gKTtcbiAgICBwcm9jZXNzLmV4aXRDb2RlID0gMTtcbiAgICByZXR1cm47XG4gIH1cbiAgY29uc3QgZGlhZ25vc2lzID0gaXNBaUNvbmZpZ3VyZWQoYWlPcHRzKSA/IGF3YWl0IGRpYWdub3NlRmFpbHVyZShmYWlsdXJlVGV4dCwgYWlPcHRzKSA6IG51bGw7XG4gIC8vIFdpdGggLS1qc29uLCB0aGUgZGlhZ25vc2lzIElTIHRoZSBtYWNoaW5lLXJlYWRhYmxlIG91dHB1dCDigJQgZW1pdCBpdFxuICAvLyBhbG9uZSAoZG9uJ3QgYWxzbyBwcmludCB0ZXh0LCB3aGljaCB3b3VsZCBjb3JydXB0IHRoZSBKU09OIHN0cmVhbSkuXG4gIGlmIChqc29uKSB7XG4gICAgY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkoeyBzdWNjZXNzOiB0cnVlLCBleGVjdXRpb25JZCwgZGlhZ25vc2lzIH0sIG51bGwsIDIpKTtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKGRpYWdub3Npcykge1xuICAgIHByaW50U2VjdGlvbignRmFpbHVyZSBkaWFnbm9zaXMnKTtcbiAgICBwcmludEluZm8oZGlhZ25vc2lzKTtcbiAgfSBlbHNlIHtcbiAgICBwcmludFdhcm5pbmcoJ0RpYWdub3NpcyB1bmF2YWlsYWJsZSAobm8gQUkga2V5IGNvbmZpZ3VyZWQgb3IgdGhlIG1vZGVsIGNvdWxkIG5vdCBiZSByZWFjaGVkKS4nKTtcbiAgfVxufVxuXG4vKiogUHJpbnQgdGhlIHByb3Zpc2lvbiBwbGFuIChzaG93biBiZWZvcmUgdGhlIGdhdGVkIGV4ZWN1dGlvbikuICovXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRQbGFuKHA6IHtcbiAgc3BlYzogVGFyZ2V0U3BlYztcbiAgdGFyZ2V0OiBUYXJnZXRJZDtcbiAgcHJlcmVxczogUHJlcmVxQ2hlY2tbXTtcbiAgbWlzc2luZzogQXNzZW1ibGVSZXN1bHRbJ21pc3NpbmcnXTtcbiAgYm9vdHN0cmFwOiBCb290c3RyYXBTcGVjO1xuICBib290c3RyYXBDbWQ6IHN0cmluZyB8IG51bGw7XG4gIHNwYXJzZVBhdGhzOiBzdHJpbmdbXTtcbiAgY29tbWFuZDogc3RyaW5nO1xuICBwb3N0U3RlcHM6IFBvc3RTdGVwW107XG4gIHNraXBwZWRTdGVwczogU2tpcHBlZFN0ZXBbXTtcbn0pOiB2b2lkIHtcbiAgY29uc3QgeyBzcGVjLCB0YXJnZXQsIHByZXJlcXMsIG1pc3NpbmcsIGJvb3RzdHJhcCwgYm9vdHN0cmFwQ21kLCBzcGFyc2VQYXRocywgY29tbWFuZCwgcG9zdFN0ZXBzLCBza2lwcGVkU3RlcHMgfSA9IHA7XG4gIHByaW50U2VjdGlvbihgUHJvdmlzaW9uIHBsYW4g4oCUICR7c3BlYy5sYWJlbH1gKTtcbiAgcHJpbnRLZXlWYWx1ZSh7ICdUYXJnZXQnOiB0YXJnZXQsICdCZXN0IGZvcic6IHNwZWMuYmVzdEZvciwgJ0Nvc3QnOiBzcGVjLmNvc3QgfSk7XG5cbiAgcHJpbnRTZWN0aW9uKCdQcmVyZXF1aXNpdGVzJyk7XG4gIGZvciAoY29uc3QgYyBvZiBwcmVyZXFzKSBwcmludEluZm8oYCR7Yy5vayA/ICfinJMnIDogJ+Kclyd9ICR7Yy5uYW1lfSDigJQgJHtjLmRldGFpbH1gKTtcbiAgaWYgKCFwcmVyZXFzU2F0aXNmaWVkKHByZXJlcXMpKSBwcmludFdhcm5pbmcoJ1Jlc29sdmUgdGhlIGZhaWxpbmcgcHJlcmVxdWlzaXRlcyBhYm92ZSBiZWZvcmUgZGVwbG95aW5nLicpO1xuXG4gIGlmIChtaXNzaW5nLmxlbmd0aCA+IDApIHtcbiAgICBwcmludFNlY3Rpb24oJ01pc3NpbmcgcmVxdWlyZWQgaW5wdXRzJyk7XG4gICAgZm9yIChjb25zdCBtIG9mIG1pc3NpbmcpIHByaW50SW5mbyhgICAtLSR7bS5mbGFnfSAgKCR7bS5kZXNjcmlwdGlvbn0pYCk7XG4gIH1cblxuICBpZiAoYm9vdHN0cmFwQ21kKSB7XG4gICAgcHJpbnRTZWN0aW9uKCdCb290c3RyYXAgKHNwYXJzZSBnaXQgY2xvbmUsIHJ1bnMgZmlyc3QpJyk7XG4gICAgcHJpbnRJbmZvKGBDbG9uZSAke2Jvb3RzdHJhcC5yZXBvfSBAICR7Ym9vdHN0cmFwLnJlZn0g4oaSICR7Ym9vdHN0cmFwLndvcmtkaXJ9OyBmb2xkZXJzOiAke3NwYXJzZVBhdGhzLmpvaW4oJywgJyl9YCk7XG4gICAgcHJpbnRJbmZvKGJvb3RzdHJhcENtZCk7XG4gIH1cblxuICBwcmludFNlY3Rpb24oJ0NvbW1hbmQgdG8gcnVuJyk7XG4gIHByaW50SW5mbyhjb21tYW5kKTtcblxuICBpZiAocG9zdFN0ZXBzLmxlbmd0aCA+IDAgfHwgc2tpcHBlZFN0ZXBzLmxlbmd0aCA+IDApIHtcbiAgICBwcmludFNlY3Rpb24oJ1Bvc3QtaW5zdGFsbCBzdGVwcycpO1xuICAgIGZvciAoY29uc3QgcyBvZiBwb3N0U3RlcHMpIHByaW50SW5mbyhg4oCiICR7cy5sYWJlbH1cXG4gICAgJHtzLmNvbW1hbmR9YCk7XG4gICAgZm9yIChjb25zdCBzIG9mIHNraXBwZWRTdGVwcykgcHJpbnRXYXJuaW5nKGBTa2lwcGVkICR7cy5pZH06ICR7cy5yZWFzb259YCk7XG4gIH1cbn1cblxuLyoqXG4gKiBQbHVnaW5zIHdlcmUgcGlja2VkIGludGVyYWN0aXZlbHk6IHJlLWNoZWNrIHRoZSBwbHVnaW4tc3BlY2lmaWMgcHJlcmVxcyB0aGF0XG4gKiB3ZXJlIGRlbGliZXJhdGVseSBub3QgaGFyZC1yZXF1aXJlZCB1cCBmcm9udCAoZS5nLiB5cSBmb3IgbWluaWt1YmUgcGx1Z2luXG4gKiBidWlsZHMpLiBPZmZlciB0byBmZXRjaCBhbnkgZmV0Y2hhYmxlIG9uZTsgd2FybiAoZG9uJ3QgYmxvY2sg4oCUIHRoZSBwbGF0Zm9ybVxuICogc3RpbGwgZGVwbG95cykgaWYgaXQgY2FuJ3QgYmUgcmVzb2x2ZWQsIHNvIHRoZSBsYXRlciBwbHVnaW4gYnVpbGQgZG9lc24ndFxuICogZmFpbCBvcGFxdWVseS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlY2hlY2tQbHVnaW5QcmVyZXFzKHRhcmdldDogVGFyZ2V0SWQsIHdhbnRCb290c3RyYXA6IGJvb2xlYW4sIHByZXJlcXM6IFByZXJlcUNoZWNrW10sIHllczogYm9vbGVhbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBwbHVnaW5QcmVyZXFzID0gY2hlY2tQcmVyZXFzKHRhcmdldCwgeyBib290c3RyYXA6IHdhbnRCb290c3RyYXAsIHdpdGhQbHVnaW5zOiB0cnVlIH0pO1xuICBjb25zdCBwbHVnaW5HYXBzID0gcGx1Z2luUHJlcmVxcy5maWx0ZXIoKGMpID0+ICFjLm9rICYmIGMucmVxdWlyZWQgJiYgIXByZXJlcXMuc29tZSgocCkgPT4gcC5uYW1lID09PSBjLm5hbWUpKTtcbiAgZm9yIChjb25zdCBjIG9mIHBsdWdpbkdhcHMpIHtcbiAgICBpZiAoaXNGZXRjaGFibGUoYy5uYW1lKSAmJiBhd2FpdCBjb25maXJtKGBcXG4ke2MubmFtZX0gaXMgbmVlZGVkIHRvIGJ1aWxkIHBsdWdpbnMgYnV0IGlzbid0IGluc3RhbGxlZCDigJQgZmV0Y2ggdGhlIHN0YXRpYyBiaW5hcnkgaW50byAke1RPT0xTX0RJUn0/YCwgeWVzKSkge1xuICAgICAgcHJpbnRJbmZvKGBGZXRjaGluZyAke2MubmFtZX3igKZgKTtcbiAgICAgIGlmICghZmV0Y2hUb29sKGMubmFtZSkpIHByaW50V2FybmluZyhgQ291bGRuJ3QgZmV0Y2ggJHtjLm5hbWV9IOKAlCBpbnN0YWxsIGl0IGJlZm9yZSB0aGUgcGx1Z2luIGJ1aWxkIHJ1bnMuYCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHByaW50V2FybmluZyhgJHtjLm5hbWV9IG1pc3Npbmcg4oCUIHRoZSBwbHVnaW4gbG9hZC9idWlsZCBzdGVwIG1heSBmYWlsLiAke2MuZGV0YWlsfWApO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIGxvY2FsL21pbmlrdWJlJ3Mgc2V0dXAuc2ggUkVRVUlSRVMgYSBgLmVudmAgYW5kIGFib3J0cyB3aXRob3V0IGl0IOKAlCBjcmVhdGVcbiAqIGl0IGZyb20gLmVudi5leGFtcGxlIHdpdGggZ2VuZXJhdGVkIHNlY3JldHMgc28gdGhlIGRlcGxveSBpcyBub24taW50ZXJhY3RpdmUuXG4gKiBlYzIgYW5kIGVrcyBkb24ndCBuZWVkIGEgbG9jYWwgYC5lbnZgOiBlYzIgYm9vdHN0cmFwcyBpdHMgc2VjcmV0cyBvbiB0aGVcbiAqIGluc3RhbmNlLCBhbmQgZWtzJ3Mgc2V0dXAuc2ggY3JlYXRlcyB0aGUgazhzIHNlY3JldHMgaXRzZWxmLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZW5zdXJlTG9jYWxFbnZGaWxlKHRhcmdldDogVGFyZ2V0SWQsIHNwZWM6IFRhcmdldFNwZWMsIGN3ZDogc3RyaW5nLCB5ZXM6IGJvb2xlYW4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKCh0YXJnZXQgIT09ICdkb2NrZXInICYmIHRhcmdldCAhPT0gJ21pbmlrdWJlJykgfHwgIWVudkZpbGVNaXNzaW5nKGN3ZCwgc3BlYy5kaXIpKSByZXR1cm47XG4gIGlmIChhd2FpdCBjb25maXJtKGBcXG4ke3NwZWMuZGlyfS8uZW52IG5vdCBmb3VuZCDigJQgY3JlYXRlIGl0IGZyb20gLmVudi5leGFtcGxlIChnZW5lcmF0ZXMgc2VjcmV0czsgZWRpdCBsYXRlciBmb3Igb3B0aW9uYWwgaW50ZWdyYXRpb25zIGxpa2UgT0F1dGgpP2AsIHllcykpIHtcbiAgICBjb25zdCBuID0gY3JlYXRlRW52RmlsZShjd2QsIHNwZWMuZGlyKTtcbiAgICBwcmludFN1Y2Nlc3MoYENyZWF0ZWQgJHtzcGVjLmRpcn0vLmVudiDigJQgJHtufSBzZWNyZXQocykgZ2VuZXJhdGVkLmApO1xuICB9IGVsc2Uge1xuICAgIHByaW50V2FybmluZygnQ29udGludWluZyB3aXRob3V0IC5lbnYg4oCUIHNldHVwLnNoIHdpbGwgYWJvcnQgaWYgaXQgc3RheXMgbWlzc2luZy4nKTtcbiAgfVxufVxuXG4vKipcbiAqIEFueSBtaXNzaW5nIHJlcXVpcmVkIHByZXJlcSB0aGF0J3MgYSBzaW5nbGUgc3RhdGljIGJpbmFyeSAoZS5nLiB5cSkgY2FuIGJlXG4gKiBmZXRjaGVkIGludG8gdGhlIHRvb2xzIGNhY2hlIGluc3RlYWQgb2YgYSBzeXN0ZW0gaW5zdGFsbCDigJQgbm8gYnJldy9hcHQuXG4gKiBPZmZlciBpdCwgdGhlbiByZS1jaGVjayAodGhlIGNhY2hlIGRpciBpcyBhbHJlYWR5IG9uIFBBVEgpLiBSZXR1cm5zIHRoZVxuICogKHBvc3NpYmx5IHJlZnJlc2hlZCkgcHJlcmVxIGxpc3QuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBvZmZlclRvb2xGZXRjaChwcmVyZXFzOiBQcmVyZXFDaGVja1tdLCB5ZXM6IGJvb2xlYW4sIHJlY2hlY2s6ICgpID0+IFByZXJlcUNoZWNrW10pOiBQcm9taXNlPFByZXJlcUNoZWNrW10+IHtcbiAgY29uc3QgZmV0Y2hhYmxlID0gcHJlcmVxcy5maWx0ZXIoKGMpID0+ICFjLm9rICYmIGMucmVxdWlyZWQgJiYgaXNGZXRjaGFibGUoYy5uYW1lKSk7XG4gIGlmIChmZXRjaGFibGUubGVuZ3RoID09PSAwKSByZXR1cm4gcHJlcmVxcztcbiAgY29uc3QgbmFtZXMgPSBmZXRjaGFibGUubWFwKChjKSA9PiBjLm5hbWUpLmpvaW4oJywgJyk7XG4gIGlmICghKGF3YWl0IGNvbmZpcm0oYFxcbiR7bmFtZXN9IG5vdCBpbnN0YWxsZWQg4oCUIGZldGNoIHRoZSBvZmZpY2lhbCBzdGF0aWMgYmluYXJ5IGludG8gJHtUT09MU19ESVJ9IChubyBzeXN0ZW0gaW5zdGFsbCk/YCwgeWVzKSkpIHJldHVybiBwcmVyZXFzO1xuICBmb3IgKGNvbnN0IGMgb2YgZmV0Y2hhYmxlKSB7XG4gICAgcHJpbnRJbmZvKGBGZXRjaGluZyAke2MubmFtZX3igKZgKTtcbiAgICBpZiAoIWZldGNoVG9vbChjLm5hbWUpKSBwcmludFdhcm5pbmcoYENvdWxkbid0IGZldGNoICR7Yy5uYW1lfSDigJQgaW5zdGFsbCBpdCBtYW51YWxseSBhbmQgcmUtcnVuLmApO1xuICB9XG4gIHJldHVybiByZWNoZWNrKCk7XG59XG5cbi8qKiBWZXJpZnkgaGVhbHRoIGFmdGVyIHRoZSBkZXBsb3kgKENSRUFURV9DT01QTEVURSAhPSBzZXJ2aW5nKS4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB2ZXJpZnlIZWFsdGgodGFyZ2V0OiBUYXJnZXRJZCwgdXJsOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgcHJpbnRTZWN0aW9uKCdWZXJpZnlpbmcgaGVhbHRoJyk7XG4gIC8vIE1pbmlrdWJlIHJlYWNoZXMgdGhlIGdhdGV3YXkgdmlhIGEga3ViZWN0bCBwb3J0LWZvcndhcmQgdGhhdCBzZXR1cC5zaFxuICAvLyBiYWNrZ3JvdW5kcyBhbmQgdGhhdCBjYW4gZGllL2ZhaWwgdG8gYmluZCDigJQgKHJlKXN0YXJ0IGl0IGJlZm9yZSBwb2xsaW5nXG4gIC8vIHNvIHdlIGRvbid0IHNpdCBhdCB0aGUgZ2F0ZSBvbiBhIGRlYWQgZm9yd2FyZCB3aGlsZSB0aGUgcG9kcyBhcmUgZmluZS5cbiAgaWYgKHRhcmdldCA9PT0gJ21pbmlrdWJlJykge1xuICAgIGF3YWl0IGVuc3VyZU1pbmlrdWJlR2F0ZXdheSh1cmwsIHsgb25JbmZvOiAobSkgPT4gcHJpbnRJbmZvKG0pIH0pO1xuICB9XG4gIHByaW50SW5mbyhgUG9sbGluZyAke3VybH0vaGVhbHRoIOKApmApO1xuICAvLyBGcmVzaCBFS1MgbGVnaXRpbWF0ZWx5IG5lZWRzIGxvbmdlciB0aGFuIHRoZSAzMDBzIGRlZmF1bHQ6IEthcnBlbnRlciBwcm92aXNpb25zXG4gIC8vIG5vZGVzLCB+MTAgc2VydmljZXMgY29sZC1wdWxsIGltYWdlcywgdGhlIEFMQiBwcm92aXNpb25zICh+Mi0zIG1pbiksIGFuZCB0aGVcbiAgLy8gUm91dGUgNTMgYWxpYXMgcHJvcGFnYXRlcy4gR2l2ZSBpdCAxNSBtaW4gYmVmb3JlIHN1cmZhY2luZyB0aGUgbm90LXJlYWNoYWJsZSBub3RlLlxuICBjb25zdCBoZWFsdGhUaW1lb3V0TXMgPSB0YXJnZXQgPT09ICdla3MnID8gOTAwXzAwMCA6IHVuZGVmaW5lZDtcbiAgY29uc3QgaGVhbHRoID0gYXdhaXQgd2FpdEhlYWx0aHkodXJsLCB7IHRpbWVvdXRNczogaGVhbHRoVGltZW91dE1zLCBvblRpY2s6IChtKSA9PiBwcmludEluZm8obSkgfSk7XG4gIC8vIEdyZWVuIG9ubHkgd2hlbiBmdWxseSByZWFkeTsgYSBcImhlYWx0aCBPSyBidXQgL3JlYWR5IG5ldmVyIGNhbWVcIiBwcm9jZWVkLVxuICAvLyBhbnl3YXkgc3RhdGUgaXMgaGVhbHRoeTp0cnVlIGJ1dCBkZWdyYWRlZCDihpIgd2FybiBzbyBpdCBkb2Vzbid0IHJlYWQgYXMgZG9uZS5cbiAgKGhlYWx0aC5oZWFsdGh5ICYmIGhlYWx0aC5yZWFkeSA/IHByaW50U3VjY2VzcyA6IHByaW50V2FybmluZykoYCR7aGVhbHRoLnVybH0g4oCUICR7aGVhbHRoLmRldGFpbH1gKTtcbn1cbiJdfQ==
|