/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import { coerceNumberProperty } from '@angular/cdk/coercion'; import { Directive, forwardRef, Input } from '@angular/core'; import { Subject } from 'rxjs'; import { distinctUntilChanged } from 'rxjs/operators'; import { VIRTUAL_SCROLL_STRATEGY } from './virtual-scroll-strategy'; /** Virtual scrolling strategy for lists with items of known fixed size. */ export class FixedSizeVirtualScrollStrategy { /** * @param itemSize The size of the items in the virtually scrolling list. * @param minBufferPx The minimum amount of buffer (in pixels) before needing to render more * @param maxBufferPx The amount of buffer (in pixels) to render when rendering more. */ constructor(itemSize, minBufferPx, maxBufferPx) { this._scrolledIndexChange = new Subject(); /** @docs-private Implemented as part of VirtualScrollStrategy. */ this.scrolledIndexChange = this._scrolledIndexChange.pipe(distinctUntilChanged()); /** The attached viewport. */ this._viewport = null; this._itemSize = itemSize; this._minBufferPx = minBufferPx; this._maxBufferPx = maxBufferPx; } /** * Attaches this scroll strategy to a viewport. * @param viewport The viewport to attach this strategy to. */ attach(viewport) { this._viewport = viewport; this._updateTotalContentSize(); this._updateRenderedRange(); } /** Detaches this scroll strategy from the currently attached viewport. */ detach() { this._scrolledIndexChange.complete(); this._viewport = null; } /** * Update the item size and buffer size. * @param itemSize The size of the items in the virtually scrolling list. * @param minBufferPx The minimum amount of buffer (in pixels) before needing to render more * @param maxBufferPx The amount of buffer (in pixels) to render when rendering more. */ updateItemAndBufferSize(itemSize, minBufferPx, maxBufferPx) { if (maxBufferPx < minBufferPx && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('CDK virtual scroll: maxBufferPx must be greater than or equal to minBufferPx'); } this._itemSize = itemSize; this._minBufferPx = minBufferPx; this._maxBufferPx = maxBufferPx; this._updateTotalContentSize(); this._updateRenderedRange(); } /** @docs-private Implemented as part of VirtualScrollStrategy. */ onContentScrolled() { this._updateRenderedRange(); } /** @docs-private Implemented as part of VirtualScrollStrategy. */ onDataLengthChanged() { this._updateTotalContentSize(); this._updateRenderedRange(); } /** @docs-private Implemented as part of VirtualScrollStrategy. */ onContentRendered() { } /** @docs-private Implemented as part of VirtualScrollStrategy. */ onRenderedOffsetChanged() { } /** * Scroll to the offset for the given index. * @param index The index of the element to scroll to. * @param behavior The ScrollBehavior to use when scrolling. */ scrollToIndex(index, behavior) { if (this._viewport) { this._viewport.scrollToOffset(index * this._itemSize, behavior); } } /** Update the viewport's total content size. */ _updateTotalContentSize() { if (!this._viewport) { return; } this._viewport.setTotalContentSize(this._viewport.getDataLength() * this._itemSize); } /** Update the viewport's rendered range. */ _updateRenderedRange() { if (!this._viewport) { return; } const renderedRange = this._viewport.getRenderedRange(); const newRange = { start: renderedRange.start, end: renderedRange.end }; const viewportSize = this._viewport.getViewportSize(); const dataLength = this._viewport.getDataLength(); let scrollOffset = this._viewport.measureScrollOffset(); // Prevent NaN as result when dividing by zero. let firstVisibleIndex = (this._itemSize > 0) ? scrollOffset / this._itemSize : 0; // If user scrolls to the bottom of the list and data changes to a smaller list if (newRange.end > dataLength) { // We have to recalculate the first visible index based on new data length and viewport size. const maxVisibleItems = Math.ceil(viewportSize / this._itemSize); const newVisibleIndex = Math.max(0, Math.min(firstVisibleIndex, dataLength - maxVisibleItems)); // If first visible index changed we must update scroll offset to handle start/end buffers // Current range must also be adjusted to cover the new position (bottom of new list). if (firstVisibleIndex != newVisibleIndex) { firstVisibleIndex = newVisibleIndex; scrollOffset = newVisibleIndex * this._itemSize; newRange.start = Math.floor(firstVisibleIndex); } newRange.end = Math.max(0, Math.min(dataLength, newRange.start + maxVisibleItems)); } const startBuffer = scrollOffset - newRange.start * this._itemSize; if (startBuffer < this._minBufferPx && newRange.start != 0) { const expandStart = Math.ceil((this._maxBufferPx - startBuffer) / this._itemSize); newRange.start = Math.max(0, newRange.start - expandStart); newRange.end = Math.min(dataLength, Math.ceil(firstVisibleIndex + (viewportSize + this._minBufferPx) / this._itemSize)); } else { const endBuffer = newRange.end * this._itemSize - (scrollOffset + viewportSize); if (endBuffer < this._minBufferPx && newRange.end != dataLength) { const expandEnd = Math.ceil((this._maxBufferPx - endBuffer) / this._itemSize); if (expandEnd > 0) { newRange.end = Math.min(dataLength, newRange.end + expandEnd); newRange.start = Math.max(0, Math.floor(firstVisibleIndex - this._minBufferPx / this._itemSize)); } } } this._viewport.setRenderedRange(newRange); this._viewport.setRenderedContentOffset(this._itemSize * newRange.start); this._scrolledIndexChange.next(Math.floor(firstVisibleIndex)); } } /** * Provider factory for `FixedSizeVirtualScrollStrategy` that simply extracts the already created * `FixedSizeVirtualScrollStrategy` from the given directive. * @param fixedSizeDir The instance of `CdkFixedSizeVirtualScroll` to extract the * `FixedSizeVirtualScrollStrategy` from. */ export function _fixedSizeVirtualScrollStrategyFactory(fixedSizeDir) { return fixedSizeDir._scrollStrategy; } /** A virtual scroll strategy that supports fixed-size items. */ export class CdkFixedSizeVirtualScroll { constructor() { this._itemSize = 20; this._minBufferPx = 100; this._maxBufferPx = 200; /** The scroll strategy used by this directive. */ this._scrollStrategy = new FixedSizeVirtualScrollStrategy(this.itemSize, this.minBufferPx, this.maxBufferPx); } /** The size of the items in the list (in pixels). */ get itemSize() { return this._itemSize; } set itemSize(value) { this._itemSize = coerceNumberProperty(value); } /** * The minimum amount of buffer rendered beyond the viewport (in pixels). * If the amount of buffer dips below this number, more items will be rendered. Defaults to 100px. */ get minBufferPx() { return this._minBufferPx; } set minBufferPx(value) { this._minBufferPx = coerceNumberProperty(value); } /** * The number of pixels worth of buffer to render for when rendering new items. Defaults to 200px. */ get maxBufferPx() { return this._maxBufferPx; } set maxBufferPx(value) { this._maxBufferPx = coerceNumberProperty(value); } ngOnChanges() { this._scrollStrategy.updateItemAndBufferSize(this.itemSize, this.minBufferPx, this.maxBufferPx); } } CdkFixedSizeVirtualScroll.decorators = [ { type: Directive, args: [{ selector: 'cdk-virtual-scroll-viewport[itemSize]', providers: [{ provide: VIRTUAL_SCROLL_STRATEGY, useFactory: _fixedSizeVirtualScrollStrategyFactory, deps: [forwardRef(() => CdkFixedSizeVirtualScroll)], }], },] } ]; CdkFixedSizeVirtualScroll.propDecorators = { itemSize: [{ type: Input }], minBufferPx: [{ type: Input }], maxBufferPx: [{ type: Input }] }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZml4ZWQtc2l6ZS12aXJ0dWFsLXNjcm9sbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9jZGsvc2Nyb2xsaW5nL2ZpeGVkLXNpemUtdmlydHVhbC1zY3JvbGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBRUgsT0FBTyxFQUNMLG9CQUFvQixFQUVyQixNQUFNLHVCQUF1QixDQUFDO0FBQy9CLE9BQU8sRUFBQyxTQUFTLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBWSxNQUFNLGVBQWUsQ0FBQztBQUN0RSxPQUFPLEVBQWEsT0FBTyxFQUFDLE1BQU0sTUFBTSxDQUFDO0FBQ3pDLE9BQU8sRUFBQyxvQkFBb0IsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQ3BELE9BQU8sRUFBQyx1QkFBdUIsRUFBd0IsTUFBTSwyQkFBMkIsQ0FBQztBQUl6RiwyRUFBMkU7QUFDM0UsTUFBTSxPQUFPLDhCQUE4QjtJQWtCekM7Ozs7T0FJRztJQUNILFlBQVksUUFBZ0IsRUFBRSxXQUFtQixFQUFFLFdBQW1CO1FBdEJyRCx5QkFBb0IsR0FBRyxJQUFJLE9BQU8sRUFBVSxDQUFDO1FBRTlELGtFQUFrRTtRQUNsRSx3QkFBbUIsR0FBdUIsSUFBSSxDQUFDLG9CQUFvQixDQUFDLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDLENBQUM7UUFFakcsNkJBQTZCO1FBQ3JCLGNBQVMsR0FBb0MsSUFBSSxDQUFDO1FBaUJ4RCxJQUFJLENBQUMsU0FBUyxHQUFHLFFBQVEsQ0FBQztRQUMxQixJQUFJLENBQUMsWUFBWSxHQUFHLFdBQVcsQ0FBQztRQUNoQyxJQUFJLENBQUMsWUFBWSxHQUFHLFdBQVcsQ0FBQztJQUNsQyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsTUFBTSxDQUFDLFFBQWtDO1FBQ3ZDLElBQUksQ0FBQyxTQUFTLEdBQUcsUUFBUSxDQUFDO1FBQzFCLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1FB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LFNBQVMsRUFBRSxDQUFDO3dCQUNWLE9BQU8sRUFBRSx1QkFBdUI7d0JBQ2hDLFVBQVUsRUFBRSxzQ0FBc0M7d0JBQ2xELElBQUksRUFBRSxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO3FCQUNwRCxDQUFDO2FBQ0g7Ozt1QkFHRSxLQUFLOzBCQVNMLEtBQUs7MEJBUUwsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG5pbXBvcnQge1xuICBjb2VyY2VOdW1iZXJQcm9wZXJ0eSxcbiAgTnVtYmVySW5wdXRcbn0gZnJvbSAnQGFuZ3VsYXIvY2RrL2NvZXJjaW9uJztcbmltcG9ydCB7RGlyZWN0aXZlLCBmb3J3YXJkUmVmLCBJbnB1dCwgT25DaGFuZ2VzfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7T2JzZXJ2YWJsZSwgU3ViamVjdH0gZnJvbSAncnhqcyc7XG5pbXBvcnQge2Rpc3RpbmN0VW50aWxDaGFuZ2VkfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQge1ZJUlRVQUxfU0NST0xMX1NUUkFURUdZLCBWaXJ0dWFsU2Nyb2xsU3RyYXRlZ3l9IGZyb20gJy4vdmlydHVhbC1zY3JvbGwtc3RyYXRlZ3knO1xuaW1wb3J0IHtDZGtWaXJ0dWFsU2Nyb2xsVmlld3BvcnR9IGZyb20gJy4vdmlydHVhbC1zY3JvbGwtdmlld3BvcnQnO1xuXG5cbi8qKiBWaXJ0dWFsIHNjcm9sbGluZyBzdHJhdGVneSBmb3IgbGlzdHMgd2l0aCBpdGVtcyBvZiBrbm93biBmaXhlZCBzaXplLiAqL1xuZXhwb3J0IGNsYXNzIEZpeGVkU2l6ZVZpcnR1YWxTY3JvbGxTdHJhdGVneSBpbXBsZW1lbnRzIFZpcnR1YWxTY3JvbGxTdHJhdGVneSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgX3Njcm9sbGVkSW5kZXhDaGFuZ2UgPSBuZXcgU3ViamVjdDxudW1iZXI+KCk7XG5cbiAgLyoqIEBkb2NzLXByaXZhdGUgSW1wbGVtZW50ZWQgYXMgcGFydCBvZiBWaXJ0dWFsU2Nyb2xsU3RyYXRlZ3kuICovXG4gIHNjcm9sbGVkSW5kZXhDaGFuZ2U6IE9ic2VydmFibGU8bnVtYmVyPiA9IHRoaXMuX3Njcm9sbGVkSW5kZXhDaGFuZ2UucGlwZShkaXN0aW5jdFVudGlsQ2hhbmdlZCgpKTtcblxuICAvKiogVGhlIGF0dGFjaGVkIHZpZXdwb3J0LiAqL1xuICBwcml2YXRlIF92aWV3cG9ydDogQ2RrVmlydHVhbFNjcm9sbFZpZXdwb3J0IHwgbnVsbCA9IG51bGw7XG5cbiAgLyoqIFRoZSBzaXplIG9mIHRoZSBpdGVtcyBpbiB0aGUgdmlydHVhbGx5IHNjcm9sbGluZyBsaXN0LiAqL1xuICBwcml2YXRlIF9pdGVtU2l6ZTogbnVtYmVyO1xuXG4gIC8qKiBUaGUgbWluaW11bSBhbW91bnQgb2YgYnVmZmVyIHJlbmRlcmVkIGJleW9uZCB0aGUgdmlld3BvcnQgKGluIHBpeGVscykuICovXG4gIHByaXZhdGUgX21pbkJ1ZmZlclB4OiBudW1iZXI7XG5cbiAgLyoqIFRoZSBudW1iZXIgb2YgYnVmZmVyIGl0ZW1zIHRvIHJlbmRlciBiZXlvbmQgdGhlIGVkZ2Ugb2YgdGhlIHZpZXdwb3J0IChpbiBwaXhlbHMpLiAqL1xuICBwcml2YXRlIF9tYXhCdWZmZXJQeDogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBAcGFyYW0gaXRlbVNpemUgVGhlIHNpemUgb2YgdGhlIGl0ZW1zIGluIHRoZSB2aXJ0dWFsbHkgc2Nyb2xsaW5nIGxpc3QuXG4gICAqIEBwYXJhbSBtaW5CdWZmZXJQeCBUaGUgbWluaW11bSBhbW91bnQgb2YgYnVmZmVyIChpbiBwaXhlbHMpIGJlZm9yZSBuZWVkaW5nIHRvIHJlbmRlciBtb3JlXG4gICAqIEBwYXJhbSBtYXhCdWZmZXJQeCBUaGUgYW1vdW50IG9mIGJ1ZmZlciAoaW4gcGl4ZWxzKSB0byByZW5kZXIgd2hlbiByZW5kZXJpbmcgbW9yZS5cbiAgICovXG4gIGNvbnN0cnVjdG9yKGl0ZW1TaXplOiBudW1iZXIsIG1pbkJ1ZmZlclB4OiBudW1iZXIsIG1heEJ1ZmZlclB4OiBudW1iZXIpIHtcbiAgICB0aGlzLl9pdGVtU2l6ZSA9IGl0ZW1TaXplO1xuICAgIHRoaXMuX21pbkJ1ZmZlclB4ID0gbWluQnVmZmVyUHg7XG4gICAgdGhpcy5fbWF4QnVmZmVyUHggPSBtYXhCdWZmZXJQeDtcbiAgfVxuXG4gIC8qKlxuICAgKiBBdHRhY2hlcyB0aGlzIHNjcm9sbCBzdHJhdGVneSB0byBhIHZpZXdwb3J0LlxuICAgKiBAcGFyYW0gdmlld3BvcnQgVGhlIHZpZXdwb3J0IHRvIGF0dGFjaCB0aGlzIHN0cmF0ZWd5IHRvLlxuICAgKi9cbiAgYXR0YWNoKHZpZXdwb3J0OiBDZGtWaXJ0dWFsU2Nyb2xsVmlld3BvcnQpIHtcbiAgICB0aGlzLl92aWV3cG9ydCA9IHZpZXdwb3J0O1xuICAgIHRoaXMuX3VwZGF0ZVRvdGFsQ29udGVudFNpemUoKTtcbiAgICB0aGlzLl91cGRhdGVSZW5kZXJlZFJhbmdlKCk7XG4gIH1cblxuICAvKiogRGV0YWNoZXMgdGhpcyBzY3JvbGwgc3RyYXRlZ3kgZnJvbSB0aGUgY3VycmVudGx5IGF0dGFjaGVkIHZpZXdwb3J0LiAqL1xuICBkZXRhY2goKSB7XG4gICAgdGhpcy5fc2Nyb2xsZWRJbmRleENoYW5nZS5jb21wbGV0ZSgpO1xuICAgIHRoaXMuX3ZpZXdwb3J0ID0gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGUgdGhlIGl0ZW0gc2l6ZSBhbmQgYnVmZmVyIHNpemUuXG4gICAqIEBwYXJhbSBpdGVtU2l6ZSBUaGUgc2l6ZSBvZiB0aGUgaXRlbXMgaW4gdGhlIHZpcnR1YWxseSBzY3JvbGxpbmcgbGlzdC5cbiAgICogQHBhcmFtIG1pbkJ1ZmZlclB4IFRoZSBtaW5pbXVtIGFtb3VudCBvZiBidWZmZXIgKGluIHBpeGVscykgYmVmb3JlIG5lZWRpbmcgdG8gcmVuZGVyIG1vcmVcbiAgICogQHBhcmFtIG1heEJ1ZmZlclB4IFRoZSBhbW91bnQgb2YgYnVmZmVyIChpbiBwaXhlbHMpIHRvIHJlbmRlciB3aGVuIHJlbmRlcmluZyBtb3JlLlxuICAgKi9cbiAgdXBkYXRlSXRlbUFuZEJ1ZmZlclNpemUoaXRlbVNpemU6IG51bWJlciwgbWluQnVmZmVyUHg6IG51bWJlciwgbWF4QnVmZmVyUHg6IG51bWJlcikge1xuICAgIGlmIChtYXhCdWZmZXJQeCA8IG1pbkJ1ZmZlclB4ICYmICh0eXBlb2YgbmdEZXZNb2RlID09PSAndW5kZWZpbmVkJyB8fCBuZ0Rldk1vZGUpKSB7XG4gICAgICB0aHJvdyBFcnJvcignQ0RLIHZpcnR1YWwgc2Nyb2xsOiBtYXhCdWZmZXJQeCBtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byBtaW5CdWZmZXJQeCcpO1xuICAgIH1cbiAgICB0aGlzLl9pdGVtU2l6ZSA9IGl0ZW1TaXplO1xuICAgIHRoaXMuX21pbkJ1ZmZlclB4ID0gbWluQnVmZmVyUHg7XG4gICAgdGhpcy5fbWF4QnVmZmVyUHggPSBtYXhCdWZmZXJQeDtcbiAgICB0aGlzLl91cGRhdGVUb3RhbENvbnRlbnRTaXplKCk7XG4gICAgdGhpcy5fdXBkYXRlUmVuZGVyZWRSYW5nZSgpO1xuICB9XG5cbiAgLyoqIEBkb2NzLXByaXZhdGUgSW1wbGVtZW50ZWQgYXMgcGFydCBvZiBWaXJ0dWFsU2Nyb2xsU3RyYXRlZ3kuICovXG4gIG9uQ29udGVudFNjcm9sbGVkKCkge1xuICAgIHRoaXMuX3VwZGF0ZVJlbmRlcmVkUmFuZ2UoKTtcbiAgfVxuXG4gIC8qKiBAZG9jcy1wcml2YXRlIEltcGxlbWVudGVkIGFzIHBhcnQgb2YgVmlydHVhbFNjcm9sbFN0cmF0ZWd5LiAqL1xuICBvbkRhdGFMZW5ndGhDaGFuZ2VkKCkge1xuICAgIHRoaXMuX3VwZGF0ZVRvdGFsQ29udGVudFNpemUoKTtcbiAgICB0aGlzLl91cGRhdGVSZW5kZXJlZFJhbmdlKCk7XG4gIH1cblxuICAvKiogQGRvY3MtcHJpdmF0ZSBJbXBsZW1lbnRlZCBhcyBwYXJ0IG9mIFZpcnR1YWxTY3JvbGxTdHJhdGVneS4gKi9cbiAgb25Db250ZW50UmVuZGVyZWQoKSB7IC8qIG5vLW9wICovIH1cblxuICAvKiogQGRvY3MtcHJpdmF0ZSBJbXBsZW1lbnRlZCBhcyBwYXJ0IG9mIFZpcnR1YWxTY3JvbGxTdHJhdGVneS4gKi9cbiAgb25SZW5kZXJlZE9mZnNldENoYW5nZWQoKSB7IC8qIG5vLW9wICovIH1cblxuICAvKipcbiAgICogU2Nyb2xsIHRvIHRoZSBvZmZzZXQgZm9yIHRoZSBnaXZlbiBpbmRleC5cbiAgICogQHBhcmFtIGluZGV4IFRoZSBpbmRleCBvZiB0aGUgZWxlbWVudCB0byBzY3JvbGwgdG8uXG4gICAqIEBwYXJhbSBiZWhhdmlvciBUaGUgU2Nyb2xsQmVoYXZpb3IgdG8gdXNlIHdoZW4gc2Nyb2xsaW5nLlxuICAgKi9cbiAgc2Nyb2xsVG9JbmRleChpbmRleDogbnVtYmVyLCBiZWhhdmlvcjogU2Nyb2xsQmVoYXZpb3IpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5fdmlld3BvcnQpIHtcbiAgICAgIHRoaXMuX3ZpZXdwb3J0LnNjcm9sbFRvT2Zmc2V0KGluZGV4ICogdGhpcy5faXRlbVNpemUsIGJlaGF2aW9yKTtcbiAgICB9XG4gIH1cblxuICAvKiogVXBkYXRlIHRoZSB2aWV3cG9ydCdzIHRvdGFsIGNvbnRlbnQgc2l6ZS4gKi9cbiAgcHJpdmF0ZSBfdXBkYXRlVG90YWxDb250ZW50U2l6ZSgpIHtcbiAgICBpZiAoIXRoaXMuX3ZpZXdwb3J0KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5fdmlld3BvcnQuc2V0VG90YWxDb250ZW50U2l6ZSh0aGlzLl92aWV3cG9ydC5nZXREYXRhTGVuZ3RoKCkgKiB0aGlzLl9pdGVtU2l6ZSk7XG4gIH1cblxuICAvKiogVXBkYXRlIHRoZSB2aWV3cG9ydCdzIHJlbmRlcmVkIHJhbmdlLiAqL1xuICBwcml2YXRlIF91cGRhdGVSZW5kZXJlZFJhbmdlKCkge1xuICAgIGlmICghdGhpcy5fdmlld3BvcnQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCByZW5kZXJlZFJhbmdlID0gdGhpcy5fdmlld3BvcnQuZ2V0UmVuZGVyZWRSYW5nZSgpO1xuICAgIGNvbnN0IG5ld1JhbmdlID0ge3N0YXJ0OiByZW5kZXJlZFJhbmdlLnN0YXJ0LCBlbmQ6IHJlbmRlcmVkUmFuZ2UuZW5kfTtcbiAgICBjb25zdCB2aWV3cG9ydFNpemUgPSB0aGlzLl92aWV3cG9ydC5nZXRWaWV3cG9ydFNpemUoKTtcbiAgICBjb25zdCBkYXRhTGVuZ3RoID0gdGhpcy5fdmlld3BvcnQuZ2V0RGF0YUxlbmd0aCgpO1xuICAgIGxldCBzY3JvbGxPZmZzZXQgPSB0aGlzLl92aWV3cG9ydC5tZWFzdXJlU2Nyb2xsT2Zmc2V0KCk7XG4gICAgIC8vIFByZXZlbnQgTmFOIGFzIHJlc3VsdCB3aGVuIGRpdmlkaW5nIGJ5IHplcm8uXG4gICAgbGV0IGZpcnN0VmlzaWJsZUluZGV4ID0gKHRoaXMuX2l0ZW1TaXplID4gMCkgPyBzY3JvbGxPZmZzZXQgLyB0aGlzLl9pdGVtU2l6ZSA6IDA7XG5cbiAgICAvLyBJZiB1c2VyIHNjcm9sbHMgdG8gdGhlIGJvdHRvbSBvZiB0aGUgbGlzdCBhbmQgZGF0YSBjaGFuZ2VzIHRvIGEgc21hbGxlciBsaXN0XG4gICAgaWYgKG5ld1JhbmdlLmVuZCA+IGRhdGFMZW5ndGgpIHtcbiAgICAgIC8vIFdlIGhhdmUgdG8gcmVjYWxjdWxhdGUgdGhlIGZpcnN0IHZpc2libGUgaW5kZXggYmFzZWQgb24gbmV3IGRhdGEgbGVuZ3RoIGFuZCB2aWV3cG9ydCBzaXplLlxuICAgICAgY29uc3QgbWF4VmlzaWJsZUl0ZW1zID0gTWF0aC5jZWlsKHZpZXdwb3J0U2l6ZSAvIHRoaXMuX2l0ZW1TaXplKTtcbiAgICAgIGNvbnN0IG5ld1Zpc2libGVJbmRleCA9IE1hdGgubWF4KDAsXG4gICAgICAgICAgTWF0aC5taW4oZmlyc3RWaXNpYmxlSW5kZXgsIGRhdGFMZW5ndGggLSBtYXhWaXNpYmxlSXRlbXMpKTtcblxuICAgICAgLy8gSWYgZmlyc3QgdmlzaWJsZSBpbmRleCBjaGFuZ2VkIHdlIG11c3QgdXBkYXRlIHNjcm9sbCBvZmZzZXQgdG8gaGFuZGxlIHN0YXJ0L2VuZCBidWZmZXJzXG4gICAgICAvLyBDdXJyZW50IHJhbmdlIG11c3QgYWxzbyBiZSBhZGp1c3RlZCB0byBjb3ZlciB0aGUgbmV3IHBvc2l0aW9uIChib3R0b20gb2YgbmV3IGxpc3QpLlxuICAgICAgaWYgKGZpcnN0VmlzaWJsZUluZGV4ICE9IG5ld1Zpc2libGVJbmRleCkge1xuICAgICAgICBmaXJzdFZpc2libGVJbmRleCA9IG5ld1Zpc2libGVJbmRleDtcbiAgICAgICAgc2Nyb2xsT2Zmc2V0ID0gbmV3VmlzaWJsZUluZGV4ICogdGhpcy5faXRlbVNpemU7XG4gICAgICAgIG5ld1JhbmdlLnN0YXJ0ID0gTWF0aC5mbG9vcihmaXJzdFZpc2libGVJbmRleCk7XG4gICAgICB9XG5cbiAgICAgIG5ld1JhbmdlLmVuZCA9IE1hdGgubWF4KDAsIE1hdGgubWluKGRhdGFMZW5ndGgsIG5ld1JhbmdlLnN0YXJ0ICsgbWF4VmlzaWJsZUl0ZW1zKSk7XG4gICAgfVxuXG4gICAgY29uc3Qgc3RhcnRCdWZmZXIgPSBzY3JvbGxPZmZzZXQgLSBuZXdSYW5nZS5zdGFydCAqIHRoaXMuX2l0ZW1TaXplO1xuICAgIGlmIChzdGFydEJ1ZmZlciA8IHRoaXMuX21pbkJ1ZmZlclB4ICYmIG5ld1JhbmdlLnN0YXJ0ICE9IDApIHtcbiAgICAgIGNvbnN0IGV4cGFuZFN0YXJ0ID0gTWF0aC5jZWlsKCh0aGlzLl9tYXhCdWZmZXJQeCAtIHN0YXJ0QnVmZmVyKSAvIHRoaXMuX2l0ZW1TaXplKTtcbiAgICAgIG5ld1JhbmdlLnN0YXJ0ID0gTWF0aC5tYXgoMCwgbmV3UmFuZ2Uuc3RhcnQgLSBleHBhbmRTdGFydCk7XG4gICAgICBuZXdSYW5nZS5lbmQgPSBNYXRoLm1pbihkYXRhTGVuZ3RoLFxuICAgICAgICAgIE1hdGguY2VpbChmaXJzdFZpc2libGVJbmRleCArICh2aWV3cG9ydFNpemUgKyB0aGlzLl9taW5CdWZmZXJQeCkgLyB0aGlzLl9pdGVtU2l6ZSkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBlbmRCdWZmZXIgPSBuZXdSYW5nZS5lbmQgKiB0aGlzLl9pdGVtU2l6ZSAtIChzY3JvbGxPZmZzZXQgKyB2aWV3cG9ydFNpemUpO1xuICAgICAgaWYgKGVuZEJ1ZmZlciA8IHRoaXMuX21pbkJ1ZmZlclB4ICYmIG5ld1JhbmdlLmVuZCAhPSBkYXRhTGVuZ3RoKSB7XG4gICAgICAgIGNvbnN0IGV4cGFuZEVuZCA9IE1hdGguY2VpbCgodGhpcy5fbWF4QnVmZmVyUHggLSBlbmRCdWZmZXIpIC8gdGhpcy5faXRlbVNpemUpO1xuICAgICAgICBpZiAoZXhwYW5kRW5kID4gMCkge1xuICAgICAgICAgIG5ld1JhbmdlLmVuZCA9IE1hdGgubWluKGRhdGFMZW5ndGgsIG5ld1JhbmdlLmVuZCArIGV4cGFuZEVuZCk7XG4gICAgICAgICAgbmV3UmFuZ2Uuc3RhcnQgPSBNYXRoLm1heCgwLFxuICAgICAgICAgICAgICBNYXRoLmZsb29yKGZpcnN0VmlzaWJsZUluZGV4IC0gdGhpcy5fbWluQnVmZmVyUHggLyB0aGlzLl9pdGVtU2l6ZSkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5fdmlld3BvcnQuc2V0UmVuZGVyZWRSYW5nZShuZXdSYW5nZSk7XG4gICAgdGhpcy5fdmlld3BvcnQuc2V0UmVuZGVyZWRDb250ZW50T2Zmc2V0KHRoaXMuX2l0ZW1TaXplICogbmV3UmFuZ2Uuc3RhcnQpO1xuICAgIHRoaXMuX3Njcm9sbGVkSW5kZXhDaGFuZ2UubmV4dChNYXRoLmZsb29yKGZpcnN0VmlzaWJsZUluZGV4KSk7XG4gIH1cbn1cblxuXG4vKipcbiAqIFByb3ZpZGVyIGZhY3RvcnkgZm9yIGBGaXhlZFNpemVWaXJ0dWFsU2Nyb2xsU3RyYXRlZ3lgIHRoYXQgc2ltcGx5IGV4dHJhY3RzIHRoZSBhbHJlYWR5IGNyZWF0ZWRcbiAqIGBGaXhlZFNpemVWaXJ0dWFsU2Nyb2xsU3RyYXRlZ3lgIGZyb20gdGhlIGdpdmVuIGRpcmVjdGl2ZS5cbiAqIEBwYXJhbSBmaXhlZFNpemVEaXIgVGhlIGluc3RhbmNlIG9mIGBDZGtGaXhlZFNpemVWaXJ0dWFsU2Nyb2xsYCB0byBleHRyYWN0IHRoZVxuICogICAgIGBGaXhlZFNpemVWaXJ0dWFsU2Nyb2xsU3RyYXRlZ3lgIGZyb20uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBfZml4ZWRTaXplVmlydHVhbFNjcm9sbFN0cmF0ZWd5RmFjdG9yeShmaXhlZFNpemVEaXI6IENka0ZpeGVkU2l6ZVZpcnR1YWxTY3JvbGwpIHtcbiAgcmV0dXJuIGZpeGVkU2l6ZURpci5fc2Nyb2xsU3RyYXRlZ3k7XG59XG5cblxuLyoqIEEgdmlydHVhbCBzY3JvbGwgc3RyYXRlZ3kgdGhhdCBzdXBwb3J0cyBmaXhlZC1zaXplIGl0ZW1zLiAqL1xuQERpcmVjdGl2ZSh7XG4gIHNlbGVjdG9yOiAnY2RrLXZpcnR1YWwtc2Nyb2xsLXZpZXdwb3J0W2l0ZW1TaXplXScsXG4gIHByb3ZpZGVyczogW3tcbiAgICBwcm92aWRlOiBWSVJUVUFMX1NDUk9MTF9TVFJBVEVHWSxcbiAgICB1c2VGYWN0b3J5OiBfZml4ZWRTaXplVmlydHVhbFNjcm9sbFN0cmF0ZWd5RmFjdG9yeSxcbiAgICBkZXBzOiBbZm9yd2FyZFJlZigoKSA9PiBDZGtGaXhlZFNpemVWaXJ0dWFsU2Nyb2xsKV0sXG4gIH1dLFxufSlcbmV4cG9ydCBjbGFzcyBDZGtGaXhlZFNpemVWaXJ0dWFsU2Nyb2xsIGltcGxlbWVudHMgT25DaGFuZ2VzIHtcbiAgLyoqIFRoZSBzaXplIG9mIHRoZSBpdGVtcyBpbiB0aGUgbGlzdCAoaW4gcGl4ZWxzKS4gKi9cbiAgQElucHV0KClcbiAgZ2V0IGl0ZW1TaXplKCk6IG51bWJlciB7IHJldHVybiB0aGlzLl9pdGVtU2l6ZTsgfVxuICBzZXQgaXRlbVNpemUodmFsdWU6IG51bWJlcikgeyB0aGlzLl9pdGVtU2l6ZSA9IGNvZXJjZU51bWJlclByb3BlcnR5KHZhbHVlKTsgfVxuICBfaXRlbVNpemUgPSAyMDtcblxuICAvKipcbiAgICogVGhlIG1pbmltdW0gYW1vdW50IG9mIGJ1ZmZlciByZW5kZXJlZCBiZXlvbmQgdGhlIHZpZXdwb3J0IChpbiBwaXhlbHMpLlxuICAgKiBJZiB0aGUgYW1vdW50IG9mIGJ1ZmZlciBkaXBzIGJlbG93IHRoaXMgbnVtYmVyLCBtb3JlIGl0ZW1zIHdpbGwgYmUgcmVuZGVyZWQuIERlZmF1bHRzIHRvIDEwMHB4LlxuICAgKi9cbiAgQElucHV0KClcbiAgZ2V0IG1pbkJ1ZmZlclB4KCk6IG51bWJlciB7IHJldHVybiB0aGlzLl9taW5CdWZmZXJQeDsgfVxuICBzZXQgbWluQnVmZmVyUHgodmFsdWU6IG51bWJlcikgeyB0aGlzLl9taW5CdWZmZXJQeCA9IGNvZXJjZU51bWJlclByb3BlcnR5KHZhbHVlKTsgfVxuICBfbWluQnVmZmVyUHggPSAxMDA7XG5cbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgcGl4ZWxzIHdvcnRoIG9mIGJ1ZmZlciB0byByZW5kZXIgZm9yIHdoZW4gcmVuZGVyaW5nIG5ldyBpdGVtcy4gRGVmYXVsdHMgdG8gMjAwcHguXG4gICAqL1xuICBASW5wdXQoKVxuICBnZXQgbWF4QnVmZmVyUHgoKTogbnVtYmVyIHsgcmV0dXJuIHRoaXMuX21heEJ1ZmZlclB4OyB9XG4gIHNldCBtYXhCdWZmZXJQeCh2YWx1ZTogbnVtYmVyKSB7IHRoaXMuX21heEJ1ZmZlclB4ID0gY29lcmNlTnVtYmVyUHJvcGVydHkodmFsdWUpOyB9XG4gIF9tYXhCdWZmZXJQeCA9IDIwMDtcblxuICAvKiogVGhlIHNjcm9sbCBzdHJhdGVneSB1c2VkIGJ5IHRoaXMgZGlyZWN0aXZlLiAqL1xuICBfc2Nyb2xsU3RyYXRlZ3kgPVxuICAgICAgbmV3IEZpeGVkU2l6ZVZpcnR1YWxTY3JvbGxTdHJhdGVneSh0aGlzLml0ZW1TaXplLCB0aGlzLm1pbkJ1ZmZlclB4LCB0aGlzLm1heEJ1ZmZlclB4KTtcblxuICBuZ09uQ2hhbmdlcygpIHtcbiAgICB0aGlzLl9zY3JvbGxTdHJhdGVneS51cGRhdGVJdGVtQW5kQnVmZmVyU2l6ZSh0aGlzLml0ZW1TaXplLCB0aGlzLm1pbkJ1ZmZlclB4LCB0aGlzLm1heEJ1ZmZlclB4KTtcbiAgfVxuXG4gIHN0YXRpYyBuZ0FjY2VwdElucHV0VHlwZV9pdGVtU2l6ZTogTnVtYmVySW5wdXQ7XG4gIHN0YXRpYyBuZ0FjY2VwdElucHV0VHlwZV9taW5CdWZmZXJQeDogTnVtYmVySW5wdXQ7XG4gIHN0YXRpYyBuZ0FjY2VwdElucHV0VHlwZV9tYXhCdWZmZXJQeDogTnVtYmVySW5wdXQ7XG59XG4iXX0=