UNPKG

faastjs

Version:

Serverless batch computing made simple.

236 lines 29.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const ava_1 = tslib_1.__importDefault(require("ava")); const fs_extra_1 = require("fs-extra"); const url_1 = require("url"); const util_1 = require("util"); const index_1 = require("../index"); const funcs = tslib_1.__importStar(require("./fixtures/functions")); const util_2 = require("./fixtures/util"); const error_1 = require("../src/error"); async function testCleanup(t, options) { const m = await (0, index_1.faastLocal)(funcs, { gc: "off", ...options }); let done = 0; m.functions .hello("there") .then(_ => done++) .catch(_ => { }); m.functions .sleep(1000) .then(_ => done++) .catch(_ => { }); await m.cleanup(); t.is(done, 0); } async function testOrder(t, options) { const faastModule = await (0, index_1.faastLocal)(funcs, { gc: "off", ...options }); t.plan(2); const a = faastModule.functions.emptyReject(); const b = faastModule.functions.sleep(0); t.is(await b, undefined); try { await a; } catch (err) { t.is(err, undefined); } finally { await faastModule.cleanup(); } } async function testConcurrency(t, { options, maxConcurrency, expectedConcurrency }) { const faastModule = await (0, index_1.faastLocal)(funcs, { ...options, gc: "off", concurrency: maxConcurrency }); try { const N = maxConcurrency * 2; const promises = []; for (let i = 0; i < N; i++) { promises.push(faastModule.functions.spin(2000)); } const timings = await Promise.all(promises); t.is((0, util_2.measureConcurrency)(timings), expectedConcurrency); } finally { await faastModule.cleanup(); } } (0, ava_1.default)("local provider cleanup stops executions", testCleanup, {}); (0, ava_1.default)("local provider cleanup stops executions with child process", testCleanup, { childProcess: true }); const orderConfigs = [ { childProcess: false, concurrency: 1, maxRetries: 0 }, { childProcess: true, concurrency: 1, maxRetries: 0 }, { childProcess: false, concurrency: 2, maxRetries: 0 }, { childProcess: true, concurrency: 2, maxRetries: 0 }, { childProcess: false, concurrency: 2, maxRetries: 2 }, { childProcess: true, concurrency: 2, maxRetries: 2 } ]; for (const config of orderConfigs) { (0, ava_1.default)(`out of order await (async catch) with ${(0, util_1.inspect)(config)}`, testOrder, config); } async function readFirstLogfile(logDirectoryUrl) { const url = new url_1.URL(logDirectoryUrl); const buf = await (0, fs_extra_1.readFile)(url.pathname + "/0.log"); return buf .toString() .split("\n") .map(m => m.replace(/^\[(\d+)\]/, "[$pid]")); } (0, ava_1.default)("local provider console.log, console.warn, and console.error with child process", async (t) => { const faastModule = await (0, index_1.faastLocal)(funcs, { childProcess: true, concurrency: 1, gc: "off" }); try { await faastModule.functions.consoleLog("Remote console.log output"); await faastModule.functions.consoleWarn("Remote console.warn output"); await faastModule.functions.consoleError("Remote console.error output"); await (0, util_2.sleep)(1000); await faastModule.cleanup({ deleteResources: false }); const messages = await readFirstLogfile(faastModule.logUrl()); t.truthy(messages.find(s => s === "[$pid]: Remote console.log output")); t.truthy(messages.find(s => s === "[$pid]: Remote console.warn output")); t.truthy(messages.find(s => s === "[$pid]: Remote console.error output")); } finally { await faastModule.cleanup({ deleteResources: false }); } }); (0, ava_1.default)("local provider log files should be appended, not truncated, after child process crash", async (t) => { const faastModule = await (0, index_1.faastLocal)(funcs, { childProcess: true, concurrency: 1, maxRetries: 1, gc: "off" }); try { await faastModule.functions.consoleLog("output 1"); try { await faastModule.functions.processExit(); } catch (err) { } await faastModule.functions.consoleWarn("output 2"); // Wait for flush await (0, util_2.sleep)(500); const messages = await readFirstLogfile(faastModule.logUrl()); t.truthy(messages.find(s => s === "[$pid]: output 1")); t.truthy(messages.find(s => s === "[$pid]: output 2")); } finally { await faastModule.cleanup({ deleteResources: false }); } }); (0, ava_1.default)("local provider child process exceptions should result in errors with logUrl", async (t) => { const faastModule = await (0, index_1.faastLocal)(funcs, { childProcess: true, concurrency: 1, maxRetries: 1, gc: "off" }); t.plan(1); try { await faastModule.functions.error("synthetic error"); } catch (err) { const info = error_1.FaastError.info(err); t.true(typeof info.logUrl === "string" && info.logUrl.startsWith(" file:///"), (0, util_1.inspect)(err)); } finally { await faastModule.cleanup(); } }); (0, ava_1.default)("local provider child process crashes should result in errors with logUrl", async (t) => { const faastModule = await (0, index_1.faastLocal)(funcs, { childProcess: true, concurrency: 1, maxRetries: 1, gc: "off" }); t.plan(1); try { await faastModule.functions.processExit(-1); } catch (err) { const info = error_1.FaastError.info(err); t.true(typeof info.logUrl === "string" && info.logUrl.startsWith(" file:///"), (0, util_1.inspect)(err)); } finally { await faastModule.cleanup(); } }); (0, ava_1.default)("local provider concurrent executions with child processes", async (t) => { await testConcurrency(t, { options: { childProcess: true }, maxConcurrency: 5, expectedConcurrency: 5 }); }); (0, ava_1.default)("local provider no concurrency for cpu bound work without child processes", async (t) => { await testConcurrency(t, { options: { childProcess: false }, maxConcurrency: 5, expectedConcurrency: 1 }); }); (0, ava_1.default)("local provider cleanup waits for all child processes to exit", async (t) => { const faastModule = await (0, index_1.faastLocal)(funcs, { childProcess: true, gc: "off" }); faastModule.functions.spin(5000).catch(_ => { }); while (true) { await (0, util_2.sleep)(100); if (faastModule.state.executors.length > 0) { break; } } t.is(faastModule.state.executors.length, 1, "executor is not running"); await faastModule.cleanup({ gcTimeout: 60 }); t.is(faastModule.state.executors.length, 0, "executors are running after cleanup"); }); (0, ava_1.default)("local unresolved module", async (t) => { t.plan(1); try { await (0, index_1.faastLocal)({}); } catch (err) { t.regex(err.message, /Could not find file/); } }); (0, ava_1.default)("local issue #37", async (t) => { // Previously this code caused an exception about module wrapper not being // re-entrant. The problem was a race condition between wrapper selection // and execution in local provider. Solved by making wrapper selector a // regular function instead of an async function. const m = await (0, index_1.faastLocal)(funcs); try { const { identityString: identity } = m.functions; await identity("a"); const b = identity("b"); const c = identity("c"); await b; await c; // Test succeeds if no exceptions are thrown. t.true(true); } finally { await m.cleanup(); } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidW5pdC1sb2NhbC50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdGVzdC91bml0LWxvY2FsLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsc0RBQTZDO0FBQzdDLHVDQUFvQztBQUNwQyw2QkFBMEI7QUFDMUIsK0JBQStCO0FBQy9CLG9DQUFvRDtBQUNwRCxvRUFBOEM7QUFDOUMsMENBQTREO0FBQzVELHdDQUEwQztBQUUxQyxLQUFLLFVBQVUsV0FBVyxDQUFDLENBQW1CLEVBQUUsT0FBcUI7SUFDakUsTUFBTSxDQUFDLEdBQUcsTUFBTSxJQUFBLGtCQUFVLEVBQUMsS0FBSyxFQUFFO1FBQzlCLEVBQUUsRUFBRSxLQUFLO1FBQ1QsR0FBRyxPQUFPO0tBQ2IsQ0FBQyxDQUFDO0lBQ0gsSUFBSSxJQUFJLEdBQUcsQ0FBQyxDQUFDO0lBRWIsQ0FBQyxDQUFDLFNBQVM7U0FDTixLQUFLLENBQUMsT0FBTyxDQUFDO1NBQ2QsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUM7U0FDakIsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7SUFFcEIsQ0FBQyxDQUFDLFNBQVM7U0FDTixLQUFLLENBQUMsSUFBSSxDQUFDO1NBQ1gsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUM7U0FDakIsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7SUFFcEIsTUFBTSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDbEIsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFDbEIsQ0FBQztBQUVELEtBQUssVUFBVSxTQUFTLENBQUMsQ0FBbUIsRUFBRSxPQUFxQjtJQUMvRCxNQUFNLFdBQVcsR0FBRyxNQUFNLElBQUEsa0JBQVUsRUFBQyxLQUFLLEVBQUU7UUFDeEMsRUFB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QUEsa0JBQVUsRUFBQyxFQUFFLENBQUMsQ0FBQztLQUN4QjtJQUFDLE9BQU8sR0FBUSxFQUFFO1FBQ2YsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLHFCQUFxQixDQUFDLENBQUM7S0FDL0M7QUFDTCxDQUFDLENBQUMsQ0FBQztBQUVILElBQUEsYUFBSSxFQUFDLGlCQUFpQixFQUFFLEtBQUssRUFBQyxDQUFDLEVBQUMsRUFBRTtJQUM5QiwwRUFBMEU7SUFDMUUseUVBQXlFO0lBQ3pFLHVFQUF1RTtJQUN2RSxpREFBaUQ7SUFDakQsTUFBTSxDQUFDLEdBQUcsTUFBTSxJQUFBLGtCQUFVLEVBQUMsS0FBSyxDQUFDLENBQUM7SUFDbEMsSUFBSTtRQUNBLE1BQU0sRUFBRSxjQUFjLEVBQUUsUUFBUSxFQUFFLEdBQUcsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUNqRCxNQUFNLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNwQixNQUFNLENBQUMsR0FBRyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDeEIsTUFBTSxDQUFDLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3hCLE1BQU0sQ0FBQyxDQUFDO1FBQ1IsTUFBTSxDQUFDLENBQUM7UUFDUiw2Q0FBNkM7UUFDN0MsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztLQUNoQjtZQUFTO1FBQ04sTUFBTSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7S0FDckI7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0ZXN0LCB7IEV4ZWN1dGlvbkNvbnRleHQgfSBmcm9tIFwiYXZhXCI7XG5pbXBvcnQgeyByZWFkRmlsZSB9IGZyb20gXCJmcy1leHRyYVwiO1xuaW1wb3J0IHsgVVJMIH0gZnJvbSBcInVybFwiO1xuaW1wb3J0IHsgaW5zcGVjdCB9IGZyb20gXCJ1dGlsXCI7XG5pbXBvcnQgeyBmYWFzdExvY2FsLCBMb2NhbE9wdGlvbnMgfSBmcm9tIFwiLi4vaW5kZXhcIjtcbmltcG9ydCAqIGFzIGZ1bmNzIGZyb20gXCIuL2ZpeHR1cmVzL2Z1bmN0aW9uc1wiO1xuaW1wb3J0IHsgbWVhc3VyZUNvbmN1cnJlbmN5LCBzbGVlcCB9IGZyb20gXCIuL2ZpeHR1cmVzL3V0aWxcIjtcbmltcG9ydCB7IEZhYXN0RXJyb3IgfSBmcm9tIFwiLi4vc3JjL2Vycm9yXCI7XG5cbmFzeW5jIGZ1bmN0aW9uIHRlc3RDbGVhbnVwKHQ6IEV4ZWN1dGlvbkNvbnRleHQsIG9wdGlvbnM6IExvY2FsT3B0aW9ucykge1xuICAgIGNvbnN0IG0gPSBhd2FpdCBmYWFzdExvY2FsKGZ1bmNzLCB7XG4gICAgICAgIGdjOiBcIm9mZlwiLFxuICAgICAgICAuLi5vcHRpb25zXG4gICAgfSk7XG4gICAgbGV0IGRvbmUgPSAwO1xuXG4gICAgbS5mdW5jdGlvbnNcbiAgICAgICAgLmhlbGxvKFwidGhlcmVcIilcbiAgICAgICAgLnRoZW4oXyA9PiBkb25lKyspXG4gICAgICAgIC5jYXRjaChfID0+IHt9KTtcblxuICAgIG0uZnVuY3Rpb25zXG4gICAgICAgIC5zbGVlcCgxMDAwKVxuICAgICAgICAudGhlbihfID0+IGRvbmUrKylcbiAgICAgICAgLmNhdGNoKF8gPT4ge30pO1xuXG4gICAgYXdhaXQgbS5jbGVhbnVwKCk7XG4gICAgdC5pcyhkb25lLCAwKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gdGVzdE9yZGVyKHQ6IEV4ZWN1dGlvbkNvbnRleHQsIG9wdGlvbnM6IExvY2FsT3B0aW9ucykge1xuICAgIGNvbnN0IGZhYXN0TW9kdWxlID0gYXdhaXQgZmFhc3RMb2NhbChmdW5jcywge1xuICAgICAgICBnYzogXCJvZmZcIixcbiAgICAgICAgLi4ub3B0aW9uc1xuICAgIH0pO1xuICAgIHQucGxhbigyKTtcblxuICAgIGNvbnN0IGEgPSBmYWFzdE1vZHVsZS5mdW5jdGlvbnMuZW1wdHlSZWplY3QoKTtcbiAgICBjb25zdCBiID0gZmFhc3RNb2R1bGUuZnVuY3Rpb25zLnNsZWVwKDApO1xuICAgIHQuaXMoYXdhaXQgYiwgdW5kZWZpbmVkKTtcbiAgICB0cnkge1xuICAgICAgICBhd2FpdCBhO1xuICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgIHQuaXMoZXJyLCB1bmRlZmluZWQpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICAgIGF3YWl0IGZhYXN0TW9kdWxlLmNsZWFudXAoKTtcbiAgICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHRlc3RDb25jdXJyZW5jeShcbiAgICB0OiBFeGVjdXRpb25Db250ZXh0LFxuICAgIHtcbiAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgbWF4Q29uY3VycmVuY3ksXG4gICAgICAgIGV4cGVjdGVkQ29uY3VycmVuY3lcbiAgICB9OiB7XG4gICAgICAgIG9wdGlvbnM6IExvY2FsT3B0aW9ucztcbiAgICAgICAgbWF4Q29uY3VycmVuY3k6IG51bWJlcjtcbiAgICAgICAgZXhwZWN0ZWRDb25jdXJyZW5jeTogbnVtYmVyO1xuICAgIH1cbikge1xuICAgIGNvbnN0IGZhYXN0TW9kdWxlID0gYXdhaXQgZmFhc3RMb2NhbChmdW5jcywge1xuICAgICAgICAuLi5vcHRpb25zLFxuICAgICAgICBnYzogXCJvZmZcIixcbiAgICAgICAgY29uY3VycmVuY3k6IG1heENvbmN1cnJlbmN5XG4gICAgfSk7XG5cbiAgICB0cnkge1xuICAgICAgICBjb25zdCBOID0gbWF4Q29uY3VycmVuY3kgKiAyO1xuICAgICAgICBjb25zdCBwcm9taXNlcyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IE47IGkrKykge1xuICAgICAgICAgICAgcHJvbWlzZXMucHVzaChmYWFzdE1vZHVsZS5mdW5jdGlvbnMuc3BpbigyMDAwKSk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB0aW1pbmdzID0gYXdhaXQgUHJvbWlzZS5hbGwocHJvbWlzZXMpO1xuICAgICAgICB0LmlzKG1lYXN1cmVDb25jdXJyZW5jeSh0aW1pbmdzKSwgZXhwZWN0ZWRDb25jdXJyZW5jeSk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgICAgYXdhaXQgZmFhc3RNb2R1bGUuY2xlYW51cCgpO1xuICAgIH1cbn1cblxudGVzdChcImxvY2FsIHByb3ZpZGVyIGNsZWFudXAgc3RvcHMgZXhlY3V0aW9uc1wiLCB0ZXN0Q2xlYW51cCwge30pO1xudGVzdChcImxvY2FsIHByb3ZpZGVyIGNsZWFudXAgc3RvcHMgZXhlY3V0aW9ucyB3aXRoIGNoaWxkIHByb2Nlc3NcIiwgdGVzdENsZWFudXAsIHtcbiAgICBjaGlsZFByb2Nlc3M6IHRydWVcbn0pO1xuXG5jb25zdCBvcmRlckNvbmZpZ3MgPSBbXG4gICAgeyBjaGlsZFByb2Nlc3M6IGZhbHNlLCBjb25jdXJyZW5jeTogMSwgbWF4UmV0cmllczogMCB9LFxuICAgIHsgY2hpbGRQcm9jZXNzOiB0cnVlLCBjb25jdXJyZW5jeTogMSwgbWF4UmV0cmllczogMCB9LFxuICAgIHsgY2hpbGRQcm9jZXNzOiBmYWxzZSwgY29uY3VycmVuY3k6IDIsIG1heFJldHJpZXM6IDAgfSxcbiAgICB7IGNoaWxkUHJvY2VzczogdHJ1ZSwgY29uY3VycmVuY3k6IDIsIG1heFJldHJpZXM6IDAgfSxcbiAgICB7IGNoaWxkUHJvY2VzczogZmFsc2UsIGNvbmN1cnJlbmN5OiAyLCBtYXhSZXRyaWVzOiAyIH0sXG4gICAgeyBjaGlsZFByb2Nlc3M6IHRydWUsIGNvbmN1cnJlbmN5OiAyLCBtYXhSZXRyaWVzOiAyIH1cbl07XG5cbmZvciAoY29uc3QgY29uZmlnIG9mIG9yZGVyQ29uZmlncykge1xuICAgIHRlc3QoYG91dCBvZiBvcmRlciBhd2FpdCAoYXN5bmMgY2F0Y2gpIHdpdGggJHtpbnNwZWN0KGNvbmZpZyl9YCwgdGVzdE9yZGVyLCBjb25maWcpO1xufVxuXG5hc3luYyBmdW5jdGlvbiByZWFkRmlyc3RMb2dmaWxlKGxvZ0RpcmVjdG9yeVVybDogc3RyaW5nKSB7XG4gICAgY29uc3QgdXJsID0gbmV3IFVSTChsb2dEaXJlY3RvcnlVcmwpO1xuICAgIGNvbnN0IGJ1ZiA9IGF3YWl0IHJlYWRGaWxlKHVybC5wYXRobmFtZSArIFwiLzAubG9nXCIpO1xuICAgIHJldHVybiBidWZcbiAgICAgICAgLnRvU3RyaW5nKClcbiAgICAgICAgLnNwbGl0KFwiXFxuXCIpXG4gICAgICAgIC5tYXAobSA9PiBtLnJlcGxhY2UoL15cXFsoXFxkKylcXF0vLCBcIlskcGlkXVwiKSk7XG59XG5cbnRlc3QoXCJsb2NhbCBwcm92aWRlciBjb25zb2xlLmxvZywgY29uc29sZS53YXJuLCBhbmQgY29uc29sZS5lcnJvciB3aXRoIGNoaWxkIHByb2Nlc3NcIiwgYXN5bmMgdCA9PiB7XG4gICAgY29uc3QgZmFhc3RNb2R1bGUgPSBhd2FpdCBmYWFzdExvY2FsKGZ1bmNzLCB7XG4gICAgICAgIGNoaWxkUHJvY2VzczogdHJ1ZSxcbiAgICAgICAgY29uY3VycmVuY3k6IDEsXG4gICAgICAgIGdjOiBcIm9mZlwiXG4gICAgfSk7XG4gICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgZmFhc3RNb2R1bGUuZnVuY3Rpb25zLmNvbnNvbGVMb2coXCJSZW1vdGUgY29uc29sZS5sb2cgb3V0cHV0XCIpO1xuICAgICAgICBhd2FpdCBmYWFzdE1vZHVsZS5mdW5jdGlvbnMuY29uc29sZVdhcm4oXCJSZW1vdGUgY29uc29sZS53YXJuIG91dHB1dFwiKTtcbiAgICAgICAgYXdhaXQgZmFhc3RNb2R1bGUuZnVuY3Rpb25zLmNvbnNvbGVFcnJvcihcIlJlbW90ZSBjb25zb2xlLmVycm9yIG91dHB1dFwiKTtcbiAgICAgICAgYXdhaXQgc2xlZXAoMTAwMCk7XG4gICAgICAgIGF3YWl0IGZhYXN0TW9kdWxlLmNsZWFudXAoeyBkZWxldGVSZXNvdXJjZXM6IGZhbHNlIH0pO1xuICAgICAgICBjb25zdCBtZXNzYWdlcyA9IGF3YWl0IHJlYWRGaXJzdExvZ2ZpbGUoZmFhc3RNb2R1bGUubG9nVXJsKCkpO1xuICAgICAgICB0LnRydXRoeShtZXNzYWdlcy5maW5kKHMgPT4gcyA9PT0gXCJbJHBpZF06IFJlbW90ZSBjb25zb2xlLmxvZyBvdXRwdXRcIikpO1xuICAgICAgICB0LnRydXRoeShtZXNzYWdlcy5maW5kKHMgPT4gcyA9PT0gXCJbJHBpZF06IFJlbW90ZSBjb25zb2xlLndhcm4gb3V0cHV0XCIpKTtcbiAgICAgICAgdC50cnV0aHkobWVzc2FnZXMuZmluZChzID0+IHMgPT09IFwiWyRwaWRdOiBSZW1vdGUgY29uc29sZS5lcnJvciBvdXRwdXRcIikpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICAgIGF3YWl0IGZhYXN0TW9kdWxlLmNsZWFudXAoeyBkZWxldGVSZXNvdXJjZXM6IGZhbHNlIH0pO1xuICAgIH1cbn0pO1xuXG50ZXN0KFwibG9jYWwgcHJvdmlkZXIgbG9nIGZpbGVzIHNob3VsZCBiZSBhcHBlbmRlZCwgbm90IHRydW5jYXRlZCwgYWZ0ZXIgY2hpbGQgcHJvY2VzcyBjcmFzaFwiLCBhc3luYyB0ID0+IHtcbiAgICBjb25zdCBmYWFzdE1vZHVsZSA9IGF3YWl0IGZhYXN0TG9jYWwoZnVuY3MsIHtcbiAgICAgICAgY2hpbGRQcm9jZXNzOiB0cnVlLFxuICAgICAgICBjb25jdXJyZW5jeTogMSxcbiAgICAgICAgbWF4UmV0cmllczogMSxcbiAgICAgICAgZ2M6IFwib2ZmXCJcbiAgICB9KTtcbiAgICB0cnkge1xuICAgICAgICBhd2FpdCBmYWFzdE1vZHVsZS5mdW5jdGlvbnMuY29uc29sZUxvZyhcIm91dHB1dCAxXCIpO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgZmFhc3RNb2R1bGUuZnVuY3Rpb25zLnByb2Nlc3NFeGl0KCk7XG4gICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7fVxuICAgICAgICBhd2FpdCBmYWFzdE1vZHVsZS5mdW5jdGlvbnMuY29uc29sZVdhcm4oXCJvdXRwdXQgMlwiKTtcblxuICAgICAgICAvLyBXYWl0IGZvciBmbHVzaFxuICAgICAgICBhd2FpdCBzbGVlcCg1MDApO1xuICAgICAgICBjb25zdCBtZXNzYWdlcyA9IGF3YWl0IHJlYWRGaXJzdExvZ2ZpbGUoZmFhc3RNb2R1bGUubG9nVXJsKCkpO1xuXG4gICAgICAgIHQudHJ1dGh5KG1lc3NhZ2VzLmZpbmQocyA9PiBzID09PSBcIlskcGlkXTogb3V0cHV0IDFcIikpO1xuICAgICAgICB0LnRydXRoeShtZXNzYWdlcy5maW5kKHMgPT4gcyA9PT0gXCJbJHBpZF06IG91dHB1dCAyXCIpKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgICBhd2FpdCBmYWFzdE1vZHVsZS5jbGVhbnVwKHsgZGVsZXRlUmVzb3VyY2VzOiBmYWxzZSB9KTtcbiAgICB9XG59KTtcblxudGVzdChcImxvY2FsIHByb3ZpZGVyIGNoaWxkIHByb2Nlc3MgZXhjZXB0aW9ucyBzaG91bGQgcmVzdWx0IGluIGVycm9ycyB3aXRoIGxvZ1VybFwiLCBhc3luYyB0ID0+IHtcbiAgICBjb25zdCBmYWFzdE1vZHVsZSA9IGF3YWl0IGZhYXN0TG9jYWwoZnVuY3MsIHtcbiAgICAgICAgY2hpbGRQcm9jZXNzOiB0cnVlLFxuICAgICAgICBjb25jdXJyZW5jeTogMSxcbiAgICAgICAgbWF4UmV0cmllczogMSxcbiAgICAgICAgZ2M6IFwib2ZmXCJcbiAgICB9KTtcbiAgICB0LnBsYW4oMSk7XG4gICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgZmFhc3RNb2R1bGUuZnVuY3Rpb25zLmVycm9yKFwic3ludGhldGljIGVycm9yXCIpO1xuICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgIGNvbnN0IGluZm8gPSBGYWFzdEVycm9yLmluZm8oZXJyKTtcbiAgICAgICAgdC50cnVlKFxuICAgICAgICAgICAgdHlwZW9mIGluZm8ubG9nVXJsID09PSBcInN0cmluZ1wiICYmIGluZm8ubG9nVXJsLnN0YXJ0c1dpdGgoXCIgZmlsZTovLy9cIiksXG4gICAgICAgICAgICBpbnNwZWN0KGVycilcbiAgICAgICAgKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgICBhd2FpdCBmYWFzdE1vZHVsZS5jbGVhbnVwKCk7XG4gICAgfVxufSk7XG5cbnRlc3QoXCJsb2NhbCBwcm92aWRlciBjaGlsZCBwcm9jZXNzIGNyYXNoZXMgc2hvdWxkIHJlc3VsdCBpbiBlcnJvcnMgd2l0aCBsb2dVcmxcIiwgYXN5bmMgdCA9PiB7XG4gICAgY29uc3QgZmFhc3RNb2R1bGUgPSBhd2FpdCBmYWFzdExvY2FsKGZ1bmNzLCB7XG4gICAgICAgIGNoaWxkUHJvY2VzczogdHJ1ZSxcbiAgICAgICAgY29uY3VycmVuY3k6IDEsXG4gICAgICAgIG1heFJldHJpZXM6IDEsXG4gICAgICAgIGdjOiBcIm9mZlwiXG4gICAgfSk7XG4gICAgdC5wbGFuKDEpO1xuICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGZhYXN0TW9kdWxlLmZ1bmN0aW9ucy5wcm9jZXNzRXhpdCgtMSk7XG4gICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgY29uc3QgaW5mbyA9IEZhYXN0RXJyb3IuaW5mbyhlcnIpO1xuICAgICAgICB0LnRydWUoXG4gICAgICAgICAgICB0eXBlb2YgaW5mby5sb2dVcmwgPT09IFwic3RyaW5nXCIgJiYgaW5mby5sb2dVcmwuc3RhcnRzV2l0aChcIiBmaWxlOi8vL1wiKSxcbiAgICAgICAgICAgIGluc3BlY3QoZXJyKVxuICAgICAgICApO1xuICAgIH0gZmluYWxseSB7XG4gICAgICAgIGF3YWl0IGZhYXN0TW9kdWxlLmNsZWFudXAoKTtcbiAgICB9XG59KTtcblxudGVzdChcImxvY2FsIHByb3ZpZGVyIGNvbmN1cnJlbnQgZXhlY3V0aW9ucyB3aXRoIGNoaWxkIHByb2Nlc3Nlc1wiLCBhc3luYyB0ID0+IHtcbiAgICBhd2FpdCB0ZXN0Q29uY3VycmVuY3kodCwge1xuICAgICAgICBvcHRpb25zOiB7XG4gICAgICAgICAgICBjaGlsZFByb2Nlc3M6IHRydWVcbiAgICAgICAgfSxcbiAgICAgICAgbWF4Q29uY3VycmVuY3k6IDUsXG4gICAgICAgIGV4cGVjdGVkQ29uY3VycmVuY3k6IDVcbiAgICB9KTtcbn0pO1xuXG50ZXN0KFwibG9jYWwgcHJvdmlkZXIgbm8gY29uY3VycmVuY3kgZm9yIGNwdSBib3VuZCB3b3JrIHdpdGhvdXQgY2hpbGQgcHJvY2Vzc2VzXCIsIGFzeW5jIHQgPT4ge1xuICAgIGF3YWl0IHRlc3RDb25jdXJyZW5jeSh0LCB7XG4gICAgICAgIG9wdGlvbnM6IHtcbiAgICAgICAgICAgIGNoaWxkUHJvY2VzczogZmFsc2VcbiAgICAgICAgfSxcbiAgICAgICAgbWF4Q29uY3VycmVuY3k6IDUsXG4gICAgICAgIGV4cGVjdGVkQ29uY3VycmVuY3k6IDFcbiAgICB9KTtcbn0pO1xuXG50ZXN0KFwibG9jYWwgcHJvdmlkZXIgY2xlYW51cCB3YWl0cyBmb3IgYWxsIGNoaWxkIHByb2Nlc3NlcyB0byBleGl0XCIsIGFzeW5jIHQgPT4ge1xuICAgIGNvbnN0IGZhYXN0TW9kdWxlID0gYXdhaXQgZmFhc3RMb2NhbChmdW5jcywge1xuICAgICAgICBjaGlsZFByb2Nlc3M6IHRydWUsXG4gICAgICAgIGdjOiBcIm9mZlwiXG4gICAgfSk7XG4gICAgZmFhc3RNb2R1bGUuZnVuY3Rpb25zLnNwaW4oNTAwMCkuY2F0Y2goXyA9PiB7fSk7XG4gICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgYXdhaXQgc2xlZXAoMTAwKTtcbiAgICAgICAgaWYgKGZhYXN0TW9kdWxlLnN0YXRlLmV4ZWN1dG9ycy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgIH1cbiAgICB0LmlzKGZhYXN0TW9kdWxlLnN0YXRlLmV4ZWN1dG9ycy5sZW5ndGgsIDEsIFwiZXhlY3V0b3IgaXMgbm90IHJ1bm5pbmdcIik7XG4gICAgYXdhaXQgZmFhc3RNb2R1bGUuY2xlYW51cCh7IGdjVGltZW91dDogNjAgfSk7XG4gICAgdC5pcyhmYWFzdE1vZHVsZS5zdGF0ZS5leGVjdXRvcnMubGVuZ3RoLCAwLCBcImV4ZWN1dG9ycyBhcmUgcnVubmluZyBhZnRlciBjbGVhbnVwXCIpO1xufSk7XG5cbnRlc3QoXCJsb2NhbCB1bnJlc29sdmVkIG1vZHVsZVwiLCBhc3luYyB0ID0+IHtcbiAgICB0LnBsYW4oMSk7XG4gICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgZmFhc3RMb2NhbCh7fSk7XG4gICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgdC5yZWdleChlcnIubWVzc2FnZSwgL0NvdWxkIG5vdCBmaW5kIGZpbGUvKTtcbiAgICB9XG59KTtcblxudGVzdChcImxvY2FsIGlzc3VlICMzN1wiLCBhc3luYyB0ID0+IHtcbiAgICAvLyBQcmV2aW91c2x5IHRoaXMgY29kZSBjYXVzZWQgYW4gZXhjZXB0aW9uIGFib3V0IG1vZHVsZSB3cmFwcGVyIG5vdCBiZWluZ1xuICAgIC8vIHJlLWVudHJhbnQuIFRoZSBwcm9ibGVtIHdhcyBhIHJhY2UgY29uZGl0aW9uIGJldHdlZW4gd3JhcHBlciBzZWxlY3Rpb25cbiAgICAvLyBhbmQgZXhlY3V0aW9uIGluIGxvY2FsIHByb3ZpZGVyLiBTb2x2ZWQgYnkgbWFraW5nIHdyYXBwZXIgc2VsZWN0b3IgYVxuICAgIC8vIHJlZ3VsYXIgZnVuY3Rpb24gaW5zdGVhZCBvZiBhbiBhc3luYyBmdW5jdGlvbi5cbiAgICBjb25zdCBtID0gYXdhaXQgZmFhc3RMb2NhbChmdW5jcyk7XG4gICAgdHJ5IHtcbiAgICAgICAgY29uc3QgeyBpZGVudGl0eVN0cmluZzogaWRlbnRpdHkgfSA9IG0uZnVuY3Rpb25zO1xuICAgICAgICBhd2FpdCBpZGVudGl0eShcImFcIik7XG4gICAgICAgIGNvbnN0IGIgPSBpZGVudGl0eShcImJcIik7XG4gICAgICAgIGNvbnN0IGMgPSBpZGVudGl0eShcImNcIik7XG4gICAgICAgIGF3YWl0IGI7XG4gICAgICAgIGF3YWl0IGM7XG4gICAgICAgIC8vIFRlc3Qgc3VjY2VlZHMgaWYgbm8gZXhjZXB0aW9ucyBhcmUgdGhyb3duLlxuICAgICAgICB0LnRydWUodHJ1ZSk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgICAgYXdhaXQgbS5jbGVhbnVwKCk7XG4gICAgfVxufSk7XG4iXX0=