@bespunky/angular-zen
Version:
The Angular tools you always wished were there.
193 lines (192 loc) • 25.2 kB
JavaScript
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