UNPKG

testcafe

Version:

Automated browser testing for the modern web development stack.

119 lines 18.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const events_1 = require("events"); const pinkie_1 = __importDefault(require("pinkie")); const time_limit_promise_1 = __importDefault(require("time-limit-promise")); const promisify_event_1 = __importDefault(require("promisify-event")); const lodash_1 = require("lodash"); const map_reverse_1 = __importDefault(require("map-reverse")); const runtime_1 = require("../errors/runtime"); const types_1 = require("../errors/types"); const LOCAL_BROWSERS_READY_TIMEOUT = 2 * 60 * 1000; const REMOTE_BROWSERS_READY_TIMEOUT = 6 * 60 * 1000; class BrowserSet extends events_1.EventEmitter { constructor(browserConnectionGroups) { super(); this.RELEASE_TIMEOUT = 10000; this.pendingReleases = []; this.browserConnectionGroups = browserConnectionGroups; this.browserConnections = lodash_1.flatten(browserConnectionGroups); this.connectionsReadyTimeout = null; this.browserErrorHandler = error => this.emit('error', error); this.browserConnections.forEach(bc => bc.on('error', this.browserErrorHandler)); // NOTE: We're setting an empty error handler, because Node kills the process on an 'error' event // if there is no handler. See: https://nodejs.org/api/events.html#events_class_events_eventemitter this.on('error', lodash_1.noop); } static async _waitIdle(bc) { if (bc.idle || !bc.ready) return; await promisify_event_1.default(bc, 'idle'); } static async _closeConnection(bc) { if (bc.closed || !bc.ready) return; bc.close(); await promisify_event_1.default(bc, 'closed'); } async _getReadyTimeout() { const isLocalBrowser = connection => connection.provider.isLocalBrowser(connection.id, connection.browserInfo.browserName); const remoteBrowsersExist = (await pinkie_1.default.all(this.browserConnections.map(isLocalBrowser))).indexOf(false) > -1; return remoteBrowsersExist ? REMOTE_BROWSERS_READY_TIMEOUT : LOCAL_BROWSERS_READY_TIMEOUT; } _createPendingConnectionPromise(readyPromise, timeout, timeoutError) { const timeoutPromise = new pinkie_1.default((_, reject) => { this.connectionsReadyTimeout = setTimeout(() => reject(timeoutError), timeout); }); return pinkie_1.default .race([readyPromise, timeoutPromise]) .then(value => { this.connectionsReadyTimeout.unref(); return value; }, error => { this.connectionsReadyTimeout.unref(); throw error; }); } async _waitConnectionsOpened() { const connectionsReadyPromise = pinkie_1.default.all(this.browserConnections .filter(bc => !bc.opened) .map(bc => promisify_event_1.default(bc, 'opened'))); const timeoutError = new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotEstablishBrowserConnection); const readyTimeout = await this._getReadyTimeout(); await this._createPendingConnectionPromise(connectionsReadyPromise, readyTimeout, timeoutError); } _checkForDisconnections() { const disconnectedUserAgents = this.browserConnections .filter(bc => bc.closed) .map(bc => bc.userAgent); if (disconnectedUserAgents.length) throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotRunAgainstDisconnectedBrowsers, disconnectedUserAgents.join(', ')); } //API static from(browserConnections) { const browserSet = new BrowserSet(browserConnections); const prepareConnection = pinkie_1.default.resolve() .then(() => { browserSet._checkForDisconnections(); return browserSet._waitConnectionsOpened(); }) .then(() => browserSet); return pinkie_1.default .race([ prepareConnection, promisify_event_1.default(browserSet, 'error') ]) .catch(async (error) => { await browserSet.dispose(); throw error; }); } releaseConnection(bc) { if (this.browserConnections.indexOf(bc) < 0) return pinkie_1.default.resolve(); lodash_1.pull(this.browserConnections, bc); bc.removeListener('error', this.browserErrorHandler); const appropriateStateSwitch = !bc.permanent ? BrowserSet._closeConnection(bc) : BrowserSet._waitIdle(bc); const release = time_limit_promise_1.default(appropriateStateSwitch, this.RELEASE_TIMEOUT).then(() => lodash_1.pull(this.pendingReleases, release)); this.pendingReleases.push(release); return release; } async dispose() { // NOTE: When browserConnection is cancelled, it is removed from // the this.connections array, which leads to shifting indexes // towards the beginning. So, we must copy the array in order to iterate it, // or we can perform iteration from the end to the beginning. if (this.connectionsReadyTimeout) this.connectionsReadyTimeout.unref(); map_reverse_1.default(this.browserConnections, bc => this.releaseConnection(bc)); await pinkie_1.default.all(this.pendingReleases); } } exports.default = BrowserSet; module.exports = exports.default; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnJvd3Nlci1zZXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVubmVyL2Jyb3dzZXItc2V0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsbUNBQXNDO0FBQ3RDLG9EQUE2QjtBQUM3Qiw0RUFBdUQ7QUFDdkQsc0VBQTZDO0FBQzdDLG1DQUF1RDtBQUN2RCw4REFBcUM7QUFDckMsK0NBQWlEO0FBQ2pELDJDQUFpRDtBQUVqRCxNQUFNLDRCQUE0QixHQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBQ3BELE1BQU0sNkJBQTZCLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFFcEQsTUFBcUIsVUFBVyxTQUFRLHFCQUFZO0lBQ2hELFlBQWEsdUJBQXVCO1FBQ2hDLEtBQUssRUFBRSxDQUFDO1FBRVIsSUFBSSxDQUFDLGVBQWUsR0FBRyxLQUFLLENBQUM7UUFFN0IsSUFBSSxDQUFDLGVBQWUsR0FBRyxFQUFFLENBQUM7UUFFMUIsSUFBSSxDQUFDLHVCQUF1QixHQUFHLHVCQUF1QixDQUFDO1FBQ3ZELElBQUksQ0FBQyxrQkFBa0IsR0FBUSxnQkFBTyxDQUFDLHVCQUF1QixDQUFDLENBQUM7UUFFaEUsSUFBSSxDQUFDLHVCQUF1QixHQUFHLElBQUksQ0FBQztRQUVwQyxJQUFJLENBQUMsbUJBQW1CLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUU5RCxJQUFJLENBQUMsa0JBQWtCLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUMsQ0FBQztRQUVoRixpR0FBaUc7UUFDakcsbUdBQW1HO1FBQ25HLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLGFBQUksQ0FBQyxDQUFDO0lB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QyxtQkFBbUIsQ0FBQyxDQUFDO1FBRXJELE1BQU0sc0JBQXNCLEdBQUcsQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDMUMsVUFBVSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDakMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUU3QixNQUFNLE9BQU8sR0FBRyw0QkFBcUIsQ0FBQyxzQkFBc0IsRUFBRSxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLGFBQU0sQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7UUFFdEksSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFbkMsT0FBTyxPQUFPLENBQUM7SUFDbkIsQ0FBQztJQUVELEtBQUssQ0FBQyxPQUFPO1FBQ1QsZ0VBQWdFO1FBQ2hFLDhEQUE4RDtRQUM5RCw0RUFBNEU7UUFDNUUsNkRBQTZEO1FBQzdELElBQUksSUFBSSxDQUFDLHVCQUF1QjtZQUM1QixJQUFJLENBQUMsdUJBQXVCLENBQUMsS0FBSyxFQUFFLENBQUM7UUFFekMscUJBQVUsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUV0RSxNQUFNLGdCQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUM1QyxDQUFDO0NBQ0o7QUE3SUQsNkJBNklDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSAnZXZlbnRzJztcbmltcG9ydCBQcm9taXNlIGZyb20gJ3BpbmtpZSc7XG5pbXBvcnQgZ2V0VGltZUxpbWl0ZWRQcm9taXNlIGZyb20gJ3RpbWUtbGltaXQtcHJvbWlzZSc7XG5pbXBvcnQgcHJvbWlzaWZ5RXZlbnQgZnJvbSAncHJvbWlzaWZ5LWV2ZW50JztcbmltcG9ydCB7IG5vb3AsIHB1bGwgYXMgcmVtb3ZlLCBmbGF0dGVuIH0gZnJvbSAnbG9kYXNoJztcbmltcG9ydCBtYXBSZXZlcnNlIGZyb20gJ21hcC1yZXZlcnNlJztcbmltcG9ydCB7IEdlbmVyYWxFcnJvciB9IGZyb20gJy4uL2Vycm9ycy9ydW50aW1lJztcbmltcG9ydCB7IFJVTlRJTUVfRVJST1JTIH0gZnJvbSAnLi4vZXJyb3JzL3R5cGVzJztcblxuY29uc3QgTE9DQUxfQlJPV1NFUlNfUkVBRFlfVElNRU9VVCAgPSAyICogNjAgKiAxMDAwO1xuY29uc3QgUkVNT1RFX0JST1dTRVJTX1JFQURZX1RJTUVPVVQgPSA2ICogNjAgKiAxMDAwO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBCcm93c2VyU2V0IGV4dGVuZHMgRXZlbnRFbWl0dGVyIHtcbiAgICBjb25zdHJ1Y3RvciAoYnJvd3NlckNvbm5lY3Rpb25Hcm91cHMpIHtcbiAgICAgICAgc3VwZXIoKTtcblxuICAgICAgICB0aGlzLlJFTEVBU0VfVElNRU9VVCA9IDEwMDAwO1xuXG4gICAgICAgIHRoaXMucGVuZGluZ1JlbGVhc2VzID0gW107XG5cbiAgICAgICAgdGhpcy5icm93c2VyQ29ubmVjdGlvbkdyb3VwcyA9IGJyb3dzZXJDb25uZWN0aW9uR3JvdXBzO1xuICAgICAgICB0aGlzLmJyb3dzZXJDb25uZWN0aW9ucyAgICAgID0gZmxhdHRlbihicm93c2VyQ29ubmVjdGlvbkdyb3Vwcyk7XG5cbiAgICAgICAgdGhpcy5jb25uZWN0aW9uc1JlYWR5VGltZW91dCA9IG51bGw7XG5cbiAgICAgICAgdGhpcy5icm93c2VyRXJyb3JIYW5kbGVyID0gZXJyb3IgPT4gdGhpcy5lbWl0KCdlcnJvcicsIGVycm9yKTtcblxuICAgICAgICB0aGlzLmJyb3dzZXJDb25uZWN0aW9ucy5mb3JFYWNoKGJjID0+IGJjLm9uKCdlcnJvcicsIHRoaXMuYnJvd3NlckVycm9ySGFuZGxlcikpO1xuXG4gICAgICAgIC8vIE5PVEU6IFdlJ3JlIHNldHRpbmcgYW4gZW1wdHkgZXJyb3IgaGFuZGxlciwgYmVjYXVzZSBOb2RlIGtpbGxzIHRoZSBwcm9jZXNzIG9uIGFuICdlcnJvcicgZXZlbnRcbiAgICAgICAgLy8gaWYgdGhlcmUgaXMgbm8gaGFuZGxlci4gU2VlOiBodHRwczovL25vZGVqcy5vcmcvYXBpL2V2ZW50cy5odG1sI2V2ZW50c19jbGFzc19ldmVudHNfZXZlbnRlbWl0dGVyXG4gICAgICAgIHRoaXMub24oJ2Vycm9yJywgbm9vcCk7XG4gICAgfVxuXG4gICAgc3RhdGljIGFzeW5jIF93YWl0SWRsZSAoYmMpIHtcbiAgICAgICAgaWYgKGJjLmlkbGUgfHwgIWJjLnJlYWR5KVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIGF3YWl0IHByb21pc2lmeUV2ZW50KGJjLCAnaWRsZScpO1xuICAgIH1cblxuICAgIHN0YXRpYyBhc3luYyBfY2xvc2VDb25uZWN0aW9uIChiYykge1xuICAgICAgICBpZiAoYmMuY2xvc2VkIHx8ICFiYy5yZWFkeSlcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICBiYy5jbG9zZSgpO1xuXG4gICAgICAgIGF3YWl0IHByb21pc2lmeUV2ZW50KGJjLCAnY2xvc2VkJyk7XG4gICAgfVxuXG4gICAgYXN5bmMgX2dldFJlYWR5VGltZW91dCAoKSB7XG4gICAgICAgIGNvbnN0IGlzTG9jYWxCcm93c2VyICAgICAgPSBjb25uZWN0aW9uID0+IGNvbm5lY3Rpb24ucHJvdmlkZXIuaXNMb2NhbEJyb3dzZXIoY29ubmVjdGlvbi5pZCwgY29ubmVjdGlvbi5icm93c2VySW5mby5icm93c2VyTmFtZSk7XG4gICAgICAgIGNvbnN0IHJlbW90ZUJyb3dzZXJzRXhpc3QgPSAoYXdhaXQgUHJvbWlzZS5hbGwodGhpcy5icm93c2VyQ29ubmVjdGlvbnMubWFwKGlzTG9jYWxCcm93c2VyKSkpLmluZGV4T2YoZmFsc2UpID4gLTE7XG5cbiAgICAgICAgcmV0dXJuIHJlbW90ZUJyb3dzZXJzRXhpc3QgPyBSRU1PVEVfQlJPV1NFUlNfUkVBRFlfVElNRU9VVCA6IExPQ0FMX0JST1dTRVJTX1JFQURZX1RJTUVPVVQ7XG4gICAgfVxuXG4gICAgX2NyZWF0ZVBlbmRpbmdDb25uZWN0aW9uUHJvbWlzZSAocmVhZHlQcm9taXNlLCB0aW1lb3V0LCB0aW1lb3V0RXJyb3IpIHtcbiAgICAgICAgY29uc3QgdGltZW91dFByb21pc2UgPSBuZXcgUHJvbWlzZSgoXywgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb25zUmVhZHlUaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiByZWplY3QodGltZW91dEVycm9yKSwgdGltZW91dCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBQcm9taXNlXG4gICAgICAgICAgICAucmFjZShbcmVhZHlQcm9taXNlLCB0aW1lb3V0UHJvbWlzZV0pXG4gICAgICAgICAgICAudGhlbihcbiAgICAgICAgICAgICAgICB2YWx1ZSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbnNSZWFkeVRpbWVvdXQudW5yZWYoKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZXJyb3IgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb25zUmVhZHlUaW1lb3V0LnVucmVmKCk7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICk7XG4gICAgfVxuXG4gICAgYXN5bmMgX3dhaXRDb25uZWN0aW9uc09wZW5lZCAoKSB7XG4gICAgICAgIGNvbnN0IGNvbm5lY3Rpb25zUmVhZHlQcm9taXNlID0gUHJvbWlzZS5hbGwoXG4gICAgICAgICAgICB0aGlzLmJyb3dzZXJDb25uZWN0aW9uc1xuICAgICAgICAgICAgICAgIC5maWx0ZXIoYmMgPT4gIWJjLm9wZW5lZClcbiAgICAgICAgICAgICAgICAubWFwKGJjID0+IHByb21pc2lmeUV2ZW50KGJjLCAnb3BlbmVkJykpXG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3QgdGltZW91dEVycm9yID0gbmV3IEdlbmVyYWxFcnJvcihSVU5USU1FX0VSUk9SUy5jYW5ub3RFc3RhYmxpc2hCcm93c2VyQ29ubmVjdGlvbik7XG4gICAgICAgIGNvbnN0IHJlYWR5VGltZW91dCA9IGF3YWl0IHRoaXMuX2dldFJlYWR5VGltZW91dCgpO1xuXG4gICAgICAgIGF3YWl0IHRoaXMuX2NyZWF0ZVBlbmRpbmdDb25uZWN0aW9uUHJvbWlzZShjb25uZWN0aW9uc1JlYWR5UHJvbWlzZSwgcmVhZHlUaW1lb3V0LCB0aW1lb3V0RXJyb3IpO1xuICAgIH1cblxuICAgIF9jaGVja0ZvckRpc2Nvbm5lY3Rpb25zICgpIHtcbiAgICAgICAgY29uc3QgZGlzY29ubmVjdGVkVXNlckFnZW50cyA9IHRoaXMuYnJvd3NlckNvbm5lY3Rpb25zXG4gICAgICAgICAgICAuZmlsdGVyKGJjID0+IGJjLmNsb3NlZClcbiAgICAgICAgICAgIC5tYXAoYmMgPT4gYmMudXNlckFnZW50KTtcblxuICAgICAgICBpZiAoZGlzY29ubmVjdGVkVXNlckFnZW50cy5sZW5ndGgpXG4gICAgICAgICAgICB0aHJvdyBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLmNhbm5vdFJ1bkFnYWluc3REaXNjb25uZWN0ZWRCcm93c2VycywgZGlzY29ubmVjdGVkVXNlckFnZW50cy5qb2luKCcsICcpKTtcbiAgICB9XG5cblxuICAgIC8vQVBJXG4gICAgc3RhdGljIGZyb20gKGJyb3dzZXJDb25uZWN0aW9ucykge1xuICAgICAgICBjb25zdCBicm93c2VyU2V0ID0gbmV3IEJyb3dzZXJTZXQoYnJvd3NlckNvbm5lY3Rpb25zKTtcblxuICAgICAgICBjb25zdCBwcmVwYXJlQ29ubmVjdGlvbiA9IFByb21pc2UucmVzb2x2ZSgpXG4gICAgICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgYnJvd3NlclNldC5fY2hlY2tGb3JEaXNjb25uZWN0aW9ucygpO1xuICAgICAgICAgICAgICAgIHJldHVybiBicm93c2VyU2V0Ll93YWl0Q29ubmVjdGlvbnNPcGVuZWQoKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAudGhlbigoKSA9PiBicm93c2VyU2V0KTtcblxuICAgICAgICByZXR1cm4gUHJvbWlzZVxuICAgICAgICAgICAgLnJhY2UoW1xuICAgICAgICAgICAgICAgIHByZXBhcmVDb25uZWN0aW9uLFxuICAgICAgICAgICAgICAgIHByb21pc2lmeUV2ZW50KGJyb3dzZXJTZXQsICdlcnJvcicpXG4gICAgICAgICAgICBdKVxuICAgICAgICAgICAgLmNhdGNoKGFzeW5jIGVycm9yID0+IHtcbiAgICAgICAgICAgICAgICBhd2FpdCBicm93c2VyU2V0LmRpc3Bvc2UoKTtcblxuICAgICAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmVsZWFzZUNvbm5lY3Rpb24gKGJjKSB7XG4gICAgICAgIGlmICh0aGlzLmJyb3dzZXJDb25uZWN0aW9ucy5pbmRleE9mKGJjKSA8IDApXG4gICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG5cbiAgICAgICAgcmVtb3ZlKHRoaXMuYnJvd3NlckNvbm5lY3Rpb25zLCBiYyk7XG5cbiAgICAgICAgYmMucmVtb3ZlTGlzdGVuZXIoJ2Vycm9yJywgdGhpcy5icm93c2VyRXJyb3JIYW5kbGVyKTtcblxuICAgICAgICBjb25zdCBhcHByb3ByaWF0ZVN0YXRlU3dpdGNoID0gIWJjLnBlcm1hbmVudCA/XG4gICAgICAgICAgICBCcm93c2VyU2V0Ll9jbG9zZUNvbm5lY3Rpb24oYmMpIDpcbiAgICAgICAgICAgIEJyb3dzZXJTZXQuX3dhaXRJZGxlKGJjKTtcblxuICAgICAgICBjb25zdCByZWxlYXNlID0gZ2V0VGltZUxpbWl0ZWRQcm9taXNlKGFwcHJvcHJpYXRlU3RhdGVTd2l0Y2gsIHRoaXMuUkVMRUFTRV9USU1FT1VUKS50aGVuKCgpID0+IHJlbW92ZSh0aGlzLnBlbmRpbmdSZWxlYXNlcywgcmVsZWFzZSkpO1xuXG4gICAgICAgIHRoaXMucGVuZGluZ1JlbGVhc2VzLnB1c2gocmVsZWFzZSk7XG5cbiAgICAgICAgcmV0dXJuIHJlbGVhc2U7XG4gICAgfVxuXG4gICAgYXN5bmMgZGlzcG9zZSAoKSB7XG4gICAgICAgIC8vIE5PVEU6IFdoZW4gYnJvd3NlckNvbm5lY3Rpb24gaXMgY2FuY2VsbGVkLCBpdCBpcyByZW1vdmVkIGZyb21cbiAgICAgICAgLy8gdGhlIHRoaXMuY29ubmVjdGlvbnMgYXJyYXksIHdoaWNoIGxlYWRzIHRvIHNoaWZ0aW5nIGluZGV4ZXNcbiAgICAgICAgLy8gdG93YXJkcyB0aGUgYmVnaW5uaW5nLiBTbywgd2UgbXVzdCBjb3B5IHRoZSBhcnJheSBpbiBvcmRlciB0byBpdGVyYXRlIGl0LFxuICAgICAgICAvLyBvciB3ZSBjYW4gcGVyZm9ybSBpdGVyYXRpb24gZnJvbSB0aGUgZW5kIHRvIHRoZSBiZWdpbm5pbmcuXG4gICAgICAgIGlmICh0aGlzLmNvbm5lY3Rpb25zUmVhZHlUaW1lb3V0KVxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uc1JlYWR5VGltZW91dC51bnJlZigpO1xuXG4gICAgICAgIG1hcFJldmVyc2UodGhpcy5icm93c2VyQ29ubmVjdGlvbnMsIGJjID0+IHRoaXMucmVsZWFzZUNvbm5lY3Rpb24oYmMpKTtcblxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbCh0aGlzLnBlbmRpbmdSZWxlYXNlcyk7XG4gICAgfVxufVxuIl19