faastjs
Version:
Serverless batch computing made simple.
371 lines • 57.4 kB
JavaScript
"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