UNPKG

electron-compile

Version:

Electron supporting package to compile JS and CSS in Electron applications

528 lines (417 loc) 40.2 kB
'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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9jb21waWxlLWNhY2hlLmpzIl0sIm5hbWVzIjpbImQiLCJyZXF1aXJlIiwiQ29tcGlsZUNhY2hlIiwiY2FjaGVQYXRoIiwiZmlsZUNoYW5nZUNhY2hlIiwiZmlsZVBhdGgiLCJnZXRIYXNoRm9yUGF0aCIsInJlc29sdmUiLCJoYXNoSW5mbyIsImNvZGUiLCJtaW1lVHlwZSIsImJpbmFyeURhdGEiLCJkZXBlbmRlbnRGaWxlcyIsImNhY2hlRmlsZSIsImpvaW4iLCJnZXRDYWNoZVBhdGgiLCJoYXNoIiwicmVzdWx0IiwiaXNGaWxlQmluYXJ5IiwiSlNPTiIsInJlYWRGaWxlIiwiaW5mbyIsInBhcnNlIiwiZ3VuemlwIiwiYnVmIiwic3RyIiwidG9TdHJpbmciLCJtZXNzYWdlIiwiY29kZU9yQmluYXJ5RGF0YSIsInRhcmdldCIsImd6aXAiLCJ3cml0ZUZpbGUiLCJCdWZmZXIiLCJmZXRjaGVyIiwiZ2V0IiwiY2FjaGVSZXN1bHQiLCJpc0luTm9kZU1vZHVsZXMiLCJzYXZlIiwiZ2V0SGFzaEZvclBhdGhTeW5jIiwicmVhZEZpbGVTeW5jIiwiZ3VuemlwU3luYyIsImUiLCJnemlwU3luYyIsIndyaXRlRmlsZVN5bmMiLCJnZXRTeW5jIiwic2F2ZVN5bmMiLCJjb21waWxlciIsInJlYWRPbmx5TW9kZSIsIm5ld0NhY2hlUGF0aCIsImRpZ2VzdE9iaiIsIm5hbWUiLCJjb25zdHJ1Y3RvciIsInZlcnNpb24iLCJnZXRDb21waWxlclZlcnNpb24iLCJvcHRpb25zIiwiY29tcGlsZXJPcHRpb25zIiwic3luYyIsInJldCIsImlzTWluaWZpZWQiLCJoYXNTb3VyY2VNYXAiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBOzs7O0FBQ0E7Ozs7QUFDQTs7OztBQUNBOzs7O0FBQ0E7O0FBQ0E7Ozs7OztBQUVBLElBQU1BLElBQUlDLFFBQVEsZ0JBQVIsRUFBMEIsZ0NBQTFCLENBQVY7O0FBRUE7Ozs7Ozs7OztJQVFxQkMsWTtBQUNuQjs7Ozs7Ozs7QUFRQSx3QkFBWUMsU0FBWixFQUF1QkMsZUFBdkIsRUFBd0M7QUFBQTs7QUFDdEMsU0FBS0QsU0FBTCxHQUFpQkEsU0FBakI7QUFDQSxTQUFLQyxlQUFMLEdBQXVCQSxlQUF2QjtBQUNEOztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBNkNBOzs7Ozs7Ozs7Ozs7Ozs7OzZGQWVVQyxROzs7Ozs7QUFDUkwsZ0NBQWNLLFFBQWQ7O3VCQUNxQixLQUFLRCxlQUFMLENBQXFCRSxjQUFyQixDQUFvQyxlQUFLQyxPQUFMLENBQWFGLFFBQWIsQ0FBcEMsQzs7O0FBQWpCRyx3QjtBQUVBQyxvQixHQUFPLEk7QUFDUEMsd0IsR0FBVyxJO0FBQ1hDLDBCLEdBQWEsSTtBQUNiQyw4QixHQUFpQixJO0FBRWpCQyx5QixHQUFZLEk7OztBQUVkQSw0QkFBWSxlQUFLQyxJQUFMLENBQVUsS0FBS0MsWUFBTCxFQUFWLEVBQStCUCxTQUFTUSxJQUF4QyxDQUFaO0FBQ0lDLHNCLEdBQVMsSTs7cUJBRVRULFNBQVNVLFk7Ozs7O0FBQ1hsQixrQkFBRSxrQ0FBRjs4QkFDV21CLEk7O3VCQUFpQixhQUFJQyxRQUFKLENBQWFQLFlBQVksT0FBekIsQzs7OztBQUF4QlEsb0IsZUFBWUMsSzs7QUFDaEJaLDJCQUFXVyxLQUFLWCxRQUFoQjtBQUNBRSxpQ0FBaUJTLEtBQUtULGNBQXRCOztBQUVBRCw2QkFBYUgsU0FBU0csVUFBdEI7O29CQUNLQSxVOzs7Ozs7dUJBQ2dCLGFBQUlTLFFBQUosQ0FBYVAsU0FBYixDOzs7QUFBbkJGLDBCOzt1QkFDbUIsZUFBTVksTUFBTixDQUFhWixVQUFiLEM7OztBQUFuQkEsMEI7Ozs7Ozs7O3VCQUdjLGFBQUlTLFFBQUosQ0FBYVAsU0FBYixDOzs7QUFBWlcsbUI7O3VCQUNhLGVBQU1ELE1BQU4sQ0FBYUMsR0FBYixDOzs7QUFBYkMsbUIsaUJBQWdDQyxRLENBQVMsTTs7O0FBRTdDVCx5QkFBU0UsS0FBS0csS0FBTCxDQUFXRyxHQUFYLENBQVQ7QUFDQWhCLHVCQUFPUSxPQUFPUixJQUFkO0FBQ0FDLDJCQUFXTyxPQUFPUCxRQUFsQjtBQUNBRSxpQ0FBaUJLLE9BQU9MLGNBQXhCOzs7Ozs7Ozs7O0FBR0ZaLGdEQUE4QkssUUFBOUIsb0JBQXFEUSxTQUFyRCxVQUFtRSxZQUFFYyxPQUFyRTs7O2lEQUdLLEVBQUVuQixrQkFBRixFQUFZQyxVQUFaLEVBQWtCQyxrQkFBbEIsRUFBNEJDLHNCQUE1QixFQUF3Q0MsOEJBQXhDLEU7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBSVQ7Ozs7Ozs7Ozs7Ozs7Ozs7OytGQWFXSixRLEVBQVVvQixnQixFQUFrQmxCLFEsRUFBVUUsYzs7Ozs7O0FBQzNDWSxtQixHQUFNLEk7QUFDTkssc0IsR0FBUyxlQUFLZixJQUFMLENBQVUsS0FBS0MsWUFBTCxFQUFWLEVBQStCUCxTQUFTUSxJQUF4QyxDOztBQUNiaEIsaUNBQWU2QixNQUFmOztxQkFFSXJCLFNBQVNVLFk7Ozs7Ozt1QkFDQyxlQUFNWSxJQUFOLENBQVdGLGdCQUFYLEM7OztBQUFaSixtQjs7dUJBQ00sYUFBSU8sU0FBSixDQUFjRixTQUFTLE9BQXZCLEVBQWdDLHlCQUFlLEVBQUNuQixrQkFBRCxFQUFXRSw4QkFBWCxFQUFmLENBQWhDLEVBQTRFLE1BQTVFLEM7Ozs7Ozs7O3VCQUVNLGVBQU1rQixJQUFOLENBQVcsSUFBSUUsTUFBSixDQUFXLHlCQUFlLEVBQUN2QixNQUFNbUIsZ0JBQVAsRUFBeUJsQixrQkFBekIsRUFBbUNFLDhCQUFuQyxFQUFmLENBQVgsQ0FBWCxDOzs7QUFBWlksbUI7Ozs7dUJBR0ksYUFBSU8sU0FBSixDQUFjRixNQUFkLEVBQXNCTCxHQUF0QixDOzs7Ozs7Ozs7Ozs7Ozs7OztBQUdSOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OytGQXdCaUJuQixRLEVBQVU0QixPOzs7Ozs7O3VCQUNELEtBQUtDLEdBQUwsQ0FBUzdCLFFBQVQsQzs7O0FBQXBCOEIsMkI7O3NCQUNBQSxZQUFZMUIsSUFBWixJQUFvQjBCLFlBQVl4QixVOzs7OztrREFBbUJ3QixXOzs7O3VCQUVwQ0YsUUFBUTVCLFFBQVIsRUFBa0I4QixZQUFZM0IsUUFBOUIsQzs7Ozs7Ozs7OzsrQkFBMkMsRUFBRUEsVUFBVTJCLFlBQVkzQixRQUF4QixFOzs7QUFBMURTLHNCOztzQkFFQUEsT0FBT1AsUUFBUCxJQUFtQixDQUFDeUIsWUFBWTNCLFFBQVosQ0FBcUI0QixlOzs7OztBQUMzQ3BDLHVEQUFxQ0ssUUFBckM7O3VCQUNNLEtBQUtnQyxJQUFMLENBQVVGLFlBQVkzQixRQUF0QixFQUFnQ1MsT0FBT1IsSUFBUCxJQUFlUSxPQUFPTixVQUF0RCxFQUFrRU0sT0FBT1AsUUFBekUsRUFBbUZPLE9BQU9MLGNBQTFGLEM7Ozs7QUFHUkssdUJBQU9ULFFBQVAsR0FBa0IyQixZQUFZM0IsUUFBOUI7a0RBQ09TLE07Ozs7Ozs7Ozs7Ozs7Ozs7Ozs0QkFHRFosUSxFQUFVO0FBQ2hCTCxzQkFBY0ssUUFBZDtBQUNBLFVBQUlHLFdBQVcsS0FBS0osZUFBTCxDQUFxQmtDLGtCQUFyQixDQUF3QyxlQUFLL0IsT0FBTCxDQUFhRixRQUFiLENBQXhDLENBQWY7O0FBRUEsVUFBSUksT0FBTyxJQUFYO0FBQ0EsVUFBSUMsV0FBVyxJQUFmO0FBQ0EsVUFBSUMsYUFBYSxJQUFqQjtBQUNBLFVBQUlDLGlCQUFpQixJQUFyQjs7QUFFQSxVQUFJO0FBQ0YsWUFBSUMsWUFBWSxlQUFLQyxJQUFMLENBQVUsS0FBS0MsWUFBTCxFQUFWLEVBQStCUCxTQUFTUSxJQUF4QyxDQUFoQjs7QUFFQSxZQUFJQyxTQUFTLElBQWI7QUFDQSxZQUFJVCxTQUFTVSxZQUFiLEVBQTJCO0FBQ3pCbEIsWUFBRSxrQ0FBRjtBQUNBLGNBQUlxQixPQUFPRixLQUFLRyxLQUFMLENBQVcsYUFBR2lCLFlBQUgsQ0FBZ0IxQixZQUFZLE9BQTVCLENBQVgsQ0FBWDtBQUNBSCxxQkFBV1csS0FBS1gsUUFBaEI7QUFDQUUsMkJBQWlCUyxLQUFLVCxjQUF0Qjs7QUFFQUQsdUJBQWFILFNBQVNHLFVBQXRCO0FBQ0EsY0FBSSxDQUFDQSxVQUFMLEVBQWlCO0FBQ2ZBLHlCQUFhLGFBQUc0QixZQUFILENBQWdCMUIsU0FBaEIsQ0FBYjtBQUNBRix5QkFBYSxlQUFLNkIsVUFBTCxDQUFnQjdCLFVBQWhCLENBQWI7QUFDRDtBQUNGLFNBWEQsTUFXTztBQUNMLGNBQUlhLE1BQU0sYUFBR2UsWUFBSCxDQUFnQjFCLFNBQWhCLENBQVY7QUFDQSxjQUFJWSxNQUFPLGVBQUtlLFVBQUwsQ0FBZ0JoQixHQUFoQixDQUFELENBQXVCRSxRQUF2QixDQUFnQyxNQUFoQyxDQUFWOztBQUVBVCxtQkFBU0UsS0FBS0csS0FBTCxDQUFXRyxHQUFYLENBQVQ7QUFDQWhCLGlCQUFPUSxPQUFPUixJQUFkO0FBQ0FDLHFCQUFXTyxPQUFPUCxRQUFsQjtBQUNBRSwyQkFBaUJLLE9BQU9MLGNBQXhCO0FBQ0Q7QUFDRixPQXhCRCxDQXdCRSxPQUFPNkIsQ0FBUCxFQUFVO0FBQ1Z6Qyx3Q0FBOEJLLFFBQTlCO0FBQ0Q7O0FBRUQsYUFBTyxFQUFFRyxrQkFBRixFQUFZQyxVQUFaLEVBQWtCQyxrQkFBbEIsRUFBNEJDLHNCQUE1QixFQUF3Q0MsOEJBQXhDLEVBQVA7QUFDRDs7OzZCQUVRSixRLEVBQVVvQixnQixFQUFrQmxCLFEsRUFBVUUsYyxFQUFnQjtBQUM3RCxVQUFJWSxNQUFNLElBQVY7QUFDQSxVQUFJSyxTQUFTLGVBQUtmLElBQUwsQ0FBVSxLQUFLQyxZQUFMLEVBQVYsRUFBK0JQLFNBQVNRLElBQXhDLENBQWI7QUFDQWhCLHVCQUFlNkIsTUFBZjs7QUFFQSxVQUFJckIsU0FBU1UsWUFBYixFQUEyQjtBQUN6Qk0sY0FBTSxlQUFLa0IsUUFBTCxDQUFjZCxnQkFBZCxDQUFOO0FBQ0EscUJBQUdlLGFBQUgsQ0FBaUJkLFNBQVMsT0FBMUIsRUFBbUMseUJBQWUsRUFBQ25CLGtCQUFELEVBQVdFLDhCQUFYLEVBQWYsQ0FBbkMsRUFBK0UsTUFBL0U7QUFDRCxPQUhELE1BR087QUFDTFksY0FBTSxlQUFLa0IsUUFBTCxDQUFjLElBQUlWLE1BQUosQ0FBVyx5QkFBZSxFQUFDdkIsTUFBTW1CLGdCQUFQLEVBQXlCbEIsa0JBQXpCLEVBQW1DRSw4QkFBbkMsRUFBZixDQUFYLENBQWQsQ0FBTjtBQUNEOztBQUVELG1CQUFHK0IsYUFBSCxDQUFpQmQsTUFBakIsRUFBeUJMLEdBQXpCO0FBQ0Q7OzttQ0FFY25CLFEsRUFBVTRCLE8sRUFBUztBQUNoQyxVQUFJRSxjQUFjLEtBQUtTLE9BQUwsQ0FBYXZDLFFBQWIsQ0FBbEI7QUFDQSxVQUFJOEIsWUFBWTFCLElBQVosSUFBb0IwQixZQUFZeEIsVUFBcEMsRUFBZ0QsT0FBT3dCLFdBQVA7O0FBRWhELFVBQUlsQixTQUFTZ0IsUUFBUTVCLFFBQVIsRUFBa0I4QixZQUFZM0IsUUFBOUIsS0FBMkMsRUFBRUEsVUFBVTJCLFlBQVkzQixRQUF4QixFQUF4RDs7QUFFQSxVQUFJUyxPQUFPUCxRQUFQLElBQW1CLENBQUN5QixZQUFZM0IsUUFBWixDQUFxQjRCLGVBQTdDLEVBQThEO0FBQzVEcEMsK0NBQXFDSyxRQUFyQztBQUNBLGFBQUt3QyxRQUFMLENBQWNWLFlBQVkzQixRQUExQixFQUFvQ1MsT0FBT1IsSUFBUCxJQUFlUSxPQUFPTixVQUExRCxFQUFzRU0sT0FBT1AsUUFBN0UsRUFBdUZPLE9BQU9MLGNBQTlGO0FBQ0Q7O0FBRURLLGFBQU9ULFFBQVAsR0FBa0IyQixZQUFZM0IsUUFBOUI7QUFDQSxhQUFPUyxNQUFQO0FBQ0Q7O0FBR0Q7Ozs7OzttQ0FHZTtBQUNiO0FBQ0E7QUFDQSxhQUFPLEtBQUtkLFNBQVo7QUFDRDs7QUFHRDs7Ozs7Ozs7Ozs7O3VDQXZPMEJBLFMsRUFBVzJDLFEsRUFBVTFDLGUsRUFBcUM7QUFBQSxVQUFwQjJDLFlBQW9CLHVFQUFQLEtBQU87O0FBQ2xGLFVBQUlDLGVBQWUsSUFBbkI7QUFDQSxVQUFJakMsZUFBZSxTQUFmQSxZQUFlLEdBQU07QUFDdkIsWUFBSWlDLFlBQUosRUFBa0IsT0FBT0EsWUFBUDs7QUFFbEIsWUFBTUMsWUFBWTtBQUNoQkMsZ0JBQU1KLFNBQVNJLElBQVQsSUFBaUIsOEJBQXNCSixRQUF0QixFQUFnQ0ssV0FBaEMsQ0FBNENELElBRG5EO0FBRWhCRSxtQkFBU04sU0FBU08sa0JBQVQsRUFGTztBQUdoQkMsbUJBQVNSLFNBQVNTO0FBSEYsU0FBbEI7O0FBTUFQLHVCQUFlLGVBQUtsQyxJQUFMLENBQVVYLFNBQVYsRUFBcUIsK0JBQXNCOEMsU0FBdEIsQ0FBckIsQ0FBZjs7QUFFQWpELHdCQUFjaUQsVUFBVUMsSUFBeEIsVUFBaUNGLFlBQWpDO0FBQ0FoRCx1Q0FBNkIseUJBQWVpRCxTQUFmLENBQTdCOztBQUVBLFlBQUksQ0FBQ0YsWUFBTCxFQUFtQixpQkFBT1MsSUFBUCxDQUFZUixZQUFaO0FBQ25CLGVBQU9BLFlBQVA7QUFDRCxPQWhCRDs7QUFrQkEsVUFBSVMsTUFBTSxJQUFJdkQsWUFBSixDQUFpQixFQUFqQixFQUFxQkUsZUFBckIsQ0FBVjtBQUNBcUQsVUFBSTFDLFlBQUosR0FBbUJBLFlBQW5COztBQUVBLGFBQU8wQyxHQUFQO0FBQ0Q7OztzQ0F3TndCakQsUSxFQUFVO0FBQ2pDLGFBQU9BLFNBQVNrRCxVQUFULElBQXVCbEQsU0FBUzRCLGVBQWhDLElBQW1ENUIsU0FBU21ELFlBQTVELElBQTRFbkQsU0FBU1UsWUFBNUY7QUFDRDs7Ozs7a0JBblJrQmhCLFkiLCJmaWxlIjoiY29tcGlsZS1jYWNoZS5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBmcyBmcm9tICdmcyc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB6bGliIGZyb20gJ3psaWInO1xuaW1wb3J0IGNyZWF0ZURpZ2VzdEZvck9iamVjdCBmcm9tICcuL2RpZ2VzdC1mb3Itb2JqZWN0JztcbmltcG9ydCB7cGZzLCBwemxpYn0gZnJvbSAnLi9wcm9taXNlJztcbmltcG9ydCBta2RpcnAgZnJvbSAnbWtkaXJwJztcblxuY29uc3QgZCA9IHJlcXVpcmUoJ2RlYnVnLWVsZWN0cm9uJykoJ2VsZWN0cm9uLWNvbXBpbGU6Y29tcGlsZS1jYWNoZScpO1xuXG4vKipcbiAqIENvbXBpbGVDYWNoZSBtYW5hZ2VzIGdldHRpbmcgYW5kIHNldHRpbmcgZW50cmllcyBmb3IgYSBzaW5nbGUgY29tcGlsZXI7IGVhY2hcbiAqIGluLXVzZSBjb21waWxlciB3aWxsIGhhdmUgYW4gaW5zdGFuY2Ugb2YgdGhpcyBjbGFzcywgdXN1YWxseSBjcmVhdGVkIHZpYVxuICoge0BsaW5rIGNyZWF0ZUZyb21Db21waWxlcn0uXG4gKlxuICogWW91IHVzdWFsbHkgd2lsbCBub3QgdXNlIHRoaXMgY2xhc3MgZGlyZWN0bHksIGl0IGlzIGFuIGltcGxlbWVudGF0aW9uIGNsYXNzXG4gKiBmb3Ige0BsaW5rIENvbXBpbGVIb3N0fS5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQ29tcGlsZUNhY2hlIHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gaW5zdGFuY2UsIHVzdWFsbHkgdXNlZCBmb3IgdGVzdGluZyBvbmx5LlxuICAgKlxuICAgKiBAcGFyYW0gIHtzdHJpbmd9IGNhY2hlUGF0aCAgVGhlIHJvb3QgZGlyZWN0b3J5IHRvIHVzZSBhcyBhIGNhY2hlIHBhdGhcbiAgICpcbiAgICogQHBhcmFtICB7RmlsZUNoYW5nZWRDYWNoZX0gZmlsZUNoYW5nZUNhY2hlICBBIGZpbGUtY2hhbmdlIGNhY2hlIHRoYXQgaXNcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25hbGx5IHByZS1sb2FkZWQuXG4gICAqL1xuICBjb25zdHJ1Y3RvcihjYWNoZVBhdGgsIGZpbGVDaGFuZ2VDYWNoZSkge1xuICAgIHRoaXMuY2FjaGVQYXRoID0gY2FjaGVQYXRoO1xuICAgIHRoaXMuZmlsZUNoYW5nZUNhY2hlID0gZmlsZUNoYW5nZUNhY2hlO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBDb21waWxlQ2FjaGUgZnJvbSBhIGNsYXNzIGNvbXBhdGlibGUgd2l0aCB0aGUgQ29tcGlsZXJCYXNlXG4gICAqIGludGVyZmFjZS4gVGhpcyBtZXRob2QgdXNlcyB0aGUgY29tcGlsZXIgbmFtZSAvIHZlcnNpb24gLyBvcHRpb25zIHRvXG4gICAqIGdlbmVyYXRlIGEgdW5pcXVlIGRpcmVjdG9yeSBuYW1lIGZvciBjYWNoZWQgcmVzdWx0c1xuICAgKlxuICAgKiBAcGFyYW0gIHtzdHJpbmd9IGNhY2hlUGF0aCAgVGhlIHJvb3QgcGF0aCB0byB1c2UgZm9yIHRoZSBjYWNoZSwgYSBkaXJlY3RvcnlcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcHJlc2VudGluZyB0aGUgaGFzaCBvZiB0aGUgY29tcGlsZXIgcGFyYW1ldGVyc1xuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lsbCBiZSBjcmVhdGVkIGhlcmUuXG4gICAqXG4gICAqIEBwYXJhbSAge0NvbXBpbGVyQmFzZX0gY29tcGlsZXIgIFRoZSBjb21waWxlciB0byB1c2UgZm9yIHZlcnNpb24gLyBvcHRpb25cbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mb3JtYXRpb24uXG4gICAqXG4gICAqIEBwYXJhbSAge0ZpbGVDaGFuZ2VkQ2FjaGV9IGZpbGVDaGFuZ2VDYWNoZSAgQSBmaWxlLWNoYW5nZSBjYWNoZSB0aGF0IGlzXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uYWxseSBwcmUtbG9hZGVkLlxuICAgKlxuICAgKiBAcGFyYW0gIHtib29sZWFufSByZWFkT25seU1vZGUgIERvbid0IGF0dGVtcHQgdG8gY3JlYXRlIHRoZSBjYWNoZSBkaXJlY3RvcnkuXG4gICAqXG4gICAqIEByZXR1cm4ge0NvbXBpbGVDYWNoZX0gIEEgY29uZmlndXJlZCBDb21waWxlQ2FjaGUgaW5zdGFuY2UuXG4gICAqL1xuICBzdGF0aWMgY3JlYXRlRnJvbUNvbXBpbGVyKGNhY2hlUGF0aCwgY29tcGlsZXIsIGZpbGVDaGFuZ2VDYWNoZSwgcmVhZE9ubHlNb2RlPWZhbHNlKSB7XG4gICAgbGV0IG5ld0NhY2hlUGF0aCA9IG51bGw7XG4gICAgbGV0IGdldENhY2hlUGF0aCA9ICgpID0+IHtcbiAgICAgIGlmIChuZXdDYWNoZVBhdGgpIHJldHVybiBuZXdDYWNoZVBhdGg7XG5cbiAgICAgIGNvbnN0IGRpZ2VzdE9iaiA9IHtcbiAgICAgICAgbmFtZTogY29tcGlsZXIubmFtZSB8fCBPYmplY3QuZ2V0UHJvdG90eXBlT2YoY29tcGlsZXIpLmNvbnN0cnVjdG9yLm5hbWUsXG4gICAgICAgIHZlcnNpb246IGNvbXBpbGVyLmdldENvbXBpbGVyVmVyc2lvbigpLFxuICAgICAgICBvcHRpb25zOiBjb21waWxlci5jb21waWxlck9wdGlvbnNcbiAgICAgIH07XG5cbiAgICAgIG5ld0NhY2hlUGF0aCA9IHBhdGguam9pbihjYWNoZVBhdGgsIGNyZWF0ZURpZ2VzdEZvck9iamVjdChkaWdlc3RPYmopKTtcblxuICAgICAgZChgUGF0aCBmb3IgJHtkaWdlc3RPYmoubmFtZX06ICR7bmV3Q2FjaGVQYXRofWApO1xuICAgICAgZChgU2V0IHVwIHdpdGggcGFyYW1ldGVyczogJHtKU09OLnN0cmluZ2lmeShkaWdlc3RPYmopfWApO1xuXG4gICAgICBpZiAoIXJlYWRPbmx5TW9kZSkgbWtkaXJwLnN5bmMobmV3Q2FjaGVQYXRoKTtcbiAgICAgIHJldHVybiBuZXdDYWNoZVBhdGg7XG4gICAgfTtcblxuICAgIGxldCByZXQgPSBuZXcgQ29tcGlsZUNhY2hlKCcnLCBmaWxlQ2hhbmdlQ2FjaGUpO1xuICAgIHJldC5nZXRDYWNoZVBhdGggPSBnZXRDYWNoZVBhdGg7XG5cbiAgICByZXR1cm4gcmV0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBmaWxlJ3MgY29tcGlsZWQgY29udGVudHMgZnJvbSB0aGUgY2FjaGUuXG4gICAqXG4gICAqIEBwYXJhbSAge3N0cmluZ30gZmlsZVBhdGggIFRoZSBwYXRoIHRvIHRoZSBmaWxlLiBGaWxlQ2hhbmdlZENhY2hlIHdpbGwgbG9va1xuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cCB0aGUgaGFzaCBhbmQgdXNlIHRoYXQgYXMgdGhlIGtleSBpbiB0aGUgY2FjaGUuXG4gICAqXG4gICAqIEByZXR1cm4ge1Byb21pc2U8T2JqZWN0Pn0gIEFuIG9iamVjdCB3aXRoIGFsbCBraW5kcyBvZiBpbmZvcm1hdGlvblxuICAgKlxuICAgKiBAcHJvcGVydHkge09iamVjdH0gaGFzaEluZm8gIFRoZSBoYXNoIGluZm9ybWF0aW9uIHJldHVybmVkIGZyb20gZ2V0SGFzaEZvclBhdGhcbiAgICogQHByb3BlcnR5IHtzdHJpbmd9IGNvZGUgIFRoZSBzb3VyY2UgY29kZSBpZiB0aGUgZmlsZSB3YXMgYSB0ZXh0IGZpbGVcbiAgICogQHByb3BlcnR5IHtCdWZmZXJ9IGJpbmFyeURhdGEgIFRoZSBmaWxlIGlmIGl0IHdhcyBhIGJpbmFyeSBmaWxlXG4gICAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBtaW1lVHlwZSAgVGhlIE1JTUUgdHlwZSBzYXZlZCBpbiB0aGUgY2FjaGUuXG4gICAqIEBwcm9wZXJ0eSB7c3RyaW5nW119IGRlcGVuZGVudEZpbGVzICBUaGUgZGVwZW5kZW50IGZpbGVzIHJldHVybmVkIGZyb21cbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbXBpbGluZyB0aGUgZmlsZSwgaWYgYW55LlxuICAgKi9cbiAgYXN5bmMgZ2V0KGZpbGVQYXRoKSB7XG4gICAgZChgRmV0Y2hpbmcgJHtmaWxlUGF0aH0gZnJvbSBjYWNoZWApO1xuICAgIGxldCBoYXNoSW5mbyA9IGF3YWl0IHRoaXMuZmlsZUNoYW5nZUNhY2hlLmdldEhhc2hGb3JQYXRoKHBhdGgucmVzb2x2ZShmaWxlUGF0aCkpO1xuXG4gICAgbGV0IGNvZGUgPSBudWxsO1xuICAgIGxldCBtaW1lVHlwZSA9IG51bGw7XG4gICAgbGV0IGJpbmFyeURhdGEgPSBudWxsO1xuICAgIGxldCBkZXBlbmRlbnRGaWxlcyA9IG51bGw7XG5cbiAgICBsZXQgY2FjaGVGaWxlID0gbnVsbDtcbiAgICB0cnkge1xuICAgICAgY2FjaGVGaWxlID0gcGF0aC5qb2luKHRoaXMuZ2V0Q2FjaGVQYXRoKCksIGhhc2hJbmZvLmhhc2gpO1xuICAgICAgbGV0IHJlc3VsdCA9IG51bGw7XG5cbiAgICAgIGlmIChoYXNoSW5mby5pc0ZpbGVCaW5hcnkpIHtcbiAgICAgICAgZChcIkZpbGUgaXMgYmluYXJ5LCByZWFkaW5nIG91dCBpbmZvXCIpO1xuICAgICAgICBsZXQgaW5mbyA9IEpTT04ucGFyc2UoYXdhaXQgcGZzLnJlYWRGaWxlKGNhY2hlRmlsZSArICcuaW5mbycpKTtcbiAgICAgICAgbWltZVR5cGUgPSBpbmZvLm1pbWVUeXBlO1xuICAgICAgICBkZXBlbmRlbnRGaWxlcyA9IGluZm8uZGVwZW5kZW50RmlsZXM7XG5cbiAgICAgICAgYmluYXJ5RGF0YSA9IGhhc2hJbmZvLmJpbmFyeURhdGE7XG4gICAgICAgIGlmICghYmluYXJ5RGF0YSkge1xuICAgICAgICAgIGJpbmFyeURhdGEgPSBhd2FpdCBwZnMucmVhZEZpbGUoY2FjaGVGaWxlKTtcbiAgICAgICAgICBiaW5hcnlEYXRhID0gYXdhaXQgcHpsaWIuZ3VuemlwKGJpbmFyeURhdGEpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgYnVmID0gYXdhaXQgcGZzLnJlYWRGaWxlKGNhY2hlRmlsZSk7XG4gICAgICAgIGxldCBzdHIgPSAoYXdhaXQgcHpsaWIuZ3VuemlwKGJ1ZikpLnRvU3RyaW5nKCd1dGY4Jyk7XG5cbiAgICAgICAgcmVzdWx0ID0gSlNPTi5wYXJzZShzdHIpO1xuICAgICAgICBjb2RlID0gcmVzdWx0LmNvZGU7XG4gICAgICAgIG1pbWVUeXBlID0gcmVzdWx0Lm1pbWVUeXBlO1xuICAgICAgICBkZXBlbmRlbnRGaWxlcyA9IHJlc3VsdC5kZXBlbmRlbnRGaWxlcztcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBkKGBGYWlsZWQgdG8gcmVhZCBjYWNoZSBmb3IgJHtmaWxlUGF0aH0sIGxvb2tlZCBpbiAke2NhY2hlRmlsZX06ICR7ZS5tZXNzYWdlfWApO1xuICAgIH1cblxuICAgIHJldHVybiB7IGhhc2hJbmZvLCBjb2RlLCBtaW1lVHlwZSwgYmluYXJ5RGF0YSwgZGVwZW5kZW50RmlsZXMgfTtcbiAgfVxuXG5cbiAgLyoqXG4gICAqIFNhdmVzIGEgY29tcGlsZWQgcmVzdWx0IHRvIGNhY2hlXG4gICAqXG4gICAqIEBwYXJhbSAge09iamVjdH0gaGFzaEluZm8gIFRoZSBoYXNoIGluZm9ybWF0aW9uIHJldHVybmVkIGZyb20gZ2V0SGFzaEZvclBhdGhcbiAgICpcbiAgICogQHBhcmFtICB7c3RyaW5nIC8gQnVmZmVyfSBjb2RlT3JCaW5hcnlEYXRhICAgVGhlIGZpbGUncyBjb250ZW50cywgZWl0aGVyIGFzXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGEgc3RyaW5nIG9yIGEgQnVmZmVyLlxuICAgKiBAcGFyYW0gIHtzdHJpbmd9IG1pbWVUeXBlICBUaGUgTUlNRSB0eXBlIHJldHVybmVkIGJ5IHRoZSBjb21waWxlci5cbiAgICpcbiAgICogQHBhcmFtICB7c3RyaW5nW119IGRlcGVuZGVudEZpbGVzICBUaGUgbGlzdCBvZiBkZXBlbmRlbnQgZmlsZXMgcmV0dXJuZWQgYnlcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgY29tcGlsZXIuXG4gICAqIEByZXR1cm4ge1Byb21pc2V9ICBDb21wbGV0aW9uLlxuICAgKi9cbiAgYXN5bmMgc2F2ZShoYXNoSW5mbywgY29kZU9yQmluYXJ5RGF0YSwgbWltZVR5cGUsIGRlcGVuZGVudEZpbGVzKSB7XG4gICAgbGV0IGJ1ZiA9IG51bGw7XG4gICAgbGV0IHRhcmdldCA9IHBhdGguam9pbih0aGlzLmdldENhY2hlUGF0aCgpLCBoYXNoSW5mby5oYXNoKTtcbiAgICBkKGBTYXZpbmcgdG8gJHt0YXJnZXR9YCk7XG5cbiAgICBpZiAoaGFzaEluZm8uaXNGaWxlQmluYXJ5KSB7XG4gICAgICBidWYgPSBhd2FpdCBwemxpYi5nemlwKGNvZGVPckJpbmFyeURhdGEpO1xuICAgICAgYXdhaXQgcGZzLndyaXRlRmlsZSh0YXJnZXQgKyAnLmluZm8nLCBKU09OLnN0cmluZ2lmeSh7bWltZVR5cGUsIGRlcGVuZGVudEZpbGVzfSksICd1dGY4Jyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGJ1ZiA9IGF3YWl0IHB6bGliLmd6aXAobmV3IEJ1ZmZlcihKU09OLnN0cmluZ2lmeSh7Y29kZTogY29kZU9yQmluYXJ5RGF0YSwgbWltZVR5cGUsIGRlcGVuZGVudEZpbGVzfSkpKTtcbiAgICB9XG5cbiAgICBhd2FpdCBwZnMud3JpdGVGaWxlKHRhcmdldCwgYnVmKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBdHRlbXB0cyB0byBmaXJzdCBnZXQgYSBrZXkgdmlhIHtAbGluayBnZXR9LCB0aGVuIGlmIGl0IGZhaWxzLCBjYWxsIGEgbWV0aG9kXG4gICAqIHRvIHJldHJpZXZlIHRoZSBjb250ZW50cywgdGhlbiBzYXZlIHRoZSByZXN1bHQgdG8gY2FjaGUuXG4gICAqXG4gICAqIFRoZSBmZXRjaGVyIHBhcmFtZXRlciBpcyBleHBlY3RlZCB0byBoYXZlIHRoZSBzaWduYXR1cmU6XG4gICAqXG4gICAqIFByb21pc2U8T2JqZWN0PiBmZXRjaGVyKGZpbGVQYXRoIDogc3RyaW5nLCBoYXNoSW5mbyA6IE9iamVjdCk7XG4gICAqXG4gICAqIGhhc2hJbmZvIGlzIGEgdmFsdWUgcmV0dXJuZWQgZnJvbSBnZXRIYXNoRm9yUGF0aFxuICAgKiBUaGUgcmV0dXJuIHZhbHVlIG9mIGZldGNoZXIgbXVzdCBiZSBhbiBPYmplY3Qgd2l0aCB0aGUgcHJvcGVydGllczpcbiAgICpcbiAgICogbWltZVR5cGUgLSB0aGUgTUlNRSB0eXBlIG9mIHRoZSBkYXRhIHRvIHNhdmVcbiAgICogY29kZSAob3B0aW9uYWwpIC0gdGhlIHNvdXJjZSBjb2RlIGFzIGEgc3RyaW5nLCBpZiBmaWxlIGlzIHRleHRcbiAgICogYmluYXJ5RGF0YSAob3B0aW9uYWwpIC0gdGhlIGZpbGUgY29udGVudHMgYXMgYSBCdWZmZXIsIGlmIGZpbGUgaXMgYmluYXJ5XG4gICAqIGRlcGVuZGVudEZpbGVzIC0gdGhlIGRlcGVuZGVudCBmaWxlcyByZXR1cm5lZCBieSB0aGUgY29tcGlsZXIuXG4gICAqXG4gICAqIEBwYXJhbSAge3N0cmluZ30gZmlsZVBhdGggIFRoZSBwYXRoIHRvIHRoZSBmaWxlLiBGaWxlQ2hhbmdlZENhY2hlIHdpbGwgbG9va1xuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cCB0aGUgaGFzaCBhbmQgdXNlIHRoYXQgYXMgdGhlIGtleSBpbiB0aGUgY2FjaGUuXG4gICAqXG4gICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBmZXRjaGVyICBBIG1ldGhvZCB3aGljaCBjb25mb3JtcyB0byB0aGUgZGVzY3JpcHRpb24gYWJvdmUuXG4gICAqXG4gICAqIEByZXR1cm4ge1Byb21pc2U8T2JqZWN0Pn0gIEFuIE9iamVjdCB3aGljaCBoYXMgdGhlIHNhbWUgZmllbGRzIGFzIHRoZVxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7QGxpbmsgZ2V0fSBtZXRob2QgcmV0dXJuIHJlc3VsdC5cbiAgICovXG4gIGFzeW5jIGdldE9yRmV0Y2goZmlsZVBhdGgsIGZldGNoZXIpIHtcbiAgICBsZXQgY2FjaGVSZXN1bHQgPSBhd2FpdCB0aGlzLmdldChmaWxlUGF0aCk7XG4gICAgaWYgKGNhY2hlUmVzdWx0LmNvZGUgfHwgY2FjaGVSZXN1bHQuYmluYXJ5RGF0YSkgcmV0dXJuIGNhY2hlUmVzdWx0O1xuXG4gICAgbGV0IHJlc3VsdCA9IGF3YWl0IGZldGNoZXIoZmlsZVBhdGgsIGNhY2hlUmVzdWx0Lmhhc2hJbmZvKSB8fCB7IGhhc2hJbmZvOiBjYWNoZVJlc3VsdC5oYXNoSW5mbyB9O1xuXG4gICAgaWYgKHJlc3VsdC5taW1lVHlwZSAmJiAhY2FjaGVSZXN1bHQuaGFzaEluZm8uaXNJbk5vZGVNb2R1bGVzKSB7XG4gICAgICBkKGBDYWNoZSBtaXNzOiBzYXZpbmcgb3V0IGluZm8gZm9yICR7ZmlsZVBhdGh9YCk7XG4gICAgICBhd2FpdCB0aGlzLnNhdmUoY2FjaGVSZXN1bHQuaGFzaEluZm8sIHJlc3VsdC5jb2RlIHx8IHJlc3VsdC5iaW5hcnlEYXRhLCByZXN1bHQubWltZVR5cGUsIHJlc3VsdC5kZXBlbmRlbnRGaWxlcyk7XG4gICAgfVxuXG4gICAgcmVzdWx0Lmhhc2hJbmZvID0gY2FjaGVSZXN1bHQuaGFzaEluZm87XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGdldFN5bmMoZmlsZVBhdGgpIHtcbiAgICBkKGBGZXRjaGluZyAke2ZpbGVQYXRofSBmcm9tIGNhY2hlYCk7XG4gICAgbGV0IGhhc2hJbmZvID0gdGhpcy5maWxlQ2hhbmdlQ2FjaGUuZ2V0SGFzaEZvclBhdGhTeW5jKHBhdGgucmVzb2x2ZShmaWxlUGF0aCkpO1xuXG4gICAgbGV0IGNvZGUgPSBudWxsO1xuICAgIGxldCBtaW1lVHlwZSA9IG51bGw7XG4gICAgbGV0IGJpbmFyeURhdGEgPSBudWxsO1xuICAgIGxldCBkZXBlbmRlbnRGaWxlcyA9IG51bGw7XG5cbiAgICB0cnkge1xuICAgICAgbGV0IGNhY2hlRmlsZSA9IHBhdGguam9pbih0aGlzLmdldENhY2hlUGF0aCgpLCBoYXNoSW5mby5oYXNoKTtcblxuICAgICAgbGV0IHJlc3VsdCA9IG51bGw7XG4gICAgICBpZiAoaGFzaEluZm8uaXNGaWxlQmluYXJ5KSB7XG4gICAgICAgIGQoXCJGaWxlIGlzIGJpbmFyeSwgcmVhZGluZyBvdXQgaW5mb1wiKTtcbiAgICAgICAgbGV0IGluZm8gPSBKU09OLnBhcnNlKGZzLnJlYWRGaWxlU3luYyhjYWNoZUZpbGUgKyAnLmluZm8nKSk7XG4gICAgICAgIG1pbWVUeXBlID0gaW5mby5taW1lVHlwZTtcbiAgICAgICAgZGVwZW5kZW50RmlsZXMgPSBpbmZvLmRlcGVuZGVudEZpbGVzO1xuXG4gICAgICAgIGJpbmFyeURhdGEgPSBoYXNoSW5mby5iaW5hcnlEYXRhO1xuICAgICAgICBpZiAoIWJpbmFyeURhdGEpIHtcbiAgICAgICAgICBiaW5hcnlEYXRhID0gZnMucmVhZEZpbGVTeW5jKGNhY2hlRmlsZSk7XG4gICAgICAgICAgYmluYXJ5RGF0YSA9IHpsaWIuZ3VuemlwU3luYyhiaW5hcnlEYXRhKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbGV0IGJ1ZiA9IGZzLnJlYWRGaWxlU3luYyhjYWNoZUZpbGUpO1xuICAgICAgICBsZXQgc3RyID0gKHpsaWIuZ3VuemlwU3luYyhidWYpKS50b1N0cmluZygndXRmOCcpO1xuXG4gICAgICAgIHJlc3VsdCA9IEpTT04ucGFyc2Uoc3RyKTtcbiAgICAgICAgY29kZSA9IHJlc3VsdC5jb2RlO1xuICAgICAgICBtaW1lVHlwZSA9IHJlc3VsdC5taW1lVHlwZTtcbiAgICAgICAgZGVwZW5kZW50RmlsZXMgPSByZXN1bHQuZGVwZW5kZW50RmlsZXM7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgZChgRmFpbGVkIHRvIHJlYWQgY2FjaGUgZm9yICR7ZmlsZVBhdGh9YCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgaGFzaEluZm8sIGNvZGUsIG1pbWVUeXBlLCBiaW5hcnlEYXRhLCBkZXBlbmRlbnRGaWxlcyB9O1xuICB9XG5cbiAgc2F2ZVN5bmMoaGFzaEluZm8sIGNvZGVPckJpbmFyeURhdGEsIG1pbWVUeXBlLCBkZXBlbmRlbnRGaWxlcykge1xuICAgIGxldCBidWYgPSBudWxsO1xuICAgIGxldCB0YXJnZXQgPSBwYXRoLmpvaW4odGhpcy5nZXRDYWNoZVBhdGgoKSwgaGFzaEluZm8uaGFzaCk7XG4gICAgZChgU2F2aW5nIHRvICR7dGFyZ2V0fWApO1xuXG4gICAgaWYgKGhhc2hJbmZvLmlzRmlsZUJpbmFyeSkge1xuICAgICAgYnVmID0gemxpYi5nemlwU3luYyhjb2RlT3JCaW5hcnlEYXRhKTtcbiAgICAgIGZzLndyaXRlRmlsZVN5bmModGFyZ2V0ICsgJy5pbmZvJywgSlNPTi5zdHJpbmdpZnkoe21pbWVUeXBlLCBkZXBlbmRlbnRGaWxlc30pLCAndXRmOCcpO1xuICAgIH0gZWxzZSB7XG4gICAgICBidWYgPSB6bGliLmd6aXBTeW5jKG5ldyBCdWZmZXIoSlNPTi5zdHJpbmdpZnkoe2NvZGU6IGNvZGVPckJpbmFyeURhdGEsIG1pbWVUeXBlLCBkZXBlbmRlbnRGaWxlc30pKSk7XG4gICAgfVxuXG4gICAgZnMud3JpdGVGaWxlU3luYyh0YXJnZXQsIGJ1Zik7XG4gIH1cblxuICBnZXRPckZldGNoU3luYyhmaWxlUGF0aCwgZmV0Y2hlcikge1xuICAgIGxldCBjYWNoZVJlc3VsdCA9IHRoaXMuZ2V0U3luYyhmaWxlUGF0aCk7XG4gICAgaWYgKGNhY2hlUmVzdWx0LmNvZGUgfHwgY2FjaGVSZXN1bHQuYmluYXJ5RGF0YSkgcmV0dXJuIGNhY2hlUmVzdWx0O1xuXG4gICAgbGV0IHJlc3VsdCA9IGZldGNoZXIoZmlsZVBhdGgsIGNhY2hlUmVzdWx0Lmhhc2hJbmZvKSB8fCB7IGhhc2hJbmZvOiBjYWNoZVJlc3VsdC5oYXNoSW5mbyB9O1xuXG4gICAgaWYgKHJlc3VsdC5taW1lVHlwZSAmJiAhY2FjaGVSZXN1bHQuaGFzaEluZm8uaXNJbk5vZGVNb2R1bGVzKSB7XG4gICAgICBkKGBDYWNoZSBtaXNzOiBzYXZpbmcgb3V0IGluZm8gZm9yICR7ZmlsZVBhdGh9YCk7XG4gICAgICB0aGlzLnNhdmVTeW5jKGNhY2hlUmVzdWx0Lmhhc2hJbmZvLCByZXN1bHQuY29kZSB8fCByZXN1bHQuYmluYXJ5RGF0YSwgcmVzdWx0Lm1pbWVUeXBlLCByZXN1bHQuZGVwZW5kZW50RmlsZXMpO1xuICAgIH1cblxuICAgIHJlc3VsdC5oYXNoSW5mbyA9IGNhY2hlUmVzdWx0Lmhhc2hJbmZvO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgZ2V0Q2FjaGVQYXRoKCkge1xuICAgIC8vIE5COiBUaGlzIGlzIGFuIGV2aWwgaGFjayBzbyB0aGF0IGNyZWF0ZUZyb21Db21waWxlciBjYW4gc3RvbXAgaXRcbiAgICAvLyBhdCB3aWxsXG4gICAgcmV0dXJuIHRoaXMuY2FjaGVQYXRoO1xuICB9XG5cblxuICAvKipcbiAgICogUmV0dXJucyB3aGV0aGVyIGEgZmlsZSBzaG91bGQgbm90IGJlIGNvbXBpbGVkLiBOb3RlIHRoYXQgdGhpcyBkb2Vzbid0XG4gICAqIG5lY2Vzc2FyaWx5IG1lYW4gaXQgd29uJ3QgZW5kIHVwIGluIHRoZSBjYWNoZSwgb25seSB0aGF0IGl0cyBjb250ZW50cyBhcmVcbiAgICogc2F2ZWQgdmVyYmF0aW0gaW5zdGVhZCBvZiB0cnlpbmcgdG8gZmluZCBhbiBhcHByb3ByaWF0ZSBjb21waWxlci5cbiAgICpcbiAgICogQHBhcmFtICB7T2JqZWN0fSBoYXNoSW5mbyAgVGhlIGhhc2ggaW5mb3JtYXRpb24gcmV0dXJuZWQgZnJvbSBnZXRIYXNoRm9yUGF0aFxuICAgKlxuICAgKiBAcmV0dXJuIHtib29sZWFufSAgVHJ1ZSBpZiBhIGZpbGUgc2hvdWxkIGJlIGlnbm9yZWRcbiAgICovXG4gIHN0YXRpYyBzaG91bGRQYXNzdGhyb3VnaChoYXNoSW5mbykge1xuICAgIHJldHVybiBoYXNoSW5mby5pc01pbmlmaWVkIHx8IGhhc2hJbmZvLmlzSW5Ob2RlTW9kdWxlcyB8fCBoYXNoSW5mby5oYXNTb3VyY2VNYXAgfHwgaGFzaEluZm8uaXNGaWxlQmluYXJ5O1xuICB9XG59XG4iXX0=