speechrecorderng 2.25.3 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2020/lib/audio/array_audio_buffer.mjs +101 -0
- package/esm2020/lib/audio/array_audio_buffer_input_stream.mjs +86 -0
- package/esm2020/lib/audio/audio_data_holder.mjs +109 -0
- package/esm2020/lib/audio/audio_display.mjs +5 -5
- package/esm2020/lib/audio/audio_player.mjs +9 -7
- package/esm2020/lib/audio/capture/capture.mjs +6 -1
- package/esm2020/lib/audio/dsp/level_measure.mjs +97 -55
- package/esm2020/lib/audio/io/stream.mjs +3 -3
- package/esm2020/lib/audio/persistor.mjs +5 -6
- package/esm2020/lib/audio/playback/array_audio_buffer_source_node.mjs +265 -0
- package/esm2020/lib/audio/playback/player.mjs +184 -50
- package/esm2020/lib/audio/ui/audio_canvas_layer_comp.mjs +25 -13
- package/esm2020/lib/audio/ui/audio_display_scroll_pane.mjs +2 -2
- package/esm2020/lib/audio/ui/audiosignal.mjs +206 -77
- package/esm2020/lib/audio/ui/container.mjs +14 -14
- package/esm2020/lib/audio/ui/livelevel.mjs +15 -2
- package/esm2020/lib/audio/ui/sonagram.mjs +343 -160
- package/esm2020/lib/io/stream.mjs +77 -1
- package/esm2020/lib/net/uploader.mjs +15 -3
- package/esm2020/lib/speechrecorder/recording.mjs +52 -7
- package/esm2020/lib/speechrecorder/recordings/recordings.service.mjs +99 -7
- package/esm2020/lib/speechrecorder/session/audiorecorder.mjs +117 -101
- package/esm2020/lib/speechrecorder/session/basicrecorder.mjs +34 -6
- package/esm2020/lib/speechrecorder/session/progress.mjs +2 -2
- package/esm2020/lib/speechrecorder/session/prompting.mjs +2 -2
- package/esm2020/lib/speechrecorder/session/recorder_combi_pane.mjs +6 -3
- package/esm2020/lib/speechrecorder/session/recording_file_cache.mjs +182 -0
- package/esm2020/lib/speechrecorder/session/recording_list.mjs +23 -10
- package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-meta.component.mjs +12 -6
- package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-u-i.component.mjs +5 -5
- package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-view.component.mjs +13 -9
- package/esm2020/lib/speechrecorder/session/recordingfile/recordingfile-service.mjs +8 -5
- package/esm2020/lib/speechrecorder/session/sessionmanager.mjs +118 -95
- package/esm2020/lib/speechrecorderng.component.mjs +2 -2
- package/esm2020/lib/speechrecorderng.module.mjs +5 -4
- package/esm2020/lib/spr.module.version.mjs +2 -2
- package/esm2020/lib/ui/recordingitem_display.mjs +2 -2
- package/fesm2015/speechrecorderng.mjs +2321 -743
- package/fesm2015/speechrecorderng.mjs.map +1 -1
- package/fesm2020/speechrecorderng.mjs +2321 -753
- package/fesm2020/speechrecorderng.mjs.map +1 -1
- package/lib/audio/array_audio_buffer.d.ts +15 -0
- package/lib/audio/array_audio_buffer_input_stream.d.ts +14 -0
- package/lib/audio/audio_data_holder.d.ts +29 -0
- package/lib/audio/audio_display.d.ts +2 -1
- package/lib/audio/audio_player.d.ts +2 -1
- package/lib/audio/capture/capture.d.ts +2 -0
- package/lib/audio/dsp/level_measure.d.ts +2 -1
- package/lib/audio/persistor.d.ts +4 -3
- package/lib/audio/playback/array_audio_buffer_source_node.d.ts +24 -0
- package/lib/audio/playback/player.d.ts +6 -0
- package/lib/audio/ui/audio_canvas_layer_comp.d.ts +4 -1
- package/lib/audio/ui/audio_display_scroll_pane.d.ts +2 -1
- package/lib/audio/ui/audiosignal.d.ts +3 -2
- package/lib/audio/ui/container.d.ts +3 -2
- package/lib/audio/ui/livelevel.d.ts +3 -1
- package/lib/audio/ui/sonagram.d.ts +3 -2
- package/lib/io/stream.d.ts +17 -0
- package/lib/net/uploader.d.ts +6 -1
- package/lib/speechrecorder/recording.d.ts +15 -3
- package/lib/speechrecorder/recordings/recordings.service.d.ts +2 -0
- package/lib/speechrecorder/session/audiorecorder.d.ts +2 -7
- package/lib/speechrecorder/session/basicrecorder.d.ts +9 -3
- package/lib/speechrecorder/session/progress.d.ts +1 -1
- package/lib/speechrecorder/session/prompting.d.ts +1 -1
- package/lib/speechrecorder/session/recorder_combi_pane.d.ts +3 -1
- package/lib/speechrecorder/session/recording_file_cache.d.ts +30 -0
- package/lib/speechrecorder/session/recording_list.d.ts +3 -1
- package/lib/speechrecorder/session/recordingfile/recording-file-meta.component.d.ts +2 -1
- package/lib/speechrecorder/session/recordingfile/recording-file-view.component.d.ts +1 -0
- package/lib/speechrecorder/session/sessionmanager.d.ts +5 -11
- package/lib/speechrecorderng.module.d.ts +2 -1
- package/lib/spr.module.version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { ArrayAudioBufferInputStream } from "../array_audio_buffer_input_stream";
|
|
2
|
+
import { EditFloat32ArrayInputStream } from "../../io/stream";
|
|
3
|
+
// Code from audio_source_worklet.js as string constant to be loaded as module
|
|
4
|
+
// Changes in audio_source_worklet.js must be copied and pasted to this string constant
|
|
5
|
+
const aswpStr = "\n" +
|
|
6
|
+
"// Important note: Changes in audio_source_worklet.js must be copied and pasted to the string constant aswpStr in array_audio_buffer_source_node.ts\n" +
|
|
7
|
+
"\n" +
|
|
8
|
+
"\n" +
|
|
9
|
+
"class AudioSourceProcessor extends AudioWorkletProcessor{\n" +
|
|
10
|
+
"\n" +
|
|
11
|
+
" filledFrames=0;\n" +
|
|
12
|
+
" audioBuffers=new Array();\n" +
|
|
13
|
+
" currentAudioBuffer=null;\n" +
|
|
14
|
+
" currentAudioBufferFramePos=0;\n" +
|
|
15
|
+
" currentAudioBufferAvail=0;\n" +
|
|
16
|
+
" running=false;\n" +
|
|
17
|
+
" ended=false;\n" +
|
|
18
|
+
"\n" +
|
|
19
|
+
" constructor() {\n" +
|
|
20
|
+
" super({numberOfInputs:0,numberOfOutputs:1});\n" +
|
|
21
|
+
" this.port.onmessage=(msgEv)=>{\n" +
|
|
22
|
+
" // received audio playback data from application\n" +
|
|
23
|
+
" //console.debug(\"Audio source worklet msg: Received.\");\n" +
|
|
24
|
+
"\n" +
|
|
25
|
+
" if(msgEv.data.cmd){\n" +
|
|
26
|
+
" if('data'===msgEv.data.cmd) {\n" +
|
|
27
|
+
" let chs = msgEv.data.chs;\n" +
|
|
28
|
+
"\n" +
|
|
29
|
+
" let audioData = new Array(chs);\n" +
|
|
30
|
+
" for (let ch = 0; ch < chs; ch++) {\n" +
|
|
31
|
+
" audioData[ch] = new Float32Array(msgEv.data.audioData[ch]);\n" +
|
|
32
|
+
" }\n" +
|
|
33
|
+
" let msgChBufLen=audioData[0].length;\n" +
|
|
34
|
+
" this.audioBuffers.push(audioData);\n" +
|
|
35
|
+
" this.filledFrames += msgChBufLen;\n" +
|
|
36
|
+
" //console.debug(\"Audio source worklet msg: Filled \" + this.filledFrames+ \" in \"+this.audioBuffers.length+\" buffers.\");\n" +
|
|
37
|
+
"\n" +
|
|
38
|
+
" }else if('start'===msgEv.data.cmd){\n" +
|
|
39
|
+
" this.running=true;\n" +
|
|
40
|
+
" }else if('stop'===msgEv.data.cmd){\n" +
|
|
41
|
+
" //console.debug(\"Stop...\");\n" +
|
|
42
|
+
" this.running=false;\n" +
|
|
43
|
+
" // clear buffers\n" +
|
|
44
|
+
" this.filledFrames=0;\n" +
|
|
45
|
+
" while(this.audioBuffers.length > 0) {\n" +
|
|
46
|
+
" this.audioBuffers.pop();\n" +
|
|
47
|
+
" }\n" +
|
|
48
|
+
" this.currentAudioBuffer=new Float32Array(0);\n" +
|
|
49
|
+
" }\n" +
|
|
50
|
+
" }\n" +
|
|
51
|
+
" }\n" +
|
|
52
|
+
" }\n" +
|
|
53
|
+
"\n" +
|
|
54
|
+
" process(\n" +
|
|
55
|
+
" inputs,\n" +
|
|
56
|
+
" outputs,\n" +
|
|
57
|
+
" parameters\n" +
|
|
58
|
+
" ){\n" +
|
|
59
|
+
" //console.debug(\"Audio source worklet: process \"+outputs.length+ \" output buffers.\");\n" +
|
|
60
|
+
" // copy ring buffer data to outputs\n" +
|
|
61
|
+
" if(!this.running){\n" +
|
|
62
|
+
" return !this.ended;\n" +
|
|
63
|
+
" }\n" +
|
|
64
|
+
"\n" +
|
|
65
|
+
" let output=outputs[0];\n" +
|
|
66
|
+
" let chs=output.length;\n" +
|
|
67
|
+
" //console.debug(\"Audio source worklet: Output channels: \"+chs);\n" +
|
|
68
|
+
" if(chs>0) {\n" +
|
|
69
|
+
"\n" +
|
|
70
|
+
" let outCh0 = output[0];\n" +
|
|
71
|
+
" let outChLen = outCh0.length;\n" +
|
|
72
|
+
"\n" +
|
|
73
|
+
" if(!this.currentAudioBuffer){\n" +
|
|
74
|
+
" // get first buffer\n" +
|
|
75
|
+
" let nxtBuff=this.audioBuffers.shift();\n" +
|
|
76
|
+
" if(nxtBuff) {\n" +
|
|
77
|
+
" this.currentAudioBuffer = nxtBuff;\n" +
|
|
78
|
+
" this.currentAudioBufferFramePos=0;\n" +
|
|
79
|
+
" this.currentAudioBufferAvail=this.currentAudioBuffer[0].length;\n" +
|
|
80
|
+
" }else{\n" +
|
|
81
|
+
" return true;\n" +
|
|
82
|
+
" }\n" +
|
|
83
|
+
" }\n" +
|
|
84
|
+
"\n" +
|
|
85
|
+
" let copied=0;\n" +
|
|
86
|
+
" do{\n" +
|
|
87
|
+
" if(this.currentAudioBufferAvail==0){\n" +
|
|
88
|
+
" let nxtBuff=this.audioBuffers.shift();\n" +
|
|
89
|
+
" if(nxtBuff){\n" +
|
|
90
|
+
" this.currentAudioBuffer=nxtBuff;\n" +
|
|
91
|
+
" this.currentAudioBufferFramePos=0;\n" +
|
|
92
|
+
" this.currentAudioBufferAvail=this.currentAudioBuffer[0].length;\n" +
|
|
93
|
+
" //console.debug(\"Next buffer with \"+this.currentAudioBufferAvail+ \" frames\");\n" +
|
|
94
|
+
" this.port.postMessage({eventType:'bufferNotification',filledFrames:this.filledFrames});\n" +
|
|
95
|
+
" }else{\n" +
|
|
96
|
+
" this.ended=true;\n" +
|
|
97
|
+
" this.port.postMessage({eventType:'ended'});\n" +
|
|
98
|
+
" //console.debug(\"Stream ended\");\n" +
|
|
99
|
+
" break;\n" +
|
|
100
|
+
" }\n" +
|
|
101
|
+
" }\n" +
|
|
102
|
+
" //console.debug(\"outChLen: \"+outChLen+\", copied: \"+copied+\", current avail: \"+this.currentAudioBufferAvail);\n" +
|
|
103
|
+
" let toCopy=outChLen-copied;\n" +
|
|
104
|
+
" if(toCopy>this.currentAudioBufferAvail){\n" +
|
|
105
|
+
" toCopy=this.currentAudioBufferAvail;\n" +
|
|
106
|
+
" }\n" +
|
|
107
|
+
" //console.debug(\"Copy \"+toCopy+\" frames...\");\n" +
|
|
108
|
+
" for(let ch=0;ch<chs;ch++) {\n" +
|
|
109
|
+
" let outCh=output[ch];\n" +
|
|
110
|
+
" for (let i = 0; i < toCopy; i++) {\n" +
|
|
111
|
+
" outCh[copied+i]=this.currentAudioBuffer[ch][this.currentAudioBufferFramePos+i];\n" +
|
|
112
|
+
" }\n" +
|
|
113
|
+
" }\n" +
|
|
114
|
+
" copied+=toCopy;\n" +
|
|
115
|
+
" this.currentAudioBufferFramePos+=toCopy;\n" +
|
|
116
|
+
" this.currentAudioBufferAvail-=toCopy;\n" +
|
|
117
|
+
"\n" +
|
|
118
|
+
" }while(copied<outChLen);\n" +
|
|
119
|
+
" this.filledFrames-=copied;\n" +
|
|
120
|
+
" //console.debug(\"Copied \"+copied+\" frames.\");\n" +
|
|
121
|
+
" }\n" +
|
|
122
|
+
" return !this.ended;\n" +
|
|
123
|
+
" }\n" +
|
|
124
|
+
"}\n" +
|
|
125
|
+
"\n" +
|
|
126
|
+
"registerProcessor('audio-source-worklet',AudioSourceProcessor);\n";
|
|
127
|
+
export class ArrayAudioBufferSourceNode extends AudioWorkletNode {
|
|
128
|
+
constructor(context) {
|
|
129
|
+
super(context, 'audio-source-worklet');
|
|
130
|
+
this._bufferFillSeconds = ArrayAudioBufferSourceNode.DEFAULT_BUFFER_FILL_SECONDS;
|
|
131
|
+
this.bufferFillFrames = 0;
|
|
132
|
+
this._arrayAudioBuffer = null;
|
|
133
|
+
this._audioInputStream = null;
|
|
134
|
+
this._aisBufs = null;
|
|
135
|
+
this.filledFrames = 0;
|
|
136
|
+
this.onended = null;
|
|
137
|
+
this.channelCountMode = 'explicit';
|
|
138
|
+
this.port.onmessage = (msgEv) => {
|
|
139
|
+
if (msgEv.data) {
|
|
140
|
+
let evType = msgEv.data.eventType;
|
|
141
|
+
if (evType) {
|
|
142
|
+
if ('bufferNotification' === evType) {
|
|
143
|
+
this.filledFrames = msgEv.data.filledFrames;
|
|
144
|
+
//console.debug("Buffer notification: filled frames: " + this.filledFrames);
|
|
145
|
+
this.fillBuffer();
|
|
146
|
+
}
|
|
147
|
+
else if ('ended' === evType) {
|
|
148
|
+
let drainTime = 0;
|
|
149
|
+
if (this._arrayAudioBuffer?.sampleRate) {
|
|
150
|
+
drainTime = ArrayAudioBufferSourceNode.QUANTUM_FRAME_LEN / this._arrayAudioBuffer.sampleRate;
|
|
151
|
+
}
|
|
152
|
+
//let dstAny:any=this.context.destination;
|
|
153
|
+
//console.debug('Destination node tail-time: '+dstAny['tail-time']);
|
|
154
|
+
window.setTimeout(() => {
|
|
155
|
+
this.onended?.call(this);
|
|
156
|
+
}, drainTime * 1000);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
fillBuffer(frameOffset) {
|
|
163
|
+
if (this._arrayAudioBuffer && this._audioInputStream && this._aisBufs) {
|
|
164
|
+
let filled = this.filledFrames;
|
|
165
|
+
let bufLen = 0;
|
|
166
|
+
while (filled < this.bufferFillFrames) {
|
|
167
|
+
let read = this._audioInputStream.read(this._aisBufs);
|
|
168
|
+
//console.log("ArrayAudioBufferSourceNode: read: "+read)
|
|
169
|
+
if (read) {
|
|
170
|
+
let trBuffers = new Array(this.channelCount);
|
|
171
|
+
for (let ch = 0; ch < this.channelCount; ch++) {
|
|
172
|
+
let adCh = this._aisBufs[ch];
|
|
173
|
+
let adChCopy = new Float32Array(adCh.length);
|
|
174
|
+
bufLen = adChCopy.length;
|
|
175
|
+
adChCopy.set(adCh);
|
|
176
|
+
trBuffers[ch] = adChCopy.buffer;
|
|
177
|
+
}
|
|
178
|
+
this.port.postMessage({
|
|
179
|
+
cmd: 'data',
|
|
180
|
+
chs: this.channelCount,
|
|
181
|
+
audioData: trBuffers
|
|
182
|
+
}, trBuffers);
|
|
183
|
+
filled += read;
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
get arrayAudioBuffer() {
|
|
192
|
+
return this._arrayAudioBuffer;
|
|
193
|
+
}
|
|
194
|
+
set arrayAudioBuffer(value) {
|
|
195
|
+
this._arrayAudioBuffer = value;
|
|
196
|
+
if (this._arrayAudioBuffer?.channelCount) {
|
|
197
|
+
this.channelCount = this._arrayAudioBuffer?.channelCount;
|
|
198
|
+
this.bufferFillFrames = this._arrayAudioBuffer.sampleRate * this._bufferFillSeconds;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
get bufferFillSeconds() {
|
|
202
|
+
return this._bufferFillSeconds;
|
|
203
|
+
}
|
|
204
|
+
set bufferFillSeconds(value) {
|
|
205
|
+
this._bufferFillSeconds = value;
|
|
206
|
+
}
|
|
207
|
+
start(when, offset, duration) {
|
|
208
|
+
if (when) {
|
|
209
|
+
throw Error("when, offest,duration parameters currently not supported by ArrayAudioBufferSourceNode class");
|
|
210
|
+
}
|
|
211
|
+
if (this._arrayAudioBuffer) {
|
|
212
|
+
let arrAis = new ArrayAudioBufferInputStream(this._arrayAudioBuffer);
|
|
213
|
+
if (offset === undefined && duration === undefined) {
|
|
214
|
+
this._audioInputStream = arrAis;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
let offsetFrames = 0;
|
|
218
|
+
let durationFrames = undefined;
|
|
219
|
+
if (offset !== undefined) {
|
|
220
|
+
offsetFrames = Math.floor(offset * this._arrayAudioBuffer.sampleRate);
|
|
221
|
+
}
|
|
222
|
+
if (duration !== undefined) {
|
|
223
|
+
durationFrames = Math.floor(duration * this._arrayAudioBuffer.sampleRate);
|
|
224
|
+
}
|
|
225
|
+
this._audioInputStream = new EditFloat32ArrayInputStream(arrAis, offsetFrames, durationFrames);
|
|
226
|
+
}
|
|
227
|
+
let chs = this._arrayAudioBuffer.channelCount;
|
|
228
|
+
this._aisBufs = new Array(chs);
|
|
229
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
230
|
+
this._aisBufs[ch] = new Float32Array(1024);
|
|
231
|
+
}
|
|
232
|
+
this.fillBuffer();
|
|
233
|
+
this.port.postMessage({ cmd: 'start' });
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
stop() {
|
|
237
|
+
this.port.postMessage({ cmd: 'stop' });
|
|
238
|
+
this.onended?.call(this);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
ArrayAudioBufferSourceNode.QUANTUM_FRAME_LEN = 128;
|
|
242
|
+
ArrayAudioBufferSourceNode.DEFAULT_BUFFER_FILL_SECONDS = 10;
|
|
243
|
+
export class AudioSourceWorkletModuleLoader {
|
|
244
|
+
static loadModule(context) {
|
|
245
|
+
return new Promise((resolve, reject) => {
|
|
246
|
+
if (AudioSourceWorkletModuleLoader.moduleLoaded) {
|
|
247
|
+
resolve.call(self);
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
let audioWorkletModuleBlob = new Blob([aswpStr], { type: 'text/javascript' });
|
|
251
|
+
let audioWorkletModuleBlobUrl = window.URL.createObjectURL(audioWorkletModuleBlob);
|
|
252
|
+
context.resume();
|
|
253
|
+
context.audioWorklet.addModule(audioWorkletModuleBlobUrl).then(() => {
|
|
254
|
+
AudioSourceWorkletModuleLoader.moduleLoaded = true;
|
|
255
|
+
resolve.call(self);
|
|
256
|
+
}).catch((reason) => {
|
|
257
|
+
console.error(reason);
|
|
258
|
+
reject.call(reason);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
AudioSourceWorkletModuleLoader.moduleLoaded = false;
|
|
265
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJyYXlfYXVkaW9fYnVmZmVyX3NvdXJjZV9ub2RlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvc3BlZWNocmVjb3JkZXJuZy9zcmMvbGliL2F1ZGlvL3BsYXliYWNrL2FycmF5X2F1ZGlvX2J1ZmZlcl9zb3VyY2Vfbm9kZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUMsMkJBQTJCLEVBQUMsTUFBTSxvQ0FBb0MsQ0FBQztBQUMvRSxPQUFPLEVBQUMsMkJBQTJCLEVBQTBCLE1BQU0saUJBQWlCLENBQUM7QUFFckYsOEVBQThFO0FBQzlFLHVGQUF1RjtBQUV2RixNQUFNLE9BQU8sR0FBRyxJQUFJO0lBQ2xCLHVKQUF1SjtJQUN2SixJQUFJO0lBQ0osSUFBSTtJQUNKLDZEQUE2RDtJQUM3RCxJQUFJO0lBQ0osdUJBQXVCO0lBQ3ZCLGlDQUFpQztJQUNqQyxnQ0FBZ0M7SUFDaEMscUNBQXFDO0lBQ3JDLGtDQUFrQztJQUNsQyxzQkFBc0I7SUFDdEIsb0JBQW9CO0lBQ3BCLElBQUk7SUFDSix1QkFBdUI7SUFDdkIsd0RBQXdEO0lBQ3hELDBDQUEwQztJQUMxQyw4REFBOEQ7SUFDOUQsdUVBQXVFO0lBQ3ZFLElBQUk7SUFDSixpQ0FBaUM7SUFDakMsNkNBQTZDO0lBQzdDLDJDQUEyQztJQUMzQyxJQUFJO0lBQ0osaURBQWlEO0lBQ2pELG9EQUFvRDtJQUNwRCwrRUFBK0U7SUFDL0UsbUJBQW1CO0lBQ25CLHNEQUFzRDtJQUN0RCxvREFBb0Q7SUFDcEQsbURBQW1EO0lBQ25ELDhJQUE4STtJQUM5SSxJQUFJO0lBQ0osbURBQW1EO0lBQ25ELG9DQUFvQztJQUNwQyxrREFBa0Q7SUFDbEQsK0NBQStDO0lBQy9DLHFDQUFxQztJQUNyQyxrQ0FBa0M7SUFDbEMsc0NBQXNDO0lBQ3RDLHVEQUF1RDtJQUN2RCw0Q0FBNEM7SUFDNUMsbUJBQW1CO0lBQ25CLDhEQUE4RDtJQUM5RCxpQkFB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O0lBQ0wsQ0FBQzs7QUFsQmMsMkNBQVksR0FBQyxLQUFLLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0FycmF5QXVkaW9CdWZmZXJ9IGZyb20gXCIuLi9hcnJheV9hdWRpb19idWZmZXJcIjtcclxuaW1wb3J0IHtBcnJheUF1ZGlvQnVmZmVySW5wdXRTdHJlYW19IGZyb20gXCIuLi9hcnJheV9hdWRpb19idWZmZXJfaW5wdXRfc3RyZWFtXCI7XHJcbmltcG9ydCB7RWRpdEZsb2F0MzJBcnJheUlucHV0U3RyZWFtLCBGbG9hdDMyQXJyYXlJbnB1dFN0cmVhbX0gZnJvbSBcIi4uLy4uL2lvL3N0cmVhbVwiO1xyXG5cclxuLy8gQ29kZSBmcm9tIGF1ZGlvX3NvdXJjZV93b3JrbGV0LmpzIGFzIHN0cmluZyBjb25zdGFudCB0byBiZSBsb2FkZWQgYXMgbW9kdWxlXHJcbi8vIENoYW5nZXMgaW4gYXVkaW9fc291cmNlX3dvcmtsZXQuanMgbXVzdCBiZSBjb3BpZWQgYW5kIHBhc3RlZCB0byB0aGlzIHN0cmluZyBjb25zdGFudFxyXG5cclxuY29uc3QgYXN3cFN0ciA9IFwiXFxuXCIgK1xyXG4gIFwiLy8gSW1wb3J0YW50IG5vdGU6IENoYW5nZXMgaW4gYXVkaW9fc291cmNlX3dvcmtsZXQuanMgbXVzdCBiZSBjb3BpZWQgYW5kIHBhc3RlZCB0byB0aGUgc3RyaW5nIGNvbnN0YW50IGFzd3BTdHIgaW4gYXJyYXlfYXVkaW9fYnVmZmVyX3NvdXJjZV9ub2RlLnRzXFxuXCIgK1xyXG4gIFwiXFxuXCIgK1xyXG4gIFwiXFxuXCIgK1xyXG4gIFwiY2xhc3MgQXVkaW9Tb3VyY2VQcm9jZXNzb3IgZXh0ZW5kcyBBdWRpb1dvcmtsZXRQcm9jZXNzb3J7XFxuXCIgK1xyXG4gIFwiXFxuXCIgK1xyXG4gIFwiICAgIGZpbGxlZEZyYW1lcz0wO1xcblwiICtcclxuICBcIiAgICBhdWRpb0J1ZmZlcnM9bmV3IEFycmF5KCk7XFxuXCIgK1xyXG4gIFwiICAgIGN1cnJlbnRBdWRpb0J1ZmZlcj1udWxsO1xcblwiICtcclxuICBcIiAgICBjdXJyZW50QXVkaW9CdWZmZXJGcmFtZVBvcz0wO1xcblwiICtcclxuICBcIiAgICBjdXJyZW50QXVkaW9CdWZmZXJBdmFpbD0wO1xcblwiICtcclxuICBcIiAgICBydW5uaW5nPWZhbHNlO1xcblwiICtcclxuICBcIiAgICBlbmRlZD1mYWxzZTtcXG5cIiArXHJcbiAgXCJcXG5cIiArXHJcbiAgXCIgICAgY29uc3RydWN0b3IoKSB7XFxuXCIgK1xyXG4gIFwiICAgICAgICBzdXBlcih7bnVtYmVyT2ZJbnB1dHM6MCxudW1iZXJPZk91dHB1dHM6MX0pO1xcblwiICtcclxuICBcIiAgICAgICAgdGhpcy5wb3J0Lm9ubWVzc2FnZT0obXNnRXYpPT57XFxuXCIgK1xyXG4gIFwiICAgICAgICAgIC8vIHJlY2VpdmVkIGF1ZGlvIHBsYXliYWNrIGRhdGEgZnJvbSBhcHBsaWNhdGlvblxcblwiICtcclxuICBcIiAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXFxcIkF1ZGlvIHNvdXJjZSB3b3JrbGV0IG1zZzogUmVjZWl2ZWQuXFxcIik7XFxuXCIgK1xyXG4gIFwiXFxuXCIgK1xyXG4gIFwiICAgICAgICAgIGlmKG1zZ0V2LmRhdGEuY21kKXtcXG5cIiArXHJcbiAgXCIgICAgICAgICAgICBpZignZGF0YSc9PT1tc2dFdi5kYXRhLmNtZCkge1xcblwiICtcclxuICBcIiAgICAgICAgICAgICAgbGV0IGNocyA9IG1zZ0V2LmRhdGEuY2hzO1xcblwiICtcclxuICBcIlxcblwiICtcclxuICBcIiAgICAgICAgICAgICAgbGV0IGF1ZGlvRGF0YSA9IG5ldyBBcnJheShjaHMpO1xcblwiICtcclxuICBcIiAgICAgICAgICAgICAgZm9yIChsZXQgY2ggPSAwOyBjaCA8IGNoczsgY2grKykge1xcblwiICtcclxuICBcIiAgICAgICAgICAgICAgICBhdWRpb0RhdGFbY2hdID0gbmV3IEZsb2F0MzJBcnJheShtc2dFdi5kYXRhLmF1ZGlvRGF0YVtjaF0pO1xcblwiICtcclxuICBcIiAgICAgICAgICAgICAgfVxcblwiICtcclxuICBcIiAgICAgICAgICAgICAgbGV0IG1zZ0NoQnVmTGVuPWF1ZGlvRGF0YVswXS5sZW5ndGg7XFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgICB0aGlzLmF1ZGlvQnVmZmVycy5wdXNoKGF1ZGlvRGF0YSk7XFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgICB0aGlzLmZpbGxlZEZyYW1lcyArPSBtc2dDaEJ1ZkxlbjtcXG5cIiArXHJcbiAgXCIgICAgICAgICAgICAgIC8vY29uc29sZS5kZWJ1ZyhcXFwiQXVkaW8gc291cmNlIHdvcmtsZXQgbXNnOiBGaWxsZWQgXFxcIiArIHRoaXMuZmlsbGVkRnJhbWVzKyBcXFwiIGluIFxcXCIrdGhpcy5hdWRpb0J1ZmZlcnMubGVuZ3RoK1xcXCIgYnVmZmVycy5cXFwiKTtcXG5cIiArXHJcbiAgXCJcXG5cIiArXHJcbiAgXCIgICAgICAgICAgICB9ZWxzZSBpZignc3RhcnQnPT09bXNnRXYuZGF0YS5jbWQpe1xcblwiICtcclxuICBcIiAgICAgICAgICAgICAgdGhpcy5ydW5uaW5nPXRydWU7XFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgfWVsc2UgaWYoJ3N0b3AnPT09bXNnRXYuZGF0YS5jbWQpe1xcblwiICtcclxuICBcIiAgICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFxcXCJTdG9wLi4uXFxcIik7XFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgICB0aGlzLnJ1bm5pbmc9ZmFsc2U7XFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgICAvLyBjbGVhciBidWZmZXJzXFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgICB0aGlzLmZpbGxlZEZyYW1lcz0wO1xcblwiICtcclxuICBcIiAgICAgICAgICAgICAgd2hpbGUodGhpcy5hdWRpb0J1ZmZlcnMubGVuZ3RoID4gMCkge1xcblwiICtcclxuICBcIiAgICAgICAgICAgICAgICB0aGlzLmF1ZGlvQnVmZmVycy5wb3AoKTtcXG5cIiArXHJcbiAgXCIgICAgICAgICAgICAgIH1cXG5cIiArXHJcbiAgXCIgICAgICAgICAgICAgIHRoaXMuY3VycmVudEF1ZGlvQnVmZmVyPW5ldyBGbG9hdDMyQXJyYXkoMCk7XFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgfVxcblwiICtcclxuICBcIiAgICAgICAgICB9XFxuXCIgK1xyXG4gIFwiICAgICAgICB9XFxuXCIgK1xyXG4gIFwiICAgIH1cXG5cIiArXHJcbiAgXCJcXG5cIiArXHJcbiAgXCIgcHJvY2VzcyhcXG5cIiArXHJcbiAgXCIgICAgICBpbnB1dHMsXFxuXCIgK1xyXG4gIFwiICAgICAgb3V0cHV0cyxcXG5cIiArXHJcbiAgXCIgICAgICBwYXJhbWV0ZXJzXFxuXCIgK1xyXG4gIFwiICApe1xcblwiICtcclxuICBcIiAgICAgIC8vY29uc29sZS5kZWJ1ZyhcXFwiQXVkaW8gc291cmNlIHdvcmtsZXQ6IHByb2Nlc3MgXFxcIitvdXRwdXRzLmxlbmd0aCsgXFxcIiBvdXRwdXQgYnVmZmVycy5cXFwiKTtcXG5cIiArXHJcbiAgXCIgICAgICAvLyBjb3B5IHJpbmcgYnVmZmVyIGRhdGEgdG8gb3V0cHV0c1xcblwiICtcclxuICBcIiAgICAgICAgaWYoIXRoaXMucnVubmluZyl7XFxuXCIgK1xyXG4gIFwiICAgICAgICAgIHJldHVybiAhdGhpcy5lbmRlZDtcXG5cIiArXHJcbiAgXCIgICAgICAgIH1cXG5cIiArXHJcbiAgXCJcXG5cIiArXHJcbiAgXCIgICAgICAgIGxldCBvdXRwdXQ9b3V0cHV0c1swXTtcXG5cIiArXHJcbiAgXCIgICAgICAgIGxldCBjaHM9b3V0cHV0Lmxlbmd0aDtcXG5cIiArXHJcbiAgXCIgICAgICAgIC8vY29uc29sZS5kZWJ1ZyhcXFwiQXVkaW8gc291cmNlIHdvcmtsZXQ6IE91dHB1dCBjaGFubmVsczogXFxcIitjaHMpO1xcblwiICtcclxuICBcIiAgICAgICAgaWYoY2hzPjApIHtcXG5cIiArXHJcbiAgXCJcXG5cIiArXHJcbiAgXCIgICAgICAgICAgbGV0IG91dENoMCA9IG91dHB1dFswXTtcXG5cIiArXHJcbiAgXCIgICAgICAgICAgbGV0IG91dENoTGVuID0gb3V0Q2gwLmxlbmd0aDtcXG5cIiArXHJcbiAgXCJcXG5cIiArXHJcbiAgXCIgICAgICAgICAgaWYoIXRoaXMuY3VycmVudEF1ZGlvQnVmZmVyKXtcXG5cIiArXHJcbiAgXCIgICAgICAgICAgICAvLyBnZXQgZmlyc3QgYnVmZmVyXFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgbGV0IG54dEJ1ZmY9dGhpcy5hdWRpb0J1ZmZlcnMuc2hpZnQoKTtcXG5cIiArXHJcbiAgXCIgICAgICAgICAgICBpZihueHRCdWZmKSB7XFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgICB0aGlzLmN1cnJlbnRBdWRpb0J1ZmZlciA9IG54dEJ1ZmY7XFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgICB0aGlzLmN1cnJlbnRBdWRpb0J1ZmZlckZyYW1lUG9zPTA7XFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgICB0aGlzLmN1cnJlbnRBdWRpb0J1ZmZlckF2YWlsPXRoaXMuY3VycmVudEF1ZGlvQnVmZmVyWzBdLmxlbmd0aDtcXG5cIiArXHJcbiAgXCIgICAgICAgICAgICB9ZWxzZXtcXG5cIiArXHJcbiAgXCIgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xcblwiICtcclxuICBcIiAgICAgICAgICAgIH1cXG5cIiArXHJcbiAgXCIgICAgICAgICAgfVxcblwiICtcclxuICBcIlxcblwiICtcclxuICBcIiAgICAgICAgICBsZXQgY29waWVkPTA7XFxuXCIgK1xyXG4gIFwiICAgICAgICAgIGRve1xcblwiICtcclxuICBcIiAgICAgICAgICAgIGlmKHRoaXMuY3VycmVudEF1ZGlvQnVmZmVyQXZhaWw9PTApe1xcblwiICtcclxuICBcIiAgICAgICAgICAgICAgbGV0IG54dEJ1ZmY9dGhpcy5hdWRpb0J1ZmZlcnMuc2hpZnQoKTtcXG5cIiArXHJcbiAgXCIgICAgICAgICAgICAgIGlmKG54dEJ1ZmYpe1xcblwiICtcclxuICBcIiAgICAgICAgICAgICAgICB0aGlzLmN1cnJlbnRBdWRpb0J1ZmZlcj1ueHRCdWZmO1xcblwiICtcclxuICBcIiAgICAgICAgICAgICAgICB0aGlzLmN1cnJlbnRBdWRpb0J1ZmZlckZyYW1lUG9zPTA7XFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudEF1ZGlvQnVmZmVyQXZhaWw9dGhpcy5jdXJyZW50QXVkaW9CdWZmZXJbMF0ubGVuZ3RoO1xcblwiICtcclxuICBcIiAgICAgICAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXFxcIk5leHQgYnVmZmVyIHdpdGggXFxcIit0aGlzLmN1cnJlbnRBdWRpb0J1ZmZlckF2YWlsKyBcXFwiIGZyYW1lc1xcXCIpO1xcblwiICtcclxuICBcIiAgICAgICAgICAgICAgICB0aGlzLnBvcnQucG9zdE1lc3NhZ2Uoe2V2ZW50VHlwZTonYnVmZmVyTm90aWZpY2F0aW9uJyxmaWxsZWRGcmFtZXM6dGhpcy5maWxsZWRGcmFtZXN9KTtcXG5cIiArXHJcbiAgXCIgICAgICAgICAgICAgIH1lbHNle1xcblwiICtcclxuICBcIiAgICAgICAgICAgICAgICB0aGlzLmVuZGVkPXRydWU7XFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgICAgIHRoaXMucG9ydC5wb3N0TWVzc2FnZSh7ZXZlbnRUeXBlOidlbmRlZCd9KTtcXG5cIiArXHJcbiAgXCIgICAgICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFxcXCJTdHJlYW0gZW5kZWRcXFwiKTtcXG5cIiArXHJcbiAgXCIgICAgICAgICAgICAgICAgYnJlYWs7XFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgICB9XFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgfVxcblwiICtcclxuICBcIiAgICAgICAgICAgIC8vY29uc29sZS5kZWJ1ZyhcXFwib3V0Q2hMZW46IFxcXCIrb3V0Q2hMZW4rXFxcIiwgY29waWVkOiBcXFwiK2NvcGllZCtcXFwiLCBjdXJyZW50IGF2YWlsOiBcXFwiK3RoaXMuY3VycmVudEF1ZGlvQnVmZmVyQXZhaWwpO1xcblwiICtcclxuICBcIiAgICAgICAgICAgIGxldCB0b0NvcHk9b3V0Q2hMZW4tY29waWVkO1xcblwiICtcclxuICBcIiAgICAgICAgICAgIGlmKHRvQ29weT50aGlzLmN1cnJlbnRBdWRpb0J1ZmZlckF2YWlsKXtcXG5cIiArXHJcbiAgXCIgICAgICAgICAgICAgIHRvQ29weT10aGlzLmN1cnJlbnRBdWRpb0J1ZmZlckF2YWlsO1xcblwiICtcclxuICBcIiAgICAgICAgICAgIH1cXG5cIiArXHJcbiAgXCIgICAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXFxcIkNvcHkgXFxcIit0b0NvcHkrXFxcIiBmcmFtZXMuLi5cXFwiKTtcXG5cIiArXHJcbiAgXCIgICAgICAgICAgICBmb3IobGV0IGNoPTA7Y2g8Y2hzO2NoKyspIHtcXG5cIiArXHJcbiAgXCIgICAgICAgICAgICAgIGxldCBvdXRDaD1vdXRwdXRbY2hdO1xcblwiICtcclxuICBcIiAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0b0NvcHk7IGkrKykge1xcblwiICtcclxuICBcIiAgICAgICAgICAgICAgICBvdXRDaFtjb3BpZWQraV09dGhpcy5jdXJyZW50QXVkaW9CdWZmZXJbY2hdW3RoaXMuY3VycmVudEF1ZGlvQnVmZmVyRnJhbWVQb3MraV07XFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgICB9XFxuXCIgK1xyXG4gIFwiICAgICAgICAgICAgfVxcblwiICtcclxuICBcIiAgICAgICAgICAgIGNvcGllZCs9dG9Db3B5O1xcblwiICtcclxuICBcIiAgICAgICAgICAgIHRoaXMuY3VycmVudEF1ZGlvQnVmZmVyRnJhbWVQb3MrPXRvQ29weTtcXG5cIiArXHJcbiAgXCIgICAgICAgICAgICB0aGlzLmN1cnJlbnRBdWRpb0J1ZmZlckF2YWlsLT10b0NvcHk7XFxuXCIgK1xyXG4gIFwiXFxuXCIgK1xyXG4gIFwiICAgICAgICAgIH13aGlsZShjb3BpZWQ8b3V0Q2hMZW4pO1xcblwiICtcclxuICBcIiAgICAgICAgICB0aGlzLmZpbGxlZEZyYW1lcy09Y29waWVkO1xcblwiICtcclxuICBcIiAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXFxcIkNvcGllZCBcXFwiK2NvcGllZCtcXFwiIGZyYW1lcy5cXFwiKTtcXG5cIiArXHJcbiAgXCIgICAgICAgIH1cXG5cIiArXHJcbiAgXCIgICAgIHJldHVybiAhdGhpcy5lbmRlZDtcXG5cIiArXHJcbiAgXCIgIH1cXG5cIiArXHJcbiAgXCJ9XFxuXCIgK1xyXG4gIFwiXFxuXCIgK1xyXG4gIFwicmVnaXN0ZXJQcm9jZXNzb3IoJ2F1ZGlvLXNvdXJjZS13b3JrbGV0JyxBdWRpb1NvdXJjZVByb2Nlc3Nvcik7XFxuXCI7XHJcblxyXG5cclxuZXhwb3J0IGNsYXNzIEFycmF5QXVkaW9CdWZmZXJTb3VyY2VOb2RlIGV4dGVuZHMgQXVkaW9Xb3JrbGV0Tm9kZSB7XHJcblxyXG4gIHN0YXRpYyByZWFkb25seSBRVUFOVFVNX0ZSQU1FX0xFTiA9IDEyODtcclxuICBzdGF0aWMgcmVhZG9ubHkgREVGQVVMVF9CVUZGRVJfRklMTF9TRUNPTkRTID0gMTA7XHJcbiAgcHJpdmF0ZSBfYnVmZmVyRmlsbFNlY29uZHMgPSBBcnJheUF1ZGlvQnVmZmVyU291cmNlTm9kZS5ERUZBVUxUX0JVRkZFUl9GSUxMX1NFQ09ORFM7XHJcbiAgcHJpdmF0ZSBidWZmZXJGaWxsRnJhbWVzID0gMDtcclxuICBwcml2YXRlIF9hcnJheUF1ZGlvQnVmZmVyOiBBcnJheUF1ZGlvQnVmZmVyIHwgbnVsbCA9IG51bGw7XHJcbiAgcHJpdmF0ZSBfYXVkaW9JbnB1dFN0cmVhbTpGbG9hdDMyQXJyYXlJbnB1dFN0cmVhbXxudWxsPW51bGw7XHJcbiAgcHJpdmF0ZSBfYWlzQnVmczpGbG9hdDMyQXJyYXlbXXxudWxsPW51bGw7XHJcblxyXG4gIHByaXZhdGUgZmlsbGVkRnJhbWVzID0gMDtcclxuICBvbmVuZGVkOiAoKCkgPT4gdm9pZCkgfCBudWxsID0gbnVsbDtcclxuXHJcbiAgY29uc3RydWN0b3IoY29udGV4dDogQXVkaW9Db250ZXh0KSB7XHJcblxyXG4gICAgc3VwZXIoY29udGV4dCwgJ2F1ZGlvLXNvdXJjZS13b3JrbGV0Jyk7XHJcbiAgICB0aGlzLmNoYW5uZWxDb3VudE1vZGUgPSAnZXhwbGljaXQnO1xyXG4gICAgdGhpcy5wb3J0Lm9ubWVzc2FnZSA9IChtc2dFdjogTWVzc2FnZUV2ZW50KSA9PiB7XHJcbiAgICAgIGlmIChtc2dFdi5kYXRhKSB7XHJcbiAgICAgICAgbGV0IGV2VHlwZSA9IG1zZ0V2LmRhdGEuZXZlbnRUeXBlO1xyXG4gICAgICAgIGlmIChldlR5cGUpIHtcclxuICAgICAgICAgIGlmICgnYnVmZmVyTm90aWZpY2F0aW9uJyA9PT0gZXZUeXBlKSB7XHJcbiAgICAgICAgICAgIHRoaXMuZmlsbGVkRnJhbWVzID0gbXNnRXYuZGF0YS5maWxsZWRGcmFtZXM7XHJcbiAgICAgICAgICAgIC8vY29uc29sZS5kZWJ1ZyhcIkJ1ZmZlciBub3RpZmljYXRpb246IGZpbGxlZCBmcmFtZXM6IFwiICsgdGhpcy5maWxsZWRGcmFtZXMpO1xyXG4gICAgICAgICAgICB0aGlzLmZpbGxCdWZmZXIoKTtcclxuICAgICAgICAgIH0gZWxzZSBpZiAoJ2VuZGVkJyA9PT0gZXZUeXBlKSB7XHJcbiAgICAgICAgICAgIGxldCBkcmFpblRpbWUgPSAwO1xyXG4gICAgICAgICAgICBpZiAodGhpcy5fYXJyYXlBdWRpb0J1ZmZlcj8uc2FtcGxlUmF0ZSkge1xyXG4gICAgICAgICAgICAgIGRyYWluVGltZSA9IEFycmF5QXVkaW9CdWZmZXJTb3VyY2VOb2RlLlFVQU5UVU1fRlJBTUVfTEVOIC8gdGhpcy5fYXJyYXlBdWRpb0J1ZmZlci5zYW1wbGVSYXRlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIC8vbGV0IGRzdEFueTphbnk9dGhpcy5jb250ZXh0LmRlc3RpbmF0aW9uO1xyXG4gICAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoJ0Rlc3RpbmF0aW9uIG5vZGUgdGFpbC10aW1lOiAnK2RzdEFueVsndGFpbC10aW1lJ10pO1xyXG4gICAgICAgICAgICB3aW5kb3cuc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgICAgICAgICAgdGhpcy5vbmVuZGVkPy5jYWxsKHRoaXMpO1xyXG4gICAgICAgICAgICB9LCBkcmFpblRpbWUgKiAxMDAwKTtcclxuXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGZpbGxCdWZmZXIoZnJhbWVPZmZzZXQ/Om51bWJlcikge1xyXG4gICAgaWYgKHRoaXMuX2FycmF5QXVkaW9CdWZmZXIgJiYgdGhpcy5fYXVkaW9JbnB1dFN0cmVhbSAmJiB0aGlzLl9haXNCdWZzKSB7XHJcbiAgICAgIGxldCBmaWxsZWQgPSB0aGlzLmZpbGxlZEZyYW1lcztcclxuICAgICAgbGV0IGJ1ZkxlbiA9IDA7XHJcblxyXG4gICAgICB3aGlsZShmaWxsZWQ8IHRoaXMuYnVmZmVyRmlsbEZyYW1lcykge1xyXG4gICAgICAgIGxldCByZWFkID0gdGhpcy5fYXVkaW9JbnB1dFN0cmVhbS5yZWFkKHRoaXMuX2Fpc0J1ZnMpO1xyXG4gICAgICAgIC8vY29uc29sZS5sb2coXCJBcnJheUF1ZGlvQnVmZmVyU291cmNlTm9kZTogcmVhZDogXCIrcmVhZClcclxuICAgICAgICBpZiAocmVhZCkge1xyXG4gICAgICAgICAgbGV0IHRyQnVmZmVycyA9IG5ldyBBcnJheTxhbnk+KHRoaXMuY2hhbm5lbENvdW50KTtcclxuICAgICAgICAgIGZvciAobGV0IGNoID0gMDsgY2ggPCB0aGlzLmNoYW5uZWxDb3VudDsgY2grKykge1xyXG4gICAgICAgICAgICBsZXQgYWRDaCA9IHRoaXMuX2Fpc0J1ZnNbY2hdO1xyXG4gICAgICAgICAgICBsZXQgYWRDaENvcHkgPSBuZXcgRmxvYXQzMkFycmF5KGFkQ2gubGVuZ3RoKTtcclxuICAgICAgICAgICAgYnVmTGVuID0gYWRDaENvcHkubGVuZ3RoO1xyXG4gICAgICAgICAgICBhZENoQ29weS5zZXQoYWRDaCk7XHJcbiAgICAgICAgICAgIHRyQnVmZmVyc1tjaF0gPSBhZENoQ29weS5idWZmZXI7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICB0aGlzLnBvcnQucG9zdE1lc3NhZ2Uoe1xyXG4gICAgICAgICAgICBjbWQ6ICdkYXRhJyxcclxuICAgICAgICAgICAgY2hzOiB0aGlzLmNoYW5uZWxDb3VudCxcclxuICAgICAgICAgICAgYXVkaW9EYXRhOiB0ckJ1ZmZlcnNcclxuICAgICAgICAgIH0sIHRyQnVmZmVycyk7XHJcbiAgICAgICAgICBmaWxsZWQrPXJlYWQ7XHJcbiAgICAgICAgfWVsc2V7XHJcbiAgICAgICAgICBicmVhaztcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBnZXQgYXJyYXlBdWRpb0J1ZmZlcigpOiBBcnJheUF1ZGlvQnVmZmVyIHwgbnVsbCB7XHJcbiAgICByZXR1cm4gdGhpcy5fYXJyYXlBdWRpb0J1ZmZlcjtcclxuICB9XHJcblxyXG4gIHNldCBhcnJheUF1ZGlvQnVmZmVyKHZhbHVlOiBBcnJheUF1ZGlvQnVmZmVyIHwgbnVsbCkge1xyXG4gICAgdGhpcy5fYXJyYXlBdWRpb0J1ZmZlciA9IHZhbHVlO1xyXG4gICAgaWYgKHRoaXMuX2FycmF5QXVkaW9CdWZmZXI/LmNoYW5uZWxDb3VudCkge1xyXG4gICAgICB0aGlzLmNoYW5uZWxDb3VudCA9IHRoaXMuX2FycmF5QXVkaW9CdWZmZXI/LmNoYW5uZWxDb3VudDtcclxuICAgICAgdGhpcy5idWZmZXJGaWxsRnJhbWVzID0gdGhpcy5fYXJyYXlBdWRpb0J1ZmZlci5zYW1wbGVSYXRlICogdGhpcy5fYnVmZmVyRmlsbFNlY29uZHM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBnZXQgYnVmZmVyRmlsbFNlY29uZHMoKTogbnVtYmVyIHtcclxuICAgIHJldHVybiB0aGlzLl9idWZmZXJGaWxsU2Vjb25kcztcclxuICB9XHJcblxyXG4gIHNldCBidWZmZXJGaWxsU2Vjb25kcyh2YWx1ZTogbnVtYmVyKSB7XHJcbiAgICB0aGlzLl9idWZmZXJGaWxsU2Vjb25kcyA9IHZhbHVlO1xyXG4gIH1cclxuXHJcbiAgc3RhcnQod2hlbj86IG51bWJlciB8IHVuZGVmaW5lZCxvZmZzZXQ/OiBudW1iZXIgfCB1bmRlZmluZWQsZHVyYXRpb24/OiBudW1iZXIgfCB1bmRlZmluZWQpOiB2b2lkIHtcclxuICAgIGlmICh3aGVuKSB7XHJcbiAgICAgIHRocm93IEVycm9yKFwid2hlbiwgb2ZmZXN0LGR1cmF0aW9uIHBhcmFtZXRlcnMgY3VycmVudGx5IG5vdCBzdXBwb3J0ZWQgYnkgQXJyYXlBdWRpb0J1ZmZlclNvdXJjZU5vZGUgY2xhc3NcIilcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5fYXJyYXlBdWRpb0J1ZmZlcikge1xyXG4gICAgICBsZXQgYXJyQWlzPW5ldyBBcnJheUF1ZGlvQnVmZmVySW5wdXRTdHJlYW0odGhpcy5fYXJyYXlBdWRpb0J1ZmZlcik7XHJcbiAgICAgIGlmKG9mZnNldD09PXVuZGVmaW5lZCAmJiBkdXJhdGlvbj09PXVuZGVmaW5lZCl7XHJcbiAgICAgICAgdGhpcy5fYXVkaW9JbnB1dFN0cmVhbSA9IGFyckFpcztcclxuICAgICAgfWVsc2V7XHJcbiAgICAgICAgbGV0IG9mZnNldEZyYW1lcz0wO1xyXG4gICAgICAgIGxldCBkdXJhdGlvbkZyYW1lcz11bmRlZmluZWQ7XHJcbiAgICAgICAgaWYob2Zmc2V0IT09dW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICBvZmZzZXRGcmFtZXM9TWF0aC5mbG9vcihvZmZzZXQgKiB0aGlzLl9hcnJheUF1ZGlvQnVmZmVyLnNhbXBsZVJhdGUpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZihkdXJhdGlvbiE9PXVuZGVmaW5lZCl7XHJcbiAgICAgICAgICBkdXJhdGlvbkZyYW1lcz1NYXRoLmZsb29yKGR1cmF0aW9uICogdGhpcy5fYXJyYXlBdWRpb0J1ZmZlci5zYW1wbGVSYXRlKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy5fYXVkaW9JbnB1dFN0cmVhbT1uZXcgRWRpdEZsb2F0MzJBcnJheUlucHV0U3RyZWFtKGFyckFpcyxvZmZzZXRGcmFtZXMsZHVyYXRpb25GcmFtZXMpO1xyXG4gICAgICB9XHJcblxyXG4gICAgbGV0IGNocz10aGlzLl9hcnJheUF1ZGlvQnVmZmVyLmNoYW5uZWxDb3VudDtcclxuICAgIHRoaXMuX2Fpc0J1ZnM9bmV3IEFycmF5PEZsb2F0MzJBcnJheT4oY2hzKTtcclxuICAgIGZvcihsZXQgY2g9MDtjaDxjaHM7Y2grKyl7XHJcbiAgICAgIHRoaXMuX2Fpc0J1ZnNbY2hdPW5ldyBGbG9hdDMyQXJyYXkoMTAyNCk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5maWxsQnVmZmVyKCk7XHJcbiAgICB0aGlzLnBvcnQucG9zdE1lc3NhZ2Uoe2NtZDogJ3N0YXJ0J30pO1xyXG4gIH1cclxuICB9XHJcblxyXG4gIHN0b3AoKSB7XHJcbiAgICB0aGlzLnBvcnQucG9zdE1lc3NhZ2Uoe2NtZDogJ3N0b3AnfSk7XHJcbiAgICB0aGlzLm9uZW5kZWQ/LmNhbGwodGhpcyk7XHJcbiAgfVxyXG5cclxufVxyXG5cclxuZXhwb3J0IGNsYXNzIEF1ZGlvU291cmNlV29ya2xldE1vZHVsZUxvYWRlcntcclxuICBwcml2YXRlIHN0YXRpYyBtb2R1bGVMb2FkZWQ9ZmFsc2U7XHJcbiAgc3RhdGljIGxvYWRNb2R1bGUoY29udGV4dDogQXVkaW9Db250ZXh0KTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgICBpZiAoQXVkaW9Tb3VyY2VXb3JrbGV0TW9kdWxlTG9hZGVyLm1vZHVsZUxvYWRlZCkge1xyXG4gICAgICAgIHJlc29sdmUuY2FsbChzZWxmKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsZXQgYXVkaW9Xb3JrbGV0TW9kdWxlQmxvYiA9IG5ldyBCbG9iKFthc3dwU3RyXSwge3R5cGU6ICd0ZXh0L2phdmFzY3JpcHQnfSk7XHJcbiAgICAgICAgbGV0IGF1ZGlvV29ya2xldE1vZHVsZUJsb2JVcmwgPSB3aW5kb3cuVVJMLmNyZWF0ZU9iamVjdFVSTChhdWRpb1dvcmtsZXRNb2R1bGVCbG9iKTtcclxuICAgICAgICBjb250ZXh0LnJlc3VtZSgpO1xyXG4gICAgICAgIGNvbnRleHQuYXVkaW9Xb3JrbGV0LmFkZE1vZHVsZShhdWRpb1dvcmtsZXRNb2R1bGVCbG9iVXJsKS50aGVuKCgpID0+IHtcclxuICAgICAgICAgIEF1ZGlvU291cmNlV29ya2xldE1vZHVsZUxvYWRlci5tb2R1bGVMb2FkZWQgPSB0cnVlO1xyXG4gICAgICAgICAgcmVzb2x2ZS5jYWxsKHNlbGYpO1xyXG4gICAgICAgIH0pLmNhdGNoKChyZWFzb24pID0+IHtcclxuICAgICAgICAgIGNvbnNvbGUuZXJyb3IocmVhc29uKTtcclxuICAgICAgICAgIHJlamVjdC5jYWxsKHJlYXNvbik7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH1cclxufVxyXG4iXX0=
|