UNPKG

@ux-aspects/ux-aspects

Version:

Open source user interface framework for building modern, responsive, mobile big data applications

211 lines 32.1 kB
import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { SPACE } from '@angular/cdk/keycodes'; import { ChangeDetectorRef, Directive, ElementRef, EventEmitter, HostBinding, HostListener, inject, Input, Output } from '@angular/core'; import { Subject } from 'rxjs'; import { debounceTime, map, skip, takeUntil, tap } from 'rxjs/operators'; import { FocusIndicatorService, ManagedFocusContainerService } from '../accessibility/index'; import { SelectionService } from './selection.service'; import * as i0 from "@angular/core"; export class SelectionItemDirective { /** Defines whether or not this item is currently selected. */ set selected(selected) { selected ? this.select() : this.deselect(); } get selected() { return this._selected; } /** Determine whether or not this item can be selected */ set uxSelectionDisabled(isDisabled) { // if this item was selected then deselect it if (this._selected && isDisabled) { this.deselect(); } // inform the selection service of the disabled state this._selectionService.setItemDisabled(this.uxSelectionItem, isDisabled); // store the current disabled state this._isDisabled = isDisabled; } /** Whether aria-selected is added to the host element */ set addAriaAttributes(value) { this._addAriaAttributes = coerceBooleanProperty(value); } get addAriaAttributes() { return this._addAriaAttributes; } get attrTabIndex() { return (this.tabindex !== null) ? this.tabindex : this._managedTabIndex; } constructor() { this.focusIndicatorService = inject(FocusIndicatorService); this._selectionService = inject(SelectionService); this._elementRef = inject(ElementRef); this._managedFocusContainerService = inject(ManagedFocusContainerService); this._changeDetector = inject(ChangeDetectorRef); /** Defines the tab index of the row */ this.tabindex = null; /** Defines whether or not this item is currently selected. */ this.selectedChange = new EventEmitter(); /** Store whether this item is the focusable item */ this.active = false; /** Store the focused state of the element */ this.isFocused = false; /** Store the current selected state */ this._selected = false; /** Store the disabled state */ this._isDisabled = false; /** Store the tab indexed if using the managed focus container */ this._managedTabIndex = -1; /** Determine if there is a pending state change as we debounce before emitting */ this._hasPendingStateChange = false; /** Store value for _addAriaAttributes */ this._addAriaAttributes = true; /** Automatically unsubscribe when the component is destroyed */ this._onDestroy = new Subject(); this._focusIndicator = this.focusIndicatorService.monitor(this._elementRef.nativeElement); } ngOnInit() { // if there is no associated data then throw an error if (!this.uxSelectionItem) { throw new Error('The uxSelectionItem directive must have data associated with it.'); } // subscribe to changes to the active state this._selectionService.active$.pipe(takeUntil(this._onDestroy), map(active => active === this.uxSelectionItem)).subscribe(active => { // store the focus state this.active = active; // if it is active then focus the element if (active === true) { this._selectionService.focus$.next(this.uxSelectionItem); this._elementRef.nativeElement.focus(); } }); // Subscribe to changes to the focus target // This is mostly the same as active$, except that it has an initial value of the first item in the collection. this._selectionService.focus$.pipe(takeUntil(this._onDestroy)).subscribe(focusTarget => { this._managedTabIndex = (focusTarget === this.uxSelectionItem) ? 0 : -1; }); // Watch for focus within the container element and manage tabindex of descendants this._managedFocusContainerService.register(this._elementRef.nativeElement, this); // Listen for changes to the focus state and apply the appropriate class this._focusIndicator.origin$.pipe(map(origin => origin === 'keyboard'), takeUntil(this._onDestroy)) .subscribe(isFocused => { this.isFocused = isFocused; this._changeDetector.markForCheck(); }); } ngOnChanges(changes) { if (changes.uxSelectionItem) { this.updateSelectionItem(); } } ngOnDestroy() { this._onDestroy.next(); this._onDestroy.complete(); this._focusIndicator.destroy(); this._managedFocusContainerService.unregister(this._elementRef.nativeElement, this); } click(event) { if (!this._isDisabled && !this._hasPendingStateChange && this._selectionService.isEnabled && this._selectionService.isClickEnabled) { this._selectionService.strategy.click(event, this.uxSelectionItem); } } mousedown(event) { if (!this._isDisabled && this._selectionService.isEnabled && this._selectionService.isClickEnabled) { this._selectionService.strategy.mousedown(event, this.uxSelectionItem); } } keydown(event) { // if the space key (selection key) is pressed and we are disabled then we should block // the event from propagating. However if this is a key such as arrow presses then we do // still want this to propagate to allow keyboard navigation for accessibility purposes. const isDisabled = this._isDisabled && event.keyCode === SPACE; if (!isDisabled && this._selectionService.isEnabled && this._selectionService.isKeyboardEnabled) { this._selectionService.strategy.keydown(event, this.uxSelectionItem); } } focus() { // If tabbed to from outside the component, activate. if (this._selectionService.active$.getValue() !== this.uxSelectionItem) { this._selectionService.activate(this.uxSelectionItem); } } /** * Select this item using the current strategy */ select() { if (!this._isDisabled && this._selectionService.isEnabled) { this._selectionService.strategy.select(this.uxSelectionItem); } } /** * Deselect this item using the current strategy */ deselect() { if (!this._isDisabled && this._selectionService.isEnabled) { this._selectionService.strategy.deselect(this.uxSelectionItem); } } updateSelectionItem() { if (this._selectionStateSubscription) { this._selectionStateSubscription.unsubscribe(); } // subscribe to selection changes on this item (don't emit the initial value) this._selectionStateSubscription = this._selectionService.getSelectionState(this.uxSelectionItem).pipe(skip(1), tap(() => this._hasPendingStateChange = true), debounceTime(0), takeUntil(this._onDestroy)).subscribe(selected => { this._hasPendingStateChange = false; if (this._selected === selected) { return; } // store the selected state this._selected = selected; // emit the selected state this.selectedChange.emit(selected); this._changeDetector.markForCheck(); }); this._selected = this._selectionService.isSelected(this.uxSelectionItem); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: SelectionItemDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.12", type: SelectionItemDirective, selector: "[uxSelectionItem]", inputs: { uxSelectionItem: "uxSelectionItem", selected: "selected", tabindex: "tabindex", uxSelectionDisabled: "uxSelectionDisabled", addAriaAttributes: "addAriaAttributes" }, outputs: { selectedChange: "selectedChange" }, host: { listeners: { "click": "click($event)", "mousedown": "mousedown($event)", "keydown": "keydown($event)", "focus": "focus()" }, properties: { "attr.aria-selected": "addAriaAttributes ? selected : null", "class.ux-selection-selected": "this.selected", "class.ux-selection-focused": "this.isFocused", "attr.tabindex": "this.attrTabIndex" } }, exportAs: ["ux-selection-item"], usesOnChanges: true, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: SelectionItemDirective, decorators: [{ type: Directive, args: [{ selector: '[uxSelectionItem]', exportAs: 'ux-selection-item', host: { '[attr.aria-selected]': 'addAriaAttributes ? selected : null', } }] }], ctorParameters: () => [], propDecorators: { uxSelectionItem: [{ type: Input }], selected: [{ type: Input }, { type: HostBinding, args: ['class.ux-selection-selected'] }], tabindex: [{ type: Input }], uxSelectionDisabled: [{ type: Input }], addAriaAttributes: [{ type: Input }], selectedChange: [{ type: Output }], isFocused: [{ type: HostBinding, args: ['class.ux-selection-focused'] }], attrTabIndex: [{ type: HostBinding, args: ['attr.tabindex'] }], click: [{ type: HostListener, args: ['click', ['$event']] }], mousedown: [{ type: HostListener, args: ['mousedown', ['$event']] }], keydown: [{ type: HostListener, args: ['keydown', ['$event']] }], focus: [{ type: HostListener, args: ['focus'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VsZWN0aW9uLWl0ZW0uZGlyZWN0aXZlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2RpcmVjdGl2ZXMvc2VsZWN0aW9uL3NlbGVjdGlvbi1pdGVtLmRpcmVjdGl2ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQWdCLHFCQUFxQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDNUUsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzlDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQWdDLE1BQU0sRUFBaUIsTUFBTSxlQUFlLENBQUM7QUFDdEwsT0FBTyxFQUFFLE9BQU8sRUFBZ0IsTUFBTSxNQUFNLENBQUM7QUFDN0MsT0FBTyxFQUFFLFlBQVksRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxHQUFHLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN6RSxPQUFPLEVBQWtCLHFCQUFxQixFQUFFLDRCQUE0QixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDN0csT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0scUJBQXFCLENBQUM7O0FBU3ZELE1BQU0sT0FBTyxzQkFBc0I7SUFjL0IsOERBQThEO0lBQzlELElBRUksUUFBUSxDQUFDLFFBQWlCO1FBQzFCLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDL0MsQ0FBQztJQUVELElBQUksUUFBUTtRQUNSLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQztJQUMxQixDQUFDO0lBS0QseURBQXlEO0lBQ3pELElBQWEsbUJBQW1CLENBQUMsVUFBbUI7UUFDaEQsNkNBQTZDO1FBQzdDLElBQUksSUFBSSxD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QUFZO3VCQUFDLE9BQU8sRUFBRSxDQUFDLFFBQVEsQ0FBQztnQkFRakMsU0FBUztzQkFEUixZQUFZO3VCQUFDLFdBQVcsRUFBRSxDQUFDLFFBQVEsQ0FBQztnQkFRckMsT0FBTztzQkFETixZQUFZO3VCQUFDLFNBQVMsRUFBRSxDQUFDLFFBQVEsQ0FBQztnQkFjbkMsS0FBSztzQkFESixZQUFZO3VCQUFDLE9BQU8iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBCb29sZWFuSW5wdXQsIGNvZXJjZUJvb2xlYW5Qcm9wZXJ0eSB9IGZyb20gJ0Bhbmd1bGFyL2Nkay9jb2VyY2lvbic7XHJcbmltcG9ydCB7IFNQQUNFIH0gZnJvbSAnQGFuZ3VsYXIvY2RrL2tleWNvZGVzJztcclxuaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0b3JSZWYsIERpcmVjdGl2ZSwgRWxlbWVudFJlZiwgRXZlbnRFbWl0dGVyLCBIb3N0QmluZGluZywgSG9zdExpc3RlbmVyLCBpbmplY3QsIElucHV0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSwgT25Jbml0LCBPdXRwdXQsIFNpbXBsZUNoYW5nZXMgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgU3ViamVjdCwgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IGRlYm91bmNlVGltZSwgbWFwLCBza2lwLCB0YWtlVW50aWwsIHRhcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuaW1wb3J0IHsgRm9jdXNJbmRpY2F0b3IsIEZvY3VzSW5kaWNhdG9yU2VydmljZSwgTWFuYWdlZEZvY3VzQ29udGFpbmVyU2VydmljZSB9IGZyb20gJy4uL2FjY2Vzc2liaWxpdHkvaW5kZXgnO1xyXG5pbXBvcnQgeyBTZWxlY3Rpb25TZXJ2aWNlIH0gZnJvbSAnLi9zZWxlY3Rpb24uc2VydmljZSc7XHJcblxyXG5ARGlyZWN0aXZlKHtcclxuICAgIHNlbGVjdG9yOiAnW3V4U2VsZWN0aW9uSXRlbV0nLFxyXG4gICAgZXhwb3J0QXM6ICd1eC1zZWxlY3Rpb24taXRlbScsXHJcbiAgICBob3N0OiB7XHJcbiAgICAgICAgJ1thdHRyLmFyaWEtc2VsZWN0ZWRdJzogJ2FkZEFyaWFBdHRyaWJ1dGVzID8gc2VsZWN0ZWQgOiBudWxsJyxcclxuICAgIH1cclxufSlcclxuZXhwb3J0IGNsYXNzIFNlbGVjdGlvbkl0ZW1EaXJlY3RpdmU8VD4gaW1wbGVtZW50cyBPbkluaXQsIE9uQ2hhbmdlcywgT25EZXN0cm95IHtcclxuICAgIHJlYWRvbmx5IGZvY3VzSW5kaWNhdG9yU2VydmljZSA9IGluamVjdChGb2N1c0luZGljYXRvclNlcnZpY2UpO1xyXG5cclxuICAgIHByaXZhdGUgcmVhZG9ubHkgX3NlbGVjdGlvblNlcnZpY2UgPSBpbmplY3Q8U2VsZWN0aW9uU2VydmljZTxUPj4oU2VsZWN0aW9uU2VydmljZSk7XHJcblxyXG4gICAgcHJpdmF0ZSByZWFkb25seSBfZWxlbWVudFJlZiA9IGluamVjdChFbGVtZW50UmVmKTtcclxuXHJcbiAgICBwcml2YXRlIHJlYWRvbmx5IF9tYW5hZ2VkRm9jdXNDb250YWluZXJTZXJ2aWNlID0gaW5qZWN0KE1hbmFnZWRGb2N1c0NvbnRhaW5lclNlcnZpY2UpO1xyXG5cclxuICAgIHByaXZhdGUgcmVhZG9ubHkgX2NoYW5nZURldGVjdG9yID0gaW5qZWN0KENoYW5nZURldGVjdG9yUmVmKTtcclxuXHJcbiAgICAvKiogRGVmaW5lcyB0aGUgZGF0YSBhc3NvY2lhdGVkIHdpdGggdGhpcyBpdGVtLiAqL1xyXG4gICAgQElucHV0KCkgdXhTZWxlY3Rpb25JdGVtOiBUO1xyXG5cclxuICAgIC8qKiBEZWZpbmVzIHdoZXRoZXIgb3Igbm90IHRoaXMgaXRlbSBpcyBjdXJyZW50bHkgc2VsZWN0ZWQuICovXHJcbiAgICBASW5wdXQoKVxyXG4gICAgQEhvc3RCaW5kaW5nKCdjbGFzcy51eC1zZWxlY3Rpb24tc2VsZWN0ZWQnKVxyXG4gICAgc2V0IHNlbGVjdGVkKHNlbGVjdGVkOiBib29sZWFuKSB7XHJcbiAgICAgICAgc2VsZWN0ZWQgPyB0aGlzLnNlbGVjdCgpIDogdGhpcy5kZXNlbGVjdCgpO1xyXG4gICAgfVxyXG5cclxuICAgIGdldCBzZWxlY3RlZCgpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5fc2VsZWN0ZWQ7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqIERlZmluZXMgdGhlIHRhYiBpbmRleCBvZiB0aGUgcm93ICovXHJcbiAgICBASW5wdXQoKSB0YWJpbmRleDogbnVtYmVyID0gbnVsbDtcclxuXHJcbiAgICAvKiogRGV0ZXJtaW5lIHdoZXRoZXIgb3Igbm90IHRoaXMgaXRlbSBjYW4gYmUgc2VsZWN0ZWQgKi9cclxuICAgIEBJbnB1dCgpIHNldCB1eFNlbGVjdGlvbkRpc2FibGVkKGlzRGlzYWJsZWQ6IGJvb2xlYW4pIHtcclxuICAgICAgICAvLyBpZiB0aGlzIGl0ZW0gd2FzIHNlbGVjdGVkIHRoZW4gZGVzZWxlY3QgaXRcclxuICAgICAgICBpZiAodGhpcy5fc2VsZWN0ZWQgJiYgaXNEaXNhYmxlZCkge1xyXG4gICAgICAgICAgICB0aGlzLmRlc2VsZWN0KCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBpbmZvcm0gdGhlIHNlbGVjdGlvbiBzZXJ2aWNlIG9mIHRoZSBkaXNhYmxlZCBzdGF0ZVxyXG4gICAgICAgIHRoaXMuX3NlbGVjdGlvblNlcnZpY2Uuc2V0SXRlbURpc2FibGVkKHRoaXMudXhTZWxlY3Rpb25JdGVtLCBpc0Rpc2FibGVkKTtcclxuXHJcbiAgICAgICAgLy8gc3RvcmUgdGhlIGN1cnJlbnQgZGlzYWJsZWQgc3RhdGVcclxuICAgICAgICB0aGlzLl9pc0Rpc2FibGVkID0gaXNEaXNhYmxlZDtcclxuICAgIH1cclxuXHJcbiAgICAvKiogV2hldGhlciBhcmlhLXNlbGVjdGVkIGlzIGFkZGVkIHRvIHRoZSBob3N0IGVsZW1lbnQgKi9cclxuICAgIEBJbnB1dCgpIHNldCBhZGRBcmlhQXR0cmlidXRlcyh2YWx1ZTogYm9vbGVhbikge1xyXG4gICAgICAgIHRoaXMuX2FkZEFyaWFBdHRyaWJ1dGVzID0gY29lcmNlQm9vbGVhblByb3BlcnR5KHZhbHVlKTtcclxuICAgIH1cclxuXHJcbiAgICBnZXQgYWRkQXJpYUF0dHJpYnV0ZXMoKTogYm9vbGVhbiB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX2FkZEFyaWFBdHRyaWJ1dGVzO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKiBEZWZpbmVzIHdoZXRoZXIgb3Igbm90IHRoaXMgaXRlbSBpcyBjdXJyZW50bHkgc2VsZWN0ZWQuICovXHJcbiAgICBAT3V0cHV0KCkgc2VsZWN0ZWRDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XHJcblxyXG4gICAgLyoqIFN0b3JlIHdoZXRoZXIgdGhpcyBpdGVtIGlzIHRoZSBmb2N1c2FibGUgaXRlbSAqL1xyXG4gICAgYWN0aXZlOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gICAgLyoqIFN0b3JlIHRoZSBmb2N1c2VkIHN0YXRlIG9mIHRoZSBlbGVtZW50ICovXHJcbiAgICBASG9zdEJpbmRpbmcoJ2NsYXNzLnV4LXNlbGVjdGlvbi1mb2N1c2VkJykgaXNGb2N1c2VkOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gICAgQEhvc3RCaW5kaW5nKCdhdHRyLnRhYmluZGV4JylcclxuICAgIGdldCBhdHRyVGFiSW5kZXgoKTogbnVtYmVyIHtcclxuICAgICAgICByZXR1cm4gKHRoaXMudGFiaW5kZXggIT09IG51bGwpID8gdGhpcy50YWJpbmRleCA6IHRoaXMuX21hbmFnZWRUYWJJbmRleDtcclxuICAgIH1cclxuXHJcbiAgICAvKiogU3RvcmUgdGhlIGN1cnJlbnQgc2VsZWN0ZWQgc3RhdGUgKi9cclxuICAgIHByaXZhdGUgX3NlbGVjdGVkOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gICAgLyoqIFN0b3JlIHRoZSBkaXNhYmxlZCBzdGF0ZSAqL1xyXG4gICAgcHJpdmF0ZSBfaXNEaXNhYmxlZDogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuICAgIC8qKiBTdG9yZSB0aGUgdGFiIGluZGV4ZWQgaWYgdXNpbmcgdGhlIG1hbmFnZWQgZm9jdXMgY29udGFpbmVyICovXHJcbiAgICBwcml2YXRlIF9tYW5hZ2VkVGFiSW5kZXg6IG51bWJlciA9IC0xO1xyXG5cclxuICAgIC8qKiBEZXRlcm1pbmUgaWYgdGhlcmUgaXMgYSBwZW5kaW5nIHN0YXRlIGNoYW5nZSBhcyB3ZSBkZWJvdW5jZSBiZWZvcmUgZW1pdHRpbmcgKi9cclxuICAgIHByaXZhdGUgX2hhc1BlbmRpbmdTdGF0ZUNoYW5nZTogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuICAgIC8qKiBTdWJzY3JpcHRpb24gdG8gdGhlIHNlbGVjdGlvbiBzdGF0ZSBvYnNlcnZhYmxlLiAqL1xyXG4gICAgcHJpdmF0ZSBfc2VsZWN0aW9uU3RhdGVTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcclxuXHJcbiAgICAvKiogU3RvcmUgdmFsdWUgZm9yIF9hZGRBcmlhQXR0cmlidXRlcyAqL1xyXG4gICAgcHJpdmF0ZSBfYWRkQXJpYUF0dHJpYnV0ZXM6IGJvb2xlYW4gPSB0cnVlO1xyXG5cclxuICAgIC8qKiBBdXRvbWF0aWNhbGx5IHVuc3Vic2NyaWJlIHdoZW4gdGhlIGNvbXBvbmVudCBpcyBkZXN0cm95ZWQgKi9cclxuICAgIHByaXZhdGUgcmVhZG9ubHkgX29uRGVzdHJveSA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XHJcblxyXG4gICAgLyoqIFRoZSB0aGUgaW5zdGFuY2Ugb2YgdGhlIGZvY3VzIGluZGljYXRvciAqL1xyXG4gICAgcHJpdmF0ZSByZWFkb25seSBfZm9jdXNJbmRpY2F0b3I6IEZvY3VzSW5kaWNhdG9yO1xyXG5cclxuICAgIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgICAgIHRoaXMuX2ZvY3VzSW5kaWNhdG9yID0gdGhpcy5mb2N1c0luZGljYXRvclNlcnZpY2UubW9uaXRvcih0aGlzLl9lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQpO1xyXG4gICAgfVxyXG5cclxuICAgIG5nT25Jbml0KCk6IHZvaWQge1xyXG5cclxuICAgICAgICAvLyBpZiB0aGVyZSBpcyBubyBhc3NvY2lhdGVkIGRhdGEgdGhlbiB0aHJvdyBhbiBlcnJvclxyXG4gICAgICAgIGlmICghdGhpcy51eFNlbGVjdGlvbkl0ZW0pIHtcclxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdUaGUgdXhTZWxlY3Rpb25JdGVtIGRpcmVjdGl2ZSBtdXN0IGhhdmUgZGF0YSBhc3NvY2lhdGVkIHdpdGggaXQuJyk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBzdWJzY3JpYmUgdG8gY2hhbmdlcyB0byB0aGUgYWN0aXZlIHN0YXRlXHJcbiAgICAgICAgdGhpcy5fc2VsZWN0aW9uU2VydmljZS5hY3RpdmUkLnBpcGUodGFrZVVudGlsKHRoaXMuX29uRGVzdHJveSksIG1hcChhY3RpdmUgPT4gYWN0aXZlID09PSB0aGlzLnV4U2VsZWN0aW9uSXRlbSkpLnN1YnNjcmliZShhY3RpdmUgPT4ge1xyXG5cclxuICAgICAgICAgICAgLy8gc3RvcmUgdGhlIGZvY3VzIHN0YXRlXHJcbiAgICAgICAgICAgIHRoaXMuYWN0aXZlID0gYWN0aXZlO1xyXG5cclxuICAgICAgICAgICAgLy8gaWYgaXQgaXMgYWN0aXZlIHRoZW4gZm9jdXMgdGhlIGVsZW1lbnRcclxuICAgICAgICAgICAgaWYgKGFjdGl2ZSA9PT0gdHJ1ZSkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5fc2VsZWN0aW9uU2VydmljZS5mb2N1cyQubmV4dCh0aGlzLnV4U2VsZWN0aW9uSXRlbSk7XHJcbiAgICAgICAgICAgICAgICB0aGlzLl9lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQuZm9jdXMoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBTdWJzY3JpYmUgdG8gY2hhbmdlcyB0byB0aGUgZm9jdXMgdGFyZ2V0XHJcbiAgICAgICAgLy8gVGhpcyBpcyBtb3N0bHkgdGhlIHNhbWUgYXMgYWN0aXZlJCwgZXhjZXB0IHRoYXQgaXQgaGFzIGFuIGluaXRpYWwgdmFsdWUgb2YgdGhlIGZpcnN0IGl0ZW0gaW4gdGhlIGNvbGxlY3Rpb24uXHJcbiAgICAgICAgdGhpcy5fc2VsZWN0aW9uU2VydmljZS5mb2N1cyQucGlwZSh0YWtlVW50aWwodGhpcy5fb25EZXN0cm95KSkuc3Vic2NyaWJlKGZvY3VzVGFyZ2V0ID0+IHtcclxuICAgICAgICAgICAgdGhpcy5fbWFuYWdlZFRhYkluZGV4ID0gKGZvY3VzVGFyZ2V0ID09PSB0aGlzLnV4U2VsZWN0aW9uSXRlbSkgPyAwIDogLTE7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFdhdGNoIGZvciBmb2N1cyB3aXRoaW4gdGhlIGNvbnRhaW5lciBlbGVtZW50IGFuZCBtYW5hZ2UgdGFiaW5kZXggb2YgZGVzY2VuZGFudHNcclxuICAgICAgICB0aGlzLl9tYW5hZ2VkRm9jdXNDb250YWluZXJTZXJ2aWNlLnJlZ2lzdGVyKHRoaXMuX2VsZW1lbnRSZWYubmF0aXZlRWxlbWVudCwgdGhpcyk7XHJcblxyXG4gICAgICAgIC8vIExpc3RlbiBmb3IgY2hhbmdlcyB0byB0aGUgZm9jdXMgc3RhdGUgYW5kIGFwcGx5IHRoZSBhcHByb3ByaWF0ZSBjbGFzc1xyXG4gICAgICAgdGhpcy5fZm9jdXNJbmRpY2F0b3Iub3JpZ2luJC5waXBlKG1hcChvcmlnaW4gPT4gb3JpZ2luID09PSAna2V5Ym9hcmQnKSwgdGFrZVVudGlsKHRoaXMuX29uRGVzdHJveSkpXHJcbiAgICAgICAgICAgLnN1YnNjcmliZShpc0ZvY3VzZWQgPT4ge1xyXG4gICAgICAgICAgICAgICB0aGlzLmlzRm9jdXNlZCA9IGlzRm9jdXNlZDtcclxuICAgICAgICAgICAgICAgdGhpcy5fY2hhbmdlRGV0ZWN0b3IubWFya0ZvckNoZWNrKCk7XHJcbiAgICAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xyXG4gICAgICAgIGlmIChjaGFuZ2VzLnV4U2VsZWN0aW9uSXRlbSkge1xyXG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVNlbGVjdGlvbkl0ZW0oKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5fb25EZXN0cm95Lm5leHQoKTtcclxuICAgICAgICB0aGlzLl9vbkRlc3Ryb3kuY29tcGxldGUoKTtcclxuICAgICAgICB0aGlzLl9mb2N1c0luZGljYXRvci5kZXN0cm95KCk7XHJcbiAgICAgICAgdGhpcy5fbWFuYWdlZEZvY3VzQ29udGFpbmVyU2VydmljZS51bnJlZ2lzdGVyKHRoaXMuX2VsZW1lbnRSZWYubmF0aXZlRWxlbWVudCwgdGhpcyk7XHJcbiAgICB9XHJcblxyXG4gICAgQEhvc3RMaXN0ZW5lcignY2xpY2snLCBbJyRldmVudCddKVxyXG4gICAgY2xpY2soZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcclxuICAgICAgICBpZiAoIXRoaXMuX2lzRGlzYWJsZWQgJiYgIXRoaXMuX2hhc1BlbmRpbmdTdGF0ZUNoYW5nZSAmJiB0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLmlzRW5hYmxlZCAmJiB0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLmlzQ2xpY2tFbmFibGVkKSB7XHJcbiAgICAgICAgICAgIHRoaXMuX3NlbGVjdGlvblNlcnZpY2Uuc3RyYXRlZ3kuY2xpY2soZXZlbnQsIHRoaXMudXhTZWxlY3Rpb25JdGVtKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgQEhvc3RMaXN0ZW5lcignbW91c2Vkb3duJywgWyckZXZlbnQnXSlcclxuICAgIG1vdXNlZG93bihldmVudDogTW91c2VFdmVudCk6IHZvaWQge1xyXG4gICAgICAgIGlmICghdGhpcy5faXNEaXNhYmxlZCAmJiB0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLmlzRW5hYmxlZCAmJiB0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLmlzQ2xpY2tFbmFibGVkKSB7XHJcbiAgICAgICAgICAgIHRoaXMuX3NlbGVjdGlvblNlcnZpY2Uuc3RyYXRlZ3kubW91c2Vkb3duKGV2ZW50LCB0aGlzLnV4U2VsZWN0aW9uSXRlbSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIEBIb3N0TGlzdGVuZXIoJ2tleWRvd24nLCBbJyRldmVudCddKVxyXG4gICAga2V5ZG93bihldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xyXG5cclxuICAgICAgICAvLyBpZiB0aGUgc3BhY2Uga2V5IChzZWxlY3Rpb24ga2V5KSBpcyBwcmVzc2VkIGFuZCB3ZSBhcmUgZGlzYWJsZWQgdGhlbiB3ZSBzaG91bGQgYmxvY2tcclxuICAgICAgICAvLyB0aGUgZXZlbnQgZnJvbSBwcm9wYWdhdGluZy4gSG93ZXZlciBpZiB0aGlzIGlzIGEga2V5IHN1Y2ggYXMgYXJyb3cgcHJlc3NlcyB0aGVuIHdlIGRvXHJcbiAgICAgICAgLy8gc3RpbGwgd2FudCB0aGlzIHRvIHByb3BhZ2F0ZSB0byBhbGxvdyBrZXlib2FyZCBuYXZpZ2F0aW9uIGZvciBhY2Nlc3NpYmlsaXR5IHB1cnBvc2VzLlxyXG4gICAgICAgIGNvbnN0IGlzRGlzYWJsZWQgPSB0aGlzLl9pc0Rpc2FibGVkICYmIGV2ZW50LmtleUNvZGUgPT09IFNQQUNFO1xyXG5cclxuICAgICAgICBpZiAoIWlzRGlzYWJsZWQgJiYgdGhpcy5fc2VsZWN0aW9uU2VydmljZS5pc0VuYWJsZWQgJiYgdGhpcy5fc2VsZWN0aW9uU2VydmljZS5pc0tleWJvYXJkRW5hYmxlZCkge1xyXG4gICAgICAgICAgICB0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLnN0cmF0ZWd5LmtleWRvd24oZXZlbnQsIHRoaXMudXhTZWxlY3Rpb25JdGVtKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgQEhvc3RMaXN0ZW5lcignZm9jdXMnKVxyXG4gICAgZm9jdXMoKTogdm9pZCB7XHJcbiAgICAgICAgLy8gSWYgdGFiYmVkIHRvIGZyb20gb3V0c2lkZSB0aGUgY29tcG9uZW50LCBhY3RpdmF0ZS5cclxuICAgICAgICBpZiAodGhpcy5fc2VsZWN0aW9uU2VydmljZS5hY3RpdmUkLmdldFZhbHVlKCkgIT09IHRoaXMudXhTZWxlY3Rpb25JdGVtKSB7XHJcbiAgICAgICAgICAgIHRoaXMuX3NlbGVjdGlvblNlcnZpY2UuYWN0aXZhdGUodGhpcy51eFNlbGVjdGlvbkl0ZW0pO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFNlbGVjdCB0aGlzIGl0ZW0gdXNpbmcgdGhlIGN1cnJlbnQgc3RyYXRlZ3lcclxuICAgICAqL1xyXG4gICAgc2VsZWN0KCk6IHZvaWQge1xyXG4gICAgICAgIGlmICghdGhpcy5faXNEaXNhYmxlZCAmJiB0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLmlzRW5hYmxlZCkge1xyXG4gICAgICAgICAgICB0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLnN0cmF0ZWd5LnNlbGVjdCh0aGlzLnV4U2VsZWN0aW9uSXRlbSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogRGVzZWxlY3QgdGhpcyBpdGVtIHVzaW5nIHRoZSBjdXJyZW50IHN0cmF0ZWd5XHJcbiAgICAgKi9cclxuICAgIGRlc2VsZWN0KCk6IHZvaWQge1xyXG4gICAgICAgIGlmICghdGhpcy5faXNEaXNhYmxlZCAmJiB0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLmlzRW5hYmxlZCkge1xyXG4gICAgICAgICAgICB0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLnN0cmF0ZWd5LmRlc2VsZWN0KHRoaXMudXhTZWxlY3Rpb25JdGVtKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSB1cGRhdGVTZWxlY3Rpb25JdGVtKCk6IHZvaWQge1xyXG5cclxuICAgICAgICBpZiAodGhpcy5fc2VsZWN0aW9uU3RhdGVTdWJzY3JpcHRpb24pIHtcclxuICAgICAgICAgICAgdGhpcy5fc2VsZWN0aW9uU3RhdGVTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIHN1YnNjcmliZSB0byBzZWxlY3Rpb24gY2hhbmdlcyBvbiB0aGlzIGl0ZW0gKGRvbid0IGVtaXQgdGhlIGluaXRpYWwgdmFsdWUpXHJcbiAgICAgICAgdGhpcy5fc2VsZWN0aW9uU3RhdGVTdWJzY3JpcHRpb24gPSB0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLmdldFNlbGVjdGlvblN0YXRlKHRoaXMudXhTZWxlY3Rpb25JdGVtKS5waXBlKFxyXG4gICAgICAgICAgICBza2lwKDEpLFxyXG4gICAgICAgICAgICB0YXAoKCkgPT4gdGhpcy5faGFzUGVuZGluZ1N0YXRlQ2hhbmdlID0gdHJ1ZSksXHJcbiAgICAgICAgICAgIGRlYm91bmNlVGltZSgwKSxcclxuICAgICAgICAgICAgdGFrZVVudGlsKHRoaXMuX29uRGVzdHJveSlcclxuICAgICAgICApLnN1YnNjcmliZShzZWxlY3RlZCA9PiB7XHJcbiAgICAgICAgICAgIHRoaXMuX2hhc1BlbmRpbmdTdGF0ZUNoYW5nZSA9IGZhbHNlO1xyXG5cclxuICAgICAgICAgICAgaWYgKHRoaXMuX3NlbGVjdGVkID09PSBzZWxlY3RlZCkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBzdG9yZSB0aGUgc2VsZWN0ZWQgc3RhdGVcclxuICAgICAgICAgICAgdGhpcy5fc2VsZWN0ZWQgPSBzZWxlY3RlZDtcclxuXHJcbiAgICAgICAgICAgIC8vIGVtaXQgdGhlIHNlbGVjdGVkIHN0YXRlXHJcbiAgICAgICAgICAgIHRoaXMuc2VsZWN0ZWRDaGFuZ2UuZW1pdChzZWxlY3RlZCk7XHJcblxyXG4gICAgICAgICAgICB0aGlzLl9jaGFuZ2VEZXRlY3Rvci5tYXJrRm9yQ2hlY2soKTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgdGhpcy5fc2VsZWN0ZWQgPSB0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLmlzU2VsZWN0ZWQodGhpcy51eFNlbGVjdGlvbkl0ZW0pO1xyXG4gICAgfVxyXG5cclxuICAgIHN0YXRpYyBuZ0FjY2VwdElucHV0VHlwZV9hZGRBcmlhQXR0cmlidXRlczogQm9vbGVhbklucHV0O1xyXG59XHJcbiJdfQ==