faastjs
Version:
Serverless batch computing made simple.
239 lines • 41.5 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,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=