@mentra/sdk 2.1.0 โ†’ 2.1.2-alpha.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 (56) hide show
  1. package/dist/app/session/events.d.ts +2 -1
  2. package/dist/app/session/events.d.ts.map +1 -1
  3. package/dist/app/session/index.d.ts +14 -5
  4. package/dist/app/session/index.d.ts.map +1 -1
  5. package/dist/app/session/index.js +71 -21
  6. package/dist/app/session/modules/audio.d.ts +190 -0
  7. package/dist/app/session/modules/audio.d.ts.map +1 -0
  8. package/dist/app/session/modules/audio.js +318 -0
  9. package/dist/app/session/modules/camera-managed-extension.d.ts +151 -0
  10. package/dist/app/session/modules/camera-managed-extension.d.ts.map +1 -0
  11. package/dist/app/session/modules/camera-managed-extension.js +231 -0
  12. package/dist/app/session/modules/camera.d.ts +55 -1
  13. package/dist/app/session/modules/camera.d.ts.map +1 -1
  14. package/dist/app/session/modules/camera.js +72 -0
  15. package/dist/app/session/modules/index.d.ts +4 -0
  16. package/dist/app/session/modules/index.d.ts.map +1 -0
  17. package/dist/app/session/modules/index.js +19 -0
  18. package/dist/app/session/modules/location.d.ts +15 -0
  19. package/dist/app/session/modules/location.d.ts.map +1 -0
  20. package/dist/app/session/modules/location.js +46 -0
  21. package/dist/app/webview/index.d.ts.map +1 -1
  22. package/dist/app/webview/index.js +0 -1
  23. package/dist/examples/managed-rtmp-streaming-example.d.ts +2 -0
  24. package/dist/examples/managed-rtmp-streaming-example.d.ts.map +1 -0
  25. package/dist/examples/managed-rtmp-streaming-example.js +155 -0
  26. package/dist/index.d.ts +3 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +4 -1
  29. package/dist/types/enums.d.ts +3 -1
  30. package/dist/types/enums.d.ts.map +1 -1
  31. package/dist/types/enums.js +2 -0
  32. package/dist/types/index.d.ts +5 -5
  33. package/dist/types/index.d.ts.map +1 -1
  34. package/dist/types/index.js +7 -1
  35. package/dist/types/message-types.d.ts +14 -2
  36. package/dist/types/message-types.d.ts.map +1 -1
  37. package/dist/types/message-types.js +16 -0
  38. package/dist/types/messages/app-to-cloud.d.ts +65 -3
  39. package/dist/types/messages/app-to-cloud.d.ts.map +1 -1
  40. package/dist/types/messages/app-to-cloud.js +28 -0
  41. package/dist/types/messages/cloud-to-app.d.ts +26 -1
  42. package/dist/types/messages/cloud-to-app.d.ts.map +1 -1
  43. package/dist/types/messages/cloud-to-app.js +8 -0
  44. package/dist/types/messages/cloud-to-glasses.d.ts +38 -1
  45. package/dist/types/messages/cloud-to-glasses.d.ts.map +1 -1
  46. package/dist/types/messages/cloud-to-glasses.js +8 -0
  47. package/dist/types/messages/glasses-to-cloud.d.ts +14 -1
  48. package/dist/types/messages/glasses-to-cloud.d.ts.map +1 -1
  49. package/dist/types/messages/glasses-to-cloud.js +4 -0
  50. package/dist/types/models.d.ts +13 -0
  51. package/dist/types/models.d.ts.map +1 -1
  52. package/dist/types/models.js +9 -0
  53. package/dist/types/streams.d.ts +6 -0
  54. package/dist/types/streams.d.ts.map +1 -1
  55. package/dist/types/streams.js +4 -0
  56. package/package.json +1 -1
@@ -0,0 +1,318 @@
1
+ "use strict";
2
+ /**
3
+ * ๐Ÿ”Š Audio Module
4
+ *
5
+ * Audio functionality for App Sessions.
6
+ * Handles audio playback on connected glasses.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.AudioManager = void 0;
10
+ const types_1 = require("../../../types");
11
+ /**
12
+ * ๐Ÿ”Š Audio Module Implementation
13
+ *
14
+ * Audio management for App Sessions.
15
+ * Provides methods for:
16
+ * - ๐ŸŽต Playing audio on glasses
17
+ * - โน๏ธ Stopping audio playback
18
+ * - ๐Ÿ” Monitoring audio request status
19
+ * - ๐Ÿงน Cleanup and cancellation
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * // Play audio
24
+ * const result = await session.audio.playAudio({
25
+ * audioUrl: 'https://example.com/sound.mp3',
26
+ * volume: 0.8
27
+ * });
28
+ *
29
+ * // Stop all audio
30
+ * session.audio.stopAudio();
31
+ * ```
32
+ */
33
+ class AudioManager {
34
+ /**
35
+ * Create a new AudioManager
36
+ *
37
+ * @param packageName - The App package name
38
+ * @param sessionId - The current session ID
39
+ * @param send - Function to send messages to the cloud
40
+ * @param session - Reference to the parent AppSession (optional)
41
+ * @param logger - Logger instance for debugging
42
+ */
43
+ constructor(packageName, sessionId, send, session, logger) {
44
+ /** Map to store pending audio play request promises */
45
+ this.pendingAudioRequests = new Map();
46
+ this.packageName = packageName;
47
+ this.sessionId = sessionId;
48
+ this.send = send;
49
+ this.session = session;
50
+ this.logger = logger || console;
51
+ }
52
+ // =====================================
53
+ // ๐ŸŽต Audio Playback Functionality
54
+ // =====================================
55
+ /**
56
+ * ๐Ÿ”Š Play audio on the connected glasses
57
+ * @param options - Audio playback configuration
58
+ * @returns Promise that resolves with playback result
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * // Play audio from URL
63
+ * const result = await session.audio.playAudio({
64
+ * audioUrl: 'https://example.com/sound.mp3',
65
+ * volume: 0.8
66
+ * });
67
+ * ```
68
+ */
69
+ async playAudio(options) {
70
+ return new Promise((resolve, reject) => {
71
+ try {
72
+ // Validate input
73
+ if (!options.audioUrl) {
74
+ reject(new Error('audioUrl must be provided'));
75
+ return;
76
+ }
77
+ // Generate unique request ID
78
+ const requestId = `audio_req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
79
+ // Store promise resolvers for when we get the response
80
+ this.pendingAudioRequests.set(requestId, { resolve, reject });
81
+ // Create audio play request message
82
+ const message = {
83
+ type: types_1.AppToCloudMessageType.AUDIO_PLAY_REQUEST,
84
+ packageName: this.packageName,
85
+ sessionId: this.sessionId,
86
+ requestId,
87
+ timestamp: new Date(),
88
+ audioUrl: options.audioUrl,
89
+ volume: options.volume ?? 1.0,
90
+ stopOtherAudio: options.stopOtherAudio ?? true
91
+ };
92
+ // Send request to cloud
93
+ this.send(message);
94
+ this.logger.info({ requestId, audioUrl: options.audioUrl, volume: options.volume }, `๐Ÿ”Š Audio play request sent`);
95
+ // Set timeout to avoid hanging promises
96
+ const timeoutMs = 60000; // 60 seconds
97
+ if (this.session && this.session.resources) {
98
+ // Use session's resource tracker for automatic cleanup
99
+ this.session.resources.setTimeout(() => {
100
+ if (this.pendingAudioRequests.has(requestId)) {
101
+ this.pendingAudioRequests.get(requestId).reject(new Error('Audio play request timed out'));
102
+ this.pendingAudioRequests.delete(requestId);
103
+ this.logger.warn({ requestId }, `๐Ÿ”Š Audio play request timed out`);
104
+ }
105
+ }, timeoutMs);
106
+ }
107
+ else {
108
+ // Fallback to regular setTimeout if session not available
109
+ setTimeout(() => {
110
+ if (this.pendingAudioRequests.has(requestId)) {
111
+ this.pendingAudioRequests.get(requestId).reject(new Error('Audio play request timed out'));
112
+ this.pendingAudioRequests.delete(requestId);
113
+ this.logger.warn({ requestId }, `๐Ÿ”Š Audio play request timed out`);
114
+ }
115
+ }, timeoutMs);
116
+ }
117
+ }
118
+ catch (error) {
119
+ const errorMessage = error instanceof Error ? error.message : String(error);
120
+ reject(new Error(`Failed to play audio: ${errorMessage}`));
121
+ }
122
+ });
123
+ }
124
+ /**
125
+ * ๐Ÿ”‡ Stop audio playback on the connected glasses
126
+ *
127
+ * @example
128
+ * ```typescript
129
+ * // Stop all currently playing audio
130
+ * session.audio.stopAudio();
131
+ * ```
132
+ */
133
+ stopAudio() {
134
+ try {
135
+ // Create audio stop request message
136
+ const message = {
137
+ type: types_1.AppToCloudMessageType.AUDIO_STOP_REQUEST,
138
+ packageName: this.packageName,
139
+ sessionId: this.sessionId,
140
+ timestamp: new Date()
141
+ };
142
+ // Send request to cloud (one-way, no response expected)
143
+ this.send(message);
144
+ this.logger.info(`๐Ÿ”‡ Audio stop request sent`);
145
+ }
146
+ catch (error) {
147
+ const errorMessage = error instanceof Error ? error.message : String(error);
148
+ this.logger.error(`Failed to stop audio: ${errorMessage}`);
149
+ }
150
+ }
151
+ /**
152
+ * ๐Ÿ—ฃ๏ธ Convert text to speech and play it on the connected glasses
153
+ * @param text - Text to convert to speech (required)
154
+ * @param options - Text-to-speech configuration (optional)
155
+ * @returns Promise that resolves with playback result
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * // Basic text-to-speech
160
+ * const result = await session.audio.speak('Hello, world!');
161
+ *
162
+ * // With custom voice settings
163
+ * const result = await session.audio.speak('Hello, world!', {
164
+ * voice_id: 'your_voice_id',
165
+ * voice_settings: {
166
+ * stability: 0.5,
167
+ * speed: 1.2
168
+ * },
169
+ * volume: 0.8
170
+ * });
171
+ * ```
172
+ */
173
+ async speak(text, options = {}) {
174
+ // Validate input
175
+ if (!text) {
176
+ throw new Error('text must be provided');
177
+ }
178
+ // Get the HTTPS server URL from the session
179
+ const baseUrl = this.session?.getHttpsServerUrl?.();
180
+ if (!baseUrl) {
181
+ throw new Error('Cannot determine server URL for TTS endpoint');
182
+ }
183
+ // Build query parameters for the TTS endpoint
184
+ const queryParams = new URLSearchParams();
185
+ queryParams.append('text', text);
186
+ if (options.voice_id) {
187
+ queryParams.append('voice_id', options.voice_id);
188
+ }
189
+ if (options.model_id) {
190
+ queryParams.append('model_id', options.model_id);
191
+ }
192
+ if (options.voice_settings) {
193
+ queryParams.append('voice_settings', JSON.stringify(options.voice_settings));
194
+ }
195
+ // Construct the TTS URL
196
+ const ttsUrl = `${baseUrl}/api/tts?${queryParams.toString()}`;
197
+ this.logger.info({ text, ttsUrl }, `๐Ÿ—ฃ๏ธ Generating speech from text`);
198
+ // Use the existing playAudio method to play the TTS audio
199
+ return this.playAudio({
200
+ audioUrl: ttsUrl,
201
+ volume: options.volume
202
+ });
203
+ }
204
+ // =====================================
205
+ // ๐Ÿ“ฅ Response Handling
206
+ // =====================================
207
+ /**
208
+ * ๐Ÿ“ฅ Handle audio play response from cloud
209
+ *
210
+ * This method is called internally when an audio play response is received.
211
+ * It resolves the corresponding pending promise with the response data.
212
+ *
213
+ * @param response - The audio play response received
214
+ * @internal This method is used internally by AppSession
215
+ */
216
+ handleAudioPlayResponse(response) {
217
+ const pendingRequest = this.pendingAudioRequests.get(response.requestId);
218
+ if (pendingRequest) {
219
+ // Resolve the promise with the response data
220
+ pendingRequest.resolve({
221
+ success: response.success,
222
+ error: response.error,
223
+ duration: response.duration
224
+ });
225
+ // Clean up
226
+ this.pendingAudioRequests.delete(response.requestId);
227
+ this.logger.info({
228
+ requestId: response.requestId,
229
+ success: response.success,
230
+ duration: response.duration
231
+ }, `๐Ÿ”Š Audio play response received`);
232
+ }
233
+ else {
234
+ this.logger.warn({ requestId: response.requestId }, `๐Ÿ”Š Received audio play response for unknown request ID`);
235
+ }
236
+ }
237
+ // =====================================
238
+ // ๐Ÿ” Status and Management
239
+ // =====================================
240
+ /**
241
+ * ๐Ÿ” Check if there are pending audio requests
242
+ * @param requestId - Optional specific request ID to check
243
+ * @returns True if there are pending requests (or specific request exists)
244
+ */
245
+ hasPendingRequest(requestId) {
246
+ if (requestId) {
247
+ return this.pendingAudioRequests.has(requestId);
248
+ }
249
+ return this.pendingAudioRequests.size > 0;
250
+ }
251
+ /**
252
+ * ๐Ÿ“Š Get the number of pending audio requests
253
+ * @returns Number of pending requests
254
+ */
255
+ getPendingRequestCount() {
256
+ return this.pendingAudioRequests.size;
257
+ }
258
+ /**
259
+ * ๐Ÿ“‹ Get all pending request IDs
260
+ * @returns Array of pending request IDs
261
+ */
262
+ getPendingRequestIds() {
263
+ return Array.from(this.pendingAudioRequests.keys());
264
+ }
265
+ /**
266
+ * โŒ Cancel a specific audio request
267
+ * @param requestId - The request ID to cancel
268
+ * @returns True if the request was found and cancelled
269
+ */
270
+ cancelAudioRequest(requestId) {
271
+ const pendingRequest = this.pendingAudioRequests.get(requestId);
272
+ if (pendingRequest) {
273
+ pendingRequest.reject(new Error('Audio request cancelled'));
274
+ this.pendingAudioRequests.delete(requestId);
275
+ this.logger.info({ requestId }, `๐Ÿ”Š Audio request cancelled`);
276
+ return true;
277
+ }
278
+ return false;
279
+ }
280
+ /**
281
+ * ๐Ÿงน Cancel all pending audio requests
282
+ * @returns Number of requests that were cancelled
283
+ */
284
+ cancelAllAudioRequests() {
285
+ const count = this.pendingAudioRequests.size;
286
+ this.pendingAudioRequests.forEach((request, requestId) => {
287
+ request.reject(new Error('Audio request cancelled due to cleanup'));
288
+ this.logger.debug({ requestId }, `๐Ÿ”Š Audio request cancelled during cleanup`);
289
+ });
290
+ this.pendingAudioRequests.clear();
291
+ if (count > 0) {
292
+ this.logger.info({ cancelledCount: count }, `๐Ÿงน Cancelled all pending audio requests`);
293
+ }
294
+ return count;
295
+ }
296
+ // =====================================
297
+ // ๐Ÿ”ง Internal Management
298
+ // =====================================
299
+ /**
300
+ * ๐Ÿ”„ Update the session ID when reconnecting
301
+ * @param newSessionId - The new session ID
302
+ * @internal Used by AppSession during reconnection
303
+ */
304
+ updateSessionId(newSessionId) {
305
+ this.sessionId = newSessionId;
306
+ this.logger.debug({ newSessionId }, `๐Ÿ”„ Audio module session ID updated`);
307
+ }
308
+ /**
309
+ * ๐Ÿงน Cancel all pending requests (cleanup)
310
+ * @returns Object with count of cancelled requests
311
+ * @internal Used by AppSession during cleanup
312
+ */
313
+ cancelAllRequests() {
314
+ const audioRequests = this.cancelAllAudioRequests();
315
+ return { audioRequests };
316
+ }
317
+ }
318
+ exports.AudioManager = AudioManager;
@@ -0,0 +1,151 @@
1
+ /**
2
+ * ๐Ÿ“ท Camera Module Managed Streaming Extension
3
+ *
4
+ * Extends the camera module with managed streaming capabilities.
5
+ * Apps can request managed streams and receive HLS/DASH URLs without managing RTMP endpoints.
6
+ */
7
+ import { ManagedStreamStatus } from '../../../types';
8
+ import { VideoConfig, AudioConfig, StreamConfig } from '../../../types/rtmp-stream';
9
+ import { Logger } from 'pino';
10
+ /**
11
+ * Configuration options for a managed stream
12
+ */
13
+ export interface ManagedStreamOptions {
14
+ /** Stream quality preset */
15
+ quality?: '720p' | '1080p';
16
+ /** Enable WebRTC for ultra-low latency viewing */
17
+ enableWebRTC?: boolean;
18
+ /** Optional video configuration settings */
19
+ video?: VideoConfig;
20
+ /** Optional audio configuration settings */
21
+ audio?: AudioConfig;
22
+ /** Optional stream configuration settings */
23
+ stream?: StreamConfig;
24
+ }
25
+ /**
26
+ * Result returned when starting a managed stream
27
+ */
28
+ export interface ManagedStreamResult {
29
+ /** HLS URL for viewing the stream */
30
+ hlsUrl: string;
31
+ /** DASH URL for viewing the stream */
32
+ dashUrl: string;
33
+ /** WebRTC URL if enabled */
34
+ webrtcUrl?: string;
35
+ /** Internal stream ID */
36
+ streamId: string;
37
+ }
38
+ /**
39
+ * ๐Ÿ“น Managed Streaming Extension for Camera Module
40
+ *
41
+ * Provides managed streaming capabilities where the cloud handles
42
+ * RTMP endpoints and returns HLS/DASH URLs for viewing.
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * // Start a managed stream
47
+ * const urls = await session.camera.startManagedStream({
48
+ * quality: '720p',
49
+ * enableWebRTC: true
50
+ * });
51
+ * console.log('HLS URL:', urls.hlsUrl);
52
+ * console.log('DASH URL:', urls.dashUrl);
53
+ *
54
+ * // Monitor managed stream status
55
+ * session.camera.onManagedStreamStatus((status) => {
56
+ * console.log('Managed stream status:', status.status);
57
+ * });
58
+ *
59
+ * // Stop managed stream
60
+ * await session.camera.stopManagedStream();
61
+ * ```
62
+ */
63
+ export declare class CameraManagedExtension {
64
+ private send;
65
+ private packageName;
66
+ private sessionId;
67
+ private logger;
68
+ private isManagedStreaming;
69
+ private currentManagedStreamId?;
70
+ private currentManagedStreamUrls?;
71
+ private managedStreamStatus?;
72
+ private pendingManagedStreamRequest?;
73
+ constructor(packageName: string, sessionId: string, send: (message: any) => void, logger: Logger);
74
+ /**
75
+ * ๐Ÿ“น Start a managed stream
76
+ *
77
+ * The cloud will handle the RTMP endpoint and return HLS/DASH URLs for viewing.
78
+ * Multiple apps can consume the same managed stream simultaneously.
79
+ *
80
+ * @param options - Configuration options for the managed stream
81
+ * @returns Promise that resolves with viewing URLs when the stream is ready
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * const urls = await session.camera.startManagedStream({
86
+ * quality: '1080p',
87
+ * enableWebRTC: true,
88
+ * video: { fps: 30 },
89
+ * audio: { sampleRate: 48000 }
90
+ * });
91
+ * ```
92
+ */
93
+ startManagedStream(options?: ManagedStreamOptions): Promise<ManagedStreamResult>;
94
+ /**
95
+ * ๐Ÿ›‘ Stop the current managed stream
96
+ *
97
+ * This will stop streaming for this app only. If other apps are consuming
98
+ * the same managed stream, it will continue for them.
99
+ *
100
+ * @returns Promise that resolves when the stop request is sent
101
+ */
102
+ stopManagedStream(): Promise<void>;
103
+ /**
104
+ * ๐Ÿ“Š Check if currently managed streaming
105
+ *
106
+ * @returns true if a managed stream is active
107
+ */
108
+ isManagedStreamActive(): boolean;
109
+ /**
110
+ * ๐Ÿ”— Get current managed stream URLs
111
+ *
112
+ * @returns Current stream URLs or undefined if not streaming
113
+ */
114
+ getManagedStreamUrls(): ManagedStreamResult | undefined;
115
+ /**
116
+ * ๐Ÿ“Š Get current managed stream status
117
+ *
118
+ * @returns Current stream status or undefined
119
+ */
120
+ getManagedStreamStatus(): ManagedStreamStatus | undefined;
121
+ /**
122
+ * ๐Ÿ”” Register a handler for managed stream status updates
123
+ *
124
+ * @param handler - Function to call when stream status changes
125
+ * @returns Cleanup function to unregister the handler
126
+ *
127
+ * @example
128
+ * ```typescript
129
+ * const cleanup = session.camera.onManagedStreamStatus((status) => {
130
+ * console.log('Status:', status.status);
131
+ * if (status.status === 'active') {
132
+ * console.log('Stream is live!');
133
+ * }
134
+ * });
135
+ *
136
+ * // Later, unregister the handler
137
+ * cleanup();
138
+ * ```
139
+ */
140
+ onManagedStreamStatus(handler: (status: ManagedStreamStatus) => void): () => void;
141
+ /**
142
+ * Handle incoming managed stream status messages
143
+ * Called by the parent AppSession when messages are received
144
+ */
145
+ handleManagedStreamStatus(status: ManagedStreamStatus): void;
146
+ /**
147
+ * ๐Ÿงน Clean up all managed streaming state
148
+ */
149
+ cleanup(): void;
150
+ }
151
+ //# sourceMappingURL=camera-managed-extension.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"camera-managed-extension.d.ts","sourceRoot":"","sources":["../../../../src/app/session/modules/camera-managed-extension.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAGL,mBAAmB,EAIpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AACpF,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAE9B;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,4BAA4B;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,kDAAkD;IAClD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,IAAI,CAAyB;IACrC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAS;IAGvB,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,sBAAsB,CAAC,CAAS;IACxC,OAAO,CAAC,wBAAwB,CAAC,CAAsB;IACvD,OAAO,CAAC,mBAAmB,CAAC,CAAsB;IAGlD,OAAO,CAAC,2BAA2B,CAAC,CAGlC;gBAGA,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,EAC5B,MAAM,EAAE,MAAM;IAQhB;;;;;;;;;;;;;;;;;;OAkBG;IACG,kBAAkB,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAwC1F;;;;;;;OAOG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBxC;;;;OAIG;IACH,qBAAqB,IAAI,OAAO;IAIhC;;;;OAIG;IACH,oBAAoB,IAAI,mBAAmB,GAAG,SAAS;IAIvD;;;;OAIG;IACH,sBAAsB,IAAI,mBAAmB,GAAG,SAAS;IAIzD;;;;;;;;;;;;;;;;;;OAkBG;IACH,qBAAqB,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,GAAG,MAAM,IAAI;IAYjF;;;OAGG;IACH,yBAAyB,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI;IA2C5D;;OAEG;IACH,OAAO,IAAI,IAAI;CAahB"}