projen
Version:
CDK for software projects
689 lines • 92.4 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.TaskRuntime = void 0;
exports.systemShell = systemShell;
const child_process = __importStar(require("child_process"));
const fs_1 = require("fs");
const path_1 = require("path");
const path = __importStar(require("path"));
const util_1 = require("util");
const chalk_1 = require("chalk");
const common_1 = require("../common");
const logging = __importStar(require("../logging"));
const dax_1 = require("../util/dax");
const exec_1 = require("../util/exec");
// avoids a (false positive) esbuild warning about incorrect imports.
// `?.default ?? module` keeps this working both as a plain CommonJS require and
// when the dependency is interop-wrapped inside the bundled run-task.cjs (where
// `require(...)` may yield `{ default: fn }` instead of the function). See
// projen#4407 ("parseConflictJSON is not a function" after eject).
// eslint-disable-next-line @typescript-eslint/no-require-imports
const parseConflictJSONModule = require("parse-conflict-json");
const parseConflictJSON = parseConflictJSONModule?.default ?? parseConflictJSONModule;
const ENV_TRIM_LEN = 20;
const ARGS_MARKER = "$@";
const QUOTED_ARGS_MARKER = `"${ARGS_MARKER}"`;
/**
* Renders args for splicing into a string command, escaped for whichever shell
* will parse that command.
*
* Everything except `cmd.exe` gets POSIX single-quoting, which survives dax's
* built-in shell and any POSIX shell losslessly. `cmd.exe` has no single-quote
* syntax, so it keeps the double-quoted form.
*/
function escapeArgsFor(shell, args) {
return isCmdExe(shell)
? args.map(quoteArgCmd).join(" ")
: (0, dax_1.escapeCommand)(args);
}
/**
* Whether a resolved shell means the host's `cmd.exe`: the only target that
* cannot parse POSIX quoting.
*/
function isCmdExe(shell) {
return shell === "system" && process.platform === "win32";
}
/**
* Double-quotes a single argument for `cmd.exe`, escaping the characters that
* stay special inside double quotes. Note that `cmd.exe` itself has no in-quote
* escape - `\"` is understood by the receiving program's argv parser, not by the
* shell - and `%VAR%` still expands, so not every value can be passed verbatim.
*/
function quoteArgCmd(arg) {
return '"' + arg.replace(/(["$`\\])/g, "\\$1") + '"';
}
/**
* dax's built-in cross-platform shell only implements a subset of POSIX shell
* syntax and throws a terse `Not implemented: ...` for the rest. Rewrite those
* into a short, actionable error that points at the system-shell escape hatch;
* pass every other error through unchanged.
*/
function enrichBuiltinShellError(error, command) {
const message = error instanceof Error ? error.message : String(error);
if (!/Not implemented:/.test(message)) {
/* v8 ignore next */
return error;
}
const commandLine = Array.isArray(command) ? command.join(" ") : command;
return new Error("projen's built-in shell can't run this command:\n" +
` ${commandLine}\n` +
"To use your system's shell instead, set this task to TaskShell.system().");
}
/**
* The runtime component of the tasks engine.
*/
class TaskRuntime {
/**
* The project-relative path of the tasks manifest file.
*/
static MANIFEST_FILE = path.posix.join(common_1.PROJEN_DIR, "tasks.json");
/**
* One-shot entrypoint for the standalone task runner.
*
* Creates a runtime rooted at the current working directory, runs the named
* task, and converts any failure into a non-zero process exit code. This is
* the single line invoked by the bundled `scripts/run-task.cjs` that
* "projen eject" emits, which keeps the generated bundle footer trivial.
*
* @param name The name of the task to run. Defaults to `process.argv[2]`.
*/
static async main(name = process.argv[2]) {
try {
await new TaskRuntime(".").runTask(name);
}
catch (e) {
console.error(e?.stack ?? String(e));
process.exit(1);
}
}
/**
* The contents of tasks.json
*/
_manifest = { tasks: {} };
/**
* The raw contents of the currently loaded manifest, used to detect changes
* on disk so the runtime can reload a regenerated manifest mid-run.
*/
_identity;
/**
* The root directory of the project and the cwd for executing tasks.
*/
workdir;
constructor(workdir) {
this.workdir = (0, path_1.resolve)(workdir);
// Perform the initial load. This also verifies the manifest's schema
// version.
this.reloadManifestIfChanged();
}
/**
* The contents of tasks.json
*/
get manifest() {
return this._manifest;
}
/**
* The absolute path of the tasks manifest file.
*/
get manifestPath() {
return (0, path_1.join)(this.workdir, TaskRuntime.MANIFEST_FILE);
}
/**
* The tasks in this project.
*/
get tasks() {
return Object.values(this.manifest.tasks ?? {});
}
/**
* Find a task by name, or `undefined` if not found.
*/
tryFindTask(name) {
if (!this.manifest.tasks) {
return undefined;
}
return this.manifest.tasks[name];
}
/**
* Runs the task.
* @param name The task name.
*/
async runTask(name, parents = [], args = [], env = {}, options = {}) {
// A previously executed task (most importantly the "default"/synth task,
// which `build` spawns first) may have regenerated `.projen/tasks.json`.
// Pick up any such changes before resolving and running this task so we
// never execute a stale, in-memory definition.
this.reloadManifestIfChanged();
const task = this.tryFindTask(name);
if (!task) {
throw new Error(`cannot find command ${name}`);
}
const runner = new RunTask(this, task, parents, args, env);
return options.captureOutput ? runner.runCapturingOutput() : runner.run();
}
/**
* Re-reads the tasks manifest from disk if its contents changed since it was
* last loaded, verifying its schema version along the way.
*
* Change detection compares the raw file contents, so an unchanged manifest
* is not re-verified or re-adopted.
*/
reloadManifestIfChanged() {
if (!(0, fs_1.existsSync)(this.manifestPath)) {
// No manifest on disk: treat as an empty project (legacy behavior).
this._manifest = { tasks: {} };
this._identity = undefined;
return;
}
const raw = (0, fs_1.readFileSync)(this.manifestPath, "utf-8");
if (raw === this._identity) {
return; // unchanged since the last load
}
const manifest = parseConflictJSON(raw, undefined, "theirs");
// A previously loaded manifest means this is a *reload* (e.g. the
// "default"/synth task regenerated the file mid-run), as opposed to the
// initial load performed by the constructor.
const isReload = this._identity !== undefined;
this.verifyManifest(manifest);
this._manifest = manifest;
this._identity = raw;
if (isReload) {
logging.debug(`${TaskRuntime.MANIFEST_FILE} changed on disk; successfully loaded the new tasks manifest.`);
}
}
/**
* Validates a freshly read manifest:
*
* - Legacy manifests (no `manifestVersion`) are accepted as-is for backwards
* compatibility.
* - Manifests from a newer projen (a higher `manifestVersion`) are accepted
* with a warning, since this runtime may not understand the schema.
*/
verifyManifest(manifest) {
// Backwards compatibility: manifests generated before versioning carry no
// version.
if (manifest.manifestVersion === undefined) {
return;
}
if (manifest.manifestVersion > common_1.TASKS_MANIFEST_VERSION) {
logging.warn(`${TaskRuntime.MANIFEST_FILE} was generated by a newer version of projen ` +
`(manifest version ${manifest.manifestVersion}, this projen supports up to ${common_1.TASKS_MANIFEST_VERSION}). ` +
`Some tasks may not behave as expected; consider upgrading projen.`);
}
}
}
exports.TaskRuntime = TaskRuntime;
class RunTask {
runtime;
task;
args;
envParam;
env = {};
parents;
workdir;
// When set, every step's stdout is captured and accumulated (for a spawned
// task whose aggregate output the caller wants).
captureAll = false;
captured = [];
// `outputEnv` captures, propagated to spawned subtasks (exec/builtin steps
// see them via `this.env`).
capturedEnv = {};
constructor(runtime, task, parents = [], args = [], envParam = {}) {
this.runtime = runtime;
this.task = task;
this.args = args;
this.envParam = envParam;
this.workdir = task.cwd ?? this.runtime.workdir;
this.parents = parents;
}
/**
* Runs the task, capturing and returning the trimmed, newline-joined stdout
* of all its steps (and any nested spawned tasks) in execution order.
*/
async runCapturingOutput() {
this.captureAll = true;
await this.run();
return this.captured.join("\n").trim();
}
/**
* Records a step's captured (trimmed) stdout: into `outputEnv` for later
* steps (and propagated to spawned subtasks), and into the run's aggregate
* output when capturing everything.
*/
recordCapture(outputEnv, value) {
if (outputEnv) {
this.env[outputEnv] = value;
this.capturedEnv[outputEnv] = value;
}
if (this.captureAll) {
this.captured.push(value);
}
}
/**
* Executes the task. This was previously done in the constructor, but is now
* an async method since shell execution is asynchronous (e.g. dax on
* Windows).
*/
async run() {
const { task, args, parents } = this;
if (!task.steps || task.steps.length === 0) {
this.logDebug((0, chalk_1.gray)("No actions have been specified for this task."));
return;
}
this.env = await this.resolveEnvironment(this.envParam, parents, this.resolveShell());
const envlogs = [];
for (const [k, v] of Object.entries(this.env)) {
const vv = v ?? "";
const trimmed = vv.length > ENV_TRIM_LEN ? vv.substring(0, ENV_TRIM_LEN) + "..." : vv;
envlogs.push(`${k}=${trimmed}`);
}
if (envlogs.length) {
this.logDebug((0, chalk_1.gray)(`${(0, chalk_1.underline)("env")}: ${envlogs.join(" ")}`));
}
// evaluate condition
if (!(await this.evalCondition(task, this.resolveShell()))) {
this.log("condition exited with non-zero - skipping");
return;
}
// verify we required environment variables are defined
const merged = { ...process.env, ...this.env };
const missing = new Array();
for (const name of task.requiredEnv ?? []) {
if (!(name in merged)) {
missing.push(name);
}
}
if (missing.length > 0) {
throw new Error(`missing required environment variables: ${missing.join(",")}`);
}
for (const step of task.steps) {
const stepShell = this.resolveShell(step);
// evaluate step condition
if (!(await this.evalCondition(step, stepShell))) {
this.log("condition exited with non-zero - skipping");
continue;
}
const argsList = [
...(step.args || []),
...(step.receiveArgs ? args : []),
].map((a) => a.toString());
if (step.say) {
logging.info(this.fmtLog(step.say));
}
if (step.spawn) {
const capture = this.captureAll || !!step.outputEnv;
const output = await this.runtime.runTask(step.spawn, [...this.parents, this.task.name], argsList, { ...this.capturedEnv, ...step.env }, { captureOutput: capture });
if (typeof output === "string") {
this.recordCapture(step.outputEnv, output);
}
}
const execs = step.exec ? [step.exec] : [];
// Parse step-specific environment variables
const env = await this.evalEnvironment(step.env ?? {}, stepShell);
if (step.builtin) {
execs.push(this.renderBuiltin(step.builtin));
}
// `execArgs` is an explicit argv (the program followed by its arguments).
// It is handed to `shell()` as an array rather than a rendered string, so
// it runs without a shell and every element is passed through verbatim -
// which is what lets callers avoid thinking about quoting. Fixed/received
// args are spliced in wherever a `$@` marker element appears (mirroring
// the string `exec` behavior), or appended at the end if there is none.
if (step.execArgs) {
const argv = [];
let placed = false;
for (const element of step.execArgs) {
if (element === ARGS_MARKER) {
argv.push(...argsList);
placed = true;
}
else {
argv.push(element);
}
}
if (!placed) {
argv.push(...argsList);
}
execs.push(argv);
}
for (const exec of execs) {
let command = exec;
// A string command is a shell line: splice task args in per the `$@`
// marker rules. An `execArgs` argv already carries its args, untouched.
if (typeof command === "string") {
if (command.includes(QUOTED_ARGS_MARKER)) {
// `"$@"`: splice each arg in as a separate verbatim word (like
// bash's quoted `"$@"`), so whitespace and metacharacters survive.
command = command.replace(QUOTED_ARGS_MARKER, escapeArgsFor(stepShell, argsList));
}
else if (command.includes(ARGS_MARKER)) {
command = command.replace(ARGS_MARKER, argsList.join(" "));
}
else {
command = [command, ...argsList].join(" ");
}
}
const cwd = step.cwd;
const capture = this.captureAll || !!step.outputEnv;
// A thrown error (e.g. spawn failure) propagates; a non-zero exit is
// reported via `result.status`.
const result = await this.shell({
command,
cwd,
extraEnv: env,
shell: stepShell,
captureOutput: capture,
});
if (result.status !== 0) {
throw new Error(`Task "${this.fullname}" failed when executing "${Array.isArray(command) ? command.join(" ") : command}" (cwd: ${(0, path_1.resolve)(cwd ?? this.workdir)})`);
}
if (capture) {
const stdout = result.stdout?.toString("utf-8").trim() ?? "";
this.recordCapture(step.outputEnv, stdout);
}
}
}
}
/**
* Determines if a task should be executed based on "condition".
*
* @returns true if the task should be executed or false if the condition
* evaluates to false (exits with non-zero), indicating that the task should
* be skipped.
*/
async evalCondition(taskOrStep, shell) {
// no condition, carry on
if (!taskOrStep.condition) {
return true;
}
this.log((0, chalk_1.gray)(`${(0, chalk_1.underline)("condition")}: ${taskOrStep.condition}`));
const result = await this.shell({
command: taskOrStep.condition,
quiet: true,
shell,
});
if (result.status === 0) {
return true;
}
else {
return false;
}
}
/**
* Evaluates environment variables from shell commands (e.g. `$(xx)`)
*/
async evalEnvironment(env, shell) {
const output = {};
for (const [key, value] of Object.entries(env ?? {})) {
if (String(value).startsWith("$(") && String(value).endsWith(")")) {
const query = value.substring(2, value.length - 1);
const result = await this.shell({
command: query,
quiet: true,
captureOutput: true,
shell,
});
if (result.status !== 0) {
const error = result.error
? result.error.stack
: result.stderr?.toString().trim() ||
result.stdout?.toString().trim() ||
`command exited with code ${result.status}`;
logging.warn(this.fmtLog(`${(0, chalk_1.underline)(key)}: unable to evaluate "${query}". Environment variable will be skipped. Check that the command exists and runs successfully.`));
logging.warn(this.fmtLog(`${(0, chalk_1.underline)(key)}: ${error}`));
}
else {
output[key] = result.stdout?.toString("utf-8").trim() ?? "";
}
}
else {
output[key] = value;
}
}
return output;
}
/**
* Renders the runtime environment for a task. Namely, it supports this syntax
* `$(xx)` for allowing environment to be evaluated by executing a shell
* command and obtaining its result.
*/
async resolveEnvironment(envParam, parents, shell) {
let env = this.runtime.manifest.env ?? {};
// add env from all parent tasks one by one
for (const parent of parents) {
env = {
...env,
...(this.runtime.tryFindTask(parent)?.env ?? {}),
};
}
// apply task environment, then the specific env last
env = {
...env,
...(this.task.env ?? {}),
...envParam,
};
return this.evalEnvironment(env, shell);
}
/**
* Resolves the shell for a step's command (or the task's, when no step is
* given): step, then task, then project default, then "projen".
*/
resolveShell(step) {
return (step?.shell ?? this.task.shell ?? this.runtime.manifest.shell ?? "projen");
}
/**
* Returns the "full name" of the task which includes all it's parent task names concatenated by chevrons.
*/
get fullname() {
return [...this.parents, this.task.name].join(" » ");
}
log(...args) {
logging.verbose(this.fmtLog(...args));
}
logDebug(...args) {
logging.debug(this.fmtLog(...args));
}
fmtLog(...args) {
return (0, util_1.format)(`${(0, chalk_1.underline)(this.fullname)} |`, ...args);
}
async shell(options) {
const quiet = options.quiet ?? false;
if (!quiet) {
const log = new Array();
log.push(Array.isArray(options.command)
? options.command.join(" ")
: options.command);
if (options.cwd) {
log.push(`(cwd: ${options.cwd})`);
}
this.log(log.join(" "));
}
const cwd = options.cwd ?? this.workdir;
if (!(0, fs_1.existsSync)(cwd) || !(0, fs_1.statSync)(cwd).isDirectory()) {
throw new Error(`invalid workdir (cwd): ${cwd} must be an existing directory`);
}
// The resolved shell is one of:
// - "projen" (default): dax's in-process cross-platform shell, so POSIX-style
// task syntax (`mkdir -p`, `&&`, `$VAR`, ...) works the same everywhere.
// - "system": the host's native shell (`/bin/sh`, or `cmd.exe` on Windows).
// - an argv, e.g. ["bash","-c"]: a shell invocation with the command appended
// as its final argument.
const shell = options.shell ?? "projen";
if (typeof shell === "string" && shell !== "projen" && shell !== "system") {
throw new Error(`unknown built-in shell ${JSON.stringify(shell)}; use the built-in "projen" or "system" shells, or a TaskShell.command([...]) invocation`);
}
const capture = options.captureOutput ?? false;
// Quiet captures (`$(...)`, conditions) stay silent; visible captures
// (`outputEnv`) stream live while still buffering.
const stream = capture && !quiet;
const command = options.command;
const env = {
...process.env,
...this.env,
...options.extraEnv,
};
// "system": the host-native engine. A string command runs through the OS
// shell; an `execArgs` argv is spawned directly (shell-free), so the real
// binary runs with no dax built-ins. (Only `$(...)`/condition eval captures,
// and those always pass a string, so an array command never needs capture.)
if (shell === "system") {
if (Array.isArray(command)) {
const [program, ...args] = command;
try {
(0, exec_1.tool)(program).run(args, { cwd, env, inheritStdio: true });
return { status: 0 };
}
catch (e) {
if (typeof e?.status === "number") {
return { status: e.status };
}
throw e;
}
}
return systemShell(command, { cwd, env, capture, stream });
}
// Otherwise run through dax: the "projen" shell or an explicit invocation.
const builder = this.buildDaxCommand(command, shell);
// `inheritPiped` streams and buffers; `piped` buffers quietly. stderr is
// buffered only for quiet captures, so it can surface in errors.
const stdoutMode = capture
? stream
? "inheritPiped"
: "piped"
: "inherit";
const stderrMode = capture && !stream ? "piped" : "inherit";
let result;
try {
result = await builder
.cwd(cwd)
.env(env)
.stdout(stdoutMode)
.stderr(stderrMode)
.noThrow();
}
catch (e) {
// dax's in-process shell throws a terse `Not implemented: ...` for shell
// syntax it does not support (e.g. `$(...)` command substitution); turn
// that into an actionable error that points at the system-shell escape
// hatch. Other errors pass through unchanged.
throw enrichBuiltinShellError(e, command);
}
return {
status: result.code,
stdout: capture ? Buffer.from(result.stdoutBytes) : null,
stderr: capture && !stream ? Buffer.from(result.stderrBytes) : null,
};
}
/**
* Builds the dax command for the "projen" shell or an explicit invocation.
* (The "system" shell is handled host-side, not here.) `command` is a shell
* line (string) or an `execArgs` argv (string[]); `shell` is `"projen"` or an
* invocation argv such as `["bash", "-c"]`.
*/
buildDaxCommand(command, shell) {
// An invocation (e.g. ["bash","-c"], ["npx","--no","-c"]): append the
// command as its final argument. A string is appended as-is; an `execArgs`
// argv is rendered to a quoted command line so the shell re-parses the same
// argv. That rendering assumes a POSIX-style shell, which is what such an
// invocation is (`bash -c`, `sh -c`, `npx -c`, ...).
if (Array.isArray(shell)) {
const [program, ...flags] = shell;
const commandLine = Array.isArray(command)
? (0, dax_1.escapeCommand)(command)
: command;
return (0, dax_1.$) `${program} ${[...flags, commandLine]}`;
}
// The built-in "projen" shell (dax).
return Array.isArray(command)
? // execArgs: shell-free argv (each element escaped; `.cmd` shims resolved).
(0, dax_1.$) `${command[0]} ${command.slice(1)}`
: // string command, parsed in-process by dax's cross-platform shell.
dax_1.$.raw `${command}`;
}
renderBuiltin(builtin) {
// Locate projen's package root by walking up from this module's directory
// until we find a package.json. This works whether the code runs from the
// compiled file (lib/cli/task-runtime.js) or from the bundled run-task.cjs
// (lib/run-task.cjs), which live at different depths - so a hard-coded
// relative path to package.json would be wrong in one of the two cases.
let moduleRoot = __dirname;
while (!(0, fs_1.existsSync)((0, path_1.join)(moduleRoot, "package.json"))) {
const parent = (0, path_1.dirname)(moduleRoot);
if (parent === moduleRoot) {
throw new Error("unable to locate the projen package root");
}
moduleRoot = parent;
}
const program = require.resolve((0, path_1.join)(moduleRoot, "lib", `${builtin}.task.js`));
return `"${process.execPath}" "${program}"`;
}
}
/**
* Runs a command line through the operating system's native shell.
*
* Calls the OS shell via `child_process` with `shell: true`.
* This backs the `system` task shell, which lets a user opt out of the built-in
* cross-platform shell and use the host's native shell instead:
* `/bin/sh`on POSIX and `cmd.exe` on Windows.
*
* Never throws for a non-zero exit (that is reported via `status`);
* a spawn failure is reported via `error`. The caller supplies the full `env`.
*/
function systemShell(command, options) {
logging.debug(`${command} (cwd: ${options.cwd})`);
const result = child_process.spawnSync(command, {
cwd: options.cwd,
shell: true,
maxBuffer: exec_1.MAX_BUFFER,
env: options.env,
// Quiet capture buffers stderr for error messages. Streamed capture
// inherits stderr and re-emits buffered stdout afterwards, since spawnSync
// can't both show and buffer the same stream at once.
stdio: options.capture
? options.stream
? ["inherit", "pipe", "inherit"]
: ["inherit", "pipe", "pipe"]
: "inherit",
});
if (options.capture && options.stream && result.stdout) {
process.stdout.write(result.stdout);
}
return {
status: result.status,
stdout: result.stdout ?? null,
stderr: result.stderr ?? null,
error: result.error,
};
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFzay1ydW50aW1lLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsaS90YXNrLXJ1bnRpbWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBdTBCQSxrQ0FpQ0M7QUF4MkJELDZEQUErQztBQUMvQywyQkFBd0Q7QUFDeEQsK0JBQThDO0FBQzlDLDJDQUE2QjtBQUM3QiwrQkFBOEI7QUFDOUIsaUNBQXdDO0FBQ3hDLHNDQUErRDtBQUMvRCxvREFBc0M7QUFFdEMscUNBQStDO0FBQy9DLHVDQUFnRDtBQUVoRCxxRUFBcUU7QUFDckUsZ0ZBQWdGO0FBQ2hGLGdGQUFnRjtBQUNoRiwyRUFBMkU7QUFDM0UsbUVBQW1FO0FBQ25FLGlFQUFpRTtBQUNqRSxNQUFNLHVCQUF1QixHQUFHLE9BQU8sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO0FBQy9ELE1BQU0saUJBQWlCLEdBQ3JCLHVCQUF1QixFQUFFLE9BQU8sSUFBSSx1QkFBdUIsQ0FBQztBQUU5RCxNQUFNLFlBQVksR0FBRyxFQUFFLENBQUM7QUFDeEIsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDO0FBQ3pCLE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxXQUFXLEdBQUcsQ0FBQztBQUU5Qzs7Ozs7OztHQU9HO0FBQ0gsU0FBUyxhQUFhLENBQUMsS0FBd0IsRUFBRSxJQUFjO0lBQzdELE9BQU8sUUFBUSxDQUFDLEtBQUssQ0FBQztRQUNwQixDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDO1FBQ2pDLENBQUMsQ0FBQyxJQUFBLG1CQUFhLEVBQUMsSUFBSSxDQUFDLENBQUM7QUFDMUIsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQVMsUUFBUSxDQUFDLEtBQXdCO0lBQ3hDLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxPQUFPLENBQUMsUUFBUSxLQUFLLE9BQU8s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SUFBSSxJQUFJO1FBQzdCLE1BQU0sRUFBRSxNQUFNLENBQUMsTUFBTSxJQUFJLElBQUk7UUFDN0IsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFLO0tBQ3BCLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgY2hpbGRfcHJvY2VzcyBmcm9tIFwiY2hpbGRfcHJvY2Vzc1wiO1xuaW1wb3J0IHsgZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCBzdGF0U3luYyB9IGZyb20gXCJmc1wiO1xuaW1wb3J0IHsgZGlybmFtZSwgam9pbiwgcmVzb2x2ZSB9IGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgeyBmb3JtYXQgfSBmcm9tIFwidXRpbFwiO1xuaW1wb3J0IHsgZ3JheSwgdW5kZXJsaW5lIH0gZnJvbSBcImNoYWxrXCI7XG5pbXBvcnQgeyBQUk9KRU5fRElSLCBUQVNLU19NQU5JRkVTVF9WRVJTSU9OIH0gZnJvbSBcIi4uL2NvbW1vblwiO1xuaW1wb3J0ICogYXMgbG9nZ2luZyBmcm9tIFwiLi4vbG9nZ2luZ1wiO1xuaW1wb3J0IHR5cGUgeyBUYXNrc01hbmlmZXN0LCBUYXNrU3BlYywgVGFza1N0ZXAgfSBmcm9tIFwiLi4vdGFzay1tb2RlbFwiO1xuaW1wb3J0IHsgJCwgZXNjYXBlQ29tbWFuZCB9IGZyb20gXCIuLi91dGlsL2RheFwiO1xuaW1wb3J0IHsgTUFYX0JVRkZFUiwgdG9vbCB9IGZyb20gXCIuLi91dGlsL2V4ZWNcIjtcblxuLy8gYXZvaWRzIGEgKGZhbHNlIHBvc2l0aXZlKSBlc2J1aWxkIHdhcm5pbmcgYWJvdXQgaW5jb3JyZWN0IGltcG9ydHMuXG4vLyBgPy5kZWZhdWx0ID8/IG1vZHVsZWAga2VlcHMgdGhpcyB3b3JraW5nIGJvdGggYXMgYSBwbGFpbiBDb21tb25KUyByZXF1aXJlIGFuZFxuLy8gd2hlbiB0aGUgZGVwZW5kZW5jeSBpcyBpbnRlcm9wLXdyYXBwZWQgaW5zaWRlIHRoZSBidW5kbGVkIHJ1bi10YXNrLmNqcyAod2hlcmVcbi8vIGByZXF1aXJlKC4uLilgIG1heSB5aWVsZCBgeyBkZWZhdWx0OiBmbiB9YCBpbnN0ZWFkIG9mIHRoZSBmdW5jdGlvbikuIFNlZVxuLy8gcHJvamVuIzQ0MDcgKFwicGFyc2VDb25mbGljdEpTT04gaXMgbm90IGEgZnVuY3Rpb25cIiBhZnRlciBlamVjdCkuXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0c1xuY29uc3QgcGFyc2VDb25mbGljdEpTT05Nb2R1bGUgPSByZXF1aXJlKFwicGFyc2UtY29uZmxpY3QtanNvblwiKTtcbmNvbnN0IHBhcnNlQ29uZmxpY3RKU09OID1cbiAgcGFyc2VDb25mbGljdEpTT05Nb2R1bGU/LmRlZmF1bHQgPz8gcGFyc2VDb25mbGljdEpTT05Nb2R1bGU7XG5cbmNvbnN0IEVOVl9UUklNX0xFTiA9IDIwO1xuY29uc3QgQVJHU19NQVJLRVIgPSBcIiRAXCI7XG5jb25zdCBRVU9URURfQVJHU19NQVJLRVIgPSBgXCIke0FSR1NfTUFSS0VSfVwiYDtcblxuLyoqXG4gKiBSZW5kZXJzIGFyZ3MgZm9yIHNwbGljaW5nIGludG8gYSBzdHJpbmcgY29tbWFuZCwgZXNjYXBlZCBmb3Igd2hpY2hldmVyIHNoZWxsXG4gKiB3aWxsIHBhcnNlIHRoYXQgY29tbWFuZC5cbiAqXG4gKiBFdmVyeXRoaW5nIGV4Y2VwdCBgY21kLmV4ZWAgZ2V0cyBQT1NJWCBzaW5nbGUtcXVvdGluZywgd2hpY2ggc3Vydml2ZXMgZGF4J3NcbiAqIGJ1aWx0LWluIHNoZWxsIGFuZCBhbnkgUE9TSVggc2hlbGwgbG9zc2xlc3NseS4gYGNtZC5leGVgIGhhcyBubyBzaW5nbGUtcXVvdGVcbiAqIHN5bnRheCwgc28gaXQga2VlcHMgdGhlIGRvdWJsZS1xdW90ZWQgZm9ybS5cbiAqL1xuZnVuY3Rpb24gZXNjYXBlQXJnc0ZvcihzaGVsbDogc3RyaW5nIHwgc3RyaW5nW10sIGFyZ3M6IHN0cmluZ1tdKTogc3RyaW5nIHtcbiAgcmV0dXJuIGlzQ21kRXhlKHNoZWxsKVxuICAgID8gYXJncy5tYXAocXVvdGVBcmdDbWQpLmpvaW4oXCIgXCIpXG4gICAgOiBlc2NhcGVDb21tYW5kKGFyZ3MpO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgYSByZXNvbHZlZCBzaGVsbCBtZWFucyB0aGUgaG9zdCdzIGBjbWQuZXhlYDogdGhlIG9ubHkgdGFyZ2V0IHRoYXRcbiAqIGNhbm5vdCBwYXJzZSBQT1NJWCBxdW90aW5nLlxuICovXG5mdW5jdGlvbiBpc0NtZEV4ZShzaGVsbDogc3RyaW5nIHwgc3RyaW5nW10pOiBib29sZWFuIHtcbiAgcmV0dXJuIHNoZWxsID09PSBcInN5c3RlbVwiICYmIHByb2Nlc3MucGxhdGZvcm0gPT09IFwid2luMzJcIjtcbn1cblxuLyoqXG4gKiBEb3VibGUtcXVvdGVzIGEgc2luZ2xlIGFyZ3VtZW50IGZvciBgY21kLmV4ZWAsIGVzY2FwaW5nIHRoZSBjaGFyYWN0ZXJzIHRoYXRcbiAqIHN0YXkgc3BlY2lhbCBpbnNpZGUgZG91YmxlIHF1b3Rlcy4gTm90ZSB0aGF0IGBjbWQuZXhlYCBpdHNlbGYgaGFzIG5vIGluLXF1b3RlXG4gKiBlc2NhcGUgLSBgXFxcImAgaXMgdW5kZXJzdG9vZCBieSB0aGUgcmVjZWl2aW5nIHByb2dyYW0ncyBhcmd2IHBhcnNlciwgbm90IGJ5IHRoZVxuICogc2hlbGwgLSBhbmQgYCVWQVIlYCBzdGlsbCBleHBhbmRzLCBzbyBub3QgZXZlcnkgdmFsdWUgY2FuIGJlIHBhc3NlZCB2ZXJiYXRpbS5cbiAqL1xuZnVuY3Rpb24gcXVvdGVBcmdDbWQoYXJnOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gJ1wiJyArIGFyZy5yZXBsYWNlKC8oW1wiJGBcXFxcXSkvZywgXCJcXFxcJDFcIikgKyAnXCInO1xufVxuXG4vKipcbiAqIGRheCdzIGJ1aWx0LWluIGNyb3NzLXBsYXRmb3JtIHNoZWxsIG9ubHkgaW1wbGVtZW50cyBhIHN1YnNldCBvZiBQT1NJWCBzaGVsbFxuICogc3ludGF4IGFuZCB0aHJvd3MgYSB0ZXJzZSBgTm90IGltcGxlbWVudGVkOiAuLi5gIGZvciB0aGUgcmVzdC4gUmV3cml0ZSB0aG9zZVxuICogaW50byBhIHNob3J0LCBhY3Rpb25hYmxlIGVycm9yIHRoYXQgcG9pbnRzIGF0IHRoZSBzeXN0ZW0tc2hlbGwgZXNjYXBlIGhhdGNoO1xuICogcGFzcyBldmVyeSBvdGhlciBlcnJvciB0aHJvdWdoIHVuY2hhbmdlZC5cbiAqL1xuZnVuY3Rpb24gZW5yaWNoQnVpbHRpblNoZWxsRXJyb3IoXG4gIGVycm9yOiB1bmtub3duLFxuICBjb21tYW5kOiBzdHJpbmcgfCBzdHJpbmdbXSxcbik6IHVua25vd24ge1xuICBjb25zdCBtZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpO1xuICBpZiAoIS9Ob3QgaW1wbGVtZW50ZWQ6Ly50ZXN0KG1lc3NhZ2UpKSB7XG4gICAgLyogdjggaWdub3JlIG5leHQgKi9cbiAgICByZXR1cm4gZXJyb3I7XG4gIH1cblxuICBjb25zdCBjb21tYW5kTGluZSA9IEFycmF5LmlzQXJyYXkoY29tbWFuZCkgPyBjb21tYW5kLmpvaW4oXCIgXCIpIDogY29tbWFuZDtcbiAgcmV0dXJuIG5ldyBFcnJvcihcbiAgICBcInByb2plbidzIGJ1aWx0LWluIHNoZWxsIGNhbid0IHJ1biB0aGlzIGNvbW1hbmQ6XFxuXCIgK1xuICAgICAgYCAgJHtjb21tYW5kTGluZX1cXG5gICtcbiAgICAgIFwiVG8gdXNlIHlvdXIgc3lzdGVtJ3Mgc2hlbGwgaW5zdGVhZCwgc2V0IHRoaXMgdGFzayB0byBUYXNrU2hlbGwuc3lzdGVtKCkuXCIsXG4gICk7XG59XG5cbi8qKlxuICogTm9ybWFsaXplZCByZXN1bHQgb2YgYHNoZWxsKClgIChhIHN1YnNldCBvZiBub2RlJ3MgYFNwYXduU3luY1JldHVybnNgKS5cbiAqL1xuaW50ZXJmYWNlIFNoZWxsUmVzdWx0IHtcbiAgLyoqXG4gICAqIFRoZSBleGl0IGNvZGUgb2YgdGhlIGNvbW1hbmQsIG9yIGBudWxsYCBpZiB0aGUgcHJvY2VzcyB3YXMgdGVybWluYXRlZCBieSBhXG4gICAqIHNpZ25hbCBvciBuZXZlciBzcGF3bmVkLlxuICAgKi9cbiAgcmVhZG9ubHkgc3RhdHVzOiBudW1iZXIgfCBudWxsO1xuXG4gIC8qKlxuICAgKiBDYXB0dXJlZCBzdGRvdXQuIE9ubHkgcG9wdWxhdGVkIHdoZW4gc3Rkb3V0IGlzIHBpcGVkIChlLmcuIHdoZW4gZXZhbHVhdGluZ1xuICAgKiBlbnZpcm9ubWVudCB2YXJpYWJsZXMpOyBgbnVsbGAvYHVuZGVmaW5lZGAgd2hlbiBzdGRpbyBpcyBpbmhlcml0ZWQuXG4gICAqL1xuICByZWFkb25seSBzdGRvdXQ/OiBCdWZmZXIgfCBudWxsO1xuXG4gIC8qKlxuICAgKiBDYXB0dXJlZCBzdGRlcnIuIFNlZSBgc3Rkb3V0YC5cbiAgICovXG4gIHJlYWRvbmx5IHN0ZGVycj86IEJ1ZmZlciB8IG51bGw7XG5cbiAgLyoqXG4gICAqIEFuIGVycm9yIHJhaXNlZCB3aGlsZSBhdHRlbXB0aW5nIHRvIHNwYXduIHRoZSBjb21tYW5kIChub3QgYSBub24temVybyBleGl0XG4gICAqIGNvZGUsIHdoaWNoIGlzIHJlcG9ydGVkIHZpYSBgc3RhdHVzYCkuXG4gICAqL1xuICByZWFkb25seSBlcnJvcj86IEVycm9yO1xufVxuXG4vKipcbiAqIFRoZSBydW50aW1lIGNvbXBvbmVudCBvZiB0aGUgdGFza3MgZW5naW5lLlxuICovXG5leHBvcnQgY2xhc3MgVGFza1J1bnRpbWUge1xuICAvKipcbiAgICogVGhlIHByb2plY3QtcmVsYXRpdmUgcGF0aCBvZiB0aGUgdGFza3MgbWFuaWZlc3QgZmlsZS5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgTUFOSUZFU1RfRklMRSA9IHBhdGgucG9zaXguam9pbihcbiAgICBQUk9KRU5fRElSLFxuICAgIFwidGFza3MuanNvblwiLFxuICApO1xuXG4gIC8qKlxuICAgKiBPbmUtc2hvdCBlbnRyeXBvaW50IGZvciB0aGUgc3RhbmRhbG9uZSB0YXNrIHJ1bm5lci5cbiAgICpcbiAgICogQ3JlYXRlcyBhIHJ1bnRpbWUgcm9vdGVkIGF0IHRoZSBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5LCBydW5zIHRoZSBuYW1lZFxuICAgKiB0YXNrLCBhbmQgY29udmVydHMgYW55IGZhaWx1cmUgaW50byBhIG5vbi16ZXJvIHByb2Nlc3MgZXhpdCBjb2RlLiBUaGlzIGlzXG4gICAqIHRoZSBzaW5nbGUgbGluZSBpbnZva2VkIGJ5IHRoZSBidW5kbGVkIGBzY3JpcHRzL3J1bi10YXNrLmNqc2AgdGhhdFxuICAgKiBcInByb2plbiBlamVjdFwiIGVtaXRzLCB3aGljaCBrZWVwcyB0aGUgZ2VuZXJhdGVkIGJ1bmRsZSBmb290ZXIgdHJpdmlhbC5cbiAgICpcbiAgICogQHBhcmFtIG5hbWUgVGhlIG5hbWUgb2YgdGhlIHRhc2sgdG8gcnVuLiBEZWZhdWx0cyB0byBgcHJvY2Vzcy5hcmd2WzJdYC5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgYXN5bmMgbWFpbihuYW1lOiBzdHJpbmcgPSBwcm9jZXNzLmFyZ3ZbMl0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgbmV3IFRhc2tSdW50aW1lKFwiLlwiKS5ydW5UYXNrKG5hbWUpO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgY29uc29sZS5lcnJvcihlPy5zdGFjayA/PyBTdHJpbmcoZSkpO1xuICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgY29udGVudHMgb2YgdGFza3MuanNvblxuICAgKi9cbiAgcHJpdmF0ZSBfbWFuaWZlc3Q6IFRhc2tzTWFuaWZlc3QgPSB7IHRhc2tzOiB7fSB9O1xuXG4gIC8qKlxuICAgKiBUaGUgcmF3IGNvbnRlbnRzIG9mIHRoZSBjdXJyZW50bHkgbG9hZGVkIG1hbmlmZXN0LCB1c2VkIHRvIGRldGVjdCBjaGFuZ2VzXG4gICAqIG9uIGRpc2sgc28gdGhlIHJ1bnRpbWUgY2FuIHJlbG9hZCBhIHJlZ2VuZXJhdGVkIG1hbmlmZXN0IG1pZC1ydW4uXG4gICAqL1xuICBwcml2YXRlIF9pZGVudGl0eT86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoZSBwcm9qZWN0IGFuZCB0aGUgY3dkIGZvciBleGVjdXRpbmcgdGFza3MuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgd29ya2Rpcjogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKHdvcmtkaXI6IHN0cmluZykge1xuICAgIHRoaXMud29ya2RpciA9IHJlc29sdmUod29ya2Rpcik7XG4gICAgLy8gUGVyZm9ybSB0aGUgaW5pdGlhbCBsb2FkLiBUaGlzIGFsc28gdmVyaWZpZXMgdGhlIG1hbmlmZXN0J3Mgc2NoZW1hXG4gICAgLy8gdmVyc2lvbi5cbiAgICB0aGlzLnJlbG9hZE1hbmlmZXN0SWZDaGFuZ2VkKCk7XG4gIH1cblxuICAvKipcbiAgICogVGhlIGNvbnRlbnRzIG9mIHRhc2tzLmpzb25cbiAgICovXG4gIHB1YmxpYyBnZXQgbWFuaWZlc3QoKTogVGFza3NNYW5pZmVzdCB7XG4gICAgcmV0dXJuIHRoaXMuX21hbmlmZXN0O1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBhYnNvbHV0ZSBwYXRoIG9mIHRoZSB0YXNrcyBtYW5pZmVzdCBmaWxlLlxuICAgKi9cbiAgcHJpdmF0ZSBnZXQgbWFuaWZlc3RQYXRoKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGpvaW4odGhpcy53b3JrZGlyLCBUYXNrUnVudGltZS5NQU5JRkVTVF9GSUxFKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgdGFza3MgaW4gdGhpcyBwcm9qZWN0LlxuICAgKi9cbiAgcHVibGljIGdldCB0YXNrcygpOiBUYXNrU3BlY1tdIHtcbiAgICByZXR1cm4gT2JqZWN0LnZhbHVlcyh0aGlzLm1hbmlmZXN0LnRhc2tzID8/IHt9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5kIGEgdGFzayBieSBuYW1lLCBvciBgdW5kZWZpbmVkYCBpZiBub3QgZm91bmQuXG4gICAqL1xuICBwdWJsaWMgdHJ5RmluZFRhc2sobmFtZTogc3RyaW5nKTogVGFza1NwZWMgfCB1bmRlZmluZWQge1xuICAgIGlmICghdGhpcy5tYW5pZmVzdC50YXNrcykge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMubWFuaWZlc3QudGFza3NbbmFtZV07XG4gIH1cblxuICAvKipcbiAgICogUnVucyB0aGUgdGFzay5cbiAgICogQHBhcmFtIG5hbWUgVGhlIHRhc2sgbmFtZS5cbiAgICovXG4gIHB1YmxpYyBhc3luYyBydW5UYXNrKFxuICAgIG5hbWU6IHN0cmluZyxcbiAgICBwYXJlbnRzOiBzdHJpbmdbXSA9IFtdLFxuICAgIGFyZ3M6IEFycmF5PHN0cmluZyB8IG51bWJlcj4gPSBbXSxcbiAgICBlbnY6IHsgW25hbWU6IHN0cmluZ106IHN0cmluZyB9ID0ge30sXG4gICAgb3B0aW9uczogeyBjYXB0dXJlT3V0cHV0PzogYm9vbGVhbiB9ID0ge30sXG4gICk6IFByb21pc2U8c3RyaW5nIHwgdm9pZD4ge1xuICAgIC8vIEEgcHJldmlvdXNseSBleGVjdXRlZCB0YXNrIChtb3N0IGltcG9ydGFudGx5IHRoZSBcImRlZmF1bHRcIi9zeW50aCB0YXNrLFxuICAgIC8vIHdoaWNoIGBidWlsZGAgc3Bhd25zIGZpcnN0KSBtYXkgaGF2ZSByZWdlbmVyYXRlZCBgLnByb2plbi90YXNrcy5qc29uYC5cbiAgICAvLyBQaWNrIHVwIGFueSBzdWNoIGNoYW5nZXMgYmVmb3JlIHJlc29sdmluZyBhbmQgcnVubmluZyB0aGlzIHRhc2sgc28gd2VcbiAgICAvLyBuZXZlciBleGVjdXRlIGEgc3RhbGUsIGluLW1lbW9yeSBkZWZpbml0aW9uLlxuICAgIHRoaXMucmVsb2FkTWFuaWZlc3RJZkNoYW5nZWQoKTtcblxuICAgIGNvbnN0IHRhc2sgPSB0aGlzLnRyeUZpbmRUYXNrKG5hbWUpO1xuICAgIGlmICghdGFzaykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBjYW5ub3QgZmluZCBjb21tYW5kICR7bmFtZX1gKTtcbiAgICB9XG5cbiAgICBjb25zdCBydW5uZXIgPSBuZXcgUnVuVGFzayh0aGlzLCB0YXNrLCBwYXJlbnRzLCBhcmdzLCBlbnYpO1xuICAgIHJldHVybiBvcHRpb25zLmNhcHR1cmVPdXRwdXQgPyBydW5uZXIucnVuQ2FwdHVyaW5nT3V0cHV0KCkgOiBydW5uZXIucnVuKCk7XG4gIH1cblxuICAvKipcbiAgICogUmUtcmVhZHMgdGhlIHRhc2tzIG1hbmlmZXN0IGZyb20gZGlzayBpZiBpdHMgY29udGVudHMgY2hhbmdlZCBzaW5jZSBpdCB3YXNcbiAgICogbGFzdCBsb2FkZWQsIHZlcmlmeWluZyBpdHMgc2NoZW1hIHZlcnNpb24gYWxvbmcgdGhlIHdheS5cbiAgICpcbiAgICogQ2hhbmdlIGRldGVjdGlvbiBjb21wYXJlcyB0aGUgcmF3IGZpbGUgY29udGVudHMsIHNvIGFuIHVuY2hhbmdlZCBtYW5pZmVzdFxuICAgKiBpcyBub3QgcmUtdmVyaWZpZWQgb3IgcmUtYWRvcHRlZC5cbiAgICovXG4gIHByaXZhdGUgcmVsb2FkTWFuaWZlc3RJZkNoYW5nZWQoKTogdm9pZCB7XG4gICAgaWYgKCFleGlzdHNTeW5jKHRoaXMubWFuaWZlc3RQYXRoKSkge1xuICAgICAgLy8gTm8gbWFuaWZlc3Qgb24gZGlzazogdHJlYXQgYXMgYW4gZW1wdHkgcHJvamVjdCAobGVnYWN5IGJlaGF2aW9yKS5cbiAgICAgIHRoaXMuX21hbmlmZXN0ID0geyB0YXNrczoge30gfTtcbiAgICAgIHRoaXMuX2lkZW50aXR5ID0gdW5kZWZpbmVkO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHJhdyA9IHJlYWRGaWxlU3luYyh0aGlzLm1hbmlmZXN0UGF0aCwgXCJ1dGYtOFwiKTtcbiAgICBpZiAocmF3ID09PSB0aGlzLl9pZGVudGl0eSkge1xuICAgICAgcmV0dXJuOyAvLyB1bmNoYW5nZWQgc2luY2UgdGhlIGxhc3QgbG9hZFxuICAgIH1cblxuICAgIGNvbnN0IG1hbmlmZXN0OiBUYXNrc01hbmlmZXN0ID0gcGFyc2VDb25mbGljdEpTT04ocmF3LCB1bmRlZmluZWQsIFwidGhlaXJzXCIpO1xuXG4gICAgLy8gQSBwcmV2aW91c2x5IGxvYWRlZCBtYW5pZmVzdCBtZWFucyB0aGlzIGlzIGEgKnJlbG9hZCogKGUuZy4gdGhlXG4gICAgLy8gXCJkZWZhdWx0XCIvc3ludGggdGFzayByZWdlbmVyYXRlZCB0aGUgZmlsZSBtaWQtcnVuKSwgYXMgb3Bwb3NlZCB0byB0aGVcbiAgICAvLyBpbml0aWFsIGxvYWQgcGVyZm9ybWVkIGJ5IHRoZSBjb25zdHJ1Y3Rvci5cbiAgICBjb25zdCBpc1JlbG9hZCA9IHRoaXMuX2lkZW50aXR5ICE9PSB1bmRlZmluZWQ7XG5cbiAgICB0aGlzLnZlcmlmeU1hbmlmZXN0KG1hbmlmZXN0KTtcbiAgICB0aGlzLl9tYW5pZmVzdCA9IG1hbmlmZXN0O1xuICAgIHRoaXMuX2lkZW50aXR5ID0gcmF3O1xuXG4gICAgaWYgKGlzUmVsb2FkKSB7XG4gICAgICBsb2dnaW5nLmRlYnVnKFxuICAgICAgICBgJHtUYXNrUnVudGltZS5NQU5JRkVTVF9GSUxFfSBjaGFuZ2VkIG9uIGRpc2s7IHN1Y2Nlc3NmdWxseSBsb2FkZWQgdGhlIG5ldyB0YXNrcyBtYW5pZmVzdC5gLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGVzIGEgZnJlc2hseSByZWFkIG1hbmlmZXN0OlxuICAgKlxuICAgKiAtIExlZ2FjeSBtYW5pZmVzdHMgKG5vIGBtYW5pZmVzdFZlcnNpb25gKSBhcmUgYWNjZXB0ZWQgYXMtaXMgZm9yIGJhY2t3YXJkc1xuICAgKiAgIGNvbXBhdGliaWxpdHkuXG4gICAqIC0gTWFuaWZlc3RzIGZyb20gYSBuZXdlciBwcm9qZW4gKGEgaGlnaGVyIGBtYW5pZmVzdFZlcnNpb25gKSBhcmUgYWNjZXB0ZWRcbiAgICogICB3aXRoIGEgd2FybmluZywgc2luY2UgdGhpcyBydW50aW1lIG1heSBub3QgdW5kZXJzdGFuZCB0aGUgc2NoZW1hLlxuICAgKi9cbiAgcHJpdmF0ZSB2ZXJpZnlNYW5pZmVzdChtYW5pZmVzdDogVGFza3NNYW5pZmVzdCk6IHZvaWQge1xuICAgIC8vIEJhY2t3YXJkcyBjb21wYXRpYmlsaXR5OiBtYW5pZmVzdHMgZ2VuZXJhdGVkIGJlZm9yZSB2ZXJzaW9uaW5nIGNhcnJ5IG5vXG4gICAgLy8gdmVyc2lvbi5cbiAgICBpZiAobWFuaWZlc3QubWFuaWZlc3RWZXJzaW9uID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAobWFuaWZlc3QubWFuaWZlc3RWZXJzaW9uID4gVEFTS1NfTUFOSUZFU1RfVkVSU0lPTikge1xuICAgICAgbG9nZ2luZy53YXJuKFxuICAgICAgICBgJHtUYXNrUnVudGltZS5NQU5JRkVTVF9GSUxFfSB3YXMgZ2VuZXJhdGVkIGJ5IGEgbmV3ZXIgdmVyc2lvbiBvZiBwcm9qZW4gYCArXG4gICAgICAgICAgYChtYW5pZmVzdCB2ZXJzaW9uICR7bWFuaWZlc3QubWFuaWZlc3RWZXJzaW9ufSwgdGhpcyBwcm9qZW4gc3VwcG9ydHMgdXAgdG8gJHtUQVNLU19NQU5JRkVTVF9WRVJTSU9OfSkuIGAgK1xuICAgICAgICAgIGBTb21lIHRhc2tzIG1heSBub3QgYmVoYXZlIGFzIGV4cGVjdGVkOyBjb25zaWRlciB1cGdyYWRpbmcgcHJvamVuLmAsXG4gICAgICApO1xuICAgIH1cbiAgfVxufVxuXG5jbGFzcyBSdW5UYXNrIHtcbiAgcHJpdmF0ZSBlbnY6IHsgW25hbWU6IHN0cmluZ106IHN0cmluZyB8IHVuZGVmaW5lZCB9ID0ge307XG4gIHByaXZhdGUgcmVhZG9ubHkgcGFyZW50czogc3RyaW5nW107XG5cbiAgcHJpdmF0ZSByZWFkb25seSB3b3JrZGlyOiBzdHJpbmc7XG5cbiAgLy8gV2hlbiBzZXQsIGV2ZXJ5IHN0ZXAncyBzdGRvdXQgaXMgY2FwdHVyZWQgYW5kIGFjY3VtdWxhdGVkIChmb3IgYSBzcGF3bmVkXG4gIC8vIHRhc2sgd2hvc2UgYWdncmVnYXRlIG91dHB1dCB0aGUgY2FsbGVyIHdhbnRzKS5cbiAgcHJpdmF0ZSBjYXB0dXJlQWxsID0gZmFsc2U7XG4gIHByaXZhdGUgcmVhZG9ubHkgY2FwdHVyZWQ6IHN0cmluZ1tdID0gW107XG5cbiAgLy8gYG91dHB1dEVudmAgY2FwdHVyZXMsIHByb3BhZ2F0ZWQgdG8gc3Bhd25lZCBzdWJ0YXNrcyAoZXhlYy9idWlsdGluIHN0ZXBzXG4gIC8vIHNlZSB0aGVtIHZpYSBgdGhpcy5lbnZgKS5cbiAgcHJpdmF0ZSByZWFkb25seSBjYXB0dXJlZEVudjogeyBbbmFtZTogc3RyaW5nXTogc3RyaW5nIH0gPSB7fTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IHJ1bnRpbWU6IFRhc2tSdW50aW1lLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgdGFzazogVGFza1NwZWMsXG4gICAgcGFyZW50czogc3RyaW5nW10gPSBbXSxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGFyZ3M6IEFycmF5PHN0cmluZyB8IG51bWJlcj4gPSBbXSxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGVudlBhcmFtOiB7IFtuYW1lOiBzdHJpbmddOiBzdHJpbmcgfSA9IHt9LFxuICApIHtcbiAgICB0aGlzLndvcmtkaXIgPSB0YXNrLmN3ZCA/PyB0aGlzLnJ1bnRpbWUud29ya2RpcjtcbiAgICB0aGlzLnBhcmVudHMgPSBwYXJlbnRzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgdGhlIHRhc2ssIGNhcHR1cmluZyBhbmQgcmV0dXJuaW5nIHRoZSB0cmltbWVkLCBuZXdsaW5lLWpvaW5lZCBzdGRvdXRcbiAgICogb2YgYWxsIGl0cyBzdGVwcyAoYW5kIGFueSBuZXN0ZWQgc3Bhd25lZCB0YXNrcykgaW4gZXhlY3V0aW9uIG9yZGVyLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIHJ1bkNhcHR1cmluZ091dHB1dCgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRoaXMuY2FwdHVyZUFsbCA9IHRydWU7XG4gICAgYXdhaXQgdGhpcy5ydW4oKTtcbiAgICByZXR1cm4gdGhpcy5jYXB0dXJlZC5qb2luKFwiXFxuXCIpLnRyaW0oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWNvcmRzIGEgc3RlcCdzIGNhcHR1cmVkICh0cmltbWVkKSBzdGRvdXQ6IGludG8gYG91dHB1dEVudmAgZm9yIGxhdGVyXG4gICAqIHN0ZXBzIChhbmQgcHJvcGFnYXRlZCB0byBzcGF3bmVkIHN1YnRhc2tzKSwgYW5kIGludG8gdGhlIHJ1bidzIGFnZ3JlZ2F0ZVxuICAgKiBvdXRwdXQgd2hlbiBjYXB0dXJpbmcgZXZlcnl0aGluZy5cbiAgICovXG4gIHByaXZhdGUgcmVjb3JkQ2FwdHVyZShvdXRwdXRFbnY6IHN0cmluZyB8IHVuZGVmaW5lZCwgdmFsdWU6IHN0cmluZykge1xuICAgIGlmIChvdXRwdXRFbnYpIHtcbiAgICAgIHRoaXMuZW52W291dHB1dEVudl0gPSB2YWx1ZTtcbiAgICAgIHRoaXMuY2FwdHVyZWRFbnZbb3V0cHV0RW52XSA9IHZhbHVlO1xuICAgIH1cbiAgICBpZiAodGhpcy5jYXB0dXJlQWxsKSB7XG4gICAgICB0aGlzLmNhcHR1cmVkLnB1c2godmFsdWUpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBFeGVjdXRlcyB0aGUgdGFzay4gVGhpcyB3YXMgcHJldmlvdXNseSBkb25lIGluIHRoZSBjb25zdHJ1Y3RvciwgYnV0IGlzIG5vd1xuICAgKiBhbiBhc3luYyBtZXRob2Qgc2luY2Ugc2hlbGwgZXhlY3V0aW9uIGlzIGFzeW5jaHJvbm91cyAoZS5nLiBkYXggb25cbiAgICogV2luZG93cykuXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgcnVuKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHsgdGFzaywgYXJncywgcGFyZW50cyB9ID0gdGhpcztcblxuICAgIGlmICghdGFzay5zdGVwcyB8fCB0YXNrLnN0ZXBzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhpcy5sb2dEZWJ1ZyhncmF5KFwiTm8gYWN0aW9ucyBoYXZlIGJlZW4gc3BlY2lmaWVkIGZvciB0aGlzIHRhc2suXCIpKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmVudiA9IGF3YWl0IHRoaXMucmVzb2x2ZUVudmlyb25tZW50KFxuICAgICAgdGhpcy5lbnZQYXJhbSxcbiAgICAgIHBhcmVudHMsXG4gICAgICB0aGlzLnJlc29sdmVTaGVsbCgpLFxuICAgICk7XG5cbiAgICBjb25zdCBlbnZsb2dzID0gW107XG4gICAgZm9yIChjb25zdCBbaywgdl0gb2YgT2JqZWN0LmVudHJpZXModGhpcy5lbnYpKSB7XG4gICAgICBjb25zdCB2diA9IHYgPz8gXCJcIjtcbiAgICAgIGNvbnN0IHRyaW1tZWQgPVxuICAgICAgICB2di5sZW5ndGggPiBFTlZfVFJJTV9MRU4gPyB2di5zdWJzdHJpbmcoMCwgRU5WX1RSSU1fTEVOKSArIFwiLi4uXCIgOiB2djtcbiAgICAgIGVudmxvZ3MucHVzaChgJHtrfT0ke3RyaW1tZWR9YCk7XG4gICAgfVxuXG4gICAgaWYgKGVudmxvZ3MubGVuZ3RoKSB7XG4gICAgICB0aGlzLmxvZ0RlYnVnKGdyYXkoYCR7dW5kZXJsaW5lKFwiZW52XCIpfTogJHtlbnZsb2dzLmpvaW4oXCIgXCIpfWApKTtcbiAgICB9XG5cbiAgICAvLyBldmFsdWF0ZSBjb25kaXRpb25cbiAgICBpZiAoIShhd2FpdCB0aGlzLmV2YWxDb25kaXRpb24odGFzaywgdGhpcy5yZXNvbHZlU2hlbGwoKSkpKSB7XG4gICAgICB0aGlzLmxvZyhcImNvbmRpdGlvbiBleGl0ZWQgd2l0aCBub24temVybyAtIHNraXBwaW5nXCIpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIHZlcmlmeSB3ZSByZXF1aXJlZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMgYXJlIGRlZmluZWRcbiAgICBjb25zdCBtZXJnZWQgPSB7IC4uLnByb2Nlc3MuZW52LCAuLi50aGlzLmVudiB9O1xuICAgIGNvbnN0IG1pc3NpbmcgPSBuZXcgQXJyYXk8c3RyaW5nPigpO1xuICAgIGZvciAoY29uc3QgbmFtZSBvZiB0YXNrLnJlcXVpcmVkRW52ID8/IFtdKSB7XG4gICAgICBpZiAoIShuYW1lIGluIG1lcmdlZCkpIHtcbiAgICAgICAgbWlzc2luZy5wdXNoKG5hbWUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChtaXNzaW5nLmxlbmd0aCA+IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYG1pc3NpbmcgcmVxdWlyZWQgZW52aXJvbm1lbnQgdmFyaWFibGVzOiAke21pc3Npbmcuam9pbihcIixcIil9YCxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBzdGVwIG9mIHRhc2suc3RlcHMpIHtcbiAgICAgIGNvbnN0IHN0ZXBTaGVsbCA9IHRoaXMucmVzb2x2ZVNoZWxsKHN0ZXApO1xuXG4gICAgICAvLyBldmFsdWF0ZSBzdGVwIGNvbmRpdGlvblxuICAgICAgaWYgKCEoYXdhaXQgdGhpcy5ldmFsQ29uZGl0aW9uKHN0ZXAsIHN0ZXBTaGVsbCkpKSB7XG4gICAgICAgIHRoaXMubG9nKFwiY29uZGl0aW9uIGV4aXRlZCB3aXRoIG5vbi16ZXJvIC0gc2tpcHBpbmdcIik7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBhcmdzTGlzdDogc3RyaW5nW10gPSBbXG4gICAgICAgIC4uLihzdGVwLmFyZ3MgfHwgW10pLFxuICAgICAgICAuLi4oc3RlcC5yZWNlaXZlQXJncyA/IGFyZ3MgOiBbXSksXG4gICAgICBdLm1hcCgoYSkgPT4gYS50b1N0cmluZygpKTtcblxuICAgICAgaWYgKHN0ZXAuc2F5KSB7XG4gICAgICAgIGxvZ2dpbmcuaW5mbyh0aGlzLmZtdExvZyhzdGVwLnNheSkpO1xuICAgICAgfVxuXG4gICAgICBpZiAoc3RlcC5zcGF3bikge1xuICAgICAgICBjb25zdCBjYXB0dXJlID0gdGhpcy5jYXB0dXJlQWxsIHx8ICEhc3RlcC5vdXRwdXRFbnY7XG4gICAgICAgIGNvbnN0IG91dHB1dCA9IGF3YWl0IHRoaXMucnVudGltZS5ydW5UYXNrKFxuICAgICAgICAgIHN0ZXAuc3Bhd24sXG4gICAgICAgICAgWy4uLnRoaXMucGFyZW50cywgdGhpcy50YXNrLm5hbWVdLFxuICAgICAgICAgIGFyZ3NMaXN0LFxuICAgICAgICAgIHsgLi4udGhpcy5jYXB0dXJlZEVudiwgLi4uc3RlcC5lbnYgfSxcbiAgICAgICAgICB7IGNhcHR1cmVPdXRwdXQ6IGNhcHR1cmUgfSxcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKHR5cGVvZiBvdXRwdXQgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICB0aGlzLnJlY29yZENhcHR1cmUoc3RlcC5vdXRwdXRFbnYsIG91dHB1dCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgZXhlY3M6IEFycmF5PHN0cmluZyB8IHN0cmluZ1tdPiA9IHN0ZXAuZXhlYyA/IFtzdGVwLmV4ZWNdIDogW107XG5cbiAgICAgIC8vIFBhcnNlIHN0ZXAtc3BlY2lmaWMgZW52aXJvbm1lbnQgdmFyaWFibGVzXG4gICAgICBjb25zdCBlbnYgPSBhd2FpdCB0aGlzLmV2YWxFbnZpcm9ubWVudChzdGVwLmVudiA/PyB7fSwgc3RlcFNoZWxsKTtcblxuICAgICAgaWYgKHN0ZXAuYnVpbHRpbikge1xuICAgICAgICBleGVjcy5wdXNoKHRoaXMucmVuZGVyQnVpbHRpbihzdGVwLmJ1aWx0aW4pKTtcbiAgICAgIH1cblxuICAgICAgLy8gYGV4ZWNBcmdzYCBpcyBhbiBleHBsaWNpdCBhcmd2ICh0aGUgcHJvZ3JhbSBmb2xsb3dlZCBieSBpdHMgYXJndW1lbnRzKS5cbiAgICAgIC8vIEl0IGlzIGhhbmRlZCB0byBgc2hlbGwoKWAgYXMgYW4gYXJyYXkgcmF0aGVyIHRoYW4gYSByZW5kZXJlZCBzdHJpbmcsIHNvXG4gICAgICAvLyBpdCBydW5zIHdpdGhvdXQgYSBzaGVsbCBhbmQgZXZlcnkgZWxlbWVudCBpcyBwYXNzZWQgdGhyb3VnaCB2ZXJiYXRpbSAtXG4gICAgICAvLyB3aGljaCBpcyB3aGF0IGxldHMgY2FsbGVycyBhdm9pZCB0aGlua2luZyBhYm91dCBxdW90aW5nLiBGaXhlZC9yZWNlaXZlZFxuICAgICAgLy8gYXJncyBhcmUgc3BsaWNlZCBpbiB3aGVyZXZlciBhIGAkQGAgbWFya2VyIGVsZW1lbnQgYXBwZWFycyAobWlycm9yaW5nXG4gICAgICAvLyB0aGUgc3RyaW5nIGBleGVjYCBiZWhhdmlvciksIG9yIGFwcGVuZGVkIGF0IHRoZSBlbmQgaWYgdGhlcmUgaXMgbm9uZS5cbiAgICAgIGlmIChzdGVwLmV4ZWNBcmdzKSB7XG4gICAgICAgIGNvbnN0IGFyZ3Y6IHN0cmluZ1tdID0gW107XG4gICAgICAgIGxldCBwbGFjZWQgPSBmYWxzZTtcbiAgICAgICAgZm9yIChjb25zdCBlbGVtZW50IG9mIHN0ZXAuZXhlY0FyZ3MpIHtcbiAgICAgICAgICBpZiAoZWxlbWVudCA9PT0gQVJHU19NQVJLRVIpIHtcbiAgICAgICAgICAgIGFyZ3YucHVzaCguLi5hcmdzTGlzdCk7XG4gICAgICAgICAgICBwbGFjZWQgPSB0cnVlO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhcmd2LnB1c2goZWxlbWVudCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICghcGxhY2VkKSB7XG4gICAgICAgICAgYXJndi5wdXNoKC4uLmFyZ3NMaXN0KTtcbiAgICAgICAgfVxuICAgICAgICBleGVjcy5wdXNoKGFyZ3YpO1xuICAgICAgfVxuXG4gICAgICBmb3IgKGNvbnN0IGV4ZWMgb2YgZXhlY3MpIHtcbiAgICAgICAgbGV0IGNvbW1hbmQgPSBleGVjO1xuXG4gICAgICAgIC8vIEEgc3RyaW5nIGNvbW1hbmQgaXMgYSBzaGVsbCBsaW5lOiBzcGxpY2UgdGFzayBhcmdzIGluIHBlciB0aGUgYCRAYFxuICAgICAgICAvLyBtYXJrZXIgcnVsZXMuIEFuIGBleGVjQXJnc2AgYXJndiBhbHJlYWR5IGNhcnJpZXMgaXRzIGFyZ3MsIHVudG91Y2hlZC5cbiAgICAgICAgaWYgKHR5cGVvZiBjb21tYW5kID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgaWYgKGNvbW1hbmQuaW5jbHVkZXMoUVVPVEVEX0FSR1NfTUFSS0VSKSkge1xuICAgICAgICAgICAgLy8gYFwiJEBcImA6IHNwbGljZSBlYWNoIGFyZyBpbiBhcyBhIHNlcGFyYXRlIHZlcmJhdGltIHdvcmQgKGxpa2VcbiAgICAgICAgICAgIC8vIGJhc2gncyBxdW90ZWQgYFwiJEBcImApLCBzbyB3aGl0ZXNwYWNlIGFuZCBtZXRhY2hhcmFjdGVycyBzdXJ2aXZlLlxuICAgICAgICAgICAgY29tbWFuZCA9IGNvbW1hbmQucmVwbGFjZShcbiAgICAgICAgICAgICAgUVVPVEVEX0FSR1NfTUFSS0VSLFxuICAgICAgICAgICAgICBlc2NhcGVBcmdzRm9yKHN0ZXBTaGVsbCwgYXJnc0xpc3QpLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKGNvbW1hbmQuaW5jbHVkZXMoQVJHU19NQVJLRVIpKSB7XG4gICAgICAgICAgICBjb21tYW5kID0gY29tbWFuZC5yZXBsYWNlKEFSR1NfTUFSS0VSLCBhcmdzTGlzdC5qb2luKFwiIFwiKSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbW1hbmQgPSBbY29tbWFuZCwgLi4uYXJnc0xpc3RdLmpvaW4oXCIgXCIpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGN3ZCA9IHN0ZXAuY3dkO1xuICAgICAgICBjb25zdCBjYXB0dXJlID0gdGhpcy5jYXB0dXJlQWxsIHx8ICEhc3RlcC5vdXRwdXRFbnY7XG4gICAgICAgIC8vIEEgdGhyb3duIGVycm9yIChlLmcuIHNwYXduIGZhaWx1cmUpIHByb3BhZ2F0ZXM7IGEgbm9uLXplcm8gZXhpdCBpc1xuICAgICAgICAvLyByZXBvcnRlZCB2aWEgYHJlc3VsdC5zdGF0dXNgLlxuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnNoZWxsKHtcbiAgICAgICAgICBjb21tYW5kLFxuICAgICAgICAgIGN3ZCxcbiAgICAgICAgICBleHRyYUVudjogZW52LFxuICAgICAgICAgIHNoZWxsOiBzdGVwU2hlbGwsXG4gICAgICAgICAgY2FwdHVyZU91dHB1dDogY2FwdHVyZSxcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChyZXN1bHQuc3RhdHVzICE9PSAwKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYFRhc2sgXCIke3RoaXMuZnVsbG5hbWV9XCIgZmFpbGVkIHdoZW4gZXhlY3V0aW5nIFwiJHtcbiAgICAgICAgICAgICAgQXJyYXkuaXNBcnJheShjb21tYW5kKSA/IGNvbW1hbmQuam9pbihcIiBcIikgOiBjb21tYW5kXG4gICAgICAgICAgICB9XCIgKGN3ZDogJHtyZXNvbHZlKGN3ZCA/PyB0aGlzLndvcmtkaXIpfSlgLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNhcHR1cmUpIHtcbiAgICAgICAgICBjb25zdCBzdGRvdXQgPSByZXN1bHQuc3Rkb3V0Py50b1N0cmluZyhcInV0Zi04XCIpLnRyaW0oKSA/PyBcIlwiO1xuICAgICAgICAgIHRoaXMucmVjb3JkQ2FwdHVyZShzdGVwLm91dHB1dEVudiwgc3Rkb3V0KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIGlmIGEgdGFzayBzaG91bGQgYmUgZXhlY3V0ZWQgYmFzZWQgb24gXCJjb25kaXRpb25cIi5cbiAgICpcbiAgICogQHJldHVybnMgdHJ1ZSBpZiB0aGUgdGFzayBzaG91bGQgYmUgZXhlY3V0ZWQgb3IgZmFsc2UgaWYgdGhlIGNvbmRpdGlvblxuICAgKiBldmFsdWF0ZXMgdG8gZmFsc2UgKGV4aXRzIHdpdGggbm9uLXplcm8pLCBpbmRpY2F0aW5nIHRoYXQgdGhlIHRhc2sgc2hvdWxkXG4gICAqIGJlIHNraXBwZWQuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGV2YWxDb25kaXRpb24oXG4gICAgdGFza09yU3RlcDogVGFza1NwZWMgfCBUYXNrU3RlcCxcbiAgICBzaGVsbDogc3RyaW5nIHwgc3RyaW5nW10sXG4gICkge1xuICAgIC8vIG5vIGNvbmRpdGlvbiwgY2Fycnkgb25cbiAgICBpZiAoIXRhc2tPclN0ZXAuY29uZGl0aW9uKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICB0aGlzLmxvZyhncmF5KGAke3VuZGVybGluZShcImNvbmRpdGlvblwiKX06ICR7dGFza09yU3RlcC5jb25kaXRpb259YCkpO1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMuc2hlbGwoe1xuICAgICAgY29tbWFuZDogdGFza09yU3RlcC5jb25kaXRpb24sXG4gICAgICBxdWlldDogdHJ1ZSxcbiAgICAgIHNoZWxsLFxuICAgIH0pO1xuICAgIGlmIChyZXN1bHQuc3RhdHVzID09PSAwKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBFdmFsdWF0ZXMgZW52aXJvbm1lbnQgdmFyaWFibGVzIGZyb20gc2hlbGwgY29tbWFuZHMgKGUuZy4gYCQoeHgpYClcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZXZhbEVudmlyb25tZW50KFxuICAgIGVudjogeyBbbmFtZTogc3RyaW5nXTogc3RyaW5nIH0sXG4gICAgc2hlbGw6IHN0cmluZyB8IHN0cmluZ1tdLFxuICApIHtcbiAgICBjb25zdCBvdXRwdXQ6IHsgW25hbWU6IHN0cmluZ106IHN0cmluZyB8IHVuZGVmaW5lZCB9ID0ge307XG5cbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhlbnYgPz8ge30pKSB7XG4gICAgICBpZiAoU3RyaW5nKHZhbHVlKS5zdGFydHNXaXRoKFwiJChcIikgJiYgU3RyaW5nKHZhbHVlKS5lbmRzV2l0aChcIilcIikpIHtcbiAgICAgICAgY29uc3QgcXVlcnkgPSB2YWx1ZS5zdWJzdHJpbmcoMiwgdmFsdWUubGVuZ3RoIC0gMSk7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMuc2hlbGwoe1xuICAgICAgICAgIGNvbW1hbmQ6IHF1ZXJ5LFxuICAgICAgICAgIHF1aWV0OiB0cnVlLFxuICAgICAgICAgIGNhcHR1cmVPdXRwdXQ6IHRydWUsXG4gICAgICAgICAgc2hlbGwsXG4gICAgICAgIH0pO1xuICAgICAgICBpZiAocmVzdWx0LnN0YXR1cyAhPT0gMCkge1xuICAgICAgICAgIGNvbnN0IGVycm9yID0gcmVzdWx0LmVycm9yXG4gICAgICAgICAgICA/IHJlc3VsdC5lcnJvci5zdGFja1xuICAgICAgICAgICAgOiByZXN1bHQuc3RkZXJyPy50b1N0cmluZygpLnRyaW0oKSB8fFxuICAgICAgICAgICAgICByZXN1bHQuc3Rkb3V0Py50b1N0cmluZygpLnRyaW0oKSB8fFxuICAgICAgICAgICAgICBgY29tbWFuZCBleGl0ZWQgd2l0aCBjb2RlICR7cmVzdWx0LnN0YXR1c31gO1xuXG4gICAgICAgICAgbG9nZ2luZy53YXJuKFxuICAgICAgICAgICAgdGhpcy5mbXRMb2coXG4gICAgICAgICAgICAgIGAke3VuZGVybGluZShrZXkpfTogdW5hYmxlIHRvIGV2YWx1YXRlIFwiJHtxdWVyeX1cIi4gRW52aXJvbm1lbnQgdmFyaWFibGUgd2lsbCBiZSBza2lwcGVkLiBDaGVjayB0aGF0IHRoZSBjb21tYW5kIGV4aXN0cyBhbmQgcnVucyBzdWNjZXNzZnVsbHkuYCxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgKTtcbiAgICAgICAgICBsb2dnaW5nLndhcm4odGhpcy5mbXRMb2coYCR7dW5kZXJsaW5lKGtleSl9OiAke2Vycm9yfWApKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBvdXRwdXRba2V5XSA9IHJlc3VsdC5zdGRvdXQ/LnRvU3RyaW5nKFwidXRmLThcIikudHJpbSgpID8/IFwiXCI7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG91dHB1dFtrZXldID0gdmFsdWU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBvdXRwdXQ7XG4gIH1cblxuICAvKipcbiAgICogUmVuZGVycyB0aGUgcnVudGltZSBlbnZpcm9ubWVudCBmb3IgYSB0YXNrLiBOYW1lbHksIGl0IHN1cHBvcnRzIHRoaXMgc3ludGF4XG4gICAqIGAkKHh4KWAgZm9yIGFsbG93aW5nIGVudmlyb25tZW50IHRvIGJlIGV2YWx1YXRlZCBieSBleGVjdXRpbmcgYSBzaGVsbFxuICAgKiBjb21tYW5kIGFuZCBvYnRhaW5pbmcgaXRzIHJlc3VsdC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcmVzb2x2ZUVudmlyb25tZW50KFxuICAgIGVudlBhcmFtOiB7IFtuYW1lOiBzdHJpbmddOiBzdHJpbmcgfSxcbiAgICBwYXJlbnRzOiBzdHJpbmdbXSxcbiAgICBzaGVsbDogc3RyaW5nIHwgc3RyaW5nW10sXG4gICkge1xuICAgIGxldCBlbnYgPSB0aGlzLnJ1bnRpbWUubWFuaWZlc3QuZW52ID8/IHt9O1xuXG4gICAgLy8gYWRkIGVudiBmcm9tIGFsbCBwYXJlbnQgdGFza3Mgb25lIGJ5IG9uZVxuICAgIGZvciAoY29uc3QgcGFyZW50IG9mIHBhcmVudHMpIHtcbiAgICAgIGVudiA9IHtcbiAgICAgICAgLi4uZW52LFxuICAgICAgICAuLi4odGhpcy5ydW50aW1lLnRyeUZpbmRUYXNrKHBhcmVudCk/LmVudiA/PyB7fSksXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIGFwcGx5IHRhc2sgZW52aXJvbm1lbnQsIHRoZW4gdGhlIHNwZWNpZmljIGVudiBsYXN0XG4gICAgZW52ID0ge1xuICAgICAgLi4uZW52LFxuICAgICAgLi4uKHRoaXMudGFzay5lbnYgPz8ge30pLFxuICAgICAgLi4uZW52UGFyYW0sXG4gICAgfTtcblxuICAgIHJldHVybiB0aGlzLmV2YWxFbnZpcm9ubWVudChlbnYsIHNoZWxsKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNvbHZlcyB0aGUgc2hlbGwgZm9yIGEgc3RlcCdzIGNvbW1hbmQgKG9yIHRoZSB0YXNrJ3MsIHdoZW4gbm8gc3RlcCBpc1xuICAgKiBnaXZlbik6IHN0ZXAsIHRoZW4gdGFzaywgdGhlbiBwcm9qZWN0IGRlZmF1bHQsIHRoZW4gXCJwcm9qZW5cIi5cbiAgICovXG4gIHByaXZhdGUgcmVzb2x2ZVNoZWxsKHN0ZXA/OiBUYXNrU3RlcCk6IHN0cmluZyB8IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gKFxuICAgICAgc3RlcD8uc2hlbGwgPz8gdGhpcy50YXNrLnNoZWxsID8/IHRoaXMucnVudGltZS5tYW5pZmVzdC5zaGVsbCA/PyBcInByb2plblwiXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBcImZ1bGwgbmFtZVwiIG9mIHRoZSB0YXNrIHdoaWNoIGluY2x1ZGVzIGFsbCBpdCdzIHBhcmVudCB0YXNrIG5hbWVzIGNvbmNhdGVuYXRlZCBieSBjaGV2cm9ucy5cbiAgICovXG4gIHByaXZhdGUgZ2V0IGZ1bGxuYW1lKCkge1xuICAgIHJldHVybiBbLi4udGhpcy5wYXJlbnRzLCB0aGlzLnRhc2submFtZV0uam9pbihcIiDCuyBcIik7XG4gIH1cblxuICBwcml2YXRlIGxvZyguLi5hcmdzOiBhbnlbXSkge1xuICAgIGxvZ2dpbmcudmVyYm9zZSh0aGlzLmZtdExvZyguLi5hcmdzKSk7XG4gIH1cblxuICBwcml2YXRlIGxvZ0RlYnVnKC4uLmFyZ3M6IGFueVtdKSB7XG4gICAgbG9nZ2luZy5kZWJ1Zyh0aGlzLmZtdExvZyguLi5hcmdzKSk7XG4gIH1cblxuICBwcml2YXRlIGZtdExvZyguLi5hcmdzOiBhbnlbXSkge1xuICAgIHJldHVybiBmb3JtYXQoYCR7dW5kZXJsaW5lKHRoaXMuZnVsbG5hbWUpfSB8YCwgLi4uYXJncyk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHNoZWxsKG9wdGlvbnM6IFNoZWxsT3B0aW9ucyk6IFByb21pc2U8U2hlbGxSZXN1bHQ+IHtcbiAgICBjb25zdCBxdWlldCA9IG9wdGlvbnMucXVpZXQgPz8gZmFsc2U7XG4gICAgaWYgKCFxdWlldCkge1xuICAgICAgY29uc3QgbG9nID0gbmV3IEFycmF5PHN0cmluZz4oKTtcblxuICAgICAgbG9nLnB1c2goXG4gICAgICAgIEFycmF5LmlzQXJyYXkob3B0aW9ucy5jb21tYW5kKVxuICAgICAgICAgID8gb3B0aW9ucy5jb21tYW5kLmpvaW4oXCIgXCIpXG4gICAgICAgICAgOiBvcHRpb25zLmNvbW1hbmQsXG4gICAgICApO1xuXG4gICAgICBpZiAob3B0aW9ucy5jd2QpIHtcbiAgICAgICAgbG9nLnB1c2goYChjd2Q6ICR7b3B0aW9ucy5jd2R9KWApO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmxvZyhsb2cuam9pbihcIiBcIikpO1xuICAgIH1cblxuICAgIGNvbnN0IGN3ZCA9IG9wdGlvbnMuY3dkID8/IHRoaXMud29ya2RpcjtcbiAgICBpZiAoIWV4aXN0c1N5bmMoY3dkKSB8fCAhc3RhdFN5bmMoY3dkKS5pc0RpcmVjdG9yeSgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBpbnZhbGlkIHdvcmtkaXIgKGN3ZCk6ICR7Y3dkfSBtdXN0IGJlIGFuIGV4aXN0aW5nIGRpcmVjdG9yeWAsXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFRoZSByZXNvbHZlZCBzaGVsbCBpcyBvbmUgb2Y6XG4gICAgLy8gLSBcInByb2plblwiIChkZWZhdWx0KTogZGF4J3MgaW4tcHJvY2VzcyBjcm9zcy1wbGF0Zm9ybSBzaGVsbCwgc28gUE9TSVgtc3R5bGVcbiAgICAvLyAgIHRhc2sgc3ludGF4IChgbWtkaXIgLXBgLCBgJiZgLCBgJFZBUmAsIC4uLikgd29ya3MgdGhlIHNhbWUgZXZlcnl3aGVyZS5cbiAgICAvLyAtIFwic3lzdGVtXCI6IHRoZSBob3N0J3MgbmF0aXZlIHNoZWxsIChgL2Jpbi9zaGAsIG9yIGBjbWQuZXhlYCBvbiBXaW5kb3dzKS5cbiAgICAvLyAtIGFuIGFyZ3YsIGUuZy4gW1wiYmFzaFwiLFwiLWNcIl06IGEgc2hlbGwgaW52b2NhdGlvbiB3aXRoIHRoZSBjb21tYW5kIGFwcGVuZGVkXG4gICAgLy8gICBhcyBpdHMgZmluYWwgYXJndW1lbnQuXG4gICAgY29uc3Qgc2hlbGwgPSBvcHRpb25zLnNoZWxsID8/IFwicHJvamVuXCI7XG4gICAgaWYgKHR5cGVvZiBzaGVsbCA9PT0gXCJzdHJpbmdcIiAmJiBzaGVsbCAhPT0gXCJwcm9qZW5cIiAmJiBzaGVsbCAhPT0gXCJzeXN0ZW1cIikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgdW5rbm93biBidWlsdC1pbiBzaGVsbCAke0pTT04uc3RyaW5naWZ5KFxuICAgICAgICAgIHNoZWxsLFxuICAgICAgICApfTsgdXNlIHRoZSBidWlsdC1pbiBcInByb2plblwiIG9yIFwic3lzdGVtXCIgc2hlbGxzLCBvciBhIFRhc2tTaGVsbC5jb21tYW5kKFsuLi5dKSBpbnZvY2F0aW9uYCxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgY2FwdHVyZSA9IG9wdGlvbnMuY2FwdHVyZU91dHB1dCA/PyBmYWxzZTtcbiAgICAvLyBRdWlldCBjYXB0dXJlcyAoYCQoLi4uKWAsIGNvbmRpdGlvbnMpIHN0YXkgc2lsZW50OyB2aXNpYmxlIGNhcHR1cmVzXG4gICAgLy8gKGBvdXRwdXRFbnZgKSBzdHJlYW0gbGl2ZSB3aGlsZSBzdGlsbCBidWZmZXJpbmcuXG4gICAgY29uc3Qgc3RyZWFtID0gY2FwdHVyZSAmJiAhcXVpZXQ7XG5cbiAgICBjb25zdCBjb21tYW5kID0gb3B0aW9ucy5jb21tYW5kO1xuICAgIGNvbnN0IGVudiA9IHtcbiAgICAgIC4uLnByb2Nlc3MuZW52LFxuICAgICAgLi4udGhpcy5lbnYsXG4gICAgICAuLi5vcHRpb25zLmV4dHJhRW52LFxuICAgIH07XG5cbiAgICAvLyBcInN5c3RlbVwiOiB0aGUgaG9zdC1uYXRpdmUgZW5naW5lLiBBIHN0cmluZyBjb21tYW5kIHJ1bnMgdGhyb3VnaCB0aGUgT1NcbiAgICAvLyBzaGVsbDsgYW4gYGV4ZWNBcmdzYCBhcmd2IGlzIHNwYXduZWQgZGlyZWN0bHkgKHNoZWxsLWZyZWUpLCBzbyB0aGUgcmVhbFxuICAgIC8vIGJpbmFyeSBydW5zIHdpdGggbm8gZGF4IGJ1aWx0LWlucy4gKE9ubHkgYCQoLi4uKWAvY29uZGl0aW9uIGV2YWwgY2FwdHVyZXMsXG4gICAgLy8gYW5kIHRob3NlIGFsd2F5cyBwYXNzIGEgc3RyaW5nLCBzbyBhbiBhcnJheSBjb21tYW5kIG5ldmVyIG5lZWRzIGNhcHR1cmUuKVxuICAgIGlmIChzaGVsbCA9PT0gXCJzeXN0ZW1cIikge1xuICAgICAgaWYgKEFycmF5LmlzQXJyYXkoY29tbWFuZCkpIHtcbiAgICAgICAgY29uc3QgW3Byb2dyYW0sIC4uLmFyZ3NdID0gY29tbWFuZDtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB0b29sKHByb2dyYW0pLnJ1bihhcmdzLCB7IGN3ZCwgZW52LCBpbmhlcml0U3RkaW86IHRydWUgfSk7XG4gICAgICAgICAgcmV0dXJuIHsgc3RhdHVzOiAwIH07XG4gICAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgICAgIGlmICh0eXBlb2YgZT8uc3RhdHVzID09PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICByZXR1cm4geyBzdGF0dXM6IGUuc3RhdHVzIH07XG4gICAgICAgICAgfVxuICAgICAgICAgIHRocm93IGU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBzeXN0ZW1TaGVsbChjb21tYW5kLCB7IGN3ZCwgZW52LCBjYXB0dXJlLCBzdHJlYW0gfSk7XG4gICAgfVxuXG4gICAgLy8gT3RoZXJ3aXNlIHJ1biB0aHJvdWdoIGRheDogdGhlIFwicHJvamVuXCIgc2hlbGwgb3IgYW4gZXhwbGljaXQgaW52b2NhdGlvbi5cbiAgICBjb25zdCBidWlsZGVyID0gdGhpcy5idWlsZERheENvbW1hbmQoY29tbWFuZCwgc2hlbGwpO1xuXG4gICAgLy8gYGluaGVyaXRQaXBlZGAgc3RyZWFtcyBhbmQgYnVmZmVyczsgYHBpcGVkYCBidWZmZXJzIHF1aWV0bHkuIHN0ZGVyciBpc1xuICAgIC8vIGJ1ZmZlcmVkIG9ubHkgZm9yIHF1aWV0IGNhcHR1cmVzLCBzbyBpdCBjYW4gc3VyZmFjZSBpbiBlcnJvcnMuXG4gICAgY29uc3Qgc3Rkb3V0TW9kZSA9IGNhcHR1cmVcbiAgICAgID8gc3RyZWFtXG4gICAgICAgID8gXCJpbmhlcml0UGlwZWRcIlxuICAgICAgICA6IFwicGlwZWRcIlxuICAgICAgOiBcImluaGVyaXRcIjtcbiAgICBjb25zdCBzdGRlcnJNb2RlID0gY2FwdHVyZSAmJiAhc3RyZWFtID8gXCJwaXBlZFwiIDogXCJpbmhlcml0XCI7XG5cbiAgICBsZXQgcmVzdWx0O1xuICAgIHRyeSB7XG4gICAgICByZXN1bHQgPSBhd2FpdCBidWlsZGVyXG4gICAgICAgIC5jd2QoY3dkKVxuICAgICAgICAuZW52KGVudilcbiAgICAgICAgLnN0ZG91dChzdGRvdXRNb2RlKVxuICAgICAgICAuc3RkZXJyKHN0ZGVyck1vZGUpXG4gICAgICAgIC5ub1Rocm93KCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgLy8gZGF4J3MgaW4tcHJvY2VzcyBzaGVsbCB0aHJvd3MgYSB0ZXJzZSBgTm90IGltcGxlbWVudGVkOiAuLi5gIGZvciBzaGVsbFxuICAgICAgLy8gc3ludGF4IGl0IGRvZXMgbm90IHN1cHBvcnQgKGUuZy4gYCQoLi4uKWAgY29tbWFuZCBzdWJzdGl0dXRpb24pOyB0dXJuXG4gICAgICAvLyB0aGF0IGludG8gYW4gYWN0aW9uYWJsZSBlcnJvciB0aGF0IHBvaW50cyBhdCB0aGUgc3lzdGVtLXNoZWxsIGVzY2FwZVxuICAgICAgLy8gaGF0Y2guIE90aGVyIGVycm9ycyBwYXNzIHRocm91Z2ggdW5jaGFuZ2VkLlxuICAgICAgdGhyb3cgZW5yaWNoQnVpbHRpblNoZWxsRXJyb3IoZSwgY29tbWFuZCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHN0YXR1czogcmVzdWx0LmNvZGUsXG4gICAgICBzdGRvdXQ6IGNhcHR1cmUgPyBCdWZmZXIuZnJvbShyZXN1bHQuc3Rkb3V0Qnl0ZXMpIDogbnVsbCxcbiAgICAgIHN0ZGVycjogY2FwdHVyZSAmJiAhc3RyZWFtID8gQnVmZmVyLmZyb20ocmVzdWx0LnN0ZGVyckJ5dGVzKSA6IG51bGwsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZHMgdGhlIGRheCBjb21tYW5kIGZvciB0aGUgXCJwcm9qZW5cIiBzaGVsbCBvciBhbiBleHBsaWNpdCBpbnZvY2F0aW9uLlxuICAgKiAoVGhlIFwic3lzdGVtXCIgc2hlbGwgaXMgaGFuZGxlZCBob3N0LXNpZGUsIG5vdCBoZXJlLikgYGNvbW1hbmRgIGlzIGEgc2hlbGxcbiAgICogbGluZSAoc3RyaW5nKSBvciBhbiBgZXhlY0FyZ3NgIGFyZ3YgKHN0cmluZ1tdKTsgYHNoZWxsYCBpcyBgXCJwcm9qZW5cImAgb3IgYW5cbiAgICogaW52b2NhdGlvbiBhcmd2IHN1Y2ggYXMgYFtcImJhc2hcIiwgXCItY1wiXWAuXG4gICAqL1xuICBwcml2YXRlIGJ1aWxkRGF4Q29tbWFuZChcbiAgICBjb21tYW5kOiBzdHJpbmcgfCBzdHJpbmdbXSxcbiAgICBzaGVsbDogc3RyaW5nIHwgc3RyaW5nW10sXG4gICkge1xuICAgIC8vIEFuIGludm9jYXRpb24gKGUuZy4gW1wiYmFzaFwiLFwiLWNcIl0sIFtcIm5weFwiLFwiLS1ub1wiLFwiLWNcIl0pOiBhcHBlbmQgdGhlXG4gICAgLy8gY29tbWFuZCBhcyBpdHMgZmluYWwgYXJndW1lbnQuIEEgc3RyaW5nIGlzIGFwcGVuZGVkIGFzLWlzOyBhbiBgZXhlY0FyZ3NgXG4gICAgLy8gYXJndiBpcyByZW5kZXJlZCB0byBhIHF1b3RlZCBjb21tYW5kIGxpbmUgc28gdGhlIHNoZWxsIHJlLXBhcnNlcyB0aGUgc2FtZVxuICAgIC8vIGFyZ3YuIFRoYXQgcmVuZGVyaW5nIGFzc3VtZXMgYSBQT1NJWC1zdHlsZSBzaGVsbCwgd2hpY2ggaXMgd2hhdCBzdWNoIGFuXG4gICAgLy8gaW52b2NhdGlvbiBpcyAoYGJhc2ggLWNgLCBgc2ggLWNgLCBgbnB4IC1jYCwgLi4uKS5cbiAgICBpZiAoQXJyYXkuaXNBcnJheShzaGVsbCkpIHtcbiAgICAgIGNvbnN0IFtwcm9ncmFtLCAuLi5mbGFnc10gPSBzaGVsbDtcbiAgICAgIGNvbnN0IGNvbW1hbmRMaW5lID0gQXJyYXkuaXNBcnJheShjb21tYW5kKVxuICAgICAgICA/IGVzY2FwZUNvbW1hbmQoY29tbWFuZClcbiAgICAgICAgOiBjb21tYW5kO1xuICAgICAgcmV0dXJuICRgJHtwcm9ncmFtfSAke1suLi5mbGFncywgY29tbWFuZExpbmVdfWA7XG4gICAgfVxuXG4gICAgLy8gVGhlIGJ1aWx0LWluIFwicHJvamVuXCIgc2hlbGwgKGRheCkuXG4gICAgcmV0dXJuIEFycmF5LmlzQXJyYXkoY29tbWFuZClcbiAgICAgID8gLy8gZXhlY0FyZ3M6IHNoZWxsLWZyZWUgYXJndiAoZWFjaCBlbGVtZW50IGVzY2FwZWQ7IGAuY21kYCBzaGltcyByZXNvbHZlZCkuXG4gICAgICAgICRgJHtjb21tYW5kWzBdfSAke2NvbW1hbmQuc2xpY2UoMSl9YFxuICAgICAgOiAvLyBzdHJpbmcgY29tbWFuZCwgcGFyc2VkIGluLXByb2Nlc3MgYnkgZGF4J3MgY3Jvc3MtcGxhdGZvcm0gc2hlbGwuXG4gICAgICAgICQucmF3YCR7Y29tbWFuZH1gO1xuICB9XG5cbiAgcHJpdmF0ZSByZW5kZXJCdWlsdGluKGJ1aWx0aW46IHN0cmluZykge1xuICAgIC8vIExvY2F0ZSBwcm9qZW4ncyBwYWNrYWdlIHJvb3QgYnkgd2Fsa2luZyB1cCBmcm9tIHRoaXMgbW9kdWxlJ3MgZGlyZWN0b3J5XG4gICAgLy8gdW50aWwgd2UgZmluZCBhIHBhY2thZ2UuanNvbi4gVGhpcyB3b3JrcyB3aGV0aGVyIHRoZSBjb2RlIHJ1bnMgZnJvbSB0aGVcbiAgICAvLyBjb21waWxlZCBmaWxlIChsaWIvY2xpL3Rhc2stcnVudGltZS5qcykgb3IgZnJvbSB0aGUgYnVuZGxlZCBydW4tdGFzay5janNcbiAgICAvLyAobGliL3J1bi10YXNrLmNqcyksIHdoaWNoIGxpdmUgYXQgZGlmZmVyZW50IGRlcHRocyAtIHNvIGEgaGFyZC1jb2RlZFxuICAgIC8vIHJlbGF0aXZlIHBhdGggdG8gcGFja2FnZS5qc29uIHdvdWxkIGJlIHdyb25nIGluIG9uZSBvZiB0aGUgdHdvIGNhc2VzLlxuICAgIGxldCBtb2R1bGVSb290ID0gX19kaXJuYW1lO1xuICAgIHdoaWxlICghZXhpc3RzU3luYyhqb2luKG1vZHVsZVJvb3QsIFwicGFja2FnZS5qc29uXCIpKSkge1xuICAgICAgY29uc3QgcGFyZW50ID0gZGlybmFtZShtb2R1bGVSb290KTtcbiAgICAgIGlmIChwYXJlbnQgPT09IG1vZHVsZVJvb3QpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwidW5hYmxlIHRvIGxvY2F0ZSB0aGUgcHJvamVuIHBhY2thZ2Ugcm9vdFwiKTtcbiAgICAgIH1cbiAgICAgIG1vZHVsZVJvb3QgPSBwYXJlbnQ7XG4gICAgfVxuICAgIGNvbnN0IHByb2dyYW0gPSByZXF1aXJlLnJlc29sdmUoXG4gICAgICBqb2luKG1vZHVsZVJvb3QsIFwibGliXCIsIGAke2J1aWx0aW59LnRhc2suanNgKSxcbiAgICApO1xuICAgIHJldHVybiBgXCIke3Byb2Nlc3MuZXhlY1BhdGh9XCIgXCIke3Byb2dyYW19XCJgO1xuICB9XG59XG5cbmludGVyZmFjZSBTaGVsbE9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIGNvbW1hbmQgdG8gcnVuLiBBIHN0cmluZyBpcyBleGVjdXRlZCBhcyBhIHNoZWxsIGNvbW1hbmQgbGluZTsgYVxuICAgKiBzdHJpbmcgYXJyYXkgaXMgYW4gZXhwbGljaXQgYXJndiAocHJvZ3JhbSArIGFyZ3VtZW50cykgZXhlY3V0ZWQgd2l0aG91dCBhXG4gICAqIHNoZWxsLlxuICAgKi9cbiAgcmVhZG9ubHkgY29tbWFuZDogc3RyaW5nIHwgc3RyaW5nW107XG4gIC8qKlxuICAgKiBAZGVmYXVsdCAtIHByb2plY3QgZGlyXG4gICAqL1xuICByZWFkb25seSBjd2Q/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBDYXB0dXJlIHN0ZG91dC9zdGRlcnIgKHNvIHRoZSBjYWxsZXIgY2FuIHJlYWQgdGhlbSBmcm9tIHRoZSByZXN1bHQpXG4gICAqIGluc3RlYWQgb2YgaW5oZXJpdGluZyB0aGUgcGFyZW50J3Mgc3RyZWFtcy5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGNhcHR1cmVPdXRwdXQ/OiBib29sZWFuO1xuICAvKiogQGRlZmF1bHQgZmFsc2UgKi9cbiAgcmVhZG9ubHkgcXVpZXQ/OiBib29sZWFuO1xuICByZWFkb25seSBleHRyYUVudj86IHsgW25hbWU6IHN0cmluZ106IHN0cmluZyB8IHVuZGVmaW5lZCB9O1xuICAvKipcbiAgICogVGhlIHJlc29sdmVkIHNoZWxsIHRvIGludGVycHJldCB0aGUgY29tbWFuZCAoZS5nLiBcInByb2plblwiLCBcImJhc2ggLWNcIikuXG4gICAqIEBkZWZhdWx0IFwicHJvamVuXCJcbiAgICovXG4gIHJlYWRvbmx5IHNoZWxsPzogc3RyaW5nIHwgc3RyaW5nW107XG59XG5cbi8qKlxuICogTm9ybWFsaXplZCByZXN1bHQgb2YgcnVubmluZyBhIGNvbW1hbmQgdGhyb3VnaCB0aGUgc3lzdGVtIHNoZWxsIChhIHN1YnNldCBvZlxuICogbm9kZSdzIGBTcGF3blN5bmNSZXR1cm5zYCkuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3lzdGVtU2hlbGxSZXN1bHQge1xuICAvKiogRXhpdCBjb2RlLCBvciBgbnVsbGAgaWYgdGVybWluYXRlZCBieSBhIHNpZ25hbCBvciBuZXZlciBzcGF3bmVkLiAqL1xuICByZWFkb25seSBzdGF0dXM6IG51bWJlciB8IG51bGw7XG4gIC8qKiBDYXB0dXJlZCBzdGRvdXQsIG9yIGBudWxsYCB3aGVuIHN0ZG91dCB3YXMgaW5oZXJpdGVkLiAqL1xuICByZWFkb25seSBzdGRvdXQ6IEJ1ZmZlciB8IG51bGw7XG4gIC8qKiBDYXB0dXJlZCBzdGRlcnIsIG9yIGBudWxsYCB3aGVuIHN0ZGVyciB3YXMgaW5oZXJpdGVkLiAqL1xuICByZWFkb25seSBzdGRlcnI6IEJ1ZmZlciB8IG51bGw7XG4gIC8qKiBBbiBlcnJvciByYWlzZWQgd2hpbGUgYXR0ZW1wdGluZyB0byBzcGF3biAobm90IGEgbm9uLXplcm8gZXhpdCkuICovXG4gIHJlYWRvbmx5IGVycm9yPzogRXJyb3I7XG59XG5cbi8qKlxuICogUnVucyBhIGNvbW1hbmQgbGluZSB0aHJvdWdoIHRoZSBvcGVyYXRpbmcgc3lzdGVtJ3MgbmF0aXZlIHNoZWxsLlxuICpcbiAqIENhbGxzIHRoZSBPUyBzaGVsbCB2aWEgYGNoaWxkX3Byb2Nlc3NgIHdpdGggYHNoZWxsOiB0cnVlYC5cbiAqIFRoaXMgYmFja3MgdGhlIGBzeXN0ZW1gIHRhc2sgc2hlbGwsIHdoaWNoIGxldHMgYSB1c2VyIG9wdCBvdXQgb2YgdGhlIGJ1aWx0LWluXG4gKiBjcm9zcy1wbGF0Zm9ybSBzaGVsbCBhbmQgdXNlIHRoZSBob3N0J3MgbmF0aXZlIHNoZWxsIGluc3RlYWQ6XG4gKiBgL2Jpbi9zaGBvbiBQT1NJWCBhbmQgYGNtZC5leGVgIG9uIFdpbmRvd3MuXG4gKlxuICogTmV2ZXIgdGhyb3dzIGZvciBhIG5vbi16ZXJvIGV4aXQgKHRoYXQgaXMgcmVwb3J0ZWQgdmlhIGBzdGF0dXNgKTtcbiAqIGEgc3Bhd24gZmFpbHVyZSBpcyByZXBvcnRlZCB2aWEgYGVycm9yYC4gVGhlIGNhbGxlciBzdXBwbGllcyB0aGUgZnVsbCBgZW52YC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN5c3RlbVNoZWxsKFxuICBjb21tYW5kOiBzdHJpbmcsXG4gIG9wdGlvbnM6IHtcbiAgICBjd2Q6IHN0cmluZztcbiAgICBlbnY/OiBOb2RlSlMuUHJvY2Vzc0VudjtcbiAgICBjYXB0dXJlPzogYm9vbGVhbjtcbiAgICBzdHJlYW0/OiBib29sZWFuO1xuICB9LFxuKTogU3lzdGVtU2hlbGxSZXN1bHQge1xuICBsb2dnaW5nLmRlYnVnKGAke2NvbW1hbmR9IChjd2Q6ICR7b3B0aW9ucy5jd2R9KWApO1xuICBjb25zdCByZXN1bHQgPSBjaGlsZF9wcm9jZXNzLnNwYXduU3luYyhjb21tYW5kLCB7XG4gICAgY3dkOiBvcHRpb25zLmN3ZCxcbiAgICBzaGVsbDogdHJ1ZSxcbiAgICBtYXhCdWZmZXI6IE1BWF9CVUZGRVIsXG4gICAgZW52OiBvcHRpb25zLmVudixcbiAgICAvLyBRdWlldCBjYXB0dXJlIGJ1ZmZlcnMgc3RkZXJyIGZvciBlcnJvciBtZXNzYWdlcy4gU3RyZWFtZWQgY2FwdHVyZVxuICAgIC8vIGluaGVyaXRzIHN0ZGVyciBhbmQgcmUtZW1pdHMgYnVmZmVyZWQgc3Rkb3V0IGFmdGVyd2FyZHMsIHNpbmNlIHNwYXduU3luY1xuICAgIC8vIGNhbid0IGJvdGggc2hvdyBhbmQgYnVmZmVyIHRoZSBzYW1lIHN0cmVhbSBhdCBvbmNlLlxuICAgIHN0ZGlvOiBvcHRpb25zLmNhcHR1cmVcbiAgICAgID8gb3B0aW9ucy5zdHJlYW1cbiAgICAgICAgPyBbXCJpbmhlcml0XCIsIFwicGlwZVwiLCBcImluaGVyaXRcIl1cbiAgICAgICAgOiBbXCJpbmhlcml0XCIsIFwicGlwZVwiLCBcInBpcGVcIl1cbiAgICAgIDogXCJpbmhlcml0XCIsXG4gIH0pO1xuICBpZiAob3B0aW9ucy5jYXB0dXJlICYmIG9wdGlvbnMuc3RyZWFtICYmIHJlc3VsdC5zdGRvdXQpIHtcbiAgICBwcm9jZXNzLnN0ZG91dC53cml0ZShyZXN1bHQuc3Rkb3V0KTtcbiAgfVxuICByZXR1cm4ge1xuICAgIHN0YXR1czogcmVzdWx0LnN0YXR1cyxcbiAgICBzdGRvdXQ6IHJlc3VsdC5zdGRvdXQgPz8gbnVsbCxcbiAgICBzdGRlcnI6IHJlc3VsdC5zdGRlcnIgPz8gbnVsbCxcbiAgICBlcnJvcjogcmVzdWx0LmVycm9yLFxuICB9O1xufVxuIl19