@angular/core 17.0.0-next.8 → 17.0.0-rc.0
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.
- package/esm2022/src/application_ref.mjs +2 -1
- package/esm2022/src/core_private_export.mjs +4 -3
- package/esm2022/src/core_render3_private_export.mjs +2 -2
- package/esm2022/src/debug/debug_node.mjs +5 -9
- package/esm2022/src/defer/cleanup.mjs +70 -0
- package/esm2022/src/defer/discovery.mjs +47 -0
- package/esm2022/src/defer/dom_triggers.mjs +256 -0
- package/esm2022/src/defer/idle_scheduler.mjs +109 -0
- package/esm2022/src/defer/instructions.mjs +641 -0
- package/esm2022/src/defer/interfaces.mjs +79 -0
- package/esm2022/src/defer/timer_scheduler.mjs +192 -0
- package/esm2022/src/defer/utils.mjs +134 -0
- package/esm2022/src/hydration/api.mjs +1 -2
- package/esm2022/src/hydration/utils.mjs +2 -2
- package/esm2022/src/render/api.mjs +1 -1
- package/esm2022/src/render3/after_render_hooks.mjs +31 -1
- package/esm2022/src/render3/index.mjs +3 -2
- package/esm2022/src/render3/instructions/all.mjs +2 -2
- package/esm2022/src/render3/instructions/control_flow.mjs +25 -15
- package/esm2022/src/render3/interfaces/container.mjs +1 -4
- package/esm2022/src/render3/interfaces/definition.mjs +2 -4
- package/esm2022/src/render3/interfaces/i18n.mjs +1 -4
- package/esm2022/src/render3/interfaces/injector.mjs +1 -4
- package/esm2022/src/render3/interfaces/node.mjs +1 -4
- package/esm2022/src/render3/interfaces/projection.mjs +2 -4
- package/esm2022/src/render3/interfaces/query.mjs +2 -4
- package/esm2022/src/render3/interfaces/renderer.mjs +2 -4
- package/esm2022/src/render3/interfaces/renderer_dom.mjs +2 -4
- package/esm2022/src/render3/interfaces/view.mjs +1 -4
- package/esm2022/src/render3/list_reconciliation.mjs +58 -34
- package/esm2022/src/render3/reactive_lview_consumer.mjs +2 -7
- package/esm2022/src/version.mjs +1 -1
- package/esm2022/testing/src/logger.mjs +3 -3
- package/fesm2022/core.mjs +777 -741
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/primitives/signals.mjs +1 -1
- package/fesm2022/rxjs-interop.mjs +1 -1
- package/fesm2022/testing.mjs +1 -1
- package/index.d.ts +43 -6
- package/package.json +1 -1
- package/primitives/signals/index.d.ts +1 -1
- package/rxjs-interop/index.d.ts +1 -1
- package/schematics/migrations/block-template-entities/bundle.js +413 -247
- package/schematics/migrations/block-template-entities/bundle.js.map +4 -4
- package/schematics/migrations/compiler-options/bundle.js +13 -13
- package/schematics/migrations/transfer-state/bundle.js +13 -13
- package/schematics/ng-generate/control-flow-migration/bundle.js +471 -259
- package/schematics/ng-generate/control-flow-migration/bundle.js.map +4 -4
- package/schematics/ng-generate/standalone-migration/bundle.js +659 -486
- package/schematics/ng-generate/standalone-migration/bundle.js.map +4 -4
- package/testing/index.d.ts +1 -1
- package/esm2022/src/render3/instructions/defer.mjs +0 -1225
- package/esm2022/src/render3/instructions/defer_events.mjs +0 -174
- package/esm2022/src/render3/interfaces/defer.mjs +0 -79
|
@@ -1,1225 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright Google LLC All Rights Reserved.
|
|
4
|
-
*
|
|
5
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
6
|
-
* found in the LICENSE file at https://angular.io/license
|
|
7
|
-
*/
|
|
8
|
-
import { inject, InjectionToken, ɵɵdefineInjectable } from '../../di';
|
|
9
|
-
import { findMatchingDehydratedView } from '../../hydration/views';
|
|
10
|
-
import { populateDehydratedViewsInLContainer } from '../../linker/view_container_ref';
|
|
11
|
-
import { arrayInsert2, arraySplice } from '../../util/array_utils';
|
|
12
|
-
import { assertDefined, assertElement, assertEqual, throwError } from '../../util/assert';
|
|
13
|
-
import { NgZone } from '../../zone';
|
|
14
|
-
import { afterRender } from '../after_render_hooks';
|
|
15
|
-
import { assertIndexInDeclRange, assertLContainer, assertLView, assertTNodeForLView } from '../assert';
|
|
16
|
-
import { bindingUpdated } from '../bindings';
|
|
17
|
-
import { getComponentDef, getDirectiveDef, getPipeDef } from '../definition';
|
|
18
|
-
import { CONTAINER_HEADER_OFFSET } from '../interfaces/container';
|
|
19
|
-
import { DEFER_BLOCK_STATE, DeferBlockBehavior, DeferBlockInternalState, DeferBlockState, DeferDependenciesLoadingState, LOADING_AFTER_CLEANUP_FN, LOADING_AFTER_SLOT, MINIMUM_SLOT, NEXT_DEFER_BLOCK_STATE, STATE_IS_FROZEN_UNTIL } from '../interfaces/defer';
|
|
20
|
-
import { isDestroyed, isLContainer, isLView } from '../interfaces/type_checks';
|
|
21
|
-
import { FLAGS, HEADER_OFFSET, INJECTOR, PARENT, TVIEW } from '../interfaces/view';
|
|
22
|
-
import { getCurrentTNode, getLView, getSelectedTNode, getTView, nextBindingIndex } from '../state';
|
|
23
|
-
import { isPlatformBrowser } from '../util/misc_utils';
|
|
24
|
-
import { getConstant, getNativeByIndex, getTNode, removeLViewOnDestroy, storeLViewOnDestroy, walkUpViews } from '../util/view_utils';
|
|
25
|
-
import { addLViewToLContainer, createAndRenderEmbeddedLView, removeLViewFromLContainer, shouldAddViewToDom } from '../view_manipulation';
|
|
26
|
-
import { onHover, onInteraction, onViewport } from './defer_events';
|
|
27
|
-
import { markViewDirty } from './mark_view_dirty';
|
|
28
|
-
import { ɵɵtemplate } from './template';
|
|
29
|
-
/**
|
|
30
|
-
* Returns whether defer blocks should be triggered.
|
|
31
|
-
*
|
|
32
|
-
* Currently, defer blocks are not triggered on the server,
|
|
33
|
-
* only placeholder content is rendered (if provided).
|
|
34
|
-
*/
|
|
35
|
-
function shouldTriggerDeferBlock(injector) {
|
|
36
|
-
const config = injector.get(DEFER_BLOCK_CONFIG, null, { optional: true });
|
|
37
|
-
if (config?.behavior === DeferBlockBehavior.Manual) {
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
return isPlatformBrowser(injector);
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Reference to the timer-based scheduler implementation of defer block state
|
|
44
|
-
* rendering method. It's used to make timer-based scheduling tree-shakable.
|
|
45
|
-
* If `minimum` or `after` parameters are used, compiler generates an extra
|
|
46
|
-
* argument for the `ɵɵdefer` instruction, which references a timer-based
|
|
47
|
-
* implementation.
|
|
48
|
-
*/
|
|
49
|
-
let applyDeferBlockStateWithSchedulingImpl = null;
|
|
50
|
-
/**
|
|
51
|
-
* Enables timer-related scheduling if `after` or `minimum` parameters are setup
|
|
52
|
-
* on the `@loading` or `@placeholder` blocks.
|
|
53
|
-
*/
|
|
54
|
-
export function ɵɵdeferEnableTimerScheduling(tView, tDetails, placeholderConfigIndex, loadingConfigIndex) {
|
|
55
|
-
const tViewConsts = tView.consts;
|
|
56
|
-
if (placeholderConfigIndex != null) {
|
|
57
|
-
tDetails.placeholderBlockConfig =
|
|
58
|
-
getConstant(tViewConsts, placeholderConfigIndex);
|
|
59
|
-
}
|
|
60
|
-
if (loadingConfigIndex != null) {
|
|
61
|
-
tDetails.loadingBlockConfig =
|
|
62
|
-
getConstant(tViewConsts, loadingConfigIndex);
|
|
63
|
-
}
|
|
64
|
-
// Enable implementation that supports timer-based scheduling.
|
|
65
|
-
if (applyDeferBlockStateWithSchedulingImpl === null) {
|
|
66
|
-
applyDeferBlockStateWithSchedulingImpl = applyDeferBlockStateWithScheduling;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Creates runtime data structures for defer blocks.
|
|
71
|
-
*
|
|
72
|
-
* @param index Index of the `defer` instruction.
|
|
73
|
-
* @param primaryTmplIndex Index of the template with the primary block content.
|
|
74
|
-
* @param dependencyResolverFn Function that contains dependencies for this defer block.
|
|
75
|
-
* @param loadingTmplIndex Index of the template with the loading block content.
|
|
76
|
-
* @param placeholderTmplIndex Index of the template with the placeholder block content.
|
|
77
|
-
* @param errorTmplIndex Index of the template with the error block content.
|
|
78
|
-
* @param loadingConfigIndex Index in the constants array of the configuration of the loading.
|
|
79
|
-
* block.
|
|
80
|
-
* @param placeholderConfigIndex Index in the constants array of the configuration of the
|
|
81
|
-
* placeholder block.
|
|
82
|
-
* @param enableTimerScheduling Function that enables timer-related scheduling if `after`
|
|
83
|
-
* or `minimum` parameters are setup on the `@loading` or `@placeholder` blocks.
|
|
84
|
-
*
|
|
85
|
-
* @codeGenApi
|
|
86
|
-
*/
|
|
87
|
-
export function ɵɵdefer(index, primaryTmplIndex, dependencyResolverFn, loadingTmplIndex, placeholderTmplIndex, errorTmplIndex, loadingConfigIndex, placeholderConfigIndex, enableTimerScheduling) {
|
|
88
|
-
const lView = getLView();
|
|
89
|
-
const tView = getTView();
|
|
90
|
-
const adjustedIndex = index + HEADER_OFFSET;
|
|
91
|
-
ɵɵtemplate(index, null, 0, 0);
|
|
92
|
-
if (tView.firstCreatePass) {
|
|
93
|
-
const tDetails = {
|
|
94
|
-
primaryTmplIndex,
|
|
95
|
-
loadingTmplIndex: loadingTmplIndex ?? null,
|
|
96
|
-
placeholderTmplIndex: placeholderTmplIndex ?? null,
|
|
97
|
-
errorTmplIndex: errorTmplIndex ?? null,
|
|
98
|
-
placeholderBlockConfig: null,
|
|
99
|
-
loadingBlockConfig: null,
|
|
100
|
-
dependencyResolverFn: dependencyResolverFn ?? null,
|
|
101
|
-
loadingState: DeferDependenciesLoadingState.NOT_STARTED,
|
|
102
|
-
loadingPromise: null,
|
|
103
|
-
};
|
|
104
|
-
enableTimerScheduling?.(tView, tDetails, placeholderConfigIndex, loadingConfigIndex);
|
|
105
|
-
setTDeferBlockDetails(tView, adjustedIndex, tDetails);
|
|
106
|
-
}
|
|
107
|
-
const tNode = getCurrentTNode();
|
|
108
|
-
const lContainer = lView[adjustedIndex];
|
|
109
|
-
// If hydration is enabled, looks up dehydrated views in the DOM
|
|
110
|
-
// using hydration annotation info and stores those views on LContainer.
|
|
111
|
-
// In client-only mode, this function is a noop.
|
|
112
|
-
populateDehydratedViewsInLContainer(lContainer, tNode, lView);
|
|
113
|
-
// Init instance-specific defer details and store it.
|
|
114
|
-
const lDetails = [
|
|
115
|
-
null,
|
|
116
|
-
DeferBlockInternalState.Initial,
|
|
117
|
-
null,
|
|
118
|
-
null // LOADING_AFTER_CLEANUP_FN
|
|
119
|
-
];
|
|
120
|
-
setLDeferBlockDetails(lView, adjustedIndex, lDetails);
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Loads defer block dependencies when a trigger value becomes truthy.
|
|
124
|
-
* @codeGenApi
|
|
125
|
-
*/
|
|
126
|
-
export function ɵɵdeferWhen(rawValue) {
|
|
127
|
-
const lView = getLView();
|
|
128
|
-
const bindingIndex = nextBindingIndex();
|
|
129
|
-
if (bindingUpdated(lView, bindingIndex, rawValue)) {
|
|
130
|
-
const value = Boolean(rawValue); // handle truthy or falsy values
|
|
131
|
-
const tNode = getSelectedTNode();
|
|
132
|
-
const lDetails = getLDeferBlockDetails(lView, tNode);
|
|
133
|
-
const renderedState = lDetails[DEFER_BLOCK_STATE];
|
|
134
|
-
if (value === false && renderedState === DeferBlockInternalState.Initial) {
|
|
135
|
-
// If nothing is rendered yet, render a placeholder (if defined).
|
|
136
|
-
renderPlaceholder(lView, tNode);
|
|
137
|
-
}
|
|
138
|
-
else if (value === true &&
|
|
139
|
-
(renderedState === DeferBlockInternalState.Initial ||
|
|
140
|
-
renderedState === DeferBlockState.Placeholder)) {
|
|
141
|
-
// The `when` condition has changed to `true`, trigger defer block loading
|
|
142
|
-
// if the block is either in initial (nothing is rendered) or a placeholder
|
|
143
|
-
// state.
|
|
144
|
-
triggerDeferBlock(lView, tNode);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Prefetches the deferred content when a value becomes truthy.
|
|
150
|
-
* @codeGenApi
|
|
151
|
-
*/
|
|
152
|
-
export function ɵɵdeferPrefetchWhen(rawValue) {
|
|
153
|
-
const lView = getLView();
|
|
154
|
-
const bindingIndex = nextBindingIndex();
|
|
155
|
-
if (bindingUpdated(lView, bindingIndex, rawValue)) {
|
|
156
|
-
const value = Boolean(rawValue); // handle truthy or falsy values
|
|
157
|
-
const tView = lView[TVIEW];
|
|
158
|
-
const tNode = getSelectedTNode();
|
|
159
|
-
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
160
|
-
if (value === true && tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
|
|
161
|
-
// If loading has not been started yet, trigger it now.
|
|
162
|
-
triggerPrefetching(tDetails, lView);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Sets up logic to handle the `on idle` deferred trigger.
|
|
168
|
-
* @codeGenApi
|
|
169
|
-
*/
|
|
170
|
-
export function ɵɵdeferOnIdle() {
|
|
171
|
-
scheduleDelayedTrigger(onIdle);
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Sets up logic to handle the `prefetch on idle` deferred trigger.
|
|
175
|
-
* @codeGenApi
|
|
176
|
-
*/
|
|
177
|
-
export function ɵɵdeferPrefetchOnIdle() {
|
|
178
|
-
scheduleDelayedPrefetching(onIdle, 0 /* DeferBlockTriggers.OnIdle */);
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* Sets up logic to handle the `on immediate` deferred trigger.
|
|
182
|
-
* @codeGenApi
|
|
183
|
-
*/
|
|
184
|
-
export function ɵɵdeferOnImmediate() {
|
|
185
|
-
const lView = getLView();
|
|
186
|
-
const tNode = getCurrentTNode();
|
|
187
|
-
const tView = lView[TVIEW];
|
|
188
|
-
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
189
|
-
// Render placeholder block only if loading template is not present
|
|
190
|
-
// to avoid content flickering, since it would be immediately replaced
|
|
191
|
-
// by the loading block.
|
|
192
|
-
if (tDetails.loadingTmplIndex === null) {
|
|
193
|
-
renderPlaceholder(lView, tNode);
|
|
194
|
-
}
|
|
195
|
-
triggerDeferBlock(lView, tNode);
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Sets up logic to handle the `prefetch on immediate` deferred trigger.
|
|
199
|
-
* @codeGenApi
|
|
200
|
-
*/
|
|
201
|
-
export function ɵɵdeferPrefetchOnImmediate() {
|
|
202
|
-
const lView = getLView();
|
|
203
|
-
const tNode = getCurrentTNode();
|
|
204
|
-
const tView = lView[TVIEW];
|
|
205
|
-
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
206
|
-
if (tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
|
|
207
|
-
triggerResourceLoading(tDetails, lView);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Creates runtime data structures for the `on timer` deferred trigger.
|
|
212
|
-
* @param delay Amount of time to wait before loading the content.
|
|
213
|
-
* @codeGenApi
|
|
214
|
-
*/
|
|
215
|
-
export function ɵɵdeferOnTimer(delay) {
|
|
216
|
-
scheduleDelayedTrigger(onTimer(delay));
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Creates runtime data structures for the `prefetch on timer` deferred trigger.
|
|
220
|
-
* @param delay Amount of time to wait before prefetching the content.
|
|
221
|
-
* @codeGenApi
|
|
222
|
-
*/
|
|
223
|
-
export function ɵɵdeferPrefetchOnTimer(delay) {
|
|
224
|
-
scheduleDelayedPrefetching(onTimer(delay), 1 /* DeferBlockTriggers.OnTimer */);
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Creates runtime data structures for the `on hover` deferred trigger.
|
|
228
|
-
* @param triggerIndex Index at which to find the trigger element.
|
|
229
|
-
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
|
|
230
|
-
* @codeGenApi
|
|
231
|
-
*/
|
|
232
|
-
export function ɵɵdeferOnHover(triggerIndex, walkUpTimes) {
|
|
233
|
-
const lView = getLView();
|
|
234
|
-
const tNode = getCurrentTNode();
|
|
235
|
-
renderPlaceholder(lView, tNode);
|
|
236
|
-
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onHover, () => triggerDeferBlock(lView, tNode));
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* Creates runtime data structures for the `prefetch on hover` deferred trigger.
|
|
240
|
-
* @param triggerIndex Index at which to find the trigger element.
|
|
241
|
-
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
|
|
242
|
-
* @codeGenApi
|
|
243
|
-
*/
|
|
244
|
-
export function ɵɵdeferPrefetchOnHover(triggerIndex, walkUpTimes) {
|
|
245
|
-
const lView = getLView();
|
|
246
|
-
const tNode = getCurrentTNode();
|
|
247
|
-
const tView = lView[TVIEW];
|
|
248
|
-
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
249
|
-
if (tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
|
|
250
|
-
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onHover, () => triggerPrefetching(tDetails, lView));
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Creates runtime data structures for the `on interaction` deferred trigger.
|
|
255
|
-
* @param triggerIndex Index at which to find the trigger element.
|
|
256
|
-
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
|
|
257
|
-
* @codeGenApi
|
|
258
|
-
*/
|
|
259
|
-
export function ɵɵdeferOnInteraction(triggerIndex, walkUpTimes) {
|
|
260
|
-
const lView = getLView();
|
|
261
|
-
const tNode = getCurrentTNode();
|
|
262
|
-
renderPlaceholder(lView, tNode);
|
|
263
|
-
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onInteraction, () => triggerDeferBlock(lView, tNode));
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Creates runtime data structures for the `prefetch on interaction` deferred trigger.
|
|
267
|
-
* @param triggerIndex Index at which to find the trigger element.
|
|
268
|
-
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
|
|
269
|
-
* @codeGenApi
|
|
270
|
-
*/
|
|
271
|
-
export function ɵɵdeferPrefetchOnInteraction(triggerIndex, walkUpTimes) {
|
|
272
|
-
const lView = getLView();
|
|
273
|
-
const tNode = getCurrentTNode();
|
|
274
|
-
const tView = lView[TVIEW];
|
|
275
|
-
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
276
|
-
if (tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
|
|
277
|
-
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onInteraction, () => triggerPrefetching(tDetails, lView));
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* Creates runtime data structures for the `on viewport` deferred trigger.
|
|
282
|
-
* @param triggerIndex Index at which to find the trigger element.
|
|
283
|
-
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
|
|
284
|
-
* @codeGenApi
|
|
285
|
-
*/
|
|
286
|
-
export function ɵɵdeferOnViewport(triggerIndex, walkUpTimes) {
|
|
287
|
-
const lView = getLView();
|
|
288
|
-
const tNode = getCurrentTNode();
|
|
289
|
-
renderPlaceholder(lView, tNode);
|
|
290
|
-
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onViewport, () => triggerDeferBlock(lView, tNode));
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* Creates runtime data structures for the `prefetch on viewport` deferred trigger.
|
|
294
|
-
* @param triggerIndex Index at which to find the trigger element.
|
|
295
|
-
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
|
|
296
|
-
* @codeGenApi
|
|
297
|
-
*/
|
|
298
|
-
export function ɵɵdeferPrefetchOnViewport(triggerIndex, walkUpTimes) {
|
|
299
|
-
const lView = getLView();
|
|
300
|
-
const tNode = getCurrentTNode();
|
|
301
|
-
const tView = lView[TVIEW];
|
|
302
|
-
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
303
|
-
if (tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
|
|
304
|
-
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onViewport, () => triggerPrefetching(tDetails, lView));
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
/********** Helper functions **********/
|
|
308
|
-
/**
|
|
309
|
-
* Schedules triggering of a defer block for `on idle` and `on timer` conditions.
|
|
310
|
-
*/
|
|
311
|
-
function scheduleDelayedTrigger(scheduleFn) {
|
|
312
|
-
const lView = getLView();
|
|
313
|
-
const tNode = getCurrentTNode();
|
|
314
|
-
renderPlaceholder(lView, tNode);
|
|
315
|
-
scheduleFn(() => triggerDeferBlock(lView, tNode), lView, true /* withLViewCleanup */);
|
|
316
|
-
}
|
|
317
|
-
/**
|
|
318
|
-
* Schedules prefetching for `on idle` and `on timer` triggers.
|
|
319
|
-
*
|
|
320
|
-
* @param scheduleFn A function that does the scheduling.
|
|
321
|
-
* @param trigger A trigger that initiated scheduling.
|
|
322
|
-
*/
|
|
323
|
-
function scheduleDelayedPrefetching(scheduleFn, trigger) {
|
|
324
|
-
const lView = getLView();
|
|
325
|
-
const tNode = getCurrentTNode();
|
|
326
|
-
const tView = lView[TVIEW];
|
|
327
|
-
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
328
|
-
if (tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
|
|
329
|
-
// Prevent scheduling more than one prefetch init call
|
|
330
|
-
// for each defer block. For this reason we use only a trigger
|
|
331
|
-
// identifier in a key, so all instances would use the same key.
|
|
332
|
-
const key = String(trigger);
|
|
333
|
-
const injector = lView[INJECTOR];
|
|
334
|
-
const manager = injector.get(DeferBlockCleanupManager);
|
|
335
|
-
if (!manager.has(tDetails, key)) {
|
|
336
|
-
// In case of prefetching, we intentionally avoid cancelling resource loading if
|
|
337
|
-
// an underlying LView get destroyed (thus passing `null` as a second argument),
|
|
338
|
-
// because there might be other LViews (that represent embedded views) that
|
|
339
|
-
// depend on resource loading.
|
|
340
|
-
const prefetch = () => triggerPrefetching(tDetails, lView);
|
|
341
|
-
const cleanupFn = scheduleFn(prefetch, lView, false /* withLViewCleanup */);
|
|
342
|
-
registerTDetailsCleanup(injector, tDetails, key, cleanupFn);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Helper function to get the LView in which a deferred block's trigger is rendered.
|
|
348
|
-
* @param deferredHostLView LView in which the deferred block is defined.
|
|
349
|
-
* @param deferredTNode TNode defining the deferred block.
|
|
350
|
-
* @param walkUpTimes Number of times to go up in the view hierarchy to find the trigger's view.
|
|
351
|
-
* A negative value means that the trigger is inside the block's placeholder, while an undefined
|
|
352
|
-
* value means that the trigger is in the same LView as the deferred block.
|
|
353
|
-
*/
|
|
354
|
-
function getTriggerLView(deferredHostLView, deferredTNode, walkUpTimes) {
|
|
355
|
-
// The trigger is in the same view, we don't need to traverse.
|
|
356
|
-
if (walkUpTimes == null) {
|
|
357
|
-
return deferredHostLView;
|
|
358
|
-
}
|
|
359
|
-
// A positive value or zero means that the trigger is in a parent view.
|
|
360
|
-
if (walkUpTimes >= 0) {
|
|
361
|
-
return walkUpViews(walkUpTimes, deferredHostLView);
|
|
362
|
-
}
|
|
363
|
-
// If the value is negative, it means that the trigger is inside the placeholder.
|
|
364
|
-
const deferredContainer = deferredHostLView[deferredTNode.index];
|
|
365
|
-
ngDevMode && assertLContainer(deferredContainer);
|
|
366
|
-
const triggerLView = deferredContainer[CONTAINER_HEADER_OFFSET] ?? null;
|
|
367
|
-
// We need to null check, because the placeholder might not have been rendered yet.
|
|
368
|
-
if (ngDevMode && triggerLView !== null) {
|
|
369
|
-
const lDetails = getLDeferBlockDetails(deferredHostLView, deferredTNode);
|
|
370
|
-
const renderedState = lDetails[DEFER_BLOCK_STATE];
|
|
371
|
-
assertEqual(renderedState, DeferBlockState.Placeholder, 'Expected a placeholder to be rendered in this defer block.');
|
|
372
|
-
assertLView(triggerLView);
|
|
373
|
-
}
|
|
374
|
-
return triggerLView;
|
|
375
|
-
}
|
|
376
|
-
/**
|
|
377
|
-
* Gets the element that a deferred block's trigger is pointing to.
|
|
378
|
-
* @param triggerLView LView in which the trigger is defined.
|
|
379
|
-
* @param triggerIndex Index at which the trigger element should've been rendered.
|
|
380
|
-
*/
|
|
381
|
-
function getTriggerElement(triggerLView, triggerIndex) {
|
|
382
|
-
const element = getNativeByIndex(HEADER_OFFSET + triggerIndex, triggerLView);
|
|
383
|
-
ngDevMode && assertElement(element);
|
|
384
|
-
return element;
|
|
385
|
-
}
|
|
386
|
-
/**
|
|
387
|
-
* Registers a DOM-node based trigger.
|
|
388
|
-
* @param initialLView LView in which the defer block is rendered.
|
|
389
|
-
* @param tNode TNode representing the defer block.
|
|
390
|
-
* @param triggerIndex Index at which to find the trigger element.
|
|
391
|
-
* @param walkUpTimes Number of times to go up/down in the view hierarchy to find the trigger.
|
|
392
|
-
* @param registerFn Function that will register the DOM events.
|
|
393
|
-
* @param callback Callback to be invoked when the trigger receives the event that should render
|
|
394
|
-
* the deferred block.
|
|
395
|
-
*/
|
|
396
|
-
function registerDomTrigger(initialLView, tNode, triggerIndex, walkUpTimes, registerFn, callback) {
|
|
397
|
-
const injector = initialLView[INJECTOR];
|
|
398
|
-
// Assumption: the `afterRender` reference should be destroyed
|
|
399
|
-
// automatically so we don't need to keep track of it.
|
|
400
|
-
const afterRenderRef = afterRender(() => {
|
|
401
|
-
const lDetails = getLDeferBlockDetails(initialLView, tNode);
|
|
402
|
-
const renderedState = lDetails[DEFER_BLOCK_STATE];
|
|
403
|
-
// If the block was loaded before the trigger was resolved, we don't need to do anything.
|
|
404
|
-
if (renderedState !== DeferBlockInternalState.Initial &&
|
|
405
|
-
renderedState !== DeferBlockState.Placeholder) {
|
|
406
|
-
afterRenderRef.destroy();
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
const triggerLView = getTriggerLView(initialLView, tNode, walkUpTimes);
|
|
410
|
-
// Keep polling until we resolve the trigger's LView.
|
|
411
|
-
// `afterRender` should stop automatically if the view is destroyed.
|
|
412
|
-
if (!triggerLView) {
|
|
413
|
-
return;
|
|
414
|
-
}
|
|
415
|
-
// It's possible that the trigger's view was destroyed before we resolved the trigger element.
|
|
416
|
-
if (triggerLView[FLAGS] & 256 /* LViewFlags.Destroyed */) {
|
|
417
|
-
afterRenderRef.destroy();
|
|
418
|
-
return;
|
|
419
|
-
}
|
|
420
|
-
// TODO: add integration with `DeferBlockCleanupManager`.
|
|
421
|
-
const element = getTriggerElement(triggerLView, triggerIndex);
|
|
422
|
-
const cleanup = registerFn(element, () => {
|
|
423
|
-
callback();
|
|
424
|
-
removeLViewOnDestroy(triggerLView, cleanup);
|
|
425
|
-
if (initialLView !== triggerLView) {
|
|
426
|
-
removeLViewOnDestroy(initialLView, cleanup);
|
|
427
|
-
}
|
|
428
|
-
cleanup();
|
|
429
|
-
}, injector);
|
|
430
|
-
afterRenderRef.destroy();
|
|
431
|
-
storeLViewOnDestroy(triggerLView, cleanup);
|
|
432
|
-
// Since the trigger and deferred block might be in different
|
|
433
|
-
// views, we have to register the callback in both locations.
|
|
434
|
-
if (initialLView !== triggerLView) {
|
|
435
|
-
storeLViewOnDestroy(initialLView, cleanup);
|
|
436
|
-
}
|
|
437
|
-
}, { injector });
|
|
438
|
-
}
|
|
439
|
-
/**
|
|
440
|
-
* Helper function to schedule a callback to be invoked when a browser becomes idle.
|
|
441
|
-
*
|
|
442
|
-
* @param callback A function to be invoked when a browser becomes idle.
|
|
443
|
-
* @param lView LView that hosts an instance of a defer block.
|
|
444
|
-
* @param withLViewCleanup A flag that indicates whether a scheduled callback
|
|
445
|
-
* should be cancelled in case an LView is destroyed before a callback
|
|
446
|
-
* was invoked.
|
|
447
|
-
*/
|
|
448
|
-
function onIdle(callback, lView, withLViewCleanup) {
|
|
449
|
-
const injector = lView[INJECTOR];
|
|
450
|
-
const scheduler = injector.get(OnIdleScheduler);
|
|
451
|
-
const cleanupFn = () => scheduler.remove(callback);
|
|
452
|
-
const wrappedCallback = withLViewCleanup ? wrapWithLViewCleanup(callback, lView, cleanupFn) : callback;
|
|
453
|
-
scheduler.add(wrappedCallback);
|
|
454
|
-
return cleanupFn;
|
|
455
|
-
}
|
|
456
|
-
/**
|
|
457
|
-
* Returns a function that captures a provided delay.
|
|
458
|
-
* Invoking the returned function schedules a trigger.
|
|
459
|
-
*/
|
|
460
|
-
function onTimer(delay) {
|
|
461
|
-
return (callback, lView, withLViewCleanup) => scheduleTimerTrigger(delay, callback, lView, withLViewCleanup);
|
|
462
|
-
}
|
|
463
|
-
/**
|
|
464
|
-
* Schedules a callback to be invoked after a given timeout.
|
|
465
|
-
*
|
|
466
|
-
* @param delay A number of ms to wait until firing a callback.
|
|
467
|
-
* @param callback A function to be invoked after a timeout.
|
|
468
|
-
* @param lView LView that hosts an instance of a defer block.
|
|
469
|
-
* @param withLViewCleanup A flag that indicates whether a scheduled callback
|
|
470
|
-
* should be cancelled in case an LView is destroyed before a callback
|
|
471
|
-
* was invoked.
|
|
472
|
-
*/
|
|
473
|
-
function scheduleTimerTrigger(delay, callback, lView, withLViewCleanup) {
|
|
474
|
-
const injector = lView[INJECTOR];
|
|
475
|
-
const scheduler = injector.get(TimerScheduler);
|
|
476
|
-
const cleanupFn = () => scheduler.remove(callback);
|
|
477
|
-
const wrappedCallback = withLViewCleanup ? wrapWithLViewCleanup(callback, lView, cleanupFn) : callback;
|
|
478
|
-
scheduler.add(delay, wrappedCallback);
|
|
479
|
-
return cleanupFn;
|
|
480
|
-
}
|
|
481
|
-
/**
|
|
482
|
-
* Wraps a given callback into a logic that registers a cleanup function
|
|
483
|
-
* in the LView cleanup slot, to be invoked when an LView is destroyed.
|
|
484
|
-
*/
|
|
485
|
-
function wrapWithLViewCleanup(callback, lView, cleanup) {
|
|
486
|
-
const wrappedCallback = () => {
|
|
487
|
-
callback();
|
|
488
|
-
removeLViewOnDestroy(lView, cleanup);
|
|
489
|
-
};
|
|
490
|
-
storeLViewOnDestroy(lView, cleanup);
|
|
491
|
-
return wrappedCallback;
|
|
492
|
-
}
|
|
493
|
-
/**
|
|
494
|
-
* Calculates a data slot index for defer block info (either static or
|
|
495
|
-
* instance-specific), given an index of a defer instruction.
|
|
496
|
-
*/
|
|
497
|
-
function getDeferBlockDataIndex(deferBlockIndex) {
|
|
498
|
-
// Instance state is located at the *next* position
|
|
499
|
-
// after the defer block slot in an LView or TView.data.
|
|
500
|
-
return deferBlockIndex + 1;
|
|
501
|
-
}
|
|
502
|
-
/** Retrieves a defer block state from an LView, given a TNode that represents a block. */
|
|
503
|
-
function getLDeferBlockDetails(lView, tNode) {
|
|
504
|
-
const tView = lView[TVIEW];
|
|
505
|
-
const slotIndex = getDeferBlockDataIndex(tNode.index);
|
|
506
|
-
ngDevMode && assertIndexInDeclRange(tView, slotIndex);
|
|
507
|
-
return lView[slotIndex];
|
|
508
|
-
}
|
|
509
|
-
/** Stores a defer block instance state in LView. */
|
|
510
|
-
function setLDeferBlockDetails(lView, deferBlockIndex, lDetails) {
|
|
511
|
-
const tView = lView[TVIEW];
|
|
512
|
-
const slotIndex = getDeferBlockDataIndex(deferBlockIndex);
|
|
513
|
-
ngDevMode && assertIndexInDeclRange(tView, slotIndex);
|
|
514
|
-
lView[slotIndex] = lDetails;
|
|
515
|
-
}
|
|
516
|
-
/** Retrieves static info about a defer block, given a TView and a TNode that represents a block. */
|
|
517
|
-
function getTDeferBlockDetails(tView, tNode) {
|
|
518
|
-
const slotIndex = getDeferBlockDataIndex(tNode.index);
|
|
519
|
-
ngDevMode && assertIndexInDeclRange(tView, slotIndex);
|
|
520
|
-
return tView.data[slotIndex];
|
|
521
|
-
}
|
|
522
|
-
/** Stores a defer block static info in `TView.data`. */
|
|
523
|
-
function setTDeferBlockDetails(tView, deferBlockIndex, deferBlockConfig) {
|
|
524
|
-
const slotIndex = getDeferBlockDataIndex(deferBlockIndex);
|
|
525
|
-
ngDevMode && assertIndexInDeclRange(tView, slotIndex);
|
|
526
|
-
tView.data[slotIndex] = deferBlockConfig;
|
|
527
|
-
}
|
|
528
|
-
function getTemplateIndexForState(newState, hostLView, tNode) {
|
|
529
|
-
const tView = hostLView[TVIEW];
|
|
530
|
-
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
531
|
-
switch (newState) {
|
|
532
|
-
case DeferBlockState.Complete:
|
|
533
|
-
return tDetails.primaryTmplIndex;
|
|
534
|
-
case DeferBlockState.Loading:
|
|
535
|
-
return tDetails.loadingTmplIndex;
|
|
536
|
-
case DeferBlockState.Error:
|
|
537
|
-
return tDetails.errorTmplIndex;
|
|
538
|
-
case DeferBlockState.Placeholder:
|
|
539
|
-
return tDetails.placeholderTmplIndex;
|
|
540
|
-
default:
|
|
541
|
-
ngDevMode && throwError(`Unexpected defer block state: ${newState}`);
|
|
542
|
-
return null;
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
/**
|
|
546
|
-
* Returns a minimum amount of time that a given state should be rendered for,
|
|
547
|
-
* taking into account `minimum` parameter value. If the `minimum` value is
|
|
548
|
-
* not specified - returns `null`.
|
|
549
|
-
*/
|
|
550
|
-
function getMinimumDurationForState(tDetails, currentState) {
|
|
551
|
-
if (currentState === DeferBlockState.Placeholder) {
|
|
552
|
-
return tDetails.placeholderBlockConfig?.[MINIMUM_SLOT] ?? null;
|
|
553
|
-
}
|
|
554
|
-
else if (currentState === DeferBlockState.Loading) {
|
|
555
|
-
return tDetails.loadingBlockConfig?.[MINIMUM_SLOT] ?? null;
|
|
556
|
-
}
|
|
557
|
-
return null;
|
|
558
|
-
}
|
|
559
|
-
/** Retrieves the value of the `after` parameter on the @loading block. */
|
|
560
|
-
function getLoadingBlockAfter(tDetails) {
|
|
561
|
-
return tDetails.loadingBlockConfig?.[LOADING_AFTER_SLOT] ?? null;
|
|
562
|
-
}
|
|
563
|
-
/**
|
|
564
|
-
* Transitions a defer block to the new state. Updates the necessary
|
|
565
|
-
* data structures and renders corresponding block.
|
|
566
|
-
*
|
|
567
|
-
* @param newState New state that should be applied to the defer block.
|
|
568
|
-
* @param tNode TNode that represents a defer block.
|
|
569
|
-
* @param lContainer Represents an instance of a defer block.
|
|
570
|
-
*/
|
|
571
|
-
export function renderDeferBlockState(newState, tNode, lContainer) {
|
|
572
|
-
const hostLView = lContainer[PARENT];
|
|
573
|
-
const hostTView = hostLView[TVIEW];
|
|
574
|
-
// Check if this view is not destroyed. Since the loading process was async,
|
|
575
|
-
// the view might end up being destroyed by the time rendering happens.
|
|
576
|
-
if (isDestroyed(hostLView))
|
|
577
|
-
return;
|
|
578
|
-
// Make sure this TNode belongs to TView that represents host LView.
|
|
579
|
-
ngDevMode && assertTNodeForLView(tNode, hostLView);
|
|
580
|
-
const lDetails = getLDeferBlockDetails(hostLView, tNode);
|
|
581
|
-
ngDevMode && assertDefined(lDetails, 'Expected a defer block state defined');
|
|
582
|
-
const currentState = lDetails[DEFER_BLOCK_STATE];
|
|
583
|
-
if (isValidStateChange(currentState, newState) &&
|
|
584
|
-
isValidStateChange(lDetails[NEXT_DEFER_BLOCK_STATE] ?? -1, newState)) {
|
|
585
|
-
const tDetails = getTDeferBlockDetails(hostTView, tNode);
|
|
586
|
-
const needsScheduling = getLoadingBlockAfter(tDetails) !== null ||
|
|
587
|
-
getMinimumDurationForState(tDetails, DeferBlockState.Loading) !== null ||
|
|
588
|
-
getMinimumDurationForState(tDetails, DeferBlockState.Placeholder);
|
|
589
|
-
if (ngDevMode && needsScheduling) {
|
|
590
|
-
assertDefined(applyDeferBlockStateWithSchedulingImpl, 'Expected scheduling function to be defined');
|
|
591
|
-
}
|
|
592
|
-
const applyStateFn = needsScheduling ? applyDeferBlockStateWithSchedulingImpl : applyDeferBlockState;
|
|
593
|
-
applyStateFn(newState, lDetails, lContainer, tNode, hostLView);
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
/**
|
|
597
|
-
* Applies changes to the DOM to reflect a given state.
|
|
598
|
-
*/
|
|
599
|
-
function applyDeferBlockState(newState, lDetails, lContainer, tNode, hostLView) {
|
|
600
|
-
const stateTmplIndex = getTemplateIndexForState(newState, hostLView, tNode);
|
|
601
|
-
if (stateTmplIndex !== null) {
|
|
602
|
-
lDetails[DEFER_BLOCK_STATE] = newState;
|
|
603
|
-
const hostTView = hostLView[TVIEW];
|
|
604
|
-
const adjustedIndex = stateTmplIndex + HEADER_OFFSET;
|
|
605
|
-
const tNode = getTNode(hostTView, adjustedIndex);
|
|
606
|
-
// There is only 1 view that can be present in an LContainer that
|
|
607
|
-
// represents a defer block, so always refer to the first one.
|
|
608
|
-
const viewIndex = 0;
|
|
609
|
-
removeLViewFromLContainer(lContainer, viewIndex);
|
|
610
|
-
const dehydratedView = findMatchingDehydratedView(lContainer, tNode.tView.ssrId);
|
|
611
|
-
const embeddedLView = createAndRenderEmbeddedLView(hostLView, tNode, null, { dehydratedView });
|
|
612
|
-
addLViewToLContainer(lContainer, embeddedLView, viewIndex, shouldAddViewToDom(tNode, dehydratedView));
|
|
613
|
-
markViewDirty(embeddedLView);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
/**
|
|
617
|
-
* Extends the `applyDeferBlockState` with timer-based scheduling.
|
|
618
|
-
* This function becomes available on a page if there are defer blocks
|
|
619
|
-
* that use `after` or `minimum` parameters in the `@loading` or
|
|
620
|
-
* `@placeholder` blocks.
|
|
621
|
-
*/
|
|
622
|
-
function applyDeferBlockStateWithScheduling(newState, lDetails, lContainer, tNode, hostLView) {
|
|
623
|
-
const now = Date.now();
|
|
624
|
-
const hostTView = hostLView[TVIEW];
|
|
625
|
-
const tDetails = getTDeferBlockDetails(hostTView, tNode);
|
|
626
|
-
if (lDetails[STATE_IS_FROZEN_UNTIL] === null || lDetails[STATE_IS_FROZEN_UNTIL] <= now) {
|
|
627
|
-
lDetails[STATE_IS_FROZEN_UNTIL] = null;
|
|
628
|
-
const loadingAfter = getLoadingBlockAfter(tDetails);
|
|
629
|
-
const inLoadingAfterPhase = lDetails[LOADING_AFTER_CLEANUP_FN] !== null;
|
|
630
|
-
if (newState === DeferBlockState.Loading && loadingAfter !== null && !inLoadingAfterPhase) {
|
|
631
|
-
// Trying to render loading, but it has an `after` config,
|
|
632
|
-
// so schedule an update action after a timeout.
|
|
633
|
-
lDetails[NEXT_DEFER_BLOCK_STATE] = newState;
|
|
634
|
-
const cleanupFn = scheduleDeferBlockUpdate(loadingAfter, lDetails, tNode, lContainer, hostLView);
|
|
635
|
-
lDetails[LOADING_AFTER_CLEANUP_FN] = cleanupFn;
|
|
636
|
-
}
|
|
637
|
-
else {
|
|
638
|
-
// If we transition to a complete or an error state and there is a pending
|
|
639
|
-
// operation to render loading after a timeout - invoke a cleanup operation,
|
|
640
|
-
// which stops the timer.
|
|
641
|
-
if (newState > DeferBlockState.Loading && inLoadingAfterPhase) {
|
|
642
|
-
lDetails[LOADING_AFTER_CLEANUP_FN]();
|
|
643
|
-
lDetails[LOADING_AFTER_CLEANUP_FN] = null;
|
|
644
|
-
lDetails[NEXT_DEFER_BLOCK_STATE] = null;
|
|
645
|
-
}
|
|
646
|
-
applyDeferBlockState(newState, lDetails, lContainer, tNode, hostLView);
|
|
647
|
-
const duration = getMinimumDurationForState(tDetails, newState);
|
|
648
|
-
if (duration !== null) {
|
|
649
|
-
lDetails[STATE_IS_FROZEN_UNTIL] = now + duration;
|
|
650
|
-
scheduleDeferBlockUpdate(duration, lDetails, tNode, lContainer, hostLView);
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
else {
|
|
655
|
-
// We are still rendering the previous state.
|
|
656
|
-
// Update the `NEXT_DEFER_BLOCK_STATE`, which would be
|
|
657
|
-
// picked up once it's time to transition to the next state.
|
|
658
|
-
lDetails[NEXT_DEFER_BLOCK_STATE] = newState;
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
/**
|
|
662
|
-
* Schedules an update operation after a specified timeout.
|
|
663
|
-
*/
|
|
664
|
-
function scheduleDeferBlockUpdate(timeout, lDetails, tNode, lContainer, hostLView) {
|
|
665
|
-
const callback = () => {
|
|
666
|
-
const nextState = lDetails[NEXT_DEFER_BLOCK_STATE];
|
|
667
|
-
lDetails[STATE_IS_FROZEN_UNTIL] = null;
|
|
668
|
-
lDetails[NEXT_DEFER_BLOCK_STATE] = null;
|
|
669
|
-
if (nextState !== null) {
|
|
670
|
-
renderDeferBlockState(nextState, tNode, lContainer);
|
|
671
|
-
}
|
|
672
|
-
};
|
|
673
|
-
return scheduleTimerTrigger(timeout, callback, hostLView, true);
|
|
674
|
-
}
|
|
675
|
-
/**
|
|
676
|
-
* Checks whether we can transition to the next state.
|
|
677
|
-
*
|
|
678
|
-
* We transition to the next state if the previous state was represented
|
|
679
|
-
* with a number that is less than the next state. For example, if the current
|
|
680
|
-
* state is "loading" (represented as `1`), we should not show a placeholder
|
|
681
|
-
* (represented as `0`), but we can show a completed state (represented as `2`)
|
|
682
|
-
* or an error state (represented as `3`).
|
|
683
|
-
*/
|
|
684
|
-
function isValidStateChange(currentState, newState) {
|
|
685
|
-
return currentState < newState;
|
|
686
|
-
}
|
|
687
|
-
/**
|
|
688
|
-
* Trigger prefetching of dependencies for a defer block.
|
|
689
|
-
*
|
|
690
|
-
* @param tDetails Static information about this defer block.
|
|
691
|
-
* @param lView LView of a host view.
|
|
692
|
-
*/
|
|
693
|
-
export function triggerPrefetching(tDetails, lView) {
|
|
694
|
-
if (lView[INJECTOR] && shouldTriggerDeferBlock(lView[INJECTOR])) {
|
|
695
|
-
triggerResourceLoading(tDetails, lView);
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
/**
|
|
699
|
-
* Trigger loading of defer block dependencies if the process hasn't started yet.
|
|
700
|
-
*
|
|
701
|
-
* @param tDetails Static information about this defer block.
|
|
702
|
-
* @param lView LView of a host view.
|
|
703
|
-
*/
|
|
704
|
-
export function triggerResourceLoading(tDetails, lView) {
|
|
705
|
-
const injector = lView[INJECTOR];
|
|
706
|
-
const tView = lView[TVIEW];
|
|
707
|
-
if (tDetails.loadingState !== DeferDependenciesLoadingState.NOT_STARTED) {
|
|
708
|
-
// If the loading status is different from initial one, it means that
|
|
709
|
-
// the loading of dependencies is in progress and there is nothing to do
|
|
710
|
-
// in this function. All details can be obtained from the `tDetails` object.
|
|
711
|
-
return;
|
|
712
|
-
}
|
|
713
|
-
const primaryBlockTNode = getPrimaryBlockTNode(tView, tDetails);
|
|
714
|
-
// Switch from NOT_STARTED -> IN_PROGRESS state.
|
|
715
|
-
tDetails.loadingState = DeferDependenciesLoadingState.IN_PROGRESS;
|
|
716
|
-
// Check if dependency function interceptor is configured.
|
|
717
|
-
const deferDependencyInterceptor = injector.get(DEFER_BLOCK_DEPENDENCY_INTERCEPTOR, null, { optional: true });
|
|
718
|
-
const dependenciesFn = deferDependencyInterceptor ?
|
|
719
|
-
deferDependencyInterceptor.intercept(tDetails.dependencyResolverFn) :
|
|
720
|
-
tDetails.dependencyResolverFn;
|
|
721
|
-
// The `dependenciesFn` might be `null` when all dependencies within
|
|
722
|
-
// a given defer block were eagerly references elsewhere in a file,
|
|
723
|
-
// thus no dynamic `import()`s were produced.
|
|
724
|
-
if (!dependenciesFn) {
|
|
725
|
-
tDetails.loadingPromise = Promise.resolve().then(() => {
|
|
726
|
-
tDetails.loadingState = DeferDependenciesLoadingState.COMPLETE;
|
|
727
|
-
});
|
|
728
|
-
return;
|
|
729
|
-
}
|
|
730
|
-
// Defer block may have multiple prefetch triggers. Once the loading
|
|
731
|
-
// starts, invoke all clean functions, since they are no longer needed.
|
|
732
|
-
invokeTDetailsCleanup(injector, tDetails);
|
|
733
|
-
// Start downloading of defer block dependencies.
|
|
734
|
-
tDetails.loadingPromise = Promise.allSettled(dependenciesFn()).then(results => {
|
|
735
|
-
let failed = false;
|
|
736
|
-
const directiveDefs = [];
|
|
737
|
-
const pipeDefs = [];
|
|
738
|
-
for (const result of results) {
|
|
739
|
-
if (result.status === 'fulfilled') {
|
|
740
|
-
const dependency = result.value;
|
|
741
|
-
const directiveDef = getComponentDef(dependency) || getDirectiveDef(dependency);
|
|
742
|
-
if (directiveDef) {
|
|
743
|
-
directiveDefs.push(directiveDef);
|
|
744
|
-
}
|
|
745
|
-
else {
|
|
746
|
-
const pipeDef = getPipeDef(dependency);
|
|
747
|
-
if (pipeDef) {
|
|
748
|
-
pipeDefs.push(pipeDef);
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
else {
|
|
753
|
-
failed = true;
|
|
754
|
-
break;
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
// Loading is completed, we no longer need this Promise.
|
|
758
|
-
tDetails.loadingPromise = null;
|
|
759
|
-
if (failed) {
|
|
760
|
-
tDetails.loadingState = DeferDependenciesLoadingState.FAILED;
|
|
761
|
-
}
|
|
762
|
-
else {
|
|
763
|
-
tDetails.loadingState = DeferDependenciesLoadingState.COMPLETE;
|
|
764
|
-
// Update directive and pipe registries to add newly downloaded dependencies.
|
|
765
|
-
const primaryBlockTView = primaryBlockTNode.tView;
|
|
766
|
-
if (directiveDefs.length > 0) {
|
|
767
|
-
primaryBlockTView.directiveRegistry =
|
|
768
|
-
addDepsToRegistry(primaryBlockTView.directiveRegistry, directiveDefs);
|
|
769
|
-
}
|
|
770
|
-
if (pipeDefs.length > 0) {
|
|
771
|
-
primaryBlockTView.pipeRegistry =
|
|
772
|
-
addDepsToRegistry(primaryBlockTView.pipeRegistry, pipeDefs);
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
});
|
|
776
|
-
}
|
|
777
|
-
/**
|
|
778
|
-
* Adds downloaded dependencies into a directive or a pipe registry,
|
|
779
|
-
* making sure that a dependency doesn't yet exist in the registry.
|
|
780
|
-
*/
|
|
781
|
-
function addDepsToRegistry(currentDeps, newDeps) {
|
|
782
|
-
if (!currentDeps || currentDeps.length === 0) {
|
|
783
|
-
return newDeps;
|
|
784
|
-
}
|
|
785
|
-
const currentDepSet = new Set(currentDeps);
|
|
786
|
-
for (const dep of newDeps) {
|
|
787
|
-
currentDepSet.add(dep);
|
|
788
|
-
}
|
|
789
|
-
// If `currentDeps` is the same length, there were no new deps and can
|
|
790
|
-
// return the original array.
|
|
791
|
-
return (currentDeps.length === currentDepSet.size) ? currentDeps : Array.from(currentDepSet);
|
|
792
|
-
}
|
|
793
|
-
/** Utility function to render placeholder content (if present) */
|
|
794
|
-
function renderPlaceholder(lView, tNode) {
|
|
795
|
-
const lContainer = lView[tNode.index];
|
|
796
|
-
ngDevMode && assertLContainer(lContainer);
|
|
797
|
-
renderDeferBlockState(DeferBlockState.Placeholder, tNode, lContainer);
|
|
798
|
-
}
|
|
799
|
-
/**
|
|
800
|
-
* Subscribes to the "loading" Promise and renders corresponding defer sub-block,
|
|
801
|
-
* based on the loading results.
|
|
802
|
-
*
|
|
803
|
-
* @param lContainer Represents an instance of a defer block.
|
|
804
|
-
* @param tNode Represents defer block info shared across all instances.
|
|
805
|
-
*/
|
|
806
|
-
function renderDeferStateAfterResourceLoading(tDetails, tNode, lContainer) {
|
|
807
|
-
ngDevMode &&
|
|
808
|
-
assertDefined(tDetails.loadingPromise, 'Expected loading Promise to exist on this defer block');
|
|
809
|
-
tDetails.loadingPromise.then(() => {
|
|
810
|
-
if (tDetails.loadingState === DeferDependenciesLoadingState.COMPLETE) {
|
|
811
|
-
ngDevMode && assertDeferredDependenciesLoaded(tDetails);
|
|
812
|
-
// Everything is loaded, show the primary block content
|
|
813
|
-
renderDeferBlockState(DeferBlockState.Complete, tNode, lContainer);
|
|
814
|
-
}
|
|
815
|
-
else if (tDetails.loadingState === DeferDependenciesLoadingState.FAILED) {
|
|
816
|
-
renderDeferBlockState(DeferBlockState.Error, tNode, lContainer);
|
|
817
|
-
}
|
|
818
|
-
});
|
|
819
|
-
}
|
|
820
|
-
/** Retrieves a TNode that represents main content of a defer block. */
|
|
821
|
-
function getPrimaryBlockTNode(tView, tDetails) {
|
|
822
|
-
const adjustedIndex = tDetails.primaryTmplIndex + HEADER_OFFSET;
|
|
823
|
-
return getTNode(tView, adjustedIndex);
|
|
824
|
-
}
|
|
825
|
-
/**
|
|
826
|
-
* Attempts to trigger loading of defer block dependencies.
|
|
827
|
-
* If the block is already in a loading, completed or an error state -
|
|
828
|
-
* no additional actions are taken.
|
|
829
|
-
*/
|
|
830
|
-
function triggerDeferBlock(lView, tNode) {
|
|
831
|
-
const tView = lView[TVIEW];
|
|
832
|
-
const lContainer = lView[tNode.index];
|
|
833
|
-
const injector = lView[INJECTOR];
|
|
834
|
-
ngDevMode && assertLContainer(lContainer);
|
|
835
|
-
if (!shouldTriggerDeferBlock(injector))
|
|
836
|
-
return;
|
|
837
|
-
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
838
|
-
switch (tDetails.loadingState) {
|
|
839
|
-
case DeferDependenciesLoadingState.NOT_STARTED:
|
|
840
|
-
renderDeferBlockState(DeferBlockState.Loading, tNode, lContainer);
|
|
841
|
-
triggerResourceLoading(tDetails, lView);
|
|
842
|
-
// The `loadingState` might have changed to "loading".
|
|
843
|
-
if (tDetails.loadingState ===
|
|
844
|
-
DeferDependenciesLoadingState.IN_PROGRESS) {
|
|
845
|
-
renderDeferStateAfterResourceLoading(tDetails, tNode, lContainer);
|
|
846
|
-
}
|
|
847
|
-
break;
|
|
848
|
-
case DeferDependenciesLoadingState.IN_PROGRESS:
|
|
849
|
-
renderDeferBlockState(DeferBlockState.Loading, tNode, lContainer);
|
|
850
|
-
renderDeferStateAfterResourceLoading(tDetails, tNode, lContainer);
|
|
851
|
-
break;
|
|
852
|
-
case DeferDependenciesLoadingState.COMPLETE:
|
|
853
|
-
ngDevMode && assertDeferredDependenciesLoaded(tDetails);
|
|
854
|
-
renderDeferBlockState(DeferBlockState.Complete, tNode, lContainer);
|
|
855
|
-
break;
|
|
856
|
-
case DeferDependenciesLoadingState.FAILED:
|
|
857
|
-
renderDeferBlockState(DeferBlockState.Error, tNode, lContainer);
|
|
858
|
-
break;
|
|
859
|
-
default:
|
|
860
|
-
if (ngDevMode) {
|
|
861
|
-
throwError('Unknown defer block state');
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
/**
|
|
866
|
-
* Asserts whether all dependencies for a defer block are loaded.
|
|
867
|
-
* Always run this function (in dev mode) before rendering a defer
|
|
868
|
-
* block in completed state.
|
|
869
|
-
*/
|
|
870
|
-
function assertDeferredDependenciesLoaded(tDetails) {
|
|
871
|
-
assertEqual(tDetails.loadingState, DeferDependenciesLoadingState.COMPLETE, 'Expecting all deferred dependencies to be loaded.');
|
|
872
|
-
}
|
|
873
|
-
/**
|
|
874
|
-
* **INTERNAL**, avoid referencing it in application code.
|
|
875
|
-
*
|
|
876
|
-
* Injector token that allows to provide `DeferBlockDependencyInterceptor` class
|
|
877
|
-
* implementation.
|
|
878
|
-
*/
|
|
879
|
-
export const DEFER_BLOCK_DEPENDENCY_INTERCEPTOR = new InjectionToken(ngDevMode ? 'DEFER_BLOCK_DEPENDENCY_INTERCEPTOR' : '');
|
|
880
|
-
/**
|
|
881
|
-
* Determines if a given value matches the expected structure of a defer block
|
|
882
|
-
*
|
|
883
|
-
* We can safely rely on the primaryTmplIndex because every defer block requires
|
|
884
|
-
* that a primary template exists. All the other template options are optional.
|
|
885
|
-
*/
|
|
886
|
-
function isTDeferBlockDetails(value) {
|
|
887
|
-
return (typeof value === 'object') &&
|
|
888
|
-
(typeof value.primaryTmplIndex === 'number');
|
|
889
|
-
}
|
|
890
|
-
/**
|
|
891
|
-
* Internal token used for configuring defer block behavior.
|
|
892
|
-
*/
|
|
893
|
-
export const DEFER_BLOCK_CONFIG = new InjectionToken(ngDevMode ? 'DEFER_BLOCK_CONFIG' : '');
|
|
894
|
-
/**
|
|
895
|
-
* Retrieves all defer blocks in a given LView.
|
|
896
|
-
*
|
|
897
|
-
* @param lView lView with defer blocks
|
|
898
|
-
* @param deferBlocks defer block aggregator array
|
|
899
|
-
*/
|
|
900
|
-
export function getDeferBlocks(lView, deferBlocks) {
|
|
901
|
-
const tView = lView[TVIEW];
|
|
902
|
-
for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
|
|
903
|
-
if (isLContainer(lView[i])) {
|
|
904
|
-
const lContainer = lView[i];
|
|
905
|
-
// An LContainer may represent an instance of a defer block, in which case
|
|
906
|
-
// we store it as a result. Otherwise, keep iterating over LContainer views and
|
|
907
|
-
// look for defer blocks.
|
|
908
|
-
const isLast = i === tView.bindingStartIndex - 1;
|
|
909
|
-
if (!isLast) {
|
|
910
|
-
const tNode = tView.data[i];
|
|
911
|
-
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
912
|
-
if (isTDeferBlockDetails(tDetails)) {
|
|
913
|
-
deferBlocks.push({ lContainer, lView, tNode, tDetails });
|
|
914
|
-
// This LContainer represents a defer block, so we exit
|
|
915
|
-
// this iteration and don't inspect views in this LContainer.
|
|
916
|
-
continue;
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
|
|
920
|
-
getDeferBlocks(lContainer[i], deferBlocks);
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
else if (isLView(lView[i])) {
|
|
924
|
-
// This is a component, enter the `getDeferBlocks` recursively.
|
|
925
|
-
getDeferBlocks(lView[i], deferBlocks);
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
/**
|
|
930
|
-
* Registers a cleanup function associated with a prefetching trigger
|
|
931
|
-
* of a given defer block.
|
|
932
|
-
*/
|
|
933
|
-
function registerTDetailsCleanup(injector, tDetails, key, cleanupFn) {
|
|
934
|
-
injector.get(DeferBlockCleanupManager).add(tDetails, key, cleanupFn);
|
|
935
|
-
}
|
|
936
|
-
/**
|
|
937
|
-
* Invokes all registered prefetch cleanup triggers
|
|
938
|
-
* and removes all cleanup functions afterwards.
|
|
939
|
-
*/
|
|
940
|
-
function invokeTDetailsCleanup(injector, tDetails) {
|
|
941
|
-
injector.get(DeferBlockCleanupManager).cleanup(tDetails);
|
|
942
|
-
}
|
|
943
|
-
/**
|
|
944
|
-
* Internal service to keep track of cleanup functions associated
|
|
945
|
-
* with defer blocks. This class is used to manage cleanup functions
|
|
946
|
-
* created for prefetching triggers.
|
|
947
|
-
*/
|
|
948
|
-
class DeferBlockCleanupManager {
|
|
949
|
-
constructor() {
|
|
950
|
-
this.blocks = new Map();
|
|
951
|
-
}
|
|
952
|
-
add(tDetails, key, callback) {
|
|
953
|
-
if (!this.blocks.has(tDetails)) {
|
|
954
|
-
this.blocks.set(tDetails, new Map());
|
|
955
|
-
}
|
|
956
|
-
const block = this.blocks.get(tDetails);
|
|
957
|
-
if (!block.has(key)) {
|
|
958
|
-
block.set(key, []);
|
|
959
|
-
}
|
|
960
|
-
const callbacks = block.get(key);
|
|
961
|
-
callbacks.push(callback);
|
|
962
|
-
}
|
|
963
|
-
has(tDetails, key) {
|
|
964
|
-
return !!this.blocks.get(tDetails)?.has(key);
|
|
965
|
-
}
|
|
966
|
-
cleanup(tDetails) {
|
|
967
|
-
const block = this.blocks.get(tDetails);
|
|
968
|
-
if (block) {
|
|
969
|
-
for (const callbacks of Object.values(block)) {
|
|
970
|
-
for (const callback of callbacks) {
|
|
971
|
-
callback();
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
this.blocks.delete(tDetails);
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
ngOnDestroy() {
|
|
978
|
-
for (const [block] of this.blocks) {
|
|
979
|
-
this.cleanup(block);
|
|
980
|
-
}
|
|
981
|
-
this.blocks.clear();
|
|
982
|
-
}
|
|
983
|
-
/** @nocollapse */
|
|
984
|
-
static { this.ɵprov = ɵɵdefineInjectable({
|
|
985
|
-
token: DeferBlockCleanupManager,
|
|
986
|
-
providedIn: 'root',
|
|
987
|
-
factory: () => new DeferBlockCleanupManager(),
|
|
988
|
-
}); }
|
|
989
|
-
}
|
|
990
|
-
/**
|
|
991
|
-
* Use shims for the `requestIdleCallback` and `cancelIdleCallback` functions for
|
|
992
|
-
* environments where those functions are not available (e.g. Node.js and Safari).
|
|
993
|
-
*
|
|
994
|
-
* Note: we wrap the `requestIdleCallback` call into a function, so that it can be
|
|
995
|
-
* overridden/mocked in test environment and picked up by the runtime code.
|
|
996
|
-
*/
|
|
997
|
-
const _requestIdleCallback = () => typeof requestIdleCallback !== 'undefined' ? requestIdleCallback : setTimeout;
|
|
998
|
-
const _cancelIdleCallback = () => typeof requestIdleCallback !== 'undefined' ? cancelIdleCallback : clearTimeout;
|
|
999
|
-
/**
|
|
1000
|
-
* Helper service to schedule `requestIdleCallback`s for batches of defer blocks,
|
|
1001
|
-
* to avoid calling `requestIdleCallback` for each defer block (e.g. if
|
|
1002
|
-
* defer blocks are defined inside a for loop).
|
|
1003
|
-
*/
|
|
1004
|
-
class OnIdleScheduler {
|
|
1005
|
-
constructor() {
|
|
1006
|
-
// Indicates whether current callbacks are being invoked.
|
|
1007
|
-
this.executingCallbacks = false;
|
|
1008
|
-
// Currently scheduled idle callback id.
|
|
1009
|
-
this.idleId = null;
|
|
1010
|
-
// Set of callbacks to be invoked next.
|
|
1011
|
-
this.current = new Set();
|
|
1012
|
-
// Set of callbacks collected while invoking current set of callbacks.
|
|
1013
|
-
// Those callbacks are scheduled for the next idle period.
|
|
1014
|
-
this.deferred = new Set();
|
|
1015
|
-
this.ngZone = inject(NgZone);
|
|
1016
|
-
this.requestIdleCallback = _requestIdleCallback().bind(globalThis);
|
|
1017
|
-
this.cancelIdleCallback = _cancelIdleCallback().bind(globalThis);
|
|
1018
|
-
}
|
|
1019
|
-
add(callback) {
|
|
1020
|
-
const target = this.executingCallbacks ? this.deferred : this.current;
|
|
1021
|
-
target.add(callback);
|
|
1022
|
-
if (this.idleId === null) {
|
|
1023
|
-
this.scheduleIdleCallback();
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
remove(callback) {
|
|
1027
|
-
this.current.delete(callback);
|
|
1028
|
-
this.deferred.delete(callback);
|
|
1029
|
-
}
|
|
1030
|
-
scheduleIdleCallback() {
|
|
1031
|
-
const callback = () => {
|
|
1032
|
-
this.cancelIdleCallback(this.idleId);
|
|
1033
|
-
this.idleId = null;
|
|
1034
|
-
this.executingCallbacks = true;
|
|
1035
|
-
for (const callback of this.current) {
|
|
1036
|
-
callback();
|
|
1037
|
-
}
|
|
1038
|
-
this.current.clear();
|
|
1039
|
-
this.executingCallbacks = false;
|
|
1040
|
-
// If there are any callbacks added during an invocation
|
|
1041
|
-
// of the current ones - make them "current" and schedule
|
|
1042
|
-
// a new idle callback.
|
|
1043
|
-
if (this.deferred.size > 0) {
|
|
1044
|
-
for (const callback of this.deferred) {
|
|
1045
|
-
this.current.add(callback);
|
|
1046
|
-
}
|
|
1047
|
-
this.deferred.clear();
|
|
1048
|
-
this.scheduleIdleCallback();
|
|
1049
|
-
}
|
|
1050
|
-
};
|
|
1051
|
-
// Ensure that the callback runs in the NgZone since
|
|
1052
|
-
// the `requestIdleCallback` is not currently patched by Zone.js.
|
|
1053
|
-
this.idleId = this.requestIdleCallback(() => this.ngZone.run(callback));
|
|
1054
|
-
}
|
|
1055
|
-
ngOnDestroy() {
|
|
1056
|
-
if (this.idleId !== null) {
|
|
1057
|
-
this.cancelIdleCallback(this.idleId);
|
|
1058
|
-
this.idleId = null;
|
|
1059
|
-
}
|
|
1060
|
-
this.current.clear();
|
|
1061
|
-
this.deferred.clear();
|
|
1062
|
-
}
|
|
1063
|
-
/** @nocollapse */
|
|
1064
|
-
static { this.ɵprov = ɵɵdefineInjectable({
|
|
1065
|
-
token: OnIdleScheduler,
|
|
1066
|
-
providedIn: 'root',
|
|
1067
|
-
factory: () => new OnIdleScheduler(),
|
|
1068
|
-
}); }
|
|
1069
|
-
}
|
|
1070
|
-
/**
|
|
1071
|
-
* Helper service to schedule `setTimeout`s for batches of defer blocks,
|
|
1072
|
-
* to avoid calling `setTimeout` for each defer block (e.g. if defer blocks
|
|
1073
|
-
* are created inside a for loop).
|
|
1074
|
-
*/
|
|
1075
|
-
class TimerScheduler {
|
|
1076
|
-
constructor() {
|
|
1077
|
-
// Indicates whether current callbacks are being invoked.
|
|
1078
|
-
this.executingCallbacks = false;
|
|
1079
|
-
// Currently scheduled `setTimeout` id.
|
|
1080
|
-
this.timeoutId = null;
|
|
1081
|
-
// When currently scheduled timer would fire.
|
|
1082
|
-
this.invokeTimerAt = null;
|
|
1083
|
-
// List of callbacks to be invoked.
|
|
1084
|
-
// For each callback we also store a timestamp on when the callback
|
|
1085
|
-
// should be invoked. We store timestamps and callback functions
|
|
1086
|
-
// in a flat array to avoid creating new objects for each entry.
|
|
1087
|
-
// [timestamp1, callback1, timestamp2, callback2, ...]
|
|
1088
|
-
this.current = [];
|
|
1089
|
-
// List of callbacks collected while invoking current set of callbacks.
|
|
1090
|
-
// Those callbacks are added to the "current" queue at the end of
|
|
1091
|
-
// the current callback invocation. The shape of this list is the same
|
|
1092
|
-
// as the shape of the `current` list.
|
|
1093
|
-
this.deferred = [];
|
|
1094
|
-
}
|
|
1095
|
-
add(delay, callback) {
|
|
1096
|
-
const target = this.executingCallbacks ? this.deferred : this.current;
|
|
1097
|
-
this.addToQueue(target, Date.now() + delay, callback);
|
|
1098
|
-
this.scheduleTimer();
|
|
1099
|
-
}
|
|
1100
|
-
remove(callback) {
|
|
1101
|
-
const callbackIndex = this.removeFromQueue(this.current, callback);
|
|
1102
|
-
if (callbackIndex === -1) {
|
|
1103
|
-
// Try cleaning up deferred queue only in case
|
|
1104
|
-
// we didn't find a callback in the "current" queue.
|
|
1105
|
-
this.removeFromQueue(this.deferred, callback);
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
addToQueue(target, invokeAt, callback) {
|
|
1109
|
-
let insertAtIndex = target.length;
|
|
1110
|
-
for (let i = 0; i < target.length; i += 2) {
|
|
1111
|
-
const invokeQueuedCallbackAt = target[i];
|
|
1112
|
-
if (invokeQueuedCallbackAt > invokeAt) {
|
|
1113
|
-
// We've reached a first timer that is scheduled
|
|
1114
|
-
// for a later time than what we are trying to insert.
|
|
1115
|
-
// This is the location at which we need to insert,
|
|
1116
|
-
// no need to iterate further.
|
|
1117
|
-
insertAtIndex = i;
|
|
1118
|
-
break;
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
arrayInsert2(target, insertAtIndex, invokeAt, callback);
|
|
1122
|
-
}
|
|
1123
|
-
removeFromQueue(target, callback) {
|
|
1124
|
-
let index = -1;
|
|
1125
|
-
for (let i = 0; i < target.length; i += 2) {
|
|
1126
|
-
const queuedCallback = target[i + 1];
|
|
1127
|
-
if (queuedCallback === callback) {
|
|
1128
|
-
index = i;
|
|
1129
|
-
break;
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
if (index > -1) {
|
|
1133
|
-
// Remove 2 elements: a timestamp slot and
|
|
1134
|
-
// the following slot with a callback function.
|
|
1135
|
-
arraySplice(target, index, 2);
|
|
1136
|
-
}
|
|
1137
|
-
return index;
|
|
1138
|
-
}
|
|
1139
|
-
scheduleTimer() {
|
|
1140
|
-
const callback = () => {
|
|
1141
|
-
clearTimeout(this.timeoutId);
|
|
1142
|
-
this.timeoutId = null;
|
|
1143
|
-
this.executingCallbacks = true;
|
|
1144
|
-
// Invoke callbacks that were scheduled to run
|
|
1145
|
-
// before the current time.
|
|
1146
|
-
let now = Date.now();
|
|
1147
|
-
let lastCallbackIndex = null;
|
|
1148
|
-
for (let i = 0; i < this.current.length; i += 2) {
|
|
1149
|
-
const invokeAt = this.current[i];
|
|
1150
|
-
const callback = this.current[i + 1];
|
|
1151
|
-
if (invokeAt <= now) {
|
|
1152
|
-
callback();
|
|
1153
|
-
// Point at the invoked callback function, which is located
|
|
1154
|
-
// after the timestamp.
|
|
1155
|
-
lastCallbackIndex = i + 1;
|
|
1156
|
-
}
|
|
1157
|
-
else {
|
|
1158
|
-
// We've reached a timer that should not be invoked yet.
|
|
1159
|
-
break;
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1162
|
-
if (lastCallbackIndex !== null) {
|
|
1163
|
-
// If last callback index is `null` - no callbacks were invoked,
|
|
1164
|
-
// so no cleanup is needed. Otherwise, remove invoked callbacks
|
|
1165
|
-
// from the queue.
|
|
1166
|
-
arraySplice(this.current, 0, lastCallbackIndex + 1);
|
|
1167
|
-
}
|
|
1168
|
-
this.executingCallbacks = false;
|
|
1169
|
-
// If there are any callbacks added during an invocation
|
|
1170
|
-
// of the current ones - move them over to the "current"
|
|
1171
|
-
// queue.
|
|
1172
|
-
if (this.deferred.length > 0) {
|
|
1173
|
-
for (let i = 0; i < this.deferred.length; i += 2) {
|
|
1174
|
-
const invokeAt = this.deferred[i];
|
|
1175
|
-
const callback = this.deferred[i + 1];
|
|
1176
|
-
this.addToQueue(this.current, invokeAt, callback);
|
|
1177
|
-
}
|
|
1178
|
-
this.deferred.length = 0;
|
|
1179
|
-
}
|
|
1180
|
-
this.scheduleTimer();
|
|
1181
|
-
};
|
|
1182
|
-
// Avoid running timer callbacks more than once per
|
|
1183
|
-
// average frame duration. This is needed for better
|
|
1184
|
-
// batching and to avoid kicking off excessive change
|
|
1185
|
-
// detection cycles.
|
|
1186
|
-
const FRAME_DURATION_MS = 16; // 1000ms / 60fps
|
|
1187
|
-
if (this.current.length > 0) {
|
|
1188
|
-
const now = Date.now();
|
|
1189
|
-
// First element in the queue points at the timestamp
|
|
1190
|
-
// of the first (earliest) event.
|
|
1191
|
-
const invokeAt = this.current[0];
|
|
1192
|
-
if (!this.timeoutId ||
|
|
1193
|
-
// Reschedule a timer in case a queue contains an item with
|
|
1194
|
-
// an earlier timestamp and the delta is more than an average
|
|
1195
|
-
// frame duration.
|
|
1196
|
-
(this.invokeTimerAt && (this.invokeTimerAt - invokeAt > FRAME_DURATION_MS))) {
|
|
1197
|
-
if (this.timeoutId !== null) {
|
|
1198
|
-
// There was a timeout already, but an earlier event was added
|
|
1199
|
-
// into the queue. In this case we drop an old timer and setup
|
|
1200
|
-
// a new one with an updated (smaller) timeout.
|
|
1201
|
-
clearTimeout(this.timeoutId);
|
|
1202
|
-
this.timeoutId = null;
|
|
1203
|
-
}
|
|
1204
|
-
const timeout = Math.max(invokeAt - now, FRAME_DURATION_MS);
|
|
1205
|
-
this.invokeTimerAt = invokeAt;
|
|
1206
|
-
this.timeoutId = setTimeout(callback, timeout);
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1210
|
-
ngOnDestroy() {
|
|
1211
|
-
if (this.timeoutId !== null) {
|
|
1212
|
-
clearTimeout(this.timeoutId);
|
|
1213
|
-
this.timeoutId = null;
|
|
1214
|
-
}
|
|
1215
|
-
this.current.length = 0;
|
|
1216
|
-
this.deferred.length = 0;
|
|
1217
|
-
}
|
|
1218
|
-
/** @nocollapse */
|
|
1219
|
-
static { this.ɵprov = ɵɵdefineInjectable({
|
|
1220
|
-
token: TimerScheduler,
|
|
1221
|
-
providedIn: 'root',
|
|
1222
|
-
factory: () => new TimerScheduler(),
|
|
1223
|
-
}); }
|
|
1224
|
-
}
|
|
1225
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9jb3JlL3NyYy9yZW5kZXIzL2luc3RydWN0aW9ucy9kZWZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxPQUFPLEVBQUMsTUFBTSxFQUFFLGNBQWMsRUFBWSxrQkFBa0IsRUFBQyxNQUFNLFVBQVUsQ0FBQztBQUM5RSxPQUFPLEVBQUMsMEJBQTBCLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUNqRSxPQUFPLEVBQUMsbUNBQW1DLEVBQUMsTUFBTSxpQ0FBaUMsQ0FBQztBQUNwRixPQUFPLEVBQUMsWUFBWSxFQUFFLFdBQVcsRUFBQyxNQUFNLHdCQUF3QixDQUFDO0FBQ2pFLE9BQU8sRUFBQyxhQUFhLEVBQUUsYUFBYSxFQUFFLFdBQVcsRUFBRSxVQUFVLEVBQUMsTUFBTSxtQkFBbUIsQ0FBQztBQUN4RixPQUFPLEVBQUMsTUFBTSxFQUFDLE1BQU0sWUFBWSxDQUFDO0FBQ2xDLE9BQU8sRUFBQyxXQUFXLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUNsRCxPQUFPLEVBQUMsc0JBQXNCLEVBQUUsZ0JBQWdCLEVBQUUsV0FBVyxFQUFFLG1CQUFtQixFQUFDLE1BQU0sV0FBVyxDQUFDO0FBQ3JHLE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSxhQUFhLENBQUM7QUFDM0MsT0FBTyxFQUFDLGVBQWUsRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBQzNFLE9BQU8sRUFBQyx1QkFBdUIsRUFBYSxNQUFNLHlCQUF5QixDQUFDO0FBQzVFLE9BQU8sRUFBQyxpQkFBaUIsRUFBRSxrQkFBa0IsRUFBb0IsdUJBQXVCLEVBQUUsZUFBZSxFQUFzQiw2QkFBNkIsRUFBd0csd0JBQXdCLEVBQUUsa0JBQWtCLEVBQUUsWUFBWSxFQUFFLHNCQUFzQixFQUFFLHFCQUFxQixFQUFxQixNQUFNLHFC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cHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG5pbXBvcnQge2luamVjdCwgSW5qZWN0aW9uVG9rZW4sIEluamVjdG9yLCDJtcm1ZGVmaW5lSW5qZWN0YWJsZX0gZnJvbSAnLi4vLi4vZGknO1xuaW1wb3J0IHtmaW5kTWF0Y2hpbmdEZWh5ZHJhdGVkVmlld30gZnJvbSAnLi4vLi4vaHlkcmF0aW9uL3ZpZXdzJztcbmltcG9ydCB7cG9wdWxhdGVEZWh5ZHJhdGVkVmlld3NJbkxDb250YWluZXJ9IGZyb20gJy4uLy4uL2xpbmtlci92aWV3X2NvbnRhaW5lcl9yZWYnO1xuaW1wb3J0IHthcnJheUluc2VydDIsIGFycmF5U3BsaWNlfSBmcm9tICcuLi8uLi91dGlsL2FycmF5X3V0aWxzJztcbmltcG9ydCB7YXNzZXJ0RGVmaW5lZCwgYXNzZXJ0RWxlbWVudCwgYXNzZXJ0RXF1YWwsIHRocm93RXJyb3J9IGZyb20gJy4uLy4uL3V0aWwvYXNzZXJ0JztcbmltcG9ydCB7Tmdab25lfSBmcm9tICcuLi8uLi96b25lJztcbmltcG9ydCB7YWZ0ZXJSZW5kZXJ9IGZyb20gJy4uL2FmdGVyX3JlbmRlcl9ob29rcyc7XG5pbXBvcnQge2Fzc2VydEluZGV4SW5EZWNsUmFuZ2UsIGFzc2VydExDb250YWluZXIsIGFzc2VydExWaWV3LCBhc3NlcnRUTm9kZUZvckxWaWV3fSBmcm9tICcuLi9hc3NlcnQnO1xuaW1wb3J0IHtiaW5kaW5nVXBkYXRlZH0gZnJvbSAnLi4vYmluZGluZ3MnO1xuaW1wb3J0IHtnZXRDb21wb25lbnREZWYsIGdldERpcmVjdGl2ZURlZiwgZ2V0UGlwZURlZn0gZnJvbSAnLi4vZGVmaW5pdGlvbic7XG5pbXBvcnQge0NPTlRBSU5FUl9IRUFERVJfT0ZGU0VULCBMQ29udGFpbmVyfSBmcm9tICcuLi9pbnRlcmZhY2VzL2NvbnRhaW5lcic7XG5pbXBvcnQge0RFRkVSX0JMT0NLX1NUQVRFLCBEZWZlckJsb2NrQmVoYXZpb3IsIERlZmVyQmxvY2tDb25maWcsIERlZmVyQmxvY2tJbnRlcm5hbFN0YXRlLCBEZWZlckJsb2NrU3RhdGUsIERlZmVyQmxvY2tUcmlnZ2VycywgRGVmZXJEZXBlbmRlbmNpZXNMb2FkaW5nU3RhdGUsIERlZmVycmVkTG9hZGluZ0Jsb2NrQ29uZmlnLCBEZWZlcnJlZFBsYWNlaG9sZGVyQmxvY2tDb25maWcsIERlcGVuZGVuY3lSZXNvbHZlckZuLCBMRGVmZXJCbG9ja0RldGFpbHMsIExPQURJTkdfQUZURVJfQ0xFQU5VUF9GTiwgTE9BRElOR19BRlRFUl9TTE9ULCBNSU5JTVVNX1NMT1QsIE5FWFRfREVGRVJfQkxPQ0tfU1RBVEUsIFNUQVRFX0lTX0ZST1pFTl9VTlRJTCwgVERlZmVyQmxvY2tEZXRhaWxzfSBmcm9tICcuLi9pbnRlcmZhY2VzL2RlZmVyJztcbmltcG9ydCB7RGVwZW5kZW5jeURlZiwgRGlyZWN0aXZlRGVmTGlzdCwgUGlwZURlZkxpc3R9IGZyb20gJy4uL2ludGVyZmFjZXMvZGVmaW5pdGlvbic7XG5pbXBvcnQge1RDb250YWluZXJOb2RlLCBUTm9kZX0gZnJvbSAnLi4vaW50ZXJmYWNlcy9ub2RlJztcbmltcG9ydCB7aXNEZXN0cm95ZWQsIGlzTENvbnRhaW5lciwgaXNMVmlld30gZnJvbSAnLi4vaW50ZXJmYWNlcy90eXBlX2NoZWNrcyc7XG5pbXBvcnQge0ZMQUdTLCBIRUFERVJfT0ZGU0VULCBJTkpFQ1RPUiwgTFZpZXcsIExWaWV3RmxhZ3MsIFBBUkVOVCwgVFZJRVcsIFRWaWV3fSBmcm9tICcuLi9pbnRlcmZhY2VzL3ZpZXcnO1xuaW1wb3J0IHtnZXRDdXJyZW50VE5vZGUsIGdldExWaWV3LCBnZXRTZWxlY3RlZFROb2RlLCBnZXRUVmlldywgbmV4dEJpbmRpbmdJbmRleH0gZnJvbSAnLi4vc3RhdGUnO1xuaW1wb3J0IHtpc1BsYXRmb3JtQnJvd3Nlcn0gZnJvbSAnLi4vdXRpbC9taXNjX3V0aWxzJztcbmltcG9ydCB7Z2V0Q29uc3RhbnQsIGdldE5hdGl2ZUJ5SW5kZXgsIGdldFROb2RlLCByZW1vdmVMVmlld09uRGVzdHJveSwgc3RvcmVMVmlld09uRGVzdHJveSwgd2Fsa1VwVmlld3N9IGZyb20gJy4uL3V0aWwvdmlld191dGlscyc7XG5pbXBvcnQge2FkZExWaWV3VG9MQ29udGFpbmVyLCBjcmVhdGVBbmRSZW5kZXJFbWJlZGRlZExWaWV3LCByZW1vdmVMVmlld0Zyb21MQ29udGFpbmVyLCBzaG91bGRBZGRWaWV3VG9Eb219IGZyb20gJy4uL3ZpZXdfbWFuaXB1bGF0aW9uJztcblxuaW1wb3J0IHtvbkhvdmVyLCBvbkludGVyYWN0aW9uLCBvblZpZXdwb3J0fSBmcm9tICcuL2RlZmVyX2V2ZW50cyc7XG5pbXBvcnQge21hcmtWaWV3RGlydHl9IGZyb20gJy4vbWFya192aWV3X2RpcnR5JztcbmltcG9ydCB7ybXJtXRlbXBsYXRlfSBmcm9tICcuL3RlbXBsYXRlJztcblxuLyoqXG4gKiBSZXR1cm5zIHdoZXRoZXIgZGVmZXIgYmxvY2tzIHNob3VsZCBiZSB0cmlnZ2VyZWQuXG4gKlxuICogQ3VycmVudGx5LCBkZWZlciBibG9ja3MgYXJlIG5vdCB0cmlnZ2VyZWQgb24gdGhlIHNlcnZlcixcbiAqIG9ubHkgcGxhY2Vob2xkZXIgY29udGVudCBpcyByZW5kZXJlZCAoaWYgcHJvdmlkZWQpLlxuICovXG5mdW5jdGlvbiBzaG91bGRUcmlnZ2VyRGVmZXJCbG9jayhpbmplY3RvcjogSW5qZWN0b3IpOiBib29sZWFuIHtcbiAgY29uc3QgY29uZmlnID0gaW5qZWN0b3IuZ2V0KERFRkVSX0JMT0NLX0NPTkZJRywgbnVsbCwge29wdGlvbmFsOiB0cnVlfSk7XG4gIGlmIChjb25maWc/LmJlaGF2aW9yID09PSBEZWZlckJsb2NrQmVoYXZpb3IuTWFudWFsKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHJldHVybiBpc1BsYXRmb3JtQnJvd3NlcihpbmplY3Rvcik7XG59XG5cbi8qKlxuICogUmVmZXJlbmNlIHRvIHRoZSB0aW1lci1iYXNlZCBzY2hlZHVsZXIgaW1wbGVtZW50YXRpb24gb2YgZGVmZXIgYmxvY2sgc3RhdGVcbiAqIHJlbmRlcmluZyBtZXRob2QuIEl0J3MgdXNlZCB0byBtYWtlIHRpbWVyLWJhc2VkIHNjaGVkdWxpbmcgdHJlZS1zaGFrYWJsZS5cbiAqIElmIGBtaW5pbXVtYCBvciBgYWZ0ZXJgIHBhcmFtZXRlcnMgYXJlIHVzZWQsIGNvbXBpbGVyIGdlbmVyYXRlcyBhbiBleHRyYVxuICogYXJndW1lbnQgZm9yIHRoZSBgybXJtWRlZmVyYCBpbnN0cnVjdGlvbiwgd2hpY2ggcmVmZXJlbmNlcyBhIHRpbWVyLWJhc2VkXG4gKiBpbXBsZW1lbnRhdGlvbi5cbiAqL1xubGV0IGFwcGx5RGVmZXJCbG9ja1N0YXRlV2l0aFNjaGVkdWxpbmdJbXBsOiAodHlwZW9mIGFwcGx5RGVmZXJCbG9ja1N0YXRlKXxudWxsID0gbnVsbDtcblxuLyoqXG4gKiBFbmFibGVzIHRpbWVyLXJlbGF0ZWQgc2NoZWR1bGluZyBpZiBgYWZ0ZXJgIG9yIGBtaW5pbXVtYCBwYXJhbWV0ZXJzIGFyZSBzZXR1cFxuICogb24gdGhlIGBAbG9hZGluZ2Agb3IgYEBwbGFjZWhvbGRlcmAgYmxvY2tzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gybXJtWRlZmVyRW5hYmxlVGltZXJTY2hlZHVsaW5nKFxuICAgIHRWaWV3OiBUVmlldywgdERldGFpbHM6IFREZWZlckJsb2NrRGV0YWlscywgcGxhY2Vob2xkZXJDb25maWdJbmRleD86IG51bWJlcnxudWxsLFxuICAgIGxvYWRpbmdDb25maWdJbmRleD86IG51bWJlcnxudWxsKSB7XG4gIGNvbnN0IHRWaWV3Q29uc3RzID0gdFZpZXcuY29uc3RzO1xuICBpZiAocGxhY2Vob2xkZXJDb25maWdJbmRleCAhPSBudWxsKSB7XG4gICAgdERldGFpbHMucGxhY2Vob2xkZXJCbG9ja0NvbmZpZyA9XG4gICAgICAgIGdldENvbnN0YW50PERlZmVycmVkUGxhY2Vob2xkZXJCbG9ja0NvbmZpZz4odFZpZXdDb25zdHMsIHBsYWNlaG9sZGVyQ29uZmlnSW5kZXgpO1xuICB9XG4gIGlmIChsb2FkaW5nQ29uZmlnSW5kZXggIT0gbnVsbCkge1xuICAgIHREZXRhaWxzLmxvYWRpbmdCbG9ja0NvbmZpZyA9XG4gICAgICAgIGdldENvbnN0YW50PERlZmVycmVkTG9hZGluZ0Jsb2NrQ29uZmlnPih0Vmlld0NvbnN0cywgbG9hZGluZ0NvbmZpZ0luZGV4KTtcbiAgfVxuXG4gIC8vIEVuYWJsZSBpbXBsZW1lbnRhdGlvbiB0aGF0IHN1cHBvcnRzIHRpbWVyLWJhc2VkIHNjaGVkdWxpbmcuXG4gIGlmIChhcHBseURlZmVyQmxvY2tTdGF0ZVdpdGhTY2hlZHVsaW5nSW1wbCA9PT0gbnVsbCkge1xuICAgIGFwcGx5RGVmZXJCbG9ja1N0YXRlV2l0aFNjaGVkdWxpbmdJbXBsID0gYXBwbHlEZWZlckJsb2NrU3RhdGVXaXRoU2NoZWR1bGluZztcbiAgfVxufVxuXG4vKipcbiAqIENyZWF0ZXMgcnVudGltZSBkYXRhIHN0cnVjdHVyZXMgZm9yIGRlZmVyIGJsb2Nrcy5cbiAqXG4gKiBAcGFyYW0gaW5kZXggSW5kZXggb2YgdGhlIGBkZWZlcmAgaW5zdHJ1Y3Rpb24uXG4gKiBAcGFyYW0gcHJpbWFyeVRtcGxJbmRleCBJbmRleCBvZiB0aGUgdGVtcGxhdGUgd2l0aCB0aGUgcHJpbWFyeSBibG9jayBjb250ZW50LlxuICogQHBhcmFtIGRlcGVuZGVuY3lSZXNvbHZlckZuIEZ1bmN0aW9uIHRoYXQgY29udGFpbnMgZGVwZW5kZW5jaWVzIGZvciB0aGlzIGRlZmVyIGJsb2NrLlxuICogQHBhcmFtIGxvYWRpbmdUbXBsSW5kZXggSW5kZXggb2YgdGhlIHRlbXBsYXRlIHdpdGggdGhlIGxvYWRpbmcgYmxvY2sgY29udGVudC5cbiAqIEBwYXJhbSBwbGFjZWhvbGRlclRtcGxJbmRleCBJbmRleCBvZiB0aGUgdGVtcGxhdGUgd2l0aCB0aGUgcGxhY2Vob2xkZXIgYmxvY2sgY29udGVudC5cbiAqIEBwYXJhbSBlcnJvclRtcGxJbmRleCBJbmRleCBvZiB0aGUgdGVtcGxhdGUgd2l0aCB0aGUgZXJyb3IgYmxvY2sgY29udGVudC5cbiAqIEBwYXJhbSBsb2FkaW5nQ29uZmlnSW5kZXggSW5kZXggaW4gdGhlIGNvbnN0YW50cyBhcnJheSBvZiB0aGUgY29uZmlndXJhdGlvbiBvZiB0aGUgbG9hZGluZy5cbiAqICAgICBibG9jay5cbiAqIEBwYXJhbSBwbGFjZWhvbGRlckNvbmZpZ0luZGV4IEluZGV4IGluIHRoZSBjb25zdGFudHMgYXJyYXkgb2YgdGhlIGNvbmZpZ3VyYXRpb24gb2YgdGhlXG4gKiAgICAgcGxhY2Vob2xkZXIgYmxvY2suXG4gKiBAcGFyYW0gZW5hYmxlVGltZXJTY2hlZHVsaW5nIEZ1bmN0aW9uIHRoYXQgZW5hYmxlcyB0aW1lci1yZWxhdGVkIHNjaGVkdWxpbmcgaWYgYGFmdGVyYFxuICogICAgIG9yIGBtaW5pbXVtYCBwYXJhbWV0ZXJzIGFyZSBzZXR1cCBvbiB0aGUgYEBsb2FkaW5nYCBvciBgQHBsYWNlaG9sZGVyYCBibG9ja3MuXG4gKlxuICogQGNvZGVHZW5BcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIMm1ybVkZWZlcihcbiAgICBpbmRleDogbnVtYmVyLCBwcmltYXJ5VG1wbEluZGV4OiBudW1iZXIsIGRlcGVuZGVuY3lSZXNvbHZlckZuPzogRGVwZW5kZW5jeVJlc29sdmVyRm58bnVsbCxcbiAgICBsb2FkaW5nVG1wbEluZGV4PzogbnVtYmVyfG51bGwsIHBsYWNlaG9sZGVyVG1wbEluZGV4PzogbnVtYmVyfG51bGwsXG4gICAgZXJyb3JUbXBsSW5kZXg/OiBudW1iZXJ8bnVsbCwgbG9hZGluZ0NvbmZpZ0luZGV4PzogbnVtYmVyfG51bGwsXG4gICAgcGxhY2Vob2xkZXJDb25maWdJbmRleD86IG51bWJlcnxudWxsLFxuICAgIGVuYWJsZVRpbWVyU2NoZWR1bGluZz86IHR5cGVvZiDJtcm1ZGVmZXJFbmFibGVUaW1lclNjaGVkdWxpbmcpIHtcbiAgY29uc3QgbFZpZXcgPSBnZXRMVmlldygpO1xuICBjb25zdCB0VmlldyA9IGdldFRWaWV3KCk7XG4gIGNvbnN0IGFkanVzdGVkSW5kZXggPSBpbmRleCArIEhFQURFUl9PRkZTRVQ7XG5cbiAgybXJtXRlbXBsYXRlKGluZGV4LCBudWxsLCAwLCAwKTtcblxuICBpZiAodFZpZXcuZmlyc3RDcmVhdGVQYXNzKSB7XG4gICAgY29uc3QgdERldGFpbHM6IFREZWZlckJsb2NrRGV0YWlscyA9IHtcbiAgICAgIHByaW1hcnlUbXBsSW5kZXgsXG4gICAgICBsb2FkaW5nVG1wbEluZGV4OiBsb2FkaW5nVG1wbEluZGV4ID8/IG51bGwsXG4gICAgICBwbGFjZWhvbGRlclRtcGxJbmRleDogcGxhY2Vob2xkZXJUbXBsSW5kZXggPz8gbnVsbCxcbiAgICAgIGVycm9yVG1wbEluZGV4OiBlcnJvclRtcGxJbmRleCA/PyBudWxsLFxuICAgICAgcGxhY2Vob2xkZXJCbG9ja0NvbmZpZzogbnVsbCxcbiAgICAgIGxvYWRpbmdCbG9ja0NvbmZpZzogbnVsbCxcbiAgICAgIGRlcGVuZGVuY3lSZXNvbHZlckZuOiBkZXBlbmRlbmN5UmVzb2x2ZXJGbiA/PyBudWxsLFxuICAgICAgbG9hZGluZ1N0YXRlOiBEZWZlckRlcGVuZGVuY2llc0xvYWRpbmdTdGF0ZS5OT1RfU1RBUlRFRCxcbiAgICAgIGxvYWRpbmdQcm9taXNlOiBudWxsLFxuICAgIH07XG4gICAgZW5hYmxlVGltZXJTY2hlZHVsaW5nPy4odFZpZXcsIHREZXRhaWxzLCBwbGFjZWhvbGRlckNvbmZpZ0luZGV4LCBsb2FkaW5nQ29uZmlnSW5kZXgpO1xuICAgIHNldFREZWZlckJsb2NrRGV0YWlscyh0VmlldywgYWRqdXN0ZWRJbmRleCwgdERldGFpbHMpO1xuICB9XG5cbiAgY29uc3QgdE5vZGUgPSBnZXRDdXJyZW50VE5vZGUoKSE7XG4gIGNvbnN0IGxDb250YWluZXIgPSBsVmlld1thZGp1c3RlZEluZGV4XTtcblxuICAvLyBJZiBoeWRyYXRpb24gaXMgZW5hYmxlZCwgbG9va3MgdXAgZGVoeWRyYXRlZCB2aWV3cyBpbiB0aGUgRE9NXG4gIC8vIHVzaW5nIGh5ZHJhdGlvbiBhbm5vdGF0aW9uIGluZm8gYW5kIHN0b3JlcyB0aG9zZSB2aWV3cyBvbiBMQ29udGFpbmVyLlxuICAvLyBJbiBjbGllbnQtb25seSBtb2RlLCB0aGlzIGZ1bmN0aW9uIGlzIGEgbm9vcC5cbiAgcG9wdWxhdGVEZWh5ZHJhdGVkVmlld3NJbkxDb250YWluZXIobENvbnRhaW5lciwgdE5vZGUsIGxWaWV3KTtcblxuICAvLyBJbml0IGluc3RhbmNlLXNwZWNpZmljIGRlZmVyIGRldGFpbHMgYW5kIHN0b3JlIGl0LlxuICBjb25zdCBsRGV0YWlsczogTERlZmVyQmxvY2tEZXRhaWxzID0gW1xuICAgIG51bGwsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBORVhUX0RFRkVSX0JMT0NLX1NUQVRFXG4gICAgRGVmZXJCbG9ja0ludGVybmFsU3RhdGUuSW5pdGlhbCwgIC8vIERFRkVSX0JMT0NLX1NUQVRFXG4gICAgbnVsbCwgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNUQVRFX0lTX0ZST1pFTl9VTlRJTFxuICAgIG51bGwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBMT0FESU5HX0FGVEVSX0NMRUFOVVBfRk5cbiAgXTtcbiAgc2V0TERlZmVyQmxvY2tEZXRhaWxzKGxWaWV3LCBhZGp1c3RlZEluZGV4LCBsRGV0YWlscyk7XG59XG5cbi8qKlxuICogTG9hZHMgZGVmZXIgYmxvY2sgZGVwZW5kZW5jaWVzIHdoZW4gYSB0cmlnZ2VyIHZhbHVlIGJlY29tZXMgdHJ1dGh5LlxuICogQGNvZGVHZW5BcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIMm1ybVkZWZlcldoZW4ocmF3VmFsdWU6IHVua25vd24pIHtcbiAgY29uc3QgbFZpZXcgPSBnZXRMVmlldygpO1xuICBjb25zdCBiaW5kaW5nSW5kZXggPSBuZXh0QmluZGluZ0luZGV4KCk7XG4gIGlmIChiaW5kaW5nVXBkYXRlZChsVmlldywgYmluZGluZ0luZGV4LCByYXdWYWx1ZSkpIHtcbiAgICBjb25zdCB2YWx1ZSA9IEJvb2xlYW4ocmF3VmFsdWUpOyAgLy8gaGFuZGxlIHRydXRoeSBvciBmYWxzeSB2YWx1ZXNcbiAgICBjb25zdCB0Tm9kZSA9IGdldFNlbGVjdGVkVE5vZGUoKTtcbiAgICBjb25zdCBsRGV0YWlscyA9IGdldExEZWZlckJsb2NrRGV0YWlscyhsVmlldywgdE5vZGUpO1xuICAgIGNvbnN0IHJlbmRlcmVkU3RhdGUgPSBsRGV0YWlsc1tERUZFUl9CTE9DS19TVEFURV07XG4gICAgaWYgKHZhbHVlID09PSBmYWxzZSAmJiByZW5kZXJlZFN0YXRlID09PSBEZWZlckJsb2NrSW50ZXJuYWxTdGF0ZS5Jbml0aWFsKSB7XG4gICAgICAvLyBJZiBub3RoaW5nIGlzIHJlbmRlcmVkIHlldCwgcmVuZGVyIGEgcGxhY2Vob2xkZXIgKGlmIGRlZmluZWQpLlxuICAgICAgcmVuZGVyUGxhY2Vob2xkZXIobFZpZXcsIHROb2RlKTtcbiAgICB9IGVsc2UgaWYgKFxuICAgICAgICB2YWx1ZSA9PT0gdHJ1ZSAmJlxuICAgICAgICAocmVuZGVyZWRTdGF0ZSA9PT0gRGVmZXJCbG9ja0ludGVybmFsU3RhdGUuSW5pdGlhbCB8fFxuICAgICAgICAgcmVuZGVyZWRTdGF0ZSA9PT0gRGVmZXJCbG9ja1N0YXRlLlBsYWNlaG9sZGVyKSkge1xuICAgICAgLy8gVGhlIGB3aGVuYCBjb25kaXRpb24gaGFzIGNoYW5nZWQgdG8gYHRydWVgLCB0cmlnZ2VyIGRlZmVyIGJsb2NrIGxvYWRpbmdcbiAgICAgIC8vIGlmIHRoZSBibG9jayBpcyBlaXRoZXIgaW4gaW5pdGlhbCAobm90aGluZyBpcyByZW5kZXJlZCkgb3IgYSBwbGFjZWhvbGRlclxuICAgICAgLy8gc3RhdGUuXG4gICAgICB0cmlnZ2VyRGVmZXJCbG9jayhsVmlldywgdE5vZGUpO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIFByZWZldGNoZXMgdGhlIGRlZmVycmVkIGNvbnRlbnQgd2hlbiBhIHZhbHVlIGJlY29tZXMgdHJ1dGh5LlxuICogQGNvZGVHZW5BcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIMm1ybVkZWZlclByZWZldGNoV2hlbihyYXdWYWx1ZTogdW5rbm93bikge1xuICBjb25zdCBsVmlldyA9IGdldExWaWV3KCk7XG4gIGNvbnN0IGJpbmRpbmdJbmRleCA9IG5leHRCaW5kaW5nSW5kZXgoKTtcblxuICBpZiAoYmluZGluZ1VwZGF0ZWQobFZpZXcsIGJpbmRpbmdJbmRleCwgcmF3VmFsdWUpKSB7XG4gICAgY29uc3QgdmFsdWUgPSBCb29sZWFuKHJhd1ZhbHVlKTsgIC8vIGhhbmRsZSB0cnV0aHkgb3IgZmFsc3kgdmFsdWVzXG4gICAgY29uc3QgdFZpZXcgPSBsVmlld1tUVklFV107XG4gICAgY29uc3QgdE5vZGUgPSBnZXRTZWxlY3RlZFROb2RlKCk7XG4gICAgY29uc3QgdERldGFpbHMgPSBnZXRURGVmZXJCbG9ja0RldGFpbHModFZpZXcsIHROb2RlKTtcbiAgICBpZiAodmFsdWUgPT09IHRydWUgJiYgdERldGFpbHMubG9hZGluZ1N0YXRlID09PSBEZWZlckRlcGVuZGVuY2llc0xvYWRpbmdTdGF0ZS5OT1RfU1RBUlRFRCkge1xuICAgICAgLy8gSWYgbG9hZGluZyBoYXMgbm90IGJlZW4gc3RhcnRlZCB5ZXQsIHRyaWdnZXIgaXQgbm93LlxuICAgICAgdHJpZ2dlclByZWZldGNoaW5nKHREZXRhaWxzLCBsVmlldyk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogU2V0cyB1cCBsb2dpYyB0byBoYW5kbGUgdGhlIGBvbiBpZGxlYCBkZWZlcnJlZCB0cmlnZ2VyLlxuICogQGNvZGVHZW5BcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIMm1ybVkZWZlck9uSWRsZSgpIHtcbiAgc2NoZWR1bGVEZWxheWVkVHJpZ2dlcihvbklkbGUpO1xufVxuXG4vKipcbiAqIFNldHMgdXAgbG9naWMgdG8gaGFuZGxlIHRoZSBgcHJlZmV0Y2ggb24gaWRsZWAgZGVmZXJyZWQgdHJpZ2dlci5cbiAqIEBjb2RlR2VuQXBpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiDJtcm1ZGVmZXJQcmVmZXRjaE9uSWRsZSgpIHtcbiAgc2NoZWR1bGVEZWxheWVkUHJlZmV0Y2hpbmcob25JZGxlLCBEZWZlckJsb2NrVHJpZ2dlcnMuT25JZGxlKTtcbn1cblxuLyoqXG4gKiBTZXRzIHVwIGxvZ2ljIHRvIGhhbmRsZSB0aGUgYG9uIGltbWVkaWF0ZWAgZGVmZXJyZWQgdHJpZ2dlci5cbiAqIEBjb2RlR2VuQXBpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiDJtcm1ZGVmZXJPbkltbWVkaWF0ZSgpIHtcbiAgY29uc3QgbFZpZXcgPSBnZXRMVmlldygpO1xuICBjb25zdCB0Tm9kZSA9IGdldEN1cnJlbnRUTm9kZSgpITtcbiAgY29uc3QgdFZpZXcgPSBsVmlld1tUVklFV107XG4gIGNvbnN0IHREZXRhaWxzID0gZ2V0VERlZmVyQmxvY2tEZXRhaWxzKHRWaWV3LCB0Tm9kZSk7XG5cbiAgLy8gUmVuZGVyIHBsYWNlaG9sZGVyIGJsb2NrIG9ubHkgaWYgbG9hZGluZyB0ZW1wbGF0ZSBpcyBub3QgcHJlc2VudFxuICAvLyB0byBhdm9pZCBjb250ZW50IGZsaWNrZXJpbmcsIHNpbmNlIGl0IHdvdWxkIGJlIGltbWVkaWF0ZWx5IHJlcGxhY2VkXG4gIC8vIGJ5IHRoZSBsb2FkaW5nIGJsb2NrLlxuICBpZiAodERldGFpbHMubG9hZGluZ1RtcGxJbmRleCA9PT0gbnVsbCkge1xuICAgIHJlbmRlclBsYWNlaG9sZGVyKGxWaWV3LCB0Tm9kZSk7XG4gIH1cbiAgdHJpZ2dlckRlZmVyQmxvY2sobFZpZXcsIHROb2RlKTtcbn1cblxuXG4vKipcbiAqIFNldHMgdXAgbG9naWMgdG8gaGFuZGxlIHRoZSBgcHJlZmV0Y2ggb24gaW1tZWRpYXRlYCBkZWZlcnJlZCB0cmlnZ2VyLlxuICogQGNvZGVHZW5BcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIMm1ybVkZWZlclByZWZldGNoT25JbW1lZGlhdGUoKSB7XG4gIGNvbnN0IGxWaWV3ID0gZ2V0TFZpZXcoKTtcbiAgY29uc3QgdE5vZGUgPSBnZXRDdXJyZW50VE5vZGUoKSE7XG4gIGNvbnN0IHRWaWV3ID0gbFZpZXdbVFZJRVddO1xuICBjb25zdCB0RGV0YWlscyA9IGdldFREZWZlckJsb2NrRGV0YWlscyh0VmlldywgdE5vZGUpO1xuXG4gIGlmICh0RGV0YWlscy5sb2FkaW5nU3RhdGUgPT09IERlZmVyRGVwZW5kZW5jaWVzTG9hZGluZ1N0YXRlLk5PVF9TVEFSVEVEKSB7XG4gICAgdHJpZ2dlclJlc291cmNlTG9hZGluZyh0RGV0YWlscywgbFZpZXcpO1xuICB9XG59XG5cbi8qKlxuICogQ3JlYXRlcyBydW50aW1lIGRhdGEgc3RydWN0dXJlcyBmb3IgdGhlIGBvbiB0aW1lcmAgZGVmZXJyZWQgdHJpZ2dlci5cbiAqIEBwYXJhbSBkZWxheSBBbW91bnQgb2YgdGltZSB0byB3YWl0IGJlZm9yZSBsb2FkaW5nIHRoZSBjb250ZW50LlxuICogQGNvZGVHZW5BcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIMm1ybVkZWZlck9uVGltZXIoZGVsYXk6IG51bWJlcikge1xuICBzY2hlZHVsZURlbGF5ZWRUcmlnZ2VyKG9uVGltZXIoZGVsYXkpKTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIHJ1bnRpbWUgZGF0YSBzdHJ1Y3R1cmVzIGZvciB0aGUgYHByZWZldGNoIG9uIHRpbWVyYCBkZWZlcnJlZCB0cmlnZ2VyLlxuICogQHBhcmFtIGRlbGF5IEFtb3VudCBvZiB0aW1lIHRvIHdhaXQgYmVmb3JlIHByZWZldGNoaW5nIHRoZSBjb250ZW50LlxuICogQGNvZGVHZW5BcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIMm1ybVkZWZlclByZWZldGNoT25UaW1lcihkZWxheTogbnVtYmVyKSB7XG4gIHNjaGVkdWxlRGVsYXllZFByZWZldGNoaW5nKG9uVGltZXIoZGVsYXkpLCBEZWZlckJsb2NrVHJpZ2dlcnMuT25UaW1lcik7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBydW50aW1lIGRhdGEgc3RydWN0dXJlcyBmb3IgdGhlIGBvbiBob3ZlcmAgZGVmZXJyZWQgdHJpZ2dlci5cbiAqIEBwYXJhbSB0cmlnZ2VySW5kZXggSW5kZXggYXQgd2hpY2ggdG8gZmluZCB0aGUgdHJpZ2dlciBlbGVtZW50LlxuICogQHBhcmFtIHdhbGtVcFRpbWVzIE51bWJlciBvZiB0aW1lcyB0byB3YWxrIHVwL2Rvd24gdGhlIHRyZWUgaGllcmFyY2h5IHRvIGZpbmQgdGhlIHRyaWdnZXIuXG4gKiBAY29kZUdlbkFwaVxuICovXG5leHBvcnQgZnVuY3Rpb24gybXJtWRlZmVyT25Ib3Zlcih0cmlnZ2VySW5kZXg6IG51bWJlciwgd2Fsa1VwVGltZXM/OiBudW1iZXIpIHtcbiAgY29uc3QgbFZpZXcgPSBnZXRMVmlldygpO1xuICBjb25zdCB0Tm9kZSA9IGdldEN1cnJlbnRUTm9kZSgpITtcblxuICByZW5kZXJQbGFjZWhvbGRlcihsVmlldywgdE5vZGUpO1xuICByZWdpc3RlckRvbVRyaWdnZXIoXG4gICAgICBsVmlldywgdE5vZGUsIHRyaWdnZXJJbmRleCwgd2Fsa1VwVGltZXMsIG9uSG92ZXIsICgpID0+IHRyaWdnZXJEZWZlckJsb2NrKGxWaWV3LCB0Tm9kZSkpO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgcnVudGltZSBkYXRhIHN0cnVjdHVyZXMgZm9yIHRoZSBgcHJlZmV0Y2ggb24gaG92ZXJgIGRlZmVycmVkIHRyaWdnZXIuXG4gKiBAcGFyYW0gdHJpZ2dlckluZGV4IEluZGV4IGF0IHdoaWNoIHRvIGZpbmQgdGhlIHRyaWdnZXIgZWxlbWVudC5cbiAqIEBwYXJhbSB3YWxrVXBUaW1lcyBOdW1iZXIgb2YgdGltZXMgdG8gd2FsayB1cC9kb3duIHRoZSB0cmVlIGhpZXJhcmNoeSB0byBmaW5kIHRoZSB0cmlnZ2VyLlxuICogQGNvZGVHZW5BcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIMm1ybVkZWZlclByZWZldGNoT25Ib3Zlcih0cmlnZ2VySW5kZXg6IG51bWJlciwgd2Fsa1VwVGltZXM/OiBudW1iZXIpIHtcbiAgY29uc3QgbFZpZXcgPSBnZXRMVmlldygpO1xuICBjb25zdCB0Tm9kZSA9IGdldEN1cnJlbnRUTm9kZSgpITtcbiAgY29uc3QgdFZpZXcgPSBsVmlld1tUVklFV107XG4gIGNvbnN0IHREZXRhaWxzID0gZ2V0VERlZmVyQmxvY2tEZXRhaWxzKHRWaWV3LCB0Tm9kZSk7XG5cbiAgaWYgKHREZXRhaWxzLmxvYWRpbmdTdGF0ZSA9PT0gRGVmZXJEZXBlbmRlbmNpZXNMb2FkaW5nU3RhdGUuTk9UX1NUQVJURUQpIHtcbiAgICByZWdpc3RlckRvbVRyaWdnZXIoXG4gICAgICAgIGxWaWV3LCB0Tm9kZSwgdHJpZ2dlckluZGV4LCB3YWxrVXBUaW1lcywgb25Ib3ZlcixcbiAgICAgICAgKCkgPT4gdHJpZ2dlclByZWZldGNoaW5nKHREZXRhaWxzLCBsVmlldykpO1xuICB9XG59XG5cbi8qKlxuICogQ3JlYXRlcyBydW50aW1lIGRhdGEgc3RydWN0dXJlcyBmb3IgdGhlIGBvbiBpbnRlcmFjdGlvbmAgZGVmZXJyZWQgdHJpZ2dlci5cbiAqIEBwYXJhbSB0cmlnZ2VySW5kZXggSW5kZXggYXQgd2hpY2ggdG8gZmluZCB0aGUgdHJpZ2dlciBlbGVtZW50LlxuICogQHBhcmFtIHdhbGtVcFRpbWVzIE51bWJlciBvZiB0aW1lcyB0byB3YWxrIHVwL2Rvd24gdGhlIHRyZWUgaGllcmFyY2h5IHRvIGZpbmQgdGhlIHRyaWdnZXIuXG4gKiBAY29kZUdlbkFwaVxuICovXG5leHBvcnQgZnVuY3Rpb24gybXJtWRlZmVyT25JbnRlcmFjdGlvbih0cmlnZ2VySW5kZXg6IG51bWJlciwgd2Fsa1VwVGltZXM/OiBudW1iZXIpIHtcbiAgY29uc3QgbFZpZXcgPSBnZXRMVmlldygpO1xuICBjb25zdCB0Tm9kZSA9IGdldEN1cnJlbnRUTm9kZSgpITtcblxuICByZW5kZXJQbGFjZWhvbGRlcihsVmlldywgdE5vZGUpO1xuICByZWdpc3RlckRvbVRyaWdnZXIoXG4gICAgICBsVmlldywgdE5vZGUsIHRyaWdnZXJJbmRleCwgd2Fsa1VwVGltZXMsIG9uSW50ZXJhY3Rpb24sXG4gICAgICAoKSA9PiB0cmlnZ2VyRGVmZXJCbG9jayhsVmlldywgdE5vZGUpKTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIHJ1bnRpbWUgZGF0YSBzdHJ1Y3R1cmVzIGZvciB0aGUgYHByZWZldGNoIG9uIGludGVyYWN0aW9uYCBkZWZlcnJlZCB0cmlnZ2VyLlxuICogQHBhcmFtIHRyaWdnZXJJbmRleCBJbmRleCBhdCB3aGljaCB0byBmaW5kIHRoZSB0cmlnZ2VyIGVsZW1lbnQuXG4gKiBAcGFyYW0gd2Fsa1VwVGltZXMgTnVtYmVyIG9mIHRpbWVzIHRvIHdhbGsgdXAvZG93biB0aGUgdHJlZSBoaWVyYXJjaHkgdG8gZmluZCB0aGUgdHJpZ2dlci5cbiAqIEBjb2RlR2VuQXBpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiDJtcm1ZGVmZXJQcmVmZXRjaE9uSW50ZXJhY3Rpb24odHJpZ2dlckluZGV4OiBudW1iZXIsIHdhbGtVcFRpbWVzPzogbnVtYmVyKSB7XG4gIGNvbnN0IGxWaWV3ID0gZ2V0TFZpZXcoKTtcbiAgY29uc3QgdE5vZGUgPSBnZXRDdXJyZW50VE5vZGUoKSE7XG4gIGNvbnN0IHRWaWV3ID0gbFZpZXdbVFZJRVddO1xuICBjb25zdCB0RGV0YWlscyA9IGdldFREZWZlckJsb2NrRGV0YWlscyh0VmlldywgdE5vZGUpO1xuXG4gIGlmICh0RGV0YWlscy5sb2FkaW5nU3RhdGUgPT09IERlZmVyRGVwZW5kZW5jaWVzTG9hZGluZ1N0YXRlLk5PVF9TVEFSVEVEKSB7XG4gICAgcmVnaXN0ZXJEb21UcmlnZ2VyKFxuICAgICAgICBsVmlldywgdE5vZGUsIHRyaWdnZXJJbmRleCwgd2Fsa1VwVGltZXMsIG9uSW50ZXJhY3Rpb24sXG4gICAgICAgICgpID0+IHRyaWdnZXJQcmVmZXRjaGluZyh0RGV0YWlscywgbFZpZXcpKTtcbiAgfVxufVxuXG4vKipcbiAqIENyZWF0ZXMgcnVudGltZSBkYXRhIHN0cnVjdHVyZXMgZm9yIHRoZSBgb24gdmlld3BvcnRgIGRlZmVycmVkIHRyaWdnZXIuXG4gKiBAcGFyYW0gdHJpZ2dlckluZGV4IEluZGV4IGF0IHdoaWNoIHRvIGZpbmQgdGhlIHRyaWdnZXIgZWxlbWVudC5cbiAqIEBwYXJhbSB3YWxrVXBUaW1lcyBOdW1iZXIgb2YgdGltZXMgdG8gd2FsayB1cC9kb3duIHRoZSB0cmVlIGhpZXJhcmNoeSB0byBmaW5kIHRoZSB0cmlnZ2VyLlxuICogQGNvZGVHZW5BcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIMm1ybVkZWZlck9uVmlld3BvcnQodHJpZ2dlckluZGV4OiBudW1iZXIsIHdhbGtVcFRpbWVzPzogbnVtYmVyKSB7XG4gIGNvbnN0IGxWaWV3ID0gZ2V0TFZpZXcoKTtcbiAgY29uc3QgdE5vZGUgPSBnZXRDdXJyZW50VE5vZGUoKSE7XG5cbiAgcmVuZGVyUGxhY2Vob2xkZXIobFZpZXcsIHROb2RlKTtcbiAgcmVnaXN0ZXJEb21UcmlnZ2VyKFxuICAgICAgbFZpZXcsIHROb2RlLCB0cmlnZ2VySW5kZXgsIHdhbGtVcFRpbWVzLCBvblZpZXdwb3J0LCAoKSA9PiB0cmlnZ2VyRGVmZXJCbG9jayhsVmlldywgdE5vZGUpKTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIHJ1bnRpbWUgZGF0YSBzdHJ1Y3R1cmVzIGZvciB0aGUgYHByZWZldGNoIG9uIHZpZXdwb3J0YCBkZWZlcnJlZCB0cmlnZ2VyLlxuICogQHBhcmFtIHRyaWdnZXJJbmRleCBJbmRleCBhdCB3aGljaCB0byBmaW5kIHRoZSB0cmlnZ2VyIGVsZW1lbnQuXG4gKiBAcGFyYW0gd2Fsa1VwVGltZXMgTnVtYmVyIG9mIHRpbWVzIHRvIHdhbGsgdXAvZG93biB0aGUgdHJlZSBoaWVyYXJjaHkgdG8gZmluZCB0aGUgdHJpZ2dlci5cbiAqIEBjb2RlR2VuQXBpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiDJtcm1ZGVmZXJQcmVmZXRjaE9uVmlld3BvcnQodHJpZ2dlckluZGV4OiBudW1iZXIsIHdhbGtVcFRpbWVzPzogbnVtYmVyKSB7XG4gIGNvbnN0IGxWaWV3ID0gZ2V0TFZpZXcoKTtcbiAgY29uc3QgdE5vZGUgPSBnZXRDdXJyZW50VE5vZGUoKSE7XG4gIGNvbnN0IHRWaWV3ID0gbFZpZXdbVFZJRVddO1xuICBjb25zdCB0RGV0YWlscyA9IGdldFREZWZlckJsb2NrRGV0YWlscyh0VmlldywgdE5vZGUpO1xuXG4gIGlmICh0RGV0YWlscy5sb2FkaW5nU3RhdGUgPT09IERlZmVyRGVwZW5kZW5jaWVzTG9hZGluZ1N0YXRlLk5PVF9TVEFSVEVEKSB7XG4gICAgcmVnaXN0ZXJEb21UcmlnZ2VyKFxuICAgICAgICBsVmlldywgdE5vZGUsIHRyaWdnZXJJbmRleCwgd2Fsa1VwVGltZXMsIG9uVmlld3BvcnQsXG4gICAgICAgICgpID0+IHRyaWdnZXJQcmVmZXRjaGluZyh0RGV0YWlscywgbFZpZXcpKTtcbiAgfVxufVxuXG4vKioqKioqKioqKiBIZWxwZXIgZnVuY3Rpb25zICoqKioqKioqKiovXG5cbi8qKlxuICogU2NoZWR1bGVzIHRyaWdnZXJpbmcgb2YgYSBkZWZlciBibG9jayBmb3IgYG9uIGlkbGVgIGFuZCBgb24gdGltZXJgIGNvbmRpdGlvbnMuXG4gKi9cbmZ1bmN0aW9uIHNjaGVkdWxlRGVsYXllZFRyaWdnZXIoXG4gICAgc2NoZWR1bGVGbjogKGNhbGxiYWNrOiBWb2lkRnVuY3Rpb24sIGxWaWV3OiBMVmlldywgd2l0aExWaWV3Q2xlYW51cDogYm9vbGVhbikgPT4gVm9pZEZ1bmN0aW9uKSB7XG4gIGNvbnN0IGxWaWV3ID0gZ2V0TFZpZXcoKTtcbiAgY29uc3QgdE5vZGUgPSBnZXRDdXJyZW50VE5vZGUoKSE7XG5cbiAgcmVuZGVyUGxhY2Vob2xkZXIobFZpZXcsIHROb2RlKTtcbiAgc2NoZWR1bGVGbigoKSA9PiB0cmlnZ2VyRGVmZXJCbG9jayhsVmlldywgdE5vZGUpLCBsVmlldywgdHJ1ZSAvKiB3aXRoTFZpZXdDbGVhbnVwICovKTtcbn1cblxuLyoqXG4gKiBTY2hlZHVsZXMgcHJlZmV0Y2hpbmcgZm9yIGBvbiBpZGxlYCBhbmQgYG9uIHRpbWVyYCB0cmlnZ2Vycy5cbiAqXG4gKiBAcGFyYW0gc2NoZWR1bGVGbiBBIGZ1bmN0aW9uIHRoYXQgZG9lcyB0aGUgc2NoZWR1bGluZy5cbiAqIEBwYXJhbSB0cmlnZ2VyIEEgdHJpZ2dlciB0aGF0IGluaXRpYXRlZCBzY2hlZHVsaW5nLlxuICovXG5mdW5jdGlvbiBzY2hlZHVsZURlbGF5ZWRQcmVmZXRjaGluZyhcbiAgICBzY2hlZHVsZUZuOiAoY2FsbGJhY2s6IFZvaWRGdW5jdGlvbiwgbFZpZXc6IExWaWV3LCB3aXRoTFZpZXdDbGVhbnVwOiBib29sZWFuKSA9PiBWb2lkRnVuY3Rpb24sXG4gICAgdHJpZ2dlcjogRGVmZXJCbG9ja1RyaWdnZXJzKSB7XG4gIGNvbnN0IGxWaWV3ID0gZ2V0TFZpZXcoKTtcbiAgY29uc3QgdE5vZGUgPSBnZXRDdXJyZW50VE5vZGUoKSE7XG4gIGNvbnN0IHRWaWV3ID0gbFZpZXdbVFZJRVddO1xuICBjb25zdCB0RGV0YWlscyA9IGdldFREZWZlckJsb2NrRGV0YWlscyh0VmlldywgdE5vZGUpO1xuXG4gIGlmICh0RGV0YWlscy5sb2FkaW5nU3RhdGUgPT09IERlZmVyRGVwZW5kZW5jaWVzTG9hZGluZ1N0YXRlLk5PVF9TVEFSVEVEKSB7XG4gICAgLy8gUHJldmVudCBzY2hlZHVsaW5nIG1vcmUgdGhhbiBvbmUgcHJlZmV0Y2ggaW5pdCBjYWxsXG4gICAgLy8gZm9yIGVhY2ggZGVmZXIgYmxvY2suIEZvciB0aGlzIHJlYXNvbiB3ZSB1c2Ugb25seSBhIHRyaWdnZXJcbiAgICAvLyBpZGVudGlmaWVyIGluIGEga2V5LCBzbyBhbGwgaW5zdGFuY2VzIHdvdWxkIHVzZSB0aGUgc2FtZSBrZXkuXG4gICAgY29uc3Qga2V5ID0gU3RyaW5nKHRyaWdnZXIpO1xuICAgIGNvbnN0IGluamVjdG9yID0gbFZpZXdbSU5KRUNUT1JdITtcbiAgICBjb25zdCBtYW5hZ2VyID0gaW5qZWN0b3IuZ2V0KERlZmVyQmxvY2tDbGVhbnVwTWFuYWdlcik7XG4gICAgaWYgKCFtYW5hZ2VyLmhhcyh0RGV0YWlscywga2V5KSkge1xuICAgICAgLy8gSW4gY2FzZSBvZiBwcmVmZXRjaGluZywgd2UgaW50ZW50aW9uYWxseSBhdm9pZCBjYW5jZWxsaW5nIHJlc291cmNlIGxvYWRpbmcgaWZcbiAgICAgIC8vIGFuIHVuZGVybHlpbmcgTFZpZXcgZ2V0IGRlc3Ryb3llZCAodGh1cyBwYXNzaW5nIGBudWxsYCBhcyBhIHNlY29uZCBhcmd1bWVudCksXG4gICAgICAvLyBiZWNhdXNlIHRoZXJlIG1pZ2h0IGJlIG90aGVyIExWaWV3cyAodGhhdCByZXByZXNlbnQgZW1iZWRkZWQgdmlld3MpIHRoYXRcbiAgICAgIC8vIGRlcGVuZCBvbiByZXNvdXJjZSBsb2FkaW5nLlxuICAgICAgY29uc3QgcHJlZmV0Y2ggPSAoKSA9PiB0cmlnZ2VyUHJlZmV0Y2hpbmcodERldGFpbHMsIGxWaWV3KTtcbiAgICAgIGNvbnN0IGNsZWFudXBGbiA9IHNjaGVkdWxlRm4ocHJlZmV0Y2gsIGxWaWV3LCBmYWxzZSAvKiB3aXRoTFZpZXdDbGVhbnVwICovKTtcbiAgICAgIHJlZ2lzdGVyVERldGFpbHNDbGVhbnVwKGluamVjdG9yLCB0RGV0YWlscywga2V5LCBjbGVhbnVwRm4pO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIEhlbHBlciBmdW5jdGlvbiB0byBnZXQgdGhlIExWaWV3IGluIHdoaWNoIGEgZGVmZXJyZWQgYmxvY2sncyB0cmlnZ2VyIGlzIHJlbmRlcmVkLlxuICogQHBhcmFtIGRlZmVycmVkSG9zdExWaWV3IExWaWV3IGluIHdoaWNoIHRoZSBkZWZlcnJlZCBibG9jayBpcyBkZWZpbmVkLlxuICogQHBhcmFtIGRlZmVycmVkVE5vZGUgVE5vZGUgZGVmaW5pbmcgdGhlIGRlZmVycmVkIGJsb2NrLlxuICogQHBhcmFtIHdhbGtVcFRpbWVzIE51bWJlciBvZiB0aW1lcyB0byBnbyB1cCBpbiB0aGUgdmlldyBoaWVyYXJjaHkgdG8gZmluZCB0aGUgdHJpZ2dlcidzIHZpZXcuXG4gKiAgIEEgbmVnYXRpdmUgdmFsdWUgbWVhbnMgdGhhdCB0aGUgdHJpZ2dlciBpcyBpbnNpZGUgdGhlIGJsb2NrJ3MgcGxhY2Vob2xkZXIsIHdoaWxlIGFuIHVuZGVmaW5lZFxuICogICB2YWx1ZSBtZWFucyB0aGF0IHRoZSB0cmlnZ2VyIGlzIGluIHRoZSBzYW1lIExWaWV3IGFzIHRoZSBkZWZlcnJlZCBibG9jay5cbiAqL1xuZnVuY3Rpb24gZ2V0VHJpZ2dlckxWaWV3KFxuICAgIGRlZmVycmVkSG9zdExWaWV3OiBMVmlldywgZGVmZXJyZWRUTm9kZTogVE5vZGUsIHdhbGtVcFRpbWVzOiBudW1iZXJ8dW5kZWZpbmVkKTogTFZpZXd8bnVsbCB7XG4gIC8vIFRoZSB0cmlnZ2VyIGlzIGluIHRoZSBzYW1lIHZpZXcsIHdlIGRvbid0IG5lZWQgdG8gdHJhdmVyc2UuXG4gIGlmICh3YWxrVXBUaW1lcyA9PSBudWxsKSB7XG4gICAgcmV0dXJuIGRlZmVycmVkSG9zdExWaWV3O1xuICB9XG5cbiAgLy8gQSBwb3NpdGl2ZSB2YWx1ZSBvciB6ZXJvIG1lYW5zIHRoYXQgdGhlIHRyaWdnZXIgaXMgaW4gYSBwYXJlbnQgdmlldy5cbiAgaWYgKHdhbGtVcFRpbWVzID49IDApIHtcbiAgICByZXR1cm4gd2Fsa1VwVmlld3Mod2Fsa1VwVGltZXMsIGRlZmVycmVkSG9zdExWaWV3KTtcbiAgfVxuXG4gIC8vIElmIHRoZSB2YWx1ZSBpcyBuZWdhdGl2ZSwgaXQgbWVhbnMgdGhhdCB0aGUgdHJpZ2dlciBpcyBpbnNpZGUgdGhlIHBsYWNlaG9sZGVyLlxuICBjb25zdCBkZWZlcnJlZENvbnRhaW5lciA9IGRlZmVycmVkSG9zdExWaWV3W2RlZmVycmVkVE5vZGUuaW5kZXhdO1xuICBuZ0Rldk1vZGUgJiYgYXNzZXJ0TENvbnRhaW5lcihkZWZlcnJlZENvbnRhaW5lcik7XG4gIGNvbnN0IHRyaWdnZXJMVmlldyA9IGRlZmVycmVkQ29udGFpbmVyW0NPTlRBSU5FUl9IRUFERVJfT0ZGU0VUXSA/PyBudWxsO1xuXG4gIC8vIFdlIG5lZWQgdG8gbnVsbCBjaGVjaywgYmVjYXVzZSB0aGUgcGxhY2Vob2xkZXIgbWlnaHQgbm90IGhhdmUgYmVlbiByZW5kZXJlZCB5ZXQuXG4gIGlmIChuZ0Rldk1vZGUgJiYgdHJpZ2dlckxWaWV3ICE9PSBudWxsKSB7XG4gICAgY29uc3QgbERldGFpbHMgPSBnZXRMRGVmZXJCbG9ja0RldGFpbHMoZGVmZXJyZWRIb3N0TFZpZXcsIGRlZmVycmVkVE5vZGUpO1xuICAgIGNvbnN0IHJlbmRlcmVkU3RhdGUgPSBsRGV0YWlsc1tERUZFUl9CTE9DS19TVEFURV07XG4gICAgYXNzZXJ0RXF1YWwoXG4gICAgICAgIHJlbmRlcmVkU3RhdGUsIERlZmVyQmxvY2tTdGF0ZS5QbGFjZWhvbGRlcixcbiAgICAgICAgJ0V4cGVjdGVkIGEgcGxhY2Vob2xkZXIgdG8gYmUgcmVuZGVyZWQgaW4gdGhpcyBkZWZlciBibG9jay4nKTtcbiAgICBhc3NlcnRMVmlldyh0cmlnZ2VyTFZpZXcpO1xuICB9XG5cbiAgcmV0dXJuIHRyaWdnZXJMVmlldztcbn1cblxuLyoqXG4gKiBHZXRzIHRoZSBlbGVtZW50IHRoYXQgYSBkZWZlcnJlZCBibG9jaydzIHRyaWdnZXIgaXMgcG9pbnRpbmcgdG8uXG4gKiBAcGFyYW0gdHJpZ2dlckxWaWV3IExWaWV3IGluIHdoaWNoIHRoZSB0cmlnZ2VyIGlzIGRlZmluZWQuXG4gKiBAcGFyYW0gdHJpZ2dlckluZGV4IEluZGV4IGF0IHdoaWNoIHRoZSB0cmlnZ2VyIGVsZW1lbnQgc2hvdWxkJ3ZlIGJlZW4gcmVuZGVyZWQuXG4gKi9cbmZ1bmN0aW9uIGdldFRyaWdnZXJFbGVtZW50KHRyaWdnZXJMVmlldzogTFZpZXcsIHRyaWdnZXJJbmRleDogbnVtYmVyKTogRWxlbWVudCB7XG4gIGNvbnN0IGVsZW1lbnQgPSBnZXROYXRpdmVCeUluZGV4KEhFQURFUl9PRkZTRVQgKyB0cmlnZ2VySW5kZXgsIHRyaWdnZXJMVmlldyk7XG4gIG5nRGV2TW9kZSAmJiBhc3NlcnRFbGVtZW50KGVsZW1lbnQpO1xuICByZXR1cm4gZWxlbWVudCBhcyBFbGVtZW50O1xufVxuXG4vKipcbiAqIFJlZ2lzdGVycyBhIERPTS1ub2RlIGJhc2VkIHRyaWdnZXIuXG4gKiBAcGFyYW0gaW5pdGlhbExWaWV3IExWaWV3IGluIHdoaWNoIHRoZSBkZWZlciBibG9jayBpcyByZW5kZXJlZC5cbiAqIEBwYXJhbSB0Tm9kZSBUTm9kZSByZXByZXNlbnRpbmcgdGhlIGRlZmVyIGJsb2NrLlxuICogQHBhcmFtIHRyaWdnZXJJbmRleCBJbmRleCBhdCB3aGljaCB0byBmaW5kIHRoZSB0cmlnZ2VyIGVsZW1lbnQuXG4gKiBAcGFyYW0gd2Fsa1VwVGltZXMgTnVtYmVyIG9mIHRpbWVzIHRvIGdvIHVwL2Rvd24gaW4gdGhlIHZpZXcgaGllcmFyY2h5IHRvIGZpbmQgdGhlIHRyaWdnZXIuXG4gKiBAcGFyYW0gcmVnaXN0ZXJGbiBGdW5jdGlvbiB0aGF0IHdpbGwgcmVnaXN0ZXIgdGhlIERPTSBldmVudHMuXG4gKiBAcGFyYW0gY2FsbGJhY2sgQ2FsbGJhY2sgdG8gYmUgaW52b2tlZCB3aGVuIHRoZSB0cmlnZ2VyIHJlY2VpdmVzIHRoZSBldmVudCB0aGF0IHNob3VsZCByZW5kZXJcbiAqICAgICB0aGUgZGVmZXJyZWQgYmxvY2suXG4gKi9cbmZ1bmN0aW9uIHJlZ2lzdGVyRG9tVHJpZ2dlcihcbiAgICBpbml0aWFsTFZpZXc6IExWaWV3LCB0Tm9kZTogVE5vZGUsIHRyaWdnZXJJbmRleDogbnVtYmVyLCB3YWxrVXBUaW1lczogbnVtYmVyfHVuZGVmaW5lZCxcbiAgICByZWdpc3RlckZuOiAoZWxlbWVudDogRWxlbWVudCwgY2FsbGJhY2s6IFZvaWRGdW5jdGlvbiwgaW5qZWN0b3I6IEluamVjdG9yKSA9PiBWb2lkRnVuY3Rpb24sXG4gICAgY2FsbGJhY2s6IFZvaWRGdW5jdGlvbikge1xuICBjb25zdCBpbmplY3RvciA9IGluaXRpYWxMVmlld1tJTkpFQ1RPUl0hO1xuXG4gIC8vIEFzc3VtcHRpb246IHRoZSBgYWZ0ZXJSZW5kZXJgIHJlZmVyZW5jZSBzaG91bGQgYmUgZGVzdHJveWVkXG4gIC8vIGF1dG9tYXRpY2FsbHkgc28gd2UgZG9uJ3QgbmVlZCB0byBrZWVwIHRyYWNrIG9mIGl0LlxuICBjb25zdCBhZnRlclJlbmRlclJlZiA9IGFmdGVyUmVuZGVyKCgpID0+IHtcbiAgICBjb25zdCBsRGV0YWlscyA9IGdldExEZWZlckJsb2NrRGV0YWlscyhpbml0aWFsTFZpZXcsIHROb2RlKTtcbiAgICBjb25zdCByZW5kZXJlZFN0YXRlID0gbERldGFpbHNbREVGRVJfQkxPQ0tfU1RBVEVdO1xuXG4gICAgLy8gSWYgdGhlIGJsb2NrIHdhcyBsb2FkZWQgYmVmb3JlIHRoZSB0cmlnZ2VyIHdhcyByZXNvbHZlZCwgd2UgZG9uJ3QgbmVlZCB0byBkbyBhbnl0aGluZy5cbiAgICBpZiAocmVuZGVyZWRTdGF0ZSAhPT0gRGVmZXJCbG9ja0ludGVybmFsU3RhdGUuSW5pdGlhbCAmJlxuICAgICAgICByZW5kZXJlZFN0YXRlICE9PSBEZWZlckJsb2NrU3RhdGUuUGxhY2Vob2xkZXIpIHtcbiAgICAgIGFmdGVyUmVuZGVyUmVmLmRlc3Ryb3koKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCB0cmlnZ2VyTFZpZXcgPSBnZXRUcmlnZ2VyTFZpZXcoaW5pdGlhbExWaWV3LCB0Tm9kZSwgd2Fsa1VwVGltZXMpO1xuXG4gICAgLy8gS2VlcCBwb2xsaW5nIHVudGlsIHdlIHJlc29sdmUgdGhlIHRyaWdnZXIncyBMVmlldy5cbiAgICAvLyBgYWZ0ZXJSZW5kZXJgIHNob3VsZCBzdG9wIGF1dG9tYXRpY2FsbHkgaWYgdGhlIHZpZXcgaXMgZGVzdHJveWVkLlxuICAgIGlmICghdHJpZ2dlckxWaWV3KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gSXQncyBwb3NzaWJsZSB0aGF0IHRoZSB0cmlnZ2VyJ3MgdmlldyB3YXMgZGVzdHJveWVkIGJlZm9yZSB3ZSByZXNvbHZlZCB0aGUgdHJpZ2dlciBlbGVtZW50LlxuICAgIGlmICh0cmlnZ2VyTFZpZXdbRkxBR1NdICYgTFZpZXdGbGFncy5EZXN0cm95ZWQpIHtcbiAgICAgIGFmdGVyUmVuZGVyUmVmLmRlc3Ryb3koKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBUT0RPOiBhZGQgaW50ZWdyYXRpb24gd2l0aCBgRGVmZXJCbG9ja0NsZWFudXBNYW5hZ2VyYC5cbiAgICBjb25zdCBlbGVtZW50ID0gZ2V0VHJpZ2dlckVsZW1lbnQodHJpZ2dlckxWaWV3LCB0cmlnZ2VySW5kZXgpO1xuICAgIGNvbnN0IGNsZWFudXAgPSByZWdpc3RlckZuKGVsZW1lbnQsICgpID0+IHtcbiAgICAgIGNhbGxiYWNrKCk7XG4gICAgICByZW1vdmVMVmlld09uRGVzdHJveSh0cmlnZ2VyTFZpZXcsIGNsZWFudXApO1xuICAgICAgaWYgKGluaXRpYWxMVmlldyAhPT0gdHJpZ2dlckxWaWV3KSB7XG4gICAgICAgIHJlbW92ZUxWaWV3T25EZXN0cm95KGluaXRpYWxMVmlldywgY2xlYW51cCk7XG4gICAgICB9XG4gICAgICBjbGVhbnVwKCk7XG4gICAgfSwgaW5qZWN0b3IpO1xuXG4gICAgYWZ0ZXJSZW5kZXJSZWYuZGVzdHJveSgpO1xuICAgIHN0b3JlTFZpZXdPbkRlc3Ryb3kodHJpZ2dlckxWaWV3LCBjbGVhbnVwKTtcblxuICAgIC8vIFNpbmNlIHRoZSB0cmlnZ2VyIGFuZCBkZWZlcnJlZCBibG9jayBtaWdodCBiZSBpbiBkaWZmZXJlbnRcbiAgICAvLyB2aWV3cywgd2UgaGF2ZSB0byByZWdpc3RlciB0aGUgY2FsbGJhY2sgaW4gYm90aCBsb2NhdGlvbnMuXG4gICAgaWYgKGluaXRpYWxMVmlldyAhPT0gdHJpZ2dlckxWaWV3KSB7XG4gICAgICBzdG9yZUxWaWV3T25EZXN0cm95KGluaXRpYWxMVmlldywgY2xlYW51cCk7XG4gICAgfVxuICB9LCB7aW5qZWN0b3J9KTtcbn1cblxuLyoqXG4gKiBIZWxwZXIgZnVuY3Rpb24gdG8gc2NoZWR1bGUgYSBjYWxsYmFjayB0byBiZSBpbnZva2VkIHdoZW4gYSBicm93c2VyIGJlY29tZXMgaWRsZS5cbiAqXG4gKiBAcGFyYW0gY2FsbGJhY2sgQSBmdW5jdGlvbiB0byBiZSBpbnZva2VkIHdoZW4gYSBicm93c2VyIGJlY29tZXMgaWRsZS5cbiAqIEBwYXJhbSBsVmlldyBMVmlldyB0aGF0IGhvc3RzIGFuIGluc3RhbmNlIG9mIGEgZGVmZXIgYmxvY2suXG4gKiBAcGFyYW0gd2l0aExWaWV3Q2xlYW51cCBBIGZsYWcgdGhhdCBpbmRpY2F0ZXMgd2hldGhlciBhIHNjaGVkdWxlZCBjYWxsYmFja1xuICogICAgICAgICAgIHNob3VsZCBiZSBjYW5jZWxsZWQgaW4gY2FzZSBhbiBMVmlldyBpcyBkZXN0cm95ZWQgYmVmb3JlIGEgY2FsbGJhY2tcbiAqICAgICAgICAgICB3YXMgaW52b2tlZC5cbiAqL1xuZnVuY3Rpb24gb25JZGxlKGNhbGxiYWNrOiBWb2lkRnVuY3Rpb24sIGxWaWV3OiBMVmlldywgd2l0aExWaWV3Q2xlYW51cDogYm9vbGVhbikge1xuICBjb25zdCBpbmplY3RvciA9IGxWaWV3W0lOSkVDVE9SXSE7XG4gIGNvbnN0IHNjaGVkdWxlciA9IGluamVjdG9yLmdldChPbklkbGVTY2hlZHVsZXIpO1xuICBjb25zdCBjbGVhbnVwRm4gPSAoKSA9PiBzY2hlZHVsZXIucmVtb3ZlKGNhbGxiYWNrKTtcbiAgY29uc3Qgd3JhcHBlZENhbGxiYWNrID1cbiAgICAgIHdpdGhMVmlld0NsZWFudXAgPyB3cmFwV2l0aExWaWV3Q2xlYW51cChjYWxsYmFjaywgbFZpZXcsIGNsZWFudXBGbikgOiBjYWxsYmFjaztcbiAgc2NoZWR1bGVyLmFkZCh3cmFwcGVkQ2FsbGJhY2spO1xuICByZXR1cm4gY2xlYW51cEZuO1xufVxuXG4vKipcbiAqIFJldHVybnMgYSBmdW5jdGlvbiB0aGF0IGNhcHR1cmVzIGEgcHJvdmlkZWQgZGVsYXkuXG4gKiBJbnZva2luZyB0aGUgcmV0dXJuZWQgZnVuY3Rpb24gc2NoZWR1bGVzIGEgdHJpZ2dlci5cbiAqL1xuZnVuY3Rpb24gb25UaW1lcihkZWxheTogbnVtYmVyKSB7XG4gIHJldHVybiAoY2FsbGJhY2s6IFZvaWRGdW5jdGlvbiwgbFZpZXc6IExWaWV3LCB3aXRoTFZpZXdDbGVhbnVwOiBib29sZWFuKSA9PlxuICAgICAgICAgICAgIHNjaGVkdWxlVGltZXJUcmlnZ2VyKGRlbGF5LCBjYWxsYmFjaywgbFZpZXcsIHdpdGhMVmlld0NsZWFudXApO1xufVxuXG4vKipcbiAqIFNjaGVkdWxlcyBhIGNhbGxiYWNrIHRvIGJlIGludm9rZWQgYWZ0ZXIgYSBnaXZlbiB0aW1lb3V0LlxuICpcbiAqIEBwYXJhbSBkZWxheSBBIG51bWJlciBvZiBtcyB0byB3YWl0IHVudGlsIGZpcmluZyBhIGNhbGxiYWNrLlxuICogQHBhcmFtIGNhbGxiYWNrIEEgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCBhZnRlciBhIHRpbWVvdXQuXG4gKiBAcGFyYW0gbFZpZXcgTFZpZXcgdGhhdCBob3N0cyBhbiBpbnN0YW5jZSBvZiBhIGRlZmVyIGJsb2NrLlxuICogQHBhcmFtIHdpdGhMVmlld0NsZWFudXAgQSBmbGFnIHRoYXQgaW5kaWNhdGVzIHdoZXRoZXIgYSBzY2hlZHVsZWQgY2FsbGJhY2tcbiAqICAgICAgICAgICBzaG91bGQgYmUgY2FuY2VsbGVkIGluIGNhc2UgYW4gTFZpZXcgaXMgZGVzdHJveWVkIGJlZm9yZSBhIGNhbGxiYWNrXG4gKiAgICAgICAgICAgd2FzIGludm9rZWQuXG4gKi9cbmZ1bmN0aW9uIHNjaGVkdWxlVGltZXJUcmlnZ2VyKFxuICAgIGRlbGF5OiBudW1iZXIsIGNhbGxiYWNrOiBWb2lkRnVuY3Rpb24sIGxWaWV3OiBMVmlldywgd2l0aExWaWV3Q2xlYW51cDogYm9vbGVhbikge1xuICBjb25zdCBpbmplY3RvciA9IGxWaWV3W0lOSkVDVE9SXSE7XG4gIGNvbnN0IHNjaGVkdWxlciA9IGluamVjdG9yLmdldChUaW1lclNjaGVkdWxlcik7XG4gIGNvbnN0IGNsZWFudXBGbiA9ICgpID0+IHNjaGVkdWxlci5yZW1vdmUoY2FsbGJhY2spO1xuICBjb25zdCB3cmFwcGVkQ2FsbGJhY2sgPVxuICAgICAgd2l0aExWaWV3Q2xlYW51cCA/IHdyYXBXaXRoTFZpZXdDbGVhbnVwKGNhbGxiYWNrLCBsVmlldywgY2xlYW51cEZuKSA6IGNhbGxiYWNrO1xuICBzY2hlZHVsZXIuYWRkKGRlbGF5LCB3cmFwcGVkQ2FsbGJhY2spO1xuICByZXR1cm4gY2xlYW51cEZuO1xufVxuXG4vKipcbiAqIFdyYXBzIGEgZ2l2ZW4gY2FsbGJhY2sgaW50byBhIGxvZ2ljIHRoYXQgcmVnaXN0ZXJzIGEgY2xlYW51cCBmdW5jdGlvblxuICogaW4gdGhlIExWaWV3IGNsZWFudXAgc2xvdCwgdG8gYmUgaW52b2tlZCB3aGVuIGFuIExWaWV3IGlzIGRlc3Ryb3llZC5cbiAqL1xuZnVuY3Rpb24gd3JhcFdpdGhMVmlld0NsZWFudXAoXG4gICAgY2FsbGJhY2s6IFZvaWRGdW5jdGlvbiwgbFZpZXc6IExWaWV3LCBjbGVhbnVwOiBWb2lkRnVuY3Rpb24pOiBWb2lkRnVuY3Rpb24ge1xuICBjb25zdCB3cmFwcGVkQ2FsbGJhY2sgPSAoKSA9PiB7XG4gICAgY2FsbGJhY2soKTtcbiAgICByZW1vdmVMVmlld09uRGVzdHJveShsVmlldywgY2xlYW51cCk7XG4gIH07XG4gIHN0b3JlTFZpZXdPbkRlc3Ryb3kobFZpZXcsIGNsZWFudXApO1xuICByZXR1cm4gd3JhcHBlZENhbGxiYWNrO1xufVxuXG4vKipcbiAqIENhbGN1bGF0ZXMgYSBkYXRhIHNsb3QgaW5kZXggZm9yIGRlZmVyIGJsb2NrIGluZm8gKGVpdGhlciBzdGF0aWMgb3JcbiAqIGluc3RhbmNlLXNwZWNpZmljKSwgZ2l2ZW4gYW4gaW5kZXggb2YgYSBkZWZlciBpbnN0cnVjdGlvbi5cbiAqL1xuZnVuY3Rpb24gZ2V0RGVmZXJCbG9ja0RhdGFJbmRleChkZWZlckJsb2NrSW5kZXg6IG51bWJlcikge1xuICAvLyBJbnN0YW5jZSBzdGF0ZSBpcyBsb2NhdGVkIGF0IHRoZSAqbmV4dCogcG9zaXRpb25cbiAgLy8gYWZ0ZXIgdGhlIGRlZmVyIGJsb2NrIHNsb3QgaW4gYW4gTFZpZXcgb3IgVFZpZXcuZGF0YS5cbiAgcmV0dXJuIGRlZmVyQmxvY2tJbmRleCArIDE7XG59XG5cbi8qKiBSZXRyaWV2ZXMgYSBkZWZlciBibG9jayBzdGF0ZSBmcm9tIGFuIExWaWV3LCBnaXZlbiBhIFROb2RlIHRoYXQgcmVwcmVzZW50cyBhIGJsb2NrLiAqL1xuZnVuY3Rpb24gZ2V0TERlZmVyQmxvY2tEZXRhaWxzKGxWaWV3OiBMVmlldywgdE5vZGU6IFROb2RlKTogTERlZmVyQmxvY2tEZXRhaWxzIHtcbiAgY29uc3QgdFZpZXcgPSBsVmlld1tUVklFV107XG4gIGNvbnN0IHNsb3RJbmRleCA9IGdldERlZmVyQmxvY2tEYXRhSW5kZXgodE5vZGUuaW5kZXgpO1xuICBuZ0Rldk1vZGUgJiYgYXNzZXJ0SW5kZXhJbkRlY2xSYW5nZSh0Vmlldywgc2xvdEluZGV4KTtcbiAgcmV0dXJuIGxWaWV3W3Nsb3RJbmRleF07XG59XG5cbi8qKiBTdG9yZXMgYSBkZWZlciBibG9jayBpbnN0YW5jZSBzdGF0ZSBpbiBMVmlldy4gKi9cbmZ1bmN0aW9uIHNldExEZWZlckJsb2NrRGV0YWlscyhcbiAgICBsVmlldzogTFZpZXcsIGRlZmVyQmxvY2tJbmRleDogbnVtYmVyLCBsRGV0YWlsczogTERlZmVyQmxvY2tEZXRhaWxzKSB7XG4gIGNvbnN0IHRWaWV3ID0gbFZpZXdbVFZJRVddO1xuICBjb25zdCBzbG90SW5kZXggPSBnZXREZWZlckJsb2NrRGF0YUluZGV4KGRlZmVyQmxvY2tJbmRleCk7XG4gIG5nRGV2TW9kZSAmJiBhc3NlcnRJbmRleEluRGVjbFJhbmdlKHRWaWV3LCBzbG90SW5kZXgpO1xuICBsVmlld1tzbG90SW5kZXhdID0gbERldGFpbHM7XG59XG5cbi8qKiBSZXRyaWV2ZXMgc3RhdGljIGluZm8gYWJvdXQgYSBkZWZlciBibG9jaywgZ2l2ZW4gYSBUVmlldyBhbmQgYSBUTm9kZSB0aGF0IHJlcHJlc2VudHMgYSBibG9jay4gKi9cbmZ1bmN0aW9uIGdldFREZWZlckJsb2NrRGV0YWlscyh0VmlldzogVFZpZXcsIHROb2RlOiBUTm9kZSk6IFREZWZlckJsb2NrRGV0YWlscyB7XG4gIGNvbnN0IHNsb3RJbmRleCA9IGdldERlZmVyQmxvY2tEYXRhSW5kZXgodE5vZGUuaW5kZXgpO1xuICBuZ0Rldk1vZGUgJiYgYXNzZXJ0SW5kZXhJbkRlY2xSYW5nZSh0Vmlldywgc2xvdEluZGV4KTtcbiAgcmV0dXJuIHRWaWV3LmRhdGFbc2xvdEluZGV4XSBhcyBURGVmZXJCbG9ja0RldGFpbHM7XG59XG5cbi8qKiBTdG9yZXMgYSBkZWZlciBibG9jayBzdGF0aWMgaW5mbyBpbiBgVFZpZXcuZGF0YWAuICovXG5mdW5jdGlvbiBzZXRURGVmZXJCbG9ja0RldGFpbHMoXG4gICAgdFZpZXc6IFRWaWV3LCBkZWZlckJsb2NrSW5kZXg6IG51bWJlciwgZGVmZXJCbG9ja0NvbmZpZzogVERlZmVyQmxvY2tEZXRhaWxzKSB7XG4gIGNvbnN0IHNsb3RJbmRleCA9IGdldERlZmVyQmxvY2tEYXRhSW5kZXgoZGVmZXJCbG9ja0luZGV4KTtcbiAgbmdEZXZNb2RlICYmIGFzc2VydEluZGV4SW5EZWNsUmFuZ2UodFZpZXcsIHNsb3RJbmRleCk7XG4gIHRWaWV3LmRhdGFbc2xvdEluZGV4XSA9IGRlZmVyQmxvY2tDb25maWc7XG59XG5cbmZ1bmN0aW9uIGdldFRlbXBsYXRlSW5kZXhGb3JTdGF0ZShcbiAgICBuZXdTdGF0ZTogRGVmZXJCbG9ja1N0YXRlLCBob3N0TFZpZXc6IExWaWV3LCB0Tm9kZTogVE5vZGUpOiBudW1iZXJ8bnVsbCB7XG4gIGNvbnN0IHRWaWV3ID0gaG9zdExWaWV3W1RWSUVXXTtcbiAgY29uc3QgdERldGFpbHMgPSBnZXRURGVmZXJCbG9ja0RldGFpbHModFZpZXcsIHROb2RlKTtcblxuICBzd2l0Y2ggKG5ld1N0YXRlKSB7XG4gICAgY2FzZSBEZWZlckJsb2NrU3RhdGUuQ29tcGxldGU6XG4gICAgICByZXR1cm4gdERldGFpbHMucHJpbWFyeVRtcGxJbmRleDtcbiAgICBjYXNlIERlZmVyQmxvY2tTdGF0ZS5Mb2FkaW5nOlxuICAgICAgcmV0dXJuIHREZXRhaWxzLmxvYWRpbmdUbXBsSW5kZXg7XG4gICAgY2FzZSBEZWZlckJsb2NrU3RhdGUuRXJyb3I6XG4gICAgICByZXR1cm4gdERldGFpbHMuZXJyb3JUbXBsSW5kZXg7XG4gICAgY2FzZSBEZWZlckJsb2NrU3RhdGUuUGxhY2Vob2xkZXI6XG4gICAgICByZXR1cm4gdERldGFpbHMucGxhY2Vob2xkZXJUbXBsSW5kZXg7XG4gICAgZGVmYXVsdDpcbiAgICAgIG5nRGV2TW9kZSAmJiB0aHJvd0Vycm9yKGBVbmV4cGVjdGVkIGRlZmVyIGJsb2NrIHN0YXRlOiAke25ld1N0YXRlfWApO1xuICAgICAgcmV0dXJuIG51bGw7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIGEgbWluaW11bSBhbW91bnQgb2YgdGltZSB0aGF0IGEgZ2l2ZW4gc3RhdGUgc2hvdWxkIGJlIHJlbmRlcmVkIGZvcixcbiAqIHRha2luZyBpbnRvIGFjY291bnQgYG1pbmltdW1gIHBhcmFtZXRlciB2YWx1ZS4gSWYgdGhlIGBtaW5pbXVtYCB2YWx1ZSBpc1xuICogbm90IHNwZWNpZmllZCAtIHJldHVybnMgYG51bGxgLlxuICovXG5mdW5jdGlvbiBnZXRNaW5pbXVtRHVyYXRpb25Gb3JTdGF0ZShcbiAgICB0RGV0YWlsczogVERlZmVyQmxvY2tEZXRhaWxzLCBjdXJyZW50U3RhdGU6IERlZmVyQmxvY2tTdGF0ZSk6IG51bWJlcnxudWxsIHtcbiAgaWYgKGN1cnJlbnRTdGF0ZSA9PT0gRGVmZXJCbG9ja1N0YXRlLlBsYWNlaG9sZGVyKSB7XG4gICAgcmV0dXJuIHREZXRhaWxzLnBsYWNlaG9sZGVyQmxvY2tDb25maWc/LltNSU5JTVVNX1NMT1RdID8/IG51bGw7XG4gIH0gZWxzZSBpZiAoY3VycmVudFN0YXRlID09PSBEZWZlckJsb2NrU3RhdGUuTG9hZGluZykge1xuICAgIHJldHVybiB0RGV0YWlscy5sb2FkaW5nQmxvY2tDb25maWc/LltNSU5JTVVNX1NMT1RdID8/IG51bGw7XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbi8qKiBSZXRyaWV2ZXMgdGhlIHZhbHVlIG9mIHRoZSBgYWZ0ZXJgIHBhcmFtZXRlciBvbiB0aGUgQGxvYWRpbmcgYmxvY2suICovXG5mdW5jdGlvbiBnZXRMb2FkaW5nQmxvY2tBZnRlcih0RGV0YWlsczogVERlZmVyQmxvY2tEZXRhaWxzKTogbnVtYmVyfG51bGwge1xuICByZXR1cm4gdERldGFpbHMubG9hZGluZ0Jsb2NrQ29uZmlnPy5bTE9BRElOR19BRlRFUl9TTE9UXSA/PyBudWxsO1xufVxuXG4vKipcbiAqIFRyYW5zaXRpb25zIGEgZGVmZXIgYmxvY2sgdG8gdGhlIG5ldyBzdGF0ZS4gVXBkYXRlcyB0aGUgIG5lY2Vzc2FyeVxuICogZGF0YSBzdHJ1Y3R1cmVzIGFuZCByZW5kZXJzIGNvcnJlc3BvbmRpbmcgYmxvY2suXG4gKlxuICogQHBhcmFtIG5ld1N0YXRlIE5ldyBzdGF0ZSB0aGF0IHNob3VsZCBiZSBhcHBsaWVkIHRvIHRoZSBkZWZlciBibG9jay5cbiAqIEBwYXJhbSB0Tm9kZSBUTm9kZSB0aGF0IHJlcHJlc2VudHMgYSBkZWZlciBibG9jay5cbiAqIEBwYXJhbSBsQ29udGFpbmVyIFJlcHJlc2VudHMgYW4gaW5zdGFuY2Ugb2YgYSBkZWZlciBibG9jay5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlbmRlckRlZmVyQmxvY2tTdGF0ZShcbiAgICBuZXdTdGF0ZTogRGVmZXJCbG9ja1N0YXRlLCB0Tm9kZTogVE5vZGUsIGxDb250YWluZXI6IExDb250YWluZXIpOiB2b2lkIHtcbiAgY29uc3QgaG9zdExWaWV3ID0gbENvbnRhaW5lcltQQVJFTlRdO1xuICBjb25zdCBob3N0VFZpZXcgPSBob3N0TFZpZXdbVFZJRVddO1xuXG4gIC8vIENoZWNrIGlmIHRoaXMgdmlldyBpcyBub3QgZGVzdHJveWVkLiBTaW5jZSB0aGUgbG9hZGluZyBwcm9jZXNzIHdhcyBhc3luYyxcbiAgLy8gdGhlIHZpZXcgbWlnaHQgZW5kIHVwIGJlaW5nIGRlc3Ryb3llZCBieSB0aGUgdGltZSByZW5kZXJpbmcgaGFwcGVucy5cbiAgaWYgKGlzRGVzdHJveWVkKGhvc3RMVmlldykpIHJldHVybjtcblxuICAvLyBNYWtlIHN1cmUgdGhpcyBUTm9kZSBiZWxvbmdzIHRvIFRWaWV3IHRoYXQgcmVwcmVzZW50cyBob3N0IExWaWV3LlxuICBuZ0Rldk1vZGUgJiYgYXNzZXJ0VE5vZGVGb3JMVmlldyh0Tm9kZSwgaG9zdExWaWV3KTtcblxuICBjb25zdCBsRGV0YWlscyA9IGdldExEZWZlckJsb2NrRGV0YWlscyhob3N0TFZpZXcsIHROb2RlKTtcblxuICBuZ0Rldk1vZGUgJiYgYXNzZXJ0RGVmaW5lZChsRGV0YWlscywgJ0V4cGVjdGVkIGEgZGVmZXIgYmxvY2sgc3RhdGUgZGVmaW5lZCcpO1xuXG4gIGNvbnN0IGN1cnJlbnRTdGF0ZSA9IGxEZXRhaWxzW0RFRkVSX0JMT0NLX1NUQVRFXTtcblxuICBpZiAoaXNWYWxpZFN0YXRlQ2hhbmdlKGN1cnJlbnRTdGF0ZSwgbmV3U3RhdGUpICYmXG4gICAgICBpc1ZhbGlkU3RhdGVDaGFuZ2UobERldGFpbHNbTkVYVF9ERUZFUl9CTE9DS19TVEFURV0gPz8gLTEsIG5ld1N0YXRlKSkge1xuICAgIGNvbnN0IHREZXRhaWxzID0gZ2V0VERlZmVyQmxvY2tEZXRhaWxzKGhvc3RUVmlldywgdE5vZGUpO1xuICAgIGNvbnN0IG5lZWRzU2NoZWR1bGluZyA9IGdldExvYWRpbmdCbG9ja0FmdGVyKHREZXRhaWxzKSAhPT0gbnVsbCB8fFxuICAgICAgICBnZXRNaW5pbXVtRHVyYXRpb25Gb3JTdGF0ZSh0RGV0YWlscywgRGVmZXJCbG9ja1N0YXRlLkxvYWRpbmcpICE9PSBudWxsIHx8XG4gICAgICAgIGdldE1pbmltdW1EdXJhdGlvbkZvclN0YXRlKHREZXRhaWxzLCBEZWZlckJsb2NrU3RhdGUuUGxhY2Vob2xkZXIpO1xuXG4gICAgaWYgKG5nRGV2TW9kZSAmJiBuZWVkc1NjaGVkdWxpbmcpIHtcbiAgICAgIGFzc2VydERlZmluZWQoXG4gICAgICAgICAgYXBwbHlEZWZlckJsb2NrU3RhdGVXaXRoU2NoZWR1bGluZ0ltcGwsICdFeHBlY3RlZCBzY2hlZHVsaW5nIGZ1bmN0aW9uIHRvIGJlIGRlZmluZWQnKTtcbiAgICB9XG5cbiAgICBjb25zdCBhcHBseVN0YXRlRm4gPVxuICAgICAgICBuZWVkc1NjaGVkdWxpbmcgPyBhcHBseURlZmVyQmxvY2tTdGF0ZVdpdGhTY2hlZHVsaW5nSW1wbCEgOiBhcHBseURlZmVyQmxvY2tTdGF0ZTtcbiAgICBhcHBseVN0YXRlRm4obmV3U3RhdGUsIGxEZXRhaWxzLCBsQ29udGFpbmVyLCB0Tm9kZSwgaG9zdExWaWV3KTtcbiAgfVxufVxuXG4vKipcbiAqIEFwcGxpZXMgY2hhbmdlcyB0byB0aGUgRE9NIHRvIHJlZmxlY3QgYSBnaXZlbiBzdGF0ZS5cbiAqL1xuZnVuY3Rpb24gYXBwbHlEZWZlckJsb2NrU3RhdGUoXG4gICAgbmV3U3RhdGU6IERlZmVyQmxvY2tTdGF0ZSwgbERldGFpbHM6IExEZWZlckJsb2NrRGV0YWlscywgbENvbnRhaW5lcjogTENvbnRhaW5lciwgdE5vZGU6IFROb2RlLFxuICAgIGhvc3RMVmlldzogTFZpZXc8dW5rbm93bj4pIHtcbiAgY29uc3Qgc3RhdGVUbXBsSW5kZXggPSBnZXRUZW1wbGF0ZUluZGV4Rm9yU3RhdGUobmV3U3RhdGUsIGhvc3RMVmlldywgdE5vZGUpO1xuXG4gIGlmIChzdGF0ZVRtcGxJbmRleCAhPT0gbnVsbCkge1xuICAgIGxEZXRhaWxzW0RFRkVSX0JMT0NLX1NUQVRFXSA9IG5ld1N0YXRlO1xuICAgIGNvbnN0IGhvc3RUVmlldyA9IGhvc3RMVmlld1tUVklFV107XG4gICAgY29uc3QgYWRqdXN0ZWRJbmRleCA9IHN0YXRlVG1wbEluZGV4ICsgSEVBREVSX09GRlNFVDtcbiAgICBjb25zdCB0Tm9kZSA9IGdldFROb2RlKGhvc3RUVmlldywgYWRqdXN0ZWRJbmRleCkgYXMgVENvbnRhaW5lck5vZGU7XG5cbiAgICAvLyBUaGVyZSBpcyBvbmx5IDEgdmlldyB0aGF0IGNhbiBiZSBwcmVzZW50IGluIGFuIExDb250YWluZXIgdGhhdFxuICAgIC8vIHJlcHJlc2VudHMgYSBkZWZlciBibG9jaywgc28gYWx3YXlzIHJlZmVyIHRvIHRoZSBmaXJzdCBvbmUuXG4gICAgY29uc3Qgdmlld0luZGV4ID0gMDtcblxuICAgIHJlbW92ZUxWaWV3RnJvbUxDb250YWluZXIobENvbnRhaW5lciwgdmlld0luZGV4KTtcbiAgICBjb25zdCBkZWh5ZHJhdGVkVmlldyA9IGZpbmRNYXRjaGluZ0RlaHlkcmF0ZWRWaWV3KGxDb250YWluZXIsIHROb2RlLnRWaWV3IS5zc3JJZCk7XG4gICAgY29uc3QgZW1iZWRkZWRMVmlldyA9IGNyZWF0ZUFuZFJlbmRlckVtYmVkZGVkTFZpZXcoaG9zdExWaWV3LCB0Tm9kZSwgbnVsbCwge2RlaHlkcmF0ZWRWaWV3fSk7XG4gICAgYWRkTFZpZXdUb0xDb250YWluZXIoXG4gICAgICAgIGxDb250YWluZXIsIGVtYmVkZGVkTFZpZXcsIHZpZXdJbmRleCwgc2hvdWxkQWRkVmlld1RvRG9tKHROb2RlLCBkZWh5ZHJhdGVkVmlldykpO1xuICAgIG1hcmtWaWV3RGlydHkoZW1iZWRkZWRMVmlldyk7XG4gIH1cbn1cblxuLyoqXG4gKiBFeHRlbmRzIHRoZSBgYXBwbHlEZWZlckJsb2NrU3RhdGVgIHdpdGggdGltZXItYmFzZWQgc2NoZWR1bGluZy5cbiAqIFRoaXMgZnVuY3Rpb24gYmVjb21lcyBhdmFpbGFibGUgb24gYSBwYWdlIGlmIHRoZXJlIGFyZSBkZWZlciBibG9ja3NcbiAqIHRoYXQgdXNlIGBhZnRlcmAgb3IgYG1pbmltdW1gIHBhcmFtZXRlcnMgaW4gdGhlIGBAbG9hZGluZ2Agb3JcbiAqIGBAcGxhY2Vob2xkZXJgIGJsb2Nrcy5cbiAqL1xuZnVuY3Rpb24gYXBwbHlEZWZlckJsb2NrU3RhdGVXaXRoU2NoZWR1bGluZyhcbiAgICBuZXdTdGF0ZTogRGVmZXJCbG9ja1N0YXRlLCBsRGV0YWlsczogTERlZmVyQmxvY2tEZXRhaWxzLCBsQ29udGFpbmVyOiBMQ29udGFpbmVyLCB0Tm9kZTogVE5vZGUsXG4gICAgaG9zdExWaWV3OiBMVmlldzx1bmtub3duPikge1xuICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICBjb25zdCBob3N0VFZpZXcgPSBob3N0TFZpZXdbVFZJRVddO1xuICBjb25zdCB0RGV0YWlscyA9IGdldFREZWZlckJsb2NrRGV0YWlscyhob3N0VFZpZXcsIHROb2RlKTtcblxuICBpZiAobERldGFpbHNbU1RBVEVfSVNfRlJPWkVOX1VOVElMXSA9PT0gbnVsbCB8fCBsRGV0YWlsc1tTVEFURV9JU19GUk9aRU5fVU5USUxdIDw9IG5vdykge1xuICAgIGxEZXRhaWxzW1NUQVRFX0lTX0ZST1pFTl9VTlRJTF0gPSBudWxsO1xuXG4gICAgY29uc3QgbG9hZGluZ0FmdGVyID0gZ2V0TG9hZGluZ0Jsb2NrQWZ0ZXIodERldGFpbHMpO1xuICAgIGNvbnN0IGluTG9hZGluZ0FmdGVyUGhhc2UgPSBsRGV0YWlsc1tMT0FESU5HX0FGVEVSX0NMRUFOVVBfRk5dICE9PSBudWxsO1xuICAgIGlmIChuZXdTdGF0ZSA9PT0gRGVmZXJCbG9ja1N0YXRlLkxvYWRpbmcgJiYgbG9hZGluZ0FmdGVyICE9PSBudWxsICYmICFpbkxvYWRpbmdBZnRlclBoYXNlKSB7XG4gICAgICAvLyBUcnlpbmcgdG8gcmVuZGVyIGxvYWRpbmcsIGJ1dCBpdCBoYXMgYW4gYGFmdGVyYCBjb25maWcsXG4gICAgICAvLyBzbyBzY2hlZHVsZSBhbiB1cGRhdGUgYWN0aW9uIGFmdGVyIGEgdGltZW91dC5cbiAgICAgIGxEZXRhaWxzW05FWFRfREVGRVJfQkxPQ0tfU1RBVEVdID0gbmV3U3RhdGU7XG4gICAgICBjb25zdCBjbGVhbnVwRm4gPVxuICAgICAgICAgIHNjaGVkdWxlRGVmZXJCbG9ja1VwZGF0ZShsb2FkaW5nQWZ0ZXIsIGxEZXRhaWxzLCB0Tm9kZSwgbENvbnRhaW5lciwgaG9zdExWaWV3KTtcbiAgICAgIGxEZXRhaWxzW0xPQURJTkdfQUZURVJfQ0xFQU5VUF9GTl0gPSBjbGVhbnVwRm47XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIElmIHdlIHRyYW5zaXRpb24gdG8gYSBjb21wbGV0ZSBvciBhbiBlcnJvciBzdGF0ZSBhbmQgdGhlcmUgaXMgYSBwZW5kaW5nXG4gICAgICAvLyBvcGVyYXRpb24gdG8gcmVuZGVyIGxvYWRpbmcgYWZ0ZXIgYSB0aW1lb3V0IC0gaW52b2tlIGEgY2xlYW51cCBvcGVyYXRpb24sXG4gICAgICAvLyB3aGljaCBzdG9wcyB0aGUgdGltZXIuXG4gICAgICBpZiAobmV3U3RhdGUgPiBEZWZlckJsb2NrU3RhdGUuTG9hZGluZyAmJiBpbkxvYWRpbmdBZnRlclBoYXNlKSB7XG4gICAgICAgIGxEZXRhaWxzW0xPQURJTkdfQUZURVJfQ0xFQU5VUF9GTl0hKCk7XG4gICAgICAgIGxEZXRhaWxzW0xPQURJTkdfQUZURVJfQ0xFQU5VUF9GTl0gPSBudWxsO1xuICAgICAgICBsRGV0YWlsc1tORVhUX0RFRkVSX0JMT0NLX1NUQVRFXSA9IG51bGw7XG4gICAgICB9XG5cbiAgICAgIGFwcGx5RGVmZXJCbG9ja1N0YXRlKG5ld1N0YXRlLCBsRGV0YWlscywgbENvbnRhaW5lciwgdE5vZGUsIGhvc3RMVmlldyk7XG5cbiAgICAgIGNvbnN0IGR1cmF0aW9uID0gZ2V0TWluaW11bUR1cmF0aW9uRm9yU3RhdGUodERldGFpbHMsIG5ld1N0YXRlKTtcbiAgICAgIGlmIChkdXJhdGlvbiAhPT0gbnVsbCkge1xuICAgICAgICBsRGV0YWlsc1tTVEFURV9JU19GUk9aRU5fVU5USUxdID0gbm93ICsgZHVyYXRpb247XG4gICAgICAgIHNjaGVkdWxlRGVmZXJCbG9ja1VwZGF0ZShkdXJhdGlvbiwgbERldGFpbHMsIHROb2RlLCBsQ29udGFpbmVyLCBob3N0TFZpZXcpO1xuICAgICAgfVxuICAgIH1cbiAgfSBlbHNlIHtcbiAgICAvLyBXZSBhcmUgc3RpbGwgcmVuZGVyaW5nIHRoZSBwcmV2aW91cyBzdGF0ZS5cbiAgICAvLyBVcGRhdGUgdGhlIGBORVhUX0RFRkVSX0JMT0NLX1NUQVRFYCwgd2hpY2ggd291bGQgYmVcbiAgICAvLyBwaWNrZWQgdXAgb25jZSBpdCdzIHRpbWUgdG8gdHJhbnNpdGlvbiB0byB0aGUgbmV4dCBzdGF0ZS5cbiAgICBsRGV0YWlsc1tORVhUX0RFRkVSX0JMT0NLX1NUQVRFXSA9IG5ld1N0YXRlO1xuICB9XG59XG5cbi8qKlxuICogU2NoZWR1bGVzIGFuIHVwZGF0ZSBvcGVyYXRpb24gYWZ0ZXIgYSBzcGVjaWZpZWQgdGltZW91dC5cbiAqL1xuZnVuY3Rpb24gc2NoZWR1bGVEZWZlckJsb2NrVXBkYXRlKFxuICAgIHRpbWVvdXQ6IG51bWJlciwgbERldGFpbHM6IExEZWZlckJsb2NrRGV0YWlscywgdE5vZGU6IFROb2RlLCBsQ29udGFpbmVyOiBMQ29udGFpbmVyLFxuICAgIGhvc3RMVmlldzogTFZpZXc8dW5rbm93bj4pOiBWb2lkRnVuY3Rpb24ge1xuICBjb25zdCBjYWxsYmFjayA9ICgpID0+IHtcbiAgICBjb25zdCBuZXh0U3RhdGUgPSBsRGV0YWlsc1tORVhUX0RFRkVSX0JMT0NLX1NUQVRFXTtcbiAgICBsRGV0YWlsc1tTVEFURV9JU19GUk9aRU5fVU5USUxdID0gbnVsbDtcbiAgICBsRGV0YWlsc1tORVhUX0RFRkVSX0JMT0NLX1NUQVRFXSA9IG51bGw7XG4gICAgaWYgKG5leHRTdGF0ZSAhPT0gbnVsbCkge1xuICAgICAgcmVuZGVyRGVmZXJCbG9ja1N0YXRlKG5leHRTdGF0ZSwgdE5vZGUsIGxDb250YWluZXIpO1xuICAgIH1cbiAgfTtcbiAgcmV0dXJuIHNjaGVkdWxlVGltZXJUcmlnZ2VyKHRpbWVvdXQsIGNhbGxiYWNrLCBob3N0TFZpZXcsIHRydWUpO1xufVxuXG4vKipcbiAqIENoZWNrcyB3aGV0aGVyIHdlIGNhbiB0cmFuc2l0aW9uIHRvIHRoZSBuZXh0IHN0YXRlLlxuICpcbiAqIFdlIHRyYW5zaXRpb24gdG8gdGhlIG5leHQgc3RhdGUgaWYgdGhlIHByZXZpb3VzIHN0YXRlIHdhcyByZXByZXNlbnRlZFxuICogd2l0aCBhIG51bWJlciB0aGF0IGlzIGxlc3MgdGhhbiB0aGUgbmV4dCBzdGF0ZS4gRm9yIGV4YW1wbGUsIGlmIHRoZSBjdXJyZW50XG4gKiBzdGF0ZSBpcyBcImxvYWRpbmdcIiAocmVwcmVzZW50ZWQgYXMgYDFgKSwgd2Ugc2hvdWxkIG5vdCBzaG93IGEgcGxhY2Vob2xkZXJcbiAqIChyZXByZXNlbnRlZCBhcyBgMGApLCBidXQgd2UgY2FuIHNob3cgYSBjb21wbGV0ZWQgc3RhdGUgKHJlcHJlc2VudGVkIGFzIGAyYClcbiAqIG9yIGFuIGVycm9yIHN0YXRlIChyZXByZXNlbnRlZCBhcyBgM2ApLlxuICovXG5mdW5jdGlvbiBpc1ZhbGlkU3RhdGVDaGFuZ2UoXG4gICAgY3VycmVudFN0YXRlOiBEZWZlckJsb2NrU3RhdGV8RGVmZXJCbG9ja0ludGVybmFsU3RhdGUsIG5ld1N0YXRlOiBEZWZlckJsb2NrU3RhdGUpOiBib29sZWFuIHtcbiAgcmV0dXJuIGN1cnJlbnRTdGF0ZSA8IG5ld1N0YXRlO1xufVxuXG4vKipcbiAqIFRyaWdnZXIgcHJlZmV0Y2hpbmcgb2YgZGVwZW5kZW5jaWVzIGZvciBhIGRlZmVyIGJsb2NrLlxuICpcbiAqIEBwYXJhbSB0RGV0YWlscyBTdGF0aWMgaW5mb3JtYXRpb24gYWJvdXQgdGhpcyBkZWZlciBibG9jay5cbiAqIEBwYXJhbSBsVmlldyBMVmlldyBvZiBhIGhvc3Qgdmlldy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRyaWdnZXJQcmVmZXRjaGluZyh0RGV0YWlsczogVERlZmVyQmxvY2tEZXRhaWxzLCBsVmlldzogTFZpZXcpIHtcbiAgaWYgKGxWaWV3W0lOSkVDVE9SXSAmJiBzaG91bGRUcmlnZ2VyRGVmZXJCbG9jayhsVmlld1tJTkpFQ1RPUl0hKSkge1xuICAgIHRyaWdnZXJSZXNvdXJjZUxvYWRpbmcodERldGFpbHMsIGxWaWV3KTtcbiAgfVxufVxuXG4vKipcbiAqIFRyaWdnZXIgbG9hZGluZyBvZiBkZWZlciBibG9jayBkZXBlbmRlbmNpZXMgaWYgdGhlIHByb2Nlc3MgaGFzbid0IHN0YXJ0ZWQgeWV0LlxuICpcbiAqIEBwYXJhbSB0RGV0YWlscyBTdGF0aWMgaW5mb3JtYXRpb24gYWJvdXQgdGhpcyBkZWZlciBibG9jay5cbiAqIEBwYXJhbSBsVmlldyBMVmlldyBvZiBhIGhvc3Qgdmlldy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRyaWdnZXJSZXNvdXJjZUxvYWRpbmcodERldGFpbHM6IFREZWZlckJsb2NrRGV0YWlscywgbFZpZXc6IExWaWV3KSB7XG4gIGNvbnN0IGluamVjdG9yID0gbFZpZXdbSU5KRUNUT1JdITtcbiAgY29uc3QgdFZpZXcgPSBsVmlld1tUVklFV107XG5cbiAgaWYgKHREZXRhaWxzLmxvYWRpbmdTdGF0ZSAhPT0gRGVmZXJEZXBlbmRlbmNpZXNMb2FkaW5nU3RhdGUuTk9UX1NUQVJURUQpIHtcbiAgICAvLyBJZiB0aGUgbG9hZGluZyBzdGF0dXMgaXMgZGlmZmVyZW50IGZyb20gaW5pdGlhbCBvbmUsIGl0IG1lYW5zIHRoYXRcbiAgICAvLyB0aGUgbG9hZGluZyBvZiBkZXBlbmRlbmNpZXMgaXMgaW4gcHJvZ3Jlc3MgYW5kIHRoZXJlIGlzIG5vdGhpbmcgdG8gZG9cbiAgICAvLyBpbiB0aGlzIGZ1bmN0aW9uLiBBbGwgZGV0YWlscyBjYW4gYmUgb2J0YWluZWQgZnJvbSB0aGUgYHREZXRhaWxzYCBvYmplY3QuXG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3QgcHJpbWFyeUJsb2NrVE5vZGUgPSBnZXRQcmltYXJ5QmxvY2tUTm9kZSh0VmlldywgdERldGFpbHMpO1xuXG4gIC8vIFN3aXRjaCBmcm9tIE5PVF9TVEFSVEVEIC0+IElOX1BST0dSRVNTIHN0YXRlLlxuICB0RGV0YWlscy5sb2FkaW5nU3RhdGUgPSBEZWZlckRlcGVuZGVuY2llc0xvYWRpbmdTdGF0ZS5JTl9QUk9HUkVTUztcblxuICAvLyBDaGVjayBpZiBkZXBlbmRlbmN5IGZ1bmN0aW9uIGludGVyY2VwdG9yIGlzIGNvbmZpZ3VyZWQuXG4gIGNvbnN0IGRlZmVyRGVwZW5kZW5jeUludGVyY2VwdG9yID1cbiAgICAgIGluamVjdG9yLmdldChERUZFUl9CTE9DS19ERVBFTkRFTkNZX0lOVEVSQ0VQVE9SLCBudWxsLCB7b3B0aW9uYWw6IHRydWV9KTtcblxuICBjb25zdCBkZXBlbmRlbmNpZXNGbiA9IGRlZmVyRGVwZW5kZW5jeUludGVyY2VwdG9yID9cbiAgICAgIGRlZmVyRGVwZW5kZW5jeUludGVyY2VwdG9yLmludGVyY2VwdCh0RGV0YWlscy5kZXBlbmRlbmN5UmVzb2x2ZXJGbikgOlxuICAgICAgdERldGFpbHMuZGVwZW5kZW5jeVJlc29sdmVyRm47XG5cbiAgLy8gVGhlIGBkZXBlbmRlbmNpZXNGbmAgbWlnaHQgYmUgYG51bGxgIHdoZW4gYWxsIGRlcGVuZGVuY2llcyB3aXRoaW5cbiAgLy8gYSBnaXZlbiBkZWZlciBibG9jayB3ZXJlIGVhZ2VybHkgcmVmZXJlbmNlcyBlbHNld2hlcmUgaW4gYSBmaWxlLFxuICAvLyB0aHVzIG5vIGR5bmFtaWMgYGltcG9ydCgpYHMgd2VyZSBwcm9kdWNlZC5cbiAgaWYgKCFkZXBlbmRlbmNpZXNGbikge1xuICAgIHREZXRhaWxzLmxvYWRpbmdQcm9taXNlID0gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiB7XG4gICAgICB0RGV0YWlscy5sb2FkaW5nU3RhdGUgPSBEZWZlckRlcGVuZGVuY2llc0xvYWRpbmdTdGF0ZS5DT01QTEVURTtcbiAgICB9KTtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBEZWZlciBibG9jayBtYXkgaGF2ZSBtdWx0aXBsZSBwcmVmZXRjaCB0cmlnZ2Vycy4gT25jZSB0aGUgbG9hZGluZ1xuICAvLyBzdGFydHMsIGludm9rZSBhbGwgY2xlYW4gZnVuY3Rpb25zLCBzaW5jZSB0aGV5IGFyZSBubyBsb25nZXIgbmVlZGVkLlxuICBpbnZva2VURGV0YWlsc0NsZWFudXAoaW5qZWN0b3IsIHREZXRhaWxzKTtcblxuICAvLyBTdGFydCBkb3dubG9hZGluZyBvZiBkZWZlciBibG9jayBkZXBlbmRlbmNpZXMuXG4gIHREZXRhaWxzLmxvYWRpbmdQcm9taXNlID0gUHJvbWlzZS5hbGxTZXR0bGVkKGRlcGVuZGVuY2llc0ZuKCkpLnRoZW4ocmVzdWx0cyA9PiB7XG4gICAgbGV0IGZhaWxlZCA9IGZhbHNlO1xuICAgIGNvbnN0IGRpcmVjdGl2ZURlZnM6IERpcmVjdGl2ZURlZkxpc3QgPSBbXTtcbiAgICBjb25zdCBwaXBlRGVmczogUGlwZURlZkxpc3QgPSBbXTtcblxuICAgIGZvciAoY29uc3QgcmVzdWx0IG9mIHJlc3VsdHMpIHtcbiAgICAgIGlmIChyZXN1bHQuc3RhdHVzID09PSAnZnVsZmlsbGVkJykge1xuICAgICAgICBjb25zdCBkZXBlbmRlbmN5ID0gcmVzdWx0LnZhbHVlO1xuICAgICAgICBjb25zdCBkaXJlY3RpdmVEZWYgPSBnZXRDb21wb25lbnREZWYoZGVwZW5kZW5jeSkgfHwgZ2V0RGlyZWN0aXZlRGVmKGRlcGVuZGVuY3kpO1xuICAgICAgICBpZiAoZGlyZWN0aXZlRGVmKSB7XG4gICAgICAgICAgZGlyZWN0aXZlRGVmcy5wdXNoKGRpcmVjdGl2ZURlZik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgcGlwZURlZiA9IGdldFBpcGVEZWYoZGVwZW5kZW5jeSk7XG4gICAgICAgICAgaWYgKHBpcGVEZWYpIHtcbiAgICAgICAgICAgIHBpcGVEZWZzLnB1c2gocGlwZURlZik7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBmYWlsZWQgPSB0cnVlO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBMb2FkaW5nIGlzIGNvbXBsZXRlZCwgd2Ugbm8gbG9uZ2VyIG5lZWQgdGhpcyBQcm9taXNlLlxuICAgIHREZXRhaWxzLmxvYWRpbmdQcm9taXNlID0gbnVsbDtcblxuICAgIGlmIChmYWlsZWQpIHtcbiAgICAgIHREZXRhaWxzLmxvYWRpbmdTdGF0ZSA9IERlZmVyRGVwZW5kZW5jaWVzTG9hZGluZ1N0YXRlLkZBSUxFRDtcbiAgICB9IGVsc2Uge1xuICAgICAgdERldGFpbHMubG9hZGluZ1N0YXRlID0gRGVmZXJEZXBlbmRlbmNpZXNMb2FkaW5nU3RhdGUuQ09NUExFVEU7XG5cbiAgICAgIC8vIFVwZGF0ZSBkaXJlY3RpdmUgYW5kIHBpcGUgcmVnaXN0cmllcyB0byBhZGQgbmV3bHkgZG93bmxvYWRlZCBkZXBlbmRlbmNpZXMuXG4gICAgICBjb25zdCBwcmltYXJ5QmxvY2tUVmlldyA9IHByaW1hcnlCbG9ja1ROb2RlLnRWaWV3ITtcbiAgICAgIGlmIChkaXJlY3RpdmVEZWZzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcHJpbWFyeUJsb2NrVFZpZXcuZGlyZWN0aXZlUmVnaXN0cnkgPVxuICAgICAgICAgICAgYWRkRGVwc1RvUmVnaXN0cnk8RGlyZWN0aXZlRGVmTGlzdD4ocHJpbWFyeUJsb2NrVFZpZXcuZGlyZWN0aXZlUmVnaXN0cnksIGRpcmVjdGl2ZURlZnMpO1xuICAgICAgfVxuICAgICAgaWYgKHBpcGVEZWZzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcHJpbWFyeUJsb2NrVFZpZXcucGlwZVJlZ2lzdHJ5ID1cbiAgICAgICAgICAgIGFkZERlcHNUb1JlZ2lzdHJ5PFBpcGVEZWZMaXN0PihwcmltYXJ5QmxvY2tUVmlldy5waXBlUmVnaXN0cnksIHBpcGVEZWZzKTtcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xufVxuXG4vKipcbiAqIEFkZHMgZG93bmxvYWRlZCBkZXBlbmRlbmNpZXMgaW50byBhIGRpcmVjdGl2ZSBvciBhIHBpcGUgcmVnaXN0cnksXG4gKiBtYWtpbmcgc3VyZSB0aGF0IGEgZGVwZW5kZW5jeSBkb2Vzbid0IHlldCBleGlzdCBpbiB0aGUgcmVnaXN0cnkuXG4gKi9cbmZ1bmN0aW9uIGFkZERlcHNUb1JlZ2lzdHJ5PFQgZXh0ZW5kcyBEZXBlbmRlbmN5RGVmW10+KGN1cnJlbnREZXBzOiBUfG51bGwsIG5ld0RlcHM6IFQpOiBUIHtcbiAgaWYgKCFjdXJyZW50RGVwcyB8fCBjdXJyZW50RGVwcy5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gbmV3RGVwcztcbiAgfVxuXG4gIGNvbnN0IGN1cnJlbnREZXBTZXQgPSBuZXcgU2V0KGN1cnJlbnREZXBzKTtcbiAgZm9yIChjb25zdCBkZXAgb2YgbmV3RGVwcykge1xuICAgIGN1cnJlbnREZXBTZXQuYWRkKGRlcCk7XG4gIH1cblxuICAvLyBJZiBgY3VycmVudERlcHNgIGlzIHRoZSBzYW1lIGxlbmd0aCwgdGhlcmUgd2VyZSBubyBuZXcgZGVwcyBhbmQgY2FuXG4gIC8vIHJldHVybiB0aGUgb3JpZ2luYWwgYXJyYXkuXG4gIHJldHVybiAoY3VycmVudERlcHMubGVuZ3RoID09PSBjdXJyZW50RGVwU2V0LnNpemUpID8gY3VycmVudERlcHMgOiBBcnJheS5mcm9tKGN1cnJlbnREZXBTZXQpIGFzIFQ7XG59XG5cbi8qKiBVdGlsaXR5IGZ1bmN0aW9uIHRvIHJlbmRlciBwbGFjZWhvbGRlciBjb250ZW50IChpZiBwcmVzZW50KSAqL1xuZnVuY3Rpb24gcmVuZGVyUGxhY2Vob2xkZXIobFZpZXc6IExWaWV3LCB0Tm9kZTogVE5vZGUpIHtcbiAgY29uc3QgbENvbnRhaW5lciA9IGxWaWV3W3ROb2RlLmluZGV4XTtcbiAgbmdEZXZNb2RlICYmIGFzc2VydExDb250YWluZXIobENvbnRhaW5lcik7XG5cbiAgcmVuZGVyRGVmZXJCbG9ja1N0YXRlKERlZmVyQmxvY2tTdGF0ZS5QbGFjZWhvbGRlciwgdE5vZGUsIGxDb250YWluZXIpO1xufVxuXG4vKipcbiAqIFN1YnNjcmliZXMgdG8gdGhlIFwibG9hZGluZ1wiIFByb21pc2UgYW5kIHJlbmRlcnMgY29ycmVzcG9uZGluZyBkZWZlciBzdWItYmxvY2ssXG4gKiBiYXNlZCBvbiB0aGUgbG9hZGluZyByZXN1bHRzLlxuICpcbiAqIEBwYXJhbSBsQ29udGFpbmVyIFJlcHJlc2VudHMgYW4gaW5zdGFuY2Ugb2YgYSBkZWZlciBibG9jay5cbiAqIEBwYXJhbSB0Tm9kZSBSZXByZXNlbnRzIGRlZmVyIGJsb2NrIGluZm8gc2hhcmVkIGFjcm9zcyBhbGwgaW5zdGFuY2VzLlxuICovXG5mdW5jdGlvbiByZW5kZXJEZWZlclN0YXRlQWZ0ZXJSZXNvdXJjZUxvYWRpbmcoXG4gICAgdERldGFpbHM6IFREZWZlckJsb2NrRGV0YWlscywgdE5vZGU6IFROb2RlLCBsQ29udGFpbmVyOiBMQ29udGFpbmVyKSB7XG4gIG5nRGV2TW9kZSAmJlxuICAgICAgYXNzZXJ0RGVmaW5lZChcbiAgICAgICAgICB0RGV0YWlscy5sb2FkaW5nUHJvbWlzZSwgJ0V4cGVjdGVkIGxvYWRpbmcgUHJvbWlzZSB0byBleGlzdCBvbiB0aGlzIGRlZmVyIGJsb2NrJyk7XG5cbiAgdERldGFpbHMubG9hZGluZ1Byb21pc2UhLnRoZW4oKCkgPT4ge1xuICAgIGlmICh0RGV0YWlscy5sb2FkaW5nU3RhdGUgPT09IERlZmVyRGVwZW5kZW5jaWVzTG9hZGluZ1N0YXRlLkNPTVBMRVRFKSB7XG4gICAgICBuZ0Rldk1vZGUgJiYgYXNzZXJ0RGVmZXJyZWREZXBlbmRlbmNpZXNMb2FkZWQodERldGFpbHMpO1xuXG4gICAgICAvLyBFdmVyeXRoaW5nIGlzIGxvYWRlZCwgc2hvdyB0aGUgcHJpbWFyeSBibG9jayBjb250ZW50XG4gICAgICByZW5kZXJEZWZlckJsb2NrU3RhdGUoRGVmZXJCbG9ja1N0YXRlLkNvbXBsZXRlLCB0Tm9kZSwgbENvbnRhaW5lcik7XG5cbiAgICB9IGVsc2UgaWYgKHREZXRhaWxzLmxvYWRpbmdTdGF0ZSA9PT0gRGVmZXJEZXBlbmRlbmNpZXNMb2FkaW5nU3RhdGUuRkFJTEVEKSB7XG4gICAgICByZW5kZXJEZWZlckJsb2NrU3RhdGUoRGVmZXJCbG9ja1N0YXRlLkVycm9yLCB0Tm9kZSwgbENvbnRhaW5lcik7XG4gICAgfVxuICB9KTtcbn1cblxuLyoqIFJldHJpZXZlcyBhIFROb2RlIHRoYXQgcmVwcmVzZW50cyBtYWluIGNvbnRlbnQgb2YgYSBkZWZlciBibG9jay4gKi9cbmZ1bmN0aW9uIGdldFByaW1hcnlCbG9ja1ROb2RlKHRWaWV3OiBUVmlldywgdERldGFpbHM6IFREZWZlckJsb2NrRGV0YWlscyk6IFRDb250YWluZXJOb2RlIHtcbiAgY29uc3QgYWRqdXN0ZWRJbmRleCA9IHREZXRhaWxzLnByaW1hcnlUbXBsSW5kZXggKyBIRUFERVJfT0ZGU0VUO1xuICByZXR1cm4gZ2V0VE5vZGUodFZpZXcsIGFkanVzdGVkSW5kZXgpIGFzIFRDb250YWluZXJOb2RlO1xufVxuXG4vKipcbiAqIEF0dGVtcHRzIHRvIHRyaWdnZXIgbG9hZGluZyBvZiBkZWZlciBibG9jayBkZXBlbmRlbmNpZXMuXG4gKiBJZiB0aGUgYmxvY2sgaXMgYWxyZWFkeSBpbiBhIGxvYWRpbmcsIGNvbXBsZXRlZCBvciBhbiBlcnJvciBzdGF0ZSAtXG4gKiBubyBhZGRpdGlvbmFsIGFjdGlvbnMgYXJlIHRha2VuLlxuICovXG5mdW5jdGlvbiB0cmlnZ2VyRGVmZXJCbG9jayhsVmlldzogTFZpZXcsIHROb2RlOiBUTm9kZSkge1xuICBjb25zdCB0VmlldyA9IGxWaWV3W1RWSUVXXTtcbiAgY29uc3QgbENvbnRhaW5lciA9IGxWaWV3W3ROb2RlLmluZGV4XTtcbiAgY29uc3QgaW5qZWN0b3IgPSBsVmlld1tJTkpFQ1RPUl0hO1xuICBuZ0Rldk1vZGUgJiYgYXNzZXJ0TENvbnRhaW5lcihsQ29udGFpbmVyKTtcblxuICBpZiAoIXNob3VsZFRyaWdnZXJEZWZlckJsb2NrKGluamVjdG9yKSkgcmV0dXJuO1xuXG4gIGNvbnN0IHREZXRhaWxzID0gZ2V0VERlZmVyQmxvY2tEZXRhaWxzKHRWaWV3LCB0Tm9kZSk7XG4gIHN3aXRjaCAodERldGFpbHMubG9hZGluZ1N0YXRlKSB7XG4gICAgY2FzZSBEZWZlckRlcGVuZGVuY2llc0xvYWRpbmdTdGF0ZS5OT1RfU1RBUlRFRDpcbiAgICAgIHJlbmRlckRlZmVyQmxvY2tTdGF0ZShEZWZlckJsb2NrU3RhdGUuTG9hZGluZywgdE5vZGUsIGxDb250YWluZXIpO1xuICAgICAgdHJpZ2dlclJlc291cmNlTG9hZGluZyh0RGV0YWlscywgbFZpZXcpO1xuXG4gICAgICAvLyBUaGUgYGxvYWRpbmdTdGF0ZWAgbWlnaHQgaGF2ZSBjaGFuZ2VkIHRvIFwibG9hZGluZ1wiLlxuICAgICAgaWYgKCh0RGV0YWlscy5sb2FkaW5nU3RhdGUgYXMgRGVmZXJEZXBlbmRlbmNpZXNMb2FkaW5nU3RhdGUpID09PVxuICAgICAgICAgIERlZmVyRGVwZW5kZW5jaWVzTG9hZGluZ1N0YXRlLklOX1BST0dSRVNTKSB7XG4gICAgICAgIHJlbmRlckRlZmVyU3RhdGVBZnRlclJlc291cmNlTG9hZGluZyh0RGV0YWlscywgdE5vZGUsIGxDb250YWluZXIpO1xuICAgICAgfVxuICAgICAgYnJlYWs7XG4gICAgY2FzZSBEZWZlckRlcGVuZGVuY2llc0xvYWRpbmdTdGF0ZS5JTl9QUk9HUkVTUzpcbiAgICAgIHJlbmRlckRlZmVyQmxvY2tTdGF0ZShEZWZlckJsb2NrU3RhdGUuTG9hZGluZywgdE5vZGUsIGxDb250YWluZXIpO1xuICAgICAgcmVuZGVyRGVmZXJTdGF0ZUFmdGVyUmVzb3VyY2VMb2FkaW5nKHREZXRhaWxzLCB0Tm9kZSwgbENvbnRhaW5lcik7XG4gICAgICBicmVhaztcbiAgICBjYXNlIERlZmVyRGVwZW5kZW5jaWVzTG9hZGluZ1N0YXRlLkNPTVBMRVRFOlxuICAgICAgbmdEZXZNb2RlICYmIGFzc2VydERlZmVycmVkRGVwZW5kZW5jaWVzTG9hZGVkKHREZXRhaWxzKTtcbiAgICAgIHJlbmRlckRlZmVyQmxvY2tTdGF0ZShEZWZlckJsb2NrU3RhdGUuQ29tcGxldGUsIHROb2RlLCBsQ29udGFpbmVyKTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgRGVmZXJEZXBlbmRlbmNpZXNMb2FkaW5nU3RhdGUuRkFJTEVEOlxuICAgICAgcmVuZGVyRGVmZXJCbG9ja1N0YXRlKERlZmVyQmxvY2tTdGF0ZS5FcnJvciwgdE5vZGUsIGxDb250YWluZXIpO1xuICAgICAgYnJlYWs7XG4gICAgZGVmYXVsdDpcbiAgICAgIGlmIChuZ0Rldk1vZGUpIHtcbiAgICAgICAgdGhyb3dFcnJvcignVW5rbm93biBkZWZlciBibG9jayBzdGF0ZScpO1xuICAgICAgfVxuICB9XG59XG5cbi8qKlxuICogQXNzZXJ0cyB3aGV0aGVyIGFsbCBkZXBlbmRlbmNpZXMgZm9yIGEgZGVmZXIgYmxvY2sgYXJlIGxvYWRlZC5cbiAqIEFsd2F5cyBydW4gdGhpcyBmdW5jdGlvbiAoaW4gZGV2IG1vZGUpIGJlZm9yZSByZW5kZXJpbmcgYSBkZWZlclxuICogYmxvY2sgaW4gY29tcGxldGVkIHN0YXRlLlxuICovXG5mdW5jdGlvbiBhc3NlcnREZWZlcnJlZERlcGVuZGVuY2llc0xvYWRlZCh0RGV0YWlsczogVERlZmVyQmxvY2tEZXRhaWxzKSB7XG4gIGFzc2VydEVxdWFsKFxuICAgICAgdERldGFpbHMubG9hZGluZ1N0YXRlLCBEZWZlckRlcGVuZGVuY2llc0xvYWRpbmdTdGF0ZS5DT01QTEVURSxcbiAgICAgICdFeHBlY3RpbmcgYWxsIGRlZmVycmVkIGRlcGVuZGVuY2llcyB0byBiZSBsb2FkZWQuJyk7XG59XG5cbi8qKlxuICogKipJTlRFUk5BTCoqLCBhdm9pZCByZWZlcmVuY2luZyBpdCBpbiBhcHBsaWNhdGlvbiBjb2RlLlxuICpcbiAqIERlc2NyaWJlcyBhIGhlbHBlciBjbGFzcyB0aGF0IGFsbG93cyB0byBpbnRlcmNlcHQgYSBjYWxsIHRvIHJldHJpZXZlIGN1cnJlbnRcbiAqIGRlcGVuZGVuY3kgbG9hZGluZyBmdW5jdGlvbiBhbmQgcmVwbGFjZSBpdCB3aXRoIGEgZGlmZmVyZW50IGltcGxlbWVudGF0aW9uLlxuICogVGhpcyBpbnRlcmNlcHRvciBjbGFzcyBpcyBuZWVkZWQgdG8gYWxsb3cgdGVzdGluZyBibG9ja3MgaW4gZGlmZmVyZW50IHN0YXRlc1xuICogYnkgc2ltdWxhdGluZyBsb2FkaW5nIHJlc3BvbnNlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIERlZmVyQmxvY2tEZXBlbmRlbmN5SW50ZXJjZXB0b3Ige1xuICAvKipcbiAgICogSW52b2tlZCBmb3IgZWFjaCBkZWZlciBibG9jayB3aGVuIGRlcGVuZGVuY3kgbG9hZGluZyBmdW5jdGlvbiBpcyBhY2Nlc3NlZC5cbiAgICovXG4gIGludGVyY2VwdChkZXBlbmRlbmN5Rm46IERlcGVuZGVuY3lSZXNvbHZlckZufG51bGwpOiBEZXBlbmRlbmN5UmVzb2x2ZXJGbnxudWxsO1xuXG4gIC8qKlxuICAgKiBBbGxvd3MgdG8gY29uZmlndXJlIGFuIGludGVyY2VwdG9yIGZ1bmN0aW9uLlxuICAgKi9cbiAgc2V0SW50ZXJjZXB0b3IoaW50ZXJjZXB0b3JGbjogKGN1cnJlbnQ6IERlcGVuZGVuY3lSZXNvbHZlckZuKSA9PiBEZXBlbmRlbmN5UmVzb2x2ZXJGbik6IHZvaWQ7XG59XG5cbi8qKlxuICogKipJTlRFUk5BTCoqLCBhdm9pZCByZWZlcmVuY2luZyBpdCBpbiBhcHBsaWNhdGlvbiBjb2RlLlxuICpcbiAqIEluamVjdG9yIHRva2VuIHRoYXQgYWxsb3dzIHRvIHByb3ZpZGUgYERlZmVyQmxvY2tEZXBlbmRlbmN5SW50ZXJjZXB0b3JgIGNsYXNzXG4gKiBpbXBsZW1lbnRhdGlvbi5cbiAqL1xuZXhwb3J0IGNvbnN0IERFRkVSX0JMT0NLX0RFUEVOREVOQ1lfSU5URVJDRVBUT1IgPVxuICAgIG5ldyBJbmplY3Rpb25Ub2tlbjxEZWZlckJsb2NrRGVwZW5kZW5jeUludGVyY2VwdG9yPihcbiAgICAgICAgbmdEZXZNb2RlID8gJ0RFRkVSX0JMT0NLX0RFUEVOREVOQ1lfSU5URVJDRVBUT1InIDogJycpO1xuXG4vKipcbiAqIERldGVybWluZXMgaWYgYSBnaXZlbiB2YWx1ZSBtYXRjaGVzIHRoZSBleHBlY3RlZCBzdHJ1Y3R1cmUgb2YgYSBkZWZlciBibG9ja1xuICpcbiAqIFdlIGNhbiBzYWZlbHkgcmVseSBvbiB0aGUgcHJpbWFyeVRtcGxJbmRleCBiZWNhdXNlIGV2ZXJ5IGRlZmVyIGJsb2NrIHJlcXVpcmVzXG4gKiB0aGF0IGEgcHJpbWFyeSB0ZW1wbGF0ZSBleGlzdHMuIEFsbCB0aGUgb3RoZXIgdGVtcGxhdGUgb3B0aW9ucyBhcmUgb3B0aW9uYWwuXG4gKi9cbmZ1bmN0aW9uIGlzVERlZmVyQmxvY2tEZXRhaWxzKHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgVERlZmVyQmxvY2tEZXRhaWxzIHtcbiAgcmV0dXJuICh0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnKSAmJlxuICAgICAgKHR5cGVvZiAodmFsdWUgYXMgVERlZmVyQmxvY2tEZXRhaWxzKS5wcmltYXJ5VG1wbEluZGV4ID09PSAnbnVtYmVyJyk7XG59XG5cbi8qKlxuICogSW50ZXJuYWwgdG9rZW4gdXNlZCBmb3IgY29uZmlndXJpbmcgZGVmZXIgYmxvY2sgYmVoYXZpb3IuXG4gKi9cbmV4cG9ydCBjb25zdCBERUZFUl9CTE9DS19DT05GSUcgPVxuICAgIG5ldyBJbmplY3Rpb25Ub2tlbjxEZWZlckJsb2NrQ29uZmlnPihuZ0Rldk1vZGUgPyAnREVGRVJfQkxPQ0tfQ09ORklHJyA6ICcnKTtcblxuLyoqXG4gKiBEZWZlciBibG9jayBpbnN0YW5jZSBmb3IgdGVzdGluZy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEZWZlckJsb2NrRGV0YWlscyB7XG4gIGxDb250YWluZXI6IExDb250YWluZXI7XG4gIGxWaWV3OiBMVmlldztcbiAgdE5vZGU6IFROb2RlO1xuICB0RGV0YWlsczogVERlZmVyQmxvY2tEZXRhaWxzO1xufVxuXG4vKipcbiAqIFJldHJpZXZlcyBhbGwgZGVmZXIgYmxvY2tzIGluIGEgZ2l2ZW4gTFZpZXcuXG4gKlxuICogQHBhcmFtIGxWaWV3IGxWaWV3IHdpdGggZGVmZXIgYmxvY2tzXG4gKiBAcGFyYW0gZGVmZXJCbG9ja3MgZGVmZXIgYmxvY2sgYWdncmVnYXRvciBhcnJheVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0RGVmZXJCbG9ja3MobFZpZXc6IExWaWV3LCBkZWZlckJsb2NrczogRGVmZXJCbG9ja0RldGFpbHNbXSkge1xuICBjb25zdCB0VmlldyA9IGxWaWV3W1RWSUVXXTtcbiAgZm9yIChsZXQgaSA9IEhFQURFUl9PRkZTRVQ7IGkgPCB0Vmlldy5iaW5kaW5nU3RhcnRJbmRleDsgaSsrKSB7XG4gICAgaWYgKGlzTENvbnRhaW5lcihsVmlld1tpXSkpIHtcbiAgICAgIGNvbnN0IGxDb250YWluZXIgPSBsVmlld1tpXTtcbiAgICAgIC8vIEFuIExDb250YWluZXIgbWF5IHJlcHJlc2VudCBhbiBpbnN0YW5jZSBvZiBhIGRlZmVyIGJsb2NrLCBpbiB3aGljaCBjYXNlXG4gICAgICAvLyB3ZSBzdG9yZSBpdCBhcyBhIHJlc3VsdC4gT3RoZXJ3aXNlLCBrZWVwIGl0ZXJhdGluZyBvdmVyIExDb250YWluZXIgdmlld3MgYW5kXG4gICAgICAvLyBsb29rIGZvciBkZWZlciBibG9ja3MuXG4gICAgICBjb25zdCBpc0xhc3QgPSBpID09PSB0Vmlldy5iaW5kaW5nU3RhcnRJbmRleCAtIDE7XG4gICAgICBpZiAoIWlzTGFzdCkge1xuICAgICAgICBjb25zdCB0Tm9kZSA9IHRWaWV3LmRhdGFbaV0gYXMgVE5vZGU7XG4gICAgICAgIGNvbnN0IHREZXRhaWxzID0gZ2V0VERlZmVyQmxvY2tEZXRhaWxzKHRWaWV3LCB0Tm9kZSk7XG4gICAgICAgIGlmIChpc1REZWZlckJsb2NrRGV0YWlscyh0RGV0YWlscykpIHtcbiAgICAgICAgICBkZWZlckJsb2Nrcy5wdXNoKHtsQ29udGFpbmVyLCBsVmlldywgdE5vZGUsIHREZXRhaWxzfSk7XG4gICAgICAgICAgLy8gVGhpcyBMQ29udGFpbmVyIHJlcHJlc2VudHMgYSBkZWZlciBibG9jaywgc28gd2UgZXhpdFxuICAgICAgICAgIC8vIHRoaXMgaXRlcmF0aW9uIGFuZCBkb24ndCBpbnNwZWN0IHZpZXdzIGluIHRoaXMgTENvbnRhaW5lci5cbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgZm9yIChsZXQgaSA9IENPTlRBSU5FUl9IRUFERVJfT0ZGU0VUOyBpIDwgbENvbnRhaW5lci5sZW5ndGg7IGkrKykge1xuICAgICAgICBnZXREZWZlckJsb2NrcyhsQ29udGFpbmVyW2ldIGFzIExWaWV3LCBkZWZlckJsb2Nrcyk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChpc0xWaWV3KGxWaWV3W2ldKSkge1xuICAgICAgLy8gVGhpcyBpcyBhIGNvbXBvbmVudCwgZW50ZXIgdGhlIGBnZXREZWZlckJsb2Nrc2AgcmVjdXJzaXZlbHkuXG4gICAgICBnZXREZWZlckJsb2NrcyhsVmlld1tpXSwgZGVmZXJCbG9ja3MpO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIFJlZ2lzdGVycyBhIGNsZWFudXAgZnVuY3Rpb24gYXNzb2NpYXRlZCB3aXRoIGEgcHJlZmV0Y2hpbmcgdHJpZ2dlclxuICogb2YgYSBnaXZlbiBkZWZlciBibG9jay5cbiAqL1xuZnVuY3Rpb24gcmVnaXN0ZXJURGV0YWlsc0NsZWFudXAoXG4gICAgaW5qZWN0b3I6IEluamVjdG9yLCB0RGV0YWlsczogVERlZmVyQmxvY2tEZXRhaWxzLCBrZXk6IHN0cmluZywgY2xlYW51cEZuOiBWb2lkRnVuY3Rpb24pIHtcbiAgaW5qZWN0b3IuZ2V0KERlZmVyQmxvY2tDbGVhbnVwTWFuYWdlcikuYWRkKHREZXRhaWxzLCBrZXksIGNsZWFudXBGbik7XG59XG5cbi8qKlxuICogSW52b2tlcyBhbGwgcmVnaXN0ZXJlZCBwcmVmZXRjaCBjbGVhbnVwIHRyaWdnZXJzXG4gKiBhbmQgcmVtb3ZlcyBhbGwgY2xlYW51cCBmdW5jdGlvbnMgYWZ0ZXJ3YXJkcy5cbiAqL1xuZnVuY3Rpb24gaW52b2tlVERldGFpbHNDbGVhbnVwKGluamVjdG9yOiBJbmplY3RvciwgdERldGFpbHM6IFREZWZlckJsb2NrRGV0YWlscykge1xuICBpbmplY3Rvci5nZXQoRGVmZXJCbG9ja0NsZWFudXBNYW5hZ2VyKS5jbGVhbnVwKHREZXRhaWxzKTtcbn1cblxuLyoqXG4gKiBJbnRlcm5hbCBzZXJ2aWNlIHRvIGtlZXAgdHJhY2sgb2YgY2xlYW51cCBmdW5jdGlvbnMgYXNzb2NpYXRlZFxuICogd2l0aCBkZWZlciBibG9ja3MuIFRoaXMgY2xhc3MgaXMgdXNlZCB0byBtYW5hZ2UgY2xlYW51cCBmdW5jdGlvbnNcbiAqIGNyZWF0ZWQgZm9yIHByZWZldGNoaW5nIHRyaWdnZXJzLlxuICovXG5jbGFzcyBEZWZlckJsb2NrQ2xlYW51cE1hbmFnZXIge1xuICBwcml2YXRlIGJsb2NrcyA9IG5ldyBNYXA8VERlZmVyQmxvY2tEZXRhaWxzLCBNYXA8c3RyaW5nLCBWb2lkRnVuY3Rpb25bXT4+KCk7XG5cbiAgYWRkKHREZXRhaWxzOiBURGVmZXJCbG9ja0RldGFpbHMsIGtleTogc3RyaW5nLCBjYWxsYmFjazogVm9pZEZ1bmN0aW9uKSB7XG4gICAgaWYgKCF0aGlzLmJsb2Nrcy5oYXModERldGFpbHMpKSB7XG4gICAgICB0aGlzLmJsb2Nrcy5zZXQodERldGFpbHMsIG5ldyBNYXAoKSk7XG4gICAgfVxuICAgIGNvbnN0IGJsb2NrID0gdGhpcy5ibG9ja3MuZ2V0KHREZXRhaWxzKSE7XG4gICAgaWYgKCFibG9jay5oYXMoa2V5KSkge1xuICAgICAgYmxvY2suc2V0KGtleSwgW10pO1xuICAgIH1cbiAgICBjb25zdCBjYWxsYmFja3MgPSBibG9jay5nZXQoa2V5KSE7XG4gICAgY2FsbGJhY2tzLnB1c2goY2FsbGJhY2spO1xuICB9XG5cbiAgaGFzKHREZXRhaWxzOiBURGVmZXJCbG9ja0RldGFpbHMsIGtleTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICEhdGhpcy5ibG9ja3MuZ2V0KHREZXRhaWxzKT8uaGFzKGtleSk7XG4gIH1cblxuICBjbGVhbnVwKHREZXRhaWxzOiBURGVmZXJCbG9ja0RldGFpbHMpIHtcbiAgICBjb25zdCBibG9jayA9IHRoaXMuYmxvY2tzLmdldCh0RGV0YWlscyk7XG4gICAgaWYgKGJsb2NrKSB7XG4gICAgICBmb3IgKGNvbnN0IGNhbGxiYWNrcyBvZiBPYmplY3QudmFsdWVzKGJsb2NrKSkge1xuICAgICAgICBmb3IgKGNvbnN0IGNhbGxiYWNrIG9mIGNhbGxiYWNrcykge1xuICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHRoaXMuYmxvY2tzLmRlbGV0ZSh0RGV0YWlscyk7XG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgZm9yIChjb25zdCBbYmxvY2tdIG9mIHRoaXMuYmxvY2tzKSB7XG4gICAgICB0aGlzLmNsZWFudXAoYmxvY2spO1xuICAgIH1cbiAgICB0aGlzLmJsb2Nrcy5jbGVhcigpO1xuICB9XG5cbiAgLyoqIEBub2NvbGxhcHNlICovXG4gIHN0YXRpYyDJtXByb3YgPSAvKiogQHB1cmVPckJyZWFrTXlDb2RlICovIMm1ybVkZWZpbmVJbmplY3RhYmxlKHtcbiAgICB0b2tlbjogRGVmZXJCbG9ja0NsZWFudXBNYW5hZ2VyLFxuICAgIHByb3ZpZGVkSW46ICdyb290JyxcbiAgICBmYWN0b3J5OiAoKSA9PiBuZXcgRGVmZXJCbG9ja0NsZWFudXBNYW5hZ2VyKCksXG4gIH0pO1xufVxuXG4vKipcbiAqIFVzZSBzaGltcyBmb3IgdGhlIGByZXF1ZXN0SWRsZUNhbGxiYWNrYCBhbmQgYGNhbmNlbElkbGVDYWxsYmFja2AgZnVuY3Rpb25zIGZvclxuICogZW52aXJvbm1lbnRzIHdoZXJlIHRob3NlIGZ1bmN0aW9ucyBhcmUgbm90IGF2YWlsYWJsZSAoZS5nLiBOb2RlLmpzIGFuZCBTYWZhcmkpLlxuICpcbiAqIE5vdGU6IHdlIHdyYXAgdGhlIGByZXF1ZXN0SWRsZUNhbGxiYWNrYCBjYWxsIGludG8gYSBmdW5jdGlvbiwgc28gdGhhdCBpdCBjYW4gYmVcbiAqIG92ZXJyaWRkZW4vbW9ja2VkIGluIHRlc3QgZW52aXJvbm1lbnQgYW5kIHBpY2tlZCB1cCBieSB0aGUgcnVudGltZSBjb2RlLlxuICovXG5jb25zdCBfcmVxdWVzdElkbGVDYWxsYmFjayA9ICgpID0+XG4gICAgdHlwZW9mIHJlcXVlc3RJZGxlQ2FsbGJhY2sgIT09ICd1bmRlZmluZWQnID8gcmVxdWVzdElkbGVDYWxsYmFjayA6IHNldFRpbWVvdXQ7XG5jb25zdCBfY2FuY2VsSWRsZUNhbGxiYWNrID0gKCkgPT5cbiAgICB0eXBlb2YgcmVxdWVzdElkbGVDYWxsYmFjayAhPT0gJ3VuZGVmaW5lZCcgPyBjYW5jZWxJZGxlQ2FsbGJhY2sgOiBjbGVhclRpbWVvdXQ7XG5cbi8qKlxuICogSGVscGVyIHNlcnZpY2UgdG8gc2NoZWR1bGUgYHJlcXVlc3RJZGxlQ2FsbGJhY2tgcyBmb3IgYmF0Y2hlcyBvZiBkZWZlciBibG9ja3MsXG4gKiB0byBhdm9pZCBjYWxsaW5nIGByZXF1ZXN0SWRsZUNhbGxiYWNrYCBmb3IgZWFjaCBkZWZlciBibG9jayAoZS5nLiBpZlxuICogZGVmZXIgYmxvY2tzIGFyZSBkZWZpbmVkIGluc2lkZSBhIGZvciBsb29wKS5cbiAqL1xuY2xhc3MgT25JZGxlU2NoZWR1bGVyIHtcbiAgLy8gSW5kaWNhdGVzIHdoZXRoZXIgY3VycmVudCBjYWxsYmFja3MgYXJlIGJlaW5nIGludm9rZWQuXG4gIGV4ZWN1dGluZ0NhbGxiYWNrcyA9IGZhbHNlO1xuXG4gIC8vIEN1cnJlbnRseSBzY2hlZHVsZWQgaWRsZSBjYWxsYmFjayBpZC5cbiAgaWRsZUlkOiBudW1iZXJ8bnVsbCA9IG51bGw7XG5cbiAgLy8gU2V0IG9mIGNhbGxiYWNrcyB0byBiZSBpbnZva2VkIG5leHQuXG4gIGN1cnJlbnQgPSBuZXcgU2V0PFZvaWRGdW5jdGlvbj4oKTtcblxuICAvLyBTZXQgb2YgY2FsbGJhY2tzIGNvbGxlY3RlZCB3aGlsZSBpbnZva2luZyBjdXJyZW50IHNldCBvZiBjYWxsYmFja3MuXG4gIC8vIFRob3NlIGNhbGxiYWNrcyBhcmUgc2NoZWR1bGVkIGZvciB0aGUgbmV4dCBpZGxlIHBlcmlvZC5cbiAgZGVmZXJyZWQgPSBuZXcgU2V0PFZvaWRGdW5jdGlvbj4oKTtcblxuICBuZ1pvbmUgPSBpbmplY3QoTmdab25lKTtcblxuICByZXF1ZXN0SWRsZUNhbGxiYWNrID0gX3JlcXVlc3RJZGxlQ2FsbGJhY2soKS5iaW5kKGdsb2JhbFRoaXMpO1xuICBjYW5jZWxJZGxlQ2FsbGJhY2sgPSBfY2FuY2VsSWRsZUNhbGxiYWNrKCkuYmluZChnbG9iYWxUaGlzKTtcblxuICBhZGQoY2FsbGJhY2s6IFZvaWRGdW5jdGlvbikge1xuICAgIGNvbnN0IHRhcmdldCA9IHRoaXMuZXhlY3V0aW5nQ2FsbGJhY2tzID8gdGhpcy5kZWZlcnJlZCA6IHRoaXMuY3VycmVudDtcbiAgICB0YXJnZXQuYWRkKGNhbGxiYWNrKTtcbiAgICBpZiAodGhpcy5pZGxlSWQgPT09IG51bGwpIHtcbiAgICAgIHRoaXMuc2NoZWR1bGVJZGxlQ2FsbGJhY2soKTtcbiAgICB9XG4gIH1cblxuICByZW1vdmUoY2FsbGJhY2s6IFZvaWRGdW5jdGlvbikge1xuICAgIHRoaXMuY3VycmVudC5kZWxldGUoY2FsbGJhY2spO1xuICAgIHRoaXMuZGVmZXJyZWQuZGVsZXRlKGNhbGxiYWNrKTtcbiAgfVxuXG4gIHByaXZhdGUgc2NoZWR1bGVJZGxlQ2FsbGJhY2soKSB7XG4gICAgY29uc3QgY2FsbGJhY2sgPSAoKSA9PiB7XG4gICAgICB0aGlzLmNhbmNlbElkbGVDYWxsYmFjayh0aGlzLmlkbGVJZCEpO1xuICAgICAgdGhpcy5pZGxlSWQgPSBudWxsO1xuXG4gICAgICB0aGlzLmV4ZWN1dGluZ0NhbGxiYWNrcyA9IHRydWU7XG5cbiAgICAgIGZvciAoY29uc3QgY2FsbGJhY2sgb2YgdGhpcy5jdXJyZW50KSB7XG4gICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICB9XG4gICAgICB0aGlzLmN1cnJlbnQuY2xlYXIoKTtcblxuICAgICAgdGhpcy5leGVjdXRpbmdDYWxsYmFja3MgPSBmYWxzZTtcblxuICAgICAgLy8gSWYgdGhlcmUgYXJlIGFueSBjYWxsYmFja3MgYWRkZWQgZHVyaW5nIGFuIGludm9jYXRpb25cbiAgICAgIC8vIG9mIHRoZSBjdXJyZW50IG9uZXMgLSBtYWtlIHRoZW0gXCJjdXJyZW50XCIgYW5kIHNjaGVkdWxlXG4gICAgICAvLyBhIG5ldyBpZGxlIGNhbGxiYWNrLlxuICAgICAgaWYgKHRoaXMuZGVmZXJyZWQuc2l6ZSA+IDApIHtcbiAgICAgICAgZm9yIChjb25zdCBjYWxsYmFjayBvZiB0aGlzLmRlZmVycmVkKSB7XG4gICAgICAgICAgdGhpcy5jdXJyZW50LmFkZChjYWxsYmFjayk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5kZWZlcnJlZC5jbGVhcigpO1xuICAgICAgICB0aGlzLnNjaGVkdWxlSWRsZUNhbGxiYWNrKCk7XG4gICAgICB9XG4gICAgfTtcbiAgICAvLyBFbnN1cmUgdGhhdCB0aGUgY2FsbGJhY2sgcnVucyBpbiB0aGUgTmdab25lIHNpbmNlXG4gICAgLy8gdGhlIGByZXF1ZXN0SWRsZUNhbGxiYWNrYCBpcyBub3QgY3VycmVudGx5IHBhdGNoZWQgYnkgWm9uZS5qcy5cbiAgICB0aGlzLmlkbGVJZCA9IHRoaXMucmVxdWVzdElkbGVDYWxsYmFjaygoKSA9PiB0aGlzLm5nWm9uZS5ydW4oY2FsbGJhY2spKSBhcyBudW1iZXI7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpIHtcbiAgICBpZiAodGhpcy5pZGxlSWQgIT09IG51bGwpIHtcbiAgICAgIHRoaXMuY2FuY2VsSWRsZUNhbGxiYWNrKHRoaXMuaWRsZUlkKTtcbiAgICAgIHRoaXMuaWRsZUlkID0gbnVsbDtcbiAgICB9XG4gICAgdGhpcy5jdXJyZW50LmNsZWFyKCk7XG4gICAgdGhpcy5kZWZlcnJlZC5jbGVhcigpO1xuICB9XG5cbiAgLyoqIEBub2NvbGxhcHNlICovXG4gIHN0YXRpYyDJtXByb3YgPSAvKiogQHB1cmVPckJyZWFrTXlDb2RlICovIMm1ybVkZWZpbmVJbmplY3RhYmxlKHtcbiAgICB0b2tlbjogT25JZGxlU2NoZWR1bGVyLFxuICAgIHByb3ZpZGVkSW46ICdyb290JyxcbiAgICBmYWN0b3J5OiAoKSA9PiBuZXcgT25JZGxlU2NoZWR1bGVyKCksXG4gIH0pO1xufVxuXG4vKipcbiAqIEhlbHBlciBzZXJ2aWNlIHRvIHNjaGVkdWxlIGBzZXRUaW1lb3V0YHMgZm9yIGJhdGNoZXMgb2YgZGVmZXIgYmxvY2tzLFxuICogdG8gYXZvaWQgY2FsbGluZyBgc2V0VGltZW91dGAgZm9yIGVhY2ggZGVmZXIgYmxvY2sgKGUuZy4gaWYgZGVmZXIgYmxvY2tzXG4gKiBhcmUgY3JlYXRlZCBpbnNpZGUgYSBmb3IgbG9vcCkuXG4gKi9cbmNsYXNzIFRpbWVyU2NoZWR1bGVyIHtcbiAgLy8gSW5kaWNhdGVzIHdoZXRoZXIgY3VycmVudCBjYWxsYmFja3MgYXJlIGJlaW5nIGludm9rZWQuXG4gIGV4ZWN1dGluZ0NhbGxiYWNrcyA9IGZhbHNlO1xuXG4gIC8vIEN1cnJlbnRseSBzY2hlZHVsZWQgYHNldFRpbWVvdXRgIGlkLlxuICB0aW1lb3V0SWQ6IG51bWJlcnxudWxsID0gbnVsbDtcblxuICAvLyBXaGVuIGN1cnJlbnRseSBzY2hlZHVsZWQgdGltZXIgd291bGQgZmlyZS5cbiAgaW52b2tlVGltZXJBdDogbnVtYmVyfG51bGwgPSBudWxsO1xuXG4gIC8vIExpc3Qgb2YgY2FsbGJhY2tzIHRvIGJlIGludm9rZWQuXG4gIC8vIEZvciBlYWNoIGNhbGxiYWNrIHdlIGFsc28gc3RvcmUgYSB0aW1lc3RhbXAgb24gd2hlbiB0aGUgY2FsbGJhY2tcbiAgLy8gc2hvdWxkIGJlIGludm9rZWQuIFdlIHN0b3JlIHRpbWVzdGFtcHMgYW5kIGNhbGxiYWNrIGZ1bmN0aW9uc1xuICAvLyBpbiBhIGZsYXQgYXJyYXkgdG8gYXZvaWQgY3JlYXRpbmcgbmV3IG9iamVjdHMgZm9yIGVhY2ggZW50cnkuXG4gIC8vIFt0aW1lc3RhbXAxLCBjYWxsYmFjazEsIHRpbWVzdGFtcDIsIGNhbGxiYWNrMiwgLi4uXVxuICBjdXJyZW50OiBBcnJheTxudW1iZXJ8Vm9pZEZ1bmN0aW9uPiA9IFtdO1xuXG4gIC8vIExpc3Qgb2YgY2FsbGJhY2tzIGNvbGxlY3RlZCB3aGlsZSBpbnZva2luZyBjdXJyZW50IHNldCBvZiBjYWxsYmFja3MuXG4gIC8vIFRob3NlIGNhbGxiYWNrcyBhcmUgYWRkZWQgdG8gdGhlIFwiY3VycmVudFwiIHF1ZXVlIGF0IHRoZSBlbmQgb2ZcbiAgLy8gdGhlIGN1cnJlbnQgY2FsbGJhY2sgaW52b2NhdGlvbi4gVGhlIHNoYXBlIG9mIHRoaXMgbGlzdCBpcyB0aGUgc2FtZVxuICAvLyBhcyB0aGUgc2hhcGUgb2YgdGhlIGBjdXJyZW50YCBsaXN0LlxuICBkZWZlcnJlZDogQXJyYXk8bnVtYmVyfFZvaWRGdW5jdGlvbj4gPSBbXTtcblxuICBhZGQoZGVsYXk6IG51bWJlciwgY2FsbGJhY2s6IFZvaWRGdW5jdGlvbikge1xuICAgIGNvbnN0IHRhcmdldCA9IHRoaXMuZXhlY3V0aW5nQ2FsbGJhY2tzID8gdGhpcy5kZWZlcnJlZCA6IHRoaXMuY3VycmVudDtcbiAgICB0aGlzLmFkZFRvUXVldWUodGFyZ2V0LCBEYXRlLm5vdygpICsgZGVsYXksIGNhbGxiYWNrKTtcbiAgICB0aGlzLnNjaGVkdWxlVGltZXIoKTtcbiAgfVxuXG4gIHJlbW92ZShjYWxsYmFjazogVm9pZEZ1bmN0aW9uKSB7XG4gICAgY29uc3QgY2FsbGJhY2tJbmRleCA9IHRoaXMucmVtb3ZlRnJvbVF1ZXVlKHRoaXMuY3VycmVudCwgY2FsbGJhY2spO1xuICAgIGlmIChjYWxsYmFja0luZGV4ID09PSAtMSkge1xuICAgICAgLy8gVHJ5IGNsZWFuaW5nIHVwIGRlZmVycmVkIHF1ZXVlIG9ubHkgaW4gY2FzZVxuICAgICAgLy8gd2UgZGlkbid0IGZpbmQgYSBjYWxsYmFjayBpbiB0aGUgXCJjdXJyZW50XCIgcXVldWUuXG4gICAgICB0aGlzLnJlbW92ZUZyb21RdWV1ZSh0aGlzLmRlZmVycmVkLCBjYWxsYmFjayk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhZGRUb1F1ZXVlKHRhcmdldDogQXJyYXk8bnVtYmVyfFZvaWRGdW5jdGlvbj4sIGludm9rZUF0OiBudW1iZXIsIGNhbGxiYWNrOiBWb2lkRnVuY3Rpb24pIHtcbiAgICBsZXQgaW5zZXJ0QXRJbmRleCA9IHRhcmdldC5sZW5ndGg7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0YXJnZXQubGVuZ3RoOyBpICs9IDIpIHtcbiAgICAgIGNvbnN0IGludm9rZVF1ZXVlZENhbGxiYWNrQXQgPSB0YXJnZXRbaV0gYXMgbnVtYmVyO1xuICAgICAgaWYgKGludm9rZVF1ZXVlZENhbGxiYWNrQXQgPiBpbnZva2VBdCkge1xuICAgICAgICAvLyBXZSd2ZSByZWFjaGVkIGEgZmlyc3QgdGltZXIgdGhhdCBpcyBzY2hlZHVsZWRcbiAgICAgICAgLy8gZm9yIGEgbGF0ZXIgdGltZSB0aGFuIHdoYXQgd2UgYXJlIHRyeWluZyB0byBpbnNlcnQuXG4gICAgICAgIC8vIFRoaXMgaXMgdGhlIGxvY2F0aW9uIGF0IHdoaWNoIHdlIG5lZWQgdG8gaW5zZXJ0LFxuICAgICAgICAvLyBubyBuZWVkIHRvIGl0ZXJhdGUgZnVydGhlci5cbiAgICAgICAgaW5zZXJ0QXRJbmRleCA9IGk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgICBhcnJheUluc2VydDIodGFyZ2V0LCBpbnNlcnRBdEluZGV4LCBpbnZva2VBdCwgY2FsbGJhY2spO1xuICB9XG5cbiAgcHJpdmF0ZSByZW1vdmVGcm9tUXVldWUodGFyZ2V0OiBBcnJheTxudW1iZXJ8Vm9pZEZ1bmN0aW9uPiwgY2FsbGJhY2s6IFZvaWRGdW5jdGlvbikge1xuICAgIGxldCBpbmRleCA9IC0xO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGFyZ2V0Lmxlbmd0aDsgaSArPSAyKSB7XG4gICAgICBjb25zdCBxdWV1ZWRDYWxsYmFjayA9IHRhcmdldFtpICsgMV07XG4gICAgICBpZiAocXVldWVkQ2FsbGJhY2sgPT09IGNhbGxiYWNrKSB7XG4gICAgICAgIGluZGV4ID0gaTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChpbmRleCA+IC0xKSB7XG4gICAgICAvLyBSZW1vdmUgMiBlbGVtZW50czogYSB0aW1lc3RhbXAgc2xvdCBhbmRcbiAgICAgIC8vIHRoZSBmb2xsb3dpbmcgc2xvdCB3aXRoIGEgY2FsbGJhY2sgZnVuY3Rpb24uXG4gICAgICBhcnJheVNwbGljZSh0YXJnZXQsIGluZGV4LCAyKTtcbiAgICB9XG4gICAgcmV0dXJuIGluZGV4O1xuICB9XG5cbiAgcHJpdmF0ZSBzY2hlZHVsZVRpbWVyKCkge1xuICAgIGNvbnN0IGNhbGxiYWNrID0gKCkgPT4ge1xuICAgICAgY2xlYXJUaW1lb3V0KHRoaXMudGltZW91dElkISk7XG4gICAgICB0aGlzLnRpbWVvdXRJZCA9IG51bGw7XG5cbiAgICAgIHRoaXMuZXhlY3V0aW5nQ2FsbGJhY2tzID0gdHJ1ZTtcblxuICAgICAgLy8gSW52b2tlIGNhbGxiYWNrcyB0aGF0IHdlcmUgc2NoZWR1bGVkIHRvIHJ1blxuICAgICAgLy8gYmVmb3JlIHRoZSBjdXJyZW50IHRpbWUuXG4gICAgICBsZXQgbm93ID0gRGF0ZS5ub3coKTtcbiAgICAgIGxldCBsYXN0Q2FsbGJhY2tJbmRleDogbnVtYmVyfG51bGwgPSBudWxsO1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmN1cnJlbnQubGVuZ3RoOyBpICs9IDIpIHtcbiAgICAgICAgY29uc3QgaW52b2tlQXQgPSB0aGlzLmN1cnJlbnRbaV0gYXMgbnVtYmVyO1xuICAgICAgICBjb25zdCBjYWxsYmFjayA9IHRoaXMuY3VycmVudFtpICsgMV0gYXMgVm9pZEZ1bmN0aW9uO1xuICAgICAgICBpZiAoaW52b2tlQXQgPD0gbm93KSB7XG4gICAgICAgICAgY2FsbGJhY2soKTtcbiAgICAgICAgICAvLyBQb2ludCBhdCB0aGUgaW52b2tlZCBjYWxsYmFjayBmdW5jdGlvbiwgd2hpY2ggaXMgbG9jYXRlZFxuICAgICAgICAgIC8vIGFmdGVyIHRoZSB0aW1lc3RhbXAuXG4gICAgICAgICAgbGFzdENhbGxiYWNrSW5kZXggPSBpICsgMTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBXZSd2ZSByZWFjaGVkIGEgdGltZXIgdGhhdCBzaG91bGQgbm90IGJlIGludm9rZWQgeWV0LlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAobGFzdENhbGxiYWNrSW5kZXggIT09IG51bGwpIHtcbiAgICAgICAgLy8gSWYgbGFzdCBjYWxsYmFjayBpbmRleCBpcyBgbnVsbGAgLSBubyBjYWxsYmFja3Mgd2VyZSBpbnZva2VkLFxuICAgICAgICAvLyBzbyBubyBjbGVhbnVwIGlzIG5lZWRlZC4gT3RoZXJ3aXNlLCByZW1vdmUgaW52b2tlZCBjYWxsYmFja3NcbiAgICAgICAgLy8gZnJvbSB0aGUgcXVldWUuXG4gICAgICAgIGFycmF5U3BsaWNlKHRoaXMuY3VycmVudCwgMCwgbGFzdENhbGxiYWNrSW5kZXggKyAxKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5leGVjdXRpbmdDYWxsYmFja3MgPSBmYWxzZTtcblxuICAgICAgLy8gSWYgdGhlcmUgYXJlIGFueSBjYWxsYmFja3MgYWRkZWQgZHVyaW5nIGFuIGludm9jYXRpb25cbiAgICAgIC8vIG9mIHRoZSBjdXJyZW50IG9uZXMgLSBtb3ZlIHRoZW0gb3ZlciB0byB0aGUgXCJjdXJyZW50XCJcbiAgICAgIC8vIHF1ZXVlLlxuICAgICAgaWYgKHRoaXMuZGVmZXJyZWQubGVuZ3RoID4gMCkge1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuZGVmZXJyZWQubGVuZ3RoOyBpICs9IDIpIHtcbiAgICAgICAgICBjb25zdCBpbnZva2VBdCA9IHRoaXMuZGVmZXJyZWRbaV0gYXMgbnVtYmVyO1xuICAgICAgICAgIGNvbnN0IGNhbGxiYWNrID0gdGhpcy5kZWZlcnJlZFtpICsgMV0gYXMgVm9pZEZ1bmN0aW9uO1xuICAgICAgICAgIHRoaXMuYWRkVG9RdWV1ZSh0aGlzLmN1cnJlbnQsIGludm9rZUF0LCBjYWxsYmFjayk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5kZWZlcnJlZC5sZW5ndGggPSAwO1xuICAgICAgfVxuICAgICAgdGhpcy5zY2hlZHVsZVRpbWVyKCk7XG4gICAgfTtcblxuICAgIC8vIEF2b2lkIHJ1bm5pbmcgdGltZXIgY2FsbGJhY2tzIG1vcmUgdGhhbiBvbmNlIHBlclxuICAgIC8vIGF2ZXJhZ2UgZnJhbWUgZHVyYXRpb24uIFRoaXMgaXMgbmVlZGVkIGZvciBiZXR0ZXJcbiAgICAvLyBiYXRjaGluZyBhbmQgdG8gYXZvaWQga2lja2luZyBvZmYgZXhjZXNzaXZlIGNoYW5nZVxuICAgIC8vIGRldGVjdGlvbiBjeWNsZXMuXG4gICAgY29uc3QgRlJBTUVfRFVSQVRJT05fTVMgPSAxNjsgIC8vIDEwMDBtcyAvIDYwZnBzXG5cbiAgICBpZiAodGhpcy5jdXJyZW50Lmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gICAgICAvLyBGaXJzdCBlbGVtZW50IGluIHRoZSBxdWV1ZSBwb2ludHMgYXQgdGhlIHRpbWVzdGFtcFxuICAgICAgLy8gb2YgdGhlIGZpcnN0IChlYXJsaWVzdCkgZXZlbnQuXG4gICAgICBjb25zdCBpbnZva2VBdCA9IHRoaXMuY3VycmVudFswXSBhcyBudW1iZXI7XG4gICAgICBpZiAoIXRoaXMudGltZW91dElkIHx8XG4gICAgICAgICAgLy8gUmVzY2hlZHVsZSBhIHRpbWVyIGluIGNhc2UgYSBxdWV1ZSBjb250YWlucyBhbiBpdGVtIHdpdGhcbiAgICAgICAgICAvLyBhbiBlYXJsaWVyIHRpbWVzdGFtcCBhbmQgdGhlIGRlbHRhIGlzIG1vcmUgdGhhbiBhbiBhdmVyYWdlXG4gICAgICAgICAgLy8gZnJhbWUgZHVyYXRpb24uXG4gICAgICAgICAgKHRoaXMuaW52b2tlVGltZXJBdCAmJiAodGhpcy5pbnZva2VUaW1lckF0IC0gaW52b2tlQXQgPiBGUkFNRV9EVVJBVElPTl9NUykpKSB7XG4gICAgICAgIGlmICh0aGlzLnRpbWVvdXRJZCAhPT0gbnVsbCkge1xuICAgICAgICAgIC8vIFRoZXJlIHdhcyBhIHRpbWVvdXQgYWxyZWFkeSwgYnV0IGFuIGVhcmxpZXIgZXZlbnQgd2FzIGFkZGVkXG4gICAgICAgICAgLy8gaW50byB0aGUgcXVldWUuIEluIHRoaXMgY2FzZSB3ZSBkcm9wIGFuIG9sZCB0aW1lciBhbmQgc2V0dXBcbiAgICAgICAgICAvLyBhIG5ldyBvbmUgd2l0aCBhbiB1cGRhdGVkIChzbWFsbGVyKSB0aW1lb3V0LlxuICAgICAgICAgIGNsZWFyVGltZW91dCh0aGlzLnRpbWVvdXRJZCk7XG4gICAgICAgICAgdGhpcy50aW1lb3V0SWQgPSBudWxsO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHRpbWVvdXQgPSBNYXRoLm1heChpbnZva2VBdCAtIG5vdywgRlJBTUVfRFVSQVRJT05fTVMpO1xuICAgICAgICB0aGlzLmludm9rZVRpbWVyQXQgPSBpbnZva2VBdDtcbiAgICAgICAgdGhpcy50aW1lb3V0SWQgPSBzZXRUaW1lb3V0KGNhbGxiYWNrLCB0aW1lb3V0KSBhcyB1bmtub3duIGFzIG51bWJlcjtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBuZ09uRGVzdHJveSgpIHtcbiAgICBpZiAodGhpcy50aW1lb3V0SWQgIT09IG51bGwpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLnRpbWVvdXRJZCk7XG4gICAgICB0aGlzLnRpbWVvdXRJZCA9IG51bGw7XG4gICAgfVxuICAgIHRoaXMuY3VycmVudC5sZW5ndGggPSAwO1xuICAgIHRoaXMuZGVmZXJyZWQubGVuZ3RoID0gMDtcbiAgfVxuXG4gIC8qKiBAbm9jb2xsYXBzZSAqL1xuICBzdGF0aWMgybVwcm92ID0gLyoqIEBwdXJlT3JCcmVha015Q29kZSAqLyDJtcm1ZGVmaW5lSW5qZWN0YWJsZSh7XG4gICAgdG9rZW46IFRpbWVyU2NoZWR1bGVyLFxuICAgIHByb3ZpZGVkSW46ICdyb290JyxcbiAgICBmYWN0b3J5OiAoKSA9PiBuZXcgVGltZXJTY2hlZHVsZXIoKSxcbiAgfSk7XG59XG4iXX0=
|