@clr/angular
Version:
Angular components for Clarity
307 lines • 35.7 kB
JavaScript
/*
* Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/
import { Component, ContentChildren, ElementRef, HostBinding, Inject, Input, ViewChild, ViewContainerRef, } from '@angular/core';
import { startWith } from 'rxjs/operators';
import { IfActiveService } from '../../utils/conditional/if-active.service';
import { ClrKeyFocus } from '../../utils/focus/key-focus/key-focus';
import { ClrPopoverHostDirective } from '../../utils/popover/popover-host.directive';
import { TabsLayout } from './enums/tabs-layout.enum';
import { TabsService } from './providers/tabs.service';
import { ClrTab } from './tab';
import { ClrTabOverflowContent } from './tab-overflow-content';
import { TABS_ID, TABS_ID_PROVIDER } from './tabs-id.provider';
import * as i0 from "@angular/core";
import * as i1 from "../../utils/conditional/if-active.service";
import * as i2 from "../../utils/popover/providers/popover-toggle.service";
import * as i3 from "./providers/tabs.service";
import * as i4 from "../../utils/i18n/common-strings.service";
import * as i5 from "../../utils/popover/popover-host.directive";
import * as i6 from "@angular/common";
import * as i7 from "../../icon/icon";
import * as i8 from "../../utils/focus/key-focus/key-focus";
import * as i9 from "./tab-overflow-content";
export class ClrTabs {
constructor(ifActiveService, toggleService, tabsService, tabsId, commonStrings) {
this.ifActiveService = ifActiveService;
this.toggleService = toggleService;
this.tabsService = tabsService;
this.tabsId = tabsId;
this.commonStrings = commonStrings;
this.tabLinkElements = [];
// in order to check focus is triggered by click
// we are using this _mousedown flag
this._mousedown = false;
this.subscriptions = [];
this._tabLinkDirectives = [];
}
get layout() {
return this.tabsService.layout;
}
set layout(layout) {
if (Object.keys(TabsLayout)
.map(key => {
return TabsLayout[key];
})
.indexOf(layout) >= 0) {
this.tabsService.layout = layout;
}
}
get tabLinkDirectives() {
return this._tabLinkDirectives;
}
get activeTabInOverflow() {
return this.tabsService.overflowTabs.indexOf(this.tabsService.activeTab) > -1;
}
get activeTabPosition() {
return this._tabLinkDirectives.findIndex(link => link.active);
}
get isCurrentInOverflow() {
return this.keyFocus.current >= this.overflowPosition;
}
get isVertical() {
return this.layout === TabsLayout.VERTICAL;
}
set tabOverflowEl(value) {
this._tabOverflowEl = value && value.nativeElement;
if (this.toggleService.open && value) {
// only when tab overflow view element is registered,
// we need to move the focus to the first item
this.keyFocus.focusCurrent();
}
}
get overflowPosition() {
return this._tabLinkDirectives.filter(link => !link.inOverflow).length;
}
set tabContentViewContainer(value) {
this.tabsService.tabContentViewContainer = value;
}
ngAfterContentInit() {
this.subscriptions.push(this.listenForTabLinkChanges());
if (typeof this.ifActiveService.current === 'undefined' && this.tabLinkDirectives[0]) {
this.tabLinkDirectives[0].activate();
}
// set initial current position
this.keyFocus.current = this.activeTabPosition;
}
ngOnDestroy() {
this.subscriptions.forEach(sub => {
sub.unsubscribe();
});
}
toggleOverflowOnPosition(position) {
// we need to check current position to determine
// whether we need to open the tab overflow or not
this.toggleService.open = position >= this.overflowPosition;
}
resetKeyFocusCurrentToActive(event) {
const keyFocusContainsFocus = this.keyFocus.nativeElement.contains(event.relatedTarget);
if (!keyFocusContainsFocus && this.keyFocus.current !== this.activeTabPosition) {
this.keyFocus.current = this.activeTabPosition;
}
}
toggleOverflowOnClick() {
if (this.isCurrentInOverflow && this.toggleService.open) {
this.keyFocus.moveTo(this.overflowPosition - 1);
}
else {
this.keyFocus.moveTo(this.overflowPosition);
}
// once click handler completes running,
// reset the _mousedown flag
this._mousedown = false;
}
openOverflowOnFocus() {
// This method should be called only on keyboard generated focus
// when the active tab is in the overflow
if (!this._mousedown && !this.toggleService.open) {
this.keyFocus.moveTo(this.activeTabPosition);
}
}
closeOnFocusOut(event) {
if (!this._tabOverflowEl.contains(event.relatedTarget) &&
this.toggleService.open &&
!this._mousedown) {
this.toggleService.open = false;
// if the focus is out of overflow and lands on the active tab link
// which is currently visible, set the key focus current to activeTabPosition
if (this.tabLinkElements[this.activeTabPosition] === event.relatedTarget) {
this.keyFocus.current = this.activeTabPosition;
}
}
}
closeOnEscapeKey() {
// Move current to the last visible focusable item
this.keyFocus.moveTo(this.overflowPosition - 1);
}
closeOnOutsideClick(event, tabOverflowTrigger) {
// Exit early if the event target is the trigger element itself or element that's inside the trigger element.
// This is because we have another handler on the tabOverflowTrigger element itself.
// As this handler method is on the document level so the event bubbles up to it and conflicts
// with the tabOverflowTrigger handler resulting in opening the tab overflow and closing it right away consecutively.
if (event.target === tabOverflowTrigger || tabOverflowTrigger.contains(event.target)) {
return;
}
// Move current to the last visible focusable item
if (!this._tabOverflowEl.contains(event.target) && this.isCurrentInOverflow) {
this.keyFocus.moveTo(this.overflowPosition - 1);
}
}
listenForTabLinkChanges() {
return this.tabs.changes.pipe(startWith(this.tabs.map(tab => tab.tabLink))).subscribe(() => {
this._tabLinkDirectives = this.tabs.map(tab => tab.tabLink);
this.tabLinkElements = this._tabLinkDirectives.map(tab => tab.el.nativeElement);
});
}
}
ClrTabs.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTabs, deps: [{ token: i1.IfActiveService }, { token: i2.ClrPopoverToggleService }, { token: i3.TabsService }, { token: TABS_ID }, { token: i4.ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component });
ClrTabs.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrTabs, selector: "clr-tabs", inputs: { layout: ["clrLayout", "layout"] }, host: { properties: { "class.tabs-vertical": "this.isVertical" } }, providers: [IfActiveService, TabsService, TABS_ID_PROVIDER], queries: [{ propertyName: "tabs", predicate: ClrTab }], viewQueries: [{ propertyName: "keyFocus", first: true, predicate: ClrKeyFocus, descendants: true, static: true }, { propertyName: "tabOverflowEl", first: true, predicate: ClrTabOverflowContent, descendants: true, read: ElementRef }, { propertyName: "tabContentViewContainer", first: true, predicate: ["tabContentViewContainer"], descendants: true, read: ViewContainerRef, static: true }], hostDirectives: [{ directive: i5.ClrPopoverHostDirective }], ngImport: i0, template: `
<ul
class="nav"
role="tablist"
[clrKeyFocus]="tabLinkElements"
clrDirection="both"
(clrFocusChange)="toggleOverflowOnPosition($event)"
(focusout)="resetKeyFocusCurrentToActive($event)"
>
<!--tab links-->
<ng-container *ngFor="let link of tabLinkDirectives">
<ng-container *ngIf="link.tabsId === tabsId && !link.inOverflow">
<li role="presentation" class="nav-item">
<ng-container [ngTemplateOutlet]="link.templateRefContainer.template"></ng-container>
</li>
</ng-container>
</ng-container>
<ng-container *ngIf="tabsService.overflowTabs.length > 0">
<div class="tabs-overflow bottom-right" role="presentation" [class.open]="toggleService.open">
<li role="application" class="nav-item">
<button
#tabOverflowTrigger
class="btn btn-link nav-link dropdown-toggle"
type="button"
aria-hidden="true"
[attr.tabindex]="activeTabInOverflow && !toggleService.open ? 0 : -1"
[class.active]="activeTabInOverflow"
[class.open]="toggleService.open"
(mousedown)="_mousedown = true"
(focus)="openOverflowOnFocus()"
(click)="toggleOverflowOnClick()"
[attr.title]="commonStrings.keys.more"
>
<cds-icon
shape="ellipsis-horizontal"
[attr.status]="toggleService.open ? 'info' : null"
[attr.title]="commonStrings.keys.more"
></cds-icon>
</button>
</li>
<!--tab links in overflow menu-->
<clr-tab-overflow-content
*ngIf="toggleService.open"
(document:keydown.escape)="closeOnEscapeKey()"
(document:click)="closeOnOutsideClick($event, tabOverflowTrigger)"
(focusout)="closeOnFocusOut($event)"
>
<ng-container *ngFor="let link of tabLinkDirectives">
<ng-container
*ngIf="link.tabsId === tabsId && link.inOverflow"
[ngTemplateOutlet]="link.templateRefContainer.template"
></ng-container>
</ng-container>
</clr-tab-overflow-content>
</div>
</ng-container>
</ul>
<ng-container #tabContentViewContainer></ng-container>
`, isInline: true, dependencies: [{ kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i7.CdsIconCustomTag, selector: "cds-icon" }, { kind: "component", type: i8.ClrKeyFocus, selector: "[clrKeyFocus]", inputs: ["clrDirection", "clrFocusOnLoad", "clrKeyFocus"], outputs: ["clrFocusChange"] }, { kind: "component", type: i9.ClrTabOverflowContent, selector: "clr-tab-overflow-content" }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTabs, decorators: [{
type: Component,
args: [{
selector: 'clr-tabs',
template: `
<ul
class="nav"
role="tablist"
[clrKeyFocus]="tabLinkElements"
clrDirection="both"
(clrFocusChange)="toggleOverflowOnPosition($event)"
(focusout)="resetKeyFocusCurrentToActive($event)"
>
<!--tab links-->
<ng-container *ngFor="let link of tabLinkDirectives">
<ng-container *ngIf="link.tabsId === tabsId && !link.inOverflow">
<li role="presentation" class="nav-item">
<ng-container [ngTemplateOutlet]="link.templateRefContainer.template"></ng-container>
</li>
</ng-container>
</ng-container>
<ng-container *ngIf="tabsService.overflowTabs.length > 0">
<div class="tabs-overflow bottom-right" role="presentation" [class.open]="toggleService.open">
<li role="application" class="nav-item">
<button
#tabOverflowTrigger
class="btn btn-link nav-link dropdown-toggle"
type="button"
aria-hidden="true"
[attr.tabindex]="activeTabInOverflow && !toggleService.open ? 0 : -1"
[class.active]="activeTabInOverflow"
[class.open]="toggleService.open"
(mousedown)="_mousedown = true"
(focus)="openOverflowOnFocus()"
(click)="toggleOverflowOnClick()"
[attr.title]="commonStrings.keys.more"
>
<cds-icon
shape="ellipsis-horizontal"
[attr.status]="toggleService.open ? 'info' : null"
[attr.title]="commonStrings.keys.more"
></cds-icon>
</button>
</li>
<!--tab links in overflow menu-->
<clr-tab-overflow-content
*ngIf="toggleService.open"
(document:keydown.escape)="closeOnEscapeKey()"
(document:click)="closeOnOutsideClick($event, tabOverflowTrigger)"
(focusout)="closeOnFocusOut($event)"
>
<ng-container *ngFor="let link of tabLinkDirectives">
<ng-container
*ngIf="link.tabsId === tabsId && link.inOverflow"
[ngTemplateOutlet]="link.templateRefContainer.template"
></ng-container>
</ng-container>
</clr-tab-overflow-content>
</div>
</ng-container>
</ul>
<ng-container #tabContentViewContainer></ng-container>
`,
providers: [IfActiveService, TabsService, TABS_ID_PROVIDER],
hostDirectives: [ClrPopoverHostDirective],
}]
}], ctorParameters: function () { return [{ type: i1.IfActiveService }, { type: i2.ClrPopoverToggleService }, { type: i3.TabsService }, { type: undefined, decorators: [{
type: Inject,
args: [TABS_ID]
}] }, { type: i4.ClrCommonStringsService }]; }, propDecorators: { keyFocus: [{
type: ViewChild,
args: [ClrKeyFocus, { static: true }]
}], tabs: [{
type: ContentChildren,
args: [ClrTab]
}], layout: [{
type: Input,
args: ['clrLayout']
}], isVertical: [{
type: HostBinding,
args: ['class.tabs-vertical']
}], tabOverflowEl: [{
type: ViewChild,
args: [ClrTabOverflowContent, { read: ElementRef }]
}], tabContentViewContainer: [{
type: ViewChild,
args: ['tabContentViewContainer', { static: true, read: ViewContainerRef }]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFicy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2FuZ3VsYXIvc3JjL2xheW91dC90YWJzL3RhYnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUVILE9BQU8sRUFFTCxTQUFTLEVBQ1QsZUFBZSxFQUNmLFVBQVUsRUFDVixXQUFXLEVBQ1gsTUFBTSxFQUNOLEtBQUssRUFHTCxTQUFTLEVBQ1QsZ0JBQWdCLEdBQ2pCLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUUzQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMkNBQTJDLENBQUM7QUFDNUUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBRXBFLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBRXJGLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN0RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDdkQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLE9BQU8sQ0FBQztBQUUvQixPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMvRCxPQUFPLEVBQUUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7Ozs7Ozs7Ozs7O0FBa0UvRCxNQUFNLE9BQU8sT0FBTztJQWVsQixZQUNTLGVBQWdDLEVBQ2hDLGFBQXNDLEVBQ3RDLFdBQXdCLEVBQ1AsTUFBYyxFQUMvQixhQUFzQztRQUp0QyxvQkFBZSxHQUFmLGVBQWUsQ0FBaUI7UUFDaEMsa0JBQWEsR0FBYixhQUFhLENBQXlCO1FBQ3RDLGdCQUFXLEdBQVgsV0FBVyxDQUFhO1FBQ1AsV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQUMvQixrQkFBYSxHQUFiLGFBQWEsQ0FBeUI7UUFu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QU0sRUFBRSxJQUFJLEVBQUU7Z0JBRVAsSUFBSTtzQkFBcEMsZUFBZTt1QkFBQyxNQUFNO2dCQWVuQixNQUFNO3NCQURULEtBQUs7dUJBQUMsV0FBVztnQkFpQ2QsVUFBVTtzQkFEYixXQUFXO3VCQUFDLHFCQUFxQjtnQkFNOUIsYUFBYTtzQkFEaEIsU0FBUzt1QkFBQyxxQkFBcUIsRUFBRSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUU7Z0JBZTFDLHVCQUF1QjtzQkFEbEMsU0FBUzt1QkFBQyx5QkFBeUIsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIENvcHlyaWdodCAoYykgMjAxNi0yMDIzIFZNd2FyZSwgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICogVGhpcyBzb2Z0d2FyZSBpcyByZWxlYXNlZCB1bmRlciBNSVQgbGljZW5zZS5cbiAqIFRoZSBmdWxsIGxpY2Vuc2UgaW5mb3JtYXRpb24gY2FuIGJlIGZvdW5kIGluIExJQ0VOU0UgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgcHJvamVjdC5cbiAqL1xuXG5pbXBvcnQge1xuICBBZnRlckNvbnRlbnRJbml0LFxuICBDb21wb25lbnQsXG4gIENvbnRlbnRDaGlsZHJlbixcbiAgRWxlbWVudFJlZixcbiAgSG9zdEJpbmRpbmcsXG4gIEluamVjdCxcbiAgSW5wdXQsXG4gIE9uRGVzdHJveSxcbiAgUXVlcnlMaXN0LFxuICBWaWV3Q2hpbGQsXG4gIFZpZXdDb250YWluZXJSZWYsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBzdGFydFdpdGggfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbmltcG9ydCB7IElmQWN0aXZlU2VydmljZSB9IGZyb20gJy4uLy4uL3V0aWxzL2NvbmRpdGlvbmFsL2lmLWFjdGl2ZS5zZXJ2aWNlJztcbmltcG9ydCB7IENscktleUZvY3VzIH0gZnJvbSAnLi4vLi4vdXRpbHMvZm9jdXMva2V5LWZvY3VzL2tleS1mb2N1cyc7XG5pbXBvcnQgeyBDbHJDb21tb25TdHJpbmdzU2VydmljZSB9IGZyb20gJy4uLy4uL3V0aWxzL2kxOG4vY29tbW9uLXN0cmluZ3Muc2VydmljZSc7XG5pbXBvcnQgeyBDbHJQb3BvdmVySG9zdERpcmVjdGl2ZSB9IGZyb20gJy4uLy4uL3V0aWxzL3BvcG92ZXIvcG9wb3Zlci1ob3N0LmRpcmVjdGl2ZSc7XG5pbXBvcnQgeyBDbHJQb3BvdmVyVG9nZ2xlU2VydmljZSB9IGZyb20gJy4uLy4uL3V0aWxzL3BvcG92ZXIvcHJvdmlkZXJzL3BvcG92ZXItdG9nZ2xlLnNlcnZpY2UnO1xuaW1wb3J0IHsgVGFic0xheW91dCB9IGZyb20gJy4vZW51bXMvdGFicy1sYXlvdXQuZW51bSc7XG5pbXBvcnQgeyBUYWJzU2VydmljZSB9IGZyb20gJy4vcHJvdmlkZXJzL3RhYnMuc2VydmljZSc7XG5pbXBvcnQgeyBDbHJUYWIgfSBmcm9tICcuL3RhYic7XG5pbXBvcnQgeyBDbHJUYWJMaW5rIH0gZnJvbSAnLi90YWItbGluay5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgQ2xyVGFiT3ZlcmZsb3dDb250ZW50IH0gZnJvbSAnLi90YWItb3ZlcmZsb3ctY29udGVudCc7XG5pbXBvcnQgeyBUQUJTX0lELCBUQUJTX0lEX1BST1ZJREVSIH0gZnJvbSAnLi90YWJzLWlkLnByb3ZpZGVyJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnY2xyLXRhYnMnLFxuICB0ZW1wbGF0ZTogYFxuICAgIDx1bFxuICAgICAgY2xhc3M9XCJuYXZcIlxuICAgICAgcm9sZT1cInRhYmxpc3RcIlxuICAgICAgW2NscktleUZvY3VzXT1cInRhYkxpbmtFbGVtZW50c1wiXG4gICAgICBjbHJEaXJlY3Rpb249XCJib3RoXCJcbiAgICAgIChjbHJGb2N1c0NoYW5nZSk9XCJ0b2dnbGVPdmVyZmxvd09uUG9zaXRpb24oJGV2ZW50KVwiXG4gICAgICAoZm9jdXNvdXQpPVwicmVzZXRLZXlGb2N1c0N1cnJlbnRUb0FjdGl2ZSgkZXZlbnQpXCJcbiAgICA+XG4gICAgICA8IS0tdGFiIGxpbmtzLS0+XG4gICAgICA8bmctY29udGFpbmVyICpuZ0Zvcj1cImxldCBsaW5rIG9mIHRhYkxpbmtEaXJlY3RpdmVzXCI+XG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJsaW5rLnRhYnNJZCA9PT0gdGFic0lkICYmICFsaW5rLmluT3ZlcmZsb3dcIj5cbiAgICAgICAgICA8bGkgcm9sZT1cInByZXNlbnRhdGlvblwiIGNsYXNzPVwibmF2LWl0ZW1cIj5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgW25nVGVtcGxhdGVPdXRsZXRdPVwibGluay50ZW1wbGF0ZVJlZkNvbnRhaW5lci50ZW1wbGF0ZVwiPjwvbmctY29udGFpbmVyPlxuICAgICAgICAgIDwvbGk+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwidGFic1NlcnZpY2Uub3ZlcmZsb3dUYWJzLmxlbmd0aCA+IDBcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInRhYnMtb3ZlcmZsb3cgYm90dG9tLXJpZ2h0XCIgcm9sZT1cInByZXNlbnRhdGlvblwiIFtjbGFzcy5vcGVuXT1cInRvZ2dsZVNlcnZpY2Uub3BlblwiPlxuICAgICAgICAgIDxsaSByb2xlPVwiYXBwbGljYXRpb25cIiBjbGFzcz1cIm5hdi1pdGVtXCI+XG4gICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgICN0YWJPdmVyZmxvd1RyaWdnZXJcbiAgICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLWxpbmsgbmF2LWxpbmsgZHJvcGRvd24tdG9nZ2xlXCJcbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgIGFyaWEtaGlkZGVuPVwidHJ1ZVwiXG4gICAgICAgICAgICAgIFthdHRyLnRhYmluZGV4XT1cImFjdGl2ZVRhYkluT3ZlcmZsb3cgJiYgIXRvZ2dsZVNlcnZpY2Uub3BlbiA/IDAgOiAtMVwiXG4gICAgICAgICAgICAgIFtjbGFzcy5hY3RpdmVdPVwiYWN0aXZlVGFiSW5PdmVyZmxvd1wiXG4gICAgICAgICAgICAgIFtjbGFzcy5vcGVuXT1cInRvZ2dsZVNlcnZpY2Uub3BlblwiXG4gICAgICAgICAgICAgIChtb3VzZWRvd24pPVwiX21vdXNlZG93biA9IHRydWVcIlxuICAgICAgICAgICAgICAoZm9jdXMpPVwib3Blbk92ZXJmbG93T25Gb2N1cygpXCJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cInRvZ2dsZU92ZXJmbG93T25DbGljaygpXCJcbiAgICAgICAgICAgICAgW2F0dHIudGl0bGVdPVwiY29tbW9uU3RyaW5ncy5rZXlzLm1vcmVcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICA8Y2RzLWljb25cbiAgICAgICAgICAgICAgICBzaGFwZT1cImVsbGlwc2lzLWhvcml6b250YWxcIlxuICAgICAgICAgICAgICAgIFthdHRyLnN0YXR1c109XCJ0b2dnbGVTZXJ2aWNlLm9wZW4gPyAnaW5mbycgOiBudWxsXCJcbiAgICAgICAgICAgICAgICBbYXR0ci50aXRsZV09XCJjb21tb25TdHJpbmdzLmtleXMubW9yZVwiXG4gICAgICAgICAgICAgID48L2Nkcy1pY29uPlxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgPC9saT5cbiAgICAgICAgICA8IS0tdGFiIGxpbmtzIGluIG92ZXJmbG93IG1lbnUtLT5cbiAgICAgICAgICA8Y2xyLXRhYi1vdmVyZmxvdy1jb250ZW50XG4gICAgICAgICAgICAqbmdJZj1cInRvZ2dsZVNlcnZpY2Uub3BlblwiXG4gICAgICAgICAgICAoZG9jdW1lbnQ6a2V5ZG93bi5lc2NhcGUpPVwiY2xvc2VPbkVzY2FwZUtleSgpXCJcbiAgICAgICAgICAgIChkb2N1bWVudDpjbGljayk9XCJjbG9zZU9uT3V0c2lkZUNsaWNrKCRldmVudCwgdGFiT3ZlcmZsb3dUcmlnZ2VyKVwiXG4gICAgICAgICAgICAoZm9jdXNvdXQpPVwiY2xvc2VPbkZvY3VzT3V0KCRldmVudClcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IGxpbmsgb2YgdGFiTGlua0RpcmVjdGl2ZXNcIj5cbiAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgICAgICAgICpuZ0lmPVwibGluay50YWJzSWQgPT09IHRhYnNJZCAmJiBsaW5rLmluT3ZlcmZsb3dcIlxuICAgICAgICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0XT1cImxpbmsudGVtcGxhdGVSZWZDb250YWluZXIudGVtcGxhdGVcIlxuICAgICAgICAgICAgICA+PC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICA8L2Nsci10YWItb3ZlcmZsb3ctY29udGVudD5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8L3VsPlxuICAgIDxuZy1jb250YWluZXIgI3RhYkNvbnRlbnRWaWV3Q29udGFpbmVyPjwvbmctY29udGFpbmVyPlxuICBgLFxuICBwcm92aWRlcnM6IFtJZkFjdGl2ZVNlcnZpY2UsIFRhYnNTZXJ2aWNlLCBUQUJTX0lEX1BST1ZJREVSXSxcbiAgaG9zdERpcmVjdGl2ZXM6IFtDbHJQb3BvdmVySG9zdERpcmVjdGl2ZV0sXG59KVxuZXhwb3J0IGNsYXNzIENsclRhYnMgaW1wbGVtZW50cyBBZnRlckNvbnRlbnRJbml0LCBPbkRlc3Ryb3kge1xuICB0YWJMaW5rRWxlbWVudHM6IEhUTUxFbGVtZW50W10gPSBbXTtcblxuICAvLyBpbiBvcmRlciB0byBjaGVjayBmb2N1cyBpcyB0cmlnZ2VyZWQgYnkgY2xpY2tcbiAgLy8gd2UgYXJlIHVzaW5nIHRoaXMgX21vdXNlZG93biBmbGFnXG4gIF9tb3VzZWRvd24gPSBmYWxzZTtcblxuICBAVmlld0NoaWxkKENscktleUZvY3VzLCB7IHN0YXRpYzogdHJ1ZSB9KSBrZXlGb2N1czogQ2xyS2V5Rm9jdXM7XG5cbiAgQENvbnRlbnRDaGlsZHJlbihDbHJUYWIpIHByaXZhdGUgdGFiczogUXVlcnlMaXN0PENsclRhYj47XG5cbiAgcHJpdmF0ZSBzdWJzY3JpcHRpb25zOiBTdWJzY3JpcHRpb25bXSA9IFtdO1xuICBwcml2YXRlIF90YWJPdmVyZmxvd0VsOiBIVE1MRWxlbWVudDtcbiAgcHJpdmF0ZSBfdGFiTGlua0RpcmVjdGl2ZXM6IENsclRhYkxpbmtbXSA9IFtdO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHB1YmxpYyBpZkFjdGl2ZVNlcnZpY2U6IElmQWN0aXZlU2VydmljZSxcbiAgICBwdWJsaWMgdG9nZ2xlU2VydmljZTogQ2xyUG9wb3ZlclRvZ2dsZVNlcnZpY2UsXG4gICAgcHVibGljIHRhYnNTZXJ2aWNlOiBUYWJzU2VydmljZSxcbiAgICBASW5qZWN0KFRBQlNfSUQpIHB1YmxpYyB0YWJzSWQ6IG51bWJlcixcbiAgICBwdWJsaWMgY29tbW9uU3RyaW5nczogQ2xyQ29tbW9uU3RyaW5nc1NlcnZpY2VcbiAgKSB7fVxuXG4gIEBJbnB1dCgnY2xyTGF5b3V0JylcbiAgZ2V0IGxheW91dCgpOiBUYWJzTGF5b3V0IHwgc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy50YWJzU2VydmljZS5sYXlvdXQ7XG4gIH1cbiAgc2V0IGxheW91dChsYXlvdXQ6IFRhYnNMYXlvdXQgfCBzdHJpbmcpIHtcbiAgICBpZiAoXG4gICAgICBPYmplY3Qua2V5cyhUYWJzTGF5b3V0KVxuICAgICAgICAubWFwKGtleSA9PiB7XG4gICAgICAgICAgcmV0dXJuIChUYWJzTGF5b3V0IGFzIFJlY29yZDxzdHJpbmcsIGFueT4pW2tleV07XG4gICAgICAgIH0pXG4gICAgICAgIC5pbmRleE9mKGxheW91dCkgPj0gMFxuICAgICkge1xuICAgICAgdGhpcy50YWJzU2VydmljZS5sYXlvdXQgPSBsYXlvdXQ7XG4gICAgfVxuICB9XG5cbiAgZ2V0IHRhYkxpbmtEaXJlY3RpdmVzKCk6IENsclRhYkxpbmtbXSB7XG4gICAgcmV0dXJuIHRoaXMuX3RhYkxpbmtEaXJlY3RpdmVzO1xuICB9XG5cbiAgZ2V0IGFjdGl2ZVRhYkluT3ZlcmZsb3coKSB7XG4gICAgcmV0dXJuIHRoaXMudGFic1NlcnZpY2Uub3ZlcmZsb3dUYWJzLmluZGV4T2YodGhpcy50YWJzU2VydmljZS5hY3RpdmVUYWIpID4gLTE7XG4gIH1cblxuICBnZXQgYWN0aXZlVGFiUG9zaXRpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuX3RhYkxpbmtEaXJlY3RpdmVzLmZpbmRJbmRleChsaW5rID0+IGxpbmsuYWN0aXZlKTtcbiAgfVxuXG4gIGdldCBpc0N1cnJlbnRJbk92ZXJmbG93KCkge1xuICAgIHJldHVybiB0aGlzLmtleUZvY3VzLmN1cnJlbnQgPj0gdGhpcy5vdmVyZmxvd1Bvc2l0aW9uO1xuICB9XG5cbiAgQEhvc3RCaW5kaW5nKCdjbGFzcy50YWJzLXZlcnRpY2FsJylcbiAgZ2V0IGlzVmVydGljYWwoKSB7XG4gICAgcmV0dXJuIHRoaXMubGF5b3V0ID09PSBUYWJzTGF5b3V0LlZFUlRJQ0FMO1xuICB9XG5cbiAgQFZpZXdDaGlsZChDbHJUYWJPdmVyZmxvd0NvbnRlbnQsIHsgcmVhZDogRWxlbWVudFJlZiB9KVxuICBzZXQgdGFiT3ZlcmZsb3dFbCh2YWx1ZTogRWxlbWVudFJlZikge1xuICAgIHRoaXMuX3RhYk92ZXJmbG93RWwgPSB2YWx1ZSAmJiB2YWx1ZS5uYXRpdmVFbGVtZW50O1xuICAgIGlmICh0aGlzLnRvZ2dsZVNlcnZpY2Uub3BlbiAmJiB2YWx1ZSkge1xuICAgICAgLy8gb25seSB3aGVuIHRhYiBvdmVyZmxvdyB2aWV3IGVsZW1lbnQgaXMgcmVnaXN0ZXJlZCxcbiAgICAgIC8vIHdlIG5lZWQgdG8gbW92ZSB0aGUgZm9jdXMgdG8gdGhlIGZpcnN0IGl0ZW1cbiAgICAgIHRoaXMua2V5Rm9jdXMuZm9jdXNDdXJyZW50KCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZXQgb3ZlcmZsb3dQb3NpdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy5fdGFiTGlua0RpcmVjdGl2ZXMuZmlsdGVyKGxpbmsgPT4gIWxpbmsuaW5PdmVyZmxvdykubGVuZ3RoO1xuICB9XG5cbiAgQFZpZXdDaGlsZCgndGFiQ29udGVudFZpZXdDb250YWluZXInLCB7IHN0YXRpYzogdHJ1ZSwgcmVhZDogVmlld0NvbnRhaW5lclJlZiB9KVxuICBwcml2YXRlIHNldCB0YWJDb250ZW50Vmlld0NvbnRhaW5lcih2YWx1ZTogVmlld0NvbnRhaW5lclJlZikge1xuICAgIHRoaXMudGFic1NlcnZpY2UudGFiQ29udGVudFZpZXdDb250YWluZXIgPSB2YWx1ZTtcbiAgfVxuXG4gIG5nQWZ0ZXJDb250ZW50SW5pdCgpIHtcbiAgICB0aGlzLnN1YnNjcmlwdGlvbnMucHVzaCh0aGlzLmxpc3RlbkZvclRhYkxpbmtDaGFuZ2VzKCkpO1xuXG4gICAgaWYgKHR5cGVvZiB0aGlzLmlmQWN0aXZlU2VydmljZS5jdXJyZW50ID09PSAndW5kZWZpbmVkJyAmJiB0aGlzLnRhYkxpbmtEaXJlY3RpdmVzWzBdKSB7XG4gICAgICB0aGlzLnRhYkxpbmtEaXJlY3RpdmVzWzBdLmFjdGl2YXRlKCk7XG4gICAgfVxuXG4gICAgLy8gc2V0IGluaXRpYWwgY3VycmVudCBwb3NpdGlvblxuICAgIHRoaXMua2V5Rm9jdXMuY3VycmVudCA9IHRoaXMuYWN0aXZlVGFiUG9zaXRpb247XG4gIH1cblxuICBuZ09uRGVzdHJveSgpIHtcbiAgICB0aGlzLnN1YnNjcmlwdGlvbnMuZm9yRWFjaChzdWIgPT4ge1xuICAgICAgc3ViLnVuc3Vic2NyaWJlKCk7XG4gICAgfSk7XG4gIH1cblxuICB0b2dnbGVPdmVyZmxvd09uUG9zaXRpb24ocG9zaXRpb246IG51bWJlcikge1xuICAgIC8vIHdlIG5lZWQgdG8gY2hlY2sgY3VycmVudCBwb3NpdGlvbiB0byBkZXRlcm1pbmVcbiAgICAvLyB3aGV0aGVyIHdlIG5lZWQgdG8gb3BlbiB0aGUgdGFiIG92ZXJmbG93IG9yIG5vdFxuICAgIHRoaXMudG9nZ2xlU2VydmljZS5vcGVuID0gcG9zaXRpb24gPj0gdGhpcy5vdmVyZmxvd1Bvc2l0aW9uO1xuICB9XG5cbiAgcmVzZXRLZXlGb2N1c0N1cnJlbnRUb0FjdGl2ZShldmVudDogRm9jdXNFdmVudCkge1xuICAgIGNvbnN0IGtleUZvY3VzQ29udGFpbnNGb2N1cyA9IHRoaXMua2V5Rm9jdXMubmF0aXZlRWxlbWVudC5jb250YWlucyhldmVudC5yZWxhdGVkVGFyZ2V0IGFzIEhUTUxFbGVtZW50KTtcbiAgICBpZiAoIWtleUZvY3VzQ29udGFpbnNGb2N1cyAmJiB0aGlzLmtleUZvY3VzLmN1cnJlbnQgIT09IHRoaXMuYWN0aXZlVGFiUG9zaXRpb24pIHtcbiAgICAgIHRoaXMua2V5Rm9jdXMuY3VycmVudCA9IHRoaXMuYWN0aXZlVGFiUG9zaXRpb247XG4gICAgfVxuICB9XG5cbiAgdG9nZ2xlT3ZlcmZsb3dPbkNsaWNrKCkge1xuICAgIGlmICh0aGlzLmlzQ3VycmVudEluT3ZlcmZsb3cgJiYgdGhpcy50b2dnbGVTZXJ2aWNlLm9wZW4pIHtcbiAgICAgIHRoaXMua2V5Rm9jdXMubW92ZVRvKHRoaXMub3ZlcmZsb3dQb3NpdGlvbiAtIDEpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmtleUZvY3VzLm1vdmVUbyh0aGlzLm92ZXJmbG93UG9zaXRpb24pO1xuICAgIH1cblxuICAgIC8vIG9uY2UgY2xpY2sgaGFuZGxlciBjb21wbGV0ZXMgcnVubmluZyxcbiAgICAvLyByZXNldCB0aGUgX21vdXNlZG93biBmbGFnXG4gICAgdGhpcy5fbW91c2Vkb3duID0gZmFsc2U7XG4gIH1cblxuICBvcGVuT3ZlcmZsb3dPbkZvY3VzKCkge1xuICAgIC8vIFRoaXMgbWV0aG9kIHNob3VsZCBiZSBjYWxsZWQgb25seSBvbiBrZXlib2FyZCBnZW5lcmF0ZWQgZm9jdXNcbiAgICAvLyB3aGVuIHRoZSBhY3RpdmUgdGFiIGlzIGluIHRoZSBvdmVyZmxvd1xuICAgIGlmICghdGhpcy5fbW91c2Vkb3duICYmICF0aGlzLnRvZ2dsZVNlcnZpY2Uub3Blbikge1xuICAgICAgdGhpcy5rZXlGb2N1cy5tb3ZlVG8odGhpcy5hY3RpdmVUYWJQb3NpdGlvbik7XG4gICAgfVxuICB9XG5cbiAgY2xvc2VPbkZvY3VzT3V0KGV2ZW50OiBGb2N1c0V2ZW50KSB7XG4gICAgaWYgKFxuICAgICAgIXRoaXMuX3RhYk92ZXJmbG93RWwuY29udGFpbnMoZXZlbnQucmVsYXRlZFRhcmdldCBhcyBIVE1MRWxlbWVudCkgJiZcbiAgICAgIHRoaXMudG9nZ2xlU2VydmljZS5vcGVuICYmXG4gICAgICAhdGhpcy5fbW91c2Vkb3duXG4gICAgKSB7XG4gICAgICB0aGlzLnRvZ2dsZVNlcnZpY2Uub3BlbiA9IGZhbHNlO1xuXG4gICAgICAvLyBpZiB0aGUgZm9jdXMgaXMgb3V0IG9mIG92ZXJmbG93IGFuZCBsYW5kcyBvbiB0aGUgYWN0aXZlIHRhYiBsaW5rXG4gICAgICAvLyB3aGljaCBpcyBjdXJyZW50bHkgdmlzaWJsZSwgc2V0IHRoZSBrZXkgZm9jdXMgY3VycmVudCB0byBhY3RpdmVUYWJQb3NpdGlvblxuICAgICAgaWYgKHRoaXMudGFiTGlua0VsZW1lbnRzW3RoaXMuYWN0aXZlVGFiUG9zaXRpb25dID09PSBldmVudC5yZWxhdGVkVGFyZ2V0KSB7XG4gICAgICAgIHRoaXMua2V5Rm9jdXMuY3VycmVudCA9IHRoaXMuYWN0aXZlVGFiUG9zaXRpb247XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgY2xvc2VPbkVzY2FwZUtleSgpIHtcbiAgICAvLyBNb3ZlIGN1cnJlbnQgdG8gdGhlIGxhc3QgdmlzaWJsZSBmb2N1c2FibGUgaXRlbVxuICAgIHRoaXMua2V5Rm9jdXMubW92ZVRvKHRoaXMub3ZlcmZsb3dQb3NpdGlvbiAtIDEpO1xuICB9XG5cbiAgY2xvc2VPbk91dHNpZGVDbGljayhldmVudDogRXZlbnQsIHRhYk92ZXJmbG93VHJpZ2dlcjogSFRNTEVsZW1lbnQpIHtcbiAgICAvLyBFeGl0IGVhcmx5IGlmIHRoZSBldmVudCB0YXJnZXQgaXMgdGhlIHRyaWdnZXIgZWxlbWVudCBpdHNlbGYgb3IgZWxlbWVudCB0aGF0J3MgaW5zaWRlIHRoZSB0cmlnZ2VyIGVsZW1lbnQuXG4gICAgLy8gVGhpcyBpcyBiZWNhdXNlIHdlIGhhdmUgYW5vdGhlciBoYW5kbGVyIG9uIHRoZSB0YWJPdmVyZmxvd1RyaWdnZXIgZWxlbWVudCBpdHNlbGYuXG4gICAgLy8gQXMgdGhpcyBoYW5kbGVyIG1ldGhvZCBpcyBvbiB0aGUgZG9jdW1lbnQgbGV2ZWwgc28gdGhlIGV2ZW50IGJ1YmJsZXMgdXAgdG8gaXQgYW5kIGNvbmZsaWN0c1xuICAgIC8vIHdpdGggdGhlIHRhYk92ZXJmbG93VHJpZ2dlciBoYW5kbGVyIHJlc3VsdGluZyBpbiBvcGVuaW5nIHRoZSB0YWIgb3ZlcmZsb3cgYW5kIGNsb3NpbmcgaXQgcmlnaHQgYXdheSBjb25zZWN1dGl2ZWx5LlxuICAgIGlmIChldmVudC50YXJnZXQgPT09IHRhYk92ZXJmbG93VHJpZ2dlciB8fCB0YWJPdmVyZmxvd1RyaWdnZXIuY29udGFpbnMoZXZlbnQudGFyZ2V0IGFzIEhUTUxFbGVtZW50KSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIE1vdmUgY3VycmVudCB0byB0aGUgbGFzdCB2aXNpYmxlIGZvY3VzYWJsZSBpdGVtXG4gICAgaWYgKCF0aGlzLl90YWJPdmVyZmxvd0VsLmNvbnRhaW5zKGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudCkgJiYgdGhpcy5pc0N1cnJlbnRJbk92ZXJmbG93KSB7XG4gICAgICB0aGlzLmtleUZvY3VzLm1vdmVUbyh0aGlzLm92ZXJmbG93UG9zaXRpb24gLSAxKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGxpc3RlbkZvclRhYkxpbmtDaGFuZ2VzKCkge1xuICAgIHJldHVybiB0aGlzLnRhYnMuY2hhbmdlcy5waXBlKHN0YXJ0V2l0aCh0aGlzLnRhYnMubWFwKHRhYiA9PiB0YWIudGFiTGluaykpKS5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgdGhpcy5fdGFiTGlua0RpcmVjdGl2ZXMgPSB0aGlzLnRhYnMubWFwKHRhYiA9PiB0YWIudGFiTGluayk7XG4gICAgICB0aGlzLnRhYkxpbmtFbGVtZW50cyA9IHRoaXMuX3RhYkxpbmtEaXJlY3RpdmVzLm1hcCh0YWIgPT4gdGFiLmVsLm5hdGl2ZUVsZW1lbnQpO1xuICAgIH0pO1xuICB9XG59XG4iXX0=