@netgrif/components-core
Version:
Netgrif Application engine frontend core Angular library
431 lines • 61.2 kB
JavaScript
import { BehaviorSubject, ReplaySubject, Subject } from 'rxjs';
import { HeaderState } from './header-state';
import { Injectable, Optional } from '@angular/core';
import { HeaderMode } from './models/header-mode';
import { HeaderColumn, HeaderColumnType } from './models/header-column';
import { LoadingEmitter } from '../utility/loading-emitter';
import { HeaderChangeType } from './models/user-changes/header-change-type';
import * as i0 from "@angular/core";
import * as i1 from "./models/header-type";
import * as i2 from "../user/services/user-preference.service";
import * as i3 from "../logger/services/logger.service";
import * as i4 from "../user/services/view-id.service";
import * as i5 from "./services/overflow.service";
export class AbstractHeaderService {
_headerType;
_preferences;
_logger;
_viewIdService;
_overflowService;
static DEFAULT_HEADER_COUNT = 5;
static DEFAULT_HEADER_RESPONSIVITY = true;
_headerColumnCount$;
_preferenceColumnCount$;
_responsiveHeaders$;
_headerState;
_headerChange$;
_clearHeaderSearch$;
_initDefaultHeaders;
_initializedCount;
loading;
fieldsGroup;
constructor(_headerType, _preferences, _logger, _viewIdService, _overflowService) {
this._headerType = _headerType;
this._preferences = _preferences;
this._logger = _logger;
this._viewIdService = _viewIdService;
this._overflowService = _overflowService;
this.loading = new LoadingEmitter(true);
this._headerChange$ = new Subject();
this.fieldsGroup = [{ groupTitle: 'Meta data', fields: this.createMetaHeaders() }];
this._headerColumnCount$ = new BehaviorSubject(AbstractHeaderService.DEFAULT_HEADER_COUNT);
this._responsiveHeaders$ = new BehaviorSubject(AbstractHeaderService.DEFAULT_HEADER_RESPONSIVITY);
this._preferenceColumnCount$ = new ReplaySubject();
this._clearHeaderSearch$ = new Subject();
this._initializedCount = false;
if (this._viewIdService === null) {
this._logger.warn('Header service could not inject ViewIdService! User preferences won\'t be loaded or saved!');
}
this._preferences.preferencesChanged$.subscribe(() => {
this.loadHeadersFromPreferences();
});
this.initializeHeaderState();
}
/**
* Provides Observable for all changes in header
*/
get headerChange$() {
return this._headerChange$.asObservable();
}
get selectedHeaders$() {
return this._headerState.selectedHeaders$;
}
get headerState() {
return this._headerState.asInterface();
}
get headerType() {
return this._headerType;
}
get overflowMode() {
if (!!this._overflowService) {
return this._overflowService.overflowMode;
}
else {
return false;
}
}
get headerColumnCount() {
return this._headerColumnCount$.getValue();
}
set headerColumnCount(maxColumns) {
if (maxColumns !== this.headerColumnCount) {
this._headerColumnCount$.next(maxColumns);
this.updateHeaderColumnCount();
if (!this._initializedCount) {
this.initializeDefaultHeaderState();
this._initializedCount = true;
}
}
}
get headerColumnCount$() {
return this._headerColumnCount$.asObservable();
}
get responsiveHeaders() {
return this._responsiveHeaders$.getValue();
}
set responsiveHeaders(responsiveHeaders) {
this._responsiveHeaders$.next(responsiveHeaders);
}
get responsiveHeaders$() {
return this._responsiveHeaders$.asObservable();
}
get clearHeaderSearch$() {
return this._clearHeaderSearch$.asObservable();
}
set initDefaultHeaders(defaultHeaders) {
this._initDefaultHeaders = defaultHeaders;
}
get initDefaultHeaders() {
return this._initDefaultHeaders;
}
get preferenceColumnCount$() {
return this._preferenceColumnCount$.asObservable();
}
initializeHeaderState() {
const defaultHeaders = [];
for (let i = 0; i < this.fieldsGroup[0].fields.length && defaultHeaders.length < this.headerColumnCount; i++) {
if (this.fieldsGroup[0].fields[i].initial) {
defaultHeaders.push(this.fieldsGroup[0].fields[i]);
}
}
while (defaultHeaders.length < this.headerColumnCount) {
defaultHeaders.push(null);
}
this._headerState = new HeaderState(defaultHeaders);
}
initializeDefaultHeaderState() {
if (this.initDefaultHeaders && Array.isArray(this.initDefaultHeaders)) {
const defaultHeaders = [];
for (let i = 0; i < this.headerColumnCount; i++) {
defaultHeaders.push(null);
}
for (let i = 0; i < this.initDefaultHeaders.length; i++) {
if (i >= this.headerColumnCount) {
this._logger.warn('there are more NAE_DEFAULT_HEADERS than header columns. Skipping the rest...');
break;
}
for (const h of this.fieldsGroup) {
const head = h.fields.find(header => header.uniqueId === this.initDefaultHeaders[i]);
if (head) {
defaultHeaders[i] = head;
break;
}
}
}
this._headerState.updateSelectedHeaders(defaultHeaders);
}
this.loadHeadersFromPreferences();
}
/**
* Adds `null` headers if the new count is greater than the current count.
*
* Removes extra headers if the new count is smaller than the current count.
*/
updateHeaderColumnCount() {
let headers = this._headerState.selectedHeaders;
if (headers.length < this.headerColumnCount) {
const lastSelectedHeaders = this._headerState.lastSelectedHeaders;
if (headers.length < this.headerColumnCount && !!lastSelectedHeaders && headers.length < lastSelectedHeaders.length) {
headers.push(...lastSelectedHeaders.slice(headers.length, this.headerColumnCount));
}
while (headers.length <= this.headerColumnCount) {
headers.push(null);
}
}
else if (headers.length > this.headerColumnCount) {
headers = headers.slice(0, this.headerColumnCount);
}
this._headerState.updateSelectedHeaders(headers);
}
setAllowedNets(allowedNets) {
/* TODO by simply replacing the select options with new object, we don't loose the old references.
Columns with headers from nets that are no longer allowed should have their value cleared.
Columns with valid values that are not metadata should have their selection remapped to the new objects.
*/
const fieldsGroups = [];
allowedNets.forEach(allowedNet => {
const fieldsGroup = {
groupTitle: allowedNet.title,
fields: []
};
allowedNet.immediateData.forEach(immediate => {
fieldsGroup.fields.push(new HeaderColumn(HeaderColumnType.IMMEDIATE, immediate.stringId, immediate.title, immediate.type, false, allowedNet.identifier));
});
fieldsGroups.push(fieldsGroup);
});
this.fieldsGroup.splice(1, this.fieldsGroup.length - 1);
this.fieldsGroup.push(...fieldsGroups);
}
setTaskAllowedNets(allowedNets) {
/* TODO by simply replacing the select options with new object, we don't loose the old references.
Columns with headers from nets that are no longer allowed should have their value cleared.
Columns with valid values that are not metadata should have their selection remapped to the new objects.
*/
const fieldsGroups = [];
allowedNets.forEach(allowedNet => {
const fieldsGroup = {
groupTitle: allowedNet.title,
fields: []
};
const existing = new Set();
allowedNet.transitions.forEach(trans => {
trans.immediateData.forEach(data => {
if (!existing.has(data.stringId)) {
existing.add(data.stringId);
fieldsGroup.fields.push(new HeaderColumn(HeaderColumnType.IMMEDIATE, data.stringId, data.title, data.type, false, allowedNet.identifier));
}
});
});
fieldsGroups.push(fieldsGroup);
});
this.fieldsGroup.splice(1, this.fieldsGroup.length - 1);
this.fieldsGroup.push(...fieldsGroups);
}
/**
* If this view has som headers stored in it's preferences attempts to load them.
* If the preferences contain nonexistent headers they will be skipped.
*
* This function is NOT called by the abstract class' constructor.
* It is the responsibility of the child class to call it at an appropriate moment.
*/
loadHeadersFromPreferences() {
const viewId = this.getViewId();
if (!viewId) {
return;
}
const preferredHeaderKeys = this._preferences.getHeaders(viewId);
if (!preferredHeaderKeys) {
return;
}
const newHeaders = [];
preferredHeaderKeys.forEach(headerKey => {
for (const fieldGroup of this.fieldsGroup) {
for (const header of fieldGroup.fields) {
if (header.uniqueId === headerKey) {
newHeaders.push(header);
return; // continue the outermost loop
}
}
}
// no match found
newHeaders.push(null);
this._logger.warn(`Could not restore header with ID '${headerKey}' from preferences. It is not one of the available headers for this view.`);
});
this._preferenceColumnCount$.next(newHeaders.length);
this._headerState.updateSelectedHeaders(newHeaders);
}
/**
* Change sort mode for selected column all other column are set to default sort mode
* Emit request for sorted panels
* @param columnIndex index of the column that caused the sort change
* @param active Represents column identifier
* @param direction Represent one of sort modes: asd, desc and ''
*/
sortHeaderChanged(columnIndex, active, direction) {
let sortChangeDescription;
let foundFirstMatch = false; // column can feature in the header in multiple positions => we don't want to send multiple events
this.headerState.selectedHeaders.filter(header => !!header).forEach(header => {
if (header.uniqueId === active && !foundFirstMatch) {
sortChangeDescription = {
sortDirection: direction,
columnType: header.type,
fieldIdentifier: header.fieldIdentifier,
petriNetIdentifier: header.petriNetIdentifier,
columnIdentifier: columnIndex,
fieldType: header.fieldType
};
header.sortDirection = direction;
foundFirstMatch = true;
}
else {
header.sortDirection = '';
}
});
this._headerChange$.next({
headerType: this.headerType,
changeType: HeaderChangeType.SORT,
description: sortChangeDescription
});
}
/**
* Saves the search value in the appropriate column in the header
* Emit request for searched panels by user input query
*/
headerSearchInputChanged(columnIndex, searchInput) {
const affectedHeader = this.headerState.selectedHeaders[columnIndex];
affectedHeader.searchInput = searchInput;
const searchChangeDescription = {
fieldIdentifier: affectedHeader.fieldIdentifier,
fieldType: affectedHeader.fieldType,
fieldTitle: affectedHeader.title,
searchInput,
type: affectedHeader.type,
petriNetIdentifier: affectedHeader.petriNetIdentifier,
columnIdentifier: columnIndex
};
this._headerChange$.next({
headerType: this.headerType,
changeType: HeaderChangeType.SEARCH,
description: searchChangeDescription
});
}
/**
* Change active header and titles of panels
*/
headerColumnSelected(columnIndex, newHeaderColumn) {
const newHeaders = [];
newHeaders.push(...this._headerState.selectedHeaders);
if (!!newHeaders[columnIndex]) {
newHeaders[columnIndex].sortDirection = '';
newHeaders[columnIndex].searchInput = undefined;
}
newHeaders[columnIndex] = newHeaderColumn;
this._headerState.updateSelectedHeaders(newHeaders);
this._headerChange$.next({
headerType: this.headerType,
changeType: HeaderChangeType.EDIT,
description: { preferredHeaders: this._headerState.selectedHeaders }
});
}
/**
* Change selected header mode there are three possible modes: SORT, SEARCH and EDIT
* @param newMode the mode that the header should change to
* @param saveLastMode whether the last state should be remembered.
* It can be restored with the [HeaderState.restoreLastMode()]{@link HeaderState#restoreLastMode} method.
*/
changeMode(newMode, saveLastMode = true) {
if (newMode === this._headerState.mode) {
return;
}
if (saveLastMode) {
this._headerState.saveState();
this.saveState();
}
const change = this.modeChangeFromCurrent(newMode);
this._headerState.mode = newMode;
this._headerChange$.next(change);
}
confirmEditMode() {
this._headerState.restoreLastMode();
this.saveNewState();
const change = this.modeChangeAfterEdit();
const viewId = this.getViewId();
if (!!viewId) {
const headers = this.headerState.selectedHeaders;
this._preferences.setHeaders(viewId, headers.map(header => !!header ? header.uniqueId : ''));
}
this._headerChange$.next(change);
}
/**
* When user cancels the edit mode, the last saved headers state is loaded and emitted
* Last mode in header is reloaded as well. Possible reloaded modes: sort or search
*/
revertEditMode() {
this._headerState.restoreLastState();
this.restoreLastState();
const change = this.modeChangeAfterEdit();
this._headerChange$.next({
headerType: this.headerType,
changeType: HeaderChangeType.EDIT,
description: { preferredHeaders: this._headerState.selectedHeaders }
});
this._headerChange$.next(change);
}
ngOnDestroy() {
this._headerChange$.complete();
this._clearHeaderSearch$.complete();
this._headerColumnCount$.complete();
this._responsiveHeaders$.complete();
this.loading.complete();
this._preferenceColumnCount$.complete();
}
/**
* @param newMode the {@link HeaderMode} that is being selected as the next mode
* @returnsa {@link HeaderChange} object with {@link ModeChangeDescription} object as it's `description`,
* where the `previousMode` is set to the currently selected mode and the `currentMode` is set to the provided argument
*/
modeChangeFromCurrent(newMode) {
return this.createModeChange(this._headerState.mode, newMode);
}
/**
* @returns a {@link HeaderChange} object with {@link ModeChangeDescription} object as it's `description`,
* where the `previousMode` is set to [EDIT]{@link HeaderMode#EDIT} and the `currentMode` to the mode
* that is currently selected
*/
modeChangeAfterEdit() {
return this.createModeChange(HeaderMode.EDIT, this._headerState.mode);
}
/**
* @param oldMode the {@link HeaderMode} that was previously selected
* @param newMode the {@link HeaderMode} that is selected now
* @returns a {@link HeaderChange} object with {@link ModeChangeDescription} object as it's `description`
* containing information about a change to the header mode
*/
createModeChange(oldMode, newMode) {
return {
changeType: HeaderChangeType.MODE_CHANGED,
description: {
currentMode: newMode,
previousMode: oldMode
},
headerType: this.headerType
};
}
/**
* Emits a new value into the [clearHeaderSearch$]{@link AbstractHeaderService#clearHeaderSearch$} stream, that notifies
* the header search component, that it should clear the input for the specified column.
* @param columnIndex the index of the column that should be cleared
*/
clearHeaderSearch(columnIndex) {
this._clearHeaderSearch$.next(columnIndex);
}
/**
* @returns the Id of the view, if the ViewIdService was injected. Returns `undefined` if the service was not injected.
*/
getViewId() {
if (this._viewIdService) {
return this._viewIdService.viewId;
}
return undefined;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AbstractHeaderService, deps: [{ token: i1.HeaderType }, { token: i2.UserPreferenceService }, { token: i3.LoggerService }, { token: i4.ViewIdService, optional: true }, { token: i5.OverflowService, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AbstractHeaderService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AbstractHeaderService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: i1.HeaderType }, { type: i2.UserPreferenceService }, { type: i3.LoggerService }, { type: i4.ViewIdService, decorators: [{
type: Optional
}] }, { type: i5.OverflowService, decorators: [{
type: Optional
}] }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWJzdHJhY3QtaGVhZGVyLXNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZXRncmlmLWNvbXBvbmVudHMtY29yZS9zcmMvbGliL2hlYWRlci9hYnN0cmFjdC1oZWFkZXItc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUMsZUFBZSxFQUFjLGFBQWEsRUFBRSxPQUFPLEVBQUMsTUFBTSxNQUFNLENBQUM7QUFFekUsT0FBTyxFQUFDLFdBQVcsRUFBdUIsTUFBTSxnQkFBZ0IsQ0FBQztBQUNqRSxPQUFPLEVBQUMsVUFBVSxFQUFhLFFBQVEsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQU05RCxPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sc0JBQXNCLENBQUM7QUFDaEQsT0FBTyxFQUFDLFlBQVksRUFBRSxnQkFBZ0IsRUFBQyxNQUFNLHdCQUF3QixDQUFDO0FBR3RFLE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSw0QkFBNEIsQ0FBQztBQUUxRCxPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSwwQ0FBMEMsQ0FBQzs7Ozs7OztBQU0xRSxNQUFNLE9BQWdCLHFCQUFxQjtJQWlCUDtJQUNBO0lBQ0E7SUFDVTtJQUNFO0lBbkJyQyxNQUFNLENBQVUsb0JBQW9CLEdBQUcsQ0FBQyxDQUFDO0lBQ3pDLE1BQU0sQ0FBVSwyQkFBMkIsR0FBRyxJQUFJLENBQUM7SUFFaEQsbUJBQW1CLENBQTBCO0lBQzdDLHVCQUF1QixDQUF3QjtJQUMvQyxtQkFBbUIsQ0FBMkI7SUFDOUMsWUFBWSxDQUFjO0lBQzFCLGNBQWMsQ0FBd0I7SUFDdEMsbUJBQW1CLENBQWtCO0lBQ3ZDLG1CQUFtQixDQUFnQjtJQUNuQyxpQkFBaUIsQ0FBVTtJQUU1QixPQUFPLENBQWlCO0lBQ3hCLFdBQVcsQ0FBcUI7SUFFdkMsWUFBZ0MsV0FBdUIsRUFDdkIsWUFBbUMsRUFDbkMsT0FBc0IsRUFDWixjQUE2QixFQUMzQixnQkFBaUM7UUFKN0MsZ0JBQVcsR0FBWCxXQUFXLENBQVk7UUFDdkIsaUJBQVksR0FBWixZQUFZLENBQXVCO1FBQ25DLFlBQU8sR0FBUCxPQUFPLENBQWU7UUFDWixtQkFBYyxHQUFkLGNBQWMsQ0FBZTtRQUMzQixxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQWlCO1FBQ3pFLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDeEMsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLE9BQU8sRUFBZ0IsQ0FBQztRQUNsRCxJQUFJLENBQUMsV0FBVyxHQUFHLENBQUMsRUFBQyxVQUFVLEVBQUUsV0FBVyxFQUFFLE1BQU0sRUFBRSxJQUFJLENBQUMsaUJBQWlCLEVBQUUsRUFBQyxDQUFDLENBQUM7UUFDakYsSUFBSSxDQUFDLG1CQUFtQixHQUFHLElBQUksZUFBZSxDQUFTLHFCQUFxQixDQUFDLG9CQUFvQixDQUFDLENBQUM7UUFDbkcsSUFBSSxDQUFDLG1CQUFtQixHQUFHLElBQUksZUFBZSxDQUFVLHFCQUFxQixDQUFDLDJCQUEyQixDQUFDLENBQUM7UUFDM0csSUFBSSxDQUFDLHVCQUF1QixHQUFHLElBQUksYUFBYSxFQUFVLENBQUM7UUFDM0QsSUFBSSxDQUFDLG1CQUFtQixHQUFHLElBQUksT0FBTyxFQUFVLENBQUM7UUFDakQsSUFBSSxDQUFDLGlCQUFpQixHQUFHLEtBQUssQ0FBQztRQUUvQixJQUFJLElBQUksQ0FBQyxjQUFjLEtBQUssSUFBSSxFQUFFO1lBQzlCLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLDRGQUE0RixDQUFDLENBQUM7U0FDbkg7UUFFRCxJQUFJLENBQUMsWUFBWSxDQUFDLG1CQUFtQixDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUU7WUFDakQsSUFBSSxDQUFDLDBCQUEwQixFQUFFLENBQUM7UUFDdEMsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQztJQUNqQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxJQUFJLGFBQWE7UUFDYixPQUFPLElBQUksQ0FBQyxjQUFjLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDOUMsQ0FBQztJQUVELElBQUksZ0JBQWdCO1FBQ2hCLE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQyxnQkFBZ0IsQ0FBQztJQUM5QyxDQUFDO0lBRUQsSUFBSSxXQUFXO1FBQ1gsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQzNDLENBQUM7SUFFRCxJQUFJLFVBQVU7UUFDVixPQUFPLElBQUksQ0FBQyxXQUFXLENBQUM7SUFDNUIsQ0FBQztJQUVELElBQUksWUFBWTtRQUNaLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRTtZQUN6QixPQUFPLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxZQUFZLENBQUM7U0FDN0M7YUFBTTtZQUNILE9BQU8sS0FBSyxDQUFDO1NBQ2hCO0lBQ0wsQ0FBQztJQUVELElBQUksaUJBQWlCO1FBQ2pCLE9BQU8sSUFBSSxDQUFDLG1CQUFtQixDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQy9DLENBQUM7SUFFRCxJQUFJLGlCQUFpQixDQUFDLFVBQWtCO1FBQ3BDLElBQUksVUFBVSxLQUFLLElBQUksQ0FBQyxpQkFBaUIsRUFBRTtZQUN2QyxJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQzFDLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1lBQy9CLElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUU7Z0JBQ3pCLElBQUksQ0FBQyw0QkFBNEIsRUFBRSxDQUFDO2dCQUNwQyxJQUFJLENBQUMsaUJBQWlCLEdBQUcsSUFBSSxDQUFDO2FBQ2pDO1NBQ0o7SUFDTCxDQUFDO0lBRUQsSUFBSSxrQkFBa0I7UUFDbEIsT0FBTyxJQUFJLENBQUMsbUJBQW1CLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDbkQsQ0FBQztJQUVELElBQUksaUJBQWlCO1FBQ2pCLE9BQU8sSUFBSSxDQUFDLG1CQUFtQixDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQy9DLENBQUM7SUFFRCxJQUFJLGlCQUFpQixDQUFDLGlCQUEwQjtRQUM1QyxJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUM7SUFDckQsQ0FBQztJQUVELElBQUksa0JBQWtCO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLG1CQUFtQixDQUFDLFlBQVksRUFBRSxDQUFDO0lBQ25ELENBQUM7SUFFRCxJQUFJLGtCQUFrQjtRQUNsQixPQUFPLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUNuRCxDQUFDO0lBRUQsSUFBSSxrQkFBa0IsQ0FBQyxjQUE2QjtRQUNoRCxJQUFJLENBQUMsbUJBQW1CLEdBQUcsY0FBYyxDQUFDO0lBQzlDLENBQUM7SUFFRCxJQUFJLGtCQUFrQjtRQUNsQixPQUFPLElBQUksQ0FBQyxtQkFBbUIsQ0FBQztJQUNwQyxDQUFDO0lBRUQsSUFBSSxzQkFBc0I7UUFDdEIsT0FBTyxJQUFJLENBQUMsdUJBQXVCLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDdkQsQ0FBQztJQUVPLHFCQUFxQjtRQUN6QixNQUFNLGNBQWMsR0FBRyxFQUFFLENBQUM7UUFDMUIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sSUFBSSxjQUFjLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUMxRyxJQUFJLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBRTtnQkFDdkMsY0FBYyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2FBQ3REO1NBQ0o7UUFDRCxPQUFPLGNBQWMsQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixFQUFFO1lBQ25ELGNBQWMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDN0I7UUFDRCxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksV0FBVyxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBQ3hELENBQUM7SUFFUyw0QkFBNEI7UUFDbEMsSUFBSSxJQUFJLENBQUMsa0JBQWtCLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsRUFBRTtZQUNuRSxNQUFNLGNBQWMsR0FBRyxFQUFFLENBQUM7WUFDMUIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLEVBQUUsRUFBRTtnQkFDN0MsY0FBYyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQzthQUM3QjtZQUNELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO2dCQUNyRCxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsaUJBQWlCLEVBQUU7b0JBQzdCLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLDhFQUE4RSxDQUFDLENBQUM7b0JBQ2xHLE1BQU07aUJBQ1Q7Z0JBQ0QsS0FBSyxNQUFNLENBQUMsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFO29CQUM5QixNQUFNLElBQUksR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEtBQUssSUFBSSxDQUFDLGtCQUFrQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7b0JBQ3JGLElBQUksSUFBSSxFQUFFO3dCQUNOLGNBQWMsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUM7d0JBQ3pCLE1BQU07cUJBQ1Q7aUJBQ0o7YUFDSjtZQUNELElBQUksQ0FBQyxZQUFZLENBQUMscUJBQXFCLENBQUMsY0FBYyxDQUFDLENBQUM7U0FDM0Q7UUFDRCxJQUFJLENBQUMsMEJBQTBCLEVBQUUsQ0FBQztJQUN0QyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNPLHVCQUF1QjtRQUM3QixJQUFJLE9BQU8sR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLGVBQWUsQ0FBQztRQUNoRCxJQUFJLE9BQU8sQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixFQUFFO1lBQ3pDLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxtQkFBbUIsQ0FBQztZQUNsRSxJQUFJLE9BQU8sQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixJQUFJLENBQUMsQ0FBQyxtQkFBbUIsSUFBSSxPQUFPLENBQUMsTUFBTSxHQUFHLG1CQUFtQixDQUFDLE1BQU0sRUFBRTtnQkFDakgsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLG1CQUFtQixDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUM7YUFDdEY7WUFDRCxPQUFPLE9BQU8sQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLGlCQUFpQixFQUFFO2dCQUM3QyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO2FBQ3RCO1NBQ0o7YUFBTSxJQUFJLE9BQU8sQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixFQUFFO1lBQ2hELE9BQU8sR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FBQztTQUN0RDtRQUNELElBQUksQ0FBQyxZQUFZLENBQUMscUJBQXFCLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDckQsQ0FBQztJQUVNLGNBQWMsQ0FBQyxXQUFxQztRQUN2RDs7O1dBR0c7UUFFSCxNQUFNLFlBQVksR0FBdUIsRUFBRSxDQUFDO1FBQzVDLFdBQVcsQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLEVBQUU7WUFDN0IsTUFBTSxXQUFXLEdBQWdCO2dCQUM3QixVQUFVLEVBQUUsVUFBVSxDQUFDLEtBQUs7Z0JBQzVCLE1BQU0sRUFBRSxFQUFFO2FBQ2IsQ0FBQztZQUNGLFVBQVUsQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFO2dCQUN6QyxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FDbkIsSUFBSSxZQUFZLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLFNBQVMsQ0FBQyxRQUFRLEVBQUUsU0FBUyxDQUFDLEtBQUssRUFDNUUsU0FBUyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsVUFBVSxDQUFDLFVBQVUsQ0FBQyxDQUNwRCxDQUFDO1lBQ04sQ0FBQyxDQUFDLENBQUM7WUFDSCxZQUFZLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ25DLENBQUMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ3hELElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEdBQUcsWUFBWSxDQUFDLENBQUM7SUFDM0MsQ0FBQztJQUVNLGtCQUFrQixDQUFDLFdBQXVCO1FBQzdDOzs7V0FHRztRQUVILE1BQU0sWUFBWSxHQUF1QixFQUFFLENBQUM7UUFDNUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsRUFBRTtZQUM3QixNQUFNLFdBQVcsR0FBZ0I7Z0JBQzdCLFVBQVUsRUFBRSxVQUFVLENBQUMsS0FBSztnQkFDNUIsTUFBTSxFQUFFLEVBQUU7YUFDYixDQUFDO1lBQ0YsTUFBTSxRQUFRLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQztZQUMzQixVQUFVLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRTtnQkFDbkMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUU7b0JBQy9CLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRTt3QkFDOUIsUUFBUSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7d0JBQzVCLFdBQVcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUNuQixJQUFJLFlBQVksQ0FBQyxnQkFBZ0IsQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLFFBQVEsRUFDdEQsSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxVQUFVLENBQUMsVUFBVSxDQUFDLENBQzNELENBQUM7cUJBQ0w7Z0JBQ0wsQ0FBQyxDQUFDLENBQUM7WUFDUCxDQUFDLENBQUMsQ0FBQztZQUNILFlBQVksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDbkMsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDeEQsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsR0FBRyxZQUFZLENBQUMsQ0FBQztJQUMzQyxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ08sMEJBQTBCO1FBQ2hDLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNoQyxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQ1QsT0FBTztTQUNWO1FBQ0QsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNqRSxJQUFJLENBQUMsbUJBQW1CLEVBQUU7WUFDdEIsT0FBTztTQUNWO1FBQ0QsTUFBTSxVQUFVLEdBQUcsRUFBRSxDQUFDO1FBQ3RCLG1CQUFtQixDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRTtZQUNwQyxLQUFLLE1BQU0sVUFBVSxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUU7Z0JBQ3ZDLEtBQUssTUFBTSxNQUFNLElBQUksVUFBVSxDQUFDLE1BQU0sRUFBRTtvQkFDcEMsSUFBSSxNQUFNLENBQUMsUUFBUSxLQUFLLFNBQVMsRUFBRTt3QkFDL0IsVUFBVSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQzt3QkFDeEIsT0FBTyxDQUFDLDhCQUE4QjtxQkFDekM7aUJBQ0o7YUFDSjtZQUNELGlCQUFpQjtZQUNqQixVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3RCLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUNiLHFDQUFxQyxTQUFTLDJFQUEyRSxDQUFDLENBQUM7UUFDbkksQ0FBQyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsdUJBQXVCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNyRCxJQUFJLENBQUMsWUFBWSxDQUFDLHFCQUFxQixDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3hELENBQUM7SUFJRDs7Ozs7O09BTUc7SUFDSSxpQkFBaUIsQ0FBQyxXQUFtQixFQUFFLE1BQWMsRUFBRSxTQUF3QjtRQUNsRixJQUFJLHFCQUE0QyxDQUFDO1FBQ2pELElBQUksZUFBZSxHQUFHLEtBQUssQ0FBQyxDQUFDLGtHQUFrRztRQUMvSCxJQUFJLENBQUMsV0FBVyxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFO1lBQ3pFLElBQUksTUFBTSxDQUFDLFFBQVEsS0FBSyxNQUFNLElBQUksQ0FBQyxlQUFlLEVBQUU7Z0JBQ2hELHFCQUFxQixHQUFHO29CQUNwQixhQUFhLEVBQUUsU0FBUztvQkFDeEIsVUFBVSxFQUFFLE1BQU0sQ0FBQyxJQUFJO29CQUN2QixlQUFlLEVBQUUsTUFBTSxDQUFDLGVBQWU7b0JBQ3ZDLGtCQUFrQixFQUFFLE1BQU0sQ0FBQyxrQkFBa0I7b0JBQzdDLGdCQUFnQixFQUFFLFdBQVc7b0JBQzdCLFNBQVMsRUFBRSxNQUFNLENBQUMsU0FBUztpQkFDOUIsQ0FBQztnQkFDRixNQUFNLENBQUMsYUFBYSxHQUFHLFNBQVMsQ0FBQztnQkFDakMsZUFBZSxHQUFHLElBQUksQ0FBQzthQUMxQjtpQkFBTTtnQkFDSCxNQUFNLENBQUMsYUFBYSxHQUFHLEVBQUUsQ0FBQzthQUM3QjtRQUNMLENBQUMsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUM7WUFDckIsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVO1lBQzNCLFVBQVUsRUFBRSxnQkFBZ0IsQ0FBQyxJQUFJO1lBQ2pDLFdBQVcsRUFBRSxxQkFBcUI7U0FDckMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVEOzs7T0FHRztJQUNJLHdCQUF3QixDQUFDLFdBQW1CLEVBQUUsV0FBZ0I7UUFDakUsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxlQUFlLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDckUsY0FBYyxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUM7UUFDekMsTUFBTSx1QkFBdUIsR0FBNEI7WUFDckQsZUFBZSxFQUFFLGNBQWMsQ0FBQyxlQUFlO1lBQy9DLFNBQVMsRUFBRSxjQUFjLENBQUMsU0FBUztZQUNuQyxVQUFVLEVBQUUsY0FBYyxDQUFDLEtBQUs7WUFDaEMsV0FBVztZQUNYLElBQUksRUFBRSxjQUFjLENBQUMsSUFBSTtZQUN6QixrQkFBa0IsRUFBRSxjQUFjLENBQUMsa0JBQWtCO1lBQ3JELGdCQUFnQixFQUFFLFdBQVc7U0FDaEMsQ0FBQztRQUNGLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDO1lBQ3JCLFVBQVUsRUFBRSxJQUFJLENBQUMsVUFBVTtZQUMzQixVQUFVLEVBQUUsZ0JBQWdCLENBQUMsTUFBTTtZQUNuQyxXQUFXLEVBQUUsdUJBQXVCO1NBQ3ZDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRDs7T0FFRztJQUNJLG9CQUFvQixDQUFDLFdBQW1CLEVBQUUsZUFBNkI7UUFDMUUsTUFBTSxVQUFVLEdBQXdCLEVBQUUsQ0FBQztRQUMzQyxVQUFVLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUN0RCxJQUFJLENBQUMsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLEVBQUU7WUFDM0IsVUFBVSxDQUFDLFdBQVcsQ0FBQyxDQUFDLGFBQWEsR0FBRyxFQUFFLENBQUM7WUFDM0MsVUFBVSxDQUFDLFdBQVcsQ0FBQyxDQUFDLFdBQVcsR0FBRyxTQUFTLENBQUM7U0FDbkQ7UUFDRCxVQUFVLENBQUMsV0FBVyxDQUFDLEdBQUcsZUFBZSxDQUFDO1FBQzFDLElBQUksQ0FBQyxZQUFZLENBQUMscUJBQXFCLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDcEQsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUM7WUFDckIsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVO1lBQzNCLFVBQVUsRUFBRSxnQkFBZ0IsQ0FBQyxJQUFJO1lBQ2pDLFdBQVcsRUFBRSxFQUFDLGdCQUFnQixFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsZUFBZSxFQUFDO1NBQ3JFLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNJLFVBQVUsQ0FBQyxPQUFtQixFQUFFLFlBQVksR0FBRyxJQUFJO1FBQ3RELElBQUksT0FBTyxLQUFLLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFO1lBQ3BDLE9BQU87U0FDVjtRQUVELElBQUksWUFBWSxFQUFFO1lBQ2QsSUFBSSxDQUFDLFlBQVksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUM5QixJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7U0FDcEI7UUFFRCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDbkQsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLEdBQUcsT0FBTyxDQUFDO1FBQ2pDLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3JDLENBQUM7SUFFTSxlQUFlO1FBQ2xCLElBQUksQ0FBQyxZQUFZLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDcEMsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ3BCLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBQzFDLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNoQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUU7WUFDVixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLGVBQWUsQ0FBQztZQUNqRCxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7U0FDaEc7UUFDRCxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNyQyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksY0FBYztRQUNqQixJQUFJLENBQUMsWUFBWSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFDckMsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFDeEIsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7UUFDMUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUM7WUFDckIsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVO1lBQzNCLFVBQVUsRUFBRSxnQkFBZ0IsQ0FBQyxJQUFJO1lBQ2pDLFdBQVcsRUFBRSxFQUFDLGdCQUFnQixFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsZUFBZSxFQUFDO1NBQ3JFLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3JDLENBQUM7SUFFRCxXQUFXO1FBQ1AsSUFBSSxDQUFDLGNBQWMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUMvQixJQUFJLENBQUMsbUJBQW1CLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDcEMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ3BDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNwQyxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ3hCLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUM1QyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNPLHFCQUFxQixDQUFDLE9BQW1CO1FBQy9DLE9BQU8sSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ2xFLENBQUM7SUFFRDs7OztPQUlHO0lBQ08sbUJBQW1CO1FBQ3pCLE9BQU8sSUFBSSxDQUFDLGdCQUFnQixDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMxRSxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDTyxnQkFBZ0IsQ0FBQyxPQUFtQixFQUFFLE9BQW1CO1FBQy9ELE9BQU87WUFDSCxVQUFVLEVBQUUsZ0JBQWdCLENBQUMsWUFBWTtZQUN6QyxXQUFXLEVBQUU7Z0JBQ1QsV0FBVyxFQUFFLE9BQU87Z0JBQ3BCLFlBQVksRUFBRSxPQUFPO2FBQ3hCO1lBQ0QsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVO1NBQzlCLENBQUM7SUFDTixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLGlCQUFpQixDQUFDLFdBQW1CO1FBQ3hDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVEOztPQUVHO0lBQ08sU0FBUztRQUNmLElBQUksSUFBSSxDQUFDLGNBQWMsRUFBRTtZQUNyQixPQUFPLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDO1NBQ3JDO1FBQ0QsT0FBTyxTQUFTLENBQUM7SUFDckIsQ0FBQzt3R0FwY2lCLHFCQUFxQjs0R0FBckIscUJBQXFCOzs0RkFBckIscUJBQXFCO2tCQUQxQyxVQUFVOzswQkFxQmdCLFFBQVE7OzBCQUNSLFFBQVEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0JlaGF2aW9yU3ViamVjdCwgT2JzZXJ2YWJsZSwgUmVwbGF5U3ViamVjdCwgU3ViamVjdH0gZnJvbSAncnhqcyc7XG5pbXBvcnQge0ZpZWxkc0dyb3VwfSBmcm9tICcuL21vZGVscy9maWVsZHMtZ3JvdXAnO1xuaW1wb3J0IHtIZWFkZXJTdGF0ZSwgSGVhZGVyU3RhdGVJbnRlcmZhY2V9IGZyb20gJy4vaGVhZGVyLXN0YXRlJztcbmltcG9ydCB7SW5qZWN0YWJsZSwgT25EZXN0cm95LCBPcHRpb25hbH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1NvcnRDaGFuZ2VEZXNjcmlwdGlvbn0gZnJvbSAnLi9tb2RlbHMvdXNlci1jaGFuZ2VzL3NvcnQtY2hhbmdlLWRlc2NyaXB0aW9uJztcbmltcG9ydCB7U2VhcmNoQ2hhbmdlRGVzY3JpcHRpb259IGZyb20gJy4vbW9kZWxzL3VzZXItY2hhbmdlcy9zZWFyY2gtY2hhbmdlLWRlc2NyaXB0aW9uJztcbmltcG9ydCB7SGVhZGVyQ2hhbmdlfSBmcm9tICcuL21vZGVscy91c2VyLWNoYW5nZXMvaGVhZGVyLWNoYW5nZSc7XG5pbXBvcnQge1BldHJpTmV0UmVmZXJlbmNlfSBmcm9tICcuLi9yZXNvdXJjZXMvaW50ZXJmYWNlL3BldHJpLW5ldC1yZWZlcmVuY2UnO1xuaW1wb3J0IHtIZWFkZXJUeXBlfSBmcm9tICcuL21vZGVscy9oZWFkZXItdHlwZSc7XG5pbXBvcnQge0hlYWRlck1vZGV9IGZyb20gJy4vbW9kZWxzL2hlYWRlci1tb2RlJztcbmltcG9ydCB7SGVhZGVyQ29sdW1uLCBIZWFkZXJDb2x1bW5UeXBlfSBmcm9tICcuL21vZGVscy9oZWFkZXItY29sdW1uJztcbmltcG9ydCB7VXNlclByZWZlcmVuY2VTZXJ2aWNlfSBmcm9tICcuLi91c2VyL3NlcnZpY2VzL3VzZXItcHJlZmVyZW5jZS5zZXJ2aWNlJztcbmltcG9ydCB7TG9nZ2VyU2VydmljZX0gZnJvbSAnLi4vbG9nZ2VyL3NlcnZpY2VzL2xvZ2dlci5zZXJ2aWNlJztcbmltcG9ydCB7TG9hZGluZ0VtaXR0ZXJ9IGZyb20gJy4uL3V0aWxpdHkvbG9hZGluZy1lbWl0dGVyJztcbmltcG9ydCB7U29ydERpcmVjdGlvbn0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvc29ydCc7XG5pbXBvcnQge0hlYWRlckNoYW5nZVR5cGV9IGZyb20gJy4vbW9kZWxzL3VzZXItY2hhbmdlcy9oZWFkZXItY2hhbmdlLXR5cGUnO1xuaW1wb3J0IHtWaWV3SWRTZXJ2aWNlfSBmcm9tICcuLi91c2VyL3NlcnZpY2VzL3ZpZXctaWQuc2VydmljZSc7XG5pbXBvcnQge05ldH0gZnJvbSAnLi4vcHJvY2Vzcy9uZXQnO1xuaW1wb3J0IHtPdmVyZmxvd1NlcnZpY2V9IGZyb20gJy4vc2VydmljZXMvb3ZlcmZsb3cuc2VydmljZSc7XG5cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBBYnN0cmFjdEhlYWRlclNlcnZpY2UgaW1wbGVtZW50cyBPbkRlc3Ryb3kge1xuXG4gICAgcHVibGljIHN0YXRpYyByZWFkb25seSBERUZBVUxUX0hFQURFUl9DT1VOVCA9IDU7XG4gICAgcHVibGljIHN0YXRpYyByZWFkb25seSBERUZBVUxUX0hFQURFUl9SRVNQT05TSVZJVFkgPSB0cnVlO1xuXG4gICAgcHJvdGVjdGVkIF9oZWFkZXJDb2x1bW5Db3VudCQ6IEJlaGF2aW9yU3ViamVjdDxudW1iZXI+O1xuICAgIHByb3RlY3RlZCBfcHJlZmVyZW5jZUNvbHVtbkNvdW50JDogUmVwbGF5U3ViamVjdDxudW1iZXI+O1xuICAgIHByb3RlY3RlZCBfcmVzcG9uc2l2ZUhlYWRlcnMkOiBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj47XG4gICAgcHJvdGVjdGVkIF9oZWFkZXJTdGF0ZTogSGVhZGVyU3RhdGU7XG4gICAgcHJvdGVjdGVkIF9oZWFkZXJDaGFuZ2UkOiBTdWJqZWN0PEhlYWRlckNoYW5nZT47XG4gICAgcHJvdGVjdGVkIF9jbGVhckhlYWRlclNlYXJjaCQ6IFN1YmplY3Q8bnVtYmVyPjtcbiAgICBwcml2YXRlIF9pbml0RGVmYXVsdEhlYWRlcnM6IEFycmF5PHN0cmluZz47XG4gICAgcHJpdmF0ZSBfaW5pdGlhbGl6ZWRDb3VudDogYm9vbGVhbjtcblxuICAgIHB1YmxpYyBsb2FkaW5nOiBMb2FkaW5nRW1pdHRlcjtcbiAgICBwdWJsaWMgZmllbGRzR3JvdXA6IEFycmF5PEZpZWxkc0dyb3VwPjtcblxuICAgIHByb3RlY3RlZCBjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgX2hlYWRlclR5cGU6IEhlYWRlclR5cGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHByb3RlY3RlZCBfcHJlZmVyZW5jZXM6IFVzZXJQcmVmZXJlbmNlU2VydmljZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvdGVjdGVkIF9sb2dnZXI6IExvZ2dlclNlcnZpY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIEBPcHRpb25hbCgpIHByaXZhdGUgX3ZpZXdJZFNlcnZpY2U6IFZpZXdJZFNlcnZpY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIEBPcHRpb25hbCgpIHByb3RlY3RlZCBfb3ZlcmZsb3dTZXJ2aWNlOiBPdmVyZmxvd1NlcnZpY2UpIHtcbiAgICAgICAgdGhpcy5sb2FkaW5nID0gbmV3IExvYWRpbmdFbWl0dGVyKHRydWUpO1xuICAgICAgICB0aGlzLl9oZWFkZXJDaGFuZ2UkID0gbmV3IFN1YmplY3Q8SGVhZGVyQ2hhbmdlPigpO1xuICAgICAgICB0aGlzLmZpZWxkc0dyb3VwID0gW3tncm91cFRpdGxlOiAnTWV0YSBkYXRhJywgZmllbGRzOiB0aGlzLmNyZWF0ZU1ldGFIZWFkZXJzKCl9XTtcbiAgICAgICAgdGhpcy5faGVhZGVyQ29sdW1uQ291bnQkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxudW1iZXI+KEFic3RyYWN0SGVhZGVyU2VydmljZS5ERUZBVUxUX0hFQURFUl9DT1VOVCk7XG4gICAgICAgIHRoaXMuX3Jlc3BvbnNpdmVIZWFkZXJzJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oQWJzdHJhY3RIZWFkZXJTZXJ2aWNlLkRFRkFVTFRfSEVBREVSX1JFU1BPTlNJVklUWSk7XG4gICAgICAgIHRoaXMuX3ByZWZlcmVuY2VDb2x1bW5Db3VudCQgPSBuZXcgUmVwbGF5U3ViamVjdDxudW1iZXI+KCk7XG4gICAgICAgIHRoaXMuX2NsZWFySGVhZGVyU2VhcmNoJCA9IG5ldyBTdWJqZWN0PG51bWJlcj4oKTtcbiAgICAgICAgdGhpcy5faW5pdGlhbGl6ZWRDb3VudCA9IGZhbHNlO1xuXG4gICAgICAgIGlmICh0aGlzLl92aWV3SWRTZXJ2aWNlID09PSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLl9sb2dnZXIud2FybignSGVhZGVyIHNlcnZpY2UgY291bGQgbm90IGluamVjdCBWaWV3SWRTZXJ2aWNlISBVc2VyIHByZWZlcmVuY2VzIHdvblxcJ3QgYmUgbG9hZGVkIG9yIHNhdmVkIScpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fcHJlZmVyZW5jZXMucHJlZmVyZW5jZXNDaGFuZ2VkJC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5sb2FkSGVhZGVyc0Zyb21QcmVmZXJlbmNlcygpO1xuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLmluaXRpYWxpemVIZWFkZXJTdGF0ZSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFByb3ZpZGVzIE9ic2VydmFibGUgZm9yIGFsbCBjaGFuZ2VzIGluIGhlYWRlclxuICAgICAqL1xuICAgIGdldCBoZWFkZXJDaGFuZ2UkKCk6IE9ic2VydmFibGU8SGVhZGVyQ2hhbmdlPiB7XG4gICAgICAgIHJldHVybiB0aGlzLl9oZWFkZXJDaGFuZ2UkLmFzT2JzZXJ2YWJsZSgpO1xuICAgIH1cblxuICAgIGdldCBzZWxlY3RlZEhlYWRlcnMkKCk6IE9ic2VydmFibGU8QXJyYXk8SGVhZGVyQ29sdW1uPj4ge1xuICAgICAgICByZXR1cm4gdGhpcy5faGVhZGVyU3RhdGUuc2VsZWN0ZWRIZWFkZXJzJDtcbiAgICB9XG5cbiAgICBnZXQgaGVhZGVyU3RhdGUoKTogSGVhZGVyU3RhdGVJbnRlcmZhY2Uge1xuICAgICAgICByZXR1cm4gdGhpcy5faGVhZGVyU3RhdGUuYXNJbnRlcmZhY2UoKTtcbiAgICB9XG5cbiAgICBnZXQgaGVhZGVyVHlwZSgpOiBIZWFkZXJUeXBlIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2hlYWRlclR5cGU7XG4gICAgfVxuXG4gICAgZ2V0IG92ZXJmbG93TW9kZSgpOiBib29sZWFuIHtcbiAgICAgICAgaWYgKCEhdGhpcy5fb3ZlcmZsb3dTZXJ2aWNlKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fb3ZlcmZsb3dTZXJ2aWNlLm92ZXJmbG93TW9kZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGdldCBoZWFkZXJDb2x1bW5Db3VudCgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5faGVhZGVyQ29sdW1uQ291bnQkLmdldFZhbHVlKCk7XG4gICAgfVxuXG4gICAgc2V0IGhlYWRlckNvbHVtbkNvdW50KG1heENvbHVtbnM6IG51bWJlcikge1xuICAgICAgICBpZiAobWF4Q29sdW1ucyAhPT0gdGhpcy5oZWFkZXJDb2x1bW5Db3VudCkge1xuICAgICAgICAgICAgdGhpcy5faGVhZGVyQ29sdW1uQ291bnQkLm5leHQobWF4Q29sdW1ucyk7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZUhlYWRlckNvbHVtbkNvdW50KCk7XG4gICAgICAgICAgICBpZiAoIXRoaXMuX2luaXRpYWxpemVkQ291bnQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmluaXRpYWxpemVEZWZhdWx0SGVhZGVyU3RhdGUoKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9pbml0aWFsaXplZENvdW50ID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIGdldCBoZWFkZXJDb2x1bW5Db3VudCQoKTogT2JzZXJ2YWJsZTxudW1iZXI+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2hlYWRlckNvbHVtbkNvdW50JC5hc09ic2VydmFibGUoKTtcbiAgICB9XG5cbiAgICBnZXQgcmVzcG9uc2l2ZUhlYWRlcnMoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLl9yZXNwb25zaXZlSGVhZGVycyQuZ2V0VmFsdWUoKTtcbiAgICB9XG5cbiAgICBzZXQgcmVzcG9uc2l2ZUhlYWRlcnMocmVzcG9uc2l2ZUhlYWRlcnM6IGJvb2xlYW4pIHtcbiAgICAgICAgdGhpcy5fcmVzcG9uc2l2ZUhlYWRlcnMkLm5leHQocmVzcG9uc2l2ZUhlYWRlcnMpO1xuICAgIH1cblxuICAgIGdldCByZXNwb25zaXZlSGVhZGVycyQoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG4gICAgICAgIHJldHVybiB0aGlzLl9yZXNwb25zaXZlSGVhZGVycyQuYXNPYnNlcnZhYmxlKCk7XG4gICAgfVxuXG4gICAgZ2V0IGNsZWFySGVhZGVyU2VhcmNoJCgpOiBPYnNlcnZhYmxlPG51bWJlcj4ge1xuICAgICAgICByZXR1cm4gdGhpcy5fY2xlYXJIZWFkZXJTZWFyY2gkLmFzT2JzZXJ2YWJsZSgpO1xuICAgIH1cblxuICAgIHNldCBpbml0RGVmYXVsdEhlYWRlcnMoZGVmYXVsdEhlYWRlcnM6IEFycmF5PHN0cmluZz4pIHtcbiAgICAgICAgdGhpcy5faW5pdERlZmF1bHRIZWFkZXJzID0gZGVmYXVsdEhlYWRlcnM7XG4gICAgfVxuXG4gICAgZ2V0IGluaXREZWZhdWx0SGVhZGVycygpOiBBcnJheTxzdHJpbmc+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2luaXREZWZhdWx0SGVhZGVycztcbiAgICB9XG5cbiAgICBnZXQgcHJlZmVyZW5jZUNvbHVtbkNvdW50JCgpOiBPYnNlcnZhYmxlPG51bWJlcj4ge1xuICAgICAgICByZXR1cm4gdGhpcy5fcHJlZmVyZW5jZUNvbHVtbkNvdW50JC5hc09ic2VydmFibGUoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGluaXRpYWxpemVIZWFkZXJTdGF0ZSgpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgZGVmYXVsdEhlYWRlcnMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmZpZWxkc0dyb3VwWzBdLmZpZWxkcy5sZW5ndGggJiYgZGVmYXVsdEhlYWRlcnMubGVuZ3RoIDwgdGhpcy5oZWFkZXJDb2x1bW5Db3VudDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5maWVsZHNHcm91cFswXS5maWVsZHNbaV0uaW5pdGlhbCkge1xuICAgICAgICAgICAgICAgIGRlZmF1bHRIZWFkZXJzLnB1c2godGhpcy5maWVsZHNHcm91cFswXS5maWVsZHNbaV0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHdoaWxlIChkZWZhdWx0SGVhZGVycy5sZW5ndGggPCB0aGlzLmhlYWRlckNvbHVtbkNvdW50KSB7XG4gICAgICAgICAgICBkZWZhdWx0SGVhZGVycy5wdXNoKG51bGwpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX2hlYWRlclN0YXRlID0gbmV3IEhlYWRlclN0YXRlKGRlZmF1bHRIZWFkZXJzKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgaW5pdGlhbGl6ZURlZmF1bHRIZWFkZXJTdGF0ZSgpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuaW5pdERlZmF1bHRIZWFkZXJzICYmIEFycmF5LmlzQXJyYXkodGhpcy5pbml0RGVmYXVsdEhlYWRlcnMpKSB7XG4gICAgICAgICAgICBjb25zdCBkZWZhdWx0SGVhZGVycyA9IFtdO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmhlYWRlckNvbHVtbkNvdW50OyBpKyspIHtcbiAgICAgICAgICAgICAgICBkZWZhdWx0SGVhZGVycy5wdXNoKG51bGwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmluaXREZWZhdWx0SGVhZGVycy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmIChpID49IHRoaXMuaGVhZGVyQ29sdW1uQ291bnQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fbG9nZ2VyLndhcm4oJ3RoZXJlIGFyZSBtb3JlIE5BRV9ERUZBVUxUX0hFQURFUlMgdGhhbiBoZWFkZXIgY29sdW1ucy4gU2tpcHBpbmcgdGhlIHJlc3QuLi4nKTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGZvciAoY29uc3QgaCBvZiB0aGlzLmZpZWxkc0dyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGhlYWQgPSBoLmZpZWxkcy5maW5kKGhlYWRlciA9PiBoZWFkZXIudW5pcXVlSWQgPT09IHRoaXMuaW5pdERlZmF1bHRIZWFkZXJzW2ldKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGhlYWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHRIZWFkZXJzW2ldID0gaGVhZDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5faGVhZGVyU3RhdGUudXBkYXRlU2VsZWN0ZWRIZWFkZXJzKGRlZmF1bHRIZWFkZXJzKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmxvYWRIZWFkZXJzRnJvbVByZWZlcmVuY2VzKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWRkcyBgbnVsbGAgaGVhZGVycyBpZiB0aGUgbmV3IGNvdW50IGlzIGdyZWF0ZXIgdGhhbiB0aGUgY3VycmVudCBjb3VudC5cbiAgICAgKlxuICAgICAqIFJlbW92ZXMgZXh0cmEgaGVhZGVycyBpZiB0aGUgbmV3IGNvdW50IGlzIHNtYWxsZXIgdGhhbiB0aGUgY3VycmVudCBjb3VudC5cbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgdXBkYXRlSGVhZGVyQ29sdW1uQ291bnQoKTogdm9pZCB7XG4gICAgICAgIGxldCBoZWFkZXJzID0gdGhpcy5faGVhZGVyU3RhdGUuc2VsZWN0ZWRIZWFkZXJzO1xuICAgICAgICBpZiAoaGVhZGVycy5sZW5ndGggPCB0aGlzLmhlYWRlckNvbHVtbkNvdW50KSB7XG4gICAgICAgICAgICBjb25zdCBsYXN0U2VsZWN0ZWRIZWFkZXJzID0gdGhpcy5faGVhZGVyU3RhdGUubGFzdFNlbGVjdGVkSGVhZGVycztcbiAgICAgICAgICAgIGlmIChoZWFkZXJzLmxlbmd0aCA8IHRoaXMuaGVhZGVyQ29sdW1uQ291bnQgJiYgISFsYXN0U2VsZWN0ZWRIZWFkZXJzICYmIGhlYWRlcnMubGVuZ3RoIDwgbGFzdFNlbGVjdGVkSGVhZGVycy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBoZWFkZXJzLnB1c2goLi4ubGFzdFNlbGVjdGVkSGVhZGVycy5zbGljZShoZWFkZXJzLmxlbmd0aCwgdGhpcy5oZWFkZXJDb2x1bW5Db3VudCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgd2hpbGUgKGhlYWRlcnMubGVuZ3RoIDw9IHRoaXMuaGVhZGVyQ29sdW1uQ291bnQpIHtcbiAgICAgICAgICAgICAgICBoZWFkZXJzLnB1c2gobnVsbCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoaGVhZGVycy5sZW5ndGggPiB0aGlzLmhlYWRlckNvbHVtbkNvdW50KSB7XG4gICAgICAgICAgICBoZWFkZXJzID0gaGVhZGVycy5zbGljZSgwLCB0aGlzLmhlYWRlckNvbHVtbkNvdW50KTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLl9oZWFkZXJTdGF0ZS51cGRhdGVTZWxlY3RlZEhlYWRlcnMoaGVhZGVycyk7XG4gICAgfVxuXG4gICAgcHVibGljIHNldEFsbG93ZWROZXRzKGFsbG93ZWROZXRzOiBBcnJheTxQZXRyaU5ldFJlZmVyZW5jZT4pIHtcbiAgICAgICAgLyogVE9ETyBieSBzaW1wbHkgcmVwbGFjaW5nIHRoZSBzZWxlY3Qgb3B0aW9ucyB3aXRoIG5ldyBvYmplY3QsIHdlIGRvbid0IGxvb3NlIHRoZSBvbGQgcmVmZXJlbmNlcy5cbiAgICAgICAgICAgICBDb2x1bW5zIHdpdGggaGVhZGVycyBmcm9tIG5ldHMgdGhhdCBhcmUgbm8gbG9uZ2VyIGFsbG93ZWQgc2hvdWxkIGhhdmUgdGhlaXIgdmFsdWUgY2xlYXJlZC5cbiAgICAgICAgICAgICBDb2x1bW5zIHdpdGggdmFsaWQgdmFsdWVzIHRoYXQgYXJlIG5vdCBtZXRhZGF0YSBzaG91bGQgaGF2ZSB0aGVpciBzZWxlY3Rpb24gcmVtYXBwZWQgdG8gdGhlIG5ldyBvYmplY3RzLlxuICAgICAgICAgKi9cblxuICAgICAgICBjb25zdCBmaWVsZHNHcm91cHM6IEFycmF5PEZpZWxkc0dyb3VwPiA9IFtdO1xuICAgICAgICBhbGxvd2VkTmV0cy5mb3JFYWNoKGFsbG93ZWROZXQgPT4ge1xuICAgICAgICAgICAgY29uc3QgZmllbGRzR3JvdXA6IEZpZWxkc0dyb3VwID0ge1xuICAgICAgICAgICAgICAgIGdyb3VwVGl0bGU6IGFsbG93ZWROZXQudGl0bGUsXG4gICAgICAgICAgICAgICAgZmllbGRzOiBbXVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGFsbG93ZWROZXQuaW1tZWRpYXRlRGF0YS5mb3JFYWNoKGltbWVkaWF0ZSA9PiB7XG4gICAgICAgICAgICAgICAgZmllbGRzR3JvdXAuZmllbGRzLnB1c2goXG4gICAgICAgICAgICAgICAgICAgIG5ldyBIZWFkZXJDb2x1bW4oSGVhZGVyQ29sdW1uVHlwZS5JTU1FRElBVEUsIGltbWVkaWF0ZS5zdHJpbmdJZCwgaW1tZWRpYXRlLnRpdGxlLFxuICAgICAgICAgICAgICAgICAgICAgICAgaW1tZWRpYXRlLnR5cGUsIGZhbHNlLCBhbGxvd2VkTmV0LmlkZW50aWZpZXIpXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgZmllbGRzR3JvdXBzLnB1c2goZmllbGRzR3JvdXApO1xuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLmZpZWxkc0dyb3VwLnNwbGljZSgxLCB0aGlzLmZpZWxkc0dyb3VwLmxlbmd0aCAtIDEpO1xuICAgICAgICB0aGlzLmZpZWxkc0dyb3VwLnB1c2goLi4uZmllbGRzR3JvdXBzKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2V0VGFza0FsbG93ZWROZXRzKGFsbG93ZWROZXRzOiBBcnJheTxOZXQ+KSB7XG4gICAgICAgIC8qIFRPRE8gYnkgc2ltcGx5IHJlcGxhY2luZyB0aGUgc2VsZWN0IG9wdGlvbnMgd2l0aCBuZXcgb2JqZWN0LCB3ZSBkb24ndCBsb29zZSB0aGUgb2xkIHJlZmVyZW5jZXMuXG4gICAgICAgICAgICAgQ29sdW1ucyB3aXRoIGhlYWRlcnMgZnJvbSBuZXRzIHRoYXQgYXJlIG5vIGxvbmdlciBhbGxvd2VkIHNob3VsZCBoYXZlIHRoZWlyIHZhbHVlIGNsZWFyZWQuXG4gICAgICAgICAgICAgQ29sdW1ucyB3aXRoIHZhbGlkIHZhbHVlcyB0aGF0IGFyZSBub3QgbWV0YWRhdGEgc2hvdWxkIGhhdmUgdGhlaXIgc2VsZWN0aW9uIHJlbWFwcGVkIHRvIHRoZSBuZXcgb2JqZWN0cy5cbiAgICAgICAgICovXG5cbiAgICAgICAgY29uc3QgZmllbGRzR3JvdXBzOiBBcnJheTxGaWVsZHNHcm91cD4gPSBbXTtcbiAgICAgICAgYWxsb3dlZE5ldHMuZm9yRWFjaChhbGxvd2VkTmV0ID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGZpZWxkc0dyb3VwOiBGaWVsZHNHcm91cCA9IHtcbiAgICAgICAgICAgICAgICBncm91cFRpdGxlOiBhbGxvd2VkTmV0LnRpdGxlLFxuICAgICAgICAgICAgICAgIGZpZWxkczogW11cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBjb25zdCBleGlzdGluZyA9IG5ldyBTZXQoKTtcbiAgICAgICAgICAgIGFsbG93ZWROZXQudHJhbnNpdGlvbnMuZm9yRWFjaCh0cmFucyA9PiB7XG4gICAgICAgICAgICAgICAgdHJhbnMuaW1tZWRpYXRlRGF0YS5mb3JFYWNoKGRhdGEgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWV4aXN0aW5nLmhhcyhkYXRhLnN0cmluZ0lkKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXhpc3RpbmcuYWRkKGRhdGEuc3RyaW5nSWQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZmllbGRzR3JvdXAuZmllbGRzLnB1c2goXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3IEhlYWRlckNvbHVtbihIZWFkZXJDb2x1bW5UeXBlLklNTUVESUFURSwgZGF0YS5zdHJpbmdJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS50aXRsZSwgZGF0YS50eXBlLCBmYWxzZSwgYWxsb3dlZE5ldC5pZGVudGlmaWVyKVxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBmaWVsZHNHcm91cHMucHVzaChmaWVsZHNHcm91cCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuZmllbGRzR3JvdXAuc3BsaWNlKDEsIHRoaXMuZmllbGRzR3JvdXAubGVuZ3RoIC0gMSk7XG4gICAgICAgIHRoaXMuZmllbGRzR3JvdXAucHVzaCguLi5maWVsZHNHcm91cHMpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIElmIHRoaXMgdmlldyBoYXMgc29tIGhlYWRlcnMgc3RvcmVkIGluIGl0J3MgcHJlZmVyZW5jZXMgYXR0ZW1wdHMgdG8gbG9hZCB0aGVtLlxuICAgICAqIElmIHRoZSBwcmVmZXJlbmNlcyBjb250YWluIG5vbmV4aXN0ZW50IGhlYWRlcnMgdGhleSB3aWxsIGJlIHNraXBwZWQuXG4gICAgICpcbiAgICAgKiBUaGlzIGZ1bmN0aW9uIGlzIE5PVCBjYWxsZWQgYnkgdGhlIGFic3RyYWN0IGNsYXNzJyBjb25zdHJ1Y3Rvci5cbiAgICAgKiBJdCBpcyB0aGUgcmVzcG9uc2liaWxpdHkgb2YgdGhlIGNoaWxkIGNsYXNzIHRvIGNhbGwgaXQgYXQgYW4gYXBwcm9wcmlhdGUgbW9tZW50LlxuICAgICAqL1xuICAgIHByb3RlY3RlZCBsb2FkSGVhZGVyc0Zyb21QcmVmZXJlbmNlcygpOiB2b2lkIHtcbiAgICAgICAgY29uc3Qgdmlld0lkID0gdGhpcy5nZXRWaWV3SWQoKTtcbiAgICAgICAgaWYgKCF2aWV3SWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBwcmVmZXJyZWRIZWFkZXJLZXlzID0gdGhpcy5fcHJlZmVyZW5jZXMuZ2V0SGVhZGVycyh2aWV3SWQpO1xuICAgICAgICBpZiAoIXByZWZlcnJlZEhlYWRlcktleXMpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBuZXdIZWFkZXJzID0gW107XG4gICAgICAgIHByZWZlcnJlZEhlYWRlcktleXMuZm9yRWFjaChoZWFkZXJLZXkgPT4ge1xuICAgICAgICAgICAgZm9yIChjb25zdCBmaWVsZEdyb3VwIG9mIHRoaXMuZmllbGRzR3JvdXApIHtcbiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGhlYWRlciBvZiBmaWVsZEdyb3VwLmZpZWxkcykge1xuICAgICAgICAgICAgICAgICAgICBpZiAoaGVhZGVyLnVuaXF1ZUlkID09PSBoZWFkZXJLZXkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5ld0hlYWRlcnMucHVzaChoZWFkZXIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuOyAvLyBjb250aW51ZSB0aGUgb3V0ZXJtb3N0IGxvb3BcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIG5vIG1hdGNoIGZvdW5kXG4gICAgICAgICAgICBuZXdIZWFkZXJzLnB1c2gobnVsbCk7XG4gICAgICAgICAgICB0aGlzLl9sb2dnZXIud2F