@framers/agentos 0.1.26 → 0.1.28
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/dist/api/AgentOSOrchestrator.js +1 -1
- package/dist/api/AgentOSOrchestrator.js.map +1 -1
- package/dist/channels/ChannelRouter.d.ts.map +1 -1
- package/dist/channels/ChannelRouter.js +1 -1
- package/dist/channels/ChannelRouter.js.map +1 -1
- package/dist/channels/IChannelAdapter.d.ts.map +1 -1
- package/dist/channels/adapters/BaseChannelAdapter.d.ts +130 -0
- package/dist/channels/adapters/BaseChannelAdapter.d.ts.map +1 -0
- package/dist/channels/adapters/BaseChannelAdapter.js +257 -0
- package/dist/channels/adapters/BaseChannelAdapter.js.map +1 -0
- package/dist/channels/adapters/DiscordChannelAdapter.d.ts +86 -0
- package/dist/channels/adapters/DiscordChannelAdapter.d.ts.map +1 -0
- package/dist/channels/adapters/DiscordChannelAdapter.js +550 -0
- package/dist/channels/adapters/DiscordChannelAdapter.js.map +1 -0
- package/dist/channels/adapters/GoogleChatChannelAdapter.d.ts +117 -0
- package/dist/channels/adapters/GoogleChatChannelAdapter.d.ts.map +1 -0
- package/dist/channels/adapters/GoogleChatChannelAdapter.js +632 -0
- package/dist/channels/adapters/GoogleChatChannelAdapter.js.map +1 -0
- package/dist/channels/adapters/IRCChannelAdapter.d.ts +86 -0
- package/dist/channels/adapters/IRCChannelAdapter.d.ts.map +1 -0
- package/dist/channels/adapters/IRCChannelAdapter.js +253 -0
- package/dist/channels/adapters/IRCChannelAdapter.js.map +1 -0
- package/dist/channels/adapters/RedditChannelAdapter.d.ts +123 -0
- package/dist/channels/adapters/RedditChannelAdapter.d.ts.map +1 -0
- package/dist/channels/adapters/RedditChannelAdapter.js +516 -0
- package/dist/channels/adapters/RedditChannelAdapter.js.map +1 -0
- package/dist/channels/adapters/SignalChannelAdapter.d.ts +120 -0
- package/dist/channels/adapters/SignalChannelAdapter.d.ts.map +1 -0
- package/dist/channels/adapters/SignalChannelAdapter.js +521 -0
- package/dist/channels/adapters/SignalChannelAdapter.js.map +1 -0
- package/dist/channels/adapters/SlackChannelAdapter.d.ts +96 -0
- package/dist/channels/adapters/SlackChannelAdapter.d.ts.map +1 -0
- package/dist/channels/adapters/SlackChannelAdapter.js +535 -0
- package/dist/channels/adapters/SlackChannelAdapter.js.map +1 -0
- package/dist/channels/adapters/TeamsChannelAdapter.d.ts +138 -0
- package/dist/channels/adapters/TeamsChannelAdapter.d.ts.map +1 -0
- package/dist/channels/adapters/TeamsChannelAdapter.js +639 -0
- package/dist/channels/adapters/TeamsChannelAdapter.js.map +1 -0
- package/dist/channels/adapters/TelegramChannelAdapter.d.ts +83 -0
- package/dist/channels/adapters/TelegramChannelAdapter.d.ts.map +1 -0
- package/dist/channels/adapters/TelegramChannelAdapter.js +463 -0
- package/dist/channels/adapters/TelegramChannelAdapter.js.map +1 -0
- package/dist/channels/adapters/TwitterChannelAdapter.d.ts +117 -0
- package/dist/channels/adapters/TwitterChannelAdapter.d.ts.map +1 -0
- package/dist/channels/adapters/TwitterChannelAdapter.js +489 -0
- package/dist/channels/adapters/TwitterChannelAdapter.js.map +1 -0
- package/dist/channels/adapters/WebChatChannelAdapter.d.ts +141 -0
- package/dist/channels/adapters/WebChatChannelAdapter.d.ts.map +1 -0
- package/dist/channels/adapters/WebChatChannelAdapter.js +539 -0
- package/dist/channels/adapters/WebChatChannelAdapter.js.map +1 -0
- package/dist/channels/adapters/WhatsAppChannelAdapter.d.ts +122 -0
- package/dist/channels/adapters/WhatsAppChannelAdapter.d.ts.map +1 -0
- package/dist/channels/adapters/WhatsAppChannelAdapter.js +643 -0
- package/dist/channels/adapters/WhatsAppChannelAdapter.js.map +1 -0
- package/dist/channels/adapters/index.d.ts +34 -0
- package/dist/channels/adapters/index.d.ts.map +1 -0
- package/dist/channels/adapters/index.js +25 -0
- package/dist/channels/adapters/index.js.map +1 -0
- package/dist/channels/index.d.ts +24 -0
- package/dist/channels/index.d.ts.map +1 -1
- package/dist/channels/index.js +16 -0
- package/dist/channels/index.js.map +1 -1
- package/dist/cognitive_substrate/personas/metaprompt_presets.d.ts.map +1 -1
- package/dist/cognitive_substrate/personas/metaprompt_presets.js +0 -2
- package/dist/cognitive_substrate/personas/metaprompt_presets.js.map +1 -1
- package/dist/core/provenance/crypto/HashChain.d.ts.map +1 -1
- package/dist/core/provenance/enforcement/AutonomyGuard.d.ts.map +1 -1
- package/dist/core/provenance/enforcement/ProvenanceStorageHooks.d.ts.map +1 -1
- package/dist/core/provenance/enforcement/ProvenanceStorageHooks.js +2 -1
- package/dist/core/provenance/enforcement/ProvenanceStorageHooks.js.map +1 -1
- package/dist/core/provenance/ledger/EventTypes.d.ts.map +1 -1
- package/dist/core/safety/ToolExecutionGuard.d.ts.map +1 -1
- package/dist/core/safety/ToolExecutionGuard.js +0 -1
- package/dist/core/safety/ToolExecutionGuard.js.map +1 -1
- package/dist/extensions/ExtensionManager.d.ts.map +1 -1
- package/dist/extensions/ExtensionManager.js +3 -9
- package/dist/extensions/ExtensionManager.js.map +1 -1
- package/dist/rag/RetrievalAugmentor.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview WhatsApp Channel Adapter for AgentOS.
|
|
3
|
+
*
|
|
4
|
+
* Supports two connection modes:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Twilio WhatsApp API** — Uses the `twilio` npm package. Messages are
|
|
7
|
+
* sent via the Twilio REST API and inbound messages arrive via webhooks.
|
|
8
|
+
* 2. **WhatsApp Business API (Cloud API)** — Uses direct HTTP calls to the
|
|
9
|
+
* Meta Graph API. No third-party SDK required.
|
|
10
|
+
*
|
|
11
|
+
* In both modes, the adapter requires a webhook endpoint to be configured
|
|
12
|
+
* externally (e.g., an Express/Fastify route) that forwards incoming HTTP
|
|
13
|
+
* requests to {@link handleIncomingWebhook}.
|
|
14
|
+
*
|
|
15
|
+
* **Dependencies**: For Twilio mode, requires the `twilio` package. For
|
|
16
|
+
* Cloud API mode, no external dependencies are needed (uses native fetch).
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // Twilio mode
|
|
21
|
+
* const wa = new WhatsAppChannelAdapter();
|
|
22
|
+
* await wa.initialize({
|
|
23
|
+
* platform: 'whatsapp',
|
|
24
|
+
* credential: 'TWILIO_AUTH_TOKEN',
|
|
25
|
+
* params: {
|
|
26
|
+
* provider: 'twilio',
|
|
27
|
+
* accountSid: 'ACXXXXXXX',
|
|
28
|
+
* authToken: 'TWILIO_AUTH_TOKEN',
|
|
29
|
+
* phoneNumber: '+14155238886',
|
|
30
|
+
* },
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* // Cloud API mode
|
|
34
|
+
* await wa.initialize({
|
|
35
|
+
* platform: 'whatsapp',
|
|
36
|
+
* credential: 'WHATSAPP_BUSINESS_TOKEN',
|
|
37
|
+
* params: {
|
|
38
|
+
* provider: 'cloud-api',
|
|
39
|
+
* businessApiToken: 'WHATSAPP_BUSINESS_TOKEN',
|
|
40
|
+
* phoneNumberId: '1234567890',
|
|
41
|
+
* verifyToken: 'MY_VERIFY_TOKEN',
|
|
42
|
+
* },
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @module @framers/agentos/channels/adapters/WhatsAppChannelAdapter
|
|
47
|
+
*/
|
|
48
|
+
import { BaseChannelAdapter } from './BaseChannelAdapter.js';
|
|
49
|
+
// ============================================================================
|
|
50
|
+
// WhatsAppChannelAdapter
|
|
51
|
+
// ============================================================================
|
|
52
|
+
/**
|
|
53
|
+
* Channel adapter for WhatsApp supporting both Twilio and Meta Cloud API.
|
|
54
|
+
*
|
|
55
|
+
* This adapter does NOT start its own HTTP server. Instead, the host
|
|
56
|
+
* application must configure a webhook route and call
|
|
57
|
+
* {@link handleIncomingWebhook} with the raw request body.
|
|
58
|
+
*
|
|
59
|
+
* Capabilities: text, images, video, audio, voice_notes, documents,
|
|
60
|
+
* reactions, buttons, group_chat.
|
|
61
|
+
*/
|
|
62
|
+
export class WhatsAppChannelAdapter extends BaseChannelAdapter {
|
|
63
|
+
constructor() {
|
|
64
|
+
super(...arguments);
|
|
65
|
+
this.platform = 'whatsapp';
|
|
66
|
+
this.displayName = 'WhatsApp';
|
|
67
|
+
this.capabilities = [
|
|
68
|
+
'text',
|
|
69
|
+
'images',
|
|
70
|
+
'video',
|
|
71
|
+
'audio',
|
|
72
|
+
'voice_notes',
|
|
73
|
+
'documents',
|
|
74
|
+
'reactions',
|
|
75
|
+
'buttons',
|
|
76
|
+
'group_chat',
|
|
77
|
+
];
|
|
78
|
+
/** Provider mode. */
|
|
79
|
+
this.provider = 'twilio';
|
|
80
|
+
this.graphApiVersion = 'v21.0';
|
|
81
|
+
}
|
|
82
|
+
// ── Abstract hook implementations ──
|
|
83
|
+
async doConnect(auth) {
|
|
84
|
+
const params = auth.params ?? {};
|
|
85
|
+
this.provider = params.provider ?? 'twilio';
|
|
86
|
+
if (this.provider === 'twilio') {
|
|
87
|
+
await this.connectTwilio(auth, params);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
await this.connectCloudApi(auth, params);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async doSendMessage(conversationId, content) {
|
|
94
|
+
if (this.provider === 'twilio') {
|
|
95
|
+
return this.sendViaTwilio(conversationId, content);
|
|
96
|
+
}
|
|
97
|
+
return this.sendViaCloudApi(conversationId, content);
|
|
98
|
+
}
|
|
99
|
+
async doShutdown() {
|
|
100
|
+
this.twilioClient = undefined;
|
|
101
|
+
this.businessApiToken = undefined;
|
|
102
|
+
this.phoneNumber = undefined;
|
|
103
|
+
this.phoneNumberId = undefined;
|
|
104
|
+
console.log('[WhatsApp] Adapter shut down.');
|
|
105
|
+
}
|
|
106
|
+
// ── IChannelAdapter optional methods ──
|
|
107
|
+
async addReaction(conversationId, messageId, emoji) {
|
|
108
|
+
if (this.provider !== 'cloud-api' || !this.businessApiToken || !this.phoneNumberId) {
|
|
109
|
+
console.warn('[WhatsApp] Reactions are only supported via the Cloud API.');
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const url = `https://graph.facebook.com/${this.graphApiVersion}/${this.phoneNumberId}/messages`;
|
|
113
|
+
const body = {
|
|
114
|
+
messaging_product: 'whatsapp',
|
|
115
|
+
to: conversationId,
|
|
116
|
+
type: 'reaction',
|
|
117
|
+
reaction: {
|
|
118
|
+
message_id: messageId,
|
|
119
|
+
emoji,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
await fetch(url, {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
headers: {
|
|
125
|
+
Authorization: `Bearer ${this.businessApiToken}`,
|
|
126
|
+
'Content-Type': 'application/json',
|
|
127
|
+
},
|
|
128
|
+
body: JSON.stringify(body),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
// ── Public: Webhook handler ──
|
|
132
|
+
/**
|
|
133
|
+
* Handle an incoming webhook request from WhatsApp (Twilio or Cloud API).
|
|
134
|
+
*
|
|
135
|
+
* The host application should forward the raw request body to this method.
|
|
136
|
+
* For Cloud API, this also handles webhook verification (GET requests
|
|
137
|
+
* with `hub.mode=subscribe`).
|
|
138
|
+
*
|
|
139
|
+
* @param body - Parsed JSON body of the webhook request.
|
|
140
|
+
* @param queryParams - Query parameters (for Cloud API verification).
|
|
141
|
+
* @returns Verification challenge string for GET requests, or void.
|
|
142
|
+
*/
|
|
143
|
+
handleIncomingWebhook(body, queryParams) {
|
|
144
|
+
// Cloud API webhook verification (GET request)
|
|
145
|
+
if (queryParams?.['hub.mode'] === 'subscribe' &&
|
|
146
|
+
queryParams?.['hub.verify_token']) {
|
|
147
|
+
if (queryParams['hub.verify_token'] === this.verifyToken) {
|
|
148
|
+
return queryParams['hub.challenge'] ?? '';
|
|
149
|
+
}
|
|
150
|
+
console.warn('[WhatsApp] Webhook verification failed — token mismatch.');
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (this.provider === 'twilio') {
|
|
154
|
+
this.handleTwilioWebhook(body);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
this.handleCloudApiWebhook(body);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// ── Private: Twilio ──
|
|
161
|
+
async connectTwilio(auth, params) {
|
|
162
|
+
const accountSid = params.accountSid;
|
|
163
|
+
const authToken = params.authToken ?? auth.credential;
|
|
164
|
+
this.phoneNumber = params.phoneNumber;
|
|
165
|
+
if (!accountSid) {
|
|
166
|
+
throw new Error('Twilio accountSid is required for WhatsApp (Twilio mode).');
|
|
167
|
+
}
|
|
168
|
+
if (!authToken) {
|
|
169
|
+
throw new Error('Twilio authToken is required for WhatsApp (Twilio mode).');
|
|
170
|
+
}
|
|
171
|
+
if (!this.phoneNumber) {
|
|
172
|
+
throw new Error('WhatsApp phone number is required for Twilio mode.');
|
|
173
|
+
}
|
|
174
|
+
// Ensure phone number has whatsapp: prefix
|
|
175
|
+
if (!this.phoneNumber.startsWith('whatsapp:')) {
|
|
176
|
+
this.phoneNumber = `whatsapp:${this.phoneNumber}`;
|
|
177
|
+
}
|
|
178
|
+
// Dynamic import
|
|
179
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
180
|
+
let TwilioModule;
|
|
181
|
+
try {
|
|
182
|
+
TwilioModule = await import('twilio');
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
throw new Error('The "twilio" package is required for WhatsApp (Twilio mode). ' +
|
|
186
|
+
'Install it with: npm install twilio');
|
|
187
|
+
}
|
|
188
|
+
const TwilioClient = TwilioModule.default ?? TwilioModule.Twilio ?? TwilioModule;
|
|
189
|
+
this.twilioClient = new TwilioClient(accountSid, authToken);
|
|
190
|
+
// Verify credentials by fetching account info
|
|
191
|
+
try {
|
|
192
|
+
const account = await this.twilioClient.api.accounts(accountSid).fetch();
|
|
193
|
+
this.platformInfo = {
|
|
194
|
+
provider: 'twilio',
|
|
195
|
+
accountSid,
|
|
196
|
+
phoneNumber: this.phoneNumber,
|
|
197
|
+
accountName: account.friendlyName,
|
|
198
|
+
};
|
|
199
|
+
console.log(`[WhatsApp] Connected via Twilio (${account.friendlyName}, ${this.phoneNumber})`);
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
// Credentials might still be valid for messaging even if account fetch fails
|
|
203
|
+
this.platformInfo = {
|
|
204
|
+
provider: 'twilio',
|
|
205
|
+
accountSid,
|
|
206
|
+
phoneNumber: this.phoneNumber,
|
|
207
|
+
};
|
|
208
|
+
console.log(`[WhatsApp] Connected via Twilio (${this.phoneNumber})`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async sendViaTwilio(conversationId, content) {
|
|
212
|
+
if (!this.twilioClient || !this.phoneNumber) {
|
|
213
|
+
throw new Error('[WhatsApp] Twilio client is not connected.');
|
|
214
|
+
}
|
|
215
|
+
// Ensure destination has whatsapp: prefix
|
|
216
|
+
const to = conversationId.startsWith('whatsapp:')
|
|
217
|
+
? conversationId
|
|
218
|
+
: `whatsapp:${conversationId}`;
|
|
219
|
+
let lastSid = '';
|
|
220
|
+
let lastTimestamp = '';
|
|
221
|
+
for (const block of content.blocks) {
|
|
222
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
223
|
+
const msgPayload = {
|
|
224
|
+
from: this.phoneNumber,
|
|
225
|
+
to,
|
|
226
|
+
};
|
|
227
|
+
switch (block.type) {
|
|
228
|
+
case 'text':
|
|
229
|
+
msgPayload.body = block.text;
|
|
230
|
+
break;
|
|
231
|
+
case 'image':
|
|
232
|
+
msgPayload.mediaUrl = [block.url];
|
|
233
|
+
msgPayload.body = block.caption ?? '';
|
|
234
|
+
break;
|
|
235
|
+
case 'video':
|
|
236
|
+
msgPayload.mediaUrl = [block.url];
|
|
237
|
+
msgPayload.body = block.caption ?? '';
|
|
238
|
+
break;
|
|
239
|
+
case 'audio':
|
|
240
|
+
msgPayload.mediaUrl = [block.url];
|
|
241
|
+
break;
|
|
242
|
+
case 'document':
|
|
243
|
+
msgPayload.mediaUrl = [block.url];
|
|
244
|
+
msgPayload.body = block.filename;
|
|
245
|
+
break;
|
|
246
|
+
case 'location':
|
|
247
|
+
// Twilio doesn't support native location — send as text
|
|
248
|
+
msgPayload.body = `Location: ${block.latitude}, ${block.longitude}${block.name ? ` (${block.name})` : ''}`;
|
|
249
|
+
break;
|
|
250
|
+
case 'button_group':
|
|
251
|
+
// Twilio interactive messages — fall back to text
|
|
252
|
+
msgPayload.body = block.buttons
|
|
253
|
+
.map((btn, i) => `${i + 1}. ${btn.label}`)
|
|
254
|
+
.join('\n');
|
|
255
|
+
break;
|
|
256
|
+
default:
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
if (!msgPayload.body && !msgPayload.mediaUrl)
|
|
260
|
+
continue;
|
|
261
|
+
const result = await this.twilioClient.messages.create(msgPayload);
|
|
262
|
+
lastSid = result.sid ?? '';
|
|
263
|
+
lastTimestamp = result.dateCreated?.toISOString() ?? new Date().toISOString();
|
|
264
|
+
}
|
|
265
|
+
if (!lastSid) {
|
|
266
|
+
throw new Error('[WhatsApp] No content blocks produced a sent message.');
|
|
267
|
+
}
|
|
268
|
+
return {
|
|
269
|
+
messageId: lastSid,
|
|
270
|
+
timestamp: lastTimestamp,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
handleTwilioWebhook(body) {
|
|
274
|
+
// Twilio sends form-encoded data; by the time it reaches us it should be parsed
|
|
275
|
+
const from = String(body.From ?? '').replace('whatsapp:', '');
|
|
276
|
+
const to = String(body.To ?? '').replace('whatsapp:', '');
|
|
277
|
+
const messageBody = String(body.Body ?? '');
|
|
278
|
+
const messageSid = String(body.MessageSid ?? '');
|
|
279
|
+
const numMedia = parseInt(String(body.NumMedia ?? '0'), 10);
|
|
280
|
+
if (!from || !messageSid)
|
|
281
|
+
return;
|
|
282
|
+
const contentBlocks = [];
|
|
283
|
+
// Text
|
|
284
|
+
if (messageBody) {
|
|
285
|
+
contentBlocks.push({ type: 'text', text: messageBody });
|
|
286
|
+
}
|
|
287
|
+
// Media attachments
|
|
288
|
+
for (let i = 0; i < numMedia; i++) {
|
|
289
|
+
const mediaUrl = String(body[`MediaUrl${i}`] ?? '');
|
|
290
|
+
const mediaType = String(body[`MediaContentType${i}`] ?? '');
|
|
291
|
+
if (!mediaUrl)
|
|
292
|
+
continue;
|
|
293
|
+
if (mediaType.startsWith('image/')) {
|
|
294
|
+
contentBlocks.push({ type: 'image', url: mediaUrl, mimeType: mediaType });
|
|
295
|
+
}
|
|
296
|
+
else if (mediaType.startsWith('video/')) {
|
|
297
|
+
contentBlocks.push({ type: 'video', url: mediaUrl, mimeType: mediaType });
|
|
298
|
+
}
|
|
299
|
+
else if (mediaType.startsWith('audio/')) {
|
|
300
|
+
contentBlocks.push({ type: 'audio', url: mediaUrl, mimeType: mediaType });
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
contentBlocks.push({
|
|
304
|
+
type: 'document',
|
|
305
|
+
url: mediaUrl,
|
|
306
|
+
filename: `attachment_${i}`,
|
|
307
|
+
mimeType: mediaType,
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (contentBlocks.length === 0) {
|
|
312
|
+
contentBlocks.push({ type: 'text', text: '' });
|
|
313
|
+
}
|
|
314
|
+
const channelMessage = {
|
|
315
|
+
messageId: messageSid,
|
|
316
|
+
platform: 'whatsapp',
|
|
317
|
+
conversationId: from,
|
|
318
|
+
conversationType: 'direct',
|
|
319
|
+
sender: {
|
|
320
|
+
id: from,
|
|
321
|
+
displayName: String(body.ProfileName ?? undefined),
|
|
322
|
+
},
|
|
323
|
+
content: contentBlocks,
|
|
324
|
+
text: messageBody,
|
|
325
|
+
timestamp: new Date().toISOString(),
|
|
326
|
+
rawEvent: body,
|
|
327
|
+
};
|
|
328
|
+
this.emit({
|
|
329
|
+
type: 'message',
|
|
330
|
+
platform: 'whatsapp',
|
|
331
|
+
conversationId: from,
|
|
332
|
+
timestamp: channelMessage.timestamp,
|
|
333
|
+
data: channelMessage,
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
// ── Private: Cloud API (Meta) ──
|
|
337
|
+
async connectCloudApi(auth, params) {
|
|
338
|
+
this.businessApiToken = params.businessApiToken ?? auth.credential;
|
|
339
|
+
this.phoneNumberId = params.phoneNumberId;
|
|
340
|
+
this.graphApiVersion = params.apiVersion ?? 'v21.0';
|
|
341
|
+
this.verifyToken = params.verifyToken;
|
|
342
|
+
if (!this.businessApiToken) {
|
|
343
|
+
throw new Error('WhatsApp Business API token is required. Provide it as credential or params.businessApiToken.');
|
|
344
|
+
}
|
|
345
|
+
if (!this.phoneNumberId) {
|
|
346
|
+
throw new Error('phoneNumberId is required for WhatsApp Cloud API mode.');
|
|
347
|
+
}
|
|
348
|
+
// Verify token by fetching phone number info
|
|
349
|
+
try {
|
|
350
|
+
const url = `https://graph.facebook.com/${this.graphApiVersion}/${this.phoneNumberId}`;
|
|
351
|
+
const resp = await fetch(url, {
|
|
352
|
+
headers: { Authorization: `Bearer ${this.businessApiToken}` },
|
|
353
|
+
});
|
|
354
|
+
if (!resp.ok) {
|
|
355
|
+
throw new Error(`HTTP ${resp.status}: ${await resp.text()}`);
|
|
356
|
+
}
|
|
357
|
+
const data = await resp.json();
|
|
358
|
+
this.platformInfo = {
|
|
359
|
+
provider: 'cloud-api',
|
|
360
|
+
phoneNumberId: this.phoneNumberId,
|
|
361
|
+
displayPhoneNumber: data.display_phone_number,
|
|
362
|
+
verifiedName: data.verified_name,
|
|
363
|
+
apiVersion: this.graphApiVersion,
|
|
364
|
+
};
|
|
365
|
+
console.log(`[WhatsApp] Connected via Cloud API (${data.verified_name ?? this.phoneNumberId})`);
|
|
366
|
+
}
|
|
367
|
+
catch (err) {
|
|
368
|
+
// Still allow connection — the token might work for sending even if GET fails
|
|
369
|
+
this.platformInfo = {
|
|
370
|
+
provider: 'cloud-api',
|
|
371
|
+
phoneNumberId: this.phoneNumberId,
|
|
372
|
+
apiVersion: this.graphApiVersion,
|
|
373
|
+
};
|
|
374
|
+
console.warn(`[WhatsApp] Cloud API credential verification failed: ${err}`);
|
|
375
|
+
console.log(`[WhatsApp] Connected via Cloud API (${this.phoneNumberId})`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
async sendViaCloudApi(conversationId, content) {
|
|
379
|
+
if (!this.businessApiToken || !this.phoneNumberId) {
|
|
380
|
+
throw new Error('[WhatsApp] Cloud API credentials not configured.');
|
|
381
|
+
}
|
|
382
|
+
const url = `https://graph.facebook.com/${this.graphApiVersion}/${this.phoneNumberId}/messages`;
|
|
383
|
+
let lastMessageId = '';
|
|
384
|
+
let lastTimestamp = '';
|
|
385
|
+
for (const block of content.blocks) {
|
|
386
|
+
const payload = this.buildCloudApiPayload(conversationId, block, content);
|
|
387
|
+
if (!payload)
|
|
388
|
+
continue;
|
|
389
|
+
const resp = await fetch(url, {
|
|
390
|
+
method: 'POST',
|
|
391
|
+
headers: {
|
|
392
|
+
Authorization: `Bearer ${this.businessApiToken}`,
|
|
393
|
+
'Content-Type': 'application/json',
|
|
394
|
+
},
|
|
395
|
+
body: JSON.stringify(payload),
|
|
396
|
+
});
|
|
397
|
+
if (!resp.ok) {
|
|
398
|
+
const errorText = await resp.text();
|
|
399
|
+
throw new Error(`[WhatsApp] Cloud API error ${resp.status}: ${errorText}`);
|
|
400
|
+
}
|
|
401
|
+
const result = await resp.json();
|
|
402
|
+
const messages = result.messages;
|
|
403
|
+
if (messages?.[0]?.id) {
|
|
404
|
+
lastMessageId = messages[0].id;
|
|
405
|
+
lastTimestamp = new Date().toISOString();
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
if (!lastMessageId) {
|
|
409
|
+
throw new Error('[WhatsApp] No content blocks produced a sent message.');
|
|
410
|
+
}
|
|
411
|
+
return {
|
|
412
|
+
messageId: lastMessageId,
|
|
413
|
+
timestamp: lastTimestamp,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Build a Cloud API message payload for a single content block.
|
|
418
|
+
*/
|
|
419
|
+
buildCloudApiPayload(to, block, content) {
|
|
420
|
+
const base = {
|
|
421
|
+
messaging_product: 'whatsapp',
|
|
422
|
+
to,
|
|
423
|
+
...(content.replyToMessageId
|
|
424
|
+
? { context: { message_id: content.replyToMessageId } }
|
|
425
|
+
: {}),
|
|
426
|
+
};
|
|
427
|
+
switch (block.type) {
|
|
428
|
+
case 'text':
|
|
429
|
+
return { ...base, type: 'text', text: { body: block.text } };
|
|
430
|
+
case 'image':
|
|
431
|
+
return {
|
|
432
|
+
...base,
|
|
433
|
+
type: 'image',
|
|
434
|
+
image: {
|
|
435
|
+
link: block.url,
|
|
436
|
+
caption: block.caption,
|
|
437
|
+
},
|
|
438
|
+
};
|
|
439
|
+
case 'video':
|
|
440
|
+
return {
|
|
441
|
+
...base,
|
|
442
|
+
type: 'video',
|
|
443
|
+
video: {
|
|
444
|
+
link: block.url,
|
|
445
|
+
caption: block.caption,
|
|
446
|
+
},
|
|
447
|
+
};
|
|
448
|
+
case 'audio':
|
|
449
|
+
return {
|
|
450
|
+
...base,
|
|
451
|
+
type: 'audio',
|
|
452
|
+
audio: { link: block.url },
|
|
453
|
+
};
|
|
454
|
+
case 'document':
|
|
455
|
+
return {
|
|
456
|
+
...base,
|
|
457
|
+
type: 'document',
|
|
458
|
+
document: {
|
|
459
|
+
link: block.url,
|
|
460
|
+
filename: block.filename,
|
|
461
|
+
},
|
|
462
|
+
};
|
|
463
|
+
case 'location':
|
|
464
|
+
return {
|
|
465
|
+
...base,
|
|
466
|
+
type: 'location',
|
|
467
|
+
location: {
|
|
468
|
+
latitude: block.latitude,
|
|
469
|
+
longitude: block.longitude,
|
|
470
|
+
name: block.name,
|
|
471
|
+
},
|
|
472
|
+
};
|
|
473
|
+
case 'sticker':
|
|
474
|
+
return {
|
|
475
|
+
...base,
|
|
476
|
+
type: 'sticker',
|
|
477
|
+
sticker: { id: block.stickerId },
|
|
478
|
+
};
|
|
479
|
+
case 'button_group': {
|
|
480
|
+
// WhatsApp interactive message with buttons
|
|
481
|
+
const textBlock = content.blocks.find((b) => b.type === 'text');
|
|
482
|
+
const bodyText = textBlock && textBlock.type === 'text'
|
|
483
|
+
? textBlock.text
|
|
484
|
+
: 'Choose an option:';
|
|
485
|
+
return {
|
|
486
|
+
...base,
|
|
487
|
+
type: 'interactive',
|
|
488
|
+
interactive: {
|
|
489
|
+
type: 'button',
|
|
490
|
+
body: { text: bodyText },
|
|
491
|
+
action: {
|
|
492
|
+
buttons: block.buttons.slice(0, 3).map((btn) => ({
|
|
493
|
+
type: 'reply',
|
|
494
|
+
reply: {
|
|
495
|
+
id: btn.id,
|
|
496
|
+
title: btn.label.slice(0, 20), // WhatsApp limits to 20 chars
|
|
497
|
+
},
|
|
498
|
+
})),
|
|
499
|
+
},
|
|
500
|
+
},
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
default:
|
|
504
|
+
return undefined;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
handleCloudApiWebhook(body) {
|
|
508
|
+
// Cloud API webhook structure:
|
|
509
|
+
// { object: 'whatsapp_business_account', entry: [{ changes: [{ value: { messages: [...] } }] }] }
|
|
510
|
+
const entries = (body.entry ?? []);
|
|
511
|
+
for (const entry of entries) {
|
|
512
|
+
const changes = (entry.changes ?? []);
|
|
513
|
+
for (const change of changes) {
|
|
514
|
+
const value = change.value;
|
|
515
|
+
if (!value)
|
|
516
|
+
continue;
|
|
517
|
+
const messages = (value.messages ?? []);
|
|
518
|
+
const contacts = (value.contacts ?? []);
|
|
519
|
+
for (const msg of messages) {
|
|
520
|
+
const from = String(msg.from ?? '');
|
|
521
|
+
const msgId = String(msg.id ?? '');
|
|
522
|
+
const msgType = String(msg.type ?? 'text');
|
|
523
|
+
const timestamp = msg.timestamp
|
|
524
|
+
? new Date(parseInt(String(msg.timestamp), 10) * 1000).toISOString()
|
|
525
|
+
: new Date().toISOString();
|
|
526
|
+
// Find contact info
|
|
527
|
+
const contact = contacts.find((c) => c.wa_id === from);
|
|
528
|
+
const profileName = contact
|
|
529
|
+
? contact.profile?.name
|
|
530
|
+
: undefined;
|
|
531
|
+
const contentBlocks = [];
|
|
532
|
+
switch (msgType) {
|
|
533
|
+
case 'text': {
|
|
534
|
+
const textData = msg.text;
|
|
535
|
+
contentBlocks.push({ type: 'text', text: String(textData?.body ?? '') });
|
|
536
|
+
break;
|
|
537
|
+
}
|
|
538
|
+
case 'image': {
|
|
539
|
+
const imgData = msg.image;
|
|
540
|
+
contentBlocks.push({
|
|
541
|
+
type: 'image',
|
|
542
|
+
url: String(imgData?.id ?? ''),
|
|
543
|
+
caption: imgData?.caption ? String(imgData.caption) : undefined,
|
|
544
|
+
mimeType: imgData?.mime_type ? String(imgData.mime_type) : undefined,
|
|
545
|
+
});
|
|
546
|
+
break;
|
|
547
|
+
}
|
|
548
|
+
case 'video': {
|
|
549
|
+
const vidData = msg.video;
|
|
550
|
+
contentBlocks.push({
|
|
551
|
+
type: 'video',
|
|
552
|
+
url: String(vidData?.id ?? ''),
|
|
553
|
+
caption: vidData?.caption ? String(vidData.caption) : undefined,
|
|
554
|
+
mimeType: vidData?.mime_type ? String(vidData.mime_type) : undefined,
|
|
555
|
+
});
|
|
556
|
+
break;
|
|
557
|
+
}
|
|
558
|
+
case 'audio': {
|
|
559
|
+
const audioData = msg.audio;
|
|
560
|
+
contentBlocks.push({
|
|
561
|
+
type: 'audio',
|
|
562
|
+
url: String(audioData?.id ?? ''),
|
|
563
|
+
mimeType: audioData?.mime_type ? String(audioData.mime_type) : undefined,
|
|
564
|
+
});
|
|
565
|
+
break;
|
|
566
|
+
}
|
|
567
|
+
case 'document': {
|
|
568
|
+
const docData = msg.document;
|
|
569
|
+
contentBlocks.push({
|
|
570
|
+
type: 'document',
|
|
571
|
+
url: String(docData?.id ?? ''),
|
|
572
|
+
filename: String(docData?.filename ?? 'document'),
|
|
573
|
+
mimeType: docData?.mime_type ? String(docData.mime_type) : undefined,
|
|
574
|
+
});
|
|
575
|
+
break;
|
|
576
|
+
}
|
|
577
|
+
case 'sticker': {
|
|
578
|
+
const stickerData = msg.sticker;
|
|
579
|
+
contentBlocks.push({
|
|
580
|
+
type: 'sticker',
|
|
581
|
+
stickerId: String(stickerData?.id ?? ''),
|
|
582
|
+
});
|
|
583
|
+
break;
|
|
584
|
+
}
|
|
585
|
+
case 'location': {
|
|
586
|
+
const locData = msg.location;
|
|
587
|
+
contentBlocks.push({
|
|
588
|
+
type: 'location',
|
|
589
|
+
latitude: Number(locData?.latitude ?? 0),
|
|
590
|
+
longitude: Number(locData?.longitude ?? 0),
|
|
591
|
+
name: locData?.name ? String(locData.name) : undefined,
|
|
592
|
+
});
|
|
593
|
+
break;
|
|
594
|
+
}
|
|
595
|
+
default:
|
|
596
|
+
contentBlocks.push({ type: 'text', text: `[Unsupported message type: ${msgType}]` });
|
|
597
|
+
break;
|
|
598
|
+
}
|
|
599
|
+
if (contentBlocks.length === 0) {
|
|
600
|
+
contentBlocks.push({ type: 'text', text: '' });
|
|
601
|
+
}
|
|
602
|
+
// Extract text for convenience field
|
|
603
|
+
const text = contentBlocks
|
|
604
|
+
.filter((b) => b.type === 'text')
|
|
605
|
+
.map((b) => b.text)
|
|
606
|
+
.join('\n');
|
|
607
|
+
const channelMessage = {
|
|
608
|
+
messageId: msgId,
|
|
609
|
+
platform: 'whatsapp',
|
|
610
|
+
conversationId: from,
|
|
611
|
+
conversationType: 'direct',
|
|
612
|
+
sender: {
|
|
613
|
+
id: from,
|
|
614
|
+
displayName: profileName ? String(profileName) : undefined,
|
|
615
|
+
},
|
|
616
|
+
content: contentBlocks,
|
|
617
|
+
text,
|
|
618
|
+
timestamp,
|
|
619
|
+
replyToMessageId: msg.context
|
|
620
|
+
? String(msg.context.id ?? '')
|
|
621
|
+
: undefined,
|
|
622
|
+
rawEvent: msg,
|
|
623
|
+
};
|
|
624
|
+
this.emit({
|
|
625
|
+
type: 'message',
|
|
626
|
+
platform: 'whatsapp',
|
|
627
|
+
conversationId: from,
|
|
628
|
+
timestamp: channelMessage.timestamp,
|
|
629
|
+
data: channelMessage,
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
// Handle status updates (delivered, read, etc.) — emit as connection events
|
|
633
|
+
const statuses = (value.statuses ?? []);
|
|
634
|
+
for (const status of statuses) {
|
|
635
|
+
if (status.status === 'read') {
|
|
636
|
+
// Could be used for read receipts in the future
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
//# sourceMappingURL=WhatsAppChannelAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WhatsAppChannelAdapter.js","sourceRoot":"","sources":["../../../src/channels/adapters/WhatsAppChannelAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAWH,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AA8B7D,+EAA+E;AAC/E,yBAAyB;AACzB,+EAA+E;AAE/E;;;;;;;;;GASG;AACH,MAAM,OAAO,sBAAuB,SAAQ,kBAAsC;IAAlF;;QACW,aAAQ,GAAoB,UAAU,CAAC;QACvC,gBAAW,GAAG,UAAU,CAAC;QACzB,iBAAY,GAAiC;YACpD,MAAM;YACN,QAAQ;YACR,OAAO;YACP,OAAO;YACP,aAAa;YACb,WAAW;YACX,WAAW;YACX,SAAS;YACT,YAAY;SACJ,CAAC;QAMX,qBAAqB;QACb,aAAQ,GAA2B,QAAQ,CAAC;QAM5C,oBAAe,GAAG,OAAO,CAAC;IA0pBpC,CAAC;IAvpBC,sCAAsC;IAE5B,KAAK,CAAC,SAAS,CACvB,IAAyD;QAEzD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAK,EAAyB,CAAC;QACzD,IAAI,CAAC,QAAQ,GAAI,MAAM,CAAC,QAAmC,IAAI,QAAQ,CAAC;QAExE,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC/B,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACzC,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAES,KAAK,CAAC,aAAa,CAC3B,cAAsB,EACtB,OAAuB;QAEvB,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC,aAAa,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,IAAI,CAAC,eAAe,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IACvD,CAAC;IAES,KAAK,CAAC,UAAU;QACxB,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;QAC9B,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;QAClC,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;QAC7B,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAC/C,CAAC;IAED,yCAAyC;IAEzC,KAAK,CAAC,WAAW,CACf,cAAsB,EACtB,SAAiB,EACjB,KAAa;QAEb,IAAI,IAAI,CAAC,QAAQ,KAAK,WAAW,IAAI,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACnF,OAAO,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;YAC3E,OAAO;QACT,CAAC;QAED,MAAM,GAAG,GAAG,8BAA8B,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,aAAa,WAAW,CAAC;QAChG,MAAM,IAAI,GAAG;YACX,iBAAiB,EAAE,UAAU;YAC7B,EAAE,EAAE,cAAc;YAClB,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE;gBACR,UAAU,EAAE,SAAS;gBACrB,KAAK;aACN;SACF,CAAC;QAEF,MAAM,KAAK,CAAC,GAAG,EAAE;YACf,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,IAAI,CAAC,gBAAgB,EAAE;gBAChD,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,gCAAgC;IAEhC;;;;;;;;;;OAUG;IACH,qBAAqB,CACnB,IAA6B,EAC7B,WAAoC;QAEpC,+CAA+C;QAC/C,IACE,WAAW,EAAE,CAAC,UAAU,CAAC,KAAK,WAAW;YACzC,WAAW,EAAE,CAAC,kBAAkB,CAAC,EACjC,CAAC;YACD,IAAI,WAAW,CAAC,kBAAkB,CAAC,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;gBACzD,OAAO,WAAW,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;YAC5C,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;YACzE,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC/B,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED,wBAAwB;IAEhB,KAAK,CAAC,aAAa,CACzB,IAAuB,EACvB,MAA0B;QAE1B,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;QACrC,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC,UAAU,CAAC;QACtD,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QAEtC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC/E,CAAC;QACD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;QAC9E,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACxE,CAAC;QAED,2CAA2C;QAC3C,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC9C,IAAI,CAAC,WAAW,GAAG,YAAY,IAAI,CAAC,WAAW,EAAE,CAAC;QACpD,CAAC;QAED,iBAAiB;QACjB,8DAA8D;QAC9D,IAAI,YAAiB,CAAC;QACtB,IAAI,CAAC;YACH,YAAY,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QACxC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CACb,+DAA+D;gBAC7D,qCAAqC,CACxC,CAAC;QACJ,CAAC;QAED,MAAM,YAAY,GAAG,YAAY,CAAC,OAAO,IAAI,YAAY,CAAC,MAAM,IAAI,YAAY,CAAC;QACjF,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QAE5D,8CAA8C;QAC9C,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,CAAC;YACzE,IAAI,CAAC,YAAY,GAAG;gBAClB,QAAQ,EAAE,QAAQ;gBAClB,UAAU;gBACV,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,WAAW,EAAE,OAAO,CAAC,YAAY;aAClC,CAAC;YACF,OAAO,CAAC,GAAG,CACT,oCAAoC,OAAO,CAAC,YAAY,KAAK,IAAI,CAAC,WAAW,GAAG,CACjF,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,6EAA6E;YAC7E,IAAI,CAAC,YAAY,GAAG;gBAClB,QAAQ,EAAE,QAAQ;gBAClB,UAAU;gBACV,WAAW,EAAE,IAAI,CAAC,WAAW;aAC9B,CAAC;YACF,OAAO,CAAC,GAAG,CAAC,oCAAoC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,aAAa,CACzB,cAAsB,EACtB,OAAuB;QAEvB,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YAC5C,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QAED,0CAA0C;QAC1C,MAAM,EAAE,GAAG,cAAc,CAAC,UAAU,CAAC,WAAW,CAAC;YAC/C,CAAC,CAAC,cAAc;YAChB,CAAC,CAAC,YAAY,cAAc,EAAE,CAAC;QAEjC,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,IAAI,aAAa,GAAG,EAAE,CAAC;QAEvB,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnC,8DAA8D;YAC9D,MAAM,UAAU,GAAQ;gBACtB,IAAI,EAAE,IAAI,CAAC,WAAW;gBACtB,EAAE;aACH,CAAC;YAEF,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;gBACnB,KAAK,MAAM;oBACT,UAAU,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;oBAC7B,MAAM;gBACR,KAAK,OAAO;oBACV,UAAU,CAAC,QAAQ,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBAClC,UAAU,CAAC,IAAI,GAAG,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;oBACtC,MAAM;gBACR,KAAK,OAAO;oBACV,UAAU,CAAC,QAAQ,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBAClC,UAAU,CAAC,IAAI,GAAG,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;oBACtC,MAAM;gBACR,KAAK,OAAO;oBACV,UAAU,CAAC,QAAQ,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBAClC,MAAM;gBACR,KAAK,UAAU;oBACb,UAAU,CAAC,QAAQ,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBAClC,UAAU,CAAC,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC;oBACjC,MAAM;gBACR,KAAK,UAAU;oBACb,wDAAwD;oBACxD,UAAU,CAAC,IAAI,GAAG,aAAa,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;oBAC3G,MAAM;gBACR,KAAK,cAAc;oBACjB,kDAAkD;oBAClD,UAAU,CAAC,IAAI,GAAG,KAAK,CAAC,OAAO;yBAC5B,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC;yBACzC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACd,MAAM;gBACR;oBACE,SAAS;YACb,CAAC;YAED,IAAI,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ;gBAAE,SAAS;YAEvD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACnE,OAAO,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;YAC3B,aAAa,GAAG,MAAM,CAAC,WAAW,EAAE,WAAW,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAChF,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC3E,CAAC;QAED,OAAO;YACL,SAAS,EAAE,OAAO;YAClB,SAAS,EAAE,aAAa;SACzB,CAAC;IACJ,CAAC;IAEO,mBAAmB,CAAC,IAA6B;QACvD,gFAAgF;QAChF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC9D,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC1D,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QAC5C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;QACjD,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QAE5D,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO;QAEjC,MAAM,aAAa,GAA0B,EAAE,CAAC;QAEhD,OAAO;QACP,IAAI,WAAW,EAAE,CAAC;YAChB,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QAC1D,CAAC;QAED,oBAAoB;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;YAClC,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;YACpD,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;YAE7D,IAAI,CAAC,QAAQ;gBAAE,SAAS;YAExB,IAAI,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACnC,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;YAC5E,CAAC;iBAAM,IAAI,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC1C,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;YAC5E,CAAC;iBAAM,IAAI,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC1C,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;YAC5E,CAAC;iBAAM,CAAC;gBACN,aAAa,CAAC,IAAI,CAAC;oBACjB,IAAI,EAAE,UAAU;oBAChB,GAAG,EAAE,QAAQ;oBACb,QAAQ,EAAE,cAAc,CAAC,EAAE;oBAC3B,QAAQ,EAAE,SAAS;iBACpB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACjD,CAAC;QAED,MAAM,cAAc,GAAmB;YACrC,SAAS,EAAE,UAAU;YACrB,QAAQ,EAAE,UAAU;YACpB,cAAc,EAAE,IAAI;YACpB,gBAAgB,EAAE,QAAQ;YAC1B,MAAM,EAAE;gBACN,EAAE,EAAE,IAAI;gBACR,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,IAAI,SAAS,CAAC;aACnD;YACD,OAAO,EAAE,aAAa;YACtB,IAAI,EAAE,WAAW;YACjB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,QAAQ,EAAE,IAAI;SACf,CAAC;QAEF,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,SAAS;YACf,QAAQ,EAAE,UAAU;YACpB,cAAc,EAAE,IAAI;YACpB,SAAS,EAAE,cAAc,CAAC,SAAS;YACnC,IAAI,EAAE,cAAc;SACrB,CAAC,CAAC;IACL,CAAC;IAED,kCAAkC;IAE1B,KAAK,CAAC,eAAe,CAC3B,IAAuB,EACvB,MAA0B;QAE1B,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,IAAI,IAAI,CAAC,UAAU,CAAC;QACnE,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;QAC1C,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC,UAAU,IAAI,OAAO,CAAC;QACpD,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QAEtC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CACb,+FAA+F,CAChG,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;QAC5E,CAAC;QAED,6CAA6C;QAC7C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,8BAA8B,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvF,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAC5B,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,gBAAgB,EAAE,EAAE;aAC9D,CAAC,CAAC;YAEH,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;gBACb,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC/D,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAA6B,CAAC;YAC1D,IAAI,CAAC,YAAY,GAAG;gBAClB,QAAQ,EAAE,WAAW;gBACrB,aAAa,EAAE,IAAI,CAAC,aAAa;gBACjC,kBAAkB,EAAE,IAAI,CAAC,oBAAoB;gBAC7C,YAAY,EAAE,IAAI,CAAC,aAAa;gBAChC,UAAU,EAAE,IAAI,CAAC,eAAe;aACjC,CAAC;YACF,OAAO,CAAC,GAAG,CACT,uCAAuC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,aAAa,GAAG,CACnF,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,8EAA8E;YAC9E,IAAI,CAAC,YAAY,GAAG;gBAClB,QAAQ,EAAE,WAAW;gBACrB,aAAa,EAAE,IAAI,CAAC,aAAa;gBACjC,UAAU,EAAE,IAAI,CAAC,eAAe;aACjC,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,wDAAwD,GAAG,EAAE,CAAC,CAAC;YAC5E,OAAO,CAAC,GAAG,CAAC,uCAAuC,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,eAAe,CAC3B,cAAsB,EACtB,OAAuB;QAEvB,IAAI,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YAClD,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACtE,CAAC;QAED,MAAM,GAAG,GAAG,8BAA8B,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,aAAa,WAAW,CAAC;QAChG,IAAI,aAAa,GAAG,EAAE,CAAC;QACvB,IAAI,aAAa,GAAG,EAAE,CAAC;QAEvB,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnC,MAAM,OAAO,GAAG,IAAI,CAAC,oBAAoB,CAAC,cAAc,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;YAC1E,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAC5B,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,IAAI,CAAC,gBAAgB,EAAE;oBAChD,cAAc,EAAE,kBAAkB;iBACnC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;aAC9B,CAAC,CAAC;YAEH,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;gBACb,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;gBACpC,MAAM,IAAI,KAAK,CAAC,8BAA8B,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC,CAAC;YAC7E,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAA6B,CAAC;YAC5D,MAAM,QAAQ,GAAG,MAAM,CAAC,QAA6C,CAAC;YACtE,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC;gBACtB,aAAa,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/B,aAAa,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAC3C,CAAC;QACH,CAAC;QAED,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC3E,CAAC;QAED,OAAO;YACL,SAAS,EAAE,aAAa;YACxB,SAAS,EAAE,aAAa;SACzB,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,oBAAoB,CAC1B,EAAU,EACV,KAA0B,EAC1B,OAAuB;QAEvB,MAAM,IAAI,GAAG;YACX,iBAAiB,EAAE,UAAU;YAC7B,EAAE;YACF,GAAG,CAAC,OAAO,CAAC,gBAAgB;gBAC1B,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,gBAAgB,EAAE,EAAE;gBACvD,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;QAEF,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,MAAM;gBACT,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YAE/D,KAAK,OAAO;gBACV,OAAO;oBACL,GAAG,IAAI;oBACP,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE;wBACL,IAAI,EAAE,KAAK,CAAC,GAAG;wBACf,OAAO,EAAE,KAAK,CAAC,OAAO;qBACvB;iBACF,CAAC;YAEJ,KAAK,OAAO;gBACV,OAAO;oBACL,GAAG,IAAI;oBACP,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE;wBACL,IAAI,EAAE,KAAK,CAAC,GAAG;wBACf,OAAO,EAAE,KAAK,CAAC,OAAO;qBACvB;iBACF,CAAC;YAEJ,KAAK,OAAO;gBACV,OAAO;oBACL,GAAG,IAAI;oBACP,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,EAAE;iBAC3B,CAAC;YAEJ,KAAK,UAAU;gBACb,OAAO;oBACL,GAAG,IAAI;oBACP,IAAI,EAAE,UAAU;oBAChB,QAAQ,EAAE;wBACR,IAAI,EAAE,KAAK,CAAC,GAAG;wBACf,QAAQ,EAAE,KAAK,CAAC,QAAQ;qBACzB;iBACF,CAAC;YAEJ,KAAK,UAAU;gBACb,OAAO;oBACL,GAAG,IAAI;oBACP,IAAI,EAAE,UAAU;oBAChB,QAAQ,EAAE;wBACR,QAAQ,EAAE,KAAK,CAAC,QAAQ;wBACxB,SAAS,EAAE,KAAK,CAAC,SAAS;wBAC1B,IAAI,EAAE,KAAK,CAAC,IAAI;qBACjB;iBACF,CAAC;YAEJ,KAAK,SAAS;gBACZ,OAAO;oBACL,GAAG,IAAI;oBACP,IAAI,EAAE,SAAS;oBACf,OAAO,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,SAAS,EAAE;iBACjC,CAAC;YAEJ,KAAK,cAAc,CAAC,CAAC,CAAC;gBACpB,4CAA4C;gBAC5C,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;gBAChE,MAAM,QAAQ,GACZ,SAAS,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM;oBACpC,CAAC,CAAC,SAAS,CAAC,IAAI;oBAChB,CAAC,CAAC,mBAAmB,CAAC;gBAE1B,OAAO;oBACL,GAAG,IAAI;oBACP,IAAI,EAAE,aAAa;oBACnB,WAAW,EAAE;wBACX,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBACxB,MAAM,EAAE;4BACN,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gCAC/C,IAAI,EAAE,OAAO;gCACb,KAAK,EAAE;oCACL,EAAE,EAAE,GAAG,CAAC,EAAE;oCACV,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,8BAA8B;iCAC9D;6BACF,CAAC,CAAC;yBACJ;qBACF;iBACF,CAAC;YACJ,CAAC;YAED;gBACE,OAAO,SAAS,CAAC;QACrB,CAAC;IACH,CAAC;IAEO,qBAAqB,CAAC,IAA6B;QACzD,+BAA+B;QAC/B,kGAAkG;QAClG,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAmC,CAAC;QAErE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAmC,CAAC;YAExE,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,KAA4C,CAAC;gBAClE,IAAI,CAAC,KAAK;oBAAE,SAAS;gBAErB,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAmC,CAAC;gBAC1E,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAmC,CAAC;gBAE1E,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;oBAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;oBACpC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;oBACnC,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,CAAC,CAAC;oBAC3C,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS;wBAC7B,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;wBACpE,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;oBAE7B,oBAAoB;oBACpB,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAC3B,CAAC,CAAC,EAAE,EAAE,CAAE,CAAC,CAAC,KAAgB,KAAK,IAAI,CACpC,CAAC;oBACF,MAAM,WAAW,GAAG,OAAO;wBACzB,CAAC,CAAE,OAAO,CAAC,OAAmC,EAAE,IAAI;wBACpD,CAAC,CAAC,SAAS,CAAC;oBAEd,MAAM,aAAa,GAA0B,EAAE,CAAC;oBAEhD,QAAQ,OAAO,EAAE,CAAC;wBAChB,KAAK,MAAM,CAAC,CAAC,CAAC;4BACZ,MAAM,QAAQ,GAAG,GAAG,CAAC,IAA+B,CAAC;4BACrD,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;4BACzE,MAAM;wBACR,CAAC;wBACD,KAAK,OAAO,CAAC,CAAC,CAAC;4BACb,MAAM,OAAO,GAAG,GAAG,CAAC,KAAgC,CAAC;4BACrD,aAAa,CAAC,IAAI,CAAC;gCACjB,IAAI,EAAE,OAAO;gCACb,GAAG,EAAE,MAAM,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC;gCAC9B,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;gCAC/D,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS;6BACrE,CAAC,CAAC;4BACH,MAAM;wBACR,CAAC;wBACD,KAAK,OAAO,CAAC,CAAC,CAAC;4BACb,MAAM,OAAO,GAAG,GAAG,CAAC,KAAgC,CAAC;4BACrD,aAAa,CAAC,IAAI,CAAC;gCACjB,IAAI,EAAE,OAAO;gCACb,GAAG,EAAE,MAAM,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC;gCAC9B,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;gCAC/D,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS;6BACrE,CAAC,CAAC;4BACH,MAAM;wBACR,CAAC;wBACD,KAAK,OAAO,CAAC,CAAC,CAAC;4BACb,MAAM,SAAS,GAAG,GAAG,CAAC,KAAgC,CAAC;4BACvD,aAAa,CAAC,IAAI,CAAC;gCACjB,IAAI,EAAE,OAAO;gCACb,GAAG,EAAE,MAAM,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC;gCAChC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS;6BACzE,CAAC,CAAC;4BACH,MAAM;wBACR,CAAC;wBACD,KAAK,UAAU,CAAC,CAAC,CAAC;4BAChB,MAAM,OAAO,GAAG,GAAG,CAAC,QAAmC,CAAC;4BACxD,aAAa,CAAC,IAAI,CAAC;gCACjB,IAAI,EAAE,UAAU;gCAChB,GAAG,EAAE,MAAM,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC;gCAC9B,QAAQ,EAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,IAAI,UAAU,CAAC;gCACjD,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS;6BACrE,CAAC,CAAC;4BACH,MAAM;wBACR,CAAC;wBACD,KAAK,SAAS,CAAC,CAAC,CAAC;4BACf,MAAM,WAAW,GAAG,GAAG,CAAC,OAAkC,CAAC;4BAC3D,aAAa,CAAC,IAAI,CAAC;gCACjB,IAAI,EAAE,SAAS;gCACf,SAAS,EAAE,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC;6BACzC,CAAC,CAAC;4BACH,MAAM;wBACR,CAAC;wBACD,KAAK,UAAU,CAAC,CAAC,CAAC;4BAChB,MAAM,OAAO,GAAG,GAAG,CAAC,QAAmC,CAAC;4BACxD,aAAa,CAAC,IAAI,CAAC;gCACjB,IAAI,EAAE,UAAU;gCAChB,QAAQ,EAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,IAAI,CAAC,CAAC;gCACxC,SAAS,EAAE,MAAM,CAAC,OAAO,EAAE,SAAS,IAAI,CAAC,CAAC;gCAC1C,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;6BACvD,CAAC,CAAC;4BACH,MAAM;wBACR,CAAC;wBACD;4BACE,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,8BAA8B,OAAO,GAAG,EAAE,CAAC,CAAC;4BACrF,MAAM;oBACV,CAAC;oBAED,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBAC/B,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;oBACjD,CAAC;oBAED,qCAAqC;oBACrC,MAAM,IAAI,GAAG,aAAa;yBACvB,MAAM,CAAC,CAAC,CAAC,EAAuC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;yBACrE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;yBAClB,IAAI,CAAC,IAAI,CAAC,CAAC;oBAEd,MAAM,cAAc,GAAmB;wBACrC,SAAS,EAAE,KAAK;wBAChB,QAAQ,EAAE,UAAU;wBACpB,cAAc,EAAE,IAAI;wBACpB,gBAAgB,EAAE,QAAQ;wBAC1B,MAAM,EAAE;4BACN,EAAE,EAAE,IAAI;4BACR,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS;yBAC3D;wBACD,OAAO,EAAE,aAAa;wBACtB,IAAI;wBACJ,SAAS;wBACT,gBAAgB,EAAE,GAAG,CAAC,OAAO;4BAC3B,CAAC,CAAC,MAAM,CAAE,GAAG,CAAC,OAAmC,CAAC,EAAE,IAAI,EAAE,CAAC;4BAC3D,CAAC,CAAC,SAAS;wBACb,QAAQ,EAAE,GAAG;qBACd,CAAC;oBAEF,IAAI,CAAC,IAAI,CAAC;wBACR,IAAI,EAAE,SAAS;wBACf,QAAQ,EAAE,UAAU;wBACpB,cAAc,EAAE,IAAI;wBACpB,SAAS,EAAE,cAAc,CAAC,SAAS;wBACnC,IAAI,EAAE,cAAc;qBACrB,CAAC,CAAC;gBACL,CAAC;gBAED,4EAA4E;gBAC5E,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAmC,CAAC;gBAC1E,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;oBAC9B,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;wBAC7B,gDAAgD;oBAClD,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
|