UNPKG

electron-compile

Version:

Electron supporting package to compile JS and CSS in Electron applications

589 lines (473 loc) 44.4 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.createCompilerHostFromProjectRoot = exports.createCompilerHostFromConfigFile = exports.createCompilerHostFromBabelRc = undefined; var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); var _getIterator2 = require('babel-runtime/core-js/get-iterator'); var _getIterator3 = _interopRequireDefault(_getIterator2); var _regenerator = require('babel-runtime/regenerator'); var _regenerator2 = _interopRequireDefault(_regenerator); var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); var _keys = require('babel-runtime/core-js/object/keys'); var _keys2 = _interopRequireDefault(_keys); var _stringify = require('babel-runtime/core-js/json/stringify'); var _stringify2 = _interopRequireDefault(_stringify); /** * Creates a compiler host from a .babelrc file. This method is usually called * from {@link createCompilerHostFromProjectRoot} instead of used directly. * * @param {string} file The path to a .babelrc file * * @param {string} rootCacheDir (optional) The directory to use as a cache. * * @return {Promise<CompilerHost>} A set-up compiler host */ var createCompilerHostFromBabelRc = exports.createCompilerHostFromBabelRc = function () { var ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee(file) { var rootCacheDir = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1]; var info, ourEnv; return _regenerator2.default.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _context.t0 = JSON; _context.next = 3; return _promise.pfs.readFile(file, 'utf8'); case 3: _context.t1 = _context.sent; info = _context.t0.parse.call(_context.t0, _context.t1); // package.json if ('babel' in info) { info = info.babel; } if ('env' in info) { ourEnv = process.env.BABEL_ENV || process.env.NODE_ENV || 'development'; info = info.env[ourEnv]; } // Are we still package.json (i.e. is there no babel info whatsoever?) if (!('name' in info && 'version' in info)) { _context.next = 9; break; } return _context.abrupt('return', createCompilerHostFromConfiguration({ appRoot: _path2.default.dirname(file), options: getDefaultConfiguration(), rootCacheDir: rootCacheDir })); case 9: return _context.abrupt('return', createCompilerHostFromConfiguration({ appRoot: _path2.default.dirname(file), options: { 'application/javascript': info }, rootCacheDir: rootCacheDir })); case 10: case 'end': return _context.stop(); } } }, _callee, this); })); return function createCompilerHostFromBabelRc(_x3) { return ref.apply(this, arguments); }; }(); /** * Creates a compiler host from a .compilerc file. This method is usually called * from {@link createCompilerHostFromProjectRoot} instead of used directly. * * @param {string} file The path to a .compilerc file * * @param {string} rootCacheDir (optional) The directory to use as a cache. * * @return {Promise<CompilerHost>} A set-up compiler host */ var createCompilerHostFromConfigFile = exports.createCompilerHostFromConfigFile = function () { var ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee2(file) { var rootCacheDir = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1]; var info, _ourEnv; return _regenerator2.default.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: _context2.t0 = JSON; _context2.next = 3; return _promise.pfs.readFile(file, 'utf8'); case 3: _context2.t1 = _context2.sent; info = _context2.t0.parse.call(_context2.t0, _context2.t1); if ('env' in info) { _ourEnv = process.env.ELECTRON_COMPILE_ENV || process.env.NODE_ENV || 'development'; info = info.env[_ourEnv]; } return _context2.abrupt('return', createCompilerHostFromConfiguration({ appRoot: _path2.default.dirname(file), options: info, rootCacheDir: rootCacheDir })); case 7: case 'end': return _context2.stop(); } } }, _callee2, this); })); return function createCompilerHostFromConfigFile(_x5) { return ref.apply(this, arguments); }; }(); /** * Creates a configured {@link CompilerHost} instance from the project root * directory. This method first searches for a .compilerc, then falls back to the * default locations for Babel configuration info. If neither are found, defaults * to standard settings * * @param {string} rootDir The root application directory (i.e. the directory * that has the app's package.json) * * @param {string} rootCacheDir (optional) The directory to use as a cache. * * @return {Promise<CompilerHost>} A set-up compiler host */ var createCompilerHostFromProjectRoot = exports.createCompilerHostFromProjectRoot = function () { var ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee3(rootDir) { var rootCacheDir = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1]; var compilerc, babelrc; return _regenerator2.default.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: compilerc = _path2.default.join(rootDir, '.compilerc'); if (!statSyncNoException(compilerc)) { _context3.next = 6; break; } d('Found a .compilerc at ' + compilerc + ', using it'); _context3.next = 5; return createCompilerHostFromConfigFile(compilerc, rootCacheDir); case 5: return _context3.abrupt('return', _context3.sent); case 6: babelrc = _path2.default.join(rootDir, '.babelrc'); if (!statSyncNoException(babelrc)) { _context3.next = 12; break; } d('Found a .babelrc at ' + babelrc + ', using it'); _context3.next = 11; return createCompilerHostFromBabelRc(babelrc, rootCacheDir); case 11: return _context3.abrupt('return', _context3.sent); case 12: d('Using package.json or default parameters at ' + rootDir); _context3.next = 15; return createCompilerHostFromBabelRc(_path2.default.join(rootDir, 'package.json'), rootCacheDir); case 15: return _context3.abrupt('return', _context3.sent); case 16: case 'end': return _context3.stop(); } } }, _callee3, this); })); return function createCompilerHostFromProjectRoot(_x7) { return ref.apply(this, arguments); }; }(); exports.initializeGlobalHooks = initializeGlobalHooks; exports.init = init; exports.createCompilerHostFromConfiguration = createCompilerHostFromConfiguration; exports.createCompilerHostFromBabelRcSync = createCompilerHostFromBabelRcSync; exports.createCompilerHostFromConfigFileSync = createCompilerHostFromConfigFileSync; exports.createCompilerHostFromProjectRootSync = createCompilerHostFromProjectRootSync; exports.calculateDefaultCompileCacheDirectory = calculateDefaultCompileCacheDirectory; exports.getDefaultConfiguration = getDefaultConfiguration; exports.createCompilers = createCompilers; var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs); var _path = require('path'); var _path2 = _interopRequireDefault(_path); var _mkdirp = require('mkdirp'); var _mkdirp2 = _interopRequireDefault(_mkdirp); var _promise = require('./promise'); var _fileChangeCache = require('./file-change-cache'); var _fileChangeCache2 = _interopRequireDefault(_fileChangeCache); var _compilerHost = require('./compiler-host'); var _compilerHost2 = _interopRequireDefault(_compilerHost); var _protocolHook = require('./protocol-hook'); var _requireHook = require('./require-hook'); var _requireHook2 = _interopRequireDefault(_requireHook); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var d = require('debug')('electron-compile:config-parser'); // NB: We intentionally delay-load this so that in production, you can create // cache-only versions of these compilers var allCompilerClasses = null; function statSyncNoException(fsPath) { if ('statSyncNoException' in _fs2.default) { return _fs2.default.statSyncNoException(fsPath); } try { return _fs2.default.statSync(fsPath); } catch (e) { return null; } } /** * Initialize the global hooks (protocol hook for file:, node.js hook) * independent of initializing the compiler. This method is usually called by * init instead of directly * * @param {CompilerHost} compilerHost The compiler host to use. * */ function initializeGlobalHooks(compilerHost) { var globalVar = global || window; globalVar.globalCompilerHost = compilerHost; (0, _requireHook2.default)(compilerHost); if ('type' in process && process.type === 'browser') { var _require = require('electron'); var app = _require.app; var protoify = function protoify() { (0, _protocolHook.initializeProtocolHook)(compilerHost); }; if (app.isReady()) { protoify(); } else { app.on('ready', protoify); } } } /** * Initialize electron-compile and set it up, either for development or * production use. This is almost always the only method you need to use in order * to use electron-compile. * * @param {string} appRoot The top-level directory for your application (i.e. * the one which has your package.json). * * @param {string} mainModule The module to require in, relative to the module * calling init, that will start your app. Write this * as if you were writing a require call from here. * * @param {bool} productionMode If explicitly True/False, will set read-only * mode to be disabled/enabled. If not, we'll * guess based on the presence of a production * cache. */ function init(appRoot, mainModule) { var productionMode = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2]; var compilerHost = null; var cacheDir = _path2.default.join(appRoot, '.cache'); if (productionMode === null) { productionMode = !!statSyncNoException(cacheDir); } if (productionMode) { // In read-only mode, we'll assume that everything is in `appRoot/.cache` compilerHost = _compilerHost2.default.createReadonlyFromConfigurationSync(cacheDir, appRoot); } else { compilerHost = createCompilerHostFromProjectRootSync(appRoot); } initializeGlobalHooks(compilerHost); require.main.require(mainModule); } /** * Creates a {@link CompilerHost} with the given information. This method is * usually called by {@link createCompilerHostFromProjectRoot}. * * @private */ function createCompilerHostFromConfiguration(info) { var compilers = createCompilers(); var rootCacheDir = info.rootCacheDir || calculateDefaultCompileCacheDirectory(); d('Creating CompilerHost: ' + (0, _stringify2.default)(info) + ', rootCacheDir = ' + rootCacheDir); var fileChangeCache = new _fileChangeCache2.default(info.appRoot); var ret = new _compilerHost2.default(rootCacheDir, compilers, fileChangeCache, false, compilers['text/plain']); _lodash2.default.each((0, _keys2.default)(info.options || {}), function (x) { var opts = info.options[x]; if (!(x in compilers)) { throw new Error('Found compiler settings for missing compiler: ' + x); } d('Setting options for ' + x + ': ' + (0, _stringify2.default)(opts)); compilers[x].compilerOptions = opts; }); // NB: It's super important that we guarantee that the configuration is saved // out, because we'll need to re-read it in the renderer process d('Created compiler host with options: ' + (0, _stringify2.default)(info)); ret.saveConfigurationSync(); return ret; }function createCompilerHostFromBabelRcSync(file) { var rootCacheDir = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1]; var info = JSON.parse(_fs2.default.readFileSync(file, 'utf8')); // package.json if ('babel' in info) { info = info.babel; } if ('env' in info) { var _ourEnv2 = process.env.BABEL_ENV || process.env.NODE_ENV || 'development'; info = info.env[_ourEnv2]; } // Are we still package.json (i.e. is there no babel info whatsoever?) if ('name' in info && 'version' in info) { return createCompilerHostFromConfiguration({ appRoot: _path2.default.dirname(file), options: getDefaultConfiguration(), rootCacheDir: rootCacheDir }); } return createCompilerHostFromConfiguration({ appRoot: _path2.default.dirname(file), options: { 'application/javascript': info }, rootCacheDir: rootCacheDir }); } function createCompilerHostFromConfigFileSync(file) { var rootCacheDir = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1]; var info = JSON.parse(_fs2.default.readFileSync(file, 'utf8')); if ('env' in info) { var _ourEnv3 = process.env.ELECTRON_COMPILE_ENV || process.env.NODE_ENV || 'development'; info = info.env[_ourEnv3]; } return createCompilerHostFromConfiguration({ appRoot: _path2.default.dirname(file), options: info, rootCacheDir: rootCacheDir }); } function createCompilerHostFromProjectRootSync(rootDir) { var rootCacheDir = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1]; var compilerc = _path2.default.join(rootDir, '.compilerc'); if (statSyncNoException(compilerc)) { d('Found a .compilerc at ' + compilerc + ', using it'); return createCompilerHostFromConfigFileSync(compilerc, rootCacheDir); } var babelrc = _path2.default.join(rootDir, '.babelrc'); if (statSyncNoException(babelrc)) { d('Found a .babelrc at ' + babelrc + ', using it'); return createCompilerHostFromBabelRcSync(babelrc, rootCacheDir); } d('Using package.json or default parameters at ' + rootDir); return createCompilerHostFromBabelRcSync(_path2.default.join(rootDir, 'package.json'), rootCacheDir); } /** * Returns what electron-compile would use as a default rootCacheDir. Usually only * used for debugging purposes * * @return {string} A path that may or may not exist where electron-compile would * set up a development mode cache. */ function calculateDefaultCompileCacheDirectory() { var tmpDir = process.env.TEMP || process.env.TMPDIR || '/tmp'; var hash = require('crypto').createHash('md5').update(process.execPath).digest('hex'); var cacheDir = _path2.default.join(tmpDir, 'compileCache_' + hash); _mkdirp2.default.sync(cacheDir); d('Using default cache directory: ' + cacheDir); return cacheDir; } /** * Returns the default .configrc if no configuration information can be found. * * @return {Object} A list of default config settings for electron-compiler. */ function getDefaultConfiguration() { return { 'application/javascript': { "presets": ["stage-0", "es2015", "react"], "sourceMaps": "inline" } }; } /** * Allows you to create new instances of all compilers that are supported by * electron-compile and use them directly. Currently supports Babel, CoffeeScript, * TypeScript, LESS, and Jade. * * @return {Object} An Object whose Keys are MIME types, and whose values * are instances of @{link CompilerBase}. */ function createCompilers() { if (!allCompilerClasses) { // First we want to see if electron-compilers itself has been installed with // devDependencies. If that's not the case, check to see if // electron-compilers is installed as a peer dependency (probably as a // devDependency of the root project). var locations = ['electron-compilers', '../../electron-compilers']; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = (0, _getIterator3.default)(locations), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var location = _step.value; try { allCompilerClasses = require(location); } catch (e) { // Yolo } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } if (!allCompilerClasses) { throw new Error("Electron compilers not found but were requested to be loaded"); } } // NB: Note that this code is carefully set up so that InlineHtmlCompiler // (i.e. classes with `createFromCompilers`) initially get an empty object, // but will have a reference to the final result of what we return, which // resolves the circular dependency we'd otherwise have here. var ret = {}; var instantiatedClasses = _lodash2.default.map(allCompilerClasses, function (Klass) { if ('createFromCompilers' in Klass) { return Klass.createFromCompilers(ret); } else { return new Klass(); } }); _lodash2.default.reduce(instantiatedClasses, function (acc, x) { var Klass = (0, _getPrototypeOf2.default)(x).constructor; var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = (0, _getIterator3.default)(Klass.getInputMimeTypes()), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var type = _step2.value; acc[type] = x; } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } return acc; }, ret); return ret; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9jb25maWctcGFyc2VyLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7dUVBdUlPLGlCQUE2QyxJQUE3QztRQUFtRCxxRUFBYTtRQUNqRSxNQVFFOzs7OzswQkFSSzs7bUJBQWlCLGFBQUksUUFBSixDQUFhLElBQWIsRUFBbUIsTUFBbkI7Ozs7QUFBeEIsK0JBQVk7Ozs7QUFHaEIsZ0JBQUksV0FBVyxJQUFYLEVBQWlCO0FBQ25CLHFCQUFPLEtBQUssS0FBTCxDQURZO2FBQXJCOztBQUlBLGdCQUFJLFNBQVMsSUFBVCxFQUFlO0FBQ2IsdUJBQVMsUUFBUSxHQUFSLENBQVksU0FBWixJQUF5QixRQUFRLEdBQVIsQ0FBWSxRQUFaLElBQXdCLGFBQWpELENBREk7O0FBRWpCLHFCQUFPLEtBQUssR0FBTCxDQUFTLE1BQVQsQ0FBUCxDQUZpQjthQUFuQjs7OztrQkFNSSxVQUFVLElBQVYsSUFBa0IsYUFBYSxJQUFiOzs7Ozs2Q0FDYixvQ0FBb0M7QUFDekMsdUJBQVMsZUFBSyxPQUFMLENBQWEsSUFBYixDQUFUO0FBQ0EsdUJBQVMseUJBQVQ7QUFDQSx3Q0FIeUM7YUFBcEM7Ozs2Q0FPRixvQ0FBb0M7QUFDekMsdUJBQVMsZUFBSyxPQUFMLENBQWEsSUFBYixDQUFUO0FBQ0EsdUJBQVM7QUFDUCwwQ0FBMEIsSUFBMUI7ZUFERjtBQUdBLHdDQUx5QzthQUFwQzs7Ozs7Ozs7R0F0QkY7a0JBQWU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozt1RUEwQ2Ysa0JBQWdELElBQWhEO1FBQXNELHFFQUFhOztRQUNwRSxNQUdFOzs7Ozs7MkJBSEs7O21CQUFpQixhQUFJLFFBQUosQ0FBYSxJQUFiLEVBQW1CLE1BQW5COzs7O0FBQXhCLGdDQUFZOzs7QUFFaEIsZ0JBQUksU0FBUyxJQUFULEVBQWU7QUFDYix3QkFBUyxRQUFRLEdBQVIsQ0FBWSxvQkFBWixJQUFvQyxRQUFRLEdBQVIsQ0FBWSxRQUFa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UCxDQUp1QztHQUFYLEVBSzNCLEdBTEgsRUFsQ2dDOztBQXlDaEMsU0FBTyxHQUFQLENBekNnQztDQUEzQiIsImZpbGUiOiJjb25maWctcGFyc2VyLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCBmcyBmcm9tICdmcyc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCBta2RpcnAgZnJvbSAnbWtkaXJwJztcbmltcG9ydCB7cGZzfSBmcm9tICcuL3Byb21pc2UnO1xuXG5pbXBvcnQgRmlsZUNoYW5nZWRDYWNoZSBmcm9tICcuL2ZpbGUtY2hhbmdlLWNhY2hlJztcbmltcG9ydCBDb21waWxlckhvc3QgZnJvbSAnLi9jb21waWxlci1ob3N0JztcbmltcG9ydCB7IGluaXRpYWxpemVQcm90b2NvbEhvb2sgfSBmcm9tICcuL3Byb3RvY29sLWhvb2snO1xuaW1wb3J0IHJlZ2lzdGVyUmVxdWlyZUV4dGVuc2lvbiBmcm9tICcuL3JlcXVpcmUtaG9vayc7XG5cbmNvbnN0IGQgPSByZXF1aXJlKCdkZWJ1ZycpKCdlbGVjdHJvbi1jb21waWxlOmNvbmZpZy1wYXJzZXInKTtcblxuLy8gTkI6IFdlIGludGVudGlvbmFsbHkgZGVsYXktbG9hZCB0aGlzIHNvIHRoYXQgaW4gcHJvZHVjdGlvbiwgeW91IGNhbiBjcmVhdGVcbi8vIGNhY2hlLW9ubHkgdmVyc2lvbnMgb2YgdGhlc2UgY29tcGlsZXJzXG5sZXQgYWxsQ29tcGlsZXJDbGFzc2VzID0gbnVsbDtcblxuZnVuY3Rpb24gc3RhdFN5bmNOb0V4Y2VwdGlvbihmc1BhdGgpIHtcbiAgaWYgKCdzdGF0U3luY05vRXhjZXB0aW9uJyBpbiBmcykge1xuICAgIHJldHVybiBmcy5zdGF0U3luY05vRXhjZXB0aW9uKGZzUGF0aCk7XG4gIH1cbiAgXG4gIHRyeSB7XG4gICAgcmV0dXJuIGZzLnN0YXRTeW5jKGZzUGF0aCk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxufVxuXG5cbi8qKlxuICogSW5pdGlhbGl6ZSB0aGUgZ2xvYmFsIGhvb2tzIChwcm90b2NvbCBob29rIGZvciBmaWxlOiwgbm9kZS5qcyBob29rKSBcbiAqIGluZGVwZW5kZW50IG9mIGluaXRpYWxpemluZyB0aGUgY29tcGlsZXIuIFRoaXMgbWV0aG9kIGlzIHVzdWFsbHkgY2FsbGVkIGJ5XG4gKiBpbml0IGluc3RlYWQgb2YgZGlyZWN0bHlcbiAqIFxuICogQHBhcmFtIHtDb21waWxlckhvc3R9IGNvbXBpbGVySG9zdCAgVGhlIGNvbXBpbGVyIGhvc3QgdG8gdXNlLlxuICogIFxuICovIFxuZXhwb3J0IGZ1bmN0aW9uIGluaXRpYWxpemVHbG9iYWxIb29rcyhjb21waWxlckhvc3QpIHtcbiAgbGV0IGdsb2JhbFZhciA9IChnbG9iYWwgfHwgd2luZG93KTtcbiAgZ2xvYmFsVmFyLmdsb2JhbENvbXBpbGVySG9zdCA9IGNvbXBpbGVySG9zdDtcblxuICByZWdpc3RlclJlcXVpcmVFeHRlbnNpb24oY29tcGlsZXJIb3N0KTtcblxuICBpZiAoJ3R5cGUnIGluIHByb2Nlc3MgJiYgcHJvY2Vzcy50eXBlID09PSAnYnJvd3NlcicpIHtcbiAgICBjb25zdCB7IGFwcCB9ID0gcmVxdWlyZSgnZWxlY3Ryb24nKTtcbiAgICBcbiAgICBsZXQgcHJvdG9pZnkgPSBmdW5jdGlvbigpIHsgaW5pdGlhbGl6ZVByb3RvY29sSG9vayhjb21waWxlckhvc3QpOyB9O1xuICAgIGlmIChhcHAuaXNSZWFkeSgpKSB7XG4gICAgICBwcm90b2lmeSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICBhcHAub24oJ3JlYWR5JywgcHJvdG9pZnkpO1xuICAgIH1cbiAgfVxufVxuXG5cbi8qKlxuICogSW5pdGlhbGl6ZSBlbGVjdHJvbi1jb21waWxlIGFuZCBzZXQgaXQgdXAsIGVpdGhlciBmb3IgZGV2ZWxvcG1lbnQgb3IgXG4gKiBwcm9kdWN0aW9uIHVzZS4gVGhpcyBpcyBhbG1vc3QgYWx3YXlzIHRoZSBvbmx5IG1ldGhvZCB5b3UgbmVlZCB0byB1c2UgaW4gb3JkZXJcbiAqIHRvIHVzZSBlbGVjdHJvbi1jb21waWxlLlxuICogIFxuICogQHBhcmFtICB7c3RyaW5nfSBhcHBSb290ICBUaGUgdG9wLWxldmVsIGRpcmVjdG9yeSBmb3IgeW91ciBhcHBsaWNhdGlvbiAoaS5lLlxuICogICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgb25lIHdoaWNoIGhhcyB5b3VyIHBhY2thZ2UuanNvbikuXG4gKlxuICogQHBhcmFtICB7c3RyaW5nfSBtYWluTW9kdWxlICBUaGUgbW9kdWxlIHRvIHJlcXVpcmUgaW4sIHJlbGF0aXZlIHRvIHRoZSBtb2R1bGVcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FsbGluZyBpbml0LCB0aGF0IHdpbGwgc3RhcnQgeW91ciBhcHAuIFdyaXRlIHRoaXMgXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzIGlmIHlvdSB3ZXJlIHdyaXRpbmcgYSByZXF1aXJlIGNhbGwgZnJvbSBoZXJlLlxuICpcbiAqIEBwYXJhbSAge2Jvb2x9IHByb2R1Y3Rpb25Nb2RlICAgSWYgZXhwbGljaXRseSBUcnVlL0ZhbHNlLCB3aWxsIHNldCByZWFkLW9ubHlcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZSB0byBiZSBkaXNhYmxlZC9lbmFibGVkLiBJZiBub3QsIHdlJ2xsXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGd1ZXNzIGJhc2VkIG9uIHRoZSBwcmVzZW5jZSBvZiBhIHByb2R1Y3Rpb25cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FjaGUuXG4gKi8gXG5leHBvcnQgZnVuY3Rpb24gaW5pdChhcHBSb290LCBtYWluTW9kdWxlLCBwcm9kdWN0aW9uTW9kZSA9IG51bGwpIHtcbiAgbGV0IGNvbXBpbGVySG9zdCA9IG51bGw7XG4gIGxldCBjYWNoZURpciA9IHBhdGguam9pbihhcHBSb290LCAnLmNhY2hlJyk7XG4gIFxuICBpZiAocHJvZHVjdGlvbk1vZGUgPT09IG51bGwpIHtcbiAgICBwcm9kdWN0aW9uTW9kZSA9ICEhc3RhdFN5bmNOb0V4Y2VwdGlvbihjYWNoZURpcik7XG4gIH1cbiAgXG4gIGlmIChwcm9kdWN0aW9uTW9kZSkge1xuICAgIC8vIEluIHJlYWQtb25seSBtb2RlLCB3ZSdsbCBhc3N1bWUgdGhhdCBldmVyeXRoaW5nIGlzIGluIGBhcHBSb290Ly5jYWNoZWBcbiAgICBjb21waWxlckhvc3QgPSBDb21waWxlckhvc3QuY3JlYXRlUmVhZG9ubHlGcm9tQ29uZmlndXJhdGlvblN5bmMoY2FjaGVEaXIsIGFwcFJvb3QpO1xuICB9IGVsc2Uge1xuICAgIGNvbXBpbGVySG9zdCA9IGNyZWF0ZUNvbXBpbGVySG9zdEZyb21Qcm9qZWN0Um9vdFN5bmMoYXBwUm9vdCk7XG4gIH1cbiAgXG4gIGluaXRpYWxpemVHbG9iYWxIb29rcyhjb21waWxlckhvc3QpO1xuICByZXF1aXJlLm1haW4ucmVxdWlyZShtYWluTW9kdWxlKTtcbn1cblxuXG4vKipcbiAqIENyZWF0ZXMgYSB7QGxpbmsgQ29tcGlsZXJIb3N0fSB3aXRoIHRoZSBnaXZlbiBpbmZvcm1hdGlvbi4gVGhpcyBtZXRob2QgaXNcbiAqIHVzdWFsbHkgY2FsbGVkIGJ5IHtAbGluayBjcmVhdGVDb21waWxlckhvc3RGcm9tUHJvamVjdFJvb3R9LlxuICogIFxuICogQHByaXZhdGVcbiAqLyBcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVDb21waWxlckhvc3RGcm9tQ29uZmlndXJhdGlvbihpbmZvKSB7XG4gIGxldCBjb21waWxlcnMgPSBjcmVhdGVDb21waWxlcnMoKTtcbiAgbGV0IHJvb3RDYWNoZURpciA9IGluZm8ucm9vdENhY2hlRGlyIHx8IGNhbGN1bGF0ZURlZmF1bHRDb21waWxlQ2FjaGVEaXJlY3RvcnkoKTtcbiAgXG4gIGQoYENyZWF0aW5nIENvbXBpbGVySG9zdDogJHtKU09OLnN0cmluZ2lmeShpbmZvKX0sIHJvb3RDYWNoZURpciA9ICR7cm9vdENhY2hlRGlyfWApO1xuICBsZXQgZmlsZUNoYW5nZUNhY2hlID0gbmV3IEZpbGVDaGFuZ2VkQ2FjaGUoaW5mby5hcHBSb290KTtcbiAgbGV0IHJldCA9IG5ldyBDb21waWxlckhvc3Qocm9vdENhY2hlRGlyLCBjb21waWxlcnMsIGZpbGVDaGFuZ2VDYWNoZSwgZmFsc2UsIGNvbXBpbGVyc1sndGV4dC9wbGFpbiddKTtcbiAgXG4gIF8uZWFjaChPYmplY3Qua2V5cyhpbmZvLm9wdGlvbnMgfHwge30pLCAoeCkgPT4ge1xuICAgIGxldCBvcHRzID0gaW5mby5vcHRpb25zW3hdO1xuICAgIGlmICghKHggaW4gY29tcGlsZXJzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGb3VuZCBjb21waWxlciBzZXR0aW5ncyBmb3IgbWlzc2luZyBjb21waWxlcjogJHt4fWApO1xuICAgIH1cbiAgICBcbiAgICBkKGBTZXR0aW5nIG9wdGlvbnMgZm9yICR7eH06ICR7SlNPTi5zdHJpbmdpZnkob3B0cyl9YCk7XG4gICAgY29tcGlsZXJzW3hdLmNvbXBpbGVyT3B0aW9ucyA9IG9wdHM7XG4gIH0pO1xuICBcbiAgLy8gTkI6IEl0J3Mgc3VwZXIgaW1wb3J0YW50IHRoYXQgd2UgZ3VhcmFudGVlIHRoYXQgdGhlIGNvbmZpZ3VyYXRpb24gaXMgc2F2ZWRcbiAgLy8gb3V0LCBiZWNhdXNlIHdlJ2xsIG5lZWQgdG8gcmUtcmVhZCBpdCBpbiB0aGUgcmVuZGVyZXIgcHJvY2Vzc1xuICBkKGBDcmVhdGVkIGNvbXBpbGVyIGhvc3Qgd2l0aCBvcHRpb25zOiAke0pTT04uc3RyaW5naWZ5KGluZm8pfWApO1xuICByZXQuc2F2ZUNvbmZpZ3VyYXRpb25TeW5jKCk7XG4gIHJldHVybiByZXQ7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIGNvbXBpbGVyIGhvc3QgZnJvbSBhIC5iYWJlbHJjIGZpbGUuIFRoaXMgbWV0aG9kIGlzIHVzdWFsbHkgY2FsbGVkXG4gKiBmcm9tIHtAbGluayBjcmVhdGVDb21waWxlckhvc3RGcm9tUHJvamVjdFJvb3R9IGluc3RlYWQgb2YgdXNlZCBkaXJlY3RseS5cbiAqICBcbiAqIEBwYXJhbSAge3N0cmluZ30gZmlsZSAgVGhlIHBhdGggdG8gYSAuYmFiZWxyYyBmaWxlXG4gKlxuICogQHBhcmFtICB7c3RyaW5nfSByb290Q2FjaGVEaXIgKG9wdGlvbmFsKSAgVGhlIGRpcmVjdG9yeSB0byB1c2UgYXMgYSBjYWNoZS5cbiAqXG4gKiBAcmV0dXJuIHtQcm9taXNlPENvbXBpbGVySG9zdD59ICBBIHNldC11cCBjb21waWxlciBob3N0XG4gKi8gXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlQ29tcGlsZXJIb3N0RnJvbUJhYmVsUmMoZmlsZSwgcm9vdENhY2hlRGlyPW51bGwpIHtcbiAgbGV0IGluZm8gPSBKU09OLnBhcnNlKGF3YWl0IHBmcy5yZWFkRmlsZShmaWxlLCAndXRmOCcpKTtcbiAgXG4gIC8vIHBhY2thZ2UuanNvblxuICBpZiAoJ2JhYmVsJyBpbiBpbmZvKSB7XG4gICAgaW5mbyA9IGluZm8uYmFiZWw7XG4gIH1cbiAgXG4gIGlmICgnZW52JyBpbiBpbmZvKSB7XG4gICAgbGV0IG91ckVudiA9IHByb2Nlc3MuZW52LkJBQkVMX0VOViB8fCBwcm9jZXNzLmVudi5OT0RFX0VOViB8fCAnZGV2ZWxvcG1lbnQnO1xuICAgIGluZm8gPSBpbmZvLmVudltvdXJFbnZdO1xuICB9XG4gIFxuICAvLyBBcmUgd2Ugc3RpbGwgcGFja2FnZS5qc29uIChpLmUuIGlzIHRoZXJlIG5vIGJhYmVsIGluZm8gd2hhdHNvZXZlcj8pXG4gIGlmICgnbmFtZScgaW4gaW5mbyAmJiAndmVyc2lvbicgaW4gaW5mbykge1xuICAgIHJldHVybiBjcmVhdGVDb21waWxlckhvc3RGcm9tQ29uZmlndXJhdGlvbih7XG4gICAgICBhcHBSb290OiBwYXRoLmRpcm5hbWUoZmlsZSksXG4gICAgICBvcHRpb25zOiBnZXREZWZhdWx0Q29uZmlndXJhdGlvbigpLFxuICAgICAgcm9vdENhY2hlRGlyXG4gICAgfSk7XG4gIH1cbiAgXG4gIHJldHVybiBjcmVhdGVDb21waWxlckhvc3RGcm9tQ29uZmlndXJhdGlvbih7XG4gICAgYXBwUm9vdDogcGF0aC5kaXJuYW1lKGZpbGUpLFxuICAgIG9wdGlvbnM6IHtcbiAgICAgICdhcHBsaWNhdGlvbi9qYXZhc2NyaXB0JzogaW5mb1xuICAgIH0sXG4gICAgcm9vdENhY2hlRGlyXG4gIH0pO1xufVxuXG5cbi8qKlxuICogQ3JlYXRlcyBhIGNvbXBpbGVyIGhvc3QgZnJvbSBhIC5jb21waWxlcmMgZmlsZS4gVGhpcyBtZXRob2QgaXMgdXN1YWxseSBjYWxsZWRcbiAqIGZyb20ge0BsaW5rIGNyZWF0ZUNvbXBpbGVySG9zdEZyb21Qcm9qZWN0Um9vdH0gaW5zdGVhZCBvZiB1c2VkIGRpcmVjdGx5LlxuICogIFxuICogQHBhcmFtICB7c3RyaW5nfSBmaWxlICBUaGUgcGF0aCB0byBhIC5jb21waWxlcmMgZmlsZVxuICpcbiAqIEBwYXJhbSAge3N0cmluZ30gcm9vdENhY2hlRGlyIChvcHRpb25hbCkgIFRoZSBkaXJlY3RvcnkgdG8gdXNlIGFzIGEgY2FjaGUuXG4gKlxuICogQHJldHVybiB7UHJvbWlzZTxDb21waWxlckhvc3Q+fSAgQSBzZXQtdXAgY29tcGlsZXIgaG9zdFxuICovIFxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUNvbXBpbGVySG9zdEZyb21Db25maWdGaWxlKGZpbGUsIHJvb3RDYWNoZURpcj1udWxsKSB7XG4gIGxldCBpbmZvID0gSlNPTi5wYXJzZShhd2FpdCBwZnMucmVhZEZpbGUoZmlsZSwgJ3V0ZjgnKSk7XG4gIFxuICBpZiAoJ2VudicgaW4gaW5mbykge1xuICAgIGxldCBvdXJFbnYgPSBwcm9jZXNzLmVudi5FTEVDVFJPTl9DT01QSUxFX0VOViB8fCBwcm9jZXNzLmVudi5OT0RFX0VOViB8fCAnZGV2ZWxvcG1lbnQnO1xuICAgIGluZm8gPSBpbmZvLmVudltvdXJFbnZdO1xuICB9XG4gIFxuICByZXR1cm4gY3JlYXRlQ29tcGlsZXJIb3N0RnJvbUNvbmZpZ3VyYXRpb24oe1xuICAgIGFwcFJvb3Q6IHBhdGguZGlybmFtZShmaWxlKSxcbiAgICBvcHRpb25zOiBpbmZvLFxuICAgIHJvb3RDYWNoZURpclxuICB9KTtcbn1cblxuXG4vKipcbiAqIENyZWF0ZXMgYSBjb25maWd1cmVkIHtAbGluayBDb21waWxlckhvc3R9IGluc3RhbmNlIGZyb20gdGhlIHByb2plY3Qgcm9vdCBcbiAqIGRpcmVjdG9yeS4gVGhpcyBtZXRob2QgZmlyc3Qgc2VhcmNoZXMgZm9yIGEgLmNvbXBpbGVyYywgdGhlbiBmYWxscyBiYWNrIHRvIHRoZVxuICogZGVmYXVsdCBsb2NhdGlvbnMgZm9yIEJhYmVsIGNvbmZpZ3VyYXRpb24gaW5mby4gSWYgbmVpdGhlciBhcmUgZm91bmQsIGRlZmF1bHRzXG4gKiB0byBzdGFuZGFyZCBzZXR0aW5nc1xuICogIFxuICogQHBhcmFtICB7c3RyaW5nfSByb290RGlyICBUaGUgcm9vdCBhcHBsaWNhdGlvbiBkaXJlY3RvcnkgKGkuZS4gdGhlIGRpcmVjdG9yeVxuICogICAgICAgICAgICAgICAgICAgICAgICAgICB0aGF0IGhhcyB0aGUgYXBwJ3MgcGFja2FnZS5qc29uKVxuICpcbiAqIEBwYXJhbSAge3N0cmluZ30gcm9vdENhY2hlRGlyIChvcHRpb25hbCkgIFRoZSBkaXJlY3RvcnkgdG8gdXNlIGFzIGEgY2FjaGUuXG4gKlxuICogQHJldHVybiB7UHJvbWlzZTxDb21waWxlckhvc3Q+fSAgQSBzZXQtdXAgY29tcGlsZXIgaG9zdFxuICovIFxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUNvbXBpbGVySG9zdEZyb21Qcm9qZWN0Um9vdChyb290RGlyLCByb290Q2FjaGVEaXI9bnVsbCkge1xuICBsZXQgY29tcGlsZXJjID0gcGF0aC5qb2luKHJvb3REaXIsICcuY29tcGlsZXJjJyk7XG4gIGlmIChzdGF0U3luY05vRXhjZXB0aW9uKGNvbXBpbGVyYykpIHtcbiAgICBkKGBGb3VuZCBhIC5jb21waWxlcmMgYXQgJHtjb21waWxlcmN9LCB1c2luZyBpdGApO1xuICAgIHJldHVybiBhd2FpdCBjcmVhdGVDb21waWxlckhvc3RGcm9tQ29uZmlnRmlsZShjb21waWxlcmMsIHJvb3RDYWNoZURpcik7XG4gIH1cbiAgXG4gIGxldCBiYWJlbHJjID0gcGF0aC5qb2luKHJvb3REaXIsICcuYmFiZWxyYycpO1xuICBpZiAoc3RhdFN5bmNOb0V4Y2VwdGlvbihiYWJlbHJjKSkge1xuICAgIGQoYEZvdW5kIGEgLmJhYmVscmMgYXQgJHtiYWJlbHJjfSwgdXNpbmcgaXRgKTtcbiAgICByZXR1cm4gYXdhaXQgY3JlYXRlQ29tcGlsZXJIb3N0RnJvbUJhYmVsUmMoYmFiZWxyYywgcm9vdENhY2hlRGlyKTtcbiAgfVxuICAgIFxuICBkKGBVc2luZyBwYWNrYWdlLmpzb24gb3IgZGVmYXVsdCBwYXJhbWV0ZXJzIGF0ICR7cm9vdERpcn1gKTtcbiAgcmV0dXJuIGF3YWl0IGNyZWF0ZUNvbXBpbGVySG9zdEZyb21CYWJlbFJjKHBhdGguam9pbihyb290RGlyLCAncGFja2FnZS5qc29uJyksIHJvb3RDYWNoZURpcik7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVDb21waWxlckhvc3RGcm9tQmFiZWxSY1N5bmMoZmlsZSwgcm9vdENhY2hlRGlyPW51bGwpIHtcbiAgbGV0IGluZm8gPSBKU09OLnBhcnNlKGZzLnJlYWRGaWxlU3luYyhmaWxlLCAndXRmOCcpKTtcbiAgXG4gIC8vIHBhY2thZ2UuanNvblxuICBpZiAoJ2JhYmVsJyBpbiBpbmZvKSB7XG4gICAgaW5mbyA9IGluZm8uYmFiZWw7XG4gIH1cbiAgXG4gIGlmICgnZW52JyBpbiBpbmZvKSB7XG4gICAgbGV0IG91ckVudiA9IHByb2Nlc3MuZW52LkJBQkVMX0VOViB8fCBwcm9jZXNzLmVudi5OT0RFX0VOViB8fCAnZGV2ZWxvcG1lbnQnO1xuICAgIGluZm8gPSBpbmZvLmVudltvdXJFbnZdO1xuICB9XG4gIFxuICAvLyBBcmUgd2Ugc3RpbGwgcGFja2FnZS5qc29uIChpLmUuIGlzIHRoZXJlIG5vIGJhYmVsIGluZm8gd2hhdHNvZXZlcj8pXG4gIGlmICgnbmFtZScgaW4gaW5mbyAmJiAndmVyc2lvbicgaW4gaW5mbykge1xuICAgIHJldHVybiBjcmVhdGVDb21waWxlckhvc3RGcm9tQ29uZmlndXJhdGlvbih7XG4gICAgICBhcHBSb290OiBwYXRoLmRpcm5hbWUoZmlsZSksXG4gICAgICBvcHRpb25zOiBnZXREZWZhdWx0Q29uZmlndXJhdGlvbigpLFxuICAgICAgcm9vdENhY2hlRGlyXG4gICAgfSk7XG4gIH1cbiAgXG4gIHJldHVybiBjcmVhdGVDb21waWxlckhvc3RGcm9tQ29uZmlndXJhdGlvbih7XG4gICAgYXBwUm9vdDogcGF0aC5kaXJuYW1lKGZpbGUpLFxuICAgIG9wdGlvbnM6IHtcbiAgICAgICdhcHBsaWNhdGlvbi9qYXZhc2NyaXB0JzogaW5mb1xuICAgIH0sXG4gICAgcm9vdENhY2hlRGlyXG4gIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlQ29tcGlsZXJIb3N0RnJvbUNvbmZpZ0ZpbGVTeW5jKGZpbGUsIHJvb3RDYWNoZURpcj1udWxsKSB7XG4gIGxldCBpbmZvID0gSlNPTi5wYXJzZShmcy5yZWFkRmlsZVN5bmMoZmlsZSwgJ3V0ZjgnKSk7XG4gIFxuICBpZiAoJ2VudicgaW4gaW5mbykge1xuICAgIGxldCBvdXJFbnYgPSBwcm9jZXNzLmVudi5FTEVDVFJPTl9DT01QSUxFX0VOViB8fCBwcm9jZXNzLmVudi5OT0RFX0VOViB8fCAnZGV2ZWxvcG1lbnQnO1xuICAgIGluZm8gPSBpbmZvLmVudltvdXJFbnZdO1xuICB9XG4gIFxuICByZXR1cm4gY3JlYXRlQ29tcGlsZXJIb3N0RnJvbUNvbmZpZ3VyYXRpb24oe1xuICAgIGFwcFJvb3Q6IHBhdGguZGlybmFtZShmaWxlKSxcbiAgICBvcHRpb25zOiBpbmZvLFxuICAgIHJvb3RDYWNoZURpclxuICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUNvbXBpbGVySG9zdEZyb21Qcm9qZWN0Um9vdFN5bmMocm9vdERpciwgcm9vdENhY2hlRGlyPW51bGwpIHtcbiAgbGV0IGNvbXBpbGVyYyA9IHBhdGguam9pbihyb290RGlyLCAnLmNvbXBpbGVyYycpO1xuICBpZiAoc3RhdFN5bmNOb0V4Y2VwdGlvbihjb21waWxlcmMpKSB7XG4gICAgZChgRm91bmQgYSAuY29tcGlsZXJjIGF0ICR7Y29tcGlsZXJjfSwgdXNpbmcgaXRgKTtcbiAgICByZXR1cm4gY3JlYXRlQ29tcGlsZXJIb3N0RnJvbUNvbmZpZ0ZpbGVTeW5jKGNvbXBpbGVyYywgcm9vdENhY2hlRGlyKTtcbiAgfVxuICBcbiAgbGV0IGJhYmVscmMgPSBwYXRoLmpvaW4ocm9vdERpciwgJy5iYWJlbHJjJyk7XG4gIGlmIChzdGF0U3luY05vRXhjZXB0aW9uKGJhYmVscmMpKSB7XG4gICAgZChgRm91bmQgYSAuYmFiZWxyYyBhdCAke2JhYmVscmN9LCB1c2luZyBpdGApO1xuICAgIHJldHVybiBjcmVhdGVDb21waWxlckhvc3RGcm9tQmFiZWxSY1N5bmMoYmFiZWxyYywgcm9vdENhY2hlRGlyKTtcbiAgfVxuICAgIFxuICBkKGBVc2luZyBwYWNrYWdlLmpzb24gb3IgZGVmYXVsdCBwYXJhbWV0ZXJzIGF0ICR7cm9vdERpcn1gKTtcbiAgcmV0dXJuIGNyZWF0ZUNvbXBpbGVySG9zdEZyb21CYWJlbFJjU3luYyhwYXRoLmpvaW4ocm9vdERpciwgJ3BhY2thZ2UuanNvbicpLCByb290Q2FjaGVEaXIpO1xufVxuXG4vKipcbiAqIFJldHVybnMgd2hhdCBlbGVjdHJvbi1jb21waWxlIHdvdWxkIHVzZSBhcyBhIGRlZmF1bHQgcm9vdENhY2hlRGlyLiBVc3VhbGx5IG9ubHlcbiAqIHVzZWQgZm9yIGRlYnVnZ2luZyBwdXJwb3Nlc1xuICogIFxuICogQHJldHVybiB7c3RyaW5nfSAgQSBwYXRoIHRoYXQgbWF5IG9yIG1heSBub3QgZXhpc3Qgd2hlcmUgZWxlY3Ryb24tY29tcGlsZSB3b3VsZFxuICogICAgICAgICAgICAgICAgICAgc2V0IHVwIGEgZGV2ZWxvcG1lbnQgbW9kZSBjYWNoZS5cbiAqLyBcbmV4cG9ydCBmdW5jdGlvbiBjYWxjdWxhdGVEZWZhdWx0Q29tcGlsZUNhY2hlRGlyZWN0b3J5KCkge1xuICBsZXQgdG1wRGlyID0gcHJvY2Vzcy5lbnYuVEVNUCB8fCBwcm9jZXNzLmVudi5UTVBESVIgfHwgJy90bXAnO1xuICBsZXQgaGFzaCA9IHJlcXVpcmUoJ2NyeXB0bycpLmNyZWF0ZUhhc2goJ21kNScpLnVwZGF0ZShwcm9jZXNzLmV4ZWNQYXRoKS5kaWdlc3QoJ2hleCcpO1xuXG4gIGxldCBjYWNoZURpciA9IHBhdGguam9pbih0bXBEaXIsIGBjb21waWxlQ2FjaGVfJHtoYXNofWApO1xuICBta2RpcnAuc3luYyhjYWNoZURpcik7XG4gIFxuICBkKGBVc2luZyBkZWZhdWx0IGNhY2hlIGRpcmVjdG9yeTogJHtjYWNoZURpcn1gKTtcbiAgcmV0dXJuIGNhY2hlRGlyO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyB0aGUgZGVmYXVsdCAuY29uZmlncmMgaWYgbm8gY29uZmlndXJhdGlvbiBpbmZvcm1hdGlvbiBjYW4gYmUgZm91bmQuXG4gKiAgXG4gKiBAcmV0dXJuIHtPYmplY3R9ICBBIGxpc3Qgb2YgZGVmYXVsdCBjb25maWcgc2V0dGluZ3MgZm9yIGVsZWN0cm9uLWNvbXBpbGVyLlxuICovIFxuZXhwb3J0IGZ1bmN0aW9uIGdldERlZmF1bHRDb25maWd1cmF0aW9uKCkge1xuICByZXR1cm4ge1xuICAgICdhcHBsaWNhdGlvbi9qYXZhc2NyaXB0Jzoge1xuICAgICAgXCJwcmVzZXRzXCI6IFtcInN0YWdlLTBcIiwgXCJlczIwMTVcIiwgXCJyZWFjdFwiXSxcbiAgICAgIFwic291cmNlTWFwc1wiOiBcImlubGluZVwiXG4gICAgfVxuICB9O1xufVxuXG4vKipcbiAqIEFsbG93cyB5b3UgdG8gY3JlYXRlIG5ldyBpbnN0YW5jZXMgb2YgYWxsIGNvbXBpbGVycyB0aGF0IGFyZSBzdXBwb3J0ZWQgYnkgXG4gKiBlbGVjdHJvbi1jb21waWxlIGFuZCB1c2UgdGhlbSBkaXJlY3RseS4gQ3VycmVudGx5IHN1cHBvcnRzIEJhYmVsLCBDb2ZmZWVTY3JpcHQsIFxuICogVHlwZVNjcmlwdCwgTEVTUywgYW5kIEphZGUuXG4gKiAgXG4gKiBAcmV0dXJuIHtPYmplY3R9ICBBbiBPYmplY3Qgd2hvc2UgS2V5cyBhcmUgTUlNRSB0eXBlcywgYW5kIHdob3NlIHZhbHVlcyBcbiAqIGFyZSBpbnN0YW5jZXMgb2YgQHtsaW5rIENvbXBpbGVyQmFzZX0uXG4gKi8gXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlQ29tcGlsZXJzKCkge1xuICBpZiAoIWFsbENvbXBpbGVyQ2xhc3Nlcykge1xuICAgIC8vIEZpcnN0IHdlIHdhbnQgdG8gc2VlIGlmIGVsZWN0cm9uLWNvbXBpbGVycyBpdHNlbGYgaGFzIGJlZW4gaW5zdGFsbGVkIHdpdGhcbiAgICAvLyBkZXZEZXBlbmRlbmNpZXMuIElmIHRoYXQncyBub3QgdGhlIGNhc2UsIGNoZWNrIHRvIHNlZSBpZlxuICAgIC8vIGVsZWN0cm9uLWNvbXBpbGVycyBpcyBpbnN0YWxsZWQgYXMgYSBwZWVyIGRlcGVuZGVuY3kgKHByb2JhYmx5IGFzIGFcbiAgICAvLyBkZXZEZXBlbmRlbmN5IG9mIHRoZSByb290IHByb2plY3QpLlxuICAgIGNvbnN0IGxvY2F0aW9ucyA9IFsnZWxlY3Ryb24tY29tcGlsZXJzJywgJy4uLy4uL2VsZWN0cm9uLWNvbXBpbGVycyddO1xuXG4gICAgZm9yIChsZXQgbG9jYXRpb24gb2YgbG9jYXRpb25zKSB7XG4gICAgICB0cnkge1xuICAgICAgICBhbGxDb21waWxlckNsYXNzZXMgPSByZXF1aXJlKGxvY2F0aW9uKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgLy8gWW9sb1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICghYWxsQ29tcGlsZXJDbGFzc2VzKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJFbGVjdHJvbiBjb21waWxlcnMgbm90IGZvdW5kIGJ1dCB3ZXJlIHJlcXVlc3RlZCB0byBiZSBsb2FkZWRcIik7XG4gICAgfVxuICB9XG5cbiAgLy8gTkI6IE5vdGUgdGhhdCB0aGlzIGNvZGUgaXMgY2FyZWZ1bGx5IHNldCB1cCBzbyB0aGF0IElubGluZUh0bWxDb21waWxlciBcbiAgLy8gKGkuZS4gY2xhc3NlcyB3aXRoIGBjcmVhdGVGcm9tQ29tcGlsZXJzYCkgaW5pdGlhbGx5IGdldCBhbiBlbXB0eSBvYmplY3QsXG4gIC8vIGJ1dCB3aWxsIGhhdmUgYSByZWZlcmVuY2UgdG8gdGhlIGZpbmFsIHJlc3VsdCBvZiB3aGF0IHdlIHJldHVybiwgd2hpY2hcbiAgLy8gcmVzb2x2ZXMgdGhlIGNpcmN1bGFyIGRlcGVuZGVuY3kgd2UnZCBvdGhlcndpc2UgaGF2ZSBoZXJlLlxuICBsZXQgcmV0ID0ge307XG4gIGxldCBpbnN0YW50aWF0ZWRDbGFzc2VzID0gXy5tYXAoYWxsQ29tcGlsZXJDbGFzc2VzLCAoS2xhc3MpID0+IHtcbiAgICBpZiAoJ2NyZWF0ZUZyb21Db21waWxlcnMnIGluIEtsYXNzKSB7XG4gICAgICByZXR1cm4gS2xhc3MuY3JlYXRlRnJvbUNvbXBpbGVycyhyZXQpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gbmV3IEtsYXNzKCk7XG4gICAgfVxuICB9KTtcblxuICBfLnJlZHVjZShpbnN0YW50aWF0ZWRDbGFzc2VzLCAoYWNjLHgpID0+IHtcbiAgICBsZXQgS2xhc3MgPSBPYmplY3QuZ2V0UHJvdG90eXBlT2YoeCkuY29uc3RydWN0b3I7XG5cbiAgICBmb3IgKGxldCB0eXBlIG9mIEtsYXNzLmdldElucHV0TWltZVR5cGVzKCkpIHsgYWNjW3R5cGVdID0geDsgfVxuICAgIHJldHVybiBhY2M7XG4gIH0sIHJldCk7XG4gIFxuICByZXR1cm4gcmV0O1xufVxuIl19