speechrecorderng 3.10.13 → 3.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,402 +0,0 @@
1
- import { Action } from '../../action/action';
2
- import { ArrayAudioBuffer } from "../array_audio_buffer";
3
- import { ArrayAudioBufferSourceNode } from "./array_audio_buffer_source_node";
4
- import { IndexedDbAudioBuffer } from "../inddb_audio_buffer";
5
- import { AudioSourceWorkletModuleLoader } from "./audio_source_worklet_module_loader";
6
- import { IndexedDbAudioBufferSourceNode } from "./inddb_audio_buffer_source_node";
7
- import { NetAudioBuffer } from "../net_audio_buffer";
8
- import { NetAudioBufferSourceNode } from "./net_audio_buffer_source_node";
9
- import { AudioBufferSource } from "../audio_data_holder";
10
- import { AudioContextProvider } from "../context";
11
- export var EventType;
12
- (function (EventType) {
13
- EventType[EventType["CLOSED"] = 0] = "CLOSED";
14
- EventType[EventType["READY"] = 1] = "READY";
15
- EventType[EventType["STARTED"] = 2] = "STARTED";
16
- EventType[EventType["POS_UPDATE"] = 3] = "POS_UPDATE";
17
- EventType[EventType["STOPPED"] = 4] = "STOPPED";
18
- EventType[EventType["ENDED"] = 5] = "ENDED";
19
- EventType[EventType["ERROR"] = 6] = "ERROR";
20
- })(EventType || (EventType = {}));
21
- export class AudioPlayerEvent {
22
- constructor(type, timePosition) {
23
- this._type = type;
24
- this._timePosition = timePosition;
25
- }
26
- get type() {
27
- return this._type;
28
- }
29
- get timePosition() {
30
- return this._timePosition;
31
- }
32
- }
33
- export class AudioPlayer {
34
- get autoPlayOnSelectToggleAction() {
35
- return this._autoPlayOnSelectToggleAction;
36
- }
37
- static { this.DEFAULT_BUFSIZE = 8192; }
38
- constructor(listener) {
39
- this.running = false;
40
- this.context = null;
41
- this.ready = false;
42
- this._audioClip = null;
43
- this._audioSource = null;
44
- this.sourceBufferNode = null;
45
- this.sourceAudioWorkletNode = null;
46
- this.playStartTime = null;
47
- this.timerVar = null;
48
- this.listener = listener;
49
- this.bufSize = AudioPlayer.DEFAULT_BUFSIZE;
50
- this.n = navigator;
51
- this.buffPos = 0;
52
- this.zeroBufCnt = 0;
53
- this.zb = new Float32Array(this.bufSize);
54
- this._startAction = new Action('Start');
55
- this._startAction.disabled = true;
56
- this._startAction.onAction = () => this.start();
57
- this._startSelectionAction = new Action('Start selected');
58
- this._startSelectionAction.disabled = true;
59
- this._startSelectionAction.onAction = () => this.startSelected();
60
- this._autoPlayOnSelectToggleAction = new Action("Autoplay on select", false);
61
- this._stopAction = new Action('Stop');
62
- this._stopAction.disabled = true;
63
- this._stopAction.onAction = () => this.stop();
64
- }
65
- _audioContext() {
66
- if (!this.context) {
67
- this.context = AudioContextProvider.audioContextInstance();
68
- if (this.context) {
69
- this.context.addEventListener('statechange', (ev) => {
70
- if (this.context && this.context.state !== 'running') {
71
- this.stop();
72
- }
73
- });
74
- }
75
- }
76
- return this.context;
77
- }
78
- get startAction() {
79
- return this._startAction;
80
- }
81
- get startSelectionAction() {
82
- return this._startSelectionAction;
83
- }
84
- get stopAction() {
85
- return this._stopAction;
86
- }
87
- set audioClip(audioClip) {
88
- this._audioClip = audioClip;
89
- let length = 0;
90
- let chs = 0;
91
- if (audioClip && audioClip.audioDataHolder) {
92
- let audioDataHolder = audioClip.audioDataHolder;
93
- chs = audioDataHolder.numberOfChannels;
94
- if (chs > 0) {
95
- length = audioDataHolder.frameLen;
96
- //if (chs > this.context.destination.maxChannelCount) {
97
- // // TODO exception
98
- //}
99
- }
100
- this.audioSource = audioDataHolder.audioSource;
101
- audioClip.addSelectionObserver((ac) => {
102
- this._startSelectionAction.disabled = this.startSelectionDisabled();
103
- if (!this.startSelectionAction.disabled && this._autoPlayOnSelectToggleAction.value) {
104
- this.startSelected();
105
- }
106
- });
107
- }
108
- else {
109
- this.audioSource = null;
110
- }
111
- }
112
- get audioSource() {
113
- return this._audioSource;
114
- }
115
- set audioSource(value) {
116
- this.stop();
117
- this._audioSource = value;
118
- if (this._audioSource) {
119
- this.ready = true;
120
- this.updateStartActions();
121
- if (this.listener) {
122
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.READY));
123
- }
124
- }
125
- else {
126
- this.ready = false;
127
- this.updateStartActions();
128
- if (this.listener) {
129
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.CLOSED));
130
- }
131
- }
132
- }
133
- _loadSourceWorkletAndInitStart() {
134
- if (this.context) {
135
- AudioSourceWorkletModuleLoader.loadModule(this.context).then(() => {
136
- //console.debug("Player ready. ( by Player::_loadSourceWorkletAndInitStart()");
137
- this.ready = true;
138
- this.updateStartActions();
139
- if (this.listener) {
140
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.READY));
141
- }
142
- }).catch((error) => {
143
- this.ready = false;
144
- this.updateStartActions();
145
- if (this.listener) {
146
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.CLOSED));
147
- }
148
- console.error('Could not add module ' + error);
149
- });
150
- }
151
- }
152
- _startAudioSourceWorkletNode() {
153
- this._loadSourceWorkletAndInitStart();
154
- if (this.context && this.sourceAudioWorkletNode) {
155
- this.sourceAudioWorkletNode.onprocessorerror = (ev) => {
156
- let msg = 'Unknwon error';
157
- if (ev instanceof ErrorEvent) {
158
- msg = ev.message;
159
- }
160
- console.error("Audio source worklet error: " + msg);
161
- if (this.listener) {
162
- // TODO
163
- // this.listener.error(msg);
164
- // this.listener.audioPlayerUpdate(new AudioPlayerEvent());
165
- }
166
- };
167
- this.sourceAudioWorkletNode.connect(this.context.destination); // this already starts playing
168
- this.sourceAudioWorkletNode.onended = () => this.onended();
169
- this.running = true;
170
- this.sourceAudioWorkletNode.start();
171
- //console.debug("Playback start action enabled. ( by Player::_startAudioSourceWorkletNode()");
172
- this._startAction.disabled = true;
173
- this._startSelectionAction.disabled = true;
174
- this._stopAction.disabled = false;
175
- if (this.listener) {
176
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.STARTED));
177
- }
178
- }
179
- }
180
- start() {
181
- this._audioContext();
182
- if (this.context) {
183
- if (!this._startAction.disabled && !this.running) {
184
- if (this.context.state === 'suspended') {
185
- this.context.resume().then(() => {
186
- this._start();
187
- }).catch((reason) => {
188
- console.error(reason.message());
189
- throw reason;
190
- });
191
- }
192
- else if (this.context.state === 'closed') {
193
- const msg = 'Error: Cannot start playback. Audio context is already closed!';
194
- console.error(msg);
195
- throw new Error(msg);
196
- }
197
- else {
198
- this._start();
199
- }
200
- }
201
- }
202
- }
203
- updateStartActions() {
204
- if (this.ready) {
205
- if (this._audioSource instanceof AudioBufferSource || this._audioSource instanceof ArrayAudioBuffer || this._audioSource instanceof IndexedDbAudioBuffer) {
206
- this._startAction.disabled = false;
207
- this._startSelectionAction.disabled = this.startSelectionDisabled();
208
- }
209
- else {
210
- if (this._audioSource instanceof NetAudioBuffer) {
211
- this._audioSource.addOnReadyListener(() => {
212
- this._startAction.disabled = false;
213
- this._startSelectionAction.disabled = this.startSelectionDisabled();
214
- });
215
- }
216
- }
217
- }
218
- else {
219
- this._startAction.disabled = true;
220
- this._startSelectionAction.disabled = true;
221
- }
222
- }
223
- startSelectionDisabled() {
224
- return !(this._audioClip && !this.startAction.disabled && this._audioClip.selection);
225
- }
226
- _start(playSelection = false) {
227
- if (!this.context) {
228
- throw new Error("Could not get audio context!");
229
- }
230
- if (this._audioSource instanceof AudioBufferSource) {
231
- this.sourceBufferNode = this.context.createBufferSource();
232
- this.sourceBufferNode.buffer = this._audioSource.audioBuffer;
233
- this.sourceBufferNode.connect(this.context.destination);
234
- this.sourceBufferNode.onended = () => this.onended();
235
- this.playStartTime = this.context.currentTime;
236
- this.running = true;
237
- // unfortunately Web Audio API uses time values not frames
238
- const ac = this._audioClip;
239
- let offset = 0;
240
- if (playSelection && ac && ac.selection) {
241
- const s = ac.selection;
242
- const sr = ac.audioDataHolder.sampleRate;
243
- offset = s.leftFrame / sr;
244
- const stopPosInsecs = s.rightFrame / sr;
245
- const dur = stopPosInsecs - offset;
246
- this.sourceBufferNode.start(0, offset, dur);
247
- }
248
- else {
249
- this.sourceBufferNode.start();
250
- }
251
- this.playStartTime = this.context.currentTime - offset;
252
- this._startAction.disabled = true;
253
- this._startSelectionAction.disabled = true;
254
- this._stopAction.disabled = false;
255
- if (this.listener) {
256
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.STARTED));
257
- }
258
- }
259
- else if (this._audioSource instanceof ArrayAudioBuffer || this._audioSource instanceof IndexedDbAudioBuffer || this._audioSource instanceof NetAudioBuffer) {
260
- AudioSourceWorkletModuleLoader.loadModule(this.context).then(() => {
261
- this.playStartTime = null;
262
- if (this.context) {
263
- if (this._audioSource instanceof ArrayAudioBuffer) {
264
- const aabsn = new ArrayAudioBufferSourceNode(this.context);
265
- aabsn.arrayAudioBuffer = this._audioSource;
266
- this.sourceAudioWorkletNode = aabsn;
267
- }
268
- else if (this._audioSource instanceof IndexedDbAudioBuffer) {
269
- const iasn = new IndexedDbAudioBufferSourceNode(this.context);
270
- iasn.inddbAudioBuffer = this._audioSource;
271
- this.sourceAudioWorkletNode = iasn;
272
- }
273
- else if (this._audioSource instanceof NetAudioBuffer) {
274
- const nabsn = new NetAudioBufferSourceNode(this.context);
275
- nabsn.netAudioBuffer = this._audioSource;
276
- this.sourceAudioWorkletNode = nabsn;
277
- }
278
- if (this.sourceAudioWorkletNode) {
279
- this.sourceAudioWorkletNode.onprocessorerror = (ev) => {
280
- let msg = 'Unknwon error';
281
- if (ev instanceof ErrorEvent) {
282
- msg = ev.message;
283
- }
284
- console.error("Audio source worklet error: " + msg);
285
- if (this.listener) {
286
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.ERROR));
287
- }
288
- };
289
- this.sourceAudioWorkletNode.connect(this.context.destination); // this already starts playing
290
- this.sourceAudioWorkletNode.onended = () => this.onended();
291
- this.running = true;
292
- const ac = this._audioClip;
293
- let offset = 0;
294
- if (playSelection && ac && ac.selection) {
295
- const s = ac.selection;
296
- const sr = ac.audioDataHolder.sampleRate;
297
- offset = s.leftFrame / sr;
298
- const stopPosInsecs = s.rightFrame / sr;
299
- const dur = stopPosInsecs - offset;
300
- this.sourceAudioWorkletNode.start(0, offset, dur);
301
- }
302
- else {
303
- this.sourceAudioWorkletNode.start();
304
- }
305
- //this.playStartTime = this.context.currentTime - offset;
306
- this._startAction.disabled = true;
307
- this._startSelectionAction.disabled = true;
308
- this._stopAction.disabled = false;
309
- if (this.listener) {
310
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.STARTED));
311
- }
312
- }
313
- }
314
- }).catch((error) => {
315
- console.error(error.message);
316
- this.ready = false;
317
- this.updateStartActions();
318
- if (this.listener) {
319
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.CLOSED));
320
- }
321
- throw error;
322
- });
323
- }
324
- }
325
- startSelected() {
326
- this._audioContext();
327
- if (!this.context) {
328
- throw new Error("Could not get audio context!");
329
- }
330
- if (!this._startAction.disabled && !this.running) {
331
- if (this.context.state === 'suspended') {
332
- this.context.resume().then(() => {
333
- this._start(true);
334
- }).catch((reason) => {
335
- console.error(reason.message);
336
- throw reason;
337
- });
338
- }
339
- else if (this.context.state === 'closed') {
340
- const msg = 'Error: Cannot start playback of selection. Audio context is already closed!';
341
- console.error(msg);
342
- throw new Error(msg);
343
- }
344
- else {
345
- this._start(true);
346
- }
347
- }
348
- }
349
- stop() {
350
- if (this.running) {
351
- if (this.sourceBufferNode) {
352
- this.sourceBufferNode.stop();
353
- }
354
- if (this.sourceAudioWorkletNode) {
355
- this.sourceAudioWorkletNode.stop();
356
- }
357
- if (this.timerVar !== null) {
358
- window.clearInterval(this.timerVar);
359
- }
360
- this.running = false;
361
- if (this.listener) {
362
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.STOPPED));
363
- }
364
- }
365
- }
366
- onended() {
367
- if (this.timerVar != null) {
368
- window.clearInterval(this.timerVar);
369
- }
370
- this._startAction.disabled = !this._audioSource;
371
- this._startSelectionAction.disabled = this.startSelectionDisabled();
372
- this._stopAction.disabled = true;
373
- this.running = false;
374
- if (this.listener) {
375
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.ENDED));
376
- }
377
- }
378
- get playPositionTime() {
379
- let ppt = null;
380
- if (this.context && this.playStartTime !== null) {
381
- ppt = this.context.currentTime - this.playStartTime;
382
- }
383
- else if (this.sourceAudioWorkletNode) {
384
- ppt = this.sourceAudioWorkletNode.playPositionTime;
385
- }
386
- return ppt;
387
- }
388
- get playPositionFrames() {
389
- let ppFrs = null;
390
- if (this._audioSource) {
391
- let sr = this._audioSource.sampleRate;
392
- if (sr) {
393
- let ppTime = this.playPositionTime;
394
- if (ppTime !== null) {
395
- ppFrs = sr * ppTime;
396
- }
397
- }
398
- }
399
- return ppFrs;
400
- }
401
- }
402
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxheWVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvc3BlZWNocmVjb3JkZXJuZy9zcmMvbGliL2F1ZGlvL3BsYXliYWNrL3BsYXllci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFFNUMsT0FBTyxFQUFDLGdCQUFnQixFQUFDLE1BQU0sdUJBQXVCLENBQUM7QUFDdkQsT0FBTyxFQUFDLDBCQUEwQixFQUFDLE1BQU0sa0NBQWtDLENBQUM7QUFDNUUsT0FBTyxFQUFDLG9CQUFvQixFQUFDLE1BQU0sdUJBQXVCLENBQUM7QUFDM0QsT0FBTyxFQUFDLDhCQUE4QixFQUFDLE1BQU0sc0NBQXNDLENBQUM7QUFDcEYsT0FBTyxFQUFDLDhCQUE4QixFQUFDLE1BQU0sa0NBQWtDLENBQUM7QUFFaEYsT0FBTyxFQUFDLGNBQWMsRUFBQyxNQUFNLHFCQUFxQixDQUFDO0FBQ25ELE9BQU8sRUFBQyx3QkFBd0IsRUFBQyxNQUFNLGdDQUFnQyxDQUFDO0FBQ3hFLE9BQU8sRUFBQyxpQkFBaUIsRUFBYyxNQUFNLHNCQUFzQixDQUFDO0FBQ3BFLE9BQU8sRUFBQyxvQkFBb0IsRUFBQyxNQUFNLFlBQVksQ0FBQztBQUk1QyxNQUFNLENBQU4sSUFBYSxTQUFpRTtBQUE5RSxXQUFhLFNBQVM7SUFBRSw2Q0FBTSxDQUFBO0lBQUMsMkNBQUssQ0FBQTtJQUFDLCtDQUFPLENBQUE7SUFBQyxxREFBVSxDQUFBO0lBQUUsK0NBQU8sQ0FBQTtJQUFFLDJDQUFLLENBQUE7SUFBQywyQ0FBSyxDQUFBO0FBQUEsQ0FBQyxFQUFqRSxTQUFTLEtBQVQsU0FBUyxRQUF3RDtBQUU5RSxNQUFNLE9BQU8sZ0JBQWdCO0lBS3pCLFlBQVksSUFBYyxFQUFFLFlBQW9CO1FBQzVDLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDO1FBQ2xCLElBQUksQ0FBQyxh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QUFHLElBQUksRUFBRSxDQUFDO1lBQzNDLEdBQUcsR0FBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDO1FBQ3ZELENBQUM7YUFBSyxJQUFHLElBQUksQ0FBQyxzQkFBc0IsRUFBQyxDQUFDO1lBQ3BDLEdBQUcsR0FBQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsZ0JBQWdCLENBQUM7UUFDbkQsQ0FBQztRQUNELE9BQU8sR0FBRyxDQUFDO0lBQ2YsQ0FBQztJQUVILElBQUksa0JBQWtCO1FBQ3BCLElBQUksS0FBSyxHQUFhLElBQUksQ0FBQztRQUM1QixJQUFHLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUNyQixJQUFJLEVBQUUsR0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQztZQUNwQyxJQUFJLEVBQUUsRUFBRSxDQUFDO2dCQUNQLElBQUksTUFBTSxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDbkMsSUFBSSxNQUFNLEtBQUssSUFBSSxFQUFFLENBQUM7b0JBQ3BCLEtBQUssR0FBRyxFQUFFLEdBQUcsTUFBTSxDQUFDO2dCQUN0QixDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7UUFDQSxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBBY3Rpb24gfSBmcm9tICcuLi8uLi9hY3Rpb24vYWN0aW9uJ1xyXG5pbXBvcnQgeyBBdWRpb0NsaXAgfSBmcm9tICcuLi9wZXJzaXN0b3InXHJcbmltcG9ydCB7QXJyYXlBdWRpb0J1ZmZlcn0gZnJvbSBcIi4uL2FycmF5X2F1ZGlvX2J1ZmZlclwiO1xyXG5pbXBvcnQge0FycmF5QXVkaW9CdWZmZXJTb3VyY2VOb2RlfSBmcm9tIFwiLi9hcnJheV9hdWRpb19idWZmZXJfc291cmNlX25vZGVcIjtcclxuaW1wb3J0IHtJbmRleGVkRGJBdWRpb0J1ZmZlcn0gZnJvbSBcIi4uL2luZGRiX2F1ZGlvX2J1ZmZlclwiO1xyXG5pbXBvcnQge0F1ZGlvU291cmNlV29ya2xldE1vZHVsZUxvYWRlcn0gZnJvbSBcIi4vYXVkaW9fc291cmNlX3dvcmtsZXRfbW9kdWxlX2xvYWRlclwiO1xyXG5pbXBvcnQge0luZGV4ZWREYkF1ZGlvQnVmZmVyU291cmNlTm9kZX0gZnJvbSBcIi4vaW5kZGJfYXVkaW9fYnVmZmVyX3NvdXJjZV9ub2RlXCI7XHJcbmltcG9ydCB7QXVkaW9Tb3VyY2VOb2RlfSBmcm9tIFwiLi9hdWRpb19zb3VyY2Vfbm9kZVwiO1xyXG5pbXBvcnQge05ldEF1ZGlvQnVmZmVyfSBmcm9tIFwiLi4vbmV0X2F1ZGlvX2J1ZmZlclwiO1xyXG5pbXBvcnQge05ldEF1ZGlvQnVmZmVyU291cmNlTm9kZX0gZnJvbSBcIi4vbmV0X2F1ZGlvX2J1ZmZlcl9zb3VyY2Vfbm9kZVwiO1xyXG5pbXBvcnQge0F1ZGlvQnVmZmVyU291cmNlLCBBdWRpb1NvdXJjZX0gZnJvbSBcIi4uL2F1ZGlvX2RhdGFfaG9sZGVyXCI7XHJcbmltcG9ydCB7QXVkaW9Db250ZXh0UHJvdmlkZXJ9IGZyb20gXCIuLi9jb250ZXh0XCI7XHJcblxyXG5cclxuXHJcbiAgICBleHBvcnQgZW51bSAgRXZlbnRUeXBlIHtDTE9TRUQsUkVBRFksU1RBUlRFRCxQT1NfVVBEQVRFLCBTVE9QUEVELCBFTkRFRCxFUlJPUn1cclxuXHJcbiAgICBleHBvcnQgY2xhc3MgQXVkaW9QbGF5ZXJFdmVudHtcclxuXHJcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBfdHlwZTpFdmVudFR5cGU7XHJcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBfdGltZVBvc2l0aW9uOm51bWJlciB8IHVuZGVmaW5lZDtcclxuXHJcbiAgICAgICAgY29uc3RydWN0b3IodHlwZTpFdmVudFR5cGUsIHRpbWVQb3NpdGlvbj86bnVtYmVyKSB7XHJcbiAgICAgICAgICAgIHRoaXMuX3R5cGUgPSB0eXBlO1xyXG4gICAgICAgICAgICB0aGlzLl90aW1lUG9zaXRpb24gPSB0aW1lUG9zaXRpb247XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBnZXQgdHlwZSgpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3R5cGU7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBnZXQgdGltZVBvc2l0aW9uKCkge1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fdGltZVBvc2l0aW9uO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGV4cG9ydCBpbnRlcmZhY2UgQXVkaW9QbGF5ZXJMaXN0ZW5lciB7XHJcbiAgICAgICAgYXVkaW9QbGF5ZXJVcGRhdGUoZTpBdWRpb1BsYXllckV2ZW50KTp2b2lkO1xyXG4gICAgfVxyXG5cclxuICAgIGV4cG9ydCBjbGFzcyBBdWRpb1BsYXllciB7XHJcblxyXG4gICAgICAgIGdldCBhdXRvUGxheU9uU2VsZWN0VG9nZ2xlQWN0aW9uKCk6IEFjdGlvbjxib29sZWFuPiB7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9hdXRvUGxheU9uU2VsZWN0VG9nZ2xlQWN0aW9uO1xyXG4gICAgICAgIH1cclxuICAgICAgICBwdWJsaWMgc3RhdGljIERFRkFVTFRfQlVGU0laRTpudW1iZXIgPSA4MTkyO1xyXG4gICAgICAgIHByaXZhdGUgcnVubmluZz1mYWxzZTtcclxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IF9zdGFydEFjdGlvbjpBY3Rpb248dm9pZD47XHJcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBfc3RhcnRTZWxlY3Rpb25BY3Rpb246QWN0aW9uPHZvaWQ+O1xyXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgX2F1dG9QbGF5T25TZWxlY3RUb2dnbGVBY3Rpb246QWN0aW9uPGJvb2xlYW4+O1xyXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgX3N0b3BBY3Rpb246QWN0aW9uPHZvaWQ+O1xyXG4gICAgICAgIGJ1ZlNpemU6bnVtYmVyO1xyXG4gICAgICAgIGNvbnRleHQ6QXVkaW9Db250ZXh0fG51bGw9bnVsbDtcclxuICAgICAgICByZWFkeT1mYWxzZTtcclxuICAgICAgICBsaXN0ZW5lcjpBdWRpb1BsYXllckxpc3RlbmVyO1xyXG4gICAgICAgIF9hdWRpb0NsaXA6QXVkaW9DbGlwfG51bGw9bnVsbDtcclxuICAgICAgICBwcml2YXRlIF9hdWRpb1NvdXJjZTpBdWRpb1NvdXJjZXxudWxsPW51bGw7XHJcbiAgICAgICAgc291cmNlQnVmZmVyTm9kZTpBdWRpb0J1ZmZlclNvdXJjZU5vZGV8bnVsbD1udWxsO1xyXG4gICAgICAgIHNvdXJjZUF1ZGlvV29ya2xldE5vZGU6QXVkaW9Tb3VyY2VOb2RlfG51bGw9bnVsbDtcclxuXHJcbiAgICAgICAgYnVmZlBvczpudW1iZXI7XHJcbiAgICAgICAgcHJpdmF0ZSB6ZXJvQnVmQ250Om51bWJlcjtcclxuICAgICAgICBuOmFueTtcclxuICAgICAgICB6YjpGbG9hdDMyQXJyYXk7XHJcbiAgICAgICAgcHJpdmF0ZSBwbGF5U3RhcnRUaW1lOm51bWJlcnxudWxsPW51bGw7XHJcblxyXG4gICAgICAgIHByaXZhdGUgdGltZXJWYXI6bnVtYmVyfG51bGw9bnVsbDtcclxuXHJcbiAgICAgICAgY29uc3RydWN0b3IobGlzdGVuZXI6QXVkaW9QbGF5ZXJMaXN0ZW5lcikge1xyXG4gICAgICAgICAgICB0aGlzLmxpc3RlbmVyPWxpc3RlbmVyO1xyXG4gICAgICAgICAgICB0aGlzLmJ1ZlNpemUgPSBBdWRpb1BsYXllci5ERUZBVUxUX0JVRlNJWkU7XHJcbiAgICAgICAgICAgIHRoaXMubj1uYXZpZ2F0b3I7XHJcbiAgICAgICAgICAgIHRoaXMuYnVmZlBvcz0wO1xyXG4gICAgICAgICAgICB0aGlzLnplcm9CdWZDbnQ9MDtcclxuICAgICAgICAgICAgdGhpcy56YiA9IG5ldyBGbG9hdDMyQXJyYXkodGhpcy5idWZTaXplKTtcclxuICAgICAgICAgICAgdGhpcy5fc3RhcnRBY3Rpb24gPSBuZXcgQWN0aW9uKCdTdGFydCcpO1xyXG4gICAgICAgICAgICB0aGlzLl9zdGFydEFjdGlvbi5kaXNhYmxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgIHRoaXMuX3N0YXJ0QWN0aW9uLm9uQWN0aW9uID0gKCk9PnRoaXMuc3RhcnQoKTtcclxuICAgICAgICAgICAgdGhpcy5fc3RhcnRTZWxlY3Rpb25BY3Rpb249bmV3IEFjdGlvbignU3RhcnQgc2VsZWN0ZWQnKVxyXG4gICAgICAgICAgICB0aGlzLl9zdGFydFNlbGVjdGlvbkFjdGlvbi5kaXNhYmxlZD10cnVlXHJcbiAgICAgICAgICAgIHRoaXMuX3N0YXJ0U2VsZWN0aW9uQWN0aW9uLm9uQWN0aW9uID0gKCk9PnRoaXMuc3RhcnRTZWxlY3RlZCgpO1xyXG4gICAgICAgICAgICB0aGlzLl9hdXRvUGxheU9uU2VsZWN0VG9nZ2xlQWN0aW9uPW5ldyBBY3Rpb248Ym9vbGVhbj4oXCJBdXRvcGxheSBvbiBzZWxlY3RcIixmYWxzZSk7XHJcbiAgICAgICAgICAgIHRoaXMuX3N0b3BBY3Rpb24gPSBuZXcgQWN0aW9uKCdTdG9wJyk7XHJcbiAgICAgICAgICAgIHRoaXMuX3N0b3BBY3Rpb24uZGlzYWJsZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICB0aGlzLl9zdG9wQWN0aW9uLm9uQWN0aW9uID0gKCk9PnRoaXMuc3RvcCgpO1xyXG5cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHByaXZhdGUgX2F1ZGlvQ29udGV4dCgpOkF1ZGlvQ29udGV4dHxudWxse1xyXG4gICAgICAgICAgICBpZighdGhpcy5jb250ZXh0KXtcclxuICAgICAgICAgICAgICAgIHRoaXMuY29udGV4dD1BdWRpb0NvbnRleHRQcm92aWRlci5hdWRpb0NvbnRleHRJbnN0YW5jZSgpO1xyXG4gICAgICAgICAgICAgICAgaWYodGhpcy5jb250ZXh0KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb250ZXh0LmFkZEV2ZW50TGlzdGVuZXIoJ3N0YXRlY2hhbmdlJywgKGV2KSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZih0aGlzLmNvbnRleHQgJiYgdGhpcy5jb250ZXh0LnN0YXRlIT09J3J1bm5pbmcnKXtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnN0b3AoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY29udGV4dDtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGdldCBzdGFydEFjdGlvbigpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3N0YXJ0QWN0aW9uO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgZ2V0IHN0YXJ0U2VsZWN0aW9uQWN0aW9uKCl7XHJcbiAgICAgICAgICByZXR1cm4gdGhpcy5fc3RhcnRTZWxlY3Rpb25BY3Rpb25cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGdldCBzdG9wQWN0aW9uKCkge1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fc3RvcEFjdGlvbjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHNldCBhdWRpb0NsaXAoYXVkaW9DbGlwOkF1ZGlvQ2xpcHwgbnVsbCkge1xyXG4gICAgICAgICAgdGhpcy5fYXVkaW9DbGlwPWF1ZGlvQ2xpcFxyXG4gICAgICAgICAgICBsZXQgbGVuZ3RoID0gMDtcclxuICAgICAgICAgICAgbGV0IGNocyA9IDA7XHJcbiAgICAgICAgICAgIGlmIChhdWRpb0NsaXAgJiYgYXVkaW9DbGlwLmF1ZGlvRGF0YUhvbGRlcikge1xyXG4gICAgICAgICAgICAgICAgbGV0IGF1ZGlvRGF0YUhvbGRlcj1hdWRpb0NsaXAuYXVkaW9EYXRhSG9sZGVyO1xyXG4gICAgICAgICAgICAgICAgY2hzID0gYXVkaW9EYXRhSG9sZGVyLm51bWJlck9mQ2hhbm5lbHNcclxuICAgICAgICAgICAgICAgIGlmIChjaHMgPiAwKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgbGVuZ3RoID0gYXVkaW9EYXRhSG9sZGVyLmZyYW1lTGVuO1xyXG4gICAgICAgICAgICAgICAgICAgIC8vaWYgKGNocyA+IHRoaXMuY29udGV4dC5kZXN0aW5hdGlvbi5tYXhDaGFubmVsQ291bnQpIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyAgICAvLyBUT0RPIGV4Y2VwdGlvblxyXG4gICAgICAgICAgICAgICAgICAgIC8vfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgdGhpcy5hdWRpb1NvdXJjZT1hdWRpb0RhdGFIb2xkZXIuYXVkaW9Tb3VyY2U7XHJcblxyXG4gICAgICAgICAgICAgICAgYXVkaW9DbGlwLmFkZFNlbGVjdGlvbk9ic2VydmVyKChhYyk9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fc3RhcnRTZWxlY3Rpb25BY3Rpb24uZGlzYWJsZWQgPSB0aGlzLnN0YXJ0U2VsZWN0aW9uRGlzYWJsZWQoKTtcclxuICAgICAgICAgICAgICAgICAgICBpZiAoIXRoaXMuc3RhcnRTZWxlY3Rpb25BY3Rpb24uZGlzYWJsZWQgJiYgdGhpcy5fYXV0b1BsYXlPblNlbGVjdFRvZ2dsZUFjdGlvbi52YWx1ZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgdGhpcy5zdGFydFNlbGVjdGVkKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgIH1lbHNle1xyXG4gICAgICAgICAgICAgICAgdGhpcy5hdWRpb1NvdXJjZT1udWxsO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgZ2V0IGF1ZGlvU291cmNlKCk6IEF1ZGlvU291cmNlIHwgbnVsbCB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX2F1ZGlvU291cmNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBzZXQgYXVkaW9Tb3VyY2UodmFsdWU6IEF1ZGlvU291cmNlIHwgbnVsbCkge1xyXG4gICAgICAgIHRoaXMuc3RvcCgpO1xyXG4gICAgICAgIHRoaXMuX2F1ZGlvU291cmNlID0gdmFsdWU7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLl9hdWRpb1NvdXJjZSkge1xyXG5cclxuICAgICAgICAgICAgICAgIHRoaXMucmVhZHkgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgdGhpcy51cGRhdGVTdGFydEFjdGlvbnMoKTtcclxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmxpc3RlbmVyKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5saXN0ZW5lci5hdWRpb1BsYXllclVwZGF0ZShuZXcgQXVkaW9QbGF5ZXJFdmVudChFdmVudFR5cGUuUkVBRFkpKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfWVsc2Uge1xyXG4gICAgICAgICAgICAgIHRoaXMucmVhZHkgPSBmYWxzZTtcclxuICAgICAgICAgICAgICB0aGlzLnVwZGF0ZVN0YXJ0QWN0aW9ucygpO1xyXG4gICAgICAgICAgICAgIGlmICh0aGlzLmxpc3RlbmVyKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmxpc3RlbmVyLmF1ZGlvUGxheWVyVXBkYXRlKG5ldyBBdWRpb1BsYXllckV2ZW50KEV2ZW50VHlwZS5DTE9TRUQpKTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgICBwcml2YXRlIF9sb2FkU291cmNlV29ya2xldEFuZEluaXRTdGFydCgpe1xyXG4gICAgICAgICAgICBpZih0aGlzLmNvbnRleHQpIHtcclxuICAgICAgICAgICAgICAgIEF1ZGlvU291cmNlV29ya2xldE1vZHVsZUxvYWRlci5sb2FkTW9kdWxlKHRoaXMuY29udGV4dCkudGhlbigoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiUGxheWVyIHJlYWR5LiAoIGJ5IFBsYXllcjo6X2xvYWRTb3VyY2VXb3JrbGV0QW5kSW5pdFN0YXJ0KClcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZWFkeSA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy51cGRhdGVTdGFydEFjdGlvbnMoKTtcclxuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5saXN0ZW5lcikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxpc3RlbmVyLmF1ZGlvUGxheWVyVXBkYXRlKG5ldyBBdWRpb1BsYXllckV2ZW50KEV2ZW50VHlwZS5SRUFEWSkpO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0pLmNhdGNoKChlcnJvcjogYW55KSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZWFkeSA9IGZhbHNlO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlU3RhcnRBY3Rpb25zKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMubGlzdGVuZXIpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5saXN0ZW5lci5hdWRpb1BsYXllclVwZGF0ZShuZXcgQXVkaW9QbGF5ZXJFdmVudChFdmVudFR5cGUuQ0xPU0VEKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ0NvdWxkIG5vdCBhZGQgbW9kdWxlICcgKyBlcnJvcik7XHJcbiAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcblxyXG4gIHByaXZhdGUgX3N0YXJ0QXVkaW9Tb3VyY2VXb3JrbGV0Tm9kZSgpe1xyXG4gICAgICB0aGlzLl9sb2FkU291cmNlV29ya2xldEFuZEluaXRTdGFydCgpO1xyXG4gICAgICAgICAgaWYodGhpcy5jb250ZXh0ICYmIHRoaXMuc291cmNlQXVkaW9Xb3JrbGV0Tm9kZSkge1xyXG4gICAgICAgICAgICB0aGlzLnNvdXJjZUF1ZGlvV29ya2xldE5vZGUub25wcm9jZXNzb3JlcnJvciA9IChldjogRXZlbnQpID0+IHtcclxuICAgICAgICAgICAgICBsZXQgbXNnID0gJ1Vua253b24gZXJyb3InO1xyXG4gICAgICAgICAgICAgIGlmIChldiBpbnN0YW5jZW9mIEVycm9yRXZlbnQpIHtcclxuICAgICAgICAgICAgICAgIG1zZyA9IGV2Lm1lc3NhZ2U7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJBdWRpbyBzb3VyY2Ugd29ya2xldCBlcnJvcjogXCIgKyBtc2cpO1xyXG4gICAgICAgICAgICAgIGlmICh0aGlzLmxpc3RlbmVyKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBUT0RPXHJcbiAgICAgICAgICAgICAgICAvLyB0aGlzLmxpc3RlbmVyLmVycm9yKG1zZyk7XHJcbiAgICAgICAgICAgICAgICAvLyB0aGlzLmxpc3RlbmVyLmF1ZGlvUGxheWVyVXBkYXRlKG5ldyBBdWRpb1BsYXllckV2ZW50KCkpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgIHRoaXMuc291cmNlQXVkaW9Xb3JrbGV0Tm9kZS5jb25uZWN0KHRoaXMuY29udGV4dC5kZXN0aW5hdGlvbik7IC8vIHRoaXMgYWxyZWFkeSBzdGFydHMgcGxheWluZ1xyXG4gICAgICAgICAgICB0aGlzLnNvdXJjZUF1ZGlvV29ya2xldE5vZGUub25lbmRlZCA9ICgpID0+IHRoaXMub25lbmRlZCgpO1xyXG4gICAgICAgICAgICB0aGlzLnJ1bm5pbmcgPSB0cnVlO1xyXG4gICAgICAgICAgICB0aGlzLnNvdXJjZUF1ZGlvV29ya2xldE5vZGUuc3RhcnQoKTtcclxuICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiUGxheWJhY2sgc3RhcnQgYWN0aW9uIGVuYWJsZWQuICggYnkgUGxheWVyOjpfc3RhcnRBdWRpb1NvdXJjZVdvcmtsZXROb2RlKClcIik7XHJcbiAgICAgICAgICAgIHRoaXMuX3N0YXJ0QWN0aW9uLmRpc2FibGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgdGhpcy5fc3RhcnRTZWxlY3Rpb25BY3Rpb24uZGlzYWJsZWQgPSB0cnVlXHJcbiAgICAgICAgICAgIHRoaXMuX3N0b3BBY3Rpb24uZGlzYWJsZWQgPSBmYWxzZTtcclxuXHJcbiAgICAgICAgICAgIGlmICh0aGlzLmxpc3RlbmVyKSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5saXN0ZW5lci5hdWRpb1BsYXllclVwZGF0ZShuZXcgQXVkaW9QbGF5ZXJFdmVudChFdmVudFR5cGUuU1RBUlRFRCkpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcblxyXG4gIH1cclxuXHJcbiAgICAgICAgc3RhcnQoKSB7XHJcblxyXG4gICAgICAgICAgICB0aGlzLl9hdWRpb0NvbnRleHQoKTtcclxuXHJcbiAgICAgICAgICAgIGlmKHRoaXMuY29udGV4dCkge1xyXG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLl9zdGFydEFjdGlvbi5kaXNhYmxlZCAmJiAhdGhpcy5ydW5uaW5nKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuY29udGV4dC5zdGF0ZSA9PT0gJ3N1c3BlbmRlZCcpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jb250ZXh0LnJlc3VtZSgpLnRoZW4oKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fc3RhcnQoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfSkuY2F0Y2goKHJlYXNvbikgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihyZWFzb24ubWVzc2FnZSgpKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IHJlYXNvbjtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuY29udGV4dC5zdGF0ZSA9PT0gJ2Nsb3NlZCcpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgbXNnID0gJ0Vycm9yOiBDYW5ub3Qgc3RhcnQgcGxheWJhY2suIEF1ZGlvIGNvbnRleHQgaXMgYWxyZWFkeSBjbG9zZWQhJztcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihtc2cpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IobXNnKTtcclxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLl9zdGFydCgpO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdXBkYXRlU3RhcnRBY3Rpb25zKCl7XHJcblxyXG4gICAgICAgICAgaWYodGhpcy5yZWFkeSl7XHJcbiAgICAgICAgICAgIGlmKHRoaXMuX2F1ZGlvU291cmNlIGluc3RhbmNlb2YgQXVkaW9CdWZmZXJTb3VyY2UgfHwgdGhpcy5fYXVkaW9Tb3VyY2UgaW5zdGFuY2VvZiBBcnJheUF1ZGlvQnVmZmVyIHx8IHRoaXMuX2F1ZGlvU291cmNlIGluc3RhbmNlb2YgSW5kZXhlZERiQXVkaW9CdWZmZXIpe1xyXG4gICAgICAgICAgICAgIHRoaXMuX3N0YXJ0QWN0aW9uLmRpc2FibGVkPWZhbHNlO1xyXG4gICAgICAgICAgICAgIHRoaXMuX3N0YXJ0U2VsZWN0aW9uQWN0aW9uLmRpc2FibGVkPXRoaXMuc3RhcnRTZWxlY3Rpb25EaXNhYmxlZCgpO1xyXG4gICAgICAgICAgICB9ZWxzZXtcclxuICAgICAgICAgICAgICBpZih0aGlzLl9hdWRpb1NvdXJjZSBpbnN0YW5jZW9mIE5ldEF1ZGlvQnVmZmVyKXtcclxuICAgICAgICAgICAgICAgIHRoaXMuX2F1ZGlvU291cmNlLmFkZE9uUmVhZHlMaXN0ZW5lcigoKT0+e1xyXG4gICAgICAgICAgICAgICAgICB0aGlzLl9zdGFydEFjdGlvbi5kaXNhYmxlZD1mYWxzZTtcclxuICAgICAgICAgICAgICAgICAgdGhpcy5fc3RhcnRTZWxlY3Rpb25BY3Rpb24uZGlzYWJsZWQ9dGhpcy5zdGFydFNlbGVjdGlvbkRpc2FibGVkKCk7XHJcbiAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1lbHNle1xyXG4gICAgICAgICAgICB0aGlzLl9zdGFydEFjdGlvbi5kaXNhYmxlZD10cnVlO1xyXG4gICAgICAgICAgICB0aGlzLl9zdGFydFNlbGVjdGlvbkFjdGlvbi5kaXNhYmxlZD10cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgc3RhcnRTZWxlY3Rpb25EaXNhYmxlZCgpe1xyXG4gICAgICAgICAgcmV0dXJuICEodGhpcy5fYXVkaW9DbGlwICYmICF0aGlzLnN0YXJ0QWN0aW9uLmRpc2FibGVkICYmIHRoaXMuX2F1ZGlvQ2xpcC5zZWxlY3Rpb24gKVxyXG4gICAgICAgIH1cclxuXHJcblxyXG4gICAgICAgIHByaXZhdGUgX3N0YXJ0KHBsYXlTZWxlY3Rpb249ZmFsc2Upe1xyXG4gICAgICAgICAgICAgICAgaWYoIXRoaXMuY29udGV4dCl7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ291bGQgbm90IGdldCBhdWRpbyBjb250ZXh0IVwiKTtcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICBpZiAodGhpcy5fYXVkaW9Tb3VyY2UgaW5zdGFuY2VvZiBBdWRpb0J1ZmZlclNvdXJjZSkge1xyXG4gICAgICAgICAgICB0aGlzLnNvdXJjZUJ1ZmZlck5vZGUgPSB0aGlzLmNvbnRleHQuY3JlYXRlQnVmZmVyU291cmNlKCk7XHJcbiAgICAgICAgICAgIHRoaXMuc291cmNlQnVmZmVyTm9kZS5idWZmZXIgPSB0aGlzLl9hdWRpb1NvdXJjZS5hdWRpb0J1ZmZlcjtcclxuICAgICAgICAgICAgdGhpcy5zb3VyY2VCdWZmZXJOb2RlLmNvbm5lY3QodGhpcy5jb250ZXh0LmRlc3RpbmF0aW9uKTtcclxuICAgICAgICAgICAgdGhpcy5zb3VyY2VCdWZmZXJOb2RlLm9uZW5kZWQgPSAoKSA9PiB0aGlzLm9uZW5kZWQoKTtcclxuICAgICAgICAgICAgdGhpcy5wbGF5U3RhcnRUaW1lID0gdGhpcy5jb250ZXh0LmN1cnJlbnRUaW1lO1xyXG4gICAgICAgICAgICB0aGlzLnJ1bm5pbmcgPSB0cnVlO1xyXG4gICAgICAgICAgICAvLyB1bmZvcnR1bmF0ZWx5IFdlYiBBdWRpbyBBUEkgdXNlcyB0aW1lIHZhbHVlcyBub3QgZnJhbWVzXHJcbiAgICAgICAgICAgIGNvbnN0IGFjID0gdGhpcy5fYXVkaW9DbGlwXHJcbiAgICAgICAgICAgIGxldCBvZmZzZXQgPSAwO1xyXG4gICAgICAgICAgICBpZiAocGxheVNlbGVjdGlvbiAmJiBhYyAmJiBhYy5zZWxlY3Rpb24pIHtcclxuXHJcbiAgICAgICAgICAgICAgY29uc3QgcyA9IGFjLnNlbGVjdGlvbjtcclxuICAgICAgICAgICAgICBjb25zdCBzciA9IGFjLmF1ZGlvRGF0YUhvbGRlci5zYW1wbGVSYXRlO1xyXG4gICAgICAgICAgICAgIG9mZnNldCA9IHMubGVmdEZyYW1lIC8gc3I7XHJcbiAgICAgICAgICAgICAgY29uc3Qgc3RvcFBvc0luc2VjcyA9IHMucmlnaHRGcmFtZSAvIHNyO1xyXG4gICAgICAgICAgICAgIGNvbnN0IGR1ciA9IHN0b3BQb3NJbnNlY3MgLSBvZmZzZXQ7XHJcbiAgICAgICAgICAgICAgdGhpcy5zb3VyY2VCdWZmZXJOb2RlLnN0YXJ0KDAsIG9mZnNldCwgZHVyKVxyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIHRoaXMuc291cmNlQnVmZmVyTm9kZS5zdGFydCgpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIHRoaXMucGxheVN0YXJ0VGltZSA9IHRoaXMuY29udGV4dC5jdXJyZW50VGltZSAtIG9mZnNldDtcclxuICAgICAgICAgICAgdGhpcy5fc3RhcnRBY3Rpb24uZGlzYWJsZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICB0aGlzLl9zdGFydFNlbGVjdGlvbkFjdGlvbi5kaXNhYmxlZCA9IHRydWVcclxuICAgICAgICAgICAgdGhpcy5fc3RvcEFjdGlvbi5kaXNhYmxlZCA9IGZhbHNlO1xyXG5cclxuICAgICAgICAgICAgaWYgKHRoaXMubGlzdGVuZXIpIHtcclxuICAgICAgICAgICAgICB0aGlzLmxpc3RlbmVyLmF1ZGlvUGxheWVyVXBkYXRlKG5ldyBBdWRpb1BsYXllckV2ZW50KEV2ZW50VHlwZS5TVEFSVEVEKSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5fYXVkaW9Tb3VyY2UgaW5zdGFuY2VvZiBBcnJheUF1ZGlvQnVmZmVyIHx8IHRoaXMuX2F1ZGlvU291cmNlIGluc3RhbmNlb2YgSW5kZXhlZERiQXVkaW9CdWZmZXIgfHwgdGhpcy5fYXVkaW9Tb3VyY2UgaW5zdGFuY2VvZiBOZXRBdWRpb0J1ZmZlcikge1xyXG4gICAgICAgICAgICAgIEF1ZGlvU291cmNlV29ya2xldE1vZHVsZUxvYWRlci5sb2FkTW9kdWxlKHRoaXMuY29udGV4dCkudGhlbigoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgIHRoaXMucGxheVN0YXJ0VGltZSA9IG51bGw7XHJcbiAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmNvbnRleHQpIHtcclxuICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuX2F1ZGlvU291cmNlIGluc3RhbmNlb2YgQXJyYXlBdWRpb0J1ZmZlcikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgY29uc3QgYWFic24gPSBuZXcgQXJyYXlBdWRpb0J1ZmZlclNvdXJjZU5vZGUodGhpcy5jb250ZXh0KTtcclxuICAgICAgICAgICAgICAgICAgICAgIGFhYnNuLmFycmF5QXVkaW9CdWZmZXIgPSB0aGlzLl9hdWRpb1NvdXJjZTtcclxuICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc291cmNlQXVkaW9Xb3JrbGV0Tm9kZSA9IGFhYnNuO1xyXG4gICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuX2F1ZGlvU291cmNlIGluc3RhbmNlb2YgSW5kZXhlZERiQXVkaW9CdWZmZXIpIHtcclxuICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGlhc24gPSBuZXcgSW5kZXhlZERiQXVkaW9CdWZmZXJTb3VyY2VOb2RlKHRoaXMuY29udGV4dCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICBpYXNuLmluZGRiQXVkaW9CdWZmZXIgPSB0aGlzLl9hdWRpb1NvdXJjZTtcclxuICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc291cmNlQXVkaW9Xb3JrbGV0Tm9kZSA9IGlhc247XHJcbiAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5fYXVkaW9Tb3VyY2UgaW5zdGFuY2VvZiBOZXRBdWRpb0J1ZmZlcikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgY29uc3QgbmFic24gPSBuZXcgTmV0QXVkaW9CdWZmZXJTb3VyY2VOb2RlKHRoaXMuY29udGV4dCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICBuYWJzbi5uZXRBdWRpb0J1ZmZlciA9IHRoaXMuX2F1ZGlvU291cmNlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgdGhpcy5zb3VyY2VBdWRpb1dvcmtsZXROb2RlID0gbmFic247XHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuc291cmNlQXVkaW9Xb3JrbGV0Tm9kZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgdGhpcy5zb3VyY2VBdWRpb1dvcmtsZXROb2RlLm9ucHJvY2Vzc29yZXJyb3IgPSAoZXY6IEV2ZW50KSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IG1zZyA9ICdVbmtud29uIGVycm9yJztcclxuICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZXYgaW5zdGFuY2VvZiBFcnJvckV2ZW50KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1zZyA9IGV2Lm1lc3NhZ2U7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJBdWRpbyBzb3VyY2Ugd29ya2xldCBlcnJvcjogXCIgKyBtc2cpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmxpc3RlbmVyKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubGlzdGVuZXIuYXVkaW9QbGF5ZXJVcGRhdGUobmV3IEF1ZGlvUGxheWVyRXZlbnQoRXZlbnRUeXBlLkVSUk9SKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICB0aGlzLnNvdXJjZUF1ZGlvV29ya2xldE5vZGUuY29ubmVjdCh0aGlzLmNvbnRleHQuZGVzdGluYXRpb24pOyAvLyB0aGlzIGFscmVhZHkgc3RhcnRzIHBsYXlpbmdcclxuICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc291cmNlQXVkaW9Xb3JrbGV0Tm9kZS5vbmVuZGVkID0gKCkgPT4gdGhpcy5vbmVuZGVkKCk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgdGhpcy5ydW5uaW5nID0gdHJ1ZTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICBjb25zdCBhYyA9IHRoaXMuX2F1ZGlvQ2xpcFxyXG4gICAgICAgICAgICAgICAgICAgICAgbGV0IG9mZnNldCA9IDBcclxuICAgICAgICAgICAgICAgICAgICAgIGlmIChwbGF5U2VsZWN0aW9uICYmIGFjICYmIGFjLnNlbGVjdGlvbikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHMgPSBhYy5zZWxlY3Rpb247XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3IgPSBhYy5hdWRpb0RhdGFIb2xkZXIuc2FtcGxlUmF0ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICBvZmZzZXQgPSBzLmxlZnRGcmFtZSAvIHNyO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHN0b3BQb3NJbnNlY3MgPSBzLnJpZ2h0RnJhbWUgLyBzcjtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBkdXIgPSBzdG9wUG9zSW5zZWNzIC0gb2Zmc2V0XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zb3VyY2VBdWRpb1dvcmtsZXROb2RlLnN0YXJ0KDAsIG9mZnNldCwgZHVyKVxyXG4gICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnNvdXJjZUF1ZGlvV29ya2xldE5vZGUuc3RhcnQoKTtcclxuICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAvL3RoaXMucGxheVN0YXJ0VGltZSA9IHRoaXMuY29udGV4dC5jdXJyZW50VGltZSAtIG9mZnNldDtcclxuICAgICAgICAgICAgICAgICAgICAgIHRoaXMuX3N0YXJ0QWN0aW9uLmRpc2FibGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgIHRoaXMuX3N0YXJ0U2VsZWN0aW9uQWN0aW9uLmRpc2FibGVkID0gdHJ1ZVxyXG4gICAgICAgICAgICAgICAgICAgICAgdGhpcy5fc3RvcEFjdGlvbi5kaXNhYmxlZCA9IGZhbHNlO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmxpc3RlbmVyKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5saXN0ZW5lci5hdWRpb1BsYXllclVwZGF0ZShuZXcgQXVkaW9QbGF5ZXJFdmVudChFdmVudFR5cGUuU1RBUlRFRCkpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIH0pLmNhdGNoKChlcnJvcjogYW55KSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IubWVzc2FnZSk7XHJcbiAgICAgICAgICAgICAgICAgIHRoaXMucmVhZHkgPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgICAgdGhpcy51cGRhdGVTdGFydEFjdGlvbnMoKTtcclxuICAgICAgICAgICAgICAgICAgaWYgKHRoaXMubGlzdGVuZXIpIHtcclxuICAgICAgICAgICAgICAgICAgICAgIHRoaXMubGlzdGVuZXIuYXVkaW9QbGF5ZXJVcGRhdGUobmV3IEF1ZGlvUGxheWVyRXZlbnQoRXZlbnRUeXBlLkNMT1NFRCkpO1xyXG4gICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgc3RhcnRTZWxlY3RlZCgpIHtcclxuICAgICAgICAgICAgdGhpcy5fYXVkaW9Db250ZXh0KCk7XHJcbiAgICAgICAgICBpZighdGhpcy5jb250ZXh0KXtcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb3VsZCBub3QgZ2V0IGF1ZGlvIGNvbnRleHQhXCIpO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIGlmKCF0aGlzLl9zdGFydEFjdGlvbi5kaXNhYmxlZCAmJiAhdGhpcy5ydW5uaW5nKSB7XHJcbiAgICAgICAgICBpZiAodGhpcy5jb250ZXh0LnN0YXRlID09PSAnc3VzcGVuZGVkJykge1xyXG4gICAgICAgICAgICB0aGlzLmNvbnRleHQucmVzdW1lKCkudGhlbigoKSA9PiB7XHJcbiAgICAgICAgICAgICAgdGhpcy5fc3RhcnQodHJ1ZSk7XHJcbiAgICAgICAgICAgIH0pLmNhdGNoKChyZWFzb24pID0+IHtcclxuICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKHJlYXNvbi5tZXNzYWdlKTtcclxuICAgICAgICAgICAgICB0aHJvdyByZWFzb247XHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICB9ZWxzZSBpZih0aGlzLmNvbnRleHQuc3RhdGU9PT0nY2xvc2VkJyl7XHJcbiAgICAgICAgICAgIGNvbnN0IG1zZz0nRXJyb3I6IENhbm5vdCBzdGFydCBwbGF5YmFjayBvZiBzZWxlY3Rpb24uIEF1ZGlvIGNvbnRleHQgaXMgYWxyZWFkeSBjbG9zZWQhJztcclxuICAgICAgICAgICAgY29uc29sZS5lcnJvcihtc2cpO1xyXG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IobXNnKTtcclxuICAgICAgICAgIH1lbHNle1xyXG4gICAgICAgICAgICB0aGlzLl9zdGFydCh0cnVlKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICAgc3RvcCgpe1xyXG4gICAgICAgICAgICBpZih0aGlzLnJ1bm5pbmcpIHtcclxuICAgICAgICAgICAgICAgIGlmICh0aGlzLnNvdXJjZUJ1ZmZlck5vZGUpIHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnNvdXJjZUJ1ZmZlck5vZGUuc3RvcCgpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgaWYodGhpcy5zb3VyY2VBdWRpb1dvcmtsZXROb2RlKXtcclxuICAgICAgICAgICAgICAgICAgdGhpcy5zb3VyY2VBdWRpb1dvcmtsZXROb2RlLnN0b3AoKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgaWYgKHRoaXMudGltZXJWYXIgIT09IG51bGwpIHtcclxuICAgICAgICAgICAgICAgICAgICB3aW5kb3cuY2xlYXJJbnRlcnZhbCh0aGlzLnRpbWVyVmFyKTtcclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICB0aGlzLnJ1bm5pbmcgPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgICAgaWYgKHRoaXMubGlzdGVuZXIpIHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLmxpc3RlbmVyLmF1ZGlvUGxheWVyVXBkYXRlKG5ldyBBdWRpb1BsYXllckV2ZW50KEV2ZW50VHlwZS5TVE9QUEVEKSk7XHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIG9uZW5kZWQoKSB7XHJcbiAgICAgICAgICAgIGlmKHRoaXMudGltZXJWYXIhPW51bGwpIHtcclxuICAgICAgICAgICAgICAgIHdpbmRvdy5jbGVhckludGVydmFsKHRoaXMudGltZXJWYXIpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIHRoaXMuX3N0YXJ0QWN0aW9uLmRpc2FibGVkID0gIXRoaXMuX2F1ZGlvU291cmNlO1xyXG4gICAgICAgICAgICB0aGlzLl9zdGFydFNlbGVjdGlvbkFjdGlvbi5kaXNhYmxlZD10aGlzLnN0YXJ0U2VsZWN0aW9uRGlzYWJsZWQoKVxyXG4gICAgICAgICAgICB0aGlzLl9zdG9wQWN0aW9uLmRpc2FibGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgdGhpcy5ydW5uaW5nPWZhbHNlO1xyXG4gICAgICAgICAgICBpZiAodGhpcy5saXN0ZW5lcikge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5saXN0ZW5lci5hdWRpb1BsYXllclVwZGF0ZShuZXcgQXVkaW9QbGF5ZXJFdmVudChFdmVudFR5cGUuRU5ERUQpKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgZ2V0IHBsYXlQb3NpdGlvblRpbWUoKTpudW1iZXJ8bnVsbCB7XHJcbiAgICAgICAgICAgIGxldCBwcHQ9bnVsbDtcclxuICAgICAgICAgICAgaWYodGhpcy5jb250ZXh0ICYmIHRoaXMucGxheVN0YXJ0VGltZSE9PW51bGwpIHtcclxuICAgICAgICAgICAgICAgIHBwdD0gdGhpcy5jb250ZXh0LmN1cnJlbnRUaW1lIC0gdGhpcy5wbGF5U3RhcnRUaW1lO1xyXG4gICAgICAgICAgICB9ZWxzZSBpZih0aGlzLnNvdXJjZUF1ZGlvV29ya2xldE5vZGUpe1xyXG4gICAgICAgICAgICAgIHBwdD10aGlzLnNvdXJjZUF1ZGlvV29ya2xldE5vZGUucGxheVBvc2l0aW9uVGltZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICByZXR1cm4gcHB0O1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgIGdldCBwbGF5UG9zaXRpb25GcmFtZXMoKTpudW1iZXJ8bnVsbCB7XHJcbiAgICAgICAgbGV0IHBwRnJzOm51bWJlcnxudWxsPW51bGw7XHJcbiAgICAgICBpZih0aGlzLl9hdWRpb1NvdXJjZSkge1xyXG4gICAgICAgICBsZXQgc3I9dGhpcy5fYXVkaW9Tb3VyY2Uuc2FtcGxlUmF0ZTtcclxuICAgICAgICAgaWYgKHNyKSB7XHJcbiAgICAgICAgICAgbGV0IHBwVGltZSA9IHRoaXMucGxheVBvc2l0aW9uVGltZTtcclxuICAgICAgICAgICBpZiAocHBUaW1lICE9PSBudWxsKSB7XHJcbiAgICAgICAgICAgICBwcEZycyA9IHNyICogcHBUaW1lO1xyXG4gICAgICAgICAgIH1cclxuICAgICAgICAgfVxyXG4gICAgICAgfVxyXG4gICAgICAgIHJldHVybiBwcEZycztcclxuICAgICAgfVxyXG5cclxuICAgIH1cclxuXHJcbiJdfQ==