@mjcctech/meteor-desktop
Version:
Build a Meteor's desktop client with hot code push.
328 lines (271 loc) • 29.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.exists = exists;
exports.rmWithRetries = rmWithRetries;
exports.readDir = readDir;
exports.getFileList = getFileList;
exports.readAndGetFileHash = readAndGetFileHash;
exports.computeHashForHashesSet = computeHashForHashesSet;
exports.readAndHashFiles = readAndHashFiles;
exports.readFilesAndComputeHash = readFilesAndComputeHash;
exports.symlinkExists = symlinkExists;
exports.default = void 0;
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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL2xpYi91dGlscy5qcyJdLCJuYW1lcyI6WyJleGlzdHMiLCJwYXRoVG9DaGVjayIsImZzIiwiYWNjZXNzU3luYyIsImUiLCJybVdpdGhSZXRyaWVzIiwiYXJncyIsInJldHJpZXMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsInJtIiwicm1BcmdzIiwic2hlbGwiLCJjb25maWciLCJmYXRhbCIsInJlc2V0Iiwic2V0VGltZW91dCIsInJlYWREaXIiLCJkaXIiLCJjYWxsYmFjayIsImVyciIsImRhdGEiLCJzdGF0cyIsImxpc3QiLCJhbGxTdGF0cyIsInJlYWRkaXIiLCJmaWxlcyIsInBlbmRpbmciLCJsZW5ndGgiLCJmb3JFYWNoIiwiZmlsZSIsImZpbGVQYXRoIiwicGF0aCIsImpvaW4iLCJzdGF0IiwiX2VyciIsImlzRGlyZWN0b3J5IiwiX19lcnIiLCJyZXMiLCJfYWxsU3RhdHMiLCJjb25jYXQiLCJPYmplY3QiLCJhc3NpZ24iLCJwdXNoIiwic2l6ZSIsImRhdGVzIiwiYmlydGh0aW1lIiwiZ2V0VGltZSIsImN0aW1lIiwibXRpbWUiLCJnZXRGaWxlTGlzdCIsInNvcnQiLCJlcnJvciIsInJlc3VsdGFudEZpbGVzTGlzdCIsInN0cmlwTGVuZ3RoIiwic3Vic3RyIiwicGF0aHNVbmlmaWVkIiwibWFwIiwicHRoIiwicmVwbGFjZSIsInRlbXBvcmFyeUluZGV4IiwiaSIsImZpbGVzU29ydGVkIiwia2V5IiwicmVhZEFuZEdldEZpbGVIYXNoIiwicmV0dXJuRmlsZUNvbnRlbnRzIiwicmVhZEZpbGUiLCJoYXNoIiwiY3J5cHRvIiwiY3JlYXRlSGFzaCIsInVwZGF0ZSIsInJldHVybk9iamVjdCIsImRpZ2VzdCIsImNvbnRlbnRzIiwidG9TdHJpbmciLCJjb21wdXRlSGFzaEZvckhhc2hlc1NldCIsIm9yZGVyT2ZLZXlzIiwiaGFzaFNldCIsImtleUZpbHRlciIsImhhc2hlc0pvaW5lZCIsInJlZHVjZSIsInRtcEhhc2giLCJyZWFkQW5kSGFzaEZpbGVzIiwiZmlsZUZpbHRlciIsImZpbGVIYXNoZXMiLCJmaWxlQ29udGVudHMiLCJwcm9taXNlcyIsInJlYWRTaW5nbGVGaWxlIiwiZW5kc1dpdGgiLCJ0aGVuIiwicmVzdWx0IiwiZmlsZU5hbWUiLCJjYXRjaCIsImFsbCIsInJlYWRGaWxlc0FuZENvbXB1dGVIYXNoIiwic3ltbGlua0V4aXN0cyIsInJlYWRsaW5rU3luYyJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7OztBQUNBOztBQUNBOztBQUNBOztBQUNBOzs7O0FBSkE7O0FBTUE7Ozs7O0FBS08sU0FBU0EsTUFBVCxDQUFnQkMsV0FBaEIsRUFBNkI7QUFDaEMsTUFBSTtBQUNBQyxnQkFBR0MsVUFBSCxDQUFjRixXQUFkOztBQUNBLFdBQU8sSUFBUDtBQUNILEdBSEQsQ0FHRSxPQUFPRyxDQUFQLEVBQVU7QUFDUixXQUFPLEtBQVA7QUFDSDtBQUNKO0FBRUQ7Ozs7OztBQUlPLFNBQVNDLGFBQVQsQ0FBdUIsR0FBR0MsSUFBMUIsRUFBZ0M7QUFDbkMsTUFBSUMsT0FBTyxHQUFHLENBQWQ7QUFDQSxTQUFPLElBQUlDLE9BQUosQ0FBWSxDQUFDQyxPQUFELEVBQVVDLE1BQVYsS0FBcUI7QUFDcEMsYUFBU0MsRUFBVCxDQUFZLEdBQUdDLE1BQWYsRUFBdUI7QUFDbkIsVUFBSTtBQUNBQyx5QkFBTUMsTUFBTixDQUFhQyxLQUFiLEdBQXFCLElBQXJCOztBQUNBRix5QkFBTUYsRUFBTixDQUFTLEdBQUdDLE1BQVo7O0FBQ0FDLHlCQUFNQyxNQUFOLENBQWFFLEtBQWI7O0FBQ0FQLFFBQUFBLE9BQU87QUFDVixPQUxELENBS0UsT0FBT0wsQ0FBUCxFQUFVO0FBQ1JHLFFBQUFBLE9BQU8sSUFBSSxDQUFYOztBQUNBLFlBQUlBLE9BQU8sR0FBRyxDQUFkLEVBQWlCO0FBQ2JVLFVBQUFBLFVBQVUsQ0FBQyxNQUFNO0FBQ2JOLFlBQUFBLEVBQUUsQ0FBQyxHQUFHQyxNQUFKLENBQUY7QUFDSCxXQUZTLEVBRVAsR0FGTyxDQUFWO0FBR0gsU0FKRCxN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R0tTLEtBSEwsQ0FHV25GLE1BSFgsRUFJS2dGLElBSkwsQ0FJV0MsTUFBRCxJQUFZO0FBQ2Q7QUFDQUEsTUFBQUEsTUFBTSxDQUFDdkIsSUFBUCxHQUFjUSx1QkFBdUIsQ0FBQ2UsTUFBTSxDQUFDaEUsS0FBUixFQUFlZ0UsTUFBTSxDQUFDTixVQUF0QixFQUFrQ0QsVUFBbEMsQ0FBckM7QUFDQTNFLE1BQUFBLE9BQU8sQ0FBQ2tGLE1BQUQsQ0FBUDtBQUNILEtBUkw7QUFTSCxHQVZNLENBQVA7QUFXSDtBQUVEOzs7Ozs7O0FBS08sU0FBU0ssYUFBVCxDQUF1Qi9GLFdBQXZCLEVBQW9DO0FBQ3ZDLE1BQUk7QUFDQUMsZ0JBQUcrRixZQUFILENBQWdCaEcsV0FBaEI7O0FBQ0EsV0FBTyxJQUFQO0FBQ0gsR0FIRCxDQUdFLE9BQU9HLENBQVAsRUFBVTtBQUNSLFdBQU8sS0FBUDtBQUNIO0FBQ0o7O2VBR2M7QUFDWCtDLEVBQUFBLFdBRFc7QUFFWDlDLEVBQUFBLGFBRlc7QUFHWEwsRUFBQUEsTUFIVztBQUlYa0IsRUFBQUEsT0FKVztBQUtYK0MsRUFBQUEsa0JBTFc7QUFNWFcsRUFBQUEsdUJBTlc7QUFPWE8sRUFBQUEsZ0JBUFc7QUFRWFksRUFBQUEsdUJBUlc7QUFTWEMsRUFBQUE7QUFUVyxDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgY29uc2lzdGVudC1yZXR1cm4gKi9cbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IGZzIGZyb20gJ2ZzJztcbmltcG9ydCBjcnlwdG8gZnJvbSAnY3J5cHRvJztcbmltcG9ydCBzaGVsbCBmcm9tICdzaGVsbGpzJztcblxuLyoqXG4gKiBFeGlzdHNcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoVG9DaGVja1xuICogQHJldHVybnMge2Jvb2xlYW59XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBleGlzdHMocGF0aFRvQ2hlY2spIHtcbiAgICB0cnkge1xuICAgICAgICBmcy5hY2Nlc3NTeW5jKHBhdGhUb0NoZWNrKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxufVxuXG4vKipcbiAqIFNpbXBsZSB3cmFwcGVyIGZvciBzaGVsbGpzLnJtIHdpdGggYWRkaXRpb25hbCByZXRyaWVzIGluIGNhc2Ugb2YgZmFpbHVyZS5cbiAqIEl0IGlzIHVzZWZ1bCB3aGVuIHNvbWV0aGluZyBpcyBjb25jdXJyZW50bHkgcmVhZGluZyB0aGUgZGlyIHlvdSB3YW50IHRvIHJlbW92ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJtV2l0aFJldHJpZXMoLi4uYXJncykge1xuICAgIGxldCByZXRyaWVzID0gMDtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBmdW5jdGlvbiBybSguLi5ybUFyZ3MpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgc2hlbGwuY29uZmlnLmZhdGFsID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBzaGVsbC5ybSguLi5ybUFyZ3MpO1xuICAgICAgICAgICAgICAgIHNoZWxsLmNvbmZpZy5yZXNldCgpO1xuICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICByZXRyaWVzICs9IDE7XG4gICAgICAgICAgICAgICAgaWYgKHJldHJpZXMgPCA1KSB7XG4gICAgICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgcm0oLi4ucm1BcmdzKTtcbiAgICAgICAgICAgICAgICAgICAgfSwgMTAwKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBzaGVsbC5jb25maWcucmVzZXQoKTtcbiAgICAgICAgICAgICAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBybSguLi5hcmdzKTtcbiAgICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlYWREaXIoZGlyLCBjYWxsYmFjaykge1xuICAgIGlmICghY2FsbGJhY2spIHtcbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIHJlYWREaXIoZGlyLCAoZXJyLCBkYXRhLCBzdGF0cykgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVqZWN0KGVycik7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZSh7IGRhdGEsIHN0YXRzIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgbGV0IGxpc3QgPSBbXTtcbiAgICBsZXQgYWxsU3RhdHMgPSB7fTtcblxuICAgIGZzLnJlYWRkaXIoZGlyLCAoZXJyLCBmaWxlcykgPT4ge1xuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICByZXR1cm4gY2FsbGJhY2soZXJyKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcGVuZGluZyA9IGZpbGVzLmxlbmd0aDtcbiAgICAgICAgaWYgKCFwZW5kaW5nKSB7XG4gICAgICAgICAgICByZXR1cm4gY2FsbGJhY2sobnVsbCwgbGlzdCwgYWxsU3RhdHMpO1xuICAgICAgICB9XG4gICAgICAgIGZpbGVzLmZvckVhY2goKGZpbGUpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGZpbGVQYXRoID0gcGF0aC5qb2luKGRpciwgZmlsZSk7XG4gICAgICAgICAgICBmcy5zdGF0KGZpbGVQYXRoLCAoX2Vyciwgc3RhdHMpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoX2Vycikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gY2FsbGJhY2soX2Vycik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChzdGF0cy5pc0RpcmVjdG9yeSgpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlYWREaXIoZmlsZVBhdGgsIChfX2VyciwgcmVzLCBfYWxsU3RhdHMpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChfX2Vycikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhfX2Vycik7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBsaXN0ID0gbGlzdC5jb25jYXQocmVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFsbFN0YXRzID0gT2JqZWN0LmFzc2lnbihhbGxTdGF0cywgX2FsbFN0YXRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBlbmRpbmcgLT0gMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghcGVuZGluZykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhudWxsLCBsaXN0LCBhbGxTdGF0cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGxpc3QucHVzaChmaWxlUGF0aCk7XG4gICAgICAgICAgICAgICAgICAgIGFsbFN0YXRzW2ZpbGVQYXRoXSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNpemU6IHN0YXRzLnNpemUsXG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRlczogW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRzLmJpcnRodGltZS5nZXRUaW1lKCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHMuY3RpbWUuZ2V0VGltZSgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRzLm10aW1lLmdldFRpbWUoKVxuICAgICAgICAgICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICBwZW5kaW5nIC09IDE7XG4gICAgICAgICAgICAgICAgICAgIGlmICghcGVuZGluZykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKG51bGwsIGxpc3QsIGFsbFN0YXRzKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9KTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIGEgZmlsZSBsaXN0IGZyb20gYSBkaXJlY3RvcnkuXG4gKiBAcGFyYW0ge3N0cmluZ30gZGlyIC0gZGlyIHBhdGhcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gc29ydCAtIHdoZXRoZXIgdG8gYXBwbHkgc29ydFxuICogQHJldHVybnMge1Byb21pc2U8QXJyYXk+fVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0RmlsZUxpc3QoZGlyLCBzb3J0ID0gZmFsc2UpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICByZWFkRGlyKGRpciwgKGVycm9yLCBmaWxlcykgPT4ge1xuICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tcGFyYW0tcmVhc3NpZ25cbiAgICAgICAgICAgIGxldCByZXN1bHRhbnRGaWxlc0xpc3Q7XG5cbiAgICAgICAgICAgIGlmIChzb3J0KSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgc3RyaXBMZW5ndGggPSAoZGlyLnN1YnN0cigwLCAyKSA9PT0gJy4vJykgPyBkaXIubGVuZ3RoIC0gMSA6IGRpci5sZW5ndGggKyAxO1xuICAgICAgICAgICAgICAgIGxldCBwYXRoc1VuaWZpZWQgPSBmaWxlcy5tYXAoKHB0aCA9PiBwdGguc3Vic3RyKHN0cmlwTGVuZ3RoKS5yZXBsYWNlKC9bXFxcXC9dL2dtLCAnLScpKSk7XG4gICAgICAgICAgICAgICAgY29uc3QgdGVtcG9yYXJ5SW5kZXggPSB7fTtcbiAgICAgICAgICAgICAgICBmaWxlcy5mb3JFYWNoKChmaWxlLCBpKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRlbXBvcmFyeUluZGV4W3BhdGhzVW5pZmllZFtpXV0gPSBmaWxlO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHBhdGhzVW5pZmllZCA9IHBhdGhzVW5pZmllZC5zb3J0KCk7XG4gICAgICAgICAgICAgICAgY29uc3QgZmlsZXNTb3J0ZWQgPSBbXTtcbiAgICAgICAgICAgICAgICBwYXRoc1VuaWZpZWQuZm9yRWFjaCgoa2V5KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGZpbGVzU29ydGVkLnB1c2godGVtcG9yYXJ5SW5kZXhba2V5XSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmVzdWx0YW50RmlsZXNMaXN0ID0gZmlsZXNTb3J0ZWQ7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJlc3VsdGFudEZpbGVzTGlzdCA9IGZpbGVzO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVzb2x2ZShyZXN1bHRhbnRGaWxlc0xpc3QpO1xuICAgICAgICB9KTtcbiAgICB9KTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIGZpbGUncyBoYXNoLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGUgLSBmaWxlIHBhdGhcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gcmV0dXJuRmlsZUNvbnRlbnRzIC0gaW5jbHVkZSBmaWxlIGNvbnRlbnRzIGluIHRoZSByZXN1bHRhbnQgb2JqZWN0XG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fVxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVhZEFuZEdldEZpbGVIYXNoKGZpbGUsIHJldHVybkZpbGVDb250ZW50cyA9IGZhbHNlKSB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgZnMucmVhZEZpbGUoZmlsZSwgKGVyciwgZGF0YSkgPT4ge1xuICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgIHJlamVjdChlcnIpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGhhc2ggPSBjcnlwdG8uY3JlYXRlSGFzaCgnc2hhMScpO1xuICAgICAgICAgICAgaGFzaC51cGRhdGUoZGF0YSk7XG4gICAgICAgICAgICBjb25zdCByZXR1cm5PYmplY3QgPSB7IGhhc2g6IGhhc2guZGlnZXN0KCdoZXgnKSB9O1xuICAgICAgICAgICAgaWYgKHJldHVybkZpbGVDb250ZW50cykge1xuICAgICAgICAgICAgICAgIHJldHVybk9iamVjdC5jb250ZW50cyA9IGRhdGEudG9TdHJpbmcoJ3V0ZjgnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJlc29sdmUocmV0dXJuT2JqZWN0KTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG59XG5cbi8qKlxuICogQ2FsY3VsYXRlcyBhIGhhc2ggZnJvbSBvYmplY3RzIHZhbHVlcyBpbiBzcGVjaWZpZWQgb3JkZXIuXG4gKiBAcGFyYW0ge0FycmF5fSBvcmRlck9mS2V5c1xuICogQHBhcmFtIHtPYmplY3R9IGhhc2hTZXRcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGtleUZpbHRlclxuICogQHJldHVybnMge3N0cmluZ31cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbXB1dGVIYXNoRm9ySGFzaGVzU2V0KG9yZGVyT2ZLZXlzLCBoYXNoU2V0LCBrZXlGaWx0ZXIgPSBrZXkgPT4ga2V5KSB7XG4gICAgY29uc3QgaGFzaCA9IGNyeXB0by5jcmVhdGVIYXNoKCdzaGExJyk7XG4gICAgY29uc3QgaGFzaGVzSm9pbmVkID0gb3JkZXJPZktleXMucmVkdWNlKFxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tcGFyYW0tcmVhc3NpZ24sbm8tcmV0dXJuLWFzc2lnblxuICAgICAgICAodG1wSGFzaCwga2V5KSA9PiAodG1wSGFzaCArPSBoYXNoU2V0W2tleUZpbHRlcihrZXkpXSwgdG1wSGFzaCksICcnXG4gICAgKTtcbiAgICBoYXNoLnVwZGF0ZShoYXNoZXNKb2luZWQpO1xuICAgIHJldHVybiBoYXNoLmRpZ2VzdCgnaGV4Jyk7XG59XG5cblxuLyoqXG4gKiBSZWFkcyBmaWxlcyBmcm9tIGRpc2sgYW5kIGNvbXB1dGVzIGhhc2hlcyBmb3IgdGhlbS5cbiAqIEBwYXJhbSB7QXJyYXl9IGZpbGVzIC0gYXJyYXkgd2l0aCBmaWxlIHBhdGhzXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fVxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVhZEFuZEhhc2hGaWxlcyhmaWxlcywgZmlsZUZpbHRlcikge1xuICAgIGNvbnN0IGZpbGVIYXNoZXMgPSB7fTtcbiAgICBjb25zdCBmaWxlQ29udGVudHMgPSB7fTtcbiAgICBjb25zdCBwcm9taXNlcyA9IFtdO1xuXG4gICAgZnVuY3Rpb24gcmVhZFNpbmdsZUZpbGUoZmlsZSkge1xuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgcmVhZEFuZEdldEZpbGVIYXNoKGZpbGUsIGZpbGUuZW5kc1dpdGgoJy5qcycpICYmICFmaWxlLmVuZHNXaXRoKCcudGVzdC5qcycpKVxuICAgICAgICAgICAgICAgIC50aGVuKChyZXN1bHQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGZpbGVOYW1lID0gZmlsZTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGZpbGVGaWx0ZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVOYW1lID0gZmlsZUZpbHRlcihmaWxlTmFtZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZmlsZUhhc2hlc1tmaWxlTmFtZV0gPSByZXN1bHQuaGFzaDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdC5jb250ZW50cykge1xuICAgICAgICAgICAgICAgICAgICAgICAgZmlsZUNvbnRlbnRzW2ZpbGVOYW1lXSA9IHJlc3VsdC5jb250ZW50cztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuY2F0Y2gocmVqZWN0KTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgZmlsZXMuZm9yRWFjaCgoZmlsZSkgPT4ge1xuICAgICAgICBwcm9taXNlcy5wdXNoKHJlYWRTaW5nbGVGaWxlKGZpbGUpKTtcbiAgICB9KTtcblxuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIFByb21pc2UuYWxsKHByb21pc2VzKVxuICAgICAgICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgIHJlc29sdmUoeyBmaWxlcywgZmlsZUNvbnRlbnRzLCBmaWxlSGFzaGVzIH0pO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5jYXRjaChyZWplY3QpO1xuICAgIH0pO1xufVxuXG4vKipcbiAqIFJlYWRzIGZpbGVzIGZyb20gLmRlc2t0b3AgYW5kIGNvbXB1dGVzIGEgdmVyc2lvbiBoYXNoLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXIgLSBwYXRoXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmaWxlRmlsdGVyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fVxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVhZEZpbGVzQW5kQ29tcHV0ZUhhc2goZGlyLCBmaWxlRmlsdGVyKSB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgZ2V0RmlsZUxpc3QoZGlyLCB0cnVlKVxuICAgICAgICAgICAgLmNhdGNoKHJlamVjdClcbiAgICAgICAgICAgIC50aGVuKGZpbGVzID0+IHJlYWRBbmRIYXNoRmlsZXMoZmlsZXMsIGZpbGVGaWx0ZXIpKVxuICAgICAgICAgICAgLmNhdGNoKHJlamVjdClcbiAgICAgICAgICAgIC50aGVuKChyZXN1bHQpID0+IHtcbiAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tcGFyYW0tcmVhc3NpZ25cbiAgICAgICAgICAgICAgICByZXN1bHQuaGFzaCA9IGNvbXB1dGVIYXNoRm9ySGFzaGVzU2V0KHJlc3VsdC5maWxlcywgcmVzdWx0LmZpbGVIYXNoZXMsIGZpbGVGaWx0ZXIpO1xuICAgICAgICAgICAgICAgIHJlc29sdmUocmVzdWx0KTtcbiAgICAgICAgICAgIH0pO1xuICAgIH0pO1xufVxuXG4vKipcbiAqIFN5bWxpbmsgZXhpc3RzXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aFRvQ2hlY2tcbiAqIEByZXR1cm5zIHtib29sZWFufVxuICovXG5leHBvcnQgZnVuY3Rpb24gc3ltbGlua0V4aXN0cyhwYXRoVG9DaGVjaykge1xuICAgIHRyeSB7XG4gICAgICAgIGZzLnJlYWRsaW5rU3luYyhwYXRoVG9DaGVjayk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn1cblxuXG5leHBvcnQgZGVmYXVsdCB7XG4gICAgZ2V0RmlsZUxpc3QsXG4gICAgcm1XaXRoUmV0cmllcyxcbiAgICBleGlzdHMsXG4gICAgcmVhZERpcixcbiAgICByZWFkQW5kR2V0RmlsZUhhc2gsXG4gICAgY29tcHV0ZUhhc2hGb3JIYXNoZXNTZXQsXG4gICAgcmVhZEFuZEhhc2hGaWxlcyxcbiAgICByZWFkRmlsZXNBbmRDb21wdXRlSGFzaCxcbiAgICBzeW1saW5rRXhpc3RzXG59O1xuIl19