UNPKG

@browserstack/testcafe

Version:

Automated browser testing for the modern web development stack.

262 lines 45.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const testcafe_browser_tools_1 = __importDefault(require("testcafe-browser-tools")); const os_family_1 = __importDefault(require("os-family")); const path_1 = require("path"); const make_dir_1 = __importDefault(require("make-dir")); const connection_1 = __importDefault(require("../connection")); const delay_1 = __importDefault(require("../../utils/delay")); const client_functions_1 = require("./utils/client-functions"); const warning_message_1 = __importDefault(require("../../notifications/warning-message")); 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 = Promise.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 = {}; } _ensureLocalBrowserInfo(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._ensureLocalBrowserInfo(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) { if (this.plugin.needCleanUpBrowserInfo) this.plugin.cleanUpBrowserInfo(browserId); const windowDescriptor = this._getWindowDescriptor(browserId); await testcafe_browser_tools_1.default.close(windowDescriptor); } 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 = Promise.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 = Promise.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, allowMultipleWindows) { await this.plugin.openBrowser(browserId, pageUrl, browserName, allowMultipleWindows); 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, fullPage) { const canUseDefaultWindowActions = await this.canUseDefaultWindowActions(browserId); const customActionsInfo = await this.hasCustomActionForBrowser(browserId); const hasCustomTakeScreenshot = customActionsInfo.hasTakeScreenshot; const connection = connection_1.default.getById(browserId); const takeLocalBrowsersScreenshot = canUseDefaultWindowActions && !hasCustomTakeScreenshot; const isLocalFullPageMode = takeLocalBrowsersScreenshot && fullPage; if (isLocalFullPageMode) { connection.addWarning(warning_message_1.default.screenshotsFullPageNotSupported, connection.browserInfo.alias); return; } await make_dir_1.default(path_1.dirname(screenshotPath)); if (takeLocalBrowsersScreenshot) await this._takeLocalBrowserScreenshot(browserId, screenshotPath); else await this.plugin.takeScreenshot(browserId, screenshotPath, pageWidth, pageHeight, fullPage); } 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); } getActiveWindowId(browserId) { if (!this.plugin.supportMultipleWindows) return null; return this.plugin.getActiveWindowId(browserId); } setActiveWindowId(browserId, val) { this.plugin.setActiveWindowId(browserId, val); } } exports.default = BrowserProvider; module.exports = exports.default; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYnJvd3Nlci9wcm92aWRlci9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLG9GQUFrRDtBQUNsRCwwREFBMkI7QUFDM0IsK0JBQStCO0FBQy9CLHdEQUErQjtBQUMvQiwrREFBOEM7QUFDOUMsOERBQXNDO0FBQ3RDLCtEQUErRjtBQUMvRiwwRkFBa0U7QUFHbEUsTUFBTSxxQkFBcUIsR0FBRyxJQUFJLENBQUM7QUFFbkMsTUFBTSxnQkFBZ0IsR0FBRztJQUNyQixLQUFLLEVBQUcsR0FBRztJQUNYLE1BQU0sRUFBRSxHQUFHO0NBQ2QsQ0FBQztBQWFGLFNBQVMsUUFBUSxDQUFFLEtBQVcsRUFBRSxLQUFXO0lBQ3ZDLE9BQU87UUFDSCxLQUFLLEVBQUcsS0FBSyxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSztRQUNqQyxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTTtLQUN0QyxDQUFDO0FBQ04sQ0FBQztBQUVELFNBQVMsYUFBYSxDQUFFLEtBQVcsRUFBRSxLQUFXO0lBQzVDLE9BQU87UUFDSCxLQUFLLEVBQUcsS0FBSyxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSztRQUNqQyxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTTtLQUN0QyxDQUFDO0FBQ04sQ0FBQztBQUVELE1BQXFCLGVBQWU7SUFNaEMsWUFBb0IsTUFBVztRQUMzQixJQUFJLENBQUMsTUFBTSxHQUFXLE1BQU0sQ0FBQztRQUM3QixJQUFJLENBQUMsV0FBVyxHQUFNLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDN0MsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQztRQUNqRCwrSEFBK0g7UUFDL0gsdUlBQXVJO1FBQ3ZJLHdJQUF3STtR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b3dzZXJUb29scyBmcm9tICd0ZXN0Y2FmZS1icm93c2VyLXRvb2xzJztcbmltcG9ydCBPUyBmcm9tICdvcy1mYW1pbHknO1xuaW1wb3J0IHsgZGlybmFtZSB9IGZyb20gJ3BhdGgnO1xuaW1wb3J0IG1ha2VEaXIgZnJvbSAnbWFrZS1kaXInO1xuaW1wb3J0IEJyb3dzZXJDb25uZWN0aW9uIGZyb20gJy4uL2Nvbm5lY3Rpb24nO1xuaW1wb3J0IGRlbGF5IGZyb20gJy4uLy4uL3V0aWxzL2RlbGF5JztcbmltcG9ydCB7IEdFVF9USVRMRV9TQ1JJUFQsIEdFVF9XSU5ET1dfRElNRU5TSU9OU19JTkZPX1NDUklQVCB9IGZyb20gJy4vdXRpbHMvY2xpZW50LWZ1bmN0aW9ucyc7XG5pbXBvcnQgV0FSTklOR19NRVNTQUdFIGZyb20gJy4uLy4uL25vdGlmaWNhdGlvbnMvd2FybmluZy1tZXNzYWdlJztcbmltcG9ydCB7IERpY3Rpb25hcnkgfSBmcm9tICcuLi8uLi9jb25maWd1cmF0aW9uL2ludGVyZmFjZXMnO1xuXG5jb25zdCBCUk9XU0VSX09QRU5JTkdfREVMQVkgPSAyMDAwO1xuXG5jb25zdCBSRVNJWkVfRElGRl9TSVpFID0ge1xuICAgIHdpZHRoOiAgMTAwLFxuICAgIGhlaWdodDogMTAwXG59O1xuXG5pbnRlcmZhY2UgU2l6ZSB7XG4gICAgd2lkdGg6IG51bWJlcjtcbiAgICBoZWlnaHQ6IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIExvY2FsQnJvd3NlckluZm8ge1xuICAgIHdpbmRvd0Rlc2NyaXB0b3I6IG51bGwgfCBzdHJpbmc7XG4gICAgbWF4U2NyZWVuU2l6ZTogbnVsbCB8IFNpemU7XG4gICAgcmVzaXplQ29ycmVjdGlvbnM6IG51bGwgfCBTaXplO1xufVxuXG5mdW5jdGlvbiBzdW1TaXplcyAoc2l6ZUE6IFNpemUsIHNpemVCOiBTaXplKTogU2l6ZSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgd2lkdGg6ICBzaXplQS53aWR0aCArIHNpemVCLndpZHRoLFxuICAgICAgICBoZWlnaHQ6IHNpemVBLmhlaWdodCArIHNpemVCLmhlaWdodFxuICAgIH07XG59XG5cbmZ1bmN0aW9uIHN1YnRyYWN0U2l6ZXMgKHNpemVBOiBTaXplLCBzaXplQjogU2l6ZSk6IFNpemUge1xuICAgIHJldHVybiB7XG4gICAgICAgIHdpZHRoOiAgc2l6ZUEud2lkdGggLSBzaXplQi53aWR0aCxcbiAgICAgICAgaGVpZ2h0OiBzaXplQS5oZWlnaHQgLSBzaXplQi5oZWlnaHRcbiAgICB9O1xufVxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBCcm93c2VyUHJvdmlkZXIge1xuICAgIHByaXZhdGUgcGx1Z2luOiBhbnk7XG4gICAgcHJpdmF0ZSBpbml0UHJvbWlzZTogUHJvbWlzZTxhbnk+O1xuICAgIHByaXZhdGUgaXNNdWx0aUJyb3dzZXI6IGJvb2xlYW47XG4gICAgcHJpdmF0ZSByZWFkb25seSBsb2NhbEJyb3dzZXJzSW5mbzogRGljdGlvbmFyeTxMb2NhbEJyb3dzZXJJbmZvPjtcblxuICAgIHB1YmxpYyBjb25zdHJ1Y3RvciAocGx1Z2luOiBhbnkpIHtcbiAgICAgICAgdGhpcy5wbHVnaW4gICAgICAgICA9IHBsdWdpbjtcbiAgICAgICAgdGhpcy5pbml0UHJvbWlzZSAgICA9IFByb21pc2UucmVzb2x2ZShmYWxzZSk7XG4gICAgICAgIHRoaXMuaXNNdWx0aUJyb3dzZXIgPSB0aGlzLnBsdWdpbi5pc011bHRpQnJvd3NlcjtcbiAgICAgICAgLy8gSEFDSzogVGhlIGJyb3dzZXIgd2luZG93IGhhcyBkaWZmZXJlbnQgYm9yZGVyIHNpemVzIGluIG5vcm1hbCBhbmQgbWF4aW1pemVkIG1vZGVzLiBTbywgd2UgbmVlZCB0byBiZSBzdXJlIHRoYXQgdGhlIHdpbmRvdyBpc1xuICAgICAgICAvLyBub3QgbWF4aW1pemVkIGJlZm9yZSByZXNpemluZyBpdCBpbiBvcmRlciB0byBrZWVwIHRoZSBtZWNoYW5pc20gb2YgY29ycmVjdGluZyB0aGUgY2xpZW50IGFyZWEgc2l6ZSB3b3JraW5nLiBXaGVuIGJyb3dzZXIgaXMgc3RhcnRlZCxcbiAgICAgICAgLy8gd2UgYXJlIHJlc2l6aW5nIGl0IGZvciB0aGUgZmlyc3QgdGltZSB0byBzd2l0Y2ggdGhlIHdpbmRvdyB0byBub3JtYWwgbW9kZSwgYW5kIGZvciB0aGUgc2Vjb25kIHRpbWUgLSB0byByZXN0b3JlIHRoZSBjbGllbnQgYXJlYSBzaXplLlxuICAgICAgICB0aGlzLmxvY2FsQnJvd3NlcnNJbmZvID0ge307XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfZW5zdXJlTG9jYWxCcm93c2VySW5mbyAoYnJvd3NlcklkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMubG9jYWxCcm93c2Vyc0luZm9bYnJvd3NlcklkXSlcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICB0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0gPSB7XG4gICAgICAgICAgICB3aW5kb3dEZXNjcmlwdG9yOiAgbnVsbCxcbiAgICAgICAgICAgIG1heFNjcmVlblNpemU6ICAgICBudWxsLFxuICAgICAgICAgICAgcmVzaXplQ29ycmVjdGlvbnM6IG51bGxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBwcml2YXRlIF9nZXRXaW5kb3dEZXNjcmlwdG9yIChicm93c2VySWQ6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuICAgICAgICByZXR1cm4gdGhpcy5sb2NhbEJyb3dzZXJzSW5mb1ticm93c2VySWRdICYmIHRoaXMubG9jYWxCcm93c2Vyc0luZm9bYnJvd3NlcklkXS53aW5kb3dEZXNjcmlwdG9yO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2dldE1heFNjcmVlblNpemUgKGJyb3dzZXJJZDogc3RyaW5nKTogU2l6ZSB8IG51bGwge1xuICAgICAgICByZXR1cm4gdGhpcy5sb2NhbEJyb3dzZXJzSW5mb1ticm93c2VySWRdICYmIHRoaXMubG9jYWxCcm93c2Vyc0luZm9bYnJvd3NlcklkXS5tYXhTY3JlZW5TaXplO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2dldFJlc2l6ZUNvcnJlY3Rpb25zIChicm93c2VySWQ6IHN0cmluZyk6IFNpemUgfCBudWxsIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubG9jYWxCcm93c2Vyc0luZm9bYnJvd3NlcklkXSAmJiB0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0ucmVzaXplQ29ycmVjdGlvbnM7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfaXNCcm93c2VySWRsZSAoYnJvd3NlcklkOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgICAgY29uc3QgY29ubmVjdGlvbiA9IEJyb3dzZXJDb25uZWN0aW9uLmdldEJ5SWQoYnJvd3NlcklkKSBhcyBCcm93c2VyQ29ubmVjdGlvbjtcblxuICAgICAgICByZXR1cm4gY29ubmVjdGlvbi5pZGxlO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2NhbGN1bGF0ZVJlc2l6ZUNvcnJlY3Rpb25zIChicm93c2VySWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAoIXRoaXMuX2lzQnJvd3NlcklkbGUoYnJvd3NlcklkKSlcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICBjb25zdCB0aXRsZSA9IGF3YWl0IHRoaXMucGx1Z2luLnJ1bkluaXRTY3JpcHQoYnJvd3NlcklkLCBHRVRfVElUTEVfU0NSSVBUKTtcblxuICAgICAgICBpZiAoIWF3YWl0IGJyb3dzZXJUb29scy5pc01heGltaXplZCh0aXRsZSkpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgY29uc3QgY3VycmVudFNpemUgPSBhd2FpdCB0aGlzLnBsdWdpbi5ydW5Jbml0U2NyaXB0KGJyb3dzZXJJZCwgR0VUX1dJTkRPV19ESU1FTlNJT05TX0lORk9fU0NSSVBUKTtcbiAgICAgICAgY29uc3QgZXRhbG9uU2l6ZSAgPSBzdWJ0cmFjdFNpemVzKGN1cnJlbnRTaXplLCBSRVNJWkVfRElGRl9TSVpFKTtcblxuICAgICAgICBhd2FpdCBicm93c2VyVG9vbHMucmVzaXplKHRpdGxlLCBjdXJyZW50U2l6ZS53aWR0aCwgY3VycmVudFNpemUuaGVpZ2h0LCBldGFsb25TaXplLndpZHRoLCBldGFsb25TaXplLmhlaWdodCk7XG5cbiAgICAgICAgbGV0IHJlc2l6ZWRTaXplICAgID0gYXdhaXQgdGhpcy5wbHVnaW4ucnVuSW5pdFNjcmlwdChicm93c2VySWQsIEdFVF9XSU5ET1dfRElNRU5TSU9OU19JTkZPX1NDUklQVCk7XG4gICAgICAgIGxldCBjb3JyZWN0aW9uU2l6ZSA9IHN1YnRyYWN0U2l6ZXMocmVzaXplZFNpemUsIGV0YWxvblNpemUpO1xuXG4gICAgICAgIGF3YWl0IGJyb3dzZXJUb29scy5yZXNpemUodGl0bGUsIHJlc2l6ZWRTaXplLndpZHRoLCByZXNpemVkU2l6ZS5oZWlnaHQsIGV0YWxvblNpemUud2lkdGgsIGV0YWxvblNpemUuaGVpZ2h0KTtcblxuICAgICAgICByZXNpemVkU2l6ZSA9IGF3YWl0IHRoaXMucGx1Z2luLnJ1bkluaXRTY3JpcHQoYnJvd3NlcklkLCBHRVRfV0lORE9XX0RJTUVOU0lPTlNfSU5GT19TQ1JJUFQpO1xuXG4gICAgICAgIGNvcnJlY3Rpb25TaXplID0gc3VtU2l6ZXMoY29ycmVjdGlvblNpemUsIHN1YnRyYWN0U2l6ZXMocmVzaXplZFNpemUsIGV0YWxvblNpemUpKTtcblxuICAgICAgICBpZiAodGhpcy5sb2NhbEJyb3dzZXJzSW5mb1ticm93c2VySWRdKVxuICAgICAgICAgICAgdGhpcy5sb2NhbEJyb3dzZXJzSW5mb1ticm93c2VySWRdLnJlc2l6ZUNvcnJlY3Rpb25zID0gY29ycmVjdGlvblNpemU7XG5cbiAgICAgICAgYXdhaXQgYnJvd3NlclRvb2xzLm1heGltaXplKHRpdGxlKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9jYWxjdWxhdGVNYWNTaXplTGltaXRzIChicm93c2VySWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAoIXRoaXMuX2lzQnJvd3NlcklkbGUoYnJvd3NlcklkKSlcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICBjb25zdCBzaXplSW5mbyA9IGF3YWl0IHRoaXMucGx1Z2luLnJ1bkluaXRTY3JpcHQoYnJvd3NlcklkLCBHRVRfV0lORE9XX0RJTUVOU0lPTlNfSU5GT19TQ1JJUFQpO1xuXG4gICAgICAgIGlmICh0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0pIHtcbiAgICAgICAgICAgIHRoaXMubG9jYWxCcm93c2Vyc0luZm9bYnJvd3NlcklkXS5tYXhTY3JlZW5TaXplID0ge1xuICAgICAgICAgICAgICAgIHdpZHRoOiAgc2l6ZUluZm8uYXZhaWxhYmxlV2lkdGggLSAoc2l6ZUluZm8ub3V0ZXJXaWR0aCAtIHNpemVJbmZvLndpZHRoKSxcbiAgICAgICAgICAgICAgICBoZWlnaHQ6IHNpemVJbmZvLmF2YWlsYWJsZUhlaWdodCAtIChzaXplSW5mby5vdXRlckhlaWdodCAtIHNpemVJbmZvLmhlaWdodClcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9lbnN1cmVCcm93c2VyV2luZG93RGVzY3JpcHRvciAoYnJvd3NlcklkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKHRoaXMuX2dldFdpbmRvd0Rlc2NyaXB0b3IoYnJvd3NlcklkKSlcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICBhd2FpdCB0aGlzLl9lbnN1cmVMb2NhbEJyb3dzZXJJbmZvKGJyb3dzZXJJZCk7XG5cbiAgICAgICAgLy8gTk9URTogZGVsYXkgdG8gZW5zdXJlIHRoZSB3aW5kb3cgZmluaXNoZWQgdGhlIG9wZW5pbmdcbiAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4ud2FpdEZvckNvbm5lY3Rpb25SZWFkeShicm93c2VySWQpO1xuICAgICAgICBhd2FpdCBkZWxheShCUk9XU0VSX09QRU5JTkdfREVMQVkpO1xuXG4gICAgICAgIGlmICh0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0pXG4gICAgICAgICAgICB0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0ud2luZG93RGVzY3JpcHRvciA9IGF3YWl0IGJyb3dzZXJUb29scy5maW5kV2luZG93KGJyb3dzZXJJZCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfZW5zdXJlQnJvd3NlcldpbmRvd1BhcmFtZXRlcnMgKGJyb3dzZXJJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuX2Vuc3VyZUJyb3dzZXJXaW5kb3dEZXNjcmlwdG9yKGJyb3dzZXJJZCk7XG5cbiAgICAgICAgaWYgKE9TLndpbiAmJiAhdGhpcy5fZ2V0UmVzaXplQ29ycmVjdGlvbnMoYnJvd3NlcklkKSlcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX2NhbGN1bGF0ZVJlc2l6ZUNvcnJlY3Rpb25zKGJyb3dzZXJJZCk7XG4gICAgICAgIGVsc2UgaWYgKE9TLm1hYyAmJiAhdGhpcy5fZ2V0TWF4U2NyZWVuU2l6ZShicm93c2VySWQpKVxuICAgICAgICAgICAgYXdhaXQgdGhpcy5fY2FsY3VsYXRlTWFjU2l6ZUxpbWl0cyhicm93c2VySWQpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2Nsb3NlTG9jYWxCcm93c2VyIChicm93c2VySWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5wbHVnaW4ubmVlZENsZWFuVXBCcm93c2VySW5mbylcbiAgICAgICAgICAgIHRoaXMucGx1Z2luLmNsZWFuVXBCcm93c2VySW5mbyhicm93c2VySWQpO1xuXG4gICAgICAgIGNvbnN0IHdpbmRvd0Rlc2NyaXB0b3IgPSB0aGlzLl9nZXRXaW5kb3dEZXNjcmlwdG9yKGJyb3dzZXJJZCk7XG5cbiAgICAgICAgYXdhaXQgYnJvd3NlclRvb2xzLmNsb3NlKHdpbmRvd0Rlc2NyaXB0b3IpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX3Jlc2l6ZUxvY2FsQnJvd3NlcldpbmRvdyAoYnJvd3NlcklkOiBzdHJpbmcsIHdpZHRoOiBudW1iZXIsIGhlaWdodDogbnVtYmVyLCBjdXJyZW50V2lkdGg6IG51bWJlciwgY3VycmVudEhlaWdodDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IHJlc2l6ZUNvcnJlY3Rpb25zID0gdGhpcy5fZ2V0UmVzaXplQ29ycmVjdGlvbnMoYnJvd3NlcklkKTtcblxuICAgICAgICBpZiAocmVzaXplQ29ycmVjdGlvbnMgJiYgYXdhaXQgYnJvd3NlclRvb2xzLmlzTWF4aW1pemVkKHRoaXMuX2dldFdpbmRvd0Rlc2NyaXB0b3IoYnJvd3NlcklkKSkpIHtcbiAgICAgICAgICAgIHdpZHRoIC09IHJlc2l6ZUNvcnJlY3Rpb25zLndpZHRoO1xuICAgICAgICAgICAgaGVpZ2h0IC09IHJlc2l6ZUNvcnJlY3Rpb25zLmhlaWdodDtcbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IGJyb3dzZXJUb29scy5yZXNpemUodGhpcy5fZ2V0V2luZG93RGVzY3JpcHRvcihicm93c2VySWQpLCBjdXJyZW50V2lkdGgsIGN1cnJlbnRIZWlnaHQsIHdpZHRoLCBoZWlnaHQpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX3Rha2VMb2NhbEJyb3dzZXJTY3JlZW5zaG90IChicm93c2VySWQ6IHN0cmluZywgc2NyZWVuc2hvdFBhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCBicm93c2VyVG9vbHMuc2NyZWVuc2hvdCh0aGlzLl9nZXRXaW5kb3dEZXNjcmlwdG9yKGJyb3dzZXJJZCksIHNjcmVlbnNob3RQYXRoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9jYW5SZXNpemVMb2NhbEJyb3dzZXJXaW5kb3dUb0RpbWVuc2lvbnMgKGJyb3dzZXJJZDogc3RyaW5nLCB3aWR0aDogbnVtYmVyLCBoZWlnaHQ6IG51bWJlcik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgICAgICBpZiAoIU9TLm1hYylcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuXG4gICAgICAgIGNvbnN0IG1heFNjcmVlblNpemUgPSB0aGlzLl9nZXRNYXhTY3JlZW5TaXplKGJyb3dzZXJJZCkgYXMgU2l6ZTtcblxuICAgICAgICByZXR1cm4gd2lkdGggPD0gbWF4U2NyZWVuU2l6ZS53aWR0aCAmJiBoZWlnaHQgPD0gbWF4U2NyZWVuU2l6ZS5oZWlnaHQ7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfbWF4aW1pemVMb2NhbEJyb3dzZXJXaW5kb3cgKGJyb3dzZXJJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IGJyb3dzZXJUb29scy5tYXhpbWl6ZSh0aGlzLl9nZXRXaW5kb3dEZXNjcmlwdG9yKGJyb3dzZXJJZCkpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBjYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyAoYnJvd3NlcklkOiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgICAgY29uc3QgaXNMb2NhbEJyb3dzZXIgICAgPSBhd2FpdCB0aGlzLnBsdWdpbi5pc0xvY2FsQnJvd3Nlcihicm93c2VySWQpO1xuICAgICAgICBjb25zdCBpc0hlYWRsZXNzQnJvd3NlciA9IGF3YWl0IHRoaXMucGx1Z2luLmlzSGVhZGxlc3NCcm93c2VyKGJyb3dzZXJJZCk7XG5cbiAgICAgICAgcmV0dXJuIGlzTG9jYWxCcm93c2VyICYmICFpc0hlYWRsZXNzQnJvd3NlcjtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgaW5pdCAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IGluaXRpYWxpemVkID0gYXdhaXQgdGhpcy5pbml0UHJvbWlzZTtcblxuICAgICAgICBpZiAoaW5pdGlhbGl6ZWQpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgdGhpcy5pbml0UHJvbWlzZSA9IHRoaXMucGx1Z2luXG4gICAgICAgICAgICAuaW5pdCgpXG4gICAgICAgICAgICAudGhlbigoKSA9PiB0cnVlKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5pbml0UHJvbWlzZTtcbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIHRoaXMuaW5pdFByb21pc2UgPSBQcm9taXNlLnJlc29sdmUoZmFsc2UpO1xuXG4gICAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBkaXNwb3NlICgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgaW5pdGlhbGl6ZWQgPSBhd2FpdCB0aGlzLmluaXRQcm9taXNlO1xuXG4gICAgICAgIGlmICghaW5pdGlhbGl6ZWQpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgdGhpcy5pbml0UHJvbWlzZSA9IHRoaXMucGx1Z2luXG4gICAgICAgICAgICAuZGlzcG9zZSgpXG4gICAgICAgICAgICAudGhlbigoKSA9PiBmYWxzZSk7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuaW5pdFByb21pc2U7XG4gICAgICAgIH1cbiAgICAgICAgY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICB0aGlzLmluaXRQcm9taXNlID0gUHJvbWlzZS5yZXNvbHZlKGZhbHNlKTtcblxuICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgaXNMb2NhbEJyb3dzZXIgKGJyb3dzZXJJZD86IHN0cmluZywgYnJvd3Nlck5hbWU/OiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucGx1Z2luLmlzTG9jYWxCcm93c2VyKGJyb3dzZXJJZCwgYnJvd3Nlck5hbWUpO1xuICAgIH1cblxuICAgIHB1YmxpYyBpc0hlYWRsZXNzQnJvd3NlciAoYnJvd3NlcklkOiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMucGx1Z2luLmlzSGVhZGxlc3NCcm93c2VyKGJyb3dzZXJJZCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIG9wZW5Ccm93c2VyIChicm93c2VySWQ6IHN0cmluZywgcGFnZVVybDogc3RyaW5nLCBicm93c2VyTmFtZTogc3RyaW5nLCBhbGxvd011bHRpcGxlV2luZG93czogYm9vbGVhbik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5vcGVuQnJvd3Nlcihicm93c2VySWQsIHBhZ2VVcmwsIGJyb3dzZXJOYW1lLCBhbGxvd011bHRpcGxlV2luZG93cyk7XG5cbiAgICAgICAgaWYgKGF3YWl0IHRoaXMuY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMoYnJvd3NlcklkKSlcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX2Vuc3VyZUJyb3dzZXJXaW5kb3dQYXJhbWV0ZXJzKGJyb3dzZXJJZCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGNsb3NlQnJvd3NlciAoYnJvd3NlcklkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMgPSBhd2FpdCB0aGlzLmNhblVzZURlZmF1bHRXaW5kb3dBY3Rpb25zKGJyb3dzZXJJZCk7XG4gICAgICAgIGNvbnN0IGN1c3RvbUFjdGlvbnNJbmZvICAgICAgICAgID0gYXdhaXQgdGhpcy5oYXNDdXN0b21BY3Rpb25Gb3JCcm93c2VyKGJyb3dzZXJJZCk7XG4gICAgICAgIGNvbnN0IGhhc0N1c3RvbUNsb3NlQnJvd3NlciAgICAgID0gY3VzdG9tQWN0aW9uc0luZm8uaGFzQ2xvc2VCcm93c2VyO1xuICAgICAgICBjb25zdCB1c2VQbHVnaW5zQ2xvc2VCcm93c2VyICAgICA9IGhhc0N1c3RvbUNsb3NlQnJvd3NlciB8fCAhY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnM7XG5cbiAgICAgICAgaWYgKHVzZVBsdWdpbnNDbG9zZUJyb3dzZXIpXG4gICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5jbG9zZUJyb3dzZXIoYnJvd3NlcklkKTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgYXdhaXQgdGhpcy5fY2xvc2VMb2NhbEJyb3dzZXIoYnJvd3NlcklkKTtcblxuICAgICAgICBpZiAoY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMpXG4gICAgICAgICAgICBkZWxldGUgdGhpcy5sb2NhbEJyb3dzZXJzSW5mb1ticm93c2VySWRdO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBnZXRCcm93c2VyTGlzdCAoKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5wbHVnaW4uZ2V0QnJvd3Nlckxpc3QoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgaXNWYWxpZEJyb3dzZXJOYW1lIChicm93c2VyTmFtZTogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLnBsdWdpbi5pc1ZhbGlkQnJvd3Nlck5hbWUoYnJvd3Nlck5hbWUpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyByZXNpemVXaW5kb3cgKGJyb3dzZXJJZDogc3RyaW5nLCB3aWR0aDogbnVtYmVyLCBoZWlnaHQ6IG51bWJlciwgY3VycmVudFdpZHRoOiBudW1iZXIsIGN1cnJlbnRIZWlnaHQ6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBjYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyA9IGF3YWl0IHRoaXMuY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMoYnJvd3NlcklkKTtcbiAgICAgICAgY29uc3QgY3VzdG9tQWN0aW9uc0luZm8gICAgICAgICAgPSBhd2FpdCB0aGlzLmhhc0N1c3RvbUFjdGlvbkZvckJyb3dzZXIoYnJvd3NlcklkKTtcbiAgICAgICAgY29uc3QgaGFzQ3VzdG9tUmVzaXplV2luZG93ICAgICAgPSBjdXN0b21BY3Rpb25zSW5mby5oYXNSZXNpemVXaW5kb3c7XG5cblxuICAgICAgICBpZiAoY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMgJiYgIWhhc0N1c3RvbVJlc2l6ZVdpbmRvdykge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5fcmVzaXplTG9jYWxCcm93c2VyV2luZG93KGJyb3dzZXJJZCwgd2lkdGgsIGhlaWdodCwgY3VycmVudFdpZHRoLCBjdXJyZW50SGVpZ2h0KTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnJlc2l6ZVdpbmRvdyhicm93c2VySWQsIHdpZHRoLCBoZWlnaHQsIGN1cnJlbnRXaWR0aCwgY3VycmVudEhlaWdodCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGNhblJlc2l6ZVdpbmRvd1RvRGltZW5zaW9ucyAoYnJvd3NlcklkOiBzdHJpbmcsIHdpZHRoOiBudW1iZXIsIGhlaWdodDogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIGNvbnN0IGNhblVzZURlZmF1bHRXaW5kb3dBY3Rpb25zICAgICA9IGF3YWl0IHRoaXMuY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMoYnJvd3NlcklkKTtcbiAgICAgICAgY29uc3QgY3VzdG9tQWN0aW9uc0luZm8gICAgICAgICAgICAgID0gYXdhaXQgdGhpcy5oYXNDdXN0b21BY3Rpb25Gb3JCcm93c2VyKGJyb3dzZXJJZCk7XG4gICAgICAgIGNvbnN0IGhhc0N1c3RvbUNhblJlc2l6ZVRvRGltZW5zaW9ucyA9IGN1c3RvbUFjdGlvbnNJbmZvLmhhc0NhblJlc2l6ZVdpbmRvd1RvRGltZW5zaW9ucztcblxuXG4gICAgICAgIGlmIChjYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyAmJiAhaGFzQ3VzdG9tQ2FuUmVzaXplVG9EaW1lbnNpb25zKVxuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuX2NhblJlc2l6ZUxvY2FsQnJvd3NlcldpbmRvd1RvRGltZW5zaW9ucyhicm93c2VySWQsIHdpZHRoLCBoZWlnaHQpO1xuXG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLnBsdWdpbi5jYW5SZXNpemVXaW5kb3dUb0RpbWVuc2lvbnMoYnJvd3NlcklkLCB3aWR0aCwgaGVpZ2h0KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgbWF4aW1pemVXaW5kb3cgKGJyb3dzZXJJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IGNhblVzZURlZmF1bHRXaW5kb3dBY3Rpb25zID0gYXdhaXQgdGhpcy5jYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyhicm93c2VySWQpO1xuICAgICAgICBjb25zdCBjdXN0b21BY3Rpb25zSW5mbyAgICAgICAgICA9IGF3YWl0IHRoaXMuaGFzQ3VzdG9tQWN0aW9uRm9yQnJvd3Nlcihicm93c2VySWQpO1xuICAgICAgICBjb25zdCBoYXNDdXN0b21NYXhpbWl6ZVdpbmRvdyAgICA9IGN1c3RvbUFjdGlvbnNJbmZvLmhhc01heGltaXplV2luZG93O1xuXG4gICAgICAgIGlmIChjYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyAmJiAhaGFzQ3VzdG9tTWF4aW1pemVXaW5kb3cpXG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5fbWF4aW1pemVMb2NhbEJyb3dzZXJXaW5kb3coYnJvd3NlcklkKTtcblxuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5wbHVnaW4ubWF4aW1pemVXaW5kb3coYnJvd3NlcklkKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgdGFrZVNjcmVlbnNob3QgKGJyb3dzZXJJZDogc3RyaW5nLCBzY3JlZW5zaG90UGF0aDogc3RyaW5nLCBwYWdlV2lkdGg6IG51bWJlciwgcGFnZUhlaWdodDogbnVtYmVyLCBmdWxsUGFnZTogYm9vbGVhbik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBjYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyAgPSBhd2FpdCB0aGlzLmNhblVzZURlZmF1bHRXaW5kb3dBY3Rpb25zKGJyb3dzZXJJZCk7XG4gICAgICAgIGNvbnN0IGN1c3RvbUFjdGlvbnNJbmZvICAgICAgICAgICA9IGF3YWl0IHRoaXMuaGFzQ3VzdG9tQWN0aW9uRm9yQnJvd3Nlcihicm93c2VySWQpO1xuICAgICAgICBjb25zdCBoYXNDdXN0b21UYWtlU2NyZWVuc2hvdCAgICAgPSBjdXN0b21BY3Rpb25zSW5mby5oYXNUYWtlU2NyZWVuc2hvdDtcbiAgICAgICAgY29uc3QgY29ubmVjdGlvbiAgICAgICAgICAgICAgICAgID0gQnJvd3NlckNvbm5lY3Rpb24uZ2V0QnlJZChicm93c2VySWQpIGFzIEJyb3dzZXJDb25uZWN0aW9uO1xuICAgICAgICBjb25zdCB0YWtlTG9jYWxCcm93c2Vyc1NjcmVlbnNob3QgPSBjYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyAmJiAhaGFzQ3VzdG9tVGFrZVNjcmVlbnNob3Q7XG4gICAgICAgIGNvbnN0IGlzTG9jYWxGdWxsUGFnZU1vZGUgICAgICAgICA9IHRha2VMb2NhbEJyb3dzZXJzU2NyZWVuc2hvdCAmJiBmdWxsUGFnZTtcblxuICAgICAgICBpZiAoaXNMb2NhbEZ1bGxQYWdlTW9kZSkge1xuICAgICAgICAgICAgY29ubmVjdGlvbi5hZGRXYXJuaW5nKFdBUk5JTkdfTUVTU0FHRS5zY3JlZW5zaG90c0Z1bGxQYWdlTm90U3VwcG9ydGVkLCBjb25uZWN0aW9uLmJyb3dzZXJJbmZvLmFsaWFzKTtcblxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgbWFrZURpcihkaXJuYW1lKHNjcmVlbnNob3RQYXRoKSk7XG5cbiAgICAgICAgaWYgKHRha2VMb2NhbEJyb3dzZXJzU2NyZWVuc2hvdClcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX3Rha2VMb2NhbEJyb3dzZXJTY3JlZW5zaG90KGJyb3dzZXJJZCwgc2NyZWVuc2hvdFBhdGgpO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi50YWtlU2NyZWVuc2hvdChicm93c2VySWQsIHNjcmVlbnNob3RQYXRoLCBwYWdlV2lkdGgsIHBhZ2VIZWlnaHQsIGZ1bGxQYWdlKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZ2V0VmlkZW9GcmFtZURhdGEgKGJyb3dzZXJJZDogc3RyaW5nKTogUHJvbWlzZTxhbnk+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMucGx1Z2luLmdldFZpZGVvRnJhbWVEYXRhKGJyb3dzZXJJZCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGhhc0N1c3RvbUFjdGlvbkZvckJyb3dzZXIgKGJyb3dzZXJJZDogc3RyaW5nKTogUHJvbWlzZTxhbnk+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMucGx1Z2luLmhhc0N1c3RvbUFjdGlvbkZvckJyb3dzZXIoYnJvd3NlcklkKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgcmVwb3J0Sm9iUmVzdWx0IChicm93c2VySWQ6IHN0cmluZywgc3RhdHVzOiBzdHJpbmcsIGRhdGE6IGFueSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5yZXBvcnRKb2JSZXN1bHQoYnJvd3NlcklkLCBzdGF0dXMsIGRhdGEpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRBY3RpdmVXaW5kb3dJZCAoYnJvd3NlcklkOiBzdHJpbmcpOiBzdHJpbmcgfCBudWxsIHtcbiAgICAgICAgaWYgKCF0aGlzLnBsdWdpbi5zdXBwb3J0TXVsdGlwbGVXaW5kb3dzKVxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucGx1Z2luLmdldEFjdGl2ZVdpbmRvd0lkKGJyb3dzZXJJZCk7XG4gICAgfVxuXG4gICAgcHVibGljIHNldEFjdGl2ZVdpbmRvd0lkIChicm93c2VySWQ6IHN0cmluZywgdmFsOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5wbHVnaW4uc2V0QWN0aXZlV2luZG93SWQoYnJvd3NlcklkLCB2YWwpO1xuICAgIH1cbn1cbiJdfQ==