@garrix82/reactgenie-lib 1.3.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.
Files changed (85) hide show
  1. package/.env.example +22 -0
  2. package/.github/workflows/publish.yml +20 -0
  3. package/LICENSE.txt +201 -0
  4. package/README.md +621 -0
  5. package/babel.config.js +29 -0
  6. package/dist/adapters/__tests__/expo-router-adapter.test.d.ts +1 -0
  7. package/dist/adapters/expo-router-adapter.d.ts +16 -0
  8. package/dist/adapters/expo-router-adapter.js +521 -0
  9. package/dist/adapters/navigation-adapter.d.ts +20 -0
  10. package/dist/adapters/navigation-adapter.js +137 -0
  11. package/dist/audio-visualizer.d.ts +14 -0
  12. package/dist/audio-visualizer.js +123 -0
  13. package/dist/current-selection.d.ts +27 -0
  14. package/dist/current-selection.js +94 -0
  15. package/dist/errors.d.ts +19 -0
  16. package/dist/errors.js +37 -0
  17. package/dist/genie/DateTime.d.ts +66 -0
  18. package/dist/genie/DateTime.js +399 -0
  19. package/dist/genie/TimeDelta.d.ts +35 -0
  20. package/dist/genie/TimeDelta.js +169 -0
  21. package/dist/genie-view-wrapper.d.ts +1 -0
  22. package/dist/genie-view-wrapper.js +377 -0
  23. package/dist/hooks/__tests__/useSpeechRecognition.test.d.ts +1 -0
  24. package/dist/hooks/useSpeechRecognition.d.ts +28 -0
  25. package/dist/hooks/useSpeechRecognition.js +118 -0
  26. package/dist/index.d.ts +30 -0
  27. package/dist/index.js +469 -0
  28. package/dist/logger.d.ts +23 -0
  29. package/dist/logger.js +597 -0
  30. package/dist/logger.remote.test.d.ts +0 -0
  31. package/dist/modality-provider-v2.d.ts +28 -0
  32. package/dist/modality-provider-v2.js +1321 -0
  33. package/dist/modality-provider.d.ts +22 -0
  34. package/dist/modality-provider.js +373 -0
  35. package/dist/native-visibility.d.ts +28 -0
  36. package/dist/native-visibility.js +50 -0
  37. package/dist/platform/VoiceRecognitionBar.d.ts +17 -0
  38. package/dist/platform/VoiceRecognitionBar.js +332 -0
  39. package/dist/platform/components.d.ts +32 -0
  40. package/dist/platform/components.js +351 -0
  41. package/dist/platform/events.d.ts +31 -0
  42. package/dist/platform/events.js +274 -0
  43. package/dist/platform/index.d.ts +3 -0
  44. package/dist/platform/index.js +39 -0
  45. package/dist/platform/types.d.ts +79 -0
  46. package/dist/platform/types.js +97 -0
  47. package/dist/react-decorators.d.ts +87 -0
  48. package/dist/react-decorators.js +368 -0
  49. package/dist/shared-store.d.ts +74 -0
  50. package/dist/shared-store.js +589 -0
  51. package/dist/speech-recognition/__tests__/speech-recognition-groq-transport.test.d.ts +1 -0
  52. package/dist/speech-recognition/__tests__/speech-recognition-native.test.d.ts +1 -0
  53. package/dist/speech-recognition/__tests__/speech-recognition-openai-native.test.d.ts +1 -0
  54. package/dist/speech-recognition/__tests__/speech-recognition-openai.test.d.ts +1 -0
  55. package/dist/speech-recognition/__tests__/speech-recognition-unified-import.test.d.ts +0 -0
  56. package/dist/speech-recognition/__tests__/speech-recognition-unified.test.d.ts +1 -0
  57. package/dist/speech-recognition/speech-recognition-groq.d.ts +21 -0
  58. package/dist/speech-recognition/speech-recognition-groq.js +409 -0
  59. package/dist/speech-recognition/speech-recognition-mlx.d.ts +15 -0
  60. package/dist/speech-recognition/speech-recognition-mlx.js +393 -0
  61. package/dist/speech-recognition/speech-recognition-native.d.ts +24 -0
  62. package/dist/speech-recognition/speech-recognition-native.js +632 -0
  63. package/dist/speech-recognition/speech-recognition-openai-native.d.ts +40 -0
  64. package/dist/speech-recognition/speech-recognition-openai-native.js +653 -0
  65. package/dist/speech-recognition/speech-recognition-openai.d.ts +39 -0
  66. package/dist/speech-recognition/speech-recognition-openai.js +718 -0
  67. package/dist/speech-recognition/speech-recognition-unified.d.ts +93 -0
  68. package/dist/speech-recognition/speech-recognition-unified.js +589 -0
  69. package/dist/speech-recognition/utils/groq-transcription.d.ts +41 -0
  70. package/dist/speech-recognition/utils/groq-transcription.js +382 -0
  71. package/dist/speech-recognition.d.ts +7 -0
  72. package/dist/speech-recognition.js +61 -0
  73. package/dist/voice-pipeline-telemetry.d.ts +26 -0
  74. package/dist/voice-pipeline-telemetry.js +15 -0
  75. package/garrix82-reactgenie-lib-1.3.0.tgz +0 -0
  76. package/metro/index.js +3 -0
  77. package/metro/with-genie-registry.js +47 -0
  78. package/package.json +111 -0
  79. package/scripts/dry-run.js +23 -0
  80. package/scripts/generate-genie-registry.js +278 -0
  81. package/scripts/log-file-test.js +51 -0
  82. package/scripts/parse.js +26 -0
  83. package/scripts/prompt.js +19 -0
  84. package/scripts/set-script.js +200 -0
  85. package/tsconfig.json +36 -0
@@ -0,0 +1,632 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.NativeSpeechRecognizer = void 0;
7
+ exports.getNativeSpeechCapabilities = getNativeSpeechCapabilities;
8
+ exports.isNativeSpeechAvailable = isNativeSpeechAvailable;
9
+ var _react = _interopRequireWildcard(require("react"));
10
+ var _reactNative = require("react-native");
11
+ var _logger = _interopRequireDefault(require("../logger"));
12
+ var _groqTranscription = require("./utils/groq-transcription");
13
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
15
+ /**
16
+ * Native Speech Recognition (iOS/Android)
17
+ * Uses Expo Audio for recording and Groq for transcription
18
+ *
19
+ * REQUIRES: expo-audio + expo-file-system (SDK 53+)
20
+ */
21
+
22
+ const FileSystem = (() => {
23
+ try {
24
+ // Prefer legacy API when available (Expo SDK 54+ warns on direct legacy usage)
25
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
26
+ return require('expo-file-system/legacy');
27
+ } catch {
28
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
29
+ return require('expo-file-system');
30
+ }
31
+ })();
32
+ const missingAudioError = 'Native audio package not found. Install `expo-audio` and `expo-file-system`, then run a dev client build: npx expo install expo-audio expo-file-system';
33
+ function loadExpoAudioBackend() {
34
+ try {
35
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
36
+ const expoAudio = require('expo-audio');
37
+ const AudioModule = expoAudio?.AudioModule;
38
+ const requestRecordingPermissionsAsync = expoAudio?.requestRecordingPermissionsAsync;
39
+ const setAudioModeAsync = expoAudio?.setAudioModeAsync;
40
+ if (!AudioModule || typeof requestRecordingPermissionsAsync !== 'function' || typeof setAudioModeAsync !== 'function') {
41
+ return null;
42
+ }
43
+ const RecordingPresets = expoAudio?.RecordingPresets;
44
+ const AudioQuality = expoAudio?.AudioQuality;
45
+ const IOSOutputFormat = expoAudio?.IOSOutputFormat;
46
+ const preset = RecordingPresets?.HIGH_QUALITY;
47
+ const iosOutputFormat = IOSOutputFormat?.MPEG4AAC ?? 'aac ';
48
+ const iosAudioQuality = AudioQuality?.HIGH ?? 0x60;
49
+ const recordingOptions = {
50
+ extension: preset?.extension ?? '.m4a',
51
+ sampleRate: 16000,
52
+ numberOfChannels: 1,
53
+ bitRate: 128000,
54
+ android: {
55
+ outputFormat: preset?.android?.outputFormat ?? 'mpeg4',
56
+ audioEncoder: preset?.android?.audioEncoder ?? 'aac',
57
+ sampleRate: 16000,
58
+ numberOfChannels: 1,
59
+ bitRate: 128000
60
+ },
61
+ ios: {
62
+ outputFormat: preset?.ios?.outputFormat ?? iosOutputFormat,
63
+ audioQuality: preset?.ios?.audioQuality ?? iosAudioQuality,
64
+ sampleRate: 16000,
65
+ numberOfChannels: 1,
66
+ bitRate: 128000,
67
+ linearPCMBitDepth: 16,
68
+ linearPCMIsBigEndian: false,
69
+ linearPCMIsFloat: false
70
+ },
71
+ web: {
72
+ mimeType: preset?.web?.mimeType ?? 'audio/webm',
73
+ bitsPerSecond: preset?.web?.bitsPerSecond ?? 128000
74
+ }
75
+ };
76
+ return {
77
+ kind: 'expo-audio',
78
+ requestPermissionsAsync: requestRecordingPermissionsAsync,
79
+ setAudioModeAsync,
80
+ createRecording: () => new AudioModule.AudioRecorder(recordingOptions),
81
+ prepareToRecordAsync: recording => recording.prepareToRecordAsync(),
82
+ startAsync: async recording => {
83
+ recording.record();
84
+ },
85
+ stopAsync: async recording => {
86
+ await recording.stop();
87
+ return {
88
+ uri: recording?.uri ?? null
89
+ };
90
+ },
91
+ getUri: (recording, stopResult) => {
92
+ if (stopResult?.uri) return stopResult.uri;
93
+ return recording?.uri ?? null;
94
+ }
95
+ };
96
+ } catch (e) {
97
+ return null;
98
+ }
99
+ }
100
+ const audioBackend = loadExpoAudioBackend();
101
+ if (!audioBackend) {
102
+ _logger.default.error('❌ No audio backend available. Install expo-audio + expo-file-system and run a dev client build.');
103
+ } else {
104
+ _logger.default.info(`🎤 Audio backend ready: ${audioBackend.kind}`);
105
+ }
106
+ const DEFAULT_CHUNK_DURATION_MS = 2000; // Reduced from 3000ms for better responsiveness while maintaining efficiency
107
+ const START_RETRY_DELAY_MS = 150;
108
+ const POST_STOP_COOLDOWN_MS = 120;
109
+ const MAX_START_ATTEMPTS = 3;
110
+ const MAX_CONSECUTIVE_START_FAILURES = 3;
111
+ const MIN_AUDIO_SIZE_FLOOR_BYTES = 256;
112
+ /**
113
+ * Native speech recognizer for iOS/Android using expo-audio
114
+ */
115
+ const NativeSpeechRecognizer = ({
116
+ shouldListen,
117
+ speechStatusCallback,
118
+ speechResultCallback,
119
+ speechTranslationCallback,
120
+ clientSecret,
121
+ groqApiBaseUrl,
122
+ groqTranscriptionEndpoint,
123
+ stream = true,
124
+ language = 'en',
125
+ onError,
126
+ minAudioSize = 500
127
+ }) => {
128
+ const [isRecording, setIsRecording] = (0, _react.useState)(false);
129
+ const activeRecordingRef = (0, _react.useRef)(null);
130
+ const stopInFlightRef = (0, _react.useRef)(null);
131
+ const chunkLoopAbortRef = (0, _react.useRef)(null);
132
+ const streamAbortRef = (0, _react.useRef)(null);
133
+ const activeChunksRef = (0, _react.useRef)(new Set());
134
+ const committedTranscriptRef = (0, _react.useRef)('');
135
+ const currentChunkTranscriptRef = (0, _react.useRef)('');
136
+ const lastInterimRef = (0, _react.useRef)('');
137
+ (0, _react.useEffect)(() => {
138
+ if (clientSecret) {
139
+ _logger.default.debug('Groq client initialized (native)');
140
+ }
141
+ }, [clientSecret]);
142
+
143
+ /**
144
+ * Request audio permissions
145
+ */
146
+ const requestPermissions = async () => {
147
+ try {
148
+ if (!audioBackend) {
149
+ throw new Error(missingAudioError);
150
+ }
151
+ _logger.default.info('Requesting microphone permissions...');
152
+ const {
153
+ status,
154
+ granted
155
+ } = await audioBackend.requestPermissionsAsync();
156
+ const isGranted = status === 'granted' || granted === true;
157
+ if (!isGranted) {
158
+ throw new Error('Audio permission not granted. Please enable microphone access in your device settings.');
159
+ }
160
+ _logger.default.info('✅ Microphone permission granted');
161
+ return true;
162
+ } catch (error) {
163
+ _logger.default.error('Permission error:', error);
164
+ if (onError) {
165
+ onError(error);
166
+ }
167
+ return false;
168
+ }
169
+ };
170
+ const resetTranscriptState = (0, _react.useCallback)(() => {
171
+ committedTranscriptRef.current = '';
172
+ currentChunkTranscriptRef.current = '';
173
+ lastInterimRef.current = '';
174
+ }, []);
175
+ const commitChunk = (0, _react.useCallback)(chunkText => {
176
+ const combined = (0, _groqTranscription.mergeTranscriptParts)(committedTranscriptRef.current, chunkText);
177
+ committedTranscriptRef.current = combined;
178
+ currentChunkTranscriptRef.current = '';
179
+ }, []);
180
+ const stopRecorderSafely = (0, _react.useCallback)(async (recording, reason) => {
181
+ if (!audioBackend || !recording) {
182
+ return null;
183
+ }
184
+ const inFlight = stopInFlightRef.current;
185
+ if (inFlight && inFlight.recording === recording) {
186
+ _logger.default.debug(`[NativeSR] ♻️ Reusing in-flight stop (${reason})`);
187
+ return inFlight.promise;
188
+ }
189
+ const stopPromise = (async () => {
190
+ try {
191
+ const stopResult = await audioBackend.stopAsync(recording);
192
+ return audioBackend.getUri(recording, stopResult);
193
+ } catch (error) {
194
+ if (isBenignStopError(error)) {
195
+ _logger.default.debug(`[NativeSR] Stop already finalized (${reason})`);
196
+ return audioBackend.getUri(recording);
197
+ }
198
+ throw error;
199
+ } finally {
200
+ if (stopInFlightRef.current?.recording === recording) {
201
+ stopInFlightRef.current = null;
202
+ }
203
+ }
204
+ })();
205
+ stopInFlightRef.current = {
206
+ recording,
207
+ promise: stopPromise
208
+ };
209
+ return stopPromise;
210
+ }, []);
211
+
212
+ /**
213
+ * Process recorded audio chunk and send to Groq (streaming)
214
+ */
215
+ const processAudioChunk = (0, _react.useCallback)(async fileUri => {
216
+ let normalizedUri;
217
+ try {
218
+ _logger.default.debug('[NativeSR] 🔍 Processing audio chunk:', fileUri);
219
+ normalizedUri = normalizeFileUri(fileUri);
220
+ _logger.default.debug('[NativeSR] 📁 Normalized URI:', normalizedUri);
221
+
222
+ // Read file
223
+ _logger.default.debug('[NativeSR] 📖 Reading file info...');
224
+ const fileInfo = await FileSystem.getInfoAsync(normalizedUri);
225
+ _logger.default.debug('[NativeSR] 📊 File info:', JSON.stringify(fileInfo));
226
+ if (!fileInfo.exists) {
227
+ _logger.default.error('[NativeSR] ❌ Audio file missing:', normalizedUri);
228
+ return;
229
+ }
230
+ const fileSize = 'size' in fileInfo && typeof fileInfo.size === 'number' ? fileInfo.size : null;
231
+ const effectiveMinAudioSize = Math.max(minAudioSize, MIN_AUDIO_SIZE_FLOOR_BYTES);
232
+ if (fileSize !== null && fileSize < effectiveMinAudioSize) {
233
+ _logger.default.warn(`[NativeSR] ⚠️ Audio file too small (${fileSize} bytes, min: ${effectiveMinAudioSize})`);
234
+ return;
235
+ }
236
+ _logger.default.info(`[NativeSR] 📤 Uploading ${fileSize ?? 'unknown'} bytes to Groq...`);
237
+ const fileName = getFileNameFromUri(normalizedUri);
238
+ const mimeType = getMimeTypeFromName(fileName);
239
+ const controller = new AbortController();
240
+ streamAbortRef.current = controller;
241
+ const chunkText = await (0, _groqTranscription.streamGroqTranscription)({
242
+ apiKey: clientSecret,
243
+ audioBlob: {
244
+ uri: normalizedUri,
245
+ name: fileName,
246
+ type: mimeType
247
+ },
248
+ mimeType,
249
+ language,
250
+ responseFormat: 'verbose_json',
251
+ stream,
252
+ endpoint: resolveGroqTranscriptionEndpoint(groqApiBaseUrl, groqTranscriptionEndpoint),
253
+ signal: controller.signal,
254
+ onInterim: text => {
255
+ if (!text) return;
256
+ _logger.default.debug(`[NativeSR] 📝 Interim chunk text (${text.length} chars)`);
257
+ currentChunkTranscriptRef.current = text;
258
+
259
+ // Real-time callback like web version
260
+ const combined = (0, _groqTranscription.mergeTranscriptParts)(committedTranscriptRef.current, text);
261
+ if (combined !== lastInterimRef.current) {
262
+ lastInterimRef.current = combined;
263
+ speechStatusCallback(true, combined);
264
+ }
265
+ }
266
+ });
267
+ if (chunkText) {
268
+ _logger.default.info(`[NativeSR] ✅ Chunk transcription complete (${chunkText.length} chars)`);
269
+ commitChunk(chunkText);
270
+ // Final update after chunk completes
271
+ const finalCombined = (0, _groqTranscription.mergeTranscriptParts)(committedTranscriptRef.current, '');
272
+ if (finalCombined !== lastInterimRef.current) {
273
+ lastInterimRef.current = finalCombined;
274
+ speechStatusCallback(true, finalCombined);
275
+ }
276
+ }
277
+ } catch (error) {
278
+ _logger.default.error('[NativeSR] Groq transcription error:', error);
279
+ if (onError) {
280
+ onError(error);
281
+ }
282
+ } finally {
283
+ try {
284
+ if (normalizedUri) {
285
+ await FileSystem.deleteAsync(normalizedUri, {
286
+ idempotent: true
287
+ });
288
+ }
289
+ } catch (error) {
290
+ _logger.default.warn('[NativeSR] Failed to delete temp audio file:', error);
291
+ }
292
+ }
293
+ }, [commitChunk, clientSecret, groqApiBaseUrl, groqTranscriptionEndpoint, stream, language, minAudioSize, onError]);
294
+
295
+ /**
296
+ * Start chunked recording loop for streaming transcription
297
+ */
298
+ const startChunkLoop = (0, _react.useCallback)(async () => {
299
+ if (!audioBackend) return;
300
+ const controller = new AbortController();
301
+ chunkLoopAbortRef.current = controller;
302
+ _logger.default.info(`[NativeSR] 🔄 Chunk loop started (${DEFAULT_CHUNK_DURATION_MS}ms chunks)`);
303
+ let chunkCount = 0;
304
+ let consecutiveStartFailures = 0;
305
+ while (!controller.signal.aborted) {
306
+ chunkCount++;
307
+ _logger.default.debug(`[NativeSR] 📼 Recording chunk #${chunkCount}...`);
308
+ let recording = null;
309
+ let started = false;
310
+ for (let attempt = 1; attempt <= MAX_START_ATTEMPTS; attempt++) {
311
+ if (controller.signal.aborted) {
312
+ break;
313
+ }
314
+ recording = audioBackend.createRecording();
315
+ activeRecordingRef.current = recording;
316
+ try {
317
+ await audioBackend.prepareToRecordAsync(recording);
318
+ await audioBackend.startAsync(recording);
319
+ _logger.default.debug(`[NativeSR] 🎙️ Chunk #${chunkCount} recording...`);
320
+ started = true;
321
+ break;
322
+ } catch (error) {
323
+ _logger.default.error(`Failed to start chunk #${chunkCount} recording (attempt ${attempt}/${MAX_START_ATTEMPTS}):`, error);
324
+ activeRecordingRef.current = null;
325
+ if (attempt < MAX_START_ATTEMPTS) {
326
+ await sleep(START_RETRY_DELAY_MS);
327
+ }
328
+ }
329
+ }
330
+ if (!started || !recording) {
331
+ consecutiveStartFailures += 1;
332
+ _logger.default.warn(`[NativeSR] ⚠️ Chunk start failed (${consecutiveStartFailures}/${MAX_CONSECUTIVE_START_FAILURES}).`);
333
+ if (consecutiveStartFailures >= MAX_CONSECUTIVE_START_FAILURES) {
334
+ _logger.default.error('[NativeSR] ❌ Too many consecutive chunk start failures; ending loop.');
335
+ break;
336
+ }
337
+ await sleep(START_RETRY_DELAY_MS);
338
+ continue;
339
+ }
340
+ consecutiveStartFailures = 0;
341
+ await sleep(DEFAULT_CHUNK_DURATION_MS);
342
+ if (controller.signal.aborted) {
343
+ _logger.default.info('[NativeSR] 🛑 Chunk loop aborted');
344
+ const stillActive = activeRecordingRef.current === recording;
345
+ if (stillActive) {
346
+ try {
347
+ const uri = await stopRecorderSafely(recording, `abort chunk #${chunkCount}`);
348
+ if (uri) {
349
+ _logger.default.info(`[NativeSR] ✅ Final chunk URI (abort): ${uri.substring(0, 50)}...`);
350
+ const chunkPromise = processAudioChunk(uri).catch(error => {
351
+ _logger.default.error('[NativeSR] Failed to process aborted chunk:', error);
352
+ }).finally(() => {
353
+ activeChunksRef.current.delete(chunkPromise);
354
+ });
355
+ activeChunksRef.current.add(chunkPromise);
356
+ } else {
357
+ _logger.default.warn('[NativeSR] ⚠️ No URI for aborted chunk - skipping upload');
358
+ }
359
+ } catch (error) {
360
+ _logger.default.warn('[NativeSR] Failed to stop chunk recording on abort:', error);
361
+ }
362
+ } else {
363
+ _logger.default.debug('[NativeSR] Abort detected after external stop; skipping duplicate stop');
364
+ }
365
+ activeRecordingRef.current = null;
366
+ break;
367
+ }
368
+ try {
369
+ _logger.default.debug(`[NativeSR] ⏹️ Stopping chunk #${chunkCount}...`);
370
+ const uri = await stopRecorderSafely(recording, `chunk #${chunkCount}`);
371
+ _logger.default.debug(`[NativeSR] ✅ Chunk #${chunkCount} stopped`);
372
+ activeRecordingRef.current = null;
373
+ if (uri) {
374
+ _logger.default.info(`[NativeSR] ✅ Chunk #${chunkCount} URI: ${uri.substring(0, 50)}...`);
375
+ // Process chunks truly in parallel - track active chunks
376
+ const chunkPromise = processAudioChunk(uri).catch(error => {
377
+ _logger.default.error(`[NativeSR] Failed to process chunk #${chunkCount}:`, error);
378
+ }).finally(() => {
379
+ activeChunksRef.current.delete(chunkPromise);
380
+ });
381
+ activeChunksRef.current.add(chunkPromise);
382
+ } else {
383
+ _logger.default.warn(`[NativeSR] ⚠️ No URI for chunk #${chunkCount} - skipping upload`);
384
+ }
385
+ } catch (error) {
386
+ _logger.default.error(`[NativeSR] Failed to stop chunk #${chunkCount}:`, error);
387
+ activeRecordingRef.current = null;
388
+ continue; // Skip this chunk, try next one
389
+ }
390
+ if (!controller.signal.aborted) {
391
+ await sleep(POST_STOP_COOLDOWN_MS);
392
+ }
393
+ }
394
+ _logger.default.info(`[NativeSR] 🏁 Chunk loop ended (processed ${chunkCount} chunks)`);
395
+ }, [processAudioChunk, stopRecorderSafely]);
396
+
397
+ /**
398
+ * Start audio recording
399
+ */
400
+ const startRecording = (0, _react.useCallback)(async () => {
401
+ try {
402
+ if (!audioBackend) {
403
+ throw new Error(missingAudioError);
404
+ }
405
+ _logger.default.info(`[NativeSR] Start recording (backend=${audioBackend.kind})`);
406
+
407
+ // Request permissions
408
+ const hasPermission = await requestPermissions();
409
+ if (!hasPermission) {
410
+ _logger.default.warn('[NativeSR] Permission denied');
411
+ speechStatusCallback(false, '');
412
+ return;
413
+ }
414
+ await audioBackend.setAudioModeAsync({
415
+ allowsRecording: true,
416
+ playsInSilentMode: true,
417
+ shouldPlayInBackground: false,
418
+ shouldRouteThroughEarpiece: false,
419
+ interruptionMode: 'duckOthers'
420
+ });
421
+ _logger.default.debug('[NativeSR] Audio mode configured');
422
+ resetTranscriptState();
423
+ setIsRecording(true);
424
+ speechStatusCallback(true, '');
425
+ _logger.default.info('[NativeSR] 🎤 Native recording started');
426
+ startChunkLoop();
427
+ } catch (error) {
428
+ _logger.default.error('[NativeSR] Failed to start native recording:', error);
429
+ if (onError) {
430
+ onError(error);
431
+ }
432
+ speechStatusCallback(false, '');
433
+ }
434
+ }, [speechStatusCallback, onError, resetTranscriptState, startChunkLoop]);
435
+
436
+ /**
437
+ * Stop audio recording
438
+ */
439
+ const stopRecording = (0, _react.useCallback)(async () => {
440
+ if (!isRecording || !audioBackend) return;
441
+ try {
442
+ _logger.default.info('[NativeSR] Stop recording requested');
443
+ if (chunkLoopAbortRef.current) {
444
+ chunkLoopAbortRef.current.abort();
445
+ chunkLoopAbortRef.current = null;
446
+ }
447
+ if (activeRecordingRef.current) {
448
+ const currentRecording = activeRecordingRef.current;
449
+ activeRecordingRef.current = null;
450
+ try {
451
+ _logger.default.info('[NativeSR] ⏹️ Stopping final active recording...');
452
+ const uri = await stopRecorderSafely(currentRecording, 'explicit stop');
453
+ if (uri) {
454
+ _logger.default.info('[NativeSR] ✅ Final recording URI:', uri);
455
+ const chunkPromise = processAudioChunk(uri).catch(error => {
456
+ _logger.default.error('[NativeSR] Failed to process final chunk:', error);
457
+ }).finally(() => {
458
+ activeChunksRef.current.delete(chunkPromise);
459
+ });
460
+ activeChunksRef.current.add(chunkPromise);
461
+ } else {
462
+ _logger.default.warn('[NativeSR] ⚠️ No URI from final recording');
463
+ }
464
+ } catch (error) {
465
+ _logger.default.warn('[NativeSR] Failed to stop active recording:', error);
466
+ }
467
+ }
468
+ setIsRecording(false);
469
+
470
+ // Wait for all active chunks to complete (truly parallel)
471
+ try {
472
+ _logger.default.info(`[NativeSR] ⏳ Waiting for ${activeChunksRef.current.size} active chunks to complete...`);
473
+ await Promise.all(Array.from(activeChunksRef.current));
474
+ _logger.default.info('[NativeSR] ✅ All chunks processed');
475
+ } catch (error) {
476
+ _logger.default.warn('[NativeSR] Some chunks failed:', error);
477
+ }
478
+ const finalText = committedTranscriptRef.current || currentChunkTranscriptRef.current;
479
+ if (speechTranslationCallback && finalText && language && !language.startsWith('en')) {
480
+ try {
481
+ const translated = await (0, _groqTranscription.translateGroqText)({
482
+ apiKey: clientSecret,
483
+ text: finalText,
484
+ language,
485
+ endpoint: resolveGroqChatEndpoint(groqApiBaseUrl)
486
+ });
487
+ if (translated) {
488
+ speechTranslationCallback(translated);
489
+ }
490
+ } catch (error) {
491
+ _logger.default.warn('[NativeSR] Groq translation failed:', error);
492
+ }
493
+ }
494
+ _logger.default.info(`[NativeSR] Final text length: ${finalText.length}`);
495
+ speechStatusCallback(false, '');
496
+ if (finalText) {
497
+ speechResultCallback(finalText);
498
+ }
499
+ resetTranscriptState();
500
+ } catch (error) {
501
+ _logger.default.error('[NativeSR] Failed to stop native recording:', error);
502
+ if (onError) {
503
+ onError(error);
504
+ }
505
+ speechStatusCallback(false, '');
506
+ }
507
+ }, [isRecording, clientSecret, groqApiBaseUrl, language, onError, processAudioChunk, resetTranscriptState, speechResultCallback, speechStatusCallback, speechTranslationCallback, stopRecorderSafely]);
508
+
509
+ /**
510
+ * Handle shouldListen prop changes
511
+ */
512
+ (0, _react.useEffect)(() => {
513
+ _logger.default.debug(`[NativeSR] shouldListen=${shouldListen} isRecording=${isRecording}`);
514
+ if (shouldListen && !isRecording) {
515
+ startRecording();
516
+ } else if (!shouldListen && isRecording) {
517
+ stopRecording();
518
+ }
519
+ }, [shouldListen, isRecording, startRecording, stopRecording]);
520
+
521
+ /**
522
+ * Cleanup on unmount
523
+ */
524
+ (0, _react.useEffect)(() => {
525
+ return () => {
526
+ if (chunkLoopAbortRef.current) {
527
+ _logger.default.info('[NativeSR] Cleanup: aborting chunk loop');
528
+ chunkLoopAbortRef.current.abort();
529
+ }
530
+ if (streamAbortRef.current) {
531
+ _logger.default.info('[NativeSR] Cleanup: aborting stream');
532
+ streamAbortRef.current.abort();
533
+ }
534
+ if (activeRecordingRef.current && audioBackend) {
535
+ _logger.default.info('[NativeSR] Cleanup: stopping active recording');
536
+ stopRecorderSafely(activeRecordingRef.current, 'cleanup').catch(() => undefined);
537
+ }
538
+ };
539
+ }, [stopRecorderSafely]);
540
+ return /*#__PURE__*/_react.default.createElement(_reactNative.View, null);
541
+ };
542
+ exports.NativeSpeechRecognizer = NativeSpeechRecognizer;
543
+ function sleep(ms) {
544
+ return new Promise(resolve => setTimeout(resolve, ms));
545
+ }
546
+ function isBenignStopError(error) {
547
+ const message = error instanceof Error ? error.message : typeof error === 'string' ? error : '';
548
+ return /stop failed|already|not recording/i.test(message);
549
+ }
550
+
551
+ /**
552
+ * Convert base64 string to Blob
553
+ */
554
+ function getFileNameFromUri(uri) {
555
+ const cleanUri = uri.split('?')[0];
556
+ const lastSlash = cleanUri.lastIndexOf('/');
557
+ const fileName = lastSlash >= 0 ? cleanUri.slice(lastSlash + 1) : cleanUri;
558
+ if (fileName && fileName.includes('.')) {
559
+ return fileName;
560
+ }
561
+ return `audio-${Date.now()}.m4a`;
562
+ }
563
+ function getMimeTypeFromName(name) {
564
+ const ext = name.split('.').pop()?.toLowerCase() || '';
565
+ switch (ext) {
566
+ case 'm4a':
567
+ return 'audio/m4a';
568
+ case 'aac':
569
+ return 'audio/aac';
570
+ case 'mp3':
571
+ return 'audio/mpeg';
572
+ case 'mp4':
573
+ return 'audio/mp4';
574
+ case 'wav':
575
+ return 'audio/wav';
576
+ case 'webm':
577
+ return 'audio/webm';
578
+ case 'ogg':
579
+ return 'audio/ogg';
580
+ default:
581
+ return 'audio/m4a';
582
+ }
583
+ }
584
+ function resolveGroqTranscriptionEndpoint(baseUrl, overrideEndpoint) {
585
+ if (overrideEndpoint) return overrideEndpoint;
586
+ if (!baseUrl) return undefined;
587
+ const trimmed = baseUrl.replace(/\/+$/, '');
588
+ if (trimmed.endsWith('/openai/v1')) {
589
+ return `${trimmed}/audio/transcriptions`;
590
+ }
591
+ return `${trimmed}/openai/v1/audio/transcriptions`;
592
+ }
593
+ function resolveGroqChatEndpoint(baseUrl) {
594
+ if (!baseUrl) return undefined;
595
+ const trimmed = baseUrl.replace(/\/+$/, '');
596
+ if (trimmed.endsWith('/openai/v1')) {
597
+ return `${trimmed}/chat/completions`;
598
+ }
599
+ return `${trimmed}/openai/v1/chat/completions`;
600
+ }
601
+ function normalizeFileUri(uri) {
602
+ if (!uri) return uri;
603
+ if (uri.startsWith('file://') || uri.startsWith('content://')) {
604
+ return uri;
605
+ }
606
+ if (uri.startsWith('/')) {
607
+ return `file://${uri}`;
608
+ }
609
+ return uri;
610
+ }
611
+
612
+ /**
613
+ * Check if native speech recognition is available
614
+ */
615
+ function isNativeSpeechAvailable() {
616
+ return (_reactNative.Platform.OS === 'ios' || _reactNative.Platform.OS === 'android') && !!audioBackend;
617
+ }
618
+
619
+ /**
620
+ * Get native speech capabilities
621
+ */
622
+ function getNativeSpeechCapabilities() {
623
+ return {
624
+ available: isNativeSpeechAvailable(),
625
+ platform: _reactNative.Platform.OS,
626
+ supportsVAD: true,
627
+ supportsAudioLevels: true,
628
+ requiresExpoAudio: true,
629
+ backend: audioBackend?.kind ?? 'none'
630
+ };
631
+ }
632
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVXaWxkY2FyZCIsInJlcXVpcmUiLCJfcmVhY3ROYXRpdmUiLCJfbG9nZ2VyIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsIl9ncm9xVHJhbnNjcmlwdGlvbiIsImUiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsInQiLCJXZWFrTWFwIiwiciIsIm4iLCJvIiwiaSIsImYiLCJfX3Byb3RvX18iLCJoYXMiLCJnZXQiLCJzZXQiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJPYmplY3QiLCJkZWZpbmVQcm9wZXJ0eSIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsIkZpbGVTeXN0ZW0iLCJtaXNzaW5nQXVkaW9FcnJvciIsImxvYWRFeHBvQXVkaW9CYWNrZW5kIiwiZXhwb0F1ZGlvIiwiQXVkaW9Nb2R1bGUiLCJyZXF1ZXN0UmVjb3JkaW5nUGVybWlzc2lvbnNBc3luYyIsInNldEF1ZGlvTW9kZUFzeW5jIiwiUmVjb3JkaW5nUHJlc2V0cyIsIkF1ZGlvUXVhbGl0eSIsIklPU091dHB1dEZvcm1hdCIsInByZXNldCIsIkhJR0hfUVVBTElUWSIsImlvc091dHB1dEZvcm1hdCIsIk1QRUc0QUFDIiwiaW9zQXVkaW9RdWFsaXR5IiwiSElHSCIsInJlY29yZGluZ09wdGlvbnMiLCJleHRlbnNpb24iLCJzYW1wbGVSYXRlIiwibnVtYmVyT2ZDaGFubmVscyIsImJpdFJhdGUiLCJhbmRyb2lkIiwib3V0cHV0Rm9ybWF0IiwiYXVkaW9FbmNvZGVyIiwiaW9zIiwiYXVkaW9RdWFsaXR5IiwibGluZWFyUENNQml0RGVwdGgiLCJsaW5lYXJQQ01Jc0JpZ0VuZGlhbiIsImxpbmVhclBDTUlzRmxvYXQiLCJ3ZWIiLCJtaW1lVHlwZSIsImJpdHNQZXJTZWNvbmQiLCJraW5kIiwicmVxdWVzdFBlcm1pc3Npb25zQXN5bmMiLCJjcmVhdGVSZWNvcmRpbmciLCJBdWRpb1JlY29yZGVyIiwicHJlcGFyZVRvUmVjb3JkQXN5bmMiLCJyZWNvcmRpbmciLCJzdGFydEFzeW5jIiwicmVjb3JkIiwic3RvcEFzeW5jIiwic3RvcCIsInVyaSIsImdldFVyaSIsInN0b3BSZXN1bHQiLCJhdWRpb0JhY2tlbmQiLCJsb2dnZXIiLCJlcnJvciIsImluZm8iLCJERUZBVUxUX0NIVU5LX0RVUkFUSU9OX01TIiwiU1RBUlRfUkVUUllfREVMQVlfTVMiLCJQT1NUX1NUT1BfQ09PTERPV05fTVMiLCJNQVhfU1RBUlRfQVRURU1QVFMiLCJNQVhfQ09OU0VDVVRJVkVfU1RBUlRfRkFJTFVSRVMiLCJNSU5fQVVESU9fU0laRV9GTE9PUl9CWVRFUyIsIk5hdGl2ZVNwZWVjaFJlY29nbml6ZXIiLCJzaG91bGRMaXN0ZW4iLCJzcGVlY2hTdGF0dXNDYWxsYmFjayIsInNwZWVjaFJlc3VsdENhbGxiYWNrIiwic3BlZWNoVHJhbnNsYXRpb25DYWxsYmFjayIsImNsaWVudFNlY3JldCIsImdyb3FBcGlCYXNlVXJsIiwiZ3JvcVRyYW5zY3JpcHRpb25FbmRwb2ludCIsInN0cmVhbSIsImxhbmd1YWdlIiwib25FcnJvciIsIm1pbkF1ZGlvU2l6ZSIsImlzUmVjb3JkaW5nIiwic2V0SXNSZWNvcmRpbmciLCJ1c2VTdGF0ZSIsImFjdGl2ZVJlY29yZGluZ1JlZiIsInVzZVJlZiIsInN0b3BJbkZsaWdodFJlZiIsImNodW5rTG9vcEFib3J0UmVmIiwic3RyZWFtQWJvcnRSZWYiLCJhY3RpdmVDaHVua3NSZWYiLCJTZXQiLCJjb21taXR0ZWRUcmFuc2NyaXB0UmVmIiwiY3VycmVudENodW5rVHJhbnNjcmlwdFJlZiIsImxhc3RJbnRlcmltUmVmIiwidXNlRWZmZWN0IiwiZGVidWciLCJyZXF1ZXN0UGVybWlzc2lvbnMiLCJFcnJvciIsInN0YXR1cyIsImdyYW50ZWQiLCJpc0dyYW50ZWQiLCJyZXNldFRyYW5zY3JpcHRTdGF0ZSIsInVzZUNhbGxiYWNrIiwiY3VycmVudCIsImNvbW1pdENodW5rIiwiY2h1bmtUZXh0IiwiY29tYmluZWQiLCJtZXJnZVRyYW5zY3JpcHRQYXJ0cyIsInN0b3BSZWNvcmRlclNhZmVseSIsInJlYXNvbiIsImluRmxpZ2h0IiwicHJvbWlzZSIsInN0b3BQcm9taXNlIiwiaXNCZW5pZ25TdG9wRXJyb3IiLCJwcm9jZXNzQXVkaW9DaHVuayIsImZpbGVVcmkiLCJub3JtYWxpemVkVXJpIiwibm9ybWFsaXplRmlsZVVyaSIsImZpbGVJbmZvIiwiZ2V0SW5mb0FzeW5jIiwiSlNPTiIsInN0cmluZ2lmeSIsImV4aXN0cyIsImZpbGVTaXplIiwic2l6ZSIsImVmZmVjdGl2ZU1pbkF1ZGlvU2l6ZSIsIk1hdGgiLCJtYXgiLCJ3YXJuIiwiZmlsZU5hbWUiLCJnZXRGaWxlTmFtZUZyb21VcmkiLCJnZXRNaW1lVHlwZUZyb21OYW1lIiwiY29udHJvbGxlciIsIkFib3J0Q29udHJvbGxlciIsInN0cmVhbUdyb3FUcmFuc2NyaXB0aW9uIiwiYXBpS2V5IiwiYXVkaW9CbG9iIiwibmFtZSIsInR5cGUiLCJyZXNwb25zZUZvcm1hdCIsImVuZHBvaW50IiwicmVzb2x2ZUdyb3FUcmFuc2NyaXB0aW9uRW5kcG9pbnQiLCJzaWduYWwiLCJvbkludGVyaW0iLCJ0ZXh0IiwibGVuZ3RoIiwiZmluYWxDb21iaW5lZCIsImRlbGV0ZUFzeW5jIiwiaWRlbXBvdGVudCIsInN0YXJ0Q2h1bmtMb29wIiwiY2h1bmtDb3VudCIsImNvbnNlY3V0aXZlU3RhcnRGYWlsdXJlcyIsImFib3J0ZWQiLCJzdGFydGVkIiwiYXR0ZW1wdCIsInNsZWVwIiwic3RpbGxBY3RpdmUiLCJzdWJzdHJpbmciLCJjaHVua1Byb21pc2UiLCJjYXRjaCIsImZpbmFsbHkiLCJkZWxldGUiLCJhZGQiLCJzdGFydFJlY29yZGluZyIsImhhc1Blcm1pc3Npb24iLCJhbGxvd3NSZWNvcmRpbmciLCJwbGF5c0luU2lsZW50TW9kZSIsInNob3VsZFBsYXlJbkJhY2tncm91bmQiLCJzaG91bGRSb3V0ZVRocm91Z2hFYXJwaWVjZSIsImludGVycnVwdGlvbk1vZGUiLCJzdG9wUmVjb3JkaW5nIiwiYWJvcnQiLCJjdXJyZW50UmVjb3JkaW5nIiwiUHJvbWlzZSIsImFsbCIsIkFycmF5IiwiZnJvbSIsImZpbmFsVGV4dCIsInN0YXJ0c1dpdGgiLCJ0cmFuc2xhdGVkIiwidHJhbnNsYXRlR3JvcVRleHQiLCJyZXNvbHZlR3JvcUNoYXRFbmRwb2ludCIsInVuZGVmaW5lZCIsImNyZWF0ZUVsZW1lbnQiLCJWaWV3IiwiZXhwb3J0cyIsIm1zIiwicmVzb2x2ZSIsInNldFRpbWVvdXQiLCJtZXNzYWdlIiwidGVzdCIsImNsZWFuVXJpIiwic3BsaXQiLCJsYXN0U2xhc2giLCJsYXN0SW5kZXhPZiIsInNsaWNlIiwiaW5jbHVkZXMiLCJEYXRlIiwibm93IiwiZXh0IiwicG9wIiwidG9Mb3dlckNhc2UiLCJiYXNlVXJsIiwib3ZlcnJpZGVFbmRwb2ludCIsInRyaW1tZWQiLCJyZXBsYWNlIiwiZW5kc1dpdGgiLCJpc05hdGl2ZVNwZWVjaEF2YWlsYWJsZSIsIlBsYXRmb3JtIiwiT1MiLCJnZXROYXRpdmVTcGVlY2hDYXBhYmlsaXRpZXMiLCJhdmFpbGFibGUiLCJwbGF0Zm9ybSIsInN1cHBvcnRzVkFEIiwic3VwcG9ydHNBdWRpb0xldmVscyIsInJlcXVpcmVzRXhwb0F1ZGlvIiwiYmFja2VuZCJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zcGVlY2gtcmVjb2duaXRpb24vc3BlZWNoLXJlY29nbml0aW9uLW5hdGl2ZS50c3giXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBOYXRpdmUgU3BlZWNoIFJlY29nbml0aW9uIChpT1MvQW5kcm9pZClcbiAqIFVzZXMgRXhwbyBBdWRpbyBmb3IgcmVjb3JkaW5nIGFuZCBHcm9xIGZvciB0cmFuc2NyaXB0aW9uXG4gKlxuICogUkVRVUlSRVM6IGV4cG8tYXVkaW8gKyBleHBvLWZpbGUtc3lzdGVtIChTREsgNTMrKVxuICovXG5cbmltcG9ydCBSZWFjdCwgeyB1c2VFZmZlY3QsIHVzZVN0YXRlLCB1c2VSZWYsIHVzZUNhbGxiYWNrIH0gZnJvbSAncmVhY3QnO1xuaW1wb3J0IHsgVmlldywgUGxhdGZvcm0gfSBmcm9tICdyZWFjdC1uYXRpdmUnO1xudHlwZSBGaWxlU3lzdGVtTW9kdWxlID0gdHlwZW9mIGltcG9ydCgnZXhwby1maWxlLXN5c3RlbScpO1xuXG5jb25zdCBGaWxlU3lzdGVtOiBGaWxlU3lzdGVtTW9kdWxlID0gKCgpID0+IHtcbiAgdHJ5IHtcbiAgICAvLyBQcmVmZXIgbGVnYWN5IEFQSSB3aGVuIGF2YWlsYWJsZSAoRXhwbyBTREsgNTQrIHdhcm5zIG9uIGRpcmVjdCBsZWdhY3kgdXNhZ2UpXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby12YXItcmVxdWlyZXNcbiAgICByZXR1cm4gcmVxdWlyZSgnZXhwby1maWxlLXN5c3RlbS9sZWdhY3knKTtcbiAgfSBjYXRjaCB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby12YXItcmVxdWlyZXNcbiAgICByZXR1cm4gcmVxdWlyZSgnZXhwby1maWxlLXN5c3RlbScpO1xuICB9XG59KSgpO1xuaW1wb3J0IGxvZ2dlciBmcm9tICcuLi9sb2dnZXInO1xuaW1wb3J0IHtcbiAgbWVyZ2VUcmFuc2NyaXB0UGFydHMsXG4gIHN0cmVhbUdyb3FUcmFuc2NyaXB0aW9uLFxuICB0cmFuc2xhdGVHcm9xVGV4dCxcbn0gZnJvbSAnLi91dGlscy9ncm9xLXRyYW5zY3JpcHRpb24nO1xuXG50eXBlIEF1ZGlvQmFja2VuZCA9IHtcbiAga2luZDogJ2V4cG8tYXVkaW8nO1xuICByZXF1ZXN0UGVybWlzc2lvbnNBc3luYzogKCkgPT4gUHJvbWlzZTx7IHN0YXR1cz86IHN0cmluZzsgZ3JhbnRlZD86IGJvb2xlYW4gfT47XG4gIHNldEF1ZGlvTW9kZUFzeW5jOiAobW9kZTogYW55KSA9PiBQcm9taXNlPHZvaWQ+O1xuICBjcmVhdGVSZWNvcmRpbmc6ICgpID0+IGFueTtcbiAgcHJlcGFyZVRvUmVjb3JkQXN5bmM6IChyZWNvcmRpbmc6IGFueSkgPT4gUHJvbWlzZTx2b2lkPjtcbiAgc3RhcnRBc3luYzogKHJlY29yZGluZzogYW55KSA9PiBQcm9taXNlPHZvaWQ+O1xuICBzdG9wQXN5bmM6IChyZWNvcmRpbmc6IGFueSkgPT4gUHJvbWlzZTx7IHVyaT86IHN0cmluZyB8IG51bGwgfSB8IHZvaWQ+O1xuICBnZXRVcmk6IChyZWNvcmRpbmc6IGFueSwgc3RvcFJlc3VsdD86IGFueSkgPT4gc3RyaW5nIHwgbnVsbDtcbn07XG5cbmNvbnN0IG1pc3NpbmdBdWRpb0Vycm9yID1cbiAgJ05hdGl2ZSBhdWRpbyBwYWNrYWdlIG5vdCBmb3VuZC4gSW5zdGFsbCBgZXhwby1hdWRpb2AgYW5kIGBleHBvLWZpbGUtc3lzdGVtYCwgdGhlbiBydW4gYSBkZXYgY2xpZW50IGJ1aWxkOiBucHggZXhwbyBpbnN0YWxsIGV4cG8tYXVkaW8gZXhwby1maWxlLXN5c3RlbSc7XG5cbmZ1bmN0aW9uIGxvYWRFeHBvQXVkaW9CYWNrZW5kKCk6IEF1ZGlvQmFja2VuZCB8IG51bGwge1xuICB0cnkge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdmFyLXJlcXVpcmVzXG4gICAgY29uc3QgZXhwb0F1ZGlvID0gcmVxdWlyZSgnZXhwby1hdWRpbycpO1xuICAgIGNvbnN0IEF1ZGlvTW9kdWxlID0gZXhwb0F1ZGlvPy5BdWRpb01vZHVsZTtcbiAgICBjb25zdCByZXF1ZXN0UmVjb3JkaW5nUGVybWlzc2lvbnNBc3luYyA9IGV4cG9BdWRpbz8ucmVxdWVzdFJlY29yZGluZ1Blcm1pc3Npb25zQXN5bmM7XG4gICAgY29uc3Qgc2V0QXVkaW9Nb2RlQXN5bmMgPSBleHBvQXVkaW8/LnNldEF1ZGlvTW9kZUFzeW5jO1xuXG4gICAgaWYgKCFBdWRpb01vZHVsZSB8fCB0eXBlb2YgcmVxdWVzdFJlY29yZGluZ1Blcm1pc3Npb25zQXN5bmMgIT09ICdmdW5jdGlvbicgfHwgdHlwZW9mIHNldEF1ZGlvTW9kZUFzeW5jICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBjb25zdCBSZWNvcmRpbmdQcmVzZXRzID0gZXhwb0F1ZGlvPy5SZWNvcmRpbmdQcmVzZXRzO1xuICAgIGNvbnN0IEF1ZGlvUXVhbGl0eSA9IGV4cG9BdWRpbz8uQXVkaW9RdWFsaXR5O1xuICAgIGNvbnN0IElPU091dHB1dEZvcm1hdCA9IGV4cG9BdWRpbz8uSU9TT3V0cHV0Rm9ybWF0O1xuXG4gICAgY29uc3QgcHJlc2V0ID0gUmVjb3JkaW5nUHJlc2V0cz8uSElHSF9RVUFMSVRZO1xuICAgIGNvbnN0IGlvc091dHB1dEZvcm1hdCA9IElPU091dHB1dEZvcm1hdD8uTVBFRzRBQUMgPz8gJ2FhYyAnO1xuICAgIGNvbnN0IGlvc0F1ZGlvUXVhbGl0eSA9IEF1ZGlvUXVhbGl0eT8uSElHSCA/PyAweDYwO1xuXG4gICAgY29uc3QgcmVjb3JkaW5nT3B0aW9ucyA9IHtcbiAgICAgIGV4dGVuc2lvbjogcHJlc2V0Py5leHRlbnNpb24gPz8gJy5tNGEnLFxuICAgICAgc2FtcGxlUmF0ZTogMTYwMDAsXG4gICAgICBudW1iZXJPZkNoYW5uZWxzOiAxLFxuICAgICAgYml0UmF0ZTogMTI4MDAwLFxuICAgICAgYW5kcm9pZDoge1xuICAgICAgICBvdXRwdXRGb3JtYXQ6IHByZXNldD8uYW5kcm9pZD8ub3V0cHV0Rm9ybWF0ID8/ICdtcGVnNCcsXG4gICAgICAgIGF1ZGlvRW5jb2RlcjogcHJlc2V0Py5hbmRyb2lkPy5hdWRpb0VuY29kZXIgPz8gJ2FhYycsXG4gICAgICAgIHNhbXBsZVJhdGU6IDE2MDAwLFxuICAgICAgICBudW1iZXJPZkNoYW5uZWxzOiAxLFxuICAgICAgICBiaXRSYXRlOiAxMjgwMDAsXG4gICAgICB9LFxuICAgICAgaW9zOiB7XG4gICAgICAgIG91dHB1dEZvcm1hdDogcHJlc2V0Py5pb3M/Lm91dHB1dEZvcm1hdCA/PyBpb3NPdXRwdXRGb3JtYXQsXG4gICAgICAgIGF1ZGlvUXVhbGl0eTogcHJlc2V0Py5pb3M/LmF1ZGlvUXVhbGl0eSA/PyBpb3NBdWRpb1F1YWxpdHksXG4gICAgICAgIHNhbXBsZVJhdGU6IDE2MDAwLFxuICAgICAgICBudW1iZXJPZkNoYW5uZWxzOiAxLFxuICAgICAgICBiaXRSYXRlOiAxMjgwMDAsXG4gICAgICAgIGxpbmVhclBDTUJpdERlcHRoOiAxNixcbiAgICAgICAgbGluZWFyUENNSXNCaWdFbmRpYW46IGZhbHNlLFxuICAgICAgICBsaW5lYXJQQ01Jc0Zsb2F0OiBmYWxzZSxcbiAgICAgIH0sXG4gICAgICB3ZWI6IHtcbiAgICAgICAgbWltZVR5cGU6IHByZXNldD8ud2ViPy5taW1lVHlwZSA/PyAnYXVkaW8vd2VibScsXG4gICAgICAgIGJpdHNQZXJTZWNvbmQ6IHByZXNldD8ud2ViPy5iaXRzUGVyU2Vjb25kID8/IDEyODAwMCxcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIHJldHVybiB7XG4gICAgICBraW5kOiAnZXhwby1hdWRpbycsXG4gICAgICByZXF1ZXN0UGVybWlzc2lvbnNBc3luYzogcmVxdWVzdFJlY29yZGluZ1Blcm1pc3Npb25zQXN5bmMsXG4gICAgICBzZXRBdWRpb01vZGVBc3luYyxcbiAgICAgIGNyZWF0ZVJlY29yZGluZzogKCkgPT4gbmV3IEF1ZGlvTW9kdWxlLkF1ZGlvUmVjb3JkZXIocmVjb3JkaW5nT3B0aW9ucyksXG4gICAgICBwcmVwYXJlVG9SZWNvcmRBc3luYzogKHJlY29yZGluZykgPT4gcmVjb3JkaW5nLnByZXBhcmVUb1JlY29yZEFzeW5jKCksXG4gICAgICBzdGFydEFzeW5jOiBhc3luYyAocmVjb3JkaW5nKSA9PiB7XG4gICAgICAgIHJlY29yZGluZy5yZWNvcmQoKTtcbiAgICAgIH0sXG4gICAgICBzdG9wQXN5bmM6IGFzeW5jIChyZWNvcmRpbmcpID0+IHtcbiAgICAgICAgYXdhaXQgcmVjb3JkaW5nLnN0b3AoKTtcbiAgICAgICAgcmV0dXJuIHsgdXJpOiByZWNvcmRpbmc/LnVyaSA/PyBudWxsIH07XG4gICAgICB9LFxuICAgICAgZ2V0VXJpOiAocmVjb3JkaW5nLCBzdG9wUmVzdWx0KSA9PiB7XG4gICAgICAgIGlmIChzdG9wUmVzdWx0Py51cmkpIHJldHVybiBzdG9wUmVzdWx0LnVyaTtcbiAgICAgICAgcmV0dXJuIHJlY29yZGluZz8udXJpID8/IG51bGw7XG4gICAgICB9LFxuICAgIH07XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxufVxuXG5jb25zdCBhdWRpb0JhY2tlbmQ6IEF1ZGlvQmFja2VuZCB8IG51bGwgPSBsb2FkRXhwb0F1ZGlvQmFja2VuZCgpO1xuXG5pZiAoIWF1ZGlvQmFja2VuZCkge1xuICBsb2dnZXIuZXJyb3IoXG4gICAgJ+KdjCBObyBhdWRpbyBiYWNrZW5kIGF2YWlsYWJsZS4gSW5zdGFsbCBleHBvLWF1ZGlvICsgZXhwby1maWxlLXN5c3RlbSBhbmQgcnVuIGEgZGV2IGNsaWVudCBidWlsZC4nLFxuICApO1xufSBlbHNlIHtcbiAgbG9nZ2VyLmluZm8oYPCfjqQgQXVkaW8gYmFja2VuZCByZWFkeTogJHthdWRpb0JhY2tlbmQua2luZH1gKTtcbn1cblxuY29uc3QgREVGQVVMVF9DSFVOS19EVVJBVElPTl9NUyA9IDIwMDA7IC8vIFJlZHVjZWQgZnJvbSAzMDAwbXMgZm9yIGJldHRlciByZXNwb25zaXZlbmVzcyB3aGlsZSBtYWludGFpbmluZyBlZmZpY2llbmN5XG5jb25zdCBTVEFSVF9SRVRSWV9ERUxBWV9NUyA9IDE1MDtcbmNvbnN0IFBPU1RfU1RPUF9DT09MRE9XTl9NUyA9IDEyMDtcbmNvbnN0IE1BWF9TVEFSVF9BVFRFTVBUUyA9IDM7XG5jb25zdCBNQVhfQ09OU0VDVVRJVkVfU1RBUlRfRkFJTFVSRVMgPSAzO1xuY29uc3QgTUlOX0FVRElPX1NJWkVfRkxPT1JfQllURVMgPSAyNTY7XG5cbmV4cG9ydCBpbnRlcmZhY2UgTmF0aXZlU3BlZWNoUmVjb2duaXplclByb3BzIHtcbiAgc2hvdWxkTGlzdGVuOiBib29sZWFuO1xuICBzcGVlY2hTdGF0dXNDYWxsYmFjazogKHN0YXR1czogYm9vbGVhbiwgdHJhbnNjcmlwdDogc3RyaW5nKSA9PiB2b2lkO1xuICBzcGVlY2hSZXN1bHRDYWxsYmFjazogKHJlc3VsdDogc3RyaW5nKSA9PiB2b2lkO1xuICBzcGVlY2hUcmFuc2xhdGlvbkNhbGxiYWNrPzogKHRyYW5zbGF0aW9uOiBzdHJpbmcpID0+IHZvaWQ7XG4gIGNsaWVudFNlY3JldDogc3RyaW5nO1xuICBncm9xQXBpQmFzZVVybD86IHN0cmluZztcbiAgZ3JvcVRyYW5zY3JpcHRpb25FbmRwb2ludD86IHN0cmluZztcbiAgc3RyZWFtPzogYm9vbGVhbjtcbiAgbGFuZ3VhZ2U/OiBzdHJpbmc7XG4gIG9uRXJyb3I/OiAoZXJyb3I6IEVycm9yKSA9PiB2b2lkO1xuICBtaW5BdWRpb1NpemU/OiBudW1iZXI7IC8vIE1pbmltdW0gYXVkaW8gc2l6ZSBpbiBieXRlcyAoZGVmYXVsdCAxMDAwKVxufVxuXG4vKipcbiAqIE5hdGl2ZSBzcGVlY2ggcmVjb2duaXplciBmb3IgaU9TL0FuZHJvaWQgdXNpbmcgZXhwby1hdWRpb1xuICovXG5leHBvcnQgY29uc3QgTmF0aXZlU3BlZWNoUmVjb2duaXplcjogUmVhY3QuRkM8TmF0aXZlU3BlZWNoUmVjb2duaXplclByb3BzPiA9ICh7XG4gIHNob3VsZExpc3RlbixcbiAgc3BlZWNoU3RhdHVzQ2FsbGJhY2ssXG4gIHNwZWVjaFJlc3VsdENhbGxiYWNrLFxuICBzcGVlY2hUcmFuc2xhdGlvbkNhbGxiYWNrLFxuICBjbGllbnRTZWNyZXQsXG4gIGdyb3FBcGlCYXNlVXJsLFxuICBncm9xVHJhbnNjcmlwdGlvbkVuZHBvaW50LFxuICBzdHJlYW0gPSB0cnVlLFxuICBsYW5ndWFnZSA9ICdlbicsXG4gIG9uRXJyb3IsXG4gIG1pbkF1ZGlvU2l6ZSA9IDUwMCxcbn0pID0+IHtcbiAgY29uc3QgW2lzUmVjb3JkaW5nLCBzZXRJc1JlY29yZGluZ10gPSB1c2VTdGF0ZShmYWxzZSk7XG4gIGNvbnN0IGFjdGl2ZVJlY29yZGluZ1JlZiA9IHVzZVJlZjxhbnk+KG51bGwpO1xuICBjb25zdCBzdG9wSW5GbGlnaHRSZWYgPSB1c2VSZWY8eyByZWNvcmRpbmc6IGFueTsgcHJvbWlzZTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPiB9IHwgbnVsbD4obnVsbCk7XG4gIGNvbnN0IGNodW5rTG9vcEFib3J0UmVmID0gdXNlUmVmPEFib3J0Q29udHJvbGxlciB8IG51bGw+KG51bGwpO1xuICBjb25zdCBzdHJlYW1BYm9ydFJlZiA9IHVzZVJlZjxBYm9ydENvbnRyb2xsZXIgfCBudWxsPihudWxsKTtcbiAgY29uc3QgYWN0aXZlQ2h1bmtzUmVmID0gdXNlUmVmPFNldDxQcm9taXNlPHZvaWQ+Pj4obmV3IFNldCgpKTtcbiAgY29uc3QgY29tbWl0dGVkVHJhbnNjcmlwdFJlZiA9IHVzZVJlZjxzdHJpbmc+KCcnKTtcbiAgY29uc3QgY3VycmVudENodW5rVHJhbnNjcmlwdFJlZiA9IHVzZVJlZjxzdHJpbmc+KCcnKTtcbiAgY29uc3QgbGFzdEludGVyaW1SZWYgPSB1c2VSZWY8c3RyaW5nPignJyk7XG5cbiAgdXNlRWZmZWN0KCgpID0+IHtcbiAgICBpZiAoY2xpZW50U2VjcmV0KSB7XG4gICAgICBsb2dnZXIuZGVidWcoJ0dyb3EgY2xpZW50IGluaXRpYWxpemVkIChuYXRpdmUpJyk7XG4gICAgfVxuICB9LCBbY2xpZW50U2VjcmV0XSk7XG5cbiAgLyoqXG4gICAqIFJlcXVlc3QgYXVkaW8gcGVybWlzc2lvbnNcbiAgICovXG4gIGNvbnN0IHJlcXVlc3RQZXJtaXNzaW9ucyA9IGFzeW5jICgpID0+IHtcbiAgICB0cnkge1xuICAgICAgaWYgKCFhdWRpb0JhY2tlbmQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKG1pc3NpbmdBdWRpb0Vycm9yKTtcbiAgICAgIH1cbiAgICAgIGxvZ2dlci5pbmZvKCdSZXF1ZXN0aW5nIG1pY3JvcGhvbmUgcGVybWlzc2lvbnMuLi4nKTtcbiAgICAgIGNvbnN0IHsgc3RhdHVzLCBncmFudGVkIH0gPSBhd2FpdCBhdWRpb0JhY2tlbmQucmVxdWVzdFBlcm1pc3Npb25zQXN5bmMoKTtcbiAgICAgIGNvbnN0IGlzR3JhbnRlZCA9IHN0YXR1cyA9PT0gJ2dyYW50ZWQnIHx8IGdyYW50ZWQgPT09IHRydWU7XG4gICAgICBpZiAoIWlzR3JhbnRlZCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0F1ZGlvIHBlcm1pc3Npb24gbm90IGdyYW50ZWQuIFBsZWFzZSBlbmFibGUgbWljcm9waG9uZSBhY2Nlc3MgaW4geW91ciBkZXZpY2Ugc2V0dGluZ3MuJyk7XG4gICAgICB9XG4gICAgICBsb2dnZXIuaW5mbygn4pyFIE1pY3JvcGhvbmUgcGVybWlzc2lvbiBncmFudGVkJyk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdQZXJtaXNzaW9uIGVycm9yOicsIGVycm9yKTtcbiAgICAgIGlmIChvbkVycm9yKSB7XG4gICAgICAgIG9uRXJyb3IoZXJyb3IgYXMgRXJyb3IpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfTtcblxuICBjb25zdCByZXNldFRyYW5zY3JpcHRTdGF0ZSA9IHVzZUNhbGxiYWNrKCgpID0+IHtcbiAgICBjb21taXR0ZWRUcmFuc2NyaXB0UmVmLmN1cnJlbnQgPSAnJztcbiAgICBjdXJyZW50Q2h1bmtUcmFuc2NyaXB0UmVmLmN1cnJlbnQgPSAnJztcbiAgICBsYXN0SW50ZXJpbVJlZi5jdXJyZW50ID0gJyc7XG4gIH0sIFtdKTtcblxuICBjb25zdCBjb21taXRDaHVuayA9IHVzZUNhbGxiYWNrKChjaHVua1RleHQ6IHN0cmluZykgPT4ge1xuICAgIGNvbnN0IGNvbWJpbmVkID0gbWVyZ2VUcmFuc2NyaXB0UGFydHMoXG4gICAgICBjb21taXR0ZWRUcmFuc2NyaXB0UmVmLmN1cnJlbnQsXG4gICAgICBjaHVua1RleHRcbiAgICApO1xuICAgIGNvbW1pdHRlZFRyYW5zY3JpcHRSZWYuY3VycmVudCA9IGNvbWJpbmVkO1xuICAgIGN1cnJlbnRDaHVua1RyYW5zY3JpcHRSZWYuY3VycmVudCA9ICcnO1xuICB9LCBbXSk7XG5cbiAgY29uc3Qgc3RvcFJlY29yZGVyU2FmZWx5ID0gdXNlQ2FsbGJhY2soXG4gICAgYXN5bmMgKHJlY29yZGluZzogYW55LCByZWFzb246IHN0cmluZyk6IFByb21pc2U8c3RyaW5nIHwgbnVsbD4gPT4ge1xuICAgICAgaWYgKCFhdWRpb0JhY2tlbmQgfHwgIXJlY29yZGluZykge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cblxuICAgICAgY29uc3QgaW5GbGlnaHQgPSBzdG9wSW5GbGlnaHRSZWYuY3VycmVudDtcbiAgICAgIGlmIChpbkZsaWdodCAmJiBpbkZsaWdodC5yZWNvcmRpbmcgPT09IHJlY29yZGluZykge1xuICAgICAgICBsb2dnZXIuZGVidWcoYFtOYXRpdmVTUl0g4pm777iPICBSZXVzaW5nIGluLWZsaWdodCBzdG9wICgke3JlYXNvbn0pYCk7XG4gICAgICAgIHJldHVybiBpbkZsaWdodC5wcm9taXNlO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzdG9wUHJvbWlzZSA9IChhc3luYyAoKSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3Qgc3RvcFJlc3VsdCA9IGF3YWl0IGF1ZGlvQmFja2VuZC5zdG9wQXN5bmMocmVjb3JkaW5nKTtcbiAgICAgICAgICByZXR1cm4gYXVkaW9CYWNrZW5kLmdldFVyaShyZWNvcmRpbmcsIHN0b3BSZXN1bHQpO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGlmIChpc0JlbmlnblN0b3BFcnJvcihlcnJvcikpIHtcbiAgICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhgW05hdGl2ZVNSXSBTdG9wIGFscmVhZHkgZmluYWxpemVkICgke3JlYXNvbn0pYCk7XG4gICAgICAgICAgICByZXR1cm4gYXVkaW9CYWNrZW5kLmdldFVyaShyZWNvcmRpbmcpO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICBpZiAoc3RvcEluRmxpZ2h0UmVmLmN1cnJlbnQ/LnJlY29yZGluZyA9PT0gcmVjb3JkaW5nKSB7XG4gICAgICAgICAgICBzdG9wSW5GbGlnaHRSZWYuY3VycmVudCA9IG51bGw7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KSgpO1xuXG4gICAgICBzdG9wSW5GbGlnaHRSZWYuY3VycmVudCA9IHtcbiAgICAgICAgcmVjb3JkaW5nLFxuICAgICAgICBwcm9taXNlOiBzdG9wUHJvbWlzZSxcbiAgICAgIH07XG4gICAgICByZXR1cm4gc3RvcFByb21pc2U7XG4gICAgfSxcbiAgICBbXSxcbiAgKTtcblxuICAvKipcbiAgICogUHJvY2VzcyByZWNvcmRlZCBhdWRpbyBjaHVuayBhbmQgc2VuZCB0byBHcm9xIChzdHJlYW1pbmcpXG4gICAqL1xuICBjb25zdCBwcm9jZXNzQXVkaW9DaHVuayA9IHVzZUNhbGxiYWNrKGFzeW5jIChmaWxlVXJpOiBzdHJpbmcpID0+IHtcbiAgICBsZXQgbm9ybWFsaXplZFVyaTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4gICAgdHJ5IHtcbiAgICAgIGxvZ2dlci5kZWJ1ZygnW05hdGl2ZVNSXSDwn5SNIFByb2Nlc3NpbmcgYXVkaW8gY2h1bms6JywgZmlsZVVyaSk7XG4gICAgICBub3JtYWxpemVkVXJpID0gbm9ybWFsaXplRmlsZVVyaShmaWxlVXJpKTtcbiAgICAgIGxvZ2dlci5kZWJ1ZygnW05hdGl2ZVNSXSDwn5OBIE5vcm1hbGl6ZWQgVVJJOicsIG5vcm1hbGl6ZWRVcmkpO1xuICAgICAgXG4gICAgICAvLyBSZWFkIGZpbGVcbiAgICAgIGxvZ2dlci5kZWJ1ZygnW05hdGl2ZVNSXSDwn5OWIFJlYWRpbmcgZmlsZSBpbmZvLi4uJyk7XG4gICAgICBjb25zdCBmaWxlSW5mbyA9IGF3YWl0IEZpbGVTeXN0ZW0uZ2V0SW5mb0FzeW5jKG5vcm1hbGl6ZWRVcmkpO1xuICAgICAgbG9nZ2VyLmRlYnVnKCdbTmF0aXZlU1JdIPCfk4ogRmlsZSBpbmZvOicsIEpTT04uc3RyaW5naWZ5KGZpbGVJbmZvKSk7XG5cbiAgICAgIGlmICghZmlsZUluZm8uZXhpc3RzKSB7XG4gICAgICAgIGxvZ2dlci5lcnJvcignW05hdGl2ZVNSXSDinYwgQXVkaW8gZmlsZSBtaXNzaW5nOicsIG5vcm1hbGl6ZWRVcmkpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGZpbGVTaXplID1cbiAgICAgICAgJ3NpemUnIGluIGZpbGVJbmZvICYmIHR5cGVvZiBmaWxlSW5mby5zaXplID09PSAnbnVtYmVyJ1xuICAgICAgICAgID8gZmlsZUluZm8uc2l6ZVxuICAgICAgICAgIDogbnVsbDtcblxuICAgICAgY29uc3QgZWZmZWN0aXZlTWluQXVkaW9TaXplID0gTWF0aC5tYXgobWluQXVkaW9TaXplLCBNSU5fQVVESU9fU0laRV9GTE9PUl9CWVRFUyk7XG4gICAgICBpZiAoZmlsZVNpemUgIT09IG51bGwgJiYgZmlsZVNpemUgPCBlZmZlY3RpdmVNaW5BdWRpb1NpemUpIHtcbiAgICAgICAgbG9nZ2VyLndhcm4oXG4gICAgICAgICAgYFtOYXRpdmVTUl0g4pqg77iPICBBdWRpbyBmaWxlIHRvbyBzbWFsbCAoJHtmaWxlU2l6ZX0gYnl0ZXMsIG1pbjogJHtlZmZlY3RpdmVNaW5BdWRpb1NpemV9KWBcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgYFtOYXRpdmVTUl0g8J+TpCBVcGxvYWRpbmcgJHtmaWxlU2l6ZSA/PyAndW5rbm93bid9IGJ5dGVzIHRvIEdyb3EuLi5gXG4gICAgICApO1xuXG4gICAgICBjb25zdCBmaWxlTmFtZSA9IGdldEZpbGVOYW1lRnJvbVVyaShub3JtYWxpemVkVXJpKTtcbiAgICAgIGNvbnN0IG1pbWVUeXBlID0gZ2V0TWltZVR5cGVGcm9tTmFtZShmaWxlTmFtZSk7XG5cbiAgICAgIGNvbnN0IGNvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gICAgICBzdHJlYW1BYm9ydFJlZi5jdXJyZW50ID0gY29udHJvbGxlcjtcblxuICAgICAgY29uc3QgY2h1bmtUZXh0ID0gYXdhaXQgc3RyZWFtR3JvcVRyYW5zY3JpcHRpb24oe1xuICAgICAgICBhcGlLZXk6IGNsaWVudFNlY3JldCxcbiAgICAgICAgYXVkaW9CbG9iOiB7XG4gICAgICAgICAgdXJpOiBub3JtYWxpemVkVXJpLFxuICAgICAgICAgIG5hbWU6IGZpbGVOYW1lLFxuICAgICAgICAgIHR5cGU6IG1pbWVUeXBlLFxuICAgICAgICB9LFxuICAgICAgICBtaW1lVHlwZSxcbiAgICAgICAgbGFuZ3VhZ2UsXG4gICAgICAgIHJlc3BvbnNlRm9ybWF0OiAndmVyYm9zZV9qc29uJyxcbiAgICAgICAgc3RyZWFtLFxuICAgICAgICBlbmRwb2ludDogcmVzb2x2ZUdyb3FUcmFuc2NyaXB0aW9uRW5kcG9pbnQoXG4gICAgICAgICAgZ3JvcUFwaUJhc2VVcmwsXG4gICAgICAgICAgZ3JvcVRyYW5zY3JpcHRpb25FbmRwb2ludCxcbiAgICAgICAgKSxcbiAgICAgICAgc2lnbmFsOiBjb250cm9sbGVyLnNpZ25hbCxcbiAgICAgICAgb25JbnRlcmltOiAodGV4dCkgPT4ge1xuICAgICAgICAgIGlmICghdGV4dCkgcmV0dXJuO1xuICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhgW05hdGl2ZVNSXSDwn5OdIEludGVyaW0gY2h1bmsgdGV4dCAoJHt0ZXh0Lmxlbmd0aH0gY2hhcnMpYCk7XG4gICAgICAgICAgY3VycmVudENodW5rVHJhbnNjcmlwdFJlZi5jdXJyZW50ID0gdGV4dDtcbiAgICAgICAgICBcbiAgICAgICAgICAvLyBSZWFsLXRpbWUgY2FsbGJhY2sgbGlrZSB3ZWIgdmVyc2lvblxuICAgICAgICAgIGNvbnN0IGNvbWJpbmVkID0gbWVyZ2VUcmFuc2NyaXB0UGFydHMoY29tbWl0dGVkVHJhbnNjcmlwdFJlZi5jdXJyZW50LCB0ZXh0KTtcbiAgICAgICAgICBpZiAoY29tYmluZWQgIT09IGxhc3RJbnRlcmltUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgICAgIGxhc3RJbnRlcmltUmVmLmN1cnJlbnQgPSBjb21iaW5lZDtcbiAgICAgICAgICAgIHNwZWVjaFN0YXR1c0NhbGxiYWNrKHRydWUsIGNvbWJpbmVkKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgaWYgKGNodW5rVGV4dCkge1xuICAgICAgICBsb2dnZXIuaW5mbyhgW05hdGl2ZVNSXSDinIUgQ2h1bmsgdHJhbnNjcmlwdGlvbiBjb21wbGV0ZSAoJHtjaHVua1RleHQubGVuZ3RofSBjaGFycylgKTtcbiAgICAgICAgY29tbWl0Q2h1bmsoY2h1bmtUZXh0KTtcbiAgICAgICAgLy8gRmluYWwgdXBkYXRlIGFmdGVyIGNodW5rIGNvbXBsZXRlc1xuICAgICAgICBjb25zdCBmaW5hbENvbWJpbmVkID0gbWVyZ2VUcmFuc2NyaXB0UGFydHMoY29tbWl0dGVkVHJhbnNjcmlwdFJlZi5jdXJyZW50LCAnJyk7XG4gICAgICAgIGlmIChmaW5hbENvbWJpbmVkICE9PSBsYXN0SW50ZXJpbVJlZi5jdXJyZW50KSB7XG4gICAgICAgICAgbGFzdEludGVyaW1SZWYuY3VycmVudCA9IGZpbmFsQ29tYmluZWQ7XG4gICAgICAgICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2sodHJ1ZSwgZmluYWxDb21iaW5lZCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdbTmF0aXZlU1JdIEdyb3EgdHJhbnNjcmlwdGlvbiBlcnJvcjonLCBlcnJvcik7XG4gICAgICBpZiAob25FcnJvcikge1xuICAgICAgICBvbkVycm9yKGVycm9yIGFzIEVycm9yKTtcbiAgICAgIH1cbiAgICB9IGZpbmFsbHkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKG5vcm1hbGl6ZWRVcmkpIHtcbiAgICAgICAgICBhd2FpdCBGaWxlU3lzdGVtLmRlbGV0ZUFzeW5jKG5vcm1hbGl6ZWRVcmksIHsgaWRlbXBvdGVudDogdHJ1ZSB9KTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nZ2VyLndhcm4oJ1tOYXRpdmVTUl0gRmFpbGVkIHRvIGRlbGV0ZSB0ZW1wIGF1ZGlvIGZpbGU6JywgZXJyb3IpO1xuICAgICAgfVxuICAgIH1cbiAgfSwgW1xuICAgIGNvbW1pdENodW5rLFxuICAgIGNsaWVudFNlY3JldCxcbiAgICBncm9xQXBpQmFzZVVybCxcbiAgICBncm9xVHJhbnNjcmlwdGlvbkVuZHBvaW50LFxuICAgIHN0cmVhbSxcbiAgICBsYW5ndWFnZSxcbiAgICBtaW5BdWRpb1NpemUsXG4gICAgb25FcnJvcixcbiAgXSk7XG5cbiAgLyoqXG4gICAqIFN0YXJ0IGNodW5rZWQgcmVjb3JkaW5nIGxvb3AgZm9yIHN0cmVhbWluZyB0cmFuc2NyaXB0aW9uXG4gICAqL1xuICBjb25zdCBzdGFydENodW5rTG9vcCA9IHVzZUNhbGxiYWNrKGFzeW5jICgpID0+IHtcbiAgICBpZiAoIWF1ZGlvQmFja2VuZCkgcmV0dXJuO1xuICAgIGNvbnN0IGNvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gICAgY2h1bmtMb29wQWJvcnRSZWYuY3VycmVudCA9IGNvbnRyb2xsZXI7XG5cbiAgICBsb2dnZXIuaW5mbyhgW05hdGl2ZVNSXSDwn5SEIENodW5rIGxvb3Agc3RhcnRlZCAoJHtERUZBVUxUX0NIVU5LX0RVUkFUSU9OX01TfW1zIGNodW5rcylgKTtcbiAgICBsZXQgY2h1bmtDb3VudCA9IDA7XG4gICAgbGV0IGNvbnNlY3V0aXZlU3RhcnRGYWlsdXJlcyA9IDA7XG5cbiAgICB3aGlsZSAoIWNvbnRyb2xsZXIuc2lnbmFsLmFib3J0ZWQpIHtcbiAgICAgIGNodW5rQ291bnQrKztcbiAgICAgIGxvZ2dlci5kZWJ1ZyhgW05hdGl2ZVNSXSDwn5O8IFJlY29yZGluZyBjaHVuayAjJHtjaHVua0NvdW50fS4uLmApO1xuICAgICAgXG4gICAgICBsZXQgcmVjb3JkaW5nOiBhbnkgfCBudWxsID0gbnVsbDtcbiAgICAgIGxldCBzdGFydGVkID0gZmFsc2U7XG5cbiAgICAgIGZvciAobGV0IGF0dGVtcHQgPSAxOyBhdHRlbXB0IDw9IE1BWF9TVEFSVF9BVFRFTVBUUzsgYXR0ZW1wdCsrKSB7XG4gICAgICAgIGlmIChjb250cm9sbGVyLnNpZ25hbC5hYm9ydGVkKSB7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICByZWNvcmRpbmcgPSBhdWRpb0JhY2tlbmQuY3JlYXRlUmVjb3JkaW5nKCk7XG4gICAgICAgIGFjdGl2ZVJlY29yZGluZ1JlZi5jdXJyZW50ID0gcmVjb3JkaW5nO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgYXVkaW9CYWNrZW5kLnByZXBhcmVUb1JlY29yZEFzeW5jKHJlY29yZGluZyk7XG4gICAgICAgICAgYXdhaXQgYXVkaW9CYWNrZW5kLnN0YXJ0QXN5bmMocmVjb3JkaW5nKTtcbiAgICAgICAgICBsb2dnZXIuZGVidWcoYFtOYXRpdmVTUl0g8J+Ome+4jyAgQ2h1bmsgIyR7Y2h1bmtDb3VudH0gcmVjb3JkaW5nLi4uYCk7XG4gICAgICAgICAgc3RhcnRlZCA9IHRydWU7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgbG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgYEZhaWxlZCB0byBzdGFydCBjaHVuayAjJHtjaHVua0NvdW50fSByZWNvcmRpbmcgKGF0dGVtcHQgJHthdHRlbXB0fS8ke01BWF9TVEFSVF9BVFRFTVBUU30pOmAsXG4gICAgICAgICAgICBlcnJvclxuICAgICAgICAgICk7XG4gICAgICAgICAgYWN0aXZlUmVjb3JkaW5nUmVmLmN1cnJlbnQgPSBudWxsO1xuICAgICAgICAgIGlmIChhdHRlbXB0IDwgTUFYX1NUQVJUX0FUVEVNUFRTKSB7XG4gICAgICAgICAgICBhd2FpdCBzbGVlcChTVEFSVF9SRVRSWV9ERUxBWV9NUyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICghc3RhcnRlZCB8fCAhcmVjb3JkaW5nKSB7XG4gICAgICAgIGNvbnNlY3V0aXZlU3RhcnRGYWlsdXJlcyArPSAxO1xuICAgICAgICBsb2dnZXIud2FybihcbiAgICAgICAgICBgW05hdGl2ZVNSXSDimqDvuI8gIENodW5rIHN0YXJ0IGZhaWxlZCAoJHtjb25zZWN1dGl2ZVN0YXJ0RmFpbHVyZXN9LyR7TUFYX0NPTlNFQ1VUSVZFX1NUQVJUX0ZBSUxVUkVTfSkuYFxuICAgICAgICApO1xuICAgICAgICBpZiAoY29uc2VjdXRpdmVTdGFydEZhaWx1cmVzID49IE1BWF9DT05TRUNVVElWRV9TVEFSVF9GQUlMVVJFUykge1xuICAgICAgICAgIGxvZ2dlci5lcnJvcignW05hdGl2ZVNSXSDinYwgVG9vIG1hbnkgY29uc2VjdXRpdmUgY2h1bmsgc3RhcnQgZmFpbHVyZXM7IGVuZGluZyBsb29wLicpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IHNsZWVwKFNUQVJUX1JFVFJZX0RFTEFZX01TKTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGNvbnNlY3V0aXZlU3RhcnRGYWlsdXJlcyA9IDA7XG5cbiAgICAgIGF3YWl0IHNsZWVwKERFRkFVTFRfQ0hVTktfRFVSQVRJT05fTVMpO1xuXG4gICAgICBpZiAoY29udHJvbGxlci5zaWduYWwuYWJvcnRlZCkge1xuICAgICAgICBsb2dnZXIuaW5mbygnW05hdGl2ZVNSXSDwn5uRIENodW5rIGxvb3AgYWJvcnRlZCcpO1xuICAgICAgICBjb25zdCBzdGlsbEFjdGl2ZSA9IGFjdGl2ZVJlY29yZGluZ1JlZi5jdXJyZW50ID09PSByZWNvcmRpbmc7XG4gICAgICAgIGlmIChzdGlsbEFjdGl2ZSkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCB1cmkgPSBhd2FpdCBzdG9wUmVjb3JkZXJTYWZlbHkocmVjb3JkaW5nLCBgYWJvcnQgY2h1bmsgIyR7Y2h1bmtDb3VudH1gKTtcbiAgICAgICAgICAgIGlmICh1cmkpIHtcbiAgICAgICAgICAgICAgbG9nZ2VyLmluZm8oYFtOYXRpdmVTUl0g4pyFIEZpbmFsIGNodW5rIFVSSSAoYWJvcnQpOiAke3VyaS5zdWJzdHJpbmcoMCwgNTApfS4uLmApO1xuICAgICAgICAgICAgICBjb25zdCBjaHVua1Byb21pc2UgPSBwcm9jZXNzQXVkaW9DaHVuayh1cmkpXG4gICAgICAgICAgICAgICAgLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgICAgbG9nZ2VyLmVycm9yKCdbTmF0aXZlU1JdIEZhaWxlZCB0byBwcm9jZXNzIGFib3J0ZWQgY2h1bms6JywgZXJyb3IpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgYWN0aXZlQ2h1bmtzUmVmLmN1cnJlbnQuZGVsZXRlKGNodW5rUHJvbWlzZSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIGFjdGl2ZUNodW5rc1JlZi5jdXJyZW50LmFkZChjaHVua1Byb21pc2UpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgbG9nZ2VyLndhcm4oJ1tOYXRpdmVTUl0g4pqg77iPICBObyBVUkkgZm9yIGFib3J0ZWQgY2h1bmsgLSBza2lwcGluZyB1cGxvYWQnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgbG9nZ2VyLndhcm4oJ1tOYXRpdmVTUl0gRmFpbGVkIHRvIHN0b3AgY2h1bmsgcmVjb3JkaW5nIG9uIGFib3J0OicsIGVycm9yKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKCdbTmF0aXZlU1JdIEFib3J0IGRldGVjdGVkIGFmdGVyIGV4dGVybmFsIHN0b3A7IHNraXBwaW5nIGR1cGxpY2F0ZSBzdG9wJyk7XG4gICAgICAgIH1cbiAgICAgICAgYWN0aXZlUmVjb3JkaW5nUmVmLmN1cnJlbnQgPSBudWxsO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cblxuICAgICAgdHJ5IHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKGBbTmF0aXZlU1JdIOKPue+4jyAgU3RvcHBpbmcgY2h1bmsgIyR7Y2h1bmtDb3VudH0uLi5gKTtcbiAgICAgICAgY29uc3QgdXJpID0gYXdhaXQgc3RvcFJlY29yZGVyU2FmZWx5KHJlY29yZGluZywgYGNodW5rICMke2NodW5rQ291bnR9YCk7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhgW05hdGl2ZVNSXSDinIUgQ2h1bmsgIyR7Y2h1bmtDb3VudH0gc3RvcHBlZGApO1xuICAgICAgICBhY3RpdmVSZWNvcmRpbmdSZWYuY3VycmVudCA9IG51bGw7XG5cbiAgICAgICAgaWYgKHVyaSkge1xuICAgICAgICAgIGxvZ2dlci5pbmZvKGBbTmF0aXZlU1JdIOKchSBDaHVuayAjJHtjaHVua0NvdW50fSBVUkk6ICR7dXJpLnN1YnN0cmluZygwLCA1MCl9Li4uYCk7XG4gICAgICAgICAgLy8gUHJvY2VzcyBjaHVua3MgdHJ1bHkgaW4gcGFyYWxsZWwgLSB0cmFjayBhY3RpdmUgY2h1bmtzXG4gICAgICAgICAgY29uc3QgY2h1bmtQcm9taXNlID0gcHJvY2Vzc0F1ZGlvQ2h1bmsodXJpKVxuICAgICAgICAgICAgLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICAgICAgICBsb2dnZXIuZXJyb3IoYFtOYXRpdmVTUl0gRmFpbGVkIHRvIHByb2Nlc3MgY2h1bmsgIyR7Y2h1bmtDb3VudH06YCwgZXJyb3IpO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5maW5hbGx5KCgpID0+IHtcbiAgICAgICAgICAgICAgYWN0aXZlQ2h1bmtzUmVmLmN1cnJlbnQuZGVsZXRlKGNodW5rUHJvbWlzZSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICBhY3RpdmVDaHVua3NSZWYuY3VycmVudC5hZGQoY2h1bmtQcm9taXNlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBsb2dnZXIud2FybihgW05hdGl2ZVNSXSDimqDvuI8gIE5vIFVSSSBmb3IgY2h1bmsgIyR7Y2h1bmtDb3VudH0gLSBza2lwcGluZyB1cGxvYWRgKTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKGBbTmF0aXZlU1JdIEZhaWxlZCB0byBzdG9wIGNodW5rICMke2NodW5rQ291bnR9OmAsIGVycm9yKTtcbiAgICAgICAgYWN0aXZlUmVjb3JkaW5nUmVmLmN1cnJlbnQgPSBudWxsO1xuICAgICAgICBjb250aW51ZTsgLy8gU2tpcCB0aGlzIGNodW5rLCB0cnkgbmV4dCBvbmVcbiAgICAgIH1cblxuICAgICAgaWYgKCFjb250cm9sbGVyLnNpZ25hbC5hYm9ydGVkKSB7XG4gICAgICAgIGF3YWl0IHNsZWVwKFBPU1RfU1RPUF9DT09MRE9XTl9NUyk7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIGxvZ2dlci5pbmZvKGBbTmF0aXZlU1JdIPCfj4EgQ2h1bmsgbG9vcCBlbmRlZCAocHJvY2Vzc2VkICR7Y2h1bmtDb3VudH0gY2h1bmtzKWApO1xuICB9LCBbcHJvY2Vzc0F1ZGlvQ2h1bmssIHN0b3BSZWNvcmRlclNhZmVseV0pO1xuXG4gIC8qKlxuICAgKiBTdGFydCBhdWRpbyByZWNvcmRpbmdcbiAgICovXG4gIGNvbnN0IHN0YXJ0UmVjb3JkaW5nID0gdXNlQ2FsbGJhY2soYXN5bmMgKCkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBpZiAoIWF1ZGlvQmFja2VuZCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IobWlzc2luZ0F1ZGlvRXJyb3IpO1xuICAgICAgfVxuXG4gICAgICBsb2dnZXIuaW5mbyhgW05hdGl2ZVNSXSBTdGFydCByZWNvcmRpbmcgKGJhY2tlbmQ9JHthdWRpb0JhY2tlbmQua2luZH0pYCk7XG5cbiAgICAgIC8vIFJlcXVlc3QgcGVybWlzc2lvbnNcbiAgICAgIGNvbnN0IGhhc1Blcm1pc3Npb24gPSBhd2FpdCByZXF1ZXN0UGVybWlzc2lvbnMoKTtcbiAgICAgIGlmICghaGFzUGVybWlzc2lvbikge1xuICAgICAgICBsb2dnZXIud2FybignW05hdGl2ZVNSXSBQZXJtaXNzaW9uIGRlbmllZCcpO1xuICAgICAgICBzcGVlY2hTdGF0dXNDYWxsYmFjayhmYWxzZSwgJycpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGF3YWl0IGF1ZGlvQmFja2VuZC5zZXRBdWRpb01vZGVBc3luYyh7XG4gICAgICAgIGFsbG93c1JlY29yZGluZzogdHJ1ZSxcbiAgICAgICAgcGxheXNJblNpbGVudE1vZGU6IHRydWUsXG4gICAgICAgIHNob3VsZFBsYXlJbkJhY2tncm91bmQ6IGZhbHNlLFxuICAgICAgICBzaG91bGRSb3V0ZVRocm91Z2hFYXJwaWVjZTogZmFsc2UsXG4gICAgICAgIGludGVycnVwdGlvbk1vZGU6ICdkdWNrT3RoZXJzJyxcbiAgICAgIH0pO1xuXG4gICAgICBsb2dnZXIuZGVidWcoJ1tOYXRpdmVTUl0gQXVkaW8gbW9kZSBjb25maWd1cmVkJyk7XG4gICAgICByZXNldFRyYW5zY3JpcHRTdGF0ZSgpO1xuICAgICAgc2V0SXNSZWNvcmRpbmcodHJ1ZSk7XG4gICAgICBzcGVlY2hTdGF0dXNDYWxsYmFjayh0cnVlLCAnJyk7XG5cbiAgICAgIGxvZ2dlci5pbmZvKCdbTmF0aXZlU1JdIPCfjqQgTmF0aXZlIHJlY29yZGluZyBzdGFydGVkJyk7XG4gICAgICBzdGFydENodW5rTG9vcCgpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ1tOYXRpdmVTUl0gRmFpbGVkIHRvIHN0YXJ0IG5hdGl2ZSByZWNvcmRpbmc6JywgZXJyb3IpO1xuICAgICAgaWYgKG9uRXJyb3IpIHtcbiAgICAgICAgb25FcnJvcihlcnJvciBhcyBFcnJvcik7XG4gICAgICB9XG4gICAgICBzcGVlY2hTdGF0dXNDYWxsYmFjayhmYWxzZSwgJycpO1xuICAgIH1cbiAgfSwgW3NwZWVjaFN0YXR1c0NhbGxiYWNrLCBvbkVycm9yLCByZXNldFRyYW5zY3JpcHRTdGF0ZSwgc3RhcnRDaHVua0xvb3BdKTtcblxuICAvKipcbiAgICogU3RvcCBhdWRpbyByZWNvcmRpbmdcbiAgICovXG4gIGNvbnN0IHN0b3BSZWNvcmRpbmcgPSB1c2VDYWxsYmFjayhhc3luYyAoKSA9PiB7XG4gICAgaWYgKCFpc1JlY29yZGluZyB8fCAhYXVkaW9CYWNrZW5kKSByZXR1cm47XG5cbiAgICB0cnkge1xuICAgICAgbG9nZ2VyLmluZm8oJ1tOYXRpdmVTUl0gU3RvcCByZWNvcmRpbmcgcmVxdWVzdGVkJyk7XG4gICAgICBpZiAoY2h1bmtMb29wQWJvcnRSZWYuY3VycmVudCkge1xuICAgICAgICBjaHVua0xvb3BBYm9ydFJlZi5jdXJyZW50LmFib3J0KCk7XG4gICAgICAgIGNodW5rTG9vcEFib3J0UmVmLmN1cnJlbnQgPSBudWxsO1xuICAgICAgfVxuXG4gICAgICBpZiAoYWN0aXZlUmVjb3JkaW5nUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgY29uc3QgY3VycmVudFJlY29yZGluZyA9IGFjdGl2ZVJlY29yZGluZ1JlZi5jdXJyZW50O1xuICAgICAgICBhY3RpdmVSZWNvcmRpbmdSZWYuY3VycmVudCA9IG51bGw7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgbG9nZ2VyLmluZm8oJ1tOYXRpdmVTUl0g4o+577iPICBTdG9wcGluZyBmaW5hbCBhY3RpdmUgcmVjb3JkaW5nLi4uJyk7XG4gICAgICAgICAgY29uc3QgdXJpID0gYXdhaXQgc3RvcFJlY29yZGVyU2FmZWx5KGN1cnJlbnRSZWNvcmRpbmcsICdleHBsaWNpdCBzdG9wJyk7XG4gICAgICAgICAgaWYgKHVyaSkge1xuICAgICAgICAgICAgbG9nZ2VyLmluZm8oJ1tOYXRpdmVTUl0g4pyFIEZpbmFsIHJlY29yZGluZyBVUkk6JywgdXJpKTtcbiAgICAgICAgICAgIGNvbnN0IGNodW5rUHJvbWlzZSA9IHByb2Nlc3NBdWRpb0NodW5rKHVyaSlcbiAgICAgICAgICAgICAgLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgIGxvZ2dlci5lcnJvcignW05hdGl2ZVNSXSBGYWlsZWQgdG8gcHJvY2VzcyBmaW5hbCBjaHVuazonLCBlcnJvcik7XG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgIC5maW5hbGx5KCgpID0+IHtcbiAgICAgICAgICAgICAgICBhY3RpdmVDaHVua3NSZWYuY3VycmVudC5kZWxldGUoY2h1bmtQcm9taXNlKTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBhY3RpdmVDaHVua3NSZWYuY3VycmVudC5hZGQoY2h1bmtQcm9taXNlKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbG9nZ2VyLndhcm4oJ1tOYXRpdmVTUl0g4pqg77iPICBObyBVUkkgZnJvbSBmaW5hbCByZWNvcmRpbmcnKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgbG9nZ2VyLndhcm4oJ1tOYXRpdmVTUl0gRmFpbGVkIHRvIHN0b3AgYWN0aXZlIHJlY29yZGluZzonLCBlcnJvcik7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgc2V0SXNSZWNvcmRpbmcoZmFsc2UpO1xuXG4gICAgICAvLyBXYWl0IGZvciBhbGwgYWN0aXZlIGNodW5rcyB0byBjb21wbGV0ZSAodHJ1bHkgcGFyYWxsZWwpXG4gICAgICB0cnkge1xuICAgICAgICBsb2dnZXIuaW5mbyhgW05hdGl2ZVNSXSDij7MgV2FpdGluZyBmb3IgJHthY3RpdmVDaHVua3NSZWYuY3VycmVudC5zaXplfSBhY3RpdmUgY2h1bmtzIHRvIGNvbXBsZXRlLi4uYCk7XG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKEFycmF5LmZyb20oYWN0aXZlQ2h1bmtzUmVmLmN1cnJlbnQpKTtcbiAgICAgICAgbG9nZ2VyLmluZm8oJ1tOYXRpdmVTUl0g4pyFIEFsbCBjaHVua3MgcHJvY2Vzc2VkJyk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dnZXIud2FybignW05hdGl2ZVNSXSBTb21lIGNodW5rcyBmYWlsZWQ6JywgZXJyb3IpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBmaW5hbFRleHQgPVxuICAgICAgICBjb21taXR0ZWRUcmFuc2NyaXB0UmVmLmN1cnJlbnQgfHxcbiAgICAgICAgY3VycmVudENodW5rVHJhbnNjcmlwdFJlZi5jdXJyZW50O1xuXG4gICAgICBpZiAoXG4gICAgICAgIHNwZWVjaFRyYW5zbGF0aW9uQ2FsbGJhY2sgJiZcbiAgICAgICAgZmluYWxUZXh0ICYmXG4gICAgICAgIGxhbmd1YWdlICYmXG4gICAgICAgICFsYW5ndWFnZS5zdGFydHNXaXRoKCdlbicpXG4gICAgICApIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCB0cmFuc2xhdGVkID0gYXdhaXQgdHJhbnNsYXRlR3JvcVRleHQoe1xuICAgICAgICAgICAgYXBpS2V5OiBjbGllbnRTZWNyZXQsXG4gICAgICAgICAgICB0ZXh0OiBmaW5hbFRleHQsXG4gICAgICAgICAgICBsYW5ndWFnZSxcbiAgICAgICAgICAgIGVuZHBvaW50OiByZXNvbHZlR3JvcUNoYXRFbmRwb2ludChncm9xQXBpQmFzZVVybCksXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgaWYgKHRyYW5zbGF0ZWQpIHtcbiAgICAgICAgICAgIHNwZWVjaFRyYW5zbGF0aW9uQ2FsbGJhY2sodHJhbnNsYXRlZCk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGxvZ2dlci53YXJuKCdbTmF0aXZlU1JdIEdyb3EgdHJhbnNsYXRpb24gZmFpbGVkOicsIGVycm9yKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBsb2dnZXIuaW5mbyhgW05hdGl2ZVNSXSBGaW5hbCB0ZXh0IGxlbmd0aDogJHtmaW5hbFRleHQubGVuZ3RofWApO1xuICAgICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2soZmFsc2UsICcnKTtcbiAgICAgIGlmIChmaW5hbFRleHQpIHtcbiAgICAgICAgc3BlZWNoUmVzdWx0Q2FsbGJhY2soZmluYWxUZXh0KTtcbiAgICAgIH1cblxuICAgICAgcmVzZXRUcmFuc2NyaXB0U3RhdGUoKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdbTmF0aXZlU1JdIEZhaWxlZCB0byBzdG9wIG5hdGl2ZSByZWNvcmRpbmc6JywgZXJyb3IpO1xuICAgICAgaWYgKG9uRXJyb3IpIHtcbiAgICAgICAgb25FcnJvcihlcnJvciBhcyBFcnJvcik7XG4gICAgICB9XG4gICAgICBzcGVlY2hTdGF0dXNDYWxsYmFjayhmYWxzZSwgJycpO1xuICAgIH1cbiAgfSwgW1xuICAgIGlzUmVjb3JkaW5nLFxuICAgIGNsaWVudFNlY3JldCxcbiAgICBncm9xQXBpQmFzZVVybCxcbiAgICBsYW5ndWFnZSxcbiAgICBvbkVycm9yLFxuICAgIHByb2Nlc3NBdWRpb0NodW5rLFxuICAgIHJlc2V0VHJhbnNjcmlwdFN0YXRlLFxuICAgIHNwZWVjaFJlc3VsdENhbGxiYWNrLFxuICAgIHNwZWVjaFN0YXR1c0NhbGxiYWNrLFxuICAgIHNwZWVjaFRyYW5zbGF0aW9uQ2FsbGJhY2ssXG4gICAgc3RvcFJlY29yZGVyU2FmZWx5LFxuICBdKTtcblxuICAvKipcbiAgICogSGFuZGxlIHNob3VsZExpc3RlbiBwcm9wIGNoYW5nZXNcbiAgICovXG4gIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgbG9nZ2VyLmRlYnVnKGBbTmF0aXZlU1JdIHNob3VsZExpc3Rlbj0ke3Nob3VsZExpc3Rlbn0gaXNSZWNvcmRpbmc9JHtpc1JlY29yZGluZ31gKTtcbiAgICBpZiAoc2hvdWxkTGlzdGVuICYmICFpc1JlY29yZGluZykge1xuICAgICAgc3RhcnRSZWNvcmRpbmcoKTtcbiAgICB9IGVsc2UgaWYgKCFzaG91bGRMaXN0ZW4gJiYgaXNSZWNvcmRpbmcpIHtcbiAgICAgIHN0b3BSZWNvcmRpbmcoKTtcbiAgICB9XG4gIH0sIFtzaG91bGRMaXN0ZW4sIGlzUmVjb3JkaW5nLCBzdGFydFJlY29yZGluZywgc3RvcFJlY29yZGluZ10pO1xuXG4gIC8qKlxuICAgKiBDbGVhbnVwIG9uIHVubW91bnRcbiAgICovXG4gIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgcmV0dXJuICgpID0+IHtcbiAgICAgIGlmIChjaHVua0xvb3BBYm9ydFJlZi5jdXJyZW50KSB7XG4gICAgICAgIGxvZ2dlci5pbmZvKCdbTmF0aXZlU1JdIENsZWFudXA6IGFib3J0aW5nIGNodW5rIGxvb3AnKTtcbiAgICAgICAgY2h1bmtMb29wQWJvcnRSZWYuY3VycmVudC5hYm9ydCgpO1xuICAgICAgfVxuICAgICAgaWYgKHN0cmVhbUFib3J0UmVmLmN1cnJlbnQpIHtcbiAgICAgICAgbG9nZ2VyLmluZm8oJ1tOYXRpdmVTUl0gQ2xlYW51cDogYWJvcnRpbmcgc3RyZWFtJyk7XG4gICAgICAgIHN0cmVhbUFib3J0UmVmLmN1cnJlbnQuYWJvcnQoKTtcbiAgICAgIH1cbiAgICAgIGlmIChhY3RpdmVSZWNvcmRpbmdSZWYuY3VycmVudCAmJiBhdWRpb0JhY2tlbmQpIHtcbiAgICAgICAgbG9nZ2VyLmluZm8oJ1tOYXRpdmVTUl0gQ2xlYW51cDogc3RvcHBpbmcgYWN0aXZlIHJlY29yZGluZycpO1xuICAgICAgICBzdG9wUmVjb3JkZXJTYWZlbHkoYWN0aXZlUmVjb3JkaW5nUmVmLmN1cnJlbnQsICdjbGVhbnVwJykuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgICAgIH1cbiAgICB9O1xuICB9LCBbc3RvcFJlY29yZGVyU2FmZWx5XSk7XG5cbiAgcmV0dXJuIDxWaWV3IC8+O1xufTtcblxuZnVuY3Rpb24gc2xlZXAobXM6IG51bWJlcikge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpKTtcbn1cblxuZnVuY3Rpb24gaXNCZW5pZ25TdG9wRXJyb3IoZXJyb3I6IHVua25vd24pOiBib29sZWFuIHtcbiAgY29uc3QgbWVzc2FnZSA9XG4gICAgZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiB0eXBlb2YgZXJyb3IgPT09ICdzdHJpbmcnID8gZXJyb3IgOiAnJztcbiAgcmV0dXJuIC9zdG9wIGZhaWxlZHxhbHJlYWR5fG5vdCByZWNvcmRpbmcvaS50ZXN0KG1lc3NhZ2UpO1xufVxuXG4vKipcbiAqIENvbnZlcnQgYmFzZTY0IHN0cmluZyB0byBCbG9iXG4gKi9cbmZ1bmN0aW9uIGdldEZpbGVOYW1lRnJvbVVyaSh1cmk6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IGNsZWFuVXJpID0gdXJpLnNwbGl0KCc/JylbMF07XG4gIGNvbnN0IGxhc3RTbGFzaCA9IGNsZWFuVXJpLmxhc3RJbmRleE9mKCcvJyk7XG4gIGNvbnN0IGZpbGVOYW1lID0gbGFzdFNsYXNoID49IDAgPyBjbGVhblVyaS5zbGljZShsYXN0U2xhc2ggKyAxKSA6IGNsZWFuVXJpO1xuICBpZiAoZmlsZU5hbWUgJiYgZmlsZU5hbWUuaW5jbHVkZXMoJy4nKSkge1xuICAgIHJldHVybiBmaWxlTmFtZTtcbiAgfVxuICByZXR1cm4gYGF1ZGlvLSR7RGF0ZS5ub3coKX0ubTRhYDtcbn1cblxuZnVuY3Rpb24gZ2V0TWltZVR5cGVGcm9tTmFtZShuYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICBjb25zdCBleHQgPSBuYW1lLnNwbGl0KCcuJykucG9wKCk/LnRvTG93ZXJDYXNlKCkgfHwgJyc7XG4gIHN3aXRjaCAoZXh0KSB7XG4gICAgY2FzZSAnbTRhJzpcbiAgICAgIHJldHVybiAnYXVkaW8vbTRhJztcbiAgICBjYXNlICdhYWMnOlxuICAgICAgcmV0dXJuICdhdWRpby9hYWMnO1xuICAgIGNhc2UgJ21wMyc6XG4gICAgICByZXR1cm4gJ2F1ZGlvL21wZWcnO1xuICAgIGNhc2UgJ21wNCc6XG4gICAgICByZXR1cm4gJ2F1ZGlvL21wNCc7XG4gICAgY2FzZSAnd2F2JzpcbiAgICAgIHJldHVybiAnYXVkaW8vd2F2JztcbiAgICBjYXNlICd3ZWJtJzpcbiAgICAgIHJldHVybiAnYXVkaW8vd2VibSc7XG4gICAgY2FzZSAnb2dnJzpcbiAgICAgIHJldHVybiAnYXVkaW8vb2dnJztcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuICdhdWRpby9tNGEnO1xuICB9XG59XG5cbmZ1bmN0aW9uIHJlc29sdmVHcm9xVHJhbnNjcmlwdGlvbkVuZHBvaW50KFxuICBiYXNlVXJsPzogc3RyaW5nLFxuICBvdmVycmlkZUVuZHBvaW50Pzogc3RyaW5nLFxuKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgaWYgKG92ZXJyaWRlRW5kcG9pbnQpIHJldHVybiBvdmVycmlkZUVuZHBvaW50O1xuICBpZiAoIWJhc2VVcmwpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IHRyaW1tZWQgPSBiYXNlVXJsLnJlcGxhY2UoL1xcLyskLywgJycpO1xuICBpZiAodHJpbW1lZC5lbmRzV2l0aCgnL29wZW5haS92MScpKSB7XG4gICAgcmV0dXJuIGAke3RyaW1tZWR9L2F1ZGlvL3RyYW5zY3JpcHRpb25zYDtcbiAgfVxuICByZXR1cm4gYCR7dHJpbW1lZH0vb3BlbmFpL3YxL2F1ZGlvL3RyYW5zY3JpcHRpb25zYDtcbn1cblxuZnVuY3Rpb24gcmVzb2x2ZUdyb3FDaGF0RW5kcG9pbnQoYmFzZVVybD86IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmICghYmFzZVVybCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgY29uc3QgdHJpbW1lZCA9IGJhc2VVcmwucmVwbGFjZSgvXFwvKyQvLCAnJyk7XG4gIGlmICh0cmltbWVkLmVuZHNXaXRoKCcvb3BlbmFpL3YxJykpIHtcbiAgICByZXR1cm4gYCR7dHJpbW1lZH0vY2hhdC9jb21wbGV0aW9uc2A7XG4gIH1cbiAgcmV0dXJuIGAke3RyaW1tZWR9L29wZW5haS92MS9jaGF0L2NvbXBsZXRpb25zYDtcbn1cblxuZnVuY3Rpb24gbm9ybWFsaXplRmlsZVVyaSh1cmk6IHN0cmluZyk6IHN0cmluZyB7XG4gIGlmICghdXJpKSByZXR1cm4gdXJpO1xuICBpZiAodXJpLnN0YXJ0c1dpdGgoJ2ZpbGU6Ly8nKSB8fCB1cmkuc3RhcnRzV2l0aCgnY29udGVudDovLycpKSB7XG4gICAgcmV0dXJuIHVyaTtcbiAgfVxuICBpZiAodXJpLnN0YXJ0c1dpdGgoJy8nKSkge1xuICAgIHJldHVybiBgZmlsZTovLyR7dXJpfWA7XG4gIH1cbiAgcmV0dXJuIHVyaTtcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBuYXRpdmUgc3BlZWNoIHJlY29nbml0aW9uIGlzIGF2YWlsYWJsZVxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNOYXRpdmVTcGVlY2hBdmFpbGFibGUoKTogYm9vbGVhbiB7XG4gIHJldHVybiAoUGxhdGZvcm0uT1MgPT09ICdpb3MnIHx8IFBsYXRmb3JtLk9TID09PSAnYW5kcm9pZCcpICYmICEhYXVkaW9CYWNrZW5kO1xufVxuXG4vKipcbiAqIEdldCBuYXRpdmUgc3BlZWNoIGNhcGFiaWxpdGllc1xuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0TmF0aXZlU3BlZWNoQ2FwYWJpbGl0aWVzKCkge1xuICByZXR1cm4ge1xuICAgIGF2YWlsYWJsZTogaXNOYXRpdmVTcGVlY2hBdmFpbGFibGUoKSxcbiAgICBwbGF0Zm9ybTogUGxhdGZvcm0uT1MsXG4gICAgc3VwcG9ydHNWQUQ6IHRydWUsXG4gICAgc3VwcG9ydHNBdWRpb0xldmVsczogdHJ1ZSxcbiAgICByZXF1aXJlc0V4cG9BdWRpbzogdHJ1ZSxcbiAgICBiYWNrZW5kOiBhdWRpb0JhY2tlbmQ/LmtpbmQgPz8gJ25vbmUnLFxuICB9O1xufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7OztBQU9BLElBQUFBLE1BQUEsR0FBQUMsdUJBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLFlBQUEsR0FBQUQsT0FBQTtBQWFBLElBQUFFLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUgsT0FBQTtBQUNB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LEVBQUUsRUFBRSxDQUFDO0VBQzNDLElBQUlELE9BQU8sQ0FBQ0UsUUFBUSxDQUFDLFlBQVksQ0FBQyxFQUFFO0lBQ2xDLE9BQU8sR0FBR0YsT0FBTyx1QkFBdUI7RUFDMUM7RUFDQSxPQUFPLEdBQUdBLE9BQU8saUNBQWlDO0FBQ3BEO0FBRUEsU0FBU3ZCLHVCQUF1QkEsQ0FBQ3FCLE9BQWdCLEVBQXNCO0VBQ3JFLElBQUksQ0FBQ0EsT0FBTyxFQUFFLE9BQU9wQixTQUFTO0VBQzlCLE1BQU1zQixPQUFPLEdBQUdGLE9BQU8sQ0FBQ0csT0FBTyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUM7RUFDM0MsSUFBSUQsT0FBTyxDQUFDRSxRQUFRLENBQUMsWUFBWSxDQUFDLEVBQUU7SUFDbEMsT0FBTyxHQUFHRixPQUFPLG1CQUFtQjtFQUN0QztFQUNBLE9BQU8sR0FBR0EsT0FBTyw2QkFBNkI7QUFDaEQ7QUFFQSxTQUFTdkYsZ0JBQWdCQSxDQUFDN0QsR0FBVyxFQUFVO0VBQzdDLElBQUksQ0FBQ0EsR0FBRyxFQUFFLE9BQU9BLEdBQUc7RUFDcEIsSUFBSUEsR0FBRyxDQUFDMEgsVUFBVSxDQUFDLFNBQVMsQ0FBQyxJQUFJMUgsR0FBRyxDQUFDMEgsVUFBVSxDQUFDLFlBQVksQ0FBQyxFQUFFO0lBQzdELE9BQU8xSCxHQUFHO0VBQ1o7RUFDQSxJQUFJQSxHQUFHLENBQUMwSCxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQUU7SUFDdkIsT0FBTyxVQUFVMUgsR0FBRyxFQUFFO0VBQ3hCO0VBQ0EsT0FBT0EsR0FBRztBQUNaOztBQUVBO0FBQ0E7QUFDQTtBQUNPLFNBQVN1Six1QkFBdUJBLENBQUEsRUFBWTtFQUNqRCxPQUFPLENBQUNDLHFCQUFRLENBQUNDLEVBQUUsS0FBSyxLQUFLLElBQUlELHFCQUFRLENBQUNDLEVBQUUsS0FBSyxTQUFTLEtBQUssQ0FBQyxDQUFDdEosWUFBWTtBQUMvRTs7QUFFQTtBQUNBO0FBQ0E7QUFDTyxTQUFTdUosMkJBQTJCQSxDQUFBLEVBQUc7RUFDNUMsT0FBTztJQUNMQyxTQUFTLEVBQUVKLHVCQUF1QixDQUFDLENBQUM7SUFDcENLLFFBQVEsRUFBRUoscUJBQVEsQ0FBQ0MsRUFBRTtJQUNyQkksV0FBVyxFQUFFLElBQUk7SUFDakJDLG1CQUFtQixFQUFFLElBQUk7SUFDekJDLGlCQUFpQixFQUFFLElBQUk7SUFDdkJDLE9BQU8sRUFBRTdKLFlBQVksRUFBRWIsSUFBSSxJQUFJO0VBQ2pDLENBQUM7QUFDSCIsImlnbm9yZUxpc3QiOltdfQ==