1 | /**
|
2 | * @license
|
3 | * Copyright Google LLC All Rights Reserved.
|
4 | *
|
5 | * Use of this source code is governed by an MIT-style license that can be
|
6 | * found in the LICENSE file at https://angular.io/license
|
7 | */
|
8 | import { Directionality } from '@angular/cdk/bidi';
|
9 | import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Inject, Input, NgZone, Optional, Output, ViewChild, ViewEncapsulation, } from '@angular/core';
|
10 | import { animationFrameScheduler, asapScheduler, Observable, Subject, Subscription, } from 'rxjs';
|
11 | import { auditTime, startWith, takeUntil } from 'rxjs/operators';
|
12 | import { ScrollDispatcher } from './scroll-dispatcher';
|
13 | import { CdkScrollable } from './scrollable';
|
14 | import { VIRTUAL_SCROLL_STRATEGY } from './virtual-scroll-strategy';
|
15 | import { ViewportRuler } from './viewport-ruler';
|
16 | import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
17 | import { CdkVirtualScrollable, VIRTUAL_SCROLLABLE } from './virtual-scrollable';
|
18 | import * as i0 from "@angular/core";
|
19 | import * as i1 from "@angular/cdk/bidi";
|
20 | import * as i2 from "./scroll-dispatcher";
|
21 | import * as i3 from "./viewport-ruler";
|
22 | import * as i4 from "./virtual-scrollable";
|
23 | /** Checks if the given ranges are equal. */
|
24 | function rangesEqual(r1, r2) {
|
25 | return r1.start == r2.start && r1.end == r2.end;
|
26 | }
|
27 | /**
|
28 | * Scheduler to be used for scroll events. Needs to fall back to
|
29 | * something that doesn't rely on requestAnimationFrame on environments
|
30 | * that don't support it (e.g. server-side rendering).
|
31 | */
|
32 | const SCROLL_SCHEDULER = typeof requestAnimationFrame !== 'undefined' ? animationFrameScheduler : asapScheduler;
|
33 | /** A viewport that virtualizes its scrolling with the help of `CdkVirtualForOf`. */
|
34 | export class CdkVirtualScrollViewport extends CdkVirtualScrollable {
|
35 | constructor(elementRef, _changeDetectorRef, ngZone, _scrollStrategy, dir, scrollDispatcher, viewportRuler, scrollable) {
|
36 | super(elementRef, scrollDispatcher, ngZone, dir);
|
37 | this.elementRef = elementRef;
|
38 | this._changeDetectorRef = _changeDetectorRef;
|
39 | this._scrollStrategy = _scrollStrategy;
|
40 | this.scrollable = scrollable;
|
41 | /** Emits when the viewport is detached from a CdkVirtualForOf. */
|
42 | this._detachedSubject = new Subject();
|
43 | /** Emits when the rendered range changes. */
|
44 | this._renderedRangeSubject = new Subject();
|
45 | this._orientation = 'vertical';
|
46 | this._appendOnly = false;
|
47 | // Note: we don't use the typical EventEmitter here because we need to subscribe to the scroll
|
48 | // strategy lazily (i.e. only if the user is actually listening to the events). We do this because
|
49 | // depending on how the strategy calculates the scrolled index, it may come at a cost to
|
50 | // performance.
|
51 | /** Emits when the index of the first element visible in the viewport changes. */
|
52 | this.scrolledIndexChange = new Observable((observer) => this._scrollStrategy.scrolledIndexChange.subscribe(index => Promise.resolve().then(() => this.ngZone.run(() => observer.next(index)))));
|
53 | /** A stream that emits whenever the rendered range changes. */
|
54 | this.renderedRangeStream = this._renderedRangeSubject;
|
55 | /**
|
56 | * The total size of all content (in pixels), including content that is not currently rendered.
|
57 | */
|
58 | this._totalContentSize = 0;
|
59 | /** A string representing the `style.width` property value to be used for the spacer element. */
|
60 | this._totalContentWidth = '';
|
61 | /** A string representing the `style.height` property value to be used for the spacer element. */
|
62 | this._totalContentHeight = '';
|
63 | /** The currently rendered range of indices. */
|
64 | this._renderedRange = { start: 0, end: 0 };
|
65 | /** The length of the data bound to this viewport (in number of items). */
|
66 | this._dataLength = 0;
|
67 | /** The size of the viewport (in pixels). */
|
68 | this._viewportSize = 0;
|
69 | /** The last rendered content offset that was set. */
|
70 | this._renderedContentOffset = 0;
|
71 | /**
|
72 | * Whether the last rendered content offset was to the end of the content (and therefore needs to
|
73 | * be rewritten as an offset to the start of the content).
|
74 | */
|
75 | this._renderedContentOffsetNeedsRewrite = false;
|
76 | /** Whether there is a pending change detection cycle. */
|
77 | this._isChangeDetectionPending = false;
|
78 | /** A list of functions to run after the next change detection cycle. */
|
79 | this._runAfterChangeDetection = [];
|
80 | /** Subscription to changes in the viewport size. */
|
81 | this._viewportChanges = Subscription.EMPTY;
|
82 | if (!_scrollStrategy && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
83 | throw Error('Error: cdk-virtual-scroll-viewport requires the "itemSize" property to be set.');
|
84 | }
|
85 | this._viewportChanges = viewportRuler.change().subscribe(() => {
|
86 | this.checkViewportSize();
|
87 | });
|
88 | if (!this.scrollable) {
|
89 | // No scrollable is provided, so the virtual-scroll-viewport needs to become a scrollable
|
90 | this.elementRef.nativeElement.classList.add('cdk-virtual-scrollable');
|
91 | this.scrollable = this;
|
92 | }
|
93 | }
|
94 | /** The direction the viewport scrolls. */
|
95 | get orientation() {
|
96 | return this._orientation;
|
97 | }
|
98 | set orientation(orientation) {
|
99 | if (this._orientation !== orientation) {
|
100 | this._orientation = orientation;
|
101 | this._calculateSpacerSize();
|
102 | }
|
103 | }
|
104 | /**
|
105 | * Whether rendered items should persist in the DOM after scrolling out of view. By default, items
|
106 | * will be removed.
|
107 | */
|
108 | get appendOnly() {
|
109 | return this._appendOnly;
|
110 | }
|
111 | set appendOnly(value) {
|
112 | this._appendOnly = coerceBooleanProperty(value);
|
113 | }
|
114 | ngOnInit() {
|
115 | if (this.scrollable === this) {
|
116 | super.ngOnInit();
|
117 | }
|
118 | // It's still too early to measure the viewport at this point. Deferring with a promise allows
|
119 | // the Viewport to be rendered with the correct size before we measure. We run this outside the
|
120 | // zone to avoid causing more change detection cycles. We handle the change detection loop
|
121 | // ourselves instead.
|
122 | this.ngZone.runOutsideAngular(() => Promise.resolve().then(() => {
|
123 | this._measureViewportSize();
|
124 | this._scrollStrategy.attach(this);
|
125 | this.scrollable
|
126 | .elementScrolled()
|
127 | .pipe(
|
128 | // Start off with a fake scroll event so we properly detect our initial position.
|
129 | startWith(null),
|
130 | // Collect multiple events into one until the next animation frame. This way if
|
131 | // there are multiple scroll events in the same frame we only need to recheck
|
132 | // our layout once.
|
133 | auditTime(0, SCROLL_SCHEDULER))
|
134 | .subscribe(() => this._scrollStrategy.onContentScrolled());
|
135 | this._markChangeDetectionNeeded();
|
136 | }));
|
137 | }
|
138 | ngOnDestroy() {
|
139 | this.detach();
|
140 | this._scrollStrategy.detach();
|
141 | // Complete all subjects
|
142 | this._renderedRangeSubject.complete();
|
143 | this._detachedSubject.complete();
|
144 | this._viewportChanges.unsubscribe();
|
145 | super.ngOnDestroy();
|
146 | }
|
147 | /** Attaches a `CdkVirtualScrollRepeater` to this viewport. */
|
148 | attach(forOf) {
|
149 | if (this._forOf && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
150 | throw Error('CdkVirtualScrollViewport is already attached.');
|
151 | }
|
152 | // Subscribe to the data stream of the CdkVirtualForOf to keep track of when the data length
|
153 | // changes. Run outside the zone to avoid triggering change detection, since we're managing the
|
154 | // change detection loop ourselves.
|
155 | this.ngZone.runOutsideAngular(() => {
|
156 | this._forOf = forOf;
|
157 | this._forOf.dataStream.pipe(takeUntil(this._detachedSubject)).subscribe(data => {
|
158 | const newLength = data.length;
|
159 | if (newLength !== this._dataLength) {
|
160 | this._dataLength = newLength;
|
161 | this._scrollStrategy.onDataLengthChanged();
|
162 | }
|
163 | this._doChangeDetection();
|
164 | });
|
165 | });
|
166 | }
|
167 | /** Detaches the current `CdkVirtualForOf`. */
|
168 | detach() {
|
169 | this._forOf = null;
|
170 | this._detachedSubject.next();
|
171 | }
|
172 | /** Gets the length of the data bound to this viewport (in number of items). */
|
173 | getDataLength() {
|
174 | return this._dataLength;
|
175 | }
|
176 | /** Gets the size of the viewport (in pixels). */
|
177 | getViewportSize() {
|
178 | return this._viewportSize;
|
179 | }
|
180 | // TODO(mmalerba): This is technically out of sync with what's really rendered until a render
|
181 | // cycle happens. I'm being careful to only call it after the render cycle is complete and before
|
182 | // setting it to something else, but its error prone and should probably be split into
|
183 | // `pendingRange` and `renderedRange`, the latter reflecting whats actually in the DOM.
|
184 | /** Get the current rendered range of items. */
|
185 | getRenderedRange() {
|
186 | return this._renderedRange;
|
187 | }
|
188 | measureBoundingClientRectWithScrollOffset(from) {
|
189 | return this.getElementRef().nativeElement.getBoundingClientRect()[from];
|
190 | }
|
191 | /**
|
192 | * Sets the total size of all content (in pixels), including content that is not currently
|
193 | * rendered.
|
194 | */
|
195 | setTotalContentSize(size) {
|
196 | if (this._totalContentSize !== size) {
|
197 | this._totalContentSize = size;
|
198 | this._calculateSpacerSize();
|
199 | this._markChangeDetectionNeeded();
|
200 | }
|
201 | }
|
202 | /** Sets the currently rendered range of indices. */
|
203 | setRenderedRange(range) {
|
204 | if (!rangesEqual(this._renderedRange, range)) {
|
205 | if (this.appendOnly) {
|
206 | range = { start: 0, end: Math.max(this._renderedRange.end, range.end) };
|
207 | }
|
208 | this._renderedRangeSubject.next((this._renderedRange = range));
|
209 | this._markChangeDetectionNeeded(() => this._scrollStrategy.onContentRendered());
|
210 | }
|
211 | }
|
212 | /**
|
213 | * Gets the offset from the start of the viewport to the start of the rendered data (in pixels).
|
214 | */
|
215 | getOffsetToRenderedContentStart() {
|
216 | return this._renderedContentOffsetNeedsRewrite ? null : this._renderedContentOffset;
|
217 | }
|
218 | /**
|
219 | * Sets the offset from the start of the viewport to either the start or end of the rendered data
|
220 | * (in pixels).
|
221 | */
|
222 | setRenderedContentOffset(offset, to = 'to-start') {
|
223 | // In appendOnly, we always start from the top
|
224 | offset = this.appendOnly && to === 'to-start' ? 0 : offset;
|
225 | // For a horizontal viewport in a right-to-left language we need to translate along the x-axis
|
226 | // in the negative direction.
|
227 | const isRtl = this.dir && this.dir.value == 'rtl';
|
228 | const isHorizontal = this.orientation == 'horizontal';
|
229 | const axis = isHorizontal ? 'X' : 'Y';
|
230 | const axisDirection = isHorizontal && isRtl ? -1 : 1;
|
231 | let transform = `translate${axis}(${Number(axisDirection * offset)}px)`;
|
232 | this._renderedContentOffset = offset;
|
233 | if (to === 'to-end') {
|
234 | transform += ` translate${axis}(-100%)`;
|
235 | // The viewport should rewrite this as a `to-start` offset on the next render cycle. Otherwise
|
236 | // elements will appear to expand in the wrong direction (e.g. `mat-expansion-panel` would
|
237 | // expand upward).
|
238 | this._renderedContentOffsetNeedsRewrite = true;
|
239 | }
|
240 | if (this._renderedContentTransform != transform) {
|
241 | // We know this value is safe because we parse `offset` with `Number()` before passing it
|
242 | // into the string.
|
243 | this._renderedContentTransform = transform;
|
244 | this._markChangeDetectionNeeded(() => {
|
245 | if (this._renderedContentOffsetNeedsRewrite) {
|
246 | this._renderedContentOffset -= this.measureRenderedContentSize();
|
247 | this._renderedContentOffsetNeedsRewrite = false;
|
248 | this.setRenderedContentOffset(this._renderedContentOffset);
|
249 | }
|
250 | else {
|
251 | this._scrollStrategy.onRenderedOffsetChanged();
|
252 | }
|
253 | });
|
254 | }
|
255 | }
|
256 | /**
|
257 | * Scrolls to the given offset from the start of the viewport. Please note that this is not always
|
258 | * the same as setting `scrollTop` or `scrollLeft`. In a horizontal viewport with right-to-left
|
259 | * direction, this would be the equivalent of setting a fictional `scrollRight` property.
|
260 | * @param offset The offset to scroll to.
|
261 | * @param behavior The ScrollBehavior to use when scrolling. Default is behavior is `auto`.
|
262 | */
|
263 | scrollToOffset(offset, behavior = 'auto') {
|
264 | const options = { behavior };
|
265 | if (this.orientation === 'horizontal') {
|
266 | options.start = offset;
|
267 | }
|
268 | else {
|
269 | options.top = offset;
|
270 | }
|
271 | this.scrollable.scrollTo(options);
|
272 | }
|
273 | /**
|
274 | * Scrolls to the offset for the given index.
|
275 | * @param index The index of the element to scroll to.
|
276 | * @param behavior The ScrollBehavior to use when scrolling. Default is behavior is `auto`.
|
277 | */
|
278 | scrollToIndex(index, behavior = 'auto') {
|
279 | this._scrollStrategy.scrollToIndex(index, behavior);
|
280 | }
|
281 | /**
|
282 | * Gets the current scroll offset from the start of the scrollable (in pixels).
|
283 | * @param from The edge to measure the offset from. Defaults to 'top' in vertical mode and 'start'
|
284 | * in horizontal mode.
|
285 | */
|
286 | measureScrollOffset(from) {
|
287 | // This is to break the call cycle
|
288 | let measureScrollOffset;
|
289 | if (this.scrollable == this) {
|
290 | measureScrollOffset = (_from) => super.measureScrollOffset(_from);
|
291 | }
|
292 | else {
|
293 | measureScrollOffset = (_from) => this.scrollable.measureScrollOffset(_from);
|
294 | }
|
295 | return Math.max(0, measureScrollOffset(from ?? (this.orientation === 'horizontal' ? 'start' : 'top')) -
|
296 | this.measureViewportOffset());
|
297 | }
|
298 | /**
|
299 | * Measures the offset of the viewport from the scrolling container
|
300 | * @param from The edge to measure from.
|
301 | */
|
302 | measureViewportOffset(from) {
|
303 | let fromRect;
|
304 | const LEFT = 'left';
|
305 | const RIGHT = 'right';
|
306 | const isRtl = this.dir?.value == 'rtl';
|
307 | if (from == 'start') {
|
308 | fromRect = isRtl ? RIGHT : LEFT;
|
309 | }
|
310 | else if (from == 'end') {
|
311 | fromRect = isRtl ? LEFT : RIGHT;
|
312 | }
|
313 | else if (from) {
|
314 | fromRect = from;
|
315 | }
|
316 | else {
|
317 | fromRect = this.orientation === 'horizontal' ? 'left' : 'top';
|
318 | }
|
319 | const scrollerClientRect = this.scrollable.measureBoundingClientRectWithScrollOffset(fromRect);
|
320 | const viewportClientRect = this.elementRef.nativeElement.getBoundingClientRect()[fromRect];
|
321 | return viewportClientRect - scrollerClientRect;
|
322 | }
|
323 | /** Measure the combined size of all of the rendered items. */
|
324 | measureRenderedContentSize() {
|
325 | const contentEl = this._contentWrapper.nativeElement;
|
326 | return this.orientation === 'horizontal' ? contentEl.offsetWidth : contentEl.offsetHeight;
|
327 | }
|
328 | /**
|
329 | * Measure the total combined size of the given range. Throws if the range includes items that are
|
330 | * not rendered.
|
331 | */
|
332 | measureRangeSize(range) {
|
333 | if (!this._forOf) {
|
334 | return 0;
|
335 | }
|
336 | return this._forOf.measureRangeSize(range, this.orientation);
|
337 | }
|
338 | /** Update the viewport dimensions and re-render. */
|
339 | checkViewportSize() {
|
340 | // TODO: Cleanup later when add logic for handling content resize
|
341 | this._measureViewportSize();
|
342 | this._scrollStrategy.onDataLengthChanged();
|
343 | }
|
344 | /** Measure the viewport size. */
|
345 | _measureViewportSize() {
|
346 | this._viewportSize = this.scrollable.measureViewportSize(this.orientation);
|
347 | }
|
348 | /** Queue up change detection to run. */
|
349 | _markChangeDetectionNeeded(runAfter) {
|
350 | if (runAfter) {
|
351 | this._runAfterChangeDetection.push(runAfter);
|
352 | }
|
353 | // Use a Promise to batch together calls to `_doChangeDetection`. This way if we set a bunch of
|
354 | // properties sequentially we only have to run `_doChangeDetection` once at the end.
|
355 | if (!this._isChangeDetectionPending) {
|
356 | this._isChangeDetectionPending = true;
|
357 | this.ngZone.runOutsideAngular(() => Promise.resolve().then(() => {
|
358 | this._doChangeDetection();
|
359 | }));
|
360 | }
|
361 | }
|
362 | /** Run change detection. */
|
363 | _doChangeDetection() {
|
364 | this._isChangeDetectionPending = false;
|
365 | // Apply the content transform. The transform can't be set via an Angular binding because
|
366 | // bypassSecurityTrustStyle is banned in Google. However the value is safe, it's composed of
|
367 | // string literals, a variable that can only be 'X' or 'Y', and user input that is run through
|
368 | // the `Number` function first to coerce it to a numeric value.
|
369 | this._contentWrapper.nativeElement.style.transform = this._renderedContentTransform;
|
370 | // Apply changes to Angular bindings. Note: We must call `markForCheck` to run change detection
|
371 | // from the root, since the repeated items are content projected in. Calling `detectChanges`
|
372 | // instead does not properly check the projected content.
|
373 | this.ngZone.run(() => this._changeDetectorRef.markForCheck());
|
374 | const runAfterChangeDetection = this._runAfterChangeDetection;
|
375 | this._runAfterChangeDetection = [];
|
376 | for (const fn of runAfterChangeDetection) {
|
377 | fn();
|
378 | }
|
379 | }
|
380 | /** Calculates the `style.width` and `style.height` for the spacer element. */
|
381 | _calculateSpacerSize() {
|
382 | this._totalContentHeight =
|
383 | this.orientation === 'horizontal' ? '' : `${this._totalContentSize}px`;
|
384 | this._totalContentWidth =
|
385 | this.orientation === 'horizontal' ? `${this._totalContentSize}px` : '';
|
386 | }
|
387 | }
|
388 | CdkVirtualScrollViewport.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: CdkVirtualScrollViewport, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: VIRTUAL_SCROLL_STRATEGY, optional: true }, { token: i1.Directionality, optional: true }, { token: i2.ScrollDispatcher }, { token: i3.ViewportRuler }, { token: VIRTUAL_SCROLLABLE, optional: true }], target: i0.ɵɵFactoryTarget.Component });
|
389 | CdkVirtualScrollViewport.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: { orientation: "orientation", appendOnly: "appendOnly" }, outputs: { scrolledIndexChange: "scrolledIndexChange" }, host: { properties: { "class.cdk-virtual-scroll-orientation-horizontal": "orientation === \"horizontal\"", "class.cdk-virtual-scroll-orientation-vertical": "orientation !== \"horizontal\"" }, classAttribute: "cdk-virtual-scroll-viewport" }, providers: [
|
390 | {
|
391 | provide: CdkScrollable,
|
392 | useFactory: (virtualScrollable, viewport) => virtualScrollable || viewport,
|
393 | deps: [CdkVirtualScrollable, CdkVirtualScrollViewport],
|
394 | },
|
395 | ], viewQueries: [{ propertyName: "_contentWrapper", first: true, predicate: ["contentWrapper"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<!--\n Wrap the rendered content in an element that will be used to offset it based on the scroll\n position.\n-->\n<div #contentWrapper class=\"cdk-virtual-scroll-content-wrapper\">\n <ng-content></ng-content>\n</div>\n<!--\n Spacer used to force the scrolling container to the correct size for the *total* number of items\n so that the scrollbar captures the size of the entire data set.\n-->\n<div class=\"cdk-virtual-scroll-spacer\"\n [style.width]=\"_totalContentWidth\" [style.height]=\"_totalContentHeight\"></div>\n", styles: ["cdk-virtual-scroll-viewport{display:block;position:relative;transform:translateZ(0)}.cdk-virtual-scrollable{overflow:auto;will-change:scroll-position;contain:strict;-webkit-overflow-scrolling:touch}.cdk-virtual-scroll-content-wrapper{position:absolute;top:0;left:0;contain:content}[dir=rtl] .cdk-virtual-scroll-content-wrapper{right:0;left:auto}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper{min-height:100%}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-left:0;padding-right:0;margin-left:0;margin-right:0;border-left-width:0;border-right-width:0;outline:none}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper{min-width:100%}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-top:0;padding-bottom:0;margin-top:0;margin-bottom:0;border-top-width:0;border-bottom-width:0;outline:none}.cdk-virtual-scroll-spacer{height:1px;transform-origin:0 0;flex:0 0 auto}[dir=rtl] .cdk-virtual-scroll-spacer{transform-origin:100% 0}"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
396 | i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: CdkVirtualScrollViewport, decorators: [{
|
397 | type: Component,
|
398 | args: [{ selector: 'cdk-virtual-scroll-viewport', host: {
|
399 | 'class': 'cdk-virtual-scroll-viewport',
|
400 | '[class.cdk-virtual-scroll-orientation-horizontal]': 'orientation === "horizontal"',
|
401 | '[class.cdk-virtual-scroll-orientation-vertical]': 'orientation !== "horizontal"',
|
402 | }, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
403 | {
|
404 | provide: CdkScrollable,
|
405 | useFactory: (virtualScrollable, viewport) => virtualScrollable || viewport,
|
406 | deps: [CdkVirtualScrollable, CdkVirtualScrollViewport],
|
407 | },
|
408 | ], template: "<!--\n Wrap the rendered content in an element that will be used to offset it based on the scroll\n position.\n-->\n<div #contentWrapper class=\"cdk-virtual-scroll-content-wrapper\">\n <ng-content></ng-content>\n</div>\n<!--\n Spacer used to force the scrolling container to the correct size for the *total* number of items\n so that the scrollbar captures the size of the entire data set.\n-->\n<div class=\"cdk-virtual-scroll-spacer\"\n [style.width]=\"_totalContentWidth\" [style.height]=\"_totalContentHeight\"></div>\n", styles: ["cdk-virtual-scroll-viewport{display:block;position:relative;transform:translateZ(0)}.cdk-virtual-scrollable{overflow:auto;will-change:scroll-position;contain:strict;-webkit-overflow-scrolling:touch}.cdk-virtual-scroll-content-wrapper{position:absolute;top:0;left:0;contain:content}[dir=rtl] .cdk-virtual-scroll-content-wrapper{right:0;left:auto}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper{min-height:100%}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-left:0;padding-right:0;margin-left:0;margin-right:0;border-left-width:0;border-right-width:0;outline:none}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper{min-width:100%}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-top:0;padding-bottom:0;margin-top:0;margin-bottom:0;border-top-width:0;border-bottom-width:0;outline:none}.cdk-virtual-scroll-spacer{height:1px;transform-origin:0 0;flex:0 0 auto}[dir=rtl] .cdk-virtual-scroll-spacer{transform-origin:100% 0}"] }]
|
409 | }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: undefined, decorators: [{
|
410 | type: Optional
|
411 | }, {
|
412 | type: Inject,
|
413 | args: [VIRTUAL_SCROLL_STRATEGY]
|
414 | }] }, { type: i1.Directionality, decorators: [{
|
415 | type: Optional
|
416 | }] }, { type: i2.ScrollDispatcher }, { type: i3.ViewportRuler }, { type: i4.CdkVirtualScrollable, decorators: [{
|
417 | type: Optional
|
418 | }, {
|
419 | type: Inject,
|
420 | args: [VIRTUAL_SCROLLABLE]
|
421 | }] }]; }, propDecorators: { orientation: [{
|
422 | type: Input
|
423 | }], appendOnly: [{
|
424 | type: Input
|
425 | }], scrolledIndexChange: [{
|
426 | type: Output
|
427 | }], _contentWrapper: [{
|
428 | type: ViewChild,
|
429 | args: ['contentWrapper', { static: true }]
|
430 | }] } });
|
431 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlydHVhbC1zY3JvbGwtdmlld3BvcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvY2RrL3Njcm9sbGluZy92aXJ0dWFsLXNjcm9sbC12aWV3cG9ydC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9jZGsvc2Nyb2xsaW5nL3ZpcnR1YWwtc2Nyb2xsLXZpZXdwb3J0Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBRUgsT0FBTyxFQUFDLGNBQWMsRUFBQyxNQUFNLG1CQUFtQixDQUFDO0FBRWpELE9BQU8sRUFDTCx1QkFBdUIsRUFDdkIsaUJBQWlCLEVBQ2pCLFNBQVMsRUFDVCxVQUFVLEVBQ1YsTUFBTSxFQUNOLEtBQUssRUFDTCxNQUFNLEVBR04sUUFBUSxFQUNSLE1BQU0sRUFDTixTQUFTLEVBQ1QsaUJBQWlCLEdBQ2xCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFDTCx1QkFBdUIsRUFDdkIsYUFBYSxFQUNiLFVBQVUsRUFDVixPQUFPLEVBRVAsWUFBWSxHQUNiLE1BQU0sTUFBTSxDQUFDO0FBQ2QsT0FBTyxFQUFDLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDL0QsT0FBTyxFQUFDLGdCQUFnQixFQUFDLE1BQU0scUJBQXFCLENBQUM7QUFDckQsT0FBTyxFQUFDLGFBQWEsRUFBMEIsTUFBTSxjQUFjLENBQUM7QUFDcEUsT0FBTyxFQUFDLHVCQUF1QixFQUF3QixNQUFNLDJCQUEyQixDQUFDO0FBQ3pGLE9BQU8sRUFBQyxhQUFhLEVBQUMsTUFBTSxrQkFBa0IsQ0FBQztBQUUvQyxPQUFPLEVBQWUscUJBQXFCLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUMxRSxPQUFPLEVBQUMsb0JBQW9CLEVBQUUsa0JBQWtCLEVBQUMsTUFBTSxzQkFBc0IsQ0FBQzs7Ozs7O0FBRTlFLDRDQUE0QztBQUM1QyxTQUFTLFdBQVcsQ0FB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QUksRUFBRSxDQUFDLG9CQUFvQixFQUFFLHdCQUF3QixDQUFDO1NBQ3ZEO0tBQ0Ysa0xDNUVILHNoQkFhQTsyRkRpRWEsd0JBQXdCO2tCQXRCcEMsU0FBUzsrQkFDRSw2QkFBNkIsUUFHakM7d0JBQ0osT0FBTyxFQUFFLDZCQUE2Qjt3QkFDdEMsbURBQW1ELEVBQUUsOEJBQThCO3dCQUNuRixpREFBaUQsRUFBRSw4QkFBOEI7cUJBQ2xGLGlCQUNjLGlCQUFpQixDQUFDLElBQUksbUJBQ3BCLHVCQUF1QixDQUFDLE1BQU0sYUFDcEM7d0JBQ1Q7NEJBQ0UsT0FBTyxFQUFFLGFBQWE7NEJBQ3RCLFVBQVUsRUFBRSxDQUNWLGlCQUE4QyxFQUM5QyxRQUFrQyxFQUNsQyxFQUFFLENBQUMsaUJBQWlCLElBQUksUUFBUTs0QkFDbEMsSUFBSSxFQUFFLENBQUMsb0JBQW9CLDJCQUEyQjt5QkFDdkQ7cUJBQ0Y7OzBCQXlHRSxRQUFROzswQkFDUixNQUFNOzJCQUFDLHVCQUF1Qjs7MEJBRTlCLFFBQVE7OzBCQUdSLFFBQVE7OzBCQUFJLE1BQU07MkJBQUMsa0JBQWtCOzRDQXBHcEMsV0FBVztzQkFEZCxLQUFLO2dCQWtCRixVQUFVO3NCQURiLEtBQUs7Z0JBZUcsbUJBQW1CO3NCQUQzQixNQUFNO2dCQVFzQyxlQUFlO3NCQUEzRCxTQUFTO3VCQUFDLGdCQUFnQixFQUFFLEVBQUMsTUFBTSxFQUFFLElBQUksRUFBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG5pbXBvcnQge0RpcmVjdGlvbmFsaXR5fSBmcm9tICdAYW5ndWxhci9jZGsvYmlkaSc7XG5pbXBvcnQge0xpc3RSYW5nZX0gZnJvbSAnQGFuZ3VsYXIvY2RrL2NvbGxlY3Rpb25zJztcbmltcG9ydCB7XG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgQ29tcG9uZW50LFxuICBFbGVtZW50UmVmLFxuICBJbmplY3QsXG4gIElucHV0LFxuICBOZ1pvbmUsXG4gIE9uRGVzdHJveSxcbiAgT25Jbml0LFxuICBPcHRpb25hbCxcbiAgT3V0cHV0LFxuICBWaWV3Q2hpbGQsXG4gIFZpZXdFbmNhcHN1bGF0aW9uLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIGFuaW1hdGlvbkZyYW1lU2NoZWR1bGVyLFxuICBhc2FwU2NoZWR1bGVyLFxuICBPYnNlcnZhYmxlLFxuICBTdWJqZWN0LFxuICBPYnNlcnZlcixcbiAgU3Vic2NyaXB0aW9uLFxufSBmcm9tICdyeGpzJztcbmltcG9ydCB7YXVkaXRUaW1lLCBzdGFydFdpdGgsIHRha2VVbnRpbH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHtTY3JvbGxEaXNwYXRjaGVyfSBmcm9tICcuL3Njcm9sbC1kaXNwYXRjaGVyJztcbmltcG9ydCB7Q2RrU2Nyb2xsYWJsZSwgRXh0ZW5kZWRTY3JvbGxUb09wdGlvbnN9IGZyb20gJy4vc2Nyb2xsYWJsZSc7XG5pbXBvcnQge1ZJUlRVQUxfU0NST0xMX1NUUkFURUdZLCBWaXJ0dWFsU2Nyb2xsU3RyYXRlZ3l9IGZyb20gJy4vdmlydHVhbC1zY3JvbGwtc3RyYXRlZ3knO1xuaW1wb3J0IHtWaWV3cG9ydFJ1bGVyfSBmcm9tICcuL3ZpZXdwb3J0LXJ1bGVyJztcbmltcG9ydCB7Q2RrVmlydHVhbFNjcm9sbFJlcGVhdGVyfSBmcm9tICcuL3ZpcnR1YWwtc2Nyb2xsLXJlcGVhdGVyJztcbmltcG9ydCB7Qm9vbGVhbklucHV0LCBjb2VyY2VCb29sZWFuUHJvcGVydHl9IGZyb20gJ0Bhbmd1bGFyL2Nkay9jb2VyY2lvbic7XG5pbXBvcnQge0Nka1ZpcnR1YWxTY3JvbGxhYmxlLCBWSVJUVUFMX1NDUk9MTEFCTEV9IGZyb20gJy4vdmlydHVhbC1zY3JvbGxhYmxlJztcblxuLyoqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gcmFuZ2VzIGFyZSBlcXVhbC4gKi9cbmZ1bmN0aW9uIHJhbmdlc0VxdWFsKHIxOiBMaXN0UmFuZ2UsIHIyOiBMaXN0UmFuZ2UpOiBib29sZWFuIHtcbiAgcmV0dXJuIHIxLnN0YXJ0ID09IHIyLnN0YXJ0ICYmIHIxLmVuZCA9PSByMi5lbmQ7XG59XG5cbi8qKlxuICogU2NoZWR1bGVyIHRvIGJlIHVzZWQgZm9yIHNjcm9sbCBldmVudHMuIE5lZWRzIHRvIGZhbGwgYmFjayB0b1xuICogc29tZXRoaW5nIHRoYXQgZG9lc24ndCByZWx5IG9uIHJlcXVlc3RBbmltYXRpb25GcmFtZSBvbiBlbnZpcm9ubWVudHNcbiAqIHRoYXQgZG9uJ3Qgc3VwcG9ydCBpdCAoZS5nLiBzZXJ2ZXItc2lkZSByZW5kZXJpbmcpLlxuICovXG5jb25zdCBTQ1JPTExfU0NIRURVTEVSID1cbiAgdHlwZW9mIHJlcXVlc3RBbmltYXRpb25GcmFtZSAhPT0gJ3VuZGVmaW5lZCcgPyBhbmltYXRpb25GcmFtZVNjaGVkdWxlciA6IGFzYXBTY2hlZHVsZXI7XG5cbi8qKiBBIHZpZXdwb3J0IHRoYXQgdmlydHVhbGl6ZXMgaXRzIHNjcm9sbGluZyB3aXRoIHRoZSBoZWxwIG9mIGBDZGtWaXJ0dWFsRm9yT2ZgLiAqL1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnY2RrLXZpcnR1YWwtc2Nyb2xsLXZpZXdwb3J0JyxcbiAgdGVtcGxhdGVVcmw6ICd2aXJ0dWFsLXNjcm9sbC12aWV3cG9ydC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJ3ZpcnR1YWwtc2Nyb2xsLXZpZXdwb3J0LmNzcyddLFxuICBob3N0OiB7XG4gICAgJ2NsYXNzJzogJ2Nkay12aXJ0dWFsLXNjcm9sbC12aWV3cG9ydCcsXG4gICAgJ1tjbGFzcy5jZGstdmlydHVhbC1zY3JvbGwtb3JpZW50YXRpb24taG9yaXpvbnRhbF0nOiAnb3JpZW50YXRpb24gPT09IFwiaG9yaXpvbnRhbFwiJyxcbiAgICAnW2NsYXNzLmNkay12aXJ0dWFsLXNjcm9sbC1vcmllbnRhdGlvbi12ZXJ0aWNhbF0nOiAnb3JpZW50YXRpb24gIT09IFwiaG9yaXpvbnRhbFwiJyxcbiAgfSxcbiAgZW5jYXBzdWxhdGlvbjogVmlld0VuY2Fwc3VsYXRpb24uTm9uZSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIHByb3ZpZGVyczogW1xuICAgIHtcbiAgICAgIHByb3ZpZGU6IENka1Njcm9sbGFibGUsXG4gICAgICB1c2VGYWN0b3J5OiAoXG4gICAgICAgIHZpcnR1YWxTY3JvbGxhYmxlOiBDZGtWaXJ0dWFsU2Nyb2xsYWJsZSB8IG51bGwsXG4gICAgICAgIHZpZXdwb3J0OiBDZGtWaXJ0dWFsU2Nyb2xsVmlld3BvcnQsXG4gICAgICApID0+IHZpcnR1YWxTY3JvbGxhYmxlIHx8IHZpZXdwb3J0LFxuICAgICAgZGVwczogW0Nka1ZpcnR1YWxTY3JvbGxhYmxlLCBDZGtWaXJ0dWFsU2Nyb2xsVmlld3BvcnRdLFxuICAgIH0sXG4gIF0sXG59KVxuZXhwb3J0IGNsYXNzIENka1ZpcnR1YWxTY3JvbGxWaWV3cG9ydCBleHRlbmRzIENka1ZpcnR1YWxTY3JvbGxhYmxlIGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuICAvKiogRW1pdHMgd2hlbiB0aGUgdmlld3BvcnQgaXMgZGV0YWNoZWQgZnJvbSBhIENka1ZpcnR1YWxGb3JPZi4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBfZGV0YWNoZWRTdWJqZWN0ID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICAvKiogRW1pdHMgd2hlbiB0aGUgcmVuZGVyZWQgcmFuZ2UgY2hhbmdlcy4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBfcmVuZGVyZWRSYW5nZVN1YmplY3QgPSBuZXcgU3ViamVjdDxMaXN0UmFuZ2U+KCk7XG5cbiAgLyoqIFRoZSBkaXJlY3Rpb24gdGhlIHZpZXdwb3J0IHNjcm9sbHMuICovXG4gIEBJbnB1dCgpXG4gIGdldCBvcmllbnRhdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy5fb3JpZW50YXRpb247XG4gIH1cblxuICBzZXQgb3JpZW50YXRpb24ob3JpZW50YXRpb246ICdob3Jpem9udGFsJyB8ICd2ZXJ0aWNhbCcpIHtcbiAgICBpZiAodGhpcy5fb3JpZW50YXRpb24gIT09IG9yaWVudGF0aW9uKSB7XG4gICAgICB0aGlzLl9vcmllbnRhdGlvbiA9IG9yaWVudGF0aW9uO1xuICAgICAgdGhpcy5fY2FsY3VsYXRlU3BhY2VyU2l6ZSgpO1xuICAgIH1cbiAgfVxuICBwcml2YXRlIF9vcmllbnRhdGlvbjogJ2hvcml6b250YWwnIHwgJ3ZlcnRpY2FsJyA9ICd2ZXJ0aWNhbCc7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgcmVuZGVyZWQgaXRlbXMgc2hvdWxkIHBlcnNpc3QgaW4gdGhlIERPTSBhZnRlciBzY3JvbGxpbmcgb3V0IG9mIHZpZXcuIEJ5IGRlZmF1bHQsIGl0ZW1zXG4gICAqIHdpbGwgYmUgcmVtb3ZlZC5cbiAgICovXG4gIEBJbnB1dCgpXG4gIGdldCBhcHBlbmRPbmx5KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9hcHBlbmRPbmx5O1xuICB9XG4gIHNldCBhcHBlbmRPbmx5KHZhbHVlOiBCb29sZWFuSW5wdXQpIHtcbiAgICB0aGlzLl9hcHBlbmRPbmx5ID0gY29lcmNlQm9vbGVhblByb3BlcnR5KHZhbHVlKTtcbiAgfVxuICBwcml2YXRlIF9hcHBlbmRPbmx5ID0gZmFsc2U7XG5cbiAgLy8gTm90ZTogd2UgZG9uJ3QgdXNlIHRoZSB0eXBpY2FsIEV2ZW50RW1pdHRlciBoZXJlIGJlY2F1c2Ugd2UgbmVlZCB0byBzdWJzY3JpYmUgdG8gdGhlIHNjcm9sbFxuICAvLyBzdHJhdGVneSBsYXppbHkgKGkuZS4gb25seSBpZiB0aGUgdXNlciBpcyBhY3R1YWxseSBsaXN0ZW5pbmcgdG8gdGhlIGV2ZW50cykuIFdlIGRvIHRoaXMgYmVjYXVzZVxuICAvLyBkZXBlbmRpbmcgb24gaG93IHRoZSBzdHJhdGVneSBjYWxjdWxhdGVzIHRoZSBzY3JvbGxlZCBpbmRleCwgaXQgbWF5IGNvbWUgYXQgYSBjb3N0IHRvXG4gIC8vIHBlcmZvcm1hbmNlLlxuICAvKiogRW1pdHMgd2hlbiB0aGUgaW5kZXggb2YgdGhlIGZpcnN0IGVsZW1lbnQgdmlzaWJsZSBpbiB0aGUgdmlld3BvcnQgY2hhbmdlcy4gKi9cbiAgQE91dHB1dCgpXG4gIHJlYWRvbmx5IHNjcm9sbGVkSW5kZXhDaGFuZ2U6IE9ic2VydmFibGU8bnVtYmVyPiA9IG5ldyBPYnNlcnZhYmxlKChvYnNlcnZlcjogT2JzZXJ2ZXI8bnVtYmVyPikgPT5cbiAgICB0aGlzLl9zY3JvbGxTdHJhdGVneS5zY3JvbGxlZEluZGV4Q2hhbmdlLnN1YnNjcmliZShpbmRleCA9PlxuICAgICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiB0aGlzLm5nWm9uZS5ydW4oKCkgPT4gb2JzZXJ2ZXIubmV4dChpbmRleCkpKSxcbiAgICApLFxuICApO1xuXG4gIC8qKiBUaGUgZWxlbWVudCB0aGF0IHdyYXBzIHRoZSByZW5kZXJlZCBjb250ZW50LiAqL1xuICBAVmlld0NoaWxkKCdjb250ZW50V3JhcHBlcicsIHtzdGF0aWM6IHRydWV9KSBfY29udGVudFdyYXBwZXI6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+O1xuXG4gIC8qKiBBIHN0cmVhbSB0aGF0IGVtaXRzIHdoZW5ldmVyIHRoZSByZW5kZXJlZCByYW5nZSBjaGFuZ2VzLiAqL1xuICByZWFkb25seSByZW5kZXJlZFJhbmdlU3RyZWFtOiBPYnNlcnZhYmxlPExpc3RSYW5nZT4gPSB0aGlzLl9yZW5kZXJlZFJhbmdlU3ViamVjdDtcblxuICAvKipcbiAgICogVGhlIHRvdGFsIHNpemUgb2YgYWxsIGNvbnRlbnQgKGluIHBpeGVscyksIGluY2x1ZGluZyBjb250ZW50IHRoYXQgaXMgbm90IGN1cnJlbnRseSByZW5kZXJlZC5cbiAgICovXG4gIHByaXZhdGUgX3RvdGFsQ29udGVudFNpemUgPSAwO1xuXG4gIC8qKiBBIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIGBzdHlsZS53aWR0aGAgcHJvcGVydHkgdmFsdWUgdG8gYmUgdXNlZCBmb3IgdGhlIHNwYWNlciBlbGVtZW50LiAqL1xuICBfdG90YWxDb250ZW50V2lkdGggPSAnJztcblxuICAvKiogQSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBgc3R5bGUuaGVpZ2h0YCBwcm9wZXJ0eSB2YWx1ZSB0byBiZSB1c2VkIGZvciB0aGUgc3BhY2VyIGVsZW1lbnQuICovXG4gIF90b3RhbENvbnRlbnRIZWlnaHQgPSAnJztcblxuICAvKipcbiAgICogVGhlIENTUyB0cmFuc2Zvcm0gYXBwbGllZCB0byB0aGUgcmVuZGVyZWQgc3Vic2V0IG9mIGl0ZW1zIHNvIHRoYXQgdGhleSBhcHBlYXIgd2l0aGluIHRoZSBib3VuZHNcbiAgICogb2YgdGhlIHZpc2libGUgdmlld3BvcnQuXG4gICAqL1xuICBwcml2YXRlIF9yZW5kZXJlZENvbnRlbnRUcmFuc2Zvcm06IHN0cmluZztcblxuICAvKiogVGhlIGN1cnJlbnRseSByZW5kZXJlZCByYW5nZSBvZiBpbmRpY2VzLiAqL1xuICBwcml2YXRlIF9yZW5kZXJlZFJhbmdlOiBMaXN0UmFuZ2UgPSB7c3RhcnQ6IDAsIGVuZDogMH07XG5cbiAgLyoqIFRoZSBsZW5ndGggb2YgdGhlIGRhdGEgYm91bmQgdG8gdGhpcyB2aWV3cG9ydCAoaW4gbnVtYmVyIG9mIGl0ZW1zKS4gKi9cbiAgcHJpdmF0ZSBfZGF0YUxlbmd0aCA9IDA7XG5cbiAgLyoqIFRoZSBzaXplIG9mIHRoZSB2aWV3cG9ydCAoaW4gcGl4ZWxzKS4gKi9cbiAgcHJpdmF0ZSBfdmlld3BvcnRTaXplID0gMDtcblxuICAvKiogdGhlIGN1cnJlbnRseSBhdHRhY2hlZCBDZGtWaXJ0dWFsU2Nyb2xsUmVwZWF0ZXIuICovXG4gIHByaXZhdGUgX2Zvck9mOiBDZGtWaXJ0dWFsU2Nyb2xsUmVwZWF0ZXI8YW55PiB8IG51bGw7XG5cbiAgLyoqIFRoZSBsYXN0IHJlbmRlcmVkIGNvbnRlbnQgb2Zmc2V0IHRoYXQgd2FzIHNldC4gKi9cbiAgcHJpdmF0ZSBfcmVuZGVyZWRDb250ZW50T2Zmc2V0ID0gMDtcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgbGFzdCByZW5kZXJlZCBjb250ZW50IG9mZnNldCB3YXMgdG8gdGhlIGVuZCBvZiB0aGUgY29udGVudCAoYW5kIHRoZXJlZm9yZSBuZWVkcyB0b1xuICAgKiBiZSByZXdyaXR0ZW4gYXMgYW4gb2Zmc2V0IHRvIHRoZSBzdGFydCBvZiB0aGUgY29udGVudCkuXG4gICAqL1xuICBwcml2YXRlIF9yZW5kZXJlZENvbnRlbnRPZmZzZXROZWVkc1Jld3JpdGUgPSBmYWxzZTtcblxuICAvKiogV2hldGhlciB0aGVyZSBpcyBhIHBlbmRpbmcgY2hhbmdlIGRldGVjdGlvbiBjeWNsZS4gKi9cbiAgcHJpdmF0ZSBfaXNDaGFuZ2VEZXRlY3Rpb25QZW5kaW5nID0gZmFsc2U7XG5cbiAgLyoqIEEgbGlzdCBvZiBmdW5jdGlvbnMgdG8gcnVuIGFmdGVyIHRoZSBuZXh0IGNoYW5nZSBkZXRlY3Rpb24gY3ljbGUuICovXG4gIHByaXZhdGUgX3J1bkFmdGVyQ2hhbmdlRGV0ZWN0aW9uOiBGdW5jdGlvbltdID0gW107XG5cbiAgLyoqIFN1YnNjcmlwdGlvbiB0byBjaGFuZ2VzIGluIHRoZSB2aWV3cG9ydCBzaXplLiAqL1xuICBwcml2YXRlIF92aWV3cG9ydENoYW5nZXMgPSBTdWJzY3JpcHRpb24uRU1QVFk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIG92ZXJyaWRlIGVsZW1lbnRSZWY6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+LFxuICAgIHByaXZhdGUgX2NoYW5nZURldGVjdG9yUmVmOiBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICBuZ1pvbmU6IE5nWm9uZSxcbiAgICBAT3B0aW9uYWwoKVxuICAgIEBJbmplY3QoVklSVFVBTF9TQ1JPTExfU1RSQVRFR1kpXG4gICAgcHJpdmF0ZSBfc2Nyb2xsU3RyYXRlZ3k6IFZpcnR1YWxTY3JvbGxTdHJhdGVneSxcbiAgICBAT3B0aW9uYWwoKSBkaXI6IERpcmVjdGlvbmFsaXR5LFxuICAgIHNjcm9sbERpc3BhdGNoZXI6IFNjcm9sbERpc3BhdGNoZXIsXG4gICAgdmlld3BvcnRSdWxlcjogVmlld3BvcnRSdWxlcixcbiAgICBAT3B0aW9uYWwoKSBASW5qZWN0KFZJUlRVQUxfU0NST0xMQUJMRSkgcHVibGljIHNjcm9sbGFibGU6IENka1ZpcnR1YWxTY3JvbGxhYmxlLFxuICApIHtcbiAgICBzdXBlcihlbGVtZW50UmVmLCBzY3JvbGxEaXNwYXRjaGVyLCBuZ1pvbmUsIGRpcik7XG5cbiAgICBpZiAoIV9zY3JvbGxTdHJhdGVneSAmJiAodHlwZW9mIG5nRGV2TW9kZSA9PT0gJ3VuZGVmaW5lZCcgfHwgbmdEZXZNb2RlKSkge1xuICAgICAgdGhyb3cgRXJyb3IoJ0Vycm9yOiBjZGstdmlydHVhbC1zY3JvbGwtdmlld3BvcnQgcmVxdWlyZXMgdGhlIFwiaXRlbVNpemVcIiBwcm9wZXJ0eSB0byBiZSBzZXQuJyk7XG4gICAgfVxuXG4gICAgdGhpcy5fdmlld3BvcnRDaGFuZ2VzID0gdmlld3BvcnRSdWxlci5jaGFuZ2UoKS5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgdGhpcy5jaGVja1ZpZXdwb3J0U2l6ZSgpO1xuICAgIH0pO1xuXG4gICAgaWYgKCF0aGlzLnNjcm9sbGFibGUpIHtcbiAgICAgIC8vIE5vIHNjcm9sbGFibGUgaXMgcHJvdmlkZWQsIHNvIHRoZSB2aXJ0dWFsLXNjcm9sbC12aWV3cG9ydCBuZWVkcyB0byBiZWNvbWUgYSBzY3JvbGxhYmxlXG4gICAgICB0aGlzLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudC5jbGFzc0xpc3QuYWRkKCdjZGstdmlydHVhbC1zY3JvbGxhYmxlJyk7XG4gICAgICB0aGlzLnNjcm9sbGFibGUgPSB0aGlzO1xuICAgIH1cbiAgfVxuXG4gIG92ZXJyaWRlIG5nT25Jbml0KCkge1xuICAgIGlmICh0aGlzLnNjcm9sbGFibGUgPT09IHRoaXMpIHtcbiAgICAgIHN1cGVyLm5nT25Jbml0KCk7XG4gICAgfVxuICAgIC8vIEl0J3Mgc3RpbGwgdG9vIGVhcmx5IHRvIG1lYXN1cmUgdGhlIHZpZXdwb3J0IGF0IHRoaXMgcG9pbnQuIERlZmVycmluZyB3aXRoIGEgcHJvbWlzZSBhbGxvd3NcbiAgICAvLyB0aGUgVmlld3BvcnQgdG8gYmUgcmVuZGVyZWQgd2l0aCB0aGUgY29ycmVjdCBzaXplIGJlZm9yZSB3ZSBtZWFzdXJlLiBXZSBydW4gdGhpcyBvdXRzaWRlIHRoZVxuICAgIC8vIHpvbmUgdG8gYXZvaWQgY2F1c2luZyBtb3JlIGNoYW5nZSBkZXRlY3Rpb24gY3ljbGVzLiBXZSBoYW5kbGUgdGhlIGNoYW5nZSBkZXRlY3Rpb24gbG9vcFxuICAgIC8vIG91cnNlbHZlcyBpbnN0ZWFkLlxuICAgIHRoaXMubmdab25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+XG4gICAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IHtcbiAgICAgICAgdGhpcy5fbWVhc3VyZVZpZXdwb3J0U2l6ZSgpO1xuICAgICAgICB0aGlzLl9zY3JvbGxTdHJhdGVneS5hdHRhY2godGhpcyk7XG5cbiAgICAgICAgdGhpcy5zY3JvbGxhYmxlXG4gICAgICAgICAgLmVsZW1lbnRTY3JvbGxlZCgpXG4gICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAvLyBTdGFydCBvZmYgd2l0aCBhIGZha2Ugc2Nyb2xsIGV2ZW50IHNvIHdlIHByb3Blcmx5IGRldGVjdCBvdXIgaW5pdGlhbCBwb3NpdGlvbi5cbiAgICAgICAgICAgIHN0YXJ0V2l0aChudWxsKSxcbiAgICAgICAgICAgIC8vIENvbGxlY3QgbXVsdGlwbGUgZXZlbnRzIGludG8gb25lIHVudGlsIHRoZSBuZXh0IGFuaW1hdGlvbiBmcmFtZS4gVGhpcyB3YXkgaWZcbiAgICAgICAgICAgIC8vIHRoZXJlIGFyZSBtdWx0aXBsZSBzY3JvbGwgZXZlbnRzIGluIHRoZSBzYW1lIGZyYW1lIHdlIG9ubHkgbmVlZCB0byByZWNoZWNrXG4gICAgICAgICAgICAvLyBvdXIgbGF5b3V0IG9uY2UuXG4gICAgICAgICAgICBhdWRpdFRpbWUoMCwgU0NST0xMX1NDSEVEVUxFUiksXG4gICAgICAgICAgKVxuICAgICAgICAgIC5zdWJzY3JpYmUoKCkgPT4gdGhpcy5fc2Nyb2xsU3RyYXRlZ3kub25Db250ZW50U2Nyb2xsZWQoKSk7XG5cbiAgICAgICAgdGhpcy5fbWFya0NoYW5nZURldGVjdGlvbk5lZWRlZCgpO1xuICAgICAgfSksXG4gICAgKTtcbiAgfVxuXG4gIG92ZXJyaWRlIG5nT25EZXN0cm95KCkge1xuICAgIHRoaXMuZGV0YWNoKCk7XG4gICAgdGhpcy5fc2Nyb2xsU3RyYXRlZ3kuZGV0YWNoKCk7XG5cbiAgICAvLyBDb21wbGV0ZSBhbGwgc3ViamVjdHNcbiAgICB0aGlzLl9yZW5kZXJlZFJhbmdlU3ViamVjdC5jb21wbGV0ZSgpO1xuICAgIHRoaXMuX2RldGFjaGVkU3ViamVjdC5jb21wbGV0ZSgpO1xuICAgIHRoaXMuX3ZpZXdwb3J0Q2hhbmdlcy51bnN1YnNjcmliZSgpO1xuXG4gICAgc3VwZXIubmdPbkRlc3Ryb3koKTtcbiAgfVxuXG4gIC8qKiBBdHRhY2hlcyBhIGBDZGtWaXJ0dWFsU2Nyb2xsUmVwZWF0ZXJgIHRvIHRoaXMgdmlld3BvcnQuICovXG4gIGF0dGFjaChmb3JPZjogQ2RrVmlydHVhbFNjcm9sbFJlcGVhdGVyPGFueT4pIHtcbiAgICBpZiAodGhpcy5fZm9yT2YgJiYgKHR5cGVvZiBuZ0Rldk1vZGUgPT09ICd1bmRlZmluZWQnIHx8IG5nRGV2TW9kZSkpIHtcbiAgICAgIHRocm93IEVycm9yKCdDZGtWaXJ0dWFsU2Nyb2xsVmlld3BvcnQgaXMgYWxyZWFkeSBhdHRhY2hlZC4nKTtcbiAgICB9XG5cbiAgICAvLyBTdWJzY3JpYmUgdG8gdGhlIGRhdGEgc3RyZWFtIG9mIHRoZSBDZGtWaXJ0dWFsRm9yT2YgdG8ga2VlcCB0cmFjayBvZiB3aGVuIHRoZSBkYXRhIGxlbmd0aFxuICAgIC8vIGNoYW5nZXMuIFJ1biBvdXRzaWRlIHRoZSB6b25lIHRvIGF2b2lkIHRyaWdnZXJpbmcgY2hhbmdlIGRldGVjdGlvbiwgc2luY2Ugd2UncmUgbWFuYWdpbmcgdGhlXG4gICAgLy8gY2hhbmdlIGRldGVjdGlvbiBsb29wIG91cnNlbHZlcy5cbiAgICB0aGlzLm5nWm9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PiB7XG4gICAgICB0aGlzLl9mb3JPZiA9IGZvck9mO1xuICAgICAgdGhpcy5fZm9yT2YuZGF0YVN0cmVhbS5waXBlKHRha2VVbnRpbCh0aGlzLl9kZXRhY2hlZFN1YmplY3QpKS5zdWJzY3JpYmUoZGF0YSA9PiB7XG4gICAgICAgIGNvbnN0IG5ld0xlbmd0aCA9IGRhdGEubGVuZ3RoO1xuICAgICAgICBpZiAobmV3TGVuZ3RoICE9PSB0aGlzLl9kYXRhTGVuZ3RoKSB7XG4gICAgICAgICAgdGhpcy5fZGF0YUxlbmd0aCA9IG5ld0xlbmd0aDtcbiAgICAgICAgICB0aGlzLl9zY3JvbGxTdHJhdGVneS5vbkRhdGFMZW5ndGhDaGFuZ2VkKCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fZG9DaGFuZ2VEZXRlY3Rpb24oKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqIERldGFjaGVzIHRoZSBjdXJyZW50IGBDZGtWaXJ0dWFsRm9yT2ZgLiAqL1xuICBkZXRhY2goKSB7XG4gICAgdGhpcy5fZm9yT2YgPSBudWxsO1xuICAgIHRoaXMuX2RldGFjaGVkU3ViamVjdC5uZXh0KCk7XG4gIH1cblxuICAvKiogR2V0cyB0aGUgbGVuZ3RoIG9mIHRoZSBkYXRhIGJvdW5kIHRvIHRoaXMgdmlld3BvcnQgKGluIG51bWJlciBvZiBpdGVtcykuICovXG4gIGdldERhdGFMZW5ndGgoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5fZGF0YUxlbmd0aDtcbiAgfVxuXG4gIC8qKiBHZXRzIHRoZSBzaXplIG9mIHRoZSB2aWV3cG9ydCAoaW4gcGl4ZWxzKS4gKi9cbiAgZ2V0Vmlld3BvcnRTaXplKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuX3ZpZXdwb3J0U2l6ZTtcbiAgfVxuXG4gIC8vIFRPRE8obW1hbGVyYmEpOiBUaGlzIGlzIHRlY2huaWNhbGx5IG91dCBvZiBzeW5jIHdpdGggd2hhdCdzIHJlYWxseSByZW5kZXJlZCB1bnRpbCBhIHJlbmRlclxuICAvLyBjeWNsZSBoYXBwZW5zLiBJJ20gYmVpbmcgY2FyZWZ1bCB0byBvbmx5IGNhbGwgaXQgYWZ0ZXIgdGhlIHJlbmRlciBjeWNsZSBpcyBjb21wbGV0ZSBhbmQgYmVmb3JlXG4gIC8vIHNldHRpbmcgaXQgdG8gc29tZXRoaW5nIGVsc2UsIGJ1dCBpdHMgZXJyb3IgcHJvbmUgYW5kIHNob3VsZCBwcm9iYWJseSBiZSBzcGxpdCBpbnRvXG4gIC8vIGBwZW5kaW5nUmFuZ2VgIGFuZCBgcmVuZGVyZWRSYW5nZWAsIHRoZSBsYXR0ZXIgcmVmbGVjdGluZyB3aGF0cyBhY3R1YWxseSBpbiB0aGUgRE9NLlxuXG4gIC8qKiBHZXQgdGhlIGN1cnJlbnQgcmVuZGVyZWQgcmFuZ2Ugb2YgaXRlbXMuICovXG4gIGdldFJlbmRlcmVkUmFuZ2UoKTogTGlzdFJhbmdlIHtcbiAgICByZXR1cm4gdGhpcy5fcmVuZGVyZWRSYW5nZTtcbiAgfVxuXG4gIG1lYXN1cmVCb3VuZGluZ0NsaWVudFJlY3RXaXRoU2Nyb2xsT2Zmc2V0KGZyb206ICdsZWZ0JyB8ICd0b3AnIHwgJ3JpZ2h0JyB8ICdib3R0b20nKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5nZXRFbGVtZW50UmVmKCkubmF0aXZlRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKVtmcm9tXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHRoZSB0b3RhbCBzaXplIG9mIGFsbCBjb250ZW50IChpbiBwaXhlbHMpLCBpbmNsdWRpbmcgY29udGVudCB0aGF0IGlzIG5vdCBjdXJyZW50bHlcbiAgICogcmVuZGVyZWQuXG4gICAqL1xuICBzZXRUb3RhbENvbnRlbnRTaXplKHNpemU6IG51bWJlcikge1xuICAgIGlmICh0aGlzLl90b3RhbENvbnRlbnRTaXplICE9PSBzaXplKSB7XG4gICAgICB0aGlzLl90b3RhbENvbnRlbnRTaXplID0gc2l6ZTtcbiAgICAgIHRoaXMuX2NhbGN1bGF0ZVNwYWNlclNpemUoKTtcbiAgICAgIHRoaXMuX21hcmtDaGFuZ2VEZXRlY3Rpb25OZWVkZWQoKTtcbiAgICB9XG4gIH1cblxuICAvKiogU2V0cyB0aGUgY3VycmVudGx5IHJlbmRlcmVkIHJhbmdlIG9mIGluZGljZXMuICovXG4gIHNldFJlbmRlcmVkUmFuZ2UocmFuZ2U6IExpc3RSYW5nZSkge1xuICAgIGlmICghcmFuZ2VzRXF1YWwodGhpcy5fcmVuZGVyZWRSYW5nZSwgcmFuZ2UpKSB7XG4gICAgICBpZiAodGhpcy5hcHBlbmRPbmx5KSB7XG4gICAgICAgIHJhbmdlID0ge3N0YXJ0OiAwLCBlbmQ6IE1hdGgubWF4KHRoaXMuX3JlbmRlcmVkUmFuZ2UuZW5kLCByYW5nZS5lbmQpfTtcbiAgICAgIH1cbiAgICAgIHRoaXMuX3JlbmRlcmVkUmFuZ2VTdWJqZWN0Lm5leHQoKHRoaXMuX3JlbmRlcmVkUmFuZ2UgPSByYW5nZSkpO1xuICAgICAgdGhpcy5fbWFya0NoYW5nZURldGVjdGlvbk5lZWRlZCgoKSA9PiB0aGlzLl9zY3JvbGxTdHJhdGVneS5vbkNvbnRlbnRSZW5kZXJlZCgpKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgb2Zmc2V0IGZyb20gdGhlIHN0YXJ0IG9mIHRoZSB2aWV3cG9ydCB0byB0aGUgc3RhcnQgb2YgdGhlIHJlbmRlcmVkIGRhdGEgKGluIHBpeGVscykuXG4gICAqL1xuICBnZXRPZmZzZXRUb1JlbmRlcmVkQ29udGVudFN0YXJ0KCk6IG51bWJlciB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLl9yZW5kZXJlZENvbnRlbnRPZmZzZXROZWVkc1Jld3JpdGUgPyBudWxsIDogdGhpcy5fcmVuZGVyZWRDb250ZW50T2Zmc2V0O1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIG9mZnNldCBmcm9tIHRoZSBzdGFydCBvZiB0aGUgdmlld3BvcnQgdG8gZWl0aGVyIHRoZSBzdGFydCBvciBlbmQgb2YgdGhlIHJlbmRlcmVkIGRhdGFcbiAgICogKGluIHBpeGVscykuXG4gICAqL1xuICBzZXRSZW5kZXJlZENvbnRlbnRPZmZzZXQob2Zmc2V0OiBudW1iZXIsIHRvOiAndG8tc3RhcnQnIHwgJ3RvLWVuZCcgPSAndG8tc3RhcnQnKSB7XG4gICAgLy8gSW4gYXBwZW5kT25seSwgd2UgYWx3YXlzIHN0YXJ0IGZyb20gdGhlIHRvcFxuICAgIG9mZnNldCA9IHRoaXMuYXBwZW5kT25seSAmJiB0byA9PT0gJ3RvLXN0YXJ0JyA/IDAgOiBvZmZzZXQ7XG5cbiAgICAvLyBGb3IgYSBob3Jpem9udGFsIHZpZXdwb3J0IGluIGEgcmlnaHQtdG8tbGVmdCBsYW5ndWFnZSB3ZSBuZWVkIHRvIHRyYW5zbGF0ZSBhbG9uZyB0aGUgeC1heGlzXG4gICAgLy8gaW4gdGhlIG5lZ2F0aXZlIGRpcmVjdGlvbi5cbiAgICBjb25zdCBpc1J0bCA9IHRoaXMuZGlyICYmIHRoaXMuZGlyLnZhbHVlID09ICdydGwnO1xuICAgIGNvbnN0IGlzSG9yaXpvbnRhbCA9IHRoaXMub3JpZW50YXRpb24gPT0gJ2hvcml6b250YWwnO1xuICAgIGNvbnN0IGF4aXMgPSBpc0hvcml6b250YWwgPyAnWCcgOiAnWSc7XG4gICAgY29uc3QgYXhpc0RpcmVjdGlvbiA9IGlzSG9yaXpvbnRhbCAmJiBpc1J0bCA/IC0xIDogMTtcbiAgICBsZXQgdHJhbnNmb3JtID0gYHRyYW5zbGF0ZSR7YXhpc30oJHtOdW1iZXIoYXhpc0RpcmVjdGlvbiAqIG9mZnNldCl9cHgpYDtcbiAgICB0aGlzLl9yZW5kZXJlZENvbnRlbnRPZmZzZXQgPSBvZmZzZXQ7XG4gICAgaWYgKHRvID09PSAndG8tZW5kJykge1xuICAgICAgdHJhbnNmb3JtICs9IGAgdHJhbnNsYXRlJHtheGlzfSgtMTAwJSlgO1xuICAgICAgLy8gVGhlIHZpZXdwb3J0IHNob3VsZCByZXdyaXRlIHRoaXMgYXMgYSBgdG8tc3RhcnRgIG9mZnNldCBvbiB0aGUgbmV4dCByZW5kZXIgY3ljbGUuIE90aGVyd2lzZVxuICAgICAgLy8gZWxlbWVudHMgd2lsbCBhcHBlYXIgdG8gZXhwYW5kIGluIHRoZSB3cm9uZyBkaXJlY3Rpb24gKGUuZy4gYG1hdC1leHBhbnNpb24tcGFuZWxgIHdvdWxkXG4gICAgICAvLyBleHBhbmQgdXB3YXJkKS5cbiAgICAgIHRoaXMuX3JlbmRlcmVkQ29udGVudE9mZnNldE5lZWRzUmV3cml0ZSA9IHRydWU7XG4gICAgfVxuICAgIGlmICh0aGlzLl9yZW5kZXJlZENvbnRlbnRUcmFuc2Zvcm0gIT0gdHJhbnNmb3JtKSB7XG4gICAgICAvLyBXZSBrbm93IHRoaXMgdmFsdWUgaXMgc2FmZSBiZWNhdXNlIHdlIHBhcnNlIGBvZmZzZXRgIHdpdGggYE51bWJlcigpYCBiZWZvcmUgcGFzc2luZyBpdFxuICAgICAgLy8gaW50byB0aGUgc3RyaW5nLlxuICAgICAgdGhpcy5fcmVuZGVyZWRDb250ZW50VHJhbnNmb3JtID0gdHJhbnNmb3JtO1xuICAgICAgdGhpcy5fbWFya0NoYW5nZURldGVjdGlvbk5lZWRlZCgoKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLl9yZW5kZXJlZENvbnRlbnRPZmZzZXROZWVkc1Jld3JpdGUpIHtcbiAgICAgICAgICB0aGlzLl9yZW5kZXJlZENvbnRlbnRPZmZzZXQgLT0gdGhpcy5tZWFzdXJlUmVuZGVyZWRDb250ZW50U2l6ZSgpO1xuICAgICAgICAgIHRoaXMuX3JlbmRlcmVkQ29udGVudE9mZnNldE5lZWRzUmV3cml0ZSA9IGZhbHNlO1xuICAgICAgICAgIHRoaXMuc2V0UmVuZGVyZWRDb250ZW50T2Zmc2V0KHRoaXMuX3JlbmRlcmVkQ29udGVudE9mZnNldCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5fc2Nyb2xsU3RyYXRlZ3kub25SZW5kZXJlZE9mZnNldENoYW5nZWQoKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNjcm9sbHMgdG8gdGhlIGdpdmVuIG9mZnNldCBmcm9tIHRoZSBzdGFydCBvZiB0aGUgdmlld3BvcnQuIFBsZWFzZSBub3RlIHRoYXQgdGhpcyBpcyBub3QgYWx3YXlzXG4gICAqIHRoZSBzYW1lIGFzIHNldHRpbmcgYHNjcm9sbFRvcGAgb3IgYHNjcm9sbExlZnRgLiBJbiBhIGhvcml6b250YWwgdmlld3BvcnQgd2l0aCByaWdodC10by1sZWZ0XG4gICAqIGRpcmVjdGlvbiwgdGhpcyB3b3VsZCBiZSB0aGUgZXF1aXZhbGVudCBvZiBzZXR0aW5nIGEgZmljdGlvbmFsIGBzY3JvbGxSaWdodGAgcHJvcGVydHkuXG4gICAqIEBwYXJhbSBvZmZzZXQgVGhlIG9mZnNldCB0byBzY3JvbGwgdG8uXG4gICAqIEBwYXJhbSBiZWhhdmlvciBUaGUgU2Nyb2xsQmVoYXZpb3IgdG8gdXNlIHdoZW4gc2Nyb2xsaW5nLiBEZWZhdWx0IGlzIGJlaGF2aW9yIGlzIGBhdXRvYC5cbiAgICovXG4gIHNjcm9sbFRvT2Zmc2V0KG9mZnNldDogbnVtYmVyLCBiZWhhdmlvcjogU2Nyb2xsQmVoYXZpb3IgPSAnYXV0bycpIHtcbiAgICBjb25zdCBvcHRpb25zOiBFeHRlbmRlZFNjcm9sbFRvT3B0aW9ucyA9IHtiZWhhdmlvcn07XG4gICAgaWYgKHRoaXMub3JpZW50YXRpb24gPT09ICdob3Jpem9udGFsJykge1xuICAgICAgb3B0aW9ucy5zdGFydCA9IG9mZnNldDtcbiAgICB9IGVsc2Uge1xuICAgICAgb3B0aW9ucy50b3AgPSBvZmZzZXQ7XG4gICAgfVxuICAgIHRoaXMuc2Nyb2xsYWJsZS5zY3JvbGxUbyhvcHRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTY3JvbGxzIHRvIHRoZSBvZmZzZXQgZm9yIHRoZSBnaXZlbiBpbmRleC5cbiAgICogQHBhcmFtIGluZGV4IFRoZSBpbmRleCBvZiB0aGUgZWxlbWVudCB0byBzY3JvbGwgdG8uXG4gICAqIEBwYXJhbSBiZWhhdmlvciBUaGUgU2Nyb2xsQmVoYXZpb3IgdG8gdXNlIHdoZW4gc2Nyb2xsaW5nLiBEZWZhdWx0IGlzIGJlaGF2aW9yIGlzIGBhdXRvYC5cbiAgICovXG4gIHNjcm9sbFRvSW5kZXgoaW5kZXg6IG51bWJlciwgYmVoYXZpb3I6IFNjcm9sbEJlaGF2aW9yID0gJ2F1dG8nKSB7XG4gICAgdGhpcy5fc2Nyb2xsU3RyYXRlZ3kuc2Nyb2xsVG9JbmRleChpbmRleCwgYmVoYXZpb3IpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGN1cnJlbnQgc2Nyb2xsIG9mZnNldCBmcm9tIHRoZSBzdGFydCBvZiB0aGUgc2Nyb2xsYWJsZSAoaW4gcGl4ZWxzKS5cbiAgICogQHBhcmFtIGZyb20gVGhlIGVkZ2UgdG8gbWVhc3VyZSB0aGUgb2Zmc2V0IGZyb20uIERlZmF1bHRzIHRvICd0b3AnIGluIHZlcnRpY2FsIG1vZGUgYW5kICdzdGFydCdcbiAgICogICAgIGluIGhvcml6b250YWwgbW9kZS5cbiAgICovXG4gIG92ZXJyaWRlIG1lYXN1cmVTY3JvbGxPZmZzZXQoXG4gICAgZnJvbT86ICd0b3AnIHwgJ2xlZnQnIHwgJ3JpZ2h0JyB8ICdib3R0b20nIHwgJ3N0YXJ0JyB8ICdlbmQnLFxuICApOiBudW1iZXIge1xuICAgIC8vIFRoaXMgaXMgdG8gYnJlYWsgdGhlIGNhbGwgY3ljbGVcbiAgICBsZXQgbWVhc3VyZVNjcm9sbE9mZnNldDogSW5zdGFuY2VUeXBlPHR5cGVvZiBDZGtWaXJ0dWFsU2Nyb2xsYWJsZT5bJ21lYXN1cmVTY3JvbGxPZmZzZXQnXTtcbiAgICBpZiAodGhpcy5zY3JvbGxhYmxlID09IHRoaXMpIHtcbiAgICAgIG1lYXN1cmVTY3JvbGxPZmZzZXQgPSAoX2Zyb206IE5vbk51bGxhYmxlPHR5cGVvZiBmcm9tPikgPT4gc3VwZXIubWVhc3VyZVNjcm9sbE9mZnNldChfZnJvbSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIG1lYXN1cmVTY3JvbGxPZmZzZXQgPSAoX2Zyb206IE5vbk51bGxhYmxlPHR5cGVvZiBmcm9tPikgPT5cbiAgICAgICAgdGhpcy5zY3JvbGxhYmxlLm1lYXN1cmVTY3JvbGxPZmZzZXQoX2Zyb20pO1xuICAgIH1cblxuICAgIHJldHVybiBNYXRoLm1heChcbiAgICAgIDAsXG4gICAgICBtZWFzdXJlU2Nyb2xsT2Zmc2V0KGZyb20gPz8gKHRoaXMub3JpZW50YXRpb24gPT09ICdob3Jpem9udGFsJyA/ICdzdGFydCcgOiAndG9wJykpIC1cbiAgICAgICAgdGhpcy5tZWFzdXJlVmlld3BvcnRPZmZzZXQoKSxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIE1lYXN1cmVzIHRoZSBvZmZzZXQgb2YgdGhlIHZpZXdwb3J0IGZyb20gdGhlIHNjcm9sbGluZyBjb250YWluZXJcbiAgICogQHBhcmFtIGZyb20gVGhlIGVkZ2UgdG8gbWVhc3VyZSBmcm9tLlxuICAgKi9cbiAgbWVhc3VyZVZpZXdwb3J0T2Zmc2V0KGZyb20/OiAndG9wJyB8ICdsZWZ0JyB8ICdyaWdodCcgfCAnYm90dG9tJyB8ICdzdGFydCcgfCAnZW5kJykge1xuICAgIGxldCBmcm9tUmVjdDogJ2xlZnQnIHwgJ3RvcCcgfCAncmlnaHQnIHwgJ2JvdHRvbSc7XG4gICAgY29uc3QgTEVGVCA9ICdsZWZ0JztcbiAgICBjb25zdCBSSUdIVCA9ICdyaWdodCc7XG4gICAgY29uc3QgaXNSdGwgPSB0aGlzLmRpcj8udmFsdWUgPT0gJ3J0bCc7XG4gICAgaWYgKGZyb20gPT0gJ3N0YXJ0Jykge1xuICAgICAgZnJvbVJlY3QgPSBpc1J0bCA/IFJJR0hUIDogTEVGVDtcbiAgICB9IGVsc2UgaWYgKGZyb20gPT0gJ2VuZCcpIHtcbiAgICAgIGZyb21SZWN0ID0gaXNSdGwgPyBMRUZUIDogUklHSFQ7XG4gICAgfSBlbHNlIGlmIChmcm9tKSB7XG4gICAgICBmcm9tUmVjdCA9IGZyb207XG4gICAgfSBlbHNlIHtcbiAgICAgIGZyb21SZWN0ID0gdGhpcy5vcmllbnRhdGlvbiA9PT0gJ2hvcml6b250YWwnID8gJ2xlZnQnIDogJ3RvcCc7XG4gICAgfVxuXG4gICAgY29uc3Qgc2Nyb2xsZXJDbGllbnRSZWN0ID0gdGhpcy5zY3JvbGxhYmxlLm1lYXN1cmVCb3VuZGluZ0NsaWVudFJlY3RXaXRoU2Nyb2xsT2Zmc2V0KGZyb21SZWN0KTtcbiAgICBjb25zdCB2aWV3cG9ydENsaWVudFJlY3QgPSB0aGlzLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKVtmcm9tUmVjdF07XG5cbiAgICByZXR1cm4gdmlld3BvcnRDbGllbnRSZWN0IC0gc2Nyb2xsZXJDbGllbnRSZWN0O1xuICB9XG5cbiAgLyoqIE1lYXN1cmUgdGhlIGNvbWJpbmVkIHNpemUgb2YgYWxsIG9mIHRoZSByZW5kZXJlZCBpdGVtcy4gKi9cbiAgbWVhc3VyZVJlbmRlcmVkQ29udGVudFNpemUoKTogbnVtYmVyIHtcbiAgICBjb25zdCBjb250ZW50RWwgPSB0aGlzLl9jb250ZW50V3JhcHBlci5uYXRpdmVFbGVtZW50O1xuICAgIHJldHVybiB0aGlzLm9yaWVudGF0aW9uID09PSAnaG9yaXpvbnRhbCcgPyBjb250ZW50RWwub2Zmc2V0V2lkdGggOiBjb250ZW50RWwub2Zmc2V0SGVpZ2h0O1xuICB9XG5cbiAgLyoqXG4gICAqIE1lYXN1cmUgdGhlIHRvdGFsIGNvbWJpbmVkIHNpemUgb2YgdGhlIGdpdmVuIHJhbmdlLiBUaHJvd3MgaWYgdGhlIHJhbmdlIGluY2x1ZGVzIGl0ZW1zIHRoYXQgYXJlXG4gICAqIG5vdCByZW5kZXJlZC5cbiAgICovXG4gIG1lYXN1cmVSYW5nZVNpemUocmFuZ2U6IExpc3RSYW5nZSk6IG51bWJlciB7XG4gICAgaWYgKCF0aGlzLl9mb3JPZikge1xuICAgICAgcmV0dXJuIDA7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLl9mb3JPZi5tZWFzdXJlUmFuZ2VTaXplKHJhbmdlLCB0aGlzLm9yaWVudGF0aW9uKTtcbiAgfVxuXG4gIC8qKiBVcGRhdGUgdGhlIHZpZXdwb3J0IGRpbWVuc2lvbnMgYW5kIHJlLXJlbmRlci4gKi9cbiAgY2hlY2tWaWV3cG9ydFNpemUoKSB7XG4gICAgLy8gVE9ETzogQ2xlYW51cCBsYXRlciB3aGVuIGFkZCBsb2dpYyBmb3IgaGFuZGxpbmcgY29udGVudCByZXNpemVcbiAgICB0aGlzLl9tZWFzdXJlVmlld3BvcnRTaXplKCk7XG4gICAgdGhpcy5fc2Nyb2xsU3RyYXRlZ3kub25EYXRhTGVuZ3RoQ2hhbmdlZCgpO1xuICB9XG5cbiAgLyoqIE1lYXN1cmUgdGhlIHZpZXdwb3J0IHNpemUuICovXG4gIHByaXZhdGUgX21lYXN1cmVWaWV3cG9ydFNpemUoKSB7XG4gICAgdGhpcy5fdmlld3BvcnRTaXplID0gdGhpcy5zY3JvbGxhYmxlLm1lYXN1cmVWaWV3cG9ydFNpemUodGhpcy5vcmllbnRhdGlvbik7XG4gIH1cblxuICAvKiogUXVldWUgdXAgY2hhbmdlIGRldGVjdGlvbiB0byBydW4uICovXG4gIHByaXZhdGUgX21hcmtDaGFuZ2VEZXRlY3Rpb25OZWVkZWQocnVuQWZ0ZXI/OiBGdW5jdGlvbikge1xuICAgIGlmIChydW5BZnRlcikge1xuICAgICAgdGhpcy5fcnVuQWZ0ZXJDaGFuZ2VEZXRlY3Rpb24ucHVzaChydW5BZnRlcik7XG4gICAgfVxuXG4gICAgLy8gVXNlIGEgUHJvbWlzZSB0byBiYXRjaCB0b2dldGhlciBjYWxscyB0byBgX2RvQ2hhbmdlRGV0ZWN0aW9uYC4gVGhpcyB3YXkgaWYgd2Ugc2V0IGEgYnVuY2ggb2ZcbiAgICAvLyBwcm9wZXJ0aWVzIHNlcXVlbnRpYWxseSB3ZSBvbmx5IGhhdmUgdG8gcnVuIGBfZG9DaGFuZ2VEZXRlY3Rpb25gIG9uY2UgYXQgdGhlIGVuZC5cbiAgICBpZiAoIXRoaXMuX2lzQ2hhbmdlRGV0ZWN0aW9uUGVuZGluZykge1xuICAgICAgdGhpcy5faXNDaGFuZ2VEZXRlY3Rpb25QZW5kaW5nID0gdHJ1ZTtcbiAgICAgIHRoaXMubmdab25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+XG4gICAgICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgIHRoaXMuX2RvQ2hhbmdlRGV0ZWN0aW9uKCk7XG4gICAgICAgIH0pLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKiogUnVuIGNoYW5nZSBkZXRlY3Rpb24uICovXG4gIHByaXZhdGUgX2RvQ2hhbmdlRGV0ZWN0aW9uKCkge1xuICAgIHRoaXMuX2lzQ2hhbmdlRGV0ZWN0aW9uUGVuZGluZyA9IGZhbHNlO1xuXG4gICAgLy8gQXBwbHkgdGhlIGNvbnRlbnQgdHJhbnNmb3JtLiBUaGUgdHJhbnNmb3JtIGNhbid0IGJlIHNldCB2aWEgYW4gQW5ndWxhciBiaW5kaW5nIGJlY2F1c2VcbiAgICAvLyBieXBhc3NTZWN1cml0eVRydXN0U3R5bGUgaXMgYmFubmVkIGluIEdvb2dsZS4gSG93ZXZlciB0aGUgdmFsdWUgaXMgc2FmZSwgaXQncyBjb21wb3NlZCBvZlxuICAgIC8vIHN0cmluZyBsaXRlcmFscywgYSB2YXJpYWJsZSB0aGF0IGNhbiBvbmx5IGJlICdYJyBvciAnWScsIGFuZCB1c2VyIGlucHV0IHRoYXQgaXMgcnVuIHRocm91Z2hcbiAgICAvLyB0aGUgYE51bWJlcmAgZnVuY3Rpb24gZmlyc3QgdG8gY29lcmNlIGl0IHRvIGEgbnVtZXJpYyB2YWx1ZS5cbiAgICB0aGlzLl9jb250ZW50V3JhcHBlci5uYXRpdmVFbGVtZW50LnN0eWxlLnRyYW5zZm9ybSA9IHRoaXMuX3JlbmRlcmVkQ29udGVudFRyYW5zZm9ybTtcbiAgICAvLyBBcHBseSBjaGFuZ2VzIHRvIEFuZ3VsYXIgYmluZGluZ3MuIE5vdGU6IFdlIG11c3QgY2FsbCBgbWFya0ZvckNoZWNrYCB0byBydW4gY2hhbmdlIGRldGVjdGlvblxuICAgIC8vIGZyb20gdGhlIHJvb3QsIHNpbmNlIHRoZSByZXBlYXRlZCBpdGVtcyBhcmUgY29udGVudCBwcm9qZWN0ZWQgaW4uIENhbGxpbmcgYGRldGVjdENoYW5nZXNgXG4gICAgLy8gaW5zdGVhZCBkb2VzIG5vdCBwcm9wZXJseSBjaGVjayB0aGUgcHJvamVjdGVkIGNvbnRlbnQuXG4gICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHRoaXMuX2NoYW5nZURldGVjdG9yUmVmLm1hcmtGb3JDaGVjaygpKTtcblxuICAgIGNvbnN0IHJ1bkFmdGVyQ2hhbmdlRGV0ZWN0aW9uID0gdGhpcy5fcnVuQWZ0ZXJDaGFuZ2VEZXRlY3Rpb247XG4gICAgdGhpcy5fcnVuQWZ0ZXJDaGFuZ2VEZXRlY3Rpb24gPSBbXTtcbiAgICBmb3IgKGNvbnN0IGZuIG9mIHJ1bkFmdGVyQ2hhbmdlRGV0ZWN0aW9uKSB7XG4gICAgICBmbigpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBDYWxjdWxhdGVzIHRoZSBgc3R5bGUud2lkdGhgIGFuZCBgc3R5bGUuaGVpZ2h0YCBmb3IgdGhlIHNwYWNlciBlbGVtZW50LiAqL1xuICBwcml2YXRlIF9jYWxjdWxhdGVTcGFjZXJTaXplKCkge1xuICAgIHRoaXMuX3RvdGFsQ29udGVudEhlaWdodCA9XG4gICAgICB0aGlzLm9yaWVudGF0aW9uID09PSAnaG9yaXpvbnRhbCcgPyAnJyA6IGAke3RoaXMuX3RvdGFsQ29udGVudFNpemV9cHhgO1xuICAgIHRoaXMuX3RvdGFsQ29udGVudFdpZHRoID1cbiAgICAgIHRoaXMub3JpZW50YXRpb24gPT09ICdob3Jpem9udGFsJyA/IGAke3RoaXMuX3RvdGFsQ29udGVudFNpemV9cHhgIDogJyc7XG4gIH1cbn1cbiIsIjwhLS1cbiAgV3JhcCB0aGUgcmVuZGVyZWQgY29udGVudCBpbiBhbiBlbGVtZW50IHRoYXQgd2lsbCBiZSB1c2VkIHRvIG9mZnNldCBpdCBiYXNlZCBvbiB0aGUgc2Nyb2xsXG4gIHBvc2l0aW9uLlxuLS0+XG48ZGl2ICNjb250ZW50V3JhcHBlciBjbGFzcz1cImNkay12aXJ0dWFsLXNjcm9sbC1jb250ZW50LXdyYXBwZXJcIj5cbiAgPG5nLWNvbnRlbnQ+PC9uZy1jb250ZW50PlxuPC9kaXY+XG48IS0tXG4gIFNwYWNlciB1c2VkIHRvIGZvcmNlIHRoZSBzY3JvbGxpbmcgY29udGFpbmVyIHRvIHRoZSBjb3JyZWN0IHNpemUgZm9yIHRoZSAqdG90YWwqIG51bWJlciBvZiBpdGVtc1xuICBzbyB0aGF0IHRoZSBzY3JvbGxiYXIgY2FwdHVyZXMgdGhlIHNpemUgb2YgdGhlIGVudGlyZSBkYXRhIHNldC5cbi0tPlxuPGRpdiBjbGFzcz1cImNkay12aXJ0dWFsLXNjcm9sbC1zcGFjZXJcIlxuICAgICBbc3R5bGUud2lkdGhdPVwiX3RvdGFsQ29udGVudFdpZHRoXCIgW3N0eWxlLmhlaWdodF09XCJfdG90YWxDb250ZW50SGVpZ2h0XCI+PC9kaXY+XG4iXX0= |
\ | No newline at end of file |