@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,21 @@
1
+ import React from 'react';
2
+ export interface GroqSpeechRecognizerProps {
3
+ shouldListen: boolean;
4
+ speechStatusCallback: (status: boolean, transcript: string) => void;
5
+ speechResultCallback: (result: string) => void;
6
+ speechTranslationCallback?: (translation: string) => void;
7
+ clientSecret: string;
8
+ groqApiBaseUrl?: string;
9
+ groqTranscriptionEndpoint?: string;
10
+ stream?: boolean;
11
+ language?: string;
12
+ onError?: (error: Error) => void;
13
+ minAudioSize?: number;
14
+ }
15
+ export declare const GroqSpeechRecognizer: React.FC<GroqSpeechRecognizerProps>;
16
+ export declare function isGroqSpeechAvailable(): boolean;
17
+ export declare function getGroqSpeechCapabilities(): {
18
+ available: boolean;
19
+ supportedMimeTypes: string[];
20
+ platform: "ios" | "android" | "windows" | "macos" | "web";
21
+ };
@@ -0,0 +1,409 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.GroqSpeechRecognizer = void 0;
7
+ exports.getGroqSpeechCapabilities = getGroqSpeechCapabilities;
8
+ exports.isGroqSpeechAvailable = isGroqSpeechAvailable;
9
+ var _react = _interopRequireWildcard(require("react"));
10
+ var _reactNative = require("react-native");
11
+ var _logger = require("../logger");
12
+ var _groqTranscription = require("./utils/groq-transcription");
13
+ 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); }
14
+ /**
15
+ * Groq-based Speech Recognition using Whisper API
16
+ * Provides real-time streaming transcription with interim results
17
+ * Streams audio chunks to Groq as they accumulate, displaying interim transcripts
18
+ */
19
+
20
+ /**
21
+ * Groq-based speech recognizer using Whisper-large-v3 model
22
+ * Supports real-time streaming and batch transcription
23
+ */
24
+ const GroqSpeechRecognizer = ({
25
+ shouldListen,
26
+ speechStatusCallback,
27
+ speechResultCallback,
28
+ speechTranslationCallback,
29
+ clientSecret,
30
+ groqApiBaseUrl,
31
+ groqTranscriptionEndpoint,
32
+ stream = true,
33
+ language = 'en',
34
+ onError,
35
+ minAudioSize = 1000
36
+ }) => {
37
+ const [isRecording, setIsRecording] = (0, _react.useState)(false);
38
+ const mediaRecorderRef = (0, _react.useRef)(null);
39
+ const audioChunksRef = (0, _react.useRef)([]);
40
+ const streamRef = (0, _react.useRef)(null);
41
+ const startTimeRef = (0, _react.useRef)(0);
42
+ const lastMimeTypeRef = (0, _react.useRef)('audio/webm');
43
+
44
+ // Real-time streaming state
45
+ const streamAbortRef = (0, _react.useRef)(null);
46
+ const transcriptionStateRef = (0, _react.useRef)({
47
+ isStreaming: false,
48
+ lastSendTime: 0,
49
+ lastInterim: ''
50
+ });
51
+ const finalTranscriptRef = (0, _react.useRef)('');
52
+ const MIN_CHUNK_SIZE = 500; // bytes (before first send)
53
+ const SEND_INTERVAL = 1000; // ms (debounce interval)
54
+
55
+ /**
56
+ * Start audio recording (matching MLX approach)
57
+ */
58
+ const startRecording = (0, _react.useCallback)(async () => {
59
+ try {
60
+ _logger.logger.debug('Starting Groq recording...');
61
+
62
+ // Browser-specific audio constraints
63
+ const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
64
+ _logger.logger.debug(`Browser detection: Safari = ${isSafari}`);
65
+ const stream = await navigator.mediaDevices.getUserMedia({
66
+ audio: isSafari ? {
67
+ // Safari prefers simpler constraints
68
+ echoCancellation: false,
69
+ noiseSuppression: false,
70
+ autoGainControl: false
71
+ } : {
72
+ echoCancellation: true,
73
+ noiseSuppression: true,
74
+ autoGainControl: true,
75
+ sampleRate: 16000
76
+ }
77
+ });
78
+ _logger.logger.debug(`Audio stream tracks: ${stream.getAudioTracks().length}`);
79
+ stream.getAudioTracks().forEach((track, index) => {
80
+ _logger.logger.debug(`Track ${index}: ${track.label}, enabled: ${track.enabled}, readyState: ${track.readyState}`);
81
+ });
82
+ streamRef.current = stream;
83
+ audioChunksRef.current = [];
84
+ finalTranscriptRef.current = '';
85
+
86
+ // Create MediaRecorder with supported format
87
+ const mimeType = getSupportedMimeType();
88
+ _logger.logger.debug(`Using MIME type: ${mimeType}`);
89
+ lastMimeTypeRef.current = mimeType;
90
+
91
+ // Try creating MediaRecorder with minimal options first
92
+ let mediaRecorder;
93
+ try {
94
+ mediaRecorder = new MediaRecorder(stream, {
95
+ mimeType
96
+ });
97
+ _logger.logger.debug('MediaRecorder created with minimal options');
98
+ } catch (error) {
99
+ _logger.logger.warn('MediaRecorder constructor failed with minimal options, trying fallback:', error);
100
+ // Fallback without mimeType
101
+ mediaRecorder = new MediaRecorder(stream);
102
+ _logger.logger.debug('MediaRecorder created with fallback options');
103
+ }
104
+ mediaRecorderRef.current = mediaRecorder;
105
+
106
+ // Handle audio data - trigger streaming checks
107
+ mediaRecorder.ondataavailable = event => {
108
+ if (event.data.size > 0) {
109
+ audioChunksRef.current.push(event.data);
110
+ _logger.logger.debug(`Audio chunk: ${event.data.size} bytes (total: ${audioChunksRef.current.length} chunks)`);
111
+ // Check if we should stream
112
+ checkAndStreamAudio();
113
+ }
114
+ };
115
+
116
+ // Handle start
117
+ mediaRecorder.onstart = () => {
118
+ _logger.logger.debug('MediaRecorder started, state:', mediaRecorder.state);
119
+ };
120
+
121
+ // Handle recording stop
122
+ mediaRecorder.onstop = async () => {
123
+ _logger.logger.debug('Recording stopped, cleaning up stream...');
124
+ setIsRecording(false);
125
+
126
+ // Cancel active stream
127
+ if (streamAbortRef.current) {
128
+ streamAbortRef.current.abort();
129
+ streamAbortRef.current = null;
130
+ }
131
+
132
+ // Clean up stream (close mic immediately)
133
+ if (streamRef.current) {
134
+ streamRef.current.getTracks().forEach(track => track.stop());
135
+ streamRef.current = null;
136
+ }
137
+ _logger.logger.info('🛑 Groq recording stopped');
138
+ const finalTranscript = (finalTranscriptRef.current || transcriptionStateRef.current.lastInterim || '').trim();
139
+ let parseTranscript = finalTranscript;
140
+ try {
141
+ if (audioChunksRef.current.length > 0 && language && !language.startsWith('en')) {
142
+ const mimeType = lastMimeTypeRef.current || getSupportedMimeType();
143
+ const audioBlob = new Blob(audioChunksRef.current, {
144
+ type: mimeType
145
+ });
146
+ if (audioBlob.size > 0) {
147
+ const translated = await (0, _groqTranscription.translateGroqAudio)({
148
+ apiKey: clientSecret,
149
+ audioBlob,
150
+ mimeType,
151
+ language,
152
+ endpoint: resolveGroqTranslationEndpoint(groqApiBaseUrl, groqTranscriptionEndpoint)
153
+ });
154
+ if (translated) {
155
+ if (speechTranslationCallback) {
156
+ speechTranslationCallback(translated);
157
+ }
158
+ parseTranscript = translated;
159
+ }
160
+ }
161
+ }
162
+ } catch (error) {
163
+ _logger.logger.warn('Groq translation failed:', error);
164
+ } finally {
165
+ audioChunksRef.current = [];
166
+ }
167
+
168
+ // Stream will naturally end, just signal end of recording
169
+ speechStatusCallback(false, '');
170
+ if (parseTranscript) {
171
+ speechResultCallback(parseTranscript);
172
+ }
173
+ };
174
+
175
+ // Handle errors
176
+ mediaRecorder.onerror = event => {
177
+ _logger.logger.error('MediaRecorder error:', event);
178
+ setIsRecording(false);
179
+ const error = new Error('Recording failed');
180
+ if (onError) onError(error);
181
+ speechStatusCallback(false, '');
182
+ };
183
+
184
+ // Start recording with 100ms timeslice (matching MLX)
185
+ mediaRecorder.start(100);
186
+ _logger.logger.debug('MediaRecorder.start(100) called');
187
+ startTimeRef.current = Date.now();
188
+ setIsRecording(true);
189
+ // Don't send empty interim on start - wait for actual transcripts
190
+ // speechStatusCallback(true, '');
191
+ _logger.logger.info('🎤 Groq recording started');
192
+ } catch (error) {
193
+ _logger.logger.error('Failed to start recording:', error);
194
+ const err = error instanceof Error ? error : new Error(String(error));
195
+ if (onError) onError(err);
196
+ speechStatusCallback(false, '');
197
+ }
198
+ }, [speechStatusCallback, speechResultCallback, speechTranslationCallback, clientSecret, groqApiBaseUrl, groqTranscriptionEndpoint, language, onError]);
199
+
200
+ /**
201
+ * Stop audio recording
202
+ */
203
+ const stopRecording = (0, _react.useCallback)(() => {
204
+ _logger.logger.debug('Stop recording called');
205
+
206
+ // Stop all audio tracks immediately
207
+ if (streamRef.current) {
208
+ streamRef.current.getTracks().forEach(track => {
209
+ track.stop();
210
+ });
211
+ streamRef.current = null;
212
+ }
213
+ if (mediaRecorderRef.current && mediaRecorderRef.current.state === 'recording') {
214
+ mediaRecorderRef.current.stop();
215
+ }
216
+ }, []);
217
+
218
+ /**
219
+ * Stream audio to Groq and handle SSE responses
220
+ * Sends accumulated chunks and streams interim transcripts
221
+ */
222
+ const streamAudio = (0, _react.useCallback)(async audioBlob => {
223
+ if (transcriptionStateRef.current.isStreaming) {
224
+ _logger.logger.warn('Already streaming, skipping');
225
+ return;
226
+ }
227
+ transcriptionStateRef.current.isStreaming = true;
228
+ transcriptionStateRef.current.lastSendTime = Date.now();
229
+ try {
230
+ const mimeType = getSupportedMimeType();
231
+ _logger.logger.info(`📤 Streaming ${audioBlob.size} bytes to Groq (interim mode)...`);
232
+ streamAbortRef.current = new AbortController();
233
+ const state = transcriptionStateRef.current;
234
+ await (0, _groqTranscription.streamGroqTranscription)({
235
+ apiKey: clientSecret,
236
+ audioBlob,
237
+ mimeType,
238
+ language,
239
+ responseFormat: 'verbose_json',
240
+ stream,
241
+ endpoint: resolveGroqTranscriptionEndpoint(groqApiBaseUrl, groqTranscriptionEndpoint),
242
+ signal: streamAbortRef.current.signal,
243
+ onInterim: interimText => {
244
+ if (!interimText || interimText === state.lastInterim) return;
245
+ state.lastInterim = interimText;
246
+ finalTranscriptRef.current = interimText;
247
+ _logger.logger.info(`📝 Interim: "${interimText}"`);
248
+ speechStatusCallback(true, interimText);
249
+ }
250
+ });
251
+ } catch (error) {
252
+ if (error instanceof Error && error.name !== 'AbortError') {
253
+ _logger.logger.error('❌ Stream error:', error);
254
+ if (onError) onError(error);
255
+ }
256
+ } finally {
257
+ transcriptionStateRef.current.isStreaming = false;
258
+ }
259
+ }, [clientSecret, groqApiBaseUrl, groqTranscriptionEndpoint, language, onError, stream]);
260
+
261
+ /**
262
+ * Check if audio threshold met and stream to Groq
263
+ * Implements debounced streaming with minimum chunk size
264
+ */
265
+ const checkAndStreamAudio = (0, _react.useCallback)(() => {
266
+ const mimeType = getSupportedMimeType();
267
+ const audioBlob = new Blob(audioChunksRef.current, {
268
+ type: mimeType
269
+ });
270
+ const now = Date.now();
271
+ const state = transcriptionStateRef.current;
272
+
273
+ // Check: minimum chunk size reached?
274
+ if (audioBlob.size < MIN_CHUNK_SIZE) {
275
+ return;
276
+ }
277
+
278
+ // Check: already streaming?
279
+ if (state.isStreaming) {
280
+ return;
281
+ }
282
+
283
+ // Check: debounce interval respected?
284
+ if (now - state.lastSendTime < SEND_INTERVAL) {
285
+ return;
286
+ }
287
+
288
+ // All checks passed - start streaming
289
+ streamAudio(audioBlob);
290
+ }, [streamAudio]);
291
+
292
+ // SSE handling moved to shared helper (groq-transcription.ts)
293
+
294
+ /**
295
+ * Process collected audio chunks and send to Groq for transcription (matching MLX)
296
+ * CRITICAL: Guard with processingRef to prevent duplicate uploads
297
+ */
298
+ const processAudioChunks = (0, _react.useCallback)(async () => {
299
+ if (audioChunksRef.current.length === 0) {
300
+ _logger.logger.warn('No audio chunks to process');
301
+ return;
302
+ }
303
+
304
+ // In streaming mode, audio already processed via stream
305
+ _logger.logger.info('✅ Streaming completed');
306
+ audioChunksRef.current = [];
307
+ }, []);
308
+
309
+ /**
310
+ * Handle shouldListen prop changes
311
+ */
312
+ (0, _react.useEffect)(() => {
313
+ _logger.logger.debug(`shouldListen changed: ${shouldListen}, isRecording: ${isRecording}`);
314
+ if (shouldListen && !isRecording) {
315
+ _logger.logger.debug('✅ Starting recording');
316
+ startRecording();
317
+ } else if (!shouldListen && isRecording) {
318
+ _logger.logger.debug('❌ Stopping recording');
319
+ stopRecording();
320
+ }
321
+ }, [shouldListen, isRecording, startRecording, stopRecording]);
322
+
323
+ /**
324
+ * Cleanup on unmount
325
+ */
326
+ (0, _react.useEffect)(() => {
327
+ return () => {
328
+ if (streamAbortRef.current) {
329
+ streamAbortRef.current.abort();
330
+ }
331
+ if (mediaRecorderRef.current && mediaRecorderRef.current.state === 'recording') {
332
+ mediaRecorderRef.current.stop();
333
+ }
334
+ if (streamRef.current) {
335
+ streamRef.current.getTracks().forEach(track => track.stop());
336
+ }
337
+ };
338
+ }, []);
339
+ return /*#__PURE__*/_react.default.createElement(_reactNative.View, null);
340
+ };
341
+
342
+ /**
343
+ * Get supported MIME type for MediaRecorder
344
+ */
345
+ exports.GroqSpeechRecognizer = GroqSpeechRecognizer;
346
+ function getSupportedMimeType() {
347
+ const types = ['audio/webm;codecs=opus', 'audio/webm', 'audio/ogg;codecs=opus', 'audio/mp4', 'audio/wav'];
348
+ for (const type of types) {
349
+ if (MediaRecorder.isTypeSupported(type)) {
350
+ return type;
351
+ }
352
+ }
353
+
354
+ // Fallback
355
+ return 'audio/webm';
356
+ }
357
+ function resolveGroqTranscriptionEndpoint(baseUrl, overrideEndpoint) {
358
+ if (overrideEndpoint) return overrideEndpoint;
359
+ if (!baseUrl) return undefined;
360
+ const trimmed = baseUrl.replace(/\/+$/, '');
361
+ if (trimmed.endsWith('/openai/v1')) {
362
+ return `${trimmed}/audio/transcriptions`;
363
+ }
364
+ return `${trimmed}/openai/v1/audio/transcriptions`;
365
+ }
366
+ function resolveGroqTranslationEndpoint(baseUrl, overrideEndpoint) {
367
+ if (overrideEndpoint) {
368
+ return overrideEndpoint.includes('/audio/transcriptions') ? overrideEndpoint.replace('/audio/transcriptions', '/audio/translations') : overrideEndpoint;
369
+ }
370
+ if (!baseUrl) return undefined;
371
+ const trimmed = baseUrl.replace(/\/+$/, '');
372
+ if (trimmed.endsWith('/openai/v1')) {
373
+ return `${trimmed}/audio/translations`;
374
+ }
375
+ return `${trimmed}/openai/v1/audio/translations`;
376
+ }
377
+
378
+ /**
379
+ * Get file extension from MIME type
380
+ */
381
+ /**
382
+ * Check if Groq speech recognition is available
383
+ */
384
+ function isGroqSpeechAvailable() {
385
+ // Check if running in browser
386
+ if (typeof window === 'undefined') {
387
+ return false;
388
+ }
389
+
390
+ // Check for required APIs
391
+ const hasMediaDevices = navigator?.mediaDevices?.getUserMedia !== undefined;
392
+ const hasMediaRecorder = typeof MediaRecorder !== 'undefined';
393
+ return hasMediaDevices && hasMediaRecorder;
394
+ }
395
+
396
+ /**
397
+ * Get browser capabilities for Groq speech
398
+ */
399
+ function getGroqSpeechCapabilities() {
400
+ return {
401
+ available: isGroqSpeechAvailable(),
402
+ supportedMimeTypes: ['audio/webm;codecs=opus', 'audio/webm', 'audio/ogg;codecs=opus', 'audio/mp4', 'audio/wav'].filter(type => {
403
+ if (typeof MediaRecorder === 'undefined') return false;
404
+ return MediaRecorder.isTypeSupported(type);
405
+ }),
406
+ platform: _reactNative.Platform.OS
407
+ };
408
+ }
409
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVXaWxkY2FyZCIsInJlcXVpcmUiLCJfcmVhY3ROYXRpdmUiLCJfbG9nZ2VyIiwiX2dyb3FUcmFuc2NyaXB0aW9uIiwiZSIsInQiLCJXZWFrTWFwIiwiciIsIm4iLCJfX2VzTW9kdWxlIiwibyIsImkiLCJmIiwiX19wcm90b19fIiwiZGVmYXVsdCIsImhhcyIsImdldCIsInNldCIsImhhc093blByb3BlcnR5IiwiY2FsbCIsIk9iamVjdCIsImRlZmluZVByb3BlcnR5IiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yIiwiR3JvcVNwZWVjaFJlY29nbml6ZXIiLCJzaG91bGRMaXN0ZW4iLCJzcGVlY2hTdGF0dXNDYWxsYmFjayIsInNwZWVjaFJlc3VsdENhbGxiYWNrIiwic3BlZWNoVHJhbnNsYXRpb25DYWxsYmFjayIsImNsaWVudFNlY3JldCIsImdyb3FBcGlCYXNlVXJsIiwiZ3JvcVRyYW5zY3JpcHRpb25FbmRwb2ludCIsInN0cmVhbSIsImxhbmd1YWdlIiwib25FcnJvciIsIm1pbkF1ZGlvU2l6ZSIsImlzUmVjb3JkaW5nIiwic2V0SXNSZWNvcmRpbmciLCJ1c2VTdGF0ZSIsIm1lZGlhUmVjb3JkZXJSZWYiLCJ1c2VSZWYiLCJhdWRpb0NodW5rc1JlZiIsInN0cmVhbVJlZiIsInN0YXJ0VGltZVJlZiIsImxhc3RNaW1lVHlwZVJlZiIsInN0cmVhbUFib3J0UmVmIiwidHJhbnNjcmlwdGlvblN0YXRlUmVmIiwiaXNTdHJlYW1pbmciLCJsYXN0U2VuZFRpbWUiLCJsYXN0SW50ZXJpbSIsImZpbmFsVHJhbnNjcmlwdFJlZiIsIk1JTl9DSFVOS19TSVpFIiwiU0VORF9JTlRFUlZBTCIsInN0YXJ0UmVjb3JkaW5nIiwidXNlQ2FsbGJhY2siLCJsb2dnZXIiLCJkZWJ1ZyIsImlzU2FmYXJpIiwidGVzdCIsIm5hdmlnYXRvciIsInVzZXJBZ2VudCIsIm1lZGlhRGV2aWNlcyIsImdldFVzZXJNZWRpYSIsImF1ZGlvIiwiZWNob0NhbmNlbGxhdGlvbiIsIm5vaXNlU3VwcHJlc3Npb24iLCJhdXRvR2FpbkNvbnRyb2wiLCJzYW1wbGVSYXRlIiwiZ2V0QXVkaW9UcmFja3MiLCJsZW5ndGgiLCJmb3JFYWNoIiwidHJhY2siLCJpbmRleCIsImxhYmVsIiwiZW5hYmxlZCIsInJlYWR5U3RhdGUiLCJjdXJyZW50IiwibWltZVR5cGUiLCJnZXRTdXBwb3J0ZWRNaW1lVHlwZSIsIm1lZGlhUmVjb3JkZXIiLCJNZWRpYVJlY29yZGVyIiwiZXJyb3IiLCJ3YXJuIiwib25kYXRhYXZhaWxhYmxlIiwiZXZlbnQiLCJkYXRhIiwic2l6ZSIsInB1c2giLCJjaGVja0FuZFN0cmVhbUF1ZGlvIiwib25zdGFydCIsInN0YXRlIiwib25zdG9wIiwiYWJvcnQiLCJnZXRUcmFja3MiLCJzdG9wIiwiaW5mbyIsImZpbmFsVHJhbnNjcmlwdCIsInRyaW0iLCJwYXJzZVRyYW5zY3JpcHQiLCJzdGFydHNXaXRoIiwiYXVkaW9CbG9iIiwiQmxvYiIsInR5cGUiLCJ0cmFuc2xhdGVkIiwidHJhbnNsYXRlR3JvcUF1ZGlvIiwiYXBpS2V5IiwiZW5kcG9pbnQiLCJyZXNvbHZlR3JvcVRyYW5zbGF0aW9uRW5kcG9pbnQiLCJvbmVycm9yIiwiRXJyb3IiLCJzdGFydCIsIkRhdGUiLCJub3ciLCJlcnIiLCJTdHJpbmciLCJzdG9wUmVjb3JkaW5nIiwic3RyZWFtQXVkaW8iLCJBYm9ydENvbnRyb2xsZXIiLCJzdHJlYW1Hcm9xVHJhbnNjcmlwdGlvbiIsInJlc3BvbnNlRm9ybWF0IiwicmVzb2x2ZUdyb3FUcmFuc2NyaXB0aW9uRW5kcG9pbnQiLCJzaWduYWwiLCJvbkludGVyaW0iLCJpbnRlcmltVGV4dCIsIm5hbWUiLCJwcm9jZXNzQXVkaW9DaHVua3MiLCJ1c2VFZmZlY3QiLCJjcmVhdGVFbGVtZW50IiwiVmlldyIsImV4cG9ydHMiLCJ0eXBlcyIsImlzVHlwZVN1cHBvcnRlZCIsImJhc2VVcmwiLCJvdmVycmlkZUVuZHBvaW50IiwidW5kZWZpbmVkIiwidHJpbW1lZCIsInJlcGxhY2UiLCJlbmRzV2l0aCIsImluY2x1ZGVzIiwiaXNHcm9xU3BlZWNoQXZhaWxhYmxlIiwid2luZG93IiwiaGFzTWVkaWFEZXZpY2VzIiwiaGFzTWVkaWFSZWNvcmRlciIsImdldEdyb3FTcGVlY2hDYXBhYmlsaXRpZXMiLCJhdmFpbGFibGUiLCJzdXBwb3J0ZWRNaW1lVHlwZXMiLCJmaWx0ZXIiLCJwbGF0Zm9ybSIsIlBsYXRmb3JtIiwiT1MiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvc3BlZWNoLXJlY29nbml0aW9uL3NwZWVjaC1yZWNvZ25pdGlvbi1ncm9xLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdyb3EtYmFzZWQgU3BlZWNoIFJlY29nbml0aW9uIHVzaW5nIFdoaXNwZXIgQVBJXG4gKiBQcm92aWRlcyByZWFsLXRpbWUgc3RyZWFtaW5nIHRyYW5zY3JpcHRpb24gd2l0aCBpbnRlcmltIHJlc3VsdHNcbiAqIFN0cmVhbXMgYXVkaW8gY2h1bmtzIHRvIEdyb3EgYXMgdGhleSBhY2N1bXVsYXRlLCBkaXNwbGF5aW5nIGludGVyaW0gdHJhbnNjcmlwdHNcbiAqL1xuXG5pbXBvcnQgUmVhY3QsIHsgdXNlRWZmZWN0LCB1c2VTdGF0ZSwgdXNlUmVmLCB1c2VDYWxsYmFjayB9IGZyb20gJ3JlYWN0JztcbmltcG9ydCB7IFZpZXcsIFBsYXRmb3JtIH0gZnJvbSAncmVhY3QtbmF0aXZlJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uL2xvZ2dlcic7XG5pbXBvcnQgeyBzdHJlYW1Hcm9xVHJhbnNjcmlwdGlvbiwgdHJhbnNsYXRlR3JvcUF1ZGlvIH0gZnJvbSAnLi91dGlscy9ncm9xLXRyYW5zY3JpcHRpb24nO1xuXG5leHBvcnQgaW50ZXJmYWNlIEdyb3FTcGVlY2hSZWNvZ25pemVyUHJvcHMge1xuICBzaG91bGRMaXN0ZW46IGJvb2xlYW47XG4gIHNwZWVjaFN0YXR1c0NhbGxiYWNrOiAoc3RhdHVzOiBib29sZWFuLCB0cmFuc2NyaXB0OiBzdHJpbmcpID0+IHZvaWQ7XG4gIHNwZWVjaFJlc3VsdENhbGxiYWNrOiAocmVzdWx0OiBzdHJpbmcpID0+IHZvaWQ7XG4gIHNwZWVjaFRyYW5zbGF0aW9uQ2FsbGJhY2s/OiAodHJhbnNsYXRpb246IHN0cmluZykgPT4gdm9pZDtcbiAgY2xpZW50U2VjcmV0OiBzdHJpbmc7XG4gIGdyb3FBcGlCYXNlVXJsPzogc3RyaW5nO1xuICBncm9xVHJhbnNjcmlwdGlvbkVuZHBvaW50Pzogc3RyaW5nO1xuICBzdHJlYW0/OiBib29sZWFuO1xuICBsYW5ndWFnZT86IHN0cmluZztcbiAgb25FcnJvcj86IChlcnJvcjogRXJyb3IpID0+IHZvaWQ7XG4gIG1pbkF1ZGlvU2l6ZT86IG51bWJlcjsgLy8gTWluaW11bSBhdWRpbyBzaXplIGluIGJ5dGVzIChkZWZhdWx0IDEwMDApXG59XG5cbi8qKlxuICogR3JvcS1iYXNlZCBzcGVlY2ggcmVjb2duaXplciB1c2luZyBXaGlzcGVyLWxhcmdlLXYzIG1vZGVsXG4gKiBTdXBwb3J0cyByZWFsLXRpbWUgc3RyZWFtaW5nIGFuZCBiYXRjaCB0cmFuc2NyaXB0aW9uXG4gKi9cbmV4cG9ydCBjb25zdCBHcm9xU3BlZWNoUmVjb2duaXplcjogUmVhY3QuRkM8R3JvcVNwZWVjaFJlY29nbml6ZXJQcm9wcz4gPSAoe1xuICBzaG91bGRMaXN0ZW4sXG4gIHNwZWVjaFN0YXR1c0NhbGxiYWNrLFxuICBzcGVlY2hSZXN1bHRDYWxsYmFjayxcbiAgc3BlZWNoVHJhbnNsYXRpb25DYWxsYmFjayxcbiAgY2xpZW50U2VjcmV0LFxuICBncm9xQXBpQmFzZVVybCxcbiAgZ3JvcVRyYW5zY3JpcHRpb25FbmRwb2ludCxcbiAgc3RyZWFtID0gdHJ1ZSxcbiAgbGFuZ3VhZ2UgPSAnZW4nLFxuICBvbkVycm9yLFxuICBtaW5BdWRpb1NpemUgPSAxMDAwLFxufSkgPT4ge1xuICBjb25zdCBbaXNSZWNvcmRpbmcsIHNldElzUmVjb3JkaW5nXSA9IHVzZVN0YXRlKGZhbHNlKTtcbiAgY29uc3QgbWVkaWFSZWNvcmRlclJlZiA9IHVzZVJlZjxNZWRpYVJlY29yZGVyIHwgbnVsbD4obnVsbCk7XG4gIGNvbnN0IGF1ZGlvQ2h1bmtzUmVmID0gdXNlUmVmPEJsb2JbXT4oW10pO1xuICBjb25zdCBzdHJlYW1SZWYgPSB1c2VSZWY8TWVkaWFTdHJlYW0gfCBudWxsPihudWxsKTtcbiAgY29uc3Qgc3RhcnRUaW1lUmVmID0gdXNlUmVmPG51bWJlcj4oMCk7XG4gIGNvbnN0IGxhc3RNaW1lVHlwZVJlZiA9IHVzZVJlZjxzdHJpbmc+KCdhdWRpby93ZWJtJyk7XG4gIFxuICAvLyBSZWFsLXRpbWUgc3RyZWFtaW5nIHN0YXRlXG4gIGNvbnN0IHN0cmVhbUFib3J0UmVmID0gdXNlUmVmPEFib3J0Q29udHJvbGxlciB8IG51bGw+KG51bGwpO1xuICBjb25zdCB0cmFuc2NyaXB0aW9uU3RhdGVSZWYgPSB1c2VSZWYoe1xuICAgIGlzU3RyZWFtaW5nOiBmYWxzZSxcbiAgICBsYXN0U2VuZFRpbWU6IDAsXG4gICAgbGFzdEludGVyaW06ICcnLFxuICB9KTtcbiAgY29uc3QgZmluYWxUcmFuc2NyaXB0UmVmID0gdXNlUmVmPHN0cmluZz4oJycpO1xuICBjb25zdCBNSU5fQ0hVTktfU0laRSA9IDUwMDsgLy8gYnl0ZXMgKGJlZm9yZSBmaXJzdCBzZW5kKVxuICBjb25zdCBTRU5EX0lOVEVSVkFMID0gMTAwMDsgLy8gbXMgKGRlYm91bmNlIGludGVydmFsKVxuXG4gIC8qKlxuICAgKiBTdGFydCBhdWRpbyByZWNvcmRpbmcgKG1hdGNoaW5nIE1MWCBhcHByb2FjaClcbiAgICovXG4gIGNvbnN0IHN0YXJ0UmVjb3JkaW5nID0gdXNlQ2FsbGJhY2soYXN5bmMgKCkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBsb2dnZXIuZGVidWcoJ1N0YXJ0aW5nIEdyb3EgcmVjb3JkaW5nLi4uJyk7XG5cbiAgICAgIC8vIEJyb3dzZXItc3BlY2lmaWMgYXVkaW8gY29uc3RyYWludHNcbiAgICAgIGNvbnN0IGlzU2FmYXJpID0gL14oKD8hY2hyb21lfGFuZHJvaWQpLikqc2FmYXJpL2kudGVzdChuYXZpZ2F0b3IudXNlckFnZW50KTtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhgQnJvd3NlciBkZXRlY3Rpb246IFNhZmFyaSA9ICR7aXNTYWZhcml9YCk7XG5cbiAgICAgIGNvbnN0IHN0cmVhbSA9IGF3YWl0IG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhKHtcbiAgICAgICAgYXVkaW86IGlzU2FmYXJpID8ge1xuICAgICAgICAgIC8vIFNhZmFyaSBwcmVmZXJzIHNpbXBsZXIgY29uc3RyYWludHNcbiAgICAgICAgICBlY2hvQ2FuY2VsbGF0aW9uOiBmYWxzZSxcbiAgICAgICAgICBub2lzZVN1cHByZXNzaW9uOiBmYWxzZSxcbiAgICAgICAgICBhdXRvR2FpbkNvbnRyb2w6IGZhbHNlLFxuICAgICAgICB9IDoge1xuICAgICAgICAgIGVjaG9DYW5jZWxsYXRpb246IHRydWUsXG4gICAgICAgICAgbm9pc2VTdXBwcmVzc2lvbjogdHJ1ZSxcbiAgICAgICAgICBhdXRvR2FpbkNvbnRyb2w6IHRydWUsXG4gICAgICAgICAgc2FtcGxlUmF0ZTogMTYwMDAsXG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgbG9nZ2VyLmRlYnVnKGBBdWRpbyBzdHJlYW0gdHJhY2tzOiAke3N0cmVhbS5nZXRBdWRpb1RyYWNrcygpLmxlbmd0aH1gKTtcbiAgICAgIHN0cmVhbS5nZXRBdWRpb1RyYWNrcygpLmZvckVhY2goKHRyYWNrLCBpbmRleCkgPT4ge1xuICAgICAgICBsb2dnZXIuZGVidWcoYFRyYWNrICR7aW5kZXh9OiAke3RyYWNrLmxhYmVsfSwgZW5hYmxlZDogJHt0cmFjay5lbmFibGVkfSwgcmVhZHlTdGF0ZTogJHt0cmFjay5yZWFkeVN0YXRlfWApO1xuICAgICAgfSk7XG5cbiAgICAgIHN0cmVhbVJlZi5jdXJyZW50ID0gc3RyZWFtO1xuICAgICAgYXVkaW9DaHVua3NSZWYuY3VycmVudCA9IFtdO1xuICAgICAgZmluYWxUcmFuc2NyaXB0UmVmLmN1cnJlbnQgPSAnJztcblxuICAgICAgLy8gQ3JlYXRlIE1lZGlhUmVjb3JkZXIgd2l0aCBzdXBwb3J0ZWQgZm9ybWF0XG4gICAgICBjb25zdCBtaW1lVHlwZSA9IGdldFN1cHBvcnRlZE1pbWVUeXBlKCk7XG4gICAgICBsb2dnZXIuZGVidWcoYFVzaW5nIE1JTUUgdHlwZTogJHttaW1lVHlwZX1gKTtcbiAgICAgIGxhc3RNaW1lVHlwZVJlZi5jdXJyZW50ID0gbWltZVR5cGU7XG5cbiAgICAgIC8vIFRyeSBjcmVhdGluZyBNZWRpYVJlY29yZGVyIHdpdGggbWluaW1hbCBvcHRpb25zIGZpcnN0XG4gICAgICBsZXQgbWVkaWFSZWNvcmRlcjogTWVkaWFSZWNvcmRlcjtcbiAgICAgIHRyeSB7XG4gICAgICAgIG1lZGlhUmVjb3JkZXIgPSBuZXcgTWVkaWFSZWNvcmRlcihzdHJlYW0sIHsgbWltZVR5cGUgfSk7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZygnTWVkaWFSZWNvcmRlciBjcmVhdGVkIHdpdGggbWluaW1hbCBvcHRpb25zJyk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dnZXIud2FybignTWVkaWFSZWNvcmRlciBjb25zdHJ1Y3RvciBmYWlsZWQgd2l0aCBtaW5pbWFsIG9wdGlvbnMsIHRyeWluZyBmYWxsYmFjazonLCBlcnJvcik7XG4gICAgICAgIC8vIEZhbGxiYWNrIHdpdGhvdXQgbWltZVR5cGVcbiAgICAgICAgbWVkaWFSZWNvcmRlciA9IG5ldyBNZWRpYVJlY29yZGVyKHN0cmVhbSk7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZygnTWVkaWFSZWNvcmRlciBjcmVhdGVkIHdpdGggZmFsbGJhY2sgb3B0aW9ucycpO1xuICAgICAgfVxuXG4gICAgICBtZWRpYVJlY29yZGVyUmVmLmN1cnJlbnQgPSBtZWRpYVJlY29yZGVyO1xuXG4gICAgICAvLyBIYW5kbGUgYXVkaW8gZGF0YSAtIHRyaWdnZXIgc3RyZWFtaW5nIGNoZWNrc1xuICAgICAgbWVkaWFSZWNvcmRlci5vbmRhdGFhdmFpbGFibGUgPSAoZXZlbnQ6IEJsb2JFdmVudCkgPT4ge1xuICAgICAgICBpZiAoZXZlbnQuZGF0YS5zaXplID4gMCkge1xuICAgICAgICAgIGF1ZGlvQ2h1bmtzUmVmLmN1cnJlbnQucHVzaChldmVudC5kYXRhKTtcbiAgICAgICAgICBsb2dnZXIuZGVidWcoYEF1ZGlvIGNodW5rOiAke2V2ZW50LmRhdGEuc2l6ZX0gYnl0ZXMgKHRvdGFsOiAke2F1ZGlvQ2h1bmtzUmVmLmN1cnJlbnQubGVuZ3RofSBjaHVua3MpYCk7XG4gICAgICAgICAgLy8gQ2hlY2sgaWYgd2Ugc2hvdWxkIHN0cmVhbVxuICAgICAgICAgIGNoZWNrQW5kU3RyZWFtQXVkaW8oKTtcbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgLy8gSGFuZGxlIHN0YXJ0XG4gICAgICBtZWRpYVJlY29yZGVyLm9uc3RhcnQgPSAoKSA9PiB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZygnTWVkaWFSZWNvcmRlciBzdGFydGVkLCBzdGF0ZTonLCBtZWRpYVJlY29yZGVyLnN0YXRlKTtcbiAgICAgIH07XG5cbiAgICAgIC8vIEhhbmRsZSByZWNvcmRpbmcgc3RvcFxuICAgICAgbWVkaWFSZWNvcmRlci5vbnN0b3AgPSBhc3luYyAoKSA9PiB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZygnUmVjb3JkaW5nIHN0b3BwZWQsIGNsZWFuaW5nIHVwIHN0cmVhbS4uLicpO1xuICAgICAgICBzZXRJc1JlY29yZGluZyhmYWxzZSk7XG4gICAgICAgIFxuICAgICAgICAvLyBDYW5jZWwgYWN0aXZlIHN0cmVhbVxuICAgICAgICBpZiAoc3RyZWFtQWJvcnRSZWYuY3VycmVudCkge1xuICAgICAgICAgIHN0cmVhbUFib3J0UmVmLmN1cnJlbnQuYWJvcnQoKTtcbiAgICAgICAgICBzdHJlYW1BYm9ydFJlZi5jdXJyZW50ID0gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENsZWFuIHVwIHN0cmVhbSAoY2xvc2UgbWljIGltbWVkaWF0ZWx5KVxuICAgICAgICBpZiAoc3RyZWFtUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgICBzdHJlYW1SZWYuY3VycmVudC5nZXRUcmFja3MoKS5mb3JFYWNoKHRyYWNrID0+IHRyYWNrLnN0b3AoKSk7XG4gICAgICAgICAgc3RyZWFtUmVmLmN1cnJlbnQgPSBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgbG9nZ2VyLmluZm8oJ/Cfm5EgR3JvcSByZWNvcmRpbmcgc3RvcHBlZCcpO1xuXG4gICAgICAgIGNvbnN0IGZpbmFsVHJhbnNjcmlwdCA9IChcbiAgICAgICAgICBmaW5hbFRyYW5zY3JpcHRSZWYuY3VycmVudCB8fFxuICAgICAgICAgIHRyYW5zY3JpcHRpb25TdGF0ZVJlZi5jdXJyZW50Lmxhc3RJbnRlcmltIHx8XG4gICAgICAgICAgJydcbiAgICAgICAgKS50cmltKCk7XG4gICAgICAgIGxldCBwYXJzZVRyYW5zY3JpcHQgPSBmaW5hbFRyYW5zY3JpcHQ7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBpZiAoXG4gICAgICAgICAgICBhdWRpb0NodW5rc1JlZi5jdXJyZW50Lmxlbmd0aCA+IDAgJiZcbiAgICAgICAgICAgIGxhbmd1YWdlICYmXG4gICAgICAgICAgICAhbGFuZ3VhZ2Uuc3RhcnRzV2l0aCgnZW4nKVxuICAgICAgICAgICkge1xuICAgICAgICAgICAgY29uc3QgbWltZVR5cGUgPSBsYXN0TWltZVR5cGVSZWYuY3VycmVudCB8fCBnZXRTdXBwb3J0ZWRNaW1lVHlwZSgpO1xuICAgICAgICAgICAgY29uc3QgYXVkaW9CbG9iID0gbmV3IEJsb2IoYXVkaW9DaHVua3NSZWYuY3VycmVudCwgeyB0eXBlOiBtaW1lVHlwZSB9KTtcbiAgICAgICAgICAgIGlmIChhdWRpb0Jsb2Iuc2l6ZSA+IDApIHtcbiAgICAgICAgICAgICAgY29uc3QgdHJhbnNsYXRlZCA9IGF3YWl0IHRyYW5zbGF0ZUdyb3FBdWRpbyh7XG4gICAgICAgICAgICAgICAgYXBpS2V5OiBjbGllbnRTZWNyZXQsXG4gICAgICAgICAgICAgICAgYXVkaW9CbG9iLFxuICAgICAgICAgICAgICAgIG1pbWVUeXBlLFxuICAgICAgICAgICAgICAgIGxhbmd1YWdlLFxuICAgICAgICAgICAgICAgIGVuZHBvaW50OiByZXNvbHZlR3JvcVRyYW5zbGF0aW9uRW5kcG9pbnQoXG4gICAgICAgICAgICAgICAgICBncm9xQXBpQmFzZVVybCxcbiAgICAgICAgICAgICAgICAgIGdyb3FUcmFuc2NyaXB0aW9uRW5kcG9pbnQsXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIGlmICh0cmFuc2xhdGVkKSB7XG4gICAgICAgICAgICAgICAgaWYgKHNwZWVjaFRyYW5zbGF0aW9uQ2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICAgIHNwZWVjaFRyYW5zbGF0aW9uQ2FsbGJhY2sodHJhbnNsYXRlZCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHBhcnNlVHJhbnNjcmlwdCA9IHRyYW5zbGF0ZWQ7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgbG9nZ2VyLndhcm4oJ0dyb3EgdHJhbnNsYXRpb24gZmFpbGVkOicsIGVycm9yKTtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICBhdWRpb0NodW5rc1JlZi5jdXJyZW50ID0gW107XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTdHJlYW0gd2lsbCBuYXR1cmFsbHkgZW5kLCBqdXN0IHNpZ25hbCBlbmQgb2YgcmVjb3JkaW5nXG4gICAgICAgIHNwZWVjaFN0YXR1c0NhbGxiYWNrKGZhbHNlLCAnJyk7XG4gICAgICAgIGlmIChwYXJzZVRyYW5zY3JpcHQpIHtcbiAgICAgICAgICBzcGVlY2hSZXN1bHRDYWxsYmFjayhwYXJzZVRyYW5zY3JpcHQpO1xuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICAvLyBIYW5kbGUgZXJyb3JzXG4gICAgICBtZWRpYVJlY29yZGVyLm9uZXJyb3IgPSAoZXZlbnQ6IEV2ZW50KSA9PiB7XG4gICAgICAgIGxvZ2dlci5lcnJvcignTWVkaWFSZWNvcmRlciBlcnJvcjonLCBldmVudCk7XG4gICAgICAgIHNldElzUmVjb3JkaW5nKGZhbHNlKTtcbiAgICAgICAgY29uc3QgZXJyb3IgPSBuZXcgRXJyb3IoJ1JlY29yZGluZyBmYWlsZWQnKTtcbiAgICAgICAgaWYgKG9uRXJyb3IpIG9uRXJyb3IoZXJyb3IpO1xuICAgICAgICBzcGVlY2hTdGF0dXNDYWxsYmFjayhmYWxzZSwgJycpO1xuICAgICAgfTtcblxuICAgICAgLy8gU3RhcnQgcmVjb3JkaW5nIHdpdGggMTAwbXMgdGltZXNsaWNlIChtYXRjaGluZyBNTFgpXG4gICAgICBtZWRpYVJlY29yZGVyLnN0YXJ0KDEwMCk7XG4gICAgICBsb2dnZXIuZGVidWcoJ01lZGlhUmVjb3JkZXIuc3RhcnQoMTAwKSBjYWxsZWQnKTtcblxuICAgICAgc3RhcnRUaW1lUmVmLmN1cnJlbnQgPSBEYXRlLm5vdygpO1xuICAgICAgc2V0SXNSZWNvcmRpbmcodHJ1ZSk7XG4gICAgICAvLyBEb24ndCBzZW5kIGVtcHR5IGludGVyaW0gb24gc3RhcnQgLSB3YWl0IGZvciBhY3R1YWwgdHJhbnNjcmlwdHNcbiAgICAgIC8vIHNwZWVjaFN0YXR1c0NhbGxiYWNrKHRydWUsICcnKTtcbiAgICAgIGxvZ2dlci5pbmZvKCfwn46kIEdyb3EgcmVjb3JkaW5nIHN0YXJ0ZWQnKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdGYWlsZWQgdG8gc3RhcnQgcmVjb3JkaW5nOicsIGVycm9yKTtcbiAgICAgIGNvbnN0IGVyciA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcihTdHJpbmcoZXJyb3IpKTtcbiAgICAgIGlmIChvbkVycm9yKSBvbkVycm9yKGVycik7XG4gICAgICBzcGVlY2hTdGF0dXNDYWxsYmFjayhmYWxzZSwgJycpO1xuICAgIH1cbiAgfSwgW1xuICAgIHNwZWVjaFN0YXR1c0NhbGxiYWNrLFxuICAgIHNwZWVjaFJlc3VsdENhbGxiYWNrLFxuICAgIHNwZWVjaFRyYW5zbGF0aW9uQ2FsbGJhY2ssXG4gICAgY2xpZW50U2VjcmV0LFxuICAgIGdyb3FBcGlCYXNlVXJsLFxuICAgIGdyb3FUcmFuc2NyaXB0aW9uRW5kcG9pbnQsXG4gICAgbGFuZ3VhZ2UsXG4gICAgb25FcnJvcixcbiAgXSk7XG5cbiAgLyoqXG4gICAqIFN0b3AgYXVkaW8gcmVjb3JkaW5nXG4gICAqL1xuICBjb25zdCBzdG9wUmVjb3JkaW5nID0gdXNlQ2FsbGJhY2soKCkgPT4ge1xuICAgIGxvZ2dlci5kZWJ1ZygnU3RvcCByZWNvcmRpbmcgY2FsbGVkJyk7XG4gICAgXG4gICAgLy8gU3RvcCBhbGwgYXVkaW8gdHJhY2tzIGltbWVkaWF0ZWx5XG4gICAgaWYgKHN0cmVhbVJlZi5jdXJyZW50KSB7XG4gICAgICBzdHJlYW1SZWYuY3VycmVudC5nZXRUcmFja3MoKS5mb3JFYWNoKCh0cmFjaykgPT4ge1xuICAgICAgICB0cmFjay5zdG9wKCk7XG4gICAgICB9KTtcbiAgICAgIHN0cmVhbVJlZi5jdXJyZW50ID0gbnVsbDtcbiAgICB9XG4gICAgXG4gICAgaWYgKG1lZGlhUmVjb3JkZXJSZWYuY3VycmVudCAmJiBtZWRpYVJlY29yZGVyUmVmLmN1cnJlbnQuc3RhdGUgPT09ICdyZWNvcmRpbmcnKSB7XG4gICAgICBtZWRpYVJlY29yZGVyUmVmLmN1cnJlbnQuc3RvcCgpO1xuICAgIH1cbiAgfSwgW10pO1xuXG4gIC8qKlxuICAgKiBTdHJlYW0gYXVkaW8gdG8gR3JvcSBhbmQgaGFuZGxlIFNTRSByZXNwb25zZXNcbiAgICogU2VuZHMgYWNjdW11bGF0ZWQgY2h1bmtzIGFuZCBzdHJlYW1zIGludGVyaW0gdHJhbnNjcmlwdHNcbiAgICovXG4gIGNvbnN0IHN0cmVhbUF1ZGlvID0gdXNlQ2FsbGJhY2soYXN5bmMgKGF1ZGlvQmxvYjogQmxvYikgPT4ge1xuICAgIGlmICh0cmFuc2NyaXB0aW9uU3RhdGVSZWYuY3VycmVudC5pc1N0cmVhbWluZykge1xuICAgICAgbG9nZ2VyLndhcm4oJ0FscmVhZHkgc3RyZWFtaW5nLCBza2lwcGluZycpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRyYW5zY3JpcHRpb25TdGF0ZVJlZi5jdXJyZW50LmlzU3RyZWFtaW5nID0gdHJ1ZTtcbiAgICB0cmFuc2NyaXB0aW9uU3RhdGVSZWYuY3VycmVudC5sYXN0U2VuZFRpbWUgPSBEYXRlLm5vdygpO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IG1pbWVUeXBlID0gZ2V0U3VwcG9ydGVkTWltZVR5cGUoKTtcbiAgICAgIGxvZ2dlci5pbmZvKGDwn5OkIFN0cmVhbWluZyAke2F1ZGlvQmxvYi5zaXplfSBieXRlcyB0byBHcm9xIChpbnRlcmltIG1vZGUpLi4uYCk7XG5cbiAgICAgIHN0cmVhbUFib3J0UmVmLmN1cnJlbnQgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gICAgICBjb25zdCBzdGF0ZSA9IHRyYW5zY3JpcHRpb25TdGF0ZVJlZi5jdXJyZW50O1xuXG4gICAgICBhd2FpdCBzdHJlYW1Hcm9xVHJhbnNjcmlwdGlvbih7XG4gICAgICAgIGFwaUtleTogY2xpZW50U2VjcmV0LFxuICAgICAgICBhdWRpb0Jsb2IsXG4gICAgICAgIG1pbWVUeXBlLFxuICAgICAgICBsYW5ndWFnZSxcbiAgICAgICAgcmVzcG9uc2VGb3JtYXQ6ICd2ZXJib3NlX2pzb24nLFxuICAgICAgICBzdHJlYW0sXG4gICAgICAgIGVuZHBvaW50OiByZXNvbHZlR3JvcVRyYW5zY3JpcHRpb25FbmRwb2ludChcbiAgICAgICAgICBncm9xQXBpQmFzZVVybCxcbiAgICAgICAgICBncm9xVHJhbnNjcmlwdGlvbkVuZHBvaW50LFxuICAgICAgICApLFxuICAgICAgICBzaWduYWw6IHN0cmVhbUFib3J0UmVmLmN1cnJlbnQuc2lnbmFsLFxuICAgICAgICBvbkludGVyaW06IChpbnRlcmltVGV4dCkgPT4ge1xuICAgICAgICAgIGlmICghaW50ZXJpbVRleHQgfHwgaW50ZXJpbVRleHQgPT09IHN0YXRlLmxhc3RJbnRlcmltKSByZXR1cm47XG4gICAgICAgICAgc3RhdGUubGFzdEludGVyaW0gPSBpbnRlcmltVGV4dDtcbiAgICAgICAgICBmaW5hbFRyYW5zY3JpcHRSZWYuY3VycmVudCA9IGludGVyaW1UZXh0O1xuICAgICAgICAgIGxvZ2dlci5pbmZvKGDwn5OdIEludGVyaW06IFwiJHtpbnRlcmltVGV4dH1cImApO1xuICAgICAgICAgIHNwZWVjaFN0YXR1c0NhbGxiYWNrKHRydWUsIGludGVyaW1UZXh0KTtcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvciAmJiBlcnJvci5uYW1lICE9PSAnQWJvcnRFcnJvcicpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKCfinYwgU3RyZWFtIGVycm9yOicsIGVycm9yKTtcbiAgICAgICAgaWYgKG9uRXJyb3IpIG9uRXJyb3IoZXJyb3IpO1xuICAgICAgfVxuICAgIH0gZmluYWxseSB7XG4gICAgICB0cmFuc2NyaXB0aW9uU3RhdGVSZWYuY3VycmVudC5pc1N0cmVhbWluZyA9IGZhbHNlO1xuICAgIH1cbiAgfSwgW2NsaWVudFNlY3JldCwgZ3JvcUFwaUJhc2VVcmwsIGdyb3FUcmFuc2NyaXB0aW9uRW5kcG9pbnQsIGxhbmd1YWdlLCBvbkVycm9yLCBzdHJlYW1dKTtcblxuICAvKipcbiAgICogQ2hlY2sgaWYgYXVkaW8gdGhyZXNob2xkIG1ldCBhbmQgc3RyZWFtIHRvIEdyb3FcbiAgICogSW1wbGVtZW50cyBkZWJvdW5jZWQgc3RyZWFtaW5nIHdpdGggbWluaW11bSBjaHVuayBzaXplXG4gICAqL1xuICBjb25zdCBjaGVja0FuZFN0cmVhbUF1ZGlvID0gdXNlQ2FsbGJhY2soKCkgPT4ge1xuICAgIGNvbnN0IG1pbWVUeXBlID0gZ2V0U3VwcG9ydGVkTWltZVR5cGUoKTtcbiAgICBjb25zdCBhdWRpb0Jsb2IgPSBuZXcgQmxvYihhdWRpb0NodW5rc1JlZi5jdXJyZW50LCB7IHR5cGU6IG1pbWVUeXBlIH0pO1xuICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG5cbiAgICBjb25zdCBzdGF0ZSA9IHRyYW5zY3JpcHRpb25TdGF0ZVJlZi5jdXJyZW50O1xuXG4gICAgLy8gQ2hlY2s6IG1pbmltdW0gY2h1bmsgc2l6ZSByZWFjaGVkP1xuICAgIGlmIChhdWRpb0Jsb2Iuc2l6ZSA8IE1JTl9DSFVOS19TSVpFKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gQ2hlY2s6IGFscmVhZHkgc3RyZWFtaW5nP1xuICAgIGlmIChzdGF0ZS5pc1N0cmVhbWluZykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIENoZWNrOiBkZWJvdW5jZSBpbnRlcnZhbCByZXNwZWN0ZWQ/XG4gICAgaWYgKG5vdyAtIHN0YXRlLmxhc3RTZW5kVGltZSA8IFNFTkRfSU5URVJWQUwpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBBbGwgY2hlY2tzIHBhc3NlZCAtIHN0YXJ0IHN0cmVhbWluZ1xuICAgIHN0cmVhbUF1ZGlvKGF1ZGlvQmxvYik7XG4gIH0sIFtzdHJlYW1BdWRpb10pO1xuXG4gIC8vIFNTRSBoYW5kbGluZyBtb3ZlZCB0byBzaGFyZWQgaGVscGVyIChncm9xLXRyYW5zY3JpcHRpb24udHMpXG5cbiAgLyoqXG4gICAqIFByb2Nlc3MgY29sbGVjdGVkIGF1ZGlvIGNodW5rcyBhbmQgc2VuZCB0byBHcm9xIGZvciB0cmFuc2NyaXB0aW9uIChtYXRjaGluZyBNTFgpXG4gICAqIENSSVRJQ0FMOiBHdWFyZCB3aXRoIHByb2Nlc3NpbmdSZWYgdG8gcHJldmVudCBkdXBsaWNhdGUgdXBsb2Fkc1xuICAgKi9cbiAgY29uc3QgcHJvY2Vzc0F1ZGlvQ2h1bmtzID0gdXNlQ2FsbGJhY2soYXN5bmMgKCkgPT4ge1xuICAgIGlmIChhdWRpb0NodW5rc1JlZi5jdXJyZW50Lmxlbmd0aCA9PT0gMCkge1xuICAgICAgbG9nZ2VyLndhcm4oJ05vIGF1ZGlvIGNodW5rcyB0byBwcm9jZXNzJyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gSW4gc3RyZWFtaW5nIG1vZGUsIGF1ZGlvIGFscmVhZHkgcHJvY2Vzc2VkIHZpYSBzdHJlYW1cbiAgICBsb2dnZXIuaW5mbygn4pyFIFN0cmVhbWluZyBjb21wbGV0ZWQnKTtcbiAgICBhdWRpb0NodW5rc1JlZi5jdXJyZW50ID0gW107XG4gIH0sIFtdKTtcblxuICAvKipcbiAgICogSGFuZGxlIHNob3VsZExpc3RlbiBwcm9wIGNoYW5nZXNcbiAgICovXG4gIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgbG9nZ2VyLmRlYnVnKGBzaG91bGRMaXN0ZW4gY2hhbmdlZDogJHtzaG91bGRMaXN0ZW59LCBpc1JlY29yZGluZzogJHtpc1JlY29yZGluZ31gKTtcblxuICAgIGlmIChzaG91bGRMaXN0ZW4gJiYgIWlzUmVjb3JkaW5nKSB7XG4gICAgICBsb2dnZXIuZGVidWcoJ+KchSBTdGFydGluZyByZWNvcmRpbmcnKTtcbiAgICAgIHN0YXJ0UmVjb3JkaW5nKCk7XG4gICAgfSBlbHNlIGlmICghc2hvdWxkTGlzdGVuICYmIGlzUmVjb3JkaW5nKSB7XG4gICAgICBsb2dnZXIuZGVidWcoJ+KdjCBTdG9wcGluZyByZWNvcmRpbmcnKTtcbiAgICAgIHN0b3BSZWNvcmRpbmcoKTtcbiAgICB9XG4gIH0sIFtzaG91bGRMaXN0ZW4sIGlzUmVjb3JkaW5nLCBzdGFydFJlY29yZGluZywgc3RvcFJlY29yZGluZ10pO1xuXG4gIC8qKlxuICAgKiBDbGVhbnVwIG9uIHVubW91bnRcbiAgICovXG4gIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgcmV0dXJuICgpID0+IHtcbiAgICAgIGlmIChzdHJlYW1BYm9ydFJlZi5jdXJyZW50KSB7XG4gICAgICAgIHN0cmVhbUFib3J0UmVmLmN1cnJlbnQuYWJvcnQoKTtcbiAgICAgIH1cbiAgICAgIGlmIChtZWRpYVJlY29yZGVyUmVmLmN1cnJlbnQgJiYgbWVkaWFSZWNvcmRlclJlZi5jdXJyZW50LnN0YXRlID09PSAncmVjb3JkaW5nJykge1xuICAgICAgICBtZWRpYVJlY29yZGVyUmVmLmN1cnJlbnQuc3RvcCgpO1xuICAgICAgfVxuICAgICAgaWYgKHN0cmVhbVJlZi5jdXJyZW50KSB7XG4gICAgICAgIHN0cmVhbVJlZi5jdXJyZW50LmdldFRyYWNrcygpLmZvckVhY2goKHRyYWNrKSA9PiB0cmFjay5zdG9wKCkpO1xuICAgICAgfVxuICAgIH07XG4gIH0sIFtdKTtcblxuICByZXR1cm4gPFZpZXcgLz47XG59O1xuXG4vKipcbiAqIEdldCBzdXBwb3J0ZWQgTUlNRSB0eXBlIGZvciBNZWRpYVJlY29yZGVyXG4gKi9cbmZ1bmN0aW9uIGdldFN1cHBvcnRlZE1pbWVUeXBlKCk6IHN0cmluZyB7XG4gIGNvbnN0IHR5cGVzID0gW1xuICAgICdhdWRpby93ZWJtO2NvZGVjcz1vcHVzJyxcbiAgICAnYXVkaW8vd2VibScsXG4gICAgJ2F1ZGlvL29nZztjb2RlY3M9b3B1cycsXG4gICAgJ2F1ZGlvL21wNCcsXG4gICAgJ2F1ZGlvL3dhdicsXG4gIF07XG5cbiAgZm9yIChjb25zdCB0eXBlIG9mIHR5cGVzKSB7XG4gICAgaWYgKE1lZGlhUmVjb3JkZXIuaXNUeXBlU3VwcG9ydGVkKHR5cGUpKSB7XG4gICAgICByZXR1cm4gdHlwZTtcbiAgICB9XG4gIH1cblxuICAvLyBGYWxsYmFja1xuICByZXR1cm4gJ2F1ZGlvL3dlYm0nO1xufVxuXG5mdW5jdGlvbiByZXNvbHZlR3JvcVRyYW5zY3JpcHRpb25FbmRwb2ludChcbiAgYmFzZVVybD86IHN0cmluZyxcbiAgb3ZlcnJpZGVFbmRwb2ludD86IHN0cmluZyxcbik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmIChvdmVycmlkZUVuZHBvaW50KSByZXR1cm4gb3ZlcnJpZGVFbmRwb2ludDtcbiAgaWYgKCFiYXNlVXJsKSByZXR1cm4gdW5kZWZpbmVkO1xuICBjb25zdCB0cmltbWVkID0gYmFzZVVybC5yZXBsYWNlKC9cXC8rJC8sICcnKTtcbiAgaWYgKHRyaW1tZWQuZW5kc1dpdGgoJy9vcGVuYWkvdjEnKSkge1xuICAgIHJldHVybiBgJHt0cmltbWVkfS9hdWRpby90cmFuc2NyaXB0aW9uc2A7XG4gIH1cbiAgcmV0dXJuIGAke3RyaW1tZWR9L29wZW5haS92MS9hdWRpby90cmFuc2NyaXB0aW9uc2A7XG59XG5cbmZ1bmN0aW9uIHJlc29sdmVHcm9xVHJhbnNsYXRpb25FbmRwb2ludChcbiAgYmFzZVVybD86IHN0cmluZyxcbiAgb3ZlcnJpZGVFbmRwb2ludD86IHN0cmluZyxcbik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmIChvdmVycmlkZUVuZHBvaW50KSB7XG4gICAgcmV0dXJuIG92ZXJyaWRlRW5kcG9pbnQuaW5jbHVkZXMoJy9hdWRpby90cmFuc2NyaXB0aW9ucycpXG4gICAgICA/IG92ZXJyaWRlRW5kcG9pbnQucmVwbGFjZSgnL2F1ZGlvL3RyYW5zY3JpcHRpb25zJywgJy9hdWRpby90cmFuc2xhdGlvbnMnKVxuICAgICAgOiBvdmVycmlkZUVuZHBvaW50O1xuICB9XG4gIGlmICghYmFzZVVybCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgY29uc3QgdHJpbW1lZCA9IGJhc2VVcmwucmVwbGFjZSgvXFwvKyQvLCAnJyk7XG4gIGlmICh0cmltbWVkLmVuZHNXaXRoKCcvb3BlbmFpL3YxJykpIHtcbiAgICByZXR1cm4gYCR7dHJpbW1lZH0vYXVkaW8vdHJhbnNsYXRpb25zYDtcbiAgfVxuICByZXR1cm4gYCR7dHJpbW1lZH0vb3BlbmFpL3YxL2F1ZGlvL3RyYW5zbGF0aW9uc2A7XG59XG5cbi8qKlxuICogR2V0IGZpbGUgZXh0ZW5zaW9uIGZyb20gTUlNRSB0eXBlXG4gKi9cbi8qKlxuICogQ2hlY2sgaWYgR3JvcSBzcGVlY2ggcmVjb2duaXRpb24gaXMgYXZhaWxhYmxlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0dyb3FTcGVlY2hBdmFpbGFibGUoKTogYm9vbGVhbiB7XG4gIC8vIENoZWNrIGlmIHJ1bm5pbmcgaW4gYnJvd3NlclxuICBpZiAodHlwZW9mIHdpbmRvdyA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvLyBDaGVjayBmb3IgcmVxdWlyZWQgQVBJc1xuICBjb25zdCBoYXNNZWRpYURldmljZXMgPSBcbiAgICBuYXZpZ2F0b3I/Lm1lZGlhRGV2aWNlcz8uZ2V0VXNlck1lZGlhICE9PSB1bmRlZmluZWQ7XG4gIGNvbnN0IGhhc01lZGlhUmVjb3JkZXIgPSB0eXBlb2YgTWVkaWFSZWNvcmRlciAhPT0gJ3VuZGVmaW5lZCc7XG5cbiAgcmV0dXJuIGhhc01lZGlhRGV2aWNlcyAmJiBoYXNNZWRpYVJlY29yZGVyO1xufVxuXG4vKipcbiAqIEdldCBicm93c2VyIGNhcGFiaWxpdGllcyBmb3IgR3JvcSBzcGVlY2hcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEdyb3FTcGVlY2hDYXBhYmlsaXRpZXMoKSB7XG4gIHJldHVybiB7XG4gICAgYXZhaWxhYmxlOiBpc0dyb3FTcGVlY2hBdmFpbGFibGUoKSxcbiAgICBzdXBwb3J0ZWRNaW1lVHlwZXM6IFtcbiAgICAgICdhdWRpby93ZWJtO2NvZGVjcz1vcHVzJyxcbiAgICAgICdhdWRpby93ZWJtJyxcbiAgICAgICdhdWRpby9vZ2c7Y29kZWNzPW9wdXMnLFxuICAgICAgJ2F1ZGlvL21wNCcsXG4gICAgICAnYXVkaW8vd2F2JyxcbiAgICBdLmZpbHRlcigodHlwZSkgPT4ge1xuICAgICAgaWYgKHR5cGVvZiBNZWRpYVJlY29yZGVyID09PSAndW5kZWZpbmVkJykgcmV0dXJuIGZhbHNlO1xuICAgICAgcmV0dXJuIE1lZGlhUmVjb3JkZXIuaXNUeXBlU3VwcG9ydGVkKHR5cGUpO1xuICAgIH0pLFxuICAgIHBsYXRmb3JtOiBQbGF0Zm9ybS5PUyxcbiAgfTtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFNQSxJQUFBQSxNQUFBLEdBQUFDLHVCQUFBLENB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
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ export type LocalWhisperMode = 'oneshot' | 'sse' | 'realtime';
3
+ export interface MLXSpeechRecognizerProps {
4
+ shouldListen: boolean;
5
+ speechStatusCallback: (status: boolean, transcript: string) => void;
6
+ speechResultCallback: (result: string) => void;
7
+ language?: string;
8
+ onError?: (error: Error) => void;
9
+ baseUrl?: string;
10
+ mode?: LocalWhisperMode;
11
+ modelName?: string;
12
+ minAudioSize?: number;
13
+ }
14
+ export declare const MLXSpeechRecognizer: React.FC<MLXSpeechRecognizerProps>;
15
+ export default MLXSpeechRecognizer;