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,218 +1,218 @@
1
- import { AsyncEditFloat32ArrayInputStream } from "../../io/stream";
2
- import { ArrayAudioBufferSourceNode } from "./array_audio_buffer_source_node";
3
- import { EMPTY, expand, Observable } from "rxjs";
4
- import { AudioSourceNode } from "./audio_source_node";
5
- import { NetAudioInputStream } from "../net_audio_buffer";
6
- export class NetAudioBufferSourceNode extends AudioSourceNode {
7
- constructor(context) {
8
- super(context, 'audio-source-worklet');
9
- this._bufferFillSeconds = AudioSourceNode.DEFAULT_BUFFER_FILL_SECONDS;
10
- this.bufferFillFrames = 0;
11
- this._streamReadFrameLen = AudioSourceNode.DEFAULT_STREAM_READ_FRAME_LEN * 8; // Much overhead fetching small buffers from indexed db, use larger buffer (8192).
12
- this._netAudioBuffer = null;
13
- this._audioInputStream = null;
14
- this._aisBufs = null;
15
- this._active = false;
16
- this.stalled = false;
17
- this._endOfStream = false;
18
- this.readDataSubscription = null;
19
- this.filledFrames = 0;
20
- this.stalledStartTime = null;
21
- this.stalledTime = 0;
22
- this.stopEndTime = null;
23
- this.channelCountMode = 'explicit';
24
- this.port.onmessage = (msgEv) => {
25
- if (msgEv.data) {
26
- let evType = msgEv.data.eventType;
27
- if (evType) {
28
- if ('bufferNotification' === evType) {
29
- this.filledFrames = msgEv.data.filledFrames;
30
- //console.debug("IndexedDbAudioBufferSourceNode: Buffer notification: filled frames: " + this.filledFrames);
31
- if (!this._endOfStream) {
32
- this.fillBufferObs().subscribe();
33
- }
34
- }
35
- else if ('ended' === evType) {
36
- //console.debug("Inddb audio source ended playback.");
37
- let drainTime = 0;
38
- if (this._netAudioBuffer?.sampleRate) {
39
- drainTime = ArrayAudioBufferSourceNode.QUANTUM_FRAME_LEN / this._netAudioBuffer.sampleRate;
40
- }
41
- //let dstAny:any=this.context.destination;
42
- //console.debug('Destination node tail-time: '+dstAny['tail-time']);
43
- window.setTimeout(() => {
44
- this.stopEndTime = this.context.currentTime;
45
- this._active = false;
46
- this.onended?.call(this);
47
- }, drainTime * 1000);
48
- }
49
- else if ('stalled' === evType) {
50
- console.debug('Playback stalled...');
51
- this.stalled = true;
52
- this.stalledStartTime = this.context.currentTime;
53
- }
54
- else if ('resumed' === evType) {
55
- console.debug('Playback resumed after stall.');
56
- this.stalled = false;
57
- if (this.stalledStartTime != null) {
58
- this.stalledTime += this.context.currentTime - this.stalledStartTime;
59
- this.stalledStartTime = null;
60
- }
61
- }
62
- }
63
- }
64
- };
65
- }
66
- fillBufferObs(frameOffset) {
67
- return new Observable(subscriber => {
68
- if (frameOffset) {
69
- subscriber.error(new Error("Starting playback from position not equal zero not supported yet."));
70
- }
71
- else {
72
- let filled = this.filledFrames;
73
- let bufLen = 0;
74
- if (this._audioInputStream && this._aisBufs && (this.readDataSubscription == null || this.readDataSubscription?.closed)) {
75
- this.readDataSubscription = this._audioInputStream.readObs(this._aisBufs).pipe(expand((read) => {
76
- if (read && this._aisBufs) {
77
- let trBuffers = new Array(this.channelCount);
78
- for (let ch = 0; ch < this.channelCount; ch++) {
79
- let adCh = this._aisBufs[ch];
80
- let adChCopy = new Float32Array(read);
81
- bufLen = adChCopy.length;
82
- if (read === adCh.length) {
83
- adChCopy.set(adCh);
84
- }
85
- else {
86
- // Note: slice() does not work here, since it returns a shallow copy.
87
- for (let i = 0; i < read; i++) {
88
- adChCopy[i] = adCh[i];
89
- }
90
- }
91
- trBuffers[ch] = adChCopy.buffer;
92
- }
93
- this.port.postMessage({
94
- cmd: 'data',
95
- chs: this.channelCount,
96
- audioData: trBuffers
97
- }, trBuffers);
98
- filled += read;
99
- //console.debug("IndexedDbAudioBufferSourceNode::fillBufferObs: Sent "+read+" frames to audio source worklet. Filled: "+filled+", to fill: "+this.bufferFillFrames);
100
- if (this._audioInputStream && filled < this.bufferFillFrames) {
101
- //console.debug("IndexedDbAudioBufferSourceNode::fillBufferObs: Next inddb audio input stream readObs");
102
- return this._audioInputStream.readObs(this._aisBufs);
103
- }
104
- else {
105
- if (this.stalled) {
106
- this.port.postMessage({
107
- cmd: 'continue'
108
- });
109
- }
110
- return EMPTY;
111
- }
112
- }
113
- else {
114
- //console.debug("IndexedDbAudioBufferSourceNode::fillBufferObs: Return EMPTY (read: "+read+")");
115
- this._endOfStream = true;
116
- this.port.postMessage({
117
- cmd: 'endOfStream'
118
- });
119
- return EMPTY;
120
- }
121
- })).subscribe(subscriber);
122
- }
123
- }
124
- });
125
- }
126
- get netAudioBuffer() {
127
- return this._netAudioBuffer;
128
- }
129
- set netAudioBuffer(value) {
130
- this._netAudioBuffer = value;
131
- if (this._netAudioBuffer?.channelCount) {
132
- this.channelCount = this._netAudioBuffer?.channelCount;
133
- this.bufferFillFrames = this._netAudioBuffer.sampleRate * this._bufferFillSeconds;
134
- }
135
- }
136
- get bufferFillSeconds() {
137
- return this._bufferFillSeconds;
138
- }
139
- set bufferFillSeconds(value) {
140
- this._bufferFillSeconds = value;
141
- }
142
- start(when, offset, duration) {
143
- if (when) {
144
- throw Error("when parameter currently not supported by IndexedDbAudioBufferSourceNode class");
145
- }
146
- this._playStartTime = null;
147
- this.stopEndTime = null;
148
- this.stalledTime = 0;
149
- this.stalledStartTime = null;
150
- if (this._netAudioBuffer) {
151
- let arrAis = new NetAudioInputStream(this._netAudioBuffer);
152
- if (offset === undefined && duration === undefined) {
153
- this._audioInputStream = arrAis;
154
- }
155
- else {
156
- let offsetFrames = 0;
157
- let durationFrames = undefined;
158
- if (offset !== undefined) {
159
- offsetFrames = Math.floor(offset * this._netAudioBuffer.sampleRate);
160
- }
161
- if (duration !== undefined) {
162
- durationFrames = Math.floor(duration * this._netAudioBuffer.sampleRate);
163
- }
164
- //console.error("Playback selection not supported yet!");
165
- this._audioInputStream = new AsyncEditFloat32ArrayInputStream(arrAis, offsetFrames, durationFrames);
166
- }
167
- let chs = this._netAudioBuffer.channelCount;
168
- this._aisBufs = new Array(chs);
169
- for (let ch = 0; ch < chs; ch++) {
170
- this._aisBufs[ch] = new Float32Array(this._streamReadFrameLen);
171
- }
172
- this.fillBufferObs().subscribe({
173
- complete: () => {
174
- //console.debug("IndexedDbAudioBufferSourceNode::start: Async play buffer fill completed. Sending start command to audio worklet.");
175
- if (this._active) {
176
- this.port.postMessage({ cmd: 'start' });
177
- if (offset) {
178
- this._playStartTime = this.context.currentTime - offset;
179
- }
180
- else {
181
- this._playStartTime = this.context.currentTime;
182
- }
183
- }
184
- }
185
- });
186
- this._active = true;
187
- }
188
- }
189
- stop() {
190
- this._active = false;
191
- this.port.postMessage({ cmd: 'stop' });
192
- this.onended?.call(this);
193
- }
194
- get playPositionTime() {
195
- let ppt = null;
196
- if (this._playStartTime !== null) {
197
- if (this._active) {
198
- if (this.stalledStartTime == null) {
199
- ppt = this.context.currentTime - this._playStartTime - this.stalledTime;
200
- }
201
- else {
202
- ppt = this.stalledStartTime - this._playStartTime - this.stalledTime;
203
- }
204
- }
205
- else {
206
- if (this.stopEndTime != null) {
207
- // if(this._netAudioBuffer?.frameLen !=null && this._netAudioBuffer.sampleRate) {
208
- // ppt = this._netAudioBuffer?.frameLen / this._netAudioBuffer?.sampleRate;
209
- // }else{
210
- ppt = this.stopEndTime - this._playStartTime - this.stalledTime;
211
- //}
212
- }
213
- }
214
- }
215
- return ppt;
216
- }
217
- }
1
+ import { AsyncEditFloat32ArrayInputStream } from "../../io/stream";
2
+ import { ArrayAudioBufferSourceNode } from "./array_audio_buffer_source_node";
3
+ import { EMPTY, expand, Observable } from "rxjs";
4
+ import { AudioSourceNode } from "./audio_source_node";
5
+ import { NetAudioInputStream } from "../net_audio_buffer";
6
+ export class NetAudioBufferSourceNode extends AudioSourceNode {
7
+ constructor(context) {
8
+ super(context, 'audio-source-worklet');
9
+ this._bufferFillSeconds = AudioSourceNode.DEFAULT_BUFFER_FILL_SECONDS;
10
+ this.bufferFillFrames = 0;
11
+ this._streamReadFrameLen = AudioSourceNode.DEFAULT_STREAM_READ_FRAME_LEN * 8; // Much overhead fetching small buffers from indexed db, use larger buffer (8192).
12
+ this._netAudioBuffer = null;
13
+ this._audioInputStream = null;
14
+ this._aisBufs = null;
15
+ this._active = false;
16
+ this.stalled = false;
17
+ this._endOfStream = false;
18
+ this.readDataSubscription = null;
19
+ this.filledFrames = 0;
20
+ this.stalledStartTime = null;
21
+ this.stalledTime = 0;
22
+ this.stopEndTime = null;
23
+ this.channelCountMode = 'explicit';
24
+ this.port.onmessage = (msgEv) => {
25
+ if (msgEv.data) {
26
+ let evType = msgEv.data.eventType;
27
+ if (evType) {
28
+ if ('bufferNotification' === evType) {
29
+ this.filledFrames = msgEv.data.filledFrames;
30
+ //console.debug("IndexedDbAudioBufferSourceNode: Buffer notification: filled frames: " + this.filledFrames);
31
+ if (!this._endOfStream) {
32
+ this.fillBufferObs().subscribe();
33
+ }
34
+ }
35
+ else if ('ended' === evType) {
36
+ //console.debug("Inddb audio source ended playback.");
37
+ let drainTime = 0;
38
+ if (this._netAudioBuffer?.sampleRate) {
39
+ drainTime = ArrayAudioBufferSourceNode.QUANTUM_FRAME_LEN / this._netAudioBuffer.sampleRate;
40
+ }
41
+ //let dstAny:any=this.context.destination;
42
+ //console.debug('Destination node tail-time: '+dstAny['tail-time']);
43
+ window.setTimeout(() => {
44
+ this.stopEndTime = this.context.currentTime;
45
+ this._active = false;
46
+ this.onended?.call(this);
47
+ }, drainTime * 1000);
48
+ }
49
+ else if ('stalled' === evType) {
50
+ console.debug('Playback stalled...');
51
+ this.stalled = true;
52
+ this.stalledStartTime = this.context.currentTime;
53
+ }
54
+ else if ('resumed' === evType) {
55
+ console.debug('Playback resumed after stall.');
56
+ this.stalled = false;
57
+ if (this.stalledStartTime != null) {
58
+ this.stalledTime += this.context.currentTime - this.stalledStartTime;
59
+ this.stalledStartTime = null;
60
+ }
61
+ }
62
+ }
63
+ }
64
+ };
65
+ }
66
+ fillBufferObs(frameOffset) {
67
+ return new Observable(subscriber => {
68
+ if (frameOffset) {
69
+ subscriber.error(new Error("Starting playback from position not equal zero not supported yet."));
70
+ }
71
+ else {
72
+ let filled = this.filledFrames;
73
+ let bufLen = 0;
74
+ if (this._audioInputStream && this._aisBufs && (this.readDataSubscription == null || this.readDataSubscription?.closed)) {
75
+ this.readDataSubscription = this._audioInputStream.readObs(this._aisBufs).pipe(expand((read) => {
76
+ if (read && this._aisBufs) {
77
+ let trBuffers = new Array(this.channelCount);
78
+ for (let ch = 0; ch < this.channelCount; ch++) {
79
+ let adCh = this._aisBufs[ch];
80
+ let adChCopy = new Float32Array(read);
81
+ bufLen = adChCopy.length;
82
+ if (read === adCh.length) {
83
+ adChCopy.set(adCh);
84
+ }
85
+ else {
86
+ // Note: slice() does not work here, since it returns a shallow copy.
87
+ for (let i = 0; i < read; i++) {
88
+ adChCopy[i] = adCh[i];
89
+ }
90
+ }
91
+ trBuffers[ch] = adChCopy.buffer;
92
+ }
93
+ this.port.postMessage({
94
+ cmd: 'data',
95
+ chs: this.channelCount,
96
+ audioData: trBuffers
97
+ }, trBuffers);
98
+ filled += read;
99
+ //console.debug("IndexedDbAudioBufferSourceNode::fillBufferObs: Sent "+read+" frames to audio source worklet. Filled: "+filled+", to fill: "+this.bufferFillFrames);
100
+ if (this._audioInputStream && filled < this.bufferFillFrames) {
101
+ //console.debug("IndexedDbAudioBufferSourceNode::fillBufferObs: Next inddb audio input stream readObs");
102
+ return this._audioInputStream.readObs(this._aisBufs);
103
+ }
104
+ else {
105
+ if (this.stalled) {
106
+ this.port.postMessage({
107
+ cmd: 'continue'
108
+ });
109
+ }
110
+ return EMPTY;
111
+ }
112
+ }
113
+ else {
114
+ //console.debug("IndexedDbAudioBufferSourceNode::fillBufferObs: Return EMPTY (read: "+read+")");
115
+ this._endOfStream = true;
116
+ this.port.postMessage({
117
+ cmd: 'endOfStream'
118
+ });
119
+ return EMPTY;
120
+ }
121
+ })).subscribe(subscriber);
122
+ }
123
+ }
124
+ });
125
+ }
126
+ get netAudioBuffer() {
127
+ return this._netAudioBuffer;
128
+ }
129
+ set netAudioBuffer(value) {
130
+ this._netAudioBuffer = value;
131
+ if (this._netAudioBuffer?.channelCount) {
132
+ this.channelCount = this._netAudioBuffer?.channelCount;
133
+ this.bufferFillFrames = this._netAudioBuffer.sampleRate * this._bufferFillSeconds;
134
+ }
135
+ }
136
+ get bufferFillSeconds() {
137
+ return this._bufferFillSeconds;
138
+ }
139
+ set bufferFillSeconds(value) {
140
+ this._bufferFillSeconds = value;
141
+ }
142
+ start(when, offset, duration) {
143
+ if (when) {
144
+ throw Error("when parameter currently not supported by IndexedDbAudioBufferSourceNode class");
145
+ }
146
+ this._playStartTime = null;
147
+ this.stopEndTime = null;
148
+ this.stalledTime = 0;
149
+ this.stalledStartTime = null;
150
+ if (this._netAudioBuffer) {
151
+ let arrAis = new NetAudioInputStream(this._netAudioBuffer);
152
+ if (offset === undefined && duration === undefined) {
153
+ this._audioInputStream = arrAis;
154
+ }
155
+ else {
156
+ let offsetFrames = 0;
157
+ let durationFrames = undefined;
158
+ if (offset !== undefined) {
159
+ offsetFrames = Math.floor(offset * this._netAudioBuffer.sampleRate);
160
+ }
161
+ if (duration !== undefined) {
162
+ durationFrames = Math.floor(duration * this._netAudioBuffer.sampleRate);
163
+ }
164
+ //console.error("Playback selection not supported yet!");
165
+ this._audioInputStream = new AsyncEditFloat32ArrayInputStream(arrAis, offsetFrames, durationFrames);
166
+ }
167
+ let chs = this._netAudioBuffer.channelCount;
168
+ this._aisBufs = new Array(chs);
169
+ for (let ch = 0; ch < chs; ch++) {
170
+ this._aisBufs[ch] = new Float32Array(this._streamReadFrameLen);
171
+ }
172
+ this.fillBufferObs().subscribe({
173
+ complete: () => {
174
+ //console.debug("IndexedDbAudioBufferSourceNode::start: Async play buffer fill completed. Sending start command to audio worklet.");
175
+ if (this._active) {
176
+ this.port.postMessage({ cmd: 'start' });
177
+ if (offset) {
178
+ this._playStartTime = this.context.currentTime - offset;
179
+ }
180
+ else {
181
+ this._playStartTime = this.context.currentTime;
182
+ }
183
+ }
184
+ }
185
+ });
186
+ this._active = true;
187
+ }
188
+ }
189
+ stop() {
190
+ this._active = false;
191
+ this.port.postMessage({ cmd: 'stop' });
192
+ this.onended?.call(this);
193
+ }
194
+ get playPositionTime() {
195
+ let ppt = null;
196
+ if (this._playStartTime !== null) {
197
+ if (this._active) {
198
+ if (this.stalledStartTime == null) {
199
+ ppt = this.context.currentTime - this._playStartTime - this.stalledTime;
200
+ }
201
+ else {
202
+ ppt = this.stalledStartTime - this._playStartTime - this.stalledTime;
203
+ }
204
+ }
205
+ else {
206
+ if (this.stopEndTime != null) {
207
+ // if(this._netAudioBuffer?.frameLen !=null && this._netAudioBuffer.sampleRate) {
208
+ // ppt = this._netAudioBuffer?.frameLen / this._netAudioBuffer?.sampleRate;
209
+ // }else{
210
+ ppt = this.stopEndTime - this._playStartTime - this.stalledTime;
211
+ //}
212
+ }
213
+ }
214
+ }
215
+ return ppt;
216
+ }
217
+ }
218
218
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV0X2F1ZGlvX2J1ZmZlcl9zb3VyY2Vfbm9kZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3NwZWVjaHJlY29yZGVybmcvc3JjL2xpYi9hdWRpby9wbGF5YmFjay9uZXRfYXVkaW9fYnVmZmVyX3NvdXJjZV9ub2RlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBQyxnQ0FBZ0MsRUFBK0IsTUFBTSxpQkFBaUIsQ0FBQztBQUMvRixPQUFPLEVBQUMsMEJBQTBCLEVBQUMsTUFBTSxrQ0FBa0MsQ0FBQztBQUM1RSxPQUFPLEVBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQWUsTUFBTSxNQUFNLENBQUM7QUFDN0QsT0FBTyxFQUFDLGVBQWUsRUFBQyxNQUFNLHFCQUFxQixDQUFDO0FBQ3BELE9BQU8sRUFBaUIsbUJBQW1CLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQztBQUV4RSxNQUFNLE9BQU8sd0JBQXlCLFNBQVEsZUFBZTtJQW1CM0QsWUFBWSxPQUFxQjtRQUUvQixLQUFLLENBQUMsT0FBTyxFQUFFLHNCQUFzQixDQUFDLENBQUM7UUFuQmpDLHVCQUFrQixHQUFHLGVBQWUsQ0FBQywyQkFBMkIsQ0FBQztRQUNqRSxxQkFBZ0IsR0FBRyxDQUFDLENBQUM7UUFDckIsd0JBQW1CLEdBQUMsZUFBZSxDQUFDLDZCQUE2QixHQUFHLENBQUMsQ0FBQyxDQUFFLGtGQUFrRjtRQUMxSixvQkFBZSxHQUFxQixJQUFJLENBQUM7UUFDekMsc0JBQWlCLEdBQW1DLElBQUksQ0FBQztRQUN6RCxhQUFRLEdBQXFCLElBQUksQ0FBQztRQUNsQyxZQUFPLEdBQUMsS0FBSyxDQUFDO1FBQ2QsWUFBTyxHQUFDLEtBQUssQ0FBQztRQUNkLGlCQUFZLEdBQUMsS0FBSyxDQUFDO1FBQ25CLHlCQUFvQixHQUFtQixJQUFJLENBQUM7UUFDNUMsaUJBQVksR0FBRyxDQUFDLENBQUM7UUFFakIscUJBQWdCLEdBQWEsSUFBSSxDQUFDO1FBQ2xDLGdCQUFXLEdBQVEsQ0FBQyxDQUFDO1FBRXJCLGdCQUFXLEdBQWEsSUFBSSxDQUFDO1FBS25DLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxVQUFVLENBQUM7UUFDbkMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEdBQUcsQ0FBQyxLQUFtQixFQUFFLEVBQUU7WUFDNUMsSUFBSSxLQUFLLENBQUMsSUFBSSxFQUFFO2dCQUNkLElBQUksTUFBTSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDO2dCQUNsQyxJQUFJLE1BQU0sRUFBRTtvQkFDVixJQUFJLG9CQUFvQixLQUFLLE1BQU0sRUFBRTt3QkFDbkMsSUFBSSxDQUFDLFlBQVksR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQzt3QkFDNUMsNEdBQTRHO3dCQUM1RyxJQUFHLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRTs0QkFDckIsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDLFNBQVMsRUFBRSxDQUFDO3lCQUNsQztxQkFDRjt5QkFBTSxJQUFJLE9BQU8sS0FBSyxNQUFNLEVBQUU7d0JBQzdCLHNEQUFzRDt3QkFDdEQsSUFBSSxTQUFTLEdBQUcsQ0FBQyxDQUFDO3dCQUNsQixJQUFJLElBQUksQ0FBQyxlQUFlLEVBQUUsVUFBVSxFQUFFOzRCQUNwQyxTQUFTLEdBQUcsMEJBQTBCLENBQUMsaUJBQWlCLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxVQUFVLENBQUM7eUJBQzVGO3dCQUNELDBDQUEwQzt3QkFDMUMsb0VBQW9FO3dCQUNwRSxNQUFNLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRTs0QkFDckIsSUFBSSxDQUFDLFdBQVcsR0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQzs0QkFDMUMsSUFBSSxDQUFDLE9BQU8sR0FBQyxLQUFLLENBQUM7NEJBQ25CLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO3dCQUMzQixDQUFDLEVBQUUsU0FBUyxHQUFHLElBQUksQ0FBQyxDQUFDO3FCQUV0Qjt5QkFBSyxJQUFJLFNBQVMsS0FBSyxNQUFNLEVBQUU7d0JBQzlCLE9BQU8sQ0FBQyxLQUFLLENBQUMscUJBQXFCLENBQUMsQ0FBQzt3QkFDckMsSUFBSSxDQUFDLE9BQU8sR0FBQyxJQUFJLENBQUM7d0JBQ2xCLElBQUksQ0FBQyxnQkFBZ0IsR0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQztxQkFDaEQ7eUJBQUssSUFBSSxTQUFTLEtBQUssTUFBTSxFQUFFO3dCQUM5QixPQUFPLENBQUMsS0FBSyxDQUFDLCtCQUErQixDQUFDLENBQUM7d0JBQy9DLElBQUksQ0FBQyxPQUFPLEdBQUMsS0FBSyxDQUFDO3dCQUNuQixJQUFHLElBQUksQ0FBQyxnQkFBZ0IsSUFBRSxJQUFJLEVBQUU7NEJBQzlCLElBQUksQ0FBQyxXQUFXLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDOzRCQUNyRSxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxDQUFDO3lCQUM5QjtxQkFDRjtpQkFDRjthQUNGO1FBQ0gsQ0FBQyxDQUFBO0lBQ0gsQ0FBQztJQUVPLGFBQWEsQ0FBQyxXQUFtQjtRQUVyQyxPQUFPLElBQUksVUFBVSxDQUFnQixVQUFVLENBQUMsRUFBRTtZQUNoRCxJQUFHLFdBQVcsRUFBQztnQkFDYixVQUFVLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxDQUFDLG1FQUFtRSxDQUFDLENBQUMsQ0FBQzthQUNsRztpQkFBSztnQkFDSixJQUFJLE1BQU0sR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDO2dCQUMvQixJQUFJLE1BQU0sR0FBRyxDQUFDLENBQUM7Z0JBQ2YsSUFBSSxJQUFJLENBQUMsaUJBQWlCLElBQUksSUFBSSxDQUFDLFFBQVEsSUFBSSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsSUFBRSxJQUFJLElBQUksSUFBSSxDQUFDLG9CQUFvQixFQUFFLE1BQU0sQ0FBQyxFQUFFO29CQUNySCxJQUFJLENBQUMsb0JBQW9CLEdBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsSUFBSSxDQUMxRSxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTt3QkFDWixJQUFJLElBQUksSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFOzRCQUN6QixJQUFJLFNBQVMsR0FBRyxJQUFJLEtBQUssQ0FBTSxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7NEJBQ2xELEtBQUssSUFBSSxFQUFFLEdBQUcsQ0FBQyxFQUFFLEVBQUUsR0FBRyxJQUFJLENBQUMsWUFBWSxFQUFFLEVBQUUsRUFBRSxFQUFFO2dDQUM3QyxJQUFJLElBQUksR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dDQUM3QixJQUFJLFFBQVEsR0FBRyxJQUFJLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztnQ0FDdEMsTUFBTSxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUM7Z0NBQ3pCLElBQUcsSUFBSSxLQUFHLElBQUksQ0FBQyxNQUFNLEVBQUU7b0NBQ3JCLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7aUNBQ3BCO3FDQUFJO29DQUNILHFFQUFxRTtvQ0FDckUsS0FBSSxJQUFJLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLElBQUksRUFBQyxDQUFDLEVBQUUsRUFBQzt3Q0FDckIsUUFBUSxDQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztxQ0FDckI7aUNBQ0Y7Z0NBQ0QsU0FBUyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUM7NkJBQ2pDOzRCQUNELElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDO2dDQUNwQixHQUFHLEVBQUUsTUFBTTtnQ0FDWCxHQUFHLEVBQUUsSUFBSSxDQUFDLFlBQVk7Z0NBQ3RCLFNBQVMsRUFBRSxTQUFTOzZCQUNyQixFQUFFLFNBQVMsQ0FBQyxDQUFDOzRCQUNkLE1BQU0sSUFBSSxJQUFJLENBQUM7NEJBQ2Ysb0tBQW9LOzRCQUNwSyxJQUFJLElBQUksQ0FBQyxpQkFBaUIsSUFBSSxNQUFNLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixFQUFFO2dDQUM1RCx3R0FBd0c7Z0NBQ3hHLE9BQU8sSUFBSSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7NkJBQ3REO2lDQUFNO2dDQUNMLElBQUcsSUFBSSxDQUFDLE9BQU8sRUFBQztvQ0FDZCxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQzt3Q0FDcEIsR0FBRyxFQUFFLFVBQVU7cUNBQ2hCLENBQUMsQ0FBQztpQ0FFSjtnQ0FDRCxPQUFPLEtBQUssQ0FBQzs2QkFDZDt5QkFDRjs2QkFBTTs0QkFDTCxnR0FBZ0c7NEJBQ2hHLElBQUksQ0FBQyxZQUFZLEdBQUMsSUFBSSxDQUFDOzRCQUN2QixJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQztnQ0FDcEIsR0FBRyxFQUFFLGFBQWE7NkJBQ25CLENBQUMsQ0FBQzs0QkFDSCxPQUFPLEtBQUssQ0FBQzt5QkFDZDtvQkFDSCxDQUFDLENBQ0YsQ0FDRixDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsQ0FBQztpQkFDekI7YUFDRjtRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUdELElBQUksY0FBYztRQUNoQixPQUFPLElBQUksQ0FBQyxlQUFlLENBQUE7SUFDN0IsQ0FBQztJQUVELElBQUksY0FBYyxDQUFDLEtBQTRCO1FBQzdDLElBQUksQ0FBQyxlQUFlLEdBQUcsS0FBSyxDQUFDO1FBQzdCLElBQUksSUFBSSxDQUFDLGVBQWUsRUFBRSxZQUFZLEVBQUU7WUFDdEMsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsZUFBZSxFQUFFLFlBQVksQ0FBQztZQUN2RCxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDO1NBQ25GO0lBQ0gsQ0FBQztJQUVELElBQUksaUJBQWlCO1FBQ25CLE9BQU8sSUFBSSxDQUFDLGtCQUFrQixDQUFDO0lBQ2pDLENBQUM7SUFFRCxJQUFJLGlCQUFpQixDQUFDLEtBQWE7UUFDakMsSUFBSSxDQUFDLGtCQUFrQixHQUFHLEtBQUssQ0FBQztJQUNsQyxDQUFDO0lBRUQsS0FBSyxDQUFDLElBQXlCLEVBQUMsTUFBMkIsRUFBQyxRQUE2QjtRQUN2RixJQUFJLElBQUksRUFBRTtZQUNSLE1BQU0sS0FBSyxDQUFDLGdGQUFnRixDQUFDLENBQUE7U0FDOUY7UUFDRCxJQUFJLENBQUMsY0FBYyxHQUFDLElBQUksQ0FBQztRQUN6QixJQUFJLENBQUMsV0FBVyxHQUFDLElBQUksQ0FBQztRQUN0QixJQUFJLENBQUMsV0FBVyxHQUFDLENBQUMsQ0FBQztRQUNuQixJQUFJLENBQUMsZ0JBQWdCLEdBQUMsSUFBSSxDQUFDO1FBRTNCLElBQUksSUFBSSxDQUFDLGVBQWUsRUFBRTtZQUN4QixJQUFJLE1BQU0sR0FBQyxJQUFJLG1CQUFtQixDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztZQUN6RCxJQUFHLE1BQU0sS0FBRyxTQUFTLElBQUksUUFBUSxLQUFHLFNBQVMsRUFBQztnQkFDNUMsSUFBSSxDQUFDLGlCQUFpQixHQUFHLE1BQU0sQ0FBQzthQUNqQztpQkFBSTtnQkFDSCxJQUFJLFlBQVksR0FBQyxDQUFDLENBQUM7Z0JBQ25CLElBQUksY0FBYyxHQUFDLFNBQVMsQ0FBQztnQkFDN0IsSUFBRyxNQUFNLEtBQUcsU0FBUyxFQUFFO29CQUNyQixZQUFZLEdBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxVQUFVLENBQUMsQ0FBQztpQkFDbkU7Z0JBQ0QsSUFBRyxRQUFRLEtBQUcsU0FBUyxFQUFDO29CQUN0QixjQUFjLEdBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxVQUFVLENBQUMsQ0FBQztpQkFDdkU7Z0JBQ0QseURBQXlEO2dCQUN6RCxJQUFJLENBQUMsaUJBQWlCLEdBQUMsSUFBSSxnQ0FBZ0MsQ0FBQyxNQUFNLEVBQUMsWUFBWSxFQUFDLGNBQWMsQ0FBQyxDQUFDO2FBQ2pHO1lBRUQsSUFBSSxHQUFHLEdBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxZQUFZLENBQUM7WUFDMUMsSUFBSSxDQUFDLFFBQVEsR0FBQyxJQUFJLEtBQUssQ0FBZSxHQUFHLENBQUMsQ0FBQztZQUMzQyxLQUFJLElBQUksRUFBRSxHQUFDLENBQUMsRUFBQyxFQUFFLEdBQUMsR0FBRyxFQUFDLEVBQUUsRUFBRSxFQUFDO2dCQUN2QixJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxHQUFDLElBQUksWUFBWSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO2FBQzlEO1lBRUQsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDLFNBQVMsQ0FBQztnQkFDN0IsUUFBUSxFQUFFLEdBQUUsRUFBRTtvQkFDWixvSUFBb0k7b0JBQ3BJLElBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRTt3QkFDZixJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxFQUFDLEdBQUcsRUFBRSxPQUFPLEVBQUMsQ0FBQyxDQUFDO3dCQUN0QyxJQUFHLE1BQU0sRUFBRTs0QkFDVCxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsV0FBVyxHQUFHLE1BQU0sQ0FBQzt5QkFDekQ7NkJBQUk7NEJBQ0gsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQzt5QkFDaEQ7cUJBQ0Y7Z0JBQ0gsQ0FBQzthQUNGLENBQUMsQ0FBQTtZQUNGLElBQUksQ0FBQyxPQUFPLEdBQUMsSUFBSSxDQUFDO1NBRW5CO0lBQ0gsQ0FBQztJQUVELElBQUk7UUFDRixJQUFJLENBQUMsT0FBTyxHQUFDLEtBQUssQ0FBQztRQUNuQixJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxFQUFDLEdBQUcsRUFBRSxNQUFNLEVBQUMsQ0FBQyxDQUFDO1FBQ3JDLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzNCLENBQUM7SUFFRCxJQUFJLGdCQUFnQjtRQUNsQixJQUFJLEdBQUcsR0FBYSxJQUFJLENBQUM7UUFDekIsSUFBRyxJQUFJLENBQUMsY0FBYyxLQUFHLElBQUksRUFBRTtZQUM3QixJQUFHLElBQUksQ0FBQyxPQUFPLEVBQUU7Z0JBQ2YsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLElBQUksSUFBSSxFQUFFO29CQUNqQyxHQUFHLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDO2lCQUN6RTtxQkFBTTtvQkFDTCxHQUFHLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQztpQkFDdEU7YUFDRjtpQkFBSTtnQkFDSCxJQUFHLElBQUksQ0FBQyxXQUFXLElBQUUsSUFBSSxFQUFDO29CQUN4QixpRkFBaUY7b0JBQ2pGLDZFQUE2RTtvQkFDN0UsU0FBUztvQkFDUCxHQUFHLEdBQUcsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUM7b0JBQ2xFLEdBQUc7aUJBQ0o7YUFDRjtTQUNGO1FBQ0QsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO0NBRUYiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0FzeW5jRWRpdEZsb2F0MzJBcnJheUlucHV0U3RyZWFtLCBBc3luY0Zsb2F0MzJBcnJheUlucHV0U3RyZWFtfSBmcm9tIFwiLi4vLi4vaW8vc3RyZWFtXCI7XHJcbmltcG9ydCB7QXJyYXlBdWRpb0J1ZmZlclNvdXJjZU5vZGV9IGZyb20gXCIuL2FycmF5X2F1ZGlvX2J1ZmZlcl9zb3VyY2Vfbm9kZVwiO1xyXG5pbXBvcnQge0VNUFRZLCBleHBhbmQsIE9ic2VydmFibGUsIFN1YnNjcmlwdGlvbn0gZnJvbSBcInJ4anNcIjtcclxuaW1wb3J0IHtBdWRpb1NvdXJjZU5vZGV9IGZyb20gXCIuL2F1ZGlvX3NvdXJjZV9ub2RlXCI7XHJcbmltcG9ydCB7TmV0QXVkaW9CdWZmZXIsIE5ldEF1ZGlvSW5wdXRTdHJlYW19IGZyb20gXCIuLi9uZXRfYXVkaW9fYnVmZmVyXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgTmV0QXVkaW9CdWZmZXJTb3VyY2VOb2RlIGV4dGVuZHMgQXVkaW9Tb3VyY2VOb2RlIHtcclxuXHJcbiAgcHJpdmF0ZSBfYnVmZmVyRmlsbFNlY29uZHMgPSBBdWRpb1NvdXJjZU5vZGUuREVGQVVMVF9CVUZGRVJfRklMTF9TRUNPTkRTO1xyXG4gIHByaXZhdGUgYnVmZmVyRmlsbEZyYW1lcyA9IDA7XHJcbiAgcHJpdmF0ZSBfc3RyZWFtUmVhZEZyYW1lTGVuPUF1ZGlvU291cmNlTm9kZS5ERUZBVUxUX1NUUkVBTV9SRUFEX0ZSQU1FX0xFTiAqIDg7ICAvLyBNdWNoIG92ZXJoZWFkIGZldGNoaW5nIHNtYWxsIGJ1ZmZlcnMgZnJvbSBpbmRleGVkIGRiLCB1c2UgbGFyZ2VyIGJ1ZmZlciAoODE5MikuXHJcbiAgcHJpdmF0ZSBfbmV0QXVkaW9CdWZmZXI6TmV0QXVkaW9CdWZmZXJ8bnVsbD1udWxsO1xyXG4gIHByaXZhdGUgX2F1ZGlvSW5wdXRTdHJlYW06QXN5bmNGbG9hdDMyQXJyYXlJbnB1dFN0cmVhbXxudWxsPW51bGw7XHJcbiAgcHJpdmF0ZSBfYWlzQnVmczpGbG9hdDMyQXJyYXlbXXxudWxsPW51bGw7XHJcbiAgcHJpdmF0ZSBfYWN0aXZlPWZhbHNlO1xyXG4gIHByaXZhdGUgc3RhbGxlZD1mYWxzZTtcclxuICBwcml2YXRlIF9lbmRPZlN0cmVhbT1mYWxzZTtcclxuICBwcml2YXRlIHJlYWREYXRhU3Vic2NyaXB0aW9uOlN1YnNjcmlwdGlvbnxudWxsPW51bGw7XHJcbiAgcHJpdmF0ZSBmaWxsZWRGcmFtZXMgPSAwO1xyXG5cclxuICBwcml2YXRlIHN0YWxsZWRTdGFydFRpbWU6bnVtYmVyfG51bGw9bnVsbDtcclxuICBwcml2YXRlIHN0YWxsZWRUaW1lOm51bWJlcj0wO1xyXG5cclxuICBwcml2YXRlIHN0b3BFbmRUaW1lOm51bWJlcnxudWxsPW51bGw7XHJcblxyXG4gIGNvbnN0cnVjdG9yKGNvbnRleHQ6IEF1ZGlvQ29udGV4dCkge1xyXG5cclxuICAgIHN1cGVyKGNvbnRleHQsICdhdWRpby1zb3VyY2Utd29ya2xldCcpO1xyXG4gICAgdGhpcy5jaGFubmVsQ291bnRNb2RlID0gJ2V4cGxpY2l0JztcclxuICAgIHRoaXMucG9ydC5vbm1lc3NhZ2UgPSAobXNnRXY6IE1lc3NhZ2VFdmVudCkgPT4ge1xyXG4gICAgICBpZiAobXNnRXYuZGF0YSkge1xyXG4gICAgICAgIGxldCBldlR5cGUgPSBtc2dFdi5kYXRhLmV2ZW50VHlwZTtcclxuICAgICAgICBpZiAoZXZUeXBlKSB7XHJcbiAgICAgICAgICBpZiAoJ2J1ZmZlck5vdGlmaWNhdGlvbicgPT09IGV2VHlwZSkge1xyXG4gICAgICAgICAgICB0aGlzLmZpbGxlZEZyYW1lcyA9IG1zZ0V2LmRhdGEuZmlsbGVkRnJhbWVzO1xyXG4gICAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJJbmRleGVkRGJBdWRpb0J1ZmZlclNvdXJjZU5vZGU6IEJ1ZmZlciBub3RpZmljYXRpb246IGZpbGxlZCBmcmFtZXM6IFwiICsgdGhpcy5maWxsZWRGcmFtZXMpO1xyXG4gICAgICAgICAgICBpZighdGhpcy5fZW5kT2ZTdHJlYW0pIHtcclxuICAgICAgICAgICAgICB0aGlzLmZpbGxCdWZmZXJPYnMoKS5zdWJzY3JpYmUoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIGlmICgnZW5kZWQnID09PSBldlR5cGUpIHtcclxuICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiSW5kZGIgYXVkaW8gc291cmNlIGVuZGVkIHBsYXliYWNrLlwiKTtcclxuICAgICAgICAgICAgbGV0IGRyYWluVGltZSA9IDA7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLl9uZXRBdWRpb0J1ZmZlcj8uc2FtcGxlUmF0ZSkge1xyXG4gICAgICAgICAgICAgIGRyYWluVGltZSA9IEFycmF5QXVkaW9CdWZmZXJTb3VyY2VOb2RlLlFVQU5UVU1fRlJBTUVfTEVOIC8gdGhpcy5fbmV0QXVkaW9CdWZmZXIuc2FtcGxlUmF0ZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAvL2xldCBkc3RBbnk6YW55PXRoaXMuY29udGV4dC5kZXN0aW5hdGlvbjtcclxuICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKCdEZXN0aW5hdGlvbiBub2RlIHRhaWwtdGltZTogJytkc3RBbnlbJ3RhaWwtdGltZSddKTtcclxuICAgICAgICAgICAgd2luZG93LnNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgICAgICAgIHRoaXMuc3RvcEVuZFRpbWU9dGhpcy5jb250ZXh0LmN1cnJlbnRUaW1lO1xyXG4gICAgICAgICAgICAgIHRoaXMuX2FjdGl2ZT1mYWxzZTtcclxuICAgICAgICAgICAgICB0aGlzLm9uZW5kZWQ/LmNhbGwodGhpcyk7XHJcbiAgICAgICAgICAgIH0sIGRyYWluVGltZSAqIDEwMDApO1xyXG5cclxuICAgICAgICAgIH1lbHNlIGlmICgnc3RhbGxlZCcgPT09IGV2VHlwZSkge1xyXG4gICAgICAgICAgICBjb25zb2xlLmRlYnVnKCdQbGF5YmFjayBzdGFsbGVkLi4uJyk7XHJcbiAgICAgICAgICAgIHRoaXMuc3RhbGxlZD10cnVlO1xyXG4gICAgICAgICAgICB0aGlzLnN0YWxsZWRTdGFydFRpbWU9dGhpcy5jb250ZXh0LmN1cnJlbnRUaW1lO1xyXG4gICAgICAgICAgfWVsc2UgaWYgKCdyZXN1bWVkJyA9PT0gZXZUeXBlKSB7XHJcbiAgICAgICAgICAgIGNvbnNvbGUuZGVidWcoJ1BsYXliYWNrIHJlc3VtZWQgYWZ0ZXIgc3RhbGwuJyk7XHJcbiAgICAgICAgICAgIHRoaXMuc3RhbGxlZD1mYWxzZTtcclxuICAgICAgICAgICAgaWYodGhpcy5zdGFsbGVkU3RhcnRUaW1lIT1udWxsKSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5zdGFsbGVkVGltZSArPSB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUgLSB0aGlzLnN0YWxsZWRTdGFydFRpbWU7XHJcbiAgICAgICAgICAgICAgdGhpcy5zdGFsbGVkU3RhcnRUaW1lID0gbnVsbDtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBmaWxsQnVmZmVyT2JzKGZyYW1lT2Zmc2V0PzpudW1iZXIpOk9ic2VydmFibGU8bnVtYmVyfG51bGw+IHtcclxuXHJcbiAgICAgIHJldHVybiBuZXcgT2JzZXJ2YWJsZTxudW1iZXIgfCBudWxsPihzdWJzY3JpYmVyID0+IHtcclxuICAgICAgICBpZihmcmFtZU9mZnNldCl7XHJcbiAgICAgICAgICBzdWJzY3JpYmVyLmVycm9yKG5ldyBFcnJvcihcIlN0YXJ0aW5nIHBsYXliYWNrIGZyb20gcG9zaXRpb24gbm90IGVxdWFsIHplcm8gbm90IHN1cHBvcnRlZCB5ZXQuXCIpKTtcclxuICAgICAgICB9ZWxzZSB7XHJcbiAgICAgICAgICBsZXQgZmlsbGVkID0gdGhpcy5maWxsZWRGcmFtZXM7XHJcbiAgICAgICAgICBsZXQgYnVmTGVuID0gMDtcclxuICAgICAgICAgIGlmICh0aGlzLl9hdWRpb0lucHV0U3RyZWFtICYmIHRoaXMuX2Fpc0J1ZnMgJiYgKHRoaXMucmVhZERhdGFTdWJzY3JpcHRpb249PW51bGwgfHwgdGhpcy5yZWFkRGF0YVN1YnNjcmlwdGlvbj8uY2xvc2VkKSkge1xyXG4gICAgICAgICAgICB0aGlzLnJlYWREYXRhU3Vic2NyaXB0aW9uPXRoaXMuX2F1ZGlvSW5wdXRTdHJlYW0ucmVhZE9icyh0aGlzLl9haXNCdWZzKS5waXBlKFxyXG4gICAgICAgICAgICAgIGV4cGFuZCgocmVhZCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICBpZiAocmVhZCAmJiB0aGlzLl9haXNCdWZzKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgbGV0IHRyQnVmZmVycyA9IG5ldyBBcnJheTxhbnk+KHRoaXMuY2hhbm5lbENvdW50KTtcclxuICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBjaCA9IDA7IGNoIDwgdGhpcy5jaGFubmVsQ291bnQ7IGNoKyspIHtcclxuICAgICAgICAgICAgICAgICAgICAgIGxldCBhZENoID0gdGhpcy5fYWlzQnVmc1tjaF07XHJcbiAgICAgICAgICAgICAgICAgICAgICBsZXQgYWRDaENvcHkgPSBuZXcgRmxvYXQzMkFycmF5KHJlYWQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgYnVmTGVuID0gYWRDaENvcHkubGVuZ3RoO1xyXG4gICAgICAgICAgICAgICAgICAgICAgaWYocmVhZD09PWFkQ2gubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGFkQ2hDb3B5LnNldChhZENoKTtcclxuICAgICAgICAgICAgICAgICAgICAgIH1lbHNle1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBOb3RlOiBzbGljZSgpIGRvZXMgbm90IHdvcmsgaGVyZSwgc2luY2UgaXQgcmV0dXJucyBhIHNoYWxsb3cgY29weS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgZm9yKGxldCBpPTA7aTxyZWFkO2krKyl7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgYWRDaENvcHlbaV09YWRDaFtpXTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgdHJCdWZmZXJzW2NoXSA9IGFkQ2hDb3B5LmJ1ZmZlcjtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wb3J0LnBvc3RNZXNzYWdlKHtcclxuICAgICAgICAgICAgICAgICAgICAgIGNtZDogJ2RhdGEnLFxyXG4gICAgICAgICAgICAgICAgICAgICAgY2hzOiB0aGlzLmNoYW5uZWxDb3VudCxcclxuICAgICAgICAgICAgICAgICAgICAgIGF1ZGlvRGF0YTogdHJCdWZmZXJzXHJcbiAgICAgICAgICAgICAgICAgICAgfSwgdHJCdWZmZXJzKTtcclxuICAgICAgICAgICAgICAgICAgICBmaWxsZWQgKz0gcmVhZDtcclxuICAgICAgICAgICAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJJbmRleGVkRGJBdWRpb0J1ZmZlclNvdXJjZU5vZGU6OmZpbGxCdWZmZXJPYnM6IFNlbnQgXCIrcmVhZCtcIiBmcmFtZXMgdG8gYXVkaW8gc291cmNlIHdvcmtsZXQuIEZpbGxlZDogXCIrZmlsbGVkK1wiLCB0byBmaWxsOiBcIit0aGlzLmJ1ZmZlckZpbGxGcmFtZXMpO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLl9hdWRpb0lucHV0U3RyZWFtICYmIGZpbGxlZCA8IHRoaXMuYnVmZmVyRmlsbEZyYW1lcykge1xyXG4gICAgICAgICAgICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiSW5kZXhlZERiQXVkaW9CdWZmZXJTb3VyY2VOb2RlOjpmaWxsQnVmZmVyT2JzOiBOZXh0IGluZGRiIGF1ZGlvIGlucHV0IHN0cmVhbSByZWFkT2JzXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2F1ZGlvSW5wdXRTdHJlYW0ucmVhZE9icyh0aGlzLl9haXNCdWZzKTtcclxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgaWYodGhpcy5zdGFsbGVkKXtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wb3J0LnBvc3RNZXNzYWdlKHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICBjbWQ6ICdjb250aW51ZSdcclxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIEVNUFRZO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJJbmRleGVkRGJBdWRpb0J1ZmZlclNvdXJjZU5vZGU6OmZpbGxCdWZmZXJPYnM6IFJldHVybiBFTVBUWSAocmVhZDogXCIrcmVhZCtcIilcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fZW5kT2ZTdHJlYW09dHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnBvcnQucG9zdE1lc3NhZ2Uoe1xyXG4gICAgICAgICAgICAgICAgICAgICAgY21kOiAnZW5kT2ZTdHJlYW0nXHJcbiAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIEVNUFRZO1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICApLnN1YnNjcmliZShzdWJzY3JpYmVyKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gIH1cclxuXHJcblxyXG4gIGdldCBuZXRBdWRpb0J1ZmZlcigpOiBOZXRBdWRpb0J1ZmZlciB8IG51bGwge1xyXG4gICAgcmV0dXJuIHRoaXMuX25ldEF1ZGlvQnVmZmVyXHJcbiAgfVxyXG5cclxuICBzZXQgbmV0QXVkaW9CdWZmZXIodmFsdWU6IE5ldEF1ZGlvQnVmZmVyIHwgbnVsbCkge1xyXG4gICAgdGhpcy5fbmV0QXVkaW9CdWZmZXIgPSB2YWx1ZTtcclxuICAgIGlmICh0aGlzLl9uZXRBdWRpb0J1ZmZlcj8uY2hhbm5lbENvdW50KSB7XHJcbiAgICAgIHRoaXMuY2hhbm5lbENvdW50ID0gdGhpcy5fbmV0QXVkaW9CdWZmZXI/LmNoYW5uZWxDb3VudDtcclxuICAgICAgdGhpcy5idWZmZXJGaWxsRnJhbWVzID0gdGhpcy5fbmV0QXVkaW9CdWZmZXIuc2FtcGxlUmF0ZSAqIHRoaXMuX2J1ZmZlckZpbGxTZWNvbmRzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZ2V0IGJ1ZmZlckZpbGxTZWNvbmRzKCk6IG51bWJlciB7XHJcbiAgICByZXR1cm4gdGhpcy5fYnVmZmVyRmlsbFNlY29uZHM7XHJcbiAgfVxyXG5cclxuICBzZXQgYnVmZmVyRmlsbFNlY29uZHModmFsdWU6IG51bWJlcikge1xyXG4gICAgdGhpcy5fYnVmZmVyRmlsbFNlY29uZHMgPSB2YWx1ZTtcclxuICB9XHJcblxyXG4gIHN0YXJ0KHdoZW4/OiBudW1iZXIgfCB1bmRlZmluZWQsb2Zmc2V0PzogbnVtYmVyIHwgdW5kZWZpbmVkLGR1cmF0aW9uPzogbnVtYmVyIHwgdW5kZWZpbmVkKTogdm9pZCB7XHJcbiAgICBpZiAod2hlbikge1xyXG4gICAgICB0aHJvdyBFcnJvcihcIndoZW4gcGFyYW1ldGVyIGN1cnJlbnRseSBub3Qgc3VwcG9ydGVkIGJ5IEluZGV4ZWREYkF1ZGlvQnVmZmVyU291cmNlTm9kZSBjbGFzc1wiKVxyXG4gICAgfVxyXG4gICAgdGhpcy5fcGxheVN0YXJ0VGltZT1udWxsO1xyXG4gICAgdGhpcy5zdG9wRW5kVGltZT1udWxsO1xyXG4gICAgdGhpcy5zdGFsbGVkVGltZT0wO1xyXG4gICAgdGhpcy5zdGFsbGVkU3RhcnRUaW1lPW51bGw7XHJcblxyXG4gICAgaWYgKHRoaXMuX25ldEF1ZGlvQnVmZmVyKSB7XHJcbiAgICAgIGxldCBhcnJBaXM9bmV3IE5ldEF1ZGlvSW5wdXRTdHJlYW0odGhpcy5fbmV0QXVkaW9CdWZmZXIpO1xyXG4gICAgICBpZihvZmZzZXQ9PT11bmRlZmluZWQgJiYgZHVyYXRpb249PT11bmRlZmluZWQpe1xyXG4gICAgICAgIHRoaXMuX2F1ZGlvSW5wdXRTdHJlYW0gPSBhcnJBaXM7XHJcbiAgICAgIH1lbHNle1xyXG4gICAgICAgIGxldCBvZmZzZXRGcmFtZXM9MDtcclxuICAgICAgICBsZXQgZHVyYXRpb25GcmFtZXM9dW5kZWZpbmVkO1xyXG4gICAgICAgIGlmKG9mZnNldCE9PXVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgb2Zmc2V0RnJhbWVzPU1hdGguZmxvb3Iob2Zmc2V0ICogdGhpcy5fbmV0QXVkaW9CdWZmZXIuc2FtcGxlUmF0ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmKGR1cmF0aW9uIT09dW5kZWZpbmVkKXtcclxuICAgICAgICAgIGR1cmF0aW9uRnJhbWVzPU1hdGguZmxvb3IoZHVyYXRpb24gKiB0aGlzLl9uZXRBdWRpb0J1ZmZlci5zYW1wbGVSYXRlKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgLy9jb25zb2xlLmVycm9yKFwiUGxheWJhY2sgc2VsZWN0aW9uIG5vdCBzdXBwb3J0ZWQgeWV0IVwiKTtcclxuICAgICAgICB0aGlzLl9hdWRpb0lucHV0U3RyZWFtPW5ldyBBc3luY0VkaXRGbG9hdDMyQXJyYXlJbnB1dFN0cmVhbShhcnJBaXMsb2Zmc2V0RnJhbWVzLGR1cmF0aW9uRnJhbWVzKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgbGV0IGNocz10aGlzLl9uZXRBdWRpb0J1ZmZlci5jaGFubmVsQ291bnQ7XHJcbiAgICAgIHRoaXMuX2Fpc0J1ZnM9bmV3IEFycmF5PEZsb2F0MzJBcnJheT4oY2hzKTtcclxuICAgICAgZm9yKGxldCBjaD0wO2NoPGNocztjaCsrKXtcclxuICAgICAgICB0aGlzLl9haXNCdWZzW2NoXT1uZXcgRmxvYXQzMkFycmF5KHRoaXMuX3N0cmVhbVJlYWRGcmFtZUxlbik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMuZmlsbEJ1ZmZlck9icygpLnN1YnNjcmliZSh7XHJcbiAgICAgICAgY29tcGxldGU6ICgpPT57XHJcbiAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJJbmRleGVkRGJBdWRpb0J1ZmZlclNvdXJjZU5vZGU6OnN0YXJ0OiBBc3luYyBwbGF5IGJ1ZmZlciBmaWxsIGNvbXBsZXRlZC4gU2VuZGluZyBzdGFydCBjb21tYW5kIHRvIGF1ZGlvIHdvcmtsZXQuXCIpO1xyXG4gICAgICAgICAgaWYodGhpcy5fYWN0aXZlKSB7XHJcbiAgICAgICAgICAgIHRoaXMucG9ydC5wb3N0TWVzc2FnZSh7Y21kOiAnc3RhcnQnfSk7XHJcbiAgICAgICAgICAgIGlmKG9mZnNldCkge1xyXG4gICAgICAgICAgICAgIHRoaXMuX3BsYXlTdGFydFRpbWUgPSB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUgLSBvZmZzZXQ7XHJcbiAgICAgICAgICAgIH1lbHNle1xyXG4gICAgICAgICAgICAgIHRoaXMuX3BsYXlTdGFydFRpbWUgPSB0aGlzLmNvbnRleHQuY3VycmVudFRpbWU7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0pXHJcbiAgICAgIHRoaXMuX2FjdGl2ZT10cnVlO1xyXG5cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHN0b3AoKSB7XHJcbiAgICB0aGlzLl9hY3RpdmU9ZmFsc2U7XHJcbiAgICB0aGlzLnBvcnQucG9zdE1lc3NhZ2Uoe2NtZDogJ3N0b3AnfSk7XHJcbiAgICB0aGlzLm9uZW5kZWQ/LmNhbGwodGhpcyk7XHJcbiAgfVxyXG5cclxuICBnZXQgcGxheVBvc2l0aW9uVGltZSgpOm51bWJlcnxudWxsIHtcclxuICAgIGxldCBwcHQ6bnVtYmVyfG51bGw9bnVsbDtcclxuICAgIGlmKHRoaXMuX3BsYXlTdGFydFRpbWUhPT1udWxsKSB7XHJcbiAgICAgIGlmKHRoaXMuX2FjdGl2ZSkge1xyXG4gICAgICAgIGlmICh0aGlzLnN0YWxsZWRTdGFydFRpbWUgPT0gbnVsbCkge1xyXG4gICAgICAgICAgcHB0ID0gdGhpcy5jb250ZXh0LmN1cnJlbnRUaW1lIC0gdGhpcy5fcGxheVN0YXJ0VGltZSAtIHRoaXMuc3RhbGxlZFRpbWU7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHBwdCA9IHRoaXMuc3RhbGxlZFN0YXJ0VGltZSAtIHRoaXMuX3BsYXlTdGFydFRpbWUgLSB0aGlzLnN0YWxsZWRUaW1lO1xyXG4gICAgICAgIH1cclxuICAgICAgfWVsc2V7XHJcbiAgICAgICAgaWYodGhpcy5zdG9wRW5kVGltZSE9bnVsbCl7XHJcbiAgICAgICAgICAvLyBpZih0aGlzLl9uZXRBdWRpb0J1ZmZlcj8uZnJhbWVMZW4gIT1udWxsICYmIHRoaXMuX25ldEF1ZGlvQnVmZmVyLnNhbXBsZVJhdGUpIHtcclxuICAgICAgICAgIC8vICAgcHB0ID0gdGhpcy5fbmV0QXVkaW9CdWZmZXI/LmZyYW1lTGVuIC8gdGhpcy5fbmV0QXVkaW9CdWZmZXI/LnNhbXBsZVJhdGU7XHJcbiAgICAgICAgICAvLyB9ZWxzZXtcclxuICAgICAgICAgICAgcHB0ID0gdGhpcy5zdG9wRW5kVGltZSAtIHRoaXMuX3BsYXlTdGFydFRpbWUgLSB0aGlzLnN0YWxsZWRUaW1lO1xyXG4gICAgICAgICAgLy99XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gcHB0O1xyXG4gIH1cclxuXHJcbn1cclxuXHJcbiJdfQ==