@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.
Files changed (90) hide show
  1. package/README.md +43 -2
  2. package/dist/agent/ai.d.ts +55 -0
  3. package/dist/agent/ai.d.ts.map +1 -0
  4. package/dist/agent/ai.js +130 -0
  5. package/dist/agent/bootstrap.d.ts +54 -0
  6. package/dist/agent/bootstrap.d.ts.map +1 -0
  7. package/dist/agent/bootstrap.js +76 -0
  8. package/dist/agent/executor.d.ts +27 -0
  9. package/dist/agent/executor.d.ts.map +1 -0
  10. package/dist/agent/executor.js +57 -0
  11. package/dist/agent/health.d.ts +22 -0
  12. package/dist/agent/health.d.ts.map +1 -0
  13. package/dist/agent/health.js +55 -0
  14. package/dist/agent/post-steps.d.ts +55 -0
  15. package/dist/agent/post-steps.d.ts.map +1 -0
  16. package/dist/agent/post-steps.js +73 -0
  17. package/dist/agent/prereqs.d.ts +25 -0
  18. package/dist/agent/prereqs.d.ts.map +1 -0
  19. package/dist/agent/prereqs.js +100 -0
  20. package/dist/agent/targets.d.ts +122 -0
  21. package/dist/agent/targets.d.ts.map +1 -0
  22. package/dist/agent/targets.js +180 -0
  23. package/dist/agent/troubleshoot.d.ts +30 -0
  24. package/dist/agent/troubleshoot.d.ts.map +1 -0
  25. package/dist/agent/troubleshoot.js +87 -0
  26. package/dist/boilerplate.js +8 -13
  27. package/dist/cli.d.ts.map +1 -1
  28. package/dist/cli.js +123 -118
  29. package/dist/commands/audit-stacks.js +22 -24
  30. package/dist/commands/audit-tokens.js +25 -27
  31. package/dist/commands/bootstrap.js +29 -37
  32. package/dist/commands/create-pipeline.js +55 -92
  33. package/dist/commands/deploy.d.ts.map +1 -1
  34. package/dist/commands/deploy.js +58 -62
  35. package/dist/commands/get-pipeline.js +24 -28
  36. package/dist/commands/get-plugin.js +24 -28
  37. package/dist/commands/list-pipelines.js +30 -31
  38. package/dist/commands/list-plugins.js +32 -33
  39. package/dist/commands/login.js +44 -49
  40. package/dist/commands/org-export.js +22 -60
  41. package/dist/commands/provision.d.ts +13 -0
  42. package/dist/commands/provision.d.ts.map +1 -0
  43. package/dist/commands/provision.js +489 -0
  44. package/dist/commands/register.js +29 -30
  45. package/dist/commands/setup-events.d.ts.map +1 -1
  46. package/dist/commands/setup-events.js +42 -77
  47. package/dist/commands/status.js +20 -25
  48. package/dist/commands/store-token.js +44 -82
  49. package/dist/commands/synth.d.ts.map +1 -1
  50. package/dist/commands/synth.js +36 -35
  51. package/dist/commands/upload-plugin.js +59 -96
  52. package/dist/commands/validate-templates.d.ts.map +1 -1
  53. package/dist/commands/validate-templates.js +23 -29
  54. package/dist/commands/version.js +42 -47
  55. package/dist/config/cli.constants.d.ts.map +1 -1
  56. package/dist/config/cli.constants.js +24 -31
  57. package/dist/types/config.js +2 -3
  58. package/dist/types/error.js +3 -7
  59. package/dist/types/index.d.ts +4 -4
  60. package/dist/types/index.d.ts.map +1 -1
  61. package/dist/types/index.js +5 -21
  62. package/dist/types/pipeline.js +2 -3
  63. package/dist/types/plugin.js +2 -3
  64. package/dist/utils/api-client.d.ts +1 -1
  65. package/dist/utils/api-client.d.ts.map +1 -1
  66. package/dist/utils/api-client.js +23 -28
  67. package/dist/utils/audit-log.js +16 -22
  68. package/dist/utils/auth-guard.js +2 -5
  69. package/dist/utils/aws-secrets.js +17 -23
  70. package/dist/utils/banner.js +16 -23
  71. package/dist/utils/cdk-utils.js +14 -24
  72. package/dist/utils/command-utils.d.ts +1 -1
  73. package/dist/utils/command-utils.d.ts.map +1 -1
  74. package/dist/utils/command-utils.js +32 -44
  75. package/dist/utils/config-loader.d.ts +1 -1
  76. package/dist/utils/config-loader.d.ts.map +1 -1
  77. package/dist/utils/config-loader.js +24 -58
  78. package/dist/utils/error-handler.d.ts +1 -1
  79. package/dist/utils/error-handler.d.ts.map +1 -1
  80. package/dist/utils/error-handler.js +16 -24
  81. package/dist/utils/list-command-utils.js +15 -20
  82. package/dist/utils/output-utils.d.ts +1 -1
  83. package/dist/utils/output-utils.d.ts.map +1 -1
  84. package/dist/utils/output-utils.js +35 -55
  85. package/dist/utils/plugin-resolver.d.ts +1 -1
  86. package/dist/utils/plugin-resolver.d.ts.map +1 -1
  87. package/dist/utils/plugin-resolver.js +6 -8
  88. package/dist/utils/rate-limiter.js +11 -19
  89. package/dist/utils/registry.js +16 -22
  90. 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