speechrecorderng 3.10.13 → 3.11.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 (99) hide show
  1. package/README.md +1 -1
  2. package/fesm2022/speechrecorderng.mjs +204 -201
  3. package/fesm2022/speechrecorderng.mjs.map +1 -1
  4. package/lib/audio/ui/audio_canvas_layer_comp.d.ts +2 -2
  5. package/lib/spr.module.version.d.ts +1 -1
  6. package/lib/ui/canvas_layer_comp.d.ts +1 -1
  7. package/lib/ui/responsive_component.d.ts +1 -1
  8. package/package.json +13 -15
  9. package/esm2022/lib/action/action.mjs +0 -73
  10. package/esm2022/lib/audio/array_audio_buffer.mjs +0 -164
  11. package/esm2022/lib/audio/array_audio_buffer_input_stream.mjs +0 -86
  12. package/esm2022/lib/audio/array_audio_buffer_random_access_stream.mjs +0 -16
  13. package/esm2022/lib/audio/audio_data_holder.mjs +0 -264
  14. package/esm2022/lib/audio/audio_display.mjs +0 -118
  15. package/esm2022/lib/audio/audio_player.mjs +0 -238
  16. package/esm2022/lib/audio/capture/capture.mjs +0 -855
  17. package/esm2022/lib/audio/context.mjs +0 -79
  18. package/esm2022/lib/audio/dsp/level_measure.mjs +0 -517
  19. package/esm2022/lib/audio/format.mjs +0 -20
  20. package/esm2022/lib/audio/impl/wavformat.mjs +0 -7
  21. package/esm2022/lib/audio/impl/wavreader.mjs +0 -144
  22. package/esm2022/lib/audio/impl/wavwriter.mjs +0 -191
  23. package/esm2022/lib/audio/inddb_audio_buffer.mjs +0 -508
  24. package/esm2022/lib/audio/io/stream.mjs +0 -59
  25. package/esm2022/lib/audio/net_audio_buffer.mjs +0 -293
  26. package/esm2022/lib/audio/persistor.mjs +0 -81
  27. package/esm2022/lib/audio/playback/array_audio_buffer_source_node.mjs +0 -126
  28. package/esm2022/lib/audio/playback/audio_source_node.mjs +0 -18
  29. package/esm2022/lib/audio/playback/audio_source_worklet_module_loader.mjs +0 -167
  30. package/esm2022/lib/audio/playback/inddb_audio_buffer_source_node.mjs +0 -167
  31. package/esm2022/lib/audio/playback/net_audio_buffer_source_node.mjs +0 -218
  32. package/esm2022/lib/audio/playback/player.mjs +0 -402
  33. package/esm2022/lib/audio/ui/audio_canvas_layer_comp.mjs +0 -347
  34. package/esm2022/lib/audio/ui/audio_display_control.mjs +0 -150
  35. package/esm2022/lib/audio/ui/audio_display_scroll_pane.mjs +0 -146
  36. package/esm2022/lib/audio/ui/audiosignal.mjs +0 -533
  37. package/esm2022/lib/audio/ui/common.mjs +0 -19
  38. package/esm2022/lib/audio/ui/container.mjs +0 -414
  39. package/esm2022/lib/audio/ui/livelevel.mjs +0 -361
  40. package/esm2022/lib/audio/ui/scroll_pane_horizontal.mjs +0 -11
  41. package/esm2022/lib/audio/ui/sonagram.mjs +0 -900
  42. package/esm2022/lib/db/inddb.mjs +0 -120
  43. package/esm2022/lib/dsp/utils.mjs +0 -48
  44. package/esm2022/lib/environment/environment.defaults.mjs +0 -9
  45. package/esm2022/lib/io/BinaryReader.mjs +0 -93
  46. package/esm2022/lib/io/BinaryWriter.mjs +0 -80
  47. package/esm2022/lib/io/stream.mjs +0 -259
  48. package/esm2022/lib/math/2d/geometry.mjs +0 -28
  49. package/esm2022/lib/math/complex.mjs +0 -58
  50. package/esm2022/lib/math/dft.mjs +0 -196
  51. package/esm2022/lib/media/utils.mjs +0 -14
  52. package/esm2022/lib/net/uploader.mjs +0 -367
  53. package/esm2022/lib/recorder_component.mjs +0 -65
  54. package/esm2022/lib/speechrecorder/project/project.mjs +0 -54
  55. package/esm2022/lib/speechrecorder/project/project.service.mjs +0 -64
  56. package/esm2022/lib/speechrecorder/recording.mjs +0 -124
  57. package/esm2022/lib/speechrecorder/recordings/basic_recording.service.mjs +0 -221
  58. package/esm2022/lib/speechrecorder/recordings/recordings.service.mjs +0 -1014
  59. package/esm2022/lib/speechrecorder/script/script.mjs +0 -114
  60. package/esm2022/lib/speechrecorder/script/script.service.mjs +0 -47
  61. package/esm2022/lib/speechrecorder/session/audiorecorder.mjs +0 -1179
  62. package/esm2022/lib/speechrecorder/session/basicrecorder.mjs +0 -676
  63. package/esm2022/lib/speechrecorder/session/controlpanel.mjs +0 -416
  64. package/esm2022/lib/speechrecorder/session/item.mjs +0 -30
  65. package/esm2022/lib/speechrecorder/session/progress.mjs +0 -135
  66. package/esm2022/lib/speechrecorder/session/prompting.mjs +0 -639
  67. package/esm2022/lib/speechrecorder/session/recorder_combi_pane.mjs +0 -88
  68. package/esm2022/lib/speechrecorder/session/recording_file_cache.mjs +0 -195
  69. package/esm2022/lib/speechrecorder/session/recording_list.mjs +0 -188
  70. package/esm2022/lib/speechrecorder/session/recordingfile/recording-file-meta.component.mjs +0 -128
  71. package/esm2022/lib/speechrecorder/session/recordingfile/recording-file-navi.component.mjs +0 -114
  72. package/esm2022/lib/speechrecorder/session/recordingfile/recording-file-u-i.component.mjs +0 -146
  73. package/esm2022/lib/speechrecorder/session/recordingfile/recording-file-view.component.mjs +0 -424
  74. package/esm2022/lib/speechrecorder/session/recordingfile/recording-file.mjs +0 -68
  75. package/esm2022/lib/speechrecorder/session/recordingfile/recordingfile-service.mjs +0 -288
  76. package/esm2022/lib/speechrecorder/session/session.mjs +0 -2
  77. package/esm2022/lib/speechrecorder/session/session.service.mjs +0 -69
  78. package/esm2022/lib/speechrecorder/session/session_finished_dialog.mjs +0 -46
  79. package/esm2022/lib/speechrecorder/session/sessionmanager.mjs +0 -1385
  80. package/esm2022/lib/speechrecorder/session/warning_bar.mjs +0 -33
  81. package/esm2022/lib/speechrecorder/spruploader.mjs +0 -22
  82. package/esm2022/lib/speechrecorder/startstopsignal/startstopsignal.mjs +0 -2
  83. package/esm2022/lib/speechrecorder/startstopsignal/ui/simpletrafficlight.mjs +0 -57
  84. package/esm2022/lib/speechrecorderng.component.mjs +0 -392
  85. package/esm2022/lib/speechrecorderng.module.mjs +0 -97
  86. package/esm2022/lib/spr.config.mjs +0 -27
  87. package/esm2022/lib/spr.module.version.mjs +0 -2
  88. package/esm2022/lib/ui/canvas_layer_comp.mjs +0 -38
  89. package/esm2022/lib/ui/intersection-observer.directive.mjs +0 -32
  90. package/esm2022/lib/ui/message_dialog.mjs +0 -51
  91. package/esm2022/lib/ui/recordingitem_display.mjs +0 -253
  92. package/esm2022/lib/ui/responsive_component.mjs +0 -24
  93. package/esm2022/lib/utils/scrollIntoViewToBottom.mjs +0 -23
  94. package/esm2022/lib/utils/ua-parser.mjs +0 -190
  95. package/esm2022/lib/utils/utils.mjs +0 -132
  96. package/esm2022/lib/utils/wake_lock.mjs +0 -114
  97. package/esm2022/lib/utils/wake_lock_media.mjs +0 -2
  98. package/esm2022/public-api.mjs +0 -35
  99. package/esm2022/speechrecorderng.mjs +0 -5
@@ -1,855 +0,0 @@
1
- import { Browser, Platform, UserAgentBuilder } from "../../utils/ua-parser";
2
- import { AudioStorageType, Platform as CfgPlatform } from "../../speechrecorder/project/project";
3
- import { ArrayAudioBuffer } from "../array_audio_buffer";
4
- import { UUID } from "../../utils/utils";
5
- import { IndexedDbAudioBuffer } from "../inddb_audio_buffer";
6
- import { AudioContextProvider } from "../context";
7
- export const CHROME_ACTIVATE_ECHO_CANCELLATION_WITH_AGC = false;
8
- const DEBUG_TRACE_LEVEL = 0;
9
- // Dirty way to load this module
10
- // Copy content of interceptor_worklet.js to this string
11
- const awpStr = "class AudioCaptureInterceptorProcessor extends AudioWorkletProcessor{\n" +
12
- "\n" +
13
- " BUFFER_QUANTUMS=64;\n" +
14
- " QUANTUM_FRAME_LEN=128;\n" +
15
- " BUFFER_FRAME_LEN=this.QUANTUM_FRAME_LEN*this.BUFFER_QUANTUMS;\n" +
16
- " buffer=null;\n" +
17
- " bufferPos=0;\n" +
18
- " bufferPosBytes=0;\n" +
19
- " constructor() {\n" +
20
- " super();\n" +
21
- "\n" +
22
- " }\n" +
23
- "\n" +
24
- " process(\n" +
25
- " inputs,\n" +
26
- " outputs,\n" +
27
- " parameters\n" +
28
- " ){\n" +
29
- "\n" +
30
- " let inputsCnt=inputs.length;\n" +
31
- " let channelCount=0;\n" +
32
- " let inputLen=0;\n" +
33
- " let inputLenBytes=0;\n" +
34
- " if(inputsCnt>0) {\n" +
35
- " let input0 = inputs[0];\n" +
36
- " channelCount = input0.length;\n" +
37
- " if (channelCount > 0) {\n" +
38
- " let input0ch0=input0[0];\n" +
39
- " inputLen=input0ch0.length;\n" +
40
- " inputLenBytes=input0ch0.buffer.length;\n" +
41
- " }\n" +
42
- " }\n" +
43
- " if (!this.buffer || this.buffer.length < channelCount) {\n" +
44
- " this.buffer = new Array(channelCount);\n" +
45
- " this.bufferPos = 0\n" +
46
- " for (let bch = 0; bch < channelCount; bch++) {\n" +
47
- " this.buffer[bch] = new Float32Array(this.BUFFER_FRAME_LEN);\n" +
48
- " this.bufferPos = 0;\n" +
49
- " this.bufferPosBytes=0;\n" +
50
- " }\n" +
51
- " }\n" +
52
- " let bufAvail = this.BUFFER_FRAME_LEN - this.bufferPos;\n" +
53
- " // check if buffer has to be transferred\n" +
54
- " if (inputLen > bufAvail) {\n" +
55
- " let ada=new Array(channelCount);\n" +
56
- " for (let ch = 0; ch < channelCount; ch++) {\n" +
57
- " ada[ch]=this.buffer[ch].buffer.slice(0);\n" +
58
- " }\n" +
59
- " this.port.postMessage({\n" +
60
- " data: ada,\n" +
61
- " chs: channelCount,\n" +
62
- " len: this.bufferPos\n" +
63
- " }, ada);\n" +
64
- " // buffer transferred, reset\n" +
65
- " this.bufferPos = 0;\n" +
66
- " this.bufferPosBytes=0;\n" +
67
- " }\n" +
68
- "\n" +
69
- " for(let ii=0;ii<inputsCnt;ii++) {\n" +
70
- " for (let ch = 0; ch < channelCount; ch++) {\n" +
71
- " // Mute outputs\n" +
72
- " //outputs[ii][ch].fill(0);\n" +
73
- " let chSamples = inputs[ii][ch];\n" +
74
- " this.buffer[ch].set(chSamples,this.bufferPos);\n" +
75
- " }\n" +
76
- " this.bufferPos+=inputLen;\n" +
77
- " this.bufferPosBytes+=inputLenBytes;\n" +
78
- " }\n" +
79
- " \n" +
80
- " return true;\n" +
81
- " }\n" +
82
- "}\n" +
83
- "\n" +
84
- "registerProcessor('capture-interceptor',AudioCaptureInterceptorProcessor);\n";
85
- export class AudioCapture {
86
- get maxAutoNetMemStoreSamples() {
87
- return this._maxAutoNetMemStoreSamples;
88
- }
89
- set maxAutoNetMemStoreSamples(value) {
90
- this._maxAutoNetMemStoreSamples = value;
91
- }
92
- set recUUID(value) {
93
- this._recUUID = value;
94
- }
95
- get recUUID() {
96
- return this._recUUID;
97
- }
98
- get audioStorageType() {
99
- return this._audioStorageType;
100
- }
101
- set audioStorageType(value) {
102
- this._audioStorageType = value;
103
- }
104
- get persistentAudioStorageTarget() {
105
- return this._persistentAudioStorageTarget;
106
- }
107
- set persistentAudioStorageTarget(value) {
108
- this._persistentAudioStorageTarget = value;
109
- }
110
- get opened() {
111
- return this._opened;
112
- }
113
- static { this.BUFFER_SIZE = 8192; }
114
- static { this.DEFAULT_MAX_NET_AUTO_MEM_STORE_SAMPLES = 2880000 * 5; } // Default 5 minute at 48kHz
115
- static { this.captureInterceptorModuleRegistered = false; }
116
- //private context:AudioContext|null=null;
117
- constructor() {
118
- this._maxAutoNetMemStoreSamples = AudioCapture.DEFAULT_MAX_NET_AUTO_MEM_STORE_SAMPLES;
119
- this.context = null;
120
- this._recUUID = null;
121
- this.agcStatus = null;
122
- this.bufferingNode = null;
123
- this.data = null;
124
- this.audioOutStream = null;
125
- this.disconnectStreams = true;
126
- this._opened = false;
127
- this.capturing = false;
128
- this.framesRecorded = 0;
129
- this._audioStorageType = AudioStorageType.MEM_ENTIRE;
130
- this._persistentAudioStorageTarget = null;
131
- this.persisted = true;
132
- this.persistError = null;
133
- this.inddbAudioBuffer = null;
134
- this.n = navigator;
135
- }
136
- _audioContext() {
137
- if (!this.context) {
138
- this.context = AudioContextProvider.audioContextInstance();
139
- if (this.context) {
140
- this.context.addEventListener('statechange', () => {
141
- if (this.context && this.context.state !== 'running') {
142
- this.close();
143
- }
144
- });
145
- }
146
- }
147
- return this.context;
148
- }
149
- initData() {
150
- if (!this._recUUID) {
151
- this._recUUID = UUID.generate();
152
- }
153
- this.persistError = null;
154
- //console.debug("Audio capture initialize storage for type: "+this._audioStorageType);
155
- if (AudioStorageType.DB_CHUNKED === this._audioStorageType && this._persistentAudioStorageTarget && this._recUUID) {
156
- //console.debug("Create indexed db audio buffer.");
157
- this.inddbAudioBuffer = new IndexedDbAudioBuffer(this._persistentAudioStorageTarget, this.channelCount, this.currentSampleRate, AudioCapture.BUFFER_SIZE, 0, this._recUUID);
158
- }
159
- if (!(AudioStorageType.NET_CHUNKED === this._audioStorageType)) {
160
- // Initialize audio data array except for net audio buffer mode
161
- this.data = new Array();
162
- for (let i = 0; i < this.channelCount; i++) {
163
- this.data.push(new Array());
164
- }
165
- }
166
- this.framesRecorded = 0;
167
- }
168
- listDevices() {
169
- navigator.mediaDevices.enumerateDevices().then((l) => this.printDevices(l));
170
- }
171
- dummySession() {
172
- // workaround to request permissions:
173
- // Start a dummy session
174
- let mediaStrCnstrs = { audio: { echoCancelation: false }
175
- };
176
- return navigator.mediaDevices.getUserMedia(mediaStrCnstrs);
177
- }
178
- stopAllSessionTracks(mediaStream) {
179
- let ats = mediaStream.getTracks();
180
- for (let atIdx = 0; atIdx < ats.length; atIdx++) {
181
- //console.debug("Stop dummy session track: #" + atIdx)
182
- ats[atIdx].stop();
183
- }
184
- }
185
- deviceInfos(cb, retry = true, dummyStream) {
186
- navigator.mediaDevices.enumerateDevices().then((l) => {
187
- let labelsAvailable = false;
188
- for (let i = 0; i < l.length; i++) {
189
- let di = l[i];
190
- if (di.label) {
191
- labelsAvailable = true;
192
- }
193
- }
194
- if (!labelsAvailable) {
195
- //console.debug("Media device enumeration: No labels.")
196
- if (retry) {
197
- console.info("Starting dummy session to request audio permissions...");
198
- this.dummySession().then((s) => {
199
- // and stop it immediately
200
- if (s) {
201
- //console.debug("Got dummy session stream: " + s + " .")
202
- }
203
- else {
204
- //console.debug("No dummy stream")
205
- }
206
- // retry (only once)
207
- this.deviceInfos(cb, false, s);
208
- }, reason => {
209
- //console.debug("Dummy session rejected.")
210
- // TODO error callback
211
- cb(null);
212
- });
213
- }
214
- else {
215
- cb(null);
216
- }
217
- }
218
- else {
219
- // success
220
- cb(l);
221
- }
222
- if (dummyStream) {
223
- this.stopAllSessionTracks(dummyStream);
224
- }
225
- }, (reason) => {
226
- //rejected
227
- //console.debug("Media device enumeration rejected.")
228
- if (retry) {
229
- //console.debug("Starting dummy session to request audio permissions...")
230
- this.dummySession().then((s) => {
231
- // and stop it immediately
232
- //console.debug("Dummy session.")
233
- if (s) {
234
- //console.debug("Got dummy session stream: " + s + " .")
235
- }
236
- else {
237
- //console.debug("No dummy stream")
238
- }
239
- // retry (only once)
240
- this.deviceInfos(cb, false, s);
241
- }, reason => {
242
- //console.debug("Dummy session rejected.")
243
- // TODO error callback
244
- cb(null);
245
- });
246
- }
247
- else {
248
- cb(null);
249
- }
250
- if (dummyStream) {
251
- this.stopAllSessionTracks(dummyStream);
252
- }
253
- });
254
- }
255
- printDevices(l) {
256
- //let selDeviceId = '___dummy___';
257
- for (let i = 0; i < l.length; i++) {
258
- let di = l[i];
259
- console.log("Audio device: Id: " + di.deviceId + " groupId: " + di.groupId + " label: " + di.label + " kind: " + di.kind);
260
- }
261
- }
262
- addCaptureInterceptor() {
263
- if (this.context) {
264
- const awn = new AudioWorkletNode(this.context, 'capture-interceptor');
265
- awn.onprocessorerror = (ev) => {
266
- let msg = 'Unknwon error';
267
- if (ev instanceof ErrorEvent) {
268
- msg = ev.message;
269
- }
270
- console.error("Capture audio worklet error: " + msg);
271
- if (this.listener) {
272
- this.listener.error(msg);
273
- }
274
- };
275
- let awnPt = awn.port;
276
- if (awnPt) {
277
- awnPt.onmessage = (ev) => {
278
- if (this.capturing) {
279
- let dt = ev.data;
280
- let chs = dt.chs;
281
- let adaLen = dt.data.length;
282
- if (DEBUG_TRACE_LEVEL > 8) {
283
- console.debug('Received data from worklet: ' + chs + ' ' + dt.len + ' Data chs: ' + adaLen);
284
- }
285
- let chunk = new Array(chs);
286
- const samples = this.framesRecorded * chs;
287
- if ((AudioStorageType.MEM_ENTIRE_AUTO_NET_CHUNKED === this.audioStorageType || AudioStorageType.MEM_CHUNKED_AUTO_NET_CHUNKED === this.audioStorageType) && this.data && samples > this._maxAutoNetMemStoreSamples) {
288
- this.data = null;
289
- }
290
- //console.debug("Data initialized: "+(this.data!=null));
291
- for (let ch = 0; ch < chs; ch++) {
292
- //console.debug("Data ch initialized: "+(this.data !=null && this.data[ch] !=null));
293
- if (ch < this.channelCount) {
294
- if (dt.data[ch]) {
295
- let fa = new Float32Array(dt.data[ch]);
296
- if (this.data && this.data[ch]) {
297
- this.data[ch].push(fa);
298
- }
299
- chunk[ch] = fa;
300
- // Use samples of channel 0 to count frames (samples)
301
- if (ch == 0) {
302
- this.framesRecorded += fa.length;
303
- }
304
- }
305
- }
306
- }
307
- if (this.audioOutStream) {
308
- try {
309
- this.audioOutStream.write(chunk);
310
- // // Random test error:
311
- // if(Math.random()>0.98) {
312
- // throw new Error('Test');
313
- // }
314
- }
315
- catch (err) {
316
- if (err instanceof Error) {
317
- this.persistError = err;
318
- }
319
- else {
320
- this.persistError = new Error('Error handling recorded audio data');
321
- }
322
- console.error("Capture error: " + err);
323
- try {
324
- this.stop();
325
- }
326
- catch (err2) {
327
- console.error("Capture next error (ignored): " + err2);
328
- }
329
- finally {
330
- if (this.listener) {
331
- let errExpl = '';
332
- if (err instanceof DOMException) {
333
- errExpl = ': ' + err.name + ': ' + err.message;
334
- }
335
- this.listener.error("Could not handle recorded audio data" + errExpl, "Please try to record again.");
336
- }
337
- else {
338
- this.close();
339
- }
340
- }
341
- }
342
- }
343
- if (AudioStorageType.DB_CHUNKED === this._audioStorageType && this._persistentAudioStorageTarget) {
344
- this.store();
345
- }
346
- }
347
- };
348
- }
349
- // Tried to fix that Safari does not record the second channel
350
- // Does not help
351
- //awn.channelCount=this.channelCount;
352
- //awn.channelCountMode='explicit';
353
- //console.debug('Channel count explicitly set to '+this.channelCount);
354
- this.bufferingNode = awn;
355
- //this.bufferingNode.channelCount=this.channelCount;
356
- this._opened = true;
357
- if (this.listener) {
358
- this.listener.opened();
359
- }
360
- }
361
- }
362
- open(channelCount, selDeviceId, autoGainControlConfigs, allowEchoCancellation) {
363
- //console.debug("Capture open: ctx state: "+this.context.state);
364
- this.context = this._audioContext();
365
- if (!this.context) {
366
- throw new Error("Could not get audio context!");
367
- }
368
- if (this.context.state === 'suspended') {
369
- //console.debug("Capture open: Resume context");
370
- this.context.resume().then(() => {
371
- //console.debug("Capture open (ctx resumed): ctx state: "+this.context.state);
372
- this._open(channelCount, selDeviceId, autoGainControlConfigs, allowEchoCancellation);
373
- }).catch((err) => {
374
- console.error(err.message);
375
- throw err;
376
- });
377
- }
378
- else if (this.context.state === 'closed') {
379
- const msg = 'Error on start capture: The audio context is already closed.';
380
- console.error(msg);
381
- throw new Error(msg);
382
- }
383
- else {
384
- this._open(channelCount, selDeviceId, autoGainControlConfigs, allowEchoCancellation);
385
- }
386
- }
387
- _open(channelCount, selDeviceId, autoGainControlConfigs, allowEchoCancellation) {
388
- this.channelCount = channelCount;
389
- this.framesRecorded = 0;
390
- this.context = this._audioContext();
391
- if (!this.context) {
392
- throw new Error("Could not get audio context!");
393
- }
394
- //var msc = new AudioStreamConstr();
395
- // var msc={};
396
- //msc.video = false;
397
- //msc.audio = true;
398
- // Chrome and Firefox stereo channels are identical !!
399
- // And even worse: The data coming from the source is already preprocessed on FF and Chrome. It contains DSP artifacts!!
400
- // https://bugs.chromium.org/p/chromium/issues/detail?id=387737
401
- // The workaround to set these constraints does _NOT_ help:
402
- //var msc={audio: {echoCancellation: false,channelCount: 2, googAudioMirroring: false},video: false};
403
- // Safari at least version 11: Support for media streams
404
- // TODO test if input is unprocessed
405
- let msc;
406
- console.info('User agent: ' + navigator.userAgent);
407
- let ua = UserAgentBuilder.userAgent();
408
- // ua.components.forEach((c)=>{
409
- // console.info("UA_Comp: "+c.toString());
410
- // })
411
- let agcCfg = null;
412
- let autoGainControl = false;
413
- let chromeEchoCancellation = false;
414
- if (autoGainControlConfigs) {
415
- for (let agcc of autoGainControlConfigs) {
416
- if (agcc.platform === CfgPlatform.Android && ua.detectedPlatform === Platform.Android) {
417
- agcCfg = agcc;
418
- break;
419
- }
420
- if (agcc.platform === CfgPlatform.Windows && ua.detectedPlatform === Platform.Windows) {
421
- agcCfg = agcc;
422
- break;
423
- }
424
- }
425
- if (agcCfg) {
426
- // TODO use EXACT/IDEAL constraint
427
- autoGainControl = agcCfg.value;
428
- if (CHROME_ACTIVATE_ECHO_CANCELLATION_WITH_AGC) {
429
- chromeEchoCancellation = agcCfg.value;
430
- }
431
- // TODO query real AGC status
432
- this.agcStatus = agcCfg.value;
433
- }
434
- else {
435
- this.agcStatus = false;
436
- }
437
- }
438
- // default
439
- msc = {
440
- audio: {
441
- deviceId: selDeviceId,
442
- echoCancellation: false,
443
- channelCount: channelCount,
444
- autoGainControl: autoGainControl
445
- },
446
- video: false
447
- };
448
- if (ua.detectedBrowser === Browser.Edge) {
449
- // Microsoft Edge sends unmodified audio
450
- // The constraint can follow the specification
451
- console.info("Setting media track constraints for Microsoft Edge.");
452
- msc = {
453
- audio: {
454
- deviceId: selDeviceId,
455
- echoCancellation: false,
456
- channelCount: channelCount,
457
- autoGainControl: autoGainControl
458
- },
459
- video: false
460
- };
461
- }
462
- else if (ua.detectedBrowser === Browser.Chrome) {
463
- // Google Chrome: we need to switch of each of the preprocessing units including the
464
- console.info("Setting media track constraints for Google Chrome.");
465
- // Chrome 60 -> 61 changed
466
- // it works now without mandatory/optional sub-objects
467
- // Requires at least Chrome 61
468
- msc = {
469
- audio: {
470
- deviceId: selDeviceId,
471
- channelCount: channelCount,
472
- echoCancellation: { exact: chromeEchoCancellation },
473
- autoGainControl: { exact: autoGainControl },
474
- sampleSize: { min: 16 },
475
- },
476
- video: false,
477
- };
478
- }
479
- else if (ua.detectedBrowser === Browser.Firefox) {
480
- console.info("Setting media track constraints for Mozilla Firefox.");
481
- // Firefox
482
- msc = {
483
- audio: {
484
- deviceId: selDeviceId,
485
- channelCount: channelCount,
486
- echoCancellation: false,
487
- autoGainControl: autoGainControl,
488
- noiseSuppression: false
489
- },
490
- video: false,
491
- };
492
- }
493
- else if (ua.detectedBrowser === Browser.Safari) {
494
- console.info("Setting media track constraints for Safari browser.");
495
- //console.info("Apply workaround for Safari: Avoid disconnect of streams.");
496
- this.disconnectStreams = true;
497
- msc = {
498
- audio: {
499
- deviceId: selDeviceId,
500
- channelCount: channelCount,
501
- echoCancellation: allowEchoCancellation ? undefined : false
502
- },
503
- video: false,
504
- };
505
- }
506
- else {
507
- // TODO default constraints or error Browser not supported
508
- }
509
- console.debug("Audio capture, AGC: " + this.agcStatus);
510
- let ump = navigator.mediaDevices.getUserMedia(msc);
511
- ump.then((s) => {
512
- if (this.context) {
513
- this.stream = s;
514
- let aTracks = s.getAudioTracks();
515
- for (let i = 0; i < aTracks.length; i++) {
516
- let aTrack = aTracks[i];
517
- console.info("Track audio info: id: " + aTrack.id + " kind: " + aTrack.kind + " label: \"" + aTrack.label + "\"");
518
- let mtrSts = aTrack.getSettings();
519
- // Typescript lib.dom.ts MediaTrackSettings.channelCount is missing
520
- // https://github.com/mdn/browser-compat-data/blob/5493d8f937e05b2ddbd41b99f5bdfad4a1f2ed85/api/MediaTrackSettings.json
521
- //@ts-ignore
522
- console.info("Track audio settings: Ch cnt: " + mtrSts.channelCount + ", AGC: " + mtrSts.autoGainControl + ", Echo cancell.: " + mtrSts.echoCancellation);
523
- if (mtrSts.autoGainControl) {
524
- this.agcStatus = mtrSts.autoGainControl;
525
- }
526
- console.debug("Echo cancellation: " + mtrSts.echoCancellation);
527
- }
528
- let vTracks = s.getVideoTracks();
529
- for (let i = 0; i < vTracks.length; i++) {
530
- let vTrack = vTracks[i];
531
- console.info("Track video info: id: " + vTrack.id + " kind: " + vTrack.kind + " label: " + vTrack.label);
532
- }
533
- this.mediaStream = this.context.createMediaStreamSource(s);
534
- // stream channel count ( is always 2 !)
535
- let streamChannelCount = this.mediaStream.channelCount;
536
- console.info("Stream channel count: " + streamChannelCount);
537
- // is not set!!
538
- //this.currentSampleRate = this.mediaStream.sampleRate;
539
- this.currentSampleRate = this.context.sampleRate;
540
- console.info("Source audio node: channels: " + streamChannelCount + " samplerate: " + this.currentSampleRate);
541
- if (this.audioOutStream) {
542
- this.audioOutStream.setFormat(this.channelCount, this.currentSampleRate);
543
- }
544
- // W3C -> new name is createScriptProcessor
545
- //
546
- // Again deprecated, but AudioWorker not yet implemented in stable releases (June 2016)
547
- // AudioWorker is now AudioWorkletProcessor ... (May 2017)
548
- // Update 12-2020:
549
- // The ScriptProcessorNode Interface - DEPRECATED
550
- // Update 06-2021
551
- // AudioWorkletProcessor is here to stay. Web Audio API has now Recommendation status !
552
- if (this.context.audioWorklet) {
553
- //const workletFileName = ('file-loader!./interceptor_worklet.js');
554
- //const workletFileName = 'http://localhost:4200/assets/interceptor_worklet.js';
555
- //console.log(awpStr);
556
- if (AudioCapture.captureInterceptorModuleRegistered) {
557
- // Required capture interceptor module already registered
558
- this.addCaptureInterceptor();
559
- }
560
- else {
561
- // Register capture interceptor module
562
- let audioWorkletModuleBlob = new Blob([awpStr], { type: 'text/javascript' });
563
- let audioWorkletModuleBlobUrl = window.URL.createObjectURL(audioWorkletModuleBlob);
564
- this.context.audioWorklet.addModule(audioWorkletModuleBlobUrl).then(() => {
565
- AudioCapture.captureInterceptorModuleRegistered = true;
566
- this.addCaptureInterceptor();
567
- }).catch((error) => {
568
- console.log('Could not add module ' + error);
569
- });
570
- }
571
- }
572
- else if (this.context.createScriptProcessor) {
573
- // The ScriptProcessorNode Interface - DEPRECATED Only as fallback
574
- // TODO should we use streamChannelCount or channelCount here ?
575
- let scriptProcessorNode = this.context.createScriptProcessor(AudioCapture.BUFFER_SIZE, streamChannelCount, streamChannelCount);
576
- this.bufferingNode = scriptProcessorNode;
577
- let c = 0;
578
- if (scriptProcessorNode.onaudioprocess) {
579
- scriptProcessorNode.onaudioprocess = (e) => {
580
- if (this.capturing) {
581
- let inBuffer = e.inputBuffer;
582
- // only process requested count of channels
583
- let currentBuffers = new Array(channelCount);
584
- for (let ch = 0; ch < channelCount; ch++) {
585
- let chSamples = inBuffer.getChannelData(ch);
586
- let chSamplesCopy = chSamples.slice(0);
587
- currentBuffers[ch] = chSamplesCopy.slice(0);
588
- if (this.data) {
589
- this.data[ch].push(chSamplesCopy);
590
- }
591
- if (DEBUG_TRACE_LEVEL > 8) {
592
- console.debug("Process " + chSamplesCopy.length + " samples.");
593
- }
594
- this.framesRecorded += chSamplesCopy.length;
595
- }
596
- c++;
597
- if (this.audioOutStream) {
598
- this.audioOutStream.write(currentBuffers);
599
- }
600
- }
601
- };
602
- this._opened = true;
603
- if (this.listener) {
604
- this.listener.opened();
605
- }
606
- }
607
- else {
608
- this.listener.error('Browser does not support audio processing (ScriptProcessor.onaudioprocess method not found)!');
609
- }
610
- }
611
- else {
612
- this.listener.error('Browser does not support audio processing (neither AudioWorkletProcessor nor ScriptProcessor)!');
613
- }
614
- }
615
- }, (e) => {
616
- console.error(e + " Error name: " + e.name);
617
- if (this.listener) {
618
- if ('NotAllowedError' === e.name) {
619
- this.listener.error('Not allowed to use your microphone.', 'Please make sure that microphone access is allowed for this web page and reload the page.');
620
- }
621
- else if ('NotReadableError' === e.name) {
622
- this.listener.error('Could not read from your audio device.', 'Please make sure your audio device is working.');
623
- }
624
- else if ('OverconstrainedError' === e.name) {
625
- let eMsg = e.msg ? e.msg : 'Overconstrained media device request error.';
626
- this.listener.error(eMsg);
627
- }
628
- else {
629
- this.listener.error();
630
- }
631
- }
632
- });
633
- }
634
- _start() {
635
- if (this.context) {
636
- this.initData();
637
- if (this.audioOutStream) {
638
- this.audioOutStream.nextStream();
639
- }
640
- this.capturing = true;
641
- if (this.bufferingNode) {
642
- this.mediaStream.connect(this.bufferingNode);
643
- this.bufferingNode.connect(this.context.destination);
644
- }
645
- if (this.listener) {
646
- this.listener.started();
647
- }
648
- }
649
- }
650
- start() {
651
- if (this.context) {
652
- const aSt = this.context.state;
653
- if (aSt === 'running') {
654
- this._start();
655
- }
656
- else {
657
- console.debug("Capture start: audio context not running, state: " + aSt + ", resuming...");
658
- this.context.resume().then(() => {
659
- console.debug("Capture start: audio context resumed, starting...");
660
- this._start();
661
- });
662
- }
663
- }
664
- }
665
- stop() {
666
- if (this.disconnectStreams && this.bufferingNode) {
667
- this.mediaStream.disconnect(this.bufferingNode);
668
- if (this.context) {
669
- this.bufferingNode.disconnect(this.context.destination);
670
- }
671
- }
672
- try {
673
- if (this.audioOutStream) {
674
- this.audioOutStream.flush();
675
- }
676
- }
677
- catch (err) {
678
- console.error("Could not flush capture stream.");
679
- throw err;
680
- }
681
- finally {
682
- this.capturing = false;
683
- if (this.inddbAudioBuffer && this.persistError) {
684
- // Delete invalid persistent audio data and hope that it will be completely uploaded to the server
685
- this.inddbAudioBuffer.releaseAudioData();
686
- this.inddbAudioBuffer = null;
687
- }
688
- if (this.listener && (this.persistError || this.persisted)) {
689
- //console.debug("Stopped by stop() method call");
690
- this.listener.stopped();
691
- }
692
- }
693
- }
694
- store() {
695
- // if(this.db && this.recUUID){
696
- // let tr= this.db.transaction(SprDb.RECORDING_FILE_CHUNKS_OBJECT_STORE_NAME, 'readwrite');
697
- // let recFileObjStore = tr.objectStore(SprDb.RECORDING_FILE_CHUNKS_OBJECT_STORE_NAME);
698
- //
699
- // try {
700
- // let ch0Data=this.data[0];
701
- // let dataChkCnt=ch0Data.length;
702
- // let pos = 0;
703
- // for (let chCkIdx = 0; chCkIdx < dataChkCnt; chCkIdx++) {
704
- // let bufLen=0;
705
- // for (let ch = 0; ch < this.channelCount; ch++) {
706
- // let chChk = this.data[ch][chCkIdx];
707
- // bufLen = chChk.length;
708
- // //let cacheId = uuid + '_' + ch + '_' + chCkIdx;
709
- // let chkDbId = [this.recUUID, this.indDbChkIdx + chCkIdx, ch];
710
- // let cr = recFileObjStore.add(chChk, chkDbId);
711
- // //console.debug("Added: "+ch+" "+(this.indDbChkIdx+chCkIdx));
712
- // cr.onsuccess=()=>{
713
- // //console.debug("Stored audio data to indexed db");
714
- // }
715
- // cr.onerror=()=>{
716
- // console.error("Error storing audio data to indexed db");
717
- // }
718
- // }
719
- // pos += bufLen;
720
- // }
721
- // this.indDbChkIdx+=dataChkCnt;
722
- //
723
- // tr.onerror = (err) => {
724
- // console.error('Failed to cache audio data to indexed db: ' + err)
725
- // }
726
- // tr.oncomplete = () => {
727
- // //console.debug('Transferred capture audio data to indexed db, deleting original data from memory...');
728
- //
729
- // /// Audio data saved to index db delete from in memory data array
730
- // for (let ch = 0; ch < this.channelCount; ch++) {
731
- // this.data[ch].splice(0);
732
- // //console.debug("Spliced/removed ch: "+ch);
733
- // }
734
- //
735
- // this.persisted=true;
736
- // if(this.listener && !this.capturing){
737
- // //console.debug("Stopped by indexed db hook");
738
- // this.listener.stopped();
739
- // }
740
- // }
741
- // // Commit chunks
742
- // this.persisted=false;
743
- // tr.commit();
744
- // } catch (err) {
745
- // console.error('Transfer capture audio data error: '+err);
746
- // }
747
- // }
748
- // if(!this.inddbAudioBuffer && this._persistentAudioStorageTarget && this.recUUID) {
749
- // this.inddbAudioBuffer = new IndexedDbAudioBuffer(this._persistentAudioStorageTarget, this.channelCount,this.currentSampleRate,AudioCapture.BUFFER_SIZE,0,this.recUUID)
750
- // }
751
- if (this.inddbAudioBuffer && this.data) {
752
- // Try to append to
753
- this.inddbAudioBuffer.appendRawAudioData(this.data).subscribe({
754
- complete: () => {
755
- //console.debug('Transferred capture audio data to indexed db, deleting original data from memory...');
756
- /// Audio data saved to index db delete from in memory data array
757
- if (this.data) {
758
- for (let ch = 0; ch < this.channelCount; ch++) {
759
- this.data[ch].splice(0);
760
- //console.debug("Spliced/removed ch: "+ch);
761
- }
762
- }
763
- this.persisted = true;
764
- if (this.listener && !this.capturing) {
765
- //console.debug("Stopped by indexed db hook");
766
- this.listener.stopped();
767
- }
768
- }, error: (err) => {
769
- // Only log the first error
770
- if (!this.persistError) {
771
- this.persistError = err;
772
- console.error("Error persisting audio data: " + err);
773
- }
774
- }
775
- });
776
- this.persisted = false;
777
- }
778
- }
779
- close() {
780
- if (this.mediaStream) {
781
- this.mediaStream.disconnect();
782
- }
783
- if (this.stream) {
784
- const mts = this.stream.getTracks();
785
- for (let i = 0; i < mts.length; i++) {
786
- mts[i].stop();
787
- }
788
- }
789
- this._opened = false;
790
- }
791
- audioBuffer() {
792
- let ab = null;
793
- if (this.context && this.data) {
794
- let frameLen = 0;
795
- let ch0Data = this.data[0];
796
- for (let ch0Chk of ch0Data) {
797
- frameLen += ch0Chk.length;
798
- }
799
- try {
800
- ab = this.context.createBuffer(this.channelCount, frameLen, this.context.sampleRate);
801
- }
802
- catch (err) {
803
- if (err instanceof DOMException) {
804
- if (err.name === 'NotSupportedError') {
805
- if (frameLen == 0) {
806
- // Empty buffers are not supported by Chromium
807
- // Create dummy buffer with one sample
808
- ab = this.context.createBuffer(this.channelCount, 1, this.context.sampleRate);
809
- }
810
- else {
811
- throw err;
812
- }
813
- }
814
- else {
815
- throw err;
816
- }
817
- }
818
- else if (err instanceof RangeError) {
819
- // Out of memory
820
- // TODO What to do ??
821
- throw err;
822
- }
823
- else {
824
- throw err;
825
- }
826
- }
827
- for (let ch = 0; ch < this.channelCount; ch++) {
828
- let chD = ab.getChannelData(ch);
829
- let pos = 0;
830
- for (let chChk of this.data[ch]) {
831
- let bufLen = chChk.length;
832
- chD.set(chChk, pos);
833
- pos += bufLen;
834
- }
835
- }
836
- }
837
- return ab;
838
- }
839
- audioBufferArray() {
840
- let arrAb = null;
841
- if (this.data) {
842
- arrAb = new ArrayAudioBuffer(this.channelCount, this.currentSampleRate, this.data);
843
- }
844
- return arrAb;
845
- }
846
- inddbAudioBufferArray() {
847
- if (this.persistError) {
848
- return null;
849
- }
850
- else {
851
- return this.inddbAudioBuffer;
852
- }
853
- }
854
- }
855
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FwdHVyZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3NwZWVjaHJlY29yZGVybmcvc3JjL2xpYi9hdWRpby9jYXB0dXJlL2NhcHR1cmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsZ0JBQWdCLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUUxRSxPQUFPLEVBQUMsZ0JBQWdCLEVBQXlCLFFBQVEsSUFBSSxXQUFXLEVBQUMsTUFBTSxzQ0FBc0MsQ0FBQztBQUN0SCxPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUN2RCxPQUFPLEVBQUMsSUFBSSxFQUFDLE1BQU0sbUJBQW1CLENBQUM7QUFDdkMsT0FBTyxFQUFDLG9CQUFvQixFQUErQixNQUFNLHVCQUF1QixDQUFDO0FBQ3pGLE9BQU8sRUFBQyxvQkFBb0IsRUFBQyxNQUFNLFlBQVksQ0FBQztBQUdoRCxNQUFNLENBQUMsTUFBTSwwQ0FBMEMsR0FBQyxLQUFLLENBQUM7QUFFOUQsTUFBTSxpQkFBaUIsR0FBQyxDQUFDLENBQUM7QUFFMUIsZ0NBQWdDO0FBQ2hDLHdEQUF3RDtBQUN4RCxNQUFNLE1BQU0sR0FBQyx5RUFBeUU7SUFDbEYsSUFBSTtJQUNKLDJCQUEyQjtJQUMzQiw4QkFBOEI7SUFDOUIscUVBQXFFO0lBQ3JFLG9CQUFvQjtJQUNwQixvQkFBb0I7SUFDcEIseUJBQXlCO0lBQ3pCLHVCQUF1QjtJQUN2QixvQkFBb0I7SUFDcEIsSUFBSTtJQUNKLFNBQVM7SUFDVCxJQUFJO0lBQ0osYUFBYTtJQUNiLGlCQUFpQjtJQUNqQixrQkFBa0I7SUFDbEIsb0JBQW9CO0lBQ3BCLFFBQVE7SUFDUixJQUFJO0lBQ0oscUNBQXFDO0lBQ3JDLDRCQUE0QjtJQUM1Qix3QkFBd0I7SUFDeEIsNkJBQTZCO0lBQzdCLDBCQUEwQjtJQUMxQixvQ0FBb0M7SUFDcEMsMENB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Q1osSUFBSSxLQUFLLEdBQXVCLElBQUksQ0FBQztRQUNyQyxJQUFHLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNiLEtBQUssR0FBQyxJQUFJLGdCQUFnQixDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsSUFBSSxDQUFDLGlCQUFpQixFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNuRixDQUFDO1FBQ0QsT0FBTyxLQUFLLENBQUM7SUFDakIsQ0FBQztJQUVELHFCQUFxQjtRQUNuQixJQUFHLElBQUksQ0FBQyxZQUFZLEVBQUMsQ0FBQztZQUNwQixPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7YUFBSyxDQUFDO1lBQ0wsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLENBQUM7UUFDL0IsQ0FBQztJQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1NlcXVlbmNlQXVkaW9GbG9hdDMyT3V0U3RyZWFtfSBmcm9tIFwiLi4vaW8vc3RyZWFtXCI7XHJcbmltcG9ydCB7QnJvd3NlciwgUGxhdGZvcm0sIFVzZXJBZ2VudEJ1aWxkZXJ9IGZyb20gXCIuLi8uLi91dGlscy91YS1wYXJzZXJcIjtcclxuXHJcbmltcG9ydCB7QXVkaW9TdG9yYWdlVHlwZSwgQXV0b0dhaW5Db250cm9sQ29uZmlnLCBQbGF0Zm9ybSBhcyBDZmdQbGF0Zm9ybX0gZnJvbSBcIi4uLy4uL3NwZWVjaHJlY29yZGVyL3Byb2plY3QvcHJvamVjdFwiO1xyXG5pbXBvcnQge0FycmF5QXVkaW9CdWZmZXJ9IGZyb20gXCIuLi9hcnJheV9hdWRpb19idWZmZXJcIjtcclxuaW1wb3J0IHtVVUlEfSBmcm9tIFwiLi4vLi4vdXRpbHMvdXRpbHNcIjtcclxuaW1wb3J0IHtJbmRleGVkRGJBdWRpb0J1ZmZlciwgUGVyc2lzdGVudEF1ZGlvU3RvcmFnZVRhcmdldH0gZnJvbSBcIi4uL2luZGRiX2F1ZGlvX2J1ZmZlclwiO1xyXG5pbXBvcnQge0F1ZGlvQ29udGV4dFByb3ZpZGVyfSBmcm9tIFwiLi4vY29udGV4dFwiO1xyXG5cclxuXHJcbmV4cG9ydCBjb25zdCBDSFJPTUVfQUNUSVZBVEVfRUNIT19DQU5DRUxMQVRJT05fV0lUSF9BR0M9ZmFsc2U7XHJcblxyXG5jb25zdCBERUJVR19UUkFDRV9MRVZFTD0wO1xyXG5cclxuLy8gRGlydHkgd2F5IHRvIGxvYWQgdGhpcyBtb2R1bGVcclxuLy8gQ29weSBjb250ZW50IG9mIGludGVyY2VwdG9yX3dvcmtsZXQuanMgdG8gdGhpcyBzdHJpbmdcclxuY29uc3QgYXdwU3RyPVwiY2xhc3MgQXVkaW9DYXB0dXJlSW50ZXJjZXB0b3JQcm9jZXNzb3IgZXh0ZW5kcyBBdWRpb1dvcmtsZXRQcm9jZXNzb3J7XFxuXCIgK1xyXG4gICAgXCJcXG5cIiArXHJcbiAgICBcIiAgICBCVUZGRVJfUVVBTlRVTVM9NjQ7XFxuXCIgK1xyXG4gICAgXCIgICAgUVVBTlRVTV9GUkFNRV9MRU49MTI4O1xcblwiICtcclxuICAgIFwiICAgIEJVRkZFUl9GUkFNRV9MRU49dGhpcy5RVUFOVFVNX0ZSQU1FX0xFTip0aGlzLkJVRkZFUl9RVUFOVFVNUztcXG5cIiArXHJcbiAgICBcIiAgICBidWZmZXI9bnVsbDtcXG5cIiArXHJcbiAgICBcIiAgICBidWZmZXJQb3M9MDtcXG5cIiArXHJcbiAgICBcIiAgICBidWZmZXJQb3NCeXRlcz0wO1xcblwiICtcclxuICAgIFwiICAgIGNvbnN0cnVjdG9yKCkge1xcblwiICtcclxuICAgIFwiICAgICAgICBzdXBlcigpO1xcblwiICtcclxuICAgIFwiXFxuXCIgK1xyXG4gICAgXCIgICAgfVxcblwiICtcclxuICAgIFwiXFxuXCIgK1xyXG4gICAgXCIgcHJvY2VzcyhcXG5cIiArXHJcbiAgICBcIiAgICAgIGlucHV0cyxcXG5cIiArXHJcbiAgICBcIiAgICAgIG91dHB1dHMsXFxuXCIgK1xyXG4gICAgXCIgICAgICBwYXJhbWV0ZXJzXFxuXCIgK1xyXG4gICAgXCIgICl7XFxuXCIgK1xyXG4gICAgXCJcXG5cIiArXHJcbiAgICBcIiAgICAgbGV0IGlucHV0c0NudD1pbnB1dHMubGVuZ3RoO1xcblwiICtcclxuICAgIFwiICAgICBsZXQgY2hhbm5lbENvdW50PTA7XFxuXCIgK1xyXG4gICAgXCIgICAgIGxldCBpbnB1dExlbj0wO1xcblwiICtcclxuICAgIFwiICAgICBsZXQgaW5wdXRMZW5CeXRlcz0wO1xcblwiICtcclxuICAgIFwiICAgICBpZihpbnB1dHNDbnQ+MCkge1xcblwiICtcclxuICAgIFwiICAgICAgICAgbGV0IGlucHV0MCA9IGlucHV0c1swXTtcXG5cIiArXHJcbiAgICBcIiAgICAgICAgIGNoYW5uZWxDb3VudCA9IGlucHV0MC5sZW5ndGg7XFxuXCIgK1xyXG4gICAgXCIgICAgICAgICBpZiAoY2hhbm5lbENvdW50ID4gMCkge1xcblwiICtcclxuICAgIFwiICAgICAgICAgICAgIGxldCBpbnB1dDBjaDA9aW5wdXQwWzBdO1xcblwiICtcclxuICAgIFwiICAgICAgICAgICAgIGlucHV0TGVuPWlucHV0MGNoMC5sZW5ndGg7XFxuXCIgK1xyXG4gICAgXCIgICAgICAgICAgICAgaW5wdXRMZW5CeXRlcz1pbnB1dDBjaDAuYnVmZmVyLmxlbmd0aDtcXG5cIiArXHJcbiAgICBcIiAgICAgICAgIH1cXG5cIiArXHJcbiAgICBcIiAgICAgfVxcblwiICtcclxuICAgIFwiICAgICBpZiAoIXRoaXMuYnVmZmVyIHx8IHRoaXMuYnVmZmVyLmxlbmd0aCA8IGNoYW5uZWxDb3VudCkge1xcblwiICtcclxuICAgIFwiICAgICAgICAgdGhpcy5idWZmZXIgPSBuZXcgQXJyYXkoY2hhbm5lbENvdW50KTtcXG5cIiArXHJcbiAgICBcIiAgICAgICAgIHRoaXMuYnVmZmVyUG9zID0gMFxcblwiICtcclxuICAgIFwiICAgICAgICAgZm9yIChsZXQgYmNoID0gMDsgYmNoIDwgY2hhbm5lbENvdW50OyBiY2grKykge1xcblwiICtcclxuICAgIFwiICAgICAgICAgICAgIHRoaXMuYnVmZmVyW2JjaF0gPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuQlVGRkVSX0ZSQU1FX0xFTik7XFxuXCIgK1xyXG4gICAgXCIgICAgICAgICAgICAgdGhpcy5idWZmZXJQb3MgPSAwO1xcblwiICtcclxuICAgIFwiICAgICAgICAgICAgIHRoaXMuYnVmZmVyUG9zQnl0ZXM9MDtcXG5cIiArXHJcbiAgICBcIiAgICAgICAgIH1cXG5cIiArXHJcbiAgICBcIiAgICAgfVxcblwiICtcclxuICAgIFwiICAgICBsZXQgYnVmQXZhaWwgPSB0aGlzLkJVRkZFUl9GUkFNRV9MRU4gLSB0aGlzLmJ1ZmZlclBvcztcXG5cIiArXHJcbiAgICBcIiAgICAgLy8gY2hlY2sgaWYgYnVmZmVyIGhhcyB0byBiZSB0cmFuc2ZlcnJlZFxcblwiICtcclxuICAgIFwiICAgICBpZiAoaW5wdXRMZW4gPiBidWZBdmFpbCkge1xcblwiICtcclxuICAgIFwiICAgICAgICAgbGV0IGFkYT1uZXcgQXJyYXkoY2hhbm5lbENvdW50KTtcXG5cIiArXHJcbiAgICBcIiAgICAgICAgIGZvciAobGV0IGNoID0gMDsgY2ggPCBjaGFubmVsQ291bnQ7IGNoKyspIHtcXG5cIiArXHJcbiAgICBcIiAgICAgICAgICAgICBhZGFbY2hdPXRoaXMuYnVmZmVyW2NoXS5idWZmZXIuc2xpY2UoMCk7XFxuXCIgK1xyXG4gICAgXCIgICAgICAgICB9XFxuXCIgK1xyXG4gICAgXCIgICAgICAgICB0aGlzLnBvcnQucG9zdE1lc3NhZ2Uoe1xcblwiICtcclxuICAgIFwiICAgICAgICAgICAgIGRhdGE6IGFkYSxcXG5cIiArXHJcbiAgICBcIiAgICAgICAgICAgICBjaHM6IGNoYW5uZWxDb3VudCxcXG5cIiArXHJcbiAgICBcIiAgICAgICAgICAgICBsZW46IHRoaXMuYnVmZmVyUG9zXFxuXCIgK1xyXG4gICAgXCIgICAgICAgICB9LCBhZGEpO1xcblwiICtcclxuICAgIFwiICAgICAgICAgLy8gYnVmZmVyIHRyYW5zZmVycmVkLCByZXNldFxcblwiICtcclxuICAgIFwiICAgICAgICAgdGhpcy5idWZmZXJQb3MgPSAwO1xcblwiICtcclxuICAgIFwiICAgICAgICAgdGhpcy5idWZmZXJQb3NCeXRlcz0wO1xcblwiICtcclxuICAgIFwiICAgICB9XFxuXCIgK1xyXG4gICAgXCJcXG5cIiArXHJcbiAgICBcIiAgICAgZm9yKGxldCBpaT0wO2lpPGlucHV0c0NudDtpaSsrKSB7XFxuXCIgK1xyXG4gICAgXCIgICAgICAgICBmb3IgKGxldCBjaCA9IDA7IGNoIDwgY2hhbm5lbENvdW50OyBjaCsrKSB7XFxuXCIgK1xyXG4gICAgXCIgICAgICAgICAgICAgLy8gTXV0ZSBvdXRwdXRzXFxuXCIgK1xyXG4gICAgXCIgICAgICAgICAgICAgLy9vdXRwdXRzW2lpXVtjaF0uZmlsbCgwKTtcXG5cIiArXHJcbiAgICBcIiAgICAgICAgICAgICBsZXQgY2hTYW1wbGVzID0gaW5wdXRzW2lpXVtjaF07XFxuXCIgK1xyXG4gICAgXCIgICAgICAgICAgICAgdGhpcy5idWZmZXJbY2hdLnNldChjaFNhbXBsZXMsdGhpcy5idWZmZXJQb3MpO1xcblwiICtcclxuICAgIFwiICAgICAgICAgfVxcblwiICtcclxuICAgIFwiICAgICAgICAgdGhpcy5idWZmZXJQb3MrPWlucHV0TGVuO1xcblwiICtcclxuICAgIFwiICAgICAgICAgdGhpcy5idWZmZXJQb3NCeXRlcys9aW5wdXRMZW5CeXRlcztcXG5cIiArXHJcbiAgICBcIiAgICAgfVxcblwiICtcclxuICAgIFwiICAgIFxcblwiICtcclxuICAgIFwiICAgICByZXR1cm4gdHJ1ZTtcXG5cIiArXHJcbiAgICBcIiAgfVxcblwiICtcclxuICAgIFwifVxcblwiICtcclxuICAgIFwiXFxuXCIgK1xyXG4gICAgXCJyZWdpc3RlclByb2Nlc3NvcignY2FwdHVyZS1pbnRlcmNlcHRvcicsQXVkaW9DYXB0dXJlSW50ZXJjZXB0b3JQcm9jZXNzb3IpO1xcblwiO1xyXG5cclxuXHJcblxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBBdWRpb0NhcHR1cmVMaXN0ZW5lciB7XHJcbiAgb3BlbmVkKCk6IHZvaWQ7XHJcblxyXG4gIHN0YXJ0ZWQoKTogdm9pZDtcclxuXHJcbiAgc3RvcHBlZCgpOiB2b2lkO1xyXG5cclxuICBjbG9zZWQoKTogdm9pZDtcclxuXHJcbiAgZXJyb3IobXNnPzpzdHJpbmcsYWR2aWNlPzpzdHJpbmcpOiB2b2lkO1xyXG59XHJcblxyXG5leHBvcnQgY2xhc3MgQXVkaW9DYXB0dXJlIHtcclxuXHJcbiAgZ2V0IG1heEF1dG9OZXRNZW1TdG9yZVNhbXBsZXMoKTogbnVtYmVyIHtcclxuICAgIHJldHVybiB0aGlzLl9tYXhBdXRvTmV0TWVtU3RvcmVTYW1wbGVzO1xyXG4gIH1cclxuXHJcbiAgc2V0IG1heEF1dG9OZXRNZW1TdG9yZVNhbXBsZXModmFsdWU6IG51bWJlcikge1xyXG4gICAgdGhpcy5fbWF4QXV0b05ldE1lbVN0b3JlU2FtcGxlcyA9IHZhbHVlO1xyXG4gIH1cclxuICBzZXQgcmVjVVVJRCh2YWx1ZTogc3RyaW5nfG51bGwpIHtcclxuICAgIHRoaXMuX3JlY1VVSUQgPSB2YWx1ZTtcclxuICB9XHJcbiAgZ2V0IHJlY1VVSUQoKTogc3RyaW5nIHxudWxse1xyXG4gICAgcmV0dXJuIHRoaXMuX3JlY1VVSUQ7XHJcbiAgfVxyXG4gIGdldCBhdWRpb1N0b3JhZ2VUeXBlKCk6IEF1ZGlvU3RvcmFnZVR5cGUge1xyXG4gICAgcmV0dXJuIHRoaXMuX2F1ZGlvU3RvcmFnZVR5cGU7XHJcbiAgfVxyXG5cclxuICBzZXQgYXVkaW9TdG9yYWdlVHlwZSh2YWx1ZTogQXVkaW9TdG9yYWdlVHlwZSkge1xyXG4gICAgdGhpcy5fYXVkaW9TdG9yYWdlVHlwZSA9IHZhbHVlO1xyXG4gIH1cclxuICBnZXQgcGVyc2lzdGVudEF1ZGlvU3RvcmFnZVRhcmdldCgpOiBQZXJzaXN0ZW50QXVkaW9TdG9yYWdlVGFyZ2V0IHwgbnVsbCB7XHJcbiAgICByZXR1cm4gdGhpcy5fcGVyc2lzdGVudEF1ZGlvU3RvcmFnZVRhcmdldDtcclxuICB9XHJcblxyXG4gIHNldCBwZXJzaXN0ZW50QXVkaW9TdG9yYWdlVGFyZ2V0KHZhbHVlOiBQZXJzaXN0ZW50QXVkaW9TdG9yYWdlVGFyZ2V0IHwgbnVsbCkge1xyXG4gICAgdGhpcy5fcGVyc2lzdGVudEF1ZGlvU3RvcmFnZVRhcmdldCA9IHZhbHVlO1xyXG4gIH1cclxuXHJcblxyXG4gIGdldCBvcGVuZWQoKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gdGhpcy5fb3BlbmVkO1xyXG4gIH1cclxuXHJcbiAgc3RhdGljIEJVRkZFUl9TSVpFOiBudW1iZXIgPSA4MTkyO1xyXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IERFRkFVTFRfTUFYX05FVF9BVVRPX01FTV9TVE9SRV9TQU1QTEVTOm51bWJlcj0yODgwMDAwKjU7IC8vIERlZmF1bHQgNSBtaW51dGUgYXQgNDhrSHpcclxuICBwcml2YXRlIF9tYXhBdXRvTmV0TWVtU3RvcmVTYW1wbGVzOm51bWJlcj1BdWRpb0NhcHR1cmUuREVGQVVMVF9NQVhfTkVUX0FVVE9fTUVNX1NUT1JFX1NBTVBMRVM7XHJcbiAgcHJpdmF0ZSBzdGF0aWMgY2FwdHVyZUludGVyY2VwdG9yTW9kdWxlUmVnaXN0ZXJlZD1mYWxzZTtcclxuICBjb250ZXh0OiBBdWRpb0NvbnRleHR8bnVsbD1udWxsO1xyXG4gIHN0cmVhbSE6IE1lZGlhU3RyZWFtO1xyXG4gIGNoYW5uZWxDb3VudCE6IG51bWJlcjtcclxuICBwcml2YXRlIF9yZWNVVUlEOnN0cmluZ3xudWxsPW51bGw7XHJcbiAgbWVkaWFTdHJlYW06IGFueTtcclxuICBhZ2NTdGF0dXM6Ym9vbGVhbnxudWxsPW51bGw7XHJcbiAgYnVmZmVyaW5nTm9kZTogQXVkaW9Ob2RlfG51bGw9bnVsbDtcclxuICBsaXN0ZW5lciE6IEF1ZGlvQ2FwdHVyZUxpc3RlbmVyO1xyXG4gIGRhdGE6IEFycmF5PEFycmF5PEZsb2F0MzJBcnJheT4+fG51bGw9bnVsbDtcclxuICBjdXJyZW50U2FtcGxlUmF0ZSE6IG51bWJlcjtcclxuICBuOiBOYXZpZ2F0b3I7XHJcbiAgYXVkaW9PdXRTdHJlYW06IFNlcXVlbmNlQXVkaW9GbG9hdDMyT3V0U3RyZWFtIHwgbnVsbD1udWxsO1xyXG4gIHByaXZhdGUgZGlzY29ubmVjdFN0cmVhbXMgPSB0cnVlO1xyXG4gIHByaXZhdGUgX29wZW5lZD1mYWxzZTtcclxuICBwcml2YXRlIGNhcHR1cmluZyA9IGZhbHNlO1xyXG5cclxuICBmcmFtZXNSZWNvcmRlZDogbnVtYmVyPTA7XHJcblxyXG4gIHByaXZhdGUgX2F1ZGlvU3RvcmFnZVR5cGU6QXVkaW9TdG9yYWdlVHlwZT1BdWRpb1N0b3JhZ2VUeXBlLk1FTV9FTlRJUkU7XHJcbiAgcHJpdmF0ZSBfcGVyc2lzdGVudEF1ZGlvU3RvcmFnZVRhcmdldDpQZXJzaXN0ZW50QXVkaW9TdG9yYWdlVGFyZ2V0fG51bGw9bnVsbDtcclxuXHJcbiAgcHJpdmF0ZSBwZXJzaXN0ZWQ9dHJ1ZTtcclxuICBwcml2YXRlIHBlcnNpc3RFcnJvcjpFcnJvcnxudWxsPW51bGw7XHJcbiAgcHJpdmF0ZSBpbmRkYkF1ZGlvQnVmZmVyOkluZGV4ZWREYkF1ZGlvQnVmZmVyfG51bGw9bnVsbDtcclxuXHJcbiAgLy9wcml2YXRlIGNvbnRleHQ6QXVkaW9Db250ZXh0fG51bGw9bnVsbDtcclxuXHJcbiAgY29uc3RydWN0b3IoKSB7XHJcbiAgICB0aGlzLm4gPSBuYXZpZ2F0b3I7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIF9hdWRpb0NvbnRleHQoKTpBdWRpb0NvbnRleHR8bnVsbHtcclxuICAgIGlmKCF0aGlzLmNvbnRleHQpe1xyXG4gICAgICB0aGlzLmNvbnRleHQ9QXVkaW9Db250ZXh0UHJvdmlkZXIuYXVkaW9Db250ZXh0SW5zdGFuY2UoKTtcclxuICAgICAgaWYodGhpcy5jb250ZXh0KSB7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0LmFkZEV2ZW50TGlzdGVuZXIoJ3N0YXRlY2hhbmdlJywgKCkgPT4ge1xyXG4gICAgICAgICAgaWYgKHRoaXMuY29udGV4dCAmJiB0aGlzLmNvbnRleHQuc3RhdGUgIT09ICdydW5uaW5nJykge1xyXG4gICAgICAgICAgICB0aGlzLmNsb3NlKCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiB0aGlzLmNvbnRleHQ7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGluaXREYXRhKCkge1xyXG4gICAgaWYoIXRoaXMuX3JlY1VVSUQpIHtcclxuICAgICAgdGhpcy5fcmVjVVVJRCA9IFVVSUQuZ2VuZXJhdGUoKTtcclxuICAgIH1cclxuICAgIHRoaXMucGVyc2lzdEVycm9yPW51bGw7XHJcbiAgICAvL2NvbnNvbGUuZGVidWcoXCJBdWRpbyBjYXB0dXJlIGluaXRpYWxpemUgc3RvcmFnZSBmb3IgdHlwZTogXCIrdGhpcy5fYXVkaW9TdG9yYWdlVHlwZSk7XHJcbiAgICBpZihBdWRpb1N0b3JhZ2VUeXBlLkRCX0NIVU5LRUQgPT09IHRoaXMuX2F1ZGlvU3RvcmFnZVR5cGUgJiYgdGhpcy5fcGVyc2lzdGVudEF1ZGlvU3RvcmFnZVRhcmdldCAmJiB0aGlzLl9yZWNVVUlEKSB7XHJcbiAgICAgIC8vY29uc29sZS5kZWJ1ZyhcIkNyZWF0ZSBpbmRleGVkIGRiIGF1ZGlvIGJ1ZmZlci5cIik7XHJcbiAgICAgIHRoaXMuaW5kZGJBdWRpb0J1ZmZlciA9IG5ldyBJbmRleGVkRGJBdWRpb0J1ZmZlcih0aGlzLl9wZXJzaXN0ZW50QXVkaW9TdG9yYWdlVGFyZ2V0LCB0aGlzLmNoYW5uZWxDb3VudCx0aGlzLmN1cnJlbnRTYW1wbGVSYXRlLEF1ZGlvQ2FwdHVyZS5CVUZGRVJfU0laRSwwLHRoaXMuX3JlY1VVSUQpXHJcbiAgICB9XHJcbiAgICBpZighKEF1ZGlvU3RvcmFnZVR5cGUuTkVUX0NIVU5LRUQgPT09IHRoaXMuX2F1ZGlvU3RvcmFnZVR5cGUpKSB7XHJcbiAgICAgIC8vIEluaXRpYWxpemUgYXVkaW8gZGF0YSBhcnJheSBleGNlcHQgZm9yIG5ldCBhdWRpbyBidWZmZXIgbW9kZVxyXG4gICAgICB0aGlzLmRhdGEgPSBuZXcgQXJyYXk8QXJyYXk8RmxvYXQzMkFycmF5Pj4oKTtcclxuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmNoYW5uZWxDb3VudDsgaSsrKSB7XHJcbiAgICAgICAgdGhpcy5kYXRhLnB1c2gobmV3IEFycmF5PEZsb2F0MzJBcnJheT4oKSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHRoaXMuZnJhbWVzUmVjb3JkZWQgPSAwO1xyXG4gIH1cclxuXHJcbiAgbGlzdERldmljZXMoKSB7XHJcbiAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmVudW1lcmF0ZURldmljZXMoKS50aGVuKChsOiBNZWRpYURldmljZUluZm9bXSkgPT4gdGhpcy5wcmludERldmljZXMobCkpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBkdW1teVNlc3Npb24oKTpQcm9taXNlPE1lZGlhU3RyZWFtPntcclxuICAgIC8vIHdvcmthcm91bmQgdG8gcmVxdWVzdCBwZXJtaXNzaW9uczpcclxuICAgIC8vIFN0YXJ0IGEgZHVtbXkgc2Vzc2lvblxyXG4gICAgbGV0IG1lZGlhU3RyQ25zdHJzID0gPE1lZGlhU3RyZWFtQ29uc3RyYWludHM+e2F1ZGlvOlxyXG4gICAgICAgIHtlY2hvQ2FuY2VsYXRpb246IGZhbHNlfVxyXG4gICAgfTtcclxuICAgIHJldHVybiBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYShtZWRpYVN0ckNuc3Rycyk7XHJcblxyXG4gIH1cclxuXHJcblxyXG4gIHByaXZhdGUgc3RvcEFsbFNlc3Npb25UcmFja3MobWVkaWFTdHJlYW06TWVkaWFTdHJlYW0pe1xyXG4gICAgICBsZXQgYXRzID0gbWVkaWFTdHJlYW0uZ2V0VHJhY2tzKCk7XHJcbiAgICAgIGZvciAobGV0IGF0SWR4ID0gMDsgYXRJZHggPCBhdHMubGVuZ3RoOyBhdElkeCsrKSB7XHJcbiAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiU3RvcCBkdW1teSBzZXNzaW9uIHRyYWNrOiAjXCIgKyBhdElkeClcclxuICAgICAgICBhdHNbYXRJZHhdLnN0b3AoKTtcclxuICAgICAgfVxyXG4gIH1cclxuXHJcbiAgZGV2aWNlSW5mb3MoY2I6IChkZXZpY2VJbmZvczogTWVkaWFEZXZpY2VJbmZvW10gfCBudWxsKSA9PiBhbnksIHJldHJ5ID0gdHJ1ZSxkdW1teVN0cmVhbT86TWVkaWFTdHJlYW0pIHtcclxuXHJcbiAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmVudW1lcmF0ZURldmljZXMoKS50aGVuKChsOiBNZWRpYURldmljZUluZm9bXSkgPT4ge1xyXG4gICAgICBsZXQgbGFiZWxzQXZhaWxhYmxlID0gZmFsc2U7XHJcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbC5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgIGxldCBkaSA9IGxbaV07XHJcbiAgICAgICAgaWYgKGRpLmxhYmVsKSB7XHJcbiAgICAgICAgICBsYWJlbHNBdmFpbGFibGUgPSB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBpZiAoIWxhYmVsc0F2YWlsYWJsZSkge1xyXG4gICAgICAgIC8vY29uc29sZS5kZWJ1ZyhcIk1lZGlhIGRldmljZSBlbnVtZXJhdGlvbjogTm8gbGFiZWxzLlwiKVxyXG4gICAgICAgIGlmIChyZXRyeSkge1xyXG4gICAgICAgICAgICBjb25zb2xlLmluZm8oXCJTdGFydGluZyBkdW1teSBzZXNzaW9uIHRvIHJlcXVlc3QgYXVkaW8gcGVybWlzc2lvbnMuLi5cIilcclxuXHJcbiAgICAgICAgICAgIHRoaXMuZHVtbXlTZXNzaW9uKCkudGhlbigoczogTWVkaWFTdHJlYW0pID0+IHtcclxuICAgICAgICAgICAgLy8gYW5kIHN0b3AgaXQgaW1tZWRpYXRlbHlcclxuXHJcbiAgICAgICAgICAgIGlmKHMpIHtcclxuICAgICAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJHb3QgZHVtbXkgc2Vzc2lvbiBzdHJlYW06IFwiICsgcyArIFwiIC5cIilcclxuICAgICAgICAgICAgfWVsc2V7XHJcbiAgICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiTm8gZHVtbXkgc3RyZWFtXCIpXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgLy8gcmV0cnkgKG9ubHkgb25jZSlcclxuICAgICAgICAgICAgdGhpcy5kZXZpY2VJbmZvcyhjYiwgZmFsc2Uscyk7XHJcbiAgICAgICAgICB9LHJlYXNvbiA9PiB7XHJcbiAgICAgICAgICAgIC8vY29uc29sZS5kZWJ1ZyhcIkR1bW15IHNlc3Npb24gcmVqZWN0ZWQuXCIpXHJcbiAgICAgICAgICAgIC8vIFRPRE8gZXJyb3IgY2FsbGJhY2tcclxuICAgICAgICAgICAgY2IobnVsbCk7XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgY2IobnVsbCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIHN1Y2Nlc3NcclxuICAgICAgICBjYihsKTtcclxuICAgICAgfVxyXG4gICAgICBpZihkdW1teVN0cmVhbSl7XHJcbiAgICAgICAgdGhpcy5zdG9wQWxsU2Vzc2lvblRyYWNrcyhkdW1teVN0cmVhbSk7XHJcbiAgICAgIH1cclxuICAgIH0sKHJlYXNvbik9PiB7XHJcbiAgICAgIC8vcmVqZWN0ZWRcclxuICAgICAgLy9jb25zb2xlLmRlYnVnKFwiTWVkaWEgZGV2aWNlIGVudW1lcmF0aW9uIHJlamVjdGVkLlwiKVxyXG4gICAgICBpZiAocmV0cnkpIHtcclxuICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJTdGFydGluZyBkdW1teSBzZXNzaW9uIHRvIHJlcXVlc3QgYXVkaW8gcGVybWlzc2lvbnMuLi5cIilcclxuICAgICAgICB0aGlzLmR1bW15U2Vzc2lvbigpLnRoZW4oKHM6IE1lZGlhU3RyZWFtKSA9PiB7XHJcbiAgICAgICAgICAvLyBhbmQgc3RvcCBpdCBpbW1lZGlhdGVseVxyXG4gICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiRHVtbXkgc2Vzc2lvbi5cIilcclxuICAgICAgICAgIGlmKHMpIHtcclxuICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiR290IGR1bW15IHNlc3Npb24gc3RyZWFtOiBcIiArIHMgKyBcIiAuXCIpXHJcbiAgICAgICAgICB9ZWxzZXtcclxuICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiTm8gZHVtbXkgc3RyZWFtXCIpXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICAvLyByZXRyeSAob25seSBvbmNlKVxyXG4gICAgICAgICAgdGhpcy5kZXZpY2VJbmZvcyhjYiwgZmFsc2Uscyk7XHJcbiAgICAgICAgfSwgcmVhc29uID0+IHtcclxuICAgICAgICAgIC8vY29uc29sZS5kZWJ1ZyhcIkR1bW15IHNlc3Npb24gcmVqZWN0ZWQuXCIpXHJcbiAgICAgICAgICAvLyBUT0RPIGVycm9yIGNhbGxiYWNrXHJcbiAgICAgICAgICBjYihudWxsKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBjYihudWxsKTtcclxuICAgICAgfVxyXG4gICAgICBpZihkdW1teVN0cmVhbSl7XHJcbiAgICAgICAgdGhpcy5zdG9wQWxsU2Vzc2lvblRyYWNrcyhkdW1teVN0cmVhbSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuXHJcblxyXG4gIH1cclxuXHJcblxyXG4gIHByaW50RGV2aWNlcyhsOiBNZWRpYURldmljZUluZm9bXSk6IHZvaWQge1xyXG4gICAgLy9sZXQgc2VsRGV2aWNlSWQgPSAnX19fZHVtbXlfX18nO1xyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgIGxldCBkaSA9IGxbaV07XHJcbiAgICAgIGNvbnNvbGUubG9nKFwiQXVkaW8gZGV2aWNlOiBJZDogXCIgKyBkaS5kZXZpY2VJZCArIFwiIGdyb3VwSWQ6IFwiICsgZGkuZ3JvdXBJZCArIFwiIGxhYmVsOiBcIiArIGRpLmxhYmVsICsgXCIga2luZDogXCIgKyBkaS5raW5kKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGFkZENhcHR1cmVJbnRlcmNlcHRvcigpIHtcclxuICAgIGlmICh0aGlzLmNvbnRleHQpIHtcclxuXHJcbiAgICBjb25zdCBhd24gPSBuZXcgQXVkaW9Xb3JrbGV0Tm9kZSh0aGlzLmNvbnRleHQsICdjYXB0dXJlLWludGVyY2VwdG9yJyk7XHJcbiAgICBhd24ub25wcm9jZXNzb3JlcnJvciA9IChldjogRXZlbnQpID0+IHtcclxuICAgICAgbGV0IG1zZyA9ICdVbmtud29uIGVycm9yJztcclxuICAgICAgaWYgKGV2IGluc3RhbmNlb2YgRXJyb3JFdmVudCkge1xyXG4gICAgICAgIG1zZyA9IGV2Lm1lc3NhZ2U7XHJcbiAgICAgIH1cclxuICAgICAgY29uc29sZS5lcnJvcihcIkNhcHR1cmUgYXVkaW8gd29ya2xldCBlcnJvcjogXCIgKyBtc2cpO1xyXG4gICAgICBpZiAodGhpcy5saXN0ZW5lcikge1xyXG4gICAgICAgIHRoaXMubGlzdGVuZXIuZXJyb3IobXNnKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgbGV0IGF3blB0ID0gYXduLnBvcnQ7XHJcbiAgICBpZiAoYXduUHQpIHtcclxuICAgICAgYXduUHQub25tZXNzYWdlID0gKGV2OiBNZXNzYWdlRXZlbnQpID0+IHtcclxuICAgICAgICBpZiAodGhpcy5jYXB0dXJpbmcpIHtcclxuICAgICAgICAgIGxldCBkdCA9IGV2LmRhdGE7XHJcbiAgICAgICAgICBsZXQgY2hzID0gZHQuY2hzO1xyXG4gICAgICAgICAgbGV0IGFkYUxlbiA9IGR0LmRhdGEubGVuZ3RoO1xyXG4gICAgICAgICAgaWYgKERFQlVHX1RSQUNFX0xFVkVMID4gOCkge1xyXG4gICAgICAgICAgICBjb25zb2xlLmRlYnVnKCdSZWNlaXZlZCBkYXRhIGZyb20gd29ya2xldDogJyArIGNocyArICcgJyArIGR0LmxlbiArICcgRGF0YSBjaHM6ICcgKyBhZGFMZW4pO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgbGV0IGNodW5rID0gbmV3IEFycmF5PEZsb2F0MzJBcnJheT4oY2hzKTtcclxuICAgICAgICAgIGNvbnN0IHNhbXBsZXMgPSB0aGlzLmZyYW1lc1JlY29yZGVkICogY2hzO1xyXG4gICAgICAgICAgaWYgKChBdWRpb1N0b3JhZ2VUeXBlLk1FTV9FTlRJUkVfQVVUT19ORVRfQ0hVTktFRCA9PT0gdGhpcy5hdWRpb1N0b3JhZ2VUeXBlIHx8IEF1ZGlvU3RvcmFnZVR5cGUuTUVNX0NIVU5LRURfQVVUT19ORVRfQ0hVTktFRCA9PT0gdGhpcy5hdWRpb1N0b3JhZ2VUeXBlKSAmJiB0aGlzLmRhdGEgJiYgc2FtcGxlcyA+IHRoaXMuX21heEF1dG9OZXRNZW1TdG9yZVNhbXBsZXMpIHtcclxuICAgICAgICAgICAgdGhpcy5kYXRhID0gbnVsbDtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJEYXRhIGluaXRpYWxpemVkOiBcIisodGhpcy5kYXRhIT1udWxsKSk7XHJcbiAgICAgICAgICBmb3IgKGxldCBjaCA9IDA7IGNoIDwgY2hzOyBjaCsrKSB7XHJcbiAgICAgICAgICAgIC8vY29uc29sZS5kZWJ1ZyhcIkRhdGEgY2ggaW5pdGlhbGl6ZWQ6IFwiKyh0aGlzLmRhdGEgIT1udWxsICYmIHRoaXMuZGF0YVtjaF0gIT1udWxsKSk7XHJcbiAgICAgICAgICAgIGlmIChjaCA8IHRoaXMuY2hhbm5lbENvdW50KSB7XHJcbiAgICAgICAgICAgICAgaWYgKGR0LmRhdGFbY2hdKSB7XHJcbiAgICAgICAgICAgICAgICBsZXQgZmEgPSBuZXcgRmxvYXQzMkFycmF5KGR0LmRhdGFbY2hdKTtcclxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmRhdGEgJiYgdGhpcy5kYXRhW2NoXSkge1xyXG4gICAgICAgICAgICAgICAgICB0aGlzLmRhdGFbY2hdLnB1c2goZmEpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgY2h1bmtbY2hdID0gZmE7XHJcbiAgICAgICAgICAgICAgICAvLyBVc2Ugc2FtcGxlcyBvZiBjaGFubmVsIDAgdG8gY291bnQgZnJhbWVzIChzYW1wbGVzKVxyXG4gICAgICAgICAgICAgICAgaWYgKGNoID09IDApIHtcclxuICAgICAgICAgICAgICAgICAgdGhpcy5mcmFtZXNSZWNvcmRlZCArPSBmYS5sZW5ndGg7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICBpZiAodGhpcy5hdWRpb091dFN0cmVhbSkge1xyXG4gICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgIHRoaXMuYXVkaW9PdXRTdHJlYW0ud3JpdGUoY2h1bmspO1xyXG4gICAgICAgICAgICAgIC8vIC8vIFJhbmRvbSB0ZXN0IGVycm9yOlxyXG4gICAgICAgICAgICAgIC8vIGlmKE1hdGgucmFuZG9tKCk+MC45OCkge1xyXG4gICAgICAgICAgICAgIC8vICAgdGhyb3cgbmV3IEVycm9yKCdUZXN0Jyk7XHJcbiAgICAgICAgICAgICAgLy8gfVxyXG4gICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcclxuICAgICAgICAgICAgICBpZiAoZXJyIGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRoaXMucGVyc2lzdEVycm9yID0gZXJyO1xyXG4gICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnBlcnNpc3RFcnJvciA9IG5ldyBFcnJvcignRXJyb3IgaGFuZGxpbmcgcmVjb3JkZWQgYXVkaW8gZGF0YScpO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkNhcHR1cmUgZXJyb3I6IFwiICsgZXJyKTtcclxuICAgICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5zdG9wKCk7XHJcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyMikge1xyXG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkNhcHR1cmUgbmV4dCBlcnJvciAoaWdub3JlZCk6IFwiICsgZXJyMik7XHJcbiAgICAgICAgICAgICAgfSBmaW5hbGx5IHtcclxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmxpc3RlbmVyKSB7XHJcbiAgICAgICAgICAgICAgICAgIGxldCBlcnJFeHBsID0gJyc7XHJcbiAgICAgICAgICAgICAgICAgIGlmIChlcnIgaW5zdGFuY2VvZiBET01FeGNlcHRpb24pIHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJFeHBsID0gJzogJyArIGVyci5uYW1lICsgJzogJyArIGVyci5tZXNzYWdlO1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgIHRoaXMubGlzdGVuZXIuZXJyb3IoXCJDb3VsZCBub3QgaGFuZGxlIHJlY29yZGVkIGF1ZGlvIGRhdGFcIiArIGVyckV4cGwsIFwiUGxlYXNlIHRyeSB0byByZWNvcmQgYWdhaW4uXCIpO1xyXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgdGhpcy5jbG9zZSgpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgaWYgKEF1ZGlvU3RvcmFnZVR5cGUuREJfQ0hVTktFRCA9PT0gdGhpcy5fYXVkaW9TdG9yYWdlVHlwZSAmJiB0aGlzLl9wZXJzaXN0ZW50QXVkaW9TdG9yYWdlVGFyZ2V0KSB7XHJcbiAgICAgICAgICAgIHRoaXMuc3RvcmUoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH07XHJcbiAgICB9XHJcbiAgICAvLyBUcmllZCB0byBmaXggdGhhdCBTYWZhcmkgZG9lcyBub3QgcmVjb3JkIHRoZSBzZWNvbmQgY2hhbm5lbFxyXG4gICAgLy8gRG9lcyBub3QgaGVscFxyXG4gICAgLy9hd24uY2hhbm5lbENvdW50PXRoaXMuY2hhbm5lbENvdW50O1xyXG4gICAgLy9hd24uY2hhbm5lbENvdW50TW9kZT0nZXhwbGljaXQnO1xyXG4gICAgLy9jb25zb2xlLmRlYnVnKCdDaGFubmVsIGNvdW50IGV4cGxpY2l0bHkgc2V0IHRvICcrdGhpcy5jaGFubmVsQ291bnQpO1xyXG5cclxuICAgIHRoaXMuYnVmZmVyaW5nTm9kZSA9IGF3bjtcclxuICAgIC8vdGhpcy5idWZmZXJpbmdOb2RlLmNoYW5uZWxDb3VudD10aGlzLmNoYW5uZWxDb3VudDtcclxuICAgIHRoaXMuX29wZW5lZCA9IHRydWU7XHJcbiAgICBpZiAodGhpcy5saXN0ZW5lcikge1xyXG4gICAgICB0aGlzLmxpc3RlbmVyLm9wZW5lZCgpO1xyXG4gICAgfVxyXG4gIH1cclxuICB9XHJcblxyXG4gIG9wZW4oY2hhbm5lbENvdW50OiBudW1iZXIsIHNlbERldmljZUlkPzogQ29uc3RyYWluRE9NU3RyaW5nfHVuZGVmaW5lZCxhdXRvR2FpbkNvbnRyb2xDb25maWdzPzpBcnJheTxBdXRvR2FpbkNvbnRyb2xDb25maWc+fG51bGx8dW5kZWZpbmVkLGFsbG93RWNob0NhbmNlbGxhdGlvbj86Ym9vbGVhbil7XHJcbiAgICAvL2NvbnNvbGUuZGVidWcoXCJDYXB0dXJlIG9wZW46IGN0eCBzdGF0ZTogXCIrdGhpcy5jb250ZXh0LnN0YXRlKTtcclxuICAgIHRoaXMuY29udGV4dD10aGlzLl9hdWRpb0NvbnRleHQoKTtcclxuICAgIGlmKCF0aGlzLmNvbnRleHQpe1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb3VsZCBub3QgZ2V0IGF1ZGlvIGNvbnRleHQhXCIpO1xyXG4gICAgfVxyXG4gICAgaWYodGhpcy5jb250ZXh0LnN0YXRlPT09J3N1c3BlbmRlZCcpe1xyXG4gICAgICAvL2NvbnNvbGUuZGVidWcoXCJDYXB0dXJlIG9wZW46IFJlc3VtZSBjb250ZXh0XCIpO1xyXG4gICAgICB0aGlzLmNvbnRleHQucmVzdW1lKCkudGhlbigoKT0+e1xyXG4gICAgICAgIC8vY29uc29sZS5kZWJ1ZyhcIkNhcHR1cmUgb3BlbiAoY3R4IHJlc3VtZWQpOiBjdHggc3RhdGU6IFwiK3RoaXMuY29udGV4dC5zdGF0ZSk7XHJcbiAgICAgICAgdGhpcy5fb3BlbihjaGFubmVsQ291bnQsIHNlbERldmljZUlkLCBhdXRvR2FpbkNvbnRyb2xDb25maWdzLGFsbG93RWNob0NhbmNlbGxhdGlvbik7XHJcbiAgICAgIH0pLmNhdGNoKChlcnIpPT57XHJcbiAgICAgICAgY29uc29sZS5lcnJvcihlcnIubWVzc2FnZSk7XHJcbiAgICAgICAgdGhyb3cgZXJyO1xyXG4gICAgICB9KVxyXG4gICAgfWVsc2UgaWYodGhpcy5jb250ZXh0LnN0YXRlPT09J2Nsb3NlZCcpIHtcclxuICAgICAgICBjb25zdCBtc2c9J0Vycm9yIG9uIHN0YXJ0IGNhcHR1cmU6IFRoZSBhdWRpbyBjb250ZXh0IGlzIGFscmVhZHkgY2xvc2VkLic7XHJcbiAgICAgICAgY29uc29sZS5lcnJvcihtc2cpO1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihtc2cpO1xyXG4gICAgfWVsc2Uge1xyXG4gICAgICB0aGlzLl9vcGVuKGNoYW5uZWxDb3VudCwgc2VsRGV2aWNlSWQsIGF1dG9HYWluQ29udHJvbENvbmZpZ3MsYWxsb3dFY2hvQ2FuY2VsbGF0aW9uKTtcclxuICAgIH1cclxuXHJcbiAgfVxyXG5cclxuICBfb3BlbihjaGFubmVsQ291bnQ6IG51bWJlciwgc2VsRGV2aWNlSWQ/OiBDb25zdHJhaW5ET01TdHJpbmd8dW5kZWZpbmVkLGF1dG9HYWluQ29udHJvbENvbmZpZ3M/OkFycmF5PEF1dG9HYWluQ29udHJvbENvbmZpZz58bnVsbHx1bmRlZmluZWQsYWxsb3dFY2hvQ2FuY2VsbGF0aW9uPzpib29sZWFuKSB7XHJcbiAgICB0aGlzLmNoYW5uZWxDb3VudCA9IGNoYW5uZWxDb3VudDtcclxuICAgIHRoaXMuZnJhbWVzUmVjb3JkZWQgPSAwO1xyXG5cclxuICAgIHRoaXMuY29udGV4dD10aGlzLl9hdWRpb0NvbnRleHQoKTtcclxuXHJcbiAgICBpZighdGhpcy5jb250ZXh0KXtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ291bGQgbm90IGdldCBhdWRpbyBjb250ZXh0IVwiKTtcclxuICAgIH1cclxuXHJcbiAgICAvL3ZhciBtc2MgPSBuZXcgQXVkaW9TdHJlYW1Db25zdHIoKTtcclxuICAgIC8vIHZhciBtc2M9e307XHJcbiAgICAvL21zYy52aWRlbyA9IGZhbHNlO1xyXG4gICAgLy9tc2MuYXVkaW8gPSB0cnVlO1xyXG5cclxuICAgIC8vIENocm9tZSBhbmQgRmlyZWZveCBzdGVyZW8gY2hhbm5lbHMgYXJlIGlkZW50aWNhbCAhIVxyXG4gICAgLy8gQW5kIGV2ZW4gd29yc2U6IFRoZSBkYXRhIGNvbWluZyBmcm9tIHRoZSBzb3VyY2UgaXMgYWxyZWFkeSBwcmVwcm9jZXNzZWQgb24gRkYgYW5kIENocm9tZS4gSXQgY29udGFpbnMgRFNQIGFydGlmYWN0cyEhXHJcblxyXG4gICAgLy8gaHR0cHM6Ly9idWdzLmNocm9taXVtLm9yZy9wL2Nocm9taXVtL2lzc3Vlcy9kZXRhaWw/aWQ9Mzg3NzM3XHJcbiAgICAvLyBUaGUgd29ya2Fyb3VuZCB0byBzZXQgdGhlc2UgY29uc3RyYWludHMgZG9lcyBfTk9UXyBoZWxwOlxyXG4gICAgLy92YXIgbXNjPXthdWRpbzoge2VjaG9DYW5jZWxsYXRpb246IGZhbHNlLGNoYW5uZWxDb3VudDogMiwgZ29vZ0F1ZGlvTWlycm9yaW5nOiBmYWxzZX0sdmlkZW86IGZhbHNlfTtcclxuXHJcbiAgICAvLyBTYWZhcmkgYXQgbGVhc3QgdmVyc2lvbiAxMTogU3VwcG9ydCBmb3IgbWVkaWEgc3RyZWFtc1xyXG4gICAgLy8gVE9ETyB0ZXN0IGlmIGlucHV0IGlzIHVucHJvY2Vzc2VkXHJcblxyXG4gICAgbGV0IG1zYzpNZWRpYVN0cmVhbUNvbnN0cmFpbnRzO1xyXG4gICAgY29uc29sZS5pbmZvKCdVc2VyIGFnZW50OiAnK25hdmlnYXRvci51c2VyQWdlbnQpO1xyXG5cclxuXHJcbiAgICAgIGxldCB1YT1Vc2VyQWdlbnRCdWlsZGVyLnVzZXJBZ2VudCgpO1xyXG5cclxuICAgICAgLy8gdWEuY29tcG9uZW50cy5mb3JFYWNoKChjKT0+e1xyXG4gICAgICAvLyAgIGNvbnNvbGUuaW5mbyhcIlVBX0NvbXA6IFwiK2MudG9TdHJpbmcoKSk7XHJcbiAgICAgIC8vIH0pXHJcblxyXG4gICAgIGxldCBhZ2NDZmc6QXV0b0dhaW5Db250cm9sQ29uZmlnfG51bGw9bnVsbDtcclxuXHJcbiAgICBsZXQgYXV0b0dhaW5Db250cm9sPWZhbHNlO1xyXG4gICAgbGV0IGNocm9tZUVjaG9DYW5jZWxsYXRpb249ZmFsc2U7XHJcbiAgICBpZihhdXRvR2FpbkNvbnRyb2xDb25maWdzKXtcclxuICAgICAgZm9yKGxldCBhZ2NjIG9mIGF1dG9HYWluQ29udHJvbENvbmZpZ3Mpe1xyXG4gICAgICAgIGlmKGFnY2MucGxhdGZvcm09PT1DZmdQbGF0Zm9ybS5BbmRyb2lkICYmIHVhLmRldGVjdGVkUGxhdGZvcm09PT1QbGF0Zm9ybS5BbmRyb2lkKXtcclxuICAgICAgICAgICAgYWdjQ2ZnPWFnY2M7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZihhZ2NjLnBsYXRmb3JtPT09Q2ZnUGxhdGZvcm0uV2luZG93cyAmJiB1YS5kZXRlY3RlZFBsYXRmb3JtPT09UGxhdGZvcm0uV2luZG93cyl7XHJcbiAgICAgICAgICBhZ2NDZmc9YWdjYztcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBpZihhZ2NDZmcpe1xyXG4gICAgICAgIC8vIFRPRE8gdXNlIEVYQUNUL0lERUFMIGNvbnN0cmFpbnRcclxuICAgICAgICBhdXRvR2FpbkNvbnRyb2w9YWdjQ2ZnLnZhbHVlO1xyXG4gICAgICAgIGlmKENIUk9NRV9BQ1RJVkFURV9FQ0hPX0NBTkNFTExBVElPTl9XSVRIX0FHQyl7XHJcbiAgICAgICAgICBjaHJvbWVFY2hvQ2FuY2VsbGF0aW9uPWFnY0NmZy52YWx1ZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgLy8gVE9ETyBxdWVyeSByZWFsIEFHQyBzdGF0dXNcclxuICAgICAgICB0aGlzLmFnY1N0YXR1cz1hZ2NDZmcudmFsdWU7XHJcbiAgICAgIH1lbHNle1xyXG4gICAgICAgIHRoaXMuYWdjU3RhdHVzPWZhbHNlO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gZGVmYXVsdFxyXG4gICAgbXNjID0ge1xyXG4gICAgICBhdWRpbzoge1xyXG4gICAgICAgIGRldmljZUlkOiBzZWxEZXZpY2VJZCxcclxuICAgICAgICBlY2hvQ2FuY2VsbGF0aW9uOiBmYWxzZSxcclxuICAgICAgICBjaGFubmVsQ291bnQ6IGNoYW5uZWxDb3VudCxcclxuICAgICAgICBhdXRvR2FpbkNvbnRyb2w6IGF1dG9HYWluQ29udHJvbFxyXG4gICAgICB9LFxyXG4gICAgICB2aWRlbzogZmFsc2VcclxuICAgIH07XHJcblxyXG4gICAgaWYgKHVhLmRldGVjdGVkQnJvd3Nlcj09PUJyb3dzZXIuRWRnZSkge1xyXG5cclxuICAgICAgLy8gTWljcm9zb2Z0IEVkZ2Ugc2VuZHMgdW5tb2RpZmllZCBhdWRpb1xyXG4gICAgICAvLyBUaGUgY29uc3RyYWludCBjYW4gZm9sbG93IHRoZSBzcGVjaWZpY2F0aW9uXHJcbiAgICAgIGNvbnNvbGUuaW5mbyhcIlNldHRpbmcgbWVkaWEgdHJhY2sgY29uc3RyYWludHMgZm9yIE1pY3Jvc29mdCBFZGdlLlwiKTtcclxuICAgICAgbXNjID0ge1xyXG4gICAgICAgIGF1ZGlvOiB7XHJcbiAgICAgICAgICBkZXZpY2VJZDogc2VsRGV2aWNlSWQsXHJcbiAgICAgICAgICBlY2hvQ2FuY2VsbGF0aW9uOiBmYWxzZSxcclxuICAgICAgICAgIGNoYW5uZWxDb3VudDogY2hhbm5lbENvdW50LFxyXG4gICAgICAgICAgYXV0b0dhaW5Db250cm9sOiBhdXRvR2FpbkNvbnRyb2xcclxuICAgICAgICB9LFxyXG4gICAgICAgIHZpZGVvOiBmYWxzZVxyXG4gICAgICB9O1xyXG4gICAgfSBlbHNlIGlmICh1YS5kZXRlY3RlZEJyb3dzZXI9PT1Ccm93c2VyLkNocm9tZSkge1xyXG4gICAgICAvLyBHb29nbGUgQ2hyb21lOiB3ZSBuZWVkIHRvIHN3aXRjaCBvZiBlYWNoIG9mIHRoZSBwcmVwcm9jZXNzaW5nIHVuaXRzIGluY2x1ZGluZyB0aGVcclxuICAgICAgY29uc29sZS5pbmZvKFwiU2V0dGluZyBtZWRpYSB0cmFjayBjb25zdHJhaW50cyBmb3IgR29vZ2xlIENocm9tZS5cIik7XHJcblxyXG4gICAgICAvLyBDaHJvbWUgNjAgLT4gNjEgY2hhbmdlZFxyXG4gICAgICAvLyBpdCB3b3JrcyBub3cgd2l0aG91dCBtYW5kYXRvcnkvb3B0aW9uYWwgc3ViLW9iamVjdHNcclxuXHJcblxyXG4gICAgICAvLyBSZXF1aXJlcyBhdCBsZWFzdCBDaHJvbWUgNjFcclxuICAgICAgbXNjID0ge1xyXG4gICAgICAgIGF1ZGlvOiB7XHJcbiAgICAgICAgICBkZXZpY2VJZDogc2VsRGV2aWNlSWQsXHJcbiAgICAgICAgICBjaGFubmVsQ291bnQ6IGNoYW5uZWxDb3VudCxcclxuICAgICAgICAgIGVjaG9DYW5jZWxsYXRpb246IHtleGFjdDpjaHJvbWVFY2hvQ2FuY2VsbGF0aW9ufSxcclxuICAgICAgICAgIGF1dG9HYWluQ29udHJvbDoge2V4YWN0OmF1dG9HYWluQ29udHJvbH0sXHJcbiAgICAgICAgICBzYW1wbGVTaXplOnttaW46IDE2fSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHZpZGVvOiBmYWxzZSxcclxuICAgICAgfVxyXG5cclxuICAgIH0gZWxzZSBpZiAodWEuZGV0ZWN0ZWRCcm93c2VyPT09QnJvd3Nlci5GaXJlZm94KSB7XHJcbiAgICAgIGNvbnNvbGUuaW5mbyhcIlNldHRpbmcgbWVkaWEgdHJhY2sgY29uc3RyYWludHMgZm9yIE1vemlsbGEgRmlyZWZveC5cIik7XHJcbiAgICAgIC8vIEZpcmVmb3hcclxuICAgICAgbXNjID0ge1xyXG4gICAgICAgIGF1ZGlvOiB7XHJcbiAgICAgICAgICAgIGRldmljZUlkOiBzZWxEZXZpY2VJZCxcclxuICAgICAgICAgICAgY2hhbm5lbENvdW50OiBjaGFubmVsQ291bnQsXHJcbiAgICAgICAgICBlY2hvQ2FuY2VsbGF0aW9uOiBmYWxzZSxcclxuICAgICAgICAgICAgYXV0b0dhaW5Db250cm9sOiBhdXRvR2FpbkNvbnRyb2wsXHJcbiAgICAgICAgICBub2lzZVN1cHByZXNzaW9uOiBmYWxzZVxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgdmlkZW86IGZhbHNlLFxyXG4gICAgICB9XHJcblxyXG4gICAgfSBlbHNlIGlmICh1YS5kZXRlY3RlZEJyb3dzZXI9PT1Ccm93c2VyLlNhZmFyaSkge1xyXG4gICAgICBjb25zb2xlLmluZm8oXCJTZXR0aW5nIG1lZGlhIHRyYWNrIGNvbnN0cmFpbnRzIGZvciBTYWZhcmkgYnJvd3Nlci5cIilcclxuICAgICAgLy9jb25zb2xlLmluZm8oXCJBcHBseSB3b3JrYXJvdW5kIGZvciBTYWZhcmk6IEF2b2lkIGRpc2Nvbm5lY3Qgb2Ygc3RyZWFtcy5cIik7XHJcblxyXG4gICAgICB0aGlzLmRpc2Nvbm5lY3RTdHJlYW1zID0gdHJ1ZTtcclxuXHJcbiAgICAgIG1zYyA9IHtcclxuICAgICAgICBhdWRpbzoge1xyXG4gICAgICAgICAgZGV2aWNlSWQ6IHNlbERldmljZUlkLFxyXG4gICAgICAgICAgY2hhbm5lbENvdW50OiBjaGFubmVsQ291bnQsXHJcbiAgICAgICAgICBlY2hvQ2FuY2VsbGF0aW9uOiBhbGxvd0VjaG9DYW5jZWxsYXRpb24/dW5kZWZpbmVkOmZhbHNlXHJcbiAgICAgICAgfSxcclxuICAgICAgICB2aWRlbzogZmFsc2UsXHJcbiAgICAgIH1cclxuXHJcbiAgICB9IGVsc2Uge1xyXG5cclxuICAgICAgLy8gVE9ETyBkZWZhdWx0IGNvbnN0cmFpbnRzIG9yIGVycm9yIEJyb3dzZXIgbm90IHN1cHBvcnRlZFxyXG4gICAgfVxyXG5cclxuXHJcblxyXG4gICAgY29uc29sZS5kZWJ1ZyhcIkF1ZGlvIGNhcHR1cmUsIEFHQzogXCIrdGhpcy5hZ2NTdGF0dXMpXHJcblxyXG4gICAgbGV0IHVtcCA9IG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhKG1zYyk7XHJcbiAgICB1bXAudGhlbigocykgPT4ge1xyXG5cclxuICAgICAgaWYgKHRoaXMuY29udGV4dCkge1xyXG4gICAgICB0aGlzLnN0cmVhbSA9IHM7XHJcblxyXG4gICAgICBsZXQgYVRyYWNrcyA9IHMuZ2V0QXVkaW9UcmFja3MoKTtcclxuXHJcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYVRyYWNrcy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgIGxldCBhVHJhY2sgPSBhVHJhY2tzW2ldO1xyXG5cclxuICAgICAgICBjb25zb2xlLmluZm8oXCJUcmFjayBhdWRpbyBpbmZvOiBpZDogXCIgKyBhVHJhY2suaWQgKyBcIiBraW5kOiBcIiArIGFUcmFjay5raW5kICsgXCIgbGFiZWw6IFxcXCJcIiArIGFUcmFjay5sYWJlbCArIFwiXFxcIlwiKTtcclxuICAgICAgICBsZXQgbXRyU3RzID0gYVRyYWNrLmdldFNldHRpbmdzKCk7XHJcblxyXG4gICAgICAgIC8vIFR5cGVzY3JpcHQgbGliLmRvbS50cyBNZWRpYVRyYWNrU2V0dGluZ3MuY2hhbm5lbENvdW50IGlzIG1pc3NpbmdcclxuICAgICAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vbWRuL2Jyb3dzZXItY29tcGF0LWRhdGEvYmxvYi81NDkzZDhmOTM3ZTA1YjJkZGJkNDFiOTlmNWJkZmFkNGExZjJlZDg1L2FwaS9NZWRpYVRyYWNrU2V0dGluZ3MuanNvblxyXG4gICAgICAgIC8vQHRzLWlnbm9yZVxyXG4gICAgICAgIGNvbnNvbGUuaW5mbyhcIlRyYWNrIGF1ZGlvIHNldHRpbmdzOiBDaCBjbnQ6IFwiICsgbXRyU3RzLmNoYW5uZWxDb3VudCArIFwiLCBBR0M6IFwiICsgbXRyU3RzLmF1dG9HYWluQ29udHJvbCArIFwiLCBFY2hvIGNhbmNlbGwuOiBcIiArIG10clN0cy5lY2hvQ2FuY2VsbGF0aW9uKTtcclxuICAgICAgICBpZiAobXRyU3RzLmF1dG9HYWluQ29udHJvbCkge1xyXG4gICAgICAgICAgdGhpcy5hZ2NTdGF0dXMgPSBtdHJTdHMuYXV0b0dhaW5Db250cm9sO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgY29uc29sZS5kZWJ1ZyhcIkVjaG8gY2FuY2VsbGF0aW9uOiBcIittdHJTdHMuZWNob0NhbmNlbGxhdGlvbik7XHJcblxyXG4gICAgICB9XHJcblxyXG4gICAgICBsZXQgdlRyYWNrcyA9IHMuZ2V0VmlkZW9UcmFja3MoKTtcclxuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB2VHJhY2tzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgbGV0IHZUcmFjayA9IHZUcmFja3NbaV07XHJcbiAgICAgICAgY29uc29sZS5pbmZvKFwiVHJhY2sgdmlkZW8gaW5mbzogaWQ6IFwiICsgdlRyYWNrLmlkICsgXCIga2luZDogXCIgKyB2VHJhY2sua2luZCArIFwiIGxhYmVsOiBcIiArIHZUcmFjay5sYWJlbCk7XHJcbiAgICAgIH1cclxuICAgICAgdGhpcy5tZWRpYVN0cmVhbSA9IHRoaXMuY29udGV4dC5jcmVhdGVNZWRpYVN0cmVhbVNvdXJjZShzKTtcclxuICAgICAgLy8gc3RyZWFtIGNoYW5uZWwgY291bnQgKCBpcyBhbHdheXMgMiAhKVxyXG4gICAgICBsZXQgc3RyZWFtQ2hhbm5lbENvdW50OiBudW1iZXIgPSB0aGlzLm1lZGlhU3RyZWFtLmNoYW5uZWxDb3VudDtcclxuICAgICAgY29uc29sZS5pbmZvKFwiU3RyZWFtIGNoYW5uZWwgY291bnQ6IFwiICsgc3RyZWFtQ2hhbm5lbENvdW50KTtcclxuICAgICAgLy8gaXMgbm90IHNldCEhXHJcbiAgICAgIC8vdGhpcy5jdXJyZW50U2FtcGxlUmF0ZSA9IHRoaXMubWVkaWFTdHJlYW0uc2FtcGxlUmF0ZTtcclxuICAgICAgdGhpcy5jdXJyZW50U2FtcGxlUmF0ZSA9IHRoaXMuY29udGV4dC5zYW1wbGVSYXRlO1xyXG4gICAgICBjb25zb2xlLmluZm8oXCJTb3VyY2UgYXVkaW8gbm9kZTogY2hhbm5lbHM6IFwiICsgc3RyZWFtQ2hhbm5lbENvdW50ICsgXCIgc2FtcGxlcmF0ZTogXCIgKyB0aGlzLmN1cnJlbnRTYW1wbGVSYXRlKTtcclxuICAgICAgaWYgKHRoaXMuYXVkaW9PdXRTdHJlYW0pIHtcclxuICAgICAgICB0aGlzLmF1ZGlvT3V0U3RyZWFtLnNldEZvcm1hdCh0aGlzLmNoYW5uZWxDb3VudCwgdGhpcy5jdXJyZW50U2FtcGxlUmF0ZSk7XHJcbiAgICAgIH1cclxuICAgICAgLy8gVzNDICAtPiBuZXcgbmFtZSBpcyBjcmVhdGVTY3JpcHRQcm9jZXNzb3JcclxuICAgICAgLy9cclxuICAgICAgLy8gQWdhaW4gZGVwcmVjYXRlZCwgYnV0IEF1ZGlvV29ya2VyIG5vdCB5ZXQgaW1wbGVtZW50ZWQgaW4gc3RhYmxlIHJlbGVhc2VzIChKdW5lIDIwMTYpXHJcbiAgICAgIC8vIEF1ZGlvV29ya2VyIGlzIG5vdyBBdWRpb1dvcmtsZXRQcm9jZXNzb3IgLi4uIChNYXkgMjAxNylcclxuXHJcbiAgICAgIC8vIFVwZGF0ZSAxMi0yMDIwOlxyXG4gICAgICAvLyBUaGUgU2NyaXB0UHJvY2Vzc29yTm9kZSBJbnRlcmZhY2UgLSBERVBSRUNBVEVEXHJcblxyXG4gICAgICAvLyBVcGRhdGUgMDYtMjAyMVxyXG4gICAgICAvLyAgQXVkaW9Xb3JrbGV0UHJvY2Vzc29yIGlzIGhlcmUgdG8gc3RheS4gV2ViIEF1ZGlvIEFQSSBoYXMgbm93IFJlY29tbWVuZGF0aW9uIHN0YXR1cyAhXHJcblxyXG4gICAgICBpZiAodGhpcy5jb250ZXh0LmF1ZGlvV29ya2xldCkge1xyXG4gICAgICAgIC8vY29uc3Qgd29ya2xldEZpbGVOYW1lID0gKCdmaWxlLWxvYWRlciEuL2ludGVyY2VwdG9yX3dvcmtsZXQuanMnKTtcclxuICAgICAgICAvL2NvbnN0IHdvcmtsZXRGaWxlTmFtZSA9ICdodHRwOi8vbG9jYWxob3N0OjQyMDAvYXNzZXRzL2ludGVyY2VwdG9yX3dvcmtsZXQuanMnO1xyXG4gICAgICAgIC8vY29uc29sZS5sb2coYXdwU3RyKTtcclxuICAgICAgICBpZiAoQXVkaW9DYXB0dXJlLmNhcHR1cmVJbnRlcmNlcHRvck1vZHVsZVJlZ2lzdGVyZWQpIHtcclxuICAgICAgICAgIC8vIFJlcXVpcmVkIGNhcHR1cmUgaW50ZXJjZXB0b3IgbW9kdWxlIGFscmVhZHkgcmVnaXN0ZXJlZFxyXG4gICAgICAgICAgdGhpcy5hZGRDYXB0dXJlSW50ZXJjZXB0b3IoKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG5cclxuICAgICAgICAgIC8vIFJlZ2lzdGVyIGNhcHR1cmUgaW50ZXJjZXB0b3IgbW9kdWxlXHJcbiAgICAgICAgICBsZXQgYXVkaW9Xb3JrbGV0TW9kdWxlQmxvYiA9IG5ldyBCbG9iKFthd3BTdHJdLCB7dHlwZTogJ3RleHQvamF2YXNjcmlwdCd9KTtcclxuXHJcbiAgICAgICAgICBsZXQgYXVkaW9Xb3JrbGV0TW9kdWxlQmxvYlVybCA9IHdpbmRvdy5VUkwuY3JlYXRlT2JqZWN0VVJMKGF1ZGlvV29ya2xldE1vZHVsZUJsb2IpO1xyXG5cclxuICAgICAgICAgIHRoaXMuY29udGV4dC5hdWRpb1dvcmtsZXQuYWRkTW9kdWxlKGF1ZGlvV29ya2xldE1vZHVsZUJsb2JVcmwpLnRoZW4oKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgQXVkaW9DYXB0dXJlLmNhcHR1cmVJbnRlcmNlcHRvck1vZHVsZVJlZ2lzdGVyZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5hZGRDYXB0dXJlSW50ZXJjZXB0b3IoKTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICApLmNhdGNoKChlcnJvcjogYW55KSA9PiB7XHJcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdDb3VsZCBub3QgYWRkIG1vZHVsZSAnICsgZXJyb3IpO1xyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2UgaWYgKHRoaXMuY29udGV4dC5jcmVhdGVTY3JpcHRQcm9jZXNzb3IpIHtcclxuICAgICAgICAvLyBUaGUgU2NyaXB0UHJvY2Vzc29yTm9kZSBJbnRlcmZhY2UgLSBERVBSRUNBVEVEIE9ubHkgYXMgZmFsbGJhY2tcclxuICAgICAgICAvLyBUT0RPIHNob3VsZCB3ZSB1c2Ugc3RyZWFtQ2hhbm5lbENvdW50IG9yIGNoYW5uZWxDb3VudCBoZXJlID9cclxuICAgICAgICBsZXQgc2NyaXB0UHJvY2Vzc29yTm9kZSA9IHRoaXMuY29udGV4dC5jcmVhdGVTY3JpcHRQcm9jZXNzb3IoQXVkaW9DYXB0dXJlLkJVRkZFUl9TSVpFLCBzdHJlYW1DaGFubmVsQ291bnQsIHN0cmVhbUNoYW5uZWxDb3VudCk7XHJcbiAgICAgICAgdGhpcy5idWZmZXJpbmdOb2RlID0gc2NyaXB0UHJvY2Vzc29yTm9kZTtcclxuICAgICAgICBsZXQgYyA9IDA7XHJcbiAgICAgICAgaWYgKHNjcmlwdFByb2Nlc3Nvck5vZGUub25hdWRpb3Byb2Nlc3MpIHtcclxuICAgICAgICAgIHNjcmlwdFByb2Nlc3Nvck5vZGUub25hdWRpb3Byb2Nlc3MgPSAoZTogQXVkaW9Qcm9jZXNzaW5nRXZlbnQpID0+IHtcclxuXHJcbiAgICAgICAgICAgIGlmICh0aGlzLmNhcHR1cmluZykge1xyXG4gICAgICAgICAgICAgIGxldCBpbkJ1ZmZlciA9IGUuaW5wdXRCdWZmZXI7XHJcbiAgICAgICAgICAgICAgLy8gb25seSBwcm9jZXNzIHJlcXVlc3RlZCBjb3VudCBvZiBjaGFubmVsc1xyXG4gICAgICAgICAgICAgIGxldCBjdXJyZW50QnVmZmVycyA9IG5ldyBBcnJheTxGbG9hdDMyQXJyYXk+KGNoYW5uZWxDb3VudCk7XHJcbiAgICAgICAgICAgICAgZm9yIChsZXQgY2g6IG51bWJlciA9IDA7IGNoIDwgY2hhbm5lbENvdW50OyBjaCsrKSB7XHJcbiAgICAgICAgICAgICAgICBsZXQgY2hTYW1wbGVzID0gaW5CdWZmZXIuZ2V0Q2hhbm5lbERhdGEoY2gpO1xyXG4gICAgICAgICAgICAgICAgbGV0IGNoU2FtcGxlc0NvcHkgPSBjaFNhbXBsZXMuc2xpY2UoMCk7XHJcbiAgICAgICAgICAgICAgICBjdXJyZW50QnVmZmVyc1tjaF0gPSBjaFNhbXBsZXNDb3B5LnNsaWNlKDApO1xyXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuZGF0YSkge1xyXG4gICAgICAgICAgICAgICAgICB0aGlzLmRhdGFbY2hdLnB1c2goY2hTYW1wbGVzQ29weSk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBpZiAoREVCVUdfVFJBQ0VfTEVWRUwgPiA4KSB7XHJcbiAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZGVidWcoXCJQcm9jZXNzIFwiICsgY2hTYW1wbGVzQ29weS5sZW5ndGggKyBcIiBzYW1wbGVzLlwiKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIHRoaXMuZnJhbWVzUmVjb3JkZWQgKz0gY2hTYW1wbGVzQ29weS5sZW5ndGg7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIGMrKztcclxuICAgICAgICAgICAgICBpZiAodGhpcy5hdWRpb091dFN0cmVhbSkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5hdWRpb091dFN0cmVhbS53cml0ZShjdXJyZW50QnVmZmVycyk7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgICAgdGhpcy5fb3BlbmVkID0gdHJ1ZTtcclxuICAgICAgICAgIGlmICh0aGlzLmxpc3RlbmVyKSB7XHJcbiAgICAgICAgICAgIHRoaXMubGlzdGVuZXIub3BlbmVkKCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHRoaXMubGlzdGVuZXIuZXJyb3IoJ0Jyb3dzZXIgZG9lcyBub3Qgc3VwcG9ydCBhdWRpbyBwcm9jZXNzaW5nIChTY3JpcHRQcm9jZXNzb3Iub25hdWRpb3Byb2Nlc3MgbWV0aG9kIG5vdCBmb3VuZCkhJyk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRoaXMubGlzdGVuZXIuZXJyb3IoJ0Jyb3dzZXIgZG9lcyBub3Qgc3VwcG9ydCBhdWRpbyBwcm9jZXNzaW5nIChuZWl0aGVyIEF1ZGlvV29ya2xldFByb2Nlc3NvciBub3IgU2NyaXB0UHJvY2Vzc29yKSEnKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgICAgIH0sIChlKSA9PiB7XHJcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGUgKyBcIiBFcnJvciBuYW1lOiBcIiArZS5uYW1lKTtcclxuICAgICAgICAgIGlmICh0aGlzLmxpc3RlbmVyKSB7XHJcbiAgICAgICAgICAgIGlmKCdOb3RBbGxvd2VkRXJyb3InID09PSBlLm5hbWUpe1xyXG4gICAgICAgICAgICAgIHRoaXMubGlzdGVuZXIuZXJyb3IoJ05vdCBhbGxvd2VkIHRvIHVzZSB5b3VyIG1pY3JvcGhvbmUuJywnUGxlYXNlIG1ha2Ugc3VyZSB0aGF0IG1pY3JvcGhvbmUgYWNjZXNzIGlzIGFsbG93ZWQgZm9yIHRoaXMgd2ViIHBhZ2UgYW5kIHJlbG9hZCB0aGUgcGFnZS4nKTtcclxuICAgICAgICAgICAgfWVsc2UgaWYoJ05vdFJlYWRhYmxlRXJyb3InID09PSBlLm5hbWUpe1xyXG4gICAgICAgICAgICAgIHRoaXMubGlzdGVuZXIuZXJyb3IoJ0NvdWxkIG5vdCByZWFkIGZyb20geW91ciBhdWRpbyBkZXZpY2UuJywnUGxlYXNlIG1ha2Ugc3VyZSB5b3VyIGF1ZGlvIGRldmljZSBpcyB3b3JraW5nLicpO1xyXG4gICAgICAgICAgICB9ZWxzZSBpZignT3ZlcmNvbnN0cmFpbmVkRXJyb3InID09PSBlLm5hbWUpe1xyXG4gICAgICAgICAgICAgIGxldCBlTXNnPWUubXNnP2UubXNnOidPdmVyY29uc3RyYWluZWQgbWVkaWEgZGV2aWNlIHJlcXVlc3QgZXJyb3IuJztcclxuICAgICAgICAgICAgICB0aGlzLmxpc3RlbmVyLmVycm9yKGVNc2cpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIHRoaXMubGlzdGVuZXIuZXJyb3IoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIClcclxuICB9XHJcblxyXG4gIHByaXZhdGUgX3N0YXJ0KCl7XHJcbiAgICBpZih0aGlzLmNvbnRleHQpIHtcclxuICAgICAgdGhpcy5pbml0RGF0YSgpO1xyXG4gICAgICBpZiAodGhpcy5hdWRpb091dFN0cmVhbSkge1xyXG4gICAgICAgIHRoaXMuYXVkaW9PdXRTdHJlYW0ubmV4dFN0cmVhbSgpXHJcbiAgICAgIH1cclxuICAgICAgdGhpcy5jYXB0dXJpbmcgPSB0cnVlO1xyXG4gICAgICBpZiAodGhpcy5idWZmZXJpbmdOb2RlKSB7XHJcbiAgICAgICAgdGhpcy5tZWRpYVN0cmVhbS5jb25uZWN0KHRoaXMuYnVmZmVyaW5nTm9kZSk7XHJcbiAgICAgICAgdGhpcy5idWZmZXJpbmdOb2RlLmNvbm5lY3QodGhpcy5jb250ZXh0LmRlc3RpbmF0aW9uKTtcclxuICAgICAgfVxyXG4gICAgICBpZiAodGhpcy5saXN0ZW5lcikge1xyXG4gICAgICAgIHRoaXMubGlzdGVuZXIuc3RhcnRlZCgpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBzdGFydCgpIHtcclxuICAgIGlmKHRoaXMuY29udGV4dCkge1xyXG4gICAgICBjb25zdCBhU3QgPSB0aGlzLmNvbnRleHQuc3RhdGU7XHJcbiAgICAgIGlmIChhU3QgPT09ICdydW5uaW5nJykge1xyXG4gICAgICAgIHRoaXMuX3N0YXJ0KCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgY29uc29sZS5kZWJ1ZyhcIkNhcHR1cmUgc3RhcnQ6IGF1ZGlvIGNvbnRleHQgbm90IHJ1bm5pbmcsIHN0YXRlOiBcIiArIGFTdCArIFwiLCByZXN1bWluZy4uLlwiKTtcclxuICAgICAgICB0aGlzLmNvbnRleHQucmVzdW1lKCkudGhlbigoKSA9PiB7XHJcbiAgICAgICAgICBjb25zb2xlLmRlYnVnKFwiQ2FwdHVyZSBzdGFydDogYXVkaW8gY29udGV4dCByZXN1bWVkLCBzdGFydGluZy4uLlwiKTtcclxuICAgICAgICAgIHRoaXMuX3N0YXJ0KCk7XHJcbiAgICAgICAgfSlcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgc3RvcCgpIHtcclxuXHJcbiAgICBpZiAodGhpcy5kaXNjb25uZWN0U3RyZWFtcyAmJiB0aGlzLmJ1ZmZlcmluZ05vZGUpIHtcclxuICAgICAgdGhpcy5tZWRpYVN0cmVhbS5kaXNjb25uZWN0KHRoaXMuYnVmZmVyaW5nTm9kZSk7XHJcbiAgICAgIGlmKHRoaXMuY29udGV4dCkge1xyXG4gICAgICAgIHRoaXMuYnVmZmVyaW5nTm9kZS5kaXNjb25uZWN0KHRoaXMuY29udGV4dC5kZXN0aW5hdGlvbik7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICB0cnkge1xyXG4gICAgICBpZiAodGhpcy5hdWRpb091dFN0cmVhbSkge1xyXG4gICAgICAgIHRoaXMuYXVkaW9PdXRTdHJlYW0uZmx1c2goKTtcclxuICAgICAgfVxyXG4gICAgfWNhdGNoKGVycil7XHJcbiAgICAgIGNvbnNvbGUuZXJyb3IoXCJDb3VsZCBub3QgZmx1c2ggY2FwdHVyZSBzdHJlYW0uXCIpO1xyXG4gICAgIHRocm93IGVycjtcclxuICAgIH1maW5hbGx5IHtcclxuICAgICAgdGhpcy5jYXB0dXJpbmcgPSBmYWxzZTtcclxuICAgICAgaWYgKHRoaXMuaW5kZGJBdWRpb0J1ZmZlciAmJiB0aGlzLnBlcnNpc3RFcnJvcikge1xyXG4gICAgICAgIC8vIERlbGV0ZSBpbnZhbGlkIHBlcnNpc3RlbnQgYXVkaW8gZGF0YSBhbmQgaG9wZSB0aGF0IGl0IHdpbGwgYmUgY29tcGxldGVseSB1cGxvYWRlZCB0byB0aGUgc2VydmVyXHJcbiAgICAgICAgdGhpcy5pbmRkYkF1ZGlvQnVmZmVyLnJlbGVhc2VBdWRpb0RhdGEoKTtcclxuICAgICAgICB0aGlzLmluZGRiQXVkaW9CdWZmZXIgPSBudWxsO1xyXG4gICAgICB9XHJcbiAgICAgIGlmICh0aGlzLmxpc3RlbmVyICYmICh0aGlzLnBlcnNpc3RFcnJvciB8fCB0aGlzLnBlcnNpc3RlZCkpIHtcclxuICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJTdG9wcGVkIGJ5IHN0b3AoKSBtZXRob2QgY2FsbFwiKTtcclxuICAgICAgICB0aGlzLmxpc3RlbmVyLnN0b3BwZWQoKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcblxyXG4gIHN0b3JlKCl7XHJcbiAgIC8vIGlmKHRoaXMuZGIgJiYgdGhpcy5yZWNVVUlEKXtcclxuICAgLy8gICAgbGV0IHRyPSB0aGlzLmRiLnRyYW5zYWN0aW9uKFNwckRiLlJFQ09SRElOR19GSUxFX0NIVU5LU19PQkpFQ1RfU1RPUkVfTkFNRSwgJ3JlYWR3cml0ZScpO1xyXG4gICAvLyAgICBsZXQgcmVjRmlsZU9ialN0b3JlID0gdHIub2JqZWN0U3RvcmUoU3ByRGIuUkVDT1JESU5HX0ZJTEVfQ0hVTktTX09CSkVDVF9TVE9SRV9OQU1FKTtcclxuICAgLy9cclxuICAgLy8gICAgICB0cnkge1xyXG4gICAvLyAgICAgICAgbGV0IGNoMERhdGE9dGhpcy5kYXRhWzBdO1xyXG4gICAvLyAgICAgICAgbGV0IGRhdGFDaGtDbnQ9Y2gwRGF0YS5sZW5ndGg7XHJcbiAgIC8vICAgICAgICAgIGxldCBwb3MgPSAwO1xyXG4gICAvLyAgICAgICAgICBmb3IgKGxldCBjaENrSWR4ID0gMDsgY2hDa0lkeCA8IGRhdGFDaGtDbnQ7IGNoQ2tJZHgrKykge1xyXG4gICAvLyAgICAgICAgICAgIGxldCBidWZMZW49MDtcclxuICAgLy8gICAgICAgICAgICBmb3IgKGxldCBjaCA9IDA7IGNoIDwgdGhpcy5jaGFubmVsQ291bnQ7IGNoKyspIHtcclxuICAgLy8gICAgICAgICAgICAgIGxldCBjaENoayA9IHRoaXMuZGF0YVtjaF1bY2hDa0lkeF07XHJcbiAgIC8vICAgICAgICAgICAgICBidWZMZW4gPSBjaENoay5sZW5ndGg7XHJcbiAgIC8vICAgICAgICAgICAgICAvL2xldCBjYWNoZUlkID0gdXVpZCArICdfJyArIGNoICsgJ18nICsgY2hDa0lkeDtcclxuICAgLy8gICAgICAgICAgICAgIGxldCBjaGtEYklkID0gW3RoaXMucmVjVVVJRCwgdGhpcy5pbmREYkNoa0lkeCArIGNoQ2tJZHgsIGNoXTtcclxuICAgLy8gICAgICAgICAgICAgIGxldCBjciA9IHJlY0ZpbGVPYmpTdG9yZS5hZGQoY2hDaGssIGNoa0RiSWQpO1xyXG4gICAvLyAgICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiQWRkZWQ6IFwiK2NoK1wiIFwiKyh0aGlzLmluZERiQ2hrSWR4K2NoQ2tJZHgpKTtcclxuICAgLy8gICAgICAgICAgICAgIGNyLm9uc3VjY2Vzcz0oKT0+e1xyXG4gICAvLyAgICAgICAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJTdG9yZWQgYXVkaW8gZGF0YSB0byBpbmRleGVkIGRiXCIpO1xyXG4gICAvLyAgICAgICAgICAgICAgfVxyXG4gICAvLyAgICAgICAgICAgICAgY3Iub25lcnJvcj0oKT0+e1xyXG4gICAvLyAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3Igc3RvcmluZyBhdWRpbyBkYXRhIHRvIGluZGV4ZWQgZGJcIik7XHJcbiAgIC8vICAgICAgICAgICAgICB9XHJcbiAgIC8vICAgICAgICAgICAgfVxyXG4gICAvLyAgICAgICAgICAgIHBvcyArPSBidWZMZW47XHJcbiAgIC8vICAgICAgICB9XHJcbiAgIC8vICAgICAgICB0aGlzLmluZERiQ2hrSWR4Kz1kYXRhQ2hrQ250O1xyXG4gICAvL1xyXG4gICAvLyAgICAgICAgdHIub25lcnJvciA9IChlcnIpID0+IHtcclxuICAgLy8gICAgICAgICAgY29uc29sZS5lcnJvcignRmFpbGVkIHRvIGNhY2hlIGF1ZGlvIGRhdGEgdG8gaW5kZXhlZCBkYjogJyArIGVycilcclxuICAgLy8gICAgICAgIH1cclxuICAgLy8gICAgICAgIHRyLm9uY29tcGxldGUgPSAoKSA9PiB7XHJcbiAgIC8vICAgICAgICAgIC8vY29uc29sZS5kZWJ1ZygnVHJhbnNmZXJyZWQgY2FwdHVyZSBhdWRpbyBkYXRhIHRvIGluZGV4ZWQgZGIsIGRlbGV0aW5nIG9yaWdpbmFsIGRhdGEgZnJvbSBtZW1vcnkuLi4nKTtcclxuICAgLy9cclxuICAgLy8gICAgICAgICAgLy8vIEF1ZGlvIGRhdGEgc2F2ZWQgdG8gaW5kZXggZGIgZGVsZXRlIGZyb20gaW4gbWVtb3J5IGRhdGEgYXJyYXlcclxuICAgLy8gICAgICAgICAgZm9yIChsZXQgY2ggPSAwOyBjaCA8IHRoaXMuY2hhbm5lbENvdW50OyBjaCsrKSB7XHJcbiAgIC8vICAgICAgICAgICB0aGlzLmRhdGFbY2hdLnNwbGljZSgwKTtcclxuICAgLy8gICAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJTcGxpY2VkL3JlbW92ZWQgY2g6IFwiK2NoKTtcclxuICAgLy8gICAgICAgICAgfVxyXG4gICAvL1xyXG4gICAvLyAgICAgICAgICB0aGlzLnBlcnNpc3RlZD10cnVlO1xyXG4gICAvLyAgICAgICAgICBpZih0aGlzLmxpc3RlbmVyICYmICF0aGlzLmNhcHR1cmluZyl7XHJcbiAgIC8vICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiU3RvcHBlZCBieSBpbmRleGVkIGRiIGhvb2tcIik7XHJcbiAgIC8vICAgICAgICAgICAgdGhpcy5saXN0ZW5lci5zdG9wcGVkKCk7XHJcbiAgIC8vICAgICAgICAgIH1cclxuICAgLy8gICAgICAgIH1cclxuICAgLy8gICAgICAgIC8vIENvbW1pdCBjaHVua3NcclxuICAgLy8gICAgICAgIHRoaXMucGVyc2lzdGVkPWZhbHNlO1xyXG4gICAvLyAgICAgICAgdHIuY29tbWl0KCk7XHJcbiAgIC8vICAgICAgfSBjYXRjaCAoZXJyKSB7XHJcbiAgIC8vICAgICAgICBjb25zb2xlLmVycm9yKCdUcmFuc2ZlciBjYXB0dXJlIGF1ZGlvIGRhdGEgZXJyb3I6ICcrZXJyKTtcclxuICAgLy8gICAgICB9XHJcbiAgIC8vICAgIH1cclxuXHJcbiAgICAvLyBpZighdGhpcy5pbmRkYkF1ZGlvQnVmZmVyICYmIHRoaXMuX3BlcnNpc3RlbnRBdWRpb1N0b3JhZ2VUYXJnZXQgJiYgdGhpcy5yZWNVVUlEKSB7XHJcbiAgICAvLyAgIHRoaXMuaW5kZGJBdWRpb0J1ZmZlciA9IG5ldyBJbmRleGVkRGJBdWRpb0J1ZmZlcih0aGlzLl9wZXJzaXN0ZW50QXVkaW9TdG9yYWdlVGFyZ2V0LCB0aGlzLmNoYW5uZWxDb3VudCx0aGlzLmN1cnJlbnRTYW1wbGVSYXRlLEF1ZGlvQ2FwdHVyZS5CVUZGRVJfU0laRSwwLHRoaXMucmVjVVVJRClcclxuICAgIC8vIH1cclxuICAgIGlmKHRoaXMuaW5kZGJBdWRpb0J1ZmZlciAmJiB0aGlzLmRhdGEpe1xyXG5cclxuICAgICAgLy8gVHJ5IHRvIGFwcGVuZCB0b1xyXG4gICAgICB0aGlzLmluZGRiQXVkaW9CdWZmZXIuYXBwZW5kUmF3QXVkaW9EYXRhKHRoaXMuZGF0YSkuc3Vic2NyaWJlKHtcclxuICAgICAgICBjb21wbGV0ZTogKCkgPT4ge1xyXG4gICAgICAgICAgLy9jb25zb2xlLmRlYnVnKCdUcmFuc2ZlcnJlZCBjYXB0dXJlIGF1ZGlvIGRhdGEgdG8gaW5kZXhlZCBkYiwgZGVsZXRpbmcgb3JpZ2luYWwgZGF0YSBmcm9tIG1lbW9yeS4uLicpO1xyXG5cclxuICAgICAgICAgIC8vLyBBdWRpbyBkYXRhIHNhdmVkIHRvIGluZGV4IGRiIGRlbGV0ZSBmcm9tIGluIG1lbW9yeSBkYXRhIGFycmF5XHJcbiAgICAgICAgICBpZih0aGlzLmRhdGEpIHtcclxuICAgICAgICAgICAgZm9yIChsZXQgY2ggPSAwOyBjaCA8IHRoaXMuY2hhbm5lbENvdW50OyBjaCsrKSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5kYXRhW2NoXS5zcGxpY2UoMCk7XHJcbiAgICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiU3BsaWNlZC9yZW1vdmVkIGNoOiBcIitjaCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHRoaXMucGVyc2lzdGVkID0gdHJ1ZTtcclxuICAgICAgICAgIGlmICh0aGlzLmxpc3RlbmVyICYmICF0aGlzLmNhcHR1cmluZykge1xyXG4gICAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJTdG9wcGVkIGJ5IGluZGV4ZWQgZGIgaG9va1wiKTtcclxuICAgICAgICAgICAgdGhpcy5saXN0ZW5lci5zdG9wcGVkKCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSxlcnJvcjooZXJyKT0+e1xyXG4gICAgICAgICAgLy8gT25seSBsb2cgdGhlIGZpcnN0IGVycm9yXHJcbiAgICAgICAgICBpZighdGhpcy5wZXJzaXN0RXJyb3IpIHtcclxuICAgICAgICAgICAgdGhpcy5wZXJzaXN0RXJyb3IgPSBlcnI7XHJcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciBwZXJzaXN0aW5nIGF1ZGlvIGRhdGE6IFwiICsgZXJyKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgICB0aGlzLnBlcnNpc3RlZD1mYWxzZTtcclxuICAgIH1cclxuICB9XHJcblxyXG5cclxuICBjbG9zZSgpIHtcclxuICAgIGlmKHRoaXMubWVkaWFTdHJlYW0pIHtcclxuICAgICAgdGhpcy5tZWRpYVN0cmVhbS5kaXNjb25uZWN0KCk7XHJcbiAgICB9XHJcbiAgICBpZiAodGhpcy5zdHJlYW0pIHtcclxuICAgICAgY29uc3QgbXRzID0gdGhpcy5zdHJlYW0uZ2V0VHJhY2tzKCk7XHJcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbXRzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgbXRzW2ldLnN0b3AoKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgdGhpcy5fb3BlbmVkPWZhbHNlO1xyXG4gIH1cclxuXHJcbiAgYXVkaW9CdWZmZXIoKTogQXVkaW9CdWZmZXIgfG51bGx7XHJcbiAgICBsZXQgYWI6IEF1ZGlvQnVmZmVyfG51bGw9bnVsbDtcclxuICAgIGlmKHRoaXMuY29udGV4dCAmJiB0aGlzLmRhdGEpIHtcclxuICAgICAgbGV0IGZyYW1lTGVuOiBudW1iZXIgPSAwO1xyXG5cclxuICAgICAgbGV0IGNoMERhdGEgPSB0aGlzLmRhdGFbMF07XHJcblxyXG4gICAgICBmb3IgKGxldCBjaDBDaGsgb2YgY2gwRGF0YSkge1xyXG4gICAgICAgIGZyYW1lTGVuICs9IGNoMENoay5sZW5ndGg7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgYWIgPSB0aGlzLmNvbnRleHQuY3JlYXRlQnVmZmVyKHRoaXMuY2hhbm5lbENvdW50LCBmcmFtZUxlbiwgdGhpcy5jb250ZXh0LnNhbXBsZVJhdGUpO1xyXG4gICAgICB9IGNhdGNoIChlcnIpIHtcclxuICAgICAgICBpZiAoZXJyIGluc3RhbmNlb2YgRE9NRXhjZXB0aW9uKSB7XHJcbiAgICAgICAgICBpZiAoZXJyLm5hbWUgPT09ICdOb3RTdXBwb3J0ZWRFcnJvcicpIHtcclxuICAgICAgICAgICAgaWYgKGZyYW1lTGVuID09IDApIHtcclxuICAgICAgICAgICAgICAvLyBFbXB0eSBidWZmZXJzIGFyZSBub3Qgc3VwcG9ydGVkIGJ5IENocm9taXVtXHJcbiAgICAgICAgICAgICAgLy8gQ3JlYXRlIGR1bW15IGJ1ZmZlciB3aXRoIG9uZSBzYW1wbGVcclxuICAgICAgICAgICAgICBhYiA9IHRoaXMuY29udGV4dC5jcmVhdGVCdWZmZXIodGhpcy5jaGFubmVsQ291bnQsIDEsIHRoaXMuY29udGV4dC5zYW1wbGVSYXRlKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICB0aHJvdyBlcnI7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRocm93IGVycjtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2UgaWYgKGVyciBpbnN0YW5jZW9mIFJhbmdlRXJyb3IpIHtcclxuICAgICAgICAgIC8vIE91dCBvZiBtZW1vcnlcclxuICAgICAgICAgIC8vIFRPRE8gV2hhdCB0byBkbyA/P1xyXG4gICAgICAgICAgdGhyb3cgZXJyO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnI7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGZvciAobGV0IGNoID0gMDsgY2ggPCB0aGlzLmNoYW5uZWxDb3VudDsgY2grKykge1xyXG4gICAgICAgIGxldCBjaEQgPSBhYi5nZXRDaGFubmVsRGF0YShjaCk7XHJcbiAgICAgICAgbGV0IHBvcyA9IDA7XHJcbiAgICAgICAgZm9yIChsZXQgY2hDaGsgb2YgdGhpcy5kYXRhW2NoXSkge1xyXG4gICAgICAgICAgbGV0IGJ1ZkxlbiA9IGNoQ2hrLmxlbmd0aDtcclxuICAgICAgICAgIGNoRC5zZXQoY2hDaGssIHBvcyk7XHJcbiAgICAgICAgICBwb3MgKz0gYnVmTGVuO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIGFiO1xyXG4gIH1cclxuXHJcbiAgYXVkaW9CdWZmZXJBcnJheSgpOkFycmF5QXVkaW9CdWZmZXJ8bnVsbHtcclxuICAgICAgbGV0IGFyckFiOkFycmF5QXVkaW9CdWZmZXJ8bnVsbD1udWxsO1xyXG4gICAgICBpZih0aGlzLmRhdGEpIHtcclxuICAgICAgICBhcnJBYj1uZXcgQXJyYXlBdWRpb0J1ZmZlcih0aGlzLmNoYW5uZWxDb3VudCwgdGhpcy5jdXJyZW50U2FtcGxlUmF0ZSwgdGhpcy5kYXRhKTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gYXJyQWI7XHJcbiAgfVxyXG5cclxuICBpbmRkYkF1ZGlvQnVmZmVyQXJyYXkoKTpJbmRleGVkRGJBdWRpb0J1ZmZlcnxudWxse1xyXG4gICAgaWYodGhpcy5wZXJzaXN0RXJyb3Ipe1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1lbHNlIHtcclxuICAgICAgcmV0dXJuIHRoaXMuaW5kZGJBdWRpb0J1ZmZlcjtcclxuICAgIH1cclxuICB9XHJcblxyXG5cclxufVxyXG5cclxuIl19