faastjs
Version:
Serverless batch computing made simple.
221 lines • 30 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.costSnapshot = exports.localPacker = exports.logUrl = exports.LocalImpl = exports.defaults = exports.defaultGcWorker = void 0;
const sys = 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 = require("./local-trampoline");
const exec = (0, util_1.promisify)(sys.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, memorySize, timeout, env, validateSerialization } = options;
if (!childProcess) {
process.env = { ...process.env, ...env };
}
const { wrapperVerbose } = options.debugOptions;
const getWrapperInfo = () => {
const idleWrapper = wrappers.find(w => w.wrapper.executing === false);
if (idleWrapper) {
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(require(serverModule), wrapperOptions2);
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 } = state.getExecutor();
await wrapper.execute({ call, startTime, logUrl: url }, { onMessage: async (msg) => state.queue.enqueue(msg) });
}
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9jYWwtZmFhc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbG9jYWwvbG9jYWwtZmFhc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUNBQXFDO0FBQ3JDLHVDQVFrQjtBQUNsQiwyQkFBNEI7QUFDNUIsK0JBQTRCO0FBRTVCLCtCQUFpQztBQUNqQyxrQ0FBbUQ7QUFDbkQsZ0NBQTZCO0FBQzdCLHNDQUE2RDtBQUM3RCwwQ0FTcUI7QUFDckIsc0NBQXNEO0FBQ3RELDBDQUF5QztBQUN6Qyx3Q0FBbUU7QUFDbkUsNkRBQTZEO0FBRTdELE1BQU0sSUFBSSxHQUFHLElBQUEsZ0JBQVMsRUFBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7QUFzQ2pDLFNBQWdCLGVBQWUsQ0FBQyxHQUFXO0lBQ3ZDLE9BQU8sSUFBQSxpQkFBTSxFQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQ3ZCLENBQUM7QUFGRCwwQ0FFQztBQUVZLFFBQUEsUUFBUSxHQUEyQjtJQUM1QyxHQUFHLHlCQUFjO0lBQ2pCLFdBQVcsRUFBRSxFQUFFO0lBQ2YsVUFBVSxFQUFFLEdBQUc7SUFDZixTQUFTLEVBQUUsZUFBZTtDQUM3QixDQUFDO0FBRVcsUUFBQSxTQUFTLEdBQTJDO0lBQzdELElBQUksRUFBRSxPQUFPO0lBQ2IsVUFBVTtJQUNWLFFBQVEsRUFBUixnQkFBUTtJQUNSLE9BQU87SUFDUCxZQUFZO0lBQ1osTUFBTTtJQUNOLE1BQU07SUFDTixJQUFJO0lBQ0osZUFBZTtDQUNsQixDQUFDO0FBRUYsS0FBSyxVQUFVLFVBQVUsQ0FDckIsWUFBb0IsRUFDcEIsS0FBVyxFQUNYLE9BQStCO0lBRS9CLE1BQU0sUUFBUSxHQUFlLEVBQUUsQ0FBQztJQUNoQyxNQUFNLEVBQUUsRUFBRSxFQUFFLGVBQWUsRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLEdBQUcsT0FBTyxDQUFDO0lBRTdELElBQUksU0FBUyxDQUFDO0lBQ2QsSUFBSSxFQUFFLEtBQUss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dGVudCI6WyJpbXBvcnQgKiBhcyBzeXMgZnJvbSBcImNoaWxkX3Byb2Nlc3NcIjtcbmltcG9ydCB7XG4gICAgY3JlYXRlV3JpdGVTdHJlYW0sXG4gICAgbWtkaXIsXG4gICAgbWtkaXJwLFxuICAgIHBhdGhFeGlzdHMsXG4gICAgcmVhZGRpcixcbiAgICByZW1vdmUsXG4gICAgc3RhdFxufSBmcm9tIFwiZnMtZXh0cmFcIjtcbmltcG9ydCB7IHRtcGRpciB9IGZyb20gXCJvc1wiO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgeyBXcml0YWJsZSB9IGZyb20gXCJzdHJlYW1cIjtcbmltcG9ydCB7IHByb21pc2lmeSB9IGZyb20gXCJ1dGlsXCI7XG5pbXBvcnQgeyBDb3N0TWV0cmljLCBDb3N0U25hcHNob3QgfSBmcm9tIFwiLi4vY29zdFwiO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSBcIi4uL2xvZ1wiO1xuaW1wb3J0IHsgcGFja2VyLCBQYWNrZXJSZXN1bHQsIHVuemlwSW5EaXIgfSBmcm9tIFwiLi4vcGFja2VyXCI7XG5pbXBvcnQge1xuICAgIENsZWFudXBPcHRpb25zLFxuICAgIGNvbW1vbkRlZmF1bHRzLFxuICAgIENvbW1vbk9wdGlvbnMsXG4gICAgRnVuY3Rpb25TdGF0cyxcbiAgICBNZXNzYWdlLFxuICAgIFBvbGxSZXN1bHQsXG4gICAgUHJvdmlkZXJJbXBsLFxuICAgIFVVSURcbn0gZnJvbSBcIi4uL3Byb3ZpZGVyXCI7XG5pbXBvcnQgeyBoYXNFeHBpcmVkLCB1dWlkdjRQYXR0ZXJuIH0gZnJvbSBcIi4uL3NoYXJlZFwiO1xuaW1wb3J0IHsgQXN5bmNRdWV1ZSB9IGZyb20gXCIuLi90aHJvdHRsZVwiO1xuaW1wb3J0IHsgRnVuY3Rpb25DYWxsLCBXcmFwcGVyLCBXcmFwcGVyT3B0aW9ucyB9IGZyb20gXCIuLi93cmFwcGVyXCI7XG5pbXBvcnQgKiBhcyBsb2NhbFRyYW1wb2xpbmVGYWN0b3J5IGZyb20gXCIuL2xvY2FsLXRyYW1wb2xpbmVcIjtcblxuY29uc3QgZXhlYyA9IHByb21pc2lmeShzeXMuZXhlYyk7XG5cbmludGVyZmFjZSBFeGVjdXRvciB7XG4gICAgd3JhcHBlcjogV3JhcHBlcjtcbiAgICBsb2dVcmw6IHN0cmluZztcbiAgICBsb2dTdHJlYW0/OiBXcml0YWJsZTtcbn1cblxuLyoqXG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTG9jYWxTdGF0ZSB7XG4gICAgLyoqIEBpbnRlcm5hbCAqL1xuICAgIGV4ZWN1dG9yczogRXhlY3V0b3JbXTtcbiAgICAvKiogQGludGVybmFsICovXG4gICAgZ2V0RXhlY3V0b3I6ICgpID0+IEV4ZWN1dG9yO1xuICAgIC8qKiBUaGUgdGVtcG9yYXJ5IGRpcmVjdG9yeSB3aGVyZSB0aGUgbG9jYWwgZnVuY3Rpb24gaXMgZGVwbG95ZWQuICovXG4gICAgdGVtcERpcjogc3RyaW5nO1xuICAgIC8qKiBUaGUgZmlsZTovLyBVUkwgZm9yIHRoZSBsb2NhbCBmdW5jdGlvbiBsb2cgZmlsZSBkaXJlY3RvcnkuICAqL1xuICAgIGxvZ1VybDogc3RyaW5nO1xuICAgIC8qKiBAaW50ZXJuYWwgKi9cbiAgICBnY1Byb21pc2U/OiBQcm9taXNlPHZvaWQ+O1xuICAgIC8qKiBAaW50ZXJuYWwgKi9cbiAgICBxdWV1ZTogQXN5bmNRdWV1ZTxNZXNzYWdlPjtcbiAgICAvKiogT3B0aW9ucyB1c2VkIHRvIGluaXRpYWxpemUgdGhlIGxvY2FsIGZ1bmN0aW9uLiAqL1xuICAgIG9wdGlvbnM6IFJlcXVpcmVkPExvY2FsT3B0aW9ucz47XG59XG5cbi8qKlxuICogTG9jYWwgcHJvdmlkZXIgb3B0aW9ucyBmb3Ige0BsaW5rIGZhYXN0TG9jYWx9LlxuICpcbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMb2NhbE9wdGlvbnMgZXh0ZW5kcyBDb21tb25PcHRpb25zIHtcbiAgICAvKiogQGludGVybmFsICovXG4gICAgX2djV29ya2VyPzogKHRlbXBkaXI6IHN0cmluZykgPT4gUHJvbWlzZTx2b2lkPjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRlZmF1bHRHY1dvcmtlcihkaXI6IHN0cmluZykge1xuICAgIHJldHVybiByZW1vdmUoZGlyKTtcbn1cblxuZXhwb3J0IGNvbnN0IGRlZmF1bHRzOiBSZXF1aXJlZDxMb2NhbE9wdGlvbnM+ID0ge1xuICAgIC4uLmNvbW1vbkRlZmF1bHRzLFxuICAgIGNvbmN1cnJlbmN5OiAxMCxcbiAgICBtZW1vcnlTaXplOiA1MTIsXG4gICAgX2djV29ya2VyOiBkZWZhdWx0R2NXb3JrZXJcbn07XG5cbmV4cG9ydCBjb25zdCBMb2NhbEltcGw6IFByb3ZpZGVySW1wbDxMb2NhbE9wdGlvbnMsIExvY2FsU3RhdGU+ID0ge1xuICAgIG5hbWU6IFwibG9jYWxcIixcbiAgICBpbml0aWFsaXplLFxuICAgIGRlZmF1bHRzLFxuICAgIGNsZWFudXAsXG4gICAgY29zdFNuYXBzaG90LFxuICAgIGxvZ1VybCxcbiAgICBpbnZva2UsXG4gICAgcG9sbCxcbiAgICByZXNwb25zZVF1ZXVlSWRcbn07XG5cbmFzeW5jIGZ1bmN0aW9uIGluaXRpYWxpemUoXG4gICAgc2VydmVyTW9kdWxlOiBzdHJpbmcsXG4gICAgbm9uY2U6IFVVSUQsXG4gICAgb3B0aW9uczogUmVxdWlyZWQ8TG9jYWxPcHRpb25zPlxuKTogUHJvbWlzZTxMb2NhbFN0YXRlPiB7XG4gICAgY29uc3Qgd3JhcHBlcnM6IEV4ZWN1dG9yW10gPSBbXTtcbiAgICBjb25zdCB7IGdjLCByZXRlbnRpb25JbkRheXMsIF9nY1dvcmtlcjogZ2NXb3JrZXIgfSA9IG9wdGlvbnM7XG5cbiAgICBsZXQgZ2NQcm9taXNlO1xuICAgIGlmIChnYyA9PT0gXCJhdXRvXCIgfHwgZ2MgPT09IFwiZm9yY2VcIikge1xuICAgICAgICBnY1Byb21pc2UgPSBjb2xsZWN0R2FyYmFnZShnY1dvcmtlciwgcmV0ZW50aW9uSW5EYXlzISk7XG4gICAgfVxuICAgIGNvbnN0IHRlbXBEaXIgPSBqb2luKHRtcGRpcigpLCBcImZhYXN0XCIsIG5vbmNlKTtcbiAgICBsb2cuaW5mbyhgdGVtcERpcjogJHt0ZW1wRGlyfSBbJHtvcHRpb25zLmRlc2NyaXB0aW9ufV1gKTtcbiAgICBhd2FpdCBta2RpcnAodGVtcERpcik7XG4gICAgY29uc3QgbG9nRGlyID0gam9pbih0ZW1wRGlyLCBcImxvZ3NcIik7XG4gICAgYXdhaXQgbWtkaXIobG9nRGlyKTtcbiAgICBjb25zdCB1cmwgPSBgZmlsZTovLyR7bG9nRGlyfWA7XG5cbiAgICBsb2cuaW5mbyhgbG9nVVJMOiAke3VybH1gKTtcblxuICAgIGNvbnN0IHsgY2hpbGRQcm9jZXNzLCBtZW1vcnlTaXplLCB0aW1lb3V0LCBlbnYsIHZhbGlkYXRlU2VyaWFsaXphdGlvbiB9ID0gb3B0aW9ucztcblxuICAgIGlmICghY2hpbGRQcm9jZXNzKSB7XG4gICAgICAgIHByb2Nlc3MuZW52ID0geyAuLi5wcm9jZXNzLmVudiwgLi4uZW52IH07XG4gICAgfVxuICAgIGNvbnN0IHsgd3JhcHBlclZlcmJvc2UgfSA9IG9wdGlvbnMuZGVidWdPcHRpb25zO1xuICAgIGNvbnN0IGdldFdyYXBwZXJJbmZvID0gKCkgPT4ge1xuICAgICAgICBjb25zdCBpZGxlV3JhcHBlciA9IHdyYXBwZXJzLmZpbmQodyA9PiB3LndyYXBwZXIuZXhlY3V0aW5nID09PSBmYWxzZSk7XG4gICAgICAgIGlmIChpZGxlV3JhcHBlcikge1xuICAgICAgICAgICAgcmV0dXJuIGlkbGVXcmFwcGVyO1xuICAgICAgICB9XG4gICAgICAgIGxldCBsb2dTdHJlYW0hOiBXcml0YWJsZTtcbiAgICAgICAgbGV0IGNoaWxkbG9nID0gKG1zZzogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICBpZiAobG9nU3RyZWFtLndyaXRhYmxlKSB7XG4gICAgICAgICAgICAgICAgbG9nU3RyZWFtLndyaXRlKG1zZyk7XG4gICAgICAgICAgICAgICAgbG9nU3RyZWFtLndyaXRlKFwiXFxuXCIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBsb2cucHJvdmlkZXIoYFdBUk5JTkc6IGNoaWxkbG9nIG5vdCB3cml0YWJsZTogJHttc2d9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IGxvZ0ZpbGUgPSBqb2luKGxvZ0RpciwgYCR7d3JhcHBlcnMubGVuZ3RofS5sb2dgKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgbG9nLmluZm8oYENyZWF0aW5nIHdyaXRlIHN0cmVhbSAke2xvZ0ZpbGV9YCk7XG4gICAgICAgICAgICBsb2dTdHJlYW0gPSBjcmVhdGVXcml0ZVN0cmVhbShsb2dGaWxlKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICAgIGxvZy53YXJuKGBFUlJPUjogQ291bGQgbm90IGNyZWF0ZSBsb2dgKTtcbiAgICAgICAgICAgIGxvZy53YXJuKGVycik7XG4gICAgICAgICAgICBjaGlsZGxvZyA9IGNvbnNvbGUubG9nO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGNoaWxkUHJvY2Vzc01lbW9yeUxpbWl0TWIgPSBvcHRpb25zLmNoaWxkUHJvY2Vzc01lbW9yeU1iO1xuICAgICAgICBjb25zdCB3cmFwcGVyT3B0aW9uczI6IFJlcXVpcmVkPFdyYXBwZXJPcHRpb25zPiA9IHtcbiAgICAgICAgICAgIHdyYXBwZXJMb2c6IGNoaWxkbG9nLFxuICAgICAgICAgICAgY2hpbGRQcm9jZXNzLFxuICAgICAgICAgICAgY2hpbGRQcm9jZXNzTWVtb3J5TGltaXRNYixcbiAgICAgICAgICAgIGNoaWxkUHJvY2Vzc1RpbWVvdXRNczogdGltZW91dCAqIDEwMDAgLSAoY2hpbGRQcm9jZXNzID8gNTAgOiAwKSxcbiAgICAgICAgICAgIGNoaWxkUHJvY2Vzc0Vudmlyb25tZW50OiBlbnYsXG4gICAgICAgICAgICBjaGlsZERpcjogdGVtcERpcixcbiAgICAgICAgICAgIHdyYXBwZXJWZXJib3NlOiB3cmFwcGVyVmVyYm9zZSB8fCBsb2cucHJvdmlkZXIuZW5hYmxlZCxcbiAgICAgICAgICAgIHZhbGlkYXRlU2VyaWFsaXphdGlvblxuICAgICAgICB9O1xuICAgICAgICBjb25zdCB3cmFwcGVyID0gbmV3IFdyYXBwZXIocmVxdWlyZShzZXJ2ZXJNb2R1bGUpLCB3cmFwcGVyT3B0aW9uczIpO1xuICAgICAgICBjb25zdCBydiA9IHsgd3JhcHBlciwgbG9nVXJsOiBgZmlsZTovLyR7bG9nRmlsZX1gLCBsb2dTdHJlYW0gfTtcbiAgICAgICAgd3JhcHBlcnMucHVzaChydik7XG4gICAgICAgIHJldHVybiBydjtcbiAgICB9O1xuXG4gICAgY29uc3QgcGFja2VyUmVzdWx0ID0gYXdhaXQgbG9jYWxQYWNrZXIoXG4gICAgICAgIHNlcnZlck1vZHVsZSxcbiAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgeyB3cmFwcGVyVmVyYm9zZSB9LFxuICAgICAgICBgZmFhc3QtJHtub25jZX1gXG4gICAgKTtcblxuICAgIGF3YWl0IHVuemlwSW5EaXIodGVtcERpciwgcGFja2VyUmVzdWx0LmFyY2hpdmUpO1xuICAgIGlmIChvcHRpb25zLnBhY2thZ2VKc29uKSB7XG4gICAgICAgIGxvZy5pbmZvKGBSdW5uaW5nICducG0gaW5zdGFsbCdgKTtcblxuICAgICAgICBhd2FpdCBleGVjKFwibnBtIGluc3RhbGwgLS1uby1wYWNrYWdlLWxvY2tcIiwgeyBjd2Q6IHRlbXBEaXIgfSkudGhlbih4ID0+IHtcbiAgICAgICAgICAgIGxvZy5pbmZvKHguc3Rkb3V0KTtcbiAgICAgICAgICAgIGlmICh4LnN0ZGVycikge1xuICAgICAgICAgICAgICAgIGxvZy53YXJuKHguc3RkZXJyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgZXhlY3V0b3JzOiB3cmFwcGVycyxcbiAgICAgICAgZ2V0RXhlY3V0b3I6IGdldFdyYXBwZXJJbmZvLFxuICAgICAgICB0ZW1wRGlyLFxuICAgICAgICBsb2dVcmw6IHVybCxcbiAgICAgICAgZ2NQcm9taXNlLFxuICAgICAgICBxdWV1ZTogbmV3IEFzeW5jUXVldWUoKSxcbiAgICAgICAgb3B0aW9uc1xuICAgIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBsb2dVcmwoc3RhdGU6IExvY2FsU3RhdGUpIHtcbiAgICByZXR1cm4gc3RhdGUubG9nVXJsO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbG9jYWxQYWNrZXIoXG4gICAgZnVuY3Rpb25Nb2R1bGU6IHN0cmluZyxcbiAgICBvcHRpb25zOiBDb21tb25PcHRpb25zLFxuICAgIHdyYXBwZXJPcHRpb25zOiBXcmFwcGVyT3B0aW9ucyxcbiAgICBGdW5jdGlvbk5hbWU6IHN0cmluZ1xuKTogUHJvbWlzZTxQYWNrZXJSZXN1bHQ+IHtcbiAgICByZXR1cm4gcGFja2VyKFxuICAgICAgICBsb2NhbFRyYW1wb2xpbmVGYWN0b3J5LFxuICAgICAgICBmdW5jdGlvbk1vZHVsZSxcbiAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgd3JhcHBlck9wdGlvbnMsXG4gICAgICAgIEZ1bmN0aW9uTmFtZVxuICAgICk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGludm9rZShcbiAgICBzdGF0ZTogTG9jYWxTdGF0ZSxcbiAgICBjYWxsOiBGdW5jdGlvbkNhbGwsXG4gICAgXzogUHJvbWlzZTx2b2lkPlxuKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3Qge30gPSBzdGF0ZTtcbiAgICBjb25zdCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICAgIGNvbnN0IHsgd3JhcHBlciwgbG9nVXJsOiB1cmwgfSA9IHN0YXRlLmdldEV4ZWN1dG9yKCk7XG4gICAgYXdhaXQgd3JhcHBlci5leGVjdXRlKFxuICAgICAgICB7IGNhbGwsIHN0YXJ0VGltZSwgbG9nVXJsOiB1cmwgfSxcbiAgICAgICAgeyBvbk1lc3NhZ2U6IGFzeW5jIG1zZyA9PiBzdGF0ZS5xdWV1ZS5lbnF1ZXVlKG1zZykgfVxuICAgICk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHBvbGwoc3RhdGU6IExvY2FsU3RhdGUsIGNhbmNlbDogUHJvbWlzZTx2b2lkPik6IFByb21pc2U8UG9sbFJlc3VsdD4ge1xuICAgIGNvbnN0IG1lc3NhZ2UgPSBhd2FpdCBQcm9taXNlLnJhY2UoW3N0YXRlLnF1ZXVlLm5leHQoKSwgY2FuY2VsXSk7XG4gICAgaWYgKCFtZXNzYWdlKSB7XG4gICAgICAgIHJldHVybiB7IE1lc3NhZ2VzOiBbXSB9O1xuICAgIH1cbiAgICByZXR1cm4geyBNZXNzYWdlczogW21lc3NhZ2VdIH07XG59XG5cbmZ1bmN0aW9uIHJlc3BvbnNlUXVldWVJZChfc3RhdGU6IExvY2FsU3RhdGUpOiBzdHJpbmcge1xuICAgIHJldHVybiBcIjxub25lPlwiO1xufVxuXG5hc3luYyBmdW5jdGlvbiBjbGVhbnVwKHN0YXRlOiBMb2NhbFN0YXRlLCBvcHRpb25zOiBDbGVhbnVwT3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGxvZy5pbmZvKGBsb2NhbCBjbGVhbnVwIHN0YXJ0aW5nLmApO1xuXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoc3RhdGUuZXhlY3V0b3JzLm1hcChlID0+IGUud3JhcHBlci5zdG9wKCkpKTtcbiAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgc3RhdGUuZXhlY3V0b3JzLm1hcChlID0+IG5ldyBQcm9taXNlKHJlc29sdmUgPT4gZS5sb2dTdHJlYW0/LmVuZChyZXNvbHZlKSkpXG4gICAgKTtcbiAgICBzdGF0ZS5leGVjdXRvcnMgPSBbXTtcbiAgICBpZiAoc3RhdGUuZ2NQcm9taXNlKSB7XG4gICAgICAgIGF3YWl0IHN0YXRlLmdjUHJvbWlzZTtcbiAgICB9XG5cbiAgICBpZiAob3B0aW9ucy5kZWxldGVSZXNvdXJjZXMpIHtcbiAgICAgICAgY29uc3QgeyB0ZW1wRGlyIH0gPSBzdGF0ZTtcbiAgICAgICAgY29uc3QgcGF0dGVybiA9IG5ldyBSZWdFeHAoYC9mYWFzdC8ke3V1aWR2NFBhdHRlcm59JGApO1xuICAgICAgICBpZiAodGVtcERpci5tYXRjaChwYXR0ZXJuKSAmJiAoYXdhaXQgcGF0aEV4aXN0cyh0ZW1wRGlyKSkpIHtcbiAgICAgICAgICAgIGxvZy5pbmZvKGBEZWxldGluZyB0ZW1wIGRpciAke3RlbXBEaXJ9YCk7XG4gICAgICAgICAgICBhd2FpdCByZW1vdmUodGVtcERpcik7XG4gICAgICAgIH1cbiAgICB9XG4gICAgbG9nLmluZm8oYGxvY2FsIGNsZWFudXAgZG9uZS5gKTtcbn1cblxubGV0IGdhcmJhZ2VDb2xsZWN0b3JSdW5uaW5nID0gZmFsc2U7XG5cbmFzeW5jIGZ1bmN0aW9uIGNvbGxlY3RHYXJiYWdlKFxuICAgIGdjV29ya2VyOiAoZGlyOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD4sXG4gICAgcmV0ZW50aW9uSW5EYXlzOiBudW1iZXJcbikge1xuICAgIGlmIChnY1dvcmtlciA9PT0gZGVmYXVsdEdjV29ya2VyKSB7XG4gICAgICAgIGlmIChnYXJiYWdlQ29sbGVjdG9yUnVubmluZykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGdhcmJhZ2VDb2xsZWN0b3JSdW5uaW5nID0gdHJ1ZTtcbiAgICB9XG4gICAgY29uc3QgdG1wID0gam9pbih0bXBkaXIoKSwgXCJmYWFzdFwiKTtcbiAgICBsb2cuZ2ModG1wKTtcbiAgICB0cnkge1xuICAgICAgICBjb25zdCBkaXIgPSBhd2FpdCByZWFkZGlyKHRtcCk7XG4gICAgICAgIGNvbnN0IHBhdHRlcm4gPSBuZXcgUmVnRXhwKGBeJHt1dWlkdjRQYXR0ZXJufSRgKTtcbiAgICAgICAgZm9yIChjb25zdCBlbnRyeSBvZiBkaXIpIHtcbiAgICAgICAgICAgIGlmIChlbnRyeS5tYXRjaChwYXR0ZXJuKSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGZhYXN0RGlyID0gam9pbih0bXAsIGVudHJ5KTtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBzdGF0cyA9IGF3YWl0IHN0YXQoZmFhc3REaXIpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoaGFzRXhwaXJlZChzdGF0cy5hdGltZU1zLCByZXRlbnRpb25JbkRheXMpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBsb2cuZ2MoZmFhc3REaXIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgZ2NXb3JrZXIoZmFhc3REaXIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHt9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICBsb2cuZ2MoZXJyKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgICBpZiAoZ2NXb3JrZXIgPT09IGRlZmF1bHRHY1dvcmtlcikge1xuICAgICAgICAgICAgZ2FyYmFnZUNvbGxlY3RvclJ1bm5pbmcgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNvc3RTbmFwc2hvdChzdGF0ZTogTG9jYWxTdGF0ZSwgc3RhdHM6IEZ1bmN0aW9uU3RhdHMpIHtcbiAgICBjb25zdCBiaWxsZWRUaW1lU3RhdHMgPSBzdGF0cy5lc3RpbWF0ZWRCaWxsZWRUaW1lO1xuICAgIGNvbnN0IHNlY29uZHMgPSAoYmlsbGVkVGltZVN0YXRzLm1lYW4gLyAxMDAwKSAqIGJpbGxlZFRpbWVTdGF0cy5zYW1wbGVzIHx8IDA7XG5cbiAgICBjb25zdCBjb3N0TWV0cmljczogQ29zdE1ldHJpY1tdID0gW107XG4gICAgY29uc3QgZnVuY3Rpb25DYWxsRHVyYXRpb24gPSBuZXcgQ29zdE1ldHJpYyh7XG4gICAgICAgIG5hbWU6IFwiZnVuY3Rpb25DYWxsRHVyYXRpb25cIixcbiAgICAgICAgcHJpY2luZzogMCxcbiAgICAgICAgdW5pdDogXCJzZWNvbmRcIixcbiAgICAgICAgbWVhc3VyZWQ6IHNlY29uZHMsXG4gICAgICAgIGluZm9ybWF0aW9uYWxPbmx5OiB0cnVlXG4gICAgfSk7XG4gICAgY29zdE1ldHJpY3MucHVzaChmdW5jdGlvbkNhbGxEdXJhdGlvbik7XG5cbiAgICBjb25zdCBmdW5jdGlvbkNhbGxSZXF1ZXN0cyA9IG5ldyBDb3N0TWV0cmljKHtcbiAgICAgICAgbmFtZTogXCJmdW5jdGlvbkNhbGxSZXF1ZXN0c1wiLFxuICAgICAgICBwcmljaW5nOiAwLFxuICAgICAgICBtZWFzdXJlZDogc3RhdHMuaW52b2NhdGlvbnMsXG4gICAgICAgIHVuaXQ6IFwicmVxdWVzdFwiLFxuICAgICAgICBpbmZvcm1hdGlvbmFsT25seTogdHJ1ZVxuICAgIH0pO1xuICAgIGNvc3RNZXRyaWNzLnB1c2goZnVuY3Rpb25DYWxsUmVxdWVzdHMpO1xuICAgIHJldHVybiBuZXcgQ29zdFNuYXBzaG90KFwibG9jYWxcIiwgc3RhdGUub3B0aW9ucywgc3RhdHMsIGNvc3RNZXRyaWNzKTtcbn1cbiJdfQ==