electron-compile
Version:
Electron supporting package to compile JS and CSS in Electron applications
479 lines (390 loc) • 47.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createCompilerHostFromProjectRoot = exports.createCompilerHostFromConfigFile = exports.createCompilerHostFromBabelRc = undefined;
/**
* Creates a compiler host from a .babelrc file. This method is usually called
* from {@link createCompilerHostFromProjectRoot} instead of used directly.
*
* @param {string} file The path to a .babelrc file
*
* @param {string} rootCacheDir (optional) The directory to use as a cache.
*
* @return {Promise<CompilerHost>} A set-up compiler host
*/
let createCompilerHostFromBabelRc = exports.createCompilerHostFromBabelRc = (() => {
var _ref = _asyncToGenerator(function* (file) {
let rootCacheDir = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
let info = JSON.parse((yield _promise.pfs.readFile(file, 'utf8')));
// package.json
if ('babel' in info) {
info = info.babel;
}
if ('env' in info) {
let ourEnv = process.env.BABEL_ENV || process.env.NODE_ENV || 'development';
info = info.env[ourEnv];
}
// Are we still package.json (i.e. is there no babel info whatsoever?)
if ('name' in info && 'version' in info) {
return createCompilerHostFromConfiguration({
appRoot: _path2.default.dirname(file),
options: getDefaultConfiguration(),
rootCacheDir
});
}
return createCompilerHostFromConfiguration({
appRoot: _path2.default.dirname(file),
options: {
'application/javascript': info
},
rootCacheDir
});
});
return function createCompilerHostFromBabelRc(_x3, _x4) {
return _ref.apply(this, arguments);
};
})();
/**
* Creates a compiler host from a .compilerc file. This method is usually called
* from {@link createCompilerHostFromProjectRoot} instead of used directly.
*
* @param {string} file The path to a .compilerc file
*
* @param {string} rootCacheDir (optional) The directory to use as a cache.
*
* @return {Promise<CompilerHost>} A set-up compiler host
*/
let createCompilerHostFromConfigFile = exports.createCompilerHostFromConfigFile = (() => {
var _ref2 = _asyncToGenerator(function* (file) {
let rootCacheDir = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
let info = JSON.parse((yield _promise.pfs.readFile(file, 'utf8')));
if ('env' in info) {
let ourEnv = process.env.ELECTRON_COMPILE_ENV || process.env.NODE_ENV || 'development';
info = info.env[ourEnv];
}
return createCompilerHostFromConfiguration({
appRoot: _path2.default.dirname(file),
options: info,
rootCacheDir
});
});
return function createCompilerHostFromConfigFile(_x6, _x7) {
return _ref2.apply(this, arguments);
};
})();
/**
* Creates a configured {@link CompilerHost} instance from the project root
* directory. This method first searches for a .compilerc (or .compilerc.json), then falls back to the
* default locations for Babel configuration info. If neither are found, defaults
* to standard settings
*
* @param {string} rootDir The root application directory (i.e. the directory
* that has the app's package.json)
*
* @param {string} rootCacheDir (optional) The directory to use as a cache.
*
* @return {Promise<CompilerHost>} A set-up compiler host
*/
let createCompilerHostFromProjectRoot = exports.createCompilerHostFromProjectRoot = (() => {
var _ref3 = _asyncToGenerator(function* (rootDir) {
let rootCacheDir = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
let compilerc = _path2.default.join(rootDir, '.compilerc');
if (statSyncNoException(compilerc)) {
d(`Found a .compilerc at ${ compilerc }, using it`);
return yield createCompilerHostFromConfigFile(compilerc, rootCacheDir);
}
compilerc += '.json';
if (statSyncNoException(compilerc)) {
d(`Found a .compilerc at ${ compilerc }, using it`);
return yield createCompilerHostFromConfigFile(compilerc, rootCacheDir);
}
let babelrc = _path2.default.join(rootDir, '.babelrc');
if (statSyncNoException(babelrc)) {
d(`Found a .babelrc at ${ babelrc }, using it`);
return yield createCompilerHostFromBabelRc(babelrc, rootCacheDir);
}
d(`Using package.json or default parameters at ${ rootDir }`);
return yield createCompilerHostFromBabelRc(_path2.default.join(rootDir, 'package.json'), rootCacheDir);
});
return function createCompilerHostFromProjectRoot(_x9, _x10) {
return _ref3.apply(this, arguments);
};
})();
exports.initializeGlobalHooks = initializeGlobalHooks;
exports.init = init;
exports.createCompilerHostFromConfiguration = createCompilerHostFromConfiguration;
exports.createCompilerHostFromBabelRcSync = createCompilerHostFromBabelRcSync;
exports.createCompilerHostFromConfigFileSync = createCompilerHostFromConfigFileSync;
exports.createCompilerHostFromProjectRootSync = createCompilerHostFromProjectRootSync;
exports.calculateDefaultCompileCacheDirectory = calculateDefaultCompileCacheDirectory;
exports.getDefaultConfiguration = getDefaultConfiguration;
exports.createCompilers = createCompilers;
var _fs = require('fs');
var _fs2 = _interopRequireDefault(_fs);
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _zlib = require('zlib');
var _zlib2 = _interopRequireDefault(_zlib);
var _mkdirp = require('mkdirp');
var _mkdirp2 = _interopRequireDefault(_mkdirp);
var _promise = require('./promise');
var _fileChangeCache = require('./file-change-cache');
var _fileChangeCache2 = _interopRequireDefault(_fileChangeCache);
var _compilerHost = require('./compiler-host');
var _compilerHost2 = _interopRequireDefault(_compilerHost);
var _requireHook = require('./require-hook');
var _requireHook2 = _interopRequireDefault(_requireHook);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
const d = require('debug-electron')('electron-compile:config-parser');
// NB: We intentionally delay-load this so that in production, you can create
// cache-only versions of these compilers
let allCompilerClasses = null;
function statSyncNoException(fsPath) {
if ('statSyncNoException' in _fs2.default) {
return _fs2.default.statSyncNoException(fsPath);
}
try {
return _fs2.default.statSync(fsPath);
} catch (e) {
return null;
}
}
/**
* Initialize the global hooks (protocol hook for file:, node.js hook)
* independent of initializing the compiler. This method is usually called by
* init instead of directly
*
* @param {CompilerHost} compilerHost The compiler host to use.
*
*/
function initializeGlobalHooks(compilerHost) {
let globalVar = global || window;
globalVar.globalCompilerHost = compilerHost;
(0, _requireHook2.default)(compilerHost);
if ('type' in process && process.type === 'browser') {
var _require = require('electron');
const app = _require.app;
var _require2 = require('./protocol-hook');
const initializeProtocolHook = _require2.initializeProtocolHook;
let protoify = function () {
initializeProtocolHook(compilerHost);
};
if (app.isReady()) {
protoify();
} else {
app.on('ready', protoify);
}
}
}
/**
* Initialize electron-compile and set it up, either for development or
* production use. This is almost always the only method you need to use in order
* to use electron-compile.
*
* @param {string} appRoot The top-level directory for your application (i.e.
* the one which has your package.json).
*
* @param {string} mainModule The module to require in, relative to the module
* calling init, that will start your app. Write this
* as if you were writing a require call from here.
*
* @param {bool} productionMode If explicitly True/False, will set read-only
* mode to be disabled/enabled. If not, we'll
* guess based on the presence of a production
* cache.
*
* @param {string} cacheDir If not passed in, read-only will look in
* `appRoot/.cache` and dev mode will compile to a
* temporary directory. If it is passed in, both modes
* will cache to/from `appRoot/{cacheDir}`
*/
function init(appRoot, mainModule) {
let productionMode = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
let cacheDir = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
let compilerHost = null;
let rootCacheDir = _path2.default.join(appRoot, cacheDir || '.cache');
if (productionMode === null) {
productionMode = !!statSyncNoException(rootCacheDir);
}
if (productionMode) {
compilerHost = _compilerHost2.default.createReadonlyFromConfigurationSync(rootCacheDir, appRoot);
} else {
// if cacheDir was passed in, pass it along. Otherwise, default to a tempdir.
if (cacheDir) {
compilerHost = createCompilerHostFromProjectRootSync(appRoot, rootCacheDir);
} else {
compilerHost = createCompilerHostFromProjectRootSync(appRoot);
}
}
initializeGlobalHooks(compilerHost);
require.main.require(mainModule);
}
/**
* Creates a {@link CompilerHost} with the given information. This method is
* usually called by {@link createCompilerHostFromProjectRoot}.
*
* @private
*/
function createCompilerHostFromConfiguration(info) {
let compilers = createCompilers();
let rootCacheDir = info.rootCacheDir || calculateDefaultCompileCacheDirectory();
d(`Creating CompilerHost: ${ JSON.stringify(info) }, rootCacheDir = ${ rootCacheDir }`);
let fileChangeCache = new _fileChangeCache2.default(info.appRoot);
let compilerInfo = _path2.default.join(rootCacheDir, 'compiler-info.json.gz');
if (_fs2.default.existsSync(compilerInfo)) {
let buf = _fs2.default.readFileSync(compilerInfo);
let json = JSON.parse(_zlib2.default.gunzipSync(buf));
fileChangeCache = _fileChangeCache2.default.loadFromData(json.fileChangeCache, info.appRoot, false);
}
Object.keys(info.options || {}).forEach(x => {
let opts = info.options[x];
if (!(x in compilers)) {
throw new Error(`Found compiler settings for missing compiler: ${ x }`);
}
// NB: Let's hope this isn't a valid compiler option...
if (opts.passthrough) {
compilers[x] = compilers['text/plain'];
delete opts.passthrough;
}
d(`Setting options for ${ x }: ${ JSON.stringify(opts) }`);
compilers[x].compilerOptions = opts;
});
let ret = new _compilerHost2.default(rootCacheDir, compilers, fileChangeCache, false, compilers['text/plain']);
// NB: It's super important that we guarantee that the configuration is saved
// out, because we'll need to re-read it in the renderer process
d(`Created compiler host with options: ${ JSON.stringify(info) }`);
ret.saveConfigurationSync();
return ret;
}function createCompilerHostFromBabelRcSync(file) {
let rootCacheDir = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
let info = JSON.parse(_fs2.default.readFileSync(file, 'utf8'));
// package.json
if ('babel' in info) {
info = info.babel;
}
if ('env' in info) {
let ourEnv = process.env.BABEL_ENV || process.env.NODE_ENV || 'development';
info = info.env[ourEnv];
}
// Are we still package.json (i.e. is there no babel info whatsoever?)
if ('name' in info && 'version' in info) {
return createCompilerHostFromConfiguration({
appRoot: _path2.default.dirname(file),
options: getDefaultConfiguration(),
rootCacheDir
});
}
return createCompilerHostFromConfiguration({
appRoot: _path2.default.dirname(file),
options: {
'application/javascript': info
},
rootCacheDir
});
}
function createCompilerHostFromConfigFileSync(file) {
let rootCacheDir = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
let info = JSON.parse(_fs2.default.readFileSync(file, 'utf8'));
if ('env' in info) {
let ourEnv = process.env.ELECTRON_COMPILE_ENV || process.env.NODE_ENV || 'development';
info = info.env[ourEnv];
}
return createCompilerHostFromConfiguration({
appRoot: _path2.default.dirname(file),
options: info,
rootCacheDir
});
}
function createCompilerHostFromProjectRootSync(rootDir) {
let rootCacheDir = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
let compilerc = _path2.default.join(rootDir, '.compilerc');
if (statSyncNoException(compilerc)) {
d(`Found a .compilerc at ${ compilerc }, using it`);
return createCompilerHostFromConfigFileSync(compilerc, rootCacheDir);
}
let babelrc = _path2.default.join(rootDir, '.babelrc');
if (statSyncNoException(babelrc)) {
d(`Found a .babelrc at ${ babelrc }, using it`);
return createCompilerHostFromBabelRcSync(babelrc, rootCacheDir);
}
d(`Using package.json or default parameters at ${ rootDir }`);
return createCompilerHostFromBabelRcSync(_path2.default.join(rootDir, 'package.json'), rootCacheDir);
}
/**
* Returns what electron-compile would use as a default rootCacheDir. Usually only
* used for debugging purposes
*
* @return {string} A path that may or may not exist where electron-compile would
* set up a development mode cache.
*/
function calculateDefaultCompileCacheDirectory() {
let tmpDir = process.env.TEMP || process.env.TMPDIR || '/tmp';
let hash = require('crypto').createHash('md5').update(process.execPath).digest('hex');
let cacheDir = _path2.default.join(tmpDir, `compileCache_${ hash }`);
_mkdirp2.default.sync(cacheDir);
d(`Using default cache directory: ${ cacheDir }`);
return cacheDir;
}
/**
* Returns the default .configrc if no configuration information can be found.
*
* @return {Object} A list of default config settings for electron-compiler.
*/
function getDefaultConfiguration() {
return {
'application/javascript': {
"presets": ["es2016-node5", "react"],
"sourceMaps": "inline"
}
};
}
/**
* Allows you to create new instances of all compilers that are supported by
* electron-compile and use them directly. Currently supports Babel, CoffeeScript,
* TypeScript, Less, and Jade.
*
* @return {Object} An Object whose Keys are MIME types, and whose values
* are instances of @{link CompilerBase}.
*/
function createCompilers() {
if (!allCompilerClasses) {
// First we want to see if electron-compilers itself has been installed with
// devDependencies. If that's not the case, check to see if
// electron-compilers is installed as a peer dependency (probably as a
// devDependency of the root project).
const locations = ['electron-compilers', '../../electron-compilers'];
for (let location of locations) {
try {
allCompilerClasses = require(location);
} catch (e) {
// Yolo
}
}
if (!allCompilerClasses) {
throw new Error("Electron compilers not found but were requested to be loaded");
}
}
// NB: Note that this code is carefully set up so that InlineHtmlCompiler
// (i.e. classes with `createFromCompilers`) initially get an empty object,
// but will have a reference to the final result of what we return, which
// resolves the circular dependency we'd otherwise have here.
let ret = {};
let instantiatedClasses = allCompilerClasses.map(Klass => {
if ('createFromCompilers' in Klass) {
return Klass.createFromCompilers(ret);
} else {
return new Klass();
}
});
instantiatedClasses.reduce((acc, x) => {
let Klass = Object.getPrototypeOf(x).constructor;
for (let type of Klass.getInputMimeTypes()) {
acc[type] = x;
}
return acc;
}, ret);
return ret;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9jb25maWctcGFyc2VyLmpzIl0sIm5hbWVzIjpbImZpbGUiLCJyb290Q2FjaGVEaXIiLCJpbmZvIiwiSlNPTiIsInBhcnNlIiwicmVhZEZpbGUiLCJiYWJlbCIsIm91ckVudiIsInByb2Nlc3MiLCJlbnYiLCJCQUJFTF9FTlYiLCJOT0RFX0VOViIsImNyZWF0ZUNvbXBpbGVySG9zdEZyb21Db25maWd1cmF0aW9uIiwiYXBwUm9vdCIsImRpcm5hbWUiLCJvcHRpb25zIiwiZ2V0RGVmYXVsdENvbmZpZ3VyYXRpb24iLCJjcmVhdGVDb21waWxlckhvc3RGcm9tQmFiZWxSYyIsIkVMRUNUUk9OX0NPTVBJTEVfRU5WIiwiY3JlYXRlQ29tcGlsZXJIb3N0RnJvbUNvbmZpZ0ZpbGUiLCJyb290RGlyIiwiY29tcGlsZXJjIiwiam9pbiIsInN0YXRTeW5jTm9FeGNlcHRpb24iLCJkIiwiYmFiZWxyYyIsImNyZWF0ZUNvbXBpbGVySG9zdEZyb21Qcm9qZWN0Um9vdCIsImluaXRpYWxpemVHbG9iYWxIb29rcyIsImluaXQiLCJjcmVhdGVDb21waWxlckhvc3RGcm9tQmFiZWxSY1N5bmMiLCJjcmVhdGVDb21waWxlckhvc3RGcm9tQ29uZmlnRmlsZVN5bmMiLCJjcmVhdGVDb21waWxlckhvc3RGcm9tUHJvamVjdFJvb3RTeW5jIiwiY2FsY3VsYXRlRGVmYXVsdENvbXBpbGVDYWNoZURpcmVjdG9yeSIsImNyZWF0ZUNvbXBpbGVycyIsInJlcXVpcmUiLCJhbGxDb21waWxlckNsYXNzZXMiLCJmc1BhdGgiLCJzdGF0U3luYyIsImUiLCJjb21waWxlckhvc3QiLCJnbG9iYWxWYXIiLCJnbG9iYWwiLCJ3aW5kb3ciLCJnbG9iYWxDb21waWxlckhvc3QiLCJ0eXBlIiwiYXBwIiwiaW5pdGlhbGl6ZVByb3RvY29sSG9vayIsInByb3RvaWZ5IiwiaXNSZWFkeSIsIm9uIiwibWFpbk1vZHVsZSIsInByb2R1Y3Rpb25Nb2RlIiwiY2FjaGVEaXIiLCJjcmVhdGVSZWFkb25seUZyb21Db25maWd1cmF0aW9uU3luYyIsIm1haW4iLCJjb21waWxlcnMiLCJzdHJpbmdpZnkiLCJmaWxlQ2hhbmdlQ2FjaGUiLCJjb21waWxlckluZm8iLCJleGlzdHNTeW5jIiwiYnVmIiwicmVhZEZpbGVTeW5jIiwianNvbiIsImd1bnppcFN5bmMiLCJsb2FkRnJvbURhdGEiLCJPYmplY3QiLCJrZXlzIiwiZm9yRWFjaCIsIngiLCJvcHRzIiwiRXJyb3IiLCJwYXNzdGhyb3VnaCIsImNvbXBpbGVyT3B0aW9ucyIsInJldCIsInNhdmVDb25maWd1cmF0aW9uU3luYyIsInRtcERpciIsIlRFTVAiLCJUTVBESVIiLCJoYXNoIiwiY3JlYXRlSGFzaCIsInVwZGF0ZSIsImV4ZWNQYXRoIiwiZGlnZXN0Iiwic3luYyIsImxvY2F0aW9ucyIsImxvY2F0aW9uIiwiaW5zdGFudGlhdGVkQ2xhc3NlcyIsIm1hcCIsIktsYXNzIiwiY3JlYXRlRnJvbUNvbXBpbGVycyIsInJlZHVjZSIsImFjYyIsImdldFByb3RvdHlwZU9mIiwiY29uc3RydWN0b3IiLCJnZXRJbnB1dE1pbWVUeXBlcyJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQXFKQTs7Ozs7Ozs7Ozs7K0JBVU8sV0FBNkNBLElBQTdDLEVBQXNFO0FBQUEsUUFBbkJDLFlBQW1CLHVFQUFOLElBQU07O0FBQzNFLFFBQUlDLE9BQU9DLEtBQUtDLEtBQUwsRUFBVyxNQUFNLGFBQUlDLFFBQUosQ0FBYUwsSUFBYixFQUFtQixNQUFuQixDQUFqQixFQUFYOztBQUVBO0FBQ0EsUUFBSSxXQUFXRSxJQUFmLEVBQXFCO0FBQ25CQSxhQUFPQSxLQUFLSSxLQUFaO0FBQ0Q7O0FBRUQsUUFBSSxTQUFTSixJQUFiLEVBQW1CO0FBQ2pCLFVBQUlLLFNBQVNDLFFBQVFDLEdBQVIsQ0FBWUMsU0FBWixJQUF5QkYsUUFBUUMsR0FBUixDQUFZRSxRQUFyQyxJQUFpRCxhQUE5RDtBQUNBVCxhQUFPQSxLQUFLTyxHQUFMLENBQVNGLE1BQVQsQ0FBUDtBQUNEOztBQUVEO0FBQ0EsUUFBSSxVQUFVTCxJQUFWLElBQWtCLGFBQWFBLElBQW5DLEVBQXlDO0FBQ3ZDLGFBQU9VLG9DQUFvQztBQUN6Q0MsaUJBQVMsZUFBS0MsT0FBTCxDQUFhZCxJQUFiLENBRGdDO0FBRXpDZSxpQkFBU0MseUJBRmdDO0FBR3pDZjtBQUh5QyxPQUFwQyxDQUFQO0FBS0Q7O0FBRUQsV0FBT1csb0NBQW9DO0FBQ3pDQyxlQUFTLGVBQUtDLE9BQUwsQ0FBYWQsSUFBYixDQURnQztBQUV6Q2UsZUFBUztBQUNQLGtDQUEwQmI7QUFEbkIsT0FGZ0M7QUFLekNEO0FBTHlDLEtBQXBDLENBQVA7QUFPRCxHOztrQkE3QnFCZ0IsNkI7Ozs7O0FBZ0N0Qjs7Ozs7Ozs7Ozs7OztnQ0FVTyxXQUFnRGpCLElBQWhELEVBQXlFO0FBQUEsUUFBbkJDLFlBQW1CLHVFQUFOLElBQU07O0FBQzlFLFFBQUlDLE9BQU9DLEtBQUtDLEtBQUwsRUFBVyxNQUFNLGFBQUlDLFFBQUosQ0FBYUwsSUFBYixFQUFtQixNQUFuQixDQUFqQixFQUFYOztBQUVBLFFBQUksU0FBU0UsSUFBYixFQUFtQjtBQUNqQixVQUFJSyxTQUFTQyxRQUFRQyxHQUFSLENBQVlTLG9CQUFaLElBQW9DVixRQUFRQyxHQUFSLENBQVlFLFFBQWhELElBQTRELGFBQXpFO0FBQ0FULGFBQU9BLEtBQUtPLEdBQUwsQ0FBU0YsTUFBVCxDQUFQO0FBQ0Q7O0FBRUQsV0FBT0ssb0NBQW9DO0FBQ3pDQyxlQUFTLGVBQUtDLE9BQUwsQ0FBYWQsSUFBYixDQURnQztBQUV6Q2UsZUFBU2IsSUFGZ0M7QUFHekNEO0FBSHlDLEtBQXBDLENBQVA7QUFLRCxHOztrQkFicUJrQixnQzs7Ozs7QUFnQnRCOzs7Ozs7Ozs7Ozs7Ozs7O2dDQWFPLFdBQWlEQyxPQUFqRCxFQUE2RTtBQUFBLFFBQW5CbkIsWUFBbUIsdUVBQU4sSUFBTTs7QUFDbEYsUUFBSW9CLFlBQVksZUFBS0MsSUFBTCxDQUFVRixPQUFWLEVBQW1CLFlBQW5CLENBQWhCO0FBQ0EsUUFBSUcsb0JBQW9CRixTQUFwQixDQUFKLEVBQW9DO0FBQ2xDRyxRQUFHLDBCQUF3QkgsU0FBVSxhQUFyQztBQUNBLGFBQU8sTUFBTUYsaUNBQWlDRSxTQUFqQyxFQUE0Q3BCLFlBQTVDLENBQWI7QUFDRDtBQUNEb0IsaUJBQWEsT0FBYjtBQUNBLFFBQUlFLG9CQUFvQkYsU0FBcEIsQ0FBSixFQUFvQztBQUNsQ0csUUFBRywwQkFBd0JILFNBQVUsYUFBckM7QUFDQSxhQUFPLE1BQU1GLGlDQUFpQ0UsU0FBakMsRUFBNENwQixZQUE1QyxDQUFiO0FBQ0Q7O0FBRUQsUUFBSXdCLFVBQVUsZUFBS0gsSUFBTCxDQUFVRixPQUFWLEVBQW1CLFVBQW5CLENBQWQ7QUFDQSxRQUFJRyxvQkFBb0JFLE9BQXBCLENBQUosRUFBa0M7QUFDaENELFFBQUcsd0JBQXNCQyxPQUFRLGFBQWpDO0FBQ0EsYUFBTyxNQUFNUiw4QkFBOEJRLE9BQTlCLEVBQXVDeEIsWUFBdkMsQ0FBYjtBQUNEOztBQUVEdUIsTUFBRyxnREFBOENKLE9BQVEsR0FBekQ7QUFDQSxXQUFPLE1BQU1ILDhCQUE4QixlQUFLSyxJQUFMLENBQVVGLE9BQVYsRUFBbUIsY0FBbkIsQ0FBOUIsRUFBa0VuQixZQUFsRSxDQUFiO0FBQ0QsRzs7a0JBcEJxQnlCLGlDOzs7OztRQWpNTkMscUIsR0FBQUEscUI7UUEwQ0FDLEksR0FBQUEsSTtRQStCQWhCLG1DLEdBQUFBLG1DO1FBOElBaUIsaUMsR0FBQUEsaUM7UUErQkFDLG9DLEdBQUFBLG9DO1FBZUFDLHFDLEdBQUFBLHFDO1FBd0JBQyxxQyxHQUFBQSxxQztRQWlCQWhCLHVCLEdBQUFBLHVCO1FBaUJBaUIsZSxHQUFBQSxlOztBQXBXaEI7Ozs7QUFDQTs7OztBQUNBOzs7O0FBQ0E7Ozs7QUFDQTs7QUFFQTs7OztBQUNBOzs7O0FBQ0E7Ozs7Ozs7O0FBRUEsTUFBTVQsSUFBSVUsUUFBUSxnQkFBUixFQUEwQixnQ0FBMUIsQ0FBVjs7QUFFQTtBQUNBO0FBQ0EsSUFBSUMscUJBQXFCLElBQXpCOztBQUVBLFNBQVNaLG1CQUFULENBQTZCYSxNQUE3QixFQUFxQztBQUNuQyxNQUFJLHFDQUFKLEVBQWlDO0FBQy9CLFdBQU8sYUFBR2IsbUJBQUgsQ0FBdUJhLE1BQXZCLENBQVA7QUFDRDs7QUFFRCxNQUFJO0FBQ0YsV0FBTyxhQUFHQyxRQUFILENBQVlELE1BQVosQ0FBUDtBQUNELEdBRkQsQ0FFRSxPQUFPRSxDQUFQLEVBQVU7QUFDVixXQUFPLElBQVA7QUFDRDtBQUNGOztBQUdEOzs7Ozs7OztBQVFPLFNBQVNYLHFCQUFULENBQStCWSxZQUEvQixFQUE2QztBQUNsRCxNQUFJQyxZQUFhQyxVQUFVQyxNQUEzQjtBQUNBRixZQUFVRyxrQkFBVixHQUErQkosWUFBL0I7O0FBRUEsNkJBQXlCQSxZQUF6Qjs7QUFFQSxNQUFJLFVBQVUvQixPQUFWLElBQXFCQSxRQUFRb0MsSUFBUixLQUFpQixTQUExQyxFQUFxRDtBQUFBLG1CQUNuQ1YsUUFBUSxVQUFSLENBRG1DOztBQUFBLFVBQzNDVyxHQUQyQyxZQUMzQ0EsR0FEMkM7O0FBQUEsb0JBRWhCWCxRQUFRLGlCQUFSLENBRmdCOztBQUFBLFVBRTNDWSxzQkFGMkMsYUFFM0NBLHNCQUYyQzs7O0FBSW5ELFFBQUlDLFdBQVcsWUFBVztBQUFFRCw2QkFBdUJQLFlBQXZCO0FBQXVDLEtBQW5FO0FBQ0EsUUFBSU0sSUFBSUcsT0FBSixFQUFKLEVBQW1CO0FBQ2pCRDtBQUNELEtBRkQsTUFFTztBQUNMRixVQUFJSSxFQUFKLENBQU8sT0FBUCxFQUFnQkYsUUFBaEI7QUFDRDtBQUNGO0FBQ0Y7O0FBR0Q7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFzQk8sU0FBU25CLElBQVQsQ0FBY2YsT0FBZCxFQUF1QnFDLFVBQXZCLEVBQTJFO0FBQUEsTUFBeENDLGNBQXdDLHVFQUF2QixJQUF1QjtBQUFBLE1BQWpCQyxRQUFpQix1RUFBTixJQUFNOztBQUNoRixNQUFJYixlQUFlLElBQW5CO0FBQ0EsTUFBSXRDLGVBQWUsZUFBS3FCLElBQUwsQ0FBVVQsT0FBVixFQUFtQnVDLFlBQVksUUFBL0IsQ0FBbkI7O0FBRUEsTUFBSUQsbUJBQW1CLElBQXZCLEVBQTZCO0FBQzNCQSxxQkFBaUIsQ0FBQyxDQUFDNUIsb0JBQW9CdEIsWUFBcEIsQ0FBbkI7QUFDRDs7QUFFRCxNQUFJa0QsY0FBSixFQUFvQjtBQUNsQlosbUJBQWUsdUJBQWFjLG1DQUFiLENBQWlEcEQsWUFBakQsRUFBK0RZLE9BQS9ELENBQWY7QUFDRCxHQUZELE1BRU87QUFDTDtBQUNBLFFBQUl1QyxRQUFKLEVBQWM7QUFDWmIscUJBQWVSLHNDQUFzQ2xCLE9BQXRDLEVBQStDWixZQUEvQyxDQUFmO0FBQ0QsS0FGRCxNQUVPO0FBQ0xzQyxxQkFBZVIsc0NBQXNDbEIsT0FBdEMsQ0FBZjtBQUNEO0FBRUY7O0FBRURjLHdCQUFzQlksWUFBdEI7QUFDQUwsVUFBUW9CLElBQVIsQ0FBYXBCLE9BQWIsQ0FBcUJnQixVQUFyQjtBQUNEOztBQUdEOzs7Ozs7QUFNTyxTQUFTdEMsbUNBQVQsQ0FBNkNWLElBQTdDLEVBQW1EO0FBQ3hELE1BQUlxRCxZQUFZdEIsaUJBQWhCO0FBQ0EsTUFBSWhDLGVBQWVDLEtBQUtELFlBQUwsSUFBcUIrQix1Q0FBeEM7O0FBRUFSLElBQUcsMkJBQXlCckIsS0FBS3FELFNBQUwsQ0FBZXRELElBQWYsQ0FBcUIsc0JBQW1CRCxZQUFhLEdBQWpGO0FBQ0EsTUFBSXdELGtCQUFrQiw4QkFBcUJ2RCxLQUFLVyxPQUExQixDQUF0Qjs7QUFFQSxNQUFJNkMsZUFBZSxlQUFLcEMsSUFBTCxDQUFVckIsWUFBVixFQUF3Qix1QkFBeEIsQ0FBbkI7QUFDQSxNQUFJLGFBQUcwRCxVQUFILENBQWNELFlBQWQsQ0FBSixFQUFpQztBQUMvQixRQUFJRSxNQUFNLGFBQUdDLFlBQUgsQ0FBZ0JILFlBQWhCLENBQVY7QUFDQSxRQUFJSSxPQUFPM0QsS0FBS0MsS0FBTCxDQUFXLGVBQUsyRCxVQUFMLENBQWdCSCxHQUFoQixDQUFYLENBQVg7QUFDQUgsc0JBQWtCLDBCQUFpQk8sWUFBakIsQ0FBOEJGLEtBQUtMLGVBQW5DLEVBQW9EdkQsS0FBS1csT0FBekQsRUFBa0UsS0FBbEUsQ0FBbEI7QUFDRDs7QUFFRG9ELFNBQU9DLElBQVAsQ0FBWWhFLEtBQUthLE9BQUwsSUFBZ0IsRUFBNUIsRUFBZ0NvRCxPQUFoQyxDQUF5Q0MsQ0FBRCxJQUFPO0FBQzdDLFFBQUlDLE9BQU9uRSxLQUFLYSxPQUFMLENBQWFxRCxDQUFiLENBQVg7QUFDQSxRQUFJLEVBQUVBLEtBQUtiLFNBQVAsQ0FBSixFQUF1QjtBQUNyQixZQUFNLElBQUllLEtBQUosQ0FBVyxrREFBZ0RGLENBQUUsR0FBN0QsQ0FBTjtBQUNEOztBQUVEO0FBQ0EsUUFBSUMsS0FBS0UsV0FBVCxFQUFzQjtBQUNwQmhCLGdCQUFVYSxDQUFWLElBQWViLFVBQVUsWUFBVixDQUFmO0FBQ0EsYUFBT2MsS0FBS0UsV0FBWjtBQUNEOztBQUVEL0MsTUFBRyx3QkFBc0I0QyxDQUFFLE9BQUlqRSxLQUFLcUQsU0FBTCxDQUFlYSxJQUFmLENBQXFCLEdBQXBEO0FBQ0FkLGNBQVVhLENBQVYsRUFBYUksZUFBYixHQUErQkgsSUFBL0I7QUFDRCxHQWREOztBQWdCQSxNQUFJSSxNQUFNLDJCQUFpQnhFLFlBQWpCLEVBQStCc0QsU0FBL0IsRUFBMENFLGVBQTFDLEVBQTJELEtBQTNELEVBQWtFRixVQUFVLFlBQVYsQ0FBbEUsQ0FBVjs7QUFFQTtBQUNBO0FBQ0EvQixJQUFHLHdDQUFzQ3JCLEtBQUtxRCxTQUFMLENBQWV0RCxJQUFmLENBQXFCLEdBQTlEO0FBQ0F1RSxNQUFJQyxxQkFBSjtBQUNBLFNBQU9ELEdBQVA7QUFDRCxDQXlHTSxTQUFTNUMsaUNBQVQsQ0FBMkM3QixJQUEzQyxFQUFvRTtBQUFBLE1BQW5CQyxZQUFtQix1RUFBTixJQUFNOztBQUN6RSxNQUFJQyxPQUFPQyxLQUFLQyxLQUFMLENBQVcsYUFBR3lELFlBQUgsQ0FBZ0I3RCxJQUFoQixFQUFzQixNQUF0QixDQUFYLENBQVg7O0FBRUE7QUFDQSxNQUFJLFdBQVdFLElBQWYsRUFBcUI7QUFDbkJBLFdBQU9BLEtBQUtJLEtBQVo7QUFDRDs7QUFFRCxNQUFJLFNBQVNKLElBQWIsRUFBbUI7QUFDakIsUUFBSUssU0FBU0MsUUFBUUMsR0FBUixDQUFZQyxTQUFaLElBQXlCRixRQUFRQyxHQUFSLENBQVlFLFFBQXJDLElBQWlELGFBQTlEO0FBQ0FULFdBQU9BLEtBQUtPLEdBQUwsQ0FBU0YsTUFBVCxDQUFQO0FBQ0Q7O0FBRUQ7QUFDQSxNQUFJLFVBQVVMLElBQVYsSUFBa0IsYUFBYUEsSUFBbkMsRUFBeUM7QUFDdkMsV0FBT1Usb0NBQW9DO0FBQ3pDQyxlQUFTLGVBQUtDLE9BQUwsQ0FBYWQsSUFBYixDQURnQztBQUV6Q2UsZUFBU0MseUJBRmdDO0FBR3pDZjtBQUh5QyxLQUFwQyxDQUFQO0FBS0Q7O0FBRUQsU0FBT1csb0NBQW9DO0FBQ3pDQyxhQUFTLGVBQUtDLE9BQUwsQ0FBYWQsSUFBYixDQURnQztBQUV6Q2UsYUFBUztBQUNQLGdDQUEwQmI7QUFEbkIsS0FGZ0M7QUFLekNEO0FBTHlDLEdBQXBDLENBQVA7QUFPRDs7QUFFTSxTQUFTNkIsb0NBQVQsQ0FBOEM5QixJQUE5QyxFQUF1RTtBQUFBLE1BQW5CQyxZQUFtQix1RUFBTixJQUFNOztBQUM1RSxNQUFJQyxPQUFPQyxLQUFLQyxLQUFMLENBQVcsYUFBR3lELFlBQUgsQ0FBZ0I3RCxJQUFoQixFQUFzQixNQUF0QixDQUFYLENBQVg7O0FBRUEsTUFBSSxTQUFTRSxJQUFiLEVBQW1CO0FBQ2pCLFFBQUlLLFNBQVNDLFFBQVFDLEdBQVIsQ0FBWVMsb0JBQVosSUFBb0NWLFFBQVFDLEdBQVIsQ0FBWUUsUUFBaEQsSUFBNEQsYUFBekU7QUFDQVQsV0FBT0EsS0FBS08sR0FBTCxDQUFTRixNQUFULENBQVA7QUFDRDs7QUFFRCxTQUFPSyxvQ0FBb0M7QUFDekNDLGFBQVMsZUFBS0MsT0FBTCxDQUFhZCxJQUFiLENBRGdDO0FBRXpDZSxhQUFTYixJQUZnQztBQUd6Q0Q7QUFIeUMsR0FBcEMsQ0FBUDtBQUtEOztBQUVNLFNBQVM4QixxQ0FBVCxDQUErQ1gsT0FBL0MsRUFBMkU7QUFBQSxNQUFuQm5CLFlBQW1CLHVFQUFOLElBQU07O0FBQ2hGLE1BQUlvQixZQUFZLGVBQUtDLElBQUwsQ0FBVUYsT0FBVixFQUFtQixZQUFuQixDQUFoQjtBQUNBLE1BQUlHLG9CQUFvQkYsU0FBcEIsQ0FBSixFQUFvQztBQUNsQ0csTUFBRywwQkFBd0JILFNBQVUsYUFBckM7QUFDQSxXQUFPUyxxQ0FBcUNULFNBQXJDLEVBQWdEcEIsWUFBaEQsQ0FBUDtBQUNEOztBQUVELE1BQUl3QixVQUFVLGVBQUtILElBQUwsQ0FBVUYsT0FBVixFQUFtQixVQUFuQixDQUFkO0FBQ0EsTUFBSUcsb0JBQW9CRSxPQUFwQixDQUFKLEVBQWtDO0FBQ2hDRCxNQUFHLHdCQUFzQkMsT0FBUSxhQUFqQztBQUNBLFdBQU9JLGtDQUFrQ0osT0FBbEMsRUFBMkN4QixZQUEzQyxDQUFQO0FBQ0Q7O0FBRUR1QixJQUFHLGdEQUE4Q0osT0FBUSxHQUF6RDtBQUNBLFNBQU9TLGtDQUFrQyxlQUFLUCxJQUFMLENBQVVGLE9BQVYsRUFBbUIsY0FBbkIsQ0FBbEMsRUFBc0VuQixZQUF0RSxDQUFQO0FBQ0Q7O0FBRUQ7Ozs7Ozs7QUFPTyxTQUFTK0IscUNBQVQsR0FBaUQ7QUFDdEQsTUFBSTJDLFNBQVNuRSxRQUFRQyxHQUFSLENBQVltRSxJQUFaLElBQW9CcEUsUUFBUUMsR0FBUixDQUFZb0UsTUFBaEMsSUFBMEMsTUFBdkQ7QUFDQSxNQUFJQyxPQUFPNUMsUUFBUSxRQUFSLEVBQWtCNkMsVUFBbEIsQ0FBNkIsS0FBN0IsRUFBb0NDLE1BQXBDLENBQTJDeEUsUUFBUXlFLFFBQW5ELEVBQTZEQyxNQUE3RCxDQUFvRSxLQUFwRSxDQUFYOztBQUVBLE1BQUk5QixXQUFXLGVBQUs5QixJQUFMLENBQVVxRCxNQUFWLEVBQW1CLGlCQUFlRyxJQUFLLEdBQXZDLENBQWY7QUFDQSxtQkFBT0ssSUFBUCxDQUFZL0IsUUFBWjs7QUFFQTVCLElBQUcsbUNBQWlDNEIsUUFBUyxHQUE3QztBQUNBLFNBQU9BLFFBQVA7QUFDRDs7QUFHRDs7Ozs7QUFLTyxTQUFTcEMsdUJBQVQsR0FBbUM7QUFDeEMsU0FBTztBQUNMLDhCQUEwQjtBQUN4QixpQkFBVyxDQUFDLGNBQUQsRUFBaUIsT0FBakIsQ0FEYTtBQUV4QixvQkFBYztBQUZVO0FBRHJCLEdBQVA7QUFNRDs7QUFFRDs7Ozs7Ozs7QUFRTyxTQUFTaUIsZUFBVCxHQUEyQjtBQUNoQyxNQUFJLENBQUNFLGtCQUFMLEVBQXlCO0FBQ3ZCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBTWlELFlBQVksQ0FBQyxvQkFBRCxFQUF1QiwwQkFBdkIsQ0FBbEI7O0FBRUEsU0FBSyxJQUFJQyxRQUFULElBQXFCRCxTQUFyQixFQUFnQztBQUM5QixVQUFJO0FBQ0ZqRCw2QkFBcUJELFFBQVFtRCxRQUFSLENBQXJCO0FBQ0QsT0FGRCxDQUVFLE9BQU8vQyxDQUFQLEVBQVU7QUFDVjtBQUNEO0FBQ0Y7O0FBRUQsUUFBSSxDQUFDSCxrQkFBTCxFQUF5QjtBQUN2QixZQUFNLElBQUltQyxLQUFKLENBQVUsOERBQVYsQ0FBTjtBQUNEO0FBQ0Y7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFJRyxNQUFNLEVBQVY7QUFDQSxNQUFJYSxzQkFBc0JuRCxtQkFBbUJvRCxHQUFuQixDQUF3QkMsS0FBRCxJQUFXO0FBQzFELFFBQUkseUJBQXlCQSxLQUE3QixFQUFvQztBQUNsQyxhQUFPQSxNQUFNQyxtQkFBTixDQUEwQmhCLEdBQTFCLENBQVA7QUFDRCxLQUZELE1BRU87QUFDTCxhQUFPLElBQUllLEtBQUosRUFBUDtBQUNEO0FBQ0YsR0FOeUIsQ0FBMUI7O0FBUUFGLHNCQUFvQkksTUFBcEIsQ0FBMkIsQ0FBQ0MsR0FBRCxFQUFLdkIsQ0FBTCxLQUFXO0FBQ3BDLFFBQUlvQixRQUFRdkIsT0FBTzJCLGNBQVAsQ0FBc0J4QixDQUF0QixFQUF5QnlCLFdBQXJDOztBQUVBLFNBQUssSUFBSWpELElBQVQsSUFBaUI0QyxNQUFNTSxpQkFBTixFQUFqQixFQUE0QztBQUFFSCxVQUFJL0MsSUFBSixJQUFZd0IsQ0FBWjtBQUFnQjtBQUM5RCxXQUFPdUIsR0FBUDtBQUNELEdBTEQsRUFLR2xCLEdBTEg7O0FBT0EsU0FBT0EsR0FBUDtBQUNEIiwiZmlsZSI6ImNvbmZpZy1wYXJzZXIuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZnMgZnJvbSAnZnMnO1xyXG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcclxuaW1wb3J0IHpsaWIgZnJvbSAnemxpYic7XHJcbmltcG9ydCBta2RpcnAgZnJvbSAnbWtkaXJwJztcclxuaW1wb3J0IHtwZnN9IGZyb20gJy4vcHJvbWlzZSc7XHJcblxyXG5pbXBvcnQgRmlsZUNoYW5nZWRDYWNoZSBmcm9tICcuL2ZpbGUtY2hhbmdlLWNhY2hlJztcclxuaW1wb3J0IENvbXBpbGVySG9zdCBmcm9tICcuL2NvbXBpbGVyLWhvc3QnO1xyXG5pbXBvcnQgcmVnaXN0ZXJSZXF1aXJlRXh0ZW5zaW9uIGZyb20gJy4vcmVxdWlyZS1ob29rJztcclxuXHJcbmNvbnN0IGQgPSByZXF1aXJlKCdkZWJ1Zy1lbGVjdHJvbicpKCdlbGVjdHJvbi1jb21waWxlOmNvbmZpZy1wYXJzZXInKTtcclxuXHJcbi8vIE5COiBXZSBpbnRlbnRpb25hbGx5IGRlbGF5LWxvYWQgdGhpcyBzbyB0aGF0IGluIHByb2R1Y3Rpb24sIHlvdSBjYW4gY3JlYXRlXHJcbi8vIGNhY2hlLW9ubHkgdmVyc2lvbnMgb2YgdGhlc2UgY29tcGlsZXJzXHJcbmxldCBhbGxDb21waWxlckNsYXNzZXMgPSBudWxsO1xyXG5cclxuZnVuY3Rpb24gc3RhdFN5bmNOb0V4Y2VwdGlvbihmc1BhdGgpIHtcclxuICBpZiAoJ3N0YXRTeW5jTm9FeGNlcHRpb24nIGluIGZzKSB7XHJcbiAgICByZXR1cm4gZnMuc3RhdFN5bmNOb0V4Y2VwdGlvbihmc1BhdGgpO1xyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIHJldHVybiBmcy5zdGF0U3luYyhmc1BhdGgpO1xyXG4gIH0gY2F0Y2ggKGUpIHtcclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxufVxyXG5cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplIHRoZSBnbG9iYWwgaG9va3MgKHByb3RvY29sIGhvb2sgZm9yIGZpbGU6LCBub2RlLmpzIGhvb2spXHJcbiAqIGluZGVwZW5kZW50IG9mIGluaXRpYWxpemluZyB0aGUgY29tcGlsZXIuIFRoaXMgbWV0aG9kIGlzIHVzdWFsbHkgY2FsbGVkIGJ5XHJcbiAqIGluaXQgaW5zdGVhZCBvZiBkaXJlY3RseVxyXG4gKlxyXG4gKiBAcGFyYW0ge0NvbXBpbGVySG9zdH0gY29tcGlsZXJIb3N0ICBUaGUgY29tcGlsZXIgaG9zdCB0byB1c2UuXHJcbiAqXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaW5pdGlhbGl6ZUdsb2JhbEhvb2tzKGNvbXBpbGVySG9zdCkge1xyXG4gIGxldCBnbG9iYWxWYXIgPSAoZ2xvYmFsIHx8IHdpbmRvdyk7XHJcbiAgZ2xvYmFsVmFyLmdsb2JhbENvbXBpbGVySG9zdCA9IGNvbXBpbGVySG9zdDtcclxuXHJcbiAgcmVnaXN0ZXJSZXF1aXJlRXh0ZW5zaW9uKGNvbXBpbGVySG9zdCk7XHJcblxyXG4gIGlmICgndHlwZScgaW4gcHJvY2VzcyAmJiBwcm9jZXNzLnR5cGUgPT09ICdicm93c2VyJykge1xyXG4gICAgY29uc3QgeyBhcHAgfSA9IHJlcXVpcmUoJ2VsZWN0cm9uJyk7XHJcbiAgICBjb25zdCB7IGluaXRpYWxpemVQcm90b2NvbEhvb2sgfSA9IHJlcXVpcmUoJy4vcHJvdG9jb2wtaG9vaycpO1xyXG5cclxuICAgIGxldCBwcm90b2lmeSA9IGZ1bmN0aW9uKCkgeyBpbml0aWFsaXplUHJvdG9jb2xIb29rKGNvbXBpbGVySG9zdCk7IH07XHJcbiAgICBpZiAoYXBwLmlzUmVhZHkoKSkge1xyXG4gICAgICBwcm90b2lmeSgpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgYXBwLm9uKCdyZWFkeScsIHByb3RvaWZ5KTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZSBlbGVjdHJvbi1jb21waWxlIGFuZCBzZXQgaXQgdXAsIGVpdGhlciBmb3IgZGV2ZWxvcG1lbnQgb3JcclxuICogcHJvZHVjdGlvbiB1c2UuIFRoaXMgaXMgYWxtb3N0IGFsd2F5cyB0aGUgb25seSBtZXRob2QgeW91IG5lZWQgdG8gdXNlIGluIG9yZGVyXHJcbiAqIHRvIHVzZSBlbGVjdHJvbi1jb21waWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0gIHtzdHJpbmd9IGFwcFJvb3QgIFRoZSB0b3AtbGV2ZWwgZGlyZWN0b3J5IGZvciB5b3VyIGFwcGxpY2F0aW9uIChpLmUuXHJcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIG9uZSB3aGljaCBoYXMgeW91ciBwYWNrYWdlLmpzb24pLlxyXG4gKlxyXG4gKiBAcGFyYW0gIHtzdHJpbmd9IG1haW5Nb2R1bGUgIFRoZSBtb2R1bGUgdG8gcmVxdWlyZSBpbiwgcmVsYXRpdmUgdG8gdGhlIG1vZHVsZVxyXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxpbmcgaW5pdCwgdGhhdCB3aWxsIHN0YXJ0IHlvdXIgYXBwLiBXcml0ZSB0aGlzXHJcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMgaWYgeW91IHdlcmUgd3JpdGluZyBhIHJlcXVpcmUgY2FsbCBmcm9tIGhlcmUuXHJcbiAqXHJcbiAqIEBwYXJhbSAge2Jvb2x9IHByb2R1Y3Rpb25Nb2RlICAgSWYgZXhwbGljaXRseSBUcnVlL0ZhbHNlLCB3aWxsIHNldCByZWFkLW9ubHlcclxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlIHRvIGJlIGRpc2FibGVkL2VuYWJsZWQuIElmIG5vdCwgd2UnbGxcclxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBndWVzcyBiYXNlZCBvbiB0aGUgcHJlc2VuY2Ugb2YgYSBwcm9kdWN0aW9uXHJcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FjaGUuXHJcbiAqXHJcbiAqIEBwYXJhbSAge3N0cmluZ30gY2FjaGVEaXIgIElmIG5vdCBwYXNzZWQgaW4sIHJlYWQtb25seSB3aWxsIGxvb2sgaW5cclxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgYGFwcFJvb3QvLmNhY2hlYCBhbmQgZGV2IG1vZGUgd2lsbCBjb21waWxlIHRvIGFcclxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVtcG9yYXJ5IGRpcmVjdG9yeS4gSWYgaXQgaXMgcGFzc2VkIGluLCBib3RoIG1vZGVzXHJcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpbGwgY2FjaGUgdG8vZnJvbSBgYXBwUm9vdC97Y2FjaGVEaXJ9YFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGluaXQoYXBwUm9vdCwgbWFpbk1vZHVsZSwgcHJvZHVjdGlvbk1vZGUgPSBudWxsLCBjYWNoZURpciA9IG51bGwpIHtcclxuICBsZXQgY29tcGlsZXJIb3N0ID0gbnVsbDtcclxuICBsZXQgcm9vdENhY2hlRGlyID0gcGF0aC5qb2luKGFwcFJvb3QsIGNhY2hlRGlyIHx8ICcuY2FjaGUnKTtcclxuXHJcbiAgaWYgKHByb2R1Y3Rpb25Nb2RlID09PSBudWxsKSB7XHJcbiAgICBwcm9kdWN0aW9uTW9kZSA9ICEhc3RhdFN5bmNOb0V4Y2VwdGlvbihyb290Q2FjaGVEaXIpO1xyXG4gIH1cclxuXHJcbiAgaWYgKHByb2R1Y3Rpb25Nb2RlKSB7XHJcbiAgICBjb21waWxlckhvc3QgPSBDb21waWxlckhvc3QuY3JlYXRlUmVhZG9ubHlGcm9tQ29uZmlndXJhdGlvblN5bmMocm9vdENhY2hlRGlyLCBhcHBSb290KTtcclxuICB9IGVsc2Uge1xyXG4gICAgLy8gaWYgY2FjaGVEaXIgd2FzIHBhc3NlZCBpbiwgcGFzcyBpdCBhbG9uZy4gT3RoZXJ3aXNlLCBkZWZhdWx0IHRvIGEgdGVtcGRpci5cclxuICAgIGlmIChjYWNoZURpcikge1xyXG4gICAgICBjb21waWxlckhvc3QgPSBjcmVhdGVDb21waWxlckhvc3RGcm9tUHJvamVjdFJvb3RTeW5jKGFwcFJvb3QsIHJvb3RDYWNoZURpcik7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjb21waWxlckhvc3QgPSBjcmVhdGVDb21waWxlckhvc3RGcm9tUHJvamVjdFJvb3RTeW5jKGFwcFJvb3QpO1xyXG4gICAgfVxyXG5cclxuICB9XHJcblxyXG4gIGluaXRpYWxpemVHbG9iYWxIb29rcyhjb21waWxlckhvc3QpO1xyXG4gIHJlcXVpcmUubWFpbi5yZXF1aXJlKG1haW5Nb2R1bGUpO1xyXG59XHJcblxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSB7QGxpbmsgQ29tcGlsZXJIb3N0fSB3aXRoIHRoZSBnaXZlbiBpbmZvcm1hdGlvbi4gVGhpcyBtZXRob2QgaXNcclxuICogdXN1YWxseSBjYWxsZWQgYnkge0BsaW5rIGNyZWF0ZUNvbXBpbGVySG9zdEZyb21Qcm9qZWN0Um9vdH0uXHJcbiAqXHJcbiAqIEBwcml2YXRlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlQ29tcGlsZXJIb3N0RnJvbUNvbmZpZ3VyYXRpb24oaW5mbykge1xyXG4gIGxldCBjb21waWxlcnMgPSBjcmVhdGVDb21waWxlcnMoKTtcclxuICBsZXQgcm9vdENhY2hlRGlyID0gaW5mby5yb290Q2FjaGVEaXIgfHwgY2FsY3VsYXRlRGVmYXVsdENvbXBpbGVDYWNoZURpcmVjdG9yeSgpO1xyXG5cclxuICBkKGBDcmVhdGluZyBDb21waWxlckhvc3Q6ICR7SlNPTi5zdHJpbmdpZnkoaW5mbyl9LCByb290Q2FjaGVEaXIgPSAke3Jvb3RDYWNoZURpcn1gKTtcclxuICBsZXQgZmlsZUNoYW5nZUNhY2hlID0gbmV3IEZpbGVDaGFuZ2VkQ2FjaGUoaW5mby5hcHBSb290KTtcclxuXHJcbiAgbGV0IGNvbXBpbGVySW5mbyA9IHBhdGguam9pbihyb290Q2FjaGVEaXIsICdjb21waWxlci1pbmZvLmpzb24uZ3onKTtcclxuICBpZiAoZnMuZXhpc3RzU3luYyhjb21waWxlckluZm8pKSB7XHJcbiAgICBsZXQgYnVmID0gZnMucmVhZEZpbGVTeW5jKGNvbXBpbGVySW5mbyk7XHJcbiAgICBsZXQganNvbiA9IEpTT04ucGFyc2UoemxpYi5ndW56aXBTeW5jKGJ1ZikpO1xyXG4gICAgZmlsZUNoYW5nZUNhY2hlID0gRmlsZUNoYW5nZWRDYWNoZS5sb2FkRnJvbURhdGEoanNvbi5maWxlQ2hhbmdlQ2FjaGUsIGluZm8uYXBwUm9vdCwgZmFsc2UpO1xyXG4gIH1cclxuXHJcbiAgT2JqZWN0LmtleXMoaW5mby5vcHRpb25zIHx8IHt9KS5mb3JFYWNoKCh4KSA9PiB7XHJcbiAgICBsZXQgb3B0cyA9IGluZm8ub3B0aW9uc1t4XTtcclxuICAgIGlmICghKHggaW4gY29tcGlsZXJzKSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEZvdW5kIGNvbXBpbGVyIHNldHRpbmdzIGZvciBtaXNzaW5nIGNvbXBpbGVyOiAke3h9YCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTkI6IExldCdzIGhvcGUgdGhpcyBpc24ndCBhIHZhbGlkIGNvbXBpbGVyIG9wdGlvbi4uLlxyXG4gICAgaWYgKG9wdHMucGFzc3Rocm91Z2gpIHtcclxuICAgICAgY29tcGlsZXJzW3hdID0gY29tcGlsZXJzWyd0ZXh0L3BsYWluJ107XHJcbiAgICAgIGRlbGV0ZSBvcHRzLnBhc3N0aHJvdWdoO1xyXG4gICAgfVxyXG5cclxuICAgIGQoYFNldHRpbmcgb3B0aW9ucyBmb3IgJHt4fTogJHtKU09OLnN0cmluZ2lmeShvcHRzKX1gKTtcclxuICAgIGNvbXBpbGVyc1t4XS5jb21waWxlck9wdGlvbnMgPSBvcHRzO1xyXG4gIH0pO1xyXG5cclxuICBsZXQgcmV0ID0gbmV3IENvbXBpbGVySG9zdChyb290Q2FjaGVEaXIsIGNvbXBpbGVycywgZmlsZUNoYW5nZUNhY2hlLCBmYWxzZSwgY29tcGlsZXJzWyd0ZXh0L3BsYWluJ10pO1xyXG5cclxuICAvLyBOQjogSXQncyBzdXBlciBpbXBvcnRhbnQgdGhhdCB3ZSBndWFyYW50ZWUgdGhhdCB0aGUgY29uZmlndXJhdGlvbiBpcyBzYXZlZFxyXG4gIC8vIG91dCwgYmVjYXVzZSB3ZSdsbCBuZWVkIHRvIHJlLXJlYWQgaXQgaW4gdGhlIHJlbmRlcmVyIHByb2Nlc3NcclxuICBkKGBDcmVhdGVkIGNvbXBpbGVyIGhvc3Qgd2l0aCBvcHRpb25zOiAke0pTT04uc3RyaW5naWZ5KGluZm8pfWApO1xyXG4gIHJldC5zYXZlQ29uZmlndXJhdGlvblN5bmMoKTtcclxuICByZXR1cm4gcmV0O1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGNvbXBpbGVyIGhvc3QgZnJvbSBhIC5iYWJlbHJjIGZpbGUuIFRoaXMgbWV0aG9kIGlzIHVzdWFsbHkgY2FsbGVkXHJcbiAqIGZyb20ge0BsaW5rIGNyZWF0ZUNvbXBpbGVySG9zdEZyb21Qcm9qZWN0Um9vdH0gaW5zdGVhZCBvZiB1c2VkIGRpcmVjdGx5LlxyXG4gKlxyXG4gKiBAcGFyYW0gIHtzdHJpbmd9IGZpbGUgIFRoZSBwYXRoIHRvIGEgLmJhYmVscmMgZmlsZVxyXG4gKlxyXG4gKiBAcGFyYW0gIHtzdHJpbmd9IHJvb3RDYWNoZURpciAob3B0aW9uYWwpICBUaGUgZGlyZWN0b3J5IHRvIHVzZSBhcyBhIGNhY2hlLlxyXG4gKlxyXG4gKiBAcmV0dXJuIHtQcm9taXNlPENvbXBpbGVySG9zdD59ICBBIHNldC11cCBjb21waWxlciBob3N0XHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlQ29tcGlsZXJIb3N0RnJvbUJhYmVsUmMoZmlsZSwgcm9vdENhY2hlRGlyPW51bGwpIHtcclxuICBsZXQgaW5mbyA9IEpTT04ucGFyc2UoYXdhaXQgcGZzLnJlYWRGaWxlKGZpbGUsICd1dGY4JykpO1xyXG5cclxuICAvLyBwYWNrYWdlLmpzb25cclxuICBpZiAoJ2JhYmVsJyBpbiBpbmZvKSB7XHJcbiAgICBpbmZvID0gaW5mby5iYWJlbDtcclxuICB9XHJcblxyXG4gIGlmICgnZW52JyBpbiBpbmZvKSB7XHJcbiAgICBsZXQgb3VyRW52ID0gcHJvY2Vzcy5lbnYuQkFCRUxfRU5WIHx8IHByb2Nlc3MuZW52Lk5PREVfRU5WIHx8ICdkZXZlbG9wbWVudCc7XHJcbiAgICBpbmZvID0gaW5mby5lbnZbb3VyRW52XTtcclxuICB9XHJcblxyXG4gIC8vIEFyZSB3ZSBzdGlsbCBwYWNrYWdlLmpzb24gKGkuZS4gaXMgdGhlcmUgbm8gYmFiZWwgaW5mbyB3aGF0c29ldmVyPylcclxuICBpZiAoJ25hbWUnIGluIGluZm8gJiYgJ3ZlcnNpb24nIGluIGluZm8pIHtcclxuICAgIHJldHVybiBjcmVhdGVDb21waWxlckhvc3RGcm9tQ29uZmlndXJhdGlvbih7XHJcbiAgICAgIGFwcFJvb3Q6IHBhdGguZGlybmFtZShmaWxlKSxcclxuICAgICAgb3B0aW9uczogZ2V0RGVmYXVsdENvbmZpZ3VyYXRpb24oKSxcclxuICAgICAgcm9vdENhY2hlRGlyXHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHJldHVybiBjcmVhdGVDb21waWxlckhvc3RGcm9tQ29uZmlndXJhdGlvbih7XHJcbiAgICBhcHBSb290OiBwYXRoLmRpcm5hbWUoZmlsZSksXHJcbiAgICBvcHRpb25zOiB7XHJcbiAgICAgICdhcHBsaWNhdGlvbi9qYXZhc2NyaXB0JzogaW5mb1xyXG4gICAgfSxcclxuICAgIHJvb3RDYWNoZURpclxyXG4gIH0pO1xyXG59XHJcblxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBjb21waWxlciBob3N0IGZyb20gYSAuY29tcGlsZXJjIGZpbGUuIFRoaXMgbWV0aG9kIGlzIHVzdWFsbHkgY2FsbGVkXHJcbiAqIGZyb20ge0BsaW5rIGNyZWF0ZUNvbXBpbGVySG9zdEZyb21Qcm9qZWN0Um9vdH0gaW5zdGVhZCBvZiB1c2VkIGRpcmVjdGx5LlxyXG4gKlxyXG4gKiBAcGFyYW0gIHtzdHJpbmd9IGZpbGUgIFRoZSBwYXRoIHRvIGEgLmNvbXBpbGVyYyBmaWxlXHJcbiAqXHJcbiAqIEBwYXJhbSAge3N0cmluZ30gcm9vdENhY2hlRGlyIChvcHRpb25hbCkgIFRoZSBkaXJlY3RvcnkgdG8gdXNlIGFzIGEgY2FjaGUuXHJcbiAqXHJcbiAqIEByZXR1cm4ge1Byb21pc2U8Q29tcGlsZXJIb3N0Pn0gIEEgc2V0LXVwIGNvbXBpbGVyIGhvc3RcclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVDb21waWxlckhvc3RGcm9tQ29uZmlnRmlsZShmaWxlLCByb290Q2FjaGVEaXI9bnVsbCkge1xyXG4gIGxldCBpbmZvID0gSlNPTi5wYXJzZShhd2FpdCBwZnMucmVhZEZpbGUoZmlsZSwgJ3V0ZjgnKSk7XHJcblxyXG4gIGlmICgnZW52JyBpbiBpbmZvKSB7XHJcbiAgICBsZXQgb3VyRW52ID0gcHJvY2Vzcy5lbnYuRUxFQ1RST05fQ09NUElMRV9FTlYgfHwgcHJvY2Vzcy5lbnYuTk9ERV9FTlYgfHwgJ2RldmVsb3BtZW50JztcclxuICAgIGluZm8gPSBpbmZvLmVudltvdXJFbnZdO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGNyZWF0ZUNvbXBpbGVySG9zdEZyb21Db25maWd1cmF0aW9uKHtcclxuICAgIGFwcFJvb3Q6IHBhdGguZGlybmFtZShmaWxlKSxcclxuICAgIG9wdGlvbnM6IGluZm8sXHJcbiAgICByb290Q2FjaGVEaXJcclxuICB9KTtcclxufVxyXG5cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgY29uZmlndXJlZCB7QGxpbmsgQ29tcGlsZXJIb3N0fSBpbnN0YW5jZSBmcm9tIHRoZSBwcm9qZWN0IHJvb3RcclxuICogZGlyZWN0b3J5LiBUaGlzIG1ldGhvZCBmaXJzdCBzZWFyY2hlcyBmb3IgYSAuY29tcGlsZXJjIChvciAuY29tcGlsZXJjLmpzb24pLCB0aGVuIGZhbGxzIGJhY2sgdG8gdGhlXHJcbiAqIGRlZmF1bHQgbG9jYXRpb25zIGZvciBCYWJlbCBjb25maWd1cmF0aW9uIGluZm8uIElmIG5laXRoZXIgYXJlIGZvdW5kLCBkZWZhdWx0c1xyXG4gKiB0byBzdGFuZGFyZCBzZXR0aW5nc1xyXG4gKlxyXG4gKiBAcGFyYW0gIHtzdHJpbmd9IHJvb3REaXIgIFRoZSByb290IGFwcGxpY2F0aW9uIGRpcmVjdG9yeSAoaS5lLiB0aGUgZGlyZWN0b3J5XHJcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhhdCBoYXMgdGhlIGFwcCdzIHBhY2thZ2UuanNvbilcclxuICpcclxuICogQHBhcmFtICB7c3RyaW5nfSByb290Q2FjaGVEaXIgKG9wdGlvbmFsKSAgVGhlIGRpcmVjdG9yeSB0byB1c2UgYXMgYSBjYWNoZS5cclxuICpcclxuICogQHJldHVybiB7UHJvbWlzZTxDb21waWxlckhvc3Q+fSAgQSBzZXQtdXAgY29tcGlsZXIgaG9zdFxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUNvbXBpbGVySG9zdEZyb21Qcm9qZWN0Um9vdChyb290RGlyLCByb290Q2FjaGVEaXI9bnVsbCkge1xyXG4gIGxldCBjb21waWxlcmMgPSBwYXRoLmpvaW4ocm9vdERpciwgJy5jb21waWxlcmMnKTtcclxuICBpZiAoc3RhdFN5bmNOb0V4Y2VwdGlvbihjb21waWxlcmMpKSB7XHJcbiAgICBkKGBGb3VuZCBhIC5jb21waWxlcmMgYXQgJHtjb21waWxlcmN9LCB1c2luZyBpdGApO1xyXG4gICAgcmV0dXJuIGF3YWl0IGNyZWF0ZUNvbXBpbGVySG9zdEZyb21Db25maWdGaWxlKGNvbXBpbGVyYywgcm9vdENhY2hlRGlyKTtcclxuICB9XHJcbiAgY29tcGlsZXJjICs9ICcuanNvbic7XHJcbiAgaWYgKHN0YXRTeW5jTm9FeGNlcHRpb24oY29tcGlsZXJjKSkge1xyXG4gICAgZChgRm91bmQgYSAuY29tcGlsZXJjIGF0ICR7Y29tcGlsZXJjfSwgdXNpbmcgaXRgKTtcclxuICAgIHJldHVybiBhd2FpdCBjcmVhdGVDb21waWxlckhvc3RGcm9tQ29uZmlnRmlsZShjb21waWxlcmMsIHJvb3RDYWNoZURpcik7XHJcbiAgfVxyXG5cclxuICBsZXQgYmFiZWxyYyA9IHBhdGguam9pbihyb290RGlyLCAnLmJhYmVscmMnKTtcclxuICBpZiAoc3RhdFN5bmNOb0V4Y2VwdGlvbihiYWJlbHJjKSkge1xyXG4gICAgZChgRm91bmQgYSAuYmFiZWxyYyBhdCAke2JhYmVscmN9LCB1c2luZyBpdGApO1xyXG4gICAgcmV0dXJuIGF3YWl0IGNyZWF0ZUNvbXBpbGVySG9zdEZyb21CYWJlbFJjKGJhYmVscmMsIHJvb3RDYWNoZURpcik7XHJcbiAgfVxyXG5cclxuICBkKGBVc2luZyBwYWNrYWdlLmpzb24gb3IgZGVmYXVsdCBwYXJhbWV0ZXJzIGF0ICR7cm9vdERpcn1gKTtcclxuICByZXR1cm4gYXdhaXQgY3JlYXRlQ29tcGlsZXJIb3N0RnJvbUJhYmVsUmMocGF0aC5qb2luKHJvb3REaXIsICdwYWNrYWdlLmpzb24nKSwgcm9vdENhY2hlRGlyKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUNvbXBpbGVySG9zdEZyb21CYWJlbFJjU3luYyhmaWxlLCByb290Q2FjaGVEaXI9bnVsbCkge1xyXG4gIGxldCBpbmZvID0gSlNPTi5wYXJzZShmcy5yZWFkRmlsZVN5bmMoZmlsZSwgJ3V0ZjgnKSk7XHJcblxyXG4gIC8vIHBhY2thZ2UuanNvblxyXG4gIGlmICgnYmFiZWwnIGluIGluZm8pIHtcclxuICAgIGluZm8gPSBpbmZvLmJhYmVsO1xyXG4gIH1cclxuXHJcbiAgaWYgKCdlbnYnIGluIGluZm8pIHtcclxuICAgIGxldCBvdXJFbnYgPSBwcm9jZXNzLmVudi5CQUJFTF9FTlYgfHwgcHJvY2Vzcy5lbnYuTk9ERV9FTlYgfHwgJ2RldmVsb3BtZW50JztcclxuICAgIGluZm8gPSBpbmZvLmVudltvdXJFbnZdO1xyXG4gIH1cclxuXHJcbiAgLy8gQXJlIHdlIHN0aWxsIHBhY2thZ2UuanNvbiAoaS5lLiBpcyB0aGVyZSBubyBiYWJlbCBpbmZvIHdoYXRzb2V2ZXI/KVxyXG4gIGlmICgnbmFtZScgaW4gaW5mbyAmJiAndmVyc2lvbicgaW4gaW5mbykge1xyXG4gICAgcmV0dXJuIGNyZWF0ZUNvbXBpbGVySG9zdEZyb21Db25maWd1cmF0aW9uKHtcclxuICAgICAgYXBwUm9vdDogcGF0aC5kaXJuYW1lKGZpbGUpLFxyXG4gICAgICBvcHRpb25zOiBnZXREZWZhdWx0Q29uZmlndXJhdGlvbigpLFxyXG4gICAgICByb290Q2FjaGVEaXJcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGNyZWF0ZUNvbXBpbGVySG9zdEZyb21Db25maWd1cmF0aW9uKHtcclxuICAgIGFwcFJvb3Q6IHBhdGguZGlybmFtZShmaWxlKSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgJ2FwcGxpY2F0aW9uL2phdmFzY3JpcHQnOiBpbmZvXHJcbiAgICB9LFxyXG4gICAgcm9vdENhY2hlRGlyXHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVDb21waWxlckhvc3RGcm9tQ29uZmlnRmlsZVN5bmMoZmlsZSwgcm9vdENhY2hlRGlyPW51bGwpIHtcclxuICBsZXQgaW5mbyA9IEpTT04ucGFyc2UoZnMucmVhZEZpbGVTeW5jKGZpbGUsICd1dGY4JykpO1xyXG5cclxuICBpZiAoJ2VudicgaW4gaW5mbykge1xyXG4gICAgbGV0IG91ckVudiA9IHByb2Nlc3MuZW52LkVMRUNUUk9OX0NPTVBJTEVfRU5WIHx8IHByb2Nlc3MuZW52Lk5PREVfRU5WIHx8ICdkZXZlbG9wbWVudCc7XHJcbiAgICBpbmZvID0gaW5mby5lbnZbb3VyRW52XTtcclxuICB9XHJcblxyXG4gIHJldHVybiBjcmVhdGVDb21waWxlckhvc3RGcm9tQ29uZmlndXJhdGlvbih7XHJcbiAgICBhcHBSb290OiBwYXRoLmRpcm5hbWUoZmlsZSksXHJcbiAgICBvcHRpb25zOiBpbmZvLFxyXG4gICAgcm9vdENhY2hlRGlyXHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVDb21waWxlckhvc3RGcm9tUHJvamVjdFJvb3RTeW5jKHJvb3REaXIsIHJvb3RDYWNoZURpcj1udWxsKSB7XHJcbiAgbGV0IGNvbXBpbGVyYyA9IHBhdGguam9pbihyb290RGlyLCAnLmNvbXBpbGVyYycpO1xyXG4gIGlmIChzdGF0U3luY05vRXhjZXB0aW9uKGNvbXBpbGVyYykpIHtcclxuICAgIGQoYEZvdW5kIGEgLmNvbXBpbGVyYyBhdCAke2NvbXBpbGVyY30sIHVzaW5nIGl0YCk7XHJcbiAgICByZXR1cm4gY3JlYXRlQ29tcGlsZXJIb3N0RnJvbUNvbmZpZ0ZpbGVTeW5jKGNvbXBpbGVyYywgcm9vdENhY2hlRGlyKTtcclxuICB9XHJcblxyXG4gIGxldCBiYWJlbHJjID0gcGF0aC5qb2luKHJvb3REaXIsICcuYmFiZWxyYycpO1xyXG4gIGlmIChzdGF0U3luY05vRXhjZXB0aW9uKGJhYmVscmMpKSB7XHJcbiAgICBkKGBGb3VuZCBhIC5iYWJlbHJjIGF0ICR7YmFiZWxyY30sIHVzaW5nIGl0YCk7XHJcbiAgICByZXR1cm4gY3JlYXRlQ29tcGlsZXJIb3N0RnJvbUJhYmVsUmNTeW5jKGJhYmVscmMsIHJvb3RDYWNoZURpcik7XHJcbiAgfVxyXG5cclxuICBkKGBVc2luZyBwYWNrYWdlLmpzb24gb3IgZGVmYXVsdCBwYXJhbWV0ZXJzIGF0ICR7cm9vdERpcn1gKTtcclxuICByZXR1cm4gY3JlYXRlQ29tcGlsZXJIb3N0RnJvbUJhYmVsUmNTeW5jKHBhdGguam9pbihyb290RGlyLCAncGFja2FnZS5qc29uJyksIHJvb3RDYWNoZURpcik7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXR1cm5zIHdoYXQgZWxlY3Ryb24tY29tcGlsZSB3b3VsZCB1c2UgYXMgYSBkZWZhdWx0IHJvb3RDYWNoZURpci4gVXN1YWxseSBvbmx5XHJcbiAqIHVzZWQgZm9yIGRlYnVnZ2luZyBwdXJwb3Nlc1xyXG4gKlxyXG4gKiBAcmV0dXJuIHtzdHJpbmd9ICBBIHBhdGggdGhhdCBtYXkgb3IgbWF5IG5vdCBleGlzdCB3aGVyZSBlbGVjdHJvbi1jb21waWxlIHdvdWxkXHJcbiAqICAgICAgICAgICAgICAgICAgIHNldCB1cCBhIGRldmVsb3BtZW50IG1vZGUgY2FjaGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gY2FsY3VsYXRlRGVmYXVsdENvbXBpbGVDYWNoZURpcmVjdG9yeSgpIHtcclxuICBsZXQgdG1wRGlyID0gcHJvY2Vzcy5lbnYuVEVNUCB8fCBwcm9jZXNzLmVudi5UTVBESVIgfHwgJy90bXAnO1xyXG4gIGxldCBoYXNoID0gcmVxdWlyZSgnY3J5cHRvJykuY3JlYXRlSGFzaCgnbWQ1JykudXBkYXRlKHByb2Nlc3MuZXhlY1BhdGgpLmRpZ2VzdCgnaGV4Jyk7XHJcblxyXG4gIGxldCBjYWNoZURpciA9IHBhdGguam9pbih0bXBEaXIsIGBjb21waWxlQ2FjaGVfJHtoYXNofWApO1xyXG4gIG1rZGlycC5zeW5jKGNhY2hlRGlyKTtcclxuXHJcbiAgZChgVXNpbmcgZGVmYXVsdCBjYWNoZSBkaXJlY3Rvcnk6ICR7Y2FjaGVEaXJ9YCk7XHJcbiAgcmV0dXJuIGNhY2hlRGlyO1xyXG59XHJcblxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIGRlZmF1bHQgLmNvbmZpZ3JjIGlmIG5vIGNvbmZpZ3VyYXRpb24gaW5mb3JtYXRpb24gY2FuIGJlIGZvdW5kLlxyXG4gKlxyXG4gKiBAcmV0dXJuIHtPYmplY3R9ICBBIGxpc3Qgb2YgZGVmYXVsdCBjb25maWcgc2V0dGluZ3MgZm9yIGVsZWN0cm9uLWNvbXBpbGVyLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldERlZmF1bHRDb25maWd1cmF0aW9uKCkge1xyXG4gIHJldHVybiB7XHJcbiAgICAnYXBwbGljYXRpb24vamF2YXNjcmlwdCc6IHtcclxuICAgICAgXCJwcmVzZXRzXCI6IFtcImVzMjAxNi1ub2RlNVwiLCBcInJlYWN0XCJdLFxyXG4gICAgICBcInNvdXJjZU1hcHNcIjogXCJpbmxpbmVcIlxyXG4gICAgfVxyXG4gIH07XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBbGxvd3MgeW91IHRvIGNyZWF0ZSBuZXcgaW5zdGFuY2VzIG9mIGFsbCBjb21waWxlcnMgdGhhdCBhcmUgc3VwcG9ydGVkIGJ5XHJcbiAqIGVsZWN0cm9uLWNvbXBpbGUgYW5kIHVzZSB0aGVtIGRpcmVjdGx5LiBDdXJyZW50bHkgc3VwcG9ydHMgQmFiZWwsIENvZmZlZVNjcmlwdCxcclxuICogVHlwZVNjcmlwdCwgTGVzcywgYW5kIEphZGUuXHJcbiAqXHJcbiAqIEByZXR1cm4ge09iamVjdH0gIEFuIE9iamVjdCB3aG9zZSBLZXlzIGFyZSBNSU1FIHR5cGVzLCBhbmQgd2hvc2UgdmFsdWVzXHJcbiAqIGFyZSBpbnN0YW5jZXMgb2YgQHtsaW5rIENvbXBpbGVyQmFzZX0uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlQ29tcGlsZXJzKCkge1xyXG4gIGlmICghYWxsQ29tcGlsZXJDbGFzc2VzKSB7XHJcbiAgICAvLyBGaXJzdCB3ZSB3YW50IHRvIHNlZSBpZiBlbGVjdHJvbi1jb21waWxlcnMgaXRzZWxmIGhhcyBiZWVuIGluc3RhbGxlZCB3aXRoXHJcbiAgICAvLyBkZXZEZXBlbmRlbmNpZXMuIElmIHRoYXQncyBub3QgdGhlIGNhc2UsIGNoZWNrIHRvIHNlZSBpZlxyXG4gICAgLy8gZWxlY3Ryb24tY29tcGlsZXJzIGlzIGluc3RhbGxlZCBhcyBhIHBlZXIgZGVwZW5kZW5jeSAocHJvYmFibHkgYXMgYVxyXG4gICAgLy8gZGV2RGVwZW5kZW5jeSBvZiB0aGUgcm9vdCBwcm9qZWN0KS5cclxuICAgIGNvbnN0IGxvY2F0aW9ucyA9IFsnZWxlY3Ryb24tY29tcGlsZXJzJywgJy4uLy4uL2VsZWN0cm9uLWNvbXBpbGVycyddO1xyXG5cclxuICAgIGZvciAobGV0IGxvY2F0aW9uIG9mIGxvY2F0aW9ucykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGFsbENvbXBpbGVyQ2xhc3NlcyA9IHJlcXVpcmUobG9jYXRpb24pO1xyXG4gICAgICB9IGNhdGNoIChlKSB7XHJcbiAgICAgICAgLy8gWW9sb1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFhbGxDb21waWxlckNsYXNzZXMpIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRWxlY3Ryb24gY29tcGlsZXJzIG5vdCBmb3VuZCBidXQgd2VyZSByZXF1ZXN0ZWQgdG8gYmUgbG9hZGVkXCIpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTkI6IE5vdGUgdGhhdCB0aGlzIGNvZGUgaXMgY2FyZWZ1bGx5IHNldCB1cCBzbyB0aGF0IElubGluZUh0bWxDb21waWxlclxyXG4gIC8vIChpLmUuIGNsYXNzZXMgd2l0aCBgY3JlYXRlRnJvbUNvbXBpbGVyc2ApIGluaXRpYWxseSBnZXQgYW4gZW1wdHkgb2JqZWN0LFxyXG4gIC8vIGJ1dCB3aWxsIGhhdmUgYSByZWZlcmVuY2UgdG8gdGhlIGZpbmFsIHJlc3VsdCBvZiB3aGF0IHdlIHJldHVybiwgd2hpY2hcclxuICAvLyByZXNvbHZlcyB0aGUgY2lyY3VsYXIgZGVwZW5kZW5jeSB3ZSdkIG90aGVyd2lzZSBoYXZlIGhlcmUuXHJcbiAgbGV0IHJldCA9IHt9O1xyXG4gIGxldCBpbnN0YW50aWF0ZWRDbGFzc2VzID0gYWxsQ29tcGlsZXJDbGFzc2VzLm1hcCgoS2xhc3MpID0+IHtcclxuICAgIGlmICgnY3JlYXRlRnJvbUNvbXBpbGVycycgaW4gS2xhc3MpIHtcclxuICAgICAgcmV0dXJuIEtsYXNzLmNyZWF0ZUZyb21Db21waWxlcnMocmV0KTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHJldHVybiBuZXcgS2xhc3MoKTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgaW5zdGFudGlhdGVkQ2xhc3Nlcy5yZWR1Y2UoKGFjYyx4KSA9PiB7XHJcbiAgICBsZXQgS2xhc3MgPSBPYmplY3QuZ2V0UHJvdG90eXBlT2YoeCkuY29uc3RydWN0b3I7XHJcblxyXG4gICAgZm9yIChsZXQgdHlwZSBvZiBLbGFzcy5nZXRJbnB1dE1pbWVUeXBlcygpKSB7IGFjY1t0eXBlXSA9IHg7IH1cclxuICAgIHJldHVybiBhY2M7XHJcbiAgfSwgcmV0KTtcclxuXHJcbiAgcmV0dXJuIHJldDtcclxufVxyXG4iXX0=