UNPKG

igniteui-angular

Version:

Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps

718 lines • 51.7 kB
/** * @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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnV0dG9uR3JvdXAuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vaWduaXRldWktYW5ndWxhci8iLCJzb3VyY2VzIjpbImxpYi9idXR0b25Hcm91cC9idXR0b25Hcm91cC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUVILFNBQVMsRUFDVCxlQUFlLEVBQ2YsaUJBQWlCLEVBQ2pCLFlBQVksRUFDWixXQUFXLEVBQ1gsS0FBSyxFQUNMLFFBQVEsRUFDUixNQUFNLEVBQ04sU0FBUyxFQUNULFNBQVMsRUFDVCxZQUFZLEVBRWYsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMvQixPQUFPLEVBQUUsa0JBQWtCLEVBQUUsZUFBZSxFQUFFLE1BQU0sdUNBQXVDLENBQUM7QUFDNUYsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQ3hFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDOUMsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7SUFFUixhQUFVLEVBQUUsV0FBUTs7Ozs7O0lBQ25ELE9BQU8sR0FBRyxDQUFDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFzQmY7SUF5TUksaUNBQW9CLElBQXVCLEVBQVUsU0FBb0I7UUFBckQsU0FBSSxHQUFKLElBQUksQ0FBbUI7UUFBVSxjQUFTLEdBQVQsU0FBUyxDQUFXO1FBbk1qRSxjQUFTLEdBQUcsS0FBSyxDQUFDO1FBQ2hCLHlCQUFvQixHQUFHLElBQUksT0FBTyxFQUFXLENBQUM7UUFDOUMsdUJBQWtCLEdBQUcsSUFBSSxPQUFPLEVBQVcsQ0FBQzs7Ozs7OztRQW9CL0MsT0FBRSxHQUFHLHFCQUFtQixPQUFPLEVBQUksQ0FBQzs7Ozs7OztRQXFDM0IsbUJBQWMs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O0lBQ2hDLDRDQUEwQjs7Ozs7SUFDMUIsdURBQXdEOzs7OztJQUN4RCxxREFBc0Q7Ozs7O0lBRXRELDhDQUFxRjs7Ozs7SUFDckYsa0RBQTRGOzs7Ozs7OztJQWU1RixxQ0FFMkM7Ozs7Ozs7O0lBcUMzQyxpREFBdUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7SUEyQnZDLHlDQUE0Qjs7Ozs7SUF3QjVCLGtEQUFzQzs7Ozs7Ozs7Ozs7Ozs7Ozs7SUE2Q3RDLDJDQUFzRTs7Ozs7Ozs7Ozs7Ozs7Ozs7SUFpQnRFLDZDQUF3RTs7Ozs7SUFvQnhFLDhDQUE2Qjs7Ozs7SUFDN0IsdURBQXFDOzs7OztJQUV6Qix1Q0FBK0I7Ozs7O0lBQUUsNENBQTRCOzs7OztBQWtLN0UsMkNBR0M7OztJQUZHLHVDQUEyQjs7SUFDM0Isc0NBQWM7Ozs7O0FBTWxCO0lBQUE7SUFPQSxDQUFDOztnQkFQQSxRQUFRLFNBQUM7b0JBQ04sWUFBWSxFQUFFLENBQUMsdUJBQXVCLENBQUM7b0JBQ3ZDLE9BQU8sRUFBRSxDQUFDLHVCQUF1QixDQUFDO29CQUNsQyxPQUFPLEVBQUUsQ0FBQyxlQUFlLEVBQUUsWUFBWSxFQUFFLGVBQWUsRUFBRSxhQUFhLENBQUM7aUJBQzNFOztJQUdELDJCQUFDO0NBQUEsQUFQRCxJQU9DO1NBRFksb0JBQW9CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7XG4gICAgQWZ0ZXJWaWV3SW5pdCxcbiAgICBDb21wb25lbnQsXG4gICAgQ29udGVudENoaWxkcmVuLFxuICAgIENoYW5nZURldGVjdG9yUmVmLFxuICAgIEV2ZW50RW1pdHRlcixcbiAgICBIb3N0QmluZGluZyxcbiAgICBJbnB1dCxcbiAgICBOZ01vZHVsZSxcbiAgICBPdXRwdXQsXG4gICAgUXVlcnlMaXN0LFxuICAgIFJlbmRlcmVyMixcbiAgICBWaWV3Q2hpbGRyZW4sXG4gICAgT25EZXN0cm95XG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgSWd4QnV0dG9uRGlyZWN0aXZlLCBJZ3hCdXR0b25Nb2R1bGUgfSBmcm9tICcuLi9kaXJlY3RpdmVzL2J1dHRvbi9idXR0b24uZGlyZWN0aXZlJztcbmltcG9ydCB7IElneFJpcHBsZU1vZHVsZSB9IGZyb20gJy4uL2RpcmVjdGl2ZXMvcmlwcGxlL3JpcHBsZS5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgSWd4SWNvbk1vZHVsZSB9IGZyb20gJy4uL2ljb24vaW5kZXgnO1xuaW1wb3J0IHsgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5leHBvcnQgZW51bSBCdXR0b25Hcm91cEFsaWdubWVudCB7IGhvcml6b250YWwsIHZlcnRpY2FsIH1cbmxldCBORVhUX0lEID0gMDtcblxuLyoqXG4gKiAqKklnbml0ZSBVSSBmb3IgQW5ndWxhciBCdXR0b24gR3JvdXAqKiAtXG4gKiBbRG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly93d3cuaW5mcmFnaXN0aWNzLmNvbS9wcm9kdWN0cy9pZ25pdGUtdWktYW5ndWxhci9hbmd1bGFyL2NvbXBvbmVudHMvYnV0dG9uZ3JvdXAuaHRtbClcbiAqXG4gKiBUaGUgSWduaXRlIFVJIEJ1dHRvbiBHcm91cCBkaXNwbGF5cyBhIGdyb3VwIG9mIGJ1dHRvbnMgZWl0aGVyIHZlcnRpY2FsbHkgb3IgaG9yaXpvbnRhbGx5LiAgVGhlIGdyb3VwIHN1cHBvcnRzXG4gKiBzaW5nbGUsIG11bHRpcGxlIGFuZCB0b2dnbGUgc2VsZWN0aW9uLlxuICpcbiAqIEV4YW1wbGU6XG4gKiBgYGBodG1sXG4gKiA8aWd4LWJ1dHRvbmdyb3VwIG11bHRpU2VsZWN0aW9uPVwidHJ1ZVwiIFt2YWx1ZXNdPVwiZm9udE9wdGlvbnNcIj5cbiAqIDwvaWd4LWJ1dHRvbmdyb3VwPlxuICogYGBgXG4gKiBUaGUgYGZvbnRPcHRpb25zYCB2YWx1ZSBzaG93biBhYm92ZSBpcyBkZWZpbmVkIGFzOlxuICogYGBgdHlwZXNjcmlwdFxuICogdGhpcy5mb250T3B0aW9ucyA9IFtcbiAqICAgeyBpY29uOiAnZm9ybWF0X2JvbGQnLCBzZWxlY3RlZDogZmFsc2UgfSxcbiAqICAgeyBpY29uOiAnZm9ybWF0X2l0YWxpYycsIHNlbGVjdGVkOiBmYWxzZSB9LFxuICogICB7IGljb246ICdmb3JtYXRfdW5kZXJsaW5lZCcsIHNlbGVjdGVkOiBmYWxzZSB9XTtcbiAqIGBgYFxuICovXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogJ2lneC1idXR0b25ncm91cCcsXG4gICAgdGVtcGxhdGVVcmw6ICdidXR0b25ncm91cC1jb250ZW50LmNvbXBvbmVudC5odG1sJ1xufSlcblxuZXhwb3J0IGNsYXNzIElneEJ1dHRvbkdyb3VwQ29tcG9uZW50IGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcbiAgICBwcml2YXRlIF9kaXNhYmxlZCA9IGZhbHNlO1xuICAgIHByb3RlY3RlZCBidXR0b25DbGlja05vdGlmaWVyJCA9IG5ldyBTdWJqZWN0PGJvb2xlYW4+KCk7XG4gICAgcHJvdGVjdGVkIHF1ZXJ5TGlzdE5vdGlmaWVyJCA9IG5ldyBTdWJqZWN0PGJvb2xlYW4+KCk7XG5cbiAgICBAVmlld0NoaWxkcmVuKElneEJ1dHRvbkRpcmVjdGl2ZSkgcHJpdmF0ZSB2aWV3QnV0dG9uczogUXVlcnlMaXN0PElneEJ1dHRvbkRpcmVjdGl2ZT47XG4gICAgQENvbnRlbnRDaGlsZHJlbihJZ3hCdXR0b25EaXJlY3RpdmUpIHByaXZhdGUgdGVtcGxhdGVCdXR0b25zOiBRdWVyeUxpc3Q8SWd4QnV0dG9uRGlyZWN0aXZlPjtcblxuICAgIC8qKlxuICAgICAqIEEgY29sbGVjdGlvbiBjb250YWluaW5nIGFsbCBidXR0b25zIGluc2lkZSB0aGUgYnV0dG9uIGdyb3VwLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgYnV0dG9ucygpOiBJZ3hCdXR0b25EaXJlY3RpdmVbXSB7XG4gICAgICAgIHJldHVybiBbLi4udGhpcy52aWV3QnV0dG9ucy50b0FycmF5KCksIC4uLnRoaXMudGVtcGxhdGVCdXR0b25zLnRvQXJyYXkoKV07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQW4gQElucHV0IHByb3BlcnR5IHRoYXQgc2V0cyB0aGUgdmFsdWUgb2YgdGhlIGBpZGAgYXR0cmlidXRlLiBJZiBub3Qgc2V0IGl0IHdpbGwgYmUgYXV0b21hdGljYWxseSBnZW5lcmF0ZWQuXG4gICAgICogYGBgaHRtbFxuICAgICAqICA8aWd4LWJ1dHRvbmdyb3VwIFtpZF09XCInaWd4LWRpYWxvZy01NidcIiBbbXVsdGlTZWxlY3Rpb25dPVwiIW11bHRpXCIgW3ZhbHVlc109XCJhbGlnbk9wdGlvbnNcIj5cbiAgICAgKiBgYGBcbiAgICAgKi9cbiAgICBASG9zdEJpbmRpbmcoJ2F0dHIuaWQnKVxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIGlkID0gYGlneC1idXR0b25ncm91cC0ke05FWFRfSUQrK31gO1xuXG4gICAgLyoqXG4gICAgICogQWxsb3dzIHlvdSB0byBzZXQgYSBzdHlsZSB1c2luZyB0aGUgYGl0ZW1Db250ZW50Q3NzQ2xhc3NgIGlucHV0LlxuICAgICAqIFRoZSB2YWx1ZSBzaG91bGQgYmUgdGhlIENTUyBjbGFzcyBuYW1lIHRoYXQgd2lsbCBiZSBhcHBsaWVkIHRvIHRoZSBidXR0b24gZ3JvdXAuXG4gICAgICpgYGB0eXBlc2NyaXB0XG4gICAgICpwdWJsaWMgc3R5bGUxID0gXCJzdHlsZUNsYXNzXCI7XG4gICAgICogLy8uLlxuICAgICAqYGBgXG4gICAgICogYGBgaHRtbFxuICAgICAqPGlneC1idXR0b25ncm91cCBbaXRlbUNvbnRlbnRDc3NDbGFzc109XCJzdHlsZTFcIiBbbXVsdGlTZWxlY3Rpb25dPVwiIW11bHRpXCIgW3ZhbHVlc109XCJhbGlnbk9wdGlvbnNcIj5cbiAgICAgKmBgYFxuICAgICAqL1xuICAgIEBJbnB1dCgpIHNldCBpdGVtQ29udGVudENzc0NsYXNzKHZhbHVlOiBzdHJpbmcpIHtcbiAgICAgICAgdGhpcy5faXRlbUNvbnRlbnRDc3NDbGFzcyA9IHZhbHVlIHx8IHRoaXMuX2l0ZW1Db250ZW50Q3NzQ2xhc3M7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgQ1NTIGNsYXNzIG9mIHRoZSBpdGVtIGNvbnRlbnQgb2YgdGhlIGBJZ3hCdXR0b25Hcm91cGAuXG4gICAgICpgYGB0eXBlc2NyaXB0XG4gICAgICpAVmlld0NoaWxkKFwiTXlDaGlsZFwiKVxuICAgICAqcHVibGljIGJ1dHRvbkc6IElneEJ1dHRvbkdyb3VwQ29tcG9uZW50O1xuICAgICAqbmdBZnRlclZpZXdJbml0KCl7XG4gICAgICogICBsZXQgYnV0dG9uU2VsZWN0ID0gdGhpcy5idXR0b25HLml0ZW1Db250ZW50Q3NzQ2xhc3M7XG4gICAgICp9XG4gICAgICpgYGBcbiAgICAgKi9cbiAgICBnZXQgaXRlbUNvbnRlbnRDc3NDbGFzcygpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy5faXRlbUNvbnRlbnRDc3NDbGFzcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBbiBASW5wdXQgcHJvcGVydHkgdGhhdCBlbmFibGVzIHNlbGVjdGluZyBtdWx0aXBsZSBidXR0b25zLiBCeSBkZWZhdWx0LCBtdWx0aS1zZWxlY3Rpb24gaXMgZmFsc2UuXG4gICAgICogYGBgaHRtbFxuICAgICAqIDxpZ3gtYnV0dG9uZ3JvdXAgW211bHRpU2VsZWN0aW9uXT1cImZhbHNlXCIgW2FsaWdubWVudF09XCJhbGlnbm1lbnRcIj48L2lneC1idXR0b25ncm91cD5cbiAgICAgKiBgYGBcbiAgICAgKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgbXVsdGlTZWxlY3Rpb24gPSBmYWxzZTtcbiAgICAvKipcbiAgICAgKiBBbiBASW5wdXQgcHJvcGVydHkgdGhhdCBhbGxvd3Mgc2V0dGluZyB0aGUgYnV0dG9ucyBpbiB0aGUgYnV0dG9uIGdyb3VwLlxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiAgcHVibGljIG5nT25Jbml0KCkge1xuICAgICAqICAgICAgdGhpcy5jaXRpZXMgPSBbXG4gICAgICogICAgICAgIG5ldyBCdXR0b24oe1xuICAgICAqICAgICAgICAgIGxhYmVsOiBcIlNvZmlhXCJcbiAgICAgKiAgICAgIH0pLFxuICAgICAqICAgICAgICBuZXcgQnV0dG9uKHtcbiAgICAgKiAgICAgICAgICBsYWJlbDogXCJMb25kb25cIlxuICAgICAqICAgICAgfSksXG4gICAgICogICAgICAgIG5ldyBCdXR0b24oe1xuICAgICAqICAgICAgICAgIGxhYmVsOiBcIk5ldyBZb3JrXCIsXG4gICAgICogICAgICAgICAgc2VsZWN0ZWQ6IHRydWVcbiAgICAgKiAgICAgIH0pLFxuICAgICAqICAgICAgICBuZXcgQnV0dG9uKHtcbiAgICAgKiAgICAgICAgICBsYWJlbDogXCJUb2t5b1wiXG4gICAgICogICAgICB9KVxuICAgICAqICBdO1xuICAgICAqICB9XG4gICAgICogIC8vLi5cbiAgICAgKiBgYGBcbiAgICAgKiBgYGBodG1sXG4gICAgICogIDxpZ3gtYnV0dG9uZ3JvdXAgW211bHRpU2VsZWN0aW9uXT1cImZhbHNlXCIgW3ZhbHVlc109XCJjaXRpZXNcIj48L2lneC1idXR0b25ncm91cD5cbiAgICAgKiBgYGBcbiAgICAgKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgdmFsdWVzOiBhbnk7XG4gICAgLyoqXG4gICAgICogQW4gQElucHV0IHByb3BlcnR5IHRoYXQgYWxsb3dzIHlvdSB0byBkaXNhYmxlIHRoZSBgaWd4LWJ1dHRvbmdyb3VwYCBjb21wb25lbnQuIEJ5IGRlZmF1bHQgaXQncyBmYWxzZS5cbiAgICAgKiBgYGBodG1sXG4gICAgICogPGlneC1idXR0b25ncm91cCBbZGlzYWJsZWRdPVwidHJ1ZVwiIFttdWx0aVNlbGVjdGlvbl09XCJtdWx0aVwiIFt2YWx1ZXNdPVwiZm9udE9wdGlvbnNcIj48L2lneC1idXR0b25ncm91cD5cbiAgICAgKiBgYGBcbiAgICAgKi9cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBnZXQgZGlzYWJsZWQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLl9kaXNhYmxlZDtcbiAgICB9XG4gICAgcHVibGljIHNldCBkaXNhYmxlZCh2YWx1ZTogYm9vbGVhbikge1xuICAgICAgICBpZiAodGhpcy5fZGlzYWJsZWQgIT09IHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLl9kaXNhYmxlZCA9IHZhbHVlO1xuXG4gICAgICAgICAgICBpZiAodGhpcy52aWV3QnV0dG9ucyAmJiB0aGlzLnRlbXBsYXRlQnV0dG9ucykge1xuICAgICAgICAgICAgICAgIHRoaXMuYnV0dG9ucy5mb3JFYWNoKChiKSA9PiBiLmRpc2FibGVkID0gdGhpcy5fZGlzYWJsZWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQGhpZGRlblxuICAgICAqL1xuICAgIHB1YmxpYyBzZWxlY3RlZEluZGV4ZXM6IG51bWJlcltdID0gW107XG5cbiAgICAvKipcbiAgICAgKiBBbGxvd3MgeW91IHRvIHNldCB0aGUgYnV0dG9uIGdyb3VwIGFsaWdubWVudC5cbiAgICAgKiBBdmFpbGFibGUgb3B0aW9ucyBhcmUgYEJ1dHRvbkdyb3VwQWxpZ25tZW50Lmhvcml6b250YWxgIChkZWZhdWx0KSBhbmQgYEJ1dHRvbkdyb3VwQWxpZ25tZW50LnZlcnRpY2FsYC5cbiAgICAgKiBgYGB0eXBlc2NyaXB0XG4gICAgICpwdWJsaWMgYWxpZ25tZW50ID0gQnV0dG9uR3JvdXBBbGlnbm1lbnQudmVydGljYWw7XG4gICAgICogLy8uLlxuICAgICAqIGBgYFxuICAgICAqIGBgYGh0bWxcbiAgICAgKjxpZ3gtYnV0dG9uZ3JvdXAgW211bHRpU2VsZWN0aW9uXT1cImZhbHNlXCIgW3ZhbHVlc109XCJjaXRpZXNcIiBbYWxpZ25tZW50XT1cImFsaWdubWVudFwiPjwvaWd4LWJ1dHRvbmdyb3VwPlxuICAgICAqIGBgYFxuICAgICAqL1xuICAgIEBJbnB1dCgpIHNldCBhbGlnbm1lbnQodmFsdWU6IEJ1dHRvbkdyb3VwQWxpZ25tZW50KSB7XG4gICAgICAgIHRoaXMuX2lzVmVydGljYWwgPSB2YWx1ZSA9PT0gQnV0dG9uR3JvdXBBbGlnbm1lbnQudmVydGljYWw7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGFsaWdubWVudCBvZiB0aGUgYGlneC1idXR0b25ncm91cGAuXG4gICAgICpgYGB0eXBlc2NyaXB0XG4gICAgICpAVmlld0NoaWxkKFwiTXlDaGlsZFwiKVxuICAgICAqcHVibGljIGJ1dHRvbkc6IElneEJ1dHRvbkdyb3VwQ29tcG9uZW50O1xuICAgICAqbmdBZnRlclZpZXdJbml0KCl7XG4gICAgICogICAgbGV0IGJ1dHRvbkFsaWdubWVudCA9IHRoaXMuYnV0dG9uRy5hbGlnbm1lbnQ7XG4gICAgICp9XG4gICAgICpgYGBcbiAgICAgKi9cbiAgICBnZXQgYWxpZ25tZW50KCk6IEJ1dHRvbkdyb3VwQWxpZ25tZW50IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2lzVmVydGljYWwgPyBCdXR0b25Hcm91cEFsaWdubWVudC52ZXJ0aWNhbCA6IEJ1dHRvbkdyb3VwQWxpZ25tZW50Lmhvcml6b250YWw7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQW4gQE91cHV0IHByb3BlcnR5IHRoYXQgZW1pdHMgYW4gZXZlbnQgd2hlbiBhIGJ1dHRvbiBpcyBzZWxlY3RlZC5cbiAgICAgKmBgYHR5cGVzY3JpcHRcbiAgICAgKkBWaWV3Q2hpbGQoXCJ0b2FzdFwiKVxuICAgICAqcHJpdmF0ZSB0b2FzdDogSWd4VG9hc3RDb21wb25lbnQ7XG4gICAgICpwdWJsaWMgb25TZWxlY3QoYnV0dG9uZ3JvdXApe1xuICAgICAqICAgIHRoaXMudG9hc3Quc2hvdygpXG4gICAgICp9XG4gICAgICogLy8uLi5cbiAgICAgKmBgYFxuICAgICAqYGBgaHRtbFxuICAgICAqIDxpZ3gtYnV0dG9uZ3JvdXAgI015Q2hpbGQgW211bHRpU2VsZWN0aW9uXT1cIiFtdWx0aVwiIChvblNlbGVjdCk9XCJvblNlbGVjdCgkZXZlbnQpXCI+PC9pZ3gtYnV0dG9uZ3JvdXA+XG4gICAgICo8aWd4LXRvYXN0ICN0b2FzdCBtZXNzYWdlPVwiWW91IGhhdmUgbWFkZSBhIHNlbGVjdGlvbiFcIj48L2lneC10b2FzdD5cbiAgICAgKmBgYFxuICAgICAqL1xuICAgIEBPdXRwdXQoKSBwdWJsaWMgb25TZWxlY3QgPSBuZXcgRXZlbnRFbWl0dGVyPElCdXR0b25Hcm91cEV2ZW50QXJncz4oKTtcblxuICAgIC8qKlxuICAgICAqIEFuIEBPdXB1dCBwcm9wZXJ0eSB0aGF0IGVtaXRzIGFuIGV2ZW50IHdoZW4gYSBidXR0b24gaXMgZGVzZWxlY3RlZC5cbiAgICAgKmBgYHR5cGVzY3JpcHRcbiAgICAgKkBWaWV3Q2hpbGQoXCJ0b2FzdFwiKVxuICAgICAqcHJpdmF0ZSB0b2FzdDogSWd4VG9hc3RDb21wb25lbnQ7XG4gICAgICpwdWJsaWMgb25VbnNlbGVjdChidXR0b25ncm91cCl7XG4gICAgICogICAgdGhpcy50b2FzdC5zaG93KClcbiAgICAgKn1cbiAgICAgKiAvLy4uLlxuICAgICAqYGBgXG4gICAgICpgYGBodG1sXG4gICAgICogaWd4LWJ1dHRvbmdyb3VwICNNeUNoaWxkIFttdWx0aVNlbGVjdGlvbl09XCJtdWx0aVwiIChvblVuc2VsZWN0KT1cIm9uVW5zZWxlY3QoJGV2ZW50KVwiPjwvaWd4LWJ1dHRvbmdyb3VwPlxuICAgICAqPGlneC10b2FzdCAjdG9hc3QgbWVzc2FnZT1cIllvdSBoYXZlIGRlc2VsZWN0ZWQgYSBidXR0b24hXCI+PC9pZ3gtdG9hc3Q+XG4gICAgICpgYGBcbiAgICAgKi9cbiAgICBAT3V0cHV0KCkgcHVibGljIG9uVW5zZWxlY3QgPSBuZXcgRXZlbnRFbWl0dGVyPElCdXR0b25Hcm91cEV2ZW50QXJncz4oKTtcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgYGlneC1idXR0b25ncm91cGAgYWxpZ25tZW50IGlzIHZlcnRpY2FsLlxuICAgICAqIE5vdGUgdGhhdCBpbiBvcmRlciBmb3IgdGhlIGFjY2Vzc29yIHRvIHdvcmsgY29ycmVjdGx5IHRoZSBwcm9wZXJ0eSBzaG91bGQgYmUgc2V0IGV4cGxpY2l0bHkuXG4gICAgICogYGBgaHRtbFxuICAgICAqIDxpZ3gtYnV0dG9uZ3JvdXAgI015Q2hpbGQgW2FsaWdubWVudF09XCJhbGlnbm1lbnRcIiBbdmFsdWVzXT1cImFsaWduT3B0aW9uc1wiPlxuICAgICAqIGBgYFxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiAvLy4uLlxuICAgICAqQFZpZXdDaGlsZChcIk15Q2hpbGRcIilcbiAgICAgKnByaXZhdGUgYnV0dG9uRzogSWd4QnV0dG9uR3JvdXBDb21wb25lbnQ7XG4gICAgICpuZ0FmdGVyVmlld0luaXQoKXtcbiAgICAgKiAgICBsZXQgb3JpZW50YXRpb24gPSB0aGlzLmJ1dHRvbkcuaXNWZXJ0aWNhbDtcbiAgICAgKn1cbiAgICAgKmBgYFxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgaXNWZXJ0aWNhbCgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2lzVmVydGljYWw7XG4gICAgfVxuICAgIHByaXZhdGUgX2lzVmVydGljYWw6IGJvb2xlYW47XG4gICAgcHJpdmF0ZSBfaXRlbUNvbnRlbnRDc3NDbGFzczogc3RyaW5nO1xuXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBfY2RyOiBDaGFuZ2VEZXRlY3RvclJlZiwgcHJpdmF0ZSBfcmVuZGVyZXI6IFJlbmRlcmVyMikge1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIHNlbGVjdGVkIGJ1dHRvbi9idXR0b25zLlxuICAgICAqYGBgdHlwZXNjcmlwdFxuICAgICAqQFZpZXdDaGlsZChcIk15Q2hpbGRcIilcbiAgICAgKnByaXZhdGUgYnV0dG9uRzogSWd4QnV0dG9uR3JvdXBDb21wb25lbnQ7XG4gICAgICpuZ0FmdGVyVmlld0luaXQoKXtcbiAgICAgKiAgICBsZXQgc2VsZWN0ZWRCdXR0b24gPSB0aGlzLmJ1dHRvbkcuc2VsZWN0ZWRCdXR0b25zO1xuICAgICAqfVxuICAgICAqYGBgXG4gICAgICovXG4gICAgZ2V0IHNlbGVjdGVkQnV0dG9ucygpOiBJZ3hCdXR0b25EaXJlY3RpdmVbXSB7XG4gICAgICAgIHJldHVybiB0aGlzLmJ1dHRvbnMuZmlsdGVyKChiLCBpKSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zZWxlY3RlZEluZGV4ZXMuaW5kZXhPZihpKSAhPT0gLTE7XG4gICAgICAgIH0pO1xuXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VsZWN0cyBhIGJ1dHRvbiBieSBpdHMgaW5kZXguXG4gICAgICogQG1lbWJlck9mIHtAbGluayBJZ3hCdXR0b25Hcm91cENvbXBvbmVudH1cbiAgICAgKmBgYHR5cGVzY3JpcHRcbiAgICAgKkBWaWV3Q2hpbGQoXCJNeUNoaWxkXCIpXG4gICAgICpwcml2YXRlIGJ1dHRvbkc6IElneEJ1dHRvbkdyb3VwQ29tcG9uZW50O1xuICAgICAqbmdBZnRlclZpZXdJbml0KCl7XG4gICAgICogICAgdGhpcy5idXR0b25HLnNlbGVjdEJ1dHRvbigyKTtcbiAgICAgKiAgICB0aGlzLmNkci5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICp9XG4gICAgICpgYGBcbiAgICAgKi9cbiAgICBwdWJsaWMgc2VsZWN0QnV0dG9uKGluZGV4OiBudW1iZXIpIHtcbiAgICAgICAgaWYgKGluZGV4ID49IHRoaXMuYnV0dG9ucy5sZW5ndGggfHwgaW5kZXggPCAwKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBidXR0b24gPSB0aGlzLmJ1dHRvbnNbaW5kZXhdO1xuICAgICAgICBjb25zdCBidXR0b25FbGVtZW50ID0gYnV0dG9uLm5hdGl2ZUVsZW1lbnQ7XG5cbiAgICAgICAgaWYgKGJ1dHRvbkVsZW1lbnQuY2xhc3NMaXN0LmNvbnRhaW5zKCdpZ3gtYnV0dG9uLS1kaXNhYmxlZCcpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNlbGVjdGVkSW5kZXhlcy5wdXNoKGluZGV4KTtcbiAgICAgICAgYnV0dG9uLnNlbGVjdGVkID0gdHJ1ZTtcblxuICAgICAgICB0aGlzLl9yZW5kZXJlci5zZXRBdHRyaWJ1dGUoYnV0dG9uRWxlbWVudCwgJ2FyaWEtcHJlc3NlZCcsICd0cnVlJyk7XG4gICAgICAgIHRoaXMuX3JlbmRlcmVyLmFkZENsYXNzKGJ1dHRvbkVsZW1lbnQsICdpZ3gtYnV0dG9uLWdyb3VwX19pdGVtLS1zZWxlY3RlZCcpO1xuXG4gICAgICAgIHRoaXMub25TZWxlY3QuZW1pdCh7IGJ1dHRvbjogYnV0dG9uLCBpbmRleDogaW5kZXggfSk7XG5cbiAgICAgICAgY29uc3QgaW5kZXhJblZpZXdCdXR0b25zID0gdGhpcy52aWV3QnV0dG9ucy50b0FycmF5KCkuaW5kZXhPZihidXR0b24pO1xuICAgICAgICBpZiAoaW5kZXhJblZpZXdCdXR0b25zICE9PSAtMSkge1xuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaW5kZXhJblZpZXdCdXR0b25zXS5zZWxlY3RlZCA9IHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkZXNlbGVjdCBvdGhlciBidXR0b25zIGlmIG11bHRpU2VsZWN0aW9uIGlzIG5vdCBlbmFibGVkXG4gICAgICAgIGlmICghdGhpcy5tdWx0aVNlbGVjdGlvbiAmJiB0aGlzLnNlbGVjdGVkSW5kZXhlcy5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICB0aGlzLmJ1dHRvbnMuZm9yRWFjaCgoYiwgaSkgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChpICE9PSBpbmRleCAmJiB0aGlzLnNlbGVjdGVkSW5kZXhlcy5pbmRleE9mKGkpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmRlc2VsZWN0QnV0dG9uKGkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRGVzZWxlY3RzIGEgYnV0dG9uIGJ5IGl0cyBpbmRleC5cbiAgICAgKiBAbWVtYmVyT2Yge0BsaW5rIElneEJ1dHRvbkdyb3VwQ29tcG9uZW50fVxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKkBWaWV3Q2hpbGQoXCJNeUNoaWxkXCIpXG4gICAgICpwcml2YXRlIGJ1dHRvbkc6IElneEJ1dHRvbkdyb3VwQ29tcG9uZW50O1xuICAgICAqbmdBZnRlclZpZXdJbml0KCl7XG4gICAgICogICAgdGhpcy5idXR0b25HLmRlc2VsZWN0QnV0dG9uKDIpO1xuICAgICAqICAgIHRoaXMuY2RyLmRldGVjdENoYW5nZXMoKTtcbiAgICAgKn1cbiAgICAgKiBgYGBcbiAgICAgKi9cbiAgICBwdWJsaWMgZGVzZWxlY3RCdXR0b24oaW5kZXg6IG51bWJlcikge1xuICAgICAgICBpZiAoaW5kZXggPj0gdGhpcy5idXR0b25zLmxlbmd0aCB8fCBpbmRleCA8IDApIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGJ1dHRvbiA9IHRoaXMuYnV0dG9uc1tpbmRleF07XG4gICAgICAgIGNvbnN0IGJ1dHRvbkVsZW1lbnQgPSBidXR0b24ubmF0aXZlRWxlbWVudDtcblxuICAgICAgICBpZiAoYnV0dG9uRWxlbWVudC5jbGFzc0xpc3QuY29udGFpbnMoJ2lneC1idXR0b24tLWRpc2FibGVkJykpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2VsZWN0ZWRJbmRleGVzLnNwbGljZSh0aGlzLnNlbGVjdGVkSW5kZXhlcy5pbmRleE9mKGluZGV4KSwgMSk7XG4gICAgICAgIGJ1dHRvbi5zZWxlY3RlZCA9IGZhbHNlO1xuXG4gICAgICAgIHRoaXMuX3JlbmRlcmVyLnNldEF0dHJpYnV0ZShidXR0b25FbGVtZW50LCAnYXJpYS1wcmVzc2VkJywgJ2ZhbHNlJyk7XG4gICAgICAgIHRoaXMuX3JlbmRlcmVyLnJlbW92ZUNsYXNzKGJ1dHRvbkVsZW1lbnQsICdpZ3gtYnV0dG9uLWdyb3VwX19pdGVtLS1zZWxlY3RlZCcpO1xuXG4gICAgICAgIHRoaXMub25VbnNlbGVjdC5lbWl0KHsgYnV0dG9uOiBidXR0b24sIGluZGV4OiBpbmRleCB9KTtcblxuICAgICAgICBjb25zdCBpbmRleEluVmlld0J1dHRvbnMgPSB0aGlzLnZpZXdCdXR0b25zLnRvQXJyYXkoKS5pbmRleE9mKGJ1dHRvbik7XG4gICAgICAgIGlmIChpbmRleEluVmlld0J1dHRvbnMgIT09IC0xKSB7XG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpbmRleEluVmlld0J1dHRvbnNdLnNlbGVjdGVkID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAaGlkZGVuXG4gICAgICovXG4gICAgcHVibGljIG5nQWZ0ZXJWaWV3SW5pdCgpIHtcbiAgICAgICAgY29uc3QgaW5pdEJ1dHRvbnMgPSAoKSA9PiB7XG4gICAgICAgICAgICAvLyBDYW5jZWwgYW55IGV4aXN0aW5nIGJ1dHRvbkNsaWNrIHN1YnNjcmlwdGlvbnNcbiAgICAgICAgICAgIHRoaXMuYnV0dG9uQ2xpY2tOb3RpZmllciQubmV4dCgpO1xuXG4gICAgICAgICAgICB0aGlzLnNlbGVjdGVkSW5kZXhlcy5zcGxpY2UoMCwgdGhpcy5zZWxlY3RlZEluZGV4ZXMubGVuZ3RoKTtcblxuICAgICAgICAgICAgLy8gaW5pdGlhbCBjb25maWd1cmF0aW9uXG4gICAgICAgICAgICB0aGlzLmJ1dHRvbnMuZm9yRWFjaCgoYnV0dG9uLCBpbmRleCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IGJ1dHRvbkVsZW1lbnQgPSBidXR0b24ubmF0aXZlRWxlbWVudDtcblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmRpc2FibGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIGJ1dHRvbi5kaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKCFidXR0b24uZGlzYWJsZWQgJiYgYnV0dG9uLnNlbGVjdGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2VsZWN0QnV0dG9uKGluZGV4KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBidXR0b24uYnV0dG9uQ2xpY2sucGlwZSh0YWtlVW50aWwodGhpcy5idXR0b25DbGlja05vdGlmaWVyJCkpLnN1Y