@cqa-lib/cqa-ui 1.1.176 → 1.1.178
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/esm2020/lib/compare-runs/compare-runs.component.mjs +1 -1
- package/esm2020/lib/execution-screen/ai-action-step/ai-action-step.component.mjs +23 -7
- package/esm2020/lib/execution-screen/ai-agent-step/ai-agent-step.component.mjs +23 -8
- package/esm2020/lib/execution-screen/api-step/api-step.component.mjs +24 -7
- package/esm2020/lib/execution-screen/base-step.component.mjs +12 -1
- package/esm2020/lib/execution-screen/basic-step/basic-step.component.mjs +25 -8
- package/esm2020/lib/execution-screen/condition-step/condition-step.component.mjs +25 -8
- package/esm2020/lib/execution-screen/db-query-execution-item/db-query-execution-item.component.mjs +70 -5
- package/esm2020/lib/execution-screen/db-verification-step/db-verification-step.component.mjs +40 -11
- package/esm2020/lib/execution-screen/document-verification-step/document-verification-step.component.mjs +22 -4
- package/esm2020/lib/execution-screen/execution-step.models.mjs +1 -1
- package/esm2020/lib/execution-screen/file-download-step/file-download-step.component.mjs +23 -5
- package/esm2020/lib/execution-screen/loop-step/loop-step.component.mjs +26 -9
- package/esm2020/lib/execution-screen/step-group/step-group.component.mjs +22 -5
- package/esm2020/lib/execution-screen/step-renderer/step-renderer.component.mjs +6 -2
- package/esm2020/lib/iterations-loop/iterations-loop.component.mjs +1 -1
- package/esm2020/lib/simulator/simulator.component.mjs +1202 -63
- package/esm2020/lib/table/dynamic-table/dynamic-table.component.mjs +35 -3
- package/esm2020/lib/templates/table-template.component.mjs +7 -4
- package/fesm2015/cqa-lib-cqa-ui.mjs +1649 -195
- package/fesm2015/cqa-lib-cqa-ui.mjs.map +1 -1
- package/fesm2020/cqa-lib-cqa-ui.mjs +1599 -184
- package/fesm2020/cqa-lib-cqa-ui.mjs.map +1 -1
- package/lib/execution-screen/ai-action-step/ai-action-step.component.d.ts +3 -1
- package/lib/execution-screen/ai-agent-step/ai-agent-step.component.d.ts +3 -1
- package/lib/execution-screen/api-step/api-step.component.d.ts +3 -1
- package/lib/execution-screen/base-step.component.d.ts +1 -0
- package/lib/execution-screen/basic-step/basic-step.component.d.ts +3 -1
- package/lib/execution-screen/condition-step/condition-step.component.d.ts +3 -1
- package/lib/execution-screen/db-query-execution-item/db-query-execution-item.component.d.ts +18 -3
- package/lib/execution-screen/db-verification-step/db-verification-step.component.d.ts +9 -1
- package/lib/execution-screen/document-verification-step/document-verification-step.component.d.ts +4 -1
- package/lib/execution-screen/execution-step.models.d.ts +4 -0
- package/lib/execution-screen/file-download-step/file-download-step.component.d.ts +4 -1
- package/lib/execution-screen/loop-step/loop-step.component.d.ts +3 -1
- package/lib/execution-screen/step-group/step-group.component.d.ts +3 -1
- package/lib/execution-screen/step-renderer/step-renderer.component.d.ts +2 -1
- package/lib/simulator/simulator.component.d.ts +122 -6
- package/lib/table/dynamic-table/dynamic-table.component.d.ts +7 -1
- package/lib/templates/table-template.component.d.ts +6 -1
- package/package.json +1 -1
- package/styles.css +1 -1
|
@@ -33,6 +33,8 @@ export class SimulatorComponent {
|
|
|
33
33
|
this.videoTimeUpdate = new EventEmitter();
|
|
34
34
|
this.videoPlay = new EventEmitter();
|
|
35
35
|
this.videoPause = new EventEmitter();
|
|
36
|
+
this.markerHit = new EventEmitter();
|
|
37
|
+
this.isVideoPlayingChange = new EventEmitter();
|
|
36
38
|
this.progress = 0;
|
|
37
39
|
this.dragging = false;
|
|
38
40
|
this.isPlaying = false;
|
|
@@ -41,6 +43,13 @@ export class SimulatorComponent {
|
|
|
41
43
|
this.currentVideoIndex = 0;
|
|
42
44
|
this.currentSpeed = '1x';
|
|
43
45
|
this.isSpeedControlOpen = false;
|
|
46
|
+
this.detectedVideoDurations = []; // Actual durations detected from video metadata
|
|
47
|
+
this.wasPlayingBeforeDrag = false; // Track if video was playing before drag started
|
|
48
|
+
this.playPromise = null; // Track the current play promise
|
|
49
|
+
this.hitMarkers = new Set(); // Track which markers have been hit (by testStepId)
|
|
50
|
+
// State machine for robust media operations
|
|
51
|
+
this.playerState = 'idle';
|
|
52
|
+
this.operationQueue = Promise.resolve(); // Serialize all media operations
|
|
44
53
|
this.segments = [
|
|
45
54
|
{ label: 'Screenshots', value: 'screenshots', icon: 'photo' },
|
|
46
55
|
{ label: 'Video', value: 'video', icon: 'videocam' },
|
|
@@ -55,6 +64,9 @@ export class SimulatorComponent {
|
|
|
55
64
|
this.dragMouseMoveHandler = null;
|
|
56
65
|
this.dragMouseUpHandler = null;
|
|
57
66
|
this.speedControlClickOutsideHandler = null;
|
|
67
|
+
this.preloadVideoElement = null;
|
|
68
|
+
this.preloadAllVideoElement = null;
|
|
69
|
+
this.targetGlobalTimeDuringSwitch = null;
|
|
58
70
|
this.traceViewerLoading = false;
|
|
59
71
|
this.traceViewerError = false;
|
|
60
72
|
this.isCorrectDeviceFrameAvailable = false;
|
|
@@ -171,9 +183,28 @@ export class SimulatorComponent {
|
|
|
171
183
|
get vplayer() {
|
|
172
184
|
return this._vplayer;
|
|
173
185
|
}
|
|
186
|
+
set timelineBarRef(ref) {
|
|
187
|
+
if (!ref)
|
|
188
|
+
return;
|
|
189
|
+
this._timelineBar = ref;
|
|
190
|
+
}
|
|
191
|
+
get timelineBar() {
|
|
192
|
+
return this._timelineBar;
|
|
193
|
+
}
|
|
194
|
+
set speedControlContainerRef(ref) {
|
|
195
|
+
if (!ref)
|
|
196
|
+
return;
|
|
197
|
+
this._speedControlContainer = ref;
|
|
198
|
+
}
|
|
199
|
+
get speedControlContainer() {
|
|
200
|
+
return this._speedControlContainer;
|
|
201
|
+
}
|
|
174
202
|
get hasDeviceFrame() {
|
|
175
203
|
return !!this.deviceFrameConfig;
|
|
176
204
|
}
|
|
205
|
+
get isPlayerSwitching() {
|
|
206
|
+
return this.playerState === 'switching';
|
|
207
|
+
}
|
|
177
208
|
get effectiveBrowserViewPort() {
|
|
178
209
|
const defaultViewport = { width: 1280, height: 720 };
|
|
179
210
|
if (!this.browserViewPort) {
|
|
@@ -234,12 +265,49 @@ export class SimulatorComponent {
|
|
|
234
265
|
const arr = changes['videoUrls'].currentValue;
|
|
235
266
|
if (arr && arr.length > 0) {
|
|
236
267
|
this.currentVideoIndex = 0;
|
|
268
|
+
this.detectVideoDurations(arr);
|
|
269
|
+
this.schedulePreloadAllSegments(arr);
|
|
237
270
|
}
|
|
238
271
|
}
|
|
239
272
|
if (changes['videoCurrentDuration'] && !changes['videoCurrentDuration'].firstChange) {
|
|
240
273
|
const newDuration = changes['videoCurrentDuration'].currentValue;
|
|
241
|
-
|
|
242
|
-
|
|
274
|
+
// Ignore sentinel value (-1) used to force change detection
|
|
275
|
+
if (newDuration === -1) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (this.isPlaying) {
|
|
279
|
+
this.pauseVideo();
|
|
280
|
+
console.log('[Simulator] ngOnChanges videoCurrentDuration: paused video before seeking');
|
|
281
|
+
}
|
|
282
|
+
if (this.hasMultipleVideos) {
|
|
283
|
+
const targetVideoIndex = this.findVideoIndexForTimestamp(newDuration);
|
|
284
|
+
if (targetVideoIndex !== null) {
|
|
285
|
+
const boundaries = this.getVideoDurationBoundaries();
|
|
286
|
+
const targetBoundary = boundaries[targetVideoIndex];
|
|
287
|
+
const relativeTimestamp = newDuration - targetBoundary.start;
|
|
288
|
+
const needsSwitch = this.currentVideoIndex !== targetVideoIndex;
|
|
289
|
+
if (this.vplayer?.nativeElement) {
|
|
290
|
+
const currentVideoTimeMs = this.vplayer.nativeElement.currentTime * 1000;
|
|
291
|
+
const timeDifference = Math.abs(relativeTimestamp - currentVideoTimeMs);
|
|
292
|
+
if (needsSwitch || newDuration !== this.lastSetDuration || timeDifference > 100) {
|
|
293
|
+
this.switchToVideoAndSeek(newDuration);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
if (needsSwitch) {
|
|
298
|
+
this.currentVideoIndex = targetVideoIndex;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
if (this.vplayer?.nativeElement) {
|
|
305
|
+
const currentVideoTimeMs = this.vplayer.nativeElement.currentTime * 1000;
|
|
306
|
+
const timeDifference = Math.abs(newDuration - currentVideoTimeMs);
|
|
307
|
+
if (newDuration !== this.lastSetDuration || timeDifference > 100) {
|
|
308
|
+
this.seekToTime(newDuration);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
243
311
|
}
|
|
244
312
|
}
|
|
245
313
|
if (changes['traceViewUrl']) {
|
|
@@ -260,46 +328,485 @@ export class SimulatorComponent {
|
|
|
260
328
|
if (this.videoEventListenerCleanup) {
|
|
261
329
|
this.videoEventListenerCleanup();
|
|
262
330
|
}
|
|
331
|
+
if (this.preloadVideoElement) {
|
|
332
|
+
this.preloadVideoElement.src = '';
|
|
333
|
+
this.preloadVideoElement.remove();
|
|
334
|
+
this.preloadVideoElement = null;
|
|
335
|
+
}
|
|
336
|
+
if (this.preloadAllVideoElement) {
|
|
337
|
+
this.preloadAllVideoElement.src = '';
|
|
338
|
+
this.preloadAllVideoElement.remove();
|
|
339
|
+
this.preloadAllVideoElement = null;
|
|
340
|
+
}
|
|
263
341
|
this.removeDragListeners();
|
|
264
342
|
this.removeSpeedControlClickOutsideListener();
|
|
343
|
+
console.log('[Simulator] ngOnDestroy: cleaned up listeners');
|
|
265
344
|
}
|
|
345
|
+
/**
|
|
346
|
+
* Seek video - public method (enqueues operation)
|
|
347
|
+
*/
|
|
266
348
|
seekToTime(milliseconds) {
|
|
267
|
-
if (!this.vplayer?.nativeElement
|
|
349
|
+
if (!this.vplayer?.nativeElement)
|
|
350
|
+
return;
|
|
351
|
+
this.enqueueOperation(() => this.seekToTimeInternal(milliseconds));
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Seek to a global time on the combined timeline (converts to segment + local time)
|
|
355
|
+
*/
|
|
356
|
+
async seekToGlobalTime(globalTimeMs) {
|
|
357
|
+
const total = this.totalDuration;
|
|
358
|
+
if (total <= 0)
|
|
359
|
+
return;
|
|
360
|
+
const clampedGlobal = Math.max(0, Math.min(globalTimeMs, total));
|
|
361
|
+
const boundaries = this.segmentBoundaries;
|
|
362
|
+
let segmentIndex = 0;
|
|
363
|
+
let segmentStart = 0;
|
|
364
|
+
for (let i = 0; i < boundaries.length; i++) {
|
|
365
|
+
if (clampedGlobal < boundaries[i]) {
|
|
366
|
+
segmentIndex = i;
|
|
367
|
+
segmentStart = i === 0 ? 0 : boundaries[i - 1];
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
segmentIndex = i;
|
|
371
|
+
segmentStart = i === 0 ? 0 : boundaries[i - 1];
|
|
372
|
+
}
|
|
373
|
+
if (boundaries.length > 0 && clampedGlobal >= boundaries[boundaries.length - 1]) {
|
|
374
|
+
segmentIndex = boundaries.length - 1;
|
|
375
|
+
segmentStart = segmentIndex === 0 ? 0 : boundaries[segmentIndex - 1];
|
|
376
|
+
}
|
|
377
|
+
const localTimeMs = clampedGlobal - segmentStart;
|
|
378
|
+
if (this.currentVideoIndex === segmentIndex) {
|
|
379
|
+
await this.seekToTimeInternal(localTimeMs);
|
|
380
|
+
// Update progress after seek in same segment
|
|
381
|
+
if (this.totalDuration > 0) {
|
|
382
|
+
this.progress = Math.min(100, Math.max(0, (this.globalCurrentTime / this.totalDuration) * 100));
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
const cumulativeTimestamp = segmentStart + localTimeMs;
|
|
387
|
+
await this.switchToVideoAndSeekInternal(cumulativeTimestamp);
|
|
388
|
+
// Progress is already updated inside switchToVideoAndSeekInternal
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Seek video internal implementation (no enqueue - called from queue)
|
|
393
|
+
* This prevents pipeline read errors during rapid seek operations
|
|
394
|
+
*/
|
|
395
|
+
async seekToTimeInternal(milliseconds) {
|
|
396
|
+
const video = this.vplayer?.nativeElement;
|
|
397
|
+
if (!video || !video.duration)
|
|
268
398
|
return;
|
|
269
399
|
const seconds = milliseconds / 1000;
|
|
270
|
-
const video = this.vplayer.nativeElement;
|
|
271
400
|
const targetTime = Math.max(0, Math.min(seconds, video.duration));
|
|
401
|
+
console.log('[Simulator] seekToTimeInternal: seeking', {
|
|
402
|
+
milliseconds,
|
|
403
|
+
targetTime,
|
|
404
|
+
playerState: this.playerState,
|
|
405
|
+
currentTimeBefore: video.currentTime
|
|
406
|
+
});
|
|
407
|
+
// Set seeking state
|
|
408
|
+
this.playerState = 'seeking';
|
|
409
|
+
// CRITICAL: Pause before seeking to avoid pipeline errors
|
|
410
|
+
video.pause();
|
|
411
|
+
// Update state
|
|
412
|
+
this.isPlaying = false;
|
|
413
|
+
this.playPromise = null;
|
|
414
|
+
this.videoPause.emit();
|
|
415
|
+
this.isVideoPlayingChange.emit(false);
|
|
416
|
+
// Perform seek
|
|
272
417
|
video.currentTime = targetTime;
|
|
273
418
|
this.lastSetDuration = milliseconds;
|
|
274
|
-
|
|
275
|
-
|
|
419
|
+
// Wait briefly for seek to complete (prevents rapid seek issues)
|
|
420
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
421
|
+
const total = this.totalDuration;
|
|
422
|
+
if (total > 0) {
|
|
423
|
+
this.progress = Math.min(100, Math.max(0, (this.globalCurrentTime / total) * 100));
|
|
276
424
|
}
|
|
425
|
+
this.videoTimeUpdate.emit(this.globalCurrentTime);
|
|
426
|
+
// Set to paused state (user must explicitly play)
|
|
427
|
+
this.playerState = 'paused';
|
|
428
|
+
console.log('[Simulator] seekToTimeInternal: seek complete', {
|
|
429
|
+
currentTimeAfter: video.currentTime,
|
|
430
|
+
playerState: this.playerState
|
|
431
|
+
});
|
|
277
432
|
}
|
|
433
|
+
/**
|
|
434
|
+
* Toggle play/pause (now trivial with state machine)
|
|
435
|
+
*/
|
|
278
436
|
togglePlay() {
|
|
279
437
|
const video = this.vplayer?.nativeElement;
|
|
280
|
-
if (!video)
|
|
438
|
+
if (!video) {
|
|
439
|
+
console.error('[Simulator] togglePlay: video element not found', {
|
|
440
|
+
playerState: this.playerState,
|
|
441
|
+
isFullScreen: this.isFullScreen
|
|
442
|
+
});
|
|
281
443
|
return;
|
|
282
|
-
|
|
444
|
+
}
|
|
445
|
+
// Check for valid source
|
|
283
446
|
if (!this.currentVideoUrl || video.networkState === HTMLMediaElement.NETWORK_NO_SOURCE || video.error) {
|
|
447
|
+
console.error('[Simulator] togglePlay: no valid source', {
|
|
448
|
+
currentVideoUrl: this.currentVideoUrl,
|
|
449
|
+
networkState: video.networkState,
|
|
450
|
+
error: video.error
|
|
451
|
+
});
|
|
284
452
|
return;
|
|
285
453
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
this.
|
|
289
|
-
|
|
454
|
+
// Recover from stuck 'loading' state when video is actually ready (e.g. after jump-to-segment)
|
|
455
|
+
if (this.playerState === 'loading' && video.readyState >= HTMLMediaElement.HAVE_METADATA) {
|
|
456
|
+
this.playerState = 'paused';
|
|
457
|
+
}
|
|
458
|
+
// Don't allow play during error state
|
|
459
|
+
if (this.playerState === 'error') {
|
|
460
|
+
console.warn('[Simulator] togglePlay: player in error state', { readyState: video.readyState });
|
|
461
|
+
this.playerState = 'idle';
|
|
462
|
+
}
|
|
463
|
+
// If still loading and video not ready, wait and retry
|
|
464
|
+
if (this.playerState === 'loading') {
|
|
465
|
+
console.warn('[Simulator] togglePlay: player not ready', {
|
|
466
|
+
playerState: this.playerState,
|
|
467
|
+
readyState: video.readyState
|
|
468
|
+
});
|
|
469
|
+
setTimeout(() => {
|
|
470
|
+
if (video.readyState >= HTMLMediaElement.HAVE_METADATA && this.playerState !== 'playing') {
|
|
471
|
+
this.togglePlay();
|
|
472
|
+
}
|
|
473
|
+
}, 50);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
console.log('[Simulator] togglePlay:', {
|
|
477
|
+
playerState: this.playerState,
|
|
478
|
+
isPlaying: this.isPlaying,
|
|
479
|
+
readyState: video.readyState
|
|
480
|
+
});
|
|
481
|
+
// Simple toggle based on state
|
|
482
|
+
if (this.playerState === 'playing') {
|
|
483
|
+
this.pauseVideo();
|
|
290
484
|
}
|
|
291
485
|
else {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
486
|
+
this.playVideo();
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Play video - public method (enqueues operation)
|
|
491
|
+
*/
|
|
492
|
+
playVideo() {
|
|
493
|
+
this.enqueueOperation(() => this.playVideoInternal());
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Play video internal implementation (no enqueue - called from queue)
|
|
497
|
+
* This eliminates FFmpegDemuxer errors and play promise interruptions
|
|
498
|
+
*/
|
|
499
|
+
async playVideoInternal() {
|
|
500
|
+
const video = this.vplayer?.nativeElement;
|
|
501
|
+
if (!video) {
|
|
502
|
+
console.error('[Simulator] playVideoInternal: video element not found');
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
// Already playing - skip
|
|
506
|
+
if (this.playerState === 'playing') {
|
|
507
|
+
console.log('[Simulator] playVideoInternal: already playing, skipping');
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
if (this.hasMultipleVideos && this.videoUrls) {
|
|
511
|
+
const total = this.totalDuration;
|
|
512
|
+
const currentGlobalTime = this.globalCurrentTime;
|
|
513
|
+
const isAtEnd = total > 0 && (this.progress >= 100 || currentGlobalTime >= total);
|
|
514
|
+
const isLastVideo = this.currentVideoIndex >= this.videoUrls.length - 1;
|
|
515
|
+
const isLastVideoAtEnd = isLastVideo && video.duration && video.currentTime >= video.duration - 0.1;
|
|
516
|
+
if (isAtEnd || isLastVideoAtEnd) {
|
|
517
|
+
console.log('[Simulator] playVideoInternal: all videos completed, resetting to first video', {
|
|
518
|
+
progress: this.progress,
|
|
519
|
+
currentGlobalTime,
|
|
520
|
+
total,
|
|
521
|
+
currentVideoIndex: this.currentVideoIndex,
|
|
522
|
+
isAtEnd,
|
|
523
|
+
isLastVideoAtEnd
|
|
524
|
+
});
|
|
525
|
+
// Reset to first video at 0 progress
|
|
526
|
+
this.currentVideoIndex = 0;
|
|
527
|
+
this.progress = 0;
|
|
528
|
+
this.targetGlobalTimeDuringSwitch = 0;
|
|
529
|
+
this.hitMarkers.clear();
|
|
530
|
+
// Switch to first video and seek to 0
|
|
531
|
+
await this.switchToVideoAndSeekInternal(0);
|
|
532
|
+
// Update video reference after switch
|
|
533
|
+
const videoAfterSwitch = this.vplayer?.nativeElement;
|
|
534
|
+
if (!videoAfterSwitch) {
|
|
535
|
+
console.error('[Simulator] playVideoInternal: video element not found after switch');
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
// Continue with normal play logic below
|
|
539
|
+
// The video element reference has changed, so we'll use videoAfterSwitch
|
|
540
|
+
// But we need to wait for metadata again
|
|
541
|
+
if (videoAfterSwitch.readyState < HTMLMediaElement.HAVE_METADATA) {
|
|
542
|
+
await new Promise((resolve, reject) => {
|
|
543
|
+
const onLoadedMetadata = () => {
|
|
544
|
+
videoAfterSwitch.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
545
|
+
videoAfterSwitch.removeEventListener('error', onError);
|
|
546
|
+
resolve();
|
|
547
|
+
};
|
|
548
|
+
const onError = () => {
|
|
549
|
+
videoAfterSwitch.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
550
|
+
videoAfterSwitch.removeEventListener('error', onError);
|
|
551
|
+
reject(new Error('Failed to load video metadata'));
|
|
552
|
+
};
|
|
553
|
+
videoAfterSwitch.addEventListener('loadedmetadata', onLoadedMetadata, { once: true });
|
|
554
|
+
videoAfterSwitch.addEventListener('error', onError, { once: true });
|
|
555
|
+
setTimeout(() => {
|
|
556
|
+
videoAfterSwitch.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
557
|
+
videoAfterSwitch.removeEventListener('error', onError);
|
|
558
|
+
if (videoAfterSwitch.readyState >= HTMLMediaElement.HAVE_METADATA) {
|
|
559
|
+
resolve();
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
reject(new Error('Timeout waiting for metadata'));
|
|
563
|
+
}
|
|
564
|
+
}, 500);
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
// Set state to loading
|
|
568
|
+
this.playerState = 'loading';
|
|
569
|
+
try {
|
|
570
|
+
await videoAfterSwitch.play();
|
|
571
|
+
this.playerState = 'playing';
|
|
572
|
+
this.isPlaying = true;
|
|
573
|
+
this.playPromise = null;
|
|
574
|
+
this.videoPlay.emit();
|
|
575
|
+
this.isVideoPlayingChange.emit(true);
|
|
576
|
+
this.targetGlobalTimeDuringSwitch = null;
|
|
577
|
+
console.log('[Simulator] playVideoInternal: restarted from first video');
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
catch (err) {
|
|
581
|
+
this.playerState = 'error';
|
|
582
|
+
this.isPlaying = false;
|
|
583
|
+
this.playPromise = null;
|
|
584
|
+
this.isVideoPlayingChange.emit(false);
|
|
585
|
+
if (err.name === 'AbortError') {
|
|
586
|
+
this.playerState = 'paused';
|
|
587
|
+
}
|
|
588
|
+
else {
|
|
589
|
+
console.error('[Simulator] playVideoInternal: failed after reset', err);
|
|
590
|
+
}
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
console.log('[Simulator] playVideoInternal: starting', {
|
|
596
|
+
playerState: this.playerState,
|
|
597
|
+
currentTime: video.currentTime,
|
|
598
|
+
readyState: video.readyState
|
|
599
|
+
});
|
|
600
|
+
// Wait for video to be ready if needed
|
|
601
|
+
if (video.readyState < HTMLMediaElement.HAVE_METADATA) {
|
|
602
|
+
console.log('[Simulator] playVideoInternal: waiting for metadata');
|
|
603
|
+
await new Promise((resolve, reject) => {
|
|
604
|
+
const onLoadedMetadata = () => {
|
|
605
|
+
video.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
606
|
+
video.removeEventListener('error', onError);
|
|
607
|
+
resolve();
|
|
608
|
+
};
|
|
609
|
+
const onError = () => {
|
|
610
|
+
video.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
611
|
+
video.removeEventListener('error', onError);
|
|
612
|
+
reject(new Error('Failed to load video metadata'));
|
|
613
|
+
};
|
|
614
|
+
video.addEventListener('loadedmetadata', onLoadedMetadata, { once: true });
|
|
615
|
+
video.addEventListener('error', onError, { once: true });
|
|
616
|
+
// Timeout fallback
|
|
617
|
+
setTimeout(() => {
|
|
618
|
+
video.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
619
|
+
video.removeEventListener('error', onError);
|
|
620
|
+
if (video.readyState >= HTMLMediaElement.HAVE_METADATA) {
|
|
621
|
+
resolve();
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
reject(new Error('Timeout waiting for metadata'));
|
|
625
|
+
}
|
|
626
|
+
}, 500);
|
|
297
627
|
});
|
|
298
628
|
}
|
|
629
|
+
// Clear hit markers if starting from beginning
|
|
630
|
+
const currentTimeMs = video.currentTime * 1000;
|
|
631
|
+
if (currentTimeMs < 100) {
|
|
632
|
+
this.hitMarkers.clear();
|
|
633
|
+
}
|
|
634
|
+
// Set state to loading
|
|
635
|
+
this.playerState = 'loading';
|
|
636
|
+
try {
|
|
637
|
+
// Verify video element is still available before playing
|
|
638
|
+
const currentVideo = this.vplayer?.nativeElement;
|
|
639
|
+
if (!currentVideo || currentVideo !== video) {
|
|
640
|
+
console.warn('[Simulator] playVideoInternal: video element changed or unavailable');
|
|
641
|
+
this.playerState = 'paused';
|
|
642
|
+
this.isPlaying = false;
|
|
643
|
+
this.playPromise = null;
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
// Await play promise - this is critical
|
|
647
|
+
await video.play();
|
|
648
|
+
// Verify video element is still available after play promise resolves
|
|
649
|
+
const videoAfterPlay = this.vplayer?.nativeElement;
|
|
650
|
+
if (!videoAfterPlay || videoAfterPlay !== video) {
|
|
651
|
+
console.warn('[Simulator] playVideoInternal: video element changed during play');
|
|
652
|
+
this.playerState = 'paused';
|
|
653
|
+
this.isPlaying = false;
|
|
654
|
+
this.playPromise = null;
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
// Play succeeded
|
|
658
|
+
this.playerState = 'playing';
|
|
659
|
+
this.isPlaying = true;
|
|
660
|
+
this.playPromise = null;
|
|
661
|
+
this.videoPlay.emit();
|
|
662
|
+
this.isVideoPlayingChange.emit(true);
|
|
663
|
+
console.log('[Simulator] playVideoInternal: playing successfully', {
|
|
664
|
+
currentTime: video.currentTime,
|
|
665
|
+
playerState: this.playerState
|
|
666
|
+
});
|
|
667
|
+
// Check early markers (non-blocking, doesn't need to be queued)
|
|
668
|
+
setTimeout(() => {
|
|
669
|
+
if (this.isPlaying) {
|
|
670
|
+
this.checkMarkerHit(this.globalCurrentTime);
|
|
671
|
+
}
|
|
672
|
+
}, 50);
|
|
673
|
+
}
|
|
674
|
+
catch (err) {
|
|
675
|
+
// Play failed
|
|
676
|
+
// Check if video element is still available
|
|
677
|
+
const videoAfterError = this.vplayer?.nativeElement;
|
|
678
|
+
if (!videoAfterError || videoAfterError !== video) {
|
|
679
|
+
console.warn('[Simulator] playVideoInternal: video element changed during error');
|
|
680
|
+
this.playerState = 'paused';
|
|
681
|
+
}
|
|
682
|
+
else {
|
|
683
|
+
this.playerState = 'error';
|
|
684
|
+
}
|
|
685
|
+
this.isPlaying = false;
|
|
686
|
+
this.playPromise = null;
|
|
687
|
+
this.isVideoPlayingChange.emit(false);
|
|
688
|
+
if (err.name === 'AbortError') {
|
|
689
|
+
console.log('[Simulator] playVideoInternal: aborted (expected during pause)');
|
|
690
|
+
// AbortError is expected, reset to paused state instead of error
|
|
691
|
+
if (videoAfterError && videoAfterError === video) {
|
|
692
|
+
this.playerState = 'paused';
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
else {
|
|
696
|
+
console.error('[Simulator] playVideoInternal: failed', err);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Pause video - public method (enqueues operation)
|
|
702
|
+
*/
|
|
703
|
+
pauseVideo() {
|
|
704
|
+
this.enqueueOperation(() => this.pauseVideoInternal());
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Pause video internal implementation (no enqueue - called from queue)
|
|
708
|
+
*/
|
|
709
|
+
async pauseVideoInternal() {
|
|
710
|
+
const video = this.vplayer?.nativeElement;
|
|
711
|
+
if (!video)
|
|
712
|
+
return;
|
|
713
|
+
// Already paused - skip
|
|
714
|
+
if (this.playerState === 'paused') {
|
|
715
|
+
console.log('[Simulator] pauseVideoInternal: already paused, skipping');
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
console.log('[Simulator] pauseVideoInternal: pausing', {
|
|
719
|
+
playerState: this.playerState,
|
|
720
|
+
currentTime: video.currentTime
|
|
721
|
+
});
|
|
722
|
+
video.pause();
|
|
723
|
+
this.playerState = 'paused';
|
|
724
|
+
this.isPlaying = false;
|
|
725
|
+
this.playPromise = null;
|
|
726
|
+
this.videoPause.emit();
|
|
727
|
+
this.isVideoPlayingChange.emit(false);
|
|
728
|
+
console.log('[Simulator] pauseVideoInternal: paused successfully');
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Enqueue media operation to prevent race conditions
|
|
732
|
+
* This is the CRITICAL fix for FFmpegDemuxer errors and play promise interruptions
|
|
733
|
+
* All media operations (play, pause, seek, switch) go through this queue
|
|
734
|
+
*/
|
|
735
|
+
enqueueOperation(operation) {
|
|
736
|
+
this.operationQueue = this.operationQueue
|
|
737
|
+
.then(() => operation())
|
|
738
|
+
.catch(err => {
|
|
739
|
+
console.error('[Simulator] Media operation failed:', err);
|
|
740
|
+
this.playerState = 'error';
|
|
741
|
+
});
|
|
299
742
|
}
|
|
300
743
|
get hasMultipleVideos() {
|
|
301
744
|
return Array.isArray(this.videoUrls) && this.videoUrls.length > 1;
|
|
302
745
|
}
|
|
746
|
+
/** Cumulative duration boundaries [ms]. segmentBoundaries[i] = sum of durations [0..i] */
|
|
747
|
+
get segmentBoundaries() {
|
|
748
|
+
const durations = this.videoDurations;
|
|
749
|
+
if (durations.length === 0)
|
|
750
|
+
return [];
|
|
751
|
+
const boundaries = [];
|
|
752
|
+
let sum = 0;
|
|
753
|
+
for (const d of durations) {
|
|
754
|
+
sum += d;
|
|
755
|
+
boundaries.push(sum);
|
|
756
|
+
}
|
|
757
|
+
return boundaries;
|
|
758
|
+
}
|
|
759
|
+
/** Total duration across all segments in ms */
|
|
760
|
+
get totalDuration() {
|
|
761
|
+
const durations = this.videoDurations;
|
|
762
|
+
if (durations.length === 0)
|
|
763
|
+
return 0;
|
|
764
|
+
return durations.reduce((a, b) => a + b, 0);
|
|
765
|
+
}
|
|
766
|
+
/** Video durations in ms (detected or from single video element) */
|
|
767
|
+
get videoDurations() {
|
|
768
|
+
if (this.hasMultipleVideos && this.detectedVideoDurations.length > 0) {
|
|
769
|
+
return this.detectedVideoDurations;
|
|
770
|
+
}
|
|
771
|
+
const video = this.vplayer?.nativeElement;
|
|
772
|
+
if (video?.duration && isFinite(video.duration)) {
|
|
773
|
+
return [video.duration * 1000];
|
|
774
|
+
}
|
|
775
|
+
return [];
|
|
776
|
+
}
|
|
777
|
+
get globalCurrentTime() {
|
|
778
|
+
if (this.targetGlobalTimeDuringSwitch !== null && !this.isPlaying && this.playerState !== 'playing') {
|
|
779
|
+
return this.targetGlobalTimeDuringSwitch;
|
|
780
|
+
}
|
|
781
|
+
const video = this.vplayer?.nativeElement;
|
|
782
|
+
if (!video?.duration || !isFinite(video.duration)) {
|
|
783
|
+
// Fallback to override if video not ready yet
|
|
784
|
+
if (this.targetGlobalTimeDuringSwitch !== null) {
|
|
785
|
+
return this.targetGlobalTimeDuringSwitch;
|
|
786
|
+
}
|
|
787
|
+
return 0;
|
|
788
|
+
}
|
|
789
|
+
const segmentStart = this.currentVideoIndex === 0 ? 0 : (this.segmentBoundaries[this.currentVideoIndex - 1] ?? 0);
|
|
790
|
+
return segmentStart + video.currentTime * 1000;
|
|
791
|
+
}
|
|
792
|
+
getActualGlobalTime() {
|
|
793
|
+
const video = this.vplayer?.nativeElement;
|
|
794
|
+
if (!video?.duration || !isFinite(video.duration))
|
|
795
|
+
return 0;
|
|
796
|
+
const segmentStart = this.currentVideoIndex === 0 ? 0 : (this.segmentBoundaries[this.currentVideoIndex - 1] ?? 0);
|
|
797
|
+
return segmentStart + video.currentTime * 1000;
|
|
798
|
+
}
|
|
799
|
+
/** Global step markers for rendering on the combined timeline */
|
|
800
|
+
get globalStepMarkers() {
|
|
801
|
+
const allMarkers = this.flattenMarkers(this.stepMarkers);
|
|
802
|
+
return allMarkers.map(m => ({
|
|
803
|
+
globalTime: m.cumulativeDuration,
|
|
804
|
+
result: m.result,
|
|
805
|
+
testStepId: m.testStepId,
|
|
806
|
+
title: m.title,
|
|
807
|
+
level: m.level
|
|
808
|
+
}));
|
|
809
|
+
}
|
|
303
810
|
get currentVideoUrl() {
|
|
304
811
|
if (Array.isArray(this.videoUrls) && this.videoUrls.length > 0) {
|
|
305
812
|
const idx = Math.min(Math.max(this.currentVideoIndex, 0), this.videoUrls.length - 1);
|
|
@@ -307,14 +814,30 @@ export class SimulatorComponent {
|
|
|
307
814
|
}
|
|
308
815
|
return this.videoUrl;
|
|
309
816
|
}
|
|
817
|
+
/**
|
|
818
|
+
* Reset video state - public method (enqueues operation)
|
|
819
|
+
*/
|
|
310
820
|
resetVideoState() {
|
|
821
|
+
this.enqueueOperation(() => this.resetVideoStateInternal());
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Reset video state internal implementation (no enqueue - called from queue)
|
|
825
|
+
*/
|
|
826
|
+
async resetVideoStateInternal() {
|
|
827
|
+
const video = this.vplayer?.nativeElement;
|
|
828
|
+
if (!video)
|
|
829
|
+
return;
|
|
830
|
+
console.log('[Simulator] resetVideoStateInternal: resetting');
|
|
831
|
+
video.pause();
|
|
832
|
+
video.currentTime = 0;
|
|
833
|
+
this.playerState = 'paused';
|
|
311
834
|
this.isPlaying = false;
|
|
312
835
|
this.progress = 0;
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
this.vplayer.nativeElement.currentTime = 0;
|
|
316
|
-
}
|
|
836
|
+
this.playPromise = null;
|
|
837
|
+
this.hitMarkers.clear();
|
|
317
838
|
this.lastSetDuration = -1;
|
|
839
|
+
this.isVideoPlayingChange.emit(false);
|
|
840
|
+
console.log('[Simulator] resetVideoStateInternal: complete');
|
|
318
841
|
}
|
|
319
842
|
prevVideo() {
|
|
320
843
|
if (!this.hasMultipleVideos)
|
|
@@ -333,22 +856,45 @@ export class SimulatorComponent {
|
|
|
333
856
|
}
|
|
334
857
|
}
|
|
335
858
|
onTimelineClick(event) {
|
|
336
|
-
if (!this.timelineBar?.nativeElement
|
|
859
|
+
if (!this.timelineBar?.nativeElement)
|
|
337
860
|
return;
|
|
338
861
|
const rect = this.timelineBar.nativeElement.getBoundingClientRect();
|
|
339
862
|
const clickX = event.clientX - rect.left;
|
|
340
863
|
const percent = Math.max(0, Math.min(1, clickX / rect.width));
|
|
341
|
-
const
|
|
342
|
-
if (
|
|
864
|
+
const total = this.totalDuration;
|
|
865
|
+
if (total <= 0)
|
|
343
866
|
return;
|
|
344
|
-
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
|
|
867
|
+
const globalTimeMs = percent * total;
|
|
868
|
+
const shouldResumePlaying = this.isPlaying;
|
|
869
|
+
console.log('[Simulator] onTimelineClick', {
|
|
870
|
+
percent,
|
|
871
|
+
globalTimeMs,
|
|
872
|
+
shouldResumePlaying
|
|
873
|
+
});
|
|
874
|
+
this.enqueueOperation(async () => {
|
|
875
|
+
await this.seekToGlobalTime(globalTimeMs);
|
|
876
|
+
if (shouldResumePlaying) {
|
|
877
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
878
|
+
await this.playVideoInternal();
|
|
879
|
+
}
|
|
880
|
+
});
|
|
348
881
|
}
|
|
349
882
|
startDrag(event) {
|
|
350
883
|
event.preventDefault();
|
|
351
884
|
this.dragging = true;
|
|
885
|
+
// CRITICAL: Capture playing state BEFORE pausing
|
|
886
|
+
// Use both isPlaying flag and playerState for reliability
|
|
887
|
+
this.wasPlayingBeforeDrag = this.isPlaying || this.playerState === 'playing';
|
|
888
|
+
console.log('[Simulator] startDrag', {
|
|
889
|
+
clientX: event.clientX,
|
|
890
|
+
playerState: this.playerState,
|
|
891
|
+
isPlaying: this.isPlaying,
|
|
892
|
+
wasPlayingBeforeDrag: this.wasPlayingBeforeDrag
|
|
893
|
+
});
|
|
894
|
+
// Pause video during drag to avoid conflicts
|
|
895
|
+
if (this.isPlaying || this.playerState === 'playing') {
|
|
896
|
+
this.pauseVideo();
|
|
897
|
+
}
|
|
352
898
|
this.addDragListeners();
|
|
353
899
|
}
|
|
354
900
|
onDrag(event) {
|
|
@@ -357,22 +903,64 @@ export class SimulatorComponent {
|
|
|
357
903
|
const rect = this.timelineBar.nativeElement.getBoundingClientRect();
|
|
358
904
|
const x = event.clientX - rect.left;
|
|
359
905
|
const percent = Math.max(0, Math.min(x / rect.width, 1));
|
|
360
|
-
this.progress = percent * 100;
|
|
906
|
+
this.progress = percent * 100; // Global timeline position
|
|
361
907
|
}
|
|
362
908
|
stopDrag() {
|
|
363
909
|
if (!this.dragging)
|
|
364
910
|
return;
|
|
365
911
|
this.dragging = false;
|
|
366
912
|
this.removeDragListeners();
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
913
|
+
// CRITICAL: Capture the playing state BEFORE any async operations
|
|
914
|
+
const shouldResumePlaying = this.wasPlayingBeforeDrag;
|
|
915
|
+
console.log('[Simulator] stopDrag: drag ended', {
|
|
916
|
+
progress: this.progress,
|
|
917
|
+
wasPlayingBeforeDrag: this.wasPlayingBeforeDrag,
|
|
918
|
+
shouldResumePlaying: shouldResumePlaying,
|
|
919
|
+
currentPlayerState: this.playerState
|
|
920
|
+
});
|
|
921
|
+
const total = this.totalDuration;
|
|
922
|
+
if (total <= 0)
|
|
923
|
+
return;
|
|
924
|
+
const globalTimeMs = (this.progress / 100) * total;
|
|
925
|
+
// CRITICAL FIX: Queue both seek and resume play together
|
|
926
|
+
// This ensures seek completes before attempting to play
|
|
927
|
+
this.enqueueOperation(async () => {
|
|
928
|
+
// Perform seek (this will pause the video)
|
|
929
|
+
await this.seekToGlobalTime(globalTimeMs);
|
|
930
|
+
// If video was playing before drag, resume it
|
|
931
|
+
if (shouldResumePlaying) {
|
|
932
|
+
console.log('[Simulator] stopDrag: resuming playback after seek', {
|
|
933
|
+
globalTimeMs,
|
|
934
|
+
playerState: this.playerState
|
|
935
|
+
});
|
|
936
|
+
// Wait a bit longer to ensure seek is fully complete
|
|
937
|
+
await new Promise(resolve => setTimeout(resolve, 150));
|
|
938
|
+
// Verify state is 'paused' after seek (seekToTimeInternal sets it to 'paused')
|
|
939
|
+
// If state is still 'seeking', wait a bit more
|
|
940
|
+
if (this.playerState === 'seeking') {
|
|
941
|
+
console.log('[Simulator] stopDrag: seek still in progress, waiting more');
|
|
942
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
943
|
+
}
|
|
944
|
+
// Now resume playback (state should be 'paused' at this point)
|
|
945
|
+
if (this.playerState === 'paused') {
|
|
946
|
+
await this.playVideoInternal();
|
|
947
|
+
console.log('[Simulator] stopDrag: playback resumed successfully', {
|
|
948
|
+
playerState: this.playerState,
|
|
949
|
+
isPlaying: this.isPlaying
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
else {
|
|
953
|
+
console.warn('[Simulator] stopDrag: unexpected state after seek, attempting to resume anyway', {
|
|
954
|
+
playerState: this.playerState
|
|
955
|
+
});
|
|
956
|
+
// Try to resume anyway - better to try than to leave it stuck
|
|
957
|
+
await this.playVideoInternal();
|
|
958
|
+
}
|
|
371
959
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
}
|
|
960
|
+
else {
|
|
961
|
+
console.log('[Simulator] stopDrag: video was paused, not resuming');
|
|
962
|
+
}
|
|
963
|
+
});
|
|
376
964
|
}
|
|
377
965
|
addDragListeners() {
|
|
378
966
|
this.removeDragListeners();
|
|
@@ -396,14 +984,33 @@ export class SimulatorComponent {
|
|
|
396
984
|
}
|
|
397
985
|
}
|
|
398
986
|
onVideoMetadataLoaded() {
|
|
987
|
+
console.log('[Simulator] onVideoMetadataLoaded');
|
|
988
|
+
// Ensure playback speed is consistent across all videos
|
|
989
|
+
this.applyCurrentPlaybackRate();
|
|
399
990
|
this.attachVideoListeners();
|
|
400
991
|
}
|
|
401
992
|
onVideoCanPlay() {
|
|
993
|
+
console.log('[Simulator] onVideoCanPlay');
|
|
994
|
+
// Ensure playback speed is consistent across all videos
|
|
995
|
+
this.applyCurrentPlaybackRate();
|
|
402
996
|
this.attachVideoListeners();
|
|
403
997
|
}
|
|
404
998
|
onVideoEnded() {
|
|
405
999
|
this.isPlaying = false;
|
|
1000
|
+
this.playerState = 'paused';
|
|
406
1001
|
this.videoPause.emit();
|
|
1002
|
+
this.isVideoPlayingChange.emit(false);
|
|
1003
|
+
// Seamlessly load and play next segment
|
|
1004
|
+
if (this.hasMultipleVideos && this.videoUrls && this.currentVideoIndex < this.videoUrls.length - 1) {
|
|
1005
|
+
const nextIndex = this.currentVideoIndex + 1;
|
|
1006
|
+
const segmentStart = nextIndex === 0 ? 0 : (this.segmentBoundaries[nextIndex - 1] ?? 0);
|
|
1007
|
+
this.enqueueOperation(async () => {
|
|
1008
|
+
await this.switchToVideoAndSeekInternal(segmentStart);
|
|
1009
|
+
if (this.vplayer?.nativeElement && this.currentVideoUrl) {
|
|
1010
|
+
await this.playVideoInternal();
|
|
1011
|
+
}
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
407
1014
|
}
|
|
408
1015
|
attachVideoListeners() {
|
|
409
1016
|
if (this.videoEventListenerCleanup) {
|
|
@@ -421,10 +1028,26 @@ export class SimulatorComponent {
|
|
|
421
1028
|
return;
|
|
422
1029
|
lastUpdate = now;
|
|
423
1030
|
const currentMs = video.currentTime * 1000;
|
|
424
|
-
if (!this.dragging) {
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
|
|
1031
|
+
if (!this.dragging && this.playerState !== 'switching') {
|
|
1032
|
+
const total = this.totalDuration;
|
|
1033
|
+
// Clear targetGlobalTimeDuringSwitch if we've reached the target position
|
|
1034
|
+
// When playing, be more aggressive about clearing to allow live updates
|
|
1035
|
+
if (this.targetGlobalTimeDuringSwitch !== null) {
|
|
1036
|
+
const currentGlobal = this.getActualGlobalTime();
|
|
1037
|
+
const tolerance = this.isPlaying ? 1000 : 500; // More tolerance when playing
|
|
1038
|
+
if (Math.abs(currentGlobal - this.targetGlobalTimeDuringSwitch) < tolerance) {
|
|
1039
|
+
this.targetGlobalTimeDuringSwitch = null;
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
// globalCurrentTime now handles override logic - use it directly
|
|
1043
|
+
if (total > 0) {
|
|
1044
|
+
this.progress = Math.min(100, Math.max(0, (this.globalCurrentTime / total) * 100));
|
|
1045
|
+
}
|
|
1046
|
+
this.videoTimeUpdate.emit(this.globalCurrentTime);
|
|
1047
|
+
// Check if current time hits any marker
|
|
1048
|
+
this.checkMarkerHit(this.globalCurrentTime);
|
|
1049
|
+
// Preload next segment when ~5-10 seconds from ending
|
|
1050
|
+
this.maybePreloadNextSegment();
|
|
428
1051
|
}
|
|
429
1052
|
};
|
|
430
1053
|
video.addEventListener('timeupdate', handler);
|
|
@@ -433,28 +1056,323 @@ export class SimulatorComponent {
|
|
|
433
1056
|
};
|
|
434
1057
|
}, 100);
|
|
435
1058
|
}
|
|
436
|
-
|
|
437
|
-
if (!
|
|
438
|
-
return
|
|
439
|
-
|
|
1059
|
+
schedulePreloadAllSegments(videoUrls) {
|
|
1060
|
+
if (!videoUrls || videoUrls.length === 0)
|
|
1061
|
+
return;
|
|
1062
|
+
this.cancelPreloadAllSegments();
|
|
1063
|
+
setTimeout(() => this.preloadAllSegments(videoUrls), 500);
|
|
1064
|
+
}
|
|
1065
|
+
cancelPreloadAllSegments() {
|
|
1066
|
+
if (this.preloadAllVideoElement) {
|
|
1067
|
+
this.preloadAllVideoElement.src = '';
|
|
1068
|
+
this.preloadAllVideoElement.remove();
|
|
1069
|
+
this.preloadAllVideoElement = null;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* Preload all video URLs in sequence (first, then second, ...) so they are cached.
|
|
1074
|
+
* When user jumps to any segment, that video is likely already loaded.
|
|
1075
|
+
*/
|
|
1076
|
+
preloadAllSegments(videoUrls) {
|
|
1077
|
+
if (!videoUrls || videoUrls.length === 0)
|
|
1078
|
+
return;
|
|
1079
|
+
this.cancelPreloadAllSegments();
|
|
1080
|
+
const video = document.createElement('video');
|
|
1081
|
+
video.preload = 'auto';
|
|
1082
|
+
video.muted = true;
|
|
1083
|
+
video.playsInline = true;
|
|
1084
|
+
video.style.display = 'none';
|
|
1085
|
+
document.body.appendChild(video);
|
|
1086
|
+
this.preloadAllVideoElement = video;
|
|
1087
|
+
let index = 0;
|
|
1088
|
+
const loadNext = () => {
|
|
1089
|
+
if (this.preloadAllVideoElement !== video || index >= videoUrls.length) {
|
|
1090
|
+
video.remove();
|
|
1091
|
+
if (this.preloadAllVideoElement === video)
|
|
1092
|
+
this.preloadAllVideoElement = null;
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1095
|
+
const url = videoUrls[index];
|
|
1096
|
+
video.src = url;
|
|
1097
|
+
index += 1;
|
|
1098
|
+
const onDone = () => {
|
|
1099
|
+
clearTimeout(timeoutId);
|
|
1100
|
+
video.removeEventListener('loadeddata', onDone);
|
|
1101
|
+
video.removeEventListener('error', onDone);
|
|
1102
|
+
loadNext();
|
|
1103
|
+
};
|
|
1104
|
+
video.addEventListener('loadeddata', onDone, { once: true });
|
|
1105
|
+
video.addEventListener('error', onDone, { once: true });
|
|
1106
|
+
const timeoutId = setTimeout(() => onDone(), 15000);
|
|
1107
|
+
};
|
|
1108
|
+
loadNext();
|
|
1109
|
+
}
|
|
1110
|
+
/** Preload next segment when ~5-10 seconds from ending to minimize switching delay */
|
|
1111
|
+
maybePreloadNextSegment() {
|
|
1112
|
+
if (!this.hasMultipleVideos || !this.videoUrls || this.currentVideoIndex >= this.videoUrls.length - 1) {
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
const video = this.vplayer?.nativeElement;
|
|
1116
|
+
if (!video?.duration)
|
|
1117
|
+
return;
|
|
1118
|
+
const timeLeftInSegment = (video.duration - video.currentTime) * 1000; // ms
|
|
1119
|
+
if (timeLeftInSegment > 10000 || timeLeftInSegment < 5000)
|
|
1120
|
+
return; // Preload when 5-10s from end
|
|
1121
|
+
const nextUrl = this.videoUrls[this.currentVideoIndex + 1];
|
|
1122
|
+
if (!nextUrl)
|
|
1123
|
+
return;
|
|
1124
|
+
if (this.preloadVideoElement?.src === nextUrl)
|
|
1125
|
+
return; // Already preloading
|
|
1126
|
+
this.preloadNextSegment(nextUrl);
|
|
1127
|
+
}
|
|
1128
|
+
preloadNextSegment(url) {
|
|
1129
|
+
if (this.preloadVideoElement) {
|
|
1130
|
+
this.preloadVideoElement.src = '';
|
|
1131
|
+
this.preloadVideoElement.remove();
|
|
1132
|
+
this.preloadVideoElement = null;
|
|
1133
|
+
}
|
|
1134
|
+
const video = document.createElement('video');
|
|
1135
|
+
video.preload = 'auto';
|
|
1136
|
+
video.src = url;
|
|
1137
|
+
video.style.display = 'none';
|
|
1138
|
+
document.body.appendChild(video);
|
|
1139
|
+
this.preloadVideoElement = video;
|
|
1140
|
+
video.addEventListener('loadeddata', () => {
|
|
1141
|
+
video.remove();
|
|
1142
|
+
if (this.preloadVideoElement === video)
|
|
1143
|
+
this.preloadVideoElement = null;
|
|
1144
|
+
}, { once: true });
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Detect actual video durations by loading video metadata
|
|
1148
|
+
* This creates temporary video elements to read duration without playing
|
|
1149
|
+
*/
|
|
1150
|
+
detectVideoDurations(videoUrls) {
|
|
1151
|
+
if (!videoUrls || videoUrls.length === 0) {
|
|
1152
|
+
this.detectedVideoDurations = [];
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
1155
|
+
// Reset detected durations
|
|
1156
|
+
this.detectedVideoDurations = [];
|
|
1157
|
+
let loadedCount = 0;
|
|
1158
|
+
videoUrls.forEach((url, index) => {
|
|
1159
|
+
const tempVideo = document.createElement('video');
|
|
1160
|
+
tempVideo.preload = 'metadata';
|
|
1161
|
+
const onLoadedMetadata = () => {
|
|
1162
|
+
const durationMs = tempVideo.duration * 1000;
|
|
1163
|
+
this.detectedVideoDurations[index] = durationMs;
|
|
1164
|
+
loadedCount++;
|
|
1165
|
+
// Clean up
|
|
1166
|
+
tempVideo.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
1167
|
+
tempVideo.removeEventListener('error', onError);
|
|
1168
|
+
tempVideo.src = '';
|
|
1169
|
+
tempVideo.remove();
|
|
1170
|
+
if (loadedCount === videoUrls.length) {
|
|
1171
|
+
console.log('[Simulator] All video durations detected:', this.detectedVideoDurations);
|
|
1172
|
+
}
|
|
1173
|
+
};
|
|
1174
|
+
const onError = () => {
|
|
1175
|
+
console.warn(`[Simulator] Failed to load metadata for video ${index + 1}`);
|
|
1176
|
+
this.detectedVideoDurations[index] = 0;
|
|
1177
|
+
loadedCount++;
|
|
1178
|
+
tempVideo.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
1179
|
+
tempVideo.removeEventListener('error', onError);
|
|
1180
|
+
tempVideo.src = '';
|
|
1181
|
+
tempVideo.remove();
|
|
1182
|
+
};
|
|
1183
|
+
tempVideo.addEventListener('loadedmetadata', onLoadedMetadata);
|
|
1184
|
+
tempVideo.addEventListener('error', onError);
|
|
1185
|
+
tempVideo.src = url;
|
|
1186
|
+
});
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* Get cumulative duration boundaries for each video
|
|
1190
|
+
* Returns an array where each element is [startDuration, endDuration] for that video
|
|
1191
|
+
* Uses detected video durations if available, otherwise falls back to videoDurations input
|
|
1192
|
+
*/
|
|
1193
|
+
getVideoDurationBoundaries() {
|
|
1194
|
+
if (!this.hasMultipleVideos) {
|
|
1195
|
+
return [];
|
|
1196
|
+
}
|
|
1197
|
+
// Use detected durations if available, otherwise use provided durations
|
|
1198
|
+
const durations = this.detectedVideoDurations.length > 0
|
|
1199
|
+
? this.detectedVideoDurations
|
|
1200
|
+
: [];
|
|
1201
|
+
if (durations.length === 0) {
|
|
1202
|
+
return [];
|
|
1203
|
+
}
|
|
1204
|
+
const boundaries = [];
|
|
1205
|
+
let cumulativeStart = 0;
|
|
1206
|
+
for (const duration of durations) {
|
|
1207
|
+
boundaries.push({
|
|
1208
|
+
start: cumulativeStart,
|
|
1209
|
+
end: cumulativeStart + duration
|
|
1210
|
+
});
|
|
1211
|
+
cumulativeStart += duration;
|
|
1212
|
+
}
|
|
1213
|
+
return boundaries;
|
|
440
1214
|
}
|
|
441
|
-
|
|
442
|
-
|
|
1215
|
+
/**
|
|
1216
|
+
* Flatten all markers recursively including childSteps
|
|
1217
|
+
*/
|
|
1218
|
+
flattenMarkers(markers) {
|
|
1219
|
+
const flattened = [];
|
|
1220
|
+
const flattenRecursive = (markers) => {
|
|
1221
|
+
markers.forEach(marker => {
|
|
1222
|
+
// Add the marker itself
|
|
1223
|
+
flattened.push(marker);
|
|
1224
|
+
// Recursively add child markers
|
|
1225
|
+
if (marker.childSteps && marker.childSteps.length > 0) {
|
|
1226
|
+
flattenRecursive(marker.childSteps);
|
|
1227
|
+
}
|
|
1228
|
+
});
|
|
1229
|
+
};
|
|
1230
|
+
flattenRecursive(markers);
|
|
1231
|
+
return flattened;
|
|
1232
|
+
}
|
|
1233
|
+
checkMarkerHit(globalTimeMs) {
|
|
1234
|
+
if (!this.isPlaying || this.dragging)
|
|
1235
|
+
return;
|
|
1236
|
+
// Check all markers (including nested ones) for a match
|
|
1237
|
+
const allMarkers = this.flattenMarkers(this.stepMarkers);
|
|
1238
|
+
const tolerance = 200; // 200ms tolerance for matching
|
|
1239
|
+
for (const marker of allMarkers) {
|
|
1240
|
+
// Skip if marker doesn't have testStepId
|
|
1241
|
+
if (!marker.testStepId)
|
|
1242
|
+
continue;
|
|
1243
|
+
// Skip if already hit
|
|
1244
|
+
if (this.hitMarkers.has(marker.testStepId))
|
|
1245
|
+
continue;
|
|
1246
|
+
// Check if current time matches marker time (within tolerance)
|
|
1247
|
+
const timeDifference = Math.abs(globalTimeMs - marker.cumulativeDuration);
|
|
1248
|
+
if (timeDifference <= tolerance) {
|
|
1249
|
+
// Mark as hit and emit event
|
|
1250
|
+
this.hitMarkers.add(marker.testStepId);
|
|
1251
|
+
this.markerHit.emit(marker);
|
|
1252
|
+
console.log('[Simulator] Marker hit detected', {
|
|
1253
|
+
testStepId: marker.testStepId,
|
|
1254
|
+
cumulativeDuration: marker.cumulativeDuration,
|
|
1255
|
+
currentTime: globalTimeMs,
|
|
1256
|
+
timeDifference,
|
|
1257
|
+
title: marker.title,
|
|
1258
|
+
level: marker.level
|
|
1259
|
+
});
|
|
1260
|
+
break; // Only emit one marker per check
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
getGlobalMarkerResultColor(result) {
|
|
1265
|
+
switch (result) {
|
|
1266
|
+
case 'SUCCESS':
|
|
1267
|
+
return '#12B76A';
|
|
1268
|
+
case 'FAILURE':
|
|
1269
|
+
return '#B91C1C';
|
|
1270
|
+
case 'ABORTED':
|
|
1271
|
+
return '#F79009';
|
|
1272
|
+
case 'SKIPPED':
|
|
1273
|
+
return '#667085';
|
|
1274
|
+
default:
|
|
1275
|
+
return '#6366F1';
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
getGlobalMarkerColor(level) {
|
|
1279
|
+
return level === 1 ? '#000000' : '#FFA500';
|
|
1280
|
+
}
|
|
1281
|
+
onMarkerClick(event, marker) {
|
|
1282
|
+
event.stopPropagation();
|
|
1283
|
+
event.preventDefault();
|
|
1284
|
+
this.enqueueOperation(async () => {
|
|
1285
|
+
await this.seekToGlobalTime(marker.globalTime);
|
|
1286
|
+
if (marker.testStepId != null) {
|
|
1287
|
+
this.hitMarkers.add(marker.testStepId);
|
|
1288
|
+
const fullMarker = this.flattenMarkers(this.stepMarkers).find(m => m.testStepId === marker.testStepId);
|
|
1289
|
+
if (fullMarker)
|
|
1290
|
+
this.markerHit.emit(fullMarker);
|
|
1291
|
+
}
|
|
1292
|
+
});
|
|
443
1293
|
}
|
|
444
1294
|
toggleFullScreen() {
|
|
1295
|
+
const wasPlaying = this.isPlaying;
|
|
1296
|
+
const currentTime = this.vplayer?.nativeElement?.currentTime || 0;
|
|
1297
|
+
// Pause video before fullscreen transition to avoid state issues
|
|
1298
|
+
if (wasPlaying) {
|
|
1299
|
+
this.pauseVideo();
|
|
1300
|
+
}
|
|
1301
|
+
// Toggle fullscreen
|
|
445
1302
|
this.isFullScreen = !this.isFullScreen;
|
|
1303
|
+
// Reset player state to allow re-initialization after DOM update
|
|
1304
|
+
// The state might be stuck in 'loading' or 'error' after fullscreen transition
|
|
1305
|
+
if (this.playerState === 'loading' || this.playerState === 'error') {
|
|
1306
|
+
this.playerState = 'idle';
|
|
1307
|
+
}
|
|
1308
|
+
// Wait for Angular to update the DOM, then re-initialize video
|
|
1309
|
+
setTimeout(() => {
|
|
1310
|
+
const video = this.vplayer?.nativeElement;
|
|
1311
|
+
if (video) {
|
|
1312
|
+
// Restore video position if it was set
|
|
1313
|
+
if (currentTime > 0 && video.duration > currentTime) {
|
|
1314
|
+
video.currentTime = currentTime;
|
|
1315
|
+
}
|
|
1316
|
+
// Re-apply playback rate
|
|
1317
|
+
this.applyCurrentPlaybackRate();
|
|
1318
|
+
// Re-attach listeners
|
|
1319
|
+
this.attachVideoListeners();
|
|
1320
|
+
// Reset state to 'paused' (ready to play)
|
|
1321
|
+
this.playerState = 'paused';
|
|
1322
|
+
this.isPlaying = false;
|
|
1323
|
+
console.log('[Simulator] toggleFullScreen: video re-initialized', {
|
|
1324
|
+
isFullScreen: this.isFullScreen,
|
|
1325
|
+
currentTime: video.currentTime,
|
|
1326
|
+
playerState: this.playerState
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
else {
|
|
1330
|
+
console.warn('[Simulator] toggleFullScreen: video element not found after transition');
|
|
1331
|
+
// Try again after a bit more time
|
|
1332
|
+
setTimeout(() => {
|
|
1333
|
+
const videoRetry = this.vplayer?.nativeElement;
|
|
1334
|
+
if (videoRetry) {
|
|
1335
|
+
this.applyCurrentPlaybackRate();
|
|
1336
|
+
this.attachVideoListeners();
|
|
1337
|
+
this.playerState = 'paused';
|
|
1338
|
+
this.isPlaying = false;
|
|
1339
|
+
}
|
|
1340
|
+
}, 100);
|
|
1341
|
+
}
|
|
1342
|
+
}, 100);
|
|
446
1343
|
}
|
|
447
1344
|
onSegmentChange(value) {
|
|
448
1345
|
this.currentView = value;
|
|
449
|
-
|
|
450
|
-
this.
|
|
451
|
-
|
|
1346
|
+
// Pause video when switching away from video view
|
|
1347
|
+
if (this.currentView !== 'video') {
|
|
1348
|
+
this.pauseVideo();
|
|
1349
|
+
this.progress = 0;
|
|
1350
|
+
}
|
|
1351
|
+
else {
|
|
1352
|
+
// Reset everything when switching back to video view
|
|
1353
|
+
this.enqueueOperation(async () => {
|
|
1354
|
+
await this.resetVideoStateInternal();
|
|
1355
|
+
// If multiple videos, reset to first video
|
|
1356
|
+
if (this.hasMultipleVideos && this.videoUrls) {
|
|
1357
|
+
this.currentVideoIndex = 0;
|
|
1358
|
+
this.targetGlobalTimeDuringSwitch = 0;
|
|
1359
|
+
// Switch to first video and seek to 0
|
|
1360
|
+
await this.switchToVideoAndSeekInternal(0);
|
|
1361
|
+
}
|
|
1362
|
+
});
|
|
1363
|
+
}
|
|
452
1364
|
}
|
|
453
1365
|
formatTime(seconds) {
|
|
454
1366
|
if (!seconds || isNaN(seconds))
|
|
455
1367
|
return '00:00';
|
|
456
|
-
const
|
|
457
|
-
const
|
|
1368
|
+
const totalSeconds = Math.floor(seconds);
|
|
1369
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
1370
|
+
const mins = Math.floor((totalSeconds % 3600) / 60);
|
|
1371
|
+
const secs = totalSeconds % 60;
|
|
1372
|
+
// If hours > 0, show HH:MM:SS format, otherwise show MM:SS format
|
|
1373
|
+
if (hours > 0) {
|
|
1374
|
+
return `${hours.toString().padStart(2, '0')}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
|
|
1375
|
+
}
|
|
458
1376
|
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
|
|
459
1377
|
}
|
|
460
1378
|
getStatusBadgeClass() {
|
|
@@ -531,11 +1449,8 @@ export class SimulatorComponent {
|
|
|
531
1449
|
}
|
|
532
1450
|
onSpeedChange(value) {
|
|
533
1451
|
this.currentSpeed = value;
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
if (this.vplayer?.nativeElement) {
|
|
537
|
-
this.vplayer.nativeElement.playbackRate = rate;
|
|
538
|
-
}
|
|
1452
|
+
// Whenever speed changes, apply it to the current video
|
|
1453
|
+
this.applyCurrentPlaybackRate();
|
|
539
1454
|
this.isSpeedControlOpen = false;
|
|
540
1455
|
}
|
|
541
1456
|
toggleSpeedControl() {
|
|
@@ -586,19 +1501,239 @@ export class SimulatorComponent {
|
|
|
586
1501
|
}
|
|
587
1502
|
onVideoElementReady() {
|
|
588
1503
|
const video = this._vplayer?.nativeElement;
|
|
1504
|
+
if (!video)
|
|
1505
|
+
return;
|
|
1506
|
+
console.log('[Simulator] onVideoElementReady: video element ready', {
|
|
1507
|
+
playerState: this.playerState,
|
|
1508
|
+
isFullScreen: this.isFullScreen,
|
|
1509
|
+
readyState: video.readyState
|
|
1510
|
+
});
|
|
1511
|
+
// Reset error/loading states when video element is recreated (e.g., during fullscreen toggle)
|
|
1512
|
+
if (this.playerState === 'error' || this.playerState === 'loading') {
|
|
1513
|
+
console.log('[Simulator] onVideoElementReady: resetting error/loading state');
|
|
1514
|
+
this.playerState = 'idle';
|
|
1515
|
+
this.isPlaying = false;
|
|
1516
|
+
this.playPromise = null;
|
|
1517
|
+
}
|
|
1518
|
+
// Apply current playback speed when the video element is first ready
|
|
1519
|
+
this.applyCurrentPlaybackRate();
|
|
1520
|
+
this.attachVideoListeners();
|
|
1521
|
+
}
|
|
1522
|
+
applyCurrentPlaybackRate() {
|
|
1523
|
+
const video = this.vplayer?.nativeElement;
|
|
589
1524
|
if (!video)
|
|
590
1525
|
return;
|
|
591
1526
|
const numeric = parseFloat(this.currentSpeed.replace('x', ''));
|
|
592
1527
|
const rate = !isNaN(numeric) && numeric > 0 ? numeric : 1;
|
|
593
1528
|
video.playbackRate = rate;
|
|
594
|
-
|
|
1529
|
+
}
|
|
1530
|
+
findVideoIndexForTimestamp(cumulativeTimestamp) {
|
|
1531
|
+
if (!this.hasMultipleVideos) {
|
|
1532
|
+
return null;
|
|
1533
|
+
}
|
|
1534
|
+
const boundaries = this.getVideoDurationBoundaries();
|
|
1535
|
+
if (boundaries.length === 0) {
|
|
1536
|
+
return null;
|
|
1537
|
+
}
|
|
1538
|
+
// Find which video contains this timestamp
|
|
1539
|
+
for (let i = 0; i < boundaries.length; i++) {
|
|
1540
|
+
const boundary = boundaries[i];
|
|
1541
|
+
if (cumulativeTimestamp >= boundary.start && cumulativeTimestamp < boundary.end) {
|
|
1542
|
+
return i;
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
// If timestamp is exactly at the end of the last video, return the last video index
|
|
1546
|
+
if (boundaries.length > 0) {
|
|
1547
|
+
const lastBoundary = boundaries[boundaries.length - 1];
|
|
1548
|
+
if (cumulativeTimestamp === lastBoundary.end) {
|
|
1549
|
+
return boundaries.length - 1;
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
return null;
|
|
1553
|
+
}
|
|
1554
|
+
switchToVideoAndSeek(cumulativeTimestamp) {
|
|
1555
|
+
this.enqueueOperation(() => this.switchToVideoAndSeekInternal(cumulativeTimestamp));
|
|
1556
|
+
}
|
|
1557
|
+
async switchToVideoAndSeekInternal(cumulativeTimestamp) {
|
|
1558
|
+
if (!this.hasMultipleVideos) {
|
|
1559
|
+
await this.seekToTimeInternal(cumulativeTimestamp);
|
|
1560
|
+
return;
|
|
1561
|
+
}
|
|
1562
|
+
const targetVideoIndex = this.findVideoIndexForTimestamp(cumulativeTimestamp);
|
|
1563
|
+
if (targetVideoIndex === null) {
|
|
1564
|
+
console.warn('[Simulator] switchToVideoAndSeek: Could not find video for timestamp', cumulativeTimestamp);
|
|
1565
|
+
return;
|
|
1566
|
+
}
|
|
1567
|
+
const boundaries = this.getVideoDurationBoundaries();
|
|
1568
|
+
const targetBoundary = boundaries[targetVideoIndex];
|
|
1569
|
+
const relativeTimestamp = cumulativeTimestamp - targetBoundary.start;
|
|
1570
|
+
if (this.currentVideoIndex === targetVideoIndex) {
|
|
1571
|
+
await this.seekToTimeInternal(relativeTimestamp);
|
|
1572
|
+
this.lastSetDuration = cumulativeTimestamp;
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
const video = this.vplayer?.nativeElement;
|
|
1576
|
+
if (!video)
|
|
1577
|
+
return;
|
|
1578
|
+
const total = this.totalDuration;
|
|
1579
|
+
this.targetGlobalTimeDuringSwitch = cumulativeTimestamp;
|
|
1580
|
+
if (total > 0) {
|
|
1581
|
+
this.progress = Math.min(100, Math.max(0, (cumulativeTimestamp / total) * 100));
|
|
1582
|
+
}
|
|
1583
|
+
this.playerState = 'switching';
|
|
1584
|
+
try {
|
|
1585
|
+
// CRITICAL: Pause before switching source
|
|
1586
|
+
video.pause();
|
|
1587
|
+
this.isPlaying = false;
|
|
1588
|
+
this.playPromise = null;
|
|
1589
|
+
this.videoPause.emit();
|
|
1590
|
+
this.isVideoPlayingChange.emit(false);
|
|
1591
|
+
// Switch video source
|
|
1592
|
+
this.currentVideoIndex = targetVideoIndex;
|
|
1593
|
+
await new Promise((resolve, reject) => {
|
|
1594
|
+
let resolved = false;
|
|
1595
|
+
const cleanup = () => {
|
|
1596
|
+
if (resolved)
|
|
1597
|
+
return;
|
|
1598
|
+
resolved = true;
|
|
1599
|
+
video.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
1600
|
+
video.removeEventListener('error', onError);
|
|
1601
|
+
clearTimeout(timeoutId);
|
|
1602
|
+
};
|
|
1603
|
+
const onLoadedMetadata = () => {
|
|
1604
|
+
cleanup();
|
|
1605
|
+
console.log('[Simulator] switchToVideoAndSeek: loadedmetadata', {
|
|
1606
|
+
readyState: video.readyState,
|
|
1607
|
+
duration: video.duration,
|
|
1608
|
+
currentTime: video.currentTime
|
|
1609
|
+
});
|
|
1610
|
+
resolve();
|
|
1611
|
+
};
|
|
1612
|
+
const onError = () => {
|
|
1613
|
+
cleanup();
|
|
1614
|
+
console.error('[Simulator] switchToVideoAndSeek: video error');
|
|
1615
|
+
reject(new Error('Failed to load video'));
|
|
1616
|
+
};
|
|
1617
|
+
setTimeout(() => {
|
|
1618
|
+
if (resolved)
|
|
1619
|
+
return;
|
|
1620
|
+
video.addEventListener('loadedmetadata', onLoadedMetadata, { once: true });
|
|
1621
|
+
video.addEventListener('error', onError, { once: true });
|
|
1622
|
+
}, 100);
|
|
1623
|
+
const timeoutId = setTimeout(() => {
|
|
1624
|
+
cleanup();
|
|
1625
|
+
if (video.readyState >= HTMLMediaElement.HAVE_METADATA) {
|
|
1626
|
+
console.log('[Simulator] switchToVideoAndSeek: metadata timeout but video ready', {
|
|
1627
|
+
readyState: video.readyState,
|
|
1628
|
+
duration: video.duration
|
|
1629
|
+
});
|
|
1630
|
+
resolve();
|
|
1631
|
+
}
|
|
1632
|
+
else {
|
|
1633
|
+
console.error('[Simulator] switchToVideoAndSeek: metadata timeout and video not ready');
|
|
1634
|
+
reject(new Error('Timeout waiting for video to load'));
|
|
1635
|
+
}
|
|
1636
|
+
}, 2000);
|
|
1637
|
+
});
|
|
1638
|
+
// Seek to the target position using 'seeked' event for reliability
|
|
1639
|
+
const seekSeconds = relativeTimestamp / 1000;
|
|
1640
|
+
const targetTime = Math.max(0, Math.min(seekSeconds, video.duration || seekSeconds));
|
|
1641
|
+
console.log('[Simulator] switchToVideoAndSeek: setting currentTime', {
|
|
1642
|
+
targetTime,
|
|
1643
|
+
seekSeconds,
|
|
1644
|
+
relativeTimestamp,
|
|
1645
|
+
videoDuration: video.duration
|
|
1646
|
+
});
|
|
1647
|
+
await new Promise((resolve) => {
|
|
1648
|
+
let resolved = false;
|
|
1649
|
+
const onSeeked = () => {
|
|
1650
|
+
if (resolved)
|
|
1651
|
+
return;
|
|
1652
|
+
resolved = true;
|
|
1653
|
+
video.removeEventListener('seeked', onSeeked);
|
|
1654
|
+
clearTimeout(timeoutId);
|
|
1655
|
+
console.log('[Simulator] switchToVideoAndSeek: seeked event fired', {
|
|
1656
|
+
currentTime: video.currentTime,
|
|
1657
|
+
targetTime,
|
|
1658
|
+
diff: Math.abs(video.currentTime - targetTime)
|
|
1659
|
+
});
|
|
1660
|
+
// Small delay to ensure browser has processed the seek
|
|
1661
|
+
setTimeout(() => resolve(), 100);
|
|
1662
|
+
};
|
|
1663
|
+
video.addEventListener('seeked', onSeeked, { once: true });
|
|
1664
|
+
video.currentTime = targetTime;
|
|
1665
|
+
// Fallback timeout
|
|
1666
|
+
const timeoutId = setTimeout(() => {
|
|
1667
|
+
if (resolved)
|
|
1668
|
+
return;
|
|
1669
|
+
resolved = true;
|
|
1670
|
+
video.removeEventListener('seeked', onSeeked);
|
|
1671
|
+
console.log('[Simulator] switchToVideoAndSeek: seeked timeout, current time is', video.currentTime);
|
|
1672
|
+
resolve();
|
|
1673
|
+
}, 1000);
|
|
1674
|
+
});
|
|
1675
|
+
this.lastSetDuration = cumulativeTimestamp;
|
|
1676
|
+
// Double-check: if video is not at target, force it again
|
|
1677
|
+
if (Math.abs(video.currentTime - targetTime) > 0.5) {
|
|
1678
|
+
console.warn('[Simulator] switchToVideoAndSeek: video not at target after seeked, forcing again', {
|
|
1679
|
+
currentTime: video.currentTime,
|
|
1680
|
+
targetTime
|
|
1681
|
+
});
|
|
1682
|
+
video.currentTime = targetTime;
|
|
1683
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
1684
|
+
}
|
|
1685
|
+
// Verify seek completed
|
|
1686
|
+
const actualGlobal = this.getActualGlobalTime();
|
|
1687
|
+
const actualVideoTime = video.currentTime;
|
|
1688
|
+
console.log('[Simulator] switchToVideoAndSeek: seek verification', {
|
|
1689
|
+
actualGlobal,
|
|
1690
|
+
targetGlobal: cumulativeTimestamp,
|
|
1691
|
+
diff: Math.abs(actualGlobal - cumulativeTimestamp),
|
|
1692
|
+
actualVideoTime,
|
|
1693
|
+
targetVideoTime: targetTime,
|
|
1694
|
+
videoDiff: Math.abs(actualVideoTime - targetTime)
|
|
1695
|
+
});
|
|
1696
|
+
// Clear override only if video is actually at the target
|
|
1697
|
+
const tolerance = 500;
|
|
1698
|
+
if (Math.abs(actualGlobal - cumulativeTimestamp) < tolerance) {
|
|
1699
|
+
this.targetGlobalTimeDuringSwitch = null;
|
|
1700
|
+
console.log('[Simulator] switchToVideoAndSeek: cleared override - video at target');
|
|
1701
|
+
}
|
|
1702
|
+
// Update UI with actual current position
|
|
1703
|
+
if (total > 0) {
|
|
1704
|
+
this.progress = Math.min(100, Math.max(0, (this.globalCurrentTime / total) * 100));
|
|
1705
|
+
}
|
|
1706
|
+
this.videoTimeUpdate.emit(this.globalCurrentTime);
|
|
1707
|
+
}
|
|
1708
|
+
catch (err) {
|
|
1709
|
+
console.error('[Simulator] switchToVideoAndSeek failed:', err);
|
|
1710
|
+
// Even on error, try to update to target position
|
|
1711
|
+
if (total > 0) {
|
|
1712
|
+
this.progress = Math.min(100, Math.max(0, (cumulativeTimestamp / total) * 100));
|
|
1713
|
+
}
|
|
1714
|
+
this.videoTimeUpdate.emit(cumulativeTimestamp);
|
|
1715
|
+
}
|
|
1716
|
+
finally {
|
|
1717
|
+
this.playerState = 'paused';
|
|
1718
|
+
this.hitMarkers.clear();
|
|
1719
|
+
// Don't clear targetGlobalTimeDuringSwitch here - it's either already cleared
|
|
1720
|
+
// or will be cleared by timeupdate handler when video reaches target
|
|
1721
|
+
}
|
|
1722
|
+
console.log('[Simulator] switchToVideoAndSeek: complete', {
|
|
1723
|
+
currentVideoIndex: this.currentVideoIndex,
|
|
1724
|
+
videoCurrentTime: video.currentTime,
|
|
1725
|
+
globalCurrentTime: this.globalCurrentTime,
|
|
1726
|
+
targetGlobalTimeDuringSwitch: this.targetGlobalTimeDuringSwitch,
|
|
1727
|
+
playerState: this.playerState,
|
|
1728
|
+
progress: this.progress
|
|
1729
|
+
});
|
|
595
1730
|
}
|
|
596
1731
|
}
|
|
597
1732
|
SimulatorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SimulatorComponent, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component });
|
|
598
|
-
SimulatorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: SimulatorComponent, selector: "cqa-simulator", inputs: { videoUrl: "videoUrl", videoUrls: "videoUrls", videoCurrentDuration: "videoCurrentDuration", stepMarkers: "stepMarkers", screenShotUrl: "screenShotUrl", traceViewUrl: "traceViewUrl", platformName: "platformName", platformType: "platformType", platform: "platform", deviceName: "deviceName", isLive: "isLive", liveStatus: "liveStatus", liveLoadingLabel: "liveLoadingLabel", isContentVideoLoading: "isContentVideoLoading", failedStatusMessage: "failedStatusMessage", isVNCSessionIntruppted: "isVNCSessionIntruppted", vncSessionIntupptedMessage: "vncSessionIntupptedMessage", selectedView: "selectedView", hideVideoTab: "hideVideoTab", browserViewPort: "browserViewPort" }, outputs: { videoTimeUpdate: "videoTimeUpdate", videoPlay: "videoPlay", videoPause: "videoPause" }, viewQueries: [{ propertyName: "vplayerRef", first: true, predicate: ["vplayer"], descendants: true }, { propertyName: "timelineBar", first: true, predicate: ["timelineBar"], descendants: true }, { propertyName: "speedControlContainer", first: true, predicate: ["speedControlContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-ui-root\" style=\"background-color: #F3F4F6; height: 100%; display: flex; flex-direction: column;\" [ngStyle]=\"{\n position: isFullScreen ? 'fixed' : null,\n inset: isFullScreen ? '1rem' : null,\n zIndex: isFullScreen ? '50' : null,\n boxShadow: isFullScreen ? '0px 13px 25px -12px rgba(0, 0, 0, 0.25)' : null,\n borderRadius: isFullScreen ? '.5rem' : null,\n border: isFullScreen ? '1px solid #E5E7EB' : null,\n width: isFullScreen ? 'calc(100% - 32px)' : null,\n height: isFullScreen ? 'calc(100% - 32px)' : '100%',\n overflow: isFullScreen ? 'hidden' : null\n}\">\n <div class=\"cqa-w-full cqa-py-1 cqa-px-2 cqa-bg-[#FFFFFF]\" style=\"border-bottom: 1px solid #E5E7EB;box-shadow: 0px 1px 2px 0px #0000000D;\">\n <div class=\"cqa-w-full cqa-flex cqa-items-center cqa-justify-between cqa-flex-wrap\">\n <div class=\"cqa-flex cqa-items-center\">\n <div *ngIf=\"isLive\" class=\"cqa-h-[21px] cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-mr-2 cqa-px-[9px] cqa-py-[3px] cqa-bg-[#FCD9D9] cqa-rounded-[6px]\" style=\"border: 1px solid #F9BFBF;\">\n <span class=\"cqa-relative cqa-w-2 cqa-h-2 cqa-rounded-full cqa-bg-[#F47F7F]\" style=\"flex-shrink: 0;\">\n <span class=\"cqa-absolute cqa-inset-0 cqa-rounded-full cqa-bg-[#F47F7F] cqa-opacity-75 cqa-animate-ping\"></span>\n </span>\n <span class=\"cqa-text-[10px] cqa-font-medium cqa-text-[#C63535] cqa-leading-[15px]\">Live</span>\n </div>\n <mat-icon *ngIf=\"platformType === 'browser'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <g clip-path=\"url(#clip0_935_15847)\">\n <path\n d=\"M0.625 5C0.625 6.16032 1.08594 7.27312 1.90641 8.09359C2.72688 8.91406 3.83968 9.375 5 9.375C6.16032 9.375 7.27312 8.91406 8.09359 8.09359C8.91406 7.27312 9.375 6.16032 9.375 5C9.375 3.83968 8.91406 2.72688 8.09359 1.90641C7.27312 1.08594 6.16032 0.625 5 0.625C3.83968 0.625 2.72688 1.08594 1.90641 1.90641C1.08594 2.72688 0.625 3.83968 0.625 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path\n d=\"M3.125 5C3.125 3.83968 3.32254 2.72688 3.67417 1.90641C4.02581 1.08594 4.50272 0.625 5 0.625C5.49728 0.625 5.97419 1.08594 6.32582 1.90641C6.67746 2.72688 6.875 3.83968 6.875 5C6.875 6.16032 6.67746 7.27312 6.32582 8.09359C5.97419 8.91406 5.49728 9.375 5 9.375C4.50272 9.375 4.02581 8.91406 3.67417 8.09359C3.32254 7.27312 3.125 6.16032 3.125 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path d=\"M0.9375 6.45866H9.0625M0.9375 3.54199H9.0625\" stroke=\"#9CA3AF\" stroke-width=\"0.6\"\n stroke-linecap=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_935_15847\">\n <rect width=\"10\" height=\"10\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </mat-icon>\n <mat-icon *ngIf=\"platformType === 'device'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M7.08325 0.833008H2.91659C2.45635 0.833008 2.08325 1.2061 2.08325 1.66634V8.33301C2.08325 8.79324 2.45635 9.16634 2.91659 9.16634H7.08325C7.54349 9.16634 7.91658 8.79324 7.91658 8.33301V1.66634C7.91658 1.2061 7.54349 0.833008 7.08325 0.833008Z\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5 7.5H5.00417\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <p class=\"cqa-text-sm !cqa-text-[10px] cqa-text-[#6B7280] cqa-ml-2\">\n {{ platformName }}\n <span\n *ngIf=\"platformType === 'browser'\"\n class=\"cqa-ml-1\"\n [matTooltip]=\"'Screen size: ' + effectiveBrowserViewPort.width + 'x' + effectiveBrowserViewPort.height\"\n matTooltipPosition=\"below\"\n >\n \u00B7\n <span class=\"cqa-ml-1\">\n {{ effectiveBrowserViewPort.width }}x{{ effectiveBrowserViewPort.height }}\n </span>\n </span>\n </p>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div *ngIf=\"isLive\" [ngClass]=\"getStatusBadgeClass()\">\n <span [ngClass]=\"getStatusTextClass()\">{{ liveStatus }}</span>\n </div>\n\n <ng-container *ngIf=\"!isLive\">\n <cqa-segment-control \n [segments]=\"segments\" \n [value]=\"currentView\"\n (valueChange)=\"onSegmentChange($event)\">\n </cqa-segment-control>\n \n <div *ngIf=\"!isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Expand\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M6.25 1.25H8.75V3.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.74992 1.25L5.83325 4.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 8.74967L4.16667 5.83301\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M3.75 8.75H1.25V6.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n\n <div *ngIf=\"isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Exit full screen\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M8.75 6.25H6.25V8.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.25008 6.25L9.16675 9.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M0.833252 0.833008L3.74992 3.74967\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 3.75H3.75V1.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n <div class=\"cqa-w-full cqa-bg-[#F3F4F6] cqa-h-[calc(100%-41px)]\">\n <!-- Live Content View -->\n <div *ngIf=\"isLive\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center cqa-relative\">\n <ng-container *ngIf=\"hasDeviceFrame;\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-max-h-full cqa-h-full': platformType !== 'browser' || !isLive, 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-z-20': platformType === 'browser', 'cqa-bg-white': platformType !== 'browser'}\">\n <!-- Loading State -->\n <div *ngIf=\"isContentVideoLoading\" class=\"cqa-p-10 cqa-text-center cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <div class=\"cqa-mb-4\">\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"40\"></mat-progress-spinner>\n </div>\n <p class=\"cqa-text-gray-400 cqa-text-sm\">{{ liveLoadingLabel }}</p>\n </div>\n\n <!-- Live Content (when not loading) -->\n <div *ngIf=\"!isContentVideoLoading\" class=\"cqa-w-full cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-relative\">\n <div *ngIf=\"liveStatus === 'Failed' && failedStatusMessage\" class=\"cqa-p-6 cqa-text-center cqa-w-full\">\n <div class=\"cqa-inline-flex cqa-items-center cqa-gap-2 cqa-px-4 cqa-py-3 cqa-bg-[#FCD9D9] cqa-border cqa-border-[#F9BFBF] cqa-rounded-lg\">\n <mat-icon style=\"width: 18px; height: 18px; color: #C63535; font-size: 18px;\">error</mat-icon>\n <p class=\"cqa-text-[#C63535] cqa-text-sm cqa-font-medium cqa-m-0\">{{ failedStatusMessage }}</p>\n </div>\n </div>\n <ng-content *ngIf=\"liveStatus !== 'Failed' || !failedStatusMessage\"></ng-content>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Normal Video View (when not live) -->\n <div *ngIf=\"!isLive && currentView === 'video'\" class=\"cqa-h-full cqa-flex cqa-flex-col\">\n <div class=\"cqa-w-full cqa-py-4 cqa-flex cqa-items-center cqa-max-h-[calc(100%-83px)]\" *ngIf=\"currentVideoUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device', 'cqa-mt-auto': hasDeviceFrame}\">\n <ng-container *ngIf=\"hasDeviceFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-p-4': platformType === 'browser'}\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <video\n #vplayer\n class=\"cqa-object-cover cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n [src]=\"currentVideoUrl\"\n type=\"video/webm\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n (loadedmetadata)=\"onVideoMetadataLoaded()\"\n (canplay)=\"onVideoCanPlay()\"\n (ended)=\"onVideoEnded()\"\n ></video>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!currentVideoUrl\">\n <ng-container *ngIf=\"isVNCSessionIntruppted && vncSessionIntupptedMessage; else noVideoDefault\">\n <p class=\"cqa-text-sm cqa-text-gray-600\">\n {{ vncSessionIntupptedMessage }}\n </p>\n </ng-container>\n <ng-template #noVideoDefault>\n <span>No video recording found</span>\n </ng-template>\n </div>\n \n <div class=\"cqa-px-2 cqa-py-2 cqa-bg-white\" style=\"border-top: 1px solid #E5E7EB;\" [ngClass]=\"{'cqa-mt-auto': hasDeviceFrame}\" *ngIf=\"currentVideoUrl && !isLive\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <button \n *ngIf=\"hasMultipleVideos\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n [disabled]=\"currentVideoIndex === 0\"\n [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': currentVideoIndex === 0}\"\n (click)=\"prevVideo()\"\n matTooltip=\"Previous video\"\n matTooltipPosition=\"above\">\n <mat-icon class=\"cqa-w-4 cqa-h-4 !cqa-text-[16px] cqa-text-[#374151]\" [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': currentVideoIndex === 0}\">skip_previous</mat-icon>\n </button>\n\n <button \n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n (click)=\"togglePlay()\"\n matTooltip=\"{{ isPlaying ? 'Pause' : 'Play' }}\"\n matTooltipPosition=\"above\">\n <span *ngIf=\"!isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M3 2L13 8L3 14V2Z\" fill=\"#374151\"/>\n </svg>\n </span>\n <span *ngIf=\"isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"3\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n <rect x=\"10\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n </svg>\n </span>\n </button>\n \n <button \n *ngIf=\"hasMultipleVideos\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n [disabled]=\"videoUrls && (currentVideoIndex >= videoUrls.length - 1)\"\n [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': videoUrls && (currentVideoIndex >= videoUrls.length - 1)}\"\n (click)=\"nextVideo()\"\n matTooltip=\"Next video\"\n matTooltipPosition=\"above\">\n <mat-icon class=\"cqa-w-4 cqa-h-4 !cqa-text-[16px] cqa-text-[#374151]\" [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': videoUrls && (currentVideoIndex >= videoUrls.length - 1)}\">skip_next</mat-icon>\n </button>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none\">\n {{ formatTime(vplayer?.nativeElement?.currentTime || 0) }}\n </span>\n\n <div #speedControlContainer class=\"cqa-relative cqa-mr-[8px] cqa-flex cqa-items-center cqa-justify-center\">\n <button\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer cqa-text-[#9CA3AF] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-whitespace-nowrap cqa-select-none hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none cqa-px-1\"\n (click)=\"toggleSpeedControl()\"\n [matTooltip]=\"'Playback Speed'\"\n [matTooltipPosition]=\"'below'\">\n {{ currentSpeed }}\n </button>\n \n <div \n *ngIf=\"isSpeedControlOpen\"\n class=\"cqa-absolute cqa-bottom-full cqa-mb-2 cqa-right-0 cqa-bg-[#F0F0F1] cqa-rounded-lg cqa-overflow-hidden cqa-shadow-lg cqa-z-50\"\n style=\"min-width: max-content; left: 50%; bottom: 0%; transform: translate(-50%, -50%);\">\n <cqa-segment-control\n [segments]=\"speedSegments\"\n [value]=\"currentSpeed\"\n [containerBgColor]=\"'#F0F0F1'\"\n (valueChange)=\"onSpeedChange($event)\">\n </cqa-segment-control>\n </div>\n </div>\n \n <div \n #timelineBar\n class=\"cqa-relative cqa-h-1 cqa-bg-gray-200 cqa-rounded-full cqa-cursor-pointer cqa-flex-1\"\n (click)=\"onTimelineClick($event)\">\n \n <div \n *ngFor=\"let step of stepMarkers\" \n class=\"cqa-absolute cqa-w-1 cqa-h-full cqa-top-0 cqa-rounded-sm\"\n [style.left.%]=\"getStepLeftPosition(step)\"\n [style.background]=\"getStepColor(step)\"\n style=\"pointer-events: none; z-index: 20;\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-h-full cqa-bg-blue-500 cqa-rounded-full\"\n [style.width.%]=\"progress\"\n [style.transition]=\"dragging ? 'none' : 'width 100ms'\"\n style=\"pointer-events: none; z-index: 2;\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-top-1/2 cqa-w-3 cqa-h-3 cqa-bg-blue-600 cqa-rounded-full cqa-cursor-grab active:cqa-cursor-grabbing cqa-shadow-md\"\n [style.left.%]=\"progress\"\n style=\"transform: translate(-50%, -50%); z-index: 40;\"\n (mousedown)=\"startDrag($event)\">\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'screenshots'\" class=\"cqa-h-full\">\n <div class=\"cqa-w-full cqa-py-4 cqa-h-full cqa-flex cqa-items-center\" *ngIf=\"screenShotUrl\">\n <ng-container *ngIf=\"hasDeviceFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-p-4': platformType === 'browser'}\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n [ngClass]=\"{'cqa-max-h-[inherit]': platformType === 'browser', 'cqa-max-h-full': platformType !== 'browser'}\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <img\n [src]=\"screenShotUrl\"\n alt=\"Screenshot\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n class=\"cqa-object-contain cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n />\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!screenShotUrl\">\n No screenshot available\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'trace'\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-relative\" *ngIf=\"traceViewUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device'}\" style=\"padding-top: 48px; padding-bottom: 0px;\">\n <div class=\"cqa-w-full cqa-h-full cqa-overflow-hidden cqa-relative\">\n <iframe \n [src]=\"safeTraceUrl\" \n title=\"Trace Viewer\"\n class=\"cqa-object-contain cqa-w-full cqa-min-h-[250px] cqa-max-h-full cqa-block cqa-bg-[##F2F2F2]\"\n style=\"margin-top: -48px; height: calc(100% + 48px);\"\n frameborder=\"0\"\n allowfullscreen\n width=\"100%\"\n loading=\"lazy\"\n (load)=\"onTraceViewerLoad()\"\n (error)=\"onTraceViewerError()\">\n </iframe>\n </div>\n \n <div *ngIf=\"traceViewerLoading\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Loading trace viewer...\n </div>\n </div>\n \n <div *ngIf=\"traceViewerError\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Failed to load trace viewer\n </div>\n </div>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!traceViewUrl\">\n No trace available\n </div>\n </div> \n </div>\n</div>", components: [{ type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i3.SegmentControlComponent, selector: "cqa-segment-control", inputs: ["segments", "value", "disabled", "containerBgColor"], outputs: ["valueChange"] }, { type: i4.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "diameter", "strokeWidth", "mode", "value"], exportAs: ["matProgressSpinner"] }], directives: [{ type: i5.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
|
|
1733
|
+
SimulatorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: SimulatorComponent, selector: "cqa-simulator", inputs: { videoUrl: "videoUrl", videoUrls: "videoUrls", videoCurrentDuration: "videoCurrentDuration", stepMarkers: "stepMarkers", screenShotUrl: "screenShotUrl", traceViewUrl: "traceViewUrl", platformName: "platformName", platformType: "platformType", platform: "platform", deviceName: "deviceName", isLive: "isLive", liveStatus: "liveStatus", liveLoadingLabel: "liveLoadingLabel", isContentVideoLoading: "isContentVideoLoading", failedStatusMessage: "failedStatusMessage", isVNCSessionIntruppted: "isVNCSessionIntruppted", vncSessionIntupptedMessage: "vncSessionIntupptedMessage", selectedView: "selectedView", hideVideoTab: "hideVideoTab", browserViewPort: "browserViewPort" }, outputs: { videoTimeUpdate: "videoTimeUpdate", videoPlay: "videoPlay", videoPause: "videoPause", markerHit: "markerHit", isVideoPlayingChange: "isVideoPlayingChange" }, viewQueries: [{ propertyName: "vplayerRef", first: true, predicate: ["vplayer"], descendants: true }, { propertyName: "timelineBarRef", first: true, predicate: ["timelineBar"], descendants: true }, { propertyName: "speedControlContainerRef", first: true, predicate: ["speedControlContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-ui-root\" style=\"background-color: #F3F4F6; height: 100%; display: flex; flex-direction: column;\" [ngStyle]=\"{\n position: isFullScreen ? 'fixed' : null,\n inset: isFullScreen ? '1rem' : null,\n zIndex: isFullScreen ? '50' : null,\n boxShadow: isFullScreen ? '0px 13px 25px -12px rgba(0, 0, 0, 0.25)' : null,\n borderRadius: isFullScreen ? '.5rem' : null,\n border: isFullScreen ? '1px solid #E5E7EB' : null,\n width: isFullScreen ? 'calc(100% - 32px)' : null,\n height: isFullScreen ? 'calc(100% - 32px)' : '100%',\n overflow: isFullScreen ? 'hidden' : null\n}\">\n <div class=\"cqa-w-full cqa-py-1 cqa-px-2 cqa-bg-[#FFFFFF]\" style=\"border-bottom: 1px solid #E5E7EB;box-shadow: 0px 1px 2px 0px #0000000D;\">\n <div class=\"cqa-w-full cqa-flex cqa-items-center cqa-justify-between cqa-flex-wrap\">\n <div class=\"cqa-flex cqa-items-center\">\n <div *ngIf=\"isLive\" class=\"cqa-h-[21px] cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-mr-2 cqa-px-[9px] cqa-py-[3px] cqa-bg-[#FCD9D9] cqa-rounded-[6px]\" style=\"border: 1px solid #F9BFBF;\">\n <span class=\"cqa-relative cqa-w-2 cqa-h-2 cqa-rounded-full cqa-bg-[#F47F7F]\" style=\"flex-shrink: 0;\">\n <span class=\"cqa-absolute cqa-inset-0 cqa-rounded-full cqa-bg-[#F47F7F] cqa-opacity-75 cqa-animate-ping\"></span>\n </span>\n <span class=\"cqa-text-[10px] cqa-font-medium cqa-text-[#C63535] cqa-leading-[15px]\">Live</span>\n </div>\n <mat-icon *ngIf=\"platformType === 'browser'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <g clip-path=\"url(#clip0_935_15847)\">\n <path\n d=\"M0.625 5C0.625 6.16032 1.08594 7.27312 1.90641 8.09359C2.72688 8.91406 3.83968 9.375 5 9.375C6.16032 9.375 7.27312 8.91406 8.09359 8.09359C8.91406 7.27312 9.375 6.16032 9.375 5C9.375 3.83968 8.91406 2.72688 8.09359 1.90641C7.27312 1.08594 6.16032 0.625 5 0.625C3.83968 0.625 2.72688 1.08594 1.90641 1.90641C1.08594 2.72688 0.625 3.83968 0.625 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path\n d=\"M3.125 5C3.125 3.83968 3.32254 2.72688 3.67417 1.90641C4.02581 1.08594 4.50272 0.625 5 0.625C5.49728 0.625 5.97419 1.08594 6.32582 1.90641C6.67746 2.72688 6.875 3.83968 6.875 5C6.875 6.16032 6.67746 7.27312 6.32582 8.09359C5.97419 8.91406 5.49728 9.375 5 9.375C4.50272 9.375 4.02581 8.91406 3.67417 8.09359C3.32254 7.27312 3.125 6.16032 3.125 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path d=\"M0.9375 6.45866H9.0625M0.9375 3.54199H9.0625\" stroke=\"#9CA3AF\" stroke-width=\"0.6\"\n stroke-linecap=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_935_15847\">\n <rect width=\"10\" height=\"10\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </mat-icon>\n <mat-icon *ngIf=\"platformType === 'device'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M7.08325 0.833008H2.91659C2.45635 0.833008 2.08325 1.2061 2.08325 1.66634V8.33301C2.08325 8.79324 2.45635 9.16634 2.91659 9.16634H7.08325C7.54349 9.16634 7.91658 8.79324 7.91658 8.33301V1.66634C7.91658 1.2061 7.54349 0.833008 7.08325 0.833008Z\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5 7.5H5.00417\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <p class=\"cqa-text-sm !cqa-text-[10px] cqa-text-[#6B7280] cqa-ml-2\">\n {{ platformName }}\n <span\n *ngIf=\"platformType === 'browser'\"\n class=\"cqa-ml-1\"\n [matTooltip]=\"'Screen size: ' + effectiveBrowserViewPort.width + 'x' + effectiveBrowserViewPort.height\"\n matTooltipPosition=\"below\"\n >\n \u00B7\n <span class=\"cqa-ml-1\">\n {{ effectiveBrowserViewPort.width }}x{{ effectiveBrowserViewPort.height }}\n </span>\n </span>\n </p>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div *ngIf=\"isLive\" [ngClass]=\"getStatusBadgeClass()\">\n <span [ngClass]=\"getStatusTextClass()\">{{ liveStatus }}</span>\n </div>\n\n <ng-container *ngIf=\"!isLive\">\n <cqa-segment-control \n [segments]=\"segments\" \n [value]=\"currentView\"\n (valueChange)=\"onSegmentChange($event)\">\n </cqa-segment-control>\n \n <div *ngIf=\"!isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Expand\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M6.25 1.25H8.75V3.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.74992 1.25L5.83325 4.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 8.74967L4.16667 5.83301\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M3.75 8.75H1.25V6.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n\n <div *ngIf=\"isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Exit full screen\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M8.75 6.25H6.25V8.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.25008 6.25L9.16675 9.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M0.833252 0.833008L3.74992 3.74967\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 3.75H3.75V1.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n <div class=\"cqa-w-full cqa-bg-[#F3F4F6] cqa-h-[calc(100%-41px)]\">\n <!-- Live Content View -->\n <div *ngIf=\"isLive\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center cqa-relative\">\n <ng-container *ngIf=\"hasDeviceFrame;\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-max-h-full cqa-h-full': platformType !== 'browser' || !isLive, 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-z-20': platformType === 'browser', 'cqa-bg-white': platformType !== 'browser'}\">\n <!-- Loading State -->\n <div *ngIf=\"isContentVideoLoading\" class=\"cqa-p-10 cqa-text-center cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <div class=\"cqa-mb-4\">\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"40\"></mat-progress-spinner>\n </div>\n <p class=\"cqa-text-gray-400 cqa-text-sm\">{{ liveLoadingLabel }}</p>\n </div>\n\n <!-- Live Content (when not loading) -->\n <div *ngIf=\"!isContentVideoLoading\" class=\"cqa-w-full cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-relative\">\n <div *ngIf=\"liveStatus === 'Failed' && failedStatusMessage\" class=\"cqa-p-6 cqa-text-center cqa-w-full\">\n <div class=\"cqa-inline-flex cqa-items-center cqa-gap-2 cqa-px-4 cqa-py-3 cqa-bg-[#FCD9D9] cqa-border cqa-border-[#F9BFBF] cqa-rounded-lg\">\n <mat-icon style=\"width: 18px; height: 18px; color: #C63535; font-size: 18px;\">error</mat-icon>\n <p class=\"cqa-text-[#C63535] cqa-text-sm cqa-font-medium cqa-m-0\">{{ failedStatusMessage }}</p>\n </div>\n </div>\n <ng-content *ngIf=\"liveStatus !== 'Failed' || !failedStatusMessage\"></ng-content>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Normal Video View (when not live) -->\n <div *ngIf=\"!isLive && currentView === 'video'\" class=\"cqa-h-full cqa-flex cqa-flex-col\">\n <div class=\"cqa-w-full cqa-py-4 cqa-flex cqa-items-center cqa-max-h-[calc(100%-83px)]\" *ngIf=\"currentVideoUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device', 'cqa-mt-auto': hasDeviceFrame}\">\n <ng-container *ngIf=\"hasDeviceFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-p-4': platformType === 'browser'}\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <video\n #vplayer\n class=\"cqa-object-cover cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n [src]=\"currentVideoUrl\"\n type=\"video/webm\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n (loadedmetadata)=\"onVideoMetadataLoaded()\"\n (canplay)=\"onVideoCanPlay()\"\n (ended)=\"onVideoEnded()\"\n ></video>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!currentVideoUrl\">\n <ng-container *ngIf=\"isVNCSessionIntruppted && vncSessionIntupptedMessage; else noVideoDefault\">\n <p class=\"cqa-text-sm cqa-text-gray-600\">\n {{ vncSessionIntupptedMessage }}\n </p>\n </ng-container>\n <ng-template #noVideoDefault>\n <span>No video recording found</span>\n </ng-template>\n </div>\n \n <div class=\"cqa-px-2 cqa-py-2 cqa-bg-white\" style=\"border-top: 1px solid #E5E7EB;\" [ngClass]=\"{'cqa-mt-auto': hasDeviceFrame}\" *ngIf=\"currentVideoUrl && !isLive\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex cqa-items-center cqa-justify-center\" style=\"width: 16px; height: 16px;\">\n <mat-progress-spinner\n *ngIf=\"isPlayerSwitching\"\n mode=\"indeterminate\"\n diameter=\"16\"\n class=\"cqa-inline-block\">\n </mat-progress-spinner>\n <button \n *ngIf=\"!isPlayerSwitching\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n (click)=\"togglePlay()\"\n matTooltip=\"{{ isPlaying ? 'Pause' : 'Play' }}\"\n matTooltipPosition=\"above\">\n <span *ngIf=\"!isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M3 2L13 8L3 14V2Z\" fill=\"#374151\"/>\n </svg>\n </span>\n <span *ngIf=\"isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"3\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n <rect x=\"10\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n </svg>\n </span>\n </button>\n </div>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none\">\n {{ formatTime(globalCurrentTime / 1000) }}\n </span>\n\n <div #speedControlContainer class=\"cqa-relative cqa-mr-[8px] cqa-flex cqa-items-center cqa-justify-center\">\n <button\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer cqa-text-[#9CA3AF] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-whitespace-nowrap cqa-select-none hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none cqa-px-1\"\n (click)=\"toggleSpeedControl()\"\n [matTooltip]=\"'Playback Speed'\"\n [matTooltipPosition]=\"'below'\">\n {{ currentSpeed }}\n </button>\n \n <div \n *ngIf=\"isSpeedControlOpen\"\n class=\"cqa-absolute cqa-bottom-full cqa-mb-2 cqa-right-0 cqa-bg-[#F0F0F1] cqa-rounded-lg cqa-overflow-hidden cqa-shadow-lg cqa-z-50\"\n style=\"min-width: max-content; left: 50%; bottom: 0%; transform: translate(-50%, -50%);\">\n <cqa-segment-control\n [segments]=\"speedSegments\"\n [value]=\"currentSpeed\"\n [containerBgColor]=\"'#F0F0F1'\"\n (valueChange)=\"onSpeedChange($event)\">\n </cqa-segment-control>\n </div>\n </div>\n \n <div \n #timelineBar\n class=\"cqa-relative cqa-h-1 cqa-bg-gray-200 cqa-rounded-full cqa-cursor-pointer cqa-flex-1\"\n (click)=\"onTimelineClick($event)\">\n \n <div \n *ngFor=\"let marker of globalStepMarkers\" \n class=\"cqa-absolute cqa-rounded-full\"\n [style.left.%]=\"totalDuration > 0 ? (marker.globalTime / totalDuration) * 100 : 0\"\n [style.width]=\"'8px'\"\n [style.height]=\"'8px'\"\n [style.background]=\"getGlobalMarkerColor(marker.level)\"\n [style.border]=\"'2px solid ' + getGlobalMarkerResultColor(marker.result)\"\n [style.box-sizing]=\"'border-box'\"\n [attr.title]=\"marker.title || ''\"\n style=\"pointer-events: auto; z-index: 50; cursor: pointer; transform: translate(-50%, -50%); top: 50%;\"\n (click)=\"onMarkerClick($event, marker)\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-h-full cqa-bg-blue-500 cqa-rounded-full\"\n [style.width.%]=\"progress\"\n [style.transition]=\"dragging ? 'none' : 'width 100ms'\"\n style=\"pointer-events: none; z-index: 2;\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-top-1/2 cqa-w-3 cqa-h-3 cqa-bg-blue-600 cqa-rounded-full cqa-cursor-grab active:cqa-cursor-grabbing cqa-shadow-md\"\n [style.left.%]=\"progress\"\n style=\"transform: translate(-50%, -50%); z-index: 60;\"\n (mousedown)=\"startDrag($event)\">\n </div>\n </div>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none\">\n {{ formatTime(totalDuration / 1000) }}\n </span>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'screenshots'\" class=\"cqa-h-full\">\n <div class=\"cqa-w-full cqa-py-4 cqa-h-full cqa-flex cqa-items-center\" *ngIf=\"screenShotUrl\">\n <ng-container *ngIf=\"hasDeviceFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-p-4': platformType === 'browser'}\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n [ngClass]=\"{'cqa-max-h-[inherit]': platformType === 'browser', 'cqa-max-h-full': platformType !== 'browser'}\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <img\n [src]=\"screenShotUrl\"\n alt=\"Screenshot\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n class=\"cqa-object-contain cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n />\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!screenShotUrl\">\n No screenshot available\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'trace'\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-relative\" *ngIf=\"traceViewUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device'}\" style=\"padding-top: 48px; padding-bottom: 0px;\">\n <div class=\"cqa-w-full cqa-h-full cqa-overflow-hidden cqa-relative\">\n <iframe \n [src]=\"safeTraceUrl\" \n title=\"Trace Viewer\"\n class=\"cqa-object-contain cqa-w-full cqa-min-h-[250px] cqa-max-h-full cqa-block cqa-bg-[##F2F2F2]\"\n style=\"margin-top: -48px; height: calc(100% + 48px);\"\n frameborder=\"0\"\n allowfullscreen\n width=\"100%\"\n loading=\"lazy\"\n (load)=\"onTraceViewerLoad()\"\n (error)=\"onTraceViewerError()\">\n </iframe>\n </div>\n \n <div *ngIf=\"traceViewerLoading\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Loading trace viewer...\n </div>\n </div>\n \n <div *ngIf=\"traceViewerError\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Failed to load trace viewer\n </div>\n </div>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!traceViewUrl\">\n No trace available\n </div>\n </div> \n </div>\n</div>", components: [{ type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i3.SegmentControlComponent, selector: "cqa-segment-control", inputs: ["segments", "value", "disabled", "containerBgColor"], outputs: ["valueChange"] }, { type: i4.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "diameter", "strokeWidth", "mode", "value"], exportAs: ["matProgressSpinner"] }], directives: [{ type: i5.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
|
|
599
1734
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SimulatorComponent, decorators: [{
|
|
600
1735
|
type: Component,
|
|
601
|
-
args: [{ selector: 'cqa-simulator', template: "<div class=\"cqa-ui-root\" style=\"background-color: #F3F4F6; height: 100%; display: flex; flex-direction: column;\" [ngStyle]=\"{\n position: isFullScreen ? 'fixed' : null,\n inset: isFullScreen ? '1rem' : null,\n zIndex: isFullScreen ? '50' : null,\n boxShadow: isFullScreen ? '0px 13px 25px -12px rgba(0, 0, 0, 0.25)' : null,\n borderRadius: isFullScreen ? '.5rem' : null,\n border: isFullScreen ? '1px solid #E5E7EB' : null,\n width: isFullScreen ? 'calc(100% - 32px)' : null,\n height: isFullScreen ? 'calc(100% - 32px)' : '100%',\n overflow: isFullScreen ? 'hidden' : null\n}\">\n <div class=\"cqa-w-full cqa-py-1 cqa-px-2 cqa-bg-[#FFFFFF]\" style=\"border-bottom: 1px solid #E5E7EB;box-shadow: 0px 1px 2px 0px #0000000D;\">\n <div class=\"cqa-w-full cqa-flex cqa-items-center cqa-justify-between cqa-flex-wrap\">\n <div class=\"cqa-flex cqa-items-center\">\n <div *ngIf=\"isLive\" class=\"cqa-h-[21px] cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-mr-2 cqa-px-[9px] cqa-py-[3px] cqa-bg-[#FCD9D9] cqa-rounded-[6px]\" style=\"border: 1px solid #F9BFBF;\">\n <span class=\"cqa-relative cqa-w-2 cqa-h-2 cqa-rounded-full cqa-bg-[#F47F7F]\" style=\"flex-shrink: 0;\">\n <span class=\"cqa-absolute cqa-inset-0 cqa-rounded-full cqa-bg-[#F47F7F] cqa-opacity-75 cqa-animate-ping\"></span>\n </span>\n <span class=\"cqa-text-[10px] cqa-font-medium cqa-text-[#C63535] cqa-leading-[15px]\">Live</span>\n </div>\n <mat-icon *ngIf=\"platformType === 'browser'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <g clip-path=\"url(#clip0_935_15847)\">\n <path\n d=\"M0.625 5C0.625 6.16032 1.08594 7.27312 1.90641 8.09359C2.72688 8.91406 3.83968 9.375 5 9.375C6.16032 9.375 7.27312 8.91406 8.09359 8.09359C8.91406 7.27312 9.375 6.16032 9.375 5C9.375 3.83968 8.91406 2.72688 8.09359 1.90641C7.27312 1.08594 6.16032 0.625 5 0.625C3.83968 0.625 2.72688 1.08594 1.90641 1.90641C1.08594 2.72688 0.625 3.83968 0.625 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path\n d=\"M3.125 5C3.125 3.83968 3.32254 2.72688 3.67417 1.90641C4.02581 1.08594 4.50272 0.625 5 0.625C5.49728 0.625 5.97419 1.08594 6.32582 1.90641C6.67746 2.72688 6.875 3.83968 6.875 5C6.875 6.16032 6.67746 7.27312 6.32582 8.09359C5.97419 8.91406 5.49728 9.375 5 9.375C4.50272 9.375 4.02581 8.91406 3.67417 8.09359C3.32254 7.27312 3.125 6.16032 3.125 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path d=\"M0.9375 6.45866H9.0625M0.9375 3.54199H9.0625\" stroke=\"#9CA3AF\" stroke-width=\"0.6\"\n stroke-linecap=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_935_15847\">\n <rect width=\"10\" height=\"10\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </mat-icon>\n <mat-icon *ngIf=\"platformType === 'device'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M7.08325 0.833008H2.91659C2.45635 0.833008 2.08325 1.2061 2.08325 1.66634V8.33301C2.08325 8.79324 2.45635 9.16634 2.91659 9.16634H7.08325C7.54349 9.16634 7.91658 8.79324 7.91658 8.33301V1.66634C7.91658 1.2061 7.54349 0.833008 7.08325 0.833008Z\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5 7.5H5.00417\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <p class=\"cqa-text-sm !cqa-text-[10px] cqa-text-[#6B7280] cqa-ml-2\">\n {{ platformName }}\n <span\n *ngIf=\"platformType === 'browser'\"\n class=\"cqa-ml-1\"\n [matTooltip]=\"'Screen size: ' + effectiveBrowserViewPort.width + 'x' + effectiveBrowserViewPort.height\"\n matTooltipPosition=\"below\"\n >\n \u00B7\n <span class=\"cqa-ml-1\">\n {{ effectiveBrowserViewPort.width }}x{{ effectiveBrowserViewPort.height }}\n </span>\n </span>\n </p>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div *ngIf=\"isLive\" [ngClass]=\"getStatusBadgeClass()\">\n <span [ngClass]=\"getStatusTextClass()\">{{ liveStatus }}</span>\n </div>\n\n <ng-container *ngIf=\"!isLive\">\n <cqa-segment-control \n [segments]=\"segments\" \n [value]=\"currentView\"\n (valueChange)=\"onSegmentChange($event)\">\n </cqa-segment-control>\n \n <div *ngIf=\"!isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Expand\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M6.25 1.25H8.75V3.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.74992 1.25L5.83325 4.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 8.74967L4.16667 5.83301\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M3.75 8.75H1.25V6.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n\n <div *ngIf=\"isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Exit full screen\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M8.75 6.25H6.25V8.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.25008 6.25L9.16675 9.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M0.833252 0.833008L3.74992 3.74967\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 3.75H3.75V1.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n <div class=\"cqa-w-full cqa-bg-[#F3F4F6] cqa-h-[calc(100%-41px)]\">\n <!-- Live Content View -->\n <div *ngIf=\"isLive\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center cqa-relative\">\n <ng-container *ngIf=\"hasDeviceFrame;\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-max-h-full cqa-h-full': platformType !== 'browser' || !isLive, 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-z-20': platformType === 'browser', 'cqa-bg-white': platformType !== 'browser'}\">\n <!-- Loading State -->\n <div *ngIf=\"isContentVideoLoading\" class=\"cqa-p-10 cqa-text-center cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <div class=\"cqa-mb-4\">\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"40\"></mat-progress-spinner>\n </div>\n <p class=\"cqa-text-gray-400 cqa-text-sm\">{{ liveLoadingLabel }}</p>\n </div>\n\n <!-- Live Content (when not loading) -->\n <div *ngIf=\"!isContentVideoLoading\" class=\"cqa-w-full cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-relative\">\n <div *ngIf=\"liveStatus === 'Failed' && failedStatusMessage\" class=\"cqa-p-6 cqa-text-center cqa-w-full\">\n <div class=\"cqa-inline-flex cqa-items-center cqa-gap-2 cqa-px-4 cqa-py-3 cqa-bg-[#FCD9D9] cqa-border cqa-border-[#F9BFBF] cqa-rounded-lg\">\n <mat-icon style=\"width: 18px; height: 18px; color: #C63535; font-size: 18px;\">error</mat-icon>\n <p class=\"cqa-text-[#C63535] cqa-text-sm cqa-font-medium cqa-m-0\">{{ failedStatusMessage }}</p>\n </div>\n </div>\n <ng-content *ngIf=\"liveStatus !== 'Failed' || !failedStatusMessage\"></ng-content>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Normal Video View (when not live) -->\n <div *ngIf=\"!isLive && currentView === 'video'\" class=\"cqa-h-full cqa-flex cqa-flex-col\">\n <div class=\"cqa-w-full cqa-py-4 cqa-flex cqa-items-center cqa-max-h-[calc(100%-83px)]\" *ngIf=\"currentVideoUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device', 'cqa-mt-auto': hasDeviceFrame}\">\n <ng-container *ngIf=\"hasDeviceFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-p-4': platformType === 'browser'}\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <video\n #vplayer\n class=\"cqa-object-cover cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n [src]=\"currentVideoUrl\"\n type=\"video/webm\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n (loadedmetadata)=\"onVideoMetadataLoaded()\"\n (canplay)=\"onVideoCanPlay()\"\n (ended)=\"onVideoEnded()\"\n ></video>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!currentVideoUrl\">\n <ng-container *ngIf=\"isVNCSessionIntruppted && vncSessionIntupptedMessage; else noVideoDefault\">\n <p class=\"cqa-text-sm cqa-text-gray-600\">\n {{ vncSessionIntupptedMessage }}\n </p>\n </ng-container>\n <ng-template #noVideoDefault>\n <span>No video recording found</span>\n </ng-template>\n </div>\n \n <div class=\"cqa-px-2 cqa-py-2 cqa-bg-white\" style=\"border-top: 1px solid #E5E7EB;\" [ngClass]=\"{'cqa-mt-auto': hasDeviceFrame}\" *ngIf=\"currentVideoUrl && !isLive\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <button \n *ngIf=\"hasMultipleVideos\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n [disabled]=\"currentVideoIndex === 0\"\n [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': currentVideoIndex === 0}\"\n (click)=\"prevVideo()\"\n matTooltip=\"Previous video\"\n matTooltipPosition=\"above\">\n <mat-icon class=\"cqa-w-4 cqa-h-4 !cqa-text-[16px] cqa-text-[#374151]\" [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': currentVideoIndex === 0}\">skip_previous</mat-icon>\n </button>\n\n <button \n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n (click)=\"togglePlay()\"\n matTooltip=\"{{ isPlaying ? 'Pause' : 'Play' }}\"\n matTooltipPosition=\"above\">\n <span *ngIf=\"!isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M3 2L13 8L3 14V2Z\" fill=\"#374151\"/>\n </svg>\n </span>\n <span *ngIf=\"isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"3\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n <rect x=\"10\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n </svg>\n </span>\n </button>\n \n <button \n *ngIf=\"hasMultipleVideos\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n [disabled]=\"videoUrls && (currentVideoIndex >= videoUrls.length - 1)\"\n [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': videoUrls && (currentVideoIndex >= videoUrls.length - 1)}\"\n (click)=\"nextVideo()\"\n matTooltip=\"Next video\"\n matTooltipPosition=\"above\">\n <mat-icon class=\"cqa-w-4 cqa-h-4 !cqa-text-[16px] cqa-text-[#374151]\" [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': videoUrls && (currentVideoIndex >= videoUrls.length - 1)}\">skip_next</mat-icon>\n </button>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none\">\n {{ formatTime(vplayer?.nativeElement?.currentTime || 0) }}\n </span>\n\n <div #speedControlContainer class=\"cqa-relative cqa-mr-[8px] cqa-flex cqa-items-center cqa-justify-center\">\n <button\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer cqa-text-[#9CA3AF] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-whitespace-nowrap cqa-select-none hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none cqa-px-1\"\n (click)=\"toggleSpeedControl()\"\n [matTooltip]=\"'Playback Speed'\"\n [matTooltipPosition]=\"'below'\">\n {{ currentSpeed }}\n </button>\n \n <div \n *ngIf=\"isSpeedControlOpen\"\n class=\"cqa-absolute cqa-bottom-full cqa-mb-2 cqa-right-0 cqa-bg-[#F0F0F1] cqa-rounded-lg cqa-overflow-hidden cqa-shadow-lg cqa-z-50\"\n style=\"min-width: max-content; left: 50%; bottom: 0%; transform: translate(-50%, -50%);\">\n <cqa-segment-control\n [segments]=\"speedSegments\"\n [value]=\"currentSpeed\"\n [containerBgColor]=\"'#F0F0F1'\"\n (valueChange)=\"onSpeedChange($event)\">\n </cqa-segment-control>\n </div>\n </div>\n \n <div \n #timelineBar\n class=\"cqa-relative cqa-h-1 cqa-bg-gray-200 cqa-rounded-full cqa-cursor-pointer cqa-flex-1\"\n (click)=\"onTimelineClick($event)\">\n \n <div \n *ngFor=\"let step of stepMarkers\" \n class=\"cqa-absolute cqa-w-1 cqa-h-full cqa-top-0 cqa-rounded-sm\"\n [style.left.%]=\"getStepLeftPosition(step)\"\n [style.background]=\"getStepColor(step)\"\n style=\"pointer-events: none; z-index: 20;\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-h-full cqa-bg-blue-500 cqa-rounded-full\"\n [style.width.%]=\"progress\"\n [style.transition]=\"dragging ? 'none' : 'width 100ms'\"\n style=\"pointer-events: none; z-index: 2;\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-top-1/2 cqa-w-3 cqa-h-3 cqa-bg-blue-600 cqa-rounded-full cqa-cursor-grab active:cqa-cursor-grabbing cqa-shadow-md\"\n [style.left.%]=\"progress\"\n style=\"transform: translate(-50%, -50%); z-index: 40;\"\n (mousedown)=\"startDrag($event)\">\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'screenshots'\" class=\"cqa-h-full\">\n <div class=\"cqa-w-full cqa-py-4 cqa-h-full cqa-flex cqa-items-center\" *ngIf=\"screenShotUrl\">\n <ng-container *ngIf=\"hasDeviceFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-p-4': platformType === 'browser'}\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n [ngClass]=\"{'cqa-max-h-[inherit]': platformType === 'browser', 'cqa-max-h-full': platformType !== 'browser'}\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <img\n [src]=\"screenShotUrl\"\n alt=\"Screenshot\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n class=\"cqa-object-contain cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n />\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!screenShotUrl\">\n No screenshot available\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'trace'\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-relative\" *ngIf=\"traceViewUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device'}\" style=\"padding-top: 48px; padding-bottom: 0px;\">\n <div class=\"cqa-w-full cqa-h-full cqa-overflow-hidden cqa-relative\">\n <iframe \n [src]=\"safeTraceUrl\" \n title=\"Trace Viewer\"\n class=\"cqa-object-contain cqa-w-full cqa-min-h-[250px] cqa-max-h-full cqa-block cqa-bg-[##F2F2F2]\"\n style=\"margin-top: -48px; height: calc(100% + 48px);\"\n frameborder=\"0\"\n allowfullscreen\n width=\"100%\"\n loading=\"lazy\"\n (load)=\"onTraceViewerLoad()\"\n (error)=\"onTraceViewerError()\">\n </iframe>\n </div>\n \n <div *ngIf=\"traceViewerLoading\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Loading trace viewer...\n </div>\n </div>\n \n <div *ngIf=\"traceViewerError\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Failed to load trace viewer\n </div>\n </div>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!traceViewUrl\">\n No trace available\n </div>\n </div> \n </div>\n</div>", styles: [] }]
|
|
1736
|
+
args: [{ selector: 'cqa-simulator', template: "<div class=\"cqa-ui-root\" style=\"background-color: #F3F4F6; height: 100%; display: flex; flex-direction: column;\" [ngStyle]=\"{\n position: isFullScreen ? 'fixed' : null,\n inset: isFullScreen ? '1rem' : null,\n zIndex: isFullScreen ? '50' : null,\n boxShadow: isFullScreen ? '0px 13px 25px -12px rgba(0, 0, 0, 0.25)' : null,\n borderRadius: isFullScreen ? '.5rem' : null,\n border: isFullScreen ? '1px solid #E5E7EB' : null,\n width: isFullScreen ? 'calc(100% - 32px)' : null,\n height: isFullScreen ? 'calc(100% - 32px)' : '100%',\n overflow: isFullScreen ? 'hidden' : null\n}\">\n <div class=\"cqa-w-full cqa-py-1 cqa-px-2 cqa-bg-[#FFFFFF]\" style=\"border-bottom: 1px solid #E5E7EB;box-shadow: 0px 1px 2px 0px #0000000D;\">\n <div class=\"cqa-w-full cqa-flex cqa-items-center cqa-justify-between cqa-flex-wrap\">\n <div class=\"cqa-flex cqa-items-center\">\n <div *ngIf=\"isLive\" class=\"cqa-h-[21px] cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-mr-2 cqa-px-[9px] cqa-py-[3px] cqa-bg-[#FCD9D9] cqa-rounded-[6px]\" style=\"border: 1px solid #F9BFBF;\">\n <span class=\"cqa-relative cqa-w-2 cqa-h-2 cqa-rounded-full cqa-bg-[#F47F7F]\" style=\"flex-shrink: 0;\">\n <span class=\"cqa-absolute cqa-inset-0 cqa-rounded-full cqa-bg-[#F47F7F] cqa-opacity-75 cqa-animate-ping\"></span>\n </span>\n <span class=\"cqa-text-[10px] cqa-font-medium cqa-text-[#C63535] cqa-leading-[15px]\">Live</span>\n </div>\n <mat-icon *ngIf=\"platformType === 'browser'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <g clip-path=\"url(#clip0_935_15847)\">\n <path\n d=\"M0.625 5C0.625 6.16032 1.08594 7.27312 1.90641 8.09359C2.72688 8.91406 3.83968 9.375 5 9.375C6.16032 9.375 7.27312 8.91406 8.09359 8.09359C8.91406 7.27312 9.375 6.16032 9.375 5C9.375 3.83968 8.91406 2.72688 8.09359 1.90641C7.27312 1.08594 6.16032 0.625 5 0.625C3.83968 0.625 2.72688 1.08594 1.90641 1.90641C1.08594 2.72688 0.625 3.83968 0.625 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path\n d=\"M3.125 5C3.125 3.83968 3.32254 2.72688 3.67417 1.90641C4.02581 1.08594 4.50272 0.625 5 0.625C5.49728 0.625 5.97419 1.08594 6.32582 1.90641C6.67746 2.72688 6.875 3.83968 6.875 5C6.875 6.16032 6.67746 7.27312 6.32582 8.09359C5.97419 8.91406 5.49728 9.375 5 9.375C4.50272 9.375 4.02581 8.91406 3.67417 8.09359C3.32254 7.27312 3.125 6.16032 3.125 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path d=\"M0.9375 6.45866H9.0625M0.9375 3.54199H9.0625\" stroke=\"#9CA3AF\" stroke-width=\"0.6\"\n stroke-linecap=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_935_15847\">\n <rect width=\"10\" height=\"10\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </mat-icon>\n <mat-icon *ngIf=\"platformType === 'device'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M7.08325 0.833008H2.91659C2.45635 0.833008 2.08325 1.2061 2.08325 1.66634V8.33301C2.08325 8.79324 2.45635 9.16634 2.91659 9.16634H7.08325C7.54349 9.16634 7.91658 8.79324 7.91658 8.33301V1.66634C7.91658 1.2061 7.54349 0.833008 7.08325 0.833008Z\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5 7.5H5.00417\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <p class=\"cqa-text-sm !cqa-text-[10px] cqa-text-[#6B7280] cqa-ml-2\">\n {{ platformName }}\n <span\n *ngIf=\"platformType === 'browser'\"\n class=\"cqa-ml-1\"\n [matTooltip]=\"'Screen size: ' + effectiveBrowserViewPort.width + 'x' + effectiveBrowserViewPort.height\"\n matTooltipPosition=\"below\"\n >\n \u00B7\n <span class=\"cqa-ml-1\">\n {{ effectiveBrowserViewPort.width }}x{{ effectiveBrowserViewPort.height }}\n </span>\n </span>\n </p>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div *ngIf=\"isLive\" [ngClass]=\"getStatusBadgeClass()\">\n <span [ngClass]=\"getStatusTextClass()\">{{ liveStatus }}</span>\n </div>\n\n <ng-container *ngIf=\"!isLive\">\n <cqa-segment-control \n [segments]=\"segments\" \n [value]=\"currentView\"\n (valueChange)=\"onSegmentChange($event)\">\n </cqa-segment-control>\n \n <div *ngIf=\"!isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Expand\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M6.25 1.25H8.75V3.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.74992 1.25L5.83325 4.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 8.74967L4.16667 5.83301\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M3.75 8.75H1.25V6.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n\n <div *ngIf=\"isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Exit full screen\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M8.75 6.25H6.25V8.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.25008 6.25L9.16675 9.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M0.833252 0.833008L3.74992 3.74967\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 3.75H3.75V1.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n <div class=\"cqa-w-full cqa-bg-[#F3F4F6] cqa-h-[calc(100%-41px)]\">\n <!-- Live Content View -->\n <div *ngIf=\"isLive\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center cqa-relative\">\n <ng-container *ngIf=\"hasDeviceFrame;\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-max-h-full cqa-h-full': platformType !== 'browser' || !isLive, 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-z-20': platformType === 'browser', 'cqa-bg-white': platformType !== 'browser'}\">\n <!-- Loading State -->\n <div *ngIf=\"isContentVideoLoading\" class=\"cqa-p-10 cqa-text-center cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <div class=\"cqa-mb-4\">\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"40\"></mat-progress-spinner>\n </div>\n <p class=\"cqa-text-gray-400 cqa-text-sm\">{{ liveLoadingLabel }}</p>\n </div>\n\n <!-- Live Content (when not loading) -->\n <div *ngIf=\"!isContentVideoLoading\" class=\"cqa-w-full cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-relative\">\n <div *ngIf=\"liveStatus === 'Failed' && failedStatusMessage\" class=\"cqa-p-6 cqa-text-center cqa-w-full\">\n <div class=\"cqa-inline-flex cqa-items-center cqa-gap-2 cqa-px-4 cqa-py-3 cqa-bg-[#FCD9D9] cqa-border cqa-border-[#F9BFBF] cqa-rounded-lg\">\n <mat-icon style=\"width: 18px; height: 18px; color: #C63535; font-size: 18px;\">error</mat-icon>\n <p class=\"cqa-text-[#C63535] cqa-text-sm cqa-font-medium cqa-m-0\">{{ failedStatusMessage }}</p>\n </div>\n </div>\n <ng-content *ngIf=\"liveStatus !== 'Failed' || !failedStatusMessage\"></ng-content>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Normal Video View (when not live) -->\n <div *ngIf=\"!isLive && currentView === 'video'\" class=\"cqa-h-full cqa-flex cqa-flex-col\">\n <div class=\"cqa-w-full cqa-py-4 cqa-flex cqa-items-center cqa-max-h-[calc(100%-83px)]\" *ngIf=\"currentVideoUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device', 'cqa-mt-auto': hasDeviceFrame}\">\n <ng-container *ngIf=\"hasDeviceFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-p-4': platformType === 'browser'}\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <video\n #vplayer\n class=\"cqa-object-cover cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n [src]=\"currentVideoUrl\"\n type=\"video/webm\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n (loadedmetadata)=\"onVideoMetadataLoaded()\"\n (canplay)=\"onVideoCanPlay()\"\n (ended)=\"onVideoEnded()\"\n ></video>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!currentVideoUrl\">\n <ng-container *ngIf=\"isVNCSessionIntruppted && vncSessionIntupptedMessage; else noVideoDefault\">\n <p class=\"cqa-text-sm cqa-text-gray-600\">\n {{ vncSessionIntupptedMessage }}\n </p>\n </ng-container>\n <ng-template #noVideoDefault>\n <span>No video recording found</span>\n </ng-template>\n </div>\n \n <div class=\"cqa-px-2 cqa-py-2 cqa-bg-white\" style=\"border-top: 1px solid #E5E7EB;\" [ngClass]=\"{'cqa-mt-auto': hasDeviceFrame}\" *ngIf=\"currentVideoUrl && !isLive\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex cqa-items-center cqa-justify-center\" style=\"width: 16px; height: 16px;\">\n <mat-progress-spinner\n *ngIf=\"isPlayerSwitching\"\n mode=\"indeterminate\"\n diameter=\"16\"\n class=\"cqa-inline-block\">\n </mat-progress-spinner>\n <button \n *ngIf=\"!isPlayerSwitching\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n (click)=\"togglePlay()\"\n matTooltip=\"{{ isPlaying ? 'Pause' : 'Play' }}\"\n matTooltipPosition=\"above\">\n <span *ngIf=\"!isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M3 2L13 8L3 14V2Z\" fill=\"#374151\"/>\n </svg>\n </span>\n <span *ngIf=\"isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"3\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n <rect x=\"10\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n </svg>\n </span>\n </button>\n </div>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none\">\n {{ formatTime(globalCurrentTime / 1000) }}\n </span>\n\n <div #speedControlContainer class=\"cqa-relative cqa-mr-[8px] cqa-flex cqa-items-center cqa-justify-center\">\n <button\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer cqa-text-[#9CA3AF] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-whitespace-nowrap cqa-select-none hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none cqa-px-1\"\n (click)=\"toggleSpeedControl()\"\n [matTooltip]=\"'Playback Speed'\"\n [matTooltipPosition]=\"'below'\">\n {{ currentSpeed }}\n </button>\n \n <div \n *ngIf=\"isSpeedControlOpen\"\n class=\"cqa-absolute cqa-bottom-full cqa-mb-2 cqa-right-0 cqa-bg-[#F0F0F1] cqa-rounded-lg cqa-overflow-hidden cqa-shadow-lg cqa-z-50\"\n style=\"min-width: max-content; left: 50%; bottom: 0%; transform: translate(-50%, -50%);\">\n <cqa-segment-control\n [segments]=\"speedSegments\"\n [value]=\"currentSpeed\"\n [containerBgColor]=\"'#F0F0F1'\"\n (valueChange)=\"onSpeedChange($event)\">\n </cqa-segment-control>\n </div>\n </div>\n \n <div \n #timelineBar\n class=\"cqa-relative cqa-h-1 cqa-bg-gray-200 cqa-rounded-full cqa-cursor-pointer cqa-flex-1\"\n (click)=\"onTimelineClick($event)\">\n \n <div \n *ngFor=\"let marker of globalStepMarkers\" \n class=\"cqa-absolute cqa-rounded-full\"\n [style.left.%]=\"totalDuration > 0 ? (marker.globalTime / totalDuration) * 100 : 0\"\n [style.width]=\"'8px'\"\n [style.height]=\"'8px'\"\n [style.background]=\"getGlobalMarkerColor(marker.level)\"\n [style.border]=\"'2px solid ' + getGlobalMarkerResultColor(marker.result)\"\n [style.box-sizing]=\"'border-box'\"\n [attr.title]=\"marker.title || ''\"\n style=\"pointer-events: auto; z-index: 50; cursor: pointer; transform: translate(-50%, -50%); top: 50%;\"\n (click)=\"onMarkerClick($event, marker)\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-h-full cqa-bg-blue-500 cqa-rounded-full\"\n [style.width.%]=\"progress\"\n [style.transition]=\"dragging ? 'none' : 'width 100ms'\"\n style=\"pointer-events: none; z-index: 2;\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-top-1/2 cqa-w-3 cqa-h-3 cqa-bg-blue-600 cqa-rounded-full cqa-cursor-grab active:cqa-cursor-grabbing cqa-shadow-md\"\n [style.left.%]=\"progress\"\n style=\"transform: translate(-50%, -50%); z-index: 60;\"\n (mousedown)=\"startDrag($event)\">\n </div>\n </div>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none\">\n {{ formatTime(totalDuration / 1000) }}\n </span>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'screenshots'\" class=\"cqa-h-full\">\n <div class=\"cqa-w-full cqa-py-4 cqa-h-full cqa-flex cqa-items-center\" *ngIf=\"screenShotUrl\">\n <ng-container *ngIf=\"hasDeviceFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-p-4': platformType === 'browser'}\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n [ngClass]=\"{'cqa-max-h-[inherit]': platformType === 'browser', 'cqa-max-h-full': platformType !== 'browser'}\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <img\n [src]=\"screenShotUrl\"\n alt=\"Screenshot\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n class=\"cqa-object-contain cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n />\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!screenShotUrl\">\n No screenshot available\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'trace'\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-relative\" *ngIf=\"traceViewUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device'}\" style=\"padding-top: 48px; padding-bottom: 0px;\">\n <div class=\"cqa-w-full cqa-h-full cqa-overflow-hidden cqa-relative\">\n <iframe \n [src]=\"safeTraceUrl\" \n title=\"Trace Viewer\"\n class=\"cqa-object-contain cqa-w-full cqa-min-h-[250px] cqa-max-h-full cqa-block cqa-bg-[##F2F2F2]\"\n style=\"margin-top: -48px; height: calc(100% + 48px);\"\n frameborder=\"0\"\n allowfullscreen\n width=\"100%\"\n loading=\"lazy\"\n (load)=\"onTraceViewerLoad()\"\n (error)=\"onTraceViewerError()\">\n </iframe>\n </div>\n \n <div *ngIf=\"traceViewerLoading\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Loading trace viewer...\n </div>\n </div>\n \n <div *ngIf=\"traceViewerError\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Failed to load trace viewer\n </div>\n </div>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!traceViewUrl\">\n No trace available\n </div>\n </div> \n </div>\n</div>", styles: [] }]
|
|
602
1737
|
}], ctorParameters: function () { return [{ type: i1.DomSanitizer }]; }, propDecorators: { videoUrl: [{
|
|
603
1738
|
type: Input
|
|
604
1739
|
}], videoUrls: [{
|
|
@@ -645,14 +1780,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
645
1780
|
type: Output
|
|
646
1781
|
}], videoPause: [{
|
|
647
1782
|
type: Output
|
|
1783
|
+
}], markerHit: [{
|
|
1784
|
+
type: Output
|
|
1785
|
+
}], isVideoPlayingChange: [{
|
|
1786
|
+
type: Output
|
|
648
1787
|
}], vplayerRef: [{
|
|
649
1788
|
type: ViewChild,
|
|
650
1789
|
args: ['vplayer']
|
|
651
|
-
}],
|
|
1790
|
+
}], timelineBarRef: [{
|
|
652
1791
|
type: ViewChild,
|
|
653
1792
|
args: ['timelineBar', { static: false }]
|
|
654
|
-
}],
|
|
1793
|
+
}], speedControlContainerRef: [{
|
|
655
1794
|
type: ViewChild,
|
|
656
1795
|
args: ['speedControlContainer', { static: false }]
|
|
657
1796
|
}] } });
|
|
658
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2ltdWxhdG9yLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc2ltdWxhdG9yL3NpbXVsYXRvci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NpbXVsYXRvci9zaW11bGF0b3IuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQWtFLE1BQU0sZUFBZSxDQUFDO0FBRWxKLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDhDQUE4QyxDQUFDOzs7Ozs7OztBQStCbkYsTUFBTSxPQUFPLGtCQUFrQjtJQXdNN0IsWUFBb0IsU0FBdUI7UUFBdkIsY0FBUyxHQUFULFNBQVMsQ0FBYztRQXRNbEMsYUFBUSxHQUFXLEVBQUUsQ0FBQztRQUN0QixjQUFTLEdBQWEsRUFBRSxDQUFDO1FBQ3pCLHlCQUFvQixHQUFXLENBQUMsQ0FBQztRQUNqQyxnQkFBVyxHQUFpQixFQUFFLENBQUM7UUFDL0Isa0JBQWEsR0FBVyxFQUFFLENBQUM7UUFDM0IsaUJBQVksR0FBVyxFQUFFLENBQUM7UUFDMUIsaUJBQVksR0FBVyxjQUFjLENBQUM7UUFDdEMsaUJBQVksR0FBeUIsU0FBUyxDQUFDO1FBQy9DLGFBQVEsR0FBVyxFQUFFLENBQUM7UUFDdEIsZUFBVSxHQUFrQixJQUFJLENBQUM7UUFDakMsV0FBTSxHQUFZLEtBQUssQ0FBQztRQUN4QixlQUFVLEdBQTZFLGFBQWEsQ0FBQztRQUNyRyxxQkFBZ0IsR0FBVyxZQUFZLENBQUM7UUFDeEMsMEJBQXFCLEdBQVksS0FBSyxDQUFDO1FBQ3ZDLHdCQUFtQixHQUFXLEVBQUUsQ0FBQztRQUNqQywyQkFBc0IsR0FBWSxLQUFLLENBQUM7UUFDeEMsK0JBQTBCLEdBQVcsRUFBRSxDQUFDO1FBQ3hDLGlCQUFZLEdBQWdCLE9B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c0JBQTlCLEtBQUs7Z0JBQ0csMEJBQTBCO3NCQUFsQyxLQUFLO2dCQUNHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBQ0csWUFBWTtzQkFBcEIsS0FBSztnQkFDRyxlQUFlO3NCQUF2QixLQUFLO2dCQUVJLGVBQWU7c0JBQXhCLE1BQU07Z0JBQ0csU0FBUztzQkFBbEIsTUFBTTtnQkFDRyxVQUFVO3NCQUFuQixNQUFNO2dCQUtILFVBQVU7c0JBRGIsU0FBUzt1QkFBQyxTQUFTO2dCQVl5QixXQUFXO3NCQUF2RCxTQUFTO3VCQUFDLGFBQWEsRUFBRSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUU7Z0JBQ1kscUJBQXFCO3NCQUEzRSxTQUFTO3VCQUFDLHVCQUF1QixFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIE91dHB1dCwgRXZlbnRFbWl0dGVyLCBWaWV3Q2hpbGQsIEVsZW1lbnRSZWYsIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveSwgT25DaGFuZ2VzLCBTaW1wbGVDaGFuZ2VzIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBEb21TYW5pdGl6ZXIsIFNhZmVSZXNvdXJjZVVybCB9IGZyb20gJ0Bhbmd1bGFyL3BsYXRmb3JtLWJyb3dzZXInO1xuaW1wb3J0IHsgZ2V0RW1wdHlTdGF0ZVByZXNldCB9IGZyb20gJy4uL2VtcHR5LXN0YXRlL2VtcHR5LXN0YXRlLXByZXNldHMuY29uc3RhbnRzJztcblxuZXhwb3J0IGludGVyZmFjZSBTdGVwTWFya2VyIHtcbiAgY3VtdWxhdGl2ZUR1cmF0aW9uOiBudW1iZXI7XG4gIHJlc3VsdDogJ1NVQ0NFU1MnIHwgJ0ZBSUxVUkUnO1xufVxuXG5leHBvcnQgdHlwZSBTZWdtZW50VHlwZSA9ICdzY3JlZW5zaG90cycgfCAndmlkZW8nIHwgJ3RyYWNlJztcblxudHlwZSBTZWdtZW50T3B0aW9uID0ge1xuICBsYWJlbDogc3RyaW5nO1xuICB2YWx1ZTogc3RyaW5nO1xuICBpY29uPzogc3RyaW5nO1xufTtcbmludGVyZmFjZSBEZXZpY2VGcmFtZUNvbmZpZyB7XG4gIG1vY2t1cEltYWdlOiBzdHJpbmc7XG4gIHNjcmVlbkluc2V0OiB7XG4gICAgdG9wOiBzdHJpbmc7XG4gICAgcmlnaHQ6IHN0cmluZztcbiAgICBib3R0b206IHN0cmluZztcbiAgICBsZWZ0OiBzdHJpbmc7XG4gIH07XG4gIGJvcmRlclJhZGl1czogc3RyaW5nO1xufVxuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjcWEtc2ltdWxhdG9yJyxcbiAgdGVtcGxhdGVVcmw6ICcuL3NpbXVsYXRvci5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogW11cbn0pXG5cbmV4cG9ydCBjbGFzcyBTaW11bGF0b3JDb21wb25lbnQgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3ksIE9uQ2hhbmdlcyB7XG5cbiAgQElucHV0KCkgdmlkZW9Vcmw6IHN0cmluZyA9ICcnO1xuICBASW5wdXQoKSB2aWRlb1VybHM6IHN0cmluZ1tdID0gW107XG4gIEBJbnB1dCgpIHZpZGVvQ3VycmVudER1cmF0aW9uOiBudW1iZXIgPSAwO1xuICBASW5wdXQoKSBzdGVwTWFya2VyczogU3RlcE1hcmtlcltdID0gW107XG4gIEBJbnB1dCgpIHNjcmVlblNob3RVcmw6IHN0cmluZyA9ICcnO1xuICBASW5wdXQoKSB0cmFjZVZpZXdVcmw6IHN0cmluZyA9ICcnO1xuICBASW5wdXQoKSBwbGF0Zm9ybU5hbWU6IHN0cmluZyA9ICdXZWIgLSBDaHJvbWUnO1xuICBASW5wdXQoKSBwbGF0Zm9ybVR5cGU6ICdicm93c2VyJyB8ICdkZXZpY2UnID0gJ2Jyb3dzZXInO1xuICBASW5wdXQoKSBwbGF0Zm9ybTogc3RyaW5nID0gJyc7XG4gIEBJbnB1dCgpIGRldmljZU5hbWU6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBASW5wdXQoKSBpc0xpdmU6IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgbGl2ZVN0YXR1czogJ0luIFByb2dyZXNzJyB8ICdQYXVzZWQnIHwgJ0Fib3J0ZWQnIHwgJ0ZhaWxlZCcgfCAnUGFzc2VkJyB8ICdFeGVjdXRpb24nID0gJ0luIFByb2dyZXNzJztcbiAgQElucHV0KCkgbGl2ZUxvYWRpbmdMYWJlbDogc3RyaW5nID0gJ0xvYWRpbmcuLi4nO1xuICBASW5wdXQoKSBpc0NvbnRlbnRWaWRlb0xvYWRpbmc6IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgZmFpbGVkU3RhdHVzTWVzc2FnZTogc3RyaW5nID0gJyc7XG4gIEBJbnB1dCgpIGlzVk5DU2Vzc2lvbkludHJ1cHB0ZWQ6IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgdm5jU2Vzc2lvbkludHVwcHRlZE1lc3NhZ2U6IHN0cmluZyA9ICcnO1xuICBASW5wdXQoKSBzZWxlY3RlZFZpZXc6IFNlZ21lbnRUeXBlID0gJ3ZpZGVvJztcbiAgQElucHV0KCkgaGlkZVZpZGVvVGFiOiBib29sZWFuID0gZmFsc2U7XG4gIEBJbnB1dCgpIGJyb3dzZXJWaWV3UG9ydDogeyB3aWR0aDogbnVtYmVyOyBoZWlnaHQ6IG51bWJlciB9IHwgbnVsbCA9IG51bGw7XG5cbiAgQE91dHB1dCgpIHZpZGVvVGltZVVwZGF0ZSA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyPigpO1xuICBAT3V0cHV0KCkgdmlkZW9QbGF5ID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xuICBAT3V0cHV0KCkgdmlkZW9QYXVzZSA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcblxuICBwcml2YXRlIF92cGxheWVyPzogRWxlbWVudFJlZjxIVE1MVmlkZW9FbGVtZW50PjtcblxuICBAVmlld0NoaWxkKCd2cGxheWVyJylcbiAgc2V0IHZwbGF5ZXJSZWYocmVmOiBFbGVtZW50UmVmPEhUTUxWaWRlb0VsZW1lbnQ+IHwgdW5kZWZpbmVkKSB7XG4gICAgaWYgKCFyZWYpIHJldHVybjtcblxuICAgIHRoaXMuX3ZwbGF5ZXIgPSByZWY7XG4gICAgdGhpcy5vblZpZGVvRWxlbWVudFJlYWR5KCk7XG4gIH1cblxuICBnZXQgdnBsYXllcigpOiBFbGVtZW50UmVmPEhUTUxWaWRlb0VsZW1lbnQ+IHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5fdnBsYXllcjtcbiAgfVxuXG4gIEBWaWV3Q2hpbGQoJ3RpbWVsaW5lQmFyJywgeyBzdGF0aWM6IGZhbHNlIH0pIHRpbWVsaW5lQmFyITogRWxlbWVudFJlZjxIVE1MRGl2RWxlbWVudD47XG4gIEBWaWV3Q2hpbGQoJ3NwZWVkQ29udHJvbENvbnRhaW5lcicsIHsgc3RhdGljOiBmYWxzZSB9KSBzcGVlZENvbnRyb2xDb250YWluZXIhOiBFbGVtZW50UmVmPEhUTUxEaXZFbGVtZW50PjtcblxuICBwcm9ncmVzcyA9IDA7XG4gIGRyYWdnaW5nID0gZmFsc2U7XG4gIGlzUGxheWluZzogYm9vbGVhbiA9IGZhbHNlO1xuICBpc0Z1bGxTY3JlZW46IGJvb2xlYW4gPSBmYWxzZTtcbiAgY3VycmVudFZpZXc6IHN0cmluZyA9ICd2aWRlbyc7XG4gIGN1cnJlbnRWaWRlb0luZGV4OiBudW1iZXIgPSAwO1xuICBjdXJyZW50U3BlZWQ6IHN0cmluZyA9ICcxeCc7XG4gIGlzU3BlZWRDb250cm9sT3BlbjogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIGdldCBoYXNEZXZpY2VGcmFtZSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gISF0aGlzLmRldmljZUZyYW1lQ29uZmlnO1xuICB9XG5cbiAgc2VnbWVudHM6IFNlZ21lbnRPcHRpb25bXSA9IFtcbiAgICB7IGxhYmVsOiAnU2NyZWVuc2hvdHMnLCB2YWx1ZTogJ3NjcmVlbnNob3RzJywgaWNvbjogJ3Bob3RvJyAgfSxcbiAgICB7IGxhYmVsOiAnVmlkZW8nLCB2YWx1ZTogJ3ZpZGVvJywgaWNvbjogJ3ZpZGVvY2FtJyB9LFxuICBdO1xuXG4gIHNwZWVkU2VnbWVudHM6IFNlZ21lbnRPcHRpb25bXSA9IFtcbiAgICB7IGxhYmVsOiAnMXgnLCB2YWx1ZTogJzF4JyB9LFxuICAgIHsgbGFiZWw6ICcyeCcsIHZhbHVlOiAnMngnIH0sXG4gICAgeyBsYWJlbDogJzV4JywgdmFsdWU6ICc1eCcgfSxcbiAgXTtcblxuICBwcml2YXRlIHZpZGVvRXZlbnRMaXN0ZW5lckNsZWFudXA6ICgoKSA9PiB2b2lkKSB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGxhc3RTZXREdXJhdGlvbjogbnVtYmVyID0gLTE7XG4gIHByaXZhdGUgZHJhZ01vdXNlTW92ZUhhbmRsZXI6ICgoZTogTW91c2VFdmVudCkgPT4gdm9pZCkgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBkcmFnTW91c2VVcEhhbmRsZXI6ICgoZTogTW91c2VFdmVudCkgPT4gdm9pZCkgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBzcGVlZENvbnRyb2xDbGlja091dHNpZGVIYW5kbGVyOiAoKGU6IE1vdXNlRXZlbnQpID0+IHZvaWQpIHwgbnVsbCA9IG51bGw7XG4gIFxuICBzYWZlVHJhY2VVcmw6IFNhZmVSZXNvdXJjZVVybDtcbiAgdHJhY2VWaWV3ZXJMb2FkaW5nOiBib29sZWFuID0gZmFsc2U7XG4gIHRyYWNlVmlld2VyRXJyb3I6IGJvb2xlYW4gPSBmYWxzZTtcbiAgaXNDb3JyZWN0RGV2aWNlRnJhbWVBdmFpbGFibGU6IGJvb2xlYW4gPSBmYWxzZTtcbiAgcHJpdmF0ZSByZWFkb25seSBlbXB0eVN0YXRlQ29uZmlnID0gZ2V0RW1wdHlTdGF0ZVByZXNldCgnbm90aGluZ1RvRGlzcGxheScpO1xuICByZWFkb25seSBkZXZpY2VFcnJvckVtcHR5U3RhdGVDb25maWcgPSB7XG4gICAgLi4udGhpcy5lbXB0eVN0YXRlQ29uZmlnLFxuICAgIHRpdGxlOiAnRGV2aWNlIE5vdCBTdXBwb3J0ZWQnLFxuICAgIGRlc2NyaXB0aW9uOiAnVGhlIGRldmljZSB5b3UgYXJlIHRyeWluZyB0byB1c2UgaXMgbm90IHN1cHBvcnRlZC4nLFxuICAgIGFjdGlvbnM6IFtdXG4gIH07XG5cbiAgZ2V0IGVmZmVjdGl2ZUJyb3dzZXJWaWV3UG9ydCgpOiB7IHdpZHRoOiBudW1iZXI7IGhlaWdodDogbnVtYmVyIH0ge1xuICAgIGNvbnN0IGRlZmF1bHRWaWV3cG9ydCA9IHsgd2lkdGg6IDEyODAsIGhlaWdodDogNzIwIH07XG5cbiAgICBpZiAoIXRoaXMuYnJvd3NlclZpZXdQb3J0KSB7XG4gICAgICByZXR1cm4gZGVmYXVsdFZpZXdwb3J0O1xuICAgIH1cblxuICAgIGNvbnN0IHdpZHRoID0gTnVtYmVyKCh0aGlzLmJyb3dzZXJWaWV3UG9ydCBhcyBhbnkpLndpZHRoKTtcbiAgICBjb25zdCBoZWlnaHQgPSBOdW1iZXIoKHRoaXMuYnJvd3NlclZpZXdQb3J0IGFzIGFueSkuaGVpZ2h0KTtcblxuICAgIGlmICghTnVtYmVyLmlzRmluaXRlKHdpZHRoKSB8fCAhTnVtYmVyLmlzRmluaXRlKGhlaWdodCkgfHwgd2lkdGggPD0gMCB8fCBoZWlnaHQgPD0gMCkge1xuICAgICAgcmV0dXJuIGRlZmF1bHRWaWV3cG9ydDtcbiAgICB9XG5cbiAgICByZXR1cm4geyB3aWR0aCwgaGVpZ2h0IH07XG4gIH1cblxuICBwcml2YXRlIHJlYWRvbmx5IGRldmljZUZyYW1lQ29uZmlnczogUmVjb3JkPHN0cmluZywgRGV2aWNlRnJhbWVDb25maWc+ID0ge1xuICAgIC8vIFBpeGVsc1xuICAgICdQaXhlbCA1Jzoge1xuICAgICAgbW9ja3VwSW1hZ2U6ICdhc3NldHMvaW1hZ2VzL21vY2t1cHMvcGl4ZWwtNS5wbmcnLFxuICAgICAgc2NyZWVuSW5zZXQ6IHtcbiAgICAgICAgdG9wOiAnMiUnLFxuICAgICAgICByaWdodDogJzQuNSUnLFxuICAgICAgICBib3R0b206ICcyJScsXG4gICAgICAgIGxlZnQ6ICc0LjUlJ1xuICAgICAgfSxcbiAgICAgIGJvcmRlclJhZGl1czogJzQlJ1xuICAgIH0sXG4gICAgJ1BpeGVsIDgnOiB7XG4gICAgICBtb2NrdXBJbWFnZTogJ2Fzc2V0cy9pbWFnZXMvbW9ja3Vwcy9waXhlbC04LnBuZycsXG4gICAgICBzY3JlZW5JbnNldDoge1xuICAgICAgICB0b3A6ICcyJScsXG4gICAgICAgIHJpZ2h0OiAnNC41JScsXG4gICAgICAgIGJvdHRvbTogJzIuNSUnLFxuICAgICAgICBsZWZ0OiAnNC41JSdcbiAgICAgIH0sXG4gICAgICBib3JkZXJSYWRpdXM6ICc0JSdcbiAgICB9LFxuICAgICdQaXhlbCA5Jzoge1xuICAgICAgbW9ja3VwSW1hZ2U6ICdhc3NldHMvaW1hZ2VzL21vY2t1cHMvcGl4ZWwtOS1wcm8ud2VicCcsXG4gICAgICBzY3JlZW5JbnNldDoge1xuICAgICAgICB0b3A6ICc0JScsXG4gICAgICAgIHJpZ2h0OiAnNSUnLFxuICAgICAgICBib3R0b206ICc0JScsXG4gICAgICAgIGxlZnQ6ICc1JSdcbiAgICAgIH0sXG4gICAgICBib3JkZXJSYWRpdXM6ICc4JSdcbiAgICB9LFxuICAgIC8vIGlQaG9uZXNcbiAgICAnaVBob25lIDExJzoge1xuICAgICAgbW9ja3VwSW1hZ2U6ICdhc3NldHMvaW1hZ2VzL21vY2t1cHMvYXBwbGUtaXBob25lLTExLnBuZycsXG4gICAgICBzY3JlZW5JbnNldDoge1xuICAgICAgICB0b3A6ICczJScsXG4gICAgICAgIHJpZ2h0OiAnNy41JScsXG4gICAgICAgIGJvdHRvbTogJzMlJyxcbiAgICAgICAgbGVmdDogJzcuNSUnXG4gICAgICB9LFxuICAgICAgYm9yZGVyUmFkaXVzOiAnNCUnXG4gICAgfSxcbiAgICAnaVBob25lIDEzJzoge1xuICAgICAgbW9ja3VwSW1hZ2U6ICdhc3NldHMvaW1hZ2VzL21vY2t1cHMvYXBwbGUtaXBob25lLTEzLnBuZycsXG4gICAgICBzY3JlZW5JbnNldDoge1xuICAgICAgICB0b3A6ICcyJScsXG4gICAgICAgIHJpZ2h0OiAnNSUnLFxuICAgICAgICBib3R0b206ICcyJScsXG4gICAgICAgIGxlZnQ6ICc1JSdcbiAgICAgIH0sXG4gICAgICBib3JkZXJSYWRpdXM6ICc0JSdcbiAgICB9LFxuICAgICdpUGhvbmUgMTUnOiB7XG4gICAgICBtb2NrdXBJbWFnZTogJ2Fzc2V0cy9pbWFnZXMvbW9ja3Vwcy9hcHBsZS1pcGhvbmUtMTUucG5nJyxcbiAgICAgIHNjcmVlbkluc2V0OiB7XG4gICAgICAgIHRvcDogJzEuNSUnLFxuICAgICAgICByaWdodDogJzQuNSUnLFxuICAgICAgICBib3R0b206ICcxLjUlJyxcbiAgICAgICAgbGVmdDogJzQuNSUnXG4gICAgICB9LFxuICAgICAgYm9yZGVyUmFkaXVzOiAnNCUnXG4gICAgfSxcbiAgICAnaVBob25lIFhSJzoge1xuICAgICAgbW9ja3VwSW1hZ2U6ICdhc3NldHMvaW1hZ2VzL21vY2t1cHMvYXBwbGUtaXBob25lLXhyLnBuZycsXG4gICAgICBzY3JlZW5JbnNldDoge1xuICAgICAgICB0b3A6ICczLjUlJyxcbiAgICAgICAgcmlnaHQ6ICc3LjUlJyxcbiAgICAgICAgYm90dG9tOiAnMy41JScsXG4gICAgICAgIGxlZnQ6ICc3LjUlJ1xuICAgICAgfSxcbiAgICAgIGJvcmRlclJhZGl1czogJzQlJ1xuICAgIH0sXG5cbiAgICAnR2FsYXh5IFMyMCBGRSc6IHtcbiAgICAgIG1vY2t1cEltYWdlOiAnYXNzZXRzL2ltYWdlcy9tb2NrdXBzL3NhbXN1bmctZ2FsYXh5LXMyMC5wbmcnLFxuICAgICAgc2NyZWVuSW5zZXQ6IHtcbiAgICAgICAgdG9wOiAnMS41JScsXG4gICAgICAgIHJpZ2h0OiAnMiUnLFxuICAgICAgICBib3R0b206ICcxLjUlJyxcbiAgICAgICAgbGVmdDogJzIlJ1xuICAgICAgfSxcbiAgICAgIGJvcmRlclJhZGl1czogJzQlJ1xuICAgIH0sXG5cbiAgICBicm93c2VyOiB7XG4gICAgICBtb2NrdXBJbWFnZTogJ2Fzc2V0cy9pbWFnZXMvbW9ja3Vwcy9icm93c2VyLW1vY2t1cC5wbmcnLFxuICAgICAgc2NyZWVuSW5zZXQ6IHtcbiAgICAgICAgdG9wOiAnNiUnLFxuICAgICAgICByaWdodDogJzAlJyxcbiAgICAgICAgYm90dG9tOiAnMCUnLFxuICAgICAgICBsZWZ0OiAnMCUnXG4gICAgICB9LFxuICAgICAgYm9yZGVyUmFkaXVzOiAnMCUnXG4gICAgfVxuICB9O1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgc2FuaXRpemVyOiBEb21TYW5pdGl6ZXIpIHtcbiAgICB0aGlzLnNhZmVUcmFjZVVybCA9IHRoaXMuc2FuaXRpemVyLmJ5cGFzc1NlY3VyaXR5VHJ1c3RSZXNvdXJjZVVybCgnJyk7XG4gICAgdGhpcy51cGRhdGVTZWdtZW50cygpO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXQgZGV2aWNlRnJhbWVDb25maWcoKTogRGV2aWNlRnJhbWVDb25maWcgfCBudWxsIHtcbiAgICBpZiAodGhpcy5wbGF0Zm9ybVR5cGUgPT09ICdicm93c2VyJykge1xuICAgICAgcmV0dXJuIHRoaXMuZGV2aWNlRnJhbWVDb25maWdzWydicm93c2VyJ10gfHwgbnVsbDtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5wbGF0Zm9ybVR5cGUgPT09ICdkZXZpY2UnKSB7XG4gICAgICAvLyBJZiB3ZSBoYXZlIGEgZGV2aWNlTmFtZSBhbmQgaXRzIGZyYW1lIGlzIGF2YWlsYWJsZSwgcmV0dXJuIGl0XG4gICAgICBpZiAodGhpcy5kZXZpY2VOYW1lICYmIHRoaXMuZGV2aWNlRnJhbWVDb25maWdzW3RoaXMuZGV2aWNlTmFtZV0pIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGV2aWNlRnJhbWVDb25maWdzW3RoaXMuZGV2aWNlTmFtZV07XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIElmIG5vIGRldmljZU5hbWUgb3IgZGV2aWNlTmFtZSdzIGZyYW1lIG5vdCBhdmFpbGFibGUsIHVzZSBkZWZhdWx0cyBiYXNlZCBvbiBwbGF0Zm9ybVxuICAgICAgaWYgKHRoaXMucGxhdGZvcm0gPT09ICdhbmRyb2lkJykge1xuICAgICAgICByZXR1cm4gdGhpcy5kZXZpY2VGcmFtZUNvbmZpZ3NbJ1BpeGVsIDknXSB8fCBudWxsO1xuICAgICAgfVxuICAgICAgaWYgKHRoaXMucGxhdGZvcm0gPT09ICdpb3MnKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRldmljZUZyYW1lQ29uZmlnc1snaVBob25lIDE1J10gfHwgbnVsbDtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBnZXQgZGV2aWNlTW9ja3VwSW1hZ2UoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5kZXZpY2VGcmFtZUNvbmZpZyA/IHRoaXMuZGV2aWNlRnJhbWVDb25maWcubW9ja3VwSW1hZ2UgOiAnJztcbiAgfVxuXG4gIGdldCBkZXZpY2VTY3JlZW5TdHlsZSgpOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9IHtcbiAgICBjb25zdCBjZmcgPSB0aGlzLmRldmljZUZyYW1lQ29uZmlnO1xuICAgIGlmICghY2ZnKSB7XG4gICAgICByZXR1cm4ge307XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHBvc2l0aW9uOiAnYWJzb2x1dGUnLFxuICAgICAgdG9wOiBjZmcuc2NyZWVuSW5zZXQudG9wLFxuICAgICAgcmlnaHQ6IGNmZy5zY3JlZW5JbnNldC5yaWdodCxcbiAgICAgIGJvdHRvbTogY2ZnLnNjcmVlbkluc2V0LmJvdHRvbSxcbiAgICAgIGxlZnQ6IGNmZy5zY3JlZW5JbnNldC5sZWZ0LFxuICAgICAgJ2JvcmRlci1yYWRpdXMnOiBjZmcuYm9yZGVyUmFkaXVzLFxuICAgICAgb3ZlcmZsb3c6ICdoaWRkZW4nXG4gICAgfTtcbiAgfVxuXG4gIG5nQWZ0ZXJWaWV3SW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLmN1cnJlbnRWaWV3ID0gdGhpcy5zZWxlY3RlZFZpZXc7XG4gICAgdGhpcy5hdHRhY2hWaWRlb0xpc3RlbmVycygpO1xuICAgIHRoaXMudXBkYXRlU2FmZVRyYWNlVXJsKCk7XG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgaWYgKGNoYW5nZXNbJ3ZpZGVvVXJscyddKSB7XG4gICAgICBjb25zdCBhcnIgPSBjaGFuZ2VzWyd2aWRlb1VybHMnXS5jdXJyZW50VmFsdWUgYXMgc3RyaW5nW10gfCB1bmRlZmluZWQ7XG4gICAgICBpZiAoYXJyICYmIGFyci5sZW5ndGggPiAwKSB7XG4gICAgICAgIHRoaXMuY3VycmVudFZpZGVvSW5kZXggPSAwO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoY2hhbmdlc1sndmlkZW9DdXJyZW50RHVyYXRpb24nXSAmJiAhY2hhbmdlc1sndmlkZW9DdXJyZW50RHVyYXRpb24nXS5maXJzdENoYW5nZSkge1xuICAgICAgY29uc3QgbmV3RHVyYXRpb24gPSBjaGFuZ2VzWyd2aWRlb0N1cnJlbnREdXJhdGlvbiddLmN1cnJlbnRWYWx1ZTtcbiAgICAgIGlmIChuZXdEdXJhdGlvbiAhPT0gdGhpcy5sYXN0U2V0RHVyYXRpb24gJiYgdGhpcy52cGxheWVyPy5uYXRpdmVFbGVtZW50KSB7XG4gICAgICAgIHRoaXMuc2Vla1RvVGltZShuZXdEdXJhdGlvbik7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChjaGFuZ2VzWyd0cmFjZVZpZXdVcmwnXSkge1xuICAgICAgdGhpcy51cGRhdGVTYWZlVHJhY2VVcmwoKTtcbiAgICAgIHRoaXMudXBkYXRlU2VnbWVudHMoKTtcbiAgICAgIGlmICghdGhpcy50cmFjZVZpZXdVcmwgJiYgdGhpcy5jdXJyZW50VmlldyA9PT0gJ3RyYWNlJykge1xuICAgICAgICB0aGlzLmN1cnJlbnRWaWV3ID0gdGhpcy5oaWRlVmlkZW9UYWIgPyAnc2NyZWVuc2hvdHMnIDogJ3ZpZGVvJztcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKGNoYW5nZXNbJ2hpZGVWaWRlb1RhYiddKSB7XG4gICAgICB0aGlzLnVwZGF0ZVNlZ21lbnRzKCk7XG4gICAgfVxuICAgIGlmIChjaGFuZ2VzWydzZWxlY3RlZFZpZXcnXSkge1xuICAgICAgdGhpcy5jdXJyZW50VmlldyA9IGNoYW5nZXNbJ3NlbGVjdGVkVmlldyddLmN1cnJlbnRWYWx1ZTtcbiAgICB9XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy52aWRlb0V2ZW50TGlzdGVuZXJDbGVhbnVwKSB7XG4gICAgICB0aGlzLnZpZGVvRXZlbnRMaXN0ZW5lckNsZWFudXAoKTtcbiAgICB9XG4gICAgdGhpcy5yZW1vdmVEcmFnTGlzdGVuZXJzKCk7XG4gICAgdGhpcy5yZW1vdmVTcGVlZENvbnRyb2xDbGlja091dHNpZGVMaXN0ZW5lcigpO1xuICB9XG5cbiAgc2Vla1RvVGltZShtaWxsaXNlY29uZHM6IG51bWJlcik6IHZvaWQge1xuICAgIGlmICghdGhpcy52cGxheWVyPy5uYXRpdmVFbGVtZW50IHx8ICF0aGlzLnZwbGF5ZXIubmF0aXZlRWxlbWVudC5kdXJhdGlvbikgcmV0dXJuO1xuICAgIFxuICAgIGNvbnN0IHNlY29uZHMgPSBtaWxsaXNlY29uZHMgLyAxMDAwO1xuICAgIGNvbnN0IHZpZGVvID0gdGhpcy52cGxheWVyLm5hdGl2ZUVsZW1lbnQ7XG4gICAgXG4gICAgY29uc3QgdGFyZ2V0VGltZSA9IE1hdGgubWF4KDAsIE1hdGgubWluKHNlY29uZHMsIHZpZGVvLmR1cmF0aW9uKSk7XG4gICAgdmlkZW8uY3VycmVudFRpbWUgPSB0YXJnZXRUaW1lO1xuICAgIHRoaXMubGFzdFNldER1cmF0aW9uID0gbWlsbGlzZWNvbmRzO1xuXG4gICAgaWYgKHRoaXMuaXNQbGF5aW5nKSB7XG4gICAgICB2aWRlby5wbGF5KCkuY2F0Y2goZXJyID0+IGNvbnNvbGUuZXJyb3IoJ1BsYXkgZmFpbGVkOicsIGVycikpO1xuICAgIH1cbiAgfVxuXG4gIHRvZ2dsZVBsYXkoKTogdm9pZCB7XG4gICAgY29uc3QgdmlkZW8gPSB0aGlzLnZwbGF5ZXI/Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgaWYgKCF2aWRlbykgcmV0dXJuO1xuXG4gICAgLy8gRG8gbm90IGF0dGVtcHQgdG8gcGxheSBpZiB0aGVyZSBpcyBubyB2YWxpZCBzb3VyY2UgeWV0XG4gICAgaWYgKCF0aGlzLmN1cnJlbnRWaWRlb1VybCB8fCB2aWRlby5uZXR3b3JrU3RhdGUgPT09IEhUTUxNZWRpYUVsZW1lbnQuTkVUV09SS19OT19TT1VSQ0UgfHwgdmlkZW8uZXJyb3IpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5pc1BsYXlpbmcpIHtcbiAgICAgIHZpZGVvLnBhdXNlKCk7XG4gICAgICB0aGlzLmlzUGxheWluZyA9IGZhbHNlO1xuICAgICAgdGhpcy52aWRlb1BhdXNlLmVtaXQoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdmlkZW8ucGxheSgpLnRoZW4oKCkgPT4ge1xuICAgICAgICB0aGlzLmlzUGxheWluZyA9IHRydWU7XG4gICAgICAgIHRoaXMudmlkZW9QbGF5LmVtaXQoKTtcbiAgICAgIH0pLmNhdGNoKGVyciA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ1ZpZGVvIHBsYXkgZmFpbGVkOicsIGVycik7XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBnZXQgaGFzTXVsdGlwbGVWaWRlb3MoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIEFycmF5LmlzQXJyYXkodGhpcy52aWRlb1VybHMpICYmIHRoaXMudmlkZW9VcmxzLmxlbmd0aCA+IDE7XG4gIH1cblxuICBnZXQgY3VycmVudFZpZGVvVXJsKCk6IHN0cmluZyB7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkodGhpcy52aWRlb1VybHMpICYmIHRoaXMudmlkZW9VcmxzLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IGlkeCA9IE1hdGgubWluKE1hdGgubWF4KHRoaXMuY3VycmVudFZpZGVvSW5kZXgsIDApLCB0aGlzLnZpZGVvVXJscy5sZW5ndGggLSAxKTtcbiAgICAgIHJldHVybiB0aGlzLnZpZGVvVXJsc1tpZHhdO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy52aWRlb1VybDtcbiAgfVxuXG4gIHByaXZhdGUgcmVzZXRWaWRlb1N0YXRlKCk6IHZvaWQge1xuICAgIHRoaXMuaXNQbGF5aW5nID0gZmFsc2U7XG4gICAgdGhpcy5wcm9ncmVzcyA9IDA7XG4gICAgaWYgKHRoaXMudnBsYXllcj8ubmF0aXZlRWxlbWVudCkge1xuICAgICAgdGhpcy52cGxheWVyLm5hdGl2ZUVsZW1lbnQucGF1c2UoKTtcbiAgICAgIHRoaXMudnBsYXllci5uYXRpdmVFbGVtZW50LmN1cnJlbnRUaW1lID0gMDtcbiAgICB9XG4gICAgdGhpcy5sYXN0U2V0RHVyYXRpb24gPSAtMTtcbiAgfVxuXG4gIHByZXZWaWRlbygpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaGFzTXVsdGlwbGVWaWRlb3MpIHJldHVybjtcbiAgICBpZiAodGhpcy5jdXJyZW50VmlkZW9JbmRleCA+IDApIHtcbiAgICAgIHRoaXMuY3VycmVudFZpZGVvSW5kZXggLT0gMTtcbiAgICAgIHRoaXMucmVzZXRWaWRlb1N0YXRlKCk7XG4gICAgfVxuICB9XG5cbiAgbmV4dFZpZGVvKCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5oYXNNdWx0aXBsZVZpZGVvcykgcmV0dXJuO1xuICAgIGlmICh0aGlzLnZpZGVvVXJscyAmJiB0aGlzLmN1cnJlbnRWaWRlb0luZGV4IDwgdGhpcy52aWRlb1VybHMubGVuZ3RoIC0gMSkge1xuICAgICAgdGhpcy5jdXJyZW50VmlkZW9JbmRleCArPSAxO1xuICAgICAgdGhpcy5yZXNldFZpZGVvU3RhdGUoKTtcbiAgICB9XG4gIH1cblxuICBvblRpbWVsaW5lQ2xpY2soZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMudGltZWxpbmVCYXI/Lm5hdGl2ZUVsZW1lbnQgfHwgIXRoaXMudnBsYXllcj8ubmF0aXZlRWxlbWVudCkgcmV0dXJuO1xuXG4gICAgY29uc3QgcmVjdCA9IHRoaXMudGltZWxpbmVCYXIubmF0aXZlRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICBjb25zdCBjbGlja1ggPSBldmVudC5jbGllbnRYIC0gcmVjdC5sZWZ0O1xuICAgIGNvbnN0IHBlcmNlbnQgPSBNYXRoLm1heCgwLCBNYXRoLm1pbigxLCBjbGlja1ggLyByZWN0LndpZHRoKSk7XG5cbiAgICBjb25zdCBkdXJhdGlvbiA9IHRoaXMudnBsYXllci5uYXRpdmVFbGVtZW50LmR1cmF0aW9uO1xuICAgIGlmICghZHVyYXRpb24gfHwgIWlzRmluaXRlKGR1cmF0aW9uKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHRhcmdldFRpbWVTZWNvbmRzID0gcGVyY2VudCAqIGR1cmF0aW9uO1xuICAgIHRoaXMudnBsYXllci5uYXRpdmVFbGVtZW50LmN1cnJlbnRUaW1lID0gdGFyZ2V0VGltZVNlY29uZHM7XG4gICAgdGhpcy5sYXN0U2V0RHVyYXRpb24gPSB0YXJnZXRUaW1lU2Vjb25kcyAqIDEwMDA7XG4gIH1cblxuICBzdGFydERyYWcoZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIHRoaXMuZHJhZ2dpbmcgPSB0cnVlO1xuICAgIHRoaXMuYWRkRHJhZ0xpc3RlbmVycygpO1xuICB9XG5cbiAgb25EcmFnKGV2ZW50OiBNb3VzZUV2ZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmRyYWdnaW5nIHx8ICF0aGlzLnRpbWVsaW5lQmFyPy5uYXRpdmVFbGVtZW50KSByZXR1cm47XG5cbiAgICBjb25zdCByZWN0ID0gdGhpcy50aW1lbGluZUJhci5uYXRpdmVFbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIGNvbnN0IHggPSBldmVudC5jbGllbnRYIC0gcmVjdC5sZWZ0O1xuICAgIGNvbnN0IHBlcmNlbnQgPSBNYXRoLm1heCgwLCBNYXRoLm1pbih4IC8gcmVjdC53aWR0aCwgMSkpO1xuICAgIHRoaXMucHJvZ3Jlc3MgPSBwZXJjZW50ICogMTAwO1xuICB9XG5cbiAgc3RvcERyYWcoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmRyYWdnaW5nKSByZXR1cm47XG5cbiAgICB0aGlzLmRyYWdnaW5nID0gZmFsc2U7XG4gICAgdGhpcy5yZW1vdmVEcmFnTGlzdGVuZXJzKCk7XG5cbiAgICBpZiAodGhpcy52cGxheWVyPy5uYXRpdmVFbGVtZW50KSB7XG4gICAgICBjb25zdCBkdXJhdGlvbiA9IHRoaXMudnBsYXllci5uYXRpdmVFbGVtZW50LmR1cmF0aW9uO1xuICAgICAgaWYgKCFkdXJhdGlvbiB8fCAhaXNGaW5pdGUoZHVyYXRpb24pKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgdGFyZ2V0VGltZVNlY29uZHMgPSAodGhpcy5wcm9ncmVzcyAvIDEwMCkgKiBkdXJhdGlvbjtcbiAgICAgIHRoaXMudnBsYXllci5uYXRpdmVFbGVtZW50LmN1cnJlbnRUaW1lID0gdGFyZ2V0VGltZVNlY29uZHM7XG4gICAgICB0aGlzLmxhc3RTZXREdXJhdGlvbiA9IHRhcmdldFRpbWVTZWNvbmRzICogMTAwMDtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFkZERyYWdMaXN0ZW5lcnMoKTogdm9pZCB7XG4gICAgdGhpcy5yZW1vdmVEcmFnTGlzdGVuZXJzKCk7XG5cbiAgICB0aGlzLmRyYWdNb3VzZU1vdmVIYW5kbGVyID0gKGU6IE1vdXNlRXZlbnQpID0+IHtcbiAgICAgIHRoaXMub25EcmFnKGUpO1xuICAgIH07XG5cbiAgICB0aGlzLmRyYWdNb3VzZVVwSGFuZGxlciA9ICgpID0+IHtcbiAgICAgIHRoaXMuc3RvcERyYWcoKTtcbiAgICB9O1xuXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgdGhpcy5kcmFnTW91c2VNb3ZlSGFuZGxlcik7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsIHRoaXMuZHJhZ01vdXNlVXBIYW5kbGVyKTtcbiAgfVxuXG4gIHByaXZhdGUgcmVtb3ZlRHJhZ0xpc3RlbmVycygpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5kcmFnTW91c2VNb3ZlSGFuZGxlcikge1xuICAgICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgdGhpcy5kcmFnTW91c2VNb3ZlSGFuZGxlcik7XG4gICAgICB0aGlzLmRyYWdNb3VzZU1vdmVIYW5kbGVyID0gbnVsbDtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5kcmFnTW91c2VVcEhhbmRsZXIpIHtcbiAgICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21vdXNldXAnLCB0aGlzLmRyYWdNb3VzZVVwSGFuZGxlcik7XG4gICAgICB0aGlzLmRyYWdNb3VzZVVwSGFuZGxlciA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgb25WaWRlb01ldGFkYXRhTG9hZGVkKCk6IHZvaWQge1xuICAgIHRoaXMuYXR0YWNoVmlkZW9MaXN0ZW5lcnMoKTtcbiAgfVxuXG4gIG9uVmlkZW9DYW5QbGF5KCk6IHZvaWQge1xuICAgIHRoaXMuYXR0YWNoVmlkZW9MaXN0ZW5lcnMoKTtcbiAgfVxuXG4gIG9uVmlkZW9FbmRlZCgpOiB2b2lkIHtcbiAgICB0aGlzLmlzUGxheWluZyA9IGZhbHNlO1xuICAgIHRoaXMudmlkZW9QYXVzZS5lbWl0KCk7XG4gIH1cblxuICBwcml2YXRlIGF0dGFjaFZpZGVvTGlzdGVuZXJzKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnZpZGVvRXZlbnRMaXN0ZW5lckNsZWFudXApIHtcbiAgICAgIHRoaXMudmlkZW9FdmVudExpc3RlbmVyQ2xlYW51cCgpO1xuICAgICAgdGhpcy52aWRlb0V2ZW50TGlzdGVuZXJDbGVhbnVwID0gbnVsbDtcbiAgICB9XG5cbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIGNvbnN0IHZpZGVvID0gdGhpcy52cGxheWVyPy5uYXRpdmVFbGVtZW50O1xuICAgICAgaWYgKCF2aWRlbykgcmV0dXJuO1xuXG4gICAgICBsZXQgbGFzdFVwZGF0ZSA9IDA7XG4gICAgICBjb25zdCBoYW5kbGVyID0gKCkgPT4ge1xuICAgICAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgICAgICBpZiAobm93IC0gbGFzdFVwZGF0ZSA8IDEwMCkgcmV0dXJuO1xuXG4gICAgICAgIGxhc3RVcGRhdGUgPSBub3c7XG4gICAgICAgIGNvbnN0IGN1cnJlbnRNcyA9IHZpZGVvLmN1cnJlbnRUaW1lICogMTAwMDtcblxuICAgICAgICBpZiAoIXRoaXMuZHJhZ2dpbmcpIHtcbiAgICAgICAgICBjb25zdCBwZXJjZW50ID0gKGN1cnJlbnRNcyAvICh2aWRlby5kdXJhdGlvbiAqIDEwMDApKSAqIDEwMDtcbiAgICAgICAgICB0aGlzLnByb2dyZXNzID0gTWF0aC5taW4oMTAwLCBNYXRoLm1heCgwLCBwZXJjZW50KSk7XG4gICAgICAgICAgdGhpcy52aWRlb1RpbWVVcGRhdGUuZW1pdChjdXJyZW50TXMpO1xuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICB2aWRlby5hZGRFdmVudExpc3RlbmVyKCd0aW1ldXBkYXRlJywgaGFuZGxlcik7XG5cbiAgICAgIHRoaXMudmlkZW9FdmVudExpc3RlbmVyQ2xlYW51cCA9ICgpID0+IHtcbiAgICAgICAgdmlkZW8ucmVtb3ZlRXZlbnRMaXN0ZW5lcigndGltZXVwZGF0ZScsIGhhbmRsZXIpO1xuICAgICAgfTtcbiAgICB9LCAxMDApO1xuICB9XG5cbiAgZ2V0U3RlcExlZnRQb3NpdGlvbihzdGVwOiBTdGVwTWFya2VyKTogbnVtYmVyIHtcbiAgICBpZiAoIXRoaXMudnBsYXllcj8ubmF0aXZlRWxlbWVudD8uZHVyYXRpb24pIHJldHVybiAwO1xuICAgIHJldHVybiAoc3RlcC5jdW11bGF0aXZlRHVyYXRpb24gLyAodGhpcy52cGxheWVyLm5hdGl2ZUVsZW1lbnQuZHVyYXRpb24gKiAxMDAwKSkgKiAxMDA7XG4gIH1cblxuICBnZXRTdGVwQ29sb3Ioc3RlcDogU3RlcE1hcmtlcik6IHN0cmluZyB7XG4gICAgcmV0dXJuIHN0ZXAucmVzdWx0ID09PSAnU1VDQ0VTUycgPyAnIzI4YTc0NScgOiAnI2RjMzU0NSc7XG4gIH1cblxuICB0b2dnbGVGdWxsU2NyZWVuKCk6IHZvaWQge1xuICAgIHRoaXMuaXNGdWxsU2NyZWVuID0gIXRoaXMuaXNGdWxsU2NyZWVuO1xuICB9XG5cbiAgb25TZWdtZW50Q2hhbmdlKHZhbHVlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmN1cnJlbnRWaWV3ID0gdmFsdWU7XG4gICAgdGhpcy5pc1BsYXlpbmcgPSBmYWxzZTtcbiAgICB0aGlzLnZwbGF5ZXI/Lm5hdGl2ZUVsZW1lbnQ/LnBhdXNlKCk7XG4gICAgdGhpcy5wcm9ncmVzcyA9IDA7XG4gIH1cblxuICBmb3JtYXRUaW1lKHNlY29uZHM6IG51bWJlcik6IHN0cmluZyB7XG4gICAgaWYgKCFzZWNvbmRzIHx8IGlzTmFOKHNlY29uZHMpKSByZXR1cm4gJzAwOjAwJztcbiAgICBcbiAgICBjb25zdCBtaW5zID0gTWF0aC5mbG9vcihzZWNvbmRzIC8gNjApO1xuICAgIGNvbnN0IHNlY3MgPSBNYXRoLmZsb29yKHNlY29uZHMgJSA2MCk7XG4gICAgXG4gICAgcmV0dXJuIGAke21pbnMudG9TdHJpbmcoKS5wYWRTdGFydCgyLCAnMCcpfToke3NlY3MudG9TdHJpbmcoKS5wYWRTdGFydCgyLCAnMCcpfWA7XG4gIH1cblxuICBnZXRTdGF0dXNCYWRnZUNsYXNzKCk6IHN0cmluZyB7XG4gICAgY29uc3QgYmFzZUNsYXNzZXMgPSAnY3FhLWlubGluZS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWdhcC0xLjUgY3FhLXB4LVs5cHhdIGNxYS1weS1bM3B4XSBjcWEtcm91bmRlZC1bNnB4XSBjcWEtaC1bMjFweF0nO1xuICAgIHN3aXRjaCAodGhpcy5saXZlU3RhdHVzKSB7XG4gICAgICBjYXNlICdJbiBQcm9ncmVzcyc6XG4gICAgICBjYXNlICdFeGVjdXRpb24nOlxuICAgICAgICByZXR1cm4gYCR7YmFzZUNsYXNzZXN9IGNxYS1iZy1bI0UwRjJGRV0gY3FhLWJvcmRlciBjcWEtYm9yZGVyLVsjN0REM0ZDXWA7XG4gICAgICBjYXNlICdQYXVzZWQnOlxuICAgICAgICByZXR1cm4gYCR7YmFzZUNsYXNzZXN9IGNxYS1iZy1bI0ZFRjNDN10gY3FhLWJvcmRlciBjcWEtYm9yZGVyLVsjRkNEMzREXWA7XG4gICAgICBjYXNlICdBYm9ydGVkJzpcbiAgICAgICAgcmV0dXJuIGAke2Jhc2VDbGFzc2VzfSBjcWEtYmctWyNGRUUyRTJdIGNxYS1ib3JkZXIgY3FhLWJvcmRlci1bI0ZDQTVBNV1gO1xuICAgICAgY2FzZSAnRmFpbGVkJzpcbiAgICAgICAgcmV0dXJuIGAke2Jhc2VDbGFzc2VzfSBjcWEtYmctWyNGQ0Q5RDldIGNxYS1ib3JkZXIgY3FhLWJvcmRlci1bI0Y5QkZCRl1gO1xuICAgICAgY2FzZSAnUGFzc2VkJzpcbiAgICAgICAgcmV0dXJuIGAke2Jhc2VDbGFzc2VzfSBjcWEtYmctWyNEMUZBRTVdIGNxYS1ib3JkZXIgY3FhLWJvcmRlci1bIzZFRTdCN11gO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIGAke2Jhc2VDbGFzc2VzfSBjcWEtYmctZ3JheS0yMDAgY3FhLWJvcmRlciBjcWEtYm9yZGVyLWdyYXktMzAwYDtcbiAgICB9XG4gIH1cblxuICBnZXRTdGF0dXNUZXh0Q2xhc3MoKTogc3RyaW5nIHtcbiAgICBzd2l0Y2ggKHRoaXMubGl2ZVN0YXR1cykge1xuICAgICAgY2FzZSAnSW4gUHJvZ3Jlc3MnOlxuICAgICAgY2FzZSAnRXhlY3V0aW9uJzpcbiAgICAgICAgcmV0dXJuICdjcWEtdGV4dC1bMTBweF0gY3FhLWZvbnQtbWVkaXVtIGNxYS10ZXh0LVsjMDI4NEM3XSBjcWEtbGVhZGluZy1bMTVweF0nO1xuICAgICAgY2FzZSAnUGF1c2VkJzpcbiAgICAgICAgcmV0dXJuICdjcWEtdGV4dC1bMTBweF0gY3FhLWZvbnQtbWVkaXVtIGNxYS10ZXh0LVsjRDk3NzA2XSBjcWEtbGVhZGluZy1bMTVweF0nO1xuICAgICAgY2FzZSAnQWJvcnRlZCc6XG4gICAgICAgIHJldHVybiAnY3FhLXRleHQtWzEwcHhdIGNxYS1mb250LW1lZGl1bSBjcWEtdGV4dC1bI0RDMjYyNl0gY3FhLWxlYWRpbmctWzE1cHhdJztcbiAgICAgIGNhc2UgJ0ZhaWxlZCc6XG4gICAgICAgIHJldHVybiAnY3FhLXRleHQtWzEwcHhdIGNxYS1mb250LW1lZGl1bSBjcWEtdGV4dC1bI0M2MzUzNV0gY3FhLWxlYWRpbmctWzE1cHhdJztcbiAgICAgIGNhc2UgJ1Bhc3NlZCc6XG4gICAgICAgIHJldHVybiAnY3FhLXRleHQtWzEwcHhdIGNxYS1mb250LW1lZGl1bSBjcWEtdGV4dC1bIzA1OTY2OV0gY3FhLWxlYWRpbmctWzE1cHhdJztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiAnY3FhLXRleHQtWzEwcHhdIGNxYS1mb250LW1lZGl1bSBjcWEtdGV4dC1ncmF5LTYwMCBjcWEtbGVhZGluZy1bMTVweF0nO1xuICAgIH1cbiAgfVxuXG4gIGdldCBwcm9jZXNzZWRUcmFjZVVybCgpOiBzdHJpbmcge1xuICAgIGlmICghdGhpcy50cmFjZVZpZXdVcmwpIHJldHVybiAnJztcbiAgICBcbiAgICBpZiAodGhpcy50cmFjZVZpZXdVcmwuZW5kc1dpdGgoJy56aXAnKSkge1xuICAgICAgY29uc3QgdXJsUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh7XG4gICAgICAgIHRyYWNlOiB0aGlzLnRyYWNlVmlld1VybCxcbiAgICAgICAgaGlkZUhlYWRlcjogJ3RydWUnLFxuICAgICAgICBoaWRlQnJhbmRpbmc6ICd0cnVlJyxcbiAgICAgICAgZW1iZWQ6ICd0cnVlJyxcbiAgICAgICAgbWluaW1hbDogJ3RydWUnLFxuICAgICAgICBub0hlYWRlcjogJ3RydWUnXG4gICAgICB9KTtcbiAgICAgIFxuICAgICAgcmV0dXJuIGBodHRwczovL3RyYWNlLnBsYXl3cmlnaHQuZGV2Lz8ke3VybFBhcmFtcy50b1N0cmluZygpfWA7XG4gICAgfVxuICAgIFxuICAgIHJldHVybiB0aGlzLnRyYWNlVmlld1VybDtcbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlU2FmZVRyYWNlVXJsKCk6IHZvaWQge1xuICAgIGNvbnN0IHVybCA9IHRoaXMucHJvY2Vzc2VkVHJhY2VVcmw7XG4gICAgaWYgKHVybCkge1xuICAgICAgdGhpcy50cmFjZVZpZXdlckxvYWRpbmcgPSB0cnVlO1xuICAgICAgdGhpcy50cmFjZVZpZXdlckVycm9yID0gZmFsc2U7XG4gICAgICB0aGlzLnNhZmVUcmFjZVVybCA9IHRoaXMuc2FuaXRpemVyLmJ5cGFzc1NlY3VyaXR5VHJ1c3RSZXNvdXJjZVVybCh1cmwpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnRyYWNlVmlld2VyTG9hZGluZyA9IGZhbHNlO1xuICAgICAgdGhpcy50cmFjZVZpZXdlckVycm9yID0gZmFsc2U7XG4gICAgICB0aGlzLnNhZmVUcmFjZVVybCA9IHRoaXMuc2FuaXRpemVyLmJ5cGFzc1NlY3VyaXR5VHJ1c3RSZXNvdXJjZVVybCgnJyk7XG4gICAgfVxuICB9XG5cbiAgb25UcmFjZVZpZXdlckxvYWQoKTogdm9pZCB7XG4gICAgdGhpcy50cmFjZVZpZXdlckxvYWRpbmcgPSBmYWxzZTtcbiAgICB0aGlzLnRyYWNlVmlld2VyRXJyb3IgPSBmYWxzZTtcbiAgfVxuXG4gIG9uVHJhY2VWaWV3ZXJFcnJvcigpOiB2b2lkIHtcbiAgICB0aGlzLnRyYWNlVmlld2VyTG9hZGluZyA9IGZhbHNlO1xuICAgIHRoaXMudHJhY2VWaWV3ZXJFcnJvciA9IHRydWU7XG4gIH1cblxuICBvblNwZWVkQ2hhbmdlKHZhbHVlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmN1cnJlbnRTcGVlZCA9IHZhbHVlO1xuICAgIGNvbnN0IG51bWVyaWMgPSBwYXJzZUZsb2F0KHZhbHVlLnJlcGxhY2UoJ3gnLCAnJykpO1xuICAgIGNvbnN0IHJhdGUgPSAhaXNOYU4obnVtZXJpYykgJiYgbnVtZXJpYyA+IDAgPyBudW1lcmljIDogMTtcbiAgICBpZiAodGhpcy52cGxheWVyPy5uYXRpdmVFbGVtZW50KSB7XG4gICAgICB0aGlzLnZwbGF5ZXIubmF0aXZlRWxlbWVudC5wbGF5YmFja1JhdGUgPSByYXRlO1xuICAgIH1cbiAgICB0aGlzLmlzU3BlZWRDb250cm9sT3BlbiA9IGZhbHNlO1xuICB9XG5cbiAgdG9nZ2xlU3BlZWRDb250cm9sKCk6IHZvaWQge1xuICAgIHRoaXMuaXNTcGVlZENvbnRyb2xPcGVuID0gIXRoaXMuaXNTcGVlZENvbnRyb2xPcGVuO1xuICAgIGlmICh0aGlzLmlzU3BlZWRDb250cm9sT3Blbikge1xuICAgICAgdGhpcy5hZGRTcGVlZENvbnRyb2xDbGlja091dHNpZGVMaXN0ZW5lcigpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnJlbW92ZVNwZWVkQ29udHJvbENsaWNrT3V0c2lkZUxpc3RlbmVyKCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhZGRTcGVlZENvbnRyb2xDbGlja091dHNpZGVMaXN0ZW5lcigpOiB2b2lkIHtcbiAgICB0aGlzLnJlbW92ZVNwZWVkQ29udHJvbENsaWNrT3V0c2lkZUxpc3RlbmVyKCk7XG4gICAgXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLnNwZWVkQ29udHJvbENsaWNrT3V0c2lkZUhhbmRsZXIgPSAoZTogTW91c2VFdmVudCkgPT4ge1xuICAgICAgICBjb25zdCB0YXJnZXQgPSBlLnRhcmdldCBhcyBIVE1MRWxlbWVudDtcbiAgICAgICAgaWYgKHRhcmdldCAmJiB0aGlzLnNwZWVkQ29udHJvbENvbnRhaW5lcj8ubmF0aXZlRWxlbWVudCAmJiBcbiAgICAgICAgICAgICF0aGlzLnNwZWVkQ29udHJvbENvbnRhaW5lci5uYXRpdmVFbGVtZW50LmNvbnRhaW5zKHRhcmdldCkpIHtcbiAgICAgICAgICB0aGlzLmlzU3BlZWRDb250cm9sT3BlbiA9IGZhbHNlO1xuICAgICAgICAgIHRoaXMucmVtb3ZlU3BlZWRDb250cm9sQ2xpY2tPdXRzaWRlTGlzdGVuZXIoKTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICAgIFxuICAgICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCB0aGlzLnNwZWVkQ29udHJvbENsaWNrT3V0c2lkZUhhbmRsZXIpO1xuICAgIH0sIDApO1xuICB9XG5cbiAgcHJpdmF0ZSByZW1vdmVTcGVlZENvbnRyb2xDbGlja091dHNpZGVMaXN0ZW5lcigpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5zcGVlZENvbnRyb2xDbGlja091dHNpZGVIYW5kbGVyKSB7XG4gICAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdjbGljaycsIHRoaXMuc3BlZWRDb250cm9sQ2xpY2tPdXRzaWRlSGFuZGxlcik7XG4gICAgICB0aGlzLnNwZWVkQ29udHJvbENsaWNrT3V0c2lkZUhhbmRsZXIgPSBudWxsO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlU2VnbWVudHMoKTogdm9pZCB7XG4gICAgY29uc3QgYmFzZVNlZ21lbnRzOiBTZWdtZW50T3B0aW9uW10gPSBbXG4gICAgICB7IGxhYmVsOiAnU2NyZWVuc2hvdHMnLCB2YWx1ZTogJ3NjcmVlbnNob3RzJywgaWNvbjogJ3Bob3RvJyAgfSxcbiAgICBdO1xuICAgIFxuICAgIC8vIE9ubHkgYWRkIFZpZGVvIHRhYiBpZiBoaWRlVmlkZW9UYWIgaXMgZmFsc2VcbiAgICBpZiAoIXRoaXMuaGlkZVZpZGVvVGFiKSB7XG4gICAgICBiYXNlU2VnbWVudHMucHVzaCh7IGxhYmVsOiAnVmlkZW8nLCB2YWx1ZTogJ3ZpZGVvJywgaWNvbjogJ3ZpZGVvY2FtJyB9KTtcbiAgICB9XG4gICAgXG4gICAgaWYgKHRoaXMudHJhY2VWaWV3VXJsKSB7XG4gICAgICBiYXNlU2VnbWVudHMucHVzaCh7IGxhYmVsOiAnVHJhY2UnLCB2YWx1ZTogJ3RyYWNlJywgaWNvbjogJ2dyYXBoaWNfZXEnIH0pO1xuICAgIH1cbiAgICBcbiAgICB0aGlzLnNlZ21lbnRzID0gYmFzZVNlZ21lbnRzO1xuICAgIFxuICAgIC8vIElmIGN1cnJlbnQgdmlldyBpcyAndmlkZW8nIGFuZCB2aWRlbyB0YWIgaXMgaGlkZGVuLCBzd2l0Y2ggdG8gc2NyZWVuc2hvdHNcbiAgICBpZiAodGhpcy5jdXJyZW50VmlldyA9PT0gJ3ZpZGVvJyAmJiB0aGlzLmhpZGVWaWRlb1RhYikge1xuICAgICAgdGhpcy5jdXJyZW50VmlldyA9ICdzY3JlZW5zaG90cyc7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBvblZpZGVvRWxlbWVudFJlYWR5KCk6IHZvaWQge1xuICAgIGNvbnN0IHZpZGVvID0gdGhpcy5fdnBsYXllcj8ubmF0aXZlRWxlbWVudDtcbiAgICBpZiAoIXZpZGVvKSByZXR1cm47XG5cbiAgICBjb25zdCBudW1lcmljID0gcGFyc2VGbG9hdCh0aGlzLmN1cnJlbnRTcGVlZC5yZXBsYWNlKCd4JywgJycpKTtcbiAgICBjb25zdCByYXRlID0gIWlzTmFOKG51bWVyaWMpICYmIG51bWVyaWMgPiAwID8gbnVtZXJpYyA6IDE7XG4gICAgdmlkZW8ucGxheWJhY2tSYXRlID0gcmF0ZTtcblxuICAgIHRoaXMuYXR0YWNoVmlkZW9MaXN0ZW5lcnMoKTtcbiAgfVxufVxuXG4iLCI8ZGl2IGNsYXNzPVwiY3FhLXVpLXJvb3RcIiBzdHlsZT1cImJhY2tncm91bmQtY29sb3I6ICNGM0Y0RjY7IGhlaWdodDogMTAwJTsgZGlzcGxheTogZmxleDsgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcIiAgIFtuZ1N0eWxlXT1cIntcbiAgcG9zaXRpb246IGlzRnVsbFNjcmVlbiA/ICdmaXhlZCcgOiBudWxsLFxuICBpbnNldDogaXNGdWxsU2NyZWVuID8gJzFyZW0nIDogbnVsbCxcbiAgekluZGV4OiBpc0Z1bGxTY3JlZW4gPyAnNTAnIDogbnVsbCxcbiAgYm94U2hhZG93OiBpc0Z1bGxTY3JlZW4gPyAnMHB4IDEzcHggMjVweCAtMTJweCByZ2JhKDAsIDAsIDAsIDAuMjUpJyA6IG51bGwsXG4gIGJvcmRlclJhZGl1czogaXNGdWxsU2NyZWVuID8gJy41cmVtJyA6IG51bGwsXG4gIGJvcmRlcjogaXNGdWxsU2NyZWVuID8gJzFweCBzb2xpZCAjRTVFN0VCJyA6IG51bGwsXG4gIHdpZHRoOiBpc0Z1bGxTY3JlZW4gPyAnY2FsYygxMDAlIC0gMzJweCknIDogbnVsbCxcbiAgaGVpZ2h0OiBpc0Z1bGxTY3JlZW4gPyAnY2FsYygxMDAlIC0gMzJweCknIDogJzEwMCUnLFxuICBvdmVyZmxvdzogaXNGdWxsU2NyZWVuID8gJ2hpZGRlbicgOiBudWxsXG59XCI+XG4gIDxkaXYgY2xhc3M9XCJjcWEtdy1mdWxsIGNxYS1weS0xIGNxYS1weC0yIGNxYS1iZy1bI0ZGRkZGRl1cIiBzdHlsZT1cImJvcmRlci1ib3R0b206IDFweCBzb2xpZCAjRTVFN0VCO2JveC1zaGFkb3c6IDBweCAxcHggMnB4IDBweCAjMDAwMDAwMEQ7XCI+XG4gICAgPGRpdiBjbGFzcz1cImNxYS13LWZ1bGwgY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1iZXR3ZWVuIGNxYS1mbGV4LXdyYXBcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyXCI+XG4gICAgICAgIDxkaXYgKm5nSWY9XCJpc0xpdmVcIiBjbGFzcz1cImNxYS1oLVsyMXB4XSBjcWEtaW5saW5lLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtZ2FwLTEuNSBjcWEtbXItMiBjcWEtcHgtWzlweF0gY3FhLXB5LVszcHhdIGNxYS1iZy1bI0ZDRDlEOV0gY3FhLXJvdW5kZWQtWzZweF1cIiBzdHlsZT1cImJvcmRlcjogMXB4IHNvbGlkICNGOUJGQkY7XCI+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtcmVsYXRpdmUgY3FhLXctMiBjcWEtaC0yIGNxYS1yb3VuZGVkLWZ1bGwgY3FhLWJnLVsjRjQ3RjdGXVwiIHN0eWxlPVwiZmxleC1zaHJpbms6IDA7XCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImNxYS1hYnNvbHV0ZSBjcWEtaW5zZXQtMCBjcWEtcm91bmRlZC1mdWxsIGNxYS1iZy1bI0Y0N0Y3Rl0gY3FhLW9wYWNpdHktNzUgY3FhLWFuaW1hdGUtcGluZ1wiPjwvc3Bhbj5cbiAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtdGV4dC1bMTBweF0gY3FhLWZvbnQtbWVkaXVtIGNxYS10ZXh0LVsjQzYzNTM1XSBjcWEtbGVhZGluZy1bMTVweF1cIj5MaXZlPC9zcGFuPlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPG1hdC1pY29uICpuZ0lmPVwicGxhdGZvcm1UeXBlID09PSAnYnJvd3NlcidcIiBzdHlsZT1cIndpZHRoOiAxMHB4OyBoZWlnaHQ6IDEwcHg7XCI+XG4gICAgICAgICAgPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgd2lkdGg9XCIxMFwiIGhlaWdodD1cIjEwXCIgdmlld0JveD1cIjAgMCAxMCAxMFwiIGZpbGw9XCJub25lXCI+XG4gICAgICAgICAgICA8ZyBjbGlwLXBhdGg9XCJ1cmwoI2NsaXAwXzkzNV8xNTg0NylcIj5cbiAgICAgICAgICAgICAgPHBhdGhcbiAgICAgICAgICAgICAgICBkPVwiTTAuNjI1IDVDMC42MjUgNi4xNjAzMiAxLjA4NTk0IDcuMjczMTIgMS45MDY0MSA4LjA5MzU5QzIuNzI2ODggOC45MTQwNiAzLjgzOTY4IDkuMzc1IDUgOS4zNzVDNi4xNjAzMiA5LjM3NSA3LjI3MzEyIDguOTE0MDYgOC4wOTM1OSA4LjA5MzU5QzguOTE0MDYgNy4yNzMxMiA5LjM3NSA2LjE2MDMyIDkuMzc1IDVDOS4zNzUgMy44Mzk2OCA4LjkxNDA2IDIuNzI2ODggOC4wOTM1OSAxLjkwNjQxQzcuMjczMTIgMS4wODU5NCA2LjE2MDMyIDAuNjI1IDUgMC42MjVDMy44Mzk2OCAwLjYyNSAyLjcyNjg4IDEuMDg1OTQgMS45MDY0MSAxLjkwNjQxQzEuMDg1OTQgMi43MjY4OCAwLjYyNSAzLjgzOTY4IDAuNjI1IDVaXCJcbiAgICAgICAgICAgICAgICBzdHJva2U9XCIjOUNBM0FGXCIgc3Ryb2tlLXdpZHRoPVwiMC42XCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIiAvPlxuICAgICAgICAgICAgICA8cGF0aFxuICAgICAgICAgICAgICAgIGQ9XCJNMy4xMjUgNUMzLjEyNSAzLjgzOTY4IDMuMzIyNTQgMi43MjY4OCAzLjY3NDE3IDEuOTA2NDFDNC4wMjU4MSAxLjA4NTk0IDQuNTAyNzIgMC42MjUgNSAwLjYyNUM1LjQ5NzI4IDAuNjI1IDUuOTc0MTkgMS4wODU5NCA2LjMyNTgyIDEuOTA2NDFDNi42Nzc0NiAyLjcyNjg4IDYuODc1IDMuODM5NjggNi44NzUgNUM2Ljg3NSA2LjE2MDMyIDYuNjc3NDYgNy4yNzMxMiA2LjMyNTgyIDguMDkzNTlDNS45NzQxOSA4LjkxNDA2IDUuNDk3MjggOS4zNzUgNSA5LjM3NUM0LjUwMjcyIDkuMzc1IDQuMDI1ODEgOC45MTQwNiAzLjY3NDE3IDguMDkzNTlDMy4zMjI1NCA3LjI3MzEyIDMuMTI1IDYuMTYwMzIgMy4xMjUgNVpcIlxuICAgICAgICAgICAgICAgIHN0cm9rZT1cIiM5Q0EzQUZcIiBzdHJva2Utd2lkdGg9XCIwLjZcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiIC8+XG4gICAgICAgICAgICAgIDxwYXRoIGQ9XCJNMC45Mzc1IDYuNDU4NjZIOS4wNjI1TTAuOTM3NSAzLjU0MTk5SDkuMDYyNVwiIHN0cm9rZT1cIiM5Q0EzQUZcIiBzdHJva2Utd2lkdGg9XCIwLjZcIlxuICAgICAgICAgICAgICAgIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiAvPlxuICAgICAgICAgICAgPC9nPlxuICAgICAgICAgICAgPGRlZnM+XG4gICAgICAgICAgICAgIDxjbGlwUGF0aCBpZD1cImNsaXAwXzkzNV8xNTg0N1wiPlxuICAgICAgICAgICAgICAgIDxyZWN0IHdpZHRoPVwiMTBcIiBoZWlnaHQ9XCIxMFwiIGZpbGw9XCJ3aGl0ZVwiIC8+XG4gICAgICAgICAgICAgIDwvY2xpcFBhdGg+XG4gICAgICAgICAgICA8L2RlZnM+XG4gICAgICAgICAgPC9zdmc+XG4gICAgICAgIDwvbWF0LWljb24+XG4gICAgICAgIDxtYXQtaWNvbiAqbmdJZj1cInBsYXRmb3JtVHlwZSA9PT0gJ2RldmljZSdcIiBzdHlsZT1cIndpZHRoOiAxMHB4OyBoZWlnaHQ6IDEwcHg7XCI+XG4gICAgICAgICAgPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgd2lkdGg9XCIxMFwiIGhlaWdodD1cIjEwXCIgdmlld0JveD1cIjAgMCAxMCAxMFwiIGZpbGw9XCJub25lXCI+XG4gICAgICAgICAgICA8cGF0aCBkPVwiTTcuMDgzMjUgMC44MzMwMDhIMi45MTY1OUMyLjQ1NjM1IDAuODMzMDA4IDIuMDgzMjUgMS4yMDYxIDIuMDgzMjUgMS42NjYzNFY4LjMzMzAxQzIuMDgzMjUgOC43OTMyNCAyLjQ1NjM1IDkuMTY2MzQgMi45MTY1OSA5LjE2NjM0SDcuMDgzMjVDNy41NDM0OSA5LjE2NjM0IDcuOTE2NTggOC43OTMyNCA3LjkxNjU4IDguMzMzMDFWMS42NjYzNEM3LjkxNjU4IDEuMjA2MSA3LjU0MzQ5IDAuODMzMDA4IDcuMDgzMjUgMC44MzMwMDhaXCIgc3Ryb2tlPVwiIzZCNzI4MFwiIHN0cm9rZS13aWR0aD1cIjAuODMzMzMzXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPlxuICAgICAgICAgICAgPHBhdGggZD1cIk01IDcuNUg1LjAwNDE3XCIgc3Ryb2tlPVwiIzZCNzI4MFwiIHN0cm9rZS13aWR0aD1cIjAuODMzMzMzXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPlxuICAgICAgICAgIDwvc3ZnPlxuICAgICAgICA8L21hdC1pY29uPlxuICAgICAgICA8cCBjbGFzcz1cImNxYS10ZXh0LXNtICFjcWEtdGV4dC1bMTBweF0gY3FhLXRleHQtWyM2QjcyODBdIGNxYS1tbC0yXCI+XG4gICAgICAgICAge3sgcGxhdGZvcm1OYW1lIH19XG4gICAgICAgICAgPHNwYW5cbiAgICAgICAgICAgICpuZ0lmPVwicGxhdGZvcm1UeXBlID09PSAnYnJvd3NlcidcIlxuICAgICAgICAgICAgY2xhc3M9XCJjcWEtbWwtMVwiXG4gICAgICAgICAgICBbbWF0VG9vbHRpcF09XCInU2NyZWVuIHNpemU6ICcgKyBlZmZlY3RpdmVCcm93c2VyVmlld1BvcnQud2lkdGggKyAneCcgKyBlZmZlY3RpdmVCcm93c2VyVmlld1BvcnQuaGVpZ2h0XCJcbiAgICAgICAgICAgIG1hdFRvb2x0aXBQb3NpdGlvbj1cImJlbG93XCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICDCt1xuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtbWwtMVwiPlxuICAgICAgICAgICAgICB7eyBlZmZlY3RpdmVCcm93c2VyVmlld1BvcnQud2lkdGggfX14e3sgZWZmZWN0aXZlQnJvd3NlclZpZXdQb3J0LmhlaWdodCB9fVxuICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgPC9wPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtZ2FwLTJcIj5cbiAgICAgICAgPGRpdiAqbmdJZj1cImlzTGl2ZVwiIFtuZ0NsYXNzXT1cImdldFN0YXR1c0JhZGdlQ2xhc3MoKVwiPlxuICAgICAgICAgIDxzcGFuIFtuZ0NsYXNzXT1cImdldFN0YXR1c1RleHRDbGFzcygpXCI+e3sgbGl2ZVN0YXR1cyB9fTwvc3Bhbj5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFpc0xpdmVcIj5cbiAgICAgICAgICA8Y3FhLXNlZ21lbnQtY29udHJvbCBcbiAgICAgICAgICAgIFtzZWdtZW50c109XCJzZWdtZW50c1wiIFxuICAgICAgICAgICAgW3ZhbHVlXT1cImN1cnJlbnRWaWV3XCJcbiAgICAgICAgICAgICh2YWx1ZUNoYW5nZSk9XCJvblNlZ21lbnRDaGFuZ2UoJGV2ZW50KVwiPlxuICAgICAgICAgIDwvY3FhLXNlZ21lbnQtY29udHJvbD5cbiAgICAgICAgICBcbiAgICAgICAgICA8ZGl2ICpuZ0lmPVwiIWlzRnVsbFNjcmVlblwiIFxuICAgICAgICAgICAgICAgY2xhc3M9XCJjcWEtcC0xIGNxYS1jdXJzb3ItcG9pbnRlciBob3ZlcjpjcWEtYmctZ3JheS0xMDAgY3FhLXJvdW5kZWQtc20gY3FhLXRyYW5zaXRpb24tY29sb3JzXCJcbiAgICAgICAgICAgICAgIChjbGljayk9XCJ0b2dnbGVGdWxsU2NyZWVuKClcIlxuICAgICAgICAgICAgICAgdGl0bGU9XCJFeHBhbmRcIj5cbiAgICAgICAgICAgIDxzdmcgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIHdpZHRoPVwiMTBcIiBoZWlnaHQ9XCIxMFwiIHZpZXdCb3g9XCIwIDAgMTAgMTBcIiBmaWxsPVwibm9uZVwiPlxuICAgICAgICAgICAgICA8cGF0aCBkPVwiTTYuMjUgMS4yNUg4Ljc1VjMuNzVcIiBzdHJva2U9XCIjOUNBM0FGXCIgc3Ryb2tlLXdpZHRoPVwiMC44MzMzMzNcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIi8+XG4gICAgICAgICAgICAgIDxwYXRoIGQ9XCJNOC43NDk5MiAxLjI1TDUuODMzMjUgNC4xNjY2N1wiIHN0cm9rZT1cIiM5Q0EzQUZcIiBzdHJva2Utd2lkdGg9XCIwLjgzMzMzM1wiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiLz5cbiAgICAgICAgICAgICAgPHBhdGggZD1cIk0xLjI1IDguNzQ5NjdMNC4xNjY2NyA1LjgzMzAxXCIgc3Ryb2tlPVwiIzlDQTNBRlwiIHN0cm9rZS13aWR0aD1cIjAuODMzMzMzXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPlxuICAgICAgICAgICAgICA8cGF0aCBkPVwiTTMuNzUgOC43NUgxLjI1VjYuMjVcIiBzdHJva2U9XCIjOUNBM0FGXCIgc3Ryb2tlLXdpZHRoPVwiMC44MzMzMzNcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIi8+XG4gICAgICAgICAgICA8L3N2Zz5cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIDxkaXYgKm5nSWY9XCJpc0Z1bGxTY3JlZW5cIiBcbiAgICAgICAgICAgICAgIGNsYXNzPVwiY3FhLXAtMSBjcWEtY3Vyc29yLXBvaW50ZXIgaG92ZXI6Y3FhLWJnLWdyYXktMTAwIGNxYS1yb3VuZGVkLXNtIGNxYS10cmFuc2l0aW9uLWNvbG9yc1wiXG4gICAgICAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlRnVsbFNjcmVlbigpXCJcbiAgICAgICAgICAgICAgIHRpdGxlPVwiRXhpdCBmdWxsIHNjcmVlblwiPlxuICAgICAgICAgICAgPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgd2lkdGg9XCIxMFwiIGhlaWdodD1cIjEwXCIgdmlld0JveD1cIjAgMCAxMCAxMFwiIGZpbGw9XCJub25lXCI+XG4gICAgICAgICAgICAgIDxwYXRoIGQ9XCJNOC43NSA2LjI1SDYuMjVWOC43NVwiIHN0cm9rZT1cIiM5Q0EzQUZcIiBzdHJva2Utd2lkdGg9XCIwLjgzMzMzM1wiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiLz5cbiAgICAgICAgICAgICAgPHBhdGggZD1cIk02LjI1MDA4IDYuMjVMOS4xNjY3NSA5LjE2NjY3XCIgc3Ryb2tlPVwiIzlDQTNBRlwiIHN0cm9rZS13aWR0aD1cIjAuODMzMzMzXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPlxuICAgICAgICAgICAgICA8cGF0aCBkPVwiTTAuODMzMjUyIDAuODMzMDA4TDMuNzQ5OTIgMy43NDk2N1wiIHN0cm9rZT1cIiM5Q0EzQUZcIiBzdHJva2Utd2lkdGg9XCIwLjgzMzMzM1wiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiLz5cbiAgICAgICAgICAgICAgPHBhdGggZD1cIk0xLjI1IDMuNzVIMy43NVYxLjI1XCIgc3Ryb2tlPVwiIzlDQTNBRlwiIHN0cm9rZS13aWR0aD1cIjAuODMzMzMzXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPlxuICAgICAgICAgICAgPC9zdmc+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuICA8ZGl2IGNsYXNzPVwiY3FhLXctZnVsbCBjcWEtYmctWyNGM0Y0RjZdIGNxYS1oLVtjYWxjKDEwMCUtNDFweCldXCI+XG4gIDwhLS0gTGl2ZSBDb250ZW50IFZpZXcgLS0+XG4gICAgPGRpdiAqbmdJZj1cImlzTGl2ZVwiIGNsYXNzPVwiY3FhLWgtZnVsbCBjcWEtZmxleCBjcWEtZmxleC1jb2wgY3FhLWp1c3RpZnktY2VudGVyIGNxYS1yZWxhdGl2ZVwiPlxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImhhc0RldmljZUZyYW1lO1wiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXctZnVsbCBjcWEtaC1mdWxsIGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyIGNxYS1wLTRcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXJlbGF0aXZlIGNxYS1oLWZ1bGwgY3FhLXctYXV0byBjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWNlbnRlclwiIFtuZ0NsYXNzXT1cInsnY3FhLXJvdW5kZWQtbWQgY3FhLW92ZXJmbG93LWhpZGRlbic6IHBsYXRmb3JtVHlwZSA9PT0gJ2Jyb3dzZXInLCAnY3FhLW1heC1oLWZ1bGwgY3FhLWgtZnVsbCc6IHBsYXRmb3JtVHlwZSAhPT0gJ2Jyb3dzZXInIHx8ICFpc0xpdmUsICdjcWEtbWluLXctbWF4JzogcGxhdGZvcm1UeXBlID09PSAnZGV2aWNlJ31cIj5cbiAgICAgICAgICAgIDxpbWdcbiAgICAgICAgICAgICAgW3NyY109XCJkZXZpY2VNb2NrdXBJbWFnZVwiXG4gICAgICAgICAgICAgIGFsdD1cIkRldmljZSBtb2NrdXBcIlxuICAgICAgICAgICAgICBjbGFzcz1cImNxYS1oLWZ1bGwgY3FhLXctYXV0byBjcWEtbWF4LWgtZnVsbCBjcWEtb2JqZWN0LWNvbnRhaW4gY3FhLWJsb2NrIGNxYS1wb2ludGVyLWV2ZW50cy1ub25lIGNxYS16LTEwXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLWFic29sdXRlIGNxYS1mbGV4IGNxYS1mbGV4LWNvbFwiIFtuZ1N0eWxlXT1cImRldmljZVNjcmVlblN0eWxlXCIgW25nQ2xhc3NdPVwieydjcWEtei0yMCc6IHBsYXRmb3JtVHlwZSA9PT0gJ2Jyb3dzZXInLCAnY3FhLWJnLXdoaXRlJzogcGxhdGZvcm1UeXBlICE9PSAnYnJvd3Nlcid9XCI+XG4gICAgICAgICAgICAgIDwhLS0gTG9hZGluZyBTdGF0ZSAtLT5cbiAgICAgICAgICAgICAgPGRpdiAqbmdJZj1cImlzQ29udGVudFZpZGVvTG9hZGluZ1wiIGNsYXNzPVwiY3FhLXAtMTAgY3FhLXRleHQtY2VudGVyIGNxYS1oLWZ1bGwgY3FhLWZsZXggY3FhLWZsZXgtY29sIGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyXCI+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1tYi00XCI+XG4gICAgICAgICAgICAgICAgICA8bWF0LXByb2dyZXNzLXNwaW5uZXIgbW9kZT1cImluZGV0ZXJtaW5hdGVcIiBkaWFtZXRlcj1cIjQwXCI+PC9tYXQtcHJvZ3Jlc3Mtc3Bpbm5lcj5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICA8cCBjbGFzcz1cImNxYS10ZXh0LWdyYXktNDAwIGNxYS10ZXh0LXNtXCI+e3sgbGl2ZUxvYWRpbmdMYWJlbCB9fTwvcD5cbiAgICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgICAgPCEtLSBMaXZlIENvbnRlbnQgKHdoZW4gbm90IGxvYWRpbmcpIC0tPlxuICAgICAgICAgICAgICA8ZGl2ICpuZ0lmPVwiIWlzQ29udGVudFZpZGVvTG9hZGluZ1wiIGNsYXNzPVwiY3FhLXctZnVsbCBjcWEtaC1mdWxsIGNxYS1mbGV4IGNxYS1mbGV4LWNvbCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWNlbnRlciBjcWEtcmVsYXRpdmVcIj5cbiAgICAgICAgICAgICAgICA8ZGl2ICpuZ0lmPVwibGl2ZVN0YXR1cyA9PT0gJ0ZhaWxlZCcgJiYgZmFpbGVkU3RhdHVzTWVzc2FnZVwiIGNsYXNzPVwiY3FhLXAtNiBjcWEtdGV4dC1jZW50ZXIgY3FhLXctZnVsbFwiPlxuICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1pbmxpbmUtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1nYXAtMiBjcWEtcHgtNCBjcWEtcHktMyBjcWEtYmctWyNGQ0Q5RDldIGNxYS1ib3JkZXIgY3FhLWJvcmRlci1bI0Y5QkZCRl0gY3FhLXJvdW5kZWQtbGdcIj5cbiAgICAgICAgICAgICAgICAgICAgPG1hdC1pY29uIHN0eWxlPVwid2lkdGg6IDE4cHg7IGhlaWdodDogMThweDsgY29sb3I6ICNDNjM1MzU7IGZvbnQtc2l6ZTogMThweDtcIj5lcnJvcjwvbWF0LWljb24+XG4gICAgICAgICAgICAgICAgICAgIDxwIGNsYXNzPVwiY3FhLXRleHQtWyNDNjM1MzVdIGNxYS10ZXh0LXNtIGNxYS1mb250LW1lZGl1bSBjcWEtbS0wXCI+e3sgZmFpbGVkU3RhdHVzTWVzc2FnZSB9fTwvcD5cbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDxuZy1jb250ZW50ICpuZ0lmPVwibGl2ZVN0YXR1cyAhPT0gJ0ZhaWxlZCcgfHwgIWZhaWxlZFN0YXR1c01lc3NhZ2VcIj48L25nLWNvbnRlbnQ+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgPC9kaXY+XG5cbiAgICA8IS0tIE5vcm1hbCBWaWRlbyBWaWV3ICh3aGVuIG5vdCBsaXZlKSAtLT5cbiAgICA8ZGl2ICpuZ0lmPVwiIWlzTGl2ZSAmJiBjdXJyZW50VmlldyA9PT0gJ3ZpZGVvJ1wiIGNsYXNzPVwiY3FhLWgtZnVsbCBjcWEtZmxleCBjcWEtZmxleC1jb2xcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJjcWEtdy1mdWxsIGNxYS1weS00IGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLW1heC1oLVtjYWxjKDEwMCUtODNweCldXCIgKm5nSWY9XCJjdXJyZW50VmlkZW9VcmxcIiBbbmdDbGFzc109XCJ7JyFjcWEtaC1mdWxsJzogcGxhdGZvcm1UeXBlID09PSAnZGV2aWNlJywgJ2NxYS1tdC1hdXRvJzogaGFzRGV2aWNlRnJhbWV9XCI+XG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJoYXNEZXZpY2VGcmFtZVwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtdy1mdWxsIGNxYS1oLWZ1bGwgY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1jZW50ZXJcIiBbbmdDbGFzc109XCJ7J2NxYS1wLTQnOiBwbGF0Zm9ybVR5cGUgPT09ICdicm93c2VyJ31cIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtcmVsYXRpdmUgY3FhLWgtZnVsbCBjcWEtdy1hdXRvIGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyIGNxYS1tYXgtaC1mdWxsXCIgW25nQ2xhc3NdPVwieydjcWEtcm91bmRlZC1tZCBjcWEtb3ZlcmZsb3ctaGlkZGVuJzogcGxhdGZvcm1UeXBlID09PSAnYnJvd3NlcicsICdjcWEtbWluLXctbWF4JzogcGxhdGZvcm1UeXBlID09PSAnZGV2aWNlJ31cIj5cbiAgICAgICAgICAgICAgPGltZ1xuICAgICAgICAgICAgICAgIFtzcmNdPVwiZGV2aWNlTW9ja3VwSW1hZ2VcIlxuICAgICAgICAgICAgICAgIGFsdD1cIkRldmljZSBtb2NrdXBcIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwiY3FhLWgtZnVsbCBjcWEtdy1hdXRvIGNxYS1tYXgtaC1mdWxsIGNxYS1vYmplY3QtY29udGFpbiBjcWEtYmxvY2sgY3FhLXBvaW50ZXItZXZlbnRzLW5vbmUgY3FhLXotMTBcIlxuICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLWFic29sdXRlIGNxYS1mbGV4IGNxYS1mbGV4LWNvbFwiIFtuZ1N0eWxlXT1cImRldmljZVNjcmVlblN0eWxlXCIgW25nQ2xhc3NdPVwieydjcWEtYmctd2hpdGUnOiBwbGF0Zm9ybVR5cGUgIT09ICdicm93c2VyJ31cIj5cbiAgICAgICAgICAgICAgICA8dmlkZW9cbiAgICAgICAgICAgICAgICAgICN2cGxheWVyXG4gICAgICAgICAgICAgICAgICBjbGFzcz1cImNxYS1vYmplY3QtY292ZXIgY3FhLXctZnVsbCBjcWEtaC1mdWxsIGNxYS1ibG9jayBjcWEtYmctWyMjRjJGMkYyXVwiXG4gICAgICAgICAgICAgICAgICBbc3JjXT1cImN1cnJlbnRWaWRlb1VybFwiXG4gICAgICAgICAgICAgICAgICB0eXBlPVwidmlkZW8vd2VibVwiXG4gICAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJ7J2NxYS16LTIwJzogcGxhdGZvcm1UeXBlID09PSAnYnJvd3Nlcid9XCJcbiAgICAgICAgICAgICAgICAgIChsb2FkZWRtZXRhZGF0YSk9XCJvblZpZGVvTWV0YWRhdGFMb2FkZWQoKVwiXG4gICAgICAgICAgICAgICAgICAoY2FucGxheSk9XCJvblZpZGVvQ2FuUGxheSgpXCJcbiAgICAgICAgICAgICAgICAgIChlbmRlZCk9XCJvblZpZGVvRW5kZWQoKVwiXG4gICAgICAgICAgICAgICAgPjwvdmlkZW8+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgPC9kaXY+XG4gICAgXG4gICAgICA8ZGl2IGNsYXNzPVwiY3FhLXAtMTAgY3FhLXRleHQtY2VudGVyIGNxYS10ZXh0LWdyYXktNDAwIGNxYS10ZXh0LXNtIGNxYS1oLWZ1bGwgY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1jZW50ZXJcIiAqbmdJZj1cIiFjdXJyZW50VmlkZW9VcmxcIj5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImlzVk5DU2Vzc2lvbkludHJ1cHB0ZWQgJiYgdm5jU2Vzc2lvbkludHVwcHRlZE1lc3NhZ2U7IGVsc2Ugbm9WaWRlb0RlZmF1bHRcIj5cbiAgICAgICAgICA8cCBjbGFzcz1cImNxYS10ZXh0LXNtIGNxYS10ZXh0LWdyYXktNjAwXCI+XG4gICAgICAgICAgICB7eyB2bmNTZXNzaW9uSW50dXBwdGVkTWVzc2FnZSB9fVxuICAgICAgICAgIDwvcD5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgIDxuZy10ZW1wbGF0ZSAjbm9WaWRlb0RlZmF1bHQ+XG4gICAgICAgICAgPHNwYW4+Tm8gdmlkZW8gcmVjb3JkaW5nIGZvdW5kPC9zcGFuPlxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgPC9kaXY+XG4gICAgXG4gICAgICA8ZGl2IGNsYXNzPVwiY3FhLXB4LTIgY3FhLXB5LTIgY3FhLWJnLXdoaXRlXCIgc3R5bGU9XCJib3JkZXItdG9wOiAxcHggc29saWQgI0U1RTdFQjtcIiBbbmdDbGFzc109XCJ7J2NxYS1tdC1hdXRvJzogaGFzRGV2aWNlRnJhbWV9XCIgKm5nSWY9XCJjdXJyZW50VmlkZW9VcmwgJiYgIWlzTGl2ZVwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtZ2FwLTJcIj5cbiAgICAgICAgICA8YnV0dG9uIFxuICAgICAgICAgICAgKm5nSWY9XCJoYXNNdWx0aXBsZVZpZGVvc1wiXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgIGNsYXNzPVwiY3FhLWJnLXRyYW5zcGFyZW50IGNxYS1ib3JkZXItbm9uZSBjcWEtY3Vyc29yLXBvaW50ZXIgIWNxYS1weC0wIGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyIGhvdmVyOmNxYS1vcGFjaXR5LTcwIGNxYS10cmFuc2l0aW9uLW9wYWNpdHkgY3FhLW91dGxpbmUtbm9uZVwiXG4gICAgICAgICAgICBzdHlsZT1cInBvaW50ZXItZXZlbnRzOiBhdXRvO1wiXG4gICAgICAgICAgICBbZGlzYWJsZWRdPVwiY3VycmVudFZpZGVvSW5kZXggPT09IDBcIlxuICAgICAgICAgICAgW25nQ2xhc3NdPVwieydjcWEtb3BhY2l0eS01MCBjcWEtY3Vyc29yLW5vdC1hbGxvd2VkJzogY3VycmVudFZpZGVvSW5kZXggPT09IDB9XCJcbiAgICAgICAgICAgIChjbGljayk9XCJwcmV2VmlkZW8oKVwiXG4gICAgICAgICAgICBtYXRUb29sdGlwPVwiUHJldmlvdXMgdmlkZW9cIlxuICAgICAgICAgICAgbWF0VG9vbHRpcFBvc2l0aW9uPVwiYWJvdmVcIj5cbiAgICAgICAgICAgIDxtYXQtaWNvbiBjbGFzcz1cImNxYS13LTQgY3FhLWgtNCAhY3FhLXRleHQtWzE2cHhdIGNxYS10ZXh0LVsjMzc0MTUxXVwiIFtuZ0NsYXNzXT1cInsnY3FhLW9wYWNpdHktNTAgY3FhLWN1cnNvci1ub3QtYWxsb3dlZCc6IGN1cnJlbnRWaWRlb0luZGV4ID09PSAwfVwiPnNraXBfcHJldmlvdXM8L21hdC1pY29uPlxuICAgICAgICAgIDwvYnV0dG9uPlxuXG4gICAgICAgICAgPGJ1dHRvbiBcbiAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgY2xhc3M9XCJjcWEtYmctdHJhbnNwYXJlbnQgY3FhLWJvcmRlci1ub25lIGNxYS1jdXJzb3ItcG9pbnRlciAhY3FhLXB4LTAgY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1jZW50ZXIgaG92ZXI6Y3FhLW9wYWNpdHktNzAgY3FhLXRyYW5zaXRpb24tb3BhY2l0eSBjcWEtb3V0bGluZS1ub25lXCJcbiAgICAgICAgICAgIHN0eWxlPVwicG9pbnRlci1ldmVudHM6IGF1dG87XCJcbiAgICAgICAgICAgIChjbGljayk9XCJ0b2dnbGVQbGF5KClcIlxuICAgICAgICAgICAgbWF0VG9vbHRpcD1cInt7IGlzUGxheWluZyA/ICdQYXVzZScgOiAnUGxheScgfX1cIlxuICAgICAgICAgICAgbWF0VG9vbHRpcFBvc2l0aW9uPVwiYWJvdmVcIj5cbiAgICAgICAgICAgIDxzcGFuICpuZ0lmPVwiIWlzUGxheWluZ1wiIGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1jZW50ZXJcIj5cbiAgICAgICAgICAgICAgPHN2ZyB3aWR0aD1cIjE2XCIgaGVpZ2h0PVwiMTZcIiB2aWV3Qm94PVwiMCAwIDE2IDE2XCIgZmlsbD1cIm5vbmVcIiB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCI+XG4gICAgICAgICAgICAgICAgPHBhdGggZD1cIk0zIDJMMTMgOEwzIDE0VjJaXCIgZmlsbD1cIiMzNzQxNTFcIi8+XG4gICAgICAgICAgICAgIDwvc3ZnPlxuICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgPHNwYW4gKm5nSWY9XCJpc1BsYXlpbmdcIiBjbGFzcz1cImNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyXCI+XG4gICAgICAgICAgICAgIDxzdmcgd2lkdGg9XCIxNlwiIGhlaWdodD1cIjE2XCIgdmlld0JveD1cIjAgMCAxNiAxNlwiIGZpbGw9XCJub25lXCIgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiPlxuICAgICAgICAgICAgICAgIDxyZWN0IHg9XCIzXCIgeT1cIjJcIiB3aWR0aD1cIjNcIiBoZWlnaHQ9XCIxMlwiIGZpbGw9XCIjMzc0MTUxXCIvPlxuICAgICAgICAgICAgICAgIDxyZWN0IHg9XCIxMFwiIHk9XCIyXCIgd2lkdGg9XCIzXCIgaGVpZ2h0PVwiMTJcIiBmaWxsPVwiIzM3NDE1MVwiLz5cbiAgICAgICAgICAgICAgPC9zdmc+XG4gICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgPC9idXR0b24+XG4gICAgXG4gICAgICAgICAgPGJ1dHRvbiBcbiAgICAgICAgICAgICpuZ0lmPVwiaGFzTXVsdGlwbGVWaWRlb3NcIlxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICBjbGFzcz1cImNxYS1iZy10cmFuc3BhcmVudCBjcWEtYm9yZGVyLW5vbmUgY3FhLWN1cnNvci1wb2ludGVyICFjcWEtcHgtMCBjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWNlbnRlciBob3ZlcjpjcWEtb3BhY2l0eS03MCBjcWEtdHJhbnNpdGlvbi1vcGFjaXR5IGNxYS1vdXRsaW5lLW5vbmVcIlxuICAgICAgICAgICAgc3R5bGU9XCJwb2ludGVyLWV2ZW50czogYXV0bztcIlxuICAgICAgICAgICAgW2Rpc2FibGVkXT1cInZpZGVvVXJscyAmJiAoY3VycmVudFZpZGVvSW5kZXggPj0gdmlkZW9VcmxzLmxlbmd0aCAtIDEpXCJcbiAgICAgICAgICAgIFtuZ0NsYXNzXT1cInsnY3FhLW9wYWNpdHktNTAgY3FhLWN1cnNvci1ub3QtYWxsb3dlZCc6IHZpZGVvVXJscyAmJiAoY3VycmVudFZpZGVvSW5kZXggPj0gdmlkZW9VcmxzLmxlbmd0aCAtIDEpfVwiXG4gICAgICAgICAgICAoY2xpY2spPVwibmV4dFZpZGVvKClcIlxuICAgICAgICAgICAgbWF0VG9vbHRpcD1cIk5leHQgdmlkZW9cIlxuICAgICAgICAgICAgbWF0VG9vbHRpcFBvc2l0aW9uPVwiYWJvdmVcIj5cbiAgICAgICAgICAgIDxtYXQtaWNvbiBjbGFzcz1cImNxYS13LTQgY3FhLWgtNCAhY3FhLXRleHQtWzE2cHhdIGNxYS10ZXh0LVsjMzc0MTUxXVwiIFtuZ0NsYXNzXT1cInsnY3FhLW9wYWNpdHktNTAgY3FhLWN1cnNvci1ub3QtYWxsb3dlZCc6IHZpZGVvVXJscyAmJiAoY3VycmVudFZpZGVvSW5kZXggPj0gdmlkZW9VcmxzLmxlbmd0aCAtIDEpfVwiPnNraXBfbmV4dDwvbWF0LWljb24+XG4gICAgICAgICAgPC9idXR0b24+XG5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cImNxYS10ZXh0LVsjOUNBM0FGXSBjcWEtdGV4dC1bOXB4XSBjcWEtZm9udC1ub3JtYWwgY3FhLXdoaXRlc3BhY2Utbm93cmFwIGNxYS1zZWxlY3Qtbm9uZVwiPlxuICAgICAgICAgICAge3sgZm9ybWF0VGltZSh2cGxheWVyPy5uYXRpdmVFbGVtZW50Py5jdXJyZW50VGltZSB8fCAwKSB9fVxuICAgICAgICAgIDwvc3Bhbj5cblxuICAgICAgICAgIDxkaXYgI3NwZWVkQ29udHJvbENvbnRhaW5lciBjbGFzcz1cImNxYS1yZWxhdGl2ZSBjcWEtbXItWzhweF0gY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1jZW50ZXJcIj5cbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgIGNsYXNzPVwiY3FhLWJnLXRyYW5zcGFyZW50IGNxYS1ib3JkZXItbm9uZSBjcWEtY3Vyc29yLXBvaW50ZXIgY3FhLXRleHQtWyM5Q0EzQUZdIGNxYS10ZXh0LVsxMHB4XSBjcWEtbGVhZGluZy1bMTVweF0gY3FhLWZvbnQtbWVkaXVtIGNxYS13aGl0ZXNwYWNlLW5vd3JhcCBjcWEtc2VsZWN0LW5vbmUgaG92ZXI6Y3FhLW9wYWNpdHktNzAgY3FhLXRyYW5zaXRpb24tb3BhY2l0eSBjcWEtb3V0bGluZS1ub25lIGNxYS1weC0xXCJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cInRvZ2dsZVNwZWVkQ29udHJvbCgpXCJcbiAgICAgICAgICAgICAgW21hdFRvb2x0aXBdPVwiJ1BsYXliYWNrIFNwZWVkJ1wiXG4gICAgICAgICAgICAgIFttYXRUb29sdGlwUG9zaXRpb25dPVwiJ2JlbG93J1wiPlxuICAgICAgICAgICAgICB7eyBjdXJyZW50U3BlZWQgfX1cbiAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgXG4gICAgICAgICAgICA8ZGl2IFxuICAgICAgICAgICAgICAqbmdJZj1cImlzU3BlZWRDb250cm9sT3BlblwiXG4gICAgICAgICAgICAgIGNsYXNzPVwiY3FhLWFic29sdXRlIGNxYS1ib3R0b20tZnVsbCBjcWEtbWItMiBjcWEtcmlnaHQtMCBjcWEtYmctWyNGMEYwRjFdIGNxYS1yb3VuZGVkLWxnIGNxYS1vdmVyZmxvdy1oaWRkZW4gY3FhLXNoYWRvdy1sZyBjcWEtei01MFwiXG4gICAgICAgICAgICAgIHN0eWxlPVwibWluLXdpZHRoOiBtYXgtY29udGVudDsgbGVmdDogNTAlOyBib3R0b206IDAlOyB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAtNTAlKTtcIj5cbiAgICAgICAgICAgICAgPGNxYS1zZWdtZW50LWNvbnRyb2xcbiAgICAgICAgICAgICAgICBbc2VnbWVudHNdPVwic3BlZWRTZWdtZW50c1wiXG4gICAgICAgICAgICAgICAgW3ZhbHVlXT1cImN1cnJlbnRTcGVlZFwiXG4gICAgICAgICAgICAgICAgW2NvbnRhaW5lckJnQ29sb3JdPVwiJyNGMEYwRjEnXCJcbiAgICAgICAgICAgICAgICAodmFsdWVDaGFuZ2UpPVwib25TcGVlZENoYW5nZSgkZXZlbnQpXCI+XG4gICAgICAgICAgICAgIDwvY3FhLXNlZ21lbnQtY29udHJvbD5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDwvZGl2PlxuICAgIFxuICAgICAgICAgIDxkaXYgXG4gICAgICAgICAgICAjdGltZWxpbmVCYXJcbiAgICAgICAgICAgIGNsYXNzPVwiY3FhLXJlbGF0aXZlIGNxYS1oLTEgY3FhLWJnLWdyYXktMjAwIGNxYS1yb3VuZGVkLWZ1bGwgY3FhLWN1cnNvci1wb2ludGVyIGNxYS1mbGV4LTFcIlxuICAgICAgICAgICAgKGNsaWNrKT1cIm9uVGltZWxpbmVDbGljaygkZXZlbnQpXCI+XG4gICAgICAgICAgICBcbiAgICAgICAgICAgIDxkaXYgXG4gICAgICAgICAgICAgICpuZ0Zvcj1cImxldCBzdGVwIG9mIHN0ZXBNYXJrZXJzXCIgXG4gICAgICAgICAgICAgIGNsYXNzPVwiY3FhLWFic29sdXRlIGNxYS13LTEgY3FhLWgtZnVsbCBjcWEtdG9wLTAgY3FhLXJvdW5kZWQtc21cIlxuICAgICAgICAgICAgICBbc3R5bGUubGVmdC4lXT1cImdldFN0ZXBMZWZ0UG9zaXRpb24oc3RlcClcIlxuICAgICAgICAgICAgICBbc3R5bGUuYmFja2dyb3VuZF09XCJnZXRTdGVwQ29sb3Ioc3RlcClcIlxuICAgICAgICAgICAgICBzdHlsZT1cInBvaW50ZXItZXZlbnRzOiBub25lOyB6LWluZGV4OiAyMDtcIj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgXG4gICAgICAgICAgICA8ZGl2IFxuICAgICAgICAgICAgICBjbGFzcz1cImNxYS1hYnNvbHV0ZSBjcWEtbGVmdC0wIGNxYS10b3AtMCBjcWEtaC1mdWxsIGNxYS1iZy1ibHVlLTUwMCBjcWEtcm91bmRlZC1mdWxsXCJcbiAgICAgICAgICAgICAgW3N0eWxlLndpZHRoLiVdPVwicHJvZ3Jlc3NcIlxuICAgICAgICAgICAgICBbc3R5bGUudHJhbnNpdGlvbl09XCJkcmFnZ2luZyA/ICdub25lJyA6ICd3aWR0aCAxMDBtcydcIlxuICAgICAgICAgICAgICBzdHlsZT1cInBvaW50ZXItZXZlbnRzOiBub25lOyB6LWluZGV4OiAyO1wiPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICBcbiAgICAgICAgICAgIDxkaXYgXG4gICAgICAgICAgICAgIGNsYXNzPVwiY3FhLWFic29sdXRlIGNxYS10b3AtMS8yIGNxYS13LTMgY3FhLWgtMyBjcWEtYmctYmx1ZS02MDAgY3FhLXJvdW5kZWQtZnVsbCBjcWEtY3Vyc29yLWdyYWIgYWN0aXZlOmNxYS1jdXJzb3ItZ3JhYmJpbmcgY3FhLXNoYWRvdy1tZFwiXG4gICAgICAgICAgICAgIFtzdHlsZS5sZWZ0LiVdPVwicHJvZ3Jlc3NcIlxuICAgICAgICAgICAgICBzdHlsZT1cInRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC01MCUpOyB6LWluZGV4OiA0MDtcIlxuICAgICAgICAgICAgICAobW91c2Vkb3duKT1cInN0YXJ0RHJhZygkZXZlbnQpXCI+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDxkaXYgKm5nSWY9XCIhaXNMaXZlICYmIGN1cnJlbnRWaWV3ID09PSAnc2NyZWVuc2hvdHMnXCIgY2xhc3M9XCJjcWEtaC1mdWxsXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiY3FhLXctZnVsbCBjcWEtcHktNCBjcWEtaC1mdWxsIGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXJcIiAqbmdJZj1cInNjcmVlblNob3RVcmxcIj5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImhhc0RldmljZUZyYW1lXCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS13LWZ1bGwgY3FhLWgtZnVsbCBjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWNlbnRlclwiIFtuZ0NsYXNzXT1cInsnY3FhLXAtNCc6IHBsYXRmb3JtVHlwZSA9PT0gJ2Jyb3dzZXInfVwiPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1yZWxhdGl2ZSBjcWEtaC1mdWxsIGNxYS13LWF1dG8gY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1jZW50ZXIgY3FhLW1heC1oLWZ1bGxcIiBbbmdDbGFzc109XCJ7J2NxYS1yb3VuZGVkLW1kIGNxYS1vdmVyZmxvdy1oaWRkZW4nOiBwbGF0Zm9ybVR5cGUgPT09ICdicm93c2VyJywgJ2NxYS1taW4tdy1tYXgnOiBwbGF0Zm9ybVR5cGUgPT09ICdkZXZpY2UnfVwiPlxuICAgICAgICAgICAgICA8aW1nXG4gICAgICAgICAgICAgICAgW3NyY109XCJkZXZpY2VNb2NrdXBJbWFnZVwiXG4gICAgICAgICAgICAgICAgYWx0PVwiRGV2aWNlIG1vY2t1cFwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJjcWEtaC1mdWxsIGNxYS13LWF1dG8gY3FhLW9iamVjdC1jb250YWluIGNxYS1ibG9jayBjcWEtcG9pbnRlci1ldmVudHMtbm9uZSBjcWEtei0xMFwiXG4gICAgICAgICAgICAgICAgW25nQ2xhc3NdPVwieydjcWEtbWF4LWgtW2luaGVyaXRdJzogcGxhdGZvcm1UeXBlID09PSAnYnJvd3NlcicsICdjcWEtbWF4LWgtZnVsbCc6IHBsYXRmb3JtVHlwZSAhPT0gJ2Jyb3dzZXInfVwiXG4gICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtYWJzb2x1dGUgY3FhLWZsZXggY3FhLWZsZXgtY29sXCIgW25nU3R5bGVdPVwiZGV2aWNlU2NyZWVuU3R5bGVcIiBbbmdDbGFzc109XCJ7J2NxYS1iZy13aGl0ZSc6IHBsYXRmb3JtVHlwZSAhPT0gJ2Jyb3dzZXInfVwiPlxuICAgICAgICAgICAgICAgIDxpbWdcbiAgICAgICAgICAgICAgICAgIFtzcmNdPVwic2NyZWVuU2hvdFVybFwiXG4gICAgICAgICAgICAgICAgICBhbHQ9XCJTY3JlZW5zaG90XCJcbiAgICAgICAgICAgICAgICAgIFtuZ0NsYXNzXT1cInsnY3FhLXotMjAnOiBwbGF0Zm9ybVR5cGUgPT09ICdicm93c2VyJ31cIlxuICAgICAgICAgICAgICAgICAgY2xhc3M9XCJjcWEtb2JqZWN0LWNvbnRhaW4gY3FhLXctZnVsbCBjcWEtaC1mdWxsIGNxYS1ibG9jayBjcWEtYmctWyMjRjJGMkYyXVwiXG4gICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICA8L2Rpdj5cbiAgICBcbiAgICAgIDxkaXYgY2xhc3M9XCJjcWEtcC0xMCBjcWEtdGV4dC1jZW50ZXIgY3FhLXRleHQtZ3JheS00MDAgY3FhLXRleHQtc20gY3FhLWgtZnVsbCBjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWNlbnRlclwiICpuZ0lmPVwiIXNjcmVlblNob3RVcmxcIj5cbiAgICAgICAgTm8gc2NyZWVuc2hvdCBhdmFpbGFibGVcbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiAqbmdJZj1cIiFpc0xpdmUgJiYgY3VycmVudFZpZXcgPT09ICd0cmFjZSdcIiBjbGFzcz1cImNxYS1oLWZ1bGwgY3FhLWZsZXggY3FhLWZsZXgtY29sIGNxYS1qdXN0aWZ5LWNlbnRlclwiPlxuICAgICAgPGRpdiBjbGFzcz1cImNxYS13LWZ1bGwgY3FhLWgtZnVsbCBjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1yZWxhdGl2ZVwiICpuZ0lmPVwidHJhY2VWaWV3VXJsXCIgW25nQ2xhc3NdPVwieychY3FhLWgtZnVsbCc6IHBsYXRmb3JtVHlwZSA9PT0gJ2RldmljZSd9XCIgc3R5bGU9XCJwYWRkaW5nLXRvcDogNDhweDsgcGFkZGluZy1ib3R0b206IDBweDtcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImNxYS13LWZ1bGwgY3FhLWgtZnVsbCBjcWEtb3ZlcmZsb3ctaGlkZGVuIGNxYS1yZWxhdGl2ZVwiPlxuICAgICAgICAgIDxpZnJhbWUgXG4gICAgICAgICAgICBbc3JjXT1cInNhZmVUcmFjZVVybFwiIFxuICAgICAgICAgICAgdGl0bGU9XCJUcmFjZSBWaWV3ZXJcIlxuICAgICAgICAgICAgY2xhc3M9XCJjcWEtb2JqZWN0LWNvbnRhaW4gY3FhLXctZnVsbCBjcWEtbWluLWgtWzI1MHB4XSBjcWEtbWF4LWgtZnVsbCBjcWEtYmxvY2sgY3FhLWJnLVsjI0YyRjJGMl1cIlxuICAgICAgICAgICAgc3R5bGU9XCJtYXJnaW4tdG9wOiAtNDhweDsgaGVpZ2h0OiBjYWxjKDEwMCUgKyA0OHB4KTtcIlxuICAgICAgICAgICAgZnJhbWVib3JkZXI9XCIwXCJcbiAgICAgICAgICAgIGFsbG93ZnVsbHNjcmVlblxuICAgICAgICAgICAgd2lkdGg9XCIxMDAlXCJcbiAgICAgICAgICAgIGxvYWRpbmc9XCJsYXp5XCJcbiAgICAgICAgICAgIChsb2FkKT1cIm9uVHJhY2VWaWV3ZXJMb2FkKClcIlxuICAgICAgICAgICAgKGVycm9yKT1cIm9uVHJhY2VWaWV3ZXJFcnJvcigpXCI+XG4gICAgICAgICAgPC9pZnJhbWU+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICBcbiAgICAgICAgPGRpdiAqbmdJZj1cInRyYWNlVmlld2VyTG9hZGluZ1wiIGNsYXNzPVwiY3FhLWFic29sdXRlIGNxYS1pbnNldC0wIGNxYS1iZy1bI0YzRjRGNl0gY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1jZW50ZXIgY3FhLXotMTBcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXRleHQtY2VudGVyIGNxYS10ZXh0LWdyYXktNDAwIGNxYS10ZXh0LXNtXCI+XG4gICAgICAgICAgICBMb2FkaW5nIHRyYWNlIHZpZXdlci4uLlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgXG4gICAgICAgIDxkaXYgKm5nSWY9XCJ0cmFjZVZpZXdlckVycm9yXCIgY2xhc3M9XCJjcWEtYWJzb2x1dGUgY3FhLWluc2V0LTAgY3FhLWJnLVsjRjNGNEY2XSBjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWNlbnRlciBjcWEtei0xMFwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtdGV4dC1jZW50ZXIgY3FhLXRleHQtZ3JheS00MDAgY3FhLXRleHQtc21cIj5cbiAgICAgICAgICAgIEZhaWxlZCB0byBsb2FkIHRyYWNlIHZpZXdlclxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIFxuICAgICAgPGRpdiBjbGFzcz1cImNxYS1wLTEwIGNxYS10ZXh0LWNlbnRlciBjcWEtdGV4dC1ncmF5LTQwMCBjcWEtdGV4dC1zbSBjcWEtaC1mdWxsIGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyXCIgKm5nSWY9XCIhdHJhY2VWaWV3VXJsXCI+XG4gICAgICAgIE5vIHRyYWNlIGF2YWlsYWJsZVxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+ICBcbiAgPC9kaXY+XG48L2Rpdj4iXX0=
|
|
1797
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2ltdWxhdG9yLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc2ltdWxhdG9yL3NpbXVsYXRvci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NpbXVsYXRvci9zaW11bGF0b3IuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQWtFLE1BQU0sZUFBZSxDQUFDO0FBRWxKLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDhDQUE4QyxDQUFDOzs7Ozs7OztBQW1DbkYsTUFBTSxPQUFPLGtCQUFrQjtJQThPN0IsWUFBb0IsU0FBdUI7UUFBdkIsY0FBUyxHQUFULFNBQVMsQ0FBYztRQTVPbEMsYUFBUSxHQUFXLEVBQUUsQ0FBQztRQUN0QixjQUFTLEdBQWEsRUFBRSxDQUFDO1FBQ3pCLHlCQUFvQixHQUFXLENBQUMsQ0FBQztRQUNqQyxnQkFBVyxHQUFpQixFQUFFLENBQUM7UUFDL0Isa0JBQWEsR0FBVyxFQUFFLENBQUM7UUFDM0IsaUJBQVksR0FBVyxFQUFFLENBQUM7UUFDMUIsaUJBQVksR0FBVyxjQUFjLENBQUM7UUFDdEMsaUJBQVksR0FBeUIsU0FBUyxDQUFDO1FBQy9DLGFBQVEsR0FBVyxFQUFFLENBQUM7UUFDdEIsZUFBVSxHQUFrQixJQUFJLENBQUM7UUFDakMsV0FBTSxHQUFZLEtBQUssQ0FBQztRQUN4QixlQUFVLEdBQTZFLGFBQWEsQ0FBQztRQUNyRyxxQkFBZ0IsR0FBVyxZQUFZLENBQUM7UUFDeEMsMEJBQXFCLEdBQVksS0FBSyxDQUFDO1FBQ3ZDLHdCQUFtQixHQUFXLEVBQUUsQ0FBQztRQUNqQywyQkFBc0IsR0FBWSxLQUFLLENBQUM7UUFDeEMsK0JBQTBCLEdBQVcsRUFBRSxDQUFDO1FBQ3hDLGlCQUFZLEdBQWdCLE9BQU8sQ0FBQztRQUNwQyxpQkFBWSxHQUFZLEtBQUssQ0FBQztRQUM5QixvQkFBZSxHQUE2QyxJQUFJLENBQUM7UUFFaEUsb0JBQWUsR0FBRyxJQUFJLFlBQVksRUFBVSxDQUFDO1FBQzdDLGNBQVMsR0FBRyxJQUFJLFlBQVksRUFBUSxDQUFDO1FBQ3JDLGVBQVUsR0FBRyxJQUFJLFlBQVksRUFBUSxDQUFDO1FBQ3RDLGNBQVMsR0FBRyxJQUFJLFlBQVksRUFBYyxDQUFDO1FBQzNDLHlCQUFvQixHQUFHLElBQUksWUFBWSxFQUFXLENBQUM7UUF3QzdELGFBQVEsR0FBRyxDQUFDLENBQUM7UUFDYixhQUFRLEdBQUcsS0FBSyxDQUFDO1FBQ2pCLGNBQVMsR0FBWSxLQUFLLENBQUM7UUFDM0IsaUJBQVksR0FBWSxLQUFLLENBQUM7UUFDOUIsZ0JBQVcsR0FBVyxPQUFPLENBQUM7UUFDOUIsc0JBQWlCLEdBQVcsQ0FBQyxDQUFDO1FBQzlCLGlCQUFZLEdBQVcsSUFBSSxDQUFDO1FBQzVCLHVCQUFrQixHQUFZLEtBQUssQ0FBQztRQUM1QiwyQkFBc0IsR0FBYSxFQUFFLENBQUMsQ0FBQyxnREFBZ0Q7UUFDdkYseUJBQW9CLEdBQVksS0FBSyxDQUFDLENBQUMsaURBQWlEO1FBQ3hGLGdCQUFXLEdBQXlCLElBQUksQ0FBQyxDQUFDLGlDQUFpQztRQUMzRSxlQUFVLEdBQWdCLElBQUksR0FBRyxFQUFFLENBQUMsQ0FBQyxvREFBb0Q7UUFFakcsNENBQTRDO1FBQ3BDLGdCQUFXLEdBQTRGLE1BQU0sQ0FBQztRQUM5RyxtQkFBYyxHQUFrQixPQUFPLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxpQ0FBaUM7UUFVNUYsYUFBUSxHQUFvQjtZQUMxQixFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUUsS0FBSyxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFHO1lBQzlELEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUU7U0FDckQsQ0FBQztRQUVGLGtCQUFhLEdBQW9CO1lBQy9CLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFO1lBQzVCLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFO1lBQzVCLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFO1NBQzdCLENBQUM7UUFFTSw4QkFBeUIsR0FBd0IsSUFBSSxDQUFDO1FBQ3RELG9CQUFlLEdBQVcsQ0FBQyxDQUFDLENBQUM7UUFDN0IseUJBQW9CLEdBQXFDLElBQUksQ0FBQztRQUM5RCx1QkFBa0IsR0FBcUMsSUFBSSxDQUFDO1FBQzVELG9DQUErQixHQUFxQyxJQUFJLENBQUM7UUFDekUsd0JBQW1CLEdBQTRCLElBQUksQ0FBQztRQUNwRCwyQkFBc0IsR0FBNEIsSUFBSSxDQUFDO1FBQ3ZELGlDQUE0QixHQUFrQixJQUFJLENBQUM7UUFHM0QsdUJBQWtCLEdBQVksS0FBSyxDQUFDO1FBQ3BDLHFCQUFnQixHQUFZLEtBQUssQ0FBQztRQUNsQyxrQ0FBNkIsR0FBWSxLQUFLLENBQUM7UUFDOUIscUJBQWdCLEdBQUcsbUJBQW1CLENBQUMsa0JBQWtCLENBQUMsQ0FBQztRQUNuRSxnQ0FBMkIsR0FBRztZQUNyQyxHQUFHLElBQUksQ0FBQyxnQkFBZ0I7WUFDeEIsS0FBSyxFQUFFLHNCQUFzQjtZQUM3QixXQUFXLEVBQUUsb0RBQW9EO1lBQ2pFLE9BQU8sRUFBRSxFQUFFO1NBQ1osQ0FBQztRQW1CZSx1QkFBa0IsR0FBc0M7WUFDdkUsU0FBUztZQUNULFNBQVMsRUFBRTtnQkFDVCxXQUFXLEVBQUUsbUNBQW1DO2dCQUNoRCxXQUFXLEVBQUU7b0JBQ1gsR0FBRyxFQUFFLElBQUk7b0JBQ1QsS0FBSyxFQUFFLE1BQU07b0JBQ2IsTUFBTSxFQUFFLElBQUk7b0JBQ1osSUFBSSxFQUFFLE1BQU07aUJBQ2I7Z0JBQ0QsWUFBWSxFQUFFLElBQUk7YUFDbkI7WUFDRCxTQUFTLEVBQUU7Z0JBQ1QsV0FBVyxFQUFFLG1DQUFtQztnQkFDaEQsV0FBVyxFQUFFO29CQUNYLEdBQUcsRUFBRSxJQUFJO29CQUNULEtBQUssRUFBRSxNQUFNO29CQUNiLE1BQU0sRUFBRSxNQUFNO29CQUNkLElBQUksRUFBRSxNQUFNO2lCQUNiO2dCQUNELFlBQVksRUFBRSxJQUFJO2FBQ25CO1lBQ0QsU0FBUyxFQUFFO2dCQUNULFdBQVcsRUFBRSx3Q0FBd0M7Z0JBQ3JELFdBQVcsRUFBRTtvQkFDWCxHQUFHLEVBQUUsSUFBSTtvQkFDVCxLQUFLLEVBQUUsSUFBSTtvQkFDWCxNQUFNLEVBQUUsSUFBSTtvQkFDWixJQUFJLEVBQUUsSUFBSTtpQkFDWDtnQkFDRCxZQUFZLEVBQUUsSUFBSTthQUNuQjtZQUNELFVBQVU7WUFDVixXQUFXLEVBQUU7Z0JBQ1gsV0FBVyxFQUFFLDJDQUEyQztnQkFDeEQsV0FBVyxFQUFFO29CQUNYLEdBQUcsRUFBRSxJQUFJO29CQUNULEtBQUssRUFBRSxNQUFNO29CQUNiLE1BQU0sRUFBRSxJQUFJO29CQUNaLElBQUksRUFBRSxNQUFNO2lCQUNiO2dCQUNELFlBQVksRUFBRSxJQUFJO2FBQ25CO1lBQ0QsV0FBVyxFQUFFO2dCQUNYLFdBQVcsRUFBRSwyQ0FBMkM7Z0JBQ3hELFdBQVcsRUFBRTtvQkFDWCxHQUFHLEVBQUUsSUFBSTtvQkFDVCxLQUFLLEVBQUUsSUFBSTtvQkFDWCxNQUFNLEVBQUUsSUFBSTtvQkFDWixJQUFJLEVBQUUsSUFBSTtpQkFDWDtnQkFDRCxZQUFZLEVBQUUsSUFBSTthQUNuQjtZQUNELFdBQVcsRUFBRTtnQkFDWCxXQUFXLEVBQUUsMkNBQTJDO2dCQUN4RCxXQUFXLEVBQUU7b0JBQ1gsR0FBRyxFQUFFLE1BQU07b0JBQ1gsS0FBSyxFQUFFLE1BQU07b0JBQ2IsTUFBTSxFQUFFLE1BQU07b0JBQ2QsSUFBSSxFQUFFLE1BQU07aUJBQ2I7Z0JBQ0QsWUFBWSxFQUFFLElBQUk7YUFDbkI7WUFDRCxXQUFXLEVBQUU7Z0JBQ1gsV0FBVyxFQUFFLDJDQUEyQztnQkFDeEQsV0FBVyxFQUFFO29CQUNYLEdBQUcsRUFBRSxNQUFNO29CQUNYLEtBQUssRUFBRSxNQUFNO29CQUNiLE1BQU0sRUFBRSxNQUFNO29CQUNkLElBQUksRUFBRSxNQUFNO2lCQUNiO2dCQUNELFlBQVksRUFBRSxJQUFJO2FBQ25CO1lBRUQsZUFBZSxFQUFFO2dCQUNmLFdBQVcsRUFBRSw4Q0FBOEM7Z0JBQzNELFdBQVcsRUFBRTtvQkFDWCxHQUFHLEVBQUUsTUFBTTtvQkFDWCxLQUFLLEVBQUUsSUFBSTtvQkFDWCxNQUFNLEVBQUUsTUFBTTtvQkFDZCxJQUFJLEVBQUUsSUFBSTtpQkFDWDtnQkFDRCxZQUFZLEVBQUUsSUFBSTthQUNuQjtZQUVELE9BQU8sRUFBRTtnQkFDUCxXQUFXLEVBQUUsMENBQTBDO2dCQUN2RCxXQUFXLEVBQUU7b0JBQ1gsR0FBRyxFQUFFLElBQUk7b0JBQ1QsS0FBSyxFQUFFLElBQUk7b0JBQ1gsTUFBTSxFQUFFLElBQUk7b0JBQ1osSUFBSSxFQUFFLElBQUk7aUJBQ1g7Z0JBQ0QsWUFBWSxFQUFFLElBQUk7YUFDbkI7U0FDRixDQUFDO1FBR0EsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLDhCQUE4QixDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3RFLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztJQUN4QixDQUFDO0lBbE5ELElBQ0ksVUFBVSxDQUFDLEdBQTZDO1FBQzFELElBQUksQ0FBQyxHQUFHO1lBQUUsT0FBTztRQUVqQixJQUFJLENBQUMsUUFBUSxHQUFHLEdBQUcsQ0FBQztRQUNwQixJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztJQUM3QixDQUFDO0lBRUQsSUFBSSxPQUFPO1FBQ1QsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDO0lBQ3ZCLENBQUM7SUFJRCxJQUNJLGNBQWMsQ0FBQyxHQUEyQztRQUM1RCxJQUFJLENBQUMsR0FBRztZQUFFLE9BQU87UUFDakIsSUFBSSxDQUFDLFlBQVksR0FBRyxHQUFHLENBQUM7SUFDMUIsQ0FBQztJQUVELElBQUksV0FBVztRQUNiLE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQztJQUMzQixDQUFDO0lBSUQsSUFDSSx3QkFBd0IsQ0FBQyxHQUEyQztRQUN0RSxJQUFJLENBQUMsR0FBRztZQUFFLE9BQU87UUFDakIsSUFBSSxDQUFDLHNCQUFzQixHQUFHLEdBQUcsQ0FBQztJQUNwQyxDQUFDO0lBRUQsSUFBSSxxQkFBcUI7UUFDdkIsT0FBTyxJQUFJLENBQUMsc0JBQXNCLENBQUM7SUFDckMsQ0FBQztJQW1CRCxJQUFJLGNBQWM7UUFDaEIsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDO0lBQ2xDLENBQUM7SUFFRCxJQUFJLGlCQUFpQjtRQUNuQixPQUFPLElBQUksQ0FBQyxXQUFXLEtBQUssV0FBVyxDQUFDO0lBQzFDLENBQUM7SUFrQ0QsSUFBSSx3QkFBd0I7UUFDMUIsTUFBTSxlQUFlLEdBQUcsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQztRQUVyRCxJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRTtZQUN6QixPQUFPLGVBQWUsQ0FBQztTQUN4QjtRQUVELE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBRSxJQUFJLENBQUMsZUFBdUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMxRCxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUUsSUFBSSxDQUFDLGVBQXVCLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFNUQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDLElBQUksTUFBTSxJQUFJLENBQUMsRUFBRTtZQUNwRixPQUFPLGVBQWUsQ0FBQztTQUN4QjtRQUVELE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUM7SUFDM0IsQ0FBQztJQXdHRCxJQUFZLGlCQUFpQjtRQUMzQixJQUFJLElBQUksQ0FBQyxZQUFZLEtBQUssU0FBUyxFQUFFO1lBQ25DLE9BQU8sSUFBSSxDQUFDLGtCQUFrQixDQUFDLFNBQVMsQ0FBQyxJQUFJLElBQUksQ0FBQztTQUNuRDtRQUVELElBQUksSUFBSSxDQUFDLFlBQVksS0FBSyxRQUFRLEVBQUU7WUFDbEMsZ0VBQWdFO1lBQ2hFLElBQUksSUFBSSxDQUFDLFVBQVUsSUFBSSxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxFQUFFO2dCQUMvRCxPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7YUFDakQ7WUFFRCx1RkFBdUY7WUFDdkYsSUFBSSxJQUFJLENBQUMsUUFBUSxLQUFLLFNBQVMsRUFBRTtnQkFDL0IsT0FBTyxJQUFJLENBQUMsa0JBQWtCLENBQUMsU0FBUyxDQUFDLElBQUksSUFBSSxDQUFDO2FBQ25EO1lBQ0QsSUFBSSxJQUFJLENBQUMsUUFBUSxLQUFLLEtBQUssRUFBRTtnQkFDM0IsT0FBTyxJQUFJLENBQUMsa0JBQWtCLENBQUMsV0FBVyxDQUFDLElBQUksSUFBSSxDQUFDO2FBQ3JEO1lBRUQsT0FBTyxJQUFJLENBQUM7U0FDYjtRQUVELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELElBQUksaUJBQWlCO1FBQ25CLE9BQU8sSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7SUFDMUUsQ0FBQztJQUVELElBQUksaUJBQWlCO1FBQ25CLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQztRQUNuQyxJQUFJLENBQUMsR0FBRyxFQUFFO1lBQ1IsT0FBTyxFQUFFLENBQUM7U0FDWDtRQUVELE9BQU87WUFDTCxRQUFRLEVBQUUsVUFBVTtZQUNwQixHQUFHLEVBQUUsR0FBRyxDQUFDLFdBQVcsQ0FBQyxHQUFHO1lBQ3hCLEtBQUssRUFBRSxHQUFHLENBQUMsV0FBVyxDQUFDLEtBQUs7WUFDNUIsTUFBTSxFQUFFLEdBQUcsQ0FBQyxXQUFXLENBQUMsTUFBTTtZQUM5QixJQUFJLEVBQUUsR0FBRyxDQUFDLFdBQVcsQ0FBQyxJQUFJO1lBQzFCLGVBQWUsRUFBRSxHQUFHLENBQUMsWUFBWTtZQUNqQyxRQUFRLEVBQUUsUUFBUTtTQUNuQixDQUFDO0lBQ0osQ0FBQztJQUVELGVBQWU7UUFDYixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUM7UUFDckMsSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUM7UUFDNUIsSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7SUFDNUIsQ0FBQztJQUVELFdBQVcsQ0FBQyxPQUFzQjtRQUNoQyxJQUFJLE9BQU8sQ0FBQyxXQUFXLENBQUMsRUFBRTtZQUN4QixNQUFNLEdBQUcsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUMsWUFBb0MsQ0FBQztZQUN0RSxJQUFJLEdBQUcsSUFBSSxHQUFHLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtnQkFDekIsSUFBSSxDQUFDLGlCQUFpQixHQUFHLENBQUMsQ0FBQztnQkFDM0IsSUFBSSxDQUFDLG9CQUFvQixDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUMvQixJQUFJLENBQUMsMEJBQTBCLENBQUMsR0FBRyxDQUFDLENBQUM7YUFDdEM7U0FDRjtRQUNELElBQUksT0FBTyxDQUFDLHNCQUFzQixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsc0JBQXNCLENBQUMsQ0FBQyxXQUFXLEVBQUU7WUFDbkYsTUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLHNCQUFzQixDQUFDLENBQUMsWUFBWSxDQUFDO1lBQ2pFLDREQUE0RDtZQUM1RCxJQUFJLFdBQVcsS0FBSyxDQUFDLENBQUMsRUFBRTtnQkFDdEIsT0FBTzthQUNSO1lBRUQsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFO2dCQUNsQixJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQ2xCLE9BQU8sQ0FBQyxHQUFHLENBQUMsMkVBQTJFLENBQUMsQ0FBQzthQUMxRjtZQUVELElBQUksSUFBSSxDQUFDLGlCQUFpQixFQUFFO2dCQUMxQixNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxXQUFXLENBQUMsQ0FBQztnQkFDdEUsSUFBSSxnQkFBZ0IsS0FBSyxJQUFJLEVBQUU7b0JBQzdCLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQywwQkFBMEIsRUFBRSxDQUFDO29CQUNyRCxNQUFNLGNBQWMsR0FBRyxVQUFVLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztvQkFDcEQsTUFBTSxpQkFBaUIsR0FBRyxXQUFXLEdBQUcsY0FBYyxDQUFDLEtBQUssQ0FBQztvQkFFN0QsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixLQUFLLGdCQUFnQixDQUFDO29CQUVoRSxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsYUFBYSxFQUFFO3dCQUMvQixNQUFNLGtCQUFrQixHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7d0JBQ3pFLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsaUJBQWlCLEdBQUcsa0JBQWtCLENBQUMsQ0FBQzt3QkFFeEUsSUFBSSxXQUFXLElBQUksV0FBVyxLQUFLLElBQUksQ0FBQyxlQUFlLElBQUksY0FBYyxHQUFHLEdBQUcsRUFBRTs0QkFDL0UsSUFBSSxDQUFDLG9CQUFvQixDQUFDLFdBQVcsQ0FBQyxDQUFDO3lCQUN4QztxQkFDRjt5QkFBTTt3QkFDTCxJQUFJLFdBQVcsRUFBRTs0QkFDZixJQUFJLENBQUMsaUJBQWlCLEdBQUcsZ0JBQWdCLENBQUM7eUJBQzNDO3FCQUNGO2lCQUNGO2FBQ0Y7aUJBQU07Z0JBQ0wsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLGFBQWEsRUFBRTtvQkFDL0IsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO29CQUN6RSxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFdBQVcsR0FBRyxrQkFBa0IsQ0FBQyxDQUFDO29CQUNsRSxJQUFJLFdBQVcsS0FBSyxJQUFJLENBQUMsZUFBZSxJQUFJLGNBQWMsR0FBRyxHQUFHLEVBQUU7d0JBQ2hFLElBQUksQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUM7cUJBQzlCO2lCQUNGO2FBQ0Y7U0FDRjtRQUNELElBQUksT0FBTyxDQUFDLGNBQWMsQ0FBQyxFQUFFO1lBQzNCLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1lBQzFCLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN0QixJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksSUFBSSxJQUFJLENBQUMsV0FBVyxLQUFLLE9BQU8sRUFBRTtnQkFDdEQsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQzthQUNoRTtTQUNGO1FBQ0QsSUFBSSxPQUFPLENBQUMsY0FBYyxDQUFDLEVBQUU7WUFDM0IsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1NBQ3ZCO1FBQ0QsSUFBSSxPQUFPLENBQUMsY0FBYyxDQUFDLEVBQUU7WUFDM0IsSUFBSSxDQUFDLFdBQVcsR0FBRyxPQUFPLENBQUMsY0FBYyxDQUFDLENBQUMsWUFBWSxDQUFDO1NBQ3pEO0lBQ0gsQ0FBQztJQUVELFdBQVc7UUFDVCxJQUFJLElBQUksQ0FBQyx5QkFBeUIsRUFBRTtZQUNsQyxJQUFJLENBQUMseUJBQXlCLEVBQUUsQ0FBQztTQUNsQztRQUNELElBQUksSUFBSSxDQUFDLG1CQUFtQixFQUFFO1lBQzVCLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxHQUFHLEdBQUcsRUFBRSxDQUFDO1lBQ2xDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNsQyxJQUFJLENBQUMsbUJBQW1CLEdBQUcsSUFBSSxDQUFDO1NBQ2pDO1FBQ0QsSUFBSSxJQUFJLENBQUMsc0JBQXNCLEVBQUU7WUFDL0IsSUFBSSxDQUFDLHNCQUFzQixDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUM7WUFDckMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ3JDLElBQUksQ0FBQyxzQkFBc0IsR0FBRyxJQUFJLENBQUM7U0FDcEM7UUFDRCxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUMzQixJQUFJLENBQUMsc0NBQXNDLEVBQUUsQ0FBQztRQUM5QyxPQUFPLENBQUMsR0FBRyxDQUFDLCtDQUErQyxDQUFDLENBQUM7SUFDL0QsQ0FBQztJQUVEOztPQUVHO0lBQ0gsVUFBVSxDQUFDLFlBQW9CO1FBQzdCLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLGFBQWE7WUFBRSxPQUFPO1FBQ3pDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQztJQUNyRSxDQUFDO0lBRUQ7O09BRUc7SUFDSyxLQUFLLENBQUMsZ0JBQWdCLENBQUMsWUFBb0I7UUFDakQsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQztRQUNqQyxJQUFJLEtBQUssSUFBSSxDQUFDO1lBQUUsT0FBTztRQUV2QixNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQ2pFLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQztRQUUxQyxJQUFJLFlBQVksR0FBRyxDQUFDLENBQUM7UUFDckIsSUFBSSxZQUFZLEdBQUcsQ0FBQyxDQUFDO1FBQ3JCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxVQUFVLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQzFDLElBQUksYUFBYSxHQUFHLFVBQVUsQ0FBQyxDQUFDLENBQUMsRUFBRTtnQkFDakMsWUFBWSxHQUFHLENBQUMsQ0FBQztnQkFDakIsWUFBWSxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztnQkFDL0MsTUFBTTthQUNQO1lBQ0QsWUFBWSxHQUFHLENBQUMsQ0FBQztZQUNqQixZQUFZLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1NBQ2hEO1FBQ0QsSUFBSSxVQUFVLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxhQUFhLElBQUksVUFBVSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLEVBQUU7WUFDL0UsWUFBWSxHQUFHLFVBQVUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO1lBQ3JDLFlBQVksR0FBRyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxZQUFZLEdBQUcsQ0FBQyxDQUFDLENBQUM7U0FDdEU7UUFFRCxNQUFNLFdBQVcsR0FBRyxhQUFhLEdBQUcsWUFBWSxDQUFDO1FBRWpELElBQUksSUFBSSxDQUFDLGlCQUFpQixLQUFLLFlBQVksRUFBRTtZQUMzQyxNQUFNLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUMzQyw2Q0FBNkM7WUFDN0MsSUFBSSxJQUFJLENBQUMsYUFBYSxHQUFHLENBQUMsRUFBRTtnQkFDMUIsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQzthQUNqRztTQUNGO2FBQU07WUFDTCxNQUFNLG1CQUFtQixHQUFHLFlBQVksR0FBRyxXQUFXLENBQUM7WUFDdkQsTUFBTSxJQUFJLENBQUMsNEJBQTRCLENBQUMsbUJBQW1CLENBQUMsQ0FBQztZQUM3RCxrRUFBa0U7U0FDbkU7SUFDSCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssS0FBSyxDQUFDLGtCQUFrQixDQUFDLFlBQW9CO1FBQ25ELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUUsYUFBYSxDQUFDO1FBQzFDLElBQUksQ0FBQyxLQUFLLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUTtZQUFFLE9BQU87UUFFdEMsTUFBTSxPQUFPLEdBQUcsWUFBWSxHQUFHLElBQUksQ0FBQztRQUNwQyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztRQUVsRSxPQUFPLENBQUMsR0FBRyxDQUFDLHlDQUF5QyxFQUFFO1lBQ3JELFlBQVk7WUFDWixVQUFVO1lBQ1YsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXO1lBQzdCLGlCQUFpQixFQUFFLEtBQUssQ0FBQyxXQUFXO1NBQ3JDLENBQUMsQ0FBQztRQUVILG9CQUFvQjtRQUNwQixJQUFJLENBQUMsV0FBVyxHQUFHLFNBQVMsQ0FBQztRQUU3QiwwREFBMEQ7UUFDeEQsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBRWhCLGVBQWU7UUFDZixJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQztRQUN2QixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztRQUN4QixJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFdEMsZUFBZTtRQUNmLEtBQUssQ0FBQyxXQUFXLEdBQUcsVUFBVSxDQUFDO1FBQy9CLElBQUksQ0FBQyxlQUFlLEdBQUcsWUFBWSxDQUFDO1FBRXBDLGlFQUFpRTtRQUNqRSxNQUFNLElBQUksT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBRXRELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUM7UUFDakMsSUFBSSxLQUFLLEdBQUcsQ0FBQyxFQUFFO1lBQ2IsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxLQUFLLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDO1NBQ3BGO1FBQ0QsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUM7UUFFbEQsa0RBQWtEO1FBQ2xELElBQUksQ0FBQyxXQUFXLEdBQUcsUUFBUSxDQUFDO1FBRTVCLE9BQU8sQ0FBQyxHQUFHLENBQUMsK0NBQStDLEVBQUU7WUFDM0QsZ0JBQWdCLEVBQUUsS0FBSyxDQUFDLFdBQVc7WUFDbkMsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXO1NBQzlCLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNILFVBQVU7UUFDUixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsT0FBTyxFQUFFLGFBQWEsQ0FBQztRQUMxQyxJQUFJLENBQUMsS0FBSyxFQUFFO1lBQ1YsT0FBTyxDQUFDLEtBQUssQ0FBQyxpREFBaUQsRUFBRTtnQkFDL0QsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXO2dCQUM3QixZQUFZLEVBQUUsSUFBSSxDQUFDLFlBQVk7YUFDaEMsQ0FBQyxDQUFDO1lBQ0gsT0FBTztTQUNSO1FBRUQseUJBQXlCO1FBQ3pCLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxJQUFJLEtBQUssQ0FBQyxZQUFZLEtBQUssZ0JBQWdCLENBQUMsaUJBQWlCLElBQUksS0FBSyxDQUFDLEtBQUssRUFBRTtZQUNyRyxPQUFPLENBQUMsS0FBSyxDQUFDLHlDQUF5QyxFQUFFO2dCQUN2RCxlQUFlLEVBQUUsSUFBSSxDQUFDLGVBQWU7Z0JBQ3JDLFlBQVksRUFBRSxLQUFLLENBQUMsWUFBWTtnQkFDaEMsS0FBSyxFQUFFLEtBQUssQ0FBQyxLQUFLO2FBQ25CLENBQUMsQ0FBQztZQUNILE9BQU87U0FDUjtRQUVELCtGQUErRjtRQUMvRixJQUFJLElBQUksQ0FBQyxXQUFXLEtBQUssU0FBUyxJQUFJLEtBQUssQ0FBQyxVQUFVLElBQUksZ0JBQWdCLENBQUMsYUFBYSxFQUFFO1lBQ3hGLElBQUksQ0FBQyxXQUFXLEdBQUcsUUFBUSxDQUFDO1NBQzdCO1FBRUQsc0NBQXNDO1FBQ3RDLElBQUksSUFBSSxDQUFDLFdBQVcsS0FBSyxPQUFPLEVBQUU7WUFDaEMsT0FBTyxDQUFDLElBQUksQ0FBQywrQ0FBK0MsRUFBRSxFQUFFLFVBQVUsRUFBRSxLQUFLLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztZQUNoRyxJQUFJLENBQUMsV0FBVyxHQUFHLE1BQU0sQ0FBQztTQUMzQjtRQUVELHVEQUF1RDtRQUN2RCxJQUFJLElBQUksQ0FBQyxXQUFXLEtBQUssU0FBUyxFQUFFO1lBQ2xDLE9BQU8sQ0FBQyxJQUFJLENBQUMsMENBQTBDLEVBQUU7Z0JBQ3ZELFdBQVcsRUFBRSxJQUFJLENBQUMsV0FBVztnQkFDN0IsVUFBVSxFQUFFLEtBQUssQ0FBQyxVQUFVO2FBQzdCLENBQUMsQ0FBQztZQUNILFVBQVUsQ0FBQyxHQUFHLEVBQUU7Z0JBQ2QsSUFBSSxLQUFLLENBQUMsVUFBVSxJQUFJLGdCQUFnQixDQUFDLGFBQWEsSUFBSSxJQUFJLENBQUMsV0FBVyxLQUFLLFNBQVMsRUFBRTtvQkFDeEYsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO2lCQUNuQjtZQUNILENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUNQLE9BQU87U0FDUjtRQUVELE9BQU8sQ0FBQyxHQUFHLENBQUMseUJBQXlCLEVBQUU7WUFDckMsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXO1lBQzdCLFNBQVMsRUFBRSxJQUFJLENBQUMsU0FBUztZQUN6QixVQUFVLEVBQUUsS0FBSyxDQUFDLFVBQVU7U0FDN0IsQ0FBQyxDQUFDO1FBRUgsK0JBQStCO1FBQy9CLElBQUksSUFBSSxDQUFDLFdBQVcsS0FBSyxTQUFTLEVBQUU7WUFDbEMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1NBQ25CO2FBQU07WUFDTCxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7U0FDbEI7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxTQUFTO1FBQ2YsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLENBQUM7SUFDeEQsQ0FBQztJQUVEOzs7T0FHRztJQUNLLEtBQUssQ0FBQyxpQkFBaUI7UUFDN0IsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxhQUFhLENBQUM7UUFDMUMsSUFBSSxDQUFDLEtBQUssRUFBRTtZQUNWLE9BQU8sQ0FBQyxLQUFLLENBQUMsd0RBQXdELENBQUMsQ0FBQztZQUN4RSxPQUFPO1NBQ1I7UUFFRCx5QkFBeUI7UUFDekIsSUFBSSxJQUFJLENBQUMsV0FBVyxLQUFLLFNBQVMsRUFBRTtZQUNsQyxPQUFPLENBQUMsR0FBRyxDQUFDLDBEQUEwRCxDQUFDLENBQUM7WUFDeEUsT0FBTztTQUNSO1FBRUQsSUFBSSxJQUFJLENBQUMsaUJBQWlCLElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRTtZQUM1QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDO1lBQ2pDLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDO1lBQ2pELE1BQU0sT0FBTyxHQUFHLEtBQUssR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxJQUFJLEdBQUcsSUFBSSxpQkFBaUIsSUFBSSxLQUFLLENBQUMsQ0FBQztZQUNsRixNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsaUJBQWlCLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO1lBQ3hFLE1BQU0sZ0JBQWdCLEdBQUcsV0FBVyxJQUFJLEtBQUssQ0FBQyxRQUFRLElBQUksS0FBSyxDQUFDLFdBQVcsSUFBSSxLQUFLLENBQUMsUUFBUSxHQUFHLEdBQUcsQ0FBQztZQUVwRyxJQUFJLE9BQU8sSUFBSSxnQkFBZ0IsRUFBRTtnQkFDL0IsT0FBTyxDQUFDLEdBQUcsQ0FBQywrRUFBK0UsRUFBRTtvQkFDM0YsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRO29CQUN2QixpQkFBaUI7b0JBQ2pCLEtBQUs7b0JBQ0wsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLGlCQUFpQjtvQkFDekMsT0FBTztvQkFDUCxnQkFBZ0I7aUJBQ2pCLENBQUMsQ0FBQztnQkFFSCxxQ0FBcUM7Z0JBQ3JDLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxDQUFDLENBQUM7Z0JBQzNCLElBQUksQ0FBQyxRQUFRLEdBQUcsQ0FBQyxDQUFDO2dCQUNsQixJQUFJLENBQUMsNEJBQTRCLEdBQUcsQ0FBQyxDQUFDO2dCQUN0QyxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUV4QixzQ0FBc0M7Z0JBQ3RDLE1BQU0sSUFBSSxDQUFDLDRCQUE0QixDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUUzQyxzQ0FBc0M7Z0JBQ3RDLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxhQUFhLENBQUM7Z0JBQ3JELElBQUksQ0FBQyxnQkFBZ0IsRUFBRTtvQkFDckIsT0FBTyxDQUFDLEtBQUssQ0FBQyxxRUFBcUUsQ0FBQyxDQUFDO29CQUNyRixPQUFPO2lCQUNSO2dCQUVELHdDQUF3QztnQkFDeEMseUVBQXlFO2dCQUN6RSx5Q0FBeUM7Z0JBQ3pDLElBQUksZ0JBQWdCLENBQUMsVUFBVSxHQUFHLGdCQUFnQixDQUFDLGFBQWEsRUFBRTtvQkFDaEUsTUFBTSxJQUFJLE9BQU8sQ0FBTyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTt3QkFDMUMsTUFBTSxnQkFBZ0IsR0FBRyxHQUFHLEVBQUU7NEJBQzVCLGdCQUFnQixDQUFDLG1CQUFtQixDQUFDLGdCQUFnQixFQUFFLGdCQUFnQixDQUFDLENBQUM7NEJBQ3pFLGdCQUFnQixDQUFDLG1CQUFtQixDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQzs0QkFDdkQsT0FBTyxFQUFFLENBQUM7d0JBQ1osQ0FBQyxDQUFDO3dCQUNGLE1BQU0sT0FBTyxHQUFHLEdBQUcsRUFBRTs0QkFDbkIsZ0JBQWdCLENBQUMsbUJBQW1CLENBQUMsZ0JBQWdCLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQzs0QkFDekUsZ0JBQWdCLENBQUMsbUJBQW1CLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDOzRCQUN2RCxNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMsK0JBQStCLENBQUMsQ0FBQyxDQUFDO3dCQUNyRCxDQUFDLENBQUM7d0JBQ0YsZ0JBQWdCLENBQUMsZ0JBQWdCLENBQUMsZ0JBQWdCLEVBQUUsZ0JBQWdCLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQzt3QkFDdEYsZ0JBQWdCLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO3dCQUNwRSxVQUFVLENBQUMsR0FBRyxFQUFFOzRCQUNkLGdCQUFnQixDQUFDLG1CQUFtQixDQUFDLGdCQUFnQixFQUFFLGdCQUFnQixDQUFDLENBQUM7NEJBQ3pFLGdCQUFnQixDQUFDLG1CQUFtQixDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQzs0QkFDdkQsSUFBSSxnQkFBZ0IsQ0FBQyxVQUFVLElBQUksZ0JBQWdCLENBQUMsYUFBYSxFQUFFO2dDQUNqRSxPQUFPLEVBQUUsQ0FBQzs2QkFDWDtpQ0FBTTtnQ0FDTCxNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMsOEJBQThCLENBQUMsQ0FBQyxDQUFDOzZCQUNuRDt3QkFDSCxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7b0JBQ1YsQ0FBQyxDQUFDLENBQUM7aUJBQ0o7Z0JBRUQsdUJBQXVCO2dCQUN2QixJQUFJLENBQUMsV0FBVyxHQUFHLFNBQVMsQ0FBQztnQkFFN0IsSUFBSTtvQkFDRixNQUFNLGdCQUFnQixDQUFDLElBQUksRUFBRSxDQUFDO29CQUM5QixJQUFJLENBQUMsV0FBVyxHQUFHLFNBQVMsQ0FBQztvQkFDN0IsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUM7b0JBQ3RCLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO29CQUN4QixJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxDQUFDO29CQUN0QixJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO29CQUNyQyxJQUFJLENBQUMsNEJBQTRCLEdBQUcsSUFBSSxDQUFDO29CQUV6QyxPQUFPLENBQUMsR0FBRyxDQUFDLDJEQUEyRCxDQUFDLENBQUM7b0JBQ3pFLE9BQU87aUJBQ1I7Z0JBQUMsT0FBTyxHQUFRLEVBQUU7b0JBQ2pCLElBQUksQ0FBQyxXQUFXLEdBQUcsT0FBTyxDQUFDO29CQUMzQixJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQztvQkFDdkIsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7b0JBQ3hCLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7b0JBQ3RDLElBQUksR0FBRyxDQUFDLElBQUksS0FBSyxZQUFZLEVBQUU7d0JBQzdCLElBQUksQ0FBQyxXQUFXLEdBQUcsUUFBUSxDQUFDO3FCQUM3Qjt5QkFBTTt3QkFDTCxPQUFPLENBQUMsS0FBSyxDQUFDLG1EQUFtRCxFQUFFLEdBQUcsQ0FBQyxDQUFDO3FCQUN6RTtvQkFDRCxPQUFPO2lCQUNSO2FBQ0Y7U0FDRjtRQUVELE9BQU8sQ0FBQyxHQUFHLENBQUMseUNBQXlDLEVBQUU7WUFDckQsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXO1lBQzdCLFdBQVcsRUFBRSxLQUFLLENBQUMsV0FBVztZQUM5QixVQUFVLEVBQUUsS0FBSyxDQUFDLFVBQVU7U0FDN0IsQ0FBQyxDQUFDO1FBRUgsdUNBQXVDO1FBQ3ZDLElBQUksS0FBSyxDQUFDLFVBQVUsR0FBRyxnQkFBZ0IsQ0FBQyxhQUFhLEVBQUU7WUFDckQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxxREFBcUQsQ0FBQyxDQUFDO1lBQ25FLE1BQU0sSUFBSSxPQUFPLENBQU8sQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7Z0JBQzFDLE1BQU0sZ0JBQWdCLEdBQUcsR0FBRyxFQUFFO29CQUM1QixLQUFLLENBQUMsbUJBQW1CLENBQUMsZ0JBQWdCLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztvQkFDOUQsS0FBSyxDQUFDLG1CQUFtQixDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztvQkFDNUMsT0FBTyxFQUFFLENBQUM7Z0JBQ1osQ0FBQyxDQUFDO2dCQUNGLE1BQU0sT0FBTyxHQUFHLEdBQUcsRUFBRTtvQkFDbkIsS0FBSyxDQUFDLG1CQUFtQixDQUFDLGdCQUFnQixFQUFFLGdCQUFnQixDQUFDLENBQUM7b0JBQzlELEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUM7b0JBQzVDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQywrQkFBK0IsQ0FBQyxDQUFDLENBQUM7Z0JBQ3JELENBQUMsQ0FBQztnQkFDRixLQUFLLENBQUMsZ0JBQWdCLENBQUMsZ0JBQWdCLEVBQUUsZ0JBQWdCLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFDM0UsS0FBSyxDQUFDLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFFekQsbUJBQW1CO2dCQUNuQixVQUFVLENBQUMsR0FBRyxFQUFFO29CQUNkLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxnQkFBZ0IsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO29CQUM5RCxLQUFLLENBQUMsbUJBQW1CLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO29CQUM1QyxJQUFJLEtBQUssQ0FBQyxVQUFVLElBQUksZ0JBQWdCLENBQUMsYUFBYSxFQUFFO3dCQUN0RCxPQUFPLEVBQUUsQ0FBQztxQkFDWDt5QkFBTTt3QkFDTCxNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMsOEJBQThCLENBQUMsQ0FBQyxDQUFDO3FCQUNuRDtnQkFDSCxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDVixDQUFDLENBQUMsQ0FBQztTQUNKO1FBRUQsK0NBQStDO1FBQy9DLE1BQU0sYUFBYSxHQUFHLEtBQUssQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO1FBQy9DLElBQUksYUFBYSxHQUFHLEdBQUcsRUFBRTtZQUN2QixJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDO1NBQ3pCO1FBRUQsdUJBQXVCO1FBQ3ZCLElBQUksQ0FBQyxXQUFXLEdBQUcsU0FBUyxDQUFDO1FBRTdCLElBQUk7WUFDRix5REFBeUQ7WUFDekQsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxhQUFhLENBQUM7WUFDakQsSUFBSSxDQUFDLFlBQVksSUFBSSxZQUFZLEtBQUssS0FBSyxFQUFFO2dCQUMzQyxPQUFPLENBQUMsSUFBSSxDQUFDLHFFQUFxRSxDQUFDLENBQUM7Z0JBQ3BGLElBQUksQ0FBQyxXQUFXLEdBQUcsUUFBUSxDQUFDO2dCQUM1QixJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQztnQkFDdkIsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7Z0JBQ3hCLE9BQU87YUFDUjtZQUVELHdDQUF3QztZQUN4QyxNQUFNLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUVuQixzRUFBc0U7WUFDdEUsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxhQUFhLENBQUM7WUFDbkQsSUFBSSxDQUFDLGNBQWMsSUFBSSxjQUFjLEtBQUssS0FBSyxFQUFFO2dCQUMvQyxPQUFPLENBQUMsSUFBSSxDQUFDLGtFQUFrRSxDQUFDLENBQUM7Z0JBQ2pGLElBQUksQ0FBQyxXQUFXLEdBQUcsUUFBUSxDQUFDO2dCQUM1QixJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQztnQkFDdkIsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7Z0JBQ3hCLE9BQU87YUFDUjtZQUVELGlCQUFpQjtZQUNqQixJQUFJLENBQUMsV0FBVyxHQUFHLFNBQVMsQ0FBQztZQUM3QixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQztZQUN0QixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztZQUN4QixJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ3RCLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7WUFFckMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxxREFBcUQsRUFBRTtnQkFDakUsV0FBVyxFQUFFLEtBQUssQ0FBQyxXQUFXO2dCQUM5QixXQUFXLEVBQUUsSUFBSSxDQUFDLFdBQVc7YUFDOUIsQ0FBQyxDQUFDO1lBRUgsZ0VBQWdFO1lBQ2hFLFVBQVUsQ0FBQyxHQUFHLEVBQUU7Z0JBQ2QsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFO29CQUNsQixJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO2lCQUM3QztZQUNILENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztTQUNSO1FBQUMsT0FBTyxHQUFRLEVBQUU7WUFDakIsY0FBYztZQUNkLDRDQUE0QztZQUM1QyxNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsT0FBTyxFQUFFLGFBQWEsQ0FBQztZQUNwRCxJQUFJLENBQUMsZUFBZSxJQUFJLGVBQWUsS0FBSyxLQUFLLEVBQUU7Z0JBQ2pELE9BQU8sQ0FBQyxJQUFJLENBQUMsbUVBQW1FLENBQUMsQ0FBQztnQkFDbEYsSUFBSSxDQUFDLFdBQVcsR0FBRyxRQUFRLENBQUM7YUFDN0I7aUJBQU07Z0JBQ0wsSUFBSSxDQUFDLFdBQVcsR0FBRyxPQUFPLENBQUM7YUFDNUI7WUFFRCxJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQztZQUN2QixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztZQUN4QixJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBRXRDLElBQUksR0FBRyxDQUFDLElBQUksS0FBSyxZQUFZLEVBQUU7Z0JBQzdCLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0VBQWdFLENBQUMsQ0FBQztnQkFDOUUsaUVBQWlFO2dCQUNqRSxJQUFJLGVBQWUsSUFBSSxlQUFlLEtBQUssS0FBSyxFQUFFO29CQUNoRCxJQUFJLENBQUMsV0FBVyxHQUFHLFFBQVEsQ0FBQztpQkFDN0I7YUFDRjtpQkFBTTtnQkFDTCxPQUFPLENBQUMsS0FBSyxDQUFDLHVDQUF1QyxFQUFFLEdBQUcsQ0FBQyxDQUFDO2FBQzdEO1NBQ0Y7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxVQUFVO1FBQ2hCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFFRDs7T0FFRztJQUNLLEtBQUssQ0FBQyxrQkFBa0I7UUFDOUIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxhQUFhLENBQUM7UUFDMUMsSUFBSSxDQUFDLEtBQUs7WUFBRSxPQUFPO1FBRW5CLHdCQUF3QjtRQUN4QixJQUFJLElBQUksQ0FBQyxXQUFXLEtBQUssUUFBUSxFQUFFO1lBQ2pDLE9BQU8sQ0FBQyxHQUFHLENBQUMsMERBQTBELENBQUMsQ0FBQztZQUN4RSxPQUFPO1NBQ1I7UUFFRCxPQUFPLENBQUMsR0FBRyxDQUFDLHlDQUF5QyxFQUFFO1lBQ3JELFdBQVcsRUFBRSxJQUFJLENBQUMsV0FBVztZQUM3QixXQUFXLEVBQUUsS0FBSyxDQUFDLFdBQVc7U0FDL0IsQ0FBQyxDQUFDO1FBRUQsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBRWhCLElBQUksQ0FBQyxXQUFXLEdBQUcsUUFBUSxDQUFDO1FBQzVCLElBQUksQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDO1FBQ3JCLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO1FBQzFCLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDdkIsSUFBSSxDQUFDLG9CQUFvQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUV0QyxPQUFPLENBQUMsR0FBRyxDQUFDLHFEQUFxRCxDQUFDLENBQUM7SUFDckUsQ0FBQztJQUVEOzs7O09BSUc7SUFDSyxnQkFBZ0IsQ0FBQyxTQUE4QjtRQUNyRCxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxjQUFjO2FBQ3RDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxTQUFTLEVBQUUsQ0FBQzthQUN2QixLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUU7WUFDWCxPQUFPLENBQUMsS0FBSyxDQUFDLHFDQUFxQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQzFELElBQUksQ0FBQyxXQUFXLEdBQUcsT0FBTyxDQUFDO1FBQzdCLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVELElBQUksaUJBQWlCO1FBQ25CLE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO0lBQ3BFLENBQUM7SUFFRCwwRkFBMEY7SUFDMUYsSUFBSSxpQkFBaUI7UUFDbkIsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQztRQUN0QyxJQUFJLFNBQVMsQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUFFLE9BQU8sRUFBRSxDQUFDO1FBQ3RDLE1BQU0sVUFBVSxHQUFhLEVBQUUsQ0FBQztRQUNoQyxJQUFJLEdBQUcsR0FBRyxDQUFDLENBQUM7UUFDWixLQUFLLE1BQU0sQ0FBQyxJQUFJLFNBQVMsRUFBRTtZQUN6QixHQUFHLElBQUksQ0FBQyxDQUFDO1lBQ1QsVUFBVSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztTQUN0QjtRQUNELE9BQU8sVUFBVSxDQUFDO0lBQ3BCLENBQUM7SUFFRCwrQ0FBK0M7SUFDL0MsSUFBSSxhQUFhO1FBQ2YsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQztRQUN0QyxJQUFJLFNBQVMsQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3JDLE9BQU8sU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDOUMsQ0FBQztJQUVELG9FQUFvRTtJQUNwRSxJQUFZLGNBQWM7UUFDeEIsSUFBSSxJQUFJLENBQUMsaUJBQWlCLElBQUksSUFBSSxDQUFDLHNCQUFzQixDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDcEUsT0FBTyxJQUFJLENBQUMsc0JBQXNCLENBQUM7U0FDcEM7UUFDRCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsT0FBTyxFQUFFLGFBQWEsQ0FBQztRQUMxQyxJQUFJLEtBQUssRUFBRSxRQUFRLElBQUksUUFBUSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsRUFBRTtZQUMvQyxPQUFPLENBQUMsS0FBSyxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsQ0FBQztTQUNoQztRQUNELE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUVELElBQUksaUJBQWlCO1FBQ25CLElBQUksSUFBSSxDQUFDLDRCQUE0QixLQUFLLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLElBQUksSUFBSSxDQUFDLFdBQVcsS0FBSyxTQUFTLEVBQUU7WUFDbkcsT0FBTyxJQUFJLENBQUMsNEJBQTRCLENBQUM7U0FDMUM7UUFDRCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsT0FBTyxFQUFFLGFBQWEsQ0FBQztRQUMxQyxJQUFJLENBQUMsS0FBSyxFQUFFLFFBQVEsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLEVBQUU7WUFDakQsOENBQThDO1lBQzlDLElBQUksSUFBSSxDQUFDLDRCQUE0QixLQUFLLElBQUksRUFBRTtnQkFDOUMsT0FBTyxJQUFJLENBQUMsNEJBQTRCLENBQUM7YUFDMUM7WUFDRCxPQUFPLENBQUMsQ0FBQztTQUNWO1FBQ0QsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDbEgsT0FBTyxZQUFZLEdBQUcsS0FBSyxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7SUFDakQsQ0FBQztJQUVPLG1CQUFtQjtRQUN6QixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsT0FBTyxFQUFFLGFBQWEsQ0FBQztRQUMxQyxJQUFJLENBQUMsS0FBSyxFQUFFLFFBQVEsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDO1lBQUUsT0FBTyxDQUFDLENBQUM7UUFDNUQsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDbEgsT0FBTyxZQUFZLEdBQUcsS0FBSyxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7SUFDakQsQ0FBQztJQUVELGlFQUFpRTtJQUNqRSxJQUFJLGlCQUFpQjtRQUNuQixNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUN6RCxPQUFPLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQzFCLFVBQVUsRUFBRSxDQUFDLENBQUMsa0JBQWtCO1lBQ2hDLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTTtZQUNoQixVQUFVLEVBQUUsQ0FBQyxDQUFDLFVBQVU7WUFDeEIsS0FBSyxFQUFFLENBQUMsQ0FBQyxLQUFLO1lBQ2QsS0FBSyxFQUFFLENBQUMsQ0FBQyxLQUFLO1NBQ2YsQ0FBQyxDQUFDLENBQUM7SUFDTixDQUFDO0lBRUQsSUFBSSxlQUFlO1FBQ2pCLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1lBQzlELE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDckYsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1NBQzVCO1FBQ0QsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDO0lBQ3ZCLENBQUM7SUFFRDs7T0FFRztJQUNLLGVBQWU7UUFDckIsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDLENBQUM7SUFDOUQsQ0FBQztJQUVEOztPQUVHO0lBQ0ssS0FBSyxDQUFDLHVCQUF1QjtRQUNuQyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsT0FBTyxFQUFFLGFBQWEsQ0FBQztRQUMxQyxJQUFJLENBQUMsS0FBSztZQUFFLE9BQU87UUFFbkIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnREFBZ0QsQ0FBQyxDQUFDO1FBRTlELEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNkLEtBQUssQ0FBQyxXQUFXLEdBQUcsQ0FBQyxDQUFDO1FBRXRCLElBQUksQ0FBQyxXQUFXLEdBQUcsUUFBUSxDQUFDO1FBQzVCLElBQUksQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxRQUFRLEdBQUcsQ0FBQyxDQUFDO1FBQ2xCLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLGVBQWUsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUMxQixJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRXRDLE9BQU8sQ0FBQyxHQUFHLENBQUMsK0NBQStDLENBQUMsQ0FBQztJQUMvRCxDQUFDO0lBRUQsU0FBUztRQUNQLElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCO1lBQUUsT0FBTztRQUNwQyxJQUFJLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxDQUFDLEVBQUU7WUFDOUIsSUFBSSxDQUFDLGlCQUFpQixJQUFJLENBQUMsQ0FBQztZQUM1QixJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7U0FDeEI7SUFDSCxDQUFDO0lBRUQsU0FBUztRQUNQLElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCO1lBQUUsT0FBTztRQUNwQyxJQUFJLElBQUksQ0FBQyxTQUFTLElBQUksSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtZQUN4RSxJQUFJLENBQUMsaUJBQWlCLElBQUksQ0FBQyxDQUFDO1lBQzVCLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztTQUN4QjtJQUNILENBQUM7SUFFRCxlQUFlLENBQUMsS0FBaUI7UUFDL0IsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsYUFBYTtZQUFFLE9BQU87UUFFN0MsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMscUJBQXFCLEVBQUUsQ0FBQztRQUNwRSxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUM7UUFDekMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBRTlELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUM7UUFDakMsSUFBSSxLQUFLLElBQUksQ0FBQztZQUFFLE9BQU87UUFFdkIsTUFBTSxZQUFZLEdBQUcsT0FBTyxHQUFHLEtBQUssQ0FBQztRQUNyQyxNQUFNLG1CQUFtQixHQUFHLElBQUksQ0FBQyxTQUFTLENBQUM7UUFFM0MsT0FBTyxDQUFDLEdBQUcsQ0FBQyw2QkFBNkIsRUFBRTtZQUN6QyxPQUFPO1lBQ1AsWUFBWTtZQUNaLG1CQUFtQjtTQUNwQixDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxJQUFJLEVBQUU7WUFDL0IsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDMUMsSUFBSSxtQkFBbUIsRUFBRTtnQkFDdkIsTUFBTSxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztnQkFDdkQsTUFBTSxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQzthQUNoQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELFNBQVMsQ0FBQyxLQUFpQjtRQUN6QixLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDdkIsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7UUFFckIsaURBQWlEO1FBQ2pELDBEQUEwRDtRQUMxRCxJQUFJLENBQUMsb0JBQW9CLEdBQUcsSUFBSSxDQUFDLFNBQVMsSUFBSSxJQUFJLENBQUMsV0FBVyxLQUFLLFNBQVMsQ0FBQztRQUU3RSxPQUFPLENBQUMsR0FBRyxDQUFDLHVCQUF1QixFQUFFO1lBQ25DLE9BQU8sRUFBRSxLQUFLLENBQUMsT0FBTztZQUN0QixXQUFXLEVBQUUsSUFBSSxDQUFDLFdBQVc7WUFDN0IsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTO1lBQ3pCLG9CQUFvQixFQUFFLElBQUksQ0FBQyxvQkFBb0I7U0FDaEQsQ0FBQyxDQUFDO1FBRUgsNkNBQTZDO1FBQzdDLElBQUksSUFBSSxDQUFDLFNBQVMsSUFBSSxJQUFJLENBQUMsV0FBVyxLQUFLLFNBQVMsRUFBRTtZQUNwRCxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7U0FDbkI7UUFFRCxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztJQUMxQixDQUFDO0lBRUQsTUFBTSxDQUFDLEtBQWlCO1FBQ3RCLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxhQUFhO1lBQUUsT0FBTztRQUUvRCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLGFBQWEsQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1FBQ3BFLE1BQU0sQ0FBQyxHQUFHLEtBQUssQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztRQUNwQyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDekQsSUFBSSxDQUFDLFFBQVEsR0FBRyxPQUFPLEdBQUcsR0FBRyxDQUFDLENBQUMsMkJBQTJCO0lBQzVELENBQUM7SUFFRCxRQUFRO1FBQ04sSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRO1lBQUUsT0FBTztRQUUzQixJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztRQUN0QixJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUUzQixrRUFBa0U7UUFDbEUsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLENBQUMsb0JBQW9CLENBQUM7UUFFdEQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQ0FBa0MsRUFBRTtZQUM5QyxRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVE7WUFDdkIsb0JBQW9CLEVBQUUsSUFBSSxDQUFDLG9CQUFvQjtZQUMvQyxtQkFBbUIsRUFBRSxtQkFBbUI7WUFDeEMsa0JBQWtCLEVBQUUsSUFBSSxDQUFDLFdBQVc7U0FDckMsQ0FBQyxDQUFDO1FBRUgsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQztRQUNqQyxJQUFJLEtBQUssSUFBSSxDQUFDO1lBQUUsT0FBTztRQUV2QixNQUFNLFlBQVksR0FBRyxDQUFDLElBQUksQ0FBQyxRQUFRLEdBQUcsR0FBRyxDQUFDLEdBQUcsS0FBSyxDQUFDO1FBRW5ELHlEQUF5RDtRQUN6RCx3REFBd0Q7UUFDeEQsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEtBQUssSUFBSSxFQUFFO1lBQy9CLDJDQUEyQztZQUMzQyxNQUFNLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUUxQyw4Q0FBOEM7WUFDOUMsSUFBSSxtQkFBbUIsRUFBRTtnQkFDdkIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxvREFBb0QsRUFBRTtvQkFDaEUsWUFBWTtvQkFDWixXQUFXLEVBQUUsSUFBSSxDQUFDLFdBQVc7aUJBQzlCLENBQUMsQ0FBQztnQkFFSCxxREFBcUQ7Z0JBQ3JELE1BQU0sSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7Z0JBRXZELCtFQUErRTtnQkFDL0UsK0NBQStDO2dCQUMvQyxJQUFJLElBQUksQ0FBQyxXQUFXLEtBQUssU0FBUyxFQUFFO29CQUNsQyxPQUFPLENBQUMsR0FBRyxDQUFDLDREQUE0RCxDQUFDLENBQUM7b0JBQzFFLE1BQU0sSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7aUJBQ3hEO2dCQUVELCtEQUErRDtnQkFDL0QsSUFBSSxJQUFJLENBQUMsV0FBVyxLQUFLLFFBQVEsRUFBRTtvQkFDakMsTUFBTSxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztvQkFDL0IsT0FBTyxDQUFDLEdBQUcsQ0FBQyxxREFBcUQsRUFBRTt3QkFDakUsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXO3dCQUM3QixTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVM7cUJBQzFCLENBQUMsQ0FBQztpQkFDSjtxQkFBTTtvQkFDTCxPQUFPLENBQUMsSUFBSSxDQUFDLGdGQUFnRixFQUFFO3dCQUM3RixXQUFXLEVBQUUsSUFBSSxDQUFDLFdBQVc7cUJBQzlCLENBQUMsQ0FBQztvQkFDSCw4REFBOEQ7b0JBQzlELE1BQU0sSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7aUJBQ2hDO2FBQ0Y7aUJBQU07Z0JBQ0wsT0FBTyxDQUFDLEdBQUcsQ0FBQyxzREFBc0QsQ0FBQyxDQUFDO2FBQ3JFO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU8sZ0JBQWdCO1FBQ3RCLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBRTNCLElBQUksQ0FBQyxvQkFBb0IsR0FBRyxDQUFDLENBQWEsRUFBRSxFQUFFO1lBQzVDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDakIsQ0FBQyxDQUFDO1FBRUYsSUFBSSxDQUFDLGtCQUFrQixHQUFHLEdBQUcsRUFBRTtZQUM3QixJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDbEIsQ0FBQyxDQUFDO1FBRUYsUUFBUSxDQUFDLGdCQUFnQixDQUFDLFdBQVcsRUFBRSxJQUFJLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUNsRSxRQUFRLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO0lBQ2hFLENBQUM7SUFFTyxtQkFBbUI7UUFDekIsSUFBSSxJQUFJLENBQUMsb0JBQW9CLEVBQUU7WUFDN0IsUUFBUSxDQUFDLG1CQUFtQixDQUFDLFdBQVcsRUFBRSxJQUFJLENBQUMsb0JBQW9CLENBQUMsQ0FBQztZQUNyRSxJQUFJLENBQUMsb0JBQW9CLEdBQUcsSUFBSSxDQUFDO1NBQ2xDO1FBRUQsSUFBSSxJQUFJLENBQUMsa0JBQWtCLEVBQUU7WUFDM0IsUUFBUSxDQUFDLG1CQUFtQixDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsa0JBQWtCLENBQUMsQ0FBQztZQUNqRSxJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDO1NBQ2hDO0lBQ0gsQ0FBQztJQUVELHFCQUFxQjtRQUNuQixPQUFPLENBQUMsR0FBRyxDQUFDLG1DQUFtQyxDQUFDLENBQUM7UUFDakQsd0RBQXdEO1FBQ3hELElBQUksQ0FBQyx3QkFBd0IsRUFBRSxDQUFDO1FBQ2hDLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO0lBQzlCLENBQUM7SUFFRCxjQUFjO1FBQ1osT0FBTyxDQUFDLEdBQUcsQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO1FBQzFDLHdEQUF3RDtRQUN4RCxJQUFJLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztRQUNoQyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztJQUM5QixDQUFDO0lBRUQsWUFBWTtRQUNWLElBQUksQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxXQUFXLEdBQUcsUUFBUSxDQUFDO1FBQzVCLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDdkIsSUFBSSxDQUFDLG9CQUFvQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUV0Qyx3Q0FBd0M7UUFDeEMsSUFBSSxJQUFJLENBQUMsaUJBQWlCLElBQUksSUFBSSxDQUFDLFNBQVMsSUFBSSxJQUFJLENBQUMsaUJBQWlCLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1lBQ2xHLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxDQUFDLENBQUM7WUFDN0MsTUFBTSxZQUFZLEdBQUcsU0FBUyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7WUFFeEYsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEtBQUssSUFBSSxFQUFFO2dCQUMvQixNQUFNLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxZQUFZLENBQUMsQ0FBQztnQkFDdEQsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLGFBQWEsSUFBSSxJQUFJLENBQUMsZUFBZSxFQUFFO29CQUN2RCxNQUFNLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO2lCQUNoQztZQUNILENBQUMsQ0FBQyxDQUFDO1NBQ0o7SUFDSCxDQUFDO0lBRU8sb0JBQW9CO1FBQzFCLElBQUksSUFBSSxDQUFDLHlCQUF5QixFQUFFO1lBQ2xDLElBQUksQ0FBQyx5QkFBeUIsRUFBRSxDQUFDO1lBQ2pDLElBQUksQ0FBQyx5QkFBeUIsR0FBRyxJQUFJLENBQUM7U0FDdkM7UUFFRCxVQUFVLENBQUMsR0FBRyxFQUFFO1lBQ2QsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxhQUFhLENBQUM7WUFDMUMsSUFBSSxDQUFDLEtBQUs7Z0JBQUUsT0FBTztZQUVuQixJQUFJLFVBQVUsR0FBRyxDQUFDLENBQUM7WUFDbkIsTUFBTSxPQUFPLEdBQUcsR0FBRyxFQUFFO2dCQUNuQixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQ3ZCLElBQUksR0FBRyxHQUFHLFVBQVUsR0FBRyxHQUFHO29CQUFFLE9BQU87Z0JBRW5DLFVBQVUsR0FBRyxHQUFHLENBQUM7Z0JBQ2pCLE1BQU0sU0FBUyxHQUFHLEtBQUssQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO2dCQUUzQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsSUFBSSxJQUFJLENBQUMsV0FBVyxLQUFLLFdBQVcsRUFBRTtvQkFDdEQsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQztvQkFFakMsMEVBQTBFO29CQUMxRSx3RUFBd0U7b0JBQ3hFLElBQUksSUFBSSxDQUFDLDRCQUE0QixLQUFLLElBQUksRUFBRTt3QkFDOUMsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7d0JBQ2pELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsOEJBQThCO3dCQUM3RSxJQUFJLElBQUksQ0FBQyxHQUFHLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxHQUFHLFNBQVMsRUFBRTs0QkFDM0UsSUFBSSxDQUFDLDRCQUE0QixHQUFHLElBQUksQ0FBQzt5QkFDMUM7cUJBQ0Y7b0JBRUQsaUVBQWlFO29CQUNqRSxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUU7d0JBQ2IsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxLQUFLLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDO3FCQUNwRjtvQkFDRCxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FBQztvQkFFbEQsd0NBQXdDO29CQUN4QyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO29CQUU1QyxzREFBc0Q7b0JBQ3RELElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO2lCQUNoQztZQUNILENBQUMsQ0FBQztZQUVGLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxZQUFZLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFFOUMsSUFBSSxDQUFDLHlCQUF5QixHQUFHLEdBQUcsRUFBRTtnQkFDcEMsS0FBSyxDQUFDLG1CQUFtQixDQUFDLFlBQVksRUFBRSxPQUFPLENBQUMsQ0FBQztZQUNuRCxDQUFDLENBQUM7UUFDSixDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDVixDQUFDO0lBRU8sMEJBQTBCLENBQUMsU0FBbUI7UUFDcEQsSUFBSSxDQUFDLFNBQVMsSUFBSSxTQUFTLENBQUMsTUFBTSxLQUFLLENBQUM7WUFBRSxPQUFPO1FBQ2pELElBQUksQ0FBQyx3QkFBd0IsRUFBRSxDQUFDO1FBQ2hDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsU0FBUyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDNUQsQ0FBQztJQUVPLHdCQUF3QjtRQUM5QixJQUFJLElBQUksQ0FBQyxzQkFBc0IsRUFBRTtZQUMvQixJQUFJLENBQUMsc0JBQXNCLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQztZQUNyQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDckMsSUFBSSxDQUFDLHNCQUFzQixHQUFHLElBQUksQ0FBQztTQUNwQztJQUNILENBQUM7SUFFRDs7O09BR0c7SUFDSyxrQkFBa0IsQ0FBQyxTQUFtQjtRQUM1QyxJQUFJLENBQUMsU0FBUyxJQUFJLFNBQVMsQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUFFLE9BQU87UUFDakQsSUFBSSxDQUFDLHdCQUF3QixFQUFFLENBQUM7UUFDaEMsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM5QyxLQUFLLENBQUMsT0FBTyxHQUFHLE1BQU0sQ0FBQztRQUN2QixLQUFLLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQztRQUNuQixLQUFLLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztRQUN6QixLQUFLLENBQUMsS0FBSyxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUM7UUFDN0IsUUFBUSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDakMsSUFBSSxDQUFDLHNCQUFzQixHQUFHLEtBQUssQ0FBQztRQUVwQyxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7UUFDZCxNQUFNLFFBQVEsR0FBRyxHQUFTLEVBQUU7WUFDMUIsSUFBSSxJQUFJLENBQUMsc0JBQXNCLEtBQUssS0FBSyxJQUFJLEtBQUssSUFBSSxTQUFTLENBQUMsTUFBTSxFQUFFO2dCQUN0RSxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ2YsSUFBSSxJQUFJLENBQUMsc0JBQXNCLEtBQUssS0FBSztvQkFBRSxJQUFJLENBQUMsc0JBQXNCLEdBQUcsSUFBSSxDQUFDO2dCQUM5RSxPQUFPO2FBQ1I7WUFDRCxNQUFNLEdBQUcsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDN0IsS0FBSyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUM7WUFDaEIsS0FBSyxJQUFJLENBQUMsQ0FBQztZQUNYLE1BQU0sTUFBTSxHQUFHLEdBQVMsRUFBRTtnQkFDeEIsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUN4QixLQUFLLENBQUMsbUJBQW1CLENBQUMsWUFBWSxFQUFFLE1BQU0sQ0FBQyxDQUFDO2dCQUNoRCxLQUFLLENBQUMsbUJBQW1CLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO2dCQUMzQyxRQUFRLEVBQUUsQ0FBQztZQUNiLENBQUMsQ0FBQztZQUNGLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxZQUFZLEVBQUUsTUFBTSxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7WUFDN0QsS0FBSyxDQUFDLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztZQUN4RCxNQUFNLFNBQVMsR0FBRyxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsTUFBTSxFQUFFLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDdEQsQ0FBQyxDQUFDO1FBQ0YsUUFBUSxFQUFFLENBQUM7SUFDYixDQUFDO0lBRUQsc0ZBQXNGO0lBQzlFLHVCQUF1QjtRQUM3QixJQUFJLENBQUMsSUFBSSxDQUFDLGlCQUFpQixJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsSUFBSSxJQUFJLENBQUMsaUJBQWlCLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1lBQ3JHLE9BQU87U0FDUjtRQUNELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUUsYUFBYSxDQUFDO1FBQzFDLElBQUksQ0FBQyxLQUFLLEVBQUUsUUFBUTtZQUFFLE9BQU87UUFDN0IsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLEtBQUssQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDLFdBQVcsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLEtBQUs7UUFDNUUsSUFBSSxpQkFBaUIsR0FBRyxLQUFLLElBQUksaUJBQWlCLEdBQUcsSUFBSTtZQUFFLE9BQU8sQ0FBQyw4QkFBOEI7UUFDakcsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDM0QsSUFBSSxDQUFDLE9BQU87WUFBRSxPQUFPO1FBQ3JCLElBQUksSUFBSSxDQUFDLG1CQUFtQixFQUFFLEdBQUcsS0FBSyxPQUFPO1lBQUUsT0FBTyxDQUFDLHFCQUFxQjtRQUM1RSxJQUFJLENBQUMsa0JBQWtCLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDbkMsQ0FBQztJQUVPLGtCQUFrQixDQUFDLEdBQVc7UUFDcEMsSUFBSSxJQUFJLENBQUMsbUJBQW1CLEVBQUU7WUFDNUIsSUFBSSxDQUFDLG1CQUFtQixDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUM7WUFDbEMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2xDLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxJQUFJLENBQUM7U0FDakM7UUFDRCxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzlDLEtBQUssQ0FBQyxPQUFPLEdBQUcsTUFBTSxDQUFDO1FBQ3ZCLEtBQUssQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDO1FBQ2hCLEtBQUssQ0FBQyxLQUFLLENBQUMsT0FBTyxHQUFHLE1BQU0sQ0FBQztRQUM3QixRQUFRLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNqQyxJQUFJLENBQUMsbUJBQW1CLEdBQUcsS0FBSyxDQUFDO1FBQ2pDLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxZQUFZLEVBQUUsR0FBRyxFQUFFO1lBQ3hDLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNmLElBQUksSUFBSSxDQUFDLG1CQUFtQixLQUFLLEtBQUs7Z0JBQUUsSUFBSSxDQUFDLG1CQUFtQixHQUFHLElBQUksQ0FBQztRQUMxRSxDQUFDLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUNyQixDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssb0JBQW9CLENBQUMsU0FBbUI7UUFDOUMsSUFBSSxDQUFDLFNBQVMsSUFBSSxTQUFTLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtZQUN4QyxJQUFJLENBQUMsc0JBQXNCLEdBQUcsRUFBRSxDQUFDO1lBQ2pDLE9BQU87U0FDUjtRQUVELDJCQUEyQjtRQUMzQixJQUFJLENBQUMsc0JBQXNCLEdBQUcsRUFBRSxDQUFDO1FBQ2pDLElBQUksV0FBVyxHQUFHLENBQUMsQ0FBQztRQUVwQixTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxFQUFFO1lBQy9CLE1BQU0sU0FBUyxHQUFHLFFBQVEsQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDbEQsU0FBUyxDQUFDLE9BQU8sR0FBRyxVQUFVLENBQUM7WUFFL0IsTUFBTSxnQkFBZ0IsR0FBRyxHQUFHLEVBQUU7Z0JBQzVCLE1BQU0sVUFBVSxHQUFHLFNBQVMsQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDO2dCQUM3QyxJQUFJLENBQUMsc0JBQXNCLENBQUMsS0FBSyxDQUFDLEdBQUcsVUFBVSxDQUFDO2dCQUNoRCxXQUFXLEVBQUUsQ0FBQztnQkFFZCxXQUFXO2dCQUNYLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxnQkFBZ0IsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO2dCQUNsRSxTQUFTLENBQUMsbUJBQW1CLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO2dCQUNoRCxTQUFTLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQztnQkFDbkIsU0FBUyxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUVuQixJQUFJLFdBQVcsS0FBSyxTQUFTLENBQUMsTUFBTSxFQUFFO29CQUNwQyxPQUFPLENBQUMsR0FBRyxDQUFDLDJDQUEyQyxFQUFFLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO2lCQUN2RjtZQUNILENBQUMsQ0FBQztZQUVGLE1BQU0sT0FBTyxHQUFHLEdBQUcsRUFBRTtnQkFDbkIsT0FBTyxDQUFDLElBQUksQ0FBQyxpREFBaUQsS0FBSyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7Z0JBQzNFLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQ3ZDLFdBQVcsRUFBRSxDQUFDO2dCQUNkLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxnQkFBZ0IsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO2dCQUNsRSxTQUFTLENBQUMsbUJBQW1CLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO2dCQUNoRCxTQUFTLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQztnQkFDbkIsU0FBUyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ3JCLENBQUMsQ0FBQztZQUVGLFNBQVMsQ0FBQyxnQkFBZ0IsQ0FBQyxnQkFBZ0IsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO1lBQy9ELFNBQVMsQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDN0MsU0FBUyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUM7UUFDdEIsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLDBCQUEwQjtRQUNoQyxJQUFJLENBQUMsSUFBSSxDQUFDLGlCQUFpQixFQUFFO1lBQzNCLE9BQU8sRUFBRSxDQUFDO1NBQ1g7UUFFRCx3RUFBd0U7UUFDeEUsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLHNCQUFzQixDQUFDLE1BQU0sR0FBRyxDQUFDO1lBQ3RELENBQUMsQ0FBQyxJQUFJLENBQUMsc0JBQXNCO1lBQzdCLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFFUCxJQUFJLFNBQVMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1lBQzFCLE9BQU8sRUFBRSxDQUFDO1NBQ1g7UUFFRCxNQUFNLFVBQVUsR0FBMEMsRUFBRSxDQUFDO1FBQzdELElBQUksZUFBZSxHQUFHLENBQUMsQ0FBQztRQUV4QixLQUFLLE1BQU0sUUFBUSxJQUFJLFNBQVMsRUFBRTtZQUNoQyxVQUFVLENBQUMsSUFBSSxDQUFDO2dCQUNkLEtBQUssRUFBRSxlQUFlO2dCQUN0QixHQUFHLEVBQUUsZUFBZSxHQUFHLFFBQVE7YUFDaEMsQ0FBQyxDQUFDO1lBQ0gsZUFBZSxJQUFJLFFBQVEsQ0FBQztTQUM3QjtRQUVELE9BQU8sVUFBVSxDQUFDO0lBQ3BCLENBQUM7SUFFRDs7T0FFRztJQUNLLGNBQWMsQ0FBQyxPQUFxQjtRQUMxQyxNQUFNLFNBQVMsR0FBaUIsRUFBRSxDQUFDO1FBRW5DLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxPQUFxQixFQUFFLEVBQUU7WUFDakQsT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsRUFBRTtnQkFDdkIsd0JBQXdCO2dCQUN4QixTQUFTLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO2dCQUV2QixnQ0FBZ0M7Z0JBQ2hDLElBQUksTUFBTSxDQUFDLFVBQVUsSUFBSSxNQUFNLENBQUMsVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7b0JBQ3JELGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztpQkFDckM7WUFDSCxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQztRQUVGLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzFCLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFFTyxjQUFjLENBQUMsWUFBb0I7UUFDekMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLElBQUksSUFBSSxDQUFDLFFBQVE7WUFBRSxPQUFPO1FBRTdDLHdEQUF3RDtRQUN4RCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUN6RCxNQUFNLFNBQVMsR0FBRyxHQUFHLENBQUMsQ0FBQywrQkFBK0I7UUFFdEQsS0FBSyxNQUFNLE1BQU0sSUFBSSxVQUFVLEVBQUU7WUFDL0IseUNBQXlDO1lBQ3pDLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVTtnQkFBRSxTQUFTO1lBRWpDLHNCQUFzQjtZQUN0QixJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUM7Z0JBQUUsU0FBUztZQUVyRCwrREFBK0Q7WUFDL0QsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLEdBQUcsTUFBTSxDQUFDLGtCQUFrQixDQUFDLENBQUM7WUFDMUUsSUFBSSxjQUFjLElBQUksU0FBUyxFQUFFO2dCQUMvQiw2QkFBNkI7Z0JBQzdCLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztnQkFDdkMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQzVCLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUNBQWlDLEVBQUU7b0JBQzdDLFVBQVUsRUFBRSxNQUFNLENBQUMsVUFBVTtvQkFDN0Isa0JBQWtCLEVBQUUsTUFBTSxDQUFDLGtCQUFrQjtvQkFDN0MsV0FBVyxFQUFFLFlBQVk7b0JBQ3pCLGNBQWM7b0JBQ2QsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFLO29CQUNuQixLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQUs7aUJBQ3BCLENBQUMsQ0FBQztnQkFDSCxNQUFNLENBQUMsaUNBQWlDO2FBQ3pDO1NBQ0Y7SUFDSCxDQUFDO0lBRUQsMEJBQTBCLENBQUMsTUFBNEI7UUFDckQsUUFBUSxNQUFNLEVBQUU7WUFDZCxLQUFLLFNBQVM7Z0JBQ1osT0FBTyxTQUFTLENBQUM7WUFDbkIsS0FBSyxTQUFTO2dCQUNaLE9BQU8sU0FBUyxDQUFDO1lBQ25CLEtBQUssU0FBUztnQkFDWixPQUFPLFNBQVMsQ0FBQztZQUNuQixLQUFLLFNBQVM7Z0JBQ1osT0FBTyxTQUFTLENBQUM7WUFDbkI7Z0JBQ0UsT0FBTyxTQUFTLENBQUM7U0FDcEI7SUFDSCxDQUFDO0lBRUQsb0JBQW9CLENBQUMsS0FBYztRQUNqQyxPQUFPLEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQzdDLENBQUM7SUFFRCxhQUFhLENBQUMsS0FBaUIsRUFBRSxNQUFpRjtRQUNoSCxLQUFLLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDeEIsS0FBSyxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLElBQUksRUFBRTtZQUMvQixNQUFNLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7WUFDL0MsSUFBSSxNQUFNLENBQUMsVUFBVSxJQUFJLElBQUksRUFBRTtnQkFDN0IsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2dCQUN2QyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsVUFBVSxLQUFLLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztnQkFDdkcsSUFBSSxVQUFVO29CQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2FBQ2pEO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsZ0JBQWdCO1FBQ2QsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQztRQUNsQyxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsT0FBTyxFQUFFLGFBQWEsRUFBRSxXQUFXLElBQUksQ0FBQyxDQUFDO1FBRWxFLGlFQUFpRTtRQUNqRSxJQUFJLFVBQVUsRUFBRTtZQUNkLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztTQUNuQjtRQUVELG9CQUFvQjtRQUNwQixJQUFJLENBQUMsWUFBWSxHQUFHLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQztRQUV2QyxpRUFBaUU7UUFDakUsK0VBQStFO1FBQy9FLElBQUksSUFBSSxDQUFDLFdBQVcsS0FBSyxTQUFTLElBQUksSUFBSSxDQUFDLFdBQVcsS0FBSyxPQUFPLEVBQUU7WUFDbEUsSUFBSSxDQUFDLFdBQVcsR0FBRyxNQUFNLENBQUM7U0FDM0I7UUFFRCwrREFBK0Q7UUFDL0QsVUFBVSxDQUFDLEdBQUcsRUFBRTtZQUNkLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUUsYUFBYSxDQUFDO1lBQzFDLElBQUksS0FBSyxFQUFFO2dCQUNULHVDQUF1QztnQkFDdkMsSUFBSSxXQUFXLEdBQUcsQ0FBQyxJQUFJLEtBQUssQ0FBQyxRQUFRLEdBQUcsV0FBVyxFQUFFO29CQUNuRCxLQUFLLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQztpQkFDakM7Z0JBRUQseUJBQXlCO2dCQUN6QixJQUFJLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztnQkFFaEMsc0JBQXNCO2dCQUN0QixJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztnQkFFNUIsMENBQTBDO2dCQUMxQyxJQUFJLENBQUMsV0FBVyxHQUFHLFFBQVEsQ0FBQztnQkFDNUIsSUFBSSxDQUFDLFNBQVMsR0FBRyxLQUFLLENBQUM7Z0JBRXZCLE9BQU8sQ0FBQyxHQUFHLENBQUMsb0RBQW9ELEVBQUU7b0JBQ2hFLFlBQVksRUFBRSxJQUFJLENBQUMsWUFBWTtvQkFDL0IsV0FBVyxFQUFFLEtBQUssQ0FBQyxXQUFXO29CQUM5QixXQUFXLEVBQUUsSUFBSSxDQUFDLFdBQVc7aUJBQzlCLENBQUMsQ0FBQzthQUNKO2lCQUFNO2dCQUNMLE9BQU8sQ0FBQyxJQUFJLENBQUMsd0VBQXdFLENBQUMsQ0FBQztnQkFDdkYsa0NBQWtDO2dCQUNsQyxVQUFVLENBQUMsR0FBRyxFQUFFO29CQUNkLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUUsYUFBYSxDQUFDO29CQUMvQyxJQUFJLFVBQVUsRUFBRTt3QkFDZCxJQUFJLENBQUMsd0JBQXdCLEVBQUUsQ0FBQzt3QkFDaEMsSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUM7d0JBQzVCLElBQUksQ0FBQyxXQUFXLEdBQUcsUUFBUSxDQUFDO3dCQUM1QixJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQztxQkFDeEI7Z0JBQ0gsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO2FBQ1Q7UUFDSCxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDVixDQUFDO0lBRUQsZUFBZSxDQUFDLEtBQWE7UUFDM0IsSUFBSSxDQUFDLFdBQVcsR0FBRyxLQUFLLENBQUM7UUFDekIsa0RBQWtEO1FBQ2xELElBQUksSUFBSSxDQUFDLFdBQVcsS0FBSyxPQUFPLEVBQUU7WUFDaEMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ2xCLElBQUksQ0FBQyxRQUFRLEdBQUcsQ0FBQyxDQUFDO1NBQ25CO2FBQU07WUFDTCxxREFBcUQ7WUFDckQsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEtBQUssSUFBSSxFQUFFO2dCQUMvQixNQUFNLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO2dCQUVyQywyQ0FBMkM7Z0JBQzNDLElBQUksSUFBSSxDQUFDLGlCQUFpQixJQUFJLElBQUksQ0FBQyxTQUFTLEVBQUU7b0JBQzVDLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxDQUFDLENBQUM7b0JBQzNCLElBQUksQ0FBQyw0QkFBNEIsR0FBRyxDQUFDLENBQUM7b0JBRXRDLHNDQUFzQztvQkFDdEMsTUFBTSxJQUFJLENBQUMsNEJBQTRCLENBQUMsQ0FBQyxDQUFDLENBQUM7aUJBQzVDO1lBQ0gsQ0FBQyxDQUFDLENBQUM7U0FDSjtJQUNILENBQUM7SUFFRCxVQUFVLENBQUMsT0FBZTtRQUN4QixJQUFJLENBQUMsT0FBTyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUM7WUFBRSxPQUFPLE9BQU8sQ0FBQztRQUUvQyxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3pDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxDQUFDO1FBQzlDLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDcEQsTUFBTSxJQUFJLEdBQUcsWUFBWSxHQUFHLEVBQUUsQ0FBQztRQUUvQixrRUFBa0U7UUFDbEUsSUFBSSxLQUFLLEdBQUcsQ0FBQyxFQUFFO1lBQ2IsT0FBTyxHQUFHLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxFQUFFLENBQUM7U0FDdkg7UUFFRCxPQUFPLEdBQUcsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLEVBQUUsQ0FBQztJQUNuRixDQUFDO0lBRUQsbUJBQW1CO1FBQ2pCLE1BQU0sV0FBVyxHQUFHLHVHQUF1RyxDQUFDO1FBQzVILFFBQVEsSUFBSSxDQUFDLFVBQVUsRUFBRTtZQUN2QixLQUFLLGFBQWEsQ0FBQztZQUNuQixLQUFLLFdBQVc7Z0JBQ2QsT0FBTyxHQUFHLFdBQVcsbURBQW1ELENBQUM7WUFDM0UsS0FBSyxRQUFRO2dCQUNYLE9BQU8sR0FBRyxXQUFXLG1EQUFtRCxDQUFDO1lBQzNFLEtBQUssU0FBUztnQkFDWixPQUFPLEdBQUcsV0FBVyxtREFBbUQsQ0FBQztZQUMzRSxLQUFLLFFBQVE7Z0JBQ1gsT0FBTyxHQUFHLFdBQVcsbURBQW1ELENBQUM7WUFDM0UsS0FBSyxRQUFRO2dCQUNYLE9BQU8sR0FBRyxXQUFXLG1EQUFtRCxDQUFDO1lBQzNFO2dCQUNFLE9BQU8sR0FBRyxXQUFXLGlEQUFpRCxDQUFDO1NBQzFFO0lBQ0gsQ0FBQztJQUVELGtCQUFrQjtRQUNoQixRQUFRLElBQUksQ0FBQyxVQUFVLEVBQUU7WUFDdkIsS0FBSyxhQUFhLENBQUM7WUFDbkIsS0FBSyxXQUFXO2dCQUNkLE9BQU8sdUVBQXVFLENBQUM7WUFDakYsS0FBSyxRQUFRO2dCQUNYLE9BQU8sdUVBQXVFLENBQUM7WUFDakYsS0FBSyxTQUFTO2dCQUNaLE9BQU8sdUVBQXVFLENBQUM7WUFDakYsS0FBSyxRQUFRO2dCQUNYLE9BQU8sdUVBQXVFLENBQUM7WUFDakYsS0FBSyxRQUFRO2dCQUNYLE9BQU8sdUVBQXVFLENBQUM7WUFDakY7Z0JBQ0UsT0FBTyxzRUFBc0UsQ0FBQztTQUNqRjtJQUNILENBQUM7SUFFRCxJQUFJLGlCQUFpQjtRQUNuQixJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVk7WUFBRSxPQUFPLEVBQUUsQ0FBQztRQUVsQyxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFO1lBQ3RDLE1BQU0sU0FBUyxHQUFHLElBQUksZUFBZSxDQUFDO2dCQUNwQyxLQUFLLEVBQUUsSUFBSSxDQUFDLFlBQVk7Z0JBQ3hCLFVBQVUsRUFBRSxNQUFNO2dCQUNsQixZQUFZLEVBQUUsTUFBTTtnQkFDcEIsS0FBSyxFQUFFLE1BQU07Z0JBQ2IsT0FBTyxFQUFFLE1BQU07Z0JBQ2YsUUFBUSxFQUFFLE1BQU07YUFDakIsQ0FBQyxDQUFDO1lBRUgsT0FBTyxpQ0FBaUMsU0FBUyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUM7U0FDaEU7UUFFRCxPQUFPLElBQUksQ0FBQyxZQUFZLENBQUM7SUFDM0IsQ0FBQztJQUVPLGtCQUFrQjtRQUN4QixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUM7UUFDbkMsSUFBSSxHQUFHLEVBQUU7WUFDUCxJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDO1lBQy9CLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxLQUFLLENBQUM7WUFDOUIsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLDhCQUE4QixDQUFDLEdBQUcsQ0FBQyxDQUFDO1NBQ3hFO2FBQU07WUFDTCxJQUFJLENBQUMsa0JBQWtCLEdBQUcsS0FBSyxDQUFDO1lBQ2hDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxLQUFLLENBQUM7WUFDOUIsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLDhCQUE4QixDQUFDLEVBQUUsQ0FBQyxDQUFDO1NBQ3ZFO0lBQ0gsQ0FBQztJQUVELGlCQUFpQjtRQUNmLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxLQUFLLENBQUM7UUFDaEMsSUFBSSxDQUFDLGdCQUFnQixHQUFHLEtBQUssQ0FBQztJQUNoQyxDQUFDO0lBRUQsa0JBQWtCO1FBQ2hCLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxLQUFLLENBQUM7UUFDaEMsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksQ0FBQztJQUMvQixDQUFDO0lBRUQsYUFBYSxDQUFDLEtBQWE7UUFDekIsSUFBSSxDQUFDLFlBQVksR0FBRyxLQUFLLENBQUM7UUFDMUIsd0RBQXdEO1FBQ3hELElBQUksQ0FBQyx3QkFBd0IsRUFBRSxDQUFDO1FBQ2hDLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxLQUFLLENBQUM7SUFDbEMsQ0FBQztJQUVELGtCQUFrQjtRQUNoQixJQUFJLENBQUMsa0JBQWtCLEdBQUcsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUM7UUFDbkQsSUFBSSxJQUFJLENBQUMsa0JBQWtCLEVBQUU7WUFDM0IsSUFBSSxDQUFDLG1DQUFtQyxFQUFFLENBQUM7U0FDNUM7YUFBTTtZQUNMLElBQUksQ0FBQyxzQ0FBc0MsRUFBRSxDQUFDO1NBQy9DO0lBQ0gsQ0FBQztJQUVPLG1DQUFtQztRQUN6QyxJQUFJLENBQUMsc0NBQXNDLEVBQUUsQ0FBQztRQUU5QyxVQUFVLENBQUMsR0FBRyxFQUFFO1lBQ2QsSUFBSSxDQUFDLCtCQUErQixHQUFHLENBQUMsQ0FBYSxFQUFFLEVBQUU7Z0JBQ3ZELE1BQU0sTUFBTSxHQUFHLENBQUMsQ0FBQyxNQUFxQixDQUFDO2dCQUN2QyxJQUFJLE1BQU0sSUFBSSxJQUFJLENBQUMscUJBQXFCLEVBQUUsYUFBYTtvQkFDbkQsQ0FBQyxJQUFJLENBQUMscUJBQXFCLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsRUFBRTtvQkFDOUQsSUFBSSxDQUFDLGtCQUFrQixHQUFHLEtBQUssQ0FBQztvQkFDaEMsSUFBSSxDQUFDLHNDQUFzQyxFQUFFLENBQUM7aUJBQy9DO1lBQ0gsQ0FBQyxDQUFDO1lBRUYsUUFBUSxDQUFDLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsK0JBQStCLENBQUMsQ0FBQztRQUMzRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDUixDQUFDO0lBRU8sc0NBQXNDO1FBQzVDLElBQUksSUFBSSxDQUFDLCtCQUErQixFQUFFO1lBQ3hDLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLCtCQUErQixDQUFDLENBQUM7WUFDNUUsSUFBSSxDQUFDLCtCQUErQixHQUFHLElBQUksQ0FBQztTQUM3QztJQUNILENBQUM7SUFFTyxjQUFjO1FBQ3BCLE1BQU0sWUFBWSxHQUFvQjtZQUNwQyxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUUsS0FBSyxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFHO1NBQy9ELENBQUM7UUFFRiw4Q0FBOEM7UUFDOUMsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUU7WUFDdEIsWUFBWSxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLENBQUMsQ0FBQztTQUN6RTtRQUVELElBQUksSUFBSSxDQUFDLFlBQVksRUFBRTtZQUNyQixZQUFZLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxZQUFZLEVBQUUsQ0FBQyxDQUFDO1NBQzNFO1FBRUQsSUFBSSxDQUFDLFFBQVEsR0FBRyxZQUFZLENBQUM7UUFFN0IsNEVBQTRFO1FBQzVFLElBQUksSUFBSSxDQUFDLFdBQVcsS0FBSyxPQUFPLElBQUksSUFBSSxDQUFDLFlBQVksRUFBRTtZQUNyRCxJQUFJLENBQUMsV0FBVyxHQUFHLGFBQWEsQ0FBQztTQUNsQztJQUNILENBQUM7SUFFTyxtQkFBbUI7UUFDekIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFFBQVEsRUFBRSxhQUFhLENBQUM7UUFDM0MsSUFBSSxDQUFDLEtBQUs7WUFBRSxPQUFPO1FBRW5CLE9BQU8sQ0FBQyxHQUFHLENBQUMsc0RBQXNELEVBQUU7WUFDbEUsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXO1lBQzdCLFlBQVksRUFBRSxJQUFJLENBQUMsWUFBWTtZQUMvQixVQUFVLEVBQUUsS0FBSyxDQUFDLFVBQVU7U0FDN0IsQ0FBQyxDQUFDO1FBRUgsOEZBQThGO1FBQzlGLElBQUksSUFBSSxDQUFDLFdBQVcsS0FBSyxPQUFPLElBQUksSUFBSSxDQUFDLFdBQVcsS0FBSyxTQUFTLEVBQUU7WUFDbEUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnRUFBZ0UsQ0FBQyxDQUFDO1lBQzlFLElBQUksQ0FBQyxXQUFXLEdBQUcsTUFBTSxDQUFDO1lBQzFCLElBQUksQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDO1lBQ3ZCLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO1NBQ3pCO1FBRUQscUVBQXFFO1FBQ3JFLElBQUksQ0FBQyx3QkFBd0IsRUFBRSxDQUFDO1FBRWhDLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO0lBQzlCLENBQUM7SUFFTyx3QkFBd0I7UUFDOUIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxhQUFhLENBQUM7UUFDMUMsSUFBSSxDQUFDLEtBQUs7WUFBRSxPQUFPO1FBRW5CLE1BQU0sT0FBTyxHQUFHLFVBQVUsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUMvRCxNQUFNLElBQUksR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxPQUFPLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUMxRCxLQUFLLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQztJQUM1QixDQUFDO0lBRU8sMEJBQTBCLENBQUMsbUJBQTJCO1FBQzVELElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUU7WUFDM0IsT0FBTyxJQUFJLENBQUM7U0FDYjtRQUVELE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQywwQkFBMEIsRUFBRSxDQUFDO1FBQ3JELElBQUksVUFBVSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7WUFDM0IsT0FBTyxJQUFJLENBQUM7U0FDYjtRQUVELDJDQUEyQztRQUMzQyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsVUFBVSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUMxQyxNQUFNLFFBQVEsR0FBRyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDL0IsSUFBSSxtQkFBbUIsSUFBSSxRQUFRLENBQUMsS0FBSyxJQUFJLG1CQUFtQixHQUFHLFFBQVEsQ0FBQyxHQUFHLEVBQUU7Z0JBQy9FLE9BQU8sQ0FBQyxDQUFDO2FBQ1Y7U0FDRjtRQUVELG9GQUFvRjtRQUNwRixJQUFJLFVBQVUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1lBQ3pCLE1BQU0sWUFBWSxHQUFHLFVBQVUsQ0FBQyxVQUFVLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ3ZELElBQUksbUJBQW1CLEtBQUssWUFBWSxDQUFDLEdBQUcsRUFBRTtnQkFDNUMsT0FBTyxVQUFVLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQzthQUM5QjtTQUNGO1FBRUQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRU8sb0JBQW9CLENBQUMsbUJBQTJCO1FBQ3RELElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsNEJBQTRCLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxDQUFDO0lBQ3RGLENBQUM7SUFFTyxLQUFLLENBQUMsNEJBQTRCLENBQUMsbUJBQTJCO1FBQ3BFLElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUU7WUFDM0IsTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsbUJBQW1CLENBQUMsQ0FBQztZQUNuRCxPQUFPO1NBQ1I7UUFFRCxNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1FBQzlFLElBQUksZ0JBQWdCLEtBQUssSUFBSSxFQUFFO1lBQzdCLE9BQU8sQ0FBQyxJQUFJLENBQUMsc0VBQXNFLEVBQUUsbUJBQW1CLENBQUMsQ0FBQztZQUMxRyxPQUFPO1NBQ1I7UUFFRCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsMEJBQTBCLEVBQUUsQ0FBQztRQUNyRCxNQUFNLGNBQWMsR0FBRyxVQUFVLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUNwRCxNQUFNLGlCQUFpQixHQUFHLG1CQUFtQixHQUFHLGNBQWMsQ0FBQyxLQUFLLENBQUM7UUFFckUsSUFBSSxJQUFJLENBQUMsaUJBQWlCLEtBQUssZ0JBQWdCLEVBQUU7WUFDL0MsTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsaUJBQWlCLENBQUMsQ0FBQztZQUNqRCxJQUFJLENBQUMsZUFBZSxHQUFHLG1CQUFtQixDQUFDO1lBQzNDLE9BQU87U0FDUjtRQUVELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUUsYUFBYSxDQUFDO1FBQzFDLElBQUksQ0FBQyxLQUFLO1lBQUUsT0FBTztRQUVuQixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDO1FBQ2pDLElBQUksQ0FBQyw0QkFBNEIsR0FBRyxtQkFBbUIsQ0FBQztRQUN4RCxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUU7WUFDYixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsbUJBQW1CLEdBQUcsS0FBSyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQztTQUNqRjtRQUVELElBQUksQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDO1FBRS9CLElBQUk7WUFDRiwwQ0FBMEM7WUFDMUMsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2QsSUFBSSxDQUFDLFNBQVMsR0FBRyxLQUFLLENBQUM7WUFDdkIsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7WUFDeEIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUN2QixJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBRXRDLHNCQUFzQjtZQUN0QixJQUFJLENBQUMsaUJBQWlCLEdBQUcsZ0JBQWdCLENBQUM7WUFFMUMsTUFBTSxJQUFJLE9BQU8sQ0FBTyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtnQkFDMUMsSUFBSSxRQUFRLEdBQUcsS0FBSyxDQUFDO2dCQUNyQixNQUFNLE9BQU8sR0FBRyxHQUFHLEVBQUU7b0JBQ25CLElBQUksUUFBUTt3QkFBRSxPQUFPO29CQUNyQixRQUFRLEdBQUcsSUFBSSxDQUFDO29CQUNoQixLQUFLLENBQUMsbUJBQW1CLENBQUMsZ0JBQWdCLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztvQkFDOUQsS0FBSyxDQUFDLG1CQUFtQixDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztvQkFDNUMsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUMxQixDQUFDLENBQUM7Z0JBRUYsTUFBTSxnQkFBZ0IsR0FBRyxHQUFHLEVBQUU7b0JBQzVCLE9BQU8sRUFBRSxDQUFDO29CQUNWLE9BQU8sQ0FBQyxHQUFHLENBQUMsa0RBQWtELEVBQUU7d0JBQzlELFVBQVUsRUFBRSxLQUFLLENBQUMsVUFBVTt3QkFDNUIsUUFBUSxFQUFFLEtBQUssQ0FBQyxRQUFRO3dCQUN4QixXQUFXLEVBQUUsS0FBSyxDQUFDLFdBQVc7cUJBQy9CLENBQUMsQ0FBQztvQkFDSCxPQUFPLEVBQUUsQ0FBQztnQkFDWixDQUFDLENBQUM7Z0JBQ0YsTUFBTSxPQUFPLEdBQUcsR0FBRyxFQUFFO29CQUNuQixPQUFPLEVBQUUsQ0FBQztvQkFDVixPQUFPLENBQUMsS0FBSyxDQUFDLCtDQUErQyxDQUFDLENBQUM7b0JBQy9ELE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDLENBQUM7Z0JBQzVDLENBQUMsQ0FBQztnQkFFRixVQUFVLENBQUMsR0FBRyxFQUFFO29CQUNkLElBQUksUUFBUTt3QkFBRSxPQUFPO29CQUNyQixLQUFLLENBQUMsZ0JBQWdCLENBQUMsZ0JBQWdCLEVBQUUsZ0JBQWdCLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztvQkFDM0UsS0FBSyxDQUFDLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFDM0QsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO2dCQUVSLE1BQU0sU0FBUyxHQUFHLFVBQVUsQ0FBQyxHQUFHLEVBQUU7b0JBQ2hDLE9BQU8sRUFBRSxDQUFDO29CQUNWLElBQUksS0FBSyxDQUFDLFVBQVUsSUFBSSxnQkFBZ0IsQ0FBQyxhQUFhLEVBQUU7d0JBQ3RELE9BQU8sQ0FBQyxHQUFHLENBQUMsb0VBQW9FLEVBQUU7NEJBQ2hGLFVBQVUsRUFBRSxLQUFLLENBQUMsVUFBVTs0QkFDNUIsUUFBUSxFQUFFLEtBQUssQ0FBQyxRQUFRO3lCQUN6QixDQUFDLENBQUM7d0JBQ0gsT0FBTyxFQUFFLENBQUM7cUJBQ1g7eUJBQU07d0JBQ0wsT0FBTyxDQUFDLEtBQUssQ0FBQyx3RUFBd0UsQ0FBQyxDQUFDO3dCQUN4RixNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMsbUNBQW1DLENBQUMsQ0FBQyxDQUFDO3FCQUN4RDtnQkFDSCxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDWCxDQUFDLENBQUMsQ0FBQztZQUVILG1FQUFtRTtZQUNuRSxNQUFNLFdBQVcsR0FBRyxpQkFBaUIsR0FBRyxJQUFJLENBQUM7WUFDN0MsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUsS0FBSyxDQUFDLFFBQVEsSUFBSSxXQUFXLENBQUMsQ0FBQyxDQUFDO1lBRXJGLE9BQU8sQ0FBQyxHQUFHLENBQUMsdURBQXVELEVBQUU7Z0JBQ25FLFVBQVU7Z0JBQ1YsV0FBVztnQkFDWCxpQkFBaUI7Z0JBQ2pCLGFBQWEsRUFBRSxLQUFLLENBQUMsUUFBUTthQUM5QixDQUFDLENBQUM7WUFFSCxNQUFNLElBQUksT0FBTyxDQUFPLENBQUMsT0FBTyxFQUFFLEVBQUU7Z0JBQ2xDLElBQUksUUFBUSxHQUFHLEtBQUssQ0FBQztnQkFDckIsTUFBTSxRQUFRLEdBQUcsR0FBRyxFQUFFO29CQUNwQixJQUFJLFFBQVE7d0JBQUUsT0FBTztvQkFDckIsUUFBUSxHQUFHLElBQUksQ0FBQztvQkFDaEIsS0FBSyxDQUFDLG1CQUFtQixDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsQ0FBQztvQkFDOUMsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFDO29CQUN4QixPQUFPLENBQUMsR0FBRyxDQUFDLHNEQUFzRCxFQUFFO3dCQUNsRSxXQUFXLEVBQUUsS0FBSyxDQUFDLFdBQVc7d0JBQzlCLFVBQVU7d0JBQ1YsSUFBSSxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFdBQVcsR0FBRyxVQUFVLENBQUM7cUJBQy9DLENBQUMsQ0FBQztvQkFFSCx1REFBdUQ7b0JBQ3ZELFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQztnQkFDbkMsQ0FBQyxDQUFDO2dCQUVGLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUUsUUFBUSxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7Z0JBQzNELEtBQUssQ0FBQyxXQUFXLEdBQUcsVUFBVSxDQUFDO2dCQUUvQixtQkFBbUI7Z0JBQ25CLE1BQU0sU0FBUyxHQUFHLFVBQVUsQ0FBQyxHQUFHLEVBQUU7b0JBQ2hDLElBQUksUUFBUTt3QkFBRSxPQUFPO29CQUNyQixRQUFRLEdBQUcsSUFBSSxDQUFDO29CQUNoQixLQUFLLENBQUMsbUJBQW1CLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDO29CQUM5QyxPQUFPLENBQUMsR0FBRyxDQUFDLG1FQUFtRSxFQUFFLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQztvQkFDcEcsT0FBTyxFQUFFLENBQUM7Z0JBQ1osQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQ1gsQ0FBQyxDQUFDLENBQUM7WUFFSCxJQUFJLENBQUMsZUFBZSxHQUFHLG1CQUFtQixDQUFDO1lBRTNDLDBEQUEwRDtZQUMxRCxJQUFJLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFdBQVcsR0FBRyxVQUFVLENBQUMsR0FBRyxHQUFHLEVBQUU7Z0JBQ2xELE9BQU8sQ0FBQyxJQUFJLENBQUMsbUZBQW1GLEVBQUU7b0JBQ2hHLFdBQVcsRUFBRSxLQUFLLENBQUMsV0FBVztvQkFDOUIsVUFBVTtpQkFDWCxDQUFDLENBQUM7Z0JBQ0gsS0FBSyxDQUFDLFdBQVcsR0FBRyxVQUFVLENBQUM7Z0JBQy9CLE1BQU0sSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7YUFDeEQ7WUFFRCx3QkFBd0I7WUFDeEIsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7WUFDaEQsTUFBTSxlQUFlLEdBQUcsS0FBSyxDQUFDLFdBQVcsQ0FBQztZQUUxQyxPQUFPLENBQUMsR0FBRyxDQUFDLHFEQUFxRCxFQUFFO2dCQUNqRSxZQUFZO2dCQUNaLFlBQVksRUFBRSxtQkFBbUI7Z0JBQ2pDLElBQUksRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksR0FBRyxtQkFBbUIsQ0FBQztnQkFDbEQsZUFBZTtnQkFDZixlQUFlLEVBQUUsVUFBVTtnQkFDM0IsU0FBUyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsZUFBZSxHQUFHLFVBQVUsQ0FBQzthQUNsRCxDQUFDLENBQUM7WUFFSCx5REFBeUQ7WUFDekQsTUFBTSxTQUFTLEdBQUcsR0FBRyxDQUFDO1lBQ3RCLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLEdBQUcsbUJBQW1CLENBQUMsR0FBRyxTQUFTLEVBQUU7Z0JBQzVELElBQUksQ0FBQyw0QkFBNEIsR0FBRyxJQUFJLENBQUM7Z0JBQ3pDLE9BQU8sQ0FBQyxHQUFHLENBQUMsc0VBQXNFLENBQUMsQ0FBQzthQUNyRjtZQUVELHlDQUF5QztZQUN6QyxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUU7Z0JBQ2IsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxLQUFLLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDO2FBQ3BGO1lBQ0QsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUM7U0FDbkQ7UUFBQyxPQUFPLEdBQUcsRUFBRTtZQUNaLE9BQU8sQ0FBQyxLQUFLLENBQUMsMENBQTBDLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDL0Qsa0RBQWtEO1lBQ2xELElBQUksS0FBSyxHQUFHLENBQUMsRUFBRTtnQkFDYixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsbUJBQW1CLEdBQUcsS0FBSyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQzthQUNqRjtZQUNELElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUM7U0FDaEQ7Z0JBQVM7WUFDUixJQUFJLENBQUMsV0FBVyxHQUFHLFFBQVEsQ0FBQztZQUM1QixJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3hCLDhFQUE4RTtZQUM5RSxxRUFBcUU7U0FDdEU7UUFFRCxPQUFPLENBQUMsR0FBRyxDQUFDLDRDQUE0QyxFQUFFO1lBQ3hELGlCQUFpQixFQUFFLElBQUksQ0FBQyxpQkFBaUI7WUFDekMsZ0JBQWdCLEVBQUUsS0FBSyxDQUFDLFdBQVc7WUFDbkMsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLGlCQUFpQjtZQUN6Qyw0QkFBNEIsRUFBRSxJQUFJLENBQUMsNEJBQTRCO1lBQy9ELFdBQVcsRUFBRSxJQUFJLENBQUMsV0FBVztZQUM3QixRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVE7U0FDeEIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQzs7K0dBaDVEVSxrQkFBa0I7bUdBQWxCLGtCQUFrQixzdENDckMvQixpeW9CQWlWTTsyRkQ1U08sa0JBQWtCO2tCQU45QixTQUFTOytCQUNFLGVBQWU7bUdBT2hCLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSztnQkFDRyxvQkFBb0I7c0JBQTVCLEtBQUs7Z0JBQ0csV0FBVztzQkFBbkIsS0FBSztnQkFDRyxhQUFhO3NCQUFyQixLQUFLO2dCQUNHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBQ0csWUFBWTtzQkFBcEIsS0FBSztnQkFDRyxZQUFZO3NCQUFwQixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csVUFBVTtzQkFBbEIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csVUFBVTtzQkFBbEIsS0FBSztnQkFDRyxnQkFBZ0I7c0JBQXhCLEtBQUs7Z0JBQ0cscUJBQXFCO3NCQUE3QixLQUFLO2dCQUNHLG1CQUFtQjtzQkFBM0IsS0FBSztnQkFDRyxzQkFBc0I7c0JBQTlCLEtBQUs7Z0JBQ0csMEJBQTBCO3NCQUFsQyxLQUFLO2dCQUNHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBQ0csWUFBWTtzQkFBcEIsS0FBSztnQkFDRyxlQUFlO3NCQUF2QixLQUFLO2dCQUVJLGVBQWU7c0JBQXhCLE1BQU07Z0JBQ0csU0FBUztzQkFBbEIsTUFBTTtnQkFDRyxVQUFVO3NCQUFuQixNQUFNO2dCQUNHLFNBQVM7c0JBQWxCLE1BQU07Z0JBQ0csb0JBQW9CO3NCQUE3QixNQUFNO2dCQUtILFVBQVU7c0JBRGIsU0FBUzt1QkFBQyxTQUFTO2dCQWVoQixjQUFjO3NCQURqQixTQUFTO3VCQUFDLGFBQWEsRUFBRSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUU7Z0JBYXZDLHdCQUF3QjtzQkFEM0IsU0FBUzt1QkFBQyx1QkFBdUIsRUFBRSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIElucHV0LCBPdXRwdXQsIEV2ZW50RW1pdHRlciwgVmlld0NoaWxkLCBFbGVtZW50UmVmLCBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3ksIE9uQ2hhbmdlcywgU2ltcGxlQ2hhbmdlcyB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRG9tU2FuaXRpemVyLCBTYWZlUmVzb3VyY2VVcmwgfSBmcm9tICdAYW5ndWxhci9wbGF0Zm9ybS1icm93c2VyJztcbmltcG9ydCB7IGdldEVtcHR5U3RhdGVQcmVzZXQgfSBmcm9tICcuLi9lbXB0eS1zdGF0ZS9lbXB0eS1zdGF0ZS1wcmVzZXRzLmNvbnN0YW50cyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3RlcE1hcmtlciB7XG4gIGN1bXVsYXRpdmVEdXJhdGlvbjogbnVtYmVyO1xuICByZXN1bHQ6ICdTVUNDRVNTJyB8ICdGQUlMVVJFJyB8ICdBQk9SVEVEJyB8ICdTS0lQUEVEJztcbiAgdGVzdFN0ZXBJZD86IG51bWJlcjtcbiAgbGV2ZWw/OiBudW1iZXI7XG4gIGNoaWxkU3RlcHM/OiBTdGVwTWFya2VyW107XG4gIHRpdGxlPzogc3RyaW5nO1xufVxuXG5leHBvcnQgdHlwZSBTZWdtZW50VHlwZSA9ICdzY3JlZW5zaG90cycgfCAndmlkZW8nIHwgJ3RyYWNlJztcblxudHlwZSBTZWdtZW50T3B0aW9uID0ge1xuICBsYWJlbDogc3RyaW5nO1xuICB2YWx1ZTogc3RyaW5nO1xuICBpY29uPzogc3RyaW5nO1xufTtcbmludGVyZmFjZSBEZXZpY2VGcmFtZUNvbmZpZyB7XG4gIG1vY2t1cEltYWdlOiBzdHJpbmc7XG4gIHNjcmVlbkluc2V0OiB7XG4gICAgdG9wOiBzdHJpbmc7XG4gICAgcmlnaHQ6IHN0cmluZztcbiAgICBib3R0b206IHN0cmluZztcbiAgICBsZWZ0OiBzdHJpbmc7XG4gIH07XG4gIGJvcmRlclJhZGl1czogc3RyaW5nO1xufVxuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjcWEtc2ltdWxhdG9yJyxcbiAgdGVtcGxhdGVVcmw6ICcuL3NpbXVsYXRvci5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogW11cbn0pXG5cbmV4cG9ydCBjbGFzcyBTaW11bGF0b3JDb21wb25lbnQgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3ksIE9uQ2hhbmdlcyB7XG5cbiAgQElucHV0KCkgdmlkZW9Vcmw6IHN0cmluZyA9ICcnO1xuICBASW5wdXQoKSB2aWRlb1VybHM6IHN0cmluZ1tdID0gW107XG4gIEBJbnB1dCgpIHZpZGVvQ3VycmVudER1cmF0aW9uOiBudW1iZXIgPSAwO1xuICBASW5wdXQoKSBzdGVwTWFya2VyczogU3RlcE1hcmtlcltdID0gW107XG4gIEBJbnB1dCgpIHNjcmVlblNob3RVcmw6IHN0cmluZyA9ICcnO1xuICBASW5wdXQoKSB0cmFjZVZpZXdVcmw6IHN0cmluZyA9ICcnO1xuICBASW5wdXQoKSBwbGF0Zm9ybU5hbWU6IHN0cmluZyA9ICdXZWIgLSBDaHJvbWUnO1xuICBASW5wdXQoKSBwbGF0Zm9ybVR5cGU6ICdicm93c2VyJyB8ICdkZXZpY2UnID0gJ2Jyb3dzZXInO1xuICBASW5wdXQoKSBwbGF0Zm9ybTogc3RyaW5nID0gJyc7XG4gIEBJbnB1dCgpIGRldmljZU5hbWU6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBASW5wdXQoKSBpc0xpdmU6IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgbGl2ZVN0YXR1czogJ0luIFByb2dyZXNzJyB8ICdQYXVzZWQnIHwgJ0Fib3J0ZWQnIHwgJ0ZhaWxlZCcgfCAnUGFzc2VkJyB8ICdFeGVjdXRpb24nID0gJ0luIFByb2dyZXNzJztcbiAgQElucHV0KCkgbGl2ZUxvYWRpbmdMYWJlbDogc3RyaW5nID0gJ0xvYWRpbmcuLi4nO1xuICBASW5wdXQoKSBpc0NvbnRlbnRWaWRlb0xvYWRpbmc6IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgZmFpbGVkU3RhdHVzTWVzc2FnZTogc3RyaW5nID0gJyc7XG4gIEBJbnB1dCgpIGlzVk5DU2Vzc2lvbkludHJ1cHB0ZWQ6IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgdm5jU2Vzc2lvbkludHVwcHRlZE1lc3NhZ2U6IHN0cmluZyA9ICcnO1xuICBASW5wdXQoKSBzZWxlY3RlZFZpZXc6IFNlZ21lbnRUeXBlID0gJ3ZpZGVvJztcbiAgQElucHV0KCkgaGlkZVZpZGVvVGFiOiBib29sZWFuID0gZmFsc2U7XG4gIEBJbnB1dCgpIGJyb3dzZXJWaWV3UG9ydDogeyB3aWR0aDogbnVtYmVyOyBoZWlnaHQ6IG51bWJlciB9IHwgbnVsbCA9IG51bGw7XG5cbiAgQE91dHB1dCgpIHZpZGVvVGltZVVwZGF0ZSA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyPigpO1xuICBAT3V0cHV0KCkgdmlkZW9QbGF5ID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xuICBAT3V0cHV0KCkgdmlkZW9QYXVzZSA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcbiAgQE91dHB1dCgpIG1hcmtlckhpdCA9IG5ldyBFdmVudEVtaXR0ZXI8U3RlcE1hcmtlcj4oKTtcbiAgQE91dHB1dCgpIGlzVmlkZW9QbGF5aW5nQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxib29sZWFuPigpO1xuXG4gIHByaXZhdGUgX3ZwbGF5ZXI/OiBFbGVtZW50UmVmPEhUTUxWaWRlb0VsZW1lbnQ+O1xuXG4gIEBWaWV3Q2hpbGQoJ3ZwbGF5ZXInKVxuICBzZXQgdnBsYXllclJlZihyZWY6IEVsZW1lbnRSZWY8SFRNTFZpZGVvRWxlbWVudD4gfCB1bmRlZmluZWQpIHtcbiAgICBpZiAoIXJlZikgcmV0dXJuO1xuXG4gICAgdGhpcy5fdnBsYXllciA9IHJlZjtcbiAgICB0aGlzLm9uVmlkZW9FbGVtZW50UmVhZHkoKTtcbiAgfVxuXG4gIGdldCB2cGxheWVyKCk6IEVsZW1lbnRSZWY8SFRNTFZpZGVvRWxlbWVudD4gfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLl92cGxheWVyO1xuICB9XG5cbiAgcHJpdmF0ZSBfdGltZWxpbmVCYXI/OiBFbGVtZW50UmVmPEhUTUxEaXZFbGVtZW50PjtcblxuICBAVmlld0NoaWxkKCd0aW1lbGluZUJhcicsIHsgc3RhdGljOiBmYWxzZSB9KVxuICBzZXQgdGltZWxpbmVCYXJSZWYocmVmOiBFbGVtZW50UmVmPEhUTUxEaXZFbGVtZW50PiB8IHVuZGVmaW5lZCkge1xuICAgIGlmICghcmVmKSByZXR1cm47XG4gICAgdGhpcy5fdGltZWxpbmVCYXIgPSByZWY7XG4gIH1cblxuICBnZXQgdGltZWxpbmVCYXIoKTogRWxlbWVudFJlZjxIVE1MRGl2RWxlbWVudD4gfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLl90aW1lbGluZUJhcjtcbiAgfVxuXG4gIHByaXZhdGUgX3NwZWVkQ29udHJvbENvbnRhaW5lcj86IEVsZW1lbnRSZWY8SFRNTERpdkVsZW1lbnQ+O1xuXG4gIEBWaWV3Q2hpbGQoJ3NwZWVkQ29udHJvbENvbnRhaW5lcicsIHsgc3RhdGljOiBmYWxzZSB9KVxuICBzZXQgc3BlZWRDb250cm9sQ29udGFpbmVyUmVmKHJlZjogRWxlbWVudFJlZjxIVE1MRGl2RWxlbWVudD4gfCB1bmRlZmluZWQpIHtcbiAgICBpZiAoIXJlZikgcmV0dXJuO1xuICAgIHRoaXMuX3NwZWVkQ29udHJvbENvbnRhaW5lciA9IHJlZjtcbiAgfVxuXG4gIGdldCBzcGVlZENvbnRyb2xDb250YWluZXIoKTogRWxlbWVudFJlZjxIVE1MRGl2RWxlbWVudD4gfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLl9zcGVlZENvbnRyb2xDb250YWluZXI7XG4gIH1cblxuICBwcm9ncmVzcyA9IDA7XG4gIGRyYWdnaW5nID0gZmFsc2U7XG4gIGlzUGxheWluZzogYm9vbGVhbiA9IGZhbHNlO1xuICBpc0Z1bGxTY3JlZW46IGJvb2xlYW4gPSBmYWxzZTtcbiAgY3VycmVudFZpZXc6IHN0cmluZyA9ICd2aWRlbyc7XG4gIGN1cnJlbnRWaWRlb0luZGV4OiBudW1iZXIgPSAwO1xuICBjdXJyZW50U3BlZWQ6IHN0cmluZyA9ICcxeCc7XG4gIGlzU3BlZWRDb250cm9sT3BlbjogYm9vbGVhbiA9IGZhbHNlO1xuICBwcml2YXRlIGRldGVjdGVkVmlkZW9EdXJhdGlvbnM6IG51bWJlcltdID0gW107IC8vIEFjdHVhbCBkdXJhdGlvbnMgZGV0ZWN0ZWQgZnJvbSB2aWRlbyBtZXRhZGF0YVxuICBwcml2YXRlIHdhc1BsYXlpbmdCZWZvcmVEcmFnOiBib29sZWFuID0gZmFsc2U7IC8vIFRyYWNrIGlmIHZpZGVvIHdhcyBwbGF5aW5nIGJlZm9yZSBkcmFnIHN0YXJ0ZWRcbiAgcHJpdmF0ZSBwbGF5UHJvbWlzZTogUHJvbWlzZTx2b2lkPiB8IG51bGwgPSBudWxsOyAvLyBUcmFjayB0aGUgY3VycmVudCBwbGF5IHByb21pc2VcbiAgcHJpdmF0ZSBoaXRNYXJrZXJzOiBTZXQ8bnVtYmVyPiA9IG5ldyBTZXQoKTsgLy8gVHJhY2sgd2hpY2ggbWFya2VycyBoYXZlIGJlZW4gaGl0IChieSB0ZXN0U3RlcElkKVxuXG4gIC8vIFN0YXRlIG1hY2hpbmUgZm9yIHJvYnVzdCBtZWRpYSBvcGVyYXRpb25zXG4gIHByaXZhdGUgcGxheWVyU3RhdGU6ICdpZGxlJyB8ICdsb2FkaW5nJyB8ICdyZWFkeScgfCAncGxheWluZycgfCAncGF1c2VkJyB8ICdzZWVraW5nJyB8ICdzd2l0Y2hpbmcnIHwgJ2Vycm9yJyA9ICdpZGxlJztcbiAgcHJpdmF0ZSBvcGVyYXRpb25RdWV1ZTogUHJvbWlzZTx2b2lkPiA9IFByb21pc2UucmVzb2x2ZSgpOyAvLyBTZXJpYWxpemUgYWxsIG1lZGlhIG9wZXJhdGlvbnNcblxuICBnZXQgaGFzRGV2aWNlRnJhbWUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICEhdGhpcy5kZXZpY2VGcmFtZUNvbmZpZztcbiAgfVxuXG4gIGdldCBpc1BsYXllclN3aXRjaGluZygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5wbGF5ZXJTdGF0ZSA9PT0gJ3N3aXRjaGluZyc7XG4gIH1cblxuICBzZWdtZW50czogU2VnbWVudE9wdGlvbltdID0gW1xuICAgIHsgbGFiZWw6ICdTY3JlZW5zaG90cycsIHZhbHVlOiAnc2NyZWVuc2hvdHMnLCBpY29uOiAncGhvdG8nICB9LFxuICAgIHsgbGFiZWw6ICdWaWRlbycsIHZhbHVlOiAndmlkZW8nLCBpY29uOiAndmlkZW9jYW0nIH0sXG4gIF07XG5cbiAgc3BlZWRTZWdtZW50czogU2VnbWVudE9wdGlvbltdID0gW1xuICAgIHsgbGFiZWw6ICcxeCcsIHZhbHVlOiAnMXgnIH0sXG4gICAgeyBsYWJlbDogJzJ4JywgdmFsdWU6ICcyeCcgfSxcbiAgICB7IGxhYmVsOiAnNXgnLCB2YWx1ZTogJzV4JyB9LFxuICBdO1xuXG4gIHByaXZhdGUgdmlkZW9FdmVudExpc3RlbmVyQ2xlYW51cDogKCgpID0+IHZvaWQpIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgbGFzdFNldER1cmF0aW9uOiBudW1iZXIgPSAtMTtcbiAgcHJpdmF0ZSBkcmFnTW91c2VNb3ZlSGFuZGxlcjogKChlOiBNb3VzZUV2ZW50KSA9PiB2b2lkKSB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGRyYWdNb3VzZVVwSGFuZGxlcjogKChlOiBNb3VzZUV2ZW50KSA9PiB2b2lkKSB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHNwZWVkQ29udHJvbENsaWNrT3V0c2lkZUhhbmRsZXI6ICgoZTogTW91c2VFdmVudCkgPT4gdm9pZCkgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBwcmVsb2FkVmlkZW9FbGVtZW50OiBIVE1MVmlkZW9FbGVtZW50IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgcHJlbG9hZEFsbFZpZGVvRWxlbWVudDogSFRNTFZpZGVvRWxlbWVudCB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHRhcmdldEdsb2JhbFRpbWVEdXJpbmdTd2l0Y2g6IG51bWJlciB8IG51bGwgPSBudWxsO1xuICBcbiAgc2FmZVRyYWNlVXJsOiBTYWZlUmVzb3VyY2VVcmw7XG4gIHRyYWNlVmlld2VyTG9hZGluZzogYm9vbGVhbiA9IGZhbHNlO1xuICB0cmFjZVZpZXdlckVycm9yOiBib29sZWFuID0gZmFsc2U7XG4gIGlzQ29ycmVjdERldmljZUZyYW1lQXZhaWxhYmxlOiBib29sZWFuID0gZmFsc2U7XG4gIHByaXZhdGUgcmVhZG9ubHkgZW1wdHlTdGF0ZUNvbmZpZyA9IGdldEVtcHR5U3RhdGVQcmVzZXQoJ25vdGhpbmdUb0Rpc3BsYXknKTtcbiAgcmVhZG9ubHkgZGV2aWNlRXJyb3JFbXB0eVN0YXRlQ29uZmlnID0ge1xuICAgIC4uLnRoaXMuZW1wdHlTdGF0ZUNvbmZpZyxcbiAgICB0aXRsZTogJ0RldmljZSBOb3QgU3VwcG9ydGVkJyxcbiAgICBkZXNjcmlwdGlvbjogJ1RoZSBkZXZpY2UgeW91IGFyZSB0cnlpbmcgdG8gdXNlIGlzIG5vdCBzdXBwb3J0ZWQuJyxcbiAgICBhY3Rpb25zOiBbXVxuICB9O1xuXG4gIGdldCBlZmZlY3RpdmVCcm93c2VyVmlld1BvcnQoKTogeyB3aWR0aDogbnVtYmVyOyBoZWlnaHQ6IG51bWJlciB9IHtcbiAgICBjb25zdCBkZWZhdWx0Vmlld3BvcnQgPSB7IHdpZHRoOiAxMjgwLCBoZWlnaHQ6IDcyMCB9O1xuXG4gICAgaWYgKCF0aGlzLmJyb3dzZXJWaWV3UG9ydCkge1xuICAgICAgcmV0dXJuIGRlZmF1bHRWaWV3cG9ydDtcbiAgICB9XG5cbiAgICBjb25zdCB3aWR0aCA9IE51bWJlcigodGhpcy5icm93c2VyVmlld1BvcnQgYXMgYW55KS53aWR0aCk7XG4gICAgY29uc3QgaGVpZ2h0ID0gTnVtYmVyKCh0aGlzLmJyb3dzZXJWaWV3UG9ydCBhcyBhbnkpLmhlaWdodCk7XG5cbiAgICBpZiAoIU51bWJlci5pc0Zpbml0ZSh3aWR0aCkgfHwgIU51bWJlci5pc0Zpbml0ZShoZWlnaHQpIHx8IHdpZHRoIDw9IDAgfHwgaGVpZ2h0IDw9IDApIHtcbiAgICAgIHJldHVybiBkZWZhdWx0Vmlld3BvcnQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgd2lkdGgsIGhlaWdodCB9O1xuICB9XG5cbiAgcHJpdmF0ZSByZWFkb25seSBkZXZpY2VGcmFtZUNvbmZpZ3M6IFJlY29yZDxzdHJpbmcsIERldmljZUZyYW1lQ29uZmlnPiA9IHtcbiAgICAvLyBQaXhlbHNcbiAgICAnUGl4ZWwgNSc6IHtcbiAgICAgIG1vY2t1cEltYWdlOiAnYXNzZXRzL2ltYWdlcy9tb2NrdXBzL3BpeGVsLTUucG5nJyxcbiAgICAgIHNjcmVlbkluc2V0OiB7XG4gICAgICAgIHRvcDogJzIlJyxcbiAgICAgICAgcmlnaHQ6ICc0LjUlJyxcbiAgICAgICAgYm90dG9tOiAnMiUnLFxuICAgICAgICBsZWZ0OiAnNC41JSdcbiAgICAgIH0sXG4gICAgICBib3JkZXJSYWRpdXM6ICc0JSdcbiAgICB9LFxuICAgICdQaXhlbCA4Jzoge1xuICAgICAgbW9ja3VwSW1hZ2U6ICdhc3NldHMvaW1hZ2VzL21vY2t1cHMvcGl4ZWwtOC5wbmcnLFxuICAgICAgc2NyZWVuSW5zZXQ6IHtcbiAgICAgICAgdG9wOiAnMiUnLFxuICAgICAgICByaWdodDogJzQuNSUnLFxuICAgICAgICBib3R0b206ICcyLjUlJyxcbiAgICAgICAgbGVmdDogJzQuNSUnXG4gICAgICB9LFxuICAgICAgYm9yZGVyUmFkaXVzOiAnNCUnXG4gICAgfSxcbiAgICAnUGl4ZWwgOSc6IHtcbiAgICAgIG1vY2t1cEltYWdlOiAnYXNzZXRzL2ltYWdlcy9tb2NrdXBzL3BpeGVsLTktcHJvLndlYnAnLFxuICAgICAgc2NyZWVuSW5zZXQ6IHtcbiAgICAgICAgdG9wOiAnNCUnLFxuICAgICAgICByaWdodDogJzUlJyxcbiAgICAgICAgYm90dG9tOiAnNCUnLFxuICAgICAgICBsZWZ0OiAnNSUnXG4gICAgICB9LFxuICAgICAgYm9yZGVyUmFkaXVzOiAnOCUnXG4gICAgfSxcbiAgICAvLyBpUGhvbmVzXG4gICAgJ2lQaG9uZSAxMSc6IHtcbiAgICAgIG1vY2t1cEltYWdlOiAnYXNzZXRzL2ltYWdlcy9tb2NrdXBzL2FwcGxlLWlwaG9uZS0xMS5wbmcnLFxuICAgICAgc2NyZWVuSW5zZXQ6IHtcbiAgICAgICAgdG9wOiAnMyUnLFxuICAgICAgICByaWdodDogJzcuNSUnLFxuICAgICAgICBib3R0b206ICczJScsXG4gICAgICAgIGxlZnQ6ICc3LjUlJ1xuICAgICAgfSxcbiAgICAgIGJvcmRlclJhZGl1czogJzQlJ1xuICAgIH0sXG4gICAgJ2lQaG9uZSAxMyc6IHtcbiAgICAgIG1vY2t1cEltYWdlOiAnYXNzZXRzL2ltYWdlcy9tb2NrdXBzL2FwcGxlLWlwaG9uZS0xMy5wbmcnLFxuICAgICAgc2NyZWVuSW5zZXQ6IHtcbiAgICAgICAgdG9wOiAnMiUnLFxuICAgICAgICByaWdodDogJzUlJyxcbiAgICAgICAgYm90dG9tOiAnMiUnLFxuICAgICAgICBsZWZ0OiAnNSUnXG4gICAgICB9LFxuICAgICAgYm9yZGVyUmFkaXVzOiAnNCUnXG4gICAgfSxcbiAgICAnaVBob25lIDE1Jzoge1xuICAgICAgbW9ja3VwSW1hZ2U6ICdhc3NldHMvaW1hZ2VzL21vY2t1cHMvYXBwbGUtaXBob25lLTE1LnBuZycsXG4gICAgICBzY3JlZW5JbnNldDoge1xuICAgICAgICB0b3A6ICcxLjUlJyxcbiAgICAgICAgcmlnaHQ6ICc0LjUlJyxcbiAgICAgICAgYm90dG9tOiAnMS41JScsXG4gICAgICAgIGxlZnQ6ICc0LjUlJ1xuICAgICAgfSxcbiAgICAgIGJvcmRlclJhZGl1czogJzQlJ1xuICAgIH0sXG4gICAgJ2lQaG9uZSBYUic6IHtcbiAgICAgIG1vY2t1cEltYWdlOiAnYXNzZXRzL2ltYWdlcy9tb2NrdXBzL2FwcGxlLWlwaG9uZS14ci5wbmcnLFxuICAgICAgc2NyZWVuSW5zZXQ6IHtcbiAgICAgICAgdG9wOiAnMy41JScsXG4gICAgICAgIHJpZ2h0OiAnNy41JScsXG4gICAgICAgIGJvdHRvbTogJzMuNSUnLFxuICAgICAgICBsZWZ0OiAnNy41JSdcbiAgICAgIH0sXG4gICAgICBib3JkZXJSYWRpdXM6ICc0JSdcbiAgICB9LFxuXG4gICAgJ0dhbGF4eSBTMjAgRkUnOiB7XG4gICAgICBtb2NrdXBJbWFnZTogJ2Fzc2V0cy9pbWFnZXMvbW9ja3Vwcy9zYW1zdW5nLWdhbGF4eS1zMjAucG5nJyxcbiAgICAgIHNjcmVlbkluc2V0OiB7XG4gICAgICAgIHRvcDogJzEuNSUnLFxuICAgICAgICByaWdodDogJzIlJyxcbiAgICAgICAgYm90dG9tOiAnMS41JScsXG4gICAgICAgIGxlZnQ6ICcyJSdcbiAgICAgIH0sXG4gICAgICBib3JkZXJSYWRpdXM6ICc0JSdcbiAgICB9LFxuXG4gICAgYnJvd3Nlcjoge1xuICAgICAgbW9ja3VwSW1hZ2U6ICdhc3NldHMvaW1hZ2VzL21vY2t1cHMvYnJvd3Nlci1tb2NrdXAucG5nJyxcbiAgICAgIHNjcmVlbkluc2V0OiB7XG4gICAgICAgIHRvcDogJzYlJyxcbiAgICAgICAgcmlnaHQ6ICcwJScsXG4gICAgICAgIGJvdHRvbTogJzAlJyxcbiAgICAgICAgbGVmdDogJzAlJ1xuICAgICAgfSxcbiAgICAgIGJvcmRlclJhZGl1czogJzAlJ1xuICAgIH1cbiAgfTtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHNhbml0aXplcjogRG9tU2FuaXRpemVyKSB7XG4gICAgdGhpcy5zYWZlVHJhY2VVcmwgPSB0aGlzLnNhbml0aXplci5ieXBhc3NTZWN1cml0eVRydXN0UmVzb3VyY2VVcmwoJycpO1xuICAgIHRoaXMudXBkYXRlU2VnbWVudHMoKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0IGRldmljZUZyYW1lQ29uZmlnKCk6IERldmljZUZyYW1lQ29uZmlnIHwgbnVsbCB7XG4gICAgaWYgKHRoaXMucGxhdGZvcm1UeXBlID09PSAnYnJvd3NlcicpIHtcbiAgICAgIHJldHVybiB0aGlzLmRldmljZUZyYW1lQ29uZmlnc1snYnJvd3NlciddIHx8IG51bGw7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMucGxhdGZvcm1UeXBlID09PSAnZGV2aWNlJykge1xuICAgICAgLy8gSWYgd2UgaGF2ZSBhIGRldmljZU5hbWUgYW5kIGl0cyBmcmFtZSBpcyBhdmFpbGFibGUsIHJldHVybiBpdFxuICAgICAgaWYgKHRoaXMuZGV2aWNlTmFtZSAmJiB0aGlzLmRldmljZUZyYW1lQ29uZmlnc1t0aGlzLmRldmljZU5hbWVdKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRldmljZUZyYW1lQ29uZmlnc1t0aGlzLmRldmljZU5hbWVdO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBJZiBubyBkZXZpY2VOYW1lIG9yIGRldmljZU5hbWUncyBmcmFtZSBub3QgYXZhaWxhYmxlLCB1c2UgZGVmYXVsdHMgYmFzZWQgb24gcGxhdGZvcm1cbiAgICAgIGlmICh0aGlzLnBsYXRmb3JtID09PSAnYW5kcm9pZCcpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGV2aWNlRnJhbWVDb25maWdzWydQaXhlbCA5J10gfHwgbnVsbDtcbiAgICAgIH1cbiAgICAgIGlmICh0aGlzLnBsYXRmb3JtID09PSAnaW9zJykge1xuICAgICAgICByZXR1cm4gdGhpcy5kZXZpY2VGcmFtZUNvbmZpZ3NbJ2lQaG9uZSAxNSddIHx8IG51bGw7XG4gICAgICB9XG4gICAgICBcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgZ2V0IGRldmljZU1vY2t1cEltYWdlKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuZGV2aWNlRnJhbWVDb25maWcgPyB0aGlzLmRldmljZUZyYW1lQ29uZmlnLm1vY2t1cEltYWdlIDogJyc7XG4gIH1cblxuICBnZXQgZGV2aWNlU2NyZWVuU3R5bGUoKTogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfSB7XG4gICAgY29uc3QgY2ZnID0gdGhpcy5kZXZpY2VGcmFtZUNvbmZpZztcbiAgICBpZiAoIWNmZykge1xuICAgICAgcmV0dXJuIHt9O1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBwb3NpdGlvbjogJ2Fic29sdXRlJyxcbiAgICAgIHRvcDogY2ZnLnNjcmVlbkluc2V0LnRvcCxcbiAgICAgIHJpZ2h0OiBjZmcuc2NyZWVuSW5zZXQucmlnaHQsXG4gICAgICBib3R0b206IGNmZy5zY3JlZW5JbnNldC5ib3R0b20sXG4gICAgICBsZWZ0OiBjZmcuc2NyZWVuSW5zZXQubGVmdCxcbiAgICAgICdib3JkZXItcmFkaXVzJzogY2ZnLmJvcmRlclJhZGl1cyxcbiAgICAgIG92ZXJmbG93OiAnaGlkZGVuJ1xuICAgIH07XG4gIH1cblxuICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG4gICAgdGhpcy5jdXJyZW50VmlldyA9IHRoaXMuc2VsZWN0ZWRWaWV3O1xuICAgIHRoaXMuYXR0YWNoVmlkZW9MaXN0ZW5lcnMoKTtcbiAgICB0aGlzLnVwZGF0ZVNhZmVUcmFjZVVybCgpO1xuICB9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmIChjaGFuZ2VzWyd2aWRlb1VybHMnXSkge1xuICAgICAgY29uc3QgYXJyID0gY2hhbmdlc1sndmlkZW9VcmxzJ10uY3VycmVudFZhbHVlIGFzIHN0cmluZ1tdIHwgdW5kZWZpbmVkO1xuICAgICAgaWYgKGFyciAmJiBhcnIubGVuZ3RoID4gMCkge1xuICAgICAgICB0aGlzLmN1cnJlbnRWaWRlb0luZGV4ID0gMDtcbiAgICAgICAgdGhpcy5kZXRlY3RWaWRlb0R1cmF0aW9ucyhhcnIpO1xuICAgICAgICB0aGlzLnNjaGVkdWxlUHJlbG9hZEFsbFNlZ21lbnRzKGFycik7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChjaGFuZ2VzWyd2aWRlb0N1cnJlbnREdXJhdGlvbiddICYmICFjaGFuZ2VzWyd2aWRlb0N1cnJlbnREdXJhdGlvbiddLmZpcnN0Q2hhbmdlKSB7XG4gICAgICBjb25zdCBuZXdEdXJhdGlvbiA9IGNoYW5nZXNbJ3ZpZGVvQ3VycmVudER1cmF0aW9uJ10uY3VycmVudFZhbHVlO1xuICAgICAgLy8gSWdub3JlIHNlbnRpbmVsIHZhbHVlICgtMSkgdXNlZCB0byBmb3JjZSBjaGFuZ2UgZGV0ZWN0aW9uXG4gICAgICBpZiAobmV3RHVyYXRpb24gPT09IC0xKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgaWYgKHRoaXMuaXNQbGF5aW5nKSB7XG4gICAgICAgIHRoaXMucGF1c2VWaWRlbygpO1xuICAgICAgICBjb25zb2xlLmxvZygnW1NpbXVsYXRvcl0gbmdPbkNoYW5nZXMgdmlkZW9DdXJyZW50RHVyYXRpb246IHBhdXNlZCB2aWRlbyBiZWZvcmUgc2Vla2luZycpO1xuICAgICAgfVxuICAgICAgXG4gICAgICBpZiAodGhpcy5oYXNNdWx0aXBsZVZpZGVvcykge1xuICAgICAgICBjb25zdCB0YXJnZXRWaWRlb0luZGV4ID0gdGhpcy5maW5kVmlkZW9JbmRleEZvclRpbWVzdGFtcChuZXdEdXJhdGlvbik7XG4gICAgICAgIGlmICh0YXJnZXRWaWRlb0luZGV4ICE9PSBudWxsKSB7XG4gICAgICAgICAgY29uc3QgYm91bmRhcmllcyA9IHRoaXMuZ2V0VmlkZW9EdXJhdGlvbkJvdW5kYXJpZXMoKTtcbiAgICAgICAgICBjb25zdCB0YXJnZXRCb3VuZGFyeSA9IGJvdW5kYXJpZXNbdGFyZ2V0VmlkZW9JbmRleF07XG4gICAgICAgICAgY29uc3QgcmVsYXRpdmVUaW1lc3RhbXAgPSBuZXdEdXJhdGlvbiAtIHRhcmdldEJvdW5kYXJ5LnN0YXJ0O1xuICAgICAgICAgIFxuICAgICAgICAgIGNvbnN0IG5lZWRzU3dpdGNoID0gdGhpcy5jdXJyZW50VmlkZW9JbmRleCAhPT0gdGFyZ2V0VmlkZW9JbmRleDtcbiAgICAgICAgICBcbiAgICAgICAgICBpZiAodGhpcy52cGxheWVyPy5uYXRpdmVFbGVtZW50KSB7XG4gICAgICAgICAgICBjb25zdCBjdXJyZW50VmlkZW9UaW1lTXMgPSB0aGlzLnZwbGF5ZXIubmF0aXZlRWxlbWVudC5jdXJyZW50VGltZSAqIDEwMDA7XG4gICAgICAgICAgICBjb25zdCB0aW1lRGlmZmVyZW5jZSA9IE1hdGguYWJzKHJlbGF0aXZlVGltZXN0YW1wIC0gY3VycmVudFZpZGVvVGltZU1zKTtcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgaWYgKG5lZWRzU3dpdGNoIHx8IG5ld0R1cmF0aW9uICE9PSB0aGlzLmxhc3RTZXREdXJhdGlvbiB8fCB0aW1lRGlmZmVyZW5jZSA+IDEwMCkge1xuICAgICAgICAgICAgICB0aGlzLnN3aXRjaFRvVmlkZW9BbmRTZWVrKG5ld0R1cmF0aW9uKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKG5lZWRzU3dpdGNoKSB7XG4gICAgICAgICAgICAgIHRoaXMuY3VycmVudFZpZGVvSW5kZXggPSB0YXJnZXRWaWRlb0luZGV4O1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKHRoaXMudnBsYXllcj8ubmF0aXZlRWxlbWVudCkge1xuICAgICAgICAgIGNvbnN0IGN1cnJlbnRWaWRlb1RpbWVNcyA9IHRoaXMudnBsYXllci5uYXRpdmVFbGVtZW50LmN1cnJlbnRUaW1lICogMTAwMDtcbiAgICAgICAgICBjb25zdCB0aW1lRGlmZmVyZW5jZSA9IE1hdGguYWJzKG5ld0R1cmF0aW9uIC0gY3VycmVudFZpZGVvVGltZU1zKTtcbiAgICAgICAgICBpZiAobmV3RHVyYXRpb24gIT09IHRoaXMubGFzdFNldER1cmF0aW9uIHx8IHRpbWVEaWZmZXJlbmNlID4gMTAwKSB7XG4gICAgICAgICAgICB0aGlzLnNlZWtUb1RpbWUobmV3RHVyYXRpb24pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICBpZiAoY2hhbmdlc1sndHJhY2VWaWV3VXJsJ10pIHtcbiAgICAgIHRoaXMudXBkYXRlU2FmZVRyYWNlVXJsKCk7XG4gICAgICB0aGlzLnVwZGF0ZVNlZ21lbnRzKCk7XG4gICAgICBpZiAoIXRoaXMudHJhY2VWaWV3VXJsICYmIHRoaXMuY3VycmVudFZpZXcgPT09ICd0cmFjZScpIHtcbiAgICAgICAgdGhpcy5jdXJyZW50VmlldyA9IHRoaXMuaGlkZVZpZGVvVGFiID8gJ3NjcmVlbnNob3RzJyA6ICd2aWRlbyc7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChjaGFuZ2VzWydoaWRlVmlkZW9UYWInXSkge1xuICAgICAgdGhpcy51cGRhdGVTZWdtZW50cygpO1xuICAgIH1cbiAgICBpZiAoY2hhbmdlc1snc2VsZWN0ZWRWaWV3J10pIHtcbiAgICAgIHRoaXMuY3VycmVudFZpZXcgPSBjaGFuZ2VzWydzZWxlY3RlZFZpZXcnXS5jdXJyZW50VmFsdWU7XG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgaWYgKHRoaXMudmlkZW9FdmVudExpc3RlbmVyQ2xlYW51cCkge1xuICAgICAgdGhpcy52aWRlb0V2ZW50TGlzdGVuZXJDbGVhbnVwKCk7XG4gICAgfVxuICAgIGlmICh0aGlzLnByZWxvYWRWaWRlb0VsZW1lbnQpIHtcbiAgICAgIHRoaXMucHJlbG9hZFZpZGVvRWxlbWVudC5zcmMgPSAnJztcbiAgICAgIHRoaXMucHJlbG9hZFZpZGVvRWxlbWVudC5yZW1vdmUoKTtcbiAgICAgIHRoaXMucHJlbG9hZFZpZGVvRWxlbWVudCA9IG51bGw7XG4gICAgfVxuICAgIGlmICh0aGlzLnByZWxvYWRBbGxWaWRlb0VsZW1lbnQpIHtcbiAgICAgIHRoaXMucHJlbG9hZEFsbFZpZGVvRWxlbWVudC5zcmMgPSAnJztcbiAgICAgIHRoaXMucHJlbG9hZEFsbFZpZGVvRWxlbWVudC5yZW1vdmUoKTtcbiAgICAgIHRoaXMucHJlbG9hZEFsbFZpZGVvRWxlbWVudCA9IG51bGw7XG4gICAgfVxuICAgIHRoaXMucmVtb3ZlRHJhZ0xpc3RlbmVycygpO1xuICAgIHRoaXMucmVtb3ZlU3BlZWRDb250cm9sQ2xpY2tPdXRzaWRlTGlzdGVuZXIoKTtcbiAgICBjb25zb2xlLmxvZygnW1NpbXVsYXRvcl0gbmdPbkRlc3Ryb3k6IGNsZWFuZWQgdXAgbGlzdGVuZXJzJyk7XG4gIH1cblxuICAvKipcbiAgICogU2VlayB2aWRlbyAtIHB1YmxpYyBtZXRob2QgKGVucXVldWVzIG9wZXJhdGlvbilcbiAgICovXG4gIHNlZWtUb1RpbWUobWlsbGlzZWNvbmRzOiBudW1iZXIpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMudnBsYXllcj8ubmF0aXZlRWxlbWVudCkgcmV0dXJuO1xuICAgIHRoaXMuZW5xdWV1ZU9wZXJhdGlvbigoKSA9PiB0aGlzLnNlZWtUb1RpbWVJbnRlcm5hbChtaWxsaXNlY29uZHMpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZWVrIHRvIGEgZ2xvYmFsIHRpbWUgb24gdGhlIGNvbWJpbmVkIHRpbWVsaW5lIChjb252ZXJ0cyB0byBzZWdtZW50ICsgbG9jYWwgdGltZSlcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgc2Vla1RvR2xvYmFsVGltZShnbG9iYWxUaW1lTXM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHRvdGFsID0gdGhpcy50b3RhbER1cmF0aW9uO1xuICAgIGlmICh0b3RhbCA8PSAwKSByZXR1cm47XG5cbiAgICBjb25zdCBjbGFtcGVkR2xvYmFsID0gTWF0aC5tYXgoMCwgTWF0aC5taW4oZ2xvYmFsVGltZU1zLCB0b3RhbCkpO1xuICAgIGNvbnN0IGJvdW5kYXJpZXMgPSB0aGlzLnNlZ21lbnRCb3VuZGFyaWVzO1xuXG4gICAgbGV0IHNlZ21lbnRJbmRleCA9IDA7XG4gICAgbGV0IHNlZ21lbnRTdGFydCA9IDA7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBib3VuZGFyaWVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoY2xhbXBlZEdsb2JhbCA8IGJvdW5kYXJpZXNbaV0pIHtcbiAgICAgICAgc2VnbWVudEluZGV4ID0gaTtcbiAgICAgICAgc2VnbWVudFN0YXJ0ID0gaSA9PT0gMCA/IDAgOiBib3VuZGFyaWVzW2kgLSAxXTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBzZWdtZW50SW5kZXggPSBpO1xuICAgICAgc2VnbWVudFN0YXJ0ID0gaSA9PT0gMCA/IDAgOiBib3VuZGFyaWVzW2kgLSAxXTtcbiAgICB9XG4gICAgaWYgKGJvdW5kYXJpZXMubGVuZ3RoID4gMCAmJiBjbGFtcGVkR2xvYmFsID49IGJvdW5kYXJpZXNbYm91bmRhcmllcy5sZW5ndGggLSAxXSkge1xuICAgICAgc2VnbWVudEluZGV4ID0gYm91bmRhcmllcy5sZW5ndGggLSAxO1xuICAgICAgc2VnbWVudFN0YXJ0ID0gc2VnbWVudEluZGV4ID09PSAwID8gMCA6IGJvdW5kYXJpZXNbc2VnbWVudEluZGV4IC0gMV07XG4gICAgfVxuXG4gICAgY29uc3QgbG9jYWxUaW1lTXMgPSBjbGFtcGVkR2xvYmFsIC0gc2VnbWVudFN0YXJ0O1xuXG4gICAgaWYgKHRoaXMuY3VycmVudFZpZGVvSW5kZXggPT09IHNlZ21lbnRJbmRleCkge1xuICAgICAgYXdhaXQgdGhpcy5zZWVrVG9UaW1lSW50ZXJuYWwobG9jYWxUaW1lTXMpO1xuICAgICAgLy8gVXBkYXRlIHByb2dyZXNzIGFmdGVyIHNlZWsgaW4gc2FtZSBzZWdtZW50XG4gICAgICBpZiAodGhpcy50b3RhbER1cmF0aW9uID4gMCkge1xuICAgICAgICB0aGlzLnByb2dyZXNzID0gTWF0aC5taW4oMTAwLCBNYXRoLm1heCgwLCAodGhpcy5nbG9iYWxDdXJyZW50VGltZSAvIHRoaXMudG90YWxEdXJhdGlvbikgKiAxMDApKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgY3VtdWxhdGl2ZVRpbWVzdGFtcCA9IHNlZ21lbnRTdGFydCArIGxvY2FsVGltZU1zO1xuICAgICAgYXdhaXQgdGhpcy5zd2l0Y2hUb1ZpZGVvQW5kU2Vla0ludGVybmFsKGN1bXVsYXRpdmVUaW1lc3RhbXApO1xuICAgICAgLy8gUHJvZ3Jlc3MgaXMgYWxyZWFkeSB1cGRhdGVkIGluc2lkZSBzd2l0Y2hUb1ZpZGVvQW5kU2Vla0ludGVybmFsXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNlZWsgdmlkZW8gaW50ZXJuYWwgaW1wbGVtZW50YXRpb24gKG5vIGVucXVldWUgLSBjYWxsZWQgZnJvbSBxdWV1ZSlcbiAgICogVGhpcyBwcmV2ZW50cyBwaXBlbGluZSByZWFkIGVycm9ycyBkdXJpbmcgcmFwaWQgc2VlayBvcGVyYXRpb25zXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHNlZWtUb1RpbWVJbnRlcm5hbChtaWxsaXNlY29uZHM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHZpZGVvID0gdGhpcy52cGxheWVyPy5uYXRpdmVFbGVtZW50O1xuICAgIGlmICghdmlkZW8gfHwgIXZpZGVvLmR1cmF0aW9uKSByZXR1cm47XG5cbiAgICBjb25zdCBzZWNvbmRzID0gbWlsbGlzZWNvbmRzIC8gMTAwMDtcbiAgICBjb25zdCB0YXJnZXRUaW1lID0gTWF0aC5tYXgoMCwgTWF0aC5taW4oc2Vjb25kcywgdmlkZW8uZHVyYXRpb24pKTtcblxuICAgIGNvbnNvbGUubG9nKCdbU2ltdWxhdG9yXSBzZWVrVG9UaW1lSW50ZXJuYWw6IHNlZWtpbmcnLCB7XG4gICAgICBtaWxsaXNlY29uZHMsXG4gICAgICB0YXJnZXRUaW1lLFxuICAgICAgcGxheWVyU3RhdGU6IHRoaXMucGxheWVyU3RhdGUsXG4gICAgICBjdXJyZW50VGltZUJlZm9yZTogdmlkZW8uY3VycmVudFRpbWVcbiAgICB9KTtcbiAgICBcbiAgICAvLyBTZXQgc2Vla2luZyBzdGF0ZVxuICAgIHRoaXMucGxheWVyU3RhdGUgPSAnc2Vla2luZyc7XG5cbiAgICAvLyBDUklUSUNBTDogUGF1c2UgYmVmb3JlIHNlZWtpbmcgdG8gYXZvaWQgcGlwZWxpbmUgZXJyb3JzXG4gICAgICB2aWRlby5wYXVzZSgpO1xuICAgIFxuICAgIC8vIFVwZGF0ZSBzdGF0ZVxuICAgIHRoaXMuaXNQbGF5aW5nID0gZmFsc2U7XG4gICAgdGhpcy5wbGF5UHJvbWlzZSA9IG51bGw7XG4gICAgdGhpcy52aWRlb1BhdXNlLmVtaXQoKTtcbiAgICB0aGlzLmlzVmlkZW9QbGF5aW5nQ2hhbmdlLmVtaXQoZmFsc2UpO1xuXG4gICAgLy8gUGVyZm9ybSBzZWVrXG4gICAgdmlkZW8uY3VycmVudFRpbWUgPSB0YXJnZXRUaW1lO1xuICAgIHRoaXMubGFzdFNldER1cmF0aW9uID0gbWlsbGlzZWNvbmRzO1xuICAgIFxuICAgIC8vIFdhaXQgYnJpZWZseSBmb3Igc2VlayB0byBjb21wbGV0ZSAocHJldmVudHMgcmFwaWQgc2VlayBpc3N1ZXMpXG4gICAgYXdhaXQgbmV3IFByb21pc2UocmVzb2x2ZSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIDUwKSk7XG5cbiAgICBjb25zdCB0b3RhbCA9IHRoaXMudG90YWxEdXJhdGlvbjtcbiAgICBpZiAodG90YWwgPiAwKSB7XG4gICAgICB0aGlzLnByb2dyZXNzID0gTWF0aC5taW4oMTAwLCBNYXRoLm1heCgwLCAodGhpcy5nbG9iYWxDdXJyZW50VGltZSAvIHRvdGFsKSAqIDEwMCkpO1xuICAgIH1cbiAgICB0aGlzLnZpZGVvVGltZVVwZGF0ZS5lbWl0KHRoaXMuZ2xvYmFsQ3VycmVudFRpbWUpO1xuICAgIFxuICAgIC8vIFNldCB0byBwYXVzZWQgc3RhdGUgKHVzZXIgbXVzdCBleHBsaWNpdGx5IHBsYXkpXG4gICAgdGhpcy5wbGF5ZXJTdGF0ZSA9ICdwYXVzZWQnO1xuXG4gICAgY29uc29sZS5sb2coJ1tTaW11bGF0b3JdIHNlZWtUb1RpbWVJbnRlcm5hbDogc2VlayBjb21wbGV0ZScsIHtcbiAgICAgIGN1cnJlbnRUaW1lQWZ0ZXI6IHZpZGVvLmN1cnJlbnRUaW1lLFxuICAgICAgcGxheWVyU3RhdGU6IHRoaXMucGxheWVyU3RhdGVcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUb2dnbGUgcGxheS9wYXVzZSAobm93IHRyaXZpYWwgd2l0aCBzdGF0ZSBtYWNoaW5lKVxuICAgKi9cbiAgdG9nZ2xlUGxheSgpOiB2b2lkIHtcbiAgICBjb25zdCB2aWRlbyA9IHRoaXMudnBsYXllcj8ubmF0aXZlRWxlbWVudDtcbiAgICBpZiAoIXZpZGVvKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdbU2ltdWxhdG9yXSB0b2dnbGVQbGF5OiB2aWRlbyBlbGVtZW50IG5vdCBmb3VuZCcsIHtcbiAgICAgICAgcGxheWVyU3RhdGU6IHRoaXMucGxheWVyU3RhdGUsXG4gICAgICAgIGlzRnVsbFNjcmVlbjogdGhpcy5pc0Z1bGxTY3JlZW5cbiAgICAgIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIENoZWNrIGZvciB2YWxpZCBzb3VyY2VcbiAgICBpZiAoIXRoaXMuY3VycmVudFZpZGVvVXJsIHx8IHZpZGVvLm5ldHdvcmtTdGF0ZSA9PT0gSFRNTE1lZGlhRWxlbWVudC5ORVRXT1JLX05PX1NPVVJDRSB8fCB2aWRlby5lcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignW1NpbXVsYXRvcl0gdG9nZ2xlUGxheTogbm8gdmFsaWQgc291cmNlJywge1xuICAgICAgICBjdXJyZW50VmlkZW9Vcmw6IHRoaXMuY3VycmVudFZpZGVvVXJsLFxuICAgICAgICBuZXR3b3JrU3RhdGU6IHZpZGVvLm5ldHdvcmtTdGF0ZSxcbiAgICAgICAgZXJyb3I6IHZpZGVvLmVycm9yXG4gICAgICB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBSZWNvdmVyIGZyb20gc3R1Y2sgJ2xvYWRpbmcnIHN0YXRlIHdoZW4gdmlkZW8gaXMgYWN0dWFsbHkgcmVhZHkgKGUuZy4gYWZ0ZXIganVtcC10by1zZWdtZW50KVxuICAgIGlmICh0aGlzLnBsYXllclN0YXRlID09PSAnbG9hZGluZycgJiYgdmlkZW8ucmVhZHlTdGF0ZSA+PSBIVE1MTWVkaWFFbGVtZW50LkhBVkVfTUVUQURBVEEpIHtcbiAgICAgIHRoaXMucGxheWVyU3RhdGUgPSAncGF1c2VkJztcbiAgICB9XG5cbiAgICAvLyBEb24ndCBhbGxvdyBwbGF5IGR1cmluZyBlcnJvciBzdGF0ZVxuICAgIGlmICh0aGlzLnBsYXllclN0YXRlID09PSAnZXJyb3InKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ1tTaW11bGF0b3JdIHRvZ2dsZVBsYXk6IHBsYXllciBpbiBlcnJvciBzdGF0ZScsIHsgcmVhZHlTdGF0ZTogdmlkZW8ucmVhZHlTdGF0ZSB9KTtcbiAgICAgIHRoaXMucGxheWVyU3RhdGUgPSAnaWRsZSc7XG4gICAgfVxuXG4gICAgLy8gSWYgc3RpbGwgbG9hZGluZyBhbmQgdmlkZW8gbm90IHJlYWR5LCB3YWl0IGFuZCByZXRyeVxuICAgIGlmICh0aGlzLnBsYXllclN0YXRlID09PSAnbG9hZGluZycpIHtcbiAgICAgIGNvbnNvbGUud2FybignW1NpbXVsYXRvcl0gdG9nZ2xlUGxheTogcGxheWVyIG5vdCByZWFkeScsIHtcbiAgICAgICAgcGxheWVyU3RhdGU6IHRoaXMucGxheWVyU3RhdGUsXG4gICAgICAgIHJlYWR5U3RhdGU6IHZpZGVvLnJlYWR5U3RhdGVcbiAgICAgIH0pO1xuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIGlmICh2aWRlby5yZWFkeVN0YXRlID49IEhUTUxNZWRpYUVsZW1lbnQuSEFWRV9NRVRBREFUQSAmJiB0aGlzLnBsYXllclN0YXRlICE9PSAncGxheWluZycpIHtcbiAgICAgICAgICB0aGlzLnRvZ2dsZVBsYXkoKTtcbiAgICAgICAgfVxuICAgICAgfSwgNTApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnNvbGUubG9nKCdbU2ltdWxhdG9yXSB0b2dnbGVQbGF5OicsIHtcbiAgICAgIHBsYXllclN0YXRlOiB0aGlzLnBsYXllclN0YXRlLFxuICAgICAgaXNQbGF5aW5nOiB0aGlzLmlzUGxheWluZyxcbiAgICAgIHJlYWR5U3RhdGU6IHZpZGVvLnJlYWR5U3RhdGVcbiAgICB9KTtcblxuICAgIC8vIFNpbXBsZSB0b2dnbGUgYmFzZWQgb24gc3RhdGVcbiAgICBpZiAodGhpcy5wbGF5ZXJTdGF0ZSA9PT0gJ3BsYXlpbmcnKSB7XG4gICAgICB0aGlzLnBhdXNlVmlkZW8oKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5wbGF5VmlkZW8oKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUGxheSB2aWRlbyAtIHB1YmxpYyBtZXRob2QgKGVucXVldWVzIG9wZXJhdGlvbilcbiAgICovXG4gIHByaXZhdGUgcGxheVZpZGVvKCk6IHZvaWQge1xuICAgIHRoaXMuZW5xdWV1ZU9wZXJhdGlvbigoKSA9PiB0aGlzLnBsYXlWaWRlb0ludGVybmFsKCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFBsYXkgdmlkZW8gaW50ZXJuYWwgaW1wbGVtZW50YXRpb24gKG5vIGVucXVldWUgLSBjYWxsZWQgZnJvbSBxdWV1ZSlcbiAgICogVGhpcyBlbGltaW5hdGVzIEZGbXBlZ0RlbXV4ZXIgZXJyb3JzIGFuZCBwbGF5IHByb21pc2UgaW50ZXJydXB0aW9uc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBwbGF5VmlkZW9JbnRlcm5hbCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB2aWRlbyA9IHRoaXMudnBsYXllcj8ubmF0aXZlRWxlbWVudDtcbiAgICBpZiAoIXZpZGVvKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdbU2ltdWxhdG9yXSBwbGF5VmlkZW9JbnRlcm5hbDogdmlkZW8gZWxlbWVudCBub3QgZm91bmQnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBBbHJlYWR5IHBsYXlpbmcgLSBza2lwXG4gICAgaWYgKHRoaXMucGxheWVyU3RhdGUgPT09ICdwbGF5aW5nJykge1xuICAgICAgY29uc29sZS5sb2coJ1tTaW11bGF0b3JdIHBsYXlWaWRlb0ludGVybmFsOiBhbHJlYWR5IHBsYXlpbmcsIHNraXBwaW5nJyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuaGFzTXVsdGlwbGVWaWRlb3MgJiYgdGhpcy52aWRlb1VybHMpIHtcbiAgICAgIGNvbnN0IHRvdGFsID0gdGhpcy50b3RhbER1cmF0aW9uO1xuICAgICAgY29uc3QgY3VycmVudEdsb2JhbFRpbWUgPSB0aGlzLmdsb2JhbEN1cnJlbnRUaW1lO1xuICAgICAgY29uc3QgaXNBdEVuZCA9IHRvdGFsID4gMCAmJiAodGhpcy5wcm9ncmVzcyA+PSAxMDAgfHwgY3VycmVudEdsb2JhbFRpbWUgPj0gdG90YWwpO1xuICAgICAgY29uc3QgaXNMYXN0VmlkZW8gPSB0aGlzLmN1cnJlbnRWaWRlb0luZGV4ID49IHRoaXMudmlkZW9VcmxzLmxlbmd0aCAtIDE7XG4gICAgICBjb25zdCBpc0xhc3RWaWRlb0F0RW5kID0gaXNMYXN0VmlkZW8gJiYgdmlkZW8uZHVyYXRpb24gJiYgdmlkZW8uY3VycmVudFRpbWUgPj0gdmlkZW8uZHVyYXRpb24gLSAwLjE7XG4gICAgICBcbiAgICAgIGlmIChpc0F0RW5kIHx8IGlzTGFzdFZpZGVvQXRFbmQpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ1tTaW11bGF0b3JdIHBsYXlWaWRlb0ludGVybmFsOiBhbGwgdmlkZW9zIGNvbXBsZXRlZCwgcmVzZXR0aW5nIHRvIGZpcnN0IHZpZGVvJywge1xuICAgICAgICAgIHByb2dyZXNzOiB0aGlzLnByb2dyZXNzLFxuICAgICAgICAgIGN1cnJlbnRHbG9iYWxUaW1lLFxuICAgICAgICAgIHRvdGFsLFxuICAgICAgICAgIGN1cnJlbnRWaWRlb0luZGV4OiB0aGlzLmN1cnJlbnRWaWRlb0luZGV4LFxuICAgICAgICAgIGlzQXRFbmQsXG4gICAgICAgICAgaXNMYXN0VmlkZW9BdEVuZFxuICAgICAgICB9KTtcbiAgICAgICAgXG4gICAgICAgIC8vIFJlc2V0IHRvIGZpcnN0IHZpZGVvIGF0IDAgcHJvZ3Jlc3NcbiAgICAgICAgdGhpcy5jdXJyZW50VmlkZW9JbmRleCA9IDA7XG4gICAgICAgIHRoaXMucHJvZ3Jlc3MgPSAwO1xuICAgICAgICB0aGlzLnRhcmdldEdsb2JhbFRpbWVEdXJpbmdTd2l0Y2ggPSAwO1xuICAgICAgICB0aGlzLmhpdE1hcmtlcnMuY2xlYXIoKTtcbiAgICAgICAgXG4gICAgICAgIC8vIFN3aXRjaCB0byBmaXJzdCB2aWRlbyBhbmQgc2VlayB0byAwXG4gICAgICAgIGF3YWl0IHRoaXMuc3dpdGNoVG9WaWRlb0FuZFNlZWtJbnRlcm5hbCgwKTtcbiAgICAgICAgXG4gICAgICAgIC8vIFVwZGF0ZSB2aWRlbyByZWZlcmVuY2UgYWZ0ZXIgc3dpdGNoXG4gICAgICAgIGNvbnN0IHZpZGVvQWZ0ZXJTd2l0Y2ggPSB0aGlzLnZwbGF5ZXI/Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgICAgIGlmICghdmlkZW9BZnRlclN3aXRjaCkge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ1tTaW11bGF0b3JdIHBsYXlWaWRlb0ludGVybmFsOiB2aWRlbyBlbGVtZW50IG5vdCBmb3VuZCBhZnRlciBzd2l0Y2gnKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIC8vIENvbnRpbnVlIHdpdGggbm9ybWFsIHBsYXkgbG9naWMgYmVsb3dcbiAgICAgICAgLy8gVGhlIHZpZGVvIGVsZW1lbnQgcmVmZXJlbmNlIGhhcyBjaGFuZ2VkLCBzbyB3ZSdsbCB1c2UgdmlkZW9BZnRlclN3aXRjaFxuICAgICAgICAvLyBCdXQgd2UgbmVlZCB0byB3YWl0IGZvciBtZXRhZGF0YSBhZ2FpblxuICAgICAgICBpZiAodmlkZW9BZnRlclN3aXRjaC5yZWFkeVN0YXRlIDwgSFRNTE1lZGlhRWxlbWVudC5IQVZFX01FVEFEQVRBKSB7XG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgY29uc3Qgb25Mb2FkZWRNZXRhZGF0YSA9ICgpID0+IHtcbiAgICAgICAgICAgICAgdmlkZW9BZnRlclN3aXRjaC5yZW1vdmVFdmVudExpc3RlbmVyKCdsb2FkZWRtZXRhZGF0YScsIG9uTG9hZGVkTWV0YWRhdGEpO1xuICAgICAgICAgICAgICB2aWRlb0FmdGVyU3dpdGNoLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2Vycm9yJywgb25FcnJvcik7XG4gICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBjb25zdCBvbkVycm9yID0gKCkgPT4ge1xuICAgICAgICAgICAgICB2aWRlb0FmdGVyU3dpdGNoLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2xvYWRlZG1ldGFkYXRhJywgb25Mb2FkZWRNZXRhZGF0YSk7XG4gICAgICAgICAgICAgIHZpZGVvQWZ0ZXJTd2l0Y2gucmVtb3ZlRXZlbnRMaXN0ZW5lcignZXJyb3InLCBvbkVycm9yKTtcbiAgICAgICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcignRmFpbGVkIHRvIGxvYWQgdmlkZW8gbWV0YWRhdGEnKSk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgdmlkZW9BZnRlclN3aXRjaC5hZGRFdmVudExpc3RlbmVyKCdsb2FkZWRtZXRhZGF0YScsIG9uTG9hZGVkTWV0YWRhdGEsIHsgb25jZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgIHZpZGVvQWZ0ZXJTd2l0Y2guYWRkRXZlbnRMaXN0ZW5lcignZXJyb3InLCBvbkVycm9yLCB7IG9uY2U6IHRydWUgfSk7XG4gICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgdmlkZW9BZnRlclN3aXRjaC5yZW1vdmVFdmVudExpc3RlbmVyKCdsb2FkZWRtZXRhZGF0YScsIG9uTG9hZGVkTWV0YWRhdGEpO1xuICAgICAgICAgICAgICB2aWRlb0FmdGVyU3dpdGNoLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2Vycm9yJywgb25FcnJvcik7XG4gICAgICAgICAgICAgIGlmICh2aWRlb0FmdGVyU3dpdGNoLnJlYWR5U3RhdGUgPj0gSFRNTE1lZGlhRWxlbWVudC5IQVZFX01FVEFEQVRBKSB7XG4gICAgICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IoJ1RpbWVvdXQgd2FpdGluZyBmb3IgbWV0YWRhdGEnKSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sIDUwMCk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIC8vIFNldCBzdGF0ZSB0byBsb2FkaW5nXG4gICAgICAgIHRoaXMucGxheWVyU3RhdGUgPSAnbG9hZGluZyc7XG4gICAgICAgIFxuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IHZpZGVvQWZ0ZXJTd2l0Y2gucGxheSgpO1xuICAgICAgICAgIHRoaXMucGxheWVyU3RhdGUgPSAncGxheWluZyc7XG4gICAgICAgICAgdGhpcy5pc1BsYXlpbmcgPSB0cnVlO1xuICAgICAgICAgIHRoaXMucGxheVByb21pc2UgPSBudWxsO1xuICAgICAgICAgIHRoaXMudmlkZW9QbGF5LmVtaXQoKTtcbiAgICAgICAgICB0aGlzLmlzVmlkZW9QbGF5aW5nQ2hhbmdlLmVtaXQodHJ1ZSk7XG4gICAgICAgICAgdGhpcy50YXJnZXRHbG9iYWxUaW1lRHVyaW5nU3dpdGNoID0gbnVsbDtcbiAgICAgICAgICBcbiAgICAgICAgICBjb25zb2xlLmxvZygnW1NpbXVsYXRvcl0gcGxheVZpZGVvSW50ZXJuYWw6IHJlc3RhcnRlZCBmcm9tIGZpcnN0IHZpZGVvJyk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgIHRoaXMucGxheWVyU3RhdGUgPSAnZXJyb3InO1xuICAgICAgICAgIHRoaXMuaXNQbGF5aW5nID0gZmFsc2U7XG4gICAgICAgICAgdGhpcy5wbGF5UHJvbWlzZSA9IG51bGw7XG4gICAgICAgICAgdGhpcy5pc1ZpZGVvUGxheWluZ0NoYW5nZS5lbWl0KGZhbHNlKTtcbiAgICAgICAgICBpZiAoZXJyLm5hbWUgPT09ICdBYm9ydEVycm9yJykge1xuICAgICAgICAgICAgdGhpcy5wbGF5ZXJTdGF0ZSA9ICdwYXVzZWQnO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdbU2ltdWxhdG9yXSBwbGF5VmlkZW9JbnRlcm5hbDogZmFpbGVkIGFmdGVyIHJlc2V0JywgZXJyKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc29sZS5sb2coJ1tTaW11bGF0b3JdIHBsYXlWaWRlb0ludGVybmFsOiBzdGFydGluZycsIHtcbiAgICAgIHBsYXllclN0YXRlOiB0aGlzLnBsYXllclN0YXRlLFxuICAgICAgY3VycmVudFRpbWU6IHZpZGVvLmN1cnJlbnRUaW1lLFxuICAgICAgcmVhZHlTdGF0ZTogdmlkZW8ucmVhZHlTdGF0ZVxuICAgIH0pO1xuXG4gICAgLy8gV2FpdCBmb3IgdmlkZW8gdG8gYmUgcmVhZHkgaWYgbmVlZGVkXG4gICAgaWYgKHZpZGVvLnJlYWR5U3RhdGUgPCBIVE1MTWVkaWFFbGVtZW50LkhBVkVfTUVUQURBVEEpIHtcbiAgICAgIGNvbnNvbGUubG9nKCdbU2ltdWxhdG9yXSBwbGF5VmlkZW9JbnRlcm5hbDogd2FpdGluZyBmb3IgbWV0YWRhdGEnKTtcbiAgICAgIGF3YWl0IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgY29uc3Qgb25Mb2FkZWRNZXRhZGF0YSA9ICgpID0+IHtcbiAgICAgICAgICB2aWRlby5yZW1vdmVFdmVudExpc3RlbmVyKCdsb2FkZWRtZXRhZGF0YScsIG9uTG9hZGVkTWV0YWRhdGEpO1xuICAgICAgICAgIHZpZGVvLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2Vycm9yJywgb25FcnJvcik7XG4gICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICB9O1xuICAgICAgICBjb25zdCBvbkVycm9yID0gKCkgPT4ge1xuICAgICAgICAgIHZpZGVvLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2xvYWRlZG1ldGFkYXRhJywgb25Mb2FkZWRNZXRhZGF0YSk7XG4gICAgICAgICAgdmlkZW8ucmVtb3ZlRXZlbnRMaXN0ZW5lcignZXJyb3InLCBvbkVycm9yKTtcbiAgICAgICAgICByZWplY3QobmV3IEVycm9yKCdGYWlsZWQgdG8gbG9hZCB2aWRlbyBtZXRhZGF0YScpKTtcbiAgICAgICAgfTtcbiAgICAgICAgdmlkZW8uYWRkRXZlbnRMaXN0ZW5lcignbG9hZGVkbWV0YWRhdGEnLCBvbkxvYWRlZE1ldGFkYXRhLCB7IG9uY2U6IHRydWUgfSk7XG4gICAgICAgIHZpZGVvLmFkZEV2ZW50TGlzdGVuZXIoJ2Vycm9yJywgb25FcnJvciwgeyBvbmNlOiB0cnVlIH0pO1xuXG4gICAgICAgIC8vIFRpbWVvdXQgZmFsbGJhY2tcbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgdmlkZW8ucmVtb3ZlRXZlbnRMaXN0ZW5lcignbG9hZGVkbWV0YWRhdGEnLCBvbkxvYWRlZE1ldGFkYXRhKTtcbiAgICAgICAgICB2aWRlby5yZW1vdmVFdmVudExpc3RlbmVyKCdlcnJvcicsIG9uRXJyb3IpO1xuICAgICAgICAgIGlmICh2aWRlby5yZWFkeVN0YXRlID49IEhUTUxNZWRpYUVsZW1lbnQuSEFWRV9NRVRBREFUQSkge1xuICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZWplY3QobmV3IEVycm9yKCdUaW1lb3V0IHdhaXRpbmcgZm9yIG1ldGFkYXRhJykpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSwgNTAwKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIENsZWFyIGhpdCBtYXJrZXJzIGlmIHN0YXJ0aW5nIGZyb20gYmVnaW5uaW5nXG4gICAgY29uc3QgY3VycmVudFRpbWVNcyA9IHZpZGVvLmN1cnJlbnRUaW1lICogMTAwMDtcbiAgICBpZiAoY3VycmVudFRpbWVNcyA8IDEwMCkge1xuICAgICAgdGhpcy5oaXRNYXJrZXJzLmNsZWFyKCk7XG4gICAgfVxuXG4gICAgLy8gU2V0IHN0YXRlIHRvIGxvYWRpbmdcbiAgICB0aGlzLnBsYXllclN0YXRlID0gJ2xvYWRpbmcnO1xuXG4gICAgdHJ5IHtcbiAgICAgIC8vIFZlcmlmeSB2aWRlbyBlbGVtZW50IGlzIHN0aWxsIGF2YWlsYWJsZSBiZWZvcmUgcGxheWluZ1xuICAgICAgY29uc3QgY3VycmVudFZpZGVvID0gdGhpcy52cGxheWVyPy5uYXRpdmVFbGVtZW50O1xuICAgICAgaWYgKCFjdXJyZW50VmlkZW8gfHwgY3VycmVudFZpZGVvICE9PSB2aWRlbykge1xuICAgICAgICBjb25zb2xlLndhcm4oJ1tTaW11bGF0b3JdIHBsYXlWaWRlb0ludGVybmFsOiB2aWRlbyBlbGVtZW50IGNoYW5nZWQgb3IgdW5hdmFpbGFibGUnKTtcbiAgICAgICAgdGhpcy5wbGF5ZXJTdGF0ZSA9ICdwYXVzZWQnO1xuICAgICAgICB0aGlzLmlzUGxheWluZyA9IGZhbHNlO1xuICAgICAgICB0aGlzLnBsYXlQcm9taXNlID0gbnVsbDtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICAvLyBBd2FpdCBwbGF5IHByb21pc2UgLSB0aGlzIGlzIGNyaXRpY2FsXG4gICAgICBhd2FpdCB2aWRlby5wbGF5KCk7XG4gICAgICBcbiAgICAgIC8vIFZlcmlmeSB2aWRlbyBlbGVtZW50IGlzIHN0aWxsIGF2YWlsYWJsZSBhZnRlciBwbGF5IHByb21pc2UgcmVzb2x2ZXNcbiAgICAgIGNvbnN0IHZpZGVvQWZ0ZXJQbGF5ID0gdGhpcy52cGxheWVyPy5uYXRpdmVFbGVtZW50O1xuICAgICAgaWYgKCF2aWRlb0FmdGVyUGxheSB8fCB2aWRlb0FmdGVyUGxheSAhPT0gdmlkZW8pIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdbU2ltdWxhdG9yXSBwbGF5VmlkZW9JbnRlcm5hbDogdmlkZW8gZWxlbWVudCBjaGFuZ2VkIGR1cmluZyBwbGF5Jyk7XG4gICAgICAgIHRoaXMucGxheWVyU3RhdGUgPSAncGF1c2VkJztcbiAgICAgICAgdGhpcy5pc1BsYXlpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5wbGF5UHJvbWlzZSA9IG51bGw7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gUGxheSBzdWNjZWVkZWRcbiAgICAgIHRoaXMucGxheWVyU3RhdGUgPSAncGxheWluZyc7XG4gICAgICB0aGlzLmlzUGxheWluZyA9IHRydWU7XG4gICAgICB0aGlzLnBsYXlQcm9taXNlID0gbnVsbDtcbiAgICAgIHRoaXMudmlkZW9QbGF5LmVtaXQoKTtcbiAgICAgIHRoaXMuaXNWaWRlb1BsYXlpbmdDaGFuZ2UuZW1pdCh0cnVlKTtcbiAgICAgIFxuICAgICAgY29uc29sZS5sb2coJ1tTaW11bGF0b3JdIHBsYXlWaWRlb0ludGVybmFsOiBwbGF5aW5nIHN1Y2Nlc3NmdWxseScsIHtcbiAgICAgICAgY3VycmVudFRpbWU6IHZpZGVvLmN1cnJlbnRUaW1lLFxuICAgICAgICBwbGF5ZXJTdGF0ZTogdGhpcy5wbGF5ZXJTdGF0ZVxuICAgICAgfSk7XG4gICAgICAgIFxuICAgICAgLy8gQ2hlY2sgZWFybHkgbWFya2VycyAobm9uLWJsb2NraW5nLCBkb2Vzbid0IG5lZWQgdG8gYmUgcXVldWVkKVxuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLmlzUGxheWluZykge1xuICAgICAgICAgIHRoaXMuY2hlY2tNYXJrZXJIaXQodGhpcy5nbG9iYWxDdXJyZW50VGltZSk7XG4gICAgICAgIH1cbiAgICAgIH0sIDUwKTtcbiAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgLy8gUGxheSBmYWlsZWRcbiAgICAgIC8vIENoZWNrIGlmIHZpZGVvIGVsZW1lbnQgaXMgc3RpbGwgYXZhaWxhYmxlXG4gICAgICBjb25zdCB2aWRlb0FmdGVyRXJyb3IgPSB0aGlzLnZwbGF5ZXI/Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgICBpZiAoIXZpZGVvQWZ0ZXJFcnJvciB8fCB2aWRlb0FmdGVyRXJyb3IgIT09IHZpZGVvKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignW1NpbXVsYXRvcl0gcGxheVZpZGVvSW50ZXJuYWw6IHZpZGVvIGVsZW1lbnQgY2hhbmdlZCBkdXJpbmcgZXJyb3InKTtcbiAgICAgICAgdGhpcy5wbGF5ZXJTdGF0ZSA9ICdwYXVzZWQnO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5wbGF5ZXJTdGF0ZSA9ICdlcnJvcic7XG4gICAgICB9XG4gICAgICBcbiAgICAgIHRoaXMuaXNQbGF5aW5nID0gZmFsc2U7XG4gICAgICB0aGlzLnBsYXlQcm9taXNlID0gbnVsbDtcbiAgICAgIHRoaXMuaXNWaWRlb1BsYXlpbmdDaGFuZ2UuZW1pdChmYWxzZSk7XG4gICAgICBcbiAgICAgIGlmIChlcnIubmFtZSA9PT0gJ0Fib3J0RXJyb3InKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdbU2ltdWxhdG9yXSBwbGF5VmlkZW9JbnRlcm5hbDogYWJvcnRlZCAoZXhwZWN0ZWQgZHVyaW5nIHBhdXNlKScpO1xuICAgICAgICAvLyBBYm9ydEVycm9yIGlzIGV4cGVjdGVkLCByZXNldCB0byBwYXVzZWQgc3RhdGUgaW5zdGVhZCBvZiBlcnJvclxuICAgICAgICBpZiAodmlkZW9BZnRlckVycm9yICYmIHZpZGVvQWZ0ZXJFcnJvciA9PT0gdmlkZW8pIHtcbiAgICAgICAgICB0aGlzLnBsYXllclN0YXRlID0gJ3BhdXNlZCc7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ1tTaW11bGF0b3JdIHBsYXlWaWRlb0ludGVybmFsOiBmYWlsZWQnLCBlcnIpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQYXVzZSB2aWRlbyAtIHB1YmxpYyBtZXRob2QgKGVucXVldWVzIG9wZXJhdGlvbilcbiAgICovXG4gIHByaXZhdGUgcGF1c2VWaWRlbygpOiB2b2lkIHtcbiAgICB0aGlzLmVucXVldWVPcGVyYXRpb24oKCkgPT4gdGhpcy5wYXVzZVZpZGVvSW50ZXJuYWwoKSk7XG4gIH1cblxuICAvKipcbiAgICogUGF1c2UgdmlkZW8gaW50ZXJuYWwgaW1wbGVtZW50YXRpb24gKG5vIGVucXVldWUgLSBjYWxsZWQgZnJvbSBxdWV1ZSlcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcGF1c2VWaWRlb0ludGVybmFsKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHZpZGVvID0gdGhpcy52cGxheWVyPy5uYXRpdmVFbGVtZW50O1xuICAgIGlmICghdmlkZW8pIHJldHVybjtcblxuICAgIC8vIEFscmVhZHkgcGF1c2VkIC0gc2tpcFxuICAgIGlmICh0aGlzLnBsYXllclN0YXRlID09PSAncGF1c2VkJykge1xuICAgICAgY29uc29sZS5sb2coJ1tTaW11bGF0b3JdIHBhdXNlVmlkZW9JbnRlcm5hbDogYWxyZWFkeSBwYXVzZWQsIHNraXBwaW5nJyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc29sZS5sb2coJ1tTaW11bGF0b3JdIHBhdXNlVmlkZW9JbnRlcm5hbDogcGF1c2luZycsIHtcbiAgICAgIHBsYXllclN0YXRlOiB0aGlzLnBsYXllclN0YXRlLFxuICAgICAgY3VycmVudFRpbWU6IHZpZGVvLmN1cnJlbnRUaW1lXG4gICAgfSk7XG5cbiAgICAgIHZpZGVvLnBhdXNlKCk7XG4gICAgXG4gICAgdGhpcy5wbGF5ZXJTdGF0ZSA9ICdwYXVzZWQnO1xuICAgIHRoaXMuaXNQbGF5aW5nID0gZmFsc2U7XG4gICAgICB0aGlzLnBsYXlQcm9taXNlID0gbnVsbDtcbiAgICB0aGlzLnZpZGVvUGF1c2UuZW1pdCgpO1xuICAgIHRoaXMuaXNWaWRlb1BsYXlpbmdDaGFuZ2UuZW1pdChmYWxzZSk7XG4gICAgXG4gICAgY29uc29sZS5sb2coJ1tTaW11bGF0b3JdIHBhdXNlVmlkZW9JbnRlcm5hbDogcGF1c2VkIHN1Y2Nlc3NmdWxseScpO1xuICB9XG5cbiAgLyoqXG4gICAqIEVucXVldWUgbWVkaWEgb3BlcmF0aW9uIHRvIHByZXZlbnQgcmFjZSBjb25kaXRpb25zXG4gICAqIFRoaXMgaXMgdGhlIENSSVRJQ0FMIGZpeCBmb3IgRkZtcGVnRGVtdXhlciBlcnJvcnMgYW5kIHBsYXkgcHJvbWlzZSBpbnRlcnJ1cHRpb25zXG4gICAqIEFsbCBtZWRpYSBvcGVyYXRpb25zIChwbGF5LCBwYXVzZSwgc2Vlaywgc3dpdGNoKSBnbyB0aHJvdWdoIHRoaXMgcXVldWVcbiAgICovXG4gIHByaXZhdGUgZW5xdWV1ZU9wZXJhdGlvbihvcGVyYXRpb246ICgpID0+IFByb21pc2U8dm9pZD4pOiB2b2lkIHtcbiAgICB0aGlzLm9wZXJhdGlvblF1ZXVlID0gdGhpcy5vcGVyYXRpb25RdWV1ZVxuICAgICAgLnRoZW4oKCkgPT4gb3BlcmF0aW9uKCkpXG4gICAgICAuY2F0Y2goZXJyID0+IHtcbiAgICAgICAgY29uc29sZS5lcnJvcignW1NpbXVsYXRvcl0gTWVkaWEgb3BlcmF0aW9uIGZhaWxlZDonLCBlcnIpO1xuICAgICAgICB0aGlzLnBsYXllclN0YXRlID0gJ2Vycm9yJztcbiAgICAgIH0pO1xuICB9XG5cbiAgZ2V0IGhhc011bHRpcGxlVmlkZW9zKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBBcnJheS5pc0FycmF5KHRoaXMudmlkZW9VcmxzKSAmJiB0aGlzLnZpZGVvVXJscy5sZW5ndGggPiAxO1xuICB9XG5cbiAgLyoqIEN1bXVsYXRpdmUgZHVyYXRpb24gYm91bmRhcmllcyBbbXNdLiBzZWdtZW50Qm91bmRhcmllc1tpXSA9IHN1bSBvZiBkdXJhdGlvbnMgWzAuLmldICovXG4gIGdldCBzZWdtZW50Qm91bmRhcmllcygpOiBudW1iZXJbXSB7XG4gICAgY29uc3QgZHVyYXRpb25zID0gdGhpcy52aWRlb0R1cmF0aW9ucztcbiAgICBpZiAoZHVyYXRpb25zLmxlbmd0aCA9PT0gMCkgcmV0dXJuIFtdO1xuICAgIGNvbnN0IGJvdW5kYXJpZXM6IG51bWJlcltdID0gW107XG4gICAgbGV0IHN1bSA9IDA7XG4gICAgZm9yIChjb25zdCBkIG9mIGR1cmF0aW9ucykge1xuICAgICAgc3VtICs9IGQ7XG4gICAgICBib3VuZGFyaWVzLnB1c2goc3VtKTtcbiAgICB9XG4gICAgcmV0dXJuIGJvdW5kYXJpZXM7XG4gIH1cblxuICAvKiogVG90YWwgZHVyYXRpb24gYWNyb3NzIGFsbCBzZWdtZW50cyBpbiBtcyAqL1xuICBnZXQgdG90YWxEdXJhdGlvbigpOiBudW1iZXIge1xuICAgIGNvbnN0IGR1cmF0aW9ucyA9IHRoaXMudmlkZW9EdXJhdGlvbnM7XG4gICAgaWYgKGR1cmF0aW9ucy5sZW5ndGggPT09IDApIHJldHVybiAwO1xuICAgIHJldHVybiBkdXJhdGlvbnMucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCk7XG4gIH1cblxuICAvKiogVmlkZW8gZHVyYXRpb25zIGluIG1zIChkZXRlY3RlZCBvciBmcm9tIHNpbmdsZSB2aWRlbyBlbGVtZW50KSAqL1xuICBwcml2YXRlIGdldCB2aWRlb0R1cmF0aW9ucygpOiBudW1iZXJbXSB7XG4gICAgaWYgKHRoaXMuaGFzTXVsdGlwbGVWaWRlb3MgJiYgdGhpcy5kZXRlY3RlZFZpZGVvRHVyYXRpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgIHJldHVybiB0aGlzLmRldGVjdGVkVmlkZW9EdXJhdGlvbnM7XG4gICAgfVxuICAgIGNvbnN0IHZpZGVvID0gdGhpcy52cGxheWVyPy5uYXRpdmVFbGVtZW50O1xuICAgIGlmICh2aWRlbz8uZHVyYXRpb24gJiYgaXNGaW5pdGUodmlkZW8uZHVyYXRpb24pKSB7XG4gICAgICByZXR1cm4gW3ZpZGVvLmR1cmF0aW9uICogMTAwMF07XG4gICAgfVxuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIGdldCBnbG9iYWxDdXJyZW50VGltZSgpOiBudW1iZXIge1xuICAgIGlmICh0aGlzLnRhcmdldEdsb2JhbFRpbWVEdXJpbmdTd2l0Y2ggIT09IG51bGwgJiYgIXRoaXMuaXNQbGF5aW5nICYmIHRoaXMucGxheWVyU3RhdGUgIT09ICdwbGF5aW5nJykge1xuICAgICAgcmV0dXJuIHRoaXMudGFyZ2V0R2xvYmFsVGltZUR1cmluZ1N3aXRjaDtcbiAgICB9XG4gICAgY29uc3QgdmlkZW8gPSB0aGlzLnZwbGF5ZXI/Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgaWYgKCF2aWRlbz8uZHVyYXRpb24gfHwgIWlzRmluaXRlKHZpZGVvLmR1cmF0aW9uKSkge1xuICAgICAgLy8gRmFsbGJhY2sgdG8gb3ZlcnJpZGUgaWYgdmlkZW8gbm90IHJlYWR5IHlldFxuICAgICAgaWYgKHRoaXMudGFyZ2V0R2xvYmFsVGltZUR1cmluZ1N3aXRjaCAhPT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gdGhpcy50YXJnZXRHbG9iYWxUaW1lRHVyaW5nU3dpdGNoO1xuICAgICAgfVxuICAgICAgcmV0dXJuIDA7XG4gICAgfVxuICAgIGNvbnN0IHNlZ21lbnRTdGFydCA9IHRoaXMuY3VycmVudFZpZGVvSW5kZXggPT09IDAgPyAwIDogKHRoaXMuc2VnbWVudEJvdW5kYXJpZXNbdGhpcy5jdXJyZW50VmlkZW9JbmRleCAtIDFdID8/IDApO1xuICAgIHJldHVybiBzZWdtZW50U3RhcnQgKyB2aWRlby5jdXJyZW50VGltZSAqIDEwMDA7XG4gIH1cblxuICBwcml2YXRlIGdldEFjdHVhbEdsb2JhbFRpbWUoKTogbnVtYmVyIHtcbiAgICBjb25zdCB2aWRlbyA9IHRoaXMudnBsYXllcj8ubmF0aXZlRWxlbWVudDtcbiAgICBpZiAoIXZpZGVvPy5kdXJhdGlvbiB8fCAhaXNGaW5pdGUodmlkZW8uZHVyYXRpb24pKSByZXR1cm4gMDtcbiAgICBjb25zdCBzZWdtZW50U3RhcnQgPSB0aGlzLmN1cnJlbnRWaWRlb0luZGV4ID09PSAwID8gMCA6ICh0aGlzLnNlZ21lbnRCb3VuZGFyaWVzW3RoaXMuY3VycmVudFZpZGVvSW5kZXggLSAxXSA/PyAwKTtcbiAgICByZXR1cm4gc2VnbWVudFN0YXJ0ICsgdmlkZW8uY3VycmVudFRpbWUgKiAxMDAwO1xuICB9XG5cbiAgLyoqIEdsb2JhbCBzdGVwIG1hcmtlcnMgZm9yIHJlbmRlcmluZyBvbiB0aGUgY29tYmluZWQgdGltZWxpbmUgKi9cbiAgZ2V0IGdsb2JhbFN0ZXBNYXJrZXJzKCk6IEFycmF5PHsgZ2xvYmFsVGltZTogbnVtYmVyOyByZXN1bHQ6IFN0ZXBNYXJrZXJbJ3Jlc3VsdCddOyB0ZXN0U3RlcElkPzogbnVtYmVyOyB0aXRsZT86IHN0cmluZzsgbGV2ZWw/OiBudW1iZXIgfT4ge1xuICAgIGNvbnN0IGFsbE1hcmtlcnMgPSB0aGlzLmZsYXR0ZW5NYXJrZXJzKHRoaXMuc3RlcE1hcmtlcnMpO1xuICAgIHJldHVybiBhbGxNYXJrZXJzLm1hcChtID0+ICh7XG4gICAgICBnbG9iYWxUaW1lOiBtLmN1bXVsYXRpdmVEdXJhdGlvbixcbiAgICAgIHJlc3VsdDogbS5yZXN1bHQsXG4gICAgICB0ZXN0U3RlcElkOiBtLnRlc3RTdGVwSWQsXG4gICAgICB0aXRsZTogbS50aXRsZSxcbiAgICAgIGxldmVsOiBtLmxldmVsXG4gICAgfSkpO1xuICB9XG5cbiAgZ2V0IGN1cnJlbnRWaWRlb1VybCgpOiBzdHJpbmcge1xuICAgIGlmIChBcnJheS5pc0FycmF5KHRoaXMudmlkZW9VcmxzKSAmJiB0aGlzLnZpZGVvVXJscy5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBpZHggPSBNYXRoLm1pbihNYXRoLm1heCh0aGlzLmN1cnJlbnRWaWRlb0luZGV4LCAwKSwgdGhpcy52aWRlb1VybHMubGVuZ3RoIC0gMSk7XG4gICAgICByZXR1cm4gdGhpcy52aWRlb1VybHNbaWR4XTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMudmlkZW9Vcmw7XG4gIH1cblxuICAvKipcbiAgICogUmVzZXQgdmlkZW8gc3RhdGUgLSBwdWJsaWMgbWV0aG9kIChlbnF1ZXVlcyBvcGVyYXRpb24pXG4gICAqL1xuICBwcml2YXRlIHJlc2V0VmlkZW9TdGF0ZSgpOiB2b2lkIHtcbiAgICB0aGlzLmVucXVldWVPcGVyYXRpb24oKCkgPT4gdGhpcy5yZXNldFZpZGVvU3RhdGVJbnRlcm5hbCgpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNldCB2aWRlbyBzdGF0ZSBpbnRlcm5hbCBpbXBsZW1lbnRhdGlvbiAobm8gZW5xdWV1ZSAtIGNhbGxlZCBmcm9tIHF1ZXVlKVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyByZXNldFZpZGVvU3RhdGVJbnRlcm5hbCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB2aWRlbyA9IHRoaXMudnBsYXllcj8ubmF0aXZlRWxlbWVudDtcbiAgICBpZiAoIXZpZGVvKSByZXR1cm47XG5cbiAgICBjb25zb2xlLmxvZygnW1NpbXVsYXRvcl0gcmVzZXRWaWRlb1N0YXRlSW50ZXJuYWw6IHJlc2V0dGluZycpO1xuXG4gICAgdmlkZW8ucGF1c2UoKTtcbiAgICB2aWRlby5jdXJyZW50VGltZSA9IDA7XG5cbiAgICB0aGlzLnBsYXllclN0YXRlID0gJ3BhdXNlZCc7XG4gICAgdGhpcy5pc1BsYXlpbmcgPSBmYWxzZTtcbiAgICB0aGlzLnByb2dyZXNzID0gMDtcbiAgICB0aGlzLnBsYXlQcm9taXNlID0gbnVsbDtcbiAgICB0aGlzLmhpdE1hcmtlcnMuY2xlYXIoKTtcbiAgICB0aGlzLmxhc3RTZXREdXJhdGlvbiA9IC0xO1xuICAgIHRoaXMuaXNWaWRlb1BsYXlpbmdDaGFuZ2UuZW1pdChmYWxzZSk7XG5cbiAgICBjb25zb2xlLmxvZygnW1NpbXVsYXRvcl0gcmVzZXRWaWRlb1N0YXRlSW50ZXJuYWw6IGNvbXBsZXRlJyk7XG4gIH1cblxuICBwcmV2VmlkZW8oKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmhhc011bHRpcGxlVmlkZW9zKSByZXR1cm47XG4gICAgaWYgKHRoaXMuY3VycmVudFZpZGVvSW5kZXggPiAwKSB7XG4gICAgICB0aGlzLmN1cnJlbnRWaWRlb0luZGV4IC09IDE7XG4gICAgICB0aGlzLnJlc2V0VmlkZW9TdGF0ZSgpO1xuICAgIH1cbiAgfVxuXG4gIG5leHRWaWRlbygpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaGFzTXVsdGlwbGVWaWRlb3MpIHJldHVybjtcbiAgICBpZiAodGhpcy52aWRlb1VybHMgJiYgdGhpcy5jdXJyZW50VmlkZW9JbmRleCA8IHRoaXMudmlkZW9VcmxzLmxlbmd0aCAtIDEpIHtcbiAgICAgIHRoaXMuY3VycmVudFZpZGVvSW5kZXggKz0gMTtcbiAgICAgIHRoaXMucmVzZXRWaWRlb1N0YXRlKCk7XG4gICAgfVxuICB9XG5cbiAgb25UaW1lbGluZUNsaWNrKGV2ZW50OiBNb3VzZUV2ZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLnRpbWVsaW5lQmFyPy5uYXRpdmVFbGVtZW50KSByZXR1cm47XG5cbiAgICBjb25zdCByZWN0ID0gdGhpcy50aW1lbGluZUJhci5uYXRpdmVFbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIGNvbnN0IGNsaWNrWCA9IGV2ZW50LmNsaWVudFggLSByZWN0LmxlZnQ7XG4gICAgY29uc3QgcGVyY2VudCA9IE1hdGgubWF4KDAsIE1hdGgubWluKDEsIGNsaWNrWCAvIHJlY3Qud2lkdGgpKTtcblxuICAgIGNvbnN0IHRvdGFsID0gdGhpcy50b3RhbER1cmF0aW9uO1xuICAgIGlmICh0b3RhbCA8PSAwKSByZXR1cm47XG5cbiAgICBjb25zdCBnbG9iYWxUaW1lTXMgPSBwZXJjZW50ICogdG90YWw7XG4gICAgY29uc3Qgc2hvdWxkUmVzdW1lUGxheWluZyA9IHRoaXMuaXNQbGF5aW5nO1xuXG4gICAgY29uc29sZS5sb2coJ1tTaW11bGF0b3JdIG9uVGltZWxpbmVDbGljaycsIHtcbiAgICAgIHBlcmNlbnQsXG4gICAgICBnbG9iYWxUaW1lTXMsXG4gICAgICBzaG91bGRSZXN1bWVQbGF5aW5nXG4gICAgfSk7XG4gICAgXG4gICAgdGhpcy5lbnF1ZXVlT3BlcmF0aW9uKGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IHRoaXMuc2Vla1RvR2xvYmFsVGltZShnbG9iYWxUaW1lTXMpO1xuICAgICAgaWYgKHNob3VsZFJlc3VtZVBsYXlpbmcpIHtcbiAgICAgICAgYXdhaXQgbmV3IFByb21pc2UocmVzb2x2ZSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIDEwMCkpO1xuICAgICAgICBhd2FpdCB0aGlzLnBsYXlWaWRlb0ludGVybmFsKCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBzdGFydERyYWcoZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIHRoaXMuZHJhZ2dpbmcgPSB0cnVlO1xuICAgIFxuICAgIC8vIENSSVRJQ0FMOiBDYXB0dXJlIHBsYXlpbmcgc3RhdGUgQkVGT1JFIHBhdXNpbmdcbiAgICAvLyBVc2UgYm90aCBpc1BsYXlpbmcgZmxhZyBhbmQgcGxheWVyU3RhdGUgZm9yIHJlbGlhYmlsaXR5XG4gICAgdGhpcy53YXNQbGF5aW5nQmVmb3JlRHJhZyA9IHRoaXMuaXNQbGF5aW5nIHx8IHRoaXMucGxheWVyU3RhdGUgPT09ICdwbGF5aW5nJztcbiAgICBcbiAgICBjb25zb2xlLmxvZygnW1NpbXVsYXRvcl0gc3RhcnREcmFnJywge1xuICAgICAgY2xpZW50WDogZXZlbnQuY2xpZW50WCxcbiAgICAgIHBsYXllclN0YXRlOiB0aGlzLnBsYXllclN0YXRlLFxuICAgICAgaXNQbGF5aW5nOiB0aGlzLmlzUGxheWluZyxcbiAgICAgIHdhc1BsYXlpbmdCZWZvcmVEcmFnOiB0aGlzLndhc1BsYXlpbmdCZWZvcmVEcmFnXG4gICAgfSk7XG4gICAgXG4gICAgLy8gUGF1c2UgdmlkZW8gZHVyaW5nIGRyYWcgdG8gYXZvaWQgY29uZmxpY3RzXG4gICAgaWYgKHRoaXMuaXNQbGF5aW5nIHx8IHRoaXMucGxheWVyU3RhdGUgPT09ICdwbGF5aW5nJykge1xuICAgICAgdGhpcy5wYXVzZVZpZGVvKCk7XG4gICAgfVxuICAgIFxuICAgIHRoaXMuYWRkRHJhZ0xpc3RlbmVycygpO1xuICB9XG5cbiAgb25EcmFnKGV2ZW50OiBNb3VzZUV2ZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmRyYWdnaW5nIHx8ICF0aGlzLnRpbWVsaW5lQmFyPy5uYXRpdmVFbGVtZW50KSByZXR1cm47XG5cbiAgICBjb25zdCByZWN0ID0gdGhpcy50aW1lbGluZUJhci5uYXRpdmVFbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIGNvbnN0IHggPSBldmVudC5jbGllbnRYIC0gcmVjdC5sZWZ0O1xuICAgIGNvbnN0IHBlcmNlbnQgPSBNYXRoLm1heCgwLCBNYXRoLm1pbih4IC8gcmVjdC53aWR0aCwgMSkpO1xuICAgIHRoaXMucHJvZ3Jlc3MgPSBwZXJjZW50ICogMTAwOyAvLyBHbG9iYWwgdGltZWxpbmUgcG9zaXRpb25cbiAgfVxuXG4gIHN0b3BEcmFnKCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5kcmFnZ2luZykgcmV0dXJuO1xuXG4gICAgdGhpcy5kcmFnZ2luZyA9IGZhbHNlO1xuICAgIHRoaXMucmVtb3ZlRHJhZ0xpc3RlbmVycygpO1xuICAgIFxuICAgIC8vIENSSVRJQ0FMOiBDYXB0dXJlIHRoZSBwbGF5aW5nIHN0YXRlIEJFRk9SRSBhbnkgYXN5bmMgb3BlcmF0aW9uc1xuICAgIGNvbnN0IHNob3VsZFJlc3VtZVBsYXlpbmcgPSB0aGlzLndhc1BsYXlpbmdCZWZvcmVEcmFnO1xuICAgIFxuICAgIGNvbnNvbGUubG9nKCdbU2ltdWxhdG9yXSBzdG9wRHJhZzogZHJhZyBlbmRlZCcsIHtcbiAgICAgIHByb2dyZXNzOiB0aGlzLnByb2dyZXNzLFxuICAgICAgd2FzUGxheWluZ0JlZm9yZURyYWc6IHRoaXMud2FzUGxheWluZ0JlZm9yZURyYWcsXG4gICAgICBzaG91bGRSZXN1bWVQbGF5aW5nOiBzaG91bGRSZXN1bWVQbGF5aW5nLFxuICAgICAgY3VycmVudFBsYXllclN0YXRlOiB0aGlzLnBsYXllclN0YXRlXG4gICAgfSk7XG5cbiAgICBjb25zdCB0b3RhbCA9IHRoaXMudG90YWxEdXJhdGlvbjtcbiAgICBpZiAodG90YWwgPD0gMCkgcmV0dXJuO1xuXG4gICAgY29uc3QgZ2xvYmFsVGltZU1zID0gKHRoaXMucHJvZ3Jlc3MgLyAxMDApICogdG90YWw7XG5cbiAgICAvLyBDUklUSUNBTCBGSVg6IFF1ZXVlIGJvdGggc2VlayBhbmQgcmVzdW1lIHBsYXkgdG9nZXRoZXJcbiAgICAvLyBUaGlzIGVuc3VyZXMgc2VlayBjb21wbGV0ZXMgYmVmb3JlIGF0dGVtcHRpbmcgdG8gcGxheVxuICAgIHRoaXMuZW5xdWV1ZU9wZXJhdGlvbihhc3luYyAoKSA9PiB7XG4gICAgICAvLyBQZXJmb3JtIHNlZWsgKHRoaXMgd2lsbCBwYXVzZSB0aGUgdmlkZW8pXG4gICAgICBhd2FpdCB0aGlzLnNlZWtUb0dsb2JhbFRpbWUoZ2xvYmFsVGltZU1zKTtcbiAgICAgIFxuICAgICAgLy8gSWYgdmlkZW8gd2FzIHBsYXlpbmcgYmVmb3JlIGRyYWcsIHJlc3VtZSBpdFxuICAgICAgaWYgKHNob3VsZFJlc3VtZVBsYXlpbmcpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ1tTaW11bGF0b3JdIHN0b3BEcmFnOiByZXN1bWluZyBwbGF5YmFjayBhZnRlciBzZWVrJywge1xuICAgICAgICAgIGdsb2JhbFRpbWVNcyxcbiAgICAgICAgICBwbGF5ZXJTdGF0ZTogdGhpcy5wbGF5ZXJTdGF0ZVxuICAgICAgICB9KTtcbiAgICAgICAgXG4gICAgICAgIC8vIFdhaXQgYSBiaXQgbG9uZ2VyIHRvIGVuc3VyZSBzZWVrIGlzIGZ1bGx5IGNvbXBsZXRlXG4gICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKHJlc29sdmUgPT4gc2V0VGltZW91dChyZXNvbHZlLCAxNTApKTtcbiAgICAgICAgXG4gICAgICAgIC8vIFZlcmlmeSBzdGF0ZSBpcyAncGF1c2VkJyBhZnRlciBzZWVrIChzZWVrVG9UaW1lSW50ZXJuYWwgc2V0cyBpdCB0byAncGF1c2VkJylcbiAgICAgICAgLy8gSWYgc3RhdGUgaXMgc3RpbGwgJ3NlZWtpbmcnLCB3YWl0IGEgYml0IG1vcmVcbiAgICAgICAgaWYgKHRoaXMucGxheWVyU3RhdGUgPT09ICdzZWVraW5nJykge1xuICAgICAgICAgIGNvbnNvbGUubG9nKCdbU2ltdWxhdG9yXSBzdG9wRHJhZzogc2VlayBzdGlsbCBpbiBwcm9ncmVzcywgd2FpdGluZyBtb3JlJyk7XG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UocmVzb2x2ZSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIDEwMCkpO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICAvLyBOb3cgcmVzdW1lIHBsYXliYWNrIChzdGF0ZSBzaG91bGQgYmUgJ3BhdXNlZCcgYXQgdGhpcyBwb2ludClcbiAgICAgICAgaWYgKHRoaXMucGxheWVyU3RhdGUgPT09ICdwYXVzZWQnKSB7XG4gICAgICAgICAgYXdhaXQgdGhpcy5wbGF5VmlkZW9JbnRlcm5hbCgpO1xuICAgICAgICAgIGNvbnNvbGUubG9nKCdbU2ltdWxhdG9yXSBzdG9wRHJhZzogcGxheWJhY2sgcmVzdW1lZCBzdWNjZXNzZnVsbHknLCB7XG4gICAgICAgICAgICBwbGF5ZXJTdGF0ZTogdGhpcy5wbGF5ZXJTdGF0ZSxcbiAgICAgICAgICAgIGlzUGxheWluZzogdGhpcy5pc1BsYXlpbmdcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zb2xlLndhcm4oJ1tTaW11bGF0b3JdIHN0b3BEcmFnOiB1bmV4cGVjdGVkIHN0YXRlIGFmdGVyIHNlZWssIGF0dGVtcHRpbmcgdG8gcmVzdW1lIGFueXdheScsIHtcbiAgICAgICAgICAgIHBsYXllclN0YXRlOiB0aGlzLnBsYXllclN0YXRlXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgLy8gVHJ5IHRvIHJlc3VtZSBhbnl3YXkgLSBiZXR0ZXIgdG8gdHJ5IHRoYW4gdG8gbGVhdmUgaXQgc3R1Y2tcbiAgICAgICAgICBhd2FpdCB0aGlzLnBsYXlWaWRlb0ludGVybmFsKCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdbU2ltdWxhdG9yXSBzdG9wRHJhZzogdmlkZW8gd2FzIHBhdXNlZCwgbm90IHJlc3VtaW5nJyk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGFkZERyYWdMaXN0ZW5lcnMoKTogdm9pZCB7XG4gICAgdGhpcy5yZW1vdmVEcmFnTGlzdGVuZXJzKCk7XG5cbiAgICB0aGlzLmRyYWdNb3VzZU1vdmVIYW5kbGVyID0gKGU6IE1vdXNlRXZlbnQpID0+IHtcbiAgICAgIHRoaXMub25EcmFnKGUpO1xuICAgIH07XG5cbiAgICB0aGlzLmRyYWdNb3VzZVVwSGFuZGxlciA9ICgpID0+IHtcbiAgICAgIHRoaXMuc3RvcERyYWcoKTtcbiAgICB9O1xuXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgdGhpcy5kcmFnTW91c2VNb3ZlSGFuZGxlcik7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsIHRoaXMuZHJhZ01vdXNlVXBIYW5kbGVyKTtcbiAgfVxuXG4gIHByaXZhdGUgcmVtb3ZlRHJhZ0xpc3RlbmVycygpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5kcmFnTW91c2VNb3ZlSGFuZGxlcikge1xuICAgICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgdGhpcy5kcmFnTW91c2VNb3ZlSGFuZGxlcik7XG4gICAgICB0aGlzLmRyYWdNb3VzZU1vdmVIYW5kbGVyID0gbnVsbDtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5kcmFnTW91c2VVcEhhbmRsZXIpIHtcbiAgICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21vdXNldXAnLCB0aGlzLmRyYWdNb3VzZVVwSGFuZGxlcik7XG4gICAgICB0aGlzLmRyYWdNb3VzZVVwSGFuZGxlciA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgb25WaWRlb01ldGFkYXRhTG9hZGVkKCk6IHZvaWQge1xuICAgIGNvbnNvbGUubG9nKCdbU2ltdWxhdG9yXSBvblZpZGVvTWV0YWRhdGFMb2FkZWQnKTtcbiAgICAvLyBFbnN1cmUgcGxheWJhY2sgc3BlZWQgaXMgY29uc2lzdGVudCBhY3Jvc3MgYWxsIHZpZGVvc1xuICAgIHRoaXMuYXBwbHlDdXJyZW50UGxheWJhY2tSYXRlKCk7XG4gICAgdGhpcy5hdHRhY2hWaWRlb0xpc3RlbmVycygpO1xuICB9XG4gIFxuICBvblZpZGVvQ2FuUGxheSgpOiB2b2lkIHtcbiAgICBjb25zb2xlLmxvZygnW1NpbXVsYXRvcl0gb25WaWRlb0NhblBsYXknKTtcbiAgICAvLyBFbnN1cmUgcGxheWJhY2sgc3BlZWQgaXMgY29uc2lzdGVudCBhY3Jvc3MgYWxsIHZpZGVvc1xuICAgIHRoaXMuYXBwbHlDdXJyZW50UGxheWJhY2tSYXRlKCk7XG4gICAgdGhpcy5hdHRhY2hWaWRlb0xpc3RlbmVycygpO1xuICB9XG5cbiAgb25WaWRlb0VuZGVkKCk6IHZvaWQge1xuICAgIHRoaXMuaXNQbGF5aW5nID0gZmFsc2U7XG4gICAgdGhpcy5wbGF5ZXJTdGF0ZSA9ICdwYXVzZWQnO1xuICAgIHRoaXMudmlkZW9QYXVzZS5lbWl0KCk7XG4gICAgdGhpcy5pc1ZpZGVvUGxheWluZ0NoYW5nZS5lbWl0KGZhbHNlKTtcbiAgICBcbiAgICAvLyBTZWFtbGVzc2x5IGxvYWQgYW5kIHBsYXkgbmV4dCBzZWdtZW50XG4gICAgaWYgKHRoaXMuaGFzTXVsdGlwbGVWaWRlb3MgJiYgdGhpcy52aWRlb1VybHMgJiYgdGhpcy5jdXJyZW50VmlkZW9JbmRleCA8IHRoaXMudmlkZW9VcmxzLmxlbmd0aCAtIDEpIHtcbiAgICAgIGNvbnN0IG5leHRJbmRleCA9IHRoaXMuY3VycmVudFZpZGVvSW5kZXggKyAxO1xuICAgICAgY29uc3Qgc2VnbWVudFN0YXJ0ID0gbmV4dEluZGV4ID09PSAwID8gMCA6ICh0aGlzLnNlZ21lbnRCb3VuZGFyaWVzW25leHRJbmRleCAtIDFdID8/IDApO1xuICAgICAgXG4gICAgICB0aGlzLmVucXVldWVPcGVyYXRpb24oYXN5bmMgKCkgPT4ge1xuICAgICAgICBhd2FpdCB0aGlzLnN3aXRjaFRvVmlkZW9BbmRTZWVrSW50ZXJuYWwoc2VnbWVudFN0YXJ0KTtcbiAgICAgICAgaWYgKHRoaXMudnBsYXllcj8ubmF0aXZlRWxlbWVudCAmJiB0aGlzLmN1cnJlbnRWaWRlb1VybCkge1xuICAgICAgICAgIGF3YWl0IHRoaXMucGxheVZpZGVvSW50ZXJuYWwoKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhdHRhY2hWaWRlb0xpc3RlbmVycygpOiB2b2lkIHtcbiAgICBpZiAodGhpcy52aWRlb0V2ZW50TGlzdGVuZXJDbGVhbnVwKSB7XG4gICAgICB0aGlzLnZpZGVvRXZlbnRMaXN0ZW5lckNsZWFudXAoKTtcbiAgICAgIHRoaXMudmlkZW9FdmVudExpc3RlbmVyQ2xlYW51cCA9IG51bGw7XG4gICAgfVxuXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICBjb25zdCB2aWRlbyA9IHRoaXMudnBsYXllcj8ubmF0aXZlRWxlbWVudDtcbiAgICAgIGlmICghdmlkZW8pIHJldHVybjtcblxuICAgICAgbGV0IGxhc3RVcGRhdGUgPSAwO1xuICAgICAgY29uc3QgaGFuZGxlciA9ICgpID0+IHtcbiAgICAgICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgaWYgKG5vdyAtIGxhc3RVcGRhdGUgPCAxMDApIHJldHVybjtcblxuICAgICAgICBsYXN0VXBkYXRlID0gbm93O1xuICAgICAgICBjb25zdCBjdXJyZW50TXMgPSB2aWRlby5jdXJyZW50VGltZSAqIDEwMDA7XG5cbiAgICAgICAgaWYgKCF0aGlzLmRyYWdnaW5nICYmIHRoaXMucGxheWVyU3RhdGUgIT09ICdzd2l0Y2hpbmcnKSB7XG4gICAgICAgICAgY29uc3QgdG90YWwgPSB0aGlzLnRvdGFsRHVyYXRpb247XG4gICAgICAgICAgXG4gICAgICAgICAgLy8gQ2xlYXIgdGFyZ2V0R2xvYmFsVGltZUR1cmluZ1N3aXRjaCBpZiB3ZSd2ZSByZWFjaGVkIHRoZSB0YXJnZXQgcG9zaXRpb25cbiAgICAgICAgICAvLyBXaGVuIHBsYXlpbmcsIGJlIG1vcmUgYWdncmVzc2l2ZSBhYm91dCBjbGVhcmluZyB0byBhbGxvdyBsaXZlIHVwZGF0ZXNcbiAgICAgICAgICBpZiAodGhpcy50YXJnZXRHbG9iYWxUaW1lRHVyaW5nU3dpdGNoICE9PSBudWxsKSB7XG4gICAgICAgICAgICBjb25zdCBjdXJyZW50R2xvYmFsID0gdGhpcy5nZXRBY3R1YWxHbG9iYWxUaW1lKCk7XG4gICAgICAgICAgICBjb25zdCB0b2xlcmFuY2UgPSB0aGlzLmlzUGxheWluZyA/IDEwMDAgOiA1MDA7IC8vIE1vcmUgdG9sZXJhbmNlIHdoZW4gcGxheWluZ1xuICAgICAgICAgICAgaWYgKE1hdGguYWJzKGN1cnJlbnRHbG9iYWwgLSB0aGlzLnRhcmdldEdsb2JhbFRpbWVEdXJpbmdTd2l0Y2gpIDwgdG9sZXJhbmNlKSB7XG4gICAgICAgICAgICAgIHRoaXMudGFyZ2V0R2xvYmFsVGltZUR1cmluZ1N3aXRjaCA9IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIFxuICAgICAgICAgIC8vIGdsb2JhbEN1cnJlbnRUaW1lIG5vdyBoYW5kbGVzIG92ZXJyaWRlIGxvZ2ljIC0gdXNlIGl0IGRpcmVjdGx5XG4gICAgICAgICAgaWYgKHRvdGFsID4gMCkge1xuICAgICAgICAgICAgdGhpcy5wcm9ncmVzcyA9IE1hdGgubWluKDEwMCwgTWF0aC5tYXgoMCwgKHRoaXMuZ2xvYmFsQ3VycmVudFRpbWUgLyB0b3RhbCkgKiAxMDApKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhpcy52aWRlb1RpbWVVcGRhdGUuZW1pdCh0aGlzLmdsb2JhbEN1cnJlbnRUaW1lKTtcbiAgICAgICAgICBcbiAgICAgICAgICAvLyBDaGVjayBpZiBjdXJyZW50IHRpbWUgaGl0cyBhbnkgbWFya2VyXG4gICAgICAgICAgdGhpcy5jaGVja01hcmtlckhpdCh0aGlzLmdsb2JhbEN1cnJlbnRUaW1lKTtcblxuICAgICAgICAgIC8vIFByZWxvYWQgbmV4dCBzZWdtZW50IHdoZW4gfjUtMTAgc2Vjb25kcyBmcm9tIGVuZGluZ1xuICAgICAgICAgIHRoaXMubWF5YmVQcmVsb2FkTmV4dFNlZ21lbnQoKTtcbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgdmlkZW8uYWRkRXZlbnRMaXN0ZW5lcigndGltZXVwZGF0ZScsIGhhbmRsZXIpO1xuXG4gICAgICB0aGlzLnZpZGVvRXZlbnRMaXN0ZW5lckNsZWFudXAgPSAoKSA9PiB7XG4gICAgICAgIHZpZGVvLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RpbWV1cGRhdGUnLCBoYW5kbGVyKTtcbiAgICAgIH07XG4gICAgfSwgMTAwKTtcbiAgfVxuXG4gIHByaXZhdGUgc2NoZWR1bGVQcmVsb2FkQWxsU2VnbWVudHModmlkZW9VcmxzOiBzdHJpbmdbXSk6IHZvaWQge1xuICAgIGlmICghdmlkZW9VcmxzIHx8IHZpZGVvVXJscy5sZW5ndGggPT09IDApIHJldHVybjtcbiAgICB0aGlzLmNhbmNlbFByZWxvYWRBbGxTZWdtZW50cygpO1xuICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy5wcmVsb2FkQWxsU2VnbWVudHModmlkZW9VcmxzKSwgNTAwKTtcbiAgfVxuXG4gIHByaXZhdGUgY2FuY2VsUHJlbG9hZEFsbFNlZ21lbnRzKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnByZWxvYWRBbGxWaWRlb0VsZW1lbnQpIHtcbiAgICAgIHRoaXMucHJlbG9hZEFsbFZpZGVvRWxlbWVudC5zcmMgPSAnJztcbiAgICAgIHRoaXMucHJlbG9hZEFsbFZpZGVvRWxlbWVudC5yZW1vdmUoKTtcbiAgICAgIHRoaXMucHJlbG9hZEFsbFZpZGVvRWxlbWVudCA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFByZWxvYWQgYWxsIHZpZGVvIFVSTHMgaW4gc2VxdWVuY2UgKGZpcnN0LCB0aGVuIHNlY29uZCwgLi4uKSBzbyB0aGV5IGFyZSBjYWNoZWQuXG4gICAqIFdoZW4gdXNlciBqdW1wcyB0byBhbnkgc2VnbWVudCwgdGhhdCB2aWRlbyBpcyBsaWtlbHkgYWxyZWFkeSBsb2FkZWQuXG4gICAqL1xuICBwcml2YXRlIHByZWxvYWRBbGxTZWdtZW50cyh2aWRlb1VybHM6IHN0cmluZ1tdKTogdm9pZCB7XG4gICAgaWYgKCF2aWRlb1VybHMgfHwgdmlkZW9VcmxzLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuICAgIHRoaXMuY2FuY2VsUHJlbG9hZEFsbFNlZ21lbnRzKCk7XG4gICAgY29uc3QgdmlkZW8gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCd2aWRlbycpO1xuICAgIHZpZGVvLnByZWxvYWQgPSAnYXV0byc7XG4gICAgdmlkZW8ubXV0ZWQgPSB0cnVlO1xuICAgIHZpZGVvLnBsYXlzSW5saW5lID0gdHJ1ZTtcbiAgICB2aWRlby5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQodmlkZW8pO1xuICAgIHRoaXMucHJlbG9hZEFsbFZpZGVvRWxlbWVudCA9IHZpZGVvO1xuXG4gICAgbGV0IGluZGV4ID0gMDtcbiAgICBjb25zdCBsb2FkTmV4dCA9ICgpOiB2b2lkID0+IHtcbiAgICAgIGlmICh0aGlzLnByZWxvYWRBbGxWaWRlb0VsZW1lbnQgIT09IHZpZGVvIHx8IGluZGV4ID49IHZpZGVvVXJscy5sZW5ndGgpIHtcbiAgICAgICAgdmlkZW8ucmVtb3ZlKCk7XG4gICAgICAgIGlmICh0aGlzLnByZWxvYWRBbGxWaWRlb0VsZW1lbnQgPT09IHZpZGVvKSB0aGlzLnByZWxvYWRBbGxWaWRlb0VsZW1lbnQgPSBudWxsO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBjb25zdCB1cmwgPSB2aWRlb1VybHNbaW5kZXhdO1xuICAgICAgdmlkZW8uc3JjID0gdXJsO1xuICAgICAgaW5kZXggKz0gMTtcbiAgICAgIGNvbnN0IG9uRG9uZSA9ICgpOiB2b2lkID0+IHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXRJZCk7XG4gICAgICAgIHZpZGVvLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2xvYWRlZGRhdGEnLCBvbkRvbmUpO1xuICAgICAgICB2aWRlby5yZW1vdmVFdmVudExpc3RlbmVyKCdlcnJvcicsIG9uRG9uZSk7XG4gICAgICAgIGxvYWROZXh0KCk7XG4gICAgICB9O1xuICAgICAgdmlkZW8uYWRkRXZlbnRMaXN0ZW5lcignbG9hZGVkZGF0YScsIG9uRG9uZSwgeyBvbmNlOiB0cnVlIH0pO1xuICAgICAgdmlkZW8uYWRkRXZlbnRMaXN0ZW5lcignZXJyb3InLCBvbkRvbmUsIHsgb25jZTogdHJ1ZSB9KTtcbiAgICAgIGNvbnN0IHRpbWVvdXRJZCA9IHNldFRpbWVvdXQoKCkgPT4gb25Eb25lKCksIDE1MDAwKTtcbiAgICB9O1xuICAgIGxvYWROZXh0KCk7XG4gIH1cblxuICAvKiogUHJlbG9hZCBuZXh0IHNlZ21lbnQgd2hlbiB+NS0xMCBzZWNvbmRzIGZyb20gZW5kaW5nIHRvIG1pbmltaXplIHN3aXRjaGluZyBkZWxheSAqL1xuICBwcml2YXRlIG1heWJlUHJlbG9hZE5leHRTZWdtZW50KCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5oYXNNdWx0aXBsZVZpZGVvcyB8fCAhdGhpcy52aWRlb1VybHMgfHwgdGhpcy5jdXJyZW50VmlkZW9JbmRleCA+PSB0aGlzLnZpZGVvVXJscy5sZW5ndGggLSAxKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHZpZGVvID0gdGhpcy52cGxheWVyPy5uYXRpdmVFbGVtZW50O1xuICAgIGlmICghdmlkZW8/LmR1cmF0aW9uKSByZXR1cm47XG4gICAgY29uc3QgdGltZUxlZnRJblNlZ21lbnQgPSAodmlkZW8uZHVyYXRpb24gLSB2aWRlby5jdXJyZW50VGltZSkgKiAxMDAwOyAvLyBtc1xuICAgIGlmICh0aW1lTGVmdEluU2VnbWVudCA+IDEwMDAwIHx8IHRpbWVMZWZ0SW5TZWdtZW50IDwgNTAwMCkgcmV0dXJuOyAvLyBQcmVsb2FkIHdoZW4gNS0xMHMgZnJvbSBlbmRcbiAgICBjb25zdCBuZXh0VXJsID0gdGhpcy52aWRlb1VybHNbdGhpcy5jdXJyZW50VmlkZW9JbmRleCArIDFdO1xuICAgIGlmICghbmV4dFVybCkgcmV0dXJuO1xuICAgIGlmICh0aGlzLnByZWxvYWRWaWRlb0VsZW1lbnQ/LnNyYyA9PT0gbmV4dFVybCkgcmV0dXJuOyAvLyBBbHJlYWR5IHByZWxvYWRpbmdcbiAgICB0aGlzLnByZWxvYWROZXh0U2VnbWVudChuZXh0VXJsKTtcbiAgfVxuXG4gIHByaXZhdGUgcHJlbG9hZE5leHRTZWdtZW50KHVybDogc3RyaW5nKTogdm9pZCB7XG4gICAgaWYgKHRoaXMucHJlbG9hZFZpZGVvRWxlbWVudCkge1xuICAgICAgdGhpcy5wcmVsb2FkVmlkZW9FbGVtZW50LnNyYyA9ICcnO1xuICAgICAgdGhpcy5wcmVsb2FkVmlkZW9FbGVtZW50LnJlbW92ZSgpO1xuICAgICAgdGhpcy5wcmVsb2FkVmlkZW9FbGVtZW50ID0gbnVsbDtcbiAgICB9XG4gICAgY29uc3QgdmlkZW8gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCd2aWRlbycpO1xuICAgIHZpZGVvLnByZWxvYWQgPSAnYXV0byc7XG4gICAgdmlkZW8uc3JjID0gdXJsO1xuICAgIHZpZGVvLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZCh2aWRlbyk7XG4gICAgdGhpcy5wcmVsb2FkVmlkZW9FbGVtZW50ID0gdmlkZW87XG4gICAgdmlkZW8uYWRkRXZlbnRMaXN0ZW5lcignbG9hZGVkZGF0YScsICgpID0+IHtcbiAgICAgIHZpZGVvLnJlbW92ZSgpO1xuICAgICAgaWYgKHRoaXMucHJlbG9hZFZpZGVvRWxlbWVudCA9PT0gdmlkZW8pIHRoaXMucHJlbG9hZFZpZGVvRWxlbWVudCA9IG51bGw7XG4gICAgfSwgeyBvbmNlOiB0cnVlIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIERldGVjdCBhY3R1YWwgdmlkZW8gZHVyYXRpb25zIGJ5IGxvYWRpbmcgdmlkZW8gbWV0YWRhdGFcbiAgICogVGhpcyBjcmVhdGVzIHRlbXBvcmFyeSB2aWRlbyBlbGVtZW50cyB0byByZWFkIGR1cmF0aW9uIHdpdGhvdXQgcGxheWluZ1xuICAgKi9cbiAgcHJpdmF0ZSBkZXRlY3RWaWRlb0R1cmF0aW9ucyh2aWRlb1VybHM6IHN0cmluZ1tdKTogdm9pZCB7XG4gICAgaWYgKCF2aWRlb1VybHMgfHwgdmlkZW9VcmxzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhpcy5kZXRlY3RlZFZpZGVvRHVyYXRpb25zID0gW107XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gUmVzZXQgZGV0ZWN0ZWQgZHVyYXRpb25zXG4gICAgdGhpcy5kZXRlY3RlZFZpZGVvRHVyYXRpb25zID0gW107XG4gICAgbGV0IGxvYWRlZENvdW50ID0gMDtcblxuICAgIHZpZGVvVXJscy5mb3JFYWNoKCh1cmwsIGluZGV4KSA9PiB7XG4gICAgICBjb25zdCB0ZW1wVmlkZW8gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCd2aWRlbycpO1xuICAgICAgdGVtcFZpZGVvLnByZWxvYWQgPSAnbWV0YWRhdGEnO1xuICAgICAgXG4gICAgICBjb25zdCBvbkxvYWRlZE1ldGFkYXRhID0gKCkgPT4ge1xuICAgICAgICBjb25zdCBkdXJhdGlvbk1zID0gdGVtcFZpZGVvLmR1cmF0aW9uICogMTAwMDtcbiAgICAgICAgdGhpcy5kZXRlY3RlZFZpZGVvRHVyYXRpb25zW2luZGV4XSA9IGR1cmF0aW9uTXM7XG4gICAgICAgIGxvYWRlZENvdW50Kys7XG4gICAgICAgIFxuICAgICAgICAvLyBDbGVhbiB1cFxuICAgICAgICB0ZW1wVmlkZW8ucmVtb3ZlRXZlbnRMaXN0ZW5lcignbG9hZGVkbWV0YWRhdGEnLCBvbkxvYWRlZE1ldGFkYXRhKTtcbiAgICAgICAgdGVtcFZpZGVvLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2Vycm9yJywgb25FcnJvcik7XG4gICAgICAgIHRlbXBWaWRlby5zcmMgPSAnJztcbiAgICAgICAgdGVtcFZpZGVvLnJlbW92ZSgpO1xuICAgICAgICBcbiAgICAgICAgaWYgKGxvYWRlZENvdW50ID09PSB2aWRlb1VybHMubGVuZ3RoKSB7XG4gICAgICAgICAgY29uc29sZS5sb2coJ1tTaW11bGF0b3JdIEFsbCB2aWRlbyBkdXJhdGlvbnMgZGV0ZWN0ZWQ6JywgdGhpcy5kZXRlY3RlZFZpZGVvRHVyYXRpb25zKTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICAgIFxuICAgICAgY29uc3Qgb25FcnJvciA9ICgpID0+IHtcbiAgICAgICAgY29uc29sZS53YXJuKGBbU2ltdWxhdG9yXSBGYWlsZWQgdG8gbG9hZCBtZXRhZGF0YSBmb3IgdmlkZW8gJHtpbmRleCArIDF9YCk7XG4gICAgICAgIHRoaXMuZGV0ZWN0ZWRWaWRlb0R1cmF0aW9uc1tpbmRleF0gPSAwO1xuICAgICAgICBsb2FkZWRDb3VudCsrO1xuICAgICAgICB0ZW1wVmlkZW8ucmVtb3ZlRXZlbnRMaXN0ZW5lcignbG9hZGVkbWV0YWRhdGEnLCBvbkxvYWRlZE1ldGFkYXRhKTtcbiAgICAgICAgdGVtcFZpZGVvLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2Vycm9yJywgb25FcnJvcik7XG4gICAgICAgIHRlbXBWaWRlby5zcmMgPSAnJztcbiAgICAgICAgdGVtcFZpZGVvLnJlbW92ZSgpO1xuICAgICAgfTtcbiAgICAgIFxuICAgICAgdGVtcFZpZGVvLmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWRlZG1ldGFkYXRhJywgb25Mb2FkZWRNZXRhZGF0YSk7XG4gICAgICB0ZW1wVmlkZW8uYWRkRXZlbnRMaXN0ZW5lcignZXJyb3InLCBvbkVycm9yKTtcbiAgICAgIHRlbXBWaWRlby5zcmMgPSB1cmw7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGN1bXVsYXRpdmUgZHVyYXRpb24gYm91bmRhcmllcyBmb3IgZWFjaCB2aWRlb1xuICAgKiBSZXR1cm5zIGFuIGFycmF5IHdoZXJlIGVhY2ggZWxlbWVudCBpcyBbc3RhcnREdXJhdGlvbiwgZW5kRHVyYXRpb25dIGZvciB0aGF0IHZpZGVvXG4gICAqIFVzZXMgZGV0ZWN0ZWQgdmlkZW8gZHVyYXRpb25zIGlmIGF2YWlsYWJsZSwgb3RoZXJ3aXNlIGZhbGxzIGJhY2sgdG8gdmlkZW9EdXJhdGlvbnMgaW5wdXRcbiAgICovXG4gIHByaXZhdGUgZ2V0VmlkZW9EdXJhdGlvbkJvdW5kYXJpZXMoKTogQXJyYXk8eyBzdGFydDogbnVtYmVyOyBlbmQ6IG51bWJlciB9PiB7XG4gICAgaWYgKCF0aGlzLmhhc011bHRpcGxlVmlkZW9zKSB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuICAgIFxuICAgIC8vIFVzZSBkZXRlY3RlZCBkdXJhdGlvbnMgaWYgYXZhaWxhYmxlLCBvdGhlcndpc2UgdXNlIHByb3ZpZGVkIGR1cmF0aW9uc1xuICAgIGNvbnN0IGR1cmF0aW9ucyA9IHRoaXMuZGV0ZWN0ZWRWaWRlb0R1cmF0aW9ucy5sZW5ndGggPiAwIFxuICAgICAgPyB0aGlzLmRldGVjdGVkVmlkZW9EdXJhdGlvbnMgXG4gICAgICA6IFtdO1xuICAgIFxuICAgIGlmIChkdXJhdGlvbnMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuICAgIFxuICAgIGNvbnN0IGJvdW5kYXJpZXM6IEFycmF5PHsgc3RhcnQ6IG51bWJlcjsgZW5kOiBudW1iZXIgfT4gPSBbXTtcbiAgICBsZXQgY3VtdWxhdGl2ZVN0YXJ0ID0gMDtcbiAgICBcbiAgICBmb3IgKGNvbnN0IGR1cmF0aW9uIG9mIGR1cmF0aW9ucykge1xuICAgICAgYm91bmRhcmllcy5wdXNoKHtcbiAgICAgICAgc3RhcnQ6IGN1bXVsYXRpdmVTdGFydCxcbiAgICAgICAgZW5kOiBjdW11bGF0aXZlU3RhcnQgKyBkdXJhdGlvblxuICAgICAgfSk7XG4gICAgICBjdW11bGF0aXZlU3RhcnQgKz0gZHVyYXRpb247XG4gICAgfVxuICAgIFxuICAgIHJldHVybiBib3VuZGFyaWVzO1xuICB9XG5cbiAgLyoqXG4gICAqIEZsYXR0ZW4gYWxsIG1hcmtlcnMgcmVjdXJzaXZlbHkgaW5jbHVkaW5nIGNoaWxkU3RlcHNcbiAgICovXG4gIHByaXZhdGUgZmxhdHRlbk1hcmtlcnMobWFya2VyczogU3RlcE1hcmtlcltdKTogU3RlcE1hcmtlcltdIHtcbiAgICBjb25zdCBmbGF0dGVuZWQ6IFN0ZXBNYXJrZXJbXSA9IFtdO1xuICAgIFxuICAgIGNvbnN0IGZsYXR0ZW5SZWN1cnNpdmUgPSAobWFya2VyczogU3RlcE1hcmtlcltdKSA9PiB7XG4gICAgICBtYXJrZXJzLmZvckVhY2gobWFya2VyID0+IHtcbiAgICAgICAgLy8gQWRkIHRoZSBtYXJrZXIgaXRzZWxmXG4gICAgICAgIGZsYXR0ZW5lZC5wdXNoKG1hcmtlcik7XG4gICAgICAgIFxuICAgICAgICAvLyBSZWN1cnNpdmVseSBhZGQgY2hpbGQgbWFya2Vyc1xuICAgICAgICBpZiAobWFya2VyLmNoaWxkU3RlcHMgJiYgbWFya2VyLmNoaWxkU3RlcHMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGZsYXR0ZW5SZWN1cnNpdmUobWFya2VyLmNoaWxkU3RlcHMpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9O1xuICAgIFxuICAgIGZsYXR0ZW5SZWN1cnNpdmUobWFya2Vycyk7XG4gICAgcmV0dXJuIGZsYXR0ZW5lZDtcbiAgfVxuXG4gIHByaXZhdGUgY2hlY2tNYXJrZXJIaXQoZ2xvYmFsVGltZU1zOiBudW1iZXIpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaXNQbGF5aW5nIHx8IHRoaXMuZHJhZ2dpbmcpIHJldHVybjtcbiAgICBcbiAgICAvLyBDaGVjayBhbGwgbWFya2VycyAoaW5jbHVkaW5nIG5lc3RlZCBvbmVzKSBmb3IgYSBtYXRjaFxuICAgIGNvbnN0IGFsbE1hcmtlcnMgPSB0aGlzLmZsYXR0ZW5NYXJrZXJzKHRoaXMuc3RlcE1hcmtlcnMpO1xuICAgIGNvbnN0IHRvbGVyYW5jZSA9IDIwMDsgLy8gMjAwbXMgdG9sZXJhbmNlIGZvciBtYXRjaGluZ1xuICAgIFxuICAgIGZvciAoY29uc3QgbWFya2VyIG9mIGFsbE1hcmtlcnMpIHtcbiAgICAgIC8vIFNraXAgaWYgbWFya2VyIGRvZXNuJ3QgaGF2ZSB0ZXN0U3RlcElkXG4gICAgICBpZiAoIW1hcmtlci50ZXN0U3RlcElkKSBjb250aW51ZTtcbiAgICAgIFxuICAgICAgLy8gU2tpcCBpZiBhbHJlYWR5IGhpdFxuICAgICAgaWYgKHRoaXMuaGl0TWFya2Vycy5oYXMobWFya2VyLnRlc3RTdGVwSWQpKSBjb250aW51ZTtcbiAgICAgIFxuICAgICAgLy8gQ2hlY2sgaWYgY3VycmVudCB0aW1lIG1hdGNoZXMgbWFya2VyIHRpbWUgKHdpdGhpbiB0b2xlcmFuY2UpXG4gICAgICBjb25zdCB0aW1lRGlmZmVyZW5jZSA9IE1hdGguYWJzKGdsb2JhbFRpbWVNcyAtIG1hcmtlci5jdW11bGF0aXZlRHVyYXRpb24pO1xuICAgICAgaWYgKHRpbWVEaWZmZXJlbmNlIDw9IHRvbGVyYW5jZSkge1xuICAgICAgICAvLyBNYXJrIGFzIGhpdCBhbmQgZW1pdCBldmVudFxuICAgICAgICB0aGlzLmhpdE1hcmtlcnMuYWRkKG1hcmtlci50ZXN0U3RlcElkKTtcbiAgICAgICAgdGhpcy5tYXJrZXJIaXQuZW1pdChtYXJrZXIpO1xuICAgICAgICBjb25zb2xlLmxvZygnW1NpbXVsYXRvcl0gTWFya2VyIGhpdCBkZXRlY3RlZCcsIHtcbiAgICAgICAgICB0ZXN0U3RlcElkOiBtYXJrZXIudGVzdFN0ZXBJZCxcbiAgICAgICAgICBjdW11bGF0aXZlRHVyYXRpb246IG1hcmtlci5jdW11bGF0aXZlRHVyYXRpb24sXG4gICAgICAgICAgY3VycmVudFRpbWU6IGdsb2JhbFRpbWVNcyxcbiAgICAgICAgICB0aW1lRGlmZmVyZW5jZSxcbiAgICAgICAgICB0aXRsZTogbWFya2VyLnRpdGxlLFxuICAgICAgICAgIGxldmVsOiBtYXJrZXIubGV2ZWxcbiAgICAgICAgfSk7XG4gICAgICAgIGJyZWFrOyAvLyBPbmx5IGVtaXQgb25lIG1hcmtlciBwZXIgY2hlY2tcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBnZXRHbG9iYWxNYXJrZXJSZXN1bHRDb2xvcihyZXN1bHQ6IFN0ZXBNYXJrZXJbJ3Jlc3VsdCddKTogc3RyaW5nIHtcbiAgICBzd2l0Y2ggKHJlc3VsdCkge1xuICAgICAgY2FzZSAnU1VDQ0VTUyc6XG4gICAgICAgIHJldHVybiAnIzEyQjc2QSc7XG4gICAgICBjYXNlICdGQUlMVVJFJzpcbiAgICAgICAgcmV0dXJuICcjQjkxQzFDJztcbiAgICAgIGNhc2UgJ0FCT1JURUQnOlxuICAgICAgICByZXR1cm4gJyNGNzkwMDknO1xuICAgICAgY2FzZSAnU0tJUFBFRCc6XG4gICAgICAgIHJldHVybiAnIzY2NzA4NSc7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4gJyM2MzY2RjEnO1xuICAgIH1cbiAgfVxuXG4gIGdldEdsb2JhbE1hcmtlckNvbG9yKGxldmVsPzogbnVtYmVyKTogc3RyaW5nIHtcbiAgICByZXR1cm4gbGV2ZWwgPT09IDEgPyAnIzAwMDAwMCcgOiAnI0ZGQTUwMCc7XG4gIH1cblxuICBvbk1hcmtlckNsaWNrKGV2ZW50OiBNb3VzZUV2ZW50LCBtYXJrZXI6IHsgZ2xvYmFsVGltZTogbnVtYmVyOyByZXN1bHQ6IFN0ZXBNYXJrZXJbJ3Jlc3VsdCddOyB0ZXN0U3RlcElkPzogbnVtYmVyIH0pOiB2b2lkIHtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIHRoaXMuZW5xdWV1ZU9wZXJhdGlvbihhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCB0aGlzLnNlZWtUb0dsb2JhbFRpbWUobWFya2VyLmdsb2JhbFRpbWUpO1xuICAgICAgaWYgKG1hcmtlci50ZXN0U3RlcElkICE9IG51bGwpIHtcbiAgICAgICAgdGhpcy5oaXRNYXJrZXJzLmFkZChtYXJrZXIudGVzdFN0ZXBJZCk7XG4gICAgICAgIGNvbnN0IGZ1bGxNYXJrZXIgPSB0aGlzLmZsYXR0ZW5NYXJrZXJzKHRoaXMuc3RlcE1hcmtlcnMpLmZpbmQobSA9PiBtLnRlc3RTdGVwSWQgPT09IG1hcmtlci50ZXN0U3RlcElkKTtcbiAgICAgICAgaWYgKGZ1bGxNYXJrZXIpIHRoaXMubWFya2VySGl0LmVtaXQoZnVsbE1hcmtlcik7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICB0b2dnbGVGdWxsU2NyZWVuKCk6IHZvaWQge1xuICAgIGNvbnN0IHdhc1BsYXlpbmcgPSB0aGlzLmlzUGxheWluZztcbiAgICBjb25zdCBjdXJyZW50VGltZSA9IHRoaXMudnBsYXllcj8ubmF0aXZlRWxlbWVudD8uY3VycmVudFRpbWUgfHwgMDtcbiAgICBcbiAgICAvLyBQYXVzZSB2aWRlbyBiZWZvcmUgZnVsbHNjcmVlbiB0cmFuc2l0aW9uIHRvIGF2b2lkIHN0YXRlIGlzc3Vlc1xuICAgIGlmICh3YXNQbGF5aW5nKSB7XG4gICAgICB0aGlzLnBhdXNlVmlkZW8oKTtcbiAgICB9XG4gICAgXG4gICAgLy8gVG9nZ2xlIGZ1bGxzY3JlZW5cbiAgICB0aGlzLmlzRnVsbFNjcmVlbiA9ICF0aGlzLmlzRnVsbFNjcmVlbjtcbiAgICBcbiAgICAvLyBSZXNldCBwbGF5ZXIgc3RhdGUgdG8gYWxsb3cgcmUtaW5pdGlhbGl6YXRpb24gYWZ0ZXIgRE9NIHVwZGF0ZVxuICAgIC8vIFRoZSBzdGF0ZSBtaWdodCBiZSBzdHVjayBpbiAnbG9hZGluZycgb3IgJ2Vycm9yJyBhZnRlciBmdWxsc2NyZWVuIHRyYW5zaXRpb25cbiAgICBpZiAodGhpcy5wbGF5ZXJTdGF0ZSA9PT0gJ2xvYWRpbmcnIHx8IHRoaXMucGxheWVyU3RhdGUgPT09ICdlcnJvcicpIHtcbiAgICAgIHRoaXMucGxheWVyU3RhdGUgPSAnaWRsZSc7XG4gICAgfVxuICAgIFxuICAgIC8vIFdhaXQgZm9yIEFuZ3VsYXIgdG8gdXBkYXRlIHRoZSBET00sIHRoZW4gcmUtaW5pdGlhbGl6ZSB2aWRlb1xuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgY29uc3QgdmlkZW8gPSB0aGlzLnZwbGF5ZXI/Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgICBpZiAodmlkZW8pIHtcbiAgICAgICAgLy8gUmVzdG9yZSB2aWRlbyBwb3NpdGlvbiBpZiBpdCB3YXMgc2V0XG4gICAgICAgIGlmIChjdXJyZW50VGltZSA+IDAgJiYgdmlkZW8uZHVyYXRpb24gPiBjdXJyZW50VGltZSkge1xuICAgICAgICAgIHZpZGVvLmN1cnJlbnRUaW1lID0gY3VycmVudFRpbWU7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIC8vIFJlLWFwcGx5IHBsYXliYWNrIHJhdGVcbiAgICAgICAgdGhpcy5hcHBseUN1cnJlbnRQbGF5YmFja1JhdGUoKTtcbiAgICAgICAgXG4gICAgICAgIC8vIFJlLWF0dGFjaCBsaXN0ZW5lcnNcbiAgICAgICAgdGhpcy5hdHRhY2hWaWRlb0xpc3RlbmVycygpO1xuICAgICAgICBcbiAgICAgICAgLy8gUmVzZXQgc3RhdGUgdG8gJ3BhdXNlZCcgKHJlYWR5IHRvIHBsYXkpXG4gICAgICAgIHRoaXMucGxheWVyU3RhdGUgPSAncGF1c2VkJztcbiAgICAgICAgdGhpcy5pc1BsYXlpbmcgPSBmYWxzZTtcbiAgICAgICAgXG4gICAgICAgIGNvbnNvbGUubG9nKCdbU2ltdWxhdG9yXSB0b2dnbGVGdWxsU2NyZWVuOiB2aWRlbyByZS1pbml0aWFsaXplZCcsIHtcbiAgICAgICAgICBpc0Z1bGxTY3JlZW46IHRoaXMuaXNGdWxsU2NyZWVuLFxuICAgICAgICAgIGN1cnJlbnRUaW1lOiB2aWRlby5jdXJyZW50VGltZSxcbiAgICAgICAgICBwbGF5ZXJTdGF0ZTogdGhpcy5wbGF5ZXJTdGF0ZVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUud2FybignW1NpbXVsYXRvcl0gdG9nZ2xlRnVsbFNjcmVlbjogdmlkZW8gZWxlbWVudCBub3QgZm91bmQgYWZ0ZXIgdHJhbnNpdGlvbicpO1xuICAgICAgICAvLyBUcnkgYWdhaW4gYWZ0ZXIgYSBiaXQgbW9yZSB0aW1lXG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgIGNvbnN0IHZpZGVvUmV0cnkgPSB0aGlzLnZwbGF5ZXI/Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgICAgICAgaWYgKHZpZGVvUmV0cnkpIHtcbiAgICAgICAgICAgIHRoaXMuYXBwbHlDdXJyZW50UGxheWJhY2tSYXRlKCk7XG4gICAgICAgICAgICB0aGlzLmF0dGFjaFZpZGVvTGlzdGVuZXJzKCk7XG4gICAgICAgICAgICB0aGlzLnBsYXllclN0YXRlID0gJ3BhdXNlZCc7XG4gICAgICAgICAgICB0aGlzLmlzUGxheWluZyA9IGZhbHNlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSwgMTAwKTtcbiAgICAgIH1cbiAgICB9LCAxMDApO1xuICB9XG5cbiAgb25TZWdtZW50Q2hhbmdlKHZhbHVlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmN1cnJlbnRWaWV3ID0gdmFsdWU7XG4gICAgLy8gUGF1c2UgdmlkZW8gd2hlbiBzd2l0Y2hpbmcgYXdheSBmcm9tIHZpZGVvIHZpZXdcbiAgICBpZiAodGhpcy5jdXJyZW50VmlldyAhPT0gJ3ZpZGVvJykge1xuICAgICAgdGhpcy5wYXVzZVZpZGVvKCk7XG4gICAgICB0aGlzLnByb2dyZXNzID0gMDtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gUmVzZXQgZXZlcnl0aGluZyB3aGVuIHN3aXRjaGluZyBiYWNrIHRvIHZpZGVvIHZpZXdcbiAgICAgIHRoaXMuZW5xdWV1ZU9wZXJhdGlvbihhc3luYyAoKSA9PiB7XG4gICAgICAgIGF3YWl0IHRoaXMucmVzZXRWaWRlb1N0YXRlSW50ZXJuYWwoKTtcbiAgICAgICAgXG4gICAgICAgIC8vIElmIG11bHRpcGxlIHZpZGVvcywgcmVzZXQgdG8gZmlyc3QgdmlkZW9cbiAgICAgICAgaWYgKHRoaXMuaGFzTXVsdGlwbGVWaWRlb3MgJiYgdGhpcy52aWRlb1VybHMpIHtcbiAgICAgICAgICB0aGlzLmN1cnJlbnRWaWRlb0luZGV4ID0gMDtcbiAgICAgICAgICB0aGlzLnRhcmdldEdsb2JhbFRpbWVEdXJpbmdTd2l0Y2ggPSAwO1xuICAgICAgICAgIFxuICAgICAgICAgIC8vIFN3aXRjaCB0byBmaXJzdCB2aWRlbyBhbmQgc2VlayB0byAwXG4gICAgICAgICAgYXdhaXQgdGhpcy5zd2l0Y2hUb1ZpZGVvQW5kU2Vla0ludGVybmFsKDApO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBmb3JtYXRUaW1lKHNlY29uZHM6IG51bWJlcik6IHN0cmluZyB7XG4gICAgaWYgKCFzZWNvbmRzIHx8IGlzTmFOKHNlY29uZHMpKSByZXR1cm4gJzAwOjAwJztcbiAgICBcbiAgICBjb25zdCB0b3RhbFNlY29uZHMgPSBNYXRoLmZsb29yKHNlY29uZHMpO1xuICAgIGNvbnN0IGhvdXJzID0gTWF0aC5mbG9vcih0b3RhbFNlY29uZHMgLyAzNjAwKTtcbiAgICBjb25zdCBtaW5zID0gTWF0aC5mbG9vcigodG90YWxTZWNvbmRzICUgMzYwMCkgLyA2MCk7XG4gICAgY29uc3Qgc2VjcyA9IHRvdGFsU2Vjb25kcyAlIDYwO1xuICAgIFxuICAgIC8vIElmIGhvdXJzID4gMCwgc2hvdyBISDpNTTpTUyBmb3JtYXQsIG90aGVyd2lzZSBzaG93IE1NOlNTIGZvcm1hdFxuICAgIGlmIChob3VycyA+IDApIHtcbiAgICAgIHJldHVybiBgJHtob3Vycy50b1N0cmluZygpLnBhZFN0YXJ0KDIsICcwJyl9OiR7bWlucy50b1N0cmluZygpLnBhZFN0YXJ0KDIsICcwJyl9OiR7c2Vjcy50b1N0cmluZygpLnBhZFN0YXJ0KDIsICcwJyl9YDtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGAke21pbnMudG9TdHJpbmcoKS5wYWRTdGFydCgyLCAnMCcpfToke3NlY3MudG9TdHJpbmcoKS5wYWRTdGFydCgyLCAnMCcpfWA7XG4gIH1cblxuICBnZXRTdGF0dXNCYWRnZUNsYXNzKCk6IHN0cmluZyB7XG4gICAgY29uc3QgYmFzZUNsYXNzZXMgPSAnY3FhLWlubGluZS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWdhcC0xLjUgY3FhLXB4LVs5cHhdIGNxYS1weS1bM3B4XSBjcWEtcm91bmRlZC1bNnB4XSBjcWEtaC1bMjFweF0nO1xuICAgIHN3aXRjaCAodGhpcy5saXZlU3RhdHVzKSB7XG4gICAgICBjYXNlICdJbiBQcm9ncmVzcyc6XG4gICAgICBjYXNlICdFeGVjdXRpb24nOlxuICAgICAgICByZXR1cm4gYCR7YmFzZUNsYXNzZXN9IGNxYS1iZy1bI0UwRjJGRV0gY3FhLWJvcmRlciBjcWEtYm9yZGVyLVsjN0REM0ZDXWA7XG4gICAgICBjYXNlICdQYXVzZWQnOlxuICAgICAgICByZXR1cm4gYCR7YmFzZUNsYXNzZXN9IGNxYS1iZy1bI0ZFRjNDN10gY3FhLWJvcmRlciBjcWEtYm9yZGVyLVsjRkNEMzREXWA7XG4gICAgICBjYXNlICdBYm9ydGVkJzpcbiAgICAgICAgcmV0dXJuIGAke2Jhc2VDbGFzc2VzfSBjcWEtYmctWyNGRUUyRTJdIGNxYS1ib3JkZXIgY3FhLWJvcmRlci1bI0ZDQTVBNV1gO1xuICAgICAgY2FzZSAnRmFpbGVkJzpcbiAgICAgICAgcmV0dXJuIGAke2Jhc2VDbGFzc2VzfSBjcWEtYmctWyNGQ0Q5RDldIGNxYS1ib3JkZXIgY3FhLWJvcmRlci1bI0Y5QkZCRl1gO1xuICAgICAgY2FzZSAnUGFzc2VkJzpcbiAgICAgICAgcmV0dXJuIGAke2Jhc2VDbGFzc2VzfSBjcWEtYmctWyNEMUZBRTVdIGNxYS1ib3JkZXIgY3FhLWJvcmRlci1bIzZFRTdCN11gO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIGAke2Jhc2VDbGFzc2VzfSBjcWEtYmctZ3JheS0yMDAgY3FhLWJvcmRlciBjcWEtYm9yZGVyLWdyYXktMzAwYDtcbiAgICB9XG4gIH1cblxuICBnZXRTdGF0dXNUZXh0Q2xhc3MoKTogc3RyaW5nIHtcbiAgICBzd2l0Y2ggKHRoaXMubGl2ZVN0YXR1cykge1xuICAgICAgY2FzZSAnSW4gUHJvZ3Jlc3MnOlxuICAgICAgY2FzZSAnRXhlY3V0aW9uJzpcbiAgICAgICAgcmV0dXJuICdjcWEtdGV4dC1bMTBweF0gY3FhLWZvbnQtbWVkaXVtIGNxYS10ZXh0LVsjMDI4NEM3XSBjcWEtbGVhZGluZy1bMTVweF0nO1xuICAgICAgY2FzZSAnUGF1c2VkJzpcbiAgICAgICAgcmV0dXJuICdjcWEtdGV4dC1bMTBweF0gY3FhLWZvbnQtbWVkaXVtIGNxYS10ZXh0LVsjRDk3NzA2XSBjcWEtbGVhZGluZy1bMTVweF0nO1xuICAgICAgY2FzZSAnQWJvcnRlZCc6XG4gICAgICAgIHJldHVybiAnY3FhLXRleHQtWzEwcHhdIGNxYS1mb250LW1lZGl1bSBjcWEtdGV4dC1bI0RDMjYyNl0gY3FhLWxlYWRpbmctWzE1cHhdJztcbiAgICAgIGNhc2UgJ0ZhaWxlZCc6XG4gICAgICAgIHJldHVybiAnY3FhLXRleHQtWzEwcHhdIGNxYS1mb250LW1lZGl1bSBjcWEtdGV4dC1bI0M2MzUzNV0gY3FhLWxlYWRpbmctWzE1cHhdJztcbiAgICAgIGNhc2UgJ1Bhc3NlZCc6XG4gICAgICAgIHJldHVybiAnY3FhLXRleHQtWzEwcHhdIGNxYS1mb250LW1lZGl1bSBjcWEtdGV4dC1bIzA1OTY2OV0gY3FhLWxlYWRpbmctWzE1cHhdJztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiAnY3FhLXRleHQtWzEwcHhdIGNxYS1mb250LW1lZGl1bSBjcWEtdGV4dC1ncmF5LTYwMCBjcWEtbGVhZGluZy1bMTVweF0nO1xuICAgIH1cbiAgfVxuXG4gIGdldCBwcm9jZXNzZWRUcmFjZVVybCgpOiBzdHJpbmcge1xuICAgIGlmICghdGhpcy50cmFjZVZpZXdVcmwpIHJldHVybiAnJztcbiAgICBcbiAgICBpZiAodGhpcy50cmFjZVZpZXdVcmwuZW5kc1dpdGgoJy56aXAnKSkge1xuICAgICAgY29uc3QgdXJsUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh7XG4gICAgICAgIHRyYWNlOiB0aGlzLnRyYWNlVmlld1VybCxcbiAgICAgICAgaGlkZUhlYWRlcjogJ3RydWUnLFxuICAgICAgICBoaWRlQnJhbmRpbmc6ICd0cnVlJyxcbiAgICAgICAgZW1iZWQ6ICd0cnVlJyxcbiAgICAgICAgbWluaW1hbDogJ3RydWUnLFxuICAgICAgICBub0hlYWRlcjogJ3RydWUnXG4gICAgICB9KTtcbiAgICAgIFxuICAgICAgcmV0dXJuIGBodHRwczovL3RyYWNlLnBsYXl3cmlnaHQuZGV2Lz8ke3VybFBhcmFtcy50b1N0cmluZygpfWA7XG4gICAgfVxuICAgIFxuICAgIHJldHVybiB0aGlzLnRyYWNlVmlld1VybDtcbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlU2FmZVRyYWNlVXJsKCk6IHZvaWQge1xuICAgIGNvbnN0IHVybCA9IHRoaXMucHJvY2Vzc2VkVHJhY2VVcmw7XG4gICAgaWYgKHVybCkge1xuICAgICAgdGhpcy50cmFjZVZpZXdlckxvYWRpbmcgPSB0cnVlO1xuICAgICAgdGhpcy50cmFjZVZpZXdlckVycm9yID0gZmFsc2U7XG4gICAgICB0aGlzLnNhZmVUcmFjZVVybCA9IHRoaXMuc2FuaXRpemVyLmJ5cGFzc1NlY3VyaXR5VHJ1c3RSZXNvdXJjZVVybCh1cmwpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnRyYWNlVmlld2VyTG9hZGluZyA9IGZhbHNlO1xuICAgICAgdGhpcy50cmFjZVZpZXdlckVycm9yID0gZmFsc2U7XG4gICAgICB0aGlzLnNhZmVUcmFjZVVybCA9IHRoaXMuc2FuaXRpemVyLmJ5cGFzc1NlY3VyaXR5VHJ1c3RSZXNvdXJjZVVybCgnJyk7XG4gICAgfVxuICB9XG5cbiAgb25UcmFjZVZpZXdlckxvYWQoKTogdm9pZCB7XG4gICAgdGhpcy50cmFjZVZpZXdlckxvYWRpbmcgPSBmYWxzZTtcbiAgICB0aGlzLnRyYWNlVmlld2VyRXJyb3IgPSBmYWxzZTtcbiAgfVxuXG4gIG9uVHJhY2VWaWV3ZXJFcnJvcigpOiB2b2lkIHtcbiAgICB0aGlzLnRyYWNlVmlld2VyTG9hZGluZyA9IGZhbHNlO1xuICAgIHRoaXMudHJhY2VWaWV3ZXJFcnJvciA9IHRydWU7XG4gIH1cblxuICBvblNwZWVkQ2hhbmdlKHZhbHVlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmN1cnJlbnRTcGVlZCA9IHZhbHVlO1xuICAgIC8vIFdoZW5ldmVyIHNwZWVkIGNoYW5nZXMsIGFwcGx5IGl0IHRvIHRoZSBjdXJyZW50IHZpZGVvXG4gICAgdGhpcy5hcHBseUN1cnJlbnRQbGF5YmFja1JhdGUoKTtcbiAgICB0aGlzLmlzU3BlZWRDb250cm9sT3BlbiA9IGZhbHNlO1xuICB9XG5cbiAgdG9nZ2xlU3BlZWRDb250cm9sKCk6IHZvaWQge1xuICAgIHRoaXMuaXNTcGVlZENvbnRyb2xPcGVuID0gIXRoaXMuaXNTcGVlZENvbnRyb2xPcGVuO1xuICAgIGlmICh0aGlzLmlzU3BlZWRDb250cm9sT3Blbikge1xuICAgICAgdGhpcy5hZGRTcGVlZENvbnRyb2xDbGlja091dHNpZGVMaXN0ZW5lcigpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnJlbW92ZVNwZWVkQ29udHJvbENsaWNrT3V0c2lkZUxpc3RlbmVyKCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhZGRTcGVlZENvbnRyb2xDbGlja091dHNpZGVMaXN0ZW5lcigpOiB2b2lkIHtcbiAgICB0aGlzLnJlbW92ZVNwZWVkQ29udHJvbENsaWNrT3V0c2lkZUxpc3RlbmVyKCk7XG4gICAgXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLnNwZWVkQ29udHJvbENsaWNrT3V0c2lkZUhhbmRsZXIgPSAoZTogTW91c2VFdmVudCkgPT4ge1xuICAgICAgICBjb25zdCB0YXJnZXQgPSBlLnRhcmdldCBhcyBIVE1MRWxlbWVudDtcbiAgICAgICAgaWYgKHRhcmdldCAmJiB0aGlzLnNwZWVkQ29udHJvbENvbnRhaW5lcj8ubmF0aXZlRWxlbWVudCAmJiBcbiAgICAgICAgICAgICF0aGlzLnNwZWVkQ29udHJvbENvbnRhaW5lci5uYXRpdmVFbGVtZW50LmNvbnRhaW5zKHRhcmdldCkpIHtcbiAgICAgICAgICB0aGlzLmlzU3BlZWRDb250cm9sT3BlbiA9IGZhbHNlO1xuICAgICAgICAgIHRoaXMucmVtb3ZlU3BlZWRDb250cm9sQ2xpY2tPdXRzaWRlTGlzdGVuZXIoKTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICAgIFxuICAgICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCB0aGlzLnNwZWVkQ29udHJvbENsaWNrT3V0c2lkZUhhbmRsZXIpO1xuICAgIH0sIDApO1xuICB9XG5cbiAgcHJpdmF0ZSByZW1vdmVTcGVlZENvbnRyb2xDbGlja091dHNpZGVMaXN0ZW5lcigpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5zcGVlZENvbnRyb2xDbGlja091dHNpZGVIYW5kbGVyKSB7XG4gICAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdjbGljaycsIHRoaXMuc3BlZWRDb250cm9sQ2xpY2tPdXRzaWRlSGFuZGxlcik7XG4gICAgICB0aGlzLnNwZWVkQ29udHJvbENsaWNrT3V0c2lkZUhhbmRsZXIgPSBudWxsO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlU2VnbWVudHMoKTogdm9pZCB7XG4gICAgY29uc3QgYmFzZVNlZ21lbnRzOiBTZWdtZW50T3B0aW9uW10gPSBbXG4gICAgICB7IGxhYmVsOiAnU2NyZWVuc2hvdHMnLCB2YWx1ZTogJ3NjcmVlbnNob3RzJywgaWNvbjogJ3Bob3RvJyAgfSxcbiAgICBdO1xuICAgIFxuICAgIC8vIE9ubHkgYWRkIFZpZGVvIHRhYiBpZiBoaWRlVmlkZW9UYWIgaXMgZmFsc2VcbiAgICBpZiAoIXRoaXMuaGlkZVZpZGVvVGFiKSB7XG4gICAgICBiYXNlU2VnbWVudHMucHVzaCh7IGxhYmVsOiAnVmlkZW8nLCB2YWx1ZTogJ3ZpZGVvJywgaWNvbjogJ3ZpZGVvY2FtJyB9KTtcbiAgICB9XG4gICAgXG4gICAgaWYgKHRoaXMudHJhY2VWaWV3VXJsKSB7XG4gICAgICBiYXNlU2VnbWVudHMucHVzaCh7IGxhYmVsOiAnVHJhY2UnLCB2YWx1ZTogJ3RyYWNlJywgaWNvbjogJ2dyYXBoaWNfZXEnIH0pO1xuICAgIH1cbiAgICBcbiAgICB0aGlzLnNlZ21lbnRzID0gYmFzZVNlZ21lbnRzO1xuICAgIFxuICAgIC8vIElmIGN1cnJlbnQgdmlldyBpcyAndmlkZW8nIGFuZCB2aWRlbyB0YWIgaXMgaGlkZGVuLCBzd2l0Y2ggdG8gc2NyZWVuc2hvdHNcbiAgICBpZiAodGhpcy5jdXJyZW50VmlldyA9PT0gJ3ZpZGVvJyAmJiB0aGlzLmhpZGVWaWRlb1RhYikge1xuICAgICAgdGhpcy5jdXJyZW50VmlldyA9ICdzY3JlZW5zaG90cyc7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBvblZpZGVvRWxlbWVudFJlYWR5KCk6IHZvaWQge1xuICAgIGNvbnN0IHZpZGVvID0gdGhpcy5fdnBsYXllcj8ubmF0aXZlRWxlbWVudDtcbiAgICBpZiAoIXZpZGVvKSByZXR1cm47XG5cbiAgICBjb25zb2xlLmxvZygnW1NpbXVsYXRvcl0gb25WaWRlb0VsZW1lbnRSZWFkeTogdmlkZW8gZWxlbWVudCByZWFkeScsIHtcbiAgICAgIHBsYXllclN0YXRlOiB0aGlzLnBsYXllclN0YXRlLFxuICAgICAgaXNGdWxsU2NyZWVuOiB0aGlzLmlzRnVsbFNjcmVlbixcbiAgICAgIHJlYWR5U3RhdGU6IHZpZGVvLnJlYWR5U3RhdGVcbiAgICB9KTtcblxuICAgIC8vIFJlc2V0IGVycm9yL2xvYWRpbmcgc3RhdGVzIHdoZW4gdmlkZW8gZWxlbWVudCBpcyByZWNyZWF0ZWQgKGUuZy4sIGR1cmluZyBmdWxsc2NyZWVuIHRvZ2dsZSlcbiAgICBpZiAodGhpcy5wbGF5ZXJTdGF0ZSA9PT0gJ2Vycm9yJyB8fCB0aGlzLnBsYXllclN0YXRlID09PSAnbG9hZGluZycpIHtcbiAgICAgIGNvbnNvbGUubG9nKCdbU2ltdWxhdG9yXSBvblZpZGVvRWxlbWVudFJlYWR5OiByZXNldHRpbmcgZXJyb3IvbG9hZGluZyBzdGF0ZScpO1xuICAgICAgdGhpcy5wbGF5ZXJTdGF0ZSA9ICdpZGxlJztcbiAgICAgIHRoaXMuaXNQbGF5aW5nID0gZmFsc2U7XG4gICAgICB0aGlzLnBsYXlQcm9taXNlID0gbnVsbDtcbiAgICB9XG5cbiAgICAvLyBBcHBseSBjdXJyZW50IHBsYXliYWNrIHNwZWVkIHdoZW4gdGhlIHZpZGVvIGVsZW1lbnQgaXMgZmlyc3QgcmVhZHlcbiAgICB0aGlzLmFwcGx5Q3VycmVudFBsYXliYWNrUmF0ZSgpO1xuXG4gICAgdGhpcy5hdHRhY2hWaWRlb0xpc3RlbmVycygpO1xuICB9XG5cbiAgcHJpdmF0ZSBhcHBseUN1cnJlbnRQbGF5YmFja1JhdGUoKTogdm9pZCB7XG4gICAgY29uc3QgdmlkZW8gPSB0aGlzLnZwbGF5ZXI/Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgaWYgKCF2aWRlbykgcmV0dXJuO1xuXG4gICAgY29uc3QgbnVtZXJpYyA9IHBhcnNlRmxvYXQodGhpcy5jdXJyZW50U3BlZWQucmVwbGFjZSgneCcsICcnKSk7XG4gICAgY29uc3QgcmF0ZSA9ICFpc05hTihudW1lcmljKSAmJiBudW1lcmljID4gMCA/IG51bWVyaWMgOiAxO1xuICAgIHZpZGVvLnBsYXliYWNrUmF0ZSA9IHJhdGU7XG4gIH1cblxuICBwcml2YXRlIGZpbmRWaWRlb0luZGV4Rm9yVGltZXN0YW1wKGN1bXVsYXRpdmVUaW1lc3RhbXA6IG51bWJlcik6IG51bWJlciB8IG51bGwge1xuICAgIGlmICghdGhpcy5oYXNNdWx0aXBsZVZpZGVvcykge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgY29uc3QgYm91bmRhcmllcyA9IHRoaXMuZ2V0VmlkZW9EdXJhdGlvbkJvdW5kYXJpZXMoKTtcbiAgICBpZiAoYm91bmRhcmllcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8vIEZpbmQgd2hpY2ggdmlkZW8gY29udGFpbnMgdGhpcyB0aW1lc3RhbXBcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGJvdW5kYXJpZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGJvdW5kYXJ5ID0gYm91bmRhcmllc1tpXTtcbiAgICAgIGlmIChjdW11bGF0aXZlVGltZXN0YW1wID49IGJvdW5kYXJ5LnN0YXJ0ICYmIGN1bXVsYXRpdmVUaW1lc3RhbXAgPCBib3VuZGFyeS5lbmQpIHtcbiAgICAgICAgcmV0dXJuIGk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gSWYgdGltZXN0YW1wIGlzIGV4YWN0bHkgYXQgdGhlIGVuZCBvZiB0aGUgbGFzdCB2aWRlbywgcmV0dXJuIHRoZSBsYXN0IHZpZGVvIGluZGV4XG4gICAgaWYgKGJvdW5kYXJpZXMubGVuZ3RoID4gMCkge1xuICAgICAgY29uc3QgbGFzdEJvdW5kYXJ5ID0gYm91bmRhcmllc1tib3VuZGFyaWVzLmxlbmd0aCAtIDFdO1xuICAgICAgaWYgKGN1bXVsYXRpdmVUaW1lc3RhbXAgPT09IGxhc3RCb3VuZGFyeS5lbmQpIHtcbiAgICAgICAgcmV0dXJuIGJvdW5kYXJpZXMubGVuZ3RoIC0gMTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIHByaXZhdGUgc3dpdGNoVG9WaWRlb0FuZFNlZWsoY3VtdWxhdGl2ZVRpbWVzdGFtcDogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5lbnF1ZXVlT3BlcmF0aW9uKCgpID0+IHRoaXMuc3dpdGNoVG9WaWRlb0FuZFNlZWtJbnRlcm5hbChjdW11bGF0aXZlVGltZXN0YW1wKSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHN3aXRjaFRvVmlkZW9BbmRTZWVrSW50ZXJuYWwoY3VtdWxhdGl2ZVRpbWVzdGFtcDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKCF0aGlzLmhhc011bHRpcGxlVmlkZW9zKSB7XG4gICAgICBhd2FpdCB0aGlzLnNlZWtUb1RpbWVJbnRlcm5hbChjdW11bGF0aXZlVGltZXN0YW1wKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCB0YXJnZXRWaWRlb0luZGV4ID0gdGhpcy5maW5kVmlkZW9JbmRleEZvclRpbWVzdGFtcChjdW11bGF0aXZlVGltZXN0YW1wKTtcbiAgICBpZiAodGFyZ2V0VmlkZW9JbmRleCA9PT0gbnVsbCkge1xuICAgICAgY29uc29sZS53YXJuKCdbU2ltdWxhdG9yXSBzd2l0Y2hUb1ZpZGVvQW5kU2VlazogQ291bGQgbm90IGZpbmQgdmlkZW8gZm9yIHRpbWVzdGFtcCcsIGN1bXVsYXRpdmVUaW1lc3RhbXApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGJvdW5kYXJpZXMgPSB0aGlzLmdldFZpZGVvRHVyYXRpb25Cb3VuZGFyaWVzKCk7XG4gICAgY29uc3QgdGFyZ2V0Qm91bmRhcnkgPSBib3VuZGFyaWVzW3RhcmdldFZpZGVvSW5kZXhdO1xuICAgIGNvbnN0IHJlbGF0aXZlVGltZXN0YW1wID0gY3VtdWxhdGl2ZVRpbWVzdGFtcCAtIHRhcmdldEJvdW5kYXJ5LnN0YXJ0O1xuXG4gICAgaWYgKHRoaXMuY3VycmVudFZpZGVvSW5kZXggPT09IHRhcmdldFZpZGVvSW5kZXgpIHtcbiAgICAgIGF3YWl0IHRoaXMuc2Vla1RvVGltZUludGVybmFsKHJlbGF0aXZlVGltZXN0YW1wKTtcbiAgICAgIHRoaXMubGFzdFNldER1cmF0aW9uID0gY3VtdWxhdGl2ZVRpbWVzdGFtcDtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCB2aWRlbyA9IHRoaXMudnBsYXllcj8ubmF0aXZlRWxlbWVudDtcbiAgICBpZiAoIXZpZGVvKSByZXR1cm47XG5cbiAgICBjb25zdCB0b3RhbCA9IHRoaXMudG90YWxEdXJhdGlvbjtcbiAgICB0aGlzLnRhcmdldEdsb2JhbFRpbWVEdXJpbmdTd2l0Y2ggPSBjdW11bGF0aXZlVGltZXN0YW1wO1xuICAgIGlmICh0b3RhbCA+IDApIHtcbiAgICAgIHRoaXMucHJvZ3Jlc3MgPSBNYXRoLm1pbigxMDAsIE1hdGgubWF4KDAsIChjdW11bGF0aXZlVGltZXN0YW1wIC8gdG90YWwpICogMTAwKSk7XG4gICAgfVxuXG4gICAgdGhpcy5wbGF5ZXJTdGF0ZSA9ICdzd2l0Y2hpbmcnO1xuXG4gICAgdHJ5IHtcbiAgICAgIC8vIENSSVRJQ0FMOiBQYXVzZSBiZWZvcmUgc3dpdGNoaW5nIHNvdXJjZVxuICAgICAgdmlkZW8ucGF1c2UoKTtcbiAgICAgIHRoaXMuaXNQbGF5aW5nID0gZmFsc2U7XG4gICAgICB0aGlzLnBsYXlQcm9taXNlID0gbnVsbDtcbiAgICAgIHRoaXMudmlkZW9QYXVzZS5lbWl0KCk7XG4gICAgICB0aGlzLmlzVmlkZW9QbGF5aW5nQ2hhbmdlLmVtaXQoZmFsc2UpO1xuXG4gICAgICAvLyBTd2l0Y2ggdmlkZW8gc291cmNlXG4gICAgICB0aGlzLmN1cnJlbnRWaWRlb0luZGV4ID0gdGFyZ2V0VmlkZW9JbmRleDtcblxuICAgICAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBsZXQgcmVzb2x2ZWQgPSBmYWxzZTtcbiAgICAgICAgY29uc3QgY2xlYW51cCA9ICgpID0+IHtcbiAgICAgICAgICBpZiAocmVzb2x2ZWQpIHJldHVybjtcbiAgICAgICAgICByZXNvbHZlZCA9IHRydWU7XG4gICAgICAgICAgdmlkZW8ucmVtb3ZlRXZlbnRMaXN0ZW5lcignbG9hZGVkbWV0YWRhdGEnLCBvbkxvYWRlZE1ldGFkYXRhKTtcbiAgICAgICAgICB2aWRlby5yZW1vdmVFdmVudExpc3RlbmVyKCdlcnJvcicsIG9uRXJyb3IpO1xuICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0SWQpO1xuICAgICAgICB9O1xuICAgICAgICBcbiAgICAgICAgY29uc3Qgb25Mb2FkZWRNZXRhZGF0YSA9ICgpID0+IHtcbiAgICAgICAgICBjbGVhbnVwKCk7XG4gICAgICAgICAgY29uc29sZS5sb2coJ1tTaW11bGF0b3JdIHN3aXRjaFRvVmlkZW9BbmRTZWVrOiBsb2FkZWRtZXRhZGF0YScsIHtcbiAgICAgICAgICAgIHJlYWR5U3RhdGU6IHZpZGVvLnJlYWR5U3RhdGUsXG4gICAgICAgICAgICBkdXJhdGlvbjogdmlkZW8uZHVyYXRpb24sXG4gICAgICAgICAgICBjdXJyZW50VGltZTogdmlkZW8uY3VycmVudFRpbWVcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IG9uRXJyb3IgPSAoKSA9PiB7XG4gICAgICAgICAgY2xlYW51cCgpO1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ1tTaW11bGF0b3JdIHN3aXRjaFRvVmlkZW9BbmRTZWVrOiB2aWRlbyBlcnJvcicpO1xuICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IoJ0ZhaWxlZCB0byBsb2FkIHZpZGVvJykpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgIGlmIChyZXNvbHZlZCkgcmV0dXJuO1xuICAgICAgICAgIHZpZGVvLmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWRlZG1ldGFkYXRhJywgb25Mb2FkZWRNZXRhZGF0YSwgeyBvbmNlOiB0cnVlIH0pO1xuICAgICAgICAgIHZpZGVvLmFkZEV2ZW50TGlzdGVuZXIoJ2Vycm9yJywgb25FcnJvciwgeyBvbmNlOiB0cnVlIH0pO1xuICAgICAgICB9LCAxMDApO1xuXG4gICAgICAgIGNvbnN0IHRpbWVvdXRJZCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgIGNsZWFudXAoKTtcbiAgICAgICAgICBpZiAodmlkZW8ucmVhZHlTdGF0ZSA+PSBIVE1MTWVkaWFFbGVtZW50LkhBVkVfTUVUQURBVEEpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdbU2ltdWxhdG9yXSBzd2l0Y2hUb1ZpZGVvQW5kU2VlazogbWV0YWRhdGEgdGltZW91dCBidXQgdmlkZW8gcmVhZHknLCB7XG4gICAgICAgICAgICAgIHJlYWR5U3RhdGU6IHZpZGVvLnJlYWR5U3RhdGUsXG4gICAgICAgICAgICAgIGR1cmF0aW9uOiB2aWRlby5kdXJhdGlvblxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ1tTaW11bGF0b3JdIHN3aXRjaFRvVmlkZW9BbmRTZWVrOiBtZXRhZGF0YSB0aW1lb3V0IGFuZCB2aWRlbyBub3QgcmVhZHknKTtcbiAgICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IoJ1RpbWVvdXQgd2FpdGluZyBmb3IgdmlkZW8gdG8gbG9hZCcpKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sIDIwMDApO1xuICAgICAgfSk7XG5cbiAgICAgIC8vIFNlZWsgdG8gdGhlIHRhcmdldCBwb3NpdGlvbiB1c2luZyAnc2Vla2VkJyBldmVudCBmb3IgcmVsaWFiaWxpdHlcbiAgICAgIGNvbnN0IHNlZWtTZWNvbmRzID0gcmVsYXRpdmVUaW1lc3RhbXAgLyAxMDAwO1xuICAgICAgY29uc3QgdGFyZ2V0VGltZSA9IE1hdGgubWF4KDAsIE1hdGgubWluKHNlZWtTZWNvbmRzLCB2aWRlby5kdXJhdGlvbiB8fCBzZWVrU2Vjb25kcykpO1xuICAgICAgXG4gICAgICBjb25zb2xlLmxvZygnW1NpbXVsYXRvcl0gc3dpdGNoVG9WaWRlb0FuZFNlZWs6IHNldHRpbmcgY3VycmVudFRpbWUnLCB7XG4gICAgICAgIHRhcmdldFRpbWUsXG4gICAgICAgIHNlZWtTZWNvbmRzLFxuICAgICAgICByZWxhdGl2ZVRpbWVzdGFtcCxcbiAgICAgICAgdmlkZW9EdXJhdGlvbjogdmlkZW8uZHVyYXRpb25cbiAgICAgIH0pO1xuICAgICAgXG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4ge1xuICAgICAgICBsZXQgcmVzb2x2ZWQgPSBmYWxzZTtcbiAgICAgICAgY29uc3Qgb25TZWVrZWQgPSAoKSA9PiB7XG4gICAgICAgICAgaWYgKHJlc29sdmVkKSByZXR1cm47XG4gICAgICAgICAgcmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgICAgIHZpZGVvLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3NlZWtlZCcsIG9uU2Vla2VkKTtcbiAgICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dElkKTtcbiAgICAgICAgICBjb25zb2xlLmxvZygnW1NpbXVsYXRvcl0gc3dpdGNoVG9WaWRlb0FuZFNlZWs6IHNlZWtlZCBldmVudCBmaXJlZCcsIHtcbiAgICAgICAgICAgIGN1cnJlbnRUaW1lOiB2aWRlby5jdXJyZW50VGltZSxcbiAgICAgICAgICAgIHRhcmdldFRpbWUsXG4gICAgICAgICAgICBkaWZmOiBNYXRoLmFicyh2aWRlby5jdXJyZW50VGltZSAtIHRhcmdldFRpbWUpXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgXG4gICAgICAgICAgLy8gU21hbGwgZGVsYXkgdG8gZW5zdXJlIGJyb3dzZXIgaGFzIHByb2Nlc3NlZCB0aGUgc2Vla1xuICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4gcmVzb2x2ZSgpLCAxMDApO1xuICAgICAgICB9O1xuICAgICAgICBcbiAgICAgICAgdmlkZW8uYWRkRXZlbnRMaXN0ZW5lcignc2Vla2VkJywgb25TZWVrZWQsIHsgb25jZTogdHJ1ZSB9KTtcbiAgICAgICAgdmlkZW8uY3VycmVudFRpbWUgPSB0YXJnZXRUaW1lO1xuICAgICAgICBcbiAgICAgICAgLy8gRmFsbGJhY2sgdGltZW91dFxuICAgICAgICBjb25zdCB0aW1lb3V0SWQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICBpZiAocmVzb2x2ZWQpIHJldHVybjtcbiAgICAgICAgICByZXNvbHZlZCA9IHRydWU7XG4gICAgICAgICAgdmlkZW8ucmVtb3ZlRXZlbnRMaXN0ZW5lcignc2Vla2VkJywgb25TZWVrZWQpO1xuICAgICAgICAgIGNvbnNvbGUubG9nKCdbU2ltdWxhdG9yXSBzd2l0Y2hUb1ZpZGVvQW5kU2Vlazogc2Vla2VkIHRpbWVvdXQsIGN1cnJlbnQgdGltZSBpcycsIHZpZGVvLmN1cnJlbnRUaW1lKTtcbiAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgIH0sIDEwMDApO1xuICAgICAgfSk7XG5cbiAgICAgIHRoaXMubGFzdFNldER1cmF0aW9uID0gY3VtdWxhdGl2ZVRpbWVzdGFtcDtcbiAgICAgIFxuICAgICAgLy8gRG91YmxlLWNoZWNrOiBpZiB2aWRlbyBpcyBub3QgYXQgdGFyZ2V0LCBmb3JjZSBpdCBhZ2FpblxuICAgICAgaWYgKE1hdGguYWJzKHZpZGVvLmN1cnJlbnRUaW1lIC0gdGFyZ2V0VGltZSkgPiAwLjUpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdbU2ltdWxhdG9yXSBzd2l0Y2hUb1ZpZGVvQW5kU2VlazogdmlkZW8gbm90IGF0IHRhcmdldCBhZnRlciBzZWVrZWQsIGZvcmNpbmcgYWdhaW4nLCB7XG4gICAgICAgICAgY3VycmVudFRpbWU6IHZpZGVvLmN1cnJlbnRUaW1lLFxuICAgICAgICAgIHRhcmdldFRpbWVcbiAgICAgICAgfSk7XG4gICAgICAgIHZpZGVvLmN1cnJlbnRUaW1lID0gdGFyZ2V0VGltZTtcbiAgICAgICAgYXdhaXQgbmV3IFByb21pc2UocmVzb2x2ZSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIDIwMCkpO1xuICAgICAgfVxuXG4gICAgICAvLyBWZXJpZnkgc2VlayBjb21wbGV0ZWRcbiAgICAgIGNvbnN0IGFjdHVhbEdsb2JhbCA9IHRoaXMuZ2V0QWN0dWFsR2xvYmFsVGltZSgpO1xuICAgICAgY29uc3QgYWN0dWFsVmlkZW9UaW1lID0gdmlkZW8uY3VycmVudFRpbWU7XG4gICAgICBcbiAgICAgIGNvbnNvbGUubG9nKCdbU2ltdWxhdG9yXSBzd2l0Y2hUb1ZpZGVvQW5kU2Vlazogc2VlayB2ZXJpZmljYXRpb24nLCB7XG4gICAgICAgIGFjdHVhbEdsb2JhbCxcbiAgICAgICAgdGFyZ2V0R2xvYmFsOiBjdW11bGF0aXZlVGltZXN0YW1wLFxuICAgICAgICBkaWZmOiBNYXRoLmFicyhhY3R1YWxHbG9iYWwgLSBjdW11bGF0aXZlVGltZXN0YW1wKSxcbiAgICAgICAgYWN0dWFsVmlkZW9UaW1lLFxuICAgICAgICB0YXJnZXRWaWRlb1RpbWU6IHRhcmdldFRpbWUsXG4gICAgICAgIHZpZGVvRGlmZjogTWF0aC5hYnMoYWN0dWFsVmlkZW9UaW1lIC0gdGFyZ2V0VGltZSlcbiAgICAgIH0pO1xuICAgICAgXG4gICAgICAvLyBDbGVhciBvdmVycmlkZSBvbmx5IGlmIHZpZGVvIGlzIGFjdHVhbGx5IGF0IHRoZSB0YXJnZXRcbiAgICAgIGNvbnN0IHRvbGVyYW5jZSA9IDUwMDtcbiAgICAgIGlmIChNYXRoLmFicyhhY3R1YWxHbG9iYWwgLSBjdW11bGF0aXZlVGltZXN0YW1wKSA8IHRvbGVyYW5jZSkge1xuICAgICAgICB0aGlzLnRhcmdldEdsb2JhbFRpbWVEdXJpbmdTd2l0Y2ggPSBudWxsO1xuICAgICAgICBjb25zb2xlLmxvZygnW1NpbXVsYXRvcl0gc3dpdGNoVG9WaWRlb0FuZFNlZWs6IGNsZWFyZWQgb3ZlcnJpZGUgLSB2aWRlbyBhdCB0YXJnZXQnKTtcbiAgICAgIH1cblxuICAgICAgLy8gVXBkYXRlIFVJIHdpdGggYWN0dWFsIGN1cnJlbnQgcG9zaXRpb25cbiAgICAgIGlmICh0b3RhbCA+IDApIHtcbiAgICAgICAgdGhpcy5wcm9ncmVzcyA9IE1hdGgubWluKDEwMCwgTWF0aC5tYXgoMCwgKHRoaXMuZ2xvYmFsQ3VycmVudFRpbWUgLyB0b3RhbCkgKiAxMDApKTtcbiAgICAgIH1cbiAgICAgIHRoaXMudmlkZW9UaW1lVXBkYXRlLmVtaXQodGhpcy5nbG9iYWxDdXJyZW50VGltZSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdbU2ltdWxhdG9yXSBzd2l0Y2hUb1ZpZGVvQW5kU2VlayBmYWlsZWQ6JywgZXJyKTtcbiAgICAgIC8vIEV2ZW4gb24gZXJyb3IsIHRyeSB0byB1cGRhdGUgdG8gdGFyZ2V0IHBvc2l0aW9uXG4gICAgICBpZiAodG90YWwgPiAwKSB7XG4gICAgICAgIHRoaXMucHJvZ3Jlc3MgPSBNYXRoLm1pbigxMDAsIE1hdGgubWF4KDAsIChjdW11bGF0aXZlVGltZXN0YW1wIC8gdG90YWwpICogMTAwKSk7XG4gICAgICB9XG4gICAgICB0aGlzLnZpZGVvVGltZVVwZGF0ZS5lbWl0KGN1bXVsYXRpdmVUaW1lc3RhbXApO1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLnBsYXllclN0YXRlID0gJ3BhdXNlZCc7XG4gICAgICB0aGlzLmhpdE1hcmtlcnMuY2xlYXIoKTtcbiAgICAgIC8vIERvbid0IGNsZWFyIHRhcmdldEdsb2JhbFRpbWVEdXJpbmdTd2l0Y2ggaGVyZSAtIGl0J3MgZWl0aGVyIGFscmVhZHkgY2xlYXJlZFxuICAgICAgLy8gb3Igd2lsbCBiZSBjbGVhcmVkIGJ5IHRpbWV1cGRhdGUgaGFuZGxlciB3aGVuIHZpZGVvIHJlYWNoZXMgdGFyZ2V0XG4gICAgfVxuXG4gICAgY29uc29sZS5sb2coJ1tTaW11bGF0b3JdIHN3aXRjaFRvVmlkZW9BbmRTZWVrOiBjb21wbGV0ZScsIHtcbiAgICAgIGN1cnJlbnRWaWRlb0luZGV4OiB0aGlzLmN1cnJlbnRWaWRlb0luZGV4LFxuICAgICAgdmlkZW9DdXJyZW50VGltZTogdmlkZW8uY3VycmVudFRpbWUsXG4gICAgICBnbG9iYWxDdXJyZW50VGltZTogdGhpcy5nbG9iYWxDdXJyZW50VGltZSxcbiAgICAgIHRhcmdldEdsb2JhbFRpbWVEdXJpbmdTd2l0Y2g6IHRoaXMudGFyZ2V0R2xvYmFsVGltZUR1cmluZ1N3aXRjaCxcbiAgICAgIHBsYXllclN0YXRlOiB0aGlzLnBsYXllclN0YXRlLFxuICAgICAgcHJvZ3Jlc3M6IHRoaXMucHJvZ3Jlc3NcbiAgICB9KTtcbiAgfVxufVxuXG4iLCI8ZGl2IGNsYXNzPVwiY3FhLXVpLXJvb3RcIiBzdHlsZT1cImJhY2tncm91bmQtY29sb3I6ICNGM0Y0RjY7IGhlaWdodDogMTAwJTsgZGlzcGxheTogZmxleDsgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcIiAgIFtuZ1N0eWxlXT1cIntcbiAgcG9zaXRpb246IGlzRnVsbFNjcmVlbiA/ICdmaXhlZCcgOiBudWxsLFxuICBpbnNldDogaXNGdWxsU2NyZWVuID8gJzFyZW0nIDogbnVsbCxcbiAgekluZGV4OiBpc0Z1bGxTY3JlZW4gPyAnNTAnIDogbnVsbCxcbiAgYm94U2hhZG93OiBpc0Z1bGxTY3JlZW4gPyAnMHB4IDEzcHggMjVweCAtMTJweCByZ2JhKDAsIDAsIDAsIDAuMjUpJyA6IG51bGwsXG4gIGJvcmRlclJhZGl1czogaXNGdWxsU2NyZWVuID8gJy41cmVtJyA6IG51bGwsXG4gIGJvcmRlcjogaXNGdWxsU2NyZWVuID8gJzFweCBzb2xpZCAjRTVFN0VCJyA6IG51bGwsXG4gIHdpZHRoOiBpc0Z1bGxTY3JlZW4gPyAnY2FsYygxMDAlIC0gMzJweCknIDogbnVsbCxcbiAgaGVpZ2h0OiBpc0Z1bGxTY3JlZW4gPyAnY2FsYygxMDAlIC0gMzJweCknIDogJzEwMCUnLFxuICBvdmVyZmxvdzogaXNGdWxsU2NyZWVuID8gJ2hpZGRlbicgOiBudWxsXG59XCI+XG4gIDxkaXYgY2xhc3M9XCJjcWEtdy1mdWxsIGNxYS1weS0xIGNxYS1weC0yIGNxYS1iZy1bI0ZGRkZGRl1cIiBzdHlsZT1cImJvcmRlci1ib3R0b206IDFweCBzb2xpZCAjRTVFN0VCO2JveC1zaGFkb3c6IDBweCAxcHggMnB4IDBweCAjMDAwMDAwMEQ7XCI+XG4gICAgPGRpdiBjbGFzcz1cImNxYS13LWZ1bGwgY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1iZXR3ZWVuIGNxYS1mbGV4LXdyYXBcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyXCI+XG4gICAgICAgIDxkaXYgKm5nSWY9XCJpc0xpdmVcIiBjbGFzcz1cImNxYS1oLVsyMXB4XSBjcWEtaW5saW5lLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtZ2FwLTEuNSBjcWEtbXItMiBjcWEtcHgtWzlweF0gY3FhLXB5LVszcHhdIGNxYS1iZy1bI0ZDRDlEOV0gY3FhLXJvdW5kZWQtWzZweF1cIiBzdHlsZT1cImJvcmRlcjogMXB4IHNvbGlkICNGOUJGQkY7XCI+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtcmVsYXRpdmUgY3FhLXctMiBjcWEtaC0yIGNxYS1yb3VuZGVkLWZ1bGwgY3FhLWJnLVsjRjQ3RjdGXVwiIHN0eWxlPVwiZmxleC1zaHJpbms6IDA7XCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImNxYS1hYnNvbHV0ZSBjcWEtaW5zZXQtMCBjcWEtcm91bmRlZC1mdWxsIGNxYS1iZy1bI0Y0N0Y3Rl0gY3FhLW9wYWNpdHktNzUgY3FhLWFuaW1hdGUtcGluZ1wiPjwvc3Bhbj5cbiAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtdGV4dC1bMTBweF0gY3FhLWZvbnQtbWVkaXVtIGNxYS10ZXh0LVsjQzYzNTM1XSBjcWEtbGVhZGluZy1bMTVweF1cIj5MaXZlPC9zcGFuPlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPG1hdC1pY29uICpuZ0lmPVwicGxhdGZvcm1UeXBlID09PSAnYnJvd3NlcidcIiBzdHlsZT1cIndpZHRoOiAxMHB4OyBoZWlnaHQ6IDEwcHg7XCI+XG4gICAgICAgICAgPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgd2lkdGg9XCIxMFwiIGhlaWdodD1cIjEwXCIgdmlld0JveD1cIjAgMCAxMCAxMFwiIGZpbGw9XCJub25lXCI+XG4gICAgICAgICAgICA8ZyBjbGlwLXBhdGg9XCJ1cmwoI2NsaXAwXzkzNV8xNTg0NylcIj5cbiAgICAgICAgICAgICAgPHBhdGhcbiAgICAgICAgICAgICAgICBkPVwiTTAuNjI1IDVDMC42MjUgNi4xNjAzMiAxLjA4NTk0IDcuMjczMTIgMS45MDY0MSA4LjA5MzU5QzIuNzI2ODggOC45MTQwNiAzLjgzOTY4IDkuMzc1IDUgOS4zNzVDNi4xNjAzMiA5LjM3NSA3LjI3MzEyIDguOTE0MDYgOC4wOTM1OSA4LjA5MzU5QzguOTE0MDYgNy4yNzMxMiA5LjM3NSA2LjE2MDMyIDkuMzc1IDVDOS4zNzUgMy44Mzk2OCA4LjkxNDA2IDIuNzI2ODggOC4wOTM1OSAxLjkwNjQxQzcuMjczMTIgMS4wODU5NCA2LjE2MDMyIDAuNjI1IDUgMC42MjVDMy44Mzk2OCAwLjYyNSAyLjcyNjg4IDEuMDg1OTQgMS45MDY0MSAxLjkwNjQxQzEuMDg1OTQgMi43MjY4OCAwLjYyNSAzLjgzOTY4IDAuNjI1IDVaXCJcbiAgICAgICAgICAgICAgICBzdHJva2U9XCIjOUNBM0FGXCIgc3Ryb2tlLXdpZHRoPVwiMC42XCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIiAvPlxuICAgICAgICAgICAgICA8cGF0aFxuICAgICAgICAgICAgICAgIGQ9XCJNMy4xMjUgNUMzLjEyNSAzLjgzOTY4IDMuMzIyNTQgMi43MjY4OCAzLjY3NDE3IDEuOTA2NDFDNC4wMjU4MSAxLjA4NTk0IDQuNTAyNzIgMC42MjUgNSAwLjYyNUM1LjQ5NzI4IDAuNjI1IDUuOTc0MTkgMS4wODU5NCA2LjMyNTgyIDEuOTA2NDFDNi42Nzc0NiAyLjcyNjg4IDYuODc1IDMuODM5NjggNi44NzUgNUM2Ljg3NSA2LjE2MDMyIDYuNjc3NDYgNy4yNzMxMiA2LjMyNTgyIDguMDkzNTlDNS45NzQxOSA4LjkxNDA2IDUuNDk3MjggOS4zNzUgNSA5LjM3NUM0LjUwMjcyIDkuMzc1IDQuMDI1ODEgOC45MTQwNiAzLjY3NDE3IDguMDkzNTlDMy4zMjI1NCA3LjI3MzEyIDMuMTI1IDYuMTYwMzIgMy4xMjUgNVpcIlxuICAgICAgICAgICAgICAgIHN0cm9rZT1cIiM5Q0EzQUZcIiBzdHJva2Utd2lkdGg9XCIwLjZcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiIC8+XG4gICAgICAgICAgICAgIDxwYXRoIGQ9XCJNMC45Mzc1IDYuNDU4NjZIOS4wNjI1TTAuOTM3NSAzLjU0MTk5SDkuMDYyNVwiIHN0cm9rZT1cIiM5Q0EzQUZcIiBzdHJva2Utd2lkdGg9XCIwLjZcIlxuICAgICAgICAgICAgICAgIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiAvPlxuICAgICAgICAgICAgPC9nPlxuICAgICAgICAgICAgPGRlZnM+XG4gICAgICAgICAgICAgIDxjbGlwUGF0aCBpZD1cImNsaXAwXzkzNV8xNTg0N1wiPlxuICAgICAgICAgICAgICAgIDxyZWN0IHdpZHRoPVwiMTBcIiBoZWlnaHQ9XCIxMFwiIGZpbGw9XCJ3aGl0ZVwiIC8+XG4gICAgICAgICAgICAgIDwvY2xpcFBhdGg+XG4gICAgICAgICAgICA8L2RlZnM+XG4gICAgICAgICAgPC9zdmc+XG4gICAgICAgIDwvbWF0LWljb24+XG4gICAgICAgIDxtYXQtaWNvbiAqbmdJZj1cInBsYXRmb3JtVHlwZSA9PT0gJ2RldmljZSdcIiBzdHlsZT1cIndpZHRoOiAxMHB4OyBoZWlnaHQ6IDEwcHg7XCI+XG4gICAgICAgICAgPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgd2lkdGg9XCIxMFwiIGhlaWdodD1cIjEwXCIgdmlld0JveD1cIjAgMCAxMCAxMFwiIGZpbGw9XCJub25lXCI+XG4gICAgICAgICAgICA8cGF0aCBkPVwiTTcuMDgzMjUgMC44MzMwMDhIMi45MTY1OUMyLjQ1NjM1IDAuODMzMDA4IDIuMDgzMjUgMS4yMDYxIDIuMDgzMjUgMS42NjYzNFY4LjMzMzAxQzIuMDgzMjUgOC43OTMyNCAyLjQ1NjM1IDkuMTY2MzQgMi45MTY1OSA5LjE2NjM0SDcuMDgzMjVDNy41NDM0OSA5LjE2NjM0IDcuOTE2NTggOC43OTMyNCA3LjkxNjU4IDguMzMzMDFWMS42NjYzNEM3LjkxNjU4IDEuMjA2MSA3LjU0MzQ5IDAuODMzMDA4IDcuMDgzMjUgMC44MzMwMDhaXCIgc3Ryb2tlPVwiIzZCNzI4MFwiIHN0cm9rZS13aWR0aD1cIjAuODMzMzMzXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPlxuICAgICAgICAgICAgPHBhdGggZD1cIk01IDcuNUg1LjAwNDE3XCIgc3Ryb2tlPVwiIzZCNzI4MFwiIHN0cm9rZS13aWR0aD1cIjAuODMzMzMzXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPlxuICAgICAgICAgIDwvc3ZnPlxuICAgICAgICA8L21hdC1pY29uPlxuICAgICAgICA8cCBjbGFzcz1cImNxYS10ZXh0LXNtICFjcWEtdGV4dC1bMTBweF0gY3FhLXRleHQtWyM2QjcyODBdIGNxYS1tbC0yXCI+XG4gICAgICAgICAge3sgcGxhdGZvcm1OYW1lIH19XG4gICAgICAgICAgPHNwYW5cbiAgICAgICAgICAgICpuZ0lmPVwicGxhdGZvcm1UeXBlID09PSAnYnJvd3NlcidcIlxuICAgICAgICAgICAgY2xhc3M9XCJjcWEtbWwtMVwiXG4gICAgICAgICAgICBbbWF0VG9vbHRpcF09XCInU2NyZWVuIHNpemU6ICcgKyBlZmZlY3RpdmVCcm93c2VyVmlld1BvcnQud2lkdGggKyAneCcgKyBlZmZlY3RpdmVCcm93c2VyVmlld1BvcnQuaGVpZ2h0XCJcbiAgICAgICAgICAgIG1hdFRvb2x0aXBQb3NpdGlvbj1cImJlbG93XCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICDCt1xuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtbWwtMVwiPlxuICAgICAgICAgICAgICB7eyBlZmZlY3RpdmVCcm93c2VyVmlld1BvcnQud2lkdGggfX14e3sgZWZmZWN0aXZlQnJvd3NlclZpZXdQb3J0LmhlaWdodCB9fVxuICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgPC9wPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtZ2FwLTJcIj5cbiAgICAgICAgPGRpdiAqbmdJZj1cImlzTGl2ZVwiIFtuZ0NsYXNzXT1cImdldFN0YXR1c0JhZGdlQ2xhc3MoKVwiPlxuICAgICAgICAgIDxzcGFuIFtuZ0NsYXNzXT1cImdldFN0YXR1c1RleHRDbGFzcygpXCI+e3sgbGl2ZVN0YXR1cyB9fTwvc3Bhbj5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFpc0xpdmVcIj5cbiAgICAgICAgICA8Y3FhLXNlZ21lbnQtY29udHJvbCBcbiAgICAgICAgICAgIFtzZWdtZW50c109XCJzZWdtZW50c1wiIFxuICAgICAgICAgICAgW3ZhbHVlXT1cImN1cnJlbnRWaWV3XCJcbiAgICAgICAgICAgICh2YWx1ZUNoYW5nZSk9XCJvblNlZ21lbnRDaGFuZ2UoJGV2ZW50KVwiPlxuICAgICAgICAgIDwvY3FhLXNlZ21lbnQtY29udHJvbD5cbiAgICAgICAgICBcbiAgICAgICAgICA8ZGl2ICpuZ0lmPVwiIWlzRnVsbFNjcmVlblwiIFxuICAgICAgICAgICAgICAgY2xhc3M9XCJjcWEtcC0xIGNxYS1jdXJzb3ItcG9pbnRlciBob3ZlcjpjcWEtYmctZ3JheS0xMDAgY3FhLXJvdW5kZWQtc20gY3FhLXRyYW5zaXRpb24tY29sb3JzXCJcbiAgICAgICAgICAgICAgIChjbGljayk9XCJ0b2dnbGVGdWxsU2NyZWVuKClcIlxuICAgICAgICAgICAgICAgdGl0bGU9XCJFeHBhbmRcIj5cbiAgICAgICAgICAgIDxzdmcgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIHdpZHRoPVwiMTBcIiBoZWlnaHQ9XCIxMFwiIHZpZXdCb3g9XCIwIDAgMTAgMTBcIiBmaWxsPVwibm9uZVwiPlxuICAgICAgICAgICAgICA8cGF0aCBkPVwiTTYuMjUgMS4yNUg4Ljc1VjMuNzVcIiBzdHJva2U9XCIjOUNBM0FGXCIgc3Ryb2tlLXdpZHRoPVwiMC44MzMzMzNcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIi8+XG4gICAgICAgICAgICAgIDxwYXRoIGQ9XCJNOC43NDk5MiAxLjI1TDUuODMzMjUgNC4xNjY2N1wiIHN0cm9rZT1cIiM5Q0EzQUZcIiBzdHJva2Utd2lkdGg9XCIwLjgzMzMzM1wiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiLz5cbiAgICAgICAgICAgICAgPHBhdGggZD1cIk0xLjI1IDguNzQ5NjdMNC4xNjY2NyA1LjgzMzAxXCIgc3Ryb2tlPVwiIzlDQTNBRlwiIHN0cm9rZS13aWR0aD1cIjAuODMzMzMzXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPlxuICAgICAgICAgICAgICA8cGF0aCBkPVwiTTMuNzUgOC43NUgxLjI1VjYuMjVcIiBzdHJva2U9XCIjOUNBM0FGXCIgc3Ryb2tlLXdpZHRoPVwiMC44MzMzMzNcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIi8+XG4gICAgICAgICAgICA8L3N2Zz5cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIDxkaXYgKm5nSWY9XCJpc0Z1bGxTY3JlZW5cIiBcbiAgICAgICAgICAgICAgIGNsYXNzPVwiY3FhLXAtMSBjcWEtY3Vyc29yLXBvaW50ZXIgaG92ZXI6Y3FhLWJnLWdyYXktMTAwIGNxYS1yb3VuZGVkLXNtIGNxYS10cmFuc2l0aW9uLWNvbG9yc1wiXG4gICAgICAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlRnVsbFNjcmVlbigpXCJcbiAgICAgICAgICAgICAgIHRpdGxlPVwiRXhpdCBmdWxsIHNjcmVlblwiPlxuICAgICAgICAgICAgPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgd2lkdGg9XCIxMFwiIGhlaWdodD1cIjEwXCIgdmlld0JveD1cIjAgMCAxMCAxMFwiIGZpbGw9XCJub25lXCI+XG4gICAgICAgICAgICAgIDxwYXRoIGQ9XCJNOC43NSA2LjI1SDYuMjVWOC43NVwiIHN0cm9rZT1cIiM5Q0EzQUZcIiBzdHJva2Utd2lkdGg9XCIwLjgzMzMzM1wiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiLz5cbiAgICAgICAgICAgICAgPHBhdGggZD1cIk02LjI1MDA4IDYuMjVMOS4xNjY3NSA5LjE2NjY3XCIgc3Ryb2tlPVwiIzlDQTNBRlwiIHN0cm9rZS13aWR0aD1cIjAuODMzMzMzXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPlxuICAgICAgICAgICAgICA8cGF0aCBkPVwiTTAuODMzMjUyIDAuODMzMDA4TDMuNzQ5OTIgMy43NDk2N1wiIHN0cm9rZT1cIiM5Q0EzQUZcIiBzdHJva2Utd2lkdGg9XCIwLjgzMzMzM1wiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiLz5cbiAgICAgICAgICAgICAgPHBhdGggZD1cIk0xLjI1IDMuNzVIMy43NVYxLjI1XCIgc3Ryb2tlPVwiIzlDQTNBRlwiIHN0cm9rZS13aWR0aD1cIjAuODMzMzMzXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPlxuICAgICAgICAgICAgPC9zdmc+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuICA8ZGl2IGNsYXNzPVwiY3FhLXctZnVsbCBjcWEtYmctWyNGM0Y0RjZdIGNxYS1oLVtjYWxjKDEwMCUtNDFweCldXCI+XG4gIDwhLS0gTGl2ZSBDb250ZW50IFZpZXcgLS0+XG4gICAgPGRpdiAqbmdJZj1cImlzTGl2ZVwiIGNsYXNzPVwiY3FhLWgtZnVsbCBjcWEtZmxleCBjcWEtZmxleC1jb2wgY3FhLWp1c3RpZnktY2VudGVyIGNxYS1yZWxhdGl2ZVwiPlxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImhhc0RldmljZUZyYW1lO1wiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXctZnVsbCBjcWEtaC1mdWxsIGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyIGNxYS1wLTRcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXJlbGF0aXZlIGNxYS1oLWZ1bGwgY3FhLXctYXV0byBjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWNlbnRlclwiIFtuZ0NsYXNzXT1cInsnY3FhLXJvdW5kZWQtbWQgY3FhLW92ZXJmbG93LWhpZGRlbic6IHBsYXRmb3JtVHlwZSA9PT0gJ2Jyb3dzZXInLCAnY3FhLW1heC1oLWZ1bGwgY3FhLWgtZnVsbCc6IHBsYXRmb3JtVHlwZSAhPT0gJ2Jyb3dzZXInIHx8ICFpc0xpdmUsICdjcWEtbWluLXctbWF4JzogcGxhdGZvcm1UeXBlID09PSAnZGV2aWNlJ31cIj5cbiAgICAgICAgICAgIDxpbWdcbiAgICAgICAgICAgICAgW3NyY109XCJkZXZpY2VNb2NrdXBJbWFnZVwiXG4gICAgICAgICAgICAgIGFsdD1cIkRldmljZSBtb2NrdXBcIlxuICAgICAgICAgICAgICBjbGFzcz1cImNxYS1oLWZ1bGwgY3FhLXctYXV0byBjcWEtbWF4LWgtZnVsbCBjcWEtb2JqZWN0LWNvbnRhaW4gY3FhLWJsb2NrIGNxYS1wb2ludGVyLWV2ZW50cy1ub25lIGNxYS16LTEwXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLWFic29sdXRlIGNxYS1mbGV4IGNxYS1mbGV4LWNvbFwiIFtuZ1N0eWxlXT1cImRldmljZVNjcmVlblN0eWxlXCIgW25nQ2xhc3NdPVwieydjcWEtei0yMCc6IHBsYXRmb3JtVHlwZSA9PT0gJ2Jyb3dzZXInLCAnY3FhLWJnLXdoaXRlJzogcGxhdGZvcm1UeXBlICE9PSAnYnJvd3Nlcid9XCI+XG4gICAgICAgICAgICAgIDwhLS0gTG9hZGluZyBTdGF0ZSAtLT5cbiAgICAgICAgICAgICAgPGRpdiAqbmdJZj1cImlzQ29udGVudFZpZGVvTG9hZGluZ1wiIGNsYXNzPVwiY3FhLXAtMTAgY3FhLXRleHQtY2VudGVyIGNxYS1oLWZ1bGwgY3FhLWZsZXggY3FhLWZsZXgtY29sIGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyXCI+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1tYi00XCI+XG4gICAgICAgICAgICAgICAgICA8bWF0LXByb2dyZXNzLXNwaW5uZXIgbW9kZT1cImluZGV0ZXJtaW5hdGVcIiBkaWFtZXRlcj1cIjQwXCI+PC9tYXQtcHJvZ3Jlc3Mtc3Bpbm5lcj5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICA8cCBjbGFzcz1cImNxYS10ZXh0LWdyYXktNDAwIGNxYS10ZXh0LXNtXCI+e3sgbGl2ZUxvYWRpbmdMYWJlbCB9fTwvcD5cbiAgICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgICAgPCEtLSBMaXZlIENvbnRlbnQgKHdoZW4gbm90IGxvYWRpbmcpIC0tPlxuICAgICAgICAgICAgICA8ZGl2ICpuZ0lmPVwiIWlzQ29udGVudFZpZGVvTG9hZGluZ1wiIGNsYXNzPVwiY3FhLXctZnVsbCBjcWEtaC1mdWxsIGNxYS1mbGV4IGNxYS1mbGV4LWNvbCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWNlbnRlciBjcWEtcmVsYXRpdmVcIj5cbiAgICAgICAgICAgICAgICA8ZGl2ICpuZ0lmPVwibGl2ZVN0YXR1cyA9PT0gJ0ZhaWxlZCcgJiYgZmFpbGVkU3RhdHVzTWVzc2FnZVwiIGNsYXNzPVwiY3FhLXAtNiBjcWEtdGV4dC1jZW50ZXIgY3FhLXctZnVsbFwiPlxuICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1pbmxpbmUtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1nYXAtMiBjcWEtcHgtNCBjcWEtcHktMyBjcWEtYmctWyNGQ0Q5RDldIGNxYS1ib3JkZXIgY3FhLWJvcmRlci1bI0Y5QkZCRl0gY3FhLXJvdW5kZWQtbGdcIj5cbiAgICAgICAgICAgICAgICAgICAgPG1hdC1pY29uIHN0eWxlPVwid2lkdGg6IDE4cHg7IGhlaWdodDogMThweDsgY29sb3I6ICNDNjM1MzU7IGZvbnQtc2l6ZTogMThweDtcIj5lcnJvcjwvbWF0LWljb24+XG4gICAgICAgICAgICAgICAgICAgIDxwIGNsYXNzPVwiY3FhLXRleHQtWyNDNjM1MzVdIGNxYS10ZXh0LXNtIGNxYS1mb250LW1lZGl1bSBjcWEtbS0wXCI+e3sgZmFpbGVkU3RhdHVzTWVzc2FnZSB9fTwvcD5cbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDxuZy1jb250ZW50ICpuZ0lmPVwibGl2ZVN0YXR1cyAhPT0gJ0ZhaWxlZCcgfHwgIWZhaWxlZFN0YXR1c01lc3NhZ2VcIj48L25nLWNvbnRlbnQ+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgPC9kaXY+XG5cbiAgICA8IS0tIE5vcm1hbCBWaWRlbyBWaWV3ICh3aGVuIG5vdCBsaXZlKSAtLT5cbiAgICA8ZGl2ICpuZ0lmPVwiIWlzTGl2ZSAmJiBjdXJyZW50VmlldyA9PT0gJ3ZpZGVvJ1wiIGNsYXNzPVwiY3FhLWgtZnVsbCBjcWEtZmxleCBjcWEtZmxleC1jb2xcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJjcWEtdy1mdWxsIGNxYS1weS00IGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLW1heC1oLVtjYWxjKDEwMCUtODNweCldXCIgKm5nSWY9XCJjdXJyZW50VmlkZW9VcmxcIiBbbmdDbGFzc109XCJ7JyFjcWEtaC1mdWxsJzogcGxhdGZvcm1UeXBlID09PSAnZGV2aWNlJywgJ2NxYS1tdC1hdXRvJzogaGFzRGV2aWNlRnJhbWV9XCI+XG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJoYXNEZXZpY2VGcmFtZVwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtdy1mdWxsIGNxYS1oLWZ1bGwgY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1jZW50ZXJcIiBbbmdDbGFzc109XCJ7J2NxYS1wLTQnOiBwbGF0Zm9ybVR5cGUgPT09ICdicm93c2VyJ31cIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtcmVsYXRpdmUgY3FhLWgtZnVsbCBjcWEtdy1hdXRvIGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyIGNxYS1tYXgtaC1mdWxsXCIgW25nQ2xhc3NdPVwieydjcWEtcm91bmRlZC1tZCBjcWEtb3ZlcmZsb3ctaGlkZGVuJzogcGxhdGZvcm1UeXBlID09PSAnYnJvd3NlcicsICdjcWEtbWluLXctbWF4JzogcGxhdGZvcm1UeXBlID09PSAnZGV2aWNlJ31cIj5cbiAgICAgICAgICAgICAgPGltZ1xuICAgICAgICAgICAgICAgIFtzcmNdPVwiZGV2aWNlTW9ja3VwSW1hZ2VcIlxuICAgICAgICAgICAgICAgIGFsdD1cIkRldmljZSBtb2NrdXBcIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwiY3FhLWgtZnVsbCBjcWEtdy1hdXRvIGNxYS1tYXgtaC1mdWxsIGNxYS1vYmplY3QtY29udGFpbiBjcWEtYmxvY2sgY3FhLXBvaW50ZXItZXZlbnRzLW5vbmUgY3FhLXotMTBcIlxuICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLWFic29sdXRlIGNxYS1mbGV4IGNxYS1mbGV4LWNvbFwiIFtuZ1N0eWxlXT1cImRldmljZVNjcmVlblN0eWxlXCIgW25nQ2xhc3NdPVwieydjcWEtYmctd2hpdGUnOiBwbGF0Zm9ybVR5cGUgIT09ICdicm93c2VyJ31cIj5cbiAgICAgICAgICAgICAgICA8dmlkZW9cbiAgICAgICAgICAgICAgICAgICN2cGxheWVyXG4gICAgICAgICAgICAgICAgICBjbGFzcz1cImNxYS1vYmplY3QtY292ZXIgY3FhLXctZnVsbCBjcWEtaC1mdWxsIGNxYS1ibG9jayBjcWEtYmctWyMjRjJGMkYyXVwiXG4gICAgICAgICAgICAgICAgICBbc3JjXT1cImN1cnJlbnRWaWRlb1VybFwiXG4gICAgICAgICAgICAgICAgICB0eXBlPVwidmlkZW8vd2VibVwiXG4gICAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJ7J2NxYS16LTIwJzogcGxhdGZvcm1UeXBlID09PSAnYnJvd3Nlcid9XCJcbiAgICAgICAgICAgICAgICAgIChsb2FkZWRtZXRhZGF0YSk9XCJvblZpZGVvTWV0YWRhdGFMb2FkZWQoKVwiXG4gICAgICAgICAgICAgICAgICAoY2FucGxheSk9XCJvblZpZGVvQ2FuUGxheSgpXCJcbiAgICAgICAgICAgICAgICAgIChlbmRlZCk9XCJvblZpZGVvRW5kZWQoKVwiXG4gICAgICAgICAgICAgICAgPjwvdmlkZW8+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgPC9kaXY+XG4gICAgXG4gICAgICA8ZGl2IGNsYXNzPVwiY3FhLXAtMTAgY3FhLXRleHQtY2VudGVyIGNxYS10ZXh0LWdyYXktNDAwIGNxYS10ZXh0LXNtIGNxYS1oLWZ1bGwgY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1jZW50ZXJcIiAqbmdJZj1cIiFjdXJyZW50VmlkZW9VcmxcIj5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImlzVk5DU2Vzc2lvbkludHJ1cHB0ZWQgJiYgdm5jU2Vzc2lvbkludHVwcHRlZE1lc3NhZ2U7IGVsc2Ugbm9WaWRlb0RlZmF1bHRcIj5cbiAgICAgICAgICA8cCBjbGFzcz1cImNxYS10ZXh0LXNtIGNxYS10ZXh0LWdyYXktNjAwXCI+XG4gICAgICAgICAgICB7eyB2bmNTZXNzaW9uSW50dXBwdGVkTWVzc2FnZSB9fVxuICAgICAgICAgIDwvcD5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgIDxuZy10ZW1wbGF0ZSAjbm9WaWRlb0RlZmF1bHQ+XG4gICAgICAgICAgPHNwYW4+Tm8gdmlkZW8gcmVjb3JkaW5nIGZvdW5kPC9zcGFuPlxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgPC9kaXY+XG4gICAgXG4gICAgICA8ZGl2IGNsYXNzPVwiY3FhLXB4LTIgY3FhLXB5LTIgY3FhLWJnLXdoaXRlXCIgc3R5bGU9XCJib3JkZXItdG9wOiAxcHggc29saWQgI0U1RTdFQjtcIiBbbmdDbGFzc109XCJ7J2NxYS1tdC1hdXRvJzogaGFzRGV2aWNlRnJhbWV9XCIgKm5nSWY9XCJjdXJyZW50VmlkZW9VcmwgJiYgIWlzTGl2ZVwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtZ2FwLTJcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1jZW50ZXJcIiBzdHlsZT1cIndpZHRoOiAxNnB4OyBoZWlnaHQ6IDE2cHg7XCI+XG4gICAgICAgICAgICA8bWF0LXByb2dyZXNzLXNwaW5uZXJcbiAgICAgICAgICAgICAgKm5nSWY9XCJpc1BsYXllclN3aXRjaGluZ1wiXG4gICAgICAgICAgICAgIG1vZGU9XCJpbmRldGVybWluYXRlXCJcbiAgICAgICAgICAgICAgZGlhbWV0ZXI9XCIxNlwiXG4gICAgICAgICAgICAgIGNsYXNzPVwiY3FhLWlubGluZS1ibG9ja1wiPlxuICAgICAgICAgICAgPC9tYXQtcHJvZ3Jlc3Mtc3Bpbm5lcj5cbiAgICAgICAgICAgIDxidXR0b24gXG4gICAgICAgICAgICAgICpuZ0lmPVwiIWlzUGxheWVyU3dpdGNoaW5nXCJcbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgIGNsYXNzPVwiY3FhLWJnLXRyYW5zcGFyZW50IGNxYS1ib3JkZXItbm9uZSBjcWEtY3Vyc29yLXBvaW50ZXIgIWNxYS1weC0wIGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyIGhvdmVyOmNxYS1vcGFjaXR5LTcwIGNxYS10cmFuc2l0aW9uLW9wYWNpdHkgY3FhLW91dGxpbmUtbm9uZVwiXG4gICAgICAgICAgICAgIHN0eWxlPVwicG9pbnRlci1ldmVudHM6IGF1dG87XCJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cInRvZ2dsZVBsYXkoKVwiXG4gICAgICAgICAgICAgIG1hdFRvb2x0aXA9XCJ7eyBpc1BsYXlpbmcgPyAnUGF1c2UnIDogJ1BsYXknIH19XCJcbiAgICAgICAgICAgICAgbWF0VG9vbHRpcFBvc2l0aW9uPVwiYWJvdmVcIj5cbiAgICAgICAgICAgICAgPHNwYW4gKm5nSWY9XCIhaXNQbGF5aW5nXCIgY2xhc3M9XCJjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWNlbnRlclwiPlxuICAgICAgICAgICAgICAgIDxzdmcgd2lkdGg9XCIxNlwiIGhlaWdodD1cIjE2XCIgdmlld0JveD1cIjAgMCAxNiAxNlwiIGZpbGw9XCJub25lXCIgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiPlxuICAgICAgICAgICAgICAgICAgPHBhdGggZD1cIk0zIDJMMTMgOEwzIDE0VjJaXCIgZmlsbD1cIiMzNzQxNTFcIi8+XG4gICAgICAgICAgICAgICAgPC9zdmc+XG4gICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgPHNwYW4gKm5nSWY9XCJpc1BsYXlpbmdcIiBjbGFzcz1cImNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyXCI+XG4gICAgICAgICAgICAgICAgPHN2ZyB3aWR0aD1cIjE2XCIgaGVpZ2h0PVwiMTZcIiB2aWV3Qm94PVwiMCAwIDE2IDE2XCIgZmlsbD1cIm5vbmVcIiB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCI+XG4gICAgICAgICAgICAgICAgICA8cmVjdCB4PVwiM1wiIHk9XCIyXCIgd2lkdGg9XCIzXCIgaGVpZ2h0PVwiMTJcIiBmaWxsPVwiIzM3NDE1MVwiLz5cbiAgICAgICAgICAgICAgICAgIDxyZWN0IHg9XCIxMFwiIHk9XCIyXCIgd2lkdGg9XCIzXCIgaGVpZ2h0PVwiMTJcIiBmaWxsPVwiIzM3NDE1MVwiLz5cbiAgICAgICAgICAgICAgICA8L3N2Zz5cbiAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cImNxYS10ZXh0LVsjOUNBM0FGXSBjcWEtdGV4dC1bOXB4XSBjcWEtZm9udC1ub3JtYWwgY3FhLXdoaXRlc3BhY2Utbm93cmFwIGNxYS1zZWxlY3Qtbm9uZVwiPlxuICAgICAgICAgICAge3sgZm9ybWF0VGltZShnbG9iYWxDdXJyZW50VGltZSAvIDEwMDApIH19XG4gICAgICAgICAgPC9zcGFuPlxuXG4gICAgICAgICAgPGRpdiAjc3BlZWRDb250cm9sQ29udGFpbmVyIGNsYXNzPVwiY3FhLXJlbGF0aXZlIGNxYS1tci1bOHB4XSBjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWNlbnRlclwiPlxuICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgY2xhc3M9XCJjcWEtYmctdHJhbnNwYXJlbnQgY3FhLWJvcmRlci1ub25lIGNxYS1jdXJzb3ItcG9pbnRlciBjcWEtdGV4dC1bIzlDQTNBRl0gY3FhLXRleHQtWzEwcHhdIGNxYS1sZWFkaW5nLVsxNXB4XSBjcWEtZm9udC1tZWRpdW0gY3FhLXdoaXRlc3BhY2Utbm93cmFwIGNxYS1zZWxlY3Qtbm9uZSBob3ZlcjpjcWEtb3BhY2l0eS03MCBjcWEtdHJhbnNpdGlvbi1vcGFjaXR5IGNxYS1vdXRsaW5lLW5vbmUgY3FhLXB4LTFcIlxuICAgICAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlU3BlZWRDb250cm9sKClcIlxuICAgICAgICAgICAgICBbbWF0VG9vbHRpcF09XCInUGxheWJhY2sgU3BlZWQnXCJcbiAgICAgICAgICAgICAgW21hdFRvb2x0aXBQb3NpdGlvbl09XCInYmVsb3cnXCI+XG4gICAgICAgICAgICAgIHt7IGN1cnJlbnRTcGVlZCB9fVxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICBcbiAgICAgICAgICAgIDxkaXYgXG4gICAgICAgICAgICAgICpuZ0lmPVwiaXNTcGVlZENvbnRyb2xPcGVuXCJcbiAgICAgICAgICAgICAgY2xhc3M9XCJjcWEtYWJzb2x1dGUgY3FhLWJvdHRvbS1mdWxsIGNxYS1tYi0yIGNxYS1yaWdodC0wIGNxYS1iZy1bI0YwRjBGMV0gY3FhLXJvdW5kZWQtbGcgY3FhLW92ZXJmbG93LWhpZGRlbiBjcWEtc2hhZG93LWxnIGNxYS16LTUwXCJcbiAgICAgICAgICAgICAgc3R5bGU9XCJtaW4td2lkdGg6IG1heC1jb250ZW50OyBsZWZ0OiA1MCU7IGJvdHRvbTogMCU7IHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC01MCUpO1wiPlxuICAgICAgICAgICAgICA8Y3FhLXNlZ21lbnQtY29udHJvbFxuICAgICAgICAgICAgICAgIFtzZWdtZW50c109XCJzcGVlZFNlZ21lbnRzXCJcbiAgICAgICAgICAgICAgICBbdmFsdWVdPVwiY3VycmVudFNwZWVkXCJcbiAgICAgICAgICAgICAgICBbY29udGFpbmVyQmdDb2xvcl09XCInI0YwRjBGMSdcIlxuICAgICAgICAgICAgICAgICh2YWx1ZUNoYW5nZSk9XCJvblNwZWVkQ2hhbmdlKCRldmVudClcIj5cbiAgICAgICAgICAgICAgPC9jcWEtc2VnbWVudC1jb250cm9sPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgXG4gICAgICAgICAgPGRpdiBcbiAgICAgICAgICAgICN0aW1lbGluZUJhclxuICAgICAgICAgICAgY2xhc3M9XCJjcWEtcmVsYXRpdmUgY3FhLWgtMSBjcWEtYmctZ3JheS0yMDAgY3FhLXJvdW5kZWQtZnVsbCBjcWEtY3Vyc29yLXBvaW50ZXIgY3FhLWZsZXgtMVwiXG4gICAgICAgICAgICAoY2xpY2spPVwib25UaW1lbGluZUNsaWNrKCRldmVudClcIj5cbiAgICAgICAgICAgIFxuICAgICAgICAgICAgPGRpdiBcbiAgICAgICAgICAgICAgKm5nRm9yPVwibGV0IG1hcmtlciBvZiBnbG9iYWxTdGVwTWFya2Vyc1wiIFxuICAgICAgICAgICAgICBjbGFzcz1cImNxYS1hYnNvbHV0ZSBjcWEtcm91bmRlZC1mdWxsXCJcbiAgICAgICAgICAgICAgW3N0eWxlLmxlZnQuJV09XCJ0b3RhbER1cmF0aW9uID4gMCA/IChtYXJrZXIuZ2xvYmFsVGltZSAvIHRvdGFsRHVyYXRpb24pICogMTAwIDogMFwiXG4gICAgICAgICAgICAgIFtzdHlsZS53aWR0aF09XCInOHB4J1wiXG4gICAgICAgICAgICAgIFtzdHlsZS5oZWlnaHRdPVwiJzhweCdcIlxuICAgICAgICAgICAgICBbc3R5bGUuYmFja2dyb3VuZF09XCJnZXRHbG9iYWxNYXJrZXJDb2xvcihtYXJrZXIubGV2ZWwpXCJcbiAgICAgICAgICAgICAgW3N0eWxlLmJvcmRlcl09XCInMnB4IHNvbGlkICcgKyBnZXRHbG9iYWxNYXJrZXJSZXN1bHRDb2xvcihtYXJrZXIucmVzdWx0KVwiXG4gICAgICAgICAgICAgIFtzdHlsZS5ib3gtc2l6aW5nXT1cIidib3JkZXItYm94J1wiXG4gICAgICAgICAgICAgIFthdHRyLnRpdGxlXT1cIm1hcmtlci50aXRsZSB8fCAnJ1wiXG4gICAgICAgICAgICAgIHN0eWxlPVwicG9pbnRlci1ldmVudHM6IGF1dG87IHotaW5kZXg6IDUwOyBjdXJzb3I6IHBvaW50ZXI7IHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC01MCUpOyB0b3A6IDUwJTtcIlxuICAgICAgICAgICAgICAoY2xpY2spPVwib25NYXJrZXJDbGljaygkZXZlbnQsIG1hcmtlcilcIj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgXG4gICAgICAgICAgICA8ZGl2IFxuICAgICAgICAgICAgICBjbGFzcz1cImNxYS1hYnNvbHV0ZSBjcWEtbGVmdC0wIGNxYS10b3AtMCBjcWEtaC1mdWxsIGNxYS1iZy1ibHVlLTUwMCBjcWEtcm91bmRlZC1mdWxsXCJcbiAgICAgICAgICAgICAgW3N0eWxlLndpZHRoLiVdPVwicHJvZ3Jlc3NcIlxuICAgICAgICAgICAgICBbc3R5bGUudHJhbnNpdGlvbl09XCJkcmFnZ2luZyA/ICdub25lJyA6ICd3aWR0aCAxMDBtcydcIlxuICAgICAgICAgICAgICBzdHlsZT1cInBvaW50ZXItZXZlbnRzOiBub25lOyB6LWluZGV4OiAyO1wiPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICBcbiAgICAgICAgICAgIDxkaXYgXG4gICAgICAgICAgICAgIGNsYXNzPVwiY3FhLWFic29sdXRlIGNxYS10b3AtMS8yIGNxYS13LTMgY3FhLWgtMyBjcWEtYmctYmx1ZS02MDAgY3FhLXJvdW5kZWQtZnVsbCBjcWEtY3Vyc29yLWdyYWIgYWN0aXZlOmNxYS1jdXJzb3ItZ3JhYmJpbmcgY3FhLXNoYWRvdy1tZFwiXG4gICAgICAgICAgICAgIFtzdHlsZS5sZWZ0LiVdPVwicHJvZ3Jlc3NcIlxuICAgICAgICAgICAgICBzdHlsZT1cInRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC01MCUpOyB6LWluZGV4OiA2MDtcIlxuICAgICAgICAgICAgICAobW91c2Vkb3duKT1cInN0YXJ0RHJhZygkZXZlbnQpXCI+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwiY3FhLXRleHQtWyM5Q0EzQUZdIGNxYS10ZXh0LVs5cHhdIGNxYS1mb250LW5vcm1hbCBjcWEtd2hpdGVzcGFjZS1ub3dyYXAgY3FhLXNlbGVjdC1ub25lXCI+XG4gICAgICAgICAgICB7eyBmb3JtYXRUaW1lKHRvdGFsRHVyYXRpb24gLyAxMDAwKSB9fVxuICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDxkaXYgKm5nSWY9XCIhaXNMaXZlICYmIGN1cnJlbnRWaWV3ID09PSAnc2NyZWVuc2hvdHMnXCIgY2xhc3M9XCJjcWEtaC1mdWxsXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiY3FhLXctZnVsbCBjcWEtcHktNCBjcWEtaC1mdWxsIGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXJcIiAqbmdJZj1cInNjcmVlblNob3RVcmxcIj5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImhhc0RldmljZUZyYW1lXCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS13LWZ1bGwgY3FhLWgtZnVsbCBjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWNlbnRlclwiIFtuZ0NsYXNzXT1cInsnY3FhLXAtNCc6IHBsYXRmb3JtVHlwZSA9PT0gJ2Jyb3dzZXInfVwiPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1yZWxhdGl2ZSBjcWEtaC1mdWxsIGNxYS13LWF1dG8gY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1jZW50ZXIgY3FhLW1heC1oLWZ1bGxcIiBbbmdDbGFzc109XCJ7J2NxYS1yb3VuZGVkLW1kIGNxYS1vdmVyZmxvdy1oaWRkZW4nOiBwbGF0Zm9ybVR5cGUgPT09ICdicm93c2VyJywgJ2NxYS1taW4tdy1tYXgnOiBwbGF0Zm9ybVR5cGUgPT09ICdkZXZpY2UnfVwiPlxuICAgICAgICAgICAgICA8aW1nXG4gICAgICAgICAgICAgICAgW3NyY109XCJkZXZpY2VNb2NrdXBJbWFnZVwiXG4gICAgICAgICAgICAgICAgYWx0PVwiRGV2aWNlIG1vY2t1cFwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJjcWEtaC1mdWxsIGNxYS13LWF1dG8gY3FhLW9iamVjdC1jb250YWluIGNxYS1ibG9jayBjcWEtcG9pbnRlci1ldmVudHMtbm9uZSBjcWEtei0xMFwiXG4gICAgICAgICAgICAgICAgW25nQ2xhc3NdPVwieydjcWEtbWF4LWgtW2luaGVyaXRdJzogcGxhdGZvcm1UeXBlID09PSAnYnJvd3NlcicsICdjcWEtbWF4LWgtZnVsbCc6IHBsYXRmb3JtVHlwZSAhPT0gJ2Jyb3dzZXInfVwiXG4gICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtYWJzb2x1dGUgY3FhLWZsZXggY3FhLWZsZXgtY29sXCIgW25nU3R5bGVdPVwiZGV2aWNlU2NyZWVuU3R5bGVcIiBbbmdDbGFzc109XCJ7J2NxYS1iZy13aGl0ZSc6IHBsYXRmb3JtVHlwZSAhPT0gJ2Jyb3dzZXInfVwiPlxuICAgICAgICAgICAgICAgIDxpbWdcbiAgICAgICAgICAgICAgICAgIFtzcmNdPVwic2NyZWVuU2hvdFVybFwiXG4gICAgICAgICAgICAgICAgICBhbHQ9XCJTY3JlZW5zaG90XCJcbiAgICAgICAgICAgICAgICAgIFtuZ0NsYXNzXT1cInsnY3FhLXotMjAnOiBwbGF0Zm9ybVR5cGUgPT09ICdicm93c2VyJ31cIlxuICAgICAgICAgICAgICAgICAgY2xhc3M9XCJjcWEtb2JqZWN0LWNvbnRhaW4gY3FhLXctZnVsbCBjcWEtaC1mdWxsIGNxYS1ibG9jayBjcWEtYmctWyMjRjJGMkYyXVwiXG4gICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICA8L2Rpdj5cbiAgICBcbiAgICAgIDxkaXYgY2xhc3M9XCJjcWEtcC0xMCBjcWEtdGV4dC1jZW50ZXIgY3FhLXRleHQtZ3JheS00MDAgY3FhLXRleHQtc20gY3FhLWgtZnVsbCBjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWNlbnRlclwiICpuZ0lmPVwiIXNjcmVlblNob3RVcmxcIj5cbiAgICAgICAgTm8gc2NyZWVuc2hvdCBhdmFpbGFibGVcbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiAqbmdJZj1cIiFpc0xpdmUgJiYgY3VycmVudFZpZXcgPT09ICd0cmFjZSdcIiBjbGFzcz1cImNxYS1oLWZ1bGwgY3FhLWZsZXggY3FhLWZsZXgtY29sIGNxYS1qdXN0aWZ5LWNlbnRlclwiPlxuICAgICAgPGRpdiBjbGFzcz1cImNxYS13LWZ1bGwgY3FhLWgtZnVsbCBjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1yZWxhdGl2ZVwiICpuZ0lmPVwidHJhY2VWaWV3VXJsXCIgW25nQ2xhc3NdPVwieychY3FhLWgtZnVsbCc6IHBsYXRmb3JtVHlwZSA9PT0gJ2RldmljZSd9XCIgc3R5bGU9XCJwYWRkaW5nLXRvcDogNDhweDsgcGFkZGluZy1ib3R0b206IDBweDtcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImNxYS13LWZ1bGwgY3FhLWgtZnVsbCBjcWEtb3ZlcmZsb3ctaGlkZGVuIGNxYS1yZWxhdGl2ZVwiPlxuICAgICAgICAgIDxpZnJhbWUgXG4gICAgICAgICAgICBbc3JjXT1cInNhZmVUcmFjZVVybFwiIFxuICAgICAgICAgICAgdGl0bGU9XCJUcmFjZSBWaWV3ZXJcIlxuICAgICAgICAgICAgY2xhc3M9XCJjcWEtb2JqZWN0LWNvbnRhaW4gY3FhLXctZnVsbCBjcWEtbWluLWgtWzI1MHB4XSBjcWEtbWF4LWgtZnVsbCBjcWEtYmxvY2sgY3FhLWJnLVsjI0YyRjJGMl1cIlxuICAgICAgICAgICAgc3R5bGU9XCJtYXJnaW4tdG9wOiAtNDhweDsgaGVpZ2h0OiBjYWxjKDEwMCUgKyA0OHB4KTtcIlxuICAgICAgICAgICAgZnJhbWVib3JkZXI9XCIwXCJcbiAgICAgICAgICAgIGFsbG93ZnVsbHNjcmVlblxuICAgICAgICAgICAgd2lkdGg9XCIxMDAlXCJcbiAgICAgICAgICAgIGxvYWRpbmc9XCJsYXp5XCJcbiAgICAgICAgICAgIChsb2FkKT1cIm9uVHJhY2VWaWV3ZXJMb2FkKClcIlxuICAgICAgICAgICAgKGVycm9yKT1cIm9uVHJhY2VWaWV3ZXJFcnJvcigpXCI+XG4gICAgICAgICAgPC9pZnJhbWU+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICBcbiAgICAgICAgPGRpdiAqbmdJZj1cInRyYWNlVmlld2VyTG9hZGluZ1wiIGNsYXNzPVwiY3FhLWFic29sdXRlIGNxYS1pbnNldC0wIGNxYS1iZy1bI0YzRjRGNl0gY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1jZW50ZXIgY3FhLXotMTBcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXRleHQtY2VudGVyIGNxYS10ZXh0LWdyYXktNDAwIGNxYS10ZXh0LXNtXCI+XG4gICAgICAgICAgICBMb2FkaW5nIHRyYWNlIHZpZXdlci4uLlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgXG4gICAgICAgIDxkaXYgKm5nSWY9XCJ0cmFjZVZpZXdlckVycm9yXCIgY2xhc3M9XCJjcWEtYWJzb2x1dGUgY3FhLWluc2V0LTAgY3FhLWJnLVsjRjNGNEY2XSBjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWNlbnRlciBjcWEtei0xMFwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtdGV4dC1jZW50ZXIgY3FhLXRleHQtZ3JheS00MDAgY3FhLXRleHQtc21cIj5cbiAgICAgICAgICAgIEZhaWxlZCB0byBsb2FkIHRyYWNlIHZpZXdlclxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIFxuICAgICAgPGRpdiBjbGFzcz1cImNxYS1wLTEwIGNxYS10ZXh0LWNlbnRlciBjcWEtdGV4dC1ncmF5LTQwMCBjcWEtdGV4dC1zbSBjcWEtaC1mdWxsIGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyXCIgKm5nSWY9XCIhdHJhY2VWaWV3VXJsXCI+XG4gICAgICAgIE5vIHRyYWNlIGF2YWlsYWJsZVxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+ICBcbiAgPC9kaXY+XG48L2Rpdj4iXX0=
|