@ceriousdevtech/ngx-cerious-scroll 1.0.0 → 1.0.2

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.
@@ -35,7 +35,13 @@ export class CeriousScrollDirective {
35
35
  this.ceriousScrollReady = new EventEmitter();
36
36
  this.hostRef = null;
37
37
  this.viewportSub = null;
38
+ this.scheduledRenderFrame = null;
38
39
  this.viewByContainer = new Map();
40
+ // Pool of views detached because their container left the viewport. Reusing
41
+ // them on subsequent renders avoids destroying + recreating the entire row
42
+ // component tree on fast scrolls (where the engine's element pool wipes
43
+ // textContent on reused containers, so view rootNodes get orphaned).
44
+ this.freeViews = [];
39
45
  }
40
46
  ngAfterViewInit() {
41
47
  this.ensureInitialized();
@@ -45,10 +51,33 @@ export class CeriousScrollDirective {
45
51
  return;
46
52
  if (changes['ceriousScrollItems'] || changes['ceriousScrollTotalElements']) {
47
53
  const total = coerceTotalElements(this.ceriousScrollTotalElements, this.ceriousScrollItems?.length ?? null);
48
- this.hostRef.scroller.totalElements = total;
49
- this.hostRef.scroller.clearAllCaches();
50
- if (this.ceriousScrollAutoRender)
54
+ const countChanged = this.hostRef.scroller.totalElements !== total;
55
+ if (countChanged) {
56
+ // The dataset size changed: the ViewportRenderer stores its own copy of
57
+ // totalElements (set by value at construction) so patching the engine's
58
+ // public property alone leaves the renderer's internal bound stale. The
59
+ // renderer would then use the old count for its viewport-fill loop and
60
+ // bottom-boundary scan, producing phantom renders at out-of-bounds
61
+ // indices (undefined items → 0-height rows → the fill loop never
62
+ // satisfies its height condition → hundreds of renderer callbacks).
63
+ // Recreating the engine gives both the engine and the renderer a fresh,
64
+ // consistent count. ensureInitialized() schedules the first render via
65
+ // queueMicrotask, which runs after the current CD cycle completes.
66
+ this.recreate();
67
+ }
68
+ else if (this.ceriousScrollAutoRender) {
69
+ // Same count, new data reference (e.g. an immutable edit or a sort that
70
+ // happens to keep the same length). The engine reuses the DOM element it
71
+ // already rendered for each overlapping index without re-invoking the
72
+ // renderer, so update the content of every currently-visible row IN
73
+ // PLACE before calling render(). This preserves each row's embedded
74
+ // view (so a focused textbox keeps focus/caret) and does NOT discard
75
+ // cached heights. If a row's height actually changes the engine's
76
+ // ResizeObserver keeps the cache correct on its own; for a wholesale
77
+ // height change across all rows, call recalculate() instead.
78
+ this.refreshRenderedContent();
51
79
  this.render();
80
+ }
52
81
  }
53
82
  if (changes['ceriousScrollOptions'] && !changes['ceriousScrollOptions'].firstChange) {
54
83
  // Options are consumed primarily at construction time.
@@ -56,6 +85,10 @@ export class CeriousScrollDirective {
56
85
  }
57
86
  }
58
87
  ngOnDestroy() {
88
+ if (this.scheduledRenderFrame != null) {
89
+ cancelAnimationFrame(this.scheduledRenderFrame);
90
+ this.scheduledRenderFrame = null;
91
+ }
59
92
  this.viewportSub?.unsubscribe();
60
93
  this.viewportSub = null;
61
94
  this.destroyAllViews();
@@ -72,16 +105,122 @@ export class CeriousScrollDirective {
72
105
  const hostContainer = this.host.nativeElement;
73
106
  const height = hostContainer.clientHeight || hostContainer.offsetHeight;
74
107
  const contentContainer = this.hostRef.contentElement;
108
+ // Track whether the engine asked us to bind any row this pass. Pure scroll
109
+ // frames where the visible row set doesn't change still drive render() via
110
+ // the rAF coalescer — there's no point in walking the prune map or
111
+ // emitting the viewport range when nothing was touched.
112
+ let rendererInvocations = 0;
75
113
  const renderer = (index, elementContainer) => {
76
- // Rendering must create Angular views inside the Angular zone.
77
- this.ngZone.run(() => {
78
- this.renderTemplateIntoContainer(template, index, elementContainer);
79
- });
114
+ rendererInvocations++;
115
+ // Render each row's embedded view with LOCAL change detection
116
+ // (`view.detectChanges()` inside `renderTemplateIntoContainer`) so the
117
+ // engine can measure its height during this pass. Do NOT wrap each row in
118
+ // its own `ngZone.run` — that fires a full `ApplicationRef` tick *per row*
119
+ // (O(newRows × visibleRows) work, janky drags). The single coalesced tick
120
+ // for the whole pass is handled by the caller (`scheduleRender`).
121
+ this.renderTemplateIntoContainer(template, index, elementContainer);
80
122
  };
81
123
  const range = this.hostRef.scroller.renderViewport(height, contentContainer, renderer);
82
- this.ngZone.run(() => this.ceriousScrollMeasuredViewport.emit(range));
124
+ if (rendererInvocations === 0) {
125
+ // Viewport didn't change — skip the prune walk and the (potentially
126
+ // zone-entering) emit.
127
+ return range;
128
+ }
129
+ // Destroy views whose container the engine no longer renders. Without this,
130
+ // every container the engine recycles into its element pool leaves its
131
+ // embedded view attached to ApplicationRef forever — so the attached-view
132
+ // list (and every O(n) `detachView`) grows without bound and scrolling gets
133
+ // progressively slower. Mirrors the React/Vue wrappers, which drop rows that
134
+ // fall out of `getRenderedIndices()`.
135
+ this.pruneDetachedViews();
136
+ // Only re-enter the zone (a global tick) if someone is actually listening.
137
+ if (this.ceriousScrollMeasuredViewport.observed) {
138
+ this.ngZone.run(() => this.ceriousScrollMeasuredViewport.emit(range));
139
+ }
83
140
  return range;
84
141
  }
142
+ /** Tear down embedded views whose container is no longer part of the viewport. */
143
+ pruneDetachedViews() {
144
+ if (!this.hostRef || this.viewByContainer.size === 0)
145
+ return;
146
+ const scroller = this.hostRef.scroller;
147
+ const active = new Set();
148
+ for (const index of scroller.getRenderedIndices()) {
149
+ const el = scroller.getRenderedElement(index);
150
+ if (el)
151
+ active.add(el);
152
+ }
153
+ for (const [container, view] of this.viewByContainer) {
154
+ if (!active.has(container)) {
155
+ // Detach DOM but keep the view alive in the pool for future reuse.
156
+ // Destroying + recreating views per scroll step dominates frame time.
157
+ for (const node of view.rootNodes) {
158
+ if (node.parentNode)
159
+ node.parentNode.removeChild(node);
160
+ }
161
+ this.viewByContainer.delete(container);
162
+ this.freeViews.push(view);
163
+ }
164
+ }
165
+ }
166
+ /** Auto-render coalesced to at most once per animation frame. */
167
+ scheduleRender() {
168
+ if (this.scheduledRenderFrame != null)
169
+ return;
170
+ this.scheduledRenderFrame = requestAnimationFrame(() => {
171
+ this.scheduledRenderFrame = null;
172
+ // Run render() OUTSIDE Angular's zone. A full ApplicationRef.tick() on
173
+ // every scroll frame is the primary FPS bottleneck: even when no rows
174
+ // change (pure translation), ngZone.run() causes Angular to walk the
175
+ // entire component tree. Instead we call view.detectChanges() locally
176
+ // inside renderTemplateIntoContainer for each affected row. Zone entry is
177
+ // only needed when creating a brand-new embedded view (to zone-patch its
178
+ // event listeners) — recycled and pooled views were already created inside
179
+ // zone and their listeners remain zone-aware.
180
+ this.render();
181
+ });
182
+ }
183
+ /**
184
+ * Discard all cached row heights and re-measure the viewport.
185
+ *
186
+ * Call this only when the heights of rows you've *already rendered* may have
187
+ * changed without their indices changing — e.g. a global font/density change,
188
+ * or swapping every row to a different layout. This forces a synchronous
189
+ * re-measure (one `offsetHeight` read per visible row), so do NOT call it on
190
+ * routine edits: a single cell edit keeps its row's size, and the engine's
191
+ * ResizeObserver picks up any incidental resize on its own.
192
+ */
193
+ recalculate() {
194
+ if (!this.hostRef)
195
+ return null;
196
+ // Discard the cached heights, then re-render. The engine re-measures and
197
+ // re-caches the rendered rows during the pass and refreshes the scroll
198
+ // percentage, so an in-place height change (e.g. expand/collapse) is
199
+ // reflected in the total content height and scrollbar immediately.
200
+ this.hostRef.scroller.clearAllCaches();
201
+ return this.render();
202
+ }
203
+ /** Jump directly to an element index, then render. */
204
+ jumpToElement(index) {
205
+ if (!this.hostRef)
206
+ return null;
207
+ this.hostRef.scroller.jumpToElement(index);
208
+ return this.render();
209
+ }
210
+ /** Scroll to a percentage (0..100), then render. */
211
+ scrollToPercentage(percentage) {
212
+ if (!this.hostRef)
213
+ return null;
214
+ this.hostRef.scroller.handleScrollPercentage(percentage);
215
+ return this.render();
216
+ }
217
+ /** Reset to the top, then render. */
218
+ reset() {
219
+ if (!this.hostRef)
220
+ return null;
221
+ this.hostRef.scroller.reset();
222
+ return this.render();
223
+ }
85
224
  recreate() {
86
225
  this.viewportSub?.unsubscribe();
87
226
  this.viewportSub = null;
@@ -96,11 +235,16 @@ export class CeriousScrollDirective {
96
235
  const container = this.host.nativeElement;
97
236
  const total = coerceTotalElements(this.ceriousScrollTotalElements, this.ceriousScrollItems?.length ?? null);
98
237
  this.hostRef = this.cerious.createHost(container, total, this.ceriousScrollOptions, this.ngZone, () => {
238
+ // Coalesce scroll-driven renders to one per frame (the native scrollbar
239
+ // can fire many scroll events between paints).
99
240
  if (this.ceriousScrollAutoRender)
100
- this.render();
241
+ this.scheduleRender();
101
242
  });
102
243
  this.viewportSub = this.hostRef.viewportChanges$.subscribe((detail) => {
103
- this.ngZone.run(() => this.ceriousScrollViewportChange.emit(detail));
244
+ // Skip the global tick when nobody is bound to the output.
245
+ if (this.ceriousScrollViewportChange.observed) {
246
+ this.ngZone.run(() => this.ceriousScrollViewportChange.emit(detail));
247
+ }
104
248
  });
105
249
  this.ceriousScrollReady.emit(this.hostRef.scroller);
106
250
  if (this.ceriousScrollAutoRender) {
@@ -119,27 +263,96 @@ export class CeriousScrollDirective {
119
263
  renderTemplateIntoContainer(template, index, elementContainer) {
120
264
  const previous = this.viewByContainer.get(elementContainer);
121
265
  if (previous) {
122
- this.appRef.detachView(previous);
123
- previous.destroy();
124
- this.viewByContainer.delete(elementContainer);
266
+ // Recycle: update the bound context and run local CD instead of
267
+ // destroying the embedded view and rebuilding the entire row tree.
268
+ const item = this.getItemForIndex(index);
269
+ previous.context.$implicit = item;
270
+ previous.context.item = item;
271
+ previous.context.index = index;
272
+ // The core engine wipes elementContainer.textContent when reusing it from
273
+ // its pool, orphaning the view's root nodes. Re-append them defensively.
274
+ if (previous.rootNodes.length && previous.rootNodes[0].parentNode !== elementContainer) {
275
+ for (const node of previous.rootNodes) {
276
+ elementContainer.appendChild(node);
277
+ }
278
+ }
279
+ previous.detectChanges();
280
+ return;
281
+ }
282
+ // Try to reuse a pooled view from a container that scrolled out of viewport.
283
+ const pooled = this.freeViews.pop();
284
+ if (pooled) {
285
+ const item = this.getItemForIndex(index);
286
+ pooled.context.$implicit = item;
287
+ pooled.context.item = item;
288
+ pooled.context.index = index;
289
+ elementContainer.textContent = '';
290
+ for (const node of pooled.rootNodes) {
291
+ elementContainer.appendChild(node);
292
+ }
293
+ pooled.detectChanges();
294
+ this.viewByContainer.set(elementContainer, pooled);
295
+ return;
125
296
  }
126
- // Clear prior DOM (CeriousScroll may recycle containers).
297
+ // No prior view for this container: create one.
298
+ // Enter the Angular zone so the new view's template event listeners
299
+ // ((click), (input), etc.) are zone-patched. This path runs at most
300
+ // once per visible row (after that, the view is recycled from the pool).
127
301
  elementContainer.textContent = '';
128
302
  const item = this.getItemForIndex(index);
129
- const view = template.createEmbeddedView({ $implicit: item, item, index });
130
- this.appRef.attachView(view);
131
- view.detectChanges();
303
+ const view = this.ngZone.run(() => {
304
+ const v = template.createEmbeddedView({ $implicit: item, item, index });
305
+ this.appRef.attachView(v);
306
+ v.detectChanges();
307
+ return v;
308
+ });
132
309
  for (const node of view.rootNodes) {
133
310
  elementContainer.appendChild(node);
134
311
  }
135
312
  this.viewByContainer.set(elementContainer, view);
136
313
  }
314
+ /**
315
+ * Update the bound item/index on every currently-rendered row's embedded view
316
+ * and run change detection, without recreating the views. Used when the data
317
+ * reference changes but the visible indices (and their heights) do not, so row
318
+ * state (focus, selection, open dropdowns) survives the update.
319
+ */
320
+ /**
321
+ * Re-bind each currently rendered row's context (from the current items/getter)
322
+ * and run change detection on its embedded view. Use this after mutating row
323
+ * state in place (e.g. selection flags) or column-level state read by the row
324
+ * template, when row identity and visible indices have not changed. Cheap
325
+ * relative to `render()` — does not invoke the engine's measurement pass.
326
+ */
327
+ refreshRenderedContent() {
328
+ if (!this.hostRef)
329
+ return;
330
+ const scroller = this.hostRef.scroller;
331
+ for (const index of scroller.getRenderedIndices()) {
332
+ const container = scroller.getRenderedElement(index);
333
+ if (!container)
334
+ continue;
335
+ const view = this.viewByContainer.get(container);
336
+ if (!view)
337
+ continue;
338
+ const item = this.getItemForIndex(index);
339
+ view.context.$implicit = item;
340
+ view.context.item = item;
341
+ view.context.index = index;
342
+ view.detectChanges();
343
+ }
344
+ }
137
345
  destroyAllViews() {
138
346
  for (const view of this.viewByContainer.values()) {
139
347
  this.appRef.detachView(view);
140
348
  view.destroy();
141
349
  }
142
350
  this.viewByContainer.clear();
351
+ for (const view of this.freeViews) {
352
+ this.appRef.detachView(view);
353
+ view.destroy();
354
+ }
355
+ this.freeViews.length = 0;
143
356
  }
144
357
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CeriousScrollDirective, deps: [{ token: i0.ElementRef }, { token: i0.ApplicationRef }, { token: i0.NgZone }, { token: i1.CeriousScrollService }], target: i0.ɵɵFactoryTarget.Directive }); }
145
358
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: CeriousScrollDirective, isStandalone: true, selector: "[ceriousScroll]", inputs: { ceriousScrollTotalElements: "ceriousScrollTotalElements", ceriousScrollItems: "ceriousScrollItems", ceriousScrollGetItem: "ceriousScrollGetItem", ceriousScrollItemTemplate: "ceriousScrollItemTemplate", ceriousScrollOptions: "ceriousScrollOptions", ceriousScrollAutoRender: "ceriousScrollAutoRender" }, outputs: { ceriousScrollViewportChange: "ceriousScrollViewportChange", ceriousScrollMeasuredViewport: "ceriousScrollMeasuredViewport", ceriousScrollReady: "ceriousScrollReady" }, usesOnChanges: true, ngImport: i0 }); }
@@ -169,4 +382,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
169
382
  }], ceriousScrollReady: [{
170
383
  type: Output
171
384
  }] } });
172
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VyaW91cy1zY3JvbGwuZGlyZWN0aXZlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWNlcmlvdXMtc2Nyb2xsL3NyYy9saWIvY2VyaW91cy1zY3JvbGwuZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFHTCxTQUFTLEVBR1QsWUFBWSxFQUNaLEtBQUssRUFJTCxNQUFNLEdBR1AsTUFBTSxlQUFlLENBQUM7OztBQWF2QixTQUFTLG1CQUFtQixDQUFDLGFBQXdDLEVBQUUsUUFBbUM7SUFDeEcsTUFBTSxTQUFTLEdBQUcsT0FBTyxhQUFhLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLE9BQU8sUUFBUSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFDMUgsSUFBSSxTQUFTLEtBQUssU0FBUyxJQUFJLE1BQU0sQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztRQUN2RCxNQUFNLElBQUksS0FBSyxDQUFDLHVGQUF1RixDQUFDLENBQUM7SUFDM0csQ0FBQztJQUNELHdDQUF3QztJQUN4QyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxDQUFDO0FBQ2hDLENBQUM7QUFNRCxNQUFNLE9BQU8sc0JBQXNCO0lBaUNqQyxZQUNtQixJQUE2QixFQUM3QixNQUFzQixFQUN0QixNQUFjLEVBQ2QsT0FBNkI7UUFIN0IsU0FBSSxHQUFKLElBQUksQ0FBeUI7UUFDN0IsV0FBTSxHQUFOLE1BQU0sQ0FBZ0I7UUFDdEIsV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQUNkLFlBQU8sR0FBUCxPQUFPLENBQXNCO1FBcENoRCxtRkFBbUY7UUFDMUUsK0JBQTBCLEdBQWtCLElBQUksQ0FBQztRQUUxRCxpREFBaUQ7UUFDeEMsdUJBQWtCLEdBQTRCLElBQUksQ0FB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LG9CQUFvQjtzQkFBNUIsS0FBSztnQkFHRyx1QkFBdUI7c0JBQS9CLEtBQUs7Z0JBR0ksMkJBQTJCO3NCQUFwQyxNQUFNO2dCQUdHLDZCQUE2QjtzQkFBdEMsTUFBTTtnQkFHRyxrQkFBa0I7c0JBQTNCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBBZnRlclZpZXdJbml0LFxuICBBcHBsaWNhdGlvblJlZixcbiAgRGlyZWN0aXZlLFxuICBFbGVtZW50UmVmLFxuICBFbWJlZGRlZFZpZXdSZWYsXG4gIEV2ZW50RW1pdHRlcixcbiAgSW5wdXQsXG4gIE5nWm9uZSxcbiAgT25DaGFuZ2VzLFxuICBPbkRlc3Ryb3ksXG4gIE91dHB1dCxcbiAgU2ltcGxlQ2hhbmdlcyxcbiAgVGVtcGxhdGVSZWYsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5pbXBvcnQge1xuICB0eXBlIENlcmlvdXNTY3JvbGxPcHRpb25zLFxuICB0eXBlIEVsZW1lbnRSZW5kZXJlcixcbiAgdHlwZSBNZWFzdXJlZFZpZXdwb3J0UmFuZ2UsXG59IGZyb20gJ0BjZXJpb3VzZGV2dGVjaC9jZXJpb3VzLXNjcm9sbCc7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcblxuaW1wb3J0IHR5cGUgeyBDZXJpb3VzVmlld3BvcnRDaGFuZ2VEZXRhaWwgfSBmcm9tICcuL2NlcmlvdXMtc2Nyb2xsLnR5cGVzJztcbmltcG9ydCB0eXBlIHsgQ2VyaW91c1Njcm9sbEl0ZW1UZW1wbGF0ZUNvbnRleHQgfSBmcm9tICcuL2NlcmlvdXMtc2Nyb2xsLWl0ZW0tdGVtcGxhdGUuZGlyZWN0aXZlJztcbmltcG9ydCB7IHR5cGUgQ2VyaW91c1Njcm9sbEhvc3RSZWYsIENlcmlvdXNTY3JvbGxTZXJ2aWNlIH0gZnJvbSAnLi9jZXJpb3VzLXNjcm9sbC5zZXJ2aWNlJztcblxuZnVuY3Rpb24gY29lcmNlVG90YWxFbGVtZW50cyhleHBsaWNpdFRvdGFsOiBudW1iZXIgfCBudWxsIHwgdW5kZWZpbmVkLCBpdGVtc0xlbjogbnVtYmVyIHwgbnVsbCB8IHVuZGVmaW5lZCk6IG51bWJlciB7XG4gIGNvbnN0IGNhbmRpZGF0ZSA9IHR5cGVvZiBleHBsaWNpdFRvdGFsID09PSAnbnVtYmVyJyA/IGV4cGxpY2l0VG90YWwgOiB0eXBlb2YgaXRlbXNMZW4gPT09ICdudW1iZXInID8gaXRlbXNMZW4gOiB1bmRlZmluZWQ7XG4gIGlmIChjYW5kaWRhdGUgPT09IHVuZGVmaW5lZCB8fCBOdW1iZXIuaXNOYU4oY2FuZGlkYXRlKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignQ2VyaW91c1Njcm9sbERpcmVjdGl2ZTogcHJvdmlkZSBgY2VyaW91c1Njcm9sbFRvdGFsRWxlbWVudHNgIG9yIGBjZXJpb3VzU2Nyb2xsSXRlbXNgLicpO1xuICB9XG4gIC8vIENlcmlvdXNTY3JvbGwgY3VycmVudGx5IHJlcXVpcmVzID49IDFcbiAgcmV0dXJuIE1hdGgubWF4KDEsIGNhbmRpZGF0ZSk7XG59XG5cbkBEaXJlY3RpdmUoe1xuICBzZWxlY3RvcjogJ1tjZXJpb3VzU2Nyb2xsXScsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG59KVxuZXhwb3J0IGNsYXNzIENlcmlvdXNTY3JvbGxEaXJlY3RpdmU8VEl0ZW0gPSB1bmtub3duPiBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQsIE9uQ2hhbmdlcywgT25EZXN0cm95IHtcbiAgLyoqIFRvdGFsIG51bWJlciBvZiBpdGVtcy4gSWYgb21pdHRlZCwgZGVyaXZlZCBmcm9tIGBjZXJpb3VzU2Nyb2xsSXRlbXMubGVuZ3RoYC4gKi9cbiAgQElucHV0KCkgY2VyaW91c1Njcm9sbFRvdGFsRWxlbWVudHM6IG51bWJlciB8IG51bGwgPSBudWxsO1xuXG4gIC8qKiBPcHRpb25hbCBpdGVtcyBhcnJheSAoZW5hYmxlcyBgbGV0LWl0ZW1gKS4gKi9cbiAgQElucHV0KCkgY2VyaW91c1Njcm9sbEl0ZW1zOiByZWFkb25seSBUSXRlbVtdIHwgbnVsbCA9IG51bGw7XG5cbiAgLyoqIE9wdGlvbmFsIGdldHRlciBmb3IgbGFyZ2UgZGF0YXNldHMgKGFsdGVybmF0aXZlIHRvIHBhc3NpbmcgZnVsbCBgaXRlbXNgKS4gKi9cbiAgQElucHV0KCkgY2VyaW91c1Njcm9sbEdldEl0ZW06ICgoaW5kZXg6IG51bWJlcikgPT4gVEl0ZW0pIHwgbnVsbCA9IG51bGw7XG5cbiAgLyoqIFRlbXBsYXRlIHVzZWQgdG8gcmVuZGVyIGVhY2ggcm93LiAqL1xuICBASW5wdXQoKSBjZXJpb3VzU2Nyb2xsSXRlbVRlbXBsYXRlOiBUZW1wbGF0ZVJlZjxDZXJpb3VzU2Nyb2xsSXRlbVRlbXBsYXRlQ29udGV4dDxUSXRlbT4+IHwgbnVsbCA9IG51bGw7XG5cbiAgLyoqIE9wdGlvbnMgcGFzc2VkIHRvIGBuZXcgQ2VyaW91c1Njcm9sbCguLi4pYC4gKi9cbiAgQElucHV0KCkgY2VyaW91c1Njcm9sbE9wdGlvbnM6IENlcmlvdXNTY3JvbGxPcHRpb25zID0ge307XG5cbiAgLyoqIEF1dG9tYXRpY2FsbHkgY2FsbCByZW5kZXIgYWZ0ZXIgZWFjaCBzY3JvbGwgZXZlbnQuIERlZmF1bHQ6IHRydWUgKi9cbiAgQElucHV0KCkgY2VyaW91c1Njcm9sbEF1dG9SZW5kZXIgPSB0cnVlO1xuXG4gIC8qKiBFbWl0cyBgY2VyaW91cy12aWV3cG9ydC1jaGFuZ2VgIGRldGFpbC4gKi9cbiAgQE91dHB1dCgpIGNlcmlvdXNTY3JvbGxWaWV3cG9ydENoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8Q2VyaW91c1ZpZXdwb3J0Q2hhbmdlRGV0YWlsPigpO1xuXG4gIC8qKiBFbWl0cyB0aGUgbGFzdCBtZWFzdXJlZCB2aWV3cG9ydCBhZnRlciBlYWNoIHJlbmRlciBwYXNzLiAqL1xuICBAT3V0cHV0KCkgY2VyaW91c1Njcm9sbE1lYXN1cmVkVmlld3BvcnQgPSBuZXcgRXZlbnRFbWl0dGVyPE1lYXN1cmVkVmlld3BvcnRSYW5nZT4oKTtcblxuICAvKiogRW1pdHMgb25jZSB0aGUgdW5kZXJseWluZyBgQ2VyaW91c1Njcm9sbGAgaW5zdGFuY2UgaXMgcmVhZHkuICovXG4gIEBPdXRwdXQoKSBjZXJpb3VzU2Nyb2xsUmVhZHkgPSBuZXcgRXZlbnRFbWl0dGVyPENlcmlvdXNTY3JvbGxIb3N0UmVmWydzY3JvbGxlciddPigpO1xuXG4gIHByaXZhdGUgaG9zdFJlZjogQ2VyaW91c1Njcm9sbEhvc3RSZWYgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSB2aWV3cG9ydFN1YjogU3Vic2NyaXB0aW9uIHwgbnVsbCA9IG51bGw7XG5cbiAgcHJpdmF0ZSByZWFkb25seSB2aWV3QnlDb250YWluZXIgPSBuZXcgTWFwPEhUTUxFbGVtZW50LCBFbWJlZGRlZFZpZXdSZWY8Q2VyaW91c1Njcm9sbEl0ZW1UZW1wbGF0ZUNvbnRleHQ8VEl0ZW0+Pj4oKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IGhvc3Q6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+LFxuICAgIHByaXZhdGUgcmVhZG9ubHkgYXBwUmVmOiBBcHBsaWNhdGlvblJlZixcbiAgICBwcml2YXRlIHJlYWRvbmx5IG5nWm9uZTogTmdab25lLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgY2VyaW91czogQ2VyaW91c1Njcm9sbFNlcnZpY2VcbiAgKSB7fVxuXG4gIG5nQWZ0ZXJWaWV3SW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLmVuc3VyZUluaXRpYWxpemVkKCk7XG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmhvc3RSZWYpIHJldHVybjtcblxuICAgIGlmIChjaGFuZ2VzWydjZXJpb3VzU2Nyb2xsSXRlbXMnXSB8fCBjaGFuZ2VzWydjZXJpb3VzU2Nyb2xsVG90YWxFbGVtZW50cyddKSB7XG4gICAgICBjb25zdCB0b3RhbCA9IGNvZXJjZVRvdGFsRWxlbWVudHModGhpcy5jZXJpb3VzU2Nyb2xsVG90YWxFbGVtZW50cywgdGhpcy5jZXJpb3VzU2Nyb2xsSXRlbXM/Lmxlbmd0aCA/PyBudWxsKTtcbiAgICAgIHRoaXMuaG9zdFJlZi5zY3JvbGxlci50b3RhbEVsZW1lbnRzID0gdG90YWw7XG4gICAgICB0aGlzLmhvc3RSZWYuc2Nyb2xsZXIuY2xlYXJBbGxDYWNoZXMoKTtcbiAgICAgIGlmICh0aGlzLmNlcmlvdXNTY3JvbGxBdXRvUmVuZGVyKSB0aGlzLnJlbmRlcigpO1xuICAgIH1cblxuICAgIGlmIChjaGFuZ2VzWydjZXJpb3VzU2Nyb2xsT3B0aW9ucyddICYmICFjaGFuZ2VzWydjZXJpb3VzU2Nyb2xsT3B0aW9ucyddLmZpcnN0Q2hhbmdlKSB7XG4gICAgICAvLyBPcHRpb25zIGFyZSBjb25zdW1lZCBwcmltYXJpbHkgYXQgY29uc3RydWN0aW9uIHRpbWUuXG4gICAgICB0aGlzLnJlY3JlYXRlKCk7XG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy52aWV3cG9ydFN1Yj8udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLnZpZXdwb3J0U3ViID0gbnVsbDtcblxuICAgIHRoaXMuZGVzdHJveUFsbFZpZXdzKCk7XG5cbiAgICB0aGlzLmhvc3RSZWY/LmRlc3Ryb3koKTtcbiAgICB0aGlzLmhvc3RSZWYgPSBudWxsO1xuICB9XG5cbiAgLyoqIEltcGVyYXRpdmVseSB0cmlnZ2VyIGEgcmVuZGVyIHBhc3MgKHVzZXMgYGNlcmlvdXNTY3JvbGxJdGVtVGVtcGxhdGVgKS4gKi9cbiAgcmVuZGVyKCk6IE1lYXN1cmVkVmlld3BvcnRSYW5nZSB8IG51bGwge1xuICAgIGlmICghdGhpcy5ob3N0UmVmKSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCB0ZW1wbGF0ZSA9IHRoaXMuY2VyaW91c1Njcm9sbEl0ZW1UZW1wbGF0ZTtcbiAgICBpZiAoIXRlbXBsYXRlKSByZXR1cm4gbnVsbDtcblxuICAgIGNvbnN0IGhvc3RDb250YWluZXIgPSB0aGlzLmhvc3QubmF0aXZlRWxlbWVudDtcbiAgICBjb25zdCBoZWlnaHQgPSBob3N0Q29udGFpbmVyLmNsaWVudEhlaWdodCB8fCBob3N0Q29udGFpbmVyLm9mZnNldEhlaWdodDtcbiAgICBjb25zdCBjb250ZW50Q29udGFpbmVyID0gdGhpcy5ob3N0UmVmLmNvbnRlbnRFbGVtZW50O1xuXG4gICAgY29uc3QgcmVuZGVyZXI6IEVsZW1lbnRSZW5kZXJlciA9IChpbmRleCwgZWxlbWVudENvbnRhaW5lcikgPT4ge1xuICAgICAgLy8gUmVuZGVyaW5nIG11c3QgY3JlYXRlIEFuZ3VsYXIgdmlld3MgaW5zaWRlIHRoZSBBbmd1bGFyIHpvbmUuXG4gICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgICB0aGlzLnJlbmRlclRlbXBsYXRlSW50b0NvbnRhaW5lcih0ZW1wbGF0ZSwgaW5kZXgsIGVsZW1lbnRDb250YWluZXIpO1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIGNvbnN0IHJhbmdlID0gdGhpcy5ob3N0UmVmLnNjcm9sbGVyLnJlbmRlclZpZXdwb3J0KGhlaWdodCwgY29udGVudENvbnRhaW5lciwgcmVuZGVyZXIpO1xuICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB0aGlzLmNlcmlvdXNTY3JvbGxNZWFzdXJlZFZpZXdwb3J0LmVtaXQocmFuZ2UpKTtcbiAgICByZXR1cm4gcmFuZ2U7XG4gIH1cblxuICBwcml2YXRlIHJlY3JlYXRlKCk6IHZvaWQge1xuICAgIHRoaXMudmlld3BvcnRTdWI/LnVuc3Vic2NyaWJlKCk7XG4gICAgdGhpcy52aWV3cG9ydFN1YiA9IG51bGw7XG5cbiAgICB0aGlzLmRlc3Ryb3lBbGxWaWV3cygpO1xuXG4gICAgdGhpcy5ob3N0UmVmPy5kZXN0cm95KCk7XG4gICAgdGhpcy5ob3N0UmVmID0gbnVsbDtcblxuICAgIHRoaXMuZW5zdXJlSW5pdGlhbGl6ZWQoKTtcbiAgfVxuXG4gIHByaXZhdGUgZW5zdXJlSW5pdGlhbGl6ZWQoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaG9zdFJlZikgcmV0dXJuO1xuXG4gICAgY29uc3QgY29udGFpbmVyID0gdGhpcy5ob3N0Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgY29uc3QgdG90YWwgPSBjb2VyY2VUb3RhbEVsZW1lbnRzKHRoaXMuY2VyaW91c1Njcm9sbFRvdGFsRWxlbWVudHMsIHRoaXMuY2VyaW91c1Njcm9sbEl0ZW1zPy5sZW5ndGggPz8gbnVsbCk7XG5cbiAgICB0aGlzLmhvc3RSZWYgPSB0aGlzLmNlcmlvdXMuY3JlYXRlSG9zdChjb250YWluZXIsIHRvdGFsLCB0aGlzLmNlcmlvdXNTY3JvbGxPcHRpb25zLCB0aGlzLm5nWm9uZSwgKCkgPT4ge1xuICAgICAgaWYgKHRoaXMuY2VyaW91c1Njcm9sbEF1dG9SZW5kZXIpIHRoaXMucmVuZGVyKCk7XG4gICAgfSk7XG5cbiAgICB0aGlzLnZpZXdwb3J0U3ViID0gdGhpcy5ob3N0UmVmLnZpZXdwb3J0Q2hhbmdlcyQuc3Vic2NyaWJlKChkZXRhaWw6IENlcmlvdXNWaWV3cG9ydENoYW5nZURldGFpbCkgPT4ge1xuICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHRoaXMuY2VyaW91c1Njcm9sbFZpZXdwb3J0Q2hhbmdlLmVtaXQoZGV0YWlsKSk7XG4gICAgfSk7XG5cbiAgICB0aGlzLmNlcmlvdXNTY3JvbGxSZWFkeS5lbWl0KHRoaXMuaG9zdFJlZi5zY3JvbGxlcik7XG5cbiAgICBpZiAodGhpcy5jZXJpb3VzU2Nyb2xsQXV0b1JlbmRlcikge1xuICAgICAgcXVldWVNaWNyb3Rhc2soKCkgPT4gdGhpcy5yZW5kZXIoKSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZXRJdGVtRm9ySW5kZXgoaW5kZXg6IG51bWJlcik6IFRJdGVtIHtcbiAgICBjb25zdCBnZXR0ZXIgPSB0aGlzLmNlcmlvdXNTY3JvbGxHZXRJdGVtO1xuICAgIGlmIChnZXR0ZXIpIHJldHVybiBnZXR0ZXIoaW5kZXgpO1xuXG4gICAgY29uc3QgaXRlbXMgPSB0aGlzLmNlcmlvdXNTY3JvbGxJdGVtcztcbiAgICBpZiAoIWl0ZW1zKSByZXR1cm4gdW5kZWZpbmVkIGFzIFRJdGVtO1xuXG4gICAgcmV0dXJuIGl0ZW1zW2luZGV4XTtcbiAgfVxuXG4gIHByaXZhdGUgcmVuZGVyVGVtcGxhdGVJbnRvQ29udGFpbmVyKFxuICAgIHRlbXBsYXRlOiBUZW1wbGF0ZVJlZjxDZXJpb3VzU2Nyb2xsSXRlbVRlbXBsYXRlQ29udGV4dDxUSXRlbT4+LFxuICAgIGluZGV4OiBudW1iZXIsXG4gICAgZWxlbWVudENvbnRhaW5lcjogSFRNTEVsZW1lbnRcbiAgKTogdm9pZCB7XG4gICAgY29uc3QgcHJldmlvdXMgPSB0aGlzLnZpZXdCeUNvbnRhaW5lci5nZXQoZWxlbWVudENvbnRhaW5lcik7XG4gICAgaWYgKHByZXZpb3VzKSB7XG4gICAgICB0aGlzLmFwcFJlZi5kZXRhY2hWaWV3KHByZXZpb3VzKTtcbiAgICAgIHByZXZpb3VzLmRlc3Ryb3koKTtcbiAgICAgIHRoaXMudmlld0J5Q29udGFpbmVyLmRlbGV0ZShlbGVtZW50Q29udGFpbmVyKTtcbiAgICB9XG5cbiAgICAvLyBDbGVhciBwcmlvciBET00gKENlcmlvdXNTY3JvbGwgbWF5IHJlY3ljbGUgY29udGFpbmVycykuXG4gICAgZWxlbWVudENvbnRhaW5lci50ZXh0Q29udGVudCA9ICcnO1xuXG4gICAgY29uc3QgaXRlbSA9IHRoaXMuZ2V0SXRlbUZvckluZGV4KGluZGV4KTtcbiAgICBjb25zdCB2aWV3ID0gdGVtcGxhdGUuY3JlYXRlRW1iZWRkZWRWaWV3KHsgJGltcGxpY2l0OiBpdGVtLCBpdGVtLCBpbmRleCB9KTtcbiAgICB0aGlzLmFwcFJlZi5hdHRhY2hWaWV3KHZpZXcpO1xuICAgIHZpZXcuZGV0ZWN0Q2hhbmdlcygpO1xuXG4gICAgZm9yIChjb25zdCBub2RlIG9mIHZpZXcucm9vdE5vZGVzKSB7XG4gICAgICBlbGVtZW50Q29udGFpbmVyLmFwcGVuZENoaWxkKG5vZGUpO1xuICAgIH1cblxuICAgIHRoaXMudmlld0J5Q29udGFpbmVyLnNldChlbGVtZW50Q29udGFpbmVyLCB2aWV3KTtcbiAgfVxuXG4gIHByaXZhdGUgZGVzdHJveUFsbFZpZXdzKCk6IHZvaWQge1xuICAgIGZvciAoY29uc3QgdmlldyBvZiB0aGlzLnZpZXdCeUNvbnRhaW5lci52YWx1ZXMoKSkge1xuICAgICAgdGhpcy5hcHBSZWYuZGV0YWNoVmlldyh2aWV3KTtcbiAgICAgIHZpZXcuZGVzdHJveSgpO1xuICAgIH1cbiAgICB0aGlzLnZpZXdCeUNvbnRhaW5lci5jbGVhcigpO1xuICB9XG59XG4iXX0=
385
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VyaW91cy1zY3JvbGwuZGlyZWN0aXZlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWNlcmlvdXMtc2Nyb2xsL3NyYy9saWIvY2VyaW91cy1zY3JvbGwuZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFHTCxTQUFTLEVBR1QsWUFBWSxFQUNaLEtBQUssRUFJTCxNQUFNLEdBR1AsTUFBTSxlQUFlLENBQUM7OztBQWF2QixTQUFTLG1CQUFtQixDQUFDLGFBQXdDLEVBQUUsUUFBbUM7SUFDeEcsTUFBTSxTQUFTLEdBQUcsT0FBTyxhQUFhLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLE9BQU8sUUFBUSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFDMUgsSUFBSSxTQUFTLEtBQUssU0FBUyxJQUFJLE1BQU0sQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztRQUN2RCxNQUFNLElBQUksS0FBSyxDQUFDLHVGQUF1RixDQUFDLENBQUM7SUFDM0csQ0FBQztJQUNELHdDQUF3QztJQUN4QyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxDQUFDO0FBQ2hDLENBQUM7QUFNRCxNQUFNLE9BQU8sc0JBQXNCO0lBdUNqQyxZQUNtQixJQUE2QixFQUM3QixNQUFzQixFQUN0QixNQUFjLEVBQ2QsT0FBNkI7UUFIN0IsU0FBSSxHQUFKLElBQUksQ0FBeUI7UUFDN0IsV0FBTSxHQUFOLE1BQU0sQ0FBZ0I7UUFDdEIsV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQUNkLFlBQU8sR0FBUCxPQUFPLENBQXNCO1FBMUNoRCxtRkFBbUY7UUFDMUUsK0JBQTBCLEdBQWtCLElBQUksQ0FBQztRQUUxRCxpREFBaUQ7UUFDeEMsdUJBQWtCLEdBQTRCLElBQUksQ0FB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UyxFQUFFLENBQUM7WUFDbEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDN0IsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2pCLENBQUM7UUFDRCxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7SUFDNUIsQ0FBQzsrR0FsWVUsc0JBQXNCO21HQUF0QixzQkFBc0I7OzRGQUF0QixzQkFBc0I7a0JBSmxDLFNBQVM7bUJBQUM7b0JBQ1QsUUFBUSxFQUFFLGlCQUFpQjtvQkFDM0IsVUFBVSxFQUFFLElBQUk7aUJBQ2pCO29LQUdVLDBCQUEwQjtzQkFBbEMsS0FBSztnQkFHRyxrQkFBa0I7c0JBQTFCLEtBQUs7Z0JBR0csb0JBQW9CO3NCQUE1QixLQUFLO2dCQUdHLHlCQUF5QjtzQkFBakMsS0FBSztnQkFHRyxvQkFBb0I7c0JBQTVCLEtBQUs7Z0JBR0csdUJBQXVCO3NCQUEvQixLQUFLO2dCQUdJLDJCQUEyQjtzQkFBcEMsTUFBTTtnQkFHRyw2QkFBNkI7c0JBQXRDLE1BQU07Z0JBR0csa0JBQWtCO3NCQUEzQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQWZ0ZXJWaWV3SW5pdCxcbiAgQXBwbGljYXRpb25SZWYsXG4gIERpcmVjdGl2ZSxcbiAgRWxlbWVudFJlZixcbiAgRW1iZWRkZWRWaWV3UmVmLFxuICBFdmVudEVtaXR0ZXIsXG4gIElucHV0LFxuICBOZ1pvbmUsXG4gIE9uQ2hhbmdlcyxcbiAgT25EZXN0cm95LFxuICBPdXRwdXQsXG4gIFNpbXBsZUNoYW5nZXMsXG4gIFRlbXBsYXRlUmVmLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuaW1wb3J0IHtcbiAgdHlwZSBDZXJpb3VzU2Nyb2xsT3B0aW9ucyxcbiAgdHlwZSBFbGVtZW50UmVuZGVyZXIsXG4gIHR5cGUgTWVhc3VyZWRWaWV3cG9ydFJhbmdlLFxufSBmcm9tICdAY2VyaW91c2RldnRlY2gvY2VyaW91cy1zY3JvbGwnO1xuaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5cbmltcG9ydCB0eXBlIHsgQ2VyaW91c1ZpZXdwb3J0Q2hhbmdlRGV0YWlsIH0gZnJvbSAnLi9jZXJpb3VzLXNjcm9sbC50eXBlcyc7XG5pbXBvcnQgdHlwZSB7IENlcmlvdXNTY3JvbGxJdGVtVGVtcGxhdGVDb250ZXh0IH0gZnJvbSAnLi9jZXJpb3VzLXNjcm9sbC1pdGVtLXRlbXBsYXRlLmRpcmVjdGl2ZSc7XG5pbXBvcnQgeyB0eXBlIENlcmlvdXNTY3JvbGxIb3N0UmVmLCBDZXJpb3VzU2Nyb2xsU2VydmljZSB9IGZyb20gJy4vY2VyaW91cy1zY3JvbGwuc2VydmljZSc7XG5cbmZ1bmN0aW9uIGNvZXJjZVRvdGFsRWxlbWVudHMoZXhwbGljaXRUb3RhbDogbnVtYmVyIHwgbnVsbCB8IHVuZGVmaW5lZCwgaXRlbXNMZW46IG51bWJlciB8IG51bGwgfCB1bmRlZmluZWQpOiBudW1iZXIge1xuICBjb25zdCBjYW5kaWRhdGUgPSB0eXBlb2YgZXhwbGljaXRUb3RhbCA9PT0gJ251bWJlcicgPyBleHBsaWNpdFRvdGFsIDogdHlwZW9mIGl0ZW1zTGVuID09PSAnbnVtYmVyJyA/IGl0ZW1zTGVuIDogdW5kZWZpbmVkO1xuICBpZiAoY2FuZGlkYXRlID09PSB1bmRlZmluZWQgfHwgTnVtYmVyLmlzTmFOKGNhbmRpZGF0ZSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0NlcmlvdXNTY3JvbGxEaXJlY3RpdmU6IHByb3ZpZGUgYGNlcmlvdXNTY3JvbGxUb3RhbEVsZW1lbnRzYCBvciBgY2VyaW91c1Njcm9sbEl0ZW1zYC4nKTtcbiAgfVxuICAvLyBDZXJpb3VzU2Nyb2xsIGN1cnJlbnRseSByZXF1aXJlcyA+PSAxXG4gIHJldHVybiBNYXRoLm1heCgxLCBjYW5kaWRhdGUpO1xufVxuXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICdbY2VyaW91c1Njcm9sbF0nLFxuICBzdGFuZGFsb25lOiB0cnVlLFxufSlcbmV4cG9ydCBjbGFzcyBDZXJpb3VzU2Nyb2xsRGlyZWN0aXZlPFRJdGVtID0gdW5rbm93bj4gaW1wbGVtZW50cyBBZnRlclZpZXdJbml0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSB7XG4gIC8qKiBUb3RhbCBudW1iZXIgb2YgaXRlbXMuIElmIG9taXR0ZWQsIGRlcml2ZWQgZnJvbSBgY2VyaW91c1Njcm9sbEl0ZW1zLmxlbmd0aGAuICovXG4gIEBJbnB1dCgpIGNlcmlvdXNTY3JvbGxUb3RhbEVsZW1lbnRzOiBudW1iZXIgfCBudWxsID0gbnVsbDtcblxuICAvKiogT3B0aW9uYWwgaXRlbXMgYXJyYXkgKGVuYWJsZXMgYGxldC1pdGVtYCkuICovXG4gIEBJbnB1dCgpIGNlcmlvdXNTY3JvbGxJdGVtczogcmVhZG9ubHkgVEl0ZW1bXSB8IG51bGwgPSBudWxsO1xuXG4gIC8qKiBPcHRpb25hbCBnZXR0ZXIgZm9yIGxhcmdlIGRhdGFzZXRzIChhbHRlcm5hdGl2ZSB0byBwYXNzaW5nIGZ1bGwgYGl0ZW1zYCkuICovXG4gIEBJbnB1dCgpIGNlcmlvdXNTY3JvbGxHZXRJdGVtOiAoKGluZGV4OiBudW1iZXIpID0+IFRJdGVtKSB8IG51bGwgPSBudWxsO1xuXG4gIC8qKiBUZW1wbGF0ZSB1c2VkIHRvIHJlbmRlciBlYWNoIHJvdy4gKi9cbiAgQElucHV0KCkgY2VyaW91c1Njcm9sbEl0ZW1UZW1wbGF0ZTogVGVtcGxhdGVSZWY8Q2VyaW91c1Njcm9sbEl0ZW1UZW1wbGF0ZUNvbnRleHQ8VEl0ZW0+PiB8IG51bGwgPSBudWxsO1xuXG4gIC8qKiBPcHRpb25zIHBhc3NlZCB0byBgbmV3IENlcmlvdXNTY3JvbGwoLi4uKWAuICovXG4gIEBJbnB1dCgpIGNlcmlvdXNTY3JvbGxPcHRpb25zOiBDZXJpb3VzU2Nyb2xsT3B0aW9ucyA9IHt9O1xuXG4gIC8qKiBBdXRvbWF0aWNhbGx5IGNhbGwgcmVuZGVyIGFmdGVyIGVhY2ggc2Nyb2xsIGV2ZW50LiBEZWZhdWx0OiB0cnVlICovXG4gIEBJbnB1dCgpIGNlcmlvdXNTY3JvbGxBdXRvUmVuZGVyID0gdHJ1ZTtcblxuICAvKiogRW1pdHMgYGNlcmlvdXMtdmlld3BvcnQtY2hhbmdlYCBkZXRhaWwuICovXG4gIEBPdXRwdXQoKSBjZXJpb3VzU2Nyb2xsVmlld3BvcnRDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPENlcmlvdXNWaWV3cG9ydENoYW5nZURldGFpbD4oKTtcblxuICAvKiogRW1pdHMgdGhlIGxhc3QgbWVhc3VyZWQgdmlld3BvcnQgYWZ0ZXIgZWFjaCByZW5kZXIgcGFzcy4gKi9cbiAgQE91dHB1dCgpIGNlcmlvdXNTY3JvbGxNZWFzdXJlZFZpZXdwb3J0ID0gbmV3IEV2ZW50RW1pdHRlcjxNZWFzdXJlZFZpZXdwb3J0UmFuZ2U+KCk7XG5cbiAgLyoqIEVtaXRzIG9uY2UgdGhlIHVuZGVybHlpbmcgYENlcmlvdXNTY3JvbGxgIGluc3RhbmNlIGlzIHJlYWR5LiAqL1xuICBAT3V0cHV0KCkgY2VyaW91c1Njcm9sbFJlYWR5ID0gbmV3IEV2ZW50RW1pdHRlcjxDZXJpb3VzU2Nyb2xsSG9zdFJlZlsnc2Nyb2xsZXInXT4oKTtcblxuICBwcml2YXRlIGhvc3RSZWY6IENlcmlvdXNTY3JvbGxIb3N0UmVmIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgdmlld3BvcnRTdWI6IFN1YnNjcmlwdGlvbiB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHNjaGVkdWxlZFJlbmRlckZyYW1lOiBudW1iZXIgfCBudWxsID0gbnVsbDtcblxuICBwcml2YXRlIHJlYWRvbmx5IHZpZXdCeUNvbnRhaW5lciA9IG5ldyBNYXA8SFRNTEVsZW1lbnQsIEVtYmVkZGVkVmlld1JlZjxDZXJpb3VzU2Nyb2xsSXRlbVRlbXBsYXRlQ29udGV4dDxUSXRlbT4+PigpO1xuICAvLyBQb29sIG9mIHZpZXdzIGRldGFjaGVkIGJlY2F1c2UgdGhlaXIgY29udGFpbmVyIGxlZnQgdGhlIHZpZXdwb3J0LiBSZXVzaW5nXG4gIC8vIHRoZW0gb24gc3Vic2VxdWVudCByZW5kZXJzIGF2b2lkcyBkZXN0cm95aW5nICsgcmVjcmVhdGluZyB0aGUgZW50aXJlIHJvd1xuICAvLyBjb21wb25lbnQgdHJlZSBvbiBmYXN0IHNjcm9sbHMgKHdoZXJlIHRoZSBlbmdpbmUncyBlbGVtZW50IHBvb2wgd2lwZXNcbiAgLy8gdGV4dENvbnRlbnQgb24gcmV1c2VkIGNvbnRhaW5lcnMsIHNvIHZpZXcgcm9vdE5vZGVzIGdldCBvcnBoYW5lZCkuXG4gIHByaXZhdGUgcmVhZG9ubHkgZnJlZVZpZXdzOiBFbWJlZGRlZFZpZXdSZWY8Q2VyaW91c1Njcm9sbEl0ZW1UZW1wbGF0ZUNvbnRleHQ8VEl0ZW0+PltdID0gW107XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBob3N0OiBFbGVtZW50UmVmPEhUTUxFbGVtZW50PixcbiAgICBwcml2YXRlIHJlYWRvbmx5IGFwcFJlZjogQXBwbGljYXRpb25SZWYsXG4gICAgcHJpdmF0ZSByZWFkb25seSBuZ1pvbmU6IE5nWm9uZSxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGNlcmlvdXM6IENlcmlvdXNTY3JvbGxTZXJ2aWNlXG4gICkge31cblxuICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG4gICAgdGhpcy5lbnN1cmVJbml0aWFsaXplZCgpO1xuICB9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmICghdGhpcy5ob3N0UmVmKSByZXR1cm47XG5cbiAgICBpZiAoY2hhbmdlc1snY2VyaW91c1Njcm9sbEl0ZW1zJ10gfHwgY2hhbmdlc1snY2VyaW91c1Njcm9sbFRvdGFsRWxlbWVudHMnXSkge1xuICAgICAgY29uc3QgdG90YWwgPSBjb2VyY2VUb3RhbEVsZW1lbnRzKHRoaXMuY2VyaW91c1Njcm9sbFRvdGFsRWxlbWVudHMsIHRoaXMuY2VyaW91c1Njcm9sbEl0ZW1zPy5sZW5ndGggPz8gbnVsbCk7XG4gICAgICBjb25zdCBjb3VudENoYW5nZWQgPSB0aGlzLmhvc3RSZWYuc2Nyb2xsZXIudG90YWxFbGVtZW50cyAhPT0gdG90YWw7XG5cbiAgICAgIGlmIChjb3VudENoYW5nZWQpIHtcbiAgICAgICAgLy8gVGhlIGRhdGFzZXQgc2l6ZSBjaGFuZ2VkOiB0aGUgVmlld3BvcnRSZW5kZXJlciBzdG9yZXMgaXRzIG93biBjb3B5IG9mXG4gICAgICAgIC8vIHRvdGFsRWxlbWVudHMgKHNldCBieSB2YWx1ZSBhdCBjb25zdHJ1Y3Rpb24pIHNvIHBhdGNoaW5nIHRoZSBlbmdpbmUnc1xuICAgICAgICAvLyBwdWJsaWMgcHJvcGVydHkgYWxvbmUgbGVhdmVzIHRoZSByZW5kZXJlcidzIGludGVybmFsIGJvdW5kIHN0YWxlLiAgVGhlXG4gICAgICAgIC8vIHJlbmRlcmVyIHdvdWxkIHRoZW4gdXNlIHRoZSBvbGQgY291bnQgZm9yIGl0cyB2aWV3cG9ydC1maWxsIGxvb3AgYW5kXG4gICAgICAgIC8vIGJvdHRvbS1ib3VuZGFyeSBzY2FuLCBwcm9kdWNpbmcgcGhhbnRvbSByZW5kZXJzIGF0IG91dC1vZi1ib3VuZHNcbiAgICAgICAgLy8gaW5kaWNlcyAodW5kZWZpbmVkIGl0ZW1zIOKGkiAwLWhlaWdodCByb3dzIOKGkiB0aGUgZmlsbCBsb29wIG5ldmVyXG4gICAgICAgIC8vIHNhdGlzZmllcyBpdHMgaGVpZ2h0IGNvbmRpdGlvbiDihpIgaHVuZHJlZHMgb2YgcmVuZGVyZXIgY2FsbGJhY2tzKS5cbiAgICAgICAgLy8gUmVjcmVhdGluZyB0aGUgZW5naW5lIGdpdmVzIGJvdGggdGhlIGVuZ2luZSBhbmQgdGhlIHJlbmRlcmVyIGEgZnJlc2gsXG4gICAgICAgIC8vIGNvbnNpc3RlbnQgY291bnQuICBlbnN1cmVJbml0aWFsaXplZCgpIHNjaGVkdWxlcyB0aGUgZmlyc3QgcmVuZGVyIHZpYVxuICAgICAgICAvLyBxdWV1ZU1pY3JvdGFzaywgd2hpY2ggcnVucyBhZnRlciB0aGUgY3VycmVudCBDRCBjeWNsZSBjb21wbGV0ZXMuXG4gICAgICAgIHRoaXMucmVjcmVhdGUoKTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5jZXJpb3VzU2Nyb2xsQXV0b1JlbmRlcikge1xuICAgICAgICAvLyBTYW1lIGNvdW50LCBuZXcgZGF0YSByZWZlcmVuY2UgKGUuZy4gYW4gaW1tdXRhYmxlIGVkaXQgb3IgYSBzb3J0IHRoYXRcbiAgICAgICAgLy8gaGFwcGVucyB0byBrZWVwIHRoZSBzYW1lIGxlbmd0aCkuIFRoZSBlbmdpbmUgcmV1c2VzIHRoZSBET00gZWxlbWVudCBpdFxuICAgICAgICAvLyBhbHJlYWR5IHJlbmRlcmVkIGZvciBlYWNoIG92ZXJsYXBwaW5nIGluZGV4IHdpdGhvdXQgcmUtaW52b2tpbmcgdGhlXG4gICAgICAgIC8vIHJlbmRlcmVyLCBzbyB1cGRhdGUgdGhlIGNvbnRlbnQgb2YgZXZlcnkgY3VycmVudGx5LXZpc2libGUgcm93IElOXG4gICAgICAgIC8vIFBMQUNFIGJlZm9yZSBjYWxsaW5nIHJlbmRlcigpLiAgVGhpcyBwcmVzZXJ2ZXMgZWFjaCByb3cncyBlbWJlZGRlZFxuICAgICAgICAvLyB2aWV3IChzbyBhIGZvY3VzZWQgdGV4dGJveCBrZWVwcyBmb2N1cy9jYXJldCkgYW5kIGRvZXMgTk9UIGRpc2NhcmRcbiAgICAgICAgLy8gY2FjaGVkIGhlaWdodHMuIElmIGEgcm93J3MgaGVpZ2h0IGFjdHVhbGx5IGNoYW5nZXMgdGhlIGVuZ2luZSdzXG4gICAgICAgIC8vIFJlc2l6ZU9ic2VydmVyIGtlZXBzIHRoZSBjYWNoZSBjb3JyZWN0IG9uIGl0cyBvd247IGZvciBhIHdob2xlc2FsZVxuICAgICAgICAvLyBoZWlnaHQgY2hhbmdlIGFjcm9zcyBhbGwgcm93cywgY2FsbCByZWNhbGN1bGF0ZSgpIGluc3RlYWQuXG4gICAgICAgIHRoaXMucmVmcmVzaFJlbmRlcmVkQ29udGVudCgpO1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChjaGFuZ2VzWydjZXJpb3VzU2Nyb2xsT3B0aW9ucyddICYmICFjaGFuZ2VzWydjZXJpb3VzU2Nyb2xsT3B0aW9ucyddLmZpcnN0Q2hhbmdlKSB7XG4gICAgICAvLyBPcHRpb25zIGFyZSBjb25zdW1lZCBwcmltYXJpbHkgYXQgY29uc3RydWN0aW9uIHRpbWUuXG4gICAgICB0aGlzLnJlY3JlYXRlKCk7XG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuc2NoZWR1bGVkUmVuZGVyRnJhbWUgIT0gbnVsbCkge1xuICAgICAgY2FuY2VsQW5pbWF0aW9uRnJhbWUodGhpcy5zY2hlZHVsZWRSZW5kZXJGcmFtZSk7XG4gICAgICB0aGlzLnNjaGVkdWxlZFJlbmRlckZyYW1lID0gbnVsbDtcbiAgICB9XG5cbiAgICB0aGlzLnZpZXdwb3J0U3ViPy51bnN1YnNjcmliZSgpO1xuICAgIHRoaXMudmlld3BvcnRTdWIgPSBudWxsO1xuXG4gICAgdGhpcy5kZXN0cm95QWxsVmlld3MoKTtcblxuICAgIHRoaXMuaG9zdFJlZj8uZGVzdHJveSgpO1xuICAgIHRoaXMuaG9zdFJlZiA9IG51bGw7XG4gIH1cblxuICAvKiogSW1wZXJhdGl2ZWx5IHRyaWdnZXIgYSByZW5kZXIgcGFzcyAodXNlcyBgY2VyaW91c1Njcm9sbEl0ZW1UZW1wbGF0ZWApLiAqL1xuICByZW5kZXIoKTogTWVhc3VyZWRWaWV3cG9ydFJhbmdlIHwgbnVsbCB7XG4gICAgaWYgKCF0aGlzLmhvc3RSZWYpIHJldHVybiBudWxsO1xuICAgIGNvbnN0IHRlbXBsYXRlID0gdGhpcy5jZXJpb3VzU2Nyb2xsSXRlbVRlbXBsYXRlO1xuICAgIGlmICghdGVtcGxhdGUpIHJldHVybiBudWxsO1xuXG4gICAgY29uc3QgaG9zdENvbnRhaW5lciA9IHRoaXMuaG9zdC5uYXRpdmVFbGVtZW50O1xuICAgIGNvbnN0IGhlaWdodCA9IGhvc3RDb250YWluZXIuY2xpZW50SGVpZ2h0IHx8IGhvc3RDb250YWluZXIub2Zmc2V0SGVpZ2h0O1xuICAgIGNvbnN0IGNvbnRlbnRDb250YWluZXIgPSB0aGlzLmhvc3RSZWYuY29udGVudEVsZW1lbnQ7XG5cbiAgICAvLyBUcmFjayB3aGV0aGVyIHRoZSBlbmdpbmUgYXNrZWQgdXMgdG8gYmluZCBhbnkgcm93IHRoaXMgcGFzcy4gUHVyZSBzY3JvbGxcbiAgICAvLyBmcmFtZXMgd2hlcmUgdGhlIHZpc2libGUgcm93IHNldCBkb2Vzbid0IGNoYW5nZSBzdGlsbCBkcml2ZSByZW5kZXIoKSB2aWFcbiAgICAvLyB0aGUgckFGIGNvYWxlc2NlciDigJQgdGhlcmUncyBubyBwb2ludCBpbiB3YWxraW5nIHRoZSBwcnVuZSBtYXAgb3JcbiAgICAvLyBlbWl0dGluZyB0aGUgdmlld3BvcnQgcmFuZ2Ugd2hlbiBub3RoaW5nIHdhcyB0b3VjaGVkLlxuICAgIGxldCByZW5kZXJlckludm9jYXRpb25zID0gMDtcbiAgICBjb25zdCByZW5kZXJlcjogRWxlbWVudFJlbmRlcmVyID0gKGluZGV4LCBlbGVtZW50Q29udGFpbmVyKSA9PiB7XG4gICAgICByZW5kZXJlckludm9jYXRpb25zKys7XG4gICAgICAvLyBSZW5kZXIgZWFjaCByb3cncyBlbWJlZGRlZCB2aWV3IHdpdGggTE9DQUwgY2hhbmdlIGRldGVjdGlvblxuICAgICAgLy8gKGB2aWV3LmRldGVjdENoYW5nZXMoKWAgaW5zaWRlIGByZW5kZXJUZW1wbGF0ZUludG9Db250YWluZXJgKSBzbyB0aGVcbiAgICAgIC8vIGVuZ2luZSBjYW4gbWVhc3VyZSBpdHMgaGVpZ2h0IGR1cmluZyB0aGlzIHBhc3MuIERvIE5PVCB3cmFwIGVhY2ggcm93IGluXG4gICAgICAvLyBpdHMgb3duIGBuZ1pvbmUucnVuYCDigJQgdGhhdCBmaXJlcyBhIGZ1bGwgYEFwcGxpY2F0aW9uUmVmYCB0aWNrICpwZXIgcm93KlxuICAgICAgLy8gKE8obmV3Um93cyDDlyB2aXNpYmxlUm93cykgd29yaywgamFua3kgZHJhZ3MpLiBUaGUgc2luZ2xlIGNvYWxlc2NlZCB0aWNrXG4gICAgICAvLyBmb3IgdGhlIHdob2xlIHBhc3MgaXMgaGFuZGxlZCBieSB0aGUgY2FsbGVyIChgc2NoZWR1bGVSZW5kZXJgKS5cbiAgICAgIHRoaXMucmVuZGVyVGVtcGxhdGVJbnRvQ29udGFpbmVyKHRlbXBsYXRlLCBpbmRleCwgZWxlbWVudENvbnRhaW5lcik7XG4gICAgfTtcblxuICAgIGNvbnN0IHJhbmdlID0gdGhpcy5ob3N0UmVmLnNjcm9sbGVyLnJlbmRlclZpZXdwb3J0KGhlaWdodCwgY29udGVudENvbnRhaW5lciwgcmVuZGVyZXIpO1xuXG4gICAgaWYgKHJlbmRlcmVySW52b2NhdGlvbnMgPT09IDApIHtcbiAgICAgIC8vIFZpZXdwb3J0IGRpZG4ndCBjaGFuZ2Ug4oCUIHNraXAgdGhlIHBydW5lIHdhbGsgYW5kIHRoZSAocG90ZW50aWFsbHlcbiAgICAgIC8vIHpvbmUtZW50ZXJpbmcpIGVtaXQuXG4gICAgICByZXR1cm4gcmFuZ2U7XG4gICAgfVxuXG4gICAgLy8gRGVzdHJveSB2aWV3cyB3aG9zZSBjb250YWluZXIgdGhlIGVuZ2luZSBubyBsb25nZXIgcmVuZGVycy4gV2l0aG91dCB0aGlzLFxuICAgIC8vIGV2ZXJ5IGNvbnRhaW5lciB0aGUgZW5naW5lIHJlY3ljbGVzIGludG8gaXRzIGVsZW1lbnQgcG9vbCBsZWF2ZXMgaXRzXG4gICAgLy8gZW1iZWRkZWQgdmlldyBhdHRhY2hlZCB0byBBcHBsaWNhdGlvblJlZiBmb3JldmVyIOKAlCBzbyB0aGUgYXR0YWNoZWQtdmlld1xuICAgIC8vIGxpc3QgKGFuZCBldmVyeSBPKG4pIGBkZXRhY2hWaWV3YCkgZ3Jvd3Mgd2l0aG91dCBib3VuZCBhbmQgc2Nyb2xsaW5nIGdldHNcbiAgICAvLyBwcm9ncmVzc2l2ZWx5IHNsb3dlci4gTWlycm9ycyB0aGUgUmVhY3QvVnVlIHdyYXBwZXJzLCB3aGljaCBkcm9wIHJvd3MgdGhhdFxuICAgIC8vIGZhbGwgb3V0IG9mIGBnZXRSZW5kZXJlZEluZGljZXMoKWAuXG4gICAgdGhpcy5wcnVuZURldGFjaGVkVmlld3MoKTtcblxuICAgIC8vIE9ubHkgcmUtZW50ZXIgdGhlIHpvbmUgKGEgZ2xvYmFsIHRpY2spIGlmIHNvbWVvbmUgaXMgYWN0dWFsbHkgbGlzdGVuaW5nLlxuICAgIGlmICh0aGlzLmNlcmlvdXNTY3JvbGxNZWFzdXJlZFZpZXdwb3J0Lm9ic2VydmVkKSB7XG4gICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4gdGhpcy5jZXJpb3VzU2Nyb2xsTWVhc3VyZWRWaWV3cG9ydC5lbWl0KHJhbmdlKSk7XG4gICAgfVxuICAgIHJldHVybiByYW5nZTtcbiAgfVxuXG4gIC8qKiBUZWFyIGRvd24gZW1iZWRkZWQgdmlld3Mgd2hvc2UgY29udGFpbmVyIGlzIG5vIGxvbmdlciBwYXJ0IG9mIHRoZSB2aWV3cG9ydC4gKi9cbiAgcHJpdmF0ZSBwcnVuZURldGFjaGVkVmlld3MoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmhvc3RSZWYgfHwgdGhpcy52aWV3QnlDb250YWluZXIuc2l6ZSA9PT0gMCkgcmV0dXJuO1xuICAgIGNvbnN0IHNjcm9sbGVyID0gdGhpcy5ob3N0UmVmLnNjcm9sbGVyO1xuICAgIGNvbnN0IGFjdGl2ZSA9IG5ldyBTZXQ8SFRNTEVsZW1lbnQ+KCk7XG4gICAgZm9yIChjb25zdCBpbmRleCBvZiBzY3JvbGxlci5nZXRSZW5kZXJlZEluZGljZXMoKSkge1xuICAgICAgY29uc3QgZWwgPSBzY3JvbGxlci5nZXRSZW5kZXJlZEVsZW1lbnQoaW5kZXgpO1xuICAgICAgaWYgKGVsKSBhY3RpdmUuYWRkKGVsKTtcbiAgICB9XG4gICAgZm9yIChjb25zdCBbY29udGFpbmVyLCB2aWV3XSBvZiB0aGlzLnZpZXdCeUNvbnRhaW5lcikge1xuICAgICAgaWYgKCFhY3RpdmUuaGFzKGNvbnRhaW5lcikpIHtcbiAgICAgICAgLy8gRGV0YWNoIERPTSBidXQga2VlcCB0aGUgdmlldyBhbGl2ZSBpbiB0aGUgcG9vbCBmb3IgZnV0dXJlIHJldXNlLlxuICAgICAgICAvLyBEZXN0cm95aW5nICsgcmVjcmVhdGluZyB2aWV3cyBwZXIgc2Nyb2xsIHN0ZXAgZG9taW5hdGVzIGZyYW1lIHRpbWUuXG4gICAgICAgIGZvciAoY29uc3Qgbm9kZSBvZiB2aWV3LnJvb3ROb2Rlcykge1xuICAgICAgICAgIGlmIChub2RlLnBhcmVudE5vZGUpIG5vZGUucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChub2RlKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnZpZXdCeUNvbnRhaW5lci5kZWxldGUoY29udGFpbmVyKTtcbiAgICAgICAgdGhpcy5mcmVlVmlld3MucHVzaCh2aWV3KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKiogQXV0by1yZW5kZXIgY29hbGVzY2VkIHRvIGF0IG1vc3Qgb25jZSBwZXIgYW5pbWF0aW9uIGZyYW1lLiAqL1xuICBwcml2YXRlIHNjaGVkdWxlUmVuZGVyKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnNjaGVkdWxlZFJlbmRlckZyYW1lICE9IG51bGwpIHJldHVybjtcbiAgICB0aGlzLnNjaGVkdWxlZFJlbmRlckZyYW1lID0gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHtcbiAgICAgIHRoaXMuc2NoZWR1bGVkUmVuZGVyRnJhbWUgPSBudWxsO1xuICAgICAgLy8gUnVuIHJlbmRlcigpIE9VVFNJREUgQW5ndWxhcidzIHpvbmUuIEEgZnVsbCBBcHBsaWNhdGlvblJlZi50aWNrKCkgb25cbiAgICAgIC8vIGV2ZXJ5IHNjcm9sbCBmcmFtZSBpcyB0aGUgcHJpbWFyeSBGUFMgYm90dGxlbmVjazogZXZlbiB3aGVuIG5vIHJvd3NcbiAgICAgIC8vIGNoYW5nZSAocHVyZSB0cmFuc2xhdGlvbiksIG5nWm9uZS5ydW4oKSBjYXVzZXMgQW5ndWxhciB0byB3YWxrIHRoZVxuICAgICAgLy8gZW50aXJlIGNvbXBvbmVudCB0cmVlLiBJbnN0ZWFkIHdlIGNhbGwgdmlldy5kZXRlY3RDaGFuZ2VzKCkgbG9jYWxseVxuICAgICAgLy8gaW5zaWRlIHJlbmRlclRlbXBsYXRlSW50b0NvbnRhaW5lciBmb3IgZWFjaCBhZmZlY3RlZCByb3cuIFpvbmUgZW50cnkgaXNcbiAgICAgIC8vIG9ubHkgbmVlZGVkIHdoZW4gY3JlYXRpbmcgYSBicmFuZC1uZXcgZW1iZWRkZWQgdmlldyAodG8gem9uZS1wYXRjaCBpdHNcbiAgICAgIC8vIGV2ZW50IGxpc3RlbmVycykg4oCUIHJlY3ljbGVkIGFuZCBwb29sZWQgdmlld3Mgd2VyZSBhbHJlYWR5IGNyZWF0ZWQgaW5zaWRlXG4gICAgICAvLyB6b25lIGFuZCB0aGVpciBsaXN0ZW5lcnMgcmVtYWluIHpvbmUtYXdhcmUuXG4gICAgICB0aGlzLnJlbmRlcigpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIERpc2NhcmQgYWxsIGNhY2hlZCByb3cgaGVpZ2h0cyBhbmQgcmUtbWVhc3VyZSB0aGUgdmlld3BvcnQuXG4gICAqXG4gICAqIENhbGwgdGhpcyBvbmx5IHdoZW4gdGhlIGhlaWdodHMgb2Ygcm93cyB5b3UndmUgKmFscmVhZHkgcmVuZGVyZWQqIG1heSBoYXZlXG4gICAqIGNoYW5nZWQgd2l0aG91dCB0aGVpciBpbmRpY2VzIGNoYW5naW5nIOKAlCBlLmcuIGEgZ2xvYmFsIGZvbnQvZGVuc2l0eSBjaGFuZ2UsXG4gICAqIG9yIHN3YXBwaW5nIGV2ZXJ5IHJvdyB0byBhIGRpZmZlcmVudCBsYXlvdXQuIFRoaXMgZm9yY2VzIGEgc3luY2hyb25vdXNcbiAgICogcmUtbWVhc3VyZSAob25lIGBvZmZzZXRIZWlnaHRgIHJlYWQgcGVyIHZpc2libGUgcm93KSwgc28gZG8gTk9UIGNhbGwgaXQgb25cbiAgICogcm91dGluZSBlZGl0czogYSBzaW5nbGUgY2VsbCBlZGl0IGtlZXBzIGl0cyByb3cncyBzaXplLCBhbmQgdGhlIGVuZ2luZSdzXG4gICAqIFJlc2l6ZU9ic2VydmVyIHBpY2tzIHVwIGFueSBpbmNpZGVudGFsIHJlc2l6ZSBvbiBpdHMgb3duLlxuICAgKi9cbiAgcmVjYWxjdWxhdGUoKTogTWVhc3VyZWRWaWV3cG9ydFJhbmdlIHwgbnVsbCB7XG4gICAgaWYgKCF0aGlzLmhvc3RSZWYpIHJldHVybiBudWxsO1xuICAgIC8vIERpc2NhcmQgdGhlIGNhY2hlZCBoZWlnaHRzLCB0aGVuIHJlLXJlbmRlci4gVGhlIGVuZ2luZSByZS1tZWFzdXJlcyBhbmRcbiAgICAvLyByZS1jYWNoZXMgdGhlIHJlbmRlcmVkIHJvd3MgZHVyaW5nIHRoZSBwYXNzIGFuZCByZWZyZXNoZXMgdGhlIHNjcm9sbFxuICAgIC8vIHBlcmNlbnRhZ2UsIHNvIGFuIGluLXBsYWNlIGhlaWdodCBjaGFuZ2UgKGUuZy4gZXhwYW5kL2NvbGxhcHNlKSBpc1xuICAgIC8vIHJlZmxlY3RlZCBpbiB0aGUgdG90YWwgY29udGVudCBoZWlnaHQgYW5kIHNjcm9sbGJhciBpbW1lZGlhdGVseS5cbiAgICB0aGlzLmhvc3RSZWYuc2Nyb2xsZXIuY2xlYXJBbGxDYWNoZXMoKTtcbiAgICByZXR1cm4gdGhpcy5yZW5kZXIoKTtcbiAgfVxuXG4gIC8qKiBKdW1wIGRpcmVjdGx5IHRvIGFuIGVsZW1lbnQgaW5kZXgsIHRoZW4gcmVuZGVyLiAqL1xuICBqdW1wVG9FbGVtZW50KGluZGV4OiBudW1iZXIpOiBNZWFzdXJlZFZpZXdwb3J0UmFuZ2UgfCBudWxsIHtcbiAgICBpZiAoIXRoaXMuaG9zdFJlZikgcmV0dXJuIG51bGw7XG4gICAgdGhpcy5ob3N0UmVmLnNjcm9sbGVyLmp1bXBUb0VsZW1lbnQoaW5kZXgpO1xuICAgIHJldHVybiB0aGlzLnJlbmRlcigpO1xuICB9XG5cbiAgLyoqIFNjcm9sbCB0byBhIHBlcmNlbnRhZ2UgKDAuLjEwMCksIHRoZW4gcmVuZGVyLiAqL1xuICBzY3JvbGxUb1BlcmNlbnRhZ2UocGVyY2VudGFnZTogbnVtYmVyKTogTWVhc3VyZWRWaWV3cG9ydFJhbmdlIHwgbnVsbCB7XG4gICAgaWYgKCF0aGlzLmhvc3RSZWYpIHJldHVybiBudWxsO1xuICAgIHRoaXMuaG9zdFJlZi5zY3JvbGxlci5oYW5kbGVTY3JvbGxQZXJjZW50YWdlKHBlcmNlbnRhZ2UpO1xuICAgIHJldHVybiB0aGlzLnJlbmRlcigpO1xuICB9XG5cbiAgLyoqIFJlc2V0IHRvIHRoZSB0b3AsIHRoZW4gcmVuZGVyLiAqL1xuICByZXNldCgpOiBNZWFzdXJlZFZpZXdwb3J0UmFuZ2UgfCBudWxsIHtcbiAgICBpZiAoIXRoaXMuaG9zdFJlZikgcmV0dXJuIG51bGw7XG4gICAgdGhpcy5ob3N0UmVmLnNjcm9sbGVyLnJlc2V0KCk7XG4gICAgcmV0dXJuIHRoaXMucmVuZGVyKCk7XG4gIH1cblxuICBwcml2YXRlIHJlY3JlYXRlKCk6IHZvaWQge1xuICAgIHRoaXMudmlld3BvcnRTdWI/LnVuc3Vic2NyaWJlKCk7XG4gICAgdGhpcy52aWV3cG9ydFN1YiA9IG51bGw7XG5cbiAgICB0aGlzLmRlc3Ryb3lBbGxWaWV3cygpO1xuXG4gICAgdGhpcy5ob3N0UmVmPy5kZXN0cm95KCk7XG4gICAgdGhpcy5ob3N0UmVmID0gbnVsbDtcblxuICAgIHRoaXMuZW5zdXJlSW5pdGlhbGl6ZWQoKTtcbiAgfVxuXG4gIHByaXZhdGUgZW5zdXJlSW5pdGlhbGl6ZWQoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaG9zdFJlZikgcmV0dXJuO1xuXG4gICAgY29uc3QgY29udGFpbmVyID0gdGhpcy5ob3N0Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgY29uc3QgdG90YWwgPSBjb2VyY2VUb3RhbEVsZW1lbnRzKHRoaXMuY2VyaW91c1Njcm9sbFRvdGFsRWxlbWVudHMsIHRoaXMuY2VyaW91c1Njcm9sbEl0ZW1zPy5sZW5ndGggPz8gbnVsbCk7XG5cbiAgICB0aGlzLmhvc3RSZWYgPSB0aGlzLmNlcmlvdXMuY3JlYXRlSG9zdChjb250YWluZXIsIHRvdGFsLCB0aGlzLmNlcmlvdXNTY3JvbGxPcHRpb25zLCB0aGlzLm5nWm9uZSwgKCkgPT4ge1xuICAgICAgLy8gQ29hbGVzY2Ugc2Nyb2xsLWRyaXZlbiByZW5kZXJzIHRvIG9uZSBwZXIgZnJhbWUgKHRoZSBuYXRpdmUgc2Nyb2xsYmFyXG4gICAgICAvLyBjYW4gZmlyZSBtYW55IHNjcm9sbCBldmVudHMgYmV0d2VlbiBwYWludHMpLlxuICAgICAgaWYgKHRoaXMuY2VyaW91c1Njcm9sbEF1dG9SZW5kZXIpIHRoaXMuc2NoZWR1bGVSZW5kZXIoKTtcbiAgICB9KTtcblxuICAgIHRoaXMudmlld3BvcnRTdWIgPSB0aGlzLmhvc3RSZWYudmlld3BvcnRDaGFuZ2VzJC5zdWJzY3JpYmUoKGRldGFpbDogQ2VyaW91c1ZpZXdwb3J0Q2hhbmdlRGV0YWlsKSA9PiB7XG4gICAgICAvLyBTa2lwIHRoZSBnbG9iYWwgdGljayB3aGVuIG5vYm9keSBpcyBib3VuZCB0byB0aGUgb3V0cHV0LlxuICAgICAgaWYgKHRoaXMuY2VyaW91c1Njcm9sbFZpZXdwb3J0Q2hhbmdlLm9ic2VydmVkKSB7XG4gICAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB0aGlzLmNlcmlvdXNTY3JvbGxWaWV3cG9ydENoYW5nZS5lbWl0KGRldGFpbCkpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5jZXJpb3VzU2Nyb2xsUmVhZHkuZW1pdCh0aGlzLmhvc3RSZWYuc2Nyb2xsZXIpO1xuXG4gICAgaWYgKHRoaXMuY2VyaW91c1Njcm9sbEF1dG9SZW5kZXIpIHtcbiAgICAgIHF1ZXVlTWljcm90YXNrKCgpID0+IHRoaXMucmVuZGVyKCkpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZ2V0SXRlbUZvckluZGV4KGluZGV4OiBudW1iZXIpOiBUSXRlbSB7XG4gICAgY29uc3QgZ2V0dGVyID0gdGhpcy5jZXJpb3VzU2Nyb2xsR2V0SXRlbTtcbiAgICBpZiAoZ2V0dGVyKSByZXR1cm4gZ2V0dGVyKGluZGV4KTtcblxuICAgIGNvbnN0IGl0ZW1zID0gdGhpcy5jZXJpb3VzU2Nyb2xsSXRlbXM7XG4gICAgaWYgKCFpdGVtcykgcmV0dXJuIHVuZGVmaW5lZCBhcyBUSXRlbTtcblxuICAgIHJldHVybiBpdGVtc1tpbmRleF07XG4gIH1cblxuICBwcml2YXRlIHJlbmRlclRlbXBsYXRlSW50b0NvbnRhaW5lcihcbiAgICB0ZW1wbGF0ZTogVGVtcGxhdGVSZWY8Q2VyaW91c1Njcm9sbEl0ZW1UZW1wbGF0ZUNvbnRleHQ8VEl0ZW0+PixcbiAgICBpbmRleDogbnVtYmVyLFxuICAgIGVsZW1lbnRDb250YWluZXI6IEhUTUxFbGVtZW50XG4gICk6IHZvaWQge1xuICAgIGNvbnN0IHByZXZpb3VzID0gdGhpcy52aWV3QnlDb250YWluZXIuZ2V0KGVsZW1lbnRDb250YWluZXIpO1xuICAgIGlmIChwcmV2aW91cykge1xuICAgICAgLy8gUmVjeWNsZTogdXBkYXRlIHRoZSBib3VuZCBjb250ZXh0IGFuZCBydW4gbG9jYWwgQ0QgaW5zdGVhZCBvZlxuICAgICAgLy8gZGVzdHJveWluZyB0aGUgZW1iZWRkZWQgdmlldyBhbmQgcmVidWlsZGluZyB0aGUgZW50aXJlIHJvdyB0cmVlLlxuICAgICAgY29uc3QgaXRlbSA9IHRoaXMuZ2V0SXRlbUZvckluZGV4KGluZGV4KTtcbiAgICAgIHByZXZpb3VzLmNvbnRleHQuJGltcGxpY2l0ID0gaXRlbTtcbiAgICAgIHByZXZpb3VzLmNvbnRleHQuaXRlbSA9IGl0ZW07XG4gICAgICBwcmV2aW91cy5jb250ZXh0LmluZGV4ID0gaW5kZXg7XG4gICAgICAvLyBUaGUgY29yZSBlbmdpbmUgd2lwZXMgZWxlbWVudENvbnRhaW5lci50ZXh0Q29udGVudCB3aGVuIHJldXNpbmcgaXQgZnJvbVxuICAgICAgLy8gaXRzIHBvb2wsIG9ycGhhbmluZyB0aGUgdmlldydzIHJvb3Qgbm9kZXMuIFJlLWFwcGVuZCB0aGVtIGRlZmVuc2l2ZWx5LlxuICAgICAgaWYgKHByZXZpb3VzLnJvb3ROb2Rlcy5sZW5ndGggJiYgcHJldmlvdXMucm9vdE5vZGVzWzBdLnBhcmVudE5vZGUgIT09IGVsZW1lbnRDb250YWluZXIpIHtcbiAgICAgICAgZm9yIChjb25zdCBub2RlIG9mIHByZXZpb3VzLnJvb3ROb2Rlcykge1xuICAgICAgICAgIGVsZW1lbnRDb250YWluZXIuYXBwZW5kQ2hpbGQobm9kZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHByZXZpb3VzLmRldGVjdENoYW5nZXMoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBUcnkgdG8gcmV1c2UgYSBwb29sZWQgdmlldyBmcm9tIGEgY29udGFpbmVyIHRoYXQgc2Nyb2xsZWQgb3V0IG9mIHZpZXdwb3J0LlxuICAgIGNvbnN0IHBvb2xlZCA9IHRoaXMuZnJlZVZpZXdzLnBvcCgpO1xuICAgIGlmIChwb29sZWQpIHtcbiAgICAgIGNvbnN0IGl0ZW0gPSB0aGlzLmdldEl0ZW1Gb3JJbmRleChpbmRleCk7XG4gICAgICBwb29sZWQuY29udGV4dC4kaW1wbGljaXQgPSBpdGVtO1xuICAgICAgcG9vbGVkLmNvbnRleHQuaXRlbSA9IGl0ZW07XG4gICAgICBwb29sZWQuY29udGV4dC5pbmRleCA9IGluZGV4O1xuICAgICAgZWxlbWVudENvbnRhaW5lci50ZXh0Q29udGVudCA9ICcnO1xuICAgICAgZm9yIChjb25zdCBub2RlIG9mIHBvb2xlZC5yb290Tm9kZXMpIHtcbiAgICAgICAgZWxlbWVudENvbnRhaW5lci5hcHBlbmRDaGlsZChub2RlKTtcbiAgICAgIH1cbiAgICAgIHBvb2xlZC5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICB0aGlzLnZpZXdCeUNvbnRhaW5lci5zZXQoZWxlbWVudENvbnRhaW5lciwgcG9vbGVkKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBObyBwcmlvciB2aWV3IGZvciB0aGlzIGNvbnRhaW5lcjogY3JlYXRlIG9uZS5cbiAgICAvLyBFbnRlciB0aGUgQW5ndWxhciB6b25lIHNvIHRoZSBuZXcgdmlldydzIHRlbXBsYXRlIGV2ZW50IGxpc3RlbmVyc1xuICAgIC8vICgoY2xpY2spLCAoaW5wdXQpLCBldGMuKSBhcmUgem9uZS1wYXRjaGVkLiBUaGlzIHBhdGggcnVucyBhdCBtb3N0XG4gICAgLy8gb25jZSBwZXIgdmlzaWJsZSByb3cgKGFmdGVyIHRoYXQsIHRoZSB2aWV3IGlzIHJlY3ljbGVkIGZyb20gdGhlIHBvb2wpLlxuICAgIGVsZW1lbnRDb250YWluZXIudGV4dENvbnRlbnQgPSAnJztcblxuICAgIGNvbnN0IGl0ZW0gPSB0aGlzLmdldEl0ZW1Gb3JJbmRleChpbmRleCk7XG4gICAgY29uc3QgdmlldyA9IHRoaXMubmdab25lLnJ1bigoKSA9PiB7XG4gICAgICBjb25zdCB2ID0gdGVtcGxhdGUuY3JlYXRlRW1iZWRkZWRWaWV3KHsgJGltcGxpY2l0OiBpdGVtLCBpdGVtLCBpbmRleCB9KTtcbiAgICAgIHRoaXMuYXBwUmVmLmF0dGFjaFZpZXcodik7XG4gICAgICB2LmRldGVjdENoYW5nZXMoKTtcbiAgICAgIHJldHVybiB2O1xuICAgIH0pO1xuXG4gICAgZm9yIChjb25zdCBub2RlIG9mIHZpZXcucm9vdE5vZGVzKSB7XG4gICAgICBlbGVtZW50Q29udGFpbmVyLmFwcGVuZENoaWxkKG5vZGUpO1xuICAgIH1cblxuICAgIHRoaXMudmlld0J5Q29udGFpbmVyLnNldChlbGVtZW50Q29udGFpbmVyLCB2aWV3KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGUgdGhlIGJvdW5kIGl0ZW0vaW5kZXggb24gZXZlcnkgY3VycmVudGx5LXJlbmRlcmVkIHJvdydzIGVtYmVkZGVkIHZpZXdcbiAgICogYW5kIHJ1biBjaGFuZ2UgZGV0ZWN0aW9uLCB3aXRob3V0IHJlY3JlYXRpbmcgdGhlIHZpZXdzLiBVc2VkIHdoZW4gdGhlIGRhdGFcbiAgICogcmVmZXJlbmNlIGNoYW5nZXMgYnV0IHRoZSB2aXNpYmxlIGluZGljZXMgKGFuZCB0aGVpciBoZWlnaHRzKSBkbyBub3QsIHNvIHJvd1xuICAgKiBzdGF0ZSAoZm9jdXMsIHNlbGVjdGlvbiwgb3BlbiBkcm9wZG93bnMpIHN1cnZpdmVzIHRoZSB1cGRhdGUuXG4gICAqL1xuICAvKipcbiAgICogUmUtYmluZCBlYWNoIGN1cnJlbnRseSByZW5kZXJlZCByb3cncyBjb250ZXh0IChmcm9tIHRoZSBjdXJyZW50IGl0ZW1zL2dldHRlcilcbiAgICogYW5kIHJ1biBjaGFuZ2UgZGV0ZWN0aW9uIG9uIGl0cyBlbWJlZGRlZCB2aWV3LiBVc2UgdGhpcyBhZnRlciBtdXRhdGluZyByb3dcbiAgICogc3RhdGUgaW4gcGxhY2UgKGUuZy4gc2VsZWN0aW9uIGZsYWdzKSBvciBjb2x1bW4tbGV2ZWwgc3RhdGUgcmVhZCBieSB0aGUgcm93XG4gICAqIHRlbXBsYXRlLCB3aGVuIHJvdyBpZGVudGl0eSBhbmQgdmlzaWJsZSBpbmRpY2VzIGhhdmUgbm90IGNoYW5nZWQuIENoZWFwXG4gICAqIHJlbGF0aXZlIHRvIGByZW5kZXIoKWAg4oCUIGRvZXMgbm90IGludm9rZSB0aGUgZW5naW5lJ3MgbWVhc3VyZW1lbnQgcGFzcy5cbiAgICovXG4gIHJlZnJlc2hSZW5kZXJlZENvbnRlbnQoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmhvc3RSZWYpIHJldHVybjtcbiAgICBjb25zdCBzY3JvbGxlciA9IHRoaXMuaG9zdFJlZi5zY3JvbGxlcjtcblxuICAgIGZvciAoY29uc3QgaW5kZXggb2Ygc2Nyb2xsZXIuZ2V0UmVuZGVyZWRJbmRpY2VzKCkpIHtcbiAgICAgIGNvbnN0IGNvbnRhaW5lciA9IHNjcm9sbGVyLmdldFJlbmRlcmVkRWxlbWVudChpbmRleCk7XG4gICAgICBpZiAoIWNvbnRhaW5lcikgY29udGludWU7XG5cbiAgICAgIGNvbnN0IHZpZXcgPSB0aGlzLnZpZXdCeUNvbnRhaW5lci5nZXQoY29udGFpbmVyKTtcbiAgICAgIGlmICghdmlldykgY29udGludWU7XG5cbiAgICAgIGNvbnN0IGl0ZW0gPSB0aGlzLmdldEl0ZW1Gb3JJbmRleChpbmRleCk7XG4gICAgICB2aWV3LmNvbnRleHQuJGltcGxpY2l0ID0gaXRlbTtcbiAgICAgIHZpZXcuY29udGV4dC5pdGVtID0gaXRlbTtcbiAgICAgIHZpZXcuY29udGV4dC5pbmRleCA9IGluZGV4O1xuICAgICAgdmlldy5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBkZXN0cm95QWxsVmlld3MoKTogdm9pZCB7XG4gICAgZm9yIChjb25zdCB2aWV3IG9mIHRoaXMudmlld0J5Q29udGFpbmVyLnZhbHVlcygpKSB7XG4gICAgICB0aGlzLmFwcFJlZi5kZXRhY2hWaWV3KHZpZXcpO1xuICAgICAgdmlldy5kZXN0cm95KCk7XG4gICAgfVxuICAgIHRoaXMudmlld0J5Q29udGFpbmVyLmNsZWFyKCk7XG4gICAgZm9yIChjb25zdCB2aWV3IG9mIHRoaXMuZnJlZVZpZXdzKSB7XG4gICAgICB0aGlzLmFwcFJlZi5kZXRhY2hWaWV3KHZpZXcpO1xuICAgICAgdmlldy5kZXN0cm95KCk7XG4gICAgfVxuICAgIHRoaXMuZnJlZVZpZXdzLmxlbmd0aCA9IDA7XG4gIH1cbn1cbiJdfQ==