UNPKG

@engie-group/fluid-design-system-angular

Version:

Fluid Design System Angular

547 lines 73.4 kB
import { CommonModule, DOCUMENT } from '@angular/common'; import { ChangeDetectionStrategy, Component, ContentChild, ElementRef, EventEmitter, forwardRef, Inject, Input, Output, TemplateRef, ViewChild, ViewChildren, ViewEncapsulation } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { Subject } from 'rxjs'; import { selectAnimations } from '../../shared/animations'; import { Utils } from '../../utils/utils.util'; import { FormFieldDirective } from '../form-field/form-field.directive'; import { FormItemComponent } from '../form-item/form-item.component'; import { HighlightDirective } from '../highlight/highlight.directive'; import { ListGroupComponent } from '../list-group/list-group.component'; import { ListItemComponent } from '../list-item/list-item.component'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; export class AutocompleteComponent extends FormItemComponent { /** * Autocomplete data */ set data(value) { this._data = value; this.updateList(); } get data() { return this._data; } constructor(renderer, elementRef, cdr, _document) { super(); this.renderer = renderer; this.elementRef = elementRef; this.cdr = cdr; this._document = _document; this.INPUT_BORDER_IN_PX = 3; this.LIST_OFFSET_IN_PX = 4; /** * @ignore */ this.unsubscribe = new Subject(); /** * @ignore */ this._onChange = (_) => { }; /** * @ignore */ this._onTouched = () => { }; /** * Bandaid hack to prevent a weird focusout event bug happening when * `appendTo` is set and an item is selected. For *some* reason, the focusout * event is triggered multiple times when opening the list, which causes * unexpected behavior. * * This variable allows to temporarily "disables" the `handleFocusout` handler. * * FIXME: Find an actual solution to this problem instead of a bandaid hack. * @ignore */ this.ignoreFocusout = false; /** * @ignore */ this.isOpen = false; /** * @ignore */ this.isFiltered = false; /** * Index of currently selected suggestion. -1 if no suggestion is currently selected * @ignore */ this.focusIndex = -1; this.activeIndex = -1; /** * Id of currently selected item. Null if no suggestion is currently selected * @ignore */ this.focusedItemId = null; /** * Live zone content. It will be announced by assistive technologies everytime it is changed. * @ignore */ this.liveZoneContent = ''; /** * Dropdown icon name */ this.iconName = 'keyboard_arrow_down'; /** * Whether to show number of results or no */ this.showNumberOfResults = true; /** * No results message to display */ this.noResultMessage = 'No Results'; /** * Result message, formatted like `{numberOfResults} {resultsNumberMessage}` */ this.resultsNumberMessage = 'results'; /** * Whether to show number of results or no */ this.showNoResultsMessage = true; /** * Emits value of searched value on input type */ this.search = new EventEmitter(); this.initScrollListener(); } /** * @ignore */ ngAfterContentInit() { super.ngAfterContentInit(); } /** * @ignore */ ngOnDestroy() { this.unsubscribe.next(); this.unsubscribe.complete(); this.clickListenerDisposeFct?.(); this.scrollListenerDisposeFct?.(); if (this.appendTo) { this.removeAppendedElementFromParent(); } } /** * Content of hint item and hidden. * @ignore */ createResultsMessageContent() { const elements = this.filteredData; if (elements.length === 0) { return this.noResultMessage; } return `${elements.length} ${this.resultsNumberMessage}`; } /** * Update displayed suggestions and update live zone * @private */ updateList() { if (!this.isFiltered || !this.searchText || Utils.isUndefinedOrNull(this._data)) { this.filteredData = this._data; } else { this.filteredData = this._data .filter((option) => Utils.normalizeAndSearchInText(option?.label, this.searchText)) .slice(0, this.searchLimit); } this.liveZoneContent = this.createResultsMessageContent(); this.processActiveOption(); } processActiveOption() { this.activeIndex = this.filteredData.findIndex((item) => item.label === this.searchText); } get interactedItemIndex() { if (this.focusIndex !== -1) { return this.focusIndex; } return this.activeIndex !== -1 ? this.activeIndex : 0; } scrollOnListOpening() { const element = this.selectOptions?.get(this.interactedItemIndex)?.el?.nativeElement; element.scrollIntoView({ block: 'nearest' }); } appendAndComputeListPosition() { if (!this.appendTo || !this.optionsList?.nativeElement) { return; } const focusedEl = document.activeElement; this._parentElement = this._document.querySelector(this.appendTo); this.computeListPosition(); this._parentElement.appendChild(this.optionsList.nativeElement); // The appendChild() call above might remove the focus from the currently // selected element so we restore the focus to where it was before the append. focusedEl?.focus(); } /** * @private */ computeListPosition() { if (this.optionsList?.nativeElement && this.inputRef?.nativeElement) { const inputBoundingRect = this.inputRef?.nativeElement?.getBoundingClientRect(); if (inputBoundingRect) { this.optionsList.nativeElement.style = ` position: fixed; left: ${inputBoundingRect.left - this.LIST_OFFSET_IN_PX}px; top: ${inputBoundingRect.top + inputBoundingRect.height + this.LIST_OFFSET_IN_PX + this.INPUT_BORDER_IN_PX}px; min-width: ${inputBoundingRect.width + this.LIST_OFFSET_IN_PX * 2}px; transform: scaleY(1); opacity: 1; `; } } } /** * @ignore */ removeAppendedElementFromParent() { if (this.optionsList?.nativeElement) { this.renderer.removeChild(this._parentElement, this.optionsList.nativeElement); } } /** * @ignore */ initScrollListener() { this.scrollListenerDisposeFct = this.renderer.listen('window', 'scroll', (_) => { if (this.appendTo && this.isOpen) { this.computeListPosition(); } }); } /** * @ignore */ getAdditionalClass() { return `nj-form-item--select nj-form-item--autocomplete${this.isOpen ? ' nj-form-item--open' : ''}`; } /** * Implemented as part of ControlValueAccessor. * @ignore */ registerOnChange(fn) { this._onChange = fn; } /** * Implemented as part of ControlValueAccessor. * @ignore */ registerOnTouched(fn) { this._onTouched = fn; } /** * Implemented as part of ControlValueAccessor. * @ignore */ setDisabledState(isDisabled) { if (!this.inputRef) { return; } this.isDisabled = isDisabled; } /** * Implemented as part of ControlValueAccessor. * @ignore */ writeValue(value) { this.selectedValue = value; this.searchText = value?.label ?? ''; if (this.inputRef) { this.inputRef.nativeElement.value = value?.label ?? ''; } this.cdr.markForCheck(); } /** Open the suggestion list. */ openList() { this.updateList(); this.isOpen = true; this.ignoreFocusout = true; setTimeout(() => { this.scrollOnListOpening(); if (this.appendTo) { this.appendAndComputeListPosition(); } this.ignoreFocusout = false; }); } /** Close the suggestion list. */ closeList() { this.isOpen = false; this.focusIndex = -1; this.activeIndex = -1; if (this.appendTo) { this.removeAppendedElementFromParent(); } this.cdr.markForCheck(); } /** * Toggle the suggestion list. * @ignore */ handleInputClick() { if (this.isOpen) { this.closeList(); } else { this.isFiltered = false; this.openList(); } } /** * Handle input change and save searchText * @ignore */ handleInputEvent(event) { if (event?.data === '') { return; } this.searchText = event?.target?.value; this.search.emit(this.searchText); const matchingOption = this._data.find((option) => option.label === this.searchText); if (matchingOption) { this.selectItem(matchingOption); } else { this.updateList(); setTimeout(() => { if (this.filteredData.length) { this.focusIndex = 0; this.focusFocusedOption(); } }); } } /** * @ignore */ getItemId(index) { return `${this.inputId}-item-${index}`; } /** * @ignore */ getListId() { return `${this.inputId}-list`; } /** * @ignore */ getInstructionsId() { return `${this.inputId}-instructions`; } /** * @ignore */ focusFocusedOption() { const element = this.selectOptions?.get(this.focusIndex)?.el?.nativeElement; this.focusedItemId = element?.id; element.scrollIntoView({ block: 'nearest' }); } /** * @ignore */ selectNextOption() { if (this.filteredData.length) { if (this.focusIndex !== -1) { const nextIndex = (this.focusIndex + 1) % this.filteredData.length; this.focusIndex = nextIndex; } else { this.focusIndex = this.interactedItemIndex; } this.focusFocusedOption(); } } /** * @ignore */ selectPreviousOption() { if (this.filteredData.length) { const previousIndex = this.focusIndex === 0 ? this.filteredData.length - 1 : this.focusIndex - 1; this.focusIndex = previousIndex; this.focusFocusedOption(); } } /** * @ignore */ unselectOption() { this.focusIndex = -1; this.focusedItemId = null; } /** * @ignore */ handleKeydownEvent(e) { if (e.key === 'Tab') { // Ignore Tab key to not mess up with focusout event handler return; } switch (e.key) { case 'ArrowDown': e.preventDefault(); if (!this.isOpen) { this.isFiltered = false; this.openList(); this.focusIndex = this.interactedItemIndex; this.focusFocusedOption(); } else { this.selectNextOption(); } break; case 'ArrowUp': e.preventDefault(); if (!this.isOpen) { this.isFiltered = false; this.openList(); } this.focusIndex = this.interactedItemIndex; this.selectPreviousOption(); break; case 'Escape': e.preventDefault(); if (this.isOpen) { this.closeList(); } break; case 'Enter': if (this.isOpen && this.focusIndex !== -1) { this.selectItem(this.filteredData[this.focusIndex]); } break; default: // Ignore non-character keys and shortcut combinations const keyIsPrintable = (e.key.length === 1 || e.key === 'Backspace') && !e.metaKey && !e.altKey && !e.ctrlKey; if (keyIsPrintable) { this.isFiltered = true; this.unselectOption(); if (!this.isOpen) { this.openList(); } setTimeout(() => { const matchingOption = this.getMatchinOption(); this._onChange(matchingOption); this.cdr.markForCheck(); }); } } } /** * @ignore */ getMatchinOption() { const filteredData = this._data?.filter((option) => this.searchText === option.label); return filteredData?.[0]; } /** * @ignore */ selectItem(option) { this.closeList(); if (this.inputRef) { this.inputRef.nativeElement.value = option.label; } this.searchText = option.label; this.selectedValue = option; this.unselectOption(); this._onChange(option); this.cdr.markForCheck(); } /** * Closes the suggestion list if the focus is moved outside of the autocomplete. * @ignore */ handleFocusout(e) { if (this.ignoreFocusout) { return; } if (!this.elementRef?.nativeElement.contains(e.relatedTarget) && !this.optionsList?.nativeElement.contains(e.relatedTarget)) { this.closeList(); } } /** * @ignore * @param index * @param option */ trackByOption(index, option) { if (this.trackByFn) { return this.trackByFn(index, option); } return option; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AutocompleteComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: AutocompleteComponent, isStandalone: true, selector: "nj-autocomplete", inputs: { iconName: "iconName", showNumberOfResults: "showNumberOfResults", noResultMessage: "noResultMessage", resultsNumberMessage: "resultsNumberMessage", showNoResultsMessage: "showNoResultsMessage", searchLimit: "searchLimit", appendTo: "appendTo", trackByFn: "trackByFn", data: "data", listLabel: "listLabel", inputInstructions: "inputInstructions" }, outputs: { search: "search" }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => AutocompleteComponent), multi: true } ], queries: [{ propertyName: "optionLabelTemplate", first: true, predicate: ["njAutocompleteOptionLabel"], descendants: true, read: TemplateRef }, { propertyName: "searchResultsTemplate", first: true, predicate: ["njAutocompleteSearchResults"], descendants: true, read: TemplateRef }, { propertyName: "noResultTemplate", first: true, predicate: ["njAutocompleteNoResult"], descendants: true, read: TemplateRef }], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["input"], descendants: true }, { propertyName: "optionsList", first: true, predicate: ["optionsList"], descendants: true, read: ElementRef }, { propertyName: "selectOptions", predicate: ListItemComponent, descendants: true }], usesInheritance: true, ngImport: i0, template: "<nj-form-item\n [hasError]=\"hasError\"\n [hasSuccess]=\"hasSuccess\"\n [hasHint]=\"hasHint\"\n [isDisabled]=\"isDisabled\"\n [hasCustomIcon]=\"hasCustomIcon\"\n [isFloatingLabel]=\"isFloatingLabel\"\n [iconName]=\"iconName\"\n [isSelect]=\"true\"\n [additionalClass]=\"getAdditionalClass()\"\n [inputId]=\"inputId\"\n [size]=\"size\"\n (keydown)=\"handleKeydownEvent($event)\"\n (focusout)=\"handleFocusout($event)\"\n>\n <input\n #input\n type=\"text\"\n (input)=\"handleInputEvent($event)\"\n (focus)=\"_onTouched?.()\"\n [value]=\"selectedValue?.label\"\n [attr.id]=\"inputId\"\n [disabled]=\"isDisabled\"\n autocomplete=\"off\"\n njFormField\n role=\"combobox\"\n aria-autocomplete=\"list\"\n [attr.aria-activedescendant]=\"focusedItemId\"\n [attr.aria-controls]=\"getListId()\"\n [attr.aria-expanded]=\"isOpen\"\n [attr.aria-describedby]=\"getInstructionsId()\"\n (click)=\"handleInputClick()\"\n />\n\n <ng-content njFormLabel select=\"[njFormLabel]\"></ng-content>\n\n <ng-content njFormSubscript select=\"[njFormSubscript]\"></ng-content>\n\n <ng-container njFormAdditionalContent>\n <div class=\"nj-sr-only\" aria-live=\"polite\" aria-atomic=\"true\">\n <p>{{ liveZoneContent }}</p>\n </div>\n\n <p [id]=\"getInstructionsId()\" hidden>{{ inputInstructions }}</p>\n\n <nj-list-group\n [@transformList]=\"isOpen ? 'open': 'void'\"\n *ngIf=\"isOpen\"\n class=\"nj-form-item__list nj-form-item__list--no-animate\"\n [ngClass]=\"{ 'nj-form-item__list--appended': appendTo }\"\n [isDense]=\"true\"\n [hasBorder]=\"false\"\n [isClickable]=\"true\"\n [listId]=\"getListId()\"\n isCustomSelectList\n [ariaLabel]=\"listLabel\"\n #optionsList\n (keydown)=\"appendTo ? handleKeydownEvent($event) : null\"\n (focusout)=\"appendTo ? handleFocusout($event) : null\"\n >\n <ng-content select=\"[njAutocompleteAdditional]\"> </ng-content>\n\n <!-- Number of suggestions -->\n <ng-container\n *ngIf=\"isFiltered && showNumberOfResults && filteredData?.length\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n searchResultsTemplate ? searchResultsTemplate : defaultSearchResults\n \"\n [ngTemplateOutletContext]=\"{\n numberOfFilteredData: filteredData.length\n }\"\n ></ng-container>\n </ng-container>\n\n <!-- No suggestions -->\n <ng-container\n *ngIf=\"isFiltered && showNoResultsMessage && !filteredData?.length\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n noResultTemplate ? noResultTemplate : defaultNoResults\n \"\n ></ng-container>\n </ng-container>\n\n <!-- Suggestion items -->\n <ng-container *ngIf=\"filteredData\">\n <li\n nj-list-item\n *ngFor=\"\n let option of filteredData;\n index as i;\n trackBy: trackByOption\n \"\n [isActive]=\"i === activeIndex\"\n [ariaSelected]=\"i === focusIndex\"\n role=\"option\"\n tabindex=\"-1\"\n [id]=\"getItemId(i)\"\n #item\n (itemClick)=\"selectItem(option)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n optionLabelTemplate ? optionLabelTemplate : defaultLabel\n \"\n [ngTemplateOutletContext]=\"{ option: option }\"\n ></ng-container>\n </li>\n </ng-container>\n </nj-list-group>\n </ng-container>\n</nj-form-item>\n\n<ng-template #defaultLabel let-option=\"option\">\n <span\n *ngIf=\"isFiltered\"\n njHighlight\n [content]=\"option?.label\"\n [textToHighlight]=\"searchText\"\n ></span>\n <span *ngIf=\"!isFiltered\">{{ option?.label }}</span>\n</ng-template>\n\n<ng-template\n #defaultSearchResults\n let-numberOfFilteredData=\"numberOfFilteredData\"\n>\n <p class=\"nj-form-item__list-item-hint\" aria-hidden=\"true\">\n {{ numberOfFilteredData }} {{ resultsNumberMessage }}\n </p>\n</ng-template>\n\n<ng-template #defaultNoResults>\n <p class=\"nj-form-item__list-item-hint\" aria-hidden=\"true\">\n {{ noResultMessage }}\n </p>\n</ng-template>\n", dependencies: [{ kind: "component", type: ListGroupComponent, selector: "nj-list-group", inputs: ["listId", "isClickable", "isCheckboxList", "hasBorder", "isDense", "isCustomSelectList", "ariaLabel", "isMultiSelect"] }, { kind: "component", type: ListItemComponent, selector: "[nj-list-item]", inputs: ["isActive", "isDisabled", "hasRightBorder", "role", "ariaSelected", "iconName", "iconAriaLabel", "type", "href", "value", "isCheckboxContent", "isIconOnly", "checkboxContentId"], outputs: ["itemClick"] }, { kind: "component", type: FormItemComponent, selector: "nj-form-item", inputs: ["inputId", "size", "isFloatingLabel", "isDisabled", "isRequired", "hasSuccess", "hasError", "hasHint", "hasCustomIcon", "isIconClickable", "iconName", "additionalClass", "passwordButtonLabelShow", "passwordButtonLabelHide", "passwordNoticeIsVisible", "passwordNoticeIsHidden", "isSelect"], outputs: ["iconClick", "iconKeydown", "wrapperClick"] }, { kind: "directive", type: FormFieldDirective, selector: "input[njFormField], textarea[njFormField], select[njFormField], nj-select[njFormField], div[njFormField]", exportAs: ["njFormField"] }, { kind: "directive", type: HighlightDirective, selector: "[njHighlight]", inputs: ["content", "textToHighlight", "escapeAccents", "caseSensitive"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], animations: [selectAnimations.transformList], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AutocompleteComponent, decorators: [{ type: Component, args: [{ selector: 'nj-autocomplete', changeDetection: ChangeDetectionStrategy.OnPush, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => AutocompleteComponent), multi: true } ], animations: [selectAnimations.transformList], encapsulation: ViewEncapsulation.None, standalone: true, imports: [ ListGroupComponent, ListItemComponent, FormItemComponent, FormFieldDirective, HighlightDirective, CommonModule ], template: "<nj-form-item\n [hasError]=\"hasError\"\n [hasSuccess]=\"hasSuccess\"\n [hasHint]=\"hasHint\"\n [isDisabled]=\"isDisabled\"\n [hasCustomIcon]=\"hasCustomIcon\"\n [isFloatingLabel]=\"isFloatingLabel\"\n [iconName]=\"iconName\"\n [isSelect]=\"true\"\n [additionalClass]=\"getAdditionalClass()\"\n [inputId]=\"inputId\"\n [size]=\"size\"\n (keydown)=\"handleKeydownEvent($event)\"\n (focusout)=\"handleFocusout($event)\"\n>\n <input\n #input\n type=\"text\"\n (input)=\"handleInputEvent($event)\"\n (focus)=\"_onTouched?.()\"\n [value]=\"selectedValue?.label\"\n [attr.id]=\"inputId\"\n [disabled]=\"isDisabled\"\n autocomplete=\"off\"\n njFormField\n role=\"combobox\"\n aria-autocomplete=\"list\"\n [attr.aria-activedescendant]=\"focusedItemId\"\n [attr.aria-controls]=\"getListId()\"\n [attr.aria-expanded]=\"isOpen\"\n [attr.aria-describedby]=\"getInstructionsId()\"\n (click)=\"handleInputClick()\"\n />\n\n <ng-content njFormLabel select=\"[njFormLabel]\"></ng-content>\n\n <ng-content njFormSubscript select=\"[njFormSubscript]\"></ng-content>\n\n <ng-container njFormAdditionalContent>\n <div class=\"nj-sr-only\" aria-live=\"polite\" aria-atomic=\"true\">\n <p>{{ liveZoneContent }}</p>\n </div>\n\n <p [id]=\"getInstructionsId()\" hidden>{{ inputInstructions }}</p>\n\n <nj-list-group\n [@transformList]=\"isOpen ? 'open': 'void'\"\n *ngIf=\"isOpen\"\n class=\"nj-form-item__list nj-form-item__list--no-animate\"\n [ngClass]=\"{ 'nj-form-item__list--appended': appendTo }\"\n [isDense]=\"true\"\n [hasBorder]=\"false\"\n [isClickable]=\"true\"\n [listId]=\"getListId()\"\n isCustomSelectList\n [ariaLabel]=\"listLabel\"\n #optionsList\n (keydown)=\"appendTo ? handleKeydownEvent($event) : null\"\n (focusout)=\"appendTo ? handleFocusout($event) : null\"\n >\n <ng-content select=\"[njAutocompleteAdditional]\"> </ng-content>\n\n <!-- Number of suggestions -->\n <ng-container\n *ngIf=\"isFiltered && showNumberOfResults && filteredData?.length\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n searchResultsTemplate ? searchResultsTemplate : defaultSearchResults\n \"\n [ngTemplateOutletContext]=\"{\n numberOfFilteredData: filteredData.length\n }\"\n ></ng-container>\n </ng-container>\n\n <!-- No suggestions -->\n <ng-container\n *ngIf=\"isFiltered && showNoResultsMessage && !filteredData?.length\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n noResultTemplate ? noResultTemplate : defaultNoResults\n \"\n ></ng-container>\n </ng-container>\n\n <!-- Suggestion items -->\n <ng-container *ngIf=\"filteredData\">\n <li\n nj-list-item\n *ngFor=\"\n let option of filteredData;\n index as i;\n trackBy: trackByOption\n \"\n [isActive]=\"i === activeIndex\"\n [ariaSelected]=\"i === focusIndex\"\n role=\"option\"\n tabindex=\"-1\"\n [id]=\"getItemId(i)\"\n #item\n (itemClick)=\"selectItem(option)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n optionLabelTemplate ? optionLabelTemplate : defaultLabel\n \"\n [ngTemplateOutletContext]=\"{ option: option }\"\n ></ng-container>\n </li>\n </ng-container>\n </nj-list-group>\n </ng-container>\n</nj-form-item>\n\n<ng-template #defaultLabel let-option=\"option\">\n <span\n *ngIf=\"isFiltered\"\n njHighlight\n [content]=\"option?.label\"\n [textToHighlight]=\"searchText\"\n ></span>\n <span *ngIf=\"!isFiltered\">{{ option?.label }}</span>\n</ng-template>\n\n<ng-template\n #defaultSearchResults\n let-numberOfFilteredData=\"numberOfFilteredData\"\n>\n <p class=\"nj-form-item__list-item-hint\" aria-hidden=\"true\">\n {{ numberOfFilteredData }} {{ resultsNumberMessage }}\n </p>\n</ng-template>\n\n<ng-template #defaultNoResults>\n <p class=\"nj-form-item__list-item-hint\" aria-hidden=\"true\">\n {{ noResultMessage }}\n </p>\n</ng-template>\n" }] }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }]; }, propDecorators: { iconName: [{ type: Input }], showNumberOfResults: [{ type: Input }], noResultMessage: [{ type: Input }], resultsNumberMessage: [{ type: Input }], showNoResultsMessage: [{ type: Input }], searchLimit: [{ type: Input }], appendTo: [{ type: Input }], trackByFn: [{ type: Input }], data: [{ type: Input }], listLabel: [{ type: Input }], inputInstructions: [{ type: Input }], search: [{ type: Output }], inputRef: [{ type: ViewChild, args: ['input'] }], optionsList: [{ type: ViewChild, args: ['optionsList', { read: ElementRef }] }], selectOptions: [{ type: ViewChildren, args: [ListItemComponent] }], optionLabelTemplate: [{ type: ContentChild, args: ['njAutocompleteOptionLabel', { read: TemplateRef }] }], searchResultsTemplate: [{ type: ContentChild, args: ['njAutocompleteSearchResults', { read: TemplateRef }] }], noResultTemplate: [{ type: ContentChild, args: ['njAutocompleteNoResult', { read: TemplateRef }] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0b2NvbXBsZXRlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL2F1dG9jb21wbGV0ZS9hdXRvY29tcGxldGUuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvYXV0b2NvbXBsZXRlL2F1dG9jb21wbGV0ZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLFFBQVEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3pELE9BQU8sRUFFTCx1QkFBdUIsRUFFdkIsU0FBUyxFQUNULFlBQVksRUFDWixVQUFVLEVBQ1YsWUFBWSxFQUNaLFVBQVUsRUFDVixNQUFNLEVBQ04sS0FBSyxFQUVMLE1BQU0sRUFHTixXQUFXLEVBQ1gsU0FBUyxFQUNULFlBQVksRUFDWixpQkFBaUIsRUFDbEIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUF3QixpQkFBaUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3pFLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDM0QsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQy9DLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQ3hFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ3JFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ3RFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQ3hFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGtDQUFrQyxDQUFDOzs7QUEwQnJFLE1BQU0sT0FBTyxxQkFDWCxTQUFRLGlCQUFpQjtJQW1KekI7O09BRUc7SUFDSCxJQUFhLElBQUksQ0FBQyxLQUEyQjtRQUMzQyxJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUNuQixJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7SUFDcEIsQ0FBQztJQUVELElBQUksSUFBSTtRQUNOLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQztJQUNwQixDQUFDO0lBc0RELFlBQ1UsUUFBbUIsRUFDbkIsVUFBbUMsRUFDbkMsR0FBc0IsRUFDSixTQUFTO1FBRW5DLEtBQUssRUFBRSxDQUFDO1FBTEEsYUFBUSxHQUFSLFFBQVEsQ0FBVztRQUNuQixlQUFVLEdBQVYsVUFBVSxDQUF5QjtRQUNuQyxRQUFHLEdBQUgsR0FBRyxDQUFtQjtRQUNKLGNBQVMsR0FBVCxTQUFTLENBQUE7UUFwTnBCLHVCQUFrQixHQUFHLENBQUMsQ0FBQztRQUN2QixzQkFBaUIsR0FBRyxDQUFDLENBQUM7UUFDdkM7O1dBRUc7UUFDSyxnQkFBVyxHQUFHLElBQUksT0FBTyxFQUFRLENBQUM7UUFPMUM7O1dBRUc7UUFDSyxjQUFTLEdBQUcsQ0FBQyxDQUFNLEVBQVEsRUFBRSxHQUFFLENBQUMsQ0FBQztRQUV6Qzs7V0FFRztRQUNPLGVBQVUsR0FBRyxHQUFTLEVBQUUsR0FBRSxDQUFDLENBQUM7UUFZdEM7Ozs7Ozs7Ozs7V0FVRztRQUNLLG1CQUFjLEdBQUcsS0FBSyxDQUFDO1FBRS9COztXQUVHO1FBQ0gsV0FBTSxHQUFHLEtBQUssQ0FBQztRQUVmOztXQUVHO1FBQ0gsZUFBVSxHQUFHLEtBQUssQ0FBQztRQWtCbkI7OztXQUdHO1FBQ0gsZUFBVSxHQUFXLENBQUMsQ0FBQyxDQUFDO1FBRWQsZ0JBQVcsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUUzQjs7O1dBR0c7UUFDTyxrQkFBYSxHQUFrQixJQUFJLENBQUM7UUFFOUM7OztXQUdHO1FBQ0gsb0JBQWUsR0FBRyxFQUFFLENBQUM7UUFFckI7O1dBRUc7UUFFSCxhQUFRLEdBQUcscUJBQXFCLENBQUM7UUFFakM7O1dBRUc7UUFFSCx3QkFBbUIsR0FBRyxJQUFJLENBQUM7UUFFM0I7O1dBRUc7UUFFSCxvQkFBZSxHQUFHLFlBQVksQ0FBQztRQUUvQjs7V0FFRztRQUVILHlCQUFvQixHQUFHLFNBQVMsQ0FBQztRQUVqQzs7V0FFRztRQUVILHlCQUFvQixHQUFHLElBQUksQ0FBQztRQWdENUI7O1dBRUc7UUFFSCxXQUFNLEdBQXlCLElBQUksWUFBWSxFQUFVLENBQUM7UUE0Q3hELElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO0lBQzVCLENBQUM7SUFFRDs7T0FFRztJQUNILGtCQUFrQjtRQUNoQixLQUFLLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztJQUM3QixDQUFDO0lBRUQ7O09BRUc7SUFDSCxXQUFXO1FBQ1QsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUN4QixJQUFJLENBQUMsV0FBVyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQzVCLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxFQUFFLENBQUM7UUFDakMsSUFBSSxDQUFDLHdCQUF3QixFQUFFLEVBQUUsQ0FBQztRQUNsQyxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUU7WUFDakIsSUFBSSxDQUFDLCtCQUErQixFQUFFLENBQUM7U0FDeEM7SUFDSCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssMkJBQTJCO1FBQ2pDLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUM7UUFFbkMsSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtZQUN6QixPQUFPLElBQUksQ0FBQyxlQUFlLENBQUM7U0FDN0I7UUFFRCxPQUFPLEdBQUcsUUFBUSxDQUFDLE1BQU0sSUFBSSxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztJQUMzRCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssVUFBVTtRQUNoQixJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLElBQUksS0FBSyxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRTtZQUMvRSxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUM7U0FDaEM7YUFBTTtZQUNMLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLEtBQUs7aUJBQzNCLE1BQU0sQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLHdCQUF3QixDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2lCQUNsRixLQUFLLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztTQUMvQjtRQUVELElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxDQUFDLDJCQUEyQixFQUFFLENBQUM7UUFDMUQsSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7SUFDN0IsQ0FBQztJQUVPLG1CQUFtQjtRQUN6QixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxLQUFLLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUMzRixDQUFDO0lBRUQsSUFBSSxtQkFBbUI7UUFDckIsSUFBSSxJQUFJLENBQUMsVUFBVSxLQUFLLENBQUMsQ0FBQyxFQUFFO1lBQzFCLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQztTQUN4QjtRQUNELE9BQU8sSUFBSSxDQUFDLFdBQVcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hELENBQUM7SUFFTyxtQkFBbUI7UUFDekIsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGFBQWEsRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLEVBQUUsRUFBRSxFQUFFLGFBQWEsQ0FBQztRQUNyRixPQUFPLENBQUMsY0FBYyxDQUFDLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVPLDRCQUE0QjtRQUNsQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsYUFBYSxFQUFFO1lBQ3RELE9BQU87U0FDUjtRQUNELE1BQU0sU0FBUyxHQUFHLFFBQVEsQ0FBQyxhQUE0QixDQUFDO1FBRXhELElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ2xFLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBQzNCLElBQUksQ0FBQyxjQUFjLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLENBQUM7UUFFaEUseUVBQXlFO1FBQ3pFLDhFQUE4RTtRQUM5RSxTQUFTLEVBQUUsS0FBSyxFQUFFLENBQUM7SUFDckIsQ0FBQztJQUVEOztPQUVHO0lBQ0ssbUJBQW1CO1FBQ3pCLElBQUksSUFBSSxDQUFDLFdBQVcsRUFBRSxhQUFhLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRSxhQUFhLEVBQUU7WUFDbkUsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLENBQUMsUUFBUSxFQUFFLGFBQWEsRUFBRSxxQkFBcUIsRUFBRSxDQUFDO1lBQ2hGLElBQUksaUJBQWlCLEVBQUU7Z0JBQ3JCLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLEtBQUssR0FBRzs7a0JBRTdCLGlCQUFpQixDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsaUJBQWlCO2lCQUNoRCxpQkFBaUIsQ0FBQyxHQUFHLEdBQUcsaUJBQWlCLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUMsa0JBQWtCO3VCQUM3RixpQkFBaUIsQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixHQUFHLENBQUM7OztTQUdsRSxDQUFDO2FBQ0g7U0FDRjtJQUNILENBQUM7SUFFRDs7T0FFRztJQUNLLCtCQUErQjtRQUNyQyxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUUsYUFBYSxFQUFFO1lBQ25DLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsQ0FBQztTQUNoRjtJQUNILENBQUM7SUFFRDs7T0FFRztJQUNLLGtCQUFrQjtRQUN4QixJQUFJLENBQUMsd0JBQXdCLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQVEsRUFBRSxFQUFFO1lBQ3BGLElBQUksSUFBSSxDQUFDLFFBQVEsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFO2dCQUNoQyxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQzthQUM1QjtRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0gsa0JBQWtCO1FBQ2hCLE9BQU8sa0RBQWtELElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQztJQUN0RyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsZ0JBQWdCLENBQUMsRUFBTztRQUN0QixJQUFJLENBQUMsU0FBUyxHQUFHLEVBQUUsQ0FBQztJQUN0QixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsaUJBQWlCLENBQUMsRUFBTztRQUN2QixJQUFJLENBQUMsVUFBVSxHQUFHLEVBQUUsQ0FBQztJQUN2QixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsZ0JBQWdCLENBQUMsVUFBbUI7UUFDbEMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUU7WUFDbEIsT0FBTztTQUNSO1FBQ0QsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7SUFDL0IsQ0FBQztJQUVEOzs7T0FHRztJQUNILFVBQVUsQ0FBQyxLQUF5QjtRQUNsQyxJQUFJLENBQUMsYUFBYSxHQUFHLEtBQUssQ0FBQztRQUMzQixJQUFJLENBQUMsVUFBVSxHQUFHLEtBQUssRUFBRSxLQUFLLElBQUksRUFBRSxDQUFDO1FBQ3JDLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRTtZQUNqQixJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxLQUFLLEdBQUcsS0FBSyxFQUFFLEtBQUssSUFBSSxFQUFFLENBQUM7U0FDeEQ7UUFDRCxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFFRCxnQ0FBZ0M7SUFDaEMsUUFBUTtRQUNOLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNsQixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQztRQUNuQixJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQztRQUUzQixVQUFVLENBQUMsR0FBRyxFQUFFO1lBQ2QsSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7WUFFM0IsSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFO2dCQUNqQixJQUFJLENBQUMsNEJBQTRCLEVBQUUsQ0FBQzthQUNyQztZQUVELElBQUksQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDO1FBQzlCLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELGlDQUFpQztJQUNqQyxTQUFTO1FBQ1AsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUM7UUFDcEIsSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNyQixJQUFJLENBQUMsV0FBVyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ3RCLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRTtZQUNqQixJQUFJLENBQUMsK0JBQStCLEVBQUUsQ0FBQztTQUN4QztRQUNELElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDMUIsQ0FBQztJQUVEOzs7T0FHRztJQUNILGdCQUFnQjtRQUNkLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUNmLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztTQUNsQjthQUFNO1lBQ0wsSUFBSSxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUM7WUFDeEIsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1NBQ2pCO0lBQ0gsQ0FBQztJQUVEOzs7T0FHRztJQUNILGdCQUFnQixDQUFDLEtBQWlCO1FBQ2hDLElBQUksS0FBSyxFQUFFLElBQUksS0FBSyxFQUFFLEVBQUU7WUFDdEIsT0FBTztTQUNSO1FBRUQsSUFBSSxDQUFDLFVBQVUsR0FBSSxLQUFLLEVBQUUsTUFBMkIsRUFBRSxLQUFLLENBQUM7UUFDN0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBRWxDLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsS0FBSyxLQUFLLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUVyRixJQUFJLGNBQWMsRUFBRTtZQUNsQixJQUFJLENBQUMsVUFBVSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1NBQ2pDO2FBQU07WUFDTCxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDbEIsVUFBVSxDQUFDLEdBQUcsRUFBRTtnQkFDZCxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFO29CQUM1QixJQUFJLENBQUMsVUFBVSxHQUFHLENBQUMsQ0FBQztvQkFFcEIsSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7aUJBQzNCO1lBQ0gsQ0FBQyxDQUFDLENBQUM7U0FDSjtJQUNILENBQUM7SUFFRDs7T0FFRztJQUNILFNBQVMsQ0FBQyxLQUFhO1FBQ3JCLE9BQU8sR0FBRyxJQUFJLENBQUMsT0FBTyxTQUFTLEtBQUssRUFBRSxDQUFDO0lBQ3pDLENBQUM7SUFFRDs7T0FFRztJQUNILFNBQVM7UUFDUCxPQUFPLEdBQUcsSUFBSSxDQUFDLE9BQU8sT0FBTyxDQUFDO0lBQ2hDLENBQUM7SUFFRDs7T0FFRztJQUNILGlCQUFpQjtRQUNmLE9BQU8sR0FBRyxJQUFJLENBQUMsT0FBTyxlQUFlLENBQUM7SUFDeEMsQ0FBQztJQUVEOztPQUVHO0lBQ0ssa0JBQWtCO1FBQ3hCLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxhQUFhLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFFLEVBQUUsYUFBYSxDQUFDO1FBQzVFLElBQUksQ0FBQyxhQUFhLEdBQUcsT0FBTyxFQUFFLEVBQUUsQ0FBQztRQUNqQyxPQUFPLENBQUMsY0FBYyxDQUFDLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVEOztPQUVHO0lBQ0ssZ0JBQWdCO1FBQ3RCLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLEVBQUU7WUFDNUIsSUFBSSxJQUFJLENBQUMsVUFBVSxLQUFLLENBQUMsQ0FBQyxFQUFFO2dCQUMxQixNQUFNLFNBQVMsR0FBRyxDQUFDLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUM7Z0JBQ25FLElBQUksQ0FBQyxVQUFVLEdBQUcsU0FBUyxDQUFDO2FBQzdCO2lCQUFNO2dCQUNMLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDO2FBQzVDO1lBRUQsSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7U0FDM0I7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxvQkFBb0I7UUFDMUIsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRTtZQUM1QixNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsVUFBVSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxHQUFHLENBQUMsQ0FBQztZQUNqRyxJQUFJLENBQUMsVUFBVSxHQUFHLGFBQWEsQ0FBQztZQUNoQyxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztTQUMzQjtJQUNILENBQUM7SUFFRDs7T0FFRztJQUNLLGNBQWM7UUFDcEIsSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNyQixJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQztJQUM1QixDQUFDO0lBRUQ7O09BRUc7SUFDSCxrQkFBa0IsQ0FBQyxDQUFnQjtRQUNqQyxJQUFJLENBQUMsQ0FBQyxHQUFHLEtBQUssS0FBSyxFQUFFO1lBQ25CLDREQUE0RDtZQUM1RCxPQUFPO1NBQ1I7UUFFRCxRQUFRLENBQUMsQ0FBQyxHQUFHLEVBQUU7WUFDYixLQUFLLFdBQVc7Z0JBQ2QsQ0FBQyxDQUFDLGNBQWMsRUFBRSxDQUFDO2dCQUNuQixJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRTtvQkFDaEIsSUFBSSxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUM7b0JBQ3hCLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztvQkFDaEIsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsbUJBQW1CLENBQUM7b0JBQzNDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO2lCQUMzQjtxQkFBTTtvQkFDTCxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztpQkFDekI7Z0JBQ0QsTUFBTTtZQUNSLEtBQUssU0FBUztnQkFDWixDQUFDLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ25CLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFO29CQUNoQixJQUFJLENBQUMsVUFBVSxHQUFHLEtBQUssQ0FBQztvQkFDeEIsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO2lCQUNqQjtnQkFDRCxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FBQztnQkFDM0MsSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUM7Z0JBQzVCLE1BQU07WUFDUixLQUFLLFFBQVE7Z0JBQ1gsQ0FBQyxDQUFDLGNBQWMsRUFBRSxDQUFDO2dCQUNuQixJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUU7b0JBQ2YsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO2lCQUNsQjtnQkFDRCxNQUFNO1lBQ1IsS0FBSyxPQUFPO2dCQUNWLElBQUksSUFBSSxDQUFDLE1BQU0sSUFBSSxJQUFJLENBQUMsVUFBVSxLQUFLLENBQUMsQ0FBQyxFQUFFO29CQUN6QyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7aUJBQ3JEO2dCQUNELE1BQU07WUFDUjtnQkFDRSxzREFBc0Q7Z0JBQ3RELE1BQU0sY0FBYyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLEtBQUssV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBSSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUM7Z0JBQzlHLElBQUksY0FBYyxFQUFFO29CQUNsQixJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQztvQkFDdkIsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO29CQUV0QixJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRTt3QkFDaEIsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO3FCQUNqQjtvQkFFRCxVQUFVLENBQUMsR0FBRyxFQUFFO3dCQUNkLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO3dCQUMvQyxJQUFJLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxDQUFDO3dCQUMvQixJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDO29CQUMxQixDQUFDLENBQUMsQ0FBQztpQkFDSjtTQUNKO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssZ0JBQWdCO1FBQ3RCLE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsVUFBVSxLQUFLLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN0RixPQUFPLFlBQVksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzNCLENBQUM7SUFFRDs7T0FFRztJQUNILFVBQVUsQ0FBQyxNQUEwQjtRQUNuQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDakIsSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFO1lBQ2pCLElBQUksQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLEtBQUssR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDO1NBQ2xEO1FBQ0QsSUFBSSxDQUFDLFVBQVUsR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDO1FBQy9CLElBQUksQ0FBQyxhQUFhLEdBQUcsTUFBTSxDQUFDO1FBQzVCLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUV0QixJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDMUIsQ0FBQztJQUVEOzs7T0FHRztJQUNILGNBQWMsQ0FBQyxDQUFhO1FBQzFCLElBQUksSUFBSSxDQUFDLGNBQWMsRUFBRTtZQUN2QixPQUFPO1NBQ1I7UUFFRCxJQUNFLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxhQUFxQixDQUFDO1lBQ2pFLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxhQUFxQixDQUFDLEVBQ2xFO1lBQ0EsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1NBQ2xCO0lBQ0gsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxhQUFhLENBQUMsS0FBYSxFQUFFLE1BQTBCO1FBQ3JELElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRTtZQUNsQixPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1NBQ3RDO1FBQ0QsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQzsrR0E1bkJVLHFCQUFxQixzR0F3TnRCLFFBQVE7bUdBeE5QLHFCQUFxQixtY0FuQnJCO1lBQ1Q7Z0JBQ0UsT0FBTyxFQUFFLGlCQUFpQjtnQkFDMUIsV0FBVyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxxQkFBcUIsQ0FBQztnQkFDcEQsS0FBSyxFQUFFLElBQUk7YUFDWjtTQUNGLG1JQWtOa0QsV0FBVywrSEFNVCxXQUFXLHFIQU1oQixXQUFXLHdNQXhCekIsVUFBVSxnREFNOUIsaUJBQWlCLHVFQ3RQakMsMHJJQTRJQSw0Q0Q3Rkksa0JBQWtCLDJMQUNsQixpQkFBaUIsK1FBQ2pCLGlCQUFpQiwyWkFDakIsa0JBQWtCLGdMQUNsQixrQkFBa0IsbUlBQ2xCLFlBQVksdWZBVEYsQ0FBQyxnQkFBZ0IsQ0FBQyxhQUFhLENBQUM7OzRGQVlqQyxxQkFBcUI7a0JBdkJqQyxTQUFTOytCQUNFLGlCQUFpQixtQkFFVix1QkFBdUIsQ0FBQyxNQUFNLGFBQ3BDO3dCQUNUOzRCQUNFLE9BQU8sRUFBRSxpQkFBaUI7NEJBQzFCLFdBQVcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLHNCQUFzQixDQUFDOzRCQUNwRCxLQUFLLEVBQUUsSUFBSTt5QkFDWjtxQkFDRixjQUNXLENBQUMsZ0JBQWdCLENBQUMsYUFBYSxDQUFDLGlCQUM3QixpQkFBaUIsQ0FBQyxJQUFJLGNBQ3pCLElBQUksV0FDUDt3QkFDUCxrQkFBa0I7d0JBQ2xCLGlCQUFpQjt3QkFDakIsaUJBQWlCO3dCQUNqQixrQkFBa0I7d0JBQ2xCLGtCQUFrQjt3QkFDbEIsWUFBWTtxQkFDYjs7MEJBME5FLE1BQU07MkJBQUMsUUFBUTs0Q0FySGxCLFFBQVE7c0JBRFAsS0FBSztnQkFPTixtQkFBbUI7c0JBRGxCLEtBQUs7Z0JBT04sZUFBZTtzQkFEZCxLQUFLO2dCQU9OLG9CQUFvQjtzQkFEbkIsS0FBSztnQkFPTixvQkFBb0I7c0JBRG5CLEtBQUs7Z0JBT04sV0FBVztzQkFEVixLQUFLO2dCQU9OLFFBQVE7c0JBRFAsS0FBSztnQkFPTixTQUFTO3NCQURSLEtBQUs7Z0JBV08sSUFBSTtzQkFBaEIsS0FBSztnQkFZRyxTQUFTO3NCQUFqQixLQUFLO2dCQU1HLGlCQUFpQjtzQkFBekIsS0FBSztnQkFNTixNQUFNO3NCQURMLE1BQU07Z0JBTWEsUUFBUTtzQkFBM0IsU0FBUzt1QkFBQyxPQUFPO2dCQUs4QixXQUFXO3NCQUExRCxTQUFTO3VCQUFDLGFBQWEsRUFBRSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUU7Z0JBTzlDLGFBQWE7c0JBRFosWUFBWTt1QkFBQyxpQkFBaUI7Z0JBTy9CLG1CQUFtQjtzQkFEbEIsWUFBWTt1QkFBQywyQkFBMkIsRUFBRSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUU7Z0JBT2hFLHFCQUFxQjtzQkFEcEIsWUFBWTt1QkFBQyw2QkFBNkIsRUFBRSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUU7Z0JBT2xFLGdCQUFnQjtzQkFEZixZQUFZO3VCQUFDLHdCQUF3QixFQUFFLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbW1vbk1vZHVsZSwgRE9DVU1FTlQgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHtcbiAgQWZ0ZXJDb250ZW50SW5pdCxcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gIENoYW5nZURldGVjdG9yUmVmLFxuICBDb21wb25lbnQsXG4gIENvbnRlbnRDaGlsZCxcbiAgRWxlbWVudFJlZixcbiAgRXZlbnRFbWl0dGVyLFxuICBmb3J3YXJkUmVmLFxuICBJbmplY3QsXG4gIElucHV0LFxuICBPbkRlc3Ryb3ksXG4gIE91dHB1dCxcbiAgUXVlcnlMaXN0LFxuICBSZW5kZXJlcjIsXG4gIFRlbXBsYXRlUmVmLFxuICBWaWV3Q2hpbGQsXG4gIFZpZXdDaGlsZHJlbixcbiAgVmlld0VuY2Fwc3VsYXRpb25cbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb250cm9sVmFsdWVBY2Nlc3NvciwgTkdfVkFMVUVfQUNDRVNTT1IgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBzZWxlY3RBbmltYXRpb25zIH0gZnJvbSAnLi4vLi4vc2hhcmVkL2FuaW1hdGlvbnMnO1xuaW1wb3J0IHsgVXRpbHMgfSBmcm9tICcuLi8uLi91dGlscy91dGlscy51dGlsJztcbmltcG9ydCB7IEZvcm1GaWVsZERpcmVjdGl2ZSB9IGZyb20gJy4uL2Zvcm0tZmllbGQvZm9ybS1maWVsZC5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgRm9ybUl0ZW1Db21wb25lbnQgfSBmcm9tICcuLi9mb3JtLWl0ZW0vZm9ybS1pdGVtLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBIaWdobGlnaHREaXJlY3RpdmUgfSBmcm9tICcuLi9oaWdobGlnaHQvaGlnaGxpZ2h0LmRpcmVjdGl2ZSc7XG5pbXBvcnQgeyBMaXN0R3JvdXBDb21wb25lbnQgfSBmcm9tICcuLi9saXN0LWdyb3VwL2xpc3QtZ3JvdXAuY29tcG9uZW50JztcbmltcG9ydCB7IExpc3RJdGVtQ29tcG9uZW50IH0gZnJvbSAnLi4vbGlzdC1pdGVtL2xpc3QtaXRlbS5jb21wb25lbnQnO1xuaW1wb3J0IHsgQXV0b2NvbXBsZXRlT3B0aW9uIH0gZnJvbSAnLi9hdXRvY29tcGxldGUubW9kZWwnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICduai1hdXRvY29tcGxldGUnLFxuICB0ZW1wbGF0ZVVybDogJy4vYXV0b2NvbXBsZXRlLmNvbXBvbmVudC5odG1sJyxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIHByb3ZpZGVyczogW1xuICAgIHtcbiAgICAgIHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gQXV0b2NvbXBsZXRlQ29tcG9uZW50KSxcbiAgICAgIG11bHRpOiB0cnVlXG4gICAgfVxuICBdLFxuICBhbmltYXRpb25zOiBbc2VsZWN0QW5pbWF0aW9ucy50cmFuc2Zvcm1MaXN0XSxcbiAgZW5jYXBzdWxhdGlvbjogVmlld0VuY2Fwc3VsYXRpb24uTm9uZSxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW1xuICAgIExpc3RHcm91cENvbXBvbmVudCxcbiAgICBMaXN0SXRlbUNvbXBvbmVudCxcbiAgICBGb3JtSXRlbUNvbXBvbmVudCxcbiAgICBGb3JtRmllbGREaXJlY3RpdmUsXG4gICAgSGlnaGxpZ2h0RGlyZWN0aXZlLFxuICAgIENvbW1vbk1vZHVsZVxuICBdXG59KVxuZXhwb3J0IGNsYXNzIEF1dG9jb21wbGV0ZUNvbXBvbmVudFxuICBleHRlbmRzIEZvcm1JdGVtQ29tcG9uZW50XG4gIGltcGxlbWVudHMgQ29udHJvbFZhbHVlQWNjZXNzb3IsIEFmdGVyQ29udGVudEluaXQsIE9uRGVzdHJveVxue1xuICBwcml2YXRlIHJlYWRvbmx5IElOUFVUX0JPUkRFUl9JTl9QWCA9IDM7XG4gIHByaXZhdGUgcmVhZG9ubHkgTElTVF9PRkZTRVRfSU5fUFggPSA0O1xuICAvKipcbiAgICogQGlnbm9yZVxuICAgKi9cbiAgcHJpdmF0ZSB1bnN1YnNjcmliZSA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgLyoqXG4gICAqIEBpZ25vcmVcbiAgICovXG4gIHByaXZhdGUgX3BhcmVudEVsZW1lbnQ6IEhUTUxFbGVtZW50O1xuXG4gIC8qKlxuICAgKiBAaWdub3JlXG4gICAqL1xuICBwcml2YXRlIF9vbkNoYW5nZSA9IChfOiBhbnkpOiB2b2lkID0+IHt9O1xuXG4gIC8qKlxuICAgKiBAaWdub3JlXG4gICAqL1xuICBwcm90ZWN0ZWQgX29uVG91Y2hlZCA9ICgpOiB2b2lkID0+IHt9O1xuXG4gIC8qKlxuICAgKiBAaWdub3JlXG4gICAqL1xuICBwcml2YXRlIGNsaWNrTGlzdGVuZXJEaXNwb3NlRmN0OiBGdW5jdGlvbjtcblxuICAvKipcbiAgICogQGlnbm9yZVxuICAgKi9cbiAgcHJpdmF0ZSBzY3JvbGxMaXN0ZW5lckRpc3Bvc2VGY3Q6IEZ1bmN0aW9uO1xuXG4gIC8qKlxuICAgKiBCYW5kYWlkIGhhY2sgdG8gcHJldmVudCBhIHdlaXJkIGZvY3Vzb3V0IGV2ZW50IGJ1ZyBoYXBwZW5pbmcgd2hlblxuICAgKiBgYXBwZW5kVG9gIGlzIHNldCBhbmQgYW4gaXRlbSBpcyBzZWxlY3RlZC4gRm9yICpzb21lKiByZWFzb24sIHRoZSBmb2N1c291dFxuICAgKiBldmVudCBpcyB0cmlnZ2VyZWQgbXVsdGlwbGUgdGltZXMgd2hlbiBvcGVuaW5nIHRoZSBsaXN0LCB3aGljaCBjYXVzZXNcbiAgICogdW5leHBlY3RlZCBiZWhhdmlvci5cbiAgICpcbiAgICogVGhpcyB2YXJpYWJsZSBhbGxvd3MgdG8gdGVtcG9yYXJpbHkgXCJkaXNhYmxlc1wiIHRoZSBgaGFuZGxlRm9jdXNvdXRgIGhhbmRsZXIuXG4gICAqXG4gICAqIEZJWE1FOiBGaW5kIGFuIGFjdHVhbCBzb2x1dGlvbiB0byB0aGlzIHByb2JsZW0gaW5zdGVhZCBvZiBhIGJhbmRhaWQgaGFjay5cbiAgICogQGlnbm9yZVxuICAgKi9cbiAgcHJpdmF0ZSBpZ25vcmVGb2N1c291dCA9IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBAaWdub3JlXG4gICAqL1xuICBpc09wZW4gPSBmYWxzZTtcblxuICAvKipcbiAgICogQGlnbm9yZVxuICAgKi9cbiAgaXNGaWx0ZXJlZCA9IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBAaWdub3JlXG4gICAqL1xuICBzZWxlY3RlZFZhbHVlOiBBdXRvY29tcGxldGVPcHRpb247XG5cbiAgLyoqXG4gICAqIEBpZ25vcmVcbiAgICovXG4gIGZpbHRlcmVkRGF0YTogQXV0b2NvbXBsZXRlT3B0aW9uW107XG5cbiAgLyoqXG4gICAqIElucHV0IHNlYXJjaCB0ZXh0XG4gICAqIEBpZ25vcmVcbiAgICovXG4gIHNlYXJjaFRleHQ6IHN0cmluZztcblxuICAvKipcbiAgICogSW5kZXggb2YgY3VycmVudGx5IHNlbGVjdGVkIHN1Z2dlc3Rpb24uIC0xIGlmIG5vIHN1Z2dlc3Rpb24gaXMgY3VycmVudGx5IHNlbGVjdGVkXG4gICAqIEBpZ25vcmVcbiAgICovXG4gIGZvY3