speechrecorderng 2.21.8 → 2.22.3
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/esm2020/lib/media/utils.mjs +14 -0
- package/esm2020/lib/net/uploader.mjs +31 -5
- package/esm2020/lib/speechrecorder/recording.mjs +23 -6
- package/esm2020/lib/speechrecorder/recordings/recordings.service.mjs +89 -16
- package/esm2020/lib/speechrecorder/session/audiorecorder.mjs +1164 -0
- package/esm2020/lib/speechrecorder/session/controlpanel.mjs +9 -6
- package/esm2020/lib/speechrecorder/session/item.mjs +1 -1
- package/esm2020/lib/speechrecorder/session/recorder_combi_pane.mjs +82 -0
- package/esm2020/lib/speechrecorder/session/recording_list.mjs +138 -0
- package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-meta.component.mjs +57 -14
- package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-u-i.component.mjs +14 -8
- package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-view.component.mjs +48 -18
- package/esm2020/lib/speechrecorder/session/recordingfile/recording-file.mjs +1 -1
- package/esm2020/lib/speechrecorder/session/recordingfile/recordingfile-service.mjs +61 -1
- package/esm2020/lib/speechrecorder/session/sessionmanager.mjs +15 -8
- package/esm2020/lib/speechrecorderng.component.mjs +1 -1
- package/esm2020/lib/speechrecorderng.module.mjs +8 -4
- package/esm2020/lib/spr.module.version.mjs +2 -2
- package/esm2020/public-api.mjs +3 -2
- package/fesm2015/speechrecorderng.mjs +1699 -86
- package/fesm2015/speechrecorderng.mjs.map +1 -1
- package/fesm2020/speechrecorderng.mjs +1695 -86
- package/fesm2020/speechrecorderng.mjs.map +1 -1
- package/lib/media/utils.d.ts +3 -0
- package/lib/net/uploader.d.ts +4 -2
- package/lib/speechrecorder/recording.d.ts +15 -3
- package/lib/speechrecorder/recordings/recordings.service.d.ts +12 -5
- package/lib/speechrecorder/session/audiorecorder.d.ts +150 -0
- package/lib/speechrecorder/session/controlpanel.d.ts +2 -1
- package/lib/speechrecorder/session/item.d.ts +2 -2
- package/lib/speechrecorder/session/recorder_combi_pane.d.ts +27 -0
- package/lib/speechrecorder/session/recording_list.d.ts +21 -0
- package/lib/speechrecorder/session/recordingfile/recording-file-meta.component.d.ts +6 -2
- package/lib/speechrecorder/session/recordingfile/recording-file-view.component.d.ts +5 -4
- package/lib/speechrecorder/session/recordingfile/recording-file.d.ts +2 -2
- package/lib/speechrecorder/session/recordingfile/recordingfile-service.d.ts +5 -3
- package/lib/speechrecorder/session/sessionmanager.d.ts +5 -5
- package/lib/speechrecorderng.module.d.ts +31 -28
- package/lib/spr.module.version.d.ts +1 -1
- package/package.json +1 -1
- package/public-api.d.ts +2 -1
|
@@ -0,0 +1,1164 @@
|
|
|
1
|
+
import { Action } from '../../action/action';
|
|
2
|
+
import { AudioCapture } from '../../audio/capture/capture';
|
|
3
|
+
import { AudioPlayer, EventType } from '../../audio/playback/player';
|
|
4
|
+
import { WavWriter } from '../../audio/impl/wavwriter';
|
|
5
|
+
import { RecordingFile } from '../recording';
|
|
6
|
+
import { Component, ViewChild, Inject, HostListener, Input } from "@angular/core";
|
|
7
|
+
import { SessionService } from "./session.service";
|
|
8
|
+
import { SPEECHRECORDER_CONFIG } from "../../spr.config";
|
|
9
|
+
import { ProjectUtil } from "../project/project";
|
|
10
|
+
import { LevelMeasure, StreamLevelMeasure } from "../../audio/dsp/level_measure";
|
|
11
|
+
import { SequenceAudioFloat32ChunkerOutStream } from "../../audio/io/stream";
|
|
12
|
+
import { TransportActions } from "./controlpanel";
|
|
13
|
+
import { MessageDialog } from "../../ui/message_dialog";
|
|
14
|
+
import { AudioContextProvider } from "../../audio/context";
|
|
15
|
+
import { AudioClip } from "../../audio/persistor";
|
|
16
|
+
import { Upload, UploaderStatus } from "../../net/uploader";
|
|
17
|
+
import { UUID } from "../../utils/utils";
|
|
18
|
+
import { MIN_DB_LEVEL } from "../../ui/recordingitem_display";
|
|
19
|
+
import { LevelBar } from "../../audio/ui/livelevel";
|
|
20
|
+
import { RecorderCombiPane } from "./recorder_combi_pane";
|
|
21
|
+
import * as i0 from "@angular/core";
|
|
22
|
+
import * as i1 from "@angular/router";
|
|
23
|
+
import * as i2 from "@angular/material/dialog";
|
|
24
|
+
import * as i3 from "../project/project.service";
|
|
25
|
+
import * as i4 from "./session.service";
|
|
26
|
+
import * as i5 from "../recordings/recordings.service";
|
|
27
|
+
import * as i6 from "../spruploader";
|
|
28
|
+
import * as i7 from "./warning_bar";
|
|
29
|
+
import * as i8 from "./recorder_combi_pane";
|
|
30
|
+
import * as i9 from "../../audio/ui/livelevel";
|
|
31
|
+
import * as i10 from "../../ui/recordingitem_display";
|
|
32
|
+
import * as i11 from "./controlpanel";
|
|
33
|
+
import * as i12 from "@angular/material/button";
|
|
34
|
+
import * as i13 from "@angular/material/icon";
|
|
35
|
+
import * as i14 from "@angular/flex-layout/flex";
|
|
36
|
+
import * as i15 from "@angular/flex-layout/extended";
|
|
37
|
+
import * as i16 from "@angular/common";
|
|
38
|
+
import * as i17 from "../../spr.config";
|
|
39
|
+
export const RECFILE_API_CTX = 'recfile';
|
|
40
|
+
const MAX_RECORDING_TIME_MS = 1000 * 60 * 60 * 60; // 1 hour
|
|
41
|
+
const LEVEL_BAR_INTERVALL_SECONDS = 0.1; // 100ms
|
|
42
|
+
export class Item {
|
|
43
|
+
constructor(promptAsString, training) {
|
|
44
|
+
this.promptAsString = promptAsString;
|
|
45
|
+
this.training = training;
|
|
46
|
+
this.recs = null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// TODO enum not possible in template language , use string for now
|
|
50
|
+
//export enum StatusAlertType {INFO,WARN,ERROR};
|
|
51
|
+
export class AudioRecorder {
|
|
52
|
+
constructor(changeDetectorRef, route, renderer, dialog, projectService, sessionService, recFileService, uploader, config) {
|
|
53
|
+
this.changeDetectorRef = changeDetectorRef;
|
|
54
|
+
this.route = route;
|
|
55
|
+
this.renderer = renderer;
|
|
56
|
+
this.dialog = dialog;
|
|
57
|
+
this.projectService = projectService;
|
|
58
|
+
this.sessionService = sessionService;
|
|
59
|
+
this.recFileService = recFileService;
|
|
60
|
+
this.uploader = uploader;
|
|
61
|
+
this.config = config;
|
|
62
|
+
this._project = null;
|
|
63
|
+
this.projectName = null;
|
|
64
|
+
this.enableUploadRecordings = true;
|
|
65
|
+
this.enableDownloadRecordings = false;
|
|
66
|
+
this.status = 0 /* BLOCKED */;
|
|
67
|
+
this.ac = null;
|
|
68
|
+
this._channelCount = 2; //TODO define constant for default format
|
|
69
|
+
this.dataSaved = true;
|
|
70
|
+
this.startedDate = null;
|
|
71
|
+
this.maxRecTimerId = null;
|
|
72
|
+
this.maxRecTimerRunning = false;
|
|
73
|
+
this._session = null;
|
|
74
|
+
this._promptIndex = null;
|
|
75
|
+
//items: Array<Item>|null=null;
|
|
76
|
+
//selectedItemIdx: number;
|
|
77
|
+
this._displayRecFile = null;
|
|
78
|
+
this.displayRecFileVersion = 0;
|
|
79
|
+
this.displayAudioClip = null;
|
|
80
|
+
this.displayLevelInfos = null;
|
|
81
|
+
this.peakLevelInDb = MIN_DB_LEVEL;
|
|
82
|
+
this.readonly = false;
|
|
83
|
+
this.statusMsg = '';
|
|
84
|
+
this.statusWaiting = false;
|
|
85
|
+
this.processingRecording = false;
|
|
86
|
+
this.uploadProgress = 100;
|
|
87
|
+
this.uploadStatus = 'ok';
|
|
88
|
+
this.audioSignalCollapsed = true;
|
|
89
|
+
this.audioFetchSubscription = null;
|
|
90
|
+
this.destroyed = false;
|
|
91
|
+
this.navigationDisabled = true;
|
|
92
|
+
this.status = 1 /* IDLE */;
|
|
93
|
+
this.transportActions = new TransportActions();
|
|
94
|
+
this.playStartAction = new Action('Play');
|
|
95
|
+
this.audio = document.getElementById('audio');
|
|
96
|
+
this.selCaptureDeviceId = null;
|
|
97
|
+
this.levelMeasure = new LevelMeasure();
|
|
98
|
+
this.streamLevelMeasure = new StreamLevelMeasure();
|
|
99
|
+
if (this.config && this.config.enableUploadRecordings != null) {
|
|
100
|
+
this.enableUploadRecordings = this.config.enableUploadRecordings;
|
|
101
|
+
}
|
|
102
|
+
if (this.config && this.config.enableDownloadRecordings != null) {
|
|
103
|
+
this.enableDownloadRecordings = this.config.enableDownloadRecordings;
|
|
104
|
+
}
|
|
105
|
+
this.init();
|
|
106
|
+
}
|
|
107
|
+
ngAfterViewInit() {
|
|
108
|
+
this.route.queryParams.subscribe((params) => {
|
|
109
|
+
if (params['sessionId']) {
|
|
110
|
+
this.fetchSession(params['sessionId']);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
this.streamLevelMeasure.levelListener = this.liveLevelDisplay;
|
|
114
|
+
this.streamLevelMeasure.peakLevelListener = (peakLvlInDb) => {
|
|
115
|
+
this.peakLevelInDb = peakLvlInDb;
|
|
116
|
+
this.changeDetectorRef.detectChanges();
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
ngOnDestroy() {
|
|
120
|
+
this.destroyed = true;
|
|
121
|
+
// TODO stop capture /playback
|
|
122
|
+
}
|
|
123
|
+
init() {
|
|
124
|
+
this.transportActions.startAction.disabled = true;
|
|
125
|
+
this.transportActions.stopAction.disabled = true;
|
|
126
|
+
this.transportActions.nextAction.disabled = true;
|
|
127
|
+
this.transportActions.pauseAction.disabled = true;
|
|
128
|
+
this.playStartAction.disabled = true;
|
|
129
|
+
let context = null;
|
|
130
|
+
try {
|
|
131
|
+
context = AudioContextProvider.audioContextInstance();
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
this.status = 4 /* ERROR */;
|
|
135
|
+
let errMsg = 'Unknown';
|
|
136
|
+
if (err instanceof Error) {
|
|
137
|
+
errMsg = err.message;
|
|
138
|
+
}
|
|
139
|
+
this.statusMsg = 'ERROR: ' + errMsg;
|
|
140
|
+
this.statusAlertType = 'error';
|
|
141
|
+
this.dialog.open(MessageDialog, {
|
|
142
|
+
data: {
|
|
143
|
+
type: 'error',
|
|
144
|
+
title: 'Error',
|
|
145
|
+
msg: errMsg,
|
|
146
|
+
advise: 'Please use a supported browser.',
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (context) {
|
|
152
|
+
console.info("State of audio context: " + context.state);
|
|
153
|
+
}
|
|
154
|
+
if (!context || !navigator.mediaDevices) {
|
|
155
|
+
this.status = 4 /* ERROR */;
|
|
156
|
+
let errMsg = 'Browser does not support Media streams!';
|
|
157
|
+
this.statusMsg = 'ERROR: ' + errMsg;
|
|
158
|
+
this.statusAlertType = 'error';
|
|
159
|
+
this.dialog.open(MessageDialog, {
|
|
160
|
+
data: {
|
|
161
|
+
type: 'error',
|
|
162
|
+
title: 'Error',
|
|
163
|
+
msg: errMsg,
|
|
164
|
+
advise: 'Please use a supported browser.',
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
this.controlAudioPlayer = new AudioPlayer(context, this);
|
|
171
|
+
this.ac = new AudioCapture(context);
|
|
172
|
+
if (this.ac) {
|
|
173
|
+
this.transportActions.startAction.onAction = () => this.startItem();
|
|
174
|
+
this.ac.listener = this;
|
|
175
|
+
this.ac.audioOutStream = new SequenceAudioFloat32ChunkerOutStream(this.streamLevelMeasure, LEVEL_BAR_INTERVALL_SECONDS);
|
|
176
|
+
// Don't list the devices here. If we do not have audio permissions we only get anonymized devices without labels.
|
|
177
|
+
//this.ac.listDevices();
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
this.transportActions.startAction.disabled = true;
|
|
181
|
+
let errMsg = 'Browser does not support Media/Audio API!';
|
|
182
|
+
this.statusMsg = 'ERROR: ' + errMsg;
|
|
183
|
+
this.statusAlertType = 'error';
|
|
184
|
+
this.dialog.open(MessageDialog, {
|
|
185
|
+
data: {
|
|
186
|
+
type: 'error',
|
|
187
|
+
title: 'Error',
|
|
188
|
+
msg: errMsg,
|
|
189
|
+
advise: 'Please use a supported browser.',
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
this.transportActions.stopAction.onAction = () => this.stopItem();
|
|
195
|
+
this.transportActions.nextAction.onAction = () => this.stopItem();
|
|
196
|
+
//this.transportActions.pauseAction.onAction = () => this.pauseItem();
|
|
197
|
+
this.playStartAction.onAction = () => this.controlAudioPlayer.start();
|
|
198
|
+
}
|
|
199
|
+
this.uploader.listener = (ue) => {
|
|
200
|
+
this.uploadUpdate(ue);
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
onKeyPress(ke) {
|
|
204
|
+
if (ke.key == ' ') {
|
|
205
|
+
//this.transportActions.startAction.perform();
|
|
206
|
+
//this.transportActions.nextAction.perform();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
onKeyDown(ke) {
|
|
210
|
+
if (ke.key == ' ') {
|
|
211
|
+
if (!this.transportActions.startAction.disabled) {
|
|
212
|
+
this.transportActions.startAction.perform();
|
|
213
|
+
}
|
|
214
|
+
else if (!this.transportActions.stopAction.disabled) {
|
|
215
|
+
this.transportActions.stopAction.perform();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (ke.key == 'p') {
|
|
219
|
+
this.transportActions.pauseAction.perform();
|
|
220
|
+
}
|
|
221
|
+
if (ke.key == 'Escape') {
|
|
222
|
+
if (!this.audioSignalCollapsed) {
|
|
223
|
+
this.audioSignalCollapsed = true;
|
|
224
|
+
}
|
|
225
|
+
this.transportActions.stopAction.perform();
|
|
226
|
+
this.transportActions.pauseAction.perform();
|
|
227
|
+
}
|
|
228
|
+
if (ke.key == 'MediaPlayPause') {
|
|
229
|
+
this.playStartAction.perform();
|
|
230
|
+
}
|
|
231
|
+
if (ke.key === 'ArrowRight') {
|
|
232
|
+
this.transportActions.fwdAction.perform();
|
|
233
|
+
}
|
|
234
|
+
if (ke.key === 'ArrowLeft') {
|
|
235
|
+
this.transportActions.bwdAction.perform();
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
isTestSession() {
|
|
239
|
+
return ((this._session != null) && (this._session.type === 'TEST' || this._session.type === 'TEST_DEF_A' || this._session.type === 'SINUS_TEST'));
|
|
240
|
+
}
|
|
241
|
+
isDefaultAudioTestSession() {
|
|
242
|
+
return ((this._session != null) && (this._session.type === 'TEST_DEF_A'));
|
|
243
|
+
}
|
|
244
|
+
isDefaultAudioTestSessionOverwriteingProjectRequirements() {
|
|
245
|
+
return ((this._session != null) && (this._session.type === 'TEST_DEF_A') && (this.audioDevices != null) && this.audioDevices.length > 0);
|
|
246
|
+
}
|
|
247
|
+
fetchSession(sessionId) {
|
|
248
|
+
//Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'statusMsg: Player initialized.'. Current value: 'statusMsg: Fetching session info...'.
|
|
249
|
+
// params.subscribe seems not to be asynchronous
|
|
250
|
+
// this.sm.statusAlertType='info';
|
|
251
|
+
// this.sm.statusMsg = 'Fetching session info...';
|
|
252
|
+
// this.sm.statusWaiting=true;
|
|
253
|
+
let sessObs = this.sessionService.sessionObserver(sessionId);
|
|
254
|
+
if (sessObs) {
|
|
255
|
+
sessObs.subscribe(sess => {
|
|
256
|
+
//this.setSession(sess);
|
|
257
|
+
this.statusAlertType = 'info';
|
|
258
|
+
this.statusMsg = 'Received session info.';
|
|
259
|
+
this.statusWaiting = false;
|
|
260
|
+
this.session = sess;
|
|
261
|
+
if (sess.project) {
|
|
262
|
+
//console.debug("Session associated project: "+sess.project)
|
|
263
|
+
this.projectService.projectObservable(sess.project).subscribe(project => {
|
|
264
|
+
this.project = project;
|
|
265
|
+
this.fetchRecordings(sess);
|
|
266
|
+
}, reason => {
|
|
267
|
+
this.statusMsg = reason;
|
|
268
|
+
this.statusAlertType = 'error';
|
|
269
|
+
this.statusWaiting = false;
|
|
270
|
+
console.error("Error fetching project config: " + reason);
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
console.info("Session has no associated project. Using default configuration.");
|
|
275
|
+
}
|
|
276
|
+
}, (reason) => {
|
|
277
|
+
this.statusMsg = reason;
|
|
278
|
+
this.statusAlertType = 'error';
|
|
279
|
+
this.statusWaiting = false;
|
|
280
|
+
console.error("Error fetching session " + reason);
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
fetchRecordings(sess) {
|
|
285
|
+
this.statusAlertType = 'info';
|
|
286
|
+
this.statusMsg = 'Fetching infos of recordings...';
|
|
287
|
+
this.statusWaiting = true;
|
|
288
|
+
let prNm = null;
|
|
289
|
+
if (this.project) {
|
|
290
|
+
let rfsObs = this.recFileService.recordingFileList(this.project.name, sess.sessionId);
|
|
291
|
+
rfsObs.subscribe((rfs) => {
|
|
292
|
+
this.statusAlertType = 'info';
|
|
293
|
+
this.statusMsg = 'Received infos of recordings.';
|
|
294
|
+
this.statusWaiting = false;
|
|
295
|
+
if (rfs) {
|
|
296
|
+
if (rfs instanceof Array) {
|
|
297
|
+
rfs.forEach((rf) => {
|
|
298
|
+
if (rf.startedDate) {
|
|
299
|
+
rf._startedAsDateObj = new Date(rf.startedDate);
|
|
300
|
+
}
|
|
301
|
+
if (rf.date) {
|
|
302
|
+
rf._dateAsDateObj = new Date(rf.date);
|
|
303
|
+
}
|
|
304
|
+
this.recorderCombiPane.push(rf);
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
console.error('Expected type array for list of already recorded files ');
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
//console.debug("Recording file list: " + rfs);
|
|
313
|
+
}
|
|
314
|
+
}, () => {
|
|
315
|
+
// Failed fetching existing, but we start the session anyway
|
|
316
|
+
this.start();
|
|
317
|
+
}, () => {
|
|
318
|
+
// Normal start
|
|
319
|
+
this.start();
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
// No project def -> error
|
|
324
|
+
this.statusAlertType = 'error';
|
|
325
|
+
this.statusMsg = 'No project definiton.';
|
|
326
|
+
this.statusWaiting = false;
|
|
327
|
+
console.error(this.statusMsg);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
set project(project) {
|
|
331
|
+
this._project = project;
|
|
332
|
+
let chCnt = ProjectUtil.DEFAULT_AUDIO_CHANNEL_COUNT;
|
|
333
|
+
if (project) {
|
|
334
|
+
console.info("Project name: " + project.name);
|
|
335
|
+
this.audioDevices = project.audioDevices;
|
|
336
|
+
chCnt = ProjectUtil.audioChannelCount(project);
|
|
337
|
+
console.info("Project requested recording channel count: " + chCnt);
|
|
338
|
+
this.autoGainControlConfigs = project.autoGainControlConfigs;
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
console.error("Empty project configuration!");
|
|
342
|
+
}
|
|
343
|
+
this.channelCount = chCnt;
|
|
344
|
+
}
|
|
345
|
+
get project() {
|
|
346
|
+
return this._project;
|
|
347
|
+
}
|
|
348
|
+
set autoGainControlConfigs(autoGainControlConfigs) {
|
|
349
|
+
this._autoGainControlConfigs = autoGainControlConfigs;
|
|
350
|
+
}
|
|
351
|
+
selectRecordingFile(rf) {
|
|
352
|
+
this.displayRecFile = rf;
|
|
353
|
+
}
|
|
354
|
+
uploadUpdate(ue) {
|
|
355
|
+
let upStatus = ue.status;
|
|
356
|
+
this.dataSaved = (UploaderStatus.DONE === upStatus);
|
|
357
|
+
let percentUpl = ue.percentDone();
|
|
358
|
+
if (UploaderStatus.ERR === upStatus) {
|
|
359
|
+
this.uploadStatus = 'warn';
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
if (percentUpl < 50) {
|
|
363
|
+
this.uploadStatus = 'accent';
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
this.uploadStatus = 'success';
|
|
367
|
+
}
|
|
368
|
+
this.uploadProgress = percentUpl;
|
|
369
|
+
}
|
|
370
|
+
this.changeDetectorRef.detectChanges();
|
|
371
|
+
}
|
|
372
|
+
set controlAudioPlayer(controlAudioPlayer) {
|
|
373
|
+
if (this._controlAudioPlayer) {
|
|
374
|
+
//this._controlAudioPlayer.listener=null;
|
|
375
|
+
}
|
|
376
|
+
this._controlAudioPlayer = controlAudioPlayer;
|
|
377
|
+
if (this._controlAudioPlayer) {
|
|
378
|
+
this._controlAudioPlayer.listener = this;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
get controlAudioPlayer() {
|
|
382
|
+
return this._controlAudioPlayer;
|
|
383
|
+
}
|
|
384
|
+
set session(session) {
|
|
385
|
+
this._session = session;
|
|
386
|
+
}
|
|
387
|
+
get session() {
|
|
388
|
+
return this._session;
|
|
389
|
+
}
|
|
390
|
+
set channelCount(channelCount) {
|
|
391
|
+
this._channelCount = channelCount;
|
|
392
|
+
}
|
|
393
|
+
set audioDevices(audioDevices) {
|
|
394
|
+
this._audioDevices = audioDevices;
|
|
395
|
+
}
|
|
396
|
+
update(e) {
|
|
397
|
+
if (e.type == EventType.STARTED) {
|
|
398
|
+
this.playStartAction.disabled = true;
|
|
399
|
+
this.updateTimerId = window.setInterval(() => {
|
|
400
|
+
//this.audioSignal.playFramePosition = this.ap.playPositionFrames;
|
|
401
|
+
}, 50);
|
|
402
|
+
}
|
|
403
|
+
else if (e.type == EventType.STOPPED || e.type == EventType.ENDED) {
|
|
404
|
+
window.clearInterval(this.updateTimerId);
|
|
405
|
+
// this.audioSignal.playFramePosition = this.ap.playPositionFrames;
|
|
406
|
+
this.playStartAction.disabled = (!(this.displayRecFile));
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
startDisabled() {
|
|
410
|
+
return !this.transportActions || this.readonly || this.transportActions.startAction.disabled;
|
|
411
|
+
}
|
|
412
|
+
stopDisabled() {
|
|
413
|
+
return !this.transportActions || this.transportActions.stopAction.disabled;
|
|
414
|
+
}
|
|
415
|
+
startStopNextName() {
|
|
416
|
+
if (!this.startDisabled()) {
|
|
417
|
+
this.startStopNextButtonName = "Start";
|
|
418
|
+
}
|
|
419
|
+
else if (!this.stopDisabled()) {
|
|
420
|
+
this.startStopNextButtonName = "Stop";
|
|
421
|
+
}
|
|
422
|
+
return this.startStopNextButtonName;
|
|
423
|
+
}
|
|
424
|
+
startStopNextIconName() {
|
|
425
|
+
if (!this.startDisabled()) {
|
|
426
|
+
this.startStopNextButtonIconName = "fiber_manual_record";
|
|
427
|
+
}
|
|
428
|
+
else if (!this.stopDisabled()) {
|
|
429
|
+
this.startStopNextButtonIconName = "stop";
|
|
430
|
+
}
|
|
431
|
+
return this.startStopNextButtonIconName;
|
|
432
|
+
}
|
|
433
|
+
startStopNextIconColor() {
|
|
434
|
+
if (!this.startDisabled()) {
|
|
435
|
+
return "red";
|
|
436
|
+
}
|
|
437
|
+
else if (!this.stopDisabled()) {
|
|
438
|
+
return "yellow";
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
return "grey";
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
startStopPerform() {
|
|
445
|
+
if (!this.startDisabled()) {
|
|
446
|
+
this.transportActions.startAction.perform();
|
|
447
|
+
}
|
|
448
|
+
else if (!this.stopDisabled()) {
|
|
449
|
+
this.transportActions.stopAction.perform();
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
startItem() {
|
|
453
|
+
this.transportActions.startAction.disabled = true;
|
|
454
|
+
this.transportActions.pauseAction.disabled = true;
|
|
455
|
+
if (this.readonly) {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
this.transportActions.fwdAction.disabled = true;
|
|
459
|
+
this.transportActions.fwdNextAction.disabled = true;
|
|
460
|
+
this.transportActions.bwdAction.disabled = true;
|
|
461
|
+
this.displayRecFile = null;
|
|
462
|
+
this.displayRecFileVersion = 0;
|
|
463
|
+
this.displayAudioClip = null;
|
|
464
|
+
this.showRecording();
|
|
465
|
+
if (this.ac) {
|
|
466
|
+
if (!this.ac.opened) {
|
|
467
|
+
if (this._selectedDeviceId) {
|
|
468
|
+
console.log("Open session with audio device Id: \'" + this._selectedDeviceId + "\' for " + this._channelCount + " channels");
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
console.log("Open session with default audio device for " + this._channelCount + " channels");
|
|
472
|
+
}
|
|
473
|
+
this.ac.open(this._channelCount, this._selectedDeviceId, this._autoGainControlConfigs);
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
this.ac.start();
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
downloadRecording() {
|
|
481
|
+
if (this.displayRecFile) {
|
|
482
|
+
let ab = this.displayRecFile.audioBuffer;
|
|
483
|
+
let ww = new WavWriter();
|
|
484
|
+
if (ab) {
|
|
485
|
+
let wavFile = ww.writeAsync(ab, (wavFile) => {
|
|
486
|
+
let blob = new Blob([wavFile], { type: 'audio/wav' });
|
|
487
|
+
let rfUrl = URL.createObjectURL(blob);
|
|
488
|
+
let dataDnlLnk = this.renderer.createElement('a');
|
|
489
|
+
//dataDnlLnk.name = 'Recording';
|
|
490
|
+
dataDnlLnk.href = rfUrl;
|
|
491
|
+
this.renderer.appendChild(document.body, dataDnlLnk);
|
|
492
|
+
// download property not yet in TS def
|
|
493
|
+
if (this.displayRecFile) {
|
|
494
|
+
let fn = this.displayRecFile.filenameString();
|
|
495
|
+
fn += '_' + this.displayRecFileVersion;
|
|
496
|
+
fn += '.wav';
|
|
497
|
+
dataDnlLnk.download = fn;
|
|
498
|
+
dataDnlLnk.click();
|
|
499
|
+
}
|
|
500
|
+
this.renderer.removeChild(document.body, dataDnlLnk);
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
set displayRecFile(displayRecFile) {
|
|
506
|
+
this._displayRecFile = displayRecFile;
|
|
507
|
+
if (this._displayRecFile) {
|
|
508
|
+
let ab = this._displayRecFile.audioBuffer;
|
|
509
|
+
if (ab) {
|
|
510
|
+
this.displayAudioClip = new AudioClip(ab);
|
|
511
|
+
this.controlAudioPlayer.audioClip = this.displayAudioClip;
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
// clear for now ...
|
|
515
|
+
this.displayAudioClip = null;
|
|
516
|
+
this.controlAudioPlayer.audioClip = null;
|
|
517
|
+
if (this._controlAudioPlayer && this._session) {
|
|
518
|
+
//... and try to fetch from server
|
|
519
|
+
this.audioFetchSubscription = this.recFileService.fetchAndApplyRecordingFile(this._controlAudioPlayer.context, this._session.project, this._displayRecFile).subscribe((rf) => {
|
|
520
|
+
let fab = null;
|
|
521
|
+
if (rf && this._displayRecFile) {
|
|
522
|
+
fab = this._displayRecFile.audioBuffer;
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
this.statusMsg = 'Recording file could not be loaded.';
|
|
526
|
+
this.statusAlertType = 'error';
|
|
527
|
+
}
|
|
528
|
+
if (fab) {
|
|
529
|
+
this.displayAudioClip = new AudioClip(fab);
|
|
530
|
+
}
|
|
531
|
+
this.controlAudioPlayer.audioClip = this.displayAudioClip;
|
|
532
|
+
this.showRecording();
|
|
533
|
+
}, err => {
|
|
534
|
+
console.error("Could not load recording file from server: " + err);
|
|
535
|
+
this.statusMsg = 'Recording file could not be loaded: ' + err;
|
|
536
|
+
this.statusAlertType = 'error';
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
this.statusMsg = 'Recording file could not be decoded. Audio context unavailable.';
|
|
541
|
+
this.statusAlertType = 'error';
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
else {
|
|
546
|
+
this.displayAudioClip = null;
|
|
547
|
+
this.controlAudioPlayer.audioClip = null;
|
|
548
|
+
}
|
|
549
|
+
this.showRecording();
|
|
550
|
+
}
|
|
551
|
+
get displayRecFile() {
|
|
552
|
+
return this._displayRecFile;
|
|
553
|
+
}
|
|
554
|
+
showRecording() {
|
|
555
|
+
this.controlAudioPlayer.stop();
|
|
556
|
+
if (this.displayAudioClip) {
|
|
557
|
+
this.levelMeasure.calcBufferLevelInfos(this.displayAudioClip.buffer, LEVEL_BAR_INTERVALL_SECONDS).then((levelInfos) => {
|
|
558
|
+
this.displayLevelInfos = levelInfos;
|
|
559
|
+
this.changeDetectorRef.detectChanges();
|
|
560
|
+
});
|
|
561
|
+
this.playStartAction.disabled = false;
|
|
562
|
+
}
|
|
563
|
+
else {
|
|
564
|
+
// TODO
|
|
565
|
+
// Setting to null does not trigger a change if it was null before (happens after nextitem() in AUTOPROGRESS mode)
|
|
566
|
+
// The level bar display does not clear, it shows the last captured stream
|
|
567
|
+
this.displayLevelInfos = null;
|
|
568
|
+
this.playStartAction.disabled = true;
|
|
569
|
+
// Collapse audio signal display if open
|
|
570
|
+
if (!this.audioSignalCollapsed) {
|
|
571
|
+
this.audioSignalCollapsed = true;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
this.changeDetectorRef.detectChanges();
|
|
575
|
+
}
|
|
576
|
+
updateStartActionDisableState() {
|
|
577
|
+
this.transportActions.startAction.disabled = !(this.ac);
|
|
578
|
+
}
|
|
579
|
+
start() {
|
|
580
|
+
this.statusAlertType = 'info';
|
|
581
|
+
this.statusMsg = 'Starting session...';
|
|
582
|
+
this.statusWaiting = false;
|
|
583
|
+
if (this._session) {
|
|
584
|
+
if (this._session.sealed) {
|
|
585
|
+
this.readonly = true;
|
|
586
|
+
this.statusMsg = 'Session sealed!';
|
|
587
|
+
//let dialogRef = this.dialog.open(SessionSealedDialog, {});
|
|
588
|
+
this.dialog.open(MessageDialog, {
|
|
589
|
+
data: {
|
|
590
|
+
type: 'error',
|
|
591
|
+
title: 'Error',
|
|
592
|
+
msg: "This session is sealed. Recordings cannot be added anymore.",
|
|
593
|
+
advise: 'Please ask your experimenter what to do (e.g start a new session).',
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
let body = {};
|
|
599
|
+
if (this._session.status === "CREATED") {
|
|
600
|
+
this._session.status = "LOADED";
|
|
601
|
+
body.status = this._session.status;
|
|
602
|
+
if (!this._session.loadedDate) {
|
|
603
|
+
this._session.loadedDate = new Date();
|
|
604
|
+
body.loadedDate = this._session.loadedDate;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
else {
|
|
608
|
+
this._session.restartedDate = new Date();
|
|
609
|
+
body.restartedDate = this._session.restartedDate;
|
|
610
|
+
}
|
|
611
|
+
this.sessionService.patchSessionObserver(this._session, body).subscribe();
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
//console.log("Session ID: "+this._session.session+ " status: "+this._session.status)
|
|
615
|
+
this._selectedDeviceId = undefined;
|
|
616
|
+
if (!this.readonly && this.ac) {
|
|
617
|
+
this.statusMsg = 'Requesting audio permissions...';
|
|
618
|
+
this.statusAlertType = 'info';
|
|
619
|
+
this.ac.deviceInfos((mdis) => {
|
|
620
|
+
let audioCaptureDeviceAvail = false;
|
|
621
|
+
let audioPlayDeviceAvail = false;
|
|
622
|
+
if (mdis && this.ac) {
|
|
623
|
+
this.ac.printDevices(mdis);
|
|
624
|
+
if (mdis.length > 0) {
|
|
625
|
+
for (let mdii = 0; mdii < mdis.length; mdii++) {
|
|
626
|
+
let mdi = mdis[mdii];
|
|
627
|
+
let kind = mdi.kind;
|
|
628
|
+
if (kind === "audioinput") {
|
|
629
|
+
audioCaptureDeviceAvail = true;
|
|
630
|
+
}
|
|
631
|
+
else if (kind === "audiooutput") {
|
|
632
|
+
audioPlayDeviceAvail = true;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
if (this._session && this._session.type !== 'TEST_DEF_A' && this._audioDevices && this._audioDevices.length > 0) {
|
|
637
|
+
let fdi = null;
|
|
638
|
+
for (let adI = 0; adI < this._audioDevices.length; adI++) {
|
|
639
|
+
let ad = this._audioDevices[adI];
|
|
640
|
+
if (ad.playback) {
|
|
641
|
+
// project audio device config for playback device
|
|
642
|
+
// not used for now
|
|
643
|
+
continue;
|
|
644
|
+
}
|
|
645
|
+
for (let mdii = 0; mdii < mdis.length; mdii++) {
|
|
646
|
+
let mdi = mdis[mdii];
|
|
647
|
+
let kind = mdi.kind;
|
|
648
|
+
if (kind === "audioinput") {
|
|
649
|
+
audioCaptureDeviceAvail = true;
|
|
650
|
+
}
|
|
651
|
+
else if (kind === "audiooutput") {
|
|
652
|
+
audioPlayDeviceAvail = true;
|
|
653
|
+
}
|
|
654
|
+
if (ad.regex) {
|
|
655
|
+
//console.log("Match?: \'"+mdi.label+"\' \'"+ad.name+"\'");
|
|
656
|
+
if (mdi.label.match(ad.name)) {
|
|
657
|
+
fdi = mdi;
|
|
658
|
+
//console.log("Match!");
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
else {
|
|
662
|
+
if (mdi.label.trim() === ad.name.trim()) {
|
|
663
|
+
fdi = mdi;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
if (fdi) {
|
|
667
|
+
break;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
if (fdi) {
|
|
671
|
+
break;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
if (fdi) {
|
|
675
|
+
// matching device found
|
|
676
|
+
// Not able to open device here since Chrome 71
|
|
677
|
+
// Chrome 71 requires a user gesture before the AudioContext can be resumed
|
|
678
|
+
// sessionmanager.ts:712 Open session with default audio device for 1 channels
|
|
679
|
+
// 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
|
|
680
|
+
// push../projects/speechrecorderng/src/lib/audio/capture/capture.ts.AudioCapture.open @ capture.ts:128
|
|
681
|
+
//this.ac.open(this._channelCount, fdi.deviceId);
|
|
682
|
+
console.info("Set selected audio device: \'" + fdi.label + "\' Id: \'" + fdi.deviceId + "\'");
|
|
683
|
+
this._selectedDeviceId = fdi.deviceId;
|
|
684
|
+
this.enableStartUserGesture();
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
// device not found
|
|
688
|
+
this.statusMsg = 'ERROR: Required audio device not available!';
|
|
689
|
+
this.statusAlertType = 'error';
|
|
690
|
+
this.readonly = true;
|
|
691
|
+
this.dialog.open(MessageDialog, {
|
|
692
|
+
data: {
|
|
693
|
+
type: 'error',
|
|
694
|
+
title: 'Required audio device',
|
|
695
|
+
msg: "Required audio device not found",
|
|
696
|
+
advice: "Please connect a suitable audio device for this project and retry (press the browser reload button)."
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
else {
|
|
702
|
+
if (!audioCaptureDeviceAvail && !audioPlayDeviceAvail) {
|
|
703
|
+
// no device found
|
|
704
|
+
this.statusMsg = 'ERROR: No audio device available!';
|
|
705
|
+
this.statusAlertType = 'warn';
|
|
706
|
+
//this.readonly = true;
|
|
707
|
+
this.dialog.open(MessageDialog, {
|
|
708
|
+
data: {
|
|
709
|
+
type: 'warn',
|
|
710
|
+
title: 'No audio device',
|
|
711
|
+
msg: "No audio device found",
|
|
712
|
+
advice: "Please connect an audio device and retry (press the browser reload button) or try to continue anyway."
|
|
713
|
+
}
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
else {
|
|
717
|
+
if (!this.readonly && !audioCaptureDeviceAvail) {
|
|
718
|
+
// no device found
|
|
719
|
+
this.statusMsg = 'WARNING: No audio capture device available!';
|
|
720
|
+
this.statusAlertType = 'warning';
|
|
721
|
+
//this.readonly = true;
|
|
722
|
+
this.dialog.open(MessageDialog, {
|
|
723
|
+
data: {
|
|
724
|
+
type: 'warning',
|
|
725
|
+
title: 'No audio capture device',
|
|
726
|
+
msg: "No audio capture device found",
|
|
727
|
+
advice: "Please connect an audio capture device and retry (press the browser reload button) or try to continue anyway."
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
if (!audioPlayDeviceAvail) {
|
|
732
|
+
// Firefox does not enumerate audiooutput devices
|
|
733
|
+
// Do not show this warning, because it would always appear on Firefox
|
|
734
|
+
// When https://bugzilla.mozilla.org/show_bug.cgi?id=1498512 is fixed the warning can be enabled for Firefox as well
|
|
735
|
+
// It is already implemneted but kept behind a preference setting https://bugzilla.mozilla.org/show_bug.cgi?id=1152401
|
|
736
|
+
// Output devices are listed if about:config media.setsinkid.enabled=true
|
|
737
|
+
// but default setting is false
|
|
738
|
+
if (!navigator.userAgent.match(".*Firefox.*")) {
|
|
739
|
+
// no device found
|
|
740
|
+
this.statusMsg = 'WARNING: No audio playback device available!';
|
|
741
|
+
this.statusAlertType = 'warn';
|
|
742
|
+
//this.readonly = true;
|
|
743
|
+
this.dialog.open(MessageDialog, {
|
|
744
|
+
data: {
|
|
745
|
+
type: 'warn',
|
|
746
|
+
title: 'No audio playback device',
|
|
747
|
+
msg: "No audio playback device found",
|
|
748
|
+
advice: "Please connect an audio playback device and retry (press the browser reload button) or try to continue anyway."
|
|
749
|
+
}
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
// Not able to open device here since Chrome 71
|
|
755
|
+
// Chrome 71 requires a user gesture before the AudioContext can be resumed
|
|
756
|
+
// sessionmanager.ts:712 Open session with default audio device for 1 channels
|
|
757
|
+
// 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
|
|
758
|
+
// push../projects/speechrecorderng/src/lib/audio/capture/capture.ts.AudioCapture.open @ capture.ts:128
|
|
759
|
+
//console.log("Open session with default audio device for "+this._channelCount+" channels");
|
|
760
|
+
//this.ac.open(this._channelCount);
|
|
761
|
+
// enable start gesture anyway
|
|
762
|
+
this.enableStartUserGesture();
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
// if(this.recorderCombiPane.recordingListComp.recordingList.length>0){
|
|
768
|
+
// this.selectRecordingFile(this.recorderCombiPane.recordingListComp.recordingList[0]);
|
|
769
|
+
// }
|
|
770
|
+
this.recorderCombiPane.selectTop();
|
|
771
|
+
this.enableNavigation();
|
|
772
|
+
}
|
|
773
|
+
isRecording() {
|
|
774
|
+
return (this.status === 2 /* RECORDING */);
|
|
775
|
+
}
|
|
776
|
+
isActive() {
|
|
777
|
+
return (!(this.status === 0 /* BLOCKED */ || this.status === 1 /* IDLE */ || this.status === 4 /* ERROR */) || this.processingRecording || this.sessionService.uploadCount > 0);
|
|
778
|
+
}
|
|
779
|
+
updateNavigationActions() {
|
|
780
|
+
this.transportActions.fwdAction.disabled = this.navigationDisabled;
|
|
781
|
+
this.transportActions.bwdAction.disabled = this.navigationDisabled;
|
|
782
|
+
}
|
|
783
|
+
enableStartUserGesture() {
|
|
784
|
+
this.statusAlertType = 'info';
|
|
785
|
+
this.statusMsg = 'Ready.';
|
|
786
|
+
//this.updateStartActionDisableState()
|
|
787
|
+
this.transportActions.startAction.disabled = !(this.ac);
|
|
788
|
+
}
|
|
789
|
+
enableNavigation() {
|
|
790
|
+
this.navigationDisabled = false;
|
|
791
|
+
this.updateNavigationActions();
|
|
792
|
+
}
|
|
793
|
+
opened() {
|
|
794
|
+
if (this.ac) {
|
|
795
|
+
this.ac.start();
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
started() {
|
|
799
|
+
this.startedDate = new Date();
|
|
800
|
+
this.transportActions.startAction.disabled = true;
|
|
801
|
+
this.statusAlertType = 'info';
|
|
802
|
+
this.statusMsg = 'Recording...';
|
|
803
|
+
let maxRecordingTimeMs = MAX_RECORDING_TIME_MS;
|
|
804
|
+
this.maxRecTimerId = window.setTimeout(() => {
|
|
805
|
+
this.stopRecordingMaxRec();
|
|
806
|
+
}, maxRecordingTimeMs);
|
|
807
|
+
this.maxRecTimerRunning = true;
|
|
808
|
+
this.status = 2 /* RECORDING */;
|
|
809
|
+
this.transportActions.stopAction.disabled = false;
|
|
810
|
+
}
|
|
811
|
+
stopItem() {
|
|
812
|
+
this.transportActions.stopAction.disabled = true;
|
|
813
|
+
this.transportActions.nextAction.disabled = true;
|
|
814
|
+
this.status = 3 /* STOPPING_STOP */;
|
|
815
|
+
this.stopRecording();
|
|
816
|
+
}
|
|
817
|
+
stopRecording() {
|
|
818
|
+
if (this.maxRecTimerRunning && this.maxRecTimerId != null) {
|
|
819
|
+
window.clearTimeout(this.maxRecTimerId);
|
|
820
|
+
this.maxRecTimerRunning = false;
|
|
821
|
+
}
|
|
822
|
+
if (this.ac) {
|
|
823
|
+
this.ac.stop();
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
stopRecordingMaxRec() {
|
|
827
|
+
this.maxRecTimerRunning = false;
|
|
828
|
+
this.status = 3 /* STOPPING_STOP */;
|
|
829
|
+
if (this.ac) {
|
|
830
|
+
this.ac.stop();
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
// addRecordingFileByDescriptor(rfd:RecordingFileDescriptorImpl){
|
|
834
|
+
// let prIdx=0;
|
|
835
|
+
// if(this.items) {
|
|
836
|
+
// let it = this.items[prIdx];
|
|
837
|
+
// if (it) {
|
|
838
|
+
// if (!it.recs) {
|
|
839
|
+
// it.recs = new Array<SprRecordingFile>();
|
|
840
|
+
// }
|
|
841
|
+
//
|
|
842
|
+
// } else {
|
|
843
|
+
// //console.debug("WARN: No recording item with code: \"" +rfd.recording.itemcode+ "\" found.");
|
|
844
|
+
// }
|
|
845
|
+
// }
|
|
846
|
+
// }
|
|
847
|
+
//
|
|
848
|
+
// addRecordingFileByPromptIndex(promptIndex:number, rf:SprRecordingFile){
|
|
849
|
+
//
|
|
850
|
+
// }
|
|
851
|
+
stopped() {
|
|
852
|
+
this.updateStartActionDisableState();
|
|
853
|
+
this.transportActions.stopAction.disabled = true;
|
|
854
|
+
this.transportActions.nextAction.disabled = true;
|
|
855
|
+
this.transportActions.pauseAction.disabled = true;
|
|
856
|
+
this.statusAlertType = 'info';
|
|
857
|
+
this.statusMsg = 'Recorded.';
|
|
858
|
+
//this.startStopSignalState = StartStopSignalState.IDLE;
|
|
859
|
+
let ad;
|
|
860
|
+
if (this.ac) {
|
|
861
|
+
ad = this.ac.audioBuffer();
|
|
862
|
+
//}
|
|
863
|
+
//if (this._session && this._promptIndex ) {
|
|
864
|
+
let sessId = 0;
|
|
865
|
+
if (this._session) {
|
|
866
|
+
sessId = this._session.sessionId;
|
|
867
|
+
}
|
|
868
|
+
// let cpIdx = this._promptIndex;
|
|
869
|
+
// let it = this.items[cpIdx];
|
|
870
|
+
// if (!it.recs) {
|
|
871
|
+
// it.recs = new Array<RecordingFile>();
|
|
872
|
+
// }
|
|
873
|
+
let rf = new RecordingFile(UUID.generate(), sessId, ad);
|
|
874
|
+
rf._startedAsDateObj = this.startedDate;
|
|
875
|
+
if (rf._startedAsDateObj) {
|
|
876
|
+
rf.startedDate = rf._startedAsDateObj.toString();
|
|
877
|
+
}
|
|
878
|
+
// it.recs.push(rf);
|
|
879
|
+
//
|
|
880
|
+
// if (this.enableUploadRecordings) {
|
|
881
|
+
// // TODO use SpeechRecorderconfig resp. RecfileService
|
|
882
|
+
// //new REST API URL
|
|
883
|
+
//
|
|
884
|
+
let apiEndPoint = '';
|
|
885
|
+
if (this.config && this.config.apiEndPoint) {
|
|
886
|
+
apiEndPoint = this.config.apiEndPoint;
|
|
887
|
+
}
|
|
888
|
+
if (apiEndPoint !== '') {
|
|
889
|
+
apiEndPoint = apiEndPoint + '/';
|
|
890
|
+
}
|
|
891
|
+
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
892
|
+
let recUrl = sessionsUrl + '/' + rf.session + '/' + RECFILE_API_CTX + '/' + rf.uuid;
|
|
893
|
+
//
|
|
894
|
+
//
|
|
895
|
+
//
|
|
896
|
+
// // convert asynchronously to 16-bit integer PCM
|
|
897
|
+
// // TODO could we avoid conversion to save CPU resources and transfer float PCM directly?
|
|
898
|
+
// // TODO duplicate conversion for manual download
|
|
899
|
+
// //console.log("Build wav writer...");
|
|
900
|
+
this.processingRecording = true;
|
|
901
|
+
let ww = new WavWriter();
|
|
902
|
+
ww.writeAsync(ad, (wavFile) => {
|
|
903
|
+
//this.postRecording(wavFile, recUrl);
|
|
904
|
+
//rf._dateAsDateObj=new Date();
|
|
905
|
+
rf.frames = ad.length;
|
|
906
|
+
this.displayRecFile = rf;
|
|
907
|
+
//this.recordingListComp.recordingList.push(rf);
|
|
908
|
+
this.recorderCombiPane.push(rf);
|
|
909
|
+
this.postRecordingMultipart(wavFile, rf.uuid, rf.session, rf._startedAsDateObj, recUrl);
|
|
910
|
+
this.processingRecording = false;
|
|
911
|
+
this.changeDetectorRef.detectChanges();
|
|
912
|
+
});
|
|
913
|
+
// }
|
|
914
|
+
}
|
|
915
|
+
// check complete session
|
|
916
|
+
let complete = true;
|
|
917
|
+
let autoStart = (this.status === 3 /* STOPPING_STOP */);
|
|
918
|
+
this.status = 1 /* IDLE */;
|
|
919
|
+
let startNext = false;
|
|
920
|
+
this.navigationDisabled = false;
|
|
921
|
+
this.updateNavigationActions();
|
|
922
|
+
this.changeDetectorRef.detectChanges();
|
|
923
|
+
}
|
|
924
|
+
postRecording(wavFile, recUrl) {
|
|
925
|
+
let wavBlob = new Blob([wavFile], { type: 'audio/wav' });
|
|
926
|
+
let ul = new Upload(wavBlob, recUrl);
|
|
927
|
+
this.uploader.queueUpload(ul);
|
|
928
|
+
}
|
|
929
|
+
postRecordingMultipart(wavFile, uuid, sessionId, startedDate, recUrl) {
|
|
930
|
+
let wavBlob = new Blob([wavFile], { type: 'audio/wav' });
|
|
931
|
+
let fd = new FormData();
|
|
932
|
+
if (uuid) {
|
|
933
|
+
fd.set('uuid', uuid);
|
|
934
|
+
}
|
|
935
|
+
if (sessionId !== null) {
|
|
936
|
+
fd.set('sessionId', sessionId.toString());
|
|
937
|
+
}
|
|
938
|
+
if (startedDate) {
|
|
939
|
+
fd.set('startedDate', startedDate.toJSON());
|
|
940
|
+
}
|
|
941
|
+
fd.set('audio', wavBlob);
|
|
942
|
+
let ul = new Upload(fd, recUrl);
|
|
943
|
+
this.uploader.queueUpload(ul);
|
|
944
|
+
}
|
|
945
|
+
stop() {
|
|
946
|
+
if (this.ac) {
|
|
947
|
+
this.ac.close();
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
updateControlPlaybackPosition() {
|
|
951
|
+
if (this._controlAudioPlayer.playPositionFrames) {
|
|
952
|
+
this.recorderCombiPane.audioDisplay.playFramePosition = this._controlAudioPlayer.playPositionFrames;
|
|
953
|
+
this.liveLevelDisplay.playFramePosition = this._controlAudioPlayer.playPositionFrames;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
audioPlayerUpdate(e) {
|
|
957
|
+
if (EventType.READY === e.type) {
|
|
958
|
+
}
|
|
959
|
+
else if (EventType.STARTED === e.type) {
|
|
960
|
+
//this.status = 'Playback...';
|
|
961
|
+
this.updateTimerId = window.setInterval(() => this.updateControlPlaybackPosition(), 50);
|
|
962
|
+
}
|
|
963
|
+
else if (EventType.ENDED === e.type) {
|
|
964
|
+
//.status='Ready.';
|
|
965
|
+
window.clearInterval(this.updateTimerId);
|
|
966
|
+
}
|
|
967
|
+
if (!this.destroyed) {
|
|
968
|
+
this.changeDetectorRef.detectChanges();
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
closed() {
|
|
972
|
+
this.statusAlertType = 'info';
|
|
973
|
+
this.statusMsg = 'Session closed.';
|
|
974
|
+
}
|
|
975
|
+
error(msg = 'An unknown error occured during recording.', advice = 'Please retry.') {
|
|
976
|
+
this.statusMsg = 'ERROR: Recording.';
|
|
977
|
+
this.statusAlertType = 'error';
|
|
978
|
+
this.dialog.open(MessageDialog, {
|
|
979
|
+
data: {
|
|
980
|
+
type: 'error',
|
|
981
|
+
title: 'Recording error',
|
|
982
|
+
msg: msg,
|
|
983
|
+
advice: advice
|
|
984
|
+
}
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
AudioRecorder.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: AudioRecorder, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.ActivatedRoute }, { token: i0.Renderer2 }, { token: i2.MatDialog }, { token: i3.ProjectService }, { token: i4.SessionService }, { token: i5.RecordingService }, { token: i6.SpeechRecorderUploader }, { token: SPEECHRECORDER_CONFIG }], target: i0.ɵɵFactoryTarget.Component });
|
|
989
|
+
AudioRecorder.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: AudioRecorder, selector: "app-audiorecorder", inputs: { projectName: "projectName", dataSaved: "dataSaved" }, host: { listeners: { "window:keypress": "onKeyPress($event)", "window:keydown": "onKeyDown($event)" } }, providers: [SessionService], viewQueries: [{ propertyName: "recorderCombiPane", first: true, predicate: RecorderCombiPane, descendants: true, static: true }, { propertyName: "liveLevelDisplay", first: true, predicate: LevelBar, descendants: true, static: true }], ngImport: i0, template: `
|
|
990
|
+
<app-warningbar [show]="isTestSession()" warningText="Test recording only!"></app-warningbar>
|
|
991
|
+
<app-warningbar [show]="isDefaultAudioTestSession()"
|
|
992
|
+
warningText="This test uses default audio device! Regular sessions may require a particular audio device (microphone)!"></app-warningbar>
|
|
993
|
+
<app-recordercombipane (selectedRecordingFileChanged)="selectRecordingFile($event)"
|
|
994
|
+
[audioSignalCollapsed]="audioSignalCollapsed"
|
|
995
|
+
[selectedRecordingFile]="displayRecFile"
|
|
996
|
+
[selectDisabled]="isActive()"
|
|
997
|
+
[displayAudioClip]="displayAudioClip"
|
|
998
|
+
[playStartAction]="controlAudioPlayer.startAction"
|
|
999
|
+
[playStopAction]="controlAudioPlayer.stopAction"
|
|
1000
|
+
[playSelectionAction]="controlAudioPlayer.startSelectionAction"
|
|
1001
|
+
[autoPlayOnSelectToggleAction]="controlAudioPlayer.autoPlayOnSelectToggleAction"
|
|
1002
|
+
></app-recordercombipane>
|
|
1003
|
+
|
|
1004
|
+
<div fxLayout="row" fxLayout.xs="column" [ngStyle]="{'height.px':100,'min-height.px': 100}"
|
|
1005
|
+
[ngStyle.xs]="{'height.px':125,'min-height.px': 125}">
|
|
1006
|
+
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()"
|
|
1007
|
+
[displayLevelInfos]="displayLevelInfos"></audio-levelbar>
|
|
1008
|
+
<div fxLayout="row">
|
|
1009
|
+
<spr-recordingitemcontrols fxFlex="10 0 1"
|
|
1010
|
+
[audioLoaded]="displayAudioClip?.buffer!==null"
|
|
1011
|
+
[playStartAction]="controlAudioPlayer?.startAction"
|
|
1012
|
+
[playStopAction]="controlAudioPlayer?.stopAction"
|
|
1013
|
+
[peakDbLvl]="peakLevelInDb"
|
|
1014
|
+
[agc]="this.ac?.agcStatus"
|
|
1015
|
+
(onShowRecordingDetails)="audioSignalCollapsed=!audioSignalCollapsed">
|
|
1016
|
+
</spr-recordingitemcontrols>
|
|
1017
|
+
<app-uploadstatus class="ricontrols dark" fxHide fxShow.xs fxFlex="0 0 0" *ngIf="enableUploadRecordings"
|
|
1018
|
+
[value]="uploadProgress"
|
|
1019
|
+
[status]="uploadStatus" [awaitNewUpload]="processingRecording"></app-uploadstatus>
|
|
1020
|
+
<app-readystateindicator class="ricontrols dark" fxHide fxShow.xs fxFlex="0 0 0"
|
|
1021
|
+
[ready]="dataSaved && !isActive()"></app-readystateindicator>
|
|
1022
|
+
</div>
|
|
1023
|
+
</div>
|
|
1024
|
+
<div #controlpanel class="controlpanel" fxLayout="row">
|
|
1025
|
+
<app-sprstatusdisplay fxHide.xs fxFlex="30% 1 30%" [statusMsg]="statusMsg" [statusAlertType]="statusAlertType"
|
|
1026
|
+
[statusWaiting]="statusWaiting"
|
|
1027
|
+
class="hidden-xs"></app-sprstatusdisplay>
|
|
1028
|
+
<div fxFlex="100% 0 100%" class="startstop">
|
|
1029
|
+
<div style="align-content: center">
|
|
1030
|
+
<button (click)="startStopPerform()" [disabled]="startDisabled() && stopDisabled()" mat-raised-button class="bigbutton">
|
|
1031
|
+
<mat-icon [style.color]="startStopNextIconColor()" inline="true">{{startStopNextIconName()}}</mat-icon>
|
|
1032
|
+
<span style="font-weight: bolder;font-size: 14px">{{startStopNextName()}}</span>
|
|
1033
|
+
</button>
|
|
1034
|
+
</div>
|
|
1035
|
+
</div>
|
|
1036
|
+
<div fxFlex="30% 1 30%" >
|
|
1037
|
+
<div fxFlex="1 1 auto"></div>
|
|
1038
|
+
<app-uploadstatus class="ricontrols" fxHide.xs fxFlex="0 0 0" *ngIf="enableUploadRecordings"
|
|
1039
|
+
[value]="uploadProgress"
|
|
1040
|
+
[status]="uploadStatus" [awaitNewUpload]="processingRecording"></app-uploadstatus>
|
|
1041
|
+
<app-readystateindicator class="ricontrols" fxHide.xs
|
|
1042
|
+
[ready]="dataSaved && !isActive()"></app-readystateindicator>
|
|
1043
|
+
</div>
|
|
1044
|
+
</div>
|
|
1045
|
+
`, isInline: true, styles: [":host{flex:2;background:lightgrey;display:flex;flex-direction:column;margin:0;padding:0;min-height:0px;overflow:hidden}\n", ".ricontrols{padding:4px;box-sizing:border-box;height:100%}\n", ".dark{background:darkgray}\n", ".controlpanel{align-content:center;align-items:center;margin:0;padding:20px;min-height:-webkit-min-content;min-height:min-content}\n", ".startstop{width:100%;text-align:center;align-content:center;align-items:center}\n", ".bigbutton{min-width:70px;min-height:50px;font-size:50px;border-radius:20px}\n"], components: [{ type: i7.WarningBar, selector: "app-warningbar", inputs: ["warningText", "show"] }, { type: i8.RecorderCombiPane, selector: "app-recordercombipane", inputs: ["selectDisabled", "selectedRecordingFile", "audioSignalCollapsed", "displayAudioClip", "playStartAction", "playSelectionAction", "autoPlayOnSelectToggleAction", "playStopAction"], outputs: ["selectedRecordingFileChanged"] }, { type: i9.LevelBar, selector: "audio-levelbar", inputs: ["streamingMode", "displayLevelInfos"] }, { type: i10.RecordingItemControls, selector: "spr-recordingitemcontrols", inputs: ["audioSignalCollapsed", "enableDownload", "peakDbLvl", "agc", "audioLoaded", "playStartAction", "playStopAction", "displayLevelInfos"], outputs: ["onShowRecordingDetails", "onDownloadRecording"] }, { type: i11.UploadStatus, selector: "app-uploadstatus", inputs: ["value", "awaitNewUpload", "status"] }, { type: i11.ReadyStateIndicator, selector: "app-readystateindicator", inputs: ["ready"] }, { type: i11.StatusDisplay, selector: "app-sprstatusdisplay", inputs: ["statusAlertType", "statusMsg", "statusWaiting"] }, { type: i12.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i13.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i14.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i15.DefaultStyleDirective, selector: " [ngStyle], [ngStyle.xs], [ngStyle.sm], [ngStyle.md], [ngStyle.lg], [ngStyle.xl], [ngStyle.lt-sm], [ngStyle.lt-md], [ngStyle.lt-lg], [ngStyle.lt-xl], [ngStyle.gt-xs], [ngStyle.gt-sm], [ngStyle.gt-md], [ngStyle.gt-lg]", inputs: ["ngStyle", "ngStyle.xs", "ngStyle.sm", "ngStyle.md", "ngStyle.lg", "ngStyle.xl", "ngStyle.lt-sm", "ngStyle.lt-md", "ngStyle.lt-lg", "ngStyle.lt-xl", "ngStyle.gt-xs", "ngStyle.gt-sm", "ngStyle.gt-md", "ngStyle.gt-lg"] }, { type: i16.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i14.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i16.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i15.DefaultShowHideDirective, selector: " [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]", inputs: ["fxShow", "fxShow.print", "fxShow.xs", "fxShow.sm", "fxShow.md", "fxShow.lg", "fxShow.xl", "fxShow.lt-sm", "fxShow.lt-md", "fxShow.lt-lg", "fxShow.lt-xl", "fxShow.gt-xs", "fxShow.gt-sm", "fxShow.gt-md", "fxShow.gt-lg", "fxHide", "fxHide.print", "fxHide.xs", "fxHide.sm", "fxHide.md", "fxHide.lg", "fxHide.xl", "fxHide.lt-sm", "fxHide.lt-md", "fxHide.lt-lg", "fxHide.lt-xl", "fxHide.gt-xs", "fxHide.gt-sm", "fxHide.gt-md", "fxHide.gt-lg"] }] });
|
|
1046
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: AudioRecorder, decorators: [{
|
|
1047
|
+
type: Component,
|
|
1048
|
+
args: [{
|
|
1049
|
+
selector: 'app-audiorecorder',
|
|
1050
|
+
providers: [SessionService],
|
|
1051
|
+
template: `
|
|
1052
|
+
<app-warningbar [show]="isTestSession()" warningText="Test recording only!"></app-warningbar>
|
|
1053
|
+
<app-warningbar [show]="isDefaultAudioTestSession()"
|
|
1054
|
+
warningText="This test uses default audio device! Regular sessions may require a particular audio device (microphone)!"></app-warningbar>
|
|
1055
|
+
<app-recordercombipane (selectedRecordingFileChanged)="selectRecordingFile($event)"
|
|
1056
|
+
[audioSignalCollapsed]="audioSignalCollapsed"
|
|
1057
|
+
[selectedRecordingFile]="displayRecFile"
|
|
1058
|
+
[selectDisabled]="isActive()"
|
|
1059
|
+
[displayAudioClip]="displayAudioClip"
|
|
1060
|
+
[playStartAction]="controlAudioPlayer.startAction"
|
|
1061
|
+
[playStopAction]="controlAudioPlayer.stopAction"
|
|
1062
|
+
[playSelectionAction]="controlAudioPlayer.startSelectionAction"
|
|
1063
|
+
[autoPlayOnSelectToggleAction]="controlAudioPlayer.autoPlayOnSelectToggleAction"
|
|
1064
|
+
></app-recordercombipane>
|
|
1065
|
+
|
|
1066
|
+
<div fxLayout="row" fxLayout.xs="column" [ngStyle]="{'height.px':100,'min-height.px': 100}"
|
|
1067
|
+
[ngStyle.xs]="{'height.px':125,'min-height.px': 125}">
|
|
1068
|
+
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()"
|
|
1069
|
+
[displayLevelInfos]="displayLevelInfos"></audio-levelbar>
|
|
1070
|
+
<div fxLayout="row">
|
|
1071
|
+
<spr-recordingitemcontrols fxFlex="10 0 1"
|
|
1072
|
+
[audioLoaded]="displayAudioClip?.buffer!==null"
|
|
1073
|
+
[playStartAction]="controlAudioPlayer?.startAction"
|
|
1074
|
+
[playStopAction]="controlAudioPlayer?.stopAction"
|
|
1075
|
+
[peakDbLvl]="peakLevelInDb"
|
|
1076
|
+
[agc]="this.ac?.agcStatus"
|
|
1077
|
+
(onShowRecordingDetails)="audioSignalCollapsed=!audioSignalCollapsed">
|
|
1078
|
+
</spr-recordingitemcontrols>
|
|
1079
|
+
<app-uploadstatus class="ricontrols dark" fxHide fxShow.xs fxFlex="0 0 0" *ngIf="enableUploadRecordings"
|
|
1080
|
+
[value]="uploadProgress"
|
|
1081
|
+
[status]="uploadStatus" [awaitNewUpload]="processingRecording"></app-uploadstatus>
|
|
1082
|
+
<app-readystateindicator class="ricontrols dark" fxHide fxShow.xs fxFlex="0 0 0"
|
|
1083
|
+
[ready]="dataSaved && !isActive()"></app-readystateindicator>
|
|
1084
|
+
</div>
|
|
1085
|
+
</div>
|
|
1086
|
+
<div #controlpanel class="controlpanel" fxLayout="row">
|
|
1087
|
+
<app-sprstatusdisplay fxHide.xs fxFlex="30% 1 30%" [statusMsg]="statusMsg" [statusAlertType]="statusAlertType"
|
|
1088
|
+
[statusWaiting]="statusWaiting"
|
|
1089
|
+
class="hidden-xs"></app-sprstatusdisplay>
|
|
1090
|
+
<div fxFlex="100% 0 100%" class="startstop">
|
|
1091
|
+
<div style="align-content: center">
|
|
1092
|
+
<button (click)="startStopPerform()" [disabled]="startDisabled() && stopDisabled()" mat-raised-button class="bigbutton">
|
|
1093
|
+
<mat-icon [style.color]="startStopNextIconColor()" inline="true">{{startStopNextIconName()}}</mat-icon>
|
|
1094
|
+
<span style="font-weight: bolder;font-size: 14px">{{startStopNextName()}}</span>
|
|
1095
|
+
</button>
|
|
1096
|
+
</div>
|
|
1097
|
+
</div>
|
|
1098
|
+
<div fxFlex="30% 1 30%" >
|
|
1099
|
+
<div fxFlex="1 1 auto"></div>
|
|
1100
|
+
<app-uploadstatus class="ricontrols" fxHide.xs fxFlex="0 0 0" *ngIf="enableUploadRecordings"
|
|
1101
|
+
[value]="uploadProgress"
|
|
1102
|
+
[status]="uploadStatus" [awaitNewUpload]="processingRecording"></app-uploadstatus>
|
|
1103
|
+
<app-readystateindicator class="ricontrols" fxHide.xs
|
|
1104
|
+
[ready]="dataSaved && !isActive()"></app-readystateindicator>
|
|
1105
|
+
</div>
|
|
1106
|
+
</div>
|
|
1107
|
+
`,
|
|
1108
|
+
styles: [`:host {
|
|
1109
|
+
flex: 2;
|
|
1110
|
+
background: lightgrey;
|
|
1111
|
+
display: flex; /* Vertical flex container: Bottom transport panel, above prompting panel */
|
|
1112
|
+
flex-direction: column;
|
|
1113
|
+
margin: 0;
|
|
1114
|
+
padding: 0;
|
|
1115
|
+
min-height: 0px;
|
|
1116
|
+
|
|
1117
|
+
/* Prevents horizontal scroll bar on swipe right */
|
|
1118
|
+
overflow: hidden;
|
|
1119
|
+
}`, `.ricontrols {
|
|
1120
|
+
padding: 4px;
|
|
1121
|
+
box-sizing: border-box;
|
|
1122
|
+
height: 100%;
|
|
1123
|
+
}`, `.dark {
|
|
1124
|
+
background: darkgray;
|
|
1125
|
+
}`, `.controlpanel {
|
|
1126
|
+
align-content: center;
|
|
1127
|
+
align-items: center;
|
|
1128
|
+
margin: 0;
|
|
1129
|
+
padding: 20px;
|
|
1130
|
+
min-height: min-content; /* important */
|
|
1131
|
+
}`, `.startstop {
|
|
1132
|
+
width: 100%;
|
|
1133
|
+
text-align: center;
|
|
1134
|
+
align-content: center;
|
|
1135
|
+
align-items: center;
|
|
1136
|
+
}`, `.bigbutton {
|
|
1137
|
+
min-width: 70px;
|
|
1138
|
+
min-height: 50px;
|
|
1139
|
+
font-size: 50px;
|
|
1140
|
+
border-radius: 20px;
|
|
1141
|
+
}`
|
|
1142
|
+
]
|
|
1143
|
+
}]
|
|
1144
|
+
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i1.ActivatedRoute }, { type: i0.Renderer2 }, { type: i2.MatDialog }, { type: i3.ProjectService }, { type: i4.SessionService }, { type: i5.RecordingService }, { type: i6.SpeechRecorderUploader }, { type: i17.SpeechRecorderConfig, decorators: [{
|
|
1145
|
+
type: Inject,
|
|
1146
|
+
args: [SPEECHRECORDER_CONFIG]
|
|
1147
|
+
}] }]; }, propDecorators: { projectName: [{
|
|
1148
|
+
type: Input
|
|
1149
|
+
}], recorderCombiPane: [{
|
|
1150
|
+
type: ViewChild,
|
|
1151
|
+
args: [RecorderCombiPane, { static: true }]
|
|
1152
|
+
}], liveLevelDisplay: [{
|
|
1153
|
+
type: ViewChild,
|
|
1154
|
+
args: [LevelBar, { static: true }]
|
|
1155
|
+
}], dataSaved: [{
|
|
1156
|
+
type: Input
|
|
1157
|
+
}], onKeyPress: [{
|
|
1158
|
+
type: HostListener,
|
|
1159
|
+
args: ['window:keypress', ['$event']]
|
|
1160
|
+
}], onKeyDown: [{
|
|
1161
|
+
type: HostListener,
|
|
1162
|
+
args: ['window:keydown', ['$event']]
|
|
1163
|
+
}] } });
|
|
1164
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXVkaW9yZWNvcmRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3NwZWVjaHJlY29yZGVybmcvc3JjL2xpYi9zcGVlY2hyZWNvcmRlci9zZXNzaW9uL2F1ZGlvcmVjb3JkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLE1BQU0sRUFBQyxNQUFNLHFCQUFxQixDQUFBO0FBQzFDLE9BQU8sRUFBQyxZQUFZLEVBQXVCLE1BQU0sNkJBQTZCLENBQUM7QUFDL0UsT0FBTyxFQUFDLFdBQVcsRUFBb0IsU0FBUyxFQUFDLE1BQU0sNkJBQTZCLENBQUE7QUFDcEYsT0FBTyxFQUFDLFNBQVMsRUFBQyxNQUFNLDRCQUE0QixDQUFBO0FBRXBELE9BQU8sRUFBQyxhQUFhLEVBQWdELE1BQU0sY0FBYyxDQUFBO0FBRXpGLE9BQU8sRUFDTCxTQUFTLEVBQUUsU0FBUyxFQUFxQixNQUFNLEVBQ2hDLFlBQVksRUFBYSxLQUFLLEVBQzlDLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSxtQkFBbUIsQ0FBQztBQUlqRCxPQUFPLEVBQUMscUJBQXFCLEVBQXVCLE1BQU0sa0JBQWtCLENBQUM7QUFFN0UsT0FBTyxFQUE4QyxXQUFXLEVBQUMsTUFBTSxvQkFBb0IsQ0FBQztBQUU1RixPQUFPLEVBQWEsWUFBWSxFQUFFLGtCQUFrQixFQUFDLE1BQU0sK0JBQStCLENBQUM7QUFFM0YsT0FBTyxFQUFDLG9DQUFvQyxFQUFDLE1BQU0sdUJBQXVCLENBQUM7QUFDM0UsT0FBTyxFQUFDLGdCQUFnQixFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDaEQsT0FBTyxFQUFDLGFBQWEsRUFBQyxNQUFNLHlCQUF5QixDQUFDO0FBR3RELE9BQU8sRUFBQyxvQkFBb0IsRUFBQyxNQUFNLHFCQUFxQixDQUFDO0FBQ3pELE9BQU8sRUFBQyxTQUFTLEVBQUMsTUFBTSx1QkFBdUIsQ0FB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Z0I7c0JBQXRELFNBQVM7dUJBQUMsUUFBUSxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRTtnQkFFNUIsU0FBUztzQkFBakIsS0FBSztnQkFtTE4sVUFBVTtzQkFEVCxZQUFZO3VCQUFDLGlCQUFpQixFQUFFLENBQUMsUUFBUSxDQUFDO2dCQVMzQyxTQUFTO3NCQURSLFlBQVk7dUJBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxRQUFRLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0FjdGlvbn0gZnJvbSAnLi4vLi4vYWN0aW9uL2FjdGlvbidcclxuaW1wb3J0IHtBdWRpb0NhcHR1cmUsIEF1ZGlvQ2FwdHVyZUxpc3RlbmVyfSBmcm9tICcuLi8uLi9hdWRpby9jYXB0dXJlL2NhcHR1cmUnO1xyXG5pbXBvcnQge0F1ZGlvUGxheWVyLCBBdWRpb1BsYXllckV2ZW50LCBFdmVudFR5cGV9IGZyb20gJy4uLy4uL2F1ZGlvL3BsYXliYWNrL3BsYXllcidcclxuaW1wb3J0IHtXYXZXcml0ZXJ9IGZyb20gJy4uLy4uL2F1ZGlvL2ltcGwvd2F2d3JpdGVyJ1xyXG5cclxuaW1wb3J0IHtSZWNvcmRpbmdGaWxlLCBSZWNvcmRpbmdGaWxlRGVzY3JpcHRvckltcGwsIFNwclJlY29yZGluZ0ZpbGV9IGZyb20gJy4uL3JlY29yZGluZydcclxuXHJcbmltcG9ydCB7XHJcbiAgQ29tcG9uZW50LCBWaWV3Q2hpbGQsIENoYW5nZURldGVjdG9yUmVmLCBJbmplY3QsXHJcbiAgQWZ0ZXJWaWV3SW5pdCwgSG9zdExpc3RlbmVyLCBPbkRlc3Ryb3ksIElucHV0LCBSZW5kZXJlcjJcclxufSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xyXG5pbXBvcnQge1Nlc3Npb25TZXJ2aWNlfSBmcm9tIFwiLi9zZXNzaW9uLnNlcnZpY2VcIjtcclxuXHJcbmltcG9ydCB7IE1hdERpYWxvZyB9IGZyb20gXCJAYW5ndWxhci9tYXRlcmlhbC9kaWFsb2dcIjtcclxuaW1wb3J0IHtTcGVlY2hSZWNvcmRlclVwbG9hZGVyfSBmcm9tIFwiLi4vc3BydXBsb2FkZXJcIjtcclxuaW1wb3J0IHtTUEVFQ0hSRUNPUkRFUl9DT05GSUcsIFNwZWVjaFJlY29yZGVyQ29uZmlnfSBmcm9tIFwiLi4vLi4vc3ByLmNvbmZpZ1wiO1xyXG5pbXBvcnQge1Nlc3Npb259IGZyb20gXCIuL3Nlc3Npb25cIjtcclxuaW1wb3J0IHtBdWRpb0RldmljZSwgQXV0b0dhaW5Db250cm9sQ29uZmlnLCBQcm9qZWN0LCBQcm9qZWN0VXRpbH0gZnJvbSBcIi4uL3Byb2plY3QvcHJvamVjdFwiO1xyXG5cclxuaW1wb3J0IHtMZXZlbEluZm9zLCBMZXZlbE1lYXN1cmUsIFN0cmVhbUxldmVsTWVhc3VyZX0gZnJvbSBcIi4uLy4uL2F1ZGlvL2RzcC9sZXZlbF9tZWFzdXJlXCI7XHJcblxyXG5pbXBvcnQge1NlcXVlbmNlQXVkaW9GbG9hdDMyQ2h1bmtlck91dFN0cmVhbX0gZnJvbSBcIi4uLy4uL2F1ZGlvL2lvL3N0cmVhbVwiO1xyXG5pbXBvcnQge1RyYW5zcG9ydEFjdGlvbnN9IGZyb20gXCIuL2NvbnRyb2xwYW5lbFwiO1xyXG5pbXBvcnQge01lc3NhZ2VEaWFsb2d9IGZyb20gXCIuLi8uLi91aS9tZXNzYWdlX2RpYWxvZ1wiO1xyXG5pbXBvcnQge1JlY29yZGluZ1NlcnZpY2V9IGZyb20gXCIuLi9yZWNvcmRpbmdzL3JlY29yZGluZ3Muc2VydmljZVwiO1xyXG5pbXBvcnQge1N1YnNjcmlwdGlvbn0gZnJvbSBcInJ4anNcIjtcclxuaW1wb3J0IHtBdWRpb0NvbnRleHRQcm92aWRlcn0gZnJvbSBcIi4uLy4uL2F1ZGlvL2NvbnRleHRcIjtcclxuaW1wb3J0IHtBdWRpb0NsaXB9IGZyb20gXCIuLi8uLi9hdWRpby9wZXJzaXN0b3JcIjtcclxuaW1wb3J0IHtSZWNvcmRpbmdMaXN0fSBmcm9tIFwiLi9yZWNvcmRpbmdfbGlzdFwiO1xyXG5pbXBvcnQge1VwbG9hZCwgVXBsb2FkZXJTdGF0dXMsIFVwbG9hZGVyU3RhdHVzQ2hhbmdlRXZlbnR9IGZyb20gXCIuLi8uLi9uZXQvdXBsb2FkZXJcIjtcclxuaW1wb3J0IHtBY3RpdmF0ZWRSb3V0ZSwgUGFyYW1zfSBmcm9tIFwiQGFuZ3VsYXIvcm91dGVyXCI7XHJcbmltcG9ydCB7UHJvamVjdFNlcnZpY2V9IGZyb20gXCIuLi9wcm9qZWN0L3Byb2plY3Quc2VydmljZVwiO1xyXG5pbXBvcnQge1VVSUR9IGZyb20gXCIuLi8uLi91dGlscy91dGlsc1wiO1xyXG5pbXBvcnQge01JTl9EQl9MRVZFTCwgUmVjb3JkaW5nSXRlbURpc3BsYXl9IGZyb20gXCIuLi8uLi91aS9yZWNvcmRpbmdpdGVtX2Rpc3BsYXlcIjtcclxuaW1wb3J0IHtMZXZlbEJhcn0gZnJvbSBcIi4uLy4uL2F1ZGlvL3VpL2xpdmVsZXZlbFwiO1xyXG5pbXBvcnQge1JlY29yZGVyQ29tYmlQYW5lfSBmcm9tIFwiLi9yZWNvcmRlcl9jb21iaV9wYW5lXCI7XHJcbmltcG9ydCB7U2NyaXB0fSBmcm9tIFwiLi4vc2NyaXB0L3NjcmlwdFwiO1xyXG5cclxuXHJcbmV4cG9ydCBjb25zdCBSRUNGSUxFX0FQSV9DVFggPSAncmVjZmlsZSc7XHJcblxyXG5cclxuY29uc3QgTUFYX1JFQ09SRElOR19USU1FX01TID0gMTAwMCAqIDYwICogNjAgKiA2MDsgLy8gMSBob3VyXHJcblxyXG5cclxuY29uc3QgTEVWRUxfQkFSX0lOVEVSVkFMTF9TRUNPTkRTID0gMC4xOyAgLy8gMTAwbXNcclxuZXhwb3J0IGNvbnN0IGVudW0gTW9kZSB7U0VSVkVSX0JPVU5ELCBTVEFORF9BTE9ORX1cclxuXHJcbmV4cG9ydCBjb25zdCBlbnVtIFN0YXR1cyB7XHJcbiAgQkxPQ0tFRCwgSURMRSwgUkVDT1JESU5HLCAgU1RPUFBJTkdfU1RPUCwgRVJST1JcclxufVxyXG5cclxuZXhwb3J0IGNsYXNzIEl0ZW0ge1xyXG4gIHByb21wdEFzU3RyaW5nOiBzdHJpbmc7XHJcbiAgdHJhaW5pbmc6IGJvb2xlYW47XHJcbiAgcmVjczogQXJyYXk8UmVjb3JkaW5nRmlsZT4gfCBudWxsO1xyXG5cclxuICBjb25zdHJ1Y3Rvcihwcm9tcHRBc1N0cmluZzogc3RyaW5nLCB0cmFpbmluZzogYm9vbGVhbikge1xyXG4gICAgdGhpcy5wcm9tcHRBc1N0cmluZyA9IHByb21wdEFzU3RyaW5nO1xyXG4gICAgdGhpcy50cmFpbmluZyA9IHRyYWluaW5nO1xyXG4gICAgdGhpcy5yZWNzID0gbnVsbDtcclxuICB9XHJcblxyXG59XHJcblxyXG4vLyBUT0RPIGVudW0gbm90IHBvc3NpYmxlIGluIHRlbXBsYXRlIGxhbmd1YWdlICwgdXNlIHN0cmluZyBmb3Igbm93XHJcbi8vZXhwb3J0IGVudW0gU3RhdHVzQWxlcnRUeXBlIHtJTkZPLFdBUk4sRVJST1J9O1xyXG5cclxuQENvbXBvbmVudCh7XHJcblxyXG4gIHNlbGVjdG9yOiAnYXBwLWF1ZGlvcmVjb3JkZXInLFxyXG4gIHByb3ZpZGVyczogW1Nlc3Npb25TZXJ2aWNlXSxcclxuICB0ZW1wbGF0ZTogYFxyXG4gICAgPGFwcC13YXJuaW5nYmFyIFtzaG93XT1cImlzVGVzdFNlc3Npb24oKVwiIHdhcm5pbmdUZXh0PVwiVGVzdCByZWNvcmRpbmcgb25seSFcIj48L2FwcC13YXJuaW5nYmFyPlxyXG4gICAgPGFwcC13YXJuaW5nYmFyIFtzaG93XT1cImlzRGVmYXVsdEF1ZGlvVGVzdFNlc3Npb24oKVwiXHJcbiAgICAgICAgICAgICAgICAgICAgd2FybmluZ1RleHQ9XCJUaGlzIHRlc3QgdXNlcyBkZWZhdWx0IGF1ZGlvIGRldmljZSEgUmVndWxhciBzZXNzaW9ucyBtYXkgcmVxdWlyZSBhIHBhcnRpY3VsYXIgYXVkaW8gZGV2aWNlIChtaWNyb3Bob25lKSFcIj48L2FwcC13YXJuaW5nYmFyPlxyXG4gICAgPGFwcC1yZWNvcmRlcmNvbWJpcGFuZSAoc2VsZWN0ZWRSZWNvcmRpbmdGaWxlQ2hhbmdlZCk9XCJzZWxlY3RSZWNvcmRpbmdGaWxlKCRldmVudClcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICBbYXVkaW9TaWduYWxDb2xsYXBzZWRdPVwiYXVkaW9TaWduYWxDb2xsYXBzZWRcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICBbc2VsZWN0ZWRSZWNvcmRpbmdGaWxlXT1cImRpc3BsYXlSZWNGaWxlXCJcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgW3NlbGVjdERpc2FibGVkXT1cImlzQWN0aXZlKClcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICBbZGlzcGxheUF1ZGlvQ2xpcF09XCJkaXNwbGF5QXVkaW9DbGlwXCJcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgW3BsYXlTdGFydEFjdGlvbl09XCJjb250cm9sQXVkaW9QbGF5ZXIuc3RhcnRBY3Rpb25cIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICBbcGxheVN0b3BBY3Rpb25dPVwiY29udHJvbEF1ZGlvUGxheWVyLnN0b3BBY3Rpb25cIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICBbcGxheVNlbGVjdGlvbkFjdGlvbl09XCJjb250cm9sQXVkaW9QbGF5ZXIuc3RhcnRTZWxlY3Rpb25BY3Rpb25cIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICBbYXV0b1BsYXlPblNlbGVjdFRvZ2dsZUFjdGlvbl09XCJjb250cm9sQXVkaW9QbGF5ZXIuYXV0b1BsYXlPblNlbGVjdFRvZ2dsZUFjdGlvblwiXHJcbiAgICA+PC9hcHAtcmVjb3JkZXJjb21iaXBhbmU+XHJcblxyXG4gICAgPGRpdiBmeExheW91dD1cInJvd1wiIGZ4TGF5b3V0LnhzPVwiY29sdW1uXCIgW25nU3R5bGVdPVwieydoZWlnaHQucHgnOjEwMCwnbWluLWhlaWdodC5weCc6IDEwMH1cIlxyXG4gICAgICAgICBbbmdTdHlsZS54c109XCJ7J2hlaWdodC5weCc6MTI1LCdtaW4taGVpZ2h0LnB4JzogMTI1fVwiPlxyXG4gICAgICA8YXVkaW8tbGV2ZWxiYXIgZnhGbGV4PVwiMSAwIDFcIiBbc3RyZWFtaW5nTW9kZV09XCJpc1JlY29yZGluZygpXCJcclxuICAgICAgICAgICAgICAgICAgICAgIFtkaXNwbGF5TGV2ZWxJbmZvc109XCJkaXNwbGF5TGV2ZWxJbmZvc1wiPjwvYXVkaW8tbGV2ZWxiYXI+XHJcbiAgICAgIDxkaXYgZnhMYXlvdXQ9XCJyb3dcIj5cclxuICAgICAgICA8c3ByLXJlY29yZGluZ2l0ZW1jb250cm9scyBmeEZsZXg9XCIxMCAwIDFcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFthdWRpb0xvYWRlZF09XCJkaXNwbGF5QXVkaW9DbGlwPy5idWZmZXIhPT1udWxsXCJcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbcGxheVN0YXJ0QWN0aW9uXT1cImNvbnRyb2xBdWRpb1BsYXllcj8uc3RhcnRBY3Rpb25cIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtwbGF5U3RvcEFjdGlvbl09XCJjb250cm9sQXVkaW9QbGF5ZXI/LnN0b3BBY3Rpb25cIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtwZWFrRGJMdmxdPVwicGVha0xldmVsSW5EYlwiXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW2FnY109XCJ0aGlzLmFjPy5hZ2NTdGF0dXNcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChvblNob3dSZWNvcmRpbmdEZXRhaWxzKT1cImF1ZGlvU2lnbmFsQ29sbGFwc2VkPSFhdWRpb1NpZ25hbENvbGxhcHNlZFwiPlxyXG4gICAgICAgIDwvc3ByLXJlY29yZGluZ2l0ZW1jb250cm9scz5cclxuICAgICAgICA8YXBwLXVwbG9hZHN0YXR1cyBjbGFzcz1cInJpY29udHJvbHMgZGFya1wiIGZ4SGlkZSBmeFNob3cueHMgZnhGbGV4PVwiMCAwIDBcIiAqbmdJZj1cImVuYWJsZVVwbG9hZFJlY29yZGluZ3NcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgIFt2YWx1ZV09XCJ1cGxvYWRQcm9ncmVzc1wiXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgW3N0YXR1c109XCJ1cGxvYWRTdGF0dXNcIiBbYXdhaXROZXdVcGxvYWRdPVwicHJvY2Vzc2luZ1JlY29yZGluZ1wiPjwvYXBwLXVwbG9hZHN0YXR1cz5cclxuICAgICAgICA8YXBwLXJlYWR5c3RhdGVpbmRpY2F0b3IgY2xhc3M9XCJyaWNvbnRyb2xzIGRhcmtcIiBmeEhpZGUgZnhTaG93LnhzIGZ4RmxleD1cIjAgMCAwXCJcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW3JlYWR5XT1cImRhdGFTYXZlZCAmJiAhaXNBY3RpdmUoKVwiPjwvYXBwLXJlYWR5c3RhdGVpbmRpY2F0b3I+XHJcbiAgICAgIDwvZGl2PlxyXG4gICAgPC9kaXY+XHJcbiAgICA8ZGl2ICNjb250cm9scGFuZWwgY2xhc3M9XCJjb250cm9scGFuZWxcIiBmeExheW91dD1cInJvd1wiPlxyXG4gICAgICA8YXBwLXNwcnN0YXR1c2Rpc3BsYXkgZnhIaWRlLnhzIGZ4RmxleD1cIjMwJSAxIDMwJVwiIFtzdGF0dXNNc2ddPVwic3RhdHVzTXNnXCIgW3N0YXR1c0FsZXJ0VHlwZV09XCJzdGF0dXNBbGVydFR5cGVcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgW3N0YXR1c1dhaXRpbmddPVwic3RhdHVzV2FpdGluZ1wiXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImhpZGRlbi14c1wiPjwvYXBwLXNwcnN0YXR1c2Rpc3BsYXk+XHJcbiAgICAgIDxkaXYgZnhGbGV4PVwiMTAwJSAwIDEwMCVcIiBjbGFzcz1cInN0YXJ0c3RvcFwiPlxyXG4gICAgICAgIDxkaXYgc3R5bGU9XCJhbGlnbi1jb250ZW50OiBjZW50ZXJcIj5cclxuICAgICAgICA8YnV0dG9uIChjbGljayk9XCJzdGFydFN0b3BQZXJmb3JtKClcIiBbZGlzYWJsZWRdPVwic3RhcnREaXNhYmxlZCgpICYmIHN0b3BEaXNhYmxlZCgpXCIgbWF0LXJhaXNlZC1idXR0b24gY2xhc3M9XCJiaWdidXR0b25cIj5cclxuICAgICAgICAgIDxtYXQtaWNvbiBbc3R5bGUuY29sb3JdPVwic3RhcnRTdG9wTmV4dEljb25Db2xvcigpXCIgaW5saW5lPVwidHJ1ZVwiPnt7c3RhcnRTdG9wTmV4dEljb25OYW1lKCl9fTwvbWF0LWljb24+XHJcbiAgICAgICAgICA8c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiBib2xkZXI7Zm9udC1zaXplOiAxNHB4XCI+e3tzdGFydFN0b3BOZXh0TmFtZSgpfX08L3NwYW4+XHJcbiAgICAgICAgPC9idXR0b24+XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICAgIDwvZGl2PlxyXG4gICAgICA8ZGl2IGZ4RmxleD1cIjMwJSAxIDMwJVwiID5cclxuICAgICAgICA8ZGl2IGZ4RmxleD1cIjEgMSBhdXRvXCI+PC9kaXY+XHJcbiAgICAgICAgPGFwcC11cGxvYWRzdGF0dXMgY2xhc3M9XCJyaWNvbnRyb2xzXCIgZnhIaWRlLnhzIGZ4RmxleD1cIjAgMCAwXCIgKm5nSWY9XCJlbmFibGVVcGxvYWRSZWNvcmRpbmdzXCJcclxuICAgICAgICAgICAgICAgICAgICAgICAgICBbdmFsdWVdPVwidXBsb2FkUHJvZ3Jlc3NcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgIFtzdGF0dXNdPVwidXBsb2FkU3RhdHVzXCIgW2F3YWl0TmV3VXBsb2FkXT1cInByb2Nlc3NpbmdSZWNvcmRpbmdcIj48L2FwcC11cGxvYWRzdGF0dXM+XHJcbiAgICAgICAgPGFwcC1yZWFkeXN0YXRlaW5kaWNhdG9yIGNsYXNzPVwicmljb250cm9sc1wiIGZ4SGlkZS54c1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbcmVhZHldPVwiZGF0YVNhdmVkICYmICFpc0FjdGl2ZSgpXCI+PC9hcHAtcmVhZHlzdGF0ZWluZGljYXRvcj5cclxuICAgICAgPC9kaXY+XHJcbiAgICA8L2Rpdj5cclxuICBgLFxyXG4gIHN0eWxlczogW2A6aG9zdCB7XHJcbiAgICBmbGV4OiAyO1xyXG4gICAgYmFja2dyb3VuZDogbGlnaHRncmV5O1xyXG4gICAgZGlzcGxheTogZmxleDsgLyogVmVydGljYWwgZmxleCBjb250YWluZXI6IEJvdHRvbSB0cmFuc3BvcnQgcGFuZWwsIGFib3ZlIHByb21wdGluZyBwYW5lbCAqL1xyXG4gICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgIG1hcmdpbjogMDtcclxuICAgIHBhZGRpbmc6IDA7XHJcbiAgICBtaW4taGVpZ2h0OiAwcHg7XHJcblxyXG4gICAgICAvKiBQcmV2ZW50cyBob3Jpem9udGFsIHNjcm9sbCBiYXIgb24gc3dpcGUgcmlnaHQgKi9cclxuICAgICAgb3ZlcmZsb3c6IGhpZGRlbjtcclxuICB9YCxgLnJpY29udHJvbHMge1xyXG4gICAgICAgIHBhZGRpbmc6IDRweDtcclxuICAgICAgICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xyXG4gICAgICAgIGhlaWdodDogMTAwJTtcclxuICAgIH1gLGAuZGFyayB7XHJcbiAgICBiYWNrZ3JvdW5kOiBkYXJrZ3JheTtcclxuICB9YCxgLmNvbnRyb2xwYW5lbCB7XHJcbiAgICBhbGlnbi1jb250ZW50OiBjZW50ZXI7XHJcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgbWFyZ2luOiAwO1xyXG4gICAgcGFkZGluZzogMjBweDtcclxuICAgIG1pbi1oZWlnaHQ6IG1pbi1jb250ZW50OyAvKiBpbXBvcnRhbnQgKi9cclxuICB9YCxgLnN0YXJ0c3RvcCB7XHJcbiAgICB3aWR0aDogMTAwJTtcclxuICAgIHRleHQtYWxpZ246IGNlbnRlcjtcclxuICAgIGFsaWduLWNvbnRlbnQ6IGNlbnRlcjtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgfWAsYC5iaWdidXR0b24ge1xyXG4gICAgbWluLXdpZHRoOiA3MHB4O1xyXG4gICAgbWluLWhlaWdodDogNTBweDtcclxuICAgIGZvbnQtc2l6ZTogNTBweDtcclxuICAgIGJvcmRlci1yYWRpdXM6IDIwcHg7XHJcbiAgfWBcclxuICAgXVxyXG59KVxyXG5leHBvcnQgY2xhc3MgQXVkaW9SZWNvcmRlciBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQsT25EZXN0cm95LCBBdWRpb0NhcHR1cmVMaXN0ZW5lciB7XHJcblxyXG4gIF9wcm9qZWN0OlByb2plY3R8bnVsbD1udWxsO1xyXG4gIEBJbnB1dCgpIHByb2plY3ROYW1lOnN0cmluZ3xudWxsPW51bGw7XHJcbiAgZW5hYmxlVXBsb2FkUmVjb3JkaW5nczogYm9vbGVhbiA9IHRydWU7XHJcbiAgZW5hYmxlRG93bmxvYWRSZWNvcmRpbmdzOiBib29sZWFuID0gZmFsc2U7XHJcbiAgc3RhdHVzOiBTdGF0dXMgPSBTdGF0dXMuQkxPQ0tFRDtcclxuXHJcbiAgYWM6IEF1ZGlvQ2FwdHVyZXxudWxsPW51bGw7XHJcbiAgcHJpdmF0ZSBfY2hhbm5lbENvdW50ID0gMjsgLy9UT0RPIGRlZmluZSBjb25zdGFudCBmb3IgZGVmYXVsdCBmb3JtYXRcclxuICBwcml2YXRlIF9zZWxlY3RlZERldmljZUlkOnN0cmluZ3x1bmRlZmluZWQ7XHJcblxyXG4gIEBWaWV3Q2hpbGQoUmVjb3JkZXJDb21iaVBhbmUsIHsgc3RhdGljOiB0cnVlIH0pIHJlY29yZGVyQ29tYmlQYW5lITogUmVjb3JkZXJDb21iaVBhbmU7XHJcbiAgQFZpZXdDaGlsZChMZXZlbEJhciwgeyBzdGF0aWM6IHRydWUgfSkgbGl2ZUxldmVsRGlzcGxheSE6IExldmVsQmFyO1xyXG5cclxuICBASW5wdXQoKSBkYXRhU2F2ZWQ9dHJ1ZVxyXG5cclxuICAvLyBQcm9wZXJ0eSBhdWRpb0RldmljZXMgZnJvbSBwcm9qZWN0IGNvbmZpZzogbGlzdCBvZiBuYW1lcyBvZiBhbGxvd2VkIGF1ZGlvIGRldmljZXMuXHJcbiAgcHJpdmF0ZSBfYXVkaW9EZXZpY2VzOiBBcnJheTxBdWRpb0RldmljZT4gfCBudWxsIHwgdW5kZWZpbmVkO1xyXG4gIHByaXZhdGUgc2VsQ2FwdHVyZURldmljZUlkOiBDb25zdHJhaW5ET01TdHJpbmcgfCBudWxsO1xyXG4gIHByaXZhdGUgX2F1dG9HYWluQ29udHJvbENvbmZpZ3M6IEFycmF5PEF1dG9HYWluQ29udHJvbENvbmZpZz4gfCBudWxsfCB1bmRlZmluZWQ7XHJcblxyXG4gIHByaXZhdGUgc3RhcnRlZERhdGU6RGF0ZXxudWxsPW51bGw7XHJcbiAgcHJpdmF0ZSBtYXhSZWNUaW1lcklkOiBudW1iZXJ8bnVsbD1udWxsO1xyXG4gIHByaXZhdGUgbWF4UmVjVGltZXJSdW5uaW5nOiBib29sZWFuPWZhbHNlO1xyXG4gIHByaXZhdGUgdXBkYXRlVGltZXJJZDogYW55O1xyXG5cclxuICB0cmFuc3BvcnRBY3Rpb25zOiBUcmFuc3BvcnRBY3Rpb25zO1xyXG4gIHN0YXJ0U3RvcE5leHRCdXR0b25OYW1lITpzdHJpbmc7XHJcbiAgc3RhcnRTdG9wTmV4dEJ1dHRvbkljb25OYW1lITpzdHJpbmc7XHJcbiAgcGxheVN0YXJ0QWN0aW9uOiBBY3Rpb248dm9pZD47XHJcbiAgYXVkaW86IGFueTtcclxuXHJcbiAgX3Nlc3Npb246IFNlc3Npb258bnVsbD1udWxsO1xyXG5cclxuICBwcml2YXRlIF9wcm9tcHRJbmRleDpudW1iZXJ8bnVsbD1udWxsO1xyXG5cclxuICAvL2l0ZW1zOiBBcnJheTxJdGVtPnxudWxsPW51bGw7XHJcbiAgLy9zZWxlY3RlZEl0ZW1JZHg6IG51bWJlcjtcclxuICBwcml2YXRlIF9kaXNwbGF5UmVjRmlsZTogUmVjb3JkaW5nRmlsZSB8IG51bGw9bnVsbDtcclxuICBwcml2YXRlIGRpc3BsYXlSZWNGaWxlVmVyc2lvbjogbnVtYmVyPTA7XHJcbiAgZGlzcGxheUF1ZGlvQ2xpcDogQXVkaW9DbGlwIHwgbnVsbD1udWxsO1xyXG5cclxuICBkaXNwbGF5TGV2ZWxJbmZvczogTGV2ZWxJbmZvcyB8IG51bGw9bnVsbDtcclxuXHJcbiAgcGVha0xldmVsSW5EYjpudW1iZXI9TUlOX0RCX0xFVkVMO1xyXG5cclxuICByZWFkb25seT1mYWxzZVxyXG5cclxuICBzdGF0dXNNc2c6IHN0cmluZz0nJztcclxuICBzdGF0dXNBbGVydFR5cGUhOiBzdHJpbmc7XHJcbiAgc3RhdHVzV2FpdGluZzogYm9vbGVhbj1mYWxzZTtcclxuXHJcbiAgcHJvY2Vzc2luZ1JlY29yZGluZz1mYWxzZVxyXG5cclxuICB1cGxvYWRQcm9ncmVzczogbnVtYmVyID0gMTAwO1xyXG4gIHVwbG9hZFN0YXR1czogc3RyaW5nID0gJ29rJ1xyXG4gIGF1ZGlvU2lnbmFsQ29sbGFwc2VkID0gdHJ1ZTtcclxuXHJcbiAgcHJpdmF0ZSBzdHJlYW1MZXZlbE1lYXN1cmU6IFN0cmVhbUxldmVsTWVhc3VyZTtcclxuICBwcml2YXRlIGxldmVsTWVhc3VyZTogTGV2ZWxNZWFzdXJlO1xyXG4gIHByaXZhdGUgX2NvbnRyb2xBdWRpb1BsYXllciE6IEF1ZGlvUGxheWVyO1xyXG5cclxuICBwcml2YXRlIGF1ZGlvRmV0Y2hTdWJzY3JpcHRpb246U3Vic2NyaXB0aW9ufG51bGw9bnVsbDtcclxuXHJcbiAgcHJpdmF0ZSBkZXN0cm95ZWQ9ZmFsc2U7XHJcblxyXG4gIHByaXZhdGUgbmF2aWdhdGlvbkRpc2FibGVkPXRydWU7XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgY2hhbmdlRGV0ZWN0b3JSZWY6IENoYW5nZURldGVjdG9yUmVmLFxyXG4gICAgICAgICAgICAgIHByaXZhdGUgcm91dGU6IEFjdGl2YXRlZFJvdXRlLFxyXG4gICAgICAgICAgICAgIHByaXZhdGUgcmVuZGVyZXI6IFJlbmRlcmVyMixcclxuICAgICAgICAgICAgICBwdWJsaWMgZGlhbG9nOiBNYXREaWFsb2csXHJcbiAgICAgICAgICAgICAgcHJpdmF0ZSBwcm9qZWN0U2VydmljZTpQcm9qZWN0U2VydmljZSxcclxuICAgICAgICAgICAgICBwcml2YXRlIHNlc3Npb25TZXJ2aWNlOlNlc3Npb25TZXJ2aWNlLFxyXG4gICAgICAgICAgICAgIHByaXZhdGUgcmVjRmlsZVNlcnZpY2U6UmVjb3JkaW5nU2VydmljZSxcclxuICAgICAgICAgICAgICBwcml2YXRlIHVwbG9hZGVyOiBTcGVlY2hSZWNvcmRlclVwbG9hZGVyLFxyXG4gICAgICAgICAgICAgIEBJbmplY3QoU1BFRUNIUkVDT1JERVJfQ09ORklHKSBwdWJsaWMgY29uZmlnPzogU3BlZWNoUmVjb3JkZXJDb25maWcpIHtcclxuICAgIHRoaXMuc3RhdHVzID0gU3RhdHVzLklETEU7XHJcbiAgICB0aGlzLnRyYW5zcG9ydEFjdGlvbnMgPSBuZXcgVHJhbnNwb3J0QWN0aW9ucygpO1xyXG4gICAgdGhpcy5wbGF5U3RhcnRBY3Rpb24gPSBuZXcgQWN0aW9uKCdQbGF5Jyk7XHJcbiAgICB0aGlzLmF1ZGlvID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2F1ZGlvJyk7XHJcbiAgICB0aGlzLnNlbENhcHR1cmVEZXZpY2VJZCA9IG51bGw7XHJcbiAgICB0aGlzLmxldmVsTWVhc3VyZSA9IG5ldyBMZXZlbE1lYXN1cmUoKTtcclxuICAgIHRoaXMuc3RyZWFtTGV2ZWxNZWFzdXJlID0gbmV3IFN0cmVhbUxldmVsTWVhc3VyZSgpO1xyXG4gICAgaWYgKHRoaXMuY29uZmlnICYmIHRoaXMuY29uZmlnLmVuYWJsZVVwbG9hZFJlY29yZGluZ3MgIT0gbnVsbCkge1xyXG4gICAgICB0aGlzLmVuYWJsZVVwbG9hZFJlY29yZGluZ3MgPSB0aGlzLmNvbmZpZy5lbmFibGVVcGxvYWRSZWNvcmRpbmdzO1xyXG4gICAgfVxyXG4gICAgaWYgKHRoaXMuY29uZmlnICYmIHRoaXMuY29uZmlnLmVuYWJsZURvd25sb2FkUmVjb3JkaW5ncyAhPSBudWxsKSB7XHJcbiAgICAgIHRoaXMuZW5hYmxlRG93bmxvYWRSZWNvcmRpbmdzID0gdGhpcy5jb25maWcuZW5hYmxlRG93bmxvYWRSZWNvcmRpbmdzO1xyXG4gICAgfVxyXG4gICAgdGhpcy5pbml0KCk7XHJcbiAgfVxyXG5cclxuICBuZ0FmdGVyVmlld0luaXQoKSB7XHJcbiAgICB0aGlzLnJvdXRlLnF1ZXJ5UGFyYW1zLnN1YnNjcmliZSgocGFyYW1zOiBQYXJhbXMpID0+IHtcclxuICAgICAgaWYgKHBhcmFtc1snc2Vzc2lvbklkJ10pIHtcclxuICAgICAgICB0aGlzLmZldGNoU2Vzc2lvbihwYXJhbXNbJ3Nlc3Npb25JZCddKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgICB0aGlzLnN0cmVhbUxldmVsTWVhc3VyZS5sZXZlbExpc3RlbmVyID0gdGhpcy5saXZlTGV2ZWxEaXNwbGF5O1xyXG4gICAgdGhpcy5zdHJlYW1MZXZlbE1lYXN1cmUucGVha0xldmVsTGlzdGVuZXI9KHBlYWtMdmxJbkRiKT0+e1xyXG4gICAgICB0aGlzLnBlYWtMZXZlbEluRGI9cGVha0x2bEluRGI7XHJcbiAgICAgIHRoaXMuY2hhbmdlRGV0ZWN0b3JSZWYuZGV0ZWN0Q2hhbmdlcygpO1xyXG4gICAgfVxyXG4gIH1cclxuICAgIG5nT25EZXN0cm95KCkge1xyXG4gICAgICAgdGhpcy5kZXN0cm95ZWQ9dHJ1ZTtcclxuICAgICAgIC8vIFRPRE8gc3RvcCBjYXB0dXJlIC9wbGF5YmFja1xyXG4gICAgfVxyXG5cclxuICBwcml2YXRlIGluaXQoKSB7XHJcblxyXG4gICAgdGhpcy50cmFuc3BvcnRBY3Rpb25zLnN0YXJ0QWN0aW9uLmRpc2FibGVkID0gdHJ1ZTtcclxuICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucy5zdG9wQWN0aW9uLmRpc2FibGVkID0gdHJ1ZTtcclxuICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucy5uZXh0QWN0aW9uLmRpc2FibGVkID0gdHJ1ZTtcclxuICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucy5wYXVzZUFjdGlvbi5kaXNhYmxlZCA9IHRydWU7XHJcbiAgICB0aGlzLnBsYXlTdGFydEFjdGlvbi5kaXNhYmxlZCA9IHRydWU7XHJcblxyXG4gICAgbGV0IGNvbnRleHQ9bnVsbDtcclxuICAgIHRyeSB7XHJcbiAgICAgIGNvbnRleHQgPSBBdWRpb0NvbnRleHRQcm92aWRlci5hdWRpb0NvbnRleHRJbnN0YW5jZSgpXHJcbiAgICB9IGNhdGNoIChlcnIpIHtcclxuICAgICAgdGhpcy5zdGF0dXMgPSBTdGF0dXMuRVJST1I7XHJcbiAgICAgIGxldCBlcnJNc2cgPSAnVW5rbm93bic7XHJcbiAgICAgIGlmKGVyciBpbnN0YW5jZW9mIEVycm9yKXtcclxuICAgICAgICBlcnJNc2c9ZXJyLm1lc3NhZ2U7XHJcbiAgICAgIH1cclxuICAgICAgdGhpcy5zdGF0dXNNc2cgPSAnRVJST1I6ICcgKyBlcnJNc2c7XHJcbiAgICAgIHRoaXMuc3RhdHVzQWxlcnRUeXBlID0gJ2Vycm9yJztcclxuICAgICAgdGhpcy5kaWFsb2cub3BlbihNZXNzYWdlRGlhbG9nLCB7XHJcbiAgICAgICAgZGF0YToge1xyXG4gICAgICAgICAgdHlwZTogJ2Vycm9yJyxcclxuICAgICAgICAgIHRpdGxlOiAnRXJyb3InLFxyXG4gICAgICAgICAgbXNnOiBlcnJNc2csXHJcbiAgICAgICAgICBhZHZpc2U6ICdQbGVhc2UgdXNlIGEgc3VwcG9ydGVkIGJyb3dzZXIuJyxcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICBpZihjb250ZXh0KSB7XHJcbiAgICAgIGNvbnNvbGUuaW5mbyhcIlN0YXRlIG9mIGF1ZGlvIGNvbnRleHQ6IFwiICsgY29udGV4dC5zdGF0ZSlcclxuICAgIH1cclxuICAgIGlmICghY29udGV4dCB8fCAhbmF2aWdhdG9yLm1lZGlhRGV2aWNlcykge1xyXG4gICAgICB0aGlzLnN0YXR1cyA9IFN0YXR1cy5FUlJPUjtcclxuICAgICAgbGV0IGVyck1zZyA9ICdCcm93c2VyIGRvZXMgbm90IHN1cHBvcnQgTWVkaWEgc3RyZWFtcyEnO1xyXG4gICAgICB0aGlzLnN0YXR1c01zZyA9ICdFUlJPUjogJyArIGVyck1zZztcclxuICAgICAgdGhpcy5zdGF0dXNBbGVydFR5cGUgPSAnZXJyb3InO1xyXG4gICAgICB0aGlzLmRpYWxvZy5vcGVuKE1lc3NhZ2VEaWFsb2csIHtcclxuICAgICAgICBkYXRhOiB7XHJcbiAgICAgICAgICB0eXBlOiAnZXJyb3InLFxyXG4gICAgICAgICAgdGl0bGU6ICdFcnJvcicsXHJcbiAgICAgICAgICBtc2c6IGVyck1zZyxcclxuICAgICAgICAgIGFkdmlzZTogJ1BsZWFzZSB1c2UgYSBzdXBwb3J0ZWQgYnJvd3Nlci4nLFxyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMuY29udHJvbEF1ZGlvUGxheWVyID0gbmV3IEF1ZGlvUGxheWVyKGNvbnRleHQsIHRoaXMpO1xyXG4gICAgICB0aGlzLmFjID0gbmV3IEF1ZGlvQ2FwdHVyZShjb250ZXh0KTtcclxuICAgICAgaWYgKHRoaXMuYWMpIHtcclxuICAgICAgICB0aGlzLnRyYW5zcG9ydEFjdGlvbnMuc3RhcnRBY3Rpb24ub25BY3Rpb24gPSAoKSA9PiB0aGlzLnN0YXJ0SXRlbSgpO1xyXG4gICAgICAgIHRoaXMuYWMubGlzdGVuZXIgPSB0aGlzO1xyXG4gICAgICAgIHRoaXMuYWMuYXVkaW9PdXRTdHJlYW0gPSBuZXcgU2VxdWVuY2VBdWRpb0Zsb2F0MzJDaHVua2VyT3V0U3RyZWFtKHRoaXMuc3RyZWFtTGV2ZWxNZWFzdXJlLCBMRVZFTF9CQVJfSU5URVJWQUxMX1NFQ09ORFMpO1xyXG4gICAgICAgIC8vIERvbid0IGxpc3QgdGhlIGRldmljZXMgaGVyZS4gSWYgd2UgZG8gbm90IGhhdmUgYXVkaW8gcGVybWlzc2lvbnMgd2Ugb25seSBnZXQgYW5vbnltaXplZCBkZXZpY2VzIHdpdGhvdXQgbGFiZWxzLlxyXG4gICAgICAgIC8vdGhpcy5hYy5saXN0RGV2aWNlcygpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucy5zdGFydEFjdGlvbi5kaXNhYmxlZCA9IHRydWU7XHJcbiAgICAgICAgbGV0IGVyck1zZyA9ICdCcm93c2VyIGRvZXMgbm90IHN1cHBvcnQgTWVkaWEvQXVkaW8gQVBJISc7XHJcbiAgICAgICAgdGhpcy5zdGF0dXNNc2cgPSAnRVJST1I6ICcgKyBlcnJNc2c7XHJcbiAgICAgICAgdGhpcy5zdGF0dXNBbGVydFR5cGUgPSAnZXJyb3InO1xyXG4gICAgICAgIHRoaXMuZGlhbG9nLm9wZW4oTWVzc2FnZURpYWxvZywge1xyXG4gICAgICAgICAgZGF0YToge1xyXG4gICAgICAgICAgICB0eXBlOiAnZXJyb3InLFxyXG4gICAgICAgICAgICB0aXRsZTogJ0Vycm9yJyxcclxuICAgICAgICAgICAgbXNnOiBlcnJNc2csXHJcbiAgICAgICAgICAgIGFkdmlzZTogJ1BsZWFzZSB1c2UgYSBzdXBwb3J0ZWQgYnJvd3Nlci4nLFxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG4gICAgICB0aGlzLnRyYW5zcG9ydEFjdGlvbnMuc3RvcEFjdGlvbi5vbkFjdGlvbiA9ICgpID0+IHRoaXMuc3RvcEl0ZW0oKTtcclxuICAgICAgdGhpcy50cmFuc3BvcnRBY3Rpb25zLm5leHRBY3Rpb24ub25BY3Rpb24gPSAoKSA9PiB0aGlzLnN0b3BJdGVtKCk7XHJcbiAgICAgIC8vdGhpcy50cmFuc3BvcnRBY3Rpb25zLnBhdXNlQWN0aW9uLm9uQWN0aW9uID0gKCkgPT4gdGhpcy5wYXVzZUl0ZW0oKTtcclxuXHJcbiAgICAgIHRoaXMucGxheVN0YXJ0QWN0aW9uLm9uQWN0aW9uID0gKCkgPT4gdGhpcy5jb250cm9sQXVkaW9QbGF5ZXIuc3RhcnQoKTtcclxuXHJcbiAgICB9XHJcbiAgICB0aGlzLnVwbG9hZGVyLmxpc3RlbmVyID0gKHVlKSA9PiB7XHJcbiAgICAgIHRoaXMudXBsb2FkVXBkYXRlKHVlKTtcclxuICAgIH1cclxufVxyXG5cclxuICBASG9zdExpc3RlbmVyKCd3aW5kb3c6a2V5cHJlc3MnLCBbJyRldmVudCddKVxyXG4gIG9uS2V5UHJlc3Moa2U6IEtleWJvYXJkRXZlbnQpIHtcclxuICAgIGlmIChrZS5rZXkgPT0gJyAnKSB7XHJcbiAgICAgIC8vdGhpcy50cmFuc3BvcnRBY3Rpb25zLnN0YXJ0QWN0aW9uLnBlcmZvcm0oKTtcclxuICAgICAgLy90aGlzLnRyYW5zcG9ydEFjdGlvbnMubmV4dEFjdGlvbi5wZXJmb3JtKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBASG9zdExpc3RlbmVyKCd3aW5kb3c6a2V5ZG93bicsIFsnJGV2ZW50J10pXHJcbiAgb25LZXlEb3duKGtlOiBLZXlib2FyZEV2ZW50KSB7XHJcbiAgICBpZiAoa2Uua2V5ID09ICcgJykge1xyXG4gICAgICBpZighdGhpcy50cmFuc3BvcnRBY3Rpb25zLnN0YXJ0QWN0aW9uLmRpc2FibGVkKXtcclxuICAgICAgICB0aGlzLnRyYW5zcG9ydEFjdGlvbnMuc3RhcnRBY3Rpb24ucGVyZm9ybSgpO1xyXG4gICAgICB9ZWxzZSBpZighdGhpcy50cmFuc3BvcnRBY3Rpb25zLnN0b3BBY3Rpb24uZGlzYWJsZWQpIHtcclxuICAgICAgICB0aGlzLnRyYW5zcG9ydEFjdGlvbnMuc3RvcEFjdGlvbi5wZXJmb3JtKCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGlmIChrZS5rZXkgPT0gJ3AnKSB7XHJcbiAgICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucy5wYXVzZUFjdGlvbi5wZXJmb3JtKCk7XHJcbiAgICB9XHJcbiAgICBpZiAoa2Uua2V5ID09ICdFc2NhcGUnKSB7XHJcbiAgICAgIGlmICghdGhpcy5hdWRpb1NpZ25hbENvbGxhcHNlZCkge1xyXG4gICAgICAgIHRoaXMuYXVkaW9TaWduYWxDb2xsYXBzZWQgPSB0cnVlO1xyXG4gICAgICB9XHJcbiAgICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucy5zdG9wQWN0aW9uLnBlcmZvcm0oKTtcclxuICAgICAgdGhpcy50cmFuc3BvcnRBY3Rpb25zLnBhdXNlQWN0aW9uLnBlcmZvcm0oKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoa2Uua2V5ID09ICdNZWRpYVBsYXlQYXVzZScpIHtcclxuICAgICAgdGhpcy5wbGF5U3RhcnRBY3Rpb24ucGVyZm9ybSgpO1xyXG4gICAgfVxyXG4gICAgaWYgKGtlLmtleSA9PT0gJ0Fycm93UmlnaHQnKSB7XHJcbiAgICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucy5md2RBY3Rpb24ucGVyZm9ybSgpO1xyXG4gICAgfVxyXG4gICAgaWYgKGtlLmtleSA9PT0gJ0Fycm93TGVmdCcpIHtcclxuICAgICAgdGhpcy50cmFuc3BvcnRBY3Rpb25zLmJ3ZEFjdGlvbi5wZXJmb3JtKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBpc1Rlc3RTZXNzaW9uKCk6Ym9vbGVhbiB7XHJcbiAgICByZXR1cm4gKCh0aGlzLl9zZXNzaW9uIT1udWxsKSAmJiAodGhpcy5fc2Vzc2lvbi50eXBlID09PSAnVEVTVCcgfHwgdGhpcy5fc2Vzc2lvbi50eXBlPT09J1RFU1RfREVGX0EnIHx8IHRoaXMuX3Nlc3Npb24udHlwZSA9PT0gJ1NJTlVTX1RFU1QnKSk7XHJcbiAgfVxyXG5cclxuICBpc0RlZmF1bHRBdWRpb1Rlc3RTZXNzaW9uKCk6Ym9vbGVhbiB7XHJcbiAgICByZXR1cm4gKCh0aGlzLl9zZXNzaW9uIT1udWxsKSAmJiAodGhpcy5fc2Vzc2lvbi50eXBlPT09J1RFU1RfREVGX0EnKSk7XHJcbiAgfVxyXG5cclxuICBpc0RlZmF1bHRBdWRpb1Rlc3RTZXNzaW9uT3ZlcndyaXRlaW5nUHJvamVjdFJlcXVpcmVtZW50cygpOmJvb2xlYW4ge1xyXG4gICAgcmV0dXJuICgodGhpcy5fc2Vzc2lvbiE9bnVsbCkgJiYgKHRoaXMuX3Nlc3Npb24udHlwZT09PSdURVNUX0RFRl9BJykgJiYgKHRoaXMuYXVkaW9EZXZpY2VzIT1udWxsKSAmJiB0aGlzLmF1ZGlvRGV2aWNlcy5sZW5ndGg+MClcclxuICB9XHJcblxyXG4gIGZldGNoU2Vzc2lvbihzZXNzaW9uSWQ6c3RyaW5nKXtcclxuXHJcblxyXG4gICAgLy9FcnJvcjogRXhwcmVzc2lvbkNoYW5nZWRBZnRlckl0SGFzQmVlbkNoZWNrZWRFcnJvcjogRXhwcmVzc2lvbiBoYXMgY2hhbmdlZCBhZnRlciBpdCB3YXMgY2hlY2tlZC4gUHJldmlvdXMgdmFsdWU6ICdzdGF0dXNNc2c6IFBsYXllciBpbml0aWFsaXplZC4nLiBDdXJyZW50IHZhbHVlOiAnc3RhdHVzTXNnOiBGZXRjaGluZyBzZXNzaW9uIGluZm8uLi4nLlxyXG4gICAgLy8gcGFyYW1zLnN1YnNjcmliZSBzZWVtcyBub3QgdG8gYmUgYXN5bmNocm9ub3VzXHJcblxyXG4gICAgLy8gdGhpcy5zbS5zdGF0dXNBbGVydFR5cGU9J2luZm8nO1xyXG4gICAgLy8gdGhpcy5zbS5zdGF0dXNNc2cgPSAnRmV0Y2hpbmcgc2Vzc2lvbiBpbmZvLi4uJztcclxuICAgIC8vIHRoaXMuc20uc3RhdHVzV2FpdGluZz10cnVlO1xyXG4gICAgbGV0IHNlc3NPYnM9IHRoaXMuc2Vzc2lvblNlcnZpY2Uuc2Vzc2lvbk9ic2VydmVyKHNlc3Npb25JZCk7XHJcblxyXG4gICAgaWYoc2Vzc09icykge1xyXG4gICAgICBzZXNzT2JzLnN1YnNjcmliZShzZXNzID0+IHtcclxuICAgICAgICAgIC8vdGhpcy5zZXRTZXNzaW9uKHNlc3MpO1xyXG4gICAgICAgICAgdGhpcy5zdGF0dXNBbGVydFR5cGU9J2luZm8nO1xyXG4gICAgICAgICAgdGhpcy5zdGF0dXNNc2cgPSAnUmVjZWl2ZWQgc2Vzc2lvbiBpbmZvLic7XHJcbiAgICAgICAgICB0aGlzLnN0YXR1c1dhaXRpbmc9ZmFsc2U7XHJcbiAgICAgICAgICB0aGlzLnNlc3Npb249c2VzcztcclxuICAgICAgICAgIGlmIChzZXNzLnByb2plY3QpIHtcclxuICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiU2Vzc2lvbiBhc3NvY2lhdGVkIHByb2plY3Q6IFwiK3Nlc3MucHJvamVjdClcclxuICAgICAgICAgICAgdGhpcy5wcm9qZWN0U2VydmljZS5wcm9qZWN0T2JzZXJ2YWJsZShzZXNzLnByb2plY3QpLnN1YnNjcmliZShwcm9qZWN0PT57XHJcbiAgICAgICAgICAgICAgdGhpcy5wcm9qZWN0PXByb2plY3Q7XHJcbiAgICAgICAgICAgICAgdGhpcy5mZXRjaFJlY29yZGluZ3Moc2Vzcyk7XHJcbiAgICAgICAgICAgIH0scmVhc29uID0+e1xyXG4gICAgICAgICAgICAgIHRoaXMuc3RhdHVzTXNnPXJlYXNvbjtcclxuICAgICAgICAgICAgICB0aGlzLnN0YXR1c0FsZXJ0VHlwZT0nZXJyb3InO1xyXG4gICAgICAgICAgICAgIHRoaXMuc3RhdHVzV2FpdGluZz1mYWxzZTtcclxuICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3IgZmV0Y2hpbmcgcHJvamVjdCBjb25maWc6IFwiK3JlYXNvbilcclxuICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiU2Vzc2lvbiBoYXMgbm8gYXNzb2NpYXRlZCBwcm9qZWN0LiBVc2luZyBkZWZhdWx0IGNvbmZpZ3VyYXRpb24uXCIpXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSxcclxuICAgICAgICAocmVhc29uKSA9PiB7XHJcbiAgICAgICAgICB0aGlzLnN0YXR1c01zZyA9IHJlYXNvbjtcclxuICAgICAgICAgIHRoaXMuc3RhdHVzQWxlcnRUeXBlID0gJ2Vycm9yJztcclxuICAgICAgICAgIHRoaXMuc3RhdHVzV2FpdGluZz1mYWxzZTtcclxuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciBmZXRjaGluZyBzZXNzaW9uIFwiICsgcmVhc29uKVxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZmV0Y2hSZWNvcmRpbmdzKHNlc3M6U2Vzc2lvbil7XHJcbiAgICB0aGlzLnN0YXR1c0FsZXJ0VHlwZT0naW5mbyc7XHJcbiAgICB0aGlzLnN0YXR1c01zZyA9ICdGZXRjaGluZyBpbmZvcyBvZiByZWNvcmRpbmdzLi4uJztcclxuICAgIHRoaXMuc3RhdHVzV2FpdGluZz10cnVlO1xyXG4gICAgbGV0IHByTm06c3RyaW5nfG51bGw9bnVsbDtcclxuICAgIGlmKHRoaXMucHJvamVjdCkge1xyXG4gICAgICBsZXQgcmZzT2JzID0gdGhpcy5yZWNGaWxlU2VydmljZS5yZWNvcmRpbmdGaWxlTGlzdCh0aGlzLnByb2plY3QubmFtZSwgc2Vzcy5zZXNzaW9uSWQpO1xyXG4gICAgICByZnNPYnMuc3Vic2NyaWJlKChyZnM6IEFycmF5PFJlY29yZGluZ0ZpbGU+KSA9PiB7XHJcbiAgICAgICAgdGhpcy5zdGF0dXNBbGVydFR5cGUgPSAnaW5mbyc7XHJcbiAgICAgICAgdGhpcy5zdGF0dXNNc2cgPSAnUmVjZWl2ZWQgaW5mb3Mgb2YgcmVjb3JkaW5ncy4nO1xyXG4gICAgICAgIHRoaXMuc3RhdHVzV2FpdGluZyA9IGZhbHNlO1xyXG4gICAgICAgIGlmIChyZnMpIHtcclxuICAgICAgICAgIGlmIChyZnMgaW5zdGFuY2VvZiBBcnJheSkge1xyXG4gICAgICAgICAgICByZnMuZm9yRWFjaCgocmYpID0+IHtcclxuICAgICAgICAgICAgICBpZihyZi5zdGFydGVkRGF0ZSl7XHJcbiAgICAgICAgICAgICAgICByZi5fc3RhcnRlZEFzRGF0ZU9iaj1uZXcgRGF0ZShyZi5zdGFydGVkRGF0ZSk7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIGlmKHJmLmRhdGUpe1xyXG4gICAgICAgICAgICAgICAgcmYuX2RhdGVBc0RhdGVPYmo9bmV3IERhdGUocmYuZGF0ZSk7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIHRoaXMucmVjb3JkZXJDb21iaVBhbmUucHVzaChyZik7XHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdFeHBlY3RlZCB0eXBlIGFycmF5IGZvciBsaXN0IG9mIGFscmVhZHkgcmVjb3JkZWQgZmlsZXMgJylcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIC8vY29uc29sZS5kZWJ1ZyhcIlJlY29yZGluZyBmaWxlIGxpc3Q6IFwiICsgcmZzKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0sICgpID0+IHtcclxuICAgICAgICAvLyBGYWlsZWQgZmV0Y2hpbmcgZXhpc3RpbmcsIGJ1dCB3ZSBzdGFydCB0aGUgc2Vzc2lvbiBhbnl3YXlcclxuICAgICAgICB0aGlzLnN0YXJ0KClcclxuICAgICAgfSwgKCkgPT4ge1xyXG4gICAgICAgIC8vIE5vcm1hbCBzdGFydFxyXG4gICAgICAgIHRoaXMuc3RhcnQoKVxyXG4gICAgICB9KVxyXG4gICAgfWVsc2V7XHJcbiAgICAgIC8vIE5vIHByb2plY3QgZGVmIC0+IGVycm9yXHJcbiAgICAgIHRoaXMuc3RhdHVzQWxlcnRUeXBlID0gJ2Vycm9yJztcclxuICAgICAgdGhpcy5zdGF0dXNNc2cgPSAnTm8gcHJvamVjdCBkZWZpbml0b24uJztcclxuICAgICAgdGhpcy5zdGF0dXNXYWl0aW5nID0gZmFsc2U7XHJcbiAgICAgIGNvbnNvbGUuZXJyb3IodGhpcy5zdGF0dXNNc2cpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcblxyXG4gIHNldCBwcm9qZWN0KHByb2plY3Q6IFByb2plY3R8bnVsbCkge1xyXG4gICAgdGhpcy5fcHJvamVjdCA9IHByb2plY3Q7XHJcbiAgICBsZXQgY2hDbnQgPSBQcm9qZWN0VXRpbC5ERUZBVUxUX0FVRElPX0NIQU5ORUxfQ09VTlQ7XHJcblxyXG4gICAgaWYgKHByb2plY3QpIHtcclxuICAgICAgY29uc29sZS5pbmZvKFwiUHJvamVjdCBuYW1lOiBcIiArIHByb2plY3QubmFtZSlcclxuICAgICAgdGhpcy5hdWRpb0RldmljZXMgPSBwcm9qZWN0LmF1ZGlvRGV2aWNlcztcclxuICAgICAgY2hDbnQgPSBQcm9qZWN0VXRpbC5hdWRpb0NoYW5uZWxDb3VudChwcm9qZWN0KTtcclxuICAgICAgY29uc29sZS5pbmZvKFwiUHJvamVjdCByZXF1ZXN0ZWQgcmVjb3JkaW5nIGNoYW5uZWwgY291bnQ6IFwiICsgY2hDbnQpO1xyXG4gICAgICB0aGlzLmF1dG9HYWluQ29udHJvbENvbmZpZ3M9cHJvamVjdC5hdXRvR2FpbkNvbnRyb2xDb25maWdzO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgY29uc29sZS5lcnJvcihcIkVtcHR5IHByb2plY3QgY29uZmlndXJhdGlvbiFcIilcclxuICAgIH1cclxuICAgIHRoaXMuY2hhbm5lbENvdW50ID0gY2hDbnQ7XHJcbiAgfVxyXG5cclxuICBnZXQgcHJvamVjdCgpOlByb2plY3R8bnVsbHtcclxuICAgIHJldHVybiB0aGlzLl9wcm9qZWN0O1xyXG4gIH1cclxuXHJcbiAgc2V0IGF1dG9HYWluQ29udHJvbENvbmZpZ3MoYXV0b0dhaW5Db250cm9sQ29uZmlnczogQXJyYXk8QXV0b0dhaW5Db250cm9sQ29uZmlnPnxudWxsfHVuZGVmaW5lZCl7XHJcbiAgICB0aGlzLl9hdXRvR2FpbkNvbnRyb2xDb25maWdzPWF1dG9HYWluQ29udHJvbENvbmZpZ3M7XHJcbiAgfVxyXG5cclxuICBzZWxlY3RSZWNvcmRpbmdGaWxlKHJmOlJlY29yZGluZ0ZpbGUpe1xyXG4gICAgdGhpcy5kaXNwbGF5UmVjRmlsZT1yZjtcclxuICB9XHJcblxyXG4gIHVwbG9hZFVwZGF0ZSh1ZTogVXBsb2FkZXJTdGF0dXNDaGFuZ2VFdmVudCkge1xyXG4gICAgbGV0IHVwU3RhdHVzID0gdWUuc3RhdHVzO1xyXG4gICAgdGhpcy5kYXRhU2F2ZWQgPSAoVXBsb2FkZXJTdGF0dXMuRE9ORSA9PT0gdXBTdGF0dXMpO1xyXG4gICAgbGV0IHBlcmNlbnRVcGwgPSB1ZS5wZXJjZW50RG9uZSgpO1xyXG4gICAgaWYgKFVwbG9hZGVyU3RhdHVzLkVSUiA9PT0gdXBTdGF0dXMpIHtcclxuICAgICAgdGhpcy51cGxvYWRTdGF0dXMgPSAnd2FybidcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGlmIChwZXJjZW50VXBsIDwgNTApIHtcclxuICAgICAgICB0aGlzLnVwbG9hZFN0YXR1cyA9ICdhY2NlbnQnXHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhpcy51cGxvYWRTdGF0dXMgPSAnc3VjY2VzcydcclxuICAgICAgfVxyXG4gICAgICB0aGlzLnVwbG9hZFByb2dyZXNzID0gcGVyY2VudFVwbDtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLmNoYW5nZURldGVjdG9yUmVmLmRldGVjdENoYW5nZXMoKVxyXG4gIH1cclxuXHJcbiAgc2V0IGNvbnRyb2xBdWRpb1BsYXllcihjb250cm9sQXVkaW9QbGF5ZXI6IEF1ZGlvUGxheWVyKSB7XHJcbiAgICBpZiAodGhpcy5fY29udHJvbEF1ZGlvUGxheWVyKSB7XHJcbiAgICAgIC8vdGhpcy5fY29udHJvbEF1ZGlvUGxheWVyLmxpc3RlbmVyPW51bGw7XHJcbiAgICB9XHJcbiAgICB0aGlzLl9jb250cm9sQXVkaW9QbGF5ZXIgPSBjb250cm9sQXVkaW9QbGF5ZXI7XHJcbiAgICBpZiAodGhpcy5fY29udHJvbEF1ZGlvUGxheWVyKSB7XHJcbiAgICAgIHRoaXMuX2NvbnRyb2xBdWRpb1BsYXllci5saXN0ZW5lciA9IHRoaXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBnZXQgY29udHJvbEF1ZGlvUGxheWVyKCk6IEF1ZGlvUGxheWVyIHtcclxuICAgIHJldHVybiB0aGlzLl9jb250cm9sQXVkaW9QbGF5ZXI7XHJcbiAgfVxyXG5cclxuICBzZXQgc2Vzc2lvbihzZXNzaW9uOiBTZXNzaW9ufG51bGwpIHtcclxuICAgIHRoaXMuX3Nlc3Npb24gPSBzZXNzaW9uO1xyXG4gIH1cclxuXHJcbiAgZ2V0IHNlc3Npb24oKTpTZXNzaW9ufG51bGx7XHJcbiAgICByZXR1cm4gdGhpcy5fc2Vzc2lvbjtcclxuICB9XHJcblxyXG4gIHNldCBjaGFubmVsQ291bnQoY2hhbm5lbENvdW50OiBudW1iZXIpIHtcclxuICAgIHRoaXMuX2NoYW5uZWxDb3VudCA9IGNoYW5uZWxDb3VudDtcclxuICB9XHJcblxyXG4gIHNldCBhdWRpb0RldmljZXMoYXVkaW9EZXZpY2VzOiBBcnJheTxBdWRpb0RldmljZT4gfCBudWxsIHwgdW5kZWZpbmVkKSB7XHJcbiAgICB0aGlzLl9hdWRpb0RldmljZXMgPSBhdWRpb0RldmljZXM7XHJcbiAgfVxyXG5cclxuICB1cGRhdGUoZTogQXVkaW9QbGF5ZXJFdmVudCkge1xyXG4gICAgaWYgKGUudHlwZSA9PSBFdmVudFR5cGUuU1RBUlRFRCkge1xyXG4gICAgICB0aGlzLnBsYXlTdGFydEFjdGlvbi5kaXNhYmxlZCA9IHRydWU7XHJcbiAgICAgIHRoaXMudXBkYXRlVGltZXJJZCA9IHdpbmRvdy5zZXRJbnRlcnZhbCgoKSA9PiB7XHJcbiAgICAgICAgLy90aGlzLmF1ZGlvU2lnbmFsLnBsYXlGcmFtZVBvc2l0aW9uID0gdGhpcy5hcC5wbGF5UG9zaXRpb25GcmFtZXM7XHJcbiAgICAgIH0sIDUwKTtcclxuICAgIH0gZWxzZSBpZiAoZS50eXBlID09IEV2ZW50VHlwZS5TVE9QUEVEIHx8IGUudHlwZSA9PSBFdmVudFR5cGUuRU5ERUQpIHtcclxuICAgICAgd2luZG93LmNsZWFySW50ZXJ2YWwodGhpcy51cGRhdGVUaW1lcklkKTtcclxuICAgICAgLy8gdGhpcy5hdWRpb1NpZ25hbC5wbGF5RnJhbWVQb3NpdGlvbiA9IHRoaXMuYXAucGxheVBvc2l0aW9uRnJhbWVzO1xyXG4gICAgICB0aGlzLnBsYXlTdGFydEFjdGlvbi5kaXNhYmxlZCA9ICghKHRoaXMuZGlzcGxheVJlY0ZpbGUpKTtcclxuXHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBzdGFydERpc2FibGVkKCkge1xyXG4gICAgcmV0dXJuICF0aGlzLnRyYW5zcG9ydEFjdGlvbnMgfHwgdGhpcy5yZWFkb25seSB8fCB0aGlzLnRyYW5zcG9ydEFjdGlvbnMuc3RhcnRBY3Rpb24uZGlzYWJsZWRcclxuICB9XHJcblxyXG4gIHN0b3BEaXNhYmxlZCgpIHtcclxuICAgIHJldHVybiAhdGhpcy50cmFuc3BvcnRBY3Rpb25zIHx8IHRoaXMudHJhbnNwb3J0QWN0aW9ucy5zdG9wQWN0aW9uLmRpc2FibGVkXHJcbiAgfVxyXG5cclxuICBzdGFydFN0b3BOZXh0TmFtZSgpOnN0cmluZ3tcclxuICAgIGlmKCF0aGlzLnN0YXJ0RGlzYWJsZWQoKSl7XHJcbiAgICAgIHRoaXMuc3RhcnRTdG9wTmV4dEJ1dHRvbk5hbWU9XCJTdGFydFwiXHJcbiAgICB9ZWxzZSBpZighdGhpcy5zdG9wRGlzYWJsZWQoKSkge1xyXG4gICAgICB0aGlzLnN0YXJ0U3RvcE5leHRCdXR0b25OYW1lID0gXCJTdG9wXCJcclxuICAgIH1cclxuICAgIHJldHVybiB0aGlzLnN0YXJ0U3RvcE5leHRCdXR0b25OYW1lO1xyXG4gIH1cclxuICBzdGFydFN0b3BOZXh0SWNvbk5hbWUoKTpzdHJpbmd7XHJcbiAgICBpZighdGhpcy5zdGFydERpc2FibGVkKCkpe1xyXG4gICAgICB0aGlzLnN0YXJ0U3RvcE5leHRCdXR0b25JY29uTmFtZT1cImZpYmVyX21hbnVhbF9yZWNvcmRcIlxyXG4gICAgfWVsc2UgaWYoIXRoaXMuc3RvcERpc2FibGVkKCkpe1xyXG4gICAgICB0aGlzLnN0YXJ0U3RvcE5leHRCdXR0b25JY29uTmFtZT1cInN0b3BcIlxyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRoaXMuc3RhcnRTdG9wTmV4dEJ1dHRvbkljb25OYW1lXHJcbiAgfVxyXG4gIHN0YXJ0U3RvcE5leHRJY29uQ29sb3IoKTpzdHJpbmd7XHJcbiAgICBpZighdGhpcy5zdGFydERpc2FibGVkKCkpe1xyXG4gICAgICByZXR1cm4gXCJyZWRcIlxyXG4gICAgfWVsc2UgaWYoIXRoaXMuc3RvcERpc2FibGVkKCkpe1xyXG4gICAgICByZXR1cm4gXCJ5ZWxsb3dcIlxyXG4gICAgfWVsc2V7XHJcbiAgICAgIHJldHVybiBcImdyZXlcIjtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHN0YXJ0U3RvcFBlcmZvcm0oKXtcclxuICAgIGlmKCF0aGlzLnN0YXJ0RGlzYWJsZWQoKSl7XHJcbiAgICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucy5zdGFydEFjdGlvbi5wZXJmb3JtKCk7XHJcbiAgICB9ZWxzZSBpZighdGhpcy5zdG9wRGlzYWJsZWQoKSl7XHJcbiAgICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucy5zdG9wQWN0aW9uLnBlcmZvcm0oKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHN0YXJ0SXRlbSgpIHtcclxuICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucy5zdGFydEFjdGlvbi5kaXNhYmxlZCA9IHRydWU7XHJcbiAgICB0aGlzLnRyYW5zcG9ydEFjdGlvbnMucGF1c2VBY3Rpb24uZGlzYWJsZWQgPSB0cnVlO1xyXG4gICAgaWYgKHRoaXMucmVhZG9ubHkpIHtcclxuICAgICAgcmV0dXJuXHJcbiAgICB9XHJcbiAgICB0aGlzLnRyYW5zcG9ydEFjdGlvbnMuZndkQWN0aW9uLmRpc2FibGVkID0gdHJ1ZVxyXG4gICAgdGhpcy50cmFuc3BvcnRBY3Rpb25zLmZ3ZE5leHRBY3Rpb24uZGlzYWJsZWQgPSB0cnVlXHJcbiAgICB0aGlzLnRyYW5zcG9ydEFjdGlvbnMuYndkQWN0aW9uLmRpc2FibGVkID0gdHJ1ZVxyXG4gICAgdGhpcy5kaXNwbGF5UmVjRmlsZSA9IG51bGw7XHJcbiAgICB0aGlzLmRpc3BsYXlSZWNGaWxlVmVyc2lvbiA9IDA7XHJcbiAgICB0aGlzLmRpc3BsYXlBdWRpb0NsaXAgPSBudWxsO1xyXG4gICAgdGhpcy5zaG93UmVjb3JkaW5nKCk7XHJcblxyXG4gICAgaWYgKHRoaXMuYWMpIHtcclxuICAgICAgaWYgKCF0aGlzLmFjLm9wZW5lZCkge1xyXG4gICAgICAgIGlmICh0aGlzLl9zZWxlY3RlZERldmljZUlkKSB7XHJcbiAgICAgICAgICBjb25zb2xlLmxvZyhcIk9wZW4gc2Vzc2lvbiB3aXRoIGF1ZGlvIGRldmljZSBJZDogXFwnXCIgKyB0aGlzLl9zZWxlY3RlZERldmljZUlkICsgXCJcXCcgZm9yIFwiICsgdGhpcy5fY2hhbm5lbENvdW50ICsgXCIgY2hhbm5lbHNcIik7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGNvbnNvbGUubG9nKFwiT3BlbiBzZXNzaW9uIHdpdGggZGVmYXVsdCBhdWRpbyBkZXZpY2UgZm9yIFwiICsgdGhpcy5fY2hhbm5lbENvdW50ICsgXCIgY2hhbm5lbHNcIik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuYWMub3Blbih0aGlzLl9jaGFubmVsQ291bnQsIHRoaXMuX3NlbGVjdGVkRGV2aWNlSWQsdGhpcy5fYXV0b0dhaW5Db250cm9sQ29uZmlncyk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhpcy5hYy5zdGFydCgpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuXHJcbiAgZG93bmxvYWRSZWNvcmRpbmcoKSB7XHJcbiAgICBpZiAodGhpcy5kaXNwbGF5UmVjRmlsZSkge1xyXG4gICAgICBsZXQgYWI6IEF1ZGlvQnVmZmVyIHwgbnVsbCA9IHRoaXMuZGlzcGxheVJlY0ZpbGUuYXVkaW9CdWZmZXI7XHJcbiAgICAgIGxldCB3dyA9IG5ldyBXYXZXcml0ZXIoKTtcclxuICAgICAgaWYgKGFiKSB7XHJcbiAgICAgICAgbGV0IHdhdkZpbGUgPSB3dy53cml0ZUFzeW5jKGFiLCAod2F2RmlsZSkgPT4ge1xyXG4gICAgICAgICAgbGV0IGJsb2IgPSBuZXcgQmxvYihbd2F2RmlsZV0sIHt0eXBlOiAnYXVkaW8vd2F2J30pO1xyXG4gICAgICAgICAgbGV0IHJmVXJsID0gVVJMLmNyZWF0ZU9iamVjdFVSTChibG9iKTtcclxuXHJcbiAgICAgICAgICBsZXQgZGF0YURubExuayA9IHRoaXMucmVuZGVyZXIuY3JlYXRlRWxlbWVudCgnYScpO1xyXG4gICAgICAgICAgLy9kYXRhRG5sTG5rLm5hbWUgPSAnUmVjb3JkaW5nJztcclxuICAgICAgICAgIGRhdGFEbmxMbmsuaHJlZiA9IHJmVXJsO1xyXG5cclxuICAgICAgICAgIHRoaXMucmVuZGVyZXIuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuYm9keSwgZGF0YURubExuayk7XHJcblxyXG4gICAgICAgICAgLy8gZG93bmxvYWQgcHJvcGVydHkgbm90IHlldCBpbiBUUyBkZWZcclxuICAgICAgICAgIGlmICh0aGlzLmRpc3BsYXlSZWNGaWxlKSB7XHJcbiAgICAgICAgICAgIGxldCBmbiA9IHRoaXMuZGlzcGxheVJlY0ZpbGUuZmlsZW5hbWVTdHJpbmcoKTtcclxuICAgICAgICAgICAgZm4gKz0gJ18nICsgdGhpcy5kaXNwbGF5UmVjRmlsZVZlcnNpb247XHJcbiAgICAgICAgICAgIGZuICs9ICcud2F2JztcclxuICAgICAgICAgICAgZGF0YURubExuay5kb3dubG9hZCA9IGZuO1xyXG4gICAgICAgICAgICBkYXRhRG5sTG5rLmNsaWNrKCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICB0aGlzLnJlbmRlcmVyLnJlbW92ZUNoaWxkKGRvY3VtZW50LmJvZHksIGRhdGFEbmxMbmspO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBzZXQgZGlzcGxheVJlY0ZpbGUoZGlzcGxheVJlY0ZpbGU6IFJlY29yZGluZ0ZpbGUgfCBudWxsKSB7XHJcbiAgICB0aGlzLl9kaXNwbGF5UmVjRmlsZSA9IGRpc3BsYXlSZWNGaWxlO1xyXG4gICAgaWYgKHRoaXMuX2Rpc3BsYXlSZWNGaWxlKSB7XHJcbiAgICAgIGxldCBhYjogQXVkaW9CdWZmZXJ8IG51bGwgPSB0aGlzLl9kaXNwbGF5UmVjRmlsZS5hdWRpb0J1ZmZlcjtcclxuICAgICAgaWYoYWIpIHtcclxuICAgICAgICB0aGlzLmRpc3BsYXlBdWRpb0NsaXAgPSBuZXcgQXVkaW9DbGlwKGFiKTtcclxuICAgICAgICB0aGlzLmNvbnRyb2xBdWRpb1BsYXllci5hdWRpb0NsaXAgPSB0aGlzLmRpc3BsYXlBdWRpb0NsaXA7XHJcbiAgICAgIH1lbHNlIHtcclxuICAgICAgICAvLyBjbGVhciBmb3Igbm93IC4uLlxyXG4gICAgICAgIHRoaXMuZGlzcGxheUF1ZGlvQ2xpcCA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5jb250cm9sQXVkaW9QbGF5ZXIuYXVkaW9DbGlwID0gbnVsbDtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMuX2NvbnRyb2xBdWRpb1BsYXllciAmJiB0aGlzLl9zZXNzaW9uKSB7XHJcbiAgICAgICAgICAgIC8vLi4uIGFuZCB0cnkgdG8gZmV0Y2ggZnJvbSBzZXJ2ZXJcclxuICAgICAgICAgICAgdGhpcy5hdWRpb0ZldGNoU3Vic2NyaXB0aW9uID0gdGhpcy5yZWNGaWxlU2VydmljZS5mZXRjaEFuZEFwcGx5UmVjb3JkaW5nRmlsZSh0aGlzLl9jb250cm9sQXVkaW9QbGF5ZXIuY29udGV4dCwgdGhpcy5fc2Vzc2lvbi5wcm9qZWN0LCB0aGlzLl9kaXNwbGF5UmVjRmlsZSkuc3Vic2NyaWJlKChyZikgPT4ge1xyXG4gICAgICAgICAgICAgIGxldCBmYWIgPSBudWxsO1xyXG4gICAgICAgICAgICAgIGlmIChyZiAmJiB0aGlzLl9kaXNwbGF5UmVjRmlsZSkge1xyXG4gICAgICAgICAgICAgICAgZmFiID0gdGhpcy5fZGlzcGxheVJlY0ZpbGUuYXVkaW9CdWZmZXI7XHJcbiAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIHRoaXMuc3RhdHVzTXNnID0gJ1JlY29yZGluZyBmaWxlIGNvdWxkIG5vdCBiZSBsb2FkZWQuJ1xyXG4gICAgICAgICAgICAgICAgdGhpcy5zdGF0dXNBbGVydFR5cGUgPSAnZXJyb3InXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIGlmIChmYWIpe1xyXG4gICAgICAgICAgICAgICAgdGhpcy5kaXNwbGF5QXVkaW9DbGlwID0gbmV3IEF1ZGlvQ2xpcChmYWIpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB0aGlzLmNvbnRyb2xBdWRpb1BsYXllci5hdWRpb0NsaXAgPXRoaXMuZGlzcGxheUF1ZGlvQ2xpcFxyXG4gICAgICAgICAgICAgIHRoaXMuc2hvd1JlY29yZGluZygpO1xyXG5cclxuICAgICAgICAgICAgfSwgZXJyID0+IHtcclxuICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiQ291bGQgbm90IGxvYWQgcmVjb3JkaW5nIGZpbGUgZnJvbSBzZXJ2ZXI6IFwiICsgZXJyKVxyXG4gICAgICAgICAgICAgIHRoaXMuc3RhdHVzTXNnID0gJ1JlY29yZGluZyBmaWxlIGNvdWxkIG5vdCBiZSBsb2FkZWQ6ICcgKyBlcnJcclxuICAgICAgICAgICAgICB0aGlzLnN0YXR1c0FsZXJ0VHlwZSA9ICdlcnJvcidcclxuICAgICAgICAgICAgfSlcclxuICAgICAgICB9ZWxzZXtcclxuICAgICAgICAgIHRoaXMuc3RhdHVzTXNnID0gJ1JlY29yZGluZyBmaWxlIGNvdWxkIG5vdCBiZSBkZWNvZGVkLiBBdWRpbyBjb250ZXh0IHVuYXZhaWxhYmxlLidcclxuICAgICAgICAgIHRoaXMuc3RhdHVzQWxlcnRUeXBlID0gJ2Vycm9yJ1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMuZGlzcGxheUF1ZGlvQ2xpcCA9IG51bGw7XHJcbiAgICAgIHRoaXMuY29udHJvbEF1ZGlvUGxheWVyLmF1ZGlvQ2xpcCA9IG51bGw7XHJcbiAgICB9XHJcbiAgICB0aGlzLnNob3dSZWNvcmRpbmcoKTtcclxuICB9XHJcblxyXG4gIGdldCBkaXNwbGF5UmVjRmlsZSgpOiBSZWNvcmRpbmdGaWxlIHwgbnVsbCB7XHJcbiAgICByZXR1cm4gdGhpcy5fZGlzcGxheVJlY0ZpbGU7XHJcbiAgfVxyXG5cclxuICBzaG93UmVjb3JkaW5nKCkge1xyXG4gICAgdGhpcy5jb250cm9sQXVkaW9QbGF5ZXIuc3RvcCgpO1xyXG5cclxuICAgIGlmICh0aGlzLmRpc3BsYXlBdWRpb0NsaXApIHtcclxuXHJcbiAgICAgIHRoaXMubGV2ZWxNZWFzdXJlLmNhbGNCdWZmZXJMZXZlbEluZm9zKHRoaXMuZGlzcGxheUF1ZGlvQ2xpcC5idWZmZXIsIExFVkVMX0JBUl9JTlRFUlZBTExfU0VDT05EUykudGhlbigobGV2ZWxJbmZvcykgPT4ge1xyXG4gICAgICAgIHRoaXMuZGlzcGxheUxldmVsSW5mb3MgPSBsZXZlbEluZm9zO1xyXG4gICAgICAgIHRoaXMuY2hhbmdlRGV0ZWN0b3JSZWYuZGV0ZWN0Q2hhbmdlcygpO1xyXG4gICAgICB9KTtcclxuICAgICAgdGhpcy5wbGF5U3RhcnRBY3Rpb24uZGlzYWJsZWQgPSBmYWxzZTtcclxuXHJcbiAgICB9IGVsc2Uge1xyXG5cclxuICAgICAgLy8gVE9ET1xyXG4gICAgICAvLyBTZXR0aW5nIHRvIG51bGwgZG9lcyBub3QgdHJpZ2dlciBhIGNoYW5nZSBpZiBpdCB3YXMgIG51bGwgYmVmb3JlIChoYXBwZW5zIGFmdGVyIG5leHRpdGVtKCkgaW4gQVVUT1BST0dSRVNTIG1vZGUpXHJcbiAgICAgIC8vIFRoZSBsZXZlbCBiYXIgZGlzcGxheSBkb2VzIG5vdCBjbGVhciwgaXQgc2hvd3MgdGhlIGxhc3QgY2FwdHVyZWQgc3RyZWFtXHJcbiAgICAgIHRoaXMuZGlzcGxheUxldmVsSW5mb3MgPSBudWxsO1xyXG5cclxuICAgICAgdGhpcy5wbGF5U3RhcnRBY3Rpb24uZGlzYWJsZWQgPSB0cnVlO1xyXG5cclxuICAgICAgLy8gQ29sbGFwc2UgYXVkaW8gc2lnbmFsIGRpc3BsYXkgaWYgb3BlblxyXG4gICAgICBpZiAoIXRoaXMuYXVkaW9TaWduYWxDb2xsYXBzZWQpIHtcclxuICAgICAgICB0aGlzLmF1ZGlvU2lnbmFsQ29sbGFwc2VkID0gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgdGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5kZXRlY3RDaGFuZ2VzKCk7XHJcbiAgfVxyXG5cclxuICB1cGRhdGVTdGFydEFjdGlvbkRpc2FibGVTdGF0ZSgpe1xyXG4gICAgdGhpcy50cmFuc3BvcnRBY3Rpb25zLnN0YXJ0QWN0aW9uLmRpc2FibGVkPSEodGhpcy5hYyk7XHJcbiAgfVxyXG5cclxuXHJcblxyXG4gIHN0YXJ0KCkge1xyXG4gICAgdGhpcy5zdGF0dXNBbGVydFR5cGUgPSAnaW5mbyc7XHJcbiAgICB0aGlzLnN0YXR1c01zZyA9ICdTdGFydGluZyBzZXNzaW9uLi4uJztcclxuICAgIHRoaXMuc3RhdHVzV2FpdGluZz1mYWxzZTtcclxuICAgIGlmKHRoaXMuX3Nlc3Npb24pIHtcclxuICAgICAgaWYgKHRoaXMuX3Nlc3Npb24uc2VhbGVkKSB7XHJcbiAgICAgICAgdGhpcy5yZWFkb25seSA9IHRydWVcclxuICAgICAgICB0aGlzLnN0YXR1c01zZyA9ICdTZXNzaW9uIHNlYWxlZCEnO1xyXG4gICAgICAgIC8vbGV0IGRpYWxvZ1JlZiA9IHRoaXMuZGlhbG9nLm9wZW4oU2Vzc2lvblNlYWxlZERpYWxvZywge30pO1xyXG4gICAgICAgIHRoaXMuZGlhbG9nLm9wZW4oTWVzc2FnZURpYWxvZywge1xyXG4gICAgICAgICAgZGF0YToge1xyXG4gICAgICAgICAgICB0eXBlOiAnZXJyb3InLFxyXG4gICAgICAgICAgICB0aXRsZTogJ0Vycm9yJyxcclxuICAgICAgICAgICAgbXNnOiBcIlRoaXMgc2Vzc2lvbiBpcyBzZWFsZWQuIFJlY29yZGluZ3MgY2Fubm90IGJlIGFkZGVkIGFueW1vcmUuXCIsXHJcbiAgICAgICAgICAgIGFkdmlzZTogJ1BsZWFzZSBhc2sgeW91ciBleHBlcmltZW50ZXIgd2hhdCB0byBkbyAoZS5nIHN0YXJ0IGEgbmV3IHNlc3Npb24pLicsXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbGV0IGJvZHk6IGFueSA9IHt9O1xyXG4gICAgICAgIGlmICh0aGlzLl9zZXNzaW9uLnN0YXR1cyA9PT0gXCJDUkVBVEVEXCIpIHtcclxuICAgICAgICAgIHRoaXMuX3Nlc3Npb24uc3RhdHVzID0gXCJMT0FERURcIjtcclxuICAgICAgICAgIGJvZHkuc3RhdHVzID0gdGhpcy5fc2Vzc2lvbi5zdGF0dXM7XHJcbiAgICAgICAgICBpZiAoIXRoaXMuX3Nlc3Npb24ubG9hZGVkRGF0ZSkge1xyXG4gICAgICAgICAgICB0aGlzLl9zZXNzaW9uLmxvYWRlZERhdGUgPSBuZXcgRGF0ZSgpO1xyXG4gICAgICAgICAgICBib2R5LmxvYWRlZERhdGUgPSB0aGlzLl9zZXNzaW9uLmxvYWRlZERhdGU7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHRoaXMuX3Nlc3Npb24ucmVzdGFydGVkRGF0ZSA9IG5ldyBEYXRlKCk7XHJcbiAgICAgICAgICBib2R5LnJlc3RhcnRlZERhdGUgPSB0aGlzLl9zZXNzaW9uLnJlc3RhcnRlZERhdGU7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuc2Vzc2lvblNlcnZpY2UucGF0Y2hTZXNzaW9uT2JzZXJ2ZXIodGhpcy5fc2Vzc2lvbiwgYm9keSkuc3Vic2NyaWJlKClcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgLy9jb25zb2xlLmxvZyhcIlNlc3Npb24gSUQ6IFwiK3RoaXMuX3Nlc3Npb24uc2Vzc2lvbisgXCIgc3RhdHVzOiBcIit0aGlzLl9zZXNzaW9uLnN0YXR1cylcclxuICAgIHRoaXMuX3NlbGVjdGVkRGV2aWNlSWQ9dW5kZWZpbmVkO1xyXG5cclxuICAgIGlmICghdGhpcy5yZWFkb25seSAmJiB0aGlzLmFjKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzTXNnID0gJ1JlcXVlc3RpbmcgYXVkaW8gcGVybWlzc2lvbnMuLi4nO1xyXG4gICAgICB0aGlzLnN0YXR1c0FsZXJ0VHlwZSA9ICdpbmZvJztcclxuXHJcbiAgICAgIHRoaXMuYWMuZGV2aWNlSW5mb3MoKG1kaXMpID0+IHtcclxuICAgICAgICBsZXQgYXVkaW9DYXB0dXJlRGV2aWNlQXZhaWw6IGJvb2xlYW4gPSBmYWxzZTtcclxuICAgICAgICBsZXQgYXVkaW9QbGF5RGV2aWNlQXZhaWw6IGJvb2xlYW4gPSBmYWxzZTtcclxuICAgICAgICBpZiAobWRpcyAmJiB0aGlzLmFjKSB7XHJcbiAgICAgICAgICB0aGlzLmFjLnByaW50RGV2aWNlcyhtZGlzKVxyXG4gICAgICAgICAgaWYgKG1kaXMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICBmb3IgKGxldCBtZGlpID0gMDsgbWRpaSA8IG1kaXMubGVuZ3RoOyBtZGlpKyspIHtcclxuICAgICAgICAgICAgICBsZXQgbWRpID0gbWRpc1ttZGlpXTtcclxuICAgICAgICAgICAgICBsZXQga2luZD1tZGkua2luZDtcclxuICAgICAgICAgICAgICBpZihraW5kID09PSBcImF1ZGlvaW5wdXRcIil7XHJcbiAgICAgICAgICAgICAgICBhdWRpb0NhcHR1cmVEZXZpY2VBdmFpbD10cnVlO1xyXG4gICAgICAgICAgICAgIH1lbHNlIGlmKGtpbmQ9PT0gXCJhdWRpb291dHB1dFwiKXtcclxuICAgICAgICAgICAgICAgIGF1ZGlvUGxheURldmljZUF2YWlsPXRydWU7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgaWYgKHRoaXMuX3Nlc3Npb24gJiYgdGhpcy5fc2Vzc2lvbi50eXBlICE9PSAnVEVTVF9ERUZfQScgJiYgdGhpcy5fYXVkaW9EZXZpY2VzICYmIHRoaXMuX2F1ZGlvRGV2aWNlcy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICAgIGxldCBmZGk6IE1lZGlhRGV2aWNlSW5mbyB8IG51bGwgPSBudWxsO1xyXG4gICAgICAgICAgICBmb3IgKGxldCBhZEkgPSAwOyBhZEkgPCB0aGlzLl9hdWRpb0RldmljZXMubGVuZ3RoOyBhZEkrKykge1xyXG4gICAgICAgICAgICAgIGxldCBhZCA9IHRoaXMuX2F1ZGlvRGV2aWNlc1thZEldO1xyXG4gICAgICAgICAgICAgIGlmIChhZC5wbGF5YmFjaykge1xyXG4gICAgICAgICAgICAgICAgLy8gcHJvamVjdCBhdWRpbyBkZXZpY2UgY29uZmlnIGZvciBwbGF5YmFjayBkZXZpY2VcclxuICAgICAgICAgICAgICAgIC8vIG5vdCB1c2VkIGZvciBub3dcclxuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICBmb3IgKGxldCBtZGlpID0gMDsgbWRpaSA8IG1kaXMubGVuZ3RoOyBtZGlpKyspIHtcclxuICAgICAgICAgICAgICAgIGxldCBtZGkgPSBtZGlzW21kaWldO1xyXG4gICAgICAgICAgICAgICAgbGV0IGtpbmQ9bWRpLmtpbmQ7XHJcbiAgICAgICAgICAgICAgICBpZihraW5kID09PSBcImF1ZGlvaW5wdXRcIil7XHJcbiAgICAgICAgICAgICAgICAgIGF1ZGlvQ2FwdHVyZURldmljZUF2YWlsPXRydWU7XHJcbiAgICAgICAgICAgICAgICB9ZWxzZSBpZihraW5kPT09IFwiYXVkaW9vdXRwdXRcIil7XHJcbiAgICAgICAgICAgICAgICAgIGF1ZGlvUGxheURldmljZUF2YWlsPXRydWU7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBpZiAoYWQucmVnZXgpIHtcclxuICAgICAgICAgICAgICAgICAgLy9jb25zb2xlLmxvZyhcIk1hdGNoPzogXFwnXCIrbWRpLmxhYmVsK1wiXFwnIFxcJ1wiK2FkLm5hbWUrXCJcXCdcIik7XHJcbiAgICAgICAgICAgICAgICAgIGlmIChtZGkubGFiZWwubWF0Y2goYWQubmFtZSkpIHtcclxuICAgICAgICAgICAgICAgICAgICBmZGkgPSBtZGk7XHJcbiAgICAgICAgICAgICAgICAgICAgLy9jb25zb2xlLmxvZyhcIk1hdGNoIVwiKTtcclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgaWYgKG1kaS5sYWJlbC50cmltKCkgPT09IGFkLm5hbWUudHJpbSgpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgZmRpID0gbWRpO1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBpZiAoZmRpKSB7XHJcbiAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICBpZiAoZmRpKSB7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGlmIChmZGkpIHtcclxuICAgICAgICAgICAgICAvLyBtYXRjaGluZyBkZXZpY2UgZm91bmRcclxuXHJcbiAgICAgICAgICAgICAgLy8gTm90IGFibGUgdG8gb3BlbiBkZXZpY2UgaGVyZSBzaW5jZSBDaHJvbWUgNzFcclxuICAgICAgICAgICAgICAvLyBDaHJvbWUgNzEgcmVxdWlyZXMgYSB1c2VyIGdlc3R1cmUgYmVmb3JlIHRoZSBBdWRpb0NvbnRleHQgY2FuIGJlIHJlc3VtZWRcclxuICAgICAgICAgICAgICAvLyBzZXNzaW9ubWFuYWdlci50czo3MTIgT3BlbiBzZXNzaW9uIHdpdGggZGVmYXVsdCBhdWRpbyBkZXZpY2UgZm9yIDEgY2hhbm5lbHNcclxuICAgICAgICAgICAgICAvLyBjYXB0dXJlLnRzOjEyOCBUaGUgQXVkaW9Db250ZXh0IHdhcyBub3QgYWxsb3dlZCB0byBzdGFydC4gSXQgbXVzdCBiZSByZXN1bWVkIChvciBjcmVhdGVkKSBhZnRlciBhIHVzZXIgZ2VzdHVyZSBvbiB0aGUgcGFnZS4gaHR0cHM6Ly9nb28uZ2wvN0s3V0x1XHJcbiAgICAgICAgICAgICAgLy8gcHVzaC4uL3Byb2plY3RzL3NwZWVjaHJlY29yZGVybmcvc3JjL2xpYi9hdWRpby9jYXB0dXJlL2NhcHR1cmUudHMuQXVkaW9DYXB0dXJlLm9wZW4gQCBjYXB0dXJlLnRzOjEyOFxyXG5cclxuICAgICAgICAgICAgICAvL3RoaXMuYWMub3Blbih0aGlzLl9jaGFubmVsQ291bnQsIGZkaS5kZXZpY2VJZCk7XHJcbiAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiU2V0IHNlbGVjdGVkIGF1ZGlvIGRldmljZTogXFwnXCIgKyBmZGkubGFiZWwgKyBcIlxcJyBJZDogXFwnXCIgKyBmZGkuZGV2aWNlSWQgKyBcIlxcJ1wiKTtcclxuICAgICAgICAgICAgICB0aGlzLl9zZWxlY3RlZERldmljZUlkID0gZmRpLmRldmljZUlkO1xyXG5cclxuICAgICAgICAgICAgICB0aGlzLmVuYWJsZVN0YXJ0VXNlckdlc3R1cmUoKVxyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIC8vIGRldmljZSBub3QgZm91bmRcclxuICAgICAgICAgICAgICB0aGlzLnN0YXR1c01zZyA9ICdFUlJPUjogUmVxdWlyZWQgYXVkaW8gZGV2aWNlIG5vdCBhdmFpbGFibGUhJztcclxuICAgICAgICAgICAgICB0aGlzLnN0YXR1c0FsZXJ0VHlwZSA9ICdlcnJvcic7XHJcbiAgICAgICAgICAgICAgdGhpcy5yZWFkb25seSA9IHRydWU7XHJcblxyXG4gICAgICAgICAgICAgIHRoaXMuZGlhbG9nLm9wZW4oTWVzc2FnZURpYWxvZywge1xyXG4gICAgICAgICAgICAgICAgZGF0YToge1xyXG4gICAgICAgICAgICAgICAgICB0eXBlOiAnZXJyb3InLFxyXG4gICAgICAgICAgICAgICAgICB0aXRsZTogJ1JlcXVpcmVkIGF1ZGlvIGRldmljZScsXHJcbiAgICAgICAgICAgICAgICAgIG1zZzogXCJSZXF1aXJlZCBhdWRpbyBkZXZpY2Ugbm90IGZvdW5kXCIsXHJcbiAgICAgICAgICAgICAgICAgIGFkdmljZTogXCJQbGVhc2UgY29ubmVjdCBhIHN1aXRhYmxlIGF1ZGlvIGRldmljZSBmb3IgdGhpcyBwcm9qZWN0IGFuZCByZXRyeSAocHJlc3MgdGhlIGJyb3dzZXIgcmVsb2FkIGJ1dHRvbikuXCJcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9ZWxzZXtcclxuICAgICAgICAgICAgaWYoIWF1ZGlvQ2FwdHVyZURldmljZUF2YWlsICYmICFhdWRpb1BsYXlEZXZpY2VBdmFpbCl7XHJcbiAgICAgICAgICAgICAgLy8gbm8gZGV2aWNlIGZvdW5kXHJcbiAgICAgICAgICAgICAgdGhpcy5zdGF0dXNNc2cgPSAnRVJST1I6IE5vIGF1ZGlvIGRldmljZSBhdmFpbGFibGUhJztcclxuICAgICAgICAgICAgICB0aGlzLnN0YXR1c0FsZXJ0VHlwZSA9ICd3YXJuJztcclxuICAgICAgICAgICAgICAvL3RoaXMucmVhZG9ubHkgPSB0cnVlO1xyXG5cclxuICAgICAgICAgICAgICB0aGlzLmRpYWxvZy5vcGVuKE1lc3NhZ2VEaWFsb2csIHtcclxuICAgICAgICAgICAgICAgIGRhdGE6IHtcclxuICAgICAgICAgICAgICAgICAgdHlwZTogJ3dhcm4nLFxyXG4gICAgICAgICAgICAgICAgICB0aXRsZTogJ05vIGF1ZGlvIGRldmljZScsXHJcbiAgICAgICAgICAgICAgICAgIG1zZzogXCJObyBhdWRpbyBkZXZpY2UgZm91bmRcIixcclxuICAgICAgICAgICAgICAgICAgYWR2aWNlOiBcIlBsZWFzZSBjb25uZWN0IGFuIGF1ZGlvIGRldmljZSBhbmQgcmV0cnkgKHByZXNzIHRoZSBicm93c2VyIHJlbG9hZCBidXR0b24pIG9yIHRyeSB0byBjb250aW51ZSBhbnl3YXkuXCJcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICB9ZWxzZSB7XHJcbiAgICAgICAgICAgICAgaWYgKCF0aGlzLnJlYWRvbmx5ICYmICFhdWRpb0NhcHR1cmVEZXZpY2VBdmFpbCkge1xyXG4gICAgICAgICAgICAgICAgLy8gbm8gZGV2aWNlIGZvdW5kXHJcbiAgICAgICAgICAgICAgICB0aGlzLnN0YXR1c01zZyA9ICdXQVJOSU5HOiBObyBhdWRpbyBjYXB0dXJlIGRldmljZSBhdmFpbGFibGUhJztcclxuICAgICAgICAgICAgICAgIHRoaXMuc3RhdHVzQWxlcnRUeXBlID0gJ3dhcm5pbmcnO1xyXG4gICAgICAgICAgICAgICAgLy90aGlzLnJlYWRvbmx5ID0gdHJ1ZTtcclxuXHJcbiAgICAgICAgICAgICAgICB0aGlzLmRpYWxvZy5vcGVuKE1lc3NhZ2VEaWFsb2csIHtcclxuICAgICAgICAgICAgICAgICAgZGF0YToge1xyXG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICd3YXJuaW5nJyxcclxuICAgICAgICAgICAgICAgICAgICB0aXRsZTogJ05vIGF1ZGlvIGNhcHR1cmUgZGV2aWNlJyxcclxuICAgICAgICAgICAgICAgICAgICBtc2c6IFwiTm8gYXVkaW8gY2FwdHVyZSBkZXZpY2UgZm91bmRcIixcclxuICAgICAgICAgICAgICAgICAgICBhZHZpY2U6IFwiUGxlYXNlIGNvbm5lY3QgYW4gYXVkaW8gY2FwdHVyZSBkZXZpY2UgYW5kIHJldHJ5IChwcmVzcyB0aGUgYnJvd3NlciByZWxvYWQgYnV0dG9uKSBvciB0cnkgdG8gY29udGludWUgYW55d2F5LlwiXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIGlmICghYXVkaW9QbGF5RGV2aWNlQXZhaWwpIHtcclxuICAgICAgICAgICAgICAgICAgLy8gRmlyZWZveCBkb2VzIG5vdCBlbnVtZXJhdGUgYXVkaW9vdXRwdXQgZGV2aWNlc1xyXG4gICAgICAgICAgICAgICAgICAvLyBEbyBub3Qgc2hvdyB0aGlzIHdhcm5pbmcsIGJlY2F1c2UgaXQgd291bGQgYWx3YXlzIGFwcGVhciBvbiBGaXJlZm94XHJcbiAgICAgICAgICAgICAgICAgIC8vIFdoZW4gaHR0cHM6Ly9idWd6aWxsYS5tb3ppbGxhLm9yZy9zaG93X2J1Zy5jZ2k/aWQ9MTQ5ODUxMiBpcyBmaXhlZCB0aGUgd2FybmluZyBjYW4gYmUgZW5hYmxlZCBmb3IgRmlyZWZveCBhcyB3ZWxsXHJcblxyXG4gICAgICAgICAgICAgICAgICAvLyBJdCBpcyBhbHJlYWR5IGltcGxlbW5ldGVkIGJ1dCBrZXB0IGJlaGluZCBhIHByZWZlcmVuY2Ugc2V0dGluZyBodHRwczovL2J1Z3ppbGxhLm1vemlsbGEub3JnL3Nob3dfYnVnLmNnaT9pZD0xMTUyNDAxXHJcblxyXG5cclxuICAgICAgICAgICAgICAgICAgLy8gT3V0cHV0IGRldmljZXMgYXJlIGxpc3RlZCBpZiBhYm91dDpjb25maWcgbWVkaWEuc2V0c2lua2lkLmVuYWJsZWQ9dHJ1ZVxyXG4gICAgICAgICAgICAgICAgICAvLyBidXQgZGVmYXVsdCBzZXR0aW5nIGlzIGZhbHNlXHJcbiAgICAgICAgICAgICAgICAgIGlmICghbmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaChcIi4qRmlyZWZveC4qXCIpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAvLyBubyBkZXZpY2UgZm91bmRcclxuICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc3RhdHVzTXNnID0gJ1dBUk5JTkc6IE5vIGF1ZGlvIHBsYXliYWNrIGRldmljZSBhdmFpbGFibGUhJztcclxuICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc3RhdHVzQWxlcnRUeXBlID0gJ3dhcm4nO1xyXG4gICAgICAgICAgICAgICAgICAgICAgLy90aGlzLnJlYWRvbmx5ID0gdHJ1ZTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRpYWxvZy5vcGVuKE1lc3NhZ2VEaWFsb2csIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhOiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICd3YXJuJyxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU6ICdObyBhdWRpbyBwbGF5YmFjayBkZXZpY2UnLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtc2c6IFwiTm8gYXVkaW8gcGxheWJhY2sgZGV2aWNlIGZvdW5kXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkdmljZTogXCJQbGVhc2UgY29ubmVjdCBhbiBhdWRpbyBwbGF5YmFjayBkZXZpY2UgYW5kIHJldHJ5IChwcmVzcyB0aGUgYnJvd3NlciByZWxvYWQgYnV0dG9uKSBvciB0cnkgdG8gY29udGludWUgYW55d2F5LlwiXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAvLyBOb3QgYWJsZSB0byBvcGVuIGRldmljZSBoZXJlIHNpbmNlIENocm9tZSA3MVxyXG4gICAgICAgICAgICAgIC8vIENocm9tZSA3MSByZXF1aXJlcyBhIHVzZXIgZ2VzdHVyZSBiZWZvcmUgdGhlIEF1ZGlvQ29udGV4dCBjYW4gYmUgcmVzdW1lZFxyXG4gICAgICAgICAgICAgIC8vIHNlc3Npb25tYW5hZ2VyLnRzOjcxMiBPcGVuIHNlc3Npb24gd2l0aCBkZWZhdWx0IGF1ZGlvIGRldmljZSBmb3IgMSBjaGFubmVsc1xyXG4gICAgICAgICAgICAgIC8vIGNhcHR1cmUudHM6MTI4IFRoZSBBdWRpb0NvbnRleHQgd2FzIG5vdCBhbGxvd2VkIHRvIHN0YXJ0LiBJdCBtdXN0IGJlIHJlc3VtZWQgKG9yIGNyZWF0ZWQpIGFmdGVyIGEgdXNlciBnZXN0dXJlIG9uIHRoZSBwYWdlLiBodHRwczovL2dvby5nbC83SzdXTHVcclxuICAgICAgICAgICAgICAvLyBwdXNoLi4vcHJvamVjdHMvc3BlZWNocmVjb3JkZXJuZy9zcmMvbGliL2F1ZGlvL2NhcHR1cmUvY2FwdHVyZS50cy5BdWRpb0NhcHR1cmUub3BlbiBAIGNhcHR1cmUudHM6MTI4XHJcbiAgICAgICAgICAgICAgLy9jb25zb2xlLmxvZyhcIk9wZW4gc2Vzc2lvbiB3aXRoIGRlZmF1bHQgYXVkaW8gZGV2aWNlIGZvciBcIit0aGlzLl9jaGFubmVsQ291bnQrXCIgY2hhbm5lbHNcIik7XHJcbiAgICAgICAgICAgICAgLy90aGlzLmFjLm9wZW4odGhpcy5fY2hhbm5lbENvdW50KTtcclxuXHJcbiAgICAgICAgICAgICAgLy8gZW5hYmxlIHN0YXJ0IGdlc3R1cmUgYW55d2F5XHJcbiAgICAgICAgICAgICAgdGhpcy5lbmFibGVTdGFydFVzZXJHZXN0dXJlKClcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICB9KTtcclxuICAgIH1cclxuICAgIC8vIGlmKHRoaXMucmVjb3JkZXJDb21iaVBhbmUucmVjb3JkaW5nTGlzdENvbXAucmVjb3JkaW5nTGlzdC5sZW5ndGg+MCl7XHJcbiAgICAvLyAgIHRoaXMuc2VsZWN0UmVjb3JkaW5nRmlsZSh0aGlzLnJlY29yZGVyQ29tYmlQYW5lLnJlY29yZGluZ0xpc3RDb21wLnJlY29yZGluZ0xpc3RbMF0pO1xyXG4gICAgLy8gfVxyXG4gICAgdGhpcy5yZWNvcmRlckNvbWJpUGFuZS5zZWxlY3RUb3AoKTtcclxuICAgIHRoaXMuZW5hYmxlTmF2aWdhdGlvbigpO1xyXG4gIH1cclxuXHJcbiAgaXNSZWNvcmRpbmcoKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gKHRoaXMuc3RhdHVzID09PSBTdGF0dXMuUkVDT1JESU5HKTtcclxuICB9XHJcblxyXG4gIGlzQWN0aXZlKCk6IGJvb2xlYW57XHJcbiAgICByZXR1cm4gKCEodGhpcy5zdGF0dXMgPT09IFN0YXR1cy5CTE9DS0VEIHx8IHRoaXMuc3RhdHVzPT09IFN0YXR1cy5JRExFIHx8IHRoaXMuc3RhdHVzPT09U3RhdHVzLkVSUk9SKSB8fCB0aGlzLnByb2Nlc3NpbmdSZWNvcmRpbmcgfHwgdGhpcy5zZXNzaW9uU2VydmljZS51cGxvYWRDb3VudD4wKVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSB1cGRhdGVOYXZpZ2F0aW9uQWN0aW9ucygpe1xyXG5cclxuICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucy5md2RBY3Rpb24uZGlzYWJsZWQgPSB0aGlzLm5hdmlnYXRpb25EaXNhYmxlZDtcclxuICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucy5id2RBY3Rpb24uZGlzYWJsZWQgPSB0aGlzLm5hdmlnYXRpb25EaXNhYmxlZDtcclxuICB9XHJcblxyXG5cclxuICBlbmFibGVTdGFydFVzZXJHZXN0dXJlKCkge1xyXG4gICAgdGhpcy5zdGF0dXNBbGVydFR5cGUgPSAnaW5mbyc7XHJcbiAgICB0aGlzLnN0YXR1c01zZyA9ICdSZWFkeS4nO1xyXG4gICAgLy90aGlzLnVwZGF0ZVN0YXJ0QWN0aW9uRGlzYWJsZVN0YXRlKClcclxuICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucy5zdGFydEFjdGlvbi5kaXNhYmxlZD0hKHRoaXMuYWMpO1xyXG5cclxuICB9XHJcblxyXG4gIGVuYWJsZU5hdmlnYXRpb24oKXtcclxuICAgIHRoaXMubmF2aWdhdGlvbkRpc2FibGVkPWZhbHNlO1xyXG4gICAgdGhpcy51cGRhdGVOYXZpZ2F0aW9uQWN0aW9ucygpO1xyXG4gIH1cclxuXHJcbiAgb3BlbmVkKCkge1xyXG4gICAgaWYodGhpcy5hYykge1xyXG4gICAgICB0aGlzLmFjLnN0YXJ0KCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBzdGFydGVkKCkge1xyXG4gICAgdGhpcy5zdGFydGVkRGF0ZT1uZXcgRGF0ZSgpO1xyXG4gICAgdGhpcy50cmFuc3BvcnRBY3Rpb25zLnN0YXJ0QWN0aW9uLmRpc2FibGVkID0gdHJ1ZTtcclxuXHJcbiAgICB0aGlzLnN0YXR1c0FsZXJ0VHlwZSA9ICdpbmZvJztcclxuICAgIHRoaXMuc3RhdHVzTXNnID0gJ1JlY29yZGluZy4uLic7XHJcblxyXG4gICAgbGV0IG1heFJlY29yZGluZ1RpbWVNcyA9IE1BWF9SRUNPUkRJTkdfVElNRV9NUztcclxuICAgIHRoaXMubWF4UmVjVGltZXJJZCA9IHdpbmRvdy5zZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgdGhpcy5zdG9wUmVjb3JkaW5nTWF4UmVjKClcclxuICAgIH0sIG1heFJlY29yZGluZ1RpbWVNcyk7XHJcbiAgICB0aGlzLm1heFJlY1RpbWVyUnVubmluZyA9IHRydWU7XHJcblxyXG4gICAgdGhpcy5zdGF0dXMgPSBTdGF0dXMuUkVDT1JESU5HO1xyXG4gICAgdGhpcy50cmFuc3BvcnRBY3Rpb25zLnN0b3BBY3Rpb24uZGlzYWJsZWQgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIHN0b3BJdGVtKCkge1xyXG5cclxuICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucy5zdG9wQWN0aW9uLmRpc2FibGVkID0gdHJ1ZTtcclxuICAgIHRoaXMudHJhbnNwb3J0QWN0aW9ucy5uZXh0QWN0aW9uLmRpc2FibGVkID0gdHJ1ZTtcclxuICAgIHRoaXMuc3RhdHVzID0gU3RhdHVzLlNUT1BQSU5HX1NUT1A7XHJcbiAgICB0aGlzLnN0b3BSZWNvcmRpbmcoKTtcclxuXHJcbiAgfVxyXG5cclxuICBzdG9wUmVjb3JkaW5nKCkge1xyXG4gICAgaWYgKHRoaXMubWF4UmVjVGltZXJSdW5uaW5nICYmIHRoaXMubWF4UmVjVGltZXJJZCE9bnVsbCkge1xyXG4gICAgICB3aW5kb3cuY2xlYXJUaW1lb3V0KHRoaXMubWF4UmVjVGltZXJJZCk7XHJcbiAgICAgIHRoaXMubWF4UmVjVGltZXJSdW5uaW5nID0gZmFsc2U7XHJcbiAgICB9XHJcbiAgICBpZih0aGlzLmFjKSB7XHJcbiAgICAgIHRoaXMuYWMuc3RvcCgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgc3RvcFJlY29yZGluZ01heFJlYygpe1xyXG5cclxuICAgIHRoaXMubWF4UmVjVGltZXJSdW5uaW5nID0gZmFsc2U7XHJcbiAgICB0aGlzLnN0YXR1cyA9IFN0YXR1cy5TVE9QUElOR19TVE9QO1xyXG4gICAgaWYodGhpcy5hYykge1xyXG4gICAgICB0aGlzLmFjLnN0b3AoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIGFkZFJlY29yZGluZ0ZpbGVCeURlc2NyaXB0b3IocmZkOlJlY29yZGluZ0ZpbGVEZXNjcmlwdG9ySW1wbCl7XHJcbiAgLy8gICAgbGV0IHBySWR4PTA7XHJcbiAgLy8gICAgaWYodGhpcy5pdGVtcykge1xyXG4gIC8vICAgICAgbGV0IGl0ID0gdGhpcy5pdGVtc1twcklkeF07XHJcbiAgLy8gICAgICBpZiAoaXQpIHtcclxuICAvLyAgICAgICAgaWYgKCFpdC5yZWNzKSB7XHJcbiAgLy8gICAgICAgICAgaXQucmVjcyA9IG5ldyBBcnJheTxTcHJSZWNvcmRpbmdGaWxlPigpO1xyXG4gIC8vICAgICAgICB9XHJcbiAgLy9cclxuICAvLyAgICAgIH0gZWxzZSB7XHJcbiAgLy8gICAgICAgIC8vY29uc29sZS5kZWJ1ZyhcIldBUk46IE5vIHJlY29yZGluZyBpdGVtIHdpdGggY29kZTogXFxcIlwiICtyZmQucmVjb3JkaW5nLml0ZW1jb2RlKyBcIlxcXCIgZm91bmQuXCIpO1xyXG4gIC8vICAgICAgfVxyXG4gIC8vICAgIH1cclxuICAvLyB9XHJcbiAgLy9cclxuICAvLyBhZGRSZWNvcmRpbmdGaWxlQnlQcm9tcHRJbmRleChwcm9tcHRJbmRleDpudW1iZXIsIHJmOlNwclJlY29yZGluZ0ZpbGUpe1xyXG4gIC8vXHJcbiAgLy8gfVxyXG5cclxuXHJcbiAgc3RvcHBlZCgpIHtcclxuICAgIHRoaXMudXBkYXRlU3RhcnRBY3Rpb25EaXNhYmxlU3RhdGUoKVxyXG4gICAgdGhpcy50cmFuc3BvcnRBY3Rpb25zLnN0b3BBY3Rpb24uZGlzYWJsZWQgPSB0cnVlO1xyXG4gICAgdGhpcy50cmFuc3BvcnRBY3Rpb25zLm5leHRBY3Rpb24uZGlzYWJsZWQgPSB0cnVlO1xyXG4gICAgdGhpcy50cmFuc3BvcnRBY3Rpb25zLnBhdXNlQWN0aW9uLmRpc2FibGVkID0gdHJ1ZTtcclxuICAgIHRoaXMuc3RhdHVzQWxlcnRUeXBlID0gJ2luZm8nO1xyXG4gICAgdGhpcy5zdGF0dXNNc2cgPSAnUmVjb3JkZWQuJztcclxuICAgIC8vdGhpcy5zdGFydFN0b3BTaWduYWxTdGF0ZSA9IFN0YXJ0U3RvcFNpZ25hbFN0YXRlLklETEU7XHJcbiAgICBsZXQgYWQ6QXVkaW9CdWZmZXI7XHJcbiAgICBpZih0aGlzLmFjKSB7XHJcbiAgICAgIGFkID0gdGhpcy5hYy5hdWRpb0J1ZmZlcigpO1xyXG4gICAgLy99XHJcbiAgICAvL2lmICh0aGlzLl9zZXNzaW9uICYmIHRoaXMuX3Byb21wdEluZGV4ICkge1xyXG4gICAgICBsZXQgc2Vzc0lkOiBzdHJpbmcgfCBudW1iZXIgPSAwO1xyXG4gICAgICBpZih0aGlzLl9zZXNzaW9uKXtcclxuICAgICAgICBzZXNzSWQ9dGhpcy5fc2Vzc2lvbi5zZXNzaW9uSWQ7XHJcbiAgICAgIH1cclxuICAgICAgLy8gbGV0IGNwSWR4ID0gdGhpcy5fcHJvbXB0SW5kZXg7XHJcbiAgICAgIC8vIGxldCBpdCA9IHRoaXMuaXRlbXNbY3BJZHhdO1xyXG4gICAgICAvLyBpZiAoIWl0LnJlY3MpIHtcclxuICAgICAgLy8gICBpdC5yZWNzID0gbmV3IEFycmF5PFJlY29yZGluZ0ZpbGU+KCk7XHJcbiAgICAgIC8vIH1cclxuXHJcbiAgICAgIGxldCByZiA9IG5ldyBSZWNvcmRpbmdGaWxlKFVVSUQuZ2VuZXJhdGUoKSxzZXNzSWQsYWQpO1xyXG4gICAgICByZi5fc3RhcnRlZEFzRGF0ZU9iaj10aGlzLnN0YXJ0ZWREYXRlO1xyXG4gICAgICBpZihyZi5fc3RhcnRlZEFzRGF0ZU9iaikge1xyXG4gICAgICAgIHJmLnN0YXJ0ZWREYXRlID0gcmYuX3N0YXJ0ZWRBc0RhdGVPYmoudG9TdHJpbmcoKTtcclxuICAgICAgfVxyXG4gICAgICAvLyBpdC5yZWNzLnB1c2gocmYpO1xyXG4gICAgICAvL1xyXG4gICAgICAvLyBpZiAodGhpcy5lbmFibGVVcGxvYWRSZWNvcmRpbmdzKSB7XHJcbiAgICAgIC8vICAgLy8gVE9ETyB1c2UgU3BlZWNoUmVjb3JkZXJjb25maWcgcmVzcC4gUmVjZmlsZVNlcnZpY2VcclxuICAgICAgLy8gICAvL25ldyBSRVNUIEFQSSBVUkxcclxuICAgICAgLy9cclxuICAgICAgICBsZXQgYXBpRW5kUG9pbnQgPSAnJztcclxuXHJcbiAgICAgICAgaWYgKHRoaXMuY29uZmlnICYmIHRoaXMuY29uZmlnLmFwaUVuZFBvaW50KSB7XHJcbiAgICAgICAgICBhcGlFbmRQb2ludCA9IHRoaXMuY29uZmlnLmFwaUVuZFBvaW50O1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoYXBpRW5kUG9pbnQgIT09ICcnKSB7XHJcbiAgICAgICAgICBhcGlFbmRQb2ludCA9IGFwaUVuZFBvaW50ICsgJy8nXHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAgIGxldCBzZXNzaW9uc1VybCA9IGFwaUVuZFBvaW50ICsgU2Vzc2lvblNlcnZpY2UuU0VTU0lPTl9BUElfQ1RYO1xyXG4gICAgICAgICAgIGxldCByZWNVcmw6IHN0cmluZyA9IHNlc3Npb25zVXJsICsgJy8nICsgcmYuc2Vzc2lvbiArICcvJyArIFJFQ0ZJTEVfQVBJX0NUWCArICcvJyArIHJmLnV1aWQ7XHJcbiAgICAgIC8vXHJcbiAgICAgIC8vXHJcbiAgICAgIC8vXHJcbiAgICAgIC8vICAgICAvLyBjb252ZXJ0IGFzeW5jaHJvbm91c2x5IHRvIDE2LWJpdCBpbnRlZ2VyIFBDTVxyXG4gICAgICAvLyAgICAgLy8gVE9ETyBjb3VsZCB3ZSBhdm9pZCBjb252ZXJzaW9uIHRvIHNhdmUgQ1BVIHJlc291cmNlcyBhbmQgdHJhbnNmZXIgZmxvYXQgUENNIGRpcmVjdGx5P1xyXG4gICAgICAvLyAgICAgLy8gVE9ETyBkdXBsaWNhdGUgY29udmVyc2lvbiBmb3IgbWFudWFsIGRvd25sb2FkXHJcbiAgICAgIC8vICAgICAvL2NvbnNvbGUubG9nKFwiQnVpbGQgd2F2IHdyaXRlci4uLlwiKTtcclxuICAgICAgICAgIHRoaXMucHJvY2Vzc2luZ1JlY29yZGluZz10cnVlXHJcbiAgICAgICAgICBsZXQgd3cgPSBuZXcgV2F2V3JpdGVyKCk7XHJcbiAgICAgICAgICB3dy53cml0ZUFzeW5jKGFkLCAod2F2RmlsZSkgPT4ge1xyXG4gICAgICAgICAgICAvL3RoaXMucG9zdFJlY29yZGluZyh3YXZGaWxlLCByZWNVcmwpO1xyXG4gICAgICAgICAgICAvL3JmLl9kYXRlQXNEYXRlT2JqPW5ldyBEYXRlKCk7XHJcbiAgICAgICAgICAgIHJmLmZyYW1lcz1hZC5sZW5ndGg7XHJcbiAgICAgICAgICAgIHRoaXMuZGlzcGxheVJlY0ZpbGU9cmY7XHJcbiAgICAgICAgICAgIC8vdGhpcy5yZWNvcmRpbmdMaXN0Q29tcC5yZWNvcmRpbmdMaXN0LnB1c2gocmYpO1xyXG4gICAgICAgICAgICB0aGlzLnJlY29yZGVyQ29tYmlQYW5lLnB1c2gocmYpO1xyXG4gICAgICAgICAgICB0aGlzLnBvc3RSZWNvcmRpbmdNdWx0aXBhcnQod2F2RmlsZSwgcmYudXVpZCxyZi5zZXNzaW9uLHJmLl9zdGFydGVkQXNEYXRlT2JqLHJlY1VybCk7XHJcbiAgICAgICAgICAgIHRoaXMucHJvY2Vzc2luZ1JlY29yZGluZz1mYWxzZTtcclxuICAgICAgICAgICAgdGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5kZXRlY3RDaGFuZ2VzKCk7XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgLy8gfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIGNoZWNrIGNvbXBsZXRlIHNlc3Npb25cclxuICAgIGxldCBjb21wbGV0ZSA9IHRydWU7XHJcblxyXG4gICAgbGV0IGF1dG9TdGFydCA9ICh0aGlzLnN0YXR1cyA9PT0gU3RhdHVzLlNUT1BQSU5HX1NUT1ApO1xyXG4gICAgdGhpcy5zdGF0dXMgPSBTdGF0dXMuSURMRTtcclxuICAgIGxldCBzdGFydE5leHQ9ZmFsc2U7XHJcblxyXG4gICAgICAgIHRoaXMubmF2aWdhdGlvbkRpc2FibGVkID0gZmFsc2U7XHJcbiAgICAgICAgdGhpcy51cGRhdGVOYXZpZ2F0aW9uQWN0aW9ucygpO1xyXG5cclxuICAgIHRoaXMuY2hhbmdlRGV0ZWN0b3JSZWYuZGV0ZWN0Q2hhbmdlcygpO1xyXG4gIH1cclxuXHJcbiAgcG9zdFJlY29yZGluZyh3YXZGaWxlOiBVaW50OEFycmF5LCByZWNVcmw6IHN0cmluZykge1xyXG4gICAgbGV0IHdhdkJsb2IgPSBuZXcgQmxvYihbd2F2RmlsZV0sIHt0eXBlOiAnYXVkaW8vd2F2J30pO1xyXG4gICAgbGV0IHVsID0gbmV3IFVwbG9hZCh3YXZCbG9iLCByZWNVcmwpO1xyXG4gICAgdGhpcy51cGxvYWRlci5xdWV1ZVVwbG9hZCh1bCk7XHJcbiAgfVxyXG5cclxuICBwb3N0UmVjb3JkaW5nTXVsdGlwYXJ0KHdhdkZpbGU6IFVpbnQ4QXJyYXksIHV1aWQ6c3RyaW5nfG51bGwsc2Vzc2lvbklkOnN0cmluZ3xudW1iZXJ8bnVsbCxzdGFydGVkRGF0ZTpEYXRlfG51bGx8dW5kZWZpbmVkLHJlY1VybDogc3RyaW5nKSB7XHJcbiAgICBsZXQgd2F2QmxvYiA9IG5ldyBCbG9iKFt3YXZGaWxlXSwge3R5cGU6ICdhdWRpby93YXYnfSk7XHJcblxyXG4gICAgbGV0IGZkPW5ldyBGb3JtRGF0YSgpO1xyXG4gICAgaWYodXVpZCkge1xyXG4gICAgICBmZC5zZXQoJ3V1aWQnLCB1dWlkKTtcclxuICAgIH1cclxuICAgIGlmKHNlc3Npb25JZCE9PW51bGwpIHtcclxuICAgICAgZmQuc2V0KCdzZXNzaW9uSWQnLCBzZXNzaW9uSWQudG9TdHJpbmcoKSk7XHJcbiAgICB9XHJcbiAgICBpZihzdGFydGVkRGF0ZSl7XHJcbiAgICAgIGZkLnNldCgnc3RhcnRlZERhdGUnLHN0YXJ0ZWREYXRlLnRvSlNPTigpKTtcclxuICAgIH1cclxuICAgIGZkLnNldCgnYXVkaW8nLHdhdkJsb2IpO1xyXG4gICAgbGV0IHVsID0gbmV3IFVwbG9hZChmZCwgcmVjVXJsKTtcclxuICAgIHRoaXMudXBsb2FkZXIucXVldWVVcGxvYWQodWwpO1xyXG4gIH1cclxuXHJcbiAgc3RvcCgpIHtcclxuICAgIGlmKHRoaXMuYWMpIHtcclxuICAgICAgdGhpcy5hYy5jbG9zZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSB1cGRhdGVDb250cm9sUGxheWJhY2tQb3NpdGlvbigpIHtcclxuICAgIGlmICh0aGlzLl9jb250cm9sQXVkaW9QbGF5ZXIucGxheVBvc2l0aW9uRnJhbWVzKSB7XHJcbiAgICAgIHRoaXMucmVjb3JkZXJDb21iaVBhbmUuYXVkaW9EaXNwbGF5LnBsYXlGcmFtZVBvc2l0aW9uID0gdGhpcy5fY29udHJvbEF1ZGlvUGxheWVyLnBsYXlQb3NpdGlvbkZyYW1lcztcclxuICAgICAgdGhpcy5saXZlTGV2ZWxEaXNwbGF5LnBsYXlGcmFtZVBvc2l0aW9uID0gdGhpcy5fY29udHJvbEF1ZGlvUGxheWVyLnBsYXlQb3NpdGlvbkZyYW1lcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGF1ZGlvUGxheWVyVXBkYXRlKGU6IEF1ZGlvUGxheWVyRXZlbnQpIHtcclxuICAgIGlmIChFdmVudFR5cGUuUkVBRFkgPT09IGUudHlwZSkge1xyXG5cclxuICAgIH0gZWxzZSBpZiAoRXZlbnRUeXBlLlNUQVJURUQgPT09IGUudHlwZSkge1xyXG4gICAgICAvL3RoaXMuc3RhdHVzID0gJ1BsYXliYWNrLi4uJztcclxuICAgICAgdGhpcy51cGRhdGVUaW1lcklkID0gd2luZG93LnNldEludGVydmFsKCgpID0+IHRoaXMudXBkYXRlQ29udHJvbFBsYXliYWNrUG9zaXRpb24oKSwgNTApO1xyXG5cclxuICAgIH0gZWxzZSBpZiAoRXZlbnRUeXBlLkVOREVEID09PSBlLnR5cGUpIHtcclxuICAgICAgLy8uc3RhdHVzPSdSZWFkeS4nO1xyXG4gICAgICB3aW5kb3cuY2xlYXJJbnRlcnZhbCh0aGlzLnVwZGF0ZVRpbWVySWQpO1xyXG5cclxuICAgIH1cclxuXHJcbiAgICBpZighdGhpcy5kZXN0cm95ZWQpIHtcclxuICAgICAgICB0aGlzLmNoYW5nZURldGVjdG9yUmVmLmRldGVjdENoYW5nZXMoKTtcclxuICAgIH1cclxuXHJcbiAgfVxyXG5cclxuICBjbG9zZWQoKSB7XHJcbiAgICB0aGlzLnN0YXR1c0FsZXJ0VHlwZSA9ICdpbmZvJztcclxuICAgIHRoaXMuc3RhdHVzTXNnID0gJ1Nlc3Npb24gY2xvc2VkLic7XHJcbiAgfVxyXG5cclxuXHJcbiAgZXJyb3IobXNnPSdBbiB1bmtub3duIGVycm9yIG9jY3VyZWQgZHVyaW5nIHJlY29yZGluZy4nLGFkdmljZTpzdHJpbmc9J1BsZWFzZSByZXRyeS4nKSB7XHJcbiAgICB0aGlzLnN0YXR1c01zZyA9ICdFUlJPUjogUmVjb3JkaW5nLic7XHJcbiAgICB0aGlzLnN0YXR1c0FsZXJ0VHlwZSA9ICdlcnJvcic7XHJcbiAgICB0aGlzLmRpYWxvZy5vcGVuKE1lc3NhZ2VEaWFsb2csIHtcclxuICAgICAgZGF0YToge1xyXG4gICAgICAgIHR5cGU6ICdlcnJvcicsXHJcbiAgICAgICAgdGl0bGU6ICdSZWNvcmRpbmcgZXJyb3InLFxyXG4gICAgICAgIG1zZzogbXNnLFxyXG4gICAgICAgIGFkdmljZTogYWR2aWNlXHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH1cclxufVxyXG5cclxuIl19
|