UNPKG

ngx-teximate

Version:
382 lines (374 loc) 31.6 kB
import { Component, Input, Output, NgZone, ElementRef, EventEmitter, ChangeDetectionStrategy, Directive, Inject, forwardRef, NgModule } from '@angular/core'; import { style, query, stagger, useAnimation, AnimationBuilder } from '@angular/animations'; import { BehaviorSubject, Subscription, fromEvent, merge, of } from 'rxjs'; import { map, filter, switchMap, tap } from 'rxjs/operators'; import { CommonModule } from '@angular/common'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ class Teximate { /** * @param {?} animationBuilder * @param {?} zone * @param {?} el */ constructor(animationBuilder, zone, el) { this.animationBuilder = animationBuilder; this.zone = zone; this.el = el; /** * Stream that emits when animation is started */ this.playEmitter = new EventEmitter(); /** * Stream that emits when animation is done */ this.finishEmitter = new EventEmitter(); /** * Teximate animations */ this.players = new Map(); /** * Teximate state */ this._state = new BehaviorSubject(''); this.state = this._state.pipe(map((text) => teximateFactory(text))); } /** * Set animated text * @param {?} text * @return {?} */ set setText(text) { this._state.next(text); } /** * @return {?} */ get isPlaying() { return this._isPlaying; } /** * @return {?} */ get enterPlayer() { return this.players.get('enter'); } /** * @return {?} */ get leavePlayer() { return this.players.get('leave'); } /** * @return {?} */ get defaultPlayer() { return this.players.get('default'); } /** * @return {?} */ ngAfterViewInit() { this._isViewInit = true; this.updateAnimations(true); } /** * @return {?} */ ngOnChanges() { if (this._isViewInit) { this.updateAnimations(); } } /** * @return {?} */ ngOnDestroy() { // TODO: Use players.forEach to destroy players if (this.players.has('enter')) { this.players.get('enter').destroy(); } if (this.players.has('leave')) { this.players.get('leave').destroy(); } if (this.players.has('default')) { this.players.get('default').destroy(); } } /** * Register a new animation * @param {?} config * @return {?} */ registerAnimation(config) { /** @type {?} */ const player = this.buildAnimation(config).create(this.el.nativeElement); /** TODO: Investigate why onStart and onDone fire only once */ player.onStart(() => { this._isPlaying = true; this.playEmitter.emit(config.id); }); player.onDone(() => { this._isPlaying = false; this.finishEmitter.emit(config.id); }); return this.players.set(config.id, player).get(config.id); } /** * @param {?=} autoPlayEnter * @return {?} */ updateAnimations(autoPlayEnter) { this.zone.runOutsideAngular(() => { if (this.enter) { /** @type {?} */ const enterPlayer = this.registerAnimation(Object.assign({}, this.enter, { id: 'enter', isEnter: true })); if (autoPlayEnter) { enterPlayer.play(); } } if (this.leave) { this.registerAnimation(Object.assign({}, this.leave, { id: 'leave' })); } if (this.animation) { this.registerAnimation(Object.assign({ id: 'default' }, this.animation)); } }); } /** * Build animation * @param {?} config * @return {?} */ buildAnimation(config) { /** TODO: Use ':enter' and ':leave' for enter and leave animations */ return this.animationBuilder.build([ query(`.teximate-${config.type}`, [ // This is a workaround for enter animation to work style({ opacity: config.isEnter ? 0 : 1 }), stagger(config.delay, [useAnimation(config.animation)]) ]) ]); } } Teximate.decorators = [ { type: Component, args: [{ selector: 'teximate', host: { 'aria-label': 'text' }, template: "<p *ngFor=\"let paragraph of state | async; index as i\"\r\n class=\"teximate-paragraph teximate-paragraph-{{i}}\">\r\n\r\n <span *ngFor=\"let word of paragraph; index as j\"\r\n class=\"teximate-word teximate-word-{{j}}\">\r\n\r\n <span *ngFor=\"let letter of word; index as k\"\r\n class=\"teximate-letter teximate-letter-{{k}}\">\r\n {{letter}}\r\n </span>\r\n </span>\r\n</p>\r\n", changeDetection: ChangeDetectionStrategy.OnPush, styles: [".teximate-letter,.teximate-word{display:inline-block}.teximate-word{margin-right:8px}"] }] } ]; /** @nocollapse */ Teximate.ctorParameters = () => [ { type: AnimationBuilder }, { type: NgZone }, { type: ElementRef } ]; Teximate.propDecorators = { setText: [{ type: Input, args: ['text',] }], enter: [{ type: Input }], leave: [{ type: Input }], animation: [{ type: Input }], playEmitter: [{ type: Output, args: ['play',] }], finishEmitter: [{ type: Output, args: ['finish',] }] }; /** * Convert text string into a workable text * @param {?} text * @return {?} */ function teximateFactory(text) { /** @type {?} */ const paragraphs = []; // Split text into paragraphs text.split('\n').map((paragraph) => { /** @type {?} */ const words = []; // Split paragraph into words paragraph .split(' ') .filter(word => word !== '') .map((word) => // Split word into letters words.push(word.split(/(?!$)/u))); paragraphs.push(words); }); return paragraphs; } /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ class TeximateEvents { /** * @param {?} element * @param {?} teximate */ constructor(element, teximate) { this.element = element; this.teximate = teximate; this.events = Subscription.EMPTY; this.click = new EventEmitter(); this.hover = new EventEmitter(); } /** * @return {?} */ ngAfterViewInit() { this.events = this.teximate.state.pipe(filter(() => !!this.click.observers.length || !!this.hover.observers.length), switchMap(() => { /** @type {?} */ let clickEvents = of(null); /** @type {?} */ let hoverEvents = of(null); /** @type {?} */ const words = this.element.nativeElement.querySelectorAll(this.selector); if (this.click.observers.length) { /** @type {?} */ const events = Array.from(words).map((el) => fromEvent(el, 'click')); clickEvents = merge(...events).pipe(tap(e => this.click.emit(e))); } if (this.hover.observers.length) { /** @type {?} */ const events = Array.from(words).map((el) => fromEvent(el, 'mouseenter')); hoverEvents = merge(...events).pipe(tap(e => this.hover.emit(e))); } return merge(clickEvents, hoverEvents); })).subscribe(); } /** * @return {?} */ ngOnDestroy() { this.events.unsubscribe(); } } /** @nocollapse */ TeximateEvents.ctorParameters = () => [ { type: ElementRef }, { type: Teximate, decorators: [{ type: Inject, args: [forwardRef(() => Teximate),] }] } ]; TeximateEvents.propDecorators = { click: [{ type: Output, args: ['',] }], hover: [{ type: Output, args: ['',] }] }; class ParagraphEvents extends TeximateEvents { /** * @param {?} element * @param {?} teximate */ constructor(element, teximate) { super(element, teximate); this.click = new EventEmitter(); this.hover = new EventEmitter(); this.selector = '.teximate-paragraph'; } } ParagraphEvents.decorators = [ { type: Directive, args: [{ selector: 'teximate[paragraphClick], teximate[paragraphHover]' },] } ]; /** @nocollapse */ ParagraphEvents.ctorParameters = () => [ { type: ElementRef }, { type: Teximate, decorators: [{ type: Inject, args: [forwardRef(() => Teximate),] }] } ]; ParagraphEvents.propDecorators = { click: [{ type: Output, args: ['paragraphClick',] }], hover: [{ type: Output, args: ['paragraphHover',] }] }; class WordEvents extends TeximateEvents { /** * @param {?} element * @param {?} teximate */ constructor(element, teximate) { super(element, teximate); this.click = new EventEmitter(); this.hover = new EventEmitter(); this.selector = '.teximate-word'; } } WordEvents.decorators = [ { type: Directive, args: [{ selector: 'teximate[wordClick], teximate[wordHover]' },] } ]; /** @nocollapse */ WordEvents.ctorParameters = () => [ { type: ElementRef }, { type: Teximate, decorators: [{ type: Inject, args: [forwardRef(() => Teximate),] }] } ]; WordEvents.propDecorators = { click: [{ type: Output, args: ['wordClick',] }], hover: [{ type: Output, args: ['wordHover',] }] }; class LetterEvents extends TeximateEvents { /** * @param {?} element * @param {?} teximate */ constructor(element, teximate) { super(element, teximate); this.click = new EventEmitter(); this.hover = new EventEmitter(); this.selector = '.teximate-letter'; } } LetterEvents.decorators = [ { type: Directive, args: [{ selector: 'teximate[letterClick], teximate[letterHover]' },] } ]; /** @nocollapse */ LetterEvents.ctorParameters = () => [ { type: ElementRef }, { type: Teximate, decorators: [{ type: Inject, args: [forwardRef(() => Teximate),] }] } ]; LetterEvents.propDecorators = { click: [{ type: Output, args: ['letterClick',] }], hover: [{ type: Output, args: ['letterHover',] }] }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ class TeximateModule { } TeximateModule.decorators = [ { type: NgModule, args: [{ imports: [CommonModule], declarations: [ Teximate, ParagraphEvents, WordEvents, LetterEvents ], exports: [ Teximate, ParagraphEvents, WordEvents, LetterEvents ] },] } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ export { teximateFactory, Teximate, TeximateModule, LetterEvents as ɵd, ParagraphEvents as ɵb, TeximateEvents as ɵa, WordEvents as ɵc }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LXRleGltYXRlLmpzLm1hcCIsInNvdXJjZXMiOlsibmc6Ly9uZ3gtdGV4aW1hdGUvbGliL3RleGltYXRlLnRzIiwibmc6Ly9uZ3gtdGV4aW1hdGUvbGliL3RleGltYXRlLWV2ZW50cy50cyIsIm5nOi8vbmd4LXRleGltYXRlL2xpYi90ZXhpbWF0ZS5tb2R1bGUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ29tcG9uZW50LFxuICBJbnB1dCxcbiAgT3V0cHV0LFxuICBBZnRlclZpZXdJbml0LFxuICBPbkNoYW5nZXMsXG4gIE9uRGVzdHJveSxcbiAgTmdab25lLFxuICBFbGVtZW50UmVmLFxuICBFdmVudEVtaXR0ZXIsXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5XG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgc3R5bGUsXG4gIHF1ZXJ5LFxuICBzdGFnZ2VyLFxuICB1c2VBbmltYXRpb24sXG4gIEFuaW1hdGlvblBsYXllcixcbiAgQW5pbWF0aW9uQnVpbGRlcixcbiAgQW5pbWF0aW9uRmFjdG9yeVxufSBmcm9tICdAYW5ndWxhci9hbmltYXRpb25zJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgbWFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgVGV4dEFuaW1hdGlvbiB9IGZyb20gJy4vdGV4aW1hdGUubW9kZWwnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICd0ZXhpbWF0ZScsXG4gIGhvc3Q6IHtcbiAgICAnYXJpYS1sYWJlbCc6ICd0ZXh0J1xuICB9LFxuICB0ZW1wbGF0ZVVybDogJy4vdGV4aW1hdGUuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3RleGltYXRlLnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2hcbn0pXG5leHBvcnQgY2xhc3MgVGV4aW1hdGUgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSB7XG5cbiAgLyoqIFNldCBhbmltYXRlZCB0ZXh0ICovXG4gIEBJbnB1dCgndGV4dCcpIHNldCBzZXRUZXh0KHRleHQ6IHN0cmluZykge1xuICAgIHRoaXMuX3N0YXRlLm5leHQodGV4dCk7XG4gIH1cblxuICAvKiogQW5pbWF0aW9uIHRoYXQgdHJpZ2dlcnMgb24gaW5pdCAqL1xuICBASW5wdXQoKSBlbnRlcjogVGV4dEFuaW1hdGlvbjtcblxuICAvKiogQW5pbWF0aW9uIHRoYXQgdHJpZ2dlcnMgb24gZGVzdHJveSAqL1xuICBASW5wdXQoKSBsZWF2ZTogVGV4dEFuaW1hdGlvbjtcblxuICAvKiogQW5pbWF0aW9uIHRoYXQgdHJpZ2dlcnMgd2l0aCB0aGUgcGxheSgpIGZ1bmN0aW9uICovXG4gIEBJbnB1dCgpIGFuaW1hdGlvbjogVGV4dEFuaW1hdGlvbjtcblxuICAvKiogU3RyZWFtIHRoYXQgZW1pdHMgd2hlbiBhbmltYXRpb24gaXMgc3RhcnRlZCAqL1xuICBAT3V0cHV0KCdwbGF5JykgcGxheUVtaXR0ZXIgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgLyoqIFN0cmVhbSB0aGF0IGVtaXRzIHdoZW4gYW5pbWF0aW9uIGlzIGRvbmUgKi9cbiAgQE91dHB1dCgnZmluaXNoJykgZmluaXNoRW1pdHRlciA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICAvKiogVGV4aW1hdGUgYW5pbWF0aW9ucyAqL1xuICBwbGF5ZXJzID0gbmV3IE1hcDxzdHJpbmcsIEFuaW1hdGlvblBsYXllcj4oKTtcblxuICAvKiogVGV4aW1hdGUgc3RhdGUgKi9cbiAgcHJpdmF0ZSBfc3RhdGUgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PHN0cmluZz4oJycpO1xuICBzdGF0ZTogT2JzZXJ2YWJsZTxzdHJpbmdbXVtdW10+O1xuXG4gIC8qKiBUZXhpbWF0ZSBwbGF5aW5nIHN0YXRlICovXG4gIHByaXZhdGUgX2lzUGxheWluZzogYm9vbGVhbjtcbiAgcHJpdmF0ZSBfaXNWaWV3SW5pdDogYm9vbGVhbjtcblxuICBnZXQgaXNQbGF5aW5nKCkge1xuICAgIHJldHVybiB0aGlzLl9pc1BsYXlpbmc7XG4gIH1cblxuICBnZXQgZW50ZXJQbGF5ZXIoKTogQW5pbWF0aW9uUGxheWVyIHtcbiAgICByZXR1cm4gdGhpcy5wbGF5ZXJzLmdldCgnZW50ZXInKTtcbiAgfVxuXG4gIGdldCBsZWF2ZVBsYXllcigpOiBBbmltYXRpb25QbGF5ZXIge1xuICAgIHJldHVybiB0aGlzLnBsYXllcnMuZ2V0KCdsZWF2ZScpO1xuICB9XG5cbiAgZ2V0IGRlZmF1bHRQbGF5ZXIoKTogQW5pbWF0aW9uUGxheWVyIHtcbiAgICByZXR1cm4gdGhpcy5wbGF5ZXJzLmdldCgnZGVmYXVsdCcpO1xuICB9XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBhbmltYXRpb25CdWlsZGVyOiBBbmltYXRpb25CdWlsZGVyLCBwcml2YXRlIHpvbmU6IE5nWm9uZSwgcHJpdmF0ZSBlbDogRWxlbWVudFJlZikge1xuICAgIHRoaXMuc3RhdGUgPSB0aGlzLl9zdGF0ZS5waXBlKG1hcCgodGV4dDogc3RyaW5nKSA9PiB0ZXhpbWF0ZUZhY3RvcnkodGV4dCkpKTtcbiAgfVxuXG4gIG5nQWZ0ZXJWaWV3SW5pdCgpIHtcbiAgICB0aGlzLl9pc1ZpZXdJbml0ID0gdHJ1ZTtcbiAgICB0aGlzLnVwZGF0ZUFuaW1hdGlvbnModHJ1ZSk7XG4gIH1cblxuICBuZ09uQ2hhbmdlcygpIHtcbiAgICBpZiAodGhpcy5faXNWaWV3SW5pdCkge1xuICAgICAgdGhpcy51cGRhdGVBbmltYXRpb25zKCk7XG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgLy8gVE9ETzogVXNlIHBsYXllcnMuZm9yRWFjaCB0byBkZXN0cm95IHBsYXllcnNcbiAgICBpZiAodGhpcy5wbGF5ZXJzLmhhcygnZW50ZXInKSkge1xuICAgICAgdGhpcy5wbGF5ZXJzLmdldCgnZW50ZXInKS5kZXN0cm95KCk7XG4gICAgfVxuICAgIGlmICh0aGlzLnBsYXllcnMuaGFzKCdsZWF2ZScpKSB7XG4gICAgICB0aGlzLnBsYXllcnMuZ2V0KCdsZWF2ZScpLmRlc3Ryb3koKTtcbiAgICB9XG4gICAgaWYgKHRoaXMucGxheWVycy5oYXMoJ2RlZmF1bHQnKSkge1xuICAgICAgdGhpcy5wbGF5ZXJzLmdldCgnZGVmYXVsdCcpLmRlc3Ryb3koKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVnaXN0ZXIgYSBuZXcgYW5pbWF0aW9uXG4gICAqL1xuICByZWdpc3RlckFuaW1hdGlvbihjb25maWc6IFRleHRBbmltYXRpb24pOiBBbmltYXRpb25QbGF5ZXIge1xuICAgIGNvbnN0IHBsYXllciA9IHRoaXMuYnVpbGRBbmltYXRpb24oY29uZmlnKS5jcmVhdGUodGhpcy5lbC5uYXRpdmVFbGVtZW50KTtcbiAgICAvKiogVE9ETzogSW52ZXN0aWdhdGUgd2h5IG9uU3RhcnQgYW5kIG9uRG9uZSBmaXJlIG9ubHkgb25jZSAqL1xuICAgIHBsYXllci5vblN0YXJ0KCgpID0+IHtcbiAgICAgIHRoaXMuX2lzUGxheWluZyA9IHRydWU7XG4gICAgICB0aGlzLnBsYXlFbWl0dGVyLmVtaXQoY29uZmlnLmlkKTtcbiAgICB9KTtcbiAgICBwbGF5ZXIub25Eb25lKCgpID0+IHtcbiAgICAgIHRoaXMuX2lzUGxheWluZyA9IGZhbHNlO1xuICAgICAgdGhpcy5maW5pc2hFbWl0dGVyLmVtaXQoY29uZmlnLmlkKTtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcy5wbGF5ZXJzLnNldChjb25maWcuaWQsIHBsYXllcikuZ2V0KGNvbmZpZy5pZCk7XG4gIH1cblxuICBwcml2YXRlIHVwZGF0ZUFuaW1hdGlvbnMoYXV0b1BsYXlFbnRlcj86IGJvb2xlYW4pIHtcbiAgICB0aGlzLnpvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xuICAgICAgaWYgKHRoaXMuZW50ZXIpIHtcbiAgICAgICAgY29uc3QgZW50ZXJQbGF5ZXIgPSB0aGlzLnJlZ2lzdGVyQW5pbWF0aW9uKHsuLi50aGlzLmVudGVyLCBpZDogJ2VudGVyJywgaXNFbnRlcjogdHJ1ZX0pO1xuICAgICAgICBpZiAoYXV0b1BsYXlFbnRlcikge1xuICAgICAgICAgIGVudGVyUGxheWVyLnBsYXkoKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKHRoaXMubGVhdmUpIHtcbiAgICAgICAgdGhpcy5yZWdpc3RlckFuaW1hdGlvbih7Li4udGhpcy5sZWF2ZSwgaWQ6ICdsZWF2ZSd9KTtcbiAgICAgIH1cbiAgICAgIGlmICh0aGlzLmFuaW1hdGlvbikge1xuICAgICAgICB0aGlzLnJlZ2lzdGVyQW5pbWF0aW9uKHtpZDogJ2RlZmF1bHQnLCAuLi50aGlzLmFuaW1hdGlvbn0pO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkIGFuaW1hdGlvblxuICAgKi9cbiAgcHJpdmF0ZSBidWlsZEFuaW1hdGlvbihjb25maWc6IFRleHRBbmltYXRpb24pOiBBbmltYXRpb25GYWN0b3J5IHtcbiAgICAvKiogVE9ETzogVXNlICc6ZW50ZXInIGFuZCAnOmxlYXZlJyBmb3IgZW50ZXIgYW5kIGxlYXZlIGFuaW1hdGlvbnMgKi9cbiAgICByZXR1cm4gdGhpcy5hbmltYXRpb25CdWlsZGVyLmJ1aWxkKFtcbiAgICAgIHF1ZXJ5KFxuICAgICAgICBgLnRleGltYXRlLSR7Y29uZmlnLnR5cGV9YCxcbiAgICAgICAgW1xuICAgICAgICAgIC8vIFRoaXMgaXMgYSB3b3JrYXJvdW5kIGZvciBlbnRlciBhbmltYXRpb24gdG8gd29ya1xuICAgICAgICAgIHN0eWxlKHtvcGFjaXR5OiBjb25maWcuaXNFbnRlciA/IDAgOiAxfSksXG4gICAgICAgICAgc3RhZ2dlcihjb25maWcuZGVsYXksIFt1c2VBbmltYXRpb24oY29uZmlnLmFuaW1hdGlvbildKVxuICAgICAgICBdXG4gICAgICApXG4gICAgXSk7XG4gIH1cbn1cblxuLyoqIENvbnZlcnQgdGV4dCBzdHJpbmcgaW50byBhIHdvcmthYmxlIHRleHQgKi9cbmV4cG9ydCBmdW5jdGlvbiB0ZXhpbWF0ZUZhY3RvcnkodGV4dDogc3RyaW5nKTogc3RyaW5nW11bXVtdIHtcbiAgY29uc3QgcGFyYWdyYXBoczogc3RyaW5nW11bXVtdID0gW107XG4gIC8vIFNwbGl0IHRleHQgaW50byBwYXJhZ3JhcGhzXG4gIHRleHQuc3BsaXQoJ1xcbicpLm1hcCgocGFyYWdyYXBoOiBzdHJpbmcpID0+IHtcbiAgICBjb25zdCB3b3Jkczogc3RyaW5nW11bXSA9IFtdO1xuICAgIC8vIFNwbGl0IHBhcmFncmFwaCBpbnRvIHdvcmRzXG4gICAgcGFyYWdyYXBoXG4gICAgICAuc3BsaXQoJyAnKVxuICAgICAgLmZpbHRlcih3b3JkID0+IHdvcmQgIT09ICcnKVxuICAgICAgLm1hcCgod29yZDogc3RyaW5nKSA9PlxuICAgICAgICAvLyBTcGxpdCB3b3JkIGludG8gbGV0dGVyc1xuICAgICAgICB3b3Jkcy5wdXNoKHdvcmQuc3BsaXQoLyg/ISQpL3UpKVxuICAgICAgKTtcbiAgICBwYXJhZ3JhcGhzLnB1c2god29yZHMpO1xuICB9KTtcbiAgcmV0dXJuIHBhcmFncmFwaHM7XG59XG4iLCJpbXBvcnQgeyBEaXJlY3RpdmUsIE91dHB1dCwgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95LCBJbmplY3QsIEVsZW1lbnRSZWYsIEV2ZW50RW1pdHRlciwgZm9yd2FyZFJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgU3Vic2NyaXB0aW9uLCBmcm9tRXZlbnQsIG1lcmdlLCBTdWJzY3JpcHRpb25MaWtlLCBvZiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZmlsdGVyLCBzd2l0Y2hNYXAsIHRhcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IFRleGltYXRlIH0gZnJvbSAnLi90ZXhpbWF0ZSc7XG5cbmV4cG9ydCBjbGFzcyBUZXhpbWF0ZUV2ZW50cyBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveSB7XG5cbiAgc2VsZWN0b3I6IHN0cmluZztcbiAgZXZlbnRzOiBTdWJzY3JpcHRpb25MaWtlID0gU3Vic2NyaXB0aW9uLkVNUFRZO1xuICBAT3V0cHV0KCcnKSBjbGljayA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgQE91dHB1dCgnJykgaG92ZXIgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgY29uc3RydWN0b3IocHVibGljIGVsZW1lbnQ6IEVsZW1lbnRSZWYsIEBJbmplY3QoZm9yd2FyZFJlZigoKSA9PiBUZXhpbWF0ZSkpIHB1YmxpYyB0ZXhpbWF0ZTogVGV4aW1hdGUpIHtcbiAgfVxuXG4gIG5nQWZ0ZXJWaWV3SW5pdCgpIHtcbiAgICB0aGlzLmV2ZW50cyA9IHRoaXMudGV4aW1hdGUuc3RhdGUucGlwZShcbiAgICAgIGZpbHRlcigoKSA9PiAhIXRoaXMuY2xpY2sub2JzZXJ2ZXJzLmxlbmd0aCB8fCAhIXRoaXMuaG92ZXIub2JzZXJ2ZXJzLmxlbmd0aCksXG4gICAgICBzd2l0Y2hNYXAoKCkgPT4ge1xuICAgICAgICBsZXQgY2xpY2tFdmVudHMgPSBvZihudWxsKTtcbiAgICAgICAgbGV0IGhvdmVyRXZlbnRzID0gb2YobnVsbCk7XG4gICAgICAgIGNvbnN0IHdvcmRzID0gdGhpcy5lbGVtZW50Lm5hdGl2ZUVsZW1lbnQucXVlcnlTZWxlY3RvckFsbCh0aGlzLnNlbGVjdG9yKTtcbiAgICAgICAgaWYgKHRoaXMuY2xpY2sub2JzZXJ2ZXJzLmxlbmd0aCkge1xuICAgICAgICAgIGNvbnN0IGV2ZW50cyA9IEFycmF5LmZyb20od29yZHMpLm1hcCgoZWw6IEhUTUxFbGVtZW50KSA9PiBmcm9tRXZlbnQoZWwsICdjbGljaycpKTtcbiAgICAgICAgICBjbGlja0V2ZW50cyA9IG1lcmdlKC4uLmV2ZW50cykucGlwZSh0YXAoZSA9PiB0aGlzLmNsaWNrLmVtaXQoZSkpKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5ob3Zlci5vYnNlcnZlcnMubGVuZ3RoKSB7XG4gICAgICAgICAgY29uc3QgZXZlbnRzID0gQXJyYXkuZnJvbSh3b3JkcykubWFwKChlbDogSFRNTEVsZW1lbnQpID0+IGZyb21FdmVudChlbCwgJ21vdXNlZW50ZXInKSk7XG4gICAgICAgICAgaG92ZXJFdmVudHMgPSBtZXJnZSguLi5ldmVudHMpLnBpcGUodGFwKGUgPT4gdGhpcy5ob3Zlci5lbWl0KGUpKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG1lcmdlKGNsaWNrRXZlbnRzLCBob3ZlckV2ZW50cyk7XG4gICAgICB9KVxuICAgICkuc3Vic2NyaWJlKCk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpIHtcbiAgICB0aGlzLmV2ZW50cy51bnN1YnNjcmliZSgpO1xuICB9XG5cbn1cblxuQERpcmVjdGl2ZSh7XG4gIHNlbGVjdG9yOiAndGV4aW1hdGVbcGFyYWdyYXBoQ2xpY2tdLCB0ZXhpbWF0ZVtwYXJhZ3JhcGhIb3Zlcl0nXG59KVxuZXhwb3J0IGNsYXNzIFBhcmFncmFwaEV2ZW50cyBleHRlbmRzIFRleGltYXRlRXZlbnRzIHtcbiAgQE91dHB1dCgncGFyYWdyYXBoQ2xpY2snKSBjbGljayA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgQE91dHB1dCgncGFyYWdyYXBoSG92ZXInKSBob3ZlciA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICBjb25zdHJ1Y3RvcihlbGVtZW50OiBFbGVtZW50UmVmLCBASW5qZWN0KGZvcndhcmRSZWYoKCkgPT4gVGV4aW1hdGUpKSB0ZXhpbWF0ZTogVGV4aW1hdGUpIHtcbiAgICBzdXBlcihlbGVtZW50LCB0ZXhpbWF0ZSk7XG4gICAgdGhpcy5zZWxlY3RvciA9ICcudGV4aW1hdGUtcGFyYWdyYXBoJztcbiAgfVxufVxuXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICd0ZXhpbWF0ZVt3b3JkQ2xpY2tdLCB0ZXhpbWF0ZVt3b3JkSG92ZXJdJ1xufSlcbmV4cG9ydCBjbGFzcyBXb3JkRXZlbnRzIGV4dGVuZHMgVGV4aW1hdGVFdmVudHMge1xuICBAT3V0cHV0KCd3b3JkQ2xpY2snKSBjbGljayA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgQE91dHB1dCgnd29yZEhvdmVyJykgaG92ZXIgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgY29uc3RydWN0b3IoZWxlbWVudDogRWxlbWVudFJlZiwgQEluamVjdChmb3J3YXJkUmVmKCgpID0+IFRleGltYXRlKSkgdGV4aW1hdGU6IFRleGltYXRlKSB7XG4gICAgc3VwZXIoZWxlbWVudCwgdGV4aW1hdGUpO1xuICAgIHRoaXMuc2VsZWN0b3IgPSAnLnRleGltYXRlLXdvcmQnO1xuICB9XG59XG5cbkBEaXJlY3RpdmUoe1xuICBzZWxlY3RvcjogJ3RleGltYXRlW2xldHRlckNsaWNrXSwgdGV4aW1hdGVbbGV0dGVySG92ZXJdJ1xufSlcbmV4cG9ydCBjbGFzcyBMZXR0ZXJFdmVudHMgZXh0ZW5kcyBUZXhpbWF0ZUV2ZW50cyB7XG4gIEBPdXRwdXQoJ2xldHRlckNsaWNrJykgY2xpY2sgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gIEBPdXRwdXQoJ2xldHRlckhvdmVyJykgaG92ZXIgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgY29uc3RydWN0b3IoZWxlbWVudDogRWxlbWVudFJlZiwgQEluamVjdChmb3J3YXJkUmVmKCgpID0+IFRleGltYXRlKSkgdGV4aW1hdGU6IFRleGltYXRlKSB7XG4gICAgc3VwZXIoZWxlbWVudCwgdGV4aW1hdGUpO1xuICAgIHRoaXMuc2VsZWN0b3IgPSAnLnRleGltYXRlLWxldHRlcic7XG4gIH1cbn1cbiIsImltcG9ydCB7IE5nTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgVGV4aW1hdGUgfSBmcm9tICcuL3RleGltYXRlJztcbmltcG9ydCB7IFBhcmFncmFwaEV2ZW50cywgV29yZEV2ZW50cywgTGV0dGVyRXZlbnRzIH0gZnJvbSAnLi90ZXhpbWF0ZS1ldmVudHMnO1xuXG5ATmdNb2R1bGUoe1xuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlXSxcbiAgZGVjbGFyYXRpb25zOiBbXG4gICAgVGV4aW1hdGUsXG4gICAgUGFyYWdyYXBoRXZlbnRzLFxuICAgIFdvcmRFdmVudHMsXG4gICAgTGV0dGVyRXZlbnRzXG4gIF0sXG4gIGV4cG9ydHM6IFtcbiAgICBUZXhpbWF0ZSxcbiAgICBQYXJhZ3JhcGhFdmVudHMsXG4gICAgV29yZEV2ZW50cyxcbiAgICBMZXR0ZXJFdmVudHNcbiAgXVxufSlcbmV4cG9ydCBjbGFzcyBUZXhpbWF0ZU1vZHVsZSB7XG59XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7OztBQUFBLE1Ba0NhLFFBQVE7Ozs7OztJQWlEbkIsWUFBb0IsZ0JBQWtDLEVBQVUsSUFBWSxFQUFVLEVBQWM7UUFBaEYscUJBQWdCLEdBQWhCLGdCQUFnQixDQUFrQjtRQUFVLFNBQUksR0FBSixJQUFJLENBQVE7UUFBVSxPQUFFLEdBQUYsRUFBRSxDQUFZOzs7O1FBaENwRixnQkFBVyxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7Ozs7UUFHL0Isa0JBQWEsR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDOzs7O1FBR3JELFlBQU8sR0FBRyxJQUFJLEdBQUcsRUFBMkIsQ0FBQzs7OztRQUdyQyxXQUFNLEdBQUcsSUFBSSxlQUFlLENBQVMsRUFBRSxDQUFDLENBQUM7UUF3Qi9DLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBWSxLQUFLLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7S0FDN0U7Ozs7OztJQWhERCxJQUFtQixPQUFPLENBQUMsSUFBWTtRQUNyQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztLQUN4Qjs7OztJQTRCRCxJQUFJLFNBQVM7UUFDWCxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUM7S0FDeEI7Ozs7SUFFRCxJQUFJLFdBQVc7UUFDYixPQUFPLElBQUksQ0FB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