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