UNPKG

testcafe

Version:

Automated browser testing for the modern web development stack.

242 lines 39.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const pinkie_1 = __importDefault(require("pinkie")); const testcafe_browser_tools_1 = __importDefault(require("testcafe-browser-tools")); const os_family_1 = __importDefault(require("os-family")); const connection_1 = __importDefault(require("../connection")); const delay_1 = __importDefault(require("../../utils/delay")); const client_functions_1 = require("./utils/client-functions"); const BROWSER_OPENING_DELAY = 2000; const RESIZE_DIFF_SIZE = { width: 100, height: 100 }; function sumSizes(sizeA, sizeB) { return { width: sizeA.width + sizeB.width, height: sizeA.height + sizeB.height }; } function subtractSizes(sizeA, sizeB) { return { width: sizeA.width - sizeB.width, height: sizeA.height - sizeB.height }; } class BrowserProvider { constructor(plugin) { this.plugin = plugin; this.initPromise = pinkie_1.default.resolve(false); this.isMultiBrowser = this.plugin.isMultiBrowser; // HACK: The browser window has different border sizes in normal and maximized modes. So, we need to be sure that the window is // not maximized before resizing it in order to keep the mechanism of correcting the client area size working. When browser is started, // we are resizing it for the first time to switch the window to normal mode, and for the second time - to restore the client area size. this.localBrowsersInfo = {}; } _createLocalBrowserInfo(browserId) { if (this.localBrowsersInfo[browserId]) return; this.localBrowsersInfo[browserId] = { windowDescriptor: null, maxScreenSize: null, resizeCorrections: null }; } _getWindowDescriptor(browserId) { return this.localBrowsersInfo[browserId] && this.localBrowsersInfo[browserId].windowDescriptor; } _getMaxScreenSize(browserId) { return this.localBrowsersInfo[browserId] && this.localBrowsersInfo[browserId].maxScreenSize; } _getResizeCorrections(browserId) { return this.localBrowsersInfo[browserId] && this.localBrowsersInfo[browserId].resizeCorrections; } _isBrowserIdle(browserId) { const connection = connection_1.default.getById(browserId); return connection.idle; } async _calculateResizeCorrections(browserId) { if (!this._isBrowserIdle(browserId)) return; const title = await this.plugin.runInitScript(browserId, client_functions_1.GET_TITLE_SCRIPT); if (!await testcafe_browser_tools_1.default.isMaximized(title)) return; const currentSize = await this.plugin.runInitScript(browserId, client_functions_1.GET_WINDOW_DIMENSIONS_INFO_SCRIPT); const etalonSize = subtractSizes(currentSize, RESIZE_DIFF_SIZE); await testcafe_browser_tools_1.default.resize(title, currentSize.width, currentSize.height, etalonSize.width, etalonSize.height); let resizedSize = await this.plugin.runInitScript(browserId, client_functions_1.GET_WINDOW_DIMENSIONS_INFO_SCRIPT); let correctionSize = subtractSizes(resizedSize, etalonSize); await testcafe_browser_tools_1.default.resize(title, resizedSize.width, resizedSize.height, etalonSize.width, etalonSize.height); resizedSize = await this.plugin.runInitScript(browserId, client_functions_1.GET_WINDOW_DIMENSIONS_INFO_SCRIPT); correctionSize = sumSizes(correctionSize, subtractSizes(resizedSize, etalonSize)); if (this.localBrowsersInfo[browserId]) this.localBrowsersInfo[browserId].resizeCorrections = correctionSize; await testcafe_browser_tools_1.default.maximize(title); } async _calculateMacSizeLimits(browserId) { if (!this._isBrowserIdle(browserId)) return; const sizeInfo = await this.plugin.runInitScript(browserId, client_functions_1.GET_WINDOW_DIMENSIONS_INFO_SCRIPT); if (this.localBrowsersInfo[browserId]) { this.localBrowsersInfo[browserId].maxScreenSize = { width: sizeInfo.availableWidth - (sizeInfo.outerWidth - sizeInfo.width), height: sizeInfo.availableHeight - (sizeInfo.outerHeight - sizeInfo.height) }; } } async _ensureBrowserWindowDescriptor(browserId) { if (this._getWindowDescriptor(browserId)) return; await this._createLocalBrowserInfo(browserId); // NOTE: delay to ensure the window finished the opening await this.plugin.waitForConnectionReady(browserId); await delay_1.default(BROWSER_OPENING_DELAY); if (this.localBrowsersInfo[browserId]) this.localBrowsersInfo[browserId].windowDescriptor = await testcafe_browser_tools_1.default.findWindow(browserId); } async _ensureBrowserWindowParameters(browserId) { await this._ensureBrowserWindowDescriptor(browserId); if (os_family_1.default.win && !this._getResizeCorrections(browserId)) await this._calculateResizeCorrections(browserId); else if (os_family_1.default.mac && !this._getMaxScreenSize(browserId)) await this._calculateMacSizeLimits(browserId); } async _closeLocalBrowser(browserId) { await testcafe_browser_tools_1.default.close(this._getWindowDescriptor(browserId)); } async _resizeLocalBrowserWindow(browserId, width, height, currentWidth, currentHeight) { const resizeCorrections = this._getResizeCorrections(browserId); if (resizeCorrections && await testcafe_browser_tools_1.default.isMaximized(this._getWindowDescriptor(browserId))) { width -= resizeCorrections.width; height -= resizeCorrections.height; } await testcafe_browser_tools_1.default.resize(this._getWindowDescriptor(browserId), currentWidth, currentHeight, width, height); } async _takeLocalBrowserScreenshot(browserId, screenshotPath) { await testcafe_browser_tools_1.default.screenshot(this._getWindowDescriptor(browserId), screenshotPath); } async _canResizeLocalBrowserWindowToDimensions(browserId, width, height) { if (!os_family_1.default.mac) return true; const maxScreenSize = this._getMaxScreenSize(browserId); return width <= maxScreenSize.width && height <= maxScreenSize.height; } async _maximizeLocalBrowserWindow(browserId) { await testcafe_browser_tools_1.default.maximize(this._getWindowDescriptor(browserId)); } async _canUseDefaultWindowActions(browserId) { const isLocalBrowser = await this.plugin.isLocalBrowser(browserId); const isHeadlessBrowser = await this.plugin.isHeadlessBrowser(browserId); return isLocalBrowser && !isHeadlessBrowser; } async init() { const initialized = await this.initPromise; if (initialized) return; this.initPromise = this.plugin .init() .then(() => true); try { await this.initPromise; } catch (error) { this.initPromise = pinkie_1.default.resolve(false); throw error; } } async dispose() { const initialized = await this.initPromise; if (!initialized) return; this.initPromise = this.plugin .dispose() .then(() => false); try { await this.initPromise; } catch (error) { this.initPromise = pinkie_1.default.resolve(false); throw error; } } async isLocalBrowser(browserId, browserName) { return await this.plugin.isLocalBrowser(browserId, browserName); } isHeadlessBrowser(browserId) { return this.plugin.isHeadlessBrowser(browserId); } async openBrowser(browserId, pageUrl, browserName) { await this.plugin.openBrowser(browserId, pageUrl, browserName); if (await this._canUseDefaultWindowActions(browserId)) await this._ensureBrowserWindowParameters(browserId); } async closeBrowser(browserId) { const canUseDefaultWindowActions = await this._canUseDefaultWindowActions(browserId); const customActionsInfo = await this.hasCustomActionForBrowser(browserId); const hasCustomCloseBrowser = customActionsInfo.hasCloseBrowser; const usePluginsCloseBrowser = hasCustomCloseBrowser || !canUseDefaultWindowActions; if (usePluginsCloseBrowser) await this.plugin.closeBrowser(browserId); else await this._closeLocalBrowser(browserId); if (canUseDefaultWindowActions) delete this.localBrowsersInfo[browserId]; } async getBrowserList() { return await this.plugin.getBrowserList(); } async isValidBrowserName(browserName) { return await this.plugin.isValidBrowserName(browserName); } async resizeWindow(browserId, width, height, currentWidth, currentHeight) { const canUseDefaultWindowActions = await this._canUseDefaultWindowActions(browserId); const customActionsInfo = await this.hasCustomActionForBrowser(browserId); const hasCustomResizeWindow = customActionsInfo.hasResizeWindow; if (canUseDefaultWindowActions && !hasCustomResizeWindow) { await this._resizeLocalBrowserWindow(browserId, width, height, currentWidth, currentHeight); return; } await this.plugin.resizeWindow(browserId, width, height, currentWidth, currentHeight); } async canResizeWindowToDimensions(browserId, width, height) { const canUseDefaultWindowActions = await this._canUseDefaultWindowActions(browserId); const customActionsInfo = await this.hasCustomActionForBrowser(browserId); const hasCustomCanResizeToDimensions = customActionsInfo.hasCanResizeWindowToDimensions; if (canUseDefaultWindowActions && !hasCustomCanResizeToDimensions) return await this._canResizeLocalBrowserWindowToDimensions(browserId, width, height); return await this.plugin.canResizeWindowToDimensions(browserId, width, height); } async maximizeWindow(browserId) { const canUseDefaultWindowActions = await this._canUseDefaultWindowActions(browserId); const customActionsInfo = await this.hasCustomActionForBrowser(browserId); const hasCustomMaximizeWindow = customActionsInfo.hasMaximizeWindow; if (canUseDefaultWindowActions && !hasCustomMaximizeWindow) return await this._maximizeLocalBrowserWindow(browserId); return await this.plugin.maximizeWindow(browserId); } async takeScreenshot(browserId, screenshotPath, pageWidth, pageHeight) { const canUseDefaultWindowActions = await this._canUseDefaultWindowActions(browserId); const customActionsInfo = await this.hasCustomActionForBrowser(browserId); const hasCustomTakeScreenshot = customActionsInfo.hasTakeScreenshot; if (canUseDefaultWindowActions && !hasCustomTakeScreenshot) { await this._takeLocalBrowserScreenshot(browserId, screenshotPath, pageWidth, pageHeight); return; } await this.plugin.takeScreenshot(browserId, screenshotPath, pageWidth, pageHeight); } async getVideoFrameData(browserId) { return this.plugin.getVideoFrameData(browserId); } async hasCustomActionForBrowser(browserId) { return this.plugin.hasCustomActionForBrowser(browserId); } async reportJobResult(browserId, status, data) { await this.plugin.reportJobResult(browserId, status, data); } } exports.default = BrowserProvider; module.exports = exports.default; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYnJvd3Nlci9wcm92aWRlci9pbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLG9EQUE2QjtBQUM3QixvRkFBa0Q7QUFDbEQsMERBQTJCO0FBQzNCLCtEQUE4QztBQUM5Qyw4REFBc0M7QUFDdEMsK0RBQStGO0FBRy9GLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxDQUFDO0FBRW5DLE1BQU0sZ0JBQWdCLEdBQUc7SUFDckIsS0FBSyxFQUFHLEdBQUc7SUFDWCxNQUFNLEVBQUUsR0FBRztDQUNkLENBQUM7QUFHRixTQUFTLFFBQVEsQ0FBRSxLQUFLLEVBQUUsS0FBSztJQUMzQixPQUFPO1FBQ0gsS0FBSyxFQUFHLEtBQUssQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUs7UUFDakMsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU07S0FDdEMsQ0FBQztBQUNOLENBQUM7QUFFRCxTQUFTLGFBQWEsQ0FBRSxLQUFLLEVBQUUsS0FBSztJQUNoQyxPQUFPO1FBQ0gsS0FBSyxFQUFHLEtBQUssQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUs7UUFDakMsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU07S0FDdEMsQ0FBQztBQUNOLENBQUM7QUFFRCxNQUFxQixlQUFlO0lBQ2hDLFlBQWEsTUFBTTtRQUNmLElBQUksQ0FBQyxNQUFNLEdBQVEsTUFBTSxDQUFDO1FBQzFCLElBQUksQ0FBQyxXQUFXLEdBQUcsZ0JBQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFMUMsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQztRQUNqRCwrSEFBK0g7UUFDL0gsdUlBQXVJO1FBQ3ZJLHdJQUF3STtRQUN4SSxJQUFJLENBQUMsaUJBQWlCLEdBQUcs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QUFNLElBQUksQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLFNBQVMsRUFBRSxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDL0QsQ0FBQztDQUNKO0FBOVJELGtDQThSQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBQcm9taXNlIGZyb20gJ3BpbmtpZSc7XG5pbXBvcnQgYnJvd3NlclRvb2xzIGZyb20gJ3Rlc3RjYWZlLWJyb3dzZXItdG9vbHMnO1xuaW1wb3J0IE9TIGZyb20gJ29zLWZhbWlseSc7XG5pbXBvcnQgQnJvd3NlckNvbm5lY3Rpb24gZnJvbSAnLi4vY29ubmVjdGlvbic7XG5pbXBvcnQgZGVsYXkgZnJvbSAnLi4vLi4vdXRpbHMvZGVsYXknO1xuaW1wb3J0IHsgR0VUX1RJVExFX1NDUklQVCwgR0VUX1dJTkRPV19ESU1FTlNJT05TX0lORk9fU0NSSVBUIH0gZnJvbSAnLi91dGlscy9jbGllbnQtZnVuY3Rpb25zJztcblxuXG5jb25zdCBCUk9XU0VSX09QRU5JTkdfREVMQVkgPSAyMDAwO1xuXG5jb25zdCBSRVNJWkVfRElGRl9TSVpFID0ge1xuICAgIHdpZHRoOiAgMTAwLFxuICAgIGhlaWdodDogMTAwXG59O1xuXG5cbmZ1bmN0aW9uIHN1bVNpemVzIChzaXplQSwgc2l6ZUIpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICB3aWR0aDogIHNpemVBLndpZHRoICsgc2l6ZUIud2lkdGgsXG4gICAgICAgIGhlaWdodDogc2l6ZUEuaGVpZ2h0ICsgc2l6ZUIuaGVpZ2h0XG4gICAgfTtcbn1cblxuZnVuY3Rpb24gc3VidHJhY3RTaXplcyAoc2l6ZUEsIHNpemVCKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgd2lkdGg6ICBzaXplQS53aWR0aCAtIHNpemVCLndpZHRoLFxuICAgICAgICBoZWlnaHQ6IHNpemVBLmhlaWdodCAtIHNpemVCLmhlaWdodFxuICAgIH07XG59XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEJyb3dzZXJQcm92aWRlciB7XG4gICAgY29uc3RydWN0b3IgKHBsdWdpbikge1xuICAgICAgICB0aGlzLnBsdWdpbiAgICAgID0gcGx1Z2luO1xuICAgICAgICB0aGlzLmluaXRQcm9taXNlID0gUHJvbWlzZS5yZXNvbHZlKGZhbHNlKTtcblxuICAgICAgICB0aGlzLmlzTXVsdGlCcm93c2VyID0gdGhpcy5wbHVnaW4uaXNNdWx0aUJyb3dzZXI7XG4gICAgICAgIC8vIEhBQ0s6IFRoZSBicm93c2VyIHdpbmRvdyBoYXMgZGlmZmVyZW50IGJvcmRlciBzaXplcyBpbiBub3JtYWwgYW5kIG1heGltaXplZCBtb2Rlcy4gU28sIHdlIG5lZWQgdG8gYmUgc3VyZSB0aGF0IHRoZSB3aW5kb3cgaXNcbiAgICAgICAgLy8gbm90IG1heGltaXplZCBiZWZvcmUgcmVzaXppbmcgaXQgaW4gb3JkZXIgdG8ga2VlcCB0aGUgbWVjaGFuaXNtIG9mIGNvcnJlY3RpbmcgdGhlIGNsaWVudCBhcmVhIHNpemUgd29ya2luZy4gV2hlbiBicm93c2VyIGlzIHN0YXJ0ZWQsXG4gICAgICAgIC8vIHdlIGFyZSByZXNpemluZyBpdCBmb3IgdGhlIGZpcnN0IHRpbWUgdG8gc3dpdGNoIHRoZSB3aW5kb3cgdG8gbm9ybWFsIG1vZGUsIGFuZCBmb3IgdGhlIHNlY29uZCB0aW1lIC0gdG8gcmVzdG9yZSB0aGUgY2xpZW50IGFyZWEgc2l6ZS5cbiAgICAgICAgdGhpcy5sb2NhbEJyb3dzZXJzSW5mbyA9IHt9O1xuICAgIH1cblxuICAgIF9jcmVhdGVMb2NhbEJyb3dzZXJJbmZvIChicm93c2VySWQpIHtcbiAgICAgICAgaWYgKHRoaXMubG9jYWxCcm93c2Vyc0luZm9bYnJvd3NlcklkXSlcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICB0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0gPSB7XG4gICAgICAgICAgICB3aW5kb3dEZXNjcmlwdG9yOiAgbnVsbCxcbiAgICAgICAgICAgIG1heFNjcmVlblNpemU6ICAgICBudWxsLFxuICAgICAgICAgICAgcmVzaXplQ29ycmVjdGlvbnM6IG51bGxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBfZ2V0V2luZG93RGVzY3JpcHRvciAoYnJvd3NlcklkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0gJiYgdGhpcy5sb2NhbEJyb3dzZXJzSW5mb1ticm93c2VySWRdLndpbmRvd0Rlc2NyaXB0b3I7XG4gICAgfVxuXG4gICAgX2dldE1heFNjcmVlblNpemUgKGJyb3dzZXJJZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5sb2NhbEJyb3dzZXJzSW5mb1ticm93c2VySWRdICYmIHRoaXMubG9jYWxCcm93c2Vyc0luZm9bYnJvd3NlcklkXS5tYXhTY3JlZW5TaXplO1xuICAgIH1cblxuICAgIF9nZXRSZXNpemVDb3JyZWN0aW9ucyAoYnJvd3NlcklkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0gJiYgdGhpcy5sb2NhbEJyb3dzZXJzSW5mb1ticm93c2VySWRdLnJlc2l6ZUNvcnJlY3Rpb25zO1xuICAgIH1cblxuICAgIF9pc0Jyb3dzZXJJZGxlIChicm93c2VySWQpIHtcbiAgICAgICAgY29uc3QgY29ubmVjdGlvbiA9IEJyb3dzZXJDb25uZWN0aW9uLmdldEJ5SWQoYnJvd3NlcklkKTtcblxuICAgICAgICByZXR1cm4gY29ubmVjdGlvbi5pZGxlO1xuICAgIH1cblxuICAgIGFzeW5jIF9jYWxjdWxhdGVSZXNpemVDb3JyZWN0aW9ucyAoYnJvd3NlcklkKSB7XG4gICAgICAgIGlmICghdGhpcy5faXNCcm93c2VySWRsZShicm93c2VySWQpKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIGNvbnN0IHRpdGxlID0gYXdhaXQgdGhpcy5wbHVnaW4ucnVuSW5pdFNjcmlwdChicm93c2VySWQsIEdFVF9USVRMRV9TQ1JJUFQpO1xuXG4gICAgICAgIGlmICghYXdhaXQgYnJvd3NlclRvb2xzLmlzTWF4aW1pemVkKHRpdGxlKSlcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICBjb25zdCBjdXJyZW50U2l6ZSA9IGF3YWl0IHRoaXMucGx1Z2luLnJ1bkluaXRTY3JpcHQoYnJvd3NlcklkLCBHRVRfV0lORE9XX0RJTUVOU0lPTlNfSU5GT19TQ1JJUFQpO1xuICAgICAgICBjb25zdCBldGFsb25TaXplICA9IHN1YnRyYWN0U2l6ZXMoY3VycmVudFNpemUsIFJFU0laRV9ESUZGX1NJWkUpO1xuXG4gICAgICAgIGF3YWl0IGJyb3dzZXJUb29scy5yZXNpemUodGl0bGUsIGN1cnJlbnRTaXplLndpZHRoLCBjdXJyZW50U2l6ZS5oZWlnaHQsIGV0YWxvblNpemUud2lkdGgsIGV0YWxvblNpemUuaGVpZ2h0KTtcblxuICAgICAgICBsZXQgcmVzaXplZFNpemUgICAgPSBhd2FpdCB0aGlzLnBsdWdpbi5ydW5Jbml0U2NyaXB0KGJyb3dzZXJJZCwgR0VUX1dJTkRPV19ESU1FTlNJT05TX0lORk9fU0NSSVBUKTtcbiAgICAgICAgbGV0IGNvcnJlY3Rpb25TaXplID0gc3VidHJhY3RTaXplcyhyZXNpemVkU2l6ZSwgZXRhbG9uU2l6ZSk7XG5cbiAgICAgICAgYXdhaXQgYnJvd3NlclRvb2xzLnJlc2l6ZSh0aXRsZSwgcmVzaXplZFNpemUud2lkdGgsIHJlc2l6ZWRTaXplLmhlaWdodCwgZXRhbG9uU2l6ZS53aWR0aCwgZXRhbG9uU2l6ZS5oZWlnaHQpO1xuXG4gICAgICAgIHJlc2l6ZWRTaXplID0gYXdhaXQgdGhpcy5wbHVnaW4ucnVuSW5pdFNjcmlwdChicm93c2VySWQsIEdFVF9XSU5ET1dfRElNRU5TSU9OU19JTkZPX1NDUklQVCk7XG5cbiAgICAgICAgY29ycmVjdGlvblNpemUgPSBzdW1TaXplcyhjb3JyZWN0aW9uU2l6ZSwgc3VidHJhY3RTaXplcyhyZXNpemVkU2l6ZSwgZXRhbG9uU2l6ZSkpO1xuXG4gICAgICAgIGlmICh0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0pXG4gICAgICAgICAgICB0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0ucmVzaXplQ29ycmVjdGlvbnMgPSBjb3JyZWN0aW9uU2l6ZTtcblxuICAgICAgICBhd2FpdCBicm93c2VyVG9vbHMubWF4aW1pemUodGl0bGUpO1xuICAgIH1cblxuXG4gICAgYXN5bmMgX2NhbGN1bGF0ZU1hY1NpemVMaW1pdHMgKGJyb3dzZXJJZCkge1xuICAgICAgICBpZiAoIXRoaXMuX2lzQnJvd3NlcklkbGUoYnJvd3NlcklkKSlcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICBjb25zdCBzaXplSW5mbyA9IGF3YWl0IHRoaXMucGx1Z2luLnJ1bkluaXRTY3JpcHQoYnJvd3NlcklkLCBHRVRfV0lORE9XX0RJTUVOU0lPTlNfSU5GT19TQ1JJUFQpO1xuXG4gICAgICAgIGlmICh0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0pIHtcbiAgICAgICAgICAgIHRoaXMubG9jYWxCcm93c2Vyc0luZm9bYnJvd3NlcklkXS5tYXhTY3JlZW5TaXplID0ge1xuICAgICAgICAgICAgICAgIHdpZHRoOiAgc2l6ZUluZm8uYXZhaWxhYmxlV2lkdGggLSAoc2l6ZUluZm8ub3V0ZXJXaWR0aCAtIHNpemVJbmZvLndpZHRoKSxcbiAgICAgICAgICAgICAgICBoZWlnaHQ6IHNpemVJbmZvLmF2YWlsYWJsZUhlaWdodCAtIChzaXplSW5mby5vdXRlckhlaWdodCAtIHNpemVJbmZvLmhlaWdodClcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhc3luYyBfZW5zdXJlQnJvd3NlcldpbmRvd0Rlc2NyaXB0b3IgKGJyb3dzZXJJZCkge1xuICAgICAgICBpZiAodGhpcy5fZ2V0V2luZG93RGVzY3JpcHRvcihicm93c2VySWQpKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIGF3YWl0IHRoaXMuX2NyZWF0ZUxvY2FsQnJvd3NlckluZm8oYnJvd3NlcklkKTtcblxuICAgICAgICAvLyBOT1RFOiBkZWxheSB0byBlbnN1cmUgdGhlIHdpbmRvdyBmaW5pc2hlZCB0aGUgb3BlbmluZ1xuICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi53YWl0Rm9yQ29ubmVjdGlvblJlYWR5KGJyb3dzZXJJZCk7XG4gICAgICAgIGF3YWl0IGRlbGF5KEJST1dTRVJfT1BFTklOR19ERUxBWSk7XG5cbiAgICAgICAgaWYgKHRoaXMubG9jYWxCcm93c2Vyc0luZm9bYnJvd3NlcklkXSlcbiAgICAgICAgICAgIHRoaXMubG9jYWxCcm93c2Vyc0luZm9bYnJvd3NlcklkXS53aW5kb3dEZXNjcmlwdG9yID0gYXdhaXQgYnJvd3NlclRvb2xzLmZpbmRXaW5kb3coYnJvd3NlcklkKTtcbiAgICB9XG5cbiAgICBhc3luYyBfZW5zdXJlQnJvd3NlcldpbmRvd1BhcmFtZXRlcnMgKGJyb3dzZXJJZCkge1xuICAgICAgICBhd2FpdCB0aGlzLl9lbnN1cmVCcm93c2VyV2luZG93RGVzY3JpcHRvcihicm93c2VySWQpO1xuXG4gICAgICAgIGlmIChPUy53aW4gJiYgIXRoaXMuX2dldFJlc2l6ZUNvcnJlY3Rpb25zKGJyb3dzZXJJZCkpXG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9jYWxjdWxhdGVSZXNpemVDb3JyZWN0aW9ucyhicm93c2VySWQpO1xuICAgICAgICBlbHNlIGlmIChPUy5tYWMgJiYgIXRoaXMuX2dldE1heFNjcmVlblNpemUoYnJvd3NlcklkKSlcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX2NhbGN1bGF0ZU1hY1NpemVMaW1pdHMoYnJvd3NlcklkKTtcbiAgICB9XG5cbiAgICBhc3luYyBfY2xvc2VMb2NhbEJyb3dzZXIgKGJyb3dzZXJJZCkge1xuICAgICAgICBhd2FpdCBicm93c2VyVG9vbHMuY2xvc2UodGhpcy5fZ2V0V2luZG93RGVzY3JpcHRvcihicm93c2VySWQpKTtcbiAgICB9XG5cbiAgICBhc3luYyBfcmVzaXplTG9jYWxCcm93c2VyV2luZG93IChicm93c2VySWQsIHdpZHRoLCBoZWlnaHQsIGN1cnJlbnRXaWR0aCwgY3VycmVudEhlaWdodCkge1xuICAgICAgICBjb25zdCByZXNpemVDb3JyZWN0aW9ucyA9IHRoaXMuX2dldFJlc2l6ZUNvcnJlY3Rpb25zKGJyb3dzZXJJZCk7XG5cbiAgICAgICAgaWYgKHJlc2l6ZUNvcnJlY3Rpb25zICYmIGF3YWl0IGJyb3dzZXJUb29scy5pc01heGltaXplZCh0aGlzLl9nZXRXaW5kb3dEZXNjcmlwdG9yKGJyb3dzZXJJZCkpKSB7XG4gICAgICAgICAgICB3aWR0aCAtPSByZXNpemVDb3JyZWN0aW9ucy53aWR0aDtcbiAgICAgICAgICAgIGhlaWdodCAtPSByZXNpemVDb3JyZWN0aW9ucy5oZWlnaHQ7XG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCBicm93c2VyVG9vbHMucmVzaXplKHRoaXMuX2dldFdpbmRvd0Rlc2NyaXB0b3IoYnJvd3NlcklkKSwgY3VycmVudFdpZHRoLCBjdXJyZW50SGVpZ2h0LCB3aWR0aCwgaGVpZ2h0KTtcbiAgICB9XG5cbiAgICBhc3luYyBfdGFrZUxvY2FsQnJvd3NlclNjcmVlbnNob3QgKGJyb3dzZXJJZCwgc2NyZWVuc2hvdFBhdGgpIHtcbiAgICAgICAgYXdhaXQgYnJvd3NlclRvb2xzLnNjcmVlbnNob3QodGhpcy5fZ2V0V2luZG93RGVzY3JpcHRvcihicm93c2VySWQpLCBzY3JlZW5zaG90UGF0aCk7XG4gICAgfVxuXG4gICAgYXN5bmMgX2NhblJlc2l6ZUxvY2FsQnJvd3NlcldpbmRvd1RvRGltZW5zaW9ucyAoYnJvd3NlcklkLCB3aWR0aCwgaGVpZ2h0KSB7XG4gICAgICAgIGlmICghT1MubWFjKVxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG5cbiAgICAgICAgY29uc3QgbWF4U2NyZWVuU2l6ZSA9IHRoaXMuX2dldE1heFNjcmVlblNpemUoYnJvd3NlcklkKTtcblxuICAgICAgICByZXR1cm4gd2lkdGggPD0gbWF4U2NyZWVuU2l6ZS53aWR0aCAmJiBoZWlnaHQgPD0gbWF4U2NyZWVuU2l6ZS5oZWlnaHQ7XG4gICAgfVxuXG4gICAgYXN5bmMgX21heGltaXplTG9jYWxCcm93c2VyV2luZG93IChicm93c2VySWQpIHtcbiAgICAgICAgYXdhaXQgYnJvd3NlclRvb2xzLm1heGltaXplKHRoaXMuX2dldFdpbmRvd0Rlc2NyaXB0b3IoYnJvd3NlcklkKSk7XG4gICAgfVxuXG4gICAgYXN5bmMgX2NhblVzZURlZmF1bHRXaW5kb3dBY3Rpb25zIChicm93c2VySWQpIHtcbiAgICAgICAgY29uc3QgaXNMb2NhbEJyb3dzZXIgICAgPSBhd2FpdCB0aGlzLnBsdWdpbi5pc0xvY2FsQnJvd3Nlcihicm93c2VySWQpO1xuICAgICAgICBjb25zdCBpc0hlYWRsZXNzQnJvd3NlciA9IGF3YWl0IHRoaXMucGx1Z2luLmlzSGVhZGxlc3NCcm93c2VyKGJyb3dzZXJJZCk7XG5cbiAgICAgICAgcmV0dXJuIGlzTG9jYWxCcm93c2VyICYmICFpc0hlYWRsZXNzQnJvd3NlcjtcbiAgICB9XG5cbiAgICBhc3luYyBpbml0ICgpIHtcbiAgICAgICAgY29uc3QgaW5pdGlhbGl6ZWQgPSBhd2FpdCB0aGlzLmluaXRQcm9taXNlO1xuXG4gICAgICAgIGlmIChpbml0aWFsaXplZClcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICB0aGlzLmluaXRQcm9taXNlID0gdGhpcy5wbHVnaW5cbiAgICAgICAgICAgIC5pbml0KClcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHRydWUpO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmluaXRQcm9taXNlO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgdGhpcy5pbml0UHJvbWlzZSA9IFByb21pc2UucmVzb2x2ZShmYWxzZSk7XG5cbiAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgZGlzcG9zZSAoKSB7XG4gICAgICAgIGNvbnN0IGluaXRpYWxpemVkID0gYXdhaXQgdGhpcy5pbml0UHJvbWlzZTtcblxuICAgICAgICBpZiAoIWluaXRpYWxpemVkKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMuaW5pdFByb21pc2UgPSB0aGlzLnBsdWdpblxuICAgICAgICAgICAgLmRpc3Bvc2UoKVxuICAgICAgICAgICAgLnRoZW4oKCkgPT4gZmFsc2UpO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmluaXRQcm9taXNlO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgdGhpcy5pbml0UHJvbWlzZSA9IFByb21pc2UucmVzb2x2ZShmYWxzZSk7XG5cbiAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgaXNMb2NhbEJyb3dzZXIgKGJyb3dzZXJJZCwgYnJvd3Nlck5hbWUpIHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucGx1Z2luLmlzTG9jYWxCcm93c2VyKGJyb3dzZXJJZCwgYnJvd3Nlck5hbWUpO1xuICAgIH1cblxuICAgIGlzSGVhZGxlc3NCcm93c2VyIChicm93c2VySWQpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucGx1Z2luLmlzSGVhZGxlc3NCcm93c2VyKGJyb3dzZXJJZCk7XG4gICAgfVxuXG4gICAgYXN5bmMgb3BlbkJyb3dzZXIgKGJyb3dzZXJJZCwgcGFnZVVybCwgYnJvd3Nlck5hbWUpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4ub3BlbkJyb3dzZXIoYnJvd3NlcklkLCBwYWdlVXJsLCBicm93c2VyTmFtZSk7XG5cbiAgICAgICAgaWYgKGF3YWl0IHRoaXMuX2NhblVzZURlZmF1bHRXaW5kb3dBY3Rpb25zKGJyb3dzZXJJZCkpXG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9lbnN1cmVCcm93c2VyV2luZG93UGFyYW1ldGVycyhicm93c2VySWQpO1xuICAgIH1cblxuICAgIGFzeW5jIGNsb3NlQnJvd3NlciAoYnJvd3NlcklkKSB7XG4gICAgICAgIGNvbnN0IGNhblVzZURlZmF1bHRXaW5kb3dBY3Rpb25zID0gYXdhaXQgdGhpcy5fY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMoYnJvd3NlcklkKTtcbiAgICAgICAgY29uc3QgY3VzdG9tQWN0aW9uc0luZm8gICAgICAgICAgPSBhd2FpdCB0aGlzLmhhc0N1c3RvbUFjdGlvbkZvckJyb3dzZXIoYnJvd3NlcklkKTtcbiAgICAgICAgY29uc3QgaGFzQ3VzdG9tQ2xvc2VCcm93c2VyICAgICAgPSBjdXN0b21BY3Rpb25zSW5mby5oYXNDbG9zZUJyb3dzZXI7XG4gICAgICAgIGNvbnN0IHVzZVBsdWdpbnNDbG9zZUJyb3dzZXIgICAgID0gaGFzQ3VzdG9tQ2xvc2VCcm93c2VyIHx8ICFjYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucztcblxuICAgICAgICBpZiAodXNlUGx1Z2luc0Nsb3NlQnJvd3NlcilcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLmNsb3NlQnJvd3Nlcihicm93c2VySWQpO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9jbG9zZUxvY2FsQnJvd3Nlcihicm93c2VySWQpO1xuXG4gICAgICAgIGlmIChjYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucylcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF07XG4gICAgfVxuXG4gICAgYXN5bmMgZ2V0QnJvd3Nlckxpc3QgKCkge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5wbHVnaW4uZ2V0QnJvd3Nlckxpc3QoKTtcbiAgICB9XG5cbiAgICBhc3luYyBpc1ZhbGlkQnJvd3Nlck5hbWUgKGJyb3dzZXJOYW1lKSB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLnBsdWdpbi5pc1ZhbGlkQnJvd3Nlck5hbWUoYnJvd3Nlck5hbWUpO1xuICAgIH1cblxuICAgIGFzeW5jIHJlc2l6ZVdpbmRvdyAoYnJvd3NlcklkLCB3aWR0aCwgaGVpZ2h0LCBjdXJyZW50V2lkdGgsIGN1cnJlbnRIZWlnaHQpIHtcbiAgICAgICAgY29uc3QgY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMgPSBhd2FpdCB0aGlzLl9jYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyhicm93c2VySWQpO1xuICAgICAgICBjb25zdCBjdXN0b21BY3Rpb25zSW5mbyAgICAgICAgICA9IGF3YWl0IHRoaXMuaGFzQ3VzdG9tQWN0aW9uRm9yQnJvd3Nlcihicm93c2VySWQpO1xuICAgICAgICBjb25zdCBoYXNDdXN0b21SZXNpemVXaW5kb3cgICAgICA9IGN1c3RvbUFjdGlvbnNJbmZvLmhhc1Jlc2l6ZVdpbmRvdztcblxuXG4gICAgICAgIGlmIChjYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyAmJiAhaGFzQ3VzdG9tUmVzaXplV2luZG93KSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9yZXNpemVMb2NhbEJyb3dzZXJXaW5kb3coYnJvd3NlcklkLCB3aWR0aCwgaGVpZ2h0LCBjdXJyZW50V2lkdGgsIGN1cnJlbnRIZWlnaHQpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4ucmVzaXplV2luZG93KGJyb3dzZXJJZCwgd2lkdGgsIGhlaWdodCwgY3VycmVudFdpZHRoLCBjdXJyZW50SGVpZ2h0KTtcbiAgICB9XG5cbiAgICBhc3luYyBjYW5SZXNpemVXaW5kb3dUb0RpbWVuc2lvbnMgKGJyb3dzZXJJZCwgd2lkdGgsIGhlaWdodCkge1xuICAgICAgICBjb25zdCBjYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyAgICAgPSBhd2FpdCB0aGlzLl9jYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyhicm93c2VySWQpO1xuICAgICAgICBjb25zdCBjdXN0b21BY3Rpb25zSW5mbyAgICAgICAgICAgICAgPSBhd2FpdCB0aGlzLmhhc0N1c3RvbUFjdGlvbkZvckJyb3dzZXIoYnJvd3NlcklkKTtcbiAgICAgICAgY29uc3QgaGFzQ3VzdG9tQ2FuUmVzaXplVG9EaW1lbnNpb25zID0gY3VzdG9tQWN0aW9uc0luZm8uaGFzQ2FuUmVzaXplV2luZG93VG9EaW1lbnNpb25zO1xuXG5cbiAgICAgICAgaWYgKGNhblVzZURlZmF1bHRXaW5kb3dBY3Rpb25zICYmICFoYXNDdXN0b21DYW5SZXNpemVUb0RpbWVuc2lvbnMpXG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5fY2FuUmVzaXplTG9jYWxCcm93c2VyV2luZG93VG9EaW1lbnNpb25zKGJyb3dzZXJJZCwgd2lkdGgsIGhlaWdodCk7XG5cbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucGx1Z2luLmNhblJlc2l6ZVdpbmRvd1RvRGltZW5zaW9ucyhicm93c2VySWQsIHdpZHRoLCBoZWlnaHQpO1xuICAgIH1cblxuICAgIGFzeW5jIG1heGltaXplV2luZG93IChicm93c2VySWQpIHtcbiAgICAgICAgY29uc3QgY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMgPSBhd2FpdCB0aGlzLl9jYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyhicm93c2VySWQpO1xuICAgICAgICBjb25zdCBjdXN0b21BY3Rpb25zSW5mbyAgICAgICAgICA9IGF3YWl0IHRoaXMuaGFzQ3VzdG9tQWN0aW9uRm9yQnJvd3Nlcihicm93c2VySWQpO1xuICAgICAgICBjb25zdCBoYXNDdXN0b21NYXhpbWl6ZVdpbmRvdyAgICA9IGN1c3RvbUFjdGlvbnNJbmZvLmhhc01heGltaXplV2luZG93O1xuXG4gICAgICAgIGlmIChjYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyAmJiAhaGFzQ3VzdG9tTWF4aW1pemVXaW5kb3cpXG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5fbWF4aW1pemVMb2NhbEJyb3dzZXJXaW5kb3coYnJvd3NlcklkKTtcblxuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5wbHVnaW4ubWF4aW1pemVXaW5kb3coYnJvd3NlcklkKTtcbiAgICB9XG5cbiAgICBhc3luYyB0YWtlU2NyZWVuc2hvdCAoYnJvd3NlcklkLCBzY3JlZW5zaG90UGF0aCwgcGFnZVdpZHRoLCBwYWdlSGVpZ2h0KSB7XG4gICAgICAgIGNvbnN0IGNhblVzZURlZmF1bHRXaW5kb3dBY3Rpb25zID0gYXdhaXQgdGhpcy5fY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMoYnJvd3NlcklkKTtcbiAgICAgICAgY29uc3QgY3VzdG9tQWN0aW9uc0luZm8gICAgICAgICAgPSBhd2FpdCB0aGlzLmhhc0N1c3RvbUFjdGlvbkZvckJyb3dzZXIoYnJvd3NlcklkKTtcbiAgICAgICAgY29uc3QgaGFzQ3VzdG9tVGFrZVNjcmVlbnNob3QgICAgPSBjdXN0b21BY3Rpb25zSW5mby5oYXNUYWtlU2NyZWVuc2hvdDtcblxuICAgICAgICBpZiAoY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMgJiYgIWhhc0N1c3RvbVRha2VTY3JlZW5zaG90KSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLl90YWtlTG9jYWxCcm93c2VyU2NyZWVuc2hvdChicm93c2VySWQsIHNjcmVlbnNob3RQYXRoLCBwYWdlV2lkdGgsIHBhZ2VIZWlnaHQpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4udGFrZVNjcmVlbnNob3QoYnJvd3NlcklkLCBzY3JlZW5zaG90UGF0aCwgcGFnZVdpZHRoLCBwYWdlSGVpZ2h0KTtcbiAgICB9XG5cbiAgICBhc3luYyBnZXRWaWRlb0ZyYW1lRGF0YSAoYnJvd3NlcklkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnBsdWdpbi5nZXRWaWRlb0ZyYW1lRGF0YShicm93c2VySWQpO1xuICAgIH1cblxuICAgIGFzeW5jIGhhc0N1c3RvbUFjdGlvbkZvckJyb3dzZXIgKGJyb3dzZXJJZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5wbHVnaW4uaGFzQ3VzdG9tQWN0aW9uRm9yQnJvd3Nlcihicm93c2VySWQpO1xuICAgIH1cblxuICAgIGFzeW5jIHJlcG9ydEpvYlJlc3VsdCAoYnJvd3NlcklkLCBzdGF0dXMsIGRhdGEpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4ucmVwb3J0Sm9iUmVzdWx0KGJyb3dzZXJJZCwgc3RhdHVzLCBkYXRhKTtcbiAgICB9XG59XG4iXX0=