openclaw-bitchat 0.1.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.
package/README.md ADDED
@@ -0,0 +1,156 @@
1
+ # @openclaw/bitchat
2
+
3
+ OpenClaw channel plugin for Bitchat BLE mesh network.
4
+
5
+ > ⚠️ **Alpha Software** — This plugin and bitchat-node are experimental. APIs may change without notice.
6
+
7
+ ## Overview
8
+
9
+ This plugin enables OpenClaw to communicate via the Bitchat peer-to-peer BLE mesh network. Messages travel directly between devices over Bluetooth Low Energy without any central server.
10
+
11
+ **Requirements:**
12
+ - [bitchat-node](https://github.com/wkyleg/bitchat-node) running as a background service
13
+ - BLE-capable hardware (Mac, Linux with BlueZ, or Windows with BLE support)
14
+ - Other Bitchat peers nearby (iOS app, other nodes)
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ openclaw plugins install @openclaw/bitchat
20
+ ```
21
+
22
+ Or for development:
23
+
24
+ ```bash
25
+ openclaw plugins install -l /path/to/openclaw-bitchat
26
+ ```
27
+
28
+ ## Configuration
29
+
30
+ Add to your OpenClaw config (`~/.openclaw/openclaw.json`):
31
+
32
+ ```json5
33
+ {
34
+ channels: {
35
+ bitchat: {
36
+ enabled: true,
37
+ nickname: "my-agent",
38
+ bridgeUrl: "http://localhost:3939",
39
+ dmPolicy: "open", // or "allowlist", "disabled"
40
+ allowFrom: [], // peer IDs when using allowlist
41
+ },
42
+ },
43
+ }
44
+ ```
45
+
46
+ ### Configuration Options
47
+
48
+ | Option | Type | Default | Description |
49
+ |--------|------|---------|-------------|
50
+ | `enabled` | boolean | `true` | Enable/disable the channel |
51
+ | `nickname` | string | `"openclaw"` | Display name on the mesh network |
52
+ | `bridgeUrl` | string | `"http://localhost:3939"` | URL of the bitchat-node HTTP bridge |
53
+ | `webhookPath` | string | `"/bitchat-webhook"` | Webhook endpoint for incoming messages |
54
+ | `autoStart` | boolean | `false` | Auto-start bitchat-node daemon |
55
+ | `dmPolicy` | string | `"open"` | DM access policy (`open`, `allowlist`, `disabled`) |
56
+ | `allowFrom` | string[] | `[]` | Allowed peer IDs when using `allowlist` policy |
57
+
58
+ ## Usage
59
+
60
+ ### 1. Start bitchat-node
61
+
62
+ First, ensure bitchat-node is running:
63
+
64
+ ```bash
65
+ cd /path/to/bitchat-node
66
+ node dist/bin/bitchat.js --nickname=MyAgent --port=3939
67
+ ```
68
+
69
+ Or run it as a background service.
70
+
71
+ ### 2. Configure OpenClaw
72
+
73
+ Add the bitchat channel configuration to your OpenClaw config.
74
+
75
+ ### 3. Restart OpenClaw Gateway
76
+
77
+ ```bash
78
+ openclaw gateway restart
79
+ ```
80
+
81
+ ### 4. Test
82
+
83
+ Send a message from a Bitchat peer (iOS app or another node). OpenClaw will receive it and route it to a session.
84
+
85
+ To send messages via OpenClaw:
86
+
87
+ ```bash
88
+ # Via message tool in session
89
+ message tool with channel=bitchat, target=<peerID>, message="Hello!"
90
+ ```
91
+
92
+ ## Architecture
93
+
94
+ ```
95
+ ┌─────────────────────┐ ┌──────────────────────┐ ┌─────────────────┐
96
+ │ Bitchat Peers │ │ bitchat-node │ │ OpenClaw │
97
+ │ (iOS, Android, │◄───►│ (BLE + HTTP) │◄───►│ Gateway │
98
+ │ other nodes) │ BLE │ localhost:3939 │HTTP │ + Plugin │
99
+ └─────────────────────┘ └──────────────────────┘ └─────────────────┘
100
+ ```
101
+
102
+ 1. **bitchat-node** maintains BLE connections to nearby peers
103
+ 2. **HTTP Bridge** exposes REST API for sending/receiving messages
104
+ 3. **OpenClaw Plugin** polls the bridge or receives webhooks for incoming messages
105
+ 4. **Outbound messages** go through the bridge API to the BLE mesh
106
+
107
+ ## API Endpoints (bitchat-node)
108
+
109
+ The plugin communicates with bitchat-node via these endpoints:
110
+
111
+ | Endpoint | Method | Description |
112
+ |----------|--------|-------------|
113
+ | `/api/status` | GET | Get node status (peerID, nickname, peer count) |
114
+ | `/api/peers` | GET | List connected peers |
115
+ | `/api/messages` | GET | Get recent messages (polling, `?since=timestamp`) |
116
+ | `/api/send` | POST | Send a message (`{ type, text, recipientPeerID? }`) |
117
+ | `/api/webhook` | POST | Register a webhook URL |
118
+
119
+ ## Limitations
120
+
121
+ - **BLE Range**: Messages only propagate within BLE range (~10-100m)
122
+ - **No Media**: BLE bandwidth is limited; text-only messaging
123
+ - **No Persistence**: Messages are ephemeral; no server-side storage
124
+ - **Peer Discovery**: Requires active BLE scanning/advertising
125
+
126
+ ## Security Considerations
127
+
128
+ - **Local Only**: All communication is local mesh; nothing leaves your network
129
+ - **No Encryption for Public**: Public messages are unencrypted
130
+ - **DM Encryption**: Direct messages use Noise protocol encryption
131
+ - **DM Policy**: Configure `dmPolicy` and `allowFrom` to restrict who can message
132
+
133
+ ## Development
134
+
135
+ ```bash
136
+ # Clone and install
137
+ git clone https://github.com/wkyleg/openclaw-bitchat.git
138
+ cd openclaw-bitchat
139
+ npm install
140
+
141
+ # Build
142
+ npm run build
143
+
144
+ # Link for development
145
+ openclaw plugins install -l .
146
+ ```
147
+
148
+ ## Related
149
+
150
+ - [bitchat-node](https://github.com/wkyleg/bitchat-node) — Node.js Bitchat implementation
151
+ - [Bitchat iOS](https://github.com/...) — Original iOS implementation
152
+ - [OpenClaw Plugins](https://docs.openclaw.ai/plugins) — Plugin development guide
153
+
154
+ ## License
155
+
156
+ [Unlicense](https://unlicense.org/) — Public Domain
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Bitchat Bridge
3
+ *
4
+ * Handles communication with the bitchat-node HTTP bridge.
5
+ * Supports both polling and WebSocket connections for real-time messages.
6
+ */
7
+ import type { BitchatInboundMessage } from './index.js';
8
+ import type { Logger } from './types.js';
9
+ export interface BridgeOptions {
10
+ bridgeUrl: string;
11
+ nickname: string;
12
+ onMessage: (msg: BitchatInboundMessage) => Promise<void>;
13
+ logger: Logger;
14
+ pollIntervalMs?: number;
15
+ }
16
+ interface BridgeStatus {
17
+ connected: boolean;
18
+ peerID?: string;
19
+ nickname?: string;
20
+ peersCount?: number;
21
+ }
22
+ interface PendingMessage {
23
+ id: string;
24
+ type: 'public' | 'direct';
25
+ senderPeerID: string;
26
+ senderNickname: string;
27
+ text: string;
28
+ timestamp: number;
29
+ }
30
+ export declare class BitchatBridge {
31
+ private readonly bridgeUrl;
32
+ private readonly onMessage;
33
+ private readonly logger;
34
+ private readonly pollIntervalMs;
35
+ private connected;
36
+ private pollTimer;
37
+ private lastMessageTimestamp;
38
+ private ws;
39
+ constructor(options: BridgeOptions);
40
+ /**
41
+ * Connect to the bitchat-node bridge
42
+ */
43
+ connect(): Promise<void>;
44
+ /**
45
+ * Disconnect from the bridge
46
+ */
47
+ disconnect(): Promise<void>;
48
+ /**
49
+ * Check if connected
50
+ */
51
+ isConnected(): boolean;
52
+ /**
53
+ * Get bridge status
54
+ */
55
+ getStatus(): Promise<BridgeStatus>;
56
+ /**
57
+ * Send a public message to all peers
58
+ */
59
+ sendPublicMessage(text: string): Promise<void>;
60
+ /**
61
+ * Send a direct message to a specific peer
62
+ */
63
+ sendDirectMessage(recipientPeerID: string, text: string): Promise<void>;
64
+ /**
65
+ * Get list of known peers
66
+ */
67
+ getPeers(): Promise<{
68
+ peerID: string;
69
+ nickname: string;
70
+ lastSeen: number;
71
+ }[]>;
72
+ /**
73
+ * Get recent messages (for polling)
74
+ */
75
+ getMessages(since?: number): Promise<PendingMessage[]>;
76
+ /**
77
+ * Register webhook for incoming messages
78
+ */
79
+ registerWebhook(webhookUrl: string): Promise<void>;
80
+ /**
81
+ * Connect via WebSocket for real-time messages
82
+ */
83
+ private connectWebSocket;
84
+ /**
85
+ * Start polling for messages
86
+ */
87
+ private startPolling;
88
+ }
89
+ export {};
90
+ //# sourceMappingURL=bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,YAAY;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgD;IAC1E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAA+C;IAChE,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,EAAE,CAA0B;gBAExB,OAAO,EAAE,aAAa;IAOlC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAsB9B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAcjC;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;IAQxC;;OAEG;IACG,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAapD;;OAEG;IACG,iBAAiB,CAAC,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAa7E;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAQnF;;OAEG;IACG,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAY5D;;OAEG;IACG,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAaxD;;OAEG;YACW,gBAAgB;IAwD9B;;OAEG;IACH,OAAO,CAAC,YAAY;CAmCrB"}
package/dist/bridge.js ADDED
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Bitchat Bridge
3
+ *
4
+ * Handles communication with the bitchat-node HTTP bridge.
5
+ * Supports both polling and WebSocket connections for real-time messages.
6
+ */
7
+ export class BitchatBridge {
8
+ bridgeUrl;
9
+ onMessage;
10
+ logger;
11
+ pollIntervalMs;
12
+ connected = false;
13
+ pollTimer = null;
14
+ lastMessageTimestamp = 0;
15
+ ws = null;
16
+ constructor(options) {
17
+ this.bridgeUrl = options.bridgeUrl.replace(/\/$/, ''); // Remove trailing slash
18
+ this.onMessage = options.onMessage;
19
+ this.logger = options.logger;
20
+ this.pollIntervalMs = options.pollIntervalMs ?? 2000;
21
+ }
22
+ /**
23
+ * Connect to the bitchat-node bridge
24
+ */
25
+ async connect() {
26
+ // First, verify the bridge is reachable
27
+ try {
28
+ const status = await this.getStatus();
29
+ this.logger.info(`[bitchat-bridge] Connected to bridge. PeerID: ${status.peerID}`);
30
+ this.connected = true;
31
+ }
32
+ catch (err) {
33
+ this.logger.error('[bitchat-bridge] Failed to connect to bridge:', err);
34
+ throw err;
35
+ }
36
+ // Try WebSocket first, fall back to polling
37
+ const wsUrl = this.bridgeUrl.replace(/^http/, 'ws') + '/ws';
38
+ try {
39
+ await this.connectWebSocket(wsUrl);
40
+ this.logger.info('[bitchat-bridge] WebSocket connected');
41
+ }
42
+ catch {
43
+ this.logger.info('[bitchat-bridge] WebSocket unavailable, using polling');
44
+ this.startPolling();
45
+ }
46
+ }
47
+ /**
48
+ * Disconnect from the bridge
49
+ */
50
+ async disconnect() {
51
+ this.connected = false;
52
+ if (this.pollTimer) {
53
+ clearInterval(this.pollTimer);
54
+ this.pollTimer = null;
55
+ }
56
+ if (this.ws) {
57
+ this.ws.close();
58
+ this.ws = null;
59
+ }
60
+ }
61
+ /**
62
+ * Check if connected
63
+ */
64
+ isConnected() {
65
+ return this.connected;
66
+ }
67
+ /**
68
+ * Get bridge status
69
+ */
70
+ async getStatus() {
71
+ const response = await fetch(`${this.bridgeUrl}/api/status`);
72
+ if (!response.ok) {
73
+ throw new Error(`Bridge status failed: ${response.status}`);
74
+ }
75
+ return response.json();
76
+ }
77
+ /**
78
+ * Send a public message to all peers
79
+ */
80
+ async sendPublicMessage(text) {
81
+ const response = await fetch(`${this.bridgeUrl}/api/send`, {
82
+ method: 'POST',
83
+ headers: { 'Content-Type': 'application/json' },
84
+ body: JSON.stringify({ type: 'public', text }),
85
+ });
86
+ if (!response.ok) {
87
+ const error = await response.text();
88
+ throw new Error(`Failed to send public message: ${error}`);
89
+ }
90
+ }
91
+ /**
92
+ * Send a direct message to a specific peer
93
+ */
94
+ async sendDirectMessage(recipientPeerID, text) {
95
+ const response = await fetch(`${this.bridgeUrl}/api/send`, {
96
+ method: 'POST',
97
+ headers: { 'Content-Type': 'application/json' },
98
+ body: JSON.stringify({ type: 'direct', recipientPeerID, text }),
99
+ });
100
+ if (!response.ok) {
101
+ const error = await response.text();
102
+ throw new Error(`Failed to send direct message: ${error}`);
103
+ }
104
+ }
105
+ /**
106
+ * Get list of known peers
107
+ */
108
+ async getPeers() {
109
+ const response = await fetch(`${this.bridgeUrl}/api/peers`);
110
+ if (!response.ok) {
111
+ throw new Error(`Failed to get peers: ${response.status}`);
112
+ }
113
+ return response.json();
114
+ }
115
+ /**
116
+ * Get recent messages (for polling)
117
+ */
118
+ async getMessages(since) {
119
+ const url = since
120
+ ? `${this.bridgeUrl}/api/messages?since=${since}`
121
+ : `${this.bridgeUrl}/api/messages`;
122
+ const response = await fetch(url);
123
+ if (!response.ok) {
124
+ throw new Error(`Failed to get messages: ${response.status}`);
125
+ }
126
+ return response.json();
127
+ }
128
+ /**
129
+ * Register webhook for incoming messages
130
+ */
131
+ async registerWebhook(webhookUrl) {
132
+ const response = await fetch(`${this.bridgeUrl}/api/webhook`, {
133
+ method: 'POST',
134
+ headers: { 'Content-Type': 'application/json' },
135
+ body: JSON.stringify({ url: webhookUrl }),
136
+ });
137
+ if (!response.ok) {
138
+ const error = await response.text();
139
+ throw new Error(`Failed to register webhook: ${error}`);
140
+ }
141
+ }
142
+ /**
143
+ * Connect via WebSocket for real-time messages
144
+ */
145
+ async connectWebSocket(wsUrl) {
146
+ return new Promise((resolve, reject) => {
147
+ try {
148
+ // Note: In Node.js, we'd use the 'ws' package
149
+ // This is a simplified version that may need adjustment
150
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
151
+ const WebSocketImpl = typeof WebSocket !== 'undefined' ? WebSocket : require('ws');
152
+ const ws = new WebSocketImpl(wsUrl);
153
+ this.ws = ws;
154
+ const timeout = setTimeout(() => {
155
+ reject(new Error('WebSocket connection timeout'));
156
+ }, 5000);
157
+ ws.onopen = () => {
158
+ clearTimeout(timeout);
159
+ resolve();
160
+ };
161
+ ws.onerror = (err) => {
162
+ clearTimeout(timeout);
163
+ reject(err);
164
+ };
165
+ ws.onmessage = async (event) => {
166
+ try {
167
+ const data = JSON.parse(String(event.data));
168
+ if (data.type === 'message') {
169
+ await this.onMessage({
170
+ type: data.isDirect ? 'direct' : 'public',
171
+ senderPeerID: data.senderPeerID,
172
+ senderNickname: data.senderNickname,
173
+ text: data.text,
174
+ timestamp: data.timestamp,
175
+ messageId: data.id ?? `ws-${Date.now()}`,
176
+ });
177
+ }
178
+ }
179
+ catch (err) {
180
+ this.logger.error('[bitchat-bridge] WebSocket message parse error:', err);
181
+ }
182
+ };
183
+ ws.onclose = () => {
184
+ this.logger.info('[bitchat-bridge] WebSocket closed');
185
+ this.ws = null;
186
+ // Reconnect or fall back to polling
187
+ if (this.connected) {
188
+ this.startPolling();
189
+ }
190
+ };
191
+ }
192
+ catch (err) {
193
+ reject(err);
194
+ }
195
+ });
196
+ }
197
+ /**
198
+ * Start polling for messages
199
+ */
200
+ startPolling() {
201
+ if (this.pollTimer) {
202
+ return; // Already polling
203
+ }
204
+ this.logger.info(`[bitchat-bridge] Starting message polling (${this.pollIntervalMs}ms)`);
205
+ this.pollTimer = setInterval(async () => {
206
+ if (!this.connected) {
207
+ return;
208
+ }
209
+ try {
210
+ const messages = await this.getMessages(this.lastMessageTimestamp);
211
+ for (const msg of messages) {
212
+ // Update timestamp to avoid duplicates
213
+ if (msg.timestamp > this.lastMessageTimestamp) {
214
+ this.lastMessageTimestamp = msg.timestamp;
215
+ }
216
+ await this.onMessage({
217
+ type: msg.type,
218
+ senderPeerID: msg.senderPeerID,
219
+ senderNickname: msg.senderNickname,
220
+ text: msg.text,
221
+ timestamp: msg.timestamp,
222
+ messageId: msg.id,
223
+ });
224
+ }
225
+ }
226
+ catch (err) {
227
+ this.logger.error('[bitchat-bridge] Poll error:', err);
228
+ }
229
+ }, this.pollIntervalMs);
230
+ }
231
+ }
232
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @openclaw/bitchat - Bitchat BLE Mesh Channel Plugin
3
+ *
4
+ * This plugin enables OpenClaw to communicate via the Bitchat
5
+ * peer-to-peer BLE mesh network.
6
+ *
7
+ * Architecture:
8
+ * - bitchat-node runs as a background service (separate process)
9
+ * - This plugin communicates with it via HTTP bridge
10
+ * - Inbound: webhook from bitchat-node → OpenClaw session
11
+ * - Outbound: OpenClaw → HTTP API → bitchat-node → BLE mesh
12
+ */
13
+ import type { PluginApi, ChannelPlugin } from './types.js';
14
+ export interface BitchatConfig {
15
+ enabled?: boolean;
16
+ nickname?: string;
17
+ bridgeUrl?: string;
18
+ webhookPath?: string;
19
+ autoStart?: boolean;
20
+ dmPolicy?: 'open' | 'allowlist' | 'disabled';
21
+ allowFrom?: string[];
22
+ }
23
+ export interface BitchatInboundMessage {
24
+ type: 'public' | 'direct';
25
+ senderPeerID: string;
26
+ senderNickname: string;
27
+ text: string;
28
+ timestamp: number;
29
+ messageId: string;
30
+ }
31
+ /**
32
+ * Main plugin registration
33
+ */
34
+ export default function register(api: PluginApi): void;
35
+ export type { PluginApi, ChannelPlugin };
36
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAI3D,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAGD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAiID;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAqHrD;AAGD,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC"}