UNPKG

faastjs

Version:

Serverless batch computing made simple.

239 lines 41.9 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBRUEsT0FBTyxDQUFDLG9CQUFvQixDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7QUFDeEMsNEVBQTRFO0FBQzVFLG9EQUF3RDtBQUN4RCwwREFBbUY7QUFDbkYsb0RBQW9GO0FBQ3BGLG9EQUF5RDtBQUV6RCx5Q0FBb0M7QUFDcEMsdUNBQTJDO0FBQzNDLHNEQUFzQjtBQUN0QiwyQkFBNEI7QUFDNUIsd0RBQXdCO0FBQ3hCLDJEQUFxQztBQUNyQyxrRUFBNEM7QUFDNUMsbUNBQWtEO0FBQ2xELHFDQUFpRDtBQUNqRCx5Q0FBc0M7QUFFdEMsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztBQUMxQixNQUFNLEdBQUcsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDO0FBT3hCLEtBQUssVUFBVSxlQUFlLENBQzFCLElBQVksRUFDWixpQkFBMkIsRUFDM0IsUUFBdUMsRUFDdkMsRUFBRSxXQUFXLEdBQUcsRUFBRSxFQUFFLElBQUksR0FBRyxDQUFDLEVBQUUsS0FBSyxHQUFHLENBQUMsRUFBRSxHQUFHLEVBQUU7SUFFOUMsSUFBSSxpQkFBaUIsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDL0IsTUFBTSxZQUFZLEdBQUcsQ0FBQyxVQUFrQixFQUFFLEVBQUUsQ0FDeEMsVUFBVSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsVUFBVSxHQUFHLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQ3BFLE1BQU0saUJBQWlCLEdBQUcsQ0FBQyxhQUFxQixDQUFDLEVBQUUsRUFBRSxDQUNqRCxZQUFZLGlCQUFpQixDQUFDLE1BQU0sSUFBSSxJQUFJLElBQUksWUFBWSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7UUFD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LEtBQUssSUFBSSxLQUFLLENBQUM7SUFFbEMsTUFBTSxJQUFJLEdBQUcsQ0FBQyxXQUFXLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDbkMsTUFBTSxPQUFPLEdBQUcsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLENBQUM7SUFDcEMsSUFBSSxVQUFVLEdBQUcsQ0FBQyxDQUFDO0lBQ25CLElBQUksT0FBTyxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ3hCLElBQUksT0FBTyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDcEIsVUFBVSxHQUFHLE1BQU0sVUFBVSxDQUFDLEtBQUssRUFBRSxFQUFFLEdBQUcsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQ3JFLElBQUksVUFBVSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNqQixNQUFNLE1BQU0sRUFBRSxDQUFDO1lBQ25CLENBQUM7aUJBQU0sQ0FBQztnQkFDSixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3BCLENBQUM7UUFDTCxDQUFDO1FBQ0QsVUFBVSxHQUFHLE1BQU0sVUFBVSxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztRQUM5QyxJQUFJLENBQUMsT0FBTyxJQUFJLFVBQVUsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUM3QixHQUFHLENBQ0MsNEVBQTRFLENBQy9FLENBQUM7UUFDTixDQUFDO0lBQ0wsQ0FBQztTQUFNLENBQUM7UUFDSixHQUFHLENBQUMsdUJBQXVCLENBQUMsQ0FBQztRQUM3QixtQkFBTyxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ25CLENBQUM7QUFDTCxDQUFDO0FBRUQsSUFBSSxFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIjIS91c3IvYmluL2VudiBub2RlXG5cbnJlcXVpcmUoXCJzb3VyY2UtbWFwLXN1cHBvcnRcIikuaW5zdGFsbCgpO1xuaW1wb3J0IHsgcGFnaW5hdGVEZXNjcmliZUxvZ0dyb3VwcyB9IGZyb20gXCJAYXdzLXNkay9jbGllbnQtY2xvdWR3YXRjaC1sb2dzXCI7XG5pbXBvcnQgeyBwYWdpbmF0ZUxpc3RSb2xlcyB9IGZyb20gXCJAYXdzLXNkay9jbGllbnQtaWFtXCI7XG5pbXBvcnQgeyBwYWdpbmF0ZUxpc3RGdW5jdGlvbnMsIHBhZ2luYXRlTGlzdExheWVycyB9IGZyb20gXCJAYXdzLXNkay9jbGllbnQtbGFtYmRhXCI7XG5pbXBvcnQgeyBwYWdpbmF0ZUxpc3RTdWJzY3JpcHRpb25zLCBwYWdpbmF0ZUxpc3RUb3BpY3MgfSBmcm9tIFwiQGF3cy1zZGsvY2xpZW50LXNuc1wiO1xuaW1wb3J0IHsgcGFnaW5hdGVMaXN0UXVldWVzIH0gZnJvbSBcIkBhd3Mtc2RrL2NsaWVudC1zcXNcIjtcbmltcG9ydCB7IFBhZ2luYXRvciB9IGZyb20gXCJAYXdzLXNkay90eXBlc1wiO1xuaW1wb3J0IHsgcHJvZ3JhbSB9IGZyb20gXCJjb21tYW5kZXJcIjtcbmltcG9ydCB7IHJlYWRkaXIsIHJlbW92ZSB9IGZyb20gXCJmcy1leHRyYVwiO1xuaW1wb3J0IG9yYSBmcm9tIFwib3JhXCI7XG5pbXBvcnQgeyB0bXBkaXIgfSBmcm9tIFwib3NcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgKiBhcyByZWFkbGluZSBmcm9tIFwicmVhZGxpbmVcIjtcbmltcG9ydCAqIGFzIGF3c0ZhYXN0IGZyb20gXCIuL2F3cy9hd3MtZmFhc3RcIjtcbmltcG9ydCB7IFBlcnNpc3RlbnRDYWNoZSwgY2FjaGVzIH0gZnJvbSBcIi4vY2FjaGVcIjtcbmltcG9ydCB7IGtleXNPZiwgdXVpZHY0UGF0dGVybiB9IGZyb20gXCIuL3NoYXJlZFwiO1xuaW1wb3J0IHsgdGhyb3R0bGUgfSBmcm9tIFwiLi90aHJvdHRsZVwiO1xuXG5jb25zdCB3YXJuID0gY29uc29sZS53YXJuO1xuY29uc3QgbG9nID0gY29uc29sZS5sb2c7XG5cbmludGVyZmFjZSBDbGVhbnVwT3B0aW9ucyB7XG4gICAgcmVnaW9uPzogc3RyaW5nOyAvLyBBV1Mgb25seS5cbiAgICBleGVjdXRlOiBib29sZWFuO1xufVxuXG5hc3luYyBmdW5jdGlvbiBkZWxldGVSZXNvdXJjZXMoXG4gICAgbmFtZTogc3RyaW5nLFxuICAgIG1hdGNoaW5nUmVzb3VyY2VzOiBzdHJpbmdbXSxcbiAgICBkb1JlbW92ZTogKGFyZzogc3RyaW5nKSA9PiBQcm9taXNlPGFueT4sXG4gICAgeyBjb25jdXJyZW5jeSA9IDEwLCByYXRlID0gNSwgYnVyc3QgPSA1IH0gPSB7fVxuKSB7XG4gICAgaWYgKG1hdGNoaW5nUmVzb3VyY2VzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgY29uc3QgdGltZUVzdGltYXRlID0gKG5SZXNvdXJjZXM6IG51bWJlcikgPT5cbiAgICAgICAgICAgIG5SZXNvdXJjZXMgPD0gNSA/IFwiXCIgOiBgKGVzdDogJHsoblJlc291cmNlcyAvIDUpLnRvRml4ZWQoMCl9cylgO1xuICAgICAgICBjb25zdCB1cGRhdGVTcGlubmVyVGV4dCA9IChuUmVzb3VyY2VzOiBudW1iZXIgPSAwKSA9PlxuICAgICAgICAgICAgYERlbGV0aW5nICR7bWF0Y2hpbmdSZXNvdXJjZXMubGVuZ3RofSAke25hbWV9ICR7dGltZUVzdGltYXRlKG5SZXNvdXJjZXMpfWA7XG4gICAgICAgIGNvbnN0IHNwaW5uZXIgPSBvcmEodXBkYXRlU3Bpbm5lclRleHQobWF0Y2hpbmdSZXNvdXJjZXMubGVuZ3RoKSkuc3RhcnQoKTtcbiAgICAgICAgbGV0IGRvbmUgPSAwO1xuICAgICAgICBjb25zdCBzY2hlZHVsZVJlbW92ZSA9IHRocm90dGxlKFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGNvbmN1cnJlbmN5LFxuICAgICAgICAgICAgICAgIHJhdGUsXG4gICAgICAgICAgICAgICAgYnVyc3QsXG4gICAgICAgICAgICAgICAgcmV0cnk6IDVcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBhc3luYyBhcmcgPT4ge1xuICAgICAgICAgICAgICAgIGF3YWl0IGRvUmVtb3ZlKGFyZyk7XG4gICAgICAgICAgICAgICAgZG9uZSsrO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgICAgICBjb25zdCB0aW1lciA9IHNldEludGVydmFsKFxuICAgICAgICAgICAgKCkgPT4gKHNwaW5uZXIudGV4dCA9IHVwZGF0ZVNwaW5uZXJUZXh0KG1hdGNoaW5nUmVzb3VyY2VzLmxlbmd0aCAtIGRvbmUpKSxcbiAgICAgICAgICAgIDEwMDBcbiAgICAgICAgKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICAgICAgICAgIG1hdGNoaW5nUmVzb3VyY2VzLm1hcChyZXNvdXJjZSA9PlxuICAgICAgICAgICAgICAgICAgICBzY2hlZHVsZVJlbW92ZShyZXNvdXJjZSkuY2F0Y2goZXJyID0+XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oYENvdWxkIG5vdCByZW1vdmUgcmVzb3VyY2UgJHtyZXNvdXJjZX06ICR7ZXJyfWApXG4gICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICApO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgY2xlYXJJbnRlcnZhbCh0aW1lcik7XG4gICAgICAgICAgICBzcGlubmVyLnRleHQgPSB1cGRhdGVTcGlubmVyVGV4dCgpO1xuICAgICAgICB9XG4gICAgICAgIHNwaW5uZXIuc3RvcEFuZFBlcnNpc3QoeyBzeW1ib2w6IFwi4pyUXCIgfSk7XG4gICAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBjbGVhbnVwQVdTKHsgcmVnaW9uLCBleGVjdXRlIH06IENsZWFudXBPcHRpb25zKSB7XG4gICAgbGV0IG5SZXNvdXJjZXMgPSAwO1xuICAgIGNvbnN0IG91dHB1dCA9IChtc2c6IHN0cmluZykgPT4gIWV4ZWN1dGUgJiYgbG9nKG1zZyk7XG4gICAgY29uc3QgeyBjbG91ZHdhdGNoLCBpYW0sIGxhbWJkYSwgc25zLCBzcXMsIHMzIH0gPSBhd2FpdCBhd3NGYWFzdC5jcmVhdGVBd3NBcGlzKFxuICAgICAgICByZWdpb24hIGFzIGF3c0ZhYXN0LkF3c1JlZ2lvblxuICAgICk7XG5cbiAgICBhc3luYyBmdW5jdGlvbiBsaXN0QVdTUmVzb3VyY2U8VCwgVT4oXG4gICAgICAgIHBhdHRlcm46IFJlZ0V4cCxcbiAgICAgICAgZ2V0TGlzdDogKCkgPT4gUGFnaW5hdG9yPFQ+LFxuICAgICAgICBleHRyYWN0TGlzdDogKGFyZzogVCkgPT4gVVtdIHwgdW5kZWZpbmVkLFxuICAgICAgICBleHRyYWN0RWxlbWVudDogKGFyZzogVSkgPT4gc3RyaW5nIHwgdW5kZWZpbmVkXG4gICAgKSB7XG4gICAgICAgIGNvbnN0IGFsbFJlc291cmNlczogc3RyaW5nW10gPSBbXTtcbiAgICAgICAgZm9yIGF3YWl0IChjb25zdCBwYWdlIG9mIGdldExpc3QoKSkge1xuICAgICAgICAgICAgY29uc3QgZWxlbXMgPSAocGFnZSAmJiBleHRyYWN0TGlzdChwYWdlKSkgfHwgW107XG4gICAgICAgICAgICBhbGxSZXNvdXJjZXMucHVzaCguLi5lbGVtcy5tYXAoZWxlbSA9PiBleHRyYWN0RWxlbWVudChlbGVtKSB8fCBcIlwiKSk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgbWF0Y2hpbmdSZXNvdXJjZXMgPSBhbGxSZXNvdXJjZXMuZmlsdGVyKHQgPT4gdC5tYXRjaChwYXR0ZXJuKSk7XG4gICAgICAgIG1hdGNoaW5nUmVzb3VyY2VzLmZvckVhY2gocmVzb3VyY2UgPT4gb3V0cHV0KGAgICR7cmVzb3VyY2V9YCkpO1xuICAgICAgICByZXR1cm4gbWF0Y2hpbmdSZXNvdXJjZXM7XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gZGVsZXRlQVdTUmVzb3VyY2U8VCwgVT4oXG4gICAgICAgIG5hbWU6IHN0cmluZyxcbiAgICAgICAgcGF0dGVybjogUmVnRXhwLFxuICAgICAgICBnZXRMaXN0OiAoKSA9PiBQYWdpbmF0b3I8VD4sXG4gICAgICAgIGV4dHJhY3RMaXN0OiAoYXJnOiBUKSA9PiBVW10gfCB1bmRlZmluZWQsXG4gICAgICAgIGV4dHJhY3RFbGVtZW50OiAoYXJnOiBVKSA9PiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gICAgICAgIGRvUmVtb3ZlOiAoYXJnOiBzdHJpbmcpID0+IFByb21pc2U8YW55PlxuICAgICkge1xuICAgICAgICBjb25zdCBhbGxSZXNvdXJjZXMgPSBhd2FpdCBsaXN0QVdTUmVzb3VyY2UoXG4gICAgICAgICAgICBwYXR0ZXJuLFxuICAgICAgICAgICAgZ2V0TGlzdCxcbiAgICAgICAgICAgIGV4dHJhY3RMaXN0LFxuICAgICAgICAgICAgZXh0cmFjdEVsZW1lbnRcbiAgICAgICAgKTtcbiAgICAgICAgblJlc291cmNlcyArPSBhbGxSZXNvdXJjZXMubGVuZ3RoO1xuICAgICAgICBpZiAoZXhlY3V0ZSkge1xuICAgICAgICAgICAgYXdhaXQgZGVsZXRlUmVzb3VyY2VzKG5hbWUsIGFsbFJlc291cmNlcywgZG9SZW1vdmUsIHtcbiAgICAgICAgICAgICAgICBjb25jdXJyZW5jeTogMTAsXG4gICAgICAgICAgICAgICAgcmF0ZTogNSxcbiAgICAgICAgICAgICAgICBidXJzdDogNVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBvdXRwdXQoYFNOUyBzdWJzY3JpcHRpb25zYCk7XG4gICAgYXdhaXQgZGVsZXRlQVdTUmVzb3VyY2UoXG4gICAgICAgIFwiU05TIHN1YnNjcmlwdGlvbihzKVwiLFxuICAgICAgICBuZXcgUmVnRXhwKGA6ZmFhc3QtJHt1dWlkdjRQYXR0ZXJufWApLFxuICAgICAgICAoKSA9PiBwYWdpbmF0ZUxpc3RTdWJzY3JpcHRpb25zKHsgY2xpZW50OiBzbnMgfSwge30pLFxuICAgICAgICBwYWdlID0+IHBhZ2UuU3Vic2NyaXB0aW9ucyxcbiAgICAgICAgc3Vic2NyaXB0aW9uID0+IHN1YnNjcmlwdGlvbi5TdWJzY3JpcHRpb25Bcm4sXG4gICAgICAgIFN1YnNjcmlwdGlvbkFybiA9PiBzbnMudW5zdWJzY3JpYmUoeyBTdWJzY3JpcHRpb25Bcm4gfSlcbiAgICApO1xuXG4gICAgb3V0cHV0KGBTTlMgdG9waWNzYCk7XG4gICAgYXdhaXQgZGVsZXRlQVdTUmVzb3VyY2UoXG4gICAgICAgIFwiU05TIHRvcGljKHMpXCIsXG4gICAgICAgIG5ldyBSZWdFeHAoYDpmYWFzdC0ke3V1aWR2NFBhdHRlcm59YCksXG4gICAgICAgICgpID0+IHBhZ2luYXRlTGlzdFRvcGljcyh7IGNsaWVudDogc25zIH0sIHt9KSxcbiAgICAgICAgcGFnZSA9PiBwYWdlLlRvcGljcyxcbiAgICAgICAgdG9waWMgPT4gdG9waWMuVG9waWNBcm4sXG4gICAgICAgIFRvcGljQXJuID0+IHNucy5kZWxldGVUb3BpYyh7IFRvcGljQXJuIH0pXG4gICAgKTtcblxuICAgIG91dHB1dChgU1FTIHF1ZXVlc2ApO1xuICAgIGF3YWl0IGRlbGV0ZUFXU1Jlc291cmNlKFxuICAgICAgICBcIlNRUyBxdWV1ZShzKVwiLFxuICAgICAgICBuZXcgUmVnRXhwKGAvZmFhc3QtJHt1dWlkdjRQYXR0ZXJufWApLFxuICAgICAgICAoKSA9PiBwYWdpbmF0ZUxpc3RRdWV1ZXMoeyBjbGllbnQ6IHNxcyB9LCB7fSksXG4gICAgICAgIHBhZ2UgPT4gcGFnZS5RdWV1ZVVybHMsXG4gICAgICAgIHF1ZXVlVXJsID0+IHF1ZXVlVXJsLFxuICAgICAgICBRdWV1ZVVybCA9PiBzcXMuZGVsZXRlUXVldWUoeyBRdWV1ZVVybCB9KVxuICAgICk7XG5cbiAgICBhc3luYyBmdW5jdGlvbiogbGlzdEJ1Y2tldHMoKSB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IHMzLmxpc3RCdWNrZXRzKHt9KTtcbiAgICAgICAgeWllbGQgcmVzdWx0O1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIG91dHB1dChgUzMgYnVja2V0c2ApO1xuICAgIGF3YWl0IGRlbGV0ZUFXU1Jlc291cmNlKFxuICAgICAgICBcIlMzIGJ1Y2tldChzKVwiLFxuICAgICAgICBuZXcgUmVnRXhwKGBeZmFhc3QtJHt1dWlkdjRQYXR0ZXJufWApLFxuICAgICAgICAoKSA9PiBsaXN0QnVja2V0cygpLFxuICAgICAgICBwYWdlID0+IHBhZ2UuQnVja2V0cyxcbiAgICAgICAgQnVja2V0ID0+IEJ1Y2tldC5OYW1lLFxuICAgICAgICBhc3luYyBCdWNrZXQgPT4ge1xuICAgICAgICAgICAgY29uc3Qgb2JqZWN0cyA9IGF3YWl0IHMzLmxpc3RPYmplY3RzVjIoeyBCdWNrZXQsIFByZWZpeDogXCJmYWFzdC1cIiB9KTtcbiAgICAgICAgICAgIGNvbnN0IGtleXMgPSAob2JqZWN0cy5Db250ZW50cyB8fCBbXSkubWFwKGVudHJ5ID0+ICh7IEtleTogZW50cnkuS2V5ISB9KSk7XG4gICAgICAgICAgICBpZiAoa2V5cy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgczMuZGVsZXRlT2JqZWN0cyh7IEJ1Y2tldCwgRGVsZXRlOiB7IE9iamVjdHM6IGtleXMgfSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGF3YWl0IHMzLmRlbGV0ZUJ1Y2tldCh7IEJ1Y2tldCB9KTtcbiAgICAgICAgfVxuICAgICk7XG5cbiAgICBvdXRwdXQoYExhbWJkYSBmdW5jdGlvbnNgKTtcbiAgICBhd2FpdCBkZWxldGVBV1NSZXNvdXJjZShcbiAgICAgICAgXCJMYW1iZGEgZnVuY3Rpb24ocylcIixcbiAgICAgICAgbmV3IFJlZ0V4cChgXmZhYXN0LSR7dXVpZHY0UGF0dGVybn1gKSxcbiAgICAgICAgKCkgPT4gcGFnaW5hdGVMaXN0RnVuY3Rpb25zKHsgY2xpZW50OiBsYW1iZGEgfSwge30pLFxuICAgICAgICBwYWdlID0+IHBhZ2UuRnVuY3Rpb25zLFxuICAgICAgICBmdW5jID0+IGZ1bmMuRnVuY3Rpb25OYW1lLFxuICAgICAgICBGdW5jdGlvbk5hbWUgPT4gbGFtYmRhLmRlbGV0ZUZ1bmN0aW9uKHsgRnVuY3Rpb25OYW1lIH0pXG4gICAgKTtcblxuICAgIG91dHB1dChgSUFNIHJvbGVzYCk7XG4gICAgYXdhaXQgZGVsZXRlQVdTUmVzb3VyY2UoXG4gICAgICAgIFwiSUFNIHJvbGUocylcIixcbiAgICAgICAgL15mYWFzdC1jYWNoZWQtbGFtYmRhLXJvbGUkLyxcbiAgICAgICAgKCkgPT4gcGFnaW5hdGVMaXN0Um9sZXMoeyBjbGllbnQ6IGlhbSB9LCB7fSksXG4gICAgICAgIHBhZ2UgPT4gcGFnZS5Sb2xlcyxcbiAgICAgICAgcm9sZSA9PiByb2xlLlJvbGVOYW1lLFxuICAgICAgICBSb2xlTmFtZSA9PiBhd3NGYWFzdC5kZWxldGVSb2xlKFJvbGVOYW1lLCBpYW0pXG4gICAgKTtcblxuICAgIG91dHB1dChgSUFNIHRlc3Qgcm9sZXNgKTtcbiAgICBhd2FpdCBkZWxldGVBV1NSZXNvdXJjZShcbiAgICAgICAgXCJJQU0gdGVzdCByb2xlKHMpXCIsXG4gICAgICAgIG5ldyBSZWdFeHAoYF5mYWFzdC10ZXN0LS4qJHt1dWlkdjRQYXR0ZXJufSRgKSxcbiAgICAgICAgKCkgPT4gcGFnaW5hdGVMaXN0Um9sZXMoeyBjbGllbnQ6IGlhbSB9LCB7fSksXG4gICAgICAgIHBhZ2UgPT4gcGFnZS5Sb2xlcyxcbiAgICAgICAgcm9sZSA9PiByb2xlLlJvbGVOYW1lLFxuICAgICAgICBSb2xlTmFtZSA9PiBhd3NGYWFzdC5kZWxldGVSb2xlKFJvbGVOYW1lLCBpYW0pXG4gICAgKTtcblxuICAgIG91dHB1dChgTGFtYmRhIGxheWVyc2ApO1xuXG4gICAgYXdhaXQgZGVsZXRlQVdTUmVzb3VyY2UoXG4gICAgICAgIFwiTGFtYmRhIGxheWVyKHMpXCIsXG4gICAgICAgIG5ldyBSZWdFeHAoYF5mYWFzdC0oJHt1dWlkdjRQYXR0ZXJufSl8KFthLWYwLTldezY0fSlgKSxcbiAgICAgICAgKCkgPT4gcGFnaW5hdGVMaXN0TGF5ZXJzKHsgY2xpZW50OiBsYW1iZGEgfSwgeyBDb21wYXRpYmxlUnVudGltZTogXCJub2RlanNcIiB9KSxcbiAgICAgICAgcGFnZSA9PiBwYWdlLkxheWVycyxcbiAgICAgICAgbGF5ZXIgPT4gbGF5ZXIuTGF5ZXJOYW1lLFxuICAgICAgICBhc3luYyBMYXllck5hbWUgPT4ge1xuICAgICAgICAgICAgY29uc3QgdmVyc2lvbnMgPSBhd2FpdCBsYW1iZGEubGlzdExheWVyVmVyc2lvbnMoeyBMYXllck5hbWUgfSk7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGxheWVyVmVyc2lvbiBvZiB2ZXJzaW9ucy5MYXllclZlcnNpb25zIHx8IFtdKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgbGFtYmRhLmRlbGV0ZUxheWVyVmVyc2lvbih7XG4gICAgICAgICAgICAgICAgICAgIExheWVyTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgVmVyc2lvbk51bWJlcjogbGF5ZXJWZXJzaW9uLlZlcnNpb24hXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICApO1xuXG4gICAgYXN5bmMgZnVuY3Rpb24gY2xlYW51cENhY2hlRGlyKGNhY2hlOiBQZXJzaXN0ZW50Q2FjaGUpIHtcbiAgICAgICAgb3V0cHV0KGBQZXJzaXN0ZW50IGNhY2hlOiAke2NhY2hlLmRpcn1gKTtcbiAgICAgICAgY29uc3QgZW50cmllcyA9IGF3YWl0IGNhY2hlLmVudHJpZXMoKTtcbiAgICAgICAgaWYgKCFleGVjdXRlKSB7XG4gICAgICAgICAgICBvdXRwdXQoYCAgY2FjaGUgZW50cmllczogJHtlbnRyaWVzLmxlbmd0aH1gKTtcbiAgICAgICAgfVxuICAgICAgICBuUmVzb3VyY2VzICs9IGVudHJpZXMubGVuZ3RoO1xuICAgICAgICBpZiAoZXhlY3V0ZSkge1xuICAgICAgICAgICAgY2FjaGUuY2xlYXIoeyBsZWF2ZUVtcHR5RGlyOiBmYWxzZSB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZvciAoY29uc3QgY2FjaGUgb2Yga2V5c09mKGNhY2hlcykpIHtcbiAgICAgICAgYXdhaXQgY2xlYW51cENhY2hlRGlyKGF3YWl0IGNhY2hlc1tjYWNoZV0pO1xuICAgIH1cblxuICAgIG91dHB1dChgQ2xvdWR3YXRjaCBsb2cgZ3JvdXBzYCk7XG4gICAgYXdhaXQgZGVsZXRlQVdTUmVzb3VyY2UoXG4gICAgICAgIFwiQ2xvdWR3YXRjaCBsb2cgZ3JvdXAocylcIixcbiAgICAgICAgbmV3IFJlZ0V4cChgL2ZhYXN0LSR7dXVpZHY0UGF0dGVybn0kYCksXG4gICAgICAgICgpID0+IHBhZ2luYXRlRGVzY3JpYmVMb2dHcm91cHMoeyBjbGllbnQ6IGNsb3Vkd2F0Y2ggfSwge30pLFxuICAgICAgICBwYWdlID0+IHBhZ2UubG9nR3JvdXBzLFxuICAgICAgICBsb2dHcm91cCA9PiBsb2dHcm91cC5sb2dHcm91cE5hbWUsXG4gICAgICAgIGxvZ0dyb3VwTmFtZSA9PiBjbG91ZHdhdGNoLmRlbGV0ZUxvZ0dyb3VwKHsgbG9nR3JvdXBOYW1lIH0pXG4gICAgKTtcblxuICAgIHJldHVybiBuUmVzb3VyY2VzO1xufVxuXG5hc3luYyBmdW5jdGlvbiBjbGVhbnVwTG9jYWwoeyBleGVjdXRlIH06IENsZWFudXBPcHRpb25zKSB7XG4gICAgY29uc3Qgb3V0cHV0ID0gKG1zZzogc3RyaW5nKSA9PiAhZXhlY3V0ZSAmJiBsb2cobXNnKTtcbiAgICBjb25zdCB0bXBEaXIgPSB0bXBkaXIoKTtcbiAgICBjb25zdCBkaXIgPSBhd2FpdCByZWFkZGlyKHRtcERpcik7XG4gICAgbGV0IG5SZXNvdXJjZXMgPSAwO1xuICAgIG91dHB1dChgVGVtcG9yYXJ5IGRpcmVjdG9yaWVzOmApO1xuICAgIGNvbnN0IGVudHJ5UmVnZXhwID0gbmV3IFJlZ0V4cChgXmZhYXN0LSR7dXVpZHY0UGF0dGVybn0kYCk7XG4gICAgZm9yIChjb25zdCBlbnRyeSBvZiBkaXIpIHtcbiAgICAgICAgaWYgKGVudHJ5Lm1hdGNoKGVudHJ5UmVnZXhwKSkge1xuICAgICAgICAgICAgblJlc291cmNlcysrO1xuICAgICAgICAgICAgY29uc3QgZmFhc3REaXIgPSBwYXRoLmpvaW4odG1wRGlyLCBlbnRyeSk7XG4gICAgICAgICAgICBvdXRwdXQoYCR7ZmFhc3REaXJ9YCk7XG4gICAgICAgICAgICBpZiAoZXhlY3V0ZSkge1xuICAgICAgICAgICAgICAgIGF3YWl0IHJlbW92ZShmYWFzdERpcik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG5SZXNvdXJjZXM7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHByb21wdCgpIHtcbiAgICBjb25zdCBybCA9IHJlYWRsaW5lLmNyZWF0ZUludGVyZmFjZSh7XG4gICAgICAgIGlucHV0OiBwcm9jZXNzLnN0ZGluLFxuICAgICAgICBvdXRwdXQ6IHByb2Nlc3Muc3Rkb3V0XG4gICAgfSk7XG5cbiAgICBhd2FpdCBuZXcgUHJvbWlzZTx2b2lkPihyZXNvbHZlID0+IHtcbiAgICAgICAgcmwucXVlc3Rpb24oXG4gICAgICAgICAgICBcIldBUk5JTkc6IHRoaXMgb3BlcmF0aW9uIHdpbGwgZGVsZXRlIHJlc291cmNlcy4gQ29uZmlybT8gW3kvTl0gXCIsXG4gICAgICAgICAgICBhbnN3ZXIgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChhbnN3ZXIgIT09IFwieVwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGxvZyhgRXhlY3V0aW9uIGFib3J0ZWQuYCk7XG4gICAgICAgICAgICAgICAgICAgIHByb2Nlc3MuZXhpdCgwKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmwuY2xvc2UoKTtcbiAgICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJ1bkNsZWFudXAoY2xvdWQ6IHN0cmluZywgb3B0aW9uczogQ2xlYW51cE9wdGlvbnMpIHtcbiAgICBsZXQgblJlc291cmNlcyA9IDA7XG4gICAgaWYgKGNsb3VkID09PSBcImF3c1wiKSB7XG4gICAgICAgIG5SZXNvdXJjZXMgPSBhd2FpdCBjbGVhbnVwQVdTKG9wdGlvbnMpO1xuICAgIH0gZWxzZSBpZiAoY2xvdWQgPT09IFwibG9jYWxcIikge1xuICAgICAgICBuUmVzb3VyY2VzID0gYXdhaXQgY2xlYW51cExvY2FsKG9wdGlvbnMpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHdhcm4oYFVua25vd24gY2xvdWQgbmFtZSBcIiR7Y2xvdWR9XCIuIE11c3Qgc3BlY2lmeSBcImF3c1wiIG9yIFwibG9jYWxcIi5gKTtcbiAgICAgICAgcHJvY2Vzcy5leGl0KC0xKTtcbiAgICB9XG4gICAgaWYgKG9wdGlvbnMuZXhlY3V0ZSkge1xuICAgICAgICBsb2coYERvbmUuYCk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKG5SZXNvdXJjZXMgPT09IDApIHtcbiAgICAgICAgICAgIGxvZyhgTm8gcmVzb3VyY2VzIHRvIGNsZWFuIHVwLmApO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBuUmVzb3VyY2VzO1xufVxuXG5hc3luYyBmdW5jdGlvbiBtYWluKCkge1xuICAgIGxldCBjbG91ZCE6IHN0cmluZztcbiAgICBsZXQgY29tbWFuZDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIHByb2dyYW1cbiAgICAgICAgLnZlcnNpb24oXCIwLjEuMFwiKVxuICAgICAgICAub3B0aW9uKFwiLXYsIC0tdmVyYm9zZVwiLCBcIlZlcmJvc2UgbW9kZVwiKVxuICAgICAgICAub3B0aW9uKFxuICAgICAgICAgICAgXCItciwgLS1yZWdpb24gPHJlZ2lvbj5cIixcbiAgICAgICAgICAgIFwiQ2xvdWQgcmVnaW9uIHRvIG9wZXJhdGUgb24uIERlZmF1bHRzIHRvIHVzLXdlc3QtMiBmb3IgQVdTLlwiXG4gICAgICAgIClcbiAgICAgICAgLm9wdGlvbihcbiAgICAgICAgICAgIFwiLXgsIC0tZXhlY3V0ZVwiLFxuICAgICAgICAgICAgXCJFeGVjdXRlIHRoZSBjbGVhbnVwIHByb2Nlc3MuIElmIHRoaXMgb3B0aW9uIGlzIG5vdCBzcGVjaWZpZWQsIHRoZSBvdXRwdXQgd2lsbCBiZSBhIGRyeSBydW4uXCJcbiAgICAgICAgKVxuICAgICAgICAub3B0aW9uKFwiLWYsIC0tZm9yY2VcIiwgXCJXaGVuIHVzZWQgd2l0aCAteCwgc2tpcHMgdGhlIHByb21wdFwiKVxuICAgICAgICAuY29tbWFuZChcImNsZWFudXAgPGNsb3VkPlwiKVxuICAgICAgICAuZGVzY3JpcHRpb24oXG4gICAgICAgICAgICBgQ2xlYW51cCBmYWFzdC5qcyByZXNvdXJjZXMgdGhhdCBtYXkgaGF2ZSBsZWFrZWQuIFRoZSA8Y2xvdWQ+IGFyZ3VtZW50IG11c3QgYmUgXCJhd3NcIiBvciBcImxvY2FsXCIuXG4gICAgICAgIEJ5IGRlZmF1bHQgdGhlIG91dHB1dCBpcyBhIGRyeSBydW4gYW5kIHdpbGwgb25seSBwcmludCB0aGUgYWN0aW9ucyB0aGF0IHdvdWxkIGJlIHBlcmZvcm1lZCBpZiAnLXgnIGlzIHNwZWNpZmllZC5gXG4gICAgICAgIClcbiAgICAgICAgLmFjdGlvbigoYXJnOiBzdHJpbmcpID0+IHtcbiAgICAgICAgICAgIGNvbW1hbmQgPSBcImNsZWFudXBcIjtcbiAgICAgICAgICAgIGNsb3VkID0gYXJnO1xuICAgICAgICB9KTtcblxuICAgIGNvbnN0IG9wdHMgPSBwcm9ncmFtLnBhcnNlKHByb2Nlc3MuYXJndikub3B0cygpO1xuICAgIGlmIChvcHRzLnZlcmJvc2UpIHtcbiAgICAgICAgcHJvY2Vzcy5lbnYuREVCVUcgPSBcImZhYXN0OipcIjtcbiAgICB9XG4gICAgY29uc3QgZXhlY3V0ZSA9IG9wdHMuZXhlY3V0ZSB8fCBmYWxzZTtcbiAgICBsZXQgcmVnaW9uID0gb3B0cy5yZWdpb247XG5cbiAgICBpZiAoIXJlZ2lvbikge1xuICAgICAgICBzd2l0Y2ggKGNsb3VkKSB7XG4gICAgICAgICAgICBjYXNlIFwiYXdzXCI6XG4gICAgICAgICAgICAgICAgcmVnaW9uID0gYXdzRmFhc3QuZGVmYXVsdHMucmVnaW9uO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbnN0IGZvcmNlID0gb3B0cy5mb3JjZSB8fCBmYWxzZTtcblxuICAgIHJlZ2lvbiAmJiBsb2coYFJlZ2lvbjogJHtyZWdpb259YCk7XG4gICAgY29uc3Qgb3B0aW9ucyA9IHsgcmVnaW9uLCBleGVjdXRlIH07XG4gICAgbGV0IG5SZXNvdXJjZXMgPSAwO1xuICAgIGlmIChjb21tYW5kID09PSBcImNsZWFudXBcIikge1xuICAgICAgICBpZiAoZXhlY3V0ZSAmJiAhZm9yY2UpIHtcbiAgICAgICAgICAgIG5SZXNvdXJjZXMgPSBhd2FpdCBydW5DbGVhbnVwKGNsb3VkLCB7IC4uLm9wdGlvbnMsIGV4ZWN1dGU6IGZhbHNlIH0pO1xuICAgICAgICAgICAgaWYgKG5SZXNvdXJjZXMgPiAwKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgcHJvbXB0KCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHByb2Nlc3MuZXhpdCgwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBuUmVzb3VyY2VzID0gYXdhaXQgcnVuQ2xlYW51cChjbG91ZCwgb3B0aW9ucyk7XG4gICAgICAgIGlmICghZXhlY3V0ZSAmJiBuUmVzb3VyY2VzID4gMCkge1xuICAgICAgICAgICAgbG9nKFxuICAgICAgICAgICAgICAgIGAoZHJ5cnVuIG1vZGUsIG5vIHJlc291cmNlcyB3aWxsIGJlIGRlbGV0ZWQsIHNwZWNpZnkgLXggdG8gZXhlY3V0ZSBjbGVhbnVwKWBcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgICBsb2coYE5vIGNvbW1hbmQgc3BlY2lmaWVkLmApO1xuICAgICAgICBwcm9ncmFtLmhlbHAoKTtcbiAgICB9XG59XG5cbm1haW4oKTtcbiJdfQ==