ngx-teximate
Version:
Angular text animations component
436 lines (428 loc) • 35 kB
JavaScript
import { __spread, __extends, __assign } from 'tslib';
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
*/
var Teximate = /** @class */ (function () {
function Teximate(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(function (text) { return teximateFactory(text); }));
}
Object.defineProperty(Teximate.prototype, "setText", {
/** Set animated text */
set: /**
* Set animated text
* @param {?} text
* @return {?}
*/
function (text) {
this._state.next(text);
},
enumerable: true,
configurable: true
});
Object.defineProperty(Teximate.prototype, "isPlaying", {
get: /**
* @return {?}
*/
function () {
return this._isPlaying;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Teximate.prototype, "enterPlayer", {
get: /**
* @return {?}
*/
function () {
return this.players.get('enter');
},
enumerable: true,
configurable: true
});
Object.defineProperty(Teximate.prototype, "leavePlayer", {
get: /**
* @return {?}
*/
function () {
return this.players.get('leave');
},
enumerable: true,
configurable: true
});
Object.defineProperty(Teximate.prototype, "defaultPlayer", {
get: /**
* @return {?}
*/
function () {
return this.players.get('default');
},
enumerable: true,
configurable: true
});
/**
* @return {?}
*/
Teximate.prototype.ngAfterViewInit = /**
* @return {?}
*/
function () {
this._isViewInit = true;
this.updateAnimations(true);
};
/**
* @return {?}
*/
Teximate.prototype.ngOnChanges = /**
* @return {?}
*/
function () {
if (this._isViewInit) {
this.updateAnimations();
}
};
/**
* @return {?}
*/
Teximate.prototype.ngOnDestroy = /**
* @return {?}
*/
function () {
// 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
*/
/**
* Register a new animation
* @param {?} config
* @return {?}
*/
Teximate.prototype.registerAnimation = /**
* Register a new animation
* @param {?} config
* @return {?}
*/
function (config) {
var _this = this;
/** @type {?} */
var player = this.buildAnimation(config).create(this.el.nativeElement);
/** TODO: Investigate why onStart and onDone fire only once */
player.onStart(function () {
_this._isPlaying = true;
_this.playEmitter.emit(config.id);
});
player.onDone(function () {
_this._isPlaying = false;
_this.finishEmitter.emit(config.id);
});
return this.players.set(config.id, player).get(config.id);
};
/**
* @param {?=} autoPlayEnter
* @return {?}
*/
Teximate.prototype.updateAnimations = /**
* @param {?=} autoPlayEnter
* @return {?}
*/
function (autoPlayEnter) {
var _this = this;
this.zone.runOutsideAngular(function () {
if (_this.enter) {
/** @type {?} */
var enterPlayer = _this.registerAnimation(__assign({}, _this.enter, { id: 'enter', isEnter: true }));
if (autoPlayEnter) {
enterPlayer.play();
}
}
if (_this.leave) {
_this.registerAnimation(__assign({}, _this.leave, { id: 'leave' }));
}
if (_this.animation) {
_this.registerAnimation(__assign({ id: 'default' }, _this.animation));
}
});
};
/**
* Build animation
*/
/**
* Build animation
* @param {?} config
* @return {?}
*/
Teximate.prototype.buildAnimation = /**
* Build animation
* @param {?} config
* @return {?}
*/
function (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 = function () { return [
{ 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',] }]
};
return Teximate;
}());
/**
* Convert text string into a workable text
* @param {?} text
* @return {?}
*/
function teximateFactory(text) {
/** @type {?} */
var paragraphs = [];
// Split text into paragraphs
text.split('\n').map(function (paragraph) {
/** @type {?} */
var words = [];
// Split paragraph into words
paragraph
.split(' ')
.filter(function (word) { return word !== ''; })
.map(function (word) {
// Split word into letters
return 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
*/
var TeximateEvents = /** @class */ (function () {
function TeximateEvents(element, teximate) {
this.element = element;
this.teximate = teximate;
this.events = Subscription.EMPTY;
this.click = new EventEmitter();
this.hover = new EventEmitter();
}
/**
* @return {?}
*/
TeximateEvents.prototype.ngAfterViewInit = /**
* @return {?}
*/
function () {
var _this = this;
this.events = this.teximate.state.pipe(filter(function () { return !!_this.click.observers.length || !!_this.hover.observers.length; }), switchMap(function () {
/** @type {?} */
var clickEvents = of(null);
/** @type {?} */
var hoverEvents = of(null);
/** @type {?} */
var words = _this.element.nativeElement.querySelectorAll(_this.selector);
if (_this.click.observers.length) {
/** @type {?} */
var events = Array.from(words).map(function (el) { return fromEvent(el, 'click'); });
clickEvents = merge.apply(void 0, __spread(events)).pipe(tap(function (e) { return _this.click.emit(e); }));
}
if (_this.hover.observers.length) {
/** @type {?} */
var events = Array.from(words).map(function (el) { return fromEvent(el, 'mouseenter'); });
hoverEvents = merge.apply(void 0, __spread(events)).pipe(tap(function (e) { return _this.hover.emit(e); }));
}
return merge(clickEvents, hoverEvents);
})).subscribe();
};
/**
* @return {?}
*/
TeximateEvents.prototype.ngOnDestroy = /**
* @return {?}
*/
function () {
this.events.unsubscribe();
};
/** @nocollapse */
TeximateEvents.ctorParameters = function () { return [
{ type: ElementRef },
{ type: Teximate, decorators: [{ type: Inject, args: [forwardRef(function () { return Teximate; }),] }] }
]; };
TeximateEvents.propDecorators = {
click: [{ type: Output, args: ['',] }],
hover: [{ type: Output, args: ['',] }]
};
return TeximateEvents;
}());
var ParagraphEvents = /** @class */ (function (_super) {
__extends(ParagraphEvents, _super);
function ParagraphEvents(element, teximate) {
var _this = _super.call(this, element, teximate) || this;
_this.click = new EventEmitter();
_this.hover = new EventEmitter();
_this.selector = '.teximate-paragraph';
return _this;
}
ParagraphEvents.decorators = [
{ type: Directive, args: [{
selector: 'teximate[paragraphClick], teximate[paragraphHover]'
},] }
];
/** @nocollapse */
ParagraphEvents.ctorParameters = function () { return [
{ type: ElementRef },
{ type: Teximate, decorators: [{ type: Inject, args: [forwardRef(function () { return Teximate; }),] }] }
]; };
ParagraphEvents.propDecorators = {
click: [{ type: Output, args: ['paragraphClick',] }],
hover: [{ type: Output, args: ['paragraphHover',] }]
};
return ParagraphEvents;
}(TeximateEvents));
var WordEvents = /** @class */ (function (_super) {
__extends(WordEvents, _super);
function WordEvents(element, teximate) {
var _this = _super.call(this, element, teximate) || this;
_this.click = new EventEmitter();
_this.hover = new EventEmitter();
_this.selector = '.teximate-word';
return _this;
}
WordEvents.decorators = [
{ type: Directive, args: [{
selector: 'teximate[wordClick], teximate[wordHover]'
},] }
];
/** @nocollapse */
WordEvents.ctorParameters = function () { return [
{ type: ElementRef },
{ type: Teximate, decorators: [{ type: Inject, args: [forwardRef(function () { return Teximate; }),] }] }
]; };
WordEvents.propDecorators = {
click: [{ type: Output, args: ['wordClick',] }],
hover: [{ type: Output, args: ['wordHover',] }]
};
return WordEvents;
}(TeximateEvents));
var LetterEvents = /** @class */ (function (_super) {
__extends(LetterEvents, _super);
function LetterEvents(element, teximate) {
var _this = _super.call(this, element, teximate) || this;
_this.click = new EventEmitter();
_this.hover = new EventEmitter();
_this.selector = '.teximate-letter';
return _this;
}
LetterEvents.decorators = [
{ type: Directive, args: [{
selector: 'teximate[letterClick], teximate[letterHover]'
},] }
];
/** @nocollapse */
LetterEvents.ctorParameters = function () { return [
{ type: ElementRef },
{ type: Teximate, decorators: [{ type: Inject, args: [forwardRef(function () { return Teximate; }),] }] }
]; };
LetterEvents.propDecorators = {
click: [{ type: Output, args: ['letterClick',] }],
hover: [{ type: Output, args: ['letterHover',] }]
};
return LetterEvents;
}(TeximateEvents));
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var TeximateModule = /** @class */ (function () {
function TeximateModule() {
}
TeximateModule.decorators = [
{ type: NgModule, args: [{
imports: [CommonModule],
declarations: [
Teximate,
ParagraphEvents,
WordEvents,
LetterEvents
],
exports: [
Teximate,
ParagraphEvents,
WordEvents,
LetterEvents
]
},] }
];
return TeximateModule;
}());
/**
* @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+IFRleGltYXRlKSkgdGV4aW1hdGU6IFRleGltYXRlKSB7XG4gICAgc3VwZXIoZWxlbWVudCwgdGV4aW1hdGUpO1xuICAgIHRoaXMuc2VsZWN0b3IgPSAnLnRleGltYXRlLWxldHRlcic7XG4gIH1cbn1cbiIsImltcG9ydCB7IE5nTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgVGV4aW1hdGUgfSBmcm9tICcuL3RleGltYXRlJztcbmltcG9ydCB7IFBhcmFncmFwaEV2ZW50cywgV29yZEV2ZW50cywgTGV0dGVyRXZlbnRzIH0gZnJvbSAnLi90ZXhpbWF0ZS1ldmVudHMnO1xuXG5ATmdNb2R1bGUoe1xuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlXSxcbiAgZGVjbGFyYXRpb25zOiBbXG4gICAgVGV4aW1hdGUsXG4gICAgUGFyYWdyYXBoRXZlbnRzLFxuICAgIFdvcmRFdmVudHMsXG4gICAgTGV0dGVyRXZlbnRzXG4gIF0sXG4gIGV4cG9ydHM6IFtcbiAgICBUZXhpbWF0ZSxcbiAgICBQYXJhZ3JhcGhFdmVudHMsXG4gICAgV29yZEV2ZW50cyxcbiAgICBMZXR0ZXJFdmVudHNcbiAgXVxufSlcbmV4cG9ydCBjbGFzcyBUZXhpbWF0ZU1vZHVsZSB7XG59XG4iXSwibmFtZXMiOlsidHNsaWJfMS5fX2V4dGVuZHMiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7OztJQW1GRSxrQkFBb0IsZ0JBQWtDLEVBQVUsSUFBWSxFQUFVLEVBQWM7UUFBaEYscUJBQWdCLEdBQWhCLGdCQUFnQixDQUFrQjtRQUFVLFNBQUksR0FBSixJQUFJLENBQVE7UUFBVSxPQUFFLEdBQUYsRUFBRSxDQUFZOzs7O1FBaENwRixnQkFBVyxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7Ozs7UUFHL0Isa0JBQWEsR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDOzs7O1FBR3JELFlBQU8sR0FBRyxJQUFJLEdBQUcsRUFBMkIsQ0FBQzs7OztRQUdyQyxXQUFNLEdBQUcsSUFBSSxlQUFlLENBQVMsRUFBRSxDQUFDLENBQUM7UUF3Qi9DLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLFVBQUMsSUFBWSxJQUFLLE9BQUEsZUFBZSxDQUFDLElBQUksQ0FBQyxHQUFBLENBQUMsQ0FBQyxDQUFDO0tBQzdFO0lBaERELHNCQUFtQiw2QkFBTzs7Ozs7OztRQUExQixVQUEyQixJQUFZO1lBQ3JDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQ3hCOzs7T0FBQTtJQTRCRCxzQkFBSSwrQkFBUzs7OztRQUFiO1lBQ0UsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDO1NBQ3hCOzs7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