UNPKG

faastjs

Version:

Serverless batch computing made simple.

371 lines 57.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Wrapper = exports.WrapperOptionDefaults = exports.createErrorResponse = exports.filename = exports.isGenerator = void 0; const tslib_1 = require("tslib"); const child_process_1 = tslib_1.__importDefault(require("child_process")); const process_1 = tslib_1.__importDefault(require("process")); const process_doctor_1 = tslib_1.__importDefault(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.selected = 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(); /* c8 ignore start */ if (process_1.default.env[FAAST_CHILD_ENV]) { this.options.childProcess = false; this.log(`faast: started child process for module wrapper.`); process_1.default.on("message", async (cc) => { const startTime = Date.now(); try { await this.execute({ ...cc, startTime }, { onMessage: async (msg) => { this.log(`Received message ${msg.kind}`); process_1.default.send({ done: false, value: msg }); } }); this.log(`Done with this.execute()`); } catch (err) { this.log(err); } finally { process_1.default.send({ done: true }); } }); } else { if (!process_1.default.env.FAAST_SILENT) { this.log(`faast: successful cold start.`); } } /* c8 ignore stop */ } 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 { /* c8 ignore start */ if (this.executing) { this.log(`faast: warning: module wrapper execute is not re-entrant`); throw new Error(`faast: module wrapper is not re-entrant`); } /* c8 ignore stop */ 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_1.default.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 => { /* c8 ignore start */ if (err) { this.log(`child send error: rejecting with ${err}`); this.queue.push(Promise.reject(err)); } /* c8 ignore stop */ }); 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_1.default.execArgv.slice(); if (this.options.childProcessMemoryLimitMb) { /* c8 ignore next */ execArgv = process_1.default.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_1.default.env, ...childProcessEnvironment, [FAAST_CHILD_ENV]: "true" }; this.verbose && this.log(`Env: ${JSON.stringify(env)}`); const forkOptions = { silent: true, // redirects stdout and stderr to IPC. env, cwd: this.options.childDir, execArgv }; const child = child_process_1.default.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); } }); /* c8 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(() => process_doctor_1.default.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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid3JhcHBlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93cmFwcGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSwwRUFBeUM7QUFDekMsOERBQThCO0FBQzlCLDRFQUFxQztBQUNyQywrQkFBK0I7QUFFL0IsMkNBQWdFO0FBQ2hFLHlDQUFnRDtBQUVoRCxtQ0FBc0Q7QUFFdEQsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFRLEVBQUUsRUFBRSxDQUFDLElBQUEsY0FBTyxFQUFDLEdBQUcsRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7QUFFeEUsTUFBTSxXQUFXLEdBQUcsQ0FBQyxFQUFZLEVBQUUsRUFBRSxDQUN4QyxFQUFFLFlBQVksUUFBUSxDQUFDLE1BQUssQ0FBQyxDQUFDLFdBQVc7SUFDekMsRUFBRSxZQUFZLEtBQUssU0FBUyxDQUFDLE1BQUssQ0FBQyxDQUFDLFdBQVcsQ0FBQztBQUZ2QyxRQUFBLFdBQVcsZUFFNEI7QUFFdkMsUUFBQSxRQUFRLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQztBQWtDeEMsU0FBZ0IsbUJBQW1CLENBQy9CLEdBQVEsRUFDUixFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBa0I7SUFFeEQsT0FBTztRQUNILElBQUksRUFBRSxTQUFTO1FBQ2YsSUFBSSxFQUFFLFFBQVE7UUFDZCxLQUFLLEVBQUUsSUFBQSxnQ0FBb0IsRUFBQyxJQUFJLENBQUMsSUFBSSxFQUFFLEdBQUcsRUFBRSxLQUFLLENBQUM7UUFDbEQsYUFBYSxFQUFFLE9BQU8sR0FBRyxLQUFLLFFBQVEsSUFBSSxHQUFHLFlBQVksS0FBSztRQUM5RCxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07UUFDbkIsd0JBQXdCLEVBQUUsU0FBUztRQUNuQyxzQkFBc0IsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFO1FBQ2xDLE1BQU07UUFD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QUFVLENBQ2YsR0FBVyxFQUNYLFFBQWdCLEVBQ2hCLFFBQXdEO0lBRXhELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUN6QixNQUFNLEtBQUssR0FBRyxXQUFXLENBQ3JCLEdBQUcsRUFBRSxDQUNELHdCQUFPLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsRUFBRSxNQUFNLEVBQUUsRUFBRTtRQUNoQyxJQUFJLEdBQUcsRUFBRSxDQUFDO1lBQ04sUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ2QsT0FBTztRQUNYLENBQUM7UUFDRCxNQUFNLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxHQUFHLE1BQU0sQ0FBQztRQUNoQyxRQUFRLENBQ0osR0FBRyxFQUNILE1BQU0sSUFBSTtZQUNOLEtBQUssRUFBRSxLQUFLLEdBQUcsRUFBRTtZQUNqQixLQUFLLEVBQUUsS0FBSyxHQUFHLEVBQUU7WUFDakIsT0FBTyxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxLQUFLO1NBQzlCLENBQ0osQ0FBQztJQUNOLENBQUMsQ0FBQyxFQUNOLFFBQVEsQ0FDWCxDQUFDO0lBQ0YsT0FBTyxLQUFLLENBQUM7QUFDakIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBjaGlsZFByb2Nlc3MgZnJvbSBcImNoaWxkX3Byb2Nlc3NcIjtcbmltcG9ydCBwcm9jZXNzIGZyb20gXCJwcm9jZXNzXCI7XG5pbXBvcnQgcHJvY3RvciBmcm9tIFwicHJvY2Vzcy1kb2N0b3JcIjtcbmltcG9ydCB7IGluc3BlY3QgfSBmcm9tIFwidXRpbFwiO1xuaW1wb3J0IHsgSXRlcmF0b3JSZXNwb25zZU1lc3NhZ2UsIE1lc3NhZ2UsIFByb21pc2VSZXNwb25zZU1lc3NhZ2UgfSBmcm9tIFwiLi9wcm92aWRlclwiO1xuaW1wb3J0IHsgZGVzZXJpYWxpemUsIHNlcmlhbGl6ZVJldHVyblZhbHVlIH0gZnJvbSBcIi4vc2VyaWFsaXplXCI7XG5pbXBvcnQgeyBBc3luY0l0ZXJhYmxlUXVldWUgfSBmcm9tIFwiLi90aHJvdHRsZVwiO1xuaW1wb3J0IHsgQW55RnVuY3Rpb24gfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgRmFhc3RFcnJvciwgRmFhc3RFcnJvck5hbWVzIH0gZnJvbSBcIi4vZXJyb3JcIjtcblxuY29uc3QgcCA9ICh2YWw6IGFueSkgPT4gaW5zcGVjdCh2YWwsIHsgY29tcGFjdDogdHJ1ZSwgYnJlYWtMZW5ndGg6IEluZmluaXR5IH0pO1xuXG5leHBvcnQgY29uc3QgaXNHZW5lcmF0b3IgPSAoZm46IEZ1bmN0aW9uKSA9PlxuICAgIGZuIGluc3RhbmNlb2YgZnVuY3Rpb24qICgpIHt9LmNvbnN0cnVjdG9yIHx8XG4gICAgZm4gaW5zdGFuY2VvZiBhc3luYyBmdW5jdGlvbiogKCkge30uY29uc3RydWN0b3I7XG5cbmV4cG9ydCBjb25zdCBmaWxlbmFtZSA9IG1vZHVsZS5maWxlbmFtZTtcblxuZXhwb3J0IGludGVyZmFjZSBDYWxsSWQge1xuICAgIGNhbGxJZDogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRyYW1wb2xpbmUge1xuICAgIHRyYW1wb2xpbmU6IEFueUZ1bmN0aW9uO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRyYW1wb2xpbmVGYWN0b3J5IHtcbiAgICBmaWxlbmFtZTogc3RyaW5nO1xuICAgIG1ha2VUcmFtcG9saW5lOiAod3JhcHBlcjogV3JhcHBlcikgPT4gVHJhbXBvbGluZTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBGdW5jdGlvbkNhbGwgZXh0ZW5kcyBDYWxsSWQge1xuICAgIGFyZ3M6IHN0cmluZztcbiAgICBtb2R1bGVQYXRoOiBzdHJpbmc7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIFJlc3BvbnNlUXVldWVJZDogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENhbGxpbmdDb250ZXh0IHtcbiAgICBjYWxsOiBGdW5jdGlvbkNhbGw7XG4gICAgc3RhcnRUaW1lOiBudW1iZXI7XG4gICAgbG9nVXJsPzogc3RyaW5nO1xuICAgIGV4ZWN1dGlvbklkPzogc3RyaW5nO1xuICAgIGluc3RhbmNlSWQ/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTW9kdWxlVHlwZSB7XG4gICAgW25hbWU6IHN0cmluZ106IGFueTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUVycm9yUmVzcG9uc2UoXG4gICAgZXJyOiBhbnksXG4gICAgeyBjYWxsLCBzdGFydFRpbWUsIGxvZ1VybCwgZXhlY3V0aW9uSWQgfTogQ2FsbGluZ0NvbnRleHRcbik6IFByb21pc2VSZXNwb25zZU1lc3NhZ2Uge1xuICAgIHJldHVybiB7XG4gICAgICAgIGtpbmQ6IFwicHJvbWlzZVwiLFxuICAgICAgICB0eXBlOiBcInJlamVjdFwiLFxuICAgICAgICB2YWx1ZTogc2VyaWFsaXplUmV0dXJuVmFsdWUoY2FsbC5uYW1lLCBlcnIsIGZhbHNlKSxcbiAgICAgICAgaXNFcnJvck9iamVjdDogdHlwZW9mIGVyciA9PT0gXCJvYmplY3RcIiAmJiBlcnIgaW5zdGFuY2VvZiBFcnJvcixcbiAgICAgICAgY2FsbElkOiBjYWxsLmNhbGxJZCxcbiAgICAgICAgcmVtb3RlRXhlY3V0aW9uU3RhcnRUaW1lOiBzdGFydFRpbWUsXG4gICAgICAgIHJlbW90ZUV4ZWN1dGlvbkVuZFRpbWU6IERhdGUubm93KCksXG4gICAgICAgIGxvZ1VybCxcbiAgICAgICAgZXhlY3V0aW9uSWRcbiAgICB9O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFdyYXBwZXJPcHRpb25zIHtcbiAgICAvKipcbiAgICAgKiBMb2dnaW5nIGZ1bmN0aW9uIGZvciBjb25zb2xlLmxvZy93YXJuL2Vycm9yIG91dHB1dC4gT25seSBhdmFpbGFibGUgaW5cbiAgICAgKiBjaGlsZCBwcm9jZXNzIG1vZGUuIFRoaXMgaXMgbWFpbmx5IHVzZWZ1bCBmb3IgZGVidWdnaW5nIHRoZSBcImxvY2FsXCJcbiAgICAgKiBtb2RlIHdoaWNoIHJ1bnMgY29kZSBsb2NhbGx5LiBJbiByZWFsIGNsb3VkcyB0aGUgbG9ncyB3aWxsIGVuZCB1cCBpbiB0aGVcbiAgICAgKiBjbG91ZCBsb2dnaW5nIHNlcnZpY2UgKGUuZy4gQ2xvdWR3YXRjaCBMb2dzKS5cbiAgICAgKiBEZWZhdWx0cyB0byBjb25zb2xlLmxvZy5cbiAgICAgKi9cbiAgICB3cmFwcGVyTG9nPzogKG1zZzogc3RyaW5nKSA9PiB2b2lkO1xuICAgIGNoaWxkUHJvY2Vzcz86IGJvb2xlYW47XG4gICAgY2hpbGRQcm9jZXNzTWVtb3J5TGltaXRNYj86IG51bWJlcjtcbiAgICBjaGlsZFByb2Nlc3NUaW1lb3V0TXM/OiBudW1iZXI7XG4gICAgY2hpbGRQcm9jZXNzRW52aXJvbm1lbnQ/OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9O1xuICAgIGNoaWxkRGlyPzogc3RyaW5nO1xuICAgIHdyYXBwZXJWZXJib3NlPzogYm9vbGVhbjtcbiAgICB2YWxpZGF0ZVNlcmlhbGl6YXRpb24/OiBib29sZWFuO1xufVxuXG5leHBvcnQgY29uc3QgV3JhcHBlck9wdGlvbkRlZmF1bHRzOiBSZXF1aXJlZDxXcmFwcGVyT3B0aW9ucz4gPSB7XG4gICAgd3JhcHBlckxvZzogY29uc29sZS5sb2csXG4gICAgY2hpbGRQcm9jZXNzOiB0cnVlLFxuICAgIGNoaWxkUHJvY2Vzc01lbW9yeUxpbWl0TWI6IDAsXG4gICAgY2hpbGRQcm9jZXNzVGltZW91dE1zOiAwLFxuICAgIGNoaWxkUHJvY2Vzc0Vudmlyb25tZW50OiB7fSxcbiAgICBjaGlsZERpcjogXCIuXCIsXG4gICAgd3JhcHBlclZlcmJvc2U6IGZhbHNlLFxuICAgIHZhbGlkYXRlU2VyaWFsaXphdGlvbjogdHJ1ZVxufTtcblxudHlwZSBFcnJvckNhbGxiYWNrID0gKGVycjogRXJyb3IpID0+IEVycm9yO1xudHlwZSBNZXNzYWdlQ2FsbGJhY2sgPSAobXNnOiBNZXNzYWdlKSA9PiBQcm9taXNlPHZvaWQ+O1xuXG5leHBvcnQgaW50ZXJmYWNlIFdyYXBwZXJFeGVjdXRlT3B0aW9ucyB7XG4gICAgZXJyb3JDYWxsYmFjaz86IEVycm9yQ2FsbGJhY2s7XG4gICAgb25NZXNzYWdlOiBNZXNzYWdlQ2FsbGJhY2s7XG4gICAgbWVhc3VyZUNwdVVzYWdlPzogYm9vbGVhbjtcbn1cblxuY29uc3Qgb29tUGF0dGVybiA9IC9BbGxvY2F0aW9uIGZhaWxlZCAtIEphdmFTY3JpcHQgaGVhcCBvdXQgb2YgbWVtb3J5LztcblxuY29uc3QgRkFBU1RfQ0hJTERfRU5WID0gXCJGQUFTVF9DSElMRFwiO1xuXG5leHBvcnQgY2xhc3MgV3JhcHBlciB7XG4gICAgZXhlY3V0aW5nID0gZmFsc2U7XG4gICAgc2VsZWN0ZWQgPSBmYWxzZTtcbiAgICBwcm90ZWN0ZWQgdmVyYm9zZSA9IGZhbHNlO1xuICAgIHByb3RlY3RlZCBmdW5jczogTW9kdWxlVHlwZSA9IHt9O1xuICAgIHByb3RlY3RlZCBjaGlsZD86IGNoaWxkUHJvY2Vzcy5DaGlsZFByb2Nlc3M7XG4gICAgcHJvdGVjdGVkIGNoaWxkUGlkPzogbnVtYmVyO1xuICAgIHByb3RlY3RlZCBsb2c6IChtc2c6IHN0cmluZykgPT4gdm9pZDtcbiAgICBwcm90ZWN0ZWQgcXVldWU6IEFzeW5jSXRlcmFibGVRdWV1ZTxNZXNzYWdlPjtcbiAgICByZWFkb25seSBvcHRpb25zOiBSZXF1aXJlZDxXcmFwcGVyT3B0aW9ucz47XG4gICAgcHJvdGVjdGVkIG1vbml0b3JpbmdUaW1lcj86IE5vZGVKUy5UaW1lcjtcblxuICAgIGNvbnN0cnVjdG9yKGZNb2R1bGU6IE1vZHVsZVR5cGUsIG9wdGlvbnM6IFdyYXBwZXJPcHRpb25zID0ge30pIHtcbiAgICAgICAgdGhpcy5vcHRpb25zID0geyAuLi5XcmFwcGVyT3B0aW9uRGVmYXVsdHMsIC4uLm9wdGlvbnMgfTtcbiAgICAgICAgdGhpcy5sb2cgPSB0aGlzLm9wdGlvbnMud3JhcHBlckxvZztcbiAgICAgICAgdGhpcy52ZXJib3NlID0gdGhpcy5vcHRpb25zLndyYXBwZXJWZXJib3NlO1xuICAgICAgICB0aGlzLmZ1bmNzID0gZk1vZHVsZTtcbiAgICAgICAgdGhpcy5xdWV1ZSA9IG5ldyBBc3luY0l0ZXJhYmxlUXVldWUoKTtcblxuICAgICAgICAvKiBjOCBpZ25vcmUgc3RhcnQgKi9cbiAgICAgICAgaWYgKHByb2Nlc3MuZW52W0ZBQVNUX0NISUxEX0VOVl0pIHtcbiAgICAgICAgICAgIHRoaXMub3B0aW9ucy5jaGlsZFByb2Nlc3MgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMubG9nKGBmYWFzdDogc3RhcnRlZCBjaGlsZCBwcm9jZXNzIGZvciBtb2R1bGUgd3JhcHBlci5gKTtcbiAgICAgICAgICAgIHByb2Nlc3Mub24oXCJtZXNzYWdlXCIsIGFzeW5jIChjYzogQ2FsbGluZ0NvbnRleHQpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuZXhlY3V0ZShcbiAgICAgICAgICAgICAgICAgICAgICAgIHsgLi4uY2MsIHN0YXJ0VGltZSB9LFxuICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uTWVzc2FnZTogYXN5bmMgbXNnID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coYFJlY2VpdmVkIG1lc3NhZ2UgJHttc2cua2luZH1gKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvY2Vzcy5zZW5kISh7IGRvbmU6IGZhbHNlLCB2YWx1ZTogbXNnIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coYERvbmUgd2l0aCB0aGlzLmV4ZWN1dGUoKWApO1xuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubG9nKGVycik7XG4gICAgICAgICAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgICAgICAgICAgcHJvY2Vzcy5zZW5kISh7IGRvbmU6IHRydWUgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAoIXByb2Nlc3MuZW52LkZBQVNUX1NJTEVOVCkge1xuICAgICAgICAgICAgICAgIHRoaXMubG9nKGBmYWFzdDogc3VjY2Vzc2Z1bCBjb2xkIHN0YXJ0LmApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8qIGM4IGlnbm9yZSBzdG9wICovXG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGxvb2t1cEZ1bmN0aW9uKHJlcXVlc3Q6IG9iamVjdCk6IEFueUZ1bmN0aW9uIHtcbiAgICAgICAgY29uc3QgeyBuYW1lLCBhcmdzIH0gPSByZXF1ZXN0IGFzIEZ1bmN0aW9uQ2FsbDtcbiAgICAgICAgaWYgKCFuYW1lKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIGZ1bmN0aW9uIGNhbGwgcmVxdWVzdDogbm8gbmFtZVwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGZ1bmMgPSB0aGlzLmZ1bmNzW25hbWVdO1xuICAgICAgICBpZiAoIWZ1bmMpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgRnVuY3Rpb24gbmFtZWQgXCIke25hbWV9XCIgbm90IGZvdW5kYCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWFyZ3MpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgYXJndW1lbnRzIHRvIGZ1bmN0aW9uIGNhbGxcIik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZ1bmM7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIHN0b3BDcHVNb25pdG9yaW5nKCkge1xuICAgICAgICB0aGlzLm1vbml0b3JpbmdUaW1lciAmJiBjbGVhckludGVydmFsKHRoaXMubW9uaXRvcmluZ1RpbWVyKTtcbiAgICAgICAgdGhpcy5tb25pdG9yaW5nVGltZXIgPSB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIHN0YXJ0Q3B1TW9uaXRvcmluZyhwaWQ6IG51bWJlciwgY2FsbElkOiBzdHJpbmcpIHtcbiAgICAgICAgaWYgKHRoaXMubW9uaXRvcmluZ1RpbWVyKSB7XG4gICAgICAgICAgICB0aGlzLnN0b3BDcHVNb25pdG9yaW5nKCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5tb25pdG9yaW5nVGltZXIgPSBjcHVNb25pdG9yKHBpZCwgMTAwMCwgKGVyciwgcmVzdWx0KSA9PiB7XG4gICAgICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5sb2coYGNwdSBtb25pdG9yIGVycm9yOiAke2Vycn1gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChyZXN1bHQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnF1ZXVlLnB1c2goeyBraW5kOiBcImNwdW1ldHJpY3NcIiwgY2FsbElkLCBtZXRyaWNzOiByZXN1bHQgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHN0b3AoKSB7XG4gICAgICAgIHRoaXMuc3RvcENwdU1vbml0b3JpbmcoKTtcbiAgICAgICAgaWYgKHRoaXMuY2hpbGQpIHtcbiAgICAgICAgICAgIHRoaXMubG9nKGBTdG9wcGluZyBjaGlsZCBwcm9jZXNzLmApO1xuICAgICAgICAgICAgdGhpcy5jaGlsZC5zdGRvdXQhLnJlbW92ZUxpc3RlbmVyKFwiZGF0YVwiLCB0aGlzLmxvZ0xpbmVzKTtcbiAgICAgICAgICAgIHRoaXMuY2hpbGQuc3RkZXJyIS5yZW1vdmVMaXN0ZW5lcihcImRhdGFcIiwgdGhpcy5sb2dMaW5lcyk7XG4gICAgICAgICAgICB0aGlzLmNoaWxkIS5kaXNjb25uZWN0KCk7XG4gICAgICAgICAgICB0aGlzLmNoaWxkIS5raWxsKCk7XG4gICAgICAgICAgICB0aGlzLmNoaWxkID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgdGhpcy5leGVjdXRpbmcgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGFzeW5jIGV4ZWN1dGUoXG4gICAgICAgIGNhbGxpbmdDb250ZXh0OiBDYWxsaW5nQ29udGV4dCxcbiAgICAgICAgeyBlcnJvckNhbGxiYWNrLCBvbk1lc3NhZ2UsIG1lYXN1cmVDcHVVc2FnZSB9OiBXcmFwcGVyRXhlY3V0ZU9wdGlvbnNcbiAgICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgcHJvY2Vzc0Vycm9yID0gKGVycjogYW55KSA9PlxuICAgICAgICAgICAgZXJyIGluc3RhbmNlb2YgRXJyb3IgJiYgZXJyb3JDYWxsYmFjayA/IGVycm9yQ2FsbGJhY2soZXJyKSA6IGVycjtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8qIGM4IGlnbm9yZSBzdGFydCAgKi9cbiAgICAgICAgICAgIGlmICh0aGlzLmV4ZWN1dGluZykge1xuICAgICAgICAgICAgICAgIHRoaXMubG9nKGBmYWFzdDogd2FybmluZzogbW9kdWxlIHdyYXBwZXIgZXhlY3V0ZSBpcyBub3QgcmUtZW50cmFudGApO1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgZmFhc3Q6IG1vZHVsZSB3cmFwcGVyIGlzIG5vdCByZS1lbnRyYW50YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvKiBjOCBpZ25vcmUgc3RvcCAgKi9cbiAgICAgICAgICAgIHRoaXMuZXhlY3V0aW5nID0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbnN0IHsgY2FsbCwgc3RhcnRUaW1lLCBsb2dVcmwsIGV4ZWN1dGlvbklkLCBpbnN0YW5jZUlkIH0gPSBjYWxsaW5nQ29udGV4dDtcbiAgICAgICAgICAgIGNvbnN0IGRldGFpbCA9IHsgbG9nVXJsLCBleGVjdXRpb25JZCwgaW5zdGFuY2VJZCB9O1xuICAgICAgICAgICAgY29uc3QgeyBjYWxsSWQgfSA9IGNhbGw7XG4gICAgICAgICAgICB0aGlzLmxvZyhgY2FsbGluZzogJHtjYWxsLm5hbWV9YCk7XG4gICAgICAgICAgICB0aGlzLmxvZyhgICAgYXJnczogJHtjYWxsLmFyZ3N9YCk7XG4gICAgICAgICAgICB0aGlzLmxvZyhgICAgY2FsbElkOiAke2NhbGxJZH1gKTtcbiAgICAgICAgICAgIC8vIGxldCBzdGFydGVkTWVzc2FnZVRpbWVyOiBOb2RlSlMuVGltZW91dCB8IHVuZGVmaW5lZCA9IHNldFRpbWVvdXQoXG4gICAgICAgICAgICAvLyAgICAgKCkgPT4gbWVzc2FnZUNhbGxiYWNrKHsga2luZDogXCJmdW5jdGlvbnN0YXJ0ZWRcIiwgY2FsbElkIH0pLFxuICAgICAgICAgICAgLy8gICAgIDIgKiAxMDAwXG4gICAgICAgICAgICAvLyApO1xuXG4gICAgICAgICAgICAvLyBUT0RPOiBBZGQgdGhpcyBjb2RlIGFmdGVyIHRoZSBleGVjdXRlIHJldHVybnMgb3IgeWllbGRzIGl0cyBmaXJzdCB2YWx1ZS4uLlxuICAgICAgICAgICAgLy8gaWYgKHN0YXJ0ZWRNZXNzYWdlVGltZXIpIHtcbiAgICAgICAgICAgIC8vICAgICBjbGVhclRpbWVvdXQoc3RhcnRlZE1lc3NhZ2VUaW1lcik7XG4gICAgICAgICAgICAvLyAgICAgc3RhcnRlZE1lc3NhZ2VUaW1lciA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIC8vIH1cblxuICAgICAgICAgICAgY29uc3QgbWVtb3J5VXNhZ2UgPSBwcm9jZXNzLm1lbW9yeVVzYWdlKCk7XG4gICAgICAgICAgICBjb25zdCBtZW1JbmZvID0gcChtZW1vcnlVc2FnZSk7XG4gICAgICAgICAgICBpZiAodGhpcy5vcHRpb25zLmNoaWxkUHJvY2Vzcykge1xuICAgICAgICAgICAgICAgIGlmICghdGhpcy5jaGlsZCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNoaWxkID0gdGhpcy5zZXR1cENoaWxkUHJvY2VzcygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLnZlcmJvc2UgJiZcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coXG4gICAgICAgICAgICAgICAgICAgICAgICBgZmFhc3Q6IGludm9raW5nICcke2NhbGwubmFtZX0nIGluIGNoaWxkIHByb2Nlc3MsIG1lbW9yeTogJHttZW1JbmZvfWBcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0aGlzLmNoaWxkLnNlbmQoY2FsbGluZ0NvbnRleHQsIGVyciA9PiB7XG4gICAgICAgICAgICAgICAgICAgIC8qIGM4IGlnbm9yZSBzdGFydCAqL1xuICAgICAgICAgICAgICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZyhgY2hpbGQgc2VuZCBlcnJvcjogcmVqZWN0aW5nIHdpdGggJHtlcnJ9YCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnF1ZXVlLnB1c2goUHJvbWlzZS5yZWplY3QoZXJyKSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgLyogYzggaWdub3JlIHN0b3AgKi9cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBpZiAobWVhc3VyZUNwdVVzYWdlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMudmVyYm9zZSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coYFN0YXJ0aW5nIENQVSBtb25pdG9yIGZvciBwaWQgJHt0aGlzLmNoaWxkLnBpZH1gKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gWFhYIENQVSBNb25pdG9yaW5nIG5vdCBlbmFibGVkIGZvciBub3cuXG4gICAgICAgICAgICAgICAgICAgIC8vIHRoaXMuc3RhcnRDcHVNb25pdG9yaW5nKHRoaXMuY2hpbGQucGlkLCBjYWxsSWQpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGxldCB0aW1lcjtcbiAgICAgICAgICAgICAgICBjb25zdCB0aW1lb3V0ID0gdGhpcy5vcHRpb25zLmNoaWxkUHJvY2Vzc1RpbWVvdXRNcztcbiAgICAgICAgICAgICAgICBpZiAodGltZW91dCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnZlcmJvc2UgJiYgdGhpcy5sb2coYFNldHRpbmcgdGltZW91dDogJHt0aW1lb3V0fWApO1xuICAgICAgICAgICAgICAgICAgICB0aW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZXJyb3IgPSBuZXcgRmFhc3RFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWU6IEZhYXN0RXJyb3JOYW1lcy5FVElNRU9VVCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbzogeyAuLi5kZXRhaWwsIGZ1bmN0aW9uTmFtZTogY2FsbC5uYW1lIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBSZXF1ZXN0IGV4Y2VlZGVkIHRpbWVvdXQgb2YgJHt0aW1lb3V0fW1zYFxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5xdWV1ZS5wdXNoKFByb21pc2UucmVqZWN0KGVycm9yKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnN0b3AoKTtcbiAgICAgICAgICAgICAgICAgICAgfSwgdGltZW91dCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMudmVyYm9zZSAmJiB0aGlzLmxvZyhgYXdhaXRpbmcgYXN5bmMgZGVxdWV1ZWApO1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHByb21pc2VzID0gW107XG4gICAgICAgICAgICAgICAgICAgIGZvciBhd2FpdCAoY29uc3QgcmVzdWx0IG9mIHRoaXMucXVldWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudmVyYm9zZSAmJiB0aGlzLmxvZyhgRGVxdWV1aW5nICR7cChyZXN1bHQpfWApO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdC5raW5kID09PSBcInByb21pc2VcIiB8fCByZXN1bHQua2luZCA9PT0gXCJpdGVyYXRvclwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LmxvZ1VybCA9IGxvZ1VybDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHByb21pc2VzLnB1c2gob25NZXNzYWdlKHJlc3VsdCkpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKHByb21pc2VzKTtcbiAgICAgICAgICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnZlcmJvc2UgJiYgdGhpcy5sb2coYEZpbmFsaXppbmcgcXVldWVgKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zdG9wQ3B1TW9uaXRvcmluZygpO1xuICAgICAgICAgICAgICAgICAgICB0aW1lciAmJiBjbGVhclRpbWVvdXQodGltZXIpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnF1ZXVlLmNsZWFyKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnZlcmJvc2UgJiZcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coYGZhYXN0OiBJbnZva2luZyAnJHtjYWxsLm5hbWV9JywgbWVtb3J5OiAke21lbUluZm99YCk7XG4gICAgICAgICAgICAgICAgY29uc3QgZnVuYyA9IHRoaXMubG9va3VwRnVuY3Rpb24oY2FsbCk7XG4gICAgICAgICAgICAgICAgaWYgKCFmdW5jKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgIGBmYWFzdCBtb2R1bGUgd3JhcHBlcjogY291bGQgbm90IGZpbmQgZnVuY3Rpb24gJyR7Y2FsbC5uYW1lfSdgXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IGFyZ3MgPSBkZXNlcmlhbGl6ZShjYWxsLmFyZ3MpO1xuICAgICAgICAgICAgICAgIGxldCB2YWx1ZTtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IGF3YWl0IGZ1bmMuYXBwbHkodW5kZWZpbmVkLCBhcmdzKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy52ZXJib3NlICYmIHRoaXMubG9nKGBGaW5pc2hlZCBjYWxsIGZ1bmN0aW9uYCk7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coYEZ1bmN0aW9uICR7Y2FsbC5uYW1lfSB0aHJldyBlcnJvcjogJHtlcnJ9YCk7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy52ZXJib3NlICYmXG4gICAgICAgICAgICAgICAgICAgIHRoaXMubG9nKGByZXR1cm5lZCB2YWx1ZTogJHtwKHZhbHVlKX0sIHR5cGU6ICR7dHlwZW9mIHZhbHVlfWApO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgdmFsaWRhdGUgPSB0aGlzLm9wdGlvbnMudmFsaWRhdGVTZXJpYWxpemF0aW9uO1xuICAgICAgICAgICAgICAgIGNvbnN0IGNvbnRleHQgPSB7IHR5cGU6IFwiZnVsZmlsbFwiLCBjYWxsSWQsIC4uLmRldGFpbCB9IGFzIGNvbnN0O1xuICAgICAgICAgICAgICAgIC8vIENoZWNrIGZvciBpdGVyYWJsZS5cblxuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSAhPT0gbnVsbCAmJiB2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpc0dlbmVyYXRvcihmdW5jKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IG5leHQgPSBhd2FpdCB2YWx1ZS5uZXh0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgc2VxdWVuY2UgPSAwO1xuICAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnZlcmJvc2UgJiYgdGhpcy5sb2coYG5leHQ6ICR7cChuZXh0KX1gKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXQgcmVzdWx0OiBJdGVyYXRvclJlc3BvbnNlTWVzc2FnZSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uY29udGV4dCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2luZDogXCJpdGVyYXRvclwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogc2VyaWFsaXplUmV0dXJuVmFsdWUoY2FsbC5uYW1lLCBbbmV4dF0sIHZhbGlkYXRlKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VxdWVuY2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGFzIGNvbnN0O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChuZXh0LmRvbmUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC