faastjs
Version:
Serverless batch computing made simple.
226 lines • 30.7 kB
JavaScript
;
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=