UNPKG

jsii-docgen

Version:

generates api docs for jsii modules

366 lines 47.5 kB
"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; }; })(); 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 = exports.UNISTALLABLE_PACKAGE_ERROR_CODES = 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"); exports.UNISTALLABLE_PACKAGE_ERROR_CODES = [ 'E404', // package (or dependency) can't be found on NPM. This can happen if the package depends on a deprecated package (for example). 'EOVERRIDE', // Package contains some version overrides that conflict. 'ERESOLVE', // dependency resolution problem requires a manual intervention (most likely version conflict) 'ETARGET', // dependency resolution problem requires a manual intervention (most likely missing package) 'ENOVERSIONS', // package has been removed from npm ]; 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', 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(`${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. * * The arguments are escaped, and will not be interpreted by the shell. * * @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. // (Even if the program is a .cmd/.bat file that gets resolved implicitly, it still needs that shell, // but then it's the caller's responsibility to pass { shell: true }). // https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2 // // If we are going through the shell, escape the arguments. const shell = (options === null || options === void 0 ? void 0 : options.shell) || (onWindows() && (command.endsWith('.cmd') || command.endsWith('.bat'))); const safeArgs = shell ? args.map(escapeForShell) : args; const child = (0, child_process_1.spawn)(command, safeArgs, { ...options, shell, 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} ${safeArgs.join(' ')}`, exitCode, signal, stdout: outputTransform(stdout), }); } catch (error) { ko(error); } }); }); } } exports.Npm = Npm; _Npm_npmCommand = new WeakMap(); function escapeForShell(arg) { if (arg.match(/^[a-z0-9_\/.=-]+$/i)) { // If the argument contains only safe characters, we can return it as is, to keep the command line readable. return arg; } if (onWindows()) { // On Windows, we need to wrap the argument in double quotes and escape any existing double quotes by doubling them. return `"${arg.replace(/"/g, '""')}"`; } else { // On Unix-like systems, we can wrap the argument in single quotes and escape any existing single quotes by closing the quote, adding an escaped single quote, and reopening the quote. return `'${arg.replace(/'/g, '\'\\\'\'')}'`; } } /** * 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); } if (exports.UNISTALLABLE_PACKAGE_ERROR_CODES.includes(code)) { throw new errors_1.UnInstallablePackageError(message); } 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX25wbS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9kb2NnZW4vdmlldy9fbnBtLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLGlEQUFnRTtBQUNoRSwyQkFBb0M7QUFDcEMsdUNBQXlCO0FBQ3pCLCtCQUE0QjtBQUM1QixtQ0FBK0I7QUFDL0IsbURBQXFEO0FBQ3JELHlDQUF3RjtBQUUzRSxRQUFBLGdDQUFnQyxHQUFHO0lBQzlDLE1BQU0sRUFBRSwrSEFBK0g7SUFDdkksV0FBVyxFQUFFLHlEQUF5RDtJQUN0RSxVQUFVLEVBQUUsOEZBQThGO0lBQzFHLFNBQVMsRUFBRSw2RkFBNkY7SUFDeEcsYUFBYSxFQUFFLG9DQUFvQztDQUNwRCxDQUFDO0FBRUYsTUFBYSxHQUFHO0lBR2QsWUFDbUIsZ0JBQXdCLEVBQ3hCLFNBQVMsT0FBTyxDQUFDLEdBQUcsRUFDckMsVUFBbUI7UUFGRixxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQVE7UUFDeEIsV0FBTSxHQUFOLE1BQU0sQ0FBYztRQUp2QyxrQ0FBZ0M7UUFPOUIsdUJBQUEsSUFBSSxtQkFBZSxVQUFVLE1BQUEsQ0FBQztJQUNoQyxDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNJLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBYyxFQUFFLEtBQUssR0FBRyxLQUFLO1FBQ2hELE1BQU0sV0FBVyxHQUFHO1lBQ2xCLEdBQUcsS0FBSztnQkFDTixDQUFDLENBQUM7b0JBQ0Esd0ZBQXdGO29CQUN4RixrRkFBa0Y7b0JBQ2xGLFNBQVM7aUJBQ1Y7Z0JBQ0QsQ0FBQyxDQUFDLEVBQUU7WUFDTiwwREFBMEQ7WUFDMUQsbUZBQW1GO1lBQ25GLGtCQUFrQjtZQUNsQixpQ0FBaUM7WUFDakMsWUFBWTtZQUNaLGdEQUFnRDtZQUNoRCxnQkFBZ0I7WUFDaEIsaURBQWlEO1lBQ2pELG1CQUFtQjtZQUNuQiw2QkFB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QkFBdUI7SUFDOUIsSUFBSSxTQUFTLEVBQUUsRUFBRSxDQUFDO1FBQ2hCLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFFRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBzcGF3biwgU3Bhd25PcHRpb25zV2l0aG91dFN0ZGlvIH0gZnJvbSAnY2hpbGRfcHJvY2Vzcyc7XG5pbXBvcnQgeyBwcm9taXNlcyBhcyBmcyB9IGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIG9zIGZyb20gJ29zJztcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcbmltcG9ydCB7IG1ham9yIH0gZnJvbSAnc2VtdmVyJztcbmltcG9ydCB7IGV4dHJhY3RQYWNrYWdlTmFtZSB9IGZyb20gJy4vZG9jdW1lbnRhdGlvbic7XG5pbXBvcnQgeyBOb1NwYWNlTGVmdE9uRGV2aWNlLCBVbkluc3RhbGxhYmxlUGFja2FnZUVycm9yLCBOcG1FcnJvciB9IGZyb20gJy4uLy4uL2Vycm9ycyc7XG5cbmV4cG9ydCBjb25zdCBVTklTVEFMTEFCTEVfUEFDS0FHRV9FUlJPUl9DT0RFUyA9IFtcbiAgJ0U0MDQnLCAvLyBwYWNrYWdlIChvciBkZXBlbmRlbmN5KSBjYW4ndCBiZSBmb3VuZCBvbiBOUE0uIFRoaXMgY2FuIGhhcHBlbiBpZiB0aGUgcGFja2FnZSBkZXBlbmRzIG9uIGEgZGVwcmVjYXRlZCBwYWNrYWdlIChmb3IgZXhhbXBsZSkuXG4gICdFT1ZFUlJJREUnLCAvLyBQYWNrYWdlIGNvbnRhaW5zIHNvbWUgdmVyc2lvbiBvdmVycmlkZXMgdGhhdCBjb25mbGljdC5cbiAgJ0VSRVNPTFZFJywgLy8gZGVwZW5kZW5jeSByZXNvbHV0aW9uIHByb2JsZW0gcmVxdWlyZXMgYSBtYW51YWwgaW50ZXJ2ZW50aW9uIChtb3N0IGxpa2VseSB2ZXJzaW9uIGNvbmZsaWN0KVxuICAnRVRBUkdFVCcsIC8vIGRlcGVuZGVuY3kgcmVzb2x1dGlvbiBwcm9ibGVtIHJlcXVpcmVzIGEgbWFudWFsIGludGVydmVudGlvbiAobW9zdCBsaWtlbHkgbWlzc2luZyBwYWNrYWdlKVxuICAnRU5PVkVSU0lPTlMnLCAvLyBwYWNrYWdlIGhhcyBiZWVuIHJlbW92ZWQgZnJvbSBucG1cbl07XG5cbmV4cG9ydCBjbGFzcyBOcG0ge1xuICAjbnBtQ29tbWFuZDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4gIHB1YmxpYyBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IHdvcmtpbmdEaXJlY3Rvcnk6IHN0cmluZyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGxvZ2dlciA9IGNvbnNvbGUubG9nLFxuICAgIG5wbUNvbW1hbmQ/OiBzdHJpbmcsXG4gICkge1xuICAgIHRoaXMuI25wbUNvbW1hbmQgPSBucG1Db21tYW5kO1xuICB9XG5cbiAgLyoqXG4gICAqIEluc3RhbGxzIHRoZSBkZXNpZ25hdGVkIHBhY2thZ2UgaW50byB0aGlzIHJlcG9zaXRvcnkncyB3b3JraW5nIGRpcmVjdG9yeS5cbiAgICpcbiAgICogQHBhcmFtIHRhcmdldCB0aGUgbmFtZSBvciBwYXRoIHRvIHRoZSBwYWNrYWdlIHRoYXQgbmVlZHMgdG8gYmUgaW5zdGFsbGVkLlxuICAgKiBAcGFyYW0gZm9yY2Ugd2hldGhlciB0byBwYXNzIGAtLWZvcmNlYCB0byBgbnBtIGluc3RhbGxgLlxuICAgKlxuICAgKiBAcmV0dXJucyB0aGUgbmFtZSBvZiB0aGUgcGFja2FnZSB0aGF0IHdhcyBpbnN0YWxsZWQuXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgaW5zdGFsbCh0YXJnZXQ6IHN0cmluZywgZm9yY2UgPSBmYWxzZSk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgY29tbW9uRmxhZ3MgPSBbXG4gICAgICAuLi5mb3JjZVxuICAgICAgICA/IFtcbiAgICAgICAgICAvLyBmb3JjZSBpbnN0YWxsLCBpZ25vcmluZyByZWNvbW1lbmRlZCBwcm90ZWN0aW9ucyBzdWNoIGFzIHBsYXRmb3JtIGNoZWNrcy4gVGhpcyBpcyBva2F5XG4gICAgICAgICAgLy8gYmVjYXVzZSB3ZSBhcmUgbm90IGFjdHVhbGx5IGV4ZWN1dGluZyB0aGUgY29kZSBiZWluZyBpbnN0YWxsZWQgaW4gdGhpcyBjb250ZXh0LlxuICAgICAgICAgICctLWZvcmNlJyxcbiAgICAgICAgXVxuICAgICAgICA6IFtdLFxuICAgICAgLy8gdGhpcyBpcyBjcml0aWNhbCBmcm9tIGEgc2VjdXJpdHkgcGVyc3BlY3RpdmUgdG8gcHJldmVudFxuICAgICAgLy8gY29kZSBleGVjdXRpb24gYXMgcGFydCBvZiB0aGUgaW5zdGFsbCBjb21tYW5kIHVzaW5nIG5wbSBob29rcy4gKGUuZyBwb3N0SW5zdGFsbClcbiAgICAgICctLWlnbm9yZS1zY3JpcHRzJyxcbiAgICAgIC8vIHNhdmUgdGltZSBieSBub3QgcnVubmluZyBhdWRpdFxuICAgICAgJy0tbm8tYXVkaXQnLFxuICAgICAgLy8gZW5zdXJlcyBucG0gZG9lcyBub3QgaW5zZXJ0IGFueXRoaW5nIGluICRQQVRIXG4gICAgICAnLS1uby1iaW4tbGlua3MnLFxuICAgICAgLy8gZG9uJ3Qgd3JpdGUgb3IgdXBkYXRlIGEgcGFja2FnZS1sb2NrLmpzb24gZmlsZVxuICAgICAgJy0tbm8tcGFja2FnZS1sb2NrJyxcbiAgICAgIC8vIGFsd2F5cyBwcm9kdWNlIEpTT04gb3V0cHV0XG4gICAgICAnLS1qc29uJyxcbiAgICBdO1xuXG4gICAgdHJ5IHtcbiAgICAgIGFzc2VydFN1Y2Nlc3MoYXdhaXQgdGhpcy5ydW5Db21tYW5kKFxuICAgICAgICBhd2FpdCB0aGlzLm5wbUNvbW1hbmRQYXRoKCksXG4gICAgICAgIFtcbiAgICAgICAgICAnaW5zdGFsbCcsXG4gICAgICAgICAgdGFyZ2V0LFxuICAgICAgICAgIC4uLmNvbW1vbkZsYWdzLFxuICAgICAgICAgIC8vIGVuc3VyZXMgd2UgYXJlIGluc3RhbGxpbmcgZGV2RGVwZW5kZW5jaWVzLCB0b28uXG4gICAgICAgICAgJy0taW5jbHVkZT1kZXYnLFxuICAgICAgICAgICctLWluY2x1ZGU9cGVlcicsXG4gICAgICAgICAgJy0taW5jbHVkZT1vcHRpb25hbCcsXG4gICAgICAgICAgLy8gTWFrZSBzdXJlIHdlIGdldCBhIGBwYWNrYWdlLmpzb25gIHNvIHdlIGNhbiBmaWd1cmUgb3V0IHRoZSBhY3R1YWwgcGFja2FnZSBuYW1lLlxuICAgICAgICAgICctLXNhdmUnLFxuICAgICAgICBdLFxuICAgICAgICBjaHVua3NUb09iamVjdCxcbiAgICAgICAge1xuICAgICAgICAgIGN3ZDogdGhpcy53b3JraW5nRGlyZWN0b3J5LFxuICAgICAgICAgIHNoZWxsOiB0cnVlLFxuICAgICAgICB9LFxuICAgICAgKSk7XG5cbiAgICAgIGNvbnN0IHsgZGVwZW5kZW5jaWVzIH0gPSBKU09OLnBhcnNlKGF3YWl0IGZzLnJlYWRGaWxlKGpvaW4odGhpcy53b3JraW5nRGlyZWN0b3J5LCAncGFja2FnZS5qc29uJyksICd1dGYtOCcpKTtcbiAgICAgIGNvbnN0IG5hbWVzID0gT2JqZWN0LmtleXMoZGVwZW5kZW5jaWVzID8/IHt9KTtcbiAgICAgIGNvbnN0IG5hbWUgPSBuYW1lcy5sZW5ndGggPT09IDFcbiAgICAgICAgPyBuYW1lc1swXVxuICAgICAgICA6IGV4dHJhY3RQYWNrYWdlTmFtZSh0YXJnZXQpO1xuXG4gICAgICBjb25zdCBvcHRpb25hbFBlZXJEZXBzID0gYXdhaXQgdGhpcy5saXN0T3B0aW9uYWxQZWVyRGVwcyhuYW1lKTtcbiAgICAgIGlmIChvcHRpb25hbFBlZXJEZXBzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgYXNzZXJ0U3VjY2Vzcyhhd2FpdCB0aGlzLnJ1bkNvbW1hbmQoXG4gICAgICAgICAgYXdhaXQgdGhpcy5ucG1Db21tYW5kUGF0aCgpLFxuICAgICAgICAgIFtcbiAgICAgICAgICAgICdpbnN0YWxsJyxcbiAgICAgICAgICAgIC4uLm9wdGlvbmFsUGVlckRlcHMsXG4gICAgICAgICAgICAuLi5jb21tb25GbGFncyxcbiAgICAgICAgICAgIC8vIFNhdmUgYXMgb3B0aW9uYWwgaW4gdGhlIHJvb3QgcGFja2FnZS5qc29uIChjb3VydGVzeSlcbiAgICAgICAgICAgICctLXNhdmUtb3B0aW9uYWwnLFxuICAgICAgICAgIF0sXG4gICAgICAgICAgY2h1bmtzVG9PYmplY3QsXG4gICAgICAgICAge1xuICAgICAgICAgICAgY3dkOiB0aGlzLndvcmtpbmdEaXJlY3RvcnksXG4gICAgICAgICAgICBzaGVsbDogdHJ1ZSxcbiAgICAgICAgICB9LFxuICAgICAgICApKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIG5hbWU7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgaWYgKCFmb3JjZSAmJiAoZSBpbnN0YW5jZW9mIE5wbUVycm9yKSAmJiBlLm5wbUVycm9yQ29kZSA9PT0gJ0VCQURQTEFURk9STScpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCducG0gaW5zdGFsbCBmYWlsZWQgd2l0aCBFQkFEUExBVEZPUk0sIHJldHJ5aW5nIHdpdGggLS1mb3JjZScpO1xuICAgICAgICByZXR1cm4gdGhpcy5pbnN0YWxsKHRhcmdldCwgdHJ1ZSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBsaXN0T3B0aW9uYWxQZWVyRGVwcyh0YXJnZXQ6IHN0cmluZyk6IFByb21pc2U8cmVhZG9ubHkgc3RyaW5nW10+IHtcbiAgICBjb25zdCByZXN1bHQgPSBuZXcgQXJyYXk8c3RyaW5nPigpO1xuXG4gICAgY29uc3QgcGFja2FnZUpzb24gPSBKU09OLnBhcnNlKGF3YWl0IGZzLnJlYWRGaWxlKGpvaW4odGhpcy53b3JraW5nRGlyZWN0b3J5LCAnbm9kZV9tb2R1bGVzJywgdGFyZ2V0LCAncGFja2FnZS5qc29uJyksICd1dGYtOCcpKTtcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCB7IG9wdGlvbmFsIH1dIG9mIE9iamVjdC5lbnRyaWVzKHBhY2thZ2VKc29uLnBlZXJEZXBlbmRlbmNpZXNNZXRhID8/IHt9KSBhcyBbc3RyaW5nLCB7IG9wdGlvbmFsOiBib29sZWFuIH1dW10pIHtcbiAgICAgIGlmICghb3B0aW9uYWwpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBjb25zdCB2ZXJzaW9uID0gcGFja2FnZUpzb24ucGVlckRlcGVuZGVuY2llc1tuYW1lXTtcbiAgICAgIGlmICh2ZXJzaW9uID09IG51bGwpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICByZXN1bHQucHVzaChgJHtuYW1lfUAke3ZlcnNpb259YCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBPYnRhaW5zIHRoZSBwYXRoIHRvIHRoZSBucG0gY29tbWFuZCB0aGF0IHNob3VsZCBiZSBydW4uIFRoaXMgYWx3YXlzIHJldHVybnNcbiAgICogdGhlIHBhdGggdG8gYW4gbnBtID49IDcsIHdoaWNoIFwiY29ycmVjdGx5XCIgaGFuZGxlcyBwZWVyRGVwZW5kZW5jaWVzLiBJZiB0aGVcbiAgICogbnBtIHZlcnNpb24gdGhhdCdzIGF2YWlsYWJsZSBpbiAkUEFUSCBzYXRpc2ZpZXMgdGhpcyBwcmVkaWNhdGUsIHRoaXMgd2lsbFxuICAgKiBzaW1wbHkgcmV0dXJuIGBucG1gLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBucG1Db21tYW5kUGF0aCgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGlmICh0aGlzLiNucG1Db21tYW5kKSB7XG4gICAgICByZXR1cm4gdGhpcy4jbnBtQ29tbWFuZDtcbiAgICB9XG5cbiAgICAvLyBHZXQgdGhlIHBsYXRmb3JtIHNwZWNpZmljIG5wbSBjb21tYW5kXG4gICAgY29uc3QgbnBtID0gbnBtUGxhdGZvcm1Bd2FyZUNvbW1hbmQoKTtcblxuICAgIHRyeSB7XG4gICAgICAvLyBJZiB0aGUgbnBtIGluICRQQVRIIGlzID49IHY3LCB3ZSBjYW4gdXNlIHRoYXQgZGlyZWN0bHkuIFRoZVxuICAgICAgLy8gYG5wbSB2ZXJzaW9uIC0tanNvbmAgY29tbWFuZCByZXR1cm5zIGEgSlNPTiBvYmplY3QgY29udGFpbmluZyB0aGVcbiAgICAgIC8vIHZlcnNpb25zIG9mIHNldmVyYWwgY29tcG9uZW50cyAobnBtLCBub2RlLCB2OCwgZXRjLi4uKS4gV2UgYXJlIG9ubHlcbiAgICAgIC8vIGludGVyZXN0ZWQgaW4gdGhlIGBucG1gIGtleSBoZXJlLlxuICAgICAgY29uc3QgeyBleGl0Q29kZSwgc3Rkb3V0IH0gPSBhd2FpdCB0aGlzLnJ1bkNvbW1hbmQoXG4gICAgICAgIG5wbSwgWyd2ZXJzaW9uJywgJy0tanNvbiddLFxuICAgICAgICBjaHVua3NUb09iamVjdCxcbiAgICAgICk7XG4gICAgICBpZiAoZXhpdENvZGUgPT09IDAgJiYgbWFqb3IoKHN0ZG91dCBhcyBhbnkpLm5wbSkgPj0gNykge1xuICAgICAgICByZXR1cm4gdGhpcy4jbnBtQ29tbWFuZCA9IG5wbTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aGlzLmxvZ2dlcignQ291bGQgbm90IGRldGVybWluZSB2ZXJzaW9uIG9mIG5wbSBpbiAkUEFUSDonLCBlKTtcbiAgICB9XG5cbiAgICAvLyBucG1AOCBpcyBuZWVkZWQgc28gdGhhdCB3ZSBhbHNvIGluc3RhbGwgcGVlckRlcGVuZGVuY2llcyAtIHRoZXkgYXJlIG5lZWRlZCB0byBjb25zdHJ1Y3RcbiAgICAvLyB0aGUgZnVsbCB0eXBlIHN5c3RlbS5cbiAgICB0aGlzLmxvZ2dlcignVGhlIG5wbSBpbiAkUEFUSCBpcyBub3QgPj0gdjcuIEluc3RhbGxpbmcgbnBtQDggbG9jYWxseS4uLicpO1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMucnVuQ29tbWFuZChcbiAgICAgIG5wbSxcbiAgICAgIFsnaW5zdGFsbCcsICducG1AOCcsICctLW5vLXBhY2thZ2UtbG9jaycsICctLW5vLXNhdmUnLCAnLS1qc29uJ10sXG4gICAgICBjaHVua3NUb09iamVjdCxcbiAgICAgIHtcbiAgICAgICAgY3dkOiB0aGlzLndvcmtpbmdEaXJlY3RvcnksXG4gICAgICAgIHNoZWxsOiB0cnVlLFxuICAgICAgfSxcbiAgICApO1xuICAgIGFzc2VydFN1Y2Nlc3MocmVzdWx0KTtcblxuICAgIHRoaXMuI25wbUNvbW1hbmQgPSBqb2luKHRoaXMud29ya2luZ0RpcmVjdG9yeSwgJ25vZGVfbW9kdWxlcycsICcuYmluJywgbnBtKTtcbiAgICB0aGlzLmxvZ2dlcihgRG9uZSBpbnN0YWxsaW5nIG5wbUA4IGF0ICR7dGhpcy4jbnBtQ29tbWFuZH1gKTtcbiAgICByZXR1cm4gdGhpcy4jbnBtQ29tbWFuZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHRoZSBzdXBwbGllZCBjb21tYW5kIHdpdGggdGhlIHByb3ZpZGVkIGFyZ3VtZW50cywgY2FwdHVyZXMgdGhlIGRhdGFcbiAgICogcHVzaGVkIHRvIFNURE9VVCwgYW5kIFwicGFyc2VzXCIgaXQgdXNpbmcgYG91dHB1dFRyYW5zZm9ybWAgdG8gcHJvZHVjZSBhXG4gICAqIHJlc3VsdC5cbiAgICpcbiAgICogWW91IG11c3QgY29uc3VsdCB0aGUgYGV4aXRDb2RlYCBvZiB0aGUgcmV0dXJuIHZhbHVlIHRvIGRldGVybWluZSB3aGV0aGVyXG4gICAqIHRoZSBjb21tYW5kIHdhcyBzdWNjZXNzZnVsIG9yIG5vdC4gVXNlIHRoZSBgYXNzZXJ0U3VjY2Vzc2AgZnVuY3Rpb24gdG9cbiAgICogdGhyb3cvcmVqZWN0IGluIGNhc2UgdGhlIGV4ZWN1dGlvbiB3YXMgbm90IHN1Y2Nlc3NmdWwuXG4gICAqXG4gICAqIFRoZSBhcmd1bWVudHMgYXJlIGVzY2FwZWQsIGFuZCB3aWxsIG5vdCBiZSBpbnRlcnByZXRlZCBieSB0aGUgc2hlbGwuXG4gICAqXG4gICAqIEBwYXJhbSBjb21tYW5kICAgICAgICAgdGhlIGNvbW1hbmQgdG8gaW52b2tlLlxuICAgKiBAcGFyYW0gYXJncyAgICAgICAgICAgIGFyZ3VtZW50cyB0byBwcm92aWRlIHRvIHRoZSBjb21tYW5kLlxuICAgKiBAcGFyYW0gb3V0cHV0VHJhbnNmb3JtIHRoZSBmdW5jdGlvbiB0aGF0IHdpbGwgcGFyc2UgU1RET1VUIGRhdGEuXG4gICAqIEBwYXJhbSBvcHRpb25zICAgICAgICAgYWRkaXRpb25hbCBgc3Bhd25gIG9wdGlvbnMsIGlmIG5lY2Vzc2FyeS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcnVuQ29tbWFuZDxUID0gQnVmZmVyPihcbiAgICBjb21tYW5kOiBzdHJpbmcsXG4gICAgYXJnczogcmVhZG9ubHkgc3RyaW5nW10sXG4gICAgb3V0cHV0VHJhbnNmb3JtOiAoc3RkZXJyOiByZWFkb25seSBCdWZmZXJbXSkgPT4gVCxcbiAgICBvcHRpb25zPzogU3Bhd25PcHRpb25zV2l0aG91dFN0ZGlvLFxuICApOiBQcm9taXNlPENvbW1hbmRSZXN1bHQ8VD4+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2U8Q29tbWFuZFJlc3VsdDxUPj4oKG9rLCBrbykgPT4ge1xuICAgICAgLy8gT24gV2luZG93cywgc3Bhd25pbmcgYSBwcm9ncmFtIGVuZGluZyBpbiAuY21kIG9yIC5iYXQgbmVlZHMgdG8gcnVuIGluIGEgc2hlbGwuXG4gICAgICAvLyAoRXZlbiBpZiB0aGUgcHJvZ3JhbSBpcyBhIC5jbWQvLmJhdCBmaWxlIHRoYXQgZ2V0cyByZXNvbHZlZCBpbXBsaWNpdGx5LCBpdCBzdGlsbCBuZWVkcyB0aGF0IHNoZWxsLFxuICAgICAgLy8gYnV0IHRoZW4gaXQncyB0aGUgY2FsbGVyJ3MgcmVzcG9uc2liaWxpdHkgdG8gcGFzcyB7IHNoZWxsOiB0cnVlIH0pLlxuICAgICAgLy8gaHR0cHM6Ly9ub2RlanMub3JnL2VuL2Jsb2cvdnVsbmVyYWJpbGl0eS9hcHJpbC0yMDI0LXNlY3VyaXR5LXJlbGVhc2VzLTJcbiAgICAgIC8vXG4gICAgICAvLyBJZiB3ZSBhcmUgZ29pbmcgdGhyb3VnaCB0aGUgc2hlbGwsIGVzY2FwZSB0aGUgYXJndW1lbnRzLlxuICAgICAgY29uc3Qgc2hlbGwgPSBvcHRpb25zPy5zaGVsbCB8fCAob25XaW5kb3dzKCkgJiYgKGNvbW1hbmQuZW5kc1dpdGgoJy5jbWQnKSB8fCBjb21tYW5kLmVuZHNXaXRoKCcuYmF0JykpKTtcbiAgICAgIGNvbnN0IHNhZmVBcmdzID0gc2hlbGwgPyBhcmdzLm1hcChlc2NhcGVGb3JTaGVsbCkgOiBhcmdzO1xuICAgICAgY29uc3QgY2hpbGQgPSBzcGF3bihjb21tYW5kLCBzYWZlQXJncywgeyAuLi5vcHRpb25zLCBzaGVsbCwgc3RkaW86IFsnaW5oZXJpdCcsICdwaXBlJywgJ3BpcGUnXSB9KTtcbiAgICAgIGNvbnN0IHN0ZG91dCA9IG5ldyBBcnJheTxCdWZmZXI+KCk7XG4gICAgICBjaGlsZC5zdGRvdXQub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcbiAgICAgICAgc3Rkb3V0LnB1c2goQnVmZmVyLmZyb20oY2h1bmspKTtcbiAgICAgIH0pO1xuICAgICAgY2hpbGQuc3RkZXJyLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XG4gICAgICAgIHN0ZG91dC5wdXNoKEJ1ZmZlci5mcm9tKGNodW5rKSk7XG4gICAgICB9KTtcblxuICAgICAgY2hpbGQub25jZSgnZXJyb3InLCBrbyk7XG4gICAgICBjaGlsZC5vbmNlKCdjbG9zZScsIChleGl0Q29kZSwgc2lnbmFsKSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgb2soe1xuICAgICAgICAgICAgY29tbWFuZDogYCR7Y29tbWFuZH0gJHtzYWZlQXJncy5qb2luKCcgJyl9YCxcbiAgICAgICAgICAgIGV4aXRDb2RlLFxuICAgICAgICAgICAgc2lnbmFsLFxuICAgICAgICAgICAgc3Rkb3V0OiBvdXRwdXRUcmFuc2Zvcm0oc3Rkb3V0KSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBrbyhlcnJvcik7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG59XG5cbmZ1bmN0aW9uIGVzY2FwZUZvclNoZWxsKGFyZzogc3RyaW5nKTogc3RyaW5nIHtcbiAgaWYgKGFyZy5tYXRjaCgvXlthLXowLTlfXFwvLj0tXSskL2kpKSB7XG4gICAgLy8gSWYgdGhlIGFyZ3VtZW50IGNvbnRhaW5zIG9ubHkgc2FmZSBjaGFyYWN0ZXJzLCB3ZSBjYW4gcmV0dXJuIGl0IGFzIGlzLCB0byBrZWVwIHRoZSBjb21tYW5kIGxpbmUgcmVhZGFibGUuXG4gICAgcmV0dXJuIGFyZztcbiAgfVxuXG4gIGlmIChvbldpbmRvd3MoKSkge1xuICAgIC8vIE9uIFdpbmRvd3MsIHdlIG5lZWQgdG8gd3JhcCB0aGUgYXJndW1lbnQgaW4gZG91YmxlIHF1b3RlcyBhbmQgZXNjYXBlIGFueSBleGlzdGluZyBkb3VibGUgcXVvdGVzIGJ5IGRvdWJsaW5nIHRoZW0uXG4gICAgcmV0dXJuIGBcIiR7YXJnLnJlcGxhY2UoL1wiL2csICdcIlwiJyl9XCJgO1xuICB9IGVsc2Uge1xuICAgIC8vIE9uIFVuaXgtbGlrZSBzeXN0ZW1zLCB3ZSBjYW4gd3JhcCB0aGUgYXJndW1lbnQgaW4gc2luZ2xlIHF1b3RlcyBhbmQgZXNjYXBlIGFueSBleGlzdGluZyBzaW5nbGUgcXVvdGVzIGJ5IGNsb3NpbmcgdGhlIHF1b3RlLCBhZGRpbmcgYW4gZXNjYXBlZCBzaW5nbGUgcXVvdGUsIGFuZCByZW9wZW5pbmcgdGhlIHF1b3RlLlxuICAgIHJldHVybiBgJyR7YXJnLnJlcGxhY2UoLycvZywgJ1xcJ1xcXFxcXCdcXCcnKX0nYDtcbiAgfVxufVxuXG4vKipcbiAqIEEgZmlsdGVyIHRvIGFwcGx5IHdoZW4gc2VsZWN0aW5nIG9wdGlvbmFsIHBlZXIgZGVwZW5kZW5jaWVzLCBiYXNlZCBvbiBob3dcbiAqIHRoZWlyIHZlcnNpb24gdGFyZ2V0IGlzIHNwZWNpZmllZC5cbiAqL1xuZXhwb3J0IGVudW0gT3B0aW9uYWxQZWVyRGVwc0ZpbHRlciB7XG4gIC8qKlxuICAgKiBJZ25vcmUgYWxsIG9wdGlvbmFsIHBlZXIgZGVwZW5kZW5jaWVzIHdoZW4gaW5zdGFsbGluZy5cbiAgICovXG4gIE5vbmUsXG5cbiAgLyoqXG4gICAqIEluc3RhbGwgb25seSBvcHRpb25hbCBwZWVyIGRlcGVuZGVuY2llcyBzcGVjaWZpZWQgYXMgYSB2ZXJzaW9uIHJhbmdlLCBhbmRcbiAgICogaWdub3JlIHRob3NlIHNwZWNpZmllZCBhcyBhIFVSTCBvciBsb2NhbCBwYXRoLlxuICAgKi9cbiAgVmVyc2lvblJhbmdlLFxuXG4gIC8qKlxuICAgKiBJbnN0YWxsIGFsbCBvcHRpb25hbCBwZWVyIGRlcGVuZGVuY2llcyByZWdhcmRsZXNzIG9mIGhvdyB0aGV5IGFyZVxuICAgKiBzcGVjaWZpZWQuIFRoaXMgcmVxdWlyZXMgVVJMIGFuZCBsb2NhbC1wYXRoIGRlcGVuZGVuY2llcyB0byBiZSByZWFjaGFibGUuXG4gICAqL1xuICBBbGwsXG59XG5cbmludGVyZmFjZSBDb21tYW5kUmVzdWx0PFQ+IHtcbiAgcmVhZG9ubHkgY29tbWFuZDogc3RyaW5nO1xuICByZWFkb25seSBleGl0Q29kZTogbnVtYmVyIHwgbnVsbDtcbiAgcmVhZG9ubHkgc2lnbmFsOiBOb2RlSlMuU2lnbmFscyB8IG51bGw7XG4gIHJlYWRvbmx5IHN0ZG91dDogVDtcbn1cbmludGVyZmFjZSBTdWNjZXNzZnVsQ29tbWFuZFJlc3VsdDxUPiBleHRlbmRzIENvbW1hbmRSZXN1bHQ8VD4ge1xuICByZWFkb25seSBleGl0Q29kZTogMDtcbiAgcmVhZG9ubHkgc2lnbmFsOiBudWxsO1xufVxuXG4vKipcbiAqIEFzc2VydHMgdGhlIHByb3ZpZGVkIENvbW1hbmRSZXN1bHQgY29ycmVzcG9uZHMgdG8gYSBjb21tYW5kIHRoYXQgZXhpdGVkIHdpdGhcbiAqIGNvZGUgYDBgLiBJZiB0aGF0IGlzIG5vdCB0aGUgY2FzZSwgdGhpcyB3aWxsIHRocm93IGFuIGFwcHJvcHJpYXRlIGVycm9yLFxuICogZWl0aGVyIGBOcG1FcnJvcmAgb3IgYE5vU3BhY2VMZWZ0T25EZXZpY2VgLlxuICovXG5mdW5jdGlvbiBhc3NlcnRTdWNjZXNzKHJlc3VsdDogQ29tbWFuZFJlc3VsdDxSZXNwb25zZU9iamVjdD4pOiBhc3NlcnRzIHJlc3VsdCBpcyBTdWNjZXNzZnVsQ29tbWFuZFJlc3VsdDxSZXNwb25zZU9iamVjdD4ge1xuICBjb25zdCB7IGNvbW1hbmQsIGV4aXRDb2RlLCBzaWduYWwsIHN0ZG91dCB9ID0gcmVzdWx0O1xuICBpZiAoZXhpdENvZGUgPT09IDApIHtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKHNpZ25hbCAhPSBudWxsKSB7XG4gICAgdGhyb3cgbmV3IE5wbUVycm9yKGBDb21tYW5kIFwiJHtjb21tYW5kfVwiIHdhcyBraWxsZWQgYnkgJHtzaWduYWx9YCwgc3Rkb3V0KTtcbiAgfVxuICBpZiAoZXhpdENvZGUgPT09IDIyOCB8fCBzdGRvdXQuZXJyb3I/LmNvZGUgPT09ICdFTk9TUEMnKSB7XG4gICAgdGhyb3cgbmV3IE5vU3BhY2VMZWZ0T25EZXZpY2UoYENvbW1hbmQgXCIke2NvbW1hbmR9XCIgZmFpbGVkIGR1ZSB0byBpbnN1ZmZpY2llbnQgYXZhaWxhYmxlIGRpc2sgc3BhY2VgKTtcbiAgfVxuICBjb25zdCB7IGNvZGUsIGRldGFpbCwgc3VtbWFyeSB9ID0gc3Rkb3V0LmVycm9yO1xuICBjb25zdCBtZXNzYWdlID0gW1xuICAgIGBDb21tYW5kIFwiJHtjb21tYW5kfVwiIGV4aXRlZCB3aXRoIGNvZGUgJHtleGl0Q29kZX1gLFxuICAgIHN1bW1hcnkgPyBgOiAke3N1bW1hcnl9YCA6ICcnLFxuICAgIGRldGFpbCA/IGBcXG4ke2RldGFpbH1gIDogJycsXG4gICAgLy8gSWYgd2UgaGF2ZSBhbiBlcnJvciwgYnV0IG5laXRoZXIgZGV0YWlsIG5vciBzdW1tYXJ5LCB0aGVuIHdlIHByb2JhYmx5XG4gICAgLy8gaGF2ZSBhbiBhY3R1YWwgRXJyb3Igb2JqZWN0LCBzbyB3ZSdsbCBzdHJpbmdpZnkgdGhhdCBoZXJlLi4uXG4gICAgc3Rkb3V0LmVycm9yICYmICFkZXRhaWwgJiYgIXN1bW1hcnkgPyBgOiAke3N0ZG91dC5lcnJvcn1gIDogJycsXG4gIF0uam9pbignJyk7XG5cbiAgaWYgKHR5cGVvZiBzdW1tYXJ5ID09PSAnc3RyaW5nJyAmJiBzdW1tYXJ5LmluY2x1ZGVzKCdtdXN0IHByb3ZpZGUgc3RyaW5nIHNwZWMnKSkge1xuICAgIC8vIGhhcHBlbnMgd2hlbiBwYWNrYWdlLmpzb24gZGVwZW5kZW5jaWVzIGRvbid0IGhhdmUgYSBzcGVjLlxuICAgIC8vIGZvciBleGFtcGxlOiBodHRwczovL2dpdGh1Yi5jb20vbWFya3VzbC9jZGstY29kZXBpcGVsaW5lLWJpdGJ1Y2tldC1idWlsZC1yZXN1bHQtcmVwb3J0ZXIvYmxvYi92MC4wLjcvcGFja2FnZS5qc29uXG4gICAgdGhyb3cgbmV3IFVuSW5zdGFsbGFibGVQYWNrYWdlRXJyb3Ioc3VtbWFyeSk7XG4gIH1cblxuICAvLyBoYXBwZW5zIHdoZW4gYSBwYWNrYWdlIGhhcyBiZWVuIGRlbGV0ZWQgZnJvbSBucG1cbiAgLy8gZm9yIGV4YW1wbGU6IHNucy1hcHAtanNpaS1jb21wb25lbnRcbiAgaWYgKCFjb2RlICYmICFkZXRhaWwgJiYgdHlwZW9mIHN1bW1hcnkgPT09ICdzdHJpbmcnICYmIHN1bW1hcnkuaW5jbHVkZXMoJ0Nhbm5vdCBjb252ZXJ0IHVuZGVmaW5lZCBvciBudWxsIHRvIG9iamVjdCcpKSB7XG4gICAgdGhyb3cgbmV3IFVuSW5zdGFsbGFibGVQYWNrYWdlRXJyb3Ioc3VtbWFyeSk7XG4gIH1cblxuICBpZiAoVU5JU1RBTExBQkxFX1BBQ0tBR0VfRVJST1JfQ09ERVMuaW5jbHVkZXMoY29kZSkpIHtcbiAgICB0aHJvdyBuZXcgVW5JbnN0YWxsYWJsZVBhY2thZ2VFcnJvcihtZXNzYWdlKTtcbiAgfVxuXG4gIHRocm93IG5ldyBOcG1FcnJvcihtZXNzYWdlLCBzdGRvdXQsIGNvZGUpO1xufVxuXG4vKipcbiAqIENvbmNhdGVuYXRlcyB0aGUgcHJvdmlkZWQgY2h1bmtzIGludG8gYSBzaW5nbGUgQnVmZmVyLCBjb252ZXJ0cyBpdCB0byBhXG4gKiBzdHJpbmcgdXNpbmcgdGhlIGRlc2lnbmF0ZWQgZW5jb2RpbmcsIHRoZW4gSlNPTi1wYXJzZXMgaXQuIElmIGFueSBwYXJ0IG9mXG4gKiB0aGlzIHByb2Nlc3MgcmVzdWx0cyBpbiBhbiBlcnJvciwgcmV0dXJucyBhbiBvYmplY3QgdGhhdCBjb250YWlucyB0aGUgZXJyb3JcbiAqIGFuZCB0aGUgcmF3IGNodW5rcy5cbiAqL1xuZnVuY3Rpb24gY2h1bmtzVG9PYmplY3QoY2h1bmtzOiByZWFkb25seSBCdWZmZXJbXSwgZW5jb2Rpbmc6IEJ1ZmZlckVuY29kaW5nID0gJ3V0Zi04Jyk6IFJlc3BvbnNlT2JqZWN0IHtcbiAgY29uc3QgcmF3ID0gQnVmZmVyLmNvbmNhdChjaHVua3MpLnRvU3RyaW5nKGVuY29kaW5nKTtcbiAgdHJ5IHtcbiAgICAvLyBucG0gd2lsbCBzb21ldGltZXMgcHJpbnQgbm9uIGpzb24gbG9nIGxpbmVzIGV2ZW4gdGhvdWdoIC0tanNvbiB3YXMgcmVxdWVzdGVkLlxuICAgIC8vIG9ic2VydmVkIHRoZXNlIGxvZyBsaW5lcyBhbHdheXMgc3RhcnQgd2l0aCAnbnBtJywgc28gd2UgZmlsdGVyIHRob3NlIG91dC5cbiAgICAvLyBmb3IgZXhhbXBsZTogXCJucG0gbm90aWNlIE5ldyBwYXRjaCB2ZXJzaW9uIG9mIG5wbSBhdmFpbGFibGUhIDguMS4wIC0+IDguMS4zXCJcbiAgICAvLyBmb3IgZXhhbXBsZTogXCJucG0gRVJSISBtdXN0IHByb3ZpZGUgc3RyaW5nIHNwZWNcIlxuICAgIGNvbnN0IG9ubHlKc29uID0gcmF3LnNwbGl0KC9bXFxyXFxuXSsvKSAvLyBzcGxpdCBvbiBhbnkgbmV3bGluZXMsIGJlY2F1c2UgbnBtIHJldHVybnMgaW5jb25zaXN0ZW50IG5ld2xpbmUgY2hhcmFjdGVycyBvbiBXaW5kb3dzXG4gICAgICAuZmlsdGVyKGwgPT4gIWwuc3RhcnRzV2l0aCgnbnBtJykpXG4gICAgICAvLyBTdXBwcmVzcyBkZWJ1Z2dlciBtZXNzYWdlcywgaWYgcHJlc2VudC4uLlxuICAgICAgLmZpbHRlcihsID0+IGwgIT09ICdEZWJ1Z2dlciBhdHRhY2hlZC4nKVxuICAgICAgLmZpbHRlcihsID0+IGwgIT09ICdXYWl0aW5nIGZvciB0aGUgZGVidWdnZXIgdG8gZGlzY29ubmVjdC4uLicpXG4gICAgICAvLyBSZS1qb2luLi4uXG4gICAgICAuam9pbihvcy5FT0wpO1xuICAgIHJldHVybiBKU09OLnBhcnNlKG9ubHlKc29uKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4geyBlcnJvciwgcmF3IH07XG4gIH1cbn1cblxudHlwZSBSZXNwb25zZU9iamVjdCA9XG4gIC8vIFRoZSBlcnJvciB3aGVuIHdlIGZhaWxlZCB0byBwYXJzZSB0aGUgb3V0cHV0IGFzIEpTT05cbiAgfCB7IHJlYWRvbmx5IGVycm9yOiBhbnk7IHJlYWRvbmx5IHJhdzogc3RyaW5nIH1cbiAgLy8gVGhlIGVycm9yIG9iamVjdHMgbnBtIHJldHVybnMgd2hlbiBvcGVyYXRpbmcgaW4gLS1qc29uIG1vZGVcbiAgfCB7IHJlYWRvbmx5IGVycm9yOiB7IHJlYWRvbmx5IGNvZGU6IHN0cmluZzsgcmVhZG9ubHkgc3VtbWFyeTogc3RyaW5nOyByZWFkb25seSBkZXRhaWw6IHN0cmluZyB9IH1cbiAgLy8gVGhlIHN1Y2Nlc3NmdWwgb2JqZWN0cyBhcmUgdHJlYXRlZCBhcyBvcGFxdWUgYmxvYnMgaGVyZVxuICB8IHsgcmVhZG9ubHkgZXJyb3I6IHVuZGVmaW5lZDsgcmVhZG9ubHkgW2tleTogc3RyaW5nXTogdW5rbm93biB9O1xuXG4vKipcbiAqIEhlbHBlciB0byBkZXRlY3QgaWYgd2UgYXJlIHJ1bm5pbmcgb24gV2luZG93cy5cbiAqL1xuZnVuY3Rpb24gb25XaW5kb3dzKCkge1xuICByZXR1cm4gcHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ3dpbjMyJztcbn1cblxuLyoqXG4gKiBHZXQgdGhlIG5wbSBiaW5hcnkgcGF0aCBkZXBlbmRpbmcgb24gdGhlIHBsYXRmb3JtLlxuICogQHJldHVybnMgXCJucG0uY21kXCIgb24gV2luZG93cywgb3RoZXJ3aXNlIFwibnBtXCJcbiAqL1xuZnVuY3Rpb24gbnBtUGxhdGZvcm1Bd2FyZUNvbW1hbmQoKSB7XG4gIGlmIChvbldpbmRvd3MoKSkge1xuICAgIHJldHVybiAnbnBtLmNtZCc7XG4gIH1cblxuICByZXR1cm4gJ25wbSc7XG59XG4iXX0=