@bespunky/angular-zen
Version:
The Angular tools you always wished were there.
186 lines • 35 kB
JavaScript
import { from, of } from 'rxjs';
import { concatAll, filter, finalize, takeUntil, toArray } from 'rxjs/operators';
import { Directive, Injectable } from '@angular/core';
import { Router, ActivatedRoute, ActivationEnd, ActivationStart, ChildActivationEnd, ChildActivationStart, GuardsCheckEnd, GuardsCheckStart, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, RoutesRecognized, Scroll } from '@angular/router';
import { Destroyable } from '@bespunky/angular-zen/core';
import { RouterOutletComponentBus } from '../outlet/router-outlet-component-bus.service';
import * as i0 from "@angular/core";
import * as i1 from "@angular/router";
import * as i2 from "../outlet/router-outlet-component-bus.service";
/**
* Hard-codes event names as strings.
* When AOT compilation is run and constructor names change, the dispatcher will still be able to get a hold
* of the correct event name using this map.
*/
const EventMap = {
[NavigationStart.prototype.constructor.name]: 'NavigationStart',
[RouteConfigLoadStart.prototype.constructor.name]: 'RouteConfigLoadStart',
[RouteConfigLoadEnd.prototype.constructor.name]: 'RouteConfigLoadEnd',
[RoutesRecognized.prototype.constructor.name]: 'RoutesRecognized',
[GuardsCheckStart.prototype.constructor.name]: 'GuardsCheckStart',
[ChildActivationStart.prototype.constructor.name]: 'ChildActivationStart',
[ActivationStart.prototype.constructor.name]: 'ActivationStart',
[GuardsCheckEnd.prototype.constructor.name]: 'GuardsCheckEnd',
[ResolveStart.prototype.constructor.name]: 'ResolveStart',
[ResolveEnd.prototype.constructor.name]: 'ResolveEnd',
[ChildActivationEnd.prototype.constructor.name]: 'ChildActivationEnd',
[ActivationEnd.prototype.constructor.name]: 'ActivationEnd',
[NavigationEnd.prototype.constructor.name]: 'NavigationEnd',
[NavigationCancel.prototype.constructor.name]: 'NavigationCancel',
[NavigationError.prototype.constructor.name]: 'NavigationError',
[Scroll.prototype.constructor.name]: 'Scroll'
};
/**
* The prefix of the id generated for zone macro tasks when calling `RouteAware.resolveInMacroTask()`.
*
* Generated ids will confrom to a `{prefix}-{random number}` format.
*/
export const ResolverMacroTaskIdPrefix = 'route-aware-resolver';
/**
* Provides functionality for extending class to easily work with routes and process changes.
*
* @export
* @abstract
* @class RouteAware
* @extends {Destroyable}
*/
// eslint-disable-next-line @angular-eslint/directive-class-suffix
export class RouteAware extends Destroyable {
/**
* Creates an instance of RouteAware.
*
* @param {Router} router The instance of Angular's router service.
* @param {ActivatedRoute} route The instance of Angular's active route service.
* @param {RouterOutletComponentBus} [componentBus] (Optional) The component bus for router-x functionality.
* Provide this when you want your route-aware service to have access to the instance(s) of the activated component(s).
*/
constructor(router, route, componentBus) {
super();
this.router = router;
this.route = route;
this.componentBus = componentBus;
// TODO: Scan class and only subscribe if handlers were defined
this.subscribe(this.router.events, this.dispatchRouterEvent.bind(this));
}
/**
* Checks if a handler method for the specific event type exists on the service and calls it.
* Handler methods should comply with `onEventType` naming (lowercase 'on', first-upper event type).
*
* @private
* @param {Event} event The event data received from the router.
*/
dispatchRouterEvent(event) {
// AOT compilation changes class names, causing the dispacher to look for a handler methods with
// wrong names (e.g. `onJ`). The EventMap is used to restore the original names.
const typeName = event.constructor.name;
const handlerName = `on${EventMap[typeName]}`;
const handle = this[handlerName];
if (handle)
handle.call(this, event);
}
/**
* Creates an observable that emits only the specified router events and is automatically destroyed when the service/component is destroyed.
*
* @protected
* @template TEvent The type of router event to emit.
* @param {Type<TEvent>} eventType The type of router event to emit.
* @param {boolean} [autoUnsubscribe=true] (Optional) `true` to make the observable complete when the service/component is destroyed; otherwise `false`. Default is `true`.
* @returns {Observable<TEvent>}
*/
observeRouterEvent(eventType, autoUnsubscribe = true) {
let observable = this.router.events;
if (autoUnsubscribe)
observable = observable.pipe(takeUntil(this.destroyed));
return observable.pipe(filter(event => event.constructor === eventType));
}
/**
* Recoursively runs a processing function on the route and its children.
* Scan is done from parent to child, meaning the parent is the first to process.
*
* @protected
* @param {ActivatedRouteSnapshot} route The top route on which to apply the processing function.
* @param {(route: ActivatedRouteSnapshot, component: any) => boolean | void} process The function to run on the route and its children. The function receives a `route` argument which reflects the route being processed,
* and a `component` argument which reflects the component that was loaded for the route's outlet.
* If the corresponding outlet wasn't marked with the `publishComponent` directive, the `component` argument will be null.
*
* Returning `true` from the process function is equal to saying 'work has completed' and will stop propogation to the route's children.
* @param {number} [levels=-1] (Optional) The number of levels (excluding the parent) to dive deeper into the route tree.
* A value of 1 for example, will process the route and its first-level children only. By default, scans all levels of the route tree.
*/
deepScanRoute(route, process, levels = -1) {
// Make sure the caller wants scan to proceed, then make sure level limit wasn't reached.
const processingConcluded = process(route, this.componentBus?.instance(route.outlet));
// Negative values will scan all, positives will scan until reaching zero.
const shouldScanChildren = !processingConcluded && levels !== 0;
if (shouldScanChildren && route.children)
route.children.forEach(childRoute => this.deepScanRoute(childRoute, process, levels - 1));
}
/**
* Creates an observable that runs all the specified resolvers and concats their results as an array.
* The resolvers will be passed with the instance of the component for the currently activated route.
*
* @protected
* @param {(Resolver | Resolver[])} resolvers The resolver(s) to concat.
* @param {...any[]} resolverArgs (Optional) Any arguments to pass into the resolvers in addition to the component.
* @returns {Observable<any[]>} An array with the concatenated results of the resolvers.
*/
resolve(resolvers, ...resolverArgs) {
if (!resolvers)
return of([]);
// Cast array
if (!Array.isArray(resolvers))
resolvers = [resolvers];
// Run resolvers to create observable tasks
const observables = resolvers.map(resolve => resolve(this.activatedRouteComponent, ...resolverArgs));
// Run tasks and output their returned data as an array
return from(observables).pipe(concatAll(), toArray());
}
/**
* Creates an observable that runs all the specified resolvers and concats their results as an array.
* The resolvers will be passed with the instance of the component for the currently activated route.
*
* **Angular Universal:**
* In SSR, the server doesn't wait for async code to complete. The result is scrapers and search engines receiving a page without resolved data,
* which is bad in case you need them to read some resolved metadata tags for example.
*
* Using `Zone` directly, this method creates a macro task and completes it when resolves are done or have errored.
* This makes the server block and wait until everything is resolved or errors before returning the rendered page.
*
* > *ℹ Make sure your resolves and process function are fast enough so that the server won't hang too much trying to render.*
*
* @see https://stackoverflow.com/a/50065783/4371525 for the discussion.
*
* @see {ResolverMacroTaskIdPrefix} if you need to identify the created macro task in your code.
*
* @protected
* @param {(Resolver | Resolver[])} resolvers The resolver(s) to concat.
* @param {...any[]} resolverArgs (Optional) Any arguments to pass into the resolvers in addition to the component.
*/
resolveInMacroTask(resolvers, ...resolverArgs) {
// eslint-disable-next-line @typescript-eslint/no-empty-function
const macroTask = Zone.current.scheduleMacroTask(`${ResolverMacroTaskIdPrefix}-${Math.random()}`, () => { }, {}, () => { }, () => { });
return this.resolve(resolvers, ...resolverArgs)
// Signal end of macro task on completion or error and allow server to return
.pipe(finalize(() => macroTask.invoke()));
}
/**
* The instance of the component created for the currently activated route.
* If no component bus was supplied at construction time, this will be `undefined`.
*
* @readonly
* @protected
* @type {(any | null)}
*/
get activatedRouteComponent() {
return this.componentBus?.instance(this.route.outlet);
}
}
RouteAware.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RouteAware, deps: [{ token: i1.Router }, { token: i1.ActivatedRoute }, { token: i2.RouterOutletComponentBus }], target: i0.ɵɵFactoryTarget.Directive });
RouteAware.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.2.12", type: RouteAware, usesInheritance: true, ngImport: i0 });
RouteAware.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RouteAware });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RouteAware, decorators: [{
type: Directive
}, {
type: Injectable
}], ctorParameters: function () { return [{ type: i1.Router }, { type: i1.ActivatedRoute }, { type: i2.RouterOutletComponentBus }]; } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUtYXdhcmUuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvYW5ndWxhci16ZW4vcm91dGVyLXgvc3JjL3NlcnZpY2VzL3JvdXRlLWF3YXJlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLElBQUksRUFBaUMsRUFBRSxFQUFVLE1BQU0sTUFBTSxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDakYsT0FBTyxFQUFFLFNBQVMsRUFBUSxVQUFVLEVBQXNCLE1BQU0sZUFBZSxDQUFDO0FBQ2hGLE9BQU8sRUFBRSxNQUFNLEVBQUUsY0FBYyxFQUFpQyxhQUFhLEVBQUUsZUFBZSxFQUFFLGtCQUFrQixFQUFFLG9CQUFvQixFQUFFLGNBQWMsRUFBRSxnQkFBZ0IsRUFBRSxnQkFBZ0IsRUFBRSxhQUFhLEVBQUUsZUFBZSxFQUFFLGVBQWUsRUFBRSxVQUFVLEVBQUUsWUFBWSxFQUFFLGtCQUFrQixFQUFFLG9CQUFvQixFQUFFLGdCQUFnQixFQUFFLE1BQU0sRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRXJXLE9BQU8sRUFBRSxXQUFXLEVBQWUsTUFBTSw0QkFBNEIsQ0FBQztBQUN0RSxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSwrQ0FBK0MsQ0FBQzs7OztBQUl6Rjs7OztHQUlHO0FBQ0gsTUFBTSxRQUFRLEdBQUc7SUFDYixDQUFDLGVBQWUsQ0FBTSxTQUFTLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxFQUFFLGlCQUFpQjtJQUNwRSxDQUFDLG9CQUFvQixDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEVBQUUsc0JBQXNCO0lBQ3pFLENBQUMsa0JBQWtCLENBQUcsU0FBUyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFB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QU8sRUFBRSxDQUFDLENBQUM7SUFDMUQsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQW9CRztJQUNPLGtCQUFrQixDQUFDLFNBQWdDLEVBQUUsR0FBRyxZQUFtQjtRQUVqRixnRUFBZ0U7UUFDaEUsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLHlCQUF5QixJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBRXZJLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsR0FBRyxZQUFZLENBQUM7WUFDM0MsNkVBQTZFO2FBQzVFLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQzNDLENBQUM7SUFDTixDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNILElBQWMsdUJBQXVCO1FBRWpDLE9BQU8sSUFBSSxDQUFDLFlBQVksRUFBRSxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUMxRCxDQUFDOzt3R0FwTGlCLFVBQVU7NEZBQVYsVUFBVTs0R0FBVixVQUFVOzRGQUFWLFVBQVU7a0JBSC9CLFNBQVM7O2tCQUNULFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBmcm9tLCBJbnRlcm9wT2JzZXJ2YWJsZSwgT2JzZXJ2YWJsZSwgb2YgICAgICAgICB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgY29uY2F0QWxsLCBmaWx0ZXIsIGZpbmFsaXplLCB0YWtlVW50aWwsIHRvQXJyYXkgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBEaXJlY3RpdmUsIFR5cGUsIEluamVjdGFibGUgICAgICAgICAgICAgICAgICAgICB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgUm91dGVyLCBBY3RpdmF0ZWRSb3V0ZSwgQWN0aXZhdGVkUm91dGVTbmFwc2hvdCwgRXZlbnQsIEFjdGl2YXRpb25FbmQsIEFjdGl2YXRpb25TdGFydCwgQ2hpbGRBY3RpdmF0aW9uRW5kLCBDaGlsZEFjdGl2YXRpb25TdGFydCwgR3VhcmRzQ2hlY2tFbmQsIEd1YXJkc0NoZWNrU3RhcnQsIE5hdmlnYXRpb25DYW5jZWwsIE5hdmlnYXRpb25FbmQsIE5hdmlnYXRpb25FcnJvciwgTmF2aWdhdGlvblN0YXJ0LCBSZXNvbHZlRW5kLCBSZXNvbHZlU3RhcnQsIFJvdXRlQ29uZmlnTG9hZEVuZCwgUm91dGVDb25maWdMb2FkU3RhcnQsIFJvdXRlc1JlY29nbml6ZWQsIFNjcm9sbCB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5cbmltcG9ydCB7IERlc3Ryb3lhYmxlICAgICAgICAgICAgICB9IGZyb20gJ0BiZXNwdW5reS9hbmd1bGFyLXplbi9jb3JlJztcbmltcG9ydCB7IFJvdXRlck91dGxldENvbXBvbmVudEJ1cyB9IGZyb20gJy4uL291dGxldC9yb3V0ZXItb3V0bGV0LWNvbXBvbmVudC1idXMuc2VydmljZSc7XG5cbmRlY2xhcmUgY29uc3QgWm9uZTogYW55O1xuXG4vKipcbiAqIEhhcmQtY29kZXMgZXZlbnQgbmFtZXMgYXMgc3RyaW5ncy5cbiAqIFdoZW4gQU9UIGNvbXBpbGF0aW9uIGlzIHJ1biBhbmQgY29uc3RydWN0b3IgbmFtZXMgY2hhbmdlLCB0aGUgZGlzcGF0Y2hlciB3aWxsIHN0aWxsIGJlIGFibGUgdG8gZ2V0IGEgaG9sZFxuICogb2YgdGhlIGNvcnJlY3QgZXZlbnQgbmFtZSB1c2luZyB0aGlzIG1hcC5cbiAqL1xuY29uc3QgRXZlbnRNYXAgPSB7XG4gICAgW05hdmlnYXRpb25TdGFydCAgICAgLnByb3RvdHlwZS5jb25zdHJ1Y3Rvci5uYW1lXTogJ05hdmlnYXRpb25TdGFydCcsXG4gICAgW1JvdXRlQ29uZmlnTG9hZFN0YXJ0LnByb3RvdHlwZS5jb25zdHJ1Y3Rvci5uYW1lXTogJ1JvdXRlQ29uZmlnTG9hZFN0YXJ0JyxcbiAgICBbUm91dGVDb25maWdMb2FkRW5kICAucHJvdG90eXBlLmNvbnN0cnVjdG9yLm5hbWVdOiAnUm91dGVDb25maWdMb2FkRW5kJyxcbiAgICBbUm91dGVzUmVjb2duaXplZCAgICAucHJvdG90eXBlLmNvbnN0cnVjdG9yLm5hbWVdOiAnUm91dGVzUmVjb2duaXplZCcsXG4gICAgW0d1YXJkc0NoZWNrU3RhcnQgICAgLnByb3RvdHlwZS5jb25zdHJ1Y3Rvci5uYW1lXTogJ0d1YXJkc0NoZWNrU3RhcnQnLFxuICAgIFtDaGlsZEFjdGl2YXRpb25TdGFydC5wcm90b3R5cGUuY29uc3RydWN0b3IubmFtZV06ICdDaGlsZEFjdGl2YXRpb25TdGFydCcsXG4gICAgW0FjdGl2YXRpb25TdGFydCAgICAgLnByb3RvdHlwZS5jb25zdHJ1Y3Rvci5uYW1lXTogJ0FjdGl2YXRpb25TdGFydCcsXG4gICAgW0d1YXJkc0NoZWNrRW5kICAgICAgLnByb3RvdHlwZS5jb25zdHJ1Y3Rvci5uYW1lXTogJ0d1YXJkc0NoZWNrRW5kJyxcbiAgICBbUmVzb2x2ZVN0YXJ0ICAgICAgICAucHJvdG90eXBlLmNvbnN0cnVjdG9yLm5hbWVdOiAnUmVzb2x2ZVN0YXJ0JyxcbiAgICBbUmVzb2x2ZUVuZCAgICAgICAgICAucHJvdG90eXBlLmNvbnN0cnVjdG9yLm5hbWVdOiAnUmVzb2x2ZUVuZCcsXG4gICAgW0NoaWxkQWN0aXZhdGlvbkVuZCAgLnByb3RvdHlwZS5jb25zdHJ1Y3Rvci5uYW1lXTogJ0NoaWxkQWN0aXZhdGlvbkVuZCcsXG4gICAgW0FjdGl2YXRpb25FbmQgICAgICAgLnByb3RvdHlwZS5jb25zdHJ1Y3Rvci5uYW1lXTogJ0FjdGl2YXRpb25FbmQnLFxuICAgIFtOYXZpZ2F0aW9uRW5kICAgICAgIC5wcm90b3R5cGUuY29uc3RydWN0b3IubmFtZV06ICdOYXZpZ2F0aW9uRW5kJyxcbiAgICBbTmF2aWdhdGlvbkNhbmNlbCAgICAucHJvdG90eXBlLmNvbnN0cnVjdG9yLm5hbWVdOiAnTmF2aWdhdGlvbkNhbmNlbCcsXG4gICAgW05hdmlnYXRpb25FcnJvciAgICAgLnByb3RvdHlwZS5jb25zdHJ1Y3Rvci5uYW1lXTogJ05hdmlnYXRpb25FcnJvcicsXG4gICAgW1Njcm9sbCAgICAgICAgICAgICAgLnByb3RvdHlwZS5jb25zdHJ1Y3Rvci5uYW1lXTogJ1Njcm9sbCdcbn07XG5cbi8qKiBSZXByZXNlbnRzIGEgZnVuY3Rpb24gdGhhdCBjcmVhdGVzIGFuIGFzeW5jIHRhc2sgdG8gYmUgcnVuIChub3JtYWxseSBvbiBhIGNvbXBvbmVudCkuICovXG5leHBvcnQgdHlwZSBSZXNvbHZlciA9IChjb21wb25lbnQ6IGFueSwgLi4ucmVzb2x2ZXJBcmdzOiBhbnlbXSkgPT4gT2JzZXJ2YWJsZTxhbnk+IHwgSW50ZXJvcE9ic2VydmFibGU8YW55PiB8IFByb21pc2U8YW55PjtcblxuLyoqXG4gKiBUaGUgcHJlZml4IG9mIHRoZSBpZCBnZW5lcmF0ZWQgZm9yIHpvbmUgbWFjcm8gdGFza3Mgd2hlbiBjYWxsaW5nIGBSb3V0ZUF3YXJlLnJlc29sdmVJbk1hY3JvVGFzaygpYC5cbiAqIFxuICogR2VuZXJhdGVkIGlkcyB3aWxsIGNvbmZyb20gdG8gYSBge3ByZWZpeH0te3JhbmRvbSBudW1iZXJ9YCBmb3JtYXQuXG4gKi9cbmV4cG9ydCBjb25zdCBSZXNvbHZlck1hY3JvVGFza0lkUHJlZml4ID0gJ3JvdXRlLWF3YXJlLXJlc29sdmVyJztcblxuLyoqXG4gKiBQcm92aWRlcyBmdW5jdGlvbmFsaXR5IGZvciBleHRlbmRpbmcgY2xhc3MgdG8gZWFzaWx5IHdvcmsgd2l0aCByb3V0ZXMgYW5kIHByb2Nlc3MgY2hhbmdlcy5cbiAqXG4gKiBAZXhwb3J0XG4gKiBAYWJzdHJhY3RcbiAqIEBjbGFzcyBSb3V0ZUF3YXJlXG4gKiBAZXh0ZW5kcyB7RGVzdHJveWFibGV9XG4gKi9cbkBEaXJlY3RpdmUoKSAgLy8gT3JpZ2luYWxseSB0aGlzIHdhcyBkZWNvcmF0ZWQgd2l0aCBgRGlyZWN0aXZlYCBvbmx5IHNvIGFuZ3VsYXIgYWNjZXB0cyBpdCBhcyBiYXNlIGZvciBib3RoIHNlcnZpY2VzIGFuZCBjb21wb25lbnRzLlxuQEluamVjdGFibGUoKSAvLyBIb3dldmVyLCBjb21wb2RvYyBmYWlscyB0byBjb2xsZWN0IGFic3RyYWN0IGNsYXNzZXMgbWFya2VkIHdpdGggYERpcmVjdGl2ZWAgc28gSSBtYXJrZWQgaXQgYXMgYm90aC4gVGVzdHMgcGFzcywgUE9DIHN0YWNrYmxpdHogZG9lc24ndCBzaG93IHNpZGUgZWZmZWN0cy5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAYW5ndWxhci1lc2xpbnQvZGlyZWN0aXZlLWNsYXNzLXN1ZmZpeFxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIFJvdXRlQXdhcmUgZXh0ZW5kcyBEZXN0cm95YWJsZVxueyAgICBcbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIFJvdXRlQXdhcmUuXG4gICAgICogXG4gICAgICogQHBhcmFtIHtSb3V0ZXJ9IHJvdXRlciBUaGUgaW5zdGFuY2Ugb2YgQW5ndWxhcidzIHJvdXRlciBzZXJ2aWNlLlxuICAgICAqIEBwYXJhbSB7QWN0aXZhdGVkUm91dGV9IHJvdXRlIFRoZSBpbnN0YW5jZSBvZiBBbmd1bGFyJ3MgYWN0aXZlIHJvdXRlIHNlcnZpY2UuXG4gICAgICogQHBhcmFtIHtSb3V0ZXJPdXRsZXRDb21wb25lbnRCdXN9IFtjb21wb25lbnRCdXNdIChPcHRpb25hbCkgVGhlIGNvbXBvbmVudCBidXMgZm9yIHJvdXRlci14IGZ1bmN0aW9uYWxpdHkuXG4gICAgICogUHJvdmlkZSB0aGlzIHdoZW4geW91IHdhbnQgeW91ciByb3V0ZS1hd2FyZSBzZXJ2aWNlIHRvIGhhdmUgYWNjZXNzIHRvIHRoZSBpbnN0YW5jZShzKSBvZiB0aGUgYWN0aXZhdGVkIGNvbXBvbmVudChzKS5cbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgcHJvdGVjdGVkIHJvdXRlciAgICAgICA6IFJvdXRlcixcbiAgICAgICAgcHJvdGVjdGVkIHJvdXRlICAgICAgICA6IEFjdGl2YXRlZFJvdXRlLFxuICAgICAgICBwcm90ZWN0ZWQgY29tcG9uZW50QnVzPzogUm91dGVyT3V0bGV0Q29tcG9uZW50QnVzXG4gICAgKVxuICAgIHtcbiAgICAgICAgc3VwZXIoKTtcblxuICAgICAgICAvLyBUT0RPOiBTY2FuIGNsYXNzIGFuZCBvbmx5IHN1YnNjcmliZSBpZiBoYW5kbGVycyB3ZXJlIGRlZmluZWRcbiAgICAgICAgdGhpcy5zdWJzY3JpYmUodGhpcy5yb3V0ZXIuZXZlbnRzLCB0aGlzLmRpc3BhdGNoUm91dGVyRXZlbnQuYmluZCh0aGlzKSk7XG4gICAgfVxuICAgIFxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiBhIGhhbmRsZXIgbWV0aG9kIGZvciB0aGUgc3BlY2lmaWMgZXZlbnQgdHlwZSBleGlzdHMgb24gdGhlIHNlcnZpY2UgYW5kIGNhbGxzIGl0LlxuICAgICAqIEhhbmRsZXIgbWV0aG9kcyBzaG91bGQgY29tcGx5IHdpdGggYG9uRXZlbnRUeXBlYCBuYW1pbmcgKGxvd2VyY2FzZSAnb24nLCBmaXJzdC11cHBlciBldmVudCB0eXBlKS5cbiAgICAgKiBcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7RXZlbnR9IGV2ZW50IFRoZSBldmVudCBkYXRhIHJlY2VpdmVkIGZyb20gdGhlIHJvdXRlci5cbiAgICAgKi9cbiAgICBwcml2YXRlIGRpc3BhdGNoUm91dGVyRXZlbnQoZXZlbnQ6IEV2ZW50KTogdm9pZFxuICAgIHtcbiAgICAgICAgLy8gQU9UIGNvbXBpbGF0aW9uIGNoYW5nZXMgY2xhc3MgbmFtZXMsIGNhdXNpbmcgdGhlIGRpc3BhY2hlciB0byBsb29rIGZvciBhIGhhbmRsZXIgbWV0aG9kcyB3aXRoXG4gICAgICAgIC8vIHdyb25nIG5hbWVzIChlLmcuIGBvbkpgKS4gVGhlIEV2ZW50TWFwIGlzIHVzZWQgdG8gcmVzdG9yZSB0aGUgb3JpZ2luYWwgbmFtZXMuXG4gICAgICAgIGNvbnN0IHR5cGVOYW1lICAgID0gZXZlbnQuY29uc3RydWN0b3IubmFtZTtcbiAgICAgICAgY29uc3QgaGFuZGxlck5hbWUgPSBgb24ke0V2ZW50TWFwW3R5cGVOYW1lXX1gO1xuICAgICAgICBjb25zdCBoYW5kbGUgICAgICA9ICh0aGlzIGFzIGFueSlbaGFuZGxlck5hbWVdO1xuXG4gICAgICAgIGlmIChoYW5kbGUpIGhhbmRsZS5jYWxsKHRoaXMsIGV2ZW50KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIG9ic2VydmFibGUgdGhhdCBlbWl0cyBvbmx5IHRoZSBzcGVjaWZpZWQgcm91dGVyIGV2ZW50cyBhbmQgaXMgYXV0b21hdGljYWxseSBkZXN0cm95ZWQgd2hlbiB0aGUgc2VydmljZS9jb21wb25lbnQgaXMgZGVzdHJveWVkLlxuICAgICAqXG4gICAgICogQHByb3RlY3RlZFxuICAgICAqIEB0ZW1wbGF0ZSBURXZlbnQgVGhlIHR5cGUgb2Ygcm91dGVyIGV2ZW50IHRvIGVtaXQuXG4gICAgICogQHBhcmFtIHtUeXBlPFRFdmVudD59IGV2ZW50VHlwZSBUaGUgdHlwZSBvZiByb3V0ZXIgZXZlbnQgdG8gZW1pdC5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFthdXRvVW5zdWJzY3JpYmU9dHJ1ZV0gKE9wdGlvbmFsKSBgdHJ1ZWAgdG8gbWFrZSB0aGUgb2JzZXJ2YWJsZSBjb21wbGV0ZSB3aGVuIHRoZSBzZXJ2aWNlL2NvbXBvbmVudCBpcyBkZXN0cm95ZWQ7IG90aGVyd2lzZSBgZmFsc2VgLiBEZWZhdWx0IGlzIGB0cnVlYC5cbiAgICAgKiBAcmV0dXJucyB7T2JzZXJ2YWJsZTxURXZlbnQ+fVxuICAgICAqL1xuICAgIHByb3RlY3RlZCBvYnNlcnZlUm91dGVyRXZlbnQ8VEV2ZW50IGV4dGVuZHMgRXZlbnQ+KGV2ZW50VHlwZTogVHlwZTxURXZlbnQ+LCBhdXRvVW5zdWJzY3JpYmU6IGJvb2xlYW4gPSB0cnVlKTogT2JzZXJ2YWJsZTxURXZlbnQ+XG4gICAge1xuICAgICAgICBsZXQgb2JzZXJ2YWJsZSA9IHRoaXMucm91dGVyLmV2ZW50cztcblxuICAgICAgICBpZiAoYXV0b1Vuc3Vic2NyaWJlKSBvYnNlcnZhYmxlID0gb2JzZXJ2YWJsZS5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3llZCkpO1xuICAgICAgICBcbiAgICAgICAgcmV0dXJuIG9ic2VydmFibGUucGlwZShmaWx0ZXIoZXZlbnQgPT4gZXZlbnQuY29uc3RydWN0b3IgPT09IGV2ZW50VHlwZSkpIGFzIE9ic2VydmFibGU8VEV2ZW50PjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZWNvdXJzaXZlbHkgcnVucyBhIHByb2Nlc3NpbmcgZnVuY3Rpb24gb24gdGhlIHJvdXRlIGFuZCBpdHMgY2hpbGRyZW4uXG4gICAgICogU2NhbiBpcyBkb25lIGZyb20gcGFyZW50IHRvIGNoaWxkLCBtZWFuaW5nIHRoZSBwYXJlbnQgaXMgdGhlIGZpcnN0IHRvIHByb2Nlc3MuXG4gICAgICpcbiAgICAgKiBAaWdub3JlXG4gICAgICogQHByb3RlY3RlZFxuICAgICAqIEBwYXJhbSB7QWN0aXZhdGVkUm91dGVTbmFwc2hvdH0gcm91dGUgVGhlIHRvcCByb3V0ZSBvbiB3aGljaCB0byBhcHBseSB0aGUgcHJvY2Vzc2luZyBmdW5jdGlvbi5cbiAgICAgKiBAcGFyYW0geyhyb3V0ZTogQWN0aXZhdGVkUm91dGVTbmFwc2hvdCwgY29tcG9uZW50OiBhbnkpID0+IGJvb2xlYW59IHByb2Nlc3MgVGhlIGZ1bmN0aW9uIHRvIHJ1biBvbiB0aGUgcm91dGUgYW5kIGl0cyBjaGlsZHJlbi4gVGhlIGZ1bmN0aW9uIHJlY2VpdmVzIGEgYHJvdXRlYCBhcmd1bWVudCB3aGljaCByZWZsZWN0cyB0aGUgcm91dGUgYmVpbmcgcHJvY2Vzc2VkLFxuICAgICAqIGFuZCBhIGBjb21wb25lbnRgIGFyZ3VtZW50IHdoaWNoIHJlZmxlY3RzIHRoZSBjb21wb25lbnQgdGhhdCB3YXMgbG9hZGVkIGZvciB0aGUgcm91dGUncyBvdXRsZXQuXG4gICAgICogSWYgdGhlIGNvcnJlc3BvbmRpbmcgb3V0bGV0IHdhc24ndCBtYXJrZWQgd2l0aCB0aGUgYHB1Ymxpc2hDb21wb25lbnRgIGRpcmVjdGl2ZSwgdGhlIGBjb21wb25lbnRgIGFyZ3VtZW50IHdpbGwgYmUgbnVsbC5cbiAgICAgKiBcbiAgICAgKiBSZXR1cm5pbmcgYHRydWVgIGZyb20gdGhlIHByb2Nlc3MgZnVuY3Rpb24gaXMgZXF1YWwgdG8gc2F5aW5nICd3b3JrIGhhcyBjb21wbGV0ZWQnIGFuZCB3aWxsIHN0b3AgcHJvcG9nYXRpb24gdG8gdGhlIHJvdXRlJ3MgY2hpbGRyZW4uXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFtsZXZlbHM9LTFdIChPcHRpb25hbCkgVGhlIG51bWJlciBvZiBsZXZlbHMgKGV4Y2x1ZGluZyB0aGUgcGFyZW50KSB0byBkaXZlIGRlZXBlciBpbnRvIHRoZSByb3V0ZSB0cmVlLlxuICAgICAqIEEgdmFsdWUgb2YgMSBmb3IgZXhhbXBsZSwgd2lsbCBwcm9jZXNzIHRoZSByb3V0ZSBhbmQgaXRzIGZpcnN0LWxldmVsIGNoaWxkcmVuIG9ubHkuIEJ5IGRlZmF1bHQsIHNjYW5zIGFsbCBsZXZlbHMgb2YgdGhlIHJvdXRlIHRyZWUuXG4gICAgICovXG4gICAgcHJvdGVjdGVkIGRlZXBTY2FuUm91dGUocm91dGU6IEFjdGl2YXRlZFJvdXRlU25hcHNob3QsIHByb2Nlc3M6IChyb3V0ZTogQWN0aXZhdGVkUm91dGVTbmFwc2hvdCwgY29tcG9uZW50OiBhbnkpID0+IGJvb2xlYW4gICwgbGV2ZWxzPzogbnVtYmVyKTogdm9pZDtcbiAgICAvKipcbiAgICAgKiBSZWNvdXJzaXZlbHkgcnVucyBhIHByb2Nlc3NpbmcgZnVuY3Rpb24gb24gdGhlIHJvdXRlIGFuZCBpdHMgY2hpbGRyZW4uXG4gICAgICogU2NhbiBpcyBkb25lIGZyb20gcGFyZW50IHRvIGNoaWxkLCBtZWFuaW5nIHRoZSBwYXJlbnQgaXMgdGhlIGZpcnN0IHRvIHByb2Nlc3MuXG4gICAgICpcbiAgICAgKiBAaWdub3JlXG4gICAgICogQHByb3RlY3RlZFxuICAgICAqIEBwYXJhbSB7QWN0aXZhdGVkUm91dGVTbmFwc2hvdH0gcm91dGUgVGhlIHRvcCByb3V0ZSBvbiB3aGljaCB0byBhcHBseSB0aGUgcHJvY2Vzc2luZyBmdW5jdGlvbi5cbiAgICAgKiBAcGFyYW0geyhyb3V0ZTogQWN0aXZhdGVkUm91dGVTbmFwc2hvdCwgY29tcG9uZW50OiBhbnkpID0+IHZvaWR9IHByb2Nlc3MgVGhlIGZ1bmN0aW9uIHRvIHJ1biBvbiB0aGUgcm91dGUgYW5kIGl0cyBjaGlsZHJlbi4gVGhlIGZ1bmN0aW9uIHJlY2VpdmVzIGEgYHJvdXRlYCBhcmd1bWVudCB3aGljaCByZWZsZWN0cyB0aGUgcm91dGUgYmVpbmcgcHJvY2Vzc2VkLFxuICAgICAqIGFuZCBhIGBjb21wb25lbnRgIGFyZ3VtZW50IHdoaWNoIHJlZmxlY3RzIHRoZSBjb21wb25lbnQgdGhhdCB3YXMgbG9hZGVkIGZvciB0aGUgcm91dGUncyBvdXRsZXQuXG4gICAgICogSWYgdGhlIGNvcnJlc3BvbmRpbmcgb3V0bGV0IHdhc24ndCBtYXJrZWQgd2l0aCB0aGUgYHB1Ymxpc2hDb21wb25lbnRgIGRpcmVjdGl2ZSwgdGhlIGBjb21wb25lbnRgIGFyZ3VtZW50IHdpbGwgYmUgbnVsbC5cbiAgICAgKiBcbiAgICAgKiBSZXR1cm5pbmcgYHRydWVgIGZyb20gdGhlIHByb2Nlc3MgZnVuY3Rpb24gaXMgZXF1YWwgdG8gc2F5aW5nICd3b3JrIGhhcyBjb21wbGV0ZWQnIGFuZCB3aWxsIHN0b3AgcHJvcG9nYXRpb24gdG8gdGhlIHJvdXRlJ3MgY2hpbGRyZW4uXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFtsZXZlbHM9LTFdIChPcHRpb25hbCkgVGhlIG51bWJlciBvZiBsZXZlbHMgKGV4Y2x1ZGluZyB0aGUgcGFyZW50KSB0byBkaXZlIGRlZXBlciBpbnRvIHRoZSByb3V0ZSB0cmVlLlxuICAgICAqIEEgdmFsdWUgb2YgMSBmb3IgZXhhbXBsZSwgd2lsbCBwcm9jZXNzIHRoZSByb3V0ZSBhbmQgaXRzIGZpcnN0LWxldmVsIGNoaWxkcmVuIG9ubHkuIEJ5IGRlZmF1bHQsIHNjYW5zIGFsbCBsZXZlbHMgb2YgdGhlIHJvdXRlIHRyZWUuXG4gICAgICovXG4gICAgcHJvdGVjdGVkIGRlZXBTY2FuUm91dGUocm91dGU6IEFjdGl2YXRlZFJvdXRlU25hcHNob3QsIHByb2Nlc3M6IChyb3V0ZTogQWN0aXZhdGVkUm91dGVTbmFwc2hvdCwgY29tcG9uZW50OiBhbnkpID0+IHZvaWQsIGxldmVscz86IG51bWJlcik6IHZvaWQ7XG4gICAgLyoqXG4gICAgICogUmVjb3Vyc2l2ZWx5IHJ1bnMgYSBwcm9jZXNzaW5nIGZ1bmN0aW9uIG9uIHRoZSByb3V0ZSBhbmQgaXRzIGNoaWxkcmVuLlxuICAgICAqIFNjYW4gaXMgZG9uZSBmcm9tIHBhcmVudCB0byBjaGlsZCwgbWVhbmluZyB0aGUgcGFyZW50IGlzIHRoZSBmaXJzdCB0byBwcm9jZXNzLlxuICAgICAqIFxuICAgICAqIEBwcm90ZWN0ZWRcbiAgICAgKiBAcGFyYW0ge0FjdGl2YXRlZFJvdXRlU25hcHNob3R9IHJvdXRlIFRoZSB0b3Agcm91dGUgb24gd2hpY2ggdG8gYXBwbHkgdGhlIHByb2Nlc3NpbmcgZnVuY3Rpb24uXG4gICAgICogQHBhcmFtIHsocm91dGU6IEFjdGl2YXRlZFJvdXRlU25hcHNob3QsIGNvbXBvbmVudDogYW55KSA9PiBib29sZWFuIHwgdm9pZH0gcHJvY2VzcyBUaGUgZnVuY3Rpb24gdG8gcnVuIG9uIHRoZSByb3V0ZSBhbmQgaXRzIGNoaWxkcmVuLiBUaGUgZnVuY3Rpb24gcmVjZWl2ZXMgYSBgcm91dGVgIGFyZ3VtZW50IHdoaWNoIHJlZmxlY3RzIHRoZSByb3V0ZSBiZWluZyBwcm9jZXNzZWQsXG4gICAgICogYW5kIGEgYGNvbXBvbmVudGAgYXJndW1lbnQgd2hpY2ggcmVmbGVjdHMgdGhlIGNvbXBvbmVudCB0aGF0IHdhcyBsb2FkZWQgZm9yIHRoZSByb3V0ZSdzIG91dGxldC5cbiAgICAgKiBJZiB0aGUgY29ycmVzcG9uZGluZyBvdXRsZXQgd2Fzbid0IG1hcmtlZCB3aXRoIHRoZSBgcHVibGlzaENvbXBvbmVudGAgZGlyZWN0aXZlLCB0aGUgYGNvbXBvbmVudGAgYXJndW1lbnQgd2lsbCBiZSBudWxsLlxuICAgICAqIFxuICAgICAqIFJldHVybmluZyBgdHJ1ZWAgZnJvbSB0aGUgcHJvY2VzcyBmdW5jdGlvbiBpcyBlcXVhbCB0byBzYXlpbmcgJ3dvcmsgaGFzIGNvbXBsZXRlZCcgYW5kIHdpbGwgc3RvcCBwcm9wb2dhdGlvbiB0byB0aGUgcm91dGUncyBjaGlsZHJlbi5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gW2xldmVscz0tMV0gKE9wdGlvbmFsKSBUaGUgbnVtYmVyIG9mIGxldmVscyAoZXhjbHVkaW5nIHRoZSBwYXJlbnQpIHRvIGRpdmUgZGVlcGVyIGludG8gdGhlIHJvdXRlIHRyZWUuXG4gICAgICogQSB2YWx1ZSBvZiAxIGZvciBleGFtcGxlLCB3aWxsIHByb2Nlc3MgdGhlIHJvdXRlIGFuZCBpdHMgZmlyc3QtbGV2ZWwgY2hpbGRyZW4gb25seS4gQnkgZGVmYXVsdCwgc2NhbnMgYWxsIGxldmVscyBvZiB0aGUgcm91dGUgdHJlZS5cbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgZGVlcFNjYW5Sb3V0ZShyb3V0ZTogQWN0aXZhdGVkUm91dGVTbmFwc2hvdCwgcHJvY2VzczogKHJvdXRlOiBBY3RpdmF0ZWRSb3V0ZVNuYXBzaG90LCBjb21wb25lbnQ6IGFueSkgPT4gYm9vbGVhbiB8IHZvaWQsIGxldmVsczogbnVtYmVyID0gLTEpOiB2b2lkXG4gICAge1xuICAgICAgICAvLyBNYWtlIHN1cmUgdGhlIGNhbGxlciB3YW50cyBzY2FuIHRvIHByb2NlZWQsIHRoZW4gbWFrZSBzdXJlIGxldmVsIGxpbWl0IHdhc24ndCByZWFjaGVkLlxuICAgICAgICBjb25zdCBwcm9jZXNzaW5nQ29uY2x1ZGVkID0gcHJvY2Vzcyhyb3V0ZSwgdGhpcy5jb21wb25lbnRCdXM/Lmluc3RhbmNlKHJvdXRlLm91dGxldCkpO1xuICAgICAgICAvLyBOZWdhdGl2ZSB2YWx1ZXMgd2lsbCBzY2FuIGFsbCwgcG9zaXRpdmVzIHdpbGwgc2NhbiB1bnRpbCByZWFjaGluZyB6ZXJvLlxuICAgICAgICBjb25zdCBzaG91bGRTY2FuQ2hpbGRyZW4gID0gIXByb2Nlc3NpbmdDb25jbHVkZWQgJiYgbGV2ZWxzICE9PSAwO1xuXG4gICAgICAgIGlmIChzaG91bGRTY2FuQ2hpbGRyZW4gJiYgcm91dGUuY2hpbGRyZW4pIHJvdXRlLmNoaWxkcmVuLmZvckVhY2goY2hpbGRSb3V0ZSA9PiB0aGlzLmRlZXBTY2FuUm91dGUoY2hpbGRSb3V0ZSwgcHJvY2VzcywgbGV2ZWxzIC0gMSkpO1xuICAgIH1cbiAgICBcbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIG9ic2VydmFibGUgdGhhdCBydW5zIGFsbCB0aGUgc3BlY2lmaWVkIHJlc29sdmVycyBhbmQgY29uY2F0cyB0aGVpciByZXN1bHRzIGFzIGFuIGFycmF5LlxuICAgICAqIFRoZSByZXNvbHZlcnMgd2lsbCBiZSBwYXNzZWQgd2l0aCB0aGUgaW5zdGFuY2Ugb2YgdGhlIGNvbXBvbmVudCBmb3IgdGhlIGN1cnJlbnRseSBhY3RpdmF0ZWQgcm91dGUuXG4gICAgICpcbiAgICAgKiBAcHJvdGVjdGVkXG4gICAgICogQHBhcmFtIHsoUmVzb2x2ZXIgfCBSZXNvbHZlcltdKX0gcmVzb2x2ZXJzIFRoZSByZXNvbHZlcihzKSB0byBjb25jYXQuXG4gICAgICogQHBhcmFtIHsuLi5hbnlbXX0gcmVzb2x2ZXJBcmdzIChPcHRpb25hbCkgQW55IGFyZ3VtZW50cyB0byBwYXNzIGludG8gdGhlIHJlc29sdmVycyBpbiBhZGRpdGlvbiB0byB0aGUgY29tcG9uZW50LlxuICAgICAqIEByZXR1cm5zIHtPYnNlcnZhYmxlPGFueVtdPn0gQW4gYXJyYXkgd2l0aCB0aGUgY29uY2F0ZW5hdGVkIHJlc3VsdHMgb2YgdGhlIHJlc29sdmVycy5cbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgcmVzb2x2ZShyZXNvbHZlcnM6IFJlc29sdmVyIHwgUmVzb2x2ZXJbXSwgLi4ucmVzb2x2ZXJBcmdzOiBhbnlbXSk6IE9ic2VydmFibGU8YW55W10+XG4gICAge1xuICAgICAgICBpZiAoIXJlc29sdmVycykgcmV0dXJuIG9mKFtdKTtcblxuICAgICAgICAvLyBDYXN0IGFycmF5XG4gICAgICAgIGlmICghQXJyYXkuaXNBcnJheShyZXNvbHZlcnMpKSByZXNvbHZlcnMgPSBbcmVzb2x2ZXJzXTtcblxuICAgICAgICAvLyBSdW4gcmVzb2x2ZXJzIHRvIGNyZWF0ZSBvYnNlcnZhYmxlIHRhc2tzXG4gICAgICAgIGNvbnN0IG9ic2VydmFibGVzID0gcmVzb2x2ZXJzLm1hcChyZXNvbHZlID0+IHJlc29sdmUodGhpcy5hY3RpdmF0ZWRSb3V0ZUNvbXBvbmVudCwgLi4ucmVzb2x2ZXJBcmdzKSk7XG4gICAgICAgIFxuICAgICAgICAvLyBSdW4gdGFza3MgYW5kIG91dHB1dCB0aGVpciByZXR1cm5lZCBkYXRhIGFzIGFuIGFycmF5XG4gICAgICAgIHJldHVybiBmcm9tKG9ic2VydmFibGVzKS5waXBlKGNvbmNhdEFsbCgpLCB0b0FycmF5KCkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW4gb2JzZXJ2YWJsZSB0aGF0IHJ1bnMgYWxsIHRoZSBzcGVjaWZpZWQgcmVzb2x2ZXJzIGFuZCBjb25jYXRzIHRoZWlyIHJlc3VsdHMgYXMgYW4gYXJyYXkuXG4gICAgICogVGhlIHJlc29sdmVycyB3aWxsIGJlIHBhc3NlZCB3aXRoIHRoZSBpbnN0YW5jZSBvZiB0aGUgY29tcG9uZW50IGZvciB0aGUgY3VycmVudGx5IGFjdGl2YXRlZCByb3V0ZS5cbiAgICAgKiBcbiAgICAgKiAqKkFuZ3VsYXIgVW5pdmVyc2FsOioqXG4gICAgICogSW4gU1NSLCB0aGUgc2VydmVyIGRvZXNuJ3Qgd2FpdCBmb3IgYXN5bmMgY29kZSB0byBjb21wbGV0ZS4gVGhlIHJlc3VsdCBpcyBzY3JhcGVycyBhbmQgc2VhcmNoIGVuZ2luZXMgcmVjZWl2aW5nIGEgcGFnZSB3aXRob3V0IHJlc29sdmVkIGRhdGEsXG4gICAgICogd2hpY2ggaXMgYmFkIGluIGNhc2UgeW91IG5lZWQgdGhlbSB0byByZWFkIHNvbWUgcmVzb2x2ZWQgbWV0YWRhdGEgdGFncyBmb3IgZXhhbXBsZS5cbiAgICAgKiBcbiAgICAgKiBVc2luZyBgWm9uZWAgZGlyZWN0bHksIHRoaXMgbWV0aG9kIGNyZWF0ZXMgYSBtYWNybyB0YXNrIGFuZCBjb21wbGV0ZXMgaXQgd2hlbiByZXNvbHZlcyBhcmUgZG9uZSBvciBoYXZlIGVycm9yZWQuXG4gICAgICogVGhpcyBtYWtlcyB0aGUgc2VydmVyIGJsb2NrIGFuZCB3YWl0IHVudGlsIGV2ZXJ5dGhpbmcgaXMgcmVzb2x2ZWQgb3IgZXJyb3JzIGJlZm9yZSByZXR1cm5pbmcgdGhlIHJlbmRlcmVkIHBhZ2UuXG4gICAgICogXG4gICAgICogPiAq4oS5IE1ha2Ugc3VyZSB5b3VyIHJlc29sdmVzIGFuZCBwcm9jZXNzIGZ1bmN0aW9uIGFyZSBmYXN0IGVub3VnaCBzbyB0aGF0IHRoZSBzZXJ2ZXIgd29uJ3QgaGFuZyB0b28gbXVjaCB0cnlpbmcgdG8gcmVuZGVyLipcbiAgICAgKlxuICAgICAqIEBzZWUgaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9hLzUwMDY1NzgzLzQzNzE1MjUgZm9yIHRoZSBkaXNjdXNzaW9uLlxuICAgICAqXG4gICAgICogQHNlZSB7UmVzb2x2ZXJNYWNyb1Rhc2tJZFByZWZpeH0gaWYgeW91IG5lZWQgdG8gaWRlbnRpZnkgdGhlIGNyZWF0ZWQgbWFjcm8gdGFzayBpbiB5b3VyIGNvZGUuXG4gICAgICogXG4gICAgICogQHByb3RlY3RlZFxuICAgICAqIEBwYXJhbSB7KFJlc29sdmVyIHwgUmVzb2x2ZXJbXSl9IHJlc29sdmVycyBUaGUgcmVzb2x2ZXIocykgdG8gY29uY2F0LlxuICAgICAqIEBwYXJhbSB7Li4uYW55W119IHJlc29sdmVyQXJncyAoT3B0aW9uYWwpIEFueSBhcmd1bWVudHMgdG8gcGFzcyBpbnRvIHRoZSByZXNvbHZlcnMgaW4gYWRkaXRpb24gdG8gdGhlIGNvbXBvbmVudC5cbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgcmVzb2x2ZUluTWFjcm9UYXNrKHJlc29sdmVyczogUmVzb2x2ZXIgfCBSZXNvbHZlcltdLCAuLi5yZXNvbHZlckFyZ3M6IGFueVtdKTogT2JzZXJ2YWJsZTxhbnlbXT5cbiAgICB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZW1wdHktZnVuY3Rpb25cbiAgICAgICAgY29uc3QgbWFjcm9UYXNrID0gWm9uZS5jdXJyZW50LnNjaGVkdWxlTWFjcm9UYXNrKGAke1Jlc29sdmVyTWFjcm9UYXNrSWRQcmVmaXh9LSR7TWF0aC5yYW5kb20oKX1gLCAoKSA9PiB7IH0sIHt9LCAoKSA9PiB7IH0sICgpID0+IHsgfSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucmVzb2x2ZShyZXNvbHZlcnMsIC4uLnJlc29sdmVyQXJncylcbiAgICAgICAgICAgIC8vIFNpZ25hbCBlbmQgb2YgbWFjcm8gdGFzayBvbiBjb21wbGV0aW9uIG9yIGVycm9yIGFuZCBhbGxvdyBzZXJ2ZXIgdG8gcmV0dXJuXG4gICAgICAgICAgICAucGlwZShmaW5hbGl6ZSgoKSA9PiBtYWNyb1Rhc2suaW52b2tlKCkpXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhlIGluc3RhbmNlIG9mIHRoZSBjb21wb25lbnQgY3JlYXRlZCBmb3IgdGhlIGN1cnJlbnRseSBhY3RpdmF0ZWQgcm91dGUuXG4gICAgICogSWYgbm8gY29tcG9uZW50IGJ1cyB3YXMgc3VwcGxpZWQgYXQgY29uc3RydWN0aW9uIHRpbWUsIHRoaXMgd2lsbCBiZSBgdW5kZWZpbmVkYC5cbiAgICAgKlxuICAgICAqIEByZWFkb25seVxuICAgICAqIEBwcm90ZWN0ZWRcbiAgICAgKiBAdHlwZSB7KGFueSB8IG51bGwpfVxuICAgICAqL1xuICAgIHByb3RlY3RlZCBnZXQgYWN0aXZhdGVkUm91dGVDb21wb25lbnQoKTogYW55IHwgbnVsbFxuICAgIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY29tcG9uZW50QnVzPy5pbnN0YW5jZSh0aGlzLnJvdXRlLm91dGxldCk7XG4gICAgfVxufVxuIl19