esap-aiui-react 1.0.0 → 1.0.2

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
@@ -1,15 +1,22 @@
1
1
  # AIUI React SDK
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/@espai/aiui-react-sdk.svg?style=flat-square)](https://www.npmjs.com/package/@espai/aiui-react-sdk)
4
- [![npm downloads](https://img.shields.io/npm/dm/@espai/aiui-react-sdk.svg?style=flat-square)](https://www.npmjs.com/package/@espai/aiui-react-sdk)
3
+ [![npm version](https://img.shields.io/npm/v/esap-aiui-react.svg?style=flat-square)](https://www.npmjs.com/package/esap-aiui-react)
4
+ [![npm downloads](https://img.shields.io/npm/dm/esap-aiui-react.svg?style=flat-square)](https://www.npmjs.com/package/esap-aiui-react)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://opensource.org/licenses/MIT)
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue.svg?style=flat-square)](https://www.typescriptlang.org/)
7
- [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/espai/aiui-react-sdk/pulls)
7
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/espai/aiui-react/pulls)
8
8
 
9
- **Zero-configuration voice and chat control for React applications through autonomous semantic UI discovery.**
9
+ **Zero-configuration voice and chat control for any React applications through autonomous semantic UI discovery.**
10
10
 
11
11
  AIUI React SDK enables natural language interaction with any React application through both voice commands and text chat, without manual UI annotation or intent mapping. The framework employs real-time DOM observation and semantic element discovery to automatically understand your application's interface, allowing users to control your app through conversational voice or text-based commands.
12
12
 
13
+ ### Enterprise features at a glance
14
+
15
+ - Security: API-key protected WebSocket channels and safety-rule gates
16
+ - Privacy: client-side redaction and sensitive-field filtering
17
+ - Auditability: server-side action logs and context update tracing
18
+ - Deployment: cloud, private VPC, or fully on-prem
19
+
13
20
  ## Overview
14
21
 
15
22
  Traditional voice control solutions require extensive manual configuration, predefined intent schemas, or explicit UI element annotation. AIUI eliminates this overhead through a novel semantic discovery architecture that automatically maps UI elements to their contextual meaning, enabling immediate voice interaction with zero setup.
@@ -26,11 +33,11 @@ The SDK implements a **hybrid discovery engine** combining MutationObserver-base
26
33
  - **Privacy-preserving architecture** — Client-side filtering with configurable redaction patterns
27
34
  - **Multi-backend AI support** — Compatible with OpenAI GPT-4, Anthropic Claude, Google Gemini, and local models
28
35
 
29
- ```markdown
36
+
30
37
  ## Architecture
31
38
 
32
- ![AIUI Architecture](./assets/architecture-diagram.png)
33
- ```
39
+ ![AIUI Architecture](https://i.imgur.com/Pvmi0Aq.png)
40
+
34
41
  ### Protocol Design
35
42
 
36
43
  The SDK implements a multi-channel WebSocket architecture to optimize for both latency and bandwidth:
@@ -46,7 +53,7 @@ This separation prevents JSON parsing overhead from blocking time-sensitive audi
46
53
  ## Installation
47
54
 
48
55
  ```bash
49
- npm install @espai/aiui-react-sdk
56
+ npm install esap-aiui-react
50
57
  ```
51
58
 
52
59
  ### Prerequisites
@@ -151,17 +158,121 @@ your-application/
151
158
  │ ├── worklet-processor.js # Microphone input processor
152
159
  │ └── index.html
153
160
  ├── src/
161
+ │ ├── aiui.config.json # AIUI configuration (REQUIRED)
154
162
  │ └── App.tsx
155
163
  └── package.json
156
164
  ```
157
165
 
166
+ ### Required: AIUI Configuration File
167
+
168
+ You **must create** an `aiui.config.json` file in your **`src/`** directory. This file defines how the AIUI SDK connects to your backend and which actions are allowed on each page.
169
+
170
+ #### Create `src/aiui.config.json`:
171
+
172
+ ```json
173
+ {
174
+ "applicationId": "your-app-name",
175
+ "serverUrl": "http://localhost:8000",
176
+ "apiKey": "your-secret-key",
177
+
178
+ "pages": [
179
+ {
180
+ "route": "/",
181
+ "title": "Home Page",
182
+ "safeActions": ["click", "fill", "navigate"],
183
+ "dangerousActions": []
184
+ },
185
+ {
186
+ "route": "/dashboard",
187
+ "title": "Dashboard",
188
+ "safeActions": ["view", "filter", "export"],
189
+ "dangerousActions": ["delete"]
190
+ },
191
+ {
192
+ "route": "/users/:id/edit",
193
+ "title": "Edit User",
194
+ "safeActions": ["edit", "save"],
195
+ "dangerousActions": ["delete user", "deactivate"]
196
+ }
197
+ ],
198
+
199
+ "safetyRules": {
200
+ "requireConfirmation": [
201
+ "delete user",
202
+ "delete item",
203
+ "cancel order"
204
+ ],
205
+ "blockedSelectors": [
206
+ "input[type=\"password\"]",
207
+ "[data-sensitive=\"true\"]",
208
+ ".admin-only"
209
+ ],
210
+ "allowedDomains": [
211
+ "localhost",
212
+ "yourdomain.com"
213
+ ]
214
+ },
215
+
216
+ "privacy": {
217
+ "exposePasswords": false,
218
+ "exposeCreditCards": false,
219
+ "redactPatterns": [
220
+ "[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}",
221
+ "\\b\\d{3}[-.]?\\d{3}[-.]?\\d{4}\\b"
222
+ ]
223
+ }
224
+ }
225
+ ```
226
+
227
+ #### Configuration Properties:
228
+
229
+ | Property | Required | Description |
230
+ |----------|----------|-------------|
231
+ | `applicationId` | ✅ | Unique identifier for your application |
232
+ | `serverUrl` | ✅ | Backend API endpoint (WebSocket server URL) |
233
+ | `apiKey` | ✅ | Authentication key for backend connection |
234
+ | `pages` | ✅ | Array of page routes with allowed actions |
235
+ | `safetyRules` | ❌ | Safety configurations for dangerous actions |
236
+ | `privacy` | ❌ | Privacy settings for sensitive data |
237
+
238
+ #### Page Configuration Details:
239
+
240
+ Each page in the `pages` array defines:
241
+ - `route`: URL path (supports dynamic routes like `/users/:id`)
242
+ - `title`: Human-readable page name
243
+ - `safeActions`: Actions users can perform via voice/chat (e.g., "click submit", "fill email")
244
+ - `dangerousActions`: Actions requiring user confirmation before execution
245
+
246
+ #### Load the configuration in your app:
247
+
248
+ ```tsx
249
+ import { AIUIProvider } from 'esap-aiui-react';
250
+ import aiuiConfig from './aiui.config.json';
251
+
252
+ function App() {
253
+ return (
254
+ <AIUIProvider config={aiuiConfig}>
255
+ <YourApplication />
256
+ </AIUIProvider>
257
+ );
258
+ }
259
+ ```
260
+
261
+ **Why this file is required:**
262
+ - ✅ Backend connection - SDK needs `serverUrl` and `apiKey` to connect
263
+ - ✅ Route mapping - Defines which actions are available on each page
264
+ - ✅ Security - Prevents dangerous actions without confirmation
265
+ - ✅ Navigation - Enables voice commands like "navigate to dashboard"
266
+
267
+ Without this file, the SDK cannot connect to your backend or understand your application's structure.
268
+
158
269
  ## Quick Start
159
270
 
160
271
  ### Basic Integration
161
272
 
162
273
  ```tsx
163
- import { AIUIProvider, useAIUI } from '@espai/aiui-react-sdk';
164
- import type { AIUIConfig } from '@espai/aiui-react-sdk';
274
+ import { AIUIProvider, useAIUI } from 'esap-aiui-react';
275
+ import type { AIUIConfig } from 'esap-aiui-react';
165
276
 
166
277
  const config: AIUIConfig = {
167
278
  applicationId: 'production-app-v1',
@@ -204,7 +315,7 @@ function App() {
204
315
  ### Voice Control Component
205
316
 
206
317
  ```tsx
207
- import { useAIUI } from '@espai/aiui-react-sdk';
318
+ import { useAIUI } from 'esap-aiui-react';
208
319
 
209
320
  function VoiceController() {
210
321
  const {
@@ -238,7 +349,7 @@ function VoiceController() {
238
349
  ### Chat Interface Component
239
350
 
240
351
  ```tsx
241
- import { useAIUI } from '@espai/aiui-react-sdk';
352
+ import { useAIUI } from 'esap-aiui-react';
242
353
  import { useState } from 'react';
243
354
 
244
355
  function ChatController() {
@@ -486,7 +597,7 @@ interface ChatMessage {
486
597
  Execute UI actions programmatically without voice input:
487
598
 
488
599
  ```typescript
489
- import { useAIUI } from '@espai/aiui-react-sdk';
600
+ import { useAIUI } from 'esap-aiui-react';
490
601
 
491
602
  function DataTable() {
492
603
  const { executeAction } = useAIUI();
@@ -536,7 +647,7 @@ function DataTable() {
536
647
  Combine both voice and chat interfaces for flexible user interaction:
537
648
 
538
649
  ```tsx
539
- import { useAIUI } from '@espai/aiui-react-sdk';
650
+ import { useAIUI } from 'esap-aiui-react';
540
651
  import { useState } from 'react';
541
652
 
542
653
  function AIAssistant() {
@@ -751,7 +862,7 @@ The `data-select-options` attribute defines available options using `|||` as a d
751
862
  ### Programmatic Navigation
752
863
 
753
864
  ```typescript
754
- import { useAIUI } from '@espai/aiui-react-sdk';
865
+ import { useAIUI } from 'esap-aiui-react';
755
866
 
756
867
  function NavigationHandler() {
757
868
  const { executeAction } = useAIUI();
@@ -922,208 +1033,6 @@ The SDK communicates with a backend server implementing the AIUI protocol. The s
922
1033
  }
923
1034
  ```
924
1035
 
925
- ### Reference Server Implementation
926
-
927
- ```javascript
928
- const WebSocket = require('ws');
929
-
930
- // Create WebSocket server with three endpoints
931
- const contextServer = new WebSocket.Server({ port: 8080, path: '/context' });
932
- const audioServer = new WebSocket.Server({ port: 8080, path: '/audio' });
933
- const chatServer = new WebSocket.Server({ port: 8080, path: '/chat' });
934
-
935
- // Session management
936
- const sessions = new Map();
937
-
938
- // Context channel handler
939
- contextServer.on('connection', (ws, req) => {
940
- const url = new URL(req.url, 'ws://localhost');
941
- const applicationId = url.searchParams.get('applicationId');
942
- const apiKey = url.searchParams.get('apiKey');
943
-
944
- // Validate API key
945
- if (!validateApiKey(apiKey)) {
946
- ws.close(1008, 'Invalid API key');
947
- return;
948
- }
949
-
950
- console.log(`Context connected: ${applicationId}`);
951
-
952
- // Store session
953
- if (!sessions.has(applicationId)) {
954
- sessions.set(applicationId, {});
955
- }
956
- sessions.get(applicationId).contextWs = ws;
957
-
958
- ws.on('message', async (data) => {
959
- const message = JSON.parse(data.toString());
960
-
961
- if (message.type === 'context_update' || message.type === 'context_append') {
962
- // Store UI context for LLM
963
- const session = sessions.get(applicationId);
964
- session.uiContext = message.context || message.elements;
965
-
966
- console.log(`UI context updated: ${session.uiContext.elements?.length || 0} elements`);
967
- }
968
- });
969
-
970
- ws.on('close', () => {
971
- console.log(`Context disconnected: ${applicationId}`);
972
- });
973
- });
974
-
975
- // Audio channel handler (for voice mode)
976
- audioServer.on('connection', (ws, req) => {
977
- const url = new URL(req.url, 'ws://localhost');
978
- const applicationId = url.searchParams.get('applicationId');
979
-
980
- console.log(`Audio connected: ${applicationId}`);
981
-
982
- const session = sessions.get(applicationId);
983
- if (session) {
984
- session.audioWs = ws;
985
- }
986
-
987
- let audioBuffer = [];
988
-
989
- ws.on('message', async (data) => {
990
- if (data instanceof Buffer) {
991
- // Accumulate audio chunks
992
- audioBuffer.push(data);
993
-
994
- // Process when sufficient audio accumulated (e.g., 1 second)
995
- if (audioBuffer.length >= 50) { // 50 * 20ms = 1 second
996
- const audioData = Buffer.concat(audioBuffer);
997
- audioBuffer = [];
998
-
999
- // Send to Speech-to-Text service
1000
- const transcript = await speechToText(audioData);
1001
-
1002
- if (transcript && session?.uiContext) {
1003
- // Process with LLM
1004
- const action = await processWithLLM(transcript, session.uiContext);
1005
-
1006
- // Send action command via context channel
1007
- session.contextWs?.send(JSON.stringify({
1008
- type: 'action',
1009
- action: action.type,
1010
- params: action.params,
1011
- timestamp: new Date().toISOString()
1012
- }));
1013
-
1014
- // Generate TTS response
1015
- const audioResponse = await textToSpeech(action.response);
1016
-
1017
- // Send audio response
1018
- ws.send(audioResponse);
1019
- }
1020
- }
1021
- }
1022
- });
1023
-
1024
- ws.on('close', () => {
1025
- console.log(`Audio disconnected: ${applicationId}`);
1026
- });
1027
- });
1028
-
1029
- // Chat channel handler (for text mode)
1030
- chatServer.on('connection', (ws, req) => {
1031
- const url = new URL(req.url, 'ws://localhost');
1032
- const applicationId = url.searchParams.get('applicationId');
1033
-
1034
- console.log(`Chat connected: ${applicationId}`);
1035
-
1036
- const session = sessions.get(applicationId);
1037
- if (session) {
1038
- session.chatWs = ws;
1039
- }
1040
-
1041
- // Confirm connection
1042
- ws.send(JSON.stringify({ type: 'chat_connected' }));
1043
-
1044
- ws.on('message', async (data) => {
1045
- const message = JSON.parse(data.toString());
1046
-
1047
- if (message.type === 'chat_message') {
1048
- const userMessage = message.content;
1049
- console.log(`Chat message from ${applicationId}: ${userMessage}`);
1050
-
1051
- // Send typing indicator
1052
- ws.send(JSON.stringify({ type: 'chat_typing', typing: true }));
1053
-
1054
- if (session?.uiContext) {
1055
- // Process with LLM
1056
- const response = await processWithLLM(userMessage, session.uiContext);
1057
-
1058
- // Stop typing indicator
1059
- ws.send(JSON.stringify({ type: 'chat_typing', typing: false }));
1060
-
1061
- // If action required, send to context channel
1062
- if (response.action) {
1063
- session.contextWs?.send(JSON.stringify({
1064
- type: 'action',
1065
- action: response.type,
1066
- params: response.params,
1067
- timestamp: new Date().toISOString()
1068
- }));
1069
- }
1070
-
1071
- // Send chat response
1072
- ws.send(JSON.stringify({
1073
- type: 'chat_message',
1074
- role: 'assistant',
1075
- content: response.message,
1076
- timestamp: new Date().toISOString()
1077
- }));
1078
- } else {
1079
- ws.send(JSON.stringify({
1080
- type: 'chat_message',
1081
- role: 'assistant',
1082
- content: 'I don\'t have access to the UI context yet. Please ensure the page is loaded.',
1083
- timestamp: new Date().toISOString()
1084
- }));
1085
- }
1086
- }
1087
- });
1088
-
1089
- ws.on('close', () => {
1090
- console.log(`Chat disconnected: ${applicationId}`);
1091
- if (session) {
1092
- session.chatWs = null;
1093
- }
1094
- });
1095
- });
1096
-
1097
- async function processWithLLM(userInput, uiContext) {
1098
- const prompt = `
1099
- You are controlling a web application via ${typeof userInput === 'string' ? 'chat' : 'voice'}.
1100
-
1101
- Current UI Context:
1102
- ${JSON.stringify(uiContext, null, 2)}
1103
-
1104
- User input: "${userInput}"
1105
-
1106
- Determine if an action is needed and respond in JSON format:
1107
- {
1108
- "action": true/false,
1109
- "type": "click" | "set_value" | "select_from_dropdown" | "navigate",
1110
- "params": { "semantic": "element description", "value": "..." },
1111
- "message": "Response to user (what you did or information about the UI)"
1112
- }
1113
-
1114
- If the user is just asking for information about the UI, set action to false and provide the information in message.
1115
- `;
1116
-
1117
- const response = await openai.chat.completions.create({
1118
- model: "gpt-4",
1119
- messages: [{ role: "user", content: prompt }],
1120
- response_format: { type: "json_object" }
1121
- });
1122
-
1123
- return JSON.parse(response.choices[0].message.content);
1124
- }
1125
- ```
1126
-
1127
1036
  ### Production Deployment Considerations
1128
1037
 
1129
1038
  **Security:**
@@ -1267,8 +1176,8 @@ We welcome contributions from the community. Please review our contribution guid
1267
1176
 
1268
1177
  ```bash
1269
1178
  # Clone repository
1270
- git clone https://github.com/espai/aiui-react-sdk.git
1271
- cd aiui-react-sdk
1179
+ git clone https://github.com/espai/aiui-react.git
1180
+ cd aiui-react
1272
1181
 
1273
1182
  # Install dependencies
1274
1183
  npm install
@@ -1329,7 +1238,7 @@ If you use AIUI in academic research, please cite:
1329
1238
  title={AIUI: Autonomous Voice-Controlled UI Framework with Zero-Configuration Semantic Discovery},
1330
1239
  author={Atik, Md Mahabube Alahi},
1331
1240
  year={2025},
1332
- url={https://www.npmjs.com/package/@espai/aiui-react-sdk},
1241
+ url={https://www.npmjs.com/package/esap-aiui-react},
1333
1242
  version={1.0.21}
1334
1243
  }
1335
1244
  ```
@@ -1349,8 +1258,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
1349
1258
  ## Support
1350
1259
 
1351
1260
  **Community Support:**
1352
- - GitHub Issues: [Report bugs and request features](https://github.com/espai/aiui-react-sdk/issues)
1353
- - GitHub Discussions: [Community Q&A and ideas](https://github.com/espai/aiui-react-sdk/discussions)
1261
+ - GitHub Issues: [Report bugs and request features](https://github.com/espai/aiui-react/issues)
1262
+ - GitHub Discussions: [Community Q&A and ideas](https://github.com/espai/aiui-react/discussions)
1354
1263
  - Stack Overflow: Tag questions with `aiui-react`
1355
1264
 
1356
1265
  **Commercial Support:**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "esap-aiui-react",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "description": "Zero-configuration voice and chat control for React applications through autonomous semantic UI discovery",
6
6
  "main": "dist/index.js",
@@ -1,57 +0,0 @@
1
- import * as React from 'react';
2
- import type { ReactNode } from 'react';
3
- export interface AIUIConfig {
4
- applicationId: string;
5
- serverUrl: string;
6
- apiKey?: string;
7
- pages: MinimalPageConfig[];
8
- safetyRules?: SafetyRules;
9
- privacy?: PrivacyConfig;
10
- onNavigate?: (route: string) => void | Promise<void>;
11
- }
12
- export interface MinimalPageConfig {
13
- route: string;
14
- title?: string;
15
- safeActions?: string[];
16
- dangerousActions?: string[];
17
- }
18
- export interface SafetyRules {
19
- requireConfirmation?: string[];
20
- blockedSelectors?: string[];
21
- allowedDomains?: string[];
22
- }
23
- export interface PrivacyConfig {
24
- redactPatterns?: string[];
25
- exposePasswords?: boolean;
26
- exposeCreditCards?: boolean;
27
- }
28
- interface AIUIContextValue {
29
- config: AIUIConfig;
30
- isConnected: boolean;
31
- isListening: boolean;
32
- currentPage: string | null;
33
- connect: () => void;
34
- disconnect: () => void;
35
- startListening: () => Promise<void>;
36
- stopListening: () => void;
37
- sendChatMessage: (message: string) => Promise<void>;
38
- chatMessages: ChatMessage[];
39
- isChatConnected: boolean;
40
- executeAction: (action: string, params: any) => Promise<any>;
41
- getComponentValue: (selector: string) => any;
42
- registerComponent: (componentId: string, element: HTMLElement) => void;
43
- unregisterComponent: (componentId: string) => void;
44
- }
45
- export interface ChatMessage {
46
- role: 'user' | 'assistant';
47
- content: string;
48
- timestamp: string;
49
- }
50
- export declare const useAIUI: () => AIUIContextValue;
51
- export interface AIUIProviderProps {
52
- config: AIUIConfig;
53
- children: ReactNode;
54
- }
55
- export declare const AIUIProvider: React.FC<AIUIProviderProps>;
56
- export default AIUIProvider;
57
- //# sourceMappingURL=auuichat.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"auuichat.d.ts","sourceRoot":"","sources":["../src/auuichat.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAOvC,MAAM,WAAW,UAAU;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxD;AAED,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,WAAW;IACxB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,UAAU,gBAAgB;IACtB,MAAM,EAAE,UAAU,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,aAAa,EAAE,MAAM,IAAI,CAAC;IAE1B,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,eAAe,EAAE,OAAO,CAAC;IAEzB,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7D,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,CAAC;IAC7C,iBAAiB,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IACvE,mBAAmB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACtD;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACrB;AAID,eAAO,MAAM,OAAO,QAAO,gBAM1B,CAAC;AAu3DF,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACvB;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA6RpD,CAAC;AA6BF,eAAe,YAAY,CAAC"}