UNPKG

faastjs

Version:

Serverless batch computing made simple.

221 lines 30 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.costSnapshot = exports.localPacker = exports.logUrl = exports.LocalImpl = exports.defaults = exports.defaultGcWorker = void 0; const sys = require("child_process"); const fs_extra_1 = require("fs-extra"); const os_1 = require("os"); const path_1 = require("path"); const util_1 = require("util"); const cost_1 = require("../cost"); const log_1 = require("../log"); const packer_1 = require("../packer"); const provider_1 = require("../provider"); const shared_1 = require("../shared"); const throttle_1 = require("../throttle"); const wrapper_1 = require("../wrapper"); const localTrampolineFactory = require("./local-trampoline"); const exec = (0, util_1.promisify)(sys.exec); function defaultGcWorker(dir) { return (0, fs_extra_1.remove)(dir); } exports.defaultGcWorker = defaultGcWorker; exports.defaults = { ...provider_1.commonDefaults, concurrency: 10, memorySize: 512, _gcWorker: defaultGcWorker }; exports.LocalImpl = { name: "local", initialize, defaults: exports.defaults, cleanup, costSnapshot, logUrl, invoke, poll, responseQueueId }; async function initialize(serverModule, nonce, options) { const wrappers = []; const { gc, retentionInDays, _gcWorker: gcWorker } = options; let gcPromise; if (gc === "auto" || gc === "force") { gcPromise = collectGarbage(gcWorker, retentionInDays); } const tempDir = (0, path_1.join)((0, os_1.tmpdir)(), "faast", nonce); log_1.log.info(`tempDir: ${tempDir} [${options.description}]`); await (0, fs_extra_1.mkdirp)(tempDir); const logDir = (0, path_1.join)(tempDir, "logs"); await (0, fs_extra_1.mkdir)(logDir); const url = `file://${logDir}`; log_1.log.info(`logURL: ${url}`); const { childProcess, memorySize, timeout, env, validateSerialization } = options; if (!childProcess) { process.env = { ...process.env, ...env }; } const { wrapperVerbose } = options.debugOptions; const getWrapperInfo = () => { const idleWrapper = wrappers.find(w => w.wrapper.executing === false); if (idleWrapper) { return idleWrapper; } let logStream; let childlog = (msg) => { if (logStream.writable) { logStream.write(msg); logStream.write("\n"); } else { log_1.log.provider(`WARNING: childlog not writable: ${msg}`); } }; const logFile = (0, path_1.join)(logDir, `${wrappers.length}.log`); try { log_1.log.info(`Creating write stream ${logFile}`); logStream = (0, fs_extra_1.createWriteStream)(logFile); } catch (err) { log_1.log.warn(`ERROR: Could not create log`); log_1.log.warn(err); childlog = console.log; } const childProcessMemoryLimitMb = options.childProcessMemoryMb; const wrapperOptions2 = { wrapperLog: childlog, childProcess, childProcessMemoryLimitMb, childProcessTimeoutMs: timeout * 1000 - (childProcess ? 50 : 0), childProcessEnvironment: env, childDir: tempDir, wrapperVerbose: wrapperVerbose || log_1.log.provider.enabled, validateSerialization }; const wrapper = new wrapper_1.Wrapper(require(serverModule), wrapperOptions2); const rv = { wrapper, logUrl: `file://${logFile}`, logStream }; wrappers.push(rv); return rv; }; const packerResult = await localPacker(serverModule, options, { wrapperVerbose }, `faast-${nonce}`); await (0, packer_1.unzipInDir)(tempDir, packerResult.archive); if (options.packageJson) { log_1.log.info(`Running 'npm install'`); await exec("npm install --no-package-lock", { cwd: tempDir }).then(x => { log_1.log.info(x.stdout); if (x.stderr) { log_1.log.warn(x.stderr); } }); } return { executors: wrappers, getExecutor: getWrapperInfo, tempDir, logUrl: url, gcPromise, queue: new throttle_1.AsyncQueue(), options }; } function logUrl(state) { return state.logUrl; } exports.logUrl = logUrl; async function localPacker(functionModule, options, wrapperOptions, FunctionName) { return (0, packer_1.packer)(localTrampolineFactory, functionModule, options, wrapperOptions, FunctionName); } exports.localPacker = localPacker; async function invoke(state, call, _) { const {} = state; const startTime = Date.now(); const { wrapper, logUrl: url } = state.getExecutor(); await wrapper.execute({ call, startTime, logUrl: url }, { onMessage: async (msg) => state.queue.enqueue(msg) }); } async function poll(state, cancel) { const message = await Promise.race([state.queue.next(), cancel]); if (!message) { return { Messages: [] }; } return { Messages: [message] }; } function responseQueueId(_state) { return "<none>"; } async function cleanup(state, options) { log_1.log.info(`local cleanup starting.`); await Promise.all(state.executors.map(e => e.wrapper.stop())); await Promise.all(state.executors.map(e => new Promise(resolve => e.logStream?.end(resolve)))); state.executors = []; if (state.gcPromise) { await state.gcPromise; } if (options.deleteResources) { const { tempDir } = state; const pattern = new RegExp(`/faast/${shared_1.uuidv4Pattern}$`); if (tempDir.match(pattern) && (await (0, fs_extra_1.pathExists)(tempDir))) { log_1.log.info(`Deleting temp dir ${tempDir}`); await (0, fs_extra_1.remove)(tempDir); } } log_1.log.info(`local cleanup done.`); } let garbageCollectorRunning = false; async function collectGarbage(gcWorker, retentionInDays) { if (gcWorker === defaultGcWorker) { if (garbageCollectorRunning) { return; } garbageCollectorRunning = true; } const tmp = (0, path_1.join)((0, os_1.tmpdir)(), "faast"); log_1.log.gc(tmp); try { const dir = await (0, fs_extra_1.readdir)(tmp); const pattern = new RegExp(`^${shared_1.uuidv4Pattern}$`); for (const entry of dir) { if (entry.match(pattern)) { const faastDir = (0, path_1.join)(tmp, entry); try { const stats = await (0, fs_extra_1.stat)(faastDir); if ((0, shared_1.hasExpired)(stats.atimeMs, retentionInDays)) { log_1.log.gc(faastDir); await gcWorker(faastDir); } } catch (err) { } } } } catch (err) { log_1.log.gc(err); } finally { if (gcWorker === defaultGcWorker) { garbageCollectorRunning = false; } } } async function costSnapshot(state, stats) { const billedTimeStats = stats.estimatedBilledTime; const seconds = (billedTimeStats.mean / 1000) * billedTimeStats.samples || 0; const costMetrics = []; const functionCallDuration = new cost_1.CostMetric({ name: "functionCallDuration", pricing: 0, unit: "second", measured: seconds, informationalOnly: true }); costMetrics.push(functionCallDuration); const functionCallRequests = new cost_1.CostMetric({ name: "functionCallRequests", pricing: 0, measured: stats.invocations, unit: "request", informationalOnly: true }); costMetrics.push(functionCallRequests); return new cost_1.CostSnapshot("local", state.options, stats, costMetrics); } exports.costSnapshot = costSnapshot; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9jYWwtZmFhc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbG9jYWwvbG9jYWwtZmFhc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUNBQXFDO0FBQ3JDLHVDQVFrQjtBQUNsQiwyQkFBNEI7QUFDNUIsK0JBQTRCO0FBRTVCLCtCQUFpQztBQUNqQyxrQ0FBbUQ7QUFDbkQsZ0NBQTZCO0FBQzdCLHNDQUE2RDtBQUM3RCwwQ0FTcUI7QUFDckIsc0NBQXNEO0FBQ3RELDBDQUF5QztBQUN6Qyx3Q0FBbUU7QUFDbkUsNkRBQTZEO0FBRTdELE1BQU0sSUFBSSxHQUFHLElBQUEsZ0JBQVMsRUFBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7QUFzQ2pDLFNBQWdCLGVBQWUsQ0FBQyxHQUFXO0lBQ3ZDLE9BQU8sSUFBQSxpQkFBTSxFQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQ3ZCLENBQUM7QUFGRCwwQ0FFQztBQUVZLFFBQUEsUUFBUSxHQUEyQjtJQUM1QyxHQUFHLHlCQUFjO0lBQ2pCLFdBQVcsRUFBRSxFQUFFO0lBQ2YsVUFBVSxFQUFFLEdBQUc7SUFDZixTQUFTLEVBQUUsZUFBZTtDQUM3QixDQUFDO0FBRVcsUUFBQSxTQUFTLEdBQTJDO0lBQzdELElBQUksRUFBRSxPQUFPO0lBQ2IsVUFBVTtJQUNWLFFBQVEsRUFBUixnQkFBUTtJQUNSLE9BQU87SUFDUCxZQUFZO0lBQ1osTUFBTTtJQUNOLE1BQU07SUFDTixJQUFJO0lBQ0osZUFBZTtDQUNsQixDQUFDO0FBRUYsS0FBSyxVQUFVLFVBQVUsQ0FDckIsWUFBb0IsRUFDcEIsS0FBVyxFQUNYLE9BQStCO0lBRS9CLE1BQU0sUUFBUSxHQUFlLEVBQUUsQ0FBQztJQUNoQyxNQUFNLEVBQUUsRUFBRSxFQUFFLGVBQWUsRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLEdBQUcsT0FBTyxDQUFDO0lBRTdELElBQUksU0FBUyxDQUFDO0lBQ2QsSUFBSSxFQUFFLEtBQUss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dGVudCI6WyJpbXBvcnQgKiBhcyBzeXMgZnJvbSBcImNoaWxkX3Byb2Nlc3NcIjtcbmltcG9ydCB7XG4gICAgY3JlYXRlV3JpdGVTdHJlYW0sXG4gICAgbWtkaXIsXG4gICAgbWtkaXJwLFxuICAgIHBhdGhFeGlzdHMsXG4gICAgcmVhZGRpcixcbiAgICByZW1vdmUsXG4gICAgc3RhdFxufSBmcm9tIFwiZnMtZXh0cmFcIjtcbmltcG9ydCB7IHRtcGRpciB9IGZyb20gXCJvc1wiO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgeyBXcml0YWJsZSB9IGZyb20gXCJzdHJlYW1cIjtcbmltcG9ydCB7IHByb21pc2lmeSB9IGZyb20gXCJ1dGlsXCI7XG5pbXBvcnQgeyBDb3N0TWV0cmljLCBDb3N0U25hcHNob3QgfSBmcm9tIFwiLi4vY29zdFwiO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSBcIi4uL2xvZ1wiO1xuaW1wb3J0IHsgcGFja2VyLCBQYWNrZXJSZXN1bHQsIHVuemlwSW5EaXIgfSBmcm9tIFwiLi4vcGFja2VyXCI7XG5pbXBvcnQge1xuICAgIENsZWFudXBPcHRpb25zLFxuICAgIGNvbW1vbkRlZmF1bHRzLFxuICAgIENvbW1vbk9wdGlvbnMsXG4gICAgRnVuY3Rpb25TdGF0cyxcbiAgICBNZXNzYWdlLFxuICAgIFBvbGxSZXN1bHQsXG4gICAgUHJvdmlkZXJJbXBsLFxuICAgIFVVSURcbn0gZnJvbSBcIi4uL3Byb3ZpZGVyXCI7XG5pbXBvcnQgeyBoYXNFeHBpcmVkLCB1dWlkdjRQYXR0ZXJuIH0gZnJvbSBcIi4uL3NoYXJlZFwiO1xuaW1wb3J0IHsgQXN5bmNRdWV1ZSB9IGZyb20gXCIuLi90aHJvdHRsZVwiO1xuaW1wb3J0IHsgRnVuY3Rpb25DYWxsLCBXcmFwcGVyLCBXcmFwcGVyT3B0aW9ucyB9IGZyb20gXCIuLi93cmFwcGVyXCI7XG5pbXBvcnQgKiBhcyBsb2NhbFRyYW1wb2xpbmVGYWN0b3J5IGZyb20gXCIuL2xvY2FsLXRyYW1wb2xpbmVcIjtcblxuY29uc3QgZXhlYyA9IHByb21pc2lmeShzeXMuZXhlYyk7XG5cbmludGVyZmFjZSBFeGVjdXRvciB7XG4gICAgd3JhcHBlcjogV3JhcHBlcjtcbiAgICBsb2dVcmw6IHN0cmluZztcbiAgICBsb2dTdHJlYW0/OiBXcml0YWJsZTtcbn1cblxuLyoqXG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTG9jYWxTdGF0ZSB7XG4gICAgLyoqIEBpbnRlcm5hbCAqL1xuICAgIGV4ZWN1dG9yczogRXhlY3V0b3JbXTtcbiAgICAvKiogQGludGVybmFsICovXG4gICAgZ2V0RXhlY3V0b3I6ICgpID0+IEV4ZWN1dG9yO1xuICAgIC8qKiBUaGUgdGVtcG9yYXJ5IGRpcmVjdG9yeSB3aGVyZSB0aGUgbG9jYWwgZnVuY3Rpb24gaXMgZGVwbG95ZWQuICovXG4gICAgdGVtcERpcjogc3RyaW5nO1xuICAgIC8qKiBUaGUgZmlsZTovLyBVUkwgZm9yIHRoZSBsb2NhbCBmdW5jdGlvbiBsb2cgZmlsZSBkaXJlY3RvcnkuICAqL1xuICAgIGxvZ1VybDogc3RyaW5nO1xuICAgIC8qKiBAaW50ZXJuYWwgKi9cbiAgICBnY1Byb21pc2U/OiBQcm9taXNlPHZvaWQ+O1xuICAgIC8qKiBAaW50ZXJuYWwgKi9cbiAgICBxdWV1ZTogQXN5bmNRdWV1ZTxNZXNzYWdlPjtcbiAgICAvKiogT3B0aW9ucyB1c2VkIHRvIGluaXRpYWxpemUgdGhlIGxvY2FsIGZ1bmN0aW9uLiAqL1xuICAgIG9wdGlvbnM6IFJlcXVpcmVkPExvY2FsT3B0aW9ucz47XG59XG5cbi8qKlxuICogTG9jYWwgcHJvdmlkZXIgb3B0aW9ucyBmb3Ige0BsaW5rIGZhYXN0TG9jYWx9LlxuICpcbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMb2NhbE9wdGlvbnMgZXh0ZW5kcyBDb21tb25PcHRpb25zIHtcbiAgICAvKiogQGludGVybmFsICovXG4gICAgX2djV29ya2VyPzogKHRlbXBkaXI6IHN0cmluZykgPT4gUHJvbWlzZTx2b2lkPjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRlZmF1bHRHY1dvcmtlcihkaXI6IHN0cmluZykge1xuICAgIHJldHVybiByZW1vdmUoZGlyKTtcbn1cblxuZXhwb3J0IGNvbnN0IGRlZmF1bHRzOiBSZXF1aXJlZDxMb2NhbE9wdGlvbnM+ID0ge1xuICAgIC4uLmNvbW1vbkRlZmF1bHRzLFxuICAgIGNvbmN1cnJlbmN5OiAxMCxcbiAgICBtZW1vcnlTaXplOiA1MTIsXG4gICAgX2djV29ya2VyOiBkZWZhdWx0R2NXb3JrZXJcbn07XG5cbmV4cG9ydCBjb25zdCBMb2NhbEltcGw6IFByb3ZpZGVySW1wbDxMb2NhbE9wdGlvbnMsIExvY2FsU3RhdGU+ID0ge1xuICAgIG5hbWU6IFwibG9jYWxcIixcbiAgICBpbml0aWFsaXplLFxuICAgIGRlZmF1bHRzLFxuICAgIGNsZWFudXAsXG4gICAgY29zdFNuYXBzaG90LFxuICAgIGxvZ1VybCxcbiAgICBpbnZva2UsXG4gICAgcG9sbCxcbiAgICByZXNwb25zZVF1ZXVlSWRcbn07XG5cbmFzeW5jIGZ1bmN0aW9uIGluaXRpYWxpemUoXG4gICAgc2VydmVyTW9kdWxlOiBzdHJpbmcsXG4gICAgbm9uY2U6IFVVSUQsXG4gICAgb3B0aW9uczogUmVxdWlyZWQ8TG9jYWxPcHRpb25zPlxuKTogUHJvbWlzZTxMb2NhbFN0YXRlPiB7XG4gICAgY29uc3Qgd3JhcHBlcnM6IEV4ZWN1dG9yW10gPSBbXTtcbiAgICBjb25zdCB7IGdjLCByZXRlbnRpb25JbkRheXMsIF9nY1dvcmtlcjogZ2NXb3JrZXIgfSA9IG9wdGlvbnM7XG5cbiAgICBsZXQgZ2NQcm9taXNlO1xuICAgIGlmIChnYyA9PT0gXCJhdXRvXCIgfHwgZ2MgPT09IFwiZm9yY2VcIikge1xuICAgICAgICBnY1Byb21pc2UgPSBjb2xsZWN0R2FyYmFnZShnY1dvcmtlciwgcmV0ZW50aW9uSW5EYXlzISk7XG4gICAgfVxuICAgIGNvbnN0IHRlbXBEaXIgPSBqb2luKHRtcGRpcigpLCBcImZhYXN0XCIsIG5vbmNlKTtcbiAgICBsb2cuaW5mbyhgdGVtcERpcjogJHt0ZW1wRGlyfSBbJHtvcHRpb25zLmRlc2NyaXB0aW9ufV1gKTtcbiAgICBhd2FpdCBta2RpcnAodGVtcERpcik7XG4gICAgY29uc3QgbG9nRGlyID0gam9pbih0ZW1wRGlyLCBcImxvZ3NcIik7XG4gICAgYXdhaXQgbWtkaXIobG9nRGlyKTtcbiAgICBjb25zdCB1cmwgPSBgZmlsZTovLyR7bG9nRGlyfWA7XG5cbiAgICBsb2cuaW5mbyhgbG9nVVJMOiAke3VybH1gKTtcblxuICAgIGNvbnN0IHsgY2hpbGRQcm9jZXNzLCBtZW1vcnlTaXplLCB0aW1lb3V0LCBlbnYsIHZhbGlkYXRlU2VyaWFsaXphdGlvbiB9ID0gb3B0aW9ucztcblxuICAgIGlmICghY2hpbGRQcm9jZXNzKSB7XG4gICAgICAgIHByb2Nlc3MuZW52ID0geyAuLi5wcm9jZXNzLmVudiwgLi4uZW52IH07XG4gICAgfVxuICAgIGNvbnN0IHsgd3JhcHBlclZlcmJvc2UgfSA9IG9wdGlvbnMuZGVidWdPcHRpb25zO1xuICAgIGNvbnN0IGdldFdyYXBwZXJJbmZvID0gKCkgPT4ge1xuICAgICAgICBjb25zdCBpZGxlV3JhcHBlciA9IHdyYXBwZXJzLmZpbmQodyA9PiB3LndyYXBwZXIuZXhlY3V0aW5nID09PSBmYWxzZSk7XG4gICAgICAgIGlmIChpZGxlV3JhcHBlcikge1xuICAgICAgICAgICAgcmV0dXJuIGlkbGVXcmFwcGVyO1xuICAgICAgICB9XG4gICAgICAgIGxldCBsb2dTdHJlYW0hOiBXcml0YWJsZTtcbiAgICAgICAgbGV0IGNoaWxkbG9nID0gKG1zZzogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICBpZiAobG9nU3RyZWFtLndyaXRhYmxlKSB7XG4gICAgICAgICAgICAgICAgbG9nU3RyZWFtLndyaXRlKG1zZyk7XG4gICAgICAgICAgICAgICAgbG9nU3RyZWFtLndyaXRlKFwiXFxuXCIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBsb2cucHJvdmlkZXIoYFdBUk5JTkc6IGNoaWxkbG9nIG5vdCB3cml0YWJsZTogJHttc2d9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IGxvZ0ZpbGUgPSBqb2luKGxvZ0RpciwgYCR7d3JhcHBlcnMubGVuZ3RofS5sb2dgKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgbG9nLmluZm8oYENyZWF0aW5nIHdyaXRlIHN0cmVhbSAke2xvZ0ZpbGV9YCk7XG4gICAgICAgICAgICBsb2dTdHJlYW0gPSBjcmVhdGVXcml0ZVN0cmVhbShsb2dGaWxlKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICAgIGxvZy53YXJuKGBFUlJPUjogQ291bGQgbm90IGNyZWF0ZSBsb2dgKTtcbiAgICAgICAgICAgIGxvZy53YXJuKGVycik7XG4gICAgICAgICAgICBjaGlsZGxvZyA9IGNvbnNvbGUubG9nO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGNoaWxkUHJvY2Vzc01lbW9yeUxpbWl0TWIgPSBvcHRpb25zLmNoaWxkUHJvY2Vzc01lbW9yeU1iO1xuICAgICAgICBjb25zdCB3cmFwcGVyT3B0aW9uczI6IFJlcXVpcmVkPFdyYXBwZXJPcHRpb25zPiA9IHtcbiAgICAgICAgICAgIHdyYXBwZXJMb2c6IGNoaWxkbG9nLFxuICAgICAgICAgICAgY2hpbGRQcm9jZXNzLFxuICAgICAgICAgICAgY2hpbGRQcm9jZXNzTWVtb3J5TGltaXRNYixcbiAgICAgICAgICAgIGNoaWxkUHJvY2Vzc1RpbWVvdXRNczogdGltZW91dCAqIDEwMDAgLSAoY2hpbGRQcm9jZXNzID8gNTAgOiAwKSxcbiAgICAgICAgICAgIGNoaWxkUHJvY2Vzc0Vudmlyb25tZW50OiBlbnYsXG4gICAgICAgICAgICBjaGlsZERpcjogdGVtcERpcixcbiAgICAgICAgICAgIHdyYXBwZXJWZXJib3NlOiB3cmFwcGVyVmVyYm9zZSB8fCBsb2cucHJvdmlkZXIuZW5hYmxlZCxcbiAgICAgICAgICAgIHZhbGlkYXRlU2VyaWFsaXphdGlvblxuICAgICAgICB9O1xuICAgICAgICBjb25zdCB3cmFwcGVyID0gbmV3IFdyYXBwZXIocmVxdWlyZShzZXJ2ZXJNb2R1bGUpLCB3cmFwcGVyT3B0aW9uczIpO1xuICAgICAgICBjb25zdCBydiA9IHsgd3JhcHBlciwgbG9nVXJsOiBgZmlsZTovLyR7bG9nRmlsZX1gLCBsb2dTdHJlYW0gfTtcbiAgICAgICAgd3JhcHBlcnMucHVzaChydik7XG4gICAgICAgIHJldHVybiBydjtcbiAgICB9O1xuXG4gICAgY29uc3QgcGFja2VyUmVzdWx0ID0gYXdhaXQgbG9jYWxQYWNrZXIoXG4gICAgICAgIHNlcnZlck1vZHVsZSxcbiAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgeyB3cmFwcGVyVmVyYm9zZSB9LFxuICAgICAgICBgZmFhc3QtJHtub25jZX1gXG4gICAgKTtcblxuICAgIGF3YWl0IHVuemlwSW5EaXIodGVtcERpciwgcGFja2VyUmVzdWx0LmFyY2hpdmUpO1xuICAgIGlmIChvcHRpb25zLnBhY2thZ2VKc29uKSB7XG4gICAgICAgIGxvZy5pbmZvKGBSdW5uaW5nICducG0gaW5zdGFsbCdgKTtcblxuICAgICAgICBhd2FpdCBleGVjKFwibnBtIGluc3RhbGwgLS1uby1wYWNrYWdlLWxvY2tcIiwgeyBjd2Q6IHRlbXBEaXIgfSkudGhlbih4ID0+IHtcbiAgICAgICAgICAgIGxvZy5pbmZvKHguc3Rkb3V0KTtcbiAgICAgICAgICAgIGlmICh4LnN0ZGVycikge1xuICAgICAgICAgICAgICAgIGxvZy53YXJuKHguc3RkZXJyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgZXhlY3V0b3JzOiB3cmFwcGVycyxcbiAgICAgICAgZ2V0RXhlY3V0b3I6IGdldFdyYXBwZXJJbmZvLFxuICAgICAgICB0ZW1wRGlyLFxuICAgICAgICBsb2dVcmw6IHVybCxcbiAgICAgICAgZ2NQcm9taXNlLFxuICAgICAgICBxdWV1ZTogbmV3IEFzeW5jUXVldWUoKSxcbiAgICAgICAgb3B0aW9uc1xuICAgIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBsb2dVcmwoc3RhdGU6IExvY2FsU3RhdGUpIHtcbiAgICByZXR1cm4gc3RhdGUubG9nVXJsO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbG9jYWxQYWNrZXIoXG4gICAgZnVuY3Rpb25Nb2R1bGU6IHN0cmluZyxcbiAgICBvcHRpb25zOiBDb21tb25PcHRpb25zLFxuICAgIHdyYXBwZXJPcHRpb25zOiBXcmFwcGVyT3B0aW9ucyxcbiAgICBGdW5jdGlvbk5hbWU6IHN0cmluZ1xuKTogUHJvbWlzZTxQYWNrZXJSZXN1bHQ+IHtcbiAgICByZXR1cm4gcGFja2VyKFxuICAgICAgICBsb2NhbFRyYW1wb2xpbmVGYWN0b3J5LFxuICAgICAgICBmdW5jdGlvbk1vZHVsZSxcbiAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgd3JhcHBlck9wdGlvbnMsXG4gICAgICAgIEZ1bmN0aW9uTmFtZVxuICAgICk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGludm9rZShcbiAgICBzdGF0ZTogTG9jYWxTdGF0ZSxcbiAgICBjYWxsOiBGdW5jdGlvbkNhbGwsXG4gICAgXzogUHJvbWlzZTx2b2lkPlxuKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3Qge30gPSBzdGF0ZTtcbiAgICBjb25zdCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICAgIGNvbnN0IHsgd3JhcHBlciwgbG9nVXJsOiB1cmwgfSA9IHN0YXRlLmdldEV4ZWN1dG9yKCk7XG4gICAgYXdhaXQgd3JhcHBlci5leGVjdXRlKFxuICAgICAgICB7IGNhbGwsIHN0YXJ0VGltZSwgbG9nVXJsOiB1cmwgfSxcbiAgICAgICAgeyBvbk1lc3NhZ2U6IGFzeW5jIG1zZyA9PiBzdGF0ZS5xdWV1ZS5lbnF1ZXVlKG1zZykgfVxuICAgICk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHBvbGwoc3RhdGU6IExvY2FsU3RhdGUsIGNhbmNlbDogUHJvbWlzZTx2b2lkPik6IFByb21pc2U8UG9sbFJlc3VsdD4ge1xuICAgIGNvbnN0IG1lc3NhZ2UgPSBhd2FpdCBQcm9taXNlLnJhY2UoW3N0YXRlLnF1ZXVlLm5leHQoKSwgY2FuY2VsXSk7XG4gICAgaWYgKCFtZXNzYWdlKSB7XG4gICAgICAgIHJldHVybiB7IE1lc3NhZ2VzOiBbXSB9O1xuICAgIH1cbiAgICByZXR1cm4geyBNZXNzYWdlczogW21lc3NhZ2VdIH07XG59XG5cbmZ1bmN0aW9uIHJlc3BvbnNlUXVldWVJZChfc3RhdGU6IExvY2FsU3RhdGUpOiBzdHJpbmcge1xuICAgIHJldHVybiBcIjxub25lPlwiO1xufVxuXG5hc3luYyBmdW5jdGlvbiBjbGVhbnVwKHN0YXRlOiBMb2NhbFN0YXRlLCBvcHRpb25zOiBDbGVhbnVwT3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGxvZy5pbmZvKGBsb2NhbCBjbGVhbnVwIHN0YXJ0aW5nLmApO1xuXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoc3RhdGUuZXhlY3V0b3JzLm1hcChlID0+IGUud3JhcHBlci5zdG9wKCkpKTtcbiAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgc3RhdGUuZXhlY3V0b3JzLm1hcChlID0+IG5ldyBQcm9taXNlKHJlc29sdmUgPT4gZS5sb2dTdHJlYW0/LmVuZChyZXNvbHZlKSkpXG4gICAgKTtcbiAgICBzdGF0ZS5leGVjdXRvcnMgPSBbXTtcbiAgICBpZiAoc3RhdGUuZ2NQcm9taXNlKSB7XG4gICAgICAgIGF3YWl0IHN0YXRlLmdjUHJvbWlzZTtcbiAgICB9XG5cbiAgICBpZiAob3B0aW9ucy5kZWxldGVSZXNvdXJjZXMpIHtcbiAgICAgICAgY29uc3QgeyB0ZW1wRGlyIH0gPSBzdGF0ZTtcbiAgICAgICAgY29uc3QgcGF0dGVybiA9IG5ldyBSZWdFeHAoYC9mYWFzdC8ke3V1aWR2NFBhdHRlcm59JGApO1xuICAgICAgICBpZiAodGVtcERpci5tYXRjaChwYXR0ZXJuKSAmJiAoYXdhaXQgcGF0aEV4aXN0cyh0ZW1wRGlyKSkpIHtcbiAgICAgICAgICAgIGxvZy5pbmZvKGBEZWxldGluZyB0ZW1wIGRpciAke3RlbXBEaXJ9YCk7XG4gICAgICAgICAgICBhd2FpdCByZW1vdmUodGVtcERpcik7XG4gICAgICAgIH1cbiAgICB9XG4gICAgbG9nLmluZm8oYGxvY2FsIGNsZWFudXAgZG9uZS5gKTtcbn1cblxubGV0IGdhcmJhZ2VDb2xsZWN0b3JSdW5uaW5nID0gZmFsc2U7XG5cbmFzeW5jIGZ1bmN0aW9uIGNvbGxlY3RHYXJiYWdlKFxuICAgIGdjV29ya2VyOiAoZGlyOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD4sXG4gICAgcmV0ZW50aW9uSW5EYXlzOiBudW1iZXJcbikge1xuICAgIGlmIChnY1dvcmtlciA9PT0gZGVmYXVsdEdjV29ya2VyKSB7XG4gICAgICAgIGlmIChnYXJiYWdlQ29sbGVjdG9yUnVubmluZykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGdhcmJhZ2VDb2xsZWN0b3JSdW5uaW5nID0gdHJ1ZTtcbiAgICB9XG4gICAgY29uc3QgdG1wID0gam9pbih0bXBkaXIoKSwgXCJmYWFzdFwiKTtcbiAgICBsb2cuZ2ModG1wKTtcbiAgICB0cnkge1xuICAgICAgICBjb25zdCBkaXIgPSBhd2FpdCByZWFkZGlyKHRtcCk7XG4gICAgICAgIGNvbnN0IHBhdHRlcm4gPSBuZXcgUmVnRXhwKGBeJHt1dWlkdjRQYXR0ZXJufSRgKTtcbiAgICAgICAgZm9yIChjb25zdCBlbnRyeSBvZiBkaXIpIHtcbiAgICAgICAgICAgIGlmIChlbnRyeS5tYXRjaChwYXR0ZXJuKSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGZhYXN0RGlyID0gam9pbih0bXAsIGVudHJ5KTtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBzdGF0cyA9IGF3YWl0IHN0YXQoZmFhc3REaXIpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoaGFzRXhwaXJlZChzdGF0cy5hdGltZU1zLCByZXRlbnRpb25JbkRheXMpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBsb2cuZ2MoZmFhc3REaXIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgZ2NXb3JrZXIoZmFhc3REaXIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHt9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICBsb2cuZ2MoZXJyKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgICBpZiAoZ2NXb3JrZXIgPT09IGRlZmF1bHRHY1dvcmtlcikge1xuICAgICAgICAgICAgZ2FyYmFnZUNvbGxlY3RvclJ1bm5pbmcgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNvc3RTbmFwc2hvdChzdGF0ZTogTG9jYWxTdGF0ZSwgc3RhdHM6IEZ1bmN0aW9uU3RhdHMpIHtcbiAgICBjb25zdCBiaWxsZWRUaW1lU3RhdHMgPSBzdGF0cy5lc3RpbWF0ZWRCaWxsZWRUaW1lO1xuICAgIGNvbnN0IHNlY29uZHMgPSAoYmlsbGVkVGltZVN0YXRzLm1lYW4gLyAxMDAwKSAqIGJpbGxlZFRpbWVTdGF0cy5zYW1wbGVzIHx8IDA7XG5cbiAgICBjb25zdCBjb3N0TWV0cmljczogQ29zdE1ldHJpY1tdID0gW107XG4gICAgY29uc3QgZnVuY3Rpb25DYWxsRHVyYXRpb24gPSBuZXcgQ29zdE1ldHJpYyh7XG4gICAgICAgIG5hbWU6IFwiZnVuY3Rpb25DYWxsRHVyYXRpb25cIixcbiAgICAgICAgcHJpY2luZzogMCxcbiAgICAgICAgdW5pdDogXCJzZWNvbmRcIixcbiAgICAgICAgbWVhc3VyZWQ6IHNlY29uZHMsXG4gICAgICAgIGluZm9ybWF0aW9uYWxPbmx5OiB0cnVlXG4gICAgfSk7XG4gICAgY29zdE1ldHJpY3MucHVzaChmdW5jdGlvbkNhbGxEdXJhdGlvbik7XG5cbiAgICBjb25zdCBmdW5jdGlvbkNhbGxSZXF1ZXN0cyA9IG5ldyBDb3N0TWV0cmljKHtcbiAgICAgICAgbmFtZTogXCJmdW5jdGlvbkNhbGxSZXF1ZXN0c1wiLFxuICAgICAgICBwcmljaW5nOiAwLFxuICAgICAgICBtZWFzdXJlZDogc3RhdHMuaW52b2NhdGlvbnMsXG4gICAgICAgIHVuaXQ6IFwicmVxdWVzdFwiLFxuICAgICAgICBpbmZvcm1hdGlvbmFsT25seTogdHJ1ZVxuICAgIH0pO1xuICAgIGNvc3RNZXRyaWNzLnB1c2goZnVuY3Rpb25DYWxsUmVxdWVzdHMpO1xuICAgIHJldHVybiBuZXcgQ29zdFNuYXBzaG90KFwibG9jYWxcIiwgc3RhdGUub3B0aW9ucywgc3RhdHMsIGNvc3RNZXRyaWNzKTtcbn1cbiJdfQ==