@bespunky/angular-zen
Version:
The Angular tools you always wished were there.
145 lines • 22.3 kB
JavaScript
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==