UNPKG

faastjs

Version:

Serverless batch computing made simple.

239 lines 41.5 kB
#!/usr/bin/env node "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); require("source-map-support").install(); const client_cloudwatch_logs_1 = require("@aws-sdk/client-cloudwatch-logs"); const client_iam_1 = require("@aws-sdk/client-iam"); const client_lambda_1 = require("@aws-sdk/client-lambda"); const client_sns_1 = require("@aws-sdk/client-sns"); const client_sqs_1 = require("@aws-sdk/client-sqs"); const commander_1 = require("commander"); const fs_extra_1 = require("fs-extra"); const ora_1 = tslib_1.__importDefault(require("ora")); const os_1 = require("os"); const path_1 = tslib_1.__importDefault(require("path")); const readline = tslib_1.__importStar(require("readline")); const awsFaast = tslib_1.__importStar(require("./aws/aws-faast")); const cache_1 = require("./cache"); const shared_1 = require("./shared"); const throttle_1 = require("./throttle"); const warn = console.warn; const log = console.log; async function deleteResources(name, matchingResources, doRemove, { concurrency = 10, rate = 5, burst = 5 } = {}) { if (matchingResources.length > 0) { const timeEstimate = (nResources) => nResources <= 5 ? "" : `(est: ${(nResources / 5).toFixed(0)}s)`; const updateSpinnerText = (nResources = 0) => `Deleting ${matchingResources.length} ${name} ${timeEstimate(nResources)}`; const spinner = (0, ora_1.default)(updateSpinnerText(matchingResources.length)).start(); let done = 0; const scheduleRemove = (0, throttle_1.throttle)({ concurrency, rate, burst, retry: 5 }, async (arg) => { await doRemove(arg); done++; }); const timer = setInterval(() => (spinner.text = updateSpinnerText(matchingResources.length - done)), 1000); try { await Promise.all(matchingResources.map(resource => scheduleRemove(resource).catch(err => console.warn(`Could not remove resource ${resource}: ${err}`)))); } finally { clearInterval(timer); spinner.text = updateSpinnerText(); } spinner.stopAndPersist({ symbol: "✔" }); } } async function cleanupAWS({ region, execute }) { let nResources = 0; const output = (msg) => !execute && log(msg); const { cloudwatch, iam, lambda, sns, sqs, s3 } = await awsFaast.createAwsApis(region); async function listAWSResource(pattern, getList, extractList, extractElement) { const allResources = []; for await (const page of getList()) { const elems = (page && extractList(page)) || []; allResources.push(...elems.map(elem => extractElement(elem) || "")); } const matchingResources = allResources.filter(t => t.match(pattern)); matchingResources.forEach(resource => output(` ${resource}`)); return matchingResources; } async function deleteAWSResource(name, pattern, getList, extractList, extractElement, doRemove) { const allResources = await listAWSResource(pattern, getList, extractList, extractElement); nResources += allResources.length; if (execute) { await deleteResources(name, allResources, doRemove, { concurrency: 10, rate: 5, burst: 5 }); } } output(`SNS subscriptions`); await deleteAWSResource("SNS subscription(s)", new RegExp(`:faast-${shared_1.uuidv4Pattern}`), () => (0, client_sns_1.paginateListSubscriptions)({ client: sns }, {}), page => page.Subscriptions, subscription => subscription.SubscriptionArn, SubscriptionArn => sns.unsubscribe({ SubscriptionArn })); output(`SNS topics`); await deleteAWSResource("SNS topic(s)", new RegExp(`:faast-${shared_1.uuidv4Pattern}`), () => (0, client_sns_1.paginateListTopics)({ client: sns }, {}), page => page.Topics, topic => topic.TopicArn, TopicArn => sns.deleteTopic({ TopicArn })); output(`SQS queues`); await deleteAWSResource("SQS queue(s)", new RegExp(`/faast-${shared_1.uuidv4Pattern}`), () => (0, client_sqs_1.paginateListQueues)({ client: sqs }, {}), page => page.QueueUrls, queueUrl => queueUrl, QueueUrl => sqs.deleteQueue({ QueueUrl })); async function* listBuckets() { const result = s3.listBuckets({}); yield result; return result; } output(`S3 buckets`); await deleteAWSResource("S3 bucket(s)", new RegExp(`^faast-${shared_1.uuidv4Pattern}`), () => listBuckets(), page => page.Buckets, Bucket => Bucket.Name, async (Bucket) => { const objects = await s3.listObjectsV2({ Bucket, Prefix: "faast-" }); const keys = (objects.Contents || []).map(entry => ({ Key: entry.Key })); if (keys.length > 0) { await s3.deleteObjects({ Bucket, Delete: { Objects: keys } }); } await s3.deleteBucket({ Bucket }); }); output(`Lambda functions`); await deleteAWSResource("Lambda function(s)", new RegExp(`^faast-${shared_1.uuidv4Pattern}`), () => (0, client_lambda_1.paginateListFunctions)({ client: lambda }, {}), page => page.Functions, func => func.FunctionName, FunctionName => lambda.deleteFunction({ FunctionName })); output(`IAM roles`); await deleteAWSResource("IAM role(s)", /^faast-cached-lambda-role$/, () => (0, client_iam_1.paginateListRoles)({ client: iam }, {}), page => page.Roles, role => role.RoleName, RoleName => awsFaast.deleteRole(RoleName, iam)); output(`IAM test roles`); await deleteAWSResource("IAM test role(s)", new RegExp(`^faast-test-.*${shared_1.uuidv4Pattern}$`), () => (0, client_iam_1.paginateListRoles)({ client: iam }, {}), page => page.Roles, role => role.RoleName, RoleName => awsFaast.deleteRole(RoleName, iam)); output(`Lambda layers`); await deleteAWSResource("Lambda layer(s)", new RegExp(`^faast-(${shared_1.uuidv4Pattern})|([a-f0-9]{64})`), () => (0, client_lambda_1.paginateListLayers)({ client: lambda }, { CompatibleRuntime: "nodejs" }), page => page.Layers, layer => layer.LayerName, async (LayerName) => { const versions = await lambda.listLayerVersions({ LayerName }); for (const layerVersion of versions.LayerVersions || []) { await lambda.deleteLayerVersion({ LayerName, VersionNumber: layerVersion.Version }); } }); async function cleanupCacheDir(cache) { output(`Persistent cache: ${cache.dir}`); const entries = await cache.entries(); if (!execute) { output(` cache entries: ${entries.length}`); } nResources += entries.length; if (execute) { cache.clear({ leaveEmptyDir: false }); } } for (const cache of (0, shared_1.keysOf)(cache_1.caches)) { await cleanupCacheDir(await cache_1.caches[cache]); } output(`Cloudwatch log groups`); await deleteAWSResource("Cloudwatch log group(s)", new RegExp(`/faast-${shared_1.uuidv4Pattern}$`), () => (0, client_cloudwatch_logs_1.paginateDescribeLogGroups)({ client: cloudwatch }, {}), page => page.logGroups, logGroup => logGroup.logGroupName, logGroupName => cloudwatch.deleteLogGroup({ logGroupName })); return nResources; } async function cleanupLocal({ execute }) { const output = (msg) => !execute && log(msg); const tmpDir = (0, os_1.tmpdir)(); const dir = await (0, fs_extra_1.readdir)(tmpDir); let nResources = 0; output(`Temporary directories:`); const entryRegexp = new RegExp(`^faast-${shared_1.uuidv4Pattern}$`); for (const entry of dir) { if (entry.match(entryRegexp)) { nResources++; const faastDir = path_1.default.join(tmpDir, entry); output(`${faastDir}`); if (execute) { await (0, fs_extra_1.remove)(faastDir); } } } return nResources; } async function prompt() { const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); await new Promise(resolve => { rl.question("WARNING: this operation will delete resources. Confirm? [y/N] ", answer => { if (answer !== "y") { log(`Execution aborted.`); process.exit(0); } rl.close(); resolve(); }); }); } async function runCleanup(cloud, options) { let nResources = 0; if (cloud === "aws") { nResources = await cleanupAWS(options); } else if (cloud === "local") { nResources = await cleanupLocal(options); } else { warn(`Unknown cloud name "${cloud}". Must specify "aws" or "local".`); process.exit(-1); } if (options.execute) { log(`Done.`); } else { if (nResources === 0) { log(`No resources to clean up.`); } } return nResources; } async function main() { let cloud; let command; commander_1.program .version("0.1.0") .option("-v, --verbose", "Verbose mode") .option("-r, --region <region>", "Cloud region to operate on. Defaults to us-west-2 for AWS.") .option("-x, --execute", "Execute the cleanup process. If this option is not specified, the output will be a dry run.") .option("-f, --force", "When used with -x, skips the prompt") .command("cleanup <cloud>") .description(`Cleanup faast.js resources that may have leaked. The <cloud> argument must be "aws" or "local". By default the output is a dry run and will only print the actions that would be performed if '-x' is specified.`) .action((arg) => { command = "cleanup"; cloud = arg; }); const opts = commander_1.program.parse(process.argv).opts(); if (opts.verbose) { process.env.DEBUG = "faast:*"; } const execute = opts.execute || false; let region = opts.region; if (!region) { switch (cloud) { case "aws": region = awsFaast.defaults.region; break; } } const force = opts.force || false; region && log(`Region: ${region}`); const options = { region, execute }; let nResources = 0; if (command === "cleanup") { if (execute && !force) { nResources = await runCleanup(cloud, { ...options, execute: false }); if (nResources > 0) { await prompt(); } else { process.exit(0); } } nResources = await runCleanup(cloud, options); if (!execute && nResources > 0) { log(`(dryrun mode, no resources will be deleted, specify -x to execute cleanup)`); } } else { log(`No command specified.`); commander_1.program.help(); } } main(); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBRUEsT0FBTyxDQUFDLG9CQUFvQixDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7QUFDeEMsNEVBQTRFO0FBQzVFLG9EQUF3RDtBQUN4RCwwREFBbUY7QUFDbkYsb0RBQW9GO0FBQ3BGLG9EQUF5RDtBQUV6RCx5Q0FBb0M7QUFDcEMsdUNBQTJDO0FBQzNDLHNEQUFzQjtBQUN0QiwyQkFBNEI7QUFDNUIsd0RBQXdCO0FBQ3hCLDJEQUFxQztBQUNyQyxrRUFBNEM7QUFDNUMsbUNBQWtEO0FBQ2xELHFDQUFpRDtBQUNqRCx5Q0FBc0M7QUFFdEMsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztBQUMxQixNQUFNLEdBQUcsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDO0FBT3hCLEtBQUssVUFBVSxlQUFlLENBQzFCLElBQVksRUFDWixpQkFBMkIsRUFDM0IsUUFBdUMsRUFDdkMsRUFBRSxXQUFXLEdBQUcsRUFBRSxFQUFFLElBQUksR0FBRyxDQUFDLEVBQUUsS0FBSyxHQUFHLENBQUMsRUFBRSxHQUFHLEVBQUU7SUFFOUMsSUFBSSxpQkFBaUIsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1FBQzlCLE1BQU0sWUFBWSxHQUFHLENBQUMsVUFBa0IsRUFBRSxFQUFFLENBQ3hDLFVBQVUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUNwRSxNQUFNLGlCQUFpQixHQUFHLENBQUMsYUFBcUIsQ0FBQyxFQUFFLEVBQUUsQ0FDakQsWUFBWSxpQkFBaUIsQ0FBQyxNQUFNLElBQUksSUFBSSxJQUFJLFlBQVksQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1FBQy9FLE1B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VSxHQUFHLE1BQU0sVUFBVSxDQUFDLEtBQUssRUFBRSxFQUFFLEdBQUcsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQ3JFLElBQUksVUFBVSxHQUFHLENBQUMsRUFBRTtnQkFDaEIsTUFBTSxNQUFNLEVBQUUsQ0FBQzthQUNsQjtpQkFBTTtnQkFDSCxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO2FBQ25CO1NBQ0o7UUFDRCxVQUFVLEdBQUcsTUFBTSxVQUFVLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzlDLElBQUksQ0FBQyxPQUFPLElBQUksVUFBVSxHQUFHLENBQUMsRUFBRTtZQUM1QixHQUFHLENBQ0MsNEVBQTRFLENBQy9FLENBQUM7U0FDTDtLQUNKO1NBQU07UUFDSCxHQUFHLENBQUMsdUJBQXVCLENBQUMsQ0FBQztRQUM3QixtQkFBTyxDQUFDLElBQUksRUFBRSxDQUFDO0tBQ2xCO0FBQ0wsQ0FBQztBQUVELElBQUksRUFBRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiIyEvdXNyL2Jpbi9lbnYgbm9kZVxuXG5yZXF1aXJlKFwic291cmNlLW1hcC1zdXBwb3J0XCIpLmluc3RhbGwoKTtcbmltcG9ydCB7IHBhZ2luYXRlRGVzY3JpYmVMb2dHcm91cHMgfSBmcm9tIFwiQGF3cy1zZGsvY2xpZW50LWNsb3Vkd2F0Y2gtbG9nc1wiO1xuaW1wb3J0IHsgcGFnaW5hdGVMaXN0Um9sZXMgfSBmcm9tIFwiQGF3cy1zZGsvY2xpZW50LWlhbVwiO1xuaW1wb3J0IHsgcGFnaW5hdGVMaXN0RnVuY3Rpb25zLCBwYWdpbmF0ZUxpc3RMYXllcnMgfSBmcm9tIFwiQGF3cy1zZGsvY2xpZW50LWxhbWJkYVwiO1xuaW1wb3J0IHsgcGFnaW5hdGVMaXN0U3Vic2NyaXB0aW9ucywgcGFnaW5hdGVMaXN0VG9waWNzIH0gZnJvbSBcIkBhd3Mtc2RrL2NsaWVudC1zbnNcIjtcbmltcG9ydCB7IHBhZ2luYXRlTGlzdFF1ZXVlcyB9IGZyb20gXCJAYXdzLXNkay9jbGllbnQtc3FzXCI7XG5pbXBvcnQgeyBQYWdpbmF0b3IgfSBmcm9tIFwiQGF3cy1zZGsvdHlwZXNcIjtcbmltcG9ydCB7IHByb2dyYW0gfSBmcm9tIFwiY29tbWFuZGVyXCI7XG5pbXBvcnQgeyByZWFkZGlyLCByZW1vdmUgfSBmcm9tIFwiZnMtZXh0cmFcIjtcbmltcG9ydCBvcmEgZnJvbSBcIm9yYVwiO1xuaW1wb3J0IHsgdG1wZGlyIH0gZnJvbSBcIm9zXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0ICogYXMgcmVhZGxpbmUgZnJvbSBcInJlYWRsaW5lXCI7XG5pbXBvcnQgKiBhcyBhd3NGYWFzdCBmcm9tIFwiLi9hd3MvYXdzLWZhYXN0XCI7XG5pbXBvcnQgeyBQZXJzaXN0ZW50Q2FjaGUsIGNhY2hlcyB9IGZyb20gXCIuL2NhY2hlXCI7XG5pbXBvcnQgeyBrZXlzT2YsIHV1aWR2NFBhdHRlcm4gfSBmcm9tIFwiLi9zaGFyZWRcIjtcbmltcG9ydCB7IHRocm90dGxlIH0gZnJvbSBcIi4vdGhyb3R0bGVcIjtcblxuY29uc3Qgd2FybiA9IGNvbnNvbGUud2FybjtcbmNvbnN0IGxvZyA9IGNvbnNvbGUubG9nO1xuXG5pbnRlcmZhY2UgQ2xlYW51cE9wdGlvbnMge1xuICAgIHJlZ2lvbj86IHN0cmluZzsgLy8gQVdTIG9ubHkuXG4gICAgZXhlY3V0ZTogYm9vbGVhbjtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZGVsZXRlUmVzb3VyY2VzKFxuICAgIG5hbWU6IHN0cmluZyxcbiAgICBtYXRjaGluZ1Jlc291cmNlczogc3RyaW5nW10sXG4gICAgZG9SZW1vdmU6IChhcmc6IHN0cmluZykgPT4gUHJvbWlzZTxhbnk+LFxuICAgIHsgY29uY3VycmVuY3kgPSAxMCwgcmF0ZSA9IDUsIGJ1cnN0ID0gNSB9ID0ge31cbikge1xuICAgIGlmIChtYXRjaGluZ1Jlc291cmNlcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IHRpbWVFc3RpbWF0ZSA9IChuUmVzb3VyY2VzOiBudW1iZXIpID0+XG4gICAgICAgICAgICBuUmVzb3VyY2VzIDw9IDUgPyBcIlwiIDogYChlc3Q6ICR7KG5SZXNvdXJjZXMgLyA1KS50b0ZpeGVkKDApfXMpYDtcbiAgICAgICAgY29uc3QgdXBkYXRlU3Bpbm5lclRleHQgPSAoblJlc291cmNlczogbnVtYmVyID0gMCkgPT5cbiAgICAgICAgICAgIGBEZWxldGluZyAke21hdGNoaW5nUmVzb3VyY2VzLmxlbmd0aH0gJHtuYW1lfSAke3RpbWVFc3RpbWF0ZShuUmVzb3VyY2VzKX1gO1xuICAgICAgICBjb25zdCBzcGlubmVyID0gb3JhKHVwZGF0ZVNwaW5uZXJUZXh0KG1hdGNoaW5nUmVzb3VyY2VzLmxlbmd0aCkpLnN0YXJ0KCk7XG4gICAgICAgIGxldCBkb25lID0gMDtcbiAgICAgICAgY29uc3Qgc2NoZWR1bGVSZW1vdmUgPSB0aHJvdHRsZShcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBjb25jdXJyZW5jeSxcbiAgICAgICAgICAgICAgICByYXRlLFxuICAgICAgICAgICAgICAgIGJ1cnN0LFxuICAgICAgICAgICAgICAgIHJldHJ5OiA1XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgYXN5bmMgYXJnID0+IHtcbiAgICAgICAgICAgICAgICBhd2FpdCBkb1JlbW92ZShhcmcpO1xuICAgICAgICAgICAgICAgIGRvbmUrKztcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgdGltZXIgPSBzZXRJbnRlcnZhbChcbiAgICAgICAgICAgICgpID0+IChzcGlubmVyLnRleHQgPSB1cGRhdGVTcGlubmVyVGV4dChtYXRjaGluZ1Jlc291cmNlcy5sZW5ndGggLSBkb25lKSksXG4gICAgICAgICAgICAxMDAwXG4gICAgICAgICk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgICAgICAgICBtYXRjaGluZ1Jlc291cmNlcy5tYXAocmVzb3VyY2UgPT5cbiAgICAgICAgICAgICAgICAgICAgc2NoZWR1bGVSZW1vdmUocmVzb3VyY2UpLmNhdGNoKGVyciA9PlxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKGBDb3VsZCBub3QgcmVtb3ZlIHJlc291cmNlICR7cmVzb3VyY2V9OiAke2Vycn1gKVxuICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgIGNsZWFySW50ZXJ2YWwodGltZXIpO1xuICAgICAgICAgICAgc3Bpbm5lci50ZXh0ID0gdXBkYXRlU3Bpbm5lclRleHQoKTtcbiAgICAgICAgfVxuICAgICAgICBzcGlubmVyLnN0b3BBbmRQZXJzaXN0KHsgc3ltYm9sOiBcIuKclFwiIH0pO1xuICAgIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gY2xlYW51cEFXUyh7IHJlZ2lvbiwgZXhlY3V0ZSB9OiBDbGVhbnVwT3B0aW9ucykge1xuICAgIGxldCBuUmVzb3VyY2VzID0gMDtcbiAgICBjb25zdCBvdXRwdXQgPSAobXNnOiBzdHJpbmcpID0+ICFleGVjdXRlICYmIGxvZyhtc2cpO1xuICAgIGNvbnN0IHsgY2xvdWR3YXRjaCwgaWFtLCBsYW1iZGEsIHNucywgc3FzLCBzMyB9ID0gYXdhaXQgYXdzRmFhc3QuY3JlYXRlQXdzQXBpcyhcbiAgICAgICAgcmVnaW9uISBhcyBhd3NGYWFzdC5Bd3NSZWdpb25cbiAgICApO1xuXG4gICAgYXN5bmMgZnVuY3Rpb24gbGlzdEFXU1Jlc291cmNlPFQsIFU+KFxuICAgICAgICBwYXR0ZXJuOiBSZWdFeHAsXG4gICAgICAgIGdldExpc3Q6ICgpID0+IFBhZ2luYXRvcjxUPixcbiAgICAgICAgZXh0cmFjdExpc3Q6IChhcmc6IFQpID0+IFVbXSB8IHVuZGVmaW5lZCxcbiAgICAgICAgZXh0cmFjdEVsZW1lbnQ6IChhcmc6IFUpID0+IHN0cmluZyB8IHVuZGVmaW5lZFxuICAgICkge1xuICAgICAgICBjb25zdCBhbGxSZXNvdXJjZXM6IHN0cmluZ1tdID0gW107XG4gICAgICAgIGZvciBhd2FpdCAoY29uc3QgcGFnZSBvZiBnZXRMaXN0KCkpIHtcbiAgICAgICAgICAgIGNvbnN0IGVsZW1zID0gKHBhZ2UgJiYgZXh0cmFjdExpc3QocGFnZSkpIHx8IFtdO1xuICAgICAgICAgICAgYWxsUmVzb3VyY2VzLnB1c2goLi4uZWxlbXMubWFwKGVsZW0gPT4gZXh0cmFjdEVsZW1lbnQoZWxlbSkgfHwgXCJcIikpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IG1hdGNoaW5nUmVzb3VyY2VzID0gYWxsUmVzb3VyY2VzLmZpbHRlcih0ID0+IHQubWF0Y2gocGF0dGVybikpO1xuICAgICAgICBtYXRjaGluZ1Jlc291cmNlcy5mb3JFYWNoKHJlc291cmNlID0+IG91dHB1dChgICAke3Jlc291cmNlfWApKTtcbiAgICAgICAgcmV0dXJuIG1hdGNoaW5nUmVzb3VyY2VzO1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIGRlbGV0ZUFXU1Jlc291cmNlPFQsIFU+KFxuICAgICAgICBuYW1lOiBzdHJpbmcsXG4gICAgICAgIHBhdHRlcm46IFJlZ0V4cCxcbiAgICAgICAgZ2V0TGlzdDogKCkgPT4gUGFnaW5hdG9yPFQ+LFxuICAgICAgICBleHRyYWN0TGlzdDogKGFyZzogVCkgPT4gVVtdIHwgdW5kZWZpbmVkLFxuICAgICAgICBleHRyYWN0RWxlbWVudDogKGFyZzogVSkgPT4gc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgICAgICBkb1JlbW92ZTogKGFyZzogc3RyaW5nKSA9PiBQcm9taXNlPGFueT5cbiAgICApIHtcbiAgICAgICAgY29uc3QgYWxsUmVzb3VyY2VzID0gYXdhaXQgbGlzdEFXU1Jlc291cmNlKFxuICAgICAgICAgICAgcGF0dGVybixcbiAgICAgICAgICAgIGdldExpc3QsXG4gICAgICAgICAgICBleHRyYWN0TGlzdCxcbiAgICAgICAgICAgIGV4dHJhY3RFbGVtZW50XG4gICAgICAgICk7XG4gICAgICAgIG5SZXNvdXJjZXMgKz0gYWxsUmVzb3VyY2VzLmxlbmd0aDtcbiAgICAgICAgaWYgKGV4ZWN1dGUpIHtcbiAgICAgICAgICAgIGF3YWl0IGRlbGV0ZVJlc291cmNlcyhuYW1lLCBhbGxSZXNvdXJjZXMsIGRvUmVtb3ZlLCB7XG4gICAgICAgICAgICAgICAgY29uY3VycmVuY3k6IDEwLFxuICAgICAgICAgICAgICAgIHJhdGU6IDUsXG4gICAgICAgICAgICAgICAgYnVyc3Q6IDVcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgb3V0cHV0KGBTTlMgc3Vic2NyaXB0aW9uc2ApO1xuICAgIGF3YWl0IGRlbGV0ZUFXU1Jlc291cmNlKFxuICAgICAgICBcIlNOUyBzdWJzY3JpcHRpb24ocylcIixcbiAgICAgICAgbmV3IFJlZ0V4cChgOmZhYXN0LSR7dXVpZHY0UGF0dGVybn1gKSxcbiAgICAgICAgKCkgPT4gcGFnaW5hdGVMaXN0U3Vic2NyaXB0aW9ucyh7IGNsaWVudDogc25zIH0sIHt9KSxcbiAgICAgICAgcGFnZSA9PiBwYWdlLlN1YnNjcmlwdGlvbnMsXG4gICAgICAgIHN1YnNjcmlwdGlvbiA9PiBzdWJzY3JpcHRpb24uU3Vic2NyaXB0aW9uQXJuLFxuICAgICAgICBTdWJzY3JpcHRpb25Bcm4gPT4gc25zLnVuc3Vic2NyaWJlKHsgU3Vic2NyaXB0aW9uQXJuIH0pXG4gICAgKTtcblxuICAgIG91dHB1dChgU05TIHRvcGljc2ApO1xuICAgIGF3YWl0IGRlbGV0ZUFXU1Jlc291cmNlKFxuICAgICAgICBcIlNOUyB0b3BpYyhzKVwiLFxuICAgICAgICBuZXcgUmVnRXhwKGA6ZmFhc3QtJHt1dWlkdjRQYXR0ZXJufWApLFxuICAgICAgICAoKSA9PiBwYWdpbmF0ZUxpc3RUb3BpY3MoeyBjbGllbnQ6IHNucyB9LCB7fSksXG4gICAgICAgIHBhZ2UgPT4gcGFnZS5Ub3BpY3MsXG4gICAgICAgIHRvcGljID0+IHRvcGljLlRvcGljQXJuLFxuICAgICAgICBUb3BpY0FybiA9PiBzbnMuZGVsZXRlVG9waWMoeyBUb3BpY0FybiB9KVxuICAgICk7XG5cbiAgICBvdXRwdXQoYFNRUyBxdWV1ZXNgKTtcbiAgICBhd2FpdCBkZWxldGVBV1NSZXNvdXJjZShcbiAgICAgICAgXCJTUVMgcXVldWUocylcIixcbiAgICAgICAgbmV3IFJlZ0V4cChgL2ZhYXN0LSR7dXVpZHY0UGF0dGVybn1gKSxcbiAgICAgICAgKCkgPT4gcGFnaW5hdGVMaXN0UXVldWVzKHsgY2xpZW50OiBzcXMgfSwge30pLFxuICAgICAgICBwYWdlID0+IHBhZ2UuUXVldWVVcmxzLFxuICAgICAgICBxdWV1ZVVybCA9PiBxdWV1ZVVybCxcbiAgICAgICAgUXVldWVVcmwgPT4gc3FzLmRlbGV0ZVF1ZXVlKHsgUXVldWVVcmwgfSlcbiAgICApO1xuXG4gICAgYXN5bmMgZnVuY3Rpb24qIGxpc3RCdWNrZXRzKCkge1xuICAgICAgICBjb25zdCByZXN1bHQgPSBzMy5saXN0QnVja2V0cyh7fSk7XG4gICAgICAgIHlpZWxkIHJlc3VsdDtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICBvdXRwdXQoYFMzIGJ1Y2tldHNgKTtcbiAgICBhd2FpdCBkZWxldGVBV1NSZXNvdXJjZShcbiAgICAgICAgXCJTMyBidWNrZXQocylcIixcbiAgICAgICAgbmV3IFJlZ0V4cChgXmZhYXN0LSR7dXVpZHY0UGF0dGVybn1gKSxcbiAgICAgICAgKCkgPT4gbGlzdEJ1Y2tldHMoKSxcbiAgICAgICAgcGFnZSA9PiBwYWdlLkJ1Y2tldHMsXG4gICAgICAgIEJ1Y2tldCA9PiBCdWNrZXQuTmFtZSxcbiAgICAgICAgYXN5bmMgQnVja2V0ID0+IHtcbiAgICAgICAgICAgIGNvbnN0IG9iamVjdHMgPSBhd2FpdCBzMy5saXN0T2JqZWN0c1YyKHsgQnVja2V0LCBQcmVmaXg6IFwiZmFhc3QtXCIgfSk7XG4gICAgICAgICAgICBjb25zdCBrZXlzID0gKG9iamVjdHMuQ29udGVudHMgfHwgW10pLm1hcChlbnRyeSA9PiAoeyBLZXk6IGVudHJ5LktleSEgfSkpO1xuICAgICAgICAgICAgaWYgKGtleXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIGF3YWl0IHMzLmRlbGV0ZU9iamVjdHMoeyBCdWNrZXQsIERlbGV0ZTogeyBPYmplY3RzOiBrZXlzIH0gfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhd2FpdCBzMy5kZWxldGVCdWNrZXQoeyBCdWNrZXQgfSk7XG4gICAgICAgIH1cbiAgICApO1xuXG4gICAgb3V0cHV0KGBMYW1iZGEgZnVuY3Rpb25zYCk7XG4gICAgYXdhaXQgZGVsZXRlQVdTUmVzb3VyY2UoXG4gICAgICAgIFwiTGFtYmRhIGZ1bmN0aW9uKHMpXCIsXG4gICAgICAgIG5ldyBSZWdFeHAoYF5mYWFzdC0ke3V1aWR2NFBhdHRlcm59YCksXG4gICAgICAgICgpID0+IHBhZ2luYXRlTGlzdEZ1bmN0aW9ucyh7IGNsaWVudDogbGFtYmRhIH0sIHt9KSxcbiAgICAgICAgcGFnZSA9PiBwYWdlLkZ1bmN0aW9ucyxcbiAgICAgICAgZnVuYyA9PiBmdW5jLkZ1bmN0aW9uTmFtZSxcbiAgICAgICAgRnVuY3Rpb25OYW1lID0+IGxhbWJkYS5kZWxldGVGdW5jdGlvbih7IEZ1bmN0aW9uTmFtZSB9KVxuICAgICk7XG5cbiAgICBvdXRwdXQoYElBTSByb2xlc2ApO1xuICAgIGF3YWl0IGRlbGV0ZUFXU1Jlc291cmNlKFxuICAgICAgICBcIklBTSByb2xlKHMpXCIsXG4gICAgICAgIC9eZmFhc3QtY2FjaGVkLWxhbWJkYS1yb2xlJC8sXG4gICAgICAgICgpID0+IHBhZ2luYXRlTGlzdFJvbGVzKHsgY2xpZW50OiBpYW0gfSwge30pLFxuICAgICAgICBwYWdlID0+IHBhZ2UuUm9sZXMsXG4gICAgICAgIHJvbGUgPT4gcm9sZS5Sb2xlTmFtZSxcbiAgICAgICAgUm9sZU5hbWUgPT4gYXdzRmFhc3QuZGVsZXRlUm9sZShSb2xlTmFtZSwgaWFtKVxuICAgICk7XG5cbiAgICBvdXRwdXQoYElBTSB0ZXN0IHJvbGVzYCk7XG4gICAgYXdhaXQgZGVsZXRlQVdTUmVzb3VyY2UoXG4gICAgICAgIFwiSUFNIHRlc3Qgcm9sZShzKVwiLFxuICAgICAgICBuZXcgUmVnRXhwKGBeZmFhc3QtdGVzdC0uKiR7dXVpZHY0UGF0dGVybn0kYCksXG4gICAgICAgICgpID0+IHBhZ2luYXRlTGlzdFJvbGVzKHsgY2xpZW50OiBpYW0gfSwge30pLFxuICAgICAgICBwYWdlID0+IHBhZ2UuUm9sZXMsXG4gICAgICAgIHJvbGUgPT4gcm9sZS5Sb2xlTmFtZSxcbiAgICAgICAgUm9sZU5hbWUgPT4gYXdzRmFhc3QuZGVsZXRlUm9sZShSb2xlTmFtZSwgaWFtKVxuICAgICk7XG5cbiAgICBvdXRwdXQoYExhbWJkYSBsYXllcnNgKTtcblxuICAgIGF3YWl0IGRlbGV0ZUFXU1Jlc291cmNlKFxuICAgICAgICBcIkxhbWJkYSBsYXllcihzKVwiLFxuICAgICAgICBuZXcgUmVnRXhwKGBeZmFhc3QtKCR7dXVpZHY0UGF0dGVybn0pfChbYS1mMC05XXs2NH0pYCksXG4gICAgICAgICgpID0+IHBhZ2luYXRlTGlzdExheWVycyh7IGNsaWVudDogbGFtYmRhIH0sIHsgQ29tcGF0aWJsZVJ1bnRpbWU6IFwibm9kZWpzXCIgfSksXG4gICAgICAgIHBhZ2UgPT4gcGFnZS5MYXllcnMsXG4gICAgICAgIGxheWVyID0+IGxheWVyLkxheWVyTmFtZSxcbiAgICAgICAgYXN5bmMgTGF5ZXJOYW1lID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHZlcnNpb25zID0gYXdhaXQgbGFtYmRhLmxpc3RMYXllclZlcnNpb25zKHsgTGF5ZXJOYW1lIH0pO1xuICAgICAgICAgICAgZm9yIChjb25zdCBsYXllclZlcnNpb24gb2YgdmVyc2lvbnMuTGF5ZXJWZXJzaW9ucyB8fCBbXSkge1xuICAgICAgICAgICAgICAgIGF3YWl0IGxhbWJkYS5kZWxldGVMYXllclZlcnNpb24oe1xuICAgICAgICAgICAgICAgICAgICBMYXllck5hbWUsXG4gICAgICAgICAgICAgICAgICAgIFZlcnNpb25OdW1iZXI6IGxheWVyVmVyc2lvbi5WZXJzaW9uIVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgKTtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIGNsZWFudXBDYWNoZURpcihjYWNoZTogUGVyc2lzdGVudENhY2hlKSB7XG4gICAgICAgIG91dHB1dChgUGVyc2lzdGVudCBjYWNoZTogJHtjYWNoZS5kaXJ9YCk7XG4gICAgICAgIGNvbnN0IGVudHJpZXMgPSBhd2FpdCBjYWNoZS5lbnRyaWVzKCk7XG4gICAgICAgIGlmICghZXhlY3V0ZSkge1xuICAgICAgICAgICAgb3V0cHV0KGAgIGNhY2hlIGVudHJpZXM6ICR7ZW50cmllcy5sZW5ndGh9YCk7XG4gICAgICAgIH1cbiAgICAgICAgblJlc291cmNlcyArPSBlbnRyaWVzLmxlbmd0aDtcbiAgICAgICAgaWYgKGV4ZWN1dGUpIHtcbiAgICAgICAgICAgIGNhY2hlLmNsZWFyKHsgbGVhdmVFbXB0eURpcjogZmFsc2UgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGNhY2hlIG9mIGtleXNPZihjYWNoZXMpKSB7XG4gICAgICAgIGF3YWl0IGNsZWFudXBDYWNoZURpcihhd2FpdCBjYWNoZXNbY2FjaGVdKTtcbiAgICB9XG5cbiAgICBvdXRwdXQoYENsb3Vkd2F0Y2ggbG9nIGdyb3Vwc2ApO1xuICAgIGF3YWl0IGRlbGV0ZUFXU1Jlc291cmNlKFxuICAgICAgICBcIkNsb3Vkd2F0Y2ggbG9nIGdyb3VwKHMpXCIsXG4gICAgICAgIG5ldyBSZWdFeHAoYC9mYWFzdC0ke3V1aWR2NFBhdHRlcm59JGApLFxuICAgICAgICAoKSA9PiBwYWdpbmF0ZURlc2NyaWJlTG9nR3JvdXBzKHsgY2xpZW50OiBjbG91ZHdhdGNoIH0sIHt9KSxcbiAgICAgICAgcGFnZSA9PiBwYWdlLmxvZ0dyb3VwcyxcbiAgICAgICAgbG9nR3JvdXAgPT4gbG9nR3JvdXAubG9nR3JvdXBOYW1lLFxuICAgICAgICBsb2dHcm91cE5hbWUgPT4gY2xvdWR3YXRjaC5kZWxldGVMb2dHcm91cCh7IGxvZ0dyb3VwTmFtZSB9KVxuICAgICk7XG5cbiAgICByZXR1cm4gblJlc291cmNlcztcbn1cblxuYXN5bmMgZnVuY3Rpb24gY2xlYW51cExvY2FsKHsgZXhlY3V0ZSB9OiBDbGVhbnVwT3B0aW9ucykge1xuICAgIGNvbnN0IG91dHB1dCA9IChtc2c6IHN0cmluZykgPT4gIWV4ZWN1dGUgJiYgbG9nKG1zZyk7XG4gICAgY29uc3QgdG1wRGlyID0gdG1wZGlyKCk7XG4gICAgY29uc3QgZGlyID0gYXdhaXQgcmVhZGRpcih0bXBEaXIpO1xuICAgIGxldCBuUmVzb3VyY2VzID0gMDtcbiAgICBvdXRwdXQoYFRlbXBvcmFyeSBkaXJlY3RvcmllczpgKTtcbiAgICBjb25zdCBlbnRyeVJlZ2V4cCA9IG5ldyBSZWdFeHAoYF5mYWFzdC0ke3V1aWR2NFBhdHRlcm59JGApO1xuICAgIGZvciAoY29uc3QgZW50cnkgb2YgZGlyKSB7XG4gICAgICAgIGlmIChlbnRyeS5tYXRjaChlbnRyeVJlZ2V4cCkpIHtcbiAgICAgICAgICAgIG5SZXNvdXJjZXMrKztcbiAgICAgICAgICAgIGNvbnN0IGZhYXN0RGlyID0gcGF0aC5qb2luKHRtcERpciwgZW50cnkpO1xuICAgICAgICAgICAgb3V0cHV0KGAke2ZhYXN0RGlyfWApO1xuICAgICAgICAgICAgaWYgKGV4ZWN1dGUpIHtcbiAgICAgICAgICAgICAgICBhd2FpdCByZW1vdmUoZmFhc3REaXIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBuUmVzb3VyY2VzO1xufVxuXG5hc3luYyBmdW5jdGlvbiBwcm9tcHQoKSB7XG4gICAgY29uc3QgcmwgPSByZWFkbGluZS5jcmVhdGVJbnRlcmZhY2Uoe1xuICAgICAgICBpbnB1dDogcHJvY2Vzcy5zdGRpbixcbiAgICAgICAgb3V0cHV0OiBwcm9jZXNzLnN0ZG91dFxuICAgIH0pO1xuXG4gICAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4ocmVzb2x2ZSA9PiB7XG4gICAgICAgIHJsLnF1ZXN0aW9uKFxuICAgICAgICAgICAgXCJXQVJOSU5HOiB0aGlzIG9wZXJhdGlvbiB3aWxsIGRlbGV0ZSByZXNvdXJjZXMuIENvbmZpcm0/IFt5L05dIFwiLFxuICAgICAgICAgICAgYW5zd2VyID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoYW5zd2VyICE9PSBcInlcIikge1xuICAgICAgICAgICAgICAgICAgICBsb2coYEV4ZWN1dGlvbiBhYm9ydGVkLmApO1xuICAgICAgICAgICAgICAgICAgICBwcm9jZXNzLmV4aXQoMCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJsLmNsb3NlKCk7XG4gICAgICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH0pO1xufVxuXG5hc3luYyBmdW5jdGlvbiBydW5DbGVhbnVwKGNsb3VkOiBzdHJpbmcsIG9wdGlvbnM6IENsZWFudXBPcHRpb25zKSB7XG4gICAgbGV0IG5SZXNvdXJjZXMgPSAwO1xuICAgIGlmIChjbG91ZCA9PT0gXCJhd3NcIikge1xuICAgICAgICBuUmVzb3VyY2VzID0gYXdhaXQgY2xlYW51cEFXUyhvcHRpb25zKTtcbiAgICB9IGVsc2UgaWYgKGNsb3VkID09PSBcImxvY2FsXCIpIHtcbiAgICAgICAgblJlc291cmNlcyA9IGF3YWl0IGNsZWFudXBMb2NhbChvcHRpb25zKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB3YXJuKGBVbmtub3duIGNsb3VkIG5hbWUgXCIke2Nsb3VkfVwiLiBNdXN0IHNwZWNpZnkgXCJhd3NcIiBvciBcImxvY2FsXCIuYCk7XG4gICAgICAgIHByb2Nlc3MuZXhpdCgtMSk7XG4gICAgfVxuICAgIGlmIChvcHRpb25zLmV4ZWN1dGUpIHtcbiAgICAgICAgbG9nKGBEb25lLmApO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChuUmVzb3VyY2VzID09PSAwKSB7XG4gICAgICAgICAgICBsb2coYE5vIHJlc291cmNlcyB0byBjbGVhbiB1cC5gKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gblJlc291cmNlcztcbn1cblxuYXN5bmMgZnVuY3Rpb24gbWFpbigpIHtcbiAgICBsZXQgY2xvdWQhOiBzdHJpbmc7XG4gICAgbGV0IGNvbW1hbmQ6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICBwcm9ncmFtXG4gICAgICAgIC52ZXJzaW9uKFwiMC4xLjBcIilcbiAgICAgICAgLm9wdGlvbihcIi12LCAtLXZlcmJvc2VcIiwgXCJWZXJib3NlIG1vZGVcIilcbiAgICAgICAgLm9wdGlvbihcbiAgICAgICAgICAgIFwiLXIsIC0tcmVnaW9uIDxyZWdpb24+XCIsXG4gICAgICAgICAgICBcIkNsb3VkIHJlZ2lvbiB0byBvcGVyYXRlIG9uLiBEZWZhdWx0cyB0byB1cy13ZXN0LTIgZm9yIEFXUy5cIlxuICAgICAgICApXG4gICAgICAgIC5vcHRpb24oXG4gICAgICAgICAgICBcIi14LCAtLWV4ZWN1dGVcIixcbiAgICAgICAgICAgIFwiRXhlY3V0ZSB0aGUgY2xlYW51cCBwcm9jZXNzLiBJZiB0aGlzIG9wdGlvbiBpcyBub3Qgc3BlY2lmaWVkLCB0aGUgb3V0cHV0IHdpbGwgYmUgYSBkcnkgcnVuLlwiXG4gICAgICAgIClcbiAgICAgICAgLm9wdGlvbihcIi1mLCAtLWZvcmNlXCIsIFwiV2hlbiB1c2VkIHdpdGggLXgsIHNraXBzIHRoZSBwcm9tcHRcIilcbiAgICAgICAgLmNvbW1hbmQoXCJjbGVhbnVwIDxjbG91ZD5cIilcbiAgICAgICAgLmRlc2NyaXB0aW9uKFxuICAgICAgICAgICAgYENsZWFudXAgZmFhc3QuanMgcmVzb3VyY2VzIHRoYXQgbWF5IGhhdmUgbGVha2VkLiBUaGUgPGNsb3VkPiBhcmd1bWVudCBtdXN0IGJlIFwiYXdzXCIgb3IgXCJsb2NhbFwiLlxuICAgICAgICBCeSBkZWZhdWx0IHRoZSBvdXRwdXQgaXMgYSBkcnkgcnVuIGFuZCB3aWxsIG9ubHkgcHJpbnQgdGhlIGFjdGlvbnMgdGhhdCB3b3VsZCBiZSBwZXJmb3JtZWQgaWYgJy14JyBpcyBzcGVjaWZpZWQuYFxuICAgICAgICApXG4gICAgICAgIC5hY3Rpb24oKGFyZzogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICBjb21tYW5kID0gXCJjbGVhbnVwXCI7XG4gICAgICAgICAgICBjbG91ZCA9IGFyZztcbiAgICAgICAgfSk7XG5cbiAgICBjb25zdCBvcHRzID0gcHJvZ3JhbS5wYXJzZShwcm9jZXNzLmFyZ3YpLm9wdHMoKTtcbiAgICBpZiAob3B0cy52ZXJib3NlKSB7XG4gICAgICAgIHByb2Nlc3MuZW52LkRFQlVHID0gXCJmYWFzdDoqXCI7XG4gICAgfVxuICAgIGNvbnN0IGV4ZWN1dGUgPSBvcHRzLmV4ZWN1dGUgfHwgZmFsc2U7XG4gICAgbGV0IHJlZ2lvbiA9IG9wdHMucmVnaW9uO1xuXG4gICAgaWYgKCFyZWdpb24pIHtcbiAgICAgICAgc3dpdGNoIChjbG91ZCkge1xuICAgICAgICAgICAgY2FzZSBcImF3c1wiOlxuICAgICAgICAgICAgICAgIHJlZ2lvbiA9IGF3c0ZhYXN0LmRlZmF1bHRzLnJlZ2lvbjtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgIH1cbiAgICBjb25zdCBmb3JjZSA9IG9wdHMuZm9yY2UgfHwgZmFsc2U7XG5cbiAgICByZWdpb24gJiYgbG9nKGBSZWdpb246ICR7cmVnaW9ufWApO1xuICAgIGNvbnN0IG9wdGlvbnMgPSB7IHJlZ2lvbiwgZXhlY3V0ZSB9O1xuICAgIGxldCBuUmVzb3VyY2VzID0gMDtcbiAgICBpZiAoY29tbWFuZCA9PT0gXCJjbGVhbnVwXCIpIHtcbiAgICAgICAgaWYgKGV4ZWN1dGUgJiYgIWZvcmNlKSB7XG4gICAgICAgICAgICBuUmVzb3VyY2VzID0gYXdhaXQgcnVuQ2xlYW51cChjbG91ZCwgeyAuLi5vcHRpb25zLCBleGVjdXRlOiBmYWxzZSB9KTtcbiAgICAgICAgICAgIGlmIChuUmVzb3VyY2VzID4gMCkge1xuICAgICAgICAgICAgICAgIGF3YWl0IHByb21wdCgpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwcm9jZXNzLmV4aXQoMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgblJlc291cmNlcyA9IGF3YWl0IHJ1bkNsZWFudXAoY2xvdWQsIG9wdGlvbnMpO1xuICAgICAgICBpZiAoIWV4ZWN1dGUgJiYgblJlc291cmNlcyA+IDApIHtcbiAgICAgICAgICAgIGxvZyhcbiAgICAgICAgICAgICAgICBgKGRyeXJ1biBtb2RlLCBubyByZXNvdXJjZXMgd2lsbCBiZSBkZWxldGVkLCBzcGVjaWZ5IC14IHRvIGV4ZWN1dGUgY2xlYW51cClgXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgICAgbG9nKGBObyBjb21tYW5kIHNwZWNpZmllZC5gKTtcbiAgICAgICAgcHJvZ3JhbS5oZWxwKCk7XG4gICAgfVxufVxuXG5tYWluKCk7XG4iXX0=