UNPKG

ngx-bootstrap

Version:
796 lines 67.2 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /* tslint:disable:max-file-line-count */ import { ChangeDetectorRef, Directive, ElementRef, EventEmitter, HostListener, Input, Output, Renderer2, TemplateRef, ViewContainerRef } from '@angular/core'; import { NgControl } from '@angular/forms'; import { from, isObservable } from 'rxjs'; import { ComponentLoaderFactory } from 'ngx-bootstrap/component-loader'; import { TypeaheadContainerComponent } from './typeahead-container.component'; import { TypeaheadMatch } from './typeahead-match.class'; import { TypeaheadConfig } from './typeahead.config'; import { getValueFromObject, latinize, tokenize } from './typeahead-utils'; import { debounceTime, filter, mergeMap, switchMap, toArray } from 'rxjs/operators'; export class TypeaheadDirective { /** * @param {?} cis * @param {?} config * @param {?} changeDetection * @param {?} element * @param {?} ngControl * @param {?} renderer * @param {?} viewContainerRef */ constructor(cis, config, changeDetection, element, ngControl, renderer, viewContainerRef) { this.changeDetection = changeDetection; this.element = element; this.ngControl = ngControl; this.renderer = renderer; /** * minimal no of characters that needs to be entered before * typeahead kicks-in. When set to 0, typeahead shows on focus with full * list of options (limited as normal by typeaheadOptionsLimit) */ this.typeaheadMinLength = void 0; /** * turn on/off animation */ this.isAnimated = false; /** * should be used only in case of typeahead attribute is array. * If true - loading of options will be async, otherwise - sync. * true make sense if options array is large. */ this.typeaheadAsync = void 0; /** * match latin symbols. * If true the word súper would match super and vice versa. */ this.typeaheadLatinize = true; /** * Can be use to search words by inserting a single white space between each characters * for example 'C a l i f o r n i a' will match 'California'. */ this.typeaheadSingleWords = true; /** * should be used only in case typeaheadSingleWords attribute is true. * Sets the word delimiter to break words. Defaults to space. */ this.typeaheadWordDelimiters = ' '; /** * should be used only in case typeaheadSingleWords attribute is true. * Sets the word delimiter to match exact phrase. * Defaults to simple and double quotes. */ this.typeaheadPhraseDelimiters = '\'"'; /** * specifies if typeahead is scrollable */ this.typeaheadScrollable = false; /** * specifies number of options to show in scroll view */ this.typeaheadOptionsInScrollableView = 5; /** * fired when an options list was opened and the user clicked Tab * If a value equal true, it will be chosen first or active item in the list * If value equal false, it will be chosen an active item in the list or nothing */ this.typeaheadSelectFirstItem = true; /** * makes active first item in a list */ this.typeaheadIsFirstItemActive = true; /** * fired when 'busy' state of this component was changed, * fired on async mode only, returns boolean */ this.typeaheadLoading = new EventEmitter(); /** * fired on every key event and returns true * in case of matches are not detected */ this.typeaheadNoResults = new EventEmitter(); /** * fired when option was selected, return object with data of this option */ this.typeaheadOnSelect = new EventEmitter(); /** * fired when blur event occurs. returns the active item */ // tslint:disable-next-line:no-any this.typeaheadOnBlur = new EventEmitter(); /** * This attribute indicates that the dropdown should be opened upwards */ this.dropup = false; this.isActiveItemChanged = false; this.isTypeaheadOptionsListActive = false; // tslint:disable-next-line:no-any this.keyUpEventEmitter = new EventEmitter(); this.placement = 'bottom-left'; this._subscriptions = []; this._typeahead = cis.createLoader(element, viewContainerRef, renderer) .provide({ provide: TypeaheadConfig, useValue: config }); Object.assign(this, { typeaheadHideResultsOnBlur: config.hideResultsOnBlur, typeaheadSelectFirstItem: config.selectFirstItem, typeaheadIsFirstItemActive: config.isFirstItemActive, typeaheadMinLength: config.minLength, adaptivePosition: config.adaptivePosition, isAnimated: config.isAnimated }); } /** * @return {?} */ ngOnInit() { this.typeaheadOptionsLimit = this.typeaheadOptionsLimit || 20; this.typeaheadMinLength = this.typeaheadMinLength === void 0 ? 1 : this.typeaheadMinLength; this.typeaheadWaitMs = this.typeaheadWaitMs || 0; // async should be false in case of array if (this.typeaheadAsync === undefined && !(isObservable(this.typeahead))) { this.typeaheadAsync = false; } if (isObservable(this.typeahead)) { this.typeaheadAsync = true; } if (this.typeaheadAsync) { this.asyncActions(); } else { this.syncActions(); } } /** * @param {?} e * @return {?} */ // tslint:disable-next-line:no-any onInput(e) { // For `<input>`s, use the `value` property. For others that don't have a // `value` (such as `<span contenteditable="true">`), use either // `textContent` or `innerText` (depending on which one is supported, i.e. // Firefox or IE). /** @type {?} */ const value = e.target.value !== undefined ? e.target.value : e.target.textContent !== undefined ? e.target.textContent : e.target.innerText; if (value != null && value.trim().length >= this.typeaheadMinLength) { this.typeaheadLoading.emit(true); this.keyUpEventEmitter.emit(e.target.value); } else { this.typeaheadLoading.emit(false); this.typeaheadNoResults.emit(false); this.hide(); } } /** * @param {?} event * @return {?} */ onChange(event) { if (this._container) { // esc /* tslint:disable-next-line: deprecation */ if (event.keyCode === 27 || event.key === 'Escape') { this.hide(); return; } // up /* tslint:disable-next-line: deprecation */ if (event.keyCode === 38 || event.key === 'ArrowUp') { this.isActiveItemChanged = true; this._container.prevActiveMatch(); return; } // down /* tslint:disable-next-line: deprecation */ if (event.keyCode === 40 || event.key === 'ArrowDown') { this.isActiveItemChanged = true; this._container.nextActiveMatch(); return; } // enter /* tslint:disable-next-line: deprecation */ if (event.keyCode === 13 || event.key === 'Enter') { this._container.selectActiveMatch(); return; } } } /** * @return {?} */ onFocus() { if (this.typeaheadMinLength === 0) { this.typeaheadLoading.emit(true); this.keyUpEventEmitter.emit(this.element.nativeElement.value || ''); } } /** * @return {?} */ onBlur() { if (this._container && !this._container.isFocused) { this.typeaheadOnBlur.emit(this._container.active); } } /** * @param {?} event * @return {?} */ onKeydown(event) { // no container - no problems if (!this._container) { return; } /* tslint:disable-next-line: deprecation */ if (event.keyCode === 9 || event.key === 'Tab' || event.keyCode === 13 || event.key === 'Enter') { event.preventDefault(); if (this.typeaheadSelectFirstItem) { this._container.selectActiveMatch(); return; } if (!this.typeaheadSelectFirstItem) { this._container.selectActiveMatch(this.isActiveItemChanged); this.isActiveItemChanged = false; this.hide(); } } } /** * @param {?} match * @return {?} */ changeModel(match) { /** @type {?} */ const valueStr = match.value; this.ngControl.viewToModelUpdate(valueStr); (this.ngControl.control).setValue(valueStr); this.changeDetection.markForCheck(); this.hide(); } /** * @return {?} */ get matches() { return this._matches; } /** * @return {?} */ show() { this._typeahead .attach(TypeaheadContainerComponent) .to(this.container) .position({ attachment: `${this.dropup ? 'top' : 'bottom'} start` }) .show({ typeaheadRef: this, placement: this.placement, animation: false, dropup: this.dropup }); this._outsideClickListener = this.renderer.listen('document', 'click', (/** * @param {?} e * @return {?} */ (e) => { if (this.typeaheadMinLength === 0 && this.element.nativeElement.contains(e.target)) { return undefined; } if (!this.typeaheadHideResultsOnBlur || this.element.nativeElement.contains(e.target)) { return undefined; } this.onOutsideClick(); })); this._container = this._typeahead.instance; this._container.parent = this; // This improves the speed as it won't have to be done for each list item /** @type {?} */ const normalizedQuery = (this.typeaheadLatinize ? latinize(this.ngControl.control.value) : this.ngControl.control.value) .toString() .toLowerCase(); this._container.query = this.typeaheadSingleWords ? tokenize(normalizedQuery, this.typeaheadWordDelimiters, this.typeaheadPhraseDelimiters) : normalizedQuery; this._container.matches = this._matches; this.element.nativeElement.focus(); } /** * @return {?} */ hide() { if (this._typeahead.isShown) { this._typeahead.hide(); this._outsideClickListener(); this._container = null; } } /** * @return {?} */ onOutsideClick() { if (this._container && !this._container.isFocused) { this.hide(); } } /** * @return {?} */ ngOnDestroy() { // clean up subscriptions for (const sub of this._subscriptions) { sub.unsubscribe(); } this._typeahead.dispose(); } /** * @protected * @return {?} */ asyncActions() { this._subscriptions.push(this.keyUpEventEmitter .pipe(debounceTime(this.typeaheadWaitMs), switchMap((/** * @return {?} */ () => this.typeahead))) .subscribe((/** * @param {?} matches * @return {?} */ (matches) => { this.finalizeAsyncCall(matches); }))); } /** * @protected * @return {?} */ syncActions() { this._subscriptions.push(this.keyUpEventEmitter .pipe(debounceTime(this.typeaheadWaitMs), mergeMap((/** * @param {?} value * @return {?} */ (value) => { /** @type {?} */ const normalizedQuery = this.normalizeQuery(value); return from(this.typeahead) .pipe(filter((/** * @param {?} option * @return {?} */ (option) => { return (option && this.testMatch(this.normalizeOption(option), normalizedQuery)); })), toArray()); }))) .subscribe((/** * @param {?} matches * @return {?} */ (matches) => { this.finalizeAsyncCall(matches); }))); } // tslint:disable-next-line:no-any /** * @protected * @param {?} option * @return {?} */ normalizeOption(option) { /** @type {?} */ const optionValue = getValueFromObject(option, this.typeaheadOptionField); /** @type {?} */ const normalizedOption = this.typeaheadLatinize ? latinize(optionValue) : optionValue; return normalizedOption.toLowerCase(); } /** * @protected * @param {?} value * @return {?} */ normalizeQuery(value) { // If singleWords, break model here to not be doing extra work on each // iteration /** @type {?} */ let normalizedQuery = (this.typeaheadLatinize ? latinize(value) : value) .toString() .toLowerCase(); normalizedQuery = this.typeaheadSingleWords ? tokenize(normalizedQuery, this.typeaheadWordDelimiters, this.typeaheadPhraseDelimiters) : normalizedQuery; return normalizedQuery; } /** * @protected * @param {?} match * @param {?} test * @return {?} */ testMatch(match, test) { /** @type {?} */ let spaceLength; if (typeof test === 'object') { spaceLength = test.length; for (let i = 0; i < spaceLength; i += 1) { if (test[i].length > 0 && match.indexOf(test[i]) < 0) { return false; } } return true; } return match.indexOf(test) >= 0; } /** * @protected * @param {?} matches * @return {?} */ finalizeAsyncCall(matches) { this.prepareMatches(matches || []); this.typeaheadLoading.emit(false); this.typeaheadNoResults.emit(!this.hasMatches()); if (!this.hasMatches()) { this.hide(); return; } if (this._container) { // fix: remove usage of ngControl internals /** @type {?} */ const _controlValue = (this.typeaheadLatinize ? latinize(this.ngControl.control.value) : this.ngControl.control.value) || ''; // This improves the speed as it won't have to be done for each list item /** @type {?} */ const normalizedQuery = _controlValue.toString().toLowerCase(); this._container.query = this.typeaheadSingleWords ? tokenize(normalizedQuery, this.typeaheadWordDelimiters, this.typeaheadPhraseDelimiters) : normalizedQuery; this._container.matches = this._matches; } else { this.show(); } } /** * @protected * @param {?} options * @return {?} */ prepareMatches(options) { /** @type {?} */ const limited = options.slice(0, this.typeaheadOptionsLimit); if (this.typeaheadGroupField) { /** @type {?} */ let matches = []; // extract all group names /** @type {?} */ const groups = limited .map((/** * @param {?} option * @return {?} */ (option) => getValueFromObject(option, this.typeaheadGroupField))) .filter((/** * @param {?} v * @param {?} i * @param {?} a * @return {?} */ (v, i, a) => a.indexOf(v) === i)); groups.forEach((/** * @param {?} group * @return {?} */ (group) => { // add group header to array of matches matches.push(new TypeaheadMatch(group, group, true)); // add each item of group to array of matches matches = matches.concat(limited .filter(( // tslint:disable-next-line:no-any /** * @param {?} option * @return {?} */ (option) => getValueFromObject(option, this.typeaheadGroupField) === group)) .map(( // tslint:disable-next-line:no-any /** * @param {?} option * @return {?} */ (option) => new TypeaheadMatch(option, getValueFromObject(option, this.typeaheadOptionField))))); })); this._matches = matches; } else { this._matches = limited.map(( // tslint:disable-next-line:no-any /** * @param {?} option * @return {?} */ (option) => new TypeaheadMatch(option, getValueFromObject(option, this.typeaheadOptionField)))); } } /** * @protected * @return {?} */ hasMatches() { return this._matches.length > 0; } } TypeaheadDirective.decorators = [ { type: Directive, args: [{ selector: '[typeahead]', exportAs: 'bs-typeahead' },] } ]; /** @nocollapse */ TypeaheadDirective.ctorParameters = () => [ { type: ComponentLoaderFactory }, { type: TypeaheadConfig }, { type: ChangeDetectorRef }, { type: ElementRef }, { type: NgControl }, { type: Renderer2 }, { type: ViewContainerRef } ]; TypeaheadDirective.propDecorators = { typeahead: [{ type: Input }], typeaheadMinLength: [{ type: Input }], adaptivePosition: [{ type: Input }], isAnimated: [{ type: Input }], typeaheadWaitMs: [{ type: Input }], typeaheadOptionsLimit: [{ type: Input }], typeaheadOptionField: [{ type: Input }], typeaheadGroupField: [{ type: Input }], typeaheadAsync: [{ type: Input }], typeaheadLatinize: [{ type: Input }], typeaheadSingleWords: [{ type: Input }], typeaheadWordDelimiters: [{ type: Input }], typeaheadPhraseDelimiters: [{ type: Input }], typeaheadItemTemplate: [{ type: Input }], optionsListTemplate: [{ type: Input }], typeaheadScrollable: [{ type: Input }], typeaheadOptionsInScrollableView: [{ type: Input }], typeaheadHideResultsOnBlur: [{ type: Input }], typeaheadSelectFirstItem: [{ type: Input }], typeaheadIsFirstItemActive: [{ type: Input }], typeaheadLoading: [{ type: Output }], typeaheadNoResults: [{ type: Output }], typeaheadOnSelect: [{ type: Output }], typeaheadOnBlur: [{ type: Output }], container: [{ type: Input }], dropup: [{ type: Input }], onInput: [{ type: HostListener, args: ['input', ['$event'],] }], onChange: [{ type: HostListener, args: ['keyup', ['$event'],] }], onFocus: [{ type: HostListener, args: ['click',] }, { type: HostListener, args: ['focus',] }], onBlur: [{ type: HostListener, args: ['blur',] }], onKeydown: [{ type: HostListener, args: ['keydown', ['$event'],] }] }; if (false) { /** * options source, can be Array of strings, objects or * an Observable for external matching process * @type {?} */ TypeaheadDirective.prototype.typeahead; /** * minimal no of characters that needs to be entered before * typeahead kicks-in. When set to 0, typeahead shows on focus with full * list of options (limited as normal by typeaheadOptionsLimit) * @type {?} */ TypeaheadDirective.prototype.typeaheadMinLength; /** * sets use adaptive position * @type {?} */ TypeaheadDirective.prototype.adaptivePosition; /** * turn on/off animation * @type {?} */ TypeaheadDirective.prototype.isAnimated; /** * minimal wait time after last character typed before typeahead kicks-in * @type {?} */ TypeaheadDirective.prototype.typeaheadWaitMs; /** * maximum length of options items list. The default value is 20 * @type {?} */ TypeaheadDirective.prototype.typeaheadOptionsLimit; /** * when options source is an array of objects, the name of field * that contains the options value, we use array item as option in case * of this field is missing. Supports nested properties and methods. * @type {?} */ TypeaheadDirective.prototype.typeaheadOptionField; /** * when options source is an array of objects, the name of field that * contains the group value, matches are grouped by this field when set. * @type {?} */ TypeaheadDirective.prototype.typeaheadGroupField; /** * should be used only in case of typeahead attribute is array. * If true - loading of options will be async, otherwise - sync. * true make sense if options array is large. * @type {?} */ TypeaheadDirective.prototype.typeaheadAsync; /** * match latin symbols. * If true the word súper would match super and vice versa. * @type {?} */ TypeaheadDirective.prototype.typeaheadLatinize; /** * Can be use to search words by inserting a single white space between each characters * for example 'C a l i f o r n i a' will match 'California'. * @type {?} */ TypeaheadDirective.prototype.typeaheadSingleWords; /** * should be used only in case typeaheadSingleWords attribute is true. * Sets the word delimiter to break words. Defaults to space. * @type {?} */ TypeaheadDirective.prototype.typeaheadWordDelimiters; /** * should be used only in case typeaheadSingleWords attribute is true. * Sets the word delimiter to match exact phrase. * Defaults to simple and double quotes. * @type {?} */ TypeaheadDirective.prototype.typeaheadPhraseDelimiters; /** * used to specify a custom item template. * Template variables exposed are called item and index; * @type {?} */ TypeaheadDirective.prototype.typeaheadItemTemplate; /** * used to specify a custom options list template. * Template variables: matches, itemTemplate, query * @type {?} */ TypeaheadDirective.prototype.optionsListTemplate; /** * specifies if typeahead is scrollable * @type {?} */ TypeaheadDirective.prototype.typeaheadScrollable; /** * specifies number of options to show in scroll view * @type {?} */ TypeaheadDirective.prototype.typeaheadOptionsInScrollableView; /** * used to hide result on blur * @type {?} */ TypeaheadDirective.prototype.typeaheadHideResultsOnBlur; /** * fired when an options list was opened and the user clicked Tab * If a value equal true, it will be chosen first or active item in the list * If value equal false, it will be chosen an active item in the list or nothing * @type {?} */ TypeaheadDirective.prototype.typeaheadSelectFirstItem; /** * makes active first item in a list * @type {?} */ TypeaheadDirective.prototype.typeaheadIsFirstItemActive; /** * fired when 'busy' state of this component was changed, * fired on async mode only, returns boolean * @type {?} */ TypeaheadDirective.prototype.typeaheadLoading; /** * fired on every key event and returns true * in case of matches are not detected * @type {?} */ TypeaheadDirective.prototype.typeaheadNoResults; /** * fired when option was selected, return object with data of this option * @type {?} */ TypeaheadDirective.prototype.typeaheadOnSelect; /** * fired when blur event occurs. returns the active item * @type {?} */ TypeaheadDirective.prototype.typeaheadOnBlur; /** * A selector specifying the element the typeahead should be appended to. * @type {?} */ TypeaheadDirective.prototype.container; /** * This attribute indicates that the dropdown should be opened upwards * @type {?} */ TypeaheadDirective.prototype.dropup; /** * if false don't focus the input element the typeahead directive is associated with on selection * @type {?} */ TypeaheadDirective.prototype._container; /** @type {?} */ TypeaheadDirective.prototype.isActiveItemChanged; /** @type {?} */ TypeaheadDirective.prototype.isTypeaheadOptionsListActive; /** * @type {?} * @protected */ TypeaheadDirective.prototype.keyUpEventEmitter; /** * @type {?} * @protected */ TypeaheadDirective.prototype._matches; /** * @type {?} * @protected */ TypeaheadDirective.prototype.placement; /** * @type {?} * @private */ TypeaheadDirective.prototype._typeahead; /** * @type {?} * @private */ TypeaheadDirective.prototype._subscriptions; /** * @type {?} * @private */ TypeaheadDirective.prototype._outsideClickListener; /** * @type {?} * @private */ TypeaheadDirective.prototype.changeDetection; /** * @type {?} * @private */ TypeaheadDirective.prototype.element; /** * @type {?} * @private */ TypeaheadDirective.prototype.ngControl; /** * @type {?} * @private */ TypeaheadDirective.prototype.renderer; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZWFoZWFkLmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiJuZzovL25neC1ib290c3RyYXAvdHlwZWFoZWFkLyIsInNvdXJjZXMiOlsidHlwZWFoZWFkLmRpcmVjdGl2ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUNBLE9BQU8sRUFDTCxpQkFBaUIsRUFDakIsU0FBUyxFQUNULFVBQVUsRUFDVixZQUFZLEVBQ1osWUFBWSxFQUNaLEtBQUssRUFHTCxNQUFNLEVBQ04sU0FBUyxFQUNULFdBQVcsRUFDWCxnQkFBZ0IsRUFDakIsTUFBTSxlQUFlLENBQUM7QUFFdkIsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTNDLE9BQU8sRUFBRSxJQUFJLEVBQWdCLFlBQVksRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN4RCxPQUFPLEVBQW1CLHNCQUFzQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDekYsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDOUUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNyRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQzNFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFHcEYsTUFBTSxPQUFPLGtCQUFrQjs7Ozs7Ozs7OztJQTJIN0IsWUFDRSxHQUEyQixFQUMzQixNQUF1QixFQUNmLGVBQWtDLEVBQ2xDLE9BQW1CLEVBQ25CLFNBQW9CLEVBQ3BCLFFBQW1CLEVBQzNCLGdCQUFrQztRQUoxQixvQkFBZSxHQUFmLGVBQWUsQ0FBbUI7UUFDbEMsWUFBTyxHQUFQLE9BQU8sQ0FBWTtRQUNuQixjQUFTLEdB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QUl0QyxpREFBcUM7Ozs7Ozs7SUFLckMsNENBQTBDOzs7Ozs7SUFJMUMsK0NBQWtDOzs7Ozs7SUFJbEMsa0RBQXFDOzs7Ozs7SUFJckMscURBQXVDOzs7Ozs7O0lBS3ZDLHVEQUEyQzs7Ozs7O0lBSzNDLG1EQUFpRDs7Ozs7O0lBS2pELGlEQUErQzs7Ozs7SUFFL0MsaURBQXFDOzs7OztJQUVyQyw4REFBOEM7Ozs7O0lBRTlDLHdEQUE2Qzs7Ozs7OztJQUs3QyxzREFBeUM7Ozs7O0lBRXpDLHdEQUEyQzs7Ozs7O0lBSTNDLDhDQUF5RDs7Ozs7O0lBSXpELGdEQUEyRDs7Ozs7SUFFM0QsK0NBQWlFOzs7OztJQUdqRSw2Q0FBb0Q7Ozs7O0lBS3BELHVDQUEyQjs7Ozs7SUFHM0Isb0NBQXdCOzs7OztJQWdCeEIsd0NBQXdDOztJQUN4QyxpREFBNEI7O0lBQzVCLDBEQUFxQzs7Ozs7SUFHckMsK0NBQW9FOzs7OztJQUNwRSxzQ0FBcUM7Ozs7O0lBQ3JDLHVDQUFvQzs7Ozs7SUFHcEMsd0NBQWlFOzs7OztJQUNqRSw0Q0FBNEM7Ozs7O0lBQzVDLG1EQUF3Qzs7Ozs7SUFLdEMsNkNBQTBDOzs7OztJQUMxQyxxQ0FBMkI7Ozs7O0lBQzNCLHVDQUE0Qjs7Ozs7SUFDNUIsc0NBQTJCIiwic291cmNlc0NvbnRlbnQiOlsiLyogdHNsaW50OmRpc2FibGU6bWF4LWZpbGUtbGluZS1jb3VudCAqL1xuaW1wb3J0IHtcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIERpcmVjdGl2ZSxcbiAgRWxlbWVudFJlZixcbiAgRXZlbnRFbWl0dGVyLFxuICBIb3N0TGlzdGVuZXIsXG4gIElucHV0LFxuICBPbkRlc3Ryb3ksXG4gIE9uSW5pdCxcbiAgT3V0cHV0LFxuICBSZW5kZXJlcjIsXG4gIFRlbXBsYXRlUmVmLFxuICBWaWV3Q29udGFpbmVyUmVmXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5pbXBvcnQgeyBOZ0NvbnRyb2wgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5cbmltcG9ydCB7IGZyb20sIFN1YnNjcmlwdGlvbiwgaXNPYnNlcnZhYmxlIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBDb21wb25lbnRMb2FkZXIsIENvbXBvbmVudExvYWRlckZhY3RvcnkgfSBmcm9tICduZ3gtYm9vdHN0cmFwL2NvbXBvbmVudC1sb2FkZXInO1xuaW1wb3J0IHsgVHlwZWFoZWFkQ29udGFpbmVyQ29tcG9uZW50IH0gZnJvbSAnLi90eXBlYWhlYWQtY29udGFpbmVyLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBUeXBlYWhlYWRNYXRjaCB9IGZyb20gJy4vdHlwZWFoZWFkLW1hdGNoLmNsYXNzJztcbmltcG9ydCB7IFR5cGVhaGVhZENvbmZpZyB9IGZyb20gJy4vdHlwZWFoZWFkLmNvbmZpZyc7XG5pbXBvcnQgeyBnZXRWYWx1ZUZyb21PYmplY3QsIGxhdGluaXplLCB0b2tlbml6ZSB9IGZyb20gJy4vdHlwZWFoZWFkLXV0aWxzJztcbmltcG9ydCB7IGRlYm91bmNlVGltZSwgZmlsdGVyLCBtZXJnZU1hcCwgc3dpdGNoTWFwLCB0b0FycmF5IH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5ARGlyZWN0aXZlKHtzZWxlY3RvcjogJ1t0eXBlYWhlYWRdJywgZXhwb3J0QXM6ICdicy10eXBlYWhlYWQnfSlcbmV4cG9ydCBjbGFzcyBUeXBlYWhlYWREaXJlY3RpdmUgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSB7XG4gIC8qKiBvcHRpb25zIHNvdXJjZSwgY2FuIGJlIEFycmF5IG9mIHN0cmluZ3MsIG9iamVjdHMgb3JcbiAgICogYW4gT2JzZXJ2YWJsZSBmb3IgZXh0ZXJuYWwgbWF0Y2hpbmcgcHJvY2Vzc1xuICAgKi9cbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tYW55XG4gIEBJbnB1dCgpIHR5cGVhaGVhZDogYW55O1xuICAvKiogbWluaW1hbCBubyBvZiBjaGFyYWN0ZXJzIHRoYXQgbmVlZHMgdG8gYmUgZW50ZXJlZCBiZWZvcmVcbiAgICogdHlwZWFoZWFkIGtpY2tzLWluLiBXaGVuIHNldCB0byAwLCB0eXBlYWhlYWQgc2hvd3Mgb24gZm9jdXMgd2l0aCBmdWxsXG4gICAqIGxpc3Qgb2Ygb3B0aW9ucyAobGltaXRlZCBhcyBub3JtYWwgYnkgdHlwZWFoZWFkT3B0aW9uc0xpbWl0KVxuICAgKi9cbiAgQElucHV0KCkgdHlwZWFoZWFkTWluTGVuZ3RoOiBudW1iZXIgPSB2b2lkIDA7XG4gIC8qKiBzZXRzIHVzZSBhZGFwdGl2ZSBwb3NpdGlvbiAqL1xuICBASW5wdXQoKSBhZGFwdGl2ZVBvc2l0aW9uOiBib29sZWFuO1xuICAvKiogdHVybiBvbi9vZmYgYW5pbWF0aW9uICovXG4gIEBJbnB1dCgpIGlzQW5pbWF0ZWQgPSBmYWxzZTtcbiAgLyoqIG1pbmltYWwgd2FpdCB0aW1lIGFmdGVyIGxhc3QgY2hhcmFjdGVyIHR5cGVkIGJlZm9yZSB0eXBlYWhlYWQga2lja3MtaW4gKi9cbiAgQElucHV0KCkgdHlwZWFoZWFkV2FpdE1zOiBudW1iZXI7XG4gIC8qKiBtYXhpbXVtIGxlbmd0aCBvZiBvcHRpb25zIGl0ZW1zIGxpc3QuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIDIwICovXG4gIEBJbnB1dCgpIHR5cGVhaGVhZE9wdGlvbnNMaW1pdDogbnVtYmVyO1xuICAvKiogd2hlbiBvcHRpb25zIHNvdXJjZSBpcyBhbiBhcnJheSBvZiBvYmplY3RzLCB0aGUgbmFtZSBvZiBmaWVsZFxuICAgKiB0aGF0IGNvbnRhaW5zIHRoZSBvcHRpb25zIHZhbHVlLCB3ZSB1c2UgYXJyYXkgaXRlbSBhcyBvcHRpb24gaW4gY2FzZVxuICAgKiBvZiB0aGlzIGZpZWxkIGlzIG1pc3NpbmcuIFN1cHBvcnRzIG5lc3RlZCBwcm9wZXJ0aWVzIGFuZCBtZXRob2RzLlxuICAgKi9cbiAgQElucHV0KCkgdHlwZWFoZWFkT3B0aW9uRmllbGQ6IHN0cmluZztcbiAgLyoqIHdoZW4gb3B0aW9ucyBzb3VyY2UgaXMgYW4gYXJyYXkgb2Ygb2JqZWN0cywgdGhlIG5hbWUgb2YgZmllbGQgdGhhdFxuICAgKiBjb250YWlucyB0aGUgZ3JvdXAgdmFsdWUsIG1hdGNoZXMgYXJlIGdyb3VwZWQgYnkgdGhpcyBmaWVsZCB3aGVuIHNldC5cbiAgICovXG4gIEBJbnB1dCgpIHR5cGVhaGVhZEdyb3VwRmllbGQ6IHN0cmluZztcbiAgLyoqIHNob3VsZCBiZSB1c2VkIG9ubHkgaW4gY2FzZSBvZiB0eXBlYWhlYWQgYXR0cmlidXRlIGlzIGFycmF5LlxuICAgKiBJZiB0cnVlIC0gbG9hZGluZyBvZiBvcHRpb25zIHdpbGwgYmUgYXN5bmMsIG90aGVyd2lzZSAtIHN5bmMuXG4gICAqIHRydWUgbWFrZSBzZW5zZSBpZiBvcHRpb25zIGFycmF5IGlzIGxhcmdlLlxuICAgKi9cbiAgQElucHV0KCkgdHlwZWFoZWFkQXN5bmM6IGJvb2xlYW4gPSB2b2lkIDA7XG4gIC8qKiBtYXRjaCBsYXRpbiBzeW1ib2xzLlxuICAgKiBJZiB0cnVlIHRoZSB3b3JkIHPDunBlciB3b3VsZCBtYXRjaCBzdXBlciBhbmQgdmljZSB2ZXJzYS5cbiAgICovXG4gIEBJbnB1dCgpIHR5cGVhaGVhZExhdGluaXplID0gdHJ1ZTtcbiAgLyoqIENhbiBiZSB1c2UgdG8gc2VhcmNoIHdvcmRzIGJ5IGluc2VydGluZyBhIHNpbmdsZSB3aGl0ZSBzcGFjZSBiZXR3ZWVuIGVhY2ggY2hhcmFjdGVyc1xuICAgKiAgZm9yIGV4YW1wbGUgJ0MgYSBsIGkgZiBvIHIgbiBpIGEnIHdpbGwgbWF0Y2ggJ0NhbGlmb3JuaWEnLlxuICAgKi9cbiAgQElucHV0KCkgdHlwZWFoZWFkU2luZ2xlV29yZHMgPSB0cnVlO1xuICAvKiogc2hvdWxkIGJlIHVzZWQgb25seSBpbiBjYXNlIHR5cGVhaGVhZFNpbmdsZVdvcmRzIGF0dHJpYnV0ZSBpcyB0cnVlLlxuICAgKiBTZXRzIHRoZSB3b3JkIGRlbGltaXRlciB0byBicmVhayB3b3Jkcy4gRGVmYXVsdHMgdG8gc3BhY2UuXG4gICAqL1xuICBASW5wdXQoKSB0eXBlYWhlYWRXb3JkRGVsaW1pdGVycyA9ICcgJztcbiAgLyoqIHNob3VsZCBiZSB1c2VkIG9ubHkgaW4gY2FzZSB0eXBlYWhlYWRTaW5nbGVXb3JkcyBhdHRyaWJ1dGUgaXMgdHJ1ZS5cbiAgICogU2V0cyB0aGUgd29yZCBkZWxpbWl0ZXIgdG8gbWF0Y2ggZXhhY3QgcGhyYXNlLlxuICAgKiBEZWZhdWx0cyB0byBzaW1wbGUgYW5kIGRvdWJsZSBxdW90ZXMuXG4gICAqL1xuICBASW5wdXQoKSB0eXBlYWhlYWRQaHJhc2VEZWxpbWl0ZXJzID0gJ1xcJ1wiJztcbiAgLyoqIHVzZWQgdG8gc3BlY2lmeSBhIGN1c3RvbSBpdGVtIHRlbXBsYXRlLlxuICAgKiBUZW1wbGF0ZSB2YXJpYWJsZXMgZXhwb3NlZCBhcmUgY2FsbGVkIGl0ZW0gYW5kIGluZGV4O1xuICAgKi9cbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tYW55XG4gIEBJbnB1dCgpIHR5cGVhaGVhZEl0ZW1UZW1wbGF0ZTogVGVtcGxhdGVSZWY8YW55PjtcbiAgLyoqIHVzZWQgdG8gc3BlY2lmeSBhIGN1c3RvbSBvcHRpb25zIGxpc3QgdGVtcGxhdGUuXG4gICAqIFRlbXBsYXRlIHZhcmlhYmxlczogbWF0Y2hlcywgaXRlbVRlbXBsYXRlLCBxdWVyeVxuICAgKi9cbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tYW55XG4gIEBJbnB1dCgpIG9wdGlvbnNMaXN0VGVtcGxhdGU6IFRlbXBsYXRlUmVmPGFueT47XG4gIC8qKiBzcGVjaWZpZXMgaWYgdHlwZWFoZWFkIGlzIHNjcm9sbGFibGUgICovXG4gIEBJbnB1dCgpIHR5cGVhaGVhZFNjcm9sbGFibGUgPSBmYWxzZTtcbiAgLyoqIHNwZWNpZmllcyBudW1iZXIgb2Ygb3B0aW9ucyB0byBzaG93IGluIHNjcm9sbCB2aWV3ICAqL1xuICBASW5wdXQoKSB0eXBlYWhlYWRPcHRpb25zSW5TY3JvbGxhYmxlVmlldyA9IDU7XG4gIC8qKiB1c2VkIHRvIGhpZGUgcmVzdWx0IG9uIGJsdXIgKi9cbiAgQElucHV0KCkgdHlwZWFoZWFkSGlkZVJlc3VsdHNPbkJsdXI6IGJvb2xlYW47XG4gIC8qKiBmaXJlZCB3aGVuIGFuIG9wdGlvbnMgbGlzdCB3YXMgb3BlbmVkIGFuZCB0aGUgdXNlciBjbGlja2VkIFRhYlxuICAgKiBJZiBhIHZhbHVlIGVxdWFsIHRydWUsIGl0IHdpbGwgYmUgY2hvc2VuIGZpcnN0IG9yIGFjdGl2ZSBpdGVtIGluIHRoZSBsaXN0XG4gICAqIElmIHZhbHVlIGVxdWFsIGZhbHNlLCBpdCB3aWxsIGJlIGNob3NlbiBhbiBhY3RpdmUgaXRlbSBpbiB0aGUgbGlzdCBvciBub3RoaW5nXG4gICAqL1xuICBASW5wdXQoKSB0eXBlYWhlYWRTZWxlY3RGaXJzdEl0ZW0gPSB0cnVlO1xuICAvKiogbWFrZXMgYWN0aXZlIGZpcnN0IGl0ZW0gaW4gYSBsaXN0ICovXG4gIEBJbnB1dCgpIHR5cGVhaGVhZElzRmlyc3RJdGVtQWN0aXZlID0gdHJ1ZTtcbiAgLyoqIGZpcmVkIHdoZW4gJ2J1c3knIHN0YXRlIG9mIHRoaXMgY29tcG9uZW50IHdhcyBjaGFuZ2VkLFxuICAgKiBmaXJlZCBvbiBhc3luYyBtb2RlIG9ubHksIHJldHVybnMgYm9vbGVhblxuICAgKi9cbiAgQE91dHB1dCgpIHR5cGVhaGVhZExvYWRpbmcgPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XG4gIC8qKiBmaXJlZCBvbiBldmVyeSBrZXkgZXZlbnQgYW5kIHJldHVybnMgdHJ1ZVxuICAgKiBpbiBjYXNlIG9mIG1hdGNoZXMgYXJlIG5vdCBkZXRlY3RlZFxuICAgKi9cbiAgQE91dHB1dCgpIHR5cGVhaGVhZE5vUmVzdWx0cyA9IG5ldyBFdmVudEVtaXR0ZXI8Ym9vbGVhbj4oKTtcbiAgLyoqIGZpcmVkIHdoZW4gb3B0aW9uIHdhcyBzZWxlY3RlZCwgcmV0dXJuIG9iamVjdCB3aXRoIGRhdGEgb2YgdGhpcyBvcHRpb24gKi9cbiAgQE91dHB1dCgpIHR5cGVhaGVhZE9uU2VsZWN0ID0gbmV3IEV2ZW50RW1pdHRlcjxUeXBlYWhlYWRNYXRjaD4oKTtcbiAgLyoqIGZpcmVkIHdoZW4gYmx1ciBldmVudCBvY2N1cnMuIHJldHVybnMgdGhlIGFjdGl2ZSBpdGVtICovXG4gIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby1hbnlcbiAgQE91dHB1dCgpIHR5cGVhaGVhZE9uQmx1ciA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xuXG4gIC8qKlxuICAgKiBBIHNlbGVjdG9yIHNwZWNpZnlpbmcgdGhlIGVsZW1lbnQgdGhlIHR5cGVhaGVhZCBzaG91bGQgYmUgYXBwZW5kZWQgdG8uXG4gICAqL1xuICBASW5wdXQoKSBjb250YWluZXI6IHN0cmluZztcblxuICAvKiogVGhpcyBhdHRyaWJ1dGUgaW5kaWNhdGVzIHRoYXQgdGhlIGRyb3Bkb3duIHNob3VsZCBiZSBvcGVuZWQgdXB3YXJkcyAqL1xuICBASW5wdXQoKSBkcm9wdXAgPSBmYWxzZTtcblxuICAvLyBub3QgeWV0IGltcGxlbWVudGVkXG4gIC8qKiBpZiBmYWxzZSByZXN0cmljdCBtb2RlbCB2YWx1ZXMgdG8gdGhlIG9uZXMgc2VsZWN0ZWQgZnJvbSB0aGUgcG9wdXAgb25seSB3aWxsIGJlIHByb3ZpZGVkICovXG4gIC8vIEBJbnB1dCgpIHByb3RlY3RlZCB0eXBlYWhlYWRFZGl0YWJsZTpib29sZWFuO1xuICAvKiogaWYgZmFsc2UgdGhlIGZpcnN0IG1hdG