@ux-aspects/ux-aspects
Version:
Open source user interface framework for building modern, responsive, mobile big data applications
256 lines • 36.8 kB
JavaScript
import { isPlatformBrowser } from '@angular/common';
import { ContentChildren, Directive, ElementRef, EventEmitter, HostListener, inject, Output, PLATFORM_ID, Renderer2 } from '@angular/core';
import { SplitAreaDirective, SplitComponent } from 'angular-split';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FocusIndicatorService } from '../focus-indicator/focus-indicator.service';
import * as i0 from "@angular/core";
export class SplitterAccessibilityDirective {
constructor() {
this._elementRef = inject(ElementRef);
this._renderer = inject(Renderer2);
this._splitter = inject(SplitComponent);
this._focusIndicatorService = inject(FocusIndicatorService);
this._platform = inject(PLATFORM_ID);
/** Emit an event whenever the gutter is moved using the keyboard */
this.gutterKeydown = new EventEmitter();
/** Store all the gutter elements */
this._gutters = [];
/** Teardown our observables on destroy */
this._onDestroy = new Subject();
/** Store references to all focus indicators */
this._focusIndicators = [];
}
ngOnInit() {
// update aria values when the a gutter is dragged
this._splitter.dragProgress$
.pipe(takeUntil(this._onDestroy))
.subscribe(() => this.updateGutterAttributes());
}
/** Once initialised make the gutters accessible */
ngAfterViewInit() {
// find the gutters
this.onGutterChange();
// if the number of split areas change then update the gutters and apply aria properties
this.areas.changes.pipe(takeUntil(this._onDestroy)).subscribe(() => this.onGutterChange());
// we can't know when additional split-gutters appear using ContentChildren as the directive class is not exported and selector doesn't work - use mutation observer instead
if (isPlatformBrowser(this._platform)) {
// create the mutation observer
this._observer = new MutationObserver(() => this.onGutterChange());
// begin observing the child nodes
this._observer.observe(this._elementRef.nativeElement, { childList: true });
}
}
/** Destroy all observables and observers */
ngOnDestroy() {
if (this._observer) {
this._observer.disconnect();
}
this._onDestroy.next();
this._onDestroy.complete();
// destroy all existing focus indicators
this._focusIndicators.forEach(indicator => indicator.destroy());
}
/** We should focus the gutter when it is clicked */
onClick(event) {
if (this.isSplitterGutter(event.target)) {
event.target.parentElement.focus();
}
}
/** Find all the gutters and set their attributes */
onGutterChange() {
// destroy all existing focus indicators
this._focusIndicators.forEach(indicator => indicator.destroy());
// reset the array
this._focusIndicators = [];
// get the new gutter elements
this._gutters = this.getGutters();
// monitor the focus of each gutter
this._gutters.forEach(gutter => this._focusIndicators.push(this._focusIndicatorService.monitor(gutter)));
// apply all required accessibility attributes to the gutter elements
this.setGutterAttributes();
}
/** Get all the gutter elements */
getGutters() {
// This function uses DOM accessing properties - which won't work if server side rendered
if (isPlatformBrowser(this._platform)) {
const gutters = [];
for (let idx = 0; idx < this._elementRef.nativeElement.children.length; idx++) {
const node = this._elementRef.nativeElement.children.item(idx);
if (this.isSplitterGutter(node)) {
gutters.push(node);
}
}
return gutters;
}
return [];
}
/** Set the appropriate attributes on the gutter elements */
setGutterAttributes() {
// apply attribute to every gutter
this._gutters.forEach(gutter => {
// apply the separator role
this._renderer.setAttribute(gutter, 'role', 'separator');
// make the gutters tabbable
this._renderer.setAttribute(gutter, 'tabindex', '0');
// set the value now aria property
this.updateGutterAttributes();
});
}
/** Apply the aria attribute values */
updateGutterAttributes() {
// update the value now properties of each gutter
this._gutters.forEach((gutter, idx) => {
this.setGutterValueNow(gutter, idx);
this.setGutterValueMin(gutter, idx);
this.setGutterValueMax(gutter, idx);
});
}
/** Apply the value now aria attribute */
setGutterValueNow(gutter, index) {
// get the matching split area
const area = this._splitter.displayedAreas[index];
if (area.size === '*') {
return;
}
// indicate the size
this._renderer.setAttribute(gutter, 'aria-valuenow', `${Math.round(area.size)}`);
}
/** Apply the value min aria attribute */
setGutterValueMin(gutter, index) {
// get the matching split area
const area = this.areas.toArray()[index];
// indicate the minimum size
this._renderer.setAttribute(gutter, 'aria-valuemin', `${Math.round(area.minSize)}`);
}
/** Apply the value max aria attribute */
setGutterValueMax(gutter, index) {
// get every other splitter area
const availableSize = this.areas
.filter((_area, idx) => index !== idx)
.reduce((total, area) => total + area.minSize, 0);
// indicate the minimum size
this._renderer.setAttribute(gutter, 'aria-valuemax', `${100 - Math.round(availableSize)}`);
}
onKeydown(event) {
if (this.isSplitterGutter(event.target)) {
this.gutterKeydown.emit(event);
}
}
onIncreaseKey(event) {
// only perform a move if a gutter is focused
if (this.isSplitterGutter(event.target)) {
this.setGutterPosition(event.target, -1);
// stop the browser from scrolling
event.preventDefault();
}
}
onDecreaseKey(event) {
// only perform a move if a gutter is focused
if (this.isSplitterGutter(event.target)) {
this.setGutterPosition(event.target, 1);
// stop the browser from scrolling
event.preventDefault();
}
}
onHomeKey(event) {
if (this.isSplitterGutter(event.target)) {
// get the affected panels
const areas = this.getAreasFromGutter(event.target);
if (areas.previous.size === '*') {
return;
}
// set the previous area to it's minimum size
const delta = areas.previous.size - areas.previous.minSize;
// update the sizes accordingly
this.setGutterPosition(event.target, delta);
// stop the browser from scrolling
event.preventDefault();
}
}
onEndKey(event) {
if (this.isSplitterGutter(event.target)) {
// get the affected panels
const areas = this.getAreasFromGutter(event.target);
if (areas.next.size === '*') {
return;
}
// set the next area to it's minimum size
const delta = areas.next.size - areas.next.minSize;
// update the sizes accordingly
this.setGutterPosition(event.target, -delta);
// stop the browser from scrolling
event.preventDefault();
}
}
/** Determine if an element is a gutter */
isSplitterGutter(element) {
return element.classList.contains('as-split-gutter') || element.classList.contains('as-split-gutter-icon');
}
/** Update the gutter position */
setGutterPosition(gutter, delta) {
// get the affected panels
const areas = this.getAreasFromGutter(gutter);
if (areas.previous.size === '*' || areas.next.size === '*') {
return;
}
// ensure we can perform the resize
if (areas.previous.size - delta < areas.previous.minSize || areas.next.size + delta < areas.next.minSize) {
return;
}
// perform the resize
areas.previous.size -= delta;
areas.next.size += delta;
// update the splitter - this is a private method but we need to call it
//eslint-disable-next-line @typescript-eslint/no-explicit-any
this._splitter.refreshStyleSizes();
// update the gutter aria values
this.updateGutterAttributes();
}
/** Get the split areas associated with a given gutter */
getAreasFromGutter(gutter) {
const index = this._gutters.indexOf(gutter);
return {
previous: this._splitter.displayedAreas[index],
next: this._splitter.displayedAreas[index + 1]
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: SplitterAccessibilityDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.12", type: SplitterAccessibilityDirective, selector: "as-split", outputs: { gutterKeydown: "gutterKeydown" }, host: { listeners: { "click": "onClick($event)", "keydown": "onKeydown($event)", "keydown.ArrowDown": "onIncreaseKey($event)", "keydown.ArrowRight": "onIncreaseKey($event)", "keydown.ArrowUp": "onDecreaseKey($event)", "keydown.ArrowLeft": "onDecreaseKey($event)", "keydown.Home": "onHomeKey($event)", "keydown.End": "onEndKey($event)" } }, queries: [{ propertyName: "areas", predicate: SplitAreaDirective }], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: SplitterAccessibilityDirective, decorators: [{
type: Directive,
args: [{
selector: 'as-split'
}]
}], propDecorators: { gutterKeydown: [{
type: Output
}], areas: [{
type: ContentChildren,
args: [SplitAreaDirective]
}], onClick: [{
type: HostListener,
args: ['click', ['$event']]
}], onKeydown: [{
type: HostListener,
args: ['keydown', ['$event']]
}], onIncreaseKey: [{
type: HostListener,
args: ['keydown.ArrowDown', ['$event']]
}, {
type: HostListener,
args: ['keydown.ArrowRight', ['$event']]
}], onDecreaseKey: [{
type: HostListener,
args: ['keydown.ArrowUp', ['$event']]
}, {
type: HostListener,
args: ['keydown.ArrowLeft', ['$event']]
}], onHomeKey: [{
type: HostListener,
args: ['keydown.Home', ['$event']]
}], onEndKey: [{
type: HostListener,
args: ['keydown.End', ['$event']]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BsaXR0ZXItYWNjZXNzaWJpbGl0eS5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvZGlyZWN0aXZlcy9hY2Nlc3NpYmlsaXR5L3NwbGl0dGVyL3NwbGl0dGVyLWFjY2Vzc2liaWxpdHkuZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3BELE9BQU8sRUFBaUIsZUFBZSxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQXFCLE1BQU0sRUFBRSxXQUFXLEVBQWEsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3hMLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxjQUFjLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbkUsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMvQixPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFM0MsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sNENBQTRDLENBQUM7O0FBS25GLE1BQU0sT0FBTyw4QkFBOEI7SUFIM0M7UUFJcUIsZ0JBQVcsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7UUFFakMsY0FBUyxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUU5QixjQUFTLEdBQUcsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBRW5DLDJCQUFzQixHQUFHLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO1FBRXZELGNBQVMsR0FBRyxNQUFNLENBQVMsV0FBVyxDQUFDLENBQUM7UUFFekQsb0VBQW9FO1FBQzFELGtCQUFhLEdBQUcsSUFBSSxZQUFZLEVBQWlCLENBQUM7UUFLNUQsb0NBQW9DO1FBQzVCLGFBQVEsR0FBa0IsRUFBRSxDQUFDO1FBS3JDLDBDQUEwQztRQUN6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QUFRLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRTVDLE9BQU87WUFDSCxRQUFRLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLENBQUMsS0FBSyxDQUFDO1lBQzlDLElBQUksRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDO1NBQ2pELENBQUM7SUFDTixDQUFDOytHQTlSUSw4QkFBOEI7bUdBQTlCLDhCQUE4Qix1Y0FldEIsa0JBQWtCOzs0RkFmMUIsOEJBQThCO2tCQUgxQyxTQUFTO21CQUFDO29CQUNQLFFBQVEsRUFBRSxVQUFVO2lCQUN2Qjs4QkFhYSxhQUFhO3NCQUF0QixNQUFNO2dCQUc4QixLQUFLO3NCQUF6QyxlQUFlO3VCQUFDLGtCQUFrQjtnQkF3RG5DLE9BQU87c0JBRE4sWUFBWTt1QkFBQyxPQUFPLEVBQUUsQ0FBQyxRQUFRLENBQUM7Z0JBeUdqQyxTQUFTO3NCQURSLFlBQVk7dUJBQUMsU0FBUyxFQUFFLENBQUMsUUFBUSxDQUFDO2dCQVNuQyxhQUFhO3NCQUZaLFlBQVk7dUJBQUMsbUJBQW1CLEVBQUUsQ0FBQyxRQUFRLENBQUM7O3NCQUM1QyxZQUFZO3VCQUFDLG9CQUFvQixFQUFFLENBQUMsUUFBUSxDQUFDO2dCQWE5QyxhQUFhO3NCQUZaLFlBQVk7dUJBQUMsaUJBQWlCLEVBQUUsQ0FBQyxRQUFRLENBQUM7O3NCQUMxQyxZQUFZO3VCQUFDLG1CQUFtQixFQUFFLENBQUMsUUFBUSxDQUFDO2dCQVk3QyxTQUFTO3NCQURSLFlBQVk7dUJBQUMsY0FBYyxFQUFFLENBQUMsUUFBUSxDQUFDO2dCQXNCeEMsUUFBUTtzQkFEUCxZQUFZO3VCQUFDLGFBQWEsRUFBRSxDQUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGlzUGxhdGZvcm1Ccm93c2VyIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IEFmdGVyVmlld0luaXQsIENvbnRlbnRDaGlsZHJlbiwgRGlyZWN0aXZlLCBFbGVtZW50UmVmLCBFdmVudEVtaXR0ZXIsIEhvc3RMaXN0ZW5lciwgaW5qZWN0LCBPbkRlc3Ryb3ksIE9uSW5pdCwgT3V0cHV0LCBQTEFURk9STV9JRCwgUXVlcnlMaXN0LCBSZW5kZXJlcjIgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFNwbGl0QXJlYURpcmVjdGl2ZSwgU3BsaXRDb21wb25lbnQgfSBmcm9tICdhbmd1bGFyLXNwbGl0JztcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IEZvY3VzSW5kaWNhdG9yIH0gZnJvbSAnLi4vZm9jdXMtaW5kaWNhdG9yL2ZvY3VzLWluZGljYXRvcic7XG5pbXBvcnQgeyBGb2N1c0luZGljYXRvclNlcnZpY2UgfSBmcm9tICcuLi9mb2N1cy1pbmRpY2F0b3IvZm9jdXMtaW5kaWNhdG9yLnNlcnZpY2UnO1xuXG5ARGlyZWN0aXZlKHtcbiAgICBzZWxlY3RvcjogJ2FzLXNwbGl0J1xufSlcbmV4cG9ydCBjbGFzcyBTcGxpdHRlckFjY2Vzc2liaWxpdHlEaXJlY3RpdmUgaW1wbGVtZW50cyBPbkluaXQsIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveSB7XG4gICAgcHJpdmF0ZSByZWFkb25seSBfZWxlbWVudFJlZiA9IGluamVjdChFbGVtZW50UmVmKTtcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgX3JlbmRlcmVyID0gaW5qZWN0KFJlbmRlcmVyMik7XG5cbiAgICBwcml2YXRlIHJlYWRvbmx5IF9zcGxpdHRlciA9IGluamVjdChTcGxpdENvbXBvbmVudCk7XG5cbiAgICBwcml2YXRlIHJlYWRvbmx5IF9mb2N1c0luZGljYXRvclNlcnZpY2UgPSBpbmplY3QoRm9jdXNJbmRpY2F0b3JTZXJ2aWNlKTtcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgX3BsYXRmb3JtID0gaW5qZWN0PHN0cmluZz4oUExBVEZPUk1fSUQpO1xuXG4gICAgLyoqIEVtaXQgYW4gZXZlbnQgd2hlbmV2ZXIgdGhlIGd1dHRlciBpcyBtb3ZlZCB1c2luZyB0aGUga2V5Ym9hcmQgKi9cbiAgICBAT3V0cHV0KCkgZ3V0dGVyS2V5ZG93biA9IG5ldyBFdmVudEVtaXR0ZXI8S2V5Ym9hcmRFdmVudD4oKTtcblxuICAgIC8qKiBGaW5kIGFsbCB0aGUgc3BsaXQgYXJlYXMgKi9cbiAgICBAQ29udGVudENoaWxkcmVuKFNwbGl0QXJlYURpcmVjdGl2ZSkgYXJlYXM6IFF1ZXJ5TGlzdDxTcGxpdEFyZWFEaXJlY3RpdmU+O1xuXG4gICAgLyoqIFN0b3JlIGFsbCB0aGUgZ3V0dGVyIGVsZW1lbnRzICovXG4gICAgcHJpdmF0ZSBfZ3V0dGVyczogSFRNTEVsZW1lbnRbXSA9IFtdO1xuXG4gICAgLyoqIFdhdGNoIGZvciBndXR0ZXJzIGJlaW5nIGFkZGVkIG9yIHJlbW92ZWQgKi9cbiAgICBwcml2YXRlIF9vYnNlcnZlcjogTXV0YXRpb25PYnNlcnZlcjtcblxuICAgIC8qKiBUZWFyZG93biBvdXIgb2JzZXJ2YWJsZXMgb24gZGVzdHJveSAqL1xuICAgIHByaXZhdGUgcmVhZG9ubHkgX29uRGVzdHJveSA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgICAvKiogU3RvcmUgcmVmZXJlbmNlcyB0byBhbGwgZm9jdXMgaW5kaWNhdG9ycyAqL1xuICAgIHByaXZhdGUgX2ZvY3VzSW5kaWNhdG9yczogRm9jdXNJbmRpY2F0b3JbXSA9IFtdO1xuXG4gICAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgICAgIC8vIHVwZGF0ZSBhcmlhIHZhbHVlcyB3aGVuIHRoZSBhIGd1dHRlciBpcyBkcmFnZ2VkXG4gICAgICAgIHRoaXMuX3NwbGl0dGVyLmRyYWdQcm9ncmVzcyRcbiAgICAgICAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLl9vbkRlc3Ryb3kpKVxuICAgICAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB0aGlzLnVwZGF0ZUd1dHRlckF0dHJpYnV0ZXMoKSk7XG4gICAgfVxuXG4gICAgLyoqIE9uY2UgaW5pdGlhbGlzZWQgbWFrZSB0aGUgZ3V0dGVycyBhY2Nlc3NpYmxlICovXG4gICAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgICAgICAvLyBmaW5kIHRoZSBndXR0ZXJzXG4gICAgICAgIHRoaXMub25HdXR0ZXJDaGFuZ2UoKTtcblxuICAgICAgICAvLyBpZiB0aGUgbnVtYmVyIG9mIHNwbGl0IGFyZWFzIGNoYW5nZSB0aGVuIHVwZGF0ZSB0aGUgZ3V0dGVycyBhbmQgYXBwbHkgYXJpYSBwcm9wZXJ0aWVzXG4gICAgICAgIHRoaXMuYXJlYXMuY2hhbmdlcy5waXBlKHRha2VVbnRpbCh0aGlzLl9vbkRlc3Ryb3kpKS5zdWJzY3JpYmUoKCkgPT4gdGhpcy5vbkd1dHRlckNoYW5nZSgpKTtcblxuICAgICAgICAvLyB3ZSBjYW4ndCBrbm93IHdoZW4gYWRkaXRpb25hbCBzcGxpdC1ndXR0ZXJzIGFwcGVhciB1c2luZyBDb250ZW50Q2hpbGRyZW4gYXMgdGhlIGRpcmVjdGl2ZSBjbGFzcyBpcyBub3QgZXhwb3J0ZWQgYW5kIHNlbGVjdG9yIGRvZXNuJ3Qgd29yayAtIHVzZSBtdXRhdGlvbiBvYnNlcnZlciBpbnN0ZWFkXG4gICAgICAgIGlmIChpc1BsYXRmb3JtQnJvd3Nlcih0aGlzLl9wbGF0Zm9ybSkpIHtcblxuICAgICAgICAgICAgLy8gY3JlYXRlIHRoZSBtdXRhdGlvbiBvYnNlcnZlclxuICAgICAgICAgICAgdGhpcy5fb2JzZXJ2ZXIgPSBuZXcgTXV0YXRpb25PYnNlcnZlcigoKSA9PiB0aGlzLm9uR3V0dGVyQ2hhbmdlKCkpO1xuXG4gICAgICAgICAgICAvLyBiZWdpbiBvYnNlcnZpbmcgdGhlIGNoaWxkIG5vZGVzXG4gICAgICAgICAgICB0aGlzLl9vYnNlcnZlci5vYnNlcnZlKHRoaXMuX2VsZW1lbnRSZWYubmF0aXZlRWxlbWVudCwgeyBjaGlsZExpc3Q6IHRydWUgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogRGVzdHJveSBhbGwgb2JzZXJ2YWJsZXMgYW5kIG9ic2VydmVycyAqL1xuICAgIG5nT25EZXN0cm95KCk6IHZvaWQge1xuXG4gICAgICAgIGlmICh0aGlzLl9vYnNlcnZlcikge1xuICAgICAgICAgICAgdGhpcy5fb2JzZXJ2ZXIuZGlzY29ubmVjdCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fb25EZXN0cm95Lm5leHQoKTtcbiAgICAgICAgdGhpcy5fb25EZXN0cm95LmNvbXBsZXRlKCk7XG5cbiAgICAgICAgLy8gZGVzdHJveSBhbGwgZXhpc3RpbmcgZm9jdXMgaW5kaWNhdG9yc1xuICAgICAgICB0aGlzLl9mb2N1c0luZGljYXRvcnMuZm9yRWFjaChpbmRpY2F0b3IgPT4gaW5kaWNhdG9yLmRlc3Ryb3koKSk7XG4gICAgfVxuXG4gICAgLyoqIFdlIHNob3VsZCBmb2N1cyB0aGUgZ3V0dGVyIHdoZW4gaXQgaXMgY2xpY2tlZCAqL1xuICAgIEBIb3N0TGlzdGVuZXIoJ2NsaWNrJywgWyckZXZlbnQnXSlcbiAgICBvbkNsaWNrKGV2ZW50OiBNb3VzZUV2ZW50KTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmlzU3BsaXR0ZXJHdXR0ZXIoZXZlbnQudGFyZ2V0IGFzIEhUTUxFbGVtZW50KSkge1xuICAgICAgICAgICAgKGV2ZW50LnRhcmdldCBhcyBIVE1MSW5wdXRFbGVtZW50KS5wYXJlbnRFbGVtZW50LmZvY3VzKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogRmluZCBhbGwgdGhlIGd1dHRlcnMgYW5kIHNldCB0aGVpciBhdHRyaWJ1dGVzICovXG4gICAgcHJpdmF0ZSBvbkd1dHRlckNoYW5nZSgpOiB2b2lkIHtcblxuICAgICAgICAvLyBkZXN0cm95IGFsbCBleGlzdGluZyBmb2N1cyBpbmRpY2F0b3JzXG4gICAgICAgIHRoaXMuX2ZvY3VzSW5kaWNhdG9ycy5mb3JFYWNoKGluZGljYXRvciA9PiBpbmRpY2F0b3IuZGVzdHJveSgpKTtcblxuICAgICAgICAvLyByZXNldCB0aGUgYXJyYXlcbiAgICAgICAgdGhpcy5fZm9jdXNJbmRpY2F0b3JzID0gW107XG5cbiAgICAgICAgLy8gZ2V0IHRoZSBuZXcgZ3V0dGVyIGVsZW1lbnRzXG4gICAgICAgIHRoaXMuX2d1dHRlcnMgPSB0aGlzLmdldEd1dHRlcnMoKTtcblxuICAgICAgICAvLyBtb25pdG9yIHRoZSBmb2N1cyBvZiBlYWNoIGd1dHRlclxuICAgICAgICB0aGlzLl9ndXR0ZXJzLmZvckVhY2goZ3V0dGVyID0+IHRoaXMuX2ZvY3VzSW5kaWNhdG9ycy5wdXNoKHRoaXMuX2ZvY3VzSW5kaWNhdG9yU2VydmljZS5tb25pdG9yKGd1dHRlcikpKTtcblxuICAgICAgICAvLyBhcHBseSBhbGwgcmVxdWlyZWQgYWNjZXNzaWJpbGl0eSBhdHRyaWJ1dGVzIHRvIHRoZSBndXR0ZXIgZWxlbWVudHNcbiAgICAgICAgdGhpcy5zZXRHdXR0ZXJBdHRyaWJ1dGVzKCk7XG4gICAgfVxuXG4gICAgLyoqIEdldCBhbGwgdGhlIGd1dHRlciBlbGVtZW50cyAqL1xuICAgIHByaXZhdGUgZ2V0R3V0dGVycygpOiBIVE1MRWxlbWVudFtdIHtcbiAgICAgICAgLy8gVGhpcyBmdW5jdGlvbiB1c2VzIERPTSBhY2Nlc3NpbmcgcHJvcGVydGllcyAtIHdoaWNoIHdvbid0IHdvcmsgaWYgc2VydmVyIHNpZGUgcmVuZGVyZWRcbiAgICAgICAgaWYgKGlzUGxhdGZvcm1Ccm93c2VyKHRoaXMuX3BsYXRmb3JtKSkge1xuICAgICAgICAgICAgY29uc3QgZ3V0dGVyczogSFRNTEVsZW1lbnRbXSA9IFtdO1xuXG4gICAgICAgICAgICBmb3IgKGxldCBpZHggPSAwOyBpZHggPCB0aGlzLl9lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQuY2hpbGRyZW4ubGVuZ3RoOyBpZHgrKykge1xuICAgICAgICAgICAgICAgIGNvbnN0IG5vZGUgPSB0aGlzLl9lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQuY2hpbGRyZW4uaXRlbShpZHgpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuaXNTcGxpdHRlckd1dHRlcihub2RlIGFzIEhUTUxFbGVtZW50KSkge1xuICAgICAgICAgICAgICAgICAgICBndXR0ZXJzLnB1c2gobm9kZSBhcyBIVE1MRWxlbWVudCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gZ3V0dGVycztcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICAvKiogU2V0IHRoZSBhcHByb3ByaWF0ZSBhdHRyaWJ1dGVzIG9uIHRoZSBndXR0ZXIgZWxlbWVudHMgKi9cbiAgICBwcml2YXRlIHNldEd1dHRlckF0dHJpYnV0ZXMoKTogdm9pZCB7XG4gICAgICAgIC8vIGFwcGx5IGF0dHJpYnV0ZSB0byBldmVyeSBndXR0ZXJcbiAgICAgICAgdGhpcy5fZ3V0dGVycy5mb3JFYWNoKGd1dHRlciA9PiB7XG4gICAgICAgICAgICAvLyBhcHBseSB0aGUgc2VwYXJhdG9yIHJvbGVcbiAgICAgICAgICAgIHRoaXMuX3JlbmRlcmVyLnNldEF0dHJpYnV0ZShndXR0ZXIsICdyb2xlJywgJ3NlcGFyYXRvcicpO1xuXG4gICAgICAgICAgICAvLyBtYWtlIHRoZSBndXR0ZXJzIHRhYmJhYmxlXG4gICAgICAgICAgICB0aGlzLl9yZW5kZXJlci5zZXRBdHRyaWJ1dGUoZ3V0dGVyLCAndGFiaW5kZXgnLCAnMCcpO1xuXG4gICAgICAgICAgICAvLyBzZXQgdGhlIHZhbHVlIG5vdyBhcmlhIHByb3BlcnR5XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZUd1dHRlckF0dHJpYnV0ZXMoKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqIEFwcGx5IHRoZSBhcmlhIGF0dHJpYnV0ZSB2YWx1ZXMgKi9cbiAgICBwcml2YXRlIHVwZGF0ZUd1dHRlckF0dHJpYnV0ZXMoKTogdm9pZCB7XG4gICAgICAgIC8vIHVwZGF0ZSB0aGUgdmFsdWUgbm93IHByb3BlcnRpZXMgb2YgZWFjaCBndXR0ZXJcbiAgICAgICAgdGhpcy5fZ3V0dGVycy5mb3JFYWNoKChndXR0ZXIsIGlkeCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRHdXR0ZXJWYWx1ZU5vdyhndXR0ZXIsIGlkeCk7XG4gICAgICAgICAgICB0aGlzLnNldEd1dHRlclZhbHVlTWluKGd1dHRlciwgaWR4KTtcbiAgICAgICAgICAgIHRoaXMuc2V0R3V0dGVyVmFsdWVNYXgoZ3V0dGVyLCBpZHgpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKiogQXBwbHkgdGhlIHZhbHVlIG5vdyBhcmlhIGF0dHJpYnV0ZSAqL1xuICAgIHByaXZhdGUgc2V0R3V0dGVyVmFsdWVOb3coZ3V0dGVyOiBIVE1MRWxlbWVudCwgaW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgICAgICAvLyBnZXQgdGhlIG1hdGNoaW5nIHNwbGl0IGFyZWFcbiAgICAgICAgY29uc3QgYXJlYSA9IHRoaXMuX3NwbGl0dGVyLmRpc3BsYXllZEFyZWFzW2luZGV4XTtcblxuICAgICAgICBpZiAoYXJlYS5zaXplID09PSAnKicpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGluZGljYXRlIHRoZSBzaXplXG4gICAgICAgIHRoaXMuX3JlbmRlcmVyLnNldEF0dHJpYnV0ZShndXR0ZXIsICdhcmlhLXZhbHVlbm93JywgYCR7TWF0aC5yb3VuZChhcmVhLnNpemUpfWApO1xuICAgIH1cblxuICAgIC8qKiBBcHBseSB0aGUgdmFsdWUgbWluIGFyaWEgYXR0cmlidXRlICovXG4gICAgcHJpdmF0ZSBzZXRHdXR0ZXJWYWx1ZU1pbihndXR0ZXI6IEhUTUxFbGVtZW50LCBpbmRleDogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIC8vIGdldCB0aGUgbWF0Y2hpbmcgc3BsaXQgYXJlYVxuICAgICAgICBjb25zdCBhcmVhID0gdGhpcy5hcmVhcy50b0FycmF5KClbaW5kZXhdO1xuXG4gICAgICAgIC8vIGluZGljYXRlIHRoZSBtaW5pbXVtIHNpemVcbiAgICAgICAgdGhpcy5fcmVuZGVyZXIuc2V0QXR0cmlidXRlKGd1dHRlciwgJ2FyaWEtdmFsdWVtaW4nLCBgJHtNYXRoLnJvdW5kKGFyZWEubWluU2l6ZSl9YCk7XG4gICAgfVxuXG4gICAgLyoqIEFwcGx5IHRoZSB2YWx1ZSBtYXggYXJpYSBhdHRyaWJ1dGUgKi9cbiAgICBwcml2YXRlIHNldEd1dHRlclZhbHVlTWF4KGd1dHRlcjogSFRNTEVsZW1lbnQsIGluZGV4OiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgLy8gZ2V0IGV2ZXJ5IG90aGVyIHNwbGl0dGVyIGFyZWFcbiAgICAgICAgY29uc3QgYXZhaWxhYmxlU2l6ZSA9IHRoaXMuYXJlYXNcbiAgICAgICAgICAgIC5maWx0ZXIoKF9hcmVhLCBpZHgpID0+IGluZGV4ICE9PSBpZHgpXG4gICAgICAgICAgICAucmVkdWNlPG51bWJlcj4oKHRvdGFsLCBhcmVhKSA9PiB0b3RhbCArIGFyZWEubWluU2l6ZSwgMCk7XG5cbiAgICAgICAgLy8gaW5kaWNhdGUgdGhlIG1pbmltdW0gc2l6ZVxuICAgICAgICB0aGlzLl9yZW5kZXJlci5zZXRBdHRyaWJ1dGUoZ3V0dGVyLCAnYXJpYS12YWx1ZW1heCcsIGAkezEwMCAtIE1hdGgucm91bmQoYXZhaWxhYmxlU2l6ZSl9YCk7XG4gICAgfVxuXG4gICAgQEhvc3RMaXN0ZW5lcigna2V5ZG93bicsIFsnJGV2ZW50J10pXG4gICAgb25LZXlkb3duKGV2ZW50OiBLZXlib2FyZEV2ZW50KTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmlzU3BsaXR0ZXJHdXR0ZXIoZXZlbnQudGFyZ2V0IGFzIEhUTUxFbGVtZW50KSkge1xuICAgICAgICAgICAgdGhpcy5ndXR0ZXJLZXlkb3duLmVtaXQoZXZlbnQpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgQEhvc3RMaXN0ZW5lcigna2V5ZG93bi5BcnJvd0Rvd24nLCBbJyRldmVudCddKVxuICAgIEBIb3N0TGlzdGVuZXIoJ2tleWRvd24uQXJyb3dSaWdodCcsIFsnJGV2ZW50J10pXG4gICAgb25JbmNyZWFzZUtleShldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xuICAgICAgICAvLyBvbmx5IHBlcmZvcm0gYSBtb3ZlIGlmIGEgZ3V0dGVyIGlzIGZvY3VzZWRcbiAgICAgICAgaWYgKHRoaXMuaXNTcGxpdHRlckd1dHRlcihldmVudC50YXJnZXQgYXMgSFRNTEVsZW1lbnQpKSB7XG4gICAgICAgICAgICB0aGlzLnNldEd1dHRlclBvc2l0aW9uKGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudCwgLTEpO1xuXG4gICAgICAgICAgICAvLyBzdG9wIHRoZSBicm93c2VyIGZyb20gc2Nyb2xsaW5nXG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgQEhvc3RMaXN0ZW5lcigna2V5ZG93bi5BcnJvd1VwJywgWyckZXZlbnQnXSlcbiAgICBASG9zdExpc3RlbmVyKCdrZXlkb3duLkFycm93TGVmdCcsIFsnJGV2ZW50J10pXG4gICAgb25EZWNyZWFzZUtleShldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xuICAgICAgICAvLyBvbmx5IHBlcmZvcm0gYSBtb3ZlIGlmIGEgZ3V0dGVyIGlzIGZvY3VzZWRcbiAgICAgICAgaWYgKHRoaXMuaXNTcGxpdHRlckd1dHRlcihldmVudC50YXJnZXQgYXMgSFRNTEVsZW1lbnQpKSB7XG4gICAgICAgICAgICB0aGlzLnNldEd1dHRlclBvc2l0aW9uKGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudCwgMSk7XG5cbiAgICAgICAgICAgIC8vIHN0b3AgdGhlIGJyb3dzZXIgZnJvbSBzY3JvbGxpbmdcbiAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBASG9zdExpc3RlbmVyKCdrZXlkb3duLkhvbWUnLCBbJyRldmVudCddKVxuICAgIG9uSG9tZUtleShldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5pc1NwbGl0dGVyR3V0dGVyKGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudCkpIHtcbiAgICAgICAgICAgIC8vIGdldCB0aGUgYWZmZWN0ZWQgcGFuZWxzXG4gICAgICAgICAgICBjb25zdCBhcmVhcyA9IHRoaXMuZ2V0QXJlYXNGcm9tR3V0dGVyKGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudCk7XG5cbiAgICAgICAgICAgIGlmIChhcmVhcy5wcmV2aW91cy5zaXplID09PSAnKicpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIHNldCB0aGUgcHJldmlvdXMgYXJlYSB0byBpdCdzIG1pbmltdW0gc2l6ZVxuICAgICAgICAgICAgY29uc3QgZGVsdGEgPSBhcmVhcy5wcmV2aW91cy5zaXplIC0gYXJlYXMucHJldmlvdXMubWluU2l6ZTtcblxuICAgICAgICAgICAgLy8gdXBkYXRlIHRoZSBzaXplcyBhY2NvcmRpbmdseVxuICAgICAgICAgICAgdGhpcy5zZXRHdXR0ZXJQb3NpdGlvbihldmVudC50YXJnZXQgYXMgSFRNTEVsZW1lbnQsIGRlbHRhKTtcblxuICAgICAgICAgICAgLy8gc3RvcCB0aGUgYnJvd3NlciBmcm9tIHNjcm9sbGluZ1xuICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIEBIb3N0TGlzdGVuZXIoJ2tleWRvd24uRW5kJywgWyckZXZlbnQnXSlcbiAgICBvbkVuZEtleShldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5pc1NwbGl0dGVyR3V0dGVyKGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudCkpIHtcbiAgICAgICAgICAgIC8vIGdldCB0aGUgYWZmZWN0ZWQgcGFuZWxzXG4gICAgICAgICAgICBjb25zdCBhcmVhcyA9IHRoaXMuZ2V0QXJlYXNGcm9tR3V0dGVyKGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudCk7XG5cbiAgICAgICAgICAgIGlmIChhcmVhcy5uZXh0LnNpemUgPT09ICcqJykge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gc2V0IHRoZSBuZXh0IGFyZWEgdG8gaXQncyBtaW5pbXVtIHNpemVcbiAgICAgICAgICAgIGNvbnN0IGRlbHRhID0gYXJlYXMubmV4dC5zaXplIC0gYXJlYXMubmV4dC5taW5TaXplO1xuXG4gICAgICAgICAgICAvLyB1cGRhdGUgdGhlIHNpemVzIGFjY29yZGluZ2x5XG4gICAgICAgICAgICB0aGlzLnNldEd1dHRlclBvc2l0aW9uKGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudCwgLWRlbHRhKTtcblxuICAgICAgICAgICAgLy8gc3RvcCB0aGUgYnJvd3NlciBmcm9tIHNjcm9sbGluZ1xuICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKiBEZXRlcm1pbmUgaWYgYW4gZWxlbWVudCBpcyBhIGd1dHRlciAqL1xuICAgIHByaXZhdGUgaXNTcGxpdHRlckd1dHRlcihlbGVtZW50OiBIVE1MRWxlbWVudCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gZWxlbWVudC5jbGFzc0xpc3QuY29udGFpbnMoJ2FzLXNwbGl0LWd1dHRlcicpIHx8IGVsZW1lbnQuY2xhc3NMaXN0LmNvbnRhaW5zKCdhcy1zcGxpdC1ndXR0ZXItaWNvbicpO1xuICAgIH1cblxuICAgIC8qKiBVcGRhdGUgdGhlIGd1dHRlciBwb3NpdGlvbiAqL1xuICAgIHByaXZhdGUgc2V0R3V0dGVyUG9zaXRpb24oZ3V0dGVyOiBIVE1MRWxlbWVudCwgZGVsdGE6IG51bWJlcik6IHZvaWQge1xuICAgICAgICAvLyBnZXQgdGhlIGFmZmVjdGVkIHBhbmVsc1xuICAgICAgICBjb25zdCBhcmVhcyA9IHRoaXMuZ2V0QXJlYXNGcm9tR3V0dGVyKGd1dHRlcik7XG5cbiAgICAgICAgaWYgKGFyZWFzLnByZXZpb3VzLnNpemUgPT09ICcqJyB8fCBhcmVhcy5uZXh0LnNpemUgPT09ICcqJykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZW5zdXJlIHdlIGNhbiBwZXJmb3JtIHRoZSByZXNpemVcbiAgICAgICAgaWYgKGFyZWFzLnByZXZpb3VzLnNpemUgLSBkZWx0YSA8IGFyZWFzLnByZXZpb3VzLm1pblNpemUgfHwgYXJlYXMubmV4dC5zaXplICsgZGVsdGEgPCBhcmVhcy5uZXh0Lm1pblNpemUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHBlcmZvcm0gdGhlIHJlc2l6ZVxuICAgICAgICBhcmVhcy5wcmV2aW91cy5zaXplIC09IGRlbHRhO1xuICAgICAgICBhcmVhcy5uZXh0LnNpemUgKz0gZGVsdGE7XG5cbiAgICAgICAgLy8gdXBkYXRlIHRoZSBzcGxpdHRlciAtIHRoaXMgaXMgYSBwcml2YXRlIG1ldGhvZCBidXQgd2UgbmVlZCB0byBjYWxsIGl0XG4gICAgICAgIC8vZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnlcbiAgICAgICAgKHRoaXMuX3NwbGl0dGVyIGFzIGFueSkucmVmcmVzaFN0eWxlU2l6ZXMoKTtcblxuICAgICAgICAvLyB1cGRhdGUgdGhlIGd1dHRlciBhcmlhIHZhbHVlc1xuICAgICAgICB0aGlzLnVwZGF0ZUd1dHRlckF0dHJpYnV0ZXMoKTtcbiAgICB9XG5cbiAgICAvKiogR2V0IHRoZSBzcGxpdCBhcmVhcyBhc3NvY2lhdGVkIHdpdGggYSBnaXZlbiBndXR0ZXIgKi9cbiAgICBwcml2YXRlIGdldEFyZWFzRnJvbUd1dHRlcihndXR0ZXI6IEhUTUxFbGVtZW50KSB7XG4gICAgICAgIGNvbnN0IGluZGV4ID0gdGhpcy5fZ3V0dGVycy5pbmRleE9mKGd1dHRlcik7XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHByZXZpb3VzOiB0aGlzLl9zcGxpdHRlci5kaXNwbGF5ZWRBcmVhc1tpbmRleF0sXG4gICAgICAgICAgICBuZXh0OiB0aGlzLl9zcGxpdHRlci5kaXNwbGF5ZWRBcmVhc1tpbmRleCArIDFdXG4gICAgICAgIH07XG4gICAgfVxufVxuIl19