326 lines
56 KiB
JavaScript
326 lines
56 KiB
JavaScript
"use strict";
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const debug_1 = __importDefault(require("debug"));
|
|
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 get_os_info_1 = __importDefault(require("get-os-info"));
|
|
const DEBUG_LOGGER = (0, debug_1.default)('testcafe:browser:provider');
|
|
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,
|
|
};
|
|
}
|
|
async _findWindow(browserId) {
|
|
const pageTitle = this._getPageTitle(browserId);
|
|
return testcafe_browser_tools_1.default.findWindow(pageTitle);
|
|
}
|
|
_getPageTitle(browserId) {
|
|
if (this.plugin.getPageTitle)
|
|
return this.plugin.getPageTitle(browserId);
|
|
return browserId;
|
|
}
|
|
_getWindowDescriptor(browserId) {
|
|
if (this.plugin.getWindowDescriptor)
|
|
return this.plugin.getWindowDescriptor(browserId);
|
|
return this.localBrowsersInfo[browserId] && this.localBrowsersInfo[browserId].windowDescriptor;
|
|
}
|
|
_setWindowDescriptor(browserId, windowDescriptor) {
|
|
if (this.plugin.setWindowDescriptor) {
|
|
this.plugin.setWindowDescriptor(browserId, windowDescriptor);
|
|
return;
|
|
}
|
|
this.localBrowsersInfo[browserId].windowDescriptor = 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 (0, delay_1.default)(BROWSER_OPENING_DELAY);
|
|
if (this.localBrowsersInfo[browserId]) {
|
|
const connection = connection_1.default.getById(browserId);
|
|
let windowDescriptor = null;
|
|
try {
|
|
windowDescriptor = await this._findWindow(browserId);
|
|
}
|
|
catch (err) {
|
|
// NOTE: We can suppress the error here since we can just disable window manipulation functions
|
|
// when we cannot find a local window descriptor
|
|
DEBUG_LOGGER(err);
|
|
connection.addWarning(warning_message_1.default.cannotFindWindowDescriptorError, connection.browserInfo.alias, err.message);
|
|
}
|
|
this._setWindowDescriptor(browserId, windowDescriptor);
|
|
}
|
|
}
|
|
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) {
|
|
await this._ensureBrowserWindowDescriptor(browserId);
|
|
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 this._ensureBrowserWindowDescriptor(browserId);
|
|
await testcafe_browser_tools_1.default.maximize(this._getWindowDescriptor(browserId));
|
|
}
|
|
async _ensureRetryTestPagesWarning(browserId) {
|
|
const connection = connection_1.default.getById(browserId);
|
|
if (connection === null || connection === void 0 ? void 0 : connection.retryTestPages) {
|
|
const isServiceWorkerEnabled = await this.plugin.runInitScript(browserId, client_functions_1.GET_IS_SERVICE_WORKER_ENABLED);
|
|
if (!isServiceWorkerEnabled)
|
|
connection.addWarning(warning_message_1.default.retryTestPagesIsNotSupported, connection.browserInfo.alias, connection.browserInfo.alias);
|
|
}
|
|
}
|
|
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, browserName) {
|
|
return this.plugin.isHeadlessBrowser(browserId, browserName);
|
|
}
|
|
async getOSInfo(browserId) {
|
|
if (await this.isLocalBrowser(browserId))
|
|
return await (0, get_os_info_1.default)();
|
|
return await this.plugin.getOSInfo(browserId);
|
|
}
|
|
async openBrowser(browserId, pageUrl, browserOption, additionalOptions = { disableMultipleWindows: false }) {
|
|
await this.plugin.openBrowser(browserId, pageUrl, browserOption, additionalOptions);
|
|
await this._ensureRetryTestPagesWarning(browserId);
|
|
if (await this.canUseDefaultWindowActions(browserId))
|
|
await this._ensureBrowserWindowParameters(browserId);
|
|
}
|
|
async closeBrowser(browserId, data) {
|
|
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, data);
|
|
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 (0, make_dir_1.default)((0, 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 startCapturingVideo(browserId) {
|
|
await this.plugin.startCapturingVideo(browserId);
|
|
}
|
|
async stopCapturingVideo(browserId) {
|
|
await this.plugin.stopCapturingVideo(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);
|
|
}
|
|
async openFileProtocol(browserId, url) {
|
|
await this.plugin.openFileProtocol(browserId, url);
|
|
}
|
|
async closeBrowserChildWindow(browserId) {
|
|
await this.plugin.closeBrowserChildWindow(browserId);
|
|
}
|
|
async dispatchProxylessEvent(browserId, type, options) {
|
|
await this.plugin.dispatchProxylessEvent(browserId, type, options);
|
|
}
|
|
}
|
|
exports.default = BrowserProvider;
|
|
module.exports = exports.default;
|
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYnJvd3Nlci9wcm92aWRlci9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLGtEQUEwQjtBQUMxQixvRkFBa0Q7QUFDbEQsMERBQTJCO0FBQzNCLCtCQUErQjtBQUMvQix3REFBK0I7QUFDL0IsK0RBQXNFO0FBQ3RFLDhEQUFzQztBQUN0QywrREFJa0M7QUFDbEMsMEZBQWtFO0FBR2xFLDhEQUFxRDtBQUtyRCxNQUFNLFlBQVksR0FBRyxJQUFBLGVBQUssRUFBQywyQkFBMkIsQ0FBQyxDQUFDO0FBRXhELE1BQU0scUJBQXFCLEdBQUcsSUFBSSxDQUFDO0FBRW5DLE1BQU0sZ0JBQWdCLEdBQUc7SUFDckIsS0FBSyxFQUFHLEdBQUc7SUFDWCxNQUFNLEVBQUUsR0FBRztDQUNkLENBQUM7QUFhRixTQUFTLFFBQVEsQ0FBRSxLQUFXLEVBQUUsS0FBVztJQUN2QyxPQUFPO1FBQ0gsS0FBSyxFQUFHLEtBQUssQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUs7UUFDakMsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU07S0FDdEMsQ0FBQztBQUNOLENBQUM7QUFFRCxTQUFTLGFBQWEsQ0FBRSxLQUFXLEVBQUUsS0FBVztJQUM1QyxPQUFPO1FBQ0gsS0FBSyxFQUFHLEtBQUssQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUs7UUFDakMsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU07S0FDdEMsQ0FBQztBQUNOLENBQUM7QUFFRCxNQUFxQixlQUFlO0lBTWhDLFlBQW9CLE1BQVc7UUFDM0IsSUFBSSxDQUFDLE1BQU0sR0FBVyxNQUFNLENBQUM7UUFDN0IsSUFBSSxDQUFDLFdBQVcsR0FBTSxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzdDLElBQUksQ0FBQyxj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SUFBSSxDQUFDO1FBRWhCLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNwRCxDQUFDO0lBRU0saUJBQWlCLENBQUUsU0FBaUIsRUFBRSxHQUFXO1FBQ3BELElBQUksQ0FBQyxNQUFNLENBQUMsaUJBQWlCLENBQUMsU0FBUyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQ2xELENBQUM7SUFFTSxLQUFLLENBQUMsZ0JBQWdCLENBQUUsU0FBaUIsRUFBRSxHQUFXO1FBQ3pELE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxTQUFTLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDdkQsQ0FBQztJQUVNLEtBQUssQ0FBQyx1QkFBdUIsQ0FBRSxTQUFpQjtRQUNuRCxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsdUJBQXVCLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDekQsQ0FBQztJQUVNLEtBQUssQ0FBQyxzQkFBc0IsQ0FBRSxTQUFpQixFQUFFLElBQWUsRUFBRSxPQUFZO1FBQ2pGLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxzQkFBc0IsQ0FBQyxTQUFTLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ3ZFLENBQUM7Q0FDSjtBQWxaRCxrQ0FrWkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZGVidWcgZnJvbSAnZGVidWcnO1xuaW1wb3J0IGJyb3dzZXJUb29scyBmcm9tICd0ZXN0Y2FmZS1icm93c2VyLXRvb2xzJztcbmltcG9ydCBPUyBmcm9tICdvcy1mYW1pbHknO1xuaW1wb3J0IHsgZGlybmFtZSB9IGZyb20gJ3BhdGgnO1xuaW1wb3J0IG1ha2VEaXIgZnJvbSAnbWFrZS1kaXInO1xuaW1wb3J0IEJyb3dzZXJDb25uZWN0aW9uLCB7IEJyb3dzZXJDbG9zaW5nSW5mbyB9IGZyb20gJy4uL2Nvbm5lY3Rpb24nO1xuaW1wb3J0IGRlbGF5IGZyb20gJy4uLy4uL3V0aWxzL2RlbGF5JztcbmltcG9ydCB7XG4gICAgR0VUX0lTX1NFUlZJQ0VfV09SS0VSX0VOQUJMRUQsXG4gICAgR0VUX1RJVExFX1NDUklQVCxcbiAgICBHRVRfV0lORE9XX0RJTUVOU0lPTlNfSU5GT19TQ1JJUFQsXG59IGZyb20gJy4vdXRpbHMvY2xpZW50LWZ1bmN0aW9ucyc7XG5pbXBvcnQgV0FSTklOR19NRVNTQUdFIGZyb20gJy4uLy4uL25vdGlmaWNhdGlvbnMvd2FybmluZy1tZXNzYWdlJztcbmltcG9ydCB7IERpY3Rpb25hcnkgfSBmcm9tICcuLi8uLi9jb25maWd1cmF0aW9uL2ludGVyZmFjZXMnO1xuaW1wb3J0IHsgV2luZG93RGltZW50aW9uc0luZm8gfSBmcm9tICcuLi9pbnRlcmZhY2VzJztcbmltcG9ydCBnZXRMb2NhbE9TSW5mbywgeyBPU0luZm8gfSBmcm9tICdnZXQtb3MtaW5mbyc7XG5pbXBvcnQgeyBPcGVuQnJvd3NlckFkZGl0aW9uYWxPcHRpb25zIH0gZnJvbSAnLi4vLi4vc2hhcmVkL3R5cGVzJztcbmltcG9ydCB7IEV2ZW50VHlwZSB9IGZyb20gJy4uLy4uL3Byb3h5bGVzcy90eXBlcyc7XG5cblxuY29uc3QgREVCVUdfTE9HR0VSID0gZGVidWcoJ3Rlc3RjYWZlOmJyb3dzZXI6cHJvdmlkZXInKTtcblxuY29uc3QgQlJPV1NFUl9PUEVOSU5HX0RFTEFZID0gMjAwMDtcblxuY29uc3QgUkVTSVpFX0RJRkZfU0laRSA9IHtcbiAgICB3aWR0aDogIDEwMCxcbiAgICBoZWlnaHQ6IDEwMCxcbn07XG5cbmludGVyZmFjZSBTaXplIHtcbiAgICB3aWR0aDogbnVtYmVyO1xuICAgIGhlaWdodDogbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgTG9jYWxCcm93c2VySW5mbyB7XG4gICAgd2luZG93RGVzY3JpcHRvcjogbnVsbCB8IHN0cmluZztcbiAgICBtYXhTY3JlZW5TaXplOiBudWxsIHwgU2l6ZTtcbiAgICByZXNpemVDb3JyZWN0aW9uczogbnVsbCB8IFNpemU7XG59XG5cbmZ1bmN0aW9uIHN1bVNpemVzIChzaXplQTogU2l6ZSwgc2l6ZUI6IFNpemUpOiBTaXplIHtcbiAgICByZXR1cm4ge1xuICAgICAgICB3aWR0aDogIHNpemVBLndpZHRoICsgc2l6ZUIud2lkdGgsXG4gICAgICAgIGhlaWdodDogc2l6ZUEuaGVpZ2h0ICsgc2l6ZUIuaGVpZ2h0LFxuICAgIH07XG59XG5cbmZ1bmN0aW9uIHN1YnRyYWN0U2l6ZXMgKHNpemVBOiBTaXplLCBzaXplQjogU2l6ZSk6IFNpemUge1xuICAgIHJldHVybiB7XG4gICAgICAgIHdpZHRoOiAgc2l6ZUEud2lkdGggLSBzaXplQi53aWR0aCxcbiAgICAgICAgaGVpZ2h0OiBzaXplQS5oZWlnaHQgLSBzaXplQi5oZWlnaHQsXG4gICAgfTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQnJvd3NlclByb3ZpZGVyIHtcbiAgICBwcml2YXRlIHBsdWdpbjogYW55O1xuICAgIHByaXZhdGUgaW5pdFByb21pc2U6IFByb21pc2U8YW55PjtcbiAgICBwcml2YXRlIGlzTXVsdGlCcm93c2VyOiBib29sZWFuO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgbG9jYWxCcm93c2Vyc0luZm86IERpY3Rpb25hcnk8TG9jYWxCcm93c2VySW5mbz47XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IgKHBsdWdpbjogYW55KSB7XG4gICAgICAgIHRoaXMucGx1Z2luICAgICAgICAgPSBwbHVnaW47XG4gICAgICAgIHRoaXMuaW5pdFByb21pc2UgICAgPSBQcm9taXNlLnJlc29sdmUoZmFsc2UpO1xuICAgICAgICB0aGlzLmlzTXVsdGlCcm93c2VyID0gdGhpcy5wbHVnaW4uaXNNdWx0aUJyb3dzZXI7XG4gICAgICAgIC8vIEhBQ0s6IFRoZSBicm93c2VyIHdpbmRvdyBoYXMgZGlmZmVyZW50IGJvcmRlciBzaXplcyBpbiBub3JtYWwgYW5kIG1heGltaXplZCBtb2Rlcy4gU28sIHdlIG5lZWQgdG8gYmUgc3VyZSB0aGF0IHRoZSB3aW5kb3cgaXNcbiAgICAgICAgLy8gbm90IG1heGltaXplZCBiZWZvcmUgcmVzaXppbmcgaXQgaW4gb3JkZXIgdG8ga2VlcCB0aGUgbWVjaGFuaXNtIG9mIGNvcnJlY3RpbmcgdGhlIGNsaWVudCBhcmVhIHNpemUgd29ya2luZy4gV2hlbiBicm93c2VyIGlzIHN0YXJ0ZWQsXG4gICAgICAgIC8vIHdlIGFyZSByZXNpemluZyBpdCBmb3IgdGhlIGZpcnN0IHRpbWUgdG8gc3dpdGNoIHRoZSB3aW5kb3cgdG8gbm9ybWFsIG1vZGUsIGFuZCBmb3IgdGhlIHNlY29uZCB0aW1lIC0gdG8gcmVzdG9yZSB0aGUgY2xpZW50IGFyZWEgc2l6ZS5cbiAgICAgICAgdGhpcy5sb2NhbEJyb3dzZXJzSW5mbyA9IHt9O1xuICAgIH1cblxuICAgIHByaXZhdGUgX2Vuc3VyZUxvY2FsQnJvd3NlckluZm8gKGJyb3dzZXJJZDogc3RyaW5nKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0pXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgdGhpcy5sb2NhbEJyb3dzZXJzSW5mb1ticm93c2VySWRdID0ge1xuICAgICAgICAgICAgd2luZG93RGVzY3JpcHRvcjogIG51bGwsXG4gICAgICAgICAgICBtYXhTY3JlZW5TaXplOiAgICAgbnVsbCxcbiAgICAgICAgICAgIHJlc2l6ZUNvcnJlY3Rpb25zOiBudWxsLFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2ZpbmRXaW5kb3cgKGJyb3dzZXJJZDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAgICAgY29uc3QgcGFnZVRpdGxlID0gdGhpcy5fZ2V0UGFnZVRpdGxlKGJyb3dzZXJJZCk7XG5cbiAgICAgICAgcmV0dXJuIGJyb3dzZXJUb29scy5maW5kV2luZG93KHBhZ2VUaXRsZSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfZ2V0UGFnZVRpdGxlIChicm93c2VySWQ6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgICAgIGlmICh0aGlzLnBsdWdpbi5nZXRQYWdlVGl0bGUpXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wbHVnaW4uZ2V0UGFnZVRpdGxlKGJyb3dzZXJJZCk7XG5cbiAgICAgICAgcmV0dXJuIGJyb3dzZXJJZDtcbiAgICB9XG5cbiAgICBwcml2YXRlIF9nZXRXaW5kb3dEZXNjcmlwdG9yIChicm93c2VySWQ6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuICAgICAgICBpZiAodGhpcy5wbHVnaW4uZ2V0V2luZG93RGVzY3JpcHRvcilcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnBsdWdpbi5nZXRXaW5kb3dEZXNjcmlwdG9yKGJyb3dzZXJJZCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMubG9jYWxCcm93c2Vyc0luZm9bYnJvd3NlcklkXSAmJiB0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0ud2luZG93RGVzY3JpcHRvcjtcbiAgICB9XG5cbiAgICBwcml2YXRlIF9zZXRXaW5kb3dEZXNjcmlwdG9yIChicm93c2VySWQ6IHN0cmluZywgd2luZG93RGVzY3JpcHRvcjogc3RyaW5nIHwgbnVsbCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5wbHVnaW4uc2V0V2luZG93RGVzY3JpcHRvcikge1xuICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0V2luZG93RGVzY3JpcHRvcihicm93c2VySWQsIHdpbmRvd0Rlc2NyaXB0b3IpO1xuXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0ud2luZG93RGVzY3JpcHRvciA9IHdpbmRvd0Rlc2NyaXB0b3I7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfZ2V0TWF4U2NyZWVuU2l6ZSAoYnJvd3NlcklkOiBzdHJpbmcpOiBTaXplIHwgbnVsbCB7XG4gICAgICAgIHJldHVybiB0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0gJiYgdGhpcy5sb2NhbEJyb3dzZXJzSW5mb1ticm93c2VySWRdLm1heFNjcmVlblNpemU7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfZ2V0UmVzaXplQ29ycmVjdGlvbnMgKGJyb3dzZXJJZDogc3RyaW5nKTogU2l6ZSB8IG51bGwge1xuICAgICAgICByZXR1cm4gdGhpcy5sb2NhbEJyb3dzZXJzSW5mb1ticm93c2VySWRdICYmIHRoaXMubG9jYWxCcm93c2Vyc0luZm9bYnJvd3NlcklkXS5yZXNpemVDb3JyZWN0aW9ucztcbiAgICB9XG5cbiAgICBwcml2YXRlIF9pc0Jyb3dzZXJJZGxlIChicm93c2VySWQ6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgICAgICBjb25zdCBjb25uZWN0aW9uID0gQnJvd3NlckNvbm5lY3Rpb24uZ2V0QnlJZChicm93c2VySWQpIGFzIEJyb3dzZXJDb25uZWN0aW9uO1xuXG4gICAgICAgIHJldHVybiBjb25uZWN0aW9uLmlkbGU7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfY2FsY3VsYXRlUmVzaXplQ29ycmVjdGlvbnMgKGJyb3dzZXJJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICghdGhpcy5faXNCcm93c2VySWRsZShicm93c2VySWQpKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIGNvbnN0IHRpdGxlID0gYXdhaXQgdGhpcy5wbHVnaW4ucnVuSW5pdFNjcmlwdChicm93c2VySWQsIEdFVF9USVRMRV9TQ1JJUFQpO1xuXG4gICAgICAgIGlmICghYXdhaXQgYnJvd3NlclRvb2xzLmlzTWF4aW1pemVkKHRpdGxlKSlcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICBjb25zdCBjdXJyZW50U2l6ZSA9IGF3YWl0IHRoaXMucGx1Z2luLnJ1bkluaXRTY3JpcHQoYnJvd3NlcklkLCBHRVRfV0lORE9XX0RJTUVOU0lPTlNfSU5GT19TQ1JJUFQpIGFzIFdpbmRvd0RpbWVudGlvbnNJbmZvO1xuICAgICAgICBjb25zdCBldGFsb25TaXplICA9IHN1YnRyYWN0U2l6ZXMoY3VycmVudFNpemUsIFJFU0laRV9ESUZGX1NJWkUpO1xuXG4gICAgICAgIGF3YWl0IGJyb3dzZXJUb29scy5yZXNpemUodGl0bGUsIGN1cnJlbnRTaXplLndpZHRoLCBjdXJyZW50U2l6ZS5oZWlnaHQsIGV0YWxvblNpemUud2lkdGgsIGV0YWxvblNpemUuaGVpZ2h0KTtcblxuICAgICAgICBsZXQgcmVzaXplZFNpemUgICAgPSBhd2FpdCB0aGlzLnBsdWdpbi5ydW5Jbml0U2NyaXB0KGJyb3dzZXJJZCwgR0VUX1dJTkRPV19ESU1FTlNJT05TX0lORk9fU0NSSVBUKSBhcyBXaW5kb3dEaW1lbnRpb25zSW5mbztcbiAgICAgICAgbGV0IGNvcnJlY3Rpb25TaXplID0gc3VidHJhY3RTaXplcyhyZXNpemVkU2l6ZSwgZXRhbG9uU2l6ZSk7XG5cbiAgICAgICAgYXdhaXQgYnJvd3NlclRvb2xzLnJlc2l6ZSh0aXRsZSwgcmVzaXplZFNpemUud2lkdGgsIHJlc2l6ZWRTaXplLmhlaWdodCwgZXRhbG9uU2l6ZS53aWR0aCwgZXRhbG9uU2l6ZS5oZWlnaHQpO1xuXG4gICAgICAgIHJlc2l6ZWRTaXplID0gYXdhaXQgdGhpcy5wbHVnaW4ucnVuSW5pdFNjcmlwdChicm93c2VySWQsIEdFVF9XSU5ET1dfRElNRU5TSU9OU19JTkZPX1NDUklQVCkgYXMgV2luZG93RGltZW50aW9uc0luZm87XG5cbiAgICAgICAgY29ycmVjdGlvblNpemUgPSBzdW1TaXplcyhjb3JyZWN0aW9uU2l6ZSwgc3VidHJhY3RTaXplcyhyZXNpemVkU2l6ZSwgZXRhbG9uU2l6ZSkpO1xuXG4gICAgICAgIGlmICh0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0pXG4gICAgICAgICAgICB0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0ucmVzaXplQ29ycmVjdGlvbnMgPSBjb3JyZWN0aW9uU2l6ZTtcblxuICAgICAgICBhd2FpdCBicm93c2VyVG9vbHMubWF4aW1pemUodGl0bGUpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2NhbGN1bGF0ZU1hY1NpemVMaW1pdHMgKGJyb3dzZXJJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICghdGhpcy5faXNCcm93c2VySWRsZShicm93c2VySWQpKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIGNvbnN0IHNpemVJbmZvID0gYXdhaXQgdGhpcy5wbHVnaW4ucnVuSW5pdFNjcmlwdChicm93c2VySWQsIEdFVF9XSU5ET1dfRElNRU5TSU9OU19JTkZPX1NDUklQVCkgYXMgV2luZG93RGltZW50aW9uc0luZm87XG5cbiAgICAgICAgaWYgKHRoaXMubG9jYWxCcm93c2Vyc0luZm9bYnJvd3NlcklkXSkge1xuICAgICAgICAgICAgdGhpcy5sb2NhbEJyb3dzZXJzSW5mb1ticm93c2VySWRdLm1heFNjcmVlblNpemUgPSB7XG4gICAgICAgICAgICAgICAgd2lkdGg6ICBzaXplSW5mby5hdmFpbGFibGVXaWR0aCAtIChzaXplSW5mby5vdXRlcldpZHRoIC0gc2l6ZUluZm8ud2lkdGgpLFxuICAgICAgICAgICAgICAgIGhlaWdodDogc2l6ZUluZm8uYXZhaWxhYmxlSGVpZ2h0IC0gKHNpemVJbmZvLm91dGVySGVpZ2h0IC0gc2l6ZUluZm8uaGVpZ2h0KSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9lbnN1cmVCcm93c2VyV2luZG93RGVzY3JpcHRvciAoYnJvd3NlcklkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKHRoaXMuX2dldFdpbmRvd0Rlc2NyaXB0b3IoYnJvd3NlcklkKSlcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICBhd2FpdCB0aGlzLl9lbnN1cmVMb2NhbEJyb3dzZXJJbmZvKGJyb3dzZXJJZCk7XG5cbiAgICAgICAgLy8gTk9URTogZGVsYXkgdG8gZW5zdXJlIHRoZSB3aW5kb3cgZmluaXNoZWQgdGhlIG9wZW5pbmdcbiAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4ud2FpdEZvckNvbm5lY3Rpb25SZWFkeShicm93c2VySWQpO1xuICAgICAgICBhd2FpdCBkZWxheShCUk9XU0VSX09QRU5JTkdfREVMQVkpO1xuXG4gICAgICAgIGlmICh0aGlzLmxvY2FsQnJvd3NlcnNJbmZvW2Jyb3dzZXJJZF0pIHtcbiAgICAgICAgICAgIGNvbnN0IGNvbm5lY3Rpb24gICAgID0gQnJvd3NlckNvbm5lY3Rpb24uZ2V0QnlJZChicm93c2VySWQpIGFzIEJyb3dzZXJDb25uZWN0aW9uO1xuICAgICAgICAgICAgbGV0IHdpbmRvd0Rlc2NyaXB0b3IgPSBudWxsO1xuXG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHdpbmRvd0Rlc2NyaXB0b3IgPSBhd2FpdCB0aGlzLl9maW5kV2luZG93KGJyb3dzZXJJZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICAgICAgICAvLyBOT1RFOiBXZSBjYW4gc3VwcHJlc3MgdGhlIGVycm9yIGhlcmUgc2luY2Ugd2UgY2FuIGp1c3QgZGlzYWJsZSB3aW5kb3cgbWFuaXB1bGF0aW9uIGZ1bmN0aW9uc1xuICAgICAgICAgICAgICAgIC8vIHdoZW4gd2UgY2Fubm90IGZpbmQgYSBsb2NhbCB3aW5kb3cgZGVzY3JpcHRvclxuICAgICAgICAgICAgICAgIERFQlVHX0xPR0dFUihlcnIpO1xuICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24uYWRkV2FybmluZyhcbiAgICAgICAgICAgICAgICAgICAgV0FSTklOR19NRVNTQUdFLmNhbm5vdEZpbmRXaW5kb3dEZXNjcmlwdG9yRXJyb3IsXG4gICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24uYnJvd3NlckluZm8uYWxpYXMsXG4gICAgICAgICAgICAgICAgICAgIGVyci5tZXNzYWdlXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5fc2V0V2luZG93RGVzY3JpcHRvcihicm93c2VySWQsIHdpbmRvd0Rlc2NyaXB0b3IpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfZW5zdXJlQnJvd3NlcldpbmRvd1BhcmFtZXRlcnMgKGJyb3dzZXJJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuX2Vuc3VyZUJyb3dzZXJXaW5kb3dEZXNjcmlwdG9yKGJyb3dzZXJJZCk7XG5cbiAgICAgICAgaWYgKE9TLndpbiAmJiAhdGhpcy5fZ2V0UmVzaXplQ29ycmVjdGlvbnMoYnJvd3NlcklkKSlcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX2NhbGN1bGF0ZVJlc2l6ZUNvcnJlY3Rpb25zKGJyb3dzZXJJZCk7XG4gICAgICAgIGVsc2UgaWYgKE9TLm1hYyAmJiAhdGhpcy5fZ2V0TWF4U2NyZWVuU2l6ZShicm93c2VySWQpKVxuICAgICAgICAgICAgYXdhaXQgdGhpcy5fY2FsY3VsYXRlTWFjU2l6ZUxpbWl0cyhicm93c2VySWQpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2Nsb3NlTG9jYWxCcm93c2VyIChicm93c2VySWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5wbHVnaW4ubmVlZENsZWFuVXBCcm93c2VySW5mbylcbiAgICAgICAgICAgIHRoaXMucGx1Z2luLmNsZWFuVXBCcm93c2VySW5mbyhicm93c2VySWQpO1xuXG4gICAgICAgIGNvbnN0IHdpbmRvd0Rlc2NyaXB0b3IgPSB0aGlzLl9nZXRXaW5kb3dEZXNjcmlwdG9yKGJyb3dzZXJJZCk7XG5cbiAgICAgICAgYXdhaXQgYnJvd3NlclRvb2xzLmNsb3NlKHdpbmRvd0Rlc2NyaXB0b3IpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX3Jlc2l6ZUxvY2FsQnJvd3NlcldpbmRvdyAoYnJvd3NlcklkOiBzdHJpbmcsIHdpZHRoOiBudW1iZXIsIGhlaWdodDogbnVtYmVyLCBjdXJyZW50V2lkdGg6IG51bWJlciwgY3VycmVudEhlaWdodDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuX2Vuc3VyZUJyb3dzZXJXaW5kb3dEZXNjcmlwdG9yKGJyb3dzZXJJZCk7XG5cbiAgICAgICAgY29uc3QgcmVzaXplQ29ycmVjdGlvbnMgPSB0aGlzLl9nZXRSZXNpemVDb3JyZWN0aW9ucyhicm93c2VySWQpO1xuXG4gICAgICAgIGlmIChyZXNpemVDb3JyZWN0aW9ucyAmJiBhd2FpdCBicm93c2VyVG9vbHMuaXNNYXhpbWl6ZWQodGhpcy5fZ2V0V2luZG93RGVzY3JpcHRvcihicm93c2VySWQpKSkge1xuICAgICAgICAgICAgd2lkdGggLT0gcmVzaXplQ29ycmVjdGlvbnMud2lkdGg7XG4gICAgICAgICAgICBoZWlnaHQgLT0gcmVzaXplQ29ycmVjdGlvbnMuaGVpZ2h0O1xuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgYnJvd3NlclRvb2xzLnJlc2l6ZSh0aGlzLl9nZXRXaW5kb3dEZXNjcmlwdG9yKGJyb3dzZXJJZCksIGN1cnJlbnRXaWR0aCwgY3VycmVudEhlaWdodCwgd2lkdGgsIGhlaWdodCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfdGFrZUxvY2FsQnJvd3NlclNjcmVlbnNob3QgKGJyb3dzZXJJZDogc3RyaW5nLCBzY3JlZW5zaG90UGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IGJyb3dzZXJUb29scy5zY3JlZW5zaG90KHRoaXMuX2dldFdpbmRvd0Rlc2NyaXB0b3IoYnJvd3NlcklkKSwgc2NyZWVuc2hvdFBhdGgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2NhblJlc2l6ZUxvY2FsQnJvd3NlcldpbmRvd1RvRGltZW5zaW9ucyAoYnJvd3NlcklkOiBzdHJpbmcsIHdpZHRoOiBudW1iZXIsIGhlaWdodDogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIGlmICghT1MubWFjKVxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG5cbiAgICAgICAgY29uc3QgbWF4U2NyZWVuU2l6ZSA9IHRoaXMuX2dldE1heFNjcmVlblNpemUoYnJvd3NlcklkKSBhcyBTaXplO1xuXG4gICAgICAgIHJldHVybiB3aWR0aCA8PSBtYXhTY3JlZW5TaXplLndpZHRoICYmIGhlaWdodCA8PSBtYXhTY3JlZW5TaXplLmhlaWdodDtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9tYXhpbWl6ZUxvY2FsQnJvd3NlcldpbmRvdyAoYnJvd3NlcklkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5fZW5zdXJlQnJvd3NlcldpbmRvd0Rlc2NyaXB0b3IoYnJvd3NlcklkKTtcblxuICAgICAgICBhd2FpdCBicm93c2VyVG9vbHMubWF4aW1pemUodGhpcy5fZ2V0V2luZG93RGVzY3JpcHRvcihicm93c2VySWQpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9lbnN1cmVSZXRyeVRlc3RQYWdlc1dhcm5pbmcgKGJyb3dzZXJJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IGNvbm5lY3Rpb24gPSBCcm93c2VyQ29ubmVjdGlvbi5nZXRCeUlkKGJyb3dzZXJJZCkgYXMgQnJvd3NlckNvbm5lY3Rpb247XG5cbiAgICAgICAgaWYgKGNvbm5lY3Rpb24/LnJldHJ5VGVzdFBhZ2VzKSB7XG4gICAgICAgICAgICBjb25zdCBpc1NlcnZpY2VXb3JrZXJFbmFibGVkID0gYXdhaXQgdGhpcy5wbHVnaW4ucnVuSW5pdFNjcmlwdChicm93c2VySWQsIEdFVF9JU19TRVJWSUNFX1dPUktFUl9FTkFCTEVEKTtcblxuICAgICAgICAgICAgaWYgKCFpc1NlcnZpY2VXb3JrZXJFbmFibGVkKVxuICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24uYWRkV2FybmluZyhXQVJOSU5HX01FU1NBR0UucmV0cnlUZXN0UGFnZXNJc05vdFN1cHBvcnRlZCwgY29ubmVjdGlvbi5icm93c2VySW5mby5hbGlhcywgY29ubmVjdGlvbi5icm93c2VySW5mby5hbGlhcyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMgKGJyb3dzZXJJZDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIGNvbnN0IGlzTG9jYWxCcm93c2VyICAgID0gYXdhaXQgdGhpcy5wbHVnaW4uaXNMb2NhbEJyb3dzZXIoYnJvd3NlcklkKTtcbiAgICAgICAgY29uc3QgaXNIZWFkbGVzc0Jyb3dzZXIgPSBhd2FpdCB0aGlzLnBsdWdpbi5pc0hlYWRsZXNzQnJvd3Nlcihicm93c2VySWQpO1xuXG4gICAgICAgIHJldHVybiBpc0xvY2FsQnJvd3NlciAmJiAhaXNIZWFkbGVzc0Jyb3dzZXI7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGluaXQgKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBpbml0aWFsaXplZCA9IGF3YWl0IHRoaXMuaW5pdFByb21pc2U7XG5cbiAgICAgICAgaWYgKGluaXRpYWxpemVkKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMuaW5pdFByb21pc2UgPSB0aGlzLnBsdWdpblxuICAgICAgICAgICAgLmluaXQoKVxuICAgICAgICAgICAgLnRoZW4oKCkgPT4gdHJ1ZSk7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuaW5pdFByb21pc2U7XG4gICAgICAgIH1cbiAgICAgICAgY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICB0aGlzLmluaXRQcm9taXNlID0gUHJvbWlzZS5yZXNvbHZlKGZhbHNlKTtcblxuICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZGlzcG9zZSAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IGluaXRpYWxpemVkID0gYXdhaXQgdGhpcy5pbml0UHJvbWlzZTtcblxuICAgICAgICBpZiAoIWluaXRpYWxpemVkKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMuaW5pdFByb21pc2UgPSB0aGlzLnBsdWdpblxuICAgICAgICAgICAgLmRpc3Bvc2UoKVxuICAgICAgICAgICAgLnRoZW4oKCkgPT4gZmFsc2UpO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmluaXRQcm9taXNlO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgdGhpcy5pbml0UHJvbWlzZSA9IFByb21pc2UucmVzb2x2ZShmYWxzZSk7XG5cbiAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGlzTG9jYWxCcm93c2VyIChicm93c2VySWQ/OiBzdHJpbmcsIGJyb3dzZXJOYW1lPzogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLnBsdWdpbi5pc0xvY2FsQnJvd3Nlcihicm93c2VySWQsIGJyb3dzZXJOYW1lKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaXNIZWFkbGVzc0Jyb3dzZXIgKGJyb3dzZXJJZD86IHN0cmluZywgYnJvd3Nlck5hbWU/OiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMucGx1Z2luLmlzSGVhZGxlc3NCcm93c2VyKGJyb3dzZXJJZCwgYnJvd3Nlck5hbWUpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBnZXRPU0luZm8gKGJyb3dzZXJJZDogc3RyaW5nKTogUHJvbWlzZTxPU0luZm8gfCBudWxsPiB7XG4gICAgICAgIGlmIChhd2FpdCB0aGlzLmlzTG9jYWxCcm93c2VyKGJyb3dzZXJJZCkpXG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZ2V0TG9jYWxPU0luZm8oKTtcblxuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5wbHVnaW4uZ2V0T1NJbmZvKGJyb3dzZXJJZCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIG9wZW5Ccm93c2VyIChicm93c2VySWQ6IHN0cmluZywgcGFnZVVybDogc3RyaW5nLCBicm93c2VyT3B0aW9uOiB1bmtub3duLCBhZGRpdGlvbmFsT3B0aW9uczogT3BlbkJyb3dzZXJBZGRpdGlvbmFsT3B0aW9ucyA9IHsgZGlzYWJsZU11bHRpcGxlV2luZG93czogZmFsc2UgfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5vcGVuQnJvd3Nlcihicm93c2VySWQsIHBhZ2VVcmwsIGJyb3dzZXJPcHRpb24sIGFkZGl0aW9uYWxPcHRpb25zKTtcblxuICAgICAgICBhd2FpdCB0aGlzLl9lbnN1cmVSZXRyeVRlc3RQYWdlc1dhcm5pbmcoYnJvd3NlcklkKTtcblxuICAgICAgICBpZiAoYXdhaXQgdGhpcy5jYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyhicm93c2VySWQpKVxuICAgICAgICAgICAgYXdhaXQgdGhpcy5fZW5zdXJlQnJvd3NlcldpbmRvd1BhcmFtZXRlcnMoYnJvd3NlcklkKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgY2xvc2VCcm93c2VyIChicm93c2VySWQ6IHN0cmluZywgZGF0YTogQnJvd3NlckNsb3NpbmdJbmZvKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IGNhblVzZURlZmF1bHRXaW5kb3dBY3Rpb25zID0gYXdhaXQgdGhpcy5jYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyhicm93c2VySWQpO1xuICAgICAgICBjb25zdCBjdXN0b21BY3Rpb25zSW5mbyAgICAgICAgICA9IGF3YWl0IHRoaXMuaGFzQ3VzdG9tQWN0aW9uRm9yQnJvd3Nlcihicm93c2VySWQpO1xuICAgICAgICBjb25zdCBoYXNDdXN0b21DbG9zZUJyb3dzZXIgICAgICA9IGN1c3RvbUFjdGlvbnNJbmZvLmhhc0Nsb3NlQnJvd3NlcjtcbiAgICAgICAgY29uc3QgdXNlUGx1Z2luc0Nsb3NlQnJvd3NlciAgICAgPSBoYXNDdXN0b21DbG9zZUJyb3dzZXIgfHwgIWNhblVzZURlZmF1bHRXaW5kb3dBY3Rpb25zO1xuXG4gICAgICAgIGlmICh1c2VQbHVnaW5zQ2xvc2VCcm93c2VyKVxuICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uY2xvc2VCcm93c2VyKGJyb3dzZXJJZCwgZGF0YSk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX2Nsb3NlTG9jYWxCcm93c2VyKGJyb3dzZXJJZCk7XG5cbiAgICAgICAgaWYgKGNhblVzZURlZmF1bHRXaW5kb3dBY3Rpb25zKVxuICAgICAgICAgICAgZGVsZXRlIHRoaXMubG9jYWxCcm93c2Vyc0luZm9bYnJvd3NlcklkXTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZ2V0QnJvd3Nlckxpc3QgKCk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucGx1Z2luLmdldEJyb3dzZXJMaXN0KCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGlzVmFsaWRCcm93c2VyTmFtZSAoYnJvd3Nlck5hbWU6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5wbHVnaW4uaXNWYWxpZEJyb3dzZXJOYW1lKGJyb3dzZXJOYW1lKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgcmVzaXplV2luZG93IChicm93c2VySWQ6IHN0cmluZywgd2lkdGg6IG51bWJlciwgaGVpZ2h0OiBudW1iZXIsIGN1cnJlbnRXaWR0aDogbnVtYmVyLCBjdXJyZW50SGVpZ2h0OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMgPSBhd2FpdCB0aGlzLmNhblVzZURlZmF1bHRXaW5kb3dBY3Rpb25zKGJyb3dzZXJJZCk7XG4gICAgICAgIGNvbnN0IGN1c3RvbUFjdGlvbnNJbmZvICAgICAgICAgID0gYXdhaXQgdGhpcy5oYXNDdXN0b21BY3Rpb25Gb3JCcm93c2VyKGJyb3dzZXJJZCk7XG4gICAgICAgIGNvbnN0IGhhc0N1c3RvbVJlc2l6ZVdpbmRvdyAgICAgID0gY3VzdG9tQWN0aW9uc0luZm8uaGFzUmVzaXplV2luZG93O1xuXG5cbiAgICAgICAgaWYgKGNhblVzZURlZmF1bHRXaW5kb3dBY3Rpb25zICYmICFoYXNDdXN0b21SZXNpemVXaW5kb3cpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX3Jlc2l6ZUxvY2FsQnJvd3NlcldpbmRvdyhicm93c2VySWQsIHdpZHRoLCBoZWlnaHQsIGN1cnJlbnRXaWR0aCwgY3VycmVudEhlaWdodCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5yZXNpemVXaW5kb3coYnJvd3NlcklkLCB3aWR0aCwgaGVpZ2h0LCBjdXJyZW50V2lkdGgsIGN1cnJlbnRIZWlnaHQpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBjYW5SZXNpemVXaW5kb3dUb0RpbWVuc2lvbnMgKGJyb3dzZXJJZDogc3RyaW5nLCB3aWR0aDogbnVtYmVyLCBoZWlnaHQ6IG51bWJlcik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgICAgICBjb25zdCBjYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyAgICAgPSBhd2FpdCB0aGlzLmNhblVzZURlZmF1bHRXaW5kb3dBY3Rpb25zKGJyb3dzZXJJZCk7XG4gICAgICAgIGNvbnN0IGN1c3RvbUFjdGlvbnNJbmZvICAgICAgICAgICAgICA9IGF3YWl0IHRoaXMuaGFzQ3VzdG9tQWN0aW9uRm9yQnJvd3Nlcihicm93c2VySWQpO1xuICAgICAgICBjb25zdCBoYXNDdXN0b21DYW5SZXNpemVUb0RpbWVuc2lvbnMgPSBjdXN0b21BY3Rpb25zSW5mby5oYXNDYW5SZXNpemVXaW5kb3dUb0RpbWVuc2lvbnM7XG5cblxuICAgICAgICBpZiAoY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMgJiYgIWhhc0N1c3RvbUNhblJlc2l6ZVRvRGltZW5zaW9ucylcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCB0aGlzLl9jYW5SZXNpemVMb2NhbEJyb3dzZXJXaW5kb3dUb0RpbWVuc2lvbnMoYnJvd3NlcklkLCB3aWR0aCwgaGVpZ2h0KTtcblxuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5wbHVnaW4uY2FuUmVzaXplV2luZG93VG9EaW1lbnNpb25zKGJyb3dzZXJJZCwgd2lkdGgsIGhlaWdodCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIG1heGltaXplV2luZG93IChicm93c2VySWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBjYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyA9IGF3YWl0IHRoaXMuY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMoYnJvd3NlcklkKTtcbiAgICAgICAgY29uc3QgY3VzdG9tQWN0aW9uc0luZm8gICAgICAgICAgPSBhd2FpdCB0aGlzLmhhc0N1c3RvbUFjdGlvbkZvckJyb3dzZXIoYnJvd3NlcklkKTtcbiAgICAgICAgY29uc3QgaGFzQ3VzdG9tTWF4aW1pemVXaW5kb3cgICAgPSBjdXN0b21BY3Rpb25zSW5mby5oYXNNYXhpbWl6ZVdpbmRvdztcblxuICAgICAgICBpZiAoY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMgJiYgIWhhc0N1c3RvbU1heGltaXplV2luZG93KVxuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuX21heGltaXplTG9jYWxCcm93c2VyV2luZG93KGJyb3dzZXJJZCk7XG5cbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucGx1Z2luLm1heGltaXplV2luZG93KGJyb3dzZXJJZCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHRha2VTY3JlZW5zaG90IChicm93c2VySWQ6IHN0cmluZywgc2NyZWVuc2hvdFBhdGg6IHN0cmluZywgcGFnZVdpZHRoOiBudW1iZXIsIHBhZ2VIZWlnaHQ6IG51bWJlciwgZnVsbFBhZ2U6IGJvb2xlYW4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMgID0gYXdhaXQgdGhpcy5jYW5Vc2VEZWZhdWx0V2luZG93QWN0aW9ucyhicm93c2VySWQpO1xuICAgICAgICBjb25zdCBjdXN0b21BY3Rpb25zSW5mbyAgICAgICAgICAgPSBhd2FpdCB0aGlzLmhhc0N1c3RvbUFjdGlvbkZvckJyb3dzZXIoYnJvd3NlcklkKTtcbiAgICAgICAgY29uc3QgaGFzQ3VzdG9tVGFrZVNjcmVlbnNob3QgICAgID0gY3VzdG9tQWN0aW9uc0luZm8uaGFzVGFrZVNjcmVlbnNob3Q7XG4gICAgICAgIGNvbnN0IGNvbm5lY3Rpb24gICAgICAgICAgICAgICAgICA9IEJyb3dzZXJDb25uZWN0aW9uLmdldEJ5SWQoYnJvd3NlcklkKSBhcyBCcm93c2VyQ29ubmVjdGlvbjtcbiAgICAgICAgY29uc3QgdGFrZUxvY2FsQnJvd3NlcnNTY3JlZW5zaG90ID0gY2FuVXNlRGVmYXVsdFdpbmRvd0FjdGlvbnMgJiYgIWhhc0N1c3RvbVRha2VTY3JlZW5zaG90O1xuICAgICAgICBjb25zdCBpc0xvY2FsRnVsbFBhZ2VNb2RlICAgICAgICAgPSB0YWtlTG9jYWxCcm93c2Vyc1NjcmVlbnNob3QgJiYgZnVsbFBhZ2U7XG5cbiAgICAgICAgaWYgKGlzTG9jYWxGdWxsUGFnZU1vZGUpIHtcbiAgICAgICAgICAgIGNvbm5lY3Rpb24uYWRkV2FybmluZyhXQVJOSU5HX01FU1NBR0Uuc2NyZWVuc2hvdHNGdWxsUGFnZU5vdFN1cHBvcnRlZCwgY29ubmVjdGlvbi5icm93c2VySW5mby5hbGlhcyk7XG5cbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IG1ha2VEaXIoZGlybmFtZShzY3JlZW5zaG90UGF0aCkpO1xuXG4gICAgICAgIGlmICh0YWtlTG9jYWxCcm93c2Vyc1NjcmVlbnNob3QpXG4gICAgICAgICAgICBhd2FpdCB0aGlzLl90YWtlTG9jYWxCcm93c2VyU2NyZWVuc2hvdChicm93c2VySWQsIHNjcmVlbnNob3RQYXRoKTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4udGFrZVNjcmVlbnNob3QoYnJvd3NlcklkLCBzY3JlZW5zaG90UGF0aCwgcGFnZVdpZHRoLCBwYWdlSGVpZ2h0LCBmdWxsUGFnZSk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGdldFZpZGVvRnJhbWVEYXRhIChicm93c2VySWQ6IHN0cmluZyk6IFByb21pc2U8YW55PiB7XG4gICAgICAgIHJldHVybiB0aGlzLnBsdWdpbi5nZXRWaWRlb0ZyYW1lRGF0YShicm93c2VySWQpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBzdGFydENhcHR1cmluZ1ZpZGVvIChicm93c2VySWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zdGFydENhcHR1cmluZ1ZpZGVvKGJyb3dzZXJJZCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHN0b3BDYXB0dXJpbmdWaWRlbyAoYnJvd3NlcklkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc3RvcENhcHR1cmluZ1ZpZGVvKGJyb3dzZXJJZCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGhhc0N1c3RvbUFjdGlvbkZvckJyb3dzZXIgKGJyb3dzZXJJZDogc3RyaW5nKTogUHJvbWlzZTxhbnk+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMucGx1Z2luLmhhc0N1c3RvbUFjdGlvbkZvckJyb3dzZXIoYnJvd3NlcklkKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgcmVwb3J0Sm9iUmVzdWx0IChicm93c2VySWQ6IHN0cmluZywgc3RhdHVzOiBzdHJpbmcsIGRhdGE6IGFueSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5yZXBvcnRKb2JSZXN1bHQoYnJvd3NlcklkLCBzdGF0dXMsIGRhdGEpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRBY3RpdmVXaW5kb3dJZCAoYnJvd3NlcklkOiBzdHJpbmcpOiBzdHJpbmcgfCBudWxsIHtcbiAgICAgICAgaWYgKCF0aGlzLnBsdWdpbi5zdXBwb3J0TXVsdGlwbGVXaW5kb3dzKVxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucGx1Z2luLmdldEFjdGl2ZVdpbmRvd0lkKGJyb3dzZXJJZCk7XG4gICAgfVxuXG4gICAgcHVibGljIHNldEFjdGl2ZVdpbmRvd0lkIChicm93c2VySWQ6IHN0cmluZywgdmFsOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5wbHVnaW4uc2V0QWN0aXZlV2luZG93SWQoYnJvd3NlcklkLCB2YWwpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBvcGVuRmlsZVByb3RvY29sIChicm93c2VySWQ6IHN0cmluZywgdXJsOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4ub3BlbkZpbGVQcm90b2NvbChicm93c2VySWQsIHVybCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGNsb3NlQnJvd3NlckNoaWxkV2luZG93IChicm93c2VySWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5jbG9zZUJyb3dzZXJDaGlsZFdpbmRvdyhicm93c2VySWQpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBkaXNwYXRjaFByb3h5bGVzc0V2ZW50IChicm93c2VySWQ6IHN0cmluZywgdHlwZTogRXZlbnRUeXBlLCBvcHRpb25zOiBhbnkpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uZGlzcGF0Y2hQcm94eWxlc3NFdmVudChicm93c2VySWQsIHR5cGUsIG9wdGlvbnMpO1xuICAgIH1cbn1cbiJdfQ==
|