UNPKG

@enterthenamehere/esdoc

Version:

Good Documentation Generator For JavaScript, updated for new decade

508 lines (488 loc) 69.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _fsExtra = _interopRequireDefault(require("fs-extra")); var _path = _interopRequireDefault(require("path")); var _ASTUtil = _interopRequireDefault(require("@enterthenamehere/esdoc/out/Util/ASTUtil")); var _DocFactory = _interopRequireDefault(require("@enterthenamehere/esdoc/out/Factory/DocFactory")); var _ESParser = _interopRequireDefault(require("@enterthenamehere/esdoc/out/Parser/ESParser")); var _FileManager = require("@enterthenamehere/esdoc/out/Util/FileManager"); var _InvalidCodeLogger = _interopRequireDefault(require("@enterthenamehere/esdoc/out/Util/InvalidCodeLogger")); var _PathResolver = _interopRequireDefault(require("@enterthenamehere/esdoc/out/Util/PathResolver")); var _PluginManager = _interopRequireDefault(require("@enterthenamehere/esdoc/out/Plugin/PluginManager")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } var debugModule = require('debug'); var debug = debugModule('ESDoc:ESDoc'); /** * API Documentation Generator. * * @example * let config = {source: './src', destination: './esdoc'}; * ESDoc.generate(config, (results, config)=>{ * console.log(results); * }); */ class ESDoc { /** * Generate documentation. * @param {ESDocConfig} config - config for generation. */ static generate(config) { var _this = this; if (typeof config === 'undefined' || config === null) { var message = "\x1B[31mError: config object is expected as an argument!\x1B[0m"; console.error("\x1B[31m".concat(message, "\x1B[0m")); throw new Error(message); } if (config.debug) debugModule.enable('ESDoc:*'); debug('Executing ESDoc with following config:\n%O', config); // Let's allow multiple sources instead of just one directory if (Object.prototype.hasOwnProperty.call(config, 'sources')) { config.source = config.sources; delete config.sources; } // To make it easier, if source is a single directory, make it array anyway. if (Object.prototype.hasOwnProperty.call(config, 'source')) { if (typeof config.source === 'string') { if (config.source.trim() === '') { var _message = "\x1B[31mError: config.source cannot be empty! This is a directory where you have your source code.\x1B[0m"; console.error("\x1B[31m".concat(_message, "\x1B[0m")); throw new Error(_message); } config.source = [config.source]; // Ok now we only expect an array, nothing else if (!Array.isArray(config.source)) { var _message2 = "\x1B[31mError: config.source must be either a string or an array of strings!\x1B[0m"; console.error("\x1B[31m".concat(_message2, "\x1B[0m")); throw new Error(_message2); } config.source.forEach(value => { if (typeof value !== 'string') { var _message3 = "\x1B[31mError: config.source must contain only strings!\x1B[0m"; console.error("\x1B[31m".concat(_message3, "\x1B[0m")); throw new Error(_message3); } if (value.trim() === '') { var _message4 = "\x1B[31mError: config.source cannot contain empty string!\x1B[0m"; console.error("\x1B[31m".concat(_message4, "\x1B[0m")); throw new Error(_message4); } }); } } if (typeof config.destination !== 'string' || config.destination === '') { var _message5 = "\x1B[31mError: config.destination needs to be a directory where to output generated documentation!\x1B[0m"; console.error("\x1B[31m".concat(_message5, "\x1B[0m")); throw new Error(_message5); } this._checkOldConfig(config); // Check whether includes/excludes is possibly regexp var isRegExp = false; if (config.includes) { for (var value of config.includes) { //console.log('value', value); //console.log('value', value.match(/[$^]/u)); if (value.match(/[\$\^]/)) { isRegExp = true; } } } if (config.excludes) { for (var _value of config.excludes) { //console.log('value', value); //console.log('value', value.match(/[$^]/u)); if (_value.match(/[\$\^]/)) { isRegExp = true; } } } this._setDefaultConfig(config, isRegExp); if (config.debug) config.verbose = true; _PluginManager.default.setGlobalConfig(this._getGlobalConfig(config)); config.plugins.forEach(pluginSettings => { var _ref, _pluginSettings$optio; _PluginManager.default.registerPlugin(pluginSettings.name, (_ref = (_pluginSettings$optio = pluginSettings.options) !== null && _pluginSettings$optio !== void 0 ? _pluginSettings$optio : pluginSettings.option) !== null && _ref !== void 0 ? _ref : {}); }); _PluginManager.default.onStart(); debug('About to call PluginManager#onHandleConfig. Current config => %O', config); config = _PluginManager.default.onHandleConfig(config); debug('PluginManager#onHandleConfig finished. Config now => %O', config); var includes = []; var excludes = []; if (isRegExp) { includes = config.includes.map(v => { return new RegExp(v, 'u'); }); excludes = config.excludes.map(v => { return new RegExp(v, 'u'); }); } else { includes = config.includes; excludes = config.excludes; } var packageName = null; var mainFilePath = null; if (config.package) { try { var packageJSON = _FileManager.FileManager.readFileContents(config.package); var packageConfig = JSON.parse(packageJSON); packageName = packageConfig.name; mainFilePath = packageConfig.main; } catch (e) { // ignore } } var results = []; var asts = []; var getResults = () => { return results; }; var getAsts = () => { return asts; }; var _loop = function _loop(sourceDirectory) { var sourceDirPath = _path.default.resolve(sourceDirectory); var fileList = []; if (isRegExp) { _this._walk(sourceDirectory, filePath => { var relativeFilePath = _path.default.relative(sourceDirPath, filePath); for (var pattern of excludes) { if (relativeFilePath.match(pattern)) { return; } } for (var _pattern of includes) { if (relativeFilePath.match(_pattern)) { fileList.push(filePath); } } }); } else { fileList = _FileManager.FileManager.getListOfFiles(sourceDirectory, includes, excludes); } fileList.forEach(filePath => { var relativeFilePath = _path.default.relative(sourceDirPath, filePath); if (config.verbose) console.info("parse: ".concat(filePath)); var temp = _this._traverse(sourceDirectory, filePath, packageName, mainFilePath, config.verbose); if (!temp) return; getResults().push(...temp.results); if (config.outputAST) { getAsts().push({ filePath: "source".concat(_path.default.sep).concat(relativeFilePath), ast: temp.ast }); } }); }; for (var sourceDirectory of config.source) { _loop(sourceDirectory); } // config.index if (config.index) { results.push(this._generateForIndex(config)); } // config.package if (config.package) { results.push(this._generateForPackageJSON(config)); } results = this._resolveDuplication(results); results = _PluginManager.default.onHandleDocs(results); // index.json { var dumpPath = _path.default.resolve(config.destination, 'index.json'); _fsExtra.default.outputFileSync(dumpPath, JSON.stringify(results, null, 2)); } // ast, array will be empty if config.outputAST is false - resulting in skipping the loop for (var ast of asts) { var json = JSON.stringify(ast.ast, null, 2); var filePath = _path.default.resolve(config.destination, "ast/".concat(ast.filePath, ".json")); _fsExtra.default.outputFileSync(filePath, json); } // publish this._publish(config); _PluginManager.default.onComplete(); } /** * check ESDoc config. and if it is old, exit with warning message. * @param {ESDocConfig} config - check config * @private */ static _checkOldConfig(config) { var exit = false; var keys = [['access', 'esdoc-standard-plugin'], ['autoPrivate', 'esdoc-standard-plugin'], ['unexportedIdentifier', 'esdoc-standard-plugin'], ['undocumentIdentifier', 'esdoc-standard-plugin'], ['builtinExternal', 'esdoc-standard-plugin'], ['coverage', 'esdoc-standard-plugin'], ['test', 'esdoc-standard-plugin'], ['title', 'esdoc-standard-plugin'], ['manual', 'esdoc-standard-plugin'], ['lint', 'esdoc-standard-plugin'], ['includeSource', 'esdoc-exclude-source-plugin'], ['styles', 'esdoc-inject-style-plugin'], ['scripts', 'esdoc-inject-script-plugin'], ['experimentalProposal', 'esdoc-ecmascript-proposal-plugin']]; for (var [key, plugin] of keys) { if (key in config) { console.error("\x1B[31merror: config.".concat(key, " is invalid. Please use ").concat(plugin, ". how to migration: https://esdoc.org/manual/migration.html\x1B[0m")); exit = true; } } if (exit) process.exit(1); } /** * set default config to specified config. * @param {ESDocConfig} config - specified config. * @param {boolean} [useRegExp=false] - fallback for RegExp if config is found using it in includes/excludes. * @private */ static _setDefaultConfig(config) { var useRegExp = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; if (useRegExp) { if (!config.includes) config.includes = ['.js$']; if (!config.excludes) config.excludes = ['(config|Config).js']; } else { if (!config.includes) config.includes = ['**/*.js']; if (!config.excludes) config.excludes = ['**/*.(spec|Spec|config|Config|test|Test).js']; } if (!config.index) config.index = './README.md'; if (Object.prototype.hasOwnProperty.call(config, 'package.json')) config.package = config['package.json']; // alias if (!config.package) config.package = './package.json'; if (!('outputAST' in config)) config.outputAST = true; if (!config.plugins) config.plugins = []; if (!config.verbose) config.verbose = false; if (!config.debug) config.debug = false; } /** * Returns GlobalConfig object. * @param {ESDocConfig} config */ static _getGlobalConfig(config) { return { debug: config.debug, verbose: config.verbose, packageScopePrefix: this._getPackagePrefix(), package: config.package }; } /** * walk recursive in directory. * @param {string} dirPath - target directory path. * @param {function(entryPath: string)} callback - callback for find file. * @private */ static _walk(dirPath, callback) { var entries = _fsExtra.default.readdirSync(dirPath); for (var entry of entries) { var entryPath = _path.default.resolve(dirPath, entry); var stat = _FileManager.FileManager.getFileStat(entryPath); if (stat.isFile()) { callback(entryPath); } else if (stat.isDirectory()) { this._walk(entryPath, callback); } } } /** * traverse doc comment in JavaScript file. * @param {string} inDirPath - root directory path. * @param {string} filePath - target JavaScript file path. * @param {string} [packageName] - npm package name of target. * @param {string} [mainFilePath] - npm main file path of target. * @param {boolean} [verbose=false] - Should we print name of file to console? * @returns {Object} - return document that is traversed. * @property {DocObject[]} results - this is contained JavaScript file. * @property {AST} ast - this is AST of JavaScript file. * @private */ static _traverse(inDirPath, filePath, packageName, mainFilePath) { var verbose = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; if (verbose) { console.info("Parsing: ".concat(filePath)); } var ast = null; try { ast = _ESParser.default.parse(filePath); } catch (e) { _InvalidCodeLogger.default.showFile(filePath, e); return null; } var pathResolver = new _PathResolver.default(inDirPath, filePath, packageName, mainFilePath); var factory = new _DocFactory.default(ast, pathResolver); _ASTUtil.default.traverse(ast, (node, parent) => { try { factory.push(node, parent); } catch (e) { _InvalidCodeLogger.default.show(filePath, node); throw e; } }); return { results: factory.results, ast: ast }; } /** * generate index doc * @param {ESDocConfig} config * @returns {Tag} * @private */ static _generateForIndex(config) { var indexContent = ''; if (_fsExtra.default.existsSync(config.index)) { indexContent = _FileManager.FileManager.readFileContents(config.index); } else { console.warn("\x1B[31mwarning: ".concat(config.index, " is not found. Please check config.index.\x1B[0m")); } var tag = { kind: 'index', content: indexContent, longname: _path.default.resolve(config.index), name: config.index, static: true, access: 'public' }; return tag; } /** * generate package doc * @param {ESDocConfig} config * @returns {Tag} * @private */ static _generateForPackageJSON(config) { var packageJSON = ''; var packagePath = ''; try { packageJSON = _FileManager.FileManager.readFileContents(config.package); packagePath = _path.default.resolve(config.package); } catch (e) { // ignore } var tag = { kind: 'packageJSON', content: packageJSON, longname: packagePath, name: _path.default.basename(packagePath), static: true, access: 'public' }; return tag; } /** * resolve duplication docs * @param {Tag[]} docs * @returns {Tag[]} * @private */ static _resolveDuplication(docs) { var memberDocs = docs.filter(doc => { return doc.kind === 'member'; }); var removeIds = []; var _loop2 = function _loop2(memberDoc) { // member duplicate with getter/setter/method. // when it, remove member. // getter/setter/method are high priority. var sameLongnameDoc = docs.find(doc => { return doc.longname === memberDoc.longname && doc.kind !== 'member'; }); if (sameLongnameDoc) { removeIds.push(memberDoc.__docId__); return "continue"; } var dup = docs.filter(doc => { return doc.longname === memberDoc.longname && doc.kind === 'member'; }); if (dup.length > 1) { var ids = dup.map(v => { return v.__docId__; }); ids.sort((a, b) => { return a < b ? -1 : 1; }); ids.shift(); removeIds.push(...ids); } }; for (var memberDoc of memberDocs) { var _ret = _loop2(memberDoc); if (_ret === "continue") continue; } return docs.filter(doc => { return !removeIds.includes(doc.__docId__); }); } /** * publish content * @param {ESDocConfig} config * @private */ static _publish(config) { try { var write = (filePath, content, option) => { var _filePath = _path.default.resolve(config.destination, filePath); content = _PluginManager.default.onHandleContent(content, _filePath); if (config.verbose) console.info("output: ".concat(_filePath)); _FileManager.FileManager.writeFileContents(_filePath, content, option); }; var copy = (srcPath, destPath) => { var _destPath = _path.default.resolve(config.destination, destPath); if (config.verbose) console.info("output: ".concat(_destPath)); _FileManager.FileManager.copy(srcPath, _destPath); }; var read = filePath => { var _filePath = _path.default.resolve(config.destination, filePath); return _FileManager.FileManager.readFileContents(_filePath); }; _PluginManager.default.onPublish(write, copy, read); } catch (e) { _InvalidCodeLogger.default.showError(e); process.exit(1); } } /** * Returns prefix, or scope, of package, ie. '@enterthenamehere/esdoc' will return '@enterthenamehere'. If no prefix * is present, it will return empty string. * * Returns empty string if name of package doesn't end '/esdoc' (eg. '/esdoc-something-after') and returns * empty string if name doesn't start with '@' (eg. 'prefix/esdoc' instead of '@prefix/esdoc'). * * @return {string} prefix of package. */ static _getPackagePrefix() { try { if (ESDoc._prefix === null) { if (require.resolve('../package.json') in require.cache) { // Since require do cache of loaded modules/files, we need to reset the entry for the // file we will require in case it was already required, which would get us cached version // instead of live version. delete require.cache[require.resolve('../package.json')]; } ESDoc._prefix = require('../package.json').name; // Since require do cache of loaded modules/files, we need to reset the entry for the // file we just required, or on next time it would not load the file and instead just // fetch it from cache. delete require.cache[require.resolve('../package.json')]; if (typeof ESDoc._prefix !== 'string') { ESDoc._prefix = ''; } else { var regex = new RegExp('/esdoc$', 'u'); if (regex.test(ESDoc._prefix) && ESDoc._prefix.length > 1 && ESDoc._prefix.substr(0, 1) === '@') { var length = ESDoc._prefix.length; ESDoc._prefix = ESDoc._prefix.substr(0, length - 6); // minus /esdoc } else { ESDoc._prefix = ''; } } } } catch (err) { if (err.code === 'MODULE_NOT_FOUND') { console.error('Error: ESDoc package is missing package.json in it\'s root directory. This should not happen with correctly installed package!'); process.exit(1); } console.error('Unexpected Error occurred! ESDoc cannot continue safely.'); console.error('Try doing reinstall like `npm ci` to see if it helps with this error.'); console.error('Error', err); process.exit(1); } return ESDoc._prefix; } } exports.default = ESDoc; _defineProperty(ESDoc, "_prefix", null); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfZnNFeHRyYSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX3BhdGgiLCJfQVNUVXRpbCIsIl9Eb2NGYWN0b3J5IiwiX0VTUGFyc2VyIiwiX0ZpbGVNYW5hZ2VyIiwiX0ludmFsaWRDb2RlTG9nZ2VyIiwiX1BhdGhSZXNvbHZlciIsIl9QbHVnaW5NYW5hZ2VyIiwib2JqIiwiX19lc01vZHVsZSIsImRlZmF1bHQiLCJfZGVmaW5lUHJvcGVydHkiLCJrZXkiLCJ2YWx1ZSIsIl90b1Byb3BlcnR5S2V5IiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJlbnVtZXJhYmxlIiwiY29uZmlndXJhYmxlIiwid3JpdGFibGUiLCJhcmciLCJfdG9QcmltaXRpdmUiLCJTdHJpbmciLCJpbnB1dCIsImhpbnQiLCJwcmltIiwiU3ltYm9sIiwidG9QcmltaXRpdmUiLCJ1bmRlZmluZWQiLCJyZXMiLCJjYWxsIiwiVHlwZUVycm9yIiwiTnVtYmVyIiwiZGVidWdNb2R1bGUiLCJkZWJ1ZyIsIkVTRG9jIiwiZ2VuZXJhdGUiLCJjb25maWciLCJfdGhpcyIsIm1lc3NhZ2UiLCJjb25zb2xlIiwiZXJyb3IiLCJjb25jYXQiLCJFcnJvciIsImVuYWJsZSIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5Iiwic291cmNlIiwic291cmNlcyIsInRyaW0iLCJBcnJheSIsImlzQXJyYXkiLCJmb3JFYWNoIiwiZGVzdGluYXRpb24iLCJfY2hlY2tPbGRDb25maWciLCJpc1JlZ0V4cCIsImluY2x1ZGVzIiwibWF0Y2giLCJleGNsdWRlcyIsIl9zZXREZWZhdWx0Q29uZmlnIiwidmVyYm9zZSIsIlBsdWdpbk1hbmFnZXIiLCJzZXRHbG9iYWxDb25maWciLCJfZ2V0R2xvYmFsQ29uZmlnIiwicGx1Z2lucyIsInBsdWdpblNldHRpbmdzIiwiX3JlZiIsIl9wbHVnaW5TZXR0aW5ncyRvcHRpbyIsInJlZ2lzdGVyUGx1Z2luIiwibmFtZSIsIm9wdGlvbnMiLCJvcHRpb24iLCJvblN0YXJ0Iiwib25IYW5kbGVDb25maWciLCJtYXAiLCJ2IiwiUmVnRXhwIiwicGFja2FnZU5hbWUiLCJtYWluRmlsZVBhdGgiLCJwYWNrYWdlIiwicGFja2FnZUpTT04iLCJGaWxlTWFuYWdlciIsInJlYWRGaWxlQ29udGVudHMiLCJwYWNrYWdlQ29uZmlnIiwiSlNPTiIsInBhcnNlIiwibWFpbiIsImUiLCJyZXN1bHRzIiwiYXN0cyIsImdldFJlc3VsdHMiLCJnZXRBc3RzIiwiX2xvb3AiLCJzb3VyY2VEaXJlY3RvcnkiLCJzb3VyY2VEaXJQYXRoIiwicGF0aCIsInJlc29sdmUiLCJmaWxlTGlzdCIsIl93YWxrIiwiZmlsZVBhdGgiLCJyZWxhdGl2ZUZpbGVQYXRoIiwicmVsYXRpdmUiLCJwYXR0ZXJuIiwicHVzaCIsImdldExpc3RPZkZpbGVzIiwiaW5mbyIsInRlbXAiLCJfdHJhdmVyc2UiLCJvdXRwdXRBU1QiLCJzZXAiLCJhc3QiLCJpbmRleCIsIl9nZW5lcmF0ZUZvckluZGV4IiwiX2dlbmVyYXRlRm9yUGFja2FnZUpTT04iLCJfcmVzb2x2ZUR1cGxpY2F0aW9uIiwib25IYW5kbGVEb2NzIiwiZHVtcFBhdGgiLCJmcyIsIm91dHB1dEZpbGVTeW5jIiwic3RyaW5naWZ5IiwianNvbiIsIl9wdWJsaXNoIiwib25Db21wbGV0ZSIsImV4aXQiLCJrZXlzIiwicGx1Z2luIiwicHJvY2VzcyIsInVzZVJlZ0V4cCIsImFyZ3VtZW50cyIsImxlbmd0aCIsInBhY2thZ2VTY29wZVByZWZpeCIsIl9nZXRQYWNrYWdlUHJlZml4IiwiZGlyUGF0aCIsImNhbGxiYWNrIiwiZW50cmllcyIsInJlYWRkaXJTeW5jIiwiZW50cnkiLCJlbnRyeVBhdGgiLCJzdGF0IiwiZ2V0RmlsZVN0YXQiLCJpc0ZpbGUiLCJpc0RpcmVjdG9yeSIsImluRGlyUGF0aCIsIkVTUGFyc2VyIiwiSW52YWxpZENvZGVMb2dnZXIiLCJzaG93RmlsZSIsInBhdGhSZXNvbHZlciIsIlBhdGhSZXNvbHZlciIsImZhY3RvcnkiLCJEb2NGYWN0b3J5IiwiQVNUVXRpbCIsInRyYXZlcnNlIiwibm9kZSIsInBhcmVudCIsInNob3ciLCJpbmRleENvbnRlbnQiLCJleGlzdHNTeW5jIiwid2FybiIsInRhZyIsImtpbmQiLCJjb250ZW50IiwibG9uZ25hbWUiLCJzdGF0aWMiLCJhY2Nlc3MiLCJwYWNrYWdlUGF0aCIsImJhc2VuYW1lIiwiZG9jcyIsIm1lbWJlckRvY3MiLCJmaWx0ZXIiLCJkb2MiLCJyZW1vdmVJZHMiLCJfbG9vcDIiLCJtZW1iZXJEb2MiLCJzYW1lTG9uZ25hbWVEb2MiLCJmaW5kIiwiX19kb2NJZF9fIiwiZHVwIiwiaWRzIiwic29ydCIsImEiLCJiIiwic2hpZnQiLCJfcmV0Iiwid3JpdGUiLCJfZmlsZVBhdGgiLCJvbkhhbmRsZUNvbnRlbnQiLCJ3cml0ZUZpbGVDb250ZW50cyIsImNvcHkiLCJzcmNQYXRoIiwiZGVzdFBhdGgiLCJfZGVzdFBhdGgiLCJyZWFkIiwib25QdWJsaXNoIiwic2hvd0Vycm9yIiwiX3ByZWZpeCIsImNhY2hlIiwicmVnZXgiLCJ0ZXN0Iiwic3Vic3RyIiwiZXJyIiwiY29kZSIsImV4cG9ydHMiXSwic291cmNlcyI6WyIuLi9zcmMvRVNEb2MuanMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGZzIGZyb20gJ2ZzLWV4dHJhJztcclxuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgQVNUVXRpbCBmcm9tICdAZW50ZXJ0aGVuYW1laGVyZS9lc2RvYy9vdXQvVXRpbC9BU1RVdGlsJztcclxuaW1wb3J0IERvY0ZhY3RvcnkgZnJvbSAnQGVudGVydGhlbmFtZWhlcmUvZXNkb2Mvb3V0L0ZhY3RvcnkvRG9jRmFjdG9yeSc7XHJcbmltcG9ydCBFU1BhcnNlciBmcm9tICdAZW50ZXJ0aGVuYW1laGVyZS9lc2RvYy9vdXQvUGFyc2VyL0VTUGFyc2VyJztcclxuaW1wb3J0IHsgRmlsZU1hbmFnZXIgfSBmcm9tICdAZW50ZXJ0aGVuYW1laGVyZS9lc2RvYy9vdXQvVXRpbC9GaWxlTWFuYWdlcic7XHJcbmltcG9ydCBJbnZhbGlkQ29kZUxvZ2dlciBmcm9tICdAZW50ZXJ0aGVuYW1laGVyZS9lc2RvYy9vdXQvVXRpbC9JbnZhbGlkQ29kZUxvZ2dlcic7XHJcbmltcG9ydCBQYXRoUmVzb2x2ZXIgZnJvbSAnQGVudGVydGhlbmFtZWhlcmUvZXNkb2Mvb3V0L1V0aWwvUGF0aFJlc29sdmVyJztcclxuaW1wb3J0IFBsdWdpbk1hbmFnZXIgZnJvbSAnQGVudGVydGhlbmFtZWhlcmUvZXNkb2Mvb3V0L1BsdWdpbi9QbHVnaW5NYW5hZ2VyJztcclxuXHJcbmNvbnN0IGRlYnVnTW9kdWxlID0gcmVxdWlyZSgnZGVidWcnKTtcclxuY29uc3QgZGVidWcgPSBkZWJ1Z01vZHVsZSgnRVNEb2M6RVNEb2MnKTtcclxuXHJcbi8qKlxyXG4gKiBBUEkgRG9jdW1lbnRhdGlvbiBHZW5lcmF0b3IuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqIGxldCBjb25maWcgPSB7c291cmNlOiAnLi9zcmMnLCBkZXN0aW5hdGlvbjogJy4vZXNkb2MnfTtcclxuICogRVNEb2MuZ2VuZXJhdGUoY29uZmlnLCAocmVzdWx0cywgY29uZmlnKT0+e1xyXG4gKiAgIGNvbnNvbGUubG9nKHJlc3VsdHMpO1xyXG4gKiB9KTtcclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEVTRG9jIHtcclxuICAvKipcclxuICAgKiBHZW5lcmF0ZSBkb2N1bWVudGF0aW9uLlxyXG4gICAqIEBwYXJhbSB7RVNEb2NDb25maWd9IGNvbmZpZyAtIGNvbmZpZyBmb3IgZ2VuZXJhdGlvbi5cclxuICAgKi9cclxuICBzdGF0aWMgZ2VuZXJhdGUoY29uZmlnKSB7XHJcbiAgICBpZiggdHlwZW9mKGNvbmZpZykgPT09ICd1bmRlZmluZWQnIHx8IGNvbmZpZyA9PT0gbnVsbCApIHtcclxuICAgICAgICBjb25zdCBtZXNzYWdlID0gYFx1MDAxYlszMW1FcnJvcjogY29uZmlnIG9iamVjdCBpcyBleHBlY3RlZCBhcyBhbiBhcmd1bWVudCFcdTAwMWJbMG1gO1xyXG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYFx1MDAxYlszMW0ke21lc3NhZ2V9XHUwMDFiWzBtYCk7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKG1lc3NhZ2UpO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICBpZihjb25maWcuZGVidWcpIGRlYnVnTW9kdWxlLmVuYWJsZSgnRVNEb2M6KicpO1xyXG4gICAgZGVidWcoJ0V4ZWN1dGluZyBFU0RvYyB3aXRoIGZvbGxvd2luZyBjb25maWc6XFxuJU8nLCBjb25maWcpO1xyXG4gICAgXHJcbiAgICAvLyBMZXQncyBhbGxvdyBtdWx0aXBsZSBzb3VyY2VzIGluc3RlYWQgb2YganVzdCBvbmUgZGlyZWN0b3J5XHJcbiAgICBpZiggT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGNvbmZpZywgJ3NvdXJjZXMnKSApIHtcclxuICAgICAgY29uZmlnLnNvdXJjZSA9IGNvbmZpZy5zb3VyY2VzO1xyXG4gICAgICBkZWxldGUgY29uZmlnLnNvdXJjZXM7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIC8vIFRvIG1ha2UgaXQgZWFzaWVyLCBpZiBzb3VyY2UgaXMgYSBzaW5nbGUgZGlyZWN0b3J5LCBtYWtlIGl0IGFycmF5IGFueXdheS5cclxuICAgIGlmKCBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoY29uZmlnLCAnc291cmNlJykgKSB7XHJcbiAgICAgIGlmKCB0eXBlb2YoY29uZmlnLnNvdXJjZSkgPT09ICdzdHJpbmcnICkge1xyXG4gICAgICAgIGlmKCBjb25maWcuc291cmNlLnRyaW0oKSA9PT0gJycgKSB7XHJcbiAgICAgICAgICBjb25zdCBtZXNzYWdlID0gYFx1MDAxYlszMW1FcnJvcjogY29uZmlnLnNvdXJjZSBjYW5ub3QgYmUgZW1wdHkhIFRoaXMgaXMgYSBkaXJlY3Rvcnkgd2hlcmUgeW91IGhhdmUgeW91ciBzb3VyY2UgY29kZS5cdTAwMWJbMG1gO1xyXG4gICAgICAgICAgY29uc29sZS5lcnJvcihgXHUwMDFiWzMxbSR7bWVzc2FnZX1cdTAwMWJbMG1gKTtcclxuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihtZXNzYWdlKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgXHJcbiAgICAgICAgY29uZmlnLnNvdXJjZSA9IFtjb25maWcuc291cmNlXTtcclxuICAgICAgICBcclxuICAgICAgICAvLyBPayBub3cgd2Ugb25seSBleHBlY3QgYW4gYXJyYXksIG5vdGhpbmcgZWxzZVxyXG4gICAgICAgIGlmKCAhQXJyYXkuaXNBcnJheShjb25maWcuc291cmNlKSApIHtcclxuICAgICAgICAgIGNvbnN0IG1lc3NhZ2UgPSBgXHUwMDFiWzMxbUVycm9yOiBjb25maWcuc291cmNlIG11c3QgYmUgZWl0aGVyIGEgc3RyaW5nIG9yIGFuIGFycmF5IG9mIHN0cmluZ3MhXHUwMDFiWzBtYDtcclxuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYFx1MDAxYlszMW0ke21lc3NhZ2V9XHUwMDFiWzBtYCk7XHJcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IobWVzc2FnZSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBjb25maWcuc291cmNlLmZvckVhY2goICh2YWx1ZSkgPT4ge1xyXG4gICAgICAgICAgaWYoIHR5cGVvZih2YWx1ZSkgIT09ICdzdHJpbmcnICkge1xyXG4gICAgICAgICAgICBjb25zdCBtZXNzYWdlID0gYFx1MDAxYlszMW1FcnJvcjogY29uZmlnLnNvdXJjZSBtdXN0IGNvbnRhaW4gb25seSBzdHJpbmdzIVx1MDAxYlswbWA7XHJcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYFx1MDAxYlszMW0ke21lc3NhZ2V9XHUwMDFiWzBtYCk7XHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihtZXNzYWdlKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIGlmKCB2YWx1ZS50cmltKCkgPT09ICcnICkge1xyXG4gICAgICAgICAgICBjb25zdCBtZXNzYWdlID0gYFx1MDAxYlszMW1FcnJvcjogY29uZmlnLnNvdXJjZSBjYW5ub3QgY29udGFpbiBlbXB0eSBzdHJpbmchXHUwMDFiWzBtYDtcclxuICAgICAgICAgICAgY29uc29sZS5lcnJvcihgXHUwMDFiWzMxbSR7bWVzc2FnZX1cdTAwMWJbMG1gKTtcclxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKG1lc3NhZ2UpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgaWYoIHR5cGVvZihjb25maWcuZGVzdGluYXRpb24pICE9PSAnc3RyaW5nJyB8fCBjb25maWcuZGVzdGluYXRpb24gPT09ICcnICkge1xyXG4gICAgICAgIGNvbnN0IG1lc3NhZ2UgPSBgXHUwMDFiWzMxbUVycm9yOiBjb25maWcuZGVzdGluYXRpb24gbmVlZHMgdG8gYmUgYSBkaXJlY3Rvcnkgd2hlcmUgdG8gb3V0cHV0IGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uIVx1MDAxYlswbWA7XHJcbiAgICAgICAgY29uc29sZS5lcnJvcihgXHUwMDFiWzMxbSR7bWVzc2FnZX1cdTAwMWJbMG1gKTtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IobWVzc2FnZSk7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIHRoaXMuX2NoZWNrT2xkQ29uZmlnKGNvbmZpZyk7XHJcblxyXG4gICAgLy8gQ2hlY2sgd2hldGhlciBpbmNsdWRlcy9leGNsdWRlcyBpcyBwb3NzaWJseSByZWdleHBcclxuICAgIGxldCBpc1JlZ0V4cCA9IGZhbHNlO1xyXG4gICAgaWYoIGNvbmZpZy5pbmNsdWRlcyApIHtcclxuICAgICAgICBmb3IoIGNvbnN0IHZhbHVlIG9mIGNvbmZpZy5pbmNsdWRlcyApIHtcclxuICAgICAgICAgICAgLy9jb25zb2xlLmxvZygndmFsdWUnLCB2YWx1ZSk7XHJcbiAgICAgICAgICAgIC8vY29uc29sZS5sb2coJ3ZhbHVlJywgdmFsdWUubWF0Y2goL1skXl0vdSkpO1xyXG4gICAgICAgICAgICBpZiggdmFsdWUubWF0Y2goL1skXl0vdSkgKSB7XHJcbiAgICAgICAgICAgICAgICBpc1JlZ0V4cCA9IHRydWU7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBpZiggY29uZmlnLmV4Y2x1ZGVzICkge1xyXG4gICAgICAgIGZvciggY29uc3QgdmFsdWUgb2YgY29uZmlnLmV4Y2x1ZGVzICkge1xyXG4gICAgICAgICAgICAvL2NvbnNvbGUubG9nKCd2YWx1ZScsIHZhbHVlKTtcclxuICAgICAgICAgICAgLy9jb25zb2xlLmxvZygndmFsdWUnLCB2YWx1ZS5tYXRjaCgvWyReXS91KSk7XHJcbiAgICAgICAgICAgIGlmKCB2YWx1ZS5tYXRjaCgvWyReXS91KSApIHtcclxuICAgICAgICAgICAgICAgIGlzUmVnRXhwID0gdHJ1ZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIFxyXG4gICAgdGhpcy5fc2V0RGVmYXVsdENvbmZpZyhjb25maWcsIGlzUmVnRXhwKTtcclxuICAgIGlmKCBjb25maWcuZGVidWcgKSBjb25maWcudmVyYm9zZSA9IHRydWU7XHJcbiAgICBcclxuICAgIFBsdWdpbk1hbmFnZXIuc2V0R2xvYmFsQ29uZmlnKCB0aGlzLl9nZXRHbG9iYWxDb25maWcoY29uZmlnKSApO1xyXG4gICAgXHJcbiAgICBjb25maWcucGx1Z2lucy5mb3JFYWNoKChwbHVnaW5TZXR0aW5ncykgPT4ge1xyXG4gICAgICBQbHVnaW5NYW5hZ2VyLnJlZ2lzdGVyUGx1Z2luKHBsdWdpblNldHRpbmdzLm5hbWUsIHBsdWdpblNldHRpbmdzLm9wdGlvbnMgPz8gcGx1Z2luU2V0dGluZ3Mub3B0aW9uID8/IHt9KTtcclxuICAgIH0pO1xyXG4gICAgXHJcbiAgICBQbHVnaW5NYW5hZ2VyLm9uU3RhcnQoKTtcclxuICAgIFxyXG4gICAgZGVidWcoJ0Fib3V0IHRvIGNhbGwgUGx1Z2luTWFuYWdlciNvbkhhbmRsZUNvbmZpZy4gQ3VycmVudCBjb25maWcgPT4gJU8nLCBjb25maWcpO1xyXG4gICAgY29uZmlnID0gUGx1Z2luTWFuYWdlci5vbkhhbmRsZUNvbmZpZyhjb25maWcpO1xyXG4gICAgZGVidWcoJ1BsdWdpbk1hbmFnZXIjb25IYW5kbGVDb25maWcgZmluaXNoZWQuIENvbmZpZyBub3cgPT4gJU8nLCBjb25maWcpO1xyXG4gICAgXHJcbiAgICBsZXQgaW5jbHVkZXMgPSBbXTtcclxuICAgIGxldCBleGNsdWRlcyA9IFtdO1xyXG4gICAgaWYoIGlzUmVnRXhwICkge1xyXG4gICAgICAgIGluY2x1ZGVzID0gY29uZmlnLmluY2x1ZGVzLm1hcCgodikgPT4geyByZXR1cm4gbmV3IFJlZ0V4cCh2LCAndScpOyB9KTtcclxuICAgICAgICBleGNsdWRlcyA9IGNvbmZpZy5leGNsdWRlcy5tYXAoKHYpID0+IHsgcmV0dXJuIG5ldyBSZWdFeHAodiwgJ3UnKTsgfSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAgIGluY2x1ZGVzID0gY29uZmlnLmluY2x1ZGVzO1xyXG4gICAgICAgIGV4Y2x1ZGVzID0gY29uZmlnLmV4Y2x1ZGVzO1xyXG4gICAgfVxyXG4gICAgXHJcblxyXG4gICAgbGV0IHBhY2thZ2VOYW1lID0gbnVsbDtcclxuICAgIGxldCBtYWluRmlsZVBhdGggPSBudWxsO1xyXG4gICAgaWYgKGNvbmZpZy5wYWNrYWdlKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcGFja2FnZUpTT04gPSBGaWxlTWFuYWdlci5yZWFkRmlsZUNvbnRlbnRzKGNvbmZpZy5wYWNrYWdlKTtcclxuICAgICAgICBjb25zdCBwYWNrYWdlQ29uZmlnID0gSlNPTi5wYXJzZShwYWNrYWdlSlNPTik7XHJcbiAgICAgICAgcGFja2FnZU5hbWUgPSBwYWNrYWdlQ29uZmlnLm5hbWU7XHJcbiAgICAgICAgbWFpbkZpbGVQYXRoID0gcGFja2FnZUNvbmZpZy5tYWluO1xyXG4gICAgICB9IGNhdGNoIChlKSB7XHJcbiAgICAgICAgLy8gaWdub3JlXHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBsZXQgcmVzdWx0cyA9IFtdO1xyXG4gICAgY29uc3QgYXN0cyA9IFtdO1xyXG4gICAgXHJcbiAgICBjb25zdCBnZXRSZXN1bHRzID0gKCkgPT4ge1xyXG4gICAgICByZXR1cm4gcmVzdWx0cztcclxuICAgIH07XHJcbiAgICBcclxuICAgIGNvbnN0IGdldEFzdHMgPSAoKSA9PiB7XHJcbiAgICAgIHJldHVybiBhc3RzO1xyXG4gICAgfTtcclxuICAgIFxyXG4gICAgZm9yKGNvbnN0IHNvdXJjZURpcmVjdG9yeSBvZiBjb25maWcuc291cmNlKSB7XHJcbiAgICAgIGNvbnN0IHNvdXJjZURpclBhdGggPSBwYXRoLnJlc29sdmUoc291cmNlRGlyZWN0b3J5KTtcclxuXHJcbiAgICAgIGxldCBmaWxlTGlzdCA9IFtdO1xyXG4gICAgICBcclxuICAgICAgaWYoIGlzUmVnRXhwICkge1xyXG4gICAgICAgIHRoaXMuX3dhbGsoIHNvdXJjZURpcmVjdG9yeSwgKGZpbGVQYXRoKSA9PiB7XHJcbiAgICAgICAgICBjb25zdCByZWxhdGl2ZUZpbGVQYXRoID0gcGF0aC5yZWxhdGl2ZShzb3VyY2VEaXJQYXRoLCBmaWxlUGF0aCk7XHJcbiAgICAgICAgICBmb3IoIGNvbnN0IHBhdHRlcm4gb2YgZXhjbHVkZXMgKSB7XHJcbiAgICAgICAgICAgICAgaWYoIHJlbGF0aXZlRmlsZVBhdGgubWF0Y2gocGF0dGVybikgKSB7XHJcbiAgICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICBmb3IoIGNvbnN0IHBhdHRlcm4gb2YgaW5jbHVkZXMgKSB7XHJcbiAgICAgICAgICAgICAgaWYoIHJlbGF0aXZlRmlsZVBhdGgubWF0Y2gocGF0dGVybikgKSB7XHJcbiAgICAgICAgICAgICAgICAgIGZpbGVMaXN0LnB1c2goZmlsZVBhdGgpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBmaWxlTGlzdCA9IEZpbGVNYW5hZ2VyLmdldExpc3RPZkZpbGVzKCBzb3VyY2VEaXJlY3RvcnksIGluY2x1ZGVzLCBleGNsdWRlcyApO1xyXG4gICAgICB9XHJcbiAgICAgIFxyXG4gICAgICBmaWxlTGlzdC5mb3JFYWNoKCAoZmlsZVBhdGgpID0+IHtcclxuICAgICAgICBjb25zdCByZWxhdGl2ZUZpbGVQYXRoID0gcGF0aC5yZWxhdGl2ZShzb3VyY2VEaXJQYXRoLCBmaWxlUGF0aCk7XHJcbiAgICAgICAgXHJcbiAgICAgICAgaWYoIGNvbmZpZy52ZXJib3NlICkgY29uc29sZS5pbmZvKGBwYXJzZTogJHtmaWxlUGF0aH1gKTtcclxuICAgICAgICBjb25zdCB0ZW1wID0gdGhpcy5fdHJhdmVyc2Uoc291cmNlRGlyZWN0b3J5LCBmaWxlUGF0aCwgcGFja2FnZU5hbWUsIG1haW5GaWxlUGF0aCwgY29uZmlnLnZlcmJvc2UpO1xyXG4gICAgICAgIGlmICghdGVtcCkgcmV0dXJuO1xyXG4gICAgICAgIGdldFJlc3VsdHMoKS5wdXNoKC4uLnRlbXAucmVzdWx0cyk7XHJcbiAgICAgICAgaWYgKGNvbmZpZy5vdXRwdXRBU1QpIHtcclxuICAgICAgICAgIGdldEFzdHMoKS5wdXNoKHtmaWxlUGF0aDogYHNvdXJjZSR7cGF0aC5zZXB9JHtyZWxhdGl2ZUZpbGVQYXRofWAsIGFzdDogdGVtcC5hc3R9KTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICAvLyBjb25maWcuaW5kZXhcclxuICAgIGlmIChjb25maWcuaW5kZXgpIHtcclxuICAgICAgcmVzdWx0cy5wdXNoKHRoaXMuX2dlbmVyYXRlRm9ySW5kZXgoY29uZmlnKSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gY29uZmlnLnBhY2thZ2VcclxuICAgIGlmIChjb25maWcucGFja2FnZSkge1xyXG4gICAgICByZXN1bHRzLnB1c2godGhpcy5fZ2VuZXJhdGVGb3JQYWNrYWdlSlNPTihjb25maWcpKTtcclxuICAgIH1cclxuXHJcbiAgICByZXN1bHRzID0gdGhpcy5fcmVzb2x2ZUR1cGxpY2F0aW9uKHJlc3VsdHMpO1xyXG5cclxuICAgIHJlc3VsdHMgPSBQbHVnaW5NYW5hZ2VyLm9uSGFuZGxlRG9jcyhyZXN1bHRzKTtcclxuXHJcbiAgICAvLyBpbmRleC5qc29uXHJcbiAgICB7XHJcbiAgICAgIGNvbnN0IGR1bXBQYXRoID0gcGF0aC5yZXNvbHZlKGNvbmZpZy5kZXN0aW5hdGlvbiwgJ2luZGV4Lmpzb24nKTtcclxuICAgICAgZnMub3V0cHV0RmlsZVN5bmMoZHVtcFBhdGgsIEpTT04uc3RyaW5naWZ5KHJlc3VsdHMsIG51bGwsIDIpKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBhc3QsIGFycmF5IHdpbGwgYmUgZW1wdHkgaWYgY29uZmlnLm91dHB1dEFTVCBpcyBmYWxzZSAtIHJlc3VsdGluZyBpbiBza2lwcGluZyB0aGUgbG9vcFxyXG4gICAgZm9yIChjb25zdCBhc3Qgb2YgYXN0cykge1xyXG4gICAgICBjb25zdCBqc29uID0gSlNPTi5zdHJpbmdpZnkoYXN0LmFzdCwgbnVsbCwgMik7XHJcbiAgICAgIGNvbnN0IGZpbGVQYXRoID0gcGF0aC5yZXNvbHZlKGNvbmZpZy5kZXN0aW5hdGlvbiwgYGFzdC8ke2FzdC5maWxlUGF0aH0uanNvbmApO1xyXG4gICAgICBmcy5vdXRwdXRGaWxlU3luYyhmaWxlUGF0aCwganNvbik7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIC8vIHB1Ymxpc2hcclxuICAgIHRoaXMuX3B1Ymxpc2goY29uZmlnKTtcclxuXHJcbiAgICBQbHVnaW5NYW5hZ2VyLm9uQ29tcGxldGUoKTtcclxuICB9XHJcbiAgXHJcbiAgLyoqXHJcbiAgICogY2hlY2sgRVNEb2MgY29uZmlnLiBhbmQgaWYgaXQgaXMgb2xkLCBleGl0IHdpdGggd2FybmluZyBtZXNzYWdlLlxyXG4gICAqIEBwYXJhbSB7RVNEb2NDb25maWd9IGNvbmZpZyAtIGNoZWNrIGNvbmZpZ1xyXG4gICAqIEBwcml2YXRlXHJcbiAgICovXHJcbiAgc3RhdGljIF9jaGVja09sZENvbmZpZyhjb25maWcpIHtcclxuICAgIGxldCBleGl0ID0gZmFsc2U7XHJcblxyXG4gICAgY29uc3Qga2V5cyA9IFtcclxuICAgICAgWydhY2Nlc3MnLCAnZXNkb2Mtc3RhbmRhcmQtcGx1Z2luJ10sXHJcbiAgICAgIFsnYXV0b1ByaXZhdGUnLCAnZXNkb2Mtc3RhbmRhcmQtcGx1Z2luJ10sXHJcbiAgICAgIFsndW5leHBvcnRlZElkZW50aWZpZXInLCAnZXNkb2Mtc3RhbmRhcmQtcGx1Z2luJ10sXHJcbiAgICAgIFsndW5kb2N1bWVudElkZW50aWZpZXInLCAnZXNkb2Mtc3RhbmRhcmQtcGx1Z2luJ10sXHJcbiAgICAgIFsnYnVpbHRpbkV4dGVybmFsJywgJ2VzZG9jLXN0YW5kYXJkLXBsdWdpbiddLFxyXG4gICAgICBbJ2NvdmVyYWdlJywgJ2VzZG9jLXN0YW5kYXJkLXBsdWdpbiddLFxyXG4gICAgICBbJ3Rlc3QnLCAnZXNkb2Mtc3RhbmRhcmQtcGx1Z2luJ10sXHJcbiAgICAgIFsndGl0bGUnLCAnZXNkb2Mtc3RhbmRhcmQtcGx1Z2luJ10sXHJcbiAgICAgIFsnbWFudWFsJywgJ2VzZG9jLXN0YW5kYXJkLXBsdWdpbiddLFxyXG4gICAgICBbJ2xpbnQnLCAnZXNkb2Mtc3RhbmRhcmQtcGx1Z2luJ10sXHJcbiAgICAgIFsnaW5jbHVkZVNvdXJjZScsICdlc2RvYy1leGNsdWRlLXNvdXJjZS1wbHVnaW4nXSxcclxuICAgICAgWydzdHlsZXMnLCAnZXNkb2MtaW5qZWN0LXN0eWxlLXBsdWdpbiddLFxyXG4gICAgICBbJ3NjcmlwdHMnLCAnZXNkb2MtaW5qZWN0LXNjcmlwdC1wbHVnaW4nXSxcclxuICAgICAgWydleHBlcmltZW50YWxQcm9wb3NhbCcsICdlc2RvYy1lY21hc2NyaXB0LXByb3Bvc2FsLXBsdWdpbiddXHJcbiAgICBdO1xyXG5cclxuICAgIGZvciAoY29uc3QgW2tleSwgcGx1Z2luXSBvZiBrZXlzKSB7XHJcbiAgICAgIGlmIChrZXkgaW4gY29uZmlnKSB7XHJcbiAgICAgICAgY29uc29sZS5lcnJvcihgXHUwMDFiWzMxbWVycm9yOiBjb25maWcuJHtrZXl9IGlzIGludmFsaWQuIFBsZWFzZSB1c2UgJHtwbHVnaW59LiBob3cgdG8gbWlncmF0aW9uOiBodHRwczovL2VzZG9jLm9yZy9tYW51YWwvbWlncmF0aW9uLmh0bWxcdTAwMWJbMG1gKTtcclxuICAgICAgICBleGl0ID0gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGlmIChleGl0KSBwcm9jZXNzLmV4aXQoMSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBzZXQgZGVmYXVsdCBjb25maWcgdG8gc3BlY2lmaWVkIGNvbmZpZy5cclxuICAgKiBAcGFyYW0ge0VTRG9jQ29uZmlnfSBjb25maWcgLSBzcGVjaWZpZWQgY29uZmlnLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gICAgIFt1c2VSZWdFeHA9ZmFsc2VdIC0gZmFsbGJhY2sgZm9yIFJlZ0V4cCBpZiBjb25maWcgaXMgZm91bmQgdXNpbmcgaXQgaW4gaW5jbHVkZXMvZXhjbHVkZXMuXHJcbiAgICogQHByaXZhdGVcclxuICAgKi9cclxuICBzdGF0aWMgX3NldERlZmF1bHRDb25maWcoY29uZmlnLCB1c2VSZWdFeHAgPSBmYWxzZSkge1xyXG4gICAgaWYgKCB1c2VSZWdFeHAgKSB7XHJcbiAgICAgICAgaWYgKCFjb25maWcuaW5jbHVkZXMpIGNvbmZpZy5pbmNsdWRlcyA9IFsnLmpzJCddO1xyXG4gICAgICAgIGlmICghY29uZmlnLmV4Y2x1ZGVzKSBjb25maWcuZXhjbHVkZXMgPSBbJyhjb25maWd8Q29uZmlnKS5qcyddO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgICBpZiAoIWNvbmZpZy5pbmNsdWRlcykgY29uZmlnLmluY2x1ZGVzID0gWycqKi8qLmpzJ107XHJcbiAgICAgICAgaWYgKCFjb25maWcuZXhjbHVkZXMpIGNvbmZpZy5leGNsdWRlcyA9IFsnKiovKi4oc3BlY3xTcGVjfGNvbmZpZ3xDb25maWd8dGVzdHxUZXN0KS5qcyddO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghY29uZmlnLmluZGV4KSBjb25maWcuaW5kZXggPSAnLi9SRUFETUUubWQnO1xyXG4gICAgXHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGNvbmZpZywgJ3BhY2thZ2UuanNvbicpKSBjb25maWcucGFja2FnZSA9IGNvbmZpZ1sncGFja2FnZS5qc29uJ107IC8vIGFsaWFzXHJcbiAgICBpZiAoIWNvbmZpZy5wYWNrYWdlKSBjb25maWcucGFja2FnZSA9ICcuL3BhY2thZ2UuanNvbic7XHJcblxyXG4gICAgaWYgKCEoJ291dHB1dEFTVCcgaW4gY29uZmlnKSkgY29uZmlnLm91dHB1dEFTVCA9IHRydWU7XHJcbiAgICBcclxuICAgIGlmICghY29uZmlnLnBsdWdpbnMpIGNvbmZpZy5wbHVnaW5zID0gW107XHJcblxyXG4gICAgaWYgKCFjb25maWcudmVyYm9zZSkgY29uZmlnLnZlcmJvc2UgPSBmYWxzZTtcclxuXHJcbiAgICBpZiAoIWNvbmZpZy5kZWJ1ZykgY29uZmlnLmRlYnVnID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBSZXR1cm5zIEdsb2JhbENvbmZpZyBvYmplY3QuXHJcbiAgICogQHBhcmFtIHtFU0RvY0NvbmZpZ30gY29uZmlnXHJcbiAgICovXHJcbiAgc3RhdGljIF9nZXRHbG9iYWxDb25maWcoY29uZmlnKSB7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBkZWJ1ZzogY29uZmlnLmRlYnVnLFxyXG4gICAgICB2ZXJib3NlOiBjb25maWcudmVyYm9zZSxcclxuICAgICAgcGFja2FnZVNjb3BlUHJlZml4OiB0aGlzLl9nZXRQYWNrYWdlUHJlZml4KCksXHJcbiAgICAgIHBhY2thZ2U6IGNvbmZpZy5wYWNrYWdlXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogd2FsayByZWN1cnNpdmUgaW4gZGlyZWN0b3J5LlxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBkaXJQYXRoIC0gdGFyZ2V0IGRpcmVjdG9yeSBwYXRoLlxyXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb24oZW50cnlQYXRoOiBzdHJpbmcpfSBjYWxsYmFjayAtIGNhbGxiYWNrIGZvciBmaW5kIGZpbGUuXHJcbiAgICogQHByaXZhdGVcclxuICAgKi9cclxuICBzdGF0aWMgX3dhbGsoZGlyUGF0aCwgY2FsbGJhY2spIHtcclxuICAgIGNvbnN0IGVudHJpZXMgPSBmcy5yZWFkZGlyU3luYyhkaXJQYXRoKTtcclxuXHJcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcclxuICAgICAgY29uc3QgZW50cnlQYXRoID0gcGF0aC5yZXNvbHZlKGRpclBhdGgsIGVudHJ5KTtcclxuICAgICAgY29uc3Qgc3RhdCA9IEZpbGVNYW5hZ2VyLmdldEZpbGVTdGF0KGVudHJ5UGF0aCk7XHJcblxyXG4gICAgICBpZiAoc3RhdC5pc0ZpbGUoKSkge1xyXG4gICAgICAgIGNhbGxiYWNrKGVudHJ5UGF0aCk7XHJcbiAgICAgIH0gZWxzZSBpZiAoc3RhdC5pc0RpcmVjdG9yeSgpKSB7XHJcbiAgICAgICAgdGhpcy5fd2FsayhlbnRyeVBhdGgsIGNhbGxiYWNrKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogdHJhdmVyc2UgZG9jIGNvbW1lbnQgaW4gSmF2YVNjcmlwdCBmaWxlLlxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbkRpclBhdGggLSByb290IGRpcmVjdG9yeSBwYXRoLlxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlUGF0aCAtIHRhcmdldCBKYXZhU2NyaXB0IGZpbGUgcGF0aC5cclxuICAgKiBAcGFyYW0ge3N0cmluZ30gW3BhY2thZ2VOYW1lXSAtIG5wbSBwYWNrYWdlIG5hbWUgb2YgdGFyZ2V0LlxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbbWFpbkZpbGVQYXRoXSAtIG5wbSBtYWluIGZpbGUgcGF0aCBvZiB0YXJnZXQuXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBbdmVyYm9zZT1mYWxzZV0gLSBTaG91bGQgd2UgcHJpbnQgbmFtZSBvZiBmaWxlIHRvIGNvbnNvbGU/XHJcbiAgICogQHJldHVybnMge09iamVjdH0gLSByZXR1cm4gZG9jdW1lbnQgdGhhdCBpcyB0cmF2ZXJzZWQuXHJcbiAgICogQHByb3BlcnR5IHtEb2NPYmplY3RbXX0gcmVzdWx0cyAtIHRoaXMgaXMgY29udGFpbmVkIEphdmFTY3JpcHQgZmlsZS5cclxuICAgKiBAcHJvcGVydHkge0FTVH0gYXN0IC0gdGhpcyBpcyBBU1Qgb2YgSmF2YVNjcmlwdCBmaWxlLlxyXG4gICAqIEBwcml2YXRlXHJcbiAgICovXHJcbiAgc3RhdGljIF90cmF2ZXJzZShpbkRpclBhdGgsIGZpbGVQYXRoLCBwYWNrYWdlTmFtZSwgbWFpbkZpbGVQYXRoLCB2ZXJib3NlID0gZmFsc2UpIHtcclxuICAgIGlmKHZlcmJvc2UpIHtcclxuICAgICAgY29uc29sZS5pbmZvKGBQYXJzaW5nOiAke2ZpbGVQYXRofWApO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICBsZXQgYXN0ID0gbnVsbDtcclxuICAgIHRyeSB7XHJcbiAgICAgIGFzdCA9IEVTUGFyc2VyLnBhcnNlKGZpbGVQYXRoKTtcclxuICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgSW52YWxpZENvZGVMb2dnZXIuc2hvd0ZpbGUoZmlsZVBhdGgsIGUpO1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBwYXRoUmVzb2x2ZXIgPSBuZXcgUGF0aFJlc29sdmVyKGluRGlyUGF0aCwgZmlsZVBhdGgsIHBhY2thZ2VOYW1lLCBtYWluRmlsZVBhdGgpO1xyXG4gICAgY29uc3QgZmFjdG9yeSA9IG5ldyBEb2NGYWN0b3J5KGFzdCwgcGF0aFJlc29sdmVyKTtcclxuXHJcbiAgICBBU1RVdGlsLnRyYXZlcnNlKGFzdCwgKG5vZGUsIHBhcmVudCkgPT4ge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGZhY3RvcnkucHVzaChub2RlLCBwYXJlbnQpO1xyXG4gICAgICB9IGNhdGNoIChlKSB7XHJcbiAgICAgICAgSW52YWxpZENvZGVMb2dnZXIuc2hvdyhmaWxlUGF0aCwgbm9kZSk7XHJcbiAgICAgICAgdGhyb3cgZTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHtyZXN1bHRzOiBmYWN0b3J5LnJlc3VsdHMsIGFzdDogYXN0fTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIGdlbmVyYXRlIGluZGV4IGRvY1xyXG4gICAqIEBwYXJhbSB7RVNEb2NDb25maWd9IGNvbmZpZ1xyXG4gICAqIEByZXR1cm5zIHtUYWd9XHJcbiAgICogQHByaXZhdGVcclxuICAgKi9cclxuICBzdGF0aWMgX2dlbmVyYXRlRm9ySW5kZXgoY29uZmlnKSB7XHJcbiAgICBsZXQgaW5kZXhDb250ZW50ID0gJyc7XHJcblxyXG4gICAgaWYgKGZzLmV4aXN0c1N5bmMoY29uZmlnLmluZGV4KSkge1xyXG4gICAgICBpbmRleENvbnRlbnQgPSBGaWxlTWFuYWdlci5yZWFkRmlsZUNvbnRlbnRzKGNvbmZpZy5pbmRleCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjb25zb2xlLndhcm4oYFx1MDAxYlszMW13YXJuaW5nOiAke2NvbmZpZy5pbmRleH0gaXMgbm90IGZvdW5kLiBQbGVhc2UgY2hlY2sgY29uZmlnLmluZGV4Llx1MDAxYlswbWApO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHRhZyA9IHtcclxuICAgICAga2luZDogJ2luZGV4JyxcclxuICAgICAgY29udGVudDogaW5kZXhDb250ZW50LFxyXG4gICAgICBsb25nbmFtZTogcGF0aC5yZXNvbHZlKGNvbmZpZy5pbmRleCksXHJcbiAgICAgIG5hbWU6IGNvbmZpZy5pbmRleCxcclxuICAgICAgc3RhdGljOiB0cnVlLFxyXG4gICAgICBhY2Nlc3M6ICdwdWJsaWMnXHJcbiAgICB9O1xyXG5cclxuICAgIHJldHVybiB0YWc7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBnZW5lcmF0ZSBwYWNrYWdlIGRvY1xyXG4gICAqIEBwYXJhbSB7RVNEb2NDb25maWd9IGNvbmZpZ1xyXG4gICAqIEByZXR1cm5zIHtUYWd9XHJcbiAgICogQHByaXZhdGVcclxuICAgKi9cclxuICBzdGF0aWMgX2dlbmVyYXRlRm9yUGFja2FnZUpTT04oY29uZmlnKSB7XHJcbiAgICBsZXQgcGFja2FnZUpTT04gPSAnJztcclxuICAgIGxldCBwYWNrYWdlUGF0aCA9ICcnO1xyXG4gICAgdHJ5IHtcclxuICAgICAgcGFja2FnZUpTT04gPSBGaWxlTWFuYWdlci5yZWFkRmlsZUNvbnRlbnRzKGNvbmZpZy5wYWNrYWdlKTtcclxuICAgICAgcGFja2FnZVBhdGggPSBwYXRoLnJlc29sdmUoY29uZmlnLnBhY2thZ2UpO1xyXG4gICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICAvLyBpZ25vcmVcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB0YWcgPSB7XHJcbiAgICAgIGtpbmQ6ICdwYWNrYWdlSlNPTicsXHJcbiAgICAgIGNvbnRlbnQ6IHBhY2thZ2VKU09OLFxyXG4gICAgICBsb25nbmFtZTogcGFja2FnZVBhdGgsXHJcbiAgICAgIG5hbWU6IHBhdGguYmFzZW5hbWUocGFja2FnZVBhdGgpLFxyXG4gICAgICBzdGF0aWM6IHRydWUsXHJcbiAgICAgIGFjY2VzczogJ3B1YmxpYydcclxuICAgIH07XHJcblxyXG4gICAgcmV0dXJuIHRhZztcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIHJlc29sdmUgZHVwbGljYXRpb24gZG9jc1xyXG4gICAqIEBwYXJhbSB7VGFnW119IGRvY3NcclxuICAgKiBAcmV0dXJucyB7VGFnW119XHJcbiAgICogQHByaXZhdGVcclxuICAgKi9cclxuICBzdGF0aWMgX3Jlc29sdmVEdXBsaWNhdGlvbihkb2NzKSB7XHJcbiAgICBjb25zdCBtZW1iZXJEb2NzID0gZG9jcy5maWx0ZXIoKGRvYykgPT4geyByZXR1cm4gZG9jLmtpbmQgPT09ICdtZW1iZXInOyB9KTtcclxuICAgIGNvbnN0IHJlbW92ZUlkcyA9IFtdO1xyXG5cclxuICAgIGZvciAoY29uc3QgbWVtYmVyRG9jIG9mIG1lbWJlckRvY3MpIHtcclxuICAgICAgLy8gbWVtYmVyIGR1cGxpY2F0ZSB3aXRoIGdldHRlci9zZXR0ZXIvbWV0aG9kLlxyXG4gICAgICAvLyB3aGVuIGl0LCByZW1vdmUgbWVtYmVyLlxyXG4gICAgICAvLyBnZXR0ZXIvc2V0dGVyL21ldGhvZCBhcmUgaGlnaCBwcmlvcml0eS5cclxuICAgICAgY29uc3Qgc2FtZUxvbmduYW1lRG9jID0gZG9jcy5maW5kKChkb2MpID0+IHsgcmV0dXJuIGRvYy5sb25nbmFtZSA9PT0gbWVtYmVyRG9jLmxvbmduYW1lICYmIGRvYy5raW5kICE9PSAnbWVtYmVyJzsgfSk7XHJcbiAgICAgIGlmIChzYW1lTG9uZ25hbWVEb2MpIHtcclxuICAgICAgICByZW1vdmVJZHMucHVzaChtZW1iZXJEb2MuX19kb2NJZF9fKTtcclxuICAgICAgICBjb250aW51ZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgY29uc3QgZHVwID0gZG9jcy5maWx0ZXIoKGRvYykgPT4geyByZXR1cm4gZG9jLmxvbmduYW1lID09PSBtZW1iZXJEb2MubG9uZ25hbWUgJiYgZG9jLmtpbmQgPT09ICdtZW1iZXInOyB9KTtcclxuICAgICAgaWYgKGR1cC5sZW5ndGggPiAxKSB7XHJcbiAgICAgICAgY29uc3QgaWRzID0gZHVwLm1hcCgodikgPT4geyByZXR1cm4gdi5fX2RvY0lkX187IH0pO1xyXG4gICAgICAgIGlkcy5zb3J0KChhLCBiKSA9PiB7XHJcbiAgICAgICAgICByZXR1cm4gYSA8IGIgPyAtMSA6IDE7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgaWRzLnNoaWZ0KCk7XHJcbiAgICAgICAgcmVtb3ZlSWRzLnB1c2goLi4uaWRzKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBkb2NzLmZpbHRlcigoZG9jKSA9PiB7IHJldHVybiAhcmVtb3ZlSWRzLmluY2x1ZGVzKGRvYy5fX2RvY0lkX18pOyB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIHB1Ymxpc2ggY29udGVudFxyXG4gICAqIEBwYXJhbSB7RVNEb2NDb25maWd9IGNvbmZpZ1xyXG4gICAqIEBwcml2YXRlXHJcbiAgICovXHJcbiAgc3RhdGljIF9wdWJsaXNoKGNvbmZpZykge1xyXG4gICAgdHJ5IHtcclxuICAgICAgY29uc3Qgd3JpdGUgPSAoZmlsZVBhdGgsIGNvbnRlbnQsIG9wdGlvbikgPT4ge1xyXG4gICAgICAgIGNvbnN0IF9maWxlUGF0aCA9IHBhdGgucmVzb2x2ZShjb25maWcuZGVzdGluYXRpb24sIGZpbGVQYXRoKTtcclxuICAgICAgICBjb250ZW50ID0gUGx1Z2luTWFuYWdlci5vbkhhbmRsZUNvbnRlbnQoY29udGVudCwgX2ZpbGVQYXRoKTtcclxuXHJcbiAgICAgICAgaWYoIGNvbmZpZy52ZXJib3NlICkgY29uc29sZS5pbmZvKGBvdXRwdXQ6ICR7X2ZpbGVQYXRofWApO1xyXG4gICAgICAgIEZpbGVNYW5hZ2VyLndyaXRlRmlsZUNvbnRlbnRzKF9maWxlUGF0aCwgY29udGVudCwgb3B0aW9uKTtcclxuICAgICAgfTtcclxuXHJcbiAgICAgIGNvbnN0IGNvcHkgPSAoc3JjUGF0aCwgZGVzdFBhdGgpID0+IHtcclxuICAgICAgICBjb25zdCBfZGVzdFBhdGggPSBwYXRoLnJlc29sdmUoY29uZmlnLmRlc3RpbmF0aW9uLCBkZXN0UGF0aCk7XHJcbiAgICAgICAgaWYoIGNvbmZpZy52ZXJib3NlICkgY29uc29sZS5pbmZvKGBvdXRwdXQ6ICR7X2Rlc3RQYXRofWApO1xyXG4gICAgICAgIEZpbGVNYW5hZ2VyLmNvcHkoc3JjUGF0aCwgX2Rlc3RQYXRoKTtcclxuICAgICAgfTtcclxuXHJcbiAgICAgIGNvbnN0IHJlYWQgPSAoZmlsZVBhdGgpID0+IHtcclxuICAgICAgICBjb25zdCBfZmlsZVBhdGggPSBwYXRoLnJlc29sdmUoY29uZmlnLmRlc3RpbmF0aW9uLCBmaWxlUGF0aCk7XHJcbiAgICAgICAgcmV0dXJuIEZpbGVNYW5hZ2VyLnJlYWRGaWxlQ29udGVudHMoX2ZpbGVQYXRoKTtcclxuICAgICAgfTtcclxuXHJcbiAgICAgIFBsdWdpbk1hbmFnZXIub25QdWJsaXNoKHdyaXRlLCBjb3B5LCByZWFkKTtcclxuICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgSW52YWxpZENvZGVMb2dnZXIuc2hvd0Vycm9yKGUpO1xyXG4gICAgICBwcm9jZXNzLmV4aXQoMSk7XHJcbiAgICB9XHJcbiAgfVxyXG4gIFxyXG4gIHN0YXRpYyBfcHJlZml4ID0gbnVsbDtcclxuICBcclxuICAvKipcclxuICAgKiBSZXR1cm5zIHByZWZpeCwgb3Igc2NvcGUsIG9mIHBhY2thZ2UsIGllLiAnQGVudGVydGhlbmFtZWhlcmUvZXNkb2MnIHdpbGwgcmV0dXJuICdAZW50ZXJ0aGVuYW1laGVyZScuIElmIG5vIHByZWZpeFxyXG4gICAqIGlzIHByZXNlbnQsIGl0IHdpbGwgcmV0dXJuIGVtcHR5IHN0cmluZy5cclxuICAgKlxyXG4gICAqIFJldHVybnMgZW1wdHkgc3RyaW5nIGlmIG5hbWUgb2YgcGFja2FnZSBkb2Vzbid0IGVuZCAnL2VzZG9jJyAoZWcuICcvZXNkb2Mtc29tZXRoaW5nLWFmdGVyJykgYW5kIHJldHVybnNcclxuICAgKiBlbXB0eSBzdHJpbmcgaWYgbmFtZSBkb2Vzbid0IHN0YXJ0IHdpdGggJ0AnIChlZy4gJ3ByZWZpeC9lc2RvYycgaW5zdGVhZCBvZiAnQHByZWZpeC9lc2RvYycpLlxyXG4gICAqXHJcbiAgICogQHJldHVybiB7c3RyaW5nfSBwcmVmaXggb2YgcGFja2FnZS5cclxuICAgKi9cclxuICBzdGF0aWMgX2dldFBhY2thZ2VQcmVmaXgoKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBpZiggRVNEb2MuX3ByZWZpeCA9PT0gbnVsbCApIHtcclxuICAgICAgICBpZiggcmVxdWlyZS5yZXNvbHZlKCcuLi9wYWNrYWdlLmpzb24nKSBpbiByZXF1aXJlLmNhY2hlICkge1xyXG4gICAgICAgICAgICAvLyBTaW5jZSByZXF1aXJlIGRvIGNhY2hlIG9mIGxvYWRlZCBtb2R1bGVzL2ZpbGVzLCB3ZSBuZWVkIHRvIHJlc2V0IHRoZSBlbnRyeSBmb3IgdGhlXHJcbiAgICAgICAgICAgIC8vIGZpbGUgd2Ugd2lsbCByZXF1aXJlIGluIGNhc2UgaXQgd2FzIGFscmVhZHkgcmVxdWlyZWQsIHdoaWNoIHdvdWxkIGdldCB1cyBjYWNoZWQgdmVyc2lvblxyXG4gICAgICAgICAgICAvLyBpbnN0ZWFkIG9mIGxpdmUgdmVyc2lvbi5cclxuICAgICAgICAgICAgZGVsZXRlIHJlcXVpcmUuY2FjaGVbcmVxdWlyZS5yZXNvbHZlKCcuLi9wYWNrYWdlLmpzb24nKV07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIEVTRG9jLl9wcmVmaXggPSByZXF1aXJlKCcuLi9wYWNrYWdlLmpzb24nKS5uYW1lO1xyXG4gICAgICAgIC8vIFNpbmNlIHJlcXVpcmUgZG8gY2FjaGUgb2YgbG9hZGVkIG1vZHVsZXMvZmlsZXMsIHdlIG5lZWQgdG8gcmVzZXQgdGhlIGVudHJ5IGZvciB0aGVcclxuICAgICAgICAvLyBmaWxlIHdlIGp1c3QgcmVxdWlyZWQsIG9yIG9uIG5leHQgdGltZSBpdCB3b3VsZCBub3QgbG9hZCB0aGUgZmlsZSBhbmQgaW5zdGVhZCBqdXN0XHJcbiAgICAgICAgLy8gZmV0Y2ggaXQgZnJvbSBjYWNoZS5cclxuICAgICAgICBkZWxldGUgcmVxdWlyZS5jYWNoZVtyZXF1aXJlLnJlc29sdmUoJy4uL3BhY2thZ2UuanNvbicpXTtcclxuICAgICAgICBpZiggdHlwZW9mKEVTRG9jLl9wcmVmaXgpICE9PSAnc3RyaW5nJyApIHtcclxuICAgICAgICAgICAgRVNEb2MuX3ByZWZpeCA9ICcnO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGNvbnN0IHJlZ2V4ID0gbmV3IFJlZ0V4cCgnL2VzZG9jJCcsICd1Jyk7XHJcbiAgICAgICAgICAgIGlmKCByZWdleC50ZXN0KEVTRG9jLl9wcmVmaXgpICYmIEVTRG9jLl9wcmVmaXgubGVuZ3RoID4gMSAmJiBFU0RvYy5fcHJlZml4LnN1YnN0cigwLDEpID09PSAnQCcgKSB7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBsZW5ndGggPSBFU0RvYy5fcHJlZml4Lmxlbmd0aDtcclxuICAgICAgICAgICAgICAgIEVTRG9jLl9wcmVmaXggPSBFU0RvYy5fcHJlZml4LnN1YnN0cigwLCBsZW5ndGggLSA2KTsgLy8gbWludXMgL2VzZG9jXHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICBFU0RvYy5fcHJlZml4ID0gJyc7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2goIGVyciApIHtcclxuICAgICAgaWYoIGVyci5jb2RlID09PSAnTU9EVUxFX05PVF9GT1VORCcgKSB7XHJcbiAgICAgICAgY29uc29sZS5lcnJvcignRXJyb3I6IEVTRG9jIHBhY2thZ2UgaXMgbWlzc2luZyBwYWNrYWdlLmpzb24gaW4gaXRcXCdzIHJvb3QgZGlyZWN0b3J5LiBUaGlzIHNob3VsZCBub3QgaGFwcGVuIHdpdGggY29ycmVjdGx5IGluc3RhbGxlZCBwYWNrYWdlIScpO1xyXG4gICAgICAgIHByb2Nlc3MuZXhpdCgxKTtcclxuICAgICAgfVxyXG4gICAgICBjb25zb2xlLmVycm9yKCAnVW5leHBlY3RlZCBFcnJvciBvY2N1cnJlZCEgRVNEb2MgY2Fubm90IGNvbnRpbnVlIHNhZmVseS4nKTtcclxuICAgICAgY29uc29sZS5lcnJvciggJ1RyeSBkb2luZyByZWluc3RhbGwgbGlrZSBgbnBtIGNpYCB0byBzZWUgaWYgaXQgaGVscHMgd2l0aCB0aGlzIGVycm9yLicgKTtcclxuICAgICAgY29uc29sZS5lcnJvciggJ0Vycm9yJywgZXJyICk7XHJcbiAgICAgIHByb2Nlc3MuZXhpdCgxKTtcclxuICAgIH1cclxuICAgICAgXHJcbiAgICByZXR1cm4gRVNEb2MuX3ByZWZpeDtcclxuICB9XHJcbn1cclxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxJQUFBQSxRQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxLQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7QUFFQSxJQUFBRSxRQUFBLEdBQUFILHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRyxXQUFBLEdBQUFKLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBSSxTQUFBLEdBQUFMLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBSyxZQUFBLEdBQUFMLE9BQUE7QUFDQSxJQUFBTSxrQkFBQSxHQUFBUCxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQU8sYUFBQSxHQUFBUixzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQVEsY0FBQSxHQUFBVCxzQkFBQSxDQUFBQyxPQUFBO0FBQTZFLFNBQUFELHVCQUFBVSxHQUFBLFdBQUFBLEdBQUEsSUFBQUEsR0FBQSxDQUFBQyxVQUFBLEdBQUFELEdBQUEsS0FBQUUsT0FBQSxFQUFBRixHQUFBO0FBQUEsU0FBQUcsZ0JBQUFILEdBQUEsRUFBQUksR0FBQSxFQUFBQyxLQUFBLElBQUFELEdBQUEsR0FBQUUsY0FBQSxDQUFBRixHQUFBLE9BQUFBLEdBQUEsSUFBQUosR0FBQSxJQUFBTyxNQUFBLENBQUFDLGNBQUEsQ0FBQVIsR0FBQSxFQUFBSSxHQUFBLElBQUFDLEtBQUEsRUFBQUEsS0FBQSxFQUFBSSxVQUFBLFFBQUFDLFlBQUEsUUFBQUMsUUFBQSxvQkFBQVgsR0FBQSxDQUFBSSxHQUFBLElBQUFDLEtBQUEsV0FBQUwsR0FBQTtBQUFBLFNBQUFNLGVBQUFNLEdBQUEsUUFBQVIsR0FBQSxHQUFBUyxZQUFBLENBQUFELEdBQUEsMkJBQUFSLEdBQUEsZ0JBQUFBLEdBQUEsR0FBQVUsTUFBQSxDQUFBVixHQUFBO0FBQUEsU0FBQVMsYUFBQUUsS0FBQSxFQUFBQyxJQUFBLGVBQUFELEtBQUEsaUJBQUFBLEtBQUEsa0JBQUFBLEtBQUEsTUFBQUUsSUFBQSxHQUFBRixLQUFBLENBQUFHLE1BQUEsQ0FBQUMsV0FBQSxPQUFBRixJQUFBLEtBQUFHLFNBQUEsUUFBQUMsR0FBQSxHQUFBSixJQUFBLENBQUFLLElBQUEsQ0FBQVAsS0FBQSxFQUFBQyxJQUFBLDJCQUFBSyxHQUFBLHNCQUFBQSxHQUFBLFlBQUFFLFNBQUEsNERBQUFQLElBQUEsZ0JBQUFGLE1BQUEsR0FBQVUsTUFBQSxFQUFBVCxLQUFBO0FBRTdFLElBQU1VLFdBQVcsR0FBR2xDLE9BQU8sQ0FBQyx