@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
195 lines • 27.6 kB
JavaScript
import { Injectable, Injector } from '@angular/core';
import { ActivatedRoute, ActivationEnd, NavigationEnd, PRIMARY_OUTLET, Router } from '@angular/router';
import { ApiService } from '@c8y/ngx-components/api';
import { NEVER, Subject } from 'rxjs';
import { filter, merge, switchMap } from 'rxjs/operators';
import { TabsService } from '../tabs/tabs.service';
import { RouterTabsResolver } from './router-tabs.resolver';
import { ViewContext } from './router.model';
import { ViewContextServices } from './view-context.service';
import * as i0 from "@angular/core";
import * as i1 from "./router-tabs.resolver";
import * as i2 from "../tabs/tabs.service";
import * as i3 from "@angular/router";
import * as i4 from "@c8y/ngx-components/api";
export class ContextRouteService {
constructor(tabsResolver, tabsService, router, apiService, injector) {
this.tabsResolver = tabsResolver;
this.tabsService = tabsService;
this.router = router;
this.apiService = apiService;
this.injector = injector;
this.lastAddedTabs = [];
this.ID_REGEX = /([0-9]+)/;
this.refreshTrigger$ = new Subject();
/**
* Last context data snapshot
*/
this.activatedContextData = null;
this.router.events
.pipe(filter(event => event instanceof ActivationEnd))
.subscribe((event) => {
const currentContext = this.getContextDataSnapshot(event.snapshot);
if (currentContext) {
this.activatedContextData = currentContext;
}
});
}
/**
* Resolves the current context data. If no context was found, null is returned.
*
* @param activatedRoute The current activated route.
*/
getContextData(activatedRoute) {
const data = this.getContextDataSnapshot(this.getSnapshot(activatedRoute));
if (data?.context) {
return data;
}
return null;
}
/**
* Returns a route for the given ContextData.
*
* @param contextData The ContextData object.
* @returns A route with the ids set correctly.
*/
getContextRoute(contextData) {
return contextData.context.replace(/:id/g, contextData.contextData.id);
}
/**
* Verifies if a given url is a view context route.
*
* @param url A route url.
* @param contextToCheck The view context(s) to check. If not provided, all contexts are checked.
* @returns true if the given url is a view context route.
*/
isContextRoute(url, contextToCheck = []) {
const viewContexts = contextToCheck.length === 0 ? Object.values(ViewContext) : contextToCheck;
// replace all :id placeholders with a regex matcher for a number
const regexMatchers = viewContexts.map(context => `/${context.replace(/:id/g, '([0-9]+)')}`);
const matchingRegexContext = regexMatchers.find(context => new RegExp(context).test(url));
return !!matchingRegexContext;
}
/**
* @deprecated: Use ScopedContextRouteService instead. Will be removed in 10.22
*/
init(route) {
this.routerSubscription = this.router.events
.pipe(filter(e => e instanceof NavigationEnd))
.subscribe(() => this.redirectToFirstTab());
this.dataSubscription = route.data
.pipe(merge(this.updatedContext(route), this.refreshTrigger$), switchMap(() => this.tabsResolver.resolve(route.snapshot)))
.subscribe(tabs => this.updateTabs(tabs));
}
/**
* @deprecated: Use ScopedContextRouteService instead. Will be removed in 10.22
*/
destroy() {
this.dataSubscription.unsubscribe();
this.routerSubscription.unsubscribe();
this.lastAddedTabs.forEach(t => this.tabsService.remove(t));
}
/**
* Reloads all ViewContexts.
*/
refreshContext() {
this.refreshTrigger$.next();
}
/**
* Sets a new contextData in the ActivatedRoute.
* @param activatedRoute The current activated route.
* @param contextData New contextData.
*/
setContext(activatedRoute, contextData) {
const data = !activatedRoute.snapshot.parent || activatedRoute.snapshot.data.context
? activatedRoute.snapshot.data
: activatedRoute.parent.snapshot.data;
if (!data) {
return;
}
data.contextData = { ...contextData };
}
/**
* @deprecated: Use ScopedContextRouteService instead. Will be removed in 10.21
*/
updatedContext(route) {
const { data } = route.snapshot;
const serviceInstance = ViewContextServices.contextToService(data.context);
if (serviceInstance) {
const service = this.injector.get(serviceInstance);
const detailsUrlRegex = service
.getDetailUrl(data.contextData)
.replace(/\d+/g, '?\\d*');
const contextRegex = new RegExp(detailsUrlRegex, 'i');
const childrenRegex = new RegExp(`${detailsUrlRegex}/child`, 'i');
const filterResponse = ({ url, method }) => {
const contextChanged = contextRegex.test(url) && ['POST', 'PUT'].includes(method);
const childrenAffected = childrenRegex.test(url) && ['POST', 'DELETE'].includes(method);
return contextChanged || childrenAffected;
};
return this.apiService.hookResponse(filterResponse);
}
return NEVER;
}
updateTabs(tabs = []) {
this.lastAddedTabs.forEach(t => this.tabsService.remove(t));
this.lastAddedTabs = tabs;
tabs.forEach(t => this.tabsService.add(t));
this.redirectToFirstTab();
}
redirectToFirstTab() {
const currentContextId = (this.router.url.match(this.ID_REGEX) || []).shift();
if (this.needsRedirect()) {
this.tabsService.firstTab$
.pipe(filter((tab) => typeof tab?.path === 'string'))
.subscribe((tab) => {
const tabPathId = (tab.path.match(this.ID_REGEX) || []).shift();
if (currentContextId === tabPathId) {
this.router.navigateByUrl(tab.path, { replaceUrl: true });
}
});
}
}
needsRedirect() {
const tree = this.router.parseUrl(this.router.url);
const groups = tree.root.children[PRIMARY_OUTLET];
const context = this.getMatchingContextRoute(this.router.url);
if (!context) {
return groups.segments.length === 2;
}
else {
return context.split('/').length === groups.segments.length;
}
}
getMatchingContextRoute(url) {
const viewContexts = Object.values(ViewContext);
const urlWithoutId = url.replace(/\d(.*)/g, '');
const id = viewContexts.findIndex(context => `/${context.replace(':id', '')}` === urlWithoutId);
return viewContexts[id];
}
getSnapshot(activatedRoute) {
return activatedRoute instanceof ActivatedRoute ||
!!activatedRoute?.snapshot
? activatedRoute.snapshot
: activatedRoute;
}
getContextDataSnapshot(activatedRoute) {
let route = activatedRoute;
while (route) {
if (route.data.context) {
return route.data;
}
route = route.parent;
}
return {};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ContextRouteService, deps: [{ token: i1.RouterTabsResolver }, { token: i2.TabsService }, { token: i3.Router }, { token: i4.ApiService }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ContextRouteService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ContextRouteService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [{ type: i1.RouterTabsResolver }, { type: i2.TabsService }, { type: i3.Router }, { type: i4.ApiService }, { type: i0.Injector }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGV4dC1yb3V0ZS5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vY29yZS9yb3V0ZXIvY29udGV4dC1yb3V0ZS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFRLE1BQU0sZUFBZSxDQUFDO0FBQzNELE9BQU8sRUFDTCxjQUFjLEVBRWQsYUFBYSxFQUViLGFBQWEsRUFDYixjQUFjLEVBQ2QsTUFBTSxFQUdQLE1BQU0saUJBQWlCLENBQUM7QUFFekIsT0FBTyxFQUFXLFVBQVUsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzlELE9BQU8sRUFBRSxLQUFLLEVBQWMsT0FBTyxFQUFnQixNQUFNLE1BQU0sQ0FBQztBQUNoRSxPQUFPLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUUxRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbkQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDNUQsT0FBTyxFQUFlLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzFELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHdCQUF3QixDQUFDOzs7Ozs7QUFLN0QsTUFBTSxPQUFPLG1CQUFtQjtJQWE5QixZQUNVLFlBQWdDLEVBQ2hDLFdBQXdCLEVBQ3hCLE1BQWMsRUFDZCxVQUFzQixFQUN0QixRQUFrQjtRQUpsQixpQkFBWSxHQUFaLFlBQVksQ0FBb0I7UUFDaEMsZ0JBQVcsR0FBWCxXQUFXLENBQWE7UUFDeEIsV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQUNkLGVBQVUsR0FBVixVQUFVLENBQVk7UUFDdEIsYUFBUSxHQUFSLFFBQVEsQ0FBVTtRQWZwQixrQkFBYSxHQUFHLEVBQUUsQ0FBQztRQUNuQixhQUFRLEdBQUcsVUFBVSxDQUFDO1FBRTlCLG9C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O21IQUFuQixtQkFBbUIsY0FGbEIsTUFBTTs7NEZBRVAsbUJBQW1CO2tCQUgvQixVQUFVO21CQUFDO29CQUNWLFVBQVUsRUFBRSxNQUFNO2lCQUNuQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUsIEluamVjdG9yLCBUeXBlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1xuICBBY3RpdmF0ZWRSb3V0ZSxcbiAgQWN0aXZhdGVkUm91dGVTbmFwc2hvdCxcbiAgQWN0aXZhdGlvbkVuZCxcbiAgRGF0YSxcbiAgTmF2aWdhdGlvbkVuZCxcbiAgUFJJTUFSWV9PVVRMRVQsXG4gIFJvdXRlcixcbiAgVXJsU2VnbWVudEdyb3VwLFxuICBVcmxUcmVlXG59IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQgeyBJSWRlbnRpZmllZCB9IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7IEFwaUNhbGwsIEFwaVNlcnZpY2UgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzL2FwaSc7XG5pbXBvcnQgeyBORVZFUiwgT2JzZXJ2YWJsZSwgU3ViamVjdCwgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBmaWx0ZXIsIG1lcmdlLCBzd2l0Y2hNYXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBUYWIsIFRhYldpdGhUZW1wbGF0ZSB9IGZyb20gJy4uL3RhYnMvdGFiLm1vZGVsJztcbmltcG9ydCB7IFRhYnNTZXJ2aWNlIH0gZnJvbSAnLi4vdGFicy90YWJzLnNlcnZpY2UnO1xuaW1wb3J0IHsgUm91dGVyVGFic1Jlc29sdmVyIH0gZnJvbSAnLi9yb3V0ZXItdGFicy5yZXNvbHZlcic7XG5pbXBvcnQgeyBDb250ZXh0RGF0YSwgVmlld0NvbnRleHQgfSBmcm9tICcuL3JvdXRlci5tb2RlbCc7XG5pbXBvcnQgeyBWaWV3Q29udGV4dFNlcnZpY2VzIH0gZnJvbSAnLi92aWV3LWNvbnRleHQuc2VydmljZSc7XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIENvbnRleHRSb3V0ZVNlcnZpY2Uge1xuICBwcml2YXRlIGRhdGFTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcbiAgcHJpdmF0ZSByb3V0ZXJTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcbiAgcHJpdmF0ZSBsYXN0QWRkZWRUYWJzID0gW107XG4gIHByaXZhdGUgSURfUkVHRVggPSAvKFswLTldKykvO1xuXG4gIHJlZnJlc2hUcmlnZ2VyJCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgLyoqXG4gICAqIExhc3QgY29udGV4dCBkYXRhIHNuYXBzaG90XG4gICAqL1xuICBhY3RpdmF0ZWRDb250ZXh0RGF0YTogQ29udGV4dERhdGEgPSBudWxsO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgdGFic1Jlc29sdmVyOiBSb3V0ZXJUYWJzUmVzb2x2ZXIsXG4gICAgcHJpdmF0ZSB0YWJzU2VydmljZTogVGFic1NlcnZpY2UsXG4gICAgcHJpdmF0ZSByb3V0ZXI6IFJvdXRlcixcbiAgICBwcml2YXRlIGFwaVNlcnZpY2U6IEFwaVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBpbmplY3RvcjogSW5qZWN0b3JcbiAgKSB7XG4gICAgdGhpcy5yb3V0ZXIuZXZlbnRzXG4gICAgICAucGlwZShmaWx0ZXIoZXZlbnQgPT4gZXZlbnQgaW5zdGFuY2VvZiBBY3RpdmF0aW9uRW5kKSlcbiAgICAgIC5zdWJzY3JpYmUoKGV2ZW50OiBBY3RpdmF0aW9uRW5kKSA9PiB7XG4gICAgICAgIGNvbnN0IGN1cnJlbnRDb250ZXh0ID0gdGhpcy5nZXRDb250ZXh0RGF0YVNuYXBzaG90KGV2ZW50LnNuYXBzaG90KTtcbiAgICAgICAgaWYgKGN1cnJlbnRDb250ZXh0KSB7XG4gICAgICAgICAgdGhpcy5hY3RpdmF0ZWRDb250ZXh0RGF0YSA9IGN1cnJlbnRDb250ZXh0IGFzIENvbnRleHREYXRhO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNvbHZlcyB0aGUgY3VycmVudCBjb250ZXh0IGRhdGEuIElmIG5vIGNvbnRleHQgd2FzIGZvdW5kLCBudWxsIGlzIHJldHVybmVkLlxuICAgKlxuICAgKiBAcGFyYW0gYWN0aXZhdGVkUm91dGUgVGhlIGN1cnJlbnQgYWN0aXZhdGVkIHJvdXRlLlxuICAgKi9cbiAgZ2V0Q29udGV4dERhdGEoXG4gICAgYWN0aXZhdGVkUm91dGU6IEFjdGl2YXRlZFJvdXRlIHwgQWN0aXZhdGVkUm91dGVTbmFwc2hvdFxuICApOiAoRGF0YSAmIENvbnRleHREYXRhKSB8IG51bGwge1xuICAgIGNvbnN0IGRhdGEgPSB0aGlzLmdldENvbnRleHREYXRhU25hcHNob3QodGhpcy5nZXRTbmFwc2hvdChhY3RpdmF0ZWRSb3V0ZSkpO1xuICAgIGlmIChkYXRhPy5jb250ZXh0KSB7XG4gICAgICByZXR1cm4gZGF0YSBhcyBEYXRhICYgQ29udGV4dERhdGE7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSByb3V0ZSBmb3IgdGhlIGdpdmVuIENvbnRleHREYXRhLlxuICAgKlxuICAgKiBAcGFyYW0gY29udGV4dERhdGEgVGhlIENvbnRleHREYXRhIG9iamVjdC5cbiAgICogQHJldHVybnMgQSByb3V0ZSB3aXRoIHRoZSBpZHMgc2V0IGNvcnJlY3RseS5cbiAgICovXG4gIGdldENvbnRleHRSb3V0ZShjb250ZXh0RGF0YTogQ29udGV4dERhdGEpOiBzdHJpbmcge1xuICAgIHJldHVybiBjb250ZXh0RGF0YS5jb250ZXh0LnJlcGxhY2UoLzppZC9nLCBjb250ZXh0RGF0YS5jb250ZXh0RGF0YS5pZCBhcyBzdHJpbmcpO1xuICB9XG5cbiAgLyoqXG4gICAqIFZlcmlmaWVzIGlmIGEgZ2l2ZW4gdXJsIGlzIGEgdmlldyBjb250ZXh0IHJvdXRlLlxuICAgKlxuICAgKiBAcGFyYW0gdXJsIEEgcm91dGUgdXJsLlxuICAgKiBAcGFyYW0gY29udGV4dFRvQ2hlY2sgVGhlIHZpZXcgY29udGV4dChzKSB0byBjaGVjay4gSWYgbm90IHByb3ZpZGVkLCBhbGwgY29udGV4dHMgYXJlIGNoZWNrZWQuXG4gICAqIEByZXR1cm5zIHRydWUgaWYgdGhlIGdpdmVuIHVybCBpcyBhIHZpZXcgY29udGV4dCByb3V0ZS5cbiAgICovXG4gIGlzQ29udGV4dFJvdXRlKHVybDogc3RyaW5nLCBjb250ZXh0VG9DaGVjazogVmlld0NvbnRleHRbXSA9IFtdKTogYm9vbGVhbiB7XG4gICAgY29uc3Qgdmlld0NvbnRleHRzID0gY29udGV4dFRvQ2hlY2subGVuZ3RoID09PSAwID8gT2JqZWN0LnZhbHVlcyhWaWV3Q29udGV4dCkgOiBjb250ZXh0VG9DaGVjaztcbiAgICAvLyByZXBsYWNlIGFsbCA6aWQgcGxhY2Vob2xkZXJzIHdpdGggYSByZWdleCBtYXRjaGVyIGZvciBhIG51bWJlclxuICAgIGNvbnN0IHJlZ2V4TWF0Y2hlcnMgPSB2aWV3Q29udGV4dHMubWFwKGNvbnRleHQgPT4gYC8ke2NvbnRleHQucmVwbGFjZSgvOmlkL2csICcoWzAtOV0rKScpfWApO1xuICAgIGNvbnN0IG1hdGNoaW5nUmVnZXhDb250ZXh0ID0gcmVnZXhNYXRjaGVycy5maW5kKGNvbnRleHQgPT4gbmV3IFJlZ0V4cChjb250ZXh0KS50ZXN0KHVybCkpO1xuICAgIHJldHVybiAhIW1hdGNoaW5nUmVnZXhDb250ZXh0O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXByZWNhdGVkOiBVc2UgU2NvcGVkQ29udGV4dFJvdXRlU2VydmljZSBpbnN0ZWFkLiBXaWxsIGJlIHJlbW92ZWQgaW4gMTAuMjJcbiAgICovXG4gIGluaXQocm91dGU6IEFjdGl2YXRlZFJvdXRlKTogdm9pZCB7XG4gICAgdGhpcy5yb3V0ZXJTdWJzY3JpcHRpb24gPSB0aGlzLnJvdXRlci5ldmVudHNcbiAgICAgIC5waXBlKGZpbHRlcihlID0+IGUgaW5zdGFuY2VvZiBOYXZpZ2F0aW9uRW5kKSlcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4gdGhpcy5yZWRpcmVjdFRvRmlyc3RUYWIoKSk7XG5cbiAgICB0aGlzLmRhdGFTdWJzY3JpcHRpb24gPSByb3V0ZS5kYXRhXG4gICAgICAucGlwZShcbiAgICAgICAgbWVyZ2UodGhpcy51cGRhdGVkQ29udGV4dChyb3V0ZSksIHRoaXMucmVmcmVzaFRyaWdnZXIkKSxcbiAgICAgICAgc3dpdGNoTWFwKCgpID0+IHRoaXMudGFic1Jlc29sdmVyLnJlc29sdmUocm91dGUuc25hcHNob3QpKVxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSh0YWJzID0+IHRoaXMudXBkYXRlVGFicyh0YWJzKSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlcHJlY2F0ZWQ6IFVzZSBTY29wZWRDb250ZXh0Um91dGVTZXJ2aWNlIGluc3RlYWQuIFdpbGwgYmUgcmVtb3ZlZCBpbiAxMC4yMlxuICAgKi9cbiAgZGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmRhdGFTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLnJvdXRlclN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgIHRoaXMubGFzdEFkZGVkVGFicy5mb3JFYWNoKHQgPT4gdGhpcy50YWJzU2VydmljZS5yZW1vdmUodCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbG9hZHMgYWxsIFZpZXdDb250ZXh0cy5cbiAgICovXG4gIHJlZnJlc2hDb250ZXh0KCkge1xuICAgIHRoaXMucmVmcmVzaFRyaWdnZXIkLm5leHQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIGEgbmV3IGNvbnRleHREYXRhIGluIHRoZSBBY3RpdmF0ZWRSb3V0ZS5cbiAgICogQHBhcmFtIGFjdGl2YXRlZFJvdXRlIFRoZSBjdXJyZW50IGFjdGl2YXRlZCByb3V0ZS5cbiAgICogQHBhcmFtIGNvbnRleHREYXRhIE5ldyBjb250ZXh0RGF0YS5cbiAgICovXG4gIHNldENvbnRleHQoYWN0aXZhdGVkUm91dGU6IEFjdGl2YXRlZFJvdXRlLCBjb250ZXh0RGF0YTogSUlkZW50aWZpZWQpOiB2b2lkIHtcbiAgICBjb25zdCBkYXRhID1cbiAgICAgICFhY3RpdmF0ZWRSb3V0ZS5zbmFwc2hvdC5wYXJlbnQgfHwgYWN0aXZhdGVkUm91dGUuc25hcHNob3QuZGF0YS5jb250ZXh0XG4gICAgICAgID8gYWN0aXZhdGVkUm91dGUuc25hcHNob3QuZGF0YVxuICAgICAgICA6IGFjdGl2YXRlZFJvdXRlLnBhcmVudC5zbmFwc2hvdC5kYXRhO1xuXG4gICAgaWYgKCFkYXRhKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGRhdGEuY29udGV4dERhdGEgPSB7IC4uLmNvbnRleHREYXRhIH07XG4gIH1cblxuICAvKipcbiAgICogQGRlcHJlY2F0ZWQ6IFVzZSBTY29wZWRDb250ZXh0Um91dGVTZXJ2aWNlIGluc3RlYWQuIFdpbGwgYmUgcmVtb3ZlZCBpbiAxMC4yMVxuICAgKi9cbiAgdXBkYXRlZENvbnRleHQocm91dGU6IEFjdGl2YXRlZFJvdXRlKTogT2JzZXJ2YWJsZTxBcGlDYWxsPiB7XG4gICAgY29uc3QgeyBkYXRhIH0gPSByb3V0ZS5zbmFwc2hvdDtcbiAgICBjb25zdCBzZXJ2aWNlSW5zdGFuY2UgPSBWaWV3Q29udGV4dFNlcnZpY2VzLmNvbnRleHRUb1NlcnZpY2UoZGF0YS5jb250ZXh0KTtcbiAgICBpZiAoc2VydmljZUluc3RhbmNlKSB7XG4gICAgICBjb25zdCBzZXJ2aWNlID0gdGhpcy5pbmplY3Rvci5nZXQoXG4gICAgICAgIHNlcnZpY2VJbnN0YW5jZSBhcyBUeXBlPEluc3RhbmNlVHlwZTx0eXBlb2Ygc2VydmljZUluc3RhbmNlPj5cbiAgICAgICk7XG4gICAgICBjb25zdCBkZXRhaWxzVXJsUmVnZXggPSAoc2VydmljZSBhcyB0eXBlb2Ygc2VydmljZSAmIHsgZ2V0RGV0YWlsVXJsPzogKC4uLmFyZ3MpID0+IHN0cmluZyB9KVxuICAgICAgICAuZ2V0RGV0YWlsVXJsKGRhdGEuY29udGV4dERhdGEpXG4gICAgICAgIC5yZXBsYWNlKC9cXGQrL2csICc/XFxcXGQqJyk7XG4gICAgICBjb25zdCBjb250ZXh0UmVnZXggPSBuZXcgUmVnRXhwKGRldGFpbHNVcmxSZWdleCwgJ2knKTtcbiAgICAgIGNvbnN0IGNoaWxkcmVuUmVnZXggPSBuZXcgUmVnRXhwKGAke2RldGFpbHNVcmxSZWdleH0vY2hpbGRgLCAnaScpO1xuICAgICAgY29uc3QgZmlsdGVyUmVzcG9uc2UgPSAoeyB1cmwsIG1ldGhvZCB9KSA9PiB7XG4gICAgICAgIGNvbnN0IGNvbnRleHRDaGFuZ2VkID0gY29udGV4dFJlZ2V4LnRlc3QodXJsKSAmJiBbJ1BPU1QnLCAnUFVUJ10uaW5jbHVkZXMobWV0aG9kKTtcbiAgICAgICAgY29uc3QgY2hpbGRyZW5BZmZlY3RlZCA9IGNoaWxkcmVuUmVnZXgudGVzdCh1cmwpICYmIFsnUE9TVCcsICdERUxFVEUnXS5pbmNsdWRlcyhtZXRob2QpO1xuICAgICAgICByZXR1cm4gY29udGV4dENoYW5nZWQgfHwgY2hpbGRyZW5BZmZlY3RlZDtcbiAgICAgIH07XG4gICAgICByZXR1cm4gdGhpcy5hcGlTZXJ2aWNlLmhvb2tSZXNwb25zZShmaWx0ZXJSZXNwb25zZSk7XG4gICAgfVxuICAgIHJldHVybiBORVZFUjtcbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlVGFicyh0YWJzID0gW10pIHtcbiAgICB0aGlzLmxhc3RBZGRlZFRhYnMuZm9yRWFjaCh0ID0+IHRoaXMudGFic1NlcnZpY2UucmVtb3ZlKHQpKTtcbiAgICB0aGlzLmxhc3RBZGRlZFRhYnMgPSB0YWJzO1xuICAgIHRhYnMuZm9yRWFjaCh0ID0+IHRoaXMudGFic1NlcnZpY2UuYWRkKHQpKTtcbiAgICB0aGlzLnJlZGlyZWN0VG9GaXJzdFRhYigpO1xuICB9XG5cbiAgcHJpdmF0ZSByZWRpcmVjdFRvRmlyc3RUYWIoKSB7XG4gICAgY29uc3QgY3VycmVudENvbnRleHRJZCA9ICh0aGlzLnJvdXRlci51cmwubWF0Y2godGhpcy5JRF9SRUdFWCkgfHwgW10pLnNoaWZ0KCk7XG4gICAgaWYgKHRoaXMubmVlZHNSZWRpcmVjdCgpKSB7XG4gICAgICB0aGlzLnRhYnNTZXJ2aWNlLmZpcnN0VGFiJFxuICAgICAgICAucGlwZShmaWx0ZXIoKHRhYjogVGFiKSA9PiB0eXBlb2YgdGFiPy5wYXRoID09PSAnc3RyaW5nJykpXG4gICAgICAgIC5zdWJzY3JpYmUoKHRhYjogVGFiV2l0aFRlbXBsYXRlPHN0cmluZz4pID0+IHtcbiAgICAgICAgICBjb25zdCB0YWJQYXRoSWQgPSAodGFiLnBhdGgubWF0Y2godGhpcy5JRF9SRUdFWCkgfHwgW10pLnNoaWZ0KCk7XG4gICAgICAgICAgaWYgKGN1cnJlbnRDb250ZXh0SWQgPT09IHRhYlBhdGhJZCkge1xuICAgICAgICAgICAgdGhpcy5yb3V0ZXIubmF2aWdhdGVCeVVybCh0YWIucGF0aCwgeyByZXBsYWNlVXJsOiB0cnVlIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBuZWVkc1JlZGlyZWN0KCkge1xuICAgIGNvbnN0IHRyZWU6IFVybFRyZWUgPSB0aGlzLnJvdXRlci5wYXJzZVVybCh0aGlzLnJvdXRlci51cmwpO1xuICAgIGNvbnN0IGdyb3VwczogVXJsU2VnbWVudEdyb3VwID0gdHJlZS5yb290LmNoaWxkcmVuW1BSSU1BUllfT1VUTEVUXTtcblxuICAgIGNvbnN0IGNvbnRleHQgPSB0aGlzLmdldE1hdGNoaW5nQ29udGV4dFJvdXRlKHRoaXMucm91dGVyLnVybCk7XG4gICAgaWYgKCFjb250ZXh0KSB7XG4gICAgICByZXR1cm4gZ3JvdXBzLnNlZ21lbnRzLmxlbmd0aCA9PT0gMjtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGNvbnRleHQuc3BsaXQoJy8nKS5sZW5ndGggPT09IGdyb3Vwcy5zZWdtZW50cy5sZW5ndGg7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZXRNYXRjaGluZ0NvbnRleHRSb3V0ZSh1cmwpIHtcbiAgICBjb25zdCB2aWV3Q29udGV4dHMgPSBPYmplY3QudmFsdWVzKFZpZXdDb250ZXh0KTtcblxuICAgIGNvbnN0IHVybFdpdGhvdXRJZCA9IHVybC5yZXBsYWNlKC9cXGQoLiopL2csICcnKTtcbiAgICBjb25zdCBpZCA9IHZpZXdDb250ZXh0cy5maW5kSW5kZXgoY29udGV4dCA9PiBgLyR7Y29udGV4dC5yZXBsYWNlKCc6aWQnLCAnJyl9YCA9PT0gdXJsV2l0aG91dElkKTtcbiAgICByZXR1cm4gdmlld0NvbnRleHRzW2lkXTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0U25hcHNob3QoXG4gICAgYWN0aXZhdGVkUm91dGU6IEFjdGl2YXRlZFJvdXRlIHwgQWN0aXZhdGVkUm91dGVTbmFwc2hvdFxuICApOiBBY3RpdmF0ZWRSb3V0ZVNuYXBzaG90IHtcbiAgICByZXR1cm4gYWN0aXZhdGVkUm91dGUgaW5zdGFuY2VvZiBBY3RpdmF0ZWRSb3V0ZSB8fFxuICAgICAgISEoYWN0aXZhdGVkUm91dGUgYXMgdW5rbm93biBhcyB7IHNuYXBzaG90OiBBY3RpdmF0ZWRSb3V0ZVNuYXBzaG90IH0pPy5zbmFwc2hvdFxuICAgICAgPyAoYWN0aXZhdGVkUm91dGUgYXMgdW5rbm93biBhcyB7IHNuYXBzaG90OiBBY3RpdmF0ZWRSb3V0ZVNuYXBzaG90IH0pLnNuYXBzaG90XG4gICAgICA6IGFjdGl2YXRlZFJvdXRlO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRDb250ZXh0RGF0YVNuYXBzaG90KFxuICAgIGFjdGl2YXRlZFJvdXRlOiBBY3RpdmF0ZWRSb3V0ZVNuYXBzaG90XG4gICk6IERhdGEgJiBQYXJ0aWFsPENvbnRleHREYXRhPiB7XG4gICAgbGV0IHJvdXRlID0gYWN0aXZhdGVkUm91dGU7XG4gICAgd2hpbGUgKHJvdXRlKSB7XG4gICAgICBpZiAocm91dGUuZGF0YS5jb250ZXh0KSB7XG4gICAgICAgIHJldHVybiByb3V0ZS5kYXRhO1xuICAgICAgfVxuICAgICAgcm91dGUgPSByb3V0ZS5wYXJlbnQ7XG4gICAgfVxuICAgIHJldHVybiB7fTtcbiAgfVxufVxuIl19