@enterthenamehere/esdoc
Version:
Good Documentation Generator For JavaScript, updated for new decade
508 lines (488 loc) • 69.5 kB
JavaScript
"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