faastjs
Version:
Serverless batch computing made simple.
239 lines • 41.9 kB
JavaScript
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==
;