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