ngx-scandoc 0.0.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/core/app.worker.d.ts +1 -0
  2. package/core/components/components.module.d.ts +8 -0
  3. package/core/components/webcam/domain/webcam-image.d.ts +35 -0
  4. package/core/components/webcam/domain/webcam-init-error.d.ts +4 -0
  5. package/core/components/webcam/domain/webcam-mirror-properties.d.ts +3 -0
  6. package/core/components/webcam/util/webcam.util.d.ts +8 -0
  7. package/core/components/webcam/webcam/webcam.component.d.ts +202 -0
  8. package/core/components/webcam/webcam.module.d.ts +9 -0
  9. package/core/pipes/pipes.module.d.ts +7 -0
  10. package/core/pipes/safeResourceUrl.pipe.d.ts +10 -0
  11. package/core/shared/material.module.d.ts +28 -0
  12. package/dialogs/components/blank/blank.component.d.ts +17 -0
  13. package/dialogs/components/confirm/confirm.component.d.ts +30 -0
  14. package/dialogs/components/loading/loading.component.d.ts +5 -0
  15. package/dialogs/components/scan-mobile/scan-mobile.component.d.ts +16 -0
  16. package/dialogs/components/scan-profile/scan-profile.component.d.ts +124 -0
  17. package/dialogs/components/scan-selfie/scan-selfie.component.d.ts +83 -0
  18. package/dialogs/dialogs.core.provider.d.ts +18 -0
  19. package/dialogs/dialogs.module.d.ts +21 -0
  20. package/esm2020/core/app.worker.mjs +236 -0
  21. package/esm2020/core/components/components.module.mjs +18 -0
  22. package/esm2020/core/components/webcam/domain/webcam-image.mjs +58 -0
  23. package/esm2020/core/components/webcam/domain/webcam-init-error.mjs +3 -0
  24. package/esm2020/core/components/webcam/domain/webcam-mirror-properties.mjs +3 -0
  25. package/esm2020/core/components/webcam/util/webcam.util.mjs +48 -0
  26. package/esm2020/core/components/webcam/webcam/webcam.component.mjs +861 -0
  27. package/esm2020/core/components/webcam/webcam.module.mjs +22 -0
  28. package/esm2020/core/pipes/pipes.module.mjs +19 -0
  29. package/esm2020/core/pipes/safeResourceUrl.pipe.mjs +20 -0
  30. package/esm2020/core/shared/material.module.mjs +162 -0
  31. package/esm2020/dialogs/components/blank/blank.component.mjs +47 -0
  32. package/esm2020/dialogs/components/confirm/confirm.component.mjs +53 -0
  33. package/esm2020/dialogs/components/loading/loading.component.mjs +12 -0
  34. package/esm2020/dialogs/components/scan-mobile/scan-mobile.component.mjs +43 -0
  35. package/esm2020/dialogs/components/scan-profile/scan-profile.component.mjs +756 -0
  36. package/esm2020/dialogs/components/scan-selfie/scan-selfie.component.mjs +392 -0
  37. package/esm2020/dialogs/dialogs.core.provider.mjs +100 -0
  38. package/esm2020/dialogs/dialogs.module.mjs +89 -0
  39. package/esm2020/forms/form.module.mjs +87 -0
  40. package/esm2020/forms/types/avatar.type.mjs +53 -0
  41. package/esm2020/forms/types/profile.image.type.mjs +54 -0
  42. package/esm2020/forms/types/title.type.mjs +60 -0
  43. package/esm2020/lib/ngx-scandoc.module.mjs +28 -11
  44. package/esm2020/providers/auth.provider.mjs +57 -0
  45. package/esm2020/providers/interceptor.provider.mjs +61 -0
  46. package/esm2020/providers/scan.form.mjs +386 -0
  47. package/esm2020/providers/scan.provider.mjs +490 -0
  48. package/esm2020/providers/translation.provider.mjs +50 -0
  49. package/esm2020/providers/webrtc.provider.mjs +58 -0
  50. package/esm2020/public-api.mjs +22 -4
  51. package/fesm2015/ngx-scandoc.mjs +4178 -32
  52. package/fesm2015/ngx-scandoc.mjs.map +1 -1
  53. package/fesm2020/ngx-scandoc.mjs +4154 -32
  54. package/fesm2020/ngx-scandoc.mjs.map +1 -1
  55. package/forms/form.module.d.ts +18 -0
  56. package/forms/types/avatar.type.d.ts +14 -0
  57. package/forms/types/profile.image.type.d.ts +14 -0
  58. package/forms/types/title.type.d.ts +12 -0
  59. package/lib/ngx-scandoc.module.d.ts +20 -2
  60. package/package.json +6 -2
  61. package/providers/auth.provider.d.ts +21 -0
  62. package/providers/interceptor.provider.d.ts +13 -0
  63. package/providers/scan.form.d.ts +13 -0
  64. package/providers/scan.provider.d.ts +239 -0
  65. package/providers/translation.provider.d.ts +9 -0
  66. package/providers/webrtc.provider.d.ts +11 -0
  67. package/public-api.d.ts +21 -3
  68. package/esm2020/lib/ngx-scandoc.component.mjs +0 -22
  69. package/esm2020/lib/ngx-scandoc.service.mjs +0 -14
  70. package/lib/ngx-scandoc.component.d.ts +0 -8
  71. package/lib/ngx-scandoc.service.d.ts +0 -6
@@ -0,0 +1,861 @@
1
+ import { Component, EventEmitter, HostListener, Input, Output, ViewChild, } from '@angular/core';
2
+ import { WebcamImage } from '../domain/webcam-image';
3
+ import { from, Observable, of } from 'rxjs';
4
+ import { WebcamUtil } from '../util/webcam.util';
5
+ import { Breakpoints, } from '@angular/cdk/layout';
6
+ import { switchMap } from 'rxjs/operators';
7
+ import { workertext } from '../../../app.worker';
8
+ import * as i0 from "@angular/core";
9
+ import * as i1 from "@angular/cdk/layout";
10
+ import * as i2 from "@angular/cdk/platform";
11
+ import * as i3 from "@angular/common";
12
+ export class WebcamComponent {
13
+ constructor(breakpointObserver, platform, cd, zone) {
14
+ this.breakpointObserver = breakpointObserver;
15
+ this.platform = platform;
16
+ this.cd = cd;
17
+ this.zone = zone;
18
+ /** Defines the max width of the webcam area in px */
19
+ this.width = 640;
20
+ /** Defines the max height of the webcam area in px */
21
+ this.height = 480;
22
+ /** Defines base constraints to apply when requesting video track from UserMedia */
23
+ this.videoOptions = WebcamComponent.DEFAULT_VIDEO_OPTIONS;
24
+ /** Flag to enable/disable camera switch. If enabled, a switch icon will be displayed if multiple cameras were found */
25
+ this.allowCameraSwitch = true;
26
+ /** Flag to control whether an ImageData object is stored into the WebcamImage object. */
27
+ this.captureImageData = false;
28
+ /** The image type to use when capturing snapshots */
29
+ this.imageType = WebcamComponent.DEFAULT_IMAGE_TYPE;
30
+ /** The image quality to use when capturing snapshots (number between 0 and 1) */
31
+ this.imageQuality = WebcamComponent.DEFAULT_IMAGE_QUALITY;
32
+ /** EventEmitter which fires when an image has been captured */
33
+ this.imageCapture = new EventEmitter();
34
+ /** Emits a mediaError if webcam cannot be initialized (e.g. missing user permissions) */
35
+ this.initError = new EventEmitter();
36
+ /** Emits when the webcam video was clicked */
37
+ this.imageClick = new EventEmitter();
38
+ /** Emits the active deviceId after the active video device was switched */
39
+ this.cameraSwitched = new EventEmitter();
40
+ this.videoReady = new EventEmitter();
41
+ this.showVideo = false;
42
+ this.destroyed = new EventEmitter();
43
+ /** available video devices */
44
+ this.availableVideoInputs = [];
45
+ /** Indicates whether the video device is ready to be switched */
46
+ this.videoInitialized = false;
47
+ this.canvasEl = document.createElement('canvas');
48
+ /** Index of active video in availableVideoInputs */
49
+ this.activeVideoInputIndex = -1;
50
+ /** MediaStream object in use for streaming UserMedia data */
51
+ this.mediaStream = null;
52
+ this.shutdown = false;
53
+ this.canStart = true;
54
+ this.videoSize = { width: 1920, height: 1080 };
55
+ this.canvasSize = { width: 1280, height: 720 };
56
+ this.landscape = true;
57
+ // if (typeof Worker !== 'undefined') {
58
+ // // Create a new
59
+ // this.worker = new Worker(
60
+ // new URL('./../../../../app/app.worker', import.meta.url)
61
+ // );
62
+ // this.worker.onmessage = ({ data }) => {
63
+ // console.log(`page got message: ${data}`);
64
+ // };
65
+ // console.log('POST');
66
+ // this.worker.postMessage('hello');
67
+ // } else {
68
+ // // Web workers are not supported in this environment.
69
+ // // You should add a fallback so that your program still executes correctly.
70
+ // }
71
+ }
72
+ /**
73
+ * If the given Observable emits, an image will be captured and emitted through 'imageCapture' EventEmitter
74
+ */
75
+ set trigger(trigger) {
76
+ if (this.triggerSubscription) {
77
+ this.triggerSubscription.unsubscribe();
78
+ }
79
+ // Subscribe to events from this Observable to take snapshots
80
+ this.triggerSubscription = trigger.subscribe((time) => {
81
+ this.takeSnapshot(time);
82
+ });
83
+ }
84
+ onResize() {
85
+ this.videoReady.next(false);
86
+ this.resizeStage();
87
+ }
88
+ /**
89
+ * Get MediaTrackConstraints to request streaming the given device
90
+ * @param deviceId
91
+ * @param baseMediaTrackConstraints base constraints to merge deviceId-constraint into
92
+ * @returns
93
+ */
94
+ static getMediaConstraintsForDevice(deviceId, baseMediaTrackConstraints) {
95
+ const result = baseMediaTrackConstraints
96
+ ? baseMediaTrackConstraints
97
+ : this.DEFAULT_VIDEO_OPTIONS;
98
+ if (deviceId) {
99
+ result.deviceId = { exact: deviceId };
100
+ }
101
+ return result;
102
+ }
103
+ /**
104
+ * Tries to harvest the deviceId from the given mediaStreamTrack object.
105
+ * Browsers populate this object differently; this method tries some different approaches
106
+ * to read the id.
107
+ * @param mediaStreamTrack
108
+ * @returns deviceId if found in the mediaStreamTrack
109
+ */
110
+ static getDeviceIdFromMediaStreamTrack(mediaStreamTrack) {
111
+ if (mediaStreamTrack.getSettings &&
112
+ mediaStreamTrack.getSettings() &&
113
+ mediaStreamTrack.getSettings().deviceId) {
114
+ return mediaStreamTrack.getSettings().deviceId;
115
+ }
116
+ else if (mediaStreamTrack.getConstraints &&
117
+ mediaStreamTrack.getConstraints() &&
118
+ mediaStreamTrack.getConstraints().deviceId) {
119
+ const deviceIdObj = mediaStreamTrack.getConstraints().deviceId;
120
+ return WebcamComponent.getValueFromConstrainDOMString(deviceIdObj);
121
+ }
122
+ }
123
+ /**
124
+ * Tries to harvest the facingMode from the given mediaStreamTrack object.
125
+ * Browsers populate this object differently; this method tries some different approaches
126
+ * to read the value.
127
+ * @param mediaStreamTrack
128
+ * @returns facingMode if found in the mediaStreamTrack
129
+ */
130
+ static getFacingModeFromMediaStreamTrack(mediaStreamTrack) {
131
+ if (mediaStreamTrack) {
132
+ if (mediaStreamTrack.getSettings &&
133
+ mediaStreamTrack.getSettings() &&
134
+ mediaStreamTrack.getSettings().facingMode) {
135
+ return mediaStreamTrack.getSettings().facingMode;
136
+ }
137
+ else if (mediaStreamTrack.getConstraints &&
138
+ mediaStreamTrack.getConstraints() &&
139
+ mediaStreamTrack.getConstraints().facingMode) {
140
+ const facingModeConstraint = mediaStreamTrack.getConstraints().facingMode;
141
+ return WebcamComponent.getValueFromConstrainDOMString(facingModeConstraint);
142
+ }
143
+ }
144
+ }
145
+ /**
146
+ * Determines whether the given mediaStreamTrack claims itself as user facing
147
+ * @param mediaStreamTrack
148
+ */
149
+ static isUserFacing(mediaStreamTrack) {
150
+ const facingMode = WebcamComponent.getFacingModeFromMediaStreamTrack(mediaStreamTrack);
151
+ return facingMode ? 'user' === facingMode.toLowerCase() : false;
152
+ }
153
+ /**
154
+ * Extracts the value from the given ConstrainDOMString
155
+ * @param constrainDOMString
156
+ */
157
+ static getValueFromConstrainDOMString(constrainDOMString) {
158
+ if (constrainDOMString) {
159
+ if (constrainDOMString instanceof String) {
160
+ return String(constrainDOMString);
161
+ }
162
+ else if (Array.isArray(constrainDOMString) &&
163
+ Array(constrainDOMString).length > 0) {
164
+ return String(constrainDOMString[0]);
165
+ }
166
+ else if (typeof constrainDOMString === 'object') {
167
+ if (constrainDOMString['exact']) {
168
+ return String(constrainDOMString['exact']);
169
+ }
170
+ else if (constrainDOMString['ideal']) {
171
+ return String(constrainDOMString['ideal']);
172
+ }
173
+ }
174
+ }
175
+ return null;
176
+ }
177
+ resizeStage() {
178
+ setTimeout(() => {
179
+ this.updateSize();
180
+ this.updatecanvasSize();
181
+ this.drawRectangle();
182
+ this.cd.detectChanges();
183
+ this.videoReady.next(true);
184
+ }, 10);
185
+ }
186
+ get canvasHeight() {
187
+ const landscape = this.width > this.height;
188
+ const aspect = this.videoSize.width / this.videoSize.height;
189
+ if (!landscape) {
190
+ return this.width * aspect;
191
+ }
192
+ return this.height;
193
+ }
194
+ updatecanvasSize() {
195
+ console.log(this.width, this.height);
196
+ const landscape = this.width > this.height;
197
+ const aspect = this.videoSize.width / this.videoSize.height;
198
+ let width = this.width;
199
+ let height = this.height;
200
+ if (landscape) {
201
+ height = width / aspect;
202
+ }
203
+ else {
204
+ height = width / aspect;
205
+ }
206
+ if (height > this.height) {
207
+ height = this.height;
208
+ width = this.height * aspect;
209
+ }
210
+ this.canvasSize = { width: Math.round(width), height: Math.round(height) };
211
+ console.log(this.canvasSize, this.videoSize);
212
+ if (this.isMobile) {
213
+ this.video.nativeElement.setAttribute('height', this.canvasSize.height);
214
+ this.video.nativeElement.setAttribute('width', this.canvasSize.width);
215
+ }
216
+ else {
217
+ if (this.videoSize.width > this.videoSize.hight) {
218
+ this.video.nativeElement.setAttribute('height', this.canvasSize.height);
219
+ }
220
+ else {
221
+ this.video.nativeElement.setAttribute('width', this.canvasSize.width);
222
+ }
223
+ }
224
+ this.cd.detectChanges();
225
+ }
226
+ setupWorker() {
227
+ if (typeof Worker !== 'undefined') {
228
+ // Create a new
229
+ if (this.type !== 'selfie') {
230
+ this.zone.runOutsideAngular(() => {
231
+ var blob = new Blob([workertext], { type: 'text/javascript' });
232
+ var url = URL.createObjectURL(blob);
233
+ this.worker = new Worker(url);
234
+ this.worker.onmessage = ({ data }) => {
235
+ if (data.base64) {
236
+ data.type == 'data';
237
+ this.imageHandler.next(data);
238
+ }
239
+ };
240
+ });
241
+ }
242
+ }
243
+ }
244
+ ngAfterViewInit() {
245
+ this.setupWorker();
246
+ if (this.imageHandler) {
247
+ this.imageHandler.subscribe((resp) => {
248
+ if (resp.type === 'stop') {
249
+ this.worker?.postMessage({ type: 'stop' });
250
+ }
251
+ });
252
+ }
253
+ this.breakpointObserver
254
+ .observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape])
255
+ .subscribe((state) => {
256
+ if (this.platform.IOS || this.platform.ANDROID) {
257
+ // this.landscape = state.breakpoints[Breakpoints.HandsetLandscape];
258
+ }
259
+ const mobile = this.platform.IOS;
260
+ if (state.matches && mobile) {
261
+ this.updateSize();
262
+ this.updatecanvasSize();
263
+ this.drawRectangle();
264
+ }
265
+ });
266
+ if (this.switchCamera) {
267
+ if (this.switchCameraSubscription) {
268
+ this.switchCameraSubscription.unsubscribe();
269
+ }
270
+ // Subscribe to events from this Observable to switch video device
271
+ this.switchCameraSubscription = this.switchCamera.subscribe((value) => {
272
+ this.switchToVideoInput(value);
273
+ });
274
+ }
275
+ this.detectAvailableDevices()
276
+ .then(() => {
277
+ // start video
278
+ if (this.canStart) {
279
+ this.switchToVideoInput('');
280
+ }
281
+ })
282
+ .catch((err) => {
283
+ this.initError.next({ message: err });
284
+ // fallback: still try to load webcam, even if device enumeration failed
285
+ if (this.canStart) {
286
+ this.switchToVideoInput('');
287
+ }
288
+ });
289
+ }
290
+ ngOnDestroy() {
291
+ this.canStart = false;
292
+ this.nativeVideoElement.pause();
293
+ this.destroyed.emit(true);
294
+ this.stopMediaTracks();
295
+ this.unsubscribeFromSubscriptions();
296
+ this.shutdown = true;
297
+ // shut down worker
298
+ if (this.imageHandler) {
299
+ this.imageHandler.next({ type: 'stop' });
300
+ }
301
+ if (this.nativeVideoElement.srcObject) {
302
+ this.nativeVideoElement.srcObject
303
+ .getTracks()
304
+ .forEach((track) => {
305
+ track.stop();
306
+ });
307
+ this.nativeVideoElement.srcObject = null;
308
+ }
309
+ // this.nativeVideoElement.src = null;
310
+ // this.nativeVideoElement.srcObject = null;
311
+ }
312
+ takeSelfie() {
313
+ const _video = this.nativeVideoElement;
314
+ const mimeType = this.imageType
315
+ ? this.imageType
316
+ : WebcamComponent.DEFAULT_IMAGE_TYPE;
317
+ let _canvas = document.createElement('canvas'); //this.canvasSnapshot.nativeElement;
318
+ const { width, height } = this.videoSize;
319
+ console.log(width, height);
320
+ const { padding, top, rWidth, rHeight } = this.snapRectangle;
321
+ _canvas.width = rWidth;
322
+ _canvas.height = rHeight;
323
+ const ctx = _canvas.getContext('2d', {
324
+ alpha: false,
325
+ powerPreference: 'high-performance',
326
+ antialias: false,
327
+ depth: false,
328
+ desynchronized: true,
329
+ });
330
+ if (ctx) {
331
+ ctx.drawImage(_video, padding, top, rWidth, rHeight, 0, 0, rWidth, rHeight);
332
+ const imgAsUrl = _canvas.toDataURL(mimeType, 1);
333
+ this.imageCapture.emit(new WebcamImage(imgAsUrl, mimeType, new ImageData(1, 1), null));
334
+ }
335
+ }
336
+ /**
337
+ * Takes a snapshot of the current webcam's view and emits the image as an event
338
+ */
339
+ takeSnapshot(time) {
340
+ if (this.type === 'selfie') {
341
+ this.takeSelfie();
342
+ return;
343
+ }
344
+ if (this.trackProcessor) {
345
+ return;
346
+ }
347
+ this.zone.runOutsideAngular(() => {
348
+ const canvasSmalSize = 384;
349
+ const _video = this.nativeVideoElement;
350
+ const mimeType = this.imageType
351
+ ? this.imageType
352
+ : WebcamComponent.DEFAULT_IMAGE_TYPE;
353
+ let _canvas = document.createElement('canvas'); //this.canvasSnapshot.nativeElement;
354
+ const { width, height } = this.videoSize;
355
+ _canvas.width = width;
356
+ _canvas.height = height;
357
+ const ctx = _canvas.getContext('2d', {
358
+ alpha: false,
359
+ powerPreference: 'high-performance',
360
+ antialias: false,
361
+ depth: false,
362
+ desynchronized: true,
363
+ });
364
+ const canvas = document.createElement('canvas'); // needs an initial size
365
+ canvas.height = canvasSmalSize;
366
+ canvas.width = canvasSmalSize;
367
+ const ctxO = canvas.getContext('2d', {
368
+ alpha: false,
369
+ powerPreference: 'high-performance',
370
+ antialias: false,
371
+ depth: false,
372
+ desynchronized: true,
373
+ });
374
+ if (ctx && ctxO) {
375
+ ctx.imageSmoothingEnabled = false;
376
+ ctx.drawImage(_video, 0, 0);
377
+ ctxO.drawImage(_video, 0, 0, canvasSmalSize, canvasSmalSize);
378
+ const imData = ctx.getImageData(0, 0, this.videoSize.width, this.videoSize.height);
379
+ const resize = canvas.toDataURL(mimeType, 1);
380
+ const currentTime = new Date().getTime();
381
+ const diff = currentTime - time;
382
+ const delay = diff > 100 ? 0 : 100 - diff;
383
+ const timeout = setTimeout(() => {
384
+ this.imageCapture.emit(new WebcamImage('', mimeType, imData, resize));
385
+ clearTimeout(timeout);
386
+ }, delay);
387
+ }
388
+ });
389
+ }
390
+ update() { }
391
+ resizeImage(base64data) {
392
+ return new Observable((observer) => {
393
+ let canvas = document.createElement('canvas');
394
+ const ctx = canvas.getContext('2d');
395
+ const max_size = 384;
396
+ let image = new Image();
397
+ image.src = base64data;
398
+ image.onload = () => {
399
+ let width = image.width;
400
+ let height = image.height;
401
+ if (width < height) {
402
+ height *= max_size / width;
403
+ width = max_size;
404
+ }
405
+ else {
406
+ width *= max_size / height;
407
+ height = max_size;
408
+ }
409
+ canvas.width = width;
410
+ canvas.height = height;
411
+ // console.log(width, height);
412
+ if (ctx) {
413
+ // ctx.rotate((90 * Math.PI) / 180);
414
+ // ctx.translate(0, -canvas.width);
415
+ ctx.drawImage(image, 0, 0, 384, 384);
416
+ observer.next(canvas.toDataURL());
417
+ ctx.clearRect(0, 0, 1, 1);
418
+ }
419
+ else {
420
+ observer.error({ type: 'generic error' });
421
+ }
422
+ image = null;
423
+ canvas = null;
424
+ };
425
+ image.onerror = (e) => {
426
+ observer.error(e);
427
+ };
428
+ });
429
+ }
430
+ /**
431
+ * Switches to the next/previous video device
432
+ * @param forward
433
+ */
434
+ rotateVideoInput(forward) {
435
+ if (this.availableVideoInputs && this.availableVideoInputs.length > 1) {
436
+ const increment = forward
437
+ ? 1
438
+ : this.availableVideoInputs.length - 1;
439
+ const nextInputIndex = (this.activeVideoInputIndex + increment) %
440
+ this.availableVideoInputs.length;
441
+ this.switchToVideoInput(this.availableVideoInputs[nextInputIndex].deviceId);
442
+ }
443
+ }
444
+ /**
445
+ * Switches the camera-view to the specified video device
446
+ */
447
+ switchToVideoInput(deviceId) {
448
+ // if(deviceId){
449
+ this.videoInitialized = false;
450
+ this.stopMediaTracks();
451
+ this.initWebcam(deviceId, this.videoOptions);
452
+ // }
453
+ }
454
+ /**
455
+ * Event-handler for video resize event.
456
+ * Triggers Angular change detection so that new video dimensions get applied
457
+ */
458
+ videoResize() {
459
+ // here to trigger Angular change detection
460
+ }
461
+ get videoWidth() {
462
+ const videoRatio = this.getVideoAspectRatio();
463
+ return Math.min(this.width, this.height * videoRatio);
464
+ }
465
+ get videoHeight() {
466
+ const videoRatio = this.getVideoAspectRatio();
467
+ return Math.min(this.height, this.width / videoRatio);
468
+ }
469
+ get videoStyleClasses() {
470
+ let classes = '';
471
+ if (this.isMirrorImage()) {
472
+ classes += 'mirrored ';
473
+ }
474
+ return classes.trim();
475
+ }
476
+ get nativeVideoElement() {
477
+ return this.video.nativeElement;
478
+ }
479
+ // public get smallVideoElement() {
480
+ // return this.videoSmall;
481
+ // }
482
+ /**
483
+ * Returns the video aspect ratio of the active video stream
484
+ */
485
+ getVideoAspectRatio() {
486
+ // calculate ratio from video element dimensions if present
487
+ const videoElement = this.nativeVideoElement;
488
+ if (videoElement.videoWidth &&
489
+ videoElement.videoWidth > 0 &&
490
+ videoElement.videoHeight &&
491
+ videoElement.videoHeight > 0) {
492
+ return videoElement.videoWidth / videoElement.videoHeight;
493
+ }
494
+ // nothing present - calculate ratio based on width/height params
495
+ return this.width / this.height;
496
+ }
497
+ updateSize() {
498
+ const track = this.mediaStream?.getTracks()[0];
499
+ if (track) {
500
+ let desired = {
501
+ width: {
502
+ ideal: 0,
503
+ },
504
+ height: {
505
+ ideal: 0,
506
+ },
507
+ // facingMode:'user',
508
+ frameRate: { min: 20, ideal: 24, max: 24 },
509
+ };
510
+ if (typeof track.getCapabilities === 'function') {
511
+ const { width, height } = track.getCapabilities();
512
+ desired = {
513
+ width: {
514
+ ideal: this.landscape && this.isMobile ? height?.max : width?.max,
515
+ },
516
+ height: {
517
+ ideal: this.landscape && this.isMobile ? width?.max : height?.max,
518
+ },
519
+ // facingMode:'user',
520
+ frameRate: { min: 20, ideal: 24, max: 24 },
521
+ };
522
+ }
523
+ else {
524
+ desired = {
525
+ width: {
526
+ ideal: 1920,
527
+ },
528
+ height: {
529
+ ideal: 1080,
530
+ },
531
+ // facingMode:'user',
532
+ frameRate: { min: 20, ideal: 30, max: 31 },
533
+ };
534
+ }
535
+ if (desired.height.ideal && desired.height.ideal >= 1600) {
536
+ desired.height.ideal = 1600;
537
+ desired.width.ideal = 1600;
538
+ }
539
+ if (this.platform.ANDROID) {
540
+ //desired.width.ideal = 2160;
541
+ //desired.height.ideal = 2160;
542
+ // if (!this.landscape) {
543
+ // } else {
544
+ // desired.width.ideal = width?.max;
545
+ // desired.height.ideal = height?.max;
546
+ // }
547
+ }
548
+ track.applyConstraints(desired);
549
+ //track.getSettings().facingMode!=='user';
550
+ this.videoSize = {
551
+ height: this.landscape
552
+ ? track.getSettings().height
553
+ : track.getSettings().width,
554
+ width: this.landscape
555
+ ? track.getSettings().width
556
+ : track.getSettings().height,
557
+ };
558
+ this.cd.detectChanges();
559
+ }
560
+ }
561
+ getStreamTrack(stream) {
562
+ return stream.getVideoTracks()[0];
563
+ }
564
+ getTrackSettings() { }
565
+ accesVideoTrack(videoTrackConstraints) {
566
+ return from(navigator.mediaDevices.getUserMedia(videoTrackConstraints)).pipe(switchMap((stream) => {
567
+ // default resolution 1280x720, check max resolution
568
+ const track = this.getStreamTrack(stream);
569
+ const capabilities = track.getCapabilities();
570
+ const { facingMode, height, width } = capabilities;
571
+ const desired = {
572
+ width: {
573
+ min: this.landscape && this.isMobile ? height?.max : width?.max,
574
+ },
575
+ // height: {
576
+ // exact: this.landscape && this.isMobile ? width?.max : height?.max,
577
+ // },
578
+ // facingMode:'en',
579
+ // frameRate: { min: 25, ideal: 30, max: 31 },
580
+ };
581
+ // get max width
582
+ const { width: sWidth, height: sHeight } = track.getSettings();
583
+ if (desired.width.min != sWidth) {
584
+ return this.accesVideoTrack({ video: desired });
585
+ }
586
+ //return this.accesVideoTrack({video:desired});
587
+ return of(stream);
588
+ }));
589
+ }
590
+ drawRectangle() {
591
+ const _canvas = this.canvas.nativeElement;
592
+ const ctx = _canvas.getContext('2d');
593
+ ctx.clearRect(0, 0, _canvas.width, _canvas.height);
594
+ // ctx.drawImage(_video, 0, 0, _canvas.width, _canvas.height);
595
+ const { padding, top, rWidth, rHeight } = this.cardRectangle;
596
+ ctx.strokeStyle = 'red';
597
+ ctx.strokeRect(padding, top, rWidth, rHeight);
598
+ }
599
+ getMaxAvailableResolution() { }
600
+ /**
601
+ * Init webcam live view
602
+ */
603
+ initWebcam(deviceId, userVideoTrackConstraints) {
604
+ const _video = this.nativeVideoElement;
605
+ // const videoStreamer = this.videoStreamer.nativeElement;
606
+ // const videoSmall = document.createElement('video');
607
+ if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
608
+ // merge deviceId -> userVideoTrackConstraints
609
+ const videoTrackConstraints = WebcamComponent.getMediaConstraintsForDevice(deviceId, userVideoTrackConstraints);
610
+ // // if (deviceId) {
611
+ // this.accesVideoTrack({ video: videoTrackConstraints }).subscribe(
612
+ // (stream: MediaStream) => {
613
+ // console.log(
614
+ // 'VALID SETTINGS',
615
+ // stream.getVideoTracks()[0].getSettings()
616
+ // );
617
+ // }
618
+ // );
619
+ // }
620
+ if (this.platform.ANDROID) {
621
+ videoTrackConstraints.width = 1600;
622
+ videoTrackConstraints.height = 1600;
623
+ }
624
+ const constraints = {
625
+ exact: deviceId,
626
+ width: { min: 480, ideal: 1280 },
627
+ height: { min: 480, ideal: 720 },
628
+ // aspectRatio: 3 / 2,
629
+ frameRate: { min: 20 },
630
+ };
631
+ navigator.mediaDevices
632
+ .getUserMedia({ video: videoTrackConstraints })
633
+ .then((stream) => {
634
+ this.mediaStream = stream;
635
+ _video.srcObject = stream;
636
+ this.updateSize();
637
+ this.updatecanvasSize();
638
+ _video.play();
639
+ _video.onplay = () => {
640
+ this.setActiveCamera(stream);
641
+ this.drawRectangle();
642
+ };
643
+ })
644
+ .catch((err) => {
645
+ console.log(err);
646
+ this.initError.next({
647
+ message: err.message,
648
+ mediaStreamError: err,
649
+ });
650
+ });
651
+ }
652
+ else {
653
+ this.initError.next({
654
+ message: 'Cannot read UserMedia from MediaDevices.',
655
+ });
656
+ }
657
+ }
658
+ get isMobile() {
659
+ return this.platform.ANDROID || this.platform.IOS;
660
+ }
661
+ get cardRectangle() {
662
+ const _canvas = this.canvas.nativeElement;
663
+ const docSize = this.type === 'selfie' ? 1 : 86 / 55;
664
+ let padding = 10;
665
+ let rWidth = _canvas.width - 2 * padding;
666
+ let rHeight = rWidth / docSize;
667
+ let top = (_canvas.height - rHeight) / 2;
668
+ if (!this.isMobile) {
669
+ padding = 40;
670
+ rHeight = _canvas.height - 2 * padding;
671
+ rWidth = rHeight * docSize;
672
+ top = (_canvas.height - rHeight) / 2;
673
+ padding = (_canvas.width - rWidth) / 2;
674
+ }
675
+ return { padding, top, rWidth, rHeight };
676
+ }
677
+ get snapRectangle() {
678
+ const _canvas = this.canvas.nativeElement;
679
+ const ar = this.videoSize.width / _canvas.width;
680
+ let { padding, top, rWidth, rHeight } = this.cardRectangle;
681
+ padding = padding * ar;
682
+ top = top * ar;
683
+ rWidth = rWidth * ar;
684
+ rHeight = rHeight * ar;
685
+ return { padding, top, rWidth, rHeight };
686
+ }
687
+ setActiveCamera(stream) {
688
+ this.videoReady.next(false);
689
+ this.showVideo = false;
690
+ this.activeVideoSettings = stream.getVideoTracks()[0].getSettings();
691
+ const activeDeviceId = WebcamComponent.getDeviceIdFromMediaStreamTrack(stream.getVideoTracks()[0]);
692
+ const videoTrack = stream.getTracks()[0];
693
+ this.trackSettings = videoTrack.getSettings();
694
+ this.cameraSwitched.next(activeDeviceId);
695
+ setTimeout(() => {
696
+ this.zone.run(() => {
697
+ this.resizeStage();
698
+ this.showVideo = true;
699
+ this.videoReady.next(true);
700
+ if (MediaStreamTrackProcessor) {
701
+ this.trackProcessor = new MediaStreamTrackProcessor(videoTrack);
702
+ let frameStream = this.trackProcessor.readable;
703
+ if (!this.shutdown) {
704
+ this.worker?.postMessage({
705
+ type: 'start',
706
+ frameStream: frameStream,
707
+ trackSettings: this.trackSettings,
708
+ }, [frameStream]);
709
+ }
710
+ }
711
+ });
712
+ }, 500);
713
+ }
714
+ getActiveVideoTrack() {
715
+ return this.mediaStream ? this.mediaStream.getVideoTracks()[0] : null;
716
+ }
717
+ isMirrorImage() {
718
+ if (!this.getActiveVideoTrack()) {
719
+ return false;
720
+ }
721
+ // check for explicit mirror override parameter
722
+ {
723
+ let mirror = 'auto';
724
+ if (this.mirrorImage) {
725
+ if (typeof this.mirrorImage === 'string') {
726
+ mirror = String(this.mirrorImage).toLowerCase();
727
+ }
728
+ else {
729
+ // WebcamMirrorProperties
730
+ if (this.mirrorImage.x) {
731
+ mirror = this.mirrorImage.x.toLowerCase();
732
+ }
733
+ }
734
+ }
735
+ switch (mirror) {
736
+ case 'always':
737
+ return true;
738
+ case 'never':
739
+ return false;
740
+ }
741
+ }
742
+ // default: enable mirroring if webcam is user facing
743
+ return WebcamComponent.isUserFacing(this.getActiveVideoTrack());
744
+ }
745
+ /**
746
+ * Stops all active media tracks.
747
+ * This prevents the webcam from being indicated as active,
748
+ * even if it is no longer used by this component.
749
+ */
750
+ stopMediaTracks() {
751
+ // this.video.nativeElement.pause();
752
+ if (this.video.nativeElement.srcObject) {
753
+ this.video.nativeElement.srcObject
754
+ .getTracks()
755
+ .forEach((track) => {
756
+ track.stop();
757
+ });
758
+ this.video.nativeElement.srcObject = null;
759
+ this.video.nativeElement.src = '';
760
+ }
761
+ if (this.mediaStream && this.mediaStream.getTracks) {
762
+ // getTracks() returns all media tracks (video+audio)
763
+ this.mediaStream
764
+ .getTracks()
765
+ .forEach((track) => track.stop());
766
+ }
767
+ }
768
+ /**
769
+ * Unsubscribe from all open subscriptions
770
+ */
771
+ unsubscribeFromSubscriptions() {
772
+ if (this.triggerSubscription) {
773
+ this.triggerSubscription.unsubscribe();
774
+ }
775
+ if (this.switchCameraSubscription) {
776
+ this.switchCameraSubscription.unsubscribe();
777
+ }
778
+ }
779
+ /**
780
+ * Reads available input devices
781
+ */
782
+ detectAvailableDevices() {
783
+ return new Promise((resolve, reject) => {
784
+ WebcamUtil.getAvailableVideoInputs().subscribe((devices) => {
785
+ this.availableVideoInputs = devices;
786
+ resolve(devices);
787
+ }, (err) => {
788
+ this.availableVideoInputs = [];
789
+ reject(err);
790
+ });
791
+ });
792
+ }
793
+ }
794
+ WebcamComponent.DEFAULT_VIDEO_OPTIONS = {
795
+ facingMode: 'environment',
796
+ };
797
+ WebcamComponent.DEFAULT_IMAGE_TYPE = 'image/jpeg';
798
+ WebcamComponent.DEFAULT_IMAGE_QUALITY = 1;
799
+ WebcamComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: WebcamComponent, deps: [{ token: i1.BreakpointObserver }, { token: i2.Platform }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
800
+ WebcamComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: WebcamComponent, selector: "app-webcam", inputs: { imageHandler: "imageHandler", id: "id", type: "type", width: "width", height: "height", videoOptions: "videoOptions", allowCameraSwitch: "allowCameraSwitch", mirrorImage: "mirrorImage", captureImageData: "captureImageData", imageType: "imageType", imageQuality: "imageQuality", trigger: "trigger", switchCamera: "switchCamera" }, outputs: { imageCapture: "imageCapture", initError: "initError", imageClick: "imageClick", cameraSwitched: "cameraSwitched", videoReady: "videoReady", destroyed: "destroyed" }, host: { listeners: { "window:resize": "onResize($event)" } }, viewQueries: [{ propertyName: "video", first: true, predicate: ["video"], descendants: true, static: true }, { propertyName: "videoStreamer", first: true, predicate: ["videoStreamer"], descendants: true, static: true }, { propertyName: "canvas", first: true, predicate: ["canvas"], descendants: true, static: true }, { propertyName: "canvasSnapshot", first: true, predicate: ["canvasSnapshot"], descendants: true, static: true }, { propertyName: "canvasResize", first: true, predicate: ["canvasResize"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"webcam-wrapper\">\n <div>\n <video\n #video\n autoplay\n muted\n style=\"display: block\"\n playsinline\n\n ></video>\n\n <div class=\"rectangle\">\n <canvas\n #canvas\n [ngStyle]=\"{ visibility: showVideo ? 'visible' : 'hidden' }\"\n [width]=\"canvasSize.width\"\n [height]=\"canvasSize.height\"\n ></canvas>\n </div>\n </div>\n</div>\n", styles: [":host{display:flex;flex-direction:row;flex:1;transform:transale3d(0,0,0);background-color:#000}.webcam-wrapper{display:flex;flex-direction:row;align-items:center;flex:1;justify-content:center}.webcam-wrapper canvas{transform:transale3d(0,0,0);display:block;position:relative;z-index:20;left:0;top:0}.webcam-wrapper .rectangle{position:absolute;left:0;top:0;display:flex;flex-direction:row;align-items:center;justify-content:center;width:100%;height:100%}\n"], dependencies: [{ kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
801
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: WebcamComponent, decorators: [{
802
+ type: Component,
803
+ args: [{ selector: 'app-webcam', template: "<div class=\"webcam-wrapper\">\n <div>\n <video\n #video\n autoplay\n muted\n style=\"display: block\"\n playsinline\n\n ></video>\n\n <div class=\"rectangle\">\n <canvas\n #canvas\n [ngStyle]=\"{ visibility: showVideo ? 'visible' : 'hidden' }\"\n [width]=\"canvasSize.width\"\n [height]=\"canvasSize.height\"\n ></canvas>\n </div>\n </div>\n</div>\n", styles: [":host{display:flex;flex-direction:row;flex:1;transform:transale3d(0,0,0);background-color:#000}.webcam-wrapper{display:flex;flex-direction:row;align-items:center;flex:1;justify-content:center}.webcam-wrapper canvas{transform:transale3d(0,0,0);display:block;position:relative;z-index:20;left:0;top:0}.webcam-wrapper .rectangle{position:absolute;left:0;top:0;display:flex;flex-direction:row;align-items:center;justify-content:center;width:100%;height:100%}\n"] }]
804
+ }], ctorParameters: function () { return [{ type: i1.BreakpointObserver }, { type: i2.Platform }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }]; }, propDecorators: { imageHandler: [{
805
+ type: Input
806
+ }], id: [{
807
+ type: Input
808
+ }], type: [{
809
+ type: Input
810
+ }], width: [{
811
+ type: Input
812
+ }], height: [{
813
+ type: Input
814
+ }], videoOptions: [{
815
+ type: Input
816
+ }], allowCameraSwitch: [{
817
+ type: Input
818
+ }], mirrorImage: [{
819
+ type: Input
820
+ }], captureImageData: [{
821
+ type: Input
822
+ }], imageType: [{
823
+ type: Input
824
+ }], imageQuality: [{
825
+ type: Input
826
+ }], imageCapture: [{
827
+ type: Output
828
+ }], initError: [{
829
+ type: Output
830
+ }], imageClick: [{
831
+ type: Output
832
+ }], cameraSwitched: [{
833
+ type: Output
834
+ }], videoReady: [{
835
+ type: Output
836
+ }], destroyed: [{
837
+ type: Output
838
+ }], video: [{
839
+ type: ViewChild,
840
+ args: ['video', { static: true }]
841
+ }], videoStreamer: [{
842
+ type: ViewChild,
843
+ args: ['videoStreamer', { static: true }]
844
+ }], canvas: [{
845
+ type: ViewChild,
846
+ args: ['canvas', { static: true }]
847
+ }], canvasSnapshot: [{
848
+ type: ViewChild,
849
+ args: ['canvasSnapshot', { static: true }]
850
+ }], canvasResize: [{
851
+ type: ViewChild,
852
+ args: ['canvasResize', { static: true }]
853
+ }], trigger: [{
854
+ type: Input
855
+ }], switchCamera: [{
856
+ type: Input
857
+ }], onResize: [{
858
+ type: HostListener,
859
+ args: ['window:resize', ['$event']]
860
+ }] } });
861
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViY2FtLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1zY2FuZG9jL3NyYy9jb3JlL2NvbXBvbmVudHMvd2ViY2FtL3dlYmNhbS93ZWJjYW0uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXNjYW5kb2Mvc3JjL2NvcmUvY29tcG9uZW50cy93ZWJjYW0vd2ViY2FtL3dlYmNhbS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBR0wsU0FBUyxFQUNULFlBQVksRUFDWixZQUFZLEVBQ1osS0FBSyxFQUdMLE1BQU0sRUFDTixTQUFTLEdBQ1YsTUFBTSxlQUFlLENBQUM7QUFFdkIsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3JELE9BQU8sRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBeUIsTUFBTSxNQUFNLENBQUM7QUFDbkUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRWpELE9BQU8sRUFFTCxXQUFXLEdBRVosTUFBTSxxQkFBcUIsQ0FBQztBQUU3QixPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDM0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHFCQUFxQixDQUFDOzs7OztBQVNqRCxNQUFNLE9BQU8sZUFBZTtJQXNIMUIsWUFDUyxrQkFBc0MsRUFDdEMsUUFBa0IsRUFDakIsRUFBcUIsRUFDckIsSUFBWTtRQUhiLHVCQUFrQixHQUFsQixrQkFBa0IsQ0FBb0I7UUFDdEMsYUFBUSxHQUFSLFFBQVEsQ0FBVTtRQUNqQixPQUFFLEdBQUYsRUFBRSxDQUFtQjtRQUNyQixTQUFJLEdBQUosSUFBSSxDQUFRO1FBNUd0QixxREFBcUQ7UUFDckMsVUFBSyxHQUFXLEdBQUcsQ0FBQztRQUNwQyxzREFBc0Q7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QkFEUCxZQUFZO3VCQUFDLGVBQWUsRUFBRSxDQUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEFmdGVyVmlld0luaXQsXG4gIENoYW5nZURldGVjdG9yUmVmLFxuICBDb21wb25lbnQsXG4gIEV2ZW50RW1pdHRlcixcbiAgSG9zdExpc3RlbmVyLFxuICBJbnB1dCxcbiAgTmdab25lLFxuICBPbkRlc3Ryb3ksXG4gIE91dHB1dCxcbiAgVmlld0NoaWxkLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFdlYmNhbUluaXRFcnJvciB9IGZyb20gJy4uL2RvbWFpbi93ZWJjYW0taW5pdC1lcnJvcic7XG5pbXBvcnQgeyBXZWJjYW1JbWFnZSB9IGZyb20gJy4uL2RvbWFpbi93ZWJjYW0taW1hZ2UnO1xuaW1wb3J0IHsgZnJvbSwgT2JzZXJ2YWJsZSwgb2YsIFN1YmplY3QsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgV2ViY2FtVXRpbCB9IGZyb20gJy4uL3V0aWwvd2ViY2FtLnV0aWwnO1xuaW1wb3J0IHsgV2ViY2FtTWlycm9yUHJvcGVydGllcyB9IGZyb20gJy4uL2RvbWFpbi93ZWJjYW0tbWlycm9yLXByb3BlcnRpZXMnO1xuaW1wb3J0IHtcbiAgQnJlYWtwb2ludE9ic2VydmVyLFxuICBCcmVha3BvaW50cyxcbiAgQnJlYWtwb2ludFN0YXRlLFxufSBmcm9tICdAYW5ndWxhci9jZGsvbGF5b3V0JztcbmltcG9ydCB7IFBsYXRmb3JtIH0gZnJvbSAnQGFuZ3VsYXIvY2RrL3BsYXRmb3JtJztcbmltcG9ydCB7IHN3aXRjaE1hcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IHdvcmtlcnRleHQgfSBmcm9tICcuLi8uLi8uLi9hcHAud29ya2VyJztcblxuZGVjbGFyZSB2YXIgTWVkaWFTdHJlYW1UcmFja1Byb2Nlc3NvcjogYW55O1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdhcHAtd2ViY2FtJyxcbiAgdGVtcGxhdGVVcmw6ICcuL3dlYmNhbS5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3dlYmNhbS5jb21wb25lbnQuc2NzcyddLFxufSlcbmV4cG9ydCBjbGFzcyBXZWJjYW1Db21wb25lbnQgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3kge1xuICB0cmFja1Byb2Nlc3NvcjogYW55O1xuICB0cmFja1NldHRpbmdzOiBhbnk7XG5cbiAgQElucHV0KCkgaW1hZ2VIYW5kbGVyITogU3ViamVjdDxhbnk+O1xuXG4gIHByaXZhdGUgc3RhdGljIERFRkFVTFRfVklERU9fT1BUSU9OUzogTWVkaWFUcmFja0NvbnN0cmFpbnRzID0ge1xuICAgIGZhY2luZ01vZGU6ICdlbnZpcm9ubWVudCcsXG4gIH07XG4gIHByaXZhdGUgc3RhdGljIERFRkFVTFRfSU1BR0VfVFlQRTogc3RyaW5nID0gJ2ltYWdlL2pwZWcnO1xuICBwcml2YXRlIHN0YXRpYyBERUZBVUxUX0lNQUdFX1FVQUxJVFk6IG51bWJlciA9IDE7XG5cbiAgQElucHV0KCkgcHVibGljIGlkPzogYW55O1xuICBASW5wdXQoKSBwdWJsaWMgdHlwZT86ICdkb2N1bWVudCcgfCAnc2VsZmllJztcbiAgLyoqIERlZmluZXMgdGhlIG1heCB3aWR0aCBvZiB0aGUgd2ViY2FtIGFyZWEgaW4gcHggKi9cbiAgQElucHV0KCkgcHVibGljIHdpZHRoOiBudW1iZXIgPSA2NDA7XG4gIC8qKiBEZWZpbmVzIHRoZSBtYXggaGVpZ2h0IG9mIHRoZSB3ZWJjYW0gYXJlYSBpbiBweCAqL1xuICBASW5wdXQoKSBwdWJsaWMgaGVpZ2h0OiBudW1iZXIgPSA0ODA7XG4gIC8qKiBEZWZpbmVzIGJhc2UgY29uc3RyYWludHMgdG8gYXBwbHkgd2hlbiByZXF1ZXN0aW5nIHZpZGVvIHRyYWNrIGZyb20gVXNlck1lZGlhICovXG4gIEBJbnB1dCgpIHB1YmxpYyB2aWRlb09wdGlvbnM6IE1lZGlhVHJhY2tDb25zdHJhaW50cyA9XG4gICAgV2ViY2FtQ29tcG9uZW50LkRFRkFVTFRfVklERU9fT1BUSU9OUztcbiAgLyoqIEZsYWcgdG8gZW5hYmxlL2Rpc2FibGUgY2FtZXJhIHN3aXRjaC4gSWYgZW5hYmxlZCwgYSBzd2l0Y2ggaWNvbiB3aWxsIGJlIGRpc3BsYXllZCBpZiBtdWx0aXBsZSBjYW1lcmFzIHdlcmUgZm91bmQgKi9cbiAgQElucHV0KCkgcHVibGljIGFsbG93Q2FtZXJhU3dpdGNoOiBib29sZWFuID0gdHJ1ZTtcbiAgLyoqIFBhcmFtZXRlciB0byBjb250cm9sIGltYWdlIG1pcnJvcmluZyAoaS5lLiBmb3IgdXNlci1mYWNpbmcgY2FtZXJhKS4gW1wiYXV0b1wiLCBcImFsd2F5c1wiLCBcIm5ldmVyXCJdICovXG4gIEBJbnB1dCgpIHB1YmxpYyBtaXJyb3JJbWFnZT86IHN0cmluZyB8IFdlYmNhbU1pcnJvclByb3BlcnRpZXM7XG4gIC8qKiBGbGFnIHRvIGNvbnRyb2wgd2hldGhlciBhbiBJbWFnZURhdGEgb2JqZWN0IGlzIHN0b3JlZCBpbnRvIHRoZSBXZWJjYW1JbWFnZSBvYmplY3QuICovXG4gIEBJbnB1dCgpIHB1YmxpYyBjYXB0dXJlSW1hZ2VEYXRhOiBib29sZWFuID0gZmFsc2U7XG4gIC8qKiBUaGUgaW1hZ2UgdHlwZSB0byB1c2Ugd2hlbiBjYXB0dXJpbmcgc25hcHNob3RzICovXG4gIEBJbnB1dCgpIHB1YmxpYyBpbWFnZVR5cGU6IHN0cmluZyA9IFdlYmNhbUNvbXBvbmVudC5ERUZBVUxUX0lNQUdFX1RZUEU7XG4gIC8qKiBUaGUgaW1hZ2UgcXVhbGl0eSB0byB1c2Ugd2hlbiBjYXB0dXJpbmcgc25hcHNob3RzIChudW1iZXIgYmV0d2VlbiAwIGFuZCAxKSAqL1xuICBASW5wdXQoKSBwdWJsaWMgaW1hZ2VRdWFsaXR5OiBudW1iZXIgPSBXZWJjYW1Db21wb25lbnQuREVGQVVMVF9JTUFHRV9RVUFMSVRZO1xuXG4gIC8qKiBFdmVudEVtaXR0ZXIgd2hpY2ggZmlyZXMgd2hlbiBhbiBpbWFnZSBoYXMgYmVlbiBjYXB0dXJlZCAqL1xuICBAT3V0cHV0KCkgcHVibGljIGltYWdlQ2FwdHVyZTogRXZlbnRFbWl0dGVyPFdlYmNhbUltYWdlPiA9XG4gICAgbmV3IEV2ZW50RW1pdHRlcjxXZWJjYW1JbWFnZT4oKTtcbiAgLyoqIEVtaXRzIGEgbWVkaWFFcnJvciBpZiB3ZWJjYW0gY2Fubm90IGJlIGluaXRpYWxpemVkIChlLmcuIG1pc3NpbmcgdXNlciBwZXJtaXNzaW9ucykgKi9cbiAgQE91dHB1dCgpIHB1YmxpYyBpbml0RXJyb3I6IEV2ZW50RW1pdHRlcjxXZWJjYW1Jbml0RXJyb3I+ID1cbiAgICBuZXcgRXZlbnRFbWl0dGVyPFdlYmNhbUluaXRFcnJvcj4oKTtcbiAgLyoqIEVtaXRzIHdoZW4gdGhlIHdlYmNhbSB2aWRlbyB3YXMgY2xpY2tlZCAqL1xuICBAT3V0cHV0KCkgcHVibGljIGltYWdlQ2xpY2s6IEV2ZW50RW1pdHRlcjx2b2lkPiA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcbiAgLyoqIEVtaXRzIHRoZSBhY3RpdmUgZGV2aWNlSWQgYWZ0ZXIgdGhlIGFjdGl2ZSB2aWRlbyBkZXZpY2Ugd2FzIHN3aXRjaGVkICovXG4gIEBPdXRwdXQoKSBwdWJsaWMgY2FtZXJhU3dpdGNoZWQ6IEV2ZW50RW1pdHRlcjxzdHJpbmc+ID1cbiAgICBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcblxuICBAT3V0cHV0KCkgcHVibGljIHZpZGVvUmVhZHk6IEV2ZW50RW1pdHRlcjxib29sZWFuPiA9XG4gICAgbmV3IEV2ZW50RW1pdHRlcjxib29sZWFuPigpO1xuICBzaG93VmlkZW8gPSBmYWxzZTtcbiAgQE91dHB1dCgpIGRlc3Ryb3llZCA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICAvKiogYXZhaWxhYmxlIHZpZGVvIGRldmljZXMgKi9cbiAgcHVibGljIGF2YWlsYWJsZVZpZGVvSW5wdXRzOiBNZWRpYURldmljZUluZm9bXSA9IFtdO1xuXG4gIC8qKiBJbmRpY2F0ZXMgd2hldGhlciB0aGUgdmlkZW8gZGV2aWNlIGlzIHJlYWR5IHRvIGJlIHN3aXRjaGVkICovXG4gIHB1YmxpYyB2aWRlb0luaXRpYWxpemVkOiBib29sZWFuID0gZmFsc2U7XG5cbiAgY2FudmFzRWwgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcblxuICAvKiogSWYgdGhlIE9ic2VydmFibGUgcmVwcmVzZW50ZWQgYnkgdGhpcyBzdWJzY3JpcHRpb24gZW1pdHMsIGFuIGltYWdlIHdpbGwgYmUgY2FwdHVyZWQgYW5kIGVtaXR0ZWQgdGhyb3VnaFxuICAgKiB0aGUgJ2ltYWdlQ2FwdHVyZScgRXZlbnRFbWl0dGVyICovXG4gIHByaXZhdGUgdHJpZ2dlclN1YnNjcmlwdGlvbj86IFN1YnNjcmlwdGlvbjtcbiAgLyoqIEluZGV4IG9mIGFjdGl2ZSB2aWRlbyBpbiBhdmFpbGFibGVWaWRlb0lucHV0cyAqL1xuICBwcml2YXRlIGFjdGl2ZVZpZGVvSW5wdXRJbmRleDogbnVtYmVyID0gLTE7XG4gIC8qKiBTdWJzY3JpcHRpb24gdG8gc3dpdGNoQ2FtZXJhIGV2ZW50cyAqL1xuICBwcml2YXRlIHN3aXRjaENhbWVyYVN1YnNjcmlwdGlvbj86IFN1YnNjcmlwdGlvbjtcbiAgLyoqIE1lZGlhU3RyZWFtIG9iamVjdCBpbiB1c2UgZm9yIHN0cmVhbWluZyBVc2VyTWVkaWEgZGF0YSAqL1xuICBwcml2YXRlIG1lZGlhU3RyZWFtOiBNZWRpYVN0cmVhbSB8IG51bGwgPSBudWxsO1xuICAvLyBPcmlnaW5hbCB2aWRlb1xuICBAVmlld0NoaWxkKCd2aWRlbycsIHsgc3RhdGljOiB0cnVlIH0pIHByaXZhdGUgdmlkZW86IGFueTtcbiAgLy8gQWRqdXN0ZWQgZm9yIFVJXG4gIEBWaWV3Q2hpbGQoJ3ZpZGVvU3RyZWFtZXInLCB7IHN0YXRpYzogdHJ1ZSB9KSBwcml2YXRlIHZpZGVvU3RyZWFtZXI6IGFueTtcblxuICAvL0BWaWV3Q2hpbGQoJ3ZpZGVvU21hbGwnLCB7IHN0YXRpYzogdHJ1ZSB9KSBwcml2YXRlIHZpZGVvU21hbGw6IGFueTtcbiAgLy92aWRlb1NtYWxsOiBIVE1MVmlkZW9FbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndmlkZW8nKTtcbiAgLyoqIENhbnZhcyBmb3IgVmlkZW8gU25hcHNob3RzICovXG4gIEBWaWV3Q2hpbGQoJ2NhbnZhcycsIHsgc3RhdGljOiB0cnVlIH0pIHByaXZhdGUgY2FudmFzOiBhbnk7XG5cbiAgLyoqIENhbnZhcyBmb3IgVmlkZW8gU25hcHNob3RzICovXG4gIEBWaWV3Q2hpbGQoJ2NhbnZhc1NuYXBzaG90JywgeyBzdGF0aWM6IHRydWUgfSkgcHJpdmF0ZSBjYW52YXNTbmFwc2hvdDogYW55O1xuXG4gIEBWaWV3Q2hpbGQoJ2NhbnZhc1Jlc2l6ZScsIHsgc3RhdGljOiB0cnVlIH0pIHByaXZhdGUgY2FudmFzUmVzaXplOiBhbnk7XG4gIC8qKiB3aWR0aCBhbmQgaGVpZ2h0IG9mIHRoZSBhY3RpdmUgdmlkZW8gc3RyZWFtICovXG4gIGFjdGl2ZVZpZGVvU2V0dGluZ3M6IGFueTtcblxuICBzaHV0ZG93biA9IGZhbHNlO1xuICBwcml2YXRlIGNhblN0YXJ0ID0gdHJ1ZTtcbiAgdmlkZW9TaXplOiBhbnkgPSB7IHdpZHRoOiAxOTIwLCBoZWlnaHQ6IDEwODAgfTtcbiAgY2FudmFzU2l6ZTogYW55ID0geyB3aWR0aDogMTI4MCwgaGVpZ2h0OiA3MjAgfTtcblxuICB3b3JrZXI/OiBXb3JrZXI7XG4gIC8qKlxuICAgKiBJZiB0aGUgZ2l2ZW4gT2JzZXJ2YWJsZSBlbWl0cywgYW4gaW1hZ2Ugd2lsbCBiZSBjYXB0dXJlZCBhbmQgZW1pdHRlZCB0aHJvdWdoICdpbWFnZUNhcHR1cmUnIEV2ZW50RW1pdHRlclxuICAgKi9cbiAgQElucHV0KClcbiAgcHVibGljIHNldCB0cmlnZ2VyKHRyaWdnZXI6IE9ic2VydmFibGU8bnVtYmVyPikge1xuICAgIGlmICh0aGlzLnRyaWdnZXJTdWJzY3JpcHRpb24pIHtcbiAgICAgIHRoaXMudHJpZ2dlclN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgIH1cblxuICAgIC8vIFN1YnNjcmliZSB0byBldmVudHMgZnJvbSB0aGlzIE9ic2VydmFibGUgdG8gdGFrZSBzbmFwc2hvdHNcbiAgICB0aGlzLnRyaWdnZXJTdWJzY3JpcHRpb24gPSB0cmlnZ2VyLnN1YnNjcmliZSgodGltZSkgPT4ge1xuICAgICAgdGhpcy50YWtlU25hcHNob3QodGltZSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogSWYgdGhlIGdpdmVuIE9ic2VydmFibGUgZW1pdHMsIHRoZSBhY3RpdmUgd2ViY2FtIHdpbGwgYmUgc3dpdGNoZWQgdG8gdGhlIG9uZSBpbmRpY2F0ZWQgYnkgdGhlIGVtaXR0ZWQgdmFsdWUuXG4gICAqIEBwYXJhbSBzd2l0Y2hDYW1lcmEgSW5kaWNhdGVzIHdoaWNoIHdlYmNhbSB0byBzd2l0Y2ggdG9cbiAgICogICB0cnVlOiBjeWNsZSBmb3J3YXJkcyB0aHJvdWdoIGF2YWlsYWJsZSB3ZWJjYW1zXG4gICAqICAgZmFsc2U6IGN5Y2xlIGJhY2t3YXJkcyB0aHJvdWdoIGF2YWlsYWJsZSB3ZWJjYW1zXG4gICAqICAgc3RyaW5nOiBhY3RpdmF0ZSB0aGUgd2ViY2FtIHdpdGggdGhlIGdpdmVuIGlkXG4gICAqL1xuICBASW5wdXQoKSBzd2l0Y2hDYW1lcmE6IGFueTtcblxuICBASG9zdExpc3RlbmVyKCd3aW5kb3c6cmVzaXplJywgWyckZXZlbnQnXSlcbiAgb25SZXNpemUoKSB7XG4gICAgdGhpcy52aWRlb1JlYWR5Lm5leHQoZmFsc2UpO1xuICAgIHRoaXMucmVzaXplU3RhZ2UoKTtcbiAgfVxuICBjb25zdHJ1Y3RvcihcbiAgICBwdWJsaWMgYnJlYWtwb2ludE9ic2VydmVyOiBCcmVha3BvaW50T2JzZXJ2ZXIsXG4gICAgcHVibGljIHBsYXRmb3JtOiBQbGF0Zm9ybSxcbiAgICBwcml2YXRlIGNkOiBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICBwcml2YXRlIHpvbmU6IE5nWm9uZVxuICApIHtcbiAgICAvLyBpZiAodHlwZW9mIFdvcmtlciAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAvLyAgIC8vIENyZWF0ZSBhIG5ld1xuICAgIC8vICAgdGhpcy53b3JrZXIgPSBuZXcgV29ya2VyKFxuICAgIC8vICAgICBuZXcgVVJMKCcuLy4uLy4uLy4uLy4uL2FwcC9hcHAud29ya2VyJywgaW1wb3J0Lm1ldGEudXJsKVxuICAgIC8vICAgKTtcbiAgICAvLyAgIHRoaXMud29ya2VyLm9ubWVzc2FnZSA9ICh7IGRhdGEgfSkgPT4ge1xuICAgIC8vICAgICBjb25zb2xlLmxvZyhgcGFnZSBnb3QgbWVzc2FnZTogJHtkYXRhfWApO1xuICAgIC8vICAgfTtcbiAgICAvLyAgIGNvbnNvbGUubG9nKCdQT1NUJyk7XG4gICAgLy8gICB0aGlzLndvcmtlci5wb3N0TWVzc2FnZSgnaGVsbG8nKTtcbiAgICAvLyB9IGVsc2Uge1xuICAgIC8vICAgLy8gV2ViIHdvcmtlcnMgYXJlIG5vdCBzdXBwb3J0ZWQgaW4gdGhpcyBlbnZpcm9ubWVudC5cbiAgICAvLyAgIC8vIFlvdSBzaG91bGQgYWRkIGEgZmFsbGJhY2sgc28gdGhhdCB5b3VyIHByb2dyYW0gc3RpbGwgZXhlY3V0ZXMgY29ycmVjdGx5LlxuICAgIC8vIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgTWVkaWFUcmFja0NvbnN0cmFpbnRzIHRvIHJlcXVlc3Qgc3RyZWFtaW5nIHRoZSBnaXZlbiBkZXZpY2VcbiAgICogQHBhcmFtIGRldmljZUlkXG4gICAqIEBwYXJhbSBiYXNlTWVkaWFUcmFja0NvbnN0cmFpbnRzIGJhc2UgY29uc3RyYWludHMgdG8gbWVyZ2UgZGV2aWNlSWQtY29uc3RyYWludCBpbnRvXG4gICAqIEByZXR1cm5zXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBnZXRNZWRpYUNvbnN0cmFpbnRzRm9yRGV2aWNlKFxuICAgIGRldmljZUlkOiBzdHJpbmcsXG4gICAgYmFzZU1lZGlhVHJhY2tDb25zdHJhaW50czogTWVkaWFUcmFja0NvbnN0cmFpbnRzXG4gICk6IE1lZGlhVHJhY2tDb25zdHJhaW50cyB7XG4gICAgY29uc3QgcmVzdWx0OiBNZWRpYVRyYWNrQ29uc3RyYWludHMgPSBiYXNlTWVkaWFUcmFja0NvbnN0cmFpbnRzXG4gICAgICA/IGJhc2VNZWRpYVRyYWNrQ29uc3RyYWludHNcbiAgICAgIDogdGhpcy5ERUZBVUxUX1ZJREVPX09QVElPTlM7XG4gICAgaWYgKGRldmljZUlkKSB7XG4gICAgICByZXN1bHQuZGV2aWNlSWQgPSB7IGV4YWN0OiBkZXZpY2VJZCB9O1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICogVHJpZXMgdG8gaGFydmVzdCB0aGUgZGV2aWNlSWQgZnJvbSB0aGUgZ2l2ZW4gbWVkaWFTdHJlYW1UcmFjayBvYmplY3QuXG4gICAqIEJyb3dzZXJzIHBvcHVsYXRlIHRoaXMgb2JqZWN0IGRpZmZlcmVudGx5OyB0aGlzIG1ldGhvZCB0cmllcyBzb21lIGRpZmZlcmVudCBhcHByb2FjaGVzXG4gICAqIHRvIHJlYWQgdGhlIGlkLlxuICAgKiBAcGFyYW0gbWVkaWFTdHJlYW1UcmFja1xuICAgKiBAcmV0dXJucyBkZXZpY2VJZCBpZiBmb3VuZCBpbiB0aGUgbWVkaWFTdHJlYW1UcmFja1xuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgZ2V0RGV2aWNlSWRGcm9tTWVkaWFTdHJlYW1UcmFjayhcbiAgICBtZWRpYVN0cmVhbVRyYWNrOiBNZWRpYVN0cmVhbVRyYWNrXG4gICk6IGFueSB7XG4gICAgaWYgKFxuICAgICAgbWVkaWFTdHJlYW1UcmFjay5nZXRTZXR0aW5ncyAmJlxuICAgICAgbWVkaWFTdHJlYW1UcmFjay5nZXRTZXR0aW5ncygpICYmXG4gICAgICBtZWRpYVN0cmVhbVRyYWNrLmdldFNldHRpbmdzKCkuZGV2aWNlSWRcbiAgICApIHtcbiAgICAgIHJldHVybiBtZWRpYVN0cmVhbVRyYWNrLmdldFNldHRpbmdzKCkuZGV2aWNlSWQ7XG4gICAgfSBlbHNlIGlmIChcbiAgICAgIG1lZGlhU3RyZWFtVHJhY2suZ2V0Q29uc3RyYWludHMgJiZcbiAgICAgIG1lZGlhU3RyZWFtVHJhY2suZ2V0Q29uc3RyYWludHMoKSAmJlxuICAgICAgbWVkaWFTdHJlYW1UcmFjay5nZXRDb25zdHJhaW50cygpLmRldmljZUlkXG4gICAgKSB7XG4gICAgICBjb25zdCBkZXZpY2VJZE9iajogYW55ID0gbWVkaWFTdHJlYW1UcmFjay5nZXRDb25zdHJhaW50cygpLmRldmljZUlkO1xuXG4gICAgICByZXR1cm4gV2ViY2FtQ29tcG9uZW50LmdldFZhbHVlRnJvbUNvbnN0cmFpbkRPTVN0cmluZyhkZXZpY2VJZE9iaik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRyaWVzIHRvIGhhcnZlc3QgdGhlIGZhY2luZ01vZGUgZnJvbSB0aGUgZ2l2ZW4gbWVkaWFTdHJlYW1UcmFjayBvYmplY3QuXG4gICAqIEJyb3dzZXJzIHBvcHVsYXRlIHRoaXMgb2JqZWN0IGRpZmZlcmVudGx5OyB0aGlzIG1ldGhvZCB0cmllcyBzb21lIGRpZmZlcmVudCBhcHByb2FjaGVzXG4gICAqIHRvIHJlYWQgdGhlIHZhbHVlLlxuICAgKiBAcGFyYW0gbWVkaWFTdHJlYW1UcmFja1xuICAgKiBAcmV0dXJucyBmYWNpbmdNb2RlIGlmIGZvdW5kIGluIHRoZSBtZWRpYVN0cmVhbVRyYWNrXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBnZXRGYWNpbmdNb2RlRnJvbU1lZGlhU3RyZWFtVHJhY2soXG4gICAgbWVkaWFTdHJlYW1UcmFjazogTWVkaWFTdHJlYW1UcmFja1xuICApOiBhbnkge1xuICAgIGlmIChtZWRpYVN0cmVhbVRyYWNrKSB7XG4gICAgICBpZiAoXG4gICAgICAgIG1lZGlhU3RyZWFtVHJhY2suZ2V0U2V0dGluZ3MgJiZcbiAgICAgICAgbWVkaWFTdHJlYW1UcmFjay5nZXRTZXR0aW5ncygpICYmXG4gICAgICAgIG1lZGlhU3RyZWFtVHJhY2suZ2V0U2V0dGluZ3MoKS5mYWNpbmdNb2RlXG4gICAgICApIHtcbiAgICAgICAgcmV0dXJuIG1lZGlhU3RyZWFtVHJhY2suZ2V0U2V0dGluZ3MoKS5mYWNpbmdNb2RlO1xuICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgbWVkaWFTdHJlYW1UcmFjay5nZXRDb25zdHJhaW50cyAmJlxuICAgICAgICBtZWRpYVN0cmVhbVRyYWNrLmdldENvbnN0cmFpbnRzKCkgJiZcbiAgICAgICAgbWVkaWFTdHJlYW1UcmFjay5nZXRDb25zdHJhaW50cygpLmZhY2luZ01vZGVcbiAgICAgICkge1xuICAgICAgICBjb25zdCBmYWNpbmdNb2RlQ29uc3RyYWludDogYW55ID1cbiAgICAgICAgICBtZWRpYVN0cmVhbVRyYWNrLmdldENvbnN0cmFpbnRzKCkuZmFjaW5nTW9kZTtcbiAgICAgICAgcmV0dXJuIFdlYmNhbUNvbXBvbmVudC5nZXRWYWx1ZUZyb21Db25zdHJhaW5ET01TdHJpbmcoXG4gICAgICAgICAgZmFjaW5nTW9kZUNvbnN0cmFpbnRcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRGV0ZXJtaW5lcyB3aGV0aGVyIHRoZSBnaXZlbiBtZWRpYVN0cmVhbVRyYWNrIGNsYWltcyBpdHNlbGYgYXMgdXNlciBmYWNpbmdcbiAgICogQHBhcmFtIG1lZGlhU3RyZWFtVHJhY2tcbiAgICovXG4gIHByaXZhdGUgc3RhdGljIGlzVXNlckZhY2luZyhtZWRpYVN0cmVhbVRyYWNrOiBNZWRpYVN0cmVhbVRyYWNrKTogYm9vbGVhbiB7XG4gICAgY29uc3QgZmFjaW5nTW9kZTogc3RyaW5nID1cbiAgICAgIFdlYmNhbUNvbXBvbmVudC5nZXRGYWNpbmdNb2RlRnJvbU1lZGlhU3RyZWFtVHJhY2sobWVkaWFTdHJlYW1UcmFjayk7XG4gICAgcmV0dXJuIGZhY2luZ01vZGUgPyAndXNlcicgPT09IGZhY2luZ01vZGUudG9Mb3dlckNhc2UoKSA6IGZhbHNlO1xuICB9XG4gIGxhbmRzY2FwZSA9IHRydWU7XG4gIC8qKlxuICAgKiBFeHRyYWN0cyB0aGUgdmFsdWUgZnJvbSB0aGUgZ2l2ZW4gQ29uc3RyYWluRE9NU3RyaW5nXG4gICAqIEBwYXJhbSBjb25zdHJhaW5ET01TdHJpbmdcbiAgICovXG4gIHByaXZhdGUgc3RhdGljIGdldFZhbHVlRnJvbUNvbnN0cmFpbkRPTVN0cmluZyhjb25zdHJhaW5ET01TdHJpbmc6IGFueSk6IGFueSB7XG4gICAgaWYgKGNvbnN0cmFpbkRPTVN0cmluZykge1xuICAgICAgaWYgKGNvbnN0cmFpbkRPTVN0cmluZyBpbnN0YW5jZW9mIFN0cmluZykge1xuICAgICAgICByZXR1cm4gU3RyaW5nKGNvbnN0cmFpbkRPTVN0cmluZyk7XG4gICAgICB9IGVsc2UgaWYgKFxuICAgICAgICBBcnJheS5pc0FycmF5KGNvbnN0cmFpbkRPTVN0cmluZykgJiZcbiAgICAgICAgQXJyYXkoY29uc3RyYWluRE9NU3RyaW5nKS5sZW5ndGggPiAwXG4gICAgICApIHtcbiAgICAgICAgcmV0dXJuIFN0cmluZyhjb25zdHJhaW5ET01TdHJpbmdbMF0pO1xuICAgICAgfSBlbHNlIGlmICh0eXBlb2YgY29uc3RyYWluRE9NU3RyaW5nID09PSAnb2JqZWN0Jykge1xuICAgICAgICBpZiAoY29uc3RyYWluRE9NU3RyaW5nWydleGFjdCddKSB7XG4gICAgICAgICAgcmV0dXJuIFN0cmluZyhjb25zdHJhaW5ET01TdHJpbmdbJ2V4YWN0J10pO1xuICAgICAgICB9IGVsc2UgaWYgKGNvbnN0cmFpbkRPTVN0cmluZ1snaWRlYWwnXSkge1xuICAgICAgICAgIHJldHVybiBTdHJpbmcoY29uc3RyYWluRE9NU3RyaW5nWydpZGVhbCddKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgcmVzaXplU3RhZ2UoKSB7XG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLnVwZGF0ZVNpemUoKTtcbiAgICAgIHRoaXMudXBkYXRlY2FudmFzU2l6ZSgpO1xuICAgICAgdGhpcy5kcmF3UmVjdGFuZ2xlKCk7XG4gICAgICB0aGlzLmNkLmRldGVjdENoYW5nZXMoKTtcbiAgICAgIHRoaXMudmlkZW9SZWFkeS5uZXh0KHRydWUpO1xuICAgIH0sIDEwKTtcbiAgfVxuXG4gIGdldCBjYW52YXNIZWlnaHQoKSB7XG4gICAgY29uc3QgbGFuZHNjYXBlID0gdGhpcy53aWR0aCA+IHRoaXMuaGVpZ2h0O1xuICAgIGNvbnN0IGFzcGVjdCA9IHRoaXMudmlkZW9TaXplLndpZHRoIC8gdGhpcy52aWRlb1NpemUuaGVpZ2h0O1xuICAgIGlmICghbGFuZHNjYXBlKSB7XG4gICAgICByZXR1cm4gdGhpcy53aWR0aCAqIGFzcGVjdDtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuaGVpZ2h0O1xuICB9XG4gIHVwZGF0ZWNhbnZhc1NpemUoKSB7XG4gICAgY29uc29sZS5sb2codGhpcy53aWR0aCwgdGhpcy5oZWlnaHQpO1xuICAgIGNvbnN0IGxhbmRzY2FwZSA9IHRoaXMud2lkdGggPiB0aGlzLmhlaWdodDtcbiAgICBjb25zdCBhc3BlY3QgPSB0aGlzLnZpZGVvU2l6ZS53aWR0aCAvIHRoaXMudmlkZW9TaXplLmhlaWdodDtcblxuICAgIGxldCB3aWR0aCA9IHRoaXMud2lkdGg7XG4gICAgbGV0IGhlaWdodCA9IHRoaXMuaGVpZ2h0O1xuXG4gICAgaWYgKGxhbmRzY2FwZSkge1xuICAgICAgaGVpZ2h0ID0gd2lkdGggLyBhc3BlY3Q7XG4gICAgfSBlbHNlIHtcbiAgICAgIGhlaWdodCA9IHdpZHRoIC8gYXNwZWN0O1xuICAgIH1cblxuICAgIGlmIChoZWlnaHQgPiB0aGlzLmhlaWdodCkge1xuICAgICAgaGVpZ2h0ID0gdGhpcy5oZWlnaHQ7XG4gICAgICB3aWR0aCA9IHRoaXMuaGVpZ2h0ICogYXNwZWN0O1xuICAgIH1cblxuICAgIHRoaXMuY2FudmFzU2l6ZSA9IHsgd2lkdGg6IE1hdGgucm91bmQod2lkdGgpLCBoZWlnaHQ6IE1hdGgucm91bmQoaGVpZ2h0KSB9O1xuXG4gICAgY29uc29sZS5sb2codGhpcy5jYW52YXNTaXplLCB0aGlzLnZpZGVvU2l6ZSk7XG5cbiAgICBpZiAodGhpcy5pc01vYmlsZSkge1xuICAgICAgdGhpcy52aWRlby5uYXRpdmVFbGVtZW50LnNldEF0dHJpYnV0ZSgnaGVpZ2h0JywgdGhpcy5jYW52YXNTaXplLmhlaWdodCk7XG4gICAgICB0aGlzLnZpZGVvLm5hdGl2ZUVsZW1lbnQuc2V0QXR0cmlidXRlKCd3aWR0aCcsIHRoaXMuY2FudmFzU2l6ZS53aWR0aCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICh0aGlzLnZpZGVvU2l6ZS53aWR0aCA+IHRoaXMudmlkZW9TaXplLmhpZ2h0KSB7XG4gICAgICAgIHRoaXMudmlkZW8ubmF0aXZlRWxlbWVudC5zZXRBdHRyaWJ1dGUoJ2hlaWdodCcsIHRoaXMuY2FudmFzU2l6ZS5oZWlnaHQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy52aWRlby5uYXRpdmVFbGVtZW50LnNldEF0dHJpYnV0ZSgnd2lkdGgnLCB0aGlzLmNhbnZhc1NpemUud2lkdGgpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMuY2QuZGV0ZWN0Q2hhbmdlcygpO1xuICB9XG5cbiAgcHJpdmF0ZSBzZXR1cFdvcmtlcigpIHtcbiAgICBpZiAodHlwZW9mIFdvcmtlciAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIC8vIENyZWF0ZSBhIG5ld1xuXG4gICAgICBpZiAodGhpcy50eXBlICE9PSAnc2VsZmllJykge1xuICAgICAgICB0aGlzLnpvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xuICAgICAgICAgIHZhciBibG9iID0gbmV3IEJsb2IoW3dvcmtlcnRleHRdLCB7IHR5cGU6ICd0ZXh0L2phdmFzY3JpcHQnIH0pO1xuXG4gICAgICAgICAgdmFyIHVybCA9IFVSTC5jcmVhdGVPYmplY3RVUkwoYmxvYik7XG5cbiAgICAgICAgICB0aGlzLndvcmtlciA9IG5ldyBXb3JrZXIodXJsKTtcbiAgICAgICAgICB0aGlzLndvcmtlci5vbm1lc3NhZ2UgPSAoeyBkYXRhIH0pID0+IHtcbiAgICAgICAgICAgIGlmIChkYXRhLmJhc2U2NCkge1xuICAgICAgICAgICAgICBkYXRhLnR5cGUgPT0gJ2RhdGEnO1xuICAgICAgICAgICAgICB0aGlzLmltYWdlSGFuZGxlci5uZXh0KGRhdGEpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG4gICAgdGhpcy5zZXR1cFdvcmtlcigpO1xuXG4gICAgaWYgKHRoaXMuaW1hZ2VIYW5kbGVyKSB7XG4gICAgICB0aGlzLmltYWdlSGFuZGxlci5zdWJzY3JpYmUoKHJlc3ApID0+IHtcbiAgICAgICAgaWYgKHJlc3AudHlwZSA9PT0gJ3N0b3AnKSB7XG4gICAgICAgICAgdGhpcy53b3JrZXI/LnBvc3RNZXNzYWdlKHsgdHlwZTogJ3N0b3AnIH0pO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gICAgdGhpcy5icmVha3BvaW50T2JzZXJ2ZXJcbiAgICAgIC5vYnNlcnZlKFtCcmVha3BvaW50cy5IYW5kc2V0UG9ydHJhaXQsIEJyZWFrcG9pbnRzLkhhbmRzZXRMYW5kc2NhcGVdKVxuICAgICAgLnN1YnNjcmliZSgoc3RhdGU6IEJyZWFrcG9pbnRTdGF0ZSkgPT4ge1xuICAgICAgICBpZiAodGhpcy5wbGF0Zm9ybS5JT1MgfHwgdGhpcy5wbGF0Zm9ybS5BTkRST0lEKSB7XG4gICAgICAgICAgLy8gdGhpcy5sYW5kc2NhcGUgPSBzdGF0ZS5icmVha3BvaW50c1tCcmVha3BvaW50cy5IYW5kc2V0TGFuZHNjYXBlXTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBtb2JpbGUgPSB0aGlzLnBsYXRmb3JtLklPUztcbiAgICAgICAgaWYgKHN0YXRlLm1hdGNoZXMgJiYgbW9iaWxlKSB7XG4gICAgICAgICAgdGhpcy51cGRhdGVTaXplKCk7XG4gICAgICAgICAgdGhpcy51cGRhdGVjYW52YXNTaXplKCk7XG4gICAgICAgICAgdGhpcy5kcmF3UmVjdGFuZ2xlKCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIGlmICh0aGlzLnN3aXRjaENhbWVyYSkge1xuICAgICAgaWYgKHRoaXMuc3dpdGNoQ2FtZXJhU3Vic2NyaXB0aW9uKSB7XG4gICAgICAgIHRoaXMuc3dpdGNoQ2FtZXJhU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgICB9XG5cbiAgICAgIC8vIFN1YnNjcmliZSB0byBldmVudHMgZnJvbSB0aGlzIE9ic2VydmFibGUgdG8gc3dpdGNoIHZpZGVvIGRldmljZVxuICAgICAgdGhpcy5zd2l0Y2hDYW1lcmFTdWJzY3JpcHRpb24gPSB0aGlzLnN3aXRjaENhbWVyYS5zdWJzY3JpYmUoXG4gICAgICAgICh2YWx1ZTogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgdGhpcy5zd2l0Y2hUb1ZpZGVvSW5wdXQodmFsdWUpO1xuICAgICAgICB9XG4gICAgICApO1xuICAgIH1cblxuICAgIHRoaXMuZGV0ZWN0QXZhaWxhYmxlRGV2aWNlcygpXG4gICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgIC8vIHN0YXJ0IHZpZGVvXG5cbiAgICAgICAgaWYgKHRoaXMuY2FuU3RhcnQpIHtcbiAgICAgICAgICB0aGlzLnN3aXRjaFRvVmlkZW9JbnB1dCgnJyk7XG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgICAuY2F0Y2goKGVycjogc3RyaW5nKSA9PiB7XG4gICAgICAgIHRoaXMuaW5pdEVycm9yLm5leHQoPFdlYmNhbUluaXRFcnJvcj57IG1lc3NhZ2U6IGVyciB9KTtcbiAgICAgICAgLy8gZmFsbGJhY2s6IHN0aWxsIHRyeSB0byBsb2FkIHdlYmNhbSwgZXZlbiBpZiBkZXZpY2UgZW51bWVyYXRpb24gZmFpbGVkXG4gICAgICAgIGlmICh0aGlzLmNhblN0YXJ0KSB7XG4gICAgICAgICAgdGhpcy5zd2l0Y2hUb1ZpZGVvSW5wdXQoJycpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmNhblN0YXJ0ID0gZmFsc2U7XG4gICAgdGhpcy5uYXRpdmVWaWRlb0VsZW1lbnQucGF1c2UoKTtcbiAgICB0aGlzLmRlc3Ryb3llZC5lbWl0KHRydWUpO1xuICAgIHRoaXMuc3RvcE1lZGlhVHJhY2tzKCk7XG4gICAgdGhpcy51bnN1YnNjcmliZUZyb21TdWJzY3JpcHRpb25zKCk7XG4gICAgdGhpcy5zaHV0ZG93biA9IHRydWU7XG5cbiAgICAvLyBzaHV0IGRvd24gd29ya2VyXG4gICAgaWYgKHRoaXMuaW1hZ2VIYW5kbGVyKSB7XG4gICAgICB0aGlzLmltYWdlSGFuZGxlci5uZXh0KHsgdHlwZTogJ3N0b3AnIH0pO1xuICAgIH1cblxuICAgIGlmICh0aGlzLm5hdGl2ZVZpZGVvRWxlbWVudC5zcmNPYmplY3QpIHtcbiAgICAgICgodGhpcy5uYXRpdmVWaWRlb0VsZW1lbnQgYXMgSFRNTFZpZGVvRWxlbWVudCkuc3JjT2JqZWN0IGFzIE1lZGlhU3RyZWFtKVxuICAgICAgICAuZ2V0VHJhY2tzKClcbiAgICAgICAgLmZvckVhY2goKHRyYWNrKSA9PiB7XG4gICAgICAgICAgdHJhY2suc3RvcCgpO1xuICAgICAgICB9KTtcbiAgICAgIHRoaXMubmF0aXZlVmlkZW9FbGVtZW50LnNyY09iamVjdCA9IG51bGw7XG4gICAgfVxuXG4gICAgLy8gdGhpcy5uYXRpdmVWaWRlb0VsZW1lbnQuc3JjID0gbnVsbDtcbiAgICAvLyB0aGlzLm5hdGl2ZVZpZGVvRWxlbWVudC5zcmNPYmplY3QgPSBudWxsO1xuICB9XG5cbiAgcHJpdmF0ZSB0YWtlU2VsZmllKCkge1xuICAgIGNvbnN0IF92aWRlbyA9IHRoaXMubmF0aXZlVmlkZW9FbGVtZW50O1xuXG4gICAgY29uc3QgbWltZVR5cGU6IHN0cmluZyA9IHRoaXMuaW1hZ2VUeXBlXG4gICAgICA/IHRoaXMuaW1hZ2VUeXBlXG4gICAgICA6IFdlYmNhbUNvbXBvbmVudC5ERUZBVUxUX0lNQUdFX1RZUEU7XG5cbiAgICBsZXQgX2NhbnZhczogSFRNTENhbnZhc0VsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTsgLy90aGlzLmNhbnZhc1NuYXBzaG90Lm5hdGl2ZUVsZW1lbnQ7XG5cbiAgICBjb25zdCB7IHdpZHRoLCBoZWlnaHQgfSA9IHRoaXMudmlkZW9TaXplO1xuICAgIGNvbnNvbGUubG9nKHdpZHRoLCBoZWlnaHQpO1xuXG4gICAgY29uc3QgeyBwYWRkaW5nLCB0b3AsIHJXaWR0aCwgckhlaWdodCB9ID0gdGhpcy5zbmFwUmVjdGFuZ2xlO1xuICAgIF9jYW52YXMud2lkdGggPSByV2lkdGg7XG4gICAgX2NhbnZhcy5oZWlnaHQgPSBySGVpZ2h0O1xuXG4gICAgY29uc3QgY3R4OiBhbnkgPSBfY2FudmFzLmdldENvbnRleHQoJzJkJywge1xuICAgICAgYWxwaGE6IGZhbHNlLFxuICAgICAgcG93ZXJQcmVmZXJlbmNlOiAnaGlnaC1wZXJmb3JtYW5jZScsXG4gICAgICBhbnRpYWxpYXM6IGZhbHNlLFxuICAgICAgZGVwdGg6IGZhbHNlLFxuICAgICAgZGVzeW5jaHJvbml6ZWQ6IHRydWUsXG4gICAgfSk7XG5cbiAgICBpZiAoY3R4KSB7XG4gICAgICBjdHguZHJhd0ltYWdlKFxuICAgICAgICBfdmlkZW8sXG4gICAgICAgIHBhZGRpbmcsXG4gICAgICAgIHRvcCxcbiAgICAgICAgcldpZHRoLFxuICAgICAgICBySGVpZ2h0LFxuICAgICAgICAwLFxuICAgICAgICAwLFxuICAgICAgICByV2lkdGgsXG4gICAgICAgIHJIZWlnaHRcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IGltZ0FzVXJsOiBhbnkgPSBfY2FudmFzLnRvRGF0YVVSTChtaW1lVHlwZSwgMSk7XG5cbiAgICAgIHRoaXMuaW1hZ2VDYXB0dXJlLmVtaXQoXG4gICAgICAgIG5ldyBXZWJjYW1JbWFnZShpbWdBc1VybCwgbWltZVR5cGUsIG5ldyBJbWFnZURhdGEoMSwgMSksIG51bGwpXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUYWtlcyBhIHNuYXBzaG90IG9mIHRoZSBjdXJyZW50IHdlYmNhbSdzIHZpZXcgYW5kIGVtaXRzIHRoZSBpbWFnZSBhcyBhbiBldmVudFxuICAgKi9cblxuICBwdWJsaWMgdGFrZVNuYXBzaG90KHRpbWU6IG51bWJlcik6IHZvaWQge1xuICAgIGlmICh0aGlzLnR5cGUgPT09ICdzZWxmaWUnKSB7XG4gICAgICB0aGlzLnRha2VTZWxmaWUoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy50cmFja1Byb2Nlc3Nvcikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLnpvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xuICAgICAgY29uc3QgY2FudmFzU21hbFNpemUgPSAzODQ7XG5cbiAgICAgIGNvbnN0IF92aWRlbyA9IHRoaXMubmF0aXZlVmlkZW9FbGVtZW50O1xuXG4gICAgICBjb25zdCBtaW1lVHlwZTogc3RyaW5nID0gdGhpcy5pbWFnZVR5cGVcbiAgICAgICAgPyB0aGlzLmltYWdlVHlwZVxuICAgICAgICA6IFdlYmNhbUNvbXBvbmVudC5ERUZBVUxUX0lNQUdFX1RZUEU7XG5cbiAgICAgIGxldCBfY2FudmFzOiBIVE1MQ2FudmFzRWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpOyAvL3RoaXMuY2FudmFzU25hcHNob3QubmF0aXZlRWxlbWVudDtcblxuICAgICAgY29uc3QgeyB3aWR0aCwgaGVpZ2h0IH0gPSB0aGlzLnZpZGVvU2l6ZTtcblxuICAgICAgX2NhbnZhcy53aWR0aCA9IHdpZHRoO1xuICAgICAgX2NhbnZhcy5oZWlnaHQgPSBoZWlnaHQ7XG5cbiAgICAgIGNvbnN0IGN0eDogYW55ID0gX2NhbnZhcy5nZXRDb250ZXh0KCcyZCcsIHtcbiAgICAgICAgYWxwaGE6IGZhbHNlLFxuICAgICAgICBwb3dlclByZWZlcmVuY2U6ICdoaWdoLXBlcmZvcm1hbmNlJyxcbiAgICAgICAgYW50aWFsaWFzOiBmYWxzZSxcbiAgICAgICAgZGVwdGg6IGZhbHNlLFxuICAgICAgICBkZXN5bmNocm9uaXplZDogdHJ1ZSxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBjYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTsgLy8gbmVlZHMgYW4gaW5pdGlhbCBzaXplXG4gICAgICBjYW52YXMuaGVpZ2h0ID0gY2FudmFzU21hbFNpemU7XG4gICAgICBjYW52YXMud2lkdGggPSBjYW52YXNTbWFsU2l6ZTtcblxuICAgICAgY29uc3QgY3R4TzogYW55ID0gY2FudmFzLmdldENvbnRleHQoJzJkJywge1xuICAgICAgICBhbHBoYTogZmFsc2UsXG4gICAgICAgIHBvd2VyUHJlZmVyZW5jZTogJ2hpZ2gtcGVyZm9ybWFuY2UnLFxuICAgICAgICBhbnRpYWxpYXM6IGZhbHNlLFxuICAgICAgICBkZXB0aDogZmFsc2UsXG4gICAgICAgIGRlc3luY2hyb25pemVkOiB0cnVlLFxuICAgICAgfSk7XG5cbiAgICAgIGlmIChjdHggJiYgY3R4Tykge1xuICAgICAgICBjdHguaW1hZ2VTbW9vdGhpbmdFbmFibGVkID0gZmFsc2U7XG5cbiAgICAgICAgY3R4LmRyYXdJbWFnZShfdmlkZW8sIDAsIDApO1xuICAgICAgICBjdHhPLmRyYXdJbWFnZShfdmlkZW8sIDAsIDAsIGNhbnZhc1NtYWxTaXplLCBjYW52YXNTbWFsU2l6ZSk7XG5cbiAgICAgICAgY29uc3QgaW1EYXRhOiBhbnkgPSBjdHguZ2V0SW1hZ2VEYXRhKFxuICAgICAgICAgIDAsXG4gICAgICAgICAgMCxcbiAgICAgICAgICB0aGlzLnZpZGVvU2l6ZS53aWR0aCxcbiAgICAgICAgICB0aGlzLnZpZGVvU2l6ZS5oZWlnaHRcbiAgICAgICAgKTtcblxuICAgICAgICBjb25zdCByZXNpemUgPSBjYW52YXMudG9EYXRhVVJMKG1pbWVUeXBlLCAxKTtcblxuICAgICAgICBjb25zdCBjdXJyZW50VGltZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgICAgICBjb25zdCBkaWZmID0gY3VycmVudFRpbWUgLSB0aW1lO1xuXG4gICAgICAgIGNvbnN0IGRlbGF5ID0gZGlmZiA+IDEwMCA/IDAgOiAxMDAgLSBkaWZmO1xuXG4gICAgICAgIGNvbnN0IHRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICB0aGlzLmltYWdlQ2FwdHVyZS5lbWl0KG5ldyBXZWJjYW1JbWFnZSgnJywgbWltZVR5cGUsIGltRGF0YSwgcmVzaXplKSk7XG4gICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgICB9LCBkZWxheSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIHVwZGF0ZSgpIHt9XG5cbiAgcmVzaXplSW1hZ2UoYmFzZTY0ZGF0YTogYW55KTogT2JzZXJ2YWJsZTxhbnk+IHtcbiAgICByZXR1cm4gbmV3IE9ic2VydmFibGUoKG9ic2VydmVyKSA9PiB7XG4gICAgICBsZXQgY2FudmFzOiBhbnkgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcbiAgICAgIGNvbnN0IGN0eCA9IGNhbnZhcy5nZXRDb250ZXh0KCcyZCcpO1xuICAgICAgY29uc3QgbWF4X3NpemUgPSAzODQ7XG4gICAgICBsZXQgaW1hZ2U6IGFueSA9IG5ldyBJbWFnZSgpO1xuXG4gICAgICBpbWFnZS5zcmMgPSBiYXNlNjRkYXRhO1xuICAgICAgaW1hZ2Uub25sb2FkID0gKCkgPT4ge1xuICAgICAgICBsZXQgd2lkdGggPSBpbWFnZS53aWR0aDtcbiAgICAgICAgbGV0IGhlaWdodCA9IGltYWdlLmhlaWdodDtcblxuICAgICAgICBpZiAod2lkdGggPCBoZWlnaHQpIHtcbiAgICAgICAgICBoZWlnaHQgKj0gbWF4X3NpemUgLyB3aWR0aDtcbiAgICAgICAgICB3aWR0aCA9IG1heF9zaXplO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHdpZHRoICo9IG1heF9zaXplIC8gaGVpZ2h0O1xuICAgICAgICAgIGhlaWdodCA9IG1heF9zaXplO1xuICAgICAgICB9XG4gICAgICAgIGNhbnZhcy53aWR0aCA9IHdpZHRoO1xuICAgICAgICBjYW52YXMuaGVpZ2h0ID0gaGVpZ2h0O1xuXG4gICAgICAgIC8vIGNvbnNvbGUubG9nKHdpZHRoLCBoZWlnaHQpO1xuXG4gICAgICAgIGlmIChjdHgpIHtcbiAgICAgICAgICAvLyBjdHgucm90YXRlKCg5MCAqIE1hdGguUEkpIC8gMTgwKTtcbiAgICAgICAgICAvLyBjdHgudHJhbnNsYXRlKDAsIC1jYW52YXMud2lkdGgpO1xuICAgICAgICAgIGN0eC5kcmF3SW1hZ2UoaW1hZ2UsIDAsIDAsIDM4NCwgMzg0KTtcblxuICAgICAgICAgIG9ic2VydmVyLm5leHQoY2FudmFzLnRvRGF0YVVSTCgpKTtcbiAgICAgICAgICBjdHguY2xlYXJSZWN0KDAsIDAsIDEsIDEpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIG9ic2VydmVyLmVycm9yKHsgdHlwZTogJ2dlbmVyaWMgZXJyb3InIH0pO1xuICAgICAgICB9XG4gICAgICAgIGltYWdlID0gbnVsbDtcbiAgICAgICAgY2FudmFzID0gbnVsbDtcbiAgICAgIH07XG4gICAgICBpbWFnZS5vbmVycm9yID0gKGU6IGFueSkgPT4ge1xuICAgICAgICBvYnNlcnZlci5lcnJvcihlKTtcbiAgICAgIH07XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogU3dpdGNoZXMgdG8gdGhlIG5leHQvcHJldmlvdXMgdmlkZW8gZGV2aWNlXG4gICAqIEBwYXJhbSBmb3J3YXJkXG4gICAqL1xuICBwdWJsaWMgcm90YXRlVmlkZW9JbnB1dChmb3J3YXJkOiBib29sZWFuKSB7XG4gICAgaWYgKHRoaXMuYXZhaWxhYmxlVmlkZW9JbnB1dHMgJiYgdGhpcy5hdmFpbGFibGVWaWRlb0lucHV0cy5sZW5ndGggPiAxKSB7XG4gICAgICBjb25zdCBpbmNyZW1lbnQ6IG51bWJlciA9IGZvcndhcmRcbiAgICAgICAgPyAxXG4gICAgICAgIDogdGhpcy5hdmFpbGFibGVWaWRlb0lucHV0cy5sZW5ndGggLSAxO1xuICAgICAgY29uc3QgbmV4dElucHV0SW5kZXggPVxuICAgICAgICAodGhpcy5hY3RpdmVWaWRlb0lucHV0SW5kZXggKyBpbmNyZW1lbnQpICVcbiAgICAgICAgdGhpcy5hdmFpbGFibGVWaWRlb0lucHV0cy5sZW5ndGg7XG4gICAgICB0aGlzLnN3aXRjaFRvVmlkZW9JbnB1dChcbiAgICAgICAgdGhpcy5hdmFpbGFibGVWaWRlb0lucHV0c1tuZXh0SW5wdXRJbmRleF0uZGV2aWNlSWRcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFN3aXRjaGVzIHRoZSBjYW1lcmEtdmlldyB0byB0aGUgc3BlY2lmaWVkIHZpZGVvIGRldmljZVxuICAgKi9cbiAgcHVibGljIHN3aXRjaFRvVmlkZW9JbnB1dChkZXZpY2VJZDogc3RyaW5nKTogdm9pZCB7XG4gICAgLy8gaWYoZGV2aWNlSWQpe1xuICAgIHRoaXMudmlkZW9Jbml0aWFsaXplZCA9IGZhbHNlO1xuICAgIHRoaXMuc3RvcE1lZGlhVHJhY2tzKCk7XG4gICAgdGhpcy5pbml0V2ViY2FtKGRldmljZUlkLCB0aGlzLnZpZGVvT3B0aW9ucyk7XG4gICAgLy8gfVxuICB9XG5cbiAgLyoqXG4gICAqIEV2ZW50LWhhbmRsZXIgZm9yIHZpZGVvIHJlc2l6ZSBldmVudC5cbiAgICogVHJpZ2dlcnMgQW5ndWxhciBjaGFuZ2UgZGV0ZWN0aW9uIHNvIHRoYXQgbmV3IHZpZGVvIGRpbWVuc2lvbnMgZ2V0IGFwcGxpZWRcbiAgICovXG4gIHB1YmxpYyB2aWRlb1Jlc2l6ZSgpOiB2b2lkIHtcbiAgICAvLyBoZXJlIHRvIHRyaWdnZXIgQW5ndWxhciBjaGFuZ2UgZGV0ZWN0aW9uXG4gIH1cblxuICBwdWJsaWMgZ2V0IHZpZGVvV2lkdGgoKSB7XG4gICAgY29uc3QgdmlkZW9SYXRpbyA9IHRoaXMuZ2V0VmlkZW9Bc3BlY3RSYXRpbygpO1xuICAgIHJldHVybiBNYXRoLm1pbih0aGlzLndpZHRoLCB0aGlzLmhlaWdodCAqIHZpZGVvUmF0aW8pO1xuICB9XG5cbiAgcHVibGljIGdldCB2aWRlb0hlaWdodCgpIHtcbiAgICBjb25zdCB2aWRlb1JhdGlvID0gdGhpcy5nZXRWaWRlb0FzcGVjdFJhdGlvKCk7XG4gICAgcmV0dXJuIE1hdGgubWluKHRoaXMuaGVpZ2h0LCB0aGlzLndpZHRoIC8gdmlkZW9SYXRpbyk7XG4gIH1cblxuICBwdWJsaWMgZ2V0IHZpZGVvU3R5bGVDbGFzc2VzKCkge1xuICAgIGxldCBjbGFzc2VzOiBzdHJpbmcgPSAnJztcblxuICAgIGlmICh0aGlzLmlzTWlycm9ySW1hZ2UoKSkge1xuICAgICAgY2xhc3NlcyArPSAnbWlycm9yZWQgJztcbiAgICB9XG5cbiAgICByZXR1cm4gY2xhc3Nlcy50cmltKCk7XG4gIH1cblxuICBwdWJsaWMgZ2V0IG5hdGl2ZVZpZGVvRWxlbWVudCgpIHtcbiAgICByZXR1cm4gdGhpcy52aWRlby5uYXRpdmVFbGVtZW50O1xuICB9XG4gIC8vIHB1YmxpYyBnZXQgc21hbGxWaWRlb0VsZW1lbnQoKSB7XG4gIC8vICAgcmV0dXJuIHRoaXMudmlkZW9TbWFsbDtcbiAgLy8gfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSB2aWRlbyBhc3BlY3QgcmF0aW8gb2YgdGhlIGFjdGl2ZSB2aWRlbyBzdHJlYW1cbiAgICovXG4gIHByaXZhdGUgZ2V0VmlkZW9Bc3BlY3RSYXRpbygpOiBudW1iZXIge1xuICAgIC8vIGNhbGN1bGF0ZSByYXRpbyBmcm9tIHZpZGVvIGVsZW1lbnQgZGltZW5zaW9ucyBpZiBwcmVzZW50XG4gICAgY29uc3QgdmlkZW9FbGVtZW50ID0gdGhpcy5uYXRpdmVWaWRlb0VsZW1lbnQ7XG4gICAgaWYgKFxuICAgICAgdmlkZW9FbGVtZW50LnZpZGVvV2lkdGggJiZcbiAgICAgIHZpZGVvRWxlbWVudC52aWRlb1dpZHRoID4gMCAmJlxuICAgICAgdmlkZW9FbGVtZW50LnZpZGVvSGVpZ2h0ICYmXG4gICAgICB2aWRlb0VsZW1lbnQudmlkZW9IZWlnaHQgPiAwXG4gICAgKSB7XG4gICAgICByZXR1cm4gdmlkZW9FbGVtZW50LnZpZGVvV2lkdGggLyB2aWRlb0VsZW1lbnQudmlkZW9IZWlnaHQ7XG4gICAgfVxuXG4gICAgLy8gbm90aGluZyBwcmVzZW50IC0gY2FsY3VsYXRlIHJhdGlvIGJhc2VkIG9uIHdpZHRoL2hlaWdodCBwYXJhbXNcbiAgICByZXR1cm4gdGhpcy53aWR0aCAvIHRoaXMuaGVpZ2h0O1xuICB9XG5cbiAgcHJpdmF0ZSB1cGRhdGVTaXplKCkge1xuICAgIGNvbnN0IHRyYWNrOiBNZWRpYVN0cmVhbVRyYWNrIHwgdW5kZWZpbmVkID1cbiAgICAgIHRoaXMubWVkaWFTdHJlYW0/LmdldFRyYWNrcygpWzBdO1xuXG4gICAgaWYgKHRyYWNrKSB7XG4gICAgICBsZXQgZGVzaXJlZDogYW55ID0ge1xuICAgICAgICB3aWR0aDoge1xuICAgICAgICAgIGlkZWFsOiAwLFxuICAgICAgICB9LFxuICAgICAgICBoZWlnaHQ6IHtcbiAgICAgICAgICBpZGVhbDogMCxcbiAgICAgICAgfSxcblxuICAgICAgICAvLyAgZmFjaW5nTW9kZTondXNlcicsXG4gICAgICAgIGZyYW1lUmF0ZTogeyBtaW46IDIwLCBpZGVhbDogMjQsIG1heDogMjQgfSxcbiAgICAgIH07XG4gICAgICBpZiAodHlwZW9mIHRyYWNrLmdldENhcGFiaWxpdGllcyA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBjb25zdCB7IHdpZHRoLCBoZWlnaHQgfSA9IHRyYWNrLmdldENhcGFiaWxpdGllcygpO1xuICAgICAgICBkZXNpcmVkID0ge1xuICAgICAgICAgIHdpZHRoOiB7XG4gICAgICAgICAgICBpZGVhbDogdGhpcy5sYW5kc2NhcGUgJiYgdGhpcy5pc01vYmlsZSA/IGhlaWdodD8ubWF4IDogd2lkdGg/Lm1heCxcbiAgICAgICAgICB9LFxuICAgICAgICAgIGhlaWdodDoge1xuICAgICAgICAgICAgaWRlYWw6IHRoaXMubGFuZHNjYXBlICYmIHRoaXMuaXNNb2JpbGUgPyB3aWR0aD8ubWF4IDogaGVpZ2h0Py5tYXgsXG4gICAgICAgICAgfSxcblxuICAgICAgICAgIC8vICBmYWNpbmdNb2RlOid1c2VyJyxcbiAgICAgICAgICBmcmFtZVJhdGU6IHsgbWluOiAyMCwgaWRlYWw6IDI0LCBtYXg6IDI0IH0sXG4gICAgICAgIH07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBkZXNpcmVkID0ge1xuICAgICAgICAgIHdpZHRoOiB7XG4gICAgICAgICAgICBpZGVhbDogMTkyMCxcbiAgICAgICAgICB9LFxuICAgICAgICAgIGhlaWdodDoge1xuICAgICAgICAgICAgaWRlYWw6IDEwODAsXG4gICAgICAgICAgfSxcblxuICAgICAgICAgIC8vICBmYWNpbmdNb2RlOid1c2VyJyxcbiAgICAgICAgICBmcmFtZVJhdGU6IHsgbWluOiAyMCwgaWRlYWw6IDMwLCBtYXg6IDMxIH0sXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGlmIChkZXNpcmVkLmhlaWdodC5pZGVhbCAmJiBkZXNpcmVkLmhlaWdodC5pZGVhbCA+PSAxNjAwKSB7XG4gICAgICAgIGRlc2lyZWQuaGVpZ2h0LmlkZWFsID0gMTYwMDtcbiAgICAgICAgZGVzaXJlZC53aWR0aC5pZGVhbCA9IDE2MDA7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnBsYXRmb3JtLkFORFJPSUQpIHtcbiAgICAgICAgLy9kZXNpcmVkLndpZHRoLmlkZWFsID0gMjE2MDtcbiAgICAgICAgLy9kZXNpcmVkLmhlaWdodC5pZGVhbCA9IDIxNjA7XG4gICAgICAgIC8vIGlmICghdGhpcy5sYW5kc2NhcGUpIHtcbiAgICAgICAgLy8gfSBlbHNlIHtcbiAgICAgICAgLy8gICBkZXNpcmVkLndpZHRoLmlkZWFsID0gd2lkdGg/Lm1heDtcbiAgICAgICAgLy8gICBkZXNpcmVkLmhlaWdodC5pZGVhbCA9IGhlaWdodD8ubWF4O1xuICAgICAgICAvLyB9XG4gICAgICB9XG5cbiAgICAgIHRyYWNrLmFwcGx5Q29uc3RyYWludHMoZGVzaXJlZCk7XG5cbiAgICAgIC8vdHJhY2suZ2V0U2V0dGluZ3MoKS5mYWNpbmdNb2RlIT09J3VzZXInO1xuXG4gICAgICB0aGlzLnZpZGVvU2l6ZSA9IHtcbiAgICAgICAgaGVpZ2h0OiB0aGlzLmxhbmRzY2FwZVxuICAgICAgICAgID8gdHJhY2suZ2V0U2V0dGluZ3MoKS5oZWlnaHRcbiAgICAgICAgICA6IHRyYWNrLmdldFNldHRpbmdzKCkud2lkdGgsXG4gICAgICAgIHdpZHRoOiB0aGlzLmxhbmRzY2FwZVxuICAgICAgICAgID8gdHJhY2suZ2V0U2V0dGluZ3MoKS53aWR0aFxuICAgICAgICAgIDogdHJhY2suZ2V0U2V0dGluZ3MoKS5oZWlnaHQsXG4gICAgICB9O1xuXG4gICAgICB0aGlzLmNkLmRldGVjdENoYW5nZXMoKTtcbiAgICB9XG4gIH1cblxuICBnZXRTdHJlYW1UcmFjayhzdHJlYW06IE1lZGlhU3RyZWFtKSB7XG4gICAgcmV0dXJuIHN0cmVhbS5nZXRWaWRlb1RyYWNrcygpWzBdO1xuICB9XG5cbiAgZ2V0VHJhY2tTZXR0aW5ncygpIHt9XG5cbiAgYWNjZXNWaWRlb1RyYWNrKHZpZGVvVHJhY2tDb25zdHJhaW50czogTWVkaWFTdHJlYW1Db25zdHJhaW50cyk6IGFueSB7XG4gICAgcmV0dXJuIGZyb20oXG4gICAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYSh2aWRlb1RyYWNrQ29uc3RyYWludHMpXG4gICAgKS5waXBlKFxuICAgICAgc3dpdGNoTWFwKChzdHJlYW06IE1lZGlhU3RyZWFtKSA9PiB7XG4gICAgICAgIC8vIGRlZmF1bHQgcmVzb2x1dGlvbiAxMjgweDcyMCwgY2hlY2sgbWF4IHJlc29sdXRpb25cblxuICAgICAgICBjb25zdCB0cmFjayA9IHRoaXMuZ2V0U3RyZWFtVHJhY2soc3RyZWFtKTtcblxuICAgICAgICBjb25zdCBjYXBhYmlsaXRpZXMgPSB0cmFjay5nZXRDYXBhYmlsaXRpZXMoKTtcblxuICAgICAgICBjb25zdCB7IGZhY2luZ01vZGUsIGhlaWdodCwgd2lkdGggfSA9IGNhcGFiaWxpdGllcztcblxuICAgICAgICBjb25zdCBkZXNpcmVkID0ge1xuICAgICAgICAgIHdpZHRoOiB7XG4gICAgICAgICAgICBtaW46IHRoaXMubGFuZHNjYXBlICYmIHRoaXMuaXNNb2JpbGUgPyBoZWlnaHQ/Lm1heCA6IHdpZHRoPy5tYXgsXG4gICAgICAgICAgfSxcbiAgICAgICAgICAvLyBoZWlnaHQ6IHtcbiAgICAgICAgICAvLyAgIGV4YWN0OiB0aGlzLmxhbmRzY2FwZSAmJiB0aGlzLmlzTW9iaWxlID8gd2lkdGg/Lm1heCA6IGhlaWdodD8ubWF4LFxuICAgICAgICAgIC8vIH0sXG4gICAgICAgICAgLy8gZmFjaW5nTW9kZTonZW4nLFxuICAgICAgICAgIC8vIGZyYW1lUmF0ZTogeyBtaW46IDI1LCBpZGVhbDogMzAsIG1heDogMzEgfSxcbiAgICAgICAgfTtcbiAgICAgICAgLy8gZ2V0IG1heCB3aWR0aFxuXG4gICAgICAgIGNvbnN0IHsgd2lkdGg6IHNXaWR0aCwgaGVpZ2h0OiBzSGVpZ2h0IH0gPSB0cmFjay5nZXRTZXR0aW5ncygpO1xuXG4gICAgICAgIGlmIChkZXNpcmVkLndpZHRoLm1pbiAhPSBzV2lkdGgpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcy5hY2Nlc1ZpZGVvVHJhY2soeyB2aWRlbzogZGVzaXJlZCB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vcmV0dXJuIHRoaXMuYWNjZXNWaWRlb1RyYWNrKHt2aWRlbzpkZXNpcmVkfSk7XG5cbiAgICAgICAgcmV0dXJuIG9mKHN0cmVhbSk7XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGRyYXdSZWN0YW5nbGUoKSB7XG4gICAgY29uc3QgX2NhbnZhcyA9IHRoaXMuY2FudmFzLm5hdGl2ZUVsZW1lbnQ7XG5cbiAgICBjb25zdCBjdHggPSBfY2FudmFzLmdldENvbnRleHQoJzJkJyk7XG4gICAgY3R4LmNsZWFyUmVjdCgwLCAwLCBfY2FudmFzLndpZHRoLCBfY2FudmFzLmhlaWdodCk7XG5cbiAgICAvLyBjdHguZHJhd0ltYWdlKF92aWRlbywgMCwgMCwgX2NhbnZhcy53aWR0aCwgX2NhbnZhcy5oZWlnaHQpO1xuXG4gICAgY29uc3QgeyBwYWRkaW5nLCB0b3AsIHJXaWR0aCwgckhlaWdodCB9ID0gdGhpcy5jYXJkUmVjdGFuZ2xlO1xuXG4gICAgY3R4LnN0cm9rZVN0eWxlID0gJ3JlZCc7XG5cbiAgICBjdHguc3Ryb2tlUmVjdChwYWRkaW5nLCB0b3AsIHJXaWR0aCwgckhlaWdodCk7XG4gIH1cblxuICBnZXRNYXhBdmFpbGFibGVSZXNvbHV0aW9uKCkge31cbiAgLyoqXG4gICAqIEluaXQgd2ViY2FtIGxpdmUgdmlld1xuICAgKi9cbiAgcHJpdmF0ZSBpbml0V2ViY2FtKFxuICAgIGRldmljZUlkOiBzdHJpbmcsXG4gICAgdXNlclZpZGVvVHJhY2tDb25zdHJhaW50czogTWVkaWFUcmFja0NvbnN0cmFpbnRzXG4gICkge1xuICAgIGNvbnN0IF92aWRlbyA9IHRoaXMubmF0aXZlVmlkZW9FbGVtZW50O1xuICAgIC8vIGNvbnN0IHZpZGVvU3RyZWFtZXIgPSB0aGlzLnZpZGVvU3RyZWFtZXIubmF0aXZlRWxlbWVudDtcbiAgICAvLyBjb25zdCB2aWRlb1NtYWxsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndmlkZW8nKTtcbiAgICBpZiAobmF2aWdhdG9yLm1lZGlhRGV2aWNlcyAmJiBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYSkge1xuICAgICAgLy8gbWVyZ2UgZGV2aWNlSWQgLT4gdXNlclZpZGVvVHJhY2tDb25zdHJhaW50c1xuICAgICAgY29uc3QgdmlkZW9UcmFja0NvbnN0cmFpbnRzID1cbiAgICAgICAgV2ViY2FtQ29tcG9uZW50LmdldE1lZGlhQ29uc3RyYWludHNGb3JEZXZpY2UoXG4gICAgICAgICAgZGV2aWNlSWQsXG4gICAgICAgICAgdXNlclZpZGVvVHJhY2tDb25zdHJhaW50c1xuICAgICAgICApO1xuXG4gICAgICAvLyAvLyBpZiAoZGV2aWNlSWQpIHtcbiAgICAgIC8vIHRoaXMuYWNjZXNWaWRlb1RyYWNrKHsgdmlkZW86IHZpZGVvVHJhY2tDb25zdHJhaW50cyB9KS5zdWJzY3JpYmUoXG4gICAgICAvLyAgIChzdHJlYW06IE1lZGlhU3RyZWFtKSA9PiB7XG4gICAgICAvLyAgICAgY29uc29sZS5sb2coXG4gICAgICAvLyAgICAgICAnVkFMSUQgU0VUVElOR1MnLFxuICAgICAgLy8gICAgICAgc3RyZWFtLmdldFZpZGVvVHJhY2tzKClbMF0uZ2V0U2V0dGluZ3MoKVxuICAgICAgLy8gICAgICk7XG4gICAgICAvLyAgIH1cbiAgICAgIC8vICk7XG4gICAgICAvLyB9XG4gICAgICBpZiAodGhpcy5wbGF0Zm9ybS5BTkRST0lEKSB7XG4gICAgICAgIHZpZGVvVHJhY2tDb25zdHJhaW50cy53aWR0aCA9IDE2MDA7XG4gICAgICAgIHZpZGVvVHJhY2tDb25zdHJhaW50cy5oZWlnaHQgPSAxNjAwO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBjb25zdHJhaW50cyA9IHtcbiAgICAgICAgZXhhY3Q6IGRldmljZUlkLFxuICAgICAgICB3aWR0aDogeyBtaW46IDQ4MCwgaWRlYWw6IDEyODAgfSxcbiAgICAgICAgaGVpZ2h0OiB7IG1pbjogNDgwLCBpZGVhbDogNzIwIH0sXG4gICAgICAgIC8vIGFzcGVjdFJhdGlvOiAzIC8gMixcbiAgICAgICAgZnJhbWVSYXRlOiB7IG1pbjogMjAgfSxcbiAgICAgIH07XG5cbiAgICAgIG5hdmlnYXRvci5tZWRpYURldmljZXNcbiAgICAgICAgLmdldFVzZXJNZWRpYSg8TWVkaWFTdHJlYW1Db25zdHJhaW50cz57IHZpZGVvOiB2aWRlb1RyYWNrQ29uc3RyYWludHMgfSlcbiAgICAgICAgLnRoZW4oKHN0cmVhbTogTWVkaWFTdHJlYW0pID0+IHtcbiAgICAgICAgICB0aGlzLm1lZGlhU3RyZWFtID0gc3RyZWFtO1xuICAgICAgICAgIF92aWRlby5zcmNPYmplY3QgPSBzdHJlYW07XG5cbiAgICAgICAgICB0aGlzLnVwZGF0ZVNpemUoKTtcbiAgICAgICAgICB0aGlzLnVwZGF0ZWNhbnZhc1NpemUoKTtcblxuICAgICAgICAgIF92aWRlby5wbGF5KCk7XG5cbiAgICAgICAgICBfdmlkZW8ub25wbGF5ID0gKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZXRBY3RpdmVDYW1lcmEoc3RyZWFtKTtcbiAgICAgICAgICAgIHRoaXMuZHJhd1JlY3RhbmdsZSgpO1xuICAgICAgICAgIH07XG4gICAgICAgIH0pXG4gICAgICAgIC5jYXRjaCgoZXJyOiBhbnkpID0+IHtcbiAgICAgICAgICBjb25zb2xlLmxvZyhlcnIpO1xuICAgICAgICAgIHRoaXMuaW5pdEVycm9yLm5leHQoPFdlYmNhbUluaXRFcnJvcj57XG4gICAgICAgICAgICBtZXNzYWdlOiBlcnIubWVzc2FnZSxcbiAgICAgICAgICAgIG1lZGlhU3RyZWFtRXJyb3I6IGVycixcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuaW5pdEVycm9yLm5leHQoPFdlYmNhbUluaXRFcnJvcj57XG4gICAgICAgIG1lc3NhZ2U6ICdDYW5ub3QgcmVhZCBVc2VyTWVkaWEgZnJvbSBNZWRpYURldmljZXMuJyxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIGdldCBpc01vYmlsZSgpIHtcbiAgICByZXR1cm4gdGhpcy5wbGF0Zm9ybS5BTkRST0lEIHx8IHRoaXMucGxhdGZvcm0uSU9TO1xuICB9XG5cbiAgZ2V0IGNhcmRSZWN0YW5nbGUoKSB7XG4gICAgY29uc3QgX2NhbnZhcyA9IHRoaXMuY2FudmFzLm5hdGl2ZUVsZW1lbnQ7XG4gICAgY29uc3QgZG9jU2l6ZSA9IHRoaXMudHlwZSA9PT0gJ3NlbGZpZScgPyAxIDogODYgLyA1NTtcblxuICAgIGxldCBwYWRkaW5nID0gMTA7XG5cbiAgICBsZXQgcldpZHRoID0gX2NhbnZhcy53aWR0aCAtIDIgKiBwYWRkaW5nO1xuICAgIGxldCBySGVpZ2h0ID0gcldpZHRoIC8gZG9jU2l6ZTtcbiAgICBsZXQgdG9wID0gKF9jYW52YXMuaGVpZ2h0IC0gckhlaWdodCkgLyAyO1xuXG4gICAgaWYgKCF0aGlzLmlzTW9iaWxlKSB7XG4gICAgICBwYWRkaW5nID0gNDA7XG5cbiAgICAgIHJIZWlnaHQgPSBfY2FudmFzLmhlaWdodCAtIDIgKiBwYWRkaW5nO1xuICAgICAgcldpZHRoID0gckhlaWdodCAqIGRvY1NpemU7XG4gICAgICB0b3AgPSAoX2NhbnZhcy5oZWlnaHQgLSBySGVpZ2h0KSAvIDI7XG4gICAgICBwYWRkaW5nID0gKF9jYW52YXMud2lkdGggLSByV2lkdGgpIC8gMjtcbiAgICB9XG5cbiAgICByZXR1cm4geyBwYWRkaW5nLCB0b3AsIHJXaWR0aCwgckhlaWdodCB9O1xuICB9XG4gIGdldCBzbmFwUmVjdGFuZ2xlKCkge1xuICAgIGNvbnN0IF9jYW52YXMgPSB0aGlzLmNhbnZhcy5uYXRpdmVFbGVtZW50O1xuXG4gICAgY29uc3QgYXIgPSB0aGlzLnZpZGVvU2l6ZS53aWR0aCAvIF9jYW52YXMud2lkdGg7XG5cbiAgICBsZXQgeyBwYWRkaW5nLCB0b3AsIHJXaWR0aCwgckhlaWdodCB9ID0gdGhpcy5jYXJkUmVjdGFuZ2xlO1xuXG4gICAgcGFkZGluZyA9IHBhZGRpbmcgKiBhcjtcbiAgICB0b3AgPSB0b3AgKiBhcjtcbiAgICByV2lkdGggPSByV2lkdGggKiBhcjtcbiAgICBySGVpZ2h0ID0gckhlaWdodCAqIGFyO1xuXG4gICAgcmV0dXJuIHsgcGFkZGluZywgdG9wLCByV2lkdGgsIHJIZWlnaHQgfTtcbiAgfVxuXG4gIHByaXZhdGUgc2V0QWN0aXZlQ2FtZXJhKHN0cmVhbTogYW55KSB7XG4gICAgdGhpcy52aWRlb1JlYWR5Lm5leHQoZmFsc2UpO1xuICAgIHRoaXMuc2hvd1ZpZGVvID0gZmFsc2U7XG4gICAgdGhpcy5hY3RpdmVWaWRlb1NldHRpbmdzID0gc3RyZWFtLmdldFZpZGVvVHJhY2tzKClbMF0uZ2V0U2V0dGluZ3MoKTtcbiAgICBjb25zdCBhY3RpdmVEZXZpY2VJZDogc3RyaW5nID1cbiAgICAgIFdlYmNhbUNvbXBvbmVudC5nZXREZXZpY2VJZEZyb21NZWRpYVN0cmVhbVRyYWNrKFxuICAgICAgICBzdHJlYW0uZ2V0VmlkZW9UcmFja3MoKVswXVxuICAgICAgKTtcblxuICAgIGNvbnN0IHZpZGVvVHJhY2sgPSBzdHJlYW0uZ2V0VHJhY2tzKClbMF07XG4gICAgdGhpcy50cmFja1NldHRpbmdzID0gdmlkZW9UcmFjay5nZXRTZXR0aW5ncygpO1xuICAgIHRoaXMuY2FtZXJhU3dpdGNoZWQubmV4dChhY3RpdmVEZXZpY2VJZCk7XG5cbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMuem9uZS5ydW4oKCkgPT4ge1xuICAgICAgICB0aGlzLnJlc2l6ZVN0YWdlKCk7XG4gICAgICAgIHRoaXMuc2hvd1ZpZGVvID0gdHJ1ZTtcbiAgICAgICAgdGhpcy52aWRlb1JlYWR5Lm5leHQodHJ1ZSk7XG5cbiAgICAgICAgaWYgKE1lZGlhU3RyZWFtVHJhY2tQcm9jZXNzb3IpIHtcbiAgICAgICAgICB0aGlzLnRyYWNrUHJvY2Vzc29yID0gbmV3IE1lZGlhU3RyZWFtVHJhY2tQcm9jZXNzb3IodmlkZW9UcmFjayk7XG4gICAgICAgICAgbGV0IGZyYW1lU3RyZWFtID0gdGhpcy50cmFja1Byb2Nlc3Nvci5yZWFkYWJsZTtcbiAgICAgICAgICBpZiAoIXRoaXMuc2h1dGRvd24pIHtcbiAgICAgICAgICAgIHRoaXMud29ya2VyPy5wb3N0TWVzc2FnZShcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHR5cGU6ICdzdGFydCcsXG5cbiAgICAgICAgICAgICAgICBmcmFtZVN0cmVhbTogZnJhbWVTdHJlYW0sXG4gICAgICAgICAgICAgICAgdHJhY2tTZXR0aW5nczogdGhpcy50cmFja1NldHRpbmdzLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICBbZnJhbWVTdHJlYW1dXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSwgNTAwKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0QWN0aXZlVmlkZW9UcmFjaygpOiBNZWRpYVN0cmVhbVRyYWNrIHwgYW55IHtcbiAgICByZXR1cm4gdGhpcy5tZWRpYVN0cmVhbSA/IHRoaXMubWVkaWFTdHJlYW0uZ2V0VmlkZW9UcmFja3MoKVswXSA6IG51bGw7XG4gIH1cblxuICBwcml2YXRlIGlzTWlycm9ySW1hZ2UoKTogYm9vbGVhbiB7XG4gICAgaWYgKCF0aGlzLmdldEFjdGl2ZVZpZGVvVHJhY2soKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vIGNoZWNrIGZvciBleHBsaWNpdCBtaXJyb3Igb3ZlcnJpZGUgcGFyYW1ldGVyXG4gICAge1xuICAgICAgbGV0IG1pcnJvcjogc3RyaW5nID0gJ2F1dG8nO1xuICAgICAgaWYgKHRoaXMubWlycm9ySW1hZ2UpIHtcbiAgICAgICAgaWYgKHR5cGVvZiB0aGlzLm1pcnJvckltYWdlID09PSAnc3RyaW5nJykge1xuICAgICAgICAgIG1pcnJvciA9IFN0cmluZyh0aGlzLm1pcnJvckltYWdlKS50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIFdlYmNhbU1pcnJvclByb3BlcnRpZXNcbiAgICAgICAgICBpZiAodGhpcy5taXJyb3JJbWFnZS54KSB7XG4gICAgICAgICAgICBtaXJyb3IgPSB0aGlzLm1pcnJvckltYWdlLngudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgc3dpdGNoIChtaXJyb3IpIHtcbiAgICAgICAgY2FzZSAnYWx3YXlzJzpcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgY2FzZSAnbmV2ZXInOlxuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBkZWZhdWx0OiBlbmFibGUgbWlycm9yaW5nIGlmIHdlYmNhbSBpcyB1c2VyIGZhY2luZ1xuICAgIHJldHVybiBXZWJjYW1Db21wb25lbnQuaXNVc2VyRmFjaW5nKHRoaXMuZ2V0QWN0aXZlVmlkZW9UcmFjaygpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdG9wcyBhbGwgYWN0aXZlIG1lZGlhIHRyYWNrcy5cbiAgICogVGhpcyBwcmV2ZW50cyB0aGUgd2ViY2FtIGZyb20gYmVpbmcgaW5kaWNhdGVkIGFzIGFjdGl2ZSxcbiAgICogZXZlbiBpZiBpdCBpcyBubyBsb25nZXIgdXNlZCBieSB0aGlzIGNvbXBvbmVudC5cbiAgICovXG4gIHByaXZhdGUgc3RvcE1lZGlhVHJhY2tzKCkge1xuICAgIC8vIHRoaXMudmlkZW8ubmF0aXZlRWxlbWVudC5wYXVzZSgpO1xuICAgIGlmICh0aGlzLnZpZGVvLm5hdGl2ZUVsZW1lbnQuc3JjT2JqZWN0KSB7XG4gICAgICAoKHRoaXMudmlkZW8ubmF0aXZlRWxlbWVudCBhcyBIVE1MVmlkZW9FbGVtZW50KS5zcmNPYmplY3QgYXMgTWVkaWFTdHJlYW0pXG4gICAgICAgIC5nZXRUcmFja3MoKVxuICAgICAgICAuZm9yRWFjaCgodHJhY2spID0+IHtcbiAgICAgICAgICB0cmFjay5zdG9wKCk7XG4gICAgICAgIH0pO1xuICAgICAgdGhpcy52aWRlby5uYXRpdmVFbGVtZW50LnNyY09iamVjdCA9IG51bGw7XG4gICAgICB0aGlzLnZpZGVvLm5hdGl2ZUVsZW1lbnQuc3JjID0gJyc7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMubWVkaWFTdHJlYW0gJiYgdGhpcy5tZWRpYVN0cmVhbS5nZXRUcmFja3MpIHtcbiAgICAgIC8vIGdldFRyYWNrcygpIHJldHVybnMgYWxsIG1lZGlhIHRyYWNrcyAodmlkZW8rYXVkaW8pXG5cbiAgICAgIHRoaXMubWVkaWFTdHJlYW1cbiAgICAgICAgLmdldFRyYWNrcygpXG4gICAgICAgIC5mb3JFYWNoKCh0cmFjazogTWVkaWFTdHJlYW1UcmFjaykgPT4gdHJhY2suc3RvcCgpKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVW5zdWJzY3JpYmUgZnJvbSBhbGwgb3BlbiBzdWJzY3JpcHRpb25zXG4gICAqL1xuICBwcml2YXRlIHVuc3Vic2NyaWJlRnJvbVN1YnNjcmlwdGlvbnMoKSB7XG4gICAgaWYgKHRoaXMudHJpZ2dlclN1YnNjcmlwdGlvbikge1xuICAgICAgdGhpcy50cmlnZ2VyU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgfVxuICAgIGlmICh0aGlzLnN3aXRjaENhbWVyYVN1YnNjcmlwdGlvbikge1xuICAgICAgdGhpcy5zd2l0Y2hDYW1lcmFTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVhZHMgYXZhaWxhYmxlIGlucHV0IGRldmljZXNcbiAgICovXG4gIHByaXZhdGUgZGV0ZWN0QXZhaWxhYmxlRGV2aWNlcygpOiBQcm9taXNlPE1lZGlhRGV2aWNlSW5mb1tdPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIFdlYmNhbVV0aWwuZ2V0QXZhaWxhYmxlVmlkZW9JbnB1dHMoKS5zdWJzY3JpYmUoXG4gICAgICAgIChkZXZpY2VzOiBNZWRpYURldmljZUluZm9bXSkgPT4ge1xuICAgICAgICAgIHRoaXMuYXZhaWxhYmxlVmlkZW9JbnB1dHMgPSBkZXZpY2VzO1xuICAgICAgICAgIHJlc29sdmUoZGV2aWNlcyk7XG4gICAgICAgIH0sXG4gICAgICAgIChlcnIpID0+IHtcbiAgICAgICAgICB0aGlzLmF2YWlsYWJsZVZpZGVvSW5wdXRzID0gW107XG4gICAgICAgICAgcmVqZWN0KGVycik7XG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSk7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJ3ZWJjYW0td3JhcHBlclwiPlxuICA8ZGl2PlxuICAgIDx2aWRlb1xuICAgICAgI3ZpZGVvXG4gICAgICBhdXRvcGxheVxuICAgICAgbXV0ZWRcbiAgICAgIHN0eWxlPVwiZGlzcGxheTogYmxvY2tcIlxuICAgICAgcGxheXNpbmxpbmVcblxuICAgID48L3ZpZGVvPlxuXG4gICAgPGRpdiBjbGFzcz1cInJlY3RhbmdsZVwiPlxuICAgICAgPGNhbnZhc1xuICAgICAgICAjY2FudmFzXG4gICAgICAgIFtuZ1N0eWxlXT1cInsgdmlzaWJpbGl0eTogc2hvd1ZpZGVvID8gJ3Zpc2libGUnIDogJ2hpZGRlbicgfVwiXG4gICAgICAgIFt3aWR0aF09XCJjYW52YXNTaXplLndpZHRoXCJcbiAgICAgICAgW2hlaWdodF09XCJjYW52YXNTaXplLmhlaWdodFwiXG4gICAgICA+PC9jYW52YXM+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuPC9kaXY+XG4iXX0=