UNPKG

@ciri/ngx-carousel

Version:
520 lines 39.4 kB
/** * @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=