@testim/testim-cli
Version:
Command line interface for running Testing on you CI
499 lines (417 loc) • 39.5 kB
JavaScript
;
var _get = require('babel-runtime/helpers/get')['default'];
var _inherits = require('babel-runtime/helpers/inherits')['default'];
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 _Object$keys = require('babel-runtime/core-js/object/keys')['default'];
var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];
Object.defineProperty(exports, '__esModule', {
value: true
});
var _tty = require('tty');
var _tty2 = _interopRequireDefault(_tty);
var _events = require('events');
var _events2 = _interopRequireDefault(_events);
var _supportsColor = require('supports-color');
var _supportsColor2 = _interopRequireDefault(_supportsColor);
var ISATTY = _tty2['default'].isatty(1) && _tty2['default'].isatty(2);
var COLORS = {
'pass': 90,
'fail': 31,
'bright pass': 92,
'bright fail': 91,
'bright yellow': 93,
'pending': 36,
'suite': 0,
'error title': 0,
'error message': 31,
'error stack': 90,
'checkmark': 32,
'fast': 90,
'medium': 33,
'slow': 31,
'green': 32,
'light': 90,
'diff gutter': 90,
'diff added': 32,
'diff removed': 31
};
var SYMBOLS_WIN = {
ok: '√',
err: '×',
dot: '.',
error: 'F'
};
var SYMBOLS = {
ok: '✓',
err: '✖',
dot: '․',
error: 'F'
};
var BaseReporter = (function (_events$EventEmitter) {
_inherits(BaseReporter, _events$EventEmitter);
function BaseReporter() {
var _this = this;
_classCallCheck(this, BaseReporter);
_get(Object.getPrototypeOf(BaseReporter.prototype), 'constructor', this).call(this);
this.stats = {
suites: 0,
tests: 0,
passes: 0,
pending: 0,
failures: 0,
runner: {}
};
this.failures = [];
this.reporters = [];
this.printEpilogue = true;
this.cursor = new Cursor();
this.on('start', function () {
_this.stats.start = new Date();
_this.propagateEvent('start');
});
this.on('runner:start', function (runner) {
if (!_this.stats.runner[runner.cid]) {
_this.stats.runner[runner.cid] = {
start: new Date(),
capabilities: runner.capabilities,
config: runner.config,
tests: []
};
}
_this.propagateEvent('runner:start', runner);
});
this.on('runner:init', function (runner) {
_this.stats.runner[runner.cid].sessionID = runner.sessionID;
_this.propagateEvent('runner:init', runner);
});
this.on('suite:start', function (suite) {
suite.root || _this.stats.suites++;
_this.propagateEvent('suite:start', suite);
});
this.on('suite:end', function (suite) {
_this.propagateEvent('suite:end', suite);
});
this.on('test:end', function (test) {
_this.stats.tests++;
_this.propagateEvent('test:end', test);
});
this.on('test:pass', function (test) {
_this.stats.runner[test.cid].tests.push(null);
_this.stats.passes++;
_this.propagateEvent('test:pass', test);
});
this.on('test:fail', function (test) {
_this.stats.failures++;
_this.stats.runner[test.cid].tests.push(test.err);
/**
* check if error also happened in other runners
*/
var duplicateError = false;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = _getIterator(_this.failures), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var failure = _step.value;
if (test.err.message !== failure.err.message || failure.title !== test.title) {
continue;
}
duplicateError = true;
failure.runner[test.cid] = test.runner[test.cid];
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
if (!duplicateError) {
_this.failures.push(test);
}
_this.propagateEvent('test:fail', test);
});
this.on('test:pending', function (test) {
_this.stats.pending++;
_this.propagateEvent('test:pending', test);
});
this.on('runner:end', function (runner) {
_this.stats.runner[runner.cid].end = new Date();
_this.propagateEvent('runner:end', runner);
});
this.on('end', function (args) {
_this.stats.end = new Date();
_this.stats.duration = new Date() - _this.stats.start;
_this.printEpilogue = _this.printEpilogue && !args.sigint;
_this.propagateEvent('end', args);
});
this.on('error', function (m) {
_this.printEpilogue = false;
var fmt = _this.color('error message', 'ERROR: %s');
console.log(fmt, m.error.message);
var sanitizedCaps = [];
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = _getIterator(_Object$keys(m.capabilities)), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var capability = _step2.value;
/**
* we don't need all capability types to recognise a vm
*/
if (['browserName', 'platform', 'version', 'platformVersion', 'deviceName', 'app'].indexOf(capability) === -1) {
continue;
}
sanitizedCaps.push(capability + ': ' + JSON.stringify(m.capabilities[capability]));
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2['return']) {
_iterator2['return']();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
fmt = _this.color('bright yellow', sanitizedCaps.join(', '));
console.log(fmt);
if (m.error.stack) {
fmt = _this.color('error stack', m.error.stack.replace('Error: ' + m.error.message + '\n', ''));
} else {
fmt = _this.color('error stack', ' no stack available');
}
console.log(fmt);
_this.propagateEvent('error', m);
});
}
/**
* Expose some basic cursor interactions
* that are common among reporters.
*/
/**
* Color `str` with the given `type`,
* allowing colors to be disabled,
* as well as user-defined color
* schemes.
*
* @param {String} type
* @param {String} str
* @return {String}
* @api private
*/
_createClass(BaseReporter, [{
key: 'color',
value: function color(type, str) {
if (!_supportsColor2['default']) return String(str);
return '\u001b[' + COLORS[type] + 'm' + str + '\u001b[0m';
}
/**
* Output common epilogue used by many of
* the bundled reporters.
*
* @api public
*/
}, {
key: 'epilogue',
value: function epilogue() {
var fmt = null;
if (!this.printEpilogue) {
return;
}
console.log('\n');
// passes
fmt = this.color('green', '%d passing') + this.color('light', ' (%ss)');
console.log(fmt, this.stats.passes || 0, (Math.round(this.stats.duration / 100) / 10).toFixed(2));
// pending
if (this.stats.pending) {
fmt = this.color('pending', '%d pending');
console.log(fmt, this.stats.pending);
}
// failures
if (this.stats.failures) {
fmt = this.color('fail', '%d failing');
console.log(fmt, this.stats.failures);
this.listFailures();
}
console.log();
}
/**
* Outut the given failures as a list
*/
}, {
key: 'listFailures',
value: function listFailures() {
var _this2 = this;
console.log();
this.failures.forEach(function (test, i) {
var runningBrowser = '';
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = _getIterator(_Object$keys(test.runner)), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var pid = _step3.value;
var caps = test.runner[pid];
runningBrowser += '\nrunning';
if (caps.browserName) {
runningBrowser += ' ' + caps.browserName;
}
if (caps.version) {
runningBrowser += ' (v' + caps.version + ')';
}
if (caps.platform) {
runningBrowser += ' on ' + caps.platform;
}
var host = _this2.stats.runner[pid].config.host;
if (host && host.indexOf('saucelabs') > -1) {
runningBrowser += '\nCheck out job at https://saucelabs.com/tests/' + _this2.stats.runner[pid].sessionID;
}
}
// format
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3['return']) {
_iterator3['return']();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
var fmt = _this2.color('error title', '%s) %s:\n') + _this2.color('error message', '%s') + _this2.color('bright yellow', '%s') + _this2.color('error stack', '\n%s\n');
console.log(fmt, i + 1, test.title, test.err.message, runningBrowser, test.err.stack);
});
}
}, {
key: 'add',
value: function add(reporter) {
this.reporters.push(reporter);
}
}, {
key: 'propagateEvent',
value: function propagateEvent() {
if (this.reporters.length === 0) {
return;
}
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
for (var _iterator4 = _getIterator(this.reporters), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var reporter = _step4.value;
/**
* skip reporter if
* - he isn't an eventemitter
* - event is not registered
*/
if (typeof reporter.emit !== 'function' || _Object$keys(reporter._events).indexOf(args[0]) < 0) {
continue;
}
reporter.emit.apply(reporter, args);
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4['return']) {
_iterator4['return']();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
}
/**
* Default color map.
*/
}, {
key: 'colors',
get: function get() {
return COLORS;
}
/**
* Default symbol map.
*/
}, {
key: 'symbols',
get: function get() {
/**
* With node.js on Windows: use symbols available in terminal default fonts
*/
if (process.platform === 'win32') {
return SYMBOLS_WIN;
}
return SYMBOLS;
}
}]);
return BaseReporter;
})(_events2['default'].EventEmitter);
var Cursor = (function () {
function Cursor() {
_classCallCheck(this, Cursor);
}
_createClass(Cursor, [{
key: 'hide',
value: function hide() {
ISATTY && process.stdout.write('\u001b[?25l');
}
}, {
key: 'show',
value: function show() {
ISATTY && process.stdout.write('\u001b[?25h');
}
}, {
key: 'deleteLine',
value: function deleteLine() {
ISATTY && process.stdout.write('\u001b[2K');
}
}, {
key: 'beginningOfLine',
value: function beginningOfLine() {
ISATTY && process.stdout.write('\u001b[0G');
}
}, {
key: 'CR',
value: function CR() {
if (ISATTY) {
this.deleteLine();
this.beginningOfLine();
} else {
process.stdout.write('\r');
}
}
}, {
key: 'isatty',
get: function get() {
return ISATTY;
}
}]);
return Cursor;
})();
exports['default'] = BaseReporter;
exports.Cursor = Cursor;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2xpYi91dGlscy9CYXNlUmVwb3J0ZXIuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7bUJBQWdCLEtBQUs7Ozs7c0JBQ0YsUUFBUTs7Ozs2QkFDRCxnQkFBZ0I7Ozs7QUFFMUMsSUFBTSxNQUFNLEdBQUcsaUJBQUksTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLGlCQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQTs7QUFFN0MsSUFBTSxNQUFNLEdBQUc7QUFDWCxVQUFNLEVBQUUsRUFBRTtBQUNWLFVBQU0sRUFBRSxFQUFFO0FBQ1YsaUJBQWEsRUFBRSxFQUFFO0FBQ2pCLGlCQUFhLEVBQUUsRUFBRTtBQUNqQixtQkFBZSxFQUFFLEVBQUU7QUFDbkIsYUFBUyxFQUFFLEVBQUU7QUFDYixXQUFPLEVBQUUsQ0FBQztBQUNWLGlCQUFhLEVBQUUsQ0FBQztBQUNoQixtQkFBZSxFQUFFLEVBQUU7QUFDbkIsaUJBQWEsRUFBRSxFQUFFO0FBQ2pCLGVBQVcsRUFBRSxFQUFFO0FBQ2YsVUFBTSxFQUFFLEVBQUU7QUFDVixZQUFRLEVBQUUsRUFBRTtBQUNaLFVBQU0sRUFBRSxFQUFFO0FBQ1YsV0FBTyxFQUFFLEVBQUU7QUFDWCxXQUFPLEVBQUUsRUFBRTtBQUNYLGlCQUFhLEVBQUUsRUFBRTtBQUNqQixnQkFBWSxFQUFFLEVBQUU7QUFDaEIsa0JBQWMsRUFBRSxFQUFFO0NBQ3JCLENBQUE7O0FBRUQsSUFBTSxXQUFXLEdBQUc7QUFDaEIsTUFBRSxFQUFFLEdBQVE7QUFDWixPQUFHLEVBQUUsR0FBUTtBQUNiLE9BQUcsRUFBRSxHQUFHO0FBQ1IsU0FBSyxFQUFFLEdBQUc7Q0FDYixDQUFBOztBQUVELElBQU0sT0FBTyxHQUFHO0FBQ1osTUFBRSxFQUFFLEdBQUc7QUFDUCxPQUFHLEVBQUUsR0FBRztBQUNSLE9BQUcsRUFBRSxHQUFHO0FBQ1IsU0FBSyxFQUFFLEdBQUc7Q0FDYixDQUFBOztJQUVLLFlBQVk7Y0FB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QUFHO0FBQ0osa0JBQU0sSUFBSSxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQTtTQUNoRDs7O2VBRVUsc0JBQUc7QUFDVixrQkFBTSxJQUFJLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFBO1NBQzlDOzs7ZUFFZSwyQkFBRztBQUNmLGtCQUFNLElBQUksT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUE7U0FDOUM7OztlQUVFLGNBQUc7QUFDRixnQkFBSSxNQUFNLEVBQUU7QUFDUixvQkFBSSxDQUFDLFVBQVUsRUFBRSxDQUFBO0FBQ2pCLG9CQUFJLENBQUMsZUFBZSxFQUFFLENBQUE7YUFDekIsTUFBTTtBQUNILHVCQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQTthQUM3QjtTQUNKOzs7YUFFVSxlQUFHO0FBQ1YsbUJBQU8sTUFBTSxDQUFBO1NBQ2hCOzs7V0E1QkMsTUFBTTs7O3FCQStCRyxZQUFZO1FBQ2xCLE1BQU0sR0FBTixNQUFNIiwiZmlsZSI6IkJhc2VSZXBvcnRlci5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0dHkgZnJvbSAndHR5J1xuaW1wb3J0IGV2ZW50cyBmcm9tICdldmVudHMnXG5pbXBvcnQgc3VwcG9ydHNDb2xvciBmcm9tICdzdXBwb3J0cy1jb2xvcidcblxuY29uc3QgSVNBVFRZID0gdHR5LmlzYXR0eSgxKSAmJiB0dHkuaXNhdHR5KDIpXG5cbmNvbnN0IENPTE9SUyA9IHtcbiAgICAncGFzcyc6IDkwLFxuICAgICdmYWlsJzogMzEsXG4gICAgJ2JyaWdodCBwYXNzJzogOTIsXG4gICAgJ2JyaWdodCBmYWlsJzogOTEsXG4gICAgJ2JyaWdodCB5ZWxsb3cnOiA5MyxcbiAgICAncGVuZGluZyc6IDM2LFxuICAgICdzdWl0ZSc6IDAsXG4gICAgJ2Vycm9yIHRpdGxlJzogMCxcbiAgICAnZXJyb3IgbWVzc2FnZSc6IDMxLFxuICAgICdlcnJvciBzdGFjayc6IDkwLFxuICAgICdjaGVja21hcmsnOiAzMixcbiAgICAnZmFzdCc6IDkwLFxuICAgICdtZWRpdW0nOiAzMyxcbiAgICAnc2xvdyc6IDMxLFxuICAgICdncmVlbic6IDMyLFxuICAgICdsaWdodCc6IDkwLFxuICAgICdkaWZmIGd1dHRlcic6IDkwLFxuICAgICdkaWZmIGFkZGVkJzogMzIsXG4gICAgJ2RpZmYgcmVtb3ZlZCc6IDMxXG59XG5cbmNvbnN0IFNZTUJPTFNfV0lOID0ge1xuICAgIG9rOiAnXFx1MjIxQScsXG4gICAgZXJyOiAnXFx1MDBENycsXG4gICAgZG90OiAnLicsXG4gICAgZXJyb3I6ICdGJ1xufVxuXG5jb25zdCBTWU1CT0xTID0ge1xuICAgIG9rOiAn4pyTJyxcbiAgICBlcnI6ICfinJYnLFxuICAgIGRvdDogJ+KApCcsXG4gICAgZXJyb3I6ICdGJ1xufVxuXG5jbGFzcyBCYXNlUmVwb3J0ZXIgZXh0ZW5kcyBldmVudHMuRXZlbnRFbWl0dGVyIHtcbiAgICBjb25zdHJ1Y3RvciAoKSB7XG4gICAgICAgIHN1cGVyKClcblxuICAgICAgICB0aGlzLnN0YXRzID0ge1xuICAgICAgICAgICAgc3VpdGVzOiAwLFxuICAgICAgICAgICAgdGVzdHM6IDAsXG4gICAgICAgICAgICBwYXNzZXM6IDAsXG4gICAgICAgICAgICBwZW5kaW5nOiAwLFxuICAgICAgICAgICAgZmFpbHVyZXM6IDAsXG4gICAgICAgICAgICBydW5uZXI6IHt9XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5mYWlsdXJlcyA9IFtdXG4gICAgICAgIHRoaXMucmVwb3J0ZXJzID0gW11cbiAgICAgICAgdGhpcy5wcmludEVwaWxvZ3VlID0gdHJ1ZVxuICAgICAgICB0aGlzLmN1cnNvciA9IG5ldyBDdXJzb3IoKVxuXG4gICAgICAgIHRoaXMub24oJ3N0YXJ0JywgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zdGF0cy5zdGFydCA9IG5ldyBEYXRlKClcbiAgICAgICAgICAgIHRoaXMucHJvcGFnYXRlRXZlbnQoJ3N0YXJ0JylcbiAgICAgICAgfSlcblxuICAgICAgICB0aGlzLm9uKCdydW5uZXI6c3RhcnQnLCAocnVubmVyKSA9PiB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuc3RhdHMucnVubmVyW3J1bm5lci5jaWRdKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zdGF0cy5ydW5uZXJbcnVubmVyLmNpZF0gPSB7XG4gICAgICAgICAgICAgICAgICAgIHN0YXJ0OiBuZXcgRGF0ZSgpLFxuICAgICAgICAgICAgICAgICAgICBjYXBhYmlsaXRpZXM6IHJ1bm5lci5jYXBhYmlsaXRpZXMsXG4gICAgICAgICAgICAgICAgICAgIGNvbmZpZzogcnVubmVyLmNvbmZpZyxcbiAgICAgICAgICAgICAgICAgICAgdGVzdHM6IFtdXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5wcm9wYWdhdGVFdmVudCgncnVubmVyOnN0YXJ0JywgcnVubmVyKVxuICAgICAgICB9KVxuXG4gICAgICAgIHRoaXMub24oJ3J1bm5lcjppbml0JywgKHJ1bm5lcikgPT4ge1xuICAgICAgICAgICAgdGhpcy5zdGF0cy5ydW5uZXJbcnVubmVyLmNpZF0uc2Vzc2lvbklEID0gcnVubmVyLnNlc3Npb25JRFxuICAgICAgICAgICAgdGhpcy5wcm9wYWdhdGVFdmVudCgncnVubmVyOmluaXQnLCBydW5uZXIpXG4gICAgICAgIH0pXG5cbiAgICAgICAgdGhpcy5vbignc3VpdGU6c3RhcnQnLCAoc3VpdGUpID0+IHtcbiAgICAgICAgICAgIHN1aXRlLnJvb3QgfHwgdGhpcy5zdGF0cy5zdWl0ZXMrK1xuICAgICAgICAgICAgdGhpcy5wcm9wYWdhdGVFdmVudCgnc3VpdGU6c3RhcnQnLCBzdWl0ZSlcbiAgICAgICAgfSlcblxuICAgICAgICB0aGlzLm9uKCdzdWl0ZTplbmQnLCAoc3VpdGUpID0+IHtcbiAgICAgICAgICAgIHRoaXMucHJvcGFnYXRlRXZlbnQoJ3N1aXRlOmVuZCcsIHN1aXRlKVxuICAgICAgICB9KVxuXG4gICAgICAgIHRoaXMub24oJ3Rlc3Q6ZW5kJywgKHRlc3QpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc3RhdHMudGVzdHMrK1xuICAgICAgICAgICAgdGhpcy5wcm9wYWdhdGVFdmVudCgndGVzdDplbmQnLCB0ZXN0KVxuICAgICAgICB9KVxuXG4gICAgICAgIHRoaXMub24oJ3Rlc3Q6cGFzcycsICh0ZXN0KSA9PiB7XG4gICAgICAgICAgICB0aGlzLnN0YXRzLnJ1bm5lclt0ZXN0LmNpZF0udGVzdHMucHVzaChudWxsKVxuICAgICAgICAgICAgdGhpcy5zdGF0cy5wYXNzZXMrK1xuICAgICAgICAgICAgdGhpcy5wcm9wYWdhdGVFdmVudCgndGVzdDpwYXNzJywgdGVzdClcbiAgICAgICAgfSlcblxuICAgICAgICB0aGlzLm9uKCd0ZXN0OmZhaWwnLCAodGVzdCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zdGF0cy5mYWlsdXJlcysrXG4gICAgICAgICAgICB0aGlzLnN0YXRzLnJ1bm5lclt0ZXN0LmNpZF0udGVzdHMucHVzaCh0ZXN0LmVycilcblxuICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgKiBjaGVjayBpZiBlcnJvciBhbHNvIGhhcHBlbmVkIGluIG90aGVyIHJ1bm5lcnNcbiAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgdmFyIGR1cGxpY2F0ZUVycm9yID0gZmFsc2VcbiAgICAgICAgICAgIGZvciAobGV0IGZhaWx1cmUgb2YgdGhpcy5mYWlsdXJlcykge1xuICAgICAgICAgICAgICAgIGlmICh0ZXN0LmVyci5tZXNzYWdlICE9PSBmYWlsdXJlLmVyci5tZXNzYWdlIHx8IGZhaWx1cmUudGl0bGUgIT09IHRlc3QudGl0bGUpIHtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWVcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZHVwbGljYXRlRXJyb3IgPSB0cnVlXG4gICAgICAgICAgICAgICAgZmFpbHVyZS5ydW5uZXJbdGVzdC5jaWRdID0gdGVzdC5ydW5uZXJbdGVzdC5jaWRdXG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghZHVwbGljYXRlRXJyb3IpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmZhaWx1cmVzLnB1c2godGVzdClcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5wcm9wYWdhdGVFdmVudCgndGVzdDpmYWlsJywgdGVzdClcbiAgICAgICAgfSlcblxuICAgICAgICB0aGlzLm9uKCd0ZXN0OnBlbmRpbmcnLCAodGVzdCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zdGF0cy5wZW5kaW5nKytcbiAgICAgICAgICAgIHRoaXMucHJvcGFnYXRlRXZlbnQoJ3Rlc3Q6cGVuZGluZycsIHRlc3QpXG4gICAgICAgIH0pXG5cbiAgICAgICAgdGhpcy5vbigncnVubmVyOmVuZCcsIChydW5uZXIpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc3RhdHMucnVubmVyW3J1bm5lci5jaWRdLmVuZCA9IG5ldyBEYXRlKClcbiAgICAgICAgICAgIHRoaXMucHJvcGFnYXRlRXZlbnQoJ3J1bm5lcjplbmQnLCBydW5uZXIpXG4gICAgICAgIH0pXG5cbiAgICAgICAgdGhpcy5vbignZW5kJywgKGFyZ3MpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc3RhdHMuZW5kID0gbmV3IERhdGUoKVxuICAgICAgICAgICAgdGhpcy5zdGF0cy5kdXJhdGlvbiA9IG5ldyBEYXRlKCkgLSB0aGlzLnN0YXRzLnN0YXJ0XG4gICAgICAgICAgICB0aGlzLnByaW50RXBpbG9ndWUgPSB0aGlzLnByaW50RXBpbG9ndWUgJiYgIWFyZ3Muc2lnaW50XG4gICAgICAgICAgICB0aGlzLnByb3BhZ2F0ZUV2ZW50KCdlbmQnLCBhcmdzKVxuICAgICAgICB9KVxuXG4gICAgICAgIHRoaXMub24oJ2Vycm9yJywgKG0pID0+IHtcbiAgICAgICAgICAgIHRoaXMucHJpbnRFcGlsb2d1ZSA9IGZhbHNlXG5cbiAgICAgICAgICAgIHZhciBmbXQgPSB0aGlzLmNvbG9yKCdlcnJvciBtZXNzYWdlJywgJ0VSUk9SOiAlcycpXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhmbXQsIG0uZXJyb3IubWVzc2FnZSlcblxuICAgICAgICAgICAgdmFyIHNhbml0aXplZENhcHMgPSBbXVxuICAgICAgICAgICAgZm9yIChsZXQgY2FwYWJpbGl0eSBvZiBPYmplY3Qua2V5cyhtLmNhcGFiaWxpdGllcykpIHtcbiAgICAgICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAgICAgKiB3ZSBkb24ndCBuZWVkIGFsbCBjYXBhYmlsaXR5IHR5cGVzIHRvIHJlY29nbmlzZSBhIHZtXG4gICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgaWYgKFsnYnJvd3Nlck5hbWUnLCAncGxhdGZvcm0nLCAndmVyc2lvbicsICdwbGF0Zm9ybVZlcnNpb24nLCAnZGV2aWNlTmFtZScsICdhcHAnXS5pbmRleE9mKGNhcGFiaWxpdHkpID09PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICBjb250aW51ZVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHNhbml0aXplZENhcHMucHVzaChjYXBhYmlsaXR5ICsgJzogJyArIEpTT04uc3RyaW5naWZ5KG0uY2FwYWJpbGl0aWVzW2NhcGFiaWxpdHldKSlcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZm10ID0gdGhpcy5jb2xvcignYnJpZ2h0IHllbGxvdycsIHNhbml0aXplZENhcHMuam9pbignLCAnKSlcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGZtdClcblxuICAgICAgICAgICAgaWYgKG0uZXJyb3Iuc3RhY2spIHtcbiAgICAgICAgICAgICAgICBmbXQgPSB0aGlzLmNvbG9yKCdlcnJvciBzdGFjaycsIG0uZXJyb3Iuc3RhY2sucmVwbGFjZShgRXJyb3I6ICR7bS5lcnJvci5tZXNzYWdlfVxcbmAsICcnKSlcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZm10ID0gdGhpcy5jb2xvcignZXJyb3Igc3RhY2snLCAnICAgIG5vIHN0YWNrIGF2YWlsYWJsZScpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhmbXQpXG5cbiAgICAgICAgICAgIHRoaXMucHJvcGFnYXRlRXZlbnQoJ2Vycm9yJywgbSlcbiAgICAgICAgfSlcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDb2xvciBgc3RyYCB3aXRoIHRoZSBnaXZlbiBgdHlwZWAsXG4gICAgICogYWxsb3dpbmcgY29sb3JzIHRvIGJlIGRpc2FibGVkLFxuICAgICAqIGFzIHdlbGwgYXMgdXNlci1kZWZpbmVkIGNvbG9yXG4gICAgICogc2NoZW1lcy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSB0eXBlXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IHN0clxuICAgICAqIEByZXR1cm4ge1N0cmluZ31cbiAgICAgKiBAYXBpIHByaXZhdGVcbiAgICAgKi9cbiAgICBjb2xvciAodHlwZSwgc3RyKSB7XG4gICAgICAgIGlmICghc3VwcG9ydHNDb2xvcikgcmV0dXJuIFN0cmluZyhzdHIpXG4gICAgICAgIHJldHVybiBgXFx1MDAxYlske0NPTE9SU1t0eXBlXX1tJHtzdHJ9XFx1MDAxYlswbWBcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBPdXRwdXQgY29tbW9uIGVwaWxvZ3VlIHVzZWQgYnkgbWFueSBvZlxuICAgICAqIHRoZSBidW5kbGVkIHJlcG9ydGVycy5cbiAgICAgKlxuICAgICAqIEBhcGkgcHVibGljXG4gICAgICovXG4gICAgZXBpbG9ndWUgKCkge1xuICAgICAgICBsZXQgZm10ID0gbnVsbFxuXG4gICAgICAgIGlmICghdGhpcy5wcmludEVwaWxvZ3VlKSB7XG4gICAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnNvbGUubG9nKCdcXG4nKVxuXG4gICAgICAgIC8vIHBhc3Nlc1xuICAgICAgICBmbXQgPSB0aGlzLmNvbG9yKCdncmVlbicsICclZCBwYXNzaW5nJykgKyB0aGlzLmNvbG9yKCdsaWdodCcsICcgKCVzcyknKVxuICAgICAgICBjb25zb2xlLmxvZyhmbXQsIHRoaXMuc3RhdHMucGFzc2VzIHx8IDAsICgoTWF0aC5yb3VuZCh0aGlzLnN0YXRzLmR1cmF0aW9uIC8gMTAwKSkgLyAxMCkudG9GaXhlZCgyKSlcblxuICAgICAgICAvLyBwZW5kaW5nXG4gICAgICAgIGlmICh0aGlzLnN0YXRzLnBlbmRpbmcpIHtcbiAgICAgICAgICAgIGZtdCA9IHRoaXMuY29sb3IoJ3BlbmRpbmcnLCAnJWQgcGVuZGluZycpXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhmbXQsIHRoaXMuc3RhdHMucGVuZGluZylcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGZhaWx1cmVzXG4gICAgICAgIGlmICh0aGlzLnN0YXRzLmZhaWx1cmVzKSB7XG4gICAgICAgICAgICBmbXQgPSB0aGlzLmNvbG9yKCdmYWlsJywgJyVkIGZhaWxpbmcnKVxuICAgICAgICAgICAgY29uc29sZS5sb2coZm10LCB0aGlzLnN0YXRzLmZhaWx1cmVzKVxuICAgICAgICAgICAgdGhpcy5saXN0RmFpbHVyZXMoKVxuICAgICAgICB9XG5cbiAgICAgICAgY29uc29sZS5sb2coKVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE91dHV0IHRoZSBnaXZlbiBmYWlsdXJlcyBhcyBhIGxpc3RcbiAgICAgKi9cbiAgICBsaXN0RmFpbHVyZXMgKCkge1xuICAgICAgICBjb25zb2xlLmxvZygpXG5cbiAgICAgICAgdGhpcy5mYWlsdXJlcy5mb3JFYWNoKCh0ZXN0LCBpKSA9PiB7XG4gICAgICAgICAgICBsZXQgcnVubmluZ0Jyb3dzZXIgPSAnJ1xuICAgICAgICAgICAgZm9yIChsZXQgcGlkIG9mIE9iamVjdC5rZXlzKHRlc3QucnVubmVyKSkge1xuICAgICAgICAgICAgICAgIGxldCBjYXBzID0gdGVzdC5ydW5uZXJbcGlkXVxuICAgICAgICAgICAgICAgIHJ1bm5pbmdCcm93c2VyICs9ICdcXG5ydW5uaW5nJ1xuXG4gICAgICAgICAgICAgICAgaWYgKGNhcHMuYnJvd3Nlck5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgcnVubmluZ0Jyb3dzZXIgKz0gYCAke2NhcHMuYnJvd3Nlck5hbWV9YFxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoY2Fwcy52ZXJzaW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIHJ1bm5pbmdCcm93c2VyICs9IGAgKHYke2NhcHMudmVyc2lvbn0pYFxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoY2Fwcy5wbGF0Zm9ybSkge1xuICAgICAgICAgICAgICAgICAgICBydW5uaW5nQnJvd3NlciArPSBgIG9uICR7Y2Fwcy5wbGF0Zm9ybX1gXG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIGhvc3QgPSB0aGlzLnN0YXRzLnJ1bm5lcltwaWRdLmNvbmZpZy5ob3N0XG4gICAgICAgICAgICAgICAgaWYgKGhvc3QgJiYgaG9zdC5pbmRleE9mKCdzYXVjZWxhYnMnKSA+IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHJ1bm5pbmdCcm93c2VyICs9ICdcXG5DaGVjayBvdXQgam9iIGF0IGh0dHBzOi8vc2F1Y2VsYWJzLmNvbS90ZXN0cy8nICsgdGhpcy5zdGF0cy5ydW5uZXJbcGlkXS5zZXNzaW9uSURcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIGZvcm1hdFxuICAgICAgICAgICAgbGV0IGZtdCA9IHRoaXMuY29sb3IoJ2Vycm9yIHRpdGxlJywgJyVzKSAlczpcXG4nKSArXG4gICAgICAgICAgICAgICAgICAgICAgdGhpcy5jb2xvcignZXJyb3IgbWVzc2FnZScsICclcycpICtcbiAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbG9yKCdicmlnaHQgeWVsbG93JywgJyVzJykgK1xuICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY29sb3IoJ2Vycm9yIHN0YWNrJywgJ1xcbiVzXFxuJylcblxuICAgICAgICAgICAgY29uc29sZS5sb2coZm10LCAoaSArIDEpLCB0ZXN0LnRpdGxlLCB0ZXN0LmVyci5tZXNzYWdlLCBydW5uaW5nQnJvd3NlciwgdGVzdC5lcnIuc3RhY2spXG4gICAgICAgIH0pXG4gICAgfVxuXG4gICAgYWRkIChyZXBvcnRlcikge1xuICAgICAgICB0aGlzLnJlcG9ydGVycy5wdXNoKHJlcG9ydGVyKVxuICAgIH1cblxuICAgIHByb3BhZ2F0ZUV2ZW50ICguLi5hcmdzKSB7XG4gICAgICAgIGlmICh0aGlzLnJlcG9ydGVycy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG5cbiAgICAgICAgZm9yIChjb25zdCByZXBvcnRlciBvZiB0aGlzLnJlcG9ydGVycykge1xuICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgKiBza2lwIHJlcG9ydGVyIGlmXG4gICAgICAgICAgICAgKiBcdC0gaGUgaXNuJ3QgYW4gZXZlbnRlbWl0dGVyXG4gICAgICAgICAgICAgKiBcdC0gZXZlbnQgaXMgbm90IHJlZ2lzdGVyZWRcbiAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgaWYgKHR5cGVvZiByZXBvcnRlci5lbWl0ICE9PSAnZnVuY3Rpb24nIHx8IE9iamVjdC5rZXlzKHJlcG9ydGVyLl9ldmVudHMpLmluZGV4T2YoYXJnc1swXSkgPCAwKSB7XG4gICAgICAgICAgICAgICAgY29udGludWVcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmVwb3J0ZXIuZW1pdC5hcHBseShyZXBvcnRlciwgYXJncylcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIERlZmF1bHQgY29sb3IgbWFwLlxuICAgICAqL1xuICAgIGdldCBjb2xvcnMgKCkge1xuICAgICAgICByZXR1cm4gQ09MT1JTXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRGVmYXVsdCBzeW1ib2wgbWFwLlxuICAgICAqL1xuICAgIGdldCBzeW1ib2xzICgpIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFdpdGggbm9kZS5qcyBvbiBXaW5kb3dzOiB1c2Ugc3ltYm9scyBhdmFpbGFibGUgaW4gdGVybWluYWwgZGVmYXVsdCBmb250c1xuICAgICAgICAgKi9cbiAgICAgICAgaWYgKHByb2Nlc3MucGxhdGZvcm0gPT09ICd3aW4zMicpIHtcbiAgICAgICAgICAgIHJldHVybiBTWU1CT0xTX1dJTlxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIFNZTUJPTFNcbiAgICB9XG59XG5cbi8qKlxuICogRXhwb3NlIHNvbWUgYmFzaWMgY3Vyc29yIGludGVyYWN0aW9uc1xuICogdGhhdCBhcmUgY29tbW9uIGFtb25nIHJlcG9ydGVycy5cbiAqL1xuY2xhc3MgQ3Vyc29yIHtcbiAgICBoaWRlICgpIHtcbiAgICAgICAgSVNBVFRZICYmIHByb2Nlc3Muc3Rkb3V0LndyaXRlKCdcXHUwMDFiWz8yNWwnKVxuICAgIH1cblxuICAgIHNob3cgKCkge1xuICAgICAgICBJU0FUVFkgJiYgcHJvY2Vzcy5zdGRvdXQud3JpdGUoJ1xcdTAwMWJbPzI1aCcpXG4gICAgfVxuXG4gICAgZGVsZXRlTGluZSAoKSB7XG4gICAgICAgIElTQVRUWSAmJiBwcm9jZXNzLnN0ZG91dC53cml0ZSgnXFx1MDAxYlsySycpXG4gICAgfVxuXG4gICAgYmVnaW5uaW5nT2ZMaW5lICgpIHtcbiAgICAgICAgSVNBVFRZICYmIHByb2Nlc3Muc3Rkb3V0LndyaXRlKCdcXHUwMDFiWzBHJylcbiAgICB9XG5cbiAgICBDUiAoKSB7XG4gICAgICAgIGlmIChJU0FUVFkpIHtcbiAgICAgICAgICAgIHRoaXMuZGVsZXRlTGluZSgpXG4gICAgICAgICAgICB0aGlzLmJlZ2lubmluZ09mTGluZSgpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwcm9jZXNzLnN0ZG91dC53cml0ZSgnXFxyJylcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGdldCBpc2F0dHkgKCkge1xuICAgICAgICByZXR1cm4gSVNBVFRZXG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBCYXNlUmVwb3J0ZXJcbmV4cG9ydCB7IEN1cnNvciB9XG4iXX0=