UNPKG

faastjs

Version:

Serverless batch computing made simple.

226 lines 30.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.costSnapshot = exports.localPacker = exports.logUrl = exports.LocalImpl = exports.defaults = exports.defaultGcWorker = void 0; const tslib_1 = require("tslib"); const child_process_1 = tslib_1.__importDefault(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 = tslib_1.__importStar(require("./local-trampoline")); const exec = (0, util_1.promisify)(child_process_1.default.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, timeout, env, validateSerialization } = options; if (!childProcess) { process.env = { ...process.env, ...env }; } const { wrapperVerbose } = options.debugOptions; const getWrapperInfo = async () => { const idleWrapper = wrappers.find(w => w.wrapper.selected === false); if (idleWrapper) { idleWrapper.wrapper.selected = true; 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(await import(serverModule), wrapperOptions2); wrapper.selected = true; 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 } = await state.getExecutor(); await wrapper .execute({ call, startTime, logUrl: url }, { onMessage: async (msg) => state.queue.enqueue(msg) }) .finally(() => (wrapper.selected = false)); } 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9jYWwtZmFhc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbG9jYWwvbG9jYWwtZmFhc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLDBFQUFnQztBQUNoQyx1Q0FRa0I7QUFDbEIsMkJBQTRCO0FBQzVCLCtCQUE0QjtBQUU1QiwrQkFBaUM7QUFDakMsa0NBQW1EO0FBQ25ELGdDQUE2QjtBQUM3QixzQ0FBNkQ7QUFDN0QsMENBU3FCO0FBQ3JCLHNDQUFzRDtBQUN0RCwwQ0FBeUM7QUFDekMsd0NBQW1FO0FBQ25FLG1GQUE2RDtBQUU3RCxNQUFNLElBQUksR0FBRyxJQUFBLGdCQUFTLEVBQUMsdUJBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztBQXNDakMsU0FBZ0IsZUFBZSxDQUFDLEdBQVc7SUFDdkMsT0FBTyxJQUFBLGlCQUFNLEVBQUMsR0FBRyxDQUFDLENBQUM7QUFDdkIsQ0FBQztBQUZELDBDQUVDO0FBRVksUUFBQSxRQUFRLEdBQTJCO0lBQzVDLEdBQUcseUJBQWM7SUFDakIsV0FBVyxFQUFFLEVBQUU7SUFDZixVQUFVLEVBQUUsR0FBRztJQUNmLFNBQVMsRUFBRSxlQUFlO0NBQzdCLENBQUM7QUFFVyxRQUFBLFNBQVMsR0FBMkM7SUFDN0QsSUFBSSxFQUFFLE9BQU87SUFDYixVQUFVO0lBQ1YsUUFBUSxFQUFSLGdCQUFRO0lBQ1IsT0FBTztJQUNQLFlBQVk7SUFDWixNQUFNO0lBQ04sTUFBTTtJQUNOLElBQUk7SUFDSixlQUFlO0NBQ2xCLENBQUM7QUFFRixLQUFLLFVBQVUsVUFBVSxDQUNyQixZQUFvQixFQUNwQixLQUFXLEVBQ1gsT0FBK0I7SUFFL0IsTUFBTSxRQUFRLEdBQWUsRUFBRSxDQUFDO0lBQ2hDLE1BQU0sRUFBRSxFQUFFLEVBQUUsZUFBZSxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsR0FBRyxPQUFPLENBQUM7SUFFN0QsSUFBSSxTQUFTLENBQUM7SUFDZCxJQUFJLEVBQUUsS0FB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QUNILFdBQVcsQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsQ0FBQztJQUN2QyxPQUFPLElBQUksbUJBQVksQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU8sRUFBRSxLQUFLLEVBQUUsV0FBVyxDQUFDLENBQUM7QUFDeEUsQ0FBQztBQXZCRCxvQ0F1QkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgc3lzIGZyb20gXCJjaGlsZF9wcm9jZXNzXCI7XG5pbXBvcnQge1xuICAgIGNyZWF0ZVdyaXRlU3RyZWFtLFxuICAgIG1rZGlyLFxuICAgIG1rZGlycCxcbiAgICBwYXRoRXhpc3RzLFxuICAgIHJlYWRkaXIsXG4gICAgcmVtb3ZlLFxuICAgIHN0YXRcbn0gZnJvbSBcImZzLWV4dHJhXCI7XG5pbXBvcnQgeyB0bXBkaXIgfSBmcm9tIFwib3NcIjtcbmltcG9ydCB7IGpvaW4gfSBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgV3JpdGFibGUgfSBmcm9tIFwic3RyZWFtXCI7XG5pbXBvcnQgeyBwcm9taXNpZnkgfSBmcm9tIFwidXRpbFwiO1xuaW1wb3J0IHsgQ29zdE1ldHJpYywgQ29zdFNuYXBzaG90IH0gZnJvbSBcIi4uL2Nvc3RcIjtcbmltcG9ydCB7IGxvZyB9IGZyb20gXCIuLi9sb2dcIjtcbmltcG9ydCB7IHBhY2tlciwgUGFja2VyUmVzdWx0LCB1bnppcEluRGlyIH0gZnJvbSBcIi4uL3BhY2tlclwiO1xuaW1wb3J0IHtcbiAgICBDbGVhbnVwT3B0aW9ucyxcbiAgICBjb21tb25EZWZhdWx0cyxcbiAgICBDb21tb25PcHRpb25zLFxuICAgIEZ1bmN0aW9uU3RhdHMsXG4gICAgTWVzc2FnZSxcbiAgICBQb2xsUmVzdWx0LFxuICAgIFByb3ZpZGVySW1wbCxcbiAgICBVVUlEXG59IGZyb20gXCIuLi9wcm92aWRlclwiO1xuaW1wb3J0IHsgaGFzRXhwaXJlZCwgdXVpZHY0UGF0dGVybiB9IGZyb20gXCIuLi9zaGFyZWRcIjtcbmltcG9ydCB7IEFzeW5jUXVldWUgfSBmcm9tIFwiLi4vdGhyb3R0bGVcIjtcbmltcG9ydCB7IEZ1bmN0aW9uQ2FsbCwgV3JhcHBlciwgV3JhcHBlck9wdGlvbnMgfSBmcm9tIFwiLi4vd3JhcHBlclwiO1xuaW1wb3J0ICogYXMgbG9jYWxUcmFtcG9saW5lRmFjdG9yeSBmcm9tIFwiLi9sb2NhbC10cmFtcG9saW5lXCI7XG5cbmNvbnN0IGV4ZWMgPSBwcm9taXNpZnkoc3lzLmV4ZWMpO1xuXG5pbnRlcmZhY2UgRXhlY3V0b3Ige1xuICAgIHdyYXBwZXI6IFdyYXBwZXI7XG4gICAgbG9nVXJsOiBzdHJpbmc7XG4gICAgbG9nU3RyZWFtPzogV3JpdGFibGU7XG59XG5cbi8qKlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgaW50ZXJmYWNlIExvY2FsU3RhdGUge1xuICAgIC8qKiBAaW50ZXJuYWwgKi9cbiAgICBleGVjdXRvcnM6IEV4ZWN1dG9yW107XG4gICAgLyoqIEBpbnRlcm5hbCAqL1xuICAgIGdldEV4ZWN1dG9yOiAoKSA9PiBQcm9taXNlPEV4ZWN1dG9yPjtcbiAgICAvKiogVGhlIHRlbXBvcmFyeSBkaXJlY3Rvcnkgd2hlcmUgdGhlIGxvY2FsIGZ1bmN0aW9uIGlzIGRlcGxveWVkLiAqL1xuICAgIHRlbXBEaXI6IHN0cmluZztcbiAgICAvKiogVGhlIGZpbGU6Ly8gVVJMIGZvciB0aGUgbG9jYWwgZnVuY3Rpb24gbG9nIGZpbGUgZGlyZWN0b3J5LiAgKi9cbiAgICBsb2dVcmw6IHN0cmluZztcbiAgICAvKiogQGludGVybmFsICovXG4gICAgZ2NQcm9taXNlPzogUHJvbWlzZTx2b2lkPjtcbiAgICAvKiogQGludGVybmFsICovXG4gICAgcXVldWU6IEFzeW5jUXVldWU8TWVzc2FnZT47XG4gICAgLyoqIE9wdGlvbnMgdXNlZCB0byBpbml0aWFsaXplIHRoZSBsb2NhbCBmdW5jdGlvbi4gKi9cbiAgICBvcHRpb25zOiBSZXF1aXJlZDxMb2NhbE9wdGlvbnM+O1xufVxuXG4vKipcbiAqIExvY2FsIHByb3ZpZGVyIG9wdGlvbnMgZm9yIHtAbGluayBmYWFzdExvY2FsfS5cbiAqXG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTG9jYWxPcHRpb25zIGV4dGVuZHMgQ29tbW9uT3B0aW9ucyB7XG4gICAgLyoqIEBpbnRlcm5hbCAqL1xuICAgIF9nY1dvcmtlcj86ICh0ZW1wZGlyOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD47XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBkZWZhdWx0R2NXb3JrZXIoZGlyOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gcmVtb3ZlKGRpcik7XG59XG5cbmV4cG9ydCBjb25zdCBkZWZhdWx0czogUmVxdWlyZWQ8TG9jYWxPcHRpb25zPiA9IHtcbiAgICAuLi5jb21tb25EZWZhdWx0cyxcbiAgICBjb25jdXJyZW5jeTogMTAsXG4gICAgbWVtb3J5U2l6ZTogNTEyLFxuICAgIF9nY1dvcmtlcjogZGVmYXVsdEdjV29ya2VyXG59O1xuXG5leHBvcnQgY29uc3QgTG9jYWxJbXBsOiBQcm92aWRlckltcGw8TG9jYWxPcHRpb25zLCBMb2NhbFN0YXRlPiA9IHtcbiAgICBuYW1lOiBcImxvY2FsXCIsXG4gICAgaW5pdGlhbGl6ZSxcbiAgICBkZWZhdWx0cyxcbiAgICBjbGVhbnVwLFxuICAgIGNvc3RTbmFwc2hvdCxcbiAgICBsb2dVcmwsXG4gICAgaW52b2tlLFxuICAgIHBvbGwsXG4gICAgcmVzcG9uc2VRdWV1ZUlkXG59O1xuXG5hc3luYyBmdW5jdGlvbiBpbml0aWFsaXplKFxuICAgIHNlcnZlck1vZHVsZTogc3RyaW5nLFxuICAgIG5vbmNlOiBVVUlELFxuICAgIG9wdGlvbnM6IFJlcXVpcmVkPExvY2FsT3B0aW9ucz5cbik6IFByb21pc2U8TG9jYWxTdGF0ZT4ge1xuICAgIGNvbnN0IHdyYXBwZXJzOiBFeGVjdXRvcltdID0gW107XG4gICAgY29uc3QgeyBnYywgcmV0ZW50aW9uSW5EYXlzLCBfZ2NXb3JrZXI6IGdjV29ya2VyIH0gPSBvcHRpb25zO1xuXG4gICAgbGV0IGdjUHJvbWlzZTtcbiAgICBpZiAoZ2MgPT09IFwiYXV0b1wiIHx8IGdjID09PSBcImZvcmNlXCIpIHtcbiAgICAgICAgZ2NQcm9taXNlID0gY29sbGVjdEdhcmJhZ2UoZ2NXb3JrZXIsIHJldGVudGlvbkluRGF5cyEpO1xuICAgIH1cbiAgICBjb25zdCB0ZW1wRGlyID0gam9pbih0bXBkaXIoKSwgXCJmYWFzdFwiLCBub25jZSk7XG4gICAgbG9nLmluZm8oYHRlbXBEaXI6ICR7dGVtcERpcn0gWyR7b3B0aW9ucy5kZXNjcmlwdGlvbn1dYCk7XG4gICAgYXdhaXQgbWtkaXJwKHRlbXBEaXIpO1xuICAgIGNvbnN0IGxvZ0RpciA9IGpvaW4odGVtcERpciwgXCJsb2dzXCIpO1xuICAgIGF3YWl0IG1rZGlyKGxvZ0Rpcik7XG4gICAgY29uc3QgdXJsID0gYGZpbGU6Ly8ke2xvZ0Rpcn1gO1xuXG4gICAgbG9nLmluZm8oYGxvZ1VSTDogJHt1cmx9YCk7XG5cbiAgICBjb25zdCB7IGNoaWxkUHJvY2VzcywgdGltZW91dCwgZW52LCB2YWxpZGF0ZVNlcmlhbGl6YXRpb24gfSA9IG9wdGlvbnM7XG5cbiAgICBpZiAoIWNoaWxkUHJvY2Vzcykge1xuICAgICAgICBwcm9jZXNzLmVudiA9IHsgLi4ucHJvY2Vzcy5lbnYsIC4uLmVudiB9O1xuICAgIH1cbiAgICBjb25zdCB7IHdyYXBwZXJWZXJib3NlIH0gPSBvcHRpb25zLmRlYnVnT3B0aW9ucztcbiAgICBjb25zdCBnZXRXcmFwcGVySW5mbyA9IGFzeW5jICgpID0+IHtcbiAgICAgICAgY29uc3QgaWRsZVdyYXBwZXIgPSB3cmFwcGVycy5maW5kKHcgPT4gdy53cmFwcGVyLnNlbGVjdGVkID09PSBmYWxzZSk7XG4gICAgICAgIGlmIChpZGxlV3JhcHBlcikge1xuICAgICAgICAgICAgaWRsZVdyYXBwZXIud3JhcHBlci5zZWxlY3RlZCA9IHRydWU7XG4gICAgICAgICAgICByZXR1cm4gaWRsZVdyYXBwZXI7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGxvZ1N0cmVhbSE6IFdyaXRhYmxlO1xuICAgICAgICBsZXQgY2hpbGRsb2cgPSAobXNnOiBzdHJpbmcpID0+IHtcbiAgICAgICAgICAgIGlmIChsb2dTdHJlYW0ud3JpdGFibGUpIHtcbiAgICAgICAgICAgICAgICBsb2dTdHJlYW0ud3JpdGUobXNnKTtcbiAgICAgICAgICAgICAgICBsb2dTdHJlYW0ud3JpdGUoXCJcXG5cIik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGxvZy5wcm92aWRlcihgV0FSTklORzogY2hpbGRsb2cgbm90IHdyaXRhYmxlOiAke21zZ31gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgbG9nRmlsZSA9IGpvaW4obG9nRGlyLCBgJHt3cmFwcGVycy5sZW5ndGh9LmxvZ2ApO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsb2cuaW5mbyhgQ3JlYXRpbmcgd3JpdGUgc3RyZWFtICR7bG9nRmlsZX1gKTtcbiAgICAgICAgICAgIGxvZ1N0cmVhbSA9IGNyZWF0ZVdyaXRlU3RyZWFtKGxvZ0ZpbGUpO1xuICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgbG9nLndhcm4oYEVSUk9SOiBDb3VsZCBub3QgY3JlYXRlIGxvZ2ApO1xuICAgICAgICAgICAgbG9nLndhcm4oZXJyKTtcbiAgICAgICAgICAgIGNoaWxkbG9nID0gY29uc29sZS5sb2c7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgY2hpbGRQcm9jZXNzTWVtb3J5TGltaXRNYiA9IG9wdGlvbnMuY2hpbGRQcm9jZXNzTWVtb3J5TWI7XG4gICAgICAgIGNvbnN0IHdyYXBwZXJPcHRpb25zMjogUmVxdWlyZWQ8V3JhcHBlck9wdGlvbnM+ID0ge1xuICAgICAgICAgICAgd3JhcHBlckxvZzogY2hpbGRsb2csXG4gICAgICAgICAgICBjaGlsZFByb2Nlc3MsXG4gICAgICAgICAgICBjaGlsZFByb2Nlc3NNZW1vcnlMaW1pdE1iLFxuICAgICAgICAgICAgY2hpbGRQcm9jZXNzVGltZW91dE1zOiB0aW1lb3V0ICogMTAwMCAtIChjaGlsZFByb2Nlc3MgPyA1MCA6IDApLFxuICAgICAgICAgICAgY2hpbGRQcm9jZXNzRW52aXJvbm1lbnQ6IGVudixcbiAgICAgICAgICAgIGNoaWxkRGlyOiB0ZW1wRGlyLFxuICAgICAgICAgICAgd3JhcHBlclZlcmJvc2U6IHdyYXBwZXJWZXJib3NlIHx8IGxvZy5wcm92aWRlci5lbmFibGVkLFxuICAgICAgICAgICAgdmFsaWRhdGVTZXJpYWxpemF0aW9uXG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IHdyYXBwZXIgPSBuZXcgV3JhcHBlcihhd2FpdCBpbXBvcnQoc2VydmVyTW9kdWxlKSwgd3JhcHBlck9wdGlvbnMyKTtcbiAgICAgICAgd3JhcHBlci5zZWxlY3RlZCA9IHRydWU7XG4gICAgICAgIGNvbnN0IHJ2ID0geyB3cmFwcGVyLCBsb2dVcmw6IGBmaWxlOi8vJHtsb2dGaWxlfWAsIGxvZ1N0cmVhbSB9O1xuICAgICAgICB3cmFwcGVycy5wdXNoKHJ2KTtcbiAgICAgICAgcmV0dXJuIHJ2O1xuICAgIH07XG5cbiAgICBjb25zdCBwYWNrZXJSZXN1bHQgPSBhd2FpdCBsb2NhbFBhY2tlcihcbiAgICAgICAgc2VydmVyTW9kdWxlLFxuICAgICAgICBvcHRpb25zLFxuICAgICAgICB7IHdyYXBwZXJWZXJib3NlIH0sXG4gICAgICAgIGBmYWFzdC0ke25vbmNlfWBcbiAgICApO1xuXG4gICAgYXdhaXQgdW56aXBJbkRpcih0ZW1wRGlyLCBwYWNrZXJSZXN1bHQuYXJjaGl2ZSk7XG4gICAgaWYgKG9wdGlvbnMucGFja2FnZUpzb24pIHtcbiAgICAgICAgbG9nLmluZm8oYFJ1bm5pbmcgJ25wbSBpbnN0YWxsJ2ApO1xuXG4gICAgICAgIGF3YWl0IGV4ZWMoXCJucG0gaW5zdGFsbCAtLW5vLXBhY2thZ2UtbG9ja1wiLCB7IGN3ZDogdGVtcERpciB9KS50aGVuKHggPT4ge1xuICAgICAgICAgICAgbG9nLmluZm8oeC5zdGRvdXQpO1xuICAgICAgICAgICAgaWYgKHguc3RkZXJyKSB7XG4gICAgICAgICAgICAgICAgbG9nLndhcm4oeC5zdGRlcnIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgICBleGVjdXRvcnM6IHdyYXBwZXJzLFxuICAgICAgICBnZXRFeGVjdXRvcjogZ2V0V3JhcHBlckluZm8sXG4gICAgICAgIHRlbXBEaXIsXG4gICAgICAgIGxvZ1VybDogdXJsLFxuICAgICAgICBnY1Byb21pc2UsXG4gICAgICAgIHF1ZXVlOiBuZXcgQXN5bmNRdWV1ZSgpLFxuICAgICAgICBvcHRpb25zXG4gICAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGxvZ1VybChzdGF0ZTogTG9jYWxTdGF0ZSkge1xuICAgIHJldHVybiBzdGF0ZS5sb2dVcmw7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsb2NhbFBhY2tlcihcbiAgICBmdW5jdGlvbk1vZHVsZTogc3RyaW5nLFxuICAgIG9wdGlvbnM6IENvbW1vbk9wdGlvbnMsXG4gICAgd3JhcHBlck9wdGlvbnM6IFdyYXBwZXJPcHRpb25zLFxuICAgIEZ1bmN0aW9uTmFtZTogc3RyaW5nXG4pOiBQcm9taXNlPFBhY2tlclJlc3VsdD4ge1xuICAgIHJldHVybiBwYWNrZXIoXG4gICAgICAgIGxvY2FsVHJhbXBvbGluZUZhY3RvcnksXG4gICAgICAgIGZ1bmN0aW9uTW9kdWxlLFxuICAgICAgICBvcHRpb25zLFxuICAgICAgICB3cmFwcGVyT3B0aW9ucyxcbiAgICAgICAgRnVuY3Rpb25OYW1lXG4gICAgKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gaW52b2tlKFxuICAgIHN0YXRlOiBMb2NhbFN0YXRlLFxuICAgIGNhbGw6IEZ1bmN0aW9uQ2FsbCxcbiAgICBfOiBQcm9taXNlPHZvaWQ+XG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7fSA9IHN0YXRlO1xuICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgY29uc3QgeyB3cmFwcGVyLCBsb2dVcmw6IHVybCB9ID0gYXdhaXQgc3RhdGUuZ2V0RXhlY3V0b3IoKTtcbiAgICBhd2FpdCB3cmFwcGVyXG4gICAgICAgIC5leGVjdXRlKFxuICAgICAgICAgICAgeyBjYWxsLCBzdGFydFRpbWUsIGxvZ1VybDogdXJsIH0sXG4gICAgICAgICAgICB7IG9uTWVzc2FnZTogYXN5bmMgbXNnID0+IHN0YXRlLnF1ZXVlLmVucXVldWUobXNnKSB9XG4gICAgICAgIClcbiAgICAgICAgLmZpbmFsbHkoKCkgPT4gKHdyYXBwZXIuc2VsZWN0ZWQgPSBmYWxzZSkpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBwb2xsKHN0YXRlOiBMb2NhbFN0YXRlLCBjYW5jZWw6IFByb21pc2U8dm9pZD4pOiBQcm9taXNlPFBvbGxSZXN1bHQ+IHtcbiAgICBjb25zdCBtZXNzYWdlID0gYXdhaXQgUHJvbWlzZS5yYWNlKFtzdGF0ZS5xdWV1ZS5uZXh0KCksIGNhbmNlbF0pO1xuICAgIGlmICghbWVzc2FnZSkge1xuICAgICAgICByZXR1cm4geyBNZXNzYWdlczogW10gfTtcbiAgICB9XG4gICAgcmV0dXJuIHsgTWVzc2FnZXM6IFttZXNzYWdlXSB9O1xufVxuXG5mdW5jdGlvbiByZXNwb25zZVF1ZXVlSWQoX3N0YXRlOiBMb2NhbFN0YXRlKTogc3RyaW5nIHtcbiAgICByZXR1cm4gXCI8bm9uZT5cIjtcbn1cblxuYXN5bmMgZnVuY3Rpb24gY2xlYW51cChzdGF0ZTogTG9jYWxTdGF0ZSwgb3B0aW9uczogQ2xlYW51cE9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBsb2cuaW5mbyhgbG9jYWwgY2xlYW51cCBzdGFydGluZy5gKTtcblxuICAgIGF3YWl0IFByb21pc2UuYWxsKHN0YXRlLmV4ZWN1dG9ycy5tYXAoZSA9PiBlLndyYXBwZXIuc3RvcCgpKSk7XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIHN0YXRlLmV4ZWN1dG9ycy5tYXAoZSA9PiBuZXcgUHJvbWlzZShyZXNvbHZlID0+IGUubG9nU3RyZWFtPy5lbmQocmVzb2x2ZSkpKVxuICAgICk7XG4gICAgc3RhdGUuZXhlY3V0b3JzID0gW107XG4gICAgaWYgKHN0YXRlLmdjUHJvbWlzZSkge1xuICAgICAgICBhd2FpdCBzdGF0ZS5nY1Byb21pc2U7XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMuZGVsZXRlUmVzb3VyY2VzKSB7XG4gICAgICAgIGNvbnN0IHsgdGVtcERpciB9ID0gc3RhdGU7XG4gICAgICAgIGNvbnN0IHBhdHRlcm4gPSBuZXcgUmVnRXhwKGAvZmFhc3QvJHt1dWlkdjRQYXR0ZXJufSRgKTtcbiAgICAgICAgaWYgKHRlbXBEaXIubWF0Y2gocGF0dGVybikgJiYgKGF3YWl0IHBhdGhFeGlzdHModGVtcERpcikpKSB7XG4gICAgICAgICAgICBsb2cuaW5mbyhgRGVsZXRpbmcgdGVtcCBkaXIgJHt0ZW1wRGlyfWApO1xuICAgICAgICAgICAgYXdhaXQgcmVtb3ZlKHRlbXBEaXIpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGxvZy5pbmZvKGBsb2NhbCBjbGVhbnVwIGRvbmUuYCk7XG59XG5cbmxldCBnYXJiYWdlQ29sbGVjdG9yUnVubmluZyA9IGZhbHNlO1xuXG5hc3luYyBmdW5jdGlvbiBjb2xsZWN0R2FyYmFnZShcbiAgICBnY1dvcmtlcjogKGRpcjogc3RyaW5nKSA9PiBQcm9taXNlPHZvaWQ+LFxuICAgIHJldGVudGlvbkluRGF5czogbnVtYmVyXG4pIHtcbiAgICBpZiAoZ2NXb3JrZXIgPT09IGRlZmF1bHRHY1dvcmtlcikge1xuICAgICAgICBpZiAoZ2FyYmFnZUNvbGxlY3RvclJ1bm5pbmcpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBnYXJiYWdlQ29sbGVjdG9yUnVubmluZyA9IHRydWU7XG4gICAgfVxuICAgIGNvbnN0IHRtcCA9IGpvaW4odG1wZGlyKCksIFwiZmFhc3RcIik7XG4gICAgbG9nLmdjKHRtcCk7XG4gICAgdHJ5IHtcbiAgICAgICAgY29uc3QgZGlyID0gYXdhaXQgcmVhZGRpcih0bXApO1xuICAgICAgICBjb25zdCBwYXR0ZXJuID0gbmV3IFJlZ0V4cChgXiR7dXVpZHY0UGF0dGVybn0kYCk7XG4gICAgICAgIGZvciAoY29uc3QgZW50cnkgb2YgZGlyKSB7XG4gICAgICAgICAgICBpZiAoZW50cnkubWF0Y2gocGF0dGVybikpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBmYWFzdERpciA9IGpvaW4odG1wLCBlbnRyeSk7XG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3RhdHMgPSBhd2FpdCBzdGF0KGZhYXN0RGlyKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGhhc0V4cGlyZWQoc3RhdHMuYXRpbWVNcywgcmV0ZW50aW9uSW5EYXlzKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgbG9nLmdjKGZhYXN0RGlyKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IGdjV29ya2VyKGZhYXN0RGlyKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7fVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgbG9nLmdjKGVycik7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgICAgaWYgKGdjV29ya2VyID09PSBkZWZhdWx0R2NXb3JrZXIpIHtcbiAgICAgICAgICAgIGdhcmJhZ2VDb2xsZWN0b3JSdW5uaW5nID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjb3N0U25hcHNob3Qoc3RhdGU6IExvY2FsU3RhdGUsIHN0YXRzOiBGdW5jdGlvblN0YXRzKSB7XG4gICAgY29uc3QgYmlsbGVkVGltZVN0YXRzID0gc3RhdHMuZXN0aW1hdGVkQmlsbGVkVGltZTtcbiAgICBjb25zdCBzZWNvbmRzID0gKGJpbGxlZFRpbWVTdGF0cy5tZWFuIC8gMTAwMCkgKiBiaWxsZWRUaW1lU3RhdHMuc2FtcGxlcyB8fCAwO1xuXG4gICAgY29uc3QgY29zdE1ldHJpY3M6IENvc3RNZXRyaWNbXSA9IFtdO1xuICAgIGNvbnN0IGZ1bmN0aW9uQ2FsbER1cmF0aW9uID0gbmV3IENvc3RNZXRyaWMoe1xuICAgICAgICBuYW1lOiBcImZ1bmN0aW9uQ2FsbER1cmF0aW9uXCIsXG4gICAgICAgIHByaWNpbmc6IDAsXG4gICAgICAgIHVuaXQ6IFwic2Vjb25kXCIsXG4gICAgICAgIG1lYXN1cmVkOiBzZWNvbmRzLFxuICAgICAgICBpbmZvcm1hdGlvbmFsT25seTogdHJ1ZVxuICAgIH0pO1xuICAgIGNvc3RNZXRyaWNzLnB1c2goZnVuY3Rpb25DYWxsRHVyYXRpb24pO1xuXG4gICAgY29uc3QgZnVuY3Rpb25DYWxsUmVxdWVzdHMgPSBuZXcgQ29zdE1ldHJpYyh7XG4gICAgICAgIG5hbWU6IFwiZnVuY3Rpb25DYWxsUmVxdWVzdHNcIixcbiAgICAgICAgcHJpY2luZzogMCxcbiAgICAgICAgbWVhc3VyZWQ6IHN0YXRzLmludm9jYXRpb25zLFxuICAgICAgICB1bml0OiBcInJlcXVlc3RcIixcbiAgICAgICAgaW5mb3JtYXRpb25hbE9ubHk6IHRydWVcbiAgICB9KTtcbiAgICBjb3N0TWV0cmljcy5wdXNoKGZ1bmN0aW9uQ2FsbFJlcXVlc3RzKTtcbiAgICByZXR1cm4gbmV3IENvc3RTbmFwc2hvdChcImxvY2FsXCIsIHN0YXRlLm9wdGlvbnMsIHN0YXRzLCBjb3N0TWV0cmljcyk7XG59XG4iXX0=