UNPKG

gentics-ui-core

Version:

This is the common core framework for the Gentics CMS and Mesh UI, and other Angular applications.

470 lines 68.6 kB
import { ChangeDetectorRef, Component, ContentChildren, ElementRef, EventEmitter, forwardRef, Input, Output, QueryList, ViewChild } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { coerceToBoolean } from '../../common/coerce-to-boolean'; import { KeyCode } from '../../common/keycodes'; import { DropdownContent } from '../dropdown-list/dropdown-content.component'; import { DropdownList } from '../dropdown-list/dropdown-list.component'; import { SelectOption, SelectOptionGroup } from './option.component'; import * as i0 from "@angular/core"; import * as i1 from "../dropdown-list/dropdown-list.component"; import * as i2 from "../dropdown-list/dropdown-content.component"; import * as i3 from "../checkbox/checkbox.component"; import * as i4 from "../button/button.component"; import * as i5 from "../dropdown-list/dropdown-trigger.directive"; import * as i6 from "@angular/common"; import * as i7 from "../icon/icon.directive"; const GTX_SELECT_VALUE_ACCESSOR = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => Select), multi: true }; /** * A Select form control which works with any kind of value - as opposed to the native HTML `<select>` which only works * with strings. The Select control depends on the [`<gtx-overlay-host>`](#/overlay-host) being present in the app. * * ```html * <gtx-select label="Choose an option" [(ngModel)]="selectVal"> * <gtx-option *ngFor="let item of options" * [value]="item" * [disabled]="item.disabled">{{ item.label }}</gtx-option> * </gtx-select> * ``` * */ export class Select { constructor(changeDetector, elementRef) { this.changeDetector = changeDetector; this.elementRef = elementRef; /** * Sets the select box to be auto-focused. Handled by `AutofocusDirective`. */ this.autofocus = false; /** * When set to true, allows multiple options to be selected. In this case, the input value should be * an array of strings; events will emit an array of strings. */ this.multiple = false; /** * Sets the required state. */ this.required = false; /** * Placeholder which is shown if nothing is selected. */ this.placeholder = ''; /** * Blur event. */ this.blur = new EventEmitter(); /** * Focus event. */ this.focus = new EventEmitter(); /** * Change event. */ this.change = new EventEmitter(); // An array of abstracted containers for options, which allows us to treat options and groups in a // consistent way. this.optionGroups = []; this.subscriptions = []; this.selectedOptions = []; this.viewValue = ''; // Keeps track of the selected option. Two dimensional because options may be nested inside groups. The first // value is the index of the group (-1 is the default "no group" group), and the second number is the index // of the option within that group. this.selectedIndex = [0, -1]; this._clearable = false; this._disabled = false; this.preventDeselect = false; // ValueAccessor members this.onChange = () => { }; this.onTouched = () => { }; } /** If true the clear button is displayed, which allows the user to clear the selection. */ get clearable() { return this._clearable; } set clearable(val) { this._clearable = coerceToBoolean(val); } /** * Sets the disabled state. */ get disabled() { return this._disabled; } set disabled(value) { this._disabled = coerceToBoolean(value); } ngAfterViewInit() { // Update the value if there are any changes to the options this.subscriptions.push(this._selectOptions.changes.subscribe(() => { this.writeValue(this.value); this.optionGroups = this.buildOptionGroups(); this.selectedOptions = this.getInitiallySelectedOptions(); })); this.elementRef.nativeElement.querySelector('gtx-dropdown-list') .addEventListener('keydown', this.handleKeydown.bind(this)); } ngAfterContentInit() { this.optionGroups = this.buildOptionGroups(); this.selectedOptions = this.getInitiallySelectedOptions(); this.updateViewValue(); } ngOnDestroy() { this.subscriptions.forEach(s => s.unsubscribe()); } /** * Event handler for when one of the Materialize-generated LI elements is clicked. */ selectItem(groupIndex, optionIndex) { const option = this.optionGroups[groupIndex] && this.optionGroups[groupIndex].options[optionIndex]; if (!this.optionGroups[groupIndex].disabled && option && !option.disabled) { this.toggleSelectedOption(option); const selectedValues = this.selectedOptions.map(o => o.value); this.value = this.multiple ? selectedValues : selectedValues[0]; this.onChange(); this.change.emit(this.value); this.updateViewValue(); this.scrollToSelectedOption(); } } inputBlur(e) { e.stopPropagation(); this.onTouched(); this.blur.emit(this.value); } /** * Select the initial value when the dropdown is opened. */ dropdownOpened() { if (0 < this.selectedOptions.length) { this.preventDeselect = true; const selected = this.selectedOptions[0]; this.selectedIndex = this.getIndexFromSelectOption(selected); setTimeout(() => { this.scrollToSelectedOption(); this.preventDeselect = false; }, 100); } } /** * Handle keydown events to enable keyboard navigation and selection of options. */ handleKeydown(event) { if (event.ctrlKey || event.altKey || event.metaKey) { return; } const keyCode = event.keyCode; switch (keyCode) { case KeyCode.UpArrow: this.updateSelectedIndex(this.getPreviousIndex(this.selectedIndex)); break; case KeyCode.DownArrow: this.updateSelectedIndex(this.getNextIndex(this.selectedIndex)); break; case KeyCode.PageUp: case KeyCode.Home: this.updateSelectedIndex(this.getFirstIndex()); break; case KeyCode.PageDown: case KeyCode.End: this.updateSelectedIndex(this.getLastIndex()); break; case KeyCode.Enter: case KeyCode.Space: if (!this.dropdownList.isOpen) { this.dropdownList.openDropdown(); } else { this.selectItem(this.selectedIndex[0], this.selectedIndex[1]); if (!this.multiple) { this.dropdownList.closeDropdown(); } } break; default: // Other keys are treated as if the user is trying to jump to an option by character const indexOfMatch = this.searchByKey(event.key); if (indexOfMatch) { this.updateSelectedIndex(indexOfMatch); } } } isSelected(option) { return -1 < this.selectedOptions.indexOf(option); } deselect() { if (!this.preventDeselect) { this.selectedIndex = [0, -1]; } } // ValueAccessor members writeValue(value) { this.value = value; if (this._selectOptions) { // select any options matching the initial value this.selectedOptions = []; const optionsArray = this._selectOptions.toArray(); if (this.multiple && this.value instanceof Array) { optionsArray.forEach(o => { if (-1 < this.value.indexOf(o.value)) { this.selectedOptions.push(o); } }); } else { this.selectedOptions = optionsArray.filter(o => this.value === o.value); } this.updateViewValue(); } } registerOnChange(fn) { this.onChange = () => { fn(this.value); }; } registerOnTouched(fn) { this.onTouched = fn; } setDisabledState(isDisabled) { this._disabled = isDisabled; this.changeDetector.markForCheck(); } /** Clears the selected value and emits `null` with the `change` event. */ clearSelection() { this.selectedOptions = []; this.value = null; this.change.emit(this.value); this.onChange(); this.updateViewValue(); } /** * Given a SelectOption, returns the position in the 2D selectedIndex array. */ getIndexFromSelectOption(selected) { if (selected) { let selectedGroup = 0; let selectedOption = 0; for (let i = 0; i < this.optionGroups.length; i++) { const group = this.optionGroups[i]; selectedGroup = i; for (let j = 0; j < group.options.length; j++) { const option = group.options[j]; selectedOption = j; if (option === selected) { return [selectedGroup, selectedOption]; } } } } else { return [0, 0]; } } /** * Once the contents have been compiled, we can build up the optionGroups array, grouping options into * a "default" group, i.e. the group of options which are not children of a <gtx-optgroup>, and then any * other groups as specified by optgroups. */ buildOptionGroups() { const groups = this._selectOptionGroups.map(g => { return { get options() { return g.options; }, get label() { return g.label; }, get disabled() { return g.disabled; }, isDefaultGroup: false }; }); if (this._selectOptions.length) { groups.unshift({ options: this._selectOptions.toArray(), label: '', isDefaultGroup: true, disabled: false }); } return groups; } /** * Select any options which match the value passed in via the `value` attribute. */ getInitiallySelectedOptions() { let selectedOptions = []; const flatOptionsList = this.optionGroups.reduce((options, group) => options.concat(group.options), []); if (this.value !== undefined) { if (this.multiple) { if (this.value instanceof Array) { selectedOptions = flatOptionsList.filter(o => -1 < this.value.indexOf(o.value)); } } else { selectedOptions = flatOptionsList.filter(o => this.value === o.value) || []; return flatOptionsList.filter(o => this.value === o.value) || []; } } return selectedOptions; } /** * Toggle the selection of the given SelectOption, taking into account whether this is a multiple * select. */ toggleSelectedOption(option) { if (!this.multiple) { this.selectedOptions = []; } let index = this.selectedOptions.indexOf(option); if (-1 < index) { // de-select the existing option this.selectedOptions.splice(index, 1); } else { this.selectedOptions.push(option); } } updateViewValue() { this.viewValue = this.selectedOptions.map(o => o.viewValue).join(', '); this.changeDetector.markForCheck(); } /** * When a list of options is too long, there will be a scroll bar. This method ensures that the currently-selected * options is scrolled into view in the options list. */ scrollToSelectedOption() { setTimeout(() => { const container = this.dropdownContent.elementRef.nativeElement; const selectedItem = container.querySelector('li.selected'); if (selectedItem) { const belowContainer = container.offsetHeight + container.scrollTop < selectedItem.offsetTop + selectedItem.offsetHeight; const aboveContainer = selectedItem.offsetTop < container.scrollTop; if (belowContainer) { container.scrollTop = selectedItem.offsetTop + selectedItem.offsetHeight - container.offsetHeight; } if (aboveContainer) { container.scrollTop = selectedItem.offsetTop; } } }); } /** * Searches through the available options and locates the next option with a viewValue whose first character * matches the character passed in. Useful for jumping to options quickly by typing the first letter of the * option view value. */ searchByKey(key) { const keyUpperCase = key.toLocaleUpperCase(); const totalOptionCount = this.optionGroups.reduce((total, group) => total + group.options.length, 0); let currentIndex = this.selectedIndex.slice(); for (let counter = 0; counter < totalOptionCount; counter++) { currentIndex = this.getNextIndex(currentIndex); const option = this.optionGroups[currentIndex[0]].options[currentIndex[1]]; const firstLetterUppercase = option.viewValue.charAt(0).toLocaleUpperCase(); if (firstLetterUppercase === keyUpperCase) { return currentIndex; } } } getFirstIndex() { return [0, 0]; } getLastIndex() { const lastGroupIndex = this.optionGroups.length - 1; return [lastGroupIndex, this.optionGroups[lastGroupIndex].options.length - 1]; } getNextIndex(currentIndex) { let nextIndex = currentIndex.slice(); const isLastGroup = currentIndex[0] === this.optionGroups.length - 1; const isLastOptionInGroup = currentIndex[1] === this.optionGroups[currentIndex[0]].options.length - 1; if (isLastOptionInGroup) { if (isLastGroup) { nextIndex = this.getFirstIndex(); } else { nextIndex[0]++; nextIndex[1] = 0; } } else { nextIndex[1]++; } return nextIndex; } getPreviousIndex(currentIndex) { let nextIndex = currentIndex.slice(); if (currentIndex[0] <= 0) { if (0 < currentIndex[1]) { nextIndex[1]--; } else { nextIndex = this.getLastIndex(); } } else { if (0 < currentIndex[1]) { nextIndex[1]--; } else { nextIndex[0]--; nextIndex[1] = this.optionGroups[currentIndex[0]].options.length - 1; } } return nextIndex; } /** * Sets the `selectedOptions` array to contain the single option at the selectedIndex. */ updateSelectedIndex(index) { this.selectedIndex = index; const options = this.optionGroups[index[0]].options; if (options && 0 <= index[1] && index[1] < options.length) { if (!this.multiple) { this.selectItem(index[0], index[1]); } else { this.scrollToSelectedOption(); } } } } /** @nocollapse */ Select.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: Select, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); /** @nocollapse */ Select.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: Select, selector: "gtx-select", inputs: { autofocus: "autofocus", clearable: "clearable", disabled: "disabled", multiple: "multiple", required: "required", value: "value", placeholder: "placeholder", label: "label" }, outputs: { blur: "blur", focus: "focus", change: "change" }, providers: [GTX_SELECT_VALUE_ACCESSOR], queries: [{ propertyName: "_selectOptions", predicate: SelectOption }, { propertyName: "_selectOptionGroups", predicate: SelectOptionGroup }], viewQueries: [{ propertyName: "dropdownList", first: true, predicate: DropdownList, descendants: true, static: true }, { propertyName: "dropdownContent", first: true, predicate: DropdownContent, descendants: true, static: true }], ngImport: i0, template: "<gtx-dropdown-list width=\"expand\"\n belowTrigger=\"false\"\n [sticky]=\"multiple\"\n [disabled]=\"disabled\"\n (open)=\"dropdownOpened()\"\n [class.clearable]=\"_clearable\">\n\n <gtx-dropdown-trigger [class.with-label]=\"label != null\">\n <div class=\"view-value select-input\"\n [attr.tabindex]=\"disabled ? null : 0\"\n [attr.disabled]=\"disabled ? true : null\"\n (blur)=\"inputBlur($event)\"\n #viewValueContainer>\n <div *ngIf=\"selectedOptions.length > 0\">{{ viewValue }}</div>\n <div class=\"placeholder\" *ngIf=\"placeholder && selectedOptions.length == 0\">{{ placeholder }}</div>\n <div *ngIf=\"!placeholder && selectedOptions.length == 0\"></div>\n <icon>arrow_drop_down</icon>\n </div><label *ngIf=\"label != null\" (click)=\"viewValueContainer.focus()\">{{ label }}</label>\n </gtx-dropdown-trigger>\n\n <gtx-dropdown-content (keydown)=\"handleKeydown($event)\">\n <ul class=\"select-options\"\n (click)=\"viewValueContainer.focus()\"\n (mouseover)=\"deselect()\">\n <ng-template ngFor [ngForOf]=\"optionGroups\" let-group let-groupIndex=\"index\">\n <li *ngIf=\"!group.isDefaultGroup\"\n class=\"group-label\">{{ group.label }}</li>\n <li *ngFor=\"let option of group.options; let optionIndex = index\"\n [class.disabled]=\"group.disabled || option.disabled\"\n [class.selected]=\"selectedIndex[0] === groupIndex && selectedIndex[1] === optionIndex\"\n class=\"select-option\"\n (click)=\"selectItem(groupIndex, optionIndex)\">\n <gtx-checkbox *ngIf=\"multiple\"\n [checked]=\"isSelected(option)\"\n (change)=\"selectItem(groupIndex, optionIndex)\"></gtx-checkbox>\n <icon *ngIf=\"option.icon\" class=\"material-icons\">{{option.icon}}</icon>\n {{ option.viewValue }}\n </li>\n </ng-template>\n </ul>\n </gtx-dropdown-content>\n\n</gtx-dropdown-list>\n\n<gtx-button icon\n class=\"clear-button\"\n *ngIf=\"_clearable\"\n type=\"secondary\"\n [disabled]=\"_disabled\"\n (click)=\"!_disabled && clearSelection()\">\n <icon>clear</icon>\n</gtx-button>\n", components: [{ type: i1.DropdownList, selector: "gtx-dropdown-list", inputs: ["align", "width", "belowTrigger", "sticky", "closeOnEscape", "disabled"], outputs: ["open", "close"] }, { type: i2.DropdownContent, selector: "gtx-dropdown-content" }, { type: i3.Checkbox, selector: "gtx-checkbox", inputs: ["autofocus", "checked", "indeterminate", "disabled", "id", "label", "name", "required", "value"], outputs: ["blur", "focus", "change"] }, { type: i4.Button, selector: "gtx-button", inputs: ["autofocus", "size", "type", "flat", "icon", "disabled", "submit"] }], directives: [{ type: i5.DropdownTriggerDirective, selector: "gtx-dropdown-trigger" }, { type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i7.Icon, selector: "icon" }, { type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: Select, decorators: [{ type: Component, args: [{ selector: 'gtx-select', providers: [GTX_SELECT_VALUE_ACCESSOR], template: "<gtx-dropdown-list width=\"expand\"\n belowTrigger=\"false\"\n [sticky]=\"multiple\"\n [disabled]=\"disabled\"\n (open)=\"dropdownOpened()\"\n [class.clearable]=\"_clearable\">\n\n <gtx-dropdown-trigger [class.with-label]=\"label != null\">\n <div class=\"view-value select-input\"\n [attr.tabindex]=\"disabled ? null : 0\"\n [attr.disabled]=\"disabled ? true : null\"\n (blur)=\"inputBlur($event)\"\n #viewValueContainer>\n <div *ngIf=\"selectedOptions.length > 0\">{{ viewValue }}</div>\n <div class=\"placeholder\" *ngIf=\"placeholder && selectedOptions.length == 0\">{{ placeholder }}</div>\n <div *ngIf=\"!placeholder && selectedOptions.length == 0\"></div>\n <icon>arrow_drop_down</icon>\n </div><label *ngIf=\"label != null\" (click)=\"viewValueContainer.focus()\">{{ label }}</label>\n </gtx-dropdown-trigger>\n\n <gtx-dropdown-content (keydown)=\"handleKeydown($event)\">\n <ul class=\"select-options\"\n (click)=\"viewValueContainer.focus()\"\n (mouseover)=\"deselect()\">\n <ng-template ngFor [ngForOf]=\"optionGroups\" let-group let-groupIndex=\"index\">\n <li *ngIf=\"!group.isDefaultGroup\"\n class=\"group-label\">{{ group.label }}</li>\n <li *ngFor=\"let option of group.options; let optionIndex = index\"\n [class.disabled]=\"group.disabled || option.disabled\"\n [class.selected]=\"selectedIndex[0] === groupIndex && selectedIndex[1] === optionIndex\"\n class=\"select-option\"\n (click)=\"selectItem(groupIndex, optionIndex)\">\n <gtx-checkbox *ngIf=\"multiple\"\n [checked]=\"isSelected(option)\"\n (change)=\"selectItem(groupIndex, optionIndex)\"></gtx-checkbox>\n <icon *ngIf=\"option.icon\" class=\"material-icons\">{{option.icon}}</icon>\n {{ option.viewValue }}\n </li>\n </ng-template>\n </ul>\n </gtx-dropdown-content>\n\n</gtx-dropdown-list>\n\n<gtx-button icon\n class=\"clear-button\"\n *ngIf=\"_clearable\"\n type=\"secondary\"\n [disabled]=\"_disabled\"\n (click)=\"!_disabled && clearSelection()\">\n <icon>clear</icon>\n</gtx-button>\n" }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { autofocus: [{ type: Input }], clearable: [{ type: Input }], disabled: [{ type: Input }], multiple: [{ type: Input }], required: [{ type: Input }], value: [{ type: Input }], placeholder: [{ type: Input }], label: [{ type: Input }], blur: [{ type: Output }], focus: [{ type: Output }], change: [{ type: Output }], dropdownList: [{ type: ViewChild, args: [DropdownList, { static: true }] }], dropdownContent: [{ type: ViewChild, args: [DropdownContent, { static: true }] }], _selectOptions: [{ type: ContentChildren, args: [SelectOption, { descendants: false }] }], _selectOptionGroups: [{ type: ContentChildren, args: [SelectOptionGroup, { descendants: false }] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VsZWN0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3NlbGVjdC9zZWxlY3QuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvc2VsZWN0L3NlbGVjdC50cGwuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0gsaUJBQWlCLEVBQ2pCLFNBQVMsRUFDVCxlQUFlLEVBQ2YsVUFBVSxFQUNWLFlBQVksRUFDWixVQUFVLEVBQ1YsS0FBSyxFQUNMLE1BQU0sRUFDTixTQUFTLEVBQ1QsU0FBUyxFQUNaLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBdUIsaUJBQWlCLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUd2RSxPQUFPLEVBQUMsZUFBZSxFQUFDLE1BQU0sZ0NBQWdDLENBQUM7QUFDL0QsT0FBTyxFQUFDLE9BQU8sRUFBQyxNQUFNLHVCQUF1QixDQUFDO0FBQzlDLE9BQU8sRUFBQyxlQUFlLEVBQUMsTUFBTSw2Q0FBNkMsQ0FBQztBQUM1RSxPQUFPLEVBQUMsWUFBWSxFQUFDLE1BQU0sMENBQTBDLENBQUM7QUFDdEUsT0FBTyxFQUFDLFlBQVksRUFBRSxpQkFBaUIsRUFBQyxNQUFNLG9CQUFvQixDQUFDOzs7Ozs7Ozs7QUFFbkUsTUFBTSx5QkFBeUIsR0FBRztJQUM5QixPQUFPLEVBQUUsaUJBQWlCO0lBQzFCLFdBQVcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDO0lBQ3JDLEtBQUssRUFBRSxJQUFJO0NBQ2QsQ0FBQztBQVdGOzs7Ozs7Ozs7Ozs7R0FZRztBQU1ILE1BQU0sT0FBTyxNQUFNO0lBMEZmLFlBQW9CLGNBQWlDLEVBQ2pDLFVBQXNCO1FBRHRCLG1CQUFjLEdBQWQsY0FBYyxDQUFtQjtRQUNqQyxlQUFVLEdBQVYsVUFBVSxDQUFZO1FBMUYxQzs7V0FFRztRQUNNLGNBQVMsR0FB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ZixcbiAgICBDb21wb25lbnQsXG4gICAgQ29udGVudENoaWxkcmVuLFxuICAgIEVsZW1lbnRSZWYsXG4gICAgRXZlbnRFbWl0dGVyLFxuICAgIGZvcndhcmRSZWYsXG4gICAgSW5wdXQsXG4gICAgT3V0cHV0LFxuICAgIFF1ZXJ5TGlzdCxcbiAgICBWaWV3Q2hpbGRcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge0NvbnRyb2xWYWx1ZUFjY2Vzc29yLCBOR19WQUxVRV9BQ0NFU1NPUn0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHtTdWJzY3JpcHRpb259IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQge2NvZXJjZVRvQm9vbGVhbn0gZnJvbSAnLi4vLi4vY29tbW9uL2NvZXJjZS10by1ib29sZWFuJztcbmltcG9ydCB7S2V5Q29kZX0gZnJvbSAnLi4vLi4vY29tbW9uL2tleWNvZGVzJztcbmltcG9ydCB7RHJvcGRvd25Db250ZW50fSBmcm9tICcuLi9kcm9wZG93bi1saXN0L2Ryb3Bkb3duLWNvbnRlbnQuY29tcG9uZW50JztcbmltcG9ydCB7RHJvcGRvd25MaXN0fSBmcm9tICcuLi9kcm9wZG93bi1saXN0L2Ryb3Bkb3duLWxpc3QuY29tcG9uZW50JztcbmltcG9ydCB7U2VsZWN0T3B0aW9uLCBTZWxlY3RPcHRpb25Hcm91cH0gZnJvbSAnLi9vcHRpb24uY29tcG9uZW50JztcblxuY29uc3QgR1RYX1NFTEVDVF9WQUxVRV9BQ0NFU1NPUiA9IHtcbiAgICBwcm92aWRlOiBOR19WQUxVRV9BQ0NFU1NPUixcbiAgICB1c2VFeGlzdGluZzogZm9yd2FyZFJlZigoKSA9PiBTZWxlY3QpLFxuICAgIG11bHRpOiB0cnVlXG59O1xuXG5leHBvcnQgaW50ZXJmYWNlIE5vcm1hbGl6ZWRPcHRpb25Hcm91cCB7XG4gICAgb3B0aW9uczogU2VsZWN0T3B0aW9uW107XG4gICAgbGFiZWw6IHN0cmluZztcbiAgICBkaXNhYmxlZDogYm9vbGVhbjtcbiAgICBpc0RlZmF1bHRHcm91cDogYm9vbGVhbjtcbn1cblxuZXhwb3J0IHR5cGUgU2VsZWN0ZWRTZWxlY3RPcHRpb24gPSBbbnVtYmVyLCBudW1iZXJdO1xuXG4vKipcbiAqIEEgU2VsZWN0IGZvcm0gY29udHJvbCB3aGljaCB3b3JrcyB3aXRoIGFueSBraW5kIG9mIHZhbHVlIC0gYXMgb3Bwb3NlZCB0byB0aGUgbmF0aXZlIEhUTUwgYDxzZWxlY3Q+YCB3aGljaCBvbmx5IHdvcmtzXG4gKiB3aXRoIHN0cmluZ3MuIFRoZSBTZWxlY3QgY29udHJvbCBkZXBlbmRzIG9uIHRoZSBbYDxndHgtb3ZlcmxheS1ob3N0PmBdKCMvb3ZlcmxheS1ob3N0KSBiZWluZyBwcmVzZW50IGluIHRoZSBhcHAuXG4gKlxuICogYGBgaHRtbFxuICogPGd0eC1zZWxlY3QgbGFiZWw9XCJDaG9vc2UgYW4gb3B0aW9uXCIgWyhuZ01vZGVsKV09XCJzZWxlY3RWYWxcIj5cbiAqICAgICA8Z3R4LW9wdGlvbiAqbmdGb3I9XCJsZXQgaXRlbSBvZiBvcHRpb25zXCJcbiAqICAgICAgICAgICAgICAgICBbdmFsdWVdPVwiaXRlbVwiXG4gKiAgICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIml0ZW0uZGlzYWJsZWRcIj57eyBpdGVtLmxhYmVsIH19PC9ndHgtb3B0aW9uPlxuICogPC9ndHgtc2VsZWN0PlxuICogYGBgXG4gKlxuICovXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogJ2d0eC1zZWxlY3QnLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9zZWxlY3QudHBsLmh0bWwnLFxuICAgIHByb3ZpZGVyczogW0dUWF9TRUxFQ1RfVkFMVUVfQUNDRVNTT1JdXG59KVxuZXhwb3J0IGNsYXNzIFNlbGVjdCBpbXBsZW1lbnRzIENvbnRyb2xWYWx1ZUFjY2Vzc29yIHtcbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBzZWxlY3QgYm94IHRvIGJlIGF1dG8tZm9jdXNlZC4gSGFuZGxlZCBieSBgQXV0b2ZvY3VzRGlyZWN0aXZlYC5cbiAgICAgKi9cbiAgICBASW5wdXQoKSBhdXRvZm9jdXM6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIC8qKiBJZiB0cnVlIHRoZSBjbGVhciBidXR0b24gaXMgZGlzcGxheWVkLCB3aGljaCBhbGxvd3MgdGhlIHVzZXIgdG8gY2xlYXIgdGhlIHNlbGVjdGlvbi4gKi9cbiAgICBASW5wdXQoKVxuICAgIGdldCBjbGVhcmFibGUoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLl9jbGVhcmFibGU7XG4gICAgfVxuICAgIHNldCBjbGVhcmFibGUodmFsOiBib29sZWFuKSB7XG4gICAgICAgIHRoaXMuX2NsZWFyYWJsZSA9IGNvZXJjZVRvQm9vbGVhbih2YWwpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldHMgdGhlIGRpc2FibGVkIHN0YXRlLlxuICAgICAqL1xuICAgIEBJbnB1dCgpXG4gICAgZ2V0IGRpc2FibGVkKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGlzYWJsZWQ7XG4gICAgfVxuICAgIHNldCBkaXNhYmxlZCh2YWx1ZTogYm9vbGVhbikge1xuICAgICAgICB0aGlzLl9kaXNhYmxlZCA9IGNvZXJjZVRvQm9vbGVhbih2YWx1ZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogV2hlbiBzZXQgdG8gdHJ1ZSwgYWxsb3dzIG11bHRpcGxlIG9wdGlvbnMgdG8gYmUgc2VsZWN0ZWQuIEluIHRoaXMgY2FzZSwgdGhlIGlucHV0IHZhbHVlIHNob3VsZCBiZVxuICAgICAqIGFuIGFycmF5IG9mIHN0cmluZ3M7IGV2ZW50cyB3aWxsIGVtaXQgYW4gYXJyYXkgb2Ygc3RyaW5ncy5cbiAgICAgKi9cbiAgICBASW5wdXQoKSBtdWx0aXBsZTogYm9vbGVhbiA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgcmVxdWlyZWQgc3RhdGUuXG4gICAgICovXG4gICAgQElucHV0KCkgcmVxdWlyZWQ6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqIFRoZSB2YWx1ZSBkZXRlcm1pbmVzIHdoaWNoIG9mIHRoZSBvcHRpb25zIGFyZSBzZWxlY3RlZC5cbiAgICAgKi9cbiAgICBASW5wdXQoKSB2YWx1ZTogYW55O1xuXG4gICAgLyoqXG4gICAgICogUGxhY2Vob2xkZXIgd2hpY2ggaXMgc2hvd24gaWYgbm90aGluZyBpcyBzZWxlY3RlZC5cbiAgICAgKi9cbiAgICBASW5wdXQoKSBwbGFjZWhvbGRlcjogc3RyaW5nID0gJyc7XG5cbiAgICAvKipcbiAgICAgKiBBIHRleHQgbGFiZWwgZm9yIHRoZSBpbnB1dC5cbiAgICAgKi9cbiAgICBASW5wdXQoKSBsYWJlbDogc3RyaW5nO1xuXG4gICAgLyoqXG4gICAgICogQmx1ciBldmVudC5cbiAgICAgKi9cbiAgICBAT3V0cHV0KCkgYmx1ciA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xuICAgIC8qKlxuICAgICAqIEZvY3VzIGV2ZW50LlxuICAgICAqL1xuICAgIEBPdXRwdXQoKSBmb2N1cyA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xuICAgIC8qKlxuICAgICAqIENoYW5nZSBldmVudC5cbiAgICAgKi9cbiAgICBAT3V0cHV0KCkgY2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XG5cbiAgICAvLyBBbiBhcnJheSBvZiBhYnN0cmFjdGVkIGNvbnRhaW5lcnMgZm9yIG9wdGlvbnMsIHdoaWNoIGFsbG93cyB1cyB0byB0cmVhdCBvcHRpb25zIGFuZCBncm91cHMgaW4gYVxuICAgIC8vIGNvbnNpc3RlbnQgd2F5LlxuICAgIG9wdGlvbkdyb3VwczogTm9ybWFsaXplZE9wdGlvbkdyb3VwW10gPSBbXTtcblxuICAgIHN1YnNjcmlwdGlvbnM6IFN1YnNjcmlwdGlvbltdID0gW107XG4gICAgc2VsZWN0ZWRPcHRpb25zOiBTZWxlY3RPcHRpb25bXSA9IFtdO1xuICAgIHZpZXdWYWx1ZTogc3RyaW5nID0gJyc7XG5cbiAgICAvLyBLZWVwcyB0cmFjayBvZiB0aGUgc2VsZWN0ZWQgb3B0aW9uLiBUd28gZGltZW5zaW9uYWwgYmVjYXVzZSBvcHRpb25zIG1heSBiZSBuZXN0ZWQgaW5zaWRlIGdyb3Vwcy4gVGhlIGZpcnN0XG4gICAgLy8gdmFsdWUgaXMgdGhlIGluZGV4IG9mIHRoZSBncm91cCAoLTEgaXMgdGhlIGRlZmF1bHQgXCJubyBncm91cFwiIGdyb3VwKSwgYW5kIHRoZSBzZWNvbmQgbnVtYmVyIGlzIHRoZSBpbmRleFxuICAgIC8vIG9mIHRoZSBvcHRpb24gd2l0aGluIHRoYXQgZ3JvdXAuXG4gICAgc2VsZWN0ZWRJbmRleDogU2VsZWN0ZWRTZWxlY3RPcHRpb24gPSBbMCwgLTFdO1xuXG4gICAgX2NsZWFyYWJsZTogYm9vbGVhbiA9IGZhbHNlO1xuICAgIF9kaXNhYmxlZDogYm9vbGVhbiA9IGZhbHNlO1xuICAgIHByaXZhdGUgcHJldmVudERlc2VsZWN0OiBib29sZWFuID0gZmFsc2U7XG4gICAgQFZpZXdDaGlsZChEcm9wZG93bkxpc3QsIHsgc3RhdGljOiB0cnVlIH0pIHByaXZhdGUgZHJvcGRvd25MaXN0OiBEcm9wZG93bkxpc3Q7XG4gICAgQFZpZXdDaGlsZChEcm9wZG93bkNvbnRlbnQsIHsgc3RhdGljOiB0cnVlIH0pIHByaXZhdGUgZHJvcGRvd25Db250ZW50OiBEcm9wZG93bkNvbnRlbnQ7XG4gICAgQENvbnRlbnRDaGlsZHJlbihTZWxlY3RPcHRpb24sIHsgZGVzY2VuZGFudHM6IGZhbHNlIH0pIHByaXZhdGUgX3NlbGVjdE9wdGlvbnM6IFF1ZXJ5TGlzdDxTZWxlY3RPcHRpb24+O1xuICAgIEBDb250ZW50Q2hpbGRyZW4oU2VsZWN0T3B0aW9uR3JvdXAsIHsgZGVzY2VuZGFudHM6IGZhbHNlIH0pIHByaXZhdGUgX3NlbGVjdE9wdGlvbkdyb3VwczogUXVlcnlMaXN0PFNlbGVjdE9wdGlvbkdyb3VwPjtcblxuICAgIC8vIFZhbHVlQWNjZXNzb3IgbWVtYmVyc1xuICAgIG9uQ2hhbmdlID0gKCk6IHZvaWQgPT4geyB9O1xuICAgIG9uVG91Y2hlZCA9ICgpOiB2b2lkID0+IHsgfTtcblxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgY2hhbmdlRGV0ZWN0b3I6IENoYW5nZURldGVjdG9yUmVmLFxuICAgICAgICAgICAgICAgIHByaXZhdGUgZWxlbWVudFJlZjogRWxlbWVudFJlZikgeyB9XG5cbiAgICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG4gICAgICAgIC8vIFVwZGF0ZSB0aGUgdmFsdWUgaWYgdGhlcmUgYXJlIGFueSBjaGFuZ2VzIHRvIHRoZSBvcHRpb25zXG4gICAgICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5wdXNoKFxuICAgICAgICAgICAgdGhpcy5fc2VsZWN0T3B0aW9ucy5jaGFuZ2VzLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy53cml0ZVZhbHVlKHRoaXMudmFsdWUpO1xuICAgICAgICAgICAgICAgIHRoaXMub3B0aW9uR3JvdXBzID0gdGhpcy5idWlsZE9wdGlvbkdyb3VwcygpO1xuICAgICAgICAgICAgICAgIHRoaXMuc2VsZWN0ZWRPcHRpb25zID0gdGhpcy5nZXRJbml0aWFsbHlTZWxlY3RlZE9wdGlvbnMoKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQucXVlcnlTZWxlY3RvcignZ3R4LWRyb3Bkb3duLWxpc3QnKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuYWRkRXZlbnRMaXN0ZW5lcigna2V5ZG93bicsIHRoaXMuaGFuZGxlS2V5ZG93bi5iaW5kKHRoaXMpKTtcbiAgICB9XG5cbiAgICBuZ0FmdGVyQ29udGVudEluaXQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMub3B0aW9uR3JvdXBzID0gdGhpcy5idWlsZE9wdGlvbkdyb3VwcygpO1xuICAgICAgICB0aGlzLnNlbGVjdGVkT3B0aW9ucyA9IHRoaXMuZ2V0SW5pdGlhbGx5U2VsZWN0ZWRPcHRpb25zKCk7XG4gICAgICAgIHRoaXMudXBkYXRlVmlld1ZhbHVlKCk7XG4gICAgfVxuXG4gICAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5mb3JFYWNoKHMgPT4gcy51bnN1YnNjcmliZSgpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBFdmVudCBoYW5kbGVyIGZvciB3aGVuIG9uZSBvZiB0aGUgTWF0ZXJpYWxpemUtZ2VuZXJhdGVkIExJIGVsZW1lbnRzIGlzIGNsaWNrZWQuXG4gICAgICovXG4gICAgc2VsZWN0SXRlbShncm91cEluZGV4OiBudW1iZXIsIG9wdGlvbkluZGV4OiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgY29uc3Qgb3B0aW9uID0gdGhpcy5vcHRpb25Hcm91cHNbZ3JvdXBJbmRleF0gJiYgdGhpcy5vcHRpb25Hcm91cHNbZ3JvdXBJbmRleF0ub3B0aW9uc1tvcHRpb25JbmRleF07XG4gICAgICAgIGlmICghdGhpcy5vcHRpb25Hcm91cHNbZ3JvdXBJbmRleF0uZGlzYWJsZWQgJiYgb3B0aW9uICYmICFvcHRpb24uZGlzYWJsZWQpIHtcbiAgICAgICAgICAgIHRoaXMudG9nZ2xlU2VsZWN0ZWRPcHRpb24ob3B0aW9uKTtcbiAgICAgICAgICAgIGNvbnN0IHNlbGVjdGVkVmFsdWVzID0gdGhpcy5zZWxlY3RlZE9wdGlvbnMubWFwKG8gPT4gby52YWx1ZSk7XG4gICAgICAgICAgICB0aGlzLnZhbHVlID0gdGhpcy5tdWx0aXBsZSA/IHNlbGVjdGVkVmFsdWVzIDogc2VsZWN0ZWRWYWx1ZXNbMF07XG4gICAgICAgICAgICB0aGlzLm9uQ2hhbmdlKCk7XG4gICAgICAgICAgICB0aGlzLmNoYW5nZS5lbWl0KHRoaXMudmFsdWUpO1xuICAgICAgICAgICAgdGhpcy51cGRhdGVWaWV3VmFsdWUoKTtcbiAgICAgICAgICAgIHRoaXMuc2Nyb2xsVG9TZWxlY3RlZE9wdGlvbigpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaW5wdXRCbHVyKGU6IEV2ZW50KTogdm9pZCB7XG4gICAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgIHRoaXMub25Ub3VjaGVkKCk7XG4gICAgICAgIHRoaXMuYmx1ci5lbWl0KHRoaXMudmFsdWUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNlbGVjdCB0aGUgaW5pdGlhbCB2YWx1ZSB3aGVuIHRoZSBkcm9wZG93biBpcyBvcGVuZWQuXG4gICAgICovXG4gICAgZ