import { ViewContainerRef, inject, Attribute, Directive, EventEmitter, Optional, Output, SkipSelf, EnvironmentInjector, Input, InjectionToken, Injectable, reflectComponentType, } from '@angular/core'; import { Router, ActivatedRoute, ChildrenOutletContexts, PRIMARY_OUTLET } from '@angular/router'; import { componentOnReady } from '@ionic/core/components'; import { BehaviorSubject, combineLatest, of } from 'rxjs'; import { distinctUntilChanged, filter, switchMap } from 'rxjs/operators'; import { Config } from '../../providers/config'; import { NavController } from '../../providers/nav-controller'; import { StackController } from './stack-controller'; import { getUrl, isTabSwitch } from './stack-utils'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "@angular/router"; // TODO(FW-2827): types // eslint-disable-next-line @angular-eslint/directive-class-suffix export class IonRouterOutlet { parentOutlet; nativeEl; activatedView = null; tabsPrefix; _swipeGesture; stackCtrl; // Maintain map of activated route proxies for each component instance proxyMap = new WeakMap(); // Keep the latest activated route in a subject for the proxy routes to switch map to currentActivatedRoute$ = new BehaviorSubject(null); activated = null; /** @internal */ get activatedComponentRef() { return this.activated; } _activatedRoute = null; /** * The name of the outlet */ name = PRIMARY_OUTLET; /** @internal */ stackWillChange = new EventEmitter(); /** @internal */ stackDidChange = new EventEmitter(); // eslint-disable-next-line @angular-eslint/no-output-rename activateEvents = new EventEmitter(); // eslint-disable-next-line @angular-eslint/no-output-rename deactivateEvents = new EventEmitter(); parentContexts = inject(ChildrenOutletContexts); location = inject(ViewContainerRef); environmentInjector = inject(EnvironmentInjector); inputBinder = inject(INPUT_BINDER, { optional: true }); /** @nodoc */ supportsBindingToComponentInputs = true; // Ionic providers config = inject(Config); navCtrl = inject(NavController); set animation(animation) { this.nativeEl.animation = animation; } set animated(animated) { this.nativeEl.animated = animated; } set swipeGesture(swipe) { this._swipeGesture = swipe; this.nativeEl.swipeHandler = swipe ? { canStart: () => this.stackCtrl.canGoBack(1) && !this.stackCtrl.hasRunningTask(), onStart: () => this.stackCtrl.startBackTransition(), onEnd: (shouldContinue) => this.stackCtrl.endBackTransition(shouldContinue), } : undefined; } constructor(name, tabs, commonLocation, elementRef, router, zone, activatedRoute, parentOutlet) { this.parentOutlet = parentOutlet; this.nativeEl = elementRef.nativeElement; this.name = name || PRIMARY_OUTLET; this.tabsPrefix = tabs === 'true' ? getUrl(router, activatedRoute) : undefined; this.stackCtrl = new StackController(this.tabsPrefix, this.nativeEl, router, this.navCtrl, zone, commonLocation); this.parentContexts.onChildOutletCreated(this.name, this); } ngOnDestroy() { this.stackCtrl.destroy(); this.inputBinder?.unsubscribeFromRouteData(this); } getContext() { return this.parentContexts.getContext(this.name); } ngOnInit() { this.initializeOutletWithName(); } // Note: Ionic deviates from the Angular Router implementation here initializeOutletWithName() { if (!this.activated) { // If the outlet was not instantiated at the time the route got activated we need to populate // the outlet when it is initialized (ie inside a NgIf) const context = this.getContext(); if (context?.route) { this.activateWith(context.route, context.injector); } } new Promise((resolve) => componentOnReady(this.nativeEl, resolve)).then(() => { if (this._swipeGesture === undefined) { this.swipeGesture = this.config.getBoolean('swipeBackEnabled', this.nativeEl.mode === 'ios'); } }); } get isActivated() { return !!this.activated; } get component() { if (!this.activated) { throw new Error('Outlet is not activated'); } return this.activated.instance; } get activatedRoute() { if (!this.activated) { throw new Error('Outlet is not activated'); } return this._activatedRoute; } get activatedRouteData() { if (this._activatedRoute) { return this._activatedRoute.snapshot.data; } return {}; } /** * Called when the `RouteReuseStrategy` instructs to detach the subtree */ detach() { throw new Error('incompatible reuse strategy'); } /** * Called when the `RouteReuseStrategy` instructs to re-attach a previously detached subtree */ // eslint-disable-next-line @typescript-eslint/no-unused-vars attach(_ref, _activatedRoute) { throw new Error('incompatible reuse strategy'); } deactivate() { if (this.activated) { if (this.activatedView) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const context = this.getContext(); this.activatedView.savedData = new Map(context.children['contexts']); /** * Angular v11.2.10 introduced a change * where this route context is cleared out when * a router-outlet is deactivated, However, * we need this route information in order to * return a user back to the correct tab when * leaving and then going back to the tab context. */ const primaryOutlet = this.activatedView.savedData.get('primary'); if (primaryOutlet && context.route) { primaryOutlet.route = { ...context.route }; } /** * Ensure we are saving the NavigationExtras * data otherwise it will be lost */ this.activatedView.savedExtras = {}; if (context.route) { const contextSnapshot = context.route.snapshot; this.activatedView.savedExtras.queryParams = contextSnapshot.queryParams; this.activatedView.savedExtras.fragment = contextSnapshot.fragment; } } const c = this.component; this.activatedView = null; this.activated = null; this._activatedRoute = null; this.deactivateEvents.emit(c); } } activateWith(activatedRoute, environmentInjector) { if (this.isActivated) { throw new Error('Cannot activate an already activated outlet'); } this._activatedRoute = activatedRoute; let cmpRef; let enteringView = this.stackCtrl.getExistingView(activatedRoute); if (enteringView) { cmpRef = this.activated = enteringView.ref; const saved = enteringView.savedData; if (saved) { // self-restore // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const context = this.getContext(); context.children['contexts'] = saved; } // Updated activated route proxy for this component this.updateActivatedRouteProxy(cmpRef.instance, activatedRoute); } else { const snapshot = activatedRoute._futureSnapshot; /** * Angular 14 introduces a new `loadComponent` property to the route config. * This function will assign a `component` property to the route snapshot. * We check for the presence of this property to determine if the route is * using standalone components. */ const childContexts = this.parentContexts.getOrCreateContext(this.name).children; // We create an activated route proxy object that will maintain future updates for this component // over its lifecycle in the stack. const component$ = new BehaviorSubject(null); const activatedRouteProxy = this.createActivatedRouteProxy(component$, activatedRoute); const injector = new OutletInjector(activatedRouteProxy, childContexts, this.location.injector); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const component = snapshot.routeConfig.component ?? snapshot.component; /** * View components need to be added as a child of ion-router-outlet * for page transitions and swipe to go back. * However, createComponent mounts components as siblings of the * ViewContainerRef. As a result, outletContent must reference * an ng-container inside of ion-router-outlet and not * ion-router-outlet itself. */ cmpRef = this.activated = this.outletContent.createComponent(component, { index: this.outletContent.length, injector, environmentInjector: environmentInjector ?? this.environmentInjector, }); // Once the component is created we can push it to our local subject supplied to the proxy component$.next(cmpRef.instance); // Calling `markForCheck` to make sure we will run the change detection when the // `RouterOutlet` is inside a `ChangeDetectionStrategy.OnPush` component. /** * At this point this.activated has been set earlier * in this function, so it is guaranteed to be non-null. */ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion enteringView = this.stackCtrl.createView(this.activated, activatedRoute); // Store references to the proxy by component this.proxyMap.set(cmpRef.instance, activatedRouteProxy); this.currentActivatedRoute$.next({ component: cmpRef.instance, activatedRoute }); } this.inputBinder?.bindActivatedRouteToOutletComponent(this); this.activatedView = enteringView; /** * The top outlet is set prior to the entering view's transition completing, * so that when we have nested outlets (e.g. ion-tabs inside an ion-router-outlet), * the tabs outlet will be assigned as the top outlet when a view inside tabs is * activated. * * In this scenario, activeWith is called for both the tabs and the root router outlet. * To avoid a race condition, we assign the top outlet synchronously. */ this.navCtrl.setTopOutlet(this); const leavingView = this.stackCtrl.getActiveView(); this.stackWillChange.emit({ enteringView, tabSwitch: isTabSwitch(enteringView, leavingView), }); this.stackCtrl.setActive(enteringView).then((data) => { this.activateEvents.emit(cmpRef.instance); this.stackDidChange.emit(data); }); } /** * Returns `true` if there are pages in the stack to go back. */ canGoBack(deep = 1, stackId) { return this.stackCtrl.canGoBack(deep, stackId); } /** * Resolves to `true` if it the outlet was able to sucessfully pop the last N pages. */ pop(deep = 1, stackId) { return this.stackCtrl.pop(deep, stackId); } /** * Returns the URL of the active page of each stack. */ getLastUrl(stackId) { const active = this.stackCtrl.getLastUrl(stackId); return active ? active.url : undefined; } /** * Returns the RouteView of the active page of each stack. * @internal */ getLastRouteView(stackId) { return this.stackCtrl.getLastUrl(stackId); } /** * Returns the root view in the tab stack. * @internal */ getRootView(stackId) { return this.stackCtrl.getRootUrl(stackId); } /** * Returns the active stack ID. In the context of ion-tabs, it means the active tab. */ getActiveStackId() { return this.stackCtrl.getActiveStackId(); } /** * Since the activated route can change over the life time of a component in an ion router outlet, we create * a proxy so that we can update the values over time as a user navigates back to components already in the stack. */ createActivatedRouteProxy(component$, activatedRoute) { const proxy = new ActivatedRoute(); proxy._futureSnapshot = activatedRoute._futureSnapshot; proxy._routerState = activatedRoute._routerState; proxy.snapshot = activatedRoute.snapshot; proxy.outlet = activatedRoute.outlet; proxy.component = activatedRoute.component; // Setup wrappers for the observables so consumers don't have to worry about switching to new observables as the state updates proxy._paramMap = this.proxyObservable(component$, 'paramMap'); proxy._queryParamMap = this.proxyObservable(component$, 'queryParamMap'); proxy.url = this.proxyObservable(component$, 'url'); proxy.params = this.proxyObservable(component$, 'params'); proxy.queryParams = this.proxyObservable(component$, 'queryParams'); proxy.fragment = this.proxyObservable(component$, 'fragment'); proxy.data = this.proxyObservable(component$, 'data'); return proxy; } /** * Create a wrapped observable that will switch to the latest activated route matched by the given component */ proxyObservable(component$, path) { return component$.pipe( // First wait until the component instance is pushed filter((component) => !!component), switchMap((component) => this.currentActivatedRoute$.pipe(filter((current) => current !== null && current.component === component), switchMap((current) => current && current.activatedRoute[path]), distinctUntilChanged()))); } /** * Updates the activated route proxy for the given component to the new incoming router state */ updateActivatedRouteProxy(component, activatedRoute) { const proxy = this.proxyMap.get(component); if (!proxy) { throw new Error(`Could not find activated route proxy for view`); } proxy._futureSnapshot = activatedRoute._futureSnapshot; proxy._routerState = activatedRoute._routerState; proxy.snapshot = activatedRoute.snapshot; proxy.outlet = activatedRoute.outlet; proxy.component = activatedRoute.component; this.currentActivatedRoute$.next({ component, activatedRoute }); } /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: IonRouterOutlet, deps: [{ token: 'name', attribute: true }, { token: 'tabs', attribute: true, optional: true }, { token: i1.Location }, { token: i0.ElementRef }, { token: i2.Router }, { token: i0.NgZone }, { token: i2.ActivatedRoute }, { token: IonRouterOutlet, optional: true, skipSelf: true }], target: i0.ɵɵFactoryTarget.Directive }); /** @nocollapse */ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: IonRouterOutlet, selector: "ion-router-outlet", inputs: { animated: "animated", animation: "animation", mode: "mode", swipeGesture: "swipeGesture", name: "name" }, outputs: { stackWillChange: "stackWillChange", stackDidChange: "stackDidChange", activateEvents: "activate", deactivateEvents: "deactivate" }, exportAs: ["outlet"], ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: IonRouterOutlet, decorators: [{ type: Directive, args: [{ selector: 'ion-router-outlet', exportAs: 'outlet', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property inputs: ['animated', 'animation', 'mode', 'swipeGesture'], }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Attribute, args: ['name'] }] }, { type: undefined, decorators: [{ type: Optional }, { type: Attribute, args: ['tabs'] }] }, { type: i1.Location }, { type: i0.ElementRef }, { type: i2.Router }, { type: i0.NgZone }, { type: i2.ActivatedRoute }, { type: IonRouterOutlet, decorators: [{ type: SkipSelf }, { type: Optional }] }]; }, propDecorators: { name: [{ type: Input }], stackWillChange: [{ type: Output }], stackDidChange: [{ type: Output }], activateEvents: [{ type: Output, args: ['activate'] }], deactivateEvents: [{ type: Output, args: ['deactivate'] }] } }); class OutletInjector { route; childContexts; parent; constructor(route, childContexts, parent) { this.route = route; this.childContexts = childContexts; this.parent = parent; } get(token, notFoundValue) { if (token === ActivatedRoute) { return this.route; } if (token === ChildrenOutletContexts) { return this.childContexts; } return this.parent.get(token, notFoundValue); } } // TODO: FW-4785 - Remove this once Angular 15 support is dropped const INPUT_BINDER = new InjectionToken(''); /** * Injectable used as a tree-shakable provider for opting in to binding router data to component * inputs. * * The RouterOutlet registers itself with this service when an `ActivatedRoute` is attached or * activated. When this happens, the service subscribes to the `ActivatedRoute` observables (params, * queryParams, data) and sets the inputs of the component using `ComponentRef.setInput`. * Importantly, when an input does not have an item in the route data with a matching key, this * input is set to `undefined`. If it were not done this way, the previous information would be * retained if the data got removed from the route (i.e. if a query parameter is removed). * * The `RouterOutlet` should unregister itself when destroyed via `unsubscribeFromRouteData` so that * the subscriptions are cleaned up. */ class RoutedComponentInputBinder { outletDataSubscriptions = new Map(); bindActivatedRouteToOutletComponent(outlet) { this.unsubscribeFromRouteData(outlet); this.subscribeToRouteData(outlet); } unsubscribeFromRouteData(outlet) { this.outletDataSubscriptions.get(outlet)?.unsubscribe(); this.outletDataSubscriptions.delete(outlet); } subscribeToRouteData(outlet) { const { activatedRoute } = outlet; const dataSubscription = combineLatest([activatedRoute.queryParams, activatedRoute.params, activatedRoute.data]) .pipe(switchMap(([queryParams, params, data], index) => { data = { ...queryParams, ...params, ...data }; // Get the first result from the data subscription synchronously so it's available to // the component as soon as possible (and doesn't require a second change detection). if (index === 0) { return of(data); } // Promise.resolve is used to avoid synchronously writing the wrong data when // two of the Observables in the `combineLatest` stream emit one after // another. return Promise.resolve(data); })) .subscribe((data) => { // Outlet may have been deactivated or changed names to be associated with a different // route if (!outlet.isActivated || !outlet.activatedComponentRef || outlet.activatedRoute !== activatedRoute || activatedRoute.component === null) { this.unsubscribeFromRouteData(outlet); return; } const mirror = reflectComponentType(activatedRoute.component); if (!mirror) { this.unsubscribeFromRouteData(outlet); return; } for (const { templateName } of mirror.inputs) { outlet.activatedComponentRef.setInput(templateName, data[templateName]); } }); this.outletDataSubscriptions.set(outlet, dataSubscription); } /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RoutedComponentInputBinder, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RoutedComponentInputBinder }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RoutedComponentInputBinder, decorators: [{ type: Injectable }] }); export const provideComponentInputBinding = () => { return { provide: INPUT_BINDER, useFactory: componentInputBindingFactory, deps: [Router], }; }; function componentInputBindingFactory(router) { /** * We cast the router to any here, since the componentInputBindingEnabled * property is not available until Angular v16. */ if (router?.componentInputBindingEnabled) { return new RoutedComponentInputBinder(); } return null; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGVyLW91dGxldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL2NvbW1vbi9zcmMvZGlyZWN0aXZlcy9uYXZpZ2F0aW9uL3JvdXRlci1vdXRsZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQU9MLGdCQUFnQixFQUNoQixNQUFNLEVBQ04sU0FBUyxFQUNULFNBQVMsRUFDVCxZQUFZLEVBQ1osUUFBUSxFQUNSLE1BQU0sRUFDTixRQUFRLEVBQ1IsbUJBQW1CLEVBQ25CLEtBQUssRUFDTCxjQUFjLEVBQ2QsVUFBVSxFQUNWLG9CQUFvQixHQUNyQixNQUFNLGVBQWUsQ0FBQztBQUV2QixPQUFPLEVBQWlCLE1BQU0sRUFBRSxjQUFjLEVBQUUsc0JBQXNCLEVBQUUsY0FBYyxFQUFRLE1BQU0saUJBQWlCLENBQUM7QUFDdEgsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFMUQsT0FBTyxFQUFjLGVBQWUsRUFBZ0IsYUFBYSxFQUFFLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNwRixPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRXpFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFFL0QsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3JELE9BQU8sRUFBd0QsTUFBTSxFQUFFLFdBQVcsRUFBRSxNQUFNLGVBQWUsQ0FBQzs7OztBQUUxRyx1QkFBdUI7QUFRdkIsa0VBQWtFO0FBQ2xFLE1BQU0sT0FBZ0IsZUFBZTtJQTRFQTtJQXpFbkMsUUFBUSxDQUE2QjtJQUNyQyxhQUFhLEdBQXFCLElBQUksQ0FBQztJQUN2QyxVQUFVLENBQXFCO0lBRXZCLGFBQWEsQ0FBVztJQUN4QixTQUFT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QUFFRixTQUFTLDRCQUE0QixDQUFDLE1BQWU7SUFDbkQ7OztPQUdHO0lBQ0gsSUFBSyxNQUFjLEVBQUUsNEJBQTRCLEVBQUU7UUFDakQsT0FBTyxJQUFJLDBCQUEwQixFQUFFLENBQUM7S0FDekM7SUFDRCxPQUFPLElBQUksQ0FBQztBQUNkLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBMb2NhdGlvbiB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQge1xuICBDb21wb25lbnRSZWYsXG4gIEVsZW1lbnRSZWYsXG4gIEluamVjdG9yLFxuICBOZ1pvbmUsXG4gIE9uRGVzdHJveSxcbiAgT25Jbml0LFxuICBWaWV3Q29udGFpbmVyUmVmLFxuICBpbmplY3QsXG4gIEF0dHJpYnV0ZSxcbiAgRGlyZWN0aXZlLFxuICBFdmVudEVtaXR0ZXIsXG4gIE9wdGlvbmFsLFxuICBPdXRwdXQsXG4gIFNraXBTZWxmLFxuICBFbnZpcm9ubWVudEluamVjdG9yLFxuICBJbnB1dCxcbiAgSW5qZWN0aW9uVG9rZW4sXG4gIEluamVjdGFibGUsXG4gIHJlZmxlY3RDb21wb25lbnRUeXBlLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB0eXBlIHsgUHJvdmlkZXIgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE91dGxldENvbnRleHQsIFJvdXRlciwgQWN0aXZhdGVkUm91dGUsIENoaWxkcmVuT3V0bGV0Q29udGV4dHMsIFBSSU1BUllfT1VUTEVULCBEYXRhIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IGNvbXBvbmVudE9uUmVhZHkgfSBmcm9tICdAaW9uaWMvY29yZS9jb21wb25lbnRzJztcbmltcG9ydCB0eXBlIHsgQW5pbWF0aW9uQnVpbGRlciB9IGZyb20gJ0Bpb25pYy9jb3JlL2NvbXBvbmVudHMnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgQmVoYXZpb3JTdWJqZWN0LCBTdWJzY3JpcHRpb24sIGNvbWJpbmVMYXRlc3QsIG9mIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBkaXN0aW5jdFVudGlsQ2hhbmdlZCwgZmlsdGVyLCBzd2l0Y2hNYXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbmltcG9ydCB7IENvbmZpZyB9IGZyb20gJy4uLy4uL3Byb3ZpZGVycy9jb25maWcnO1xuaW1wb3J0IHsgTmF2Q29udHJvbGxlciB9IGZyb20gJy4uLy4uL3Byb3ZpZGVycy9uYXYtY29udHJvbGxlcic7XG5cbmltcG9ydCB7IFN0YWNrQ29udHJvbGxlciB9IGZyb20gJy4vc3RhY2stY29udHJvbGxlcic7XG5pbXBvcnQgeyBSb3V0ZVZpZXcsIFN0YWNrRGlkQ2hhbmdlRXZlbnQsIFN0YWNrV2lsbENoYW5nZUV2ZW50LCBnZXRVcmwsIGlzVGFiU3dpdGNoIH0gZnJvbSAnLi9zdGFjay11dGlscyc7XG5cbi8vIFRPRE8oRlctMjgyNyk6IHR5cGVzXG5cbkBEaXJlY3RpdmUoe1xuICBzZWxlY3RvcjogJ2lvbi1yb3V0ZXItb3V0bGV0JyxcbiAgZXhwb3J0QXM6ICdvdXRsZXQnLFxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQGFuZ3VsYXItZXNsaW50L25vLWlucHV0cy1tZXRhZGF0YS1wcm9wZXJ0eVxuICBpbnB1dHM6IFsnYW5pbWF0ZWQnLCAnYW5pbWF0aW9uJywgJ21vZGUnLCAnc3dpcGVHZXN0dXJlJ10sXG59KVxuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEBhbmd1bGFyLWVzbGludC9kaXJlY3RpdmUtY2xhc3Mtc3VmZml4XG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgSW9uUm91dGVyT3V0bGV0IGltcGxlbWVudHMgT25EZXN0cm95LCBPbkluaXQge1xuICBhYnN0cmFjdCBvdXRsZXRDb250ZW50OiBhbnk7XG5cbiAgbmF0aXZlRWw6IEhUTUxJb25Sb3V0ZXJPdXRsZXRFbGVtZW50O1xuICBhY3RpdmF0ZWRWaWV3OiBSb3V0ZVZpZXcgfCBudWxsID0gbnVsbDtcbiAgdGFic1ByZWZpeDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4gIHByaXZhdGUgX3N3aXBlR2VzdHVyZT86IGJvb2xlYW47XG4gIHByaXZhdGUgc3RhY2tDdHJsOiBTdGFja0NvbnRyb2xsZXI7XG5cbiAgLy8gTWFpbnRhaW4gbWFwIG9mIGFjdGl2YXRlZCByb3V0ZSBwcm94aWVzIGZvciBlYWNoIGNvbXBvbmVudCBpbnN0YW5jZVxuICBwcml2YXRlIHByb3h5TWFwID0gbmV3IFdlYWtNYXA8YW55LCBBY3RpdmF0ZWRSb3V0ZT4oKTtcbiAgLy8gS2VlcCB0aGUgbGF0ZXN0IGFjdGl2YXRlZCByb3V0ZSBpbiBhIHN1YmplY3QgZm9yIHRoZSBwcm94eSByb3V0ZXMgdG8gc3dpdGNoIG1hcCB0b1xuICBwcml2YXRlIGN1cnJlbnRBY3RpdmF0ZWRSb3V0ZSQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PHsgY29tcG9uZW50OiBhbnk7IGFjdGl2YXRlZFJvdXRlOiBBY3RpdmF0ZWRSb3V0ZSB9IHwgbnVsbD4obnVsbCk7XG5cbiAgcHJpdmF0ZSBhY3RpdmF0ZWQ6IENvbXBvbmVudFJlZjxhbnk+IHwgbnVsbCA9IG51bGw7XG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgZ2V0IGFjdGl2YXRlZENvbXBvbmVudFJlZigpOiBDb21wb25lbnRSZWY8YW55PiB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmFjdGl2YXRlZDtcbiAgfVxuICBwcml2YXRlIF9hY3RpdmF0ZWRSb3V0ZTogQWN0aXZhdGVkUm91dGUgfCBudWxsID0gbnVsbDtcblxuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIG91dGxldFxuICAgKi9cbiAgQElucHV0KCkgbmFtZSA9IFBSSU1BUllfT1VUTEVUO1xuXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgQE91dHB1dCgpIHN0YWNrV2lsbENoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8U3RhY2tXaWxsQ2hhbmdlRXZlbnQ+KCk7XG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgQE91dHB1dCgpIHN0YWNrRGlkQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxTdGFja0RpZENoYW5nZUV2ZW50PigpO1xuXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAYW5ndWxhci1lc2xpbnQvbm8tb3V0cHV0LXJlbmFtZVxuICBAT3V0cHV0KCdhY3RpdmF0ZScpIGFjdGl2YXRlRXZlbnRzID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAYW5ndWxhci1lc2xpbnQvbm8tb3V0cHV0LXJlbmFtZVxuICBAT3V0cHV0KCdkZWFjdGl2YXRlJykgZGVhY3RpdmF0ZUV2ZW50cyA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xuXG4gIHByaXZhdGUgcGFyZW50Q29udGV4dHMgPSBpbmplY3QoQ2hpbGRyZW5PdXRsZXRDb250ZXh0cyk7XG4gIHByaXZhdGUgbG9jYXRpb24gPSBpbmplY3QoVmlld0NvbnRhaW5lclJlZik7XG4gIHByaXZhdGUgZW52aXJvbm1lbnRJbmplY3RvciA9IGluamVjdChFbnZpcm9ubWVudEluamVjdG9yKTtcbiAgcHJpdmF0ZSBpbnB1dEJpbmRlciA9IGluamVjdChJTlBVVF9CSU5ERVIsIHsgb3B0aW9uYWw6IHRydWUgfSk7XG4gIC8qKiBAbm9kb2MgKi9cbiAgcmVhZG9ubHkgc3VwcG9ydHNCaW5kaW5nVG9Db21wb25lbnRJbnB1dHMgPSB0cnVlO1xuXG4gIC8vIElvbmljIHByb3ZpZGVyc1xuICBwcml2YXRlIGNvbmZpZyA9IGluamVjdChDb25maWcpO1xuICBwcml2YXRlIG5hdkN0cmwgPSBpbmplY3QoTmF2Q29udHJvbGxlcik7XG5cbiAgc2V0IGFuaW1hdGlvbihhbmltYXRpb246IEFuaW1hdGlvbkJ1aWxkZXIpIHtcbiAgICB0aGlzLm5hdGl2ZUVsLmFuaW1hdGlvbiA9IGFuaW1hdGlvbjtcbiAgfVxuXG4gIHNldCBhbmltYXRlZChhbmltYXRlZDogYm9vbGVhbikge1xuICAgIHRoaXMubmF0aXZlRWwuYW5pbWF0ZWQgPSBhbmltYXRlZDtcbiAgfVxuXG4gIHNldCBzd2lwZUdlc3R1cmUoc3dpcGU6IGJvb2xlYW4pIHtcbiAgICB0aGlzLl9zd2lwZUdlc3R1cmUgPSBzd2lwZTtcblxuICAgIHRoaXMubmF0aXZlRWwuc3dpcGVIYW5kbGVyID0gc3dpcGVcbiAgICAgID8ge1xuICAgICAgICAgIGNhblN0YXJ0OiAoKSA9PiB0aGlzLnN0YWNrQ3RybC5jYW5Hb0JhY2soMSkgJiYgIXRoaXMuc3RhY2tDdHJsLmhhc1J1bm5pbmdUYXNrKCksXG4gICAgICAgICAgb25TdGFydDogKCkgPT4gdGhpcy5zdGFja0N0cmwuc3RhcnRCYWNrVHJhbnNpdGlvbigpLFxuICAgICAgICAgIG9uRW5kOiAoc2hvdWxkQ29udGludWUpID0+IHRoaXMuc3RhY2tDdHJsLmVuZEJhY2tUcmFuc2l0aW9uKHNob3VsZENvbnRpbnVlKSxcbiAgICAgICAgfVxuICAgICAgOiB1bmRlZmluZWQ7XG4gIH1cblxuICBjb25zdHJ1Y3RvcihcbiAgICBAQXR0cmlidXRlKCduYW1lJykgbmFtZTogc3RyaW5nLFxuICAgIEBPcHRpb25hbCgpIEBBdHRyaWJ1dGUoJ3RhYnMnKSB0YWJzOiBzdHJpbmcsXG4gICAgY29tbW9uTG9jYXRpb246IExvY2F0aW9uLFxuICAgIGVsZW1lbnRSZWY6IEVsZW1lbnRSZWYsXG4gICAgcm91dGVyOiBSb3V0ZXIsXG4gICAgem9uZTogTmdab25lLFxuICAgIGFjdGl2YXRlZFJvdXRlOiBBY3RpdmF0ZWRSb3V0ZSxcbiAgICBAU2tpcFNlbGYoKSBAT3B0aW9uYWwoKSByZWFkb25seSBwYXJlbnRPdXRsZXQ/OiBJb25Sb3V0ZXJPdXRsZXRcbiAgKSB7XG4gICAgdGhpcy5uYXRpdmVFbCA9IGVsZW1lbnRSZWYubmF0aXZlRWxlbWVudDtcbiAgICB0aGlzLm5hbWUgPSBuYW1lIHx8IFBSSU1BUllfT1VUTEVUO1xuICAgIHRoaXMudGFic1ByZWZpeCA9IHRhYnMgPT09ICd0cnVlJyA/IGdldFVybChyb3V0ZXIsIGFjdGl2YXRlZFJvdXRlKSA6IHVuZGVmaW5lZDtcbiAgICB0aGlzLnN0YWNrQ3RybCA9IG5ldyBTdGFja0NvbnRyb2xsZXIodGhpcy50YWJzUHJlZml4LCB0aGlzLm5hdGl2ZUVsLCByb3V0ZXIsIHRoaXMubmF2Q3RybCwgem9uZSwgY29tbW9uTG9jYXRpb24pO1xuICAgIHRoaXMucGFyZW50Q29udGV4dHMub25DaGlsZE91dGxldENyZWF0ZWQodGhpcy5uYW1lLCB0aGlzIGFzIGFueSk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLnN0YWNrQ3RybC5kZXN0cm95KCk7XG4gICAgdGhpcy5pbnB1dEJpbmRlcj8udW5zdWJzY3JpYmVGcm9tUm91dGVEYXRhKHRoaXMpO1xuICB9XG5cbiAgZ2V0Q29udGV4dCgpOiBPdXRsZXRDb250ZXh0IHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMucGFyZW50Q29udGV4dHMuZ2V0Q29udGV4dCh0aGlzLm5hbWUpO1xuICB9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5pbml0aWFsaXplT3V0bGV0V2l0aE5hbWUoKTtcbiAgfVxuXG4gIC8vIE5vdGU6IElvbmljIGRldmlhdGVzIGZyb20gdGhlIEFuZ3VsYXIgUm91dGVyIGltcGxlbWVudGF0aW9uIGhlcmVcbiAgcHJpdmF0ZSBpbml0aWFsaXplT3V0bGV0V2l0aE5hbWUoKSB7XG4gICAgaWYgKCF0aGlzLmFjdGl2YXRlZCkge1xuICAgICAgLy8gSWYgdGhlIG91dGxldCB3YXMgbm90IGluc3RhbnRpYXRlZCBhdCB0aGUgdGltZSB0aGUgcm91dGUgZ290IGFjdGl2YXRlZCB3ZSBuZWVkIHRvIHBvcHVsYXRlXG4gICAgICAvLyB0aGUgb3V0bGV0IHdoZW4gaXQgaXMgaW5pdGlhbGl6ZWQgKGllIGluc2lkZSBhIE5nSWYpXG4gICAgICBjb25zdCBjb250ZXh0ID0gdGhpcy5nZXRDb250ZXh0KCk7XG4gICAgICBpZiAoY29udGV4dD8ucm91dGUpIHtcbiAgICAgICAgdGhpcy5hY3RpdmF0ZVdpdGgoY29udGV4dC5yb3V0ZSwgY29udGV4dC5pbmplY3Rvcik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IGNvbXBvbmVudE9uUmVhZHkodGhpcy5uYXRpdmVFbCwgcmVzb2x2ZSkpLnRoZW4oKCkgPT4ge1xuICAgICAgaWYgKHRoaXMuX3N3aXBlR2VzdHVyZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRoaXMuc3dpcGVHZXN0dXJlID0gdGhpcy5jb25maWcuZ2V0Qm9vbGVhbignc3dpcGVCYWNrRW5hYmxlZCcsICh0aGlzLm5hdGl2ZUVsIGFzIGFueSkubW9kZSA9PT0gJ2lvcycpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgZ2V0IGlzQWN0aXZhdGVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhIXRoaXMuYWN0aXZhdGVkO1xuICB9XG5cbiAgZ2V0IGNvbXBvbmVudCgpOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gICAgaWYgKCF0aGlzLmFjdGl2YXRlZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdPdXRsZXQgaXMgbm90IGFjdGl2YXRlZCcpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5hY3RpdmF0ZWQuaW5zdGFuY2U7XG4gIH1cblxuICBnZXQgYWN0aXZhdGVkUm91dGUoKTogQWN0aXZhdGVkUm91dGUge1xuICAgIGlmICghdGhpcy5hY3RpdmF0ZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignT3V0bGV0IGlzIG5vdCBhY3RpdmF0ZWQnKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX2FjdGl2YXRlZFJvdXRlIGFzIEFjdGl2YXRlZFJvdXRlO1xuICB9XG5cbiAgZ2V0IGFjdGl2YXRlZFJvdXRlRGF0YSgpOiBEYXRhIHtcbiAgICBpZiAodGhpcy5fYWN0aXZhdGVkUm91dGUpIHtcbiAgICAgIHJldHVybiB0aGlzLl9hY3RpdmF0ZWRSb3V0ZS5zbmFwc2hvdC5kYXRhO1xuICAgIH1cbiAgICByZXR1cm4ge307XG4gIH1cblxuICAvKipcbiAgICogQ2FsbGVkIHdoZW4gdGhlIGBSb3V0ZVJldXNlU3RyYXRlZ3lgIGluc3RydWN0cyB0byBkZXRhY2ggdGhlIHN1YnRyZWVcbiAgICovXG4gIGRldGFjaCgpOiBDb21wb25lbnRSZWY8YW55PiB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdpbmNvbXBhdGlibGUgcmV1c2Ugc3RyYXRlZ3knKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxsZWQgd2hlbiB0aGUgYFJvdXRlUmV1c2VTdHJhdGVneWAgaW5zdHJ1Y3RzIHRvIHJlLWF0dGFjaCBhIHByZXZpb3VzbHkgZGV0YWNoZWQgc3VidHJlZVxuICAgKi9cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICBhdHRhY2goX3JlZjogQ29tcG9uZW50UmVmPGFueT4sIF9hY3RpdmF0ZWRSb3V0ZTogQWN0aXZhdGVkUm91dGUpOiB2b2lkIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2luY29tcGF0aWJsZSByZXVzZSBzdHJhdGVneScpO1xuICB9XG5cbiAgZGVhY3RpdmF0ZSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5hY3RpdmF0ZWQpIHtcbiAgICAgIGlmICh0aGlzLmFjdGl2YXRlZFZpZXcpIHtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1ub24tbnVsbC1hc3NlcnRpb25cbiAgICAgICAgY29uc3QgY29udGV4dCA9IHRoaXMuZ2V0Q29udGV4dCgpITtcbiAgICAgICAgdGhpcy5hY3RpdmF0ZWRWaWV3LnNhdmVkRGF0YSA9IG5ldyBNYXAoY29udGV4dC5jaGlsZHJlblsnY29udGV4dHMnXSk7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEFuZ3VsYXIgdjExLjIuMTAgaW50cm9kdWNlZCBhIGNoYW5nZVxuICAgICAgICAgKiB3aGVyZSB0aGlzIHJvdXRlIGNvbnRleHQgaXMgY2xlYXJlZCBvdXQgd2hlblxuICAgICAgICAgKiBhIHJvdXRlci1vdXRsZXQgaXMgZGVhY3RpdmF0ZWQsIEhvd2V2ZXIsXG4gICAgICAgICAqIHdlIG5lZWQgdGhpcyByb3V0ZSBpbmZvcm1hdGlvbiBpbiBvcmRlciB0b1xuICAgICAgICAgKiByZXR1cm4gYSB1c2VyIGJhY2sgdG8gdGhlIGNvcnJlY3QgdGFiIHdoZW5cbiAgICAgICAgICogbGVhdmluZyBhbmQgdGhlbiBnb2luZyBiYWNrIHRvIHRoZSB0YWIgY29udGV4dC5cbiAgICAgICAgICovXG4gICAgICAgIGNvbnN0IHByaW1hcnlPdXRsZXQgPSB0aGlzLmFjdGl2YXRlZFZpZXcuc2F2ZWREYXRhLmdldCgncHJpbWFyeScpO1xuICAgICAgICBpZiAocHJpbWFyeU91dGxldCAmJiBjb250ZXh0LnJvdXRlKSB7XG4gICAgICAgICAgcHJpbWFyeU91dGxldC5yb3V0ZSA9IHsgLi4uY29udGV4dC5yb3V0ZSB9O1xuICAgICAgICB9XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVuc3VyZSB3ZSBhcmUgc2F2aW5nIHRoZSBOYXZpZ2F0aW9uRXh0cmFzXG4gICAgICAgICAqIGRhdGEgb3RoZXJ3aXNlIGl0IHdpbGwgYmUgbG9zdFxuICAgICAgICAgKi9cbiAgICAgICAgdGhpcy5hY3RpdmF0ZWRWaWV3LnNhdmVkRXh0cmFzID0ge307XG4gICAgICAgIGlmIChjb250ZXh0LnJvdXRlKSB7XG4gICAgICAgICAgY29uc3QgY29udGV4dFNuYXBzaG90ID0gY29udGV4dC5yb3V0ZS5zbmFwc2hvdDtcblxuICAgICAgICAgIHRoaXMuYWN0aXZhdGVkVmlldy5zYXZlZEV4dHJhcy5xdWVyeVBhcmFtcyA9IGNvbnRleHRTbmFwc2hvdC5xdWVyeVBhcmFtcztcbiAgICAgICAgICAodGhpcy5hY3RpdmF0ZWRWaWV3LnNhdmVkRXh0cmFzLmZyYWdtZW50IGFzIHN0cmluZyB8IG51bGwpID0gY29udGV4dFNuYXBzaG90LmZyYWdtZW50O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBjb25zdCBjID0gdGhpcy5jb21wb25lbnQ7XG4gICAgICB0aGlzLmFjdGl2YXRlZFZpZXcgPSBudWxsO1xuICAgICAgdGhpcy5hY3RpdmF0ZWQgPSBudWxsO1xuICAgICAgdGhpcy5fYWN0aXZhdGVkUm91dGUgPSBudWxsO1xuICAgICAgdGhpcy5kZWFjdGl2YXRlRXZlbnRzLmVtaXQoYyk7XG4gICAgfVxuICB9XG5cbiAgYWN0aXZhdGVXaXRoKGFjdGl2YXRlZFJvdXRlOiBBY3RpdmF0ZWRSb3V0ZSwgZW52aXJvbm1lbnRJbmplY3RvcjogRW52aXJvbm1lbnRJbmplY3RvciB8IG51bGwpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5pc0FjdGl2YXRlZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgYWN0aXZhdGUgYW4gYWxyZWFkeSBhY3RpdmF0ZWQgb3V0bGV0Jyk7XG4gICAgfVxuICAgIHRoaXMuX2FjdGl2YXRlZFJvdXRlID0gYWN0aXZhdGVkUm91dGU7XG5cbiAgICBsZXQgY21wUmVmOiBhbnk7XG4gICAgbGV0IGVudGVyaW5nVmlldyA9IHRoaXMuc3RhY2tDdHJsLmdldEV4aXN0aW5nVmlldyhhY3RpdmF0ZWRSb3V0ZSk7XG4gICAgaWYgKGVudGVyaW5nVmlldykge1xuICAgICAgY21wUmVmID0gdGhpcy5hY3RpdmF0ZWQgPSBlbnRlcmluZ1ZpZXcucmVmO1xuICAgICAgY29uc3Qgc2F2ZWQgPSBlbnRlcmluZ1ZpZXcuc2F2ZWREYXRhO1xuICAgICAgaWYgKHNhdmVkKSB7XG4gICAgICAgIC8vIHNlbGYtcmVzdG9yZVxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLW5vbi1udWxsLWFzc2VydGlvblxuICAgICAgICBjb25zdCBjb250ZXh0ID0gdGhpcy5nZXRDb250ZXh0KCkhO1xuICAgICAgICBjb250ZXh0LmNoaWxkcmVuWydjb250ZXh0cyddID0gc2F2ZWQ7XG4gICAgICB9XG4gICAgICAvLyBVcGRhdGVkIGFjdGl2YXRlZCByb3V0ZSBwcm94eSBmb3IgdGhpcyBjb21wb25lbnRcbiAgICAgIHRoaXMudXBkYXRlQWN0aXZhdGVkUm91dGVQcm94eShjbXBSZWYuaW5zdGFuY2UsIGFjdGl2YXRlZFJvdXRlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3Qgc25hcHNob3QgPSAoYWN0aXZhdGVkUm91dGUgYXMgYW55KS5fZnV0dXJlU25hcHNob3Q7XG5cbiAgICAgIC8qKlxuICAgICAgICogQW5ndWxhciAxNCBpbnRyb2R1Y2VzIGEgbmV3IGBsb2FkQ29tcG9uZW50YCBwcm9wZXJ0eSB0byB0aGUgcm91dGUgY29uZmlnLlxuICAgICAgICogVGhpcyBmdW5jdGlvbiB3aWxsIGFzc2lnbiBhIGBjb21wb25lbnRgIHByb3BlcnR5IHRvIHRoZSByb3V0ZSBzbmFwc2hvdC5cbiAgICAgICAqIFdlIGNoZWNrIGZvciB0aGUgcHJlc2VuY2Ugb2YgdGhpcyBwcm9wZXJ0eSB0byBkZXRlcm1pbmUgaWYgdGhlIHJvdXRlIGlzXG4gICAgICAgKiB1c2luZyBzdGFuZGFsb25lIGNvbXBvbmVudHMuXG4gICAgICAgKi9cbiAgICAgIGNvbnN0IGNoaWxkQ29udGV4dHMgPSB0aGlzLnBhcmVudENvbnRleHRzLmdldE9yQ3JlYXRlQ29udGV4dCh0aGlzLm5hbWUpLmNoaWxkcmVuO1xuXG4gICAgICAvLyBXZSBjcmVhdGUgYW4gYWN0aXZhdGVkIHJvdXRlIHByb3h5IG9iamVjdCB0aGF0IHdpbGwgbWFpbnRhaW4gZnV0dXJlIHVwZGF0ZXMgZm9yIHRoaXMgY29tcG9uZW50XG4gICAgICAvLyBvdmVyIGl0cyBsaWZlY3ljbGUgaW4gdGhlIHN0YWNrLlxuICAgICAgY29uc3QgY29tcG9uZW50JCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8YW55PihudWxsKTtcbiAgICAgIGNvbnN0IGFjdGl2YXRlZFJvdXRlUHJveHkgPSB0aGlzLmNyZWF0ZUFjdGl2YXRlZFJvdXRlUHJveHkoY29tcG9uZW50JCwgYWN0aXZhdGVkUm91dGUpO1xuXG4gICAgICBjb25zdCBpbmplY3RvciA9IG5ldyBPdXRsZXRJbmplY3RvcihhY3RpdmF0ZWRSb3V0ZVByb3h5LCBjaGlsZENvbnRleHRzLCB0aGlzLmxvY2F0aW9uLmluamVjdG9yKTtcblxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1ub24tbnVsbC1hc3NlcnRpb25cbiAgICAgIGNvbnN0IGNvbXBvbmVudCA9IHNuYXBzaG90LnJvdXRlQ29uZmlnIS5jb21wb25lbnQgPz8gc25hcHNob3QuY29tcG9uZW50O1xuXG4gICAgICAvKipcbiAgICAgICAqIFZpZXcgY29tcG9uZW50cyBuZWVkIHRvIGJlIGFkZGVkIGFzIGEgY2hpbGQgb2YgaW9uLXJvdXRlci1vdXRsZXRcbiAgICAgICAqIGZvciBwYWdlIHRyYW5zaXRpb25zIGFuZCBzd2lwZSB0byBnbyBiYWNrLlxuICAgICAgICogSG93ZXZlciwgY3JlYXRlQ29tcG9uZW50IG1vdW50cyBjb21wb25lbnRzIGFzIHNpYmxpbmdzIG9mIHRoZVxuICAgICAgICogVmlld0NvbnRhaW5lclJlZi4gQXMgYSByZXN1bHQsIG91dGxldENvbnRlbnQgbXVzdCByZWZlcmVuY2VcbiAgICAgICAqIGFuIG5nLWNvbnRhaW5lciBpbnNpZGUgb2YgaW9uLXJvdXRlci1vdXRsZXQgYW5kIG5vdFxuICAgICAgICogaW9uLXJvdXRlci1vdXRsZXQgaXRzZWxmLlxuICAgICAgICovXG4gICAgICBjbXBSZWYgPSB0aGlzLmFjdGl2YXRlZCA9IHRoaXMub3V0bGV0Q29udGVudC5jcmVhdGVDb21wb25lbnQoY29tcG9uZW50LCB7XG4gICAgICAgIGluZGV4OiB0aGlzLm91dGxldENvbnRlbnQubGVuZ3RoLFxuICAgICAgICBpbmplY3RvcixcbiAgICAgICAgZW52aXJvbm1lbnRJbmplY3RvcjogZW52aXJvbm1lbnRJbmplY3RvciA/PyB0aGlzLmVudmlyb25tZW50SW5qZWN0b3IsXG4gICAgICB9KTtcblxuICAgICAgLy8gT25jZSB0aGUgY29tcG9uZW50IGlzIGNyZWF0ZWQgd2UgY2FuIHB1c2ggaXQgdG8gb3VyIGxvY2FsIHN1YmplY3Qgc3VwcGxpZWQgdG8gdGhlIHByb3h5XG4gICAgICBjb21wb25lbnQkLm5leHQoY21wUmVmLmluc3RhbmNlKTtcblxuICAgICAgLy8gQ2FsbGluZyBgbWFya0ZvckNoZWNrYCB0byBtYWtlIHN1cmUgd2Ugd2lsbCBydW4gdGhlIGNoYW5nZSBkZXRlY3Rpb24gd2hlbiB0aGVcbiAgICAgIC8vIGBSb3V0ZXJPdXRsZXRgIGlzIGluc2lkZSBhIGBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2hgIGNvbXBvbmVudC5cblxuICAgICAgLyoqXG4gICAgICAgKiBBdCB0aGlzIHBvaW50IHRoaXMuYWN0aXZhdGVkIGhhcyBiZWVuIHNldCBlYXJsaWVyXG4gICAgICAgKiBpbiB0aGlzIGZ1bmN0aW9uLCBzbyBpdCBpcyBndWFyYW50ZWVkIHRvIGJlIG5vbi1udWxsLlxuICAgICAgICovXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLW5vbi1udWxsLWFzc2VydGlvblxuICAgICAgZW50ZXJpbmdWaWV3ID0gdGhpcy5zdGFja0N0cmwuY3JlYXRlVmlldyh0aGlzLmFjdGl2YXRlZCEsIGFjdGl2YXRlZFJvdXRlKTtcblxuICAgICAgLy8gU3RvcmUgcmVmZXJlbmNlcyB0byB0aGUgcHJveHkgYnkgY29tcG9uZW50XG4gICAgICB0aGlzLnByb3h5TWFwLnNldChjbXBSZWYuaW5zdGFuY2UsIGFjdGl2YXRlZFJvdXRlUHJveHkpO1xuICAgICAgdGhpcy5jdXJyZW50QWN0aXZhdGVkUm91dGUkLm5leHQoeyBjb21wb25lbnQ6IGNtcFJlZi5pbnN0YW5jZSwgYWN0aXZhdGVkUm91dGUgfSk7XG4gICAgfVxuXG4gICAgdGhpcy5pbnB1dEJpbmRlcj8uYmluZEFjdGl2YXRlZFJvdXRlVG9PdXRsZXRDb21wb25lbnQodGhpcyk7XG5cbiAgICB0aGlzLmFjdGl2YXRlZFZpZXcgPSBlbnRlcmluZ1ZpZXc7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdG9wIG91dGxldCBpcyBzZXQgcHJpb3IgdG8gdGhlIGVudGVyaW5nIHZpZXcncyB0cmFuc2l0aW9uIGNvbXBsZXRpbmcsXG4gICAgICogc28gdGhhdCB3aGVuIHdlIGhhdmUgbmVzdGVkIG91dGxldHMgKGUuZy4gaW9uLXRhYnMgaW5zaWRlIGFuIGlvbi1yb3V0ZXItb3V0bGV0KSxcbiAgICAgKiB0aGUgdGFicyBvdXRsZXQgd2lsbCBiZSBhc3NpZ25lZCBhcyB0aGUgdG9wIG91dGxldCB3aGVuIGEgdmlldyBpbnNpZGUgdGFicyBpc1xuICAgICAqIGFjdGl2YXRlZC5cbiAgICAgKlxuICAgICAqIEluIHRoaXMgc2NlbmFyaW8sIGFjdGl2ZVdpdGggaXMgY2FsbGVkIGZvciBib3RoIHRoZSB0YWJzIGFuZCB0aGUgcm9vdCByb3V0ZXIgb3V0bGV0LlxuICAgICAqIFRvIGF2b2lkIGEgcmFjZSBjb25kaXRpb24sIHdlIGFzc2lnbiB0aGUgdG9wIG91dGxldCBzeW5jaHJvbm91c2x5LlxuICAgICAqL1xuICAgIHRoaXMubmF2Q3RybC5zZXRUb3BPdXRsZXQodGhpcyk7XG5cbiAgICBjb25zdCBsZWF2aW5nVmlldyA9IHRoaXMuc3RhY2tDdHJsLmdldEFjdGl2ZVZpZXcoKTtcblxuICAgIHRoaXMuc3RhY2tXaWxsQ2hhbmdlLmVtaXQoe1xuICAgICAgZW50ZXJpbmdWaWV3LFxuICAgICAgdGFiU3dpdGNoOiBpc1RhYlN3aXRjaChlbnRlcmluZ1ZpZXcsIGxlYXZpbmdWaWV3KSxcbiAgICB9KTtcblxuICAgIHRoaXMuc3RhY2tDdHJsLnNldEFjdGl2ZShlbnRlcmluZ1ZpZXcpLnRoZW4oKGRhdGEpID0+IHtcbiAgICAgIHRoaXMuYWN0aXZhdGVFdmVudHMuZW1pdChjbXBSZWYuaW5zdGFuY2UpO1xuICAgICAgdGhpcy5zdGFja0RpZENoYW5nZS5lbWl0KGRhdGEpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYHRydWVgIGlmIHRoZXJlIGFyZSBwYWdlcyBpbiB0aGUgc3RhY2sgdG8gZ28gYmFjay5cbiAgICovXG4gIGNhbkdvQmFjayhkZWVwID0gMSwgc3RhY2tJZD86IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnN0YWNrQ3RybC5jYW5Hb0JhY2soZGVlcCwgc3RhY2tJZCk7XG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZXMgdG8gYHRydWVgIGlmIGl0IHRoZSBvdXRsZXQgd2FzIGFibGUgdG8gc3VjZXNzZnVsbHkgcG9wIHRoZSBsYXN0IE4gcGFnZXMuXG4gICAqL1xuICBwb3AoZGVlcCA9IDEsIHN0YWNrSWQ/OiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICByZXR1cm4gdGhpcy5zdGFja0N0cmwucG9wKGRlZXAsIHN0YWNrSWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIFVSTCBvZiB0aGUgYWN0aXZlIHBhZ2Ugb2YgZWFjaCBzdGFjay5cbiAgICovXG4gIGdldExhc3RVcmwoc3RhY2tJZD86IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgYWN0aXZlID0gdGhpcy5zdGFja0N0cmwuZ2V0TGFzdFVybChzdGFja0lkKTtcbiAgICByZXR1cm4gYWN0aXZlID8gYWN0aXZlLnVybCA6IHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBSb3V0ZVZpZXcgb2YgdGhlIGFjdGl2ZSBwYWdlIG9mIGVhY2ggc3RhY2suXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgZ2V0TGFzdFJvdXRlVmlldyhzdGFja0lkPzogc3RyaW5nKTogUm91dGVWaWV3IHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5zdGFja0N0cmwuZ2V0TGFzdFVybChzdGFja0lkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSByb290IHZpZXcgaW4gdGhlIHRhYiBzdGFjay5cbiAgICogQGludGVybmFsXG4gICAqL1xuICBnZXRSb290VmlldyhzdGFja0lkPzogc3RyaW5nKTogUm91dGVWaWV3IHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5zdGFja0N0cmwuZ2V0Um9vdFVybChzdGFja0lkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBhY3RpdmUgc3RhY2sgSUQuIEluIHRoZSBjb250ZXh0IG9mIGlvbi10YWJzLCBpdCBtZWFucyB0aGUgYWN0aXZlIHRhYi5cbiAgICovXG4gIGdldEFjdGl2ZVN0YWNrSWQoKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5zdGFja0N0cmwuZ2V0QWN0aXZlU3RhY2tJZCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNpbmNlIHRoZSBhY3RpdmF0ZWQgcm91dGUgY2FuIGNoYW5nZSBvdmVyIHRoZSBsaWZlIHRpbWUgb2YgYSBjb21wb25lbnQgaW4gYW4gaW9uIHJvdXRlciBvdXRsZXQsIHdlIGNyZWF0ZVxuICAgKiBhIHByb3h5IHNvIHRoYXQgd2UgY2FuIHVwZGF0ZSB0aGUgdmFsdWVzIG92ZXIgdGltZSBhcyBhIHVzZXIgbmF2aWdhdGVzIGJhY2sgdG8gY29tcG9uZW50cyBhbHJlYWR5IGluIHRoZSBzdGFjay5cbiAgICovXG4gIHByaXZhdGUgY3JlYXRlQWN0aXZhdGVkUm91dGVQcm94eShjb21wb25lbnQkOiBPYnNlcnZhYmxlPGFueT4sIGFjdGl2YXRlZFJvdXRlOiBBY3RpdmF0ZWRSb3V0ZSk6IEFjdGl2YXRlZFJvdXRlIHtcbiAgICBjb25zdCBwcm94eTogYW55ID0gbmV3IEFjdGl2YXRlZFJvdXRlKCk7XG5cbiAgICBwcm94eS5fZnV0dXJlU25hcHNob3QgPSAoYWN0aXZhdGVkUm91dGUgYXMgYW55KS5fZnV0dXJlU25hcHNob3Q7XG4gICAgcHJveHkuX3JvdXRlclN0YXRlID0gKGFjdGl2YXRlZFJvdXRlIGFzIGFueSkuX3JvdXRlclN0YXRlO1xuICAgIHByb3h5LnNuYXBzaG90ID0gYWN0aXZhdGVkUm91dGUuc25hcHNob3Q7XG4gICAgcHJveHkub3V0bGV0ID0gYWN0aXZhdGVkUm91dGUub3V0bGV0O1xuICAgIHByb3h5LmNvbXBvbmVudCA9IGFjdGl2YXRlZFJvdXRlLmNvbXBvbmVudDtcblxuICAgIC8vIFNldHVwIHdyYXBwZXJzIGZvciB0aGUgb2JzZXJ2YWJsZXMgc28gY29uc3VtZXJzIGRvbid0IGhhdmUgdG8gd29ycnkgYWJvdXQgc3dpdGNoaW5nIHRvIG5ldyBvYnNlcnZhYmxlcyBhcyB0aGUgc3RhdGUgdXBkYXRlc1xuICAgIChwcm94eSBhcyBhbnkpLl9wYXJhbU1hcCA9IHRoaXMucHJveHlPYnNlcnZhYmxlKGNvbXBvbmVudCQsICdwYXJhbU1hcCcpO1xuICAgIChwcm94eSBhcyBhbnkpLl9xdWVyeVBhcmFtTWFwID0gdGhpcy5wcm94eU9ic2VydmFibGUoY29tcG9uZW50JCwgJ3F1ZXJ5UGFyYW1NYXAnKTtcbiAgICBwcm94eS51cmwgPSB0aGlzLnByb3h5T2JzZXJ2YWJsZShjb21wb25lbnQkLCAndXJsJyk7XG4gICAgcHJveHkucGFyYW1zID0gdGhpcy5wcm94eU9ic2VydmFibGUoY29tcG9uZW50JCwgJ3BhcmFtcycpO1xuICAgIHByb3h5LnF1ZXJ5UGFyYW1zID0gdGhpcy5wcm94eU9ic2VydmFibGUoY29tcG9uZW50JCwgJ3F1ZXJ5UGFyYW1zJyk7XG4gICAgcHJveHkuZnJhZ21lbnQgPSB0aGlzLnByb3h5T2JzZXJ2YWJsZShjb21wb25lbnQkLCAnZnJhZ21lbnQnKTtcbiAgICBwcm94eS5kYXRhID0gdGhpcy5wcm94eU9ic2VydmFibGUoY29tcG9uZW50JCwgJ2RhdGEnKTtcblxuICAgIHJldHVybiBwcm94eSBhcyBBY3RpdmF0ZWRSb3V0ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSB3cmFwcGVkIG9ic2VydmFibGUgdGhhdCB3aWxsIHN3aXRjaCB0byB0aGUgbGF0ZXN0IGFjdGl2YXRlZCByb3V0ZSBtYXRjaGVkIGJ5IHRoZSBnaXZlbiBjb21wb25lbnRcbiAgICovXG4gIHByaXZhdGUgcHJveHlPYnNlcnZhYmxlKGNvbXBvbmVudCQ6IE9ic2VydmFibGU8YW55PiwgcGF0aDogc3RyaW5nKTogT2JzZXJ2YWJsZTxhbnk+IHtcbiAgICByZXR1cm4gY29tcG9uZW50JC5waXBlKFxuICAgICAgLy8gRmlyc3Qgd2FpdCB1bnRpbCB0aGUgY29tcG9uZW50IGluc3RhbmNlIGlzIHB1c2hlZFxuICAgICAgZmlsdGVyKChjb21wb25lbnQpID0+ICEhY29tcG9uZW50KSxcbiAgICAgIHN3aXRjaE1hcCgoY29tcG9uZW50KSA9PlxuICAgICAgICB0aGlzLmN1cnJlbnRBY3RpdmF0ZWRSb3V0ZSQucGlwZShcbiAgICAgICAgICBmaWx0ZXIoKGN1cnJlbnQpID0+IGN1cnJlbnQgIT09IG51bGwgJiYgY3VycmVudC5jb21wb25lbnQgPT09IGNvbXBvbmVudCksXG4gICAgICAgICAgc3dpdGNoTWFwKChjdXJyZW50KSA9PiBjdXJyZW50ICYmIChjdXJyZW50LmFjdGl2YXRlZFJvdXRlIGFzIGFueSlbcGF0aF0pLFxuICAgICAgICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKClcbiAgICAgICAgKVxuICAgICAgKVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlcyB0aGUgYWN0aXZhdGVkIHJvdXRlIHByb3h5IGZvciB0aGUgZ2l2ZW4gY29tcG9uZW50IHRvIHRoZSBuZXcgaW5jb21pbmcgcm91dGVyIHN0YXRlXG4gICAqL1xuICBwcml2YXRlIHVwZGF0ZUFjdGl2YXRlZFJvdXRlUHJveHkoY29tcG9uZW50OiBhbnksIGFjdGl2YXRlZFJvdXRlOiBBY3RpdmF0ZWRSb3V0ZSk6IHZvaWQge1xuICAgIGNvbnN0IHByb3h5ID0gdGhpcy5wcm94eU1hcC5nZXQoY29tcG9uZW50KTtcbiAgICBpZiAoIXByb3h5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENvdWxkIG5vdCBmaW5kIGFjdGl2YXRlZCByb3V0ZSBwcm94eSBmb3Igdmlld2ApO1xuICAgIH1cblxuICAgIChwcm94eSBhcyBhbnkpLl9mdXR1cmVTbmFwc2hvdCA9IChhY3RpdmF0ZWRSb3V0ZSBhcyBhbnkpLl9mdXR1cmVTbmFwc2hvdDtcbiAgICAocHJveHkgYXMgYW55KS5fcm91dGVyU3RhdGUgPSAoYWN0aXZhdGVkUm91dGUgYXMgYW55KS5fcm91dGVyU3RhdGU7XG4gICAgcHJveHkuc25hcHNob3QgPSBhY3RpdmF0ZWRSb3V0ZS5zbmFwc2hvdDtcbiAgICBwcm94eS5vdXRsZXQgPSBhY3RpdmF0ZWRSb3V0ZS5vdXRsZXQ7XG4gICAgcHJveHkuY29tcG9uZW50ID0gYWN0aXZhdGVkUm91dGUuY29tcG9uZW50O1xuXG4gICAgdGhpcy5jdXJyZW50QWN0aXZhdGVkUm91dGUkLm5leHQoeyBjb21wb25lbnQsIGFjdGl2YXRlZFJvdXRlIH0pO1xuICB9XG59XG5cbmNsYXNzIE91dGxldEluamVjdG9yIGltcGxlbWVudHMgSW5qZWN0b3Ige1xuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJvdXRlOiBBY3RpdmF0ZWRSb3V0ZSwgcHJpdmF0ZSBjaGlsZENvbnRleHRzOiBDaGlsZHJlbk91dGxldENvbnRleHRzLCBwcml2YXRlIHBhcmVudDogSW5qZWN0b3IpIHt9XG5cbiAgZ2V0KHRva2VuOiBhbnksIG5vdEZvdW5kVmFsdWU/OiBhbnkpOiBhbnkge1xuICAgIGlmICh0b2tlbiA9PT0gQWN0aXZhdGVkUm91dGUpIHtcbiAgICAgIHJldHVybiB0aGlzLnJvdXRlO1xuICAgIH1cblxuICAgIGlmICh0b2tlbiA9PT0gQ2hpbGRyZW5PdXRsZXRDb250ZXh0cykge1xuICAgICAgcmV0dXJuIHRoaXMuY2hpbGRDb250ZXh0cztcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5wYXJlbnQuZ2V0KHRva2VuLCBub3RGb3VuZFZhbHVlKTtcbiAgfVxufVxuXG4vLyBUT0RPOiBGVy00Nzg1IC0gUmVtb3ZlIHRoaXMgb25jZSBBbmd1bGFyIDE1IHN1cHBvcnQgaXMgZHJvcHBlZFxuY29uc3QgSU5QVVRfQklOREVSID0gbmV3IEluamVjdGlvblRva2VuPFJvdXRlZENvbXBvbmVudElucHV0QmluZGVyPignJyk7XG5cbi8qKlxuICogSW5qZWN0YWJsZSB1c2VkIGFzIGEgdHJlZS1zaGFrYWJsZSBwcm92aWRlciBmb3Igb3B0aW5nIGluIHRvIGJpbmRpbmcgcm91dGVyIGRhdGEgdG8gY29tcG9uZW50XG4gKiBpbnB1dHMuXG4gKlxuICogVGhlIFJvdXRlck91dGxldCByZWdpc3RlcnMgaXRzZWxmIHdpdGggdGhpcyBzZXJ2aWNlIHdoZW4gYW4gYEFjdGl2YXRlZFJvdXRlYCBpcyBhdHRhY2hlZCBvclxuICogYWN0aXZhdGVkLiBXaGVuIHRoaXMgaGFwcGVucywgdGhlIHNlcnZpY2Ugc3Vic2NyaWJlcyB0byB0aGUgYEFjdGl2YXRlZFJvdXRlYCBvYnNlcnZhYmxlcyAocGFyYW1zLFxuICogcXVlcnlQYXJhbXMsIGRhdGEpIGFuZCBzZXRzIHRoZSBpbnB1dHMgb2YgdGhlIGNvbXBvbmVudCB1c2luZyBgQ29tcG9uZW50UmVmLnNldElucHV0YC5cbiAqIEltcG9ydGFudGx5LCB3aGVuIGFuIGlucHV0IGRvZXMgbm90IGhhdmUgYW4gaXRlbSBpbiB0aGUgcm91dGUgZGF0YSB3aXRoIGEgbWF0Y2hpbmcga2V5LCB0aGlzXG4gKiBpbnB1dCBpcyBzZXQgdG8gYHVuZGVmaW5lZGAuIElmIGl0IHdlcmUgbm90IGRvbmUgdGhpcyB3YXksIHRoZSBwcmV2aW91cyBpbmZvcm1hdGlvbiB3b3VsZCBiZVxuICogcmV0YWluZWQgaWYgdGhlIGRhdGEgZ290IHJlbW92ZWQgZnJvbSB0aGUgcm91dGUgKGkuZS4gaWYgYSBxdWVyeSBwYXJhbWV0ZXIgaXMgcmVtb3ZlZCkuXG4gKlxuICogVGhlIGBSb3V0ZXJPdXRsZXRgIHNob3VsZCB1bnJlZ2lzdGVyIGl0c2VsZiB3aGVuIGRlc3Ryb3llZCB2aWEgYHVuc3Vic2NyaWJlRnJvbVJvdXRlRGF0YWAgc28gdGhhdFxuICogdGhlIHN1YnNjcmlwdGlvbnMgYXJlIGNsZWFuZWQgdXAuXG4gKi9cbkBJbmplY3RhYmxlKClcbmNsYXNzIFJvdXRlZENvbXBvbmVudElucHV0QmluZGVyIHtcbiAgcHJpdmF0ZSBvdXRsZXREYXRhU3Vic2NyaXB0aW9ucyA9IG5ldyBNYXA8SW9uUm91dGVyT3V0bGV0LCBTdWJzY3JpcHRpb24+KCk7XG5cbiAgYmluZEFjdGl2YXRlZFJvdXRlVG9PdXRsZXRDb21wb25lbnQob3V0bGV0OiBJb25Sb3V0ZXJPdXRsZXQpOiB2b2lkIHtcbiAgICB0aGlzLnVuc3Vic2NyaWJlRnJvbVJvdXRlRGF0YShvdXRsZXQpO1xuICAgIHRoaXMuc3Vic2NyaWJlVG9Sb3V0ZURhdGEob3V0bGV0KTtcbiAgfVxuXG4gIHVuc3Vic2NyaWJlRnJvbVJvdXRlRGF0YShvdXRsZXQ6IElvblJvdXRlck91dGxldCk6IHZvaWQge1xuICAgIHRoaXMub3V0bGV0RGF0YVN1YnNjcmlwdGlvbnMuZ2V0KG91dGxldCk/LnVuc3Vic2NyaWJlKCk7XG4gICAgdGhpcy5vdXRsZXREYXRhU3Vic2NyaXB0aW9ucy5kZWxldGUob3V0bGV0KTtcbiAgfVxuXG4gIHByaXZhdGUgc3Vic2NyaWJlVG9Sb3V0ZURhdGEob3V0bGV0OiBJb25Sb3V0ZXJPdXRsZXQpIHtcbiAgICBjb25zdCB7IGFjdGl2YXRlZFJvdXRlIH0gPSBvdXRsZXQ7XG4gICAgY29uc3QgZGF0YVN1YnNjcmlwdGlvbiA9IGNvbWJpbmVMYXRlc3QoW2FjdGl2YXRlZFJvdXRlLnF1ZXJ5UGFyYW1zLCBhY3RpdmF0ZWRSb3V0ZS5wYXJhbXMsIGFjdGl2YXRlZFJvdXRlLmRhdGFdKVxuICAgICAgLnBpcGUoXG4gICAgICAgIHN3aXRjaE1hcCgoW3F1ZXJ5UGFyYW1zLCBwYXJhbXMsIGRhdGFdLCBpbmRleCkgPT4ge1xuICAgICAgICAgIGRhdGEgPSB7IC4uLnF1ZXJ5UGFyYW1zLCAuLi5wYXJhbXMsIC4uLmRhdGEgfTtcbiAgICAgICAgICAvLyBHZXQgdGhlIGZpcnN0IHJlc3VsdCBmcm9tIHRoZSBkYXRhIHN1YnNjcmlwdGlvbiBzeW5jaHJvbm91c2x5IHNvIGl0J3MgYXZhaWxhYmxlIHRvXG4gICAgICAgICAgLy8gdGhlIGNvbXBvbmVudCBhcyBzb29uIGFzIHBvc3NpYmxlIChhbmQgZG9lc24ndCByZXF1aXJlIGEgc2Vjb25kIGNoYW5nZSBkZXRlY3Rpb24pLlxuICAgICAgICAgIGlmIChpbmRleCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIG9mKGRhdGEpO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBQcm9taXNlLnJlc29sdmUgaXMgdXNlZCB0byBhdm9pZCBzeW5jaHJvbm91c2x5IHdyaXRpbmcgdGhlIHdyb25nIGRhdGEgd2hlblxuICAgICAgICAgIC8vIHR3byBvZiB0aGUgT2JzZXJ2YWJsZXMgaW4gdGhlIGBjb21iaW5lTGF0ZXN0YCBzdHJlYW0gZW1pdCBvbmUgYWZ0ZXJcbiAgICAgICAgICAvLyBhbm90aGVyLlxuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoZGF0YSk7XG4gICAgICAgIH0pXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKChkYXRhKSA9PiB7XG4gICAgICAgIC8vIE91dGxldCBtYXkgaGF2ZSBiZWVuIGRlYWN0aXZhdGVkIG9yIGNoYW5nZWQgbmFtZXMgdG8gYmUgYXNzb2NpYXRlZCB3aXRoIGEgZGlmZmVyZW50XG4gICAgICAgIC8vIHJvdXRlXG4gICAgICAgIGlmIChcbiAgICAgICAgICAhb3V0bGV0LmlzQWN0aXZhdGVkIHx8XG4gICAgICAgICAgIW91dGxldC5hY3RpdmF0ZWRDb21wb25lbnRSZWYgfHxcbiAgICAgICAgICBvdXRsZXQuYWN0aXZhdGVkUm91dGUgIT09IGFjdGl2YXRlZFJvdXRlIHx8XG4gICAgICAgICAgYWN0aXZhdGVkUm91dGUuY29tcG9uZW50ID09PSBudWxsXG4gICAgICAgICkge1xuICAgICAgICAgIHRoaXMudW5zdWJzY3JpYmVGcm9tUm91dGVEYXRhKG91dGxldCk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgbWlycm9yID0gcmVmbGVjdENvbXBvbmVudFR5cGUoYWN0aXZhdGVkUm91dGUuY29tcG9uZW50KTtcbiAgICAgICAgaWYgKCFtaXJyb3IpIHtcbiAgICAgICAgICB0aGlzLnVuc3Vic2NyaWJlRnJvbVJvdXRlRGF0YShvdXRsZXQpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGZvciAoY29uc3QgeyB0ZW1wbGF0ZU5hbWUgfSBvZiBtaXJyb3IuaW5wdXRzKSB7XG4gICAgICAgICAgb3V0bGV0LmFjdGl2YXRlZENvbXBvbmVudFJlZi5zZXRJbnB1dCh0ZW1wbGF0ZU5hbWUsIGRhdGFbdGVtcGxhdGVOYW1lXSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgdGhpcy5vdXRsZXREYXRhU3Vic2NyaXB0aW9ucy5zZXQob3V0bGV0LCBkYXRhU3Vic2NyaXB0aW9uKTtcbiAgfVxufVxuXG5leHBvcnQgY29uc3QgcHJvdmlkZUNvbXBvbmVudElucHV0QmluZGluZyA9ICgpOiBQcm92aWRlciA9PiB7XG4gIHJldHVybiB7XG4gICAgcHJvdmlkZTogSU5QVVRfQklOREVSLFxuICAgIHVzZUZhY3Rvcnk6IGNvbXBvbmVudElucHV0QmluZGluZ0ZhY3RvcnksXG4gICAgZGVwczogW1JvdXRlcl0sXG4gIH07XG59O1xuXG5mdW5jdGlvbiBjb21wb25lbnRJbnB1dEJpbmRpbmdGYWN0b3J5KHJvdXRlcj86IFJvdXRlcikge1xuICAvKipcbiAgICogV2UgY2FzdCB0aGUgcm91dGVyIHRvIGFueSBoZXJlLCBzaW5jZSB0aGUgY29tcG9uZW50SW5wdXRCaW5kaW5nRW5hYmxlZFxuICAgKiBwcm9wZXJ0eSBpcyBub3QgYXZhaWxhYmxlIHVudGlsIEFuZ3VsYXIgdjE2LlxuICAgKi9cbiAgaWYgKChyb3V0ZXIgYXMgYW55KT8uY29tcG9uZW50SW5wdXRCaW5kaW5nRW5hYmxlZCkge1xuICAgIHJldHVybiBuZXcgUm91dGVkQ29tcG9uZW50SW5wdXRCaW5kZXIoKTtcbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cbiJdfQ==