UNPKG

22.1 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const ava_1 = require("ava");
4const util_1 = require("util");
5const index_1 = require("../index");
6const funcs = require("./fixtures/functions");
7const util_2 = require("./fixtures/util");
8/**
9 * Note that there is an AWS Lambda bug where timeouts are not delivered if the
10 * function has a timeout >= 300s, and the function is invoked directly with the
11 * Invoke API (e.g. in faast.js' "https" mode, which is the default.). In this
12 * case if faast.js has childProcess mode on (the default), then it will set its
13 * own timeout. This situation is not explicitly tested here because it would
14 * make the entire testsuite slower for just one test. To test this situation
15 * manually, change the timeout to 300 or more, and run one of these tests:
16 *
17 * $ ava --timeout=10m -m="remote aws generator timeout { mode: 'https', childProcess: true }"
18 * $ ava --timeout=10m -m="remote aws timeout { mode: 'https', childProcess: true }"
19 */
20async function testTimeout(t, provider, options) {
21 const lambda = await (0, index_1.faast)(provider, funcs, {
22 ...options,
23 timeout: 5,
24 maxRetries: 0,
25 gc: "off",
26 description: t.title
27 });
28 t.plan(1);
29 // t.log(`${lambda.logUrl()}`);
30 try {
31 try {
32 await lambda.functions.infiniteLoop();
33 }
34 catch (err) {
35 const isTimeout = index_1.FaastError.hasCauseWithName(err, index_1.FaastErrorNames.ETIMEOUT);
36 t.is(isTimeout, true, `${(0, util_1.inspect)(err)}`);
37 }
38 }
39 finally {
40 await lambda.cleanup();
41 }
42}
43/**
44 * The purpose of this test is to verify that a CPU hogging async generator
45 * function won't starve the sending logic, so yield messages prior to the CPU
46 * intensive work are delivered.
47 */
48async function testGenerator(t, provider, options) {
49 t.plan(2);
50 const lambda = await (0, index_1.faast)(provider, funcs, {
51 ...options,
52 timeout: 5,
53 maxRetries: 0,
54 gc: "off",
55 description: t.title
56 });
57 // t.log(`${lambda.logUrl()}`);
58 try {
59 const arg = "hello, generator!";
60 for await (const result of lambda.functions.generateThenInfiniteLoop(arg)) {
61 t.is(result, arg);
62 }
63 t.fail("Did not timeout");
64 }
65 catch (err) {
66 t.is(index_1.FaastError.hasCauseWithName(err, index_1.FaastErrorNames.ETIMEOUT), true);
67 }
68 finally {
69 await lambda.cleanup();
70 }
71}
72async function memoryLimitOk(t, provider, options) {
73 const lambda = await (0, index_1.faast)(provider, funcs, {
74 ...options,
75 timeout: 200,
76 memorySize: 512,
77 maxRetries: 0,
78 gc: "off",
79 description: t.title
80 });
81 try {
82 const bytes = 64 * 1024 * 1024;
83 const rv = await lambda.functions.allocate(bytes);
84 t.is(rv.elems, bytes / 8);
85 }
86 finally {
87 await lambda.cleanup();
88 }
89}
90async function memoryLimitFail(t, provider, options) {
91 const lambda = await (0, index_1.faast)(provider, funcs, {
92 ...options,
93 timeout: 200,
94 memorySize: 512,
95 maxRetries: 0,
96 gc: "off",
97 description: t.title
98 });
99 try {
100 const bytes = 512 * 1024 * 1024;
101 await t.throwsAsync(lambda.functions.allocate(bytes), { message: /memory/i });
102 }
103 finally {
104 lambda && (await lambda.cleanup());
105 }
106}
107// Note that this test takes 180s by default. Set the ava timeout to 2m or
108// longer otherwise it will fail with a timeout error.
109async function testLongInvoke(t, provider, options) {
110 // The http timeout is 120s in awssdk by default. Uncomment the following
111 // line to shorten it to 20s for focused testing. Note that shortening it
112 // below 20s causes (harmless) timeout error messages from SQS on the long
113 // polling response queue. If faast.js is working correctly, the shortened
114 // timeout should not cause a test failure.
115 //
116 // config.update({ httpOptions: { timeout: 20000 } });
117 const opts = {
118 timeout: 500,
119 gc: "off",
120 description: t.title,
121 ...options
122 };
123 const faastModule = await (0, index_1.faast)(provider, funcs, opts);
124 const remote = faastModule.functions;
125 try {
126 let i = 0;
127 const args = ["a", "b", "c"];
128 // The use of an async generator is to mimick a real use case from a
129 // client of faast.js. The presence of an error should also be revealed
130 // with a regular remote function call.
131 for await (const arg of remote.asyncGeneratorDelay(args, 60000)) {
132 t.is(arg, args[i++]);
133 }
134 }
135 finally {
136 await faastModule.cleanup();
137 }
138}
139const allLimits = ["memory", "timeout", "long", "generator"];
140const configurations = [
141 ["aws", { mode: "https", childProcess: true }, allLimits],
142 ["aws", { mode: "queue", childProcess: true }, allLimits],
143 ["aws", { mode: "https", childProcess: false }, ["memory", "timeout", "generator"]],
144 ["aws", { mode: "queue", childProcess: false }, ["memory", "timeout", "generator"]],
145 ["google", { mode: "https", childProcess: true }, ["memory", "timeout", "long"]],
146 ["google", { mode: "queue", childProcess: true }, []],
147 ["local", {}, ["timeout"]]
148];
149for (const [provider, config, limitTypes] of configurations) {
150 const opts = (0, util_1.inspect)(config);
151 if (limitTypes.find(t => t === "memory")) {
152 (0, ava_1.default)((0, util_2.title)(provider, `memory under limit ${opts}`), memoryLimitOk, provider, config);
153 (0, ava_1.default)((0, util_2.title)(provider, `out of memory`, config), memoryLimitFail, provider, config);
154 }
155 if (limitTypes.find(t => t === "timeout")) {
156 (0, ava_1.default)((0, util_2.title)(provider, `timeout`, config), testTimeout, provider, config);
157 }
158 if (limitTypes.find(t => t === "long")) {
159 (0, ava_1.default)((0, util_2.title)(provider, `long invoke`, config), testLongInvoke, provider, config);
160 }
161 if (limitTypes.find(t => t === "generator")) {
162 (0, ava_1.default)((0, util_2.title)(provider, `generator timeout`, config), testGenerator, provider, config);
163 }
164}
165//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGltaXRzLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90ZXN0L2xpbWl0cy50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsNkJBQTZDO0FBQzdDLCtCQUErQjtBQUMvQixvQ0FBdUY7QUFDdkYsOENBQThDO0FBQzlDLDBDQUF3QztBQUV4Qzs7Ozs7Ozs7Ozs7R0FXRztBQUNILEtBQUssVUFBVSxXQUFXLENBQ3RCLENBQW1CLEVBQ25CLFFBQWtCLEVBQ2xCLE9BQXNCO0lBRXRCLE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBQSxhQUFLLEVBQUMsUUFBUSxFQUFFLEtBQUssRUFBRTtRQUN4QyxHQUFHLE9BQU87UUFDVixPQUFPLEVBQUUsQ0FBQztRQUNWLFVBQVUsRUFBRSxDQUFDO1FBQ2IsRUFBRSxFQUFFLEtBQUs7UUFDVCxXQUFXLEVBQUUsQ0FBQyxDQUFDLEtBQUs7S0FDdkIsQ0FBQyxDQUFDO0lBQ0gsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNWLCtCQUErQjtJQUMvQixJQUFJO1FBQ0EsSUFBSTtZQUNBLE1BQU0sTUFBTSxDQUFDLFNBQVMsQ0FBQyxZQUFZLEVBQUUsQ0FBQztTQUN6QztRQUFDLE9BQU8sR0FBUSxFQUFFO1lBQ2YsTUFBTSxTQUFTLEdBQUcsa0JBQVUsQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLEVBQUUsdUJBQWUsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUM3RSxDQUFDLENBQUMsRUFBRSxDQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUUsR0FBRyxJQUFBLGNBQU8sRUFBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7U0FDNUM7S0FDSjtZQUFTO1FBQ04sTUFBTSxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7S0FDMUI7QUFDTCxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILEtBQUssVUFBVSxhQUFhLENBQ3hCLENBQW1CLEVBQ25CLFFBQWtCLEVBQ2xCLE9BQXNCO0lBRXRCLENB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QyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssU0FBUyxDQUFDLEVBQUU7UUFDdkMsSUFBQSxhQUFJLEVBQUMsSUFBQSxZQUFLLEVBQUMsUUFBUSxFQUFFLFNBQVMsRUFBRSxNQUFNLENBQUMsRUFBRSxXQUFXLEVBQUUsUUFBUSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0tBQzNFO0lBQ0QsSUFBSSxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLE1BQU0sQ0FBQyxFQUFFO1FBQ3BDLElBQUEsYUFBSSxFQUFDLElBQUEsWUFBSyxFQUFDLFFBQVEsRUFBRSxhQUFhLEVBQUUsTUFBTSxDQUFDLEVBQUUsY0FBYyxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQUMsQ0FBQztLQUNsRjtJQUNELElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsS0FBSyxXQUFXLENBQUMsRUFBRTtRQUN6QyxJQUFBLGFBQUksRUFDQSxJQUFBLFlBQUssRUFBQyxRQUFRLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxDQUFDLEVBQzVDLGFBQWEsRUFDYixRQUFRLEVBQ1IsTUFBTSxDQUNULENBQUM7S0FDTDtDQUNKIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHRlc3QsIHsgRXhlY3V0aW9uQ29udGV4dCB9IGZyb20gXCJhdmFcIjtcbmltcG9ydCB7IGluc3BlY3QgfSBmcm9tIFwidXRpbFwiO1xuaW1wb3J0IHsgQ29tbW9uT3B0aW9ucywgZmFhc3QsIEZhYXN0RXJyb3IsIEZhYXN0RXJyb3JOYW1lcywgUHJvdmlkZXIgfSBmcm9tIFwiLi4vaW5kZXhcIjtcbmltcG9ydCAqIGFzIGZ1bmNzIGZyb20gXCIuL2ZpeHR1cmVzL2Z1bmN0aW9uc1wiO1xuaW1wb3J0IHsgdGl0bGUgfSBmcm9tIFwiLi9maXh0dXJlcy91dGlsXCI7XG5cbi8qKlxuICogTm90ZSB0aGF0IHRoZXJlIGlzIGFuIEFXUyBMYW1iZGEgYnVnIHdoZXJlIHRpbWVvdXRzIGFyZSBub3QgZGVsaXZlcmVkIGlmIHRoZVxuICogZnVuY3Rpb24gaGFzIGEgdGltZW91dCA+PSAzMDBzLCBhbmQgdGhlIGZ1bmN0aW9uIGlzIGludm9rZWQgZGlyZWN0bHkgd2l0aCB0aGVcbiAqIEludm9rZSBBUEkgKGUuZy4gaW4gZmFhc3QuanMnIFwiaHR0cHNcIiBtb2RlLCB3aGljaCBpcyB0aGUgZGVmYXVsdC4pLiBJbiB0aGlzXG4gKiBjYXNlIGlmIGZhYXN0LmpzIGhhcyBjaGlsZFByb2Nlc3MgbW9kZSBvbiAodGhlIGRlZmF1bHQpLCB0aGVuIGl0IHdpbGwgc2V0IGl0c1xuICogb3duIHRpbWVvdXQuIFRoaXMgc2l0dWF0aW9uIGlzIG5vdCBleHBsaWNpdGx5IHRlc3RlZCBoZXJlIGJlY2F1c2UgaXQgd291bGRcbiAqIG1ha2UgdGhlIGVudGlyZSB0ZXN0c3VpdGUgc2xvd2VyIGZvciBqdXN0IG9uZSB0ZXN0LiBUbyB0ZXN0IHRoaXMgc2l0dWF0aW9uXG4gKiBtYW51YWxseSwgY2hhbmdlIHRoZSB0aW1lb3V0IHRvIDMwMCBvciBtb3JlLCBhbmQgcnVuIG9uZSBvZiB0aGVzZSB0ZXN0czpcbiAqXG4gKiAgICAkIGF2YSAtLXRpbWVvdXQ9MTBtIC1tPVwicmVtb3RlIGF3cyBnZW5lcmF0b3IgdGltZW91dCB7IG1vZGU6ICdodHRwcycsIGNoaWxkUHJvY2VzczogdHJ1ZSB9XCJcbiAqICAgICQgYXZhIC0tdGltZW91dD0xMG0gLW09XCJyZW1vdGUgYXdzIHRpbWVvdXQgeyBtb2RlOiAnaHR0cHMnLCBjaGlsZFByb2Nlc3M6IHRydWUgfVwiXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHRlc3RUaW1lb3V0KFxuICAgIHQ6IEV4ZWN1dGlvbkNvbnRleHQsXG4gICAgcHJvdmlkZXI6IFByb3ZpZGVyLFxuICAgIG9wdGlvbnM6IENvbW1vbk9wdGlvbnNcbikge1xuICAgIGNvbnN0IGxhbWJkYSA9IGF3YWl0IGZhYXN0KHByb3ZpZGVyLCBmdW5jcywge1xuICAgICAgICAuLi5vcHRpb25zLFxuICAgICAgICB0aW1lb3V0OiA1LFxuICAgICAgICBtYXhSZXRyaWVzOiAwLFxuICAgICAgICBnYzogXCJvZmZcIixcbiAgICAgICAgZGVzY3JpcHRpb246IHQudGl0bGVcbiAgICB9KTtcbiAgICB0LnBsYW4oMSk7XG4gICAgLy8gdC5sb2coYCR7bGFtYmRhLmxvZ1VybCgpfWApO1xuICAgIHRyeSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBsYW1iZGEuZnVuY3Rpb25zLmluZmluaXRlTG9vcCgpO1xuICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgY29uc3QgaXNUaW1lb3V0ID0gRmFhc3RFcnJvci5oYXNDYXVzZVdpdGhOYW1lKGVyciwgRmFhc3RFcnJvck5hbWVzLkVUSU1FT1VUKTtcbiAgICAgICAgICAgIHQuaXMoaXNUaW1lb3V0LCB0cnVlLCBgJHtpbnNwZWN0KGVycil9YCk7XG4gICAgICAgIH1cbiAgICB9IGZpbmFsbHkge1xuICAgICAgICBhd2FpdCBsYW1iZGEuY2xlYW51cCgpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBUaGUgcHVycG9zZSBvZiB0aGlzIHRlc3QgaXMgdG8gdmVyaWZ5IHRoYXQgYSBDUFUgaG9nZ2luZyBhc3luYyBnZW5lcmF0b3JcbiAqIGZ1bmN0aW9uIHdvbid0IHN0YXJ2ZSB0aGUgc2VuZGluZyBsb2dpYywgc28geWllbGQgbWVzc2FnZXMgcHJpb3IgdG8gdGhlIENQVVxuICogaW50ZW5zaXZlIHdvcmsgYXJlIGRlbGl2ZXJlZC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gdGVzdEdlbmVyYXRvcihcbiAgICB0OiBFeGVjdXRpb25Db250ZXh0LFxuICAgIHByb3ZpZGVyOiBQcm92aWRlcixcbiAgICBvcHRpb25zOiBDb21tb25PcHRpb25zXG4pIHtcbiAgICB0LnBsYW4oMik7XG4gICAgY29uc3QgbGFtYmRhID0gYXdhaXQgZmFhc3QocHJvdmlkZXIsIGZ1bmNzLCB7XG4gICAgICAgIC4uLm9wdGlvbnMsXG4gICAgICAgIHRpbWVvdXQ6IDUsXG4gICAgICAgIG1heFJldHJpZXM6IDAsXG4gICAgICAgIGdjOiBcIm9mZlwiLFxuICAgICAgICBkZXNjcmlwdGlvbjogdC50aXRsZVxuICAgIH0pO1xuICAgIC8vIHQubG9nKGAke2xhbWJkYS5sb2dVcmwoKX1gKTtcbiAgICB0cnkge1xuICAgICAgICBjb25zdCBhcmcgPSBcImhlbGxvLCBnZW5lcmF0b3IhXCI7XG4gICAgICAgIGZvciBhd2FpdCAoY29uc3QgcmVzdWx0IG9mIGxhbWJkYS5mdW5jdGlvbnMuZ2VuZXJhdGVUaGVuSW5maW5pdGVMb29wKGFyZykpIHtcbiAgICAgICAgICAgIHQuaXMocmVzdWx0LCBhcmcpO1xuICAgICAgICB9XG4gICAgICAgIHQuZmFpbChcIkRpZCBub3QgdGltZW91dFwiKTtcbiAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICB0LmlzKEZhYXN0RXJyb3IuaGFzQ2F1c2VXaXRoTmFtZShlcnIsIEZhYXN0RXJyb3JOYW1lcy5FVElNRU9VVCksIHRydWUpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICAgIGF3YWl0IGxhbWJkYS5jbGVhbnVwKCk7XG4gICAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBtZW1vcnlMaW1pdE9rKFxuICAgIHQ6IEV4ZWN1dGlvbkNvbnRleHQsXG4gICAgcHJvdmlkZXI6IFByb3ZpZGVyLFxuICAgIG9wdGlvbnM6IENvbW1vbk9wdGlvbnNcbikge1xuICAgIGNvbnN0IGxhbWJkYSA9IGF3YWl0IGZhYXN0KHByb3ZpZGVyLCBmdW5jcywge1xuICAgICAgICAuLi5vcHRpb25zLFxuICAgICAgICB0aW1lb3V0OiAyMDAsXG4gICAgICAgIG1lbW9yeVNpemU6IDUxMixcbiAgICAgICAgbWF4UmV0cmllczogMCxcbiAgICAgICAgZ2M6IFwib2ZmXCIsXG4gICAgICAgIGRlc2NyaXB0aW9uOiB0LnRpdGxlXG4gICAgfSk7XG5cbiAgICB0cnkge1xuICAgICAgICBjb25zdCBieXRlcyA9IDY0ICogMTAyNCAqIDEwMjQ7XG4gICAgICAgIGNvbnN0IHJ2ID0gYXdhaXQgbGFtYmRhLmZ1bmN0aW9ucy5hbGxvY2F0ZShieXRlcyk7XG4gICAgICAgIHQuaXMocnYuZWxlbXMsIGJ5dGVzIC8gOCk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgICAgYXdhaXQgbGFtYmRhLmNsZWFudXAoKTtcbiAgICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG1lbW9yeUxpbWl0RmFpbChcbiAgICB0OiBFeGVjdXRpb25Db250ZXh0LFxuICAgIHByb3ZpZGVyOiBQcm92aWRlcixcbiAgICBvcHRpb25zOiBDb21tb25PcHRpb25zXG4pIHtcbiAgICBjb25zdCBsYW1iZGEgPSBhd2FpdCBmYWFzdChwcm92aWRlciwgZnVuY3MsIHtcbiAgICAgICAgLi4ub3B0aW9ucyxcbiAgICAgICAgdGltZW91dDogMjAwLFxuICAgICAgICBtZW1vcnlTaXplOiA1MTIsXG4gICAgICAgIG1heFJldHJpZXM6IDAsXG4gICAgICAgIGdjOiBcIm9mZlwiLFxuICAgICAgICBkZXNjcmlwdGlvbjogdC50aXRsZVxuICAgIH0pO1xuXG4gICAgdHJ5IHtcbiAgICAgICAgY29uc3QgYnl0ZXMgPSA1MTIgKiAxMDI0ICogMTAyNDtcbiAgICAgICAgYXdhaXQgdC50aHJvd3NBc3luYyhsYW1iZGEuZnVuY3Rpb25zLmFsbG9jYXRlKGJ5dGVzKSwgeyBtZXNzYWdlOiAvbWVtb3J5L2kgfSk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgICAgbGFtYmRhICYmIChhd2FpdCBsYW1iZGEuY2xlYW51cCgpKTtcbiAgICB9XG59XG5cbi8vIE5vdGUgdGhhdCB0aGlzIHRlc3QgdGFrZXMgMTgwcyBieSBkZWZhdWx0LiBTZXQgdGhlIGF2YSB0aW1lb3V0IHRvIDJtIG9yXG4vLyBsb25nZXIgb3RoZXJ3aXNlIGl0IHdpbGwgZmFpbCB3aXRoIGEgdGltZW91dCBlcnJvci5cbmFzeW5jIGZ1bmN0aW9uIHRlc3RMb25nSW52b2tlKFxuICAgIHQ6IEV4ZWN1dGlvbkNvbnRleHQsXG4gICAgcHJvdmlkZXI6IFByb3ZpZGVyLFxuICAgIG9wdGlvbnM6IENvbW1vbk9wdGlvbnNcbikge1xuICAgIC8vIFRoZSBodHRwIHRpbWVvdXQgaXMgMTIwcyBpbiBhd3NzZGsgYnkgZGVmYXVsdC4gVW5jb21tZW50IHRoZSBmb2xsb3dpbmdcbiAgICAvLyBsaW5lIHRvIHNob3J0ZW4gaXQgdG8gMjBzIGZvciBmb2N1c2VkIHRlc3RpbmcuIE5vdGUgdGhhdCBzaG9ydGVuaW5nIGl0XG4gICAgLy8gYmVsb3cgMjBzIGNhdXNlcyAoaGFybWxlc3MpIHRpbWVvdXQgZXJyb3IgbWVzc2FnZXMgZnJvbSBTUVMgb24gdGhlIGxvbmdcbiAgICAvLyBwb2xsaW5nIHJlc3BvbnNlIHF1ZXVlLiBJZiBmYWFzdC5qcyBpcyB3b3JraW5nIGNvcnJlY3RseSwgdGhlIHNob3J0ZW5lZFxuICAgIC8vIHRpbWVvdXQgc2hvdWxkIG5vdCBjYXVzZSBhIHRlc3QgZmFpbHVyZS5cbiAgICAvL1xuICAgIC8vIGNvbmZpZy51cGRhdGUoeyBodHRwT3B0aW9uczogeyB0aW1lb3V0OiAyMDAwMCB9IH0pO1xuICAgIGNvbnN0IG9wdHM6IENvbW1vbk9wdGlvbnMgPSB7XG4gICAgICAgIHRpbWVvdXQ6IDUwMCxcbiAgICAgICAgZ2M6IFwib2ZmXCIsXG4gICAgICAgIGRlc2NyaXB0aW9uOiB0LnRpdGxlLFxuICAgICAgICAuLi5vcHRpb25zXG4gICAgfTtcbiAgICBjb25zdCBmYWFzdE1vZHVsZSA9IGF3YWl0IGZhYXN0KHByb3ZpZGVyLCBmdW5jcywgb3B0cyk7XG4gICAgY29uc3QgcmVtb3RlID0gZmFhc3RNb2R1bGUuZnVuY3Rpb25zO1xuICAgIHRyeSB7XG4gICAgICAgIGxldCBpID0gMDtcbiAgICAgICAgY29uc3QgYXJncyA9IFtcImFcIiwgXCJiXCIsIFwiY1wiXTtcbiAgICAgICAgLy8gVGhlIHVzZSBvZiBhbiBhc3luYyBnZW5lcmF0b3IgaXMgdG8gbWltaWNrIGEgcmVhbCB1c2UgY2FzZSBmcm9tIGFcbiAgICAgICAgLy8gY2xpZW50IG9mIGZhYXN0LmpzLiBUaGUgcHJlc2VuY2Ugb2YgYW4gZXJyb3Igc2hvdWxkIGFsc28gYmUgcmV2ZWFsZWRcbiAgICAgICAgLy8gd2l0aCBhIHJlZ3VsYXIgcmVtb3RlIGZ1bmN0aW9uIGNhbGwuXG4gICAgICAgIGZvciBhd2FpdCAoY29uc3QgYXJnIG9mIHJlbW90ZS5hc3luY0dlbmVyYXRvckRlbGF5KGFyZ3MsIDYwMDAwKSkge1xuICAgICAgICAgICAgdC5pcyhhcmcsIGFyZ3NbaSsrXSk7XG4gICAgICAgIH1cbiAgICB9IGZpbmFsbHkge1xuICAgICAgICBhd2FpdCBmYWFzdE1vZHVsZS5jbGVhbnVwKCk7XG4gICAgfVxufVxuXG50eXBlIExpbWl0VHlwZSA9IFwibWVtb3J5XCIgfCBcInRpbWVvdXRcIiB8IFwiZ2VuZXJhdG9yXCIgfCBcImxvbmdcIjtcbmNvbnN0IGFsbExpbWl0cyA9IFtcIm1lbW9yeVwiLCBcInRpbWVvdXRcIiwgXCJsb25nXCIsIFwiZ2VuZXJhdG9yXCJdIGFzIGNvbnN0O1xuXG5jb25zdCBjb25maWd1cmF0aW9uczogW1Byb3ZpZGVyLCBDb21tb25PcHRpb25zLCByZWFkb25seSBMaW1pdFR5cGVbXV1bXSA9IFtcbiAgICBbXCJhd3NcIiwgeyBtb2RlOiBcImh0dHBzXCIsIGNoaWxkUHJvY2VzczogdHJ1ZSB9LCBhbGxMaW1pdHNdLFxuICAgIFtcImF3c1wiLCB7IG1vZGU6IFwicXVldWVcIiwgY2hpbGRQcm9jZXNzOiB0cnVlIH0sIGFsbExpbWl0c10sXG4gICAgW1wiYXdzXCIsIHsgbW9kZTogXCJodHRwc1wiLCBjaGlsZFByb2Nlc3M6IGZhbHNlIH0sIFtcIm1lbW9yeVwiLCBcInRpbWVvdXRcIiwgXCJnZW5lcmF0b3JcIl1dLFxuICAgIFtcImF3c1wiLCB7IG1vZGU6IFwicXVldWVcIiwgY2hpbGRQcm9jZXNzOiBmYWxzZSB9LCBbXCJtZW1vcnlcIiwgXCJ0aW1lb3V0XCIsIFwiZ2VuZXJhdG9yXCJdXSxcbiAgICBbXCJnb29nbGVcIiwgeyBtb2RlOiBcImh0dHBzXCIsIGNoaWxkUHJvY2VzczogdHJ1ZSB9LCBbXCJtZW1vcnlcIiwgXCJ0aW1lb3V0XCIsIFwibG9uZ1wiXV0sXG4gICAgW1wiZ29vZ2xlXCIsIHsgbW9kZTogXCJxdWV1ZVwiLCBjaGlsZFByb2Nlc3M6IHRydWUgfSwgW11dLFxuICAgIFtcImxvY2FsXCIsIHt9LCBbXCJ0aW1lb3V0XCJdXVxuXTtcblxuZm9yIChjb25zdCBbcHJvdmlkZXIsIGNvbmZpZywgbGltaXRUeXBlc10gb2YgY29uZmlndXJhdGlvbnMpIHtcbiAgICBjb25zdCBvcHRzID0gaW5zcGVjdChjb25maWcpO1xuICAgIGlmIChsaW1pdFR5cGVzLmZpbmQodCA9PiB0ID09PSBcIm1lbW9yeVwiKSkge1xuICAgICAgICB0ZXN0KFxuICAgICAgICAgICAgdGl0bGUocHJvdmlkZXIsIGBtZW1vcnkgdW5kZXIgbGltaXQgJHtvcHRzfWApLFxuICAgICAgICAgICAgbWVtb3J5TGltaXRPayxcbiAgICAgICAgICAgIHByb3ZpZGVyLFxuICAgICAgICAgICAgY29uZmlnXG4gICAgICAgICk7XG4gICAgICAgIHRlc3QodGl0bGUocHJvdmlkZXIsIGBvdXQgb2YgbWVtb3J5YCwgY29uZmlnKSwgbWVtb3J5TGltaXRGYWlsLCBwcm92aWRlciwgY29uZmlnKTtcbiAgICB9XG4gICAgaWYgKGxpbWl0VHlwZXMuZmluZCh0ID0+IHQgPT09IFwidGltZW91dFwiKSkge1xuICAgICAgICB0ZXN0KHRpdGxlKHByb3ZpZGVyLCBgdGltZW91dGAsIGNvbmZpZyksIHRlc3RUaW1lb3V0LCBwcm92aWRlciwgY29uZmlnKTtcbiAgICB9XG4gICAgaWYgKGxpbWl0VHlwZXMuZmluZCh0ID0+IHQgPT09IFwibG9uZ1wiKSkge1xuICAgICAgICB0ZXN0KHRpdGxlKHByb3ZpZGVyLCBgbG9uZyBpbnZva2VgLCBjb25maWcpLCB0ZXN0TG9uZ0ludm9rZSwgcHJvdmlkZXIsIGNvbmZpZyk7XG4gICAgfVxuICAgIGlmIChsaW1pdFR5cGVzLmZpbmQodCA9PiB0ID09PSBcImdlbmVyYXRvclwiKSkge1xuICAgICAgICB0ZXN0KFxuICAgICAgICAgICAgdGl0bGUocHJvdmlkZXIsIGBnZW5lcmF0b3IgdGltZW91dGAsIGNvbmZpZyksXG4gICAgICAgICAgICB0ZXN0R2VuZXJhdG9yLFxuICAgICAgICAgICAgcHJvdmlkZXIsXG4gICAgICAgICAgICBjb25maWdcbiAgICAgICAgKTtcbiAgICB9XG59XG4iXX0=
\No newline at end of file