faastjs
Version:
Serverless batch computing made simple.
226 lines • 31 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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aUIsRUFBRSxJQUFJO0tBQzFCLENBQUMsQ0FBQztJQUNILFdBQVcsQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsQ0FBQztJQUV2QyxNQUFNLG9CQUFvQixHQUFHLElBQUksaUJBQVUsQ0FBQztRQUN4QyxJQUFJLEVBQUUsc0JBQXNCO1FBQzVCLE9BQU8sRUFBRSxDQUFDO1FBQ1YsUUFBUSxFQUFFLEtBQUssQ0FBQyxXQUFXO1FBQzNCLElBQUksRUFBRSxTQUFTO1FBQ2YsaUJBQWlCLEVBQUUsSUFBSTtLQUMxQixDQUFDLENBQUM7SUFDSCxXQUFXLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUM7SUFDdkMsT0FBTyxJQUFJLG1CQUFZLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPLEVBQUUsS0FBSyxFQUFFLFdBQVcsQ0FBQyxDQUFDO0FBQ3hFLENBQUM7QUF2QkQsb0NBdUJDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHN5cyBmcm9tIFwiY2hpbGRfcHJvY2Vzc1wiO1xuaW1wb3J0IHtcbiAgICBjcmVhdGVXcml0ZVN0cmVhbSxcbiAgICBta2RpcixcbiAgICBta2RpcnAsXG4gICAgcGF0aEV4aXN0cyxcbiAgICByZWFkZGlyLFxuICAgIHJlbW92ZSxcbiAgICBzdGF0XG59IGZyb20gXCJmcy1leHRyYVwiO1xuaW1wb3J0IHsgdG1wZGlyIH0gZnJvbSBcIm9zXCI7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IFdyaXRhYmxlIH0gZnJvbSBcInN0cmVhbVwiO1xuaW1wb3J0IHsgcHJvbWlzaWZ5IH0gZnJvbSBcInV0aWxcIjtcbmltcG9ydCB7IENvc3RNZXRyaWMsIENvc3RTbmFwc2hvdCB9IGZyb20gXCIuLi9jb3N0XCI7XG5pbXBvcnQgeyBsb2cgfSBmcm9tIFwiLi4vbG9nXCI7XG5pbXBvcnQgeyBwYWNrZXIsIFBhY2tlclJlc3VsdCwgdW56aXBJbkRpciB9IGZyb20gXCIuLi9wYWNrZXJcIjtcbmltcG9ydCB7XG4gICAgQ2xlYW51cE9wdGlvbnMsXG4gICAgY29tbW9uRGVmYXVsdHMsXG4gICAgQ29tbW9uT3B0aW9ucyxcbiAgICBGdW5jdGlvblN0YXRzLFxuICAgIE1lc3NhZ2UsXG4gICAgUG9sbFJlc3VsdCxcbiAgICBQcm92aWRlckltcGwsXG4gICAgVVVJRFxufSBmcm9tIFwiLi4vcHJvdmlkZXJcIjtcbmltcG9ydCB7IGhhc0V4cGlyZWQsIHV1aWR2NFBhdHRlcm4gfSBmcm9tIFwiLi4vc2hhcmVkXCI7XG5pbXBvcnQgeyBBc3luY1F1ZXVlIH0gZnJvbSBcIi4uL3Rocm90dGxlXCI7XG5pbXBvcnQgeyBGdW5jdGlvbkNhbGwsIFdyYXBwZXIsIFdyYXBwZXJPcHRpb25zIH0gZnJvbSBcIi4uL3dyYXBwZXJcIjtcbmltcG9ydCAqIGFzIGxvY2FsVHJhbXBvbGluZUZhY3RvcnkgZnJvbSBcIi4vbG9jYWwtdHJhbXBvbGluZVwiO1xuXG5jb25zdCBleGVjID0gcHJvbWlzaWZ5KHN5cy5leGVjKTtcblxuaW50ZXJmYWNlIEV4ZWN1dG9yIHtcbiAgICB3cmFwcGVyOiBXcmFwcGVyO1xuICAgIGxvZ1VybDogc3RyaW5nO1xuICAgIGxvZ1N0cmVhbT86IFdyaXRhYmxlO1xufVxuXG4vKipcbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMb2NhbFN0YXRlIHtcbiAgICAvKiogQGludGVybmFsICovXG4gICAgZXhlY3V0b3JzOiBFeGVjdXRvcltdO1xuICAgIC8qKiBAaW50ZXJuYWwgKi9cbiAgICBnZXRFeGVjdXRvcjogKCkgPT4gUHJvbWlzZTxFeGVjdXRvcj47XG4gICAgLyoqIFRoZSB0ZW1wb3JhcnkgZGlyZWN0b3J5IHdoZXJlIHRoZSBsb2NhbCBmdW5jdGlvbiBpcyBkZXBsb3llZC4gKi9cbiAgICB0ZW1wRGlyOiBzdHJpbmc7XG4gICAgLyoqIFRoZSBmaWxlOi8vIFVSTCBmb3IgdGhlIGxvY2FsIGZ1bmN0aW9uIGxvZyBmaWxlIGRpcmVjdG9yeS4gICovXG4gICAgbG9nVXJsOiBzdHJpbmc7XG4gICAgLyoqIEBpbnRlcm5hbCAqL1xuICAgIGdjUHJvbWlzZT86IFByb21pc2U8dm9pZD47XG4gICAgLyoqIEBpbnRlcm5hbCAqL1xuICAgIHF1ZXVlOiBBc3luY1F1ZXVlPE1lc3NhZ2U+O1xuICAgIC8qKiBPcHRpb25zIHVzZWQgdG8gaW5pdGlhbGl6ZSB0aGUgbG9jYWwgZnVuY3Rpb24uICovXG4gICAgb3B0aW9uczogUmVxdWlyZWQ8TG9jYWxPcHRpb25zPjtcbn1cblxuLyoqXG4gKiBMb2NhbCBwcm92aWRlciBvcHRpb25zIGZvciB7QGxpbmsgZmFhc3RMb2NhbH0uXG4gKlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgaW50ZXJmYWNlIExvY2FsT3B0aW9ucyBleHRlbmRzIENvbW1vbk9wdGlvbnMge1xuICAgIC8qKiBAaW50ZXJuYWwgKi9cbiAgICBfZ2NXb3JrZXI/OiAodGVtcGRpcjogc3RyaW5nKSA9PiBQcm9taXNlPHZvaWQ+O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZGVmYXVsdEdjV29ya2VyKGRpcjogc3RyaW5nKSB7XG4gICAgcmV0dXJuIHJlbW92ZShkaXIpO1xufVxuXG5leHBvcnQgY29uc3QgZGVmYXVsdHM6IFJlcXVpcmVkPExvY2FsT3B0aW9ucz4gPSB7XG4gICAgLi4uY29tbW9uRGVmYXVsdHMsXG4gICAgY29uY3VycmVuY3k6IDEwLFxuICAgIG1lbW9yeVNpemU6IDUxMixcbiAgICBfZ2NXb3JrZXI6IGRlZmF1bHRHY1dvcmtlclxufTtcblxuZXhwb3J0IGNvbnN0IExvY2FsSW1wbDogUHJvdmlkZXJJbXBsPExvY2FsT3B0aW9ucywgTG9jYWxTdGF0ZT4gPSB7XG4gICAgbmFtZTogXCJsb2NhbFwiLFxuICAgIGluaXRpYWxpemUsXG4gICAgZGVmYXVsdHMsXG4gICAgY2xlYW51cCxcbiAgICBjb3N0U25hcHNob3QsXG4gICAgbG9nVXJsLFxuICAgIGludm9rZSxcbiAgICBwb2xsLFxuICAgIHJlc3BvbnNlUXVldWVJZFxufTtcblxuYXN5bmMgZnVuY3Rpb24gaW5pdGlhbGl6ZShcbiAgICBzZXJ2ZXJNb2R1bGU6IHN0cmluZyxcbiAgICBub25jZTogVVVJRCxcbiAgICBvcHRpb25zOiBSZXF1aXJlZDxMb2NhbE9wdGlvbnM+XG4pOiBQcm9taXNlPExvY2FsU3RhdGU+IHtcbiAgICBjb25zdCB3cmFwcGVyczogRXhlY3V0b3JbXSA9IFtdO1xuICAgIGNvbnN0IHsgZ2MsIHJldGVudGlvbkluRGF5cywgX2djV29ya2VyOiBnY1dvcmtlciB9ID0gb3B0aW9ucztcblxuICAgIGxldCBnY1Byb21pc2U7XG4gICAgaWYgKGdjID09PSBcImF1dG9cIiB8fCBnYyA9PT0gXCJmb3JjZVwiKSB7XG4gICAgICAgIGdjUHJvbWlzZSA9IGNvbGxlY3RHYXJiYWdlKGdjV29ya2VyLCByZXRlbnRpb25JbkRheXMhKTtcbiAgICB9XG4gICAgY29uc3QgdGVtcERpciA9IGpvaW4odG1wZGlyKCksIFwiZmFhc3RcIiwgbm9uY2UpO1xuICAgIGxvZy5pbmZvKGB0ZW1wRGlyOiAke3RlbXBEaXJ9IFske29wdGlvbnMuZGVzY3JpcHRpb259XWApO1xuICAgIGF3YWl0IG1rZGlycCh0ZW1wRGlyKTtcbiAgICBjb25zdCBsb2dEaXIgPSBqb2luKHRlbXBEaXIsIFwibG9nc1wiKTtcbiAgICBhd2FpdCBta2Rpcihsb2dEaXIpO1xuICAgIGNvbnN0IHVybCA9IGBmaWxlOi8vJHtsb2dEaXJ9YDtcblxuICAgIGxvZy5pbmZvKGBsb2dVUkw6ICR7dXJsfWApO1xuXG4gICAgY29uc3QgeyBjaGlsZFByb2Nlc3MsIHRpbWVvdXQsIGVudiwgdmFsaWRhdGVTZXJpYWxpemF0aW9uIH0gPSBvcHRpb25zO1xuXG4gICAgaWYgKCFjaGlsZFByb2Nlc3MpIHtcbiAgICAgICAgcHJvY2Vzcy5lbnYgPSB7IC4uLnByb2Nlc3MuZW52LCAuLi5lbnYgfTtcbiAgICB9XG4gICAgY29uc3QgeyB3cmFwcGVyVmVyYm9zZSB9ID0gb3B0aW9ucy5kZWJ1Z09wdGlvbnM7XG4gICAgY29uc3QgZ2V0V3JhcHBlckluZm8gPSBhc3luYyAoKSA9PiB7XG4gICAgICAgIGNvbnN0IGlkbGVXcmFwcGVyID0gd3JhcHBlcnMuZmluZCh3ID0+IHcud3JhcHBlci5zZWxlY3RlZCA9PT0gZmFsc2UpO1xuICAgICAgICBpZiAoaWRsZVdyYXBwZXIpIHtcbiAgICAgICAgICAgIGlkbGVXcmFwcGVyLndyYXBwZXIuc2VsZWN0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgcmV0dXJuIGlkbGVXcmFwcGVyO1xuICAgICAgICB9XG4gICAgICAgIGxldCBsb2dTdHJlYW0hOiBXcml0YWJsZTtcbiAgICAgICAgbGV0IGNoaWxkbG9nID0gKG1zZzogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICBpZiAobG9nU3RyZWFtLndyaXRhYmxlKSB7XG4gICAgICAgICAgICAgICAgbG9nU3RyZWFtLndyaXRlKG1zZyk7XG4gICAgICAgICAgICAgICAgbG9nU3RyZWFtLndyaXRlKFwiXFxuXCIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBsb2cucHJvdmlkZXIoYFdBUk5JTkc6IGNoaWxkbG9nIG5vdCB3cml0YWJsZTogJHttc2d9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IGxvZ0ZpbGUgPSBqb2luKGxvZ0RpciwgYCR7d3JhcHBlcnMubGVuZ3RofS5sb2dgKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgbG9nLmluZm8oYENyZWF0aW5nIHdyaXRlIHN0cmVhbSAke2xvZ0ZpbGV9YCk7XG4gICAgICAgICAgICBsb2dTdHJlYW0gPSBjcmVhdGVXcml0ZVN0cmVhbShsb2dGaWxlKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICAgIGxvZy53YXJuKGBFUlJPUjogQ291bGQgbm90IGNyZWF0ZSBsb2dgKTtcbiAgICAgICAgICAgIGxvZy53YXJuKGVycik7XG4gICAgICAgICAgICBjaGlsZGxvZyA9IGNvbnNvbGUubG9nO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGNoaWxkUHJvY2Vzc01lbW9yeUxpbWl0TWIgPSBvcHRpb25zLmNoaWxkUHJvY2Vzc01lbW9yeU1iO1xuICAgICAgICBjb25zdCB3cmFwcGVyT3B0aW9uczI6IFJlcXVpcmVkPFdyYXBwZXJPcHRpb25zPiA9IHtcbiAgICAgICAgICAgIHdyYXBwZXJMb2c6IGNoaWxkbG9nLFxuICAgICAgICAgICAgY2hpbGRQcm9jZXNzLFxuICAgICAgICAgICAgY2hpbGRQcm9jZXNzTWVtb3J5TGltaXRNYixcbiAgICAgICAgICAgIGNoaWxkUHJvY2Vzc1RpbWVvdXRNczogdGltZW91dCAqIDEwMDAgLSAoY2hpbGRQcm9jZXNzID8gNTAgOiAwKSxcbiAgICAgICAgICAgIGNoaWxkUHJvY2Vzc0Vudmlyb25tZW50OiBlbnYsXG4gICAgICAgICAgICBjaGlsZERpcjogdGVtcERpcixcbiAgICAgICAgICAgIHdyYXBwZXJWZXJib3NlOiB3cmFwcGVyVmVyYm9zZSB8fCBsb2cucHJvdmlkZXIuZW5hYmxlZCxcbiAgICAgICAgICAgIHZhbGlkYXRlU2VyaWFsaXphdGlvblxuICAgICAgICB9O1xuICAgICAgICBjb25zdCB3cmFwcGVyID0gbmV3IFdyYXBwZXIoYXdhaXQgaW1wb3J0KHNlcnZlck1vZHVsZSksIHdyYXBwZXJPcHRpb25zMik7XG4gICAgICAgIHdyYXBwZXIuc2VsZWN0ZWQgPSB0cnVlO1xuICAgICAgICBjb25zdCBydiA9IHsgd3JhcHBlciwgbG9nVXJsOiBgZmlsZTovLyR7bG9nRmlsZX1gLCBsb2dTdHJlYW0gfTtcbiAgICAgICAgd3JhcHBlcnMucHVzaChydik7XG4gICAgICAgIHJldHVybiBydjtcbiAgICB9O1xuXG4gICAgY29uc3QgcGFja2VyUmVzdWx0ID0gYXdhaXQgbG9jYWxQYWNrZXIoXG4gICAgICAgIHNlcnZlck1vZHVsZSxcbiAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgeyB3cmFwcGVyVmVyYm9zZSB9LFxuICAgICAgICBgZmFhc3QtJHtub25jZX1gXG4gICAgKTtcblxuICAgIGF3YWl0IHVuemlwSW5EaXIodGVtcERpciwgcGFja2VyUmVzdWx0LmFyY2hpdmUpO1xuICAgIGlmIChvcHRpb25zLnBhY2thZ2VKc29uKSB7XG4gICAgICAgIGxvZy5pbmZvKGBSdW5uaW5nICducG0gaW5zdGFsbCdgKTtcblxuICAgICAgICBhd2FpdCBleGVjKFwibnBtIGluc3RhbGwgLS1uby1wYWNrYWdlLWxvY2tcIiwgeyBjd2Q6IHRlbXBEaXIgfSkudGhlbih4ID0+IHtcbiAgICAgICAgICAgIGxvZy5pbmZvKHguc3Rkb3V0KTtcbiAgICAgICAgICAgIGlmICh4LnN0ZGVycikge1xuICAgICAgICAgICAgICAgIGxvZy53YXJuKHguc3RkZXJyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgZXhlY3V0b3JzOiB3cmFwcGVycyxcbiAgICAgICAgZ2V0RXhlY3V0b3I6IGdldFdyYXBwZXJJbmZvLFxuICAgICAgICB0ZW1wRGlyLFxuICAgICAgICBsb2dVcmw6IHVybCxcbiAgICAgICAgZ2NQcm9taXNlLFxuICAgICAgICBxdWV1ZTogbmV3IEFzeW5jUXVldWUoKSxcbiAgICAgICAgb3B0aW9uc1xuICAgIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBsb2dVcmwoc3RhdGU6IExvY2FsU3RhdGUpIHtcbiAgICByZXR1cm4gc3RhdGUubG9nVXJsO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbG9jYWxQYWNrZXIoXG4gICAgZnVuY3Rpb25Nb2R1bGU6IHN0cmluZyxcbiAgICBvcHRpb25zOiBDb21tb25PcHRpb25zLFxuICAgIHdyYXBwZXJPcHRpb25zOiBXcmFwcGVyT3B0aW9ucyxcbiAgICBGdW5jdGlvbk5hbWU6IHN0cmluZ1xuKTogUHJvbWlzZTxQYWNrZXJSZXN1bHQ+IHtcbiAgICByZXR1cm4gcGFja2VyKFxuICAgICAgICBsb2NhbFRyYW1wb2xpbmVGYWN0b3J5LFxuICAgICAgICBmdW5jdGlvbk1vZHVsZSxcbiAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgd3JhcHBlck9wdGlvbnMsXG4gICAgICAgIEZ1bmN0aW9uTmFtZVxuICAgICk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGludm9rZShcbiAgICBzdGF0ZTogTG9jYWxTdGF0ZSxcbiAgICBjYWxsOiBGdW5jdGlvbkNhbGwsXG4gICAgXzogUHJvbWlzZTx2b2lkPlxuKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3Qge30gPSBzdGF0ZTtcbiAgICBjb25zdCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICAgIGNvbnN0IHsgd3JhcHBlciwgbG9nVXJsOiB1cmwgfSA9IGF3YWl0IHN0YXRlLmdldEV4ZWN1dG9yKCk7XG4gICAgYXdhaXQgd3JhcHBlclxuICAgICAgICAuZXhlY3V0ZShcbiAgICAgICAgICAgIHsgY2FsbCwgc3RhcnRUaW1lLCBsb2dVcmw6IHVybCB9LFxuICAgICAgICAgICAgeyBvbk1lc3NhZ2U6IGFzeW5jIG1zZyA9PiBzdGF0ZS5xdWV1ZS5lbnF1ZXVlKG1zZykgfVxuICAgICAgICApXG4gICAgICAgIC5maW5hbGx5KCgpID0+ICh3cmFwcGVyLnNlbGVjdGVkID0gZmFsc2UpKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcG9sbChzdGF0ZTogTG9jYWxTdGF0ZSwgY2FuY2VsOiBQcm9taXNlPHZvaWQ+KTogUHJvbWlzZTxQb2xsUmVzdWx0PiB7XG4gICAgY29uc3QgbWVzc2FnZSA9IGF3YWl0IFByb21pc2UucmFjZShbc3RhdGUucXVldWUubmV4dCgpLCBjYW5jZWxdKTtcbiAgICBpZiAoIW1lc3NhZ2UpIHtcbiAgICAgICAgcmV0dXJuIHsgTWVzc2FnZXM6IFtdIH07XG4gICAgfVxuICAgIHJldHVybiB7IE1lc3NhZ2VzOiBbbWVzc2FnZV0gfTtcbn1cblxuZnVuY3Rpb24gcmVzcG9uc2VRdWV1ZUlkKF9zdGF0ZTogTG9jYWxTdGF0ZSk6IHN0cmluZyB7XG4gICAgcmV0dXJuIFwiPG5vbmU+XCI7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNsZWFudXAoc3RhdGU6IExvY2FsU3RhdGUsIG9wdGlvbnM6IENsZWFudXBPcHRpb25zKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgbG9nLmluZm8oYGxvY2FsIGNsZWFudXAgc3RhcnRpbmcuYCk7XG5cbiAgICBhd2FpdCBQcm9taXNlLmFsbChzdGF0ZS5leGVjdXRvcnMubWFwKGUgPT4gZS53cmFwcGVyLnN0b3AoKSkpO1xuICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBzdGF0ZS5leGVjdXRvcnMubWFwKGUgPT4gbmV3IFByb21pc2UocmVzb2x2ZSA9PiBlLmxvZ1N0cmVhbT8uZW5kKHJlc29sdmUpKSlcbiAgICApO1xuICAgIHN0YXRlLmV4ZWN1dG9ycyA9IFtdO1xuICAgIGlmIChzdGF0ZS5nY1Byb21pc2UpIHtcbiAgICAgICAgYXdhaXQgc3RhdGUuZ2NQcm9taXNlO1xuICAgIH1cblxuICAgIGlmIChvcHRpb25zLmRlbGV0ZVJlc291cmNlcykge1xuICAgICAgICBjb25zdCB7IHRlbXBEaXIgfSA9IHN0YXRlO1xuICAgICAgICBjb25zdCBwYXR0ZXJuID0gbmV3IFJlZ0V4cChgL2ZhYXN0LyR7dXVpZHY0UGF0dGVybn0kYCk7XG4gICAgICAgIGlmICh0ZW1wRGlyLm1hdGNoKHBhdHRlcm4pICYmIChhd2FpdCBwYXRoRXhpc3RzKHRlbXBEaXIpKSkge1xuICAgICAgICAgICAgbG9nLmluZm8oYERlbGV0aW5nIHRlbXAgZGlyICR7dGVtcERpcn1gKTtcbiAgICAgICAgICAgIGF3YWl0IHJlbW92ZSh0ZW1wRGlyKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBsb2cuaW5mbyhgbG9jYWwgY2xlYW51cCBkb25lLmApO1xufVxuXG5sZXQgZ2FyYmFnZUNvbGxlY3RvclJ1bm5pbmcgPSBmYWxzZTtcblxuYXN5bmMgZnVuY3Rpb24gY29sbGVjdEdhcmJhZ2UoXG4gICAgZ2NXb3JrZXI6IChkaXI6IHN0cmluZykgPT4gUHJvbWlzZTx2b2lkPixcbiAgICByZXRlbnRpb25JbkRheXM6IG51bWJlclxuKSB7XG4gICAgaWYgKGdjV29ya2VyID09PSBkZWZhdWx0R2NXb3JrZXIpIHtcbiAgICAgICAgaWYgKGdhcmJhZ2VDb2xsZWN0b3JSdW5uaW5nKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgZ2FyYmFnZUNvbGxlY3RvclJ1bm5pbmcgPSB0cnVlO1xuICAgIH1cbiAgICBjb25zdCB0bXAgPSBqb2luKHRtcGRpcigpLCBcImZhYXN0XCIpO1xuICAgIGxvZy5nYyh0bXApO1xuICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGRpciA9IGF3YWl0IHJlYWRkaXIodG1wKTtcbiAgICAgICAgY29uc3QgcGF0dGVybiA9IG5ldyBSZWdFeHAoYF4ke3V1aWR2NFBhdHRlcm59JGApO1xuICAgICAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGRpcikge1xuICAgICAgICAgICAgaWYgKGVudHJ5Lm1hdGNoKHBhdHRlcm4pKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZmFhc3REaXIgPSBqb2luKHRtcCwgZW50cnkpO1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHN0YXRzID0gYXdhaXQgc3RhdChmYWFzdERpcik7XG4gICAgICAgICAgICAgICAgICAgIGlmIChoYXNFeHBpcmVkKHN0YXRzLmF0aW1lTXMsIHJldGVudGlvbkluRGF5cykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxvZy5nYyhmYWFzdERpcik7XG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBnY1dvcmtlcihmYWFzdERpcik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge31cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgIGxvZy5nYyhlcnIpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICAgIGlmIChnY1dvcmtlciA9PT0gZGVmYXVsdEdjV29ya2VyKSB7XG4gICAgICAgICAgICBnYXJiYWdlQ29sbGVjdG9yUnVubmluZyA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY29zdFNuYXBzaG90KHN0YXRlOiBMb2NhbFN0YXRlLCBzdGF0czogRnVuY3Rpb25TdGF0cykge1xuICAgIGNvbnN0IGJpbGxlZFRpbWVTdGF0cyA9IHN0YXRzLmVzdGltYXRlZEJpbGxlZFRpbWU7XG4gICAgY29uc3Qgc2Vjb25kcyA9IChiaWxsZWRUaW1lU3RhdHMubWVhbiAvIDEwMDApICogYmlsbGVkVGltZVN0YXRzLnNhbXBsZXMgfHwgMDtcblxuICAgIGNvbnN0IGNvc3RNZXRyaWNzOiBDb3N0TWV0cmljW10gPSBbXTtcbiAgICBjb25zdCBmdW5jdGlvbkNhbGxEdXJhdGlvbiA9IG5ldyBDb3N0TWV0cmljKHtcbiAgICAgICAgbmFtZTogXCJmdW5jdGlvbkNhbGxEdXJhdGlvblwiLFxuICAgICAgICBwcmljaW5nOiAwLFxuICAgICAgICB1bml0OiBcInNlY29uZFwiLFxuICAgICAgICBtZWFzdXJlZDogc2Vjb25kcyxcbiAgICAgICAgaW5mb3JtYXRpb25hbE9ubHk6IHRydWVcbiAgICB9KTtcbiAgICBjb3N0TWV0cmljcy5wdXNoKGZ1bmN0aW9uQ2FsbER1cmF0aW9uKTtcblxuICAgIGNvbnN0IGZ1bmN0aW9uQ2FsbFJlcXVlc3RzID0gbmV3IENvc3RNZXRyaWMoe1xuICAgICAgICBuYW1lOiBcImZ1bmN0aW9uQ2FsbFJlcXVlc3RzXCIsXG4gICAgICAgIHByaWNpbmc6IDAsXG4gICAgICAgIG1lYXN1cmVkOiBzdGF0cy5pbnZvY2F0aW9ucyxcbiAgICAgICAgdW5pdDogXCJyZXF1ZXN0XCIsXG4gICAgICAgIGluZm9ybWF0aW9uYWxPbmx5OiB0cnVlXG4gICAgfSk7XG4gICAgY29zdE1ldHJpY3MucHVzaChmdW5jdGlvbkNhbGxSZXF1ZXN0cyk7XG4gICAgcmV0dXJuIG5ldyBDb3N0U25hcHNob3QoXCJsb2NhbFwiLCBzdGF0ZS5vcHRpb25zLCBzdGF0cywgY29zdE1ldHJpY3MpO1xufVxuIl19
;