UNPKG

@bespunky/angular-zen

Version:

The Angular tools you always wished were there.

145 lines 22.3 kB
import { EMPTY, BehaviorSubject } from 'rxjs'; import { map, materialize, share, switchMap, tap } from 'rxjs/operators'; import { Directive, TemplateRef, ViewContainerRef, EventEmitter, Output } from '@angular/core'; import { Destroyable } from '../../destroyable/destroyable'; import * as i0 from "@angular/core"; /** * The base class for all `*observeXXX` directives. * This directive bind an observable or a collection of observables with a template, causing the values in the template to be updated whenever the observables emit. * * Any template assigned with the directive will render immediately, and its view context will be updated with the emitted value on * each emission. The directive will be responsible for subscribing on init and unsubscribing on destroy. * * ## Features * * #### Shared observable * The watched observable will automatically be multicasted so that any child observables created by the template will use the same * stream. * * The shared observable can be accessed using the `let source = source` microsyntax. * * #### Observer events * Whenever the observable changes state or emits a value, the corresponding event is emitted: * `nextCalled` - A value has been emitted. `$event` will be the emitted value. * `errorCalled` - An error has occured in the pipeline. `$event` will be the error. * `completeCalled` - The observable has completed. `$event` will be void. * * > Because of limitations to Angular's Structural Directives, in order to bind the events the desugared syntax must be used. * This, for example, **will trigger** the event: * > ```html * ><ng-template [observe]="x$" let-source="source" (nextCalled)="onNext($event)"> * > ... * ></ng-template> * > ``` * > * >This **will NOT trigger** the event: * >```html * > <div *observe="x$; let source = source" (nextCalled)="onNext($event)">...</div> * >``` * * ## ⚠️ Extending notes: * As the base class cannot deduce the directive selector (e.g. `observeLatest`, `observeMerge`, etc.) the extending class * is required to do 4 things: * 1. Implement the abstract `selector` member and assign it with the directive's selector. * 2. Implement and `@Input() public set <selector>(value: T)` which will pass its value to the `input` member. * 3. Implement a static context TypeGuard. * * These will enable Angular features like template type checking and the microsyntax `as` keyword. * * @export * @abstract * @class ObserveBaseDirective * @extends {Destroyable} * @implements {OnInit} * @template TInput The type of value this directive will work with. Depends on the extending class. * @template TResolved The type of value emitted by the observable. Depends on the extending class. * @template TContext The type of the context object the template will work with. */ export class ObserveBaseDirective extends Destroyable { constructor(template, viewContainer) { super(); this.template = template; this.viewContainer = viewContainer; /** * Triggered whenever the observable emits a value. `$event` will be the emitted value. * * @type {EventEmitter<TResolved>} */ this.nextCalled = new EventEmitter(); /** * Triggered when an error occurs in the observable's pipeline. `$event` will be the error. * * @type {EventEmitter<unknown>} */ this.errorCalled = new EventEmitter(); /** * Triggered when the observable completes. `$event` will be the void. * * @type {EventEmitter<void>} */ this.completeCalled = new EventEmitter(); /** * ### Why BehaviorSubject<{@link TInput s} | null> and not Subject<{@link TInput}> * `input` is set from @Input properties. For some reason, Angular passes-in the first value BEFORE * ngOnInit, even though other @Input properties (e.g. showAfter, showFor) are passed AFTER ngOnInit. * If subscription occurs in the constructor, `input` will emit the first observable too fast, which * might lead to pipes breaking or misbehaving if they rely on properties to be instantiated first. * * This leads to subscribing in ngOnInit, to allow Angular time to initialize those. * BUT, if `input` is a Subject, as the first value was already emitted BEFORE ngOnInit, it will not be * captured by our subscription to `input`. Hence the BehaviorSubject - To allow capturing that first observable. */ this.input = new BehaviorSubject(null); this.renderView(); } ngOnInit() { // See `this.input` documentation for why subscription is done in ngOnInit. this.subscribe(this.contextFeed()); } contextFeed() { return this.input.pipe( // Whenever a new value is provided into the directive use the extender's implementation to observe it and multicast it. map(input => input ? this.observeInput(input).pipe(share()) : EMPTY), // Replace the source observable in the context with the newly created observable. tap(source => this.updateViewContext({ source })), // Switch to the new observable and materialize it to watch for state changes and emit events accordingly switchMap(source => source.pipe(materialize())), // Whenever a materialized notification is emitted, handle it and emit the relevant event tap(meta => this.onStateChange(meta))); } onStateChange(meta) { // Call the appropriate handler according to the received notification return meta.observe({ next: value => { this.updateViewContext({ value }); this.nextCalled.emit(value); }, error: error => this.errorCalled.emit(error), complete: () => this.completeCalled.emit() }); } renderView() { const context = this.createViewContext({}); this.view = this.viewContainer.createEmbeddedView(this.template, context); } updateViewContext(data) { this.view.context = this.createViewContext(data); } createViewContext({ value, source }) { value ?? (value = this.view?.context.$implicit || null); source ?? (source = this.view?.context.source || EMPTY); return { $implicit: value, [this.selector]: value, source }; } } ObserveBaseDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: ObserveBaseDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); ObserveBaseDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.2.12", type: ObserveBaseDirective, outputs: { nextCalled: "nextCalled", errorCalled: "errorCalled", completeCalled: "completeCalled" }, usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: ObserveBaseDirective, decorators: [{ type: Directive }], ctorParameters: function () { return [{ type: i0.TemplateRef }, { type: i0.ViewContainerRef }]; }, propDecorators: { nextCalled: [{ type: Output }], errorCalled: [{ type: Output }], completeCalled: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib2JzZXJ2ZS1iYXNlLmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvYW5ndWxhci16ZW4vY29yZS9zcmMvcnhqcy9vYnNlcnZlL2Fic3RyYWN0aW9uL29ic2VydmUtYmFzZS5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEtBQUssRUFBNEIsZUFBZSxFQUF5QyxNQUFNLE1BQU0sQ0FBQztBQUMvRyxPQUFPLEVBQUUsR0FBRyxFQUFFLFdBQVcsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBa0QsTUFBTSxnQkFBZ0IsQ0FBQztBQUN6SCxPQUFPLEVBQUUsU0FBUyxFQUFtQixXQUFXLEVBQUUsZ0JBQWdCLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBVSxNQUFNLGVBQWUsQ0FBQztBQUV4SCxPQUFPLEVBQUUsV0FBVyxFQUFhLE1BQU0sK0JBQStCLENBQUM7O0FBR3ZFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtREc7QUFFSCxNQUFNLE9BQWdCLG9CQUNSLFNBQVEsV0FBVztJQTZDN0IsWUFDcUIsUUFBb0MsRUFDcEMsYUFBK0I7UUFHaEQsS0FBSyxFQUFFLENBQUM7UUFKUyxhQUFRLEdBQVIsUUFBUSxDQUE0QjtRQUNwQyxrQkFBYSxHQUFiLGFBQWEsQ0FBa0I7UUE3Q3BEOzs7O1dBSUc7UUFDYyxlQUFVLEdBQWdDLElBQUksWUFBWSxFQUFFLENBQUM7UUFDOUU7Ozs7V0FJRztRQUNjLGdCQUFXLEdBQStCLElBQUksWUFBWSxFQUFFLENBQUM7UUFDOUU7Ozs7V0FJRztRQUNjLG1CQUFjLEdBQTRCLElBQUksWUFBWSxFQUFFLENBQUM7UUFhOUU7Ozs7Ozs7Ozs7V0FVRztRQUNnQixVQUFLLEdBQW1DLElBQUksZUFBZSxDQUFDLElBQXFCLENBQUMsQ0FBQztRQVNsRyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7SUFDdEIsQ0FBQztJQUVELFFBQVE7UUFFSiwyRUFBMkU7UUFDM0UsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQztJQUN2QyxDQUFDO0lBZU8sV0FBVztRQUVmLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJO1FBQ2xCLHdIQUF3SDtRQUN4SCxHQUFHLENBQU8sS0FBSyxDQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztRQUMzRSxrRkFBa0Y7UUFDbEYsR0FBRyxDQUFPLE1BQU0sQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUN2RCx5R0FBeUc7UUFDekcsU0FBUyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDO1FBQy9DLHlGQUF5RjtRQUN6RixHQUFHLENBQU8sSUFBSSxDQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQ2hELENBQUM7SUFDTixDQUFDO0lBRU8sYUFBYSxDQUFDLElBQTZCO1FBRS9DLHNFQUFzRTtRQUN0RSxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7WUFDaEIsSUFBSSxFQUFFLEtBQUssQ0FBQyxFQUFFO2dCQUVWLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7Z0JBRWxDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ2hDLENBQUM7WUFDRCxLQUFLLEVBQUssS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUM7WUFDL0MsUUFBUSxFQUFFLEdBQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxFQUFFO1NBQ2hELENBQUMsQ0FBQztJQUNQLENBQUM7SUFFTyxVQUFVO1FBRWQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBRTNDLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQzlFLENBQUM7SUFFTyxpQkFBaUIsQ0FBQyxJQUFtRTtRQUV6RixJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDckQsQ0FBQztJQUVTLGlCQUFpQixDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBaUU7UUFFeEcsS0FBSyxLQUFMLEtBQUssR0FBTSxJQUFJLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxTQUFTLElBQUksSUFBSSxFQUFDO1FBQ2hELE1BQU0sS0FBTixNQUFNLEdBQUssSUFBSSxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsTUFBTSxJQUFPLEtBQUssRUFBQztRQUVqRCxPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFjLENBQUM7SUFDNUUsQ0FBQzs7a0hBMUhpQixvQkFBb0I7c0dBQXBCLG9CQUFvQjs0RkFBcEIsb0JBQW9CO2tCQUR6QyxTQUFTO2lJQVNXLFVBQVU7c0JBQTFCLE1BQU07Z0JBTVUsV0FBVztzQkFBM0IsTUFBTTtnQkFNVSxjQUFjO3NCQUE5QixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRU1QVFksIE9ic2VydmFibGUsIE5vdGlmaWNhdGlvbiwgQmVoYXZpb3JTdWJqZWN0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBtYXAsIG1hdGVyaWFsaXplLCBzaGFyZSwgc3dpdGNoTWFwLCB0YXAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBEaXJlY3RpdmUsIEVtYmVkZGVkVmlld1JlZiwgVGVtcGxhdGVSZWYsIFZpZXdDb250YWluZXJSZWYsIEV2ZW50RW1pdHRlciwgT3V0cHV0LCBPbkluaXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuaW1wb3J0IHsgRGVzdHJveWFibGUgICAgICAgICAgICB9IGZyb20gJy4uLy4uL2Rlc3Ryb3lhYmxlL2Rlc3Ryb3lhYmxlJztcbmltcG9ydCB7IFJlc29sdmVkT2JzZXJ2ZUNvbnRleHQgfSBmcm9tICcuL3R5cGVzL2dlbmVyYWwnO1xuXG4vKipcbiAqIFRoZSBiYXNlIGNsYXNzIGZvciBhbGwgYCpvYnNlcnZlWFhYYCBkaXJlY3RpdmVzLlxuICogVGhpcyBkaXJlY3RpdmUgYmluZCBhbiBvYnNlcnZhYmxlIG9yIGEgY29sbGVjdGlvbiBvZiBvYnNlcnZhYmxlcyB3aXRoIGEgdGVtcGxhdGUsIGNhdXNpbmcgdGhlIHZhbHVlcyBpbiB0aGUgdGVtcGxhdGUgdG8gYmUgdXBkYXRlZCB3aGVuZXZlciB0aGUgb2JzZXJ2YWJsZXMgZW1pdC5cbiAqIFxuICogQW55IHRlbXBsYXRlIGFzc2lnbmVkIHdpdGggdGhlIGRpcmVjdGl2ZSB3aWxsIHJlbmRlciBpbW1lZGlhdGVseSwgYW5kIGl0cyB2aWV3IGNvbnRleHQgd2lsbCBiZSB1cGRhdGVkIHdpdGggdGhlIGVtaXR0ZWQgdmFsdWUgb25cbiAqIGVhY2ggZW1pc3Npb24uIFRoZSBkaXJlY3RpdmUgd2lsbCBiZSByZXNwb25zaWJsZSBmb3Igc3Vic2NyaWJpbmcgb24gaW5pdCBhbmQgdW5zdWJzY3JpYmluZyBvbiBkZXN0cm95LlxuICogXG4gKiAjIyBGZWF0dXJlc1xuICogXG4gKiAjIyMjIFNoYXJlZCBvYnNlcnZhYmxlXG4gKiBUaGUgd2F0Y2hlZCBvYnNlcnZhYmxlIHdpbGwgYXV0b21hdGljYWxseSBiZSBtdWx0aWNhc3RlZCBzbyB0aGF0IGFueSBjaGlsZCBvYnNlcnZhYmxlcyBjcmVhdGVkIGJ5IHRoZSB0ZW1wbGF0ZSB3aWxsIHVzZSB0aGUgc2FtZVxuICogc3RyZWFtLlxuICogXG4gKiBUaGUgc2hhcmVkIG9ic2VydmFibGUgY2FuIGJlIGFjY2Vzc2VkIHVzaW5nIHRoZSBgbGV0IHNvdXJjZSA9IHNvdXJjZWAgbWljcm9zeW50YXguXG4gKiBcbiAqICMjIyMgT2JzZXJ2ZXIgZXZlbnRzXG4gKiBXaGVuZXZlciB0aGUgb2JzZXJ2YWJsZSBjaGFuZ2VzIHN0YXRlIG9yIGVtaXRzIGEgdmFsdWUsIHRoZSBjb3JyZXNwb25kaW5nIGV2ZW50IGlzIGVtaXR0ZWQ6ICBcbiAqIGBuZXh0Q2FsbGVkYCAtIEEgdmFsdWUgaGFzIGJlZW4gZW1pdHRlZC4gYCRldmVudGAgd2lsbCBiZSB0aGUgZW1pdHRlZCB2YWx1ZS4gIFxuICogYGVycm9yQ2FsbGVkYCAtIEFuIGVycm9yIGhhcyBvY2N1cmVkIGluIHRoZSBwaXBlbGluZS4gYCRldmVudGAgd2lsbCBiZSB0aGUgZXJyb3IuICBcbiAqIGBjb21wbGV0ZUNhbGxlZGAgLSBUaGUgb2JzZXJ2YWJsZSBoYXMgY29tcGxldGVkLiBgJGV2ZW50YCB3aWxsIGJlIHZvaWQuXG4gKlxuICogPiBCZWNhdXNlIG9mIGxpbWl0YXRpb25zIHRvIEFuZ3VsYXIncyBTdHJ1Y3R1cmFsIERpcmVjdGl2ZXMsIGluIG9yZGVyIHRvIGJpbmQgdGhlIGV2ZW50cyB0aGUgZGVzdWdhcmVkIHN5bnRheCBtdXN0IGJlIHVzZWQuXG4gKiBUaGlzLCBmb3IgZXhhbXBsZSwgKip3aWxsIHRyaWdnZXIqKiB0aGUgZXZlbnQ6XG4gKiA+IGBgYGh0bWxcbiAqID48bmctdGVtcGxhdGUgW29ic2VydmVdPVwieCRcIiBsZXQtc291cmNlPVwic291cmNlXCIgKG5leHRDYWxsZWQpPVwib25OZXh0KCRldmVudClcIj5cbiAqID4gICAgLi4uXG4gKiA+PC9uZy10ZW1wbGF0ZT5cbiAqID4gYGBgXG4gKiA+XG4gKiA+VGhpcyAqKndpbGwgTk9UIHRyaWdnZXIqKiB0aGUgZXZlbnQ6XG4gKiA+YGBgaHRtbFxuICogPiA8ZGl2ICpvYnNlcnZlPVwieCQ7IGxldCBzb3VyY2UgPSBzb3VyY2VcIiAobmV4dENhbGxlZCk9XCJvbk5leHQoJGV2ZW50KVwiPi4uLjwvZGl2PlxuICogPmBgYFxuICogXG4gKiAjIyDimqDvuI8gRXh0ZW5kaW5nIG5vdGVzOlxuICogQXMgdGhlIGJhc2UgY2xhc3MgY2Fubm90IGRlZHVjZSB0aGUgZGlyZWN0aXZlIHNlbGVjdG9yIChlLmcuIGBvYnNlcnZlTGF0ZXN0YCwgYG9ic2VydmVNZXJnZWAsIGV0Yy4pIHRoZSBleHRlbmRpbmcgY2xhc3NcbiAqIGlzIHJlcXVpcmVkIHRvIGRvIDQgdGhpbmdzOlxuICogMS4gSW1wbGVtZW50IHRoZSBhYnN0cmFjdCBgc2VsZWN0b3JgIG1lbWJlciBhbmQgYXNzaWduIGl0IHdpdGggdGhlIGRpcmVjdGl2ZSdzIHNlbGVjdG9yLlxuICogMi4gSW1wbGVtZW50IGFuZCBgQElucHV0KCkgcHVibGljIHNldCA8c2VsZWN0b3I+KHZhbHVlOiBUKWAgd2hpY2ggd2lsbCBwYXNzIGl0cyB2YWx1ZSB0byB0aGUgYGlucHV0YCBtZW1iZXIuXG4gKiAzLiBJbXBsZW1lbnQgYSBzdGF0aWMgY29udGV4dCBUeXBlR3VhcmQuXG4gKiBcbiAqIFRoZXNlIHdpbGwgZW5hYmxlIEFuZ3VsYXIgZmVhdHVyZXMgbGlrZSB0ZW1wbGF0ZSB0eXBlIGNoZWNraW5nIGFuZCB0aGUgbWljcm9zeW50YXggYGFzYCBrZXl3b3JkLlxuICogXG4gKiBAZXhwb3J0XG4gKiBAYWJzdHJhY3RcbiAqIEBjbGFzcyBPYnNlcnZlQmFzZURpcmVjdGl2ZVxuICogQGV4dGVuZHMge0Rlc3Ryb3lhYmxlfVxuICogQGltcGxlbWVudHMge09uSW5pdH1cbiAqIEB0ZW1wbGF0ZSBUSW5wdXQgVGhlIHR5cGUgb2YgdmFsdWUgdGhpcyBkaXJlY3RpdmUgd2lsbCB3b3JrIHdpdGguIERlcGVuZHMgb24gdGhlIGV4dGVuZGluZyBjbGFzcy5cbiAqIEB0ZW1wbGF0ZSBUUmVzb2x2ZWQgVGhlIHR5cGUgb2YgdmFsdWUgZW1pdHRlZCBieSB0aGUgb2JzZXJ2YWJsZS4gRGVwZW5kcyBvbiB0aGUgZXh0ZW5kaW5nIGNsYXNzLlxuICogQHRlbXBsYXRlIFRDb250ZXh0IFRoZSB0eXBlIG9mIHRoZSBjb250ZXh0IG9iamVjdCB0aGUgdGVtcGxhdGUgd2lsbCB3b3JrIHdpdGguXG4gKi9cbkBEaXJlY3RpdmUoKVxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIE9ic2VydmVCYXNlRGlyZWN0aXZlPFRJbnB1dCwgVFJlc29sdmVkLCBUQ29udGV4dCBleHRlbmRzIFJlc29sdmVkT2JzZXJ2ZUNvbnRleHQ8VFJlc29sdmVkPj5cbiAgICAgICAgICAgICAgZXh0ZW5kcyBEZXN0cm95YWJsZSBpbXBsZW1lbnRzIE9uSW5pdFxue1xuICAgIC8qKlxuICAgICAqIFRyaWdnZXJlZCB3aGVuZXZlciB0aGUgb2JzZXJ2YWJsZSBlbWl0cyBhIHZhbHVlLiBgJGV2ZW50YCB3aWxsIGJlIHRoZSBlbWl0dGVkIHZhbHVlLlxuICAgICAqXG4gICAgICogQHR5cGUge0V2ZW50RW1pdHRlcjxUUmVzb2x2ZWQ+fVxuICAgICAqL1xuICAgIEBPdXRwdXQoKSBwdWJsaWMgbmV4dENhbGxlZCAgICA6IEV2ZW50RW1pdHRlcjxUUmVzb2x2ZWQ+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICAgIC8qKlxuICAgICAqIFRyaWdnZXJlZCB3aGVuIGFuIGVycm9yIG9jY3VycyBpbiB0aGUgb2JzZXJ2YWJsZSdzIHBpcGVsaW5lLiBgJGV2ZW50YCB3aWxsIGJlIHRoZSBlcnJvci5cbiAgICAgKlxuICAgICAqIEB0eXBlIHtFdmVudEVtaXR0ZXI8dW5rbm93bj59XG4gICAgICovXG4gICAgQE91dHB1dCgpIHB1YmxpYyBlcnJvckNhbGxlZCAgIDogRXZlbnRFbWl0dGVyPHVua25vd24+ICAgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gICAgLyoqXG4gICAgICogVHJpZ2dlcmVkIHdoZW4gdGhlIG9ic2VydmFibGUgY29tcGxldGVzLiBgJGV2ZW50YCB3aWxsIGJlIHRoZSB2b2lkLlxuICAgICAqXG4gICAgICogQHR5cGUge0V2ZW50RW1pdHRlcjx2b2lkPn1cbiAgICAgKi9cbiAgICBAT3V0cHV0KCkgcHVibGljIGNvbXBsZXRlQ2FsbGVkOiBFdmVudEVtaXR0ZXI8dm9pZD4gICAgICA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICAgIHByaXZhdGUgdmlldyE6IEVtYmVkZGVkVmlld1JlZjxUQ29udGV4dD47XG4gICAgXG4gICAgLyoqXG4gICAgICogVGhlIHNlbGVjdG9yIGRlZmluZWQgZm9yIHRoZSBkaXJlY3RpdmUgZXh0ZW5kaW5nIHRoaXMgY2xhc3MuIFdpbGwgYmUgdXNlZCB0byBjcmVhdGUgYSBjb3JyZXNwb25kaW5nXG4gICAgICogcHJvcGVydHkgaW4gdGhlIHZpZXcgY29udGV4dCBpbiBvcmRlciB0byBtYWtlIHRoZSBtaWNyby1zeW50YXggYGFzYCBrZXl3b3JkIHdvcmsuXG4gICAgICpcbiAgICAgKiBAcHJvdGVjdGVkXG4gICAgICogQGFic3RyYWN0XG4gICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgYWJzdHJhY3QgcmVhZG9ubHkgc2VsZWN0b3I6IHN0cmluZztcbiAgICAvKipcbiAgICAgKiAjIyMgV2h5IEJlaGF2aW9yU3ViamVjdDx7QGxpbmsgVElucHV0IHN9IHwgbnVsbD4gYW5kIG5vdCBTdWJqZWN0PHtAbGluayBUSW5wdXR9PlxuICAgICAqIGBpbnB1dGAgaXMgc2V0IGZyb20gQElucHV0IHByb3BlcnRpZXMuIEZvciBzb21lIHJlYXNvbiwgQW5ndWxhciBwYXNzZXMtaW4gdGhlIGZpcnN0IHZhbHVlIEJFRk9SRVxuICAgICAqIG5nT25Jbml0LCBldmVuIHRob3VnaCBvdGhlciBASW5wdXQgcHJvcGVydGllcyAoZS5nLiBzaG93QWZ0ZXIsIHNob3dGb3IpIGFyZSBwYXNzZWQgQUZURVIgbmdPbkluaXQuXG4gICAgICogSWYgc3Vic2NyaXB0aW9uIG9jY3VycyBpbiB0aGUgY29uc3RydWN0b3IsIGBpbnB1dGAgd2lsbCBlbWl0IHRoZSBmaXJzdCBvYnNlcnZhYmxlIHRvbyBmYXN0LCB3aGljaFxuICAgICAqIG1pZ2h0IGxlYWQgdG8gcGlwZXMgYnJlYWtpbmcgb3IgbWlzYmVoYXZpbmcgaWYgdGhleSByZWx5IG9uIHByb3BlcnRpZXMgdG8gYmUgaW5zdGFudGlhdGVkIGZpcnN0LlxuICAgICAqIFxuICAgICAqIFRoaXMgbGVhZHMgdG8gc3Vic2NyaWJpbmcgaW4gbmdPbkluaXQsIHRvIGFsbG93IEFuZ3VsYXIgdGltZSB0byBpbml0aWFsaXplIHRob3NlLlxuICAgICAqIEJVVCwgaWYgYGlucHV0YCBpcyBhIFN1YmplY3QsIGFzIHRoZSBmaXJzdCB2YWx1ZSB3YXMgYWxyZWFkeSBlbWl0dGVkIEJFRk9SRSBuZ09uSW5pdCwgaXQgd2lsbCBub3QgYmVcbiAgICAgKiBjYXB0dXJlZCBieSBvdXIgc3Vic2NyaXB0aW9uIHRvIGBpbnB1dGAuIEhlbmNlIHRoZSBCZWhhdmlvclN1YmplY3QgLSBUbyBhbGxvdyBjYXB0dXJpbmcgdGhhdCBmaXJzdCBvYnNlcnZhYmxlLlxuICAgICAqL1xuICAgIHByb3RlY3RlZCByZWFkb25seSBpbnB1dDogQmVoYXZpb3JTdWJqZWN0PFRJbnB1dCB8IG51bGw+ID0gbmV3IEJlaGF2aW9yU3ViamVjdChudWxsIGFzIFRJbnB1dCB8IG51bGwpO1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgdGVtcGxhdGUgICAgIDogVGVtcGxhdGVSZWY8VENvbnRleHQ+LFxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IHZpZXdDb250YWluZXI6IFZpZXdDb250YWluZXJSZWZcbiAgICApXG4gICAge1xuICAgICAgICBzdXBlcigpO1xuICAgICAgICBcbiAgICAgICAgdGhpcy5yZW5kZXJWaWV3KCk7XG4gICAgfVxuICAgIFxuICAgIG5nT25Jbml0KClcbiAgICB7XG4gICAgICAgIC8vIFNlZSBgdGhpcy5pbnB1dGAgZG9jdW1lbnRhdGlvbiBmb3Igd2h5IHN1YnNjcmlwdGlvbiBpcyBkb25lIGluIG5nT25Jbml0LlxuICAgICAgICB0aGlzLnN1YnNjcmliZSh0aGlzLmNvbnRleHRGZWVkKCkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRha2VzIHRoZSBpbnB1dCBwYXNzZWQgdG8gdGhlIGRpcmVjdGl2ZSAod2hpY2ggbWlnaHQgYmUgYW4gb2JzZXJ2YWJsZSwgYSBtYXAgb3IgYW4gYXJyYXkgb2Ygb2JzZXJ2YWJsZSBmb3IgZXhhbXBsZSlcbiAgICAgKiBhbmQgY3JlYXRlcyBhbiBvYnNlcnZhYmxlIHRoYXQgY29tYmluZXMgYW5kIHJlcHJlc2VudHMgYWxsIHRoZSBvYnNlcnZhYmxlcyBpbiB0aGUgdmFsdWUuXG4gICAgICogXG4gICAgICogSW50ZW5kZWQgZm9yIGFwcGx5aW5nIGZ1bmN0aW9ucyBsaWtlIGBjb21iaW5lTGF0ZXN0KClgLCBgY29udGFjdCgpYCwgZXRjLlxuICAgICAqIFxuICAgICAqIEBwcm90ZWN0ZWRcbiAgICAgKiBAYWJzdHJhY3RcbiAgICAgKiBAcGFyYW0ge1RJbnB1dH0gaW5wdXQgVGhlIGlucHV0IHBhc3NlZCB0byB0aGUgZGlyZWN0aXZlICh3aGljaCBtaWdodCBiZSBhbiBvYnNlcnZhYmxlLCBhIG1hcCBvciBhbiBhcnJheSBvZiBvYnNlcnZhYmxlIGZvciBleGFtcGxlKS5cbiAgICAgKiBAcmV0dXJuIHtPYnNlcnZhYmxlPFRSZXNvbHZlZD59IEFuIG9ic2VydmFibGUgd2hpY2ggY29tYmluZXMgYW5kIHJlcHJlc2VudHMgYWxsIHRoZSBvYnNlcnZhYmxlcyBpbiB0aGUgaW5wdXQgdmFsdWUuXG4gICAgICovXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IG9ic2VydmVJbnB1dChpbnB1dDogVElucHV0KTogT2JzZXJ2YWJsZTxUUmVzb2x2ZWQ+O1xuXG4gICAgcHJpdmF0ZSBjb250ZXh0RmVlZCgpOiBPYnNlcnZhYmxlPE5vdGlmaWNhdGlvbjxUUmVzb2x2ZWQ+PlxuICAgIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaW5wdXQucGlwZShcbiAgICAgICAgICAgIC8vIFdoZW5ldmVyIGEgbmV3IHZhbHVlIGlzIHByb3ZpZGVkIGludG8gdGhlIGRpcmVjdGl2ZSB1c2UgdGhlIGV4dGVuZGVyJ3MgaW1wbGVtZW50YXRpb24gdG8gb2JzZXJ2ZSBpdCBhbmQgbXVsdGljYXN0IGl0LlxuICAgICAgICAgICAgbWFwICAgICAgKGlucHV0ICA9PiBpbnB1dCA/IHRoaXMub2JzZXJ2ZUlucHV0KGlucHV0KS5waXBlKHNoYXJlKCkpIDogRU1QVFkpLFxuICAgICAgICAgICAgLy8gUmVwbGFjZSB0aGUgc291cmNlIG9ic2VydmFibGUgaW4gdGhlIGNvbnRleHQgd2l0aCB0aGUgbmV3bHkgY3JlYXRlZCBvYnNlcnZhYmxlLlxuICAgICAgICAgICAgdGFwICAgICAgKHNvdXJjZSA9PiB0aGlzLnVwZGF0ZVZpZXdDb250ZXh0KHsgc291cmNlIH0pKSxcbiAgICAgICAgICAgIC8vIFN3aXRjaCB0byB0aGUgbmV3IG9ic2VydmFibGUgYW5kIG1hdGVyaWFsaXplIGl0IHRvIHdhdGNoIGZvciBzdGF0ZSBjaGFuZ2VzIGFuZCBlbWl0IGV2ZW50cyBhY2NvcmRpbmdseVxuICAgICAgICAgICAgc3dpdGNoTWFwKHNvdXJjZSA9PiBzb3VyY2UucGlwZShtYXRlcmlhbGl6ZSgpKSksXG4gICAgICAgICAgICAvLyBXaGVuZXZlciBhIG1hdGVyaWFsaXplZCBub3RpZmljYXRpb24gaXMgZW1pdHRlZCwgaGFuZGxlIGl0IGFuZCBlbWl0IHRoZSByZWxldmFudCBldmVudFxuICAgICAgICAgICAgdGFwICAgICAgKG1ldGEgICA9PiB0aGlzLm9uU3RhdGVDaGFuZ2UobWV0YSkpXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvblN0YXRlQ2hhbmdlKG1ldGE6IE5vdGlmaWNhdGlvbjxUUmVzb2x2ZWQ+KTogdm9pZFxuICAgIHtcbiAgICAgICAgLy8gQ2FsbCB0aGUgYXBwcm9wcmlhdGUgaGFuZGxlciBhY2NvcmRpbmcgdG8gdGhlIHJlY2VpdmVkIG5vdGlmaWNhdGlvblxuICAgICAgICByZXR1cm4gbWV0YS5vYnNlcnZlKHtcbiAgICAgICAgICAgIG5leHQ6IHZhbHVlID0+XG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdGhpcy51cGRhdGVWaWV3Q29udGV4dCh7IHZhbHVlIH0pO1xuXG4gICAgICAgICAgICAgICAgdGhpcy5uZXh0Q2FsbGVkLmVtaXQodmFsdWUpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGVycm9yICAgOiBlcnJvciA9PiB0aGlzLmVycm9yQ2FsbGVkLmVtaXQoZXJyb3IpLFxuICAgICAgICAgICAgY29tcGxldGU6ICgpICAgID0+IHRoaXMuY29tcGxldGVDYWxsZWQuZW1pdCgpXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgcmVuZGVyVmlldygpOiB2b2lkXG4gICAge1xuICAgICAgICBjb25zdCBjb250ZXh0ID0gdGhpcy5jcmVhdGVWaWV3Q29udGV4dCh7fSk7XG5cbiAgICAgICAgdGhpcy52aWV3ID0gdGhpcy52aWV3Q29udGFpbmVyLmNyZWF0ZUVtYmVkZGVkVmlldyh0aGlzLnRlbXBsYXRlLCBjb250ZXh0KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHVwZGF0ZVZpZXdDb250ZXh0KGRhdGE6IHsgdmFsdWU/OiBUUmVzb2x2ZWQgfCBudWxsICwgc291cmNlPzogT2JzZXJ2YWJsZTxUUmVzb2x2ZWQ+IH0pOiB2b2lkXG4gICAgeyAgICBcbiAgICAgICAgdGhpcy52aWV3LmNvbnRleHQgPSB0aGlzLmNyZWF0ZVZpZXdDb250ZXh0KGRhdGEpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBjcmVhdGVWaWV3Q29udGV4dCh7IHZhbHVlLCBzb3VyY2UgfTogeyB2YWx1ZT86IFRSZXNvbHZlZCB8IG51bGwgLCBzb3VyY2U/OiBPYnNlcnZhYmxlPFRSZXNvbHZlZD4gfSk6IFRDb250ZXh0XG4gICAge1xuICAgICAgICB2YWx1ZSAgPz89IHRoaXMudmlldz8uY29udGV4dC4kaW1wbGljaXQgfHwgbnVsbDtcbiAgICAgICAgc291cmNlID8/PSB0aGlzLnZpZXc/LmNvbnRleHQuc291cmNlICAgIHx8IEVNUFRZO1xuXG4gICAgICAgIHJldHVybiB7ICRpbXBsaWNpdDogdmFsdWUsIFt0aGlzLnNlbGVjdG9yXTogdmFsdWUsIHNvdXJjZSB9IGFzIFRDb250ZXh0O1xuICAgIH1cbn1cbiJdfQ==