@sharekey/meteor-desktop
Version:
Build a Meteor's desktop client with hot code push.
231 lines (216 loc) • 27 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _runtime = _interopRequireDefault(require("regenerator-runtime/runtime"));
var _shelljs = _interopRequireDefault(require("shelljs"));
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _log = _interopRequireDefault(require("./log"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// eslint-disable-next-line no-unused-vars
_shelljs.default.config.fatal = true;
/**
* Checks if the path is empty.
* @param {string} searchPath
* @returns {boolean}
*/
function isEmptySync(searchPath) {
let stat;
try {
stat = _fs.default.statSync(searchPath);
} catch (e) {
return true;
}
if (stat.isDirectory()) {
const items = _fs.default.readdirSync(searchPath);
return !items || !items.length;
}
return false;
}
/**
* Represents the .desktop directory.
* @class
* @property {desktopSettings} settings
*/
class Desktop {
/**
* @param {MeteorDesktop} $ - context
*
* @constructor
*/
constructor($) {
this.$ = $;
this.log = new _log.default('desktop');
this.settings = null;
this.dependencies = null;
}
/**
* Tries to read and returns settings.json contents from .desktop dir.
*
* @returns {desktopSettings|null}
*/
getSettings() {
if (!this.settings) {
try {
this.settings = JSON.parse(_fs.default.readFileSync(this.$.env.paths.desktop.settings, 'UTF-8'));
} catch (e) {
this.log.error('error while trying to read \'.desktop/settings.json\': ', e);
process.exit(1);
}
}
return this.settings;
}
/**
* Returns a version hash representing current .desktop contents.
* @returns {string}
*/
async getHashVersion() {
this.log.info('calculating hash version from .desktop contents');
const version = await this.$.utils.readFilesAndComputeHash(this.$.env.paths.desktop.root);
this.log.verbose(`calculated .desktop hash version is ${version.hash}`);
return version.hash;
}
/**
* Tries to read a module.json file from a module at provided path.
*
* @param {string} modulePath - path to the module dir
* @returns {Object}
*/
getModuleConfig(modulePath) {
let moduleConfig = {};
try {
moduleConfig = JSON.parse(_fs.default.readFileSync(_path.default.join(modulePath, 'module.json'), 'UTF-8'));
} catch (e) {
this.log.error(`error while trying to read 'module.json' from '${modulePath}' module: `, e);
process.exit(1);
}
if (!('name' in moduleConfig)) {
this.log.error(`no 'name' field defined in 'module.json' in '${modulePath}' module.`);
process.exit(1);
}
return moduleConfig;
}
/**
* Scans all modules for module.json and gathers this configuration altogether.
*
* @returns {[]}
*/
gatherModuleConfigs() {
const configs = [];
if (!isEmptySync(this.$.env.paths.desktop.modules)) {
_shelljs.default.ls('-d', _path.default.join(this.$.env.paths.desktop.modules, '*')).forEach(module => {
if (_fs.default.lstatSync(module).isDirectory()) {
const moduleConfig = this.getModuleConfig(module);
moduleConfig.dirName = _path.default.parse(module).name;
configs.push(moduleConfig);
}
});
}
return configs;
}
/**
* Summarizes all dependencies defined in .desktop.
*
* @params {Object} settings - settings.json
* @params {boolean} checkModules - whether to gather modules dependencies
* @params {boolean} refresh - recompute
* @returns {{fromSettings: {}, plugins: {}, modules: {}}}
*/
getDependencies(settings = null, checkModules = true, refresh = false) {
if (!refresh && this.dependencies) {
return this.dependencies;
}
const dependencies = {
fromSettings: {},
plugins: {},
modules: {}
};
/** @type {desktopSettings} * */
const settingsJson = settings || this.getSettings();
// Settings can have a 'dependencies' field.
if ('dependencies' in settingsJson) {
dependencies.fromSettings = settingsJson.dependencies;
}
// Plugins are also a npm packages.
if ('plugins' in settingsJson) {
dependencies.plugins = Object.keys(settingsJson.plugins).reduce((plugins, plugin) => {
/* eslint-disable no-param-reassign */
if (typeof settingsJson.plugins[plugin] === 'object') {
plugins[plugin] = settingsJson.plugins[plugin].version;
} else {
plugins[plugin] = settingsJson.plugins[plugin];
}
return plugins;
}, {});
}
// Each module can have its own dependencies defined.
const moduleDependencies = {};
if (checkModules) {
const configs = this.gatherModuleConfigs();
configs.forEach(moduleConfig => {
if (!('dependencies' in moduleConfig)) {
moduleConfig.dependencies = {};
}
if (moduleConfig.name in moduleDependencies) {
this.log.error(`duplicate name '${moduleConfig.name}' in 'module.json' in ` + `'${moduleConfig.dirName}' - another module already registered the same name.`);
process.exit(1);
}
moduleDependencies[moduleConfig.name] = moduleConfig.dependencies;
});
}
dependencies.modules = moduleDependencies;
this.dependencies = dependencies;
return dependencies;
}
/**
* Copies the .desktop scaffold into the meteor app dir.
* Adds entry to .meteor/.gitignore.
*/
scaffold() {
this.log.info('creating .desktop scaffold in your project');
if (this.$.utils.exists(this.$.env.paths.desktop.root)) {
this.log.warn('.desktop already exists - delete it if you want a new one to be ' + 'created');
return;
}
_shelljs.default.cp('-r', this.$.env.paths.scaffold, this.$.env.paths.desktop.root);
_shelljs.default.mkdir(this.$.env.paths.desktop.import);
this.log.info('.desktop directory prepared');
}
/**
* Verifies if all mandatory files are present in the .desktop.
*
* @returns {boolean}
*/
check() {
this.log.verbose('checking .desktop existence');
return !!(this.$.utils.exists(this.$.env.paths.desktop.root) && this.$.utils.exists(this.$.env.paths.desktop.settings) && this.$.utils.exists(this.$.env.paths.desktop.desktop));
}
}
/**
* @typedef {Object} desktopSettings
* @property {string} name
* @property {string} projectName
* @property {boolean} devTools
* @property {boolean} devtron
* @property {boolean} desktopHCP
* @property {Object} desktopHCPSettings
* @property {boolean} desktopHCPSettings.ignoreCompatibilityVersion
* @property {boolean} desktopHCPSettings.blockAppUpdateOnDesktopIncompatibility
* @property {number} webAppStartupTimeout
* @property {Array} linkPackages
* @property {Array} exposedModules
* @property {Object} window
* @property {Object} windowDev
* @property {Object} packageJsonFields
* @property {Object} builderOptions
* @property {Object} builderCliOptions
* @property {Object} packagerOptions
* @property {Object} plugins
* @property {Object} dependencies
* @property {boolean} uglify
* @property {string} version
* */
exports.default = Desktop;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcnVudGltZSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX3NoZWxsanMiLCJfZnMiLCJfcGF0aCIsIl9sb2ciLCJvYmoiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsInNoZWxsIiwiY29uZmlnIiwiZmF0YWwiLCJpc0VtcHR5U3luYyIsInNlYXJjaFBhdGgiLCJzdGF0IiwiZnMiLCJzdGF0U3luYyIsImUiLCJpc0RpcmVjdG9yeSIsIml0ZW1zIiwicmVhZGRpclN5bmMiLCJsZW5ndGgiLCJEZXNrdG9wIiwiY29uc3RydWN0b3IiLCIkIiwibG9nIiwiTG9nIiwic2V0dGluZ3MiLCJkZXBlbmRlbmNpZXMiLCJnZXRTZXR0aW5ncyIsIkpTT04iLCJwYXJzZSIsInJlYWRGaWxlU3luYyIsImVudiIsInBhdGhzIiwiZGVza3RvcCIsImVycm9yIiwicHJvY2VzcyIsImV4aXQiLCJnZXRIYXNoVmVyc2lvbiIsImluZm8iLCJ2ZXJzaW9uIiwidXRpbHMiLCJyZWFkRmlsZXNBbmRDb21wdXRlSGFzaCIsInJvb3QiLCJ2ZXJib3NlIiwiaGFzaCIsImdldE1vZHVsZUNvbmZpZyIsIm1vZHVsZVBhdGgiLCJtb2R1bGVDb25maWciLCJwYXRoIiwiam9pbiIsImdhdGhlck1vZHVsZUNvbmZpZ3MiLCJjb25maWdzIiwibW9kdWxlcyIsImxzIiwiZm9yRWFjaCIsIm1vZHVsZSIsImxzdGF0U3luYyIsImRpck5hbWUiLCJuYW1lIiwicHVzaCIsImdldERlcGVuZGVuY2llcyIsImNoZWNrTW9kdWxlcyIsInJlZnJlc2giLCJmcm9tU2V0dGluZ3MiLCJwbHVnaW5zIiwic2V0dGluZ3NKc29uIiwiT2JqZWN0Iiwia2V5cyIsInJlZHVjZSIsInBsdWdpbiIsIm1vZHVsZURlcGVuZGVuY2llcyIsInNjYWZmb2xkIiwiZXhpc3RzIiwid2FybiIsImNwIiwibWtkaXIiLCJpbXBvcnQiLCJjaGVjayIsImV4cG9ydHMiXSwic291cmNlcyI6WyIuLi9saWIvZGVza3RvcC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW51c2VkLXZhcnNcbmltcG9ydCByZWdlbmVyYXRvclJ1bnRpbWUgZnJvbSAncmVnZW5lcmF0b3ItcnVudGltZS9ydW50aW1lJztcbmltcG9ydCBzaGVsbCBmcm9tICdzaGVsbGpzJztcbmltcG9ydCBmcyBmcm9tICdmcyc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcblxuaW1wb3J0IExvZyBmcm9tICcuL2xvZyc7XG5cbnNoZWxsLmNvbmZpZy5mYXRhbCA9IHRydWU7XG5cbi8qKlxuICogQ2hlY2tzIGlmIHRoZSBwYXRoIGlzIGVtcHR5LlxuICogQHBhcmFtIHtzdHJpbmd9IHNlYXJjaFBhdGhcbiAqIEByZXR1cm5zIHtib29sZWFufVxuICovXG5mdW5jdGlvbiBpc0VtcHR5U3luYyhzZWFyY2hQYXRoKSB7XG4gICAgbGV0IHN0YXQ7XG4gICAgdHJ5IHtcbiAgICAgICAgc3RhdCA9IGZzLnN0YXRTeW5jKHNlYXJjaFBhdGgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGlmIChzdGF0LmlzRGlyZWN0b3J5KCkpIHtcbiAgICAgICAgY29uc3QgaXRlbXMgPSBmcy5yZWFkZGlyU3luYyhzZWFyY2hQYXRoKTtcbiAgICAgICAgcmV0dXJuICFpdGVtcyB8fCAhaXRlbXMubGVuZ3RoO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG59XG5cbi8qKlxuICogUmVwcmVzZW50cyB0aGUgLmRlc2t0b3AgZGlyZWN0b3J5LlxuICogQGNsYXNzXG4gKiBAcHJvcGVydHkge2Rlc2t0b3BTZXR0aW5nc30gc2V0dGluZ3NcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRGVza3RvcCB7XG4gICAgLyoqXG4gICAgICogQHBhcmFtIHtNZXRlb3JEZXNrdG9wfSAkIC0gY29udGV4dFxuICAgICAqXG4gICAgICogQGNvbnN0cnVjdG9yXG4gICAgICovXG4gICAgY29uc3RydWN0b3IoJCkge1xuICAgICAgICB0aGlzLiQgPSAkO1xuICAgICAgICB0aGlzLmxvZyA9IG5ldyBMb2coJ2Rlc2t0b3AnKTtcbiAgICAgICAgdGhpcy5zZXR0aW5ncyA9IG51bGw7XG4gICAgICAgIHRoaXMuZGVwZW5kZW5jaWVzID0gbnVsbDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUcmllcyB0byByZWFkIGFuZCByZXR1cm5zIHNldHRpbmdzLmpzb24gY29udGVudHMgZnJvbSAuZGVza3RvcCBkaXIuXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB7ZGVza3RvcFNldHRpbmdzfG51bGx9XG4gICAgICovXG4gICAgZ2V0U2V0dGluZ3MoKSB7XG4gICAgICAgIGlmICghdGhpcy5zZXR0aW5ncykge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldHRpbmdzID0gSlNPTi5wYXJzZShcbiAgICAgICAgICAgICAgICAgICAgZnMucmVhZEZpbGVTeW5jKHRoaXMuJC5lbnYucGF0aHMuZGVza3RvcC5zZXR0aW5ncywgJ1VURi04JylcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIHRoaXMubG9nLmVycm9yKCdlcnJvciB3aGlsZSB0cnlpbmcgdG8gcmVhZCBcXCcuZGVza3RvcC9zZXR0aW5ncy5qc29uXFwnOiAnLCBlKTtcbiAgICAgICAgICAgICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuc2V0dGluZ3M7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhIHZlcnNpb24gaGFzaCByZXByZXNlbnRpbmcgY3VycmVudCAuZGVza3RvcCBjb250ZW50cy5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfVxuICAgICAqL1xuICAgIGFzeW5jIGdldEhhc2hWZXJzaW9uKCkge1xuICAgICAgICB0aGlzLmxvZy5pbmZvKCdjYWxjdWxhdGluZyBoYXNoIHZlcnNpb24gZnJvbSAuZGVza3RvcCBjb250ZW50cycpO1xuXG4gICAgICAgIGNvbnN0IHZlcnNpb24gPSBhd2FpdCB0aGlzLiQudXRpbHMucmVhZEZpbGVzQW5kQ29tcHV0ZUhhc2godGhpcy4kLmVudi5wYXRocy5kZXNrdG9wLnJvb3QpO1xuXG4gICAgICAgIHRoaXMubG9nLnZlcmJvc2UoYGNhbGN1bGF0ZWQgLmRlc2t0b3AgaGFzaCB2ZXJzaW9uIGlzICR7dmVyc2lvbi5oYXNofWApO1xuICAgICAgICByZXR1cm4gdmVyc2lvbi5oYXNoO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRyaWVzIHRvIHJlYWQgYSBtb2R1bGUuanNvbiBmaWxlIGZyb20gYSBtb2R1bGUgYXQgcHJvdmlkZWQgcGF0aC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBtb2R1bGVQYXRoIC0gcGF0aCB0byB0aGUgbW9kdWxlIGRpclxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9XG4gICAgICovXG4gICAgZ2V0TW9kdWxlQ29uZmlnKG1vZHVsZVBhdGgpIHtcbiAgICAgICAgbGV0IG1vZHVsZUNvbmZpZyA9IHt9O1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgbW9kdWxlQ29uZmlnID0gSlNPTi5wYXJzZShcbiAgICAgICAgICAgICAgICBmcy5yZWFkRmlsZVN5bmMocGF0aC5qb2luKG1vZHVsZVBhdGgsICdtb2R1bGUuanNvbicpLCAnVVRGLTgnKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgdGhpcy5sb2cuZXJyb3IoXG4gICAgICAgICAgICAgICAgYGVycm9yIHdoaWxlIHRyeWluZyB0byByZWFkICdtb2R1bGUuanNvbicgZnJvbSAnJHttb2R1bGVQYXRofScgbW9kdWxlOiBgLFxuICAgICAgICAgICAgICAgIGVcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCEoJ25hbWUnIGluIG1vZHVsZUNvbmZpZykpIHtcbiAgICAgICAgICAgIHRoaXMubG9nLmVycm9yKGBubyAnbmFtZScgZmllbGQgZGVmaW5lZCBpbiAnbW9kdWxlLmpzb24nIGluICcke21vZHVsZVBhdGh9JyBtb2R1bGUuYCk7XG4gICAgICAgICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG1vZHVsZUNvbmZpZztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTY2FucyBhbGwgbW9kdWxlcyBmb3IgbW9kdWxlLmpzb24gYW5kIGdhdGhlcnMgdGhpcyBjb25maWd1cmF0aW9uIGFsdG9nZXRoZXIuXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB7W119XG4gICAgICovXG4gICAgZ2F0aGVyTW9kdWxlQ29uZmlncygpIHtcbiAgICAgICAgY29uc3QgY29uZmlncyA9IFtdO1xuXG4gICAgICAgIGlmICghaXNFbXB0eVN5bmModGhpcy4kLmVudi5wYXRocy5kZXNrdG9wLm1vZHVsZXMpKSB7XG4gICAgICAgICAgICBzaGVsbC5scygnLWQnLCBwYXRoLmpvaW4odGhpcy4kLmVudi5wYXRocy5kZXNrdG9wLm1vZHVsZXMsICcqJykpLmZvckVhY2goXG4gICAgICAgICAgICAgICAgKG1vZHVsZSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZnMubHN0YXRTeW5jKG1vZHVsZSkuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgbW9kdWxlQ29uZmlnID0gdGhpcy5nZXRNb2R1bGVDb25maWcobW9kdWxlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1vZHVsZUNvbmZpZy5kaXJOYW1lID0gcGF0aC5wYXJzZShtb2R1bGUpLm5hbWU7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25maWdzLnB1c2gobW9kdWxlQ29uZmlnKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGNvbmZpZ3M7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU3VtbWFyaXplcyBhbGwgZGVwZW5kZW5jaWVzIGRlZmluZWQgaW4gLmRlc2t0b3AuXG4gICAgICpcbiAgICAgKiBAcGFyYW1zIHtPYmplY3R9IHNldHRpbmdzICAgICAgLSBzZXR0aW5ncy5qc29uXG4gICAgICogQHBhcmFtcyB7Ym9vbGVhbn0gY2hlY2tNb2R1bGVzIC0gd2hldGhlciB0byBnYXRoZXIgbW9kdWxlcyBkZXBlbmRlbmNpZXNcbiAgICAgKiBAcGFyYW1zIHtib29sZWFufSByZWZyZXNoICAgICAgLSByZWNvbXB1dGVcbiAgICAgKiBAcmV0dXJucyB7e2Zyb21TZXR0aW5nczoge30sIHBsdWdpbnM6IHt9LCBtb2R1bGVzOiB7fX19XG4gICAgICovXG4gICAgZ2V0RGVwZW5kZW5jaWVzKHNldHRpbmdzID0gbnVsbCwgY2hlY2tNb2R1bGVzID0gdHJ1ZSwgcmVmcmVzaCA9IGZhbHNlKSB7XG4gICAgICAgIGlmICghcmVmcmVzaCAmJiB0aGlzLmRlcGVuZGVuY2llcykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZGVwZW5kZW5jaWVzO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZGVwZW5kZW5jaWVzID0ge1xuICAgICAgICAgICAgZnJvbVNldHRpbmdzOiB7fSxcbiAgICAgICAgICAgIHBsdWdpbnM6IHt9LFxuICAgICAgICAgICAgbW9kdWxlczoge31cbiAgICAgICAgfTtcbiAgICAgICAgLyoqIEB0eXBlIHtkZXNrdG9wU2V0dGluZ3N9ICogKi9cbiAgICAgICAgY29uc3Qgc2V0dGluZ3NKc29uID0gc2V0dGluZ3MgfHwgdGhpcy5nZXRTZXR0aW5ncygpO1xuXG4gICAgICAgIC8vIFNldHRpbmdzIGNhbiBoYXZlIGEgJ2RlcGVuZGVuY2llcycgZmllbGQuXG4gICAgICAgIGlmICgnZGVwZW5kZW5jaWVzJyBpbiBzZXR0aW5nc0pzb24pIHtcbiAgICAgICAgICAgIGRlcGVuZGVuY2llcy5mcm9tU2V0dGluZ3MgPSBzZXR0aW5nc0pzb24uZGVwZW5kZW5jaWVzO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gUGx1Z2lucyBhcmUgYWxzbyBhIG5wbSBwYWNrYWdlcy5cbiAgICAgICAgaWYgKCdwbHVnaW5zJyBpbiBzZXR0aW5nc0pzb24pIHtcbiAgICAgICAgICAgIGRlcGVuZGVuY2llcy5wbHVnaW5zID0gT2JqZWN0LmtleXMoc2V0dGluZ3NKc29uLnBsdWdpbnMpLnJlZHVjZSgocGx1Z2lucywgcGx1Z2luKSA9PiB7XG4gICAgICAgICAgICAgICAgLyogZXNsaW50LWRpc2FibGUgbm8tcGFyYW0tcmVhc3NpZ24gKi9cbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHNldHRpbmdzSnNvbi5wbHVnaW5zW3BsdWdpbl0gPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAgICAgICAgIHBsdWdpbnNbcGx1Z2luXSA9IHNldHRpbmdzSnNvbi5wbHVnaW5zW3BsdWdpbl0udmVyc2lvbjtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBwbHVnaW5zW3BsdWdpbl0gPSBzZXR0aW5nc0pzb24ucGx1Z2luc1twbHVnaW5dO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gcGx1Z2lucztcbiAgICAgICAgICAgIH0sIHt9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEVhY2ggbW9kdWxlIGNhbiBoYXZlIGl0cyBvd24gZGVwZW5kZW5jaWVzIGRlZmluZWQuXG4gICAgICAgIGNvbnN0IG1vZHVsZURlcGVuZGVuY2llcyA9IHt9O1xuICAgICAgICBpZiAoY2hlY2tNb2R1bGVzKSB7XG4gICAgICAgICAgICBjb25zdCBjb25maWdzID0gdGhpcy5nYXRoZXJNb2R1bGVDb25maWdzKCk7XG5cbiAgICAgICAgICAgIGNvbmZpZ3MuZm9yRWFjaChcbiAgICAgICAgICAgICAgICAobW9kdWxlQ29uZmlnKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmICghKCdkZXBlbmRlbmNpZXMnIGluIG1vZHVsZUNvbmZpZykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1vZHVsZUNvbmZpZy5kZXBlbmRlbmNpZXMgPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAobW9kdWxlQ29uZmlnLm5hbWUgaW4gbW9kdWxlRGVwZW5kZW5jaWVzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZy5lcnJvcihgZHVwbGljYXRlIG5hbWUgJyR7bW9kdWxlQ29uZmlnLm5hbWV9JyBpbiAnbW9kdWxlLmpzb24nIGluIGAgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGAnJHttb2R1bGVDb25maWcuZGlyTmFtZX0nIC0gYW5vdGhlciBtb2R1bGUgYWxyZWFkeSByZWdpc3RlcmVkIHRoZSBzYW1lIG5hbWUuYCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgbW9kdWxlRGVwZW5kZW5jaWVzW21vZHVsZUNvbmZpZy5uYW1lXSA9IG1vZHVsZUNvbmZpZy5kZXBlbmRlbmNpZXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGRlcGVuZGVuY2llcy5tb2R1bGVzID0gbW9kdWxlRGVwZW5kZW5jaWVzO1xuICAgICAgICB0aGlzLmRlcGVuZGVuY2llcyA9IGRlcGVuZGVuY2llcztcbiAgICAgICAgcmV0dXJuIGRlcGVuZGVuY2llcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDb3BpZXMgdGhlIC5kZXNrdG9wIHNjYWZmb2xkIGludG8gdGhlIG1ldGVvciBhcHAgZGlyLlxuICAgICAqIEFkZHMgZW50cnkgdG8gLm1ldGVvci8uZ2l0aWdub3JlLlxuICAgICAqL1xuICAgIHNjYWZmb2xkKCkge1xuICAgICAgICB0aGlzLmxvZy5pbmZvKCdjcmVhdGluZyAuZGVza3RvcCBzY2FmZm9sZCBpbiB5b3VyIHByb2plY3QnKTtcblxuICAgICAgICBpZiAodGhpcy4kLnV0aWxzLmV4aXN0cyh0aGlzLiQuZW52LnBhdGhzLmRlc2t0b3Aucm9vdCkpIHtcbiAgICAgICAgICAgIHRoaXMubG9nLndhcm4oJy5kZXNrdG9wIGFscmVhZHkgZXhpc3RzIC0gZGVsZXRlIGl0IGlmIHlvdSB3YW50IGEgbmV3IG9uZSB0byBiZSAnICtcbiAgICAgICAgICAgICAgICAnY3JlYXRlZCcpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgc2hlbGwuY3AoJy1yJywgdGhpcy4kLmVudi5wYXRocy5zY2FmZm9sZCwgdGhpcy4kLmVudi5wYXRocy5kZXNrdG9wLnJvb3QpO1xuICAgICAgICBzaGVsbC5ta2Rpcih0aGlzLiQuZW52LnBhdGhzLmRlc2t0b3AuaW1wb3J0KTtcbiAgICAgICAgdGhpcy5sb2cuaW5mbygnLmRlc2t0b3AgZGlyZWN0b3J5IHByZXBhcmVkJyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVmVyaWZpZXMgaWYgYWxsIG1hbmRhdG9yeSBmaWxlcyBhcmUgcHJlc2VudCBpbiB0aGUgLmRlc2t0b3AuXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICBjaGVjaygpIHtcbiAgICAgICAgdGhpcy5sb2cudmVyYm9zZSgnY2hlY2tpbmcgLmRlc2t0b3AgZXhpc3RlbmNlJyk7XG4gICAgICAgIHJldHVybiAhISh0aGlzLiQudXRpbHMuZXhpc3RzKHRoaXMuJC5lbnYucGF0aHMuZGVza3RvcC5yb290KSAmJlxuICAgICAgICAgICAgdGhpcy4kLnV0aWxzLmV4aXN0cyh0aGlzLiQuZW52LnBhdGhzLmRlc2t0b3Auc2V0dGluZ3MpICYmXG4gICAgICAgICAgICB0aGlzLiQudXRpbHMuZXhpc3RzKHRoaXMuJC5lbnYucGF0aHMuZGVza3RvcC5kZXNrdG9wKSk7XG4gICAgfVxufVxuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IGRlc2t0b3BTZXR0aW5nc1xuICogQHByb3BlcnR5IHtzdHJpbmd9IG5hbWVcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBwcm9qZWN0TmFtZVxuICogQHByb3BlcnR5IHtib29sZWFufSBkZXZUb29sc1xuICogQHByb3BlcnR5IHtib29sZWFufSBkZXZ0cm9uXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IGRlc2t0b3BIQ1BcbiAqIEBwcm9wZXJ0eSB7T2JqZWN0fSBkZXNrdG9wSENQU2V0dGluZ3NcbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gZGVza3RvcEhDUFNldHRpbmdzLmlnbm9yZUNvbXBhdGliaWxpdHlWZXJzaW9uXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IGRlc2t0b3BIQ1BTZXR0aW5ncy5ibG9ja0FwcFVwZGF0ZU9uRGVza3RvcEluY29tcGF0aWJpbGl0eVxuICogQHByb3BlcnR5IHtudW1iZXJ9IHdlYkFwcFN0YXJ0dXBUaW1lb3V0XG4gKiBAcHJvcGVydHkge0FycmF5fSBsaW5rUGFja2FnZXNcbiAqIEBwcm9wZXJ0eSB7QXJyYXl9IGV4cG9zZWRNb2R1bGVzXG4gKiBAcHJvcGVydHkge09iamVjdH0gd2luZG93XG4gKiBAcHJvcGVydHkge09iamVjdH0gd2luZG93RGV2XG4gKiBAcHJvcGVydHkge09iamVjdH0gcGFja2FnZUpzb25GaWVsZHNcbiAqIEBwcm9wZXJ0eSB7T2JqZWN0fSBidWlsZGVyT3B0aW9uc1xuICogQHByb3BlcnR5IHtPYmplY3R9IGJ1aWxkZXJDbGlPcHRpb25zXG4gKiBAcHJvcGVydHkge09iamVjdH0gcGFja2FnZXJPcHRpb25zXG4gKiBAcHJvcGVydHkge09iamVjdH0gcGx1Z2luc1xuICogQHByb3BlcnR5IHtPYmplY3R9IGRlcGVuZGVuY2llc1xuICogQHByb3BlcnR5IHtib29sZWFufSB1Z2xpZnlcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSB2ZXJz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