@centive/aria-sdk 0.5.6 → 0.5.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,9 +13,10 @@ A production-ready React SDK for [Anam AI](https://docs.anam.ai/) with dual-mode
13
13
  - **Both modes work simultaneously** - Maximum flexibility for any use case
14
14
 
15
15
  ### 🚀 Global Session Management
16
- - **Session Preloading** - Session is ready before user clicks, for instant response
16
+ - **Lazy Session Initialization** - Greeting plays exactly when user opens widget (not preloaded)
17
17
  - **Session Persistence** - Session survives page navigation in SPAs
18
18
  - **Widget Toggle Persistence** - Keep session alive when widget is closed/reopened (optional)
19
+ - **Minimized Widget State** - Click outside to minimize, keeping session active
19
20
  - **Proactive Refresh** - Automatically refreshes session before expiration
20
21
  - **Tab Visibility Awareness** - Only refreshes when tab is active
21
22
  - **Error Recovery** - Exponential backoff retry on failures
@@ -32,6 +33,7 @@ A production-ready React SDK for [Anam AI](https://docs.anam.ai/) with dual-mode
32
33
  - Mute/unmute audio controls
33
34
  - Live transcription display
34
35
  - Message history tracking
36
+ - **Tool Call Indicators** - Visual feedback when AI is executing tools/functions
35
37
 
36
38
  ### 🎨 Modern UI
37
39
  - Video-call-style interface
@@ -260,6 +262,7 @@ function MyComponent() {
260
262
  const {
261
263
  // UI State
262
264
  isOpen,
265
+ isMinimized, // True when widget is minimized (compact floating state)
263
266
  isConnected,
264
267
  isLoading,
265
268
  displayMode,
@@ -271,15 +274,20 @@ function MyComponent() {
271
274
  isMuted,
272
275
  error,
273
276
 
277
+ // Tool Call State
278
+ toolCallState, // { isActive: boolean, toolName: string | null, toolData: object | null }
279
+
274
280
  // Session State
275
281
  sessionState,
276
282
  sessionManagerStatus, // 'idle' | 'connecting' | 'connected' | 'preloading' | 'ready' | 'refreshing' | 'error'
277
- isSessionPreloaded, // True when session is ready before widget opens
283
+ isSessionPreloaded, // True when session token is ready
278
284
  isSessionPaused, // True when session is paused (widget closed with persistSession: true)
279
285
 
280
286
  // Actions
281
287
  openAssistant,
282
288
  closeAssistant,
289
+ minimizeAssistant, // Minimize widget to compact floating state
290
+ maximizeAssistant, // Restore widget from minimized state
283
291
  toggleChat,
284
292
  sendMessage,
285
293
  toggleMute,
@@ -495,20 +503,25 @@ See `example-ws-server.js` for a complete implementation.
495
503
 
496
504
  The SDK uses a singleton pattern to maintain session state globally, ensuring:
497
505
 
498
- 1. **Session Preloading** - When `AriaProvider` mounts, it automatically:
506
+ 1. **Lazy Session Initialization** - When `AriaProvider` mounts, it automatically:
499
507
  - Connects to WebSocket
500
- - Requests a session token
501
- - Pre-initializes the Anam client
502
- - Prepares video streaming in a hidden element
508
+ - Requests a session token (token is ready)
509
+ - **Does NOT initialize Anam client yet** (lazy mode)
503
510
 
504
- 2. **Instant Response** - When users click the trigger button:
505
- - Session is already ready (no loading delay)
506
- - Video stream transfers instantly to the visible widget
511
+ 2. **Greeting Plays on Open** - When users click the trigger button:
512
+ - Anam client initializes at this moment
513
+ - **Greeting plays exactly when user sees the widget**
514
+ - No missed greetings from preloading
507
515
 
508
516
  3. **Session Persistence** - During page navigation:
509
517
  - Session survives component unmounts/remounts
510
518
  - No reconnection needed when navigating between pages
511
519
 
520
+ 4. **Minimized Widget State** - When users click outside the widget:
521
+ - Widget minimizes to a compact floating state
522
+ - Session stays active (no interruption)
523
+ - Click to restore full widget
524
+
512
525
  ### Provider Placement (Critical)
513
526
 
514
527
  **Correct:** Place at app root, above router:
@@ -543,6 +556,68 @@ function App() {
543
556
 
544
557
  > **Note:** Even if placed incorrectly, the SDK's singleton pattern provides a safety net to maintain session continuity.
545
558
 
559
+ ### Minimized Widget State
560
+
561
+ When users click outside the widget (on the backdrop), the widget minimizes to a compact floating state instead of closing completely. This allows users to:
562
+
563
+ - Navigate the platform while keeping the session active
564
+ - See a preview of the live transcript
565
+ - Quickly resume the conversation with one click
566
+
567
+ ```tsx
568
+ function WidgetController() {
569
+ const {
570
+ isMinimized,
571
+ minimizeAssistant,
572
+ maximizeAssistant,
573
+ closeAssistant,
574
+ } = useAria();
575
+
576
+ return (
577
+ <div>
578
+ <p>Minimized: {isMinimized ? 'Yes' : 'No'}</p>
579
+
580
+ {/* Programmatic control */}
581
+ <button onClick={minimizeAssistant}>Minimize</button>
582
+ <button onClick={maximizeAssistant}>Maximize</button>
583
+ <button onClick={closeAssistant}>Close (End Session)</button>
584
+ </div>
585
+ );
586
+ }
587
+ ```
588
+
589
+ **Behavior:**
590
+ | Action | Result |
591
+ |--------|--------|
592
+ | Click outside widget (backdrop) | Widget minimizes, session stays active |
593
+ | Click minimized widget | Widget maximizes |
594
+ | Click "End Call" button | Session ends completely |
595
+ | Click X on minimized widget | Session ends completely |
596
+
597
+ ### Tool Call Indicators
598
+
599
+ When Aria executes tool calls (function calling), the widget displays a visual indicator showing:
600
+ - The tool name being executed
601
+ - An animated "processing" state
602
+ - Auto-clears when the tool completes
603
+
604
+ ```tsx
605
+ function ToolCallMonitor() {
606
+ const { toolCallState } = useAria();
607
+
608
+ return (
609
+ <div>
610
+ {toolCallState.isActive && (
611
+ <p>
612
+ Running tool: {toolCallState.toolName}
613
+ Data: {JSON.stringify(toolCallState.toolData)}
614
+ </p>
615
+ )}
616
+ </div>
617
+ );
618
+ }
619
+ ```
620
+
546
621
  ### Session Persistence (Widget Toggle)
547
622
 
548
623
  By default, the SDK ends the session when the widget is closed. With `persistSession: true`, the session stays alive across widget open/close cycles:
@@ -661,7 +736,14 @@ function SessionController() {
661
736
 
662
737
  ```tsx
663
738
  function CustomController() {
664
- const { openAssistant, closeAssistant, triggerSession } = useAria();
739
+ const {
740
+ openAssistant,
741
+ closeAssistant,
742
+ minimizeAssistant,
743
+ maximizeAssistant,
744
+ triggerSession,
745
+ isMinimized,
746
+ } = useAria();
665
747
 
666
748
  return (
667
749
  <div>
@@ -675,6 +757,16 @@ function CustomController() {
675
757
  Start Video Call
676
758
  </button>
677
759
 
760
+ {/* Minimize/Maximize widget */}
761
+ <button onClick={isMinimized ? maximizeAssistant : minimizeAssistant}>
762
+ {isMinimized ? 'Maximize' : 'Minimize'}
763
+ </button>
764
+
765
+ {/* Close widget (ends session) */}
766
+ <button onClick={closeAssistant}>
767
+ End Session
768
+ </button>
769
+
678
770
  {/* Manually trigger session */}
679
771
  <button onClick={triggerSession}>
680
772
  Create New Session
@@ -1 +1 @@
1
- {"version":3,"file":"AriaAssistant.d.ts","sourceRoot":"","sources":["../../src/components/AriaAssistant.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAOhC,UAAU,kBAAkB;IAC1B,uDAAuD;IACvD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,oDAAoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,sCAAsC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,CAwDhD,CAAC"}
1
+ {"version":3,"file":"AriaAssistant.d.ts","sourceRoot":"","sources":["../../src/components/AriaAssistant.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAUhC,UAAU,kBAAkB;IAC1B,uDAAuD;IACvD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,oDAAoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,sCAAsC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAmID,eAAO,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,CAyEhD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"AriaWidget.d.ts","sourceRoot":"","sources":["../../src/components/AriaWidget.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAOnD,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CA0T1C,CAAC"}
1
+ {"version":3,"file":"AriaWidget.d.ts","sourceRoot":"","sources":["../../src/components/AriaWidget.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAOnD,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CAmY1C,CAAC"}
@@ -1,6 +1,8 @@
1
- import type { ChatMessage, AriaSDKConfig, DisplayMode, TriggerMode, Theme, SessionState, TriggerSessionOptions, SessionManagerStatus } from '@/types';
1
+ import type { ChatMessage, AriaSDKConfig, DisplayMode, TriggerMode, Theme, SessionState, TriggerSessionOptions, SessionManagerStatus, ToolCallState } from '@/types';
2
2
  export interface AriaContextType {
3
3
  isOpen: boolean;
4
+ /** Whether the widget is minimized (compact floating state) */
5
+ isMinimized: boolean;
4
6
  isConnected: boolean;
5
7
  isLoading: boolean;
6
8
  chatMessages: ChatMessage[];
@@ -8,6 +10,8 @@ export interface AriaContextType {
8
10
  isChatVisible: boolean;
9
11
  isMuted: boolean;
10
12
  error: string | null;
13
+ /** Current tool call state for UI display */
14
+ toolCallState: ToolCallState;
11
15
  sessionState: SessionState;
12
16
  /** Current status of the session manager */
13
17
  sessionManagerStatus: SessionManagerStatus;
@@ -17,6 +21,10 @@ export interface AriaContextType {
17
21
  isSessionPaused: boolean;
18
22
  openAssistant: (mode?: TriggerMode) => void;
19
23
  closeAssistant: () => void;
24
+ /** Minimize the widget to a compact floating state */
25
+ minimizeAssistant: () => void;
26
+ /** Maximize the widget from minimized state */
27
+ maximizeAssistant: () => void;
20
28
  toggleChat: () => void;
21
29
  sendMessage: (message: string) => Promise<void>;
22
30
  toggleMute: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"AriaContext.d.ts","sourceRoot":"","sources":["../../src/context/AriaContext.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEtJ,MAAM,WAAW,eAAe;IAE9B,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAGrB,YAAY,EAAE,YAAY,CAAC;IAC3B,4CAA4C;IAC5C,oBAAoB,EAAE,oBAAoB,CAAC;IAC3C,iEAAiE;IACjE,kBAAkB,EAAE,OAAO,CAAC;IAC5B,wFAAwF;IACxF,eAAe,EAAE,OAAO,CAAC;IAGzB,aAAa,EAAE,CAAC,IAAI,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC;IAC5C,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,cAAc,EAAE,CAAC,OAAO,CAAC,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAC1D,+DAA+D;IAC/D,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,eAAe,EAAE,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,KAAK,IAAI,CAAC;IAG5D,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,KAAK,CAAC;IAGb,MAAM,EAAE,aAAa,CAAC;IAGtB,YAAY,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,eAAO,MAAM,WAAW,iDAA8C,CAAC"}
1
+ {"version":3,"file":"AriaContext.d.ts","sourceRoot":"","sources":["../../src/context/AriaContext.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAErK,MAAM,WAAW,eAAe;IAE9B,MAAM,EAAE,OAAO,CAAC;IAChB,+DAA+D;IAC/D,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAGrB,6CAA6C;IAC7C,aAAa,EAAE,aAAa,CAAC;IAG7B,YAAY,EAAE,YAAY,CAAC;IAC3B,4CAA4C;IAC5C,oBAAoB,EAAE,oBAAoB,CAAC;IAC3C,iEAAiE;IACjE,kBAAkB,EAAE,OAAO,CAAC;IAC5B,wFAAwF;IACxF,eAAe,EAAE,OAAO,CAAC;IAGzB,aAAa,EAAE,CAAC,IAAI,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC;IAC5C,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,sDAAsD;IACtD,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,+CAA+C;IAC/C,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,cAAc,EAAE,CAAC,OAAO,CAAC,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAC1D,+DAA+D;IAC/D,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,eAAe,EAAE,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,KAAK,IAAI,CAAC;IAG5D,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,KAAK,CAAC;IAGb,MAAM,EAAE,aAAa,CAAC;IAGtB,YAAY,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,eAAO,MAAM,WAAW,iDAA8C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"AriaProvider.d.ts","sourceRoot":"","sources":["../../src/context/AriaProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA4C,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAU1F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C,UAAU,iBAAiB;IACzB,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAMD,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CA6a9C,CAAC"}
1
+ {"version":3,"file":"AriaProvider.d.ts","sourceRoot":"","sources":["../../src/context/AriaProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA4C,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAW1F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C,UAAU,iBAAiB;IACzB,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAMD,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAwf9C,CAAC"}
@@ -0,0 +1,75 @@
1
+ import type { SessionState, SessionManagerStatus } from '@/types';
2
+ /**
3
+ * Session information returned by useAriaSession hook
4
+ */
5
+ export interface AriaSessionInfo {
6
+ /** Current session state including token, expiry, and readiness */
7
+ sessionState: SessionState;
8
+ /** Current status of the session manager */
9
+ status: SessionManagerStatus;
10
+ /** Whether the session is preloaded and ready for instant use */
11
+ isPreloaded: boolean;
12
+ /** Whether the session is currently paused (widget closed with persistSession: true) */
13
+ isPaused: boolean;
14
+ /** Whether the session is connected */
15
+ isConnected: boolean;
16
+ /** Whether the session is currently loading */
17
+ isLoading: boolean;
18
+ /** Current session ID if available */
19
+ sessionId: string | null;
20
+ /** Whether the session token is expired */
21
+ isExpired: boolean;
22
+ /** Whether the session is expiring soon (within refresh buffer) */
23
+ isExpiringSoon: boolean;
24
+ /** Time until session expires in milliseconds (null if no expiry) */
25
+ timeUntilExpiry: number | null;
26
+ }
27
+ /**
28
+ * Session control actions returned by useAriaSession hook
29
+ */
30
+ export interface AriaSessionActions {
31
+ /** End the current session explicitly (for logout scenarios) */
32
+ endSession: () => Promise<void>;
33
+ /** Refresh the session token proactively */
34
+ refreshSession: () => Promise<void>;
35
+ /** Start a new session (if not already active) */
36
+ startSession: () => Promise<void>;
37
+ /** Trigger a session with optional user trigger flag */
38
+ triggerSession: (userTrigger?: boolean) => void;
39
+ }
40
+ /**
41
+ * Return type for useAriaSession hook
42
+ */
43
+ export interface UseAriaSessionReturn {
44
+ /** Session information and state */
45
+ session: AriaSessionInfo;
46
+ /** Session control actions */
47
+ actions: AriaSessionActions;
48
+ }
49
+ /**
50
+ * Hook to access and control Aria session state.
51
+ *
52
+ * This hook provides:
53
+ * - Session state information (token, expiry, status)
54
+ * - Session control actions (end, refresh, start)
55
+ * - Expiry tracking utilities
56
+ *
57
+ * @example
58
+ * ```tsx
59
+ * const { session, actions } = useAriaSession();
60
+ *
61
+ * // Check session state
62
+ * if (session.isExpiringSoon) {
63
+ * console.log('Session expiring soon, will auto-refresh');
64
+ * }
65
+ *
66
+ * // End session on logout
67
+ * const handleLogout = async () => {
68
+ * await actions.endSession();
69
+ * // ... rest of logout logic
70
+ * };
71
+ * ```
72
+ */
73
+ export declare const useAriaSession: () => UseAriaSessionReturn;
74
+ export default useAriaSession;
75
+ //# sourceMappingURL=useAriaSession.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAriaSession.d.ts","sourceRoot":"","sources":["../../src/hooks/useAriaSession.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,YAAY,EAAE,YAAY,CAAC;IAC3B,4CAA4C;IAC5C,MAAM,EAAE,oBAAoB,CAAC;IAC7B,iEAAiE;IACjE,WAAW,EAAE,OAAO,CAAC;IACrB,wFAAwF;IACxF,QAAQ,EAAE,OAAO,CAAC;IAClB,uCAAuC;IACvC,WAAW,EAAE,OAAO,CAAC;IACrB,+CAA+C;IAC/C,SAAS,EAAE,OAAO,CAAC;IACnB,sCAAsC;IACtC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,2CAA2C;IAC3C,SAAS,EAAE,OAAO,CAAC;IACnB,mEAAmE;IACnE,cAAc,EAAE,OAAO,CAAC;IACxB,qEAAqE;IACrE,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,gEAAgE;IAChE,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,4CAA4C;IAC5C,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,kDAAkD;IAClD,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,wDAAwD;IACxD,cAAc,EAAE,CAAC,WAAW,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACjD;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,oCAAoC;IACpC,OAAO,EAAE,eAAe,CAAC;IACzB,8BAA8B;IAC9B,OAAO,EAAE,kBAAkB,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,cAAc,QAAO,oBAyFjC,CAAC;AAEF,eAAe,cAAc,CAAC"}