electron-compile
Version:
Electron supporting package to compile JS and CSS in Electron applications
528 lines (417 loc) • 40.2 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _stringify = require('babel-runtime/core-js/json/stringify');
var _stringify2 = _interopRequireDefault(_stringify);
var _regenerator = require('babel-runtime/regenerator');
var _regenerator2 = _interopRequireDefault(_regenerator);
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
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 _digestForObject = require('./digest-for-object');
var _digestForObject2 = _interopRequireDefault(_digestForObject);
var _promise = require('./promise');
var _mkdirp = require('mkdirp');
var _mkdirp2 = _interopRequireDefault(_mkdirp);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var d = require('debug-electron')('electron-compile:compile-cache');
/**
* CompileCache manages getting and setting entries for a single compiler; each
* in-use compiler will have an instance of this class, usually created via
* {@link createFromCompiler}.
*
* You usually will not use this class directly, it is an implementation class
* for {@link CompileHost}.
*/
var CompileCache = function () {
/**
* Creates an instance, usually used for testing only.
*
* @param {string} cachePath The root directory to use as a cache path
*
* @param {FileChangedCache} fileChangeCache A file-change cache that is
* optionally pre-loaded.
*/
function CompileCache(cachePath, fileChangeCache) {
(0, _classCallCheck3.default)(this, CompileCache);
this.cachePath = cachePath;
this.fileChangeCache = fileChangeCache;
}
/**
* Creates a CompileCache from a class compatible with the CompilerBase
* interface. This method uses the compiler name / version / options to
* generate a unique directory name for cached results
*
* @param {string} cachePath The root path to use for the cache, a directory
* representing the hash of the compiler parameters
* will be created here.
*
* @param {CompilerBase} compiler The compiler to use for version / option
* information.
*
* @param {FileChangedCache} fileChangeCache A file-change cache that is
* optionally pre-loaded.
*
* @param {boolean} readOnlyMode Don't attempt to create the cache directory.
*
* @return {CompileCache} A configured CompileCache instance.
*/
(0, _createClass3.default)(CompileCache, [{
key: 'get',
/**
* Returns a file's compiled contents from the cache.
*
* @param {string} filePath The path to the file. FileChangedCache will look
* up the hash and use that as the key in the cache.
*
* @return {Promise<Object>} An object with all kinds of information
*
* @property {Object} hashInfo The hash information returned from getHashForPath
* @property {string} code The source code if the file was a text file
* @property {Buffer} binaryData The file if it was a binary file
* @property {string} mimeType The MIME type saved in the cache.
* @property {string[]} dependentFiles The dependent files returned from
* compiling the file, if any.
*/
value: function () {
var _ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee(filePath) {
var hashInfo, code, mimeType, binaryData, dependentFiles, cacheFile, result, info, buf, str;
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
d('Fetching ' + filePath + ' from cache');
_context.next = 3;
return this.fileChangeCache.getHashForPath(_path2.default.resolve(filePath));
case 3:
hashInfo = _context.sent;
code = null;
mimeType = null;
binaryData = null;
dependentFiles = null;
cacheFile = null;
_context.prev = 9;
cacheFile = _path2.default.join(this.getCachePath(), hashInfo.hash);
result = null;
if (!hashInfo.isFileBinary) {
_context.next = 31;
break;
}
d("File is binary, reading out info");
_context.t0 = JSON;
_context.next = 17;
return _promise.pfs.readFile(cacheFile + '.info');
case 17:
_context.t1 = _context.sent;
info = _context.t0.parse.call(_context.t0, _context.t1);
mimeType = info.mimeType;
dependentFiles = info.dependentFiles;
binaryData = hashInfo.binaryData;
if (binaryData) {
_context.next = 29;
break;
}
_context.next = 25;
return _promise.pfs.readFile(cacheFile);
case 25:
binaryData = _context.sent;
_context.next = 28;
return _promise.pzlib.gunzip(binaryData);
case 28:
binaryData = _context.sent;
case 29:
_context.next = 41;
break;
case 31:
_context.next = 33;
return _promise.pfs.readFile(cacheFile);
case 33:
buf = _context.sent;
_context.next = 36;
return _promise.pzlib.gunzip(buf);
case 36:
str = _context.sent.toString('utf8');
result = JSON.parse(str);
code = result.code;
mimeType = result.mimeType;
dependentFiles = result.dependentFiles;
case 41:
_context.next = 46;
break;
case 43:
_context.prev = 43;
_context.t2 = _context['catch'](9);
d('Failed to read cache for ' + filePath + ', looked in ' + cacheFile + ': ' + _context.t2.message);
case 46:
return _context.abrupt('return', { hashInfo: hashInfo, code: code, mimeType: mimeType, binaryData: binaryData, dependentFiles: dependentFiles });
case 47:
case 'end':
return _context.stop();
}
}
}, _callee, this, [[9, 43]]);
}));
function get(_x) {
return _ref.apply(this, arguments);
}
return get;
}()
/**
* Saves a compiled result to cache
*
* @param {Object} hashInfo The hash information returned from getHashForPath
*
* @param {string / Buffer} codeOrBinaryData The file's contents, either as
* a string or a Buffer.
* @param {string} mimeType The MIME type returned by the compiler.
*
* @param {string[]} dependentFiles The list of dependent files returned by
* the compiler.
* @return {Promise} Completion.
*/
}, {
key: 'save',
value: function () {
var _ref2 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee2(hashInfo, codeOrBinaryData, mimeType, dependentFiles) {
var buf, target;
return _regenerator2.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
buf = null;
target = _path2.default.join(this.getCachePath(), hashInfo.hash);
d('Saving to ' + target);
if (!hashInfo.isFileBinary) {
_context2.next = 11;
break;
}
_context2.next = 6;
return _promise.pzlib.gzip(codeOrBinaryData);
case 6:
buf = _context2.sent;
_context2.next = 9;
return _promise.pfs.writeFile(target + '.info', (0, _stringify2.default)({ mimeType: mimeType, dependentFiles: dependentFiles }), 'utf8');
case 9:
_context2.next = 14;
break;
case 11:
_context2.next = 13;
return _promise.pzlib.gzip(new Buffer((0, _stringify2.default)({ code: codeOrBinaryData, mimeType: mimeType, dependentFiles: dependentFiles })));
case 13:
buf = _context2.sent;
case 14:
_context2.next = 16;
return _promise.pfs.writeFile(target, buf);
case 16:
case 'end':
return _context2.stop();
}
}
}, _callee2, this);
}));
function save(_x2, _x3, _x4, _x5) {
return _ref2.apply(this, arguments);
}
return save;
}()
/**
* Attempts to first get a key via {@link get}, then if it fails, call a method
* to retrieve the contents, then save the result to cache.
*
* The fetcher parameter is expected to have the signature:
*
* Promise<Object> fetcher(filePath : string, hashInfo : Object);
*
* hashInfo is a value returned from getHashForPath
* The return value of fetcher must be an Object with the properties:
*
* mimeType - the MIME type of the data to save
* code (optional) - the source code as a string, if file is text
* binaryData (optional) - the file contents as a Buffer, if file is binary
* dependentFiles - the dependent files returned by the compiler.
*
* @param {string} filePath The path to the file. FileChangedCache will look
* up the hash and use that as the key in the cache.
*
* @param {Function} fetcher A method which conforms to the description above.
*
* @return {Promise<Object>} An Object which has the same fields as the
* {@link get} method return result.
*/
}, {
key: 'getOrFetch',
value: function () {
var _ref3 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee3(filePath, fetcher) {
var cacheResult, result;
return _regenerator2.default.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
_context3.next = 2;
return this.get(filePath);
case 2:
cacheResult = _context3.sent;
if (!(cacheResult.code || cacheResult.binaryData)) {
_context3.next = 5;
break;
}
return _context3.abrupt('return', cacheResult);
case 5:
_context3.next = 7;
return fetcher(filePath, cacheResult.hashInfo);
case 7:
_context3.t0 = _context3.sent;
if (_context3.t0) {
_context3.next = 10;
break;
}
_context3.t0 = { hashInfo: cacheResult.hashInfo };
case 10:
result = _context3.t0;
if (!(result.mimeType && !cacheResult.hashInfo.isInNodeModules)) {
_context3.next = 15;
break;
}
d('Cache miss: saving out info for ' + filePath);
_context3.next = 15;
return this.save(cacheResult.hashInfo, result.code || result.binaryData, result.mimeType, result.dependentFiles);
case 15:
result.hashInfo = cacheResult.hashInfo;
return _context3.abrupt('return', result);
case 17:
case 'end':
return _context3.stop();
}
}
}, _callee3, this);
}));
function getOrFetch(_x6, _x7) {
return _ref3.apply(this, arguments);
}
return getOrFetch;
}()
}, {
key: 'getSync',
value: function getSync(filePath) {
d('Fetching ' + filePath + ' from cache');
var hashInfo = this.fileChangeCache.getHashForPathSync(_path2.default.resolve(filePath));
var code = null;
var mimeType = null;
var binaryData = null;
var dependentFiles = null;
try {
var cacheFile = _path2.default.join(this.getCachePath(), hashInfo.hash);
var result = null;
if (hashInfo.isFileBinary) {
d("File is binary, reading out info");
var info = JSON.parse(_fs2.default.readFileSync(cacheFile + '.info'));
mimeType = info.mimeType;
dependentFiles = info.dependentFiles;
binaryData = hashInfo.binaryData;
if (!binaryData) {
binaryData = _fs2.default.readFileSync(cacheFile);
binaryData = _zlib2.default.gunzipSync(binaryData);
}
} else {
var buf = _fs2.default.readFileSync(cacheFile);
var str = _zlib2.default.gunzipSync(buf).toString('utf8');
result = JSON.parse(str);
code = result.code;
mimeType = result.mimeType;
dependentFiles = result.dependentFiles;
}
} catch (e) {
d('Failed to read cache for ' + filePath);
}
return { hashInfo: hashInfo, code: code, mimeType: mimeType, binaryData: binaryData, dependentFiles: dependentFiles };
}
}, {
key: 'saveSync',
value: function saveSync(hashInfo, codeOrBinaryData, mimeType, dependentFiles) {
var buf = null;
var target = _path2.default.join(this.getCachePath(), hashInfo.hash);
d('Saving to ' + target);
if (hashInfo.isFileBinary) {
buf = _zlib2.default.gzipSync(codeOrBinaryData);
_fs2.default.writeFileSync(target + '.info', (0, _stringify2.default)({ mimeType: mimeType, dependentFiles: dependentFiles }), 'utf8');
} else {
buf = _zlib2.default.gzipSync(new Buffer((0, _stringify2.default)({ code: codeOrBinaryData, mimeType: mimeType, dependentFiles: dependentFiles })));
}
_fs2.default.writeFileSync(target, buf);
}
}, {
key: 'getOrFetchSync',
value: function getOrFetchSync(filePath, fetcher) {
var cacheResult = this.getSync(filePath);
if (cacheResult.code || cacheResult.binaryData) return cacheResult;
var result = fetcher(filePath, cacheResult.hashInfo) || { hashInfo: cacheResult.hashInfo };
if (result.mimeType && !cacheResult.hashInfo.isInNodeModules) {
d('Cache miss: saving out info for ' + filePath);
this.saveSync(cacheResult.hashInfo, result.code || result.binaryData, result.mimeType, result.dependentFiles);
}
result.hashInfo = cacheResult.hashInfo;
return result;
}
/**
* @private
*/
}, {
key: 'getCachePath',
value: function getCachePath() {
// NB: This is an evil hack so that createFromCompiler can stomp it
// at will
return this.cachePath;
}
/**
* Returns whether a file should not be compiled. Note that this doesn't
* necessarily mean it won't end up in the cache, only that its contents are
* saved verbatim instead of trying to find an appropriate compiler.
*
* @param {Object} hashInfo The hash information returned from getHashForPath
*
* @return {boolean} True if a file should be ignored
*/
}], [{
key: 'createFromCompiler',
value: function createFromCompiler(cachePath, compiler, fileChangeCache) {
var readOnlyMode = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
var newCachePath = null;
var getCachePath = function getCachePath() {
if (newCachePath) return newCachePath;
var digestObj = {
name: compiler.name || (0, _getPrototypeOf2.default)(compiler).constructor.name,
version: compiler.getCompilerVersion(),
options: compiler.compilerOptions
};
newCachePath = _path2.default.join(cachePath, (0, _digestForObject2.default)(digestObj));
d('Path for ' + digestObj.name + ': ' + newCachePath);
d('Set up with parameters: ' + (0, _stringify2.default)(digestObj));
if (!readOnlyMode) _mkdirp2.default.sync(newCachePath);
return newCachePath;
};
var ret = new CompileCache('', fileChangeCache);
ret.getCachePath = getCachePath;
return ret;
}
}, {
key: 'shouldPassthrough',
value: function shouldPassthrough(hashInfo) {
return hashInfo.isMinified || hashInfo.isInNodeModules || hashInfo.hasSourceMap || hashInfo.isFileBinary;
}
}]);
return CompileCache;
}();
exports.default = CompileCache;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9jb21waWxlLWNhY2hlLmpzIl0sIm5hbWVzIjpbImQiLCJyZXF1aXJlIiwiQ29tcGlsZUNhY2hlIiwiY2FjaGVQYXRoIiwiZmlsZUNoYW5nZUNhY2hlIiwiZmlsZVBhdGgiLCJnZXRIYXNoRm9yUGF0aCIsInJlc29sdmUiLCJoYXNoSW5mbyIsImNvZGUiLCJtaW1lVHlwZSIsImJpbmFyeURhdGEiLCJkZXBlbmRlbnRGaWxlcyIsImNhY2hlRmlsZSIsImpvaW4iLCJnZXRDYWNoZVBhdGgiLCJoYXNoIiwicmVzdWx0IiwiaXNGaWxlQmluYXJ5IiwiSlNPTiIsInJlYWRGaWxlIiwiaW5mbyIsInBhcnNlIiwiZ3VuemlwIiwiYnVmIiwic3RyIiwidG9TdHJpbmciLCJtZXNzYWdlIiwiY29kZU9yQmluYXJ5RGF0YSIsInRhcmdldCIsImd6aXAiLCJ3cml0ZUZpbGUiLCJCdWZmZXIiLCJmZXRjaGVyIiwiZ2V0IiwiY2FjaGVSZXN1bHQiLCJpc0luTm9kZU1vZHVsZXMiLCJzYXZlIiwiZ2V0SGFzaEZvclBhdGhTeW5jIiwicmVhZEZpbGVTeW5jIiwiZ3VuemlwU3luYyIsImUiLCJnemlwU3luYyIsIndyaXRlRmlsZVN5bmMiLCJnZXRTeW5jIiwic2F2ZVN5bmMiLCJjb21waWxlciIsInJlYWRPbmx5TW9kZSIsIm5ld0NhY2hlUGF0aCIsImRpZ2VzdE9iaiIsIm5hbWUiLCJjb25zdHJ1Y3RvciIsInZlcnNpb24iLCJnZXRDb21waWxlclZlcnNpb24iLCJvcHRpb25zIiwiY29tcGlsZXJPcHRpb25zIiwic3luYyIsInJldCIsImlzTWluaWZpZWQiLCJoYXNTb3VyY2VNYXAiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBOzs7O0FBQ0E7Ozs7QUFDQTs7OztBQUNBOzs7O0FBQ0E7O0FBQ0E7Ozs7OztBQUVBLElBQU1BLElBQUlDLFFBQVEsZ0JBQVIsRUFBMEIsZ0NBQTFCLENBQVY7O0FBRUE7Ozs7Ozs7OztJQVFxQkMs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Q0FBNENELElBRG5EO0FBRWhCRSxtQkFBU04sU0FBU08sa0JBQVQsRUFGTztBQUdoQkMsbUJBQVNSLFNBQVNTO0FBSEYsU0FBbEI7O0FBTUFQLHVCQUFlLGVBQUtsQyxJQUFMLENBQVVYLFNBQVYsRUFBcUIsK0JBQXNCOEMsU0FBdEIsQ0FBckIsQ0FBZjs7QUFFQWpELHdCQUFjaUQsVUFBVUMsSUFBeEIsVUFBaUNGLFlBQWpDO0FBQ0FoRCx1Q0FBNkIseUJBQWVpRCxTQUFmLENBQTdCOztBQUVBLFlBQUksQ0FBQ0YsWUFBTCxFQUFtQixpQkFBT1MsSUFBUCxDQUFZUixZQUFaO0FBQ25CLGVBQU9BLFlBQVA7QUFDRCxPQWhCRDs7QUFrQkEsVUFBSVMsTUFBTSxJQUFJdkQsWUFBSixDQUFpQixFQUFqQixFQUFxQkUsZUFBckIsQ0FBVjtBQUNBcUQsVUFBSTFDLFlBQUosR0FBbUJBLFlBQW5COztBQUVBLGFBQU8wQyxHQUFQO0FBQ0Q7OztzQ0F3TndCakQsUSxFQUFVO0FBQ2pDLGFBQU9BLFNBQVNrRCxVQUFULElBQXVCbEQsU0FBUzRCLGVBQWhDLElBQW1ENUIsU0FBU21ELFlBQTVELElBQTRFbkQsU0FBU1UsWUFBNUY7QUFDRDs7Ozs7a0JBblJrQmhCLFkiLCJmaWxlIjoiY29tcGlsZS1jYWNoZS5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBmcyBmcm9tICdmcyc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB6bGliIGZyb20gJ3psaWInO1xuaW1wb3J0IGNyZWF0ZURpZ2VzdEZvck9iamVjdCBmcm9tICcuL2RpZ2VzdC1mb3Itb2JqZWN0JztcbmltcG9ydCB7cGZzLCBwemxpYn0gZnJvbSAnLi9wcm9taXNlJztcbmltcG9ydCBta2RpcnAgZnJvbSAnbWtkaXJwJztcblxuY29uc3QgZCA9IHJlcXVpcmUoJ2RlYnVnLWVsZWN0cm9uJykoJ2VsZWN0cm9uLWNvbXBpbGU6Y29tcGlsZS1jYWNoZScpO1xuXG4vKipcbiAqIENvbXBpbGVDYWNoZSBtYW5hZ2VzIGdldHRpbmcgYW5kIHNldHRpbmcgZW50cmllcyBmb3IgYSBzaW5nbGUgY29tcGlsZXI7IGVhY2hcbiAqIGluLXVzZSBjb21waWxlciB3aWxsIGhhdmUgYW4gaW5zdGFuY2Ugb2YgdGhpcyBjbGFzcywgdXN1YWxseSBjcmVhdGVkIHZpYVxuICoge0BsaW5rIGNyZWF0ZUZyb21Db21waWxlcn0uXG4gKlxuICogWW91IHVzdWFsbHkgd2lsbCBub3QgdXNlIHRoaXMgY2xhc3MgZGlyZWN0bHksIGl0IGlzIGFuIGltcGxlbWVudGF0aW9uIGNsYXNzXG4gKiBmb3Ige0BsaW5rIENvbXBpbGVIb3N0fS5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQ29tcGlsZUNhY2hlIHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gaW5zdGFuY2UsIHVzdWFsbHkgdXNlZCBmb3IgdGVzdGluZyBvbmx5LlxuICAgKlxuICAgKiBAcGFyYW0gIHtzdHJpbmd9IGNhY2hlUGF0aCAgVGhlIHJvb3QgZGlyZWN0b3J5IHRvIHVzZSBhcyBhIGNhY2hlIHBhdGhcbiAgICpcbiAgICogQHBhcmFtICB7RmlsZUNoYW5nZWRDYWNoZX0gZmlsZUNoYW5nZUNhY2hlICBBIGZpbGUtY2hhbmdlIGNhY2hlIHRoYXQgaXNcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25hbGx5IHByZS1sb2FkZWQuXG4gICAqL1xuICBjb25zdHJ1Y3RvcihjYWNoZVBhdGgsIGZpbGVDaGFuZ2VDYWNoZSkge1xuICAgIHRoaXMuY2FjaGVQYXRoID0gY2FjaGVQYXRoO1xuICAgIHRoaXMuZmlsZUNoYW5nZUNhY2hlID0gZmlsZUNoYW5nZUNhY2hlO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBDb21waWxlQ2FjaGUgZnJvbSBhIGNsYXNzIGNvbXBhdGlibGUgd2l0aCB0aGUgQ29tcGlsZXJCYXNlXG4gICAqIGludGVyZmFjZS4gVGhpcyBtZXRob2QgdXNlcyB0aGUgY29tcGlsZXIgbmFtZSAvIHZlcnNpb24gLyBvcHRpb25zIHRvXG4gICAqIGdlbmVyYXRlIGEgdW5pcXVlIGRpcmVjdG9yeSBuYW1lIGZvciBjYWNoZWQgcmVzdWx0c1xuICAgKlxuICAgKiBAcGFyYW0gIHtzdHJpbmd9IGNhY2hlUGF0aCAgVGhlIHJvb3QgcGF0aCB0byB1c2UgZm9yIHRoZSBjYWNoZSwgYSBkaXJlY3RvcnlcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcHJlc2VudGluZyB0aGUgaGFzaCBvZiB0aGUgY29tcGlsZXIgcGFyYW1ldGVyc1xuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lsbCBiZSBjcmVhdGVkIGhlcmUuXG4gICAqXG4gICAqIEBwYXJhbSAge0NvbXBpbGVyQmFzZX0gY29tcGlsZXIgIFRoZSBjb21waWxlciB0byB1c2UgZm9yIHZlcnNpb24gLyBvcHRpb25cbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mb3JtYXRpb24uXG4gICAqXG4gICAqIEBwYXJhbSAge0ZpbGVDaGFuZ2VkQ2FjaGV9IGZpbGVDaGFuZ2VDYWNoZSAgQSBmaWxlLWNoYW5nZSBjYWNoZSB0aGF0IGlzXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uYWxseSBwcmUtbG9hZGVkLlxuICAgKlxuICAgKiBAcGFyYW0gIHtib29sZWFufSByZWFkT25seU1vZGUgIERvbid0IGF0dGVtcHQgdG8gY3JlYXRlIHRoZSBjYWNoZSBkaXJlY3RvcnkuXG4gICAqXG4gICAqIEByZXR1cm4ge0NvbXBpbGVDYWNoZX0gIEEgY29uZmlndXJlZCBDb21waWxlQ2FjaGUgaW5zdGFuY2UuXG4gICAqL1xuICBzdGF0aWMgY3JlYXRlRnJvbUNvbXBpbGVyKGNhY2hlUGF0aCwgY29tcGlsZXIsIGZpbGVDaGFuZ2VDYWNoZSwgcmVhZE9ubHlNb2RlPWZhbHNlKSB7XG4gICAgbGV0IG5ld0NhY2hlUGF0aCA9IG51bGw7XG4gICAgbGV0IGdldENhY2hlUGF0aCA9ICgpID0+IHtcbiAgICAgIGlmIChuZXdDYWNoZVBhdGgpIHJldHVybiBuZXdDYWNoZVBhdGg7XG5cbiAgICAgIGNvbnN0IGRpZ2VzdE9iaiA9IHtcbiAgICAgICAgbmFtZTogY29tcGlsZXIubmFtZSB8fCBPYmplY3QuZ2V0UHJvdG90eXBlT2YoY29tcGlsZXIpLmNvbnN0cnVjdG9yLm5hbWUsXG4gICAgICAgIHZlcnNpb246IGNvbXBpbGVyLmdldENvbXBpbGVyVmVyc2lvbigpLFxuICAgICAgICBvcHRpb25zOiBjb21waWxlci5jb21waWxlck9wdGlvbnNcbiAgICAgIH07XG5cbiAgICAgIG5ld0NhY2hlUGF0aCA9IHBhdGguam9pbihjYWNoZVBhdGgsIGNyZWF0ZURpZ2VzdEZvck9iamVjdChkaWdlc3RPYmopKTtcblxuICAgICAgZChgUGF0aCBmb3IgJHtkaWdlc3RPYmoubmFtZX06ICR7bmV3Q2FjaGVQYXRofWApO1xuICAgICAgZChgU2V0IHVwIHdpdGggcGFyYW1ldGVyczogJHtKU09OLnN0cmluZ2lmeShkaWdlc3RPYmopfWApO1xuXG4gICAgICBpZiAoIXJlYWRPbmx5TW9kZSkgbWtkaXJwLnN5bmMobmV3Q2FjaGVQYXRoKTtcbiAgICAgIHJldHVybiBuZXdDYWNoZVBhdGg7XG4gICAgfTtcblxuICAgIGxldCByZXQgPSBuZXcgQ29tcGlsZUNhY2hlKCcnLCBmaWxlQ2hhbmdlQ2FjaGUpO1xuICAgIHJldC5nZXRDYWNoZVBhdGggPSBnZXRDYWNoZVBhdGg7XG5cbiAgICByZXR1cm4gcmV0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBmaWxlJ3MgY29tcGlsZWQgY29udGVudHMgZnJvbSB0aGUgY2FjaGUuXG4gICAqXG4gICAqIEBwYXJhbSAge3N0cmluZ30gZmlsZVBhdGggIFRoZSBwYXRoIHRvIHRoZSBmaWxlLiBGaWxlQ2hhbmdlZENhY2hlIHdpbGwgbG9va1xuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cCB0aGUgaGFzaCBhbmQgdXNlIHRoYXQgYXMgdGhlIGtleSBpbiB0aGUgY2FjaGUuXG4gICAqXG4gICAqIEByZXR1cm4ge1Byb21pc2U8T2JqZWN0Pn0gIEFuIG9iamVjdCB3aXRoIGFsbCBraW5kcyBvZiBpbmZvcm1hdGlvblxuICAgKlxuICAgKiBAcHJvcGVydHkge09iamVjdH0gaGFzaEluZm8gIFRoZSBoYXNoIGluZm9ybWF0aW9uIHJldHVybmVkIGZyb20gZ2V0SGFzaEZvclBhdGhcbiAgICogQHByb3BlcnR5IHtzdHJpbmd9IGNvZGUgIFRoZSBzb3VyY2UgY29kZSBpZiB0aGUgZmlsZSB3YXMgYSB0ZXh0IGZpbGVcbiAgICogQHByb3BlcnR5IHtCdWZmZXJ9IGJpbmFyeURhdGEgIFRoZSBmaWxlIGlmIGl0IHdhcyBhIGJpbmFyeSBmaWxlXG4gICAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBtaW1lVHlwZSAgVGhlIE1JTUUgdHlwZSBzYXZlZCBpbiB0aGUgY2FjaGUuXG4gICAqIEBwcm9wZXJ0eSB7c3RyaW5nW119IGRlcGVuZGVudEZpbGVzICBUaGUgZGVwZW5kZW50IGZpbGVzIHJldHVybmVkIGZyb21cbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbXBpbGluZyB0aGUgZmlsZSwgaWYgYW55LlxuICAgKi9cbiAgYXN5bmMgZ2V0KGZpbGVQYXRoKSB7XG4gICAgZChgRmV0Y2hpbmcgJHtmaWxlUGF0aH0gZnJvbSBjYWNoZWApO1xuICAgIGxldCBoYXNoSW5mbyA9IGF3YWl0IHRoaXMuZmlsZUNoYW5nZUNhY2hlLmdldEhhc2hGb3JQYXRoKHBhdGgucmVzb2x2ZShmaWxlUGF0aCkpO1xuXG4gICAgbGV0IGNvZGUgPSBudWxsO1xuICAgIGxldCBtaW1lVHlwZSA9IG51bGw7XG4gICAgbGV0IGJpbmFyeURhdGEgPSBudWxsO1xuICAgIGxldCBkZXBlbmRlbnRGaWxlcyA9IG51bGw7XG5cbiAgICBsZXQgY2FjaGVGaWxlID0gbnVsbDtcbiAgICB0cnkge1xuICAgICAgY2FjaGVGaWxlID0gcGF0aC5qb2luKHRoaXMuZ2V0Q2FjaGVQYXRoKCksIGhhc2hJbmZvLmhhc2gpO1xuICAgICAgbGV0IHJlc3VsdCA9IG51bGw7XG5cbiAgICAgIGlmIChoYXNoSW5mby5pc0ZpbGVCaW5hcnkpIHtcbiAgICAgICAgZChcIkZpbGUgaXMgYmluYXJ5LCByZWFkaW5nIG91dCBpbmZvXCIpO1xuICAgICAgICBsZXQgaW5mbyA9IEpTT04ucGFyc2UoYXdhaXQgcGZzLnJlYWRGaWxlKGNhY2hlRmlsZSArICcuaW5mbycpKTtcbiAgICAgICAgbWltZVR5cGUgPSBpbmZvLm1pbWVUeXBlO1xuICAgICAgICBkZXBlbmRlbnRGaWxlcyA9IGluZm8uZGVwZW5kZW50RmlsZXM7XG5cbiAgICAgICAgYmluYXJ5RGF0YSA9IGhhc2hJbmZvLmJpbmFyeURhdGE7XG4gICAgICAgIGlmICghYmluYXJ5RGF0YSkge1xuICAgICAgICAgIGJpbmFyeURhdGEgPSBhd2FpdCBwZnMucmVhZEZpbGUoY2FjaGVGaWxlKTtcbiAgICAgICAgICBiaW5hcnlEYXRhID0gYXdhaXQgcHpsaWIuZ3VuemlwKGJpbmFyeURhdGEpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgYnVmID0gYXdhaXQgcGZzLnJlYWRGaWxlKGNhY2hlRmlsZSk7XG4gICAgICAgIGxldCBzdHIgPSAoYXdhaXQgcHpsaWIuZ3VuemlwKGJ1ZikpLnRvU3RyaW5nKCd1dGY4Jyk7XG5cbiAgICAgICAgcmVzdWx0ID0gSlNPTi5wYXJzZShzdHIpO1xuICAgICAgICBjb2RlID0gcmVzdWx0LmNvZGU7XG4gICAgICAgIG1pbWVUeXBlID0gcmVzdWx0Lm1pbWVUeXBlO1xuICAgICAgICBkZXBlbmRlbnRGaWxlcyA9IHJlc3VsdC5kZXBlbmRlbnRGaWxlcztcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBkKGBGYWlsZWQgdG8gcmVhZCBjYWNoZSBmb3IgJHtmaWxlUGF0aH0sIGxvb2tlZCBpbiAke2NhY2hlRmlsZX06ICR7ZS5tZXNzYWdlfWApO1xuICAgIH1cblxuICAgIHJldHVybiB7IGhhc2hJbmZvLCBjb2RlLCBtaW1lVHlwZSwgYmluYXJ5RGF0YSwgZGVwZW5kZW50RmlsZXMgfTtcbiAgfVxuXG5cbiAgLyoqXG4gICAqIFNhdmVzIGEgY29tcGlsZWQgcmVzdWx0IHRvIGNhY2hlXG4gICAqXG4gICAqIEBwYXJhbSAge09iamVjdH0gaGFzaEluZm8gIFRoZSBoYXNoIGluZm9ybWF0aW9uIHJldHVybmVkIGZyb20gZ2V0SGFzaEZvclBhdGhcbiAgICpcbiAgICogQHBhcmFtICB7c3RyaW5nIC8gQnVmZmVyfSBjb2RlT3JCaW5hcnlEYXRhICAgVGhlIGZpbGUncyBjb250ZW50cywgZWl0aGVyIGFzXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGEgc3RyaW5nIG9yIGEgQnVmZmVyLlxuICAgKiBAcGFyYW0gIHtzdHJpbmd9IG1pbWVUeXBlICBUaGUgTUlNRSB0eXBlIHJldHVybmVkIGJ5IHRoZSBjb21waWxlci5cbiAgICpcbiAgICogQHBhcmFtICB7c3RyaW5nW119IGRlcGVuZGVudEZpbGVzICBUaGUgbGlzdCBvZiBkZXBlbmRlbnQgZmlsZXMgcmV0dXJuZWQgYnlcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgY29tcGlsZXIuXG4gICAqIEByZXR1cm4ge1Byb21pc2V9ICBDb21wbGV0aW9uLlxuICAgKi9cbiAgYXN5bmMgc2F2ZShoYXNoSW5mbywgY29kZU9yQmluYXJ5RGF0YSwgbWltZVR5cGUsIGRlcGVuZGVudEZpbGVzKSB7XG4gICAgbGV0IGJ1ZiA9IG51bGw7XG4gICAgbGV0IHRhcmdldCA9IHBhdGguam9pbih0aGlzLmdldENhY2hlUGF0aCgpLCBoYXNoSW5mby5oYXNoKTtcbiAgICBkKGBTYXZpbmcgdG8gJHt0YXJnZXR9YCk7XG5cbiAgICBpZiAoaGFzaEluZm8uaXNGaWxlQmluYXJ5KSB7XG4gICAgICBidWYgPSBhd2FpdCBwemxpYi5nemlwKGNvZGVPckJpbmFyeURhdGEpO1xuICAgICAgYXdhaXQgcGZzLndyaXRlRmlsZSh0YXJnZXQgKyAnLmluZm8nLCBKU09OLnN0cmluZ2lmeSh7bWltZVR5cGUsIGRlcGVuZGVudEZpbGVzfSksICd1dGY4Jyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGJ1ZiA9IGF3YWl0IHB6bGliLmd6aXAobmV3IEJ1ZmZlcihKU09OLnN0cmluZ2lmeSh7Y29kZTogY29kZU9yQmluYXJ5RGF0YSwgbWltZVR5cGUsIGRlcGVuZGVudEZpbGVzfSkpKTtcbiAgICB9XG5cbiAgICBhd2FpdCBwZnMud3JpdGVGaWxlKHRhcmdldCwgYnVmKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBdHRlbXB0cyB0byBmaXJzdCBnZXQgYSBrZXkgdmlhIHtAbGluayBnZXR9LCB0aGVuIGlmIGl0IGZhaWxzLCBjYWxsIGEgbWV0aG9kXG4gICAqIHRvIHJldHJpZXZlIHRoZSBjb250ZW50cywgdGhlbiBzYXZlIHRoZSByZXN1bHQgdG8gY2FjaGUuXG4gICAqXG4gICAqIFRoZSBmZXRjaGVyIHBhcmFtZXRlciBpcyBleHBlY3RlZCB0byBoYXZlIHRoZSBzaWduYXR1cmU6XG4gICAqXG4gICAqIFByb21pc2U8T2JqZWN0PiBmZXRjaGVyKGZpbGVQYXRoIDogc3RyaW5nLCBoYXNoSW5mbyA6IE9iamVjdCk7XG4gICAqXG4gICAqIGhhc2hJbmZvIGlzIGEgdmFsdWUgcmV0dXJuZWQgZnJvbSBnZXRIYXNoRm9yUGF0aFxuICAgKiBUaGUgcmV0dXJuIHZhbHVlIG9mIGZldGNoZXIgbXVzdCBiZSBhbiBPYmplY3Qgd2l0aCB0aGUgcHJvcGVydGllczpcbiAgICpcbiAgICogbWltZVR5cGUgLSB0aGUgTUlNRSB0eXBlIG9mIHRoZSBkYXRhIHRvIHNhdmVcbiAgICogY29kZSAob3B0aW9uYWwpIC0gdGhlIHNvdXJjZSBjb2RlIGFzIGEgc3RyaW5nLCBpZiBmaWxlIGlzIHRleHRcbiAgICogYmluYXJ5RGF0YSAob3B0aW9uYWwpIC0gdGhlIGZpbGUgY29udGVudHMgYXMgYSBCdWZmZXIsIGlmIGZpbGUgaXMgYmluYXJ5XG4gICAqIGRlcGVuZGVudEZpbGVzIC0gdGhlIGRlcGVuZGVudCBmaWxlcyByZXR1cm5lZCBieSB0aGUgY29tcGlsZXIuXG4gICAqXG4gICAqIEBwYXJhbSAge3N0cmluZ30gZmlsZVBhdGggIFRoZSBwYXRoIHRvIHRoZSBmaWxlLiBGaWxlQ2hhbmdlZENhY2hlIHdpbGwgbG9va1xuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cCB0aGUgaGFzaCBhbmQgdXNlIHRoYXQgYXMgdGhlIGtleSBpbiB0aGUgY2FjaGUuXG4gICAqXG4gICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBmZXRjaGVyICBBIG1ldGhvZCB3aGljaCBjb25mb3JtcyB0byB0aGUgZGVzY3JpcHRpb24gYWJvdmUuXG4gICAqXG4gICAqIEByZXR1cm4ge1Byb21pc2U8T2JqZWN0Pn0gIEFuIE9iamVjdCB3aGljaCBoYXMgdGhlIHNhbWUgZmllbGRzIGFzIHRoZVxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7QGxpbmsgZ2V0fSBtZXRob2QgcmV0dXJuIHJlc3VsdC5cbiAgICovXG4gIGFzeW5jIGdldE9yRmV0Y2goZmlsZVBhdGgsIGZldGNoZXIpIHtcbiAgICBsZXQgY2FjaGVSZXN1bHQgPSBhd2FpdCB0aGlzLmdldChmaWxlUGF0aCk7XG4gICAgaWYgKGNhY2hlUmVzdWx0LmNvZGUgfHwgY2FjaGVSZXN1bHQuYmluYXJ5RGF0YSkgcmV0dXJuIGNhY2hlUmVzdWx0O1xuXG4gICAgbGV0IHJlc3VsdCA9IGF3YWl0IGZldGNoZXIoZmlsZVBhdGgsIGNhY2hlUmVzdWx0Lmhhc2hJbmZvKSB8fCB7IGhhc2hJbmZvOiBjYWNoZVJlc3VsdC5oYXNoSW5mbyB9O1xuXG4gICAgaWYgKHJlc3VsdC5taW1lVHlwZSAmJiAhY2FjaGVSZXN1bHQuaGFzaEluZm8uaXNJbk5vZGVNb2R1bGVzKSB7XG4gICAgICBkKGBDYWNoZSBtaXNzOiBzYXZpbmcgb3V0IGluZm8gZm9yICR7ZmlsZVBhdGh9YCk7XG4gICAgICBhd2FpdCB0aGlzLnNhdmUoY2FjaGVSZXN1bHQuaGFzaEluZm8sIHJlc3VsdC5jb2RlIHx8IHJlc3VsdC5iaW5hcnlEYXRhLCByZXN1bHQubWltZVR5cGUsIHJlc3VsdC5kZXBlbmRlbnRGaWxlcyk7XG4gICAgfVxuXG4gICAgcmVzdWx0Lmhhc2hJbmZvID0gY2FjaGVSZXN1bHQuaGFzaEluZm87XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGdldFN5bmMoZmlsZVBhdGgpIHtcbiAgICBkKGBGZXRjaGluZyAke2ZpbGVQYXRofSBmcm9tIGNhY2hlYCk7XG4gICAgbGV0IGhhc2hJbmZvID0gdGhpcy5maWxlQ2hhbmdlQ2FjaGUuZ2V0SGFzaEZvclBhdGhTeW5jKHBhdGgucmVzb2x2ZShmaWxlUGF0aCkpO1xuXG4gICAgbGV0IGNvZGUgPSBudWxsO1xuICAgIGxldCBtaW1lVHlwZSA9IG51bGw7XG4gICAgbGV0IGJpbmFyeURhdGEgPSBudWxsO1xuICAgIGxldCBkZXBlbmRlbnRGaWxlcyA9IG51bGw7XG5cbiAgICB0cnkge1xuICAgICAgbGV0IGNhY2hlRmlsZSA9IHBhdGguam9pbih0aGlzLmdldENhY2hlUGF0aCgpLCBoYXNoSW5mby5oYXNoKTtcblxuICAgICAgbGV0IHJlc3VsdCA9IG51bGw7XG4gICAgICBpZiAoaGFzaEluZm8uaXNGaWxlQmluYXJ5KSB7XG4gICAgICAgIGQoXCJGaWxlIGlzIGJpbmFyeSwgcmVhZGluZyBvdXQgaW5mb1wiKTtcbiAgICAgICAgbGV0IGluZm8gPSBKU09OLnBhcnNlKGZzLnJlYWRGaWxlU3luYyhjYWNoZUZpbGUgKyAnLmluZm8nKSk7XG4gICAgICAgIG1pbWVUeXBlID0gaW5mby5taW1lVHlwZTtcbiAgICAgICAgZGVwZW5kZW50RmlsZXMgPSBpbmZvLmRlcGVuZGVudEZpbGVzO1xuXG4gICAgICAgIGJpbmFyeURhdGEgPSBoYXNoSW5mby5iaW5hcnlEYXRhO1xuICAgICAgICBpZiAoIWJpbmFyeURhdGEpIHtcbiAgICAgICAgICBiaW5hcnlEYXRhID0gZnMucmVhZEZpbGVTeW5jKGNhY2hlRmlsZSk7XG4gICAgICAgICAgYmluYXJ5RGF0YSA9IHpsaWIuZ3VuemlwU3luYyhiaW5hcnlEYXRhKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbGV0IGJ1ZiA9IGZzLnJlYWRGaWxlU3luYyhjYWNoZUZpbGUpO1xuICAgICAgICBsZXQgc3RyID0gKHpsaWIuZ3VuemlwU3luYyhidWYpKS50b1N0cmluZygndXRmOCcpO1xuXG4gICAgICAgIHJlc3VsdCA9IEpTT04ucGFyc2Uoc3RyKTtcbiAgICAgICAgY29kZSA9IHJlc3VsdC5jb2RlO1xuICAgICAgICBtaW1lVHlwZSA9IHJlc3VsdC5taW1lVHlwZTtcbiAgICAgICAgZGVwZW5kZW50RmlsZXMgPSByZXN1bHQuZGVwZW5kZW50RmlsZXM7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgZChgRmFpbGVkIHRvIHJlYWQgY2FjaGUgZm9yICR7ZmlsZVBhdGh9YCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgaGFzaEluZm8sIGNvZGUsIG1pbWVUeXBlLCBiaW5hcnlEYXRhLCBkZXBlbmRlbnRGaWxlcyB9O1xuICB9XG5cbiAgc2F2ZVN5bmMoaGFzaEluZm8sIGNvZGVPckJpbmFyeURhdGEsIG1pbWVUeXBlLCBkZXBlbmRlbnRGaWxlcykge1xuICAgIGxldCBidWYgPSBudWxsO1xuICAgIGxldCB0YXJnZXQgPSBwYXRoLmpvaW4odGhpcy5nZXRDYWNoZVBhdGgoKSwgaGFzaEluZm8uaGFzaCk7XG4gICAgZChgU2F2aW5nIHRvICR7dGFyZ2V0fWApO1xuXG4gICAgaWYgKGhhc2hJbmZvLmlzRmlsZUJpbmFyeSkge1xuICAgICAgYnVmID0gemxpYi5nemlwU3luYyhjb2RlT3JCaW5hcnlEYXRhKTtcbiAgICAgIGZzLndyaXRlRmlsZVN5bmModGFyZ2V0ICsgJy5pbmZvJywgSlNPTi5zdHJpbmdpZnkoe21pbWVUeXBlLCBkZXBlbmRlbnRGaWxlc30pLCAndXRmOCcpO1xuICAgIH0gZWxzZSB7XG4gICAgICBidWYgPSB6bGliLmd6aXBTeW5jKG5ldyBCdWZmZXIoSlNPTi5zdHJpbmdpZnkoe2NvZGU6IGNvZGVPckJpbmFyeURhdGEsIG1pbWVUeXBlLCBkZXBlbmRlbnRGaWxlc30pKSk7XG4gICAgfVxuXG4gICAgZnMud3JpdGVGaWxlU3luYyh0YXJnZXQsIGJ1Zik7XG4gIH1cblxuICBnZXRPckZldGNoU3luYyhmaWxlUGF0aCwgZmV0Y2hlcikge1xuICAgIGxldCBjYWNoZVJlc3VsdCA9IHRoaXMuZ2V0U3luYyhmaWxlUGF0aCk7XG4gICAgaWYgKGNhY2hlUmVzdWx0LmNvZGUgfHwgY2FjaGVSZXN1bHQuYmluYXJ5RGF0YSkgcmV0dXJuIGNhY2hlUmVzdWx0O1xuXG4gICAgbGV0IHJlc3VsdCA9IGZldGNoZXIoZmlsZVBhdGgsIGNhY2hlUmVzdWx0Lmhhc2hJbmZvKSB8fCB7IGhhc2hJbmZvOiBjYWNoZVJlc3VsdC5oYXNoSW5mbyB9O1xuXG4gICAgaWYgKHJlc3VsdC5taW1lVHlwZSAmJiAhY2FjaGVSZXN1bHQuaGFzaEluZm8uaXNJbk5vZGVNb2R1bGVzKSB7XG4gICAgICBkKGBDYWNoZSBtaXNzOiBzYXZpbmcgb3V0IGluZm8gZm9yICR7ZmlsZVBhdGh9YCk7XG4gICAgICB0aGlzLnNhdmVTeW5jKGNhY2hlUmVzdWx0Lmhhc2hJbmZvLCByZXN1bHQuY29kZSB8fCByZXN1bHQuYmluYXJ5RGF0YSwgcmVzdWx0Lm1pbWVUeXBlLCByZXN1bHQuZGVwZW5kZW50RmlsZXMpO1xuICAgIH1cblxuICAgIHJlc3VsdC5oYXNoSW5mbyA9IGNhY2hlUmVzdWx0Lmhhc2hJbmZvO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgZ2V0Q2FjaGVQYXRoKCkge1xuICAgIC8vIE5COiBUaGlzIGlzIGFuIGV2aWwgaGFjayBzbyB0aGF0IGNyZWF0ZUZyb21Db21waWxlciBjYW4gc3RvbXAgaXRcbiAgICAvLyBhdCB3aWxsXG4gICAgcmV0dXJuIHRoaXMuY2FjaGVQYXRoO1xuICB9XG5cblxuICAvKipcbiAgICogUmV0dXJucyB3aGV0aGVyIGEgZmlsZSBzaG91bGQgbm90IGJlIGNvbXBpbGVkLiBOb3RlIHRoYXQgdGhpcyBkb2Vzbid0XG4gICAqIG5lY2Vzc2FyaWx5IG1lYW4gaXQgd29uJ3QgZW5kIHVwIGluIHRoZSBjYWNoZSwgb25seSB0aGF0IGl0cyBjb250ZW50cyBhcmVcbiAgICogc2F2ZWQgdmVyYmF0aW0gaW5zdGVhZCBvZiB0cnlpbmcgdG8gZmluZCBhbiBhcHByb3ByaWF0ZSBjb21waWxlci5cbiAgICpcbiAgICogQHBhcmFtICB7T2JqZWN0fSBoYXNoSW5mbyAgVGhlIGhhc2ggaW5mb3JtYXRpb24gcmV0dXJuZWQgZnJvbSBnZXRIYXNoRm9yUGF0aFxuICAgKlxuICAgKiBAcmV0dXJuIHtib29sZWFufSAgVHJ1ZSBpZiBhIGZpbGUgc2hvdWxkIGJlIGlnbm9yZWRcbiAgICovXG4gIHN0YXRpYyBzaG91bGRQYXNzdGhyb3VnaChoYXNoSW5mbykge1xuICAgIHJldHVybiBoYXNoSW5mby5pc01pbmlmaWVkIHx8IGhhc2hJbmZvLmlzSW5Ob2RlTW9kdWxlcyB8fCBoYXNoSW5mby5oYXNTb3VyY2VNYXAgfHwgaGFzaEluZm8uaXNGaWxlQmluYXJ5O1xuICB9XG59XG4iXX0=