UNPKG

26 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const ava_1 = require("ava");
4const uuid_1 = require("uuid");
5const index_1 = require("../index");
6const aws_faast_1 = require("../src/aws/aws-faast");
7const util_aws_1 = require("./fixtures/util-aws");
8const functions = require("./fixtures/functions");
9const util_1 = require("./fixtures/util");
10const assert = require("assert");
11async function waitForLogGroupCreation(cloudwatch, logGroupName, message) {
12 let n = 0;
13 while (true) {
14 await (0, util_1.sleep)(1000);
15 try {
16 n++;
17 const described = await cloudwatch
18 .describeLogGroups({ logGroupNamePrefix: logGroupName })
19 .promise();
20 if (!described.logGroups) {
21 continue;
22 }
23 const retrievedLogGroup = described.logGroups?.[0]?.logGroupName;
24 if (!retrievedLogGroup) {
25 continue;
26 }
27 assert(retrievedLogGroup === logGroupName, `Unexpected logGroupName: ${retrievedLogGroup}, expecting ${logGroupName}`);
28 const logResult = await cloudwatch
29 .filterLogEvents({ logGroupName })
30 .promise();
31 const events = logResult.events ?? [];
32 // console.log(`[${n}] Found log group: ${logGroupName}`);
33 let foundMessage = false;
34 for (const event of events) {
35 // console.log(
36 // `[${n}] ${event.logStreamName} ${event.eventId} ${event.timestamp} ${event.message}`
37 // );
38 if (event.message.includes(message)) {
39 foundMessage = true;
40 }
41 if (foundMessage && event.message.match(/REPORT RequestId/)) {
42 return;
43 }
44 }
45 }
46 catch (err) {
47 console.error(`Transient error waiting for log group creation: ${err}`);
48 }
49 }
50}
51ava_1.default.serial((0, util_1.title)("aws", "garbage collects functions that are called"), async (t) => {
52 // Idea behind this test: create a faast module and make a call. Then
53 // cleanup while leaving the resources in place. Then create another faast
54 // module and set its retention to 0, and use a synthetic gc worker to
55 // observe and verify the garbage collector actually cleans up.
56 const mod = await (0, index_1.faastAws)(functions, {
57 gc: "off",
58 mode: "queue",
59 description: t.title,
60 packageJson: {
61 name: (0, uuid_1.v4)(),
62 dependencies: {
63 tslib: "^1.9.1"
64 }
65 },
66 maxRetries: 0
67 });
68 try {
69 await mod.functions.consoleLog("gc-test-string");
70 const { cloudwatch } = mod.state.services;
71 const { logGroupName } = mod.state.resources;
72 await waitForLogGroupCreation(cloudwatch, logGroupName, "gc-test-string");
73 await mod.cleanup({ deleteResources: false, gcTimeout: 0 });
74 // Create some work for gc to do by removing the log retention policy, gc
75 // should add it back.
76 const deleteRetentionPolicy = (0, index_1.throttle)({ concurrency: 1, retry: 5 }, () => cloudwatch.deleteRetentionPolicy({ logGroupName }).promise());
77 await deleteRetentionPolicy();
78 let deletedLayer = false;
79 const { layer, FunctionName } = mod.state.resources;
80 // log.gc.enabled = true;
81 const mod2 = await (0, index_1.faastAws)(functions, {
82 gc: "force",
83 retentionInDays: 0,
84 description: t.title,
85 _gcWorker: async (work, services) => {
86 switch (work.type) {
87 case "SetLogRetention":
88 // checkResourcesCleanedUp will verify the log group is
89 // deleted.
90 await (0, aws_faast_1.defaultGcWorker)(work, services);
91 break;
92 case "DeleteLayerVersion":
93 if (work.LayerName === layer.LayerName) {
94 index_1.log.gc(`deleting layer ${work.LayerName}`);
95 await (0, aws_faast_1.defaultGcWorker)(work, services);
96 deletedLayer = true;
97 }
98 break;
99 case "DeleteResources":
100 if (work.resources.FunctionName === FunctionName) {
101 index_1.log.gc(`deleting resources for ${FunctionName}`);
102 await (0, aws_faast_1.defaultGcWorker)(work, services);
103 }
104 }
105 }
106 });
107 await mod2.cleanup({ gcTimeout: 0 });
108 t.true(deletedLayer, "Deleted layer is true");
109 await (0, util_1.checkResourcesCleanedUp)(t, await (0, util_aws_1.getAWSResources)(mod, true));
110 }
111 finally {
112 index_1.log.gc.enabled = false;
113 await mod.cleanup({ deleteResources: true, deleteCaches: true, gcTimeout: 0 });
114 }
115});
116ava_1.default.serial((0, util_1.title)("aws", "garbage collects functions that are never called"), async (t) => {
117 const mod = await (0, index_1.faastAws)(functions, {
118 gc: "off",
119 mode: "queue",
120 description: t.title,
121 maxRetries: 0
122 });
123 try {
124 await mod.cleanup({ deleteResources: false, gcTimeout: 0 });
125 const { FunctionName } = mod.state.resources;
126 const mod2 = await (0, index_1.faastAws)(functions, {
127 gc: "force",
128 retentionInDays: 0,
129 description: t.title,
130 _gcWorker: async (work, services) => {
131 switch (work.type) {
132 case "DeleteResources":
133 if (work.resources.FunctionName === FunctionName) {
134 index_1.log.gc(`deleting resources for ${FunctionName}`);
135 await (0, aws_faast_1.defaultGcWorker)(work, services);
136 }
137 }
138 }
139 });
140 await mod2.cleanup({ gcTimeout: 0 });
141 // Don't fail if a log group exists because we didn't wait for its
142 // creation; it might be created by AWS after the cleanup occurs. The
143 // reason is that the log group will only be created if there's an
144 // invocation test, which only happens in the special case that the role
145 // was recently created. Which is true for the nightly testsuite but
146 // rarely elsewhere.
147 const { logGroupResult, ...resources } = await (0, util_aws_1.getAWSResources)(mod, true);
148 await (0, util_1.checkResourcesCleanedUp)(t, resources);
149 }
150 finally {
151 await mod.cleanup({ deleteResources: true, deleteCaches: true, gcTimeout: 0 });
152 }
153});
154ava_1.default.skip((0, util_1.title)("aws", "garbage collection caching"), async (t) => {
155 {
156 // Run a real gc so the build account doesn't accumulate garbage.
157 const mod = await (0, index_1.faastAws)(functions, { gc: "force", description: t.title });
158 await mod.cleanup({ gcTimeout: 0 });
159 t.is(await mod.state.gcPromise, "done");
160 }
161 {
162 // Test the in-memory cache that prevents gc from multiple faast.js
163 // instances from running at the same time.
164 const mod = await (0, index_1.faastAws)(functions, { description: t.title });
165 await mod.cleanup();
166 t.is(await mod.state.gcPromise, "skipped");
167 }
168 {
169 // Test the persistent cache that prevents gc from running too often
170 // even across processes.
171 (0, aws_faast_1.clearLastGc)();
172 const mod = await (0, index_1.faastAws)(functions, { description: t.title });
173 await mod.cleanup();
174 t.is(await mod.state.gcPromise, "skipped");
175 }
176});
177//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXdzLWdjLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90ZXN0L2F3cy1nYy50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsNkJBQXVCO0FBRXZCLCtCQUFrQztBQUNsQyxvQ0FBbUQ7QUFDbkQsb0RBQW9FO0FBQ3BFLGtEQUFzRDtBQUN0RCxrREFBa0Q7QUFDbEQsMENBQXdFO0FBQ3hFLGlDQUFpQztBQUVqQyxLQUFLLFVBQVUsdUJBQXVCLENBQ2xDLFVBQTBCLEVBQzFCLFlBQW9CLEVBQ3BCLE9BQWU7SUFFZixJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDVixPQUFPLElBQUksRUFBRTtRQUNULE1BQU0sSUFBQSxZQUFLLEVBQUMsSUFBSSxDQUFDLENBQUM7UUFDbEIsSUFBSTtZQUNBLENBQUMsRUFBRSxDQUFDO1lBQ0osTUFBTSxTQUFTLEdBQUcsTUFBTSxVQUFVO2lCQUM3QixpQkFBaUIsQ0FBQyxFQUFFLGtCQUFrQixFQUFFLFlBQVksRUFBRSxDQUFDO2lCQUN2RCxPQUFPLEVBQUUsQ0FBQztZQUNmLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxFQUFFO2dCQUN0QixTQUFTO2FBQ1o7WUFDRCxNQUFNLGlCQUFpQixHQUFHLFNBQVMsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxZQUFZLENBQUM7WUFDakUsSUFBSSxDQUFDLGlCQUFpQixFQUFFO2dCQUNwQixTQUFTO2FBQ1o7WUFDRCxNQUFNLENBQ0YsaUJBQWlCLEtBQUssWUFBWSxFQUNsQyw0QkFBNEIsaUJBQWlCLGVBQWUsWUFBWSxFQUFFLENBQzdFLENBQUM7WUFDRixNQUFNLFNBQVMsR0FBRyxNQUFNLFVBQVU7aUJBQzdCLGVBQWUsQ0FBQyxFQUFFLFlBQVksRUFBRSxDQUFDO2lCQUNqQyxPQUFPLEVBQUUsQ0FBQztZQUNmLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxNQUFNLElBQUksRUFBRSxDQUFDO1lBQ3RDLDBEQUEw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QUNJLG9FQUFvRTtRQUNwRSx5QkFBeUI7UUFDekIsSUFBQSx1QkFBVyxHQUFFLENBQUM7UUFDZCxNQUFNLEdBQUcsR0FBRyxNQUFNLElBQUEsZ0JBQVEsRUFBQyxTQUFTLEVBQUUsRUFBRSxXQUFXLEVBQUUsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDaEUsTUFBTSxHQUFHLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDcEIsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLFNBQVMsQ0FBQyxDQUFDO0tBQzlDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdGVzdCBmcm9tIFwiYXZhXCI7XG5pbXBvcnQgeyBDbG91ZFdhdGNoTG9ncyB9IGZyb20gXCJhd3Mtc2RrXCI7XG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSBcInV1aWRcIjtcbmltcG9ydCB7IGZhYXN0QXdzLCBsb2csIHRocm90dGxlIH0gZnJvbSBcIi4uL2luZGV4XCI7XG5pbXBvcnQgeyBkZWZhdWx0R2NXb3JrZXIsIGNsZWFyTGFzdEdjIH0gZnJvbSBcIi4uL3NyYy9hd3MvYXdzLWZhYXN0XCI7XG5pbXBvcnQgeyBnZXRBV1NSZXNvdXJjZXMgfSBmcm9tIFwiLi9maXh0dXJlcy91dGlsLWF3c1wiO1xuaW1wb3J0ICogYXMgZnVuY3Rpb25zIGZyb20gXCIuL2ZpeHR1cmVzL2Z1bmN0aW9uc1wiO1xuaW1wb3J0IHsgY2hlY2tSZXNvdXJjZXNDbGVhbmVkVXAsIHNsZWVwLCB0aXRsZSB9IGZyb20gXCIuL2ZpeHR1cmVzL3V0aWxcIjtcbmltcG9ydCAqIGFzIGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5cbmFzeW5jIGZ1bmN0aW9uIHdhaXRGb3JMb2dHcm91cENyZWF0aW9uKFxuICAgIGNsb3Vkd2F0Y2g6IENsb3VkV2F0Y2hMb2dzLFxuICAgIGxvZ0dyb3VwTmFtZTogc3RyaW5nLFxuICAgIG1lc3NhZ2U6IHN0cmluZ1xuKSB7XG4gICAgbGV0IG4gPSAwO1xuICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgIGF3YWl0IHNsZWVwKDEwMDApO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgbisrO1xuICAgICAgICAgICAgY29uc3QgZGVzY3JpYmVkID0gYXdhaXQgY2xvdWR3YXRjaFxuICAgICAgICAgICAgICAgIC5kZXNjcmliZUxvZ0dyb3Vwcyh7IGxvZ0dyb3VwTmFtZVByZWZpeDogbG9nR3JvdXBOYW1lIH0pXG4gICAgICAgICAgICAgICAgLnByb21pc2UoKTtcbiAgICAgICAgICAgIGlmICghZGVzY3JpYmVkLmxvZ0dyb3Vwcykge1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgcmV0cmlldmVkTG9nR3JvdXAgPSBkZXNjcmliZWQubG9nR3JvdXBzPy5bMF0/LmxvZ0dyb3VwTmFtZTtcbiAgICAgICAgICAgIGlmICghcmV0cmlldmVkTG9nR3JvdXApIHtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGFzc2VydChcbiAgICAgICAgICAgICAgICByZXRyaWV2ZWRMb2dHcm91cCA9PT0gbG9nR3JvdXBOYW1lLFxuICAgICAgICAgICAgICAgIGBVbmV4cGVjdGVkIGxvZ0dyb3VwTmFtZTogJHtyZXRyaWV2ZWRMb2dHcm91cH0sIGV4cGVjdGluZyAke2xvZ0dyb3VwTmFtZX1gXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgbG9nUmVzdWx0ID0gYXdhaXQgY2xvdWR3YXRjaFxuICAgICAgICAgICAgICAgIC5maWx0ZXJMb2dFdmVudHMoeyBsb2dHcm91cE5hbWUgfSlcbiAgICAgICAgICAgICAgICAucHJvbWlzZSgpO1xuICAgICAgICAgICAgY29uc3QgZXZlbnRzID0gbG9nUmVzdWx0LmV2ZW50cyA/PyBbXTtcbiAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKGBbJHtufV0gRm91bmQgbG9nIGdyb3VwOiAke2xvZ0dyb3VwTmFtZX1gKTtcbiAgICAgICAgICAgIGxldCBmb3VuZE1lc3NhZ2UgPSBmYWxzZTtcbiAgICAgICAgICAgIGZvciAoY29uc3QgZXZlbnQgb2YgZXZlbnRzKSB7XG4gICAgICAgICAgICAgICAgLy8gY29uc29sZS5sb2coXG4gICAgICAgICAgICAgICAgLy8gICAgIGBbJHtufV0gJHtldmVudC5sb2dTdHJlYW1OYW1lfSAke2V2ZW50LmV2ZW50SWR9ICR7ZXZlbnQudGltZXN0YW1wfSAke2V2ZW50Lm1lc3NhZ2V9YFxuICAgICAgICAgICAgICAgIC8vICk7XG4gICAgICAgICAgICAgICAgaWYgKGV2ZW50Lm1lc3NhZ2UhLmluY2x1ZGVzKG1lc3NhZ2UpKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvdW5kTWVzc2FnZSA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChmb3VuZE1lc3NhZ2UgJiYgZXZlbnQubWVzc2FnZSEubWF0Y2goL1JFUE9SVCBSZXF1ZXN0SWQvKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihgVHJhbnNpZW50IGVycm9yIHdhaXRpbmcgZm9yIGxvZyBncm91cCBjcmVhdGlvbjogJHtlcnJ9YCk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbnRlc3Quc2VyaWFsKHRpdGxlKFwiYXdzXCIsIFwiZ2FyYmFnZSBjb2xsZWN0cyBmdW5jdGlvbnMgdGhhdCBhcmUgY2FsbGVkXCIpLCBhc3luYyB0ID0+IHtcbiAgICAvLyBJZGVhIGJlaGluZCB0aGlzIHRlc3Q6IGNyZWF0ZSBhIGZhYXN0IG1vZHVsZSBhbmQgbWFrZSBhIGNhbGwuIFRoZW5cbiAgICAvLyBjbGVhbnVwIHdoaWxlIGxlYXZpbmcgdGhlIHJlc291cmNlcyBpbiBwbGFjZS4gVGhlbiBjcmVhdGUgYW5vdGhlciBmYWFzdFxuICAgIC8vIG1vZHVsZSBhbmQgc2V0IGl0cyByZXRlbnRpb24gdG8gMCwgYW5kIHVzZSBhIHN5bnRoZXRpYyBnYyB3b3JrZXIgdG9cbiAgICAvLyBvYnNlcnZlIGFuZCB2ZXJpZnkgdGhlIGdhcmJhZ2UgY29sbGVjdG9yIGFjdHVhbGx5IGNsZWFucyB1cC5cbiAgICBjb25zdCBtb2QgPSBhd2FpdCBmYWFzdEF3cyhmdW5jdGlvbnMsIHtcbiAgICAgICAgZ2M6IFwib2ZmXCIsXG4gICAgICAgIG1vZGU6IFwicXVldWVcIixcbiAgICAgICAgZGVzY3JpcHRpb246IHQudGl0bGUsXG4gICAgICAgIHBhY2thZ2VKc29uOiB7XG4gICAgICAgICAgICBuYW1lOiB1dWlkKCksXG4gICAgICAgICAgICBkZXBlbmRlbmNpZXM6IHtcbiAgICAgICAgICAgICAgICB0c2xpYjogXCJeMS45LjFcIlxuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBtYXhSZXRyaWVzOiAwXG4gICAgfSk7XG4gICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgbW9kLmZ1bmN0aW9ucy5jb25zb2xlTG9nKFwiZ2MtdGVzdC1zdHJpbmdcIik7XG4gICAgICAgIGNvbnN0IHsgY2xvdWR3YXRjaCB9ID0gbW9kLnN0YXRlLnNlcnZpY2VzO1xuICAgICAgICBjb25zdCB7IGxvZ0dyb3VwTmFtZSB9ID0gbW9kLnN0YXRlLnJlc291cmNlcztcbiAgICAgICAgYXdhaXQgd2FpdEZvckxvZ0dyb3VwQ3JlYXRpb24oY2xvdWR3YXRjaCwgbG9nR3JvdXBOYW1lLCBcImdjLXRlc3Qtc3RyaW5nXCIpO1xuICAgICAgICBhd2FpdCBtb2QuY2xlYW51cCh7IGRlbGV0ZVJlc291cmNlczogZmFsc2UsIGdjVGltZW91dDogMCB9KTtcblxuICAgICAgICAvLyBDcmVhdGUgc29tZSB3b3JrIGZvciBnYyB0byBkbyBieSByZW1vdmluZyB0aGUgbG9nIHJldGVudGlvbiBwb2xpY3ksIGdjXG4gICAgICAgIC8vIHNob3VsZCBhZGQgaXQgYmFjay5cbiAgICAgICAgY29uc3QgZGVsZXRlUmV0ZW50aW9uUG9saWN5ID0gdGhyb3R0bGUoeyBjb25jdXJyZW5jeTogMSwgcmV0cnk6IDUgfSwgKCkgPT5cbiAgICAgICAgICAgIGNsb3Vkd2F0Y2guZGVsZXRlUmV0ZW50aW9uUG9saWN5KHsgbG9nR3JvdXBOYW1lIH0pLnByb21pc2UoKVxuICAgICAgICApO1xuICAgICAgICBhd2FpdCBkZWxldGVSZXRlbnRpb25Qb2xpY3koKTtcblxuICAgICAgICBsZXQgZGVsZXRlZExheWVyID0gZmFsc2U7XG4gICAgICAgIGNvbnN0IHsgbGF5ZXIsIEZ1bmN0aW9uTmFtZSB9ID0gbW9kLnN0YXRlLnJlc291cmNlcztcbiAgICAgICAgLy8gbG9nLmdjLmVuYWJsZWQgPSB0cnVlO1xuICAgICAgICBjb25zdCBtb2QyID0gYXdhaXQgZmFhc3RBd3MoZnVuY3Rpb25zLCB7XG4gICAgICAgICAgICBnYzogXCJmb3JjZVwiLFxuICAgICAgICAgICAgcmV0ZW50aW9uSW5EYXlzOiAwLFxuICAgICAgICAgICAgZGVzY3JpcHRpb246IHQudGl0bGUsXG4gICAgICAgICAgICBfZ2NXb3JrZXI6IGFzeW5jICh3b3JrLCBzZXJ2aWNlcykgPT4ge1xuICAgICAgICAgICAgICAgIHN3aXRjaCAod29yay50eXBlKSB7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgXCJTZXRMb2dSZXRlbnRpb25cIjpcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGNoZWNrUmVzb3VyY2VzQ2xlYW5lZFVwIHdpbGwgdmVyaWZ5IHRoZSBsb2cgZ3JvdXAgaXNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGRlbGV0ZWQuXG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBkZWZhdWx0R2NXb3JrZXIod29yaywgc2VydmljZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgXCJEZWxldGVMYXllclZlcnNpb25cIjpcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh3b3JrLkxheWVyTmFtZSA9PT0gbGF5ZXIhLkxheWVyTmFtZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZy5nYyhgZGVsZXRpbmcgbGF5ZXIgJHt3b3JrLkxheWVyTmFtZX1gKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBkZWZhdWx0R2NXb3JrZXIod29yaywgc2VydmljZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZWRMYXllciA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBcIkRlbGV0ZVJlc291cmNlc1wiOlxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHdvcmsucmVzb3VyY2VzLkZ1bmN0aW9uTmFtZSA9PT0gRnVuY3Rpb25OYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nLmdjKGBkZWxldGluZyByZXNvdXJjZXMgZm9yICR7RnVuY3Rpb25OYW1lfWApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IGRlZmF1bHRHY1dvcmtlcih3b3JrLCBzZXJ2aWNlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBhd2FpdCBtb2QyLmNsZWFudXAoeyBnY1RpbWVvdXQ6IDAgfSk7XG4gICAgICAgIHQudHJ1ZShkZWxldGVkTGF5ZXIsIFwiRGVsZXRlZCBsYXllciBpcyB0cnVlXCIpO1xuICAgICAgICBhd2FpdCBjaGVja1Jlc291cmNlc0NsZWFuZWRVcCh0LCBhd2FpdCBnZXRBV1NSZXNvdXJjZXMobW9kLCB0cnVlKSk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgICAgbG9nLmdjLmVuYWJsZWQgPSBmYWxzZTtcbiAgICAgICAgYXdhaXQgbW9kLmNsZWFudXAoeyBkZWxldGVSZXNvdXJjZXM6IHRydWUsIGRlbGV0ZUNhY2hlczogdHJ1ZSwgZ2NUaW1lb3V0OiAwIH0pO1xuICAgIH1cbn0pO1xuXG50ZXN0LnNlcmlhbCh0aXRsZShcImF3c1wiLCBcImdhcmJhZ2UgY29sbGVjdHMgZnVuY3Rpb25zIHRoYXQgYXJlIG5ldmVyIGNhbGxlZFwiKSwgYXN5bmMgdCA9PiB7XG4gICAgY29uc3QgbW9kID0gYXdhaXQgZmFhc3RBd3MoZnVuY3Rpb25zLCB7XG4gICAgICAgIGdjOiBcIm9mZlwiLFxuICAgICAgICBtb2RlOiBcInF1ZXVlXCIsXG4gICAgICAgIGRlc2NyaXB0aW9uOiB0LnRpdGxlLFxuICAgICAgICBtYXhSZXRyaWVzOiAwXG4gICAgfSk7XG4gICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgbW9kLmNsZWFudXAoeyBkZWxldGVSZXNvdXJjZXM6IGZhbHNlLCBnY1RpbWVvdXQ6IDAgfSk7XG4gICAgICAgIGNvbnN0IHsgRnVuY3Rpb25OYW1lIH0gPSBtb2Quc3RhdGUucmVzb3VyY2VzO1xuICAgICAgICBjb25zdCBtb2QyID0gYXdhaXQgZmFhc3RBd3MoZnVuY3Rpb25zLCB7XG4gICAgICAgICAgICBnYzogXCJmb3JjZVwiLFxuICAgICAgICAgICAgcmV0ZW50aW9uSW5EYXlzOiAwLFxuICAgICAgICAgICAgZGVzY3JpcHRpb246IHQudGl0bGUsXG4gICAgICAgICAgICBfZ2NXb3JrZXI6IGFzeW5jICh3b3JrLCBzZXJ2aWNlcykgPT4ge1xuICAgICAgICAgICAgICAgIHN3aXRjaCAod29yay50eXBlKSB7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgXCJEZWxldGVSZXNvdXJjZXNcIjpcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh3b3JrLnJlc291cmNlcy5GdW5jdGlvbk5hbWUgPT09IEZ1bmN0aW9uTmFtZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZy5nYyhgZGVsZXRpbmcgcmVzb3VyY2VzIGZvciAke0Z1bmN0aW9uTmFtZX1gKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBkZWZhdWx0R2NXb3JrZXIod29yaywgc2VydmljZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgYXdhaXQgbW9kMi5jbGVhbnVwKHsgZ2NUaW1lb3V0OiAwIH0pO1xuICAgICAgICAvLyBEb24ndCBmYWlsIGlmIGEgbG9nIGdyb3VwIGV4aXN0cyBiZWNhdXNlIHdlIGRpZG4ndCB3YWl0IGZvciBpdHNcbiAgICAgICAgLy8gY3JlYXRpb247IGl0IG1pZ2h0IGJlIGNyZWF0ZWQgYnkgQVdTIGFmdGVyIHRoZSBjbGVhbnVwIG9jY3Vycy4gVGhlXG4gICAgICAgIC8vIHJlYXNvbiBpcyB0aGF0IHRoZSBsb2cgZ3JvdXAgd2lsbCBvbmx5IGJlIGNyZWF0ZWQgaWYgdGhlcmUncyBhblxuICAgICAgICAvLyBpbnZvY2F0aW9uIHRlc3QsIHdoaWNoIG9ubHkgaGFwcGVucyBpbiB0aGUgc3BlY2lhbCBjYXNlIHRoYXQgdGhlIHJvbGVcbiAgICAgICAgLy8gd2FzIHJlY2VudGx5IGNyZWF0ZWQuIFdoaWNoIGlzIHRydWUgZm9yIHRoZSBuaWdodGx5IHRlc3RzdWl0ZSBidXRcbiAgICAgICAgLy8gcmFyZWx5IGVsc2V3aGVyZS5cbiAgICAgICAgY29uc3QgeyBsb2dHcm91cFJlc3VsdCwgLi4ucmVzb3VyY2VzIH0gPSBhd2FpdCBnZXRBV1NSZXNvdXJjZXMobW9kLCB0cnVlKTtcbiAgICAgICAgYXdhaXQgY2hlY2tSZXNvdXJjZXNDbGVhbmVkVXAodCwgcmVzb3VyY2VzKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgICBhd2FpdCBtb2QuY2xlYW51cCh7IGRlbGV0ZVJlc291cmNlczogdHJ1ZSwgZGVsZXRlQ2FjaGVzOiB0cnVlLCBnY1RpbWVvdXQ6IDAgfSk7XG4gICAgfVxufSk7XG5cbnRlc3Quc2tpcCh0aXRsZShcImF3c1wiLCBcImdhcmJhZ2UgY29sbGVjdGlvbiBjYWNoaW5nXCIpLCBhc3luYyB0ID0+IHtcbiAgICB7XG4gICAgICAgIC8vIFJ1biBhIHJlYWwgZ2Mgc28gdGhlIGJ1aWxkIGFjY291bnQgZG9lc24ndCBhY2N1bXVsYXRlIGdhcmJhZ2UuXG4gICAgICAgIGNvbnN0IG1vZCA9IGF3YWl0IGZhYXN0QXdzKGZ1bmN0aW9ucywgeyBnYzogXCJmb3JjZVwiLCBkZXNjcmlwdGlvbjogdC50aXRsZSB9KTtcbiAgICAgICAgYXdhaXQgbW9kLmNsZWFudXAoeyBnY1RpbWVvdXQ6IDAgfSk7XG4gICAgICAgIHQuaXMoYXdhaXQgbW9kLnN0YXRlLmdjUHJvbWlzZSwgXCJkb25lXCIpO1xuICAgIH1cblxuICAgIHtcbiAgICAgICAgLy8gVGVzdCB0aGUgaW4tbWVtb3J5IGNhY2hlIHRoYXQgcHJldmVudHMgZ2MgZnJvbSBtdWx0aXBsZSBmYWFzdC5qc1xuICAgICAgICAvLyBpbnN0YW5jZXMgZnJvbSBydW5uaW5nIGF0IHRoZSBzYW1lIHRpbWUuXG4gICAgICAgIGNvbnN0IG1vZCA9IGF3YWl0IGZhYXN0QXdzKGZ1bmN0aW9ucywgeyBkZXNjcmlwdGlvbjogdC50aXRsZSB9KTtcbiAgICAgICAgYXdhaXQgbW9kLmNsZWFudXAoKTtcbiAgICAgICAgdC5pcyhhd2FpdCBtb2Quc3RhdGUuZ2NQcm9taXNlLCBcInNraXBwZWRcIik7XG4gICAgfVxuXG4gICAge1xuICAgICAgICAvLyBUZXN0IHRoZSBwZXJzaXN0ZW50IGNhY2hlIHRoYXQgcHJldmVudHMgZ2MgZnJvbSBydW5uaW5nIHRvbyBvZnRlblxuICAgICAgICAvLyBldmVuIGFjcm9zcyBwcm9jZXNzZXMuXG4gICAgICAgIGNsZWFyTGFzdEdjKCk7XG4gICAgICAgIGNvbnN0IG1vZCA9IGF3YWl0IGZhYXN0QXdzKGZ1bmN0aW9ucywgeyBkZXNjcmlwdGlvbjogdC50aXRsZSB9KTtcbiAgICAgICAgYXdhaXQgbW9kLmNsZWFudXAoKTtcbiAgICAgICAgdC5pcyhhd2FpdCBtb2Quc3RhdGUuZ2NQcm9taXNlLCBcInNraXBwZWRcIik7XG4gICAgfVxufSk7XG4iXX0=
\No newline at end of file