genassist-chat-react 1.0.38 → 1.0.39

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.
@@ -0,0 +1,32 @@
1
+ export type LiveVoiceStatus = 'idle' | 'connecting' | 'listening' | 'speaking' | 'error';
2
+ interface UseLiveVoiceOptions {
3
+ baseUrl: string;
4
+ apiKey: string;
5
+ guestToken?: string | null;
6
+ tenant?: string;
7
+ agentId?: string | null;
8
+ conversationId?: string | null;
9
+ language?: string;
10
+ onError?: (error: Error) => void;
11
+ onInputTranscript?: (text: string) => void;
12
+ onOutputTranscript?: (text: string) => void;
13
+ onTurnComplete?: (turn: {
14
+ transcript: string;
15
+ response: string;
16
+ }) => void;
17
+ }
18
+ interface UseLiveVoiceReturn {
19
+ isActive: boolean;
20
+ status: LiveVoiceStatus;
21
+ start: () => Promise<void>;
22
+ stop: () => void;
23
+ }
24
+ /**
25
+ * Continuous, two-way voice conversation with a Voice Agent node.
26
+ *
27
+ * Streams 16 kHz mic PCM up a WebSocket to a persistent Gemini Live session and
28
+ * plays the 24 kHz reply audio back as it arrives (no record/stop/send). Supports
29
+ * barge-in: when the agent is interrupted, queued playback is flushed instantly.
30
+ */
31
+ export declare function useLiveVoice(opts: UseLiveVoiceOptions): UseLiveVoiceReturn;
32
+ export {};
@@ -0,0 +1,292 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __generator = (this && this.__generator) || function (thisArg, body) {
11
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
12
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
+ function verb(n) { return function (v) { return step([n, v]); }; }
14
+ function step(op) {
15
+ if (f) throw new TypeError("Generator is already executing.");
16
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
+ if (y = 0, t) op = [op[0] & 2, t.value];
19
+ switch (op[0]) {
20
+ case 0: case 1: t = op; break;
21
+ case 4: _.label++; return { value: op[1], done: false };
22
+ case 5: _.label++; y = op[1]; op = [0]; continue;
23
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
+ default:
25
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
+ if (t[2]) _.ops.pop();
30
+ _.trys.pop(); continue;
31
+ }
32
+ op = body.call(thisArg, _);
33
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
+ }
36
+ };
37
+ import { useCallback, useEffect, useRef, useState } from 'react';
38
+ import { createWebSocket } from '../utils/websocket';
39
+ var LIVE_INPUT_SAMPLE_RATE = 16000; // Gemini Live expects 16 kHz mono PCM in
40
+ var LIVE_OUTPUT_SAMPLE_RATE = 24000; // Gemini Live emits 24 kHz mono PCM out
41
+ var CAPTURE_BUFFER_SIZE = 4096;
42
+ /** Downsample a mono Float32 buffer to 16 kHz Int16 PCM (little-endian). */
43
+ function floatTo16kPcm(input, inputRate) {
44
+ var ratio = inputRate / LIVE_INPUT_SAMPLE_RATE;
45
+ var outLength = Math.floor(input.length / ratio);
46
+ var out = new Int16Array(outLength);
47
+ for (var i = 0; i < outLength; i++) {
48
+ var sample = input[Math.floor(i * ratio)] || 0;
49
+ var clamped = Math.max(-1, Math.min(1, sample));
50
+ out[i] = clamped < 0 ? clamped * 0x8000 : clamped * 0x7fff;
51
+ }
52
+ return out.buffer;
53
+ }
54
+ function buildLiveUrl(opts, threadId) {
55
+ // Live voice is a stateful 1:1 audio stream held by the backend, so the plugin
56
+ // connects directly to the backend (not the fan-out websocket service).
57
+ var wsBase = opts.baseUrl.replace(/^http/, 'ws').replace(/\/$/, '');
58
+ var auth = opts.guestToken
59
+ ? "access_token=".concat(encodeURIComponent(opts.guestToken))
60
+ : "api_key=".concat(encodeURIComponent(opts.apiKey));
61
+ var params = [auth, "thread_id=".concat(encodeURIComponent(threadId))];
62
+ if (opts.tenant)
63
+ params.push("x-tenant-id=".concat(encodeURIComponent(opts.tenant)));
64
+ if (opts.language)
65
+ params.push("lang=".concat(encodeURIComponent(opts.language)));
66
+ return "".concat(wsBase, "/api/voice/live/").concat(opts.agentId, "?").concat(params.join('&'));
67
+ }
68
+ /**
69
+ * Continuous, two-way voice conversation with a Voice Agent node.
70
+ *
71
+ * Streams 16 kHz mic PCM up a WebSocket to a persistent Gemini Live session and
72
+ * plays the 24 kHz reply audio back as it arrives (no record/stop/send). Supports
73
+ * barge-in: when the agent is interrupted, queued playback is flushed instantly.
74
+ */
75
+ export function useLiveVoice(opts) {
76
+ var _this = this;
77
+ var _a = useState(false), isActive = _a[0], setIsActive = _a[1];
78
+ var _b = useState('idle'), status = _b[0], setStatus = _b[1];
79
+ var wsRef = useRef(null);
80
+ var streamRef = useRef(null);
81
+ var captureCtxRef = useRef(null);
82
+ var processorRef = useRef(null);
83
+ var playbackCtxRef = useRef(null);
84
+ var playheadRef = useRef(0);
85
+ var sourcesRef = useRef([]);
86
+ var speakingTimerRef = useRef(null);
87
+ // Mirror `isActive` into a ref so async callbacks (e.g. the speaking timer)
88
+ // can read the latest value without being re-created.
89
+ var isActiveRef = useRef(false);
90
+ isActiveRef.current = isActive;
91
+ // Keep the latest callbacks without re-creating start/stop.
92
+ var optsRef = useRef(opts);
93
+ optsRef.current = opts;
94
+ var flushPlayback = useCallback(function () {
95
+ sourcesRef.current.forEach(function (src) {
96
+ try {
97
+ src.stop();
98
+ }
99
+ catch (_a) {
100
+ /* already stopped */
101
+ }
102
+ });
103
+ sourcesRef.current = [];
104
+ if (playbackCtxRef.current) {
105
+ playheadRef.current = playbackCtxRef.current.currentTime;
106
+ }
107
+ }, []);
108
+ var stop = useCallback(function () {
109
+ var _a, _b, _c, _d;
110
+ if (speakingTimerRef.current)
111
+ clearTimeout(speakingTimerRef.current);
112
+ flushPlayback();
113
+ (_a = processorRef.current) === null || _a === void 0 ? void 0 : _a.disconnect();
114
+ processorRef.current = null;
115
+ (_b = streamRef.current) === null || _b === void 0 ? void 0 : _b.getTracks().forEach(function (t) { return t.stop(); });
116
+ streamRef.current = null;
117
+ (_c = captureCtxRef.current) === null || _c === void 0 ? void 0 : _c.close().catch(function () { return undefined; });
118
+ captureCtxRef.current = null;
119
+ (_d = playbackCtxRef.current) === null || _d === void 0 ? void 0 : _d.close().catch(function () { return undefined; });
120
+ playbackCtxRef.current = null;
121
+ if (wsRef.current) {
122
+ wsRef.current.onclose = null;
123
+ try {
124
+ wsRef.current.close();
125
+ }
126
+ catch (_e) {
127
+ /* noop */
128
+ }
129
+ wsRef.current = null;
130
+ }
131
+ setIsActive(false);
132
+ setStatus('idle');
133
+ }, [flushPlayback]);
134
+ var playPcmChunk = useCallback(function (pcm) {
135
+ var ctx = playbackCtxRef.current;
136
+ if (!ctx)
137
+ return;
138
+ var ints = new Int16Array(pcm);
139
+ if (ints.length === 0)
140
+ return;
141
+ var floats = new Float32Array(ints.length);
142
+ for (var i = 0; i < ints.length; i++)
143
+ floats[i] = ints[i] / 0x8000;
144
+ var buffer = ctx.createBuffer(1, floats.length, LIVE_OUTPUT_SAMPLE_RATE);
145
+ buffer.copyToChannel(floats, 0);
146
+ var source = ctx.createBufferSource();
147
+ source.buffer = buffer;
148
+ source.connect(ctx.destination);
149
+ var startAt = Math.max(ctx.currentTime, playheadRef.current);
150
+ source.start(startAt);
151
+ playheadRef.current = startAt + buffer.duration;
152
+ sourcesRef.current.push(source);
153
+ source.onended = function () {
154
+ sourcesRef.current = sourcesRef.current.filter(function (s) { return s !== source; });
155
+ };
156
+ // Reflect "speaking" until the scheduled audio drains.
157
+ setStatus('speaking');
158
+ if (speakingTimerRef.current)
159
+ clearTimeout(speakingTimerRef.current);
160
+ var remainingMs = (playheadRef.current - ctx.currentTime) * 1000 + 150;
161
+ speakingTimerRef.current = setTimeout(function () {
162
+ if (isActiveRef.current)
163
+ setStatus('listening');
164
+ }, remainingMs);
165
+ }, []);
166
+ var handleEvent = useCallback(function (data) {
167
+ var _a, _b, _c, _d, _e, _f, _g;
168
+ var cb = optsRef.current;
169
+ switch (data.type) {
170
+ case 'ready':
171
+ setStatus('listening');
172
+ break;
173
+ case 'input_transcript':
174
+ if (typeof data.text === 'string')
175
+ (_a = cb.onInputTranscript) === null || _a === void 0 ? void 0 : _a.call(cb, data.text);
176
+ break;
177
+ case 'output_transcript':
178
+ if (typeof data.text === 'string')
179
+ (_b = cb.onOutputTranscript) === null || _b === void 0 ? void 0 : _b.call(cb, data.text);
180
+ break;
181
+ case 'interrupted':
182
+ flushPlayback();
183
+ setStatus('listening');
184
+ break;
185
+ case 'turn_complete':
186
+ (_c = cb.onTurnComplete) === null || _c === void 0 ? void 0 : _c.call(cb, {
187
+ transcript: String((_d = data.transcript) !== null && _d !== void 0 ? _d : ''),
188
+ response: String((_e = data.response) !== null && _e !== void 0 ? _e : ''),
189
+ });
190
+ break;
191
+ case 'error':
192
+ (_f = cb.onError) === null || _f === void 0 ? void 0 : _f.call(cb, new Error(String((_g = data.message) !== null && _g !== void 0 ? _g : 'Live voice error')));
193
+ setStatus('error');
194
+ break;
195
+ default:
196
+ break;
197
+ }
198
+ }, [flushPlayback]);
199
+ var start = useCallback(function () { return __awaiter(_this, void 0, void 0, function () {
200
+ var cb, threadId, stream_1, AudioCtx, captureCtx_1, ws_1, err_1;
201
+ var _a, _b;
202
+ return __generator(this, function (_c) {
203
+ switch (_c.label) {
204
+ case 0:
205
+ cb = optsRef.current;
206
+ if (!cb.agentId) {
207
+ (_a = cb.onError) === null || _a === void 0 ? void 0 : _a.call(cb, new Error('Live voice unavailable: agent is still loading'));
208
+ return [2 /*return*/];
209
+ }
210
+ if (wsRef.current)
211
+ return [2 /*return*/]; // already active
212
+ setStatus('connecting');
213
+ // Persistence (transcript/dashboard) keys off an existing conversation UUID.
214
+ // Without one the call still works, but the backend skips saving the turns.
215
+ if (!cb.conversationId) {
216
+ console.warn('[useLiveVoice] No conversationId yet — the live call will run but its ' +
217
+ 'transcripts will not be persisted.');
218
+ }
219
+ threadId = cb.conversationId ||
220
+ (typeof crypto !== 'undefined' && 'randomUUID' in crypto
221
+ ? crypto.randomUUID()
222
+ : "live-".concat(Date.now()));
223
+ _c.label = 1;
224
+ case 1:
225
+ _c.trys.push([1, 3, , 4]);
226
+ return [4 /*yield*/, navigator.mediaDevices.getUserMedia({
227
+ audio: { channelCount: 1, echoCancellation: true, noiseSuppression: true },
228
+ })];
229
+ case 2:
230
+ stream_1 = _c.sent();
231
+ streamRef.current = stream_1;
232
+ AudioCtx = window.AudioContext ||
233
+ window.webkitAudioContext;
234
+ captureCtx_1 = new AudioCtx();
235
+ captureCtxRef.current = captureCtx_1;
236
+ playbackCtxRef.current = new AudioCtx();
237
+ playheadRef.current = playbackCtxRef.current.currentTime;
238
+ ws_1 = createWebSocket(buildLiveUrl(cb, threadId));
239
+ ws_1.binaryType = 'arraybuffer';
240
+ wsRef.current = ws_1;
241
+ ws_1.onopen = function () {
242
+ var source = captureCtx_1.createMediaStreamSource(stream_1);
243
+ // TODO: migrate to AudioWorklet — ScriptProcessorNode is deprecated and
244
+ // runs the downsample on the main thread (can jank on slow devices).
245
+ var processor = captureCtx_1.createScriptProcessor(CAPTURE_BUFFER_SIZE, 1, 1);
246
+ processorRef.current = processor;
247
+ processor.onaudioprocess = function (e) {
248
+ if (ws_1.readyState !== ws_1.OPEN)
249
+ return;
250
+ var pcm = floatTo16kPcm(e.inputBuffer.getChannelData(0), captureCtx_1.sampleRate);
251
+ ws_1.send(pcm);
252
+ };
253
+ source.connect(processor);
254
+ processor.connect(captureCtx_1.destination); // required to drive onaudioprocess
255
+ setIsActive(true);
256
+ setStatus('listening');
257
+ };
258
+ ws_1.onmessage = function (event) {
259
+ if (event.data instanceof ArrayBuffer) {
260
+ playPcmChunk(event.data);
261
+ }
262
+ else if (typeof event.data === 'string') {
263
+ try {
264
+ handleEvent(JSON.parse(event.data));
265
+ }
266
+ catch (_a) {
267
+ /* ignore malformed event */
268
+ }
269
+ }
270
+ };
271
+ ws_1.onerror = function () {
272
+ var _a;
273
+ (_a = cb.onError) === null || _a === void 0 ? void 0 : _a.call(cb, new Error('Live voice connection error'));
274
+ };
275
+ ws_1.onclose = function () {
276
+ stop();
277
+ };
278
+ return [3 /*break*/, 4];
279
+ case 3:
280
+ err_1 = _c.sent();
281
+ (_b = cb.onError) === null || _b === void 0 ? void 0 : _b.call(cb, err_1 instanceof Error ? err_1 : new Error(String(err_1)));
282
+ stop();
283
+ return [3 /*break*/, 4];
284
+ case 4: return [2 /*return*/];
285
+ }
286
+ });
287
+ }); }, [handleEvent, playPcmChunk, stop]);
288
+ // Tear down on unmount.
289
+ useEffect(function () { return function () { return stop(); }; }, [stop]);
290
+ return { isActive: isActive, status: status, start: start, stop: stop };
291
+ }
292
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlTGl2ZVZvaWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2hvb2tzL3VzZUxpdmVWb2ljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sT0FBTyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUVyRCxJQUFNLHNCQUFzQixHQUFHLEtBQUssQ0FBQyxDQUFDLHlDQUF5QztBQUMvRSxJQUFNLHVCQUF1QixHQUFHLEtBQUssQ0FBQyxDQUFDLHdDQUF3QztBQUMvRSxJQUFNLG1CQUFtQixHQUFHLElBQUksQ0FBQztBQWlDakMsNEVBQTRFO0FBQzVFLFNBQVMsYUFBYSxDQUFDLEtBQW1CLEVBQUUsU0FBaUI7SUFDM0QsSUFBTSxLQUFLLEdBQUcsU0FBUyxHQUFHLHNCQUFzQixDQUFDO0lBQ2pELElBQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsQ0FBQztJQUNuRCxJQUFNLEdBQUcsR0FBRyxJQUFJLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN0QyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDbkMsSUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2pELElBQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUNsRCxHQUFH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T0FBQSxFQUFFLElBQUksTUFBQSxFQUFFLENBQUM7QUFDM0MsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHVzZUNhbGxiYWNrLCB1c2VFZmZlY3QsIHVzZVJlZiwgdXNlU3RhdGUgfSBmcm9tICdyZWFjdCc7XG5pbXBvcnQgeyBjcmVhdGVXZWJTb2NrZXQgfSBmcm9tICcuLi91dGlscy93ZWJzb2NrZXQnO1xuXG5jb25zdCBMSVZFX0lOUFVUX1NBTVBMRV9SQVRFID0gMTYwMDA7IC8vIEdlbWluaSBMaXZlIGV4cGVjdHMgMTYga0h6IG1vbm8gUENNIGluXG5jb25zdCBMSVZFX09VVFBVVF9TQU1QTEVfUkFURSA9IDI0MDAwOyAvLyBHZW1pbmkgTGl2ZSBlbWl0cyAyNCBrSHogbW9ubyBQQ00gb3V0XG5jb25zdCBDQVBUVVJFX0JVRkZFUl9TSVpFID0gNDA5NjtcblxuZXhwb3J0IHR5cGUgTGl2ZVZvaWNlU3RhdHVzID1cbiAgfCAnaWRsZSdcbiAgfCAnY29ubmVjdGluZydcbiAgfCAnbGlzdGVuaW5nJ1xuICB8ICdzcGVha2luZydcbiAgfCAnZXJyb3InO1xuXG5pbnRlcmZhY2UgVXNlTGl2ZVZvaWNlT3B0aW9ucyB7XG4gIC8vIEJhY2tlbmQgYmFzZSBVUkwgKGh0dHAvaHR0cHMpLiBMaXZlIHZvaWNlIGlzIGEgc3RhdGVmdWwgMToxIGF1ZGlvIHN0cmVhbVxuICAvLyBoZWxkIGJ5IHRoZSBiYWNrZW5kLCBzbyB0aGUgcGx1Z2luIGNvbm5lY3RzIHRoZXJlIGRpcmVjdGx5ICh0aGUgZmFuLW91dFxuICAvLyB3ZWJzb2NrZXQgc2VydmljZSBpcyBub3QgaW52b2x2ZWQpLlxuICBiYXNlVXJsOiBzdHJpbmc7XG4gIGFwaUtleTogc3RyaW5nO1xuICBndWVzdFRva2VuPzogc3RyaW5nIHwgbnVsbDtcbiAgdGVuYW50Pzogc3RyaW5nO1xuICBhZ2VudElkPzogc3RyaW5nIHwgbnVsbDtcbiAgY29udmVyc2F0aW9uSWQ/OiBzdHJpbmcgfCBudWxsO1xuICBsYW5ndWFnZT86IHN0cmluZztcbiAgb25FcnJvcj86IChlcnJvcjogRXJyb3IpID0+IHZvaWQ7XG4gIG9uSW5wdXRUcmFuc2NyaXB0PzogKHRleHQ6IHN0cmluZykgPT4gdm9pZDtcbiAgb25PdXRwdXRUcmFuc2NyaXB0PzogKHRleHQ6IHN0cmluZykgPT4gdm9pZDtcbiAgb25UdXJuQ29tcGxldGU/OiAodHVybjogeyB0cmFuc2NyaXB0OiBzdHJpbmc7IHJlc3BvbnNlOiBzdHJpbmcgfSkgPT4gdm9pZDtcbn1cblxuaW50ZXJmYWNlIFVzZUxpdmVWb2ljZVJldHVybiB7XG4gIGlzQWN0aXZlOiBib29sZWFuO1xuICBzdGF0dXM6IExpdmVWb2ljZVN0YXR1cztcbiAgc3RhcnQ6ICgpID0+IFByb21pc2U8dm9pZD47XG4gIHN0b3A6ICgpID0+IHZvaWQ7XG59XG5cbi8qKiBEb3duc2FtcGxlIGEgbW9ubyBGbG9hdDMyIGJ1ZmZlciB0byAxNiBrSHogSW50MTYgUENNIChsaXR0bGUtZW5kaWFuKS4gKi9cbmZ1bmN0aW9uIGZsb2F0VG8xNmtQY20oaW5wdXQ6IEZsb2F0MzJBcnJheSwgaW5wdXRSYXRlOiBudW1iZXIpOiBBcnJheUJ1ZmZlciB7XG4gIGNvbnN0IHJhdGlvID0gaW5wdXRSYXRlIC8gTElWRV9JTlBVVF9TQU1QTEVfUkFURTtcbiAgY29uc3Qgb3V0TGVuZ3RoID0gTWF0aC5mbG9vcihpbnB1dC5sZW5ndGggLyByYXRpbyk7XG4gIGNvbnN0IG91dCA9IG5ldyBJbnQxNkFycmF5KG91dExlbmd0aCk7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgb3V0TGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBzYW1wbGUgPSBpbnB1dFtNYXRoLmZsb29yKGkgKiByYXRpbyldIHx8IDA7XG4gICAgY29uc3QgY2xhbXBlZCA9IE1hdGgubWF4KC0xLCBNYXRoLm1pbigxLCBzYW1wbGUpKTtcbiAgICBvdXRbaV0gPSBjbGFtcGVkIDwgMCA/IGNsYW1wZWQgKiAweDgwMDAgOiBjbGFtcGVkICogMHg3ZmZmO1xuICB9XG4gIHJldHVybiBvdXQuYnVmZmVyO1xufVxuXG5mdW5jdGlvbiBidWlsZExpdmVVcmwob3B0czogVXNlTGl2ZVZvaWNlT3B0aW9ucywgdGhyZWFkSWQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIC8vIExpdmUgdm9pY2UgaXMgYSBzdGF0ZWZ1bCAxOjEgYXVkaW8gc3RyZWFtIGhlbGQgYnkgdGhlIGJhY2tlbmQsIHNvIHRoZSBwbHVnaW5cbiAgLy8gY29ubmVjdHMgZGlyZWN0bHkgdG8gdGhlIGJhY2tlbmQgKG5vdCB0aGUgZmFuLW91dCB3ZWJzb2NrZXQgc2VydmljZSkuXG4gIGNvbnN0IHdzQmFzZSA9IG9wdHMuYmFzZVVybC5yZXBsYWNlKC9eaHR0cC8sICd3cycpLnJlcGxhY2UoL1xcLyQvLCAnJyk7XG4gIGNvbnN0IGF1dGggPSBvcHRzLmd1ZXN0VG9rZW5cbiAgICA/IGBhY2Nlc3NfdG9rZW49JHtlbmNvZGVVUklDb21wb25lbnQob3B0cy5ndWVzdFRva2VuKX1gXG4gICAgOiBgYXBpX2tleT0ke2VuY29kZVVSSUNvbXBvbmVudChvcHRzLmFwaUtleSl9YDtcbiAgY29uc3QgcGFyYW1zID0gW2F1dGgsIGB0aHJlYWRfaWQ9JHtlbmNvZGVVUklDb21wb25lbnQodGhyZWFkSWQpfWBdO1xuICBpZiAob3B0cy50ZW5hbnQpIHBhcmFtcy5wdXNoKGB4LXRlbmFudC1pZD0ke2VuY29kZVVSSUNvbXBvbmVudChvcHRzLnRlbmFudCl9YCk7XG4gIGlmIChvcHRzLmxhbmd1YWdlKSBwYXJhbXMucHVzaChgbGFuZz0ke2VuY29kZVVSSUNvbXBvbmVudChvcHRzLmxhbmd1YWdlKX1gKTtcbiAgcmV0dXJuIGAke3dzQmFzZX0vYXBpL3ZvaWNlL2xpdmUvJHtvcHRzLmFnZW50SWR9PyR7cGFyYW1zLmpvaW4oJyYnKX1gO1xufVxuXG4vKipcbiAqIENvbnRpbnVvdXMsIHR3by13YXkgdm9pY2UgY29udmVyc2F0aW9uIHdpdGggYSBWb2ljZSBBZ2VudCBub2RlLlxuICpcbiAqIFN0cmVhbXMgMTYga0h6IG1pYyBQQ00gdXAgYSBXZWJTb2NrZXQgdG8gYSBwZXJzaXN0ZW50IEdlbWluaSBMaXZlIHNlc3Npb24gYW5kXG4gKiBwbGF5cyB0aGUgMjQga0h6IHJlcGx5IGF1ZGlvIGJhY2sgYXMgaXQgYXJyaXZlcyAobm8gcmVjb3JkL3N0b3Avc2VuZCkuIFN1cHBvcnRzXG4gKiBiYXJnZS1pbjogd2hlbiB0aGUgYWdlbnQgaXMgaW50ZXJydXB0ZWQsIHF1ZXVlZCBwbGF5YmFjayBpcyBmbHVzaGVkIGluc3RhbnRseS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVzZUxpdmVWb2ljZShvcHRzOiBVc2VMaXZlVm9pY2VPcHRpb25zKTogVXNlTGl2ZVZvaWNlUmV0dXJuIHtcbiAgY29uc3QgW2lzQWN0aXZlLCBzZXRJc0FjdGl2ZV0gPSB1c2VTdGF0ZShmYWxzZSk7XG4gIGNvbnN0IFtzdGF0dXMsIHNldFN0YXR1c10gPSB1c2VTdGF0ZTxMaXZlVm9pY2VTdGF0dXM+KCdpZGxlJyk7XG5cbiAgY29uc3Qgd3NSZWYgPSB1c2VSZWY8V2ViU29ja2V0IHwgbnVsbD4obnVsbCk7XG4gIGNvbnN0IHN0cmVhbVJlZiA9IHVzZVJlZjxNZWRpYVN0cmVhbSB8IG51bGw+KG51bGwpO1xuICBjb25zdCBjYXB0dXJlQ3R4UmVmID0gdXNlUmVmPEF1ZGlvQ29udGV4dCB8IG51bGw+KG51bGwpO1xuICBjb25zdCBwcm9jZXNzb3JSZWYgPSB1c2VSZWY8U2NyaXB0UHJvY2Vzc29yTm9kZSB8IG51bGw+KG51bGwpO1xuICBjb25zdCBwbGF5YmFja0N0eFJlZiA9IHVzZVJlZjxBdWRpb0NvbnRleHQgfCBudWxsPihudWxsKTtcbiAgY29uc3QgcGxheWhlYWRSZWYgPSB1c2VSZWY8bnVtYmVyPigwKTtcbiAgY29uc3Qgc291cmNlc1JlZiA9IHVzZVJlZjxBdWRpb0J1ZmZlclNvdXJjZU5vZGVbXT4oW10pO1xuICBjb25zdCBzcGVha2luZ1RpbWVyUmVmID0gdXNlUmVmPFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgbnVsbD4obnVsbCk7XG5cbiAgLy8gTWlycm9yIGBpc0FjdGl2ZWAgaW50byBhIHJlZiBzbyBhc3luYyBjYWxsYmFja3MgKGUuZy4gdGhlIHNwZWFraW5nIHRpbWVyKVxuICAvLyBjYW4gcmVhZCB0aGUgbGF0ZXN0IHZhbHVlIHdpdGhvdXQgYmVpbmcgcmUtY3JlYXRlZC5cbiAgY29uc3QgaXNBY3RpdmVSZWYgPSB1c2VSZWYoZmFsc2UpO1xuICBpc0FjdGl2ZVJlZi5jdXJyZW50ID0gaXNBY3RpdmU7XG5cbiAgLy8gS2VlcCB0aGUgbGF0ZXN0IGNhbGxiYWNrcyB3aXRob3V0IHJlLWNyZWF0aW5nIHN0YXJ0L3N0b3AuXG4gIGNvbnN0IG9wdHNSZWYgPSB1c2VSZWYob3B0cyk7XG4gIG9wdHNSZWYuY3VycmVudCA9IG9wdHM7XG5cbiAgY29uc3QgZmx1c2hQbGF5YmFjayA9IHVzZUNhbGxiYWNrKCgpID0+IHtcbiAgICBzb3VyY2VzUmVmLmN1cnJlbnQuZm9yRWFjaCgoc3JjKSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICBzcmMuc3RvcCgpO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIC8qIGFscmVhZHkgc3RvcHBlZCAqL1xuICAgICAgfVxuICAgIH0pO1xuICAgIHNvdXJjZXNSZWYuY3VycmVudCA9IFtdO1xuICAgIGlmIChwbGF5YmFja0N0eFJlZi5jdXJyZW50KSB7XG4gICAgICBwbGF5aGVhZFJlZi5jdXJyZW50ID0gcGxheWJhY2tDdHhSZWYuY3VycmVudC5jdXJyZW50VGltZTtcbiAgICB9XG4gIH0sIFtdKTtcblxuICBjb25zdCBzdG9wID0gdXNlQ2FsbGJhY2soKCkgPT4ge1xuICAgIGlmIChzcGVha2luZ1RpbWVyUmVmLmN1cnJlbnQpIGNsZWFyVGltZW91dChzcGVha2luZ1RpbWVyUmVmLmN1cnJlbnQpO1xuICAgIGZsdXNoUGxheWJhY2soKTtcbiAgICBwcm9jZXNzb3JSZWYuY3VycmVudD8uZGlzY29ubmVjdCgpO1xuICAgIHByb2Nlc3NvclJlZi5jdXJyZW50ID0gbnVsbDtcbiAgICBzdHJlYW1SZWYuY3VycmVudD8uZ2V0VHJhY2tzKCkuZm9yRWFjaCgodCkgPT4gdC5zdG9wKCkpO1xuICAgIHN0cmVhbVJlZi5jdXJyZW50ID0gbnVsbDtcbiAgICBjYXB0dXJlQ3R4UmVmLmN1cnJlbnQ/LmNsb3NlKCkuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgICBjYXB0dXJlQ3R4UmVmLmN1cnJlbnQgPSBudWxsO1xuICAgIHBsYXliYWNrQ3R4UmVmLmN1cnJlbnQ/LmNsb3NlKCkuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgICBwbGF5YmFja0N0eFJlZi5jdXJyZW50ID0gbnVsbDtcbiAgICBpZiAod3NSZWYuY3VycmVudCkge1xuICAgICAgd3NSZWYuY3VycmVudC5vbmNsb3NlID0gbnVsbDtcbiAgICAgIHRyeSB7XG4gICAgICAgIHdzUmVmLmN1cnJlbnQuY2xvc2UoKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvKiBub29wICovXG4gICAgICB9XG4gICAgICB3c1JlZi5jdXJyZW50ID0gbnVsbDtcbiAgICB9XG4gICAgc2V0SXNBY3RpdmUoZmFsc2UpO1xuICAgIHNldFN0YXR1cygnaWRsZScpO1xuICB9LCBbZmx1c2hQbGF5YmFja10pO1xuXG4gIGNvbnN0IHBsYXlQY21DaHVuayA9IHVzZUNhbGxiYWNrKChwY206IEFycmF5QnVmZmVyKSA9PiB7XG4gICAgY29uc3QgY3R4ID0gcGxheWJhY2tDdHhSZWYuY3VycmVudDtcbiAgICBpZiAoIWN0eCkgcmV0dXJuO1xuICAgIGNvbnN0IGludHMgPSBuZXcgSW50MTZBcnJheShwY20pO1xuICAgIGlmIChpbnRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuICAgIGNvbnN0IGZsb2F0cyA9IG5ldyBGbG9hdDMyQXJyYXkoaW50cy5sZW5ndGgpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgaW50cy5sZW5ndGg7IGkrKykgZmxvYXRzW2ldID0gaW50c1tpXSAvIDB4ODAwMDtcblxuICAgIGNvbnN0IGJ1ZmZlciA9IGN0eC5jcmVhdGVCdWZmZXIoMSwgZmxvYXRzLmxlbmd0aCwgTElWRV9PVVRQVVRfU0FNUExFX1JBVEUpO1xuICAgIGJ1ZmZlci5jb3B5VG9DaGFubmVsKGZsb2F0cywgMCk7XG4gICAgY29uc3Qgc291cmNlID0gY3R4LmNyZWF0ZUJ1ZmZlclNvdXJjZSgpO1xuICAgIHNvdXJjZS5idWZmZXIgPSBidWZmZXI7XG4gICAgc291cmNlLmNvbm5lY3QoY3R4LmRlc3RpbmF0aW9uKTtcblxuICAgIGNvbnN0IHN0YXJ0QXQgPSBNYXRoLm1heChjdHguY3VycmVudFRpbWUsIHBsYXloZWFkUmVmLmN1cnJlbnQpO1xuICAgIHNvdXJjZS5zdGFydChzdGFydEF0KTtcbiAgICBwbGF5aGVhZFJlZi5jdXJyZW50ID0gc3RhcnRBdCArIGJ1ZmZlci5kdXJhdGlvbjtcbiAgICBzb3VyY2VzUmVmLmN1cnJlbnQucHVzaChzb3VyY2UpO1xuICAgIHNvdXJjZS5vbmVuZGVkID0gKCkgPT4ge1xuICAgICAgc291cmNlc1JlZi5jdXJyZW50ID0gc291cmNlc1JlZi5jdXJyZW50LmZpbHRlcigocykgPT4gcyAhPT0gc291cmNlKTtcbiAgICB9O1xuXG4gICAgLy8gUmVmbGVjdCBcInNwZWFraW5nXCIgdW50aWwgdGhlIHNjaGVkdWxlZCBhdWRpbyBkcmFpbnMuXG4gICAgc2V0U3RhdHVzKCdzcGVha2luZycpO1xuICAgIGlmIChzcGVha2luZ1RpbWVyUmVmLmN1cnJlbnQpIGNsZWFyVGltZW91dChzcGVha2luZ1RpbWVyUmVmLmN1cnJlbnQpO1xuICAgIGNvbnN0IHJlbWFpbmluZ01zID0gKHBsYXloZWFkUmVmLmN1cnJlbnQgLSBjdHguY3VycmVudFRpbWUpICogMTAwMCArIDE1MDtcbiAgICBzcGVha2luZ1RpbWVyUmVmLmN1cnJlbnQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIGlmIChpc0FjdGl2ZVJlZi5jdXJyZW50KSBzZXRTdGF0dXMoJ2xpc3RlbmluZycpO1xuICAgIH0sIHJlbWFpbmluZ01zKTtcbiAgfSwgW10pO1xuXG4gIGNvbnN0IGhhbmRsZUV2ZW50ID0gdXNlQ2FsbGJhY2soKGRhdGE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA9PiB7XG4gICAgY29uc3QgY2IgPSBvcHRzUmVmLmN1cnJlbnQ7XG4gICAgc3dpdGNoIChkYXRhLnR5cGUpIHtcbiAgICAgIGNhc2UgJ3JlYWR5JzpcbiAgICAgICAgc2V0U3RhdHVzKCdsaXN0ZW5pbmcnKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdpbnB1dF90cmFuc2NyaXB0JzpcbiAgICAgICAgaWYgKHR5cGVvZiBkYXRhLnRleHQgPT09ICdzdHJpbmcnKSBjYi5vbklucHV0VHJhbnNjcmlwdD8uKGRhdGEudGV4dCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnb3V0cHV0X3RyYW5zY3JpcHQnOlxuICAgICAgICBpZiAodHlwZW9mIGRhdGEudGV4dCA9PT0gJ3N0cmluZycpIGNiLm9uT3V0cHV0VHJhbnNjcmlwdD8uKGRhdGEudGV4dCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnaW50ZXJydXB0ZWQnOlxuICAgICAgICBmbHVzaFBsYXliYWNrKCk7XG4gICAgICAgIHNldFN0YXR1cygnbGlzdGVuaW5nJyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAndHVybl9jb21wbGV0ZSc6XG4gICAgICAgIGNiLm9uVHVybkNvbXBsZXRlPy4oe1xuICAgICAgICAgIHRyYW5zY3JpcHQ6IFN0cmluZyhkYXRhLnRyYW5zY3JpcHQgPz8gJycpLFxuICAgICAgICAgIHJlc3BvbnNlOiBTdHJpbmcoZGF0YS5yZXNwb25zZSA/PyAnJyksXG4gICAgICAgIH0pO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2Vycm9yJzpcbiAgICAgICAgY2Iub25FcnJvcj8uKG5ldyBFcnJvcihTdHJpbmcoZGF0YS5tZXNzYWdlID8/ICdMaXZlIHZvaWNlIGVycm9yJykpKTtcbiAgICAgICAgc2V0U3RhdHVzKCdlcnJvcicpO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfSwgW2ZsdXNoUGxheWJhY2tdKTtcblxuICBjb25zdCBzdGFydCA9IHVzZUNhbGxiYWNrKGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBjYiA9IG9wdHNSZWYuY3VycmVudDtcbiAgICBpZiAoIWNiLmFnZW50SWQpIHtcbiAgICAgIGNiLm9uRXJyb3I/LihuZXcgRXJyb3IoJ0xpdmUgdm9pY2UgdW5hdmFpbGFibGU6IGFnZW50IGlzIHN0aWxsIGxvYWRpbmcnKSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICh3c1JlZi5jdXJyZW50KSByZXR1cm47IC8vIGFscmVhZHkgYWN0aXZlXG5cbiAgICBzZXRTdGF0dXMoJ2Nvbm5lY3RpbmcnKTtcbiAgICAvLyBQZXJzaXN0ZW5jZSAodHJhbnNjcmlwdC9kYXNoYm9hcmQpIGtleXMgb2ZmIGFuIGV4aXN0aW5nIGNvbnZlcnNhdGlvbiBVVUlELlxuICAgIC8vIFdpdGhvdXQgb25lIHRoZSBjYWxsIHN0aWxsIHdvcmtzLCBidXQgdGhlIGJhY2tlbmQgc2tpcHMgc2F2aW5nIHRoZSB0dXJucy5cbiAgICBpZiAoIWNiLmNvbnZlcnNhdGlvbklkKSB7XG4gICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICdbdXNlTGl2ZVZvaWNlXSBObyBjb252ZXJzYXRpb25JZCB5ZXQg4oCUIHRoZSBsaXZlIGNhbGwgd2lsbCBydW4gYnV0IGl0cyAnICtcbiAgICAgICAgICAndHJhbnNjcmlwdHMgd2lsbCBub3QgYmUgcGVyc2lzdGVkLicsXG4gICAgICApO1xuICAgIH1cbiAgICBjb25zdCB0aHJlYWRJZCA9XG4gICAgICBjYi5jb252ZXJzYXRpb25JZCB8fFxuICAgICAgKHR5cGVvZiBjcnlwdG8gIT09ICd1bmRlZmluZWQnICYmICdyYW5kb21VVUlEJyBpbiBjcnlwdG9cbiAgICAgICAgPyBjcnlwdG8ucmFuZG9tVVVJRCgpXG4gICAgICAgIDogYGxpdmUtJHtEYXRlLm5vdygpfWApO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHN0cmVhbSA9IGF3YWl0IG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhKHtcbiAgICAgICAgYXVkaW86IHsgY2hhbm5lbENvdW50OiAxLCBlY2hvQ2FuY2VsbGF0aW9uOiB0cnVlLCBub2lzZVN1cHByZXNzaW9uOiB0cnVlIH0sXG4gICAgICB9KTtcbiAgICAgIHN0cmVhbVJlZi5jdXJyZW50ID0gc3RyZWFtO1xuXG4gICAgICBjb25zdCBBdWRpb0N0eCA9XG4gICAgICAgIHdpbmRvdy5BdWRpb0NvbnRleHQgfHxcbiAgICAgICAgKHdpbmRvdyBhcyB1bmtub3duIGFzIHsgd2Via2l0QXVkaW9Db250ZXh0OiB0eXBlb2YgQXVkaW9Db250ZXh0IH0pLndlYmtpdEF1ZGlvQ29udGV4dDtcbiAgICAgIGNvbnN0IGNhcHR1cmVDdHggPSBuZXcgQXVkaW9DdHgoKTtcbiAgICAgIGNhcHR1cmVDdHhSZWYuY3VycmVudCA9IGNhcHR1cmVDdHg7XG4gICAgICBwbGF5YmFja0N0eFJlZi5jdXJyZW50ID0gbmV3IEF1ZGlvQ3R4KCk7XG4gICAgICBwbGF5aGVhZFJlZi5jdXJyZW50ID0gcGxheWJhY2tDdHhSZWYuY3VycmVudC5jdXJyZW50VGltZTtcblxuICAgICAgY29uc3Qgd3MgPSBjcmVhdGVXZWJTb2NrZXQoYnVpbGRMaXZlVXJsKGNiLCB0aHJlYWRJZCkpO1xuICAgICAgd3MuYmluYXJ5VHlwZSA9ICdhcnJheWJ1ZmZlcic7XG4gICAgICB3c1JlZi5jdXJyZW50ID0gd3M7XG5cbiAgICAgIHdzLm9ub3BlbiA9ICgpID0+IHtcbiAgICAgICAgY29uc3Qgc291cmNlID0gY2FwdHVyZUN0eC5jcmVhdGVNZWRpYVN0cmVhbVNvdXJjZShzdHJlYW0pO1xuICAgICAgICAvLyBUT0RPOiBtaWdyYXRlIHRvIEF1ZGlvV29ya2xldCDigJQgU2NyaXB0UHJvY2Vzc29yTm9kZSBpcyBkZXByZWNhdGVkIGFuZFxuICAgICAgICAvLyBydW5zIHRoZSBkb3duc2FtcGxlIG9uIHRoZSBtYWluIHRocmVhZCAoY2FuIGphbmsgb24gc2xvdyBkZXZpY2VzKS5cbiAgICAgICAgY29uc3QgcHJvY2Vzc29yID0gY2FwdHVyZUN0eC5jcmVhdGVTY3JpcHRQcm9jZXNzb3IoQ0FQVFVSRV9CVUZGRVJfU0laRSwgMSwgMSk7XG4gICAgICAgIHByb2Nlc3NvclJlZi5jdXJyZW50ID0gcHJvY2Vzc29yO1xuICAgICAgICBwcm9jZXNzb3Iub25hdWRpb3Byb2Nlc3MgPSAoZSkgPT4ge1xuICAgICAgICAgIGlmICh3cy5yZWFkeVN0YXRlICE9PSB3cy5PUEVOKSByZXR1cm47XG4gICAgICAgICAgY29uc3QgcGNtID0gZmxvYXRUbzE2a1BjbShlLmlucHV0QnVmZmVyLmdldENoYW5uZWxEYXRhKDApLCBjYXB0dXJlQ3R4LnNhbXBsZVJhdGUpO1xuICAgICAgICAgIHdzLnNlbmQocGNtKTtcbiAgICAgICAgfTtcbiAgICAgICAgc291cmNlLmNvbm5lY3QocHJvY2Vzc29yKTtcbiAgICAgICAgcHJvY2Vzc29yLmNvbm5lY3QoY2FwdHVyZUN0eC5kZXN0aW5hdGlvbik7IC8vIHJlcXVpcmVkIHRvIGRyaXZlIG9uYXVkaW9wcm9jZXNzXG4gICAgICAgIHNldElzQWN0aXZlKHRydWUpO1xuICAgICAgICBzZXRTdGF0dXMoJ2xpc3RlbmluZycpO1xuICAgICAgfTtcblxuICAgICAgd3Mub25tZXNzYWdlID0gKGV2ZW50OiBNZXNzYWdlRXZlbnQpID0+IHtcbiAgICAgICAgaWYgKGV2ZW50LmRhdGEgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikge1xuICAgICAgICAgIHBsYXlQY21DaHVuayhldmVudC5kYXRhKTtcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgZXZlbnQuZGF0YSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgaGFuZGxlRXZlbnQoSlNPTi5wYXJzZShldmVudC5kYXRhKSk7XG4gICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAvKiBpZ25vcmUgbWFsZm9ybWVkIGV2ZW50ICovXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICB3cy5vbmVycm9yID0gKCkgPT4ge1xuICAgICAgICBjYi5vbkVycm9yPy4obmV3IEVycm9yKCdMaXZlIHZvaWNlIGNvbm5lY3Rpb24gZXJyb3InKSk7XG4gICAgICB9O1xuXG4gICAgICB3cy5vbmNsb3NlID0gKCkgPT4ge1xuICAgICAgICBzdG9wKCk7XG4gICAgICB9O1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY2Iub25FcnJvcj8uKGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyIDogbmV3IEVycm9yKFN0cmluZyhlcnIpKSk7XG4gICAgICBzdG9wKCk7XG4gICAgfVxuICB9LCBbaGFuZGxlRXZlbnQsIHBsYXlQY21DaHVuaywgc3RvcF0pO1xuXG4gIC8vIFRlYXIgZG93biBvbiB1bm1vdW50LlxuICB1c2VFZmZlY3QoKCkgPT4gKCkgPT4gc3RvcCgpLCBbc3RvcF0pO1xuXG4gIHJldHVybiB7IGlzQWN0aXZlLCBzdGF0dXMsIHN0YXJ0LCBzdG9wIH07XG59XG4iXX0=