@sharekey/meteor-desktop
Version:
Build a Meteor's desktop client with hot code push.
282 lines (273 loc) • 29.8 kB
JavaScript
;
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+IHtcbiAgICAgICAgUHJvbWlzZS5hbGwocHJvbWlzZXMpXG4gICAgICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgcmVzb2x2ZSh7IGZpbGVzLCBmaWxlQ29udGVudHMsIGZpbGVIYXNoZXMgfSk7XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmNhdGNoKHJlamVjdCk7XG4gICAgfSk7XG59XG5cbi8qKlxuICogUmVhZHMgZmlsZXMgZnJvbSAuZGVza3RvcCBhbmQgY29tcHV0ZXMgYSB2ZXJzaW9uIGhhc2guXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGRpciAtIHBhdGhcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZpbGVGaWx0ZXJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWFkRmlsZXNBbmRDb21wdXRlSGFzaChkaXIsIGZpbGVGaWx0ZXIpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBnZXRGaWxlTGlzdChkaXIsIHRydWUpXG4gICAgICAgICAgICAuY2F0Y2gocmVqZWN0KVxuICAgICAgICAgICAgLnRoZW4oZmlsZXMgPT4gcmVhZEFuZEhhc2hGaWxlcyhmaWxlcywgZmlsZUZpbHRlcikpXG4gICAgICAgICAgICAuY2F0Y2gocmVqZWN0KVxuICAgICAgICAgICAgLnRoZW4oKHJlc3VsdCkgPT4ge1xuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1wYXJhbS1yZWFzc2lnblxuICAgICAgICAgICAgICAgIHJlc3VsdC5oYXNoID0gY29tcHV0ZUhhc2hGb3JIYXNoZXNTZXQocmVzdWx0LmZpbGVzLCByZXN1bHQuZmlsZUhhc2hlcywgZmlsZUZpbHRlcik7XG4gICAgICAgICAgICAgICAgcmVzb2x2ZShyZXN1bHQpO1xuICAgICAgICAgICAgfSk7XG4gICAgfSk7XG59XG5cbi8qKlxuICogU3ltbGluayBleGlzdHNcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoVG9DaGVja1xuICogQHJldHVybnMge2Jvb2xlYW59XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzeW1saW5rRXhpc3RzKHBhdGhUb0NoZWNrKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgZnMucmVhZGxpbmtTeW5jKHBhdGhUb0NoZWNrKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxufVxuXG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgICBnZXRGaWxlTGlzdCxcbiAgICBybVdpdGhSZXRyaWVzLFxuICAgIGV4aXN0cyxcbiAgICByZWFkRGlyLFxuICAgIHJlYWRBbmRHZXRGaWxlSGFzaCxcbiAgICBjb21wdXRlSGFzaEZvckhhc2hlc1NldCxcbiAgICByZWFkQW5kSGFzaEZpbGVzLFxuICAgIHJlYWRGaWxlc0FuZENvbXB1dGVIYXNoLFxuICAgIHN5bWxpbmtFeGlzdHNcbn07XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7OztBQUNBLElBQUFBLEtBQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLEdBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFFLE9BQUEsR0FBQUgsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFHLFFBQUEsR0FBQUosc0JBQUEsQ0FBQUMsT0FBQTtBQUE0QixTQUFBRCx1QkFBQUssR0FBQSxXQUFBQSxHQUFBLElBQUFBLEdBQUEsQ0FBQUMs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