1 | ;
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | const events_1 = require("events");
|
7 | const time_limit_promise_1 = __importDefault(require("time-limit-promise"));
|
8 | const promisify_event_1 = __importDefault(require("promisify-event"));
|
9 | const lodash_1 = require("lodash");
|
10 | const map_reverse_1 = __importDefault(require("map-reverse"));
|
11 | const runtime_1 = require("../errors/runtime");
|
12 | const types_1 = require("../errors/types");
|
13 | const LOCAL_BROWSERS_READY_TIMEOUT = 2 * 60 * 1000;
|
14 | const REMOTE_BROWSERS_READY_TIMEOUT = 6 * 60 * 1000;
|
15 | class BrowserSet extends events_1.EventEmitter {
|
16 | constructor(browserConnectionGroups) {
|
17 | super();
|
18 | this.RELEASE_TIMEOUT = 10000;
|
19 | this.pendingReleases = [];
|
20 | this.browserConnectionGroups = browserConnectionGroups;
|
21 | this.browserConnections = lodash_1.flatten(browserConnectionGroups);
|
22 | this.connectionsReadyTimeout = null;
|
23 | this.browserErrorHandler = error => this.emit('error', error);
|
24 | this.browserConnections.forEach(bc => bc.on('error', this.browserErrorHandler));
|
25 | // NOTE: We're setting an empty error handler, because Node kills the process on an 'error' event
|
26 | // if there is no handler. See: https://nodejs.org/api/events.html#events_class_events_eventemitter
|
27 | this.on('error', lodash_1.noop);
|
28 | }
|
29 | static async _waitIdle(bc) {
|
30 | if (bc.idle || !bc.ready)
|
31 | return;
|
32 | await promisify_event_1.default(bc, 'idle');
|
33 | }
|
34 | static async _closeConnection(bc) {
|
35 | if (bc.closed || !bc.ready)
|
36 | return;
|
37 | bc.close();
|
38 | await promisify_event_1.default(bc, 'closed');
|
39 | }
|
40 | async _getReadyTimeout() {
|
41 | const isLocalBrowser = connection => connection.provider.isLocalBrowser(connection.id, connection.browserInfo.browserName);
|
42 | const remoteBrowsersExist = (await Promise.all(this.browserConnections.map(isLocalBrowser))).indexOf(false) > -1;
|
43 | return remoteBrowsersExist ? REMOTE_BROWSERS_READY_TIMEOUT : LOCAL_BROWSERS_READY_TIMEOUT;
|
44 | }
|
45 | _createPendingConnectionPromise(readyPromise, timeout, timeoutError) {
|
46 | const timeoutPromise = new Promise((_, reject) => {
|
47 | this.connectionsReadyTimeout = setTimeout(() => reject(timeoutError), timeout);
|
48 | });
|
49 | return Promise
|
50 | .race([readyPromise, timeoutPromise])
|
51 | .then(value => {
|
52 | this.connectionsReadyTimeout.unref();
|
53 | return value;
|
54 | }, error => {
|
55 | this.connectionsReadyTimeout.unref();
|
56 | throw error;
|
57 | });
|
58 | }
|
59 | async _waitConnectionsOpened() {
|
60 | const connectionsReadyPromise = Promise.all(this.browserConnections
|
61 | .filter(bc => !bc.opened)
|
62 | .map(bc => promisify_event_1.default(bc, 'opened')));
|
63 | const timeoutError = new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotEstablishBrowserConnection);
|
64 | const readyTimeout = await this._getReadyTimeout();
|
65 | await this._createPendingConnectionPromise(connectionsReadyPromise, readyTimeout, timeoutError);
|
66 | }
|
67 | _checkForDisconnections() {
|
68 | const disconnectedUserAgents = this.browserConnections
|
69 | .filter(bc => bc.closed)
|
70 | .map(bc => bc.userAgent);
|
71 | if (disconnectedUserAgents.length)
|
72 | throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotRunAgainstDisconnectedBrowsers, disconnectedUserAgents.join(', '));
|
73 | }
|
74 | //API
|
75 | static from(browserConnections) {
|
76 | const browserSet = new BrowserSet(browserConnections);
|
77 | const prepareConnection = Promise.resolve()
|
78 | .then(() => {
|
79 | browserSet._checkForDisconnections();
|
80 | return browserSet._waitConnectionsOpened();
|
81 | })
|
82 | .then(() => browserSet);
|
83 | return Promise
|
84 | .race([
|
85 | prepareConnection,
|
86 | promisify_event_1.default(browserSet, 'error')
|
87 | ])
|
88 | .catch(async (error) => {
|
89 | await browserSet.dispose();
|
90 | throw error;
|
91 | });
|
92 | }
|
93 | releaseConnection(bc) {
|
94 | if (this.browserConnections.indexOf(bc) < 0)
|
95 | return Promise.resolve();
|
96 | lodash_1.pull(this.browserConnections, bc);
|
97 | bc.removeListener('error', this.browserErrorHandler);
|
98 | const appropriateStateSwitch = !bc.permanent ?
|
99 | BrowserSet._closeConnection(bc) :
|
100 | BrowserSet._waitIdle(bc);
|
101 | const release = time_limit_promise_1.default(appropriateStateSwitch, this.RELEASE_TIMEOUT).then(() => lodash_1.pull(this.pendingReleases, release));
|
102 | this.pendingReleases.push(release);
|
103 | return release;
|
104 | }
|
105 | async dispose() {
|
106 | // NOTE: When browserConnection is cancelled, it is removed from
|
107 | // the this.connections array, which leads to shifting indexes
|
108 | // towards the beginning. So, we must copy the array in order to iterate it,
|
109 | // or we can perform iteration from the end to the beginning.
|
110 | if (this.connectionsReadyTimeout)
|
111 | this.connectionsReadyTimeout.unref();
|
112 | map_reverse_1.default(this.browserConnections, bc => this.releaseConnection(bc));
|
113 | await Promise.all(this.pendingReleases);
|
114 | }
|
115 | }
|
116 | exports.default = BrowserSet;
|
117 | module.exports = exports.default;
|
118 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnJvd3Nlci1zZXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVubmVyL2Jyb3dzZXItc2V0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsbUNBQXNDO0FBQ3RDLDRFQUF1RDtBQUN2RCxzRUFBNkM7QUFDN0MsbUNBQXVEO0FBQ3ZELDhEQUFxQztBQUNyQywrQ0FBaUQ7QUFDakQsMkNBQWlEO0FBRWpELE1BQU0sNEJBQTRCLEdBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFDcEQsTUFBTSw2QkFBNkIsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUVwRCxNQUFxQixVQUFXLFNBQVEscUJBQVk7SUFDaEQsWUFBYSx1QkFBdUI7UUFDaEMsS0FBSyxFQUFFLENBQUM7UUFFUixJQUFJLENBQUMsZUFBZSxHQUFHLEtBQUssQ0FBQztRQUU3QixJQUFJLENBQUMsZUFBZSxHQUFHLEVBQUUsQ0FBQztRQUUxQixJQUFJLENBQUMsdUJBQXVCLEdBQUcsdUJBQXVCLENBQUM7UUFDdkQsSUFBSSxDQUFDLGtCQUFrQixHQUFRLGdCQUFPLENBQUMsdUJBQXVCLENBQUMsQ0FBQztRQUVoRSxJQUFJLENBQUMsdUJBQXVCLEdBQUcsSUFBSSxDQUFDO1FBRXBDLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRTlELElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxDQUFDO1FBRWhGLGlHQUFpRztRQUNqRyxtR0FBbUc7UUFDbkcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsYUFBSSxDQUFDLENBQUM7SUFDM0IsQ0FBQztJQUVE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QUVyRCxNQUFNLHNCQUFzQixHQUFHLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQzFDLFVBQVUsQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQ2pDLFVBQVUsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFN0IsTUFBTSxPQUFPLEdBQUcsNEJBQXFCLENBQUMsc0JBQXNCLEVBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxhQUFNLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO1FBRXRJLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRW5DLE9BQU8sT0FBTyxDQUFDO0lBQ25CLENBQUM7SUFFRCxLQUFLLENBQUMsT0FBTztRQUNULGdFQUFnRTtRQUNoRSw4REFBOEQ7UUFDOUQsNEVBQTRFO1FBQzVFLDZEQUE2RDtRQUM3RCxJQUFJLElBQUksQ0FBQyx1QkFBdUI7WUFDNUIsSUFBSSxDQUFDLHVCQUF1QixDQUFDLEtBQUssRUFBRSxDQUFDO1FBRXpDLHFCQUFVLENBQUMsSUFBSSxDQUFDLGtCQUFrQixFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFFdEUsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUM1QyxDQUFDO0NBQ0o7QUE3SUQsNkJBNklDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSAnZXZlbnRzJztcbmltcG9ydCBnZXRUaW1lTGltaXRlZFByb21pc2UgZnJvbSAndGltZS1saW1pdC1wcm9taXNlJztcbmltcG9ydCBwcm9taXNpZnlFdmVudCBmcm9tICdwcm9taXNpZnktZXZlbnQnO1xuaW1wb3J0IHsgbm9vcCwgcHVsbCBhcyByZW1vdmUsIGZsYXR0ZW4gfSBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IG1hcFJldmVyc2UgZnJvbSAnbWFwLXJldmVyc2UnO1xuaW1wb3J0IHsgR2VuZXJhbEVycm9yIH0gZnJvbSAnLi4vZXJyb3JzL3J1bnRpbWUnO1xuaW1wb3J0IHsgUlVOVElNRV9FUlJPUlMgfSBmcm9tICcuLi9lcnJvcnMvdHlwZXMnO1xuXG5jb25zdCBMT0NBTF9CUk9XU0VSU19SRUFEWV9USU1FT1VUICA9IDIgKiA2MCAqIDEwMDA7XG5jb25zdCBSRU1PVEVfQlJPV1NFUlNfUkVBRFlfVElNRU9VVCA9IDYgKiA2MCAqIDEwMDA7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEJyb3dzZXJTZXQgZXh0ZW5kcyBFdmVudEVtaXR0ZXIge1xuICAgIGNvbnN0cnVjdG9yIChicm93c2VyQ29ubmVjdGlvbkdyb3Vwcykge1xuICAgICAgICBzdXBlcigpO1xuXG4gICAgICAgIHRoaXMuUkVMRUFTRV9USU1FT1VUID0gMTAwMDA7XG5cbiAgICAgICAgdGhpcy5wZW5kaW5nUmVsZWFzZXMgPSBbXTtcblxuICAgICAgICB0aGlzLmJyb3dzZXJDb25uZWN0aW9uR3JvdXBzID0gYnJvd3NlckNvbm5lY3Rpb25Hcm91cHM7XG4gICAgICAgIHRoaXMuYnJvd3NlckNvbm5lY3Rpb25zICAgICAgPSBmbGF0dGVuKGJyb3dzZXJDb25uZWN0aW9uR3JvdXBzKTtcblxuICAgICAgICB0aGlzLmNvbm5lY3Rpb25zUmVhZHlUaW1lb3V0ID0gbnVsbDtcblxuICAgICAgICB0aGlzLmJyb3dzZXJFcnJvckhhbmRsZXIgPSBlcnJvciA9PiB0aGlzLmVtaXQoJ2Vycm9yJywgZXJyb3IpO1xuXG4gICAgICAgIHRoaXMuYnJvd3NlckNvbm5lY3Rpb25zLmZvckVhY2goYmMgPT4gYmMub24oJ2Vycm9yJywgdGhpcy5icm93c2VyRXJyb3JIYW5kbGVyKSk7XG5cbiAgICAgICAgLy8gTk9URTogV2UncmUgc2V0dGluZyBhbiBlbXB0eSBlcnJvciBoYW5kbGVyLCBiZWNhdXNlIE5vZGUga2lsbHMgdGhlIHByb2Nlc3Mgb24gYW4gJ2Vycm9yJyBldmVudFxuICAgICAgICAvLyBpZiB0aGVyZSBpcyBubyBoYW5kbGVyLiBTZWU6IGh0dHBzOi8vbm9kZWpzLm9yZy9hcGkvZXZlbnRzLmh0bWwjZXZlbnRzX2NsYXNzX2V2ZW50c19ldmVudGVtaXR0ZXJcbiAgICAgICAgdGhpcy5vbignZXJyb3InLCBub29wKTtcbiAgICB9XG5cbiAgICBzdGF0aWMgYXN5bmMgX3dhaXRJZGxlIChiYykge1xuICAgICAgICBpZiAoYmMuaWRsZSB8fCAhYmMucmVhZHkpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgYXdhaXQgcHJvbWlzaWZ5RXZlbnQoYmMsICdpZGxlJyk7XG4gICAgfVxuXG4gICAgc3RhdGljIGFzeW5jIF9jbG9zZUNvbm5lY3Rpb24gKGJjKSB7XG4gICAgICAgIGlmIChiYy5jbG9zZWQgfHwgIWJjLnJlYWR5KVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIGJjLmNsb3NlKCk7XG5cbiAgICAgICAgYXdhaXQgcHJvbWlzaWZ5RXZlbnQoYmMsICdjbG9zZWQnKTtcbiAgICB9XG5cbiAgICBhc3luYyBfZ2V0UmVhZHlUaW1lb3V0ICgpIHtcbiAgICAgICAgY29uc3QgaXNMb2NhbEJyb3dzZXIgICAgICA9IGNvbm5lY3Rpb24gPT4gY29ubmVjdGlvbi5wcm92aWRlci5pc0xvY2FsQnJvd3Nlcihjb25uZWN0aW9uLmlkLCBjb25uZWN0aW9uLmJyb3dzZXJJbmZvLmJyb3dzZXJOYW1lKTtcbiAgICAgICAgY29uc3QgcmVtb3RlQnJvd3NlcnNFeGlzdCA9IChhd2FpdCBQcm9taXNlLmFsbCh0aGlzLmJyb3dzZXJDb25uZWN0aW9ucy5tYXAoaXNMb2NhbEJyb3dzZXIpKSkuaW5kZXhPZihmYWxzZSkgPiAtMTtcblxuICAgICAgICByZXR1cm4gcmVtb3RlQnJvd3NlcnNFeGlzdCA/IFJFTU9URV9CUk9XU0VSU19SRUFEWV9USU1FT1VUIDogTE9DQUxfQlJPV1NFUlNfUkVBRFlfVElNRU9VVDtcbiAgICB9XG5cbiAgICBfY3JlYXRlUGVuZGluZ0Nvbm5lY3Rpb25Qcm9taXNlIChyZWFkeVByb21pc2UsIHRpbWVvdXQsIHRpbWVvdXRFcnJvcikge1xuICAgICAgICBjb25zdCB0aW1lb3V0UHJvbWlzZSA9IG5ldyBQcm9taXNlKChfLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbnNSZWFkeVRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHJlamVjdCh0aW1lb3V0RXJyb3IpLCB0aW1lb3V0KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIFByb21pc2VcbiAgICAgICAgICAgIC5yYWNlKFtyZWFkeVByb21pc2UsIHRpbWVvdXRQcm9taXNlXSlcbiAgICAgICAgICAgIC50aGVuKFxuICAgICAgICAgICAgICAgIHZhbHVlID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uc1JlYWR5VGltZW91dC51bnJlZigpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBlcnJvciA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbnNSZWFkeVRpbWVvdXQudW5yZWYoKTtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICB9XG5cbiAgICBhc3luYyBfd2FpdENvbm5lY3Rpb25zT3BlbmVkICgpIHtcbiAgICAgICAgY29uc3QgY29ubmVjdGlvbnNSZWFkeVByb21pc2UgPSBQcm9taXNlLmFsbChcbiAgICAgICAgICAgIHRoaXMuYnJvd3NlckNvbm5lY3Rpb25zXG4gICAgICAgICAgICAgICAgLmZpbHRlcihiYyA9PiAhYmMub3BlbmVkKVxuICAgICAgICAgICAgICAgIC5tYXAoYmMgPT4gcHJvbWlzaWZ5RXZlbnQoYmMsICdvcGVuZWQnKSlcbiAgICAgICAgKTtcblxuICAgICAgICBjb25zdCB0aW1lb3V0RXJyb3IgPSBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLmNhbm5vdEVzdGFibGlzaEJyb3dzZXJDb25uZWN0aW9uKTtcbiAgICAgICAgY29uc3QgcmVhZHlUaW1lb3V0ID0gYXdhaXQgdGhpcy5fZ2V0UmVhZHlUaW1lb3V0KCk7XG5cbiAgICAgICAgYXdhaXQgdGhpcy5fY3JlYXRlUGVuZGluZ0Nvbm5lY3Rpb25Qcm9taXNlKGNvbm5lY3Rpb25zUmVhZHlQcm9taXNlLCByZWFkeVRpbWVvdXQsIHRpbWVvdXRFcnJvcik7XG4gICAgfVxuXG4gICAgX2NoZWNrRm9yRGlzY29ubmVjdGlvbnMgKCkge1xuICAgICAgICBjb25zdCBkaXNjb25uZWN0ZWRVc2VyQWdlbnRzID0gdGhpcy5icm93c2VyQ29ubmVjdGlvbnNcbiAgICAgICAgICAgIC5maWx0ZXIoYmMgPT4gYmMuY2xvc2VkKVxuICAgICAgICAgICAgLm1hcChiYyA9PiBiYy51c2VyQWdlbnQpO1xuXG4gICAgICAgIGlmIChkaXNjb25uZWN0ZWRVc2VyQWdlbnRzLmxlbmd0aClcbiAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMuY2Fubm90UnVuQWdhaW5zdERpc2Nvbm5lY3RlZEJyb3dzZXJzLCBkaXNjb25uZWN0ZWRVc2VyQWdlbnRzLmpvaW4oJywgJykpO1xuICAgIH1cblxuXG4gICAgLy9BUElcbiAgICBzdGF0aWMgZnJvbSAoYnJvd3NlckNvbm5lY3Rpb25zKSB7XG4gICAgICAgIGNvbnN0IGJyb3dzZXJTZXQgPSBuZXcgQnJvd3NlclNldChicm93c2VyQ29ubmVjdGlvbnMpO1xuXG4gICAgICAgIGNvbnN0IHByZXBhcmVDb25uZWN0aW9uID0gUHJvbWlzZS5yZXNvbHZlKClcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICBicm93c2VyU2V0Ll9jaGVja0ZvckRpc2Nvbm5lY3Rpb25zKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGJyb3dzZXJTZXQuX3dhaXRDb25uZWN0aW9uc09wZW5lZCgpO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC50aGVuKCgpID0+IGJyb3dzZXJTZXQpO1xuXG4gICAgICAgIHJldHVybiBQcm9taXNlXG4gICAgICAgICAgICAucmFjZShbXG4gICAgICAgICAgICAgICAgcHJlcGFyZUNvbm5lY3Rpb24sXG4gICAgICAgICAgICAgICAgcHJvbWlzaWZ5RXZlbnQoYnJvd3NlclNldCwgJ2Vycm9yJylcbiAgICAgICAgICAgIF0pXG4gICAgICAgICAgICAuY2F0Y2goYXN5bmMgZXJyb3IgPT4ge1xuICAgICAgICAgICAgICAgIGF3YWl0IGJyb3dzZXJTZXQuZGlzcG9zZSgpO1xuXG4gICAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgICAgICB9KTtcbiAgICB9XG5cbiAgICByZWxlYXNlQ29ubmVjdGlvbiAoYmMpIHtcbiAgICAgICAgaWYgKHRoaXMuYnJvd3NlckNvbm5lY3Rpb25zLmluZGV4T2YoYmMpIDwgMClcbiAgICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcblxuICAgICAgICByZW1vdmUodGhpcy5icm93c2VyQ29ubmVjdGlvbnMsIGJjKTtcblxuICAgICAgICBiYy5yZW1vdmVMaXN0ZW5lcignZXJyb3InLCB0aGlzLmJyb3dzZXJFcnJvckhhbmRsZXIpO1xuXG4gICAgICAgIGNvbnN0IGFwcHJvcHJpYXRlU3RhdGVTd2l0Y2ggPSAhYmMucGVybWFuZW50ID9cbiAgICAgICAgICAgIEJyb3dzZXJTZXQuX2Nsb3NlQ29ubmVjdGlvbihiYykgOlxuICAgICAgICAgICAgQnJvd3NlclNldC5fd2FpdElkbGUoYmMpO1xuXG4gICAgICAgIGNvbnN0IHJlbGVhc2UgPSBnZXRUaW1lTGltaXRlZFByb21pc2UoYXBwcm9wcmlhdGVTdGF0ZVN3aXRjaCwgdGhpcy5SRUxFQVNFX1RJTUVPVVQpLnRoZW4oKCkgPT4gcmVtb3ZlKHRoaXMucGVuZGluZ1JlbGVhc2VzLCByZWxlYXNlKSk7XG5cbiAgICAgICAgdGhpcy5wZW5kaW5nUmVsZWFzZXMucHVzaChyZWxlYXNlKTtcblxuICAgICAgICByZXR1cm4gcmVsZWFzZTtcbiAgICB9XG5cbiAgICBhc3luYyBkaXNwb3NlICgpIHtcbiAgICAgICAgLy8gTk9URTogV2hlbiBicm93c2VyQ29ubmVjdGlvbiBpcyBjYW5jZWxsZWQsIGl0IGlzIHJlbW92ZWQgZnJvbVxuICAgICAgICAvLyB0aGUgdGhpcy5jb25uZWN0aW9ucyBhcnJheSwgd2hpY2ggbGVhZHMgdG8gc2hpZnRpbmcgaW5kZXhlc1xuICAgICAgICAvLyB0b3dhcmRzIHRoZSBiZWdpbm5pbmcuIFNvLCB3ZSBtdXN0IGNvcHkgdGhlIGFycmF5IGluIG9yZGVyIHRvIGl0ZXJhdGUgaXQsXG4gICAgICAgIC8vIG9yIHdlIGNhbiBwZXJmb3JtIGl0ZXJhdGlvbiBmcm9tIHRoZSBlbmQgdG8gdGhlIGJlZ2lubmluZy5cbiAgICAgICAgaWYgKHRoaXMuY29ubmVjdGlvbnNSZWFkeVRpbWVvdXQpXG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb25zUmVhZHlUaW1lb3V0LnVucmVmKCk7XG5cbiAgICAgICAgbWFwUmV2ZXJzZSh0aGlzLmJyb3dzZXJDb25uZWN0aW9ucywgYmMgPT4gdGhpcy5yZWxlYXNlQ29ubmVjdGlvbihiYykpO1xuXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKHRoaXMucGVuZGluZ1JlbGVhc2VzKTtcbiAgICB9XG59XG4iXX0= |
\ | No newline at end of file |