jsii-docgen
Version:
generates api docs for jsii modules
343 lines • 43.7 kB
JavaScript
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;
};
})();
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _Npm_npmCommand;
Object.defineProperty(exports, "__esModule", { value: true });
exports.OptionalPeerDepsFilter = exports.Npm = void 0;
const child_process_1 = require("child_process");
const fs_1 = require("fs");
const os = __importStar(require("os"));
const path_1 = require("path");
const semver_1 = require("semver");
const documentation_1 = require("./documentation");
const errors_1 = require("../../errors");
class Npm {
constructor(workingDirectory, logger = console.log, npmCommand) {
this.workingDirectory = workingDirectory;
this.logger = logger;
_Npm_npmCommand.set(this, void 0);
__classPrivateFieldSet(this, _Npm_npmCommand, npmCommand, "f");
}
/**
* Installs the designated package into this repository's working directory.
*
* @param target the name or path to the package that needs to be installed.
* @param force whether to pass `--force` to `npm install`.
*
* @returns the name of the package that was installed.
*/
async install(target, force = false) {
const commonFlags = [
...force
? [
// force install, ignoring recommended protections such as platform checks. This is okay
// because we are not actually executing the code being installed in this context.
'--force',
]
: [],
// this is critical from a security perspective to prevent
// code execution as part of the install command using npm hooks. (e.g postInstall)
'--ignore-scripts',
// save time by not running audit
'--no-audit',
// ensures npm does not insert anything in $PATH
'--no-bin-links',
// don't write or update a package-lock.json file
'--no-package-lock',
// always produce JSON output
'--json',
];
try {
assertSuccess(await this.runCommand(await this.npmCommandPath(), [
'install',
JSON.stringify(target),
...commonFlags,
// ensures we are installing devDependencies, too.
'--include=dev',
'--include=peer',
'--include=optional',
// Make sure we get a `package.json` so we can figure out the actual package name.
'--save',
], chunksToObject, {
cwd: this.workingDirectory,
shell: true,
}));
const { dependencies } = JSON.parse(await fs_1.promises.readFile((0, path_1.join)(this.workingDirectory, 'package.json'), 'utf-8'));
const names = Object.keys(dependencies !== null && dependencies !== void 0 ? dependencies : {});
const name = names.length === 1
? names[0]
: (0, documentation_1.extractPackageName)(target);
const optionalPeerDeps = await this.listOptionalPeerDeps(name);
if (optionalPeerDeps.length > 0) {
assertSuccess(await this.runCommand(await this.npmCommandPath(), [
'install',
...optionalPeerDeps,
...commonFlags,
// Save as optional in the root package.json (courtesy)
'--save-optional',
], chunksToObject, {
cwd: this.workingDirectory,
shell: true,
}));
}
return name;
}
catch (e) {
if (!force && (e instanceof errors_1.NpmError) && e.npmErrorCode === 'EBADPLATFORM') {
console.warn('npm install failed with EBADPLATFORM, retrying with --force');
return this.install(target, true);
}
return Promise.reject(e);
}
}
async listOptionalPeerDeps(target) {
var _a;
const result = new Array();
const packageJson = JSON.parse(await fs_1.promises.readFile((0, path_1.join)(this.workingDirectory, 'node_modules', target, 'package.json'), 'utf-8'));
for (const [name, { optional }] of Object.entries((_a = packageJson.peerDependenciesMeta) !== null && _a !== void 0 ? _a : {})) {
if (!optional) {
continue;
}
const version = packageJson.peerDependencies[name];
if (version == null) {
continue;
}
result.push(JSON.stringify(`${name}@${version}`));
}
return result;
}
/**
* Obtains the path to the npm command that should be run. This always returns
* the path to an npm >= 7, which "correctly" handles peerDependencies. If the
* npm version that's available in $PATH satisfies this predicate, this will
* simply return `npm`.
*/
async npmCommandPath() {
if (__classPrivateFieldGet(this, _Npm_npmCommand, "f")) {
return __classPrivateFieldGet(this, _Npm_npmCommand, "f");
}
// Get the platform specific npm command
const npm = npmPlatformAwareCommand();
try {
// If the npm in $PATH is >= v7, we can use that directly. The
// `npm version --json` command returns a JSON object containing the
// versions of several components (npm, node, v8, etc...). We are only
// interested in the `npm` key here.
const { exitCode, stdout } = await this.runCommand(npm, ['version', '--json'], chunksToObject);
if (exitCode === 0 && (0, semver_1.major)(stdout.npm) >= 7) {
return __classPrivateFieldSet(this, _Npm_npmCommand, npm, "f");
}
}
catch (e) {
this.logger('Could not determine version of npm in $PATH:', e);
}
// npm@8 is needed so that we also install peerDependencies - they are needed to construct
// the full type system.
this.logger('The npm in $PATH is not >= v7. Installing npm@8 locally...');
const result = await this.runCommand(npm, ['install', 'npm@8', '--no-package-lock', '--no-save', '--json'], chunksToObject, {
cwd: this.workingDirectory,
shell: true,
});
assertSuccess(result);
__classPrivateFieldSet(this, _Npm_npmCommand, (0, path_1.join)(this.workingDirectory, 'node_modules', '.bin', npm), "f");
this.logger(`Done installing npm@8 at ${__classPrivateFieldGet(this, _Npm_npmCommand, "f")}`);
return __classPrivateFieldGet(this, _Npm_npmCommand, "f");
}
/**
* Runs the supplied command with the provided arguments, captures the data
* pushed to STDOUT, and "parses" it using `outputTransform` to produce a
* result.
*
* You must consult the `exitCode` of the return value to determine whether
* the command was successful or not. Use the `assertSuccess` function to
* throw/reject in case the execution was not successful.
*
* @param command the command to invoke.
* @param args arguments to provide to the command.
* @param outputTransform the function that will parse STDOUT data.
* @param options additional `spawn` options, if necessary.
*/
async runCommand(command, args, outputTransform, options) {
return new Promise((ok, ko) => {
// On Windows, spawning a program ending in .cmd or .bat needs to run in a shell
// https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2
const shell = onWindows() && (command.endsWith('.cmd') || command.endsWith('.bat'));
const child = (0, child_process_1.spawn)(command, args, { shell, ...options, stdio: ['inherit', 'pipe', 'pipe'] });
const stdout = new Array();
child.stdout.on('data', (chunk) => {
stdout.push(Buffer.from(chunk));
});
child.stderr.on('data', (chunk) => {
stdout.push(Buffer.from(chunk));
});
child.once('error', ko);
child.once('close', (exitCode, signal) => {
try {
ok({
command: `${command} ${args.join(' ')}`,
exitCode,
signal,
stdout: outputTransform(stdout),
});
}
catch (error) {
ko(error);
}
});
});
}
}
exports.Npm = Npm;
_Npm_npmCommand = new WeakMap();
/**
* A filter to apply when selecting optional peer dependencies, based on how
* their version target is specified.
*/
var OptionalPeerDepsFilter;
(function (OptionalPeerDepsFilter) {
/**
* Ignore all optional peer dependencies when installing.
*/
OptionalPeerDepsFilter[OptionalPeerDepsFilter["None"] = 0] = "None";
/**
* Install only optional peer dependencies specified as a version range, and
* ignore those specified as a URL or local path.
*/
OptionalPeerDepsFilter[OptionalPeerDepsFilter["VersionRange"] = 1] = "VersionRange";
/**
* Install all optional peer dependencies regardless of how they are
* specified. This requires URL and local-path dependencies to be reachable.
*/
OptionalPeerDepsFilter[OptionalPeerDepsFilter["All"] = 2] = "All";
})(OptionalPeerDepsFilter || (exports.OptionalPeerDepsFilter = OptionalPeerDepsFilter = {}));
/**
* Asserts the provided CommandResult corresponds to a command that exited with
* code `0`. If that is not the case, this will throw an appropriate error,
* either `NpmError` or `NoSpaceLeftOnDevice`.
*/
function assertSuccess(result) {
var _a;
const { command, exitCode, signal, stdout } = result;
if (exitCode === 0) {
return;
}
if (signal != null) {
throw new errors_1.NpmError(`Command "${command}" was killed by ${signal}`, stdout);
}
if (exitCode === 228 || ((_a = stdout.error) === null || _a === void 0 ? void 0 : _a.code) === 'ENOSPC') {
throw new errors_1.NoSpaceLeftOnDevice(`Command "${command}" failed due to insufficient available disk space`);
}
const { code, detail, summary } = stdout.error;
const message = [
`Command "${command}" exited with code ${exitCode}`,
summary ? `: ${summary}` : '',
detail ? `\n${detail}` : '',
// If we have an error, but neither detail nor summary, then we probably
// have an actual Error object, so we'll stringify that here...
stdout.error && !detail && !summary ? `: ${stdout.error}` : '',
].join('');
if (typeof summary === 'string' && summary.includes('must provide string spec')) {
// happens when package.json dependencies don't have a spec.
// for example: https://github.com/markusl/cdk-codepipeline-bitbucket-build-result-reporter/blob/v0.0.7/package.json
throw new errors_1.UnInstallablePackageError(summary);
}
// happens when a package has been deleted from npm
// for example: sns-app-jsii-component
if (!code && !detail && typeof summary === 'string' && summary.includes('Cannot convert undefined or null to object')) {
throw new errors_1.UnInstallablePackageError(summary);
}
switch (code) {
case 'E404': // package (or dependency) can't be found on NPM. This can happen if the package depends on a deprecated package (for example).
case 'EOVERRIDE': // Package contains some version overrides that conflict.
case 'ERESOLVE': // dependency resolution problem requires a manual intervention (most likely...)
case 'ENOVERSIONS': // package has been removed from npm
throw new errors_1.UnInstallablePackageError(message);
default:
throw new errors_1.NpmError(message, stdout, code);
}
}
/**
* Concatenates the provided chunks into a single Buffer, converts it to a
* string using the designated encoding, then JSON-parses it. If any part of
* this process results in an error, returns an object that contains the error
* and the raw chunks.
*/
function chunksToObject(chunks, encoding = 'utf-8') {
const raw = Buffer.concat(chunks).toString(encoding);
try {
// npm will sometimes print non json log lines even though --json was requested.
// observed these log lines always start with 'npm', so we filter those out.
// for example: "npm notice New patch version of npm available! 8.1.0 -> 8.1.3"
// for example: "npm ERR! must provide string spec"
const onlyJson = raw.split(/[\r\n]+/) // split on any newlines, because npm returns inconsistent newline characters on Windows
.filter(l => !l.startsWith('npm'))
// Suppress debugger messages, if present...
.filter(l => l !== 'Debugger attached.')
.filter(l => l !== 'Waiting for the debugger to disconnect...')
// Re-join...
.join(os.EOL);
return JSON.parse(onlyJson);
}
catch (error) {
return { error, raw };
}
}
/**
* Helper to detect if we are running on Windows.
*/
function onWindows() {
return process.platform === 'win32';
}
/**
* Get the npm binary path depending on the platform.
* @returns "npm.cmd" on Windows, otherwise "npm"
*/
function npmPlatformAwareCommand() {
if (onWindows()) {
return 'npm.cmd';
}
return 'npm';
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX25wbS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9kb2NnZW4vdmlldy9fbnBtLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLGlEQUFnRTtBQUNoRSwyQkFBb0M7QUFDcEMsdUNBQXlCO0FBQ3pCLCtCQUE0QjtBQUM1QixtQ0FBK0I7QUFDL0IsbURBQXFEO0FBQ3JELHlDQUF3RjtBQUV4RixNQUFhLEdBQUc7SUFHZCxZQUNtQixnQkFBd0IsRUFDeEIsU0FBUyxPQUFPLENBQUMsR0FBRyxFQUNyQyxVQUFtQjtRQUZGLHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBUTtRQUN4QixXQUFNLEdBQU4sTUFBTSxDQUFjO1FBSnZDLGtDQUFnQztRQU85Qix1QkFBQSxJQUFJLG1CQUFlLFVBQVUsTUFBQSxDQUFDO0lBQ2hDLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0ksS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFjLEVBQUUsS0FBSyxHQUFHLEtBQUs7UUFDaEQsTUFBTSxXQUFXLEdBQUc7WUFDbEIsR0FBRyxLQUFLO2dCQUNOLENBQUMsQ0FBQztvQkFDQSx3RkFBd0Y7b0JBQ3hGLGtGQUFrRjtvQkFDbEYsU0FBUztpQkFDVjtnQkFDRCxDQUFDLENBQUMsRUFBRTtZQUNOLDBEQUEwRDtZQUMxRCxtRkFBbUY7WUFDbkYsa0JBQWtCO1lBQ2xCLGlDQUFpQztZQUNqQyxZQUFZO1lBQ1osZ0RBQWdEO1lBQ2hELGdCQUFnQjtZQUNoQixpREFBaUQ7WUFDakQsbUJBQW1CO1lBQ25CLDZCQUE2QjtZQUM3QixRQUFRO1NBQ1QsQ0FBQztRQUVGLElBQUksQ0FBQztZQUNILGFBQWEsQ0FBQyxNQUFNLElBQUksQ0FBQyxVQUFVLENBQ2pDLE1BQU0sSUFBSSxDQUFDLGNBQWMsRUFBRSxFQUMzQjtnQkFDRSxTQUFTO2dCQUNULElBQUksQ0FBQyxTQUFTLENBQUMs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YUFDdkMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLDJDQUEyQyxDQUFDO1lBQy9ELGFBQWE7YUFDWixJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2hCLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM5QixDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLE9BQU8sRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLENBQUM7SUFDeEIsQ0FBQztBQUNILENBQUM7QUFVRDs7R0FFRztBQUNILFNBQVMsU0FBUztJQUNoQixPQUFPLE9BQU8sQ0FBQyxRQUFRLEtBQUssT0FBTyxDQUFDO0FBQ3RDLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFTLHVCQUF1QjtJQUM5QixJQUFJLFNBQVMsRUFBRSxFQUFFLENBQUM7UUFDaEIsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUVELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHNwYXduLCBTcGF3bk9wdGlvbnNXaXRob3V0U3RkaW8gfSBmcm9tICdjaGlsZF9wcm9jZXNzJztcbmltcG9ydCB7IHByb21pc2VzIGFzIGZzIH0gZnJvbSAnZnMnO1xuaW1wb3J0ICogYXMgb3MgZnJvbSAnb3MnO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgbWFqb3IgfSBmcm9tICdzZW12ZXInO1xuaW1wb3J0IHsgZXh0cmFjdFBhY2thZ2VOYW1lIH0gZnJvbSAnLi9kb2N1bWVudGF0aW9uJztcbmltcG9ydCB7IE5vU3BhY2VMZWZ0T25EZXZpY2UsIFVuSW5zdGFsbGFibGVQYWNrYWdlRXJyb3IsIE5wbUVycm9yIH0gZnJvbSAnLi4vLi4vZXJyb3JzJztcblxuZXhwb3J0IGNsYXNzIE5wbSB7XG4gICNucG1Db21tYW5kOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgcHVibGljIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgd29ya2luZ0RpcmVjdG9yeTogc3RyaW5nLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgbG9nZ2VyID0gY29uc29sZS5sb2csXG4gICAgbnBtQ29tbWFuZD86IHN0cmluZyxcbiAgKSB7XG4gICAgdGhpcy4jbnBtQ29tbWFuZCA9IG5wbUNvbW1hbmQ7XG4gIH1cblxuICAvKipcbiAgICogSW5zdGFsbHMgdGhlIGRlc2lnbmF0ZWQgcGFja2FnZSBpbnRvIHRoaXMgcmVwb3NpdG9yeSdzIHdvcmtpbmcgZGlyZWN0b3J5LlxuICAgKlxuICAgKiBAcGFyYW0gdGFyZ2V0IHRoZSBuYW1lIG9yIHBhdGggdG8gdGhlIHBhY2thZ2UgdGhhdCBuZWVkcyB0byBiZSBpbnN0YWxsZWQuXG4gICAqIEBwYXJhbSBmb3JjZSB3aGV0aGVyIHRvIHBhc3MgYC0tZm9yY2VgIHRvIGBucG0gaW5zdGFsbGAuXG4gICAqXG4gICAqIEByZXR1cm5zIHRoZSBuYW1lIG9mIHRoZSBwYWNrYWdlIHRoYXQgd2FzIGluc3RhbGxlZC5cbiAgICovXG4gIHB1YmxpYyBhc3luYyBpbnN0YWxsKHRhcmdldDogc3RyaW5nLCBmb3JjZSA9IGZhbHNlKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBjb21tb25GbGFncyA9IFtcbiAgICAgIC4uLmZvcmNlXG4gICAgICAgID8gW1xuICAgICAgICAgIC8vIGZvcmNlIGluc3RhbGwsIGlnbm9yaW5nIHJlY29tbWVuZGVkIHByb3RlY3Rpb25zIHN1Y2ggYXMgcGxhdGZvcm0gY2hlY2tzLiBUaGlzIGlzIG9rYXlcbiAgICAgICAgICAvLyBiZWNhdXNlIHdlIGFyZSBub3QgYWN0dWFsbHkgZXhlY3V0aW5nIHRoZSBjb2RlIGJlaW5nIGluc3RhbGxlZCBpbiB0aGlzIGNvbnRleHQuXG4gICAgICAgICAgJy0tZm9yY2UnLFxuICAgICAgICBdXG4gICAgICAgIDogW10sXG4gICAgICAvLyB0aGlzIGlzIGNyaXRpY2FsIGZyb20gYSBzZWN1cml0eSBwZXJzcGVjdGl2ZSB0byBwcmV2ZW50XG4gICAgICAvLyBjb2RlIGV4ZWN1dGlvbiBhcyBwYXJ0IG9mIHRoZSBpbnN0YWxsIGNvbW1hbmQgdXNpbmcgbnBtIGhvb2tzLiAoZS5nIHBvc3RJbnN0YWxsKVxuICAgICAgJy0taWdub3JlLXNjcmlwdHMnLFxuICAgICAgLy8gc2F2ZSB0aW1lIGJ5IG5vdCBydW5uaW5nIGF1ZGl0XG4gICAgICAnLS1uby1hdWRpdCcsXG4gICAgICAvLyBlbnN1cmVzIG5wbSBkb2VzIG5vdCBpbnNlcnQgYW55dGhpbmcgaW4gJFBBVEhcbiAgICAgICctLW5vLWJpbi1saW5rcycsXG4gICAgICAvLyBkb24ndCB3cml0ZSBvciB1cGRhdGUgYSBwYWNrYWdlLWxvY2suanNvbiBmaWxlXG4gICAgICAnLS1uby1wYWNrYWdlLWxvY2snLFxuICAgICAgLy8gYWx3YXlzIHByb2R1Y2UgSlNPTiBvdXRwdXRcbiAgICAgICctLWpzb24nLFxuICAgIF07XG5cbiAgICB0cnkge1xuICAgICAgYXNzZXJ0U3VjY2Vzcyhhd2FpdCB0aGlzLnJ1bkNvbW1hbmQoXG4gICAgICAgIGF3YWl0IHRoaXMubnBtQ29tbWFuZFBhdGgoKSxcbiAgICAgICAgW1xuICAgICAgICAgICdpbnN0YWxsJyxcbiAgICAgICAgICBKU09OLnN0cmluZ2lmeSh0YXJnZXQpLFxuICAgICAgICAgIC4uLmNvbW1vbkZsYWdzLFxuICAgICAgICAgIC8vIGVuc3VyZXMgd2UgYXJlIGluc3RhbGxpbmcgZGV2RGVwZW5kZW5jaWVzLCB0b28uXG4gICAgICAgICAgJy0taW5jbHVkZT1kZXYnLFxuICAgICAgICAgICctLWluY2x1ZGU9cGVlcicsXG4gICAgICAgICAgJy0taW5jbHVkZT1vcHRpb25hbCcsXG4gICAgICAgICAgLy8gTWFrZSBzdXJlIHdlIGdldCBhIGBwYWNrYWdlLmpzb25gIHNvIHdlIGNhbiBmaWd1cmUgb3V0IHRoZSBhY3R1YWwgcGFja2FnZSBuYW1lLlxuICAgICAgICAgICctLXNhdmUnLFxuICAgICAgICBdLFxuICAgICAgICBjaHVua3NUb09iamVjdCxcbiAgICAgICAge1xuICAgICAgICAgIGN3ZDogdGhpcy53b3JraW5nRGlyZWN0b3J5LFxuICAgICAgICAgIHNoZWxsOiB0cnVlLFxuICAgICAgICB9LFxuICAgICAgKSk7XG5cbiAgICAgIGNvbnN0IHsgZGVwZW5kZW5jaWVzIH0gPSBKU09OLnBhcnNlKGF3YWl0IGZzLnJlYWRGaWxlKGpvaW4odGhpcy53b3JraW5nRGlyZWN0b3J5LCAncGFja2FnZS5qc29uJyksICd1dGYtOCcpKTtcbiAgICAgIGNvbnN0IG5hbWVzID0gT2JqZWN0LmtleXMoZGVwZW5kZW5jaWVzID8/IHt9KTtcbiAgICAgIGNvbnN0IG5hbWUgPSBuYW1lcy5sZW5ndGggPT09IDFcbiAgICAgICAgPyBuYW1lc1swXVxuICAgICAgICA6IGV4dHJhY3RQYWNrYWdlTmFtZSh0YXJnZXQpO1xuXG4gICAgICBjb25zdCBvcHRpb25hbFBlZXJEZXBzID0gYXdhaXQgdGhpcy5saXN0T3B0aW9uYWxQZWVyRGVwcyhuYW1lKTtcbiAgICAgIGlmIChvcHRpb25hbFBlZXJEZXBzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgYXNzZXJ0U3VjY2Vzcyhhd2FpdCB0aGlzLnJ1bkNvbW1hbmQoXG4gICAgICAgICAgYXdhaXQgdGhpcy5ucG1Db21tYW5kUGF0aCgpLFxuICAgICAgICAgIFtcbiAgICAgICAgICAgICdpbnN0YWxsJyxcbiAgICAgICAgICAgIC4uLm9wdGlvbmFsUGVlckRlcHMsXG4gICAgICAgICAgICAuLi5jb21tb25GbGFncyxcbiAgICAgICAgICAgIC8vIFNhdmUgYXMgb3B0aW9uYWwgaW4gdGhlIHJvb3QgcGFja2FnZS5qc29uIChjb3VydGVzeSlcbiAgICAgICAgICAgICctLXNhdmUtb3B0aW9uYWwnLFxuICAgICAgICAgIF0sXG4gICAgICAgICAgY2h1bmtzVG9PYmplY3QsXG4gICAgICAgICAge1xuICAgICAgICAgICAgY3dkOiB0aGlzLndvcmtpbmdEaXJlY3RvcnksXG4gICAgICAgICAgICBzaGVsbDogdHJ1ZSxcbiAgICAgICAgICB9LFxuICAgICAgICApKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIG5hbWU7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgaWYgKCFmb3JjZSAmJiAoZSBpbnN0YW5jZW9mIE5wbUVycm9yKSAmJiBlLm5wbUVycm9yQ29kZSA9PT0gJ0VCQURQTEFURk9STScpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCducG0gaW5zdGFsbCBmYWlsZWQgd2l0aCBFQkFEUExBVEZPUk0sIHJldHJ5aW5nIHdpdGggLS1mb3JjZScpO1xuICAgICAgICByZXR1cm4gdGhpcy5pbnN0YWxsKHRhcmdldCwgdHJ1ZSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBsaXN0T3B0aW9uYWxQZWVyRGVwcyh0YXJnZXQ6IHN0cmluZyk6IFByb21pc2U8cmVhZG9ubHkgc3RyaW5nW10+IHtcbiAgICBjb25zdCByZXN1bHQgPSBuZXcgQXJyYXk8c3RyaW5nPigpO1xuXG4gICAgY29uc3QgcGFja2FnZUpzb24gPSBKU09OLnBhcnNlKGF3YWl0IGZzLnJlYWRGaWxlKGpvaW4odGhpcy53b3JraW5nRGlyZWN0b3J5LCAnbm9kZV9tb2R1bGVzJywgdGFyZ2V0LCAncGFja2FnZS5qc29uJyksICd1dGYtOCcpKTtcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCB7IG9wdGlvbmFsIH1dIG9mIE9iamVjdC5lbnRyaWVzKHBhY2thZ2VKc29uLnBlZXJEZXBlbmRlbmNpZXNNZXRhID8/IHt9KSBhcyBbc3RyaW5nLCB7IG9wdGlvbmFsOiBib29sZWFuIH1dW10pIHtcbiAgICAgIGlmICghb3B0aW9uYWwpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBjb25zdCB2ZXJzaW9uID0gcGFja2FnZUpzb24ucGVlckRlcGVuZGVuY2llc1tuYW1lXTtcbiAgICAgIGlmICh2ZXJzaW9uID09IG51bGwpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICByZXN1bHQucHVzaChKU09OLnN0cmluZ2lmeShgJHtuYW1lfUAke3ZlcnNpb259YCkpO1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICogT2J0YWlucyB0aGUgcGF0aCB0byB0aGUgbnBtIGNvbW1hbmQgdGhhdCBzaG91bGQgYmUgcnVuLiBUaGlzIGFsd2F5cyByZXR1cm5zXG4gICAqIHRoZSBwYXRoIHRvIGFuIG5wbSA+PSA3LCB3aGljaCBcImNvcnJlY3RseVwiIGhhbmRsZXMgcGVlckRlcGVuZGVuY2llcy4gSWYgdGhlXG4gICAqIG5wbSB2ZXJzaW9uIHRoYXQncyBhdmFpbGFibGUgaW4gJFBBVEggc2F0aXNmaWVzIHRoaXMgcHJlZGljYXRlLCB0aGlzIHdpbGxcbiAgICogc2ltcGx5IHJldHVybiBgbnBtYC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgbnBtQ29tbWFuZFBhdGgoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBpZiAodGhpcy4jbnBtQ29tbWFuZCkge1xuICAgICAgcmV0dXJuIHRoaXMuI25wbUNvbW1hbmQ7XG4gICAgfVxuXG4gICAgLy8gR2V0IHRoZSBwbGF0Zm9ybSBzcGVjaWZpYyBucG0gY29tbWFuZFxuICAgIGNvbnN0IG5wbSA9IG5wbVBsYXRmb3JtQXdhcmVDb21tYW5kKCk7XG5cbiAgICB0cnkge1xuICAgICAgLy8gSWYgdGhlIG5wbSBpbiAkUEFUSCBpcyA+PSB2Nywgd2UgY2FuIHVzZSB0aGF0IGRpcmVjdGx5LiBUaGVcbiAgICAgIC8vIGBucG0gdmVyc2lvbiAtLWpzb25gIGNvbW1hbmQgcmV0dXJucyBhIEpTT04gb2JqZWN0IGNvbnRhaW5pbmcgdGhlXG4gICAgICAvLyB2ZXJzaW9ucyBvZiBzZXZlcmFsIGNvbXBvbmVudHMgKG5wbSwgbm9kZSwgdjgsIGV0Yy4uLikuIFdlIGFyZSBvbmx5XG4gICAgICAvLyBpbnRlcmVzdGVkIGluIHRoZSBgbnBtYCBrZXkgaGVyZS5cbiAgICAgIGNvbnN0IHsgZXhpdENvZGUsIHN0ZG91dCB9ID0gYXdhaXQgdGhpcy5ydW5Db21tYW5kKFxuICAgICAgICBucG0sIFsndmVyc2lvbicsICctLWpzb24nXSxcbiAgICAgICAgY2h1bmtzVG9PYmplY3QsXG4gICAgICApO1xuICAgICAgaWYgKGV4aXRDb2RlID09PSAwICYmIG1ham9yKChzdGRvdXQgYXMgYW55KS5ucG0pID49IDcpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuI25wbUNvbW1hbmQgPSBucG07XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhpcy5sb2dnZXIoJ0NvdWxkIG5vdCBkZXRlcm1pbmUgdmVyc2lvbiBvZiBucG0gaW4gJFBBVEg6JywgZSk7XG4gICAgfVxuXG4gICAgLy8gbnBtQDggaXMgbmVlZGVkIHNvIHRoYXQgd2UgYWxzbyBpbnN0YWxsIHBlZXJEZXBlbmRlbmNpZXMgLSB0aGV5IGFyZSBuZWVkZWQgdG8gY29uc3RydWN0XG4gICAgLy8gdGhlIGZ1bGwgdHlwZSBzeXN0ZW0uXG4gICAgdGhpcy5sb2dnZXIoJ1RoZSBucG0gaW4gJFBBVEggaXMgbm90ID49IHY3LiBJbnN0YWxsaW5nIG5wbUA4IGxvY2FsbHkuLi4nKTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnJ1bkNvbW1hbmQoXG4gICAgICBucG0sXG4gICAgICBbJ2luc3RhbGwnLCAnbnBtQDgnLCAnLS1uby1wYWNrYWdlLWxvY2snLCAnLS1uby1zYXZlJywgJy0tanNvbiddLFxuICAgICAgY2h1bmtzVG9PYmplY3QsXG4gICAgICB7XG4gICAgICAgIGN3ZDogdGhpcy53b3JraW5nRGlyZWN0b3J5LFxuICAgICAgICBzaGVsbDogdHJ1ZSxcbiAgICAgIH0sXG4gICAgKTtcbiAgICBhc3NlcnRTdWNjZXNzKHJlc3VsdCk7XG5cbiAgICB0aGlzLiNucG1Db21tYW5kID0gam9pbih0aGlzLndvcmtpbmdEaXJlY3RvcnksICdub2RlX21vZHVsZXMnLCAnLmJpbicsIG5wbSk7XG4gICAgdGhpcy5sb2dnZXIoYERvbmUgaW5zdGFsbGluZyBucG1AOCBhdCAke3RoaXMuI25wbUNvbW1hbmR9YCk7XG4gICAgcmV0dXJuIHRoaXMuI25wbUNvbW1hbmQ7XG4gIH1cblxuICAvKipcbiAgICogUnVucyB0aGUgc3VwcGxpZWQgY29tbWFuZCB3aXRoIHRoZSBwcm92aWRlZCBhcmd1bWVudHMsIGNhcHR1cmVzIHRoZSBkYXRhXG4gICAqIHB1c2hlZCB0byBTVERPVVQsIGFuZCBcInBhcnNlc1wiIGl0IHVzaW5nIGBvdXRwdXRUcmFuc2Zvcm1gIHRvIHByb2R1Y2UgYVxuICAgKiByZXN1bHQuXG4gICAqXG4gICAqIFlvdSBtdXN0IGNvbnN1bHQgdGhlIGBleGl0Q29kZWAgb2YgdGhlIHJldHVybiB2YWx1ZSB0byBkZXRlcm1pbmUgd2hldGhlclxuICAgKiB0aGUgY29tbWFuZCB3YXMgc3VjY2Vzc2Z1bCBvciBub3QuIFVzZSB0aGUgYGFzc2VydFN1Y2Nlc3NgIGZ1bmN0aW9uIHRvXG4gICAqIHRocm93L3JlamVjdCBpbiBjYXNlIHRoZSBleGVjdXRpb24gd2FzIG5vdCBzdWNjZXNzZnVsLlxuICAgKlxuICAgKiBAcGFyYW0gY29tbWFuZCAgICAgICAgIHRoZSBjb21tYW5kIHRvIGludm9rZS5cbiAgICogQHBhcmFtIGFyZ3MgICAgICAgICAgICBhcmd1bWVudHMgdG8gcHJvdmlkZSB0byB0aGUgY29tbWFuZC5cbiAgICogQHBhcmFtIG91dHB1dFRyYW5zZm9ybSB0aGUgZnVuY3Rpb24gdGhhdCB3aWxsIHBhcnNlIFNURE9VVCBkYXRhLlxuICAgKiBAcGFyYW0gb3B0aW9ucyAgICAgICAgIGFkZGl0aW9uYWwgYHNwYXduYCBvcHRpb25zLCBpZiBuZWNlc3NhcnkuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHJ1bkNvbW1hbmQ8VCA9IEJ1ZmZlcj4oXG4gICAgY29tbWFuZDogc3RyaW5nLFxuICAgIGFyZ3M6IHJlYWRvbmx5IHN0cmluZ1tdLFxuICAgIG91dHB1dFRyYW5zZm9ybTogKHN0ZGVycjogcmVhZG9ubHkgQnVmZmVyW10pID0+IFQsXG4gICAgb3B0aW9ucz86IFNwYXduT3B0aW9uc1dpdGhvdXRTdGRpbyxcbiAgKTogUHJvbWlzZTxDb21tYW5kUmVzdWx0PFQ+PiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlPENvbW1hbmRSZXN1bHQ8VD4+KChvaywga28pID0+IHtcbiAgICAgIC8vIE9uIFdpbmRvd3MsIHNwYXduaW5nIGEgcHJvZ3JhbSBlbmRpbmcgaW4gLmNtZCBvciAuYmF0IG5lZWRzIHRvIHJ1biBpbiBhIHNoZWxsXG4gICAgICAvLyBodHRwczovL25vZGVqcy5vcmcvZW4vYmxvZy92dWxuZXJhYmlsaXR5L2FwcmlsLTIwMjQtc2VjdXJpdHktcmVsZWFzZXMtMlxuICAgICAgY29uc3Qgc2hlbGwgPSBvbldpbmRvd3MoKSAmJiAoY29tbWFuZC5lbmRzV2l0aCgnLmNtZCcpIHx8IGNvbW1hbmQuZW5kc1dpdGgoJy5iYXQnKSk7XG4gICAgICBjb25zdCBjaGlsZCA9IHNwYXduKGNvbW1hbmQsIGFyZ3MsIHsgc2hlbGwsIC4uLm9wdGlvbnMsIHN0ZGlvOiBbJ2luaGVyaXQnLCAncGlwZScsICdwaXBlJ10gfSk7XG4gICAgICBjb25zdCBzdGRvdXQgPSBuZXcgQXJyYXk8QnVmZmVyPigpO1xuICAgICAgY2hpbGQuc3Rkb3V0Lm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XG4gICAgICAgIHN0ZG91dC5wdXNoKEJ1ZmZlci5mcm9tKGNodW5rKSk7XG4gICAgICB9KTtcbiAgICAgIGNoaWxkLnN0ZGVyci5vbignZGF0YScsIChjaHVuaykgPT4ge1xuICAgICAgICBzdGRvdXQucHVzaChCdWZmZXIuZnJvbShjaHVuaykpO1xuICAgICAgfSk7XG5cbiAgICAgIGNoaWxkLm9uY2UoJ2Vycm9yJywga28pO1xuICAgICAgY2hpbGQub25jZSgnY2xvc2UnLCAoZXhpdENvZGUsIHNpZ25hbCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIG9rKHtcbiAgICAgICAgICAgIGNvbW1hbmQ6IGAke2NvbW1hbmR9ICR7YXJncy5qb2luKCcgJyl9YCxcbiAgICAgICAgICAgIGV4aXRDb2RlLFxuICAgICAgICAgICAgc2lnbmFsLFxuICAgICAgICAgICAgc3Rkb3V0OiBvdXRwdXRUcmFuc2Zvcm0oc3Rkb3V0KSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBrbyhlcnJvcik7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG59XG5cbi8qKlxuICogQSBmaWx0ZXIgdG8gYXBwbHkgd2hlbiBzZWxlY3Rpbmcgb3B0aW9uYWwgcGVlciBkZXBlbmRlbmNpZXMsIGJhc2VkIG9uIGhvd1xuICogdGhlaXIgdmVyc2lvbiB0YXJnZXQgaXMgc3BlY2lmaWVkLlxuICovXG5leHBvcnQgZW51bSBPcHRpb25hbFBlZXJEZXBzRmlsdGVyIHtcbiAgLyoqXG4gICAqIElnbm9yZSBhbGwgb3B0aW9uYWwgcGVlciBkZXBlbmRlbmNpZXMgd2hlbiBpbnN0YWxsaW5nLlxuICAgKi9cbiAgTm9uZSxcblxuICAvKipcbiAgICogSW5zdGFsbCBvbmx5IG9wdGlvbmFsIHBlZXIgZGVwZW5kZW5jaWVzIHNwZWNpZmllZCBhcyBhIHZlcnNpb24gcmFuZ2UsIGFuZFxuICAgKiBpZ25vcmUgdGhvc2Ugc3BlY2lmaWVkIGFzIGEgVVJMIG9yIGxvY2FsIHBhdGguXG4gICAqL1xuICBWZXJzaW9uUmFuZ2UsXG5cbiAgLyoqXG4gICAqIEluc3RhbGwgYWxsIG9wdGlvbmFsIHBlZXIgZGVwZW5kZW5jaWVzIHJlZ2FyZGxlc3Mgb2YgaG93IHRoZXkgYXJlXG4gICAqIHNwZWNpZmllZC4gVGhpcyByZXF1aXJlcyBVUkwgYW5kIGxvY2FsLXBhdGggZGVwZW5kZW5jaWVzIHRvIGJlIHJlYWNoYWJsZS5cbiAgICovXG4gIEFsbCxcbn1cblxuaW50ZXJmYWNlIENvbW1hbmRSZXN1bHQ8VD4ge1xuICByZWFkb25seSBjb21tYW5kOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGV4aXRDb2RlOiBudW1iZXIgfCBudWxsO1xuICByZWFkb25seSBzaWduYWw6IE5vZGVKUy5TaWduYWxzIHwgbnVsbDtcbiAgcmVhZG9ubHkgc3Rkb3V0OiBUO1xufVxuaW50ZXJmYWNlIFN1Y2Nlc3NmdWxDb21tYW5kUmVzdWx0PFQ+IGV4dGVuZHMgQ29tbWFuZFJlc3VsdDxUPiB7XG4gIHJlYWRvbmx5IGV4aXRDb2RlOiAwO1xuICByZWFkb25seSBzaWduYWw6IG51bGw7XG59XG5cbi8qKlxuICogQXNzZXJ0cyB0aGUgcHJvdmlkZWQgQ29tbWFuZFJlc3VsdCBjb3JyZXNwb25kcyB0byBhIGNvbW1hbmQgdGhhdCBleGl0ZWQgd2l0aFxuICogY29kZSBgMGAuIElmIHRoYXQgaXMgbm90IHRoZSBjYXNlLCB0aGlzIHdpbGwgdGhyb3cgYW4gYXBwcm9wcmlhdGUgZXJyb3IsXG4gKiBlaXRoZXIgYE5wbUVycm9yYCBvciBgTm9TcGFjZUxlZnRPbkRldmljZWAuXG4gKi9cbmZ1bmN0aW9uIGFzc2VydFN1Y2Nlc3MocmVzdWx0OiBDb21tYW5kUmVzdWx0PFJlc3BvbnNlT2JqZWN0Pik6IGFzc2VydHMgcmVzdWx0IGlzIFN1Y2Nlc3NmdWxDb21tYW5kUmVzdWx0PFJlc3BvbnNlT2JqZWN0PiB7XG4gIGNvbnN0IHsgY29tbWFuZCwgZXhpdENvZGUsIHNpZ25hbCwgc3Rkb3V0IH0gPSByZXN1bHQ7XG4gIGlmIChleGl0Q29kZSA9PT0gMCkge1xuICAgIHJldHVybjtcbiAgfVxuICBpZiAoc2lnbmFsICE9IG51bGwpIHtcbiAgICB0aHJvdyBuZXcgTnBtRXJyb3IoYENvbW1hbmQgXCIke2NvbW1hbmR9XCIgd2FzIGtpbGxlZCBieSAke3NpZ25hbH1gLCBzdGRvdXQpO1xuICB9XG4gIGlmIChleGl0Q29kZSA9PT0gMjI4IHx8IHN0ZG91dC5lcnJvcj8uY29kZSA9PT0gJ0VOT1NQQycpIHtcbiAgICB0aHJvdyBuZXcgTm9TcGFjZUxlZnRPbkRldmljZShgQ29tbWFuZCBcIiR7Y29tbWFuZH1cIiBmYWlsZWQgZHVlIHRvIGluc3VmZmljaWVudCBhdmFpbGFibGUgZGlzayBzcGFjZWApO1xuICB9XG4gIGNvbnN0IHsgY29kZSwgZGV0YWlsLCBzdW1tYXJ5IH0gPSBzdGRvdXQuZXJyb3I7XG4gIGNvbnN0IG1lc3NhZ2UgPSBbXG4gICAgYENvbW1hbmQgXCIke2NvbW1hbmR9XCIgZXhpdGVkIHdpdGggY29kZSAke2V4aXRDb2RlfWAsXG4gICAgc3VtbWFyeSA/IGA6ICR7c3VtbWFyeX1gIDogJycsXG4gICAgZGV0YWlsID8gYFxcbiR7ZGV0YWlsfWAgOiAnJyxcbiAgICAvLyBJZiB3ZSBoYXZlIGFuIGVycm9yLCBidXQgbmVpdGhlciBkZXRhaWwgbm9yIHN1bW1hcnksIHRoZW4gd2UgcHJvYmFibHlcbiAgICAvLyBoYXZlIGFuIGFjdHVhbCBFcnJvciBvYmplY3QsIHNvIHdlJ2xsIHN0cmluZ2lmeSB0aGF0IGhlcmUuLi5cbiAgICBzdGRvdXQuZXJyb3IgJiYgIWRldGFpbCAmJiAhc3VtbWFyeSA/IGA6ICR7c3Rkb3V0LmVycm9yfWAgOiAnJyxcbiAgXS5qb2luKCcnKTtcblxuICBpZiAodHlwZW9mIHN1bW1hcnkgPT09ICdzdHJpbmcnICYmIHN1bW1hcnkuaW5jbHVkZXMoJ211c3QgcHJvdmlkZSBzdHJpbmcgc3BlYycpKSB7XG4gICAgLy8gaGFwcGVucyB3aGVuIHBhY2thZ2UuanNvbiBkZXBlbmRlbmNpZXMgZG9uJ3QgaGF2ZSBhIHNwZWMuXG4gICAgLy8gZm9yIGV4YW1wbGU6IGh0dHBzOi8vZ2l0aHViLmNvbS9tYXJrdXNsL2Nkay1jb2RlcGlwZWxpbmUtYml0YnVja2V0LWJ1aWxkLXJlc3VsdC1yZXBvcnRlci9ibG9iL3YwLjAuNy9wYWNrYWdlLmpzb25cbiAgICB0aHJvdyBuZXcgVW5JbnN0YWxsYWJsZVBhY2thZ2VFcnJvcihzdW1tYXJ5KTtcbiAgfVxuXG4gIC8vIGhhcHBlbnMgd2hlbiBhIHBhY2thZ2UgaGFzIGJlZW4gZGVsZXRlZCBmcm9tIG5wbVxuICAvLyBmb3IgZXhhbXBsZTogc25zLWFwcC1qc2lpLWNvbXBvbmVudFxuICBpZiAoIWNvZGUgJiYgIWRldGFpbCAmJiB0eXBlb2Ygc3VtbWFyeSA9PT0gJ3N0cmluZycgJiYgc3VtbWFyeS5pbmNsdWRlcygnQ2Fubm90IGNvbnZlcnQgdW5kZWZpbmVkIG9yIG51bGwgdG8gb2JqZWN0JykpIHtcbiAgICB0aHJvdyBuZXcgVW5JbnN0YWxsYWJsZVBhY2thZ2VFcnJvcihzdW1tYXJ5KTtcbiAgfVxuXG4gIHN3aXRjaCAoY29kZSkge1xuICAgIGNhc2UgJ0U0MDQnOiAvLyBwYWNrYWdlIChvciBkZXBlbmRlbmN5KSBjYW4ndCBiZSBmb3VuZCBvbiBOUE0uIFRoaXMgY2FuIGhhcHBlbiBpZiB0aGUgcGFja2FnZSBkZXBlbmRzIG9uIGEgZGVwcmVjYXRlZCBwYWNrYWdlIChmb3IgZXhhbXBsZSkuXG4gICAgY2FzZSAnRU9WRVJSSURFJzogLy8gUGFja2FnZSBjb250YWlucyBzb21lIHZlcnNpb24gb3ZlcnJpZGVzIHRoYXQgY29uZmxpY3QuXG4gICAgY2FzZSAnRVJFU09MVkUnOiAvLyBkZXBlbmRlbmN5IHJlc29sdXRpb24gcHJvYmxlbSByZXF1aXJlcyBhIG1hbnVhbCBpbnRlcnZlbnRpb24gKG1vc3QgbGlrZWx5Li4uKVxuICAgIGNhc2UgJ0VOT1ZFUlNJT05TJzogLy8gcGFja2FnZSBoYXMgYmVlbiByZW1vdmVkIGZyb20gbnBtXG4gICAgICB0aHJvdyBuZXcgVW5JbnN0YWxsYWJsZVBhY2thZ2VFcnJvcihtZXNzYWdlKTtcbiAgICBkZWZhdWx0OlxuICAgICAgdGhyb3cgbmV3IE5wbUVycm9yKG1lc3NhZ2UsIHN0ZG91dCwgY29kZSk7XG4gIH1cbn1cblxuLyoqXG4gKiBDb25jYXRlbmF0ZXMgdGhlIHByb3ZpZGVkIGNodW5rcyBpbnRvIGEgc2luZ2xlIEJ1ZmZlciwgY29udmVydHMgaXQgdG8gYVxuICogc3RyaW5nIHVzaW5nIHRoZSBkZXNpZ25hdGVkIGVuY29kaW5nLCB0aGVuIEpTT04tcGFyc2VzIGl0LiBJZiBhbnkgcGFydCBvZlxuICogdGhpcyBwcm9jZXNzIHJlc3VsdHMgaW4gYW4gZXJyb3IsIHJldHVybnMgYW4gb2JqZWN0IHRoYXQgY29udGFpbnMgdGhlIGVycm9yXG4gKiBhbmQgdGhlIHJhdyBjaHVua3MuXG4gKi9cbmZ1bmN0aW9uIGNodW5rc1RvT2JqZWN0KGNodW5rczogcmVhZG9ubHkgQnVmZmVyW10sIGVuY29kaW5nOiBCdWZmZXJFbmNvZGluZyA9ICd1dGYtOCcpOiBSZXNwb25zZU9iamVjdCB7XG4gIGNvbnN0IHJhdyA9IEJ1ZmZlci5jb25jYXQoY2h1bmtzKS50b1N0cmluZyhlbmNvZGluZyk7XG4gIHRyeSB7XG4gICAgLy8gbnBtIHdpbGwgc29tZXRpbWVzIHByaW50IG5vbiBqc29uIGxvZyBsaW5lcyBldmVuIHRob3VnaCAtLWpzb24gd2FzIHJlcXVlc3RlZC5cbiAgICAvLyBvYnNlcnZlZCB0aGVzZSBsb2cgbGluZXMgYWx3YXlzIHN0YXJ0IHdpdGggJ25wbScsIHNvIHdlIGZpbHRlciB0aG9zZSBvdXQuXG4gICAgLy8gZm9yIGV4YW1wbGU6IFwibnBtIG5vdGljZSBOZXcgcGF0Y2ggdmVyc2lvbiBvZiBucG0gYXZhaWxhYmxlISA4LjEuMCAtPiA4LjEuM1wiXG4gICAgLy8gZm9yIGV4YW1wbGU6IFwibnBtIEVSUiEgbXVzdCBwcm92aWRlIHN0cmluZyBzcGVjXCJcbiAgICBjb25zdCBvbmx5SnNvbiA9IHJhdy5zcGxpdCgvW1xcclxcbl0rLykgLy8gc3BsaXQgb24gYW55IG5ld2xpbmVzLCBiZWNhdXNlIG5wbSByZXR1cm5zIGluY29uc2lzdGVudCBuZXdsaW5lIGNoYXJhY3RlcnMgb24gV2luZG93c1xuICAgICAgLmZpbHRlcihsID0+ICFsLnN0YXJ0c1dpdGgoJ25wbScpKVxuICAgICAgLy8gU3VwcHJlc3MgZGVidWdnZXIgbWVzc2FnZXMsIGlmIHByZXNlbnQuLi5cbiAgICAgIC5maWx0ZXIobCA9PiBsICE9PSAnRGVidWdnZXIgYXR0YWNoZWQuJylcbiAgICAgIC5maWx0ZXIobCA9PiBsICE9PSAnV2FpdGluZyBmb3IgdGhlIGRlYnVnZ2VyIHRvIGRpc2Nvbm5lY3QuLi4nKVxuICAgICAgLy8gUmUtam9pbi4uLlxuICAgICAgLmpvaW4ob3MuRU9MKTtcbiAgICByZXR1cm4gSlNPTi5wYXJzZShvbmx5SnNvbik7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgcmV0dXJuIHsgZXJyb3IsIHJhdyB9O1xuICB9XG59XG5cbnR5cGUgUmVzcG9uc2VPYmplY3QgPVxuICAvLyBUaGUgZXJyb3Igd2hlbiB3ZSBmYWlsZWQgdG8gcGFyc2UgdGhlIG91dHB1dCBhcyBKU09OXG4gIHwgeyByZWFkb25seSBlcnJvcjogYW55OyByZWFkb25seSByYXc6IHN0cmluZyB9XG4gIC8vIFRoZSBlcnJvciBvYmplY3RzIG5wbSByZXR1cm5zIHdoZW4gb3BlcmF0aW5nIGluIC0tanNvbiBtb2RlXG4gIHwgeyByZWFkb25seSBlcnJvcjogeyByZWFkb25seSBjb2RlOiBzdHJpbmc7IHJlYWRvbmx5IHN1bW1hcnk6IHN0cmluZzsgcmVhZG9ubHkgZGV0YWlsOiBzdHJpbmcgfSB9XG4gIC8vIFRoZSBzdWNjZXNzZnVsIG9iamVjdHMgYXJlIHRyZWF0ZWQgYXMgb3BhcXVlIGJsb2JzIGhlcmVcbiAgfCB7IHJlYWRvbmx5IGVycm9yOiB1bmRlZmluZWQ7IHJlYWRvbmx5IFtrZXk6IHN0cmluZ106IHVua25vd24gfTtcblxuLyoqXG4gKiBIZWxwZXIgdG8gZGV0ZWN0IGlmIHdlIGFyZSBydW5uaW5nIG9uIFdpbmRvd3MuXG4gKi9cbmZ1bmN0aW9uIG9uV2luZG93cygpIHtcbiAgcmV0dXJuIHByb2Nlc3MucGxhdGZvcm0gPT09ICd3aW4zMic7XG59XG5cbi8qKlxuICogR2V0IHRoZSBucG0gYmluYXJ5IHBhdGggZGVwZW5kaW5nIG9uIHRoZSBwbGF0Zm9ybS5cbiAqIEByZXR1cm5zIFwibnBtLmNtZFwiIG9uIFdpbmRvd3MsIG90aGVyd2lzZSBcIm5wbVwiXG4gKi9cbmZ1bmN0aW9uIG5wbVBsYXRmb3JtQXdhcmVDb21tYW5kKCkge1xuICBpZiAob25XaW5kb3dzKCkpIHtcbiAgICByZXR1cm4gJ25wbS5jbWQnO1xuICB9XG5cbiAgcmV0dXJuICducG0nO1xufVxuIl19
;