UNPKG

@bespunky/angular-zen

Version:

The Angular tools you always wished were there.

193 lines (192 loc) 25.2 kB
import { BehaviorSubject } from 'rxjs'; import { EventEmitter, Injectable } from '@angular/core'; import { PRIMARY_OUTLET } from '@angular/router'; import * as i0 from "@angular/core"; /** * Holds data related with a router outlet event. * * @export * @class RouterOutletEventData */ export class RouterOutletEventData { /** * Creates an instance of RouterOutletEventData. * * @param {string} outletName The name of the outlet which triggered the event. For the primary unnamed outlet, this will be angular's PRIMARY_OUTLET. */ constructor(outletName) { this.outletName = outletName; } /** * `true` if the event was triggered by the primary unnamed outlet; otherwise `false`. * * @readonly * @type {boolean} */ get isPrimaryOutlet() { return this.outletName === PRIMARY_OUTLET; } } /** * Holds data related with component publishing triggered by outlet activation. * * @export * @class ComponentPublishEventData * @extends {RouterOutletEventData} */ export class ComponentPublishEventData extends RouterOutletEventData { /** * Creates an instance of ComponentPublishEventData. * * @param {BehaviorSubject<AnyObject | null>} changes The observable used to track changes to the activated component of the triggering outlet. * @param {string} outletName The name of the outlet which triggered the event. For the primary unnamed outlet, this will be angular's PRIMARY_OUTLET. */ constructor(changes, outletName) { super(outletName); this.changes = changes; } /** * The instance of the last component activated by the outlet which triggered the event. * This will be null if the outlet has deactivated the component. * * @readonly * @type {(AnyObject | null)} */ get componentInstance() { return this.changes.value; } } /** * Provides a publish bus for the currently rendered component. * * **Why?** * Angular's router only provides the type of component being rendered for a specific route, but not the instance it has created for it. * This service is a bridge which allows other services to get a hold of the instance of a currently rendered component. * * **How to use:** * Use the [`publishComponent`](/directives/PublishComponentDirective.html) directive on your `<router-outlet>` element. This will hook into the outlet's `activate` event and pass * the activated component to the bus service: * @example * <!-- Component template --> * <router-outlet publishComponent name="header"></router-outlet> * <router-outlet publishComponent ></router-outlet> * <router-outlet publishComponent name="footer"></router-outlet> * * @export * @class RouterOutletComponentBus */ export class RouterOutletComponentBus { constructor() { this._outletsState = new Map(); /** * A map of the currently instantiated components by outlet name. * Users can either subscribe to changes, or get the current value of a component. * * The primary unnamed outlet component will be accessible via PRIMARY_OUTLET, but for scalability it is better to access it via the `instance()` method. * * @private */ this.components = new Map(); /** * Emits whenever a router outlet marked with the `publishComponent` directive activates a component. * When an outlet deactivates a component, the published component instance will be `null`. * * @type {EventEmitter<ComponentPublishEventData>} */ this.componentPublished = new EventEmitter(); /** * Emits whenever a router outlet marked with the `publishComponent` directive is removed from the DOM. * * @type {EventEmitter<ComponentPublishEventData>} */ this.componentUnpublished = new EventEmitter(); } /** * Gets a shallow clone of the current state outlet state. * * @readonly * @type {(Map<string, AnyObject | null>)} */ get outletsState() { return new Map(this._outletsState); } /** * Publishes the instance of a currently activated or deactivated component by the specified outlet. * When an outlet first publishes, this will create an observable for tracking the outlet's changes. * The observable can be fetched using the `changes()` method. * Following calls to publish a component by the same outlet will subscribers. * * The last published component of an outlet can be fetched using the `instance()` method. * * @param {AnyObject | null} instance The instance of the activated component. For publishing deactivation of a component pass `null`. * @param {string} [outletName=PRIMARY_OUTLET] (Optional) The name of the outlet which activated or deactivated the component. The primary unnamed outlet will be used when not specified. */ publishComponent(instance, outletName = PRIMARY_OUTLET) { const components = this.components; let componentChanges = components.get(outletName); if (!componentChanges) { componentChanges = new BehaviorSubject(instance); components.set(outletName, componentChanges); } this._outletsState.set(outletName, instance); componentChanges.next(instance); this.componentPublished.emit(new ComponentPublishEventData(componentChanges, outletName)); } /** * Notifies any subscribers to the outlet's changes observable that the outlet is being removed by completing * the observable and removes the observable from the service. * * @param {string} [outletName=PRIMARY_OUTLET] (Optional) The name of the outlet to unpublish. The primary unnamed outlet will be used when not specified. */ unpublishComponent(outletName = PRIMARY_OUTLET) { const components = this.components; if (components.has(outletName)) { // Notify any subscribers that the outlet will stop emitting components.get(outletName)?.complete(); // Make sure the outlet is no longer present on the bus components.delete(outletName); this._outletsState.delete(outletName); this.componentUnpublished.emit(new RouterOutletEventData(outletName)); } } /** * Checks whether the outlet by the given name is present in the DOM and has already activated at least one component. * This will be `true` even if the outlet currently has no active component (component is `null`). * * A `false` value can either mean the outlet hasn't been marked with `publishComponent`, or that the outlet is not currently rendered (not present in the DOM). * * When `true`, the user can subscribe to changes of that outlet through the `changes()` method. * * @param {string} [outletName=PRIMARY_OUTLET] (Optional) The name of the outlet to check. The primary unnamed outlet will be checked if no name is provided. * @returns {boolean} `true` if the outlet has published a component at least once; otherwise `false`. */ isComponentPublished(outletName = PRIMARY_OUTLET) { return this.components.has(outletName); } /** * Gets an observable which can be used to track changes to the activated component of the specified outlet. * If the outlet is not rendered (present in the DOM), or hasn't been marked with `publishComponent`, this will be `null`. * * @param {string} [outletName=PRIMARY_OUTLET] (Optional) The name of the outlet to track changes for. The primary unnamed outlet will be used when not specified. * @returns {(BehaviorSubject<AnyObject | null> | null)} An observable to use for tracking changes to the activated component for the specified outlet, or `null` if no such outlet exists. */ changes(outletName = PRIMARY_OUTLET) { return this.components.get(outletName) ?? null; } /** * Gets the current instance of the component created by the specified outlet. * * @param {string} [outletName=PRIMARY_OUTLET] (Optional) The name of the outlet to fetch the component instance for. If not provided, the primary unnamed outlet's component will be fetched. * @returns {(AnyObject | null)} The instance of the component created by the specified outlet. If the outlet doesn't exist, or there is no component instance for the requested outlet, returns `null`. */ instance(outletName = PRIMARY_OUTLET) { return this.components.get(outletName)?.value ?? null; } } RouterOutletComponentBus.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RouterOutletComponentBus, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); RouterOutletComponentBus.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RouterOutletComponentBus, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RouterOutletComponentBus, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGVyLW91dGxldC1jb21wb25lbnQtYnVzLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9saWJzL2FuZ3VsYXItemVuL3JvdXRlci14L3NyYy9vdXRsZXQvcm91dGVyLW91dGxldC1jb21wb25lbnQtYnVzLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGVBQWUsRUFBVyxNQUFNLE1BQU0sQ0FBQztBQUNoRCxPQUFPLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6RCxPQUFPLEVBQUUsY0FBYyxFQUFZLE1BQU0saUJBQWlCLENBQUM7O0FBRzNEOzs7OztHQUtHO0FBQ0gsTUFBTSxPQUFPLHFCQUFxQjtJQUU5Qjs7OztPQUlHO0lBQ0gsWUFBNEIsVUFBa0I7UUFBbEIsZUFBVSxHQUFWLFVBQVUsQ0FBUTtJQUFJLENBQUM7SUFFbkQ7Ozs7O09BS0c7SUFDSCxJQUFXLGVBQWU7UUFFdEIsT0FBTyxJQUFJLENBQUMsVUFBVSxLQUFLLGNBQWMsQ0FBQztJQUM5QyxDQUFDO0NBQ0o7QUFFRDs7Ozs7O0dBTUc7QUFDSCxNQUFNLE9BQU8seUJBQTBCLFNBQVEscUJBQXFCO0lBRWhFOzs7OztPQUtHO0lBQ0gsWUFBNEIsT0FBMEMsRUFBRSxVQUFrQjtRQUV0RixLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7UUFGTSxZQUFPLEdBQVAsT0FBTyxDQUFtQztJQUd0RSxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0gsSUFBVyxpQkFBaUI7UUFFeEIsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQztJQUM5QixDQUFDO0NBQ0o7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQUVILE1BQU0sT0FBTyx3QkFBd0I7SUFEckM7UUFHWSxrQkFBYSxHQUFHLElBQUksR0FBRyxFQUE0QixDQUFDO1FBYTVEOzs7Ozs7O1dBT0c7UUFDYyxlQUFVLEdBQUcsSUFBSSxHQUFHLEVBQTZDLENBQUM7UUFFbkY7Ozs7O1dBS0c7UUFDYSx1QkFBa0IsR0FBOEMsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUNuRzs7OztXQUlHO1FBQ2EseUJBQW9CLEdBQTRDLElBQUksWUFBWSxFQUFFLENBQUM7S0EyRnRHO0lBNUhHOzs7OztPQUtHO0lBQ0gsSUFBVyxZQUFZO1FBRW5CLE9BQU8sSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQ3ZDLENBQUM7SUEwQkQ7Ozs7Ozs7Ozs7T0FVRztJQUNJLGdCQUFnQixDQUFDLFFBQTBCLEVBQUUsYUFBcUIsY0FBYztRQUVuRixNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDO1FBRW5DLElBQUksZ0JBQWdCLEdBQUcsVUFBVSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUVsRCxJQUFJLENBQUMsZ0JBQWdCLEVBQ3JCO1lBQ0ksZ0JBQWdCLEdBQUcsSUFBSSxlQUFlLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDakQsVUFBVSxDQUFDLEdBQUcsQ0FBQyxVQUFVLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztTQUNoRDtRQUVELElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRSxRQUFRLENBQUMsQ0FBQztRQUM3QyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7UUFFaEMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxJQUFJLHlCQUF5QixDQUFDLGdCQUFnQixFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUM7SUFDOUYsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ksa0JBQWtCLENBQUMsYUFBcUIsY0FBYztRQUV6RCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDO1FBRW5DLElBQUksVUFBVSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsRUFDOUI7WUFDSSw0REFBNEQ7WUFDNUQsVUFBVSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsRUFBRSxRQUFRLEVBQUUsQ0FBQztZQUN2Qyx1REFBdUQ7WUFDdkQsVUFBVSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUM5QixJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUV0QyxJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLElBQUkscUJBQXFCLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztTQUN6RTtJQUNMLENBQUM7SUFFRDs7Ozs7Ozs7OztPQVVHO0lBQ0ksb0JBQW9CLENBQUMsYUFBcUIsY0FBYztRQUUzRCxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSSxPQUFPLENBQUMsYUFBcUIsY0FBYztRQUU5QyxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxJQUFJLElBQUksQ0FBQztJQUNuRCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxRQUFRLENBQUMsYUFBcUIsY0FBYztRQUUvQyxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxFQUFFLEtBQUssSUFBSSxJQUFJLENBQUM7SUFDMUQsQ0FBQzs7c0hBL0hRLHdCQUF3QjswSEFBeEIsd0JBQXdCLGNBRFgsTUFBTTs0RkFDbkIsd0JBQXdCO2tCQURwQyxVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCAgICAgICAgICB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgRXZlbnRFbWl0dGVyLCBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBQUklNQVJZX09VVExFVCAgICAgICAgICAgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuaW1wb3J0IHsgQW55T2JqZWN0IH0gZnJvbSAnQGJlc3B1bmt5L3R5cGVzY3JpcHQtdXRpbHMnO1xuXG4vKipcbiAqIEhvbGRzIGRhdGEgcmVsYXRlZCB3aXRoIGEgcm91dGVyIG91dGxldCBldmVudC5cbiAqXG4gKiBAZXhwb3J0XG4gKiBAY2xhc3MgUm91dGVyT3V0bGV0RXZlbnREYXRhXG4gKi9cbmV4cG9ydCBjbGFzcyBSb3V0ZXJPdXRsZXRFdmVudERhdGFcbntcbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIFJvdXRlck91dGxldEV2ZW50RGF0YS5cbiAgICAgKiBcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gb3V0bGV0TmFtZSBUaGUgbmFtZSBvZiB0aGUgb3V0bGV0IHdoaWNoIHRyaWdnZXJlZCB0aGUgZXZlbnQuIEZvciB0aGUgcHJpbWFyeSB1bm5hbWVkIG91dGxldCwgdGhpcyB3aWxsIGJlIGFuZ3VsYXIncyBQUklNQVJZX09VVExFVC5cbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihwdWJsaWMgcmVhZG9ubHkgb3V0bGV0TmFtZTogc3RyaW5nKSB7IH1cbiAgICBcbiAgICAvKipcbiAgICAgKiBgdHJ1ZWAgaWYgdGhlIGV2ZW50IHdhcyB0cmlnZ2VyZWQgYnkgdGhlIHByaW1hcnkgdW5uYW1lZCBvdXRsZXQ7IG90aGVyd2lzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHJlYWRvbmx5XG4gICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICovXG4gICAgcHVibGljIGdldCBpc1ByaW1hcnlPdXRsZXQoKTogYm9vbGVhblxuICAgIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3V0bGV0TmFtZSA9PT0gUFJJTUFSWV9PVVRMRVQ7XG4gICAgfVxufVxuXG4vKipcbiAqIEhvbGRzIGRhdGEgcmVsYXRlZCB3aXRoIGNvbXBvbmVudCBwdWJsaXNoaW5nIHRyaWdnZXJlZCBieSBvdXRsZXQgYWN0aXZhdGlvbi5cbiAqXG4gKiBAZXhwb3J0XG4gKiBAY2xhc3MgQ29tcG9uZW50UHVibGlzaEV2ZW50RGF0YVxuICogQGV4dGVuZHMge1JvdXRlck91dGxldEV2ZW50RGF0YX1cbiAqL1xuZXhwb3J0IGNsYXNzIENvbXBvbmVudFB1Ymxpc2hFdmVudERhdGEgZXh0ZW5kcyBSb3V0ZXJPdXRsZXRFdmVudERhdGFcbntcbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIENvbXBvbmVudFB1Ymxpc2hFdmVudERhdGEuXG4gICAgICogXG4gICAgICogQHBhcmFtIHtCZWhhdmlvclN1YmplY3Q8QW55T2JqZWN0IHwgbnVsbD59IGNoYW5nZXMgVGhlIG9ic2VydmFibGUgdXNlZCB0byB0cmFjayBjaGFuZ2VzIHRvIHRoZSBhY3RpdmF0ZWQgY29tcG9uZW50IG9mIHRoZSB0cmlnZ2VyaW5nIG91dGxldC5cbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gb3V0bGV0TmFtZSBUaGUgbmFtZSBvZiB0aGUgb3V0bGV0IHdoaWNoIHRyaWdnZXJlZCB0aGUgZXZlbnQuIEZvciB0aGUgcHJpbWFyeSB1bm5hbWVkIG91dGxldCwgdGhpcyB3aWxsIGJlIGFuZ3VsYXIncyBQUklNQVJZX09VVExFVC5cbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihwdWJsaWMgcmVhZG9ubHkgY2hhbmdlczogQmVoYXZpb3JTdWJqZWN0PEFueU9iamVjdCB8IG51bGw+LCBvdXRsZXROYW1lOiBzdHJpbmcpXG4gICAge1xuICAgICAgICBzdXBlcihvdXRsZXROYW1lKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgaW5zdGFuY2Ugb2YgdGhlIGxhc3QgY29tcG9uZW50IGFjdGl2YXRlZCBieSB0aGUgb3V0bGV0IHdoaWNoIHRyaWdnZXJlZCB0aGUgZXZlbnQuXG4gICAgICogVGhpcyB3aWxsIGJlIG51bGwgaWYgdGhlIG91dGxldCBoYXMgZGVhY3RpdmF0ZWQgdGhlIGNvbXBvbmVudC5cbiAgICAgKiBcbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKiBAdHlwZSB7KEFueU9iamVjdCB8IG51bGwpfVxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgY29tcG9uZW50SW5zdGFuY2UoKTogQW55T2JqZWN0IHwgbnVsbFxuICAgIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2hhbmdlcy52YWx1ZTtcbiAgICB9XG59XG5cbi8qKlxuICogUHJvdmlkZXMgYSBwdWJsaXNoIGJ1cyBmb3IgdGhlIGN1cnJlbnRseSByZW5kZXJlZCBjb21wb25lbnQuXG4gKiBcbiAqICoqV2h5PyoqICBcbiAqIEFuZ3VsYXIncyByb3V0ZXIgb25seSBwcm92aWRlcyB0aGUgdHlwZSBvZiBjb21wb25lbnQgYmVpbmcgcmVuZGVyZWQgZm9yIGEgc3BlY2lmaWMgcm91dGUsIGJ1dCBub3QgdGhlIGluc3RhbmNlIGl0IGhhcyBjcmVhdGVkIGZvciBpdC5cbiAqIFRoaXMgc2VydmljZSBpcyBhIGJyaWRnZSB3aGljaCBhbGxvd3Mgb3RoZXIgc2VydmljZXMgdG8gZ2V0IGEgaG9sZCBvZiB0aGUgaW5zdGFuY2Ugb2YgYSBjdXJyZW50bHkgcmVuZGVyZWQgY29tcG9uZW50LlxuICogXG4gKiAqKkhvdyB0byB1c2U6KiogIFxuICogVXNlIHRoZSBbYHB1Ymxpc2hDb21wb25lbnRgXSgvZGlyZWN0aXZlcy9QdWJsaXNoQ29tcG9uZW50RGlyZWN0aXZlLmh0bWwpIGRpcmVjdGl2ZSBvbiB5b3VyIGA8cm91dGVyLW91dGxldD5gIGVsZW1lbnQuIFRoaXMgd2lsbCBob29rIGludG8gdGhlIG91dGxldCdzIGBhY3RpdmF0ZWAgZXZlbnQgYW5kIHBhc3NcbiAqIHRoZSBhY3RpdmF0ZWQgY29tcG9uZW50IHRvIHRoZSBidXMgc2VydmljZTpcblxuICogQGV4YW1wbGVcbiAqIDwhLS0gQ29tcG9uZW50IHRlbXBsYXRlIC0tPlxuICogPHJvdXRlci1vdXRsZXQgcHVibGlzaENvbXBvbmVudCBuYW1lPVwiaGVhZGVyXCI+PC9yb3V0ZXItb3V0bGV0PlxuICogPHJvdXRlci1vdXRsZXQgcHVibGlzaENvbXBvbmVudCAgICAgICAgICAgICAgPjwvcm91dGVyLW91dGxldD5cbiAqIDxyb3V0ZXItb3V0bGV0IHB1Ymxpc2hDb21wb25lbnQgbmFtZT1cImZvb3RlclwiPjwvcm91dGVyLW91dGxldD5cbiAqICBcbiAqIEBleHBvcnRcbiAqIEBjbGFzcyBSb3V0ZXJPdXRsZXRDb21wb25lbnRCdXNcbiAqL1xuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBSb3V0ZXJPdXRsZXRDb21wb25lbnRCdXNcbntcbiAgICBwcml2YXRlIF9vdXRsZXRzU3RhdGUgPSBuZXcgTWFwPHN0cmluZywgQW55T2JqZWN0IHwgbnVsbD4oKTtcblxuICAgIC8qKlxuICAgICAqIEdldHMgYSBzaGFsbG93IGNsb25lIG9mIHRoZSBjdXJyZW50IHN0YXRlIG91dGxldCBzdGF0ZS5cbiAgICAgKlxuICAgICAqIEByZWFkb25seVxuICAgICAqIEB0eXBlIHsoTWFwPHN0cmluZywgQW55T2JqZWN0IHwgbnVsbD4pfVxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgb3V0bGV0c1N0YXRlKCk6IE1hcDxzdHJpbmcsIEFueU9iamVjdCB8IG51bGw+XG4gICAge1xuICAgICAgICByZXR1cm4gbmV3IE1hcCh0aGlzLl9vdXRsZXRzU3RhdGUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEEgbWFwIG9mIHRoZSBjdXJyZW50bHkgaW5zdGFudGlhdGVkIGNvbXBvbmVudHMgYnkgb3V0bGV0IG5hbWUuXG4gICAgICogVXNlcnMgY2FuIGVpdGhlciBzdWJzY3JpYmUgdG8gY2hhbmdlcywgb3IgZ2V0IHRoZSBjdXJyZW50IHZhbHVlIG9mIGEgY29tcG9uZW50LlxuICAgICAqIFxuICAgICAqIFRoZSBwcmltYXJ5IHVubmFtZWQgb3V0bGV0IGNvbXBvbmVudCB3aWxsIGJlIGFjY2Vzc2libGUgdmlhIFBSSU1BUllfT1VUTEVULCBidXQgZm9yIHNjYWxhYmlsaXR5IGl0IGlzIGJldHRlciB0byBhY2Nlc3MgaXQgdmlhIHRoZSBgaW5zdGFuY2UoKWAgbWV0aG9kLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBwcml2YXRlIHJlYWRvbmx5IGNvbXBvbmVudHMgPSBuZXcgTWFwPHN0cmluZywgQmVoYXZpb3JTdWJqZWN0PEFueU9iamVjdCB8IG51bGw+PigpO1xuXG4gICAgLyoqXG4gICAgICogRW1pdHMgd2hlbmV2ZXIgYSByb3V0ZXIgb3V0bGV0IG1hcmtlZCB3aXRoIHRoZSBgcHVibGlzaENvbXBvbmVudGAgZGlyZWN0aXZlIGFjdGl2YXRlcyBhIGNvbXBvbmVudC5cbiAgICAgKiBXaGVuIGFuIG91dGxldCBkZWFjdGl2YXRlcyBhIGNvbXBvbmVudCwgdGhlIHB1Ymxpc2hlZCBjb21wb25lbnQgaW5zdGFuY2Ugd2lsbCBiZSBgbnVsbGAuXG4gICAgICogXG4gICAgICogQHR5cGUge0V2ZW50RW1pdHRlcjxDb21wb25lbnRQdWJsaXNoRXZlbnREYXRhPn1cbiAgICAgKi9cbiAgICBwdWJsaWMgcmVhZG9ubHkgY29tcG9uZW50UHVibGlzaGVkICA6IEV2ZW50RW1pdHRlcjxDb21wb25lbnRQdWJsaXNoRXZlbnREYXRhPiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgICAvKipcbiAgICAgKiBFbWl0cyB3aGVuZXZlciBhIHJvdXRlciBvdXRsZXQgbWFya2VkIHdpdGggdGhlIGBwdWJsaXNoQ29tcG9uZW50YCBkaXJlY3RpdmUgaXMgcmVtb3ZlZCBmcm9tIHRoZSBET00uXG4gICAgICpcbiAgICAgKiBAdHlwZSB7RXZlbnRFbWl0dGVyPENvbXBvbmVudFB1Ymxpc2hFdmVudERhdGE+fVxuICAgICAqL1xuICAgIHB1YmxpYyByZWFkb25seSBjb21wb25lbnRVbnB1Ymxpc2hlZDogRXZlbnRFbWl0dGVyPFJvdXRlck91dGxldEV2ZW50RGF0YT4gICAgID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gICAgLyoqXG4gICAgICogUHVibGlzaGVzIHRoZSBpbnN0YW5jZSBvZiBhIGN1cnJlbnRseSBhY3RpdmF0ZWQgb3IgZGVhY3RpdmF0ZWQgY29tcG9uZW50IGJ5IHRoZSBzcGVjaWZpZWQgb3V0bGV0LlxuICAgICAqIFdoZW4gYW4gb3V0bGV0IGZpcnN0IHB1Ymxpc2hlcywgdGhpcyB3aWxsIGNyZWF0ZSBhbiBvYnNlcnZhYmxlIGZvciB0cmFja2luZyB0aGUgb3V0bGV0J3MgY2hhbmdlcy5cbiAgICAgKiBUaGUgb2JzZXJ2YWJsZSBjYW4gYmUgZmV0Y2hlZCB1c2luZyB0aGUgYGNoYW5nZXMoKWAgbWV0aG9kLlxuICAgICAqIEZvbGxvd2luZyBjYWxscyB0byBwdWJsaXNoIGEgY29tcG9uZW50IGJ5IHRoZSBzYW1lIG91dGxldCB3aWxsIHN1YnNjcmliZXJzLlxuICAgICAqIFxuICAgICAqIFRoZSBsYXN0IHB1Ymxpc2hlZCBjb21wb25lbnQgb2YgYW4gb3V0bGV0IGNhbiBiZSBmZXRjaGVkIHVzaW5nIHRoZSBgaW5zdGFuY2UoKWAgbWV0aG9kLlxuICAgICAqIFxuICAgICAqIEBwYXJhbSB7QW55T2JqZWN0IHwgbnVsbH0gaW5zdGFuY2UgVGhlIGluc3RhbmNlIG9mIHRoZSBhY3RpdmF0ZWQgY29tcG9uZW50LiBGb3IgcHVibGlzaGluZyBkZWFjdGl2YXRpb24gb2YgYSBjb21wb25lbnQgcGFzcyBgbnVsbGAuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IFtvdXRsZXROYW1lPVBSSU1BUllfT1VUTEVUXSAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBvdXRsZXQgd2hpY2ggYWN0aXZhdGVkIG9yIGRlYWN0aXZhdGVkIHRoZSBjb21wb25lbnQuIFRoZSBwcmltYXJ5IHVubmFtZWQgb3V0bGV0IHdpbGwgYmUgdXNlZCB3aGVuIG5vdCBzcGVjaWZpZWQuXG4gICAgICovXG4gICAgcHVibGljIHB1Ymxpc2hDb21wb25lbnQoaW5zdGFuY2U6IEFueU9iamVjdCB8IG51bGwsIG91dGxldE5hbWU6IHN0cmluZyA9IFBSSU1BUllfT1VUTEVUKTogdm9pZFxuICAgIHtcbiAgICAgICAgY29uc3QgY29tcG9uZW50cyA9IHRoaXMuY29tcG9uZW50cztcblxuICAgICAgICBsZXQgY29tcG9uZW50Q2hhbmdlcyA9IGNvbXBvbmVudHMuZ2V0KG91dGxldE5hbWUpO1xuXG4gICAgICAgIGlmICghY29tcG9uZW50Q2hhbmdlcylcbiAgICAgICAge1xuICAgICAgICAgICAgY29tcG9uZW50Q2hhbmdlcyA9IG5ldyBCZWhhdmlvclN1YmplY3QoaW5zdGFuY2UpO1xuICAgICAgICAgICAgY29tcG9uZW50cy5zZXQob3V0bGV0TmFtZSwgY29tcG9uZW50Q2hhbmdlcyk7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIHRoaXMuX291dGxldHNTdGF0ZS5zZXQob3V0bGV0TmFtZSwgaW5zdGFuY2UpO1xuICAgICAgICBjb21wb25lbnRDaGFuZ2VzLm5leHQoaW5zdGFuY2UpO1xuXG4gICAgICAgIHRoaXMuY29tcG9uZW50UHVibGlzaGVkLmVtaXQobmV3IENvbXBvbmVudFB1Ymxpc2hFdmVudERhdGEoY29tcG9uZW50Q2hhbmdlcywgb3V0bGV0TmFtZSkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE5vdGlmaWVzIGFueSBzdWJzY3JpYmVycyB0byB0aGUgb3V0bGV0J3MgY2hhbmdlcyBvYnNlcnZhYmxlIHRoYXQgdGhlIG91dGxldCBpcyBiZWluZyByZW1vdmVkIGJ5IGNvbXBsZXRpbmdcbiAgICAgKiB0aGUgb2JzZXJ2YWJsZSBhbmQgcmVtb3ZlcyB0aGUgb2JzZXJ2YWJsZSBmcm9tIHRoZSBzZXJ2aWNlLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IFtvdXRsZXROYW1lPVBSSU1BUllfT1VUTEVUXSAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBvdXRsZXQgdG8gdW5wdWJsaXNoLiBUaGUgcHJpbWFyeSB1bm5hbWVkIG91dGxldCB3aWxsIGJlIHVzZWQgd2hlbiBub3Qgc3BlY2lmaWVkLlxuICAgICAqL1xuICAgIHB1YmxpYyB1bnB1Ymxpc2hDb21wb25lbnQob3V0bGV0TmFtZTogc3RyaW5nID0gUFJJTUFSWV9PVVRMRVQpOiB2b2lkXG4gICAge1xuICAgICAgICBjb25zdCBjb21wb25lbnRzID0gdGhpcy5jb21wb25lbnRzO1xuXG4gICAgICAgIGlmIChjb21wb25lbnRzLmhhcyhvdXRsZXROYW1lKSlcbiAgICAgICAge1xuICAgICAgICAgICAgLy8gTm90aWZ5IGFueSBzdWJzY3JpYmVycyB0aGF0IHRoZSBvdXRsZXQgd2lsbCBzdG9wIGVtaXR0aW5nXG4gICAgICAgICAgICBjb21wb25lbnRzLmdldChvdXRsZXROYW1lKT8uY29tcGxldGUoKTtcbiAgICAgICAgICAgIC8vIE1ha2Ugc3VyZSB0aGUgb3V0bGV0IGlzIG5vIGxvbmdlciBwcmVzZW50IG9uIHRoZSBidXNcbiAgICAgICAgICAgIGNvbXBvbmVudHMuZGVsZXRlKG91dGxldE5hbWUpO1xuICAgICAgICAgICAgdGhpcy5fb3V0bGV0c1N0YXRlLmRlbGV0ZShvdXRsZXROYW1lKTtcblxuICAgICAgICAgICAgdGhpcy5jb21wb25lbnRVbnB1Ymxpc2hlZC5lbWl0KG5ldyBSb3V0ZXJPdXRsZXRFdmVudERhdGEob3V0bGV0TmFtZSkpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIHdoZXRoZXIgdGhlIG91dGxldCBieSB0aGUgZ2l2ZW4gbmFtZSBpcyBwcmVzZW50IGluIHRoZSBET00gYW5kIGhhcyBhbHJlYWR5IGFjdGl2YXRlZCBhdCBsZWFzdCBvbmUgY29tcG9uZW50LlxuICAgICAqIFRoaXMgd2lsbCBiZSBgdHJ1ZWAgZXZlbiBpZiB0aGUgb3V0bGV0IGN1cnJlbnRseSBoYXMgbm8gYWN0aXZlIGNvbXBvbmVudCAoY29tcG9uZW50IGlzIGBudWxsYCkuXG4gICAgICogXG4gICAgICogQSBgZmFsc2VgIHZhbHVlIGNhbiBlaXRoZXIgbWVhbiB0aGUgb3V0bGV0IGhhc24ndCBiZWVuIG1hcmtlZCB3aXRoIGBwdWJsaXNoQ29tcG9uZW50YCwgb3IgdGhhdCB0aGUgb3V0bGV0IGlzIG5vdCBjdXJyZW50bHkgcmVuZGVyZWQgKG5vdCBwcmVzZW50IGluIHRoZSBET00pLlxuICAgICAqIFxuICAgICAqIFdoZW4gYHRydWVgLCB0aGUgdXNlciBjYW4gc3Vic2NyaWJlIHRvIGNoYW5nZXMgb2YgdGhhdCBvdXRsZXQgdGhyb3VnaCB0aGUgYGNoYW5nZXMoKWAgbWV0aG9kLlxuICAgICAqIFxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3V0bGV0TmFtZT1QUklNQVJZX09VVExFVF0gKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgb3V0bGV0IHRvIGNoZWNrLiBUaGUgcHJpbWFyeSB1bm5hbWVkIG91dGxldCB3aWxsIGJlIGNoZWNrZWQgaWYgbm8gbmFtZSBpcyBwcm92aWRlZC5cbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gYHRydWVgIGlmIHRoZSBvdXRsZXQgaGFzIHB1Ymxpc2hlZCBhIGNvbXBvbmVudCBhdCBsZWFzdCBvbmNlOyBvdGhlcndpc2UgYGZhbHNlYC5cbiAgICAgKi9cbiAgICBwdWJsaWMgaXNDb21wb25lbnRQdWJsaXNoZWQob3V0bGV0TmFtZTogc3RyaW5nID0gUFJJTUFSWV9PVVRMRVQpOiBib29sZWFuXG4gICAge1xuICAgICAgICByZXR1cm4gdGhpcy5jb21wb25lbnRzLmhhcyhvdXRsZXROYW1lKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXRzIGFuIG9ic2VydmFibGUgd2hpY2ggY2FuIGJlIHVzZWQgdG8gdHJhY2sgY2hhbmdlcyB0byB0aGUgYWN0aXZhdGVkIGNvbXBvbmVudCBvZiB0aGUgc3BlY2lmaWVkIG91dGxldC5cbiAgICAgKiBJZiB0aGUgb3V0bGV0IGlzIG5vdCByZW5kZXJlZCAocHJlc2VudCBpbiB0aGUgRE9NKSwgb3IgaGFzbid0IGJlZW4gbWFya2VkIHdpdGggYHB1Ymxpc2hDb21wb25lbnRgLCB0aGlzIHdpbGwgYmUgYG51bGxgLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IFtvdXRsZXROYW1lPVBSSU1BUllfT1VUTEVUXSAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBvdXRsZXQgdG8gdHJhY2sgY2hhbmdlcyBmb3IuIFRoZSBwcmltYXJ5IHVubmFtZWQgb3V0bGV0IHdpbGwgYmUgdXNlZCB3aGVuIG5vdCBzcGVjaWZpZWQuXG4gICAgICogQHJldHVybnMgeyhCZWhhdmlvclN1YmplY3Q8QW55T2JqZWN0IHwgbnVsbD4gfCBudWxsKX0gQW4gb2JzZXJ2YWJsZSB0byB1c2UgZm9yIHRyYWNraW5nIGNoYW5nZXMgdG8gdGhlIGFjdGl2YXRlZCBjb21wb25lbnQgZm9yIHRoZSBzcGVjaWZpZWQgb3V0bGV0LCBvciBgbnVsbGAgaWYgbm8gc3VjaCBvdXRsZXQgZXhpc3RzLlxuICAgICAqL1xuICAgIHB1YmxpYyBjaGFuZ2VzKG91dGxldE5hbWU6IHN0cmluZyA9IFBSSU1BUllfT1VUTEVUKTogQmVoYXZpb3JTdWJqZWN0PEFueU9iamVjdCB8IG51bGw+IHwgbnVsbFxuICAgIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY29tcG9uZW50cy5nZXQob3V0bGV0TmFtZSkgPz8gbnVsbDtcbiAgICB9XG4gICAgXG4gICAgLyoqXG4gICAgICogR2V0cyB0aGUgY3VycmVudCBpbnN0YW5jZSBvZiB0aGUgY29tcG9uZW50IGNyZWF0ZWQgYnkgdGhlIHNwZWNpZmllZCBvdXRsZXQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW291dGxldE5hbWU9UFJJTUFSWV9PVVRMRVRdIChPcHRpb25hbCkgVGhlIG5hbWUgb2YgdGhlIG91dGxldCB0byBmZXRjaCB0aGUgY29tcG9uZW50IGluc3RhbmNlIGZvci4gSWYgbm90IHByb3ZpZGVkLCB0aGUgcHJpbWFyeSB1bm5hbWVkIG91dGxldCdzIGNvbXBvbmVudCB3aWxsIGJlIGZldGNoZWQuXG4gICAgICogQHJldHVybnMgeyhBbnlPYmplY3QgfCBudWxsKX0gVGhlIGluc3RhbmNlIG9mIHRoZSBjb21wb25lbnQgY3JlYXRlZCBieSB0aGUgc3BlY2lmaWVkIG91dGxldC4gSWYgdGhlIG91dGxldCBkb2Vzbid0IGV4aXN0LCBvciB0aGVyZSBpcyBubyBjb21wb25lbnQgaW5zdGFuY2UgZm9yIHRoZSByZXF1ZXN0ZWQgb3V0bGV0LCByZXR1cm5zIGBudWxsYC5cbiAgICAgKi9cbiAgICBwdWJsaWMgaW5zdGFuY2Uob3V0bGV0TmFtZTogc3RyaW5nID0gUFJJTUFSWV9PVVRMRVQpOiBBbnlPYmplY3QgfCBudWxsXG4gICAge1xuICAgICAgICByZXR1cm4gdGhpcy5jb21wb25lbnRzLmdldChvdXRsZXROYW1lKT8udmFsdWUgPz8gbnVsbDtcbiAgICB9XG59Il19