UNPKG

@netgrif/components-core

Version:

Netgrif Application engine frontend core Angular library

300 lines 43.9 kB
import { OpenedTab } from './opened-tab'; import { Injector } from '@angular/core'; import { ComponentPortal } from '@angular/cdk/portal'; import { orderBy } from 'natural-orderby'; import { NAE_TAB_DATA } from '../tab-data-injection-token/tab-data-injection-token'; import { IncrementingCounter } from '../../utility/incrementing-counter'; import { NAE_VIEW_ID_SEGMENT } from '../../user/models/view-id-injection-tokens'; import { FormControl } from '@angular/forms'; /** * Holds the logic for tab management in {@link AbstractTabViewComponent}. * If you want to implement your own TabViewComponent, you might want to extend this class to hold your logic. */ export class TabView { _viewService; _logger; _initialTabs; _parentInjector; static DYNAMIC_TAB_VIEW_ID_SEGMENT = 'dynamic'; /** * Holds the tabs that are opened in the tab view, and allows them to be bound to HTML. */ openedTabs; /** * Holds the index of the currently selected tab. * * Selected index initializes to `0`. */ selectedIndex; uniqueIdCounter = new IncrementingCounter(); _switching = false; _pendingTabUniqueId; /** * @ignore * Holds a reference to an object that hides some public attributes and methods from tabs. */ tabViewInterface = { currentlySelectedTab: () => this.currentlySelectedTab(), openTab: (tabContent, autoswitch = false) => this.openTab(tabContent, autoswitch), switchToTabIndex: (index) => this.switchToTabIndex(index), switchToTabUniqueId: (uniqueId) => this.switchToTabUniqueId(uniqueId), closeTabIndex: (index, force = false) => this.closeTabIndex(index, force), closeTabUniqueId: (uniqueId, force = false) => this.closeTabUniqueId(uniqueId, force) }; /** * @param _viewService [ViewService]{@link ViewService} reference * @param _logger [Logger]{@link LoggerService} reference * @param _initialTabs Tabs that should be initially opened in the tab view * @param _parentInjector `Injector` instance of the [TabViewComponent]{@link AbstractTabViewComponent}, * to be passed onto each tab, so that the dependency injection tree is not broken */ constructor(_viewService, _logger, _initialTabs, _parentInjector) { this._viewService = _viewService; this._logger = _logger; this._initialTabs = _initialTabs; this._parentInjector = _parentInjector; this._initialTabs.forEach(tab => { if (tab.order === undefined) { tab.order = 0; } tab.initial = true; }); this.selectedIndex = new FormControl(0); // orderBy is a stable sort // Native javascript implementation has undefined stability and it depends on it's implementation (browser) this.openedTabs = orderBy(this._initialTabs, v => v.order, 'asc').map(tabData => new OpenedTab(tabData, `${this.uniqueIdCounter.next()}`)); if (this.openedTabs.length > 0) { this.openedTabs[0].tabSelected$.next(true); } } /** * @returns the index of the currently selected tab */ currentlySelectedTab() { return this.selectedIndex.value; } /** * Opens a new tab with the provided content. * @param tabContent - content of the new tab * @param autoswitch - whether the newly opened tab should be switched to. Defaults to `false`. * @param openExisting - whether the opened tab already existing should be switched to existing one. Defaults to `true`. * @returns the `tabUniqueId` of the newly opened tab */ openTab(tabContent, autoswitch = false, openExisting = true) { if (tabContent.initial) { this._logger.warn(`'initial' attribute is not meant to be used with new tabs and will be ignored`); delete tabContent.initial; } const newTab = new OpenedTab(tabContent, `${this.uniqueIdCounter.next()}`); const indexExisting = this.findIndexExistingTab(newTab); if (indexExisting === -1 || !openExisting) { return this.openNewTab(newTab, autoswitch); } else { this.setTabIndexWithNotification(indexExisting); return this.openedTabs[indexExisting].uniqueId; } } findIndexExistingTab(newTab) { if (!this.searchesForOneCaseId(newTab)) { return -1; } return this.openedTabs.findIndex(existingTab => this.searchesForOneCaseId(existingTab) && this.getSearchedCaseId(existingTab) === this.getSearchedCaseId(newTab)); } searchesForOneCaseId(tab) { return this.hasCaseFilterParamSet(tab) && !Array.isArray(this.getSearchedCase(tab)) && !!this.getSearchedCaseId(tab); } getSearchedCaseId(tab) { return this.getSearchedCase(tab).id; } getSearchedCase(tab) { return tab.injectedObject.baseFilter.getRequestBody().case; } hasCaseFilterParamSet(tab) { return this.hasBaseFilter(tab) && !!(tab.injectedObject.baseFilter.getRequestBody().case); } hasBaseFilter(tab) { return this.hasInjectedObject(tab) && !!(tab.injectedObject.baseFilter); } hasInjectedObject(tab) { return !!tab.injectedObject; } /** * Adds a new tab into the correct position based on its `order` property. * @param newTab the tab that should be opened * @param autoswitch whether the new tab should be switched to after it is created * @returns the `uniqueId` of the opened tab */ openNewTab(newTab, autoswitch) { let index = this.openedTabs.findIndex(existingTab => existingTab.order > newTab.order); if (index === -1) { index = this.openedTabs.length; } this.openedTabs.splice(index, 0, newTab); if (autoswitch || this.openedTabs.length === 1) { this.setTabIndexWithNotification(index); } return newTab.uniqueId; } /** * Switches to a tab with the given `index`. * * Throws an error if the `index` is invalid. * @param index - index of the tab that should be switched to */ switchToTabIndex(index) { this.checkIndexRange(index); this.setTabIndexWithNotification(index); } /** * Switches to a tab with the given `uniqueId`. * * Throws an error if the `uniqueId` is invalid. * @param uniqueId - id of the tab that should be switched to */ switchToTabUniqueId(uniqueId) { this.setTabIndexWithNotification(this.getTabIndex(uniqueId)); } setTabIndexWithNotification(index) { this.openedTabs[this.selectedIndex.value].tabSelected$.next(false); this.selectedIndex.setValue(index); this.openedTabs[this.selectedIndex.value].tabSelected$.next(true); } /** * Closes the tab with the given `index`. * * Throws an error if the `index` is invalid. * * Throws an error if the tab has it's `canBeClosed` property set to `false`. * @param index index of the tab that should be closed * @param force when `true` closes a tab even if it's `cantBeClosed` attribute is set to `true` */ closeTabIndex(index, force = false) { this.closeTab(index, force, `Tab at index ${index} can't be closed`); } /** * Closes the tab with the given `uniqueId`. Throws an error if the `uniqueId` is invalid. * Throws an error if the tab has it's `canBeClosed` property set to `false`. * @param uniqueId - id of the tab that should be closed * @param force when `true` closes a tab even if it's `cantBeClosed` attribute is set to `true` */ closeTabUniqueId(uniqueId, force = false) { const index = this.getTabIndex(uniqueId); this.closeTab(index, force, `Tab with ID ${uniqueId} can't be closed`); } /** * Closes the tab at the given index. * * If the conditions for closing a tab are not met throws an `Error` with the given message. * @param index index of the tab that should be closed * @param force when `true` closes a tab even if it's `cantBeClosed` attribute is set to `true` * @param error the message that should be displayed if the conditions for closing a tab are not met */ closeTab(index, force, error) { this.checkIndexRange(index); if (!force && !this.openedTabs[index].canBeClosed) { throw new Error(error); } if (index === this.selectedIndex.value && this.openedTabs[index].parentUniqueId && this.openedTabs.findIndex(tab => tab.uniqueId === this.openedTabs[index].parentUniqueId) !== -1) { this.switchToTabUniqueId(this.openedTabs[index].parentUniqueId); } if (index === this.selectedIndex.value && this.selectedIndex.value + 1 < this.openedTabs.length) { this.openedTabs[index + 1].tabSelected$.next(true); } this.openedTabs[index].tabClosed$.next(); const deleted = this.openedTabs.splice(index, 1); deleted[0].destroy(); if (index < this.selectedIndex.value) { this.selectedIndex.setValue(this.selectedIndex.value - 1); } } /** * Initializes the tab if it wasn't initialized yet. * Creates a new {@link ComponentPortal} for the tab and provides the data for the tab under the `NAE_TAB_DATA` injection token. * @param index - index of the tab that should be initialized */ initializeTab(index) { this.checkIndexRange(index); const tab = this.openedTabs[index]; if (!tab.isTabInitialized) { Object.assign(tab.injectedObject, { tabUniqueId: tab.uniqueId, tabViewRef: Object.assign({ setIcon: t => tab.setIcon(t), setText: t => tab.setText(t), getIcon$: () => tab.getIcon$(), getText$: () => tab.getText$(), }, this.tabViewInterface), tabSelected$: tab.tabSelected$.asObservable(), tabClosed$: tab.tabClosed$.asObservable(), }); const providers = [ { provide: NAE_TAB_DATA, useValue: tab.injectedObject } ]; providers.push({ provide: NAE_VIEW_ID_SEGMENT, useValue: tab.initial ? tab.uniqueId : (tab.injectedObject?.loadFilter?.id ?? TabView.DYNAMIC_TAB_VIEW_ID_SEGMENT) }); const injector = Injector.create({ providers, parent: this._parentInjector }); tab.portal = new ComponentPortal(tab.tabContentComponent, null, injector); tab.isTabInitialized = true; } } tabChange(event) { const pendingTabUniqueId = this.openedTabs[event.index]?.uniqueId; if (pendingTabUniqueId === undefined) { return; } this._pendingTabUniqueId = pendingTabUniqueId; if (this._switching) { return; // an update is already being processed; the pending value will be picked up after } this._processSwitch(); } _processSwitch() { this._switching = true; const uniqueId = this._pendingTabUniqueId; const index = this.openedTabs.findIndex(tab => tab.uniqueId === uniqueId); if (index !== -1 && index !== this.selectedIndex.value) { let tab = this.openedTabs[this.selectedIndex.value]; if (tab) { tab.tabSelected$.next(false); } tab = this.openedTabs[index]; if (tab) { tab.tabSelected$.next(true); } this.selectedIndex.setValue(index); } setTimeout(() => { this._switching = false; if (this._pendingTabUniqueId !== uniqueId) { this._processSwitch(); } }, 150); } /** * Transforms a tab `uniqueId` into it's index. * * Throws an error if no tab with the given `uniqueId` exists. * @param uniqueId - id of the tab that we want to find index for * @returns index of the tab with the given id */ getTabIndex(uniqueId) { const index = this.openedTabs.findIndex(tab => tab.uniqueId === uniqueId); if (index === -1) { throw new Error(`No tab with ID ${uniqueId} exists`); } return index; } checkIndexRange(index) { if (index < 0 || index >= this.openedTabs.length) { throw new Error(`No tab with index ${index} exists`); } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFiLXZpZXcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZXRncmlmLWNvbXBvbmVudHMtY29yZS9zcmMvbGliL3RhYnMvY2xhc3Nlcy90YWItdmlldy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUMsU0FBUyxFQUFDLE1BQU0sY0FBYyxDQUFDO0FBQ3ZDLE9BQU8sRUFBQyxRQUFRLEVBQWlCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZELE9BQU8sRUFBQyxlQUFlLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQztBQUNwRCxPQUFPLEVBQUMsT0FBTyxFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFDeEMsT0FBTyxFQUFDLFlBQVksRUFBQyxNQUFNLHNEQUFzRCxDQUFDO0FBTWxGLE9BQU8sRUFBQyxtQkFBbUIsRUFBQyxNQUFNLG9DQUFvQyxDQUFDO0FBQ3ZFLE9BQU8sRUFBQyxtQkFBbUIsRUFBQyxNQUFNLDRDQUE0QyxDQUFDO0FBQy9FLE9BQU8sRUFBQyxXQUFXLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUUzQzs7O0dBR0c7QUFDSCxNQUFNLE9BQU8sT0FBTztJQXlDSTtJQUNBO0lBQ0E7SUFDQTtJQTFDYixNQUFNLENBQVUsMkJBQTJCLEdBQUcsU0FBUyxDQUFDO0lBRS9EOztPQUVHO0lBQ0ksVUFBVSxDQUFtQjtJQUNwQzs7OztPQUlHO0lBQ0ksYUFBYSxDQUFzQjtJQUVsQyxlQUFlLEdBQUcsSUFBSSxtQkFBbUIsRUFBRSxDQUFDO0lBRTVDLFVBQVUsR0FBRyxLQUFLLENBQUM7SUFFbkIsbUJBQW1CLENBQXFCO0lBRWhEOzs7T0FHRztJQUNLLGdCQUFnQixHQUFxQjtRQUN6QyxvQkFBb0IsRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsb0JBQW9CLEVBQUU7UUFDdkQsT0FBTyxFQUFFLENBQUMsVUFBc0IsRUFBRSxVQUFVLEdBQUcsS0FBSyxFQUFFLEVBQUUsQ0FBQyxJQUFJ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YlZpZXdJbnRlcmZhY2V9IGZyb20gJy4uL2ludGVyZmFjZXMnO1xuaW1wb3J0IHtPcGVuZWRUYWJ9IGZyb20gJy4vb3BlbmVkLXRhYic7XG5pbXBvcnQge0luamVjdG9yLCBTdGF0aWNQcm92aWRlcn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge0NvbXBvbmVudFBvcnRhbH0gZnJvbSAnQGFuZ3VsYXIvY2RrL3BvcnRhbCc7XG5pbXBvcnQge29yZGVyQnl9IGZyb20gJ25hdHVyYWwtb3JkZXJieSc7XG5pbXBvcnQge05BRV9UQUJfREFUQX0gZnJvbSAnLi4vdGFiLWRhdGEtaW5qZWN0aW9uLXRva2VuL3RhYi1kYXRhLWluamVjdGlvbi10b2tlbic7XG5pbXBvcnQge1ZpZXdTZXJ2aWNlfSBmcm9tICcuLi8uLi9yb3V0aW5nL3ZpZXctc2VydmljZS92aWV3LnNlcnZpY2UnO1xuaW1wb3J0IHtMb2dnZXJTZXJ2aWNlfSBmcm9tICcuLi8uLi9sb2dnZXIvc2VydmljZXMvbG9nZ2VyLnNlcnZpY2UnO1xuaW1wb3J0IHtJbmplY3RlZFRhYmJlZFRhc2tWaWV3RGF0YX0gZnJvbSAnLi4vLi4vdmlldy90YXNrLXZpZXcvbW9kZWxzL2luamVjdGVkLXRhYmJlZC10YXNrLXZpZXctZGF0YSc7XG5pbXBvcnQge1Rhc2tTZWFyY2hDYXNlUXVlcnksIFRhc2tTZWFyY2hSZXF1ZXN0Qm9keX0gZnJvbSAnLi4vLi4vZmlsdGVyL21vZGVscy90YXNrLXNlYXJjaC1yZXF1ZXN0LWJvZHknO1xuaW1wb3J0IHtNYXRUYWJDaGFuZ2VFdmVudH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvdGFicyc7XG5pbXBvcnQge0luY3JlbWVudGluZ0NvdW50ZXJ9IGZyb20gJy4uLy4uL3V0aWxpdHkvaW5jcmVtZW50aW5nLWNvdW50ZXInO1xuaW1wb3J0IHtOQUVfVklFV19JRF9TRUdNRU5UfSBmcm9tICcuLi8uLi91c2VyL21vZGVscy92aWV3LWlkLWluamVjdGlvbi10b2tlbnMnO1xuaW1wb3J0IHtGb3JtQ29udHJvbH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuXG4vKipcbiAqIEhvbGRzIHRoZSBsb2dpYyBmb3IgdGFiIG1hbmFnZW1lbnQgaW4ge0BsaW5rIEFic3RyYWN0VGFiVmlld0NvbXBvbmVudH0uXG4gKiBJZiB5b3Ugd2FudCB0byBpbXBsZW1lbnQgeW91ciBvd24gVGFiVmlld0NvbXBvbmVudCwgeW91IG1pZ2h0IHdhbnQgdG8gZXh0ZW5kIHRoaXMgY2xhc3MgdG8gaG9sZCB5b3VyIGxvZ2ljLlxuICovXG5leHBvcnQgY2xhc3MgVGFiVmlldyBpbXBsZW1lbnRzIFRhYlZpZXdJbnRlcmZhY2Uge1xuXG4gICAgcHVibGljIHN0YXRpYyByZWFkb25seSBEWU5BTUlDX1RBQl9WSUVXX0lEX1NFR01FTlQgPSAnZHluYW1pYyc7XG5cbiAgICAvKipcbiAgICAgKiBIb2xkcyB0aGUgdGFicyB0aGF0IGFyZSBvcGVuZWQgaW4gdGhlIHRhYiB2aWV3LCBhbmQgYWxsb3dzIHRoZW0gdG8gYmUgYm91bmQgdG8gSFRNTC5cbiAgICAgKi9cbiAgICBwdWJsaWMgb3BlbmVkVGFiczogQXJyYXk8T3BlbmVkVGFiPjtcbiAgICAvKipcbiAgICAgKiBIb2xkcyB0aGUgaW5kZXggb2YgdGhlIGN1cnJlbnRseSBzZWxlY3RlZCB0YWIuXG4gICAgICpcbiAgICAgKiBTZWxlY3RlZCBpbmRleCBpbml0aWFsaXplcyB0byBgMGAuXG4gICAgICovXG4gICAgcHVibGljIHNlbGVjdGVkSW5kZXg6IEZvcm1Db250cm9sPG51bWJlcj47XG5cbiAgICBwcml2YXRlIHVuaXF1ZUlkQ291bnRlciA9IG5ldyBJbmNyZW1lbnRpbmdDb3VudGVyKCk7XG5cbiAgICBwcml2YXRlIF9zd2l0Y2hpbmcgPSBmYWxzZTtcblxuICAgIHByaXZhdGUgX3BlbmRpbmdUYWJVbmlxdWVJZDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4gICAgLyoqXG4gICAgICogQGlnbm9yZVxuICAgICAqIEhvbGRzIGEgcmVmZXJlbmNlIHRvIGFuIG9iamVjdCB0aGF0IGhpZGVzIHNvbWUgcHVibGljIGF0dHJpYnV0ZXMgYW5kIG1ldGhvZHMgZnJvbSB0YWJzLlxuICAgICAqL1xuICAgIHByaXZhdGUgdGFiVmlld0ludGVyZmFjZTogVGFiVmlld0ludGVyZmFjZSA9IHtcbiAgICAgICAgY3VycmVudGx5U2VsZWN0ZWRUYWI6ICgpID0+IHRoaXMuY3VycmVudGx5U2VsZWN0ZWRUYWIoKSxcbiAgICAgICAgb3BlblRhYjogKHRhYkNvbnRlbnQ6IFRhYkNvbnRlbnQsIGF1dG9zd2l0Y2ggPSBmYWxzZSkgPT4gdGhpcy5vcGVuVGFiKHRhYkNvbnRlbnQsIGF1dG9zd2l0Y2gpLFxuICAgICAgICBzd2l0Y2hUb1RhYkluZGV4OiAoaW5kZXg6IG51bWJlcikgPT4gdGhpcy5zd2l0Y2hUb1RhYkluZGV4KGluZGV4KSxcbiAgICAgICAgc3dpdGNoVG9UYWJVbmlxdWVJZDogKHVuaXF1ZUlkOiBzdHJpbmcpID0+IHRoaXMuc3dpdGNoVG9UYWJVbmlxdWVJZCh1bmlxdWVJZCksXG4gICAgICAgIGNsb3NlVGFiSW5kZXg6IChpbmRleDogbnVtYmVyLCBmb3JjZSA9IGZhbHNlKSA9PiB0aGlzLmNsb3NlVGFiSW5kZXgoaW5kZXgsIGZvcmNlKSxcbiAgICAgICAgY2xvc2VUYWJVbmlxdWVJZDogKHVuaXF1ZUlkOiBzdHJpbmcsIGZvcmNlID0gZmFsc2UpID0+IHRoaXMuY2xvc2VUYWJVbmlxdWVJZCh1bmlxdWVJZCwgZm9yY2UpXG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSBfdmlld1NlcnZpY2UgW1ZpZXdTZXJ2aWNlXXtAbGluayBWaWV3U2VydmljZX0gcmVmZXJlbmNlXG4gICAgICogQHBhcmFtIF9sb2dnZXIgW0xvZ2dlcl17QGxpbmsgTG9nZ2VyU2VydmljZX0gcmVmZXJlbmNlXG4gICAgICogQHBhcmFtIF9pbml0aWFsVGFicyBUYWJzIHRoYXQgc2hvdWxkIGJlIGluaXRpYWxseSBvcGVuZWQgaW4gdGhlIHRhYiB2aWV3XG4gICAgICogQHBhcmFtIF9wYXJlbnRJbmplY3RvciBgSW5qZWN0b3JgIGluc3RhbmNlIG9mIHRoZSBbVGFiVmlld0NvbXBvbmVudF17QGxpbmsgQWJzdHJhY3RUYWJWaWV3Q29tcG9uZW50fSxcbiAgICAgKiB0byBiZSBwYXNzZWQgb250byBlYWNoIHRhYiwgc28gdGhhdCB0aGUgZGVwZW5kZW5jeSBpbmplY3Rpb24gdHJlZSBpcyBub3QgYnJva2VuXG4gICAgICovXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBfdmlld1NlcnZpY2U6IFZpZXdTZXJ2aWNlLFxuICAgICAgICAgICAgICAgIHByaXZhdGUgX2xvZ2dlcjogTG9nZ2VyU2VydmljZSxcbiAgICAgICAgICAgICAgICBwcml2YXRlIF9pbml0aWFsVGFiczogQXJyYXk8VGFiQ29udGVudD4sXG4gICAgICAgICAgICAgICAgcHJpdmF0ZSBfcGFyZW50SW5qZWN0b3I6IEluamVjdG9yKSB7XG4gICAgICAgIHRoaXMuX2luaXRpYWxUYWJzLmZvckVhY2godGFiID0+IHtcbiAgICAgICAgICAgIGlmICh0YWIub3JkZXIgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHRhYi5vcmRlciA9IDA7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0YWIuaW5pdGlhbCA9IHRydWU7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNlbGVjdGVkSW5kZXggPSBuZXcgRm9ybUNvbnRyb2woMCk7XG5cbiAgICAgICAgLy8gb3JkZXJCeSBpcyBhIHN0YWJsZSBzb3J0XG4gICAgICAgIC8vIE5hdGl2ZSBqYXZhc2NyaXB0IGltcGxlbWVudGF0aW9uIGhhcyB1bmRlZmluZWQgc3RhYmlsaXR5IGFuZCBpdCBkZXBlbmRzIG9uIGl0J3MgaW1wbGVtZW50YXRpb24gKGJyb3dzZXIpXG4gICAgICAgIHRoaXMub3BlbmVkVGFicyA9IG9yZGVyQnkodGhpcy5faW5pdGlhbFRhYnMsIHYgPT4gdi5vcmRlciwgJ2FzYycpLm1hcCh0YWJEYXRhID0+XG4gICAgICAgICAgICBuZXcgT3BlbmVkVGFiKHRhYkRhdGEsIGAke3RoaXMudW5pcXVlSWRDb3VudGVyLm5leHQoKX1gKSk7XG4gICAgICAgIGlmICh0aGlzLm9wZW5lZFRhYnMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgdGhpcy5vcGVuZWRUYWJzWzBdLnRhYlNlbGVjdGVkJC5uZXh0KHRydWUpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHJldHVybnMgdGhlIGluZGV4IG9mIHRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgdGFiXG4gICAgICovXG4gICAgcHVibGljIGN1cnJlbnRseVNlbGVjdGVkVGFiKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLnNlbGVjdGVkSW5kZXgudmFsdWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogT3BlbnMgYSBuZXcgdGFiIHdpdGggdGhlIHByb3ZpZGVkIGNvbnRlbnQuXG4gICAgICogQHBhcmFtIHRhYkNvbnRlbnQgLSBjb250ZW50IG9mIHRoZSBuZXcgdGFiXG4gICAgICogQHBhcmFtIGF1dG9zd2l0Y2ggLSB3aGV0aGVyIHRoZSBuZXdseSBvcGVuZWQgdGFiIHNob3VsZCBiZSBzd2l0Y2hlZCB0by4gRGVmYXVsdHMgdG8gYGZhbHNlYC5cbiAgICAgKiBAcGFyYW0gb3BlbkV4aXN0aW5nIC0gd2hldGhlciB0aGUgb3BlbmVkIHRhYiBhbHJlYWR5IGV4aXN0aW5nIHNob3VsZCBiZSBzd2l0Y2hlZCB0byBleGlzdGluZyBvbmUuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgKiBAcmV0dXJucyB0aGUgYHRhYlVuaXF1ZUlkYCBvZiB0aGUgbmV3bHkgb3BlbmVkIHRhYlxuICAgICAqL1xuICAgIHB1YmxpYyBvcGVuVGFiKHRhYkNvbnRlbnQ6IFRhYkNvbnRlbnQsIGF1dG9zd2l0Y2ggPSBmYWxzZSwgb3BlbkV4aXN0aW5nID0gdHJ1ZSk6IHN0cmluZyB7XG4gICAgICAgIGlmICh0YWJDb250ZW50LmluaXRpYWwpIHtcbiAgICAgICAgICAgIHRoaXMuX2xvZ2dlci53YXJuKGAnaW5pdGlhbCcgYXR0cmlidXRlIGlzIG5vdCBtZWFudCB0byBiZSB1c2VkIHdpdGggbmV3IHRhYnMgYW5kIHdpbGwgYmUgaWdub3JlZGApO1xuICAgICAgICAgICAgZGVsZXRlIHRhYkNvbnRlbnQuaW5pdGlhbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IG5ld1RhYiA9IG5ldyBPcGVuZWRUYWIodGFiQ29udGVudCwgYCR7dGhpcy51bmlxdWVJZENvdW50ZXIubmV4dCgpfWApO1xuICAgICAgICBjb25zdCBpbmRleEV4aXN0aW5nID0gdGhpcy5maW5kSW5kZXhFeGlzdGluZ1RhYihuZXdUYWIpO1xuICAgICAgICBpZiAoaW5kZXhFeGlzdGluZyA9PT0gLTEgfHwgIW9wZW5FeGlzdGluZykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMub3Blbk5ld1RhYihuZXdUYWIsIGF1dG9zd2l0Y2gpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5zZXRUYWJJbmRleFdpdGhOb3RpZmljYXRpb24oaW5kZXhFeGlzdGluZyk7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5vcGVuZWRUYWJzW2luZGV4RXhpc3RpbmddLnVuaXF1ZUlkO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGZpbmRJbmRleEV4aXN0aW5nVGFiKG5ld1RhYjogT3BlbmVkVGFiKSB7XG4gICAgICAgIGlmICghdGhpcy5zZWFyY2hlc0Zvck9uZUNhc2VJZChuZXdUYWIpKSB7XG4gICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMub3BlbmVkVGFicy5maW5kSW5kZXgoZXhpc3RpbmdUYWIgPT5cbiAgICAgICAgICAgIHRoaXMuc2VhcmNoZXNGb3JPbmVDYXNlSWQoZXhpc3RpbmdUYWIpICYmIHRoaXMuZ2V0U2VhcmNoZWRDYXNlSWQoZXhpc3RpbmdUYWIpID09PSB0aGlzLmdldFNlYXJjaGVkQ2FzZUlkKG5ld1RhYikpO1xuICAgIH1cblxuICAgIHByaXZhdGUgc2VhcmNoZXNGb3JPbmVDYXNlSWQodGFiOiBPcGVuZWRUYWIpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaGFzQ2FzZUZpbHRlclBhcmFtU2V0KHRhYilcbiAgICAgICAgICAgICYmICFBcnJheS5pc0FycmF5KHRoaXMuZ2V0U2VhcmNoZWRDYXNlKHRhYikpXG4gICAgICAgICAgICAmJiAhIXRoaXMuZ2V0U2VhcmNoZWRDYXNlSWQodGFiKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldFNlYXJjaGVkQ2FzZUlkKHRhYjogT3BlbmVkVGFiKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuICh0aGlzLmdldFNlYXJjaGVkQ2FzZSh0YWIpIGFzIFRhc2tTZWFyY2hDYXNlUXVlcnkpLmlkO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0U2VhcmNoZWRDYXNlKHRhYjogT3BlbmVkVGFiKTogVGFza1NlYXJjaENhc2VRdWVyeSB8IEFycmF5PFRhc2tTZWFyY2hDYXNlUXVlcnk+IHtcbiAgICAgICAgcmV0dXJuICgodGFiLmluamVjdGVkT2JqZWN0IGFzIEluamVjdGVkVGFiYmVkVGFza1ZpZXdEYXRhKS5iYXNlRmlsdGVyLmdldFJlcXVlc3RCb2R5KCkgYXMgVGFza1NlYXJjaFJlcXVlc3RCb2R5KS5jYXNlO1xuICAgIH1cblxuICAgIHByaXZhdGUgaGFzQ2FzZUZpbHRlclBhcmFtU2V0KHRhYjogT3BlbmVkVGFiKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLmhhc0Jhc2VGaWx0ZXIodGFiKVxuICAgICAgICAgICAgJiYgISEoKCh0YWIuaW5qZWN0ZWRPYmplY3QgYXMgSW5qZWN0ZWRUYWJiZWRUYXNrVmlld0RhdGEpLmJhc2VGaWx0ZXIuZ2V0UmVxdWVzdEJvZHkoKSBhcyBUYXNrU2VhcmNoUmVxdWVzdEJvZHkpLmNhc2UpO1xuICAgIH1cblxuICAgIHByaXZhdGUgaGFzQmFzZUZpbHRlcih0YWI6IE9wZW5lZFRhYik6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5oYXNJbmplY3RlZE9iamVjdCh0YWIpICYmICEhKCh0YWIuaW5qZWN0ZWRPYmplY3QgYXMgSW5qZWN0ZWRUYWJiZWRUYXNrVmlld0RhdGEpLmJhc2VGaWx0ZXIpO1xuICAgIH1cblxuICAgIHByaXZhdGUgaGFzSW5qZWN0ZWRPYmplY3QodGFiOiBPcGVuZWRUYWIpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuICEhdGFiLmluamVjdGVkT2JqZWN0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFkZHMgYSBuZXcgdGFiIGludG8gdGhlIGNvcnJlY3QgcG9zaXRpb24gYmFzZWQgb24gaXRzIGBvcmRlcmAgcHJvcGVydHkuXG4gICAgICogQHBhcmFtIG5ld1RhYiB0aGUgdGFiIHRoYXQgc2hvdWxkIGJlIG9wZW5lZFxuICAgICAqIEBwYXJhbSBhdXRvc3dpdGNoIHdoZXRoZXIgdGhlIG5ldyB0YWIgc2hvdWxkIGJlIHN3aXRjaGVkIHRvIGFmdGVyIGl0IGlzIGNyZWF0ZWRcbiAgICAgKiBAcmV0dXJucyB0aGUgYHVuaXF1ZUlkYCBvZiB0aGUgb3BlbmVkIHRhYlxuICAgICAqL1xuICAgIHByb3RlY3RlZCBvcGVuTmV3VGFiKG5ld1RhYjogT3BlbmVkVGFiLCBhdXRvc3dpdGNoOiBib29sZWFuKTogc3RyaW5nIHtcbiAgICAgICAgbGV0IGluZGV4ID0gdGhpcy5vcGVuZWRUYWJzLmZpbmRJbmRleChleGlzdGluZ1RhYiA9PiBleGlzdGluZ1RhYi5vcmRlciA+IG5ld1RhYi5vcmRlcik7XG4gICAgICAgIGlmIChpbmRleCA9PT0gLTEpIHtcbiAgICAgICAgICAgIGluZGV4ID0gdGhpcy5vcGVuZWRUYWJzLmxlbmd0aDtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLm9wZW5lZFRhYnMuc3BsaWNlKGluZGV4LCAwLCBuZXdUYWIpO1xuXG4gICAgICAgIGlmIChhdXRvc3dpdGNoIHx8IHRoaXMub3BlbmVkVGFicy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0VGFiSW5kZXhXaXRoTm90aWZpY2F0aW9uKGluZGV4KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbmV3VGFiLnVuaXF1ZUlkO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFN3aXRjaGVzIHRvIGEgdGFiIHdpdGggdGhlIGdpdmVuIGBpbmRleGAuXG4gICAgICpcbiAgICAgKiBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIGBpbmRleGAgaXMgaW52YWxpZC5cbiAgICAgKiBAcGFyYW0gaW5kZXggLSBpbmRleCBvZiB0aGUgdGFiIHRoYXQgc2hvdWxkIGJlIHN3aXRjaGVkIHRvXG4gICAgICovXG4gICAgcHVibGljIHN3aXRjaFRvVGFiSW5kZXgoaW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgICAgICB0aGlzLmNoZWNrSW5kZXhSYW5nZShpbmRleCk7XG4gICAgICAgIHRoaXMuc2V0VGFiSW5kZXhXaXRoTm90aWZpY2F0aW9uKGluZGV4KVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFN3aXRjaGVzIHRvIGEgdGFiIHdpdGggdGhlIGdpdmVuIGB1bmlxdWVJZGAuXG4gICAgICpcbiAgICAgKiBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIGB1bmlxdWVJZGAgaXMgaW52YWxpZC5cbiAgICAgKiBAcGFyYW0gdW5pcXVlSWQgLSBpZCBvZiB0aGUgdGFiIHRoYXQgc2hvdWxkIGJlIHN3aXRjaGVkIHRvXG4gICAgICovXG4gICAgcHVibGljIHN3aXRjaFRvVGFiVW5pcXVlSWQodW5pcXVlSWQ6IHN0cmluZyk6IHZvaWQge1xuICAgICAgICB0aGlzLnNldFRhYkluZGV4V2l0aE5vdGlmaWNhdGlvbih0aGlzLmdldFRhYkluZGV4KHVuaXF1ZUlkKSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzZXRUYWJJbmRleFdpdGhOb3RpZmljYXRpb24oaW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgICAgICB0aGlzLm9wZW5lZFRhYnNbdGhpcy5zZWxlY3RlZEluZGV4LnZhbHVlXS50YWJTZWxlY3RlZCQubmV4dChmYWxzZSk7XG4gICAgICAgIHRoaXMuc2VsZWN0ZWRJbmRleC5zZXRWYWx1ZShpbmRleCk7XG4gICAgICAgIHRoaXMub3BlbmVkVGFic1t0aGlzLnNlbGVjdGVkSW5kZXgudmFsdWVdLnRhYlNlbGVjdGVkJC5uZXh0KHRydWUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENsb3NlcyB0aGUgdGFiIHdpdGggdGhlIGdpdmVuIGBpbmRleGAuXG4gICAgICpcbiAgICAgKiBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIGBpbmRleGAgaXMgaW52YWxpZC5cbiAgICAgKlxuICAgICAqIFRocm93cyBhbiBlcnJvciBpZiB0aGUgdGFiIGhhcyBpdCdzIGBjYW5CZUNsb3NlZGAgcHJvcGVydHkgc2V0IHRvIGBmYWxzZWAuXG4gICAgICogQHBhcmFtIGluZGV4IGluZGV4IG9mIHRoZSB0YWIgdGhhdCBzaG91bGQgYmUgY2xvc2VkXG4gICAgICogQHBhcmFtIGZvcmNlIHdoZW4gYHRydWVgIGNsb3NlcyBhIHRhYiBldmVuIGlmIGl0J3MgYGNhbnRCZUNsb3NlZGAgYXR0cmlidXRlIGlzIHNldCB0byBgdHJ1ZWBcbiAgICAgKi9cbiAgICBwdWJsaWMgY2xvc2VUYWJJbmRleChpbmRleDogbnVtYmVyLCBmb3JjZSA9IGZhbHNlKTogdm9pZCB7XG4gICAgICAgIHRoaXMuY2xvc2VUYWIoaW5kZXgsIGZvcmNlLCBgVGFiIGF0IGluZGV4ICR7aW5kZXh9IGNhbid0IGJlIGNsb3NlZGApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENsb3NlcyB0aGUgdGFiIHdpdGggdGhlIGdpdmVuIGB1bmlxdWVJZGAuIFRocm93cyBhbiBlcnJvciBpZiB0aGUgYHVuaXF1ZUlkYCBpcyBpbnZhbGlkLlxuICAgICAqIFRocm93cyBhbiBlcnJvciBpZiB0aGUgdGFiIGhhcyBpdCdzIGBjYW5CZUNsb3NlZGAgcHJvcGVydHkgc2V0IHRvIGBmYWxzZWAuXG4gICAgICogQHBhcmFtIHVuaXF1ZUlkIC0gaWQgb2YgdGhlIHRhYiB0aGF0IHNob3VsZCBiZSBjbG9zZWRcbiAgICAgKiBAcGFyYW0gZm9yY2Ugd2hlbiBgdHJ1ZWAgY2xvc2VzIGEgdGFiIGV2ZW4gaWYgaXQncyBgY2FudEJlQ2xvc2VkYCBhdHRyaWJ1dGUgaXMgc2V0IHRvIGB0cnVlYFxuICAgICAqL1xuICAgIHB1YmxpYyBjbG9zZVRhYlVuaXF1ZUlkKHVuaXF1ZUlkOiBzdHJpbmcsIGZvcmNlID0gZmFsc2UpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgaW5kZXggPSB0aGlzLmdldFRhYkluZGV4KHVuaXF1ZUlkKTtcbiAgICAgICAgdGhpcy5jbG9zZVRhYihpbmRleCwgZm9yY2UsIGBUYWIgd2l0aCBJRCAke3VuaXF1ZUlkfSBjYW4ndCBiZSBjbG9zZWRgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDbG9zZXMgdGhlIHRhYiBhdCB0aGUgZ2l2ZW4gaW5kZXguXG4gICAgICpcbiAgICAgKiBJZiB0aGUgY29uZGl0aW9ucyBmb3IgY2xvc2luZyBhIHRhYiBhcmUgbm90IG1ldCB0aHJvd3MgYW4gYEVycm9yYCB3aXRoIHRoZSBnaXZlbiBtZXNzYWdlLlxuICAgICAqIEBwYXJhbSBpbmRleCBpbmRleCBvZiB0aGUgdGFiIHRoYXQgc2hvdWxkIGJlIGNsb3NlZFxuICAgICAqIEBwYXJhbSBmb3JjZSB3aGVuIGB0cnVlYCBjbG9zZXMgYSB0YWIgZXZlbiBpZiBpdCdzIGBjYW50QmVDbG9zZWRgIGF0dHJpYnV0ZSBpcyBzZXQgdG8gYHRydWVgXG4gICAgICogQHBhcmFtIGVycm9yIHRoZSBtZXNzYWdlIHRoYXQgc2hvdWxkIGJlIGRpc3BsYXllZCBpZiB0aGUgY29uZGl0aW9ucyBmb3IgY2xvc2luZyBhIHRhYiBhcmUgbm90IG1ldFxuICAgICAqL1xuICAgIHByb3RlY3RlZCBjbG9zZVRhYihpbmRleDogbnVtYmVyLCBmb3JjZTogYm9vbGVhbiwgZXJyb3I6IHN0cmluZyk6IHZvaWQge1xuICAgICAgICB0aGlzLmNoZWNrSW5kZXhSYW5nZShpbmRleCk7XG4gICAgICAgIGlmICghZm9yY2UgJiYgIXRoaXMub3BlbmVkVGFic1tpbmRleF0uY2FuQmVDbG9zZWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihlcnJvcik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGluZGV4ID09PSB0aGlzLnNlbGVjdGVkSW5kZXgudmFsdWUgJiYgdGhpcy5vcGVuZWRUYWJzW2luZGV4XS5wYXJlbnRVbmlxdWVJZCAmJlxuICAgICAgICAgICAgdGhpcy5vcGVuZWRUYWJzLmZpbmRJbmRleCh0YWIgPT4gdGFiLnVuaXF1ZUlkID09PSB0aGlzLm9wZW5lZFRhYnNbaW5kZXhdLnBhcmVudFVuaXF1ZUlkKSAhPT0gLTEpIHtcbiAgICAgICAgICAgIHRoaXMuc3dpdGNoVG9UYWJVbmlxdWVJZCh0aGlzLm9wZW5lZFRhYnNbaW5kZXhdLnBhcmVudFVuaXF1ZUlkKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaW5kZXggPT09IHRoaXMuc2VsZWN0ZWRJbmRleC52YWx1ZSAmJiB0aGlzLnNlbGVjdGVkSW5kZXgudmFsdWUgKyAxIDwgdGhpcy5vcGVuZWRUYWJzLmxlbmd0aCkge1xuICAgICAgICAgICAgdGhpcy5vcGVuZWRUYWJzW2luZGV4ICsgMV0udGFiU2VsZWN0ZWQkLm5leHQodHJ1ZSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5vcGVuZWRUYWJzW2luZGV4XS50YWJDbG9zZWQkLm5leHQoKTtcbiAgICAgICAgY29uc3QgZGVsZXRlZCA9IHRoaXMub3BlbmVkVGFicy5zcGxpY2UoaW5kZXgsIDEpO1xuICAgICAgICBkZWxldGVkWzBdLmRlc3Ryb3koKTtcbiAgICAgICAgaWYgKGluZGV4IDwgdGhpcy5zZWxlY3RlZEluZGV4LnZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnNlbGVjdGVkSW5kZXguc2V0VmFsdWUodGhpcy5zZWxlY3RlZEluZGV4LnZhbHVlIC0gMSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplcyB0aGUgdGFiIGlmIGl0IHdhc24ndCBpbml0aWFsaXplZCB5ZXQuXG4gICAgICogQ3JlYXRlcyBhIG5ldyB7QGxpbmsgQ29tcG9uZW50UG9ydGFsfSBmb3IgdGhlIHRhYiBhbmQgcHJvdmlkZXMgdGhlIGRhdGEgZm9yIHRoZSB0YWIgdW5kZXIgdGhlIGBOQUVfVEFCX0RBVEFgIGluamVjdGlvbiB0b2tlbi5cbiAgICAgKiBAcGFyYW0gaW5kZXggLSBpbmRleCBvZiB0aGUgdGFiIHRoYXQgc2hvdWxkIGJlIGluaXRpYWxpemVkXG4gICAgICovXG4gICAgcHVibGljIGluaXRpYWxpemVUYWIoaW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgICAgICB0aGlzLmNoZWNrSW5kZXhSYW5nZShpbmRleCk7XG4gICAgICAgIGNvbnN0IHRhYiA9IHRoaXMub3BlbmVkVGFic1tpbmRleF07XG4gICAgICAgIGlmICghdGFiLmlzVGFiSW5pdGlhbGl6ZWQpIHtcbiAgICAgICAgICAgIE9iamVjdC5hc3NpZ24odGFiLmluamVjdGVkT2JqZWN0LCB7XG4gICAgICAgICAgICAgICAgdGFiVW5pcXVlSWQ6IHRhYi51bmlxdWVJZCxcbiAgICAgICAgICAgICAgICB0YWJWaWV3UmVmOiBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgICAgICAgICAgICAgc2V0SWNvbjogdCA9PiB0YWIuc2V0SWNvbih0KSxcbiAgICAgICAgICAgICAgICAgICAgc2V0VGV4dDogdCA9PiB0YWIuc2V0VGV4dCh0KSxcbiAgICAgICAgICAgICAgICAgICAgZ2V0SWNvbiQ6ICgpID0+IHRhYi5nZXRJY29uJCgpLFxuICAgICAgICAgICAgICAgICAgICBnZXRUZXh0JDogKCkgPT4gdGFiLmdldFRleHQkKCksXG4gICAgICAgICAgICAgICAgfSwgdGhpcy50YWJWaWV3SW50ZXJmYWNlKSxcbiAgICAgICAgICAgICAgICB0YWJTZWxlY3RlZCQ6IHRhYi50YWJTZWxlY3RlZCQuYXNPYnNlcnZhYmxlKCksXG4gICAgICAgICAgICAgICAgdGFiQ2xvc2VkJDogdGFiLnRhYkNsb3NlZCQuYXNPYnNlcnZhYmxlKCksXG4gICAgICAgICAgICB9IGFzIEluamVjdGVkVGFiRGF0YSk7XG5cbiAgICAgICAgICAgIGNvbnN0IHByb3ZpZGVyczogQXJyYXk8U3RhdGljUHJvdmlkZXI+ID0gW1xuICAgICAgICAgICAgICAgIHtwcm92aWRlOiBOQUVfVEFCX0RBVEEsIHVzZVZhbHVlOiB0YWIuaW5qZWN0ZWRPYmplY3R9XG4gICAgICAgICAgICBdO1xuICAgICAgICAgICAgcHJvdmlkZXJzLnB1c2goe1xuICAgICAgICAgICAgICAgIHByb3ZpZGU6IE5BRV9WSUVXX0lEX1NFR01FTlQsXG4gICAgICAgICAgICAgICAgdXNlVmFsdWU6IHRhYi5pbml0aWFsID8gdGFiLnVuaXF1ZUlkIDogKCh0YWIuaW5qZWN0ZWRPYmplY3QgYXMgSW5qZWN0ZWRUYWJEYXRhKT8ubG9hZEZpbHRlcj8uaWQgPz8gVGFiVmlldy5EWU5BTUlDX1RBQl9WSUVXX0lEX1NFR01FTlQpXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgY29uc3QgaW5qZWN0b3IgPSBJbmplY3Rvci5jcmVhdGUoe3Byb3ZpZGVycywgcGFyZW50OiB0aGlzLl9wYXJlbnRJbmplY3Rvcn0pO1xuXG4gICAgICAgICAgICB0YWIucG9ydGFsID0gbmV3IENvbXBvbmVudFBvcnRhbCh0YWIudGFiQ29udGVudENvbXBvbmVudCwgbnVsbCwgaW5qZWN0b3IpO1xuICAgICAgICAgICAgdGFiLmlzVGFiSW5pdGlhbGl6ZWQgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIHRhYkNoYW5nZShldmVudDogTWF0VGFiQ2hhbmdlRXZlbnQpIHtcbiAgICAgICAgY29uc3QgcGVuZGluZ1RhYlVuaXF1ZUlkID0gdGhpcy5vcGVuZWRUYWJzW2V2ZW50LmluZGV4XT8udW5pcXVlSWQ7XG4gICAgICAgIGlmIChwZW5kaW5nVGFiVW5pcXVlSWQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX3BlbmRpbmdUYWJVbmlxdWVJZCA9IHBlbmRpbmdUYWJVbmlxdWVJZDtcbiAgICAgICAgaWYgKHRoaXMuX3N3aXRjaGluZykge1xuICAgICAgICAgICAgcmV0dXJuOyAvLyBhbiB1cGRhdGUgaXMgYWxyZWFkeSBiZWluZyBwcm9jZXNzZWQ7IHRoZSBwZW5kaW5nIHZhbHVlIHdpbGwgYmUgcGlja2VkIHVwIGFmdGVyXG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fcHJvY2Vzc1N3aXRjaCgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgX3Byb2Nlc3NTd2l0Y2goKSB7XG4gICAgICAgIHRoaXMuX3N3aXRjaGluZyA9IHRydWU7XG4gICAgICAgIGNvbnN0IHVuaXF1ZUlkID0gdGhpcy5fcGVuZGluZ1RhYlVuaXF1ZUlkO1xuICAgICAgICBjb25zdCBpbmRleCA9IHRoaXMub3BlbmVkVGFicy5maW5kSW5kZXgodGFiID0+IHRhYi51bmlxdWVJZCA9PT0gdW5pcXVlSWQpO1xuXG4gICAgICAgIGlmIChpbmRleCAhPT0gLTEgJiYgaW5kZXggIT09IHRoaXMuc2VsZWN0ZWRJbmRleC52YWx1ZSkge1xuICAgICAgICAgICAgbGV0IHRhYiA9IHRoaXMub3BlbmVkVGFic1t0aGlzLnNlbGVjdGVkSW5kZXgudmFsdWVdO1xuICAgICAgICAgICAgaWYgKHRhYikge1xuICAgICAgICAgICAgICAgIHRhYi50YWJTZWxlY3RlZCQubmV4dChmYWxzZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0YWIgPSB0aGlzLm9wZW5lZFRhYnNbaW5kZXhdO1xuICAgICAgICAgICAgaWYgKHRhYikge1xuICAgICAgICAgICAgICAgIHRhYi50YWJTZWxlY3RlZCQubmV4dCh0cnVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuc2VsZWN0ZWRJbmRleC5zZXRWYWx1ZShpbmRleCk7XG4gICAgICAgIH1cblxuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuX3N3aXRjaGluZyA9IGZhbHNlO1xuICAgICAgICAgICAgaWYgKHRoaXMuX3BlbmRpbmdUYWJVbmlxdWVJZCAhPT0gdW5pcXVlSWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9wcm9jZXNzU3dpdGNoKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sIDE1MCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVHJhbnNmb3JtcyBhIHRhYiBgdW5pcXVlSWRgIGludG8gaXQncyBpbmRleC5cbiAgICAgKlxuICAgICAqIFRocm93cyBhbiBlcnJvciBpZiBubyB0YWIgd2l0aCB0aGUgZ2l2ZW4gYHVuaXF1ZUlkYCBleGlzdHMuXG4gICAgICogQHBhcmFtIHVuaXF1ZUlkIC0gaWQgb2YgdGhlIHRhYiB0aGF0IHdlIHdhbnQgdG8gZmluZCBpbmRleCBmb3JcbiAgICAgKiBAcmV0dXJucyBpbmRleCBvZiB0aGUgdGFiIHdpdGggdGhlIGdpdmVuIGlkXG4gICAgICovXG4gICAgcHJpdmF0ZSBnZXRUYWJJbmRleCh1bmlxdWVJZDogc3RyaW5nKTogbnVtYmVyIHtcbiAgICAgICAgY29uc3QgaW5kZXggPSB0aGlzLm9wZW5lZFRhYnMuZmluZEluZGV4KHRhYiA9PiB0YWIudW5pcXVlSWQgPT09IHVuaXF1ZUlkKTtcbiAgICAgICAgaWYgKGluZGV4ID09PSAtMSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBObyB0YWIgd2l0aCBJRCAke3VuaXF1ZUlkfSBleGlzdHNgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gaW5kZXg7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjaGVja0luZGV4UmFuZ2UoaW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgICAgICBpZiAoaW5kZXggPCAwIHx8IGluZGV4ID49IHRoaXMub3BlbmVkVGFicy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgTm8gdGFiIHdpdGggaW5kZXggJHtpbmRleH0gZXhpc3RzYCk7XG4gICAgICAgIH1cbiAgICB9XG59XG4iXX0=