UNPKG

@axway/axway-cli-pm

Version:

Package manager for Axway products

506 lines (414 loc) 48.9 kB
"use strict"; 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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