@ciri/ngx-carousel
Version:
A simple angular carousel component.
520 lines • 39.4 kB
JavaScript
/**
* @fileoverview added by tsickle
* Generated from: lib/carousel/carousel.component.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChildren, ElementRef, EventEmitter, forwardRef, Input, Output, QueryList, Renderer2, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core';
import { BehaviorSubject, interval, Subject, timer } from 'rxjs';
import { debounceTime, distinctUntilChanged, filter, skip, startWith, takeUntil } from 'rxjs/operators';
import { animationFrame } from 'rxjs/internal/scheduler/animationFrame';
import { CarouselItemComponent } from '../carousel-item/carousel-item.component';
import { CAROUSEL, clamp, inRange } from '../../utils';
export class CarouselComponent {
// 后镜像节点
/**
* @param {?} renderer
* @param {?} hostElRef
* @param {?} cdr
*/
constructor(renderer, hostElRef, cdr) {
this.renderer = renderer;
this.hostElRef = hostElRef;
this.cdr = cdr;
/**
* 是否开启无缝模式
*/
this.loop = false;
/**
* 切换速度(ms)
*/
this.speed = 300;
/**
* 自动轮播时间间隔,0 代表关闭自动轮播
*/
this.autoplay = 0;
/**
* 是否跟随手指滑动,设为 false 代表只在松手后进行移动判断
*/
this.followFinger = true;
/**
* 是否允许手动滑动,设为 false 代表只能通过 api 翻页
*/
this.allowTouchMove = true;
/**
* 默认激活项
*/
this.initialIndex = 0;
/**
* lazyRender 模式下预渲染个数,1 代表左右多渲染一个,2 代表左右多渲染两个,...
*/
this.lazyRenderOffset = 0;
/**
* 是否缓存 lazyRender 模式下渲染过的 item,不从 dom 树中删除
*/
this.cache = false;
/**
* 索引变动时触发
*/
this.indexChange = new EventEmitter();
this.active$ = new BehaviorSubject(null);
this.destroy$ = new Subject();
this.percent = 0; // 手指滑动距离所占宽度总和百分比
// 手指滑动距离所占宽度总和百分比
this.offset = 0; // 偏移量(%)
// 偏移量(%)
this.animating = false; // 是否处于过渡效果中
}
/**
* @return {?}
*/
get active() {
return this.active$.value;
}
/**
* @return {?}
*/
get count() {
return (this.items || []).length;
}
/**
* @return {?}
*/
get viewport() {
return this.hostElRef.nativeElement;
}
/**
* @return {?}
*/
get width() {
return this.viewport.offsetWidth;
}
/**
* @return {?}
*/
get canMove() {
return this.allowTouchMove && !this.animating;
}
/**
* @return {?}
*/
get data() {
return {
active: this.active,
count: this.count,
offset: this.offset,
animating: this.animating,
atFirst: this.active === 0,
atLast: this.active === this.count - 1
};
}
/**
* @return {?}
*/
ngOnInit() { }
/**
* @return {?}
*/
ngAfterViewInit() {
this.items.changes
.pipe(takeUntil(this.destroy$), startWith(null), debounceTime(0, animationFrame))
.subscribe((/**
* @return {?}
*/
() => {
this.init();
}));
this.active$
.pipe(takeUntil(this.destroy$), skip(1), filter((/**
* @param {?} v
* @return {?}
*/
v => v !== null && inRange(v, 0, this.count - 1))), distinctUntilChanged())
.subscribe((/**
* @param {?} res
* @return {?}
*/
res => {
this.indexChange.emit(res);
this.cdr.markForCheck();
}));
// resize 功能待开发
// resize(this.viewport)
// .pipe(takeUntil(this.destroy$), debounceTime(0, animationFrame))
// .subscribe(() => {
// // this.updateWidth()
// // this.goTo(this.active, true)
// })
}
/**
* @return {?}
*/
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
/**
* @param {?} e
* @return {?}
*/
onPanStart(e) {
this.stopAutoplay();
}
/**
* @param {?} e
* @return {?}
*/
onPanMove(e) {
if (!this.canMove) {
return;
}
/** @type {?} */
const deltaX = this.getSafeDeltaX(e.deltaX);
this.percent = ((100 / this.count) * deltaX) / this.width;
if (this.followFinger) {
/** @type {?} */
const offset = this.percent - (100 / this.count) * this.active;
this.move(offset, true);
}
}
/**
* @param {?} e
* @return {?}
*/
onPanEnd(e) {
if (!this.canMove) {
return;
}
// 轻拂或者滑动距离大于等于一个节点宽度的 50% 才进行跳转
/** @type {?} */
let newActive = this.active;
/** @type {?} */
const isSwipeLeft = e.direction === Hammer.DIRECTION_LEFT && e.velocityX < -0.3;
/** @type {?} */
const isSwipeRight = e.direction === Hammer.DIRECTION_RIGHT && e.velocityX > 0.3;
if (isSwipeLeft || this.percent <= -50 / this.count) {
newActive++;
}
else if (isSwipeRight || this.percent >= 50 / this.count) {
newActive--;
}
this.goTo(newActive);
this.startAutoplay();
}
/**
* @param {?=} target
* @param {?=} immediate
* @return {?}
*/
goTo(target = 0, immediate = false) {
if (this.animating) {
return;
}
/** @type {?} */
const active = this.getSafeActive(target);
/** @type {?} */
const realActive = this.getRealActive(active);
this.active$.next(realActive);
// 到达第一个或最后一个时更新镜像节点
if (this.loop && (realActive === 0 || realActive === this.count - 1)) {
this.handleMirrorNodes();
}
this.animating = true;
this.move(-(100 / this.count) * active, immediate).subscribe((/**
* @return {?}
*/
() => {
this.animating = false;
if (active === -1 || active === this.count) {
this.goTo(realActive, true);
}
}));
}
/**
* @return {?}
*/
prev() {
this.goTo(this.active - 1);
}
/**
* @return {?}
*/
next() {
this.goTo(this.active + 1);
}
/**
* @private
* @return {?}
*/
init() {
if (this.items.length === 0) {
return;
}
this.items.forEach((/**
* @param {?} el
* @param {?} index
* @return {?}
*/
(el, index) => {
el.index = index;
this.renderer.setStyle(el.elRef.nativeElement, 'width', `${this.width}px`);
}));
this.goTo(this.getSafeActive(this.initialIndex, true), true);
this.startAutoplay();
}
/**
* @private
* @param {?} deltaX
* @return {?}
*/
getSafeDeltaX(deltaX) {
/** @type {?} */
const w = this.width;
return clamp(deltaX, -w, w);
}
/**
* @private
* @param {?} active
* @param {?=} strict
* @return {?}
*/
getSafeActive(active, strict = false) {
/** @type {?} */
const min = this.loop && !strict ? -1 : 0;
/** @type {?} */
const max = this.loop && !strict ? this.count : this.count - 1;
return clamp(active, min, max);
}
// 计算真实索引
// 由于 loop 模式下拷贝了俩节点,所以 active 有误差
// 假设有三个节点,那么 active 非 loop 模式下为 0 ~ 2,loop 模式下为 -1 ~ 3
/**
* @private
* @param {?} active
* @return {?}
*/
getRealActive(active) {
return (active + this.count) % this.count;
}
// loop 模式下首尾拷贝一个节点,模拟无缝轮播
// 0 1 2 => 2 0 1 2 0
// TODO: 也许能找到一个不用手动复制 dom,并且可以自动更新内容的方式
/**
* @private
* @return {?}
*/
handleMirrorNodes() {
/** @type {?} */
const trackEl = this.track.nativeElement
// 清理镜像节点
;
// 清理镜像节点
try {
this.renderer.removeChild(trackEl, this.preMirrorNode);
this.renderer.removeChild(trackEl, this.postMirrorNode);
}
catch (e) { }
const { first, last } = this.items;
this.preMirrorNode = last.elRef.nativeElement.cloneNode(true);
this.postMirrorNode = first.elRef.nativeElement.cloneNode(true);
this.renderer.addClass(this.preMirrorNode, 'pre-mirror-node');
this.renderer.addClass(this.postMirrorNode, 'post-mirror-node');
this.renderer.insertBefore(trackEl, this.preMirrorNode, first.elRef.nativeElement);
this.renderer.appendChild(trackEl, this.postMirrorNode);
}
/**
* @private
* @param {?} offset
* @param {?=} immediate
* @return {?}
*/
move(offset, immediate = false) {
/** @type {?} */
const el = this.track.nativeElement;
/** @type {?} */
const oldOffset = this.offset;
/** @type {?} */
const newOffset = (this.offset = offset);
this.renderer.setStyle(el, 'transition', immediate ? 'none' : `transform ${this.speed}ms`);
this.renderer.setStyle(el, 'transform', `translate3d(${offset}%, 0, 0)`);
return timer(immediate || newOffset === oldOffset ? 0 : this.speed).pipe(takeUntil(this.destroy$));
}
/**
* @private
* @return {?}
*/
startAutoplay() {
if (!this.autoplay || this.count <= 1) {
return;
}
this.stopAutoplay();
this.intervalSub = interval(this.autoplay + this.speed)
.pipe(takeUntil(this.destroy$))
.subscribe((/**
* @return {?}
*/
() => {
/** @type {?} */
const oldActive = this.active;
/** @type {?} */
const newActive = this.loop ? oldActive + 1 : this.getRealActive(oldActive + 1);
this.goTo(newActive);
}));
}
/**
* @private
* @return {?}
*/
stopAutoplay() {
this.intervalSub && this.intervalSub.unsubscribe();
}
}
CarouselComponent.decorators = [
{ type: Component, args: [{
selector: 'ngx-carousel',
template: "<div\n class=\"ngx-carousel__track\"\n #track\n (dragstart)=\"$event.preventDefault()\"\n (panstart)=\"onPanStart($event)\"\n (panmove)=\"onPanMove($event)\"\n (panend)=\"onPanEnd($event)\"\n (pancancel)=\"onPanEnd($event)\"\n>\n <ng-content></ng-content>\n</div>\n\n<div class=\"ngx-carousel__indicator\" *ngIf=\"!indicator\">\n <div\n *ngFor=\"let item of items; let i = index\"\n [class.active]=\"i === active\"\n ></div>\n</div>\n\n<ng-container *ngTemplateOutlet=\"indicator; context: { $implicit: data }\"></ng-container>\n",
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
host: {
'[class.ngx-carousel]': `true`
},
providers: [
{
provide: CAROUSEL,
useExisting: forwardRef((/**
* @return {?}
*/
() => CarouselComponent))
}
],
styles: [".ngx-carousel{position:relative;display:block;overflow:hidden}.ngx-carousel__track{position:relative;display:inline-block;white-space:nowrap}.ngx-carousel__indicator{position:absolute;bottom:10px;width:100%;text-align:center;white-space:nowrap;font-size:0;pointer-events:none}.ngx-carousel__indicator div{display:inline-block;width:6px;height:6px;margin:0 3px;border-radius:50%;background:rgba(0,0,0,.25);pointer-events:auto}.ngx-carousel__indicator div.active{background:rgba(0,0,0,.75)}"]
}] }
];
/** @nocollapse */
CarouselComponent.ctorParameters = () => [
{ type: Renderer2 },
{ type: ElementRef },
{ type: ChangeDetectorRef }
];
CarouselComponent.propDecorators = {
loop: [{ type: Input }],
speed: [{ type: Input }],
autoplay: [{ type: Input }],
followFinger: [{ type: Input }],
allowTouchMove: [{ type: Input }],
indicator: [{ type: Input }],
initialIndex: [{ type: Input }],
lazyRenderOffset: [{ type: Input }],
cache: [{ type: Input }],
indexChange: [{ type: Output }],
track: [{ type: ViewChild, args: ['track', { static: false },] }],
items: [{ type: ContentChildren, args: [CarouselItemComponent,] }]
};
if (false) {
/**
* 是否开启无缝模式
* @type {?}
*/
CarouselComponent.prototype.loop;
/**
* 切换速度(ms)
* @type {?}
*/
CarouselComponent.prototype.speed;
/**
* 自动轮播时间间隔,0 代表关闭自动轮播
* @type {?}
*/
CarouselComponent.prototype.autoplay;
/**
* 是否跟随手指滑动,设为 false 代表只在松手后进行移动判断
* @type {?}
*/
CarouselComponent.prototype.followFinger;
/**
* 是否允许手动滑动,设为 false 代表只能通过 api 翻页
* @type {?}
*/
CarouselComponent.prototype.allowTouchMove;
/**
* 自定义指示器
* @type {?}
*/
CarouselComponent.prototype.indicator;
/**
* 默认激活项
* @type {?}
*/
CarouselComponent.prototype.initialIndex;
/**
* lazyRender 模式下预渲染个数,1 代表左右多渲染一个,2 代表左右多渲染两个,...
* @type {?}
*/
CarouselComponent.prototype.lazyRenderOffset;
/**
* 是否缓存 lazyRender 模式下渲染过的 item,不从 dom 树中删除
* @type {?}
*/
CarouselComponent.prototype.cache;
/**
* 索引变动时触发
* @type {?}
*/
CarouselComponent.prototype.indexChange;
/** @type {?} */
CarouselComponent.prototype.track;
/** @type {?} */
CarouselComponent.prototype.items;
/** @type {?} */
CarouselComponent.prototype.active$;
/**
* @type {?}
* @private
*/
CarouselComponent.prototype.destroy$;
/**
* @type {?}
* @private
*/
CarouselComponent.prototype.intervalSub;
/**
* @type {?}
* @private
*/
CarouselComponent.prototype.percent;
/**
* @type {?}
* @private
*/
CarouselComponent.prototype.offset;
/**
* @type {?}
* @private
*/
CarouselComponent.prototype.animating;
/**
* @type {?}
* @private
*/
CarouselComponent.prototype.preMirrorNode;
/**
* @type {?}
* @private
*/
CarouselComponent.prototype.postMirrorNode;
/**
* @type {?}
* @private
*/
CarouselComponent.prototype.renderer;
/**
* @type {?}
* @private
*/
CarouselComponent.prototype.hostElRef;
/**
* @type {?}
* @private
*/
CarouselComponent.prototype.cdr;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2Fyb3VzZWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vQGNpcmkvbmd4LWNhcm91c2VsLyIsInNvdXJjZXMiOlsibGliL2Nhcm91c2VsL2Nhcm91c2VsLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLE9BQU8sRUFFTCx1QkFBdUIsRUFDdkIsaUJBQWlCLEVBQ2pCLFNBQVMsRUFDVCxlQUFlLEVBQ2YsVUFBVSxFQUNWLFlBQVksRUFDWixVQUFVLEVBQ1YsS0FBSyxFQUdMLE1BQU0sRUFDTixTQUFTLEVBQ1QsU0FBUyxFQUVULFdBQVcsRUFDWCxTQUFTLEVBQ1QsaUJBQWlCLEVBQ2xCLE1BQU0sZUFBZSxDQUFBO0FBQ3RCLE9BQU8sRUFBRSxlQUFlLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBZ0IsS0FBSyxFQUFFLE1BQU0sTUFBTSxDQUFBO0FBQzlFLE9BQU8sRUFDTCxZQUFZLEVBQ1osb0JBQW9CLEVBQ3BCLE1BQU0sRUFDTixJQUFJLEVBQ0osU0FBUyxFQUNULFNBQVMsRUFDVixNQUFNLGdCQUFnQixDQUFBO0FBQ3ZCLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQTtBQUV2RSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSwwQ0FBMEMsQ0FBQTtBQUNoRixPQUFPLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQVUsTUFBTSxhQUFhLENBQUE7QUFrQjlELE1BQU0sT0FBTyxpQkFBaUI7Ozs7Ozs7SUFpRTVCLFlBQ1UsUUFBbUIsRUFDbkIsU0FBcUIsRUFDckIsR0FBc0I7UUFGdEIsYUFBUSxHQUFSLFFBQVEsQ0FBVztRQUNuQixjQUFTLEdBQVQsU0FBUyxDQUFZO1FBQ3JCLFFBQUcsR0FBSCxHQUFHLENBQW1COzs7O1FBbEV2QixTQUFJLEdBQVksS0FBSyxDQUFBOzs7O1FBRXJCLFVBQUssR0FBVyxHQUFHLENBQUE7Ozs7UUFFbkIsYUFBUSxHQUFXLENBQUMsQ0FBQTs7OztR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SzsyQkFFTCxLQUFLOytCQUVMLEtBQUs7b0JBRUwsS0FBSzswQkFHTCxNQUFNO29CQUVOLFNBQVMsU0FBQyxPQUFPLEVBQUUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFO29CQUNwQyxlQUFlLFNBQUMscUJBQXFCOzs7Ozs7O0lBdEJ0QyxpQ0FBOEI7Ozs7O0lBRTlCLGtDQUE0Qjs7Ozs7SUFFNUIscUNBQTZCOzs7OztJQUU3Qix5Q0FBcUM7Ozs7O0lBRXJDLDJDQUF1Qzs7Ozs7SUFFdkMsc0NBQTREOzs7OztJQUU1RCx5Q0FBaUM7Ozs7O0lBRWpDLDZDQUFxQzs7Ozs7SUFFckMsa0NBQStCOzs7OztJQUcvQix3Q0FBa0Q7O0lBRWxELGtDQUF3RDs7SUFDeEQsa0NBQStFOztJQWdDL0Usb0NBQTJDOzs7OztJQUMzQyxxQ0FBZ0M7Ozs7O0lBQ2hDLHdDQUFpQzs7Ozs7SUFDakMsb0NBQW1COzs7OztJQUNuQixtQ0FBa0I7Ozs7O0lBQ2xCLHNDQUF5Qjs7Ozs7SUFDekIsMENBQTJCOzs7OztJQUMzQiwyQ0FBNEI7Ozs7O0lBRzFCLHFDQUEyQjs7Ozs7SUFDM0Isc0NBQTZCOzs7OztJQUM3QixnQ0FBOEIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBBZnRlclZpZXdJbml0LFxuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgQ29udGVudENoaWxkcmVuLFxuICBFbGVtZW50UmVmLFxuICBFdmVudEVtaXR0ZXIsXG4gIGZvcndhcmRSZWYsXG4gIElucHV0LFxuICBPbkRlc3Ryb3ksXG4gIE9uSW5pdCxcbiAgT3V0cHV0LFxuICBRdWVyeUxpc3QsXG4gIFJlbmRlcmVyMixcbiAgU2ltcGxlQ2hhbmdlcyxcbiAgVGVtcGxhdGVSZWYsXG4gIFZpZXdDaGlsZCxcbiAgVmlld0VuY2Fwc3VsYXRpb25cbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSdcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgaW50ZXJ2YWwsIFN1YmplY3QsIFN1YnNjcmlwdGlvbiwgdGltZXIgfSBmcm9tICdyeGpzJ1xuaW1wb3J0IHtcbiAgZGVib3VuY2VUaW1lLFxuICBkaXN0aW5jdFVudGlsQ2hhbmdlZCxcbiAgZmlsdGVyLFxuICBza2lwLFxuICBzdGFydFdpdGgsXG4gIHRha2VVbnRpbFxufSBmcm9tICdyeGpzL29wZXJhdG9ycydcbmltcG9ydCB7IGFuaW1hdGlvbkZyYW1lIH0gZnJvbSAncnhqcy9pbnRlcm5hbC9zY2hlZHVsZXIvYW5pbWF0aW9uRnJhbWUnXG5pbXBvcnQgeyBDYXJvdXNlbERhdGEgfSBmcm9tICcuLi9jYXJvdXNlbC5tb2RlbCdcbmltcG9ydCB7IENhcm91c2VsSXRlbUNvbXBvbmVudCB9IGZyb20gJy4uL2Nhcm91c2VsLWl0ZW0vY2Fyb3VzZWwtaXRlbS5jb21wb25lbnQnXG5pbXBvcnQgeyBDQVJPVVNFTCwgY2xhbXAsIGluUmFuZ2UsIHJlc2l6ZSB9IGZyb20gJy4uLy4uL3V0aWxzJ1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICduZ3gtY2Fyb3VzZWwnLFxuICB0ZW1wbGF0ZVVybDogJy4vY2Fyb3VzZWwuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9jYXJvdXNlbC5jb21wb25lbnQubGVzcyddLFxuICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgaG9zdDoge1xuICAgICdbY2xhc3Mubmd4LWNhcm91c2VsXSc6IGB0cnVlYFxuICB9LFxuICBwcm92aWRlcnM6IFtcbiAgICB7XG4gICAgICBwcm92aWRlOiBDQVJPVVNFTCxcbiAgICAgIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IENhcm91c2VsQ29tcG9uZW50KVxuICAgIH1cbiAgXVxufSlcbmV4cG9ydCBjbGFzcyBDYXJvdXNlbENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcbiAgLyoqIOaYr+WQpuW8gOWQr+aXoOe8neaooeW8jyAqL1xuICBASW5wdXQoKSBsb29wOiBib29sZWFuID0gZmFsc2VcbiAgLyoqIOWIh+aNoumAn+W6pu+8iG1z77yJICovXG4gIEBJbnB1dCgpIHNwZWVkOiBudW1iZXIgPSAzMDBcbiAgLyoqIOiHquWKqOi9ruaSreaXtumXtOmXtOmalO+8jDAg5Luj6KGo5YWz6Zet6Ieq5Yqo6L2u5pKtICovXG4gIEBJbnB1dCgpIGF1dG9wbGF5OiBudW1iZXIgPSAwXG4gIC8qKiDmmK/lkKbot5/pmo/miYvmjIfmu5HliqjvvIzorr7kuLogZmFsc2Ug5Luj6KGo5Y+q5Zyo5p2+5omL5ZCO6L+b6KGM56e75Yqo5Yik5patICovXG4gIEBJbnB1dCgpIGZvbGxvd0ZpbmdlcjogYm9vbGVhbiA9IHRydWVcbiAgLyoqIOaYr+WQpuWFgeiuuOaJi+WKqOa7keWKqO+8jOiuvuS4uiBmYWxzZSDku6Pooajlj6rog73pgJrov4cgYXBpIOe/u+mhtSAqL1xuICBASW5wdXQoKSBhbGxvd1RvdWNoTW92ZTogYm9vbGVhbiA9IHRydWVcbiAgLyoqIOiHquWumuS5ieaMh+ekuuWZqCAqL1xuICBASW5wdXQoKSBpbmRpY2F0b3I6IFRlbXBsYXRlUmVmPHsgJGltcGxpY2l0OiBDYXJvdXNlbERhdGEgfT5cbiAgLyoqIOm7mOiupOa/gOa0u+mhuSAqL1xuICBASW5wdXQoKSBpbml0aWFsSW5kZXg6IG51bWJlciA9IDBcbiAgLyoqIGxhenlSZW5kZXIg5qih5byP5LiL6aKE5riy5p+T5Liq5pWw77yMMSDku6Pooajlt6blj7PlpJrmuLLmn5PkuIDkuKrvvIwyIOS7o+ihqOW3puWPs+Wkmua4suafk+S4pOS4qu+8jC4uLiAqL1xuICBASW5wdXQoKSBsYXp5UmVuZGVyT2Zmc2V0OiBudW1iZXIgPSAwXG4gIC8qKiDmmK/lkKbnvJPlrZggbGF6eVJlbmRlciDmqKHlvI/kuIvmuLLmn5Pov4fnmoQgaXRlbe+8jOS4jeS7jiBkb20g5qCR5Lit5Yig6ZmkICovXG4gIEBJbnB1dCgpIGNhY2hlOiBib29sZWFuID0gZmFsc2VcblxuICAvKiog57Si5byV5Y+Y5Yqo5pe26Kem5Y+RICovXG4gIEBPdXRwdXQoKSBpbmRleENoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyPigpXG5cbiAgQFZpZXdDaGlsZCgndHJhY2snLCB7IHN0YXRpYzogZmFsc2UgfSkgdHJhY2s6IEVsZW1lbnRSZWZcbiAgQENvbnRlbnRDaGlsZHJlbihDYXJvdXNlbEl0ZW1Db21wb25lbnQpIGl0ZW1zOiBRdWVyeUxpc3Q8Q2Fyb3VzZWxJdGVtQ29tcG9uZW50PlxuXG4gIGdldCBhY3RpdmUoKSB7XG4gICAgcmV0dXJuIHRoaXMuYWN0aXZlJC52YWx1ZVxuICB9XG5cbiAgZ2V0IGNvdW50KCkge1xuICAgIHJldHVybiAodGhpcy5pdGVtcyB8fCBbXSkubGVuZ3RoXG4gIH1cblxuICBnZXQgdmlld3BvcnQoKSB7XG4gICAgcmV0dXJuIHRoaXMuaG9zdEVsUmVmLm5hdGl2ZUVsZW1lbnRcbiAgfVxuXG4gIGdldCB3aWR0aCgpIHtcbiAgICByZXR1cm4gdGhpcy52aWV3cG9ydC5vZmZzZXRXaWR0aFxuICB9XG5cbiAgZ2V0IGNhbk1vdmUoKSB7XG4gICAgcmV0dXJuIHRoaXMuYWxsb3dUb3VjaE1vdmUgJiYgIXRoaXMuYW5pbWF0aW5nXG4gIH1cblxuICBnZXQgZGF0YSgpOiBDYXJvdXNlbERhdGEge1xuICAgIHJldHVybiB7XG4gICAgICBhY3RpdmU6IHRoaXMuYWN0aXZlLFxuICAgICAgY291bnQ6IHRoaXMuY291bnQsXG4gICAgICBvZmZzZXQ6IHRoaXMub2Zmc2V0LFxuICAgICAgYW5pbWF0aW5nOiB0aGlzLmFuaW1hdGluZyxcbiAgICAgIGF0Rmlyc3Q6IHRoaXMuYWN0aXZlID09PSAwLFxuICAgICAgYXRMYXN0OiB0aGlzLmFjdGl2ZSA9PT0gdGhpcy5jb3VudCAtIDFcbiAgICB9XG4gIH1cbiAgYWN0aXZlJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8bnVtYmVyPihudWxsKVxuICBwcml2YXRlIGRlc3Ryb3kkID0gbmV3IFN1YmplY3QoKVxuICBwcml2YXRlIGludGVydmFsU3ViOiBTdWJzY3JpcHRpb25cbiAgcHJpdmF0ZSBwZXJjZW50ID0gMCAvLyDmiYvmjIfmu5Hliqjot53nprvmiYDljaDlrr3luqbmgLvlkoznmb7liIbmr5RcbiAgcHJpdmF0ZSBvZmZzZXQgPSAwIC8vIOWBj+enu+mHj++8iCXvvIlcbiAgcHJpdmF0ZSBhbmltYXRpbmcgPSBmYWxzZSAvLyDmmK/lkKblpITkuo7ov4fmuKHmlYjmnpzkuK1cbiAgcHJpdmF0ZSBwcmVNaXJyb3JOb2RlOiBOb2RlIC8vIOWJjemVnOWDj+iKgueCuVxuICBwcml2YXRlIHBvc3RNaXJyb3JOb2RlOiBOb2RlIC8vIOWQjumVnOWDj+iKgueCuVxuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVuZGVyZXI6IFJlbmRlcmVyMixcbiAgICBwcml2YXRlIGhvc3RFbFJlZjogRWxlbWVudFJlZixcbiAgICBwcml2YXRlIGNkcjogQ2hhbmdlRGV0ZWN0b3JSZWZcbiAgKSB7fVxuXG4gIG5nT25Jbml0KCkge31cblxuICBuZ0FmdGVyVmlld0luaXQoKSB7XG4gICAgdGhpcy5pdGVtcy5jaGFuZ2VzXG4gICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCksIHN0YXJ0V2l0aChudWxsKSwgZGVib3VuY2VUaW1lKDAsIGFuaW1hdGlvbkZyYW1lKSlcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICB0aGlzLmluaXQoKVxuICAgICAgfSlcblxuICAgIHRoaXMuYWN0aXZlJFxuICAgICAgLnBpcGUoXG4gICAgICAgIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSxcbiAgICAgICAgc2tpcCgxKSxcbiAgICAgICAgZmlsdGVyKHYgPT4gdiAhPT0gbnVsbCAmJiBpblJhbmdlKHYsIDAsIHRoaXMuY291bnQgLSAxKSksXG4gICAgICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKClcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUocmVzID0+IHtcbiAgICAgICAgdGhpcy5pbmRleENoYW5nZS5lbWl0KHJlcylcbiAgICAgICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKClcbiAgICAgIH0pXG5cbiAgICAvLyByZXNpemUg5Yqf6IO95b6F5byA5Y+RXG4gICAgLy8gcmVzaXplKHRoaXMudmlld3BvcnQpXG4gICAgLy8gICAucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCksIGRlYm91bmNlVGltZSgwLCBhbmltYXRpb25GcmFtZSkpXG4gICAgLy8gICAuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAvLyAgICAgLy8gdGhpcy51cGRhdGVXaWR0aCgpXG4gICAgLy8gICAgIC8vIHRoaXMuZ29Ubyh0aGlzLmFjdGl2ZSwgdHJ1ZSlcbiAgICAvLyAgIH0pXG4gIH1cblxuICBuZ09uRGVzdHJveSgpIHtcbiAgICB0aGlzLmRlc3Ryb3kkLm5leHQoKVxuICAgIHRoaXMuZGVzdHJveSQuY29tcGxldGUoKVxuICB9XG5cbiAgb25QYW5TdGFydChlOiBIYW1tZXJJbnB1dCkge1xuICAgIHRoaXMuc3RvcEF1dG9wbGF5KClcbiAgfVxuXG4gIG9uUGFuTW92ZShlOiBIYW1tZXJJbnB1dCkge1xuICAgIGlmICghdGhpcy5jYW5Nb3ZlKSB7XG4gICAgICByZXR1cm5cbiAgICB9XG4gICAgY29uc3QgZGVsdGFYID0gdGhpcy5nZXRTYWZlRGVsdGFYKGUuZGVsdGFYKVxuICAgIHRoaXMucGVyY2VudCA9ICgoMTAwIC8gdGhpcy5jb3VudCkgKiBkZWx0YVgpIC8gdGhpcy53aWR0aFxuXG4gICAgaWYgKHRoaXMuZm9sbG93RmluZ2VyKSB7XG4gICAgICBjb25zdCBvZmZzZXQgPSB0aGlzLnBlcmNlbnQgLSAoMTAwIC8gdGhpcy5jb3VudCkgKiB0aGlzLmFjdGl2ZVxuICAgICAgdGhpcy5tb3ZlKG9mZnNldCwgdHJ1ZSlcbiAgICB9XG4gIH1cblxuICBvblBhbkVuZChlOiBIYW1tZXJJbnB1dCkge1xuICAgIGlmICghdGhpcy5jYW5Nb3ZlKSB7XG4gICAgICByZXR1cm5cbiAgICB9XG4gICAgLy8g6L275ouC5oiW6ICF5ruR5Yqo6Led56a75aSn5LqO562J5LqO5LiA5Liq6IqC54K55a695bqm55qEIDUwJSDmiY3ov5vooYzot7PovaxcbiAgICBsZXQgbmV3QWN0aXZlID0gdGhpcy5hY3RpdmVcbiAgICBjb25zdCBpc1N3aXBlTGVmdCA9IGUuZGlyZWN0aW9uID09PSBIYW1tZXIuRElSRUNUSU9OX0xFRlQgJiYgZS52ZWxvY2l0eVggPCAtMC4zXG4gICAgY29uc3QgaXNTd2lwZVJpZ2h0ID0gZS5kaXJlY3Rpb24gPT09IEhhbW1lci5ESVJFQ1RJT05fUklHSFQgJiYgZS52ZWxvY2l0eVggPiAwLjNcbiAgICBpZiAoaXNTd2lwZUxlZnQgfHwgdGhpcy5wZXJjZW50IDw9IC01MCAvIHRoaXMuY291bnQpIHtcbiAgICAgIG5ld0FjdGl2ZSsrXG4gICAgfSBlbHNlIGlmIChpc1N3aXBlUmlnaHQgfHwgdGhpcy5wZXJjZW50ID49IDUwIC8gdGhpcy5jb3VudCkge1xuICAgICAgbmV3QWN0aXZlLS1cbiAgICB9XG4gICAgdGhpcy5nb1RvKG5ld0FjdGl2ZSlcbiAgICB0aGlzLnN0YXJ0QXV0b3BsYXkoKVxuICB9XG5cbiAgZ29Ubyh0YXJnZXQgPSAwLCBpbW1lZGlhdGUgPSBmYWxzZSkge1xuICAgIGlmICh0aGlzLmFuaW1hdGluZykge1xuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgY29uc3QgYWN0aXZlID0gdGhpcy5nZXRTYWZlQWN0aXZlKHRhcmdldClcbiAgICBjb25zdCByZWFsQWN0aXZlID0gdGhpcy5nZXRSZWFsQWN0aXZlKGFjdGl2ZSlcbiAgICB0aGlzLmFjdGl2ZSQubmV4dChyZWFsQWN0aXZlKVxuXG4gICAgLy8g5Yiw6L6+56ys5LiA5Liq5oiW5pyA5ZCO5LiA5Liq5pe25pu05paw6ZWc5YOP6IqC54K5XG4gICAgaWYgKHRoaXMubG9vcCAmJiAocmVhbEFjdGl2ZSA9PT0gMCB8fCByZWFsQWN0aXZlID09PSB0aGlzLmNvdW50IC0gMSkpIHtcbiAgICAgIHRoaXMuaGFuZGxlTWlycm9yTm9kZXMoKVxuICAgIH1cblxuICAgIHRoaXMuYW5pbWF0aW5nID0gdHJ1ZVxuICAgIHRoaXMubW92ZSgtKDEwMCAvIHRoaXMuY291bnQpICogYWN0aXZlLCBpbW1lZGlhdGUpLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICB0aGlzLmFuaW1hdGluZyA9IGZhbHNlXG4gICAgICBpZiAoYWN0aXZlID09PSAtMSB8fCBhY3RpdmUgPT09IHRoaXMuY291bnQpIHtcbiAgICAgICAgdGhpcy5nb1RvKHJlYWxBY3RpdmUsIHRydWUpXG4gICAgICB9XG4gICAgfSlcbiAgfVxuXG4gIHByZXYoKSB7XG4gICAgdGhpcy5nb1RvKHRoaXMuYWN0aXZlIC0gMSlcbiAgfVxuXG4gIG5leHQoKSB7XG4gICAgdGhpcy5nb1RvKHRoaXMuYWN0aXZlICsgMSlcbiAgfVxuXG4gIHByaXZhdGUgaW5pdCgpIHtcbiAgICBpZiAodGhpcy5pdGVtcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVyblxuICAgIH1cbiAgICB0aGlzLml0ZW1zLmZvckVhY2goKGVsLCBpbmRleCkgPT4ge1xuICAgICAgZWwuaW5kZXggPSBpbmRleFxuICAgICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZShlbC5lbFJlZi5uYXRpdmVFbGVtZW50LCAnd2lkdGgnLCBgJHt0aGlzLndpZHRofXB4YClcbiAgICB9KVxuICAgIHRoaXMuZ29Ubyh0aGlzLmdldFNhZmVBY3RpdmUodGhpcy5pbml0aWFsSW5kZXgsIHRydWUpLCB0cnVlKVxuICAgIHRoaXMuc3RhcnRBdXRvcGxheSgpXG4gIH1cblxuICBwcml2YXRlIGdldFNhZmVEZWx0YVgoZGVsdGFYKSB7XG4gICAgY29uc3QgdyA9IHRoaXMud2lkdGhcbiAgICByZXR1cm4gY2xhbXAoZGVsdGFYLCAtdywgdylcbiAgfVxuXG4gIHByaXZhdGUgZ2V0U2FmZUFjdGl2ZShhY3RpdmUsIHN0cmljdCA9IGZhbHNlKSB7XG4gICAgY29uc3QgbWluID0gdGhpcy5sb29wICYmICFzdHJpY3QgPyAtMSA6IDBcbiAgICBjb25zdCBtYXggPSB0aGlzLmxvb3AgJiYgIXN0cmljdCA/IHRoaXMuY291bnQgOiB0aGlzLmNvdW50IC0gMVxuICAgIHJldHVybiBjbGFtcChhY3RpdmUsIG1pbiwgbWF4KVxuICB9XG5cbiAgLy8g6K6h566X55yf5a6e57Si5byVXG4gIC8vIOeUseS6jiBsb29wIOaooeW8j+S4i+aLt+i0neS6huS/qeiKgueCue+8jOaJgOS7pSBhY3RpdmUg5pyJ6K+v5beuXG4gIC8vIOWBh+iuvuacieS4ieS4quiKgueCue+8jOmCo+S5iCBhY3RpdmUg6Z2eIGxvb3Ag5qih5byP5LiL5Li6IDAg772eIDLvvIxsb29wIOaooeW8j+S4i+S4uiAtMSDvvZ4gM1xuICBwcml2YXRlIGdldFJlYWxBY3RpdmUoYWN0aXZlKSB7XG4gICAgcmV0dXJuIChhY3RpdmUgKyB0aGlzLmNvdW50KSAlIHRoaXMuY291bnRcbiAgfVxuXG4gIC8vIGxvb3Ag5qih5byP5LiL6aaW5bC+5ou36LSd5LiA5Liq6IqC54K577yM5qih5ouf5peg57yd6L2u5pKtXG4gIC8vIDAgMSAyID0+IDIgMCAxIDIgMFxuICAvLyBUT0RPOiDkuZ/orrjog73mib7liLDkuIDkuKrkuI3nlKjmiYvliqjlpI3liLYgZG9t77yM5bm25LiU5Y+v5Lul6Ieq5Yqo5pu05paw5YaF5a6555qE5pa55byPXG4gIHByaXZhdGUgaGFuZGxlTWlycm9yTm9kZXMoKSB7XG4gICAgY29uc3QgdHJhY2tFbCA9IHRoaXMudHJhY2submF0aXZlRWxlbWVudFxuICAgIC8vIOa4heeQhumVnOWDj+iKgueCuVxuICAgIHRyeSB7XG4gICAgICB0aGlzLnJlbmRlcmVyLnJlbW92ZUNoaWxkKHRyYWNrRWwsIHRoaXMucHJlTWlycm9yTm9kZSlcbiAgICAgIHRoaXMucmVuZGVyZXIucmVtb3ZlQ2hpbGQodHJhY2tFbCwgdGhpcy5wb3N0TWlycm9yTm9kZSlcbiAgICB9IGNhdGNoIChlKSB7fVxuXG4gICAgY29uc3QgeyBmaXJzdCwgbGFzdCB9ID0gdGhpcy5pdGVtc1xuICAgIHRoaXMucHJlTWlycm9yTm9kZSA9IGxhc3QuZWxSZWYubmF0aXZlRWxlbWVudC5jbG9uZU5vZGUodHJ1ZSlcbiAgICB0aGlzLnBvc3RNaXJyb3JOb2RlID0gZmlyc3QuZWxSZWYubmF0aXZlRWxlbWVudC5jbG9uZU5vZGUodHJ1ZSlcblxuICAgIHRoaXMucmVuZGVyZXIuYWRkQ2xhc3ModGhpcy5wcmVNaXJyb3JOb2RlLCAncHJlLW1pcnJvci1ub2RlJylcbiAgICB0aGlzLnJlbmRlcmVyLmFkZENsYXNzKHRoaXMucG9zdE1pcnJvck5vZGUsICdwb3N0LW1pcnJvci1ub2RlJylcbiAgICB0aGlzLnJlbmRlcmVyLmluc2VydEJlZm9yZSh0cmFja0VsLCB0aGlzLnByZU1pcnJvck5vZGUsIGZpcnN0LmVsUmVmLm5hdGl2ZUVsZW1lbnQpXG4gICAgdGhpcy5yZW5kZXJlci5hcHBlbmRDaGlsZCh0cmFja0VsLCB0aGlzLnBvc3RNaXJyb3JOb2RlKVxuICB9XG5cbiAgcHJpdmF0ZSBtb3ZlKG9mZnNldCwgaW1tZWRpYXRlID0gZmFsc2UpIHtcbiAgICBjb25zdCBlbCA9IHRoaXMudHJhY2submF0aXZlRWxlbWVudFxuICAgIGNvbnN0IG9sZE9mZnNldCA9IHRoaXMub2Zmc2V0XG4gICAgY29uc3QgbmV3T2Zmc2V0ID0gKHRoaXMub2Zmc2V0ID0gb2Zmc2V0KVxuXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZShlbCwgJ3RyYW5zaXRpb24nLCBpbW1lZGlhdGUgPyAnbm9uZScgOiBgdHJhbnNmb3JtICR7dGhpcy5zcGVlZH1tc2ApXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZShlbCwgJ3RyYW5zZm9ybScsIGB0cmFuc2xhdGUzZCgke29mZnNldH0lLCAwLCAwKWApXG5cbiAgICByZXR1cm4gdGltZXIoaW1tZWRpYXRlIHx8IG5ld09mZnNldCA9PT0gb2xkT2Zmc2V0ID8gMCA6IHRoaXMuc3BlZWQpLnBpcGUoXG4gICAgICB0YWtlVW50aWwodGhpcy5kZXN0cm95JClcbiAgICApXG4gIH1cblxuICBwcml2YXRlIHN0YXJ0QXV0b3BsYXkoKSB7XG4gICAgaWYgKCF0aGlzLmF1dG9wbGF5IHx8IHRoaXMuY291bnQgPD0gMSkge1xuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgdGhpcy5zdG9wQXV0b3BsYXkoKVxuXG4gICAgdGhpcy5pbnRlcnZhbFN1YiA9IGludGVydmFsKHRoaXMuYXV0b3BsYXkgKyB0aGlzLnNwZWVkKVxuICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKVxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgIGNvbnN0IG9sZEFjdGl2ZSA9IHRoaXMuYWN0aXZlXG4gICAgICAgIGNvbnN0IG5ld0FjdGl2ZSA9IHRoaXMubG9vcCA/IG9sZEFjdGl2ZSArIDEgOiB0aGlzLmdldFJlYWxBY3RpdmUob2xkQWN0aXZlICsgMSlcbiAgICAgICAgdGhpcy5nb1RvKG5ld0FjdGl2ZSlcbiAgICAgIH0pXG4gIH1cblxuICBwcml2YXRlIHN0b3BBdXRvcGxheSgpIHtcbiAgICB0aGlzLmludGVydmFsU3ViICYmIHRoaXMuaW50ZXJ2YWxTdWIudW5zdWJzY3JpYmUoKVxuICB9XG59XG4iXX0=