UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

168 lines 36.5 kB
import { Component } from '@angular/core'; import { Subject, combineLatest, of } from 'rxjs'; import { delay, distinctUntilChanged, map, startWith, switchMap, takeUntil } from 'rxjs/operators'; import { ActionBarService } from '../action-bar/action-bar.service'; import { OptionsService } from '../common/options.service'; import { AppStateService } from '../common/ui-state.service'; import { HeaderService } from '../header/header.service'; import { NavigatorService } from '../navigator/navigator.service'; import { PluginsResolveService } from '../plugins/plugins-resolve.service'; import { SetupService } from '../setup/setup.service'; import { TabsService } from '../tabs/tabs.service'; import { isEmpty } from 'lodash-es'; import { LoginService } from '../login/login.service'; import { TranslationLoaderService } from '../i18n/translation-loader.service'; import * as i0 from "@angular/core"; import * as i1 from "../tabs/tabs.service"; import * as i2 from "../common/ui-state.service"; import * as i3 from "../navigator/navigator.service"; import * as i4 from "../action-bar/action-bar.service"; import * as i5 from "../header/header.service"; import * as i6 from "../common/options.service"; import * as i7 from "../plugins/plugins-resolve.service"; import * as i8 from "../setup/setup.service"; import * as i9 from "../login/login.service"; import * as i10 from "../i18n/translation-loader.service"; import * as i11 from "@angular/common"; import * as i12 from "../header/header-bar/header-bar.component"; import * as i13 from "../login/login.component"; import * as i14 from "@angular/router"; import * as i15 from "../tabs/tabs-outlet.component"; import * as i16 from "../action-bar/action-bar.component"; import * as i17 from "../alert/alert-outlet.component"; import * as i18 from "../setup/setup.component"; import * as i19 from "../drawer/drawer-outlet/drawer-outlet.component"; import * as i20 from "./cookie-banner/cookie-banner.component"; import * as i21 from "./message-banner/message-banner.component"; export class BootstrapComponent { constructor(tabs, ui, navigator, actionBar, headerService, options, pluginsResolve, setupService, loginService, // only here to ensure the service is instantiated translationLoaderService) { this.tabs = tabs; this.ui = ui; this.navigator = navigator; this.actionBar = actionBar; this.headerService = headerService; this.options = options; this.pluginsResolve = pluginsResolve; this.setupService = setupService; this.loginService = loginService; this.translationLoaderService = translationLoaderService; this.showPoweredBy = true; this.destroy$ = new Subject(); this.loadedRemotesContextPathCache = new Map(); this.noAppsMargin$ = this.headerService.map(({ nav }) => !nav.open && nav.hiddenOnStartup); this.tabsOrientation = this.options.tabsHorizontal ? 'horizontal' : 'vertical'; this.ui .map(({ lang }) => lang) .pipe(takeUntil(this.destroy$), distinctUntilChanged()) .subscribe(() => { this.actionBar.refresh(); }); this.showPoweredBy = !this.options.get('hidePowered'); const noLogin$ = of(this.options.get('noLogin', false)); this.showLogin$ = combineLatest([noLogin$, this.ui.currentUser]).pipe(map(([noLogin, currentUser]) => !noLogin && !currentUser)); this.showLoadingIndicator$ = combineLatest([ noLogin$, this.ui.currentUser, this.loginService.automaticLoginInProgress$, this.pluginsResolve.allPluginsLoaded$ ]).pipe(delay(0), // delay to avoid ExpressionChangedAfterItHasBeenCheckedError map(([noLogin, currentUser, automaticLoginInProgress, allPluginsLoaded]) => (!noLogin && automaticLoginInProgress) || (currentUser && !allPluginsLoaded)), startWith(true)); this.showMainView$ = noLogin$.pipe(switchMap(noLogin => { if (noLogin) { return of(true); } return combineLatest([ this.ui.currentUser, this.setupService.isSetupNeeded$, this.pluginsResolve.allPluginsLoaded$ ]).pipe(map(([currentUser, isSetupNeeded, allPluginsLoaded]) => { return currentUser && !isSetupNeeded && allPluginsLoaded; })); })); this.showSetup$ = combineLatest([this.ui.currentUser, this.setupService.isSetupNeeded$]).pipe(map(([currentUser, isSetupNeeded]) => currentUser && isSetupNeeded)); } async ngOnInit() { this.subscribeToLoadRemotes(); } ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); } getRemotes(config) { let selfRemotes; // We need to import the self imports, as this app is not configured at all if (this.options?.exports) { const selfModuleNames = this.options.exports .filter(plugin => plugin.scope === 'self') .map(plugin => plugin.module || plugin.name); selfRemotes = { [this.options.contextPath]: selfModuleNames }; } // Merge plugins config remotes and remotes passed in the URL. // Remotes in the URL are used in the development process. let remotes = PluginsResolveService.mergeRemotes([ selfRemotes, // if the config remotes are not present we fall back to the application remotes config?.remotes || this.options?.remotes || {}, // url remotes should always be loaded this.pluginsResolve.loadUrlRemotes() ]); // remove remotes that are on the exclude list remotes = PluginsResolveService.removeRemotes(remotes, config?.excludedRemotes); // Block the possibility of loading plugins multiple times. Object.keys(remotes || {}).forEach(contextPath => { if (this.loadedRemotesContextPathCache.get(contextPath)) { delete remotes[contextPath]; } }); return isEmpty(remotes) ? undefined : remotes; } async loadRemotes(remotes) { if (!remotes) { this.ensureWeMarkPluginsAsLoaded(); return; } const remoteModules = await this.pluginsResolve.loadRemotes(remotes); // Cache loaded remotes. Object.keys(remotes).forEach(contextPath => this.loadedRemotesContextPathCache.set(contextPath, true)); if (remoteModules.length) { this.pluginsResolve.resolveRemotePlugins(remoteModules); } else { // in case loading all modules via pluginsResolve.loadRemotes failed // (e.g. all plugins that were installed have been deleted from the tenant) // we still need to mark loading the plugins as successful. this.ensureWeMarkPluginsAsLoaded(); } } subscribeToLoadRemotes() { if (this.options.get('noPlugins', false)) { this.ensureWeMarkPluginsAsLoaded(); return; } if (this.options.get('forceUrlRemotes', false)) { const remotes = this.pluginsResolve.loadUrlRemotes(); this.loadRemotes(remotes); return; } if (this.options.get('noLogin', false)) { this.loadRemotes(this.getRemotes(null)); return; } this.ui.currentApplicationConfig .pipe(takeUntil(this.destroy$)) .subscribe((config) => this.loadRemotes(this.getRemotes(config))); } ensureWeMarkPluginsAsLoaded() { // ensure we call markPluginsAsLoaded on the DynamicComponentService this.pluginsResolve.markPluginsAsLoaded(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BootstrapComponent, deps: [{ token: i1.TabsService }, { token: i2.AppStateService }, { token: i3.NavigatorService }, { token: i4.ActionBarService }, { token: i5.HeaderService }, { token: i6.OptionsService }, { token: i7.PluginsResolveService }, { token: i8.SetupService }, { token: i9.LoginService }, { token: i10.TranslationLoaderService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: BootstrapComponent, selector: "c8y-bootstrap", ngImport: i0, template: "<c8y-message-banner\n *ngIf=\"!(showLogin$ | async)\"\n class=\"c8y-message-banner\"\n></c8y-message-banner>\n<c8y-login *ngIf=\"showLogin$ | async\"></c8y-login>\n\n<div\n class=\"init-load\"\n *ngIf=\"showLoadingIndicator$ | async\"\n>\n <div class=\"spinner-snake\"></div>\n <div class=\"mainlogo-placeholder mainlogo\"></div>\n</div>\n\n<div\n [class.head-open]=\"headerService.headerOpen\"\n *ngIf=\"showMainView$ | async\"\n>\n <c8y-header-bar\n *ngIf=\"!headerService.hideHeader\"\n #header\n ></c8y-header-bar>\n <c8y-drawer-outlet\n [tabindex]=\"(headerService.navigatorOpen$ | async) ? '0' : '-1'\"\n role=\"region\"\n position=\"left\"\n data-cy=\"bootstrap.template--c8y-drawer-outlet\"\n [open]=\"headerService.navigatorOpen$ | async\"\n ></c8y-drawer-outlet>\n\n <div class=\"alerts\">\n <c8y-alert-outlet></c8y-alert-outlet>\n </div>\n <c8y-tabs-outlet\n role=\"navigation\"\n #tabsComponent\n [tabs]=\"tabs.items$ | async\"\n [hasHeader]=\"tabsComponent.hasHeader\"\n [navigatorOpen]=\"headerService.navigatorOpen$ | async\"\n [orientation]=\"tabs.orientation$ | async\"\n ></c8y-tabs-outlet>\n <c8y-action-bar\n role=\"group\"\n #actionBarComponent\n [navigatorOpen]=\"headerService.navigatorOpen$ | async\"\n [hasTabs]=\"tabsComponent.hasTabs\"\n [hasHeader]=\"tabsComponent.hasHeader\"\n [isTabsHorizontal]=\"tabsComponent?.isHorizontal\"\n [items$]=\"actionBar.items$\"\n ></c8y-action-bar>\n\n <div\n class=\"mcontainer\"\n [ngClass]=\"{\n open: headerService.navigatorOpen$ | async,\n 'no-apps-margin': noAppsMargin$ | async,\n 'horizontal-tabs': tabsComponent.isHorizontal,\n 'vertical-tabs': !tabsComponent.isHorizontal,\n 'has-tabs': tabsComponent.hasTabs,\n 'has-action-bar': !actionBarComponent?.hidden,\n 'has-header': headerService.hideHeader\n }\"\n >\n <main\n class=\"container-fluid\"\n id=\"main-content\"\n tabindex=\"-1\"\n >\n <router-outlet></router-outlet>\n <ng-content select=\"#c8y-legacy-view\"></ng-content>\n <!-- legacy ng-view, will not be migrated atm -->\n </main>\n </div>\n</div>\n\n<div *ngIf=\"showSetup$ | async\">\n <c8y-header-bar\n *ngIf=\"!headerService.hideHeader\"\n [simple]=\"true\"\n ></c8y-header-bar>\n <div class=\"alerts\">\n <c8y-alert-outlet></c8y-alert-outlet>\n </div>\n <div\n class=\"mcontainer\"\n role=\"main\"\n >\n <div class=\"container-fluid\">\n <c8y-setup></c8y-setup>\n </div>\n </div>\n</div>\n\n<c8y-cookie-banner></c8y-cookie-banner>\n", dependencies: [{ kind: "directive", type: i11.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i12.HeaderBarComponent, selector: "c8y-header-bar", inputs: ["simple"] }, { kind: "component", type: i13.LoginComponent, selector: "c8y-login", inputs: ["name"] }, { kind: "directive", type: i14.RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: i15.TabsOutletComponent, selector: "c8y-tabs-outlet,c8y-ui-tabs", inputs: ["tabs", "orientation", "navigatorOpen", "outletName", "context", "openFirstTab", "hasHeader"] }, { kind: "component", type: i16.ActionBarComponent, selector: "c8y-action-bar", inputs: ["navigatorOpen", "hasTabs", "hasHeader", "isTabsHorizontal", "items$"] }, { kind: "component", type: i17.AlertOutletComponent, selector: "c8y-alert-outlet" }, { kind: "component", type: i18.SetupComponent, selector: "c8y-setup" }, { kind: "component", type: i19.DrawerOutletComponent, selector: "c8y-drawer-outlet", inputs: ["position", "open"] }, { kind: "component", type: i20.CookieBannerComponent, selector: "c8y-cookie-banner" }, { kind: "component", type: i21.MessageBannerComponent, selector: "c8y-message-banner" }, { kind: "pipe", type: i11.AsyncPipe, name: "async" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BootstrapComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-bootstrap', template: "<c8y-message-banner\n *ngIf=\"!(showLogin$ | async)\"\n class=\"c8y-message-banner\"\n></c8y-message-banner>\n<c8y-login *ngIf=\"showLogin$ | async\"></c8y-login>\n\n<div\n class=\"init-load\"\n *ngIf=\"showLoadingIndicator$ | async\"\n>\n <div class=\"spinner-snake\"></div>\n <div class=\"mainlogo-placeholder mainlogo\"></div>\n</div>\n\n<div\n [class.head-open]=\"headerService.headerOpen\"\n *ngIf=\"showMainView$ | async\"\n>\n <c8y-header-bar\n *ngIf=\"!headerService.hideHeader\"\n #header\n ></c8y-header-bar>\n <c8y-drawer-outlet\n [tabindex]=\"(headerService.navigatorOpen$ | async) ? '0' : '-1'\"\n role=\"region\"\n position=\"left\"\n data-cy=\"bootstrap.template--c8y-drawer-outlet\"\n [open]=\"headerService.navigatorOpen$ | async\"\n ></c8y-drawer-outlet>\n\n <div class=\"alerts\">\n <c8y-alert-outlet></c8y-alert-outlet>\n </div>\n <c8y-tabs-outlet\n role=\"navigation\"\n #tabsComponent\n [tabs]=\"tabs.items$ | async\"\n [hasHeader]=\"tabsComponent.hasHeader\"\n [navigatorOpen]=\"headerService.navigatorOpen$ | async\"\n [orientation]=\"tabs.orientation$ | async\"\n ></c8y-tabs-outlet>\n <c8y-action-bar\n role=\"group\"\n #actionBarComponent\n [navigatorOpen]=\"headerService.navigatorOpen$ | async\"\n [hasTabs]=\"tabsComponent.hasTabs\"\n [hasHeader]=\"tabsComponent.hasHeader\"\n [isTabsHorizontal]=\"tabsComponent?.isHorizontal\"\n [items$]=\"actionBar.items$\"\n ></c8y-action-bar>\n\n <div\n class=\"mcontainer\"\n [ngClass]=\"{\n open: headerService.navigatorOpen$ | async,\n 'no-apps-margin': noAppsMargin$ | async,\n 'horizontal-tabs': tabsComponent.isHorizontal,\n 'vertical-tabs': !tabsComponent.isHorizontal,\n 'has-tabs': tabsComponent.hasTabs,\n 'has-action-bar': !actionBarComponent?.hidden,\n 'has-header': headerService.hideHeader\n }\"\n >\n <main\n class=\"container-fluid\"\n id=\"main-content\"\n tabindex=\"-1\"\n >\n <router-outlet></router-outlet>\n <ng-content select=\"#c8y-legacy-view\"></ng-content>\n <!-- legacy ng-view, will not be migrated atm -->\n </main>\n </div>\n</div>\n\n<div *ngIf=\"showSetup$ | async\">\n <c8y-header-bar\n *ngIf=\"!headerService.hideHeader\"\n [simple]=\"true\"\n ></c8y-header-bar>\n <div class=\"alerts\">\n <c8y-alert-outlet></c8y-alert-outlet>\n </div>\n <div\n class=\"mcontainer\"\n role=\"main\"\n >\n <div class=\"container-fluid\">\n <c8y-setup></c8y-setup>\n </div>\n </div>\n</div>\n\n<c8y-cookie-banner></c8y-cookie-banner>\n" }] }], ctorParameters: () => [{ type: i1.TabsService }, { type: i2.AppStateService }, { type: i3.NavigatorService }, { type: i4.ActionBarService }, { type: i5.HeaderService }, { type: i6.OptionsService }, { type: i7.PluginsResolveService }, { type: i8.SetupService }, { type: i9.LoginService }, { type: i10.TranslationLoaderService }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9vdHN0cmFwLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2NvcmUvYm9vdHN0cmFwL2Jvb3RzdHJhcC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9jb3JlL2Jvb3RzdHJhcC9ib290c3RyYXAudGVtcGxhdGUuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFxQixNQUFNLGVBQWUsQ0FBQztBQUU3RCxPQUFPLEVBQWMsT0FBTyxFQUFFLGFBQWEsRUFBRSxFQUFFLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDOUQsT0FBTyxFQUFFLEtBQUssRUFBRSxvQkFBb0IsRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNuRyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUNwRSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQzdELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNsRSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUUzRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDdEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDcEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3RELE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLG9DQUFvQyxDQUFDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztB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U0FBUyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDdkMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDeEMsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLENBQUMsRUFBRSxDQUFDLHdCQUF3QjthQUM3QixJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQzthQUM5QixTQUFTLENBQUMsQ0FBQyxNQUFxQixFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3JGLENBQUM7SUFFTywyQkFBMkI7UUFDakMsb0VBQW9FO1FBQ3BFLElBQUksQ0FBQyxjQUFjLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztJQUM1QyxDQUFDOytHQWpLVSxrQkFBa0I7bUdBQWxCLGtCQUFrQixxRENyQi9CLDhqRkE4RkE7OzRGRHpFYSxrQkFBa0I7a0JBSjlCLFNBQVM7K0JBQ0UsZUFBZSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgT25EZXN0cm95LCBPbkluaXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFwcGxpY2F0aW9uUmVtb3RlUGx1Z2lucyB9IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7IE9ic2VydmFibGUsIFN1YmplY3QsIGNvbWJpbmVMYXRlc3QsIG9mIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBkZWxheSwgZGlzdGluY3RVbnRpbENoYW5nZWQsIG1hcCwgc3RhcnRXaXRoLCBzd2l0Y2hNYXAsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IEFjdGlvbkJhclNlcnZpY2UgfSBmcm9tICcuLi9hY3Rpb24tYmFyL2FjdGlvbi1iYXIuc2VydmljZSc7XG5pbXBvcnQgeyBPcHRpb25zU2VydmljZSB9IGZyb20gJy4uL2NvbW1vbi9vcHRpb25zLnNlcnZpY2UnO1xuaW1wb3J0IHsgQXBwU3RhdGVTZXJ2aWNlIH0gZnJvbSAnLi4vY29tbW9uL3VpLXN0YXRlLnNlcnZpY2UnO1xuaW1wb3J0IHsgSGVhZGVyU2VydmljZSB9IGZyb20gJy4uL2hlYWRlci9oZWFkZXIuc2VydmljZSc7XG5pbXBvcnQgeyBOYXZpZ2F0b3JTZXJ2aWNlIH0gZnJvbSAnLi4vbmF2aWdhdG9yL25hdmlnYXRvci5zZXJ2aWNlJztcbmltcG9ydCB7IFBsdWdpbnNSZXNvbHZlU2VydmljZSB9IGZyb20gJy4uL3BsdWdpbnMvcGx1Z2lucy1yZXNvbHZlLnNlcnZpY2UnO1xuaW1wb3J0IHsgUGx1Z2luc0NvbmZpZyB9IGZyb20gJy4uL3BsdWdpbnMvcGx1Z2lucy5tb2RlbCc7XG5pbXBvcnQgeyBTZXR1cFNlcnZpY2UgfSBmcm9tICcuLi9zZXR1cC9zZXR1cC5zZXJ2aWNlJztcbmltcG9ydCB7IFRhYnNTZXJ2aWNlIH0gZnJvbSAnLi4vdGFicy90YWJzLnNlcnZpY2UnO1xuaW1wb3J0IHsgaXNFbXB0eSB9IGZyb20gJ2xvZGFzaC1lcyc7XG5pbXBvcnQgeyBMb2dpblNlcnZpY2UgfSBmcm9tICcuLi9sb2dpbi9sb2dpbi5zZXJ2aWNlJztcbmltcG9ydCB7IFRyYW5zbGF0aW9uTG9hZGVyU2VydmljZSB9IGZyb20gJy4uL2kxOG4vdHJhbnNsYXRpb24tbG9hZGVyLnNlcnZpY2UnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjOHktYm9vdHN0cmFwJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2Jvb3RzdHJhcC50ZW1wbGF0ZS5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBCb290c3RyYXBDb21wb25lbnQgaW1wbGVtZW50cyBPbkRlc3Ryb3ksIE9uSW5pdCB7XG4gIG5hdmlnYXRvck9wZW4kOiBPYnNlcnZhYmxlPGJvb2xlYW4+O1xuICBub0FwcHNNYXJnaW4kOiBPYnNlcnZhYmxlPGJvb2xlYW4+O1xuICB0YWJzT3JpZW50YXRpb246IHN0cmluZztcbiAgc2hvd1Bvd2VyZWRCeSA9IHRydWU7XG4gIHNob3dMb2dpbiQ6IE9ic2VydmFibGU8Ym9vbGVhbj47XG4gIHNob3dMb2FkaW5nSW5kaWNhdG9yJDogT2JzZXJ2YWJsZTxib29sZWFuPjtcbiAgc2hvd01haW5WaWV3JDogT2JzZXJ2YWJsZTxib29sZWFuPjtcbiAgc2hvd1NldHVwJDogT2JzZXJ2YWJsZTxib29sZWFuPjtcbiAgcHJpdmF0ZSBkZXN0cm95JDogU3ViamVjdDx2b2lkPiA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG4gIHByaXZhdGUgbG9hZGVkUmVtb3Rlc0NvbnRleHRQYXRoQ2FjaGUgPSBuZXcgTWFwPHN0cmluZywgYm9vbGVhbj4oKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwdWJsaWMgdGFiczogVGFic1NlcnZpY2UsXG4gICAgcHVibGljIHVpOiBBcHBTdGF0ZVNlcnZpY2UsXG4gICAgcHVibGljIG5hdmlnYXRvcjogTmF2aWdhdG9yU2VydmljZSxcbiAgICBwdWJsaWMgYWN0aW9uQmFyOiBBY3Rpb25CYXJTZXJ2aWNlLFxuICAgIHB1YmxpYyBoZWFkZXJTZXJ2aWNlOiBIZWFkZXJTZXJ2aWNlLFxuICAgIHByaXZhdGUgb3B0aW9uczogT3B0aW9uc1NlcnZpY2UsXG4gICAgcHJpdmF0ZSBwbHVnaW5zUmVzb2x2ZTogUGx1Z2luc1Jlc29sdmVTZXJ2aWNlLFxuICAgIHB1YmxpYyBzZXR1cFNlcnZpY2U6IFNldHVwU2VydmljZSxcbiAgICBwdWJsaWMgbG9naW5TZXJ2aWNlOiBMb2dpblNlcnZpY2UsXG4gICAgLy8gb25seSBoZXJlIHRvIGVuc3VyZSB0aGUgc2VydmljZSBpcyBpbnN0YW50aWF0ZWRcbiAgICBwdWJsaWMgdHJhbnNsYXRpb25Mb2FkZXJTZXJ2aWNlOiBUcmFuc2xhdGlvbkxvYWRlclNlcnZpY2VcbiAgKSB7XG4gICAgdGhpcy5ub0FwcHNNYXJnaW4kID0gdGhpcy5oZWFkZXJTZXJ2aWNlLm1hcCgoeyBuYXYgfSkgPT4gIW5hdi5vcGVuICYmIG5hdi5oaWRkZW5PblN0YXJ0dXApO1xuICAgIHRoaXMudGFic09yaWVudGF0aW9uID0gdGhpcy5vcHRpb25zLnRhYnNIb3Jpem9udGFsID8gJ2hvcml6b250YWwnIDogJ3ZlcnRpY2FsJztcbiAgICB0aGlzLnVpXG4gICAgICAubWFwKCh7IGxhbmcgfSkgPT4gbGFuZylcbiAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSwgZGlzdGluY3RVbnRpbENoYW5nZWQoKSlcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICB0aGlzLmFjdGlvbkJhci5yZWZyZXNoKCk7XG4gICAgICB9KTtcbiAgICB0aGlzLnNob3dQb3dlcmVkQnkgPSAhdGhpcy5vcHRpb25zLmdldCgnaGlkZVBvd2VyZWQnKTtcbiAgICBjb25zdCBub0xvZ2luJCA9IG9mKHRoaXMub3B0aW9ucy5nZXQoJ25vTG9naW4nLCBmYWxzZSkpO1xuICAgIHRoaXMuc2hvd0xvZ2luJCA9IGNvbWJpbmVMYXRlc3QoW25vTG9naW4kLCB0aGlzLnVpLmN1cnJlbnRVc2VyXSkucGlwZShcbiAgICAgIG1hcCgoW25vTG9naW4sIGN1cnJlbnRVc2VyXSkgPT4gIW5vTG9naW4gJiYgIWN1cnJlbnRVc2VyKVxuICAgICk7XG4gICAgdGhpcy5zaG93TG9hZGluZ0luZGljYXRvciQgPSBjb21iaW5lTGF0ZXN0KFtcbiAgICAgIG5vTG9naW4kLFxuICAgICAgdGhpcy51aS5jdXJyZW50VXNlcixcbiAgICAgIHRoaXMubG9naW5TZXJ2aWNlLmF1dG9tYXRpY0xvZ2luSW5Qcm9ncmVzcyQsXG4gICAgICB0aGlzLnBsdWdpbnNSZXNvbHZlLmFsbFBsdWdpbnNMb2FkZWQkXG4gICAgXSkucGlwZShcbiAgICAgIGRlbGF5KDApLCAvLyBkZWxheSB0byBhdm9pZCBFeHByZXNzaW9uQ2hhbmdlZEFmdGVySXRIYXNCZWVuQ2hlY2tlZEVycm9yXG4gICAgICBtYXAoXG4gICAgICAgIChbbm9Mb2dpbiwgY3VycmVudFVzZXIsIGF1dG9tYXRpY0xvZ2luSW5Qcm9ncmVzcywgYWxsUGx1Z2luc0xvYWRlZF0pID0+XG4gICAgICAgICAgKCFub0xvZ2luICYmIGF1dG9tYXRpY0xvZ2luSW5Qcm9ncmVzcykgfHwgKGN1cnJlbnRVc2VyICYmICFhbGxQbHVnaW5zTG9hZGVkKVxuICAgICAgKSxcbiAgICAgIHN0YXJ0V2l0aCh0cnVlKVxuICAgICk7XG4gICAgdGhpcy5zaG93TWFpblZpZXckID0gbm9Mb2dpbiQucGlwZShcbiAgICAgIHN3aXRjaE1hcChub0xvZ2luID0+IHtcbiAgICAgICAgaWYgKG5vTG9naW4pIHtcbiAgICAgICAgICByZXR1cm4gb2YodHJ1ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGNvbWJpbmVMYXRlc3QoW1xuICAgICAgICAgIHRoaXMudWkuY3VycmVudFVzZXIsXG4gICAgICAgICAgdGhpcy5zZXR1cFNlcnZpY2UuaXNTZXR1cE5lZWRlZCQsXG4gICAgICAgICAgdGhpcy5wbHVnaW5zUmVzb2x2ZS5hbGxQbHVnaW5zTG9hZGVkJFxuICAgICAgICBdKS5waXBlKFxuICAgICAgICAgIG1hcCgoW2N1cnJlbnRVc2VyLCBpc1NldHVwTmVlZGVkLCBhbGxQbHVnaW5zTG9hZGVkXSkgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIGN1cnJlbnRVc2VyICYmICFpc1NldHVwTmVlZGVkICYmIGFsbFBsdWdpbnNMb2FkZWQ7XG4gICAgICAgICAgfSlcbiAgICAgICAgKTtcbiAgICAgIH0pXG4gICAgKTtcbiAgICB0aGlzLnNob3dTZXR1cCQgPSBjb21iaW5lTGF0ZXN0KFt0aGlzLnVpLmN1cnJlbnRVc2VyLCB0aGlzLnNldHVwU2VydmljZS5pc1NldHVwTmVlZGVkJF0pLnBpcGUoXG4gICAgICBtYXAoKFtjdXJyZW50VXNlciwgaXNTZXR1cE5lZWRlZF0pID0+IGN1cnJlbnRVc2VyICYmIGlzU2V0dXBOZWVkZWQpXG4gICAgKTtcbiAgfVxuXG4gIGFzeW5jIG5nT25Jbml0KCkge1xuICAgIHRoaXMuc3Vic2NyaWJlVG9Mb2FkUmVtb3RlcygpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgdGhpcy5kZXN0cm95JC5uZXh0KCk7XG4gICAgdGhpcy5kZXN0cm95JC5jb21wbGV0ZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRSZW1vdGVzKGNvbmZpZzogUGx1Z2luc0NvbmZpZyk6IEFwcGxpY2F0aW9uUmVtb3RlUGx1Z2lucyB8IHVuZGVmaW5lZCB7XG4gICAgbGV0IHNlbGZSZW1vdGVzOiBBcHBsaWNhdGlvblJlbW90ZVBsdWdpbnM7XG5cbiAgICAvLyBXZSBuZWVkIHRvIGltcG9ydCB0aGUgc2VsZiBpbXBvcnRzLCBhcyB0aGlzIGFwcCBpcyBub3QgY29uZmlndXJlZCBhdCBhbGxcbiAgICBpZiAodGhpcy5vcHRpb25zPy5leHBvcnRzKSB7XG4gICAgICBjb25zdCBzZWxmTW9kdWxlTmFtZXM6IHN0cmluZ1tdID0gdGhpcy5vcHRpb25zLmV4cG9ydHNcbiAgICAgICAgLmZpbHRlcihwbHVnaW4gPT4gcGx1Z2luLnNjb3BlID09PSAnc2VsZicpXG4gICAgICAgIC5tYXAocGx1Z2luID0+IHBsdWdpbi5tb2R1bGUgfHwgcGx1Z2luLm5hbWUpO1xuICAgICAgc2VsZlJlbW90ZXMgPSB7IFt0aGlzLm9wdGlvbnMuY29udGV4dFBhdGhdOiBzZWxmTW9kdWxlTmFtZXMgfTtcbiAgICB9XG5cbiAgICAvLyBNZXJnZSBwbHVnaW5zIGNvbmZpZyByZW1vdGVzIGFuZCByZW1vdGVzIHBhc3NlZCBpbiB0aGUgVVJMLlxuICAgIC8vIFJlbW90ZXMgaW4gdGhlIFVSTCBhcmUgdXNlZCBpbiB0aGUgZGV2ZWxvcG1lbnQgcHJvY2Vzcy5cbiAgICBsZXQgcmVtb3RlcyA9IFBsdWdpbnNSZXNvbHZlU2VydmljZS5tZXJnZVJlbW90ZXMoW1xuICAgICAgc2VsZlJlbW90ZXMsXG4gICAgICAvLyBpZiB0aGUgY29uZmlnIHJlbW90ZXMgYXJlIG5vdCBwcmVzZW50IHdlIGZhbGwgYmFjayB0byB0aGUgYXBwbGljYXRpb24gcmVtb3Rlc1xuICAgICAgY29uZmlnPy5yZW1vdGVzIHx8IHRoaXMub3B0aW9ucz8ucmVtb3RlcyB8fCB7fSxcbiAgICAgIC8vIHVybCByZW1vdGVzIHNob3VsZCBhbHdheXMgYmUgbG9hZGVkXG4gICAgICB0aGlzLnBsdWdpbnNSZXNvbHZlLmxvYWRVcmxSZW1vdGVzKClcbiAgICBdKTtcblxuICAgIC8vIHJlbW92ZSByZW1vdGVzIHRoYXQgYXJlIG9uIHRoZSBleGNsdWRlIGxpc3RcbiAgICByZW1vdGVzID0gUGx1Z2luc1Jlc29sdmVTZXJ2aWNlLnJlbW92ZVJlbW90ZXMocmVtb3RlcywgY29uZmlnPy5leGNsdWRlZFJlbW90ZXMpO1xuXG4gICAgLy8gQmxvY2sgdGhlIHBvc3NpYmlsaXR5IG9mIGxvYWRpbmcgcGx1Z2lucyBtdWx0aXBsZSB0aW1lcy5cbiAgICBPYmplY3Qua2V5cyhyZW1vdGVzIHx8IHt9KS5mb3JFYWNoKGNvbnRleHRQYXRoID0+IHtcbiAgICAgIGlmICh0aGlzLmxvYWRlZFJlbW90ZXNDb250ZXh0UGF0aENhY2hlLmdldChjb250ZXh0UGF0aCkpIHtcbiAgICAgICAgZGVsZXRlIHJlbW90ZXNbY29udGV4dFBhdGhdO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBpc0VtcHR5KHJlbW90ZXMpID8gdW5kZWZpbmVkIDogcmVtb3RlcztcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgbG9hZFJlbW90ZXMocmVtb3RlczogQXBwbGljYXRpb25SZW1vdGVQbHVnaW5zKSB7XG4gICAgaWYgKCFyZW1vdGVzKSB7XG4gICAgICB0aGlzLmVuc3VyZVdlTWFya1BsdWdpbnNBc0xvYWRlZCgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCByZW1vdGVNb2R1bGVzID0gYXdhaXQgdGhpcy5wbHVnaW5zUmVzb2x2ZS5sb2FkUmVtb3RlcyhyZW1vdGVzKTtcblxuICAgIC8vIENhY2hlIGxvYWRlZCByZW1vdGVzLlxuICAgIE9iamVjdC5rZXlzKHJlbW90ZXMpLmZvckVhY2goY29udGV4dFBhdGggPT5cbiAgICAgIHRoaXMubG9hZGVkUmVtb3Rlc0NvbnRleHRQYXRoQ2FjaGUuc2V0KGNvbnRleHRQYXRoLCB0cnVlKVxuICAgICk7XG5cbiAgICBpZiAocmVtb3RlTW9kdWxlcy5sZW5ndGgpIHtcbiAgICAgIHRoaXMucGx1Z2luc1Jlc29sdmUucmVzb2x2ZVJlbW90ZVBsdWdpbnMocmVtb3RlTW9kdWxlcyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIGluIGNhc2UgbG9hZGluZyBhbGwgbW9kdWxlcyB2aWEgcGx1Z2luc1Jlc29sdmUubG9hZFJlbW90ZXMgZmFpbGVkXG4gICAgICAvLyAoZS5nLiBhbGwgcGx1Z2lucyB0aGF0IHdlcmUgaW5zdGFsbGVkIGhhdmUgYmVlbiBkZWxldGVkIGZyb20gdGhlIHRlbmFudClcbiAgICAgIC8vIHdlIHN0aWxsIG5lZWQgdG8gbWFyayBsb2FkaW5nIHRoZSBwbHVnaW5zIGFzIHN1Y2Nlc3NmdWwuXG4gICAgICB0aGlzLmVuc3VyZVdlTWFya1BsdWdpbnNBc0xvYWRlZCgpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc3Vic2NyaWJlVG9Mb2FkUmVtb3RlcygpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5vcHRpb25zLmdldCgnbm9QbHVnaW5zJywgZmFsc2UpKSB7XG4gICAgICB0aGlzLmVuc3VyZVdlTWFya1BsdWdpbnNBc0xvYWRlZCgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0aGlzLm9wdGlvbnMuZ2V0KCdmb3JjZVVybFJlbW90ZXMnLCBmYWxzZSkpIHtcbiAgICAgIGNvbnN0IHJlbW90ZXMgPSB0aGlzLnBsdWdpbnNSZXNvbHZlLmxvYWRVcmxSZW1vdGVzKCk7XG4gICAgICB0aGlzLmxvYWRSZW1vdGVzKHJlbW90ZXMpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0aGlzLm9wdGlvbnMuZ2V0KCdub0xvZ2luJywgZmFsc2UpKSB7XG4gICAgICB0aGlzLmxvYWRSZW1vdGVzKHRoaXMuZ2V0UmVtb3RlcyhudWxsKSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy51aS5jdXJyZW50QXBwbGljYXRpb25Db25maWdcbiAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSlcbiAgICAgIC5zdWJzY3JpYmUoKGNvbmZpZzogUGx1Z2luc0NvbmZpZykgPT4gdGhpcy5sb2FkUmVtb3Rlcyh0aGlzLmdldFJlbW90ZXMoY29uZmlnKSkpO1xuICB9XG5cbiAgcHJpdmF0ZSBlbnN1cmVXZU1hcmtQbHVnaW5zQXNMb2FkZWQoKTogdm9pZCB7XG4gICAgLy8gZW5zdXJlIHdlIGNhbGwgbWFya1BsdWdpbnNBc0xvYWRlZCBvbiB0aGUgRHluYW1pY0NvbXBvbmVudFNlcnZpY2VcbiAgICB0aGlzLnBsdWdpbnNSZXNvbHZlLm1hcmtQbHVnaW5zQXNMb2FkZWQoKTtcbiAgfVxufVxuIiwiPGM4eS1tZXNzYWdlLWJhbm5lclxuICAqbmdJZj1cIiEoc2hvd0xvZ2luJCB8IGFzeW5jKVwiXG4gIGNsYXNzPVwiYzh5LW1lc3NhZ2UtYmFubmVyXCJcbj48L2M4eS1tZXNzYWdlLWJhbm5lcj5cbjxjOHktbG9naW4gKm5nSWY9XCJzaG93TG9naW4kIHwgYXN5bmNcIj48L2M4eS1sb2dpbj5cblxuPGRpdlxuICBjbGFzcz1cImluaXQtbG9hZFwiXG4gICpuZ0lmPVwic2hvd0xvYWRpbmdJbmRpY2F0b3IkIHwgYXN5bmNcIlxuPlxuICA8ZGl2IGNsYXNzPVwic3Bpbm5lci1zbmFrZVwiPjwvZGl2PlxuICA8ZGl2IGNsYXNzPVwibWFpbmxvZ28tcGxhY2Vob2xkZXIgbWFpbmxvZ29cIj48L2Rpdj5cbjwvZGl2PlxuXG48ZGl2XG4gIFtjbGFzcy5oZWFkLW9wZW5dPVwiaGVhZGVyU2VydmljZS5oZWFkZXJPcGVuXCJcbiAgKm5nSWY9XCJzaG93TWFpblZpZXckIHwgYXN5bmNcIlxuPlxuICA8Yzh5LWhlYWRlci1iYXJcbiAgICAqbmdJZj1cIiFoZWFkZXJTZXJ2aWNlLmhpZGVIZWFkZXJcIlxuICAgICNoZWFkZXJcbiAgPjwvYzh5LWhlYWRlci1iYXI+XG4gIDxjOHktZHJhd2VyLW91dGxldFxuICAgIFt0YWJpbmRleF09XCIoaGVhZGVyU2VydmljZS5uYXZpZ2F0b3JPcGVuJCB8IGFzeW5jKSA/ICcwJyA6ICctMSdcIlxuICAgIHJvbGU9XCJyZWdpb25cIlxuICAgIHBvc2l0aW9uPVwibGVmdFwiXG4gICAgZGF0YS1jeT1cImJvb3RzdHJhcC50ZW1wbGF0ZS0tYzh5LWRyYXdlci1vdXRsZXRcIlxuICAgIFtvcGVuXT1cImhlYWRlclNlcnZpY2UubmF2aWdhdG9yT3BlbiQgfCBhc3luY1wiXG4gID48L2M4eS1kcmF3ZXItb3V0bGV0PlxuXG4gIDxkaXYgY2xhc3M9XCJhbGVydHNcIj5cbiAgICA8Yzh5LWFsZXJ0LW91dGxldD48L2M4eS1hbGVydC1vdXRsZXQ+XG4gIDwvZGl2PlxuICA8Yzh5LXRhYnMtb3V0bGV0XG4gICAgcm9sZT1cIm5hdmlnYXRpb25cIlxuICAgICN0YWJzQ29tcG9uZW50XG4gICAgW3RhYnNdPVwidGFicy5pdGVtcyQgfCBhc3luY1wiXG4gICAgW2hhc0hlYWRlcl09XCJ0YWJzQ29tcG9uZW50Lmhhc0hlYWRlclwiXG4gICAgW25hdmlnYXRvck9wZW5dPVwiaGVhZGVyU2VydmljZS5uYXZpZ2F0b3JPcGVuJCB8IGFzeW5jXCJcbiAgICBbb3JpZW50YXRpb25dPVwidGFicy5vcmllbnRhdGlvbiQgfCBhc3luY1wiXG4gID48L2M4eS10YWJzLW91dGxldD5cbiAgPGM4eS1hY3Rpb24tYmFyXG4gICAgcm9sZT1cImdyb3VwXCJcbiAgICAjYWN0aW9uQmFyQ29tcG9uZW50XG4gICAgW25hdmlnYXRvck9wZW5dPVwiaGVhZGVyU2VydmljZS5uYXZpZ2F0b3JPcGVuJCB8IGFzeW5jXCJcbiAgICBbaGFzVGFic109XCJ0YWJzQ29tcG9uZW50Lmhhc1RhYnNcIlxuICAgIFtoYXNIZWFkZXJdPVwidGFic0NvbXBvbmVudC5oYXNIZWFkZXJcIlxuICAgIFtpc1RhYnNIb3Jpem9udGFsXT1cInRhYnNDb21wb25lbnQ/LmlzSG9yaXpvbnRhbFwiXG4gICAgW2l0ZW1zJF09XCJhY3Rpb25CYXIuaXRlbXMkXCJcbiAgPjwvYzh5LWFjdGlvbi1iYXI+XG5cbiAgPGRpdlxuICAgIGNsYXNzPVwibWNvbnRhaW5lclwiXG4gICAgW25nQ2xhc3NdPVwie1xuICAgICAgb3BlbjogaGVhZGVyU2VydmljZS5uYXZpZ2F0b3JPcGVuJCB8IGFzeW5jLFxuICAgICAgJ25vLWFwcHMtbWFyZ2luJzogbm9BcHBzTWFyZ2luJCB8IGFzeW5jLFxuICAgICAgJ2hvcml6b250YWwtdGFicyc6IHRhYnNDb21wb25lbnQuaXNIb3Jpem9udGFsLFxuICAgICAgJ3ZlcnRpY2FsLXRhYnMnOiAhdGFic0NvbXBvbmVudC5pc0hvcml6b250YWwsXG4gICAgICAnaGFzLXRhYnMnOiB0YWJzQ29tcG9uZW50Lmhhc1RhYnMsXG4gICAgICAnaGFzLWFjdGlvbi1iYXInOiAhYWN0aW9uQmFyQ29tcG9uZW50Py5oaWRkZW4sXG4gICAgICAnaGFzLWhlYWRlcic6IGhlYWRlclNlcnZpY2UuaGlkZUhlYWRlclxuICAgIH1cIlxuICA+XG4gICAgPG1haW5cbiAgICAgIGNsYXNzPVwiY29udGFpbmVyLWZsdWlkXCJcbiAgICAgIGlkPVwibWFpbi1jb250ZW50XCJcbiAgICAgIHRhYmluZGV4PVwiLTFcIlxuICAgID5cbiAgICAgIDxyb3V0ZXItb3V0bGV0Pjwvcm91dGVyLW91dGxldD5cbiAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cIiNjOHktbGVnYWN5LXZpZXdcIj48L25nLWNvbnRlbnQ+XG4gICAgICA8IS0tIGxlZ2FjeSBuZy12aWV3LCB3aWxsIG5vdCBiZSBtaWdyYXRlZCBhdG0gLS0+XG4gICAgPC9tYWluPlxuICA8L2Rpdj5cbjwvZGl2PlxuXG48ZGl2ICpuZ0lmPVwic2hvd1NldHVwJCB8IGFzeW5jXCI+XG4gIDxjOHktaGVhZGVyLWJhclxuICAgICpuZ0lmPVwiIWhlYWRlclNlcnZpY2UuaGlkZUhlYWRlclwiXG4gICAgW3NpbXBsZV09XCJ0cnVlXCJcbiAgPjwvYzh5LWhlYWRlci1iYXI+XG4gIDxkaXYgY2xhc3M9XCJhbGVydHNcIj5cbiAgICA8Yzh5LWFsZXJ0LW91dGxldD48L2M4eS1hbGVydC1vdXRsZXQ+XG4gIDwvZGl2PlxuICA8ZGl2XG4gICAgY2xhc3M9XCJtY29udGFpbmVyXCJcbiAgICByb2xlPVwibWFpblwiXG4gID5cbiAgICA8ZGl2IGNsYXNzPVwiY29udGFpbmVyLWZsdWlkXCI+XG4gICAgICA8Yzh5LXNldHVwPjwvYzh5LXNldHVwPlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbjwvZGl2PlxuXG48Yzh5LWNvb2tpZS1iYW5uZXI+PC9jOHktY29va2llLWJhbm5lcj5cbiJdfQ==