@bespunky/angular-zen
Version:
The Angular tools you always wished were there.
145 lines • 20.7 kB
JavaScript
import { Observable } from 'rxjs';
import { Directive, Input } from '@angular/core';
import { OnObserverBaseDirective } from '../abstraction/on-observer-base.directive';
import * as i0 from "@angular/core";
/**
* Documentation in {@link OnObserverCompleteDirective.onObserverComplete} to allow in-template tooltips.
*
* @export
* @class OnObserverCompleteDirective
* @extends {OnObserverBaseDirective<T>}
* @template T The type of value the observable emits.
*/
export class OnObserverCompleteDirective extends OnObserverBaseDirective {
constructor() {
super(...arguments);
this.selector = 'onObserverComplete';
this.renderOnCallsTo = 'complete';
}
/**
* Renders the template when the specified observable has completed without error.
*
* ## Features
*
* #### View Context
* Use the microsyntax `as` keyword to assign resolved values to a variable.
* Use the microsyntax `let` keyword to assign the {@link OnObserverContext full context object} to a variable (e.g. `let context`).
*
* #### Delayed rendering
* Specify a value for {@link OnObserverBaseDirective.showAfter `showAfter`} to delay rendering.
*
* #### Auto destroy
* Specify {@link OnObserverBaseDirective.showFor `showFor`} to automatically destroy the view after a certain duration.
*
* #### Countdown updates
* When {@link OnObserverBaseDirective.showFor `showFor`} is specified, the view context will be updated with the time remaining until the view
* is destroyed and the time elapsed since it was rendered. This allows giving the user feedback in a progress bar, a spinner, a textual timer
* or any other UI component.
*
* Remaining is provided by the {@link OnObserverContext.remaining `remaining`} property. Elapsed time is provided by the {@link OnObserverContext.elapsed `elapsed`}
* property. Access it by assigning a variable using `let`, like so:
* `let remaining = remaining`
*
* #### Multi view mode
* Specify {@link OnObserverBaseDirective.viewMode `viewMode = 'multiple'`} to enable rendering a new view for each intercepted call
* instead of updating a single rendered view. This allows stacking logs, notification snackbars, or any other aggregation functionality.
* Combined with {@link OnObserverBaseDirective.showFor `showFor`}, this is great for disappearing messages/notifications.
*
* #### View index
* In multi-view mode, the context will contain the index of the view, which can be used for calculations and styling.
*/
set onObserverComplete(value) { this.input.next(value); }
/**
* (Optional) The view mode the directive will operate in:
* `'single'` - A single view will be rendered on intercepted calls. If a view has already been rendered when a call is intercepted,
* the existing view will be updated with data from the new call.
*
* `'multiple'` - Every new intercepted call will render a new view with its own context and data encapsulated from the current call.
*
* Default is `'single'`.
*/
set onObserverCompleteViewMode(viewMode) { this.viewMode = viewMode; }
/**
* (Optional) The duration for which the directive should wait before rendering the view once an intercepted call is made.
*
* You can specify a number, which will be treated as milliseconds, or a string with the format of `<number><ms | s | ms>`.
* Numbers can be either integers or floats.
* For example:
* - `3000` - Wait for 3 seconds, then render the view.
* - `'10s'` - Wait for 10 seconds, then render the view.
* - `'0.5m'` - Wait for 30 seconds, then render the view.
* - `'100ms'` - Wait for 100 milliseconds, then render the view.
*
* Default is `0`, meaning immediately render the view.
*
* TODO: ADD LINK TO TOUR OR FULL WIKI PAGE
* Read more {@link OnObserverBaseDirective About render flow}.
**/
set onObserverCompleteShowAfter(duration) { this.showAfter = duration; }
/**
* (Optional) The duration for which the view should be rendered. When the duration passes, the view will be auto destroyed.
*
* You can specify a number, which will be treated as milliseconds, or a string with the format of `<number><ms | s | ms>`.
* Numbers can be either integers or floats.
* For example:
* - `3000` - The view will be destroyed after 3 seconds.
* - `'10s'` - The view will be destroyed after 10 seconds.
* - `'0.5m'` - The view will be destroyed after 30 seconds.
* - `'100ms'` - The view will be destroyed after 100 milliseconds.
*
* During the time the view is rendered, the context will be updated with a countdown object to facilitate any UI part used to
* indicate countdown to the user. The countdown will be exposed through the {@link OnObserverContext.remaining `remaining`}
* property and the elapsed time through {@link OnObserverContext.elapsed `elapsed`} property in the view context and can both
* be accessed be declaring a `let` variable (e.g. `let remaining = remaining`).
* See {@link OnObserverBaseDirective.countdownInterval `countdownInterval`} for changing the updates interval.
*
* When unspecified, the view will be destroyed immediately once the observer detects a call different to the intercepted ones.
*
* TODO: ADD LINK TO TOUR OR FULL WIKI PAGE
* Read more {@link OnObserverBaseDirective About render flow}.
**/
set onObserverCompleteShowFor(duration) { this.showFor = duration; }
;
/**
* ### Only used when passing a value to {@link OnObserverBaseDirective.showFor `showFor`}.
*
* (Optional) The interval with which countdown updates should be made to the view's context before it auto destroys.
* The lower the value, the more updates will be made to the context, but the more resources your directive will consume.
*
* You can specify a number, which will be treated as milliseconds, or a string with the format of `<number><ms | s | ms>`.
* Numbers can be either integers or floats.
* For example:
* - `3000` - 3 seconds between each update.
* - `'10s'` - 10 seconds between each update.
* - `'0.5m'` - 30 seconds between each update.
* - `'100ms'` - 100 milliseconds between each update.
*
* You can also specify `'animationFrames'` so the countdown gets updated each time the browser is working on animations.
*
* When unspecified, the total duration of the countdown will be divided by {@link DefaultCountdownUpdateCount `DefaultCountdownUpdateCount`}
* to get a fixed interval which will make for {@link DefaultCountdownUpdateCount `DefaultCountdownUpdateCount`} countdown updates.
*/
set onObserverCompleteCountdownInterval(duration) { this.countdownInterval = duration; }
;
static ngTemplateContextGuard(directive, context) { return true; }
}
OnObserverCompleteDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: OnObserverCompleteDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
OnObserverCompleteDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.2.12", type: OnObserverCompleteDirective, selector: "[onObserverComplete]", inputs: { onObserverComplete: "onObserverComplete", onObserverCompleteViewMode: "onObserverCompleteViewMode", onObserverCompleteShowAfter: "onObserverCompleteShowAfter", onObserverCompleteShowFor: "onObserverCompleteShowFor", onObserverCompleteCountdownInterval: "onObserverCompleteCountdownInterval" }, usesInheritance: true, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: OnObserverCompleteDirective, decorators: [{
type: Directive,
args: [{
// eslint-disable-next-line @angular-eslint/directive-selector
selector: '[onObserverComplete]'
}]
}], propDecorators: { onObserverComplete: [{
type: Input
}], onObserverCompleteViewMode: [{
type: Input
}], onObserverCompleteShowAfter: [{
type: Input
}], onObserverCompleteShowFor: [{
type: Input
}], onObserverCompleteCountdownInterval: [{
type: Input
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib24tb2JzZXJ2ZXItY29tcGxldGUuZGlyZWN0aXZlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vbGlicy9hbmd1bGFyLXplbi9jb3JlL3NyYy9yeGpzL29uLW9ic2VydmVyL2RpcmVjdGl2ZXMvb24tb2JzZXJ2ZXItY29tcGxldGUuZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQVEsTUFBTSxNQUFNLENBQUM7QUFDeEMsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFHakQsT0FBTyxFQUFFLHVCQUF1QixFQUFxQixNQUFNLDJDQUEyQyxDQUFDOztBQUd2Rzs7Ozs7OztHQU9HO0FBS0gsTUFBTSxPQUFPLDJCQUErQixTQUFRLHVCQUEwQjtJQUo5RTs7UUFNYyxhQUFRLEdBQXdCLG9CQUFvQixDQUFDO1FBQ3JELG9CQUFlLEdBQWlCLFVBQVUsQ0FBQztLQTRHeEQ7SUExR0c7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0ErQkc7SUFDSCxJQUFvQixrQkFBa0IsQ0FBQyxLQUFvQixJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUV4Rjs7Ozs7Ozs7T0FRRztJQUNILElBQW9CLDBCQUEwQixDQUFVLFFBQWtCLElBQWMsSUFBSSxDQUFDLFFBQVEsR0FBWSxRQUFRLENBQUMsQ0FBQyxDQUFDO0lBQzVIOzs7Ozs7Ozs7Ozs7Ozs7UUFlSTtJQUNKLElBQW9CLDJCQUEyQixDQUFTLFFBQTRCLElBQUksSUFBSSxDQUFDLFNBQVMsR0FBVyxRQUFRLENBQUMsQ0FBQyxDQUFDO0lBQzVIOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7UUFxQkk7SUFDSixJQUFvQix5QkFBeUIsQ0FBVyxRQUE0QixJQUFJLElBQUksQ0FBQyxPQUFPLEdBQWEsUUFBUSxDQUFDLENBQUMsQ0FBQztJQUFBLENBQUM7SUFDN0g7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQWtCRztJQUNILElBQW9CLG1DQUFtQyxDQUFDLFFBQWdELElBQUksSUFBSSxDQUFDLGlCQUFpQixHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUM7SUFBQSxDQUFDO0lBRWpKLE1BQU0sQ0FBQyxzQkFBc0IsQ0FBSSxTQUF5QyxFQUFFLE9BQWdCLElBQXFDLE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQzs7eUhBOUd0SSwyQkFBMkI7NkdBQTNCLDJCQUEyQjs0RkFBM0IsMkJBQTJCO2tCQUp2QyxTQUFTO21CQUFDO29CQUNQLDhEQUE4RDtvQkFDOUQsUUFBUSxFQUFFLHNCQUFzQjtpQkFDbkM7OEJBc0N1QixrQkFBa0I7c0JBQXJDLEtBQUs7Z0JBV2MsMEJBQTBCO3NCQUE3QyxLQUFLO2dCQWlCYywyQkFBMkI7c0JBQTlDLEtBQUs7Z0JBdUJjLHlCQUF5QjtzQkFBNUMsS0FBSztnQkFvQmMsbUNBQW1DO3NCQUF0RCxLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgT2JzZXJ2YWJsZSAgICAgICB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgRGlyZWN0aXZlLCBJbnB1dCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5pbXBvcnQgeyBEdXJhdGlvbkFubm90YXRpb24sIE9ic2VydmVyTmFtZSwgVmlld01vZGUgfSBmcm9tICcuLi9hYnN0cmFjdGlvbi90eXBlcy9nZW5lcmFsJztcbmltcG9ydCB7IE9uT2JzZXJ2ZXJCYXNlRGlyZWN0aXZlICAgICAgICAgICAgICAgICAgICB9IGZyb20gJy4uL2Fic3RyYWN0aW9uL29uLW9ic2VydmVyLWJhc2UuZGlyZWN0aXZlJztcbmltcG9ydCB7IE9uT2JzZXJ2ZXJDb250ZXh0IH0gZnJvbSAnLi4vYWJzdHJhY3Rpb24vdHlwZXMvb24tb2JzZXJ2ZXItY29udGV4dCc7XG5cbi8qKlxuICogIERvY3VtZW50YXRpb24gaW4ge0BsaW5rIE9uT2JzZXJ2ZXJDb21wbGV0ZURpcmVjdGl2ZS5vbk9ic2VydmVyQ29tcGxldGV9IHRvIGFsbG93IGluLXRlbXBsYXRlIHRvb2x0aXBzLlxuICpcbiAqIEBleHBvcnRcbiAqIEBjbGFzcyBPbk9ic2VydmVyQ29tcGxldGVEaXJlY3RpdmVcbiAqIEBleHRlbmRzIHtPbk9ic2VydmVyQmFzZURpcmVjdGl2ZTxUPn1cbiAqIEB0ZW1wbGF0ZSBUIFRoZSB0eXBlIG9mIHZhbHVlIHRoZSBvYnNlcnZhYmxlIGVtaXRzLlxuICovXG5ARGlyZWN0aXZlKHtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQGFuZ3VsYXItZXNsaW50L2RpcmVjdGl2ZS1zZWxlY3RvclxuICAgIHNlbGVjdG9yOiAnW29uT2JzZXJ2ZXJDb21wbGV0ZV0nXG59KVxuZXhwb3J0IGNsYXNzIE9uT2JzZXJ2ZXJDb21wbGV0ZURpcmVjdGl2ZTxUPiBleHRlbmRzIE9uT2JzZXJ2ZXJCYXNlRGlyZWN0aXZlPFQ+XG57XG4gICAgcHJvdGVjdGVkIHNlbGVjdG9yICAgICAgICAgICAgICAgICAgICAgID0gJ29uT2JzZXJ2ZXJDb21wbGV0ZSc7XG4gICAgcHJvdGVjdGVkIHJlbmRlck9uQ2FsbHNUbzogT2JzZXJ2ZXJOYW1lID0gJ2NvbXBsZXRlJztcbiAgICBcbiAgICAvKipcbiAgICAgKiBSZW5kZXJzIHRoZSB0ZW1wbGF0ZSB3aGVuIHRoZSBzcGVjaWZpZWQgb2JzZXJ2YWJsZSBoYXMgY29tcGxldGVkIHdpdGhvdXQgZXJyb3IuXG4gICAgICogXG4gICAgICogIyMgRmVhdHVyZXNcbiAgICAgKiBcbiAgICAgKiAjIyMjIFZpZXcgQ29udGV4dFxuICAgICAqIFVzZSB0aGUgbWljcm9zeW50YXggYGFzYCBrZXl3b3JkIHRvIGFzc2lnbiByZXNvbHZlZCB2YWx1ZXMgdG8gYSB2YXJpYWJsZS5cbiAgICAgKiBVc2UgdGhlIG1pY3Jvc3ludGF4IGBsZXRgIGtleXdvcmQgdG8gYXNzaWduIHRoZSB7QGxpbmsgT25PYnNlcnZlckNvbnRleHQgZnVsbCBjb250ZXh0IG9iamVjdH0gdG8gYSB2YXJpYWJsZSAoZS5nLiBgbGV0IGNvbnRleHRgKS5cbiAgICAgKiAgXG4gICAgICogIyMjIyBEZWxheWVkIHJlbmRlcmluZ1xuICAgICAqIFNwZWNpZnkgYSB2YWx1ZSBmb3Ige0BsaW5rIE9uT2JzZXJ2ZXJCYXNlRGlyZWN0aXZlLnNob3dBZnRlciBgc2hvd0FmdGVyYH0gdG8gZGVsYXkgcmVuZGVyaW5nLlxuICAgICAqIFxuICAgICAqICMjIyMgQXV0byBkZXN0cm95XG4gICAgICogU3BlY2lmeSB7QGxpbmsgT25PYnNlcnZlckJhc2VEaXJlY3RpdmUuc2hvd0ZvciBgc2hvd0ZvcmB9IHRvIGF1dG9tYXRpY2FsbHkgZGVzdHJveSB0aGUgdmlldyBhZnRlciBhIGNlcnRhaW4gZHVyYXRpb24uXG4gICAgICogXG4gICAgICogIyMjIyBDb3VudGRvd24gdXBkYXRlc1xuICAgICAqIFdoZW4ge0BsaW5rIE9uT2JzZXJ2ZXJCYXNlRGlyZWN0aXZlLnNob3dGb3IgYHNob3dGb3JgfSBpcyBzcGVjaWZpZWQsIHRoZSB2aWV3IGNvbnRleHQgd2lsbCBiZSB1cGRhdGVkIHdpdGggdGhlIHRpbWUgcmVtYWluaW5nIHVudGlsIHRoZSB2aWV3XG4gICAgICogaXMgZGVzdHJveWVkIGFuZCB0aGUgdGltZSBlbGFwc2VkIHNpbmNlIGl0IHdhcyByZW5kZXJlZC4gVGhpcyBhbGxvd3MgZ2l2aW5nIHRoZSB1c2VyIGZlZWRiYWNrIGluIGEgcHJvZ3Jlc3MgYmFyLCBhIHNwaW5uZXIsIGEgdGV4dHVhbCB0aW1lclxuICAgICAqIG9yIGFueSBvdGhlciBVSSBjb21wb25lbnQuIFxuICAgICAqIFxuICAgICAqIFJlbWFpbmluZyBpcyBwcm92aWRlZCBieSB0aGUge0BsaW5rIE9uT2JzZXJ2ZXJDb250ZXh0LnJlbWFpbmluZyBgcmVtYWluaW5nYH0gcHJvcGVydHkuIEVsYXBzZWQgdGltZSBpcyBwcm92aWRlZCBieSB0aGUge0BsaW5rIE9uT2JzZXJ2ZXJDb250ZXh0LmVsYXBzZWQgYGVsYXBzZWRgfVxuICAgICAqIHByb3BlcnR5LiBBY2Nlc3MgaXQgYnkgYXNzaWduaW5nIGEgdmFyaWFibGUgdXNpbmcgYGxldGAsIGxpa2Ugc286ICBcbiAgICAgKiBgbGV0IHJlbWFpbmluZyA9IHJlbWFpbmluZ2BcbiAgICAgKiBcbiAgICAgKiAjIyMjIE11bHRpIHZpZXcgbW9kZVxuICAgICAqIFNwZWNpZnkge0BsaW5rIE9uT2JzZXJ2ZXJCYXNlRGlyZWN0aXZlLnZpZXdNb2RlIGB2aWV3TW9kZSA9ICdtdWx0aXBsZSdgfSB0byBlbmFibGUgcmVuZGVyaW5nIGEgbmV3IHZpZXcgZm9yIGVhY2ggaW50ZXJjZXB0ZWQgY2FsbFxuICAgICAqIGluc3RlYWQgb2YgdXBkYXRpbmcgYSBzaW5nbGUgcmVuZGVyZWQgdmlldy4gVGhpcyBhbGxvd3Mgc3RhY2tpbmcgbG9ncywgbm90aWZpY2F0aW9uIHNuYWNrYmFycywgb3IgYW55IG90aGVyIGFnZ3JlZ2F0aW9uIGZ1bmN0aW9uYWxpdHkuXG4gICAgICogQ29tYmluZWQgd2l0aCB7QGxpbmsgT25PYnNlcnZlckJhc2VEaXJlY3RpdmUuc2hvd0ZvciBgc2hvd0ZvcmB9LCB0aGlzIGlzIGdyZWF0IGZvciBkaXNhcHBlYXJpbmcgbWVzc2FnZXMvbm90aWZpY2F0aW9ucy5cbiAgICAgKiBcbiAgICAgKiAjIyMjIFZpZXcgaW5kZXhcbiAgICAgKiBJbiBtdWx0aS12aWV3IG1vZGUsIHRoZSBjb250ZXh0IHdpbGwgY29udGFpbiB0aGUgaW5kZXggb2YgdGhlIHZpZXcsIHdoaWNoIGNhbiBiZSB1c2VkIGZvciBjYWxjdWxhdGlvbnMgYW5kIHN0eWxpbmcuXG4gICAgICovXG4gICAgQElucHV0KCkgcHVibGljIHNldCBvbk9ic2VydmVyQ29tcGxldGUodmFsdWU6IE9ic2VydmFibGU8VD4pIHsgdGhpcy5pbnB1dC5uZXh0KHZhbHVlKTsgfVxuXG4gICAgLyoqXG4gICAgICogKE9wdGlvbmFsKSBUaGUgdmlldyBtb2RlIHRoZSBkaXJlY3RpdmUgd2lsbCBvcGVyYXRlIGluOiAgXG4gICAgICogYCdzaW5nbGUnYCAtIEEgc2luZ2xlIHZpZXcgd2lsbCBiZSByZW5kZXJlZCBvbiBpbnRlcmNlcHRlZCBjYWxscy4gSWYgYSB2aWV3IGhhcyBhbHJlYWR5IGJlZW4gcmVuZGVyZWQgd2hlbiBhIGNhbGwgaXMgaW50ZXJjZXB0ZWQsXG4gICAgICogdGhlIGV4aXN0aW5nIHZpZXcgd2lsbCBiZSB1cGRhdGVkIHdpdGggZGF0YSBmcm9tIHRoZSBuZXcgY2FsbC5cbiAgICAgKiBcbiAgICAgKiBgJ211bHRpcGxlJ2AgLSBFdmVyeSBuZXcgaW50ZXJjZXB0ZWQgY2FsbCB3aWxsIHJlbmRlciBhIG5ldyB2aWV3IHdpdGggaXRzIG93biBjb250ZXh0IGFuZCBkYXRhIGVuY2Fwc3VsYXRlZCBmcm9tIHRoZSBjdXJyZW50IGNhbGwuXG4gICAgICogXG4gICAgICogRGVmYXVsdCBpcyBgJ3NpbmdsZSdgLlxuICAgICAqL1xuICAgIEBJbnB1dCgpIHB1YmxpYyBzZXQgb25PYnNlcnZlckNvbXBsZXRlVmlld01vZGUgICAgICAgICAodmlld01vZGU6IFZpZXdNb2RlICAgICAgICAgICkgeyB0aGlzLnZpZXdNb2RlICAgICAgICAgID0gdmlld01vZGU7IH1cbiAgICAvKipcbiAgICAgKiAoT3B0aW9uYWwpIFRoZSBkdXJhdGlvbiBmb3Igd2hpY2ggdGhlIGRpcmVjdGl2ZSBzaG91bGQgd2FpdCBiZWZvcmUgcmVuZGVyaW5nIHRoZSB2aWV3IG9uY2UgYW4gaW50ZXJjZXB0ZWQgY2FsbCBpcyBtYWRlLlxuICAgICAqIFxuICAgICAqIFlvdSBjYW4gc3BlY2lmeSBhIG51bWJlciwgd2hpY2ggd2lsbCBiZSB0cmVhdGVkIGFzIG1pbGxpc2Vjb25kcywgb3IgYSBzdHJpbmcgd2l0aCB0aGUgZm9ybWF0IG9mIGA8bnVtYmVyPjxtcyB8IHMgfCBtcz5gLlxuICAgICAqIE51bWJlcnMgY2FuIGJlIGVpdGhlciBpbnRlZ2VycyBvciBmbG9hdHMuXG4gICAgICogRm9yIGV4YW1wbGU6XG4gICAgICogLSBgMzAwMGAgLSBXYWl0IGZvciAzIHNlY29uZHMsIHRoZW4gcmVuZGVyIHRoZSB2aWV3LlxuICAgICAqIC0gYCcxMHMnYCAtIFdhaXQgZm9yIDEwIHNlY29uZHMsIHRoZW4gcmVuZGVyIHRoZSB2aWV3LlxuICAgICAqIC0gYCcwLjVtJ2AgLSBXYWl0IGZvciAzMCBzZWNvbmRzLCB0aGVuIHJlbmRlciB0aGUgdmlldy5cbiAgICAgKiAtIGAnMTAwbXMnYCAtIFdhaXQgZm9yIDEwMCBtaWxsaXNlY29uZHMsIHRoZW4gcmVuZGVyIHRoZSB2aWV3LlxuICAgICAqIFxuICAgICAqIERlZmF1bHQgaXMgYDBgLCBtZWFuaW5nIGltbWVkaWF0ZWx5IHJlbmRlciB0aGUgdmlldy5cbiAgICAgKlxuICAgICAqIFRPRE86IEFERCBMSU5LIFRPIFRPVVIgT1IgRlVMTCBXSUtJIFBBR0VcbiAgICAgKiBSZWFkIG1vcmUge0BsaW5rIE9uT2JzZXJ2ZXJCYXNlRGlyZWN0aXZlIEFib3V0IHJlbmRlciBmbG93fS5cbiAgICAgKiovXG4gICAgQElucHV0KCkgcHVibGljIHNldCBvbk9ic2VydmVyQ29tcGxldGVTaG93QWZ0ZXIgICAgICAgIChkdXJhdGlvbjogRHVyYXRpb25Bbm5vdGF0aW9uKSB7IHRoaXMuc2hvd0FmdGVyICAgICAgICAgPSBkdXJhdGlvbjsgfVxuICAgIC8qKlxuICAgICAqIChPcHRpb25hbCkgVGhlIGR1cmF0aW9uIGZvciB3aGljaCB0aGUgdmlldyBzaG91bGQgYmUgcmVuZGVyZWQuIFdoZW4gdGhlIGR1cmF0aW9uIHBhc3NlcywgdGhlIHZpZXcgd2lsbCBiZSBhdXRvIGRlc3Ryb3llZC5cbiAgICAgKlxuICAgICAqIFlvdSBjYW4gc3BlY2lmeSBhIG51bWJlciwgd2hpY2ggd2lsbCBiZSB0cmVhdGVkIGFzIG1pbGxpc2Vjb25kcywgb3IgYSBzdHJpbmcgd2l0aCB0aGUgZm9ybWF0IG9mIGA8bnVtYmVyPjxtcyB8IHMgfCBtcz5gLlxuICAgICAqIE51bWJlcnMgY2FuIGJlIGVpdGhlciBpbnRlZ2VycyBvciBmbG9hdHMuXG4gICAgICogRm9yIGV4YW1wbGU6XG4gICAgICogLSBgMzAwMGAgLSBUaGUgdmlldyB3aWxsIGJlIGRlc3Ryb3llZCBhZnRlciAzIHNlY29uZHMuXG4gICAgICogLSBgJzEwcydgIC0gVGhlIHZpZXcgd2lsbCBiZSBkZXN0cm95ZWQgYWZ0ZXIgMTAgc2Vjb25kcy5cbiAgICAgKiAtIGAnMC41bSdgIC0gVGhlIHZpZXcgd2lsbCBiZSBkZXN0cm95ZWQgYWZ0ZXIgMzAgc2Vjb25kcy5cbiAgICAgKiAtIGAnMTAwbXMnYCAtIFRoZSB2aWV3IHdpbGwgYmUgZGVzdHJveWVkIGFmdGVyIDEwMCBtaWxsaXNlY29uZHMuXG4gICAgICogXG4gICAgICogRHVyaW5nIHRoZSB0aW1lIHRoZSB2aWV3IGlzIHJlbmRlcmVkLCB0aGUgY29udGV4dCB3aWxsIGJlIHVwZGF0ZWQgd2l0aCBhIGNvdW50ZG93biBvYmplY3QgdG8gZmFjaWxpdGF0ZSBhbnkgVUkgcGFydCB1c2VkIHRvXG4gICAgICogaW5kaWNhdGUgY291bnRkb3duIHRvIHRoZSB1c2VyLiBUaGUgY291bnRkb3duIHdpbGwgYmUgZXhwb3NlZCB0aHJvdWdoIHRoZSB7QGxpbmsgT25PYnNlcnZlckNvbnRleHQucmVtYWluaW5nIGByZW1haW5pbmdgfVxuICAgICAqIHByb3BlcnR5IGFuZCB0aGUgZWxhcHNlZCB0aW1lIHRocm91Z2gge0BsaW5rIE9uT2JzZXJ2ZXJDb250ZXh0LmVsYXBzZWQgYGVsYXBzZWRgfSBwcm9wZXJ0eSBpbiB0aGUgdmlldyBjb250ZXh0IGFuZCBjYW4gYm90aFxuICAgICAqIGJlIGFjY2Vzc2VkIGJlIGRlY2xhcmluZyBhIGBsZXRgIHZhcmlhYmxlIChlLmcuIGBsZXQgcmVtYWluaW5nID0gcmVtYWluaW5nYCkuXG4gICAgICogU2VlIHtAbGluayBPbk9ic2VydmVyQmFzZURpcmVjdGl2ZS5jb3VudGRvd25JbnRlcnZhbCBgY291bnRkb3duSW50ZXJ2YWxgfSBmb3IgY2hhbmdpbmcgdGhlIHVwZGF0ZXMgaW50ZXJ2YWwuXG4gICAgICogXG4gICAgICogV2hlbiB1bnNwZWNpZmllZCwgdGhlIHZpZXcgd2lsbCBiZSBkZXN0cm95ZWQgaW1tZWRpYXRlbHkgb25jZSB0aGUgb2JzZXJ2ZXIgZGV0ZWN0cyBhIGNhbGwgZGlmZmVyZW50IHRvIHRoZSBpbnRlcmNlcHRlZCBvbmVzLlxuICAgICAqIFxuICAgICAqIFRPRE86IEFERCBMSU5LIFRPIFRPVVIgT1IgRlVMTCBXSUtJIFBBR0VcbiAgICAgKiBSZWFkIG1vcmUge0BsaW5rIE9uT2JzZXJ2ZXJCYXNlRGlyZWN0aXZlIEFib3V0IHJlbmRlciBmbG93fS5cbiAgICAgKiovXG4gICAgQElucHV0KCkgcHVibGljIHNldCBvbk9ic2VydmVyQ29tcGxldGVTaG93Rm9yICAgICAgICAgIChkdXJhdGlvbjogRHVyYXRpb25Bbm5vdGF0aW9uKSB7IHRoaXMuc2hvd0ZvciAgICAgICAgICAgPSBkdXJhdGlvbjsgfTtcbiAgICAvKipcbiAgICAgKiAjIyMgT25seSB1c2VkIHdoZW4gcGFzc2luZyBhIHZhbHVlIHRvIHtAbGluayBPbk9ic2VydmVyQmFzZURpcmVjdGl2ZS5zaG93Rm9yIGBzaG93Rm9yYH0uXG4gICAgICogXG4gICAgICogKE9wdGlvbmFsKSBUaGUgaW50ZXJ2YWwgd2l0aCB3aGljaCBjb3VudGRvd24gdXBkYXRlcyBzaG91bGQgYmUgbWFkZSB0byB0aGUgdmlldydzIGNvbnRleHQgYmVmb3JlIGl0IGF1dG8gZGVzdHJveXMuXG4gICAgICogVGhlIGxvd2VyIHRoZSB2YWx1ZSwgdGhlIG1vcmUgdXBkYXRlcyB3aWxsIGJlIG1hZGUgdG8gdGhlIGNvbnRleHQsIGJ1dCB0aGUgbW9yZSByZXNvdXJjZXMgeW91ciBkaXJlY3RpdmUgd2lsbCBjb25zdW1lLlxuICAgICAqIFxuICAgICAqIFlvdSBjYW4gc3BlY2lmeSBhIG51bWJlciwgd2hpY2ggd2lsbCBiZSB0cmVhdGVkIGFzIG1pbGxpc2Vjb25kcywgb3IgYSBzdHJpbmcgd2l0aCB0aGUgZm9ybWF0IG9mIGA8bnVtYmVyPjxtcyB8IHMgfCBtcz5gLlxuICAgICAqIE51bWJlcnMgY2FuIGJlIGVpdGhlciBpbnRlZ2VycyBvciBmbG9hdHMuXG4gICAgICogRm9yIGV4YW1wbGU6XG4gICAgICogLSBgMzAwMGAgLSAzIHNlY29uZHMgYmV0d2VlbiBlYWNoIHVwZGF0ZS5cbiAgICAgKiAtIGAnMTBzJ2AgLSAxMCBzZWNvbmRzIGJldHdlZW4gZWFjaCB1cGRhdGUuXG4gICAgICogLSBgJzAuNW0nYCAtIDMwIHNlY29uZHMgYmV0d2VlbiBlYWNoIHVwZGF0ZS5cbiAgICAgKiAtIGAnMTAwbXMnYCAtIDEwMCBtaWxsaXNlY29uZHMgYmV0d2VlbiBlYWNoIHVwZGF0ZS5cbiAgICAgKiBcbiAgICAgKiBZb3UgY2FuIGFsc28gc3BlY2lmeSBgJ2FuaW1hdGlvbkZyYW1lcydgIHNvIHRoZSBjb3VudGRvd24gZ2V0cyB1cGRhdGVkIGVhY2ggdGltZSB0aGUgYnJvd3NlciBpcyB3b3JraW5nIG9uIGFuaW1hdGlvbnMuXG4gICAgICogXG4gICAgICogV2hlbiB1bnNwZWNpZmllZCwgdGhlIHRvdGFsIGR1cmF0aW9uIG9mIHRoZSBjb3VudGRvd24gd2lsbCBiZSBkaXZpZGVkIGJ5IHtAbGluayBEZWZhdWx0Q291bnRkb3duVXBkYXRlQ291bnQgYERlZmF1bHRDb3VudGRvd25VcGRhdGVDb3VudGB9XG4gICAgICogdG8gZ2V0IGEgZml4ZWQgaW50ZXJ2YWwgd2hpY2ggd2lsbCBtYWtlIGZvciB7QGxpbmsgRGVmYXVsdENvdW50ZG93blVwZGF0ZUNvdW50IGBEZWZhdWx0Q291bnRkb3duVXBkYXRlQ291bnRgfSBjb3VudGRvd24gdXBkYXRlcy5cbiAgICAgKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgc2V0IG9uT2JzZXJ2ZXJDb21wbGV0ZUNvdW50ZG93bkludGVydmFsKGR1cmF0aW9uOiBEdXJhdGlvbkFubm90YXRpb24gfCAnYW5pbWF0aW9uRnJhbWVzJykgeyB0aGlzLmNvdW50ZG93bkludGVydmFsID0gZHVyYXRpb247IH07XG4gXG4gICAgc3RhdGljIG5nVGVtcGxhdGVDb250ZXh0R3VhcmQ8VD4oZGlyZWN0aXZlOiBPbk9ic2VydmVyQ29tcGxldGVEaXJlY3RpdmU8VD4sIGNvbnRleHQ6IHVua25vd24pOiBjb250ZXh0IGlzIE9uT2JzZXJ2ZXJDb250ZXh0PFQ+IHsgcmV0dXJuIHRydWU7IH1cbn0iXX0=