@axway/axway-cli-pm
Version:
Package manager for Axway products
506 lines (414 loc) • 48.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.find = find;
exports.install = install;
exports.list = list;
exports.listPurgable = listPurgable;
exports.packagesDir = void 0;
exports.search = search;
exports.uninstallPackage = uninstallPackage;
exports.view = view;
var _fsExtra = _interopRequireDefault(require("fs-extra"));
var _npmPackageArg = _interopRequireDefault(require("npm-package-arg"));
var _libnpmsearch = _interopRequireDefault(require("libnpmsearch"));
var _pacote = _interopRequireDefault(require("pacote"));
var _path = _interopRequireDefault(require("path"));
var _promiseLimit = _interopRequireDefault(require("promise-limit"));
var _semver = _interopRequireDefault(require("semver"));
var _snooplogg = _interopRequireDefault(require("snooplogg"));
var _crossSpawn = _interopRequireDefault(require("cross-spawn"));
var _which = _interopRequireDefault(require("which"));
var _amplifyCliUtils = require("@axway/amplify-cli-utils");
var _events = require("events");
var _amplifyUtils = require("@axway/amplify-utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const scopedPackageRegex = /^@[a-z0-9][\w-.]+\/?/;
const {
error,
log
} = (0, _snooplogg.default)('pm');
const {
alert,
highlight
} = _snooplogg.default.styles;
/**
* The path to the Axway CLI packages directory.
* @type {String}
*/
const packagesDir = _path.default.join(_amplifyCliUtils.locations.axwayHome, 'axway-cli', 'packages');
/**
* Finds a specific installed package.
*
* @param {String} packageName - The name of the package to find.
* @returns {Object}
*/
exports.packagesDir = packagesDir;
async function find(packageName) {
if (!packageName || typeof packageName !== 'string') {
throw new TypeError('Expected package name to be a non-empty string');
}
if (!(0, _amplifyUtils.isDir)(packagesDir)) {
return undefined;
}
const config = await (0, _amplifyCliUtils.loadConfig)();
const extensions = await config.get('extensions', {});
packageName = packageName.toLowerCase();
for (const name of _fsExtra.default.readdirSync(packagesDir)) {
const pkgDir = _path.default.join(packagesDir, name);
if (!(0, _amplifyUtils.isDir)(pkgDir)) {
continue;
}
if (scopedPackageRegex.test(name)) {
for (const pkgSubDir of _fsExtra.default.readdirSync(pkgDir)) {
const dir = _path.default.join(pkgDir, pkgSubDir);
const pkgName = `${name}/${pkgSubDir}`;
if ((0, _amplifyUtils.isDir)(dir) && pkgName.toLowerCase() === packageName) {
const packageData = loadPackageData(pkgName, extensions, dir);
if (packageData.version || Object.keys(packageData.versions).length) {
return packageData;
}
}
}
} else if (name.toLowerCase() === packageName) {
const packageData = loadPackageData(name, extensions, pkgDir);
if (packageData.version || Object.keys(packageData.versions).length) {
return packageData;
}
}
}
}
/**
* Installs a package from npm.
*
* @param {String} pkgName - The package and version to install.
* @returns {EventEmitter}
*/
function install(pkgName) {
const emitter = new _events.EventEmitter();
setImmediate(async () => {
let cfg = await (0, _amplifyCliUtils.loadConfig)();
let previousActivePackage;
let info;
try {
info = await view(pkgName);
let npm;
try {
npm = await (0, _which.default)('npm');
} catch (e) {
const err = new Error('Unable to find the "npm" executable. Please ensure you have "npm" installed on your machine');
err.code = 'ENONPM';
throw err;
}
previousActivePackage = await cfg.get(`extensions.${info.name}`);
info.path = _path.default.join(packagesDir, info.name, info.version);
(0, _amplifyUtils.mkdirpSync)(info.path);
emitter.emit('download', info);
await _pacote.default.extract(`${info.name}@${info.version}`, info.path, (0, _amplifyCliUtils.createRequestOptions)());
emitter.emit('install', info);
const args = ['install', '--production', '--force', // needed for npm 7
...(0, _amplifyCliUtils.createNPMRequestArgs)()];
const opts = {
cwd: info.path,
env: Object.assign({
NO_UPDATE_NOTIFIER: 1
}, process.env),
gid: process.env.SUDO_GID ? parseInt(process.env.SUDO_GID) : undefined,
uid: process.env.SUDO_UID ? parseInt(process.env.SUDO_UID) : undefined,
windowsHide: true
};
log(`node ${highlight(process.version)} npm ${highlight(_crossSpawn.default.sync('npm', ['-v'], opts).stdout.toString().trim())}`);
log(`Running PWD=${info.path} ${highlight(`${npm} ${args.join(' ')}`)}`);
await new Promise((resolve, reject) => {
let stderr = '';
const child = (0, _crossSpawn.default)(npm, args, opts);
child.stdout.on('data', data => log(data.toString().trim()));
child.stderr.on('data', data => {
const s = data.toString();
stderr += s;
log(s.trim());
});
child.on('close', status => {
if (status) {
reject(new Error(`${stderr ? String(stderr.split(/\r\n|\n/)[0]).replace(/^\s*error:\s*/i, '') : 'unknown error'} (code ${status})`));
} else {
resolve();
}
});
});
emitter.emit('register', info);
cfg = await (0, _amplifyCliUtils.loadConfig)();
await cfg.set(`extensions.${info.name}`, info.path);
await cfg.save();
emitter.emit('end', info);
} catch (err) {
if (info) {
if (previousActivePackage === info.path) {
// package was reinstalled, but failed and directory is in an unknown state
cfg = await (0, _amplifyCliUtils.loadConfig)();
await cfg.delete(`extensions.${info.name}`);
await cfg.save();
} else if (previousActivePackage) {
// restore the previous value
cfg = await (0, _amplifyCliUtils.loadConfig)();
await cfg.set(`extensions.${info.name}`, previousActivePackage);
await cfg.save();
}
if (info.path) {
await _fsExtra.default.remove(info.path);
}
}
emitter.emit('error', err);
}
});
return emitter;
}
/**
* Detects all installed packages.
*
* @returns {Promise<Array.<Object>>}
*/
async function list() {
if (!(0, _amplifyUtils.isDir)(packagesDir)) {
return [];
}
const config = await (0, _amplifyCliUtils.loadConfig)();
const extensions = await config.get('extensions', {});
const packages = [];
for (const name of _fsExtra.default.readdirSync(packagesDir)) {
const pkgDir = _path.default.join(packagesDir, name);
if (!(0, _amplifyUtils.isDir)(pkgDir)) {
continue;
}
if (scopedPackageRegex.test(name)) {
for (const pkgSubDir of _fsExtra.default.readdirSync(pkgDir)) {
const dir = _path.default.join(pkgDir, pkgSubDir);
const pkgName = `${name}/${pkgSubDir}`;
if ((0, _amplifyUtils.isDir)(dir)) {
const packageData = loadPackageData(pkgName, extensions, dir);
if (packageData.version || Object.keys(packageData.versions).length) {
packages.push(packageData);
}
}
}
} else {
const packageData = loadPackageData(name, extensions, pkgDir);
if (packageData.version || Object.keys(packageData.versions).length) {
packages.push(packageData);
}
}
}
return packages;
}
/**
* Determines if there are any older versions of packages installed that could be purged.
*
* @param {String} [pkgName] - A specific package to check if purgable, otherwise checks all
* packages.
* @returns {Object}
*/
async function listPurgable(pkgName) {
let packages = [];
if (pkgName) {
const pkg = await find(pkgName);
if (!pkg) {
throw new Error(`Package "${pkgName}" is not installed`);
}
packages.push(pkg);
} else {
packages = await list();
}
const purgable = {};
for (const {
name,
version,
versions
} of packages) {
for (const [ver, versionData] of Object.entries(versions)) {
// if managed and not in use
if (versionData.managed && versionData.path.startsWith(packagesDir) && _semver.default.neq(ver, version)) {
if (!purgable[name]) {
purgable[name] = [];
}
purgable[name].push({ ...versionData,
version: ver
});
}
}
}
return purgable;
}
/**
* Scans a package directory for all installed versions.
*
* @param {String} name - The package name.
* @param {Object} extensions - An object of registered extension names and their paths.
* @param {String} pkgDir - The path to the package.
* @returns {Object}
*/
function loadPackageData(name, extensions, pkgDir) {
const packageData = {
name,
description: undefined,
version: undefined,
versions: {}
}; // find all versions
for (const version of _fsExtra.default.readdirSync(pkgDir)) {
try {
const versionDir = _path.default.join(pkgDir, version);
const pkgJson = _fsExtra.default.readJsonSync(_path.default.join(versionDir, 'package.json'));
packageData.description = pkgJson.description;
packageData.versions[version] = {
path: versionDir,
managed: true
};
} catch (e) {// squelch
}
} // see if this package is an extension and if it's the currently selected version
let extPath = extensions[name];
if (!extPath) {
name = name.replace(scopedPackageRegex, '');
extPath = extensions[name];
}
if (extPath) {
const pkgJsonFile = _path.default.join(extPath, 'package.json');
if ((0, _amplifyUtils.isFile)(pkgJsonFile)) {
const {
version
} = _fsExtra.default.readJsonSync(pkgJsonFile);
packageData.version = version;
if (!packageData.versions[version]) {
packageData.versions[version] = {
path: extPath,
managed: false
};
}
}
}
return packageData;
}
/**
* Uninstalls a package.
*
* @param {String} dir - Path to the package to delete.
* @returns {Promise}
*/
async function uninstallPackage(dir) {
try {
const pkgJson = await _fsExtra.default.readJson(_path.default.join(dir, 'package.json'));
if (pkgJson.scripts.uninstall) {
log(`Running npm uninstall script: ${highlight(pkgJson.scripts.uninstall)}`);
const {
status,
stderr
} = _crossSpawn.default.sync('npm', ['run', 'uninstall'], {
cwd: dir
});
if (status) {
error(alert('Failed to run npm uninstall script:'));
error(stderr);
}
}
} catch (e) {// squelch
}
await _fsExtra.default.remove(dir);
}
/**
* Searches npm for Axway CLI packages.
*
* @param {Object} [opts] - Various options.
* @param {String} [opts.keyword] - A keyword to search for.
* @param {Number} [opts.limit=50] - The max number of results to return.
* @param {String} [opts.type] - A package type to filter by.
* @returns {Promse<Array.<Object>>}
*/
async function search({
keyword,
limit,
type
} = {}) {
const plimit = (0, _promiseLimit.default)(10);
const requestOpts = (0, _amplifyCliUtils.createRequestOptions)();
const keywords = ['amplify-package'];
if (process.env.TEST) {
keywords.push('amplify-test-package');
}
if (keyword) {
keywords.push(keyword);
}
const q = 'keywords:' + keywords.join(',');
const packages = await (0, _libnpmsearch.default)(q, { ...requestOpts,
limit: Math.max(limit && parseInt(limit, 10) || 50, 1)
});
const results = [];
await Promise.all(packages.map(({
name,
version
}) => {
return plimit(async () => {
try {
const pkg = await view(`${name}@${version}`, {
requestOpts,
type
});
if (pkg) {
results.push(pkg);
}
} catch (err) {// squelch
}
});
}));
return results.sort((a, b) => a.name.localeCompare(b.name));
}
/**
* Fetches package information directly from npm and checks that it's a valid package.
*
* @param {String} pkgName - The package name.
* @param {Object} [opts] - Various options.
* @param {Object} [opts.requestOpts] - HTTP request options.
* @param {String} [opts.type] - The package type to filter by.
*/
async function view(pkgName, {
requestOpts = (0, _amplifyCliUtils.createRequestOptions)(),
type
} = {}) {
var _info$distTags, _pkg$amplify, _info;
if (!pkgName || typeof pkgName !== 'string') {
throw new TypeError('Expected package name to be a non-empty string');
}
const {
name,
fetchSpec
} = (0, _npmPackageArg.default)(pkgName);
let info;
if (!name) {
throw new Error(`Invalid package name "${pkgName}"`);
}
try {
info = await _pacote.default.packument(name, { ...requestOpts,
fullMetadata: true
});
} catch (err) {
if (err.statusCode === 404) {
throw new Error(`Package "${pkgName}" not found`);
}
throw err;
}
const version = ((_info$distTags = info['dist-tags']) === null || _info$distTags === void 0 ? void 0 : _info$distTags[fetchSpec]) || fetchSpec;
const pkg = info.versions[version];
const maintainers = ['appcelerator', 'axway-npm'];
if (!pkg || !((_pkg$amplify = pkg.amplify) !== null && _pkg$amplify !== void 0 && _pkg$amplify.type) || type && pkg.amplify.type !== type || pkg.keywords.includes('amplify-test-package') && !process.env.TEST || !pkg.keywords.includes('amplify-package') || !((_info = info) !== null && _info !== void 0 && _info.maintainers.some(m => maintainers.includes(m.name)))) {
throw new Error(`Package "${pkgName}" not found`);
}
const installed = await find(pkg.name);
return {
description: pkg.description,
installed: (installed === null || installed === void 0 ? void 0 : installed.versions) || false,
name: pkg.name,
type: pkg.amplify.type,
version,
versions: Object.keys(info.versions)
};
}
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG0uanMiLCJuYW1lcyI6WyJzY29wZWRQYWNrYWdlUmVnZXgiLCJlcnJvciIsImxvZyIsImFsZXJ0IiwiaGlnaGxpZ2h0Iiwic25vb3Bsb2dnIiwic3R5bGVzIiwicGFja2FnZXNEaXIiLCJwYXRoIiwiam9pbiIsImxvY2F0aW9ucyIsImF4d2F5SG9tZSIsImZpbmQiLCJwYWNrYWdlTmFtZSIsIlR5cGVFcnJvciIsInVuZGVmaW5lZCIsImNvbmZpZyIsImV4dGVuc2lvbnMiLCJnZXQiLCJ0b0xvd2VyQ2FzZSIsIm5hbWUiLCJmcyIsInJlYWRkaXJTeW5jIiwicGtnRGlyIiwidGVzdCIsInBrZ1N1YkRpciIsImRpciIsInBrZ05hbWUiLCJwYWNrYWdlRGF0YSIsImxvYWRQYWNrYWdlRGF0YSIsInZlcnNpb24iLCJPYmplY3QiLCJrZXlzIiwidmVyc2lvbnMiLCJsZW5ndGgiLCJpbnN0YWxsIiwiZW1pdHRlciIsIkV2ZW50RW1pdHRlciIsInNldEltbWVkaWF0ZSIsImNmZyIsInByZXZpb3VzQWN0aXZlUGFja2FnZSIsImluZm8iLCJ2aWV3IiwibnBtIiwiZSIsImVyciIsIkVycm9yIiwiY29kZSIsImVtaXQiLCJwYWNvdGUiLCJleHRyYWN0IiwiYXJncyIsIm9wdHMiLCJjd2QiLCJlbnYiLCJhc3NpZ24iLCJOT19VUERBVEVfTk9USUZJRVIiLCJwcm9jZXNzIiwiZ2lkIiwiU1VET19HSUQiLCJwYXJzZUludCIsInVpZCIsIlNVRE9fVUlEIiwid2luZG93c0hpZGUiLCJzcGF3biIsInN5bmMiLCJzdGRvdXQiLCJ0b1N0cmluZyIsInRyaW0iLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsInN0ZGVyciIsImNoaWxkIiwib24iLCJkYXRhIiwicyIsInN0YXR1cyIsIlN0cmluZyIsInNwbGl0IiwicmVwbGFjZSIsInNldCIsInNhdmUiLCJkZWxldGUiLCJyZW1vdmUiLCJsaXN0IiwicGFja2FnZXMiLCJwdXNoIiwibGlzdFB1cmdhYmxlIiwicGtnIiwicHVyZ2FibGUiLCJ2ZXIiLCJ2ZXJzaW9uRGF0YSIsImVudHJpZXMiLCJtYW5hZ2VkIiwic3RhcnRzV2l0aCIsInNlbXZlciIsIm5lcSIsImRlc2NyaXB0aW9uIiwidmVyc2lvbkRpciIsInBrZ0pzb24iLCJyZWFkSnNvblN5bmMiLCJleHRQYXRoIiwicGtnSnNvbkZpbGUiLCJ1bmluc3RhbGxQYWNrYWdlIiwicmVhZEpzb24iLCJzY3JpcHRzIiwidW5pbnN0YWxsIiwic2VhcmNoIiwia2V5d29yZCIsImxpbWl0IiwidHlwZSIsInBsaW1pdCIsInJlcXVlc3RPcHRzIiwia2V5d29yZHMiLCJURVNUIiwicSIsIk1hdGgiLCJtYXgiLCJyZXN1bHRzIiwiYWxsIiwibWFwIiwic29ydCIsImEiLCJiIiwibG9jYWxlQ29tcGFyZSIsImZldGNoU3BlYyIsInBhY2t1bWVudCIsImZ1bGxNZXRhZGF0YSIsInN0YXR1c0NvZGUiLCJtYWludGFpbmVycyIsImFtcGxpZnkiLCJpbmNsdWRlcyIsInNvbWUiLCJtIiwiaW5zdGFsbGVkIl0sInNvdXJjZXMiOlsicG0uanMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGZzIGZyb20gJ2ZzLWV4dHJhJztcbmltcG9ydCBucGEgZnJvbSAnbnBtLXBhY2thZ2UtYXJnJztcbmltcG9ydCBucG1zZWFyY2ggZnJvbSAnbGlibnBtc2VhcmNoJztcbmltcG9ydCBwYWNvdGUgZnJvbSAncGFjb3RlJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHByb21pc2VMaW1pdCBmcm9tICdwcm9taXNlLWxpbWl0JztcbmltcG9ydCBzZW12ZXIgZnJvbSAnc2VtdmVyJztcbmltcG9ydCBzbm9vcGxvZ2cgZnJvbSAnc25vb3Bsb2dnJztcbmltcG9ydCBzcGF3biBmcm9tICdjcm9zcy1zcGF3bic7XG5pbXBvcnQgd2hpY2ggZnJvbSAnd2hpY2gnO1xuaW1wb3J0IHsgY3JlYXRlTlBNUmVxdWVzdEFyZ3MsIGNyZWF0ZVJlcXVlc3RPcHRpb25zLCBsb2FkQ29uZmlnLCBsb2NhdGlvbnMgfSBmcm9tICdAYXh3YXkvYW1wbGlmeS1jbGktdXRpbHMnO1xuaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSAnZXZlbnRzJztcbmltcG9ydCB7IGlzRGlyLCBpc0ZpbGUsIG1rZGlycFN5bmMgfSBmcm9tICdAYXh3YXkvYW1wbGlmeS11dGlscyc7XG5cbmNvbnN0IHNjb3BlZFBhY2thZ2VSZWdleCA9IC9eQFthLXowLTldW1xcdy0uXStcXC8/LztcbmNvbnN0IHsgZXJyb3IsIGxvZyB9ID0gc25vb3Bsb2dnKCdwbScpO1xuY29uc3QgeyBhbGVydCwgaGlnaGxpZ2h0IH0gPSBzbm9vcGxvZ2cuc3R5bGVzO1xuXG4vKipcbiAqIFRoZSBwYXRoIHRvIHRoZSBBeHdheSBDTEkgcGFja2FnZXMgZGlyZWN0b3J5LlxuICogQHR5cGUge1N0cmluZ31cbiAqL1xuZXhwb3J0IGNvbnN0IHBhY2thZ2VzRGlyID0gcGF0aC5qb2luKGxvY2F0aW9ucy5heHdheUhvbWUsICdheHdheS1jbGknLCAncGFja2FnZXMnKTtcblxuLyoqXG4gKiBGaW5kcyBhIHNwZWNpZmljIGluc3RhbGxlZCBwYWNrYWdlLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBwYWNrYWdlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBwYWNrYWdlIHRvIGZpbmQuXG4gKiBAcmV0dXJucyB7T2JqZWN0fVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmluZChwYWNrYWdlTmFtZSkge1xuXHRpZiAoIXBhY2thZ2VOYW1lIHx8IHR5cGVvZiBwYWNrYWdlTmFtZSAhPT0gJ3N0cmluZycpIHtcblx0XHR0aHJvdyBuZXcgVHlwZUVycm9yKCdFeHBlY3RlZCBwYWNrYWdlIG5hbWUgdG8gYmUgYSBub24tZW1wdHkgc3RyaW5nJyk7XG5cdH1cblxuXHRpZiAoIWlzRGlyKHBhY2thZ2VzRGlyKSkge1xuXHRcdHJldHVybiB1bmRlZmluZWQ7XG5cdH1cblx0Y29uc3QgY29uZmlnID0gYXdhaXQgbG9hZENvbmZpZygpO1xuXHRjb25zdCBleHRlbnNpb25zID0gYXdhaXQgY29uZmlnLmdldCgnZXh0ZW5zaW9ucycsIHt9KTtcblxuXHRwYWNrYWdlTmFtZSA9IHBhY2thZ2VOYW1lLnRvTG93ZXJDYXNlKCk7XG5cblx0Zm9yIChjb25zdCBuYW1lIG9mIGZzLnJlYWRkaXJTeW5jKHBhY2thZ2VzRGlyKSkge1xuXHRcdGNvbnN0IHBrZ0RpciA9IHBhdGguam9pbihwYWNrYWdlc0RpciwgbmFtZSk7XG5cdFx0aWYgKCFpc0Rpcihwa2dEaXIpKSB7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cblx0XHRpZiAoc2NvcGVkUGFja2FnZVJlZ2V4LnRlc3QobmFtZSkpIHtcblx0XHRcdGZvciAoY29uc3QgcGtnU3ViRGlyIG9mIGZzLnJlYWRkaXJTeW5jKHBrZ0RpcikpIHtcblx0XHRcdFx0Y29uc3QgZGlyID0gcGF0aC5qb2luKHBrZ0RpciwgcGtnU3ViRGlyKTtcblx0XHRcdFx0Y29uc3QgcGtnTmFtZSA9IGAke25hbWV9LyR7cGtnU3ViRGlyfWA7XG5cdFx0XHRcdGlmIChpc0RpcihkaXIpICYmIHBrZ05hbWUudG9Mb3dlckNhc2UoKSA9PT0gcGFja2FnZU5hbWUpIHtcblx0XHRcdFx0XHRjb25zdCBwYWNrYWdlRGF0YSA9IGxvYWRQYWNrYWdlRGF0YShwa2dOYW1lLCBleHRlbnNpb25zLCBkaXIpO1xuXHRcdFx0XHRcdGlmIChwYWNrYWdlRGF0YS52ZXJzaW9uIHx8IE9iamVjdC5rZXlzKHBhY2thZ2VEYXRhLnZlcnNpb25zKS5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdHJldHVybiBwYWNrYWdlRGF0YTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9IGVsc2UgaWYgKG5hbWUudG9Mb3dlckNhc2UoKSA9PT0gcGFja2FnZU5hbWUpIHtcblx0XHRcdGNvbnN0IHBhY2thZ2VEYXRhID0gbG9hZFBhY2thZ2VEYXRhKG5hbWUsIGV4dGVuc2lvbnMsIHBrZ0Rpcik7XG5cdFx0XHRpZiAocGFja2FnZURhdGEudmVyc2lvbiB8fCBPYmplY3Qua2V5cyhwYWNrYWdlRGF0YS52ZXJzaW9ucykubGVuZ3RoKSB7XG5cdFx0XHRcdHJldHVybiBwYWNrYWdlRGF0YTtcblx0XHRcdH1cblx0XHR9XG5cdH1cbn1cblxuLyoqXG4gKiBJbnN0YWxscyBhIHBhY2thZ2UgZnJvbSBucG0uXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHBrZ05hbWUgLSBUaGUgcGFja2FnZSBhbmQgdmVyc2lvbiB0byBpbnN0YWxsLlxuICogQHJldHVybnMge0V2ZW50RW1pdHRlcn1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGluc3RhbGwocGtnTmFtZSkge1xuXHRjb25zdCBlbWl0dGVyID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG5cdHNldEltbWVkaWF0ZShhc3luYyAoKSA9PiB7XG5cdFx0bGV0IGNmZyA9IGF3YWl0IGxvYWRDb25maWcoKTtcblx0XHRsZXQgcHJldmlvdXNBY3RpdmVQYWNrYWdlO1xuXHRcdGxldCBpbmZvO1xuXG5cdFx0dHJ5IHtcblx0XHRcdGluZm8gPSBhd2FpdCB2aWV3KHBrZ05hbWUpO1xuXG5cdFx0XHRsZXQgbnBtO1xuXHRcdFx0dHJ5IHtcblx0XHRcdFx0bnBtID0gYXdhaXQgd2hpY2goJ25wbScpO1xuXHRcdFx0fSBjYXRjaCAoZSkge1xuXHRcdFx0XHRjb25zdCBlcnIgPSBuZXcgRXJyb3IoJ1VuYWJsZSB0byBmaW5kIHRoZSBcIm5wbVwiIGV4ZWN1dGFibGUuIFBsZWFzZSBlbnN1cmUgeW91IGhhdmUgXCJucG1cIiBpbnN0YWxsZWQgb24geW91ciBtYWNoaW5lJyk7XG5cdFx0XHRcdGVyci5jb2RlID0gJ0VOT05QTSc7XG5cdFx0XHRcdHRocm93IGVycjtcblx0XHRcdH1cblxuXHRcdFx0cHJldmlvdXNBY3RpdmVQYWNrYWdlID0gYXdhaXQgY2ZnLmdldChgZXh0ZW5zaW9ucy4ke2luZm8ubmFtZX1gKTtcblxuXHRcdFx0aW5mby5wYXRoID0gcGF0aC5qb2luKHBhY2thZ2VzRGlyLCBpbmZvLm5hbWUsIGluZm8udmVyc2lvbik7XG5cdFx0XHRta2RpcnBTeW5jKGluZm8ucGF0aCk7XG5cblx0XHRcdGVtaXR0ZXIuZW1pdCgnZG93bmxvYWQnLCBpbmZvKTtcblx0XHRcdGF3YWl0IHBhY290ZS5leHRyYWN0KGAke2luZm8ubmFtZX1AJHtpbmZvLnZlcnNpb259YCwgaW5mby5wYXRoLCBjcmVhdGVSZXF1ZXN0T3B0aW9ucygpKTtcblxuXHRcdFx0ZW1pdHRlci5lbWl0KCdpbnN0YWxsJywgaW5mbyk7XG5cdFx0XHRjb25zdCBhcmdzID0gW1xuXHRcdFx0XHQnaW5zdGFsbCcsXG5cdFx0XHRcdCctLXByb2R1Y3Rpb24nLFxuXHRcdFx0XHQnLS1mb3JjZScsIC8vIG5lZWRlZCBmb3IgbnBtIDdcblx0XHRcdFx0Li4uY3JlYXRlTlBNUmVxdWVzdEFyZ3MoKVxuXHRcdFx0XTtcblx0XHRcdGNvbnN0IG9wdHMgPSB7XG5cdFx0XHRcdGN3ZDogaW5mby5wYXRoLFxuXHRcdFx0XHRlbnY6IE9iamVjdC5hc3NpZ24oeyBOT19VUERBVEVfTk9USUZJRVI6IDEgfSwgcHJvY2Vzcy5lbnYpLFxuXHRcdFx0XHRnaWQ6IHByb2Nlc3MuZW52LlNVRE9fR0lEID8gcGFyc2VJbnQocHJvY2Vzcy5lbnYuU1VET19HSUQpIDogdW5kZWZpbmVkLFxuXHRcdFx0XHR1aWQ6IHByb2Nlc3MuZW52LlNVRE9fVUlEID8gcGFyc2VJbnQocHJvY2Vzcy5lbnYuU1VET19VSUQpIDogdW5kZWZpbmVkLFxuXHRcdFx0XHR3aW5kb3dzSGlkZTogdHJ1ZVxuXHRcdFx0fTtcblxuXHRcdFx0bG9nKGBub2RlICR7aGlnaGxpZ2h0KHByb2Nlc3MudmVyc2lvbil9IG5wbSAke2hpZ2hsaWdodChzcGF3bi5zeW5jKCducG0nLCBbICctdicgXSwgb3B0cykuc3Rkb3V0LnRvU3RyaW5nKCkudHJpbSgpKX1gKTtcblx0XHRcdGxvZyhgUnVubmluZyBQV0Q9JHtpbmZvLnBhdGh9ICR7aGlnaGxpZ2h0KGAke25wbX0gJHthcmdzLmpvaW4oJyAnKX1gKX1gKTtcblx0XHRcdGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcblx0XHRcdFx0bGV0IHN0ZGVyciA9ICcnO1xuXHRcdFx0XHRjb25zdCBjaGlsZCA9IHNwYXduKG5wbSwgYXJncywgb3B0cyk7XG5cblx0XHRcdFx0Y2hpbGQuc3Rkb3V0Lm9uKCdkYXRhJywgZGF0YSA9PiBsb2coZGF0YS50b1N0cmluZygpLnRyaW0oKSkpO1xuXHRcdFx0XHRjaGlsZC5zdGRlcnIub24oJ2RhdGEnLCBkYXRhID0+IHtcblx0XHRcdFx0XHRjb25zdCBzID0gZGF0YS50b1N0cmluZygpO1xuXHRcdFx0XHRcdHN0ZGVyciArPSBzO1xuXHRcdFx0XHRcdGxvZyhzLnRyaW0oKSk7XG5cdFx0XHRcdH0pO1xuXG5cdFx0XHRcdGNoaWxkLm9uKCdjbG9zZScsIHN0YXR1cyA9PiB7XG5cdFx0XHRcdFx0aWYgKHN0YXR1cykge1xuXHRcdFx0XHRcdFx0cmVqZWN0KG5ldyBFcnJvcihgJHtzdGRlcnIgPyBTdHJpbmcoc3RkZXJyLnNwbGl0KC9cXHJcXG58XFxuLylbMF0pLnJlcGxhY2UoL15cXHMqZXJyb3I6XFxzKi9pLCAnJykgOiAndW5rbm93biBlcnJvcid9IChjb2RlICR7c3RhdHVzfSlgKSk7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHJlc29sdmUoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0pO1xuXHRcdFx0fSk7XG5cblx0XHRcdGVtaXR0ZXIuZW1pdCgncmVnaXN0ZXInLCBpbmZvKTtcblx0XHRcdGNmZyA9IGF3YWl0IGxvYWRDb25maWcoKTtcblx0XHRcdGF3YWl0IGNmZy5zZXQoYGV4dGVuc2lvbnMuJHtpbmZvLm5hbWV9YCwgaW5mby5wYXRoKTtcblx0XHRcdGF3YWl0IGNmZy5zYXZlKCk7XG5cblx0XHRcdGVtaXR0ZXIuZW1pdCgnZW5kJywgaW5mbyk7XG5cdFx0fSBjYXRjaCAoZXJyKSB7XG5cdFx0XHRpZiAoaW5mbykge1xuXHRcdFx0XHRpZiAocHJldmlvdXNBY3RpdmVQYWNrYWdlID09PSBpbmZvLnBhdGgpIHtcblx0XHRcdFx0XHQvLyBwYWNrYWdlIHdhcyByZWluc3RhbGxlZCwgYnV0IGZhaWxlZCBhbmQgZGlyZWN0b3J5IGlzIGluIGFuIHVua25vd24gc3RhdGVcblx0XHRcdFx0XHRjZmcgPSBhd2FpdCBsb2FkQ29uZmlnKCk7XG5cdFx0XHRcdFx0YXdhaXQgY2ZnLmRlbGV0ZShgZXh0ZW5zaW9ucy4ke2luZm8ubmFtZX1gKTtcblx0XHRcdFx0XHRhd2FpdCBjZmcuc2F2ZSgpO1xuXHRcdFx0XHR9IGVsc2UgaWYgKHByZXZpb3VzQWN0aXZlUGFja2FnZSkge1xuXHRcdFx0XHRcdC8vIHJlc3RvcmUgdGhlIHByZXZpb3VzIHZhbHVlXG5cdFx0XHRcdFx0Y2ZnID0gYXdhaXQgbG9hZENvbmZpZygpO1xuXHRcdFx0XHRcdGF3YWl0IGNmZy5zZXQoYGV4dGVuc2lvbnMuJHtpbmZvLm5hbWV9YCwgcHJldmlvdXNBY3RpdmVQYWNrYWdlKTtcblx0XHRcdFx0XHRhd2FpdCBjZmcuc2F2ZSgpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKGluZm8ucGF0aCkge1xuXHRcdFx0XHRcdGF3YWl0IGZzLnJlbW92ZShpbmZvLnBhdGgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdGVtaXR0ZXIuZW1pdCgnZXJyb3InLCBlcnIpO1xuXHRcdH1cblx0fSk7XG5cblx0cmV0dXJuIGVtaXR0ZXI7XG59XG5cbi8qKlxuICogRGV0ZWN0cyBhbGwgaW5zdGFsbGVkIHBhY2thZ2VzLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPEFycmF5LjxPYmplY3Q+Pn1cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGxpc3QoKSB7XG5cdGlmICghaXNEaXIocGFja2FnZXNEaXIpKSB7XG5cdFx0cmV0dXJuIFtdO1xuXHR9XG5cblx0Y29uc3QgY29uZmlnID0gYXdhaXQgbG9hZENvbmZpZygpO1xuXHRjb25zdCBleHRlbnNpb25zID0gYXdhaXQgY29uZmlnLmdldCgnZXh0ZW5zaW9ucycsIHt9KTtcblx0Y29uc3QgcGFja2FnZXMgPSBbXTtcblxuXHRmb3IgKGNvbnN0IG5hbWUgb2YgZnMucmVhZGRpclN5bmMocGFja2FnZXNEaXIpKSB7XG5cdFx0Y29uc3QgcGtnRGlyID0gcGF0aC5qb2luKHBhY2thZ2VzRGlyLCBuYW1lKTtcblx0XHRpZiAoIWlzRGlyKHBrZ0RpcikpIHtcblx0XHRcdGNvbnRpbnVlO1xuXHRcdH1cblxuXHRcdGlmIChzY29wZWRQYWNrYWdlUmVnZXgudGVzdChuYW1lKSkge1xuXHRcdFx0Zm9yIChjb25zdCBwa2dTdWJEaXIgb2YgZnMucmVhZGRpclN5bmMocGtnRGlyKSkge1xuXHRcdFx0XHRjb25zdCBkaXIgPSBwYXRoLmpvaW4ocGtnRGlyLCBwa2dTdWJEaXIpO1xuXHRcdFx0XHRjb25zdCBwa2dOYW1lID0gYCR7bmFtZX0vJHtwa2dTdWJEaXJ9YDtcblx0XHRcdFx0aWYgKGlzRGlyKGRpcikpIHtcblx0XHRcdFx0XHRjb25zdCBwYWNrYWdlRGF0YSA9IGxvYWRQYWNrYWdlRGF0YShwa2dOYW1lLCBleHRlbnNpb25zLCBkaXIpO1xuXHRcdFx0XHRcdGlmIChwYWNrYWdlRGF0YS52ZXJzaW9uIHx8IE9iamVjdC5rZXlzKHBhY2thZ2VEYXRhLnZlcnNpb25zKS5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdHBhY2thZ2VzLnB1c2gocGFja2FnZURhdGEpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHRjb25zdCBwYWNrYWdlRGF0YSA9IGxvYWRQYWNrYWdlRGF0YShuYW1lLCBleHRlbnNpb25zLCBwa2dEaXIpO1xuXHRcdFx0aWYgKHBhY2thZ2VEYXRhLnZlcnNpb24gfHwgT2JqZWN0LmtleXMocGFja2FnZURhdGEudmVyc2lvbnMpLmxlbmd0aCkge1xuXHRcdFx0XHRwYWNrYWdlcy5wdXNoKHBhY2thZ2VEYXRhKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gcGFja2FnZXM7XG59XG5cbi8qKlxuICogRGV0ZXJtaW5lcyBpZiB0aGVyZSBhcmUgYW55IG9sZGVyIHZlcnNpb25zIG9mIHBhY2thZ2VzIGluc3RhbGxlZCB0aGF0IGNvdWxkIGJlIHB1cmdlZC5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gW3BrZ05hbWVdIC0gQSBzcGVjaWZpYyBwYWNrYWdlIHRvIGNoZWNrIGlmIHB1cmdhYmxlLCBvdGhlcndpc2UgY2hlY2tzIGFsbFxuICogcGFja2FnZXMuXG4gKiBAcmV0dXJucyB7T2JqZWN0fVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbGlzdFB1cmdhYmxlKHBrZ05hbWUpIHtcblx0bGV0IHBhY2thZ2VzID0gW107XG5cblx0aWYgKHBrZ05hbWUpIHtcblx0XHRjb25zdCBwa2cgPSBhd2FpdCBmaW5kKHBrZ05hbWUpO1xuXHRcdGlmICghcGtnKSB7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoYFBhY2thZ2UgXCIke3BrZ05hbWV9XCIgaXMgbm90IGluc3RhbGxlZGApO1xuXHRcdH1cblx0XHRwYWNrYWdlcy5wdXNoKHBrZyk7XG5cdH0gZWxzZSB7XG5cdFx0cGFja2FnZXMgPSBhd2FpdCBsaXN0KCk7XG5cdH1cblxuXHRjb25zdCBwdXJnYWJsZSA9IHt9O1xuXG5cdGZvciAoY29uc3QgeyBuYW1lLCB2ZXJzaW9uLCB2ZXJzaW9ucyB9IG9mIHBhY2thZ2VzKSB7XG5cdFx0Zm9yIChjb25zdCBbIHZlciwgdmVyc2lvbkRhdGEgXSBvZiBPYmplY3QuZW50cmllcyh2ZXJzaW9ucykpIHtcblx0XHRcdC8vIGlmIG1hbmFnZWQgYW5kIG5vdCBpbiB1c2Vcblx0XHRcdGlmICh2ZXJzaW9uRGF0YS5tYW5hZ2VkICYmIHZlcnNpb25EYXRhLnBhdGguc3RhcnRzV2l0aChwYWNrYWdlc0RpcikgJiYgc2VtdmVyLm5lcSh2ZXIsIHZlcnNpb24pKSB7XG5cdFx0XHRcdGlmICghcHVyZ2FibGVbbmFtZV0pIHtcblx0XHRcdFx0XHRwdXJnYWJsZVtuYW1lXSA9IFtdO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHB1cmdhYmxlW25hbWVdLnB1c2goe1xuXHRcdFx0XHRcdC4uLnZlcnNpb25EYXRhLFxuXHRcdFx0XHRcdHZlcnNpb246IHZlclxuXHRcdFx0XHR9KTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gcHVyZ2FibGU7XG59XG5cbi8qKlxuICogU2NhbnMgYSBwYWNrYWdlIGRpcmVjdG9yeSBmb3IgYWxsIGluc3RhbGxlZCB2ZXJzaW9ucy5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSAtIFRoZSBwYWNrYWdlIG5hbWUuXG4gKiBAcGFyYW0ge09iamVjdH0gZXh0ZW5zaW9ucyAtIEFuIG9iamVjdCBvZiByZWdpc3RlcmVkIGV4dGVuc2lvbiBuYW1lcyBhbmQgdGhlaXIgcGF0aHMuXG4gKiBAcGFyYW0ge1N0cmluZ30gcGtnRGlyIC0gVGhlIHBhdGggdG8gdGhlIHBhY2thZ2UuXG4gKiBAcmV0dXJucyB7T2JqZWN0fVxuICovXG5mdW5jdGlvbiBsb2FkUGFja2FnZURhdGEobmFtZSwgZXh0ZW5zaW9ucywgcGtnRGlyKSB7XG5cdGNvbnN0IHBhY2thZ2VEYXRhID0ge1xuXHRcdG5hbWUsXG5cdFx0ZGVzY3JpcHRpb246IHVuZGVmaW5lZCxcblx0XHR2ZXJzaW9uOiB1bmRlZmluZWQsXG5cdFx0dmVyc2lvbnM6IHt9XG5cdH07XG5cblx0Ly8gZmluZCBhbGwgdmVyc2lvbnNcblx0Zm9yIChjb25zdCB2ZXJzaW9uIG9mIGZzLnJlYWRkaXJTeW5jKHBrZ0RpcikpIHtcblx0XHR0cnkge1xuXHRcdFx0Y29uc3QgdmVyc2lvbkRpciA9IHBhdGguam9pbihwa2dEaXIsIHZlcnNpb24pO1xuXHRcdFx0Y29uc3QgcGtnSnNvbiA9IGZzLnJlYWRKc29uU3luYyhwYXRoLmpvaW4odmVyc2lvbkRpciwgJ3BhY2thZ2UuanNvbicpKTtcblx0XHRcdHBhY2thZ2VEYXRhLmRlc2NyaXB0aW9uID0gcGtnSnNvbi5kZXNjcmlwdGlvbjtcblx0XHRcdHBhY2thZ2VEYXRhLnZlcnNpb25zW3ZlcnNpb25dID0ge1xuXHRcdFx0XHRwYXRoOiB2ZXJzaW9uRGlyLFxuXHRcdFx0XHRtYW5hZ2VkOiB0cnVlXG5cdFx0XHR9O1xuXHRcdH0gY2F0Y2ggKGUpIHtcblx0XHRcdC8vIHNxdWVsY2hcblx0XHR9XG5cdH1cblxuXHQvLyBzZWUgaWYgdGhpcyBwYWNrYWdlIGlzIGFuIGV4dGVuc2lvbiBhbmQgaWYgaXQncyB0aGUgY3VycmVudGx5IHNlbGVjdGVkIHZlcnNpb25cblx0bGV0IGV4dFBhdGggPSBleHRlbnNpb25zW25hbWVdO1xuXHRpZiAoIWV4dFBhdGgpIHtcblx0XHRuYW1lID0gbmFtZS5yZXBsYWNlKHNjb3BlZFBhY2thZ2VSZWdleCwgJycpO1xuXHRcdGV4dFBhdGggPSBleHRlbnNpb25zW25hbWVdO1xuXHR9XG5cdGlmIChleHRQYXRoKSB7XG5cdFx0Y29uc3QgcGtnSnNvbkZpbGUgPSBwYXRoLmpvaW4oZXh0UGF0aCwgJ3BhY2thZ2UuanNvbicpO1xuXHRcdGlmIChpc0ZpbGUocGtnSnNvbkZpbGUpKSB7XG5cdFx0XHRjb25zdCB7IHZlcnNpb24gfSA9IGZzLnJlYWRKc29uU3luYyhwa2dKc29uRmlsZSk7XG5cdFx0XHRwYWNrYWdlRGF0YS52ZXJzaW9uID0gdmVyc2lvbjtcblx0XHRcdGlmICghcGFja2FnZURhdGEudmVyc2lvbnNbdmVyc2lvbl0pIHtcblx0XHRcdFx0cGFja2FnZURhdGEudmVyc2lvbnNbdmVyc2lvbl0gPSB7XG5cdFx0XHRcdFx0cGF0aDogZXh0UGF0aCxcblx0XHRcdFx0XHRtYW5hZ2VkOiBmYWxzZVxuXHRcdFx0XHR9O1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdHJldHVybiBwYWNrYWdlRGF0YTtcbn1cblxuLyoqXG4gKiBVbmluc3RhbGxzIGEgcGFja2FnZS5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gZGlyIC0gUGF0aCB0byB0aGUgcGFja2FnZSB0byBkZWxldGUuXG4gKiBAcmV0dXJucyB7UHJvbWlzZX1cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHVuaW5zdGFsbFBhY2thZ2UoZGlyKSB7XG5cdHRyeSB7XG5cdFx0Y29uc3QgcGtnSnNvbiA9IGF3YWl0IGZzLnJlYWRKc29uKHBhdGguam9pbihkaXIsICdwYWNrYWdlLmpzb24nKSk7XG5cdFx0aWYgKHBrZ0pzb24uc2NyaXB0cy51bmluc3RhbGwpIHtcblx0XHRcdGxvZyhgUnVubmluZyBucG0gdW5pbnN0YWxsIHNjcmlwdDogJHtoaWdobGlnaHQocGtnSnNvbi5zY3JpcHRzLnVuaW5zdGFsbCl9YCk7XG5cdFx0XHRjb25zdCB7IHN0YXR1cywgc3RkZXJyIH0gPSBzcGF3bi5zeW5jKCducG0nLCBbICdydW4nLCAndW5pbnN0YWxsJyBdLCB7IGN3ZDogZGlyIH0pO1xuXHRcdFx0aWYgKHN0YXR1cykge1xuXHRcdFx0XHRlcnJvcihhbGVydCgnRmFpbGVkIHRvIHJ1biBucG0gdW5pbnN0YWxsIHNjcmlwdDonKSk7XG5cdFx0XHRcdGVycm9yKHN0ZGVycik7XG5cdFx0XHR9XG5cdFx0fVxuXHR9IGNhdGNoIChlKSB7XG5cdFx0Ly8gc3F1ZWxjaFxuXHR9XG5cblx0YXdhaXQgZnMucmVtb3ZlKGRpcik7XG59XG5cbi8qKlxuICogU2VhcmNoZXMgbnBtIGZvciBBeHdheSBDTEkgcGFja2FnZXMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRzXSAtIFZhcmlvdXMgb3B0aW9ucy5cbiAqIEBwYXJhbSB7U3RyaW5nfSBbb3B0cy5rZXl3b3JkXSAtIEEga2V5d29yZCB0byBzZWFyY2ggZm9yLlxuICogQHBhcmFtIHtOdW1iZXJ9IFtvcHRzLmxpbWl0PTUwXSAtIFRoZSBtYXggbnVtYmVyIG9mIHJlc3VsdHMgdG8gcmV0dXJuLlxuICogQHBhcmFtIHtTdHJpbmd9IFtvcHRzLnR5cGVdIC0gQSBwYWNrYWdlIHR5cGUgdG8gZmlsdGVyIGJ5LlxuICogQHJldHVybnMge1Byb21zZTxBcnJheS48T2JqZWN0Pj59XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZWFyY2goeyBrZXl3b3JkLCBsaW1pdCwgdHlwZSB9ID0ge30pIHtcblx0Y29uc3QgcGxpbWl0ID0gcHJvbWlzZUxpbWl0KDEwKTtcblx0Y29uc3QgcmVxdWVzdE9wdHMgPSBjcmVhdGVSZXF1ZXN0T3B0aW9ucygpO1xuXHRjb25zdCBrZXl3b3JkcyA9IFsgJ2FtcGxpZnktcGFja2FnZScgXTtcblx0aWYgKHByb2Nlc3MuZW52LlRFU1QpIHtcblx0XHRrZXl3b3Jkcy5wdXNoKCdhbXBsaWZ5LXRlc3QtcGFja2FnZScpO1xuXHR9XG5cdGlmIChrZXl3b3JkKSB7XG5cdFx0a2V5d29yZHMucHVzaChrZXl3b3JkKTtcblx0fVxuXHRjb25zdCBxID0gJ2tleXdvcmRzOicgKyBrZXl3b3Jkcy5qb2luKCcsJyk7XG5cdGNvbnN0IHBhY2thZ2VzID0gYXdhaXQgbnBtc2VhcmNoKHEsIHtcblx0XHQuLi5yZXF1ZXN0T3B0cyxcblx0XHRsaW1pdDogTWF0aC5tYXgobGltaXQgJiYgcGFyc2VJbnQobGltaXQsIDEwKSB8fCA1MCwgMSlcblx0fSk7XG5cdGNvbnN0IHJlc3VsdHMgPSBbXTtcblxuXHRhd2FpdCBQcm9taXNlLmFsbChwYWNrYWdlcy5tYXAoKHsgbmFtZSwgdmVyc2lvbiB9KSA9PiB7XG5cdFx0cmV0dXJuIHBsaW1pdChhc3luYyAoKSA9PiB7XG5cdFx0XHR0cnkge1xuXHRcdFx0XHRjb25zdCBwa2cgPSBhd2FpdCB2aWV3KGAke25hbWV9QCR7dmVyc2lvbn1gLCB7IHJlcXVlc3RPcHRzLCB0eXBlIH0pO1xuXHRcdFx0XHRpZiAocGtnKSB7XG5cdFx0XHRcdFx0cmVzdWx0cy5wdXNoKHBrZyk7XG5cdFx0XHRcdH1cblx0XHRcdH0gY2F0Y2ggKGVycikge1xuXHRcdFx0XHQvLyBzcXVlbGNoXG5cdFx0XHR9XG5cdFx0fSk7XG5cdH0pKTtcblx0cmV0dXJuIHJlc3VsdHMuc29ydCgoYSwgYikgPT4gYS5uYW1lLmxvY2FsZUNvbXBhcmUoYi5uYW1lKSk7XG59XG5cbi8qKlxuICogRmV0Y2hlcyBwYWNrYWdlIGluZm9ybWF0aW9uIGRpcmVjdGx5IGZyb20gbnBtIGFuZCBjaGVja3MgdGhhdCBpdCdzIGEgdmFsaWQgcGFja2FnZS5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gcGtnTmFtZSAtIFRoZSBwYWNrYWdlIG5hbWUuXG4gKiBAcGFyYW0ge09iamVjdH0gW29wdHNdIC0gVmFyaW91cyBvcHRpb25zLlxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRzLnJlcXVlc3RPcHRzXSAtIEhUVFAgcmVxdWVzdCBvcHRpb25zLlxuICogQHBhcmFtIHtTdHJpbmd9IFtvcHRzLnR5cGVdIC0gVGhlIHBhY2thZ2UgdHlwZSB0byBmaWx0ZXIgYnkuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB2aWV3KHBrZ05hbWUsIHsgcmVxdWVzdE9wdHMgPSBjcmVhdGVSZXF1ZXN0T3B0aW9ucygpLCB0eXBlIH0gPSB7fSkge1xuXHRpZiAoIXBrZ05hbWUgfHwgdHlwZW9mIHBrZ05hbWUgIT09ICdzdHJpbmcnKSB7XG5cdFx0dGhyb3cgbmV3IFR5cGVFcnJvcignRXhwZWN0ZWQgcGFja2FnZSBuYW1lIHRvIGJlIGEgbm9uLWVtcHR5IHN0cmluZycpO1xuXHR9XG5cblx0Y29uc3QgeyBuYW1lLCBmZXRjaFNwZWMgfSA9IG5wYShwa2dOYW1lKTtcblx0bGV0IGluZm87XG5cblx0aWYgKCFuYW1lKSB7XG5cdFx0dGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHBhY2thZ2UgbmFtZSBcIiR7cGtnTmFtZX1cImApO1xuXHR9XG5cblx0dHJ5IHtcblx0XHRpbmZvID0gYXdhaXQgcGFjb3RlLnBhY2t1bWVudChuYW1lLCB7XG5cdFx0XHQuLi5yZXF1ZXN0T3B0cyxcblx0XHRcdGZ1bGxNZXRhZGF0YTogdHJ1ZVxuXHRcdH0pO1xuXHR9IGNhdGNoIChlcnIpIHtcblx0XHRpZiAoZXJyLnN0YXR1c0NvZGUgPT09IDQwNCkge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKGBQYWNrYWdlIFwiJHtwa2dOYW1lfVwiIG5vdCBmb3VuZGApO1xuXHRcdH1cblx0XHR0aHJvdyBlcnI7XG5cdH1cblxuXHRjb25zdCB2ZXJzaW9uID0gaW5mb1snZGlzdC10YWdzJ10/LltmZXRjaFNwZWNdIHx8IGZldGNoU3BlYztcblx0Y29uc3QgcGtnID0gaW5mby52ZXJzaW9uc1t2ZXJzaW9uXTtcblx0Y29uc3QgbWFpbnRhaW5lcnMgPSBbICdhcHBjZWxlcmF0b3InLCAnYXh3YXktbnBtJyBdO1xuXG5cdGlmICghcGtnXG5cdFx0fHwgIXBrZy5hbXBsaWZ5Py50eXBlXG5cdFx0fHwgKHR5cGUgJiYgcGtnLmFtcGxpZnkudHlwZSAhPT0gdHlwZSlcblx0XHR8fCAocGtnLmtleXdvcmRzLmluY2x1ZGVzKCdhbXBsaWZ5LXRlc3QtcGFja2FnZScpICYmICFwcm9jZXNzLmVudi5URVNUKVxuXHRcdHx8ICFwa2cua2V5d29yZHMuaW5jbHVkZXMoJ2FtcGxpZnktcGFja2FnZScpXG5cdFx0fHwgIWluZm8/Lm1haW50YWluZXJzLnNvbWUobSA9PiBtYWludGFpbmVycy5pbmNsdWRlcyhtLm5hbWUpKVxuXHQpIHtcblx0XHR0aHJvdyBuZXcgRXJyb3IoYFBhY2thZ2UgXCIke3BrZ05hbWV9XCIgbm90IGZvdW5kYCk7XG5cdH1cblxuXHRjb25zdCBpbnN0YWxsZWQgPSBhd2FpdCBmaW5kKHBrZy5uYW1lKTtcblxuXHRyZXR1cm4ge1xuXHRcdGRlc2NyaXB0aW9uOiBwa2cuZGVzY3JpcHRpb24sXG5cdFx0aW5zdGFsbGVkOiAgIGluc3RhbGxlZD8udmVyc2lvbnMgfHwgZmFsc2UsXG5cdFx0bmFtZTogICAgICAgIHBrZy5uYW1lLFxuXHRcdHR5cGU6ICAgICAgICBwa2cuYW1wbGlmeS50eXBlLFxuXHRcdHZlcnNpb24sXG5cdFx0dmVyc2lvbnM6ICAgIE9iamVjdC5rZXlzKGluZm8udmVyc2lvbnMpXG5cdH07XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7O0FBQUE7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7Ozs7QUFFQSxNQUFNQSxrQkFBa0IsR0FBRyxzQkFBM0I7QUFDQSxNQUFNO0VBQUVDLEtBQUY7RUFB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