igniteui-angular
Version:
Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps
718 lines • 51.7 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import * as tslib_1 from "tslib";
import { CommonModule } from '@angular/common';
import { Component, ContentChildren, ChangeDetectorRef, EventEmitter, HostBinding, Input, NgModule, Output, QueryList, Renderer2, ViewChildren } from '@angular/core';
import { Subject } from 'rxjs';
import { IgxButtonDirective, IgxButtonModule } from '../directives/button/button.directive';
import { IgxRippleModule } from '../directives/ripple/ripple.directive';
import { IgxIconModule } from '../icon/index';
import { takeUntil } from 'rxjs/operators';
/** @enum {number} */
var ButtonGroupAlignment = {
horizontal: 0, vertical: 1,
};
export { ButtonGroupAlignment };
ButtonGroupAlignment[ButtonGroupAlignment.horizontal] = 'horizontal';
ButtonGroupAlignment[ButtonGroupAlignment.vertical] = 'vertical';
/** @type {?} */
var NEXT_ID = 0;
/**
* **Ignite UI for Angular Button Group** -
* [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/buttongroup.html)
*
* The Ignite UI Button Group displays a group of buttons either vertically or horizontally. The group supports
* single, multiple and toggle selection.
*
* Example:
* ```html
* <igx-buttongroup multiSelection="true" [values]="fontOptions">
* </igx-buttongroup>
* ```
* The `fontOptions` value shown above is defined as:
* ```typescript
* this.fontOptions = [
* { icon: 'format_bold', selected: false },
* { icon: 'format_italic', selected: false },
* { icon: 'format_underlined', selected: false }];
* ```
*/
var IgxButtonGroupComponent = /** @class */ (function () {
function IgxButtonGroupComponent(_cdr, _renderer) {
this._cdr = _cdr;
this._renderer = _renderer;
this._disabled = false;
this.buttonClickNotifier$ = new Subject();
this.queryListNotifier$ = new Subject();
/**
* An \@Input property that sets the value of the `id` attribute. If not set it will be automatically generated.
* ```html
* <igx-buttongroup [id]="'igx-dialog-56'" [multiSelection]="!multi" [values]="alignOptions">
* ```
*/
this.id = "igx-buttongroup-" + NEXT_ID++;
/**
* An \@Input property that enables selecting multiple buttons. By default, multi-selection is false.
* ```html
* <igx-buttongroup [multiSelection]="false" [alignment]="alignment"></igx-buttongroup>
* ```
*/
this.multiSelection = false;
/**
* @hidden
*/
this.selectedIndexes = [];
/**
* An \@Ouput property that emits an event when a button is selected.
* ```typescript
* \@ViewChild("toast")
* private toast: IgxToastComponent;
* public onSelect(buttongroup){
* this.toast.show()
* }
* //...
* ```
* ```html
* <igx-buttongroup #MyChild [multiSelection]="!multi" (onSelect)="onSelect($event)"></igx-buttongroup>
* <igx-toast #toast message="You have made a selection!"></igx-toast>
* ```
*/
this.onSelect = new EventEmitter();
/**
* An \@Ouput property that emits an event when a button is deselected.
* ```typescript
* \@ViewChild("toast")
* private toast: IgxToastComponent;
* public onUnselect(buttongroup){
* this.toast.show()
* }
* //...
* ```
* ```html
* igx-buttongroup #MyChild [multiSelection]="multi" (onUnselect)="onUnselect($event)"></igx-buttongroup>
* <igx-toast #toast message="You have deselected a button!"></igx-toast>
* ```
*/
this.onUnselect = new EventEmitter();
}
Object.defineProperty(IgxButtonGroupComponent.prototype, "buttons", {
/**
* A collection containing all buttons inside the button group.
*/
get: /**
* A collection containing all buttons inside the button group.
* @return {?}
*/
function () {
return tslib_1.__spread(this.viewButtons.toArray(), this.templateButtons.toArray());
},
enumerable: true,
configurable: true
});
Object.defineProperty(IgxButtonGroupComponent.prototype, "itemContentCssClass", {
/**
* Returns the CSS class of the item content of the `IgxButtonGroup`.
*```typescript
*@ViewChild("MyChild")
*public buttonG: IgxButtonGroupComponent;
*ngAfterViewInit(){
* let buttonSelect = this.buttonG.itemContentCssClass;
*}
*```
*/
get: /**
* Returns the CSS class of the item content of the `IgxButtonGroup`.
* ```typescript
* \@ViewChild("MyChild")
* public buttonG: IgxButtonGroupComponent;
* ngAfterViewInit(){
* let buttonSelect = this.buttonG.itemContentCssClass;
* }
* ```
* @return {?}
*/
function () {
return this._itemContentCssClass;
},
/**
* Allows you to set a style using the `itemContentCssClass` input.
* The value should be the CSS class name that will be applied to the button group.
*```typescript
*public style1 = "styleClass";
* //..
*```
* ```html
*<igx-buttongroup [itemContentCssClass]="style1" [multiSelection]="!multi" [values]="alignOptions">
*```
*/
set: /**
* Allows you to set a style using the `itemContentCssClass` input.
* The value should be the CSS class name that will be applied to the button group.
* ```typescript
* public style1 = "styleClass";
* //..
* ```
* ```html
* <igx-buttongroup [itemContentCssClass]="style1" [multiSelection]="!multi" [values]="alignOptions">
* ```
* @param {?} value
* @return {?}
*/
function (value) {
this._itemContentCssClass = value || this._itemContentCssClass;
},
enumerable: true,
configurable: true
});
Object.defineProperty(IgxButtonGroupComponent.prototype, "disabled", {
/**
* An @Input property that allows you to disable the `igx-buttongroup` component. By default it's false.
* ```html
* <igx-buttongroup [disabled]="true" [multiSelection]="multi" [values]="fontOptions"></igx-buttongroup>
* ```
*/
get: /**
* An \@Input property that allows you to disable the `igx-buttongroup` component. By default it's false.
* ```html
* <igx-buttongroup [disabled]="true" [multiSelection]="multi" [values]="fontOptions"></igx-buttongroup>
* ```
* @return {?}
*/
function () {
return this._disabled;
},
set: /**
* @param {?} value
* @return {?}
*/
function (value) {
var _this = this;
if (this._disabled !== value) {
this._disabled = value;
if (this.viewButtons && this.templateButtons) {
this.buttons.forEach(function (b) { return b.disabled = _this._disabled; });
}
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(IgxButtonGroupComponent.prototype, "alignment", {
/**
* Returns the alignment of the `igx-buttongroup`.
*```typescript
*@ViewChild("MyChild")
*public buttonG: IgxButtonGroupComponent;
*ngAfterViewInit(){
* let buttonAlignment = this.buttonG.alignment;
*}
*```
*/
get: /**
* Returns the alignment of the `igx-buttongroup`.
* ```typescript
* \@ViewChild("MyChild")
* public buttonG: IgxButtonGroupComponent;
* ngAfterViewInit(){
* let buttonAlignment = this.buttonG.alignment;
* }
* ```
* @return {?}
*/
function () {
return this._isVertical ? ButtonGroupAlignment.vertical : ButtonGroupAlignment.horizontal;
},
/**
* Allows you to set the button group alignment.
* Available options are `ButtonGroupAlignment.horizontal` (default) and `ButtonGroupAlignment.vertical`.
* ```typescript
*public alignment = ButtonGroupAlignment.vertical;
* //..
* ```
* ```html
*<igx-buttongroup [multiSelection]="false" [values]="cities" [alignment]="alignment"></igx-buttongroup>
* ```
*/
set: /**
* Allows you to set the button group alignment.
* Available options are `ButtonGroupAlignment.horizontal` (default) and `ButtonGroupAlignment.vertical`.
* ```typescript
* public alignment = ButtonGroupAlignment.vertical;
* //..
* ```
* ```html
* <igx-buttongroup [multiSelection]="false" [values]="cities" [alignment]="alignment"></igx-buttongroup>
* ```
* @param {?} value
* @return {?}
*/
function (value) {
this._isVertical = value === ButtonGroupAlignment.vertical;
},
enumerable: true,
configurable: true
});
Object.defineProperty(IgxButtonGroupComponent.prototype, "isVertical", {
/**
* Returns true if the `igx-buttongroup` alignment is vertical.
* Note that in order for the accessor to work correctly the property should be set explicitly.
* ```html
* <igx-buttongroup #MyChild [alignment]="alignment" [values]="alignOptions">
* ```
* ```typescript
* //...
*@ViewChild("MyChild")
*private buttonG: IgxButtonGroupComponent;
*ngAfterViewInit(){
* let orientation = this.buttonG.isVertical;
*}
*```
*/
get: /**
* Returns true if the `igx-buttongroup` alignment is vertical.
* Note that in order for the accessor to work correctly the property should be set explicitly.
* ```html
* <igx-buttongroup #MyChild [alignment]="alignment" [values]="alignOptions">
* ```
* ```typescript
* //...
* \@ViewChild("MyChild")
* private buttonG: IgxButtonGroupComponent;
* ngAfterViewInit(){
* let orientation = this.buttonG.isVertical;
* }
* ```
* @return {?}
*/
function () {
return this._isVertical;
},
enumerable: true,
configurable: true
});
Object.defineProperty(IgxButtonGroupComponent.prototype, "selectedButtons", {
/**
* Gets the selected button/buttons.
*```typescript
*@ViewChild("MyChild")
*private buttonG: IgxButtonGroupComponent;
*ngAfterViewInit(){
* let selectedButton = this.buttonG.selectedButtons;
*}
*```
*/
get: /**
* Gets the selected button/buttons.
* ```typescript
* \@ViewChild("MyChild")
* private buttonG: IgxButtonGroupComponent;
* ngAfterViewInit(){
* let selectedButton = this.buttonG.selectedButtons;
* }
* ```
* @return {?}
*/
function () {
var _this = this;
return this.buttons.filter(function (b, i) {
return _this.selectedIndexes.indexOf(i) !== -1;
});
},
enumerable: true,
configurable: true
});
/**
* Selects a button by its index.
* @memberOf {@link IgxButtonGroupComponent}
*```typescript
*@ViewChild("MyChild")
*private buttonG: IgxButtonGroupComponent;
*ngAfterViewInit(){
* this.buttonG.selectButton(2);
* this.cdr.detectChanges();
*}
*```
*/
/**
* Selects a button by its index.
* \@memberOf {\@link IgxButtonGroupComponent}
* ```typescript
* \@ViewChild("MyChild")
* private buttonG: IgxButtonGroupComponent;
* ngAfterViewInit(){
* this.buttonG.selectButton(2);
* this.cdr.detectChanges();
* }
* ```
* @param {?} index
* @return {?}
*/
IgxButtonGroupComponent.prototype.selectButton = /**
* Selects a button by its index.
* \@memberOf {\@link IgxButtonGroupComponent}
* ```typescript
* \@ViewChild("MyChild")
* private buttonG: IgxButtonGroupComponent;
* ngAfterViewInit(){
* this.buttonG.selectButton(2);
* this.cdr.detectChanges();
* }
* ```
* @param {?} index
* @return {?}
*/
function (index) {
var _this = this;
if (index >= this.buttons.length || index < 0) {
return;
}
/** @type {?} */
var button = this.buttons[index];
/** @type {?} */
var buttonElement = button.nativeElement;
if (buttonElement.classList.contains('igx-button--disabled')) {
return;
}
this.selectedIndexes.push(index);
button.selected = true;
this._renderer.setAttribute(buttonElement, 'aria-pressed', 'true');
this._renderer.addClass(buttonElement, 'igx-button-group__item--selected');
this.onSelect.emit({ button: button, index: index });
/** @type {?} */
var indexInViewButtons = this.viewButtons.toArray().indexOf(button);
if (indexInViewButtons !== -1) {
this.values[indexInViewButtons].selected = true;
}
// deselect other buttons if multiSelection is not enabled
if (!this.multiSelection && this.selectedIndexes.length > 1) {
this.buttons.forEach(function (b, i) {
if (i !== index && _this.selectedIndexes.indexOf(i) !== -1) {
_this.deselectButton(i);
}
});
}
};
/**
* Deselects a button by its index.
* @memberOf {@link IgxButtonGroupComponent}
* ```typescript
*@ViewChild("MyChild")
*private buttonG: IgxButtonGroupComponent;
*ngAfterViewInit(){
* this.buttonG.deselectButton(2);
* this.cdr.detectChanges();
*}
* ```
*/
/**
* Deselects a button by its index.
* \@memberOf {\@link IgxButtonGroupComponent}
* ```typescript
* \@ViewChild("MyChild")
* private buttonG: IgxButtonGroupComponent;
* ngAfterViewInit(){
* this.buttonG.deselectButton(2);
* this.cdr.detectChanges();
* }
* ```
* @param {?} index
* @return {?}
*/
IgxButtonGroupComponent.prototype.deselectButton = /**
* Deselects a button by its index.
* \@memberOf {\@link IgxButtonGroupComponent}
* ```typescript
* \@ViewChild("MyChild")
* private buttonG: IgxButtonGroupComponent;
* ngAfterViewInit(){
* this.buttonG.deselectButton(2);
* this.cdr.detectChanges();
* }
* ```
* @param {?} index
* @return {?}
*/
function (index) {
if (index >= this.buttons.length || index < 0) {
return;
}
/** @type {?} */
var button = this.buttons[index];
/** @type {?} */
var buttonElement = button.nativeElement;
if (buttonElement.classList.contains('igx-button--disabled')) {
return;
}
this.selectedIndexes.splice(this.selectedIndexes.indexOf(index), 1);
button.selected = false;
this._renderer.setAttribute(buttonElement, 'aria-pressed', 'false');
this._renderer.removeClass(buttonElement, 'igx-button-group__item--selected');
this.onUnselect.emit({ button: button, index: index });
/** @type {?} */
var indexInViewButtons = this.viewButtons.toArray().indexOf(button);
if (indexInViewButtons !== -1) {
this.values[indexInViewButtons].selected = false;
}
};
/**
* @hidden
*/
/**
* @hidden
* @return {?}
*/
IgxButtonGroupComponent.prototype.ngAfterViewInit = /**
* @hidden
* @return {?}
*/
function () {
var _this = this;
/** @type {?} */
var initButtons = function () {
// Cancel any existing buttonClick subscriptions
_this.buttonClickNotifier$.next();
_this.selectedIndexes.splice(0, _this.selectedIndexes.length);
// initial configuration
_this.buttons.forEach(function (button, index) {
/** @type {?} */
var buttonElement = button.nativeElement;
if (_this.disabled) {
button.disabled = true;
}
if (!button.disabled && button.selected) {
_this.selectButton(index);
}
button.buttonClick.pipe(takeUntil(_this.buttonClickNotifier$)).subscribe(function (ev) { return _this._clickHandler(ev, index); });
_this._renderer.addClass(buttonElement, 'igx-button-group__item');
});
};
this.viewButtons.changes.pipe(takeUntil(this.queryListNotifier$)).subscribe(function () { return initButtons(); });
this.templateButtons.changes.pipe(takeUntil(this.queryListNotifier$)).subscribe(function () { return initButtons(); });
initButtons();
this._cdr.detectChanges();
};
/**
* @hidden
*/
/**
* @hidden
* @return {?}
*/
IgxButtonGroupComponent.prototype.ngOnDestroy = /**
* @hidden
* @return {?}
*/
function () {
this.buttonClickNotifier$.next();
this.buttonClickNotifier$.complete();
this.queryListNotifier$.next();
this.queryListNotifier$.complete();
};
/**
*@hidden
*/
/**
* @hidden
* @param {?} event
* @param {?} i
* @return {?}
*/
IgxButtonGroupComponent.prototype._clickHandler = /**
* @hidden
* @param {?} event
* @param {?} i
* @return {?}
*/
function (event, i) {
if (this.selectedIndexes.indexOf(i) !== -1) {
this.deselectButton(i);
}
else {
this.selectButton(i);
}
};
IgxButtonGroupComponent.decorators = [
{ type: Component, args: [{
selector: 'igx-buttongroup',
template: "<div class=\"igx-button-group\" role=\"group\" [class.igx-button-group--vertical]=\"isVertical\">\n <span *ngFor=\"let button of values; let i = 'index'\" type=\"button\" igxButton=\"flat\" [selected]=\"button.selected\"\n [attr.data-togglable]=\"button.togglable\" [disabled]=\"disabled || button.disabled\" [igxButtonColor]=\"button.color\"\n [igxButtonBackground]=\"button.bgcolor\" [igxLabel]=\"button.label\" [igxRipple]=\"button.ripple\">\n <div class=\"igx-button-group__item-content {{ itemContentCssClass }}\">\n <igx-icon *ngIf=\"button.icon\" fontSet=\"material\">{{button.icon}}</igx-icon>\n <span *ngIf=\"button.label\">{{button.label}}</span>\n </div>\n </span>\n <ng-content></ng-content>\n</div>\n"
}] }
];
/** @nocollapse */
IgxButtonGroupComponent.ctorParameters = function () { return [
{ type: ChangeDetectorRef },
{ type: Renderer2 }
]; };
IgxButtonGroupComponent.propDecorators = {
viewButtons: [{ type: ViewChildren, args: [IgxButtonDirective,] }],
templateButtons: [{ type: ContentChildren, args: [IgxButtonDirective,] }],
id: [{ type: HostBinding, args: ['attr.id',] }, { type: Input }],
itemContentCssClass: [{ type: Input }],
multiSelection: [{ type: Input }],
values: [{ type: Input }],
disabled: [{ type: Input }],
alignment: [{ type: Input }],
onSelect: [{ type: Output }],
onUnselect: [{ type: Output }]
};
return IgxButtonGroupComponent;
}());
export { IgxButtonGroupComponent };
if (false) {
/**
* @type {?}
* @private
*/
IgxButtonGroupComponent.prototype._disabled;
/**
* @type {?}
* @protected
*/
IgxButtonGroupComponent.prototype.buttonClickNotifier$;
/**
* @type {?}
* @protected
*/
IgxButtonGroupComponent.prototype.queryListNotifier$;
/**
* @type {?}
* @private
*/
IgxButtonGroupComponent.prototype.viewButtons;
/**
* @type {?}
* @private
*/
IgxButtonGroupComponent.prototype.templateButtons;
/**
* An \@Input property that sets the value of the `id` attribute. If not set it will be automatically generated.
* ```html
* <igx-buttongroup [id]="'igx-dialog-56'" [multiSelection]="!multi" [values]="alignOptions">
* ```
* @type {?}
*/
IgxButtonGroupComponent.prototype.id;
/**
* An \@Input property that enables selecting multiple buttons. By default, multi-selection is false.
* ```html
* <igx-buttongroup [multiSelection]="false" [alignment]="alignment"></igx-buttongroup>
* ```
* @type {?}
*/
IgxButtonGroupComponent.prototype.multiSelection;
/**
* An \@Input property that allows setting the buttons in the button group.
* ```typescript
* public ngOnInit() {
* this.cities = [
* new Button({
* label: "Sofia"
* }),
* new Button({
* label: "London"
* }),
* new Button({
* label: "New York",
* selected: true
* }),
* new Button({
* label: "Tokyo"
* })
* ];
* }
* //..
* ```
* ```html
* <igx-buttongroup [multiSelection]="false" [values]="cities"></igx-buttongroup>
* ```
* @type {?}
*/
IgxButtonGroupComponent.prototype.values;
/**
* @hidden
* @type {?}
*/
IgxButtonGroupComponent.prototype.selectedIndexes;
/**
* An \@Ouput property that emits an event when a button is selected.
* ```typescript
* \@ViewChild("toast")
* private toast: IgxToastComponent;
* public onSelect(buttongroup){
* this.toast.show()
* }
* //...
* ```
* ```html
* <igx-buttongroup #MyChild [multiSelection]="!multi" (onSelect)="onSelect($event)"></igx-buttongroup>
* <igx-toast #toast message="You have made a selection!"></igx-toast>
* ```
* @type {?}
*/
IgxButtonGroupComponent.prototype.onSelect;
/**
* An \@Ouput property that emits an event when a button is deselected.
* ```typescript
* \@ViewChild("toast")
* private toast: IgxToastComponent;
* public onUnselect(buttongroup){
* this.toast.show()
* }
* //...
* ```
* ```html
* igx-buttongroup #MyChild [multiSelection]="multi" (onUnselect)="onUnselect($event)"></igx-buttongroup>
* <igx-toast #toast message="You have deselected a button!"></igx-toast>
* ```
* @type {?}
*/
IgxButtonGroupComponent.prototype.onUnselect;
/**
* @type {?}
* @private
*/
IgxButtonGroupComponent.prototype._isVertical;
/**
* @type {?}
* @private
*/
IgxButtonGroupComponent.prototype._itemContentCssClass;
/**
* @type {?}
* @private
*/
IgxButtonGroupComponent.prototype._cdr;
/**
* @type {?}
* @private
*/
IgxButtonGroupComponent.prototype._renderer;
}
/**
* @record
*/
export function IButtonGroupEventArgs() { }
if (false) {
/** @type {?} */
IButtonGroupEventArgs.prototype.button;
/** @type {?} */
IButtonGroupEventArgs.prototype.index;
}
/**
* @hidden
*/
var IgxButtonGroupModule = /** @class */ (function () {
function IgxButtonGroupModule() {
}
IgxButtonGroupModule.decorators = [
{ type: NgModule, args: [{
declarations: [IgxButtonGroupComponent],
exports: [IgxButtonGroupComponent],
imports: [IgxButtonModule, CommonModule, IgxRippleModule, IgxIconModule]
},] }
];
return IgxButtonGroupModule;
}());
export { IgxButtonGroupModule };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnV0dG9uR3JvdXAuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vaWduaXRldWktYW5ndWxhci8iLCJzb3VyY2VzIjpbImxpYi9idXR0b25Hcm91cC9idXR0b25Hcm91cC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUVILFNBQVMsRUFDVCxlQUFlLEVBQ2YsaUJBQWlCLEVBQ2pCLFlBQVksRUFDWixXQUFXLEVBQ1gsS0FBSyxFQUNMLFFBQVEsRUFDUixNQUFNLEVBQ04sU0FBUyxFQUNULFNBQVMsRUFDVCxZQUFZLEVBRWYsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMvQixPQUFPLEVBQUUsa0JBQWtCLEVBQUUsZUFBZSxFQUFFLE1BQU0sdUNBQXVDLENBQUM7QUFDNUYsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQ3hFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDOUMsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7SUFFUixhQUFVLEVBQUUsV0FBUTs7Ozs7O0lBQ25ELE9BQU8sR0FBRyxDQUFDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFzQmY7SUF5TUksaUNBQW9CLElBQXVCLEVBQVUsU0FBb0I7UUFBckQsU0FBSSxHQUFKLElBQUksQ0FBbUI7UUFBVSxjQUFTLEdBQVQsU0FBUyxDQUFXO1FBbk1qRSxjQUFTLEdBQUcsS0FBSyxDQUFDO1FBQ2hCLHlCQUFvQixHQUFHLElBQUksT0FBTyxFQUFXLENBQUM7UUFDOUMsdUJBQWtCLEdBQUcsSUFBSSxPQUFPLEVBQVcsQ0FBQzs7Ozs7OztRQW9CL0MsT0FBRSxHQUFHLHFCQUFtQixPQUFPLEVBQUksQ0FBQzs7Ozs7OztRQXFDM0IsbUJBQWMsR0FBRyxLQUFLLENBQUM7Ozs7UUFtRGhDLG9CQUFlLEdBQWEsRUFBRSxDQUFDOzs7Ozs7Ozs7Ozs7Ozs7O1FBNkNyQixhQUFRLEdBQUcsSUFBSSxZQUFZLEVBQXlCLENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7UUFpQnJELGVBQVUsR0FBRyxJQUFJLFlBQVksRUFBeUIsQ0FBQztJQXdCeEUsQ0FBQztJQTFMRCxzQkFBVyw0Q0FBTztRQUhsQjs7V0FFRzs7Ozs7UUFDSDtZQUNJLHdCQUFXLElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxFQUFFLEVBQUssSUFBSSxDQUFDLGVBQWUsQ0FBQyxPQUFPLEVBQUUsRUFBRTtRQUM5RSxDQUFDOzs7T0FBQTtJQXVCRCxzQkFBYSx3REFBbUI7UUFJaEM7Ozs7Ozs7OztXQVNHOzs7Ozs7Ozs7Ozs7UUFDSDtZQUNJLE9BQU8sSUFBSSxDQUFDLG9CQUFvQixDQUFDO1FBQ3JDLENBQUM7UUEzQkQ7Ozs7Ozs7Ozs7V0FVRzs7Ozs7Ozs7Ozs7Ozs7UUFDSCxVQUFpQyxLQUFhO1lBQzFDLElBQUksQ0FBQyxvQkFBb0IsR0FBRyxLQUFLLElBQUksSUFBSSxDQUFDLG9CQUFvQixDQUFDO1FBQ25FLENBQUM7OztPQUFBO0lBd0RELHNCQUNXLDZDQUFRO1FBUG5COzs7OztXQUtHOzs7Ozs7OztRQUNIO1lBRUksT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDO1FBQzFCLENBQUM7Ozs7O1FBQ0QsVUFBb0IsS0FBYztZQUFsQyxpQkFRQztZQVBHLElBQUksSUFBSSxDQUFDLFNBQVMsS0FBSyxLQUFLLEVBQUU7Z0JBQzFCLElBQUksQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDO2dCQUV2QixJQUFJLElBQUksQ0FBQyxXQUFXLElBQUksSUFBSSxDQUFDLGVBQWUsRUFBRTtvQkFDMUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsVUFBQyxDQUFDLElBQUssT0FBQSxDQUFDLENBQUMsUUFBUSxHQUFHLEtBQUksQ0FBQyxTQUFTLEVBQTNCLENBQTJCLENBQUMsQ0FBQztpQkFDNUQ7YUFDSjtRQUNMLENBQUM7OztPQVRBO0lBMkJELHNCQUFhLDhDQUFTO1FBR3RCOzs7Ozs7Ozs7V0FTRzs7Ozs7Ozs7Ozs7O1FBQ0g7WUFDSSxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLG9CQUFvQixDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsb0JBQW9CLENBQUMsVUFBVSxDQUFDO1FBQzlGLENBQUM7UUExQkQ7Ozs7Ozs7Ozs7V0FVRzs7Ozs7Ozs7Ozs7Ozs7UUFDSCxVQUF1QixLQUEyQjtZQUM5QyxJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssS0FBSyxvQkFBb0IsQ0FBQyxRQUFRLENBQUM7UUFDL0QsQ0FBQzs7O09BQUE7SUFnRUQsc0JBQVcsK0NBQVU7UUFmckI7Ozs7Ozs7Ozs7Ozs7O1dBY0c7Ozs7Ozs7Ozs7Ozs7Ozs7O1FBQ0g7WUFDSSxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUM7UUFDNUIsQ0FBQzs7O09BQUE7SUFpQkQsc0JBQUksb0RBQWU7UUFWbkI7Ozs7Ozs7OztXQVNHOzs7Ozs7Ozs7Ozs7UUFDSDtZQUFBLGlCQUtDO1lBSkcsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxVQUFDLENBQUMsRUFBRSxDQUFDO2dCQUM1QixPQUFPLEtBQUksQ0FBQyxlQUFlLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBQ2xELENBQUMsQ0FBQyxDQUFDO1FBRVAsQ0FBQzs7O09BQUE7SUFFRDs7Ozs7Ozs7Ozs7T0FXRzs7Ozs7Ozs7Ozs7Ozs7O0lBQ0ksOENBQVk7Ozs7Ozs7Ozs7Ozs7O0lBQW5CLFVBQW9CLEtBQWE7UUFBakMsaUJBaUNDO1FBaENHLElBQUksS0FBSyxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUU7WUFDM0MsT0FBTztTQUNWOztZQUVLLE1BQU0sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQzs7WUFDNUIsYUFBYSxHQUFHLE1BQU0sQ0FBQyxhQUFhO1FBRTFDLElBQUksYUFBYSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsc0JBQXNCLENBQUMsRUFBRTtZQUMxRCxPQUFPO1NBQ1Y7UUFFRCxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNqQyxNQUFNLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztRQUV2QixJQUFJLENBQUMsU0FBUyxDQUFDLFlBQVksQ0FBQyxhQUFhLEVBQUUsY0FBYyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQ25FLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLGFBQWEsRUFBRSxrQ0FBa0MsQ0FBQyxDQUFDO1FBRTNFLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQzs7WUFFL0Msa0JBQWtCLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDO1FBQ3JFLElBQUksa0JBQWtCLEtBQUssQ0FBQyxDQUFDLEVBQUU7WUFDM0IsSUFBSSxDQUFDLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7U0FDbkQ7UUFFRCwwREFBMEQ7UUFDMUQsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLElBQUksSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1lBQ3pELElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFVBQUMsQ0FBQyxFQUFFLENBQUM7Z0JBQ3RCLElBQUksQ0FBQyxLQUFLLEtBQUssSUFBSSxLQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRTtvQkFDdkQsS0FBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQztpQkFDMUI7WUFDTCxDQUFDLENBQUMsQ0FBQztTQUNOO0lBQ0wsQ0FBQztJQUVEOzs7Ozs7Ozs7OztPQVdHOzs7Ozs7Ozs7Ozs7Ozs7SUFDSSxnREFBYzs7Ozs7Ozs7Ozs7Ozs7SUFBckIsVUFBc0IsS0FBYTtRQUMvQixJQUFJLEtBQUssSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sSUFBSSxLQUFLLEdBQUcsQ0FBQyxFQUFFO1lBQzNDLE9BQU87U0FDVjs7WUFFSyxNQUFNLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7O1lBQzVCLGFBQWEsR0FBRyxNQUFNLENBQUMsYUFBYTtRQUUxQyxJQUFJLGFBQWEsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLHNCQUFzQixDQUFDLEVBQUU7WUFDMUQsT0FBTztTQUNWO1FBRUQsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDcEUsTUFBTSxDQUFDLFFBQVEsR0FBRyxLQUFLLENBQUM7UUFFeEIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxZQUFZLENBQUMsYUFBYSxFQUFFLGNBQWMsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUNwRSxJQUFJLENBQUMsU0FBUyxDQUFDLFdBQVcsQ0FBQyxhQUFhLEVBQUUsa0NBQWtDLENBQUMsQ0FBQztRQUU5RSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7O1lBRWpELGtCQUFrQixHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxFQUFFLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQztRQUNyRSxJQUFJLGtCQUFrQixLQUFLLENBQUMsQ0FBQyxFQUFFO1lBQzNCLElBQUksQ0FBQyxNQUFNLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDO1NBQ3BEO0lBQ0wsQ0FBQztJQUVEOztPQUVHOzs7OztJQUNJLGlEQUFlOzs7O0lBQXRCO1FBQUEsaUJBNkJDOztZQTVCUyxXQUFXLEdBQUc7WUFDaEIsZ0RBQWdEO1lBQ2hELEtBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUVqQyxLQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsS0FBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUU1RCx3QkFBd0I7WUFDeEIsS0FBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsVUFBQyxNQUFNLEVBQUUsS0FBSzs7b0JBQ3pCLGFBQWEsR0FBRyxNQUFNLENBQUMsYUFBYTtnQkFFMUMsSUFBSSxLQUFJLENBQUMsUUFBUSxFQUFFO29CQUNmLE1BQU0sQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDO2lCQUMxQjtnQkFFRCxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsSUFBSSxNQUFNLENBQUMsUUFBUSxFQUFFO29CQUNyQyxLQUFJLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDO2lCQUM1QjtnQkFFRCxNQUFNLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSSxDQUFDLG9CQUFvQixDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsVUFBQyxFQUFFLElBQUssT0FBQSxLQUFJLENBQUMsYUFBYSxDQUFDLEVBQUUsRUFBRSxLQUFLLENBQUMsRUFBN0IsQ0FBNkIsQ0FBQyxDQUFDO2dCQUMvRyxLQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxhQUFhLEVBQUUsd0JBQXdCLENBQUMsQ0FBQztZQUNyRSxDQUFDLENBQUMsQ0FBQztRQUNQLENBQUM7UUFFRCxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLGNBQU0sT0FBQSxXQUFXLEVBQUUsRUFBYixDQUFhLENBQUMsQ0FBQztRQUNqRyxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLGNBQU0sT0FBQSxXQUFXLEVBQUUsRUFBYixDQUFhLENBQUMsQ0FBQztRQUNyRyxXQUFXLEVBQUUsQ0FBQztRQUVkLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDOUIsQ0FBQztJQUVEOztPQUVHOzs7OztJQUNJLDZDQUFXOzs7O0lBQWxCO1FBQ0ksSUFBSSxDQUFDLG9CQUFvQixDQUFDLElBQUksRUFBRSxDQUFDO1FBQ2pDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUVyQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDL0IsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQ3ZDLENBQUM7SUFFRDs7T0FFRzs7Ozs7OztJQUNJLCtDQUFhOzs7Ozs7SUFBcEIsVUFBcUIsS0FBSyxFQUFFLENBQUM7UUFDekIsSUFBSSxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRTtZQUN4QyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQzFCO2FBQU07WUFDSCxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQ3hCO0lBQ0wsQ0FBQzs7Z0JBeFdKLFNBQVMsU0FBQztvQkFDUCxRQUFRLEVBQUUsaUJBQWlCO29CQUMzQixneEJBQWlEO2lCQUNwRDs7OztnQkEzQ0csaUJBQWlCO2dCQU9qQixTQUFTOzs7OEJBMkNSLFlBQVksU0FBQyxrQkFBa0I7a0NBQy9CLGVBQWUsU0FBQyxrQkFBa0I7cUJBZWxDLFdBQVcsU0FBQyxTQUFTLGNBQ3JCLEtBQUs7c0NBY0wsS0FBSztpQ0F3QkwsS0FBSzt5QkEyQkwsS0FBSzsyQkFPTCxLQUFLOzRCQThCTCxLQUFLOzJCQWdDTCxNQUFNOzZCQWlCTixNQUFNOztJQXVMWCw4QkFBQztDQUFBLEFBeldELElBeVdDO1NBcFdZLHVCQUF1Qjs7Ozs7O0lBQ2hDLDRDQUEwQjs7Ozs7SUFDMUIsdURBQXdEOzs7OztJQUN4RCxxREFBc0Q7Ozs7O0lBRXRELDhDQUFxRjs7Ozs7SUFDckYsa0RBQTRGOzs7Ozs7OztJQWU1RixxQ0FFMkM7Ozs7Ozs7O0lBcUMzQyxpREFBdUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7SUEyQnZDLHlDQUE0Qjs7Ozs7SUF3QjVCLGtEQUFzQzs7Ozs7Ozs7Ozs7Ozs7Ozs7SUE2Q3RDLDJDQUFzRTs7Ozs7Ozs7Ozs7Ozs7Ozs7SUFpQnRFLDZDQUF3RTs7Ozs7SUFvQnhFLDhDQUE2Qjs7Ozs7SUFDN0IsdURBQXFDOzs7OztJQUV6Qix1Q0FBK0I7Ozs7O0lBQUUsNENBQTRCOzs7OztBQWtLN0UsMkNBR0M7OztJQUZHLHVDQUEyQjs7SUFDM0Isc0NBQWM7Ozs7O0FBTWxCO0lBQUE7SUFPQSxDQUFDOztnQkFQQSxRQUFRLFNBQUM7b0JBQ04sWUFBWSxFQUFFLENBQUMsdUJBQXVCLENBQUM7b0JBQ3ZDLE9BQU8sRUFBRSxDQUFDLHVCQUF1QixDQUFDO29CQUNsQyxPQUFPLEVBQUUsQ0FBQyxlQUFlLEVBQUUsWUFBWSxFQUFFLGVBQWUsRUFBRSxhQUFhLENBQUM7aUJBQzNFOztJQUdELDJCQUFDO0NBQUEsQUFQRCxJQU9DO1NBRFksb0JBQW9CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7XG4gICAgQWZ0ZXJWaWV3SW5pdCxcbiAgICBDb21wb25lbnQsXG4gICAgQ29udGVudENoaWxkcmVuLFxuICAgIENoYW5nZURldGVjdG9yUmVmLFxuICAgIEV2ZW50RW1pdHRlcixcbiAgICBIb3N0QmluZGluZyxcbiAgICBJbnB1dCxcbiAgICBOZ01vZHVsZSxcbiAgICBPdXRwdXQsXG4gICAgUXVlcnlMaXN0LFxuICAgIFJlbmRlcmVyMixcbiAgICBWaWV3Q2hpbGRyZW4sXG4gICAgT25EZXN0cm95XG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgSWd4QnV0dG9uRGlyZWN0aXZlLCBJZ3hCdXR0b25Nb2R1bGUgfSBmcm9tICcuLi9kaXJlY3RpdmVzL2J1dHRvbi9idXR0b24uZGlyZWN0aXZlJztcbmltcG9ydCB7IElneFJpcHBsZU1vZHVsZSB9IGZyb20gJy4uL2RpcmVjdGl2ZXMvcmlwcGxlL3JpcHBsZS5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgSWd4SWNvbk1vZHVsZSB9IGZyb20gJy4uL2ljb24vaW5kZXgnO1xuaW1wb3J0IHsgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5leHBvcnQgZW51bSBCdXR0b25Hcm91cEFsaWdubWVudCB7IGhvcml6b250YWwsIHZlcnRpY2FsIH1cbmxldCBORVhUX0lEID0gMDtcblxuLyoqXG4gKiAqKklnbml0ZSBVSSBmb3IgQW5ndWxhciBCdXR0b24gR3JvdXAqKiAtXG4gKiBbRG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly93d3cuaW5mcmFnaXN0aWNzLmNvbS9wcm9kdWN0cy9pZ25pdGUtdWktYW5ndWxhci9hbmd1bGFyL2NvbXBvbmVudHMvYnV0dG9uZ3JvdXAuaHRtbClcbiAqXG4gKiBUaGUgSWduaXRlIFVJIEJ1dHRvbiBHcm91cCBkaXNwbGF5cyBhIGdyb3VwIG9mIGJ1dHRvbnMgZWl0aGVyIHZlcnRpY2FsbHkgb3IgaG9yaXpvbnRhbGx5LiAgVGhlIGdyb3VwIHN1cHBvcnRzXG4gKiBzaW5nbGUsIG11bHRpcGxlIGFuZCB0b2dnbGUgc2VsZWN0aW9uLlxuICpcbiAqIEV4YW1wbGU6XG4gKiBgYGBodG1sXG4gKiA8aWd4LWJ1dHRvbmdyb3VwIG11bHRpU2VsZWN0aW9uPVwidHJ1ZVwiIFt2YWx1ZXNdPVwiZm9udE9wdGlvbnNcIj5cbiAqIDwvaWd4LWJ1dHRvbmdyb3VwPlxuICogYGBgXG4gKiBUaGUgYGZvbnRPcHRpb25zYCB2YWx1ZSBzaG93biBhYm92ZSBpcyBkZWZpbmVkIGFzOlxuICogYGBgdHlwZXNjcmlwdFxuICogdGhpcy5mb250T3B0aW9ucyA9IFtcbiAqICAgeyBpY29uOiAnZm9ybWF0X2JvbGQnLCBzZWxlY3RlZDogZmFsc2UgfSxcbiAqICAgeyBpY29uOiAnZm9ybWF0X2l0YWxpYycsIHNlbGVjdGVkOiBmYWxzZSB9LFxuICogICB7IGljb246ICdmb3JtYXRfdW5kZXJsaW5lZCcsIHNlbGVjdGVkOiBmYWxzZSB9XTtcbiAqIGBgYFxuICovXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogJ2lneC1idXR0b25ncm91cCcsXG4gICAgdGVtcGxhdGVVcmw6ICdidXR0b25ncm91cC1jb250ZW50LmNvbXBvbmVudC5odG1sJ1xufSlcblxuZXhwb3J0IGNsYXNzIElneEJ1dHRvbkdyb3VwQ29tcG9uZW50IGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcbiAgICBwcml2YXRlIF9kaXNhYmxlZCA9IGZhbHNlO1xuICAgIHByb3RlY3RlZCBidXR0b25DbGlja05vdGlmaWVyJCA9IG5ldyBTdWJqZWN0PGJvb2xlYW4+KCk7XG4gICAgcHJvdGVjdGVkIHF1ZXJ5TGlzdE5vdGlmaWVyJCA9IG5ldyBTdWJqZWN0PGJvb2xlYW4+KCk7XG5cbiAgICBAVmlld0NoaWxkcmVuKElneEJ1dHRvbkRpcmVjdGl2ZSkgcHJpdmF0ZSB2aWV3QnV0dG9uczogUXVlcnlMaXN0PElneEJ1dHRvbkRpcmVjdGl2ZT47XG4gICAgQENvbnRlbnRDaGlsZHJlbihJZ3hCdXR0b25EaXJlY3RpdmUpIHByaXZhdGUgdGVtcGxhdGVCdXR0b25zOiBRdWVyeUxpc3Q8SWd4QnV0dG9uRGlyZWN0aXZlPjtcblxuICAgIC8qKlxuICAgICAqIEEgY29sbGVjdGlvbiBjb250YWluaW5nIGFsbCBidXR0b25zIGluc2lkZSB0aGUgYnV0dG9uIGdyb3VwLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgYnV0dG9ucygpOiBJZ3hCdXR0b25EaXJlY3RpdmVbXSB7XG4gICAgICAgIHJldHVybiBbLi4udGhpcy52aWV3QnV0dG9ucy50b0FycmF5KCksIC4uLnRoaXMudGVtcGxhdGVCdXR0b25zLnRvQXJyYXkoKV07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQW4gQElucHV0IHByb3BlcnR5IHRoYXQgc2V0cyB0aGUgdmFsdWUgb2YgdGhlIGBpZGAgYXR0cmlidXRlLiBJZiBub3Qgc2V0IGl0IHdpbGwgYmUgYXV0b21hdGljYWxseSBnZW5lcmF0ZWQuXG4gICAgICogYGBgaHRtbFxuICAgICAqICA8aWd4LWJ1dHRvbmdyb3VwIFtpZF09XCInaWd4LWRpYWxvZy01NidcIiBbbXVsdGlTZWxlY3Rpb25dPVwiIW11bHRpXCIgW3ZhbHVlc109XCJhbGlnbk9wdGlvbnNcIj5cbiAgICAgKiBgYGBcbiAgICAgKi9cbiAgICBASG9zdEJpbmRpbmcoJ2F0dHIuaWQnKVxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIGlkID0gYGlneC1idXR0b25ncm91cC0ke05FWFRfSUQrK31gO1xuXG4gICAgLyoqXG4gICAgICogQWxsb3dzIHlvdSB0byBzZXQgYSBzdHlsZSB1c2luZyB0aGUgYGl0ZW1Db250ZW50Q3NzQ2xhc3NgIGlucHV0LlxuICAgICAqIFRoZSB2YWx1ZSBzaG91bGQgYmUgdGhlIENTUyBjbGFzcyBuYW1lIHRoYXQgd2lsbCBiZSBhcHBsaWVkIHRvIHRoZSBidXR0b24gZ3JvdXAuXG4gICAgICpgYGB0eXBlc2NyaXB0XG4gICAgICpwdWJsaWMgc3R5bGUxID0gXCJzdHlsZUNsYXNzXCI7XG4gICAgICogLy8uLlxuICAgICAqYGBgXG4gICAgICogYGBgaHRtbFxuICAgICAqPGlneC1idXR0b25ncm91cCBbaXRlbUNvbnRlbnRDc3NDbGFzc109XCJzdHlsZTFcIiBbbXVsdGlTZWxlY3Rpb25dPVwiIW11bHRpXCIgW3ZhbHVlc109XCJhbGlnbk9wdGlvbnNcIj5cbiAgICAgKmBgYFxuICAgICAqL1xuICAgIEBJbnB1dCgpIHNldCBpdGVtQ29udGVudENzc0NsYXNzKHZhbHVlOiBzdHJpbmcpIHtcbiAgICAgICAgdGhpcy5faXRlbUNvbnRlbnRDc3NDbGFzcyA9IHZhbHVlIHx8IHRoaXMuX2l0ZW1Db250ZW50Q3NzQ2xhc3M7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgQ1NTIGNsYXNzIG9mIHRoZSBpdGVtIGNvbnRlbnQgb2YgdGhlIGBJZ3hCdXR0b25Hcm91cGAuXG4gICAgICpgYGB0eXBlc2NyaXB0XG4gICAgICpAVmlld0NoaWxkKFwiTXlDaGlsZFwiKVxuICAgICAqcHVibGljIGJ1dHRvbkc6IElneEJ1dHRvbkdyb3VwQ29tcG9uZW50O1xuICAgICAqbmdBZnRlclZpZXdJbml0KCl7XG4gICAgICogICBsZXQgYnV0dG9uU2VsZWN0ID0gdGhpcy5idXR0b25HLml0ZW1Db250ZW50Q3NzQ2xhc3M7XG4gICAgICp9XG4gICAgICpgYGBcbiAgICAgKi9cbiAgICBnZXQgaXRlbUNvbnRlbnRDc3NDbGFzcygpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy5faXRlbUNvbnRlbnRDc3NDbGFzcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBbiBASW5wdXQgcHJvcGVydHkgdGhhdCBlbmFibGVzIHNlbGVjdGluZyBtdWx0aXBsZSBidXR0b25zLiBCeSBkZWZhdWx0LCBtdWx0aS1zZWxlY3Rpb24gaXMgZmFsc2UuXG4gICAgICogYGBgaHRtbFxuICAgICAqIDxpZ3gtYnV0dG9uZ3JvdXAgW211bHRpU2VsZWN0aW9uXT1cImZhbHNlXCIgW2FsaWdubWVudF09XCJhbGlnbm1lbnRcIj48L2lneC1idXR0b25ncm91cD5cbiAgICAgKiBgYGBcbiAgICAgKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgbXVsdGlTZWxlY3Rpb24gPSBmYWxzZTtcbiAgICAvKipcbiAgICAgKiBBbiBASW5wdXQgcHJvcGVydHkgdGhhdCBhbGxvd3Mgc2V0dGluZyB0aGUgYnV0dG9ucyBpbiB0aGUgYnV0dG9uIGdyb3VwLlxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiAgcHVibGljIG5nT25Jbml0KCkge1xuICAgICAqICAgICAgdGhpcy5jaXRpZXMgPSBbXG4gICAgICogICAgICAgIG5ldyBCdXR0b24oe1xuICAgICAqICAgICAgICAgIGxhYmVsOiBcIlNvZmlhXCJcbiAgICAgKiAgICAgIH0pLFxuICAgICAqICAgICAgICBuZXcgQnV0dG9uKHtcbiAgICAgKiAgICAgICAgICBsYWJlbDogXCJMb25kb25cIlxuICAgICAqICAgICAgfSksXG4gICAgICogICAgICAgIG5ldyBCdXR0b24oe1xuICAgICAqICAgICAgICAgIGxhYmVsOiBcIk5ldyBZb3JrXCIsXG4gICAgICogICAgICAgICAgc2VsZWN0ZWQ6IHRydWVcbiAgICAgKiAgICAgIH0pLFxuICAgICAqICAgICAgICBuZXcgQnV0dG9uKHtcbiAgICAgKiAgICAgICAgICBsYWJlbDogXCJUb2t5b1wiXG4gICAgICogICAgICB9KVxuICAgICAqICBdO1xuICAgICAqICB9XG4gICAgICogIC8vLi5cbiAgICAgKiBgYGBcbiAgICAgKiBgYGBodG1sXG4gICAgICogIDxpZ3gtYnV0dG9uZ3JvdXAgW211bHRpU2VsZWN0aW9uXT1cImZhbHNlXCIgW3ZhbHVlc109XCJjaXRpZXNcIj48L2lneC1idXR0b25ncm91cD5cbiAgICAgKiBgYGBcbiAgICAgKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgdmFsdWVzOiBhbnk7XG4gICAgLyoqXG4gICAgICogQW4gQElucHV0IHByb3BlcnR5IHRoYXQgYWxsb3dzIHlvdSB0byBkaXNhYmxlIHRoZSBgaWd4LWJ1dHRvbmdyb3VwYCBjb21wb25lbnQuIEJ5IGRlZmF1bHQgaXQncyBmYWxzZS5cbiAgICAgKiBgYGBodG1sXG4gICAgICogPGlneC1idXR0b25ncm91cCBbZGlzYWJsZWRdPVwidHJ1ZVwiIFttdWx0aVNlbGVjdGlvbl09XCJtdWx0aVwiIFt2YWx1ZXNdPVwiZm9udE9wdGlvbnNcIj48L2lneC1idXR0b25ncm91cD5cbiAgICAgKiBgYGBcbiAgICAgKi9cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBnZXQgZGlzYWJsZWQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLl9kaXNhYmxlZDtcbiAgICB9XG4gICAgcHVibGljIHNldCBkaXNhYmxlZCh2YWx1ZTogYm9vbGVhbikge1xuICAgICAgICBpZiAodGhpcy5fZGlzYWJsZWQgIT09IHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLl9kaXNhYmxlZCA9IHZhbHVlO1xuXG4gICAgICAgICAgICBpZiAodGhpcy52aWV3QnV0dG9ucyAmJiB0aGlzLnRlbXBsYXRlQnV0dG9ucykge1xuICAgICAgICAgICAgICAgIHRoaXMuYnV0dG9ucy5mb3JFYWNoKChiKSA9PiBiLmRpc2FibGVkID0gdGhpcy5fZGlzYWJsZWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQGhpZGRlblxuICAgICAqL1xuICAgIHB1YmxpYyBzZWxlY3RlZEluZGV4ZXM6IG51bWJlcltdID0gW107XG5cbiAgICAvKipcbiAgICAgKiBBbGxvd3MgeW91IHRvIHNldCB0aGUgYnV0dG9uIGdyb3VwIGFsaWdubWVudC5cbiAgICAgKiBBdmFpbGFibGUgb3B0aW9ucyBhcmUgYEJ1dHRvbkdyb3VwQWxpZ25tZW50Lmhvcml6b250YWxgIChkZWZhdWx0KSBhbmQgYEJ1dHRvbkdyb3VwQWxpZ25tZW50LnZlcnRpY2FsYC5cbiAgICAgKiBgYGB0eXBlc2NyaXB0XG4gICAgICpwdWJsaWMgYWxpZ25tZW50ID0gQnV0dG9uR3JvdXBBbGlnbm1lbnQudmVydGljYWw7XG4gICAgICogLy8uLlxuICAgICAqIGBgYFxuICAgICAqIGBgYGh0bWxcbiAgICAgKjxpZ3gtYnV0dG9uZ3JvdXAgW211bHRpU2VsZWN0aW9uXT1cImZhbHNlXCIgW3ZhbHVlc109XCJjaXRpZXNcIiBbYWxpZ25tZW50XT1cImFsaWdubWVudFwiPjwvaWd4LWJ1dHRvbmdyb3VwPlxuICAgICAqIGBgYFxuICAgICAqL1xuICAgIEBJbnB1dCgpIHNldCBhbGlnbm1lbnQodmFsdWU6IEJ1dHRvbkdyb3VwQWxpZ25tZW50KSB7XG4gICAgICAgIHRoaXMuX2lzVmVydGljYWwgPSB2YWx1ZSA9PT0gQnV0dG9uR3JvdXBBbGlnbm1lbnQudmVydGljYWw7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGFsaWdubWVudCBvZiB0aGUgYGlneC1idXR0b25ncm91cGAuXG4gICAgICpgYGB0eXBlc2NyaXB0XG4gICAgICpAVmlld0NoaWxkKFwiTXlDaGlsZFwiKVxuICAgICAqcHVibGljIGJ1dHRvbkc6IElneEJ1dHRvbkdyb3VwQ29tcG9uZW50O1xuICAgICAqbmdBZnRlclZpZXdJbml0KCl7XG4gICAgICogICAgbGV0IGJ1dHRvbkFsaWdubWVudCA9IHRoaXMuYnV0dG9uRy5hbGlnbm1lbnQ7XG4gICAgICp9XG4gICAgICpgYGBcbiAgICAgKi9cbiAgICBnZXQgYWxpZ25tZW50KCk6IEJ1dHRvbkdyb3VwQWxpZ25tZW50IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2lzVmVydGljYWwgPyBCdXR0b25Hcm91cEFsaWdubWVudC52ZXJ0aWNhbCA6IEJ1dHRvbkdyb3VwQWxpZ25tZW50Lmhvcml6b250YWw7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQW4gQE91cHV0IHByb3BlcnR5IHRoYXQgZW1pdHMgYW4gZXZlbnQgd2hlbiBhIGJ1dHRvbiBpcyBzZWxlY3RlZC5cbiAgICAgKmBgYHR5cGVzY3JpcHRcbiAgICAgKkBWaWV3Q2hpbGQoXCJ0b2FzdFwiKVxuICAgICAqcHJpdmF0ZSB0b2FzdDogSWd4VG9hc3RDb21wb25lbnQ7XG4gICAgICpwdWJsaWMgb25TZWxlY3QoYnV0dG9uZ3JvdXApe1xuICAgICAqICAgIHRoaXMudG9hc3Quc2hvdygpXG4gICAgICp9XG4gICAgICogLy8uLi5cbiAgICAgKmBgYFxuICAgICAqYGBgaHRtbFxuICAgICAqIDxpZ3gtYnV0dG9uZ3JvdXAgI015Q2hpbGQgW211bHRpU2VsZWN0aW9uXT1cIiFtdWx0aVwiIChvblNlbGVjdCk9XCJvblNlbGVjdCgkZXZlbnQpXCI+PC9pZ3gtYnV0dG9uZ3JvdXA+XG4gICAgICo8aWd4LXRvYXN0ICN0b2FzdCBtZXNzYWdlPVwiWW91IGhhdmUgbWFkZSBhIHNlbGVjdGlvbiFcIj48L2lneC10b2FzdD5cbiAgICAgKmBgYFxuICAgICAqL1xuICAgIEBPdXRwdXQoKSBwdWJsaWMgb25TZWxlY3QgPSBuZXcgRXZlbnRFbWl0dGVyPElCdXR0b25Hcm91cEV2ZW50QXJncz4oKTtcblxuICAgIC8qKlxuICAgICAqIEFuIEBPdXB1dCBwcm9wZXJ0eSB0aGF0IGVtaXRzIGFuIGV2ZW50IHdoZW4gYSBidXR0b24gaXMgZGVzZWxlY3RlZC5cbiAgICAgKmBgYHR5cGVzY3JpcHRcbiAgICAgKkBWaWV3Q2hpbGQoXCJ0b2FzdFwiKVxuICAgICAqcHJpdmF0ZSB0b2FzdDogSWd4VG9hc3RDb21wb25lbnQ7XG4gICAgICpwdWJsaWMgb25VbnNlbGVjdChidXR0b25ncm91cCl7XG4gICAgICogICAgdGhpcy50b2FzdC5zaG93KClcbiAgICAgKn1cbiAgICAgKiAvLy4uLlxuICAgICAqYGBgXG4gICAgICpgYGBodG1sXG4gICAgICogaWd4LWJ1dHRvbmdyb3VwICNNeUNoaWxkIFttdWx0aVNlbGVjdGlvbl09XCJtdWx0aVwiIChvblVuc2VsZWN0KT1cIm9uVW5zZWxlY3QoJGV2ZW50KVwiPjwvaWd4LWJ1dHRvbmdyb3VwPlxuICAgICAqPGlneC10b2FzdCAjdG9hc3QgbWVzc2FnZT1cIllvdSBoYXZlIGRlc2VsZWN0ZWQgYSBidXR0b24hXCI+PC9pZ3gtdG9hc3Q+XG4gICAgICpgYGBcbiAgICAgKi9cbiAgICBAT3V0cHV0KCkgcHVibGljIG9uVW5zZWxlY3QgPSBuZXcgRXZlbnRFbWl0dGVyPElCdXR0b25Hcm91cEV2ZW50QXJncz4oKTtcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgYGlneC1idXR0b25ncm91cGAgYWxpZ25tZW50IGlzIHZlcnRpY2FsLlxuICAgICAqIE5vdGUgdGhhdCBpbiBvcmRlciBmb3IgdGhlIGFjY2Vzc29yIHRvIHdvcmsgY29ycmVjdGx5IHRoZSBwcm9wZXJ0eSBzaG91bGQgYmUgc2V0IGV4cGxpY2l0bHkuXG4gICAgICogYGBgaHRtbFxuICAgICAqIDxpZ3gtYnV0dG9uZ3JvdXAgI015Q2hpbGQgW2FsaWdubWVudF09XCJhbGlnbm1lbnRcIiBbdmFsdWVzXT1cImFsaWduT3B0aW9uc1wiPlxuICAgICAqIGBgYFxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiAvLy4uLlxuICAgICAqQFZpZXdDaGlsZChcIk15Q2hpbGRcIilcbiAgICAgKnByaXZhdGUgYnV0dG9uRzogSWd4QnV0dG9uR3JvdXBDb21wb25lbnQ7XG4gICAgICpuZ0FmdGVyVmlld0luaXQoKXtcbiAgICAgKiAgICBsZXQgb3JpZW50YXRpb24gPSB0aGlzLmJ1dHRvbkcuaXNWZXJ0aWNhbDtcbiAgICAgKn1cbiAgICAgKmBgYFxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgaXNWZXJ0aWNhbCgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2lzVmVydGljYWw7XG4gICAgfVxuICAgIHByaXZhdGUgX2lzVmVydGljYWw6IGJvb2xlYW47XG4gICAgcHJpdmF0ZSBfaXRlbUNvbnRlbnRDc3NDbGFzczogc3RyaW5nO1xuXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBfY2RyOiBDaGFuZ2VEZXRlY3RvclJlZiwgcHJpdmF0ZSBfcmVuZGVyZXI6IFJlbmRlcmVyMikge1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIHNlbGVjdGVkIGJ1dHRvbi9idXR0b25zLlxuICAgICAqYGBgdHlwZXNjcmlwdFxuICAgICAqQFZpZXdDaGlsZChcIk15Q2hpbGRcIilcbiAgICAgKnByaXZhdGUgYnV0dG9uRzogSWd4QnV0dG9uR3JvdXBDb21wb25lbnQ7XG4gICAgICpuZ0FmdGVyVmlld0luaXQoKXtcbiAgICAgKiAgICBsZXQgc2VsZWN0ZWRCdXR0b24gPSB0aGlzLmJ1dHRvbkcuc2VsZWN0ZWRCdXR0b25zO1xuICAgICAqfVxuICAgICAqYGBgXG4gICAgICovXG4gICAgZ2V0IHNlbGVjdGVkQnV0dG9ucygpOiBJZ3hCdXR0b25EaXJlY3RpdmVbXSB7XG4gICAgICAgIHJldHVybiB0aGlzLmJ1dHRvbnMuZmlsdGVyKChiLCBpKSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zZWxlY3RlZEluZGV4ZXMuaW5kZXhPZihpKSAhPT0gLTE7XG4gICAgICAgIH0pO1xuXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VsZWN0cyBhIGJ1dHRvbiBieSBpdHMgaW5kZXguXG4gICAgICogQG1lbWJlck9mIHtAbGluayBJZ3hCdXR0b25Hcm91cENvbXBvbmVudH1cbiAgICAgKmBgYHR5cGVzY3JpcHRcbiAgICAgKkBWaWV3Q2hpbGQoXCJNeUNoaWxkXCIpXG4gICAgICpwcml2YXRlIGJ1dHRvbkc6IElneEJ1dHRvbkdyb3VwQ29tcG9uZW50O1xuICAgICAqbmdBZnRlclZpZXdJbml0KCl7XG4gICAgICogICAgdGhpcy5idXR0b25HLnNlbGVjdEJ1dHRvbigyKTtcbiAgICAgKiAgICB0aGlzLmNkci5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICp9XG4gICAgICpgYGBcbiAgICAgKi9cbiAgICBwdWJsaWMgc2VsZWN0QnV0dG9uKGluZGV4OiBudW1iZXIpIHtcbiAgICAgICAgaWYgKGluZGV4ID49IHRoaXMuYnV0dG9ucy5sZW5ndGggfHwgaW5kZXggPCAwKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBidXR0b24gPSB0aGlzLmJ1dHRvbnNbaW5kZXhdO1xuICAgICAgICBjb25zdCBidXR0b25FbGVtZW50ID0gYnV0dG9uLm5hdGl2ZUVsZW1lbnQ7XG5cbiAgICAgICAgaWYgKGJ1dHRvbkVsZW1lbnQuY2xhc3NMaXN0LmNvbnRhaW5zKCdpZ3gtYnV0dG9uLS1kaXNhYmxlZCcpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNlbGVjdGVkSW5kZXhlcy5wdXNoKGluZGV4KTtcbiAgICAgICAgYnV0dG9uLnNlbGVjdGVkID0gdHJ1ZTtcblxuICAgICAgICB0aGlzLl9yZW5kZXJlci5zZXRBdHRyaWJ1dGUoYnV0dG9uRWxlbWVudCwgJ2FyaWEtcHJlc3NlZCcsICd0cnVlJyk7XG4gICAgICAgIHRoaXMuX3JlbmRlcmVyLmFkZENsYXNzKGJ1dHRvbkVsZW1lbnQsICdpZ3gtYnV0dG9uLWdyb3VwX19pdGVtLS1zZWxlY3RlZCcpO1xuXG4gICAgICAgIHRoaXMub25TZWxlY3QuZW1pdCh7IGJ1dHRvbjogYnV0dG9uLCBpbmRleDogaW5kZXggfSk7XG5cbiAgICAgICAgY29uc3QgaW5kZXhJblZpZXdCdXR0b25zID0gdGhpcy52aWV3QnV0dG9ucy50b0FycmF5KCkuaW5kZXhPZihidXR0b24pO1xuICAgICAgICBpZiAoaW5kZXhJblZpZXdCdXR0b25zICE9PSAtMSkge1xuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaW5kZXhJblZpZXdCdXR0b25zXS5zZWxlY3RlZCA9IHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkZXNlbGVjdCBvdGhlciBidXR0b25zIGlmIG11bHRpU2VsZWN0aW9uIGlzIG5vdCBlbmFibGVkXG4gICAgICAgIGlmICghdGhpcy5tdWx0aVNlbGVjdGlvbiAmJiB0aGlzLnNlbGVjdGVkSW5kZXhlcy5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICB0aGlzLmJ1dHRvbnMuZm9yRWFjaCgoYiwgaSkgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChpICE9PSBpbmRleCAmJiB0aGlzLnNlbGVjdGVkSW5kZXhlcy5pbmRleE9mKGkpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmRlc2VsZWN0QnV0dG9uKGkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRGVzZWxlY3RzIGEgYnV0dG9uIGJ5IGl0cyBpbmRleC5cbiAgICAgKiBAbWVtYmVyT2Yge0BsaW5rIElneEJ1dHRvbkdyb3VwQ29tcG9uZW50fVxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKkBWaWV3Q2hpbGQoXCJNeUNoaWxkXCIpXG4gICAgICpwcml2YXRlIGJ1dHRvbkc6IElneEJ1dHRvbkdyb3VwQ29tcG9uZW50O1xuICAgICAqbmdBZnRlclZpZXdJbml0KCl7XG4gICAgICogICAgdGhpcy5idXR0b25HLmRlc2VsZWN0QnV0dG9uKDIpO1xuICAgICAqICAgIHRoaXMuY2RyLmRldGVjdENoYW5nZXMoKTtcbiAgICAgKn1cbiAgICAgKiBgYGBcbiAgICAgKi9cbiAgICBwdWJsaWMgZGVzZWxlY3RCdXR0b24oaW5kZXg6IG51bWJlcikge1xuICAgICAgICBpZiAoaW5kZXggPj0gdGhpcy5idXR0b25zLmxlbmd0aCB8fCBpbmRleCA8IDApIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGJ1dHRvbiA9IHRoaXMuYnV0dG9uc1tpbmRleF07XG4gICAgICAgIGNvbnN0IGJ1dHRvbkVsZW1lbnQgPSBidXR0b24ubmF0aXZlRWxlbWVudDtcblxuICAgICAgICBpZiAoYnV0dG9uRWxlbWVudC5jbGFzc0xpc3QuY29udGFpbnMoJ2lneC1idXR0b24tLWRpc2FibGVkJykpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2VsZWN0ZWRJbmRleGVzLnNwbGljZSh0aGlzLnNlbGVjdGVkSW5kZXhlcy5pbmRleE9mKGluZGV4KSwgMSk7XG4gICAgICAgIGJ1dHRvbi5zZWxlY3RlZCA9IGZhbHNlO1xuXG4gICAgICAgIHRoaXMuX3JlbmRlcmVyLnNldEF0dHJpYnV0ZShidXR0b25FbGVtZW50LCAnYXJpYS1wcmVzc2VkJywgJ2ZhbHNlJyk7XG4gICAgICAgIHRoaXMuX3JlbmRlcmVyLnJlbW92ZUNsYXNzKGJ1dHRvbkVsZW1lbnQsICdpZ3gtYnV0dG9uLWdyb3VwX19pdGVtLS1zZWxlY3RlZCcpO1xuXG4gICAgICAgIHRoaXMub25VbnNlbGVjdC5lbWl0KHsgYnV0dG9uOiBidXR0b24sIGluZGV4OiBpbmRleCB9KTtcblxuICAgICAgICBjb25zdCBpbmRleEluVmlld0J1dHRvbnMgPSB0aGlzLnZpZXdCdXR0b25zLnRvQXJyYXkoKS5pbmRleE9mKGJ1dHRvbik7XG4gICAgICAgIGlmIChpbmRleEluVmlld0J1dHRvbnMgIT09IC0xKSB7XG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpbmRleEluVmlld0J1dHRvbnNdLnNlbGVjdGVkID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAaGlkZGVuXG4gICAgICovXG4gICAgcHVibGljIG5nQWZ0ZXJWaWV3SW5pdCgpIHtcbiAgICAgICAgY29uc3QgaW5pdEJ1dHRvbnMgPSAoKSA9PiB7XG4gICAgICAgICAgICAvLyBDYW5jZWwgYW55IGV4aXN0aW5nIGJ1dHRvbkNsaWNrIHN1YnNjcmlwdGlvbnNcbiAgICAgICAgICAgIHRoaXMuYnV0dG9uQ2xpY2tOb3RpZmllciQubmV4dCgpO1xuXG4gICAgICAgICAgICB0aGlzLnNlbGVjdGVkSW5kZXhlcy5zcGxpY2UoMCwgdGhpcy5zZWxlY3RlZEluZGV4ZXMubGVuZ3RoKTtcblxuICAgICAgICAgICAgLy8gaW5pdGlhbCBjb25maWd1cmF0aW9uXG4gICAgICAgICAgICB0aGlzLmJ1dHRvbnMuZm9yRWFjaCgoYnV0dG9uLCBpbmRleCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IGJ1dHRvbkVsZW1lbnQgPSBidXR0b24ubmF0aXZlRWxlbWVudDtcblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmRpc2FibGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIGJ1dHRvbi5kaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKCFidXR0b24uZGlzYWJsZWQgJiYgYnV0dG9uLnNlbGVjdGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2VsZWN0QnV0dG9uKGluZGV4KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBidXR0b24uYnV0dG9uQ2xpY2sucGlwZSh0YWtlVW50aWwodGhpcy5idXR0b25DbGlja05vdGlmaWVyJCkpLnN1Y