igniteui-angular
Version:
Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps
664 lines • 45.4 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { CommonModule } from '@angular/common';
import { Component, ContentChild, ContentChildren, Directive, ElementRef, EventEmitter, forwardRef, HostBinding, HostListener, Input, NgModule, Output, QueryList, TemplateRef, ViewChildren } from '@angular/core';
import { IgxBadgeModule } from '../badge/badge.component';
import { IgxIconModule } from '../icon/index';
/**
* @record
*/
export function ISelectTabEventArgs() { }
if (false) {
/** @type {?} */
ISelectTabEventArgs.prototype.tab;
/** @type {?} */
ISelectTabEventArgs.prototype.panel;
}
/** @type {?} */
let NEXT_ID = 0;
export class IgxTabTemplateDirective {
/**
* @param {?} template
*/
constructor(template) {
this.template = template;
}
}
IgxTabTemplateDirective.decorators = [
{ type: Directive, args: [{
selector: '[igxTab]'
},] }
];
/** @nocollapse */
IgxTabTemplateDirective.ctorParameters = () => [
{ type: TemplateRef }
];
if (false) {
/** @type {?} */
IgxTabTemplateDirective.prototype.template;
}
/**
* **Ignite UI for Angular Tab Bar** -
* [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tabbar.html)
*
* The Ignite UI Tab Bar enables the user to navigate among a number of content panels displayed in a single view.
*
* Example:
* ```html
* <igx-bottom-nav>
* <igx-tab-panel label="Tab 1">Tab 1 Content</igx-tab-panel>
* <igx-tab-panel label="Tab 2">Tab 2 Content</igx-tab-panel>
* <igx-tab-panel label="Tab 3">Tab 3 Content</igx-tab-panel>
* </igx-bottom-nav>
* ```
*/
export class IgxBottomNavComponent {
/**
* @param {?} _element
*/
constructor(_element) {
this._element = _element;
/**
* Sets/gets the `id` of the tab bar.
* If not set, the `id` of the first tab bar component will be `"igx-bottom-nav-0"`.
* ```html
* <igx-bottom-nav id = "my-first-tab-bar"></igx-bottom-nav>
* ```
* ```typescript
* let tabBarId = this.tabBar.id;
* ```
* \@memberof IgxBottomNavComponent
*/
this.id = `igx-bottom-nav-${NEXT_ID++}`;
/**
* Emits an event when a new tab is selected.
* Provides references to the `IgxTabComponent` and `IgxTabPanelComponent` as event arguments.
* ```html
* <igx-bottom-nav (onTableSelected) = "onTabSelected($event)"><igx-bottom-nav>
* ```
* \@memberof IgxBottomNavComponent
*/
this.onTabSelected = new EventEmitter();
/**
* Emits an event when a tab is deselected.
* Provides references to the `IgxTabComponent` and `IgxTabPanelComponent` as event arguments.
* ```html
* <igx-bottom-nav (onTabDeselected) = "onTabDeselected($event)"><igx-bottom-nav>
* ```
* \@memberof IgxBottomNavComponent
*/
this.onTabDeselected = new EventEmitter();
/**
* Gets the `index` of selected tab/panel in the respective collection.
* ```typescript
* let index = this.tabBar.selectedIndex;
* ```
* \@memberof IgxBottomNavComponent
*/
this.selectedIndex = -1;
/**
* @hidden
*/
this._itemStyle = 'igx-bottom-nav';
}
/**
* Gets the `itemStyle` of the tab bar.
* ```typescript
* let itemStyle = this.tabBar.itemStyle;
* ```
* \@memberof IgxBottomNavComponent
* @return {?}
*/
get itemStyle() {
return this._itemStyle;
}
/**
* Gets the selected tab in the tab bar.
* ```typescript
* let tab = this.tabBar.selectedTab;
* ```
* \@memberof IgxBottomNavComponent
* @return {?}
*/
get selectedTab() {
if (this.tabs && this.selectedIndex !== undefined) {
return this.tabs.toArray()[this.selectedIndex];
}
}
/**
* @hidden
* @return {?}
*/
ngAfterViewInit() {
// initial selection
setTimeout(() => {
if (this.selectedIndex === -1) {
/** @type {?} */
const selectablePanels = this.panels.filter((p) => !p.disabled);
/** @type {?} */
const panel = selectablePanels[0];
if (panel) {
panel.select();
}
}
}, 0);
}
/**
* @hidden
* @param {?} args
* @return {?}
*/
_selectedPanelHandler(args) {
this.selectedIndex = args.panel.index;
this.panels.forEach((p) => {
if (p.index !== this.selectedIndex) {
this._deselectPanel(p);
}
});
}
/**
* @hidden
* @private
* @param {?} panel
* @return {?}
*/
_deselectPanel(panel) {
// Cannot deselect the selected tab - this will mean that there will be not selected tab left
if (panel.disabled || this.selectedTab.index === panel.index) {
return;
}
panel.isSelected = false;
this.onTabDeselected.emit({ tab: this.tabs[panel.index], panel });
}
}
IgxBottomNavComponent.decorators = [
{ type: Component, args: [{
selector: 'igx-bottom-nav',
template: "<div>\n <ng-content></ng-content>\n</div>\n<div #tablist class=\"{{itemStyle}}__menu {{itemStyle}}__menu--bottom\" role=\"tablist\" aria-orientation=\"horizontal\">\n <igx-tab *ngFor=\"let panel of panels\" [id]=\"'igx-tab-' + panel.index\" [attr.aria-label]=\"panel.label\" [attr.aria-disabled]=\"panel.disabled\"\n [attr.aria-selected]=\"panel.isSelected\" [attr.aria-controls]=\"'igx-tab-panel-'+ panel.index\" [ngClass]=\"{\n 'igx-bottom-nav__menu-item': !panel.isSelected && !panel.disabled,\n 'igx-bottom-nav__menu-item--selected': panel.isSelected,\n 'igx-bottom-nav__menu-item--disabled': panel.disabled\n }\" [relatedPanel]=\"panel\" (click)=\"panel.select()\" role=\"tab\">\n </igx-tab>\n</div>\n",
styles: [`
:host {
display: block;
}
`]
}] }
];
/** @nocollapse */
IgxBottomNavComponent.ctorParameters = () => [
{ type: ElementRef }
];
IgxBottomNavComponent.propDecorators = {
tabs: [{ type: ViewChildren, args: [forwardRef(() => IgxTabComponent),] }],
panels: [{ type: ContentChildren, args: [forwardRef(() => IgxTabPanelComponent),] }],
id: [{ type: HostBinding, args: ['attr.id',] }, { type: Input }],
onTabSelected: [{ type: Output }],
onTabDeselected: [{ type: Output }],
_selectedPanelHandler: [{ type: HostListener, args: ['onTabSelected', ['$event'],] }]
};
if (false) {
/**
* Gets the `IgxTabComponent` elements in the tab bar component.
* ```typescript
* let tabs: QueryList<IgxTabComponent> = this.tabBar.tabs;
* ```
* \@memberof IgxBottomNavComponent
* @type {?}
*/
IgxBottomNavComponent.prototype.tabs;
/**
* Gets the `IgxTabPanelComponent` elements in the tab bar component.
* ```typescript
* let tabPanels: QueryList<IgxTabPanelComponent> = this.tabBar.panels;
* ```
* \@memberof IgxBottomNavComponent
* @type {?}
*/
IgxBottomNavComponent.prototype.panels;
/**
* Sets/gets the `id` of the tab bar.
* If not set, the `id` of the first tab bar component will be `"igx-bottom-nav-0"`.
* ```html
* <igx-bottom-nav id = "my-first-tab-bar"></igx-bottom-nav>
* ```
* ```typescript
* let tabBarId = this.tabBar.id;
* ```
* \@memberof IgxBottomNavComponent
* @type {?}
*/
IgxBottomNavComponent.prototype.id;
/**
* Emits an event when a new tab is selected.
* Provides references to the `IgxTabComponent` and `IgxTabPanelComponent` as event arguments.
* ```html
* <igx-bottom-nav (onTableSelected) = "onTabSelected($event)"><igx-bottom-nav>
* ```
* \@memberof IgxBottomNavComponent
* @type {?}
*/
IgxBottomNavComponent.prototype.onTabSelected;
/**
* Emits an event when a tab is deselected.
* Provides references to the `IgxTabComponent` and `IgxTabPanelComponent` as event arguments.
* ```html
* <igx-bottom-nav (onTabDeselected) = "onTabDeselected($event)"><igx-bottom-nav>
* ```
* \@memberof IgxBottomNavComponent
* @type {?}
*/
IgxBottomNavComponent.prototype.onTabDeselected;
/**
* Gets the `index` of selected tab/panel in the respective collection.
* ```typescript
* let index = this.tabBar.selectedIndex;
* ```
* \@memberof IgxBottomNavComponent
* @type {?}
*/
IgxBottomNavComponent.prototype.selectedIndex;
/**
* @hidden
* @type {?}
* @private
*/
IgxBottomNavComponent.prototype._itemStyle;
/**
* @type {?}
* @private
*/
IgxBottomNavComponent.prototype._element;
}
// ================================= IgxTabPanelComponent ======================================
export class IgxTabPanelComponent {
/**
* @param {?} _tabBar
* @param {?} _element
*/
constructor(_tabBar, _element) {
this._tabBar = _tabBar;
this._element = _element;
/**
* @hidden
*/
this._itemStyle = 'igx-tab-panel';
/**
* Gets the role of the tab panel.
* ```typescript
* let tabPanelRole = this.tabPanel.role;
* ```
* \@memberof IgxTabPanelComponent
*/
this.role = 'tabpanel';
/**
* Sets/gets whether a tab panel is selected.
* ```typescript
* this.tabPanel.isSelected = true;
* ```
* ```typescript
* let isSelected = this.tabPanelIsSelected;
* ```
* \@memberof IgxTabPanelComponent
*/
this.isSelected = false;
}
/**
* Gets whether a tab panel will have `igx-bottom-nav__panel` class.
* ```typescript
* let styleClass = this.tabPanel.styleClass;
* ```
* \@memberof IgxTabPanelComponent
* @return {?}
*/
get styleClass() {
return (!this.isSelected);
}
/**
* Gets the `itemStyle` of the tab panel.
* ```typescript
* let itemStyle = this.tabPanel.itemStyle;
* ```
* \@memberof IgxTabPanelComponent
* @return {?}
*/
get itemStyle() {
return this._itemStyle;
}
/**
* Gets the tab associated with the panel.
* ```typescript
* let tab = this.tabPanel.relatedTab;
* ```
* \@memberof IgxTabPanelComponent
* @return {?}
*/
get relatedTab() {
if (this._tabBar.tabs) {
return this._tabBar.tabs.toArray()[this.index];
}
}
/**
* Gets the index of a panel in the panels collection.
* ```typescript
* let panelIndex = this.tabPanel.index
* ```
* \@memberof IgxTabPanelComponent
* @return {?}
*/
get index() {
if (this._tabBar.panels) {
return this._tabBar.panels.toArray().indexOf(this);
}
}
/**
* Gets the tab template.
* ```typescript
* let tabTemplate = this.tabPanel.customTabTemplate
* ```
* \@memberof IgxTabPanelComponent
* @return {?}
*/
get customTabTemplate() {
return this._tabTemplate;
}
/**
* Sets the tab template.
* ```typescript
* this.tabPanel.customTabTemplate(tabTemplate);
* ```
* \@memberof IgxTabPanelComponent
* @param {?} template
* @return {?}
*/
set customTabTemplate(template) {
this._tabTemplate = template;
}
/**
* @hidden
* @return {?}
*/
ngAfterContentInit() {
if (this.tabTemplate) {
this._tabTemplate = this.tabTemplate.template;
}
}
/**
* @hidden
* @return {?}
*/
ngAfterViewChecked() {
this._element.nativeElement.setAttribute('aria-labelledby', `igx-tab-${this.index}`);
this._element.nativeElement.setAttribute('id', `igx-bottom-nav__panel-${this.index}`);
}
/**
* Selects the current tab and the tab panel.
* ```typescript
* this.tabPanel.select();
* ```
* \@memberof IgxTabPanelComponent
* @return {?}
*/
select() {
if (this.disabled || this._tabBar.selectedIndex === this.index) {
return;
}
this.isSelected = true;
this._tabBar.onTabSelected.emit({ tab: this._tabBar.tabs.toArray()[this.index], panel: this });
}
}
IgxTabPanelComponent.decorators = [
{ type: Component, args: [{
selector: 'igx-tab-panel',
template: "<ng-content></ng-content>\n"
}] }
];
/** @nocollapse */
IgxTabPanelComponent.ctorParameters = () => [
{ type: IgxBottomNavComponent },
{ type: ElementRef }
];
IgxTabPanelComponent.propDecorators = {
label: [{ type: Input }],
icon: [{ type: Input }],
disabled: [{ type: Input }],
role: [{ type: HostBinding, args: ['attr.role',] }],
styleClass: [{ type: HostBinding, args: ['class.igx-bottom-nav__panel',] }],
isSelected: [{ type: HostBinding, args: ['class.igx-bottom-nav__panel--selected',] }],
tabTemplate: [{ type: ContentChild, args: [IgxTabTemplateDirective, { read: IgxTabTemplateDirective },] }]
};
if (false) {
/**
* @hidden
* @type {?}
* @private
*/
IgxTabPanelComponent.prototype._itemStyle;
/**
* Sets/gets the `label` of the tab panel.
* ```html
* <igx-tab-panel [label] = "'Tab panel label'"><igx-tab-panel>
* ```
* ```typescript
* let tabPanelLabel = this.tabPanel.label;
* ```
* \@memberof IgxTabPanelComponent
* @type {?}
*/
IgxTabPanelComponent.prototype.label;
/**
* Sets/gets the `icon` of the tab panel.
* ```html
* <igx-tab-panel [icon] = "panel_icon"><igx-tab-panel>
* ```
* ```typescript
* let tabPanelIcon = this.tabPanel.icon;
* ```
* \@memberof IgxTabPanelComponent
* @type {?}
*/
IgxTabPanelComponent.prototype.icon;
/**
* Sets/gets whether the tab panel is disabled.
* ```html
* <igx-tab-panel [disabled] = "true"><igx-tab-panel>
* ```
* ```typescript
* let isDisabled = this.tabPanel.disabled;
* ```
* \@memberof IgxTabPanelComponent
* @type {?}
*/
IgxTabPanelComponent.prototype.disabled;
/**
* Gets the role of the tab panel.
* ```typescript
* let tabPanelRole = this.tabPanel.role;
* ```
* \@memberof IgxTabPanelComponent
* @type {?}
*/
IgxTabPanelComponent.prototype.role;
/**
* Sets/gets whether a tab panel is selected.
* ```typescript
* this.tabPanel.isSelected = true;
* ```
* ```typescript
* let isSelected = this.tabPanelIsSelected;
* ```
* \@memberof IgxTabPanelComponent
* @type {?}
*/
IgxTabPanelComponent.prototype.isSelected;
/**
* @hidden
* @type {?}
* @private
*/
IgxTabPanelComponent.prototype._tabTemplate;
/**
* @hidden
* @type {?}
* @protected
*/
IgxTabPanelComponent.prototype.tabTemplate;
/**
* @type {?}
* @private
*/
IgxTabPanelComponent.prototype._tabBar;
/**
* @type {?}
* @private
*/
IgxTabPanelComponent.prototype._element;
}
// ======================================= IgxTabComponent ==========================================
export class IgxTabComponent {
/**
* @param {?} _tabBar
* @param {?} _element
*/
constructor(_tabBar, _element) {
this._tabBar = _tabBar;
this._element = _element;
/**
* Gets the `role` attribute.
* ```typescript
* let tabRole = this.tab.role;
* ```
* \@memberof IgxTabComponent
*/
this.role = 'tab';
/**
* @hidden
*/
this._changesCount = 0; // changes and updates accordingly applied to the tab.
}
// changes and updates accordingly applied to the tab.
/**
* Gets the changes and updates accordingly applied to the tab.
*
* \@memberof IgxTabComponent
* @return {?}
*/
get changesCount() {
return this._changesCount;
}
/**
* Gets whether the tab is disabled.
* ```typescript
* let isDisabled = this.tab.disabled;
* ```
* \@memberof IgxTabComponent
* @return {?}
*/
get disabled() {
/** @type {?} */
const panel = this.relatedPanel;
if (panel) {
return panel.disabled;
}
}
/**
* Gets whether the tab is selected.
* ```typescript
* let isSelected = this.tab.isSelected;
* ```
* \@memberof IgxTabComponent
* @return {?}
*/
get isSelected() {
/** @type {?} */
const panel = this.relatedPanel;
if (panel) {
return panel.isSelected;
}
}
/**
* Gets the `index` of the tab.
* ```typescript
* let tabIndex = this.tab.index;
* ```
* \@memberof IgxTabComponent
* @return {?}
*/
get index() {
return this._tabBar.tabs.toArray().indexOf(this);
}
/**
* Selects the current tab and the associated panel.
* ```typescript
* this.tab.select();
* ```
* \@memberof IgxTabComponent
* @return {?}
*/
select() {
this.relatedPanel.select();
}
}
IgxTabComponent.decorators = [
{ type: Component, args: [{
selector: 'igx-tab',
template: "<ng-template #defaultTabTemplate>\n <div *ngIf=\"relatedPanel.icon\" class=\"tab-icon\">\n <igx-icon fontSet=\"material\">{{relatedPanel.icon}}</igx-icon>\n <igx-badge [value]=\"changesCount\" [hidden]=\"changesCount === 0\"></igx-badge>\n </div>\n <div *ngIf=\"relatedPanel.label\" ngClass=\"tab-label\">{{relatedPanel.label}}</div>\n</ng-template>\n<ng-container *ngTemplateOutlet=\"relatedPanel.customTabTemplate ? relatedPanel.customTabTemplate : defaultTabTemplate; context: { $implicit: relatedPanel }\">\n</ng-container>"
}] }
];
/** @nocollapse */
IgxTabComponent.ctorParameters = () => [
{ type: IgxBottomNavComponent },
{ type: ElementRef }
];
IgxTabComponent.propDecorators = {
role: [{ type: HostBinding, args: ['attr.role',] }],
relatedPanel: [{ type: Input }]
};
if (false) {
/**
* Gets the `role` attribute.
* ```typescript
* let tabRole = this.tab.role;
* ```
* \@memberof IgxTabComponent
* @type {?}
*/
IgxTabComponent.prototype.role;
/**
* Gets the panel associated with the tab.
* ```typescript
* let tabPanel = this.tab.relatedPanel;
* ```
* \@memberof IgxTabComponent
* @type {?}
*/
IgxTabComponent.prototype.relatedPanel;
/**
* @hidden
* @type {?}
* @private
*/
IgxTabComponent.prototype._changesCount;
/**
* @type {?}
* @private
*/
IgxTabComponent.prototype._tabBar;
/**
* @type {?}
* @private
*/
IgxTabComponent.prototype._element;
}
/**
* @hidden
*/
export class IgxBottomNavModule {
}
IgxBottomNavModule.decorators = [
{ type: NgModule, args: [{
declarations: [IgxBottomNavComponent, IgxTabPanelComponent, IgxTabComponent, IgxTabTemplateDirective],
exports: [IgxBottomNavComponent, IgxTabPanelComponent, IgxTabComponent, IgxTabTemplateDirective],
imports: [CommonModule, IgxBadgeModule, IgxIconModule]
},] }
];
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFiYmFyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL2lnbml0ZXVpLWFuZ3VsYXIvIiwic291cmNlcyI6WyJsaWIvdGFiYmFyL3RhYmJhci5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBSUgsU0FBUyxFQUNULFlBQVksRUFDWixlQUFlLEVBQ2YsU0FBUyxFQUNULFVBQVUsRUFDVixZQUFZLEVBQ1osVUFBVSxFQUNWLFdBQVcsRUFDWCxZQUFZLEVBQ1osS0FBSyxFQUNMLFFBQVEsRUFDUixNQUFNLEVBQ04sU0FBUyxFQUNULFdBQVcsRUFFWCxZQUFZLEVBQ2YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzFELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxlQUFlLENBQUM7Ozs7QUFFOUMseUNBR0M7OztJQUZHLGtDQUFxQjs7SUFDckIsb0NBQTRCOzs7SUFHNUIsT0FBTyxHQUFHLENBQUM7QUFLZixNQUFNLE9BQU8sdUJBQXVCOzs7O0lBRWhDLFlBQW1CLFFBQTBCO1FBQTFCLGFBQVEsR0FBUixRQUFRLENBQWtCO0lBQzdDLENBQUM7OztZQU5KLFNBQVMsU0FBQztnQkFDUCxRQUFRLEVBQUUsVUFBVTthQUN2Qjs7OztZQWhCRyxXQUFXOzs7O0lBbUJDLDJDQUFpQzs7Ozs7Ozs7Ozs7Ozs7Ozs7QUEyQmpELE1BQU0sT0FBTyxxQkFBcUI7Ozs7SUFxRjlCLFlBQW9CLFFBQW9CO1FBQXBCLGFBQVEsR0FBUixRQUFRLENBQVk7Ozs7Ozs7Ozs7OztRQXREakMsT0FBRSxHQUFHLGtCQUFrQixPQUFPLEVBQUUsRUFBRSxDQUFDOzs7Ozs7Ozs7UUFTekIsa0JBQWEsR0FBRyxJQUFJLFlBQVksRUFBdUIsQ0FBQzs7Ozs7Ozs7O1FBU3hELG9CQUFlLEdBQUcsSUFBSSxZ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Ozs7SUFROUMsdUNBQW1EOzs7Ozs7SUFJbkQsd0NBQTBCOzs7OztJQWdEZCxrQ0FBc0M7Ozs7O0lBQUUsbUNBQTRCOzs7OztBQXNCcEYsTUFBTSxPQUFPLGtCQUFrQjs7O1lBTDlCLFFBQVEsU0FBQztnQkFDTixZQUFZLEVBQUUsQ0FBQyxxQkFBcUIsRUFBRSxvQkFBb0IsRUFBRSxlQUFlLEVBQUUsdUJBQXVCLENBQUM7Z0JBQ3JHLE9BQU8sRUFBRSxDQUFDLHFCQUFxQixFQUFFLG9CQUFvQixFQUFFLGVBQWUsRUFBRSx1QkFBdUIsQ0FBQztnQkFDaEcsT0FBTyxFQUFFLENBQUMsWUFBWSxFQUFFLGNBQWMsRUFBRSxhQUFhLENBQUM7YUFDekQiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHtcbiAgICBBZnRlckNvbnRlbnRJbml0LFxuICAgIEFmdGVyVmlld0NoZWNrZWQsXG4gICAgQWZ0ZXJWaWV3SW5pdCxcbiAgICBDb21wb25lbnQsXG4gICAgQ29udGVudENoaWxkLFxuICAgIENvbnRlbnRDaGlsZHJlbixcbiAgICBEaXJlY3RpdmUsXG4gICAgRWxlbWVudFJlZixcbiAgICBFdmVudEVtaXR0ZXIsXG4gICAgZm9yd2FyZFJlZixcbiAgICBIb3N0QmluZGluZyxcbiAgICBIb3N0TGlzdGVuZXIsXG4gICAgSW5wdXQsXG4gICAgTmdNb2R1bGUsXG4gICAgT3V0cHV0LFxuICAgIFF1ZXJ5TGlzdCxcbiAgICBUZW1wbGF0ZVJlZixcbiAgICBWaWV3Q2hpbGQsXG4gICAgVmlld0NoaWxkcmVuXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgSWd4QmFkZ2VNb2R1bGUgfSBmcm9tICcuLi9iYWRnZS9iYWRnZS5jb21wb25lbnQnO1xuaW1wb3J0IHsgSWd4SWNvbk1vZHVsZSB9IGZyb20gJy4uL2ljb24vaW5kZXgnO1xuXG5leHBvcnQgaW50ZXJmYWNlIElTZWxlY3RUYWJFdmVudEFyZ3Mge1xuICAgIHRhYjogSWd4VGFiQ29tcG9uZW50O1xuICAgIHBhbmVsOiBJZ3hUYWJQYW5lbENvbXBvbmVudDtcbn1cblxubGV0IE5FWFRfSUQgPSAwO1xuXG5ARGlyZWN0aXZlKHtcbiAgICBzZWxlY3RvcjogJ1tpZ3hUYWJdJ1xufSlcbmV4cG9ydCBjbGFzcyBJZ3hUYWJUZW1wbGF0ZURpcmVjdGl2ZSB7XG5cbiAgICBjb25zdHJ1Y3RvcihwdWJsaWMgdGVtcGxhdGU6IFRlbXBsYXRlUmVmPGFueT4pIHtcbiAgICB9XG59XG4vKipcbiAqICoqSWduaXRlIFVJIGZvciBBbmd1bGFyIFRhYiBCYXIqKiAtXG4gKiBbRG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly93d3cuaW5mcmFnaXN0aWNzLmNvbS9wcm9kdWN0cy9pZ25pdGUtdWktYW5ndWxhci9hbmd1bGFyL2NvbXBvbmVudHMvdGFiYmFyLmh0bWwpXG4gKlxuICogVGhlIElnbml0ZSBVSSBUYWIgQmFyIGVuYWJsZXMgdGhlIHVzZXIgdG8gbmF2aWdhdGUgYW1vbmcgYSBudW1iZXIgb2YgY29udGVudCBwYW5lbHMgZGlzcGxheWVkIGluIGEgc2luZ2xlIHZpZXcuXG4gKlxuICogRXhhbXBsZTpcbiAqIGBgYGh0bWxcbiAqIDxpZ3gtYm90dG9tLW5hdj5cbiAqICAgPGlneC10YWItcGFuZWwgbGFiZWw9XCJUYWIgMVwiPlRhYiAxIENvbnRlbnQ8L2lneC10YWItcGFuZWw+XG4gKiAgIDxpZ3gtdGFiLXBhbmVsIGxhYmVsPVwiVGFiIDJcIj5UYWIgMiBDb250ZW50PC9pZ3gtdGFiLXBhbmVsPlxuICogICA8aWd4LXRhYi1wYW5lbCBsYWJlbD1cIlRhYiAzXCI+VGFiIDMgQ29udGVudDwvaWd4LXRhYi1wYW5lbD5cbiAqIDwvaWd4LWJvdHRvbS1uYXY+XG4gKiBgYGBcbiAqL1xuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICdpZ3gtYm90dG9tLW5hdicsXG4gICAgdGVtcGxhdGVVcmw6ICd0YWItYmFyLWNvbnRlbnQuY29tcG9uZW50Lmh0bWwnLFxuICAgIHN0eWxlczogW2BcbiAgICAgICAgOmhvc3Qge1xuICAgICAgICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICAgIH1cbiAgICBgXVxufSlcbmV4cG9ydCBjbGFzcyBJZ3hCb3R0b21OYXZDb21wb25lbnQgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0IHtcbiAgICAvKipcbiAgICAgKiBHZXRzIHRoZSBgSWd4VGFiQ29tcG9uZW50YCBlbGVtZW50cyBpbiB0aGUgdGFiIGJhciBjb21wb25lbnQuXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqIGxldCB0YWJzOiBRdWVyeUxpc3Q8SWd4VGFiQ29tcG9uZW50PiA9ICB0aGlzLnRhYkJhci50YWJzO1xuICAgICAqIGBgYFxuICAgICAqIEBtZW1iZXJvZiBJZ3hCb3R0b21OYXZDb21wb25lbnRcbiAgICAgKi9cbiAgICBAVmlld0NoaWxkcmVuKGZvcndhcmRSZWYoKCkgPT4gSWd4VGFiQ29tcG9uZW50KSkgcHVibGljIHRhYnM6IFF1ZXJ5TGlzdDxJZ3hUYWJDb21wb25lbnQ+O1xuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIGBJZ3hUYWJQYW5lbENvbXBvbmVudGAgZWxlbWVudHMgaW4gdGhlIHRhYiBiYXIgY29tcG9uZW50LlxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiBsZXQgdGFiUGFuZWxzOiBRdWVyeUxpc3Q8SWd4VGFiUGFuZWxDb21wb25lbnQ+ID0gdGhpcy50YWJCYXIucGFuZWxzO1xuICAgICAqIGBgYFxuICAgICAqIEBtZW1iZXJvZiBJZ3hCb3R0b21OYXZDb21wb25lbnRcbiAgICAgKi9cbiAgICBAQ29udGVudENoaWxkcmVuKGZvcndhcmRSZWYoKCkgPT4gSWd4VGFiUGFuZWxDb21wb25lbnQpKSBwdWJsaWMgcGFuZWxzOiBRdWVyeUxpc3Q8SWd4VGFiUGFuZWxDb21wb25lbnQ+O1xuXG4gICAgLyoqXG4gICAgICogU2V0cy9nZXRzIHRoZSBgaWRgIG9mIHRoZSB0YWIgYmFyLlxuICAgICAqIElmIG5vdCBzZXQsIHRoZSBgaWRgIG9mIHRoZSBmaXJzdCB0YWIgYmFyIGNvbXBvbmVudCB3aWxsIGJlIGBcImlneC1ib3R0b20tbmF2LTBcImAuXG4gICAgICogYGBgaHRtbFxuICAgICAqIDxpZ3gtYm90dG9tLW5hdiBpZCA9IFwibXktZmlyc3QtdGFiLWJhclwiPjwvaWd4LWJvdHRvbS1uYXY+XG4gICAgICogYGBgXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqIGxldCB0YWJCYXJJZCA9ICB0aGlzLnRhYkJhci5pZDtcbiAgICAgKiBgYGBcbiAgICAgKiBAbWVtYmVyb2YgSWd4Qm90dG9tTmF2Q29tcG9uZW50XG4gICAgICovXG4gICAgQEhvc3RCaW5kaW5nKCdhdHRyLmlkJylcbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBpZCA9IGBpZ3gtYm90dG9tLW5hdi0ke05FWFRfSUQrK31gO1xuICAgIC8qKlxuICAgICAqIEVtaXRzIGFuIGV2ZW50IHdoZW4gYSBuZXcgdGFiIGlzIHNlbGVjdGVkLlxuICAgICAqIFByb3ZpZGVzIHJlZmVyZW5jZXMgdG8gdGhlIGBJZ3hUYWJDb21wb25lbnRgIGFuZCBgSWd4VGFiUGFuZWxDb21wb25lbnRgIGFzIGV2ZW50IGFyZ3VtZW50cy5cbiAgICAgKiBgYGBodG1sXG4gICAgICogPGlneC1ib3R0b20tbmF2IChvblRhYmxlU2VsZWN0ZWQpID0gXCJvblRhYlNlbGVjdGVkKCRldmVudClcIj48aWd4LWJvdHRvbS1uYXY+XG4gICAgICogYGBgXG4gICAgICogQG1lbWJlcm9mIElneEJvdHRvbU5hdkNvbXBvbmVudFxuICAgICAqL1xuICAgIEBPdXRwdXQoKSBwdWJsaWMgb25UYWJTZWxlY3RlZCA9IG5ldyBFdmVudEVtaXR0ZXI8SVNlbGVjdFRhYkV2ZW50QXJncz4oKTtcbiAgICAvKipcbiAgICAgKiBFbWl0cyBhbiBldmVudCB3aGVuIGEgdGFiIGlzIGRlc2VsZWN0ZWQuXG4gICAgICogUHJvdmlkZXMgcmVmZXJlbmNlcyB0byB0aGUgYElneFRhYkNvbXBvbmVudGAgYW5kIGBJZ3hUYWJQYW5lbENvbXBvbmVudGAgYXMgZXZlbnQgYXJndW1lbnRzLlxuICAgICAqIGBgYGh0bWxcbiAgICAgKiA8aWd4LWJvdHRvbS1uYXYgKG9uVGFiRGVzZWxlY3RlZCkgPSBcIm9uVGFiRGVzZWxlY3RlZCgkZXZlbnQpXCI+PGlneC1ib3R0b20tbmF2PlxuICAgICAqIGBgYFxuICAgICAqIEBtZW1iZXJvZiBJZ3hCb3R0b21OYXZDb21wb25lbnRcbiAgICAgKi9cbiAgICBAT3V0cHV0KCkgcHVibGljIG9uVGFiRGVzZWxlY3RlZCA9IG5ldyBFdmVudEVtaXR0ZXI8SVNlbGVjdFRhYkV2ZW50QXJncz4oKTtcbiAgICAvKipcbiAgICAgKiBHZXRzIHRoZSBgaW5kZXhgIG9mIHNlbGVjdGVkIHRhYi9wYW5lbCBpbiB0aGUgcmVzcGVjdGl2ZSBjb2xsZWN0aW9uLlxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiBsZXQgaW5kZXggPSAgdGhpcy50YWJCYXIuc2VsZWN0ZWRJbmRleDtcbiAgICAgKiBgYGBcbiAgICAgKiBAbWVtYmVyb2YgSWd4Qm90dG9tTmF2Q29tcG9uZW50XG4gICAgICovXG4gICAgcHVibGljIHNlbGVjdGVkSW5kZXggPSAtMTtcbiAgICAvKipcbiAgICAgKiBHZXRzIHRoZSBgaXRlbVN0eWxlYCBvZiB0aGUgdGFiIGJhci5cbiAgICAgKiBgYGB0eXBlc2NyaXB0XG4gICAgICogbGV0IGl0ZW1TdHlsZSA9ICB0aGlzLnRhYkJhci5pdGVtU3R5bGU7XG4gICAgICogYGBgXG4gICAgICogQG1lbWJlcm9mIElneEJvdHRvbU5hdkNvbXBvbmVudFxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgaXRlbVN0eWxlKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aGlzLl9pdGVtU3R5bGU7XG4gICAgfVxuICAgIC8qKlxuICAgICAqQGhpZGRlblxuICAgICAqL1xuICAgIHByaXZhdGUgX2l0ZW1TdHlsZSA9ICdpZ3gtYm90dG9tLW5hdic7XG4gICAgLyoqXG4gICAgICogR2V0cyB0aGUgc2VsZWN0ZWQgdGFiIGluIHRoZSB0YWIgYmFyLlxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiBsZXQgdGFiID0gIHRoaXMudGFiQmFyLnNlbGVjdGVkVGFiO1xuICAgICAqIGBgYFxuICAgICAqIEBtZW1iZXJvZiBJZ3hCb3R0b21OYXZDb21wb25lbnRcbiAgICAgKi9cbiAgICBnZXQgc2VsZWN0ZWRUYWIoKTogSWd4VGFiQ29tcG9uZW50IHtcbiAgICAgICAgaWYgKHRoaXMudGFicyAmJiB0aGlzLnNlbGVjdGVkSW5kZXggIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudGFicy50b0FycmF5KClbdGhpcy5zZWxlY3RlZEluZGV4XTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgX2VsZW1lbnQ6IEVsZW1lbnRSZWYpIHtcbiAgICB9XG4gICAgLyoqXG4gICAgICpAaGlkZGVuXG4gICAgICovXG4gICAgcHVibGljIG5nQWZ0ZXJWaWV3SW5pdCgpIHtcbiAgICAgICAgLy8gaW5pdGlhbCBzZWxlY3Rpb25cbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy5zZWxlY3RlZEluZGV4ID09PSAtMSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHNlbGVjdGFibGVQYW5lbHMgPSB0aGlzLnBhbmVscy5maWx0ZXIoKHApID0+ICFwLmRpc2FibGVkKTtcbiAgICAgICAgICAgICAgICBjb25zdCBwYW5lbCA9IHNlbGVjdGFibGVQYW5lbHNbMF07XG5cbiAgICAgICAgICAgICAgICBpZiAocGFuZWwpIHtcbiAgICAgICAgICAgICAgICAgICAgcGFuZWwuc2VsZWN0KCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9LCAwKTtcbiAgICB9XG4gICAgLyoqXG4gICAgICpAaGlkZGVuXG4gICAgICovXG4gICAgQEhvc3RMaXN0ZW5lcignb25UYWJTZWxlY3RlZCcsIFsnJGV2ZW50J10pXG4gICAgcHVibGljIF9zZWxlY3RlZFBhbmVsSGFuZGxlcihhcmdzKSB7XG4gICAgICAgIHRoaXMuc2VsZWN0ZWRJbmRleCA9IGFyZ3MucGFuZWwuaW5kZXg7XG5cbiAgICAgICAgdGhpcy5wYW5lbHMuZm9yRWFjaCgocCkgPT4ge1xuICAgICAgICAgICAgaWYgKHAuaW5kZXggIT09IHRoaXMuc2VsZWN0ZWRJbmRleCkge1xuICAgICAgICAgICAgICAgIHRoaXMuX2Rlc2VsZWN0UGFuZWwocCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICAvKipcbiAgICAgKkBoaWRkZW5cbiAgICAgKi9cbiAgICBwcml2YXRlIF9kZXNlbGVjdFBhbmVsKHBhbmVsOiBJZ3hUYWJQYW5lbENvbXBvbmVudCkge1xuICAgICAgICAvLyBDYW5ub3QgZGVzZWxlY3QgdGhlIHNlbGVjdGVkIHRhYiAtIHRoaXMgd2lsbCBtZWFuIHRoYXQgdGhlcmUgd2lsbCBiZSBub3Qgc2VsZWN0ZWQgdGFiIGxlZnRcbiAgICAgICAgaWYgKHBhbmVsLmRpc2FibGVkIHx8IHRoaXMuc2VsZWN0ZWRUYWIuaW5kZXggPT09IHBhbmVsLmluZGV4KSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBwYW5lbC5pc1NlbGVjdGVkID0gZmFsc2U7XG4gICAgICAgIHRoaXMub25UYWJEZXNlbGVjdGVkLmVtaXQoeyB0YWI6IHRoaXMudGFic1twYW5lbC5pbmRleF0sIHBhbmVsIH0pO1xuICAgIH1cbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IElneFRhYlBhbmVsQ29tcG9uZW50ID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnaWd4LXRhYi1wYW5lbCcsXG4gICAgdGVtcGxhdGVVcmw6ICd0YWItcGFuZWwuY29tcG9uZW50Lmh0bWwnXG59KVxuXG5leHBvcnQgY2xhc3MgSWd4VGFiUGFuZWxDb21wb25lbnQgaW1wbGVtZW50cyBBZnRlckNvbnRlbnRJbml0LCBBZnRlclZpZXdDaGVja2VkIHtcbiAgICAvKipcbiAgICAgKkBoaWRkZW5cbiAgICAgKi9cbiAgICBwcml2YXRlIF9pdGVtU3R5bGUgPSAnaWd4LXRhYi1wYW5lbCc7XG4gICAgLyoqXG4gICAgICogU2V0cy9nZXRzIHRoZSBgbGFiZWxgIG9mIHRoZSB0YWIgcGFuZWwuXG4gICAgICogYGBgaHRtbFxuICAgICAqIDxpZ3gtdGFiLXBhbmVsIFtsYWJlbF0gPSBcIidUYWIgcGFuZWwgbGFiZWwnXCI+PGlneC10YWItcGFuZWw+XG4gICAgICogYGBgXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqIGxldCB0YWJQYW5lbExhYmVsID0gdGhpcy50YWJQYW5lbC5sYWJlbDtcbiAgICAgKiBgYGBcbiAgICAgKiBAbWVtYmVyb2YgSWd4VGFiUGFuZWxDb21wb25lbnRcbiAgICAgKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgbGFiZWw6IHN0cmluZztcbiAgICAvKipcbiAgICAgKiBTZXRzL2dldHMgIHRoZSBgaWNvbmAgb2YgdGhlIHRhYiBwYW5lbC5cbiAgICAgKiBgYGBodG1sXG4gICAgICogPGlneC10YWItcGFuZWwgW2ljb25dID0gXCJwYW5lbF9pY29uXCI+PGlneC10YWItcGFuZWw+XG4gICAgICogYGBgXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqIGxldCB0YWJQYW5lbEljb24gPSAgdGhpcy50YWJQYW5lbC5pY29uO1xuICAgICAqIGBgYFxuICAgICAqIEBtZW1iZXJvZiBJZ3hUYWJQYW5lbENvbXBvbmVudFxuICAgICAqL1xuICAgIEBJbnB1dCgpIHB1YmxpYyBpY29uOiBzdHJpbmc7XG4gICAgLyoqXG4gICAgICogU2V0cy9nZXRzIHdoZXRoZXIgdGhlIHRhYiBwYW5lbCBpcyBkaXNhYmxlZC5cbiAgICAgKiBgYGBodG1sXG4gICAgICogPGlneC10YWItcGFuZWwgW2Rpc2FibGVkXSA9IFwidHJ1ZVwiPjxpZ3gtdGFiLXBhbmVsPlxuICAgICAqIGBgYFxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiBsZXQgaXNEaXNhYmxlZCA9IHRoaXMudGFiUGFuZWwuZGlzYWJsZWQ7XG4gICAgICogYGBgXG4gICAgICogQG1lbWJlcm9mIElneFRhYlBhbmVsQ29tcG9uZW50XG4gICAgICovXG4gICAgQElucHV0KCkgcHVibGljIGRpc2FibGVkOiBib29sZWFuO1xuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIHJvbGUgb2YgdGhlIHRhYiBwYW5lbC5cbiAgICAgKiBgYGB0eXBlc2NyaXB0XG4gICAgICogbGV0IHRhYlBhbmVsUm9sZSA9IHRoaXMudGFiUGFuZWwucm9sZTtcbiAgICAgKiBgYGBcbiAgICAgKiBAbWVtYmVyb2YgSWd4VGFiUGFuZWxDb21wb25lbnRcbiAgICAgKi9cbiAgICBASG9zdEJpbmRpbmcoJ2F0dHIucm9sZScpIHB1YmxpYyByb2xlID0gJ3RhYnBhbmVsJztcbiAgICAvKipcbiAgICAgKiBHZXRzIHdoZXRoZXIgYSB0YWIgcGFuZWwgd2lsbCBoYXZlIGBpZ3gtYm90dG9tLW5hdl9fcGFuZWxgIGNsYXNzLlxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiBsZXQgc3R5bGVDbGFzcyA9IHRoaXMudGFiUGFuZWwuc3R5bGVDbGFzcztcbiAgICAgKiBgYGBcbiAgICAgKiBAbWVtYmVyb2YgSWd4VGFiUGFuZWxDb21wb25lbnRcbiAgICAgKi9cbiAgICBASG9zdEJpbmRpbmcoJ2NsYXNzLmlneC1ib3R0b20tbmF2X19wYW5lbCcpXG4gICAgZ2V0IHN0eWxlQ2xhc3MoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAoIXRoaXMuaXNTZWxlY3RlZCk7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFNldHMvZ2V0cyB3aGV0aGVyIGEgdGFiIHBhbmVsIGlzIHNlbGVjdGVkLlxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiB0aGlzLnRhYlBhbmVsLmlzU2VsZWN0ZWQgPSB0cnVlO1xuICAgICAqIGBgYFxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiBsZXQgaXNTZWxlY3RlZCA9ICB0aGlzLnRhYlBhbmVsSXNTZWxlY3RlZDtcbiAgICAgKiBgYGBcbiAgICAgKiBAbWVtYmVyb2YgSWd4VGFiUGFuZWxDb21wb25lbnRcbiAgICAgKi9cbiAgICBASG9zdEJpbmRpbmcoJ2NsYXNzLmlneC1ib3R0b20tbmF2X19wYW5lbC0tc2VsZWN0ZWQnKVxuICAgIHB1YmxpYyBpc1NlbGVjdGVkID0gZmFsc2U7XG4gICAgLyoqXG4gICAgICogR2V0cyB0aGUgYGl0ZW1TdHlsZWAgb2YgdGhlIHRhYiBwYW5lbC5cbiAgICAgKiBgYGB0eXBlc2NyaXB0XG4gICAgICogbGV0IGl0ZW1TdHlsZSA9IHRoaXMudGFiUGFuZWwuaXRlbVN0eWxlO1xuICAgICAqIGBgYFxuICAgICAqIEBtZW1iZXJvZiBJZ3hUYWJQYW5lbENvbXBvbmVudFxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgaXRlbVN0eWxlKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aGlzLl9pdGVtU3R5bGU7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIHRhYiBhc3NvY2lhdGVkIHdpdGggdGhlIHBhbmVsLlxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiBsZXQgdGFiID0gdGhpcy50YWJQYW5lbC5yZWxhdGVkVGFiO1xuICAgICAqIGBgYFxuICAgICAqIEBtZW1iZXJvZiBJZ3hUYWJQYW5lbENvbXBvbmVudFxuICAgICAqL1xuICAgIGdldCByZWxhdGVkVGFiKCk6IElneFRhYkNvbXBvbmVudCB7XG4gICAgICAgIGlmICh0aGlzLl90YWJCYXIudGFicykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3RhYkJhci50YWJzLnRvQXJyYXkoKVt0aGlzLmluZGV4XTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvKipcbiAgICAgKiBHZXRzIHRoZSBpbmRleCBvZiBhIHBhbmVsIGluIHRoZSBwYW5lbHMgY29sbGVjdGlvbi5cbiAgICAgKiBgYGB0eXBlc2NyaXB0XG4gICAgICogbGV0IHBhbmVsSW5kZXggPSAgdGhpcy50YWJQYW5lbC5pbmRleFxuICAgICAqIGBgYFxuICAgICAqIEBtZW1iZXJvZiBJZ3hUYWJQYW5lbENvbXBvbmVudFxuICAgICAqL1xuICAgIGdldCBpbmRleCgpIHtcbiAgICAgICAgaWYgKHRoaXMuX3RhYkJhci5wYW5lbHMpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl90YWJCYXIucGFuZWxzLnRvQXJyYXkoKS5pbmRleE9mKHRoaXMpO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIHRhYiB0ZW1wbGF0ZS5cbiAgICAgKiBgYGB0eXBlc2NyaXB0XG4gICAgICogbGV0IHRhYlRlbXBsYXRlID0gdGhpcy50YWJQYW5lbC5jdXN0b21UYWJUZW1wbGF0ZVxuICAgICAqIGBgYFxuICAgICAqIEBtZW1iZXJvZiBJZ3hUYWJQYW5lbENvbXBvbmVudFxuICAgICAqL1xuICAgIGdldCBjdXN0b21UYWJUZW1wbGF0ZSgpOiBUZW1wbGF0ZVJlZjxhbnk+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3RhYlRlbXBsYXRlO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSB0YWIgdGVtcGxhdGUuXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqIHRoaXMudGFiUGFuZWwuY3VzdG9tVGFiVGVtcGxhdGUodGFiVGVtcGxhdGUpO1xuICAgICAqIGBgYFxuICAgICAqIEBtZW1iZXJvZiBJZ3hUYWJQYW5lbENvbXBvbmVudFxuICAgICAqL1xuICAgIHNldCBjdXN0b21UYWJUZW1wbGF0ZSh0ZW1wbGF0ZTogVGVtcGxhdGVSZWY8YW55Pikge1xuICAgICAgICB0aGlzLl90YWJUZW1wbGF0ZSA9IHRlbXBsYXRlO1xuICAgIH1cbiAgICAvKipcbiAgICAgKkBoaWRkZW5cbiAgICAgKi9cbiAgICBwcml2YXRlIF90YWJUZW1wbGF0ZTogVGVtcGxhdGVSZWY8YW55PjtcbiAgICAvKipcbiAgICAgKkBoaWRkZW5cbiAgICAgKi9cbiAgICBAQ29udGVudENoaWxkKElneFRhYlRlbXBsYXRlRGlyZWN0aXZlLCB7IHJlYWQ6IElneFRhYlRlbXBsYXRlRGlyZWN0aXZlIH0pXG4gICAgcHJvdGVjdGVkIHRhYlRlbXBsYXRlOiBJZ3hUYWJUZW1wbGF0ZURpcmVjdGl2ZTtcblxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgX3RhYkJhcjogSWd4Qm90dG9tTmF2Q29tcG9uZW50LCBwcml2YXRlIF9lbGVtZW50OiBFbGVtZW50UmVmKSB7XG4gICAgfVxuICAgIC8qKlxuICAgICAqQGhpZGRlblxuICAgICAqL1xuICAgIHB1YmxpYyBuZ0FmdGVyQ29udGVudEluaXQoKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLnRhYlRlbXBsYXRlKSB7XG4gICAgICAgICAgICB0aGlzLl90YWJUZW1wbGF0ZSA9IHRoaXMudGFiVGVtcGxhdGUudGVtcGxhdGU7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLyoqXG4gICAgICpAaGlkZGVuXG4gICAgICovXG4gICAgcHVibGljIG5nQWZ0ZXJWaWV3Q2hlY2tlZCgpIHtcbiAgICAgICAgdGhpcy5fZWxlbWVudC5uYXRpdmVFbGVtZW50LnNldEF0dHJpYnV0ZSgnYXJpYS1sYWJlbGxlZGJ5JywgYGlneC10YWItJHt0aGlzLmluZGV4fWApO1xuICAgICAgICB0aGlzLl9lbGVtZW50Lm5hdGl2ZUVsZW1lbnQuc2V0QXR0cmlidXRlKCdpZCcsIGBpZ3gtYm90dG9tLW5hdl9fcGFuZWwtJHt0aGlzLmluZGV4fWApO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBTZWxlY3RzIHRoZSBjdXJyZW50IHRhYiBhbmQgdGhlIHRhYiBwYW5lbC5cbiAgICAgKiBgYGB0eXBlc2NyaXB0XG4gICAgICogdGhpcy50YWJQYW5lbC5zZWxlY3QoKTtcbiAgICAgKiBgYGBcbiAgICAgKiBAbWVtYmVyb2YgSWd4VGFiUGFuZWxDb21wb25lbnRcbiAgICAgKi9cbiAgICBwdWJsaWMgc2VsZWN0KCkge1xuICAgICAgICBpZiAodGhpcy5kaXNhYmxlZCB8fCB0aGlzLl90YWJCYXIuc2VsZWN0ZWRJbmRleCA9PT0gdGhpcy5pbmRleCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5pc1NlbGVjdGVkID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5fdGFiQmFyLm9uVGFiU2VsZWN0ZWQuZW1pdCh7IHRhYjogdGhpcy5fdGFiQmFyLnRhYnMudG9BcnJheSgpW3RoaXMuaW5kZXhdLCBwYW5lbDogdGhpcyB9KTtcbiAgICB9XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSBJZ3hUYWJDb21wb25lbnQgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnaWd4LXRhYicsXG4gICAgdGVtcGxhdGVVcmw6ICd0YWIuY29tcG9uZW50Lmh0bWwnXG59KVxuXG5leHBvcnQgY2xhc3MgSWd4VGFiQ29tcG9uZW50IHtcbiAgICAvKipcbiAgICAgKiBHZXRzIHRoZSBgcm9sZWAgYXR0cmlidXRlLlxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiBsZXQgdGFiUm9sZSA9IHRoaXMudGFiLnJvbGU7XG4gICAgICogYGBgXG4gICAgICogQG1lbWJlcm9mIElneFRhYkNvbXBvbmVudFxuICAgICAqL1xuICAgIEBIb3N0QmluZGluZygnYXR0ci5yb2xlJykgcHVibGljIHJvbGUgPSAndGFiJztcbiAgICAvKipcbiAgICAgKiBHZXRzIHRoZSBwYW5lbCBhc3NvY2lhdGVkIHdpdGggdGhlIHRhYi5cbiAgICAgKiBgYGB0eXBlc2NyaXB0XG4gICAgICogbGV0IHRhYlBhbmVsID0gIHRoaXMudGFiLnJlbGF0ZWRQYW5lbDtcbiAgICAgKiBgYGBcbiAgICAgKiBAbWVtYmVyb2YgSWd4VGFiQ29tcG9uZW50XG4gICAgICovXG4gICAgQElucHV0KCkgcHVibGljIHJlbGF0ZWRQYW5lbDogSWd4VGFiUGFuZWxDb21wb25lbnQ7XG4gICAgLyoqXG4gICAgICpAaGlkZGVuXG4gICAgICovXG4gICAgcHJpdmF0ZSBfY2hhbmdlc0NvdW50ID0gMDsgLy8gY2hhbmdlcyBhbmQgdXBkYXRlcyBhY2NvcmRpbmdseSBhcHBsaWVkIHRvIHRoZSB0YWIuXG4gICAgLyoqXG4gICAgICogR2V0cyB0aGUgY2hhbmdlcyBhbmQgdXBkYXRlcyBhY2NvcmRpbmdseSBhcHBsaWVkIHRvIHRoZSB0YWIuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyb2YgSWd4VGFiQ29tcG9uZW50XG4gICAgICovXG4gICAgZ2V0IGNoYW5nZXNDb3VudCgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5fY2hhbmdlc0NvdW50O1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBHZXRzIHdoZXRoZXIgdGhlIHRhYiBpcyBkaXNhYmxlZC5cbiAgICAgKiBgYGB0eXBlc2NyaXB0XG4gICAgICogbGV0IGlzRGlzYWJsZWQgPSB0aGlzLnRhYi5kaXNhYmxlZDtcbiAgICAgKiBgYGBcbiAgICAgKiBAbWVtYmVyb2YgSWd4VGFiQ29tcG9uZW50XG4gICAgICovXG4gICAgZ2V0IGRpc2FibGVkKCk6IGJvb2xlYW4ge1xuICAgICAgICBjb25zdCBwYW5lbCA9IHRoaXMucmVsYXRlZFBhbmVsO1xuXG4gICAgICAgIGlmIChwYW5lbCkge1xuICAgICAgICAgICAgcmV0dXJuIHBhbmVsLmRpc2FibGVkO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEdldHMgd2hldGhlciB0aGUgdGFiIGlzIHNlbGVjdGVkLlxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiBsZXQgaXNTZWxlY3RlZCAgPSB0aGlzLnRhYi5pc1NlbGVjdGVkO1xuICAgICAqIGBgYFxuICAgICAqIEBtZW1iZXJvZiBJZ3hUYWJDb21wb25lbnRcbiAgICAgKi9cbiAgICBnZXQgaXNTZWxlY3RlZCgpOiBib29sZWFuIHtcbiAgICAgICAgY29uc3QgcGFuZWwgPSB0aGlzLnJlbGF0ZWRQYW5lbDtcblxuICAgICAgICBpZiAocGFuZWwpIHtcbiAgICAgICAgICAgIHJldHVybiBwYW5lbC5pc1NlbGVjdGVkO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIGBpbmRleGAgb2YgdGhlIHRhYi5cbiAgICAgKiBgYGB0eXBlc2NyaXB0XG4gICAgICogbGV0IHRhYkluZGV4ID0gdGhpcy50YWIuaW5kZXg7XG4gICAgICogYGBgXG4gICAgICogQG1lbWJlcm9mIElneFRhYkNvbXBvbmVudFxuICAgICAqL1xuICAgIGdldCBpbmRleCgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5fdGFiQmFyLnRhYnMudG9BcnJheSgpLmluZGV4T2YodGhpcyk7XG4gICAgfVxuXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBfdGFiQmFyOiBJZ3hCb3R0b21OYXZDb21wb25lbnQsIHByaXZhdGUgX2VsZW1lbnQ6IEVsZW1lbnRSZWYpIHtcbiAgICB9XG4gICAgLyoqXG4gICAgICogU2VsZWN0cyB0aGUgY3VycmVudCB0YWIgYW5kIHRoZSBhc3NvY2lhdGVkIHBhbmVsLlxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiB0aGlzLnRhYi5zZWxlY3QoKTtcbiAgICAgKiBgYGBcbiAgICAgKiBAbWVtYmVyb2YgSWd4VGFiQ29tcG9uZW50XG4gICAgICovXG4gICAgcHVibGljIHNlbGVjdCgpIHtcbiAgICAgICAgdGhpcy5yZWxhdGVkUGFuZWwuc2VsZWN0KCk7XG4gICAgfVxufVxuXG4vKipcbiAqIEBoaWRkZW5cbiAqL1xuQE5nTW9kdWxlKHtcbiAgICBkZWNsYXJhdGlvbnM6IFtJZ3hCb3R0b21OYXZDb21wb25lbnQsIElneFRhYlBhbmVsQ29tcG9uZW50LCBJZ3hUYWJDb21wb25lbnQsIElneFRhYlRlbXBsYXRlRGlyZWN0aXZlXSxcbiAgICBleHBvcnRzOiBbSWd4Qm90dG9tTmF2Q29tcG9uZW50LCBJZ3hUYWJQYW5lbENvbXBvbmVudCwgSWd4VGFiQ29tcG9uZW50LCBJZ3hUYWJUZW1wbGF0ZURpcmVjdGl2ZV0sXG4gICAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgSWd4QmFkZ2VNb2R1bGUsIElneEljb25Nb2R1bGVdXG59KVxuZXhwb3J0IGNsYXNzIElneEJvdHRvbU5hdk1vZHVsZSB7XG59XG4iXX0=