UNPKG

@decaf-ts/utils

Version:

module management utils for decaf-ts

243 lines 31.4 kB
"use strict"; 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 module: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; } /** * @description Spawns a command as a child process with output handling. * @summary Creates a child process to execute a command with support for piping multiple commands, * custom output handling, and abort control. This function handles the low-level details of * spawning processes and connecting their inputs/outputs when piping is used. * * @template R - The type of the processed output, defaulting to string. * @param {StandardOutputWriter<R>} output - The output writer to handle command output. * @param {string} command - The command to execute, can include pipe operators. * @param {SpawnOptionsWithoutStdio} opts - Options for the spawned process. * @param {AbortController} abort - Controller to abort the command execution. * @param {Logger} logger - Logger for recording command execution details. * @return {ChildProcessWithoutNullStreams} The spawned child process. * * @function spawnCommand * * @memberOf module:utils */ 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 module: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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUErQ0EsMEJBT0M7QUFtQ0Qsb0RBcUNDO0FBb0JELG9DQTJDQztBQStDRCxnQ0E4RUM7QUExVEQsaURBSXVCO0FBQ3ZCLGdGQUF1RTtBQUd2RSwrQ0FBd0M7QUFDeEMsK0NBQW9EO0FBRXBEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1DRztBQUNILFNBQWdCLE9BQU8sQ0FBSSxDQUE4QjtJQUN2RCxJQUFJLElBQUksR0FBc0IsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ2hELE9BQU8sQ0FBQyxHQUFHLE1BQWlCLEVBQUUsRUFBRTtRQUM5QixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUM7UUFDN0MsSUFBSSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7UUFDOUIsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQW1DRCxTQUFnQixvQkFBb0IsQ0FDbEMsU0FBd0MsRUFDeEMsR0FBRyxTQUF3QjtJQUUzQixJQUFJLE9BQXNCLENBQUM7SUFDM0IsSUFBSSxVQUEyQixDQUFDO0lBRWhDLGlCQUFpQjtJQUNqQixJQUFJLFNBQVMsWUFBWSxXQUFXLEVBQUUsQ0FBQztRQUNyQyxVQUFVLEdBQUcsSUFBSSxlQUFlLEVBQUUsQ0FBQztRQUNuQyxPQUFPLEdBQUcsQ0FBQyxTQUFTLEVBQUUsR0FBRyxTQUFTLENBQUMsQ0FBQztJQUN0QyxDQUFDO1NBQU0sQ0FBQztRQUNOLFVBQVUsR0FBRyxTQUFTLENBQUM7UUFDdkIsT0FBTyxHQUFHLFNBQVMsQ0FBQztJQUN0QixDQUFDO0lBRUQsbURBQW1EO0lB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OlsiaW1wb3J0IHtcbiAgQ2hpbGRQcm9jZXNzV2l0aG91dE51bGxTdHJlYW1zLFxuICBzcGF3bixcbiAgU3Bhd25PcHRpb25zV2l0aG91dFN0ZGlvLFxufSBmcm9tIFwiY2hpbGRfcHJvY2Vzc1wiO1xuaW1wb3J0IHsgU3RhbmRhcmRPdXRwdXRXcml0ZXIgfSBmcm9tIFwiLi4vd3JpdGVycy9TdGFuZGFyZE91dHB1dFdyaXRlclwiO1xuaW1wb3J0IHsgQ29tbWFuZFJlc3VsdCB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBPdXRwdXRXcml0ZXJDb25zdHJ1Y3RvciB9IGZyb20gXCIuLi93cml0ZXJzL3R5cGVzXCI7XG5pbXBvcnQgeyBBYm9ydENvZGUgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IExvZ2dlciwgTG9nZ2luZyB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGEgbG9ja2VkIHZlcnNpb24gb2YgYSBmdW5jdGlvbi5cbiAqIEBzdW1tYXJ5IFRoaXMgaGlnaGVyLW9yZGVyIGZ1bmN0aW9uIHRha2VzIGEgZnVuY3Rpb24gYW5kIHJldHVybnMgYSBuZXcgZnVuY3Rpb24gdGhhdCBlbnN1cmVzXG4gKiBzZXF1ZW50aWFsIGV4ZWN1dGlvbiBvZiB0aGUgb3JpZ2luYWwgZnVuY3Rpb24sIGV2ZW4gd2hlbiBjYWxsZWQgbXVsdGlwbGUgdGltZXMgY29uY3VycmVudGx5LlxuICogSXQgdXNlcyBhIFByb21pc2UtYmFzZWQgbG9ja2luZyBtZWNoYW5pc20gdG8gcXVldWUgZnVuY3Rpb24gY2FsbHMuXG4gKlxuICogQHRlbXBsYXRlIFIgLSBUaGUgcmV0dXJuIHR5cGUgb2YgdGhlIGlucHV0IGZ1bmN0aW9uLlxuICpcbiAqIEBwYXJhbSBmIC0gVGhlIGZ1bmN0aW9uIHRvIGJlIGxvY2tlZC4gSXQgY2FuIHRha2UgYW55IG51bWJlciBvZiBwYXJhbWV0ZXJzIGFuZCByZXR1cm4gYSB2YWx1ZSBvZiB0eXBlIFIuXG4gKiBAcmV0dXJuIEEgbmV3IGZ1bmN0aW9uIHdpdGggdGhlIHNhbWUgc2lnbmF0dXJlIGFzIHRoZSBpbnB1dCBmdW5jdGlvbiwgYnV0IHdpdGggc2VxdWVudGlhbCBleGVjdXRpb24gZ3VhcmFudGVlZC5cbiAqXG4gKiBAZnVuY3Rpb24gbG9ja2lmeVxuICpcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2FsbGVyXG4gKiAgIHBhcnRpY2lwYW50IExvY2tlZEZ1bmN0aW9uXG4gKiAgIHBhcnRpY2lwYW50IE9yaWdpbmFsRnVuY3Rpb25cbiAqICAgQ2FsbGVyLT4+TG9ja2VkRnVuY3Rpb246IENhbGwgd2l0aCBwYXJhbXNcbiAqICAgTG9ja2VkRnVuY3Rpb24tPj5Mb2NrZWRGdW5jdGlvbjogQ2hlY2sgY3VycmVudCBsb2NrXG4gKiAgIGFsdCBMb2NrIGlzIHJlc29sdmVkXG4gKiAgICAgTG9ja2VkRnVuY3Rpb24tPj5PcmlnaW5hbEZ1bmN0aW9uOiBFeGVjdXRlIHdpdGggcGFyYW1zXG4gKiAgICAgT3JpZ2luYWxGdW5jdGlvbi0tPj5Mb2NrZWRGdW5jdGlvbjogUmV0dXJuIHJlc3VsdFxuICogICAgIExvY2tlZEZ1bmN0aW9uLS0+PkNhbGxlcjogUmV0dXJuIHJlc3VsdFxuICogICBlbHNlIExvY2sgaXMgcGVuZGluZ1xuICogICAgIExvY2tlZEZ1bmN0aW9uLT4+TG9ja2VkRnVuY3Rpb246IFF1ZXVlIGV4ZWN1dGlvblxuICogICAgIExvY2tlZEZ1bmN0aW9uLS0+PkNhbGxlcjogUmV0dXJuIHByb21pc2VcbiAqICAgICBOb3RlIG92ZXIgTG9ja2VkRnVuY3Rpb246IFdhaXQgZm9yIHByZXZpb3VzIGV4ZWN1dGlvblxuICogICAgIExvY2tlZEZ1bmN0aW9uLT4+T3JpZ2luYWxGdW5jdGlvbjogRXhlY3V0ZSB3aXRoIHBhcmFtc1xuICogICAgIE9yaWdpbmFsRnVuY3Rpb24tLT4+TG9ja2VkRnVuY3Rpb246IFJldHVybiByZXN1bHRcbiAqICAgICBMb2NrZWRGdW5jdGlvbi0tPj5DYWxsZXI6IFJlc29sdmUgcHJvbWlzZSB3aXRoIHJlc3VsdFxuICogICBlbmRcbiAqICAgTG9ja2VkRnVuY3Rpb24tPj5Mb2NrZWRGdW5jdGlvbjogVXBkYXRlIGxvY2tcbiAqXG4gKiBAbWVtYmVyT2YgbW9kdWxlOnV0aWxzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsb2NraWZ5PFI+KGY6ICguLi5wYXJhbXM6IHVua25vd25bXSkgPT4gUikge1xuICBsZXQgbG9jazogUHJvbWlzZTxSIHwgdm9pZD4gPSBQcm9taXNlLnJlc29sdmUoKTtcbiAgcmV0dXJuICguLi5wYXJhbXM6IHVua25vd25bXSkgPT4ge1xuICAgIGNvbnN0IHJlc3VsdCA9IGxvY2sudGhlbigoKSA9PiBmKC4uLnBhcmFtcykpO1xuICAgIGxvY2sgPSByZXN1bHQuY2F0Y2goKCkgPT4ge30pO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH07XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENoYWlucyBtdWx0aXBsZSBhYm9ydCBzaWduYWxzIHRvIGEgY29udHJvbGxlci5cbiAqIEBzdW1tYXJ5IENyZWF0ZXMgYSBtZWNoYW5pc20gd2hlcmUgbXVsdGlwbGUgYWJvcnQgc2lnbmFscyBjYW4gdHJpZ2dlciBhIHNpbmdsZSBhYm9ydCBjb250cm9sbGVyLlxuICogVGhpcyBpcyB1c2VmdWwgZm9yIGNvb3JkaW5hdGluZyBjYW5jZWxsYXRpb24gYWNyb3NzIG11bHRpcGxlIGFzeW5jaHJvbm91cyBvcGVyYXRpb25zLlxuICpcbiAqIEBwYXJhbSB7QWJvcnRDb250cm9sbGVyfSBjb250cm9sbGVyIC0gVGhlIGFib3J0IGNvbnRyb2xsZXIgdG8gYmUgdHJpZ2dlcmVkIGJ5IHNpZ25hbHMuXG4gKiBAcGFyYW0gey4uLkFib3J0U2lnbmFsfSBzaWduYWxzIC0gT25lIG9yIG1vcmUgYWJvcnQgc2lnbmFscyB0aGF0IGNhbiB0cmlnZ2VyIHRoZSBjb250cm9sbGVyLlxuICogQHJldHVybiB7QWJvcnRDb250cm9sbGVyfSBUaGUgaW5wdXQgY29udHJvbGxlciwgbm93IGNvbm5lY3RlZCB0byB0aGUgc2lnbmFscy5cbiAqXG4gKiBAZnVuY3Rpb24gY2hhaW5BYm9ydENvbnRyb2xsZXJcbiAqXG4gKiBAbWVtYmVyT2YgbW9kdWxlOnV0aWxzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjaGFpbkFib3J0Q29udHJvbGxlcihcbiAgY29udHJvbGxlcjogQWJvcnRDb250cm9sbGVyLFxuICAuLi5zaWduYWxzOiBBYm9ydFNpZ25hbFtdXG4pOiBBYm9ydENvbnRyb2xsZXI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBuZXcgY29udHJvbGxlciBjaGFpbmVkIHRvIG11bHRpcGxlIGFib3J0IHNpZ25hbHMuXG4gKiBAc3VtbWFyeSBDcmVhdGVzIGEgbmV3IGFib3J0IGNvbnRyb2xsZXIgdGhhdCB3aWxsIGJlIHRyaWdnZXJlZCBpZiBhbnkgb2YgdGhlIHByb3ZpZGVkIHNpZ25hbHMgYXJlIGFib3J0ZWQuXG4gKlxuICogQHBhcmFtIHsuLi5BYm9ydFNpZ25hbH0gc2lnbmFscyAtIE9uZSBvciBtb3JlIGFib3J0IHNpZ25hbHMgdGhhdCBjYW4gdHJpZ2dlciB0aGUgbmV3IGNvbnRyb2xsZXIuXG4gKiBAcmV0dXJuIHtBYm9ydENvbnRyb2xsZXJ9IEEgbmV3IGFib3J0IGNvbnRyb2xsZXIgY29ubmVjdGVkIHRvIHRoZSBzaWduYWxzLlxuICpcbiAqIEBmdW5jdGlvbiBjaGFpbkFib3J0Q29udHJvbGxlclxuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNoYWluQWJvcnRDb250cm9sbGVyKFxuICAuLi5zaWduYWxzOiBBYm9ydFNpZ25hbFtdXG4pOiBBYm9ydENvbnRyb2xsZXI7XG5cbmV4cG9ydCBmdW5jdGlvbiBjaGFpbkFib3J0Q29udHJvbGxlcihcbiAgYXJndW1lbnQwOiBBYm9ydENvbnRyb2xsZXIgfCBBYm9ydFNpZ25hbCxcbiAgLi4ucmVtYWluZGVyOiBBYm9ydFNpZ25hbFtdXG4pOiBBYm9ydENvbnRyb2xsZXIge1xuICBsZXQgc2lnbmFsczogQWJvcnRTaWduYWxbXTtcbiAgbGV0IGNvbnRyb2xsZXI6IEFib3J0Q29udHJvbGxlcjtcblxuICAvLyBub3JtYWxpemUgYXJnc1xuICBpZiAoYXJndW1lbnQwIGluc3RhbmNlb2YgQWJvcnRTaWduYWwpIHtcbiAgICBjb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuICAgIHNpZ25hbHMgPSBbYXJndW1lbnQwLCAuLi5yZW1haW5kZXJdO1xuICB9IGVsc2Uge1xuICAgIGNvbnRyb2xsZXIgPSBhcmd1bWVudDA7XG4gICAgc2lnbmFscyA9IHJlbWFpbmRlcjtcbiAgfVxuXG4gIC8vIGlmIHRoZSBjb250cm9sbGVyIGlzIGFscmVhZHkgYWJvcnRlZCwgZXhpdCBlYXJseVxuICBpZiAoY29udHJvbGxlci5zaWduYWwuYWJvcnRlZCkge1xuICAgIHJldHVybiBjb250cm9sbGVyO1xuICB9XG5cbiAgY29uc3QgaGFuZGxlciA9ICgpID0+IGNvbnRyb2xsZXIuYWJvcnQoKTtcblxuICBmb3IgKGNvbnN0IHNpZ25hbCBvZiBzaWduYWxzKSB7XG4gICAgLy8gY2hlY2sgYmVmb3JlIGFkZGluZyEgKGFuZCBhc3N1bWUgdGhlcmUgaXMgbm8gcG9zc2libGUgd2F5IHRoYXQgdGhlIHNpZ25hbCBjb3VsZFxuICAgIC8vIGFib3J0IGJldHdlZW4gdGhlIGBpZmAgY2hlY2sgYW5kIGFkZGluZyB0aGUgZXZlbnQgbGlzdGVuZXIpXG4gICAgaWYgKHNpZ25hbC5hYm9ydGVkKSB7XG4gICAgICBjb250cm9sbGVyLmFib3J0KCk7XG4gICAgICBicmVhaztcbiAgICB9XG4gICAgc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCBoYW5kbGVyLCB7XG4gICAgICBvbmNlOiB0cnVlLFxuICAgICAgc2lnbmFsOiBjb250cm9sbGVyLnNpZ25hbCxcbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiBjb250cm9sbGVyO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBTcGF3bnMgYSBjb21tYW5kIGFzIGEgY2hpbGQgcHJvY2VzcyB3aXRoIG91dHB1dCBoYW5kbGluZy5cbiAqIEBzdW1tYXJ5IENyZWF0ZXMgYSBjaGlsZCBwcm9jZXNzIHRvIGV4ZWN1dGUgYSBjb21tYW5kIHdpdGggc3VwcG9ydCBmb3IgcGlwaW5nIG11bHRpcGxlIGNvbW1hbmRzLFxuICogY3VzdG9tIG91dHB1dCBoYW5kbGluZywgYW5kIGFib3J0IGNvbnRyb2wuIFRoaXMgZnVuY3Rpb24gaGFuZGxlcyB0aGUgbG93LWxldmVsIGRldGFpbHMgb2ZcbiAqIHNwYXduaW5nIHByb2Nlc3NlcyBhbmQgY29ubmVjdGluZyB0aGVpciBpbnB1dHMvb3V0cHV0cyB3aGVuIHBpcGluZyBpcyB1c2VkLlxuICpcbiAqIEB0ZW1wbGF0ZSBSIC0gVGhlIHR5cGUgb2YgdGhlIHByb2Nlc3NlZCBvdXRwdXQsIGRlZmF1bHRpbmcgdG8gc3RyaW5nLlxuICogQHBhcmFtIHtTdGFuZGFyZE91dHB1dFdyaXRlcjxSPn0gb3V0cHV0IC0gVGhlIG91dHB1dCB3cml0ZXIgdG8gaGFuZGxlIGNvbW1hbmQgb3V0cHV0LlxuICogQHBhcmFtIHtzdHJpbmd9IGNvbW1hbmQgLSBUaGUgY29tbWFuZCB0byBleGVjdXRlLCBjYW4gaW5jbHVkZSBwaXBlIG9wZXJhdG9ycy5cbiAqIEBwYXJhbSB7U3Bhd25PcHRpb25zV2l0aG91dFN0ZGlvfSBvcHRzIC0gT3B0aW9ucyBmb3IgdGhlIHNwYXduZWQgcHJvY2Vzcy5cbiAqIEBwYXJhbSB7QWJvcnRDb250cm9sbGVyfSBhYm9ydCAtIENvbnRyb2xsZXIgdG8gYWJvcnQgdGhlIGNvbW1hbmQgZXhlY3V0aW9uLlxuICogQHBhcmFtIHtMb2dnZXJ9IGxvZ2dlciAtIExvZ2dlciBmb3IgcmVjb3JkaW5nIGNvbW1hbmQgZXhlY3V0aW9uIGRldGFpbHMuXG4gKiBAcmV0dXJuIHtDaGlsZFByb2Nlc3NXaXRob3V0TnVsbFN0cmVhbXN9IFRoZSBzcGF3bmVkIGNoaWxkIHByb2Nlc3MuXG4gKlxuICogQGZ1bmN0aW9uIHNwYXduQ29tbWFuZFxuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6dXRpbHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNwYXduQ29tbWFuZDxSID0gc3RyaW5nPihcbiAgb3V0cHV0OiBTdGFuZGFyZE91dHB1dFdyaXRlcjxSPixcbiAgY29tbWFuZDogc3RyaW5nLFxuICBvcHRzOiBTcGF3bk9wdGlvbnNXaXRob3V0U3RkaW8sXG4gIGFib3J0OiBBYm9ydENvbnRyb2xsZXIsXG4gIGxvZ2dlcjogTG9nZ2VyXG4pOiBDaGlsZFByb2Nlc3NXaXRob3V0TnVsbFN0cmVhbXMge1xuICBmdW5jdGlvbiBzcGF3bklubmVyKGNvbW1hbmQ6IHN0cmluZywgY29udHJvbGxlcjogQWJvcnRDb250cm9sbGVyKSB7XG4gICAgY29uc3QgW2NtZCwgYXJnel0gPSBvdXRwdXQucGFyc2VDb21tYW5kKGNvbW1hbmQpO1xuICAgIGxvZ2dlci5pbmZvKGBSdW5uaW5nIGNvbW1hbmQ6ICR7Y21kfWApO1xuICAgIGxvZ2dlci5kZWJ1Zyhgd2l0aCBhcmdzOiAke2FyZ3ouam9pbihcIiBcIil9YCk7XG4gICAgY29uc3QgY2hpbGRQcm9jZXNzID0gc3Bhd24oY21kLCBhcmd6LCB7XG4gICAgICAuLi5vcHRzLFxuICAgICAgY3dkOiBvcHRzLmN3ZCB8fCBwcm9jZXNzLmN3ZCgpLFxuICAgICAgZW52OiBPYmplY3QuYXNzaWduKHt9LCBwcm9jZXNzLmVudiwgb3B0cy5lbnYsIHsgUEFUSDogcHJvY2Vzcy5lbnYuUEFUSCB9KSxcbiAgICAgIHNoZWxsOiBvcHRzLnNoZWxsIHx8IGZhbHNlLFxuICAgICAgc2lnbmFsOiBjb250cm9sbGVyLnNpZ25hbCxcbiAgICB9KTtcbiAgICBsb2dnZXIudmVyYm9zZShgcGlkIDogJHtjaGlsZFByb2Nlc3MucGlkfWApO1xuICAgIHJldHVybiBjaGlsZFByb2Nlc3M7XG4gIH1cblxuICBjb25zdCBtID0gY29tbWFuZC5tYXRjaCgvWzw+JCNdL2cpO1xuICBpZiAobSlcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgSW52YWxpZCBjb21tYW5kOiAke2NvbW1hbmR9LiBjb250YWlucyBpbnZhbGlkIGNoYXJhY3RlcnM6ICR7bX1gXG4gICAgKTtcbiAgaWYgKGNvbW1hbmQuaW5jbHVkZXMoXCIgfCBcIikpIHtcbiAgICBjb25zdCBjbWRzID0gY29tbWFuZC5zcGxpdChcIiB8IFwiKTtcbiAgICBjb25zdCBzcGF3bnMgPSBbXTtcbiAgICBjb25zdCBjb250cm9sbGVycyA9IG5ldyBBcnJheShjbWRzLmxlbmd0aCk7XG4gICAgY29udHJvbGxlcnNbMF0gPSBhYm9ydDtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNtZHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmIChpICE9PSAwKVxuICAgICAgICBjb250cm9sbGVyc1tpXSA9IGNoYWluQWJvcnRDb250cm9sbGVyKGNvbnRyb2xsZXJzW2kgLSAxXS5zaWduYWwpO1xuICAgICAgc3Bhd25zLnB1c2goc3Bhd25Jbm5lcihjbWRzW2ldLCBjb250cm9sbGVyc1tpXSkpO1xuICAgICAgaWYgKGkgPT09IDApIGNvbnRpbnVlO1xuICAgICAgc3Bhd25zW2kgLSAxXS5zdGRvdXQucGlwZShzcGF3bnNbaV0uc3RkaW4pO1xuICAgIH1cbiAgICByZXR1cm4gc3Bhd25zW2NtZHMubGVuZ3RoIC0gMV07XG4gIH1cblxuICByZXR1cm4gc3Bhd25Jbm5lcihjb21tYW5kLCBhYm9ydCk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEV4ZWN1dGVzIGEgY29tbWFuZCBhc3luY2hyb25vdXNseSB3aXRoIGN1c3RvbWl6YWJsZSBvdXRwdXQgaGFuZGxpbmcuXG4gKiBAc3VtbWFyeSBUaGlzIGZ1bmN0aW9uIHJ1bnMgYSBzaGVsbCBjb21tYW5kIGFzIGEgY2hpbGQgcHJvY2VzcywgcHJvdmlkaW5nIGZpbmUtZ3JhaW5lZFxuICogY29udHJvbCBvdmVyIGl0cyBleGVjdXRpb24gYW5kIG91dHB1dCBoYW5kbGluZy4gSXQgc3VwcG9ydHMgY3VzdG9tIG91dHB1dCB3cml0ZXJzLFxuICogYWxsb3dzIGZvciBjb21tYW5kIGFib3J0aW9uLCBhbmQgY2FwdHVyZXMgYm90aCBzdGRvdXQgYW5kIHN0ZGVyci5cbiAqXG4gKiBAdGVtcGxhdGUgUiAtIFRoZSB0eXBlIG9mIHRoZSByZXNvbHZlZCB2YWx1ZSBmcm9tIHRoZSBjb21tYW5kIGV4ZWN1dGlvbi5cbiAqXG4gKiBAcGFyYW0gY29tbWFuZCAtIFRoZSBjb21tYW5kIHRvIHJ1biwgZWl0aGVyIGFzIGEgc3RyaW5nIG9yIGFuIGFycmF5IG9mIHN0cmluZ3MuXG4gKiBAcGFyYW0gb3B0cyAtIFNwYXduIG9wdGlvbnMgZm9yIHRoZSBjaGlsZCBwcm9jZXNzLiBEZWZhdWx0cyB0byBhbiBlbXB0eSBvYmplY3QuXG4gKiBAcGFyYW0gb3V0cHV0Q29uc3RydWN0b3IgLSBDb25zdHJ1Y3RvciBmb3IgdGhlIG91dHB1dCB3cml0ZXIuIERlZmF1bHRzIHRvIFN0YW5kYXJkT3V0cHV0V3JpdGVyLlxuICogQHBhcmFtIGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cyB0byBwYXNzIHRvIHRoZSBvdXRwdXQgY29uc3RydWN0b3IuXG4gKiBAcmV0dXJuIHtDb21tYW5kUmVzdWx0fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgY29tbWFuZCByZXN1bHQgb2YgdHlwZSBSLlxuICpcbiAqIEBmdW5jdGlvbiBydW5Db21tYW5kXG4gKlxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAqICAgcGFydGljaXBhbnQgcnVuQ29tbWFuZFxuICogICBwYXJ0aWNpcGFudCBPdXRwdXRXcml0ZXJcbiAqICAgcGFydGljaXBhbnQgQ2hpbGRQcm9jZXNzXG4gKiAgIENhbGxlci0+PnJ1bkNvbW1hbmQ6IENhbGwgd2l0aCBjb21tYW5kIGFuZCBvcHRpb25zXG4gKiAgIHJ1bkNvbW1hbmQtPj5PdXRwdXRXcml0ZXI6IENyZWF0ZSBuZXcgaW5zdGFuY2VcbiAqICAgcnVuQ29tbWFuZC0+Pk91dHB1dFdyaXRlcjogUGFyc2UgY29tbWFuZFxuICogICBydW5Db21tYW5kLT4+Q2hpbGRQcm9jZXNzOiBTcGF3biBwcm9jZXNzXG4gKiAgIENoaWxkUHJvY2Vzcy0tPj5ydW5Db21tYW5kOiBSZXR1cm4gcHJvY2VzcyBvYmplY3RcbiAqICAgcnVuQ29tbWFuZC0+PkNoaWxkUHJvY2VzczogU2V0IHVwIGV2ZW50IGxpc3RlbmVyc1xuICogICBsb29wIEZvciBlYWNoIHN0ZG91dCBkYXRhXG4gKiAgICAgQ2hpbGRQcm9jZXNzLT4+cnVuQ29tbWFuZDogRW1pdCBzdGRvdXQgZGF0YVxuICogICAgIHJ1bkNvbW1hbmQtPj5PdXRwdXRXcml0ZXI6IEhhbmRsZSBzdGRvdXQgZGF0YVxuICogICBlbmRcbiAqICAgbG9vcCBGb3IgZWFjaCBzdGRlcnIgZGF0YVxuICogICAgIENoaWxkUHJvY2Vzcy0+PnJ1bkNvbW1hbmQ6IEVtaXQgc3RkZXJyIGRhdGFcbiAqICAgICBydW5Db21tYW5kLT4+T3V0cHV0V3JpdGVyOiBIYW5kbGUgc3RkZXJyIGRhdGFcbiAqICAgZW5kXG4gKiAgIENoaWxkUHJvY2Vzcy0+PnJ1bkNvbW1hbmQ6IEVtaXQgZXJyb3IgKGlmIGFueSlcbiAqICAgcnVuQ29tbWFuZC0+Pk91dHB1dFdyaXRlcjogSGFuZGxlIGVycm9yXG4gKiAgIENoaWxkUHJvY2Vzcy0+PnJ1bkNvbW1hbmQ6IEVtaXQgZXhpdFxuICogICBydW5Db21tYW5kLT4+T3V0cHV0V3JpdGVyOiBIYW5kbGUgZXhpdFxuICogICBPdXRwdXRXcml0ZXItLT4+cnVuQ29tbWFuZDogUmVzb2x2ZSBvciByZWplY3QgcHJvbWlzZVxuICogICBydW5Db21tYW5kLS0+PkNhbGxlcjogUmV0dXJuIENvbW1hbmRSZXN1bHRcbiAqXG4gKiBAbWVtYmVyT2YgbW9kdWxlOnV0aWxzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBydW5Db21tYW5kPFIgPSBzdHJpbmc+KFxuICBjb21tYW5kOiBzdHJpbmcsXG4gIG9wdHM6IFNwYXduT3B0aW9uc1dpdGhvdXRTdGRpbyA9IHt9LFxuICBvdXRwdXRDb25zdHJ1Y3RvcjogT3V0cHV0V3JpdGVyQ29uc3RydWN0b3I8XG4gICAgUixcbiAgICBTdGFuZGFyZE91dHB1dFdyaXRlcjxSPixcbiAgICBFcnJvclxuICA+ID0gU3RhbmRhcmRPdXRwdXRXcml0ZXI8Uj4sXG4gIC4uLmFyZ3M6IHVua25vd25bXVxuKTogQ29tbWFuZFJlc3VsdDxSPiB7XG4gIGNvbnN0IGxvZ2dlciA9IExvZ2dpbmcuZm9yKHJ1bkNvbW1hbmQpO1xuICBjb25zdCBhYm9ydCA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcblxuICBjb25zdCByZXN1bHQ6IE9taXQ8Q29tbWFuZFJlc3VsdCwgXCJwcm9taXNlXCIgfCBcInBpcGVcIj4gPSB7XG4gICAgYWJvcnQ6IGFib3J0LFxuICAgIGNvbW1hbmQ6IGNvbW1hbmQsXG4gICAgbG9nczogW10sXG4gICAgZXJyczogW10sXG4gIH07XG5cbiAgY29uc3QgbG9jayA9IG5ldyBQcm9taXNlPFI+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBsZXQgb3V0cHV0O1xuICAgIHRyeSB7XG4gICAgICBvdXRwdXQgPSBuZXcgb3V0cHV0Q29uc3RydWN0b3IoXG4gICAgICAgIGNvbW1hbmQsXG4gICAgICAgIHtcbiAgICAgICAgICByZXNvbHZlLFxuICAgICAgICAgIHJlamVjdCxcbiAgICAgICAgfSxcbiAgICAgICAgLi4uYXJnc1xuICAgICAgKTtcblxuICAgICAgcmVzdWx0LmNtZCA9IHNwYXduQ29tbWFuZDxSPihvdXRwdXQsIGNvbW1hbmQsIG9wdHMsIGFib3J0LCBsb2dnZXIpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHJldHVybiByZWplY3QobmV3IEVycm9yKGBFcnJvciBydW5uaW5nIGNvbW1hbmQgJHtjb21tYW5kfTogJHtlfWApKTtcbiAgICB9XG5cbiAgICByZXN1bHQuY21kLnN0ZG91dC5zZXRFbmNvZGluZyhcInV0ZjhcIik7XG5cbiAgICByZXN1bHQuY21kLnN0ZG91dC5vbihcImRhdGFcIiwgKGNodW5rOiBhbnkpID0+IHtcbiAgICAgIGNodW5rID0gY2h1bmsudG9TdHJpbmcoKTtcbiAgICAgIHJlc3VsdC5sb2dzLnB1c2goY2h1bmspO1xuICAgICAgb3V0cHV0LmRhdGEoY2h1bmspO1xuICAgIH0pO1xuXG4gICAgcmVzdWx0LmNtZC5zdGRlcnIub24oXCJkYXRhXCIsIChkYXRhOiBhbnkpID0+IHtcbiAgICAgIGRhdGEgPSBkYXRhLnRvU3RyaW5nKCk7XG4gICAgICByZXN1bHQuZXJycy5wdXNoKGRhdGEpO1xuICAgICAgb3V0cHV0LmVycm9yKGRhdGEpO1xuICAgIH0pO1xuXG4gICAgcmVzdWx0LmNtZC5vbmNlKFwiZXJyb3JcIiwgKGVycjogRXJyb3IpID0+IHtcbiAgICAgIG91dHB1dC5leGl0KGVyci5tZXNzYWdlLCByZXN1bHQuZXJycyk7XG4gICAgfSk7XG5cbiAgICByZXN1bHQuY21kLm9uY2UoXCJleGl0XCIsIChjb2RlOiBudW1iZXIgPSAwKSA9PiB7XG4gICAgICBpZiAoYWJvcnQuc2lnbmFsLmFib3J0ZWQgJiYgY29kZSA9PT0gbnVsbCkgY29kZSA9IEFib3J0Q29kZSBhcyBhbnk7XG4gICAgICBvdXRwdXQuZXhpdChjb2RlLCBjb2RlID09PSAwID8gcmVzdWx0LmxvZ3MgOiByZXN1bHQuZXJycyk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIE9iamVjdC5hc3NpZ24ocmVzdWx0LCB7XG4gICAgcHJvbWlzZTogbG9jayxcbiAgICBwaXBlOiBhc3luYyA8RT4oY2I6IChyOiBSKSA9PiBFKSA9PiB7XG4gICAgICBjb25zdCBsID0gbG9nZ2VyLmZvcihcInBpcGVcIik7XG4gICAgICB0cnkge1xuICAgICAgICBsLnZlcmJvc2UoYEV4ZWN1dGluZyBwaXBlIGZ1bmN0aW9uICR7Y29tbWFuZH0uLi5gKTtcbiAgICAgICAgY29uc3QgcmVzdWx0OiBSID0gYXdhaXQgbG9jaztcbiAgICAgICAgbC52ZXJib3NlKGBQaXBpbmcgb3V0cHV0IHRvICR7Y2IubmFtZX06ICR7cmVzdWx0fWApO1xuICAgICAgICByZXR1cm4gY2IocmVzdWx0KTtcbiAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgbC5lcnJvcihgRXJyb3IgcGlwaW5nIGNvbW1hbmQgb3V0cHV0OiAke2V9YCk7XG4gICAgICAgIHRocm93IGU7XG4gICAgICB9XG4gICAgfSxcbiAgfSk7XG5cbiAgcmV0dXJuIHJlc3VsdCBhcyBDb21tYW5kUmVzdWx0PFI+O1xufVxuIl19