@pipeline-builder/pipeline-manager 3.4.70 → 3.4.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -2
- package/dist/agent/ai.d.ts +55 -0
- package/dist/agent/ai.d.ts.map +1 -0
- package/dist/agent/ai.js +130 -0
- package/dist/agent/bootstrap.d.ts +54 -0
- package/dist/agent/bootstrap.d.ts.map +1 -0
- package/dist/agent/bootstrap.js +76 -0
- package/dist/agent/executor.d.ts +27 -0
- package/dist/agent/executor.d.ts.map +1 -0
- package/dist/agent/executor.js +57 -0
- package/dist/agent/health.d.ts +22 -0
- package/dist/agent/health.d.ts.map +1 -0
- package/dist/agent/health.js +55 -0
- package/dist/agent/post-steps.d.ts +55 -0
- package/dist/agent/post-steps.d.ts.map +1 -0
- package/dist/agent/post-steps.js +73 -0
- package/dist/agent/prereqs.d.ts +25 -0
- package/dist/agent/prereqs.d.ts.map +1 -0
- package/dist/agent/prereqs.js +100 -0
- package/dist/agent/targets.d.ts +122 -0
- package/dist/agent/targets.d.ts.map +1 -0
- package/dist/agent/targets.js +180 -0
- package/dist/agent/troubleshoot.d.ts +30 -0
- package/dist/agent/troubleshoot.d.ts.map +1 -0
- package/dist/agent/troubleshoot.js +87 -0
- package/dist/boilerplate.js +8 -13
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +123 -118
- package/dist/commands/audit-stacks.js +22 -24
- package/dist/commands/audit-tokens.js +25 -27
- package/dist/commands/bootstrap.js +29 -37
- package/dist/commands/create-pipeline.js +55 -92
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +58 -62
- package/dist/commands/get-pipeline.js +24 -28
- package/dist/commands/get-plugin.js +24 -28
- package/dist/commands/list-pipelines.js +30 -31
- package/dist/commands/list-plugins.js +32 -33
- package/dist/commands/login.js +44 -49
- package/dist/commands/org-export.js +22 -60
- package/dist/commands/provision.d.ts +13 -0
- package/dist/commands/provision.d.ts.map +1 -0
- package/dist/commands/provision.js +489 -0
- package/dist/commands/register.js +29 -30
- package/dist/commands/setup-events.d.ts.map +1 -1
- package/dist/commands/setup-events.js +42 -77
- package/dist/commands/status.js +20 -25
- package/dist/commands/store-token.js +44 -82
- package/dist/commands/synth.d.ts.map +1 -1
- package/dist/commands/synth.js +36 -35
- package/dist/commands/upload-plugin.js +59 -96
- package/dist/commands/validate-templates.d.ts.map +1 -1
- package/dist/commands/validate-templates.js +23 -29
- package/dist/commands/version.js +42 -47
- package/dist/config/cli.constants.d.ts.map +1 -1
- package/dist/config/cli.constants.js +24 -31
- package/dist/types/config.js +2 -3
- package/dist/types/error.js +3 -7
- package/dist/types/index.d.ts +4 -4
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +5 -21
- package/dist/types/pipeline.js +2 -3
- package/dist/types/plugin.js +2 -3
- package/dist/utils/api-client.d.ts +1 -1
- package/dist/utils/api-client.d.ts.map +1 -1
- package/dist/utils/api-client.js +23 -28
- package/dist/utils/audit-log.js +16 -22
- package/dist/utils/auth-guard.js +2 -5
- package/dist/utils/aws-secrets.js +17 -23
- package/dist/utils/banner.js +16 -23
- package/dist/utils/cdk-utils.js +14 -24
- package/dist/utils/command-utils.d.ts +1 -1
- package/dist/utils/command-utils.d.ts.map +1 -1
- package/dist/utils/command-utils.js +32 -44
- package/dist/utils/config-loader.d.ts +1 -1
- package/dist/utils/config-loader.d.ts.map +1 -1
- package/dist/utils/config-loader.js +24 -58
- package/dist/utils/error-handler.d.ts +1 -1
- package/dist/utils/error-handler.d.ts.map +1 -1
- package/dist/utils/error-handler.js +16 -24
- package/dist/utils/list-command-utils.js +15 -20
- package/dist/utils/output-utils.d.ts +1 -1
- package/dist/utils/output-utils.d.ts.map +1 -1
- package/dist/utils/output-utils.js +35 -55
- package/dist/utils/plugin-resolver.d.ts +1 -1
- package/dist/utils/plugin-resolver.d.ts.map +1 -1
- package/dist/utils/plugin-resolver.js +6 -8
- package/dist/utils/rate-limiter.js +11 -19
- package/dist/utils/registry.js +16 -22
- package/package.json +26 -17
|
@@ -0,0 +1,489 @@
|
|
|
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 { Command } from 'commander';
|
|
7
|
+
import { diagnoseFailure, isAiConfigured, parseGoal } from '../agent/ai.js';
|
|
8
|
+
import { bootstrapCommand, resolveBootstrap } from '../agent/bootstrap.js';
|
|
9
|
+
import { entrypointExists, executionBlocked, runScript } from '../agent/executor.js';
|
|
10
|
+
import { deriveHealthUrl, waitHealthy } from '../agent/health.js';
|
|
11
|
+
import { resolvePostSteps } from '../agent/post-steps.js';
|
|
12
|
+
import { checkPrereqs, gitAvailable, gitSupportsSparseCheckout, prereqsSatisfied } from '../agent/prereqs.js';
|
|
13
|
+
import { assembleCommand, isTargetId, LOAD_STEPS, sparsePathsFor, TARGETS, TARGET_IDS, teardownCommand, } from '../agent/targets.js';
|
|
14
|
+
import { matchIssues, sesPostDeployGuidance } from '../agent/troubleshoot.js';
|
|
15
|
+
import { printCommandHeader } from '../utils/command-utils.js';
|
|
16
|
+
import { ERROR_CODES, handleError } from '../utils/error-handler.js';
|
|
17
|
+
import { printSection, printKeyValue, printInfo, printWarning, printError, printSuccess } from '../utils/output-utils.js';
|
|
18
|
+
/**
|
|
19
|
+
* Read one line of trimmed input from the terminal, owning the readline
|
|
20
|
+
* lifecycle. Used directly for the destructive teardown gate (a y/N is too easy
|
|
21
|
+
* to fat-finger, so we require the operator to TYPE the target id back), and as
|
|
22
|
+
* the basis for `confirm`. Deliberately has no auto-accept.
|
|
23
|
+
*/
|
|
24
|
+
async function ask(question) {
|
|
25
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
26
|
+
try {
|
|
27
|
+
return (await rl.question(question)).trim();
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
rl.close();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** Interactive y/N confirmation; auto-true when `autoYes` (the `--yes` flag). */
|
|
34
|
+
async function confirm(question, autoYes) {
|
|
35
|
+
if (autoYes)
|
|
36
|
+
return true;
|
|
37
|
+
const answer = (await ask(`${question} [y/N] `)).toLowerCase();
|
|
38
|
+
return answer === 'y' || answer === 'yes';
|
|
39
|
+
}
|
|
40
|
+
/** Commander collector: accumulate repeated `--post-step` values in order. */
|
|
41
|
+
function collectStep(value, acc) {
|
|
42
|
+
return [...acc, value];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Redact secret param values (e.g. the ghcr token) from captured deploy output
|
|
46
|
+
* before it is sent to the LLM for diagnosis. The deploy runs with secrets
|
|
47
|
+
* unmasked, so although the current scripts don't echo them, this keeps a future
|
|
48
|
+
* script's stray echo (or a verbose sub-tool) from crossing the third-party-LLM
|
|
49
|
+
* boundary.
|
|
50
|
+
*/
|
|
51
|
+
function redactSecrets(text, spec, params) {
|
|
52
|
+
let out = text;
|
|
53
|
+
for (const input of [...spec.required, ...spec.optional]) {
|
|
54
|
+
if (!input.secret)
|
|
55
|
+
continue;
|
|
56
|
+
const value = params[input.key];
|
|
57
|
+
if (typeof value === 'string' && value.length >= 4)
|
|
58
|
+
out = out.split(value).join('***');
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Registers the `provision` command — an AI-assisted installer for the Pipeline
|
|
64
|
+
* Builder PLATFORM (local/minikube/EC2/Fargate). Phase 1 is READ-ONLY (prereq
|
|
65
|
+
* checks, NL-goal parsing, command assembly, failure diagnosis); `--execute`
|
|
66
|
+
* gates a real deploy. With `--repo` it can bootstrap a fresh machine by sparsely
|
|
67
|
+
* cloning only the deploy folders the selected target + options need, then runs
|
|
68
|
+
* post-install steps (register admin, opt-in loads, smoke test, custom commands).
|
|
69
|
+
*
|
|
70
|
+
* @param program - The root Commander program instance to attach the command to.
|
|
71
|
+
*/
|
|
72
|
+
export function provision(program) {
|
|
73
|
+
program
|
|
74
|
+
.command('provision')
|
|
75
|
+
.description('AI-assisted installer for the platform (local/minikube/EC2/Fargate): advise, --execute to deploy, or --teardown to remove')
|
|
76
|
+
.option('-t, --target <target>', `Deploy target: ${TARGET_IDS.join(' | ')}`)
|
|
77
|
+
.option('-p, --prompt <text>', 'Natural-language goal (parsed into params when an AI key is set)')
|
|
78
|
+
.option('--region <region>', 'AWS region (EC2/Fargate)')
|
|
79
|
+
.option('--domain <domain>', 'Fully-qualified domain name (EC2/Fargate)')
|
|
80
|
+
.option('--hosted-zone-id <id>', 'Public Route 53 hosted zone ID (EC2/Fargate)')
|
|
81
|
+
.option('--deploy-mode <mode>', 'public | private (EC2/Fargate)')
|
|
82
|
+
.option('--key-pair <name>', 'EC2 key pair (EC2)')
|
|
83
|
+
.option('--instance-type <type>', 'EC2 instance type (EC2)')
|
|
84
|
+
.option('--ghcr-token <token>', 'GitHub PAT (read:packages) — masked in output')
|
|
85
|
+
.option('--email', 'Enable SES transactional email (on by default for AWS)')
|
|
86
|
+
.option('--no-email', 'Skip SES (transactional email is provisioned by default on AWS)')
|
|
87
|
+
.option('--email-from <addr>', 'SES From address')
|
|
88
|
+
.option('--email-from-name <name>', 'SES From display name')
|
|
89
|
+
.option('--alert-email <addr>', 'Subscribe an address to the bounce/complaint SNS topic')
|
|
90
|
+
.option('--skip-ses-identity', 'Skip SES identity creation (domain already verified)')
|
|
91
|
+
.option('--ai-provider <provider>', 'AI provider (anthropic|openai|google|xai|bedrock)')
|
|
92
|
+
.option('--model <model>', 'AI model id')
|
|
93
|
+
.option('--diagnose <file>', 'Diagnose a CloudFormation/deploy failure from a file (needs an AI key)')
|
|
94
|
+
.option('-y, --yes', 'Auto-accept the execution approval prompt (for CI / non-interactive)', false)
|
|
95
|
+
.option('--execute', 'Run the deploy (gated: needs approval, refuses on failed prereqs / missing inputs)', false)
|
|
96
|
+
.option('--retries <n>', 'Auto-fix + retry attempts after a failure (deploy scripts are idempotent)', '1')
|
|
97
|
+
.option('--teardown', 'Tear down an existing deployment instead of creating one (gated; AWS targets require a typed confirmation)', false)
|
|
98
|
+
.option('--stack-name <name>', 'Stack name (EC2) / stack prefix (Fargate) to tear down — defaults to the deploy default')
|
|
99
|
+
.option('--force', 'Skip the teardown typed-confirmation (DANGEROUS — for CI/automation only)', false)
|
|
100
|
+
.option('--no-init', 'Skip the post-deploy register/init-platform step')
|
|
101
|
+
// Bootstrap (sparse clone) — provision a fresh machine in one command.
|
|
102
|
+
.option('--repo [url]', 'Bootstrap: git-clone the platform repo first (sparse — only the needed deploy folders), then run from it (no value = the upstream default)')
|
|
103
|
+
.option('--ref <ref>', 'Git branch/tag to check out when bootstrapping (default: main)')
|
|
104
|
+
.option('--workdir <dir>', 'Directory to clone into / run from when bootstrapping (default: pipeline-builder)')
|
|
105
|
+
// Post-install loads — each opt-in step also adds its deploy folder to the sparse clone.
|
|
106
|
+
.option('--with-plugins', 'Post-install: build + load plugins (adds deploy/plugins, deploy/codebuild)', false)
|
|
107
|
+
.option('--with-compliance', 'Post-install: load sample compliance rules/policies (adds deploy/compliance)', false)
|
|
108
|
+
.option('--with-samples', 'Post-install: load sample pipelines (adds deploy/samples)', false)
|
|
109
|
+
.option('--with-all', 'Post-install: plugins + compliance + samples', false)
|
|
110
|
+
.option('--build-bootstrap', 'Build + publish the CodeBuild bootstrap image during register (adds deploy/codebuild)', false)
|
|
111
|
+
.option('--with-smoke-test', 'Post-install: read-only API reachability check', false)
|
|
112
|
+
.option('--with-events', 'Post-install: EventBridge ingestion via setup-events (AWS targets)', false)
|
|
113
|
+
.option('--post-step <cmd>', 'Run an extra command after the loads (repeatable, in order)', collectStep, [])
|
|
114
|
+
.option('--admin-email <addr>', 'Admin email for non-interactive register (sets PLATFORM_IDENTIFIER)')
|
|
115
|
+
.option('--admin-password <pw>', 'Admin password for non-interactive register (sets PLATFORM_PASSWORD)')
|
|
116
|
+
.option('--json', 'Output the plan as JSON (never executes)', false)
|
|
117
|
+
.action(async (options) => {
|
|
118
|
+
const executionId = printCommandHeader('Provision (advisor)');
|
|
119
|
+
try {
|
|
120
|
+
// 1. Assemble params from explicit flags (flags always win over NL parse).
|
|
121
|
+
const params = {
|
|
122
|
+
region: options.region,
|
|
123
|
+
domain: options.domain,
|
|
124
|
+
hostedZoneId: options.hostedZoneId,
|
|
125
|
+
deployMode: options.deployMode,
|
|
126
|
+
keyPair: options.keyPair,
|
|
127
|
+
instanceType: options.instanceType,
|
|
128
|
+
ghcrToken: options.ghcrToken,
|
|
129
|
+
// Commander tri-states `email`: undefined (neither), true (--email),
|
|
130
|
+
// false (--no-email). SES is on by default, so only --no-email is
|
|
131
|
+
// load-bearing (it emits `--no-email` into the deploy command).
|
|
132
|
+
email: options.email === true,
|
|
133
|
+
noEmail: options.email === false,
|
|
134
|
+
emailFrom: options.emailFrom,
|
|
135
|
+
emailFromName: options.emailFromName,
|
|
136
|
+
alertEmail: options.alertEmail,
|
|
137
|
+
noCreateSesIdentity: options.skipSesIdentity,
|
|
138
|
+
};
|
|
139
|
+
const aiOpts = { provider: options.aiProvider, model: options.model };
|
|
140
|
+
// Bootstrap (sparse clone) + post-install selections.
|
|
141
|
+
const wantBootstrap = options.repo !== undefined && options.repo !== false;
|
|
142
|
+
const withAll = options.withAll === true;
|
|
143
|
+
const enabledLoadIds = LOAD_STEPS.filter((s) => withAll || options[s.flag] === true).map((s) => s.id);
|
|
144
|
+
const postStepFlags = {
|
|
145
|
+
init: options.init !== false,
|
|
146
|
+
buildBootstrap: options.buildBootstrap === true || enabledLoadIds.includes('plugins'),
|
|
147
|
+
smokeTest: options.withSmokeTest === true,
|
|
148
|
+
events: options.withEvents === true,
|
|
149
|
+
steps: (options.postStep ?? []),
|
|
150
|
+
};
|
|
151
|
+
// Admin credentials forwarded as env so register runs non-interactively.
|
|
152
|
+
const adminEnv = {};
|
|
153
|
+
if (typeof options.adminEmail === 'string')
|
|
154
|
+
adminEnv.PLATFORM_IDENTIFIER = options.adminEmail;
|
|
155
|
+
if (typeof options.adminPassword === 'string')
|
|
156
|
+
adminEnv.PLATFORM_PASSWORD = options.adminPassword;
|
|
157
|
+
// 2. Optionally parse a natural-language goal to fill any GAPS (best-effort).
|
|
158
|
+
let target = isTargetId(options.target) ? options.target : undefined;
|
|
159
|
+
if (options.prompt) {
|
|
160
|
+
if (isAiConfigured(aiOpts)) {
|
|
161
|
+
const parsed = await parseGoal(options.prompt, aiOpts);
|
|
162
|
+
if (parsed) {
|
|
163
|
+
if (!target && isTargetId(parsed.target))
|
|
164
|
+
target = parsed.target;
|
|
165
|
+
for (const [k, v] of Object.entries(parsed)) {
|
|
166
|
+
if (k !== 'target' && params[k] === undefined && v !== undefined)
|
|
167
|
+
params[k] = v;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
printWarning('A --prompt was given but no AI key is set — ignoring it and using flags only. Set ANTHROPIC_API_KEY (or --ai-provider + its key).');
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// 3. Optional failure diagnosis (independent of a deploy plan).
|
|
176
|
+
if (options.diagnose) {
|
|
177
|
+
let failureText;
|
|
178
|
+
try {
|
|
179
|
+
failureText = readFileSync(options.diagnose, 'utf-8');
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
printError(`Cannot read --diagnose file: ${options.diagnose}`);
|
|
183
|
+
process.exitCode = 1;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const diagnosis = isAiConfigured(aiOpts) ? await diagnoseFailure(failureText, aiOpts) : null;
|
|
187
|
+
// With --json, the diagnosis IS the machine-readable output — emit it
|
|
188
|
+
// alone (don't also print text, which would corrupt the JSON stream).
|
|
189
|
+
if (options.json) {
|
|
190
|
+
console.log(JSON.stringify({ success: true, executionId, diagnosis }, null, 2));
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (diagnosis) {
|
|
194
|
+
printSection('Failure diagnosis');
|
|
195
|
+
printInfo(diagnosis);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
printWarning('Diagnosis unavailable (no AI key configured or the model could not be reached).');
|
|
199
|
+
}
|
|
200
|
+
if (!target)
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
// 4. Need a target to assemble a plan.
|
|
204
|
+
if (!target) {
|
|
205
|
+
printError(`No target specified. Pass --target <${TARGET_IDS.join('|')}> or describe the goal with --prompt.`);
|
|
206
|
+
process.exitCode = 1;
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const spec = TARGETS[target];
|
|
210
|
+
let cwd = process.cwd();
|
|
211
|
+
// 4b. Teardown mode — the destroy counterpart of provisioning. Gated harder
|
|
212
|
+
// than deploy: AWS targets are irreversible, so we require the operator to
|
|
213
|
+
// TYPE the target id (--force bypasses for CI; --yes alone does NOT).
|
|
214
|
+
if (options.teardown) {
|
|
215
|
+
const { command: downCommand, destructive } = teardownCommand(target, {
|
|
216
|
+
stackName: options.stackName,
|
|
217
|
+
region: options.region,
|
|
218
|
+
// Our typed gate IS the confirmation — forward --yes so the native
|
|
219
|
+
// script (Fargate) doesn't also block on stdin we're inheriting.
|
|
220
|
+
assumeYes: true,
|
|
221
|
+
});
|
|
222
|
+
if (options.json) {
|
|
223
|
+
console.log(JSON.stringify({ success: true, executionId, target, teardown: true, destructive, destroys: spec.destroys, command: downCommand }, null, 2));
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
printSection(`Teardown plan — ${spec.label}`);
|
|
227
|
+
printKeyValue({ 'Target': target, 'Destroys': spec.destroys, 'Stops cost': spec.cost });
|
|
228
|
+
printSection('Command to run');
|
|
229
|
+
printInfo(downCommand);
|
|
230
|
+
if (!options.execute) {
|
|
231
|
+
printWarning('\nAdvisor mode — nothing was executed. Re-run with --execute to tear down.');
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (destructive && !options.force) {
|
|
235
|
+
const token = await ask(`\nThis is IRREVERSIBLE. Type "${target}" to confirm teardown: `);
|
|
236
|
+
if (token !== target) {
|
|
237
|
+
printWarning('That didn\'t match, so nothing was destroyed — you have to type the exact target id to confirm.');
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
else if (!destructive && !options.force && !(await confirm('\nProceed with teardown (stops the stack; on-disk data persists)?', options.yes))) {
|
|
242
|
+
printWarning('No problem — nothing was changed.');
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
printSection('Tearing down');
|
|
246
|
+
const { code: downCode } = await runScript(downCommand, cwd, { capture: false });
|
|
247
|
+
if (downCode !== 0) {
|
|
248
|
+
printError(`\nTeardown failed (exit ${downCode}). Inspect the stack/containers and retry.`);
|
|
249
|
+
process.exitCode = 1;
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
printSuccess('Teardown complete.');
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
const prereqs = checkPrereqs(target, { bootstrap: wantBootstrap });
|
|
256
|
+
const { command, missing } = assembleCommand(spec, params);
|
|
257
|
+
const url = deriveHealthUrl(target, params);
|
|
258
|
+
// Sparse bootstrap clone command (common base + target + selected loads).
|
|
259
|
+
const sparsePaths = sparsePathsFor(target, enabledLoadIds);
|
|
260
|
+
const bootstrap = resolveBootstrap({ repo: typeof options.repo === 'string' ? options.repo : undefined, ref: options.ref, workdir: options.workdir, full: !gitSupportsSparseCheckout() }, sparsePaths);
|
|
261
|
+
const bootstrapCmd = wantBootstrap ? bootstrapCommand(bootstrap) : null;
|
|
262
|
+
// Resolve post-install steps (register → smoke → events → custom).
|
|
263
|
+
const { steps: postSteps, skipped: skippedSteps } = resolvePostSteps({
|
|
264
|
+
target,
|
|
265
|
+
url,
|
|
266
|
+
region: typeof params.region === 'string' ? params.region : undefined,
|
|
267
|
+
enabledLoadIds,
|
|
268
|
+
...postStepFlags,
|
|
269
|
+
});
|
|
270
|
+
if (options.json) {
|
|
271
|
+
console.log(JSON.stringify({
|
|
272
|
+
success: true,
|
|
273
|
+
executionId,
|
|
274
|
+
target,
|
|
275
|
+
prereqs,
|
|
276
|
+
prereqsSatisfied: prereqsSatisfied(prereqs),
|
|
277
|
+
missingInputs: missing.map((m) => ({ flag: m.flag, description: m.description })),
|
|
278
|
+
bootstrap: bootstrapCmd,
|
|
279
|
+
sparsePaths: wantBootstrap ? sparsePaths : null,
|
|
280
|
+
command,
|
|
281
|
+
postSteps: postSteps.map((s) => ({ id: s.id, label: s.label, command: s.command })),
|
|
282
|
+
skippedPostSteps: skippedSteps,
|
|
283
|
+
}, null, 2));
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
// 5. Print the plan (shared by advisor + execute).
|
|
287
|
+
printSection(`Provision plan — ${spec.label}`);
|
|
288
|
+
printKeyValue({ 'Target': target, 'Best for': spec.bestFor, 'Cost': spec.cost });
|
|
289
|
+
printSection('Prerequisites');
|
|
290
|
+
for (const c of prereqs)
|
|
291
|
+
printInfo(`${c.ok ? '✓' : '✗'} ${c.name} — ${c.detail}`);
|
|
292
|
+
if (!prereqsSatisfied(prereqs))
|
|
293
|
+
printWarning('Resolve the failing prerequisites above before deploying.');
|
|
294
|
+
if (missing.length > 0) {
|
|
295
|
+
printSection('Missing required inputs');
|
|
296
|
+
for (const m of missing)
|
|
297
|
+
printInfo(` --${m.flag} (${m.description})`);
|
|
298
|
+
}
|
|
299
|
+
if (bootstrapCmd) {
|
|
300
|
+
printSection('Bootstrap (sparse git clone, runs first)');
|
|
301
|
+
printInfo(`Clone ${bootstrap.repo} @ ${bootstrap.ref} → ${bootstrap.workdir}; folders: ${sparsePaths.join(', ')}`);
|
|
302
|
+
printInfo(bootstrapCmd);
|
|
303
|
+
}
|
|
304
|
+
printSection('Command to run');
|
|
305
|
+
printInfo(command);
|
|
306
|
+
if (postSteps.length > 0 || skippedSteps.length > 0) {
|
|
307
|
+
printSection('Post-install steps');
|
|
308
|
+
for (const s of postSteps)
|
|
309
|
+
printInfo(`• ${s.label}\n ${s.command}`);
|
|
310
|
+
for (const s of skippedSteps)
|
|
311
|
+
printWarning(`skipped ${s.id}: ${s.reason}`);
|
|
312
|
+
}
|
|
313
|
+
// 6. Advisor mode (default) — stop here, nothing executed.
|
|
314
|
+
if (!options.execute) {
|
|
315
|
+
printWarning('\nAdvisor mode — nothing was executed. Re-run with --execute to deploy (gated by approval).');
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
// 7. Gated execution. Check prereqs / required inputs first — this also
|
|
319
|
+
// catches a missing `git` when bootstrapping.
|
|
320
|
+
const blocked = executionBlocked(prereqs, missing);
|
|
321
|
+
if (blocked) {
|
|
322
|
+
printError(`Can't start just yet — ${blocked}. Resolve that and re-run.`);
|
|
323
|
+
process.exitCode = 1;
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
// 7a. Sparse-clone the platform repo, repoint cwd, and verify the tree.
|
|
327
|
+
// Shared by `--repo` (below) and the interactive offer in 7b. Returns
|
|
328
|
+
// false (and sets exitCode) on failure — with a friendly message.
|
|
329
|
+
const bootstrapClone = async () => {
|
|
330
|
+
const cmd = bootstrapCommand(bootstrap);
|
|
331
|
+
printSection('Bootstrap');
|
|
332
|
+
printInfo(cmd);
|
|
333
|
+
const { code } = await runScript(cmd, cwd, { capture: false });
|
|
334
|
+
if (code !== 0) {
|
|
335
|
+
printError(`\nThe clone didn't finish (exit ${code}). Double-check the repo URL / ref (or your network) and give it another go.`);
|
|
336
|
+
process.exitCode = 1;
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
cwd = path.resolve(cwd, bootstrap.workdir);
|
|
340
|
+
printSuccess(`Repo is ready — continuing from ${cwd}`);
|
|
341
|
+
const absent = sparsePaths.filter((p) => !existsSync(path.join(cwd, p)));
|
|
342
|
+
if (absent.length > 0) {
|
|
343
|
+
printError(`\nThe sparse clone is missing ${absent.join(', ')} — that ref may not have those folders. Try a different --ref.`);
|
|
344
|
+
process.exitCode = 1;
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
return true;
|
|
348
|
+
};
|
|
349
|
+
// `--repo`: clone up front (must precede the entrypoint check).
|
|
350
|
+
if (bootstrapCmd) {
|
|
351
|
+
printInfo(`\nBootstrap → clone ${bootstrap.repo} @ ${bootstrap.ref} into ${bootstrap.workdir} (sparse).`);
|
|
352
|
+
if (!(await confirm('Go ahead with the clone?', options.yes))) {
|
|
353
|
+
printWarning('No problem — nothing was changed. Re-run whenever you\'re ready.');
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
if (!(await bootstrapClone()))
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
// 7b. The deploy entrypoint must exist relative to cwd. If it doesn't and
|
|
360
|
+
// we haven't bootstrapped, gracefully OFFER to clone (interactive only),
|
|
361
|
+
// so a fresh machine can proceed without re-running with --repo.
|
|
362
|
+
if (!entrypointExists(spec, cwd)) {
|
|
363
|
+
const interactive = Boolean(process.stdin.isTTY) && !options.yes;
|
|
364
|
+
if (!bootstrapCmd && interactive && gitAvailable()) {
|
|
365
|
+
printInfo(`\nLooks like you're not inside a pipeline-builder checkout, so the ${spec.label} deploy scripts aren't here yet.`);
|
|
366
|
+
if (await confirm(`Want me to sparse-clone them into ${bootstrap.workdir} and keep going?`, false)) {
|
|
367
|
+
if (!(await bootstrapClone()))
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (!entrypointExists(spec, cwd)) {
|
|
372
|
+
printWarning(`\nI couldn't find ${spec.dir}/${spec.entrypoint} from ${cwd}.`);
|
|
373
|
+
printInfo('Two easy ways forward:');
|
|
374
|
+
printInfo(' • cd into your pipeline-builder checkout and re-run, or');
|
|
375
|
+
printInfo(` • add --repo and I'll bootstrap a fresh sparse clone for you${gitAvailable() ? '.' : ' (once git is installed).'}`);
|
|
376
|
+
process.exitCode = 1;
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (!(await confirm('\nProceed with this deploy?', options.yes))) {
|
|
381
|
+
printWarning('Aborted — nothing was executed.');
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
// 7c. Run the deploy out-of-loop (real command, secrets unmasked, streamed +
|
|
385
|
+
// captured), with a bounded auto-fix + retry loop — the deploy scripts are
|
|
386
|
+
// idempotent, so a fixed re-run resumes rather than starting over.
|
|
387
|
+
const maxAttempts = 1 + Math.max(0, parseInt(options.retries, 10) || 0);
|
|
388
|
+
let runParams = params;
|
|
389
|
+
let succeeded = false;
|
|
390
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
391
|
+
const realCommand = assembleCommand(spec, runParams, { mask: false }).command;
|
|
392
|
+
printSection(attempt === 1 ? 'Deploying' : `Deploying — retry ${attempt - 1}`);
|
|
393
|
+
const { code, tail } = await runScript(realCommand, cwd, { capture: true });
|
|
394
|
+
if (code === 0) {
|
|
395
|
+
succeeded = true;
|
|
396
|
+
break;
|
|
397
|
+
}
|
|
398
|
+
printError(`\nDeploy failed (exit ${code}).`);
|
|
399
|
+
const issues = matchIssues(tail);
|
|
400
|
+
if (issues.length > 0) {
|
|
401
|
+
printSection('Likely cause');
|
|
402
|
+
for (const i of issues)
|
|
403
|
+
printInfo(`• ${i.cause}\n → ${i.suggestion}`);
|
|
404
|
+
}
|
|
405
|
+
if (isAiConfigured(aiOpts)) {
|
|
406
|
+
const diagnosis = await diagnoseFailure(redactSecrets(tail, spec, runParams), aiOpts);
|
|
407
|
+
if (diagnosis) {
|
|
408
|
+
printSection('Diagnosis');
|
|
409
|
+
printInfo(diagnosis);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (attempt >= maxAttempts)
|
|
413
|
+
break;
|
|
414
|
+
// Auto-fix: a retryable issue with a param we haven't already applied.
|
|
415
|
+
const fix = issues.find((i) => i.retryable && i.paramFix && runParams[i.paramFix.key] !== i.paramFix.value);
|
|
416
|
+
if (fix?.paramFix && await confirm(`\nApply fix and retry — ${fix.suggestion}`, options.yes)) {
|
|
417
|
+
runParams = { ...runParams, [fix.paramFix.key]: fix.paramFix.value };
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
// Retryable but no param change (e.g. ACM DNS propagation) — offer a plain re-run.
|
|
421
|
+
if (!fix && issues.some((i) => i.retryable) && await confirm('\nRetry the deploy (it is idempotent and will resume)?', options.yes)) {
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
break;
|
|
425
|
+
}
|
|
426
|
+
if (!succeeded) {
|
|
427
|
+
process.exitCode = 1;
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
printSuccess('Deploy command completed.');
|
|
431
|
+
// 7d. SES post-deploy guidance (async DKIM + sandbox + bounce topic).
|
|
432
|
+
// SES is provisioned BY DEFAULT on AWS deploys, so surface the guidance
|
|
433
|
+
// for ec2/fargate unless the operator opted out with --no-email.
|
|
434
|
+
const sesProvisioned = (target === 'ec2' || target === 'fargate') && runParams.noEmail !== true;
|
|
435
|
+
if (sesProvisioned) {
|
|
436
|
+
printSection('SES — next steps');
|
|
437
|
+
for (const line of sesPostDeployGuidance())
|
|
438
|
+
printInfo(`• ${line}`);
|
|
439
|
+
}
|
|
440
|
+
// 7e. Verify health (CREATE_COMPLETE != serving).
|
|
441
|
+
if (url) {
|
|
442
|
+
printSection('Verifying health');
|
|
443
|
+
printInfo(`Polling ${url}/health …`);
|
|
444
|
+
const health = await waitHealthy(url, { onTick: (m) => printInfo(m) });
|
|
445
|
+
(health.healthy ? printSuccess : printWarning)(`${health.url} — ${health.detail}`);
|
|
446
|
+
}
|
|
447
|
+
// 7f. Post-install steps (register + opt-in loads, smoke test, events, custom).
|
|
448
|
+
// register runs init-platform; for EC2/Fargate it must run from inside the
|
|
449
|
+
// VPC, so we surface the command there instead of executing it locally.
|
|
450
|
+
if (postSteps.length > 0) {
|
|
451
|
+
for (const s of skippedSteps)
|
|
452
|
+
printWarning(`Skipped post-step ${s.id}: ${s.reason}`);
|
|
453
|
+
const isRemoteRegister = (id) => id === 'register' && (target === 'ec2' || target === 'fargate');
|
|
454
|
+
const runnable = postSteps.filter((s) => !isRemoteRegister(s.id));
|
|
455
|
+
for (const s of postSteps) {
|
|
456
|
+
if (isRemoteRegister(s.id)) {
|
|
457
|
+
printInfo('\nNext (run from inside the VPC): register admin + load plugins —');
|
|
458
|
+
printInfo(` ${s.command}`);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
if (runnable.length > 0 && await confirm(`\nRun ${runnable.length} post-install step(s) now?`, options.yes)) {
|
|
462
|
+
for (const s of runnable) {
|
|
463
|
+
printSection(`Post-step: ${s.label}`);
|
|
464
|
+
printInfo(s.command);
|
|
465
|
+
const env = s.id === 'register' ? { ...s.env, ...adminEnv } : s.env;
|
|
466
|
+
const { code } = await runScript(s.command, cwd, { capture: false, env });
|
|
467
|
+
if (code !== 0) {
|
|
468
|
+
printError(`\nPost-step '${s.id}' failed (exit ${code}). The platform is deployed; fix and re-run the step manually.`);
|
|
469
|
+
process.exitCode = 1;
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
printSuccess(`${s.id} ✓`);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
else if (runnable.length > 0) {
|
|
476
|
+
printInfo('\nSkipped post-install steps. Run the commands above manually when ready.');
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
catch (error) {
|
|
481
|
+
handleError(error, ERROR_CODES.GENERAL, {
|
|
482
|
+
debug: program.opts().debug,
|
|
483
|
+
exit: true,
|
|
484
|
+
context: { command: 'provision', executionId },
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmlzaW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRzL3Byb3Zpc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQzlDLE9BQU8sS0FBSyxJQUFJLE1BQU0sV0FBVyxDQUFDO0FBQ2xDLE9BQU8sS0FBSyxRQUFRLE1BQU0sd0JBQXdCLENBQUM7QUFDbkQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNwQyxPQUFPLEVBQUUsZUFBZSxFQUFFLGNBQWMsRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM1RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUMzRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsZ0JBQWdCLEVBQUUsU0FBUyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDckYsT0FBTyxFQUFFLGVBQWUsRUFBRSxXQUFXLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNsRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSx5QkFBeUIsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzlHLE9BQU8sRUFDTCxlQUFlLEVBQ2YsVUFBVSxFQUNWLFVBQVUsRUFDVixjQUFjLEVBQ2QsT0FBTyxFQUNQLFVBQVUsRUFDVixlQUFlLEdBR2hCLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsT0FBTyxFQUFFLFdBQVcsRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzlFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQy9ELE9BQU8sRUFBRSxXQUFXLEVB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LENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO3dCQUNwRSxNQUFNLEVBQUUsSUFBSSxFQUFFLEdBQUcsTUFBTSxTQUFTLENBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxHQUFHLEVBQUUsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7d0JBQzFFLElBQUksSUFBSSxLQUFLLENBQUMsRUFBRSxDQUFDOzRCQUNmLFVBQVUsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLEVBQUUsa0JBQWtCLElBQUksZ0VBQWdFLENBQUMsQ0FBQzs0QkFDdkgsT0FBTyxDQUFDLFFBQVEsR0FBRyxDQUFDLENBQUM7NEJBQ3JCLE1BQU07d0JBQ1IsQ0FBQzt3QkFDRCxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztvQkFDNUIsQ0FBQztnQkFDSCxDQUFDO3FCQUFNLElBQUksUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztvQkFDL0IsU0FBUyxDQUFDLDJFQUEyRSxDQUFDLENBQUM7Z0JBQ3pGLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixXQUFXLENBQUMsS0FBSyxFQUFFLFdBQVcsQ0FBQyxPQUFPLEVBQUU7Z0JBQ3RDLEtBQUssRUFBRSxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUMsS0FBSztnQkFDM0IsSUFBSSxFQUFFLElBQUk7Z0JBQ1YsT0FBTyxFQUFFLEVBQUUsT0FBTyxFQUFFLFdBQVcsRUFBRSxXQUFXLEVBQUU7YUFDL0MsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztJQUNILENBQUMsQ0FBQyxDQUFDO0FBQ1AsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIGV4aXN0c1N5bmMgfSBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQgKiBhcyByZWFkbGluZSBmcm9tICdub2RlOnJlYWRsaW5lL3Byb21pc2VzJztcbmltcG9ydCB7IENvbW1hbmQgfSBmcm9tICdjb21tYW5kZXInO1xuaW1wb3J0IHsgZGlhZ25vc2VGYWlsdXJlLCBpc0FpQ29uZmlndXJlZCwgcGFyc2VHb2FsIH0gZnJvbSAnLi4vYWdlbnQvYWkuanMnO1xuaW1wb3J0IHsgYm9vdHN0cmFwQ29tbWFuZCwgcmVzb2x2ZUJvb3RzdHJhcCB9IGZyb20gJy4uL2FnZW50L2Jvb3RzdHJhcC5qcyc7XG5pbXBvcnQgeyBlbnRyeXBvaW50RXhpc3RzLCBleGVjdXRpb25CbG9ja2VkLCBydW5TY3JpcHQgfSBmcm9tICcuLi9hZ2VudC9leGVjdXRvci5qcyc7XG5pbXBvcnQgeyBkZXJpdmVIZWFsdGhVcmwsIHdhaXRIZWFsdGh5IH0gZnJvbSAnLi4vYWdlbnQvaGVhbHRoLmpzJztcbmltcG9ydCB7IHJlc29sdmVQb3N0U3RlcHMgfSBmcm9tICcuLi9hZ2VudC9wb3N0LXN0ZXBzLmpzJztcbmltcG9ydCB7IGNoZWNrUHJlcmVxcywgZ2l0QXZhaWxhYmxlLCBnaXRTdXBwb3J0c1NwYXJzZUNoZWNrb3V0LCBwcmVyZXFzU2F0aXNmaWVkIH0gZnJvbSAnLi4vYWdlbnQvcHJlcmVxcy5qcyc7XG5pbXBvcnQge1xuICBhc3NlbWJsZUNvbW1hbmQsXG4gIGlzVGFyZ2V0SWQsXG4gIExPQURfU1RFUFMsXG4gIHNwYXJzZVBhdGhzRm9yLFxuICBUQVJHRVRTLFxuICBUQVJHRVRfSURTLFxuICB0ZWFyZG93bkNvbW1hbmQsXG4gIHR5cGUgVGFyZ2V0SWQsXG4gIHR5cGUgVGFyZ2V0U3BlYyxcbn0gZnJvbSAnLi4vYWdlbnQvdGFyZ2V0cy5qcyc7XG5pbXBvcnQgeyBtYXRjaElzc3Vlcywgc2VzUG9zdERlcGxveUd1aWRhbmNlIH0gZnJvbSAnLi4vYWdlbnQvdHJvdWJsZXNob290LmpzJztcbmltcG9ydCB7IHByaW50Q29tbWFuZEhlYWRlciB9IGZyb20gJy4uL3V0aWxzL2NvbW1hbmQtdXRpbHMuanMnO1xuaW1wb3J0IHsgRVJST1JfQ09ERVMsIGhhbmRsZUVycm9yIH0gZnJvbSAnLi4vdXRpbHMvZXJyb3ItaGFuZGxlci5qcyc7XG5pbXBvcnQgeyBwcmludFNlY3Rpb24sIHByaW50S2V5VmFsdWUsIHByaW50SW5mbywgcHJpbnRXYXJuaW5nLCBwcmludEVycm9yLCBwcmludFN1Y2Nlc3MgfSBmcm9tICcuLi91dGlscy9vdXRwdXQtdXRpbHMuanMnO1xuXG4vKipcbiAqIFJlYWQgb25lIGxpbmUgb2YgdHJpbW1lZCBpbnB1dCBmcm9tIHRoZSB0ZXJtaW5hbCwgb3duaW5nIHRoZSByZWFkbGluZVxuICogbGlmZWN5Y2xlLiBVc2VkIGRpcmVjdGx5IGZvciB0aGUgZGVzdHJ1Y3RpdmUgdGVhcmRvd24gZ2F0ZSAoYSB5L04gaXMgdG9vIGVhc3lcbiAqIHRvIGZhdC1maW5nZXIsIHNvIHdlIHJlcXVpcmUgdGhlIG9wZXJhdG9yIHRvIFRZUEUgdGhlIHRhcmdldCBpZCBiYWNrKSwgYW5kIGFzXG4gKiB0aGUgYmFzaXMgZm9yIGBjb25maXJtYC4gRGVsaWJlcmF0ZWx5IGhhcyBubyBhdXRvLWFjY2VwdC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gYXNrKHF1ZXN0aW9uOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCBybCA9IHJlYWRsaW5lLmNyZWF0ZUludGVyZmFjZSh7IGlucHV0OiBwcm9jZXNzLnN0ZGluLCBvdXRwdXQ6IHByb2Nlc3Muc3Rkb3V0IH0pO1xuICB0cnkge1xuICAgIHJldHVybiAoYXdhaXQgcmwucXVlc3Rpb24ocXVlc3Rpb24pKS50cmltKCk7XG4gIH0gZmluYWxseSB7XG4gICAgcmwuY2xvc2UoKTtcbiAgfVxufVxuXG4vKiogSW50ZXJhY3RpdmUgeS9OIGNvbmZpcm1hdGlvbjsgYXV0by10cnVlIHdoZW4gYGF1dG9ZZXNgICh0aGUgYC0teWVzYCBmbGFnKS4gKi9cbmFzeW5jIGZ1bmN0aW9uIGNvbmZpcm0ocXVlc3Rpb246IHN0cmluZywgYXV0b1llczogYm9vbGVhbik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBpZiAoYXV0b1llcykgcmV0dXJuIHRydWU7XG4gIGNvbnN0IGFuc3dlciA9IChhd2FpdCBhc2soYCR7cXVlc3Rpb259IFt5L05dIGApKS50b0xvd2VyQ2FzZSgpO1xuICByZXR1cm4gYW5zd2VyID09PSAneScgfHwgYW5zd2VyID09PSAneWVzJztcbn1cblxuLyoqIENvbW1hbmRlciBjb2xsZWN0b3I6IGFjY3VtdWxhdGUgcmVwZWF0ZWQgYC0tcG9zdC1zdGVwYCB2YWx1ZXMgaW4gb3JkZXIuICovXG5mdW5jdGlvbiBjb2xsZWN0U3RlcCh2YWx1ZTogc3RyaW5nLCBhY2M6IHN0cmluZ1tdKTogc3RyaW5nW10ge1xuICByZXR1cm4gWy4uLmFjYywgdmFsdWVdO1xufVxuXG4vKipcbiAqIFJlZGFjdCBzZWNyZXQgcGFyYW0gdmFsdWVzIChlLmcuIHRoZSBnaGNyIHRva2VuKSBmcm9tIGNhcHR1cmVkIGRlcGxveSBvdXRwdXRcbiAqIGJlZm9yZSBpdCBpcyBzZW50IHRvIHRoZSBMTE0gZm9yIGRpYWdub3Npcy4gVGhlIGRlcGxveSBydW5zIHdpdGggc2VjcmV0c1xuICogdW5tYXNrZWQsIHNvIGFsdGhvdWdoIHRoZSBjdXJyZW50IHNjcmlwdHMgZG9uJ3QgZWNobyB0aGVtLCB0aGlzIGtlZXBzIGEgZnV0dXJlXG4gKiBzY3JpcHQncyBzdHJheSBlY2hvIChvciBhIHZlcmJvc2Ugc3ViLXRvb2wpIGZyb20gY3Jvc3NpbmcgdGhlIHRoaXJkLXBhcnR5LUxMTVxuICogYm91bmRhcnkuXG4gKi9cbmZ1bmN0aW9uIHJlZGFjdFNlY3JldHModGV4dDogc3RyaW5nLCBzcGVjOiBUYXJnZXRTcGVjLCBwYXJhbXM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogc3RyaW5nIHtcbiAgbGV0IG91dCA9IHRleHQ7XG4gIGZvciAoY29uc3QgaW5wdXQgb2YgWy4uLnNwZWMucmVxdWlyZWQsIC4uLnNwZWMub3B0aW9uYWxdKSB7XG4gICAgaWYgKCFpbnB1dC5zZWNyZXQpIGNvbnRpbnVlO1xuICAgIGNvbnN0IHZhbHVlID0gcGFyYW1zW2lucHV0LmtleV07XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUubGVuZ3RoID49IDQpIG91dCA9IG91dC5zcGxpdCh2YWx1ZSkuam9pbignKioqJyk7XG4gIH1cbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqXG4gKiBSZWdpc3RlcnMgdGhlIGBwcm92aXNpb25gIGNvbW1hbmQg4oCUIGFuIEFJLWFzc2lzdGVkIGluc3RhbGxlciBmb3IgdGhlIFBpcGVsaW5lXG4gKiBCdWlsZGVyIFBMQVRGT1JNIChsb2NhbC9taW5pa3ViZS9FQzIvRmFyZ2F0ZSkuIFBoYXNlIDEgaXMgUkVBRC1PTkxZIChwcmVyZXFcbiAqIGNoZWNrcywgTkwtZ29hbCBwYXJzaW5nLCBjb21tYW5kIGFzc2VtYmx5LCBmYWlsdXJlIGRpYWdub3Npcyk7IGAtLWV4ZWN1dGVgXG4gKiBnYXRlcyBhIHJlYWwgZGVwbG95LiBXaXRoIGAtLXJlcG9gIGl0IGNhbiBib290c3RyYXAgYSBmcmVzaCBtYWNoaW5lIGJ5IHNwYXJzZWx5XG4gKiBjbG9uaW5nIG9ubHkgdGhlIGRlcGxveSBmb2xkZXJzIHRoZSBzZWxlY3RlZCB0YXJnZXQgKyBvcHRpb25zIG5lZWQsIHRoZW4gcnVuc1xuICogcG9zdC1pbnN0YWxsIHN0ZXBzIChyZWdpc3RlciBhZG1pbiwgb3B0LWluIGxvYWRzLCBzbW9rZSB0ZXN0LCBjdXN0b20gY29tbWFuZHMpLlxuICpcbiAqIEBwYXJhbSBwcm9ncmFtIC0gVGhlIHJvb3QgQ29tbWFuZGVyIHByb2dyYW0gaW5zdGFuY2UgdG8gYXR0YWNoIHRoZSBjb21tYW5kIHRvLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJvdmlzaW9uKHByb2dyYW06IENvbW1hbmQpOiB2b2lkIHtcbiAgcHJvZ3JhbVxuICAgIC5jb21tYW5kKCdwcm92aXNpb24nKVxuICAgIC5kZXNjcmlwdGlvbignQUktYXNzaXN0ZWQgaW5zdGFsbGVyIGZvciB0aGUgcGxhdGZvcm0gKGxvY2FsL21pbmlrdWJlL0VDMi9GYXJnYXRlKTogYWR2aXNlLCAtLWV4ZWN1dGUgdG8gZGVwbG95LCBvciAtLXRlYXJkb3duIHRvIHJlbW92ZScpXG4gICAgLm9wdGlvbignLXQsIC0tdGFyZ2V0IDx0YXJnZXQ+JywgYERlcGxveSB0YXJnZXQ6ICR7VEFSR0VUX0lEUy5qb2luKCcgfCAnKX1gKVxuICAgIC5vcHRpb24oJy1wLCAtLXByb21wdCA8dGV4dD4nLCAnTmF0dXJhbC1sYW5ndWFnZSBnb2FsIChwYXJzZWQgaW50byBwYXJhbXMgd2hlbiBhbiBBSSBrZXkgaXMgc2V0KScpXG4gICAgLm9wdGlvbignLS1yZWdpb24gPHJlZ2lvbj4nLCAnQVdTIHJlZ2lvbiAoRUMyL0ZhcmdhdGUpJylcbiAgICAub3B0aW9uKCctLWRvbWFpbiA8ZG9tYWluPicsICdGdWxseS1xdWFsaWZpZWQgZG9tYWluIG5hbWUgKEVDMi9GYXJnYXRlKScpXG4gICAgLm9wdGlvbignLS1ob3N0ZWQtem9uZS1pZCA8aWQ+JywgJ1B1YmxpYyBSb3V0ZSA1MyBob3N0ZWQgem9uZSBJRCAoRUMyL0ZhcmdhdGUpJylcbiAgICAub3B0aW9uKCctLWRlcGxveS1tb2RlIDxtb2RlPicsICdwdWJsaWMgfCBwcml2YXRlIChFQzIvRmFyZ2F0ZSknKVxuICAgIC5vcHRpb24oJy0ta2V5LXBhaXIgPG5hbWU+JywgJ0VDMiBrZXkgcGFpciAoRUMyKScpXG4gICAgLm9wdGlvbignLS1pbnN0YW5jZS10eXBlIDx0eXBlPicsICdFQzIgaW5zdGFuY2UgdHlwZSAoRUMyKScpXG4gICAgLm9wdGlvbignLS1naGNyLXRva2VuIDx0b2tlbj4nLCAnR2l0SHViIFBBVCAocmVhZDpwYWNrYWdlcykg4oCUIG1hc2tlZCBpbiBvdXRwdXQnKVxuICAgIC5vcHRpb24oJy0tZW1haWwnLCAnRW5hYmxlIFNFUyB0cmFuc2FjdGlvbmFsIGVtYWlsIChvbiBieSBkZWZhdWx0IGZvciBBV1MpJylcbiAgICAub3B0aW9uKCctLW5vLWVtYWlsJywgJ1NraXAgU0VTICh0cmFuc2FjdGlvbmFsIGVtYWlsIGlzIHByb3Zpc2lvbmVkIGJ5IGRlZmF1bHQgb24gQVdTKScpXG4gICAgLm9wdGlvbignLS1lbWFpbC1mcm9tIDxhZGRyPicsICdTRVMgRnJvbSBhZGRyZXNzJylcbiAgICAub3B0aW9uKCctLWVtYWlsLWZyb20tbmFtZSA8bmFtZT4nLCAnU0VTIEZyb20gZGlzcGxheSBuYW1lJylcbiAgICAub3B0aW9uKCctLWFsZXJ0LWVtYWlsIDxhZGRyPicsICdTdWJzY3JpYmUgYW4gYWRkcmVzcyB0byB0aGUgYm91bmNlL2NvbXBsYWludCBTTlMgdG9waWMnKVxuICAgIC5vcHRpb24oJy0tc2tpcC1zZXMtaWRlbnRpdHknLCAnU2tpcCBTRVMgaWRlbnRpdHkgY3JlYXRpb24gKGRvbWFpbiBhbHJlYWR5IHZlcmlmaWVkKScpXG4gICAgLm9wdGlvbignLS1haS1wcm92aWRlciA8cHJvdmlkZXI+JywgJ0FJIHByb3ZpZGVyIChhbnRocm9waWN8b3BlbmFpfGdvb2dsZXx4YWl8YmVkcm9jayknKVxuICAgIC5vcHRpb24oJy0tbW9kZWwgPG1vZGVsPicsICdBSSBtb2RlbCBpZCcpXG4gICAgLm9wdGlvbignLS1kaWFnbm9zZSA8ZmlsZT4nLCAnRGlhZ25vc2UgYSBDbG91ZEZvcm1hdGlvbi9kZXBsb3kgZmFpbHVyZSBmcm9tIGEgZmlsZSAobmVlZHMgYW4gQUkga2V5KScpXG4gICAgLm9wdGlvbignLXksIC0teWVzJywgJ0F1dG8tYWNjZXB0IHRoZSBleGVjdXRpb24gYXBwcm92YWwgcHJvbXB0IChmb3IgQ0kgLyBub24taW50ZXJhY3RpdmUpJywgZmFsc2UpXG4gICAgLm9wdGlvbignLS1leGVjdXRlJywgJ1J1biB0aGUgZGVwbG95IChnYXRlZDogbmVlZHMgYXBwcm92YWwsIHJlZnVzZXMgb24gZmFpbGVkIHByZXJlcXMgLyBtaXNzaW5nIGlucHV0cyknLCBmYWxzZSlcbiAgICAub3B0aW9uKCctLXJldHJpZXMgPG4+JywgJ0F1dG8tZml4ICsgcmV0cnkgYXR0ZW1wdHMgYWZ0ZXIgYSBmYWlsdXJlIChkZXBsb3kgc2NyaXB0cyBhcmUgaWRlbXBvdGVudCknLCAnMScpXG4gICAgLm9wdGlvbignLS10ZWFyZG93bicsICdUZWFyIGRvd24gYW4gZXhpc3RpbmcgZGVwbG95bWVudCBpbnN0ZWFkIG9mIGNyZWF0aW5nIG9uZSAoZ2F0ZWQ7IEFXUyB0YXJnZXRzIHJlcXVpcmUgYSB0eXBlZCBjb25maXJtYXRpb24pJywgZmFsc2UpXG4gICAgLm9wdGlvbignLS1zdGFjay1uYW1lIDxuYW1lPicsICdTdGFjayBuYW1lIChFQzIpIC8gc3RhY2sgcHJlZml4IChGYXJnYXRlKSB0byB0ZWFyIGRvd24g4oCUIGRlZmF1bHRzIHRvIHRoZSBkZXBsb3kgZGVmYXVsdCcpXG4gICAgLm9wdGlvbignLS1mb3JjZScsICdTa2lwIHRoZSB0ZWFyZG93biB0eXBlZC1jb25maXJtYXRpb24gKERBTkdFUk9VUyDigJQgZm9yIENJL2F1dG9tYXRpb24gb25seSknLCBmYWxzZSlcbiAgICAub3B0aW9uKCctLW5vLWluaXQnLCAnU2tpcCB0aGUgcG9zdC1kZXBsb3kgcmVnaXN0ZXIvaW5pdC1wbGF0Zm9ybSBzdGVwJylcbiAgICAvLyBCb290c3RyYXAgKHNwYXJzZSBjbG9uZSkg4oCUIHByb3Zpc2lvbiBhIGZyZXNoIG1hY2hpbmUgaW4gb25lIGNvbW1hbmQuXG4gICAgLm9wdGlvbignLS1yZXBvIFt1cmxdJywgJ0Jvb3RzdHJhcDogZ2l0LWNsb25lIHRoZSBwbGF0Zm9ybSByZXBvIGZpcnN0IChzcGFyc2Ug4oCUIG9ubHkgdGhlIG5lZWRlZCBkZXBsb3kgZm9sZGVycyksIHRoZW4gcnVuIGZyb20gaXQgKG5vIHZhbHVlID0gdGhlIHVwc3RyZWFtIGRlZmF1bHQpJylcbiAgICAub3B0aW9uKCctLXJlZiA8cmVmPicsICdHaXQgYnJhbmNoL3RhZyB0byBjaGVjayBvdXQgd2hlbiBib290c3RyYXBwaW5nIChkZWZhdWx0OiBtYWluKScpXG4gICAgLm9wdGlvbignLS13b3JrZGlyIDxkaXI+JywgJ0RpcmVjdG9yeSB0byBjbG9uZSBpbnRvIC8gcnVuIGZyb20gd2hlbiBib290c3RyYXBwaW5nIChkZWZhdWx0OiBwaXBlbGluZS1idWlsZGVyKScpXG4gICAgLy8gUG9zdC1pbnN0YWxsIGxvYWRzIOKAlCBlYWNoIG9wdC1pbiBzdGVwIGFsc28gYWRkcyBpdHMgZGVwbG95IGZvbGRlciB0byB0aGUgc3BhcnNlIGNsb25lLlxuICAgIC5vcHRpb24oJy0td2l0aC1wbHVnaW5zJywgJ1Bvc3QtaW5zdGFsbDogYnVpbGQgKyBsb2FkIHBsdWdpbnMgKGFkZHMgZGVwbG95L3BsdWdpbnMsIGRlcGxveS9jb2RlYnVpbGQpJywgZmFsc2UpXG4gICAgLm9wdGlvbignLS13aXRoLWNvbXBsaWFuY2UnLCAnUG9zdC1pbnN0YWxsOiBsb2FkIHNhbXBsZSBjb21wbGlhbmNlIHJ1bGVzL3BvbGljaWVzIChhZGRzIGRlcGxveS9jb21wbGlhbmNlKScsIGZhbHNlKVxuICAgIC5vcHRpb24oJy0td2l0aC1zYW1wbGVzJywgJ1Bvc3QtaW5zdGFsbDogbG9hZCBzYW1wbGUgcGlwZWxpbmVzIChhZGRzIGRlcGxveS9zYW1wbGVzKScsIGZhbHNlKVxuICAgIC5vcHRpb24oJy0td2l0aC1hbGwnLCAnUG9zdC1pbnN0YWxsOiBwbHVnaW5zICsgY29tcGxpYW5jZSArIHNhbXBsZXMnLCBmYWxzZSlcbiAgICAub3B0aW9uKCctLWJ1aWxkLWJvb3RzdHJhcCcsICdCdWlsZCArIHB1Ymxpc2ggdGhlIENvZGVCdWlsZCBib290c3RyYXAgaW1hZ2UgZHVyaW5nIHJlZ2lzdGVyIChhZGRzIGRlcGxveS9jb2RlYnVpbGQpJywgZmFsc2UpXG4gICAgLm9wdGlvbignLS13aXRoLXNtb2tlLXRlc3QnLCAnUG9zdC1pbnN0YWxsOiByZWFkLW9ubHkgQVBJIHJlYWNoYWJpbGl0eSBjaGVjaycsIGZhbHNlKVxuICAgIC5vcHRpb24oJy0td2l0aC1ldmVudHMnLCAnUG9zdC1pbnN0YWxsOiBFdmVudEJyaWRnZSBpbmdlc3Rpb24gdmlhIHNldHVwLWV2ZW50cyAoQVdTIHRhcmdldHMpJywgZmFsc2UpXG4gICAgLm9wdGlvbignLS1wb3N0LXN0ZXAgPGNtZD4nLCAnUnVuIGFuIGV4dHJhIGNvbW1hbmQgYWZ0ZXIgdGhlIGxvYWRzIChyZXBlYXRhYmxlLCBpbiBvcmRlciknLCBjb2xsZWN0U3RlcCwgW10pXG4gICAgLm9wdGlvbignLS1hZG1pbi1lbWFpbCA8YWRkcj4nLCAnQWRtaW4gZW1haWwgZm9yIG5vbi1pbnRlcmFjdGl2ZSByZWdpc3RlciAoc2V0cyBQTEFURk9STV9JREVOVElGSUVSKScpXG4gICAgLm9wdGlvbignLS1hZG1pbi1wYXNzd29yZCA8cHc+JywgJ0FkbWluIHBhc3N3b3JkIGZvciBub24taW50ZXJhY3RpdmUgcmVnaXN0ZXIgKHNldHMgUExBVEZPUk1fUEFTU1dPUkQpJylcbiAgICAub3B0aW9uKCctLWpzb24nLCAnT3V0cHV0IHRoZSBwbGFuIGFzIEpTT04gKG5ldmVyIGV4ZWN1dGVzKScsIGZhbHNlKVxuICAgIC5hY3Rpb24oYXN5bmMgKG9wdGlvbnMpID0+IHtcbiAgICAgIGNvbnN0IGV4ZWN1dGlvbklkID0gcHJpbnRDb21tYW5kSGVhZGVyKCdQcm92aXNpb24gKGFkdmlzb3IpJyk7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIDEuIEFzc2VtYmxlIHBhcmFtcyBmcm9tIGV4cGxpY2l0IGZsYWdzIChmbGFncyBhbHdheXMgd2luIG92ZXIgTkwgcGFyc2UpLlxuICAgICAgICBjb25zdCBwYXJhbXM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge1xuICAgICAgICAgIHJlZ2lvbjogb3B0aW9ucy5yZWdpb24sXG4gICAgICAgICAgZG9tYWluOiBvcHRpb25zLmRvbWFpbixcbiAgICAgICAgICBob3N0ZWRab25lSWQ6IG9wdGlvbnMuaG9zdGVkWm9uZUlkLFxuICAgICAgICAgIGRlcGxveU1vZGU6IG9wdGlvbnMuZGVwbG95TW9kZSxcbiAgICAgICAgICBrZXlQYWlyOiBvcHRpb25zLmtleVBhaXIsXG4gICAgICAgICAgaW5zdGFuY2VUeXBlOiBvcHRpb25zLmluc3RhbmNlVHlwZSxcbiAgICAgICAgICBnaGNyVG9rZW46IG9wdGlvbnMuZ2hjclRva2VuLFxuICAgICAgICAgIC8vIENvbW1hbmRlciB0cmktc3RhdGVzIGBlbWFpbGA6IHVuZGVmaW5lZCAobmVpdGhlciksIHRydWUgKC0tZW1haWwpLFxuICAgICAgICAgIC8vIGZhbHNlICgtLW5vLWVtYWlsKS4gU0VTIGlzIG9uIGJ5IGRlZmF1bHQsIHNvIG9ubHkgLS1uby1lbWFpbCBpc1xuICAgICAgICAgIC8vIGxvYWQtYmVhcmluZyAoaXQgZW1pdHMgYC0tbm8tZW1haWxgIGludG8gdGhlIGRlcGxveSBjb21tYW5kKS5cbiAgICAgICAgICBlbWFpbDogb3B0aW9ucy5lbWFpbCA9PT0gdHJ1ZSxcbiAgICAgICAgICBub0VtYWlsOiBvcHRpb25zLmVtYWlsID09PSBmYWxzZSxcbiAgICAgICAgICBlbWFpbEZyb206IG9wdGlvbnMuZW1haWxGcm9tLFxuICAgICAgICAgIGVtYWlsRnJvbU5hbWU6IG9wdGlvbnMuZW1haWxGcm9tTmFtZSxcbiAgICAgICAgICBhbGVydEVtYWlsOiBvcHRpb25zLmFsZXJ0RW1haWwsXG4gICAgICAgICAgbm9DcmVhdGVTZXNJZGVudGl0eTogb3B0aW9ucy5za2lwU2VzSWRlbnRpdHksXG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IGFpT3B0cyA9IHsgcHJvdmlkZXI6IG9wdGlvbnMuYWlQcm92aWRlciwgbW9kZWw6IG9wdGlvbnMubW9kZWwgfTtcblxuICAgICAgICAvLyBCb290c3RyYXAgKHNwYXJzZSBjbG9uZSkgKyBwb3N0LWluc3RhbGwgc2VsZWN0aW9ucy5cbiAgICAgICAgY29uc3Qgd2FudEJvb3RzdHJhcCA9IG9wdGlvbnMucmVwbyAhPT0gdW5kZWZpbmVkICYmIG9wdGlvbnMucmVwbyAhPT0gZmFsc2U7XG4gICAgICAgIGNvbnN0IHdpdGhBbGwgPSBvcHRpb25zLndpdGhBbGwgPT09IHRydWU7XG4gICAgICAgIGNvbnN0IGVuYWJsZWRMb2FkSWRzID0gTE9BRF9TVEVQUy5maWx0ZXIoKHMpID0+IHdpdGhBbGwgfHwgb3B0aW9uc1tzLmZsYWddID09PSB0cnVlKS5tYXAoKHMpID0+IHMuaWQpO1xuICAgICAgICBjb25zdCBwb3N0U3RlcEZsYWdzID0ge1xuICAgICAgICAgIGluaXQ6IG9wdGlvbnMuaW5pdCAhPT0gZmFsc2UsXG4gICAgICAgICAgYnVpbGRCb290c3RyYXA6IG9wdGlvbnMuYnVpbGRCb290c3RyYXAgPT09IHRydWUgfHwgZW5hYmxlZExvYWRJZHMuaW5jbHVkZXMoJ3BsdWdpbnMnKSxcbiAgICAgICAgICBzbW9rZVRlc3Q6IG9wdGlvbnMud2l0aFNtb2tlVGVzdCA9PT0gdHJ1ZSxcbiAgICAgICAgICBldmVudHM6IG9wdGlvbnMud2l0aEV2ZW50cyA9PT0gdHJ1ZSxcbiAgICAgICAgICBzdGVwczogKG9wdGlvbnMucG9zdFN0ZXAgPz8gW10pIGFzIHN0cmluZ1tdLFxuICAgICAgICB9O1xuICAgICAgICAvLyBBZG1pbiBjcmVkZW50aWFscyBmb3J3YXJkZWQgYXMgZW52IHNvIHJlZ2lzdGVyIHJ1bnMgbm9uLWludGVyYWN0aXZlbHkuXG4gICAgICAgIGNvbnN0IGFkbWluRW52OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG4gICAgICAgIGlmICh0eXBlb2Ygb3B0aW9ucy5hZG1pbkVtYWlsID09PSAnc3RyaW5nJykgYWRtaW5FbnYuUExBVEZPUk1fSURFTlRJRklFUiA9IG9wdGlvbnMuYWRtaW5FbWFpbDtcbiAgICAgICAgaWYgKHR5cGVvZiBvcHRpb25zLmFkbWluUGFzc3dvcmQgPT09ICdzdHJpbmcnKSBhZG1pbkVudi5QTEFURk9STV9QQVNTV09SRCA9IG9wdGlvbnMuYWRtaW5QYXNzd29yZDtcblxuICAgICAgICAvLyAyLiBPcHRpb25hbGx5IHBhcnNlIGEgbmF0dXJhbC1sYW5ndWFnZSBnb2FsIHRvIGZpbGwgYW55IEdBUFMgKGJlc3QtZWZmb3J0KS5cbiAgICAgICAgbGV0IHRhcmdldDogVGFyZ2V0SWQgfCB1bmRlZmluZWQgPSBpc1RhcmdldElkKG9wdGlvbnMudGFyZ2V0KSA/IG9wdGlvbnMudGFyZ2V0IDogdW5kZWZpbmVkO1xuICAgICAgICBpZiAob3B0aW9ucy5wcm9tcHQpIHtcbiAgICAgICAgICBpZiAoaXNBaUNvbmZpZ3VyZWQoYWlPcHRzKSkge1xuICAgICAgICAgICAgY29uc3QgcGFyc2VkID0gYXdhaXQgcGFyc2VHb2FsKG9wdGlvbnMucHJvbXB0LCBhaU9wdHMpO1xuICAgICAgICAgICAgaWYgKHBhcnNlZCkge1xuICAgICAgICAgICAgICBpZiAoIXRhcmdldCAmJiBpc1RhcmdldElkKHBhcnNlZC50YXJnZXQpKSB0YXJnZXQgPSBwYXJzZWQudGFyZ2V0O1xuICAgICAgICAgICAgICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyhwYXJzZWQpKSB7XG4gICAgICAgICAgICAgICAgaWYgKGsgIT09ICd0YXJnZXQnICYmIHBhcmFtc1trXSA9PT0gdW5kZWZpbmVkICYmIHYgIT09IHVuZGVmaW5lZCkgcGFyYW1zW2tdID0gdjtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwcmludFdhcm5pbmcoJ0EgLS1wcm9tcHQgd2FzIGdpdmVuIGJ1dCBubyBBSSBrZXkgaXMgc2V0IOKAlCBpZ25vcmluZyBpdCBhbmQgdXNpbmcgZmxhZ3Mgb25seS4gU2V0IEFOVEhST1BJQ19BUElfS0VZIChvciAtLWFpLXByb3ZpZGVyICsgaXRzIGtleSkuJyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gMy4gT3B0aW9uYWwgZmFpbHVyZSBkaWFnbm9zaXMgKGluZGVwZW5kZW50IG9mIGEgZGVwbG95IHBsYW4pLlxuICAgICAgICBpZiAob3B0aW9ucy5kaWFnbm9zZSkge1xuICAgICAgICAgIGxldCBmYWlsdXJlVGV4dDogc3RyaW5nO1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBmYWlsdXJlVGV4dCA9IHJlYWRGaWxlU3luYyhvcHRpb25zLmRpYWdub3NlLCAndXRmLTgnKTtcbiAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgIHByaW50RXJyb3IoYENhbm5vdCByZWFkIC0tZGlhZ25vc2UgZmlsZTogJHtvcHRpb25zLmRpYWdub3NlfWApO1xuICAgICAgICAgICAgcHJvY2Vzcy5leGl0Q29kZSA9IDE7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IGRpYWdub3NpcyA9IGlzQWlDb25maWd1cmVkKGFpT3B0cykgPyBhd2FpdCBkaWFnbm9zZUZhaWx1cmUoZmFpbHVyZVRleHQsIGFpT3B0cykgOiBudWxsO1xuICAgICAgICAgIC8vIFdpdGggLS1qc29uLCB0aGUgZGlhZ25vc2lzIElTIHRoZSBtYWNoaW5lLXJlYWRhYmxlIG91dHB1dCDigJQgZW1pdCBpdFxuICAgICAgICAgIC8vIGFsb25lIChkb24ndCBhbHNvIHByaW50IHRleHQsIHdoaWNoIHdvdWxkIGNvcnJ1cHQgdGhlIEpTT04gc3RyZWFtKS5cbiAgICAgICAgICBpZiAob3B0aW9ucy5qc29uKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhKU09OLnN0cmluZ2lmeSh7IHN1Y2Nlc3M6IHRydWUsIGV4ZWN1dGlvbklkLCBkaWFnbm9zaXMgfSwgbnVsbCwgMikpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoZGlhZ25vc2lzKSB7XG4gICAgICAgICAgICBwcmludFNlY3Rpb24oJ0ZhaWx1cmUgZGlhZ25vc2lzJyk7XG4gICAgICAgICAgICBwcmludEluZm8oZGlhZ25vc2lzKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcHJpbnRXYXJuaW5nKCdEaWFnbm9zaXMgdW5hdmFpbGFibGUgKG5vIEFJIGtleSBjb25maWd1cmVkIG9yIHRoZSBtb2RlbCBjb3VsZCBub3QgYmUgcmVhY2hlZCkuJyk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmICghdGFyZ2V0KSByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyA0LiBOZWVkIGEgdGFyZ2V0IHRvIGFzc2VtYmxlIGEgcGxhbi5cbiAgICAgICAgaWYgKCF0YXJnZXQpIHtcbiAgICAgICAgICBwcmludEVycm9yKGBObyB0YXJnZXQgc3BlY2lmaWVkLiBQYXNzIC0tdGFyZ2V0IDwke1RBUkdFVF9JRFMuam9pbignfCcpfT4gb3IgZGVzY3JpYmUgdGhlIGdvYWwgd2l0aCAtLXByb21wdC5gKTtcbiAgICAgICAgICBwcm9jZXNzLmV4aXRDb2RlID0gMTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzcGVjID0gVEFSR0VUU1t0YXJnZXRdO1xuICAgICAgICBsZXQgY3dkID0gcHJvY2Vzcy5jd2QoKTtcblxuICAgICAgICAvLyA0Yi4gVGVhcmRvd24gbW9kZSDigJQgdGhlIGRlc3Ryb3kgY291bnRlcnBhcnQgb2YgcHJvdmlzaW9uaW5nLiBHYXRlZCBoYXJkZXJcbiAgICAgICAgLy8gdGhhbiBkZXBsb3k6IEFXUyB0YXJnZXRzIGFyZSBpcnJldmVyc2libGUsIHNvIHdlIHJlcXVpcmUgdGhlIG9wZXJhdG9yIHRvXG4gICAgICAgIC8vIFRZUEUgdGhlIHRhcmdldCBpZCAoLS1mb3JjZSBieXBhc3NlcyBmb3IgQ0k7IC0teWVzIGFsb25lIGRvZXMgTk9UKS5cbiAgICAgICAgaWYgKG9wdGlvbnMudGVhcmRvd24pIHtcbiAgICAgICAgICBjb25zdCB7IGNvbW1hbmQ6IGRvd25Db21tYW5kLCBkZXN0cnVjdGl2ZSB9ID0gdGVhcmRvd25Db21tYW5kKHRhcmdldCwge1xuICAgICAgICAgICAgc3RhY2tOYW1lOiBvcHRpb25zLnN0YWNrTmFtZSxcbiAgICAgICAgICAgIHJlZ2lvbjogb3B0aW9ucy5yZWdpb24sXG4gICAgICAgICAgICAvLyBPdXIgdHlwZWQgZ2F0ZSBJUyB0aGUgY29uZmlybWF0aW9uIOKAlCBmb3J3YXJkIC0teWVzIHNvIHRoZSBuYXRpdmVcbiAgICAgICAgICAgIC8vIHNjcmlwdCAoRmFyZ2F0ZSkgZG9lc24ndCBhbHNvIGJsb2NrIG9uIHN0ZGluIHdlJ3JlIGluaGVyaXRpbmcuXG4gICAgICAgICAgICBhc3N1bWVZZXM6IHRydWUsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBpZiAob3B0aW9ucy5qc29uKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhKU09OLnN0cmluZ2lmeSh7IHN1Y2Nlc3M6IHRydWUsIGV4ZWN1dGlvbklkLCB0YXJnZXQsIHRlYXJkb3duOiB0cnVlLCBkZXN0cnVjdGl2ZSwgZGVzdHJveXM6IHNwZWMuZGVzdHJveXMsIGNvbW1hbmQ6IGRvd25Db21tYW5kIH0sIG51bGwsIDIpKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBwcmludFNlY3Rpb24oYFRlYXJkb3duIHBsYW4g4oCUICR7c3BlYy5sYWJlbH1gKTtcbiAgICAgICAgICBwcmludEtleVZhbHVlKHsgJ1RhcmdldCc6IHRhcmdldCwgJ0Rlc3Ryb3lzJzogc3BlYy5kZXN0cm95cywgJ1N0b3BzIGNvc3QnOiBzcGVjLmNvc3QgfSk7XG4gICAgICAgICAgcHJpbnRTZWN0aW9uKCdDb21tYW5kIHRvIHJ1bicpO1xuICAgICAgICAgIHByaW50SW5mbyhkb3duQ29tbWFuZCk7XG5cbiAgICAgICAgICBpZiAoIW9wdGlvbnMuZXhlY3V0ZSkge1xuICAgICAgICAgICAgcHJpbnRXYXJuaW5nKCdcXG5BZHZpc29yIG1vZGUg4oCUIG5vdGhpbmcgd2FzIGV4ZWN1dGVkLiBSZS1ydW4gd2l0aCAtLWV4ZWN1dGUgdG8gdGVhciBkb3duLicpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChkZXN0cnVjdGl2ZSAmJiAhb3B0aW9ucy5mb3JjZSkge1xuICAgICAgICAgICAgY29uc3QgdG9rZW4gPSBhd2FpdCBhc2soYFxcblRoaXMgaXMgSVJSRVZFUlNJQkxFLiBUeXBlIFwiJHt0YXJnZXR9XCIgdG8gY29uZmlybSB0ZWFyZG93bjogYCk7XG4gICAgICAgICAgICBpZiAodG9rZW4gIT09IHRhcmdldCkge1xuICAgICAgICAgICAgICBwcmludFdhcm5pbmcoJ1RoYXQgZGlkblxcJ3QgbWF0Y2gsIHNvIG5vdGhpbmcgd2FzIGRlc3Ryb3llZCDigJQgeW91IGhhdmUgdG8gdHlwZSB0aGUgZXhhY3QgdGFyZ2V0IGlkIHRvIGNvbmZpcm0uJyk7XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2UgaWYgKCFkZXN0cnVjdGl2ZSAmJiAhb3B0aW9ucy5mb3JjZSAmJiAhKGF3YWl0IGNvbmZpcm0oJ1xcblByb2NlZWQgd2l0aCB0ZWFyZG93biAoc3RvcHMgdGhlIHN0YWNrOyBvbi1kaXNrIGRhdGEgcGVyc2lzdHMpPycsIG9wdGlvbnMueWVzKSkpIHtcbiAgICAgICAgICAgIHByaW50V2FybmluZygnTm8gcHJvYmxlbSDigJQgbm90aGluZyB3YXMgY2hhbmdlZC4nKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBwcmludFNlY3Rpb24oJ1RlYXJpbmcgZG93bicpO1xuICAgICAgICAgIGNvbnN0IHsgY29kZTogZG93bkNvZGUgfSA9IGF3YWl0IHJ1blNjcmlwdChkb3duQ29tbWFuZCwgY3dkLCB7IGNhcHR1cmU6IGZhbHNlIH0pO1xuICAgICAgICAgIGlmIChkb3duQ29kZSAhPT0gMCkge1xuICAgICAgICAgICAgcHJpbnRFcnJvcihgXFxuVGVhcmRvd24gZmFpbGVkIChleGl0ICR7ZG93bkNvZGV9KS4gSW5zcGVjdCB0aGUgc3RhY2svY29udGFpbmVycyBhbmQgcmV0cnkuYCk7XG4gICAgICAgICAgICBwcm9jZXNzLmV4aXRDb2RlID0gMTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgICAgcHJpbnRTdWNjZXNzKCdUZWFyZG93biBjb21wbGV0ZS4nKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBwcmVyZXFzID0gY2hlY2tQcmVyZXFzKHRhcmdldCwgeyBib290c3RyYXA6IHdhbnRCb290c3RyYXAgfSk7XG4gICAgICAgIGNvbnN0IHsgY29tbWFuZCwgbWlzc2luZyB9ID0gYXNzZW1ibGVDb21tYW5kKHNwZWMsIHBhcmFtcyk7XG4gICAgICAgIGNvbnN0IHVybCA9IGRlcml2ZUhlYWx0aFVybCh0YXJnZXQsIHBhcmFtcyk7XG5cbiAgICAgICAgLy8gU3BhcnNlIGJvb3RzdHJhcCBjbG9uZSBjb21tYW5kIChjb21tb24gYmFzZSArIHRhcmdldCArIHNlbGVjdGVkIGxvYWRzKS5cbiAgICAgICAgY29uc3Qgc3BhcnNlUGF0aHMgPSBzcGFyc2VQYXRoc0Zvcih0YXJnZXQsIGVuYWJsZWRMb2FkSWRzKTtcbiAgICAgICAgY29uc3QgYm9vdHN0cmFwID0gcmVzb2x2ZUJvb3RzdHJhcChcbiAgICAgICAgICB7IHJlcG86IHR5cGVvZiBvcHRpb25zLnJlcG8gPT09ICdzdHJpbmcnID8gb3B0aW9ucy5yZXBvIDogdW5kZWZpbmVkLCByZWY6IG9wdGlvbnMucmVmLCB3b3JrZGlyOiBvcHRpb25zLndvcmtkaXIsIGZ1bGw6ICFnaXRTdXBwb3J0c1NwYXJzZUNoZWNrb3V0KCkgfSxcbiAgICAgICAgICBzcGFyc2VQYXRocyxcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgYm9vdHN0cmFwQ21kID0gd2FudEJvb3RzdHJhcCA/IGJvb3RzdHJhcENvbW1hbmQoYm9vdHN0cmFwKSA6IG51bGw7XG5cbiAgICAgICAgLy8gUmVzb2x2ZSBwb3N0LWluc3RhbGwgc3RlcHMgKHJlZ2lzdGVyIOKGkiBzbW9rZSDihpIgZXZlbnRzIOKGkiBjdXN0b20pLlxuICAgICAgICBjb25zdCB7IHN0ZXBzOiBwb3N0U3RlcHMsIHNraXBwZWQ6IHNraXBwZWRTdGVwcyB9ID0gcmVzb2x2ZVBvc3RTdGVwcyh7XG4gICAgICAgICAgdGFyZ2V0LFxuICAgICAgICAgIHVybCxcbiAgICAgICAgICByZWdpb246IHR5cGVvZiBwYXJhbXMucmVnaW9uID09PSAnc3RyaW5nJyA/IHBhcmFtcy5yZWdpb24gOiB1bmRlZmluZWQsXG4gICAgICAgICAgZW5hYmxlZExvYWRJZHMsXG4gICAgICAgICAgLi4ucG9zdFN0ZXBGbGFncyxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKG9wdGlvbnMuanNvbikge1xuICAgICAgICAgIGNvbnNvbGUubG9nKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICBleGVjdXRpb25JZCxcbiAgICAgICAgICAgIHRhcmdldCxcbiAgICAgICAgICAgIHByZXJlcXMsXG4gICAgICAgICAgICBwcmVyZXFzU2F0aXNmaWVkOiBwcmVyZXFzU2F0aXNmaWVkKHByZXJlcXMpLFxuICAgICAgICAgICAgbWlzc2luZ0lucHV0czogbWlzc2luZy5tYXAoKG0pID0+ICh7IGZsYWc6IG0uZmxhZywgZGVzY3JpcHRpb246IG0uZGVzY3JpcHRpb24gfSkpLFxuICAgICAgICAgICAgYm9vdHN0cmFwOiBib290c3RyYXBDbWQsXG4gICAgICAgICAgICBzcGFyc2VQYXRoczogd2FudEJvb3RzdHJhcCA/IHNwYXJzZVBhdGhzIDogbnVsbCxcbiAgICAgICAgICAgIGNvbW1hbmQsXG4gICAgICAgICAgICBwb3N0U3RlcHM6IHBvc3RTdGVwcy5tYXAoKHMpID0+ICh7IGlkOiBzLmlkLCBsYWJlbDogcy5sYWJlbCwgY29tbWFuZDogcy5jb21tYW5kIH0pKSxcbiAgICAgICAgICAgIHNraXBwZWRQb3N0U3RlcHM6IHNraXBwZWRTdGVwcyxcbiAgICAgICAgICB9LCBudWxsLCAyKSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gNS4gUHJpbnQgdGhlIHBsYW4gKHNoYXJlZCBieSBhZHZpc29yICsgZXhlY3V0ZSkuXG4gICAgICAgIHByaW50U2VjdGlvbihgUHJvdmlzaW9uIHBsYW4g4oCUICR7c3BlYy5sYWJlbH1gKTtcbiAgICAgICAgcHJpbnRLZXlWYWx1ZSh7ICdUYXJnZXQnOiB0YXJnZXQsICdCZXN0IGZvcic6IHNwZWMuYmVzdEZvciwgJ0Nvc3QnOiBzcGVjLmNvc3QgfSk7XG5cbiAgICAgICAgcHJpbnRTZWN0aW9uKCdQcmVyZXF1aXNpdGVzJyk7XG4gICAgICAgIGZvciAoY29uc3QgYyBvZiBwcmVyZXFzKSBwcmludEluZm8oYCR7Yy5vayA/ICfinJMnIDogJ+Kclyd9ICR7Yy5uYW1lfSDigJQgJHtjLmRldGFpbH1gKTtcbiAgICAgICAgaWYgKCFwcmVyZXFzU2F0aXNmaWVkKHByZXJlcXMpKSBwcmludFdhcm5pbmcoJ1Jlc29sdmUgdGhlIGZhaWxpbmcgcHJlcmVxdWlzaXRlcyBhYm92ZSBiZWZvcmUgZGVwbG95aW5nLicpO1xuXG4gICAgICAgIGlmIChtaXNzaW5nLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICBwcmludFNlY3Rpb24oJ01pc3NpbmcgcmVxdWlyZWQgaW5wdXRzJyk7XG4gICAgICAgICAgZm9yIChjb25zdCBtIG9mIG1pc3NpbmcpIHByaW50SW5mbyhgICAtLSR7bS5mbGFnfSAgKCR7bS5kZXNjcmlwdGlvbn0pYCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoYm9vdHN0cmFwQ21kKSB7XG4gICAgICAgICAgcHJpbnRTZWN0aW9uKCdCb290c3RyYXAgKHNwYXJzZSBnaXQgY2xvbmUsIHJ1bnMgZmlyc3QpJyk7XG4gICAgICAgICAgcHJpbnRJbmZvKGBDbG9uZSAke2Jvb3RzdHJhcC5yZXBvfSBAICR7Ym9vdHN0cmFwLnJlZn0g4oaSICR7Ym9vdHN0cmFwLndvcmtkaXJ9OyBmb2xkZXJzOiAke3NwYXJzZVBhdGhzLmpvaW4oJywgJyl9YCk7XG4gICAgICAgICAgcHJpbnRJbmZvKGJvb3RzdHJhcENtZCk7XG4gICAgICAgIH1cblxuICAgICAgICBwcmludFNlY3Rpb24oJ0NvbW1hbmQgdG8gcnVuJyk7XG4gICAgICAgIHByaW50SW5mbyhjb21tYW5kKTtcblxuICAgICAgICBpZiAocG9zdFN0ZXBzLmxlbmd0aCA+IDAgfHwgc2tpcHBlZFN0ZXBzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICBwcmludFNlY3Rpb24oJ1Bvc3QtaW5zdGFsbCBzdGVwcycpO1xuICAgICAgICAgIGZvciAoY29uc3QgcyBvZiBwb3N0U3RlcHMpIHByaW50SW5mbyhg4oCiICR7cy5sYWJlbH1cXG4gICAgJHtzLmNvbW1hbmR9YCk7XG4gICAgICAgICAgZm9yIChjb25zdCBzIG9mIHNraXBwZWRTdGVwcykgcHJpbnRXYXJuaW5nKGBza2lwcGVkICR7cy5pZH06ICR7cy5yZWFzb259YCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyA2LiBBZHZpc29yIG1vZGUgKGRlZmF1bHQpIOKAlCBzdG9wIGhlcmUsIG5vdGhpbmcgZXhlY3V0ZWQuXG4gICAgICAgIGlmICghb3B0aW9ucy5leGVjdXRlKSB7XG4gICAgICAgICAgcHJpbnRXYXJuaW5nKCdcXG5BZHZpc29yIG1vZGUg4oCUIG5vdGhpbmcgd2FzIGV4ZWN1dGVkLiBSZS1ydW4gd2l0aCAtLWV4ZWN1dGUgdG8gZGVwbG95IChnYXRlZCBieSBhcHByb3ZhbCkuJyk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gNy4gR2F0ZWQgZXhlY3V0aW9uLiBDaGVjayBwcmVyZXFzIC8gcmVxdWlyZWQgaW5wdXRzIGZpcnN0IOKAlCB0aGlzIGFsc29cbiAgICAgICAgLy8gY2F0Y2hlcyBhIG1pc3NpbmcgYGdpdGAgd2hlbiBib290c3RyYXBwaW5nLlxuICAgICAgICBjb25zdCBibG9ja2VkID0gZXhlY3V0aW9uQmxvY2tlZChwcmVyZXFzLCBtaXNzaW5nKTtcbiAgICAgICAgaWYgKGJsb2NrZWQpIHtcbiAgICAgICAgICBwcmludEVycm9yKGBDYW4ndCBzdGFydCBqdXN0IHlldCDigJQgJHtibG9ja2VkfS4gUmVzb2x2ZSB0aGF0IGFuZCByZS1ydW4uYCk7XG4gICAgICAgICAgcHJvY2Vzcy5leGl0Q29kZSA9IDE7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gN2EuIFNwYXJzZS1jbG9uZSB0aGUgcGxhdGZvcm0gcmVwbywgcmVwb2ludCBjd2QsIGFuZCB2ZXJpZnkgdGhlIHRyZWUuXG4gICAgICAgIC8vIFNoYXJlZCBieSBgLS1yZXBvYCAoYmVsb3cpIGFuZCB0aGUgaW50ZXJhY3RpdmUgb2ZmZXIgaW4gN2IuIFJldHVybnNcbiAgICAgICAgLy8gZmFsc2UgKGFuZCBzZXRzIGV4aXRDb2RlKSBvbiBmYWlsdXJlIOKAlCB3aXRoIGEgZnJpZW5kbHkgbWVzc2FnZS5cbiAgICAgICAgY29uc3QgYm9vdHN0cmFwQ2xvbmUgPSBhc3luYyAoKTogUHJvbWlzZTxib29sZWFuPiA9PiB7XG4gICAgICAgICAgY29uc3QgY21kID0gYm9vdHN0cmFwQ29tbWFuZChib290c3RyYXApO1xuICAgICAgICAgIHByaW50U2VjdGlvbignQm9vdHN0cmFwJyk7XG4gICAgICAgICAgcHJpbnRJbmZvKGNtZCk7XG4gICAgICAgICAgY29uc3QgeyBjb2RlIH0gPSBhd2FpdCBydW5TY3JpcHQoY21kLCBjd2QsIHsgY2FwdHVyZTogZmFsc2UgfSk7XG4gICAgICAgICAgaWYgKGNvZGUgIT09IDApIHtcbiAgICAgICAgICAgIHByaW50RXJyb3IoYFxcblRoZSBjbG9uZSBkaWRuJ3QgZmluaXNoIChleGl0ICR7Y29kZX0pLiBEb3VibGUtY2hlY2sgdGhlIHJlcG8gVVJMIC8gcmVmIChvciB5b3VyIG5ldHdvcmspIGFuZCBnaXZlIGl0IGFub3RoZXIgZ28uYCk7XG4gICAgICAgICAgICBwcm9jZXNzLmV4aXRDb2RlID0gMTtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY3dkID0gcGF0aC5yZXNvbHZlKGN3ZCwgYm9vdHN0cmFwLndvcmtkaXIpO1xuICAgICAgICAgIHByaW50U3VjY2VzcyhgUmVwbyBpcyByZWFkeSDigJQgY29udGludWluZyBmcm9tICR7Y3dkfWApO1xuICAgICAgICAgIGNvbnN0IGFic2VudCA9IHNwYXJzZVBhdGhzLmZpbHRlcigocCkgPT4gIWV4aXN0c1N5bmMocGF0aC5qb2luKGN3ZCwgcCkpKTtcbiAgICAgICAgICBpZiAoYWJzZW50Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHByaW50RXJyb3IoYFxcblRoZSBzcGFyc2UgY2xvbmUgaXMgbWlzc2luZyAke2Fic2VudC5qb2luKCcsICcpfSDigJQgdGhhdCByZWYgbWF5IG5vdCBoYXZlIHRob3NlIGZvbGRlcnMuIFRyeSBhIGRpZmZlcmVudCAtLXJlZi5gKTtcbiAgICAgICAgICAgIHByb2Nlc3MuZXhpdENvZGUgPSAxO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBgLS1yZXBvYDogY2xvbmUgdXAgZnJvbnQgKG11c3QgcHJlY2VkZSB0aGUgZW50cnlwb2ludCBjaGVjaykuXG4gICAgICAgIGlmIChib290c3RyYXBDbWQpIHtcbiAgICAgICAgICBwcmludEluZm8oYFxcbkJvb3RzdHJhcCDihpIgY2xvbmUgJHtib290c3RyYXAucmVwb30gQCAke2Jvb3RzdHJhcC5yZWZ9IGludG8gJHtib290c3RyYXAud29ya2Rpcn0gKHNwYXJzZSkuYCk7XG4gICAgICAgICAgaWYgKCEoYXdhaXQgY29uZmlybSgnR28gYWhlYWQgd2l0aCB0aGUgY2xvbmU/Jywgb3B0aW9ucy55ZXMpKSkge1xuICAgICAgICAgICAgcHJpbnRXYXJuaW5nKCdObyBwcm9ibGVtIOKAlCBub3RoaW5nIHdhcyBjaGFuZ2VkLiBSZS1ydW4gd2hlbmV2ZXIgeW91XFwncmUgcmVhZHkuJyk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmICghKGF3YWl0IGJvb3RzdHJhcENsb25lKCkpKSByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyA3Yi4gVGhlIGRlcGxveSBlbnRyeXBvaW50IG11c3QgZXhpc3QgcmVsYXRpdmUgdG8gY3dkLiBJZiBpdCBkb2Vzbid0IGFuZFxuICAgICAgICAvLyB3ZSBoYXZlbid0IGJvb3RzdHJhcHBlZCwgZ3JhY2VmdWxseSBPRkZFUiB0byBjbG9uZSAoaW50ZXJhY3RpdmUgb25seSksXG4gICAgICAgIC8vIHNvIGEgZnJlc2ggbWFjaGluZSBjYW4gcHJvY2VlZCB3aXRob3V0IHJlLXJ1bm5pbmcgd2l0aCAtLXJlcG8uXG4gICAgICAgIGlmICghZW50cnlwb2ludEV4aXN0cyhzcGVjLCBjd2QpKSB7XG4gICAgICAgICAgY29uc3QgaW50ZXJhY3RpdmUgPSBCb29sZWFuKHByb2Nlc3Muc3RkaW4uaXNUVFkpICYmICFvcHRpb25zLnllcztcbiAgICAgICAgICBpZiAoIWJvb3RzdHJhcENtZCAmJiBpbnRlcmFjdGl2ZSAmJiBnaXRBdmFpbGFibGUoKSkge1xuICAgICAgICAgICAgcHJpbnRJbmZvKGBcXG5Mb29rcyBsaWtlIHlvdSdyZSBub3QgaW5zaWRlIGEgcGlwZWxpbmUtYnVpbGRlciBjaGVja291dCwgc28gdGhlICR7c3BlYy5sYWJlbH0gZGVwbG95IHNjcmlwdHMgYXJlbid0IGhlcmUgeWV0LmApO1xuICAgICAgICAgICAgaWYgKGF3YWl0IGNvbmZpcm0oYFdhbnQgbWUgdG8gc3BhcnNlLWNsb25lIHRoZW0gaW50byAke2Jvb3RzdHJhcC53b3JrZGlyfSBhbmQga2VlcCBnb2luZz9gLCBmYWxzZSkpIHtcbiAgICAgICAgICAgICAgaWYgKCEoYXdhaXQgYm9vdHN0cmFwQ2xvbmUoKSkpIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKCFlbnRyeXBvaW50RXhpc3RzKHNwZWMsIGN3ZCkpIHtcbiAgICAgICAgICAgIHByaW50V2FybmluZyhgXFxuSSBjb3VsZG4ndCBmaW5kICR7c3BlYy5kaXJ9LyR7c3BlYy5lbnRyeXBvaW50fSBmcm9tICR7Y3dkfS5gKTtcbiAgICAgICAgICAgIHByaW50SW5mbygnVHdvIGVhc3kgd2F5cyBmb3J3YXJkOicpO1xuICAgICAgICAgICAgcHJpbnRJbmZvKCcgIOKAoiBjZCBpbnRvIHlvdXIgcGlwZWxpbmUtYnVpbGRlciBjaGVja291dCBhbmQgcmUtcnVuLCBvcicpO1xuICAgICAgICAgICAgcHJpbnRJbmZvKGAgIOKAoiBhZGQgLS1yZXBvIGFuZCBJJ2xsIGJvb3RzdHJhcCBhIGZyZXNoIHNwYXJzZSBjbG9uZSBmb3IgeW91JHtnaXRBdmFpbGFibGUoKSA/ICcuJyA6ICcgKG9uY2UgZ2l0IGlzIGluc3RhbGxlZCkuJ31gKTtcbiAgICAgICAgICAgIHByb2Nlc3MuZXhpdENvZGUgPSAxO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoIShhd2FpdCBjb25maXJtKCdcXG5Qcm9jZWVkIHdpdGggdGhpcyBkZXBsb3k/Jywgb3B0aW9ucy55ZXMpKSkge1xuICAgICAgICAgIHByaW50V2FybmluZygnQWJvcnRlZCDigJQgbm90aGluZyB3YXMgZXhlY3V0ZWQuJyk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gN2MuIFJ1biB0aGUgZGVwbG95IG91dC1vZi1sb29wIChyZWFsIGNvbW1hbmQsIHNlY3JldHMgdW5tYXNrZWQsIHN0cmVhbWVkICtcbiAgICAgICAgLy8gY2FwdHVyZWQpLCB3aXRoIGEgYm91bmRlZCBhdXRvLWZpeCArIHJldHJ5IGxvb3Ag4oCUIHRoZSBkZXBsb3kgc2NyaXB0cyBhcmVcbiAgICAgICAgLy8gaWRlbXBvdGVudCwgc28gYSBmaXhlZCByZS1ydW4gcmVzdW1lcyByYXRoZXIgdGhhbiBzdGFydGluZyBvdmVyLlxuICAgICAgICBjb25zdCBtYXhBdHRlbXB0cyA9IDEgKyBNYXRoLm1heCgwLCBwYXJzZUludChvcHRpb25zLnJldHJpZXMsIDEwKSB8fCAwKTtcbiAgICAgICAgbGV0IHJ1blBhcmFtczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSBwYXJhbXM7XG4gICAgICAgIGxldCBzdWNjZWVkZWQgPSBmYWxzZTtcbiAgICAgICAgZm9yIChsZXQgYXR0ZW1wdCA9IDE7IGF0dGVtcHQgPD0gbWF4QXR0ZW1wdHM7IGF0dGVtcHQrKykge1xuICAgICAgICAgIGNvbnN0IHJlYWxDb21tYW5kID0gYXNzZW1ibGVDb21tYW5kKHNwZWMsIHJ1blBhcmFtcywgeyBtYXNrOiBmYWxzZSB9KS5jb21tYW5kO1xuICAgICAgICAgIHByaW50U2VjdGlvbihhdHRlbXB0ID09PSAxID8gJ0RlcGxveWluZycgOiBgRGVwbG95aW5nIOKAlCByZXRyeSAke2F0dGVtcHQgLSAxfWApO1xuICAgICAgICAgIGNvbnN0IHsgY29kZSwgdGFpbCB9ID0gYXdhaXQgcnVuU2NyaXB0KHJlYWxDb21tYW5kLCBjd2QsIHsgY2FwdHVyZTogdHJ1ZSB9KTtcbiAgICAgICAgICBpZiAoY29kZSA9PT0gMCkgeyBzdWNjZWVkZWQgPSB0cnVlOyBicmVhazsgfVxuXG4gICAgICAgICAgcHJpbnRFcnJvcihgXFxuRGVwbG95IGZhaWxlZCAoZXhpdCAke2NvZGV9KS5gKTtcbiAgICAgICAgICBjb25zdCBpc3N1ZXMgPSBtYXRjaElzc3Vlcyh0YWlsKTtcbiAgICAgICAgICBpZiAoaXNzdWVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHByaW50U2VjdGlvbignTGlrZWx5IGNhdXNlJyk7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGkgb2YgaXNzdWVzKSBwcmludEluZm8oYOKAoiAke2kuY2F1c2V9XFxuICDihpIgJHtpLnN1Z2dlc3Rpb259YCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChpc0FpQ29uZmlndXJlZChhaU9wdHMpKSB7XG4gICAgICAgICAgICBjb25zdCBkaWFnbm9zaXMgPSBhd2FpdCBkaWFnbm9zZUZhaWx1cmUocmVkYWN0U2VjcmV0cyh0YWlsLCBzcGVjLCBydW5QYXJhbXMpLCBhaU9wdHMpO1xuICAgICAgICAgICAgaWYgKGRpYWdub3NpcykgeyBwcmludFNlY3Rpb24oJ0RpYWdub3NpcycpOyBwcmludEluZm8oZGlhZ25vc2lzKTsgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoYXR0ZW1wdCA+PSBtYXhBdHRlbXB0cykgYnJlYWs7XG5cbiAgICAgICAgICAvLyBBdXRvLWZpeDogYSByZXRyeWFibGUgaXNzdWUgd2l0aCBhIHBhcmFtIHdlIGhhdmVuJ3QgYWxyZWFkeSBhcHBsaWVkLlxuICAgICAgICAgIGNvbnN0IGZpeCA9IGlzc3Vlcy5maW5kKChpKSA9PiBpLnJldHJ5YWJsZSAmJiBpLnBhcmFtRml4ICYmIHJ1blBhcmFtc1tpLnBhcmFtRml4LmtleV0gIT09IGkucGFyYW1GaXgudmFsdWUpO1xuICAgICAgICAgIGlmIChmaXg/LnBhcmFtRml4ICYmIGF3YWl0IGNvbmZpcm0oYFxcbkFwcGx5IGZpeCBhbmQgcmV0cnkg4oCUICR7Zml4LnN1Z2dlc3Rpb259YCwgb3B0aW9ucy55ZXMpKSB7XG4gICAgICAgICAgICBydW5QYXJhbXMgPSB7IC4uLnJ1blBhcmFtcywgW2ZpeC5wYXJhbUZpeC5rZXldOiBmaXgucGFyYW1GaXgudmFsdWUgfTtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBSZXRyeWFibGUgYnV0IG5vIHBhcmFtIGNoYW5nZSAoZS5nLiBBQ00gRE5TIHByb3BhZ2F0aW9uKSDigJQgb2ZmZXIgYSBwbGFpbiByZS1ydW4uXG4gICAgICAgICAgaWYgKCFmaXggJiYgaXNzdWVzLnNvbWUoKGkpID0+IGkucmV0cnlhYmxlKSAmJiBhd2FpdCBjb25maXJtKCdcXG5SZXRyeSB0aGUgZGVwbG95IChpdCBpcyBpZGVtcG90ZW50IGFuZCB3aWxsIHJlc3VtZSk/Jywgb3B0aW9ucy55ZXMpKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzdWNjZWVkZWQpIHsgcHJvY2Vzcy5leGl0Q29kZSA9IDE7IHJldHVybjsgfVxuICAgICAgICBwcmludFN1Y2Nlc3MoJ0RlcGxveSBjb21tYW5kIGNvbXBsZXRlZC4nKTtcblxuICAgICAgICAvLyA3ZC4gU0VTIHBvc3QtZGVwbG95IGd1aWRhbmNlIChhc3luYyBES0lNICsgc2FuZGJveCArIGJvdW5jZSB0b3BpYykuXG4gICAgICAgIC8vIFNFUyBpcyBwcm92aXNpb25lZCBCWSBERUZBVUxUIG9uIEFXUyBkZXBsb3lzLCBzbyBzdXJmYWNlIHRoZSBndWlkYW5jZVxuICAgICAgICAvLyBmb3IgZWMyL2ZhcmdhdGUgdW5sZXNzIHRoZSBvcGVyYXRvciBvcHRlZCBvdXQgd2l0aCAtLW5vLWVtYWlsLlxuICAgICAgICBjb25zdCBzZXNQcm92aXNpb25lZCA9ICh0YXJnZXQgPT09ICdlYzInIHx8IHRhcmdldCA9PT0gJ2ZhcmdhdGUnKSAmJiBydW5QYXJhbXMubm9FbWFpbCAhPT0gdHJ1ZTtcbiAgICAgICAgaWYgKHNlc1Byb3Zpc2lvbmVkKSB7XG4gICAgICAgICAgcHJpbnRTZWN0aW9uKCdTRVMg4oCUIG5leHQgc3RlcHMnKTtcbiAgICAgICAgICBmb3IgKGNvbnN0IGxpbmUgb2Ygc2VzUG9zdERlcGxveUd1aWRhbmNlKCkpIHByaW50SW5mbyhg4oCiICR7bGluZX1gKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIDdlLiBWZXJpZnkgaGVhbHRoIChDUkVBVEVfQ09NUExFVEUgIT0gc2VydmluZykuXG4gICAgICAgIGlmICh1cmwpIHtcbiAgICAgICAgICBwcmludFNlY3Rpb24oJ1ZlcmlmeWluZyBoZWFsdGgnKTtcbiAgICAgICAgICBwcmludEluZm8oYFBvbGxpbmcgJHt1cmx9L2hlYWx0aCDigKZgKTtcbiAgICAgICAgICBjb25zdCBoZWFsdGggPSBhd2FpdCB3YWl0SGVhbHRoeSh1cmwsIHsgb25UaWNrOiAobSkgPT4gcHJpbnRJbmZvKG0pIH0pO1xuICAgICAgICAgIChoZWFsdGguaGVhbHRoeSA/IHByaW50U3VjY2VzcyA6IHByaW50V2FybmluZykoYCR7aGVhbHRoLnVybH0g4oCUICR7aGVhbHRoLmRldGFpbH1gKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIDdmLiBQb3N0LWluc3RhbGwgc3RlcHMgKHJlZ2lzdGVyICsgb3B0LWluIGxvYWRzLCBzbW9rZSB0ZXN0LCBldmVudHMsIGN1c3RvbSkuXG4gICAgICAgIC8vIHJlZ2lzdGVyIHJ1bnMgaW5pdC1wbGF0Zm9ybTsgZm9yIEVDMi9GYXJnYXRlIGl0IG11c3QgcnVuIGZyb20gaW5zaWRlIHRoZVxuICAgICAgICAvLyBWUEMsIHNvIHdlIHN1cmZhY2UgdGhlIGNvbW1hbmQgdGhlcmUgaW5zdGVhZCBvZiBleGVjdXRpbmcgaXQgbG9jYWxseS5cbiAgICAgICAgaWYgKHBvc3RTdGVwcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgZm9yIChjb25zdCBzIG9mIHNraXBwZWRTdGVwcykgcHJpbnRXYXJuaW5nKGBTa2lwcGVkIHBvc3Qtc3RlcCAke3MuaWR9OiAke3MucmVhc29ufWApO1xuICAgICAgICAgIGNvbnN0IGlzUmVtb3RlUmVnaXN0ZXIgPSAoaWQ6IHN0cmluZyk6IGJvb2xlYW4gPT4gaWQgPT09ICdyZWdpc3RlcicgJiYgKHRhcmdldCA9PT0gJ2VjMicgfHwgdGFyZ2V0ID09PSAnZmFyZ2F0ZScpO1xuICAgICAgICAgIGNvbnN0IHJ1bm5hYmxlID0gcG9zdFN0ZXBzLmZpbHRlcigocykgPT4gIWlzUmVtb3RlUmVnaXN0ZXIocy5pZCkpO1xuICAgICAgICAgIGZvciAoY29uc3QgcyBvZiBwb3N0U3RlcHMpIHtcbiAgICAgICAgICAgIGlmIChpc1JlbW90ZVJlZ2lzdGVyKHMuaWQpKSB7XG4gICAgICAgICAgICAgIHByaW50SW5mbygnXFxuTmV4dCAocnVuIGZyb20gaW5zaWRlIHRoZSBWUEMpOiByZWdpc3RlciBhZG1pbiArIGxvYWQgcGx1Z2lucyDigJQnKTtcbiAgICAgICAgICAgICAgcHJpbnRJbmZvKGAgICR7cy5jb21tYW5kfWApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAocnVubmFibGUubGVuZ3RoID4gMCAmJiBhd2FpdCBjb25maXJtKGBcXG5SdW4gJHtydW5uYWJsZS5sZW5ndGh9IHBvc3QtaW5zdGFsbCBzdGVwKHMpIG5vdz9gLCBvcHRpb25zLnllcykpIHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgcyBvZiBydW5uYWJsZSkge1xuICAgICAgICAgICAgICBwcmludFNlY3Rpb24oYFBvc3Qtc3RlcDogJHtzLmxhYmVsfWApO1xuICAgICAgICAgICAgICBwcmludEluZm8ocy5jb21tYW5kKTtcbiAgICAgICAgICAgICAgY29uc3QgZW52ID0gcy5pZCA9PT0gJ3JlZ2lzdGVyJyA/IHsgLi4ucy5lbnYsIC4uLmFkbWluRW52IH0gOiBzLmVudjtcbiAgICAgICAgICAgICAgY29uc3QgeyBjb2RlIH0gPSBhd2FpdCBydW5TY3JpcHQocy5jb21tYW5kLCBjd2QsIHsgY2FwdHVyZTogZmFsc2UsIGVudiB9KTtcbiAgICAgICAgICAgICAgaWYgKGNvZGUgIT09IDApIHtcbiAgICAgICAgICAgICAgICBwcmludEVycm9yKGBcXG5Qb3N0LXN0ZXAgJyR7cy5pZH0nIGZhaWxlZCAoZXhpdCAke2NvZGV9KS4gVGhlIHBsYXRmb3JtIGlzIGRlcGxveWVkOyBmaXggYW5kIHJlLXJ1biB0aGUgc3RlcCBtYW51YWxseS5gKTtcbiAgICAgICAgICAgICAgICBwcm9jZXNzLmV4aXRDb2RlID0gMTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBwcmludFN1Y2Nlc3MoYCR7cy5pZH0g4pyTYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIGlmIChydW5uYWJsZS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBwcmludEluZm8oJ1xcblNraXBwZWQgcG9zdC1pbnN0YWxsIHN0ZXBzLiBSdW4gdGhlIGNvbW1hbmRzIGFib3ZlIG1hbnVhbGx5IHdoZW4gcmVhZHkuJyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBoYW5kbGVFcnJvcihlcnJvciwgRVJST1JfQ09ERVMuR0VORVJBTCwge1xuICAgICAgICAgIGRlYnVnOiBwcm9ncmFtLm9wdHMoKS5kZWJ1ZyxcbiAgICAgICAgICBleGl0OiB0cnVlLFxuICAgICAgICAgIGNvbnRleHQ6IHsgY29tbWFuZDogJ3Byb3Zpc2lvbicsIGV4ZWN1dGlvbklkIH0sXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xufVxuIl19
|