UNPKG

@bespunky/angular-zen

Version:

The Angular tools you always wished were there.

146 lines 21.1 kB
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 OnObserverFinalizedDirective.onObserverFinalized} to allow in-template tooltips. * * @export * @class OnObserverFinalizedDirective * @extends {OnObserverBaseDirective<T>} * @template T The type of value the observable emits. */ export class OnObserverFinalizedDirective extends OnObserverBaseDirective { constructor() { super(...arguments); this.selector = 'onObserverFinalized'; this.renderOnCallsTo = ['error', 'complete']; } /** * Renders the template when the specified observable is either completed or errored. In case of an error, the error will be * provided as the value in the context. * * ## 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 onObserverFinalized(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 onObserverFinalizedViewMode(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 onObserverFinalizedShowAfter(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 onObserverFinalizedShowFor(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 onObserverFinalizedCountdownInterval(duration) { this.countdownInterval = duration; } ; static ngTemplateContextGuard(directive, context) { return true; } } OnObserverFinalizedDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: OnObserverFinalizedDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); OnObserverFinalizedDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.2.12", type: OnObserverFinalizedDirective, selector: "[onObserverFinalized]", inputs: { onObserverFinalized: "onObserverFinalized", onObserverFinalizedViewMode: "onObserverFinalizedViewMode", onObserverFinalizedShowAfter: "onObserverFinalizedShowAfter", onObserverFinalizedShowFor: "onObserverFinalizedShowFor", onObserverFinalizedCountdownInterval: "onObserverFinalizedCountdownInterval" }, usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: OnObserverFinalizedDirective, decorators: [{ type: Directive, args: [{ // eslint-disable-next-line @angular-eslint/directive-selector selector: '[onObserverFinalized]' }] }], propDecorators: { onObserverFinalized: [{ type: Input }], onObserverFinalizedViewMode: [{ type: Input }], onObserverFinalizedShowAfter: [{ type: Input }], onObserverFinalizedShowFor: [{ type: Input }], onObserverFinalizedCountdownInterval: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib24tb2JzZXJ2ZXItZmluYWxpemVkLmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvYW5ndWxhci16ZW4vY29yZS9zcmMvcnhqcy9vbi1vYnNlcnZlci9kaXJlY3RpdmVzL29uLW9ic2VydmVyLWZpbmFsaXplZC5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBUSxNQUFNLE1BQU0sQ0FBQztBQUN4QyxPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUlqRCxPQUFPLEVBQUUsdUJBQXVCLEVBQXFCLE1BQU0sMkNBQTJDLENBQUM7O0FBRXZHOzs7Ozs7O0dBT0c7QUFLSCxNQUFNLE9BQU8sNEJBQWdDLFNBQVEsdUJBQTBCO0lBSi9FOztRQU1jLGFBQVEsR0FBMEIscUJBQXFCLENBQUM7UUFDeEQsb0JBQWUsR0FBbUIsQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDLENBQUM7S0E2R3JFO0lBM0dHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQWdDRztJQUNILElBQW9CLG1CQUFtQixDQUFDLEtBQW9CLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRXpGOzs7Ozs7OztPQVFHO0lBQ0gsSUFBb0IsMkJBQTJCLENBQVUsUUFBa0IsSUFBYyxJQUFJLENBQUMsUUFBUSxHQUFZLFFBQVEsQ0FBQyxDQUFDLENBQUM7SUFDN0g7Ozs7Ozs7Ozs7Ozs7OztRQWVJO0lBQ0osSUFBb0IsNEJBQTRCLENBQVMsUUFBNEIsSUFBSSxJQUFJLENBQUMsU0FBUyxHQUFXLFFBQVEsQ0FBQyxDQUFDLENBQUM7SUFDN0g7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztRQXFCSTtJQUNKLElBQW9CLDBCQUEwQixDQUFXLFFBQTRCLElBQUksSUFBSSxDQUFDLE9BQU8sR0FBYSxRQUFRLENBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQztJQUM5SDs7Ozs7Ozs7Ozs7Ozs7Ozs7O09Ba0JHO0lBQ0gsSUFBb0Isb0NBQW9DLENBQUMsUUFBZ0QsSUFBSSxJQUFJLENBQUMsaUJBQWlCLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQztJQUFBLENBQUM7SUFFbEosTUFBTSxDQUFDLHNCQUFzQixDQUFJLFNBQTBDLEVBQUUsT0FBZ0IsSUFBcUMsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDOzswSEEvR3ZJLDRCQUE0Qjs4R0FBNUIsNEJBQTRCOzRGQUE1Qiw0QkFBNEI7a0JBSnhDLFNBQVM7bUJBQUM7b0JBQ1AsOERBQThEO29CQUM5RCxRQUFRLEVBQUUsdUJBQXVCO2lCQUNwQzs4QkF1Q3VCLG1CQUFtQjtzQkFBdEMsS0FBSztnQkFXYywyQkFBMkI7c0JBQTlDLEtBQUs7Z0JBaUJjLDRCQUE0QjtzQkFBL0MsS0FBSztnQkF1QmMsMEJBQTBCO3NCQUE3QyxLQUFLO2dCQW9CYyxvQ0FBb0M7c0JBQXZELEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBPYnNlcnZhYmxlICAgICAgIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBEaXJlY3RpdmUsIElucHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmltcG9ydCB7IER1cmF0aW9uQW5ub3RhdGlvbiwgT2JzZXJ2ZXJOYW1lLCBWaWV3TW9kZSB9IGZyb20gJy4uL2Fic3RyYWN0aW9uL3R5cGVzL2dlbmVyYWwnO1xuaW1wb3J0IHsgT25PYnNlcnZlckNvbnRleHQgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZnJvbSAnLi4vYWJzdHJhY3Rpb24vdHlwZXMvb24tb2JzZXJ2ZXItY29udGV4dCc7XG5pbXBvcnQgeyBPbk9ic2VydmVyQmFzZURpcmVjdGl2ZSAgICAgICAgICAgICAgICAgICAgfSBmcm9tICcuLi9hYnN0cmFjdGlvbi9vbi1vYnNlcnZlci1iYXNlLmRpcmVjdGl2ZSc7XG5cbi8qKlxuICogRG9jdW1lbnRhdGlvbiBpbiB7QGxpbmsgT25PYnNlcnZlckZpbmFsaXplZERpcmVjdGl2ZS5vbk9ic2VydmVyRmluYWxpemVkfSB0byBhbGxvdyBpbi10ZW1wbGF0ZSB0b29sdGlwcy5cbiAqXG4gKiBAZXhwb3J0XG4gKiBAY2xhc3MgT25PYnNlcnZlckZpbmFsaXplZERpcmVjdGl2ZVxuICogQGV4dGVuZHMge09uT2JzZXJ2ZXJCYXNlRGlyZWN0aXZlPFQ+fVxuICogQHRlbXBsYXRlIFQgVGhlIHR5cGUgb2YgdmFsdWUgdGhlIG9ic2VydmFibGUgZW1pdHMuXG4gKi9cbkBEaXJlY3RpdmUoe1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAYW5ndWxhci1lc2xpbnQvZGlyZWN0aXZlLXNlbGVjdG9yXG4gICAgc2VsZWN0b3I6ICdbb25PYnNlcnZlckZpbmFsaXplZF0nXG59KVxuZXhwb3J0IGNsYXNzIE9uT2JzZXJ2ZXJGaW5hbGl6ZWREaXJlY3RpdmU8VD4gZXh0ZW5kcyBPbk9ic2VydmVyQmFzZURpcmVjdGl2ZTxUPlxue1xuICAgIHByb3RlY3RlZCBzZWxlY3RvciAgICAgICAgICAgICAgICAgICAgICAgID0gJ29uT2JzZXJ2ZXJGaW5hbGl6ZWQnO1xuICAgIHByb3RlY3RlZCByZW5kZXJPbkNhbGxzVG86IE9ic2VydmVyTmFtZVtdID0gWydlcnJvcicsICdjb21wbGV0ZSddO1xuICAgIFxuICAgIC8qKlxuICAgICAqIFJlbmRlcnMgdGhlIHRlbXBsYXRlIHdoZW4gdGhlIHNwZWNpZmllZCBvYnNlcnZhYmxlIGlzIGVpdGhlciBjb21wbGV0ZWQgb3IgZXJyb3JlZC4gSW4gY2FzZSBvZiBhbiBlcnJvciwgdGhlIGVycm9yIHdpbGwgYmVcbiAgICAgKiBwcm92aWRlZCBhcyB0aGUgdmFsdWUgaW4gdGhlIGNvbnRleHQuXG4gICAgICogXG4gICAgICogIyMgRmVhdHVyZXNcbiAgICAgKiBcbiAgICAgKiAjIyMjIFZpZXcgQ29udGV4dFxuICAgICAqIFVzZSB0aGUgbWljcm9zeW50YXggYGFzYCBrZXl3b3JkIHRvIGFzc2lnbiByZXNvbHZlZCB2YWx1ZXMgdG8gYSB2YXJpYWJsZS5cbiAgICAgKiBVc2UgdGhlIG1pY3Jvc3ludGF4IGBsZXRgIGtleXdvcmQgdG8gYXNzaWduIHRoZSB7QGxpbmsgT25PYnNlcnZlckNvbnRleHQgZnVsbCBjb250ZXh0IG9iamVjdH0gdG8gYSB2YXJpYWJsZSAoZS5nLiBgbGV0IGNvbnRleHRgKS5cbiAgICAgKiAgXG4gICAgICogIyMjIyBEZWxheWVkIHJlbmRlcmluZ1xuICAgICAqIFNwZWNpZnkgYSB2YWx1ZSBmb3Ige0BsaW5rIE9uT2JzZXJ2ZXJCYXNlRGlyZWN0aXZlLnNob3dBZnRlciBgc2hvd0FmdGVyYH0gdG8gZGVsYXkgcmVuZGVyaW5nLlxuICAgICAqIFxuICAgICAqICMjIyMgQXV0byBkZXN0cm95XG4gICAgICogU3BlY2lmeSB7QGxpbmsgT25PYnNlcnZlckJhc2VEaXJlY3RpdmUuc2hvd0ZvciBgc2hvd0ZvcmB9IHRvIGF1dG9tYXRpY2FsbHkgZGVzdHJveSB0aGUgdmlldyBhZnRlciBhIGNlcnRhaW4gZHVyYXRpb24uXG4gICAgICogXG4gICAgICogIyMjIyBDb3VudGRvd24gdXBkYXRlc1xuICAgICAqIFdoZW4ge0BsaW5rIE9uT2JzZXJ2ZXJCYXNlRGlyZWN0aXZlLnNob3dGb3IgYHNob3dGb3JgfSBpcyBzcGVjaWZpZWQsIHRoZSB2aWV3IGNvbnRleHQgd2lsbCBiZSB1cGRhdGVkIHdpdGggdGhlIHRpbWUgcmVtYWluaW5nIHVudGlsIHRoZSB2aWV3XG4gICAgICogaXMgZGVzdHJveWVkIGFuZCB0aGUgdGltZSBlbGFwc2VkIHNpbmNlIGl0IHdhcyByZW5kZXJlZC4gVGhpcyBhbGxvd3MgZ2l2aW5nIHRoZSB1c2VyIGZlZWRiYWNrIGluIGEgcHJvZ3Jlc3MgYmFyLCBhIHNwaW5uZXIsIGEgdGV4dHVhbCB0aW1lclxuICAgICAqIG9yIGFueSBvdGhlciBVSSBjb21wb25lbnQuIFxuICAgICAqIFxuICAgICAqIFJlbWFpbmluZyBpcyBwcm92aWRlZCBieSB0aGUge0BsaW5rIE9uT2JzZXJ2ZXJDb250ZXh0LnJlbWFpbmluZyBgcmVtYWluaW5nYH0gcHJvcGVydHkuIEVsYXBzZWQgdGltZSBpcyBwcm92aWRlZCBieSB0aGUge0BsaW5rIE9uT2JzZXJ2ZXJDb250ZXh0LmVsYXBzZWQgYGVsYXBzZWRgfVxuICAgICAqIHByb3BlcnR5LiBBY2Nlc3MgaXQgYnkgYXNzaWduaW5nIGEgdmFyaWFibGUgdXNpbmcgYGxldGAsIGxpa2Ugc286ICBcbiAgICAgKiBgbGV0IHJlbWFpbmluZyA9IHJlbWFpbmluZ2BcbiAgICAgKiBcbiAgICAgKiAjIyMjIE11bHRpIHZpZXcgbW9kZVxuICAgICAqIFNwZWNpZnkge0BsaW5rIE9uT2JzZXJ2ZXJCYXNlRGlyZWN0aXZlLnZpZXdNb2RlIGB2aWV3TW9kZSA9ICdtdWx0aXBsZSdgfSB0byBlbmFibGUgcmVuZGVyaW5nIGEgbmV3IHZpZXcgZm9yIGVhY2ggaW50ZXJjZXB0ZWQgY2FsbFxuICAgICAqIGluc3RlYWQgb2YgdXBkYXRpbmcgYSBzaW5nbGUgcmVuZGVyZWQgdmlldy4gVGhpcyBhbGxvd3Mgc3RhY2tpbmcgbG9ncywgbm90aWZpY2F0aW9uIHNuYWNrYmFycywgb3IgYW55IG90aGVyIGFnZ3JlZ2F0aW9uIGZ1bmN0aW9uYWxpdHkuXG4gICAgICogQ29tYmluZWQgd2l0aCB7QGxpbmsgT25PYnNlcnZlckJhc2VEaXJlY3RpdmUuc2hvd0ZvciBgc2hvd0ZvcmB9LCB0aGlzIGlzIGdyZWF0IGZvciBkaXNhcHBlYXJpbmcgbWVzc2FnZXMvbm90aWZpY2F0aW9ucy5cbiAgICAgKiBcbiAgICAgKiAjIyMjIFZpZXcgaW5kZXhcbiAgICAgKiBJbiBtdWx0aS12aWV3IG1vZGUsIHRoZSBjb250ZXh0IHdpbGwgY29udGFpbiB0aGUgaW5kZXggb2YgdGhlIHZpZXcsIHdoaWNoIGNhbiBiZSB1c2VkIGZvciBjYWxjdWxhdGlvbnMgYW5kIHN0eWxpbmcuXG4gICAgICovXG4gICAgQElucHV0KCkgcHVibGljIHNldCBvbk9ic2VydmVyRmluYWxpemVkKHZhbHVlOiBPYnNlcnZhYmxlPFQ+KSB7IHRoaXMuaW5wdXQubmV4dCh2YWx1ZSk7IH1cblxuICAgIC8qKlxuICAgICAqIChPcHRpb25hbCkgVGhlIHZpZXcgbW9kZSB0aGUgZGlyZWN0aXZlIHdpbGwgb3BlcmF0ZSBpbjogIFxuICAgICAqIGAnc2luZ2xlJ2AgLSBBIHNpbmdsZSB2aWV3IHdpbGwgYmUgcmVuZGVyZWQgb24gaW50ZXJjZXB0ZWQgY2FsbHMuIElmIGEgdmlldyBoYXMgYWxyZWFkeSBiZWVuIHJlbmRlcmVkIHdoZW4gYSBjYWxsIGlzIGludGVyY2VwdGVkLFxuICAgICAqIHRoZSBleGlzdGluZyB2aWV3IHdpbGwgYmUgdXBkYXRlZCB3aXRoIGRhdGEgZnJvbSB0aGUgbmV3IGNhbGwuXG4gICAgICogXG4gICAgICogYCdtdWx0aXBsZSdgIC0gRXZlcnkgbmV3IGludGVyY2VwdGVkIGNhbGwgd2lsbCByZW5kZXIgYSBuZXcgdmlldyB3aXRoIGl0cyBvd24gY29udGV4dCBhbmQgZGF0YSBlbmNhcHN1bGF0ZWQgZnJvbSB0aGUgY3VycmVudCBjYWxsLlxuICAgICAqIFxuICAgICAqIERlZmF1bHQgaXMgYCdzaW5nbGUnYC5cbiAgICAgKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgc2V0IG9uT2JzZXJ2ZXJGaW5hbGl6ZWRWaWV3TW9kZSAgICAgICAgICh2aWV3TW9kZTogVmlld01vZGUgICAgICAgICAgKSB7IHRoaXMudmlld01vZGUgICAgICAgICAgPSB2aWV3TW9kZTsgfVxuICAgIC8qKlxuICAgICAqIChPcHRpb25hbCkgVGhlIGR1cmF0aW9uIGZvciB3aGljaCB0aGUgZGlyZWN0aXZlIHNob3VsZCB3YWl0IGJlZm9yZSByZW5kZXJpbmcgdGhlIHZpZXcgb25jZSBhbiBpbnRlcmNlcHRlZCBjYWxsIGlzIG1hZGUuXG4gICAgICogXG4gICAgICogWW91IGNhbiBzcGVjaWZ5IGEgbnVtYmVyLCB3aGljaCB3aWxsIGJlIHRyZWF0ZWQgYXMgbWlsbGlzZWNvbmRzLCBvciBhIHN0cmluZyB3aXRoIHRoZSBmb3JtYXQgb2YgYDxudW1iZXI+PG1zIHwgcyB8IG1zPmAuXG4gICAgICogTnVtYmVycyBjYW4gYmUgZWl0aGVyIGludGVnZXJzIG9yIGZsb2F0cy5cbiAgICAgKiBGb3IgZXhhbXBsZTpcbiAgICAgKiAtIGAzMDAwYCAtIFdhaXQgZm9yIDMgc2Vjb25kcywgdGhlbiByZW5kZXIgdGhlIHZpZXcuXG4gICAgICogLSBgJzEwcydgIC0gV2FpdCBmb3IgMTAgc2Vjb25kcywgdGhlbiByZW5kZXIgdGhlIHZpZXcuXG4gICAgICogLSBgJzAuNW0nYCAtIFdhaXQgZm9yIDMwIHNlY29uZHMsIHRoZW4gcmVuZGVyIHRoZSB2aWV3LlxuICAgICAqIC0gYCcxMDBtcydgIC0gV2FpdCBmb3IgMTAwIG1pbGxpc2Vjb25kcywgdGhlbiByZW5kZXIgdGhlIHZpZXcuXG4gICAgICogXG4gICAgICogRGVmYXVsdCBpcyBgMGAsIG1lYW5pbmcgaW1tZWRpYXRlbHkgcmVuZGVyIHRoZSB2aWV3LlxuICAgICAqXG4gICAgICogVE9ETzogQUREIExJTksgVE8gVE9VUiBPUiBGVUxMIFdJS0kgUEFHRVxuICAgICAqIFJlYWQgbW9yZSB7QGxpbmsgT25PYnNlcnZlckJhc2VEaXJlY3RpdmUgQWJvdXQgcmVuZGVyIGZsb3d9LlxuICAgICAqKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgc2V0IG9uT2JzZXJ2ZXJGaW5hbGl6ZWRTaG93QWZ0ZXIgICAgICAgIChkdXJhdGlvbjogRHVyYXRpb25Bbm5vdGF0aW9uKSB7IHRoaXMuc2hvd0FmdGVyICAgICAgICAgPSBkdXJhdGlvbjsgfVxuICAgIC8qKlxuICAgICAqIChPcHRpb25hbCkgVGhlIGR1cmF0aW9uIGZvciB3aGljaCB0aGUgdmlldyBzaG91bGQgYmUgcmVuZGVyZWQuIFdoZW4gdGhlIGR1cmF0aW9uIHBhc3NlcywgdGhlIHZpZXcgd2lsbCBiZSBhdXRvIGRlc3Ryb3llZC5cbiAgICAgKlxuICAgICAqIFlvdSBjYW4gc3BlY2lmeSBhIG51bWJlciwgd2hpY2ggd2lsbCBiZSB0cmVhdGVkIGFzIG1pbGxpc2Vjb25kcywgb3IgYSBzdHJpbmcgd2l0aCB0aGUgZm9ybWF0IG9mIGA8bnVtYmVyPjxtcyB8IHMgfCBtcz5gLlxuICAgICAqIE51bWJlcnMgY2FuIGJlIGVpdGhlciBpbnRlZ2VycyBvciBmbG9hdHMuXG4gICAgICogRm9yIGV4YW1wbGU6XG4gICAgICogLSBgMzAwMGAgLSBUaGUgdmlldyB3aWxsIGJlIGRlc3Ryb3llZCBhZnRlciAzIHNlY29uZHMuXG4gICAgICogLSBgJzEwcydgIC0gVGhlIHZpZXcgd2lsbCBiZSBkZXN0cm95ZWQgYWZ0ZXIgMTAgc2Vjb25kcy5cbiAgICAgKiAtIGAnMC41bSdgIC0gVGhlIHZpZXcgd2lsbCBiZSBkZXN0cm95ZWQgYWZ0ZXIgMzAgc2Vjb25kcy5cbiAgICAgKiAtIGAnMTAwbXMnYCAtIFRoZSB2aWV3IHdpbGwgYmUgZGVzdHJveWVkIGFmdGVyIDEwMCBtaWxsaXNlY29uZHMuXG4gICAgICogXG4gICAgICogRHVyaW5nIHRoZSB0aW1lIHRoZSB2aWV3IGlzIHJlbmRlcmVkLCB0aGUgY29udGV4dCB3aWxsIGJlIHVwZGF0ZWQgd2l0aCBhIGNvdW50ZG93biBvYmplY3QgdG8gZmFjaWxpdGF0ZSBhbnkgVUkgcGFydCB1c2VkIHRvXG4gICAgICogaW5kaWNhdGUgY291bnRkb3duIHRvIHRoZSB1c2VyLiBUaGUgY291bnRkb3duIHdpbGwgYmUgZXhwb3NlZCB0aHJvdWdoIHRoZSB7QGxpbmsgT25PYnNlcnZlckNvbnRleHQucmVtYWluaW5nIGByZW1haW5pbmdgfVxuICAgICAqIHByb3BlcnR5IGFuZCB0aGUgZWxhcHNlZCB0aW1lIHRocm91Z2gge0BsaW5rIE9uT2JzZXJ2ZXJDb250ZXh0LmVsYXBzZWQgYGVsYXBzZWRgfSBwcm9wZXJ0eSBpbiB0aGUgdmlldyBjb250ZXh0IGFuZCBjYW4gYm90aFxuICAgICAqIGJlIGFjY2Vzc2VkIGJlIGRlY2xhcmluZyBhIGBsZXRgIHZhcmlhYmxlIChlLmcuIGBsZXQgcmVtYWluaW5nID0gcmVtYWluaW5nYCkuXG4gICAgICogU2VlIHtAbGluayBPbk9ic2VydmVyQmFzZURpcmVjdGl2ZS5jb3VudGRvd25JbnRlcnZhbCBgY291bnRkb3duSW50ZXJ2YWxgfSBmb3IgY2hhbmdpbmcgdGhlIHVwZGF0ZXMgaW50ZXJ2YWwuXG4gICAgICogXG4gICAgICogV2hlbiB1bnNwZWNpZmllZCwgdGhlIHZpZXcgd2lsbCBiZSBkZXN0cm95ZWQgaW1tZWRpYXRlbHkgb25jZSB0aGUgb2JzZXJ2ZXIgZGV0ZWN0cyBhIGNhbGwgZGlmZmVyZW50IHRvIHRoZSBpbnRlcmNlcHRlZCBvbmVzLlxuICAgICAqIFxuICAgICAqIFRPRE86IEFERCBMSU5LIFRPIFRPVVIgT1IgRlVMTCBXSUtJIFBBR0VcbiAgICAgKiBSZWFkIG1vcmUge0BsaW5rIE9uT2JzZXJ2ZXJCYXNlRGlyZWN0aXZlIEFib3V0IHJlbmRlciBmbG93fS5cbiAgICAgKiovXG4gICAgQElucHV0KCkgcHVibGljIHNldCBvbk9ic2VydmVyRmluYWxpemVkU2hvd0ZvciAgICAgICAgICAoZHVyYXRpb246IER1cmF0aW9uQW5ub3RhdGlvbikgeyB0aGlzLnNob3dGb3IgICAgICAgICAgID0gZHVyYXRpb247IH07XG4gICAgLyoqXG4gICAgICogIyMjIE9ubHkgdXNlZCB3aGVuIHBhc3NpbmcgYSB2YWx1ZSB0byB7QGxpbmsgT25PYnNlcnZlckJhc2VEaXJlY3RpdmUuc2hvd0ZvciBgc2hvd0ZvcmB9LlxuICAgICAqIFxuICAgICAqIChPcHRpb25hbCkgVGhlIGludGVydmFsIHdpdGggd2hpY2ggY291bnRkb3duIHVwZGF0ZXMgc2hvdWxkIGJlIG1hZGUgdG8gdGhlIHZpZXcncyBjb250ZXh0IGJlZm9yZSBpdCBhdXRvIGRlc3Ryb3lzLlxuICAgICAqIFRoZSBsb3dlciB0aGUgdmFsdWUsIHRoZSBtb3JlIHVwZGF0ZXMgd2lsbCBiZSBtYWRlIHRvIHRoZSBjb250ZXh0LCBidXQgdGhlIG1vcmUgcmVzb3VyY2VzIHlvdXIgZGlyZWN0aXZlIHdpbGwgY29uc3VtZS5cbiAgICAgKiBcbiAgICAgKiBZb3UgY2FuIHNwZWNpZnkgYSBudW1iZXIsIHdoaWNoIHdpbGwgYmUgdHJlYXRlZCBhcyBtaWxsaXNlY29uZHMsIG9yIGEgc3RyaW5nIHdpdGggdGhlIGZvcm1hdCBvZiBgPG51bWJlcj48bXMgfCBzIHwgbXM+YC5cbiAgICAgKiBOdW1iZXJzIGNhbiBiZSBlaXRoZXIgaW50ZWdlcnMgb3IgZmxvYXRzLlxuICAgICAqIEZvciBleGFtcGxlOlxuICAgICAqIC0gYDMwMDBgIC0gMyBzZWNvbmRzIGJldHdlZW4gZWFjaCB1cGRhdGUuXG4gICAgICogLSBgJzEwcydgIC0gMTAgc2Vjb25kcyBiZXR3ZWVuIGVhY2ggdXBkYXRlLlxuICAgICAqIC0gYCcwLjVtJ2AgLSAzMCBzZWNvbmRzIGJldHdlZW4gZWFjaCB1cGRhdGUuXG4gICAgICogLSBgJzEwMG1zJ2AgLSAxMDAgbWlsbGlzZWNvbmRzIGJldHdlZW4gZWFjaCB1cGRhdGUuXG4gICAgICogXG4gICAgICogWW91IGNhbiBhbHNvIHNwZWNpZnkgYCdhbmltYXRpb25GcmFtZXMnYCBzbyB0aGUgY291bnRkb3duIGdldHMgdXBkYXRlZCBlYWNoIHRpbWUgdGhlIGJyb3dzZXIgaXMgd29ya2luZyBvbiBhbmltYXRpb25zLlxuICAgICAqIFxuICAgICAqIFdoZW4gdW5zcGVjaWZpZWQsIHRoZSB0b3RhbCBkdXJhdGlvbiBvZiB0aGUgY291bnRkb3duIHdpbGwgYmUgZGl2aWRlZCBieSB7QGxpbmsgRGVmYXVsdENvdW50ZG93blVwZGF0ZUNvdW50IGBEZWZhdWx0Q291bnRkb3duVXBkYXRlQ291bnRgfVxuICAgICAqIHRvIGdldCBhIGZpeGVkIGludGVydmFsIHdoaWNoIHdpbGwgbWFrZSBmb3Ige0BsaW5rIERlZmF1bHRDb3VudGRvd25VcGRhdGVDb3VudCBgRGVmYXVsdENvdW50ZG93blVwZGF0ZUNvdW50YH0gY291bnRkb3duIHVwZGF0ZXMuXG4gICAgICovXG4gICAgQElucHV0KCkgcHVibGljIHNldCBvbk9ic2VydmVyRmluYWxpemVkQ291bnRkb3duSW50ZXJ2YWwoZHVyYXRpb246IER1cmF0aW9uQW5ub3RhdGlvbiB8ICdhbmltYXRpb25GcmFtZXMnKSB7IHRoaXMuY291bnRkb3duSW50ZXJ2YWwgPSBkdXJhdGlvbjsgfTtcbiBcbiAgICBzdGF0aWMgbmdUZW1wbGF0ZUNvbnRleHRHdWFyZDxUPihkaXJlY3RpdmU6IE9uT2JzZXJ2ZXJGaW5hbGl6ZWREaXJlY3RpdmU8VD4sIGNvbnRleHQ6IHVua25vd24pOiBjb250ZXh0IGlzIE9uT2JzZXJ2ZXJDb250ZXh0PFQ+IHsgcmV0dXJuIHRydWU7IH1cbn0iXX0=