1 |
|
2 | ;
|
3 | Object.defineProperty(exports, "__esModule", { value: true });
|
4 | require("source-map-support").install();
|
5 | const commander_1 = require("commander");
|
6 | const fs_extra_1 = require("fs-extra");
|
7 | const googleapis_1 = require("googleapis");
|
8 | const ora = require("ora");
|
9 | const os_1 = require("os");
|
10 | const path = require("path");
|
11 | const awsFaast = require("./aws/aws-faast");
|
12 | const cache_1 = require("./cache");
|
13 | const googleFaast = require("./google/google-faast");
|
14 | const shared_1 = require("./shared");
|
15 | const throttle_1 = require("./throttle");
|
16 | const warn = console.warn;
|
17 | const log = console.log;
|
18 | async 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 | }
|
44 | async 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 | }
|
133 | async 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 | }
|
141 | async 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 | }
|
182 | async 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 | }
|
201 | const readline = require("readline");
|
202 | async 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 | }
|
218 | async 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 | }
|
243 | async 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 | }
|
299 | main();
|
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 |