@decaf-ts/utils
Version:
module management utils for decaf-ts
225 lines • 27.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.lockify = lockify;
exports.chainAbortController = chainAbortController;
exports.spawnCommand = spawnCommand;
exports.runCommand = runCommand;
const child_process_1 = require("child_process");
const StandardOutputWriter_1 = require("./../writers/StandardOutputWriter.cjs");
const constants_1 = require("./constants.cjs");
const logging_1 = require("@decaf-ts/logging");
/**
* @description Creates a locked version of a function.
* @summary This higher-order function takes a function and returns a new function that ensures
* sequential execution of the original function, even when called multiple times concurrently.
* It uses a Promise-based locking mechanism to queue function calls.
*
* @template R - The return type of the input function.
*
* @param f - The function to be locked. It can take any number of parameters and return a value of type R.
* @return A new function with the same signature as the input function, but with sequential execution guaranteed.
*
* @function lockify
*
* @mermaid
* sequenceDiagram
* participant Caller
* participant LockedFunction
* participant OriginalFunction
* Caller->>LockedFunction: Call with params
* LockedFunction->>LockedFunction: Check current lock
* alt Lock is resolved
* LockedFunction->>OriginalFunction: Execute with params
* OriginalFunction-->>LockedFunction: Return result
* LockedFunction-->>Caller: Return result
* else Lock is pending
* LockedFunction->>LockedFunction: Queue execution
* LockedFunction-->>Caller: Return promise
* Note over LockedFunction: Wait for previous execution
* LockedFunction->>OriginalFunction: Execute with params
* OriginalFunction-->>LockedFunction: Return result
* LockedFunction-->>Caller: Resolve promise with result
* end
* LockedFunction->>LockedFunction: Update lock
*
* @memberOf @decaf-ts/utils
*/
function lockify(f) {
let lock = Promise.resolve();
return (...params) => {
const result = lock.then(() => f(...params));
lock = result.catch(() => { });
return result;
};
}
function chainAbortController(argument0, ...remainder) {
let signals;
let controller;
// normalize args
if (argument0 instanceof AbortSignal) {
controller = new AbortController();
signals = [argument0, ...remainder];
}
else {
controller = argument0;
signals = remainder;
}
// if the controller is already aborted, exit early
if (controller.signal.aborted) {
return controller;
}
const handler = () => controller.abort();
for (const signal of signals) {
// check before adding! (and assume there is no possible way that the signal could
// abort between the `if` check and adding the event listener)
if (signal.aborted) {
controller.abort();
break;
}
signal.addEventListener("abort", handler, {
once: true,
signal: controller.signal,
});
}
return controller;
}
function spawnCommand(output, command, opts, abort, logger) {
function spawnInner(command, controller) {
const [cmd, argz] = output.parseCommand(command);
logger.info(`Running command: ${cmd}`);
logger.debug(`with args: ${argz.join(" ")}`);
const childProcess = (0, child_process_1.spawn)(cmd, argz, {
...opts,
cwd: opts.cwd || process.cwd(),
env: Object.assign({}, process.env, opts.env, { PATH: process.env.PATH }),
shell: opts.shell || false,
signal: controller.signal,
});
logger.verbose(`pid : ${childProcess.pid}`);
return childProcess;
}
const m = command.match(/[<>$#]/g);
if (m)
throw new Error(`Invalid command: ${command}. contains invalid characters: ${m}`);
if (command.includes(" | ")) {
const cmds = command.split(" | ");
const spawns = [];
const controllers = new Array(cmds.length);
controllers[0] = abort;
for (let i = 0; i < cmds.length; i++) {
if (i !== 0)
controllers[i] = chainAbortController(controllers[i - 1].signal);
spawns.push(spawnInner(cmds[i], controllers[i]));
if (i === 0)
continue;
spawns[i - 1].stdout.pipe(spawns[i].stdin);
}
return spawns[cmds.length - 1];
}
return spawnInner(command, abort);
}
/**
* @description Executes a command asynchronously with customizable output handling.
* @summary This function runs a shell command as a child process, providing fine-grained
* control over its execution and output handling. It supports custom output writers,
* allows for command abortion, and captures both stdout and stderr.
*
* @template R - The type of the resolved value from the command execution.
*
* @param command - The command to run, either as a string or an array of strings.
* @param opts - Spawn options for the child process. Defaults to an empty object.
* @param outputConstructor - Constructor for the output writer. Defaults to StandardOutputWriter.
* @param args - Additional arguments to pass to the output constructor.
* @return {CommandResult} A promise that resolves to the command result of type R.
*
* @function runCommand
*
* @mermaid
* sequenceDiagram
* participant Caller
* participant runCommand
* participant OutputWriter
* participant ChildProcess
* Caller->>runCommand: Call with command and options
* runCommand->>OutputWriter: Create new instance
* runCommand->>OutputWriter: Parse command
* runCommand->>ChildProcess: Spawn process
* ChildProcess-->>runCommand: Return process object
* runCommand->>ChildProcess: Set up event listeners
* loop For each stdout data
* ChildProcess->>runCommand: Emit stdout data
* runCommand->>OutputWriter: Handle stdout data
* end
* loop For each stderr data
* ChildProcess->>runCommand: Emit stderr data
* runCommand->>OutputWriter: Handle stderr data
* end
* ChildProcess->>runCommand: Emit error (if any)
* runCommand->>OutputWriter: Handle error
* ChildProcess->>runCommand: Emit exit
* runCommand->>OutputWriter: Handle exit
* OutputWriter-->>runCommand: Resolve or reject promise
* runCommand-->>Caller: Return CommandResult
*
* @memberOf @decaf-ts/utils
*/
function runCommand(command, opts = {}, outputConstructor = (StandardOutputWriter_1.StandardOutputWriter), ...args) {
const logger = logging_1.Logging.for(runCommand);
const abort = new AbortController();
const result = {
abort: abort,
command: command,
logs: [],
errs: [],
};
const lock = new Promise((resolve, reject) => {
let output;
try {
output = new outputConstructor(command, {
resolve,
reject,
}, ...args);
result.cmd = spawnCommand(output, command, opts, abort, logger);
}
catch (e) {
return reject(new Error(`Error running command ${command}: ${e}`));
}
result.cmd.stdout.setEncoding("utf8");
result.cmd.stdout.on("data", (chunk) => {
chunk = chunk.toString();
result.logs.push(chunk);
output.data(chunk);
});
result.cmd.stderr.on("data", (data) => {
data = data.toString();
result.errs.push(data);
output.error(data);
});
result.cmd.once("error", (err) => {
output.exit(err.message, result.errs);
});
result.cmd.once("exit", (code = 0) => {
if (abort.signal.aborted && code === null)
code = constants_1.AbortCode;
output.exit(code, code === 0 ? result.logs : result.errs);
});
});
Object.assign(result, {
promise: lock,
pipe: async (cb) => {
const l = logger.for("pipe");
try {
l.verbose(`Executing pipe function ${command}...`);
const result = await lock;
l.verbose(`Piping output to ${cb.name}: ${result}`);
return cb(result);
}
catch (e) {
l.error(`Error piping command output: ${e}`);
throw e;
}
},
});
return result;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUErQ0EsMEJBT0M7QUFTRCxvREFxQ0M7QUFFRCxvQ0EyQ0M7QUErQ0QsZ0NBOEVDO0FBOVFELGlEQUl1QjtBQUN2QixnRkFBdUU7QUFHdkUsK0NBQXdDO0FBQ3hDLCtDQUFvRDtBQUVwRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQ0c7QUFDSCxTQUFnQixPQUFPLENBQUksQ0FBOEI7SUFDdkQsSUFBSSxJQUFJLEdBQXNCLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUNoRCxPQUFPLENBQUMsR0FBRyxNQUFpQixFQUFFLEVBQUU7UUFDOUIsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQzdDLElBQUksR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzlCLE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUMsQ0FBQztBQUNKLENBQUM7QUFTRCxTQUFnQixvQkFBb0IsQ0FDbEMsU0FBd0MsRUFDeEMsR0FBRyxTQUF3QjtJQUUzQixJQUFJLE9BQXNCLENBQUM7SUFDM0IsSUFBSSxVQUEyQixDQUFDO0lBRWhDLGlCQUFpQjtJQUNqQixJQUFJLFNBQVMsWUFBWSxXQUFXLEVBQUUsQ0FBQztRQUNyQyxVQUFVLEdBQUcsSUFBSSxlQUFlLEVBQUUsQ0FBQztRQUNuQyxPQUFPLEdBQUcsQ0FBQyxTQUFTLEVBQUUsR0FBRyxTQUFTLENBQUMsQ0FBQztJQUN0QyxDQUFDO1NBQU0sQ0FBQztRQUNOLFVBQVUsR0FBRyxTQUFTLENBQUM7UUFDdkIsT0FBTyxHQUFHLFNBQVMsQ0FBQztJQUN0QixDQUFDO0lBRUQsbURBQW1EO0lBQ25E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aG91dE51bGxTdHJlYW1zLFxuICBzcGF3bixcbiAgU3Bhd25PcHRpb25zV2l0aG91dFN0ZGlvLFxufSBmcm9tIFwiY2hpbGRfcHJvY2Vzc1wiO1xuaW1wb3J0IHsgU3RhbmRhcmRPdXRwdXRXcml0ZXIgfSBmcm9tIFwiLi4vd3JpdGVycy9TdGFuZGFyZE91dHB1dFdyaXRlclwiO1xuaW1wb3J0IHsgQ29tbWFuZFJlc3VsdCB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBPdXRwdXRXcml0ZXJDb25zdHJ1Y3RvciB9IGZyb20gXCIuLi93cml0ZXJzL3R5cGVzXCI7XG5pbXBvcnQgeyBBYm9ydENvZGUgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IExvZ2dlciwgTG9nZ2luZyB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGEgbG9ja2VkIHZlcnNpb24gb2YgYSBmdW5jdGlvbi5cbiAqIEBzdW1tYXJ5IFRoaXMgaGlnaGVyLW9yZGVyIGZ1bmN0aW9uIHRha2VzIGEgZnVuY3Rpb24gYW5kIHJldHVybnMgYSBuZXcgZnVuY3Rpb24gdGhhdCBlbnN1cmVzXG4gKiBzZXF1ZW50aWFsIGV4ZWN1dGlvbiBvZiB0aGUgb3JpZ2luYWwgZnVuY3Rpb24sIGV2ZW4gd2hlbiBjYWxsZWQgbXVsdGlwbGUgdGltZXMgY29uY3VycmVudGx5LlxuICogSXQgdXNlcyBhIFByb21pc2UtYmFzZWQgbG9ja2luZyBtZWNoYW5pc20gdG8gcXVldWUgZnVuY3Rpb24gY2FsbHMuXG4gKlxuICogQHRlbXBsYXRlIFIgLSBUaGUgcmV0dXJuIHR5cGUgb2YgdGhlIGlucHV0IGZ1bmN0aW9uLlxuICpcbiAqIEBwYXJhbSBmIC0gVGhlIGZ1bmN0aW9uIHRvIGJlIGxvY2tlZC4gSXQgY2FuIHRha2UgYW55IG51bWJlciBvZiBwYXJhbWV0ZXJzIGFuZCByZXR1cm4gYSB2YWx1ZSBvZiB0eXBlIFIuXG4gKiBAcmV0dXJuIEEgbmV3IGZ1bmN0aW9uIHdpdGggdGhlIHNhbWUgc2lnbmF0dXJlIGFzIHRoZSBpbnB1dCBmdW5jdGlvbiwgYnV0IHdpdGggc2VxdWVudGlhbCBleGVjdXRpb24gZ3VhcmFudGVlZC5cbiAqXG4gKiBAZnVuY3Rpb24gbG9ja2lmeVxuICpcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2FsbGVyXG4gKiAgIHBhcnRpY2lwYW50IExvY2tlZEZ1bmN0aW9uXG4gKiAgIHBhcnRpY2lwYW50IE9yaWdpbmFsRnVuY3Rpb25cbiAqICAgQ2FsbGVyLT4+TG9ja2VkRnVuY3Rpb246IENhbGwgd2l0aCBwYXJhbXNcbiAqICAgTG9ja2VkRnVuY3Rpb24tPj5Mb2NrZWRGdW5jdGlvbjogQ2hlY2sgY3VycmVudCBsb2NrXG4gKiAgIGFsdCBMb2NrIGlzIHJlc29sdmVkXG4gKiAgICAgTG9ja2VkRnVuY3Rpb24tPj5PcmlnaW5hbEZ1bmN0aW9uOiBFeGVjdXRlIHdpdGggcGFyYW1zXG4gKiAgICAgT3JpZ2luYWxGdW5jdGlvbi0tPj5Mb2NrZWRGdW5jdGlvbjogUmV0dXJuIHJlc3VsdFxuICogICAgIExvY2tlZEZ1bmN0aW9uLS0+PkNhbGxlcjogUmV0dXJuIHJlc3VsdFxuICogICBlbHNlIExvY2sgaXMgcGVuZGluZ1xuICogICAgIExvY2tlZEZ1bmN0aW9uLT4+TG9ja2VkRnVuY3Rpb246IFF1ZXVlIGV4ZWN1dGlvblxuICogICAgIExvY2tlZEZ1bmN0aW9uLS0+PkNhbGxlcjogUmV0dXJuIHByb21pc2VcbiAqICAgICBOb3RlIG92ZXIgTG9ja2VkRnVuY3Rpb246IFdhaXQgZm9yIHByZXZpb3VzIGV4ZWN1dGlvblxuICogICAgIExvY2tlZEZ1bmN0aW9uLT4+T3JpZ2luYWxGdW5jdGlvbjogRXhlY3V0ZSB3aXRoIHBhcmFtc1xuICogICAgIE9yaWdpbmFsRnVuY3Rpb24tLT4+TG9ja2VkRnVuY3Rpb246IFJldHVybiByZXN1bHRcbiAqICAgICBMb2NrZWRGdW5jdGlvbi0tPj5DYWxsZXI6IFJlc29sdmUgcHJvbWlzZSB3aXRoIHJlc3VsdFxuICogICBlbmRcbiAqICAgTG9ja2VkRnVuY3Rpb24tPj5Mb2NrZWRGdW5jdGlvbjogVXBkYXRlIGxvY2tcbiAqXG4gKiBAbWVtYmVyT2YgQGRlY2FmLXRzL3V0aWxzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsb2NraWZ5PFI+KGY6ICguLi5wYXJhbXM6IHVua25vd25bXSkgPT4gUikge1xuICBsZXQgbG9jazogUHJvbWlzZTxSIHwgdm9pZD4gPSBQcm9taXNlLnJlc29sdmUoKTtcbiAgcmV0dXJuICguLi5wYXJhbXM6IHVua25vd25bXSkgPT4ge1xuICAgIGNvbnN0IHJlc3VsdCA9IGxvY2sudGhlbigoKSA9PiBmKC4uLnBhcmFtcykpO1xuICAgIGxvY2sgPSByZXN1bHQuY2F0Y2goKCkgPT4ge30pO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjaGFpbkFib3J0Q29udHJvbGxlcihcbiAgY29udHJvbGxlcjogQWJvcnRDb250cm9sbGVyLFxuICAuLi5zaWduYWxzOiBBYm9ydFNpZ25hbFtdXG4pOiBBYm9ydENvbnRyb2xsZXI7XG5leHBvcnQgZnVuY3Rpb24gY2hhaW5BYm9ydENvbnRyb2xsZXIoXG4gIC4uLnNpZ25hbHM6IEFib3J0U2lnbmFsW11cbik6IEFib3J0Q29udHJvbGxlcjtcbmV4cG9ydCBmdW5jdGlvbiBjaGFpbkFib3J0Q29udHJvbGxlcihcbiAgYXJndW1lbnQwOiBBYm9ydENvbnRyb2xsZXIgfCBBYm9ydFNpZ25hbCxcbiAgLi4ucmVtYWluZGVyOiBBYm9ydFNpZ25hbFtdXG4pOiBBYm9ydENvbnRyb2xsZXIge1xuICBsZXQgc2lnbmFsczogQWJvcnRTaWduYWxbXTtcbiAgbGV0IGNvbnRyb2xsZXI6IEFib3J0Q29udHJvbGxlcjtcblxuICAvLyBub3JtYWxpemUgYXJnc1xuICBpZiAoYXJndW1lbnQwIGluc3RhbmNlb2YgQWJvcnRTaWduYWwpIHtcbiAgICBjb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuICAgIHNpZ25hbHMgPSBbYXJndW1lbnQwLCAuLi5yZW1haW5kZXJdO1xuICB9IGVsc2Uge1xuICAgIGNvbnRyb2xsZXIgPSBhcmd1bWVudDA7XG4gICAgc2lnbmFscyA9IHJlbWFpbmRlcjtcbiAgfVxuXG4gIC8vIGlmIHRoZSBjb250cm9sbGVyIGlzIGFscmVhZHkgYWJvcnRlZCwgZXhpdCBlYXJseVxuICBpZiAoY29udHJvbGxlci5zaWduYWwuYWJvcnRlZCkge1xuICAgIHJldHVybiBjb250cm9sbGVyO1xuICB9XG5cbiAgY29uc3QgaGFuZGxlciA9ICgpID0+IGNvbnRyb2xsZXIuYWJvcnQoKTtcblxuICBmb3IgKGNvbnN0IHNpZ25hbCBvZiBzaWduYWxzKSB7XG4gICAgLy8gY2hlY2sgYmVmb3JlIGFkZGluZyEgKGFuZCBhc3N1bWUgdGhlcmUgaXMgbm8gcG9zc2libGUgd2F5IHRoYXQgdGhlIHNpZ25hbCBjb3VsZFxuICAgIC8vIGFib3J0IGJldHdlZW4gdGhlIGBpZmAgY2hlY2sgYW5kIGFkZGluZyB0aGUgZXZlbnQgbGlzdGVuZXIpXG4gICAgaWYgKHNpZ25hbC5hYm9ydGVkKSB7XG4gICAgICBjb250cm9sbGVyLmFib3J0KCk7XG4gICAgICBicmVhaztcbiAgICB9XG4gICAgc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCBoYW5kbGVyLCB7XG4gICAgICBvbmNlOiB0cnVlLFxuICAgICAgc2lnbmFsOiBjb250cm9sbGVyLnNpZ25hbCxcbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiBjb250cm9sbGVyO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc3Bhd25Db21tYW5kPFIgPSBzdHJpbmc+KFxuICBvdXRwdXQ6IFN0YW5kYXJkT3V0cHV0V3JpdGVyPFI+LFxuICBjb21tYW5kOiBzdHJpbmcsXG4gIG9wdHM6IFNwYXduT3B0aW9uc1dpdGhvdXRTdGRpbyxcbiAgYWJvcnQ6IEFib3J0Q29udHJvbGxlcixcbiAgbG9nZ2VyOiBMb2dnZXJcbik6IENoaWxkUHJvY2Vzc1dpdGhvdXROdWxsU3RyZWFtcyB7XG4gIGZ1bmN0aW9uIHNwYXduSW5uZXIoY29tbWFuZDogc3RyaW5nLCBjb250cm9sbGVyOiBBYm9ydENvbnRyb2xsZXIpIHtcbiAgICBjb25zdCBbY21kLCBhcmd6XSA9IG91dHB1dC5wYXJzZUNvbW1hbmQoY29tbWFuZCk7XG4gICAgbG9nZ2VyLmluZm8oYFJ1bm5pbmcgY29tbWFuZDogJHtjbWR9YCk7XG4gICAgbG9nZ2VyLmRlYnVnKGB3aXRoIGFyZ3M6ICR7YXJnei5qb2luKFwiIFwiKX1gKTtcbiAgICBjb25zdCBjaGlsZFByb2Nlc3MgPSBzcGF3bihjbWQsIGFyZ3osIHtcbiAgICAgIC4uLm9wdHMsXG4gICAgICBjd2Q6IG9wdHMuY3dkIHx8IHByb2Nlc3MuY3dkKCksXG4gICAgICBlbnY6IE9iamVjdC5hc3NpZ24oe30sIHByb2Nlc3MuZW52LCBvcHRzLmVudiwgeyBQQVRIOiBwcm9jZXNzLmVudi5QQVRIIH0pLFxuICAgICAgc2hlbGw6IG9wdHMuc2hlbGwgfHwgZmFsc2UsXG4gICAgICBzaWduYWw6IGNvbnRyb2xsZXIuc2lnbmFsLFxuICAgIH0pO1xuICAgIGxvZ2dlci52ZXJib3NlKGBwaWQgOiAke2NoaWxkUHJvY2Vzcy5waWR9YCk7XG4gICAgcmV0dXJuIGNoaWxkUHJvY2VzcztcbiAgfVxuXG4gIGNvbnN0IG0gPSBjb21tYW5kLm1hdGNoKC9bPD4kI10vZyk7XG4gIGlmIChtKVxuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBJbnZhbGlkIGNvbW1hbmQ6ICR7Y29tbWFuZH0uIGNvbnRhaW5zIGludmFsaWQgY2hhcmFjdGVyczogJHttfWBcbiAgICApO1xuICBpZiAoY29tbWFuZC5pbmNsdWRlcyhcIiB8IFwiKSkge1xuICAgIGNvbnN0IGNtZHMgPSBjb21tYW5kLnNwbGl0KFwiIHwgXCIpO1xuICAgIGNvbnN0IHNwYXducyA9IFtdO1xuICAgIGNvbnN0IGNvbnRyb2xsZXJzID0gbmV3IEFycmF5KGNtZHMubGVuZ3RoKTtcbiAgICBjb250cm9sbGVyc1swXSA9IGFib3J0O1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY21kcy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGkgIT09IDApXG4gICAgICAgIGNvbnRyb2xsZXJzW2ldID0gY2hhaW5BYm9ydENvbnRyb2xsZXIoY29udHJvbGxlcnNbaSAtIDFdLnNpZ25hbCk7XG4gICAgICBzcGF3bnMucHVzaChzcGF3bklubmVyKGNtZHNbaV0sIGNvbnRyb2xsZXJzW2ldKSk7XG4gICAgICBpZiAoaSA9PT0gMCkgY29udGludWU7XG4gICAgICBzcGF3bnNbaSAtIDFdLnN0ZG91dC5waXBlKHNwYXduc1tpXS5zdGRpbik7XG4gICAgfVxuICAgIHJldHVybiBzcGF3bnNbY21kcy5sZW5ndGggLSAxXTtcbiAgfVxuXG4gIHJldHVybiBzcGF3bklubmVyKGNvbW1hbmQsIGFib3J0KTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRXhlY3V0ZXMgYSBjb21tYW5kIGFzeW5jaHJvbm91c2x5IHdpdGggY3VzdG9taXphYmxlIG91dHB1dCBoYW5kbGluZy5cbiAqIEBzdW1tYXJ5IFRoaXMgZnVuY3Rpb24gcnVucyBhIHNoZWxsIGNvbW1hbmQgYXMgYSBjaGlsZCBwcm9jZXNzLCBwcm92aWRpbmcgZmluZS1ncmFpbmVkXG4gKiBjb250cm9sIG92ZXIgaXRzIGV4ZWN1dGlvbiBhbmQgb3V0cHV0IGhhbmRsaW5nLiBJdCBzdXBwb3J0cyBjdXN0b20gb3V0cHV0IHdyaXRlcnMsXG4gKiBhbGxvd3MgZm9yIGNvbW1hbmQgYWJvcnRpb24sIGFuZCBjYXB0dXJlcyBib3RoIHN0ZG91dCBhbmQgc3RkZXJyLlxuICpcbiAqIEB0ZW1wbGF0ZSBSIC0gVGhlIHR5cGUgb2YgdGhlIHJlc29sdmVkIHZhbHVlIGZyb20gdGhlIGNvbW1hbmQgZXhlY3V0aW9uLlxuICpcbiAqIEBwYXJhbSBjb21tYW5kIC0gVGhlIGNvbW1hbmQgdG8gcnVuLCBlaXRoZXIgYXMgYSBzdHJpbmcgb3IgYW4gYXJyYXkgb2Ygc3RyaW5ncy5cbiAqIEBwYXJhbSBvcHRzIC0gU3Bhd24gb3B0aW9ucyBmb3IgdGhlIGNoaWxkIHByb2Nlc3MuIERlZmF1bHRzIHRvIGFuIGVtcHR5IG9iamVjdC5cbiAqIEBwYXJhbSBvdXRwdXRDb25zdHJ1Y3RvciAtIENvbnN0cnVjdG9yIGZvciB0aGUgb3V0cHV0IHdyaXRlci4gRGVmYXVsdHMgdG8gU3RhbmRhcmRPdXRwdXRXcml0ZXIuXG4gKiBAcGFyYW0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIHRvIHBhc3MgdG8gdGhlIG91dHB1dCBjb25zdHJ1Y3Rvci5cbiAqIEByZXR1cm4ge0NvbW1hbmRSZXN1bHR9IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBjb21tYW5kIHJlc3VsdCBvZiB0eXBlIFIuXG4gKlxuICogQGZ1bmN0aW9uIHJ1bkNvbW1hbmRcbiAqXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENhbGxlclxuICogICBwYXJ0aWNpcGFudCBydW5Db21tYW5kXG4gKiAgIHBhcnRpY2lwYW50IE91dHB1dFdyaXRlclxuICogICBwYXJ0aWNpcGFudCBDaGlsZFByb2Nlc3NcbiAqICAgQ2FsbGVyLT4+cnVuQ29tbWFuZDogQ2FsbCB3aXRoIGNvbW1hbmQgYW5kIG9wdGlvbnNcbiAqICAgcnVuQ29tbWFuZC0+Pk91dHB1dFdyaXRlcjogQ3JlYXRlIG5ldyBpbnN0YW5jZVxuICogICBydW5Db21tYW5kLT4+T3V0cHV0V3JpdGVyOiBQYXJzZSBjb21tYW5kXG4gKiAgIHJ1bkNvbW1hbmQtPj5DaGlsZFByb2Nlc3M6IFNwYXduIHByb2Nlc3NcbiAqICAgQ2hpbGRQcm9jZXNzLS0+PnJ1bkNvbW1hbmQ6IFJldHVybiBwcm9jZXNzIG9iamVjdFxuICogICBydW5Db21tYW5kLT4+Q2hpbGRQcm9jZXNzOiBTZXQgdXAgZXZlbnQgbGlzdGVuZXJzXG4gKiAgIGxvb3AgRm9yIGVhY2ggc3Rkb3V0IGRhdGFcbiAqICAgICBDaGlsZFByb2Nlc3MtPj5ydW5Db21tYW5kOiBFbWl0IHN0ZG91dCBkYXRhXG4gKiAgICAgcnVuQ29tbWFuZC0+Pk91dHB1dFdyaXRlcjogSGFuZGxlIHN0ZG91dCBkYXRhXG4gKiAgIGVuZFxuICogICBsb29wIEZvciBlYWNoIHN0ZGVyciBkYXRhXG4gKiAgICAgQ2hpbGRQcm9jZXNzLT4+cnVuQ29tbWFuZDogRW1pdCBzdGRlcnIgZGF0YVxuICogICAgIHJ1bkNvbW1hbmQtPj5PdXRwdXRXcml0ZXI6IEhhbmRsZSBzdGRlcnIgZGF0YVxuICogICBlbmRcbiAqICAgQ2hpbGRQcm9jZXNzLT4+cnVuQ29tbWFuZDogRW1pdCBlcnJvciAoaWYgYW55KVxuICogICBydW5Db21tYW5kLT4+T3V0cHV0V3JpdGVyOiBIYW5kbGUgZXJyb3JcbiAqICAgQ2hpbGRQcm9jZXNzLT4+cnVuQ29tbWFuZDogRW1pdCBleGl0XG4gKiAgIHJ1bkNvbW1hbmQtPj5PdXRwdXRXcml0ZXI6IEhhbmRsZSBleGl0XG4gKiAgIE91dHB1dFdyaXRlci0tPj5ydW5Db21tYW5kOiBSZXNvbHZlIG9yIHJlamVjdCBwcm9taXNlXG4gKiAgIHJ1bkNvbW1hbmQtLT4+Q2FsbGVyOiBSZXR1cm4gQ29tbWFuZFJlc3VsdFxuICpcbiAqIEBtZW1iZXJPZiBAZGVjYWYtdHMvdXRpbHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJ1bkNvbW1hbmQ8UiA9IHN0cmluZz4oXG4gIGNvbW1hbmQ6IHN0cmluZyxcbiAgb3B0czogU3Bhd25PcHRpb25zV2l0aG91dFN0ZGlvID0ge30sXG4gIG91dHB1dENvbnN0cnVjdG9yOiBPdXRwdXRXcml0ZXJDb25zdHJ1Y3RvcjxcbiAgICBSLFxuICAgIFN0YW5kYXJkT3V0cHV0V3JpdGVyPFI+LFxuICAgIEVycm9yXG4gID4gPSBTdGFuZGFyZE91dHB1dFdyaXRlcjxSPixcbiAgLi4uYXJnczogdW5rbm93bltdXG4pOiBDb21tYW5kUmVzdWx0PFI+IHtcbiAgY29uc3QgbG9nZ2VyID0gTG9nZ2luZy5mb3IocnVuQ29tbWFuZCk7XG4gIGNvbnN0IGFib3J0ID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuXG4gIGNvbnN0IHJlc3VsdDogT21pdDxDb21tYW5kUmVzdWx0LCBcInByb21pc2VcIiB8IFwicGlwZVwiPiA9IHtcbiAgICBhYm9ydDogYWJvcnQsXG4gICAgY29tbWFuZDogY29tbWFuZCxcbiAgICBsb2dzOiBbXSxcbiAgICBlcnJzOiBbXSxcbiAgfTtcblxuICBjb25zdCBsb2NrID0gbmV3IFByb21pc2U8Uj4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGxldCBvdXRwdXQ7XG4gICAgdHJ5IHtcbiAgICAgIG91dHB1dCA9IG5ldyBvdXRwdXRDb25zdHJ1Y3RvcihcbiAgICAgICAgY29tbWFuZCxcbiAgICAgICAge1xuICAgICAgICAgIHJlc29sdmUsXG4gICAgICAgICAgcmVqZWN0LFxuICAgICAgICB9LFxuICAgICAgICAuLi5hcmdzXG4gICAgICApO1xuXG4gICAgICByZXN1bHQuY21kID0gc3Bhd25Db21tYW5kPFI+KG91dHB1dCwgY29tbWFuZCwgb3B0cywgYWJvcnQsIGxvZ2dlcik7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgcmV0dXJuIHJlamVjdChuZXcgRXJyb3IoYEVycm9yIHJ1bm5pbmcgY29tbWFuZCAke2NvbW1hbmR9OiAke2V9YCkpO1xuICAgIH1cblxuICAgIHJlc3VsdC5jbWQuc3Rkb3V0LnNldEVuY29kaW5nKFwidXRmOFwiKTtcblxuICAgIHJlc3VsdC5jbWQuc3Rkb3V0Lm9uKFwiZGF0YVwiLCAoY2h1bms6IGFueSkgPT4ge1xuICAgICAgY2h1bmsgPSBjaHVuay50b1N0cmluZygpO1xuICAgICAgcmVzdWx0LmxvZ3MucHVzaChjaHVuayk7XG4gICAgICBvdXRwdXQuZGF0YShjaHVuayk7XG4gICAgfSk7XG5cbiAgICByZXN1bHQuY21kLnN0ZGVyci5vbihcImRhdGFcIiwgKGRhdGE6IGFueSkgPT4ge1xuICAgICAgZGF0YSA9IGRhdGEudG9TdHJpbmcoKTtcbiAgICAgIHJlc3VsdC5lcnJzLnB1c2goZGF0YSk7XG4gICAgICBvdXRwdXQuZXJyb3IoZGF0YSk7XG4gICAgfSk7XG5cbiAgICByZXN1bHQuY21kLm9uY2UoXCJlcnJvclwiLCAoZXJyOiBFcnJvcikgPT4ge1xuICAgICAgb3V0cHV0LmV4aXQoZXJyLm1lc3NhZ2UsIHJlc3VsdC5lcnJzKTtcbiAgICB9KTtcblxuICAgIHJlc3VsdC5jbWQub25jZShcImV4aXRcIiwgKGNvZGU6IG51bWJlciA9IDApID0+IHtcbiAgICAgIGlmIChhYm9ydC5zaWduYWwuYWJvcnRlZCAmJiBjb2RlID09PSBudWxsKSBjb2RlID0gQWJvcnRDb2RlIGFzIGFueTtcbiAgICAgIG91dHB1dC5leGl0KGNvZGUsIGNvZGUgPT09IDAgPyByZXN1bHQubG9ncyA6IHJlc3VsdC5lcnJzKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgT2JqZWN0LmFzc2lnbihyZXN1bHQsIHtcbiAgICBwcm9taXNlOiBsb2NrLFxuICAgIHBpcGU6IGFzeW5jIDxFPihjYjogKHI6IFIpID0+IEUpID0+IHtcbiAgICAgIGNvbnN0IGwgPSBsb2dnZXIuZm9yKFwicGlwZVwiKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGwudmVyYm9zZShgRXhlY3V0aW5nIHBpcGUgZnVuY3Rpb24gJHtjb21tYW5kfS4uLmApO1xuICAgICAgICBjb25zdCByZXN1bHQ6IFIgPSBhd2FpdCBsb2NrO1xuICAgICAgICBsLnZlcmJvc2UoYFBpcGluZyBvdXRwdXQgdG8gJHtjYi5uYW1lfTogJHtyZXN1bHR9YCk7XG4gICAgICAgIHJldHVybiBjYihyZXN1bHQpO1xuICAgICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgICBsLmVycm9yKGBFcnJvciBwaXBpbmcgY29tbWFuZCBvdXRwdXQ6ICR7ZX1gKTtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cbiAgICB9LFxuICB9KTtcblxuICByZXR1cm4gcmVzdWx0IGFzIENvbW1hbmRSZXN1bHQ8Uj47XG59XG4iXX0=