electron-compile
Version:
Electron supporting package to compile JS and CSS in Electron applications
520 lines (414 loc) • 39.1 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-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]]);
}));
return function get(_x) {
return ref.apply(this, arguments);
};
}()
/**
* 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 ref = (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);
}));
return function save(_x2, _x3, _x4, _x5) {
return ref.apply(this, arguments);
};
}()
/**
* 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 ref = (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);
}));
return function getOrFetch(_x6, _x7) {
return ref.apply(this, arguments);
};
}()
}, {
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 ? false : arguments[3];
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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9jb21waWxlLWNhY2hlLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQU9BLElBQU0sSUFBSSxRQUFRLE9BQVIsRUFBaUIsZ0NBQWpCLENBQUo7Ozs7Ozs7Ozs7O0lBVWU7Ozs7Ozs7Ozs7QUFTbkIsV0FUbUIsWUFTbkIsQ0FBWSxTQUFaLEVBQXVCLGVBQXZCLEVBQXdDO3dDQVRyQixjQVNxQjs7QUFDdEMsU0FBSyxTQUFMLEdBQWlCLFNBQWpCLENBRHNDO0FBRXRDLFNBQUssZUFBTCxHQUF1QixlQUF2QixDQUZzQztHQUF4Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7NkJBVG1COzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs0RkEwRVQ7WUFFSixVQUVBLE1BQ0EsVUFDQSxZQUNBLGdCQUVBLFdBR0UsUUFJRSxNQVVBLEtBQ0E7Ozs7O0FBMUJSLGdDQUFjLHdCQUFkOzt1QkFDcUIsS0FBSyxlQUFMLENBQXFCLGNBQXJCLENBQW9DLGVBQUssT0FBTCxDQUFhLFFBQWIsQ0FBcEM7OztBQUFqQjtBQUVBLHVCQUFPO0FBQ1AsMkJBQVc7QUFDWCw2QkFBYTtBQUNiLGlDQUFpQjtBQUVqQiw0QkFBWTs7O0FBRWQsNEJBQVksZUFBSyxJQUFMLENBQVUsS0FBSyxZQUFMLEVBQVYsRUFBK0IsU0FBUyxJQUFULENBQTNDO0FBQ0kseUJBQVM7O3FCQUVULFNBQVMsWUFBVDs7Ozs7QUFDRixrQkFBRSxrQ0FBRjs4QkFDVzs7dUJBQWlCLGFBQUksUUFBSixDQUFhLFlBQVksT0FBWjs7OztBQUFyQyxtQ0FBWTs7QUFDaEIsMkJBQVcsS0FBSyxRQUFMO0FBQ1gsaUNBQWlCLEtBQUssY0FBTDs7QUFFakIsNkJBQWEsU0FBUyxVQUFUOztvQkFDUjs7Ozs7O3VCQUNnQixhQUFJLFFBQUosQ0FBYSxTQUFiOzs7QUFBbkI7O3VCQUNtQixlQUFNLE1BQU4sQ0FBYSxVQUFiOzs7QUFBbkI7Ozs7Ozs7O3VCQUdjLGFBQUksUUFBSixDQUFhLFNBQWI7OztBQUFaOzt1QkFDYSxlQUFNLE1BQU4sQ0FBYSxHQUFiOzs7QUFBYixvQ0FBZ0MsU0FBUzs7O0FBRTdDLHlCQUFTLEtBQUssS0FBTCxDQUFXLEdBQVgsQ0FBVDtBQUNBLHVCQUFPLE9BQU8sSUFBUDtBQUNQLDJCQUFXLE9BQU8sUUFBUDtBQUNYLGlDQUFpQixPQUFPLGNBQVA7Ozs7Ozs7Ozs7QUFHbkIsZ0RBQThCLDRCQUF1QixtQkFBYyxZQUFFLE9BQUYsQ0FBbkU7OztpREFHSyxFQUFFLGtCQUFGLEVBQVksVUFBWixFQUFrQixrQkFBbEIsRUFBNEIsc0JBQTVCLEVBQXdDLDhCQUF4Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs2RkFpQkUsVUFBVSxrQkFBa0IsVUFBVTtZQUMzQyxLQUNBOzs7OztBQURBLHNCQUFNO0FBQ04seUJBQVMsZUFBSyxJQUFMLENBQVUsS0FBSyxZQUFMLEVBQVYsRUFBK0IsU0FBUyxJQUFUOztBQUM1QyxpQ0FBZSxNQUFmOztxQkFFSSxTQUFTLFlBQVQ7Ozs7Ozt1QkFDVSxlQUFNLElBQU4sQ0FBVyxnQkFBWDs7O0FBQVo7O3VCQUNNLGFBQUksU0FBSixDQUFjLFNBQVMsT0FBVCxFQUFrQix5QkFBZSxFQUFDLGtCQUFELEVBQVcsOEJBQVgsRUFBZixDQUFoQyxFQUE0RSxNQUE1RTs7Ozs7Ozs7dUJBRU0sZUFBTSxJQUFOLENBQVcsSUFBSSxNQUFKLENBQVcseUJBQWUsRUFBQyxNQUFNLGdCQUFOLEVBQXdCLGtCQUF6QixFQUFtQyw4QkFBbkMsRUFBZixDQUFYLENBQVg7OztBQUFaOzs7O3VCQUdJLGFBQUksU0FBSixDQUFjLE1BQWQsRUFBc0IsR0FBdEI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs2RkEyQlMsVUFBVTtZQUNyQixhQUdBOzs7Ozs7dUJBSG9CLEtBQUssR0FBTCxDQUFTLFFBQVQ7OztBQUFwQjs7c0JBQ0EsWUFBWSxJQUFaLElBQW9CLFlBQVksVUFBWjs7Ozs7a0RBQStCOzs7O3VCQUVwQyxRQUFRLFFBQVIsRUFBa0IsWUFBWSxRQUFaOzs7Ozs7Ozs7OytCQUF5QixFQUFFLFVBQVUsWUFBWSxRQUFaOzs7QUFBdEU7O3NCQUVBLE9BQU8sUUFBUCxJQUFtQixDQUFDLFlBQVksUUFBWixDQUFxQixlQUFyQjs7Ozs7QUFDdEIsdURBQXFDLFFBQXJDOzt1QkFDTSxLQUFLLElBQUwsQ0FBVSxZQUFZLFFBQVosRUFBc0IsT0FBTyxJQUFQLElBQWUsT0FBTyxVQUFQLEVBQW1CLE9BQU8sUUFBUCxFQUFpQixPQUFPLGNBQVA7Ozs7QUFHM0YsdUJBQU8sUUFBUCxHQUFrQixZQUFZLFFBQVo7a0RBQ1g7Ozs7Ozs7Ozs7Ozs7Ozs0QkFHRCxVQUFVO0FBQ2hCLHNCQUFjLHdCQUFkLEVBRGdCO0FBRWhCLFVBQUksV0FBVyxLQUFLLGVBQUwsQ0FBcUIsa0JBQXJCLENBQXdDLGVBQUssT0FBTCxDQUFhLFFBQWIsQ0FBeEMsQ0FBWCxDQUZZOztBQUloQixVQUFJLE9BQU8sSUFBUCxDQUpZO0FBS2hCLFVBQUksV0FBVyxJQUFYLENBTFk7QUFNaEIsVUFBSSxhQUFhLElBQWIsQ0FOWTtBQU9oQixVQUFJLGlCQUFpQixJQUFqQixDQVBZOztBQVNoQixVQUFJO0FBQ0YsWUFBSSxZQUFZLGVBQUssSUFBTCxDQUFVLEtBQUssWUFBTCxFQUFWLEVBQStCLFNBQVMsSUFBVCxDQUEzQyxDQURGOztBQUdGLFlBQUksVUFBUyxJQUFULENBSEY7QUFJRixZQUFJLFNBQVMsWUFBVCxFQUF1QjtBQUN6QixZQUFFLGtDQUFGLEVBRHlCO0FBRXpCLGNBQUksUUFBTyxLQUFLLEtBQUwsQ0FBVyxhQUFHLFlBQUgsQ0FBZ0IsWUFBWSxPQUFaLENBQTNCLENBQVAsQ0FGcUI7QUFHekIscUJBQVcsTUFBSyxRQUFMLENBSGM7QUFJekIsMkJBQWlCLE1BQUssY0FBTCxDQUpROztBQU16Qix1QkFBYSxTQUFTLFVBQVQsQ0FOWTtBQU96QixjQUFJLENBQUMsVUFBRCxFQUFhO0FBQ2YseUJBQWEsYUFBRyxZQUFILENBQWdCLFNBQWhCLENBQWIsQ0FEZTtBQUVmLHlCQUFhLGVBQUssVUFBTCxDQUFnQixVQUFoQixDQUFiLENBRmU7V0FBakI7U0FQRixNQVdPO0FBQ0wsY0FBSSxPQUFNLGFBQUcsWUFBSCxDQUFnQixTQUFoQixDQUFOLENBREM7QUFFTCxjQUFJLE9BQU0sY0FBQyxDQUFLLFVBQUwsQ0FBZ0IsSUFBaEIsQ0FBRCxDQUF1QixRQUF2QixDQUFnQyxNQUFoQyxDQUFOLENBRkM7O0FBSUwsb0JBQVMsS0FBSyxLQUFMLENBQVcsSUFBWCxDQUFULENBSks7QUFLTCxpQkFBTyxRQUFPLElBQVAsQ0FMRjtBQU1MLHFCQUFXLFFBQU8sUUFBUCxDQU5OO0FBT0wsMkJBQWlCLFFBQU8sY0FBUCxDQVBaO1NBWFA7T0FKRixDQXdCRSxPQUFPLENBQVAsRUFBVTtBQUNWLHdDQUE4QixRQUE5QixFQURVO09BQVY7O0FBSUYsYUFBTyxFQUFFLGtCQUFGLEVBQVksVUFBWixFQUFrQixrQkFBbEIsRUFBNEIsc0JBQTVCLEVBQXdDLDhCQUF4QyxFQUFQLENBckNnQjs7Ozs2QkF3Q1QsVUFBVSxrQkFBa0IsVUFBVSxnQkFBZ0I7QUFDN0QsVUFBSSxNQUFNLElBQU4sQ0FEeUQ7QUFFN0QsVUFBSSxTQUFTLGVBQUssSUFBTCxDQUFVLEtBQUssWUFBTCxFQUFWLEVBQStCLFNBQVMsSUFBVCxDQUF4QyxDQUZ5RDtBQUc3RCx1QkFBZSxNQUFmLEVBSDZEOztBQUs3RCxVQUFJLFNBQVMsWUFBVCxFQUF1QjtBQUN6QixjQUFNLGVBQUssUUFBTCxDQUFjLGdCQUFkLENBQU4sQ0FEeUI7QUFFekIscUJBQUcsYUFBSCxDQUFpQixTQUFTLE9BQVQsRUFBa0IseUJBQWUsRUFBQyxrQkFBRCxFQUFXLDhCQUFYLEVBQWYsQ0FBbkMsRUFBK0UsTUFBL0UsRUFGeUI7T0FBM0IsTUFHTztBQUNMLGNBQU0sZUFBSyxRQUFMLENBQWMsSUFBSSxNQUFKLENBQVcseUJBQWUsRUFBQyxNQUFNLGdCQUFOLEVBQXdCLGtCQUF6QixFQUFtQyw4QkFBbkMsRUFBZixDQUFYLENBQWQsQ0FBTixDQURLO09BSFA7O0FBT0EsbUJBQUcsYUFBSCxDQUFpQixNQUFqQixFQUF5QixHQUF6QixFQVo2RDs7OzttQ0FlaEQsVUFBVSxTQUFTO0FBQ2hDLFVBQUksY0FBYyxLQUFLLE9BQUwsQ0FBYSxRQUFiLENBQWQsQ0FENEI7QUFFaEMsVUFBSSxZQUFZLElBQVosSUFBb0IsWUFBWSxVQUFaLEVBQXdCLE9BQU8sV0FBUCxDQUFoRDs7QUFFQSxVQUFJLFNBQVMsUUFBUSxRQUFSLEVBQWtCLFlBQVksUUFBWixDQUFsQixJQUEyQyxFQUFFLFVBQVUsWUFBWSxRQUFaLEVBQXZELENBSm1COztBQU1oQyxVQUFJLE9BQU8sUUFBUCxJQUFtQixDQUFDLFlBQVksUUFBWixDQUFxQixlQUFyQixFQUFzQztBQUM1RCwrQ0FBcUMsUUFBckMsRUFENEQ7QUFFNUQsYUFBSyxRQUFMLENBQWMsWUFBWSxRQUFaLEVBQXNCLE9BQU8sSUFBUCxJQUFlLE9BQU8sVUFBUCxFQUFtQixPQUFPLFFBQVAsRUFBaUIsT0FBTyxjQUFQLENBQXZGLENBRjREO09BQTlEOztBQUtBLGFBQU8sUUFBUCxHQUFrQixZQUFZLFFBQVosQ0FYYztBQVloQyxhQUFPLE1BQVAsQ0FaZ0M7Ozs7Ozs7OzttQ0FtQm5COzs7QUFHYixhQUFPLEtBQUssU0FBTCxDQUhNOzs7Ozs7Ozs7Ozs7Ozs7dUNBaE9XLFdBQVcsVUFBVSxpQkFBcUM7VUFBcEIscUVBQWEscUJBQU87O0FBQ2xGLFVBQUksZUFBZSxJQUFmLENBRDhFO0FBRWxGLFVBQUksZUFBZSxTQUFmLFlBQWUsR0FBTTtBQUN2QixZQUFJLFlBQUosRUFBa0IsT0FBTyxZQUFQLENBQWxCOztBQUVBLFlBQU0sWUFBWTtBQUNoQixnQkFBTSxTQUFTLElBQVQsSUFBaUIsOEJBQXNCLFFBQXRCLEVBQWdDLFdBQWhDLENBQTRDLElBQTVDO0FBQ3ZCLG1CQUFTLFNBQVMsa0JBQVQsRUFBVDtBQUNBLG1CQUFTLFNBQVMsZUFBVDtTQUhMLENBSGlCOztBQVN2Qix1QkFBZSxlQUFLLElBQUwsQ0FBVSxTQUFWLEVBQXFCLCtCQUFzQixTQUF0QixDQUFyQixDQUFmLENBVHVCOztBQVd2Qix3QkFBYyxVQUFVLElBQVYsVUFBbUIsWUFBakMsRUFYdUI7QUFZdkIsdUNBQTZCLHlCQUFlLFNBQWYsQ0FBN0IsRUFadUI7O0FBY3ZCLFlBQUksQ0FBQyxZQUFELEVBQWUsaUJBQU8sSUFBUCxDQUFZLFlBQVosRUFBbkI7QUFDQSxlQUFPLFlBQVAsQ0FmdUI7T0FBTixDQUYrRDs7QUFvQmxGLFVBQUksTUFBTSxJQUFJLFlBQUosQ0FBaUIsRUFBakIsRUFBcUIsZUFBckIsQ0FBTixDQXBCOEU7QUFxQmxGLFVBQUksWUFBSixHQUFtQixZQUFuQixDQXJCa0Y7O0FBdUJsRixhQUFPLEdBQVAsQ0F2QmtGOzs7O3NDQWdQM0QsVUFBVTtBQUNqQyxhQUFPLFNBQVMsVUFBVCxJQUF1QixTQUFTLGVBQVQsSUFBNEIsU0FBUyxZQUFULElBQXlCLFNBQVMsWUFBVCxDQURsRDs7O1NBalJoQiIsImZpbGUiOiJjb21waWxlLWNhY2hlLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGZzIGZyb20gJ2ZzJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHpsaWIgZnJvbSAnemxpYic7XG5pbXBvcnQgY3JlYXRlRGlnZXN0Rm9yT2JqZWN0IGZyb20gJy4vZGlnZXN0LWZvci1vYmplY3QnO1xuaW1wb3J0IHtwZnMsIHB6bGlifSBmcm9tICcuL3Byb21pc2UnO1xuaW1wb3J0IG1rZGlycCBmcm9tICdta2RpcnAnO1xuXG5jb25zdCBkID0gcmVxdWlyZSgnZGVidWcnKSgnZWxlY3Ryb24tY29tcGlsZTpjb21waWxlLWNhY2hlJyk7XG5cbi8qKlxuICogQ29tcGlsZUNhY2hlIG1hbmFnZXMgZ2V0dGluZyBhbmQgc2V0dGluZyBlbnRyaWVzIGZvciBhIHNpbmdsZSBjb21waWxlcjsgZWFjaFxuICogaW4tdXNlIGNvbXBpbGVyIHdpbGwgaGF2ZSBhbiBpbnN0YW5jZSBvZiB0aGlzIGNsYXNzLCB1c3VhbGx5IGNyZWF0ZWQgdmlhXG4gKiB7QGxpbmsgY3JlYXRlRnJvbUNvbXBpbGVyfS4gXG4gKiBcbiAqIFlvdSB1c3VhbGx5IHdpbGwgbm90IHVzZSB0aGlzIGNsYXNzIGRpcmVjdGx5LCBpdCBpcyBhbiBpbXBsZW1lbnRhdGlvbiBjbGFzcyBcbiAqIGZvciB7QGxpbmsgQ29tcGlsZUhvc3R9LlxuICovIFxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQ29tcGlsZUNhY2hlIHtcbiAgLyoqICBcbiAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSwgdXN1YWxseSB1c2VkIGZvciB0ZXN0aW5nIG9ubHkuXG4gICAqICAgIFxuICAgKiBAcGFyYW0gIHtzdHJpbmd9IGNhY2hlUGF0aCAgVGhlIHJvb3QgZGlyZWN0b3J5IHRvIHVzZSBhcyBhIGNhY2hlIHBhdGhcbiAgICpcbiAgICogQHBhcmFtICB7RmlsZUNoYW5nZWRDYWNoZX0gZmlsZUNoYW5nZUNhY2hlICBBIGZpbGUtY2hhbmdlIGNhY2hlIHRoYXQgaXMgXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uYWxseSBwcmUtbG9hZGVkLlxuICAgKi8gICBcbiAgY29uc3RydWN0b3IoY2FjaGVQYXRoLCBmaWxlQ2hhbmdlQ2FjaGUpIHtcbiAgICB0aGlzLmNhY2hlUGF0aCA9IGNhY2hlUGF0aDtcbiAgICB0aGlzLmZpbGVDaGFuZ2VDYWNoZSA9IGZpbGVDaGFuZ2VDYWNoZTtcbiAgfVxuICBcbiAgLyoqICBcbiAgICogQ3JlYXRlcyBhIENvbXBpbGVDYWNoZSBmcm9tIGEgY2xhc3MgY29tcGF0aWJsZSB3aXRoIHRoZSBDb21waWxlckJhc2UgXG4gICAqIGludGVyZmFjZS4gVGhpcyBtZXRob2QgdXNlcyB0aGUgY29tcGlsZXIgbmFtZSAvIHZlcnNpb24gLyBvcHRpb25zIHRvIFxuICAgKiBnZW5lcmF0ZSBhIHVuaXF1ZSBkaXJlY3RvcnkgbmFtZSBmb3IgY2FjaGVkIHJlc3VsdHNcbiAgICogICAgXG4gICAqIEBwYXJhbSAge3N0cmluZ30gY2FjaGVQYXRoICBUaGUgcm9vdCBwYXRoIHRvIHVzZSBmb3IgdGhlIGNhY2hlLCBhIGRpcmVjdG9yeVxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwcmVzZW50aW5nIHRoZSBoYXNoIG9mIHRoZSBjb21waWxlciBwYXJhbWV0ZXJzXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aWxsIGJlIGNyZWF0ZWQgaGVyZS5cbiAgICpcbiAgICogQHBhcmFtICB7Q29tcGlsZXJCYXNlfSBjb21waWxlciAgVGhlIGNvbXBpbGVyIHRvIHVzZSBmb3IgdmVyc2lvbiAvIG9wdGlvblxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmZvcm1hdGlvbi5cbiAgICpcbiAgICogQHBhcmFtICB7RmlsZUNoYW5nZWRDYWNoZX0gZmlsZUNoYW5nZUNhY2hlICBBIGZpbGUtY2hhbmdlIGNhY2hlIHRoYXQgaXMgXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uYWxseSBwcmUtbG9hZGVkLlxuICAgKlxuICAgKiBAcGFyYW0gIHtib29sZWFufSByZWFkT25seU1vZGUgIERvbid0IGF0dGVtcHQgdG8gY3JlYXRlIHRoZSBjYWNoZSBkaXJlY3RvcnkuXG4gICAqXG4gICAqIEByZXR1cm4ge0NvbXBpbGVDYWNoZX0gIEEgY29uZmlndXJlZCBDb21waWxlQ2FjaGUgaW5zdGFuY2UuXG4gICAqLyAgIFxuICBzdGF0aWMgY3JlYXRlRnJvbUNvbXBpbGVyKGNhY2hlUGF0aCwgY29tcGlsZXIsIGZpbGVDaGFuZ2VDYWNoZSwgcmVhZE9ubHlNb2RlPWZhbHNlKSB7XG4gICAgbGV0IG5ld0NhY2hlUGF0aCA9IG51bGw7XG4gICAgbGV0IGdldENhY2hlUGF0aCA9ICgpID0+IHtcbiAgICAgIGlmIChuZXdDYWNoZVBhdGgpIHJldHVybiBuZXdDYWNoZVBhdGg7XG5cbiAgICAgIGNvbnN0IGRpZ2VzdE9iaiA9IHtcbiAgICAgICAgbmFtZTogY29tcGlsZXIubmFtZSB8fCBPYmplY3QuZ2V0UHJvdG90eXBlT2YoY29tcGlsZXIpLmNvbnN0cnVjdG9yLm5hbWUsXG4gICAgICAgIHZlcnNpb246IGNvbXBpbGVyLmdldENvbXBpbGVyVmVyc2lvbigpLFxuICAgICAgICBvcHRpb25zOiBjb21waWxlci5jb21waWxlck9wdGlvbnNcbiAgICAgIH07XG5cbiAgICAgIG5ld0NhY2hlUGF0aCA9IHBhdGguam9pbihjYWNoZVBhdGgsIGNyZWF0ZURpZ2VzdEZvck9iamVjdChkaWdlc3RPYmopKTtcblxuICAgICAgZChgUGF0aCBmb3IgJHtkaWdlc3RPYmoubmFtZX06ICR7bmV3Q2FjaGVQYXRofWApO1xuICAgICAgZChgU2V0IHVwIHdpdGggcGFyYW1ldGVyczogJHtKU09OLnN0cmluZ2lmeShkaWdlc3RPYmopfWApO1xuICAgICAgXG4gICAgICBpZiAoIXJlYWRPbmx5TW9kZSkgbWtkaXJwLnN5bmMobmV3Q2FjaGVQYXRoKTtcbiAgICAgIHJldHVybiBuZXdDYWNoZVBhdGg7XG4gICAgfTtcbiAgICBcbiAgICBsZXQgcmV0ID0gbmV3IENvbXBpbGVDYWNoZSgnJywgZmlsZUNoYW5nZUNhY2hlKTtcbiAgICByZXQuZ2V0Q2FjaGVQYXRoID0gZ2V0Q2FjaGVQYXRoO1xuICAgIFxuICAgIHJldHVybiByZXQ7XG4gIH1cbiAgXG4gIC8qKiAgXG4gICAqIFJldHVybnMgYSBmaWxlJ3MgY29tcGlsZWQgY29udGVudHMgZnJvbSB0aGUgY2FjaGUuXG4gICAqICAgIFxuICAgKiBAcGFyYW0gIHtzdHJpbmd9IGZpbGVQYXRoICBUaGUgcGF0aCB0byB0aGUgZmlsZS4gRmlsZUNoYW5nZWRDYWNoZSB3aWxsIGxvb2tcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgdXAgdGhlIGhhc2ggYW5kIHVzZSB0aGF0IGFzIHRoZSBrZXkgaW4gdGhlIGNhY2hlLlxuICAgKlxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE9iamVjdD59ICBBbiBvYmplY3Qgd2l0aCBhbGwga2luZHMgb2YgaW5mb3JtYXRpb25cbiAgICpcbiAgICogQHByb3BlcnR5IHtPYmplY3R9IGhhc2hJbmZvICBUaGUgaGFzaCBpbmZvcm1hdGlvbiByZXR1cm5lZCBmcm9tIGdldEhhc2hGb3JQYXRoXG4gICAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBjb2RlICBUaGUgc291cmNlIGNvZGUgaWYgdGhlIGZpbGUgd2FzIGEgdGV4dCBmaWxlXG4gICAqIEBwcm9wZXJ0eSB7QnVmZmVyfSBiaW5hcnlEYXRhICBUaGUgZmlsZSBpZiBpdCB3YXMgYSBiaW5hcnkgZmlsZVxuICAgKiBAcHJvcGVydHkge3N0cmluZ30gbWltZVR5cGUgIFRoZSBNSU1FIHR5cGUgc2F2ZWQgaW4gdGhlIGNhY2hlLlxuICAgKiBAcHJvcGVydHkge3N0cmluZ1tdfSBkZXBlbmRlbnRGaWxlcyAgVGhlIGRlcGVuZGVudCBmaWxlcyByZXR1cm5lZCBmcm9tIFxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tcGlsaW5nIHRoZSBmaWxlLCBpZiBhbnkuXG4gICAqLyAgIFxuICBhc3luYyBnZXQoZmlsZVBhdGgpIHtcbiAgICBkKGBGZXRjaGluZyAke2ZpbGVQYXRofSBmcm9tIGNhY2hlYCk7XG4gICAgbGV0IGhhc2hJbmZvID0gYXdhaXQgdGhpcy5maWxlQ2hhbmdlQ2FjaGUuZ2V0SGFzaEZvclBhdGgocGF0aC5yZXNvbHZlKGZpbGVQYXRoKSk7XG4gIFxuICAgIGxldCBjb2RlID0gbnVsbDtcbiAgICBsZXQgbWltZVR5cGUgPSBudWxsO1xuICAgIGxldCBiaW5hcnlEYXRhID0gbnVsbDtcbiAgICBsZXQgZGVwZW5kZW50RmlsZXMgPSBudWxsO1xuICAgIFxuICAgIGxldCBjYWNoZUZpbGUgPSBudWxsO1xuICAgIHRyeSB7XG4gICAgICBjYWNoZUZpbGUgPSBwYXRoLmpvaW4odGhpcy5nZXRDYWNoZVBhdGgoKSwgaGFzaEluZm8uaGFzaCk7XG4gICAgICBsZXQgcmVzdWx0ID0gbnVsbDtcblxuICAgICAgaWYgKGhhc2hJbmZvLmlzRmlsZUJpbmFyeSkge1xuICAgICAgICBkKFwiRmlsZSBpcyBiaW5hcnksIHJlYWRpbmcgb3V0IGluZm9cIik7XG4gICAgICAgIGxldCBpbmZvID0gSlNPTi5wYXJzZShhd2FpdCBwZnMucmVhZEZpbGUoY2FjaGVGaWxlICsgJy5pbmZvJykpO1xuICAgICAgICBtaW1lVHlwZSA9IGluZm8ubWltZVR5cGU7XG4gICAgICAgIGRlcGVuZGVudEZpbGVzID0gaW5mby5kZXBlbmRlbnRGaWxlcztcbiAgICAgICAgXG4gICAgICAgIGJpbmFyeURhdGEgPSBoYXNoSW5mby5iaW5hcnlEYXRhO1xuICAgICAgICBpZiAoIWJpbmFyeURhdGEpIHtcbiAgICAgICAgICBiaW5hcnlEYXRhID0gYXdhaXQgcGZzLnJlYWRGaWxlKGNhY2hlRmlsZSk7XG4gICAgICAgICAgYmluYXJ5RGF0YSA9IGF3YWl0IHB6bGliLmd1bnppcChiaW5hcnlEYXRhKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbGV0IGJ1ZiA9IGF3YWl0IHBmcy5yZWFkRmlsZShjYWNoZUZpbGUpO1xuICAgICAgICBsZXQgc3RyID0gKGF3YWl0IHB6bGliLmd1bnppcChidWYpKS50b1N0cmluZygndXRmOCcpO1xuXG4gICAgICAgIHJlc3VsdCA9IEpTT04ucGFyc2Uoc3RyKTtcbiAgICAgICAgY29kZSA9IHJlc3VsdC5jb2RlO1xuICAgICAgICBtaW1lVHlwZSA9IHJlc3VsdC5taW1lVHlwZTtcbiAgICAgICAgZGVwZW5kZW50RmlsZXMgPSByZXN1bHQuZGVwZW5kZW50RmlsZXM7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgZChgRmFpbGVkIHRvIHJlYWQgY2FjaGUgZm9yICR7ZmlsZVBhdGh9LCBsb29rZWQgaW4gJHtjYWNoZUZpbGV9OiAke2UubWVzc2FnZX1gKTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHsgaGFzaEluZm8sIGNvZGUsIG1pbWVUeXBlLCBiaW5hcnlEYXRhLCBkZXBlbmRlbnRGaWxlcyB9O1xuICB9XG5cbiAgXG4gIC8qKiAgXG4gICAqIFNhdmVzIGEgY29tcGlsZWQgcmVzdWx0IHRvIGNhY2hlXG4gICAqICAgIFxuICAgKiBAcGFyYW0gIHtPYmplY3R9IGhhc2hJbmZvICBUaGUgaGFzaCBpbmZvcm1hdGlvbiByZXR1cm5lZCBmcm9tIGdldEhhc2hGb3JQYXRoICAgXG4gICAqXG4gICAqIEBwYXJhbSAge3N0cmluZyAvIEJ1ZmZlcn0gY29kZU9yQmluYXJ5RGF0YSAgIFRoZSBmaWxlJ3MgY29udGVudHMsIGVpdGhlciBhc1xuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhIHN0cmluZyBvciBhIEJ1ZmZlci5cbiAgICogQHBhcmFtICB7c3RyaW5nfSBtaW1lVHlwZSAgVGhlIE1JTUUgdHlwZSByZXR1cm5lZCBieSB0aGUgY29tcGlsZXIuXG4gICAqXG4gICAqIEBwYXJhbSAge3N0cmluZ1tdfSBkZXBlbmRlbnRGaWxlcyAgVGhlIGxpc3Qgb2YgZGVwZW5kZW50IGZpbGVzIHJldHVybmVkIGJ5XG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIGNvbXBpbGVyLlxuICAgKiBAcmV0dXJuIHtQcm9taXNlfSAgQ29tcGxldGlvbi5cbiAgICovICAgXG4gIGFzeW5jIHNhdmUoaGFzaEluZm8sIGNvZGVPckJpbmFyeURhdGEsIG1pbWVUeXBlLCBkZXBlbmRlbnRGaWxlcykge1xuICAgIGxldCBidWYgPSBudWxsO1xuICAgIGxldCB0YXJnZXQgPSBwYXRoLmpvaW4odGhpcy5nZXRDYWNoZVBhdGgoKSwgaGFzaEluZm8uaGFzaCk7XG4gICAgZChgU2F2aW5nIHRvICR7dGFyZ2V0fWApO1xuICAgIFxuICAgIGlmIChoYXNoSW5mby5pc0ZpbGVCaW5hcnkpIHtcbiAgICAgIGJ1ZiA9IGF3YWl0IHB6bGliLmd6aXAoY29kZU9yQmluYXJ5RGF0YSk7XG4gICAgICBhd2FpdCBwZnMud3JpdGVGaWxlKHRhcmdldCArICcuaW5mbycsIEpTT04uc3RyaW5naWZ5KHttaW1lVHlwZSwgZGVwZW5kZW50RmlsZXN9KSwgJ3V0ZjgnKTtcbiAgICB9IGVsc2Uge1xuICAgICAgYnVmID0gYXdhaXQgcHpsaWIuZ3ppcChuZXcgQnVmZmVyKEpTT04uc3RyaW5naWZ5KHtjb2RlOiBjb2RlT3JCaW5hcnlEYXRhLCBtaW1lVHlwZSwgZGVwZW5kZW50RmlsZXN9KSkpO1xuICAgIH1cbiAgICBcbiAgICBhd2FpdCBwZnMud3JpdGVGaWxlKHRhcmdldCwgYnVmKTtcbiAgfVxuICBcbiAgLyoqICBcbiAgICogQXR0ZW1wdHMgdG8gZmlyc3QgZ2V0IGEga2V5IHZpYSB7QGxpbmsgZ2V0fSwgdGhlbiBpZiBpdCBmYWlscywgY2FsbCBhIG1ldGhvZFxuICAgKiB0byByZXRyaWV2ZSB0aGUgY29udGVudHMsIHRoZW4gc2F2ZSB0aGUgcmVzdWx0IHRvIGNhY2hlLlxuICAgKiBcbiAgICogVGhlIGZldGNoZXIgcGFyYW1ldGVyIGlzIGV4cGVjdGVkIHRvIGhhdmUgdGhlIHNpZ25hdHVyZTpcbiAgICogXG4gICAqIFByb21pc2U8T2JqZWN0PiBmZXRjaGVyKGZpbGVQYXRoIDogc3RyaW5nLCBoYXNoSW5mbyA6IE9iamVjdCk7XG4gICAqIFxuICAgKiBoYXNoSW5mbyBpcyBhIHZhbHVlIHJldHVybmVkIGZyb20gZ2V0SGFzaEZvclBhdGhcbiAgICogVGhlIHJldHVybiB2YWx1ZSBvZiBmZXRjaGVyIG11c3QgYmUgYW4gT2JqZWN0IHdpdGggdGhlIHByb3BlcnRpZXM6XG4gICAqIFxuICAgKiBtaW1lVHlwZSAtIHRoZSBNSU1FIHR5cGUgb2YgdGhlIGRhdGEgdG8gc2F2ZVxuICAgKiBjb2RlIChvcHRpb25hbCkgLSB0aGUgc291cmNlIGNvZGUgYXMgYSBzdHJpbmcsIGlmIGZpbGUgaXMgdGV4dFxuICAgKiBiaW5hcnlEYXRhIChvcHRpb25hbCkgLSB0aGUgZmlsZSBjb250ZW50cyBhcyBhIEJ1ZmZlciwgaWYgZmlsZSBpcyBiaW5hcnlcbiAgICogZGVwZW5kZW50RmlsZXMgLSB0aGUgZGVwZW5kZW50IGZpbGVzIHJldHVybmVkIGJ5IHRoZSBjb21waWxlci5cbiAgICpcbiAgICogQHBhcmFtICB7c3RyaW5nfSBmaWxlUGF0aCAgVGhlIHBhdGggdG8gdGhlIGZpbGUuIEZpbGVDaGFuZ2VkQ2FjaGUgd2lsbCBsb29rXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwIHRoZSBoYXNoIGFuZCB1c2UgdGhhdCBhcyB0aGUga2V5IGluIHRoZSBjYWNoZS5cbiAgICpcbiAgICogQHBhcmFtICB7RnVuY3Rpb259IGZldGNoZXIgIEEgbWV0aG9kIHdoaWNoIGNvbmZvcm1zIHRvIHRoZSBkZXNjcmlwdGlvbiBhYm92ZS5cbiAgICpcbiAgICogQHJldHVybiB7UHJvbWlzZTxPYmplY3Q+fSAgQW4gT2JqZWN0IHdoaWNoIGhhcyB0aGUgc2FtZSBmaWVsZHMgYXMgdGhlIFxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7QGxpbmsgZ2V0fSBtZXRob2QgcmV0dXJuIHJlc3VsdC5cbiAgICovICAgXG4gIGFzeW5jIGdldE9yRmV0Y2goZmlsZVBhdGgsIGZldGNoZXIpIHtcbiAgICBsZXQgY2FjaGVSZXN1bHQgPSBhd2FpdCB0aGlzLmdldChmaWxlUGF0aCk7XG4gICAgaWYgKGNhY2hlUmVzdWx0LmNvZGUgfHwgY2FjaGVSZXN1bHQuYmluYXJ5RGF0YSkgcmV0dXJuIGNhY2hlUmVzdWx0O1xuICAgIFxuICAgIGxldCByZXN1bHQgPSBhd2FpdCBmZXRjaGVyKGZpbGVQYXRoLCBjYWNoZVJlc3VsdC5oYXNoSW5mbykgfHwgeyBoYXNoSW5mbzogY2FjaGVSZXN1bHQuaGFzaEluZm8gfTtcbiAgICBcbiAgICBpZiAocmVzdWx0Lm1pbWVUeXBlICYmICFjYWNoZVJlc3VsdC5oYXNoSW5mby5pc0luTm9kZU1vZHVsZXMpIHtcbiAgICAgIGQoYENhY2hlIG1pc3M6IHNhdmluZyBvdXQgaW5mbyBmb3IgJHtmaWxlUGF0aH1gKTtcbiAgICAgIGF3YWl0IHRoaXMuc2F2ZShjYWNoZVJlc3VsdC5oYXNoSW5mbywgcmVzdWx0LmNvZGUgfHwgcmVzdWx0LmJpbmFyeURhdGEsIHJlc3VsdC5taW1lVHlwZSwgcmVzdWx0LmRlcGVuZGVudEZpbGVzKTtcbiAgICB9XG4gICAgXG4gICAgcmVzdWx0Lmhhc2hJbmZvID0gY2FjaGVSZXN1bHQuaGFzaEluZm87XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuICBcbiAgZ2V0U3luYyhmaWxlUGF0aCkge1xuICAgIGQoYEZldGNoaW5nICR7ZmlsZVBhdGh9IGZyb20gY2FjaGVgKTtcbiAgICBsZXQgaGFzaEluZm8gPSB0aGlzLmZpbGVDaGFuZ2VDYWNoZS5nZXRIYXNoRm9yUGF0aFN5bmMocGF0aC5yZXNvbHZlKGZpbGVQYXRoKSk7XG4gIFxuICAgIGxldCBjb2RlID0gbnVsbDtcbiAgICBsZXQgbWltZVR5cGUgPSBudWxsO1xuICAgIGxldCBiaW5hcnlEYXRhID0gbnVsbDtcbiAgICBsZXQgZGVwZW5kZW50RmlsZXMgPSBudWxsO1xuICAgIFxuICAgIHRyeSB7XG4gICAgICBsZXQgY2FjaGVGaWxlID0gcGF0aC5qb2luKHRoaXMuZ2V0Q2FjaGVQYXRoKCksIGhhc2hJbmZvLmhhc2gpO1xuICAgICAgXG4gICAgICBsZXQgcmVzdWx0ID0gbnVsbDtcbiAgICAgIGlmIChoYXNoSW5mby5pc0ZpbGVCaW5hcnkpIHtcbiAgICAgICAgZChcIkZpbGUgaXMgYmluYXJ5LCByZWFkaW5nIG91dCBpbmZvXCIpO1xuICAgICAgICBsZXQgaW5mbyA9IEpTT04ucGFyc2UoZnMucmVhZEZpbGVTeW5jKGNhY2hlRmlsZSArICcuaW5mbycpKTtcbiAgICAgICAgbWltZVR5cGUgPSBpbmZvLm1pbWVUeXBlO1xuICAgICAgICBkZXBlbmRlbnRGaWxlcyA9IGluZm8uZGVwZW5kZW50RmlsZXM7XG4gICAgICAgIFxuICAgICAgICBiaW5hcnlEYXRhID0gaGFzaEluZm8uYmluYXJ5RGF0YTtcbiAgICAgICAgaWYgKCFiaW5hcnlEYXRhKSB7XG4gICAgICAgICAgYmluYXJ5RGF0YSA9IGZzLnJlYWRGaWxlU3luYyhjYWNoZUZpbGUpO1xuICAgICAgICAgIGJpbmFyeURhdGEgPSB6bGliLmd1bnppcFN5bmMoYmluYXJ5RGF0YSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxldCBidWYgPSBmcy5yZWFkRmlsZVN5bmMoY2FjaGVGaWxlKTtcbiAgICAgICAgbGV0IHN0ciA9ICh6bGliLmd1bnppcFN5bmMoYnVmKSkudG9TdHJpbmcoJ3V0ZjgnKTtcblxuICAgICAgICByZXN1bHQgPSBKU09OLnBhcnNlKHN0cik7XG4gICAgICAgIGNvZGUgPSByZXN1bHQuY29kZTtcbiAgICAgICAgbWltZVR5cGUgPSByZXN1bHQubWltZVR5cGU7XG4gICAgICAgIGRlcGVuZGVudEZpbGVzID0gcmVzdWx0LmRlcGVuZGVudEZpbGVzO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGQoYEZhaWxlZCB0byByZWFkIGNhY2hlIGZvciAke2ZpbGVQYXRofWApO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4geyBoYXNoSW5mbywgY29kZSwgbWltZVR5cGUsIGJpbmFyeURhdGEsIGRlcGVuZGVudEZpbGVzIH07XG4gIH1cblxuICBzYXZlU3luYyhoYXNoSW5mbywgY29kZU9yQmluYXJ5RGF0YSwgbWltZVR5cGUsIGRlcGVuZGVudEZpbGVzKSB7XG4gICAgbGV0IGJ1ZiA9IG51bGw7XG4gICAgbGV0IHRhcmdldCA9IHBhdGguam9pbih0aGlzLmdldENhY2hlUGF0aCgpLCBoYXNoSW5mby5oYXNoKTtcbiAgICBkKGBTYXZpbmcgdG8gJHt0YXJnZXR9YCk7XG4gICAgXG4gICAgaWYgKGhhc2hJbmZvLmlzRmlsZUJpbmFyeSkge1xuICAgICAgYnVmID0gemxpYi5nemlwU3luYyhjb2RlT3JCaW5hcnlEYXRhKTtcbiAgICAgIGZzLndyaXRlRmlsZVN5bmModGFyZ2V0ICsgJy5pbmZvJywgSlNPTi5zdHJpbmdpZnkoe21pbWVUeXBlLCBkZXBlbmRlbnRGaWxlc30pLCAndXRmOCcpO1xuICAgIH0gZWxzZSB7XG4gICAgICBidWYgPSB6bGliLmd6aXBTeW5jKG5ldyBCdWZmZXIoSlNPTi5zdHJpbmdpZnkoe2NvZGU6IGNvZGVPckJpbmFyeURhdGEsIG1pbWVUeXBlLCBkZXBlbmRlbnRGaWxlc30pKSk7XG4gICAgfVxuICAgIFxuICAgIGZzLndyaXRlRmlsZVN5bmModGFyZ2V0LCBidWYpO1xuICB9XG4gIFxuICBnZXRPckZldGNoU3luYyhmaWxlUGF0aCwgZmV0Y2hlcikge1xuICAgIGxldCBjYWNoZVJlc3VsdCA9IHRoaXMuZ2V0U3luYyhmaWxlUGF0aCk7XG4gICAgaWYgKGNhY2hlUmVzdWx0LmNvZGUgfHwgY2FjaGVSZXN1bHQuYmluYXJ5RGF0YSkgcmV0dXJuIGNhY2hlUmVzdWx0O1xuICAgIFxuICAgIGxldCByZXN1bHQgPSBmZXRjaGVyKGZpbGVQYXRoLCBjYWNoZVJlc3VsdC5oYXNoSW5mbykgfHwgeyBoYXNoSW5mbzogY2FjaGVSZXN1bHQuaGFzaEluZm8gfTtcbiAgICBcbiAgICBpZiAocmVzdWx0Lm1pbWVUeXBlICYmICFjYWNoZVJlc3VsdC5oYXNoSW5mby5pc0luTm9kZU1vZHVsZXMpIHtcbiAgICAgIGQoYENhY2hlIG1pc3M6IHNhdmluZyBvdXQgaW5mbyBmb3IgJHtmaWxlUGF0aH1gKTtcbiAgICAgIHRoaXMuc2F2ZVN5bmMoY2FjaGVSZXN1bHQuaGFzaEluZm8sIHJlc3VsdC5jb2RlIHx8IHJlc3VsdC5iaW5hcnlEYXRhLCByZXN1bHQubWltZVR5cGUsIHJlc3VsdC5kZXBlbmRlbnRGaWxlcyk7XG4gICAgfVxuICAgIFxuICAgIHJlc3VsdC5oYXNoSW5mbyA9IGNhY2hlUmVzdWx0Lmhhc2hJbmZvO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbiAgXG4gIFxuICAvKiogIFxuICAgKiBAcHJpdmF0ZVxuICAgKi8gICBcbiAgZ2V0Q2FjaGVQYXRoKCkge1xuICAgIC8vIE5COiBUaGlzIGlzIGFuIGV2aWwgaGFjayBzbyB0aGF0IGNyZWF0ZUZyb21Db21waWxlciBjYW4gc3RvbXAgaXRcbiAgICAvLyBhdCB3aWxsXG4gICAgcmV0dXJuIHRoaXMuY2FjaGVQYXRoO1xuICB9XG4gICAgXG4gICAgXG4gIC8qKiAgICBcbiAgICogUmV0dXJucyB3aGV0aGVyIGEgZmlsZSBzaG91bGQgbm90IGJlIGNvbXBpbGVkLiBOb3RlIHRoYXQgdGhpcyBkb2Vzbid0IFxuICAgKiBuZWNlc3NhcmlseSBtZWFuIGl0IHdvbid0IGVuZCB1cCBpbiB0aGUgY2FjaGUsIG9ubHkgdGhhdCBpdHMgY29udGVudHMgYXJlXG4gICAqIHNhdmVkIHZlcmJhdGltIGluc3RlYWQgb2YgdHJ5aW5nIHRvIGZpbmQgYW4gYXBwcm9wcmlhdGUgY29tcGlsZXIuXG4gICAqICAgIFxuICAgKiBAcGFyYW0gIHtPYmplY3R9IGhhc2hJbmZvICBUaGUgaGFzaCBpbmZvcm1hdGlvbiByZXR1cm5lZCBmcm9tIGdldEhhc2hGb3JQYXRoICAgXG4gICAqXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59ICBUcnVlIGlmIGEgZmlsZSBzaG91bGQgYmUgaWdub3JlZFxuICAgKi8gICBcbiAgc3RhdGljIHNob3VsZFBhc3N0aHJvdWdoKGhhc2hJbmZvKSB7XG4gICAgcmV0dXJuIGhhc2hJbmZvLmlzTWluaWZpZWQgfHwgaGFzaEluZm8uaXNJbk5vZGVNb2R1bGVzIHx8IGhhc2hJbmZvLmhhc1NvdXJjZU1hcCB8fCBoYXNoSW5mby5pc0ZpbGVCaW5hcnk7XG4gIH1cbn1cbiJdfQ==