UNPKG

fundamental-ngx

Version:

SAP Fundamentals, implemented in Angular

567 lines 45.9 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ import { Component, ContentChildren, EventEmitter, forwardRef, HostBinding, HostListener, Input, Output, QueryList, TemplateRef, ViewEncapsulation } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { OptionComponent } from './option/option.component'; import { defer, merge, Subject } from 'rxjs'; import { startWith, switchMap, takeUntil } from 'rxjs/operators'; /** * Select component intended to mimic the behaviour of the native select element. */ export class SelectComponent { constructor() { /** * @hidden */ this.fdDropdownClass = true; /** * Whether the select component is disabled. */ this.disabled = false; /** * Open state of the select. */ this.isOpen = false; /** * Popper.js options of the popover. */ this.popperOptions = { placement: 'bottom-start', modifiers: { preventOverflow: { enabled: true, escapeWithReference: true, boundariesElement: 'scrollParent' } } }; /** * Preset options for the popover body width. * * `at-least` will apply a minimum width to the body equivalent to the width of the control. * * `equal` will apply a width to the body equivalent to the width of the control. * * Leave blank for no effect. */ this.fillControlMode = 'at-least'; /** * Event emitted when the popover open state changes. */ this.isOpenChange = new EventEmitter(); /** * Event emitted when the selected value of the select changes. */ this.valueChange = new EventEmitter(); /** * Subject triggered when the component is destroyed. */ this.destroy$ = new Subject(); /** * Observable triggered when an option has its selectedChange event fire. */ this.optionsStatusChanges = (/** @type {?} */ (defer((/** * @return {?} */ () => { /** @type {?} */ const options = this.options; if (options) { return options.changes.pipe(startWith(options), switchMap((/** * @return {?} */ () => merge(...options.map((/** * @param {?} option * @return {?} */ option => option.selectedChange)))))); } })))); /** * @hidden */ this.onChange = (/** * @return {?} */ () => { }); /** * @hidden */ this.onTouched = (/** * @return {?} */ () => { }); } /** * @hidden * @param {?} changes * @return {?} */ ngOnChanges(changes) { if (changes.value) { setTimeout((/** * @return {?} */ () => { if (this.value) { this.selectValue(this.value, false); } })); } } /** * @hidden * @return {?} */ ngAfterContentInit() { // If the observable state changes, reset the options and initialize selection. this.options.changes.pipe(startWith(null), takeUntil(this.destroy$)).subscribe((/** * @return {?} */ () => { this.resetOptions(); this.initSelection(); })); } /** * @hidden * @return {?} */ ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); } /** * Toggles the open state of the select. * @return {?} */ toggle() { if (this.isOpen && !this.disabled) { this.close(); } else { this.open(); } } /** * Opens the select popover body. * @return {?} */ open() { if (!this.isOpen && !this.disabled) { this.isOpen = true; this.isOpenChange.emit(this.isOpen); } } /** * Closes the select popover body. * @return {?} */ close() { if (this.isOpen && !this.disabled) { this.isOpen = false; this.isOpenChange.emit(this.isOpen); } } /** * @hidden * @param {?} fn * @return {?} */ registerOnChange(fn) { this.onChange = fn; } /** * @hidden * @param {?} fn * @return {?} */ registerOnTouched(fn) { this.onTouched = fn; } /** * @hidden * @param {?} isDisabled * @return {?} */ setDisabledState(isDisabled) { this.disabled = isDisabled; } /** * @hidden * @param {?} value * @return {?} */ writeValue(value) { if (this.options) { this.selectValue(value, false); } else { // Defer the selection of the value to support forms Promise.resolve().then((/** * @return {?} */ () => { if (this.options) { this.selectValue(value, false); } })); } } /** * Returns the current trigger value if there is a selected option. Otherwise, returns the placeholder. * @return {?} */ get triggerValue() { return this.selected ? this.selected.viewValueText : this.placeholder; } /** * @hidden * @param {?} event * @return {?} */ keydownHandler(event) { switch (event.code) { case ('ArrowUp'): { event.preventDefault(); this.decrementFocused(); break; } case ('ArrowDown'): { event.preventDefault(); this.incrementFocused(); break; } } } /** * Selects an option by option component reference. Preferred method of selection. * @private * @param {?} option The option component to search for. * @param {?=} fireEvents Whether to fire change events. * @return {?} */ selectOption(option, fireEvents = true) { if (!this.isOptionActive(option)) { if (this.selected) { this.selected.setSelected(false, false); } option.setSelected(true, false); this.selected = option; this.updateValue(fireEvents); this.close(); return option; } return; } /** * Selects an option by value. If two components have the same value, the first one found is selected. * Recommend using selectOption generally. * @private * @param {?} value Value to search for. * @param {?=} fireEvents Whether to fire change events. * @return {?} */ selectValue(value, fireEvents = true) { /** @type {?} */ const matchOption = this.options.find((/** * @param {?} option * @return {?} */ (option) => { return option.value != null && option.value === value; })); // If not match is found, set everything to null // This is mostly only for cases where a user removes an active option if (!matchOption) { this.unselectOptions(); return; } // If match is found, select the new value if (matchOption && !this.isOptionActive(matchOption)) { if (this.selected) { this.selected.setSelected(false, false); } matchOption.setSelected(true, false); this.selected = matchOption; this.updateValue(fireEvents); this.close(); } return matchOption; } /** * Updates the value parameter with optional events. * @private * @param {?=} fireEvents If true, function fires valueChange, onChange and onTouched events. * @return {?} */ updateValue(fireEvents = true) { this.value = this.selected.value; if (fireEvents) { this.valueChange.emit(this.value); this.onChange(this.value); this.onTouched(); } } /** * Function used to reset the options state. * @private * @return {?} */ resetOptions() { // Create observable that fires when the options change or the component is destroyed. /** @type {?} */ const destroyCurrentObs = merge(this.options.changes, this.destroy$); // Subscribe to observable defined in component properties which fires when an option is clicked. // Destroy if the observable defined above triggers. this.optionsStatusChanges.pipe(takeUntil(destroyCurrentObs)).subscribe((/** * @param {?} instance * @return {?} */ (instance) => { this.selectOption(instance); })); } /** * Selection initialization when a change occurs in options. * @private * @return {?} */ initSelection() { if (this.value) { this.selected = undefined; this.selectValue(this.value, false); } } /** * Function that tests whether the tested option is currently selected. * @private * @param {?} option Option to test against the selected option. * @return {?} */ isOptionActive(option) { return option && this.selected && option === this.selected; } /** * Method that focuses the next option in the list, or the first one if the last one is currently focused. * @private * @return {?} */ incrementFocused() { // Get active focused element /** @type {?} */ const activeElement = document.activeElement; // Get corresponding option element to the above /** @type {?} */ const correspondingOption = this.options.find((/** * @param {?} option * @return {?} */ option => { return option.getHtmlElement() === activeElement; })); if (correspondingOption) { /** @type {?} */ const arrayOptions = this.options.toArray(); /** @type {?} */ const index = arrayOptions.indexOf(correspondingOption); // If active option is the last option, focus the first one // Otherwise, focus the next option. if (index === this.options.length - 1) { arrayOptions[0].focus(); } else { arrayOptions[index + 1].focus(); } } else if (this.options) { this.options.first.focus(); } } /** * Method that focuses the previous option in the list, or the last one if the last one is currently focused. * @private * @return {?} */ decrementFocused() { // Get active focused element /** @type {?} */ const activeElement = document.activeElement; // Get corresponding option element to the above /** @type {?} */ const correspondingOption = this.options.find((/** * @param {?} option * @return {?} */ option => { return option.getHtmlElement() === activeElement; })); // If active option is the first option, focus the last one // Otherwise, focus the previous option. if (correspondingOption) { /** @type {?} */ const arrayOptions = this.options.toArray(); /** @type {?} */ const index = arrayOptions.indexOf(correspondingOption); if (index === 0) { arrayOptions[this.options.length - 1].focus(); } else { arrayOptions[index - 1].focus(); } } else if (this.options) { this.options.first.focus(); } } /** * Method used to handle cases where a user removes the currently active option. * The timeout is required because this can happen after the view has been checked. * @private * @return {?} */ unselectOptions() { setTimeout((/** * @return {?} */ () => { if (this.selected) { this.selected.setSelected(false, false); } this.selected = undefined; this.value = undefined; this.valueChange.emit(undefined); this.onChange(undefined); })); } } SelectComponent.decorators = [ { type: Component, args: [{ selector: 'fd-select', template: "<fd-popover [(isOpen)]=\"isOpen\"\n (isOpenChange)=\"isOpenChange.emit($event)\"\n [options]=\"popperOptions\"\n [fillControlMode]=\"fillControlMode\"\n [appendTo]=\"appendTo\"\n class=\"fd-select-popover-custom\">\n <fd-popover-control>\n <ng-container *ngIf=\"triggerTemplate\">\n <ng-container *ngTemplateOutlet=\"triggerTemplate; context: {$implicit: this}\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"!triggerTemplate\">\n <button class=\"fd-dropdown__control fd-button fd-select-button-custom\"\n [attr.aria-expanded]=\"isOpen\"\n aria-haspopup=\"true\"\n [disabled]=\"disabled\">\n <span class=\"fd-select-text-custom\">{{triggerValue}}</span>\n </button>\n </ng-container>\n </fd-popover-control>\n <fd-popover-body>\n <ng-content></ng-content>\n </fd-popover-body>\n</fd-popover>\n", encapsulation: ViewEncapsulation.None, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef((/** * @return {?} */ () => SelectComponent)), multi: true } ], host: { '[class.fd-select-custom]': 'true', 'role': 'listbox', }, styles: [".fd-select-custom{display:inline-block;width:100%}.fd-select-custom .fd-select-popover-custom{display:block}.fd-select-custom .fd-select-popover-custom fd-popover-container{min-width:100%;overflow:auto}.fd-select-custom .fd-select-button-custom{display:flex;align-items:flex-end;justify-content:space-between}.fd-select-custom .fd-select-button-custom::after{flex-shrink:0;margin-top:0}.fd-select-custom .fd-select-text-custom{text-overflow:ellipsis;white-space:nowrap;overflow-x:hidden}"] }] } ]; SelectComponent.propDecorators = { fdDropdownClass: [{ type: HostBinding, args: ['class.fd-dropdown',] }], options: [{ type: ContentChildren, args: [OptionComponent, { descendants: true },] }], disabled: [{ type: Input }], placeholder: [{ type: Input }], isOpen: [{ type: Input }], value: [{ type: Input }], popperOptions: [{ type: Input }], fillControlMode: [{ type: Input }], triggerTemplate: [{ type: Input }], appendTo: [{ type: Input }], isOpenChange: [{ type: Output }], valueChange: [{ type: Output }], keydownHandler: [{ type: HostListener, args: ['keydown', ['$event'],] }] }; if (false) { /** * @hidden * @type {?} */ SelectComponent.prototype.fdDropdownClass; /** * @hidden * @type {?} */ SelectComponent.prototype.options; /** * Whether the select component is disabled. * @type {?} */ SelectComponent.prototype.disabled; /** * Placeholder for the select. Appears in the triggerbox if no option is selected. * @type {?} */ SelectComponent.prototype.placeholder; /** * Open state of the select. * @type {?} */ SelectComponent.prototype.isOpen; /** * Current value of the selected option. * @type {?} */ SelectComponent.prototype.value; /** * Popper.js options of the popover. * @type {?} */ SelectComponent.prototype.popperOptions; /** * Preset options for the popover body width. * * `at-least` will apply a minimum width to the body equivalent to the width of the control. * * `equal` will apply a width to the body equivalent to the width of the control. * * Leave blank for no effect. * @type {?} */ SelectComponent.prototype.fillControlMode; /** * Template with which to display the trigger box. * @type {?} */ SelectComponent.prototype.triggerTemplate; /** * The element to which the popover should be appended. * @type {?} */ SelectComponent.prototype.appendTo; /** * Event emitted when the popover open state changes. * @type {?} */ SelectComponent.prototype.isOpenChange; /** * Event emitted when the selected value of the select changes. * @type {?} */ SelectComponent.prototype.valueChange; /** * Current selected option component reference. * @type {?} * @private */ SelectComponent.prototype.selected; /** * Subject triggered when the component is destroyed. * @type {?} * @private */ SelectComponent.prototype.destroy$; /** * Observable triggered when an option has its selectedChange event fire. * @type {?} * @private */ SelectComponent.prototype.optionsStatusChanges; /** * @hidden * @type {?} */ SelectComponent.prototype.onChange; /** * @hidden * @type {?} */ SelectComponent.prototype.onTouched; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VsZWN0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL2Z1bmRhbWVudGFsLW5neC8iLCJzb3VyY2VzIjpbImxpYi9zZWxlY3Qvc2VsZWN0LmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsT0FBTyxFQUVILFNBQVMsRUFDVCxlQUFlLEVBQ2YsWUFBWSxFQUFFLFVBQVUsRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUNuRCxLQUFLLEVBQ0wsTUFBTSxFQUNOLFNBQVMsRUFBaUIsV0FBVyxFQUNyQyxpQkFBaUIsRUFDcEIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUF3QixpQkFBaUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3pFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUM1RCxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBYyxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDekQsT0FBTyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7Ozs7QUF3QmpFLE1BQU0sT0FBTyxlQUFlO0lBakI1Qjs7OztRQXFCSSxvQkFBZSxHQUFZLElBQUksQ0FBQzs7OztRQVFoQyxhQUFRLEdBQVksS0FBSyxDQUFDOzs7O1FBUTFCLFdBQU0sR0FBWSxLQUFLLENBQUM7Ozs7UUFReEIsa0JBQWEsR0FBa0I7WUFDM0IsU0FBUyxFQUFFLGNBQWM7WUFDekIsU0FBUyxFQUFFO2dCQUNQLGVBQWUsRUFBRTtvQkFDYixPQUFPLEVBQUUsSUFBSTtvQkFDYixtQkFBbUIsRUFBRSxJQUFJO29CQUN6QixpQkFBaUIsRUFBRSxjQUFjO2lCQUNwQzthQUNKO1NBQ0osQ0FBQzs7Ozs7OztRQVNGLG9CQUFlLEdBQW9CLFVBQVUsQ0FBQzs7OztRQVlyQyxpQkFBWSxHQUNmLElBQUksWUFBWSxFQUFXLENBQUM7Ozs7UUFJekIsZ0JBQVcsR0FDZCxJQUFJLFlBQVksRUFB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V0FBVyxTQUFDLG1CQUFtQjtzQkFJL0IsZUFBZSxTQUFDLGVBQWUsRUFBRSxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUU7dUJBSXRELEtBQUs7MEJBSUwsS0FBSztxQkFJTCxLQUFLO29CQUlMLEtBQUs7NEJBSUwsS0FBSzs4QkFrQkwsS0FBSzs4QkFJTCxLQUFLO3VCQUlMLEtBQUs7MkJBSUwsTUFBTTswQkFLTixNQUFNOzZCQWtITixZQUFZLFNBQUMsU0FBUyxFQUFFLENBQUMsUUFBUSxDQUFDOzs7Ozs7O0lBN0tuQywwQ0FDZ0M7Ozs7O0lBR2hDLGtDQUNvQzs7Ozs7SUFHcEMsbUNBQzBCOzs7OztJQUcxQixzQ0FDb0I7Ozs7O0lBR3BCLGlDQUN3Qjs7Ozs7SUFHeEIsZ0NBQ1c7Ozs7O0lBR1gsd0NBVUU7Ozs7Ozs7O0lBUUYsMENBQzhDOzs7OztJQUc5QywwQ0FDa0M7Ozs7O0lBR2xDLG1DQUMrQjs7Ozs7SUFHL0IsdUNBRWtDOzs7OztJQUdsQyxzQ0FFOEI7Ozs7OztJQUc5QixtQ0FBa0M7Ozs7OztJQUdsQyxtQ0FBK0Q7Ozs7OztJQUcvRCwrQ0FRa0M7Ozs7O0lBR2xDLG1DQUE4Qjs7Ozs7SUFHOUIsb0NBQStCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgICBBZnRlckNvbnRlbnRJbml0LFxuICAgIENvbXBvbmVudCxcbiAgICBDb250ZW50Q2hpbGRyZW4sXG4gICAgRXZlbnRFbWl0dGVyLCBmb3J3YXJkUmVmLCBIb3N0QmluZGluZywgSG9zdExpc3RlbmVyLFxuICAgIElucHV0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSxcbiAgICBPdXRwdXQsXG4gICAgUXVlcnlMaXN0LCBTaW1wbGVDaGFuZ2VzLCBUZW1wbGF0ZVJlZixcbiAgICBWaWV3RW5jYXBzdWxhdGlvblxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbnRyb2xWYWx1ZUFjY2Vzc29yLCBOR19WQUxVRV9BQ0NFU1NPUiB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IE9wdGlvbkNvbXBvbmVudCB9IGZyb20gJy4vb3B0aW9uL29wdGlvbi5jb21wb25lbnQnO1xuaW1wb3J0IHsgZGVmZXIsIG1lcmdlLCBPYnNlcnZhYmxlLCBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBzdGFydFdpdGgsIHN3aXRjaE1hcCwgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgUG9wcGVyT3B0aW9ucyB9IGZyb20gJ3BvcHBlci5qcyc7XG5pbXBvcnQgeyBQb3BvdmVyRmlsbE1vZGUgfSBmcm9tICcuLi9wb3BvdmVyL3BvcG92ZXItZGlyZWN0aXZlL3BvcG92ZXIuZGlyZWN0aXZlJztcblxuLyoqXG4gKiBTZWxlY3QgY29tcG9uZW50IGludGVuZGVkIHRvIG1pbWljIHRoZSBiZWhhdmlvdXIgb2YgdGhlIG5hdGl2ZSBzZWxlY3QgZWxlbWVudC5cbiAqL1xuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICdmZC1zZWxlY3QnLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9zZWxlY3QuY29tcG9uZW50Lmh0bWwnLFxuICAgIHN0eWxlVXJsczogWycuL3NlbGVjdC5jb21wb25lbnQuc2NzcyddLFxuICAgIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG4gICAgcHJvdmlkZXJzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICAgIHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuICAgICAgICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gU2VsZWN0Q29tcG9uZW50KSxcbiAgICAgICAgICAgIG11bHRpOiB0cnVlXG4gICAgICAgIH1cbiAgICBdLFxuICAgIGhvc3Q6IHtcbiAgICAgICAgJ1tjbGFzcy5mZC1zZWxlY3QtY3VzdG9tXSc6ICd0cnVlJyxcbiAgICAgICAgJ3JvbGUnOiAnbGlzdGJveCcsXG4gICAgfVxufSlcbmV4cG9ydCBjbGFzcyBTZWxlY3RDb21wb25lbnQgaW1wbGVtZW50cyBPbkNoYW5nZXMsIEFmdGVyQ29udGVudEluaXQsIE9uRGVzdHJveSwgQ29udHJvbFZhbHVlQWNjZXNzb3Ige1xuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBASG9zdEJpbmRpbmcoJ2NsYXNzLmZkLWRyb3Bkb3duJylcbiAgICBmZERyb3Bkb3duQ2xhc3M6IGJvb2xlYW4gPSB0cnVlO1xuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBAQ29udGVudENoaWxkcmVuKE9wdGlvbkNvbXBvbmVudCwgeyBkZXNjZW5kYW50czogdHJ1ZSB9KVxuICAgIG9wdGlvbnM6IFF1ZXJ5TGlzdDxPcHRpb25Db21wb25lbnQ+O1xuXG4gICAgLyoqIFdoZXRoZXIgdGhlIHNlbGVjdCBjb21wb25lbnQgaXMgZGlzYWJsZWQuICovXG4gICAgQElucHV0KClcbiAgICBkaXNhYmxlZDogYm9vbGVhbiA9IGZhbHNlO1xuXG4gICAgLyoqIFBsYWNlaG9sZGVyIGZvciB0aGUgc2VsZWN0LiBBcHBlYXJzIGluIHRoZSB0cmlnZ2VyYm94IGlmIG5vIG9wdGlvbiBpcyBzZWxlY3RlZC4gKi9cbiAgICBASW5wdXQoKVxuICAgIHBsYWNlaG9sZGVyOiBzdHJpbmc7XG5cbiAgICAvKiogT3BlbiBzdGF0ZSBvZiB0aGUgc2VsZWN0LiAqL1xuICAgIEBJbnB1dCgpXG4gICAgaXNPcGVuOiBib29sZWFuID0gZmFsc2U7XG5cbiAgICAvKiogQ3VycmVudCB2YWx1ZSBvZiB0aGUgc2VsZWN0ZWQgb3B0aW9uLiAqL1xuICAgIEBJbnB1dCgpXG4gICAgdmFsdWU6IGFueTtcblxuICAgIC8qKiBQb3BwZXIuanMgb3B0aW9ucyBvZiB0aGUgcG9wb3Zlci4gKi9cbiAgICBASW5wdXQoKVxuICAgIHBvcHBlck9wdGlvbnM6IFBvcHBlck9wdGlvbnMgPSB7XG4gICAgICAgIHBsYWNlbWVudDogJ2JvdHRvbS1zdGFydCcsXG4gICAgICAgIG1vZGlmaWVyczoge1xuICAgICAgICAgICAgcHJldmVudE92ZXJmbG93OiB7XG4gICAgICAgICAgICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICBlc2NhcGVXaXRoUmVmZXJlbmNlOiB0cnVlLFxuICAgICAgICAgICAgICAgIGJvdW5kYXJpZXNFbGVtZW50OiAnc2Nyb2xsUGFyZW50J1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFByZXNldCBvcHRpb25zIGZvciB0aGUgcG9wb3ZlciBib2R5IHdpZHRoLlxuICAgICAqICogYGF0LWxlYXN0YCB3aWxsIGFwcGx5IGEgbWluaW11bSB3aWR0aCB0byB0aGUgYm9keSBlcXVpdmFsZW50IHRvIHRoZSB3aWR0aCBvZiB0aGUgY29udHJvbC5cbiAgICAgKiAqIGBlcXVhbGAgd2lsbCBhcHBseSBhIHdpZHRoIHRvIHRoZSBib2R5IGVxdWl2YWxlbnQgdG8gdGhlIHdpZHRoIG9mIHRoZSBjb250cm9sLlxuICAgICAqICogTGVhdmUgYmxhbmsgZm9yIG5vIGVmZmVjdC5cbiAgICAgKi9cbiAgICBASW5wdXQoKVxuICAgIGZpbGxDb250cm9sTW9kZTogUG9wb3ZlckZpbGxNb2RlID0gJ2F0LWxlYXN0JztcblxuICAgIC8qKiBUZW1wbGF0ZSB3aXRoIHdoaWNoIHRvIGRpc3BsYXkgdGhlIHRyaWdnZXIgYm94LiAqL1xuICAgIEBJbnB1dCgpXG4gICAgdHJpZ2dlclRlbXBsYXRlOiBUZW1wbGF0ZVJlZjxhbnk+O1xuXG4gICAgLyoqIFRoZSBlbGVtZW50IHRvIHdoaWNoIHRoZSBwb3BvdmVyIHNob3VsZCBiZSBhcHBlbmRlZC4gKi9cbiAgICBASW5wdXQoKVxuICAgIGFwcGVuZFRvOiBIVE1MRWxlbWVudCB8ICdib2R5JztcblxuICAgIC8qKiBFdmVudCBlbWl0dGVkIHdoZW4gdGhlIHBvcG92ZXIgb3BlbiBzdGF0ZSBjaGFuZ2VzLiAqL1xuICAgIEBPdXRwdXQoKVxuICAgIHJlYWRvbmx5IGlzT3BlbkNoYW5nZTogRXZlbnRFbWl0dGVyPGJvb2xlYW4+XG4gICAgICAgID0gbmV3IEV2ZW50RW1pdHRlcjxib29sZWFuPigpO1xuXG4gICAgLyoqIEV2ZW50IGVtaXR0ZWQgd2hlbiB0aGUgc2VsZWN0ZWQgdmFsdWUgb2YgdGhlIHNlbGVjdCBjaGFuZ2VzLiAqL1xuICAgIEBPdXRwdXQoKVxuICAgIHJlYWRvbmx5IHZhbHVlQ2hhbmdlOiBFdmVudEVtaXR0ZXI8YW55PlxuICAgICAgICA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xuXG4gICAgLyoqIEN1cnJlbnQgc2VsZWN0ZWQgb3B0aW9uIGNvbXBvbmVudCByZWZlcmVuY2UuICovXG4gICAgcHJpdmF0ZSBzZWxlY3RlZDogT3B0aW9uQ29tcG9uZW50O1xuXG4gICAgLyoqIFN1YmplY3QgdHJpZ2dlcmVkIHdoZW4gdGhlIGNvbXBvbmVudCBpcyBkZXN0cm95ZWQuICovXG4gICAgcHJpdmF0ZSByZWFkb25seSBkZXN0cm95JDogU3ViamVjdDx2b2lkPiA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgICAvKiogT2JzZXJ2YWJsZSB0cmlnZ2VyZWQgd2hlbiBhbiBvcHRpb24gaGFzIGl0cyBzZWxlY3RlZENoYW5nZSBldmVudCBmaXJlLiAqL1xuICAgIHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uc1N0YXR1c0NoYW5nZXM6IE9ic2VydmFibGU8T3B0aW9uQ29tcG9uZW50PiA9IGRlZmVyKCgpID0+IHtcbiAgICAgICAgY29uc3Qgb3B0aW9ucyA9IHRoaXMub3B0aW9ucztcbiAgICAgICAgaWYgKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBvcHRpb25zLmNoYW5nZXMucGlwZShcbiAgICAgICAgICAgICAgICBzdGFydFdpdGgob3B0aW9ucyksXG4gICAgICAgICAgICAgICAgc3dpdGNoTWFwKCgpID0+IG1lcmdlKC4uLm9wdGlvbnMubWFwKG9wdGlvbiA9PiBvcHRpb24uc2VsZWN0ZWRDaGFuZ2UpKSlcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9KSBhcyBPYnNlcnZhYmxlPE9wdGlvbkNvbXBvbmVudD47XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIG9uQ2hhbmdlOiBGdW5jdGlvbiA9ICgpID0+IHt9O1xuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBvblRvdWNoZWQ6IEZ1bmN0aW9uID0gKCkgPT4ge307XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcbiAgICAgICAgaWYgKGNoYW5nZXMudmFsdWUpIHtcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLnZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2VsZWN0VmFsdWUodGhpcy52YWx1ZSwgZmFsc2UpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBuZ0FmdGVyQ29udGVudEluaXQoKTogdm9pZCB7XG5cbiAgICAgICAgLy8gSWYgdGhlIG9ic2VydmFibGUgc3RhdGUgY2hhbmdlcywgcmVzZXQgdGhlIG9wdGlvbnMgYW5kIGluaXRpYWxpemUgc2VsZWN0aW9uLlxuICAgICAgICB0aGlzLm9wdGlvbnMuY2hhbmdlcy5waXBlKHN0YXJ0V2l0aChudWxsKSwgdGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKS5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5yZXNldE9wdGlvbnMoKTtcbiAgICAgICAgICAgIHRoaXMuaW5pdFNlbGVjdGlvbigpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgICAgICB0aGlzLmRlc3Ryb3kkLm5leHQoKTtcbiAgICAgICAgdGhpcy5kZXN0cm95JC5jb21wbGV0ZSgpO1xuICAgIH1cblxuICAgIC8qKiBUb2dnbGVzIHRoZSBvcGVuIHN0YXRlIG9mIHRoZSBzZWxlY3QuICovXG4gICAgdG9nZ2xlKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5pc09wZW4gJiYgIXRoaXMuZGlzYWJsZWQpIHtcbiAgICAgICAgICAgIHRoaXMuY2xvc2UoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMub3BlbigpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIE9wZW5zIHRoZSBzZWxlY3QgcG9wb3ZlciBib2R5LiAqL1xuICAgIG9wZW4oKTogdm9pZCB7XG4gICAgICAgIGlmICghdGhpcy5pc09wZW4gJiYgIXRoaXMuZGlzYWJsZWQpIHtcbiAgICAgICAgICAgIHRoaXMuaXNPcGVuID0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMuaXNPcGVuQ2hhbmdlLmVtaXQodGhpcy5pc09wZW4pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIENsb3NlcyB0aGUgc2VsZWN0IHBvcG92ZXIgYm9keS4gKi9cbiAgICBjbG9zZSgpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuaXNPcGVuICYmICF0aGlzLmRpc2FibGVkKSB7XG4gICAgICAgICAgICB0aGlzLmlzT3BlbiA9IGZhbHNlO1xuICAgICAgICAgICAgdGhpcy5pc09wZW5DaGFuZ2UuZW1pdCh0aGlzLmlzT3Blbik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIHJlZ2lzdGVyT25DaGFuZ2UoZm46IGFueSk6IHZvaWQge1xuICAgICAgICB0aGlzLm9uQ2hhbmdlID0gZm47XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICByZWdpc3Rlck9uVG91Y2hlZChmbjogYW55KTogdm9pZCB7XG4gICAgICAgIHRoaXMub25Ub3VjaGVkID0gZm47XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBzZXREaXNhYmxlZFN0YXRlKGlzRGlzYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICAgICAgdGhpcy5kaXNhYmxlZCA9IGlzRGlzYWJsZWQ7XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICB3cml0ZVZhbHVlKHZhbHVlOiBhbnkpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucykge1xuICAgICAgICAgICAgdGhpcy5zZWxlY3RWYWx1ZSh2YWx1ZSwgZmFsc2UpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gRGVmZXIgdGhlIHNlbGVjdGlvbiBvZiB0aGUgdmFsdWUgdG8gc3VwcG9ydCBmb3Jtc1xuICAgICAgICAgICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMub3B0aW9ucykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnNlbGVjdFZhbHVlKHZhbHVlLCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogUmV0dXJucyB0aGUgY3VycmVudCB0cmlnZ2VyIHZhbHVlIGlmIHRoZXJlIGlzIGEgc2VsZWN0ZWQgb3B0aW9uLiBPdGhlcndpc2UsIHJldHVybnMgdGhlIHBsYWNlaG9sZGVyLiAqL1xuICAgIGdldCB0cmlnZ2VyVmFsdWUoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2VsZWN0ZWQgPyB0aGlzLnNlbGVjdGVkLnZpZXdWYWx1ZVRleHQgOiB0aGlzLnBsYWNlaG9sZGVyO1xuICAgIH1cblxuICAgIC8qKiBAaGlkZGVuICovXG4gICAgQEhvc3RMaXN0ZW5lcigna2V5ZG93bicsIFsnJGV2ZW50J10pXG4gICAga2V5ZG93bkhhbmRsZXIoZXZlbnQ6IEtleWJvYXJkRXZlbnQpOiB2b2lkIHtcbiAgICAgICAgc3dpdGNoIChldmVudC5jb2RlKSB7XG4gICAgICAgICAgICBjYXNlICgnQXJyb3dVcCcpOiB7XG4gICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICB0aGlzLmRlY3JlbWVudEZvY3VzZWQoKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgKCdBcnJvd0Rvd24nKToge1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgdGhpcy5pbmNyZW1lbnRGb2N1c2VkKCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZWxlY3RzIGFuIG9wdGlvbiBieSBvcHRpb24gY29tcG9uZW50IHJlZmVyZW5jZS4gUHJlZmVycmVkIG1ldGhvZCBvZiBzZWxlY3Rpb24uXG4gICAgICogQHBhcmFtIG9wdGlvbiBUaGUgb3B0aW9uIGNvbXBvbmVudCB0byBzZWFyY2ggZm9yLlxuICAgICAqIEBwYXJhbSBmaXJlRXZlbnRzIFdoZXRoZXIgdG8gZmlyZSBjaGFuZ2UgZXZlbnRzLlxuICAgICAqL1xuICAgIHByaXZhdGUgc2VsZWN0T3B0aW9uKG9wdGlvbjogT3B0aW9uQ29tcG9uZW50LCBmaXJlRXZlbnRzOiBib29sZWFuID0gdHJ1ZSk6IE9wdGlvbkNvbXBvbmVudCB8IHVuZGVmaW5lZCB7XG4gICAgICAgIGlmICghdGhpcy5pc09wdGlvbkFjdGl2ZShvcHRpb24pKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5zZWxlY3RlZCkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2VsZWN0ZWQuc2V0U2VsZWN0ZWQoZmFsc2UsIGZhbHNlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIG9wdGlvbi5zZXRTZWxlY3RlZCh0cnVlLCBmYWxzZSk7XG4gICAgICAgICAgICB0aGlzLnNlbGVjdGVkID0gb3B0aW9uO1xuICAgICAgICAgICAgdGhpcy51cGRhdGVWYWx1ZShmaXJlRXZlbnRzKTtcbiAgICAgICAgICAgIHRoaXMuY2xvc2UoKTtcbiAgICAgICAgICAgIHJldHVybiBvcHRpb247XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNlbGVjdHMgYW4gb3B0aW9uIGJ5IHZhbHVlLiBJZiB0d28gY29tcG9uZW50cyBoYXZlIHRoZSBzYW1lIHZhbHVlLCB0aGUgZmlyc3Qgb25lIGZvdW5kIGlzIHNlbGVjdGVkLlxuICAgICAqIFJlY29tbWVuZCB1c2luZyBzZWxlY3RPcHRpb24gZ2VuZXJhbGx5LlxuICAgICAqIEBwYXJhbSB2YWx1ZSBWYWx1ZSB0byBzZWFyY2ggZm9yLlxuICAgICAqIEBwYXJhbSBmaXJlRXZlbnRzIFdoZXRoZXIgdG8gZmlyZSBjaGFuZ2UgZXZlbnRzLlxuICAgICAqL1xuICAgIHByaXZhdGUgc2VsZWN0VmFsdWUodmFsdWU6IGFueSwgZmlyZUV2ZW50czogYm9vbGVhbiA9IHRydWUpOiBPcHRpb25Db21wb25lbnQgfCB1bmRlZmluZWQge1xuICAgICAgICBjb25zdCBtYXRjaE9wdGlvbiA9IHRoaXMub3B0aW9ucy5maW5kKChvcHRpb246IE9wdGlvbkNvbXBvbmVudCkgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIG9wdGlvbi52YWx1ZSAhPSBudWxsICYmIG9wdGlvbi52YWx1ZSA9PT0gdmFsdWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIElmIG5vdCBtYXRjaCBpcyBmb3VuZCwgc2V0IGV2ZXJ5dGhpbmcgdG8gbnVsbFxuICAgICAgICAvLyBUaGlzIGlzIG1vc3RseSBvbmx5IGZvciBjYXNlcyB3aGVyZSBhIHVzZXIgcmVtb3ZlcyBhbiBhY3RpdmUgb3B0aW9uXG4gICAgICAgIGlmICghbWF0Y2hPcHRpb24pIHtcbiAgICAgICAgICAgIHRoaXMudW5zZWxlY3RPcHRpb25zKCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBJZiBtYXRjaCBpcyBmb3VuZCwgc2VsZWN0IHRoZSBuZXcgdmFsdWVcbiAgICAgICAgaWYgKG1hdGNoT3B0aW9uICYmICF0aGlzLmlzT3B0aW9uQWN0aXZlKG1hdGNoT3B0aW9uKSkge1xuICAgICAgICAgICAgaWYgKHRoaXMuc2VsZWN0ZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNlbGVjdGVkLnNldFNlbGVjdGVkKGZhbHNlLCBmYWxzZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBtYXRjaE9wdGlvbi5zZXRTZWxlY3RlZCh0cnVlLCBmYWxzZSk7XG4gICAgICAgICAgICB0aGlzLnNlbGVjdGVkID0gbWF0Y2hPcHRpb247XG5cbiAgICAgICAgICAgIHRoaXMudXBkYXRlVmFsdWUoZmlyZUV2ZW50cyk7XG4gICAgICAgICAgICB0aGlzLmNsb3NlKCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbWF0Y2hPcHRpb247XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyB0aGUgdmFsdWUgcGFyYW1ldGVyIHdpdGggb3B0aW9uYWwgZXZlbnRzLlxuICAgICAqIEBwYXJhbSBmaXJlRXZlbnRzIElmIHRydWUsIGZ1bmN0aW9uIGZpcmVzIHZhbHVlQ2hhbmdlLCBvbkNoYW5nZSBhbmQgb25Ub3VjaGVkIGV2ZW50cy5cbiAgICAgKi9cbiAgICBwcml2YXRlIHVwZGF0ZVZhbHVlKGZpcmVFdmVudHM6IGJvb2xlYW4gPSB0cnVlKTogdm9pZCB7XG4gICAgICAgIHRoaXMudmFsdWUgPSB0aGlzLnNlbGVjdGVkLnZhbHVlO1xuICAgICAgICBpZiAoZmlyZUV2ZW50cykge1xuICAgICAgICAgICAgdGhpcy52YWx1ZUNoYW5nZS5lbWl0KHRoaXMudmFsdWUpO1xuICAgICAgICAgICAgdGhpcy5vbkNoYW5nZSh0aGlzLnZhbHVlKTtcbiAgICAgICAgICAgIHRoaXMub25Ub3VjaGVkKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBGdW5jdGlvbiB1c2VkIHRvIHJlc2V0IHRoZSBvcHRpb25zIHN0YXRlLlxuICAgICAqL1xuICAgIHByaXZhdGUgcmVzZXRPcHRpb25zKCk6IHZvaWQge1xuICAgICAgICAvLyBDcmVhdGUgb2JzZXJ2YWJsZSB0aGF0IGZpcmVzIHdoZW4gdGhlIG9wdGlvbnMgY2hhbmdlIG9yIHRoZSBjb21wb25lbnQgaXMgZGVzdHJveWVkLlxuICAgICAgICBjb25zdCBkZXN0cm95Q3VycmVudE9icyA9IG1lcmdlKHRoaXMub3B0aW9ucy5jaGFuZ2VzLCB0aGlzLmRlc3Ryb3kkKTtcblxuICAgICAgICAvLyBTdWJzY3JpYmUgdG8gb2JzZXJ2YWJsZSBkZWZpbmVkIGluIGNvbXBvbmVudCBwcm9wZXJ0aWVzIHdoaWNoIGZpcmVzIHdoZW4gYW4gb3B0aW9uIGlzIGNsaWNrZWQuXG4gICAgICAgIC8vIERlc3Ryb3kgaWYgdGhlIG9ic2VydmFibGUgZGVmaW5lZCBhYm92ZSB0cmlnZ2Vycy5cbiAgICAgICAgdGhpcy5vcHRpb25zU3RhdHVzQ2hhbmdlcy5waXBlKHRha2VVbnRpbChkZXN0cm95Q3VycmVudE9icykpLnN1YnNjcmliZSgoaW5zdGFuY2U6IE9wdGlvbkNvbXBvbmVudCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZWxlY3RPcHRpb24oaW5zdGFuY2UpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKiogU2VsZWN0aW9uIGluaXRpYWxpemF0aW9uIHdoZW4gYSBjaGFuZ2Ugb2NjdXJzIGluIG9wdGlvbnMuICovXG4gICAgcHJpdmF0ZSBpbml0U2VsZWN0aW9uKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy52YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy5zZWxlY3RlZCA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIHRoaXMuc2VsZWN0VmFsdWUodGhpcy52YWx1ZSwgZmFsc2UpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRnVuY3Rpb24gdGhhdCB0ZXN0cyB3aGV0aGVyIHRoZSB0ZXN0ZWQgb3B0aW9uIGlzIGN1cnJlbnRseSBzZWxlY3RlZC5cbiAgICAgKiBAcGFyYW0gb3B0aW9uIE9wdGlvbiB0byB0ZXN0IGFnYWluc3QgdGhlIHNlbGVjdGVkIG9wdGlvbi5cbiAgICAgKi9cbiAgICBwcml2YXRlIGlzT3B0aW9uQWN0aXZlKG9wdGlvbjogT3B0aW9uQ29tcG9uZW50KTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBvcHRpb24gJiYgdGhpcy5zZWxlY3RlZCAmJiBvcHRpb24gPT09IHRoaXMuc2VsZWN0ZWQ7XG4gICAgfVxuXG4gICAgLyoqIE1ldGhvZCB0aGF0IGZvY3VzZXMgdGhlIG5leHQgb3B0aW9uIGluIHRoZSBsaXN0LCBvciB0aGUgZmlyc3Qgb25lIGlmIHRoZSBsYXN0IG9uZSBpcyBjdXJyZW50bHkgZm9jdXNlZC4gKi9cbiAgICBwcml2YXRlIGluY3JlbWVudEZvY3VzZWQoKTogdm9pZCB7XG5cbiAgICAgICAgLy8gR2V0IGFjdGl2ZSBmb2N1c2VkIGVsZW1lbnRcbiAgICAgICAgY29uc3QgYWN0aXZlRWxlbWVudCA9IGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQ7XG5cbiAgICAgICAgLy8gR2V0IGNvcnJlc3BvbmRpbmcgb3B0aW9uIGVsZW1lbnQgdG8gdGhlIGFib3ZlXG4gICAgICAgIGNvbnN0IGNvcnJlc3BvbmRpbmdPcHRpb24gPSB0aGlzLm9wdGlvbnMuZmluZChvcHRpb24gPT4ge1xuICAgICAgICAgICAgcmV0dXJuIG9wdGlvbi5nZXRIdG1sRWxlbWVudCgpID09PSBhY3RpdmVFbGVtZW50O1xuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoY29ycmVzcG9uZGluZ09wdGlvbikge1xuICAgICAgICAgICAgY29uc3QgYXJyYXlPcHRpb25zID0gdGhpcy5vcHRpb25zLnRvQXJyYXkoKTtcbiAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gYXJyYXlPcHRpb25zLmluZGV4T2YoY29ycmVzcG9uZGluZ09wdGlvbik7XG5cbiAgICAgICAgICAgIC8vIElmIGFjdGl2ZSBvcHRpb24gaXMgdGhlIGxhc3Qgb3B0aW9uLCBmb2N1cyB0aGUgZmlyc3Qgb25lXG4gICAgICAgICAgICAvLyBPdGhlcndpc2UsIGZvY3VzIHRoZSBuZXh0IG9wdGlvbi5cbiAgICAgICAgICAgIGlmIChpbmRleCA9PT0gdGhpcy5vcHRpb25zLmxlbmd0aCAtIDEpIHtcbiAgICAgICAgICAgICAgICBhcnJheU9wdGlvbnNbMF0uZm9jdXMoKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgYXJyYXlPcHRpb25zW2luZGV4ICsgMV0uZm9jdXMoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLm9wdGlvbnMpIHtcbiAgICAgICAgICAgIHRoaXMub3B0aW9ucy5maXJzdC5mb2N1cygpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIE1ldGhvZCB0aGF0IGZvY3VzZXMgdGhlIHByZXZpb3VzIG9wdGlvbiBpbiB0aGUgbGlzdCwgb3IgdGhlIGxhc3Qgb25lIGlmIHRoZSBsYXN0IG9uZSBpcyBjdXJyZW50bHkgZm9jdXNlZC4gKi9cbiAgICBwcml2YXRlIGRlY3JlbWVudEZvY3VzZWQoKTogdm9pZCB7XG5cbiAgICAgICAgLy8gR2V0IGFjdGl2ZSBmb2N1c2VkIGVsZW1lbnRcbiAgICAgICAgY29uc3QgYWN0aXZlRWxlbWVudCA9IGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQ7XG5cbiAgICAgICAgLy8gR2V0IGNvcnJlc3BvbmRpbmcgb3B0aW9uIGVsZW1lbnQgdG8gdGhlIGFib3ZlXG4gICAgICAgIGNvbnN0IGNvcnJlc3BvbmRpbmdPcHRpb24gPSB0aGlzLm9wdGlvbnMuZmluZChvcHRpb24gPT4ge1xuICAgICAgICAgICAgcmV0dXJuIG9wdGlvbi5nZXRIdG1sRWxlbWVudCgpID09PSBhY3RpdmVFbGVtZW50O1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBJZiBhY3RpdmUgb3B0aW9uIGlzIHRoZSBmaXJzdCBvcHRpb24sIGZvY3VzIHRoZSBsYXN0IG9uZVxuICAgICAgICAvLyBPdGhlcndpc2UsIGZvY3VzIHRoZSBwcmV2aW91cyBvcHRpb24uXG4gICAgICAgIGlmIChjb3JyZXNwb25kaW5nT3B0aW9uKSB7XG4gICAgICAgICAgICBjb25zdCBhcnJheU9wdGlvbnMgPSB0aGlzLm9wdGlvbnMudG9BcnJheSgpO1xuICAgICAgICAgICAgY29uc3QgaW5kZXggPSBhcnJheU9wdGlvbnMuaW5kZXhPZihjb3JyZXNwb25kaW5nT3B0aW9uKTtcblxuICAgICAgICAgICAgaWYgKGluZGV4ID09PSAwKSB7XG4gICAgICAgICAgICAgICAgYXJyYXlPcHRpb25zW3RoaXMub3B0aW9ucy5sZW5ndGggLSAxXS5mb2N1cygpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBhcnJheU9wdGlvbnNbaW5kZXggLSAxXS5mb2N1cygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHRoaXMub3B0aW9ucykge1xuICAgICAgICAgICAgdGhpcy5vcHRpb25zLmZpcnN0LmZvY3VzKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBNZXRob2QgdXNlZCB0byBoYW5kbGUgY2FzZXMgd2hlcmUgYSB1c2VyIHJlbW92ZXMgdGhlIGN1cnJlbnRseSBhY3RpdmUgb3B0aW9uLlxuICAgICAqIFRoZSB0aW1lb3V0IGlzIHJlcXVpcmVkIGJlY2F1c2UgdGhpcyBjYW4gaGFwcGVuIGFmdGVyIHRoZSB2aWV3IGhhcyBiZWVuIGNoZWNrZWQuXG4gICAgICovXG4gICAgcHJpdmF0ZSB1bnNlbGVjdE9wdGlvbnMoKTogdm9pZCB7XG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMuc2VsZWN0ZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNlbGVjdGVkLnNldFNlbGVjdGVkKGZhbHNlLCBmYWxzZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnNlbGVjdGVkID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgdGhpcy52YWx1ZSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIHRoaXMudmFsdWVDaGFuZ2UuZW1pdCh1bmRlZmluZWQpO1xuICAgICAgICAgICAgdGhpcy5vbkNoYW5nZSh1bmRlZmluZWQpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbn1cbiJdfQ==