@netgrif/components-core
Version:
Netgrif Application engine frontend core Angular library
300 lines • 43.9 kB
JavaScript
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=