@clr/angular
Version:
Angular components for Clarity
327 lines • 38.9 kB
JavaScript
/*
* Copyright (c) 2016-2025 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
* 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 { ClrTabAction } from './tab-action.directive';
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());
this.subscriptions.push(this.listedForTabsActionsChanges());
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.
const isTabsAction = this.tabsActions.some(action => action.nativeElement.contains(event.target));
if (event.target === tabOverflowTrigger ||
tabOverflowTrigger.contains(event.target) ||
isTabsAction) {
return;
}
// Move current to the last visible focusable item
if (!this._tabOverflowEl.contains(event.target) && this.isCurrentInOverflow) {
this.keyFocus.moveTo(this.overflowPosition - 1);
}
}
setTabLinkElements() {
this._tabLinkDirectives = this.tabs.map(tab => tab.tabLink);
this.tabLinkElements = this._tabLinkDirectives.map(tab => tab.el.nativeElement);
if (this.tabsActions && this.tabsActions) {
this.tabLinkElements.push(...this.tabsActions.map(action => action.nativeElement));
}
}
listenForTabLinkChanges() {
return this.tabs.changes
.pipe(startWith(this.tabs.map(tab => tab.tabLink)))
.subscribe(() => this.setTabLinkElements());
}
listedForTabsActionsChanges() {
return this.tabsActions.changes.subscribe(() => this.setTabLinkElements());
}
}
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: "tabsActions", predicate: ClrTabAction, descendants: true, read: ElementRef }, { 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>
<ng-content select="clr-tabs-actions"></ng-content>
</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>
<ng-content select="clr-tabs-actions"></ng-content>
</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 }]
}], tabsActions: [{
type: ContentChildren,
args: [ClrTabAction, { read: ElementRef, descendants: 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFicy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2FuZ3VsYXIvc3JjL2xheW91dC90YWJzL3RhYnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7O0dBS0c7QUFFSCxPQUFPLEVBRUwsU0FBUyxFQUNULGVBQWUsRUFDZixVQUFVLEVBQ1YsV0FBVyxFQUNYLE1BQU0sRUFDTixLQUFLLEVBR0wsU0FBUyxFQUNULGdCQUFnQixHQUNqQixNQUFNLGVBQWUsQ0FBQztBQUV2QixPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFM0MsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDJDQUEyQyxDQUFDO0FBQzVFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUVwRSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQUVyRixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDdEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxPQUFPLENBQUM7QUFDL0IsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBRXRELE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQy9ELE9BQU8sRUFBRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQzs7Ozs7Ozs7Ozs7QUFtRS9ELE1BQU0sT0FBTyxPQUFPO0lBZ0JsQixZQUNTLGVBQWdDLEVBQ2hDLGFBQXNDLEVBQ3RDLFdBQXdCLEVBQ1AsTUFBYyxFQUMvQixhQUFzQztRQUp0QyxvQkFBZSxHQUFmLGVBQWUsQ0FBaUI7UUFDaEMsa0JBQWEsR0FBYixhQUFhLENBQXlCO1FBQ3RDLGdCQUFXLEdBQVgsV0FBVyxDQUFhO1FBQ1AsV0FBTSxH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QWUxQyx1QkFBdUI7c0JBRGxDLFNBQVM7dUJBQUMseUJBQXlCLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxnQkFBZ0IsRUFBRSIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTYtMjAyNSBCcm9hZGNvbS4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqIFRoZSB0ZXJtIFwiQnJvYWRjb21cIiByZWZlcnMgdG8gQnJvYWRjb20gSW5jLiBhbmQvb3IgaXRzIHN1YnNpZGlhcmllcy5cbiAqIFRoaXMgc29mdHdhcmUgaXMgcmVsZWFzZWQgdW5kZXIgTUlUIGxpY2Vuc2UuXG4gKiBUaGUgZnVsbCBsaWNlbnNlIGluZm9ybWF0aW9uIGNhbiBiZSBmb3VuZCBpbiBMSUNFTlNFIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHByb2plY3QuXG4gKi9cblxuaW1wb3J0IHtcbiAgQWZ0ZXJDb250ZW50SW5pdCxcbiAgQ29tcG9uZW50LFxuICBDb250ZW50Q2hpbGRyZW4sXG4gIEVsZW1lbnRSZWYsXG4gIEhvc3RCaW5kaW5nLFxuICBJbmplY3QsXG4gIElucHV0LFxuICBPbkRlc3Ryb3ksXG4gIFF1ZXJ5TGlzdCxcbiAgVmlld0NoaWxkLFxuICBWaWV3Q29udGFpbmVyUmVmLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgc3RhcnRXaXRoIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQgeyBJZkFjdGl2ZVNlcnZpY2UgfSBmcm9tICcuLi8uLi91dGlscy9jb25kaXRpb25hbC9pZi1hY3RpdmUuc2VydmljZSc7XG5pbXBvcnQgeyBDbHJLZXlGb2N1cyB9IGZyb20gJy4uLy4uL3V0aWxzL2ZvY3VzL2tleS1mb2N1cy9rZXktZm9jdXMnO1xuaW1wb3J0IHsgQ2xyQ29tbW9uU3RyaW5nc1NlcnZpY2UgfSBmcm9tICcuLi8uLi91dGlscy9pMThuL2NvbW1vbi1zdHJpbmdzLnNlcnZpY2UnO1xuaW1wb3J0IHsgQ2xyUG9wb3Zlckhvc3REaXJlY3RpdmUgfSBmcm9tICcuLi8uLi91dGlscy9wb3BvdmVyL3BvcG92ZXItaG9zdC5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgQ2xyUG9wb3ZlclRvZ2dsZVNlcnZpY2UgfSBmcm9tICcuLi8uLi91dGlscy9wb3BvdmVyL3Byb3ZpZGVycy9wb3BvdmVyLXRvZ2dsZS5zZXJ2aWNlJztcbmltcG9ydCB7IFRhYnNMYXlvdXQgfSBmcm9tICcuL2VudW1zL3RhYnMtbGF5b3V0LmVudW0nO1xuaW1wb3J0IHsgVGFic1NlcnZpY2UgfSBmcm9tICcuL3Byb3ZpZGVycy90YWJzLnNlcnZpY2UnO1xuaW1wb3J0IHsgQ2xyVGFiIH0gZnJvbSAnLi90YWInO1xuaW1wb3J0IHsgQ2xyVGFiQWN0aW9uIH0gZnJvbSAnLi90YWItYWN0aW9uLmRpcmVjdGl2ZSc7XG5pbXBvcnQgeyBDbHJUYWJMaW5rIH0gZnJvbSAnLi90YWItbGluay5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgQ2xyVGFiT3ZlcmZsb3dDb250ZW50IH0gZnJvbSAnLi90YWItb3ZlcmZsb3ctY29udGVudCc7XG5pbXBvcnQgeyBUQUJTX0lELCBUQUJTX0lEX1BST1ZJREVSIH0gZnJvbSAnLi90YWJzLWlkLnByb3ZpZGVyJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnY2xyLXRhYnMnLFxuICB0ZW1wbGF0ZTogYFxuICAgIDx1bFxuICAgICAgY2xhc3M9XCJuYXZcIlxuICAgICAgcm9sZT1cInRhYmxpc3RcIlxuICAgICAgW2NscktleUZvY3VzXT1cInRhYkxpbmtFbGVtZW50c1wiXG4gICAgICBjbHJEaXJlY3Rpb249XCJib3RoXCJcbiAgICAgIChjbHJGb2N1c0NoYW5nZSk9XCJ0b2dnbGVPdmVyZmxvd09uUG9zaXRpb24oJGV2ZW50KVwiXG4gICAgICAoZm9jdXNvdXQpPVwicmVzZXRLZXlGb2N1c0N1cnJlbnRUb0FjdGl2ZSgkZXZlbnQpXCJcbiAgICA+XG4gICAgICA8IS0tdGFiIGxpbmtzLS0+XG4gICAgICA8bmctY29udGFpbmVyICpuZ0Zvcj1cImxldCBsaW5rIG9mIHRhYkxpbmtEaXJlY3RpdmVzXCI+XG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJsaW5rLnRhYnNJZCA9PT0gdGFic0lkICYmICFsaW5rLmluT3ZlcmZsb3dcIj5cbiAgICAgICAgICA8bGkgcm9sZT1cInByZXNlbnRhdGlvblwiIGNsYXNzPVwibmF2LWl0ZW1cIj5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgW25nVGVtcGxhdGVPdXRsZXRdPVwibGluay50ZW1wbGF0ZVJlZkNvbnRhaW5lci50ZW1wbGF0ZVwiPjwvbmctY29udGFpbmVyPlxuICAgICAgICAgIDwvbGk+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwidGFic1NlcnZpY2Uub3ZlcmZsb3dUYWJzLmxlbmd0aCA+IDBcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInRhYnMtb3ZlcmZsb3cgYm90dG9tLXJpZ2h0XCIgcm9sZT1cInByZXNlbnRhdGlvblwiIFtjbGFzcy5vcGVuXT1cInRvZ2dsZVNlcnZpY2Uub3BlblwiPlxuICAgICAgICAgIDxsaSByb2xlPVwiYXBwbGljYXRpb25cIiBjbGFzcz1cIm5hdi1pdGVtXCI+XG4gICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgICN0YWJPdmVyZmxvd1RyaWdnZXJcbiAgICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLWxpbmsgbmF2LWxpbmsgZHJvcGRvd24tdG9nZ2xlXCJcbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgIGFyaWEtaGlkZGVuPVwidHJ1ZVwiXG4gICAgICAgICAgICAgIFthdHRyLnRhYmluZGV4XT1cImFjdGl2ZVRhYkluT3ZlcmZsb3cgJiYgIXRvZ2dsZVNlcnZpY2Uub3BlbiA/IDAgOiAtMVwiXG4gICAgICAgICAgICAgIFtjbGFzcy5hY3RpdmVdPVwiYWN0aXZlVGFiSW5PdmVyZmxvd1wiXG4gICAgICAgICAgICAgIFtjbGFzcy5vcGVuXT1cInRvZ2dsZVNlcnZpY2Uub3BlblwiXG4gICAgICAgICAgICAgIChtb3VzZWRvd24pPVwiX21vdXNlZG93biA9IHRydWVcIlxuICAgICAgICAgICAgICAoZm9jdXMpPVwib3Blbk92ZXJmbG93T25Gb2N1cygpXCJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cInRvZ2dsZU92ZXJmbG93T25DbGljaygpXCJcbiAgICAgICAgICAgICAgW2F0dHIudGl0bGVdPVwiY29tbW9uU3RyaW5ncy5rZXlzLm1vcmVcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICA8Y2RzLWljb25cbiAgICAgICAgICAgICAgICBzaGFwZT1cImVsbGlwc2lzLWhvcml6b250YWxcIlxuICAgICAgICAgICAgICAgIFthdHRyLnN0YXR1c109XCJ0b2dnbGVTZXJ2aWNlLm9wZW4gPyAnaW5mbycgOiBudWxsXCJcbiAgICAgICAgICAgICAgICBbYXR0ci50aXRsZV09XCJjb21tb25TdHJpbmdzLmtleXMubW9yZVwiXG4gICAgICAgICAgICAgID48L2Nkcy1pY29uPlxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgPC9saT5cbiAgICAgICAgICA8IS0tdGFiIGxpbmtzIGluIG92ZXJmbG93IG1lbnUtLT5cbiAgICAgICAgICA8Y2xyLXRhYi1vdmVyZmxvdy1jb250ZW50XG4gICAgICAgICAgICAqbmdJZj1cInRvZ2dsZVNlcnZpY2Uub3BlblwiXG4gICAgICAgICAgICAoZG9jdW1lbnQ6a2V5ZG93bi5lc2NhcGUpPVwiY2xvc2VPbkVzY2FwZUtleSgpXCJcbiAgICAgICAgICAgIChkb2N1bWVudDpjbGljayk9XCJjbG9zZU9uT3V0c2lkZUNsaWNrKCRldmVudCwgdGFiT3ZlcmZsb3dUcmlnZ2VyKVwiXG4gICAgICAgICAgICAoZm9jdXNvdXQpPVwiY2xvc2VPbkZvY3VzT3V0KCRldmVudClcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IGxpbmsgb2YgdGFiTGlua0RpcmVjdGl2ZXNcIj5cbiAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgICAgICAgICpuZ0lmPVwibGluay50YWJzSWQgPT09IHRhYnNJZCAmJiBsaW5rLmluT3ZlcmZsb3dcIlxuICAgICAgICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0XT1cImxpbmsudGVtcGxhdGVSZWZDb250YWluZXIudGVtcGxhdGVcIlxuICAgICAgICAgICAgICA+PC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICA8L2Nsci10YWItb3ZlcmZsb3ctY29udGVudD5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cImNsci10YWJzLWFjdGlvbnNcIj48L25nLWNvbnRlbnQ+XG4gICAgPC91bD5cbiAgICA8bmctY29udGFpbmVyICN0YWJDb250ZW50Vmlld0NvbnRhaW5lcj48L25nLWNvbnRhaW5lcj5cbiAgYCxcbiAgcHJvdmlkZXJzOiBbSWZBY3RpdmVTZXJ2aWNlLCBUYWJzU2VydmljZSwgVEFCU19JRF9QUk9WSURFUl0sXG4gIGhvc3REaXJlY3RpdmVzOiBbQ2xyUG9wb3Zlckhvc3REaXJlY3RpdmVdLFxufSlcbmV4cG9ydCBjbGFzcyBDbHJUYWJzIGltcGxlbWVudHMgQWZ0ZXJDb250ZW50SW5pdCwgT25EZXN0cm95IHtcbiAgdGFiTGlua0VsZW1lbnRzOiBIVE1MRWxlbWVudFtdID0gW107XG5cbiAgLy8gaW4gb3JkZXIgdG8gY2hlY2sgZm9jdXMgaXMgdHJpZ2dlcmVkIGJ5IGNsaWNrXG4gIC8vIHdlIGFyZSB1c2luZyB0aGlzIF9tb3VzZWRvd24gZmxhZ1xuICBfbW91c2Vkb3duID0gZmFsc2U7XG5cbiAgQFZpZXdDaGlsZChDbHJLZXlGb2N1cywgeyBzdGF0aWM6IHRydWUgfSkga2V5Rm9jdXM6IENscktleUZvY3VzO1xuXG4gIEBDb250ZW50Q2hpbGRyZW4oQ2xyVGFiQWN0aW9uLCB7IHJlYWQ6IEVsZW1lbnRSZWYsIGRlc2NlbmRhbnRzOiB0cnVlIH0pIHRhYnNBY3Rpb25zOiBRdWVyeUxpc3Q8RWxlbWVudFJlZj47XG4gIEBDb250ZW50Q2hpbGRyZW4oQ2xyVGFiKSBwcml2YXRlIHRhYnM6IFF1ZXJ5TGlzdDxDbHJUYWI+O1xuXG4gIHByaXZhdGUgc3Vic2NyaXB0aW9uczogU3Vic2NyaXB0aW9uW10gPSBbXTtcbiAgcHJpdmF0ZSBfdGFiT3ZlcmZsb3dFbDogSFRNTEVsZW1lbnQ7XG4gIHByaXZhdGUgX3RhYkxpbmtEaXJlY3RpdmVzOiBDbHJUYWJMaW5rW10gPSBbXTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwdWJsaWMgaWZBY3RpdmVTZXJ2aWNlOiBJZkFjdGl2ZVNlcnZpY2UsXG4gICAgcHVibGljIHRvZ2dsZVNlcnZpY2U6IENsclBvcG92ZXJUb2dnbGVTZXJ2aWNlLFxuICAgIHB1YmxpYyB0YWJzU2VydmljZTogVGFic1NlcnZpY2UsXG4gICAgQEluamVjdChUQUJTX0lEKSBwdWJsaWMgdGFic0lkOiBudW1iZXIsXG4gICAgcHVibGljIGNvbW1vblN0cmluZ3M6IENsckNvbW1vblN0cmluZ3NTZXJ2aWNlXG4gICkge31cblxuICBASW5wdXQoJ2NsckxheW91dCcpXG4gIGdldCBsYXlvdXQoKTogVGFic0xheW91dCB8IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMudGFic1NlcnZpY2UubGF5b3V0O1xuICB9XG4gIHNldCBsYXlvdXQobGF5b3V0OiBUYWJzTGF5b3V0IHwgc3RyaW5nKSB7XG4gICAgaWYgKFxuICAgICAgT2JqZWN0LmtleXMoVGFic0xheW91dClcbiAgICAgICAgLm1hcChrZXkgPT4ge1xuICAgICAgICAgIHJldHVybiAoVGFic0xheW91dCBhcyBSZWNvcmQ8c3RyaW5nLCBhbnk+KVtrZXldO1xuICAgICAgICB9KVxuICAgICAgICAuaW5kZXhPZihsYXlvdXQpID49IDBcbiAgICApIHtcbiAgICAgIHRoaXMudGFic1NlcnZpY2UubGF5b3V0ID0gbGF5b3V0O1xuICAgIH1cbiAgfVxuXG4gIGdldCB0YWJMaW5rRGlyZWN0aXZlcygpOiBDbHJUYWJMaW5rW10ge1xuICAgIHJldHVybiB0aGlzLl90YWJMaW5rRGlyZWN0aXZlcztcbiAgfVxuXG4gIGdldCBhY3RpdmVUYWJJbk92ZXJmbG93KCkge1xuICAgIHJldHVybiB0aGlzLnRhYnNTZXJ2aWNlLm92ZXJmbG93VGFicy5pbmRleE9mKHRoaXMudGFic1NlcnZpY2UuYWN0aXZlVGFiKSA+IC0xO1xuICB9XG5cbiAgZ2V0IGFjdGl2ZVRhYlBvc2l0aW9uKCkge1xuICAgIHJldHVybiB0aGlzLl90YWJMaW5rRGlyZWN0aXZlcy5maW5kSW5kZXgobGluayA9PiBsaW5rLmFjdGl2ZSk7XG4gIH1cblxuICBnZXQgaXNDdXJyZW50SW5PdmVyZmxvdygpIHtcbiAgICByZXR1cm4gdGhpcy5rZXlGb2N1cy5jdXJyZW50ID49IHRoaXMub3ZlcmZsb3dQb3NpdGlvbjtcbiAgfVxuXG4gIEBIb3N0QmluZGluZygnY2xhc3MudGFicy12ZXJ0aWNhbCcpXG4gIGdldCBpc1ZlcnRpY2FsKCkge1xuICAgIHJldHVybiB0aGlzLmxheW91dCA9PT0gVGFic0xheW91dC5WRVJUSUNBTDtcbiAgfVxuXG4gIEBWaWV3Q2hpbGQoQ2xyVGFiT3ZlcmZsb3dDb250ZW50LCB7IHJlYWQ6IEVsZW1lbnRSZWYgfSlcbiAgc2V0IHRhYk92ZXJmbG93RWwodmFsdWU6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+KSB7XG4gICAgdGhpcy5fdGFiT3ZlcmZsb3dFbCA9IHZhbHVlICYmIHZhbHVlLm5hdGl2ZUVsZW1lbnQ7XG4gICAgaWYgKHRoaXMudG9nZ2xlU2VydmljZS5vcGVuICYmIHZhbHVlKSB7XG4gICAgICAvLyBvbmx5IHdoZW4gdGFiIG92ZXJmbG93IHZpZXcgZWxlbWVudCBpcyByZWdpc3RlcmVkLFxuICAgICAgLy8gd2UgbmVlZCB0byBtb3ZlIHRoZSBmb2N1cyB0byB0aGUgZmlyc3QgaXRlbVxuICAgICAgdGhpcy5rZXlGb2N1cy5mb2N1c0N1cnJlbnQoKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGdldCBvdmVyZmxvd1Bvc2l0aW9uKCkge1xuICAgIHJldHVybiB0aGlzLl90YWJMaW5rRGlyZWN0aXZlcy5maWx0ZXIobGluayA9PiAhbGluay5pbk92ZXJmbG93KS5sZW5ndGg7XG4gIH1cblxuICBAVmlld0NoaWxkKCd0YWJDb250ZW50Vmlld0NvbnRhaW5lcicsIHsgc3RhdGljOiB0cnVlLCByZWFkOiBWaWV3Q29udGFpbmVyUmVmIH0pXG4gIHByaXZhdGUgc2V0IHRhYkNvbnRlbnRWaWV3Q29udGFpbmVyKHZhbHVlOiBWaWV3Q29udGFpbmVyUmVmKSB7XG4gICAgdGhpcy50YWJzU2VydmljZS50YWJDb250ZW50Vmlld0NvbnRhaW5lciA9IHZhbHVlO1xuICB9XG5cbiAgbmdBZnRlckNvbnRlbnRJbml0KCkge1xuICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5wdXNoKHRoaXMubGlzdGVuRm9yVGFiTGlua0NoYW5nZXMoKSk7XG4gICAgdGhpcy5zdWJzY3JpcHRpb25zLnB1c2godGhpcy5saXN0ZWRGb3JUYWJzQWN0aW9uc0NoYW5nZXMoKSk7XG5cbiAgICBpZiAodHlwZW9mIHRoaXMuaWZBY3RpdmVTZXJ2aWNlLmN1cnJlbnQgPT09ICd1bmRlZmluZWQnICYmIHRoaXMudGFiTGlua0RpcmVjdGl2ZXNbMF0pIHtcbiAgICAgIHRoaXMudGFiTGlua0RpcmVjdGl2ZXNbMF0uYWN0aXZhdGUoKTtcbiAgICB9XG5cbiAgICAvLyBzZXQgaW5pdGlhbCBjdXJyZW50IHBvc2l0aW9uXG4gICAgdGhpcy5rZXlGb2N1cy5jdXJyZW50ID0gdGhpcy5hY3RpdmVUYWJQb3NpdGlvbjtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCkge1xuICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5mb3JFYWNoKHN1YiA9PiB7XG4gICAgICBzdWIudW5zdWJzY3JpYmUoKTtcbiAgICB9KTtcbiAgfVxuXG4gIHRvZ2dsZU92ZXJmbG93T25Qb3NpdGlvbihwb3NpdGlvbjogbnVtYmVyKSB7XG4gICAgLy8gd2UgbmVlZCB0byBjaGVjayBjdXJyZW50IHBvc2l0aW9uIHRvIGRldGVybWluZVxuICAgIC8vIHdoZXRoZXIgd2UgbmVlZCB0byBvcGVuIHRoZSB0YWIgb3ZlcmZsb3cgb3Igbm90XG4gICAgdGhpcy50b2dnbGVTZXJ2aWNlLm9wZW4gPSBwb3NpdGlvbiA+PSB0aGlzLm92ZXJmbG93UG9zaXRpb247XG4gIH1cblxuICByZXNldEtleUZvY3VzQ3VycmVudFRvQWN0aXZlKGV2ZW50OiBGb2N1c0V2ZW50KSB7XG4gICAgY29uc3Qga2V5Rm9jdXNDb250YWluc0ZvY3VzID0gdGhpcy5rZXlGb2N1cy5uYXRpdmVFbGVtZW50LmNvbnRhaW5zKGV2ZW50LnJlbGF0ZWRUYXJnZXQgYXMgSFRNTEVsZW1lbnQpO1xuICAgIGlmICgha2V5Rm9jdXNDb250YWluc0ZvY3VzICYmIHRoaXMua2V5Rm9jdXMuY3VycmVudCAhPT0gdGhpcy5hY3RpdmVUYWJQb3NpdGlvbikge1xuICAgICAgdGhpcy5rZXlGb2N1cy5jdXJyZW50ID0gdGhpcy5hY3RpdmVUYWJQb3NpdGlvbjtcbiAgICB9XG4gIH1cblxuICB0b2dnbGVPdmVyZmxvd09uQ2xpY2soKSB7XG4gICAgaWYgKHRoaXMuaXNDdXJyZW50SW5PdmVyZmxvdyAmJiB0aGlzLnRvZ2dsZVNlcnZpY2Uub3Blbikge1xuICAgICAgdGhpcy5rZXlGb2N1cy5tb3ZlVG8odGhpcy5vdmVyZmxvd1Bvc2l0aW9uIC0gMSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMua2V5Rm9jdXMubW92ZVRvKHRoaXMub3ZlcmZsb3dQb3NpdGlvbik7XG4gICAgfVxuXG4gICAgLy8gb25jZSBjbGljayBoYW5kbGVyIGNvbXBsZXRlcyBydW5uaW5nLFxuICAgIC8vIHJlc2V0IHRoZSBfbW91c2Vkb3duIGZsYWdcbiAgICB0aGlzLl9tb3VzZWRvd24gPSBmYWxzZTtcbiAgfVxuXG4gIG9wZW5PdmVyZmxvd09uRm9jdXMoKSB7XG4gICAgLy8gVGhpcyBtZXRob2Qgc2hvdWxkIGJlIGNhbGxlZCBvbmx5IG9uIGtleWJvYXJkIGdlbmVyYXRlZCBmb2N1c1xuICAgIC8vIHdoZW4gdGhlIGFjdGl2ZSB0YWIgaXMgaW4gdGhlIG92ZXJmbG93XG4gICAgaWYgKCF0aGlzLl9tb3VzZWRvd24gJiYgIXRoaXMudG9nZ2xlU2VydmljZS5vcGVuKSB7XG4gICAgICB0aGlzLmtleUZvY3VzLm1vdmVUbyh0aGlzLmFjdGl2ZVRhYlBvc2l0aW9uKTtcbiAgICB9XG4gIH1cblxuICBjbG9zZU9uRm9jdXNPdXQoZXZlbnQ6IEZvY3VzRXZlbnQpIHtcbiAgICBpZiAoXG4gICAgICAhdGhpcy5fdGFiT3ZlcmZsb3dFbC5jb250YWlucyhldmVudC5yZWxhdGVkVGFyZ2V0IGFzIEhUTUxFbGVtZW50KSAmJlxuICAgICAgdGhpcy50b2dnbGVTZXJ2aWNlLm9wZW4gJiZcbiAgICAgICF0aGlzLl9tb3VzZWRvd25cbiAgICApIHtcbiAgICAgIHRoaXMudG9nZ2xlU2VydmljZS5vcGVuID0gZmFsc2U7XG5cbiAgICAgIC8vIGlmIHRoZSBmb2N1cyBpcyBvdXQgb2Ygb3ZlcmZsb3cgYW5kIGxhbmRzIG9uIHRoZSBhY3RpdmUgdGFiIGxpbmtcbiAgICAgIC8vIHdoaWNoIGlzIGN1cnJlbnRseSB2aXNpYmxlLCBzZXQgdGhlIGtleSBmb2N1cyBjdXJyZW50IHRvIGFjdGl2ZVRhYlBvc2l0aW9uXG4gICAgICBpZiAodGhpcy50YWJMaW5rRWxlbWVudHNbdGhpcy5hY3RpdmVUYWJQb3NpdGlvbl0gPT09IGV2ZW50LnJlbGF0ZWRUYXJnZXQpIHtcbiAgICAgICAgdGhpcy5rZXlGb2N1cy5jdXJyZW50ID0gdGhpcy5hY3RpdmVUYWJQb3NpdGlvbjtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBjbG9zZU9uRXNjYXBlS2V5KCkge1xuICAgIC8vIE1vdmUgY3VycmVudCB0byB0aGUgbGFzdCB2aXNpYmxlIGZvY3VzYWJsZSBpdGVtXG4gICAgdGhpcy5rZXlGb2N1cy5tb3ZlVG8odGhpcy5vdmVyZmxvd1Bvc2l0aW9uIC0gMSk7XG4gIH1cblxuICBjbG9zZU9uT3V0c2lkZUNsaWNrKGV2ZW50OiBFdmVudCwgdGFiT3ZlcmZsb3dUcmlnZ2VyOiBIVE1MRWxlbWVudCkge1xuICAgIC8vIEV4aXQgZWFybHkgaWYgdGhlIGV2ZW50IHRhcmdldCBpcyB0aGUgdHJpZ2dlciBlbGVtZW50IGl0c2VsZiBvciBlbGVtZW50IHRoYXQncyBpbnNpZGUgdGhlIHRyaWdnZXIgZWxlbWVudC5cbiAgICAvLyBUaGlzIGlzIGJlY2F1c2Ugd2UgaGF2ZSBhbm90aGVyIGhhbmRsZXIgb24gdGhlIHRhYk92ZXJmbG93VHJpZ2dlciBlbGVtZW50IGl0c2VsZi5cbiAgICAvLyBBcyB0aGlzIGhhbmRsZXIgbWV0aG9kIGlzIG9uIHRoZSBkb2N1bWVudCBsZXZlbCBzbyB0aGUgZXZlbnQgYnViYmxlcyB1cCB0byBpdCBhbmQgY29uZmxpY3RzXG4gICAgLy8gd2l0aCB0aGUgdGFiT3ZlcmZsb3dUcmlnZ2VyIGhhbmRsZXIgcmVzdWx0aW5nIGluIG9wZW5pbmcgdGhlIHRhYiBvdmVyZmxvdyBhbmQgY2xvc2luZyBpdCByaWdodCBhd2F5IGNvbnNlY3V0aXZlbHkuXG4gICAgY29uc3QgaXNUYWJzQWN0aW9uID0gdGhpcy50YWJzQWN0aW9ucy5zb21lKGFjdGlvbiA9PlxuICAgICAgKGFjdGlvbi5uYXRpdmVFbGVtZW50IGFzIEhUTUxFbGVtZW50KS5jb250YWlucyhldmVudC50YXJnZXQgYXMgSFRNTEVsZW1lbnQpXG4gICAgKTtcbiAgICBpZiAoXG4gICAgICBldmVudC50YXJnZXQgPT09IHRhYk92ZXJmbG93VHJpZ2dlciB8fFxuICAgICAgdGFiT3ZlcmZsb3dUcmlnZ2VyLmNvbnRhaW5zKGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudCkgfHxcbiAgICAgIGlzVGFic0FjdGlvblxuICAgICkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIE1vdmUgY3VycmVudCB0byB0aGUgbGFzdCB2aXNpYmxlIGZvY3VzYWJsZSBpdGVtXG4gICAgaWYgKCF0aGlzLl90YWJPdmVyZmxvd0VsLmNvbnRhaW5zKGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudCkgJiYgdGhpcy5pc0N1cnJlbnRJbk92ZXJmbG93KSB7XG4gICAgICB0aGlzLmtleUZvY3VzLm1vdmVUbyh0aGlzLm92ZXJmbG93UG9zaXRpb24gLSAxKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHNldFRhYkxpbmtFbGVtZW50cygpIHtcbiAgICB0aGlzLl90YWJMaW5rRGlyZWN0aXZlcyA9IHRoaXMudGFicy5tYXAodGFiID0+IHRhYi50YWJMaW5rKTtcbiAgICB0aGlzLnRhYkxpbmtFbGVtZW50cyA9IHRoaXMuX3RhYkxpbmtEaXJlY3RpdmVzLm1hcCh0YWIgPT4gdGFiLmVsLm5hdGl2ZUVsZW1lbnQpO1xuICAgIGlmICh0aGlzLnRhYnNBY3Rpb25zICYmIHRoaXMudGFic0FjdGlvbnMpIHtcbiAgICAgIHRoaXMudGFiTGlua0VsZW1lbnRzLnB1c2goLi4udGhpcy50YWJzQWN0aW9ucy5tYXAoYWN0aW9uID0+IGFjdGlvbi5uYXRpdmVFbGVtZW50KSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBsaXN0ZW5Gb3JUYWJMaW5rQ2hhbmdlcygpIHtcbiAgICByZXR1cm4gdGhpcy50YWJzLmNoYW5nZXNcbiAgICAgIC5waXBlKHN0YXJ0V2l0aCh0aGlzLnRhYnMubWFwKHRhYiA9PiB0YWIudGFiTGluaykpKVxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB0aGlzLnNldFRhYkxpbmtFbGVtZW50cygpKTtcbiAgfVxuXG4gIHByaXZhdGUgbGlzdGVkRm9yVGFic0FjdGlvbnNDaGFuZ2VzKCkge1xuICAgIHJldHVybiB0aGlzLnRhYnNBY3Rpb25zLmNoYW5nZXMuc3Vic2NyaWJlKCgpID0+IHRoaXMuc2V0VGFiTGlua0VsZW1lbnRzKCkpO1xuICB9XG59XG4iXX0=