gentics-ui-core
Version:
This is the common core framework for the Gentics CMS and Mesh UI, and other Angular applications.
249 lines • 39 kB
JavaScript
import { Component, ContentChildren, QueryList, Input, Output, EventEmitter, ElementRef } from '@angular/core';
import { TabPane } from './tab-pane.component';
import { TabGroup } from './tab-group.component';
import { combineLatest, Subscription, BehaviorSubject, ObjectUnsubscribedError } from 'rxjs';
import { debounceTime, switchMap, startWith } from 'rxjs/operators';
import { coerceToBoolean } from '../../common/coerce-to-boolean';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
import * as i2 from "../icon/icon.directive";
let uniqueGroupedTabsId = 0;
/**
* GroupedTabs supports tabs either with and without groups.
*
* Pure tabs will only change the active tab when the `activeId` property is updated.
*
* ## Tabs with simple labels
* ```html
* <gtx-grouped-tabs>
* <gtx-tab-pane label="First without Group">Content 1</gtx-tab-pane>
* <gtx-tab-group label="1st Group name" expanded="true">
* <gtx-tab-pane label="First">Content 2</gtx-tab-pane>
* <gtx-tab-pane label="Second">Content 3</gtx-tab-pane>
* </gtx-tab-group>
* <gtx-tab-group label="2nd Group name">
* <gtx-tab-pane label="First">Content 4</gtx-tab-pane>
* <gtx-tab-pane label="Second">Content 5</gtx-tab-pane>
* </gtx-tab-group>
* </gtx-grouped-tabs>
* ```
*
* ## Tabs with template labels
* ```html
* <gtx-grouped-tabs>
* <gtx-tab-pane>
* <ng-template gtx-tab-label>First without Group</ng-template>
* Implicit Content 1
* </gtx-tab-pane>
* <gtx-tab-group expanded="true">
* <ng-template gtx-tab-label>
* <icon>add</icon> 1st Group name
* </ng-template>
* <gtx-tab-pane>
* <ng-template gtx-tab-label>First</ng-template>
* <ng-template gtx-tab-content>
* Content 2
* </ng-template>
* </gtx-tab-pane>
* <gtx-tab-pane label="Second">Content 3</gtx-tab-pane>
* </gtx-tab-group>
* <gtx-tab-group label="2nd Group name">
* <gtx-tab-pane label="First">Content 4</gtx-tab-pane>
* <gtx-tab-pane label="Second">Content 5</gtx-tab-pane>
* </gtx-tab-group>
* </gtx-grouped-tabs>
* ```
*
* ## Export components to use in templates
* ```html
* <gtx-grouped-tabs #groupedTabs="gtxGroupedTabs">
* <gtx-tab-pane label="First" #tab1>First content</gtx-tab-pane>
* <gtx-tab-pane label="Second">
* Seconds content
* <gtx-button (click)="groupedTabs.selectTab(tab1)">Switch to Tab 1</gtx-button>
* </gtx-tab-pane>
* </gtx-grouped-tabs>
* ```
*
*/
export class GroupedTabs {
constructor(elementRef) {
this.elementRef = elementRef;
/** Unique id for this input. */
this.uniqueId = `gtx-grouped-tabs-${uniqueGroupedTabsId++}`;
this.tabs$ = new BehaviorSubject(null);
/**
* Fires an event whenever the active tab changes. Argument is the id of the selected tab.
*/
this.tabChange = new EventEmitter();
this.tabsShouldWrap = false;
this.displayStatusIcons = false;
this.isPure = false;
this.subscriptions = new Subscription();
}
set id(val) {
this.uniqueId = val;
}
get id() { return this.uniqueId; }
/**
* When present, sets the tabs to pure (stateless) mode.
*/
set pure(val) {
this.isPure = val != null;
}
/**
* When present (or set to true), tabs title will wrap onto a new line. Otherwise, tabs will remain on one line
* and the contents will be elided if all the available space is filled.
*/
set wrap(val) {
this.tabsShouldWrap = coerceToBoolean(val);
}
set statusIcons(val) {
this.displayStatusIcons = coerceToBoolean(val);
}
get currentTab() { return this.tabPanes.filter(tab => tab.active === true)[0]; }
isTabGroup(item) { return item.expand !== undefined; }
collectTabs() {
let tabs = Array();
// Collect all the available tabs and groups
this.tabPanes.map(item => {
const tabGroup = this.tabGroups.find(group => group.tabs.some(tab => tab === item));
if (tabGroup !== undefined) {
if (tabs.indexOf(tabGroup) === -1) {
tabs.push(tabGroup);
}
}
else {
tabs.push(item);
}
});
// Activates the first tab if there are no active currently
this.preActivateTab();
this.tabs$.next(tabs);
}
preActivateTab() {
if (this.isPure) {
setTimeout(() => this.setActiveTab());
}
else {
let activeTabs = this.tabPanes.filter(tab => tab.active);
// if there is no active tab set, activate the first
if (activeTabs.length === 0) {
this.tabPanes.first.active = true;
}
}
}
ngAfterContentInit() {
const tabChanges = combineLatest(this.tabPanes.changes, this.tabGroups.changes).pipe(switchMap(([tabPanes, tabGroups]) => {
let allChanges = [
tabPanes.changes.pipe(startWith(tabPanes)),
tabGroups.changes.pipe(startWith(tabGroups))
];
tabGroups.map((group) => {
try {
group.tabs.notifyOnChanges();
allChanges.push(group.tabs.changes.pipe(startWith(group.tabs)));
}
catch (e) {
if (e instanceof ObjectUnsubscribedError) {
// To prevent Unsubscribe error
}
else {
throw e;
}
}
});
return combineLatest(allChanges);
}), debounceTime(5));
this.subscriptions.add(tabChanges.subscribe(() => {
this.collectTabs();
}));
this.tabPanes.notifyOnChanges();
this.tabGroups.notifyOnChanges();
this.collectTabs();
}
ngOnChanges(changes) {
this.setActiveTab();
}
ngOnDestroy() {
this.subscriptions.unsubscribe();
}
/**
* Sets the tab with id === this.activeId to active.
*/
setActiveTab() {
if (this.tabPanes) {
let tabToActivate = this.tabPanes.filter(t => t.id === this.activeId)[0];
if (tabToActivate) {
this.setAsActive(tabToActivate);
}
}
}
/**
* Invoked when a tab link is clicked.
*/
selectTab(tab) {
if (tab.stateDisabled) {
return;
}
if (!this.isPure) {
this.setAsActive(tab);
this.tabChange.emit(tab.id);
}
else {
tab.select.emit(tab.id);
}
}
/**
* Toggle TabGroup open/close state.
*/
toggleGroup(group) {
group.toggle();
}
/**
* Calculates TabGroup body height to to make it correctly animateable.
*/
tabsHeight(group) {
if (group.expand) {
let body = this.elementRef.nativeElement.querySelector(`li#${group.uniqueId} div.collapsible-body > ul`);
if (body) {
return body.getBoundingClientRect().height + 30;
}
}
return 0;
}
setAsActive(tab) {
this.tabPanes.toArray().forEach(tab => tab.active = false);
this.tabGroups.map(group => {
if (group.tabs.some(currentTab => currentTab === tab)) {
group.expand = true;
}
});
tab.active = true;
}
}
/** @nocollapse */ GroupedTabs.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: GroupedTabs, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ GroupedTabs.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: GroupedTabs, selector: "gtx-grouped-tabs", inputs: { activeId: "activeId", id: "id", pure: "pure", wrap: "wrap", statusIcons: "statusIcons" }, outputs: { tabChange: "tabChange" }, queries: [{ propertyName: "tabPanes", predicate: TabPane, descendants: true }, { propertyName: "tabGroups", predicate: TabGroup }], exportAs: ["gtxGroupedTabs"], usesOnChanges: true, ngImport: i0, template: "<div class=\"grouped-tabs\">\n <ul class=\"collapsible expandable\" [class.wrap-tab-title]=\"tabsShouldWrap\">\n <ng-container *ngFor=\"let tabItem of tabs$ | async\">\n <ng-template [ngIf]=\"isTabGroup(tabItem)\" [ngIfElse]=\"standaloneTabItem\">\n <li class=\"tab-group\" [id]=\"tabItem.id\" [ngClass]=\"{\n expanded: tabItem.expand,\n 'is-active': tabItem.hasActiveChild\n }\">\n <div class=\"collapsible-header\" (click)=\"toggleGroup(tabItem)\">\n <ng-container *ngTemplateOutlet=\"labelTemplate;context:{tabItem: tabItem}\"></ng-container>\n </div>\n <div class=\"collapsible-body\" [style.max-height.px]=\"tabsHeight(tabItem)\">\n <ul class=\"tab-links\" *ngIf=\"tabItem.tabs.length > 0\">\n <ng-container *ngFor=\"let tab of tabItem.tabs\">\n <ng-container *ngTemplateOutlet=\"tabItemTemplate;context:{tabItem: tab}\"></ng-container>\n </ng-container>\n </ul>\n </div>\n </li>\n </ng-template>\n <ng-template #standaloneTabItem>\n <ng-container *ngTemplateOutlet=\"tabItemTemplate;context:{tabItem: tabItem}\">\n </ng-container>\n </ng-template>\n </ng-container>\n </ul>\n</div>\n<div class=\"grouped-tab-content\">\n <ng-container *ngTemplateOutlet=\"currentTab?.content\"></ng-container>\n</div>\n<div class=\"clearfix\"></div>\n\n<ng-template #labelTemplate let-tabItem=\"tabItem\">\n <ng-template [ngIf]=\"tabItem?.expand === true\">\n <icon left>keyboard_arrow_down</icon>\n </ng-template>\n <ng-template [ngIf]=\"tabItem?.expand === false\">\n <icon left>keyboard_arrow_right</icon>\n </ng-template>\n <!-- If there is a label template, use it. -->\n <ng-template [ngIf]=\"tabItem.templateLabel\">\n <ng-container *ngTemplateOutlet=\"tabItem.templateLabel\"></ng-container>\n </ng-template>\n <!-- If there is not a label template, fall back to the text label. -->\n <ng-template [ngIf]=\"!tabItem.templateLabel\">{{ tabItem.textLabel }}</ng-template>\n</ng-template>\n\n<ng-template #tabItemTemplate let-tabItem=\"tabItem\">\n <li class=\"tab-link\" role=\"presentation\"\n (click)=\"selectTab(tabItem)\"\n [ngClass]=\"{\n disabled: tabItem.stateDisabled,\n 'is-active': tabItem.active,\n 'readonly': tabItem.stateReadOnly,\n 'inactive': tabItem.stateInactive,\n 'statusIcon': !tabItem.disabled && displayStatusIcons && tabItem.displayStatusIcon\n }\">\n <i *ngIf=\"!tabItem.stateDisabled && displayStatusIcons && tabItem.displayStatusIcon\" class=\"statusIcon\"></i>\n <a role=\"tab\">\n <ng-container *ngTemplateOutlet=\"labelTemplate;context:{tabItem: tabItem}\"></ng-container>\n </a>\n </li>\n</ng-template>\n", directives: [{ type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2.Icon, selector: "icon" }], pipes: { "async": i1.AsyncPipe } });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: GroupedTabs, decorators: [{
type: Component,
args: [{ selector: 'gtx-grouped-tabs', exportAs: 'gtxGroupedTabs', template: "<div class=\"grouped-tabs\">\n <ul class=\"collapsible expandable\" [class.wrap-tab-title]=\"tabsShouldWrap\">\n <ng-container *ngFor=\"let tabItem of tabs$ | async\">\n <ng-template [ngIf]=\"isTabGroup(tabItem)\" [ngIfElse]=\"standaloneTabItem\">\n <li class=\"tab-group\" [id]=\"tabItem.id\" [ngClass]=\"{\n expanded: tabItem.expand,\n 'is-active': tabItem.hasActiveChild\n }\">\n <div class=\"collapsible-header\" (click)=\"toggleGroup(tabItem)\">\n <ng-container *ngTemplateOutlet=\"labelTemplate;context:{tabItem: tabItem}\"></ng-container>\n </div>\n <div class=\"collapsible-body\" [style.max-height.px]=\"tabsHeight(tabItem)\">\n <ul class=\"tab-links\" *ngIf=\"tabItem.tabs.length > 0\">\n <ng-container *ngFor=\"let tab of tabItem.tabs\">\n <ng-container *ngTemplateOutlet=\"tabItemTemplate;context:{tabItem: tab}\"></ng-container>\n </ng-container>\n </ul>\n </div>\n </li>\n </ng-template>\n <ng-template #standaloneTabItem>\n <ng-container *ngTemplateOutlet=\"tabItemTemplate;context:{tabItem: tabItem}\">\n </ng-container>\n </ng-template>\n </ng-container>\n </ul>\n</div>\n<div class=\"grouped-tab-content\">\n <ng-container *ngTemplateOutlet=\"currentTab?.content\"></ng-container>\n</div>\n<div class=\"clearfix\"></div>\n\n<ng-template #labelTemplate let-tabItem=\"tabItem\">\n <ng-template [ngIf]=\"tabItem?.expand === true\">\n <icon left>keyboard_arrow_down</icon>\n </ng-template>\n <ng-template [ngIf]=\"tabItem?.expand === false\">\n <icon left>keyboard_arrow_right</icon>\n </ng-template>\n <!-- If there is a label template, use it. -->\n <ng-template [ngIf]=\"tabItem.templateLabel\">\n <ng-container *ngTemplateOutlet=\"tabItem.templateLabel\"></ng-container>\n </ng-template>\n <!-- If there is not a label template, fall back to the text label. -->\n <ng-template [ngIf]=\"!tabItem.templateLabel\">{{ tabItem.textLabel }}</ng-template>\n</ng-template>\n\n<ng-template #tabItemTemplate let-tabItem=\"tabItem\">\n <li class=\"tab-link\" role=\"presentation\"\n (click)=\"selectTab(tabItem)\"\n [ngClass]=\"{\n disabled: tabItem.stateDisabled,\n 'is-active': tabItem.active,\n 'readonly': tabItem.stateReadOnly,\n 'inactive': tabItem.stateInactive,\n 'statusIcon': !tabItem.disabled && displayStatusIcons && tabItem.displayStatusIcon\n }\">\n <i *ngIf=\"!tabItem.stateDisabled && displayStatusIcons && tabItem.displayStatusIcon\" class=\"statusIcon\"></i>\n <a role=\"tab\">\n <ng-container *ngTemplateOutlet=\"labelTemplate;context:{tabItem: tabItem}\"></ng-container>\n </a>\n </li>\n</ng-template>\n" }]
}], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { tabPanes: [{
type: ContentChildren,
args: [TabPane, { descendants: true }]
}], tabGroups: [{
type: ContentChildren,
args: [TabGroup]
}], tabChange: [{
type: Output
}], activeId: [{
type: Input
}], id: [{
type: Input
}], pure: [{
type: Input
}], wrap: [{
type: Input
}], statusIcons: [{
type: Input
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JvdXBlZC10YWJzLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL2dyb3VwZWQtdGFicy9ncm91cGVkLXRhYnMuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvZ3JvdXBlZC10YWJzL2dyb3VwZWQtdGFicy50cGwuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLGVBQWUsRUFBRSxTQUFTLEVBQW9CLEtBQUssRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFpQixVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDaEosT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUNqRCxPQUFPLEVBQUUsYUFBYSxFQUFFLFlBQVksRUFBRSxlQUFlLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDN0YsT0FBTyxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFTLE1BQU0sZ0JBQWdCLENBQUM7QUFDM0UsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDOzs7O0FBRWpFLElBQUksbUJBQW1CLEdBQUcsQ0FBQyxDQUFDO0FBRTVCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F5REc7QUFNSCxNQUFNLE9BQU8sV0FBVztJQXVEcEIsWUFBb0IsVUFBc0I7UUFBdEIsZUFBVSxHQUFWLFVBQVUsQ0FBWTtRQXJEMUMsZ0NBQWdDO1FBQ3hCLGFBQVEsR0FBRyxvQkFBb0IsbUJBQW1CLEVBQUUsRUFBRSxDQUFDO1FBRS9ELFVBQUssR0FBRyxJQUFJLGVBQWUsQ0FBMEIsSUFBSSxDQUFDLENBQUM7UUFRM0Q7O1dBRUc7UUFDTyxjQUFT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b25lbnQsIENvbnRlbnRDaGlsZHJlbiwgUXVlcnlMaXN0LCBBZnRlckNvbnRlbnRJbml0LCBJbnB1dCwgT3V0cHV0LCBFdmVudEVtaXR0ZXIsIFNpbXBsZUNoYW5nZXMsIEVsZW1lbnRSZWYgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFRhYlBhbmUgfSBmcm9tICcuL3RhYi1wYW5lLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBUYWJHcm91cCB9IGZyb20gJy4vdGFiLWdyb3VwLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBjb21iaW5lTGF0ZXN0LCBTdWJzY3JpcHRpb24sIEJlaGF2aW9yU3ViamVjdCwgT2JqZWN0VW5zdWJzY3JpYmVkRXJyb3IgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGRlYm91bmNlVGltZSwgc3dpdGNoTWFwLCBzdGFydFdpdGgsIGRlbGF5IH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgY29lcmNlVG9Cb29sZWFuIH0gZnJvbSAnLi4vLi4vY29tbW9uL2NvZXJjZS10by1ib29sZWFuJztcblxubGV0IHVuaXF1ZUdyb3VwZWRUYWJzSWQgPSAwO1xuXG4vKipcbiAqIEdyb3VwZWRUYWJzIHN1cHBvcnRzIHRhYnMgZWl0aGVyIHdpdGggYW5kIHdpdGhvdXQgZ3JvdXBzLlxuICpcbiAqIFB1cmUgdGFicyB3aWxsIG9ubHkgY2hhbmdlIHRoZSBhY3RpdmUgdGFiIHdoZW4gdGhlIGBhY3RpdmVJZGAgcHJvcGVydHkgaXMgdXBkYXRlZC5cbiAqXG4gKiAjIyBUYWJzIHdpdGggc2ltcGxlIGxhYmVsc1xuICogYGBgaHRtbFxuICogPGd0eC1ncm91cGVkLXRhYnM+XG4gKiAgICAgIDxndHgtdGFiLXBhbmUgbGFiZWw9XCJGaXJzdCB3aXRob3V0IEdyb3VwXCI+Q29udGVudCAxPC9ndHgtdGFiLXBhbmU+XG4gKiAgICAgIDxndHgtdGFiLWdyb3VwIGxhYmVsPVwiMXN0IEdyb3VwIG5hbWVcIiBleHBhbmRlZD1cInRydWVcIj5cbiAqICAgICAgICAgIDxndHgtdGFiLXBhbmUgbGFiZWw9XCJGaXJzdFwiPkNvbnRlbnQgMjwvZ3R4LXRhYi1wYW5lPlxuICogICAgICAgICAgPGd0eC10YWItcGFuZSBsYWJlbD1cIlNlY29uZFwiPkNvbnRlbnQgMzwvZ3R4LXRhYi1wYW5lPlxuICogICAgICA8L2d0eC10YWItZ3JvdXA+XG4gKiAgICAgIDxndHgtdGFiLWdyb3VwIGxhYmVsPVwiMm5kIEdyb3VwIG5hbWVcIj5cbiAqICAgICAgICAgIDxndHgtdGFiLXBhbmUgbGFiZWw9XCJGaXJzdFwiPkNvbnRlbnQgNDwvZ3R4LXRhYi1wYW5lPlxuICogICAgICAgICAgPGd0eC10YWItcGFuZSBsYWJlbD1cIlNlY29uZFwiPkNvbnRlbnQgNTwvZ3R4LXRhYi1wYW5lPlxuICogICAgICA8L2d0eC10YWItZ3JvdXA+XG4gKiA8L2d0eC1ncm91cGVkLXRhYnM+XG4gKiBgYGBcbiAqXG4gKiAjIyBUYWJzIHdpdGggdGVtcGxhdGUgbGFiZWxzXG4gKiBgYGBodG1sXG4gKiA8Z3R4LWdyb3VwZWQtdGFicz5cbiAqICAgICAgPGd0eC10YWItcGFuZT5cbiAqICAgICAgICAgIDxuZy10ZW1wbGF0ZSBndHgtdGFiLWxhYmVsPkZpcnN0IHdpdGhvdXQgR3JvdXA8L25nLXRlbXBsYXRlPlxuICogICAgICAgICAgSW1wbGljaXQgQ29udGVudCAxXG4gKiAgICAgIDwvZ3R4LXRhYi1wYW5lPlxuICogICAgICA8Z3R4LXRhYi1ncm91cCBleHBhbmRlZD1cInRydWVcIj5cbiAqICAgICAgICAgIDxuZy10ZW1wbGF0ZSBndHgtdGFiLWxhYmVsPlxuICogICAgICAgICAgICAgIDxpY29uPmFkZDwvaWNvbj4gMXN0IEdyb3VwIG5hbWVcbiAqICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gKiAgICAgICAgICA8Z3R4LXRhYi1wYW5lPlxuICogICAgICAgICAgICAgIDxuZy10ZW1wbGF0ZSBndHgtdGFiLWxhYmVsPkZpcnN0PC9uZy10ZW1wbGF0ZT5cbiAqICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgZ3R4LXRhYi1jb250ZW50PlxuICogICAgICAgICAgICAgICAgICBDb250ZW50IDJcbiAqICAgICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICogICAgICAgICAgPC9ndHgtdGFiLXBhbmU+XG4gKiAgICAgICAgICA8Z3R4LXRhYi1wYW5lIGxhYmVsPVwiU2Vjb25kXCI+Q29udGVudCAzPC9ndHgtdGFiLXBhbmU+XG4gKiAgICAgIDwvZ3R4LXRhYi1ncm91cD5cbiAqICAgICAgPGd0eC10YWItZ3JvdXAgbGFiZWw9XCIybmQgR3JvdXAgbmFtZVwiPlxuICogICAgICAgICAgPGd0eC10YWItcGFuZSBsYWJlbD1cIkZpcnN0XCI+Q29udGVudCA0PC9ndHgtdGFiLXBhbmU+XG4gKiAgICAgICAgICA8Z3R4LXRhYi1wYW5lIGxhYmVsPVwiU2Vjb25kXCI+Q29udGVudCA1PC9ndHgtdGFiLXBhbmU+XG4gKiAgICAgIDwvZ3R4LXRhYi1ncm91cD5cbiAqIDwvZ3R4LWdyb3VwZWQtdGFicz5cbiAqIGBgYFxuICpcbiAqICMjIEV4cG9ydCBjb21wb25lbnRzIHRvIHVzZSBpbiB0ZW1wbGF0ZXNcbiAqIGBgYGh0bWxcbiAqIDxndHgtZ3JvdXBlZC10YWJzICNncm91cGVkVGFicz1cImd0eEdyb3VwZWRUYWJzXCI+XG4gKiAgICAgIDxndHgtdGFiLXBhbmUgbGFiZWw9XCJGaXJzdFwiICN0YWIxPkZpcnN0IGNvbnRlbnQ8L2d0eC10YWItcGFuZT5cbiAqICAgICAgPGd0eC10YWItcGFuZSBsYWJlbD1cIlNlY29uZFwiPlxuICogICAgICAgICAgU2Vjb25kcyBjb250ZW50XG4gKiAgICAgICAgICA8Z3R4LWJ1dHRvbiAoY2xpY2spPVwiZ3JvdXBlZFRhYnMuc2VsZWN0VGFiKHRhYjEpXCI+U3dpdGNoIHRvIFRhYiAxPC9ndHgtYnV0dG9uPlxuICogICAgICA8L2d0eC10YWItcGFuZT5cbiAqIDwvZ3R4LWdyb3VwZWQtdGFicz5cbiAqIGBgYFxuICpcbiAqL1xuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICdndHgtZ3JvdXBlZC10YWJzJyxcbiAgICBleHBvcnRBczogJ2d0eEdyb3VwZWRUYWJzJyxcbiAgICB0ZW1wbGF0ZVVybDogJy4vZ3JvdXBlZC10YWJzLnRwbC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBHcm91cGVkVGFicyBpbXBsZW1lbnRzIEFmdGVyQ29udGVudEluaXQge1xuXG4gICAgLyoqIFVuaXF1ZSBpZCBmb3IgdGhpcyBpbnB1dC4gKi9cbiAgICBwcml2YXRlIHVuaXF1ZUlkID0gYGd0eC1ncm91cGVkLXRhYnMtJHt1bmlxdWVHcm91cGVkVGFic0lkKyt9YDtcblxuICAgIHRhYnMkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxBcnJheTxUYWJQYW5lfFRhYkdyb3VwPj4obnVsbCk7XG5cbiAgICAvKiogQWxsIG9mIHRoZSBkZWZpbmVkIHRhYiBwYW5lcy4gKi9cbiAgICBAQ29udGVudENoaWxkcmVuKFRhYlBhbmUsIHsgZGVzY2VuZGFudHM6IHRydWUgfSkgdGFiUGFuZXM6IFF1ZXJ5TGlzdDxUYWJQYW5lPjtcblxuICAgIC8qKiBBbGwgb2YgdGhlIGRlZmluZWQgZ3JvdXBzIG9mIHRhYiBwYW5lcy4gKi9cbiAgICBAQ29udGVudENoaWxkcmVuKFRhYkdyb3VwKSB0YWJHcm91cHM6IFF1ZXJ5TGlzdDxUYWJHcm91cD47XG5cbiAgICAvKipcbiAgICAgKiBGaXJlcyBhbiBldmVudCB3aGVuZXZlciB0aGUgYWN0aXZlIHRhYiBjaGFuZ2VzLiBBcmd1bWVudCBpcyB0aGUgaWQgb2YgdGhlIHNlbGVjdGVkIHRhYi5cbiAgICAgKi9cbiAgICBAT3V0cHV0KCkgdGFiQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxzdHJpbmc+KCk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgaWQgb2YgdGhlIGFjdGl2ZSB0YWIuIFNob3VsZCBvbmx5IGJlIHVzZWQgaW4gcHVyZSAoc3RhdGVsZXNzKSBtb2RlLlxuICAgICAqL1xuICAgIEBJbnB1dCgpIGFjdGl2ZUlkOiBzdHJpbmc7XG5cbiAgICBASW5wdXQoKSBzZXQgaWQodmFsOiBzdHJpbmcpIHtcbiAgICAgICAgdGhpcy51bmlxdWVJZCA9IHZhbDtcbiAgICB9XG5cbiAgICBnZXQgaWQoKTogc3RyaW5nIHsgcmV0dXJuIHRoaXMudW5pcXVlSWQ7IH1cblxuICAgIC8qKlxuICAgICAqIFdoZW4gcHJlc2VudCwgc2V0cyB0aGUgdGFicyB0byBwdXJlIChzdGF0ZWxlc3MpIG1vZGUuXG4gICAgICovXG4gICAgQElucHV0KCkgc2V0IHB1cmUodmFsOiBhbnkpIHtcbiAgICAgICAgdGhpcy5pc1B1cmUgPSB2YWwgIT0gbnVsbDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBXaGVuIHByZXNlbnQgKG9yIHNldCB0byB0cnVlKSwgdGFicyB0aXRsZSB3aWxsIHdyYXAgb250byBhIG5ldyBsaW5lLiBPdGhlcndpc2UsIHRhYnMgd2lsbCByZW1haW4gb24gb25lIGxpbmVcbiAgICAgKiBhbmQgdGhlIGNvbnRlbnRzIHdpbGwgYmUgZWxpZGVkIGlmIGFsbCB0aGUgYXZhaWxhYmxlIHNwYWNlIGlzIGZpbGxlZC5cbiAgICAgKi9cbiAgICBASW5wdXQoKSBzZXQgd3JhcCh2YWw6IGFueSkge1xuICAgICAgICB0aGlzLnRhYnNTaG91bGRXcmFwID0gY29lcmNlVG9Cb29sZWFuKHZhbCk7XG4gICAgfVxuXG4gICAgQElucHV0KCkgc2V0IHN0YXR1c0ljb25zKHZhbDogYW55KSB7XG4gICAgICAgIHRoaXMuZGlzcGxheVN0YXR1c0ljb25zID0gY29lcmNlVG9Cb29sZWFuKHZhbCk7XG4gICAgfVxuXG4gICAgZ2V0IGN1cnJlbnRUYWIoKTogVGFiUGFuZSB7IHJldHVybiB0aGlzLnRhYlBhbmVzLmZpbHRlcih0YWIgPT4gdGFiLmFjdGl2ZSA9PT0gdHJ1ZSlbMF07IH1cblxuICAgIHRhYnNTaG91bGRXcmFwOiBib29sZWFuID0gZmFsc2U7XG4gICAgZGlzcGxheVN0YXR1c0ljb25zOiBib29sZWFuID0gZmFsc2U7XG4gICAgcHJpdmF0ZSBpc1B1cmU6IGJvb2xlYW4gPSBmYWxzZTtcbiAgICBwcml2YXRlIHN1YnNjcmlwdGlvbnMgPSBuZXcgU3Vic2NyaXB0aW9uKCk7XG5cbiAgICBjb25zdHJ1Y3Rvcihwcml2YXRlIGVsZW1lbnRSZWY6IEVsZW1lbnRSZWYpIHt9XG5cbiAgICBpc1RhYkdyb3VwKGl0ZW0pIHsgcmV0dXJuIGl0ZW0uZXhwYW5kICE9PSB1bmRlZmluZWQ7IH1cblxuICAgIGNvbGxlY3RUYWJzKCk6IHZvaWQge1xuICAgICAgICBsZXQgdGFicyA9IEFycmF5PFRhYlBhbmV8VGFiR3JvdXA+KCk7XG5cbiAgICAgICAgLy8gQ29sbGVjdCBhbGwgdGhlIGF2YWlsYWJsZSB0YWJzIGFuZCBncm91cHNcbiAgICAgICAgdGhpcy50YWJQYW5lcy5tYXAoaXRlbSA9PiB7XG4gICAgICAgICAgICBjb25zdCB0YWJHcm91cCA9IHRoaXMudGFiR3JvdXBzLmZpbmQoZ3JvdXAgPT4gZ3JvdXAudGFicy5zb21lKHRhYiA9PiB0YWIgPT09IGl0ZW0pKTtcbiAgICAgICAgICAgIGlmICh0YWJHcm91cCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRhYnMuaW5kZXhPZih0YWJHcm91cCkgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHRhYnMucHVzaCh0YWJHcm91cCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0YWJzLnB1c2goaXRlbSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEFjdGl2YXRlcyB0aGUgZmlyc3QgdGFiIGlmIHRoZXJlIGFyZSBubyBhY3RpdmUgY3VycmVudGx5XG4gICAgICAgIHRoaXMucHJlQWN0aXZhdGVUYWIoKTtcbiAgICAgICAgdGhpcy50YWJzJC5uZXh0KHRhYnMpO1xuICAgIH1cblxuICAgIHByZUFjdGl2YXRlVGFiKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5pc1B1cmUpIHtcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy5zZXRBY3RpdmVUYWIoKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsZXQgYWN0aXZlVGFicyA9IHRoaXMudGFiUGFuZXMuZmlsdGVyKHRhYiA9PiB0YWIuYWN0aXZlKTtcblxuICAgICAgICAgICAgLy8gaWYgdGhlcmUgaXMgbm8gYWN0aXZlIHRhYiBzZXQsIGFjdGl2YXRlIHRoZSBmaXJzdFxuICAgICAgICAgICAgaWYgKGFjdGl2ZVRhYnMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgdGhpcy50YWJQYW5lcy5maXJzdC5hY3RpdmUgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgbmdBZnRlckNvbnRlbnRJbml0KCk6IHZvaWQge1xuICAgICAgICBjb25zdCB0YWJDaGFuZ2VzID0gY29tYmluZUxhdGVzdChcbiAgICAgICAgICAgIHRoaXMudGFiUGFuZXMuY2hhbmdlcyxcbiAgICAgICAgICAgIHRoaXMudGFiR3JvdXBzLmNoYW5nZXNcbiAgICAgICAgKS5waXBlKHN3aXRjaE1hcCgoW3RhYlBhbmVzLCB0YWJHcm91cHNdOiBbUXVlcnlMaXN0PFRhYlBhbmU+LCBRdWVyeUxpc3Q8VGFiR3JvdXA+XSkgID0+IHtcbiAgICAgICAgICAgIGxldCBhbGxDaGFuZ2VzID0gW1xuICAgICAgICAgICAgICAgIHRhYlBhbmVzLmNoYW5nZXMucGlwZShzdGFydFdpdGgodGFiUGFuZXMpKSxcbiAgICAgICAgICAgICAgICB0YWJHcm91cHMuY2hhbmdlcy5waXBlKHN0YXJ0V2l0aCh0YWJHcm91cHMpKVxuICAgICAgICAgICAgXTtcblxuICAgICAgICAgICAgdGFiR3JvdXBzLm1hcCgoZ3JvdXApID0+IHtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBncm91cC50YWJzLm5vdGlmeU9uQ2hhbmdlcygpO1xuICAgICAgICAgICAgICAgICAgICBhbGxDaGFuZ2VzLnB1c2goZ3JvdXAudGFicy5jaGFuZ2VzLnBpcGUoc3RhcnRXaXRoKGdyb3VwLnRhYnMpKSk7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZSBpbnN0YW5jZW9mIE9iamVjdFVuc3Vic2NyaWJlZEVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBUbyBwcmV2ZW50IFVuc3Vic2NyaWJlIGVycm9yXG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiBjb21iaW5lTGF0ZXN0KGFsbENoYW5nZXMpO1xuICAgICAgICB9KSxcbiAgICAgICAgZGVib3VuY2VUaW1lKDUpKTtcblxuICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbnMuYWRkKHRhYkNoYW5nZXMuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuY29sbGVjdFRhYnMoKTtcbiAgICAgICAgfSkpO1xuXG4gICAgICAgIHRoaXMudGFiUGFuZXMubm90aWZ5T25DaGFuZ2VzKCk7XG4gICAgICAgIHRoaXMudGFiR3JvdXBzLm5vdGlmeU9uQ2hhbmdlcygpO1xuICAgICAgICB0aGlzLmNvbGxlY3RUYWJzKCk7XG4gICAgfVxuXG4gICAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgICAgICB0aGlzLnNldEFjdGl2ZVRhYigpO1xuICAgIH1cblxuICAgIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbnMudW5zdWJzY3JpYmUoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSB0YWIgd2l0aCBpZCA9PT0gdGhpcy5hY3RpdmVJZCB0byBhY3RpdmUuXG4gICAgICovXG4gICAgc2V0QWN0aXZlVGFiKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy50YWJQYW5lcykge1xuICAgICAgICAgICAgbGV0IHRhYlRvQWN0aXZhdGUgPSB0aGlzLnRhYlBhbmVzLmZpbHRlcih0ID0+IHQuaWQgPT09IHRoaXMuYWN0aXZlSWQpWzBdO1xuICAgICAgICAgICAgaWYgKHRhYlRvQWN0aXZhdGUpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldEFzQWN0aXZlKHRhYlRvQWN0aXZhdGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSW52b2tlZCB3aGVuIGEgdGFiIGxpbmsgaXMgY2xpY2tlZC5cbiAgICAgKi9cbiAgICBzZWxlY3RUYWIodGFiOiBUYWJQYW5lKTogdm9pZCB7XG4gICAgICAgIGlmICh0YWIuc3RhdGVEaXNhYmxlZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmICghdGhpcy5pc1B1cmUpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0QXNBY3RpdmUodGFiKTtcbiAgICAgICAgICAgIHRoaXMudGFiQ2hhbmdlLmVtaXQodGFiLmlkKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRhYi5zZWxlY3QuZW1pdCh0YWIuaWQpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVG9nZ2xlIFRhYkdyb3VwIG9wZW4vY2xvc2Ugc3RhdGUuXG4gICAgICovXG4gICAgdG9nZ2xlR3JvdXAoZ3JvdXA6IFRhYkdyb3VwKTogdm9pZCB7XG4gICAgICAgIGdyb3VwLnRvZ2dsZSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENhbGN1bGF0ZXMgVGFiR3JvdXAgYm9keSBoZWlnaHQgdG8gdG8gbWFrZSBpdCBjb3JyZWN0bHkgYW5pbWF0ZWFibGUuXG4gICAgICovXG4gICAgdGFic0hlaWdodChncm91cDogVGFiR3JvdXApOiBudW1iZXIge1xuICAgICAgICBpZiAoZ3JvdXAuZXhwYW5kKSB7XG4gICAgICAgICAgICBsZXQgYm9keSA9IHRoaXMuZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50LnF1ZXJ5U2VsZWN0b3IoYGxpIyR7Z3JvdXAudW5pcXVlSWR9IGRpdi5jb2xsYXBzaWJsZS1ib2R5ID4gdWxgKTtcbiAgICAgICAgICAgIGlmIChib2R5KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGJvZHkuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuaGVpZ2h0ICsgMzA7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gMDtcbiAgICB9XG5cbiAgICBwcml2YXRlIHNldEFzQWN0aXZlKHRhYjogVGFiUGFuZSk6IHZvaWQge1xuICAgICAgICB0aGlzLnRhYlBhbmVzLnRvQXJyYXkoKS5mb3JFYWNoKHRhYiA9PiB0YWIuYWN0aXZlID0gZmFsc2UpO1xuICAgICAgICB0aGlzLnRhYkdyb3Vwcy5tYXAoZ3JvdXAgPT4ge1xuICAgICAgICAgICAgaWYgKGdyb3VwLnRhYnMuc29tZShjdXJyZW50VGFiID0+IGN1cnJlbnRUYWIgPT09IHRhYikpIHtcbiAgICAgICAgICAgICAgICBncm91cC5leHBhbmQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgdGFiLmFjdGl2ZSA9IHRydWU7XG4gICAgfVxufVxuIiwiPGRpdiBjbGFzcz1cImdyb3VwZWQtdGFic1wiPlxuICAgIDx1bCBjbGFzcz1cImNvbGxhcHNpYmxlIGV4cGFuZGFibGVcIiBbY2xhc3Mud3JhcC10YWItdGl0bGVdPVwidGFic1Nob3VsZFdyYXBcIj5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgdGFiSXRlbSBvZiB0YWJzJCB8IGFzeW5jXCI+XG4gICAgICAgICAgICA8bmctdGVtcGxhdGUgW25nSWZdPVwiaXNUYWJHcm91cCh0YWJJdGVtKVwiIFtuZ0lmRWxzZV09XCJzdGFuZGFsb25lVGFiSXRlbVwiPlxuICAgICAgICAgICAgICAgIDxsaSBjbGFzcz1cInRhYi1ncm91cFwiIFtpZF09XCJ0YWJJdGVtLmlkXCIgW25nQ2xhc3NdPVwie1xuICAgICAgICAgICAgICAgICAgICBleHBhbmRlZDogdGFiSXRlbS5leHBhbmQsXG4gICAgICAgICAgICAgICAgICAgICdpcy1hY3RpdmUnOiB0YWJJdGVtLmhhc0FjdGl2ZUNoaWxkXG4gICAgICAgICAgICAgICAgfVwiPlxuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sbGFwc2libGUtaGVhZGVyXCIgKGNsaWNrKT1cInRvZ2dsZUdyb3VwKHRhYkl0ZW0pXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwibGFiZWxUZW1wbGF0ZTtjb250ZXh0Ont0YWJJdGVtOiB0YWJJdGVtfVwiPjwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbGxhcHNpYmxlLWJvZHlcIiBbc3R5bGUubWF4LWhlaWdodC5weF09XCJ0YWJzSGVpZ2h0KHRhYkl0ZW0pXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICA8dWwgY2xhc3M9XCJ0YWItbGlua3NcIiAqbmdJZj1cInRhYkl0ZW0udGFicy5sZW5ndGggPiAwXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgdGFiIG9mIHRhYkl0ZW0udGFic1wiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwidGFiSXRlbVRlbXBsYXRlO2NvbnRleHQ6e3RhYkl0ZW06IHRhYn1cIj48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvdWw+XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDwvbGk+XG4gICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgICAgPG5nLXRlbXBsYXRlICNzdGFuZGFsb25lVGFiSXRlbT5cbiAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwidGFiSXRlbVRlbXBsYXRlO2NvbnRleHQ6e3RhYkl0ZW06IHRhYkl0ZW19XCI+XG4gICAgICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8L3VsPlxuPC9kaXY+XG48ZGl2IGNsYXNzPVwiZ3JvdXBlZC10YWItY29udGVudFwiPlxuICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJjdXJyZW50VGFiPy5jb250ZW50XCI+PC9uZy1jb250YWluZXI+XG48L2Rpdj5cbjxkaXYgY2xhc3M9XCJjbGVhcmZpeFwiPjwvZGl2PlxuXG48bmctdGVtcGxhdGUgI2xhYmVsVGVtcGxhdGUgbGV0LXRhYkl0ZW09XCJ0YWJJdGVtXCI+XG4gICAgPG5nLXRlbXBsYXRlIFtuZ0lmXT1cInRhYkl0ZW0/LmV4cGFuZCA9PT0gdHJ1ZVwiPlxuICAgICAgICA8aWNvbiBsZWZ0PmtleWJvYXJkX2Fycm93X2Rvd248L2ljb24+XG4gICAgPC9uZy10ZW1wbGF0ZT5cbiAgICA8bmctdGVtcGxhdGUgW25nSWZdPVwidGFiSXRlbT8uZXhwYW5kID09PSBmYWxzZVwiPlxuICAgICAgICA8aWNvbiBsZWZ0PmtleWJvYXJkX2Fycm93X3JpZ2h0PC9pY29uPlxuICAgIDwvbmctdGVtcGxhdGU+XG4gICAgPCEtLSBJZiB0aGVyZSBpcyBhIGxhYmVsIHRlbXBsYXRlLCB1c2UgaXQuIC0tPlxuICAgIDxuZy10ZW1wbGF0ZSBbbmdJZl09XCJ0YWJJdGVtLnRlbXBsYXRlTGFiZWxcIj5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cInRhYkl0ZW0udGVtcGxhdGVMYWJlbFwiPjwvbmctY29udGFpbmVyPlxuICAgIDwvbmctdGVtcGxhdGU+XG4gICAgPCEtLSBJZiB0aGVyZSBpcyBub3QgYSBsYWJlbCB0ZW1wbGF0ZSwgZmFsbCBiYWNrIHRvIHRoZSB0ZXh0IGxhYmVsLiAtLT5cbiAgICA8bmctdGVtcGxhdGUgW25nSWZdPVwiIXRhYkl0ZW0udGVtcGxhdGVMYWJlbFwiPnt7IHRhYkl0ZW0udGV4dExhYmVsIH19PC9uZy10ZW1wbGF0ZT5cbjwvbmctdGVtcGxhdGU+XG5cbjxuZy10ZW1wbGF0ZSAjdGFiSXRlbVRlbXBsYXRlIGxldC10YWJJdGVtPVwidGFiSXRlbVwiPlxuICAgIDxsaSBjbGFzcz1cInRhYi1saW5rXCIgcm9sZT1cInByZXNlbnRhdGlvblwiXG4gICAgICAgIChjbGljayk9XCJzZWxlY3RUYWIodGFiSXRlbSlcIlxuICAgICAgICBbbmdDbGFzc109XCJ7XG4gICAgICAgICAgICBkaXNhYmxlZDogdGFiSXRlbS5zdGF0ZURpc2FibGVkLFxuICAgICAgICAgICAgJ2lzLWFjdGl2ZSc6IHRhYkl0ZW0uYWN0aXZlLFxuICAgICAgICAgICAgJ3JlYWRvbmx5JzogdGFiSXRlbS5zdGF0ZVJlYWRPbmx5LFxuICAgICAgICAgICAgJ2luYWN0aXZlJzogdGFiSXRlbS5zdGF0ZUluYWN0aXZlLFxuICAgICAgICAgICAgJ3N0YXR1c0ljb24nOiAhdGFiSXRlbS5kaXNhYmxlZCAmJiBkaXNwbGF5U3RhdHVzSWNvbnMgJiYgdGFiSXRlbS5kaXNwbGF5U3RhdHVzSWNvblxuICAgICAgICB9XCI+XG4gICAgICAgIDxpICpuZ0lmPVwiIXRhYkl0ZW0uc3RhdGVEaXNhYmxlZCAmJiBkaXNwbGF5U3RhdHVzSWNvbnMgJiYgdGFiSXRlbS5kaXNwbGF5U3RhdHVzSWNvblwiIGNsYXNzPVwic3RhdHVzSWNvblwiPjwvaT5cbiAgICAgICAgPGEgcm9sZT1cInRhYlwiPlxuICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImxhYmVsVGVtcGxhdGU7Y29udGV4dDp7dGFiSXRlbTogdGFiSXRlbX1cIj48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPC9hPlxuICAgIDwvbGk+XG48L25nLXRlbXBsYXRlPlxuIl19