ng-virtual-list 14.4.2 → 14.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +1 -1
  2. package/esm2020/lib/utils/tracker.mjs +18 -9
  3. package/esm2022/lib/components/ng-virtual-list-item.component.mjs +132 -0
  4. package/esm2022/lib/const/index.mjs +44 -0
  5. package/esm2022/lib/enums/direction.mjs +2 -0
  6. package/esm2022/lib/enums/directions.mjs +18 -0
  7. package/esm2022/lib/enums/index.mjs +4 -0
  8. package/esm2022/lib/enums/snapping-method.mjs +2 -0
  9. package/esm2022/lib/enums/snapping-methods.mjs +18 -0
  10. package/esm2022/lib/models/base-virtual-list-item-component.mjs +9 -0
  11. package/esm2022/lib/models/collection.model.mjs +3 -0
  12. package/esm2022/lib/models/component.model.mjs +2 -0
  13. package/esm2022/lib/models/index.mjs +2 -0
  14. package/esm2022/lib/models/item.model.mjs +2 -0
  15. package/esm2022/lib/models/render-collection.model.mjs +3 -0
  16. package/esm2022/lib/models/render-item-config.model.mjs +2 -0
  17. package/esm2022/lib/models/render-item.model.mjs +3 -0
  18. package/esm2022/lib/models/scroll-direction.model.mjs +2 -0
  19. package/esm2022/lib/models/scroll-event.model.mjs +2 -0
  20. package/esm2022/lib/models/sticky-map.model.mjs +2 -0
  21. package/esm2022/lib/ng-virtual-list.component.mjs +535 -0
  22. package/esm2022/lib/ng-virtual-list.module.mjs +20 -0
  23. package/esm2022/lib/types/id.mjs +2 -0
  24. package/esm2022/lib/types/index.mjs +2 -0
  25. package/esm2022/lib/types/rect.mjs +2 -0
  26. package/esm2022/lib/types/size.mjs +2 -0
  27. package/esm2022/lib/utils/browser.mjs +3 -0
  28. package/esm2022/lib/utils/buffer-interpolation.mjs +27 -0
  29. package/esm2022/lib/utils/cacheMap.mjs +168 -0
  30. package/esm2022/lib/utils/debounce.mjs +31 -0
  31. package/esm2022/lib/utils/eventEmitter.mjs +105 -0
  32. package/esm2022/lib/utils/index.mjs +5 -0
  33. package/esm2022/lib/utils/isDirection.mjs +15 -0
  34. package/esm2022/lib/utils/scrollEvent.mjs +42 -0
  35. package/esm2022/lib/utils/snapping-method.mjs +9 -0
  36. package/esm2022/lib/utils/toggleClassName.mjs +15 -0
  37. package/esm2022/lib/utils/trackBox.mjs +762 -0
  38. package/esm2022/lib/utils/tracker.mjs +135 -0
  39. package/esm2022/ng-virtual-list.mjs +5 -0
  40. package/esm2022/public-api.mjs +11 -0
  41. package/fesm2015/ng-virtual-list.mjs +16 -8
  42. package/fesm2015/ng-virtual-list.mjs.map +1 -1
  43. package/fesm2020/ng-virtual-list.mjs +16 -8
  44. package/fesm2020/ng-virtual-list.mjs.map +1 -1
  45. package/fesm2022/ng-virtual-list.mjs +2055 -0
  46. package/fesm2022/ng-virtual-list.mjs.map +1 -0
  47. package/lib/utils/tracker.d.ts +3 -7
  48. package/package.json +1 -1
@@ -0,0 +1,535 @@
1
+ import { ChangeDetectionStrategy, Component, ElementRef, inject, input, output, signal, ViewChild, viewChild, ViewContainerRef, ViewEncapsulation, } from '@angular/core';
2
+ import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
3
+ import { combineLatest, distinctUntilChanged, filter, map, of, switchMap, tap } from 'rxjs';
4
+ import { NgVirtualListItemComponent } from './components/ng-virtual-list-item.component';
5
+ import { BEHAVIOR_AUTO, BEHAVIOR_INSTANT, CLASS_LIST_HORIZONTAL, CLASS_LIST_VERTICAL, DEFAULT_DIRECTION, DEFAULT_DYNAMIC_SIZE, DEFAULT_ENABLED_BUFFER_OPTIMIZATION, DEFAULT_ITEM_SIZE, DEFAULT_BUFFER_SIZE, DEFAULT_LIST_SIZE, DEFAULT_SNAP, DEFAULT_SNAPPING_METHOD, HEIGHT_PROP_NAME, LEFT_PROP_NAME, MAX_SCROLL_TO_ITERATIONS, PX, SCROLL, SCROLL_END, TOP_PROP_NAME, TRACK_BY_PROPERTY_NAME, WIDTH_PROP_NAME, DEFAULT_MAX_BUFFER_SIZE, } from './const';
6
+ import { Directions } from './enums';
7
+ import { ScrollEvent, toggleClassName } from './utils';
8
+ import { TRACK_BOX_CHANGE_EVENT_NAME, TrackBox } from './utils/trackBox';
9
+ import { isSnappingMethodAdvenced } from './utils/snapping-method';
10
+ import { FIREFOX_SCROLLBAR_OVERLAP_SIZE, IS_FIREFOX } from './utils/browser';
11
+ import { isDirection } from './utils/isDirection';
12
+ import * as i0 from "@angular/core";
13
+ /**
14
+ * Virtual list component.
15
+ * Maximum performance for extremely large lists.
16
+ * It is based on algorithms for virtualization of screen objects.
17
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/18.x/projects/ng-virtual-list/src/lib/ng-virtual-list.component.ts
18
+ * @author Evgenii Grebennikov
19
+ * @email djonnyx@gmail.com
20
+ */
21
+ export class NgVirtualListComponent {
22
+ static __nextId = 0;
23
+ _id = NgVirtualListComponent.__nextId;
24
+ /**
25
+ * Readonly. Returns the unique identifier of the component.
26
+ */
27
+ get id() { return this._id; }
28
+ _listContainerRef;
29
+ _snapContainerRef;
30
+ _snappedContainer = viewChild('snapped');
31
+ _container = viewChild('container');
32
+ _list = viewChild('list');
33
+ /**
34
+ * Fires when the list has been scrolled.
35
+ */
36
+ onScroll = output();
37
+ /**
38
+ * Fires when the list has completed scrolling.
39
+ */
40
+ onScrollEnd = output();
41
+ _itemsOptions = {
42
+ transform: (v) => {
43
+ this._trackBox.resetCollection(v, this.itemSize());
44
+ return v;
45
+ },
46
+ };
47
+ /**
48
+ * Collection of list items.
49
+ */
50
+ items = input.required({
51
+ ...this._itemsOptions,
52
+ });
53
+ /**
54
+ * Determines whether elements will snap. Default value is "true".
55
+ */
56
+ snap = input(DEFAULT_SNAP);
57
+ /**
58
+ * Experimental!
59
+ * Enables buffer optimization.
60
+ * Can only be used if items in the collection are not added or updated. Otherwise, artifacts in the form of twitching of the scroll area are possible.
61
+ * Works only if the property dynamic = true
62
+ */
63
+ enabledBufferOptimization = input(DEFAULT_ENABLED_BUFFER_OPTIMIZATION);
64
+ /**
65
+ * Rendering element template.
66
+ */
67
+ itemRenderer = input.required();
68
+ _itemRenderer = signal(undefined);
69
+ /**
70
+ * Dictionary zIndex by id of the list element. If the value is not set or equal to 0,
71
+ * then a simple element is displayed, if the value is greater than 0, then the sticky position mode is enabled for the element.
72
+ */
73
+ stickyMap = input({});
74
+ _itemSizeOptions = {
75
+ transform: (v) => {
76
+ if (v === undefined) {
77
+ return DEFAULT_ITEM_SIZE;
78
+ }
79
+ const val = Number(v);
80
+ return Number.isNaN(val) || val <= 0 ? DEFAULT_ITEM_SIZE : val;
81
+ },
82
+ };
83
+ /**
84
+ * If direction = 'vertical', then the height of a typical element. If direction = 'horizontal', then the width of a typical element.
85
+ * Ignored if the dynamicSize property is true.
86
+ */
87
+ itemSize = input(DEFAULT_ITEM_SIZE, { ...this._itemSizeOptions });
88
+ /**
89
+ * If true then the items in the list can have different sizes and the itemSize property is ignored.
90
+ * If false then the items in the list have a fixed size specified by the itemSize property. The default value is false.
91
+ */
92
+ dynamicSize = input(DEFAULT_DYNAMIC_SIZE);
93
+ /**
94
+ * Determines the direction in which elements are placed. Default value is "vertical".
95
+ */
96
+ direction = input(DEFAULT_DIRECTION);
97
+ _itemOffsetTransform = {
98
+ transform: (v) => {
99
+ throw Error('"itemOffset" parameter is deprecated. Use "bufferSize" and "maxBufferSize".');
100
+ }
101
+ };
102
+ /**
103
+ * Number of elements outside the scope of visibility. Default value is 2.
104
+ * @deprecated "itemOffset" parameter is deprecated. Use "bufferSize" and "maxBufferSize".
105
+ */
106
+ itemsOffset = input(DEFAULT_BUFFER_SIZE, { ...this._itemOffsetTransform });
107
+ /**
108
+ * Number of elements outside the scope of visibility. Default value is 2.
109
+ */
110
+ bufferSize = input(DEFAULT_BUFFER_SIZE);
111
+ _maxBufferSizeTransform = {
112
+ transform: (v) => {
113
+ const bufferSize = this.bufferSize();
114
+ if (v === undefined || v <= bufferSize) {
115
+ return bufferSize;
116
+ }
117
+ return v;
118
+ }
119
+ };
120
+ /**
121
+ * Maximum number of elements outside the scope of visibility. Default value is 100.
122
+ * If maxBufferSize is set to be greater than bufferSize, then adaptive buffer mode is enabled.
123
+ * The greater the scroll size, the more elements are allocated for rendering.
124
+ */
125
+ maxBufferSize = input(DEFAULT_MAX_BUFFER_SIZE, { ...this._maxBufferSizeTransform });
126
+ /**
127
+ * Snapping method.
128
+ * 'default' - Normal group rendering.
129
+ * 'advanced' - The group is rendered on a transparent background. List items below the group are not rendered.
130
+ */
131
+ snappingMethod = input(DEFAULT_SNAPPING_METHOD);
132
+ _isSnappingMethodAdvanced = this.getIsSnappingMethodAdvanced();
133
+ get isSnappingMethodAdvanced() { return this._isSnappingMethodAdvanced; }
134
+ _isVertical = this.getIsVertical();
135
+ _displayComponents = [];
136
+ _snapedDisplayComponent;
137
+ _bounds = signal(null);
138
+ _scrollSize = signal(0);
139
+ _resizeObserver = null;
140
+ _resizeSnappedComponentHandler = () => {
141
+ const list = this._list(), container = this._container(), snappedComponent = this._snapedDisplayComponent?.instance;
142
+ if (list && container && snappedComponent) {
143
+ const isVertical = this._isVertical, listBounds = list.nativeElement.getBoundingClientRect(), listElement = list?.nativeElement, { width: lWidth, height: lHeight } = listElement?.getBoundingClientRect() ?? { width: 0, height: 0 }, { width, height } = this._bounds() ?? { width: 0, height: 0 }, isScrollable = isVertical ? container.nativeElement.scrollHeight > 0 : container.nativeElement.scrollWidth > 0;
144
+ let scrollBarSize = isVertical ? width - lWidth : height - lHeight, isScrollBarOverlap = true, overlapScrollBarSize = 0;
145
+ if (scrollBarSize === 0 && isScrollable) {
146
+ isScrollBarOverlap = true;
147
+ }
148
+ if (isScrollBarOverlap && IS_FIREFOX) {
149
+ scrollBarSize = overlapScrollBarSize = FIREFOX_SCROLLBAR_OVERLAP_SIZE;
150
+ }
151
+ snappedComponent.element.style.clipPath = `path("M 0 0 L 0 ${snappedComponent.element.offsetHeight} L ${snappedComponent.element.offsetWidth - overlapScrollBarSize} ${snappedComponent.element.offsetHeight} L ${snappedComponent.element.offsetWidth - overlapScrollBarSize} 0 Z")`;
152
+ snappedComponent.regularLength = `${isVertical ? listBounds.width : listBounds.height}${PX}`;
153
+ const { width: sWidth, height: sHeight } = snappedComponent.getBounds() ?? { width: 0, height: 0 }, containerElement = container.nativeElement, delta = snappedComponent.item?.measures.delta ?? 0;
154
+ let left, right, top, bottom;
155
+ if (isVertical) {
156
+ left = 0;
157
+ right = width - scrollBarSize;
158
+ top = sHeight;
159
+ bottom = height;
160
+ containerElement.style.clipPath = `path("M 0 ${top + delta} L 0 ${height} L ${width} ${height} L ${width} 0 L ${right} 0 L ${right} ${top + delta} Z")`;
161
+ }
162
+ else {
163
+ left = sWidth;
164
+ right = width;
165
+ top = 0;
166
+ bottom = height - scrollBarSize;
167
+ containerElement.style.clipPath = `path("M ${left + delta} 0 L ${left + delta} ${bottom} L 0 ${bottom} L 0 ${height} L ${width} ${height} L ${width} 0 Z")`;
168
+ }
169
+ }
170
+ };
171
+ _resizeSnappedObserver = null;
172
+ _componentsResizeObserver = new ResizeObserver(() => {
173
+ this._trackBox.changes();
174
+ });
175
+ _onResizeHandler = () => {
176
+ const bounds = this._container()?.nativeElement?.getBoundingClientRect();
177
+ if (bounds) {
178
+ this._bounds.set({ width: bounds.width, height: bounds.height });
179
+ }
180
+ else {
181
+ this._bounds.set({ width: DEFAULT_LIST_SIZE, height: DEFAULT_LIST_SIZE });
182
+ }
183
+ if (this._isSnappingMethodAdvanced) {
184
+ this.updateRegularRenderer();
185
+ }
186
+ };
187
+ _onScrollHandler = (e) => {
188
+ this.clearScrollToRepeatExecutionTimeout();
189
+ const container = this._container()?.nativeElement;
190
+ if (container) {
191
+ const scrollSize = (this._isVertical ? container.scrollTop : container.scrollLeft), actualScrollSize = scrollSize;
192
+ this._scrollSize.set(actualScrollSize);
193
+ }
194
+ };
195
+ _elementRef = inject((ElementRef));
196
+ _initialized;
197
+ $initialized;
198
+ /**
199
+ * The name of the property by which tracking is performed
200
+ */
201
+ trackBy = input(TRACK_BY_PROPERTY_NAME);
202
+ /**
203
+ * Base class of the element component
204
+ */
205
+ _itemComponentClass = NgVirtualListItemComponent;
206
+ /**
207
+ * Base class trackBox
208
+ */
209
+ _trackBoxClass = TrackBox;
210
+ /**
211
+ * Dictionary of element sizes by their id
212
+ */
213
+ _trackBox = new this._trackBoxClass(this.trackBy());
214
+ _onTrackBoxChangeHandler = (v) => {
215
+ this._cacheVersion.set(v);
216
+ };
217
+ _cacheVersion = signal(-1);
218
+ constructor() {
219
+ NgVirtualListComponent.__nextId = NgVirtualListComponent.__nextId + 1 === Number.MAX_SAFE_INTEGER
220
+ ? 0 : NgVirtualListComponent.__nextId + 1;
221
+ this._id = NgVirtualListComponent.__nextId;
222
+ this._initialized = signal(false);
223
+ this.$initialized = toObservable(this._initialized);
224
+ this._trackBox.displayComponents = this._displayComponents;
225
+ const $trackBy = toObservable(this.trackBy);
226
+ $trackBy.pipe(takeUntilDestroyed(), tap(v => {
227
+ this._trackBox.trackingPropertyName = v;
228
+ })).subscribe();
229
+ const $bounds = toObservable(this._bounds).pipe(filter(b => !!b)), $items = toObservable(this.items).pipe(map(i => !i ? [] : i)), $scrollSize = toObservable(this._scrollSize), $itemSize = toObservable(this.itemSize).pipe(map(v => v <= 0 ? DEFAULT_ITEM_SIZE : v)), $bufferSize = toObservable(this.bufferSize).pipe(map(v => v < 0 ? DEFAULT_BUFFER_SIZE : v)), $maxBufferSize = toObservable(this.maxBufferSize).pipe(map(v => v < 0 ? DEFAULT_BUFFER_SIZE : v)), $stickyMap = toObservable(this.stickyMap).pipe(map(v => !v ? {} : v)), $snap = toObservable(this.snap), $isVertical = toObservable(this.direction).pipe(map(v => this.getIsVertical(v || DEFAULT_DIRECTION))), $dynamicSize = toObservable(this.dynamicSize), $enabledBufferOptimization = toObservable(this.enabledBufferOptimization), $snappingMethod = toObservable(this.snappingMethod).pipe(map(v => this.getIsSnappingMethodAdvanced(v || DEFAULT_SNAPPING_METHOD))), $cacheVersion = toObservable(this._cacheVersion);
230
+ $isVertical.pipe(takeUntilDestroyed(), tap(v => {
231
+ this._isVertical = v;
232
+ const el = this._elementRef.nativeElement;
233
+ toggleClassName(el, v ? CLASS_LIST_VERTICAL : CLASS_LIST_HORIZONTAL, v ? CLASS_LIST_HORIZONTAL : CLASS_LIST_VERTICAL);
234
+ })).subscribe();
235
+ $snappingMethod.pipe(takeUntilDestroyed(), tap(v => {
236
+ this._isSnappingMethodAdvanced = this._trackBox.isSnappingMethodAdvanced = v;
237
+ })).subscribe();
238
+ $dynamicSize.pipe(takeUntilDestroyed(), tap(dynamicSize => {
239
+ this.listenCacheChangesIfNeed(dynamicSize);
240
+ })).subscribe();
241
+ combineLatest([this.$initialized, $bounds, $items, $stickyMap, $scrollSize, $itemSize,
242
+ $bufferSize, $maxBufferSize, $snap, $isVertical, $dynamicSize, $enabledBufferOptimization, $cacheVersion,
243
+ ]).pipe(takeUntilDestroyed(), distinctUntilChanged(), filter(([initialized]) => !!initialized), switchMap(([, bounds, items, stickyMap, scrollSize, itemSize, bufferSize, maxBufferSize, snap, isVertical, dynamicSize, enabledBufferOptimization, cacheVersion,]) => {
244
+ let actualScrollSize = (this._isVertical ? this._container()?.nativeElement.scrollTop ?? 0 : this._container()?.nativeElement.scrollLeft) ?? 0;
245
+ const { width, height } = bounds, opts = {
246
+ bounds: { width, height }, dynamicSize, isVertical, itemSize,
247
+ bufferSize, maxBufferSize, scrollSize: actualScrollSize, snap, enabledBufferOptimization,
248
+ }, { displayItems, totalSize } = this._trackBox.updateCollection(items, stickyMap, opts);
249
+ this.resetBoundsSize(isVertical, totalSize);
250
+ this.createDisplayComponentsIfNeed(displayItems);
251
+ this.tracking();
252
+ if (this._isSnappingMethodAdvanced) {
253
+ this.updateRegularRenderer();
254
+ }
255
+ const container = this._container();
256
+ if (container) {
257
+ const delta = this._trackBox.delta;
258
+ actualScrollSize = actualScrollSize + delta;
259
+ this._trackBox.clearDelta();
260
+ if (scrollSize !== actualScrollSize) {
261
+ const params = {
262
+ [this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: actualScrollSize,
263
+ behavior: BEHAVIOR_INSTANT
264
+ };
265
+ container.nativeElement.scrollTo(params);
266
+ }
267
+ }
268
+ return of(displayItems);
269
+ })).subscribe();
270
+ const $itemRenderer = toObservable(this.itemRenderer);
271
+ $itemRenderer.pipe(takeUntilDestroyed(), distinctUntilChanged(), filter(v => !!v), tap(v => {
272
+ this._itemRenderer.set(v);
273
+ })).subscribe();
274
+ }
275
+ /** @internal */
276
+ ngOnInit() {
277
+ this.onInit();
278
+ }
279
+ onInit() {
280
+ this._initialized.set(true);
281
+ }
282
+ listenCacheChangesIfNeed(value) {
283
+ if (value) {
284
+ if (!this._trackBox.hasEventListener(TRACK_BOX_CHANGE_EVENT_NAME, this._onTrackBoxChangeHandler)) {
285
+ this._trackBox.addEventListener(TRACK_BOX_CHANGE_EVENT_NAME, this._onTrackBoxChangeHandler);
286
+ }
287
+ }
288
+ else {
289
+ if (this._trackBox.hasEventListener(TRACK_BOX_CHANGE_EVENT_NAME, this._onTrackBoxChangeHandler)) {
290
+ this._trackBox.removeEventListener(TRACK_BOX_CHANGE_EVENT_NAME, this._onTrackBoxChangeHandler);
291
+ }
292
+ }
293
+ }
294
+ getIsSnappingMethodAdvanced(m) {
295
+ const method = m || this.snappingMethod();
296
+ return isSnappingMethodAdvenced(method);
297
+ }
298
+ getIsVertical(d) {
299
+ const dir = d || this.direction();
300
+ return isDirection(dir, Directions.VERTICAL);
301
+ }
302
+ createDisplayComponentsIfNeed(displayItems) {
303
+ if (!displayItems || !this._listContainerRef) {
304
+ this._trackBox.setDisplayObjectIndexMapById({});
305
+ return;
306
+ }
307
+ if (this._isSnappingMethodAdvanced && this.snap()) {
308
+ if (!this._snapedDisplayComponent && this._snapContainerRef) {
309
+ const comp = this._snapContainerRef.createComponent(this._itemComponentClass);
310
+ comp.instance.regular = true;
311
+ this._snapedDisplayComponent = comp;
312
+ this._trackBox.snapedDisplayComponent = this._snapedDisplayComponent;
313
+ this._resizeSnappedObserver = new ResizeObserver(this._resizeSnappedComponentHandler);
314
+ this._resizeSnappedObserver.observe(comp.instance.element);
315
+ }
316
+ }
317
+ this._trackBox.items = displayItems;
318
+ const _listContainerRef = this._listContainerRef;
319
+ const maxLength = displayItems.length, components = this._displayComponents;
320
+ while (components.length < maxLength) {
321
+ if (_listContainerRef) {
322
+ const comp = _listContainerRef.createComponent(this._itemComponentClass);
323
+ components.push(comp);
324
+ this._componentsResizeObserver.observe(comp.instance.element);
325
+ }
326
+ }
327
+ this.resetRenderers();
328
+ }
329
+ updateRegularRenderer() {
330
+ this._resizeSnappedComponentHandler();
331
+ }
332
+ resetRenderers(itemRenderer) {
333
+ const doMap = {}, components = this._displayComponents;
334
+ for (let i = 0, l = components.length; i < l; i++) {
335
+ const item = components[i];
336
+ if (item) {
337
+ const id = item.instance.id;
338
+ item.instance.renderer = itemRenderer || this._itemRenderer();
339
+ doMap[id] = i;
340
+ }
341
+ }
342
+ if (this._isSnappingMethodAdvanced && this.snap() && this._snapedDisplayComponent && this._snapContainerRef) {
343
+ const comp = this._snapedDisplayComponent;
344
+ comp.instance.renderer = itemRenderer || this._itemRenderer();
345
+ }
346
+ this._trackBox.setDisplayObjectIndexMapById(doMap);
347
+ }
348
+ /**
349
+ * Tracking by id
350
+ */
351
+ tracking() {
352
+ this._trackBox.track();
353
+ }
354
+ resetBoundsSize(isVertical, totalSize) {
355
+ const l = this._list();
356
+ if (l) {
357
+ l.nativeElement.style[isVertical ? HEIGHT_PROP_NAME : WIDTH_PROP_NAME] = `${totalSize}${PX}`;
358
+ }
359
+ }
360
+ /**
361
+ * Returns the bounds of an element with a given id
362
+ */
363
+ getItemBounds(id) {
364
+ return this._trackBox.getItemBounds(id);
365
+ }
366
+ /**
367
+ * The method scrolls the list to the element with the given id and returns the value of the scrolled area.
368
+ * Behavior accepts the values ​​"auto", "instant" and "smooth".
369
+ */
370
+ scrollTo(id, behavior = BEHAVIOR_AUTO) {
371
+ this.scrollToExecutor(id, behavior);
372
+ }
373
+ _scrollToRepeatExecutionTimeout;
374
+ clearScrollToRepeatExecutionTimeout() {
375
+ clearTimeout(this._scrollToRepeatExecutionTimeout);
376
+ }
377
+ scrollToExecutor(id, behavior, iteration = 0, isLastIteration = false) {
378
+ const items = this.items();
379
+ if (!items || !items.length) {
380
+ return;
381
+ }
382
+ const dynamicSize = this.dynamicSize(), container = this._container(), itemSize = this.itemSize();
383
+ if (container) {
384
+ this.clearScrollToRepeatExecutionTimeout();
385
+ if (dynamicSize) {
386
+ if (container) {
387
+ container.nativeElement.removeEventListener(SCROLL, this._onScrollHandler);
388
+ }
389
+ const { width, height } = this._bounds() || { width: DEFAULT_LIST_SIZE, height: DEFAULT_LIST_SIZE }, stickyMap = this.stickyMap(), items = this.items(), isVertical = this._isVertical, delta = this._trackBox.delta, opts = {
390
+ bounds: { width, height }, collection: items, dynamicSize, isVertical: this._isVertical, itemSize,
391
+ bufferSize: this.bufferSize(), maxBufferSize: this.maxBufferSize(),
392
+ scrollSize: (isVertical ? container.nativeElement.scrollTop : container.nativeElement.scrollLeft) + delta,
393
+ snap: this.snap(), fromItemId: id, enabledBufferOptimization: this.enabledBufferOptimization(),
394
+ }, scrollSize = this._trackBox.getItemPosition(id, stickyMap, opts), params = { [isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: scrollSize, behavior };
395
+ if (scrollSize === -1) {
396
+ container.nativeElement.addEventListener(SCROLL, this._onScrollHandler);
397
+ return;
398
+ }
399
+ this._trackBox.clearDelta();
400
+ if (container) {
401
+ const { displayItems, totalSize } = this._trackBox.updateCollection(items, stickyMap, {
402
+ ...opts, scrollSize, fromItemId: isLastIteration ? undefined : id,
403
+ }), delta = this._trackBox.delta;
404
+ this._trackBox.clearDelta();
405
+ let actualScrollSize = scrollSize + delta;
406
+ this.resetBoundsSize(isVertical, totalSize);
407
+ this.createDisplayComponentsIfNeed(displayItems);
408
+ this.tracking();
409
+ const _scrollSize = this._trackBox.getItemPosition(id, stickyMap, { ...opts, scrollSize: actualScrollSize, fromItemId: id });
410
+ if (_scrollSize === -1) {
411
+ container.nativeElement.addEventListener(SCROLL, this._onScrollHandler);
412
+ return;
413
+ }
414
+ const notChanged = actualScrollSize === _scrollSize;
415
+ if (!notChanged || iteration < MAX_SCROLL_TO_ITERATIONS) {
416
+ this.clearScrollToRepeatExecutionTimeout();
417
+ this._scrollToRepeatExecutionTimeout = setTimeout(() => {
418
+ this.scrollToExecutor(id, BEHAVIOR_INSTANT, iteration + 1, notChanged);
419
+ });
420
+ }
421
+ else {
422
+ this._scrollSize.set(actualScrollSize);
423
+ container.nativeElement.addEventListener(SCROLL, this._onScrollHandler);
424
+ }
425
+ }
426
+ container.nativeElement.scrollTo(params);
427
+ this._scrollSize.set(scrollSize);
428
+ }
429
+ else {
430
+ const index = items.findIndex(item => item.id === id);
431
+ if (index > -1) {
432
+ const scrollSize = index * this.itemSize();
433
+ const params = { [this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: scrollSize, behavior };
434
+ container.nativeElement.scrollTo(params);
435
+ }
436
+ }
437
+ }
438
+ }
439
+ /**
440
+ * Scrolls the scroll area to the desired element with the specified ID.
441
+ */
442
+ scrollToEnd(behavior = BEHAVIOR_INSTANT) {
443
+ const items = this.items(), latItem = items[items.length > 0 ? items.length - 1 : 0];
444
+ this.scrollTo(latItem.id, behavior);
445
+ }
446
+ _onContainerScrollHandler = (e) => {
447
+ const containerEl = this._container();
448
+ if (containerEl) {
449
+ const scrollSize = (this._isVertical ? containerEl.nativeElement.scrollTop : containerEl.nativeElement.scrollLeft);
450
+ this._trackBox.deltaDirection = this._scrollSize() > scrollSize ? -1 : this._scrollSize() < scrollSize ? 1 : 0;
451
+ const event = new ScrollEvent({
452
+ direction: this._trackBox.scrollDirection, container: containerEl.nativeElement,
453
+ list: this._list().nativeElement, delta: this._trackBox.delta,
454
+ scrollDelta: this._trackBox.scrollDelta, isVertical: this._isVertical,
455
+ });
456
+ this.onScroll.emit(event);
457
+ }
458
+ };
459
+ _onContainerScrollEndHandler = (e) => {
460
+ const containerEl = this._container();
461
+ if (containerEl) {
462
+ const scrollSize = (this._isVertical ? containerEl.nativeElement.scrollTop : containerEl.nativeElement.scrollLeft);
463
+ this._trackBox.deltaDirection = this._scrollSize() > scrollSize ? -1 : 0;
464
+ const event = new ScrollEvent({
465
+ direction: this._trackBox.scrollDirection, container: containerEl.nativeElement,
466
+ list: this._list().nativeElement, delta: this._trackBox.delta,
467
+ scrollDelta: this._trackBox.scrollDelta, isVertical: this._isVertical,
468
+ });
469
+ this.onScrollEnd.emit(event);
470
+ }
471
+ };
472
+ /** @internal */
473
+ ngAfterViewInit() {
474
+ this.afterViewInit();
475
+ }
476
+ afterViewInit() {
477
+ const containerEl = this._container();
478
+ if (containerEl) {
479
+ // for direction calculation
480
+ containerEl.nativeElement.addEventListener(SCROLL, this._onContainerScrollHandler);
481
+ containerEl.nativeElement.addEventListener(SCROLL_END, this._onContainerScrollEndHandler);
482
+ containerEl.nativeElement.addEventListener(SCROLL, this._onScrollHandler);
483
+ this._resizeObserver = new ResizeObserver(this._onResizeHandler);
484
+ this._resizeObserver.observe(containerEl.nativeElement);
485
+ this._onResizeHandler();
486
+ }
487
+ }
488
+ /** @internal */
489
+ ngOnDestroy() {
490
+ this.dispose();
491
+ }
492
+ dispose() {
493
+ this.clearScrollToRepeatExecutionTimeout();
494
+ if (this._trackBox) {
495
+ this._trackBox.dispose();
496
+ }
497
+ if (this._componentsResizeObserver) {
498
+ this._componentsResizeObserver.disconnect();
499
+ }
500
+ if (this._resizeSnappedObserver) {
501
+ this._resizeSnappedObserver.disconnect();
502
+ }
503
+ if (this._resizeObserver) {
504
+ this._resizeObserver.disconnect();
505
+ }
506
+ const containerEl = this._container();
507
+ if (containerEl) {
508
+ containerEl.nativeElement.removeEventListener(SCROLL, this._onScrollHandler);
509
+ containerEl.nativeElement.removeEventListener(SCROLL, this._onContainerScrollHandler);
510
+ containerEl.nativeElement.removeEventListener(SCROLL_END, this._onContainerScrollEndHandler);
511
+ }
512
+ if (this._snapedDisplayComponent) {
513
+ this._snapedDisplayComponent.destroy();
514
+ }
515
+ if (this._displayComponents) {
516
+ while (this._displayComponents.length > 0) {
517
+ const comp = this._displayComponents.pop();
518
+ comp?.destroy();
519
+ }
520
+ }
521
+ }
522
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NgVirtualListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
523
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: NgVirtualListComponent, selector: "ng-virtual-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, snap: { classPropertyName: "snap", publicName: "snap", isSignal: true, isRequired: false, transformFunction: null }, enabledBufferOptimization: { classPropertyName: "enabledBufferOptimization", publicName: "enabledBufferOptimization", isSignal: true, isRequired: false, transformFunction: null }, itemRenderer: { classPropertyName: "itemRenderer", publicName: "itemRenderer", isSignal: true, isRequired: true, transformFunction: null }, stickyMap: { classPropertyName: "stickyMap", publicName: "stickyMap", isSignal: true, isRequired: false, transformFunction: null }, itemSize: { classPropertyName: "itemSize", publicName: "itemSize", isSignal: true, isRequired: false, transformFunction: null }, dynamicSize: { classPropertyName: "dynamicSize", publicName: "dynamicSize", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, itemsOffset: { classPropertyName: "itemsOffset", publicName: "itemsOffset", isSignal: true, isRequired: false, transformFunction: null }, bufferSize: { classPropertyName: "bufferSize", publicName: "bufferSize", isSignal: true, isRequired: false, transformFunction: null }, maxBufferSize: { classPropertyName: "maxBufferSize", publicName: "maxBufferSize", isSignal: true, isRequired: false, transformFunction: null }, snappingMethod: { classPropertyName: "snappingMethod", publicName: "snappingMethod", isSignal: true, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onScroll: "onScroll", onScrollEnd: "onScrollEnd" }, viewQueries: [{ propertyName: "_snappedContainer", first: true, predicate: ["snapped"], descendants: true, isSignal: true }, { propertyName: "_container", first: true, predicate: ["container"], descendants: true, isSignal: true }, { propertyName: "_list", first: true, predicate: ["list"], descendants: true, isSignal: true }, { propertyName: "_listContainerRef", first: true, predicate: ["renderersContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "_snapContainerRef", first: true, predicate: ["snapRendererContainer"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "@if (snap()) {\r\n<div #snapped part=\"snapped-item\" class=\"ngvl__list-snapper\">\r\n <ng-container #snapRendererContainer></ng-container>\r\n</div>\r\n}\r\n<div #container part=\"scroller\" class=\"ngvl__scroller\">\r\n <ul #list part=\"list\" class=\"ngvl__list\">\r\n <ng-container #renderersContainer></ng-container>\r\n </ul>\r\n</div>", styles: [":host{position:relative;display:block;width:400px;overflow:hidden}:host(.horizontal){height:48px}:host(.horizontal) .ngvl__list{display:inline-flex}:host(.horizontal) .ngvl__scroller{overflow:auto hidden}:host(.vertical) .ngvl__scroller{overflow:hidden auto}:host(.vertical){height:320px}.ngvl__scroller{overflow:auto;width:100%;height:100%}.ngvl__list-snapper{pointer-events:none;position:absolute;list-style:none;left:0;top:0;z-index:1}.ngvl__list{position:relative;list-style:none;padding:0;margin:0;width:100%;height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
524
+ }
525
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NgVirtualListComponent, decorators: [{
526
+ type: Component,
527
+ args: [{ selector: 'ng-virtual-list', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.ShadowDom, template: "@if (snap()) {\r\n<div #snapped part=\"snapped-item\" class=\"ngvl__list-snapper\">\r\n <ng-container #snapRendererContainer></ng-container>\r\n</div>\r\n}\r\n<div #container part=\"scroller\" class=\"ngvl__scroller\">\r\n <ul #list part=\"list\" class=\"ngvl__list\">\r\n <ng-container #renderersContainer></ng-container>\r\n </ul>\r\n</div>", styles: [":host{position:relative;display:block;width:400px;overflow:hidden}:host(.horizontal){height:48px}:host(.horizontal) .ngvl__list{display:inline-flex}:host(.horizontal) .ngvl__scroller{overflow:auto hidden}:host(.vertical) .ngvl__scroller{overflow:hidden auto}:host(.vertical){height:320px}.ngvl__scroller{overflow:auto;width:100%;height:100%}.ngvl__list-snapper{pointer-events:none;position:absolute;list-style:none;left:0;top:0;z-index:1}.ngvl__list{position:relative;list-style:none;padding:0;margin:0;width:100%;height:100%}\n"] }]
528
+ }], ctorParameters: () => [], propDecorators: { _listContainerRef: [{
529
+ type: ViewChild,
530
+ args: ['renderersContainer', { read: ViewContainerRef }]
531
+ }], _snapContainerRef: [{
532
+ type: ViewChild,
533
+ args: ['snapRendererContainer', { read: ViewContainerRef }]
534
+ }] } });
535
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctdmlydHVhbC1saXN0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25nLXZpcnR1YWwtbGlzdC9zcmMvbGliL25nLXZpcnR1YWwtbGlzdC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZy12aXJ0dWFsLWxpc3Qvc3JjL2xpYi9uZy12aXJ0dWFsLWxpc3QuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNVLHVCQUF1QixFQUFFLFNBQVMsRUFBZ0IsVUFBVSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQ3ZFLE1BQU0sRUFBRSxNQUFNLEVBQWUsU0FBUyxFQUFFLFNBQVMsRUFBRSxnQkFBZ0IsRUFBRSxpQkFBaUIsR0FFMUcsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLGtCQUFrQixFQUFFLFlBQVksRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQzlFLE9BQU8sRUFBRSxhQUFhLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBYyxFQUFFLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN4RyxPQUFPLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSw2Q0FBNkMsQ0FBQztBQUN6RixPQUFPLEVBQ0wsYUFBYSxFQUFFLGdCQUFnQixFQUFFLHFCQUFxQixFQUFFLG1CQUFtQixFQUFFLGlCQUFpQixFQUFFLG9CQUFvQixFQUNwSCxtQ0FBbUMsRUFBRSxpQkFBaUIsRUFBRSxtQkFBbUIsRUFBRSxpQkFBaUIsRUFBRSxZQUFZLEVBQUUsdUJBQXVCLEVBQ3JJLGdCQUFnQixFQUFFLGNBQWMsRUFBRSx3QkFBd0IsRUFBRSxFQUFFLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxhQUFhLEVBQUUsc0JBQXNCLEVBQUUsZUFBZSxFQUMxSSx1QkFBdUIsR0FDeEIsTUFBTSxTQUFTLENBQUM7QUFJakIsT0FB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UyxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsSUFBSSxDQUMxQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQ3pDLEVBQ0QsV0FBVyxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsSUFBSSxDQUM5QyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQzFDLEVBQ0QsY0FBYyxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsSUFBSSxDQUNwRCxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQzFDLEVBQ0QsVUFBVSxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxDQUM1QyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FDdEIsRUFDRCxLQUFLLEdBQUcsWUFBWSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFDL0IsV0FBVyxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxDQUM3QyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsSUFBSSxpQkFBaUIsQ0FBQyxDQUFDLENBQ3JELEVBQ0QsWUFBWSxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEVBQzdDLDBCQUEwQixHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUMseUJBQXlC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QixDQUFDLENBQUM7WUFDdEYsV0FBVyxDQUFDLGFBQWEsQ0FBQyxtQkFBbUIsQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLDRCQUE0QixDQUFDLENBQUM7UUFDL0YsQ0FBQztRQUVELElBQUksSUFBSSxDQUFDLHVCQUF1QixFQUFFLENBQUM7WUFDakMsSUFBSSxDQUFDLHVCQUF1QixDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3pDLENBQUM7UUFFRCxJQUFJLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1lBQzVCLE9BQU8sSUFBSSxDQUFDLGtCQUFrQixDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDMUMsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEdBQUcsRUFBRSxDQUFDO2dCQUMzQyxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUM7WUFDbEIsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO3dHQTFyQlUsc0JBQXNCOzRGQUF0QixzQkFBc0IsZ3hFQVNRLGdCQUFnQixxSEFHYixnQkFBZ0IsNkJDdEQ5RCw4VkFTTTs7NEZEaUNPLHNCQUFzQjtrQkFSbEMsU0FBUzsrQkFDRSxpQkFBaUIsY0FDZixLQUFLLG1CQUdBLHVCQUF1QixDQUFDLE1BQU0saUJBQ2hDLGlCQUFpQixDQUFDLFNBQVM7d0RBWWxDLGlCQUFpQjtzQkFEeEIsU0FBUzt1QkFBQyxvQkFBb0IsRUFBRSxFQUFFLElBQUksRUFBRSxnQkFBZ0IsRUFBRTtnQkFJbkQsaUJBQWlCO3NCQUR4QixTQUFTO3VCQUFDLHVCQUF1QixFQUFFLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICBBZnRlclZpZXdJbml0LCBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgQ29tcG9uZW50LCBDb21wb25lbnRSZWYsIEVsZW1lbnRSZWYsIGluamVjdCwgaW5wdXQsXHJcbiAgT25EZXN0cm95LCBPbkluaXQsIG91dHB1dCwgc2lnbmFsLCBUZW1wbGF0ZVJlZiwgVmlld0NoaWxkLCB2aWV3Q2hpbGQsIFZpZXdDb250YWluZXJSZWYsIFZpZXdFbmNhcHN1bGF0aW9uLFxyXG4gIFdyaXRhYmxlU2lnbmFsLFxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQsIHRvT2JzZXJ2YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUvcnhqcy1pbnRlcm9wJztcclxuaW1wb3J0IHsgY29tYmluZUxhdGVzdCwgZGlzdGluY3RVbnRpbENoYW5nZWQsIGZpbHRlciwgbWFwLCBPYnNlcnZhYmxlLCBvZiwgc3dpdGNoTWFwLCB0YXAgfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHsgTmdWaXJ0dWFsTGlzdEl0ZW1Db21wb25lbnQgfSBmcm9tICcuL2NvbXBvbmVudHMvbmctdmlydHVhbC1saXN0LWl0ZW0uY29tcG9uZW50JztcclxuaW1wb3J0IHtcclxuICBCRUhBVklPUl9BVVRPLCBCRUhBVklPUl9JTlNUQU5ULCBDTEFTU19MSVNUX0hPUklaT05UQUwsIENMQVNTX0xJU1RfVkVSVElDQUwsIERFRkFVTFRfRElSRUNUSU9OLCBERUZBVUxUX0RZTkFNSUNfU0laRSxcclxuICBERUZBVUxUX0VOQUJMRURfQlVGRkVSX09QVElNSVpBVElPTiwgREVGQVVMVF9JVEVNX1NJWkUsIERFRkFVTFRfQlVGRkVSX1NJWkUsIERFRkFVTFRfTElTVF9TSVpFLCBERUZBVUxUX1NOQVAsIERFRkFVTFRfU05BUFBJTkdfTUVUSE9ELFxyXG4gIEhFSUdIVF9QUk9QX05BTUUsIExFRlRfUFJPUF9OQU1FLCBNQVhfU0NST0xMX1RPX0lURVJBVElPTlMsIFBYLCBTQ1JPTEwsIFNDUk9MTF9FTkQsIFRPUF9QUk9QX05BTUUsIFRSQUNLX0JZX1BST1BFUlRZX05BTUUsIFdJRFRIX1BST1BfTkFNRSxcclxuICBERUZBVUxUX01BWF9CVUZGRVJfU0laRSxcclxufSBmcm9tICcuL2NvbnN0JztcclxuaW1wb3J0IHsgSVNjcm9sbEV2ZW50LCBJVmlydHVhbExpc3RDb2xsZWN0aW9uLCBJVmlydHVhbExpc3RJdGVtLCBJVmlydHVhbExpc3RTdGlja3lNYXAgfSBmcm9tICcuL21vZGVscyc7XHJcbmltcG9ydCB7IElkLCBJU2l6ZSB9IGZyb20gJy4vdHlwZXMnO1xyXG5pbXBvcnQgeyBJUmVuZGVyVmlydHVhbExpc3RDb2xsZWN0aW9uIH0gZnJvbSAnLi9tb2RlbHMvcmVuZGVyLWNvbGxlY3Rpb24ubW9kZWwnO1xyXG5pbXBvcnQgeyBEaXJlY3Rpb24sIERpcmVjdGlvbnMsIFNuYXBwaW5nTWV0aG9kIH0gZnJvbSAnLi9lbnVtcyc7XHJcbmltcG9ydCB7IFNjcm9sbEV2ZW50LCB0b2dnbGVDbGFzc05hbWUgfSBmcm9tICcuL3V0aWxzJztcclxuaW1wb3J0IHsgSUdldEl0ZW1Qb3NpdGlvbk9wdGlvbnMsIElVcGRhdGVDb2xsZWN0aW9uT3B0aW9ucywgVFJBQ0tfQk9YX0NIQU5HRV9FVkVOVF9OQU1FLCBUcmFja0JveCB9IGZyb20gJy4vdXRpbHMvdHJhY2tCb3gnO1xyXG5pbXBvcnQgeyBpc1NuYXBwaW5nTWV0aG9kQWR2ZW5jZWQgfSBmcm9tICcuL3V0aWxzL3NuYXBwaW5nLW1ldGhvZCc7XHJcbmltcG9ydCB7IEZJUkVGT1hfU0NST0xMQkFSX09WRVJMQVBfU0laRSwgSVNfRklSRUZPWCB9IGZyb20gJy4vdXRpbHMvYnJvd3Nlcic7XHJcbmltcG9ydCB7IEJhc2VWaXJ0dWFsTGlzdEl0ZW1Db21wb25lbnQgfSBmcm9tICcuL21vZGVscy9iYXNlLXZpcnR1YWwtbGlzdC1pdGVtLWNvbXBvbmVudCc7XHJcbmltcG9ydCB7IENvbXBvbmVudCQxIH0gZnJvbSAnLi9tb2RlbHMvY29tcG9uZW50Lm1vZGVsJztcclxuaW1wb3J0IHsgaXNEaXJlY3Rpb24gfSBmcm9tICcuL3V0aWxzL2lzRGlyZWN0aW9uJztcclxuXHJcbi8qKlxyXG4gKiBWaXJ0dWFsIGxpc3QgY29tcG9uZW50LlxyXG4gKiBNYXhpbXVtIHBlcmZvcm1hbmNlIGZvciBleHRyZW1lbHkgbGFyZ2UgbGlzdHMuXHJcbiAqIEl0IGlzIGJhc2VkIG9uIGFsZ29yaXRobXMgZm9yIHZpcnR1YWxpemF0aW9uIG9mIHNjcmVlbiBvYmplY3RzLlxyXG4gKiBAbGluayBodHRwczovL2dpdGh1Yi5jb20vRGpvbm55WC9uZy12aXJ0dWFsLWxpc3QvYmxvYi8xOC54L3Byb2plY3RzL25nLXZpcnR1YWwtbGlzdC9zcmMvbGliL25nLXZpcnR1YWwtbGlzdC5jb21wb25lbnQudHNcclxuICogQGF1dGhvciBFdmdlbmlpIEdyZWJlbm5pa292XHJcbiAqIEBlbWFpbCBkam9ubnl4QGdtYWlsLmNvbVxyXG4gKi9cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICduZy12aXJ0dWFsLWxpc3QnLFxyXG4gIHN0YW5kYWxvbmU6IGZhbHNlLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9uZy12aXJ0dWFsLWxpc3QuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsOiAnLi9uZy12aXJ0dWFsLWxpc3QuY29tcG9uZW50LnNjc3MnLFxyXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxyXG4gIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLlNoYWRvd0RvbSxcclxufSlcclxuZXhwb3J0IGNsYXNzIE5nVmlydHVhbExpc3RDb21wb25lbnQgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0LCBPbkluaXQsIE9uRGVzdHJveSB7XHJcbiAgcHJpdmF0ZSBzdGF0aWMgX19uZXh0SWQ6IG51bWJlciA9IDA7XHJcblxyXG4gIHByaXZhdGUgX2lkOiBudW1iZXIgPSBOZ1ZpcnR1YWxMaXN0Q29tcG9uZW50Ll9fbmV4dElkO1xyXG4gIC8qKlxyXG4gICAqIFJlYWRvbmx5LiBSZXR1cm5zIHRoZSB1bmlxdWUgaWRlbnRpZmllciBvZiB0aGUgY29tcG9uZW50LlxyXG4gICAqL1xyXG4gIGdldCBpZCgpIHsgcmV0dXJuIHRoaXMuX2lkOyB9XHJcblxyXG4gIEBWaWV3Q2hpbGQoJ3JlbmRlcmVyc0NvbnRhaW5lcicsIHsgcmVhZDogVmlld0NvbnRhaW5lclJlZiB9KVxyXG4gIHByaXZhdGUgX2xpc3RDb250YWluZXJSZWY6IFZpZXdDb250YWluZXJSZWYgfCB1bmRlZmluZWQ7XHJcblxyXG4gIEBWaWV3Q2hpbGQoJ3NuYXBSZW5kZXJlckNvbnRhaW5lcicsIHsgcmVhZDogVmlld0NvbnRhaW5lclJlZiB9KVxyXG4gIHByaXZhdGUgX3NuYXBDb250YWluZXJSZWY6IFZpZXdDb250YWluZXJSZWYgfCB1bmRlZmluZWQ7XHJcblxyXG4gIHByaXZhdGUgX3NuYXBwZWRDb250YWluZXIgPSB2aWV3Q2hpbGQ8RWxlbWVudFJlZjxIVE1MRGl2RWxlbWVudD4+KCdzbmFwcGVkJyk7XHJcblxyXG4gIHByaXZhdGUgX2NvbnRhaW5lciA9IHZpZXdDaGlsZDxFbGVtZW50UmVmPEhUTUxEaXZFbGVtZW50Pj4oJ2NvbnRhaW5lcicpO1xyXG5cclxuICBwcml2YXRlIF9saXN0ID0gdmlld0NoaWxkPEVsZW1lbnRSZWY8SFRNTFVMaXN0RWxlbWVudD4+KCdsaXN0Jyk7XHJcblxyXG4gIC8qKlxyXG4gICAqIEZpcmVzIHdoZW4gdGhlIGxpc3QgaGFzIGJlZW4gc2Nyb2xsZWQuXHJcbiAgICovXHJcbiAgb25TY3JvbGwgPSBvdXRwdXQ8SVNjcm9sbEV2ZW50PigpO1xyXG5cclxuICAvKipcclxuICAgKiBGaXJlcyB3aGVuIHRoZSBsaXN0IGhhcyBjb21wbGV0ZWQgc2Nyb2xsaW5nLlxyXG4gICAqL1xyXG4gIG9uU2Nyb2xsRW5kID0gb3V0cHV0PElTY3JvbGxFdmVudD4oKTtcclxuXHJcbiAgcHJpdmF0ZSBfaXRlbXNPcHRpb25zID0ge1xyXG4gICAgdHJhbnNmb3JtOiAodjogSVZpcnR1YWxMaXN0Q29sbGVjdGlvbiB8IHVuZGVmaW5lZCkgPT4ge1xyXG4gICAgICB0aGlzLl90cmFja0JveC5yZXNldENvbGxlY3Rpb24odiwgdGhpcy5pdGVtU2l6ZSgpKTtcclxuICAgICAgcmV0dXJuIHY7XHJcbiAgICB9LFxyXG4gIH0gYXMgYW55O1xyXG5cclxuICAvKipcclxuICAgKiBDb2xsZWN0aW9uIG9mIGxpc3QgaXRlbXMuXHJcbiAgICovXHJcbiAgaXRlbXMgPSBpbnB1dC5yZXF1aXJlZDxJVmlydHVhbExpc3RDb2xsZWN0aW9uPih7XHJcbiAgICAuLi50aGlzLl9pdGVtc09wdGlvbnMsXHJcbiAgfSk7XHJcblxyXG4gIC8qKlxyXG4gICAqIERldGVybWluZXMgd2hldGhlciBlbGVtZW50cyB3aWxsIHNuYXAuIERlZmF1bHQgdmFsdWUgaXMgXCJ0cnVlXCIuXHJcbiAgICovXHJcbiAgc25hcCA9IGlucHV0PGJvb2xlYW4+KERFRkFVTFRfU05BUCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIEV4cGVyaW1lbnRhbCFcclxuICAgKiBFbmFibGVzIGJ1ZmZlciBvcHRpbWl6YXRpb24uXHJcbiAgICogQ2FuIG9ubHkgYmUgdXNlZCBpZiBpdGVtcyBpbiB0aGUgY29sbGVjdGlvbiBhcmUgbm90IGFkZGVkIG9yIHVwZGF0ZWQuIE90aGVyd2lzZSwgYXJ0aWZhY3RzIGluIHRoZSBmb3JtIG9mIHR3aXRjaGluZyBvZiB0aGUgc2Nyb2xsIGFyZWEgYXJlIHBvc3NpYmxlLlxyXG4gICAqIFdvcmtzIG9ubHkgaWYgdGhlIHByb3BlcnR5IGR5bmFtaWMgPSB0cnVlXHJcbiAgICovXHJcbiAgZW5hYmxlZEJ1ZmZlck9wdGltaXphdGlvbiA9IGlucHV0PGJvb2xlYW4+KERFRkFVTFRfRU5BQkxFRF9CVUZGRVJfT1BUSU1JWkFUSU9OKTtcclxuXHJcbiAgLyoqXHJcbiAgICogUmVuZGVyaW5nIGVsZW1lbnQgdGVtcGxhdGUuXHJcbiAgICovXHJcbiAgaXRlbVJlbmRlcmVyID0gaW5wdXQucmVxdWlyZWQ8VGVtcGxhdGVSZWY8YW55Pj4oKTtcclxuXHJcbiAgcHJpdmF0ZSBfaXRlbVJlbmRlcmVyID0gc2lnbmFsPFRlbXBsYXRlUmVmPGFueT4gfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIERpY3Rpb25hcnkgekluZGV4IGJ5IGlkIG9mIHRoZSBsaXN0IGVsZW1lbnQuIElmIHRoZSB2YWx1ZSBpcyBub3Qgc2V0IG9yIGVxdWFsIHRvIDAsXHJcbiAgICogdGhlbiBhIHNpbXBsZSBlbGVtZW50IGlzIGRpc3BsYXllZCwgaWYgdGhlIHZhbHVlIGlzIGdyZWF0ZXIgdGhhbiAwLCB0aGVuIHRoZSBzdGlja3kgcG9zaXRpb24gbW9kZSBpcyBlbmFibGVkIGZvciB0aGUgZWxlbWVudC5cclxuICAgKi9cclxuICBzdGlja3lNYXAgPSBpbnB1dDxJVmlydHVhbExpc3RTdGlja3lNYXA+KHt9KTtcclxuXHJcbiAgcHJpdmF0ZSBfaXRlbVNpemVPcHRpb25zID0ge1xyXG4gICAgdHJhbnNmb3JtOiAodjogbnVtYmVyIHwgdW5kZWZpbmVkKSA9PiB7XHJcbiAgICAgIGlmICh2ID09PSB1bmRlZmluZWQpIHtcclxuICAgICAgICByZXR1cm4gREVGQVVMVF9JVEVNX1NJWkU7XHJcbiAgICAgIH1cclxuICAgICAgY29uc3QgdmFsID0gTnVtYmVyKHYpO1xyXG4gICAgICByZXR1cm4gTnVtYmVyLmlzTmFOKHZhbCkgfHwgdmFsIDw9IDAgPyBERUZBVUxUX0lURU1fU0laRSA6IHZhbDtcclxuICAgIH0sXHJcbiAgfSBhcyBhbnk7XHJcblxyXG4gIC8qKlxyXG4gICAqIElmIGRpcmVjdGlvbiA9ICd2ZXJ0aWNhbCcsIHRoZW4gdGhlIGhlaWdodCBvZiBhIHR5cGljYWwgZWxlbWVudC4gSWYgZGlyZWN0aW9uID0gJ2hvcml6b250YWwnLCB0aGVuIHRoZSB3aWR0aCBvZiBhIHR5cGljYWwgZWxlbWVudC5cclxuICAgKiBJZ25vcmVkIGlmIHRoZSBkeW5hbWljU2l6ZSBwcm9wZXJ0eSBpcyB0cnVlLlxyXG4gICAqL1xyXG4gIGl0ZW1TaXplID0gaW5wdXQ8bnVtYmVyPihERUZBVUxUX0lURU1fU0laRSwgeyAuLi50aGlzLl9pdGVtU2l6ZU9wdGlvbnMgfSk7XHJcblxyXG4gIC8qKlxyXG4gICAqIElmIHRydWUgdGhlbiB0aGUgaXRlbXMgaW4gdGhlIGxpc3QgY2FuIGhhdmUgZGlmZmVyZW50IHNpemVzIGFuZCB0aGUgaXRlbVNpemUgcHJvcGVydHkgaXMgaWdub3JlZC5cclxuICAgKiBJZiBmYWxzZSB0aGVuIHRoZSBpdGVtcyBpbiB0aGUgbGlzdCBoYXZlIGEgZml4ZWQgc2l6ZSBzcGVjaWZpZWQgYnkgdGhlIGl0ZW1TaXplIHByb3BlcnR5LiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBmYWxzZS5cclxuICAgKi9cclxuICBkeW5hbWljU2l6ZSA9IGlucHV0KERFRkFVTFRfRFlOQU1JQ19TSVpFKTtcclxuXHJcbiAgLyoqXHJcbiAgICogRGV0ZXJtaW5lcyB0aGUgZGlyZWN0aW9uIGluIHdoaWNoIGVsZW1lbnRzIGFyZSBwbGFjZWQuIERlZmF1bHQgdmFsdWUgaXMgXCJ2ZXJ0aWNhbFwiLlxyXG4gICAqL1xyXG4gIGRpcmVjdGlvbiA9IGlucHV0PERpcmVjdGlvbj4oREVGQVVMVF9ESVJFQ1RJT04pO1xyXG5cclxuICBwcml2YXRlIF9pdGVtT2Zmc2V0VHJhbnNmb3JtID0ge1xyXG4gICAgdHJhbnNmb3JtOiAodjogbnVtYmVyIHwgdW5kZWZpbmVkKSA9PiB7XHJcbiAgICAgIHRocm93IEVycm9yKCdcIml0ZW1PZmZzZXRcIiBwYXJhbWV0ZXIgaXMgZGVwcmVjYXRlZC4gVXNlIFwiYnVmZmVyU2l6ZVwiIGFuZCBcIm1heEJ1ZmZlclNpemVcIi4nKTtcclxuICAgIH1cclxuICB9IGFzIGFueTtcclxuXHJcbiAgLyoqXHJcbiAgICogTnVtYmVyIG9mIGVsZW1lbnRzIG91dHNpZGUgdGhlIHNjb3BlIG9mIHZpc2liaWxpdHkuIERlZmF1bHQgdmFsdWUgaXMgMi5cclxuICAgKiBAZGVwcmVjYXRlZCBcIml0ZW1PZmZzZXRcIiBwYXJhbWV0ZXIgaXMgZGVwcmVjYXRlZC4gVXNlIFwiYnVmZmVyU2l6ZVwiIGFuZCBcIm1heEJ1ZmZlclNpemVcIi5cclxuICAgKi9cclxuICBpdGVtc09mZnNldCA9IGlucHV0PG51bWJlcj4oREVGQVVMVF9CVUZGRVJfU0laRSwgeyAuLi50aGlzLl9pdGVtT2Zmc2V0VHJhbnNmb3JtIH0pO1xyXG5cclxuICAvKipcclxuICAgKiBOdW1iZXIgb2YgZWxlbWVudHMgb3V0c2lkZSB0aGUgc2NvcGUgb2YgdmlzaWJpbGl0eS4gRGVmYXVsdCB2YWx1ZSBpcyAyLlxyXG4gICAqL1xyXG4gIGJ1ZmZlclNpemUgPSBpbnB1dDxudW1iZXI+KERFRkFVTFRfQlVGRkVSX1NJWkUpO1xyXG5cclxuICBwcml2YXRlIF9tYXhCdWZmZXJTaXplVHJhbnNmb3JtID0ge1xyXG4gICAgdHJhbnNmb3JtOiAodjogbnVtYmVyIHwgdW5kZWZpbmVkKSA9PiB7XHJcbiAgICAgIGNvbnN0IGJ1ZmZlclNpemUgPSB0aGlzLmJ1ZmZlclNpemUoKTtcclxuICAgICAgaWYgKHYgPT09IHVuZGVmaW5lZCB8fCB2IDw9IGJ1ZmZlclNpemUpIHtcclxuICAgICAgICByZXR1cm4gYnVmZmVyU2l6ZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gdjtcclxuICAgIH1cclxuICB9IGFzIGFueTtcclxuXHJcbiAgLyoqXHJcbiAgICogTWF4aW11bSBudW1iZXIgb2YgZWxlbWVudHMgb3V0c2lkZSB0aGUgc2NvcGUgb2YgdmlzaWJpbGl0eS4gRGVmYXVsdCB2YWx1ZSBpcyAxMDAuXHJcbiAgICogSWYgbWF4QnVmZmVyU2l6ZSBpcyBzZXQgdG8gYmUgZ3JlYXRlciB0aGFuIGJ1ZmZlclNpemUsIHRoZW4gYWRhcHRpdmUgYnVmZmVyIG1vZGUgaXMgZW5hYmxlZC5cclxuICAgKiBUaGUgZ3JlYXRlciB0aGUgc2Nyb2xsIHNpemUsIHRoZSBtb3JlIGVsZW1lbnRzIGFyZSBhbGxvY2F0ZWQgZm9yIHJlbmRlcmluZy5cclxuICAgKi9cclxuICBtYXhCdWZmZXJTaXplID0gaW5wdXQ8bnVtYmVyPihERUZBVUxUX01BWF9CVUZGRVJfU0laRSwgeyAuLi50aGlzLl9tYXhCdWZmZXJTaXplVHJhbnNmb3JtIH0pO1xyXG5cclxuICAvKipcclxuICAgKiBTbmFwcGluZyBtZXRob2QuXHJcbiAgICogJ2RlZmF1bHQnIC0gTm9ybWFsIGdyb3VwIHJlbmRlcmluZy5cclxuICAgKiAnYWR2YW5jZWQnIC0gVGhlIGdyb3VwIGlzIHJlbmRlcmVkIG9uIGEgdHJhbnNwYXJlbnQgYmFja2dyb3VuZC4gTGlzdCBpdGVtcyBiZWxvdyB0aGUgZ3JvdXAgYXJlIG5vdCByZW5kZXJlZC5cclxuICAgKi9cclxuICBzbmFwcGluZ01ldGhvZCA9IGlucHV0PFNuYXBwaW5nTWV0aG9kPihERUZBVUxUX1NOQVBQSU5HX01FVEhPRCk7XHJcblxyXG4gIHByaXZhdGUgX2lzU25hcHBpbmdNZXRob2RBZHZhbmNlZDogYm9vbGVhbiA9IHRoaXMuZ2V0SXNTbmFwcGluZ01ldGhvZEFkdmFuY2VkKCk7XHJcbiAgZ2V0IGlzU25hcHBpbmdNZXRob2RBZHZhbmNlZCgpIHsgcmV0dXJuIHRoaXMuX2lzU25hcHBpbmdNZXRob2RBZHZhbmNlZDsgfVxyXG5cclxuICBwcml2YXRlIF9pc1ZlcnRpY2FsID0gdGhpcy5nZXRJc1ZlcnRpY2FsKCk7XHJcblxyXG4gIHByaXZhdGUgX2Rpc3BsYXlDb21wb25lbnRzOiBBcnJheTxDb21wb25lbnRSZWY8QmFzZVZpcnR1YWxMaXN0SXRlbUNvbXBvbmVudD4+ID0gW107XHJcblxyXG4gIHByaXZhdGUgX3NuYXBlZERpc3BsYXlDb21wb25lbnQ6IENvbXBvbmVudFJlZjxCYXNlVmlydHVhbExpc3RJdGVtQ29tcG9uZW50PiB8IHVuZGVmaW5lZDtcclxuXHJcbiAgcHJpdmF0ZSBfYm91bmRzID0gc2lnbmFsPElTaXplIHwgbnVsbD4obnVsbCk7XHJcblxyXG4gIHByaXZhdGUgX3Njcm9sbFNpemUgPSBzaWduYWw8bnVtYmVyPigwKTtcclxuXHJcbiAgcHJpdmF0ZSBfcmVzaXplT2JzZXJ2ZXI6IFJlc2l6ZU9ic2VydmVyIHwgbnVsbCA9IG51bGw7XHJcblxyXG4gIHByaXZhdGUgX3Jlc2l6ZVNuYXBwZWRDb21wb25lbnRIYW5kbGVyID0gKCkgPT4ge1xyXG4gICAgY29uc3QgbGlzdCA9IHRoaXMuX2xpc3QoKSwgY29udGFpbmVyID0gdGhpcy5fY29udGFpbmVyKCksIHNuYXBwZWRDb21wb25lbnQgPSB0aGlzLl9zbmFwZWREaXNwbGF5Q29tcG9uZW50Py5pbnN0YW5jZTtcclxuICAgIGlmIChsaXN0ICYmIGNvbnRhaW5lciAmJiBzbmFwcGVkQ29tcG9uZW50KSB7XHJcbiAgICAgIGNvbnN0IGlzVmVydGljYWwgPSB0aGlzLl9pc1ZlcnRpY2FsLCBsaXN0Qm91bmRzID0gbGlzdC5uYXRpdmVFbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLCBsaXN0RWxlbWVudCA9IGxpc3Q/Lm5hdGl2ZUVsZW1lbnQsXHJcbiAgICAgICAgeyB3aWR0aDogbFdpZHRoLCBoZWlnaHQ6IGxIZWlnaHQgfSA9IGxpc3RFbGVtZW50Py5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKSA/PyB7IHdpZHRoOiAwLCBoZWlnaHQ6IDAgfSxcclxuICAgICAgICB7IHdpZHRoLCBoZWlnaHQgfSA9IHRoaXMuX2JvdW5kcygpID8/IHsgd2lkdGg6IDAsIGhlaWdodDogMCB9LFxyXG4gICAgICAgIGlzU2Nyb2xsYWJsZSA9IGlzVmVydGljYWwgPyBjb250YWluZXIubmF0aXZlRWxlbWVudC5zY3JvbGxIZWlnaHQgPiAwIDogY29udGFpbmVyLm5hdGl2ZUVsZW1lbnQuc2Nyb2xsV2lkdGggPiAwO1xyXG5cclxuICAgICAgbGV0IHNjcm9sbEJhclNpemUgPSBpc1ZlcnRpY2FsID8gd2lkdGggLSBsV2lkdGggOiBoZWlnaHQgLSBsSGVpZ2h0LCBpc1Njcm9sbEJhck92ZXJsYXAgPSB0cnVlLCBvdmVybGFwU2Nyb2xsQmFyU2l6ZSA9IDA7XHJcbiAgICAgIGlmIChzY3JvbGxCYXJTaXplID09PSAwICYmIGlzU2Nyb2xsYWJsZSkge1xyXG4gICAgICAgIGlzU2Nyb2xsQmFyT3ZlcmxhcCA9IHRydWU7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChpc1Njcm9sbEJhck92ZXJsYXAgJiYgSVNfRklSRUZPWCkge1xyXG4gICAgICAgIHNjcm9sbEJhclNpemUgPSBvdmVybGFwU2Nyb2xsQmFyU2l6ZSA9IEZJUkVGT1hfU0NST0xMQkFSX09WRVJMQVBfU0laRTtcclxuICAgICAgfVxyXG5cclxuICAgICAgc25hcHBlZENvbXBvbmVudC5lbGVtZW50LnN0eWxlLmNsaXBQYXRoID0gYHBhdGgoXCJNIDAgMCBMIDAgJHtzbmFwcGVkQ29tcG9uZW50LmVsZW1lbnQub2Zmc2V0SGVpZ2h0fSBMICR7c25hcHBlZENvbXBvbmVudC5lbGVtZW50Lm9mZnNldFdpZHRoIC0gb3ZlcmxhcFNjcm9sbEJhclNpemV9ICR7c25hcHBlZENvbXBvbmVudC5lbGVtZW50Lm9mZnNldEhlaWdodH0gTCAke3NuYXBwZWRDb21wb25lbnQuZWxlbWVudC5vZmZzZXRXaWR0aCAtIG92ZXJsYXBTY3JvbGxCYXJTaXplfSAwIFpcIilgO1xyXG5cclxuICAgICAgc25hcHBlZENvbXBvbmVudC5yZWd1bGFyTGVuZ3RoID0gYCR7aXNWZXJ0aWNhbCA/IGxpc3RCb3VuZHMud2lkdGggOiBsaXN0Qm91bmRzLmhlaWdodH0ke1BYfWA7XHJcbiAgICAgIGNvbnN0IHsgd2lkdGg6IHNXaWR0aCwgaGVpZ2h0OiBzSGVpZ2h0IH0gPSBzbmFwcGVkQ29tcG9uZW50LmdldEJvdW5kcygpID8/IHsgd2lkdGg6IDAsIGhlaWdodDogMCB9LFxyXG4gICAgICAgIGNvbnRhaW5lckVsZW1lbnQgPSBjb250YWluZXIubmF0aXZlRWxlbWVudCwgZGVsdGEgPSBzbmFwcGVkQ29tcG9uZW50Lml0ZW0/Lm1lYXN1cmVzLmRlbHRhID8/IDA7XHJcblxyXG4gICAgICBsZXQgbGVmdDogbnVtYmVyLCByaWdodDogbnVtYmVyLCB0b3A6IG51bWJlciwgYm90dG9tOiBudW1iZXI7XHJcbiAgICAgIGlmIChpc1ZlcnRpY2FsKSB7XHJcbiAgICAgICAgbGVmdCA9IDA7XHJcbiAgICAgICAgcmlnaHQgPSB3aWR0aCAtIHNjcm9sbEJhclNpemU7XHJcbiAgICAgICAgdG9wID0gc0hlaWdodDtcclxuICAgICAgICBib3R0b20gPSBoZWlnaHQ7XHJcbiAgICAgICAgY29udGFpbmVyRWxlbWVudC5zdHlsZS5jbGlwUGF0aCA9IGBwYXRoKFwiTSAwICR7dG9wICsgZGVsdGF9IEwgMCAke2hlaWdodH0gTCAke3dpZHRofSAke2hlaWdodH0gTCAke3dpZHRofSAwIEwgJHtyaWdodH0gMCBMICR7cmlnaHR9ICR7dG9wICsgZGVsdGF9IFpcIilgO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxlZnQgPSBzV2lkdGg7XHJcbiAgICAgICAgcmlnaHQgPSB3aWR0aDtcclxuICAgICAgICB0b3AgPSAwO1xyXG4gICAgICAgIGJvdHRvbSA9IGhlaWdodCAtIHNjcm9sbEJhclNpemU7XHJcbiAgICAgICAgY29udGFpbmVyRWxlbWVudC5zdHlsZS5jbGlwUGF0aCA9IGBwYXRoKFwiTSAke2xlZnQgKyBkZWx0YX0gMCBMICR7bGVmdCArIGRlbHRhfSAke2JvdHRvbX0gTCAwICR7Ym90dG9tfSBMIDAgJHtoZWlnaHR9IEwgJHt3aWR0aH0gJHtoZWlnaHR9IEwgJHt3aWR0aH0gMCBaXCIpYDtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIHByaXZhdGUgX3Jlc2l6ZVNuYXBwZWRPYnNlcnZlcjogUmVzaXplT2JzZXJ2ZXIgfCBudWxsID0gbnVsbDtcclxuXHJcbiAgcHJpdmF0ZSBfY29tcG9uZW50c1Jlc2l6ZU9ic2VydmVyID0gbmV3IFJlc2l6ZU9ic2VydmVyKCgpID0+IHtcclxuICAgIHRoaXMuX3RyYWNrQm94LmNoYW5nZXMoKTtcclxuICB9KTtcclxuXHJcbiAgcHJpdmF0ZSBfb25SZXNpemVIYW5kbGVyID0gKCkgPT4ge1xyXG4gICAgY29uc3QgYm91bmRzID0gdGhpcy5fY29udGFpbmVyKCk/Lm5hdGl2ZUVsZW1lbnQ/LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgaWYgKGJvdW5kcykge1xyXG4gICAgICB0aGlzLl9ib3VuZHMuc2V0KHsgd2lkdGg6IGJvdW5kcy53aWR0aCwgaGVpZ2h0OiBib3VuZHMuaGVpZ2h0IH0pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5fYm91bmRzLnNldCh7IHdpZHRoOiBERUZBVUxUX0xJU1RfU0laRSwgaGVpZ2h0OiBERUZBVUxUX0xJU1RfU0laRSB9KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5faXNTbmFwcGluZ01ldGhvZEFkdmFuY2VkKSB7XHJcbiAgICAgIHRoaXMudXBkYXRlUmVndWxhclJlbmRlcmVyKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIF9vblNjcm9sbEhhbmRsZXIgPSAoZT86IEV2ZW50KSA9PiB7XHJcbiAgICB0aGlzLmNsZWFyU2Nyb2xsVG9SZXBlYXRFeGVjdXRpb25UaW1lb3V0KCk7XHJcblxyXG4gICAgY29uc3QgY29udGFpbmVyID0gdGhpcy5fY29udGFpbmVyKCk/Lm5hdGl2ZUVsZW1lbnQ7XHJcbiAgICBpZiAoY29udGFpbmVyKSB7XHJcbiAgICAgIGNvbnN0IHNjcm9sbFNpemUgPSAodGhpcy5faXNWZXJ0aWNhbCA/IGNvbnRhaW5lci5zY3JvbGxUb3AgOiBjb250YWluZXIuc2Nyb2xsTGVmdCksXHJcbiAgICAgICAgYWN0dWFsU2Nyb2xsU2l6ZSA9IHNjcm9sbFNpemU7XHJcbiAgICAgIHRoaXMuX3Njcm9sbFNpemUuc2V0KGFjdHVhbFNjcm9sbFNpemUpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBfZWxlbWVudFJlZiA9IGluamVjdChFbGVtZW50UmVmPEhUTUxEaXZFbGVtZW50Pik7XHJcblxyXG4gIHByaXZhdGUgX2luaXRpYWxpemVkITogV3JpdGFibGVTaWduYWw8Ym9vbGVhbj47XHJcblxyXG4gIHJlYWRvbmx5ICRpbml0aWFsaXplZCE6IE9ic2VydmFibGU8Ym9vbGVhbj47XHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBwcm9wZXJ0eSBieSB3aGljaCB0cmFja2luZyBpcyBwZXJmb3JtZWRcclxuICAgKi9cclxuICB0cmFja0J5ID0gaW5wdXQ8c3RyaW5nPihUUkFDS19CWV9QUk9QRVJUWV9OQU1FKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQmFzZSBjbGFzcyBvZiB0aGUgZWxlbWVudCBjb21wb25lbnRcclxuICAgKi9cclxuICBwcml2YXRlIF9pdGVtQ29tcG9uZW50Q2xhc3M6IENvbXBvbmVudCQxPEJhc2VWaXJ0dWFsTGlzdEl0ZW1Db21wb25lbnQ+ID0gTmdWaXJ0dWFsTGlzdEl0ZW1Db21wb25lbnQ7XHJcblxyXG4gIC8qKlxyXG4gICAqIEJhc2UgY2xhc3MgdHJhY2tCb3hcclxuICAgKi9cclxuICBwcml2YXRlIF90cmFja0JveENsYXNzOiBDb21wb25lbnQkMTxUcmFja0JveD4gPSBUcmFja0JveDtcclxuXHJcbiAgLyoqXHJcbiAgICogRGljdGlvbmFyeSBvZiBlbGVtZW50IHNpemVzIGJ5IHRoZWlyIGlkXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBfdHJhY2tCb3g6IFRyYWNrQm94ID0gbmV3IHRoaXMuX3RyYWNrQm94Q2xhc3ModGhpcy50cmFja0J5KCkpO1xyXG5cclxuICBwcml2YXRlIF9vblRyYWNrQm94Q2hhbmdlSGFuZGxlciA9ICh2OiBudW1iZXIpID0+IHtcclxuICAgIHRoaXMuX2NhY2hlVmVyc2lvbi5zZXQodik7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIF9jYWNoZVZlcnNpb24gPSBzaWduYWw8bnVtYmVyPigtMSk7XHJcblxyXG4gIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgTmdWaXJ0dWFsTGlzdENvbXBvbmVudC5fX25leHRJZCA9IE5nVmlydHVhbExpc3RDb21wb25lbnQuX19uZXh0SWQgKyAxID09PSBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUlxyXG4gICAgICA/IDAgOiBOZ1ZpcnR1YWxMaXN0Q29tcG9uZW50Ll9fbmV4dElkICsgMTtcclxuICAgIHRoaXMuX2lkID0gTmdWaXJ0dWFsTGlzdENvbXBvbmVudC5fX25leHRJZDtcclxuXHJcbiAgICB0aGlzLl9pbml0aWFsaXplZCA9IHNpZ25hbDxib29sZWFuPihmYWxzZSk7XHJcbiAgICB0aGlzLiRpbml0aWFsaXplZCA9IHRvT2JzZXJ2YWJsZSh0aGlzLl9pbml0aWFsaXplZCk7XHJcblxyXG4gICAgdGhpcy5fdHJhY2tCb3guZGlzcGxheUNvbXBvbmVudHMgPSB0aGlzLl9kaXNwbGF5Q29tcG9uZW50cztcclxuXHJcbiAgICBjb25zdCAkdHJhY2tCeSA9IHRvT2JzZXJ2YWJsZSh0aGlzLnRyYWNrQnkpO1xyXG5cclxuICAgICR0cmFja0J5LnBpcGUoXHJcbiAgICAgIHRha2VVbnRpbERlc3Ryb3llZCgpLFxyXG4gICAgICB0YXAodiA9PiB7XHJcbiAgICAgICAgdGhpcy5fdHJhY2tCb3gudHJhY2tpbmdQcm9wZXJ0eU5hbWUgPSB2O1xyXG4gICAgICB9KSxcclxuICAgICkuc3Vic2NyaWJlKCk7XHJcblxyXG4gICAgY29uc3QgJGJvdW5kcyA9IHRvT2JzZXJ2YWJsZSh0aGlzLl9ib3VuZHMpLnBpcGUoXHJcbiAgICAgIGZpbHRlcihiID0+ICEhYiksXHJcbiAgICApLCAkaXRlbXMgPSB0b09ic2VydmFibGUodGhpcy5pdGVtcykucGlwZShcclxuICAgICAgbWFwKGkgPT4gIWkgPyBbXSA6IGkpLFxyXG4gICAgKSwgJHNjcm9sbFNpemUgPSB0b09ic2VydmFibGUodGhpcy5fc2Nyb2xsU2l6ZSksXHJcbiAgICAgICRpdGVtU2l6ZSA9IHRvT2JzZXJ2YWJsZSh0aGlzLml0ZW1TaXplKS5waXBlKFxyXG4gICAgICAgIG1hcCh2ID0+IHYgPD0gMCA/IERFRkFVTFRfSVRFTV9TSVpFIDogdiksXHJcbiAgICAgICksXHJcbiAgICAgICRidWZmZXJTaXplID0gdG9PYnNlcnZhYmxlKHRoaXMuYnVmZmVyU2l6ZSkucGlwZShcclxuICAgICAgICBtYXAodiA9PiB2IDwgMCA/IERFRkFVTFRfQlVGRkVSX1NJWkUgOiB2KSxcclxuICAgICAgKSxcclxuICAgICAgJG1heEJ1ZmZlclNpemUgPSB0b09ic2VydmFibGUodGhpcy5tYXhCdWZmZXJTaXplKS5waXBlKFxyXG4gICAgICAgIG1hcCh2ID0+IHYgPCAwID8gREVGQVVMVF9CVUZGRVJfU0laRSA6IHYpLFxyXG4gICAgICApLFxyXG4gICAgICAkc3RpY2t5TWFwID0gdG9PYnNlcnZhYmxlKHRoaXMuc3RpY2t5TWFwKS5waXBlKFxyXG4gICAgICAgIG1hcCh2ID0+ICF2ID8ge30gOiB2KSxcclxuICAgICAgKSxcclxuICAgICAgJHNuYXAgPSB0b09ic2VydmFibGUodGhpcy5zbmFwKSxcclxuICAgICAgJGlzVmVydGljYWwgPSB0b09ic2VydmFibGUodGhpcy5kaXJlY3Rpb24pLnBpcGUoXHJcbiAgICAgICAgbWFwKHYgPT4gdGhpcy5nZXRJc1ZlcnRpY2FsKHYgfHwgREVGQVVMVF9ESVJFQ1RJT04pKSxcclxuICAgICAgKSxcclxuICAgICAgJGR5bmFtaWNTaXplID0gdG9PYnNlcnZhYmxlKHRoaXMuZHluYW1pY1NpemUpLFxyXG4gICAgICAkZW5hYmxlZEJ1ZmZlck9wdGltaXphdGlvbiA9IHRvT2JzZXJ2YWJsZSh0aGlzLmVuYWJsZWRCdWZmZXJPcHRpbWl6YXRpb24pLFxyXG4gICAgICAkc25hcHBpbmdNZXRob2QgPSB0b09ic2VydmFibGUodGhpcy5zbmFwcGluZ01ldGhvZCkucGlwZShcclxuICAgICAgICBtYXAodiA9PiB0aGlzLmdldElzU25hcHBpbmdNZXRob2RBZHZhbmNlZCh2IHx8IERFRkFVTFRfU05BUFBJTkdfTUVUSE9EKSksXHJcbiAgICAgICksXHJcbiAgICAgICRjYWNoZVZlcnNpb24gPSB0b09ic2VydmFibGUodGhpcy5fY2FjaGVWZXJzaW9uKTtcclxuXHJcbiAgICAkaXNWZXJ0aWNhbC5waXBlKFxyXG4gICAgICB0YWtlVW50aWxEZXN0cm95ZWQoKSxcclxuICAgICAgdGFwKHYgPT4ge1xyXG4gICAgICAgIHRoaXMuX2lzVmVydGljYWwgPSB2O1xyXG4gICAgICAgIGNvbnN0IGVsOiBIVE1MRWxlbWVudCA9IHRoaXMuX2VsZW1lbnRSZWYubmF0aXZlRWxlbWVudDtcclxuICAgICAgICB0b2dnbGVDbGFzc05hbWUoZWwsIHYgPyBDTEFTU19MSVNUX1ZFUlRJQ0FMIDogQ0xBU1NfTElTVF9IT1JJWk9OVEFMLCB2ID8gQ0xBU1NfTElTVF9IT1JJWk9OVEFMIDogQ0xBU1NfTElTVF9WRVJUSUNBTCk7XHJcbiAgICAgIH0pLFxyXG4gICAgKS5zdWJzY3JpYmUoKTtcclxuXHJcbiAgICAkc25hcHBpbmdNZXRob2QucGlwZShcclxuICAgICAgdGFrZVVudGlsRGVzdHJveWVkKCksXHJcbiAgICAgIHRhcCh2ID0+IHtcclxuICAgICAgICB0aGlzLl9pc1NuYXBwaW5nTWV0aG9kQWR2YW5jZWQgPSB0aGlzLl90cmFja0JveC5pc1NuYXBwaW5nTWV0aG9kQWR2YW5jZWQgPSB2O1xyXG4gICAgICB9KSxcclxuICAgICkuc3Vic2NyaWJlKCk7XHJcblxyXG4gICAgJGR5bmFtaWNTaXplLnBpcGUoXHJcbiAgICAgIHRha2VVbnRpbERlc3Ryb3llZCgpLFxyXG4gICAgICB0YXAoZHluYW1pY1NpemUgPT4ge1xyXG4gICAgICAgIHRoaXMubGlzdGVuQ2FjaGVDaGFuZ2VzSWZOZWVkKGR5bmFtaWNTaXplKTtcclxuICAgICAgfSlcclxuICAgICkuc3Vic2NyaWJlKCk7XHJcblxyXG4gICAgY29tYmluZUxhdGVzdChbdGhpcy4kaW5pdGlhbGl6ZWQsICRib3VuZHMsICRpdGVtcywgJHN0aWNreU1hcCwgJHNjcm9sbFNpemUsICRpdGVtU2l6ZSxcclxuICAgICAgJGJ1ZmZlclNpemUsICRtYXhCdWZmZXJTaXplLCAkc25hcCwgJGlzVmVydGljYWwsICRkeW5hbWljU2l6ZSwgJGVuYWJsZWRCdWZmZXJPcHRpbWl6YXRpb24sICRjYWNoZVZlcnNpb24sXHJcbiAgICBdKS5waXBlKFxyXG4gICAgICB0YWtlVW50aWxEZXN0cm95ZWQoKSxcclxuICAgICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKSxcclxuICAgICAgZmlsdGVyKChbaW5pdGlhbGl6ZWRdKSA9PiAhIWluaXRpYWxpemVkKSxcclxuICAgICAgc3dpdGNoTWFwKChbLFxyXG4gICAgICAgIGJvdW5kcywgaXRlbXMsIHN0aWNreU1hcCwgc2Nyb2xsU2l6ZSwgaXRlbVNpemUsXHJcbiAgICAgICAgYnVmZmVyU2l6ZSwgbWF4QnVmZmVyU2l6ZSwgc25hcCwgaXNWZXJ0aWNhbCwgZHluYW1pY1NpemUsIGVuYWJsZWRCdWZmZXJPcHRpbWl6YXRpb24sIGNhY2hlVmVyc2lvbixcclxuICAgICAgXSkgPT4ge1xyXG4gICAgICAgIGxldCBhY3R1YWxTY3JvbGxTaXplID0gKHRoaXMuX2lzVmVydGljYWwgPyB0aGlzLl9jb250YWluZXIoKT8ubmF0aXZlRWxlbWVudC5zY3JvbGxUb3AgPz8gMCA6IHRoaXMuX2NvbnRhaW5lcigpPy5uYXRpdmVFbGVtZW50LnNjcm9sbExlZnQpID8/IDA7XHJcbiAgICAgICAgY29uc3QgeyB3aWR0aCwgaGVpZ2h0IH0gPSBib3VuZHMgYXMgSVNpemUsXHJcbiAgICAgICAgICBvcHRzOiBJVXBkYXRlQ29sbGVjdGlvbk9wdGlvbnM8SVZpcnR1YWxMaXN0SXRlbSwgSVZpcnR1YWxMaXN0Q29sbGVjdGlvbj4gPSB7XHJcbiAgICAgICAgICAgIGJvdW5kczogeyB3aWR0aCwgaGVpZ2h0IH0sIGR5bmFtaWNTaXplLCBpc1ZlcnRpY2FsLCBpdGVtU2l6ZSxcclxuICAgICAgICAgICAgYnVmZmVyU2l6ZSwgbWF4QnVmZmVyU2l6ZSwgc2Nyb2xsU2l6ZTogYWN0dWFsU2Nyb2xsU2l6ZSwgc25hcCwgZW5hYmxlZEJ1ZmZlck9wdGltaXphdGlvbixcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICB7IGRpc3BsYXlJdGVtcywgdG90YWxTaXplIH0gPSB0aGlzLl90cmFja0JveC51cGRhdGVDb2xsZWN0aW9uKGl0ZW1zLCBzdGlja3lNYXAsIG9wdHMpO1xyXG5cclxuICAgICAgICB0aGlzLnJlc2V0Qm91bmRzU2l6ZShpc1ZlcnRpY2FsLCB0b3RhbFNpemUpO1xyXG5cclxuICAgICAgICB0aGlzLmNyZWF0ZURpc3BsYXlDb21wb25lbnRzSWZOZWVkKGRpc3BsYXlJdGVtcyk7XHJcblxyXG4gICAgICAgIHRoaXMudHJhY2tpbmcoKTtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMuX2lzU25hcHBpbmdNZXRob2RBZHZhbmNlZCkge1xyXG4gICAgICAgICAgdGhpcy51cGRhdGVSZWd1bGFyUmVuZGVyZXIoKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGNvbnN0IGNvbnRhaW5lciA9IHRoaXMuX2NvbnRhaW5lcigpO1xyXG5cclxuICAgICAgICBpZiAoY29udGFpbmVyKSB7XHJcbiAgICAgICAgICBjb25zdCBkZWx0YSA9IHRoaXMuX3RyYWNrQm94LmRlbHRhO1xyXG4gICAgICAgICAgYWN0dWFsU2Nyb2xsU2l6ZSA9IGFjdHVhbFNjcm9sbFNpemUgKyBkZWx0YTtcclxuXHJcbiAgICAgICAgICB0aGlzLl90cmFja0JveC5jbGVhckRlbHRhKCk7XHJcblxyXG4gICAgICAgICAgaWYgKHNjcm9sbFNpemUgIT09IGFjdHVhbFNjcm9sbFNpemUpIHtcclxuICAgICAgICAgICAgY29uc3QgcGFyYW1zOiBTY3JvbGxUb09wdGlvbnMgPSB7XHJcbiAgICAgICAgICAgICAgW3RoaXMuX2lzVmVydGljYWwgPyBUT1BfUFJPUF9OQU1FIDogTEVGVF9QUk9QX05BTUVdOiBhY3R1YWxTY3JvbGxTaXplLFxyXG4gICAgICAgICAgICAgIGJlaGF2aW9yOiBCRUhBVklPUl9JTlNUQU5UXHJcbiAgICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgICBjb250YWluZXIubmF0aXZlRWxlbWVudC5zY3JvbGxUbyhwYXJhbXMpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgcmV0dXJuIG9mKGRpc3BsYXlJdGVtcyk7XHJcbiAgICAgIH0pLFxyXG4gICAgKS5zdWJzY3JpYmUoKTtcclxuXHJcbiAgICBjb25zdCAkaXRlbVJlbmRlcmVyID0gdG9PYnNlcnZhYmxlKHRoaXMuaXRlbVJlbmRlcmVyKTtcclxuXHJcbiAgICAkaXRlbVJlbmRlcmVyLnBpcGUoXHJcbiAgICAgIHRha2VVbnRpbERlc3Ryb3llZCgpLFxyXG4gICAgICBkaXN0aW5jdFVudGlsQ2hhbmdlZCgpLFxyXG4gICAgICBmaWx0ZXIodiA9PiAhIXYpLFxyXG4gICAgICB0YXAodiA9PiB7XHJcbiAgICAgICAgdGhpcy5faXRlbVJlbmRlcmVyLnNldCh2KTtcclxuICAgICAgfSksXHJcbiAgICApLnN1YnNjcmliZSgpO1xyXG4gIH1cclxuXHJcbiAgLyoqIEBpbnRlcm5hbCAqL1xyXG4gIG5nT25Jbml0KCkge1xyXG4gICAgdGhpcy5vbkluaXQoKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgb25Jbml0KCkge1xyXG4gICAgdGhpcy5faW5pdGlhbGl6ZWQuc2V0KHRydWUpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBsaXN0ZW5DYWNoZUNoYW5nZXNJZk5lZWQodmFsdWU6IGJvb2xlYW4pIHtcclxuICAgIGlmICh2YWx1ZSkge1xyXG4gICAgICBpZiAoIXRoaXMuX3RyYWNrQm94Lmhhc0V2ZW50TGlzdGVuZXIoVFJBQ0tfQk9YX0NIQU5HRV9FVkVOVF9OQU1FLCB0aGlzLl9vblRyYWNrQm94Q2hhbmdlSGFuZGxlcikpIHtcclxuICAgICAgICB0aGlzLl90cmFja0JveC5hZGRFdmVudExpc3RlbmVyKFRSQUNLX0JPWF9DSEFOR0VfRVZFTlRfTkFNRSwgdGhpcy5fb25UcmFja0JveENoYW5nZUhhbmRsZXIpO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBpZiAodGhpcy5fdHJhY2tCb3guaGFzRXZlbnRMaXN0ZW5lcihUUkFDS19CT1hfQ0hBTkdFX0VWRU5UX05BTUUsIHRoaXMuX29uVHJhY2tCb3hDaGFuZ2VIYW5kbGVyKSkge1xyXG4gICAgICAgIHRoaXMuX3RyYWNrQm94LnJlbW92ZUV2ZW50TGlzdGVuZXIoVFJBQ0tfQk9YX0NIQU5HRV9FVkVOVF9OQU1FLCB0aGlzLl9vblRyYWNrQm94Q2hhbmdlSGFuZGxlcik7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgZ2V0SXNTbmFwcGluZ01ldGhvZEFkdmFuY2VkKG0/OiBTbmFwcGluZ01ldGhvZCkge1xyXG4gICAgY29uc3QgbWV0aG9kID0gbSB8fCB0aGlzLnNuYXBwaW5nTWV0aG9kKCk7XHJcbiAgICByZXR1cm4gaXNTbmFwcGluZ01ldGhvZEFkdmVuY2VkKG1ldGhvZCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGdldElzVmVydGljYWwoZD86IERpcmVjdGlvbikge1xyXG4gICAgY29uc3QgZGlyID0gZCB8fCB0aGlzLmRpcmVjdGlvbigpO1xyXG4gICAgcmV0dXJuIGlzRGlyZWN0aW9uKGRpciwgRGlyZWN0aW9ucy5WRVJUSUNBTCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGNyZWF0ZURpc3BsYXlDb21wb25lbnRzSWZOZWVkKGRpc3BsYXlJdGVtczogSVJlbmRlclZpcnR1YWxMaXN0Q29sbGVjdGlvbiB8IG51bGwpIHtcclxuICAgIGlmICghZGlzcGxheUl0ZW1zIHx8ICF0aGlzLl9saXN0Q29udGFpbmVyUmVmKSB7XHJcbiAgICAgIHRoaXMuX3RyYWNrQm94LnNldERpc3BsYXlPYmplY3RJbmRleE1hcEJ5SWQoe30pO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMuX2lzU25hcHBpbmdNZXRob2RBZHZhbmNlZCAmJiB0aGlzLnNuYXAoKSkge1xyXG4gICAgICBpZiAoIXRoaXMuX3NuYXBlZERpc3BsYXlDb21wb25lbnQgJiYgdGhpcy5fc25hcENvbnRhaW5lclJlZikge1xyXG4gICAgICAgIGNvbnN0IGNvbXAgPSB0aGlzLl9zbmFwQ29udGFpbmVyUmVmLmNyZWF0ZUNvbXBvbmVudCh0aGlzLl9pdGVtQ29tcG9uZW50Q2xhc3MpO1xyXG4gICAgICAgIGNvbXAuaW5zdGFuY2UucmVndWxhciA9IHRydWU7XHJcbiAgICAgICAgdGhpcy5fc25hcGVkRGlzcGxheUNvbXBvbmVudCA9IGNvbXA7XHJcbiAgICAgICAgdGhpcy5fdHJhY2tCb3guc25hcGVkRGlzcGxheUNvbXBvbmVudCA9IHRoaXMuX3NuYXBlZERpc3BsYXlDb21wb25lbnQ7XHJcblxyXG4gICAgICAgIHRoaXMuX3Jlc2l6ZVNuYXBwZWRPYnNlcnZlciA9IG5ldyBSZXNpemVPYnNlcnZlcih0aGlzLl9yZXNpemVTbmFwcGVkQ29tcG9uZW50SGFuZGxlcik7XHJcbiAgICAgICAgdGhpcy5fcmVzaXplU25hcHBlZE9ic2VydmVyLm9ic2VydmUoY29tcC5pbnN0YW5jZS5lbGVtZW50KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuX3RyYWNrQm94Lml0ZW1zID0gZGlzcGxheUl0ZW1zO1xyXG5cclxuICAgIGNvbnN0IF9saXN0Q29udGFpbmVyUmVmID0gdGhpcy5fbGlzdENvbnRhaW5lclJlZjtcclxuXHJcbiAgICBjb25zdCBtYXhMZW5ndGggPSBkaXNwbGF5SXRlbXMubGVuZ3RoLCBjb21wb25lbnRzID0gdGhpcy5fZGlzcGxheUNvbXBvbmVudHM7XHJcblxyXG4gICAgd2hpbGUgKGNvbXBvbmVudHMubGVuZ3RoIDwgbWF4TGVuZ3RoKSB7XHJcbiAgICAgIGlmIChfbGlzdENvbnRhaW5lclJlZikge1xyXG4gICAgICAgIGNvbnN0IGNvbXAgPSBfbGlzdENvbnRhaW5lclJlZi5jcmVhdGVDb21wb25lbnQodGhpcy5faXRlbUNvbXBvbmVudENsYXNzKTtcclxuICAgICAgICBjb21wb25lbnRzLnB1c2goY29tcCk7XHJcblxyXG4gICAgICAgIHRoaXMuX2NvbXBvbmVudHNSZXNpemVPYnNlcnZlci5vYnNlcnZlKGNvbXAuaW5zdGFuY2UuZWxlbWVudCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICB0aGlzLnJlc2V0UmVuZGVyZXJzKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHVwZGF0ZVJlZ3VsYXJSZW5kZXJlcigpIHtcclxuICAgIHRoaXMuX3Jlc2l6ZVNuYXBwZWRDb21wb25lbnRIYW5kbGVyKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHJlc2V0UmVuZGVyZXJzKGl0ZW1SZW5kZXJlcj86IFRlbXBsYXRlUmVmPEhUTUxFbGVtZW50Pikge1xyXG4gICAgY29uc3QgZG9NYXA6IHsgW2lkOiBudW1iZXJdOiBudW1iZXIgfSA9IHt9LCBjb21wb25lbnRzID0gdGhpcy5fZGlzcGxheUNvbXBvbmVudHM7XHJcbiAgICBmb3IgKGxldCBpID0gMCwgbCA9IGNvbXBvbmVudHMubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XHJcbiAgICAgIGNvbnN0IGl0ZW0gPSBjb21wb25lbnRzW2ldO1xyXG4gICAgICBpZiAoaXRlbSkge1xyXG4gICAgICAgIGNvbnN0IGlkID0gaXRlbS5pbnN0YW5jZS5pZDtcclxuICAgICAgICBpdGVtLmluc3RhbmNlLnJlbmRlcmVyID0gaXRlbVJlbmRlcmVyIHx8IHRoaXMuX2l0ZW1SZW5kZXJlcigpO1xyXG4gICAgICAgIGRvTWFwW2lkXSA9IGk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5faXNTbmFwcGluZ01ldGhvZEFkdmFuY2VkICYmIHRoaXMuc25hcCgpICYmIHRoaXMuX3NuYXBlZERpc3BsYXlDb21wb25lbnQgJiYgdGhpcy5fc25hcENvbnRhaW5lclJlZikge1xyXG4gICAgICBjb25zdCBjb21wID0gdGhpcy5fc25hcGVkRGlzcGxheUNvbXBvbmVudDtcclxuICAgICAgY29tcC5pbnN0YW5jZS5yZW5kZXJlciA9IGl0ZW1SZW5kZXJlciB8fCB0aGlzLl9pdGVtUmVuZGVyZXIoKTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLl90cmFja0JveC5zZXREaXNwbGF5T2JqZWN0SW5kZXhNYXBCeUlkKGRvTWFwKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFRyYWNraW5nIGJ5IGlkXHJcbiAgICovXHJcbiAgcHJpdmF0ZSB0cmFja2luZygpIHtcclxuICAgIHRoaXMuX3RyYWNrQm94LnRyYWNrKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHJlc2V0Qm91bmRzU2l6ZShpc1ZlcnRpY2FsOiBib29sZWFuLCB0b3RhbFNpemU6IG51bWJlcikge1xyXG4gICAgY29uc3QgbCA9IHRoaXMuX2xpc3QoKTtcclxuICAgIGlmIChsKSB7XHJcbiAgICAgIGwubmF0aXZlRWxlbWVudC5zdHlsZVtpc1ZlcnRpY2FsID8gSEVJR0hUX1BST1BfTkFNRSA6IFdJRFRIX1BST1BfTkFNRV0gPSBgJHt0b3RhbFNpemV9JHtQWH1gO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmV0dXJucyB0aGUgYm91bmRzIG9mIGFuIGVsZW1lbnQgd2l0aCBhIGdpdmVuIGlkXHJcbiAgICovXHJcbiAgZ2V0SXRlbUJvdW5kcyhpZDogSWQpOiBJU2l6ZSB8IHVuZGVmaW5lZCB7XHJcbiAgICByZXR1cm4gdGhpcy5fdHJhY2tCb3guZ2V0SXRlbUJvdW5kcyhpZCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBUaGUgbWV0aG9kIHNjcm9sbHMgdGhlIGxpc3QgdG8gdGhlIGVsZW1lbnQgd2l0aCB0aGUgZ2l2ZW4gaWQgYW5kIHJldHVybnMgdGhlIHZhbHVlIG9mIHRoZSBzY3JvbGxlZCBhcmVhLlxyXG4gICAqIEJlaGF2aW9yIGFjY2VwdHMgdGhlIHZhbHVlcyDigIvigItcImF1dG9cIiwgXCJpbnN0YW50XCIgYW5kIFwic21vb3RoXCIuXHJcbiAgICovXHJcbiAgc2Nyb2xsVG8oaWQ6IElkLCBiZWhhdmlvcjogU2Nyb2xsQmVoYXZpb3IgPSBCRUhBVklPUl9BVVRPKSB7XHJcbiAgICB0aGlzLnNjcm9sbFRvRXhlY3V0b3IoaWQsIGJlaGF2aW9yKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgX3Njcm9sbFRvUmVwZWF0RXhlY3V0aW9uVGltZW91dDogbnVtYmVyIHwgdW5kZWZpbmVkO1xyXG5cclxuICBwcml2YXRlIGNsZWFyU2Nyb2xsVG9SZXBlYXRFeGVjdXRpb25UaW1lb3V0KCkge1xyXG4gICAgY2xlYXJUaW1lb3V0KHRoaXMuX3Njcm9sbFRvUmVwZWF0RXhlY3V0aW9uVGltZW91dCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHNjcm9sbFRvRXhlY3V0b3IoaWQ6IElkLCBiZWhhdmlvcjogU2Nyb2xsQmVoYXZpb3IsIGl0ZXJhdGlvbjogbnVtYmVyID0gMCwgaXNMYXN0SXRlcmF0aW9uID0gZmFsc2UpIHtcclxuICAgIGNvbnN0IGl0ZW1zID0gdGhpcy5pdGVtcygpO1xyXG4gICAgaWYgKCFpdGVtcyB8fCAhaXRlbXMubGVuZ3RoKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBkeW5hbWljU2l6ZSA9IHRoaXMuZHluYW1pY1NpemUoKSwgY29udGFpbmVyID0gdGhpcy5fY29udGFpbmVyKCksIGl0ZW1TaXplID0gdGhpcy5pdGVtU2l6ZSgpO1xyXG4gICAgaWYgKGNvbnRhaW5lcikge1xyXG4gICAgICB0aGlzLmNsZWFyU2Nyb2xsVG9SZXBlYXRFeGVjdXRpb25UaW1lb3V0KCk7XHJcblxyXG4gICAgICBpZiAoZHluYW1pY1NpemUpIHtcclxuICAgICAgICBpZiAoY29udGFpbmVyKSB7XHJcbiAgICAgICAgICBjb250YWluZXIubmF0aXZlRWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKFNDUk9MTCwgdGhpcy5fb25TY3JvbGxIYW5kbGVyKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGNvbnN0IHsgd2lkdGgsIGhlaWdodCB9ID0gdGhpcy5fYm91bmRzKCkgfHwgeyB3aWR0aDogREVGQVVMVF9MSVNUX1NJWkUsIGhlaWdodDogREVGQVVMVF9MSVNUX1NJWkUgfSxcclxuICAgICAgICAgIHN0aWNreU1hcCA9IHRoaXMuc3RpY2t5TWFwKCksIGl0ZW1zID0gdGhpcy5pdGVtcygpLCBpc1ZlcnRpY2FsID0gdGhpcy5faXNWZXJ0aWNhbCwgZGVsdGEgPSB0aGlzLl90cmFja0JveC5kZWx0YSxcclxuICAgICAgICAgIG9wdHM6IElHZXRJdGVtUG9zaXRpb25PcHRpb25zPElWaXJ0dWFsTGlzdEl0ZW0sIElWaXJ0dWFsTGlzdENvbGxlY3Rpb24+ID0ge1xyXG4gICAgICAgICAgICBib3VuZHM6IHsgd2lkdGgsIGhlaWdodCB9LCBjb2xsZWN0aW9uOiBpdGVtcywgZHluYW1pY1NpemUsIGlzVmVydGljYWw6IHRoaXMuX2lzVmVydGljYWwsIGl0ZW1TaXplLFxyXG4gICAgICAgICAgICBidWZmZXJTaXplOiB0aGlzLmJ1ZmZlclNpemUoKSwgbWF4QnVmZmVyU2l6ZTogdGhpcy5tYXhCdWZmZXJTaXplKCksXHJcbiAgICAgICAgICAgIHNjcm9sbFNpemU6IChpc1ZlcnRpY2FsID8gY29udGFpbmVyLm5hdGl2ZUVsZW1lbnQuc2Nyb2xsVG9wIDogY29udGFpbmVyLm5hdGl2ZUVsZW1lbnQuc2Nyb2xsTGVmdCkgKyBkZWx0YSxcclxuICAgICAgICAgICAgc25hcDogdGhpcy5zbmFwKCksIGZyb21JdGVtSWQ6IGlkLCBlbmFibGVkQnVmZmVyT3B0aW1pemF0aW9uOiB0aGlzLmVuYWJsZWRCdWZmZXJPcHRpbWl6YXRpb24oKSxcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBzY3JvbGxTaXplID0gdGhpcy5fdHJhY2tCb3guZ2V0SXRlbVBvc2l0aW9uKGlkLCBzdGlja3lNYXAsIG9wdHMpLFxyXG4gICAgICAgICAgcGFyYW1zOiBTY3JvbGxUb09wdGlvbnMgPSB7IFtpc1ZlcnRpY2FsID8gVE9QX1BST1BfTkFNRSA6IExFRlRfUFJPUF9OQU1FXTogc2Nyb2xsU2l6ZSwgYmVoYXZpb3IgfTtcclxuXHJcbiAgICAgICAgaWYgKHNjcm9sbFNpemUgPT09IC0xKSB7XHJcbiAgICAgICAgICBjb250YWluZXIubmF0aXZlRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKFNDUk9MTCwgdGhpcy5fb25TY3JvbGxIYW5kbGVyKTtcclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoaXMuX3RyYWNrQm94LmNsZWFyRGVsdGEoKTtcclxuXHJcbiAgICAgICAgaWYgKGNvbnRhaW5lcikge1xyXG4gICAgICAgICAgY29uc3QgeyBkaXNwbGF5SXRlbXMsIHRvdGFsU2l6ZSB9ID0gdGhpcy5fdHJhY2tCb3gudXBkYXRlQ29sbGVjdGlvbihpdGVtcywgc3RpY2t5TWFwLCB7XHJcbiAgICAgICAgICAgIC4uLm9wdHMsIHNjcm9sbFNpemUsIGZyb21JdGVtSWQ6IGlzTGFzdEl0ZXJhdGlvbiA/IHVuZGVmaW5lZCA6IGlkLFxyXG4gICAgICAgICAgfSksIGRlbHRhID0gdGhpcy5fdHJhY2tCb3guZGVsdGE7XHJcblxyXG4gICAgICAgICAgdGhpcy5fdHJhY2tCb3guY2xlYXJEZWx0YSgpO1xyXG5cclxuICAgICAgICAgIGxldCBhY3R1YWxTY3JvbGxTaXplID0gc2Nyb2xsU2l6ZSArIGRlbHRhO1xyXG5cclxuICAgICAgICAgIHRoaXMucmVzZXRCb3VuZHNTaXplKGlzVmVydGljYWwsIHRvdGFsU2l6ZSk7XHJcblxyXG4gICAgICAgICAgdGhpcy5jcmVhdGVEaXNwbGF5Q29tcG9uZW50c0lmTmVlZChkaXNwbGF5SXRlbXMpO1xyXG5cclxuICAgICAgICAgIHRoaXMudHJhY2tpbmcoKTtcclxuXHJcbiAgICAgICAgICBjb25zdCBfc2Nyb2xsU2l6ZSA9IHRoaXMuX3RyYWNrQm94LmdldEl0ZW1Qb3NpdGlvbihpZCwgc3RpY2t5TWFwLCB7IC4uLm9wdHMsIHNjcm9sbFNpemU6IGFjdHVhbFNjcm9sbFNpemUsIGZyb21JdGVtSWQ6IGlkIH0pO1xyXG5cclxuICAgICAgICAgIGlmIChfc2Nyb2xsU2l6ZSA9PT0gLTEpIHtcclxuICAgICAgICAgICAgY29udGFpbmVyLm5hdGl2ZUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihTQ1JPTEwsIHRoaXMuX29uU2Nyb2xsSGFuZGxlcik7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICBjb25zdCBub3RDaGFuZ2VkID0gYWN0dWFsU2Nyb2xsU2l6ZSA9PT0gX3Njcm9sbFNpemVcclxuXHJcbiAgICAgICAgICBpZiAoIW5vdENoYW5nZWQgfHwgaXRlcmF0aW9uIDwgTUFYX1NDUk9MTF9UT19JVEVSQVRJT05TKSB7XHJcbiAgICAgICAgICAgIHRoaXMuY2xlYXJTY3JvbGxUb1JlcGVhdEV4ZWN1dGlvblRpbWVvdXQoKTtcclxuICAgICAgICAgICAgdGhpcy5fc2Nyb2xsVG9SZXBlYXRFeGVjdXRpb25UaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgICAgICAgICAgdGhpcy5zY3JvbGxUb0V4ZWN1dG9yKGlkLCBCRUhBVklPUl9JTlNUQU5ULCBpdGVyYXRpb24gKyAxLCBub3RDaGFuZ2VkKTtcclxuICAgICAgICAgICAgfSkgYXMgdW5rbm93biBhcyBudW1iZXI7XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICB0aGlzLl9zY3JvbGxTaXplLnNldChhY3R1YWxTY3JvbGxTaXplKTtcclxuXHJcbiAgICAgICAgICAgIGNvbnRhaW5lci5uYXRpdmVFbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoU0NST0xMLCB0aGlzLl9vblNjcm9sbEhhbmRsZXIpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgY29udGFpbmVyLm5hdGl2ZUVsZW1lbnQuc2Nyb2xsVG8ocGFyYW1zKTtcclxuXHJcbiAgICAgICAgdGhpcy5fc2Nyb2xsU2l6ZS5zZXQoc2Nyb2xsU2l6ZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgY29uc3QgaW5kZXggPSBpdGVtcy5maW5kSW5kZXgoaXRlbSA9PiBpdGVtLmlkID09PSBpZCk7XHJcbiAgICAgICAgaWYgKGluZGV4ID4gLTEpIHtcclxuICAgICAgICAgIGNvbnN0IHNjcm9sbFNpemUgPSBpbmRleCAqIHRoaXMuaXRlbVNpemUoKTtcclxuICAgICAgICAgIGNvbnN0IHBhcmFtczogU2Nyb2xsVG9PcHRpb25zID0geyBbdGhpcy5faXNWZXJ0aWNhbCA/IFRPUF9QUk9QX05BTUUgOiBMRUZUX1BST1BfTkFNRV06IHNjcm9sbFNpemUsIGJlaGF2aW9yIH07XHJcbiAgICAgICAgICBjb250YWluZXIubmF0aXZlRWxlbWVudC5zY3JvbGxUbyhwYXJhbXMpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU2Nyb2xscyB0aGUgc2Nyb2xsIGFyZWEgdG8gdGhlIGRlc2lyZWQgZWxlbWVudCB3aXRoIHRoZSBzcGVjaWZpZWQgSUQuXHJcbiAgICovXHJcbiAgc2Nyb2xsVG9FbmQoYmVoYXZpb3I6IFNjcm9sbEJlaGF2aW9yID0gQkVIQVZJT1JfSU5TVEFOVCkge1xyXG4gICAgY29uc3QgaXRlbXMgPSB0aGlzLml0ZW1zKCksIGxhdEl0ZW0gPSBpdGVtc1tpdGVtcy5sZW5ndGggPiAwID8gaXRlbXMubGVuZ3RoIC0gMSA6IDBdO1xyXG4gICAgdGhpcy5zY3JvbGxUbyhsYXRJdGVtLmlkLCBiZWhhdmlvcik7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIF9vbkNvbnRhaW5lclNjcm9sbEhhbmRsZXIgPSAoZTogRXZlbnQpID0+IHtcclxuICAgIGNvbnN0IGNvbnRhaW5lckVsID0gdGhpcy5fY29udGFpbmVyKCk7XHJcbiAgICBpZiAoY29udGFpbmVyRWwpIHtcclxuICAgICAgY29uc3Qgc2Nyb2xsU2l6ZSA9ICh0aGlzLl9pc1ZlcnRpY2FsID8gY29udGFpbmVyRWwubmF0aXZlRWxlbWVudC5zY3JvbGxUb3AgOiBjb250YWluZXJFbC5uYXRpdmVFbGVtZW50LnNjcm9sbExlZnQpO1xyXG4gICAgICB0aGlzLl90cmFja0JveC5kZWx0YURpcmVjdGlvbiA9IHRoaXMuX3Njcm9sbFNpemUoKSA+IHNjcm9sbFNpemUgPyAtMSA6IHRoaXMuX3Njcm9sbFNpemUoKSA8IHNjcm9sbFNpemUgPyAxIDogMDtcclxuXHJcbiAgICAgIGNvbnN0IGV2ZW50ID0gbmV3IFNjcm9sbEV2ZW50KHtcclxuICAgICAgICBkaXJlY3Rpb246IHRoaXMuX3RyYWNrQm94LnNjcm9sbERpcmVjdGlvbiwgY29udGFpbmVyOiBjb250YWluZXJFbC5uYXRpdmVFbGVtZW50LFxyXG4gICAgICAgIGxpc3Q6IHRoaXMuX2xpc3QoKSEubmF0aXZlRWxlbWVudCwgZGVsdGE6IHRoaXMuX3RyYWNrQm94LmRlbHRhLFxyXG4gICAgICAgIHNjcm9sbERlbHRhOiB0aGlzLl90cmFja0JveC5zY3JvbGxEZWx0YSwgaXNWZXJ0aWNhbDogdGhpcy5faXNWZXJ0aWNhbCxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICB0aGlzLm9uU2Nyb2xsLmVtaXQoZXZlbnQpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBfb25Db250YWluZXJTY3JvbGxFbmRIYW5kbGVyID0gKGU6IEV2ZW50KSA9PiB7XHJcbiAgICBjb25zdCBjb250YWluZXJFbCA9IHRoaXMuX2NvbnRhaW5lcigpO1xyXG4gICAgaWYgKGNvbnRhaW5lckVsKSB7XHJcbiAgICAgIGNvbnN0IHNjcm9sbFNpemUgPSAodGhpcy5faXNWZXJ0aWNhbCA/IGNvbnRhaW5lckVsLm5hdGl2ZUVsZW1lbnQuc2Nyb2xsVG9wIDogY29udGFpbmVyRWwubmF0aXZlRWxlbWVudC5zY3JvbGxMZWZ0KTtcclxuICAgICAgdGhpcy5fdHJhY2tCb3guZGVsdGFEaXJlY3Rpb24gPSB0aGlzLl9zY3JvbGxTaXplKCkgPiBzY3JvbGxTaXplID8gLTEgOiAwO1xyXG5cclxuICAgICAgY29uc3QgZXZlbnQgPSBuZXcgU2Nyb2xsRXZlbnQoe1xyXG4gICAgICAgIGRpcmVjdGlvbjogdGhpcy5fdHJhY2tCb3guc2Nyb2xsRGlyZWN0aW9uLCBjb250YWluZXI6IGNvbnRhaW5lckVsLm5hdGl2ZUVsZW1lbnQsXHJcbiAgICAgICAgbGlzdDogdGhpcy5fbGlzdCgpIS5uYXRpdmVFbGVtZW50LCBkZWx0YTogdGhpcy5fdHJhY2tCb3guZGVsdGEsXHJcbiAgICAgICAgc2Nyb2xsRGVsdGE6IHRoaXMuX3RyYWNrQm94LnNjcm9sbERlbHRhLCBpc1ZlcnRpY2FsOiB0aGlzLl9pc1ZlcnRpY2FsLFxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIHRoaXMub25TY3JvbGxFbmQuZW1pdChldmVudCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKiogQGludGVybmFsICovXHJcbiAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xyXG4gICAgdGhpcy5hZnRlclZpZXdJbml0KCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGFmdGVyVmlld0luaXQoKSB7XHJcbiAgICBjb25zdCBjb250YWluZXJFbCA9IHRoaXMuX2NvbnRhaW5lcigpO1xyXG4gICAgaWYgKGNvbnRhaW5lckVsKSB7XHJcbiAgICAgIC8vIGZvciBkaXJlY3Rpb24gY2FsY3VsYXRpb25cclxuICAgICAgY29udGFpbmVyRWwubmF0aXZlRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKFNDUk9MTCwgdGhpcy5fb25Db250YWluZXJTY3JvbGxIYW5kbGVyKTtcclxuICAgICAgY29udGFpbmVyRWwubmF0aXZlRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKFNDUk9MTF9FTkQsIHRoaXMuX29uQ29udGFpbmVyU2Nyb2xsRW5kSGFuZGxlcik7XHJcblxyXG4gICAgICBjb250YWluZXJFbC5uYXRpdmVFbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoU0NST0xMLCB0aGlzLl9vblNjcm9sbEhhbmRsZXIpO1xyXG5cclxuICAgICAgdGhpcy5fcmVzaXplT2JzZXJ2ZXIgPSBuZXcgUmVzaXplT2JzZXJ2ZXIodGhpcy5fb25SZXNpemVIYW5kbGVyKTtcclxuICAgICAgdGhpcy5fcmVzaXplT2JzZXJ2ZXIub2JzZXJ2ZShjb250YWluZXJFbC5uYXRpdmVFbGVtZW50KTtcclxuXHJcbiAgICAgIHRoaXMuX29uUmVzaXplSGFuZGxlcigpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqIEBpbnRlcm5hbCAqL1xyXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xyXG4gICAgdGhpcy5kaXNwb3NlKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGRpc3Bvc2UoKSB7XHJcbiAgICB0aGlzLmNsZWFyU2Nyb2xsVG9SZXBlYXRFeGVjdXRpb25UaW1lb3V0KCk7XHJcblxyXG4gICAgaWYgKHRoaXMuX3RyYWNrQm94KSB7XHJcbiAgICAgIHRoaXMuX3RyYWNrQm94LmRpc3Bvc2UoKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5fY29tcG9uZW50c1Jlc2l6ZU9ic2VydmVyKSB7XHJcbiAgICAgIHRoaXMuX2NvbXBvbmVudHNSZXNpemVPYnNlcnZlci5kaXNjb25uZWN0KCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMuX3Jlc2l6ZVNuYXBwZWRPYnNlcnZlcikge1xyXG4gICAgICB0aGlzLl9yZXNpemVTbmFwcGVkT2JzZXJ2ZXIuZGlzY29ubmVjdCgpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLl9yZXNpemVPYnNlcnZlcikge1xyXG4gICAgICB0aGlzLl9yZXNpemVPYnNlcnZlci5kaXNjb25uZWN0KCk7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgY29udGFpbmVyRWwgPSB0aGlzLl9jb250YWluZXIoKTtcclxuICAgIGlmIChjb250YWluZXJFbCkge1xyXG4gICAgICBjb250YWluZXJFbC5uYXRpdmVFbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoU0NST0xMLCB0aGlzLl9vblNjcm9sbEhhbmRsZXIpO1xyXG4gICAgICBjb250YWluZXJFbC5uYXRpdmVFbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoU0NST0xMLCB0aGlzLl9vbkNvbnRhaW5lclNjcm9sbEhhbmRsZXIpO1xyXG4gICAgICBjb250YWluZXJFbC5uYXRpdmVFbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoU0NST0xMX0VORCwgdGhpcy5fb25Db250YWluZXJTY3JvbGxFbmRIYW5kbGVyKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5fc25hcGVkRGlzcGxheUNvbXBvbmVudCkge1xyXG4gICAgICB0aGlzLl9zbmFwZWREaXNwbGF5Q29tcG9uZW50LmRlc3Ryb3koKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5fZGlzcGxheUNvbXBvbmVudHMpIHtcclxuICAgICAgd2hpbGUgKHRoaXMuX2Rpc3BsYXlDb21wb25lbnRzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICBjb25zdCBjb21wID0gdGhpcy5fZGlzcGxheUNvbXBvbmVudHMucG9wKCk7XHJcbiAgICAgICAgY29tcD8uZGVzdHJveSgpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcbiIsIkBpZiAoc25hcCgpKSB7XHJcbjxkaXYgI3NuYXBwZWQgcGFydD1cInNuYXBwZWQtaXRlbVwiIGNsYXNzPVwibmd2bF9fbGlzdC1zbmFwcGVyXCI+XHJcbiAgPG5nLWNvbnRhaW5lciAjc25hcFJlbmRlcmVyQ29udGFpbmVyPjwvbmctY29udGFpbmVyPlxyXG48L2Rpdj5cclxufVxyXG48ZGl2ICNjb250YWluZXIgcGFydD1cInNjcm9sbGVyXCIgY2xhc3M9XCJuZ3ZsX19zY3JvbGxlclwiPlxyXG4gIDx1bCAjbGlzdCBwYXJ0PVwibGlzdFwiIGNsYXNzPVwibmd2bF9fbGlzdFwiPlxyXG4gICAgPG5nLWNvbnRhaW5lciAjcmVuZGVyZXJzQ29udGFpbmVyPjwvbmctY29udGFpbmVyPlxyXG4gIDwvdWw+XHJcbjwvZGl2PiJdfQ==