electron-compile
Version:
Electron supporting package to compile JS and CSS in Electron applications
332 lines (275 loc) • 36.3 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
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 }; }
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: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}.
*/
class CompileCache {
/**
* 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.
*/
constructor(cachePath, fileChangeCache) {
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.
*/
static createFromCompiler(cachePath, compiler, fileChangeCache) {
let readOnlyMode = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
let newCachePath = null;
let getCachePath = () => {
if (newCachePath) return newCachePath;
const digestObj = {
name: compiler.name || Object.getPrototypeOf(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: ${ JSON.stringify(digestObj) }`);
if (!readOnlyMode) _mkdirp2.default.sync(newCachePath);
return newCachePath;
};
let ret = new CompileCache('', fileChangeCache);
ret.getCachePath = getCachePath;
return ret;
}
/**
* 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.
*/
get(filePath) {
var _this = this;
return _asyncToGenerator(function* () {
d(`Fetching ${ filePath } from cache`);
let hashInfo = yield _this.fileChangeCache.getHashForPath(_path2.default.resolve(filePath));
let code = null;
let mimeType = null;
let binaryData = null;
let dependentFiles = null;
let cacheFile = null;
try {
cacheFile = _path2.default.join(_this.getCachePath(), hashInfo.hash);
let result = null;
if (hashInfo.isFileBinary) {
d("File is binary, reading out info");
let info = JSON.parse((yield _promise.pfs.readFile(cacheFile + '.info')));
mimeType = info.mimeType;
dependentFiles = info.dependentFiles;
binaryData = hashInfo.binaryData;
if (!binaryData) {
binaryData = yield _promise.pfs.readFile(cacheFile);
binaryData = yield _promise.pzlib.gunzip(binaryData);
}
} else {
let buf = yield _promise.pfs.readFile(cacheFile);
let str = (yield _promise.pzlib.gunzip(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 }, looked in ${ cacheFile }: ${ e.message }`);
}
return { hashInfo, code, mimeType, binaryData, dependentFiles };
})();
}
/**
* 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.
*/
save(hashInfo, codeOrBinaryData, mimeType, dependentFiles) {
var _this2 = this;
return _asyncToGenerator(function* () {
let buf = null;
let target = _path2.default.join(_this2.getCachePath(), hashInfo.hash);
d(`Saving to ${ target }`);
if (hashInfo.isFileBinary) {
buf = yield _promise.pzlib.gzip(codeOrBinaryData);
yield _promise.pfs.writeFile(target + '.info', JSON.stringify({ mimeType, dependentFiles }), 'utf8');
} else {
buf = yield _promise.pzlib.gzip(new Buffer(JSON.stringify({ code: codeOrBinaryData, mimeType, dependentFiles })));
}
yield _promise.pfs.writeFile(target, buf);
})();
}
/**
* 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.
*/
getOrFetch(filePath, fetcher) {
var _this3 = this;
return _asyncToGenerator(function* () {
let cacheResult = yield _this3.get(filePath);
if (cacheResult.code || cacheResult.binaryData) return cacheResult;
let result = (yield fetcher(filePath, cacheResult.hashInfo)) || { hashInfo: cacheResult.hashInfo };
if (result.mimeType && !cacheResult.hashInfo.isInNodeModules) {
d(`Cache miss: saving out info for ${ filePath }`);
yield _this3.save(cacheResult.hashInfo, result.code || result.binaryData, result.mimeType, result.dependentFiles);
}
result.hashInfo = cacheResult.hashInfo;
return result;
})();
}
getSync(filePath) {
d(`Fetching ${ filePath } from cache`);
let hashInfo = this.fileChangeCache.getHashForPathSync(_path2.default.resolve(filePath));
let code = null;
let mimeType = null;
let binaryData = null;
let dependentFiles = null;
try {
let cacheFile = _path2.default.join(this.getCachePath(), hashInfo.hash);
let result = null;
if (hashInfo.isFileBinary) {
d("File is binary, reading out info");
let 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 {
let buf = _fs2.default.readFileSync(cacheFile);
let 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, code, mimeType, binaryData, dependentFiles };
}
saveSync(hashInfo, codeOrBinaryData, mimeType, dependentFiles) {
let buf = null;
let 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', JSON.stringify({ mimeType, dependentFiles }), 'utf8');
} else {
buf = _zlib2.default.gzipSync(new Buffer(JSON.stringify({ code: codeOrBinaryData, mimeType, dependentFiles })));
}
_fs2.default.writeFileSync(target, buf);
}
getOrFetchSync(filePath, fetcher) {
let cacheResult = this.getSync(filePath);
if (cacheResult.code || cacheResult.binaryData) return cacheResult;
let 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
*/
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
*/
static shouldPassthrough(hashInfo) {
return hashInfo.isMinified || hashInfo.isInNodeModules || hashInfo.hasSourceMap || hashInfo.isFileBinary;
}
}
exports.default = CompileCache;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9jb21waWxlLWNhY2hlLmpzIl0sIm5hbWVzIjpbImQiLCJyZXF1aXJlIiwiQ29tcGlsZUNhY2hlIiwiY29uc3RydWN0b3IiLCJjYWNoZVBhdGgiLCJmaWxlQ2hhbmdlQ2FjaGUiLCJjcmVhdGVGcm9tQ29tcGlsZXIiLCJjb21waWxlciIsInJlYWRPbmx5TW9kZSIsIm5ld0NhY2hlUGF0aCIsImdldENhY2hlUGF0aCIsImRpZ2VzdE9iaiIsIm5hbWUiLCJPYmplY3QiLCJnZXRQcm90b3R5cGVPZiIsInZlcnNpb24iLCJnZXRDb21waWxlclZlcnNpb24iLCJvcHRpb25zIiwiY29tcGlsZXJPcHRpb25zIiwiam9pbiIsIkpTT04iLCJzdHJpbmdpZnkiLCJzeW5jIiwicmV0IiwiZ2V0IiwiZmlsZVBhdGgiLCJoYXNoSW5mbyIsImdldEhhc2hGb3JQYXRoIiwicmVzb2x2ZSIsImNvZGUiLCJtaW1lVHlwZSIsImJpbmFyeURhdGEiLCJkZXBlbmRlbnRGaWxlcyIsImNhY2hlRmlsZSIsImhhc2giLCJyZXN1bHQiLCJpc0ZpbGVCaW5hcnkiLCJpbmZvIiwicGFyc2UiLCJyZWFkRmlsZSIsImd1bnppcCIsImJ1ZiIsInN0ciIsInRvU3RyaW5nIiwiZSIsIm1lc3NhZ2UiLCJzYXZlIiwiY29kZU9yQmluYXJ5RGF0YSIsInRhcmdldCIsImd6aXAiLCJ3cml0ZUZpbGUiLCJCdWZmZXIiLCJnZXRPckZldGNoIiwiZmV0Y2hlciIsImNhY2hlUmVzdWx0IiwiaXNJbk5vZGVNb2R1bGVzIiwiZ2V0U3luYyIsImdldEhhc2hGb3JQYXRoU3luYyIsInJlYWRGaWxlU3luYyIsImd1bnppcFN5bmMiLCJzYXZlU3luYyIsImd6aXBTeW5jIiwid3JpdGVGaWxlU3luYyIsImdldE9yRmV0Y2hTeW5jIiwic2hvdWxkUGFzc3Rocm91Z2giLCJpc01pbmlmaWVkIiwiaGFzU291cmNlTWFwIl0sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQTs7OztBQUNBOzs7O0FBQ0E7Ozs7QUFDQTs7OztBQUNBOztBQUNBOzs7Ozs7OztBQUVBLE1BQU1BLElBQUlDLFFBQVEsZ0JBQVIsRUFBMEIsZ0NBQTFCLENBQVY7O0FBRUE7Ozs7Ozs7O0FBUWUsTUFBTUMsWUFBTixDQUFtQjtBQUNoQzs7Ozs7Ozs7QUFRQUMsY0FBWUMsU0FBWixFQUF1QkMsZUFBdkIsRUFBd0M7QUFDdEMsU0FBS0QsU0FBTCxHQUFpQkEsU0FBakI7QUFDQSxTQUFLQyxlQUFMLEdBQXVCQSxlQUF2QjtBQUNEOztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBbUJBLFNBQU9DLGtCQUFQLENBQTBCRixTQUExQixFQUFxQ0csUUFBckMsRUFBK0NGLGVBQS9DLEVBQW9GO0FBQUEsUUFBcEJHLFlBQW9CLHVFQUFQLEtBQU87O0FBQ2xGLFFBQUlDLGVBQWUsSUFBbkI7QUFDQSxRQUFJQyxlQUFlLE1BQU07QUFDdkIsVUFBSUQsWUFBSixFQUFrQixPQUFPQSxZQUFQOztBQUVsQixZQUFNRSxZQUFZO0FBQ2hCQyxjQUFNTCxTQUFTSyxJQUFULElBQWlCQyxPQUFPQyxjQUFQLENBQXNCUCxRQUF0QixFQUFnQ0osV0FBaEMsQ0FBNENTLElBRG5EO0FBRWhCRyxpQkFBU1IsU0FBU1Msa0JBQVQsRUFGTztBQUdoQkMsaUJBQVNWLFNBQVNXO0FBSEYsT0FBbEI7O0FBTUFULHFCQUFlLGVBQUtVLElBQUwsQ0FBVWYsU0FBVixFQUFxQiwrQkFBc0JPLFNBQXRCLENBQXJCLENBQWY7O0FBRUFYLFFBQUcsYUFBV1csVUFBVUMsSUFBSyxPQUFJSCxZQUFhLEdBQTlDO0FBQ0FULFFBQUcsNEJBQTBCb0IsS0FBS0MsU0FBTCxDQUFlVixTQUFmLENBQTBCLEdBQXZEOztBQUVBLFVBQUksQ0FBQ0gsWUFBTCxFQUFtQixpQkFBT2MsSUFBUCxDQUFZYixZQUFaO0FBQ25CLGFBQU9BLFlBQVA7QUFDRCxLQWhCRDs7QUFrQkEsUUFBSWMsTUFBTSxJQUFJckIsWUFBSixDQUFpQixFQUFqQixFQUFxQkcsZUFBckIsQ0FBVjtBQUNBa0IsUUFBSWIsWUFBSixHQUFtQkEsWUFBbkI7O0FBRUEsV0FBT2EsR0FBUDtBQUNEOztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7QUFlTUMsS0FBTixDQUFVQyxRQUFWLEVBQW9CO0FBQUE7O0FBQUE7QUFDbEJ6QixRQUFHLGFBQVd5QixRQUFTLGNBQXZCO0FBQ0EsVUFBSUMsV0FBVyxNQUFNLE1BQUtyQixlQUFMLENBQXFCc0IsY0FBckIsQ0FBb0MsZUFBS0MsT0FBTCxDQUFhSCxRQUFiLENBQXBDLENBQXJCOztBQUVBLFVBQUlJLE9BQU8sSUFBWDtBQUNBLFVBQUlDLFdBQVcsSUFBZjtBQUNBLFVBQUlDLGFBQWEsSUFBakI7QUFDQSxVQUFJQyxpQkFBaUIsSUFBckI7O0FBRUEsVUFBSUMsWUFBWSxJQUFoQjtBQUNBLFVBQUk7QUFDRkEsb0JBQVksZUFBS2QsSUFBTCxDQUFVLE1BQUtULFlBQUwsRUFBVixFQUErQmdCLFNBQVNRLElBQXhDLENBQVo7QUFDQSxZQUFJQyxTQUFTLElBQWI7O0FBRUEsWUFBSVQsU0FBU1UsWUFBYixFQUEyQjtBQUN6QnBDLFlBQUUsa0NBQUY7QUFDQSxjQUFJcUMsT0FBT2pCLEtBQUtrQixLQUFMLEVBQVcsTUFBTSxhQUFJQyxRQUFKLENBQWFOLFlBQVksT0FBekIsQ0FBakIsRUFBWDtBQUNBSCxxQkFBV08sS0FBS1AsUUFBaEI7QUFDQUUsMkJBQWlCSyxLQUFLTCxjQUF0Qjs7QUFFQUQsdUJBQWFMLFNBQVNLLFVBQXRCO0FBQ0EsY0FBSSxDQUFDQSxVQUFMLEVBQWlCO0FBQ2ZBLHlCQUFhLE1BQU0sYUFBSVEsUUFBSixDQUFhTixTQUFiLENBQW5CO0FBQ0FGLHlCQUFhLE1BQU0sZUFBTVMsTUFBTixDQUFhVCxVQUFiLENBQW5CO0FBQ0Q7QUFDRixTQVhELE1BV087QUFDTCxjQUFJVSxNQUFNLE1BQU0sYUFBSUYsUUFBSixDQUFhTixTQUFiLENBQWhCO0FBQ0EsY0FBSVMsTUFBTSxDQUFDLE1BQU0sZUFBTUYsTUFBTixDQUFhQyxHQUFiLENBQVAsRUFBMEJFLFFBQTFCLENBQW1DLE1BQW5DLENBQVY7O0FBRUFSLG1CQUFTZixLQUFLa0IsS0FBTCxDQUFXSSxHQUFYLENBQVQ7QUFDQWIsaUJBQU9NLE9BQU9OLElBQWQ7QUFDQUMscUJBQVdLLE9BQU9MLFFBQWxCO0FBQ0FFLDJCQUFpQkcsT0FBT0gsY0FBeEI7QUFDRDtBQUNGLE9BeEJELENBd0JFLE9BQU9ZLENBQVAsRUFBVTtBQUNWNUMsVUFBRyw2QkFBMkJ5QixRQUFTLGlCQUFjUSxTQUFVLE9BQUlXLEVBQUVDLE9BQVEsR0FBN0U7QUFDRDs7QUFFRCxhQUFPLEVBQUVuQixRQUFGLEVBQVlHLElBQVosRUFBa0JDLFFBQWxCLEVBQTRCQyxVQUE1QixFQUF3Q0MsY0FBeEMsRUFBUDtBQXRDa0I7QUF1Q25COztBQUdEOzs7Ozs7Ozs7Ozs7O0FBYU1jLE1BQU4sQ0FBV3BCLFFBQVgsRUFBcUJxQixnQkFBckIsRUFBdUNqQixRQUF2QyxFQUFpREUsY0FBakQsRUFBaUU7QUFBQTs7QUFBQTtBQUMvRCxVQUFJUyxNQUFNLElBQVY7QUFDQSxVQUFJTyxTQUFTLGVBQUs3QixJQUFMLENBQVUsT0FBS1QsWUFBTCxFQUFWLEVBQStCZ0IsU0FBU1EsSUFBeEMsQ0FBYjtBQUNBbEMsUUFBRyxjQUFZZ0QsTUFBTyxHQUF0Qjs7QUFFQSxVQUFJdEIsU0FBU1UsWUFBYixFQUEyQjtBQUN6QkssY0FBTSxNQUFNLGVBQU1RLElBQU4sQ0FBV0YsZ0JBQVgsQ0FBWjtBQUNBLGNBQU0sYUFBSUcsU0FBSixDQUFjRixTQUFTLE9BQXZCLEVBQWdDNUIsS0FBS0MsU0FBTCxDQUFlLEVBQUNTLFFBQUQsRUFBV0UsY0FBWCxFQUFmLENBQWhDLEVBQTRFLE1BQTVFLENBQU47QUFDRCxPQUhELE1BR087QUFDTFMsY0FBTSxNQUFNLGVBQU1RLElBQU4sQ0FBVyxJQUFJRSxNQUFKLENBQVcvQixLQUFLQyxTQUFMLENBQWUsRUFBQ1EsTUFBTWtCLGdCQUFQLEVBQXlCakIsUUFBekIsRUFBbUNFLGNBQW5DLEVBQWYsQ0FBWCxDQUFYLENBQVo7QUFDRDs7QUFFRCxZQUFNLGFBQUlrQixTQUFKLENBQWNGLE1BQWQsRUFBc0JQLEdBQXRCLENBQU47QUFaK0Q7QUFhaEU7O0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQXdCTVcsWUFBTixDQUFpQjNCLFFBQWpCLEVBQTJCNEIsT0FBM0IsRUFBb0M7QUFBQTs7QUFBQTtBQUNsQyxVQUFJQyxjQUFjLE1BQU0sT0FBSzlCLEdBQUwsQ0FBU0MsUUFBVCxDQUF4QjtBQUNBLFVBQUk2QixZQUFZekIsSUFBWixJQUFvQnlCLFlBQVl2QixVQUFwQyxFQUFnRCxPQUFPdUIsV0FBUDs7QUFFaEQsVUFBSW5CLFNBQVMsT0FBTWtCLFFBQVE1QixRQUFSLEVBQWtCNkIsWUFBWTVCLFFBQTlCLENBQU4sS0FBaUQsRUFBRUEsVUFBVTRCLFlBQVk1QixRQUF4QixFQUE5RDs7QUFFQSxVQUFJUyxPQUFPTCxRQUFQLElBQW1CLENBQUN3QixZQUFZNUIsUUFBWixDQUFxQjZCLGVBQTdDLEVBQThEO0FBQzVEdkQsVUFBRyxvQ0FBa0N5QixRQUFTLEdBQTlDO0FBQ0EsY0FBTSxPQUFLcUIsSUFBTCxDQUFVUSxZQUFZNUIsUUFBdEIsRUFBZ0NTLE9BQU9OLElBQVAsSUFBZU0sT0FBT0osVUFBdEQsRUFBa0VJLE9BQU9MLFFBQXpFLEVBQW1GSyxPQUFPSCxjQUExRixDQUFOO0FBQ0Q7O0FBRURHLGFBQU9ULFFBQVAsR0FBa0I0QixZQUFZNUIsUUFBOUI7QUFDQSxhQUFPUyxNQUFQO0FBWmtDO0FBYW5DOztBQUVEcUIsVUFBUS9CLFFBQVIsRUFBa0I7QUFDaEJ6QixNQUFHLGFBQVd5QixRQUFTLGNBQXZCO0FBQ0EsUUFBSUMsV0FBVyxLQUFLckIsZUFBTCxDQUFxQm9ELGtCQUFyQixDQUF3QyxlQUFLN0IsT0FBTCxDQUFhSCxRQUFiLENBQXhDLENBQWY7O0FBRUEsUUFBSUksT0FBTyxJQUFYO0FBQ0EsUUFBSUMsV0FBVyxJQUFmO0FBQ0EsUUFBSUMsYUFBYSxJQUFqQjtBQUNBLFFBQUlDLGlCQUFpQixJQUFyQjs7QUFFQSxRQUFJO0FBQ0YsVUFBSUMsWUFBWSxlQUFLZCxJQUFMLENBQVUsS0FBS1QsWUFBTCxFQUFWLEVBQStCZ0IsU0FBU1EsSUFBeEMsQ0FBaEI7O0FBRUEsVUFBSUMsU0FBUyxJQUFiO0FBQ0EsVUFBSVQsU0FBU1UsWUFBYixFQUEyQjtBQUN6QnBDLFVBQUUsa0NBQUY7QUFDQSxZQUFJcUMsT0FBT2pCLEtBQUtrQixLQUFMLENBQVcsYUFBR29CLFlBQUgsQ0FBZ0J6QixZQUFZLE9BQTVCLENBQVgsQ0FBWDtBQUNBSCxtQkFBV08sS0FBS1AsUUFBaEI7QUFDQUUseUJBQWlCSyxLQUFLTCxjQUF0Qjs7QUFFQUQscUJBQWFMLFNBQVNLLFVBQXRCO0FBQ0EsWUFBSSxDQUFDQSxVQUFMLEVBQWlCO0FBQ2ZBLHVCQUFhLGFBQUcyQixZQUFILENBQWdCekIsU0FBaEIsQ0FBYjtBQUNBRix1QkFBYSxlQUFLNEIsVUFBTCxDQUFnQjVCLFVBQWhCLENBQWI7QUFDRDtBQUNGLE9BWEQsTUFXTztBQUNMLFlBQUlVLE1BQU0sYUFBR2lCLFlBQUgsQ0FBZ0J6QixTQUFoQixDQUFWO0FBQ0EsWUFBSVMsTUFBTyxlQUFLaUIsVUFBTCxDQUFnQmxCLEdBQWhCLENBQUQsQ0FBdUJFLFFBQXZCLENBQWdDLE1BQWhDLENBQVY7O0FBRUFSLGlCQUFTZixLQUFLa0IsS0FBTCxDQUFXSSxHQUFYLENBQVQ7QUFDQWIsZUFBT00sT0FBT04sSUFBZDtBQUNBQyxtQkFBV0ssT0FBT0wsUUFBbEI7QUFDQUUseUJBQWlCRyxPQUFPSCxjQUF4QjtBQUNEO0FBQ0YsS0F4QkQsQ0F3QkUsT0FBT1ksQ0FBUCxFQUFVO0FBQ1Y1QyxRQUFHLDZCQUEyQnlCLFFBQVMsR0FBdkM7QUFDRDs7QUFFRCxXQUFPLEVBQUVDLFFBQUYsRUFBWUcsSUFBWixFQUFrQkMsUUFBbEIsRUFBNEJDLFVBQTVCLEVBQXdDQyxjQUF4QyxFQUFQO0FBQ0Q7O0FBRUQ0QixXQUFTbEMsUUFBVCxFQUFtQnFCLGdCQUFuQixFQUFxQ2pCLFFBQXJDLEVBQStDRSxjQUEvQyxFQUErRDtBQUM3RCxRQUFJUyxNQUFNLElBQVY7QUFDQSxRQUFJTyxTQUFTLGVBQUs3QixJQUFMLENBQVUsS0FBS1QsWUFBTCxFQUFWLEVBQStCZ0IsU0FBU1EsSUFBeEMsQ0FBYjtBQUNBbEMsTUFBRyxjQUFZZ0QsTUFBTyxHQUF0Qjs7QUFFQSxRQUFJdEIsU0FBU1UsWUFBYixFQUEyQjtBQUN6QkssWUFBTSxlQUFLb0IsUUFBTCxDQUFjZCxnQkFBZCxDQUFOO0FBQ0EsbUJBQUdlLGFBQUgsQ0FBaUJkLFNBQVMsT0FBMUIsRUFBbUM1QixLQUFLQyxTQUFMLENBQWUsRUFBQ1MsUUFBRCxFQUFXRSxjQUFYLEVBQWYsQ0FBbkMsRUFBK0UsTUFBL0U7QUFDRCxLQUhELE1BR087QUFDTFMsWUFBTSxlQUFLb0IsUUFBTCxDQUFjLElBQUlWLE1BQUosQ0FBVy9CLEtBQUtDLFNBQUwsQ0FBZSxFQUFDUSxNQUFNa0IsZ0JBQVAsRUFBeUJqQixRQUF6QixFQUFtQ0UsY0FBbkMsRUFBZixDQUFYLENBQWQsQ0FBTjtBQUNEOztBQUVELGlCQUFHOEIsYUFBSCxDQUFpQmQsTUFBakIsRUFBeUJQLEdBQXpCO0FBQ0Q7O0FBRURzQixpQkFBZXRDLFFBQWYsRUFBeUI0QixPQUF6QixFQUFrQztBQUNoQyxRQUFJQyxjQUFjLEtBQUtFLE9BQUwsQ0FBYS9CLFFBQWIsQ0FBbEI7QUFDQSxRQUFJNkIsWUFBWXpCLElBQVosSUFBb0J5QixZQUFZdkIsVUFBcEMsRUFBZ0QsT0FBT3VCLFdBQVA7O0FBRWhELFFBQUluQixTQUFTa0IsUUFBUTVCLFFBQVIsRUFBa0I2QixZQUFZNUIsUUFBOUIsS0FBMkMsRUFBRUEsVUFBVTRCLFlBQVk1QixRQUF4QixFQUF4RDs7QUFFQSxRQUFJUyxPQUFPTCxRQUFQLElBQW1CLENBQUN3QixZQUFZNUIsUUFBWixDQUFxQjZCLGVBQTdDLEVBQThEO0FBQzVEdkQsUUFBRyxvQ0FBa0N5QixRQUFTLEdBQTlDO0FBQ0EsV0FBS21DLFFBQUwsQ0FBY04sWUFBWTVCLFFBQTFCLEVBQW9DUyxPQUFPTixJQUFQLElBQWVNLE9BQU9KLFVBQTFELEVBQXNFSSxPQUFPTCxRQUE3RSxFQUF1RkssT0FBT0gsY0FBOUY7QUFDRDs7QUFFREcsV0FBT1QsUUFBUCxHQUFrQjRCLFlBQVk1QixRQUE5QjtBQUNBLFdBQU9TLE1BQVA7QUFDRDs7QUFHRDs7O0FBR0F6QixpQkFBZTtBQUNiO0FBQ0E7QUFDQSxXQUFPLEtBQUtOLFNBQVo7QUFDRDs7QUFHRDs7Ozs7Ozs7O0FBU0EsU0FBTzRELGlCQUFQLENBQXlCdEMsUUFBekIsRUFBbUM7QUFDakMsV0FBT0EsU0FBU3VDLFVBQVQsSUFBdUJ2QyxTQUFTNkIsZUFBaEMsSUFBbUQ3QixTQUFTd0MsWUFBNUQsSUFBNEV4QyxTQUFTVSxZQUE1RjtBQUNEO0FBblIrQjtrQkFBYmxDLFkiLCJmaWxlIjoiY29tcGlsZS1jYWNoZS5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBmcyBmcm9tICdmcyc7XHJcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgemxpYiBmcm9tICd6bGliJztcclxuaW1wb3J0IGNyZWF0ZURpZ2VzdEZvck9iamVjdCBmcm9tICcuL2RpZ2VzdC1mb3Itb2JqZWN0JztcclxuaW1wb3J0IHtwZnMsIHB6bGlifSBmcm9tICcuL3Byb21pc2UnO1xyXG5pbXBvcnQgbWtkaXJwIGZyb20gJ21rZGlycCc7XHJcblxyXG5jb25zdCBkID0gcmVxdWlyZSgnZGVidWctZWxlY3Ryb24nKSgnZWxlY3Ryb24tY29tcGlsZTpjb21waWxlLWNhY2hlJyk7XHJcblxyXG4vKipcclxuICogQ29tcGlsZUNhY2hlIG1hbmFnZXMgZ2V0dGluZyBhbmQgc2V0dGluZyBlbnRyaWVzIGZvciBhIHNpbmdsZSBjb21waWxlcjsgZWFjaFxyXG4gKiBpbi11c2UgY29tcGlsZXIgd2lsbCBoYXZlIGFuIGluc3RhbmNlIG9mIHRoaXMgY2xhc3MsIHVzdWFsbHkgY3JlYXRlZCB2aWFcclxuICoge0BsaW5rIGNyZWF0ZUZyb21Db21waWxlcn0uXHJcbiAqXHJcbiAqIFlvdSB1c3VhbGx5IHdpbGwgbm90IHVzZSB0aGlzIGNsYXNzIGRpcmVjdGx5LCBpdCBpcyBhbiBpbXBsZW1lbnRhdGlvbiBjbGFzc1xyXG4gKiBmb3Ige0BsaW5rIENvbXBpbGVIb3N0fS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIENvbXBpbGVDYWNoZSB7XHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSwgdXN1YWxseSB1c2VkIGZvciB0ZXN0aW5nIG9ubHkuXHJcbiAgICpcclxuICAgKiBAcGFyYW0gIHtzdHJpbmd9IGNhY2hlUGF0aCAgVGhlIHJvb3QgZGlyZWN0b3J5IHRvIHVzZSBhcyBhIGNhY2hlIHBhdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSAge0ZpbGVDaGFuZ2VkQ2FjaGV9IGZpbGVDaGFuZ2VDYWNoZSAgQSBmaWxlLWNoYW5nZSBjYWNoZSB0aGF0IGlzXHJcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25hbGx5IHByZS1sb2FkZWQuXHJcbiAgICovXHJcbiAgY29uc3RydWN0b3IoY2FjaGVQYXRoLCBmaWxlQ2hhbmdlQ2FjaGUpIHtcclxuICAgIHRoaXMuY2FjaGVQYXRoID0gY2FjaGVQYXRoO1xyXG4gICAgdGhpcy5maWxlQ2hhbmdlQ2FjaGUgPSBmaWxlQ2hhbmdlQ2FjaGU7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDcmVhdGVzIGEgQ29tcGlsZUNhY2hlIGZyb20gYSBjbGFzcyBjb21wYXRpYmxlIHdpdGggdGhlIENvbXBpbGVyQmFzZVxyXG4gICAqIGludGVyZmFjZS4gVGhpcyBtZXRob2QgdXNlcyB0aGUgY29tcGlsZXIgbmFtZSAvIHZlcnNpb24gLyBvcHRpb25zIHRvXHJcbiAgICogZ2VuZXJhdGUgYSB1bmlxdWUgZGlyZWN0b3J5IG5hbWUgZm9yIGNhY2hlZCByZXN1bHRzXHJcbiAgICpcclxuICAgKiBAcGFyYW0gIHtzdHJpbmd9IGNhY2hlUGF0aCAgVGhlIHJvb3QgcGF0aCB0byB1c2UgZm9yIHRoZSBjYWNoZSwgYSBkaXJlY3RvcnlcclxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwcmVzZW50aW5nIHRoZSBoYXNoIG9mIHRoZSBjb21waWxlciBwYXJhbWV0ZXJzXHJcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpbGwgYmUgY3JlYXRlZCBoZXJlLlxyXG4gICAqXHJcbiAgICogQHBhcmFtICB7Q29tcGlsZXJCYXNlfSBjb21waWxlciAgVGhlIGNvbXBpbGVyIHRvIHVzZSBmb3IgdmVyc2lvbiAvIG9wdGlvblxyXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZm9ybWF0aW9uLlxyXG4gICAqXHJcbiAgICogQHBhcmFtICB7RmlsZUNoYW5nZWRDYWNoZX0gZmlsZUNoYW5nZUNhY2hlICBBIGZpbGUtY2hhbmdlIGNhY2hlIHRoYXQgaXNcclxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbmFsbHkgcHJlLWxvYWRlZC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSAge2Jvb2xlYW59IHJlYWRPbmx5TW9kZSAgRG9uJ3QgYXR0ZW1wdCB0byBjcmVhdGUgdGhlIGNhY2hlIGRpcmVjdG9yeS5cclxuICAgKlxyXG4gICAqIEByZXR1cm4ge0NvbXBpbGVDYWNoZX0gIEEgY29uZmlndXJlZCBDb21waWxlQ2FjaGUgaW5zdGFuY2UuXHJcbiAgICovXHJcbiAgc3RhdGljIGNyZWF0ZUZyb21Db21waWxlcihjYWNoZVBhdGgsIGNvbXBpbGVyLCBmaWxlQ2hhbmdlQ2FjaGUsIHJlYWRPbmx5TW9kZT1mYWxzZSkge1xyXG4gICAgbGV0IG5ld0NhY2hlUGF0aCA9IG51bGw7XHJcbiAgICBsZXQgZ2V0Q2FjaGVQYXRoID0gKCkgPT4ge1xyXG4gICAgICBpZiAobmV3Q2FjaGVQYXRoKSByZXR1cm4gbmV3Q2FjaGVQYXRoO1xyXG5cclxuICAgICAgY29uc3QgZGlnZXN0T2JqID0ge1xyXG4gICAgICAgIG5hbWU6IGNvbXBpbGVyLm5hbWUgfHwgT2JqZWN0LmdldFByb3RvdHlwZU9mKGNvbXBpbGVyKS5jb25zdHJ1Y3Rvci5uYW1lLFxyXG4gICAgICAgIHZlcnNpb246IGNvbXBpbGVyLmdldENvbXBpbGVyVmVyc2lvbigpLFxyXG4gICAgICAgIG9wdGlvbnM6IGNvbXBpbGVyLmNvbXBpbGVyT3B0aW9uc1xyXG4gICAgICB9O1xyXG5cclxuICAgICAgbmV3Q2FjaGVQYXRoID0gcGF0aC5qb2luKGNhY2hlUGF0aCwgY3JlYXRlRGlnZXN0Rm9yT2JqZWN0KGRpZ2VzdE9iaikpO1xyXG5cclxuICAgICAgZChgUGF0aCBmb3IgJHtkaWdlc3RPYmoubmFtZX06ICR7bmV3Q2FjaGVQYXRofWApO1xyXG4gICAgICBkKGBTZXQgdXAgd2l0aCBwYXJhbWV0ZXJzOiAke0pTT04uc3RyaW5naWZ5KGRpZ2VzdE9iail9YCk7XHJcblxyXG4gICAgICBpZiAoIXJlYWRPbmx5TW9kZSkgbWtkaXJwLnN5bmMobmV3Q2FjaGVQYXRoKTtcclxuICAgICAgcmV0dXJuIG5ld0NhY2hlUGF0aDtcclxuICAgIH07XHJcblxyXG4gICAgbGV0IHJldCA9IG5ldyBDb21waWxlQ2FjaGUoJycsIGZpbGVDaGFuZ2VDYWNoZSk7XHJcbiAgICByZXQuZ2V0Q2FjaGVQYXRoID0gZ2V0Q2FjaGVQYXRoO1xyXG5cclxuICAgIHJldHVybiByZXQ7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBSZXR1cm5zIGEgZmlsZSdzIGNvbXBpbGVkIGNvbnRlbnRzIGZyb20gdGhlIGNhY2hlLlxyXG4gICAqXHJcbiAgICogQHBhcmFtICB7c3RyaW5nfSBmaWxlUGF0aCAgVGhlIHBhdGggdG8gdGhlIGZpbGUuIEZpbGVDaGFuZ2VkQ2FjaGUgd2lsbCBsb29rXHJcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgdXAgdGhlIGhhc2ggYW5kIHVzZSB0aGF0IGFzIHRoZSBrZXkgaW4gdGhlIGNhY2hlLlxyXG4gICAqXHJcbiAgICogQHJldHVybiB7UHJvbWlzZTxPYmplY3Q+fSAgQW4gb2JqZWN0IHdpdGggYWxsIGtpbmRzIG9mIGluZm9ybWF0aW9uXHJcbiAgICpcclxuICAgKiBAcHJvcGVydHkge09iamVjdH0gaGFzaEluZm8gIFRoZSBoYXNoIGluZm9ybWF0aW9uIHJldHVybmVkIGZyb20gZ2V0SGFzaEZvclBhdGhcclxuICAgKiBAcHJvcGVydHkge3N0cmluZ30gY29kZSAgVGhlIHNvdXJjZSBjb2RlIGlmIHRoZSBmaWxlIHdhcyBhIHRleHQgZmlsZVxyXG4gICAqIEBwcm9wZXJ0eSB7QnVmZmVyfSBiaW5hcnlEYXRhICBUaGUgZmlsZSBpZiBpdCB3YXMgYSBiaW5hcnkgZmlsZVxyXG4gICAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBtaW1lVHlwZSAgVGhlIE1JTUUgdHlwZSBzYXZlZCBpbiB0aGUgY2FjaGUuXHJcbiAgICogQHByb3BlcnR5IHtzdHJpbmdbXX0gZGVwZW5kZW50RmlsZXMgIFRoZSBkZXBlbmRlbnQgZmlsZXMgcmV0dXJuZWQgZnJvbVxyXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21waWxpbmcgdGhlIGZpbGUsIGlmIGFueS5cclxuICAgKi9cclxuICBhc3luYyBnZXQoZmlsZVBhdGgpIHtcclxuICAgIGQoYEZldGNoaW5nICR7ZmlsZVBhdGh9IGZyb20gY2FjaGVgKTtcclxuICAgIGxldCBoYXNoSW5mbyA9IGF3YWl0IHRoaXMuZmlsZUNoYW5nZUNhY2hlLmdldEhhc2hGb3JQYXRoKHBhdGgucmVzb2x2ZShmaWxlUGF0aCkpO1xyXG5cclxuICAgIGxldCBjb2RlID0gbnVsbDtcclxuICAgIGxldCBtaW1lVHlwZSA9IG51bGw7XHJcbiAgICBsZXQgYmluYXJ5RGF0YSA9IG51bGw7XHJcbiAgICBsZXQgZGVwZW5kZW50RmlsZXMgPSBudWxsO1xyXG5cclxuICAgIGxldCBjYWNoZUZpbGUgPSBudWxsO1xyXG4gICAgdHJ5IHtcclxuICAgICAgY2FjaGVGaWxlID0gcGF0aC5qb2luKHRoaXMuZ2V0Q2FjaGVQYXRoKCksIGhhc2hJbmZvLmhhc2gpO1xyXG4gICAgICBsZXQgcmVzdWx0ID0gbnVsbDtcclxuXHJcbiAgICAgIGlmIChoYXNoSW5mby5pc0ZpbGVCaW5hcnkpIHtcclxuICAgICAgICBkKFwiRmlsZSBpcyBiaW5hcnksIHJlYWRpbmcgb3V0IGluZm9cIik7XHJcbiAgICAgICAgbGV0IGluZm8gPSBKU09OLnBhcnNlKGF3YWl0IHBmcy5yZWFkRmlsZShjYWNoZUZpbGUgKyAnLmluZm8nKSk7XHJcbiAgICAgICAgbWltZVR5cGUgPSBpbmZvLm1pbWVUeXBlO1xyXG4gICAgICAgIGRlcGVuZGVudEZpbGVzID0gaW5mby5kZXBlbmRlbnRGaWxlcztcclxuXHJcbiAgICAgICAgYmluYXJ5RGF0YSA9IGhhc2hJbmZvLmJpbmFyeURhdGE7XHJcbiAgICAgICAgaWYgKCFiaW5hcnlEYXRhKSB7XHJcbiAgICAgICAgICBiaW5hcnlEYXRhID0gYXdhaXQgcGZzLnJlYWRGaWxlKGNhY2hlRmlsZSk7XHJcbiAgICAgICAgICBiaW5hcnlEYXRhID0gYXdhaXQgcHpsaWIuZ3VuemlwKGJpbmFyeURhdGEpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsZXQgYnVmID0gYXdhaXQgcGZzLnJlYWRGaWxlKGNhY2hlRmlsZSk7XHJcbiAgICAgICAgbGV0IHN0ciA9IChhd2FpdCBwemxpYi5ndW56aXAoYnVmKSkudG9TdHJpbmcoJ3V0ZjgnKTtcclxuXHJcbiAgICAgICAgcmVzdWx0ID0gSlNPTi5wYXJzZShzdHIpO1xyXG4gICAgICAgIGNvZGUgPSByZXN1bHQuY29kZTtcclxuICAgICAgICBtaW1lVHlwZSA9IHJlc3VsdC5taW1lVHlwZTtcclxuICAgICAgICBkZXBlbmRlbnRGaWxlcyA9IHJlc3VsdC5kZXBlbmRlbnRGaWxlcztcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICBkKGBGYWlsZWQgdG8gcmVhZCBjYWNoZSBmb3IgJHtmaWxlUGF0aH0sIGxvb2tlZCBpbiAke2NhY2hlRmlsZX06ICR7ZS5tZXNzYWdlfWApO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB7IGhhc2hJbmZvLCBjb2RlLCBtaW1lVHlwZSwgYmluYXJ5RGF0YSwgZGVwZW5kZW50RmlsZXMgfTtcclxuICB9XHJcblxyXG5cclxuICAvKipcclxuICAgKiBTYXZlcyBhIGNvbXBpbGVkIHJlc3VsdCB0byBjYWNoZVxyXG4gICAqXHJcbiAgICogQHBhcmFtICB7T2JqZWN0fSBoYXNoSW5mbyAgVGhlIGhhc2ggaW5mb3JtYXRpb24gcmV0dXJuZWQgZnJvbSBnZXRIYXNoRm9yUGF0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtICB7c3RyaW5nIC8gQnVmZmVyfSBjb2RlT3JCaW5hcnlEYXRhICAgVGhlIGZpbGUncyBjb250ZW50cywgZWl0aGVyIGFzXHJcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYSBzdHJpbmcgb3IgYSBCdWZmZXIuXHJcbiAgICogQHBhcmFtICB7c3RyaW5nfSBtaW1lVHlwZSAgVGhlIE1JTUUgdHlwZSByZXR1cm5lZCBieSB0aGUgY29tcGlsZXIuXHJcbiAgICpcclxuICAgKiBAcGFyYW0gIHtzdHJpbmdbXX0gZGVwZW5kZW50RmlsZXMgIFRoZSBsaXN0IG9mIGRlcGVuZGVudCBmaWxlcyByZXR1cm5lZCBieVxyXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIGNvbXBpbGVyLlxyXG4gICAqIEByZXR1cm4ge1Byb21pc2V9ICBDb21wbGV0aW9uLlxyXG4gICAqL1xyXG4gIGFzeW5jIHNhdmUoaGFzaEluZm8sIGNvZGVPckJpbmFyeURhdGEsIG1pbWVUeXBlLCBkZXBlbmRlbnRGaWxlcykge1xyXG4gICAgbGV0IGJ1ZiA9IG51bGw7XHJcbiAgICBsZXQgdGFyZ2V0ID0gcGF0aC5qb2luKHRoaXMuZ2V0Q2FjaGVQYXRoKCksIGhhc2hJbmZvLmhhc2gpO1xyXG4gICAgZChgU2F2aW5nIHRvICR7dGFyZ2V0fWApO1xyXG5cclxuICAgIGlmIChoYXNoSW5mby5pc0ZpbGVCaW5hcnkpIHtcclxuICAgICAgYnVmID0gYXdhaXQgcHpsaWIuZ3ppcChjb2RlT3JCaW5hcnlEYXRhKTtcclxuICAgICAgYXdhaXQgcGZzLndyaXRlRmlsZSh0YXJnZXQgKyAnLmluZm8nLCBKU09OLnN0cmluZ2lmeSh7bWltZVR5cGUsIGRlcGVuZGVudEZpbGVzfSksICd1dGY4Jyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBidWYgPSBhd2FpdCBwemxpYi5nemlwKG5ldyBCdWZmZXIoSlNPTi5zdHJpbmdpZnkoe2NvZGU6IGNvZGVPckJpbmFyeURhdGEsIG1pbWVUeXBlLCBkZXBlbmRlbnRGaWxlc30pKSk7XHJcbiAgICB9XHJcblxyXG4gICAgYXdhaXQgcGZzLndyaXRlRmlsZSh0YXJnZXQsIGJ1Zik7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBBdHRlbXB0cyB0byBmaXJzdCBnZXQgYSBrZXkgdmlhIHtAbGluayBnZXR9LCB0aGVuIGlmIGl0IGZhaWxzLCBjYWxsIGEgbWV0aG9kXHJcbiAgICogdG8gcmV0cmlldmUgdGhlIGNvbnRlbnRzLCB0aGVuIHNhdmUgdGhlIHJlc3VsdCB0byBjYWNoZS5cclxuICAgKlxyXG4gICAqIFRoZSBmZXRjaGVyIHBhcmFtZXRlciBpcyBleHBlY3RlZCB0byBoYXZlIHRoZSBzaWduYXR1cmU6XHJcbiAgICpcclxuICAgKiBQcm9taXNlPE9iamVjdD4gZmV0Y2hlcihmaWxlUGF0aCA6IHN0cmluZywgaGFzaEluZm8gOiBPYmplY3QpO1xyXG4gICAqXHJcbiAgICogaGFzaEluZm8gaXMgYSB2YWx1ZSByZXR1cm5lZCBmcm9tIGdldEhhc2hGb3JQYXRoXHJcbiAgICogVGhlIHJldHVybiB2YWx1ZSBvZiBmZXRjaGVyIG11c3QgYmUgYW4gT2JqZWN0IHdpdGggdGhlIHByb3BlcnRpZXM6XHJcbiAgICpcclxuICAgKiBtaW1lVHlwZSAtIHRoZSBNSU1FIHR5cGUgb2YgdGhlIGRhdGEgdG8gc2F2ZVxyXG4gICAqIGNvZGUgKG9wdGlvbmFsKSAtIHRoZSBzb3VyY2UgY29kZSBhcyBhIHN0cmluZywgaWYgZmlsZSBpcyB0ZXh0XHJcbiAgICogYmluYXJ5RGF0YSAob3B0aW9uYWwpIC0gdGhlIGZpbGUgY29udGVudHMgYXMgYSBCdWZmZXIsIGlmIGZpbGUgaXMgYmluYXJ5XHJcbiAgICogZGVwZW5kZW50RmlsZXMgLSB0aGUgZGVwZW5kZW50IGZpbGVzIHJldHVybmVkIGJ5IHRoZSBjb21waWxlci5cclxuICAgKlxyXG4gICAqIEBwYXJhbSAge3N0cmluZ30gZmlsZVBhdGggIFRoZSBwYXRoIHRvIHRoZSBmaWxlLiBGaWxlQ2hhbmdlZENhY2hlIHdpbGwgbG9va1xyXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwIHRoZSBoYXNoIGFuZCB1c2UgdGhhdCBhcyB0aGUga2V5IGluIHRoZSBjYWNoZS5cclxuICAgKlxyXG4gICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBmZXRjaGVyICBBIG1ldGhvZCB3aGljaCBjb25mb3JtcyB0byB0aGUgZGVzY3JpcHRpb24gYWJvdmUuXHJcbiAgICpcclxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE9iamVjdD59ICBBbiBPYmplY3Qgd2hpY2ggaGFzIHRoZSBzYW1lIGZpZWxkcyBhcyB0aGVcclxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7QGxpbmsgZ2V0fSBtZXRob2QgcmV0dXJuIHJlc3VsdC5cclxuICAgKi9cclxuICBhc3luYyBnZXRPckZldGNoKGZpbGVQYXRoLCBmZXRjaGVyKSB7XHJcbiAgICBsZXQgY2FjaGVSZXN1bHQgPSBhd2FpdCB0aGlzLmdldChmaWxlUGF0aCk7XHJcbiAgICBpZiAoY2FjaGVSZXN1bHQuY29kZSB8fCBjYWNoZVJlc3VsdC5iaW5hcnlEYXRhKSByZXR1cm4gY2FjaGVSZXN1bHQ7XHJcblxyXG4gICAgbGV0IHJlc3VsdCA9IGF3YWl0IGZldGNoZXIoZmlsZVBhdGgsIGNhY2hlUmVzdWx0Lmhhc2hJbmZvKSB8fCB7IGhhc2hJbmZvOiBjYWNoZVJlc3VsdC5oYXNoSW5mbyB9O1xyXG5cclxuICAgIGlmIChyZXN1bHQubWltZVR5cGUgJiYgIWNhY2hlUmVzdWx0Lmhhc2hJbmZvLmlzSW5Ob2RlTW9kdWxlcykge1xyXG4gICAgICBkKGBDYWNoZSBtaXNzOiBzYXZpbmcgb3V0IGluZm8gZm9yICR7ZmlsZVBhdGh9YCk7XHJcbiAgICAgIGF3YWl0IHRoaXMuc2F2ZShjYWNoZVJlc3VsdC5oYXNoSW5mbywgcmVzdWx0LmNvZGUgfHwgcmVzdWx0LmJpbmFyeURhdGEsIHJlc3VsdC5taW1lVHlwZSwgcmVzdWx0LmRlcGVuZGVudEZpbGVzKTtcclxuICAgIH1cclxuXHJcbiAgICByZXN1bHQuaGFzaEluZm8gPSBjYWNoZVJlc3VsdC5oYXNoSW5mbztcclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfVxyXG5cclxuICBnZXRTeW5jKGZpbGVQYXRoKSB7XHJcbiAgICBkKGBGZXRjaGluZyAke2ZpbGVQYXRofSBmcm9tIGNhY2hlYCk7XHJcbiAgICBsZXQgaGFzaEluZm8gPSB0aGlzLmZpbGVDaGFuZ2VDYWNoZS5nZXRIYXNoRm9yUGF0aFN5bmMocGF0aC5yZXNvbHZlKGZpbGVQYXRoKSk7XHJcblxyXG4gICAgbGV0IGNvZGUgPSBudWxsO1xyXG4gICAgbGV0IG1pbWVUeXBlID0gbnVsbDtcclxuICAgIGxldCBiaW5hcnlEYXRhID0gbnVsbDtcclxuICAgIGxldCBkZXBlbmRlbnRGaWxlcyA9IG51bGw7XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgbGV0IGNhY2hlRmlsZSA9IHBhdGguam9pbih0aGlzLmdldENhY2hlUGF0aCgpLCBoYXNoSW5mby5oYXNoKTtcclxuXHJcbiAgICAgIGxldCByZXN1bHQgPSBudWxsO1xyXG4gICAgICBpZiAoaGFzaEluZm8uaXNGaWxlQmluYXJ5KSB7XHJcbiAgICAgICAgZChcIkZpbGUgaXMgYmluYXJ5LCByZWFkaW5nIG91dCBpbmZvXCIpO1xyXG4gICAgICAgIGxldCBpbmZvID0gSlNPTi5wYXJzZShmcy5yZWFkRmlsZVN5bmMoY2FjaGVGaWxlICsgJy5pbmZvJykpO1xyXG4gICAgICAgIG1pbWVUeXBlID0gaW5mby5taW1lVHlwZTtcclxuICAgICAgICBkZXBlbmRlbnRGaWxlcyA9IGluZm8uZGVwZW5kZW50RmlsZXM7XHJcblxyXG4gICAgICAgIGJpbmFyeURhdGEgPSBoYXNoSW5mby5iaW5hcnlEYXRhO1xyXG4gICAgICAgIGlmICghYmluYXJ5RGF0YSkge1xyXG4gICAgICAgICAgYmluYXJ5RGF0YSA9IGZzLnJlYWRGaWxlU3luYyhjYWNoZUZpbGUpO1xyXG4gICAgICAgICAgYmluYXJ5RGF0YSA9IHpsaWIuZ3VuemlwU3luYyhiaW5hcnlEYXRhKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbGV0IGJ1ZiA9IGZzLnJlYWRGaWxlU3luYyhjYWNoZUZpbGUpO1xyXG4gICAgICAgIGxldCBzdHIgPSAoemxpYi5ndW56aXBTeW5jKGJ1ZikpLnRvU3RyaW5nKCd1dGY4Jyk7XHJcblxyXG4gICAgICAgIHJlc3VsdCA9IEpTT04ucGFyc2Uoc3RyKTtcclxuICAgICAgICBjb2RlID0gcmVzdWx0LmNvZGU7XHJcbiAgICAgICAgbWltZVR5cGUgPSByZXN1bHQubWltZVR5cGU7XHJcbiAgICAgICAgZGVwZW5kZW50RmlsZXMgPSByZXN1bHQuZGVwZW5kZW50RmlsZXM7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgZChgRmFpbGVkIHRvIHJlYWQgY2FjaGUgZm9yICR7ZmlsZVBhdGh9YCk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHsgaGFzaEluZm8sIGNvZGUsIG1pbWVUeXBlLCBiaW5hcnlEYXRhLCBkZXBlbmRlbnRGaWxlcyB9O1xyXG4gIH1cclxuXHJcbiAgc2F2ZVN5bmMoaGFzaEluZm8sIGNvZGVPckJpbmFyeURhdGEsIG1pbWVUeXBlLCBkZXBlbmRlbnRGaWxlcykge1xyXG4gICAgbGV0IGJ1ZiA9IG51bGw7XHJcbiAgICBsZXQgdGFyZ2V0ID0gcGF0aC5qb2luKHRoaXMuZ2V0Q2FjaGVQYXRoKCksIGhhc2hJbmZvLmhhc2gpO1xyXG4gICAgZChgU2F2aW5nIHRvICR7dGFyZ2V0fWApO1xyXG5cclxuICAgIGlmIChoYXNoSW5mby5pc0ZpbGVCaW5hcnkpIHtcclxuICAgICAgYnVmID0gemxpYi5nemlwU3luYyhjb2RlT3JCaW5hcnlEYXRhKTtcclxuICAgICAgZnMud3JpdGVGaWxlU3luYyh0YXJnZXQgKyAnLmluZm8nLCBKU09OLnN0cmluZ2lmeSh7bWltZVR5cGUsIGRlcGVuZGVudEZpbGVzfSksICd1dGY4Jyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBidWYgPSB6bGliLmd6aXBTeW5jKG5ldyBCdWZmZXIoSlNPTi5zdHJpbmdpZnkoe2NvZGU6IGNvZGVPckJpbmFyeURhdGEsIG1pbWVUeXBlLCBkZXBlbmRlbnRGaWxlc30pKSk7XHJcbiAgICB9XHJcblxyXG4gICAgZnMud3JpdGVGaWxlU3luYyh0YXJnZXQsIGJ1Zik7XHJcbiAgfVxyXG5cclxuICBnZXRPckZldGNoU3luYyhmaWxlUGF0aCwgZmV0Y2hlcikge1xyXG4gICAgbGV0IGNhY2hlUmVzdWx0ID0gdGhpcy5nZXRTeW5jKGZpbGVQYXRoKTtcclxuICAgIGlmIChjYWNoZVJlc3VsdC5jb2RlIHx8IGNhY2hlUmVzdWx0LmJpbmFyeURhdGEpIHJldHVybiBjYWNoZVJlc3VsdDtcclxuXHJcbiAgICBsZXQgcmVzdWx0ID0gZmV0Y2hlcihmaWxlUGF0aCwgY2FjaGVSZXN1bHQuaGFzaEluZm8pIHx8IHsgaGFzaEluZm86IGNhY2hlUmVzdWx0Lmhhc2hJbmZvIH07XHJcblxyXG4gICAgaWYgKHJlc3VsdC5taW1lVHlwZSAmJiAhY2FjaGVSZXN1bHQuaGFzaEluZm8uaXNJbk5vZGVNb2R1bGVzKSB7XHJcbiAgICAgIGQoYENhY2hlIG1pc3M6IHNhdmluZyBvdXQgaW5mbyBmb3IgJHtmaWxlUGF0aH1gKTtcclxuICAgICAgdGhpcy5zYXZlU3luYyhjYWNoZVJlc3VsdC5oYXNoSW5mbywgcmVzdWx0LmNvZGUgfHwgcmVzdWx0LmJpbmFyeURhdGEsIHJlc3VsdC5taW1lVHlwZSwgcmVzdWx0LmRlcGVuZGVudEZpbGVzKTtcclxuICAgIH1cclxuXHJcbiAgICByZXN1bHQuaGFzaEluZm8gPSBjYWNoZVJlc3VsdC5oYXNoSW5mbztcclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfVxyXG5cclxuXHJcbiAgLyoqXHJcbiAgICogQHByaXZhdGVcclxuICAgKi9cclxuICBnZXRDYWNoZVBhdGgoKSB7XHJcbiAgICAvLyBOQjogVGhpcyBpcyBhbiBldmlsIGhhY2sgc28gdGhhdCBjcmVhdGVGcm9tQ29tcGlsZXIgY2FuIHN0b21wIGl0XHJcbiAgICAvLyBhdCB3aWxsXHJcbiAgICByZXR1cm4gdGhpcy5jYWNoZVBhdGg7XHJcbiAgfVxyXG5cclxuXHJcbiAgLyoqXHJcbiAgICogUmV0dXJucyB3aGV0aGVyIGEgZmlsZSBzaG91bGQgbm90IGJlIGNvbXBpbGVkLiBOb3RlIHRoYXQgdGhpcyBkb2Vzbid0XHJcbiAgICogbmVjZXNzYXJpbHkgbWVhbiBpdCB3b24ndCBlbmQgdXAgaW4gdGhlIGNhY2hlLCBvbmx5IHRoYXQgaXRzIGNvbnRlbnRzIGFyZVxyXG4gICAqIHNhdmVkIHZlcmJhdGltIGluc3RlYWQgb2YgdHJ5aW5nIHRvIGZpbmQgYW4gYXBwcm9wcmlhdGUgY29tcGlsZXIuXHJcbiAgICpcclxuICAgKiBAcGFyYW0gIHtPYmplY3R9IGhhc2hJbmZvICBUaGUgaGFzaCBpbmZvcm1hdGlvbiByZXR1cm5lZCBmcm9tIGdldEhhc2hGb3JQYXRoXHJcbiAgICpcclxuICAgKiBAcmV0dXJuIHtib29sZWFufSAgVHJ1ZSBpZiBhIGZpbGUgc2hvdWxkIGJlIGlnbm9yZWRcclxuICAgKi9cclxuICBzdGF0aWMgc2hvdWxkUGFzc3Rocm91Z2goaGFzaEluZm8pIHtcclxuICAgIHJldHVybiBoYXNoSW5mby5pc01pbmlmaWVkIHx8IGhhc2hJbmZvLmlzSW5Ob2RlTW9kdWxlcyB8fCBoYXNoSW5mby5oYXNTb3VyY2VNYXAgfHwgaGFzaEluZm8uaXNGaWxlQmluYXJ5O1xyXG4gIH1cclxufVxyXG4iXX0=
;