UNPKG

carbon-components-angular

Version:
641 lines 65.7 kB
import { Component, Input, Output, EventEmitter, ViewChild, ViewChildren } from "@angular/core"; import { Observable, isObservable, of } from "rxjs"; import { first } from "rxjs/operators"; import { AbstractDropdownView } from "../abstract-dropdown-view.class"; import { watchFocusJump } from "../dropdowntools"; import * as i0 from "@angular/core"; import * as i1 from "carbon-components-angular/i18n"; import * as i2 from "@angular/common"; import * as i3 from "carbon-components-angular/icon"; /** * ```html * <cds-dropdown-list [items]="listItems"></cds-dropdown-list> * ``` * ```typescript * listItems = [ * { * content: "item one", * selected: false * }, * { * content: "item two", * selected: false, * }, * { * content: "item three", * selected: false * }, * { * content: "item four", * selected: false * } * ]; * ``` */ export class DropdownList { /** * Creates an instance of `DropdownList`. */ constructor(elementRef, i18n, appRef) { this.elementRef = elementRef; this.i18n = i18n; this.appRef = appRef; this.ariaLabel = this.i18n.get().DROPDOWN_LIST.LABEL; /** * Template to bind to items in the `DropdownList` (optional). */ this.listTpl = null; /** * Event to emit selection of a list item within the `DropdownList`. */ this.select = new EventEmitter(); /** * Event to emit scroll event of a list within the `DropdownList`. */ this.scroll = new EventEmitter(); /** * Event to suggest a blur on the view. * Emits _after_ the first/last item has been focused. * ex. * ArrowUp -> focus first item * ArrowUp -> emit event * * When this event fires focus should be placed on some element outside of the list - blurring the list as a result */ this.blurIntent = new EventEmitter(); /** * Defines whether or not the `DropdownList` supports selecting multiple items as opposed to single * item selection. */ this.type = "single"; /** * Defines whether to show title attribute or not */ this.showTitles = true; /** * Defines the rendering size of the `DropdownList` input component. */ this.size = "md"; this.listId = `listbox-${DropdownList.listCount++}`; this.highlightedItem = null; /** * Holds the list of items that will be displayed in the `DropdownList`. * It differs from the the complete set of items when filtering is used (but * it is always a subset of the total items in `DropdownList`). */ this.displayItems = []; /** * Maintains the index for the selected item within the `DropdownList`. */ this.index = -1; /** * Useful representation of the items, should be accessed via `getListItems`. */ this._items = []; } /** * The list items belonging to the `DropdownList`. */ set items(value) { if (isObservable(value)) { if (this._itemsSubscription) { this._itemsSubscription.unsubscribe(); } this._itemsReady = new Observable((observer) => { this._itemsSubscription = value.subscribe(v => { this.updateList(v); observer.next(true); observer.complete(); }); }); this.onItemsReady(null); } else { this.updateList(value); } this._originalItems = value; } get items() { return this._originalItems; } /** * Retrieves array of list items and index of the selected item after view has rendered. * Additionally, any Observables for the `DropdownList` are initialized. */ ngAfterViewInit() { this.index = this.getListItems().findIndex(item => item.selected); this.setupFocusObservable(); setTimeout(() => { this.doEmitSelect(true); }); } /** * Removes any Observables on destruction of the component. */ ngOnDestroy() { if (this.focusJump) { this.focusJump.unsubscribe(); } if (this._itemsSubscription) { this._itemsSubscription.unsubscribe(); } } doEmitSelect(isUpdate = true) { if (this.type === "single") { this.select.emit({ item: this._items.find(item => item.selected), isUpdate: isUpdate }); } else { // abuse javascripts object mutability until we can break the API and switch to // { items: [], isUpdate: true } const selected = this.getSelected() || []; selected["isUpdate"] = isUpdate; this.select.emit(selected); } } getItemId(index) { return `${this.listId}-${index}`; } /** * Updates the displayed list of items and then retrieves the most current properties for the `DropdownList` from the DOM. */ updateList(items) { this._items = items.map(item => Object.assign({}, item)); this.displayItems = this._items; this.updateIndex(); this.setupFocusObservable(); this.doEmitSelect(); } /** * Filters the items being displayed in the DOM list. */ filterBy(query = "") { if (query) { this.displayItems = this.getListItems().filter(item => item.content.toLowerCase().includes(query.toLowerCase())); // Reset index if items were found // Prevent selecting index in list that are undefined. if (this.displayItems) { this.index = 0; } } else { this.displayItems = this.getListItems(); } this.updateIndex(); } /** * Initializes (or re-initializes) the Observable that handles switching focus to an element based on * key input matching the first letter of the item in the list. */ setupFocusObservable() { if (!this.list) { return; } if (this.focusJump) { this.focusJump.unsubscribe(); } let elList = Array.from(this.list.nativeElement.querySelectorAll("li")); this.focusJump = watchFocusJump(this.list.nativeElement, elList) .subscribe(el => { el.focus(); }); } /** * Returns the `ListItem` that is subsequent to the selected item in the `DropdownList`. */ getNextItem() { if (this.index < this.displayItems.length - 1) { this.index++; } return this.displayItems[this.index]; } /** * Returns `true` if the selected item is not the last item in the `DropdownList`. */ hasNextElement() { return this.index < this.displayItems.length - 1 && (!(this.index === this.displayItems.length - 2) || !this.displayItems[this.index + 1].disabled); } /** * Returns the `HTMLElement` for the item that is subsequent to the selected item. */ getNextElement() { // Only return native elements if they are rendered const elemList = this.listElementList ? this.listElementList.toArray() : []; if (!elemList.length) { return null; } /** * Start checking from next index * Continue looping through the list until a non disabeled element is found or * end of list is reached */ for (let i = this.index + 1; i < elemList.length; i++) { // If the values in the list are not disabled if (!this.displayItems[i].disabled) { this.index = i; return elemList[i].nativeElement; } } return elemList[this.index]?.nativeElement; } /** * Returns the `ListItem` that precedes the selected item within `DropdownList`. */ getPrevItem() { if (this.index > 0) { this.index--; } return this.displayItems[this.index]; } /** * Returns `true` if the selected item is not the first in the list. */ hasPrevElement() { return this.index > 0 && (!(this.index === 1) || !this.displayItems[0].disabled); } /** * Returns the `HTMLElement` for the item that precedes the selected item. */ getPrevElement() { // Only return native elements if they are rendered const elemList = this.listElementList ? this.listElementList.toArray() : []; if (!elemList.length) { return null; } /** * Start checking from next index * Continue looping through the list until a non disabeled element is found or * end of list is reached */ for (let i = this.index - 1; i < this.index && i >= 0; i--) { // If the values in the list are not disabled if (!this.displayItems[i].disabled) { this.index = i; return elemList[i].nativeElement; } } return elemList[this.index].nativeElement; } /** * Returns the `ListItem` that is selected within `DropdownList`. */ getCurrentItem() { if (this.index < 0) { return this.displayItems[0]; } return this.displayItems[this.index]; } /** * Returns the `HTMLElement` for the item that is selected within the `DropdownList`. */ getCurrentElement() { if (this.index < 0) { return this.listElementList.first.nativeElement; } return this.listElementList.toArray()[this.index].nativeElement; } /** * Returns the items as an Array */ getListItems() { return this._items; } /** * Returns a list containing the selected item(s) in the `DropdownList`. */ getSelected() { let selected = this.getListItems().filter(item => item.selected); if (selected.length === 0) { return []; } return selected; } /** * Transforms array input list of items to the correct state by updating the selected item(s). */ propagateSelected(value) { // if we get a non-array, log out an error (since it is one) if (!Array.isArray(value)) { console.error(`${this.constructor.name}.propagateSelected expects an Array<ListItem>, got ${JSON.stringify(value)}`); } this.onItemsReady(() => { const selectedNewItems = []; for (let newItem of value) { if (newItem && newItem.selected) { // copy the item let tempNewItem = Object.assign({}, newItem); // deleted selected because it's what we _want_ to change delete tempNewItem.selected; // stringify for compare later tempNewItem = JSON.stringify(tempNewItem); // add to the list of selected items selectedNewItems.push(tempNewItem); } } // loop through the list items and update the `selected` state for matching items in `value` for (let oldItem of this.getListItems()) { // fast path when no items are selected if (selectedNewItems.length === 0) { oldItem.selected = false; continue; } // copy the item let tempOldItem = Object.assign({}, oldItem); // deleted selected because it's what we _want_ to change delete tempOldItem.selected; // stringify for compare tempOldItem = JSON.stringify(tempOldItem); for (let selectedNewItem of selectedNewItems) { // do the compare if (tempOldItem.includes(selectedNewItem)) { oldItem.selected = true; // if we've found a matching item, we can stop looping break; } else { oldItem.selected = false; } } } }); } /** * Initializes focus in the list, effectively a wrapper for `getCurrentElement().focus()` */ initFocus() { if (this.index < 0) { this.updateIndex(); } this.list.nativeElement.focus(); setTimeout(() => { this.highlightedItem = this.getItemId(this.index); }); } updateIndex() { // initialize index on the first selected item or // on the next non disabled item if no items are selected // in case, if all items are disabled, the index value will remain same const selected = this.getSelected(); if (selected.length) { this.index = this.displayItems.indexOf(selected[0]); } else if (this.hasNextElement()) { this.getNextElement(); } } /** * Manages the keyboard accessibility for navigation and selection within a `DropdownList`. */ navigateList(event) { if (event.key === "Enter" || event.key === " ") { if (this.listElementList.some(option => option.nativeElement === event.target)) { event.preventDefault(); } if (event.key === "Enter") { this.doClick(event, this.getCurrentItem()); } } else if (event.key === "ArrowDown" || event.key === "ArrowUp") { event.preventDefault(); if (event.key === "ArrowDown") { if (this.hasNextElement()) { this.getNextElement()?.scrollIntoView({ block: "end" }); } else { this.blurIntent.emit("bottom"); } } else if (event.key === "ArrowUp") { if (this.hasPrevElement()) { this.getPrevElement().scrollIntoView({ block: "nearest" }); } else { this.blurIntent.emit("top"); } } setTimeout(() => { this.highlightedItem = this.getItemId(this.index); }); } } /** * Emits the selected item or items after a mouse click event has occurred. */ doClick(event, item) { event.preventDefault(); if (item && !item.disabled) { this.list.nativeElement.focus(); if (this.type === "single") { item.selected = true; // reset the selection for (let otherItem of this.getListItems()) { if (item !== otherItem) { otherItem.selected = false; } } } else { item.selected = !item.selected; } this.index = this.displayItems.indexOf(item); this.highlightedItem = this.getItemId(this.index); this.doEmitSelect(false); this.appRef.tick(); } } onItemFocus(index) { const element = this.listElementList.toArray()[index].nativeElement; element.classList.add("cds--list-box__menu-item--highlighted"); element.tabIndex = 0; } onItemBlur(index) { const element = this.listElementList.toArray()[index].nativeElement; element.classList.remove("cds--list-box__menu-item--highlighted"); element.tabIndex = -1; } /** * Emits the scroll event of the options list */ emitScroll(event) { const atTop = event.srcElement.scrollTop === 0; const atBottom = event.srcElement.scrollHeight - event.srcElement.scrollTop === event.srcElement.clientHeight; const customScrollEvent = { atTop, atBottom, event }; this.scroll.emit(customScrollEvent); } /** * Subscribe the function passed to an internal observable that will resolve once the items are ready */ onItemsReady(subcription) { // this subscription will auto unsubscribe because of the `first()` pipe (this._itemsReady || of(true)).pipe(first()).subscribe(subcription); } reorderSelected(moveFocus = true) { this.displayItems = [...this.getSelected(), ...this.getListItems().filter(item => !item.selected)]; if (moveFocus) { setTimeout(() => { this.updateIndex(); this.highlightedItem = this.getItemId(this.index); }); } } } DropdownList.listCount = 0; DropdownList.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: DropdownList, deps: [{ token: i0.ElementRef }, { token: i1.I18n }, { token: i0.ApplicationRef }], target: i0.ɵɵFactoryTarget.Component }); DropdownList.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: DropdownList, selector: "cds-dropdown-list, ibm-dropdown-list", inputs: { ariaLabel: "ariaLabel", items: "items", listTpl: "listTpl", type: "type", showTitles: "showTitles" }, outputs: { select: "select", scroll: "scroll", blurIntent: "blurIntent" }, providers: [ { provide: AbstractDropdownView, useExisting: DropdownList } ], viewQueries: [{ propertyName: "list", first: true, predicate: ["list"], descendants: true, static: true }, { propertyName: "listElementList", predicate: ["listItem"], descendants: true }], ngImport: i0, template: ` <ul #list [id]="listId" role="listbox" class="cds--list-box__menu cds--multi-select" (scroll)="emitScroll($event)" (keydown)="navigateList($event)" tabindex="-1" [attr.aria-label]="ariaLabel" [attr.aria-activedescendant]="highlightedItem"> <li role="option" *ngFor="let item of displayItems; let i = index" (click)="doClick($event, item)" class="cds--list-box__menu-item" [attr.aria-selected]="item.selected" [id]="getItemId(i)" [attr.title]=" showTitles ? item.content : null" [attr.disabled]="item.disabled ? true : null" [ngClass]="{ 'cds--list-box__menu-item--active': item.selected, 'cds--list-box__menu-item--highlighted': highlightedItem === getItemId(i) }"> <div #listItem tabindex="-1" class="cds--list-box__menu-item__option"> <div *ngIf="!listTpl && type === 'multi'" class="cds--form-item cds--checkbox-wrapper"> <label [attr.data-contained-checkbox-state]="item.selected" class="cds--checkbox-label"> <input class="cds--checkbox" type="checkbox" [checked]="item.selected" [disabled]="item.disabled" tabindex="-1"> <span class="cds--checkbox-appearance"></span> <span class="cds--checkbox-label-text">{{item.content}}</span> </label> </div> <ng-container *ngIf="!listTpl && type === 'single'">{{item.content}}</ng-container> <svg *ngIf="!listTpl && type === 'single'" cdsIcon="checkmark" size="16" class="cds--list-box__menu-item__selected-icon"> </svg> <ng-template *ngIf="listTpl" [ngTemplateOutletContext]="{item: item}" [ngTemplateOutlet]="listTpl"> </ng-template> </div> </li> </ul>`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: DropdownList, decorators: [{ type: Component, args: [{ selector: "cds-dropdown-list, ibm-dropdown-list", template: ` <ul #list [id]="listId" role="listbox" class="cds--list-box__menu cds--multi-select" (scroll)="emitScroll($event)" (keydown)="navigateList($event)" tabindex="-1" [attr.aria-label]="ariaLabel" [attr.aria-activedescendant]="highlightedItem"> <li role="option" *ngFor="let item of displayItems; let i = index" (click)="doClick($event, item)" class="cds--list-box__menu-item" [attr.aria-selected]="item.selected" [id]="getItemId(i)" [attr.title]=" showTitles ? item.content : null" [attr.disabled]="item.disabled ? true : null" [ngClass]="{ 'cds--list-box__menu-item--active': item.selected, 'cds--list-box__menu-item--highlighted': highlightedItem === getItemId(i) }"> <div #listItem tabindex="-1" class="cds--list-box__menu-item__option"> <div *ngIf="!listTpl && type === 'multi'" class="cds--form-item cds--checkbox-wrapper"> <label [attr.data-contained-checkbox-state]="item.selected" class="cds--checkbox-label"> <input class="cds--checkbox" type="checkbox" [checked]="item.selected" [disabled]="item.disabled" tabindex="-1"> <span class="cds--checkbox-appearance"></span> <span class="cds--checkbox-label-text">{{item.content}}</span> </label> </div> <ng-container *ngIf="!listTpl && type === 'single'">{{item.content}}</ng-container> <svg *ngIf="!listTpl && type === 'single'" cdsIcon="checkmark" size="16" class="cds--list-box__menu-item__selected-icon"> </svg> <ng-template *ngIf="listTpl" [ngTemplateOutletContext]="{item: item}" [ngTemplateOutlet]="listTpl"> </ng-template> </div> </li> </ul>`, providers: [ { provide: AbstractDropdownView, useExisting: DropdownList } ] }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.I18n }, { type: i0.ApplicationRef }]; }, propDecorators: { ariaLabel: [{ type: Input }], items: [{ type: Input }], listTpl: [{ type: Input }], select: [{ type: Output }], scroll: [{ type: Output }], blurIntent: [{ type: Output }], list: [{ type: ViewChild, args: ["list", { static: true }] }], type: [{ type: Input }], showTitles: [{ type: Input }], listElementList: [{ type: ViewChildren, args: ["listItem"] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHJvcGRvd24tbGlzdC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvZHJvcGRvd24vbGlzdC9kcm9wZG93bi1saXN0LmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ04sU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBRU4sWUFBWSxFQUdaLFNBQVMsRUFFVCxZQUFZLEVBR1osTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQWdCLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNsRSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFHdkMsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFdkUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGtCQUFrQixDQUFDOzs7OztBQUlsRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHO0FBcUVILE1BQU0sT0FBTyxZQUFZO0lBMEd4Qjs7T0FFRztJQUNILFlBQW1CLFVBQXNCLEVBQVksSUFBVSxFQUFZLE1BQXNCO1FBQTlFLGVBQVUsR0FBVixVQUFVLENBQVk7UUFBWSxTQUFJLEdBQUosSUFBSSxDQUFNO1FBQVksV0FBTSxHQUFOLE1BQU0sQ0FBZ0I7UUEzR3hGLGNBQVMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUM7UUEwQnpEOztXQUVHO1FBQ00sWUFBTyxHQUE4QixJQUFJLENBQUM7UUFDbkQ7O1dBRUc7UUFDTyxXQUFNLEdBQXNFLElBQUksWUFBWSxFQUFFLENBQUM7UUFDekc7O1dBRUc7UUFDTyxXQUFNLEdBQW9DLElBQUksWUFBWSxFQUFFLENBQUM7UUFDdkU7Ozs7Ozs7O1dBUUc7UUFDTyxlQUFVLEdBQUcsSUFBSSxZQUFZLEVBQW9CLENBQUM7UUFLNUQ7OztX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Ozs7Ozs7Ozs7Ozs7O1FBMERIO29CQUNQLFNBQVMsRUFBRTt3QkFDVjs0QkFDQyxPQUFPLEVBQUUsb0JBQW9COzRCQUM3QixXQUFXLGNBQWM7eUJBQ3pCO3FCQUNEO2lCQUNEO2lKQUdTLFNBQVM7c0JBQWpCLEtBQUs7Z0JBSU8sS0FBSztzQkFBakIsS0FBSztnQkF5QkcsT0FBTztzQkFBZixLQUFLO2dCQUlJLE1BQU07c0JBQWYsTUFBTTtnQkFJRyxNQUFNO3NCQUFmLE1BQU07Z0JBVUcsVUFBVTtzQkFBbkIsTUFBTTtnQkFJOEIsSUFBSTtzQkFBeEMsU0FBUzt1QkFBQyxNQUFNLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFO2dCQUsxQixJQUFJO3NCQUFaLEtBQUs7Z0JBS0csVUFBVTtzQkFBbEIsS0FBSztnQkFxQjhCLGVBQWU7c0JBQWxELFlBQVk7dUJBQUMsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG5cdENvbXBvbmVudCxcblx0SW5wdXQsXG5cdE91dHB1dCxcblx0T25EZXN0cm95LFxuXHRFdmVudEVtaXR0ZXIsXG5cdFRlbXBsYXRlUmVmLFxuXHRBZnRlclZpZXdJbml0LFxuXHRWaWV3Q2hpbGQsXG5cdEVsZW1lbnRSZWYsXG5cdFZpZXdDaGlsZHJlbixcblx0UXVlcnlMaXN0LFxuXHRBcHBsaWNhdGlvblJlZlxufSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgaXNPYnNlcnZhYmxlLCBTdWJzY3JpcHRpb24sIG9mIH0gZnJvbSBcInJ4anNcIjtcbmltcG9ydCB7IGZpcnN0IH0gZnJvbSBcInJ4anMvb3BlcmF0b3JzXCI7XG5cbmltcG9ydCB7IEkxOG4gfSBmcm9tIFwiY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhci9pMThuXCI7XG5pbXBvcnQgeyBBYnN0cmFjdERyb3Bkb3duVmlldyB9IGZyb20gXCIuLi9hYnN0cmFjdC1kcm9wZG93bi12aWV3LmNsYXNzXCI7XG5pbXBvcnQgeyBMaXN0SXRlbSB9IGZyb20gXCIuLi9saXN0LWl0ZW0uaW50ZXJmYWNlXCI7XG5pbXBvcnQgeyB3YXRjaEZvY3VzSnVtcCB9IGZyb20gXCIuLi9kcm9wZG93bnRvb2xzXCI7XG5pbXBvcnQgeyBTY3JvbGxDdXN0b21FdmVudCB9IGZyb20gXCIuL3Njcm9sbC1jdXN0b20tZXZlbnQuaW50ZXJmYWNlXCI7XG5cblxuLyoqXG4gKiBgYGBodG1sXG4gKiA8Y2RzLWRyb3Bkb3duLWxpc3QgW2l0ZW1zXT1cImxpc3RJdGVtc1wiPjwvY2RzLWRyb3Bkb3duLWxpc3Q+XG4gKiBgYGBcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGxpc3RJdGVtcyA9IFtcbiAqIFx0e1xuICogXHRcdGNvbnRlbnQ6IFwiaXRlbSBvbmVcIixcbiAqIFx0XHRzZWxlY3RlZDogZmFsc2VcbiAqIFx0fSxcbiAqIFx0e1xuICogXHRcdGNvbnRlbnQ6IFwiaXRlbSB0d29cIixcbiAqIFx0XHRzZWxlY3RlZDogZmFsc2UsXG4gKiBcdH0sXG4gKiBcdHtcbiAqIFx0XHRjb250ZW50OiBcIml0ZW0gdGhyZWVcIixcbiAqIFx0XHRzZWxlY3RlZDogZmFsc2VcbiAqIFx0fSxcbiAqIFx0e1xuICogXHRcdGNvbnRlbnQ6IFwiaXRlbSBmb3VyXCIsXG4gKiBcdFx0c2VsZWN0ZWQ6IGZhbHNlXG4gKiBcdH1cbiAqIF07XG4gKiBgYGBcbiAqL1xuQENvbXBvbmVudCh7XG5cdHNlbGVjdG9yOiBcImNkcy1kcm9wZG93bi1saXN0LCBpYm0tZHJvcGRvd24tbGlzdFwiLFxuXHR0ZW1wbGF0ZTogYFxuXHRcdDx1bFxuXHRcdFx0I2xpc3Rcblx0XHRcdFtpZF09XCJsaXN0SWRcIlxuXHRcdFx0cm9sZT1cImxpc3Rib3hcIlxuXHRcdFx0Y2xhc3M9XCJjZHMtLWxpc3QtYm94X19tZW51IGNkcy0tbXVsdGktc2VsZWN0XCJcblx0XHRcdChzY3JvbGwpPVwiZW1pdFNjcm9sbCgkZXZlbnQpXCJcblx0XHRcdChrZXlkb3duKT1cIm5hdmlnYXRlTGlzdCgkZXZlbnQpXCJcblx0XHRcdHRhYmluZGV4PVwiLTFcIlxuXHRcdFx0W2F0dHIuYXJpYS1sYWJlbF09XCJhcmlhTGFiZWxcIlxuXHRcdFx0W2F0dHIuYXJpYS1hY3RpdmVkZXNjZW5kYW50XT1cImhpZ2hsaWdodGVkSXRlbVwiPlxuXHRcdFx0PGxpXG5cdFx0XHRcdHJvbGU9XCJvcHRpb25cIlxuXHRcdFx0XHQqbmdGb3I9XCJsZXQgaXRlbSBvZiBkaXNwbGF5SXRlbXM7IGxldCBpID0gaW5kZXhcIlxuXHRcdFx0XHQoY2xpY2spPVwiZG9DbGljaygkZXZlbnQsIGl0ZW0pXCJcblx0XHRcdFx0Y2xhc3M9XCJjZHMtLWxpc3QtYm94X19tZW51LWl0ZW1cIlxuXHRcdFx0XHRbYXR0ci5hcmlhLXNlbGVjdGVkXT1cIml0ZW0uc2VsZWN0ZWRcIlxuXHRcdFx0XHRbaWRdPVwiZ2V0SXRlbUlkKGkpXCJcblx0XHRcdFx0W2F0dHIudGl0bGVdPVwiIHNob3dUaXRsZXMgPyBpdGVtLmNvbnRlbnQgOiBudWxsXCJcblx0XHRcdFx0W2F0dHIuZGlzYWJsZWRdPVwiaXRlbS5kaXNhYmxlZCA/IHRydWUgOiBudWxsXCJcblx0XHRcdFx0W25nQ2xhc3NdPVwie1xuXHRcdFx0XHRcdCdjZHMtLWxpc3QtYm94X19tZW51LWl0ZW0tLWFjdGl2ZSc6IGl0ZW0uc2VsZWN0ZWQsXG5cdFx0XHRcdFx0J2Nkcy0tbGlzdC1ib3hfX21lbnUtaXRlbS0taGlnaGxpZ2h0ZWQnOiBoaWdobGlnaHRlZEl0ZW0gPT09IGdldEl0ZW1JZChpKVxuXHRcdFx0XHR9XCI+XG5cdFx0XHRcdDxkaXZcblx0XHRcdFx0XHQjbGlzdEl0ZW1cblx0XHRcdFx0XHR0YWJpbmRleD1cIi0xXCJcblx0XHRcdFx0XHRjbGFzcz1cImNkcy0tbGlzdC1ib3hfX21lbnUtaXRlbV9fb3B0aW9uXCI+XG5cdFx0XHRcdFx0PGRpdlxuXHRcdFx0XHRcdFx0Km5nSWY9XCIhbGlzdFRwbCAmJiB0eXBlID09PSAnbXVsdGknXCJcblx0XHRcdFx0XHRcdGNsYXNzPVwiY2RzLS1mb3JtLWl0ZW0gY2RzLS1jaGVja2JveC13cmFwcGVyXCI+XG5cdFx0XHRcdFx0XHQ8bGFiZWxcblx0XHRcdFx0XHRcdFx0W2F0dHIuZGF0YS1jb250YWluZWQtY2hlY2tib3gtc3RhdGVdPVwiaXRlbS5zZWxlY3RlZFwiXG5cdFx0XHRcdFx0XHRcdGNsYXNzPVwiY2RzLS1jaGVja2JveC1sYWJlbFwiPlxuXHRcdFx0XHRcdFx0XHQ8aW5wdXRcblx0XHRcdFx0XHRcdFx0XHRjbGFzcz1cImNkcy0tY2hlY2tib3hcIlxuXHRcdFx0XHRcdFx0XHRcdHR5cGU9XCJjaGVja2JveFwiXG5cdFx0XHRcdFx0XHRcdFx0W2NoZWNrZWRdPVwiaXRlbS5zZWxlY3RlZFwiXG5cdFx0XHRcdFx0XHRcdFx0W2Rpc2FibGVkXT1cIml0ZW0uZGlzYWJsZWRcIlxuXHRcdFx0XHRcdFx0XHRcdHRhYmluZGV4PVwiLTFcIj5cblx0XHRcdFx0XHRcdFx0PHNwYW4gY2xhc3M9XCJjZHMtLWNoZWNrYm94LWFwcGVhcmFuY2VcIj48L3NwYW4+XG5cdFx0XHRcdFx0XHRcdDxzcGFuIGNsYXNzPVwiY2RzLS1jaGVja2JveC1sYWJlbC10ZXh0XCI+e3tpdGVtLmNvbnRlbnR9fTwvc3Bhbj5cblx0XHRcdFx0XHRcdDwvbGFiZWw+XG5cdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0PG5nLWNvbnRhaW5lciAqbmdJZj1cIiFsaXN0VHBsICYmIHR5cGUgPT09ICdzaW5nbGUnXCI+e3tpdGVtLmNvbnRlbnR9fTwvbmctY29udGFpbmVyPlxuXHRcdFx0XHRcdDxzdmdcblx0XHRcdFx0XHRcdCpuZ0lmPVwiIWxpc3RUcGwgJiYgdHlwZSA9PT0gJ3NpbmdsZSdcIlxuXHRcdFx0XHRcdFx0Y2RzSWNvbj1cImNoZWNrbWFya1wiXG5cdFx0XHRcdFx0XHRzaXplPVwiMTZcIlxuXHRcdFx0XHRcdFx0Y2xhc3M9XCJjZHMtLWxpc3QtYm94X19tZW51LWl0ZW1fX3NlbGVjdGVkLWljb25cIj5cblx0XHRcdFx0XHQ8L3N2Zz5cblx0XHRcdFx0XHQ8bmctdGVtcGxhdGVcblx0XHRcdFx0XHRcdCpuZ0lmPVwibGlzdFRwbFwiXG5cdFx0XHRcdFx0XHRbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwie2l0ZW06IGl0ZW19XCJcblx0XHRcdFx0XHRcdFtuZ1RlbXBsYXRlT3V0bGV0XT1cImxpc3RUcGxcIj5cblx0XHRcdFx0XHQ8L25nLXRlbXBsYXRlPlxuXHRcdFx0XHQ8L2Rpdj5cblx0XHRcdDwvbGk+XG5cdFx0PC91bD5gLFxuXHRwcm92aWRlcnM6IFtcblx0XHR7XG5cdFx0XHRwcm92aWRlOiBBYnN0cmFjdERyb3Bkb3duVmlldyxcblx0XHRcdHVzZUV4aXN0aW5nOiBEcm9wZG93bkxpc3Rcblx0XHR9XG5cdF1cbn0pXG5leHBvcnQgY2xhc3MgRHJvcGRvd25MaXN0IGltcGxlbWVudHMgQWJzdHJhY3REcm9wZG93blZpZXcsIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveSB7XG5cdHN0YXRpYyBsaXN0Q291bnQgPSAwO1xuXHRASW5wdXQoKSBhcmlhTGFiZWwgPSB0aGlzLmkxOG4uZ2V0KCkuRFJPUERPV05fTElTVC5MQUJFTDtcblx0LyoqXG5cdCAqIFRoZSBsaXN0IGl0ZW1zIGJlbG9uZ2luZyB0byB0aGUgYERyb3Bkb3duTGlzdGAuXG5cdCAqL1xuXHRASW5wdXQoKSBzZXQgaXRlbXModmFsdWU6IEFycmF5PExpc3RJdGVtPiB8IE9ic2VydmFibGU8QXJyYXk8TGlzdEl0ZW0+Pikge1xuXHRcdGlmIChpc09ic2VydmFibGUodmFsdWUpKSB7XG5cdFx0XHRpZiAodGhpcy5faXRlbXNTdWJzY3JpcHRpb24pIHtcblx0XHRcdFx0dGhpcy5faXRlbXNTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcblx0XHRcdH1cblx0XHRcdHRoaXMuX2l0ZW1zUmVhZHkgPSBuZXcgT2JzZXJ2YWJsZTxib29sZWFuPigob2JzZXJ2ZXIpID0+IHtcblx0XHRcdFx0dGhpcy5faXRlbXNTdWJzY3JpcHRpb24gPSB2YWx1ZS5zdWJzY3JpYmUodiA9PiB7XG5cdFx0XHRcdFx0dGhpcy51cGRhdGVMaXN0KHYpO1xuXHRcdFx0XHRcdG9ic2VydmVyLm5leHQodHJ1ZSk7XG5cdFx0XHRcdFx0b2JzZXJ2ZXIuY29tcGxldGUoKTtcblx0XHRcdFx0fSk7XG5cdFx0XHR9KTtcblx0XHRcdHRoaXMub25JdGVtc1JlYWR5KG51bGwpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLnVwZGF0ZUxpc3QodmFsdWUpO1xuXHRcdH1cblx0XHR0aGlzLl9vcmlnaW5hbEl0ZW1zID0gdmFsdWU7XG5cdH1cblxuXHRnZXQgaXRlbXMoKTogQXJyYXk8TGlzdEl0ZW0+IHwgT2JzZXJ2YWJsZTxBcnJheTxMaXN0SXRlbT4+IHtcblx0XHRyZXR1cm4gdGhpcy5fb3JpZ2luYWxJdGVtcztcblx0fVxuXHQvKipcblx0ICogVGVtcGxhdGUgdG8gYmluZCB0byBpdGVtcyBpbiB0aGUgYERyb3Bkb3duTGlzdGAgKG9wdGlvbmFsKS5cblx0ICovXG5cdEBJbnB1dCgpIGxpc3RUcGw6IHN0cmluZyB8IFRlbXBsYXRlUmVmPGFueT4gPSBudWxsO1xuXHQvKipcblx0ICogRXZlbnQgdG8gZW1pdCBzZWxlY3Rpb24gb2YgYSBsaXN0IGl0ZW0gd2l0aGluIHRoZSBgRHJvcGRvd25MaXN0YC5cblx0ICovXG5cdEBPdXRwdXQoKSBzZWxlY3Q6IEV2ZW50RW1pdHRlcjx7IGl0ZW06IExpc3RJdGVtLCBpc1VwZGF0ZT86IGJvb2xlYW4gfSB8IExpc3RJdGVtW10+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXHQvKipcblx0ICogRXZlbnQgdG8gZW1pdCBzY3JvbGwgZXZlbnQgb2YgYSBsaXN0IHdpdGhpbiB0aGUgYERyb3Bkb3duTGlzdGAuXG5cdCAqL1xuXHRAT3V0cHV0KCkgc2Nyb2xsOiBFdmVudEVtaXR0ZXI8U2Nyb2xsQ3VzdG9tRXZlbnQ+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXHQvKipcblx0ICogRXZlbnQgdG8gc3VnZ2VzdCBhIGJsdXIgb24gdGhlIHZpZXcuXG5cdCAqIEVtaXRzIF9hZnRlcl8gdGhlIGZpcnN0L2xhc3QgaXRlbSBoYXMgYmVlbiBmb2N1c2VkLlxuXHQgKiBleC5cblx0ICogQXJyb3dVcCAtPiBmb2N1cyBmaXJzdCBpdGVtXG5cdCAqIEFycm93VXAgLT4gZW1pdCBldmVudFxuXHQgKlxuXHQgKiBXaGVuIHRoaXMgZXZlbnQgZmlyZXMgZm9jdXMgc2hvdWxkIGJlIHBsYWNlZCBvbiBzb21lIGVsZW1lbnQgb3V0c2lkZSBvZiB0aGUgbGlzdCAtIGJsdXJyaW5nIHRoZSBsaXN0IGFzIGEgcmVzdWx0XG5cdCAqL1xuXHRAT3V0cHV0KCkgYmx1ckludGVudCA9IG5ldyBFdmVudEVtaXR0ZXI8XCJ0b3BcIiB8IFwiYm90dG9tXCI+KCk7XG5cdC8qKlxuXHQgKiBNYWludGFpbnMgYSByZWZlcmVuY2UgdG8gdGhlIHZpZXcgRE9NIGVsZW1lbnQgZm9yIHRoZSB1bm9yZGVyZWQgbGlzdCBvZiBpdGVtcyB3aXRoaW4gdGhlIGBEcm9wZG93bkxpc3RgLlxuXHQgKi9cblx0QFZpZXdDaGlsZChcImxpc3RcIiwgeyBzdGF0aWM6IHRydWUgfSkgbGlzdDogRWxlbWVudFJlZjtcblx0LyoqXG5cdCAqIERlZmluZXMgd2hldGhlciBvciBub3QgdGhlIGBEcm9wZG93bkxpc3RgIHN1cHBvcnRzIHNlbGVjdGluZyBtdWx0aXBsZSBpdGVtcyBhcyBvcHBvc2VkIHRvIHNpbmdsZVxuXHQgKiBpdGVtIHNlbGVjdGlvbi5cblx0ICovXG5cdEBJbnB1dCgpIHR5cGU6IFwic2luZ2xlXCIgfCBcIm11bHRpXCIgPSBcInNpbmdsZVwiO1xuXG5cdC8qKlxuXHQgKiBEZWZpbmVzIHdoZXRoZXIgdG8gc2hvdyB0aXRsZSBhdHRyaWJ1dGUgb3Igbm90XG5cdCAqL1xuXHRASW5wdXQoKSBzaG93VGl0bGVzID0gdHJ1ZTtcblxuXHQvKipcblx0ICogRGVmaW5lcyB0aGUgcmVuZGVyaW5nIHNpemUgb2YgdGhlIGBEcm9wZG93bkxpc3RgIGlucHV0IGNvbXBvbmVudC5cblx0ICovXG5cdHB1YmxpYyBzaXplOiBcInNtXCIgfCBcIm1kXCIgfCBcImxnXCIgPSBcIm1kXCI7XG5cdHB1YmxpYyBsaXN0SWQgPSBgbGlzdGJveC0ke0Ryb3Bkb3duTGlzdC5saXN0Q291bnQrK31gO1xuXHRwdWJsaWMgaGlnaGxpZ2h0ZWRJdGVtID0gbnVsbDtcblx0LyoqXG5cdCAqIEhvbGRzIHRoZSBsaXN0IG9mIGl0ZW1zIHRoYXQgd2lsbCBiZSBkaXNwbGF5ZWQgaW4gdGhlIGBEcm9wZG93bkxpc3RgLlxuXHQgKiBJdCBkaWZmZXJzIGZyb20gdGhlIHRoZSBjb21wbGV0ZSBzZXQgb2YgaXRlbXMgd2hlbiBmaWx0ZXJpbmcgaXMgdXNlZCAoYnV0XG5cdCAqIGl0IGlzIGFsd2F5cyBhIHN1YnNldCBvZiB0aGUgdG90YWwgaXRlbXMgaW4gYERyb3Bkb3duTGlzdGApLlxuXHQgKi9cblx0cHVibGljIGRpc3BsYXlJdGVtczogQXJyYXk8TGlzdEl0ZW0+ID0gW107XG5cdC8qKlxuXHQgKiBNYWludGFpbnMgdGhlIGluZGV4IGZvciB0aGUgc2VsZWN0ZWQgaXRlbSB3aXRoaW4gdGhlIGBEcm9wZG93bkxpc3RgLlxuXHQgKi9cblx0cHJvdGVjdGVkIGluZGV4ID0gLTE7XG5cdC8qKlxuXHQgKiBBbiBhcnJheSBob2xkaW5nIHRoZSBIVE1MIGxpc3QgZWxlbWVudHMgaW4gdGhlIHZpZXcuXG5cdCAqL1xuXHRAVmlld0NoaWxkcmVuKFwibGlzdEl0ZW1cIikgcHJvdGVjdGVkIGxpc3RFbGVtZW50TGlzdDogUXVlcnlMaXN0PEVsZW1lbnRSZWY+O1xuXHQvKipcblx0ICogT2JzZXJ2YWJsZSBib3VuZCB0byBrZXlkb3duIGV2ZW50cyB0byBjb250cm9sIGZpbHRlcmluZy5cblx0ICovXG5cdHByb3RlY3RlZCBmb2N1c0p1bXA7XG5cdC8qKlxuXHQgKiBUcmFja3MgdGhlIGN1cnJlbnQgKGlmIGFueSkgc3Vic2NyaXB0aW9uIHRvIHRoZSBpdGVtcyBvYnNlcnZhYmxlIHNvIHdlIGNhbiBjbGVhbiB1cCB3aGVuIHRoZSBpbnB1dCBpcyB1cGRhdGVkLlxuXHQgKi9cblx0cHJvdGVjdGVkIF9pdGVtc1N1YnNjcmlwdGlvbjogU3Vic2NyaXB0aW9uO1xuXHQvKipcblx0ICogVXNlZCB0byByZXRhaW4gdGhlIG9yaWdpbmFsIGl0ZW1zIHBhc3NlZCB0byB0aGUgc2V0dGVyLlxuXHQgKi9cblx0cHJvdGVjdGVkIF9vcmlnaW5hbEl0ZW1zOiBBcnJheTxMaXN0SXRlbT4gfCBPYnNlcnZhYmxlPEFycmF5PExpc3RJdGVtPj47XG5cdC8qKlxuXHQgKiBVc2VmdWwgcmVwcmVzZW50YXRpb24gb2YgdGhlIGl0ZW1zLCBzaG91bGQgYmUgYWNjZXNzZWQgdmlhIGBnZXRMaXN0SXRlbXNgLlxuXHQgKi9cblx0cHJvdGVjdGVkIF9pdGVtczogQXJyYXk8TGlzdEl0ZW0+ID0gW107XG5cdC8qKlxuXHQgKiBVc2VkIHRvIHdhaXQgZm9yIGl0ZW1zIGluIGNhc2UgdGhleSBhcmUgcGFzc2VkIHRocm91Z2ggYW4gb2JzZXJ2YWJsZS5cblx0ICovXG5cdHByb3RlY3RlZCBfaXRlbXNSZWFkeTogT2JzZXJ2YWJsZTxib29sZWFuPjtcblxuXHQvKipcblx0ICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBgRHJvcGRvd25MaXN0YC5cblx0ICovXG5cdGNvbnN0cnVjdG9yKHB1YmxpYyBlbGVtZW50UmVmOiBFbGVtZW50UmVmLCBwcm90ZWN0ZWQgaTE4bjogSTE4biwgcHJvdGVjdGVkIGFwcFJlZjogQXBwbGljYXRpb25SZWYpIHt9XG5cblx0LyoqXG5cdCAqIFJldHJpZXZlcyBhcnJheSBvZiBsaXN0IGl0ZW1zIGFuZCBpbmRleCBvZiB0aGUgc2VsZWN0ZWQgaXRlbSBhZnRlciB2aWV3IGhhcyByZW5kZXJlZC5cblx0ICogQWRkaXRpb25hbGx5LCBhbnkgT2JzZXJ2YWJsZXMgZm9yIHRoZSBgRHJvcGRvd25MaXN0YCBhcmUgaW5pdGlhbGl6ZWQuXG5cdCAqL1xuXHRuZ0FmdGVyVmlld0luaXQoKSB7XG5cdFx0dGhpcy5pbmRleCA9IHRoaXMuZ2V0TGlzdEl0ZW1zKCkuZmluZEluZGV4KGl0ZW0gPT4gaXRlbS5zZWxlY3RlZCk7XG5cdFx0dGhpcy5zZXR1cEZvY3VzT2JzZXJ2YWJsZSgpO1xuXHRcdHNldFRpbWVvdXQoKCkg