UNPKG

@testim/testim-cli

Version:

Command line interface for running Testing on you CI

499 lines (417 loc) 39.5 kB
'use strict'; 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=