@testim/testim-cli
Version:
Command line interface for running Testing on you CI
375 lines (295 loc) • 27.7 kB
JavaScript
;
var _createClass = require('babel-runtime/helpers/create-class')['default'];
var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default'];
var _getIterator = require('babel-runtime/core-js/get-iterator')['default'];
var _regeneratorRuntime = require('babel-runtime/regenerator')['default'];
var _Promise = require('babel-runtime/core-js/promise')['default'];
var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];
Object.defineProperty(exports, '__esModule', {
value: true
});
var _child_process = require('child_process');
var _child_process2 = _interopRequireDefault(_child_process);
var _wdioDotReporter = require('wdio-dot-reporter');
var _wdioDotReporter2 = _interopRequireDefault(_wdioDotReporter);
var _utilsConfigParser = require('./utils/ConfigParser');
var _utilsConfigParser2 = _interopRequireDefault(_utilsConfigParser);
var _utilsBaseReporter = require('./utils/BaseReporter');
var _utilsBaseReporter2 = _interopRequireDefault(_utilsBaseReporter);
var Launcher = (function () {
function Launcher(configFile, argv) {
_classCallCheck(this, Launcher);
this.configParser = new _utilsConfigParser2['default']();
this.configParser.addConfigFile(configFile);
this.configParser.merge(argv);
this.reporter = this.initReporter();
this.argv = argv;
this.configFile = configFile;
this.exitCode = 0;
this.hasTriggeredExitRoutine = false;
this.hasStartedAnyProcess = false;
this.processes = [];
this.schedule = [];
}
/**
* check if multiremote or wdio test
*/
_createClass(Launcher, [{
key: 'isMultiremote',
value: function isMultiremote() {
var caps = this.configParser.getCapabilities();
return !Array.isArray(caps);
}
/**
* initialise reporter
*/
}, {
key: 'initReporter',
value: function initReporter() {
var reporter = new _utilsBaseReporter2['default']();
var config = this.configParser.getConfig();
/**
* if no reporter is set or config property is in a wrong format
* just use the dot reporter
*/
if (!config.reporter || !Array.isArray(config.reporter)) {
reporter.add(new _wdioDotReporter2['default'](reporter));
return reporter;
}
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = _getIterator(config.reporter), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var _reporter = _step.value;
try {
var Reporter = require('wdio-' + _reporter + '-reporter');
_reporter.add(new Reporter(_reporter));
} catch (e) {
throw new Error('reporter "wdio-' + _reporter + '-reporter" is not installed');
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return reporter;
}
/**
* run sequence
* @return {Promise} that only gets resolves with either an exitCode or an error
*/
}, {
key: 'run',
value: function run() {
var config, caps, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, capabilities, exitCode;
return _regeneratorRuntime.async(function run$(context$2$0) {
var _this = this;
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
config = this.configParser.getConfig();
caps = this.configParser.getCapabilities();
this.reporter.emit('start');
context$2$0.prev = 3;
context$2$0.next = 6;
return _regeneratorRuntime.awrap(config.onPrepare(config, caps));
case 6:
context$2$0.next = 11;
break;
case 8:
context$2$0.prev = 8;
context$2$0.t0 = context$2$0['catch'](3);
return context$2$0.abrupt('return', context$2$0.t0);
case 11:
if (!this.isMultiremote()) {
context$2$0.next = 13;
break;
}
return context$2$0.abrupt('return', this.startInstance(this.configParser.getSpecs(), caps));
case 13:
_iteratorNormalCompletion2 = true;
_didIteratorError2 = false;
_iteratorError2 = undefined;
context$2$0.prev = 16;
/**
* schedule test runs
*/
for (_iterator2 = _getIterator(caps); !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
capabilities = _step2.value;
this.schedule.push({
specs: this.configParser.getSpecs(capabilities.specs, capabilities.exclude),
availableInstances: capabilities.maxInstances || config.maxInstances || 1,
runningInstances: 0
});
}
/**
* catches ctrl+c event
*/
context$2$0.next = 24;
break;
case 20:
context$2$0.prev = 20;
context$2$0.t1 = context$2$0['catch'](16);
_didIteratorError2 = true;
_iteratorError2 = context$2$0.t1;
case 24:
context$2$0.prev = 24;
context$2$0.prev = 25;
if (!_iteratorNormalCompletion2 && _iterator2['return']) {
_iterator2['return']();
}
case 27:
context$2$0.prev = 27;
if (!_didIteratorError2) {
context$2$0.next = 30;
break;
}
throw _iteratorError2;
case 30:
return context$2$0.finish(27);
case 31:
return context$2$0.finish(24);
case 32:
process.on('SIGINT', this.exitHandler.bind(this));
/**
* make sure the program will not close instantly
*/
process.stdin.resume();
context$2$0.next = 36;
return _regeneratorRuntime.awrap(new _Promise(function (resolve, reject) {
_this.resolve = resolve;
_this.runSpecs();
}));
case 36:
exitCode = context$2$0.sent;
context$2$0.prev = 37;
context$2$0.next = 40;
return _regeneratorRuntime.awrap(config.onComplete(exitCode));
case 40:
context$2$0.next = 45;
break;
case 42:
context$2$0.prev = 42;
context$2$0.t2 = context$2$0['catch'](37);
return context$2$0.abrupt('return', context$2$0.t2);
case 45:
return context$2$0.abrupt('return', exitCode);
case 46:
case 'end':
return context$2$0.stop();
}
}, null, this, [[3, 8], [16, 20, 24, 32], [25,, 27, 31], [37, 42]]);
}
/**
* run multiple single remote tests
*/
}, {
key: 'runSpecs',
value: function runSpecs() {
var _this2 = this;
var specsLeft = 0;
var isRunning = false;
this.schedule.forEach(function (capability, cid) {
var specFiles = capability.specs.length;
specsLeft += specFiles;
for (var i = 0; i < capability.availableInstances && i < specFiles; i++) {
_this2.startInstance([capability.specs.pop()], cid);
capability.availableInstances--;
capability.runningInstances++;
}
isRunning = isRunning || capability.runningInstances > 0;
});
return specsLeft === 0 && !isRunning;
}
/**
* Start instance in a child process.
* @param {Object|Object[]} capabilities desired capabilities of instance
*/
}, {
key: 'startInstance',
value: function startInstance(specs, i) {
var childProcess = _child_process2['default'].fork(__dirname + '/runner.js', [], {
cwd: process.cwd()
});
this.processes.push(childProcess);
childProcess.on('message', this.messageHandler.bind(this)).on('exit', this.endHandler.bind(this));
childProcess.send({
cid: i,
command: 'run',
configFile: this.configFile,
argv: this.argv,
specs: specs,
isMultiremote: this.isMultiremote()
});
}
/**
* emit event from child process to reporter
* @param {Object} m event object
*/
}, {
key: 'messageHandler',
value: function messageHandler(m) {
this.hasStartedAnyProcess = true;
/**
* update schedule
*/
if (m.event === 'runner:end' || m.event === 'runner:error') {
this.schedule[m.cid].availableInstances++;
this.schedule[m.cid].runningInstances--;
}
if (m.event === 'runner:error') {
this.reporter.emit('error', m);
}
this.reporter.emit(m.event, m);
}
/**
* Closes test runner process once all instances finished and excited process.
* @param {Number} childProcessExitCode exit code of child process
*/
}, {
key: 'endHandler',
value: function endHandler(childProcessExitCode) {
this.exitCode = this.exitCode || childProcessExitCode;
if (!this.isMultiremote() && !this.runSpecs()) {
return;
}
this.reporter.emit('end', {
sigint: this.hasTriggeredExitRoutine,
exitCode: this.exitCode
});
this.resolve(this.exitCode);
}
/**
* Make sure all started selenium sessions get closed properly and prevent
* having dead driver processes. To do so let the runner end its Selenium
* session first before killing
*/
}, {
key: 'exitHandler',
value: function exitHandler() {
if (this.hasTriggeredExitRoutine || !this.hasStartedAnyProcess) {
console.log('\nKilling process, bye!');
return this.resolve(1);
}
console.log('\n\nEnd selenium sessions properly ...\n(press crtl+c again to hard kill the runner)\n');
this.hasTriggeredExitRoutine = true;
}
}]);
return Launcher;
})();
exports['default'] = Launcher;
module.exports = exports['default'];
/**
* if it is an object run multiremote test
*/
//# sourceMappingURL=data:application/json;base64,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QUFDLElBQUksQ0FBQyxvQkFBb0IsRUFBRTtBQUM1RCx1QkFBTyxDQUFDLEdBQUcsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFBO0FBQ3RDLHVCQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUE7YUFDekI7O0FBRUQsbUJBQU8sQ0FBQyxHQUFHLDBGQUlqQixDQUFBOztBQUVNLGdCQUFJLENBQUMsdUJBQXVCLEdBQUcsSUFBSSxDQUFBO1NBQ3RDOzs7V0F4TkMsUUFBUTs7O3FCQTJOQyxRQUFRIiwiZmlsZSI6ImxhdW5jaGVyLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNoaWxkIGZyb20gJ2NoaWxkX3Byb2Nlc3MnXG5pbXBvcnQgRG90UmVwb3J0ZXIgZnJvbSAnd2Rpby1kb3QtcmVwb3J0ZXInXG5cbmltcG9ydCBDb25maWdQYXJzZXIgZnJvbSAnLi91dGlscy9Db25maWdQYXJzZXInXG5pbXBvcnQgQmFzZVJlcG9ydGVyIGZyb20gJy4vdXRpbHMvQmFzZVJlcG9ydGVyJ1xuXG5cbmNsYXNzIExhdW5jaGVyIHtcbiAgICBjb25zdHJ1Y3RvciAoY29uZmlnRmlsZSwgYXJndikge1xuICAgICAgICB0aGlzLmNvbmZpZ1BhcnNlciA9IG5ldyBDb25maWdQYXJzZXIoKVxuICAgICAgICB0aGlzLmNvbmZpZ1BhcnNlci5hZGRDb25maWdGaWxlKGNvbmZpZ0ZpbGUpXG4gICAgICAgIHRoaXMuY29uZmlnUGFyc2VyLm1lcmdlKGFyZ3YpXG5cbiAgICAgICAgdGhpcy5yZXBvcnRlciA9IHRoaXMuaW5pdFJlcG9ydGVyKClcblxuICAgICAgICB0aGlzLmFyZ3YgPSBhcmd2XG4gICAgICAgIHRoaXMuY29uZmlnRmlsZSA9IGNvbmZpZ0ZpbGVcblxuICAgICAgICB0aGlzLmV4aXRDb2RlID0gMFxuICAgICAgICB0aGlzLmhhc1RyaWdnZXJlZEV4aXRSb3V0aW5lID0gZmFsc2VcbiAgICAgICAgdGhpcy5oYXNTdGFydGVkQW55UHJvY2VzcyA9IGZhbHNlXG4gICAgICAgIHRoaXMucHJvY2Vzc2VzID0gW11cbiAgICAgICAgdGhpcy5zY2hlZHVsZSA9IFtdXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogY2hlY2sgaWYgbXVsdGlyZW1vdGUgb3Igd2RpbyB0ZXN0XG4gICAgICovXG4gICAgaXNNdWx0aXJlbW90ZSAoKSB7XG4gICAgICAgIGxldCBjYXBzID0gdGhpcy5jb25maWdQYXJzZXIuZ2V0Q2FwYWJpbGl0aWVzKClcbiAgICAgICAgcmV0dXJuICFBcnJheS5pc0FycmF5KGNhcHMpXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogaW5pdGlhbGlzZSByZXBvcnRlclxuICAgICAqL1xuICAgIGluaXRSZXBvcnRlciAoKSB7XG4gICAgICAgIGxldCByZXBvcnRlciA9IG5ldyBCYXNlUmVwb3J0ZXIoKVxuICAgICAgICBsZXQgY29uZmlnID0gdGhpcy5jb25maWdQYXJzZXIuZ2V0Q29uZmlnKClcblxuICAgICAgICAvKipcbiAgICAgICAgICogaWYgbm8gcmVwb3J0ZXIgaXMgc2V0IG9yIGNvbmZpZyBwcm9wZXJ0eSBpcyBpbiBhIHdyb25nIGZvcm1hdFxuICAgICAgICAgKiBqdXN0IHVzZSB0aGUgZG90IHJlcG9ydGVyXG4gICAgICAgICAqL1xuICAgICAgICBpZiAoIWNvbmZpZy5yZXBvcnRlciB8fCAhQXJyYXkuaXNBcnJheShjb25maWcucmVwb3J0ZXIpKSB7XG4gICAgICAgICAgICByZXBvcnRlci5hZGQobmV3IERvdFJlcG9ydGVyKHJlcG9ydGVyKSlcbiAgICAgICAgICAgIHJldHVybiByZXBvcnRlclxuICAgICAgICB9XG5cbiAgICAgICAgZm9yIChsZXQgcmVwb3J0ZXIgb2YgY29uZmlnLnJlcG9ydGVyKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGxldCBSZXBvcnRlciA9IHJlcXVpcmUoYHdkaW8tJHtyZXBvcnRlcn0tcmVwb3J0ZXJgKVxuICAgICAgICAgICAgICAgIHJlcG9ydGVyLmFkZChuZXcgUmVwb3J0ZXIocmVwb3J0ZXIpKVxuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgcmVwb3J0ZXIgXCJ3ZGlvLSR7cmVwb3J0ZXJ9LXJlcG9ydGVyXCIgaXMgbm90IGluc3RhbGxlZGApXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVwb3J0ZXJcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBydW4gc2VxdWVuY2VcbiAgICAgKiBAcmV0dXJuICB7UHJvbWlzZX0gdGhhdCBvbmx5IGdldHMgcmVzb2x2ZXMgd2l0aCBlaXRoZXIgYW4gZXhpdENvZGUgb3IgYW4gZXJyb3JcbiAgICAgKi9cbiAgICBhc3luYyBydW4gKCkge1xuICAgICAgICBsZXQgY29uZmlnID0gdGhpcy5jb25maWdQYXJzZXIuZ2V0Q29uZmlnKClcbiAgICAgICAgbGV0IGNhcHMgPSB0aGlzLmNvbmZpZ1BhcnNlci5nZXRDYXBhYmlsaXRpZXMoKVxuXG4gICAgICAgIHRoaXMucmVwb3J0ZXIuZW1pdCgnc3RhcnQnKVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgY29uZmlnLm9uUHJlcGFyZShjb25maWcsIGNhcHMpXG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHJldHVybiBlXG4gICAgICAgIH1cblxuICAgICAgICAvKipcbiAgICAgICAgICogaWYgaXQgaXMgYW4gb2JqZWN0IHJ1biBtdWx0aXJlbW90ZSB0ZXN0XG4gICAgICAgICAqL1xuICAgICAgICBpZiAodGhpcy5pc011bHRpcmVtb3RlKCkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnN0YXJ0SW5zdGFuY2UodGhpcy5jb25maWdQYXJzZXIuZ2V0U3BlY3MoKSwgY2FwcylcbiAgICAgICAgfVxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBzY2hlZHVsZSB0ZXN0IHJ1bnNcbiAgICAgICAgICovXG4gICAgICAgIGZvciAobGV0IGNhcGFiaWxpdGllcyBvZiBjYXBzKSB7XG4gICAgICAgICAgICB0aGlzLnNjaGVkdWxlLnB1c2goe1xuICAgICAgICAgICAgICAgIHNwZWNzOiB0aGlzLmNvbmZpZ1BhcnNlci5nZXRTcGVjcyhjYXBhYmlsaXRpZXMuc3BlY3MsIGNhcGFiaWxpdGllcy5leGNsdWRlKSxcbiAgICAgICAgICAgICAgICBhdmFpbGFibGVJbnN0YW5jZXM6IGNhcGFiaWxpdGllcy5tYXhJbnN0YW5jZXMgfHwgY29uZmlnLm1heEluc3RhbmNlcyB8fCAxLFxuICAgICAgICAgICAgICAgIHJ1bm5pbmdJbnN0YW5jZXM6IDBcbiAgICAgICAgICAgIH0pXG4gICAgICAgIH1cblxuICAgICAgICAvKipcbiAgICAgICAgICogY2F0Y2hlcyBjdHJsK2MgZXZlbnRcbiAgICAgICAgICovXG4gICAgICAgIHByb2Nlc3Mub24oJ1NJR0lOVCcsIHRoaXMuZXhpdEhhbmRsZXIuYmluZCh0aGlzKSlcblxuICAgICAgICAvKipcbiAgICAgICAgICogbWFrZSBzdXJlIHRoZSBwcm9ncmFtIHdpbGwgbm90IGNsb3NlIGluc3RhbnRseVxuICAgICAgICAgKi9cbiAgICAgICAgcHJvY2Vzcy5zdGRpbi5yZXN1bWUoKVxuXG4gICAgICAgIGxldCBleGl0Q29kZSA9IGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIHRoaXMucmVzb2x2ZSA9IHJlc29sdmVcbiAgICAgICAgICAgIHRoaXMucnVuU3BlY3MoKVxuICAgICAgICB9KVxuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBjb25maWcub25Db21wbGV0ZShleGl0Q29kZSlcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgcmV0dXJuIGVcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZXhpdENvZGVcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBydW4gbXVsdGlwbGUgc2luZ2xlIHJlbW90ZSB0ZXN0c1xuICAgICAqL1xuICAgIHJ1blNwZWNzICgpIHtcbiAgICAgICAgbGV0IHNwZWNzTGVmdCA9IDBcbiAgICAgICAgbGV0IGlzUnVubmluZyA9IGZhbHNlXG5cbiAgICAgICAgdGhpcy5zY2hlZHVsZS5mb3JFYWNoKChjYXBhYmlsaXR5LCBjaWQpID0+IHtcbiAgICAgICAgICAgIGxldCBzcGVjRmlsZXMgPSBjYXBhYmlsaXR5LnNwZWNzLmxlbmd0aFxuICAgICAgICAgICAgc3BlY3NMZWZ0ICs9IHNwZWNGaWxlc1xuXG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNhcGFiaWxpdHkuYXZhaWxhYmxlSW5zdGFuY2VzICYmIGkgPCBzcGVjRmlsZXM7IGkrKykge1xuICAgICAgICAgICAgICAgIHRoaXMuc3RhcnRJbnN0YW5jZShbY2FwYWJpbGl0eS5zcGVjcy5wb3AoKV0sIGNpZClcbiAgICAgICAgICAgICAgICBjYXBhYmlsaXR5LmF2YWlsYWJsZUluc3RhbmNlcy0tXG4gICAgICAgICAgICAgICAgY2FwYWJpbGl0eS5ydW5uaW5nSW5zdGFuY2VzKytcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlzUnVubmluZyA9IGlzUnVubmluZyB8fCBjYXBhYmlsaXR5LnJ1bm5pbmdJbnN0YW5jZXMgPiAwXG4gICAgICAgIH0pXG5cbiAgICAgICAgcmV0dXJuIHNwZWNzTGVmdCA9PT0gMCAmJiAhaXNSdW5uaW5nXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU3RhcnQgaW5zdGFuY2UgaW4gYSBjaGlsZCBwcm9jZXNzLlxuICAgICAqIEBwYXJhbSAge09iamVjdHxPYmplY3RbXX0gY2FwYWJpbGl0aWVzICBkZXNpcmVkIGNhcGFiaWxpdGllcyBvZiBpbnN0YW5jZVxuICAgICAqL1xuICAgIHN0YXJ0SW5zdGFuY2UgKHNwZWNzLCBpKSB7XG4gICAgICAgIGxldCBjaGlsZFByb2Nlc3MgPSBjaGlsZC5mb3JrKF9fZGlybmFtZSArICcvcnVubmVyLmpzJywgW10sIHtcbiAgICAgICAgICAgIGN3ZDogcHJvY2Vzcy5jd2QoKVxuICAgICAgICB9KVxuXG4gICAgICAgIHRoaXMucHJvY2Vzc2VzLnB1c2goY2hpbGRQcm9jZXNzKVxuXG4gICAgICAgIGNoaWxkUHJvY2Vzc1xuICAgICAgICAgICAgLm9uKCdtZXNzYWdlJywgdGhpcy5tZXNzYWdlSGFuZGxlci5iaW5kKHRoaXMpKVxuICAgICAgICAgICAgLm9uKCdleGl0JywgdGhpcy5lbmRIYW5kbGVyLmJpbmQodGhpcykpXG5cbiAgICAgICAgY2hpbGRQcm9jZXNzLnNlbmQoe1xuICAgICAgICAgICAgY2lkOiBpLFxuICAgICAgICAgICAgY29tbWFuZDogJ3J1bicsXG4gICAgICAgICAgICBjb25maWdGaWxlOiB0aGlzLmNvbmZpZ0ZpbGUsXG4gICAgICAgICAgICBhcmd2OiB0aGlzLmFyZ3YsXG4gICAgICAgICAgICBzcGVjczogc3BlY3MsXG4gICAgICAgICAgICBpc011bHRpcmVtb3RlOiB0aGlzLmlzTXVsdGlyZW1vdGUoKVxuICAgICAgICB9KVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIGVtaXQgZXZlbnQgZnJvbSBjaGlsZCBwcm9jZXNzIHRvIHJlcG9ydGVyXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSBtICBldmVudCBvYmplY3RcbiAgICAgKi9cbiAgICBtZXNzYWdlSGFuZGxlciAobSkge1xuICAgICAgICB0aGlzLmhhc1N0YXJ0ZWRBbnlQcm9jZXNzID0gdHJ1ZVxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiB1cGRhdGUgc2NoZWR1bGVcbiAgICAgICAgICovXG4gICAgICAgIGlmIChtLmV2ZW50ID09PSAncnVubmVyOmVuZCcgfHwgbS5ldmVudCA9PT0gJ3J1bm5lcjplcnJvcicpIHtcbiAgICAgICAgICAgIHRoaXMuc2NoZWR1bGVbbS5jaWRdLmF2YWlsYWJsZUluc3RhbmNlcysrXG4gICAgICAgICAgICB0aGlzLnNjaGVkdWxlW20uY2lkXS5ydW5uaW5nSW5zdGFuY2VzLS1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChtLmV2ZW50ID09PSAncnVubmVyOmVycm9yJykge1xuICAgICAgICAgICAgdGhpcy5yZXBvcnRlci5lbWl0KCdlcnJvcicsIG0pXG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnJlcG9ydGVyLmVtaXQobS5ldmVudCwgbSlcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDbG9zZXMgdGVzdCBydW5uZXIgcHJvY2VzcyBvbmNlIGFsbCBpbnN0YW5jZXMgZmluaXNoZWQgYW5kIGV4Y2l0ZWQgcHJvY2Vzcy5cbiAgICAgKiBAcGFyYW0gIHtOdW1iZXJ9IGNoaWxkUHJvY2Vzc0V4aXRDb2RlICBleGl0IGNvZGUgb2YgY2hpbGQgcHJvY2Vzc1xuICAgICAqL1xuICAgIGVuZEhhbmRsZXIgKGNoaWxkUHJvY2Vzc0V4aXRDb2RlKSB7XG4gICAgICAgIHRoaXMuZXhpdENvZGUgPSB0aGlzLmV4aXRDb2RlIHx8IGNoaWxkUHJvY2Vzc0V4aXRDb2RlXG5cbiAgICAgICAgaWYgKCF0aGlzLmlzTXVsdGlyZW1vdGUoKSAmJiAhdGhpcy5ydW5TcGVjcygpKSB7XG4gICAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucmVwb3J0ZXIuZW1pdCgnZW5kJywge1xuICAgICAgICAgICAgc2lnaW50OiB0aGlzLmhhc1RyaWdnZXJlZEV4aXRSb3V0aW5lLFxuICAgICAgICAgICAgZXhpdENvZGU6IHRoaXMuZXhpdENvZGVcbiAgICAgICAgfSlcblxuICAgICAgICB0aGlzLnJlc29sdmUodGhpcy5leGl0Q29kZSlcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBNYWtlIHN1cmUgYWxsIHN0YXJ0ZWQgc2VsZW5pdW0gc2Vzc2lvbnMgZ2V0IGNsb3NlZCBwcm9wZXJseSBhbmQgcHJldmVudFxuICAgICAqIGhhdmluZyBkZWFkIGRyaXZlciBwcm9jZXNzZXMuIFRvIGRvIHNvIGxldCB0aGUgcnVubmVyIGVuZCBpdHMgU2VsZW5pdW1cbiAgICAgKiBzZXNzaW9uIGZpcnN0IGJlZm9yZSBraWxsaW5nXG4gICAgICovXG4gICAgZXhpdEhhbmRsZXIgKCkge1xuICAgICAgICBpZiAodGhpcy5oYXNUcmlnZ2VyZWRFeGl0Um91dGluZSB8fCAhdGhpcy5oYXNTdGFydGVkQW55UHJvY2Vzcykge1xuICAgICAgICAgICAgY29uc29sZS5sb2coJ1xcbktpbGxpbmcgcHJvY2VzcywgYnllIScpXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNvbHZlKDEpXG4gICAgICAgIH1cblxuICAgICAgICBjb25zb2xlLmxvZyhgXG5cbkVuZCBzZWxlbml1bSBzZXNzaW9ucyBwcm9wZXJseSAuLi5cbihwcmVzcyBjcnRsK2MgYWdhaW4gdG8gaGFyZCBraWxsIHRoZSBydW5uZXIpXG5gKVxuXG4gICAgICAgIHRoaXMuaGFzVHJpZ2dlcmVkRXhpdFJvdXRpbmUgPSB0cnVlXG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBMYXVuY2hlclxuIl19