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
@@ -0,0 +1,668 @@
1
+ var BasicRecorder_1;
2
+ import { __decorate, __param } from "tslib";
3
+ import { TransportActions } from "./controlpanel";
4
+ import { Browser, UserAgentBuilder } from "../../utils/ua-parser";
5
+ import { MessageDialog } from "../../ui/message_dialog";
6
+ import { SessionService } from "./session.service";
7
+ import { AudioStorageType } from "../project/project";
8
+ import { LevelMeasure, StreamLevelMeasure } from "../../audio/dsp/level_measure";
9
+ import { Action } from "../../action/action";
10
+ import { MIN_DB_LEVEL } from "../../ui/recordingitem_display";
11
+ import { Upload, UploadSet } from "../../net/uploader";
12
+ import { Inject } from "@angular/core";
13
+ import { SPEECHRECORDER_CONFIG } from "../../spr.config";
14
+ import { SequenceAudioFloat32ChunkerOutStream, SequenceAudioFloat32OutStreamMultiplier } from "../../audio/io/stream";
15
+ import { AudioContextProvider } from "../../audio/context";
16
+ import { UUID } from "../../utils/utils";
17
+ import { WakeLockManager } from "../../utils/wake_lock";
18
+ import { State as LiveLevelState } from "../../audio/ui/livelevel";
19
+ import { ResponsiveComponent } from "../../ui/responsive_component";
20
+ export const FORCE_REQUEST_AUDIO_PERMISSIONS = false;
21
+ export const RECFILE_API_CTX = 'recfile';
22
+ export const MAX_RECORDING_TIME_MS = 1000 * 60 * 60 * 60; // 1 hour
23
+ export const LEVEL_BAR_INTERVALL_SECONDS = 0.1; // 100ms
24
+ export const NOSLEEP_VIDEO_TITLE = 'No Sleep';
25
+ export class ChunkManager {
26
+ set recordingFile(value) {
27
+ this._rf = value;
28
+ }
29
+ constructor(chunkAudioBufferReceiver) {
30
+ this.chunkAudioBufferReceiver = chunkAudioBufferReceiver;
31
+ this.channels = 0;
32
+ this.sampleRate = -1;
33
+ this.chunkIdx = 0;
34
+ }
35
+ close() {
36
+ // Nothing to do
37
+ }
38
+ flush() {
39
+ this.chunkAudioBufferReceiver.postAudioStreamEnd(this.chunkIdx);
40
+ }
41
+ nextStream() {
42
+ // reset chunk counter
43
+ this.chunkIdx = 0;
44
+ this.chunkAudioBufferReceiver.postAudioStreamStart();
45
+ }
46
+ setFormat(channels, sampleRate) {
47
+ this.channels = channels;
48
+ this.sampleRate = sampleRate;
49
+ }
50
+ write(buffers) {
51
+ let aCtx = AudioContextProvider.audioContextInstance();
52
+ let bChs = buffers.length;
53
+ let frameLen = 0;
54
+ if (aCtx && bChs > 0) {
55
+ frameLen = buffers[0].length;
56
+ try {
57
+ let ad = aCtx.createBuffer(this.channels, frameLen, this.sampleRate);
58
+ for (let ch = 0; ch < this.channels; ch++) {
59
+ ad.copyToChannel(buffers[ch], ch);
60
+ }
61
+ this.chunkAudioBufferReceiver.postChunkAudioBuffer(ad, this.chunkIdx);
62
+ this.chunkIdx++;
63
+ }
64
+ catch (err) {
65
+ // TODO Handle errors
66
+ // iOS Safari sometimes throws NotSupportedError
67
+ console.error("Could not create audio buffer for chunked upload.");
68
+ console.error("Nr. of chs: " + this.channels + ", frame length: " + frameLen + ", sample rate: " + this.sampleRate);
69
+ if (err instanceof DOMException) {
70
+ console.error("DOM exception: Name: " + err.name + ", Msg: " + err.message);
71
+ if (err.name === 'NotSupportedError') {
72
+ if (frameLen == 0) {
73
+ // Empty buffers are not supported by Chromium
74
+ // No data to transfer, but this case should never happen
75
+ return frameLen;
76
+ }
77
+ else {
78
+ throw err;
79
+ }
80
+ }
81
+ else if (err.name === 'RangeError') {
82
+ console.error("DOM RangeError");
83
+ // Out of memory
84
+ // TODO What to do ??
85
+ throw err;
86
+ }
87
+ else {
88
+ console.error("DOM Exception unknown");
89
+ throw err;
90
+ }
91
+ }
92
+ else if (err instanceof RangeError) {
93
+ console.error("RangeError: Name: " + err.name + ", Msg: " + err.message);
94
+ // Out of memory
95
+ // TODO What to do ??
96
+ throw err;
97
+ }
98
+ else {
99
+ throw err;
100
+ }
101
+ }
102
+ }
103
+ return frameLen;
104
+ }
105
+ }
106
+ let BasicRecorder = class BasicRecorder extends ResponsiveComponent {
107
+ static { BasicRecorder_1 = this; }
108
+ get allowEchoCancellation() {
109
+ return this._allowEchoCancellation;
110
+ }
111
+ set allowEchoCancellation(value) {
112
+ this._allowEchoCancellation = value;
113
+ }
114
+ get maxAutoNetMemStoreSamples() {
115
+ return this._maxAutoNetMemStoreSamples;
116
+ }
117
+ set maxAutoNetMemStoreSamples(value) {
118
+ this._maxAutoNetMemStoreSamples = value;
119
+ }
120
+ static { this.DEFAULT_MAX_NET_AUTO_MEM_STORE_SAMPLES = 2880000 * 5; } // Default 5 minutes one channel at 48kHz
121
+ static { this.DEFAULT_CHUNK_SIZE_SECONDS = 30; }
122
+ get clientAudioStorageType() {
123
+ return this._clientAudioStorageType;
124
+ }
125
+ set clientAudioStorageType(value) {
126
+ let oldValue = this._clientAudioStorageType;
127
+ this._clientAudioStorageType = value;
128
+ if (value !== oldValue) {
129
+ this.configureStreamCaptureStream();
130
+ }
131
+ }
132
+ get persistentAudioStorageTarget() {
133
+ return this._persistentAudioStorageTarget;
134
+ }
135
+ set persistentAudioStorageTarget(value) {
136
+ let oldValue = this._persistentAudioStorageTarget;
137
+ this._persistentAudioStorageTarget = value;
138
+ if (value !== oldValue) {
139
+ this.configureStreamCaptureStream();
140
+ }
141
+ }
142
+ // Enable only for developemnt/debug purposes of array audio buffers !!
143
+ static { this.FORCE_ARRRAY_AUDIO_BUFFER = false; }
144
+ get uploadChunkSizeSeconds() {
145
+ return this._uploadChunkSizeSeconds;
146
+ }
147
+ set uploadChunkSizeSeconds(value) {
148
+ let oldValue = this.uploadChunkSizeSeconds;
149
+ this._uploadChunkSizeSeconds = value;
150
+ if (value !== oldValue) {
151
+ this.configureStreamCaptureStream();
152
+ }
153
+ }
154
+ constructor(bpo, changeDetectorRef, dialog, sessionService, uploader, config) {
155
+ super(bpo);
156
+ this.bpo = bpo;
157
+ this.changeDetectorRef = changeDetectorRef;
158
+ this.dialog = dialog;
159
+ this.sessionService = sessionService;
160
+ this.uploader = uploader;
161
+ this.config = config;
162
+ this.maxRecTimerId = null;
163
+ this.maxRecTimerRunning = false;
164
+ this._maxAutoNetMemStoreSamples = BasicRecorder_1.DEFAULT_MAX_NET_AUTO_MEM_STORE_SAMPLES;
165
+ this.statusMsg = '';
166
+ this.statusWaiting = false;
167
+ this.readonly = false;
168
+ this.rfUuid = null;
169
+ this.processingRecording = false;
170
+ this.ac = null;
171
+ this._wakeLock = false;
172
+ this._selectedDeviceId = undefined;
173
+ this._channelCount = 2;
174
+ this._allowEchoCancellation = false;
175
+ this._session = null;
176
+ this._recordingFile = null;
177
+ this.startedDate = null;
178
+ this.uploadProgress = 100;
179
+ this.uploadStatus = 'ok';
180
+ this.uploadSet = null;
181
+ this.audioSignalCollapsed = true;
182
+ this.peakLevelInDb = MIN_DB_LEVEL;
183
+ this.audioLoaded = false;
184
+ this.disableAudioDetails = false;
185
+ this._controlAudioPlayer = null;
186
+ this.displayAudioClip = null;
187
+ this.audioFetchSubscription = null;
188
+ this.liveLevelDisplayState = LiveLevelState.READY;
189
+ this.keepLiveLevel = false;
190
+ this.calcBufferInfosSubscr = null;
191
+ this.destroyed = false;
192
+ this.navigationDisabled = true;
193
+ this._uploadChunkSizeSeconds = null;
194
+ //=BasicRecorder.DEFAULT_CHUNK_SIZE_SECONDS;
195
+ // Default: Continuous HTML5 Audio API AudioBuffer, no chunked upload
196
+ this._clientAudioStorageType = AudioStorageType.MEM_ENTIRE;
197
+ this._persistentAudioStorageTarget = null;
198
+ this._screenLocked = false;
199
+ this.userAgent = UserAgentBuilder.userAgent();
200
+ const detPfm = this.userAgent.detectedPlatform;
201
+ if (detPfm) {
202
+ console.debug("Detected platform: " + detPfm);
203
+ }
204
+ const detBr = this.userAgent.detectedBrowser;
205
+ const detBrVers = this.userAgent.detectedBrowserVersion;
206
+ if (detBr) {
207
+ let detBrVersStr = (detBrVers) ? ' ' + detBrVers : '';
208
+ console.debug("Detected browser: " + detBr + detBrVersStr);
209
+ }
210
+ this.transportActions = new TransportActions();
211
+ this.playStartAction = new Action('Play');
212
+ this.levelMeasure = new LevelMeasure();
213
+ this.streamLevelMeasure = new StreamLevelMeasure();
214
+ this.selCaptureDeviceId = null;
215
+ }
216
+ get wakeLock() {
217
+ return this._wakeLock;
218
+ }
219
+ set wakeLock(value) {
220
+ this._wakeLock = value;
221
+ }
222
+ enableWakeLockCond() {
223
+ if (this.wakeLock === true) {
224
+ if (!this.wakeLockManager) {
225
+ this.wakeLockManager = new WakeLockManager();
226
+ this.wakeLockManager.behaviorSubject.subscribe({
227
+ next: (v) => {
228
+ this._screenLocked = v;
229
+ },
230
+ error: (err) => {
231
+ console.error("Wake lock error!");
232
+ this._screenLocked = false;
233
+ }
234
+ });
235
+ }
236
+ this.wakeLockManager.enableWakeLock();
237
+ }
238
+ }
239
+ disableWakeLockCond() {
240
+ this.wakeLockManager?.disableWakeLock();
241
+ }
242
+ get screenLocked() {
243
+ return this._screenLocked;
244
+ }
245
+ set audioDevices(audioDevices) {
246
+ this._audioDevices = audioDevices;
247
+ }
248
+ set autoGainControlConfigs(autoGainControlConfigs) {
249
+ this._autoGainControlConfigs = autoGainControlConfigs;
250
+ }
251
+ set channelCount(channelCount) {
252
+ this._channelCount = channelCount;
253
+ }
254
+ set session(session) {
255
+ this._session = session;
256
+ }
257
+ get session() {
258
+ return this._session;
259
+ }
260
+ enableStartUserGesture() {
261
+ this.statusAlertType = 'info';
262
+ this.statusMsg = 'Ready.';
263
+ }
264
+ configureStreamCaptureStream() {
265
+ let outStream;
266
+ if (AudioStorageType.MEM_ENTIRE !== this._clientAudioStorageType || this.uploadChunkSizeSeconds) {
267
+ if (!this.uploadChunkSizeSeconds) {
268
+ this.uploadChunkSizeSeconds = BasicRecorder_1.DEFAULT_CHUNK_SIZE_SECONDS;
269
+ }
270
+ // Multiply the capture stream to...
271
+ let sasm = new SequenceAudioFloat32OutStreamMultiplier();
272
+ // ...upload audio data in chunks...
273
+ let chMng = new ChunkManager(this); // The chunk manager connects the chunked audio stream to this class to upload the chunks
274
+ let chOsUpload = new SequenceAudioFloat32ChunkerOutStream(chMng, this.uploadChunkSizeSeconds); // The audio stream chunker itself
275
+ sasm.sequenceAudioFloat32OutStreams.push(chOsUpload);
276
+ // ...and to measure the level
277
+ let chOsLvlMeas = new SequenceAudioFloat32ChunkerOutStream(this.streamLevelMeasure, LEVEL_BAR_INTERVALL_SECONDS);
278
+ sasm.sequenceAudioFloat32OutStreams.push(chOsLvlMeas);
279
+ outStream = sasm;
280
+ }
281
+ else {
282
+ outStream = new SequenceAudioFloat32ChunkerOutStream(this.streamLevelMeasure, LEVEL_BAR_INTERVALL_SECONDS);
283
+ }
284
+ if (this.ac) {
285
+ this.ac.maxAutoNetMemStoreSamples = this._maxAutoNetMemStoreSamples;
286
+ this.ac.audioStorageType = this._clientAudioStorageType;
287
+ this.ac.audioOutStream = outStream;
288
+ if (AudioStorageType.DB_CHUNKED === this._clientAudioStorageType && this._persistentAudioStorageTarget !== null) {
289
+ this.ac.persistentAudioStorageTarget = this._persistentAudioStorageTarget;
290
+ }
291
+ }
292
+ }
293
+ showRecording() {
294
+ if (this._controlAudioPlayer) {
295
+ this._controlAudioPlayer.stop();
296
+ }
297
+ if (this.calcBufferInfosSubscr) {
298
+ this.calcBufferInfosSubscr.unsubscribe();
299
+ }
300
+ if (this.displayAudioClip) {
301
+ let dap = this.displayAudioClip;
302
+ let adh = dap.audioDataHolder;
303
+ if (adh) {
304
+ if (!this.keepLiveLevel) {
305
+ this.liveLevelDisplayState = LiveLevelState.LOADING;
306
+ }
307
+ adh.addOnReadyListener(() => {
308
+ //console.debug("Audio data holder ready. Enable playback. Audio loaded true.")
309
+ if (!this.keepLiveLevel) {
310
+ this.liveLevelDisplayState = LiveLevelState.RENDERING;
311
+ this.calcBufferInfosSubscr = this.levelMeasure.calcBufferLevelInfos(adh, LEVEL_BAR_INTERVALL_SECONDS).subscribe((levelInfos) => {
312
+ //console.debug("Level infos: levelInfos number size: "+levelInfos.numberSize());
313
+ dap.levelInfos = levelInfos;
314
+ this.liveLevelDisplayState = LiveLevelState.READY;
315
+ this.changeDetectorRef.detectChanges();
316
+ });
317
+ }
318
+ this.playStartAction.disabled = false;
319
+ this.audioLoaded = true;
320
+ this.changeDetectorRef.detectChanges();
321
+ });
322
+ //console.debug("Audio data holder added onReady.")
323
+ }
324
+ //this.playStartAction.disabled = false;
325
+ }
326
+ else {
327
+ this.playStartAction.disabled = true;
328
+ this.audioLoaded = false;
329
+ // Collapse audio signal display if open
330
+ if (!this.audioSignalCollapsed) {
331
+ this.audioSignalCollapsed = true;
332
+ }
333
+ }
334
+ this.changeDetectorRef.detectChanges();
335
+ }
336
+ start() {
337
+ this.statusAlertType = 'info';
338
+ this.statusMsg = 'Starting session...';
339
+ this.statusWaiting = false;
340
+ if (this._session) {
341
+ if (this._session.sealed) {
342
+ this.readonly = true;
343
+ this.statusMsg = 'Session sealed!';
344
+ //let dialogRef = this.dialog.open(SessionSealedDialog, {});
345
+ this.dialog.open(MessageDialog, {
346
+ data: {
347
+ type: 'error',
348
+ title: 'Error',
349
+ msg: "This session is sealed. Recordings cannot be added anymore.",
350
+ advice: 'Please ask your experimenter what to do (e.g start a new session).',
351
+ }
352
+ });
353
+ }
354
+ else {
355
+ let body = {};
356
+ if (this._session.status === "CREATED") {
357
+ this._session.status = "LOADED";
358
+ body.status = this._session.status;
359
+ if (!this._session.loadedDate) {
360
+ this._session.loadedDate = new Date();
361
+ body.loadedDate = this._session.loadedDate;
362
+ }
363
+ }
364
+ else {
365
+ this._session.restartedDate = new Date();
366
+ body.restartedDate = this._session.restartedDate;
367
+ }
368
+ this.sessionService.patchSessionObserver(this._session, body).subscribe();
369
+ }
370
+ }
371
+ // Check browser compatibility
372
+ if (this.userAgent.detectedBrowser === Browser.Safari && this._channelCount > 1) {
373
+ let eMsg = "Error: Safari browser does not support stereo recordings.";
374
+ console.error(eMsg);
375
+ this.dialog.open(MessageDialog, {
376
+ data: {
377
+ type: 'error',
378
+ title: 'Browser not supported',
379
+ msg: eMsg,
380
+ advice: "Please use a supported browser, e.g. Mozilla Firefox."
381
+ }
382
+ });
383
+ }
384
+ //console.log("Session ID: "+this._session.session+ " status: "+this._session.status)
385
+ this._selectedDeviceId = undefined;
386
+ if (!this.readonly && this.ac && (FORCE_REQUEST_AUDIO_PERMISSIONS || (this._audioDevices && this._audioDevices.length > 0))) {
387
+ this.statusMsg = 'Requesting audio permissions...';
388
+ this.statusAlertType = 'info';
389
+ this.ac.deviceInfos((mdis) => {
390
+ let audioCaptureDeviceAvail = false;
391
+ let audioPlayDeviceAvail = false;
392
+ if (mdis) {
393
+ if (this.ac) {
394
+ this.ac.printDevices(mdis);
395
+ }
396
+ if (mdis.length > 0) {
397
+ for (let mdii = 0; mdii < mdis.length; mdii++) {
398
+ let mdi = mdis[mdii];
399
+ let kind = mdi.kind;
400
+ if (kind === "audioinput") {
401
+ audioCaptureDeviceAvail = true;
402
+ }
403
+ else if (kind === "audiooutput") {
404
+ audioPlayDeviceAvail = true;
405
+ }
406
+ }
407
+ }
408
+ if (this._session && this._session.type !== 'TEST_DEF_A' && this._audioDevices && this._audioDevices.length > 0) {
409
+ let fdi = null;
410
+ for (let adI = 0; adI < this._audioDevices.length; adI++) {
411
+ let ad = this._audioDevices[adI];
412
+ if (ad.playback) {
413
+ // project audio device config for playback device
414
+ // not used for now
415
+ continue;
416
+ }
417
+ for (let mdii = 0; mdii < mdis.length; mdii++) {
418
+ let mdi = mdis[mdii];
419
+ let kind = mdi.kind;
420
+ if (kind === "audioinput") {
421
+ audioCaptureDeviceAvail = true;
422
+ }
423
+ else if (kind === "audiooutput") {
424
+ audioPlayDeviceAvail = true;
425
+ }
426
+ if (ad.regex) {
427
+ //console.log("Match?: \'"+mdi.label+"\' \'"+ad.name+"\'");
428
+ if (mdi.label.match(ad.name)) {
429
+ fdi = mdi;
430
+ //console.log("Match!");
431
+ }
432
+ }
433
+ else {
434
+ if (mdi.label.trim() === ad.name.trim()) {
435
+ fdi = mdi;
436
+ }
437
+ }
438
+ if (fdi) {
439
+ break;
440
+ }
441
+ }
442
+ if (fdi) {
443
+ break;
444
+ }
445
+ }
446
+ if (fdi) {
447
+ // matching device found
448
+ // Not able to open device here since Chrome 71
449
+ // Chrome 71 requires a user gesture before the AudioContext can be resumed
450
+ // sessionmanager.ts:712 Open session with default audio device for 1 channels
451
+ // capture.ts:128 The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page. https://goo.gl/7K7WLu
452
+ // push../projects/speechrecorderng/src/lib/audio/capture/capture.ts.AudioCapture.open @ capture.ts:128
453
+ //this.ac.open(this._channelCount, fdi.deviceId);
454
+ console.info("Set selected audio device: \'" + fdi.label + "\' Id: \'" + fdi.deviceId + "\'");
455
+ this._selectedDeviceId = fdi.deviceId;
456
+ this.enableStartUserGesture();
457
+ }
458
+ else {
459
+ // device not found
460
+ this.statusMsg = 'ERROR: Required audio device not available!';
461
+ this.statusAlertType = 'error';
462
+ this.readonly = true;
463
+ this.dialog.open(MessageDialog, {
464
+ data: {
465
+ type: 'error',
466
+ title: 'Required audio device',
467
+ msg: "Required audio device not found",
468
+ advice: "Please connect a suitable audio device for this project and retry (press the browser reload button)."
469
+ }
470
+ });
471
+ }
472
+ }
473
+ else {
474
+ if (!audioCaptureDeviceAvail && !audioPlayDeviceAvail) {
475
+ // no device found
476
+ this.statusMsg = 'ERROR: No audio device available!';
477
+ this.statusAlertType = 'warn';
478
+ //this.readonly = true;
479
+ this.dialog.open(MessageDialog, {
480
+ data: {
481
+ type: 'warn',
482
+ title: 'No audio device',
483
+ msg: "No audio device found",
484
+ advice: "Please connect an audio device and retry (press the browser reload button) or try to continue anyway."
485
+ }
486
+ });
487
+ }
488
+ else {
489
+ if (!this.readonly && !audioCaptureDeviceAvail) {
490
+ // no device found
491
+ this.statusMsg = 'WARNING: No audio capture device available!';
492
+ this.statusAlertType = 'warning';
493
+ //this.readonly = true;
494
+ this.dialog.open(MessageDialog, {
495
+ data: {
496
+ type: 'warning',
497
+ title: 'No audio capture device',
498
+ msg: "No audio capture device found",
499
+ advice: "Please connect an audio capture device and retry (press the browser reload button) or try to continue anyway."
500
+ }
501
+ });
502
+ }
503
+ // Safari does not list playback devices
504
+ if (!audioPlayDeviceAvail) {
505
+ // Firefox does not enumerate audiooutput devices
506
+ // Do not show this warning, because it would always appear on Firefox
507
+ // When https://bugzilla.mozilla.org/show_bug.cgi?id=1498512 is fixed the warning can be enabled for Firefox as well
508
+ // It is already implemneted but kept behind a preference setting https://bugzilla.mozilla.org/show_bug.cgi?id=1152401
509
+ // Output devices are listed if about:config media.setsinkid.enabled=true
510
+ // but default setting is false
511
+ // Same problem with Safari
512
+ if (!(this.userAgent.detectedBrowser === Browser.Safari || this.userAgent.detectedBrowser === Browser.Firefox)) {
513
+ // no device found
514
+ this.statusMsg = 'WARNING: No audio playback device available!';
515
+ this.statusAlertType = 'warn';
516
+ //this.readonly = true;
517
+ this.dialog.open(MessageDialog, {
518
+ data: {
519
+ type: 'warn',
520
+ title: 'No audio playback device',
521
+ msg: "No audio playback device found",
522
+ advice: "Please connect an audio playback device and retry (press the browser reload button) or try to continue anyway."
523
+ }
524
+ });
525
+ }
526
+ }
527
+ }
528
+ // Not able to open device here since Chrome 71
529
+ // Chrome 71 requires a user gesture before the AudioContext can be resumed
530
+ // sessionmanager.ts:712 Open session with default audio device for 1 channels
531
+ // capture.ts:128 The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page. https://goo.gl/7K7WLu
532
+ // push../projects/speechrecorderng/src/lib/audio/capture/capture.ts.AudioCapture.open @ capture.ts:128
533
+ //console.log("Open session with default audio device for "+this._channelCount+" channels");
534
+ //this.ac.open(this._channelCount);
535
+ // enable start gesture anyway
536
+ this.enableStartUserGesture();
537
+ }
538
+ }
539
+ });
540
+ }
541
+ this.statusMsg = 'Ready.';
542
+ }
543
+ startItem() {
544
+ this.rfUuid = UUID.generate();
545
+ if (this.ac) {
546
+ this.ac.recUUID = this.rfUuid;
547
+ }
548
+ this.startedDate = null;
549
+ this.enableWakeLockCond();
550
+ //this.rfUuid=UUID.generate();
551
+ this.uploadSet = null;
552
+ this.transportActions.startAction.disabled = true;
553
+ this.transportActions.pauseAction.disabled = true;
554
+ }
555
+ startCapture() {
556
+ if (this.ac) {
557
+ if (!this.ac.opened) {
558
+ if (this._selectedDeviceId) {
559
+ console.log("Open session with audio device Id: \'" + this._selectedDeviceId + "\' for " + this._channelCount + " channels");
560
+ }
561
+ else {
562
+ console.log("Open session with default audio device for " + this._channelCount + " channels");
563
+ }
564
+ this.ac.open(this._channelCount, this._selectedDeviceId, this._autoGainControlConfigs, this._allowEchoCancellation);
565
+ }
566
+ else {
567
+ this.ac.start();
568
+ }
569
+ }
570
+ }
571
+ opened() {
572
+ if (this.ac) {
573
+ this.ac.start();
574
+ }
575
+ }
576
+ started() {
577
+ if (!this.startedDate) {
578
+ this.startedDate = new Date();
579
+ }
580
+ this.transportActions.startAction.disabled = true;
581
+ }
582
+ postRecording(wavFile, recUrl, rf, uploadHolder) {
583
+ let wavBlob = new Blob([wavFile], { type: 'audio/wav' });
584
+ let ul = new Upload(wavBlob, recUrl, rf);
585
+ if (uploadHolder) {
586
+ uploadHolder.upload = ul;
587
+ }
588
+ this.uploader.queueUpload(ul);
589
+ }
590
+ postAudioStreamStart() {
591
+ if (this.rfUuid) {
592
+ this.uploadSet = new UploadSet();
593
+ let apiEndPoint = '';
594
+ if (this.config && this.config.apiEndPoint) {
595
+ apiEndPoint = this.config.apiEndPoint;
596
+ }
597
+ if (apiEndPoint !== '') {
598
+ apiEndPoint = apiEndPoint + '/';
599
+ }
600
+ let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
601
+ let recUrl = sessionsUrl + '/' + this.session?.sessionId + '/' + RECFILE_API_CTX + '/' + this.rfUuid + '/prepareChunksRequest';
602
+ let fd = new FormData();
603
+ // Note: At least one parameter must be set
604
+ fd.set('uuid', this.rfUuid);
605
+ if (!this.startedDate) {
606
+ this.startedDate = new Date();
607
+ }
608
+ fd.set('startedDate', this.startedDate.toJSON());
609
+ let ul = new Upload(fd, recUrl);
610
+ this.uploadSet.add(ul);
611
+ this.uploader.queueUpload(ul);
612
+ }
613
+ else {
614
+ console.error("Recording file UUID not set!");
615
+ }
616
+ }
617
+ sessionsBaseUrl() {
618
+ let apiEndPoint = '';
619
+ if (this.config && this.config.apiEndPoint) {
620
+ apiEndPoint = this.config.apiEndPoint;
621
+ }
622
+ if (apiEndPoint !== '') {
623
+ apiEndPoint = apiEndPoint + '/';
624
+ }
625
+ return apiEndPoint + SessionService.SESSION_API_CTX;
626
+ }
627
+ postAudioStreamEnd(chunkCount) {
628
+ if (this.rfUuid) {
629
+ let sessionsUrl = this.sessionsBaseUrl();
630
+ let recUrl = sessionsUrl + '/' + this.session?.sessionId + '/' + RECFILE_API_CTX + '/' + this.rfUuid + '/concatChunksRequest';
631
+ let fd = new FormData();
632
+ fd.set('uuid', this.rfUuid);
633
+ fd.set('chunkCount', chunkCount.toString());
634
+ let ul = new Upload(fd, recUrl, this._recordingFile);
635
+ if (this.uploadSet) {
636
+ this.uploadSet.add(ul);
637
+ this.uploadSet.complete();
638
+ }
639
+ this.uploader.queueUpload(ul);
640
+ //console.debug("Queued for upload: "+this._recordingFile);
641
+ }
642
+ else {
643
+ console.error("Recording file UUID not set!");
644
+ }
645
+ }
646
+ closed() {
647
+ this.statusAlertType = 'info';
648
+ this.statusMsg = 'Session closed.';
649
+ }
650
+ error(msg = 'An unknown error occured during recording.', advice = 'Please retry.') {
651
+ this.navigationDisabled = false;
652
+ this.statusMsg = 'ERROR: Recording.';
653
+ this.statusAlertType = 'error';
654
+ this.dialog.open(MessageDialog, {
655
+ data: {
656
+ type: 'error',
657
+ title: 'Recording error',
658
+ msg: msg,
659
+ advice: advice
660
+ }
661
+ });
662
+ }
663
+ };
664
+ BasicRecorder = BasicRecorder_1 = __decorate([
665
+ __param(5, Inject(SPEECHRECORDER_CONFIG))
666
+ ], BasicRecorder);
667
+ export { BasicRecorder };
668
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzaWNyZWNvcmRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3NwZWVjaHJlY29yZGVybmcvc3JjL2xpYi9zcGVlY2hyZWNvcmRlci9zZXNzaW9uL2Jhc2ljcmVjb3JkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUNoRCxPQUFPLEVBQUMsT0FBTyxFQUFhLGdCQUFnQixFQUFDLE1BQU0sdUJBQXVCLENBQUM7QUFFM0UsT0FBTyxFQUFDLGFBQWEsRUFBQyxNQUFNLHlCQUF5QixDQUFDO0FBRXRELE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSxtQkFBbUIsQ0FBQztBQUVqRCxPQUFPLEVBQWMsZ0JBQWdCLEVBQXdCLE1BQU0sb0JBQW9CLENBQUM7QUFDeEYsT0FBTyxFQUFDLFlBQVksRUFBRSxrQkFBa0IsRUFBQyxNQUFNLCtCQUErQixDQUFDO0FBSS9FLE9BQU8sRUFBQyxNQUFNLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQztBQUMzQyxPQUFPLEVBQUMsWUFBWSxFQUFDLE1BQU0sZ0NBQWdDLENBQUM7QUFDNUQsT0FBTyxFQUFDLE1BQU0sRUFBZ0IsU0FBUyxFQUFDLE1BQU0sb0JBQW9CLENBQUM7QUFDbkUsT0FBTyxFQUFvQixNQUFNLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFDeEQsT0FBTyxFQUFDLHFCQUFxQixFQUF1QixNQUFNLGtCQUFrQixDQUFDO0FBRzdFLE9BQU8sRUFDTCxvQ0FBb0MsRUFFcEMsdUNBQXVDLEVBQ3hDLE1BQU0sdUJBQXVCLENBQUM7QUFFL0IsT0FBTyxFQUFDLG9CQUFvQixFQUFDLE1BQU0scUJBQXFCLENBQUM7QUFDekQsT0FBTyxFQUFDLElBQUksRUFBQyxNQUFNLG1CQUFtQixDQUFDO0FBQ3ZDLE9BQU8sRUFBQyxlQUFlLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUN0RCxPQUFP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QUMsY0FBYyxDQUFDLENBQUM7WUFDcEQsSUFBRyxJQUFJLENBQUMsU0FBUyxFQUFDO2dCQUNoQixJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDdkIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUUsQ0FBQzthQUMzQjtZQUNELElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQzlCLDJEQUEyRDtTQUM1RDthQUFJO1lBQ0gsT0FBTyxDQUFDLEtBQUssQ0FBQyw4QkFBOEIsQ0FBQyxDQUFBO1NBQzlDO0lBQ0gsQ0FBQztJQUVELE1BQU07UUFDSixJQUFJLENBQUMsZUFBZSxHQUFHLE1BQU0sQ0FBQztRQUM5QixJQUFJLENBQUMsU0FBUyxHQUFHLGlCQUFpQixDQUFDO0lBQ3JDLENBQUM7SUFFRCxLQUFLLENBQUMsR0FBRyxHQUFDLDRDQUE0QyxFQUFDLFNBQWMsZUFBZTtRQUNsRixJQUFJLENBQUMsa0JBQWtCLEdBQUcsS0FBSyxDQUFDO1FBQ2hDLElBQUksQ0FBQyxTQUFTLEdBQUcsbUJBQW1CLENBQUM7UUFDckMsSUFBSSxDQUFDLGVBQWUsR0FBRyxPQUFPLENBQUM7UUFDL0IsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFO1lBQzlCLElBQUksRUFBRTtnQkFDSixJQUFJLEVBQUUsT0FBTztnQkFDYixLQUFLLEVBQUUsaUJBQWlCO2dCQUN4QixHQUFHLEVBQUUsR0FBRztnQkFDUixNQUFNLEVBQUUsTUFBTTthQUNmO1NBQ0YsQ0FBQyxDQUFDO0lBQ0wsQ0FBQzs7QUFsb0JtQixhQUFhO0lBb0lsQixXQUFBLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFBO0dBcEl4QixhQUFhLENBb29CbEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1RyYW5zcG9ydEFjdGlvbnN9IGZyb20gXCIuL2NvbnRyb2xwYW5lbFwiO1xyXG5pbXBvcnQge0Jyb3dzZXIsIFVzZXJBZ2VudCwgVXNlckFnZW50QnVpbGRlcn0gZnJvbSBcIi4uLy4uL3V0aWxzL3VhLXBhcnNlclwiO1xyXG5pbXBvcnQge01hdERpYWxvZ30gZnJvbSBcIkBhbmd1bGFyL21hdGVyaWFsL2RpYWxvZ1wiO1xyXG5pbXBvcnQge01lc3NhZ2VEaWFsb2d9IGZyb20gXCIuLi8uLi91aS9tZXNzYWdlX2RpYWxvZ1wiO1xyXG5pbXBvcnQge1Nlc3Npb259IGZyb20gXCIuL3Nlc3Npb25cIjtcclxuaW1wb3J0IHtTZXNzaW9uU2VydmljZX0gZnJvbSBcIi4vc2Vzc2lvbi5zZXJ2aWNlXCI7XHJcbmltcG9ydCB7QXVkaW9DYXB0dXJlfSBmcm9tIFwiLi4vLi4vYXVkaW8vY2FwdHVyZS9jYXB0dXJlXCI7XHJcbmltcG9ydCB7QXVkaW9EZXZpY2UsIEF1ZGlvU3RvcmFnZVR5cGUsIEF1dG9HYWluQ29udHJvbENvbmZpZ30gZnJvbSBcIi4uL3Byb2plY3QvcHJvamVjdFwiO1xyXG5pbXBvcnQge0xldmVsTWVhc3VyZSwgU3RyZWFtTGV2ZWxNZWFzdXJlfSBmcm9tIFwiLi4vLi4vYXVkaW8vZHNwL2xldmVsX21lYXN1cmVcIjtcclxuaW1wb3J0IHtBdWRpb1BsYXllcn0gZnJvbSBcIi4uLy4uL2F1ZGlvL3BsYXliYWNrL3BsYXllclwiO1xyXG5pbXBvcnQge1N1YnNjcmlwdGlvbn0gZnJvbSBcInJ4anNcIjtcclxuaW1wb3J0IHtBdWRpb0NsaXB9IGZyb20gXCIuLi8uLi9hdWRpby9wZXJzaXN0b3JcIjtcclxuaW1wb3J0IHtBY3Rpb259IGZyb20gXCIuLi8uLi9hY3Rpb24vYWN0aW9uXCI7XHJcbmltcG9ydCB7TUlOX0RCX0xFVkVMfSBmcm9tIFwiLi4vLi4vdWkvcmVjb3JkaW5naXRlbV9kaXNwbGF5XCI7XHJcbmltcG9ydCB7VXBsb2FkLCBVcGxvYWRIb2xkZXIsIFVwbG9hZFNldH0gZnJvbSBcIi4uLy4uL25ldC91cGxvYWRlclwiO1xyXG5pbXBvcnQge0NoYW5nZURldGVjdG9yUmVmLCBJbmplY3R9IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XHJcbmltcG9ydCB7U1BFRUNIUkVDT1JERVJfQ09ORklHLCBTcGVlY2hSZWNvcmRlckNvbmZpZ30gZnJvbSBcIi4uLy4uL3Nwci5jb25maWdcIjtcclxuaW1wb3J0IHtTcGVlY2hSZWNvcmRlclVwbG9hZGVyfSBmcm9tIFwiLi4vc3BydXBsb2FkZXJcIjtcclxuXHJcbmltcG9ydCB7XHJcbiAgU2VxdWVuY2VBdWRpb0Zsb2F0MzJDaHVua2VyT3V0U3RyZWFtLFxyXG4gIFNlcXVlbmNlQXVkaW9GbG9hdDMyT3V0U3RyZWFtLFxyXG4gIFNlcXVlbmNlQXVkaW9GbG9hdDMyT3V0U3RyZWFtTXVsdGlwbGllclxyXG59IGZyb20gXCIuLi8uLi9hdWRpby9pby9zdHJlYW1cIjtcclxuaW1wb3J0IHtSZWNvcmRpbmdGaWxlLCBTcHJSZWNvcmRpbmdGaWxlfSBmcm9tIFwiLi4vcmVjb3JkaW5nXCI7XHJcbmltcG9ydCB7QXVkaW9Db250ZXh0UHJvdmlkZXJ9IGZyb20gXCIuLi8uLi9hdWRpby9jb250ZXh0XCI7XHJcbmltcG9ydCB7VVVJRH0gZnJvbSBcIi4uLy4uL3V0aWxzL3V0aWxzXCI7XHJcbmltcG9ydCB7V2FrZUxvY2tNYW5hZ2VyfSBmcm9tIFwiLi4vLi4vdXRpbHMvd2FrZV9sb2NrXCI7XHJcbmltcG9ydCB7U3RhdGUgYXMgTGl2ZUxldmVsU3RhdGV9IGZyb20gXCIuLi8uLi9hdWRpby91aS9saXZlbGV2ZWxcIlxyXG5pbXBvcnQge1BlcnNpc3RlbnRBdWRpb1N0b3JhZ2VUYXJnZXR9IGZyb20gXCIuLi8uLi9hdWRpby9pbmRkYl9hdWRpb19idWZmZXJcIjtcclxuaW1wb3J0IHtSZXNwb25zaXZlQ29tcG9uZW50fSBmcm9tIFwiLi4vLi4vdWkvcmVzcG9uc2l2ZV9jb21wb25lbnRcIjtcclxuaW1wb3J0IHtCcmVha3BvaW50T2JzZXJ2ZXJ9IGZyb20gXCJAYW5ndWxhci9jZGsvbGF5b3V0XCI7XHJcblxyXG5leHBvcnQgY29uc3QgRk9SQ0VfUkVRVUVTVF9BVURJT19QRVJNSVNTSU9OUz1mYWxzZTtcclxuZXhwb3J0IGNvbnN0IFJFQ0ZJTEVfQVBJX0NUWCA9ICdyZWNmaWxlJztcclxuZXhwb3J0IGNvbnN0IE1BWF9SRUNPUkRJTkdfVElNRV9NUyA9IDEwMDAgKiA2MCAqIDYwICogNjA7IC8vIDEgaG91clxyXG5cclxuZXhwb3J0IGNvbnN0IExFVkVMX0JBUl9JTlRFUlZBTExfU0VDT05EUyA9IDAuMTsgIC8vIDEwMG1zXHJcblxyXG5leHBvcnQgY29uc3QgTk9TTEVFUF9WSURFT19USVRMRT0nTm8gU2xlZXAnO1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBDaHVua0F1ZGlvQnVmZmVyUmVjZWl2ZXJ7XHJcbiAgcG9zdEF1ZGlvU3RyZWFtU3RhcnQoKTp2b2lkO1xyXG4gIHBvc3RDaHVua0F1ZGlvQnVmZmVyKGF1ZGlvQnVmZmVyOkF1ZGlvQnVmZmVyLGNodW5rSWR4Om51bWJlcik6dm9pZDtcclxuICBwb3N0QXVkaW9TdHJlYW1FbmQoY2h1bmtDb3VudDpudW1iZXIpOnZvaWQ7XHJcbn1cclxuXHJcbmV4cG9ydCBjbGFzcyBDaHVua01hbmFnZXIgaW1wbGVtZW50cyBTZXF1ZW5jZUF1ZGlvRmxvYXQzMk91dFN0cmVhbXtcclxuXHJcbiAgc2V0IHJlY29yZGluZ0ZpbGUodmFsdWU6IFNwclJlY29yZGluZ0ZpbGUpIHtcclxuICAgIHRoaXMuX3JmID0gdmFsdWU7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGNoYW5uZWxzOm51bWJlcj0wO1xyXG4gIHByaXZhdGUgc2FtcGxlUmF0ZTpudW1iZXI9LTE7XHJcblxyXG4gIHByaXZhdGUgX3JmITpTcHJSZWNvcmRpbmdGaWxlO1xyXG5cclxuICBwcml2YXRlIGNodW5rSWR4Om51bWJlcj0wO1xyXG5cclxuXHJcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBjaHVua0F1ZGlvQnVmZmVyUmVjZWl2ZXI6Q2h1bmtBdWRpb0J1ZmZlclJlY2VpdmVyKSB7XHJcbiAgfVxyXG5cclxuICBjbG9zZSgpOiB2b2lkIHtcclxuICAgIC8vIE5vdGhpbmcgdG8gZG9cclxuICB9XHJcblxyXG4gIGZsdXNoKCk6IHZvaWQge1xyXG4gICAgdGhpcy5jaHVua0F1ZGlvQnVmZmVyUmVjZWl2ZXIucG9zdEF1ZGlvU3RyZWFtRW5kKHRoaXMuY2h1bmtJZHgpO1xyXG4gIH1cclxuXHJcbiAgbmV4dFN0cmVhbSgpOiB2b2lkIHtcclxuICAgIC8vIHJlc2V0IGNodW5rIGNvdW50ZXJcclxuICAgIHRoaXMuY2h1bmtJZHg9MDtcclxuICAgIHRoaXMuY2h1bmtBdWRpb0J1ZmZlclJlY2VpdmVyLnBvc3RBdWRpb1N0cmVhbVN0YXJ0KCk7XHJcbiAgfVxyXG5cclxuICBzZXRGb3JtYXQoY2hhbm5lbHM6IG51bWJlciwgc2FtcGxlUmF0ZTogbnVtYmVyKTogdm9pZCB7XHJcbiAgICB0aGlzLmNoYW5uZWxzPWNoYW5uZWxzO1xyXG4gICAgdGhpcy5zYW1wbGVSYXRlPXNhbXBsZVJhdGU7XHJcbiAgfVxyXG5cclxuICB3cml0ZShidWZmZXJzOiBBcnJheTxGbG9hdDMyQXJyYXk+KTogbnVtYmVyIHtcclxuICAgIGxldCBhQ3R4PUF1ZGlvQ29udGV4dFByb3ZpZGVyLmF1ZGlvQ29udGV4dEluc3RhbmNlKCk7XHJcbiAgICBsZXQgYkNocz1idWZmZXJzLmxlbmd0aDtcclxuICAgIGxldCBmcmFtZUxlbj0wO1xyXG4gICAgaWYoYUN0eCAmJiBiQ2hzPjApIHtcclxuICAgICAgZnJhbWVMZW49YnVmZmVyc1swXS5sZW5ndGg7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbGV0IGFkID0gYUN0eC5jcmVhdGVCdWZmZXIodGhpcy5jaGFubmVscywgZnJhbWVMZW4sIHRoaXMuc2FtcGxlUmF0ZSk7XHJcbiAgICAgICAgZm9yIChsZXQgY2ggPSAwOyBjaCA8IHRoaXMuY2hhbm5lbHM7IGNoKyspIHtcclxuICAgICAgICAgIGFkLmNvcHlUb0NoYW5uZWwoYnVmZmVyc1tjaF0sY2gpO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLmNodW5rQXVkaW9CdWZmZXJSZWNlaXZlci5wb3N0Q2h1bmtBdWRpb0J1ZmZlcihhZCx0aGlzLmNodW5rSWR4KTtcclxuICAgICAgICB0aGlzLmNodW5rSWR4Kys7XHJcbiAgICAgIH1jYXRjaChlcnIpe1xyXG4gICAgICAgIC8vIFRPRE8gSGFuZGxlIGVycm9yc1xyXG4gICAgICAgIC8vIGlPUyBTYWZhcmkgc29tZXRpbWVzIHRocm93cyBOb3RTdXBwb3J0ZWRFcnJvclxyXG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJDb3VsZCBub3QgY3JlYXRlIGF1ZGlvIGJ1ZmZlciBmb3IgY2h1bmtlZCB1cGxvYWQuXCIpO1xyXG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJOci4gb2YgY2hzOiBcIit0aGlzLmNoYW5uZWxzK1wiLCBmcmFtZSBsZW5ndGg6IFwiK2ZyYW1lTGVuK1wiLCBzYW1wbGUgcmF0ZTogXCIrdGhpcy5zYW1wbGVSYXRlKTtcclxuICAgICAgICBpZihlcnIgaW5zdGFuY2VvZiBET01FeGNlcHRpb24pe1xyXG4gICAgICAgICAgY29uc29sZS5lcnJvcihcIkRPTSBleGNlcHRpb246IE5hbWU6IFwiK2Vyci5uYW1lK1wiLCBNc2c6IFwiK2Vyci5tZXNzYWdlKTtcclxuICAgICAgICAgIGlmKGVyci5uYW1lPT09J05vdFN1cHBvcnRlZEVycm9yJyl7XHJcbiAgICAgICAgICAgIGlmKGZyYW1lTGVuPT0wKXtcclxuICAgICAgICAgICAgICAvLyBFbXB0eSBidWZmZXJzIGFyZSBub3Qgc3VwcG9ydGVkIGJ5IENocm9taXVtXHJcbiAgICAgICAgICAgICAvLyBObyBkYXRhIHRvIHRyYW5zZmVyLCBidXQgdGhpcyBjYXNlIHNob3VsZCBuZXZlciBoYXBwZW5cclxuICAgICAgICAgICAgICByZXR1cm4gZnJhbWVMZW47XHJcbiAgICAgICAgICAgIH1lbHNle1xyXG4gICAgICAgICAgICAgIHRocm93IGVycjtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfWVsc2UgaWYoZXJyLm5hbWU9PT0nUmFuZ2VFcnJvcicpe1xyXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRE9NIFJhbmdlRXJyb3JcIik7XHJcbiAgICAgICAgICAgIC8vIE91dCBvZiBtZW1vcnlcclxuICAgICAgICAgICAgLy8gVE9ETyBXaGF0IHRvIGRvID8/XHJcbiAgICAgICAgICAgIHRocm93IGVycjtcclxuICAgICAgICAgIH1lbHNle1xyXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRE9NIEV4Y2VwdGlvbiB1bmtub3duXCIpO1xyXG4gICAgICAgICAgICB0aHJvdyBlcnI7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfWVsc2UgaWYgKGVyciBpbnN0YW5jZW9mIFJhbmdlRXJyb3Ipe1xyXG4gICAgICAgICAgY29uc29sZS5lcnJvcihcIlJhbmdlRXJyb3I6IE5hbWU6IFwiK2Vyci5uYW1lK1wiLCBNc2c6IFwiK2Vyci5tZXNzYWdlKTtcclxuICAgICAgICAgIC8vIE91dCBvZiBtZW1vcnlcclxuICAgICAgICAgIC8vIFRPRE8gV2hhdCB0byBkbyA/P1xyXG4gICAgICAgICAgdGhyb3cgZXJyO1xyXG4gICAgICAgIH1lbHNle1xyXG4gICAgICAgICAgdGhyb3cgZXJyO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIGZyYW1lTGVuO1xyXG4gIH1cclxuXHJcbn1cclxuXHJcbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBCYXNpY1JlY29yZGVyIGV4dGVuZHMgUmVzcG9uc2l2ZUNvbXBvbmVudHtcclxuICBnZXQgYWxsb3dFY2hvQ2FuY2VsbGF0aW9uKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMuX2FsbG93RWNob0NhbmNlbGxhdGlvbjtcclxuICB9XHJcblxyXG4gIHNldCBhbGxvd0VjaG9DYW5jZWxsYXRpb24odmFsdWU6IGJvb2xlYW4pIHtcclxuICAgIHRoaXMuX2FsbG93RWNob0NhbmNlbGxhdGlvbiA9IHZhbHVlO1xyXG4gIH1cclxuXHJcbiAgcHJvdGVjdGVkIHVwZGF0ZVRpbWVySWQ6IGFueTtcclxuXHJcbiAgcHJvdGVjdGVkIG1heFJlY1RpbWVySWQ6IG51bWJlcnxudWxsPW51bGw7XHJcbiAgcHJvdGVjdGVkIG1heFJlY1RpbWVyUnVubmluZzogYm9vbGVhbj1mYWxzZTtcclxuXHJcbiAgZ2V0IG1heEF1dG9OZXRNZW1TdG9yZVNhbXBsZXMoKTogbnVtYmVyIHtcclxuICAgIHJldHVybiB0aGlzLl9tYXhBdXRvTmV0TWVtU3RvcmVTYW1wbGVzO1xyXG4gIH1cclxuXHJcbiAgc2V0IG1heEF1dG9OZXRNZW1TdG9yZVNhbXBsZXModmFsdWU6IG51bWJlcikge1xyXG4gICAgdGhpcy5fbWF4QXV0b05ldE1lbVN0b3JlU2FtcGxlcyA9IHZhbHVlO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBERUZBVUxUX01BWF9ORVRfQVVUT19NRU1fU1RPUkVfU0FNUExFUzpudW1iZXI9Mjg4MDAwMCo1OyAvLyBEZWZhdWx0IDUgbWludXRlcyBvbmUgY2hhbm5lbCBhdCA0OGtIelxyXG4gIHByb3RlY3RlZCBfbWF4QXV0b05ldE1lbVN0b3JlU2FtcGxlczpudW1iZXI9QmFzaWNSZWNvcmRlci5ERUZBVUxUX01BWF9ORVRfQVVUT19NRU1fU1RPUkVfU0FNUExFUztcclxuXHJcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBERUZBVUxUX0NIVU5LX1NJWkVfU0VDT05EUzpudW1iZXI9MzA7XHJcblxyXG4gIGdldCBjbGllbnRBdWRpb1N0b3JhZ2VUeXBlKCk6IEF1ZGlvU3RvcmFnZVR5cGUge1xyXG4gICAgcmV0dXJuIHRoaXMuX2NsaWVudEF1ZGlvU3RvcmFnZVR5cGU7XHJcbiAgfVxyXG5cclxuICBzZXQgY2xpZW50QXVkaW9TdG9yYWdlVHlwZSh2YWx1ZTogQXVkaW9TdG9yYWdlVHlwZSkge1xyXG5cclxuICAgIGxldCBvbGRWYWx1ZT10aGlzLl9jbGllbnRBdWRpb1N0b3JhZ2VUeXBlO1xyXG4gICAgdGhpcy5fY2xpZW50QXVkaW9TdG9yYWdlVHlwZSA9IHZhbHVlO1xyXG4gICAgaWYodmFsdWUhPT1vbGRWYWx1ZSl7XHJcbiAgICAgIHRoaXMuY29uZmlndXJlU3RyZWFtQ2FwdHVyZVN0cmVhbSgpO1xyXG4gICAgfVxyXG4gIH1cclxuICBnZXQgcGVyc2lzdGVudEF1ZGlvU3RvcmFnZVRhcmdldCgpOiBQZXJzaXN0ZW50QXVkaW9TdG9yYWdlVGFyZ2V0IHwgbnVsbCB7XHJcbiAgICByZXR1cm4gdGhpcy5fcGVyc2lzdGVudEF1ZGlvU3RvcmFnZVRhcmdldDtcclxuICB9XHJcblxyXG4gIHNldCBwZXJzaXN0ZW50QXVkaW9TdG9yYWdlVGFyZ2V0KHZhbHVlOiBQZXJzaXN0ZW50QXVkaW9TdG9yYWdlVGFyZ2V0IHwgbnVsbCkge1xyXG4gICAgbGV0IG9sZFZhbHVlPXRoaXMuX3BlcnNpc3RlbnRBdWRpb1N0b3JhZ2VUYXJnZXQ7XHJcbiAgICB0aGlzLl9wZXJzaXN0ZW50QXVkaW9TdG9yYWdlVGFyZ2V0ID0gdmFsdWU7XHJcbiAgICBpZih2YWx1ZSE9PW9sZFZhbHVlKXtcclxuICAgICAgdGhpcy5jb25maWd1cmVTdHJlYW1DYXB0dXJlU3RyZWFtKCk7XHJcbiAgICB9XHJcblxyXG4gIH1cclxuXHJcbiAgLy8gRW5hYmxlIG9ubHkgZm9yIGRldmVsb3BlbW50L2RlYnVnIHB1cnBvc2VzIG9mIGFycmF5IGF1ZGlvIGJ1ZmZlcnMgISFcclxuICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IEZPUkNFX0FSUlJBWV9BVURJT19CVUZGRVI9ZmFsc2U7XHJcblxyXG4gIGdldCB1cGxvYWRDaHVua1NpemVTZWNvbmRzKCk6IG51bWJlcnxudWxsIHtcclxuICAgIHJldHVybiB0aGlzLl91cGxvYWRDaHVua1NpemVTZWNvbmRzO1xyXG4gIH1cclxuXHJcbiAgc2V0IHVwbG9hZENodW5rU2l6ZVNlY29uZHModmFsdWU6IG51bWJlcnxudWxsKSB7XHJcbiAgICBsZXQgb2xkVmFsdWU9dGhpcy51cGxvYWRDaHVua1NpemVTZWNvbmRzO1xyXG4gICAgdGhpcy5fdXBsb2FkQ2h1bmtTaXplU2Vjb25kcyA9IHZhbHVlO1xyXG4gICAgaWYodmFsdWUhPT1vbGRWYWx1ZSl7XHJcbiAgICAgIHRoaXMuY29uZmlndXJlU3RyZWFtQ2FwdHVyZVN0cmVhbSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJvdGVjdGVkIHVzZXJBZ2VudDpVc2VyQWdlbnQ7XHJcbiAgc3RhdHVzTXNnOiBzdHJpbmc9Jyc7XHJcbiAgc3RhdHVzQWxlcnRUeXBlITogc3RyaW5nO1xyXG4gIHN0YXR1c1dhaXRpbmc6IGJvb2xlYW49ZmFsc2U7XHJcbiAgcmVhZG9ubHk9ZmFsc2U7XHJcbiAgcHJvdGVjdGVkIHJmVXVpZDpzdHJpbmd8bnVsbD1udWxsO1xyXG4gIHByb2Nlc3NpbmdSZWNvcmRpbmc9ZmFsc2U7XHJcbiAgYWM6IEF1ZGlvQ2FwdHVyZXxudWxsPW51bGw7XHJcblxyXG4gIHByb3RlY3RlZCBfd2FrZUxvY2s6Ym9vbGVhbj1mYWxzZTtcclxuICAvLyBQcm9wZXJ0eSBhdWRpb0RldmljZXMgZnJvbSBwcm9qZWN0IGNvbmZpZzogbGlzdCBvZiBuYW1lcyBvZiBhbGxvd2VkIGF1ZGlvIGRldmljZXMuXHJcbiAgcHJvdGVjdGVkIF9hdWRpb0RldmljZXM6IEFycmF5PEF1ZGlvRGV2aWNlPiB8IG51bGx8IHVuZGVmaW5lZDtcclxuICBwcm90ZWN0ZWQgX3NlbGVjdGVkRGV2aWNlSWQ6c3RyaW5nfHVuZGVmaW5lZD11bmRlZmluZWQ7XHJcbiAgcHJvdGVjdGVkIHNlbENhcHR1cmVEZXZpY2VJZDogQ29uc3RyYWluRE9NU3RyaW5nIHwgbnVsbDtcclxuICBwcm90ZWN0ZWQgX2NoYW5uZWxDb3VudCA9IDI7XHJcbiAgcHJvdGVjdGVkIF9hdXRvR2FpbkNvbnRyb2xDb25maWdzOiBBcnJheTxBdXRvR2FpbkNvbnRyb2xDb25maWc+IHwgbnVsbHwgdW5kZWZpbmVkO1xyXG4gIHByb3RlY3RlZCBfYWxsb3dFY2hvQ2FuY2VsbGF0aW9uOmJvb2xlYW49ZmFsc2U7XHJcblxyXG4gIF9zZXNzaW9uOiBTZXNzaW9ufG51bGw9bnVsbDtcclxuICBwcm90ZWN0ZWQgX3JlY29yZGluZ0ZpbGU6UmVjb3JkaW5nRmlsZXxudWxsPW51bGw7XHJcblxyXG4gIHRyYW5zcG9ydEFjdGlvbnM6IFRyYW5zcG9ydEFjdGlvbnM7XHJcbiAgcGxheVN0YXJ0QWN0aW9uOiBBY3Rpb248dm9pZD47XHJcblxyXG4gIHByb3RlY3RlZCBzdGFydGVkRGF0ZTpEYXRlfG51bGw9bnVsbDtcclxuXHJcbiAgdXBsb2FkUHJvZ3Jlc3M6IG51bWJlciA9IDEwMDtcclxuICB1cGxvYWRTdGF0dXM6IHN0cmluZyA9ICdvaydcclxuICBwcm90ZWN0ZWQgdXBsb2FkU2V0OlVwbG9hZFNldHxudWxsPW51bGw7XHJcblxyXG4gIGF1ZGlvU2lnbmFsQ29sbGFwc2VkID0gdHJ1ZTtcclxuXHJcbiAgcHJvdGVjdGVkIHN0cmVhbUxldmVsTWVhc3VyZTogU3RyZWFtTGV2ZWxNZWFzdXJlO1xyXG4gIHByb3RlY3RlZCBsZXZlbE1lYXN1cmU6IExldmVsTWVhc3VyZTtcclxuICBwZWFrTGV2ZWxJbkRiOm51bWJlcj1NSU5fREJfTEVWRUw7XHJcbiAgYXVkaW9Mb2FkZWQ6Ym9vbGVhbj1mYWxzZTtcclxuICBkaXNhYmxlQXVkaW9EZXRhaWxzOmJvb2xlYW49ZmFsc2U7XHJcbiAgcHJvdGVjdGVkIF9jb250cm9sQXVkaW9QbGF5ZXI6IEF1ZGlvUGxheWVyfG51bGw9bnVsbDtcclxuICBwdWJsaWMgZGlzcGxheUF1ZGlvQ2xpcDogQXVkaW9DbGlwIHwgbnVsbD1udWxsO1xyXG4gIHByb3RlY3RlZCBhdWRpb0ZldGNoU3Vic2NyaXB0aW9uOlN1YnNjcmlwdGlvbnxudWxsPW51bGw7XHJcblxyXG4gIGxpdmVMZXZlbERpc3BsYXlTdGF0ZTpMaXZlTGV2ZWxTdGF0ZT1MaXZlTGV2ZWxTdGF0ZS5SRUFEWTtcclxuICBrZWVwTGl2ZUxldmVsOmJvb2xlYW49ZmFsc2U7XHJcbiAgcHJpdmF0ZSBjYWxjQnVmZmVySW5mb3NTdWJzY3I6U3Vic2NyaXB0aW9ufG51bGw9bnVsbDtcclxuXHJcbiAgcHJvdGVjdGVkIGRlc3Ryb3llZD1mYWxzZTtcclxuXHJcbiAgcHJvdGVjdGVkIG5hdmlnYXRpb25EaXNhYmxlZD10cnVlO1xyXG5cclxuICBwcm90ZWN0ZWQgX3VwbG9hZENodW5rU2l6ZVNlY29uZHM6bnVtYmVyfG51bGw9bnVsbDtcclxuICAvLz1CYXNpY1JlY29yZGVyLkRFRkFVTFRfQ0hVTktfU0laRV9TRUNPTkRTO1xyXG5cclxuICAvLyBEZWZhdWx0OiBDb250aW51b3VzIEhUTUw1IEF1ZGlvIEFQSSBBdWRpb0J1ZmZlciwgbm8gY2h1bmtlZCB1cGxvYWRcclxuICBwcm90ZWN0ZWQgX2NsaWVudEF1ZGlvU3RvcmFnZVR5cGU6QXVkaW9TdG9yYWdlVHlwZT1BdWRpb1N0b3JhZ2VUeXBlLk1FTV9FTlRJUkU7XHJcblxyXG4gIHByb3RlY3RlZCBfcGVyc2lzdGVudEF1ZGlvU3RvcmFnZVRhcmdldDpQZXJzaXN0ZW50QXVkaW9TdG9yYWdlVGFyZ2V0fG51bGw9bnVsbDtcclxuXHJcbiAgcHJvdGVjdGVkIF9zY3JlZW5Mb2NrZWQ9ZmFsc2U7XHJcblxyXG4gIHByaXZhdGUgd2FrZUxvY2tNYW5hZ2VyPzpXYWtlTG9ja01hbmFnZXI7XHJcblxyXG4gIHByb3RlY3RlZCBjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgYnBvOkJyZWFrcG9pbnRPYnNlcnZlcixwcm90ZWN0ZWQgY2hhbmdlRGV0ZWN0b3JSZWY6IENoYW5nZURldGVjdG9yUmVmLFxyXG4gICAgICAgICAgICAgICAgcHVibGljIGRpYWxvZzogTWF0RGlhbG9nLFxyXG4gICAgICAgICAgICAgICAgcHJvdGVjdGVkIHNlc3Npb25TZXJ2aWNlOlNlc3Npb25TZXJ2aWNlLFxyXG4gICAgICAgICAgICAgICAgcHJvdGVjdGVkIHVwbG9hZGVyOiBTcGVlY2hSZWNvcmRlclVwbG9hZGVyLFxyXG4gICAgICAgICAgICAgICAgQEluamVjdChTUEVFQ0hSRUNPUkRFUl9DT05GSUcpIHB1YmxpYyBjb25maWc/OiBTcGVlY2hSZWNvcmRlckNvbmZpZykge1xyXG4gICAgc3VwZXIoYnBvKTtcclxuICAgIHRoaXMudXNlckFnZW50PVVzZXJBZ2VudEJ1aWxkZXIudXNlckFnZW50KCk7XHJcbiAgICBjb25zdCBkZXRQZm09dGhpcy51c2VyQWdlbnQuZGV0ZWN0ZWRQbGF0Zm9ybTtcclxuICAgIGlmKGRldFBmbSkge1xyXG4gICAgICBjb25zb2xlLmRlYnVnKFwiRGV0ZWN0ZWQgcGxhdGZvcm06IFwiICtkZXRQZm0pO1xyXG4gICAgfVxyXG4gICAgY29uc3QgZGV0QnI9dGhpcy51c2VyQWdlbnQuZGV0ZWN0ZWRCcm93c2VyO1xyXG4gICAgY29uc3QgZGV0QnJWZXJzPXRoaXMudXNlckFnZW50LmRldGVjdGVkQnJvd3NlclZlcnNpb247XHJcbiAgICBpZihkZXRCcikge1xyXG4gICAgICBsZXQgZGV0QnJWZXJzU3RyPShkZXRCclZlcnMpPycgJytkZXRCclZlcnM6Jyc7XHJcbiAgICAgIGNvbnNvbGUuZGVidWcoXCJEZXRlY3RlZCBicm93c2VyOiBcIiArZGV0QnIrZGV0QnJWZXJzU3RyKTtcclxuICAgIH1cclxuICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucyA9IG5ldyBUcmFuc3BvcnRBY3Rpb25zKCk7XHJcbiAgICB0aGlzLnBsYXlTdGFydEFjdGlvbiA9IG5ldyBBY3Rpb24oJ1BsYXknKTtcclxuICAgIHRoaXMubGV2ZWxNZWFzdXJlID0gbmV3IExldmVsTWVhc3VyZSgpO1xyXG4gICAgdGhpcy5zdHJlYW1MZXZlbE1lYXN1cmUgPSBuZXcgU3RyZWFtTGV2ZWxNZWFzdXJlKCk7XHJcbiAgICB0aGlzLnNlbENhcHR1cmVEZXZpY2VJZCA9IG51bGw7XHJcbiAgfVxyXG5cclxuICBnZXQgd2FrZUxvY2soKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gdGhpcy5fd2FrZUxvY2s7XHJcbiAgfVxyXG5cclxuICBzZXQgd2FrZUxvY2sodmFsdWU6IGJvb2xlYW4pIHtcclxuICAgIHRoaXMuX3dha2VMb2NrID0gdmFsdWU7XHJcbiAgfVxyXG5cclxuICBlbmFibGVXYWtlTG9ja0NvbmQoKXtcclxuICAgIGlmKHRoaXMud2FrZUxvY2s9PT10cnVlKSB7XHJcbiAgICAgIGlmKCF0aGlzLndha2VMb2NrTWFuYWdlcil7XHJcbiAgICAgICAgdGhpcy53YWtlTG9ja01hbmFnZXI9bmV3IFdha2VMb2NrTWFuYWdlcigpO1xyXG4gICAgICAgIHRoaXMud2FrZUxvY2tNYW5hZ2VyLmJlaGF2aW9yU3ViamVjdC5zdWJzY3JpYmUoe1xyXG4gICAgICAgICAgICBuZXh0OiAodikgPT4ge1xyXG4gICAgICAgICAgICAgIHRoaXMuX3NjcmVlbkxvY2tlZCA9IHY7XHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIGVycm9yOiAoZXJyKSA9PiB7XHJcbiAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIldha2UgbG9jayBlcnJvciFcIilcclxuICAgICAgICAgICAgICB0aGlzLl9zY3JlZW5Mb2NrZWQgPSBmYWxzZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgICAgdGhpcy53YWtlTG9ja01hbmFnZXIuZW5hYmxlV2FrZUxvY2soKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGRpc2FibGVXYWtlTG9ja0NvbmQoKXtcclxuICAgIHRoaXMud2FrZUxvY2tNYW5hZ2VyPy5kaXNhYmxlV2FrZUxvY2soKTtcclxuICB9XHJcblxyXG4gIGdldCBzY3JlZW5Mb2NrZWQoKXtcclxuICAgIHJldHVybiB0aGlzLl9zY3JlZW5Mb2NrZWQ7XHJcbiAgfVxyXG5cclxuICBzZXQgYXVkaW9EZXZpY2VzKGF1ZGlvRGV2aWNlczogQXJyYXk8QXVkaW9EZXZpY2U+IHwgbnVsbCB8IHVuZGVmaW5lZCkge1xyXG4gICAgdGhpcy5fYXVkaW9EZXZpY2VzID0gYXVkaW9EZXZpY2VzO1xyXG4gIH1cclxuXHJcbiAgc2V0IGF1dG9HYWluQ29udHJvbENvbmZpZ3MoYXV0b0dhaW5Db250cm9sQ29uZmlnczogQXJyYXk8QXV0b0dhaW5Db250cm9sQ29uZmlnPnxudWxsfHVuZGVmaW5lZCl7XHJcbiAgICB0aGlzLl9hdXRvR2FpbkNvbnRyb2xDb25maWdzPWF1dG9HYWluQ29udHJvbENvbmZpZ3M7XHJcbiAgfVxyXG5cclxuICBzZXQgY2hhbm5lbENvdW50KGNoYW5uZWxDb3VudDogbnVtYmVyKSB7XHJcbiAgICB0aGlzLl9jaGFubmVsQ291bnQgPSBjaGFubmVsQ291bnQ7XHJcbiAgfVxyXG5cclxuICBzZXQgc2Vzc2lvbihzZXNzaW9uOiBTZXNzaW9ufG51bGwpIHtcclxuICAgIHRoaXMuX3Nlc3Npb24gPSBzZXNzaW9uO1xyXG4gIH1cclxuXHJcbiAgZ2V0IHNlc3Npb24oKTpTZXNzaW9ufG51bGx7XHJcbiAgICByZXR1cm4gdGhpcy5fc2Vzc2lvbjtcclxuICB9XHJcblxyXG4gIGVuYWJsZVN0YXJ0VXNlckdlc3R1cmUoKSB7XHJcbiAgICB0aGlzLnN0YXR1c0FsZXJ0VHlwZSA9ICdpbmZvJztcclxuICAgIHRoaXMuc3RhdHVzTXNnID0gJ1JlYWR5Lic7XHJcbiAgfVxyXG5cclxuICBjb25maWd1cmVTdHJlYW1DYXB0dXJlU3RyZWFtKCkge1xyXG4gICAgbGV0IG91dFN0cmVhbTtcclxuXHJcbiAgICBpZiAoQXVkaW9TdG9yYWdlVHlwZS5NRU1fRU5USVJFIT09dGhpcy5fY2xpZW50QXVkaW9TdG9yYWdlVHlwZSB8fCB0aGlzLnVwbG9hZENodW5rU2l6ZVNlY29uZHMpIHtcclxuICAgICAgaWYoIXRoaXMudXBsb2FkQ2h1bmtTaXplU2Vjb25kcyl7XHJcbiAgICAgICAgdGhpcy51cGxvYWRDaHVua1NpemVTZWNvbmRzPUJhc2ljUmVjb3JkZXIuREVGQVVMVF9DSFVOS19TSVpFX1NFQ09ORFM7XHJcbiAgICAgIH1cclxuICAgICAgLy8gTXVsdGlwbHkgdGhlIGNhcHR1cmUgc3RyZWFtIHRvLi4uXHJcbiAgICAgIGxldCBzYXNtID0gbmV3IFNlcXVlbmNlQXVkaW9GbG9hdDMyT3V0U3RyZWFtTXVsdGlwbGllcigpO1xyXG5cclxuICAgICAgLy8gLi4udXBsb2FkIGF1ZGlvIGRhdGEgaW4gY2h1bmtzLi4uXHJcbiAgICAgIGxldCBjaE1uZyA9IG5ldyBDaHVua01hbmFnZXIodGhpcyk7ICAvLyBUaGUgY2h1bmsgbWFuYWdlciBjb25uZWN0cyB0aGUgY2h1bmtlZCBhdWRpbyBzdHJlYW0gdG8gdGhpcyBjbGFzcyB0byB1cGxvYWQgdGhlIGNodW5rc1xyXG4gICAgICBsZXQgY2hPc1VwbG9hZCA9IG5ldyBTZXF1ZW5jZUF1ZGlvRmxvYXQzMkNodW5rZXJPdXRTdHJlYW0oY2hNbmcsIHRoaXMudXBsb2FkQ2h1bmtTaXplU2Vjb25kcyk7IC8vIFRoZSBhdWRpbyBzdHJlYW0gY2h1bmtlciBpdHNlbGZcclxuICAgICAgc2FzbS5zZXF1ZW5jZUF1ZGlvRmxvYXQzMk91dFN0cmVhbXMucHVzaChjaE9zVXBsb2FkKTtcclxuXHJcbiAgICAgIC8vIC4uLmFuZCB0byBtZWFzdXJlIHRoZSBsZXZlbFxyXG4gICAgICBsZXQgY2hPc0x2bE1lYXMgPSBuZXcgU2VxdWVuY2VBdWRpb0Zsb2F0MzJDaHVua2VyT3V0U3RyZWFtKHRoaXMuc3RyZWFtTGV2ZWxNZWFzdXJlLCBMRVZFTF9CQVJfSU5URVJWQUxMX1NFQ09ORFMpXHJcbiAgICAgIHNhc20uc2VxdWVuY2VBdWRpb0Zsb2F0MzJPdXRTdHJlYW1zLnB1c2goY2hPc0x2bE1lYXMpO1xyXG5cclxuICAgICAgb3V0U3RyZWFtID0gc2FzbTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIG91dFN0cmVhbSA9IG5ldyBTZXF1ZW5jZUF1ZGlvRmxvYXQzMkNodW5rZXJPdXRTdHJlYW0odGhpcy5zdHJlYW1MZXZlbE1lYXN1cmUsIExFVkVMX0JBUl9JTlRFUlZBTExfU0VDT05EUyk7XHJcbiAgICB9XHJcbiAgICBpZih0aGlzLmFjKSB7XHJcbiAgICAgIHRoaXMuYWMubWF4QXV0b05ldE1lbVN0b3JlU2FtcGxlcz10aGlzLl9tYXhBdXRvTmV0TWVtU3RvcmVTYW1wbGVzO1xyXG4gICAgICB0aGlzLmFjLmF1ZGlvU3RvcmFnZVR5cGU9dGhpcy5fY2xpZW50QXVkaW9TdG9yYWdlVHlwZTtcclxuICAgICAgdGhpcy5hYy5hdWRpb091dFN0cmVhbSA9IG91dFN0cmVhbTtcclxuICAgICAgaWYoQXVkaW9TdG9yYWdlVHlwZS5EQl9DSFVOS0VEPT09dGhpcy5fY2xpZW50QXVkaW9TdG9yYWdlVHlwZSAmJiB0aGlzLl9wZXJzaXN0ZW50QXVkaW9TdG9yYWdlVGFyZ2V0IT09bnVsbCkge1xyXG4gICAgICAgIHRoaXMuYWMucGVyc2lzdGVudEF1ZGlvU3RvcmFnZVRhcmdldCA9IHRoaXMuX3BlcnNpc3RlbnRBdWRpb1N0b3JhZ2VUYXJnZXQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG5cclxuICBzaG93UmVjb3JkaW5nKCkge1xyXG4gICAgaWYodGhpcy5fY29udHJvbEF1ZGlvUGxheWVyKSB7XHJcbiAgICAgIHRoaXMuX2NvbnRyb2xBdWRpb1BsYXllci5zdG9wKCk7XHJcbiAgICB9XHJcbiAgICBpZih0aGlzLmNhbGNCdWZmZXJJbmZvc1N1YnNjcil7XHJcbiAgICAgIHRoaXMuY2FsY0J1ZmZlckluZm9zU3Vic2NyLnVuc3Vic2NyaWJlKCk7XHJcbiAgICB9XHJcbiAgICBpZiAodGhpcy5kaXNwbGF5QXVkaW9DbGlwKSB7XHJcbiAgICAgIGxldCBkYXA9dGhpcy5kaXNwbGF5QXVkaW9DbGlwO1xyXG4gICAgICBsZXQgYWRoPWRhcC5hdWRpb0RhdGFIb2xkZXI7XHJcbiAgICAgIGlmKGFkaCl7XHJcbiAgICAgICAgaWYoIXRoaXMua2VlcExpdmVMZXZlbCkge1xyXG4gICAgICAgICAgdGhpcy5saXZlTGV2ZWxEaXNwbGF5U3RhdGUgPSBMaXZlTGV2ZWxTdGF0ZS5MT0FESU5HO1xyXG4gICAgICAgIH1cclxuICAgICAgICBhZGguYWRkT25SZWFkeUxpc3RlbmVyKCgpPT57XHJcbiAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJBdWRpbyBkYXRhIGhvbGRlciByZWFkeS4gRW5hYmxlIHBsYXliYWNrLiBBdWRpbyBsb2FkZWQgdHJ1ZS5cIilcclxuICAgICAgICAgIGlmKCF0aGlzLmtlZXBMaXZlTGV2ZWwpIHtcclxuICAgICAgICAgICAgdGhpcy5saXZlTGV2ZWxEaXNwbGF5U3RhdGUgPSBMaXZlTGV2ZWxTdGF0ZS5SRU5ERVJJTkc7XHJcbiAgICAgICAgICAgIHRoaXMuY2FsY0J1ZmZlckluZm9zU3Vic2NyID0gdGhpcy5sZXZlbE1lYXN1cmUuY2FsY0J1ZmZlckxldmVsSW5mb3MoYWRoLCBMRVZFTF9CQVJfSU5URVJWQUxMX1NFQ09ORFMpLnN1YnNjcmliZSgobGV2ZWxJbmZvcykgPT4ge1xyXG4gICAgICAgICAgICAgIC8vY29uc29sZS5kZWJ1ZyhcIkxldmVsIGluZm9zOiBsZXZlbEluZm9zIG51bWJlciBzaXplOiBcIitsZXZlbEluZm9zLm51bWJlclNpemUoKSk7XHJcbiAgICAgICAgICAgICAgZGFwLmxldmVsSW5mb3MgPSBsZXZlbEluZm9zO1xyXG4gICAgICAgICAgICAgIHRoaXMubGl2ZUxldmVsRGlzcGxheVN0YXRlID0gTGl2ZUxldmVsU3RhdGUuUkVBRFk7XHJcbiAgICAgICAgICAgICAgdGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5kZXRlY3RDaGFuZ2VzKCk7XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgdGhpcy5wbGF5U3RhcnRBY3Rpb24uZGlzYWJsZWQgPSBmYWxzZTtcclxuICAgICAgICAgIHRoaXMuYXVkaW9Mb2FkZWQ9dHJ1ZTtcclxuICAgICAgICAgIHRoaXMuY2hhbmdlRGV0ZWN0b3JSZWYuZGV0ZWN0Q2hhbmdlcygpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIC8vY29uc29sZS5kZWJ1ZyhcIkF1ZGlvIGRhdGEgaG9sZGVyIGFkZGVkIG9uUmVhZHkuXCIpXHJcbiAgICAgIH1cclxuICAgICAgLy90aGlzLnBsYXlTdGFydEFjdGlvbi5kaXNhYmxlZCA9IGZhbHNlO1xyXG4gICAgfSBlbHNlIHtcclxuXHJcbiAgICAgIHRoaXMucGxheVN0YXJ0QWN0aW9uLmRpc2FibGVkID0gdHJ1ZTtcclxuICAgICAgdGhpcy5hdWRpb0xvYWRlZD1mYWxzZTtcclxuICAgICAgLy8gQ29sbGFwc2UgYXVkaW8gc2lnbmFsIGRpc3BsYXkgaWYgb3BlblxyXG4gICAgICBpZiAoIXRoaXMuYXVkaW9TaWduYWxDb2xsYXBzZWQpIHtcclxuICAgICAgICB0aGlzLmF1ZGlvU2lnbmFsQ29sbGFwc2VkID0gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgdGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5kZXRlY3RDaGFuZ2VzKCk7XHJcbiAgfVxyXG5cclxuICBzdGFydCgpIHtcclxuICAgIHRoaXMuc3RhdHVzQWxlcnRUeXBlID0gJ2luZm8nO1xyXG4gICAgdGhpcy5zdGF0dXNNc2cgPSAnU3RhcnRpbmcgc2Vzc2lvbi4uLic7XHJcbiAgICB0aGlzLnN0YXR1c1dhaXRpbmc9ZmFsc2U7XHJcbiAgICBpZih0aGlzLl9zZXNzaW9uKSB7XHJcbiAgICAgIGlmICh0aGlzLl9zZXNzaW9uLnNlYWxlZCkge1xyXG4gICAgICAgIHRoaXMucmVhZG9ubHkgPSB0cnVlXHJcbiAgICAgICAgdGhpcy5zdGF0dXNNc2cgPSAnU2Vzc2lvbiBzZWFsZWQhJztcclxuICAgICAgICAvL2xldCBkaWFsb2dSZWYgPSB0aGlzLmRpYWxvZy5vcGVuKFNlc3Npb25TZWFsZWREaWFsb2csIHt9KTtcclxuICAgICAgICB0aGlzLmRpYWxvZy5vcGVuKE1lc3NhZ2VEaWFsb2csIHtcclxuICAgICAgICAgIGRhdGE6IHtcclxuICAgICAgICAgICAgdHlwZTogJ2Vycm9yJyxcclxuICAgICAgICAgICAgdGl0bGU6ICdFcnJvcicsXHJcbiAgICAgICAgICAgIG1zZzogXCJUaGlzIHNlc3Npb24gaXMgc2VhbGVkLiBSZWNvcmRpbmdzIGNhbm5vdCBiZSBhZGRlZCBhbnltb3JlLlwiLFxyXG4gICAgICAgICAgICBhZHZpY2U6ICdQbGVhc2UgYXNrIHlvdXIgZXhwZXJpbWVudGVyIHdoYXQgdG8gZG8gKGUuZyBzdGFydCBhIG5ldyBzZXNzaW9uKS4nLFxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxldCBib2R5OiBhbnkgPSB7fTtcclxuICAgICAgICBpZiAodGhpcy5fc2Vzc2lvbi5zdGF0dXMgPT09IFwiQ1JFQVRFRFwiKSB7XHJcbiAgICAgICAgICB0aGlzLl9zZXNzaW9uLnN0YXR1cyA9IFwiTE9BREVEXCI7XHJcbiAgICAgICAgICBib2R5LnN0YXR1cyA9IHRoaXMuX3Nlc3Npb24uc3RhdHVzO1xyXG4gICAgICAgICAgaWYgKCF0aGlzLl9zZXNzaW9uLmxvYWRlZERhdGUpIHtcclxuICAgICAgICAgICAgdGhpcy5fc2Vzc2lvbi5sb2FkZWREYXRlID0gbmV3IERhdGUoKTtcclxuICAgICAgICAgICAgYm9keS5sb2FkZWREYXRlID0gdGhpcy5fc2Vzc2lvbi5sb2FkZWREYXRlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aGlzLl9zZXNzaW9uLnJlc3RhcnRlZERhdGUgPSBuZXcgRGF0ZSgpO1xyXG4gICAgICAgICAgYm9keS5yZXN0YXJ0ZWREYXRlID0gdGhpcy5fc2Vzc2lvbi5yZXN0YXJ0ZWREYXRlO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLnNlc3Npb25TZXJ2aWNlLnBhdGNoU2Vzc2lvbk9ic2VydmVyKHRoaXMuX3Nlc3Npb24sIGJvZHkpLnN1YnNjcmliZSgpXHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayBicm93c2VyIGNvbXBhdGliaWxpdHlcclxuICAgIGlmKHRoaXMudXNlckFnZW50LmRldGVjdGVkQnJvd3Nlcj09PUJyb3dzZXIuU2FmYXJpICYmIHRoaXMuX2NoYW5uZWxDb3VudD4xKXtcclxuICAgICAgbGV0IGVNc2c9XCJFcnJvcjogU2FmYXJpIGJyb3dzZXIgZG9lcyBub3Qgc3VwcG9ydCBzdGVyZW8gcmVjb3JkaW5ncy5cIjtcclxuICAgICAgY29uc29sZS5lcnJvcihlTXNnKTtcclxuICAgICAgdGhpcy5kaWFsb2cub3BlbihNZXNzYWdlRGlhbG9nLCB7XHJcbiAgICAgICAgZGF0YToge1xyXG4gICAgICAgICAgdHlwZTogJ2Vycm9yJyxcclxuICAgICAgICAgIHRpdGxlOiAnQnJvd3NlciBub3Qgc3VwcG9ydGVkJyxcclxuICAgICAgICAgIG1zZzogZU1zZyxcclxuICAgICAgICAgIGFkdmljZTogXCJQbGVhc2UgdXNlIGEgc3VwcG9ydGVkIGJyb3dzZXIsIGUuZy4gTW96aWxsYSBGaXJlZm94LlwiXHJcbiAgICAgICAgfVxyXG4gICAgICB9KVxyXG4gICAgfVxyXG5cclxuICAgIC8vY29uc29sZS5sb2coXCJTZXNzaW9uIElEOiBcIit0aGlzLl9zZXNzaW9uLnNlc3Npb24rIFwiIHN0YXR1czogXCIrdGhpcy5fc2Vzc2lvbi5zdGF0dXMpXHJcbiAgICB0aGlzLl9zZWxlY3RlZERldmljZUlkPXVuZGVmaW5lZDtcclxuXHJcbiAgICBpZiAoIXRoaXMucmVhZG9ubHkgJiYgdGhpcy5hYyAmJiAoRk9SQ0VfUkVRVUVTVF9BVURJT19QRVJNSVNTSU9OUyB8fCAodGhpcy5fYXVkaW9EZXZpY2VzICYmIHRoaXMuX2F1ZGlvRGV2aWNlcy5sZW5ndGggPiAwKSkpIHtcclxuICAgICAgdGhpcy5zdGF0dXNNc2cgPSAnUmVxdWVzdGluZyBhdWRpbyBwZXJtaXNzaW9ucy4uLic7XHJcbiAgICAgIHRoaXMuc3RhdHVzQWxlcnRUeXBlID0gJ2luZm8nO1xyXG5cclxuICAgICAgdGhpcy5hYy5kZXZpY2VJbmZvcygobWRpcykgPT4ge1xyXG4gICAgICAgIGxldCBhdWRpb0NhcHR1cmVEZXZpY2VBdmFpbDogYm9vbGVhbiA9IGZhbHNlO1xyXG4gICAgICAgIGxldCBhdWRpb1BsYXlEZXZpY2VBdmFpbDogYm9vbGVhbiA9IGZhbHNlO1xyXG4gICAgICAgIGlmIChtZGlzKSB7XHJcbiAgICAgICAgICBpZih0aGlzLmFjKSB7XHJcbiAgICAgICAgICAgIHRoaXMuYWMucHJpbnREZXZpY2VzKG1kaXMpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgaWYgKG1kaXMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICBmb3IgKGxldCBtZGlpID0gMDsgbWRpaSA8IG1kaXMubGVuZ3RoOyBtZGlpKyspIHtcclxuICAgICAgICAgICAgICBsZXQgbWRpID0gbWRpc1ttZGlpXTtcclxuICAgICAgICAgICAgICBsZXQga2luZD1tZGkua2luZDtcclxuICAgICAgICAgICAgICBpZihraW5kID09PSBcImF1ZGlvaW5wdXRcIil7XHJcbiAgICAgICAgICAgICAgICBhdWRpb0NhcHR1cmVEZXZpY2VBdmFpbD10cnVlO1xyXG4gICAgICAgICAgICAgIH1lbHNlIGlmKGtpbmQ9PT0gXCJhdWRpb291dHB1dFwiKXtcclxuICAgICAgICAgICAgICAgIGF1ZGlvUGxheURldmljZUF2YWlsPXRydWU7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgaWYgKHRoaXMuX3Nlc3Npb24gJiYgdGhpcy5fc2Vzc2lvbi50eXBlICE9PSAnVEVTVF9ERUZfQScgJiYgdGhpcy5fYXVkaW9EZXZpY2VzICYmIHRoaXMuX2F1ZGlvRGV2aWNlcy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICAgIGxldCBmZGk6IE1lZGlhRGV2aWNlSW5mbyB8IG51bGwgPSBudWxsO1xyXG4gICAgICAgICAgICBmb3IgKGxldCBhZEkgPSAwOyBhZEkgPCB0aGlzLl9hdWRpb0RldmljZXMubGVuZ3RoOyBhZEkrKykge1xyXG4gICAgICAgICAgICAgIGxldCBhZCA9IHRoaXMuX2F1ZGlvRGV2aWNlc1thZEldO1xyXG4gICAgICAgICAgICAgIGlmIChhZC5wbGF5YmFjaykge1xyXG4gICAgICAgICAgICAgICAgLy8gcHJvamVjdCBhdWRpbyBkZXZpY2UgY29uZmlnIGZvciBwbGF5YmFjayBkZXZpY2VcclxuICAgICAgICAgICAgICAgIC8vIG5vdCB1c2VkIGZvciBub3dcclxuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICBmb3IgKGxldCBtZGlpID0gMDsgbWRpaSA8IG1kaXMubGVuZ3RoOyBtZGlpKyspIHtcclxuICAgICAgICAgICAgICAgIGxldCBtZGkgPSBtZGlzW21kaWldO1xyXG4gICAgICAgICAgICAgICAgbGV0IGtpbmQ9bWRpLmtpbmQ7XHJcbiAgICAgICAgICAgICAgICBpZihraW5kID09PSBcImF1ZGlvaW5wdXRcIil7XHJcbiAgICAgICAgICAgICAgICAgIGF1ZGlvQ2FwdHVyZURldmljZUF2YWlsPXRydWU7XHJcbiAgICAgICAgICAgICAgICB9ZWxzZSBpZihraW5kPT09IFwiYXVkaW9vdXRwdXRcIil7XHJcbiAgICAgICAgICAgICAgICAgIGF1ZGlvUGxheURldmljZUF2YWlsPXRydWU7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBpZiAoYWQucmVnZXgpIHtcclxuICAgICAgICAgICAgICAgICAgLy9jb25zb2xlLmxvZyhcIk1hdGNoPzogXFwnXCIrbWRpLmxhYmVsK1wiXFwnIFxcJ1wiK2FkLm5hbWUrXCJcXCdcIik7XHJcbiAgICAgICAgICAgICAgICAgIGlmIChtZGkubGFiZWwubWF0Y2goYWQubmFtZSkpIHtcclxuICAgICAgICAgICAgICAgICAgICBmZGkgPSBtZGk7XHJcbiAgICAgICAgICAgICAgICAgICAgLy9jb25zb2xlLmxvZyhcIk1hdGNoIVwiKTtcclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgaWYgKG1kaS5sYWJlbC50cmltKCkgPT09IGFkLm5hbWUudHJpbSgpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgZmRpID0gbWRpO1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBpZiAoZmRpKSB7XHJcbiAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICBpZiAoZmRpKSB7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGlmIChmZGkpIHtcclxuICAgICAgICAgICAgICAvLyBtYXRjaGluZyBkZXZpY2UgZm91bmRcclxuXHJcbiAgICAgICAgICAgICAgLy8gTm90IGFibGUgdG8gb3BlbiBkZXZpY2UgaGVyZSBzaW5jZSBDaHJvbWUgNzFcclxuICAgICAgICAgICAgICAvLyBDaHJvbWUgNzEgcmVxdWlyZXMgYSB1c2VyIGdlc3R1cmUgYmVmb3JlIHRoZSBBdWRpb0NvbnRleHQgY2FuIGJlIHJlc3VtZWRcclxuICAgICAgICAgICAgICAvLyBzZXNzaW9ubWFuYWdlci50czo3MTIgT3BlbiBzZXNzaW9uIHdpdGggZGVmYXVsdCBhdWRpbyBkZXZpY2UgZm9yIDEgY2hhbm5lbHNcclxuICAgICAgICAgICAgICAvLyBjYXB0dXJlLnRzOjEyOCBUaGUgQXVkaW9Db250ZXh0IHdhcyBub3QgYWxsb3dlZCB0byBzdGFydC4gSXQgbXVzdCBiZSByZXN1bWVkIChvciBjcmVhdGVkKSBhZnRlciBhIHVzZXIgZ2VzdHVyZSBvbiB0aGUgcGFnZS4gaHR0cHM6Ly9nb28uZ2wvN0s3V0x1XHJcbiAgICAgICAgICAgICAgLy8gcHVzaC4uL3Byb2plY3RzL3NwZWVjaHJlY29yZGVybmcvc3JjL2xpYi9hdWRpby9jYXB0dXJlL2NhcHR1cmUudHMuQXVkaW9DYXB0dXJlLm9wZW4gQCBjYXB0dXJlLnRzOjEyOFxyXG5cclxuICAgICAgICAgICAgICAvL3RoaXMuYWMub3Blbih0aGlzLl9jaGFubmVsQ291bnQsIGZkaS5kZXZpY2VJZCk7XHJcbiAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiU2V0IHNlbGVjdGVkIGF1ZGlvIGRldmljZTogXFwnXCIgKyBmZGkubGFiZWwgKyBcIlxcJyBJZDogXFwnXCIgKyBmZGkuZGV2aWNlSWQgKyBcIlxcJ1wiKTtcclxuICAgICAgICAgICAgICB0aGlzLl9zZWxlY3RlZERldmljZUlkID0gZmRpLmRldmljZUlkO1xyXG5cclxuICAgICAgICAgICAgICB0aGlzLmVuYWJsZVN0YXJ0VXNlckdlc3R1cmUoKVxyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIC8vIGRldmljZSBub3QgZm91bmRcclxuICAgICAgICAgICAgICB0aGlzLnN0YXR1c01zZyA9ICdFUlJPUjogUmVxdWlyZWQgYXVkaW8gZGV2aWNlIG5vdCBhdmFpbGFibGUhJztcclxuICAgICAgICAgICAgICB0aGlzLnN0YXR1c0FsZXJ0VHlwZSA9ICdlcnJvcic7XHJcbiAgICAgICAgICAgICAgdGhpcy5yZWFkb25seSA9IHRydWU7XHJcblxyXG4gICAgICAgICAgICAgIHRoaXMuZGlhbG9nLm9wZW4oTWVzc2FnZURpYWxvZywge1xyXG4gICAgICAgICAgICAgICAgZGF0YToge1xyXG4gICAgICAgICAgICAgICAgICB0eXBlOiAnZXJyb3InLFxyXG4gICAgICAgICAgICAgICAgICB0aXRsZTogJ1JlcXVpcmVkIGF1ZGlvIGRldmljZScsXHJcbiAgICAgICAgICAgICAgICAgIG1zZzogXCJSZXF1aXJlZCBhdWRpbyBkZXZpY2Ugbm90IGZvdW5kXCIsXHJcbiAgICAgICAgICAgICAgICAgIGFkdmljZTogXCJQbGVhc2UgY29ubmVjdCBhIHN1aXRhYmxlIGF1ZGlvIGRldmljZSBmb3IgdGhpcyBwcm9qZWN0IGFuZCByZXRyeSAocHJlc3MgdGhlIGJyb3dzZXIgcmVsb2FkIGJ1dHRvbikuXCJcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9ZWxzZXtcclxuICAgICAgICAgICAgaWYoIWF1ZGlvQ2FwdHVyZURldmljZUF2YWlsICYmICFhdWRpb1BsYXlEZXZpY2VBdmFpbCl7XHJcbiAgICAgICAgICAgICAgLy8gbm8gZGV2aWNlIGZvdW5kXHJcbiAgICAgICAgICAgICAgdGhpcy5zdGF0dXNNc2cgPSAnRVJST1I6IE5vIGF1ZGlvIGRldmljZSBhdmFpbGFibGUhJztcclxuICAgICAgICAgICAgICB0aGlzLnN0YXR1c0FsZXJ0VHlwZSA9ICd3YXJuJztcclxuICAgICAgICAgICAgICAvL3RoaXMucmVhZG9ubHkgPSB0cnVlO1xyXG5cclxuICAgICAgICAgICAgICB0aGlzLmRpYWxvZy5vcGVuKE1lc3NhZ2VEaWFsb2csIHtcclxuICAgICAgICAgICAgICAgIGRhdGE6IHtcclxuICAgICAgICAgICAgICAgICAgdHlwZTogJ3dhcm4nLFxyXG4gICAgICAgICAgICAgICAgICB0aXRsZTogJ05vIGF1ZGlvIGRldmljZScsXHJcbiAgICAgICAgICAgICAgICAgIG1zZzogXCJObyBhdWRpbyBkZXZpY2UgZm91bmRcIixcclxuICAgICAgICAgICAgICAgICAgYWR2aWNlOiBcIlBsZWFzZSBjb25uZWN0IGFuIGF1ZGlvIGRldmljZSBhbmQgcmV0cnkgKHByZXNzIHRoZSBicm93c2VyIHJlbG9hZCBidXR0b24pIG9yIHRyeSB0byBjb250aW51ZSBhbnl3YXkuXCJcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICB9ZWxzZSB7XHJcbiAgICAgICAgICAgICAgaWYgKCF0aGlzLnJlYWRvbmx5ICYmICFhdWRpb0NhcHR1cmVEZXZpY2VBdmFpbCkge1xyXG4gICAgICAgICAgICAgICAgLy8gbm8gZGV2aWNlIGZvdW5kXHJcbiAgICAgICAgICAgICAgICB0aGlzLnN0YXR1c01zZyA9ICdXQVJOSU5HOiBObyBhdWRpbyBjYXB0dXJlIGRldmljZSBhdmFpbGFibGUhJztcclxuICAgICAgICAgICAgICAgIHRoaXMuc3RhdHVzQWxlcnRUeXBlID0gJ3dhcm5pbmcnO1xyXG4gICAgICAgICAgICAgICAgLy90aGlzLnJlYWRvbmx5ID0gdHJ1ZTtcclxuXHJcbiAgICAgICAgICAgICAgICB0aGlzLmRpYWxvZy5vcGVuKE1lc3NhZ2VEaWFsb2csIHtcclxuICAgICAgICAgICAgICAgICAgZGF0YToge1xyXG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICd3YXJuaW5nJyxcclxuICAgICAgICAgICAgICAgICAgICB0aXRsZTogJ05vIGF1ZGlvIGNhcHR1cmUgZGV2aWNlJyxcclxuICAgICAgICAgICAgICAgICAgICBtc2c6IFwiTm8gYXVkaW8gY2FwdHVyZSBkZXZpY2UgZm91bmRcIixcclxuICAgICAgICAgICAgICAgICAgICBhZHZpY2U6IFwiUGxlYXNlIGNvbm5lY3QgYW4gYXVkaW8gY2FwdHVyZSBkZXZpY2UgYW5kIHJldHJ5IChwcmVzcyB0aGUgYnJvd3NlciByZWxvYWQgYnV0dG9uKSBvciB0cnkgdG8gY29udGludWUgYW55d2F5LlwiXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIC8vIFNhZmFyaSBkb2VzIG5vdCBsaXN0IHBsYXliYWNrIGRldmljZXNcclxuICAgICAgICAgICAgICBpZiAoIWF1ZGlvUGxheURldmljZUF2YWlsKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBGaXJlZm94IGRvZXMgbm90IGVudW1lcmF0ZSBhdWRpb291dHB1dCBkZXZpY2VzXHJcbiAgICAgICAgICAgICAgICAvLyBEbyBub3Qgc2hvdyB0aGlzIHdhcm5pbmcsIGJlY2F1c2UgaXQgd291bGQgYWx3YXlzIGFwcGVhciBvbiBGaXJlZm94XHJcbiAgICAgICAgICAgICAgICAvLyBXaGVuIGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTE0OTg1MTIgaXMgZml4ZWQgdGhlIHdhcm5pbmcgY2FuIGJlIGVuYWJsZWQgZm9yIEZpcmVmb3ggYXMgd2VsbFxyXG5cclxuICAgICAgICAgICAgICAgIC8vIEl0IGlzIGFscmVhZHkgaW1wbGVtbmV0ZWQgYnV0IGtlcHQgYmVoaW5kIGEgcHJlZmVyZW5jZSBzZXR0aW5nIGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTExNTI0MDFcclxuXHJcblxyXG4gICAgICAgICAgICAgICAgLy8gT3V0cHV0IGRldmljZXMgYXJlIGxpc3RlZCBpZiBhYm91dDpjb25maWcgbWVkaWEuc2V0c2lua2lkLmVuYWJsZWQ9dHJ1ZVxyXG4gICAgICAgICAgICAgICAgLy8gYnV0IGRlZmF1bHQgc2V0dGluZyBpcyBmYWxzZVxyXG5cclxuXHJcbiAgICAgICAgICAgICAgICAvLyBTYW1lIHByb2JsZW0gd2l0aCBTYWZhcmlcclxuXHJcbiAgICAgICAgICAgICAgICBpZiAoISh0aGlzLnVzZXJBZ2VudC5kZXRlY3RlZEJyb3dzZXI9PT1Ccm93c2VyLlNhZmFyaSB8fCB0aGlzLnVzZXJBZ2VudC5kZXRlY3RlZEJyb3dzZXI9PT1Ccm93c2VyLkZpcmVmb3gpKSB7XHJcbiAgICAgICAgICAgICAgICAgIC8vIG5vIGRldmljZSBmb3VuZFxyXG4gICAgICAgICAgICAgICAgICB0aGlzLnN0YXR1c01zZyA9ICdXQVJOSU5HOiBObyBhdWRpbyBwbGF5YmFjayBkZXZpY2UgYXZhaWxhYmxlISc7XHJcbiAgICAgICAgICAgICAgICAgIHRoaXMuc3RhdHVzQWxlcnRUeXBlID0gJ3dhcm4nO1xyXG4gICAgICAgICAgICAgICAgICAvL3RoaXMucmVhZG9ubHkgPSB0cnVlO1xyXG5cclxuICAgICAgICAgICAgICAgICAgdGhpcy5kaWFsb2cub3BlbihNZXNzYWdlRGlhbG9nLCB7XHJcbiAgICAgICAgICAgICAgICAgICAgZGF0YToge1xyXG4gICAgICAgICAgICAgICAgICAgICAgdHlwZTogJ3dhcm4nLFxyXG4gICAgICAgICAgICAgICAgICAgICAgdGl0bGU6ICdObyBhdWRpbyBwbGF5YmFjayBkZXZpY2UnLFxyXG4gICAgICAgICAgICAgICAgICAgICAgbXNnOiBcIk5vIGF1ZGlvIHBsYXliYWNrIGRldmljZSBmb3VuZFwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgYWR2aWNlOiBcIlBsZWFzZSBjb25uZWN0IGFuIGF1ZGlvIHBsYXliYWNrIGRldmljZSBhbmQgcmV0cnkgKHByZXNzIHRoZSBicm93c2VyIHJlbG9hZCBidXR0b24pIG9yIHRyeSB0byBjb250aW51ZSBhbnl3YXkuXCJcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBOb3QgYWJsZSB0byBvcGVuIGRldmljZSBoZXJlIHNpbmNlIENocm9tZSA3MVxyXG4gICAgICAgICAgICAvLyBDaHJvbWUgNzEgcmVxdWlyZXMgYSB1c2VyIGdlc3R1cmUgYmVmb3JlIHRoZSBBdWRpb0NvbnRleHQgY2FuIGJlIHJlc3VtZWRcclxuICAgICAgICAgICAgLy8gc2Vzc2lvbm1hbmFnZXIudHM6NzEyIE9wZW4gc2Vzc2lvbiB3aXRoIGRlZmF1bHQgYXVkaW8gZGV2aWNlIGZvciAxIGNoYW5uZWxzXHJcbiAgICAgICAgICAgIC8vIGNhcHR1cmUudHM6MTI4IFRoZSBBdWRpb0NvbnRleHQgd2FzIG5vdCBhbGxvd2VkIHRvIHN0YXJ0LiBJdCBtdXN0IGJlIHJlc3VtZWQgKG9yIGNyZWF0ZWQpIGFmdGVyIGEgdXNlciBnZXN0dXJlIG9uIHRoZSBwYWdlLiBodHRwczovL2dvby5nbC83SzdXTHVcclxuICAgICAgICAgICAgLy8gcHVzaC4uL3Byb2plY3RzL3NwZWVjaHJlY29yZGVybmcvc3JjL2xpYi9hdWRpby9jYXB0dXJlL2NhcHR1cmUudHMuQXVkaW9DYXB0dXJlLm9wZW4gQCBjYXB0dXJlLnRzOjEyOFxyXG4gICAgICAgICAgICAvL2NvbnNvbGUubG9nKFwiT3BlbiBzZXNzaW9uIHdpdGggZGVmYXVsdCBhdWRpbyBkZXZpY2UgZm9yIFwiK3RoaXMuX2NoYW5uZWxDb3VudCtcIiBjaGFubmVsc1wiKTtcclxuICAgICAgICAgICAgLy90aGlzLmFjLm9wZW4odGhpcy5fY2hhbm5lbENvdW50KTtcclxuXHJcbiAgICAgICAgICAgIC8vIGVuYWJsZSBzdGFydCBnZXN0dXJlIGFueXdheVxyXG4gICAgICAgICAgICB0aGlzLmVuYWJsZVN0YXJ0VXNlckdlc3R1cmUoKVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgdGhpcy5zdGF0dXNNc2c9J1JlYWR5Lic7XHJcbiAgfVxyXG5cclxuICBzdGFydEl0ZW0oKSB7XHJcbiAgICB0aGlzLnJmVXVpZCA9IFVVSUQuZ2VuZXJhdGUoKTtcclxuICAgIGlmKHRoaXMuYWMpIHtcclxuICAgICAgdGhpcy5hYy5yZWNVVUlEID0gdGhpcy5yZlV1aWQ7XHJcbiAgICB9XHJcbiAgICB0aGlzLnN0YXJ0ZWREYXRlPW51bGw7XHJcbiAgICB0aGlzLmVuYWJsZVdha2VMb2NrQ29uZCgpO1xyXG4gICAgLy90aGlzLnJmVXVpZD1VVUlELmdlbmVyYXRlKCk7XHJcbiAgICB0aGlzLnVwbG9hZFNldD1udWxsO1xyXG4gICAgdGhpcy50cmFuc3BvcnRBY3Rpb25zLnN0YXJ0QWN0aW9uLmRpc2FibGVkID0gdHJ1ZTtcclxuICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucy5wYXVzZUFjdGlvbi5kaXNhYmxlZCA9IHRydWU7XHJcbiAgfVxyXG5cclxuICBwcm90ZWN0ZWQgc3RhcnRDYXB0dXJlKCkge1xyXG4gICAgaWYgKHRoaXMuYWMpIHtcclxuICAgICAgaWYgKCF0aGlzLmFjLm9wZW5lZCkge1xyXG4gICAgICAgIGlmICh0aGlzLl9zZWxlY3RlZERldmljZUlkKSB7XHJcbiAgICAgICAgICBjb25zb2xlLmxvZyhcIk9wZW4gc2Vzc2lvbiB3aXRoIGF1ZGlvIGRldmljZSBJZDogXFwnXCIgKyB0aGlzLl9zZWxlY3RlZERldmljZUlkICsgXCJcXCcgZm9yIFwiICsgdGhpcy5fY2hhbm5lbENvdW50ICsgXCIgY2hhbm5lbHNcIik7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGNvbnNvbGUubG9nKFwiT3BlbiBzZXNzaW9uIHdpdGggZGVmYXVsdCBhdWRpbyBkZXZpY2UgZm9yIFwiICsgdGhpcy5fY2hhbm5lbENvdW50ICsgXCIgY2hhbm5lbHNcIik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuYWMub3Blbih0aGlzLl9jaGFubmVsQ291bnQsIHRoaXMuX3NlbGVjdGVkRGV2aWNlSWQsIHRoaXMuX2F1dG9HYWluQ29udHJvbENvbmZpZ3MsdGhpcy5fYWxsb3dFY2hvQ2FuY2VsbGF0aW9uKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLmFjLnN0YXJ0KCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIG9wZW5lZCgpIHtcclxuICAgIGlmKHRoaXMuYWMpIHtcclxuICAgICAgdGhpcy5hYy5zdGFydCgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgc3RhcnRlZCgpIHtcclxuXHJcbiAgICBpZighdGhpcy5zdGFydGVkRGF0ZSkge1xyXG4gICAgICB0aGlzLnN0YXJ0ZWREYXRlPW5ldyBEYXRlKCk7XHJcbiAgICB9XHJcbiAgICB0aGlzLnRyYW5zcG9ydEFjdGlvbnMuc3RhcnRBY3Rpb24uZGlzYWJsZWQgPSB0cnVlO1xyXG4gIH1cclxuXHJcbiAgcG9zdFJlY29yZGluZyh3YXZGaWxlOiBVaW50OEFycmF5LCByZWNVcmw6IHN0cmluZyxyZjpSZWNvcmRpbmdGaWxlfG51bGwsdXBsb2FkSG9sZGVyPzpVcGxvYWRIb2xkZXIpIHtcclxuICAgIGxldCB3YXZCbG9iID0gbmV3IEJsb2IoW3dhdkZpbGVdLCB7dHlwZTogJ2F1ZGlvL3dhdid9KTtcclxuICAgIGxldCB1bCA9IG5ldyBVcGxvYWQod2F2QmxvYiwgcmVjVXJsLHJmKTtcclxuICAgIGlmKHVwbG9hZEhvbGRlcil7XHJcbiAgICAgIHVwbG9hZEhvbGRlci51cGxvYWQ9dWw7XHJcbiAgICB9XHJcbiAgICB0aGlzLnVwbG9hZGVyLnF1ZXVlVXBsb2FkKHVsKTtcclxuICB9XHJcblxyXG4gIHBvc3RBdWRpb1N0cmVhbVN0YXJ0KCk6IHZvaWQge1xyXG4gICAgaWYodGhpcy5yZlV1aWQpIHtcclxuICAgICAgdGhpcy51cGxvYWRTZXQ9bmV3IFVwbG9hZFNldCgpO1xyXG4gICAgICBsZXQgYXBpRW5kUG9pbnQgPSAnJztcclxuICAgICAgaWYgKHRoaXMuY29uZmlnICYmIHRoaXMuY29uZmlnLmFwaUVuZFBvaW50KSB7XHJcbiAgICAgICAgYXBpRW5kUG9pbnQgPSB0aGlzLmNvbmZpZy5hcGlFbmRQb2ludDtcclxuICAgICAgfVxyXG4gICAgICBpZiAoYXBpRW5kUG9pbnQgIT09ICcnKSB7XHJcbiAgICAgICAgYXBpRW5kUG9pbnQgPSBhcGlFbmRQb2ludCArICcvJ1xyXG4gICAgICB9XHJcbiAgICAgIGxldCBzZXNzaW9uc1VybCA9IGFwaUVuZFBvaW50ICsgU2Vzc2lvblNlcnZpY2UuU0VTU0lPTl9BUElfQ1RYO1xyXG4gICAgICBsZXQgcmVjVXJsOiBzdHJpbmcgPSBzZXNzaW9uc1VybCArICcvJyArIHRoaXMuc2Vzc2lvbj8uc2Vzc2lvbklkICsgJy8nICsgUkVDRklMRV9BUElfQ1RYICsgJy8nICsgdGhpcy5yZlV1aWQgKyAnL3ByZXBhcmVDaHVua3NSZXF1ZXN0JztcclxuICAgICAgbGV0IGZkID0gbmV3IEZvcm1EYXRhKCk7XHJcbiAgICAgIC8vIE5vdGU6IEF0IGxlYXN0IG9uZSBwYXJhbWV0ZXIgbXVzdCBiZSBzZXRcclxuICAgICAgZmQuc2V0KCd1dWlkJyx0aGlzLnJmVXVpZCk7XHJcbiAgICAgIGlmKCF0aGlzLnN0YXJ0ZWREYXRlKSB7XHJcbiAgICAgICAgdGhpcy5zdGFydGVkRGF0ZT1uZXcgRGF0ZSgpO1xyXG4gICAgICB9XHJcbiAgICAgIGZkLnNldCgnc3RhcnRlZERhdGUnLHRoaXMuc3RhcnRlZERhdGUudG9KU09OKCkpO1xyXG5cclxuICAgICAgbGV0IHVsID0gbmV3IFVwbG9hZChmZCwgcmVjVXJsKTtcclxuICAgICAgdGhpcy51cGxvYWRTZXQuYWRkKHVsKTtcclxuICAgICAgdGhpcy51cGxvYWRlci5xdWV1ZVVwbG9hZCh1bCk7XHJcbiAgICB9ZWxzZXtcclxuICAgICAgY29uc29sZS5lcnJvcihcIlJlY29yZGluZyBmaWxlIFVVSUQgbm90IHNldCFcIilcclxuICAgIH1cclxuICB9XHJcblxyXG5wcm90ZWN0ZWQgc2Vzc2lvbnNCYXNlVXJsKCk6c3RyaW5nIHtcclxuICBsZXQgYXBpRW5kUG9pbnQgPSAnJztcclxuICBpZiAodGhpcy5jb25maWcgJiYgdGhpcy5jb25maWcuYXBpRW5kUG9pbnQpIHtcclxuICAgIGFwaUVuZFBvaW50ID0gdGhpcy5jb25maWcuYXBpRW5kUG9pbnQ7XHJcbiAgfVxyXG4gIGlmIChhcGlFbmRQb2ludCAhPT0gJycpIHtcclxuICAgIGFwaUVuZFBvaW50ID0gYXBpRW5kUG9pbnQgKyAnLydcclxuICB9XHJcbiAgcmV0dXJuICBhcGlFbmRQb2ludCArIFNlc3Npb25TZXJ2aWNlLlNFU1NJT05fQVBJX0NUWDtcclxufVxyXG5cclxuICBhYnN0cmFjdCBwb3N0Q2h1bmtBdWRpb0J1ZmZlcihhdWRpb0J1ZmZlcjogQXVkaW9CdWZmZXIsIGNodW5rSWR4OiBudW1iZXIpOiB2b2lkO1xyXG5cclxuICBwb3N0QXVkaW9TdHJlYW1FbmQoY2h1bmtDb3VudDogbnVtYmVyKTogdm9pZCB7XHJcblxyXG4gICAgaWYodGhpcy5yZlV1aWQpIHtcclxuXHJcbiAgICAgIGxldCBzZXNzaW9uc1VybCA9IHRoaXMuc2Vzc2lvbnNCYXNlVXJsKCk7XHJcbiAgICAgIGxldCByZWNVcmw6IHN0cmluZyA9IHNlc3Npb25zVXJsICsgJy8nICsgdGhpcy5zZXNzaW9uPy5zZXNzaW9uSWQgKyAnLycgKyBSRUNGSUxFX0FQSV9DVFggKyAnLycgKyB0aGlzLnJmVXVpZCsnL2NvbmNhdENodW5rc1JlcXVlc3QnO1xyXG4gICAgICBsZXQgZmQ9bmV3IEZvcm1EYXRhKCk7XHJcbiAgICAgIGZkLnNldCgndXVpZCcsdGhpcy5yZlV1aWQpO1xyXG4gICAgICBmZC5zZXQoJ2NodW5rQ291bnQnLGNodW5rQ291bnQudG9TdHJpbmcoKSk7XHJcbiAgICAgIGxldCB1bCA9IG5ldyBVcGxvYWQoZmQsIHJlY1VybCx0aGlzLl9yZWNvcmRpbmdGaWxlKTtcclxuICAgICAgaWYodGhpcy51cGxvYWRTZXQpe1xyXG4gICAgICAgIHRoaXMudXBsb2FkU2V0LmFkZCh1bCk7XHJcbiAgICAgICAgdGhpcy51cGxvYWRTZXQuY29tcGxldGUoKTtcclxuICAgICAgfVxyXG4gICAgICB0aGlzLnVwbG9hZGVyLnF1ZXVlVXBsb2FkKHVsKTtcclxuICAgICAgLy9jb25zb2xlLmRlYnVnKFwiUXVldWVkIGZvciB1cGxvYWQ6IFwiK3RoaXMuX3JlY29yZGluZ0ZpbGUpO1xyXG4gICAgfWVsc2V7XHJcbiAgICAgIGNvbnNvbGUuZXJyb3IoXCJSZWNvcmRpbmcgZmlsZSBVVUlEIG5vdCBzZXQhXCIpXHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBjbG9zZWQoKSB7XHJcbiAgICB0aGlzLnN0YXR1c0FsZXJ0VHlwZSA9ICdpbmZvJztcclxuICAgIHRoaXMuc3RhdHVzTXNnID0gJ1Nlc3Npb24gY2xvc2VkLic7XHJcbiAgfVxyXG5cclxuICBlcnJvcihtc2c9J0FuIHVua25vd24gZXJyb3Igb2NjdXJlZCBkdXJpbmcgcmVjb3JkaW5nLicsYWR2aWNlOnN0cmluZz0nUGxlYXNlIHJldHJ5LicpIHtcclxuICAgIHRoaXMubmF2aWdhdGlvbkRpc2FibGVkID0gZmFsc2U7XHJcbiAgICB0aGlzLnN0YXR1c01zZyA9ICdFUlJPUjogUmVjb3JkaW5nLic7XHJcbiAgICB0aGlzLnN0YXR1c0FsZXJ0VHlwZSA9ICdlcnJvcic7XHJcbiAgICB0aGlzLmRpYWxvZy5vcGVuKE1lc3NhZ2VEaWFsb2csIHtcclxuICAgICAgZGF0YToge1xyXG4gICAgICAgIHR5cGU6ICdlcnJvcicsXHJcbiAgICAgICAgdGl0bGU6ICdSZWNvcmRpbmcgZXJyb3InLFxyXG4gICAgICAgIG1zZzogbXNnLFxyXG4gICAgICAgIGFkdmljZTogYWR2aWNlXHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbn1cclxuIl19