UNPKG

53.8 kBJavaScriptView Raw
1#!/usr/bin/env node
2"use strict";
3Object.defineProperty(exports, "__esModule", { value: true });
4require("source-map-support").install();
5const commander_1 = require("commander");
6const fs_extra_1 = require("fs-extra");
7const googleapis_1 = require("googleapis");
8const ora = require("ora");
9const os_1 = require("os");
10const path = require("path");
11const awsFaast = require("./aws/aws-faast");
12const cache_1 = require("./cache");
13const googleFaast = require("./google/google-faast");
14const shared_1 = require("./shared");
15const throttle_1 = require("./throttle");
16const warn = console.warn;
17const log = console.log;
18async function deleteResources(name, matchingResources, doRemove, { concurrency = 10, rate = 5, burst = 5 } = {}) {
19 if (matchingResources.length > 0) {
20 const timeEstimate = (nResources) => nResources <= 5 ? "" : `(est: ${(nResources / 5).toFixed(0)}s)`;
21 const updateSpinnerText = (nResources = 0) => `Deleting ${matchingResources.length} ${name} ${timeEstimate(nResources)}`;
22 const spinner = ora(updateSpinnerText(matchingResources.length)).start();
23 let done = 0;
24 const scheduleRemove = (0, throttle_1.throttle)({
25 concurrency,
26 rate,
27 burst,
28 retry: 5
29 }, async (arg) => {
30 await doRemove(arg);
31 done++;
32 });
33 const timer = setInterval(() => (spinner.text = updateSpinnerText(matchingResources.length - done)), 1000);
34 try {
35 await Promise.all(matchingResources.map(resource => scheduleRemove(resource).catch(err => console.warn(`Could not remove resource ${resource}: ${err}`))));
36 }
37 finally {
38 clearInterval(timer);
39 spinner.text = updateSpinnerText();
40 }
41 spinner.stopAndPersist({ symbol: "✔" });
42 }
43}
44async function cleanupAWS({ region, execute }) {
45 let nResources = 0;
46 const output = (msg) => !execute && log(msg);
47 const { cloudwatch, iam, lambda, sns, sqs, s3 } = await awsFaast.createAwsApis(region);
48 function listAWSResource(pattern, getList, extractList, extractElement) {
49 const allResources = [];
50 return new Promise((resolve, reject) => {
51 getList().eachPage((err, page) => {
52 if (err) {
53 reject(err);
54 return false;
55 }
56 const elems = (page && extractList(page)) || [];
57 allResources.push(...elems.map(elem => extractElement(elem) || ""));
58 if (page === null) {
59 // console.log(`allResources: ${allResources.join("\n")}`);
60 // console.log(`pattern: ${pattern}`);
61 const matchingResources = allResources.filter(t => t.match(pattern));
62 matchingResources.forEach(resource => output(` ${resource}`));
63 resolve(matchingResources);
64 }
65 return true;
66 });
67 });
68 }
69 async function deleteAWSResource(name, pattern, getList, extractList, extractElement, doRemove) {
70 const allResources = await listAWSResource(pattern, getList, extractList, extractElement);
71 nResources += allResources.length;
72 if (execute) {
73 await deleteResources(name, allResources, doRemove, {
74 concurrency: 10,
75 rate: 5,
76 burst: 5
77 });
78 }
79 }
80 output(`SNS subscriptions`);
81 await deleteAWSResource("SNS subscription(s)", new RegExp(`:faast-${shared_1.uuidv4Pattern}`), () => sns.listSubscriptions(), page => page.Subscriptions, subscription => subscription.SubscriptionArn, SubscriptionArn => sns.unsubscribe({ SubscriptionArn }).promise());
82 output(`SNS topics`);
83 await deleteAWSResource("SNS topic(s)", new RegExp(`:faast-${shared_1.uuidv4Pattern}`), () => sns.listTopics(), page => page.Topics, topic => topic.TopicArn, TopicArn => sns.deleteTopic({ TopicArn }).promise());
84 output(`SQS queues`);
85 await deleteAWSResource("SQS queue(s)", new RegExp(`/faast-${shared_1.uuidv4Pattern}`), () => sqs.listQueues(), page => page.QueueUrls, queueUrl => queueUrl, QueueUrl => sqs.deleteQueue({ QueueUrl }).promise());
86 output(`S3 buckets`);
87 await deleteAWSResource("S3 bucket(s)", new RegExp(`^faast-${shared_1.uuidv4Pattern}`), () => s3.listBuckets(), page => page.Buckets, Bucket => Bucket.Name, async (Bucket) => {
88 const objects = await s3
89 .listObjectsV2({ Bucket, Prefix: "faast-" })
90 .promise();
91 const keys = (objects.Contents || []).map(entry => ({ Key: entry.Key }));
92 if (keys.length > 0) {
93 await s3.deleteObjects({ Bucket, Delete: { Objects: keys } }).promise();
94 }
95 await s3.deleteBucket({ Bucket }).promise();
96 });
97 output(`Lambda functions`);
98 await deleteAWSResource("Lambda function(s)", new RegExp(`^faast-${shared_1.uuidv4Pattern}`), () => lambda.listFunctions(), page => page.Functions, func => func.FunctionName, FunctionName => lambda.deleteFunction({ FunctionName }).promise());
99 output(`IAM roles`);
100 await deleteAWSResource("IAM role(s)", /^faast-cached-lambda-role$/, () => iam.listRoles(), page => page.Roles, role => role.RoleName, RoleName => awsFaast.deleteRole(RoleName, iam));
101 output(`IAM test roles`);
102 await deleteAWSResource("IAM test role(s)", new RegExp(`^faast-test-.*${shared_1.uuidv4Pattern}$`), () => iam.listRoles(), page => page.Roles, role => role.RoleName, RoleName => awsFaast.deleteRole(RoleName, iam));
103 output(`Lambda layers`);
104 await deleteAWSResource("Lambda layer(s)", new RegExp(`^faast-(${shared_1.uuidv4Pattern})|([a-f0-9]{64})`), () => lambda.listLayers({ CompatibleRuntime: "nodejs" }), page => page.Layers, layer => layer.LayerName, async (LayerName) => {
105 const versions = await lambda.listLayerVersions({ LayerName }).promise();
106 for (const layerVersion of versions.LayerVersions || []) {
107 await lambda
108 .deleteLayerVersion({
109 LayerName,
110 VersionNumber: layerVersion.Version
111 })
112 .promise();
113 }
114 });
115 async function cleanupCacheDir(cache) {
116 output(`Persistent cache: ${cache.dir}`);
117 const entries = await cache.entries();
118 if (!execute) {
119 output(` cache entries: ${entries.length}`);
120 }
121 nResources += entries.length;
122 if (execute) {
123 cache.clear({ leaveEmptyDir: false });
124 }
125 }
126 for (const cache of (0, shared_1.keysOf)(cache_1.caches)) {
127 await cleanupCacheDir(await cache_1.caches[cache]);
128 }
129 output(`Cloudwatch log groups`);
130 await deleteAWSResource("Cloudwatch log group(s)", new RegExp(`/faast-${shared_1.uuidv4Pattern}$`), () => cloudwatch.describeLogGroups(), page => page.logGroups, logGroup => logGroup.logGroupName, logGroupName => cloudwatch.deleteLogGroup({ logGroupName }).promise());
131 return nResources;
132}
133async function iterate(getPage, each) {
134 let token;
135 do {
136 const result = await getPage(token);
137 each(result.data);
138 token = result.data.nextPageToken;
139 } while (token);
140}
141async function cleanupGoogle({ execute }) {
142 let nResources = 0;
143 const output = (msg) => !execute && log(msg);
144 async function listGoogleResource(pattern, getList, extractList, extractElement) {
145 const allResources = [];
146 await iterate(pageToken => getList(pageToken), result => {
147 const resources = extractList(result) || [];
148 allResources.push(...resources.map(elem => extractElement(elem) || ""));
149 });
150 const matchingResources = allResources.filter(t => t.match(pattern));
151 matchingResources.forEach(resource => output(` ${resource}`));
152 return matchingResources;
153 }
154 async function deleteGoogleResource(name, pattern, getList, extractList, extractElement, doRemove) {
155 const allResources = await listGoogleResource(pattern, getList, extractList, extractElement);
156 nResources += allResources.length;
157 if (execute) {
158 await deleteResources(name, allResources, doRemove, {
159 concurrency: 20,
160 rate: 20,
161 burst: 20
162 });
163 }
164 }
165 const { cloudFunctions, pubsub } = await googleFaast.initializeGoogleServices();
166 const project = await googleapis_1.google.auth.getProjectId();
167 log(`Default project: ${project}`);
168 output(`Cloud functions`);
169 await deleteGoogleResource("Cloud Function(s)", new RegExp(`faast-${shared_1.uuidv4Pattern}`), (pageToken) => cloudFunctions.projects.locations.functions.list({
170 pageToken,
171 parent: `projects/${project}/locations/-`
172 }), page => page.functions, func => func.name ?? undefined, name => cloudFunctions.projects.locations.functions.delete({ name }));
173 output(`Pub/Sub subscriptions`);
174 await deleteGoogleResource("Pub/Sub Subscription(s)", new RegExp(`faast-${shared_1.uuidv4Pattern}`), pageToken => pubsub.projects.subscriptions.list({
175 pageToken,
176 project: `projects/${project}`
177 }), page => page.subscriptions, subscription => subscription.name ?? undefined, subscriptionName => pubsub.projects.subscriptions.delete({ subscription: subscriptionName }));
178 output(`Pub/Sub topics`);
179 await deleteGoogleResource("Pub/Sub topic(s)", new RegExp(`topics/faast-${shared_1.uuidv4Pattern}`), pageToken => pubsub.projects.topics.list({ pageToken, project: `projects/${project}` }), page => page.topics, topic => topic.name ?? undefined, topicName => pubsub.projects.topics.delete({ topic: topicName }));
180 return nResources;
181}
182async function cleanupLocal({ execute }) {
183 const output = (msg) => !execute && log(msg);
184 const tmpDir = (0, os_1.tmpdir)();
185 const dir = await (0, fs_extra_1.readdir)(tmpDir);
186 let nResources = 0;
187 output(`Temporary directories:`);
188 const entryRegexp = new RegExp(`^faast-${shared_1.uuidv4Pattern}$`);
189 for (const entry of dir) {
190 if (entry.match(entryRegexp)) {
191 nResources++;
192 const faastDir = path.join(tmpDir, entry);
193 output(`${faastDir}`);
194 if (execute) {
195 await (0, fs_extra_1.remove)(faastDir);
196 }
197 }
198 }
199 return nResources;
200}
201const readline = require("readline");
202async function prompt() {
203 const rl = readline.createInterface({
204 input: process.stdin,
205 output: process.stdout
206 });
207 await new Promise(resolve => {
208 rl.question("WARNING: this operation will delete resources. Confirm? [y/N] ", answer => {
209 if (answer !== "y") {
210 log(`Execution aborted.`);
211 process.exit(0);
212 }
213 rl.close();
214 resolve();
215 });
216 });
217}
218async function runCleanup(cloud, options) {
219 let nResources = 0;
220 if (cloud === "aws") {
221 nResources = await cleanupAWS(options);
222 }
223 else if (cloud === "google") {
224 nResources = await cleanupGoogle(options);
225 }
226 else if (cloud === "local") {
227 nResources = await cleanupLocal(options);
228 }
229 else {
230 warn(`Unknown cloud name "${cloud}". Must specify "aws" or "google", or "local".`);
231 process.exit(-1);
232 }
233 if (options.execute) {
234 log(`Done.`);
235 }
236 else {
237 if (nResources === 0) {
238 log(`No resources to clean up.`);
239 }
240 }
241 return nResources;
242}
243async function main() {
244 let cloud;
245 let command;
246 commander_1.program
247 .version("0.1.0")
248 .option("-v, --verbose", "Verbose mode")
249 .option("-r, --region <region>", "Cloud region to operate on. Defaults to us-west-2 for AWS, and us-central1 for Google.")
250 .option("-x, --execute", "Execute the cleanup process. If this option is not specified, the output will be a dry run.")
251 .option("-f, --force", "When used with -x, skips the prompt")
252 .command("cleanup <cloud>")
253 .description(`Cleanup faast.js resources that may have leaked. The <cloud> argument must be "aws", "google", or "local".
254 By default the output is a dry run and will only print the actions that would be performed if '-x' is specified.`)
255 .action((arg) => {
256 command = "cleanup";
257 cloud = arg;
258 });
259 const opts = commander_1.program.parse(process.argv).opts();
260 if (opts.verbose) {
261 process.env.DEBUG = "faast:*";
262 }
263 const execute = opts.execute || false;
264 let region = opts.region;
265 if (!region) {
266 switch (cloud) {
267 case "aws":
268 region = awsFaast.defaults.region;
269 break;
270 case "google":
271 region = googleFaast.defaults.region;
272 break;
273 }
274 }
275 const force = opts.force || false;
276 region && log(`Region: ${region}`);
277 const options = { region, execute };
278 let nResources = 0;
279 if (command === "cleanup") {
280 if (execute && !force) {
281 nResources = await runCleanup(cloud, { ...options, execute: false });
282 if (nResources > 0) {
283 await prompt();
284 }
285 else {
286 process.exit(0);
287 }
288 }
289 nResources = await runCleanup(cloud, options);
290 if (!execute && nResources > 0) {
291 log(`(dryrun mode, no resources will be deleted, specify -x to execute cleanup)`);
292 }
293 }
294 else {
295 log(`No command specified.`);
296 commander_1.program.help();
297 }
298}
299main();
300//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFFQSxPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztBQUd4Qyx5Q0FBb0M7QUFDcEMsdUNBQTJDO0FBRTNDLDJDQUFvQztBQUNwQywyQkFBMkI7QUFDM0IsMkJBQTRCO0FBQzVCLDZCQUE2QjtBQUM3Qiw0Q0FBNEM7QUFDNUMsbUNBQWtEO0FBQ2xELHFEQUFxRDtBQUNyRCxxQ0FBaUQ7QUFDakQseUNBQXNDO0FBRXRDLE1BQU0sSUFBSSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUM7QUFDMUIsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQztBQU94QixLQUFLLFVBQVUsZUFBZSxDQUMxQixJQUFZLEVBQ1osaUJBQTJCLEVBQzNCLFFBQXVDLEVBQ3ZDLEVBQUUsV0FBVyxHQUFHLEVBQUUsRUFBRSxJQUFJLEdBQUcsQ0FBQyxFQUFFLEtBQUssR0FBRyxDQUFDLEVBQUUsR0FBRyxFQUFFO0lBRTlDLElBQUksaUJBQWlCLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtRQUM5QixNQUFNLFlBQVksR0FBRyxDQUFDLFVBQWtCLEVBQUUsRUFBRSxDQUN4QyxVQUFVLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxVQUFVLEdBQUcsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFDcEUsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLGFBQXFCLENBQUMsRUFBRSxFQUFFLENBQ2pELFlBQVksaUJBQWlCLENBQUMsTUFBTSxJQUFJLElBQUksSUFBSSxZQUFZLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUMvRSxNQUFNLE9BQU8sR0FBRyxHQUFHLENBQUMsaUJBQWlCLENBQUMsaUJBQWlCLENBQUMsTUFBTSxD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LFFBQVEsQ0FBQyxNQUFNLENBQUM7Z0JBQ3JDLE1BQU07U0FDYjtLQUNKO0lBQ0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssSUFBSSxLQUFLLENBQUM7SUFFbEMsTUFBTSxJQUFJLEdBQUcsQ0FBQyxXQUFXLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDbkMsTUFBTSxPQUFPLEdBQUcsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLENBQUM7SUFDcEMsSUFBSSxVQUFVLEdBQUcsQ0FBQyxDQUFDO0lBQ25CLElBQUksT0FBTyxLQUFLLFNBQVMsRUFBRTtRQUN2QixJQUFJLE9BQU8sSUFBSSxDQUFDLEtBQUssRUFBRTtZQUNuQixVQUFVLEdBQUcsTUFBTSxVQUFVLENBQUMsS0FBSyxFQUFFLEVBQUUsR0FBRyxPQUFPLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDckUsSUFBSSxVQUFVLEdBQUcsQ0FBQyxFQUFFO2dCQUNoQixNQUFNLE1BQU0sRUFBRSxDQUFDO2FBQ2xCO2lCQUFNO2dCQUNILE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7YUFDbkI7U0FDSjtRQUNELFVBQVUsR0FBRyxNQUFNLFVBQVUsQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDOUMsSUFBSSxDQUFDLE9BQU8sSUFBSSxVQUFVLEdBQUcsQ0FBQyxFQUFFO1lBQzVCLEdBQUcsQ0FDQyw0RUFBNEUsQ0FDL0UsQ0FBQztTQUNMO0tBQ0o7U0FBTTtRQUNILEdBQUcsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO1FBQzdCLG1CQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7S0FDbEI7QUFDTCxDQUFDO0FBRUQsSUFBSSxFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIjIS91c3IvYmluL2VudiBub2RlXG5cbnJlcXVpcmUoXCJzb3VyY2UtbWFwLXN1cHBvcnRcIikuaW5zdGFsbCgpO1xuXG5pbXBvcnQgeyBSZXF1ZXN0IGFzIEFXU1JlcXVlc3QsIEFXU0Vycm9yIH0gZnJvbSBcImF3cy1zZGtcIjtcbmltcG9ydCB7IHByb2dyYW0gfSBmcm9tIFwiY29tbWFuZGVyXCI7XG5pbXBvcnQgeyByZWFkZGlyLCByZW1vdmUgfSBmcm9tIFwiZnMtZXh0cmFcIjtcbmltcG9ydCB7IEdheGlvc1Byb21pc2UsIEdheGlvc1Jlc3BvbnNlIH0gZnJvbSBcImdheGlvc1wiO1xuaW1wb3J0IHsgZ29vZ2xlIH0gZnJvbSBcImdvb2dsZWFwaXNcIjtcbmltcG9ydCAqIGFzIG9yYSBmcm9tIFwib3JhXCI7XG5pbXBvcnQgeyB0bXBkaXIgfSBmcm9tIFwib3NcIjtcbmltcG9ydCAqIGFzIHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCAqIGFzIGF3c0ZhYXN0IGZyb20gXCIuL2F3cy9hd3MtZmFhc3RcIjtcbmltcG9ydCB7IGNhY2hlcywgUGVyc2lzdGVudENhY2hlIH0gZnJvbSBcIi4vY2FjaGVcIjtcbmltcG9ydCAqIGFzIGdvb2dsZUZhYXN0IGZyb20gXCIuL2dvb2dsZS9nb29nbGUtZmFhc3RcIjtcbmltcG9ydCB7IGtleXNPZiwgdXVpZHY0UGF0dGVybiB9IGZyb20gXCIuL3NoYXJlZFwiO1xuaW1wb3J0IHsgdGhyb3R0bGUgfSBmcm9tIFwiLi90aHJvdHRsZVwiO1xuXG5jb25zdCB3YXJuID0gY29uc29sZS53YXJuO1xuY29uc3QgbG9nID0gY29uc29sZS5sb2c7XG5cbmludGVyZmFjZSBDbGVhbnVwT3B0aW9ucyB7XG4gICAgcmVnaW9uPzogc3RyaW5nOyAvLyBBV1MgYW5kIEdvb2dsZSBvbmx5LlxuICAgIGV4ZWN1dGU6IGJvb2xlYW47XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGRlbGV0ZVJlc291cmNlcyhcbiAgICBuYW1lOiBzdHJpbmcsXG4gICAgbWF0Y2hpbmdSZXNvdXJjZXM6IHN0cmluZ1tdLFxuICAgIGRvUmVtb3ZlOiAoYXJnOiBzdHJpbmcpID0+IFByb21pc2U8YW55PixcbiAgICB7IGNvbmN1cnJlbmN5ID0gMTAsIHJhdGUgPSA1LCBidXJzdCA9IDUgfSA9IHt9XG4pIHtcbiAgICBpZiAobWF0Y2hpbmdSZXNvdXJjZXMubGVuZ3RoID4gMCkge1xuICAgICAgICBjb25zdCB0aW1lRXN0aW1hdGUgPSAoblJlc291cmNlczogbnVtYmVyKSA9PlxuICAgICAgICAgICAgblJlc291cmNlcyA8PSA1ID8gXCJcIiA6IGAoZXN0OiAkeyhuUmVzb3VyY2VzIC8gNSkudG9GaXhlZCgwKX1zKWA7XG4gICAgICAgIGNvbnN0IHVwZGF0ZVNwaW5uZXJUZXh0ID0gKG5SZXNvdXJjZXM6IG51bWJlciA9IDApID0+XG4gICAgICAgICAgICBgRGVsZXRpbmcgJHttYXRjaGluZ1Jlc291cmNlcy5sZW5ndGh9ICR7bmFtZX0gJHt0aW1lRXN0aW1hdGUoblJlc291cmNlcyl9YDtcbiAgICAgICAgY29uc3Qgc3Bpbm5lciA9IG9yYSh1cGRhdGVTcGlubmVyVGV4dChtYXRjaGluZ1Jlc291cmNlcy5sZW5ndGgpKS5zdGFydCgpO1xuICAgICAgICBsZXQgZG9uZSA9IDA7XG4gICAgICAgIGNvbnN0IHNjaGVkdWxlUmVtb3ZlID0gdGhyb3R0bGUoXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgY29uY3VycmVuY3ksXG4gICAgICAgICAgICAgICAgcmF0ZSxcbiAgICAgICAgICAgICAgICBidXJzdCxcbiAgICAgICAgICAgICAgICByZXRyeTogNVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGFzeW5jIGFyZyA9PiB7XG4gICAgICAgICAgICAgICAgYXdhaXQgZG9SZW1vdmUoYXJnKTtcbiAgICAgICAgICAgICAgICBkb25lKys7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHRpbWVyID0gc2V0SW50ZXJ2YWwoXG4gICAgICAgICAgICAoKSA9PiAoc3Bpbm5lci50ZXh0ID0gdXBkYXRlU3Bpbm5lclRleHQobWF0Y2hpbmdSZXNvdXJjZXMubGVuZ3RoIC0gZG9uZSkpLFxuICAgICAgICAgICAgMTAwMFxuICAgICAgICApO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgICAgICAgICAgbWF0Y2hpbmdSZXNvdXJjZXMubWFwKHJlc291cmNlID0+XG4gICAgICAgICAgICAgICAgICAgIHNjaGVkdWxlUmVtb3ZlKHJlc291cmNlKS5jYXRjaChlcnIgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihgQ291bGQgbm90IHJlbW92ZSByZXNvdXJjZSAke3Jlc291cmNlfTogJHtlcnJ9YClcbiAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICk7XG4gICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgICBjbGVhckludGVydmFsKHRpbWVyKTtcbiAgICAgICAgICAgIHNwaW5uZXIudGV4dCA9IHVwZGF0ZVNwaW5uZXJUZXh0KCk7XG4gICAgICAgIH1cbiAgICAgICAgc3Bpbm5lci5zdG9wQW5kUGVyc2lzdCh7IHN5bWJvbDogXCLinJRcIiB9KTtcbiAgICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNsZWFudXBBV1MoeyByZWdpb24sIGV4ZWN1dGUgfTogQ2xlYW51cE9wdGlvbnMpIHtcbiAgICBsZXQgblJlc291cmNlcyA9IDA7XG4gICAgY29uc3Qgb3V0cHV0ID0gKG1zZzogc3RyaW5nKSA9PiAhZXhlY3V0ZSAmJiBsb2cobXNnKTtcbiAgICBjb25zdCB7IGNsb3Vkd2F0Y2gsIGlhbSwgbGFtYmRhLCBzbnMsIHNxcywgczMgfSA9IGF3YWl0IGF3c0ZhYXN0LmNyZWF0ZUF3c0FwaXMoXG4gICAgICAgIHJlZ2lvbiEgYXMgYXdzRmFhc3QuQXdzUmVnaW9uXG4gICAgKTtcblxuICAgIGZ1bmN0aW9uIGxpc3RBV1NSZXNvdXJjZTxULCBVPihcbiAgICAgICAgcGF0dGVybjogUmVnRXhwLFxuICAgICAgICBnZXRMaXN0OiAoKSA9PiBBV1NSZXF1ZXN0PFQsIEFXU0Vycm9yPixcbiAgICAgICAgZXh0cmFjdExpc3Q6IChhcmc6IFQpID0+IFVbXSB8IHVuZGVmaW5lZCxcbiAgICAgICAgZXh0cmFjdEVsZW1lbnQ6IChhcmc6IFUpID0+IHN0cmluZyB8IHVuZGVmaW5lZFxuICAgICkge1xuICAgICAgICBjb25zdCBhbGxSZXNvdXJjZXM6IHN0cmluZ1tdID0gW107XG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZTxzdHJpbmdbXT4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgZ2V0TGlzdCgpLmVhY2hQYWdlKChlcnIsIHBhZ2UpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlamVjdChlcnIpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IGVsZW1zID0gKHBhZ2UgJiYgZXh0cmFjdExpc3QocGFnZSkpIHx8IFtdO1xuICAgICAgICAgICAgICAgIGFsbFJlc291cmNlcy5wdXNoKC4uLmVsZW1zLm1hcChlbGVtID0+IGV4dHJhY3RFbGVtZW50KGVsZW0pIHx8IFwiXCIpKTtcbiAgICAgICAgICAgICAgICBpZiAocGFnZSA9PT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhgYWxsUmVzb3VyY2VzOiAke2FsbFJlc291cmNlcy5qb2luKFwiXFxuXCIpfWApO1xuICAgICAgICAgICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhgcGF0dGVybjogJHtwYXR0ZXJufWApO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBtYXRjaGluZ1Jlc291cmNlcyA9IGFsbFJlc291cmNlcy5maWx0ZXIodCA9PiB0Lm1hdGNoKHBhdHRlcm4pKTtcbiAgICAgICAgICAgICAgICAgICAgbWF0Y2hpbmdSZXNvdXJjZXMuZm9yRWFjaChyZXNvdXJjZSA9PiBvdXRwdXQoYCAgJHtyZXNvdXJjZX1gKSk7XG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUobWF0Y2hpbmdSZXNvdXJjZXMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiBkZWxldGVBV1NSZXNvdXJjZTxULCBVPihcbiAgICAgICAgbmFtZTogc3RyaW5nLFxuICAgICAgICBwYXR0ZXJuOiBSZWdFeHAsXG4gICAgICAgIGdldExpc3Q6ICgpID0+IEFXU1JlcXVlc3Q8VCwgQVdTRXJyb3I+LFxuICAgICAgICBleHRyYWN0TGlzdDogKGFyZzogVCkgPT4gVVtdIHwgdW5kZWZpbmVkLFxuICAgICAgICBleHRyYWN0RWxlbWVudDogKGFyZzogVSkgPT4gc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgICAgICBkb1JlbW92ZTogKGFyZzogc3RyaW5nKSA9PiBQcm9taXNlPGFueT5cbiAgICApIHtcbiAgICAgICAgY29uc3QgYWxsUmVzb3VyY2VzID0gYXdhaXQgbGlzdEFXU1Jlc291cmNlKFxuICAgICAgICAgICAgcGF0dGVybixcbiAgICAgICAgICAgIGdldExpc3QsXG4gICAgICAgICAgICBleHRyYWN0TGlzdCxcbiAgICAgICAgICAgIGV4dHJhY3RFbGVtZW50XG4gICAgICAgICk7XG4gICAgICAgIG5SZXNvdXJjZXMgKz0gYWxsUmVzb3VyY2VzLmxlbmd0aDtcbiAgICAgICAgaWYgKGV4ZWN1dGUpIHtcbiAgICAgICAgICAgIGF3YWl0IGRlbGV0ZVJlc291cmNlcyhuYW1lLCBhbGxSZXNvdXJjZXMsIGRvUmVtb3ZlLCB7XG4gICAgICAgICAgICAgICAgY29uY3VycmVuY3k6IDEwLFxuICAgICAgICAgICAgICAgIHJhdGU6IDUsXG4gICAgICAgICAgICAgICAgYnVyc3Q6IDVcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgb3V0cHV0KGBTTlMgc3Vic2NyaXB0aW9uc2ApO1xuICAgIGF3YWl0IGRlbGV0ZUFXU1Jlc291cmNlKFxuICAgICAgICBcIlNOUyBzdWJzY3JpcHRpb24ocylcIixcbiAgICAgICAgbmV3IFJlZ0V4cChgOmZhYXN0LSR7dXVpZHY0UGF0dGVybn1gKSxcbiAgICAgICAgKCkgPT4gc25zLmxpc3RTdWJzY3JpcHRpb25zKCksXG4gICAgICAgIHBhZ2UgPT4gcGFnZS5TdWJzY3JpcHRpb25zLFxuICAgICAgICBzdWJzY3JpcHRpb24gPT4gc3Vic2NyaXB0aW9uLlN1YnNjcmlwdGlvbkFybixcbiAgICAgICAgU3Vic2NyaXB0aW9uQXJuID0+IHNucy51bnN1YnNjcmliZSh7IFN1YnNjcmlwdGlvbkFybiB9KS5wcm9taXNlKClcbiAgICApO1xuXG4gICAgb3V0cHV0KGBTTlMgdG9waWNzYCk7XG4gICAgYXdhaXQgZGVsZXRlQVdTUmVzb3VyY2UoXG4gICAgICAgIFwiU05TIHRvcGljKHMpXCIsXG4gICAgICAgIG5ldyBSZWdFeHAoYDpmYWFzdC0ke3V1aWR2NFBhdHRlcm59YCksXG4gICAgICAgICgpID0+IHNucy5saXN0VG9waWNzKCksXG4gICAgICAgIHBhZ2UgPT4gcGFnZS5Ub3BpY3MsXG4gICAgICAgIHRvcGljID0+IHRvcGljLlRvcGljQXJuLFxuICAgICAgICBUb3BpY0FybiA9PiBzbnMuZGVsZXRlVG9waWMoeyBUb3BpY0FybiB9KS5wcm9taXNlKClcbiAgICApO1xuXG4gICAgb3V0cHV0KGBTUVMgcXVldWVzYCk7XG4gICAgYXdhaXQgZGVsZXRlQVdTUmVzb3VyY2UoXG4gICAgICAgIFwiU1FTIHF1ZXVlKHMpXCIsXG4gICAgICAgIG5ldyBSZWdFeHAoYC9mYWFzdC0ke3V1aWR2NFBhdHRlcm59YCksXG4gICAgICAgICgpID0+IHNxcy5saXN0UXVldWVzKCksXG4gICAgICAgIHBhZ2UgPT4gcGFnZS5RdWV1ZVVybHMsXG4gICAgICAgIHF1ZXVlVXJsID0+IHF1ZXVlVXJsLFxuICAgICAgICBRdWV1ZVVybCA9PiBzcXMuZGVsZXRlUXVldWUoeyBRdWV1ZVVybCB9KS5wcm9taXNlKClcbiAgICApO1xuXG4gICAgb3V0cHV0KGBTMyBidWNrZXRzYCk7XG4gICAgYXdhaXQgZGVsZXRlQVdTUmVzb3VyY2UoXG4gICAgICAgIFwiUzMgYnVja2V0KHMpXCIsXG4gICAgICAgIG5ldyBSZWdFeHAoYF5mYWFzdC0ke3V1aWR2NFBhdHRlcm59YCksXG4gICAgICAgICgpID0+IHMzLmxpc3RCdWNrZXRzKCksXG4gICAgICAgIHBhZ2UgPT4gcGFnZS5CdWNrZXRzLFxuICAgICAgICBCdWNrZXQgPT4gQnVja2V0Lk5hbWUsXG4gICAgICAgIGFzeW5jIEJ1Y2tldCA9PiB7XG4gICAgICAgICAgICBjb25zdCBvYmplY3RzID0gYXdhaXQgczNcbiAgICAgICAgICAgICAgICAubGlzdE9iamVjdHNWMih7IEJ1Y2tldCwgUHJlZml4OiBcImZhYXN0LVwiIH0pXG4gICAgICAgICAgICAgICAgLnByb21pc2UoKTtcbiAgICAgICAgICAgIGNvbnN0IGtleXMgPSAob2JqZWN0cy5Db250ZW50cyB8fCBbXSkubWFwKGVudHJ5ID0+ICh7IEtleTogZW50cnkuS2V5ISB9KSk7XG4gICAgICAgICAgICBpZiAoa2V5cy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgczMuZGVsZXRlT2JqZWN0cyh7IEJ1Y2tldCwgRGVsZXRlOiB7IE9iamVjdHM6IGtleXMgfSB9KS5wcm9taXNlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhd2FpdCBzMy5kZWxldGVCdWNrZXQoeyBCdWNrZXQgfSkucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgKTtcblxuICAgIG91dHB1dChgTGFtYmRhIGZ1bmN0aW9uc2ApO1xuICAgIGF3YWl0IGRlbGV0ZUFXU1Jlc291cmNlKFxuICAgICAgICBcIkxhbWJkYSBmdW5jdGlvbihzKVwiLFxuICAgICAgICBuZXcgUmVnRXhwKGBeZmFhc3QtJHt1dWlkdjRQYXR0ZXJufWApLFxuICAgICAgICAoKSA9PiBsYW1iZGEubGlzdEZ1bmN0aW9ucygpLFxuICAgICAgICBwYWdlID0+IHBhZ2UuRnVuY3Rpb25zLFxuICAgICAgICBmdW5jID0+IGZ1bmMuRnVuY3Rpb25OYW1lLFxuICAgICAgICBGdW5jdGlvbk5hbWUgPT4gbGFtYmRhLmRlbGV0ZUZ1bmN0aW9uKHsgRnVuY3Rpb25OYW1lIH0pLnByb21pc2UoKVxuICAgICk7XG5cbiAgICBvdXRwdXQoYElBTSByb2xlc2ApO1xuICAgIGF3YWl0IGRlbGV0ZUFXU1Jlc291cmNlKFxuICAgICAgICBcIklBTSByb2xlKHMpXCIsXG4gICAgICAgIC9eZmFhc3QtY2FjaGVkLWxhbWJkYS1yb2xlJC8sXG4gICAgICAgICgpID0+IGlhbS5saXN0Um9sZXMoKSxcbiAgICAgICAgcGFnZSA9PiBwYWdlLlJvbGVzLFxuICAgICAgICByb2xlID0+IHJvbGUuUm9sZU5hbWUsXG4gICAgICAgIFJvbGVOYW1lID0+IGF3c0ZhYXN0LmRlbGV0ZVJvbGUoUm9sZU5hbWUsIGlhbSlcbiAgICApO1xuXG4gICAgb3V0cHV0KGBJQU0gdGVzdCByb2xlc2ApO1xuICAgIGF3YWl0IGRlbGV0ZUFXU1Jlc291cmNlKFxuICAgICAgICBcIklBTSB0ZXN0IHJvbGUocylcIixcbiAgICAgICAgbmV3IFJlZ0V4cChgXmZhYXN0LXRlc3QtLioke3V1aWR2NFBhdHRlcm59JGApLFxuICAgICAgICAoKSA9PiBpYW0ubGlzdFJvbGVzKCksXG4gICAgICAgIHBhZ2UgPT4gcGFnZS5Sb2xlcyxcbiAgICAgICAgcm9sZSA9PiByb2xlLlJvbGVOYW1lLFxuICAgICAgICBSb2xlTmFtZSA9PiBhd3NGYWFzdC5kZWxldGVSb2xlKFJvbGVOYW1lLCBpYW0pXG4gICAgKTtcblxuICAgIG91dHB1dChgTGFtYmRhIGxheWVyc2ApO1xuXG4gICAgYXdhaXQgZGVsZXRlQVdTUmVzb3VyY2UoXG4gICAgICAgIFwiTGFtYmRhIGxheWVyKHMpXCIsXG4gICAgICAgIG5ldyBSZWdFeHAoYF5mYWFzdC0oJHt1dWlkdjRQYXR0ZXJufSl8KFthLWYwLTldezY0fSlgKSxcbiAgICAgICAgKCkgPT4gbGFtYmRhLmxpc3RMYXllcnMoeyBDb21wYXRpYmxlUnVudGltZTogXCJub2RlanNcIiB9KSxcbiAgICAgICAgcGFnZSA9PiBwYWdlLkxheWVycyxcbiAgICAgICAgbGF5ZXIgPT4gbGF5ZXIuTGF5ZXJOYW1lLFxuICAgICAgICBhc3luYyBMYXllck5hbWUgPT4ge1xuICAgICAgICAgICAgY29uc3QgdmVyc2lvbnMgPSBhd2FpdCBsYW1iZGEubGlzdExheWVyVmVyc2lvbnMoeyBMYXllck5hbWUgfSkucHJvbWlzZSgpO1xuICAgICAgICAgICAgZm9yIChjb25zdCBsYXllclZlcnNpb24gb2YgdmVyc2lvbnMuTGF5ZXJWZXJzaW9ucyB8fCBbXSkge1xuICAgICAgICAgICAgICAgIGF3YWl0IGxhbWJkYVxuICAgICAgICAgICAgICAgICAgICAuZGVsZXRlTGF5ZXJWZXJzaW9uKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIExheWVyTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb25OdW1iZXI6IGxheWVyVmVyc2lvbi5WZXJzaW9uIVxuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAucHJvbWlzZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgKTtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIGNsZWFudXBDYWNoZURpcihjYWNoZTogUGVyc2lzdGVudENhY2hlKSB7XG4gICAgICAgIG91dHB1dChgUGVyc2lzdGVudCBjYWNoZTogJHtjYWNoZS5kaXJ9YCk7XG4gICAgICAgIGNvbnN0IGVudHJpZXMgPSBhd2FpdCBjYWNoZS5lbnRyaWVzKCk7XG4gICAgICAgIGlmICghZXhlY3V0ZSkge1xuICAgICAgICAgICAgb3V0cHV0KGAgIGNhY2hlIGVudHJpZXM6ICR7ZW50cmllcy5sZW5ndGh9YCk7XG4gICAgICAgIH1cbiAgICAgICAgblJlc291cmNlcyArPSBlbnRyaWVzLmxlbmd0aDtcbiAgICAgICAgaWYgKGV4ZWN1dGUpIHtcbiAgICAgICAgICAgIGNhY2hlLmNsZWFyKHsgbGVhdmVFbXB0eURpcjogZmFsc2UgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGNhY2hlIG9mIGtleXNPZihjYWNoZXMpKSB7XG4gICAgICAgIGF3YWl0IGNsZWFudXBDYWNoZURpcihhd2FpdCBjYWNoZXNbY2FjaGVdKTtcbiAgICB9XG5cbiAgICBvdXRwdXQoYENsb3Vkd2F0Y2ggbG9nIGdyb3Vwc2ApO1xuICAgIGF3YWl0IGRlbGV0ZUFXU1Jlc291cmNlKFxuICAgICAgICBcIkNsb3Vkd2F0Y2ggbG9nIGdyb3VwKHMpXCIsXG4gICAgICAgIG5ldyBSZWdFeHAoYC9mYWFzdC0ke3V1aWR2NFBhdHRlcm59JGApLFxuICAgICAgICAoKSA9PiBjbG91ZHdhdGNoLmRlc2NyaWJlTG9nR3JvdXBzKCksXG4gICAgICAgIHBhZ2UgPT4gcGFnZS5sb2dHcm91cHMsXG4gICAgICAgIGxvZ0dyb3VwID0+IGxvZ0dyb3VwLmxvZ0dyb3VwTmFtZSxcbiAgICAgICAgbG9nR3JvdXBOYW1lID0+IGNsb3Vkd2F0Y2guZGVsZXRlTG9nR3JvdXAoeyBsb2dHcm91cE5hbWUgfSkucHJvbWlzZSgpXG4gICAgKTtcblxuICAgIHJldHVybiBuUmVzb3VyY2VzO1xufVxuXG5pbnRlcmZhY2UgSGFzTmV4dFBhZ2VUb2tlbiB7XG4gICAgbmV4dFBhZ2VUb2tlbj86IHN0cmluZztcbn1cblxuYXN5bmMgZnVuY3Rpb24gaXRlcmF0ZTxUIGV4dGVuZHMgSGFzTmV4dFBhZ2VUb2tlbj4oXG4gICAgZ2V0UGFnZTogKHRva2VuPzogc3RyaW5nKSA9PiBHYXhpb3NQcm9taXNlPFQ+LFxuICAgIGVhY2g6ICh2YWw6IFQpID0+IHZvaWRcbikge1xuICAgIGxldCB0b2tlbjtcbiAgICBkbyB7XG4gICAgICAgIGNvbnN0IHJlc3VsdDogR2F4aW9zUmVzcG9uc2U8VD4gPSBhd2FpdCBnZXRQYWdlKHRva2VuKTtcbiAgICAgICAgZWFjaChyZXN1bHQuZGF0YSk7XG4gICAgICAgIHRva2VuID0gcmVzdWx0LmRhdGEubmV4dFBhZ2VUb2tlbjtcbiAgICB9IHdoaWxlICh0b2tlbik7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNsZWFudXBHb29nbGUoeyBleGVjdXRlIH06IENsZWFudXBPcHRpb25zKSB7XG4gICAgbGV0IG5SZXNvdXJjZXMgPSAwO1xuICAgIGNvbnN0IG91dHB1dCA9IChtc2c6IHN0cmluZykgPT4gIWV4ZWN1dGUgJiYgbG9nKG1zZyk7XG5cbiAgICBhc3luYyBmdW5jdGlvbiBsaXN0R29vZ2xlUmVzb3VyY2U8VCwgVT4oXG4gICAgICAgIHBhdHRlcm46IFJlZ0V4cCxcbiAgICAgICAgZ2V0TGlzdDogKHBhZ2VUb2tlbj86IHN0cmluZykgPT4gR2F4aW9zUHJvbWlzZTxUPixcbiAgICAgICAgZXh0cmFjdExpc3Q6IChhcmc6IFQpID0+IFVbXSB8IHVuZGVmaW5lZCxcbiAgICAgICAgZXh0cmFjdEVsZW1lbnQ6IChhcmc6IFUpID0+IHN0cmluZyB8IHVuZGVmaW5lZFxuICAgICkge1xuICAgICAgICBjb25zdCBhbGxSZXNvdXJjZXM6IHN0cmluZ1tdID0gW107XG4gICAgICAgIGF3YWl0IGl0ZXJhdGUoXG4gICAgICAgICAgICBwYWdlVG9rZW4gPT4gZ2V0TGlzdChwYWdlVG9rZW4pLFxuICAgICAgICAgICAgcmVzdWx0ID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCByZXNvdXJjZXMgPSBleHRyYWN0TGlzdChyZXN1bHQpIHx8IFtdO1xuICAgICAgICAgICAgICAgIGFsbFJlc291cmNlcy5wdXNoKC4uLnJlc291cmNlcy5tYXAoZWxlbSA9PiBleHRyYWN0RWxlbWVudChlbGVtKSB8fCBcIlwiKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3QgbWF0Y2hpbmdSZXNvdXJjZXMgPSBhbGxSZXNvdXJjZXMuZmlsdGVyKHQgPT4gdC5tYXRjaChwYXR0ZXJuKSk7XG4gICAgICAgIG1hdGNoaW5nUmVzb3VyY2VzLmZvckVhY2gocmVzb3VyY2UgPT4gb3V0cHV0KGAgICR7cmVzb3VyY2V9YCkpO1xuICAgICAgICByZXR1cm4gbWF0Y2hpbmdSZXNvdXJjZXM7XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gZGVsZXRlR29vZ2xlUmVzb3VyY2U8VCwgVT4oXG4gICAgICAgIG5hbWU6IHN0cmluZyxcbiAgICAgICAgcGF0dGVybjogUmVnRXhwLFxuICAgICAgICBnZXRMaXN0OiAocGFnZVRva2VuPzogc3RyaW5nKSA9PiBHYXhpb3NQcm9taXNlPFQ+LFxuICAgICAgICBleHRyYWN0TGlzdDogKGFyZzogVCkgPT4gVVtdIHwgdW5kZWZpbmVkLFxuICAgICAgICBleHRyYWN0RWxlbWVudDogKGFyZzogVSkgPT4gc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgICAgICBkb1JlbW92ZTogKGFyZzogc3RyaW5nKSA9PiBQcm9taXNlPGFueT5cbiAgICApIHtcbiAgICAgICAgY29uc3QgYWxsUmVzb3VyY2VzID0gYXdhaXQgbGlzdEdvb2dsZVJlc291cmNlKFxuICAgICAgICAgICAgcGF0dGVybixcbiAgICAgICAgICAgIGdldExpc3QsXG4gICAgICAgICAgICBleHRyYWN0TGlzdCxcbiAgICAgICAgICAgIGV4dHJhY3RFbGVtZW50XG4gICAgICAgICk7XG4gICAgICAgIG5SZXNvdXJjZXMgKz0gYWxsUmVzb3VyY2VzLmxlbmd0aDtcbiAgICAgICAgaWYgKGV4ZWN1dGUpIHtcbiAgICAgICAgICAgIGF3YWl0IGRlbGV0ZVJlc291cmNlcyhuYW1lLCBhbGxSZXNvdXJjZXMsIGRvUmVtb3ZlLCB7XG4gICAgICAgICAgICAgICAgY29uY3VycmVuY3k6IDIwLFxuICAgICAgICAgICAgICAgIHJhdGU6IDIwLFxuICAgICAgICAgICAgICAgIGJ1cnN0OiAyMFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgY29uc3QgeyBjbG91ZEZ1bmN0aW9ucywgcHVic3ViIH0gPSBhd2FpdCBnb29nbGVGYWFzdC5pbml0aWFsaXplR29vZ2xlU2VydmljZXMoKTtcbiAgICBjb25zdCBwcm9qZWN0ID0gYXdhaXQgZ29vZ2xlLmF1dGguZ2V0UHJvamVjdElkKCk7XG4gICAgbG9nKGBEZWZhdWx0IHByb2plY3Q6ICR7cHJvamVjdH1gKTtcblxuICAgIG91dHB1dChgQ2xvdWQgZnVuY3Rpb25zYCk7XG4gICAgYXdhaXQgZGVsZXRlR29vZ2xlUmVzb3VyY2UoXG4gICAgICAgIFwiQ2xvdWQgRnVuY3Rpb24ocylcIixcbiAgICAgICAgbmV3IFJlZ0V4cChgZmFhc3QtJHt1dWlkdjRQYXR0ZXJufWApLFxuICAgICAgICAocGFnZVRva2VuPzogc3RyaW5nKSA9PlxuICAgICAgICAgICAgY2xvdWRGdW5jdGlvbnMucHJvamVjdHMubG9jYXRpb25zLmZ1bmN0aW9ucy5saXN0KHtcbiAgICAgICAgICAgICAgICBwYWdlVG9rZW4sXG4gICAgICAgICAgICAgICAgcGFyZW50OiBgcHJvamVjdHMvJHtwcm9qZWN0fS9sb2NhdGlvbnMvLWBcbiAgICAgICAgICAgIH0pLFxuICAgICAgICBwYWdlID0+IHBhZ2UuZnVuY3Rpb25zLFxuICAgICAgICBmdW5jID0+IGZ1bmMubmFtZSA/PyB1bmRlZmluZWQsXG4gICAgICAgIG5hbWUgPT4gY2xvdWRGdW5jdGlvbnMucHJvamVjdHMubG9jYXRpb25zLmZ1bmN0aW9ucy5kZWxldGUoeyBuYW1lIH0pXG4gICAgKTtcblxuICAgIG91dHB1dChgUHViL1N1YiBzdWJzY3JpcHRpb25zYCk7XG4gICAgYXdhaXQgZGVsZXRlR29vZ2xlUmVzb3VyY2UoXG4gICAgICAgIFwiUHViL1N1YiBTdWJzY3JpcHRpb24ocylcIixcbiAgICAgICAgbmV3IFJlZ0V4cChgZmFhc3QtJHt1dWlkdjRQYXR0ZXJufWApLFxuICAgICAgICBwYWdlVG9rZW4gPT5cbiAgICAgICAgICAgIHB1YnN1Yi5wcm9qZWN0cy5zdWJzY3JpcHRpb25zLmxpc3Qoe1xuICAgICAgICAgICAgICAgIHBhZ2VUb2tlbixcbiAgICAgICAgICAgICAgICBwcm9qZWN0OiBgcHJvamVjdHMvJHtwcm9qZWN0fWBcbiAgICAgICAgICAgIH0pLFxuICAgICAgICBwYWdlID0+IHBhZ2Uuc3Vic2NyaXB0aW9ucyxcbiAgICAgICAgc3Vic2NyaXB0aW9uID0+IHN1YnNjcmlwdGlvbi5uYW1lID8/IHVuZGVmaW5lZCxcbiAgICAgICAgc3Vic2NyaXB0aW9uTmFtZSA9PlxuICAgICAgICAgICAgcHVic3ViLnByb2plY3RzLnN1YnNjcmlwdGlvbnMuZGVsZXRlKHsgc3Vic2NyaXB0aW9uOiBzdWJzY3JpcHRpb25OYW1lIH0pXG4gICAgKTtcblxuICAgIG91dHB1dChgUHViL1N1YiB0b3BpY3NgKTtcbiAgICBhd2FpdCBkZWxldGVHb29nbGVSZXNvdXJjZShcbiAgICAgICAgXCJQdWIvU3ViIHRvcGljKHMpXCIsXG4gICAgICAgIG5ldyBSZWdFeHAoYHRvcGljcy9mYWFzdC0ke3V1aWR2NFBhdHRlcm59YCksXG4gICAgICAgIHBhZ2VUb2tlbiA9PlxuICAgICAgICAgICAgcHVic3ViLnByb2plY3RzLnRvcGljcy5saXN0KHsgcGFnZVRva2VuLCBwcm9qZWN0OiBgcHJvamVjdHMvJHtwcm9qZWN0fWAgfSksXG4gICAgICAgIHBhZ2UgPT4gcGFnZS50b3BpY3MsXG4gICAgICAgIHRvcGljID0+IHRvcGljLm5hbWUgPz8gdW5kZWZpbmVkLFxuICAgICAgICB0b3BpY05hbWUgPT4gcHVic3ViLnByb2plY3RzLnRvcGljcy5kZWxldGUoeyB0b3BpYzogdG9waWNOYW1lIH0pXG4gICAgKTtcblxuICAgIHJldHVybiBuUmVzb3VyY2VzO1xufVxuXG5hc3luYyBmdW5jdGlvbiBjbGVhbnVwTG9jYWwoeyBleGVjdXRlIH06IENsZWFudXBPcHRpb25zKSB7XG4gICAgY29uc3Qgb3V0cHV0ID0gKG1zZzogc3RyaW5nKSA9PiAhZXhlY3V0ZSAmJiBsb2cobXNnKTtcbiAgICBjb25zdCB0bXBEaXIgPSB0bXBkaXIoKTtcbiAgICBjb25zdCBkaXIgPSBhd2FpdCByZWFkZGlyKHRtcERpcik7XG4gICAgbGV0IG5SZXNvdXJjZXMgPSAwO1xuICAgIG91dHB1dChgVGVtcG9yYXJ5IGRpcmVjdG9yaWVzOmApO1xuICAgIGNvbnN0IGVudHJ5UmVnZXhwID0gbmV3IFJlZ0V4cChgXmZhYXN0LSR7dXVpZHY0UGF0dGVybn0kYCk7XG4gICAgZm9yIChjb25zdCBlbnRyeSBvZiBkaXIpIHtcbiAgICAgICAgaWYgKGVudHJ5Lm1hdGNoKGVudHJ5UmVnZXhwKSkge1xuICAgICAgICAgICAgblJlc291cmNlcysrO1xuICAgICAgICAgICAgY29uc3QgZmFhc3REaXIgPSBwYXRoLmpvaW4odG1wRGlyLCBlbnRyeSk7XG4gICAgICAgICAgICBvdXRwdXQoYCR7ZmFhc3REaXJ9YCk7XG4gICAgICAgICAgICBpZiAoZXhlY3V0ZSkge1xuICAgICAgICAgICAgICAgIGF3YWl0IHJlbW92ZShmYWFzdERpcik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG5SZXNvdXJjZXM7XG59XG5cbmltcG9ydCAqIGFzIHJlYWRsaW5lIGZyb20gXCJyZWFkbGluZVwiO1xuXG5hc3luYyBmdW5jdGlvbiBwcm9tcHQoKSB7XG4gICAgY29uc3QgcmwgPSByZWFkbGluZS5jcmVhdGVJbnRlcmZhY2Uoe1xuICAgICAgICBpbnB1dDogcHJvY2Vzcy5zdGRpbixcbiAgICAgICAgb3V0cHV0OiBwcm9jZXNzLnN0ZG91dFxuICAgIH0pO1xuXG4gICAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4ocmVzb2x2ZSA9PiB7XG4gICAgICAgIHJsLnF1ZXN0aW9uKFxuICAgICAgICAgICAgXCJXQVJOSU5HOiB0aGlzIG9wZXJhdGlvbiB3aWxsIGRlbGV0ZSByZXNvdXJjZXMuIENvbmZpcm0/IFt5L05dIFwiLFxuICAgICAgICAgICAgYW5zd2VyID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoYW5zd2VyICE9PSBcInlcIikge1xuICAgICAgICAgICAgICAgICAgICBsb2coYEV4ZWN1dGlvbiBhYm9ydGVkLmApO1xuICAgICAgICAgICAgICAgICAgICBwcm9jZXNzLmV4aXQoMCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJsLmNsb3NlKCk7XG4gICAgICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH0pO1xufVxuXG5hc3luYyBmdW5jdGlvbiBydW5DbGVhbnVwKGNsb3VkOiBzdHJpbmcsIG9wdGlvbnM6IENsZWFudXBPcHRpb25zKSB7XG4gICAgbGV0IG5SZXNvdXJjZXMgPSAwO1xuICAgIGlmIChjbG91ZCA9PT0gXCJhd3NcIikge1xuICAgICAgICBuUmVzb3VyY2VzID0gYXdhaXQgY2xlYW51cEFXUyhvcHRpb25zKTtcbiAgICB9IGVsc2UgaWYgKGNsb3VkID09PSBcImdvb2dsZVwiKSB7XG4gICAgICAgIG5SZXNvdXJjZXMgPSBhd2FpdCBjbGVhbnVwR29vZ2xlKG9wdGlvbnMpO1xuICAgIH0gZWxzZSBpZiAoY2xvdWQgPT09IFwibG9jYWxcIikge1xuICAgICAgICBuUmVzb3VyY2VzID0gYXdhaXQgY2xlYW51cExvY2FsKG9wdGlvbnMpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHdhcm4oXG4gICAgICAgICAgICBgVW5rbm93biBjbG91ZCBuYW1lIFwiJHtjbG91ZH1cIi4gTXVzdCBzcGVjaWZ5IFwiYXdzXCIgb3IgXCJnb29nbGVcIiwgb3IgXCJsb2NhbFwiLmBcbiAgICAgICAgKTtcbiAgICAgICAgcHJvY2Vzcy5leGl0KC0xKTtcbiAgICB9XG4gICAgaWYgKG9wdGlvbnMuZXhlY3V0ZSkge1xuICAgICAgICBsb2coYERvbmUuYCk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKG5SZXNvdXJjZXMgPT09IDApIHtcbiAgICAgICAgICAgIGxvZyhgTm8gcmVzb3VyY2VzIHRvIGNsZWFuIHVwLmApO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBuUmVzb3VyY2VzO1xufVxuXG5hc3luYyBmdW5jdGlvbiBtYWluKCkge1xuICAgIGxldCBjbG91ZCE6IHN0cmluZztcbiAgICBsZXQgY29tbWFuZDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIHByb2dyYW1cbiAgICAgICAgLnZlcnNpb24oXCIwLjEuMFwiKVxuICAgICAgICAub3B0aW9uKFwiLXYsIC0tdmVyYm9zZVwiLCBcIlZlcmJvc2UgbW9kZVwiKVxuICAgICAgICAub3B0aW9uKFxuICAgICAgICAgICAgXCItciwgLS1yZWdpb24gPHJlZ2lvbj5cIixcbiAgICAgICAgICAgIFwiQ2xvdWQgcmVnaW9uIHRvIG9wZXJhdGUgb24uIERlZmF1bHRzIHRvIHVzLXdlc3QtMiBmb3IgQVdTLCBhbmQgdXMtY2VudHJhbDEgZm9yIEdvb2dsZS5cIlxuICAgICAgICApXG4gICAgICAgIC5vcHRpb24oXG4gICAgICAgICAgICBcIi14LCAtLWV4ZWN1dGVcIixcbiAgICAgICAgICAgIFwiRXhlY3V0ZSB0aGUgY2xlYW51cCBwcm9jZXNzLiBJZiB0aGlzIG9wdGlvbiBpcyBub3Qgc3BlY2lmaWVkLCB0aGUgb3V0cHV0IHdpbGwgYmUgYSBkcnkgcnVuLlwiXG4gICAgICAgIClcbiAgICAgICAgLm9wdGlvbihcIi1mLCAtLWZvcmNlXCIsIFwiV2hlbiB1c2VkIHdpdGggLXgsIHNraXBzIHRoZSBwcm9tcHRcIilcbiAgICAgICAgLmNvbW1hbmQoXCJjbGVhbnVwIDxjbG91ZD5cIilcbiAgICAgICAgLmRlc2NyaXB0aW9uKFxuICAgICAgICAgICAgYENsZWFudXAgZmFhc3QuanMgcmVzb3VyY2VzIHRoYXQgbWF5IGhhdmUgbGVha2VkLiBUaGUgPGNsb3VkPiBhcmd1bWVudCBtdXN0IGJlIFwiYXdzXCIsIFwiZ29vZ2xlXCIsIG9yIFwibG9jYWxcIi5cbiAgICAgICAgQnkgZGVmYXVsdCB0aGUgb3V0cHV0IGlzIGEgZHJ5IHJ1biBhbmQgd2lsbCBvbmx5IHByaW50IHRoZSBhY3Rpb25zIHRoYXQgd291bGQgYmUgcGVyZm9ybWVkIGlmICcteCcgaXMgc3BlY2lmaWVkLmBcbiAgICAgICAgKVxuICAgICAgICAuYWN0aW9uKChhcmc6IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgY29tbWFuZCA9IFwiY2xlYW51cFwiO1xuICAgICAgICAgICAgY2xvdWQgPSBhcmc7XG4gICAgICAgIH0pO1xuXG4gICAgY29uc3Qgb3B0cyA9IHByb2dyYW0ucGFyc2UocHJvY2Vzcy5hcmd2KS5vcHRzKCk7XG4gICAgaWYgKG9wdHMudmVyYm9zZSkge1xuICAgICAgICBwcm9jZXNzLmVudi5ERUJVRyA9IFwiZmFhc3Q6KlwiO1xuICAgIH1cbiAgICBjb25zdCBleGVjdXRlID0gb3B0cy5leGVjdXRlIHx8IGZhbHNlO1xuICAgIGxldCByZWdpb24gPSBvcHRzLnJlZ2lvbjtcblxuICAgIGlmICghcmVnaW9uKSB7XG4gICAgICAgIHN3aXRjaCAoY2xvdWQpIHtcbiAgICAgICAgICAgIGNhc2UgXCJhd3NcIjpcbiAgICAgICAgICAgICAgICByZWdpb24gPSBhd3NGYWFzdC5kZWZhdWx0cy5yZWdpb247XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwiZ29vZ2xlXCI6XG4gICAgICAgICAgICAgICAgcmVnaW9uID0gZ29vZ2xlRmFhc3QuZGVmYXVsdHMucmVnaW9uO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbnN0IGZvcmNlID0gb3B0cy5mb3JjZSB8fCBmYWxzZTtcblxuICAgIHJlZ2lvbiAmJiBsb2coYFJlZ2lvbjogJHtyZWdpb259YCk7XG4gICAgY29uc3Qgb3B0aW9ucyA9IHsgcmVnaW9uLCBleGVjdXRlIH07XG4gICAgbGV0IG5SZXNvdXJjZXMgPSAwO1xuICAgIGlmIChjb21tYW5kID09PSBcImNsZWFudXBcIikge1xuICAgICAgICBpZiAoZXhlY3V0ZSAmJiAhZm9yY2UpIHtcbiAgICAgICAgICAgIG5SZXNvdXJjZXMgPSBhd2FpdCBydW5DbGVhbnVwKGNsb3VkLCB7IC4uLm9wdGlvbnMsIGV4ZWN1dGU6IGZhbHNlIH0pO1xuICAgICAgICAgICAgaWYgKG5SZXNvdXJjZXMgPiAwKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgcHJvbXB0KCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHByb2Nlc3MuZXhpdCgwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBuUmVzb3VyY2VzID0gYXdhaXQgcnVuQ2xlYW51cChjbG91ZCwgb3B0aW9ucyk7XG4gICAgICAgIGlmICghZXhlY3V0ZSAmJiBuUmVzb3VyY2VzID4gMCkge1xuICAgICAgICAgICAgbG9nKFxuICAgICAgICAgICAgICAgIGAoZHJ5cnVuIG1vZGUsIG5vIHJlc291cmNlcyB3aWxsIGJlIGRlbGV0ZWQsIHNwZWNpZnkgLXggdG8gZXhlY3V0ZSBjbGVhbnVwKWBcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgICBsb2coYE5vIGNvbW1hbmQgc3BlY2lmaWVkLmApO1xuICAgICAgICBwcm9ncmFtLmhlbHAoKTtcbiAgICB9XG59XG5cbm1haW4oKTtcbiJdfQ==
\No newline at end of file