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