UNPKG

@sharekey/meteor-desktop

Version:

Build a Meteor's desktop client with hot code push.

282 lines (273 loc) 29.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.computeHashForHashesSet = computeHashForHashesSet; exports.default = void 0; exports.exists = exists; exports.getFileList = getFileList; exports.readAndGetFileHash = readAndGetFileHash; exports.readAndHashFiles = readAndHashFiles; exports.readDir = readDir; exports.readFilesAndComputeHash = readFilesAndComputeHash; exports.rmWithRetries = rmWithRetries; exports.symlinkExists = symlinkExists; var _path = _interopRequireDefault(require("path")); var _fs = _interopRequireDefault(require("fs")); var _crypto = _interopRequireDefault(require("crypto")); var _shelljs = _interopRequireDefault(require("shelljs")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /* eslint-disable consistent-return */ /** * Exists * @param {string} pathToCheck * @returns {boolean} */ function exists(pathToCheck) { try { _fs.default.accessSync(pathToCheck); return true; } catch (e) { return false; } } /** * Simple wrapper for shelljs.rm with additional retries in case of failure. * It is useful when something is concurrently reading the dir you want to remove. */ function rmWithRetries(...args) { let retries = 0; return new Promise((resolve, reject) => { function rm(...rmArgs) { try { _shelljs.default.config.fatal = true; _shelljs.default.rm(...rmArgs); _shelljs.default.config.reset(); resolve(); } catch (e) { retries += 1; if (retries < 5) { setTimeout(() => { rm(...rmArgs); }, 100); } else { _shelljs.default.config.reset(); reject(e); } } } rm(...args); }); } function readDir(dir, callback) { if (!callback) { return new Promise((resolve, reject) => { readDir(dir, (err, data, stats) => { if (err) { reject(err); } else { resolve({ data, stats }); } }); }); } let list = []; let allStats = {}; _fs.default.readdir(dir, (err, files) => { if (err) { return callback(err); } let pending = files.length; if (!pending) { return callback(null, list, allStats); } files.forEach(file => { const filePath = _path.default.join(dir, file); _fs.default.stat(filePath, (_err, stats) => { if (_err) { return callback(_err); } if (stats.isDirectory()) { readDir(filePath, (__err, res, _allStats) => { if (__err) { return callback(__err); } list = list.concat(res); allStats = Object.assign(allStats, _allStats); pending -= 1; if (!pending) { return callback(null, list, allStats); } }); } else { list.push(filePath); allStats[filePath] = { size: stats.size, dates: [stats.birthtime.getTime(), stats.ctime.getTime(), stats.mtime.getTime()] }; pending -= 1; if (!pending) { return callback(null, list, allStats); } } }); }); }); } /** * Returns a file list from a directory. * @param {string} dir - dir path * @param {boolean} sort - whether to apply sort * @returns {Promise<Array>} */ function getFileList(dir, sort = false) { return new Promise((resolve, reject) => { readDir(dir, (error, files) => { if (error) { reject(error); return; } // eslint-disable-next-line no-param-reassign let resultantFilesList; if (sort) { const stripLength = dir.substr(0, 2) === './' ? dir.length - 1 : dir.length + 1; let pathsUnified = files.map(pth => pth.substr(stripLength).replace(/[\\/]/gm, '-')); const temporaryIndex = {}; files.forEach((file, i) => { temporaryIndex[pathsUnified[i]] = file; }); pathsUnified = pathsUnified.sort(); const filesSorted = []; pathsUnified.forEach(key => { filesSorted.push(temporaryIndex[key]); }); resultantFilesList = filesSorted; } else { resultantFilesList = files; } resolve(resultantFilesList); }); }); } /** * Returns file's hash. * @param {string} file - file path * @param {boolean} returnFileContents - include file contents in the resultant object * @returns {Promise<Object>} */ function readAndGetFileHash(file, returnFileContents = false) { return new Promise((resolve, reject) => { _fs.default.readFile(file, (err, data) => { if (err) { reject(err); return; } const hash = _crypto.default.createHash('sha1'); hash.update(data); const returnObject = { hash: hash.digest('hex') }; if (returnFileContents) { returnObject.contents = data.toString('utf8'); } resolve(returnObject); }); }); } /** * Calculates a hash from objects values in specified order. * @param {Array} orderOfKeys * @param {Object} hashSet * @param {Function} keyFilter * @returns {string} */ function computeHashForHashesSet(orderOfKeys, hashSet, keyFilter = key => key) { const hash = _crypto.default.createHash('sha1'); const hashesJoined = orderOfKeys.reduce( // eslint-disable-next-line no-param-reassign,no-return-assign (tmpHash, key) => (tmpHash += hashSet[keyFilter(key)], tmpHash), ''); hash.update(hashesJoined); return hash.digest('hex'); } /** * Reads files from disk and computes hashes for them. * @param {Array} files - array with file paths * @returns {Promise<Object>} */ function readAndHashFiles(files, fileFilter) { const fileHashes = {}; const fileContents = {}; const promises = []; function readSingleFile(file) { return new Promise((resolve, reject) => { readAndGetFileHash(file, file.endsWith('.js') && !file.endsWith('.test.js')).then(result => { let fileName = file; if (fileFilter) { fileName = fileFilter(fileName); } fileHashes[fileName] = result.hash; if (result.contents) { fileContents[fileName] = result.contents; } resolve(); }).catch(reject); }); } files.forEach(file => { promises.push(readSingleFile(file)); }); return new Promise((resolve, reject) => { Promise.all(promises).then(() => { resolve({ files, fileContents, fileHashes }); }).catch(reject); }); } /** * Reads files from .desktop and computes a version hash. * * @param {string} dir - path * @param {Function} fileFilter * @returns {Promise<Object>} */ function readFilesAndComputeHash(dir, fileFilter) { return new Promise((resolve, reject) => { getFileList(dir, true).catch(reject).then(files => readAndHashFiles(files, fileFilter)).catch(reject).then(result => { // eslint-disable-next-line no-param-reassign result.hash = computeHashForHashesSet(result.files, result.fileHashes, fileFilter); resolve(result); }); }); } /** * Symlink exists * @param {string} pathToCheck * @returns {boolean} */ function symlinkExists(pathToCheck) { try { _fs.default.readlinkSync(pathToCheck); return true; } catch (e) { return false; } } var _default = { getFileList, rmWithRetries, exists, readDir, readAndGetFileHash, computeHashForHashesSet, readAndHashFiles, readFilesAndComputeHash, symlinkExists }; exports.default = _default; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcGF0aCIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX2ZzIiwiX2NyeXB0byIsIl9zaGVsbGpzIiwib2JqIiwiX19lc01vZHVsZSIsImRlZmF1bHQiLCJleGlzdHMiLCJwYXRoVG9DaGVjayIsImZzIiwiYWNjZXNzU3luYyIsImUiLCJybVdpdGhSZXRyaWVzIiwiYXJncyIsInJldHJpZXMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsInJtIiwicm1BcmdzIiwic2hlbGwiLCJjb25maWciLCJmYXRhbCIsInJlc2V0Iiwic2V0VGltZW91dCIsInJlYWREaXIiLCJkaXIiLCJjYWxsYmFjayIsImVyciIsImRhdGEiLCJzdGF0cyIsImxpc3QiLCJhbGxTdGF0cyIsInJlYWRkaXIiLCJmaWxlcyIsInBlbmRpbmciLCJsZW5ndGgiLCJmb3JFYWNoIiwiZmlsZSIsImZpbGVQYXRoIiwicGF0aCIsImpvaW4iLCJzdGF0IiwiX2VyciIsImlzRGlyZWN0b3J5IiwiX19lcnIiLCJyZXMiLCJfYWxsU3RhdHMiLCJjb25jYXQiLCJPYmplY3QiLCJhc3NpZ24iLCJwdXNoIiwic2l6ZSIsImRhdGVzIiwiYmlydGh0aW1lIiwiZ2V0VGltZSIsImN0aW1lIiwibXRpbWUiLCJnZXRGaWxlTGlzdCIsInNvcnQiLCJlcnJvciIsInJlc3VsdGFudEZpbGVzTGlzdCIsInN0cmlwTGVuZ3RoIiwic3Vic3RyIiwicGF0aHNVbmlmaWVkIiwibWFwIiwicHRoIiwicmVwbGFjZSIsInRlbXBvcmFyeUluZGV4IiwiaSIsImZpbGVzU29ydGVkIiwia2V5IiwicmVhZEFuZEdldEZpbGVIYXNoIiwicmV0dXJuRmlsZUNvbnRlbnRzIiwicmVhZEZpbGUiLCJoYXNoIiwiY3J5cHRvIiwiY3JlYXRlSGFzaCIsInVwZGF0ZSIsInJldHVybk9iamVjdCIsImRpZ2VzdCIsImNvbnRlbnRzIiwidG9TdHJpbmciLCJjb21wdXRlSGFzaEZvckhhc2hlc1NldCIsIm9yZGVyT2ZLZXlzIiwiaGFzaFNldCIsImtleUZpbHRlciIsImhhc2hlc0pvaW5lZCIsInJlZHVjZSIsInRtcEhhc2giLCJyZWFkQW5kSGFzaEZpbGVzIiwiZmlsZUZpbHRlciIsImZpbGVIYXNoZXMiLCJmaWxlQ29udGVudHMiLCJwcm9taXNlcyIsInJlYWRTaW5nbGVGaWxlIiwiZW5kc1dpdGgiLCJ0aGVuIiwicmVzdWx0IiwiZmlsZU5hbWUiLCJjYXRjaCIsImFsbCIsInJlYWRGaWxlc0FuZENvbXB1dGVIYXNoIiwic3ltbGlua0V4aXN0cyIsInJlYWRsaW5rU3luYyIsIl9kZWZhdWx0IiwiZXhwb3J0cyJdLCJzb3VyY2VzIjpbIi4uL2xpYi91dGlscy5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBjb25zaXN0ZW50LXJldHVybiAqL1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgZnMgZnJvbSAnZnMnO1xuaW1wb3J0IGNyeXB0byBmcm9tICdjcnlwdG8nO1xuaW1wb3J0IHNoZWxsIGZyb20gJ3NoZWxsanMnO1xuXG4vKipcbiAqIEV4aXN0c1xuICogQHBhcmFtIHtzdHJpbmd9IHBhdGhUb0NoZWNrXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGV4aXN0cyhwYXRoVG9DaGVjaykge1xuICAgIHRyeSB7XG4gICAgICAgIGZzLmFjY2Vzc1N5bmMocGF0aFRvQ2hlY2spO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG59XG5cbi8qKlxuICogU2ltcGxlIHdyYXBwZXIgZm9yIHNoZWxsanMucm0gd2l0aCBhZGRpdGlvbmFsIHJldHJpZXMgaW4gY2FzZSBvZiBmYWlsdXJlLlxuICogSXQgaXMgdXNlZnVsIHdoZW4gc29tZXRoaW5nIGlzIGNvbmN1cnJlbnRseSByZWFkaW5nIHRoZSBkaXIgeW91IHdhbnQgdG8gcmVtb3ZlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcm1XaXRoUmV0cmllcyguLi5hcmdzKSB7XG4gICAgbGV0IHJldHJpZXMgPSAwO1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGZ1bmN0aW9uIHJtKC4uLnJtQXJncykge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBzaGVsbC5jb25maWcuZmF0YWwgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHNoZWxsLnJtKC4uLnJtQXJncyk7XG4gICAgICAgICAgICAgICAgc2hlbGwuY29uZmlnLnJlc2V0KCk7XG4gICAgICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIHJldHJpZXMgKz0gMTtcbiAgICAgICAgICAgICAgICBpZiAocmV0cmllcyA8IDUpIHtcbiAgICAgICAgICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBybSguLi5ybUFyZ3MpO1xuICAgICAgICAgICAgICAgICAgICB9LCAxMDApO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHNoZWxsLmNvbmZpZy5yZXNldCgpO1xuICAgICAgICAgICAgICAgICAgICByZWplY3QoZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJtKC4uLmFyZ3MpO1xuICAgIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVhZERpcihkaXIsIGNhbGxiYWNrKSB7XG4gICAgaWYgKCFjYWxsYmFjaykge1xuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgcmVhZERpcihkaXIsIChlcnIsIGRhdGEsIHN0YXRzKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgICAgICByZWplY3QoZXJyKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKHsgZGF0YSwgc3RhdHMgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBsZXQgbGlzdCA9IFtdO1xuICAgIGxldCBhbGxTdGF0cyA9IHt9O1xuXG4gICAgZnMucmVhZGRpcihkaXIsIChlcnIsIGZpbGVzKSA9PiB7XG4gICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhlcnIpO1xuICAgICAgICB9XG4gICAgICAgIGxldCBwZW5kaW5nID0gZmlsZXMubGVuZ3RoO1xuICAgICAgICBpZiAoIXBlbmRpbmcpIHtcbiAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhudWxsLCBsaXN0LCBhbGxTdGF0cyk7XG4gICAgICAgIH1cbiAgICAgICAgZmlsZXMuZm9yRWFjaCgoZmlsZSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgZmlsZVBhdGggPSBwYXRoLmpvaW4oZGlyLCBmaWxlKTtcbiAgICAgICAgICAgIGZzLnN0YXQoZmlsZVBhdGgsIChfZXJyLCBzdGF0cykgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChfZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhfZXJyKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHN0YXRzLmlzRGlyZWN0b3J5KCkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVhZERpcihmaWxlUGF0aCwgKF9fZXJyLCByZXMsIF9hbGxTdGF0cykgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKF9fZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKF9fZXJyKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QgPSBsaXN0LmNvbmNhdChyZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYWxsU3RhdHMgPSBPYmplY3QuYXNzaWduKGFsbFN0YXRzLCBfYWxsU3RhdHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcGVuZGluZyAtPSAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFwZW5kaW5nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKG51bGwsIGxpc3QsIGFsbFN0YXRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgbGlzdC5wdXNoKGZpbGVQYXRoKTtcbiAgICAgICAgICAgICAgICAgICAgYWxsU3RhdHNbZmlsZVBhdGhdID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZTogc3RhdHMuc2l6ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGVzOiBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHMuYmlydGh0aW1lLmdldFRpbWUoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0cy5jdGltZS5nZXRUaW1lKCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHMubXRpbWUuZ2V0VGltZSgpXG4gICAgICAgICAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIHBlbmRpbmcgLT0gMTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFwZW5kaW5nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gY2FsbGJhY2sobnVsbCwgbGlzdCwgYWxsU3RhdHMpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgIH0pO1xufVxuXG4vKipcbiAqIFJldHVybnMgYSBmaWxlIGxpc3QgZnJvbSBhIGRpcmVjdG9yeS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXIgLSBkaXIgcGF0aFxuICogQHBhcmFtIHtib29sZWFufSBzb3J0IC0gd2hldGhlciB0byBhcHBseSBzb3J0XG4gKiBAcmV0dXJucyB7UHJvbWlzZTxBcnJheT59XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRGaWxlTGlzdChkaXIsIHNvcnQgPSBmYWxzZSkge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHJlYWREaXIoZGlyLCAoZXJyb3IsIGZpbGVzKSA9PiB7XG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1wYXJhbS1yZWFzc2lnblxuICAgICAgICAgICAgbGV0IHJlc3VsdGFudEZpbGVzTGlzdDtcblxuICAgICAgICAgICAgaWYgKHNvcnQpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBzdHJpcExlbmd0aCA9IChkaXIuc3Vic3RyKDAsIDIpID09PSAnLi8nKSA/IGRpci5sZW5ndGggLSAxIDogZGlyLmxlbmd0aCArIDE7XG4gICAgICAgICAgICAgICAgbGV0IHBhdGhzVW5pZmllZCA9IGZpbGVzLm1hcCgocHRoID0+IHB0aC5zdWJzdHIoc3RyaXBMZW5ndGgpLnJlcGxhY2UoL1tcXFxcL10vZ20sICctJykpKTtcbiAgICAgICAgICAgICAgICBjb25zdCB0ZW1wb3JhcnlJbmRleCA9IHt9O1xuICAgICAgICAgICAgICAgIGZpbGVzLmZvckVhY2goKGZpbGUsIGkpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGVtcG9yYXJ5SW5kZXhbcGF0aHNVbmlmaWVkW2ldXSA9IGZpbGU7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcGF0aHNVbmlmaWVkID0gcGF0aHNVbmlmaWVkLnNvcnQoKTtcbiAgICAgICAgICAgICAgICBjb25zdCBmaWxlc1NvcnRlZCA9IFtdO1xuICAgICAgICAgICAgICAgIHBhdGhzVW5pZmllZC5mb3JFYWNoKChrZXkpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgZmlsZXNTb3J0ZWQucHVzaCh0ZW1wb3JhcnlJbmRleFtrZXldKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXN1bHRhbnRGaWxlc0xpc3QgPSBmaWxlc1NvcnRlZDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmVzdWx0YW50RmlsZXNMaXN0ID0gZmlsZXM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXNvbHZlKHJlc3VsdGFudEZpbGVzTGlzdCk7XG4gICAgICAgIH0pO1xuICAgIH0pO1xufVxuXG4vKipcbiAqIFJldHVybnMgZmlsZSdzIGhhc2guXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZSAtIGZpbGUgcGF0aFxuICogQHBhcmFtIHtib29sZWFufSByZXR1cm5GaWxlQ29udGVudHMgLSBpbmNsdWRlIGZpbGUgY29udGVudHMgaW4gdGhlIHJlc3VsdGFudCBvYmplY3RcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWFkQW5kR2V0RmlsZUhhc2goZmlsZSwgcmV0dXJuRmlsZUNvbnRlbnRzID0gZmFsc2UpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBmcy5yZWFkRmlsZShmaWxlLCAoZXJyLCBkYXRhKSA9PiB7XG4gICAgICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgcmVqZWN0KGVycik7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgaGFzaCA9IGNyeXB0by5jcmVhdGVIYXNoKCdzaGExJyk7XG4gICAgICAgICAgICBoYXNoLnVwZGF0ZShkYXRhKTtcbiAgICAgICAgICAgIGNvbnN0IHJldHVybk9iamVjdCA9IHsgaGFzaDogaGFzaC5kaWdlc3QoJ2hleCcpIH07XG4gICAgICAgICAgICBpZiAocmV0dXJuRmlsZUNvbnRlbnRzKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuT2JqZWN0LmNvbnRlbnRzID0gZGF0YS50b1N0cmluZygndXRmOCcpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVzb2x2ZShyZXR1cm5PYmplY3QpO1xuICAgICAgICB9KTtcbiAgICB9KTtcbn1cblxuLyoqXG4gKiBDYWxjdWxhdGVzIGEgaGFzaCBmcm9tIG9iamVjdHMgdmFsdWVzIGluIHNwZWNpZmllZCBvcmRlci5cbiAqIEBwYXJhbSB7QXJyYXl9IG9yZGVyT2ZLZXlzXG4gKiBAcGFyYW0ge09iamVjdH0gaGFzaFNldFxuICogQHBhcmFtIHtGdW5jdGlvbn0ga2V5RmlsdGVyXG4gKiBAcmV0dXJucyB7c3RyaW5nfVxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcHV0ZUhhc2hGb3JIYXNoZXNTZXQob3JkZXJPZktleXMsIGhhc2hTZXQsIGtleUZpbHRlciA9IGtleSA9PiBrZXkpIHtcbiAgICBjb25zdCBoYXNoID0gY3J5cHRvLmNyZWF0ZUhhc2goJ3NoYTEnKTtcbiAgICBjb25zdCBoYXNoZXNKb2luZWQgPSBvcmRlck9mS2V5cy5yZWR1Y2UoXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1wYXJhbS1yZWFzc2lnbixuby1yZXR1cm4tYXNzaWduXG4gICAgICAgICh0bXBIYXNoLCBrZXkpID0+ICh0bXBIYXNoICs9IGhhc2hTZXRba2V5RmlsdGVyKGtleSldLCB0bXBIYXNoKSwgJydcbiAgICApO1xuICAgIGhhc2gudXBkYXRlKGhhc2hlc0pvaW5lZCk7XG4gICAgcmV0dXJuIGhhc2guZGlnZXN0KCdoZXgnKTtcbn1cblxuXG4vKipcbiAqIFJlYWRzIGZpbGVzIGZyb20gZGlzayBhbmQgY29tcHV0ZXMgaGFzaGVzIGZvciB0aGVtLlxuICogQHBhcmFtIHtBcnJheX0gZmlsZXMgLSBhcnJheSB3aXRoIGZpbGUgcGF0aHNcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWFkQW5kSGFzaEZpbGVzKGZpbGVzLCBmaWxlRmlsdGVyKSB7XG4gICAgY29uc3QgZmlsZUhhc2hlcyA9IHt9O1xuICAgIGNvbnN0IGZpbGVDb250ZW50cyA9IHt9O1xuICAgIGNvbnN0IHByb21pc2VzID0gW107XG5cbiAgICBmdW5jdGlvbiByZWFkU2luZ2xlRmlsZShmaWxlKSB7XG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICByZWFkQW5kR2V0RmlsZUhhc2goZmlsZSwgZmlsZS5lbmRzV2l0aCgnLmpzJykgJiYgIWZpbGUuZW5kc1dpdGgoJy50ZXN0LmpzJykpXG4gICAgICAgICAgICAgICAgLnRoZW4oKHJlc3VsdCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBsZXQgZmlsZU5hbWUgPSBmaWxlO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZmlsZUZpbHRlcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZmlsZU5hbWUgPSBmaWxlRmlsdGVyKGZpbGVOYW1lKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBmaWxlSGFzaGVzW2ZpbGVOYW1lXSA9IHJlc3VsdC5oYXNoO1xuICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0LmNvbnRlbnRzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmaWxlQ29udGVudHNbZmlsZU5hbWVdID0gcmVzdWx0LmNvbnRlbnRzO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5jYXRjaChyZWplY3QpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBmaWxlcy5mb3JFYWNoKChmaWxlKSA9PiB7XG4gICAgICAgIHByb21pc2VzLnB1c2gocmVhZFNpbmdsZUZpbGUoZmlsZSkpO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgUHJvbWlzZS5hbGwocHJvbWlzZXMpXG4gICAgICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgcmVzb2x2ZSh7IGZpbGVzLCBmaWxlQ29udGVudHMsIGZpbGVIYXNoZXMgfSk7XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmNhdGNoKHJlamVjdCk7XG4gICAgfSk7XG59XG5cbi8qKlxuICogUmVhZHMgZmlsZXMgZnJvbSAuZGVza3RvcCBhbmQgY29tcHV0ZXMgYSB2ZXJzaW9uIGhhc2guXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGRpciAtIHBhdGhcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZpbGVGaWx0ZXJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWFkRmlsZXNBbmRDb21wdXRlSGFzaChkaXIsIGZpbGVGaWx0ZXIpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBnZXRGaWxlTGlzdChkaXIsIHRydWUpXG4gICAgICAgICAgICAuY2F0Y2gocmVqZWN0KVxuICAgICAgICAgICAgLnRoZW4oZmlsZXMgPT4gcmVhZEFuZEhhc2hGaWxlcyhmaWxlcywgZmlsZUZpbHRlcikpXG4gICAgICAgICAgICAuY2F0Y2gocmVqZWN0KVxuICAgICAgICAgICAgLnRoZW4oKHJlc3VsdCkgPT4ge1xuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1wYXJhbS1yZWFzc2lnblxuICAgICAgICAgICAgICAgIHJlc3VsdC5oYXNoID0gY29tcHV0ZUhhc2hGb3JIYXNoZXNTZXQocmVzdWx0LmZpbGVzLCByZXN1bHQuZmlsZUhhc2hlcywgZmlsZUZpbHRlcik7XG4gICAgICAgICAgICAgICAgcmVzb2x2ZShyZXN1bHQpO1xuICAgICAgICAgICAgfSk7XG4gICAgfSk7XG59XG5cbi8qKlxuICogU3ltbGluayBleGlzdHNcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoVG9DaGVja1xuICogQHJldHVybnMge2Jvb2xlYW59XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzeW1saW5rRXhpc3RzKHBhdGhUb0NoZWNrKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgZnMucmVhZGxpbmtTeW5jKHBhdGhUb0NoZWNrKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxufVxuXG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgICBnZXRGaWxlTGlzdCxcbiAgICBybVdpdGhSZXRyaWVzLFxuICAgIGV4aXN0cyxcbiAgICByZWFkRGlyLFxuICAgIHJlYWRBbmRHZXRGaWxlSGFzaCxcbiAgICBjb21wdXRlSGFzaEZvckhhc2hlc1NldCxcbiAgICByZWFkQW5kSGFzaEZpbGVzLFxuICAgIHJlYWRGaWxlc0FuZENvbXB1dGVIYXNoLFxuICAgIHN5bWxpbmtFeGlzdHNcbn07XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7OztBQUNBLElBQUFBLEtBQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLEdBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFFLE9BQUEsR0FBQUgsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFHLFFBQUEsR0FBQUosc0JBQUEsQ0FBQUMsT0FBQTtBQUE0QixTQUFBRCx1QkFBQUssR0FBQSxXQUFBQSxHQUFBLElBQUFBLEdBQUEsQ0FBQUMsVUFBQSxHQUFBRCxHQUFBLEtBQUFFLE9BQUEsRUFBQUYsR0FBQTtBQUo1Qjs7QUFNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ08sU0FBU0csTUFBTUEsQ0FBQ0MsV0FBVyxFQUFFO0VBQ2hDLElBQUk7SUFDQUMsV0FBRSxDQUFDQyxVQUFVLENBQUNGLFdBQVcsQ0FBQztJQUMxQixPQUFPLElBQUk7RUFDZixDQUFDLENBQUMsT0FBT0csQ0FBQyxFQUFFO0lBQ1IsT0FBTyxLQUFLO0VBQ2hCO0FBQ0o7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDTyxTQUFTQyxhQUFhQSxDQUFDLEdBQUdDLElBQUksRUFBRTtFQUNuQyxJQUFJQyxPQUFPLEdBQUcsQ0FBQztFQUNmLE9BQU8sSUFBSUMsT0FBTyxDQUFDLENBQUNDLE9BQU8sRUFBRUMsTUFBTSxLQUFLO0lBQ3BDLFNBQVNDLEVBQUVBLENBQUMsR0FBR0MsTUFBTSxFQUFFO01BQ25CLElBQUk7UUFDQUMsZ0JBQUssQ0FBQ0MsTUFBTSxDQUFDQyxLQUFLLEdBQUcsSUFBSTtRQUN6QkYsZ0JBQUssQ0FBQ0YsRUFBRSxDQUFDLEdBQUdDLE1BQU0sQ0FBQztRQUNuQkMsZ0JBQUssQ0FBQ0MsTUFBTSxDQUFDRSxLQUFLLENBQUMsQ0FBQztRQUNwQlAsT0FBTyxDQUFDLENBQUM7TUFDYixDQUFDLENBQUMsT0FBT0wsQ0FBQyxFQUFFO1FBQ1JHLE9BQU8sSUFBSSxDQUFDO1FBQ1osSUFBSUEsT0FBTyxHQUFHLENBQUMsRUFBRTtVQUNiVSxVQUFVLENBQUMsTUFBTTtZQUNiTixFQUFFLENBQUMsR0FBR0MsTUFBTSxDQUFDO1VBQ2pCLENBQUMsRUFBRSxHQUFHLENBQUM7UUFDWCxDQUFDLE1BQU07VUFDSEMsZ0JBQUssQ0FBQ0MsTUFBTSxDQUFDRSxLQUFLLENBQUMsQ0FBQztVQUNwQk4sTUFBTSxDQUFDTixDQUFDLENBQUM7UUFDYjtNQUNKO0lBQ0o7SUFDQU8sRUFBRSxDQUFDLEdBQUdMLElBQUksQ0FBQztFQUNmLENBQUMsQ0FBQztBQUNOO0FBRU8sU0FBU1ksT0FBT0EsQ0FBQ0MsR0FBRyxFQUFFQyxRQUFRLEVBQUU7RUFDbkMsSUFBSSxDQUFDQSxRQUFRLEVBQUU7SUFDWCxPQUFPLElBQUlaLE9BQU8sQ0FBQyxDQUFDQyxPQUFPLEVBQUVDLE1BQU0sS0FBSztNQUNwQ1EsT0FBTyxDQUFDQyxHQUFHLEVBQUUsQ0FBQ0UsR0FBRyxFQUFFQyxJQUFJLEVBQUVDLEtBQUssS0FBSztRQUMvQixJQUFJRixHQUFHLEVBQUU7VUFDTFgsTUFBTSxDQUFDVyxHQUFHLENBQUM7UUFDZixDQUFDLE1BQU07VUFDSFosT0FBTyxDQUFDO1lBQUVhLElBQUk7WUFBRUM7VUFBTSxDQUFDLENBQUM7UUFDNUI7TUFDSixDQUFDLENBQUM7SUFDTixDQUFDLENBQUM7RUFDTjtFQUNBLElBQUlDLElBQUksR0FBRyxFQUFFO0VBQ2IsSUFBSUMsUUFBUSxHQUFHLENBQUMsQ0FBQztFQUVqQnZCLFdBQUUsQ0FBQ3dCLE9BQU8sQ0FBQ1AsR0FBRyxFQUFFLENBQUNFLEdBQUcsRUFBRU0sS0FBSyxLQUFLO0lBQzVCLElBQUlOLEdBQUcsRUFBRTtNQUNMLE9BQU9ELFFBQVEsQ0FBQ0MsR0FBRyxDQUFDO0lBQ3hCO0lBQ0EsSUFBSU8sT0FBTyxHQUFHRCxLQUFLLENBQUNFLE1BQU07SUFDMUIsSUFBSSxDQUFDRCxPQUFPLEVBQUU7TUFDVixPQUFPUixRQUFRLENBQUMsSUFBSSxFQUFFSSxJQUFJLEVBQUVDLFFBQVEsQ0FBQztJQUN6QztJQUNBRSxLQUFLLENBQUNHLE9BQU8sQ0FBRUMsSUFBSSxJQUFLO01BQ3BCLE1BQU1DLFFBQVEsR0FBR0MsYUFBSSxDQUFDQyxJQUFJLENBQUNmLEdBQUcsRUFBRVksSUFBSSxDQUFDO01BQ3JDN0IsV0FBRSxDQUFDaUMsSUFBSSxDQUFDSCxRQUFRLEVBQUUsQ0FBQ0ksSUFBSSxFQUFFYixLQUFLLEtBQUs7UUFDL0IsSUFBSWEsSUFBSSxFQUFFO1VBQ04sT0FBT2hCLFFBQVEsQ0FBQ2dCLElBQUksQ0FBQztRQUN6QjtRQUNBLElBQUliLEtBQUssQ0FBQ2MsV0FBVyxDQUFDLENBQUMsRUFBRTtVQUNyQm5CLE9BQU8sQ0FBQ2MsUUFBUSxFQUFFLENBQUNNLEtBQUssRUFBRUMsR0FBRyxFQUFFQyxTQUFTLEtBQUs7WUFDekMsSUFBSUYsS0FBSyxFQUFFO2NBQ1AsT0FBT2xCLFFBQVEsQ0FBQ2tCLEtBQUssQ0FBQztZQUMxQjtZQUNBZCxJQUFJLEdBQUdBLElBQUksQ0FBQ2lCLE1BQU0sQ0FBQ0YsR0FBRyxDQUFDO1lBQ3ZCZCxRQUFRLEdBQUdpQixNQUFNLENBQUNDLE1BQU0sQ0FBQ2xCLFFBQVEsRUFBRWUsU0FBUyxDQUFDO1lBQzdDWixPQUFPLElBQUksQ0FBQztZQUNaLElBQUksQ0FBQ0EsT0FBTyxFQUFFO2NBQ1YsT0FBT1IsUUFBUSxDQUFDLElBQUksRUFBRUksSUFBSSxFQUFFQyxRQUFRLENBQUM7WUFDekM7VUFDSixDQUFDLENBQUM7UUFDTixDQUFDLE1BQU07VUFDSEQsSUFBSSxDQUFDb0IsSUFBSSxDQUFDWixRQUFRLENBQUM7VUFDbkJQLFFBQVEsQ0FBQ08sUUFBUSxDQUFDLEdBQUc7WUFDakJhLElBQUksRUFBRXRCLEtBQUssQ0FBQ3NCLElBQUk7WUFDaEJDLEtBQUssRUFBRSxDQUNIdkIsS0FBSyxDQUFDd0IsU0FBUyxDQUFDQyxPQUFPLENBQUMsQ0FBQyxFQUN6QnpCLEtBQUssQ0FBQzBCLEtBQUssQ0FBQ0QsT0FBTyxDQUFDLENBQUMsRUFDckJ6QixLQUFLLENBQUMyQixLQUFLLENBQUNGLE9BQU8sQ0FBQyxDQUFDO1VBRTdCLENBQUM7VUFDRHBCLE9BQU8sSUFBSSxDQUFDO1VBQ1osSUFBSSxDQUFDQSxPQUFPLEVBQUU7WUFDVixPQUFPUixRQUFRLENBQUMsSUFBSSxFQUFFSSxJQUFJLEVBQUVDLFFBQVEsQ0FBQztVQUN6QztRQUNKO01BQ0osQ0FBQyxDQUFDO0lBQ04sQ0FBQyxDQUFDO0VBQ04sQ0FBQyxDQUFDO0FBQ047O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ08sU0FBUzBCLFdBQVdBLENBQUNoQyxHQUFHLEVBQUVpQyxJQUFJLEdBQUcsS0FBSyxFQUFFO0VBQzNDLE9BQU8sSUFBSTVDLE9BQU8sQ0FBQyxDQUFDQyxPQUFPLEVBQUVDLE1BQU0sS0FBSztJQUNwQ1EsT0FBTyxDQUFDQyxHQUFHLEVBQUUsQ0FBQ2tDLEtBQUssRUFBRTFCLEtBQUssS0FBSztNQUMzQixJQUFJMEIsS0FBSyxFQUFFO1FBQ1AzQyxNQUFNLENBQUMyQyxLQUFLLENBQUM7UUFDYjtNQUNKO01BQ0E7TUFDQSxJQUFJQyxrQkFBa0I7TUFFdEIsSUFBSUYsSUFBSSxFQUFFO1FBQ04sTUFBTUcsV0FBVyxHQUFJcEMsR0FBRyxDQUFDcUMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsS0FBSyxJQUFJLEdBQUlyQyxHQUFHLENBQUNVLE1BQU0sR0FBRyxDQUFDLEdBQUdWLEdBQUcsQ0FBQ1UsTUFBTSxHQUFHLENBQUM7UUFDakYsSUFBSTRCLFlBQVksR0FBRzlCLEtBQUssQ0FBQytCLEdBQUcsQ0FBRUMsR0FBRyxJQUFJQSxHQUFHLENBQUNILE1BQU0sQ0FBQ0QsV0FBVyxDQUFDLENBQUNLLE9BQU8sQ0FBQyxTQUFTLEVBQUUsR0FBRyxDQUFFLENBQUM7UUFDdEYsTUFBTUMsY0FBYyxHQUFHLENBQUMsQ0FBQztRQUN6QmxDLEtBQUssQ0FBQ0csT0FBTyxDQUFDLENBQUNDLElBQUksRUFBRStCLENBQUMsS0FBSztVQUN2QkQsY0FBYyxDQUFDSixZQUFZLENBQUNLLENBQUMsQ0FBQyxDQUFDLEdBQUcvQixJQUFJO1FBQzFDLENBQUMsQ0FBQztRQUNGMEIsWUFBWSxHQUFHQSxZQUFZLENBQUNMLElBQUksQ0FBQyxDQUFDO1FBQ2xDLE1BQU1XLFdBQVcsR0FBRyxFQUFFO1FBQ3RCTixZQUFZLENBQUMzQixPQUFPLENBQUVrQyxHQUFHLElBQUs7VUFDMUJELFdBQVcsQ0FBQ25CLElBQUksQ0FBQ2lCLGNBQWMsQ0FBQ0csR0FBRyxDQUFDLENBQUM7UUFDekMsQ0FBQyxDQUFDO1FBQ0ZWLGtCQUFrQixHQUFHUyxXQUFXO01BQ3BDLENBQUMsTUFBTTtRQUNIVCxrQkFBa0IsR0FBRzNCLEtBQUs7TUFDOUI7TUFDQWxCLE9BQU8sQ0FBQzZDLGtCQUFrQixDQUFDO0lBQy9CLENBQUMsQ0FBQztFQUNOLENBQUMsQ0FBQztBQUNOOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNPLFNBQVNXLGtCQUFrQkEsQ0FBQ2xDLElBQUksRUFBRW1DLGtCQUFrQixHQUFHLEtBQUssRUFBRTtFQUNqRSxPQUFPLElBQUkxRCxPQUFPLENBQUMsQ0FBQ0MsT0FBTyxFQUFFQyxNQUFNLEtBQUs7SUFDcENSLFdBQUUsQ0FBQ2lFLFFBQVEsQ0FBQ3BDLElBQUksRUFBRSxDQUFDVixHQUFHLEVBQUVDLElBQUksS0FBSztNQUM3QixJQUFJRCxHQUFHLEVBQUU7UUFDTFgsTUFBTSxDQUFDVyxHQUFHLENBQUM7UUFDWDtNQUNKO01BQ0EsTUFBTStDLElBQUksR0FBR0MsZUFBTSxDQUFDQyxVQUFVLENBQUMsTUFBTSxDQUFDO01BQ3RDRixJQUFJLENBQUNHLE1BQU0sQ0FBQ2pELElBQUksQ0FBQztNQUNqQixNQUFNa0QsWUFBWSxHQUFHO1FBQUVKLElBQUksRUFBRUEsSUFBSSxDQUFDSyxNQUFNLENBQUMsS0FBSztNQUFFLENBQUM7TUFDakQsSUFBSVAsa0JBQWtCLEVBQUU7UUFDcEJNLFlBQVksQ0FBQ0UsUUFBUSxHQUFHcEQsSUFBSSxDQUFDcUQsUUFBUSxDQUFDLE1BQU0sQ0FBQztNQUNqRDtNQUNBbEUsT0FBTyxDQUFDK0QsWUFBWSxDQUFDO0lBQ3pCLENBQUMsQ0FBQztFQUNOLENBQUMsQ0FBQztBQUNOOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ08sU0FBU0ksdUJBQXVCQSxDQUFDQyxXQUFXLEVBQUVDLE9BQU8sRUFBRUMsU0FBUyxHQUFHZixHQUFHLElBQUlBLEdBQUcsRUFBRTtFQUNsRixNQUFNSSxJQUFJLEdBQUdDLGVBQU0sQ0FBQ0MsVUFBVSxDQUFDLE1BQU0sQ0FBQztFQUN0QyxNQUFNVSxZQUFZLEdBQUdILFdBQVcsQ0FBQ0ksTUFBTTtFQUNuQztFQUNBLENBQUNDLE9BQU8sRUFBRWxCLEdBQUcsTUFBTWtCLE9BQU8sSUFBSUosT0FBTyxDQUFDQyxTQUFTLENBQUNmLEdBQUcsQ0FBQyxDQUFDLEVBQUVrQixPQUFPLENBQUMsRUFBRSxFQUNyRSxDQUFDO0VBQ0RkLElBQUksQ0FBQ0csTUFBTSxDQUFDUyxZQUFZLENBQUM7RUFDekIsT0FBT1osSUFBSSxDQUFDSyxNQUFNLENBQUMsS0FBSyxDQUFDO0FBQzdCOztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDTyxTQUFTVSxnQkFBZ0JBLENBQUN4RCxLQUFLLEVBQUV5RCxVQUFVLEVBQUU7RUFDaEQsTUFBTUMsVUFBVSxHQUFHLENBQUMsQ0FBQztFQUNyQixNQUFNQyxZQUFZLEdBQUcsQ0FBQyxDQUFDO0VBQ3ZCLE1BQU1DLFFBQVEsR0FBRyxFQUFFO0VBRW5CLFNBQVNDLGNBQWNBLENBQUN6RCxJQUFJLEVBQUU7SUFDMUIsT0FBTyxJQUFJdkIsT0FBTyxDQUFDLENBQUNDLE9BQU8sRUFBRUMsTUFBTSxLQUFLO01BQ3BDdUQsa0JBQWtCLENBQUNsQyxJQUFJLEVBQUVBLElBQUksQ0FBQzBELFFBQVEsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDMUQsSUFBSSxDQUFDMEQsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQ3ZFQyxJQUFJLENBQUVDLE1BQU0sSUFBSztRQUNkLElBQUlDLFFBQVEsR0FBRzdELElBQUk7UUFDbkIsSUFBSXFELFVBQVUsRUFBRTtVQUNaUSxRQUFRLEdBQUdSLFVBQVUsQ0FBQ1EsUUFBUSxDQUFDO1FBQ25DO1FBQ0FQLFVBQVUsQ0FBQ08sUUFBUSxDQUFDLEdBQUdELE1BQU0sQ0FBQ3ZCLElBQUk7UUFDbEMsSUFBSXVCLE1BQU0sQ0FBQ2pCLFFBQVEsRUFBRTtVQUNqQlksWUFBWSxDQUFDTSxRQUFRLENBQUMsR0FBR0QsTUFBTSxDQUFDakIsUUFBUTtRQUM1QztRQUNBakUsT0FBTyxDQUFDLENBQUM7TUFDYixDQUFDLENBQUMsQ0FDRG9GLEtBQUssQ0FBQ25GLE1BQU0sQ0FBQztJQUN0QixDQUFDLENBQUM7RUFDTjtFQUVBaUIsS0FBSyxDQUFDRyxPQUFPLENBQUVDLElBQUksSUFBSztJQUNwQndELFFBQVEsQ0FBQzNDLElBQUksQ0FBQzRDLGNBQWMsQ0FBQ3pELElBQUksQ0FBQyxDQUFDO0VBQ3ZDLENBQUMsQ0FBQztFQUVGLE9BQU8sSUFBSXZCLE9BQU8sQ0FBQyxDQUFDQyxPQUFPLEVBQUVDLE1BQU0sS0FBSztJQUNwQ0YsT0FBTyxDQUFDc0YsR0FBRyxDQUFDUCxRQUFRLENBQUMsQ0FDaEJHLElBQUksQ0FBQyxNQUFNO01BQ1JqRixPQUFPLENBQUM7UUFBRWtCLEtBQUs7UUFBRTJELFlBQVk7UUFBRUQ7TUFBVyxDQUFDLENBQUM7SUFDaEQsQ0FBQyxDQUFDLENBQ0RRLEtBQUssQ0FBQ25GLE1BQU0sQ0FBQztFQUN0QixDQUFDLENBQUM7QUFDTjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNPLFNBQVNxRix1QkFBdUJBLENBQUM1RSxHQUFHLEVBQUVpRSxVQUFVLEVBQUU7RUFDckQsT0FBTyxJQUFJNUUsT0FBTyxDQUFDLENBQUNDLE9BQU8sRUFBRUMsTUFBTSxLQUFLO0lBQ3BDeUMsV0FBVyxDQUFDaEMsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUNqQjBFLEtBQUssQ0FBQ25GLE1BQU0sQ0FBQyxDQUNiZ0YsSUFBSSxDQUFDL0QsS0FBSyxJQUFJd0QsZ0JBQWdCLENBQUN4RCxLQUFLLEVBQUV5RCxVQUFVLENBQUMsQ0FBQyxDQUNsRFMsS0FBSyxDQUFDbkYsTUFBTSxDQUFDLENBQ2JnRixJQUFJLENBQUVDLE1BQU0sSUFBSztNQUNkO01BQ0FBLE1BQU0sQ0FBQ3ZCLElBQUksR0FBR1EsdUJBQXVCLENBQUNlLE1BQU0sQ0FBQ2hFLEtBQUssRUFBRWdFLE1BQU0sQ0FBQ04sVUFBVSxFQUFFRCxVQUFVLENBQUM7TUFDbEYzRSxPQUFPLENBQUNrRixNQUFNLENBQUM7SUFDbkIsQ0FBQyxDQUFDO0VBQ1YsQ0FBQyxDQUFDO0FBQ047O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNPLFNBQVNLLGFBQWFBLENBQUMvRixXQUFXLEVBQUU7RUFDdkMsSUFBSTtJQUNBQyxXQUFFLENBQUMrRixZQUFZLENBQUNoRyxXQUFXLENBQUM7SUFDNUIsT0FBTyxJQUFJO0VBQ2YsQ0FBQyxDQUFDLE9BQU9HLENBQUMsRUFBRTtJQUNSLE9BQU8sS0FBSztFQUNoQjtBQUNKO0FBQUMsSUFBQThGLFFBQUEsR0FHYztFQUNYL0MsV0FBVztFQUNYOUMsYUFBYTtFQUNiTCxNQUFNO0VBQ05rQixPQUFPO0VBQ1ArQyxrQkFBa0I7RUFDbEJXLHVCQUF1QjtFQUN2Qk8sZ0JBQWdCO0VBQ2hCWSx1QkFBdUI7RUFDdkJDO0FBQ0osQ0FBQztBQUFBRyxPQUFBLENBQUFwRyxPQUFBLEdBQUFtRyxRQUFBIn0=