@ux-aspects/ux-aspects
Version:
Open source user interface framework for building modern, responsive, mobile big data applications
99 lines • 22.2 kB
JavaScript
import { SPACE } from '@angular/cdk/keycodes';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChildren, forwardRef, inject, Input } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { TabComponent } from './tab/tab.component';
import { TabsetService } from './tabset.service';
import { TabsetToken } from './tabset.token';
import * as i0 from "@angular/core";
import * as i1 from "../../directives/accessibility/focus-indicator/focus-indicator.directive";
import * as i2 from "../../directives/accessibility/tabbable-list/tabbable-list.directive";
import * as i3 from "../../directives/accessibility/tabbable-list/tabbable-list-item.directive";
import * as i4 from "@angular/common";
import * as i5 from "@angular/router";
export class TabsetComponent {
constructor() {
this._tabset = inject(TabsetService);
this._changeDetector = inject(ChangeDetectorRef);
/** Determine if the appearance of the tabset */
this.minimal = true;
/** Determine if the tabset should appear stacked */
this.stacked = 'none';
/** Remove subscriptions on destroy */
this._onDestroy$ = new Subject();
}
/** Determine if we want to manually update the active state */
set manual(manual) {
this._tabset.manual = manual;
}
ngAfterViewInit() {
// provide the service with the initial array of items
this._tabset.update(this._tabs.toArray());
// Make sure a tab is selected
if (!this._tabset.isTabActive()) {
this._tabset.selectFirstTab();
}
// run change detection once we have setup the tabs
this._changeDetector.detectChanges();
// watch for any future changes
this._tabs.changes.pipe(takeUntil(this._onDestroy$)).subscribe(tabs => {
// update the internal list of tabs
this._tabset.update(tabs);
// run change detection
this._changeDetector.detectChanges();
});
}
ngOnDestroy() {
this._onDestroy$.next();
this._onDestroy$.complete();
}
selectTab(tab) {
// pass tab to select method
this._tabset.select(tab instanceof TabComponent ? tab : this._tabs.toArray()[tab]);
// run change detection
this._changeDetector.detectChanges();
}
handleKeyDown(event, tab) {
if (event.keyCode === SPACE) {
event.preventDefault();
tab.click();
}
}
markForCheck() {
this._changeDetector.detectChanges();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: TabsetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: TabsetComponent, selector: "ux-tabset", inputs: { minimal: "minimal", stacked: "stacked", manual: "manual", ariaLabel: ["aria-label", "ariaLabel"] }, host: { properties: { "class.tabs-left": "stacked === \"left\"", "class.tabs-right": "stacked === \"right\"" } }, providers: [
TabsetService,
{
provide: TabsetToken,
useExisting: forwardRef(() => TabsetComponent),
}
], queries: [{ propertyName: "_tabs", predicate: TabComponent }], ngImport: i0, template: "<!-- Nav tabs -->\n<ul\n role=\"tablist\"\n uxTabbableList\n [direction]=\"stacked === 'none' ? 'horizontal' : 'vertical'\"\n [allowBoundaryKeys]=\"true\"\n class=\"nav nav-tabs\"\n [class.minimal-tab]=\"minimal\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-orientation]=\"stacked === 'none' ? 'horizontal' : 'vertical'\"\n >\n @for (tab of _tabset.tabs; track tab; let index = $index) {\n <li\n role=\"presentation\"\n class=\"nav-item\"\n [class.active]=\"(_tabset.activeTab$ | async) === tab\"\n [class.disabled]=\"tab.disabled\"\n [ngClass]=\"tab.customClass\"\n >\n <ng-template #tabDetails>\n @if (!tab.headingRef) {\n <span>{{ tab.heading }}</span>\n }\n @if (tab.headingRef) {\n <ng-container [ngTemplateOutlet]=\"tab.headingRef\"></ng-container>\n }\n </ng-template>\n @if (tab.route) {\n <a\n class=\"nav-link\"\n [attr.id]=\"tab.id\"\n role=\"tab\"\n #anchorTab\n uxTabbableListItem\n uxFocusIndicator\n [attr.aria-controls]=\"tab.id\"\n [attr.aria-selected]=\"(_tabset.activeTab$ | async) === tab\"\n [attr.aria-disabled]=\"tab.disabled\"\n [routerLink]=\"tab.route\"\n [fragment]=\"tab.routerLinkExtras?.fragment\"\n [queryParams]=\"tab.routerLinkExtras?.queryParams\"\n [queryParamsHandling]=\"tab.routerLinkExtras?.queryParamsHandling\"\n [preserveFragment]=\"tab.routerLinkExtras?.preserveFragment\"\n [skipLocationChange]=\"tab.routerLinkExtras?.skipLocationChange\"\n [replaceUrl]=\"tab.routerLinkExtras?.replaceUrl\"\n [state]=\"tab.routerLinkExtras?.state\"\n (keydown)=\"handleKeyDown($event, anchorTab)\"\n >\n <ng-container [ngTemplateOutlet]=\"tabDetails\"> </ng-container>\n </a>\n }\n @if (!tab.route) {\n <a\n class=\"nav-link\"\n [attr.id]=\"tab.id\"\n role=\"tab\"\n uxTabbableListItem\n uxFocusIndicator\n (mousedown)=\"_tabset.select(tab)\"\n (activated)=\"_tabset.select(tab)\"\n [attr.aria-controls]=\"tab.id\"\n [attr.aria-selected]=\"(_tabset.activeTab$ | async) === tab\"\n [attr.aria-disabled]=\"tab.disabled\"\n >\n <ng-container [ngTemplateOutlet]=\"tabDetails\"> </ng-container>\n </a>\n }\n </li>\n }\n</ul>\n\n<!-- Tab panes -->\n<div class=\"tab-content\">\n <ng-content></ng-content>\n</div>\n", dependencies: [{ kind: "directive", type: i1.FocusIndicatorDirective, selector: "[uxFocusIndicator]", inputs: ["checkChildren", "mouseFocusIndicator", "touchFocusIndicator", "keyboardFocusIndicator", "programmaticFocusIndicator"], outputs: ["indicator"], exportAs: ["ux-focus-indicator"] }, { kind: "directive", type: i2.TabbableListDirective, selector: "[uxTabbableList]", inputs: ["direction", "wrap", "focusOnShow", "returnFocus", "hierarchy", "allowAltModifier", "allowCtrlModifier", "allowBoundaryKeys"], exportAs: ["ux-tabbable-list"] }, { kind: "directive", type: i3.TabbableListItemDirective, selector: "[uxTabbableListItem]", inputs: ["parent", "rank", "disabled", "expanded", "key"], outputs: ["expandedChange", "activated"], exportAs: ["ux-tabbable-list-item"] }, { kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i5.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: TabsetComponent, decorators: [{
type: Component,
args: [{ selector: 'ux-tabset', changeDetection: ChangeDetectionStrategy.OnPush, providers: [
TabsetService,
{
provide: TabsetToken,
useExisting: forwardRef(() => TabsetComponent),
}
], host: {
'[class.tabs-left]': 'stacked === "left"',
'[class.tabs-right]': 'stacked === "right"',
}, template: "<!-- Nav tabs -->\n<ul\n role=\"tablist\"\n uxTabbableList\n [direction]=\"stacked === 'none' ? 'horizontal' : 'vertical'\"\n [allowBoundaryKeys]=\"true\"\n class=\"nav nav-tabs\"\n [class.minimal-tab]=\"minimal\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-orientation]=\"stacked === 'none' ? 'horizontal' : 'vertical'\"\n >\n @for (tab of _tabset.tabs; track tab; let index = $index) {\n <li\n role=\"presentation\"\n class=\"nav-item\"\n [class.active]=\"(_tabset.activeTab$ | async) === tab\"\n [class.disabled]=\"tab.disabled\"\n [ngClass]=\"tab.customClass\"\n >\n <ng-template #tabDetails>\n @if (!tab.headingRef) {\n <span>{{ tab.heading }}</span>\n }\n @if (tab.headingRef) {\n <ng-container [ngTemplateOutlet]=\"tab.headingRef\"></ng-container>\n }\n </ng-template>\n @if (tab.route) {\n <a\n class=\"nav-link\"\n [attr.id]=\"tab.id\"\n role=\"tab\"\n #anchorTab\n uxTabbableListItem\n uxFocusIndicator\n [attr.aria-controls]=\"tab.id\"\n [attr.aria-selected]=\"(_tabset.activeTab$ | async) === tab\"\n [attr.aria-disabled]=\"tab.disabled\"\n [routerLink]=\"tab.route\"\n [fragment]=\"tab.routerLinkExtras?.fragment\"\n [queryParams]=\"tab.routerLinkExtras?.queryParams\"\n [queryParamsHandling]=\"tab.routerLinkExtras?.queryParamsHandling\"\n [preserveFragment]=\"tab.routerLinkExtras?.preserveFragment\"\n [skipLocationChange]=\"tab.routerLinkExtras?.skipLocationChange\"\n [replaceUrl]=\"tab.routerLinkExtras?.replaceUrl\"\n [state]=\"tab.routerLinkExtras?.state\"\n (keydown)=\"handleKeyDown($event, anchorTab)\"\n >\n <ng-container [ngTemplateOutlet]=\"tabDetails\"> </ng-container>\n </a>\n }\n @if (!tab.route) {\n <a\n class=\"nav-link\"\n [attr.id]=\"tab.id\"\n role=\"tab\"\n uxTabbableListItem\n uxFocusIndicator\n (mousedown)=\"_tabset.select(tab)\"\n (activated)=\"_tabset.select(tab)\"\n [attr.aria-controls]=\"tab.id\"\n [attr.aria-selected]=\"(_tabset.activeTab$ | async) === tab\"\n [attr.aria-disabled]=\"tab.disabled\"\n >\n <ng-container [ngTemplateOutlet]=\"tabDetails\"> </ng-container>\n </a>\n }\n </li>\n }\n</ul>\n\n<!-- Tab panes -->\n<div class=\"tab-content\">\n <ng-content></ng-content>\n</div>\n" }]
}], propDecorators: { minimal: [{
type: Input
}], stacked: [{
type: Input
}], manual: [{
type: Input
}], ariaLabel: [{
type: Input,
args: ['aria-label']
}], _tabs: [{
type: ContentChildren,
args: [TabComponent]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFic2V0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3RhYnNldC90YWJzZXQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvdGFic2V0L3RhYnNldC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDOUMsT0FBTyxFQUFpQix1QkFBdUIsRUFBRSxpQkFBaUIsRUFBRSxTQUFTLEVBQUUsZUFBZSxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUF3QixNQUFNLGVBQWUsQ0FBQztBQUN2SyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQy9CLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUMzQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDbkQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQzs7Ozs7OztBQWtCN0MsTUFBTSxPQUFPLGVBQWU7SUFoQjVCO1FBaUJhLFlBQU8sR0FBRyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUM7UUFFeEIsb0JBQWUsR0FBRyxNQUFNLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUU3RCxnREFBZ0Q7UUFDdkMsWUFBTyxHQUFZLElBQUksQ0FBQztRQUVqQyxvREFBb0Q7UUFDM0MsWUFBTyxHQUE4QixNQUFNLENBQUM7UUFhckQsc0NBQXNDO1FBQ3JCLGdCQUFXLEdBQUcsSUFBSSxPQUFPLEVBQVEsQ0FBQztLQWtEdEQ7SUE5REcsK0RBQStEO0lBQy9ELElBQWEsTUFBTSxDQUFDLE1BQWU7UUFDL0IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO0lBQ2pDLENBQUM7SUFXRCxlQUFlO1FBRVgsc0RBQXNEO1FBQ3RELElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUUxQyw4QkFBOEI7UUFDOUIsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQztZQUM5QixJQUFJLENBQUMsT0FBTyxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ2xDLENBQUM7UUFFRCxtREFBbUQ7UUFDbkQsSUFBSSxDQUFDLGVBQWUsQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUVyQywrQkFBK0I7UUFDL0IsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUU7WUFFbEUsbUNBQW1DO1lBQ25DLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBRTFCLHVCQUF1QjtZQUN2QixJQUFJLENBQUMsZUFBZSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ3pDLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVELFdBQVc7UUFDUCxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxXQUFXLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDaEMsQ0FBQztJQUVELFNBQVMsQ0FBQyxHQUEwQjtRQUVoQyw0QkFBNEI7UUFDNUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsR0FBRyxZQUFZLFlBQVksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFFbkYsdUJBQXVCO1FBQ3ZCLElBQUksQ0FBQyxlQUFlLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDekMsQ0FBQztJQUVELGFBQWEsQ0FBQyxLQUFvQixFQUFFLEdBQWdCO1FBQ2hELElBQUksS0FBSyxDQUFDLE9BQU8sS0FBSyxLQUFLLEVBQUUsQ0FBQztZQUMxQixLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDdkIsR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2hCLENBQUM7SUFDTCxDQUFDO0lBRUQsWUFBWTtRQUNSLElBQUksQ0FBQyxlQUFlLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDekMsQ0FBQzsrR0F4RVEsZUFBZTttR0FBZixlQUFlLG9RQVpiO1lBQ1AsYUFBYTtZQUNiO2dCQUNJLE9BQU8sRUFBRSxXQUFXO2dCQUNwQixXQUFXLEVBQUUsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLGVBQWUsQ0FBQzthQUNqRDtTQUNKLGdEQTBCZ0IsWUFBWSw2QkM1Q2pDLHNoRkEyRUE7OzRGRG5EYSxlQUFlO2tCQWhCM0IsU0FBUzsrQkFDSSxXQUFXLG1CQUVKLHVCQUF1QixDQUFDLE1BQU0sYUFDcEM7d0JBQ1AsYUFBYTt3QkFDYjs0QkFDSSxPQUFPLEVBQUUsV0FBVzs0QkFDcEIsV0FBVyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsZ0JBQWdCLENBQUM7eUJBQ2pEO3FCQUNKLFFBQ0s7d0JBQ0YsbUJBQW1CLEVBQUUsb0JBQW9CO3dCQUN6QyxvQkFBb0IsRUFBRSxxQkFBcUI7cUJBQzlDOzhCQVFRLE9BQU87c0JBQWYsS0FBSztnQkFHRyxPQUFPO3NCQUFmLEtBQUs7Z0JBR08sTUFBTTtzQkFBbEIsS0FBSztnQkFLZSxTQUFTO3NCQUE3QixLQUFLO3VCQUFDLFlBQVk7Z0JBR1ksS0FBSztzQkFBbkMsZUFBZTt1QkFBQyxZQUFZIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgU1BBQ0UgfSBmcm9tICdAYW5ndWxhci9jZGsva2V5Y29kZXMnO1xuaW1wb3J0IHsgQWZ0ZXJWaWV3SW5pdCwgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENoYW5nZURldGVjdG9yUmVmLCBDb21wb25lbnQsIENvbnRlbnRDaGlsZHJlbiwgZm9yd2FyZFJlZiwgaW5qZWN0LCBJbnB1dCwgT25EZXN0cm95LCBRdWVyeUxpc3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IFRhYkNvbXBvbmVudCB9IGZyb20gJy4vdGFiL3RhYi5jb21wb25lbnQnO1xuaW1wb3J0IHsgVGFic2V0U2VydmljZSB9IGZyb20gJy4vdGFic2V0LnNlcnZpY2UnO1xuaW1wb3J0IHsgVGFic2V0VG9rZW4gfSBmcm9tICcuL3RhYnNldC50b2tlbic7XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAndXgtdGFic2V0JyxcbiAgICB0ZW1wbGF0ZVVybDogJy4vdGFic2V0LmNvbXBvbmVudC5odG1sJyxcbiAgICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgICBwcm92aWRlcnM6IFtcbiAgICAgICAgVGFic2V0U2VydmljZSxcbiAgICAgICAge1xuICAgICAgICAgICAgcHJvdmlkZTogVGFic2V0VG9rZW4sXG4gICAgICAgICAgICB1c2VFeGlzdGluZzogZm9yd2FyZFJlZigoKSA9PiBUYWJzZXRDb21wb25lbnQpLFxuICAgICAgICB9XG4gICAgXSxcbiAgICBob3N0OiB7XG4gICAgICAgICdbY2xhc3MudGFicy1sZWZ0XSc6ICdzdGFja2VkID09PSBcImxlZnRcIicsXG4gICAgICAgICdbY2xhc3MudGFicy1yaWdodF0nOiAnc3RhY2tlZCA9PT0gXCJyaWdodFwiJyxcbiAgICB9XG59KVxuZXhwb3J0IGNsYXNzIFRhYnNldENvbXBvbmVudCBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveSB7XG4gICAgcmVhZG9ubHkgX3RhYnNldCA9IGluamVjdChUYWJzZXRTZXJ2aWNlKTtcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgX2NoYW5nZURldGVjdG9yID0gaW5qZWN0KENoYW5nZURldGVjdG9yUmVmKTtcblxuICAgIC8qKiBEZXRlcm1pbmUgaWYgdGhlIGFwcGVhcmFuY2Ugb2YgdGhlIHRhYnNldCAqL1xuICAgIEBJbnB1dCgpIG1pbmltYWw6IGJvb2xlYW4gPSB0cnVlO1xuXG4gICAgLyoqIERldGVybWluZSBpZiB0aGUgdGFic2V0IHNob3VsZCBhcHBlYXIgc3RhY2tlZCAqL1xuICAgIEBJbnB1dCgpIHN0YWNrZWQ6ICdsZWZ0JyB8ICdyaWdodCcgfCAnbm9uZScgPSAnbm9uZSc7XG5cbiAgICAvKiogRGV0ZXJtaW5lIGlmIHdlIHdhbnQgdG8gbWFudWFsbHkgdXBkYXRlIHRoZSBhY3RpdmUgc3RhdGUgKi9cbiAgICBASW5wdXQoKSBzZXQgbWFudWFsKG1hbnVhbDogYm9vbGVhbikge1xuICAgICAgICB0aGlzLl90YWJzZXQubWFudWFsID0gbWFudWFsO1xuICAgIH1cblxuICAgIC8qKiBQcm92aWRlIGFtIGFyaWEgbGFiZWwgZm9yIHRoZSB0YWJzZXQgKi9cbiAgICBASW5wdXQoJ2FyaWEtbGFiZWwnKSBhcmlhTGFiZWw6IHN0cmluZztcblxuICAgIC8qKiBBY2Nlc3MgYWxsIHRoZSBjaGlsZHJlbiAqL1xuICAgIEBDb250ZW50Q2hpbGRyZW4oVGFiQ29tcG9uZW50KSBfdGFiczogUXVlcnlMaXN0PFRhYkNvbXBvbmVudD47XG5cbiAgICAvKiogUmVtb3ZlIHN1YnNjcmlwdGlvbnMgb24gZGVzdHJveSAqL1xuICAgIHByaXZhdGUgcmVhZG9ubHkgX29uRGVzdHJveSQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gICAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuXG4gICAgICAgIC8vIHByb3ZpZGUgdGhlIHNlcnZpY2Ugd2l0aCB0aGUgaW5pdGlhbCBhcnJheSBvZiBpdGVtc1xuICAgICAgICB0aGlzLl90YWJzZXQudXBkYXRlKHRoaXMuX3RhYnMudG9BcnJheSgpKTtcblxuICAgICAgICAvLyBNYWtlIHN1cmUgYSB0YWIgaXMgc2VsZWN0ZWRcbiAgICAgICAgaWYgKCF0aGlzLl90YWJzZXQuaXNUYWJBY3RpdmUoKSkge1xuICAgICAgICAgICAgdGhpcy5fdGFic2V0LnNlbGVjdEZpcnN0VGFiKCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBydW4gY2hhbmdlIGRldGVjdGlvbiBvbmNlIHdlIGhhdmUgc2V0dXAgdGhlIHRhYnNcbiAgICAgICAgdGhpcy5fY2hhbmdlRGV0ZWN0b3IuZGV0ZWN0Q2hhbmdlcygpO1xuXG4gICAgICAgIC8vIHdhdGNoIGZvciBhbnkgZnV0dXJlIGNoYW5nZXNcbiAgICAgICAgdGhpcy5fdGFicy5jaGFuZ2VzLnBpcGUodGFrZVVudGlsKHRoaXMuX29uRGVzdHJveSQpKS5zdWJzY3JpYmUodGFicyA9PiB7XG5cbiAgICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgaW50ZXJuYWwgbGlzdCBvZiB0YWJzXG4gICAgICAgICAgICB0aGlzLl90YWJzZXQudXBkYXRlKHRhYnMpO1xuXG4gICAgICAgICAgICAvLyBydW4gY2hhbmdlIGRldGVjdGlvblxuICAgICAgICAgICAgdGhpcy5fY2hhbmdlRGV0ZWN0b3IuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5fb25EZXN0cm95JC5uZXh0KCk7XG4gICAgICAgIHRoaXMuX29uRGVzdHJveSQuY29tcGxldGUoKTtcbiAgICB9XG5cbiAgICBzZWxlY3RUYWIodGFiOiBudW1iZXIgfCBUYWJDb21wb25lbnQpOiB2b2lkIHtcblxuICAgICAgICAvLyBwYXNzIHRhYiB0byBzZWxlY3QgbWV0aG9kXG4gICAgICAgIHRoaXMuX3RhYnNldC5zZWxlY3QodGFiIGluc3RhbmNlb2YgVGFiQ29tcG9uZW50ID8gdGFiIDogdGhpcy5fdGFicy50b0FycmF5KClbdGFiXSk7XG5cbiAgICAgICAgLy8gcnVuIGNoYW5nZSBkZXRlY3Rpb25cbiAgICAgICAgdGhpcy5fY2hhbmdlRGV0ZWN0b3IuZGV0ZWN0Q2hhbmdlcygpO1xuICAgIH1cblxuICAgIGhhbmRsZUtleURvd24oZXZlbnQ6IEtleWJvYXJkRXZlbnQsIHRhYjogSFRNTEVsZW1lbnQpOiB2b2lkIHtcbiAgICAgICAgaWYgKGV2ZW50LmtleUNvZGUgPT09IFNQQUNFKSB7XG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgdGFiLmNsaWNrKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBtYXJrRm9yQ2hlY2soKTogdm9pZCB7XG4gICAgICAgIHRoaXMuX2NoYW5nZURldGVjdG9yLmRldGVjdENoYW5nZXMoKTtcbiAgICB9XG59XG4iLCI8IS0tIE5hdiB0YWJzIC0tPlxuPHVsXG4gIHJvbGU9XCJ0YWJsaXN0XCJcbiAgdXhUYWJiYWJsZUxpc3RcbiAgW2RpcmVjdGlvbl09XCJzdGFja2VkID09PSAnbm9uZScgPyAnaG9yaXpvbnRhbCcgOiAndmVydGljYWwnXCJcbiAgW2FsbG93Qm91bmRhcnlLZXlzXT1cInRydWVcIlxuICBjbGFzcz1cIm5hdiBuYXYtdGFic1wiXG4gIFtjbGFzcy5taW5pbWFsLXRhYl09XCJtaW5pbWFsXCJcbiAgW2F0dHIuYXJpYS1sYWJlbF09XCJhcmlhTGFiZWxcIlxuICBbYXR0ci5hcmlhLW9yaWVudGF0aW9uXT1cInN0YWNrZWQgPT09ICdub25lJyA/ICdob3Jpem9udGFsJyA6ICd2ZXJ0aWNhbCdcIlxuICA+XG4gIEBmb3IgKHRhYiBvZiBfdGFic2V0LnRhYnM7IHRyYWNrIHRhYjsgbGV0IGluZGV4ID0gJGluZGV4KSB7XG4gICAgPGxpXG4gICAgICByb2xlPVwicHJlc2VudGF0aW9uXCJcbiAgICAgIGNsYXNzPVwibmF2LWl0ZW1cIlxuICAgICAgW2NsYXNzLmFjdGl2ZV09XCIoX3RhYnNldC5hY3RpdmVUYWIkIHwgYXN5bmMpID09PSB0YWJcIlxuICAgICAgW2NsYXNzLmRpc2FibGVkXT1cInRhYi5kaXNhYmxlZFwiXG4gICAgICBbbmdDbGFzc109XCJ0YWIuY3VzdG9tQ2xhc3NcIlxuICAgICAgPlxuICAgICAgPG5nLXRlbXBsYXRlICN0YWJEZXRhaWxzPlxuICAgICAgICBAaWYgKCF0YWIuaGVhZGluZ1JlZikge1xuICAgICAgICAgIDxzcGFuPnt7IHRhYi5oZWFkaW5nIH19PC9zcGFuPlxuICAgICAgICB9XG4gICAgICAgIEBpZiAodGFiLmhlYWRpbmdSZWYpIHtcbiAgICAgICAgICA8bmctY29udGFpbmVyIFtuZ1RlbXBsYXRlT3V0bGV0XT1cInRhYi5oZWFkaW5nUmVmXCI+PC9uZy1jb250YWluZXI+XG4gICAgICAgIH1cbiAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICBAaWYgKHRhYi5yb3V0ZSkge1xuICAgICAgICA8YVxuICAgICAgICAgIGNsYXNzPVwibmF2LWxpbmtcIlxuICAgICAgICAgIFthdHRyLmlkXT1cInRhYi5pZFwiXG4gICAgICAgICAgcm9sZT1cInRhYlwiXG4gICAgICAgICAgI2FuY2hvclRhYlxuICAgICAgICAgIHV4VGFiYmFibGVMaXN0SXRlbVxuICAgICAgICAgIHV4Rm9jdXNJbmRpY2F0b3JcbiAgICAgICAgICBbYXR0ci5hcmlhLWNvbnRyb2xzXT1cInRhYi5pZFwiXG4gICAgICAgICAgW2F0dHIuYXJpYS1zZWxlY3RlZF09XCIoX3RhYnNldC5hY3RpdmVUYWIkIHwgYXN5bmMpID09PSB0YWJcIlxuICAgICAgICAgIFthdHRyLmFyaWEtZGlzYWJsZWRdPVwidGFiLmRpc2FibGVkXCJcbiAgICAgICAgICBbcm91dGVyTGlua109XCJ0YWIucm91dGVcIlxuICAgICAgICAgIFtmcmFnbWVudF09XCJ0YWIucm91dGVyTGlua0V4dHJhcz8uZnJhZ21lbnRcIlxuICAgICAgICAgIFtxdWVyeVBhcmFtc109XCJ0YWIucm91dGVyTGlua0V4dHJhcz8ucXVlcnlQYXJhbXNcIlxuICAgICAgICAgIFtxdWVyeVBhcmFtc0hhbmRsaW5nXT1cInRhYi5yb3V0ZXJMaW5rRXh0cmFzPy5xdWVyeVBhcmFtc0hhbmRsaW5nXCJcbiAgICAgICAgICBbcHJlc2VydmVGcmFnbWVudF09XCJ0YWIucm91dGVyTGlua0V4dHJhcz8ucHJlc2VydmVGcmFnbWVudFwiXG4gICAgICAgICAgW3NraXBMb2NhdGlvbkNoYW5nZV09XCJ0YWIucm91dGVyTGlua0V4dHJhcz8uc2tpcExvY2F0aW9uQ2hhbmdlXCJcbiAgICAgICAgICBbcmVwbGFjZVVybF09XCJ0YWIucm91dGVyTGlua0V4dHJhcz8ucmVwbGFjZVVybFwiXG4gICAgICAgICAgW3N0YXRlXT1cInRhYi5yb3V0ZXJMaW5rRXh0cmFzPy5zdGF0ZVwiXG4gICAgICAgICAgKGtleWRvd24pPVwiaGFuZGxlS2V5RG93bigkZXZlbnQsIGFuY2hvclRhYilcIlxuICAgICAgICAgID5cbiAgICAgICAgICA8bmctY29udGFpbmVyIFtuZ1RlbXBsYXRlT3V0bGV0XT1cInRhYkRldGFpbHNcIj4gPC9uZy1jb250YWluZXI+XG4gICAgICAgIDwvYT5cbiAgICAgIH1cbiAgICAgIEBpZiAoIXRhYi5yb3V0ZSkge1xuICAgICAgICA8YVxuICAgICAgICAgIGNsYXNzPVwibmF2LWxpbmtcIlxuICAgICAgICAgIFthdHRyLmlkXT1cInRhYi5pZFwiXG4gICAgICAgICAgcm9sZT1cInRhYlwiXG4gICAgICAgICAgdXhUYWJiYWJsZUxpc3RJdGVtXG4gICAgICAgICAgdXhGb2N1c0luZGljYXRvclxuICAgICAgICAgIChtb3VzZWRvd24pPVwiX3RhYnNldC5zZWxlY3QodGFiKVwiXG4gICAgICAgICAgKGFjdGl2YXRlZCk9XCJfdGFic2V0LnNlbGVjdCh0YWIpXCJcbiAgICAgICAgICBbYXR0ci5hcmlhLWNvbnRyb2xzXT1cInRhYi5pZFwiXG4gICAgICAgICAgW2F0dHIuYXJpYS1zZWxlY3RlZF09XCIoX3RhYnNldC5hY3RpdmVUYWIkIHwgYXN5bmMpID09PSB0YWJcIlxuICAgICAgICAgIFthdHRyLmFyaWEtZGlzYWJsZWRdPVwidGFiLmRpc2FibGVkXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgPG5nLWNvbnRhaW5lciBbbmdUZW1wbGF0ZU91dGxldF09XCJ0YWJEZXRhaWxzXCI+IDwvbmctY29udGFpbmVyPlxuICAgICAgICA8L2E+XG4gICAgICB9XG4gICAgPC9saT5cbiAgfVxuPC91bD5cblxuPCEtLSBUYWIgcGFuZXMgLS0+XG48ZGl2IGNsYXNzPVwidGFiLWNvbnRlbnRcIj5cbiAgPG5nLWNvbnRlbnQ+PC9uZy1jb250ZW50PlxuPC9kaXY+XG4iXX0=