UNPKG

faastjs

Version:

Serverless batch computing made simple.

366 lines 56.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Wrapper = exports.WrapperOptionDefaults = exports.createErrorResponse = exports.filename = exports.isGenerator = void 0; const childProcess = require("child_process"); const process = require("process"); const proctor = require("process-doctor"); const util_1 = require("util"); const serialize_1 = require("./serialize"); const throttle_1 = require("./throttle"); const error_1 = require("./error"); const p = (val) => (0, util_1.inspect)(val, { compact: true, breakLength: Infinity }); const isGenerator = (fn) => fn instanceof function* () { }.constructor || fn instanceof async function* () { }.constructor; exports.isGenerator = isGenerator; exports.filename = module.filename; function createErrorResponse(err, { call, startTime, logUrl, executionId }) { return { kind: "promise", type: "reject", value: (0, serialize_1.serializeReturnValue)(call.name, err, false), isErrorObject: typeof err === "object" && err instanceof Error, callId: call.callId, remoteExecutionStartTime: startTime, remoteExecutionEndTime: Date.now(), logUrl, executionId }; } exports.createErrorResponse = createErrorResponse; exports.WrapperOptionDefaults = { wrapperLog: console.log, childProcess: true, childProcessMemoryLimitMb: 0, childProcessTimeoutMs: 0, childProcessEnvironment: {}, childDir: ".", wrapperVerbose: false, validateSerialization: true }; const oomPattern = /Allocation failed - JavaScript heap out of memory/; const FAAST_CHILD_ENV = "FAAST_CHILD"; class Wrapper { constructor(fModule, options = {}) { this.executing = false; this.verbose = false; this.funcs = {}; this.logLines = (msg) => { let lines = msg.split("\n"); if (lines[lines.length - 1] === "") { lines = lines.slice(0, lines.length - 1); } for (const line of lines) { this.log(`[${this.childPid}]: ${line}`); } }; this.options = { ...exports.WrapperOptionDefaults, ...options }; this.log = this.options.wrapperLog; this.verbose = this.options.wrapperVerbose; this.funcs = fModule; this.queue = new throttle_1.AsyncIterableQueue(); /* istanbul ignore if */ if (process.env[FAAST_CHILD_ENV]) { this.options.childProcess = false; this.log(`faast: started child process for module wrapper.`); process.on("message", async (cc) => { const startTime = Date.now(); try { await this.execute({ ...cc, startTime }, { onMessage: async (msg) => { this.log(`Received message ${msg.kind}`); process.send({ done: false, value: msg }); } }); this.log(`Done with this.execute()`); } catch (err) { this.log(err); } finally { process.send({ done: true }); } }); } else { if (!process.env.FAAST_SILENT) { this.log(`faast: successful cold start.`); } } } lookupFunction(request) { const { name, args } = request; if (!name) { throw new Error("Invalid function call request: no name"); } const func = this.funcs[name]; if (!func) { throw new Error(`Function named "${name}" not found`); } if (!args) { throw new Error("Invalid arguments to function call"); } return func; } stopCpuMonitoring() { this.monitoringTimer && clearInterval(this.monitoringTimer); this.monitoringTimer = undefined; } startCpuMonitoring(pid, callId) { if (this.monitoringTimer) { this.stopCpuMonitoring(); } this.monitoringTimer = cpuMonitor(pid, 1000, (err, result) => { if (err) { this.log(`cpu monitor error: ${err}`); } if (result) { this.queue.push({ kind: "cpumetrics", callId, metrics: result }); } }); } stop() { this.stopCpuMonitoring(); if (this.child) { this.log(`Stopping child process.`); this.child.stdout.removeListener("data", this.logLines); this.child.stderr.removeListener("data", this.logLines); this.child.disconnect(); this.child.kill(); this.child = undefined; this.executing = false; } } async execute(callingContext, { errorCallback, onMessage, measureCpuUsage }) { const processError = (err) => err instanceof Error && errorCallback ? errorCallback(err) : err; try { /* istanbul ignore if */ if (this.executing) { this.log(`faast: warning: module wrapper execute is not re-entrant`); throw new Error(`faast: module wrapper is not re-entrant`); } this.executing = true; const { call, startTime, logUrl, executionId, instanceId } = callingContext; const detail = { logUrl, executionId, instanceId }; const { callId } = call; this.log(`calling: ${call.name}`); this.log(` args: ${call.args}`); this.log(` callId: ${callId}`); // let startedMessageTimer: NodeJS.Timeout | undefined = setTimeout( // () => messageCallback({ kind: "functionstarted", callId }), // 2 * 1000 // ); // TODO: Add this code after the execute returns or yields its first value... // if (startedMessageTimer) { // clearTimeout(startedMessageTimer); // startedMessageTimer = undefined; // } const memoryUsage = process.memoryUsage(); const memInfo = p(memoryUsage); if (this.options.childProcess) { if (!this.child) { this.child = this.setupChildProcess(); } this.verbose && this.log(`faast: invoking '${call.name}' in child process, memory: ${memInfo}`); this.child.send(callingContext, err => { /* istanbul ignore if */ if (err) { this.log(`child send error: rejecting with ${err}`); this.queue.push(Promise.reject(err)); } }); if (measureCpuUsage) { this.verbose && this.log(`Starting CPU monitor for pid ${this.child.pid}`); // XXX CPU Monitoring not enabled for now. // this.startCpuMonitoring(this.child.pid, callId); } let timer; const timeout = this.options.childProcessTimeoutMs; if (timeout) { this.verbose && this.log(`Setting timeout: ${timeout}`); timer = setTimeout(() => { const error = new error_1.FaastError({ name: error_1.FaastErrorNames.ETIMEOUT, info: { ...detail, functionName: call.name } }, `Request exceeded timeout of ${timeout}ms`); this.queue.push(Promise.reject(error)); this.stop(); }, timeout); } this.verbose && this.log(`awaiting async dequeue`); try { const promises = []; for await (const result of this.queue) { this.verbose && this.log(`Dequeuing ${p(result)}`); if (result.kind === "promise" || result.kind === "iterator") { result.logUrl = logUrl; } promises.push(onMessage(result)); } await Promise.all(promises); } finally { this.verbose && this.log(`Finalizing queue`); this.stopCpuMonitoring(); timer && clearTimeout(timer); this.queue.clear(); } } else { this.verbose && this.log(`faast: Invoking '${call.name}', memory: ${memInfo}`); const func = this.lookupFunction(call); if (!func) { throw new Error(`faast module wrapper: could not find function '${call.name}'`); } const args = (0, serialize_1.deserialize)(call.args); let value; try { value = await func.apply(undefined, args); this.verbose && this.log(`Finished call function`); } catch (err) { this.log(`Function ${call.name} threw error: ${err}`); throw err; } this.verbose && this.log(`returned value: ${p(value)}, type: ${typeof value}`); const validate = this.options.validateSerialization; const context = { type: "fulfill", callId, ...detail }; // Check for iterable. if (value !== null && value !== undefined) { if ((0, exports.isGenerator)(func)) { let next = await value.next(); let sequence = 0; while (true) { this.verbose && this.log(`next: ${p(next)}`); let result = { ...context, kind: "iterator", value: (0, serialize_1.serializeReturnValue)(call.name, [next], validate), sequence }; if (next.done) { result.remoteExecutionStartTime = startTime; result.remoteExecutionEndTime = Date.now(); result.memoryUsage = memoryUsage; } await onMessage(result); if (next.done) { return; } sequence++; next = await value.next(); } } } await onMessage({ ...context, kind: "promise", value: (0, serialize_1.serializeReturnValue)(call.name, [value], validate), remoteExecutionStartTime: startTime, remoteExecutionEndTime: Date.now(), memoryUsage }); } } catch (err) { this.log(`faast: wrapped function exception or promise rejection: ${err}`); const response = createErrorResponse(processError(err), callingContext); this.log(`Error response: ${(0, util_1.inspect)(response)}`); await onMessage(response); } finally { this.verbose && this.log(`Exiting execute`); this.executing = false; } } setupChildProcess() { this.verbose && this.log(`faast: creating child process`); let execArgv = process.execArgv.slice(); if (this.options.childProcessMemoryLimitMb) { /* istanbul ignore next */ execArgv = process.execArgv.filter(arg => !arg.match(/^--max-old-space-size/) && !arg.match(/^--inspect/)); execArgv.push(`--max-old-space-size=${this.options.childProcessMemoryLimitMb}`); } const { childProcessEnvironment } = this.options; const env = { ...process.env, ...childProcessEnvironment, [FAAST_CHILD_ENV]: "true" }; this.verbose && this.log(`Env: ${JSON.stringify(env)}`); const forkOptions = { silent: true, env, cwd: this.options.childDir, execArgv }; const child = childProcess.fork("./index.js", [], forkOptions); this.childPid = child.pid; child.stdout.setEncoding("utf8"); child.stderr.setEncoding("utf8"); let oom; const detectOom = (chunk) => { if (oomPattern.test(chunk)) { oom = chunk; } }; child.stdout.on("data", this.logLines); child.stderr.on("data", this.logLines); child.stderr.on("data", detectOom); child.on("message", (message) => { this.verbose && this.log(`child message: resolving with ${p(message)}`); if (message.done) { this.queue.done(); } else { this.queue.push(message.value); } }); /* istanbul ignore next */ child.on("error", err => { this.verbose && this.log(`child error: rejecting with ${err}`); this.child = undefined; this.queue.push(Promise.reject(err)); }); child.on("exit", (code, signal) => { this.verbose && this.log(`child exit: code: ${code}, signal: ${signal}`); this.child = undefined; if (code) { this.queue.push(Promise.reject(new Error(`Exited with error code ${code}`))); } else if (signal !== null && signal !== "SIGTERM") { let errorMessage = `Aborted with signal ${signal}`; if (signal === "SIGABRT" && oom) { errorMessage += ` (${oom})`; oom = undefined; } this.queue.push(Promise.reject(new Error(errorMessage))); } else { this.verbose && this.log(`child exiting normally`); } }); return child; } } exports.Wrapper = Wrapper; function cpuMonitor(pid, interval, callback) { const start = Date.now(); const timer = setInterval(() => proctor.lookup(pid, (err, result) => { if (err) { callback(err); return; } const { stime, utime } = result; callback(err, result && { stime: stime * 10, utime: utime * 10, elapsed: Date.now() - start }); }), interval); return timer; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid3JhcHBlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93cmFwcGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDhDQUE4QztBQUM5QyxtQ0FBbUM7QUFDbkMsMENBQTBDO0FBQzFDLCtCQUErQjtBQUUvQiwyQ0FBZ0U7QUFDaEUseUNBQWdEO0FBRWhELG1DQUFzRDtBQUV0RCxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQVEsRUFBRSxFQUFFLENBQUMsSUFBQSxjQUFPLEVBQUMsR0FBRyxFQUFFLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztBQUV4RSxNQUFNLFdBQVcsR0FBRyxDQUFDLEVBQVksRUFBRSxFQUFFLENBQ3hDLEVBQUUsWUFBWSxRQUFRLENBQUMsTUFBSyxDQUFDLENBQUMsV0FBVztJQUN6QyxFQUFFLFlBQVksS0FBSyxTQUFTLENBQUMsTUFBSyxDQUFDLENBQUMsV0FBVyxDQUFDO0FBRnZDLFFBQUEsV0FBVyxlQUU0QjtBQUV2QyxRQUFBLFFBQVEsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDO0FBa0N4QyxTQUFnQixtQkFBbUIsQ0FDL0IsR0FBUSxFQUNSLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsV0FBVyxFQUFrQjtJQUV4RCxPQUFPO1FBQ0gsSUFBSSxFQUFFLFNBQVM7UUFDZixJQUFJLEVBQUUsUUFBUTtRQUNkLEtBQUssRUFBRSxJQUFBLGdDQUFvQixFQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFLEtBQUssQ0FBQztRQUNsRCxhQUFhLEVBQUUsT0FBTyxHQUFHLEtBQUssUUFBUSxJQUFJLEdBQUcsWUFBWSxLQUFLO1FBQzlELE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTTtRQUNuQix3QkFBd0IsRUFBRSxTQUFTO1FBQ25DLHNCQUFzQixFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7UUFDbEMsTUFBTTtRQUNO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bnQiOlsiaW1wb3J0ICogYXMgY2hpbGRQcm9jZXNzIGZyb20gXCJjaGlsZF9wcm9jZXNzXCI7XG5pbXBvcnQgKiBhcyBwcm9jZXNzIGZyb20gXCJwcm9jZXNzXCI7XG5pbXBvcnQgKiBhcyBwcm9jdG9yIGZyb20gXCJwcm9jZXNzLWRvY3RvclwiO1xuaW1wb3J0IHsgaW5zcGVjdCB9IGZyb20gXCJ1dGlsXCI7XG5pbXBvcnQgeyBJdGVyYXRvclJlc3BvbnNlTWVzc2FnZSwgTWVzc2FnZSwgUHJvbWlzZVJlc3BvbnNlTWVzc2FnZSB9IGZyb20gXCIuL3Byb3ZpZGVyXCI7XG5pbXBvcnQgeyBkZXNlcmlhbGl6ZSwgc2VyaWFsaXplUmV0dXJuVmFsdWUgfSBmcm9tIFwiLi9zZXJpYWxpemVcIjtcbmltcG9ydCB7IEFzeW5jSXRlcmFibGVRdWV1ZSB9IGZyb20gXCIuL3Rocm90dGxlXCI7XG5pbXBvcnQgeyBBbnlGdW5jdGlvbiB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBGYWFzdEVycm9yLCBGYWFzdEVycm9yTmFtZXMgfSBmcm9tIFwiLi9lcnJvclwiO1xuXG5jb25zdCBwID0gKHZhbDogYW55KSA9PiBpbnNwZWN0KHZhbCwgeyBjb21wYWN0OiB0cnVlLCBicmVha0xlbmd0aDogSW5maW5pdHkgfSk7XG5cbmV4cG9ydCBjb25zdCBpc0dlbmVyYXRvciA9IChmbjogRnVuY3Rpb24pID0+XG4gICAgZm4gaW5zdGFuY2VvZiBmdW5jdGlvbiogKCkge30uY29uc3RydWN0b3IgfHxcbiAgICBmbiBpbnN0YW5jZW9mIGFzeW5jIGZ1bmN0aW9uKiAoKSB7fS5jb25zdHJ1Y3RvcjtcblxuZXhwb3J0IGNvbnN0IGZpbGVuYW1lID0gbW9kdWxlLmZpbGVuYW1lO1xuXG5leHBvcnQgaW50ZXJmYWNlIENhbGxJZCB7XG4gICAgY2FsbElkOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVHJhbXBvbGluZSB7XG4gICAgdHJhbXBvbGluZTogQW55RnVuY3Rpb247XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVHJhbXBvbGluZUZhY3Rvcnkge1xuICAgIGZpbGVuYW1lOiBzdHJpbmc7XG4gICAgbWFrZVRyYW1wb2xpbmU6ICh3cmFwcGVyOiBXcmFwcGVyKSA9PiBUcmFtcG9saW5lO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEZ1bmN0aW9uQ2FsbCBleHRlbmRzIENhbGxJZCB7XG4gICAgYXJnczogc3RyaW5nO1xuICAgIG1vZHVsZVBhdGg6IHN0cmluZztcbiAgICBuYW1lOiBzdHJpbmc7XG4gICAgUmVzcG9uc2VRdWV1ZUlkOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2FsbGluZ0NvbnRleHQge1xuICAgIGNhbGw6IEZ1bmN0aW9uQ2FsbDtcbiAgICBzdGFydFRpbWU6IG51bWJlcjtcbiAgICBsb2dVcmw/OiBzdHJpbmc7XG4gICAgZXhlY3V0aW9uSWQ/OiBzdHJpbmc7XG4gICAgaW5zdGFuY2VJZD86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNb2R1bGVUeXBlIHtcbiAgICBbbmFtZTogc3RyaW5nXTogYW55O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRXJyb3JSZXNwb25zZShcbiAgICBlcnI6IGFueSxcbiAgICB7IGNhbGwsIHN0YXJ0VGltZSwgbG9nVXJsLCBleGVjdXRpb25JZCB9OiBDYWxsaW5nQ29udGV4dFxuKTogUHJvbWlzZVJlc3BvbnNlTWVzc2FnZSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAga2luZDogXCJwcm9taXNlXCIsXG4gICAgICAgIHR5cGU6IFwicmVqZWN0XCIsXG4gICAgICAgIHZhbHVlOiBzZXJpYWxpemVSZXR1cm5WYWx1ZShjYWxsLm5hbWUsIGVyciwgZmFsc2UpLFxuICAgICAgICBpc0Vycm9yT2JqZWN0OiB0eXBlb2YgZXJyID09PSBcIm9iamVjdFwiICYmIGVyciBpbnN0YW5jZW9mIEVycm9yLFxuICAgICAgICBjYWxsSWQ6IGNhbGwuY2FsbElkLFxuICAgICAgICByZW1vdGVFeGVjdXRpb25TdGFydFRpbWU6IHN0YXJ0VGltZSxcbiAgICAgICAgcmVtb3RlRXhlY3V0aW9uRW5kVGltZTogRGF0ZS5ub3coKSxcbiAgICAgICAgbG9nVXJsLFxuICAgICAgICBleGVjdXRpb25JZFxuICAgIH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV3JhcHBlck9wdGlvbnMge1xuICAgIC8qKlxuICAgICAqIExvZ2dpbmcgZnVuY3Rpb24gZm9yIGNvbnNvbGUubG9nL3dhcm4vZXJyb3Igb3V0cHV0LiBPbmx5IGF2YWlsYWJsZSBpblxuICAgICAqIGNoaWxkIHByb2Nlc3MgbW9kZS4gVGhpcyBpcyBtYWlubHkgdXNlZnVsIGZvciBkZWJ1Z2dpbmcgdGhlIFwibG9jYWxcIlxuICAgICAqIG1vZGUgd2hpY2ggcnVucyBjb2RlIGxvY2FsbHkuIEluIHJlYWwgY2xvdWRzIHRoZSBsb2dzIHdpbGwgZW5kIHVwIGluIHRoZVxuICAgICAqIGNsb3VkIGxvZ2dpbmcgc2VydmljZSAoZS5nLiBDbG91ZHdhdGNoIExvZ3MsIG9yIEdvb2dsZSBTdGFja2RyaXZlciBsb2dzKS5cbiAgICAgKiBEZWZhdWx0cyB0byBjb25zb2xlLmxvZy5cbiAgICAgKi9cbiAgICB3cmFwcGVyTG9nPzogKG1zZzogc3RyaW5nKSA9PiB2b2lkO1xuICAgIGNoaWxkUHJvY2Vzcz86IGJvb2xlYW47XG4gICAgY2hpbGRQcm9jZXNzTWVtb3J5TGltaXRNYj86IG51bWJlcjtcbiAgICBjaGlsZFByb2Nlc3NUaW1lb3V0TXM/OiBudW1iZXI7XG4gICAgY2hpbGRQcm9jZXNzRW52aXJvbm1lbnQ/OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9O1xuICAgIGNoaWxkRGlyPzogc3RyaW5nO1xuICAgIHdyYXBwZXJWZXJib3NlPzogYm9vbGVhbjtcbiAgICB2YWxpZGF0ZVNlcmlhbGl6YXRpb24/OiBib29sZWFuO1xufVxuXG5leHBvcnQgY29uc3QgV3JhcHBlck9wdGlvbkRlZmF1bHRzOiBSZXF1aXJlZDxXcmFwcGVyT3B0aW9ucz4gPSB7XG4gICAgd3JhcHBlckxvZzogY29uc29sZS5sb2csXG4gICAgY2hpbGRQcm9jZXNzOiB0cnVlLFxuICAgIGNoaWxkUHJvY2Vzc01lbW9yeUxpbWl0TWI6IDAsXG4gICAgY2hpbGRQcm9jZXNzVGltZW91dE1zOiAwLFxuICAgIGNoaWxkUHJvY2Vzc0Vudmlyb25tZW50OiB7fSxcbiAgICBjaGlsZERpcjogXCIuXCIsXG4gICAgd3JhcHBlclZlcmJvc2U6IGZhbHNlLFxuICAgIHZhbGlkYXRlU2VyaWFsaXphdGlvbjogdHJ1ZVxufTtcblxudHlwZSBFcnJvckNhbGxiYWNrID0gKGVycjogRXJyb3IpID0+IEVycm9yO1xudHlwZSBNZXNzYWdlQ2FsbGJhY2sgPSAobXNnOiBNZXNzYWdlKSA9PiBQcm9taXNlPHZvaWQ+O1xuXG5leHBvcnQgaW50ZXJmYWNlIFdyYXBwZXJFeGVjdXRlT3B0aW9ucyB7XG4gICAgZXJyb3JDYWxsYmFjaz86IEVycm9yQ2FsbGJhY2s7XG4gICAgb25NZXNzYWdlOiBNZXNzYWdlQ2FsbGJhY2s7XG4gICAgbWVhc3VyZUNwdVVzYWdlPzogYm9vbGVhbjtcbn1cblxuY29uc3Qgb29tUGF0dGVybiA9IC9BbGxvY2F0aW9uIGZhaWxlZCAtIEphdmFTY3JpcHQgaGVhcCBvdXQgb2YgbWVtb3J5LztcblxuY29uc3QgRkFBU1RfQ0hJTERfRU5WID0gXCJGQUFTVF9DSElMRFwiO1xuXG5leHBvcnQgY2xhc3MgV3JhcHBlciB7XG4gICAgZXhlY3V0aW5nID0gZmFsc2U7XG4gICAgcHJvdGVjdGVkIHZlcmJvc2UgPSBmYWxzZTtcbiAgICBwcm90ZWN0ZWQgZnVuY3M6IE1vZHVsZVR5cGUgPSB7fTtcbiAgICBwcm90ZWN0ZWQgY2hpbGQ/OiBjaGlsZFByb2Nlc3MuQ2hpbGRQcm9jZXNzO1xuICAgIHByb3RlY3RlZCBjaGlsZFBpZD86IG51bWJlcjtcbiAgICBwcm90ZWN0ZWQgbG9nOiAobXNnOiBzdHJpbmcpID0+IHZvaWQ7XG4gICAgcHJvdGVjdGVkIHF1ZXVlOiBBc3luY0l0ZXJhYmxlUXVldWU8TWVzc2FnZT47XG4gICAgcmVhZG9ubHkgb3B0aW9uczogUmVxdWlyZWQ8V3JhcHBlck9wdGlvbnM+O1xuICAgIHByb3RlY3RlZCBtb25pdG9yaW5nVGltZXI/OiBOb2RlSlMuVGltZXI7XG5cbiAgICBjb25zdHJ1Y3RvcihmTW9kdWxlOiBNb2R1bGVUeXBlLCBvcHRpb25zOiBXcmFwcGVyT3B0aW9ucyA9IHt9KSB7XG4gICAgICAgIHRoaXMub3B0aW9ucyA9IHsgLi4uV3JhcHBlck9wdGlvbkRlZmF1bHRzLCAuLi5vcHRpb25zIH07XG4gICAgICAgIHRoaXMubG9nID0gdGhpcy5vcHRpb25zLndyYXBwZXJMb2c7XG4gICAgICAgIHRoaXMudmVyYm9zZSA9IHRoaXMub3B0aW9ucy53cmFwcGVyVmVyYm9zZTtcbiAgICAgICAgdGhpcy5mdW5jcyA9IGZNb2R1bGU7XG4gICAgICAgIHRoaXMucXVldWUgPSBuZXcgQXN5bmNJdGVyYWJsZVF1ZXVlKCk7XG5cbiAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICAqL1xuICAgICAgICBpZiAocHJvY2Vzcy5lbnZbRkFBU1RfQ0hJTERfRU5WXSkge1xuICAgICAgICAgICAgdGhpcy5vcHRpb25zLmNoaWxkUHJvY2VzcyA9IGZhbHNlO1xuICAgICAgICAgICAgdGhpcy5sb2coYGZhYXN0OiBzdGFydGVkIGNoaWxkIHByb2Nlc3MgZm9yIG1vZHVsZSB3cmFwcGVyLmApO1xuICAgICAgICAgICAgcHJvY2Vzcy5vbihcIm1lc3NhZ2VcIiwgYXN5bmMgKGNjOiBDYWxsaW5nQ29udGV4dCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5leGVjdXRlKFxuICAgICAgICAgICAgICAgICAgICAgICAgeyAuLi5jYywgc3RhcnRUaW1lIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb25NZXNzYWdlOiBhc3luYyBtc2cgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZyhgUmVjZWl2ZWQgbWVzc2FnZSAke21zZy5raW5kfWApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9jZXNzLnNlbmQhKHsgZG9uZTogZmFsc2UsIHZhbHVlOiBtc2cgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZyhgRG9uZSB3aXRoIHRoaXMuZXhlY3V0ZSgpYCk7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coZXJyKTtcbiAgICAgICAgICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgICAgICAgICBwcm9jZXNzLnNlbmQhKHsgZG9uZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmICghcHJvY2Vzcy5lbnYuRkFBU1RfU0lMRU5UKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5sb2coYGZhYXN0OiBzdWNjZXNzZnVsIGNvbGQgc3RhcnQuYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgbG9va3VwRnVuY3Rpb24ocmVxdWVzdDogb2JqZWN0KTogQW55RnVuY3Rpb24ge1xuICAgICAgICBjb25zdCB7IG5hbWUsIGFyZ3MgfSA9IHJlcXVlc3QgYXMgRnVuY3Rpb25DYWxsO1xuICAgICAgICBpZiAoIW5hbWUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgZnVuY3Rpb24gY2FsbCByZXF1ZXN0OiBubyBuYW1lXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZnVuYyA9IHRoaXMuZnVuY3NbbmFtZV07XG4gICAgICAgIGlmICghZnVuYykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBGdW5jdGlvbiBuYW1lZCBcIiR7bmFtZX1cIiBub3QgZm91bmRgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghYXJncykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBhcmd1bWVudHMgdG8gZnVuY3Rpb24gY2FsbFwiKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZnVuYztcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgc3RvcENwdU1vbml0b3JpbmcoKSB7XG4gICAgICAgIHRoaXMubW9uaXRvcmluZ1RpbWVyICYmIGNsZWFySW50ZXJ2YWwodGhpcy5tb25pdG9yaW5nVGltZXIpO1xuICAgICAgICB0aGlzLm1vbml0b3JpbmdUaW1lciA9IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgc3RhcnRDcHVNb25pdG9yaW5nKHBpZDogbnVtYmVyLCBjYWxsSWQ6IHN0cmluZykge1xuICAgICAgICBpZiAodGhpcy5tb25pdG9yaW5nVGltZXIpIHtcbiAgICAgICAgICAgIHRoaXMuc3RvcENwdU1vbml0b3JpbmcoKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLm1vbml0b3JpbmdUaW1lciA9IGNwdU1vbml0b3IocGlkLCAxMDAwLCAoZXJyLCByZXN1bHQpID0+IHtcbiAgICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmxvZyhgY3B1IG1vbml0b3IgZXJyb3I6ICR7ZXJyfWApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHJlc3VsdCkge1xuICAgICAgICAgICAgICAgIHRoaXMucXVldWUucHVzaCh7IGtpbmQ6IFwiY3B1bWV0cmljc1wiLCBjYWxsSWQsIG1ldHJpY3M6IHJlc3VsdCB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgc3RvcCgpIHtcbiAgICAgICAgdGhpcy5zdG9wQ3B1TW9uaXRvcmluZygpO1xuICAgICAgICBpZiAodGhpcy5jaGlsZCkge1xuICAgICAgICAgICAgdGhpcy5sb2coYFN0b3BwaW5nIGNoaWxkIHByb2Nlc3MuYCk7XG4gICAgICAgICAgICB0aGlzLmNoaWxkLnN0ZG91dCEucmVtb3ZlTGlzdGVuZXIoXCJkYXRhXCIsIHRoaXMubG9nTGluZXMpO1xuICAgICAgICAgICAgdGhpcy5jaGlsZC5zdGRlcnIhLnJlbW92ZUxpc3RlbmVyKFwiZGF0YVwiLCB0aGlzLmxvZ0xpbmVzKTtcbiAgICAgICAgICAgIHRoaXMuY2hpbGQhLmRpc2Nvbm5lY3QoKTtcbiAgICAgICAgICAgIHRoaXMuY2hpbGQhLmtpbGwoKTtcbiAgICAgICAgICAgIHRoaXMuY2hpbGQgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICB0aGlzLmV4ZWN1dGluZyA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgZXhlY3V0ZShcbiAgICAgICAgY2FsbGluZ0NvbnRleHQ6IENhbGxpbmdDb250ZXh0LFxuICAgICAgICB7IGVycm9yQ2FsbGJhY2ssIG9uTWVzc2FnZSwgbWVhc3VyZUNwdVVzYWdlIH06IFdyYXBwZXJFeGVjdXRlT3B0aW9uc1xuICAgICk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBwcm9jZXNzRXJyb3IgPSAoZXJyOiBhbnkpID0+XG4gICAgICAgICAgICBlcnIgaW5zdGFuY2VvZiBFcnJvciAmJiBlcnJvckNhbGxiYWNrID8gZXJyb3JDYWxsYmFjayhlcnIpIDogZXJyO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICAqL1xuICAgICAgICAgICAgaWYgKHRoaXMuZXhlY3V0aW5nKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5sb2coYGZhYXN0OiB3YXJuaW5nOiBtb2R1bGUgd3JhcHBlciBleGVjdXRlIGlzIG5vdCByZS1lbnRyYW50YCk7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBmYWFzdDogbW9kdWxlIHdyYXBwZXIgaXMgbm90IHJlLWVudHJhbnRgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuZXhlY3V0aW5nID0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbnN0IHsgY2FsbCwgc3RhcnRUaW1lLCBsb2dVcmwsIGV4ZWN1dGlvbklkLCBpbnN0YW5jZUlkIH0gPSBjYWxsaW5nQ29udGV4dDtcbiAgICAgICAgICAgIGNvbnN0IGRldGFpbCA9IHsgbG9nVXJsLCBleGVjdXRpb25JZCwgaW5zdGFuY2VJZCB9O1xuICAgICAgICAgICAgY29uc3QgeyBjYWxsSWQgfSA9IGNhbGw7XG4gICAgICAgICAgICB0aGlzLmxvZyhgY2FsbGluZzogJHtjYWxsLm5hbWV9YCk7XG4gICAgICAgICAgICB0aGlzLmxvZyhgICAgYXJnczogJHtjYWxsLmFyZ3N9YCk7XG4gICAgICAgICAgICB0aGlzLmxvZyhgICAgY2FsbElkOiAke2NhbGxJZH1gKTtcbiAgICAgICAgICAgIC8vIGxldCBzdGFydGVkTWVzc2FnZVRpbWVyOiBOb2RlSlMuVGltZW91dCB8IHVuZGVmaW5lZCA9IHNldFRpbWVvdXQoXG4gICAgICAgICAgICAvLyAgICAgKCkgPT4gbWVzc2FnZUNhbGxiYWNrKHsga2luZDogXCJmdW5jdGlvbnN0YXJ0ZWRcIiwgY2FsbElkIH0pLFxuICAgICAgICAgICAgLy8gICAgIDIgKiAxMDAwXG4gICAgICAgICAgICAvLyApO1xuXG4gICAgICAgICAgICAvLyBUT0RPOiBBZGQgdGhpcyBjb2RlIGFmdGVyIHRoZSBleGVjdXRlIHJldHVybnMgb3IgeWllbGRzIGl0cyBmaXJzdCB2YWx1ZS4uLlxuICAgICAgICAgICAgLy8gaWYgKHN0YXJ0ZWRNZXNzYWdlVGltZXIpIHtcbiAgICAgICAgICAgIC8vICAgICBjbGVhclRpbWVvdXQoc3RhcnRlZE1lc3NhZ2VUaW1lcik7XG4gICAgICAgICAgICAvLyAgICAgc3RhcnRlZE1lc3NhZ2VUaW1lciA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIC8vIH1cblxuICAgICAgICAgICAgY29uc3QgbWVtb3J5VXNhZ2UgPSBwcm9jZXNzLm1lbW9yeVVzYWdlKCk7XG4gICAgICAgICAgICBjb25zdCBtZW1JbmZvID0gcChtZW1vcnlVc2FnZSk7XG4gICAgICAgICAgICBpZiAodGhpcy5vcHRpb25zLmNoaWxkUHJvY2Vzcykge1xuICAgICAgICAgICAgICAgIGlmICghdGhpcy5jaGlsZCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNoaWxkID0gdGhpcy5zZXR1cENoaWxkUHJvY2VzcygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLnZlcmJvc2UgJiZcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coXG4gICAgICAgICAgICAgICAgICAgICAgICBgZmFhc3Q6IGludm9raW5nICcke2NhbGwubmFtZX0nIGluIGNoaWxkIHByb2Nlc3MsIG1lbW9yeTogJHttZW1JbmZvfWBcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0aGlzLmNoaWxkLnNlbmQoY2FsbGluZ0NvbnRleHQsIGVyciA9PiB7XG4gICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBpZiAgKi9cbiAgICAgICAgICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coYGNoaWxkIHNlbmQgZXJyb3I6IHJlamVjdGluZyB3aXRoICR7ZXJyfWApO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5xdWV1ZS5wdXNoKFByb21pc2UucmVqZWN0KGVycikpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgaWYgKG1lYXN1cmVDcHVVc2FnZSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnZlcmJvc2UgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubG9nKGBTdGFydGluZyBDUFUgbW9uaXRvciBmb3IgcGlkICR7dGhpcy5jaGlsZC5waWR9YCk7XG4gICAgICAgICAgICAgICAgICAgIC8vIFhYWCBDUFUgTW9uaXRvcmluZyBub3QgZW5hYmxlZCBmb3Igbm93LlxuICAgICAgICAgICAgICAgICAgICAvLyB0aGlzLnN0YXJ0Q3B1TW9uaXRvcmluZyh0aGlzLmNoaWxkLnBpZCwgY2FsbElkKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBsZXQgdGltZXI7XG4gICAgICAgICAgICAgICAgY29uc3QgdGltZW91dCA9IHRoaXMub3B0aW9ucy5jaGlsZFByb2Nlc3NUaW1lb3V0TXM7XG4gICAgICAgICAgICAgICAgaWYgKHRpbWVvdXQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy52ZXJib3NlICYmIHRoaXMubG9nKGBTZXR0aW5nIHRpbWVvdXQ6ICR7dGltZW91dH1gKTtcbiAgICAgICAgICAgICAgICAgICAgdGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGVycm9yID0gbmV3IEZhYXN0RXJyb3IoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lOiBGYWFzdEVycm9yTmFtZXMuRVRJTUVPVVQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZm86IHsgLi4uZGV0YWlsLCBmdW5jdGlvbk5hbWU6IGNhbGwubmFtZSB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBgUmVxdWVzdCBleGNlZWRlZCB0aW1lb3V0IG9mICR7dGltZW91dH1tc2BcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucXVldWUucHVzaChQcm9taXNlLnJlamVjdChlcnJvcikpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zdG9wKCk7XG4gICAgICAgICAgICAgICAgICAgIH0sIHRpbWVvdXQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLnZlcmJvc2UgJiYgdGhpcy5sb2coYGF3YWl0aW5nIGFzeW5jIGRlcXVldWVgKTtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBwcm9taXNlcyA9IFtdO1xuICAgICAgICAgICAgICAgICAgICBmb3IgYXdhaXQgKGNvbnN0IHJlc3VsdCBvZiB0aGlzLnF1ZXVlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnZlcmJvc2UgJiYgdGhpcy5sb2coYERlcXVldWluZyAke3AocmVzdWx0KX1gKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXN1bHQua2luZCA9PT0gXCJwcm9taXNlXCIgfHwgcmVzdWx0LmtpbmQgPT09IFwiaXRlcmF0b3JcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5sb2dVcmwgPSBsb2dVcmw7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBwcm9taXNlcy5wdXNoKG9uTWVzc2FnZShyZXN1bHQpKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChwcm9taXNlcyk7XG4gICAgICAgICAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy52ZXJib3NlICYmIHRoaXMubG9nKGBGaW5hbGl6aW5nIHF1ZXVlYCk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc3RvcENwdU1vbml0b3JpbmcoKTtcbiAgICAgICAgICAgICAgICAgICAgdGltZXIgJiYgY2xlYXJUaW1lb3V0KHRpbWVyKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5xdWV1ZS5jbGVhcigpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy52ZXJib3NlICYmXG4gICAgICAgICAgICAgICAgICAgIHRoaXMubG9nKGBmYWFzdDogSW52b2tpbmcgJyR7Y2FsbC5uYW1lfScsIG1lbW9yeTogJHttZW1JbmZvfWApO1xuICAgICAgICAgICAgICAgIGNvbnN0IGZ1bmMgPSB0aGlzLmxvb2t1cEZ1bmN0aW9uKGNhbGwpO1xuICAgICAgICAgICAgICAgIGlmICghZnVuYykge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgICAgICAgICAgICBgZmFhc3QgbW9kdWxlIHdyYXBwZXI6IGNvdWxkIG5vdCBmaW5kIGZ1bmN0aW9uICcke2NhbGwubmFtZX0nYFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zdCBhcmdzID0gZGVzZXJpYWxpemUoY2FsbC5hcmdzKTtcbiAgICAgICAgICAgICAgICBsZXQgdmFsdWU7XG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBhd2FpdCBmdW5jLmFwcGx5KHVuZGVmaW5lZCwgYXJncyk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMudmVyYm9zZSAmJiB0aGlzLmxvZyhgRmluaXNoZWQgY2FsbCBmdW5jdGlvbmApO1xuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubG9nKGBGdW5jdGlvbiAke2NhbGwubmFtZX0gdGhyZXcgZXJyb3I6ICR7ZXJyfWApO1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMudmVyYm9zZSAmJlxuICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZyhgcmV0dXJuZWQgdmFsdWU6ICR7cCh2YWx1ZSl9LCB0eXBlOiAke3R5cGVvZiB2YWx1ZX1gKTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IHZhbGlkYXRlID0gdGhpcy5vcHRpb25zLnZhbGlkYXRlU2VyaWFsaXphdGlvbjtcbiAgICAgICAgICAgICAgICBjb25zdCBjb250ZXh0ID0geyB0eXBlOiBcImZ1bGZpbGxcIiwgY2FsbElkLCAuLi5kZXRhaWwgfSBhcyBjb25zdDtcbiAgICAgICAgICAgICAgICAvLyBDaGVjayBmb3IgaXRlcmFibGUuXG5cbiAgICAgICAgICAgICAgICBpZiAodmFsdWUgIT09IG51bGwgJiYgdmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoaXNHZW5lcmF0b3IoZnVuYykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxldCBuZXh0ID0gYXdhaXQgdmFsdWUubmV4dCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHNlcXVlbmNlID0gMDtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy52ZXJib3NlICYmIHRoaXMubG9nKGBuZXh0OiAke3AobmV4dCl9YCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHJlc3VsdDogSXRlcmF0b3JSZXNwb25zZU1lc3NhZ2UgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLmNvbnRleHQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtpbmQ6IFwiaXRlcmF0b3JcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHNlcmlhbGl6ZVJldHVyblZhbHVlKGNhbGwubmFtZSwgW25leHRdLCB2YWxpZGF0ZSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcXVlbmNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBhcyBjb25zdDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobmV4dC5kb25lKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5yZW1vdGVFeGVjdXRpb25TdGFydFRpbWUgPSBzdGFydFRpbWU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5yZW1vdGVFeGVjdXRpb25FbmRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0Lm1lbW9yeVVzYWdlID0gbWVtb3J5VXNhZ2U7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IG9uTWVzc2FnZShyZXN1bHQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChuZXh0LmRvbmUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXF1ZW5jZSsrO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5leHQgPSBhd2FpdCB2YWx1ZS5uZXh0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBhd2FpdCBvbk1lc3NhZ2Uoe1xuICAgICAgICAgICAgICAgICAgICAuLi5jb250ZXh0LFxuICAgICAgICAgICAgICAgICAgICBraW5kOiBcInByb21pc2VcIixcbiAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHNlcmlhbGl6ZVJldHVyblZhbHVlKGNhbGwubmFtZSwgW3ZhbHVlXSwgdmFsaWRhdGUpLFxuICAgICAgICAgICAgICAgICAgICByZW1vdGVFeGVjdXRpb25TdGFydFRpbWU6IHN0YXJ0VGltZSxcbiAgICAgICAgICAgICAgICAgICAgcmVtb3RlRXhlY3V0aW9uRW5kVGltZTogRGF0ZS5ub3coKSxcbiAgICAgICAgICAgICAgICAgICAgbWVtb3J5VXNhZ2VcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgI