@maincode-ai/channel-base 0.18.3

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.
@@ -0,0 +1,115 @@
1
+ /**
2
+ * BlockStreamer — progressive multi-message delivery for channels.
3
+ *
4
+ * Accumulates text chunks from the agent's streaming response and emits
5
+ * completed "blocks" (paragraphs / sections) as separate channel messages
6
+ * while the agent is still working. This gives users a natural conversation
7
+ * flow instead of waiting 30–120 seconds for a single wall of text.
8
+ *
9
+ * Emission triggers:
10
+ * 1. Buffer ≥ maxChars → force-split at best break point
11
+ * 2. Buffer ≥ minChars AND a paragraph boundary (\n\n) exists → emit up to boundary
12
+ * 3. Idle timer fires (no chunk for idleMs) AND buffer ≥ minChars → emit buffer
13
+ * 4. flush() called (response complete) → emit everything remaining
14
+ *
15
+ * All sends are serialized — the next block waits for the previous send to complete.
16
+ */
17
+ export class BlockStreamer {
18
+ buffer = '';
19
+ idleTimer = null;
20
+ sending = Promise.resolve();
21
+ opts;
22
+ /** Number of blocks emitted so far. */
23
+ blockCount = 0;
24
+ constructor(opts) {
25
+ this.opts = opts;
26
+ }
27
+ /** Feed a new text chunk from the agent stream. */
28
+ push(chunk) {
29
+ this.buffer += chunk;
30
+ this.clearIdleTimer();
31
+ this.checkEmit();
32
+ if (this.buffer.length > 0 && this.opts.idleMs > 0) {
33
+ this.idleTimer = setTimeout(() => this.onIdle(), this.opts.idleMs);
34
+ }
35
+ }
36
+ /** Flush all remaining buffered text. Awaits all pending sends. */
37
+ async flush() {
38
+ this.clearIdleTimer();
39
+ if (this.buffer.length > 0) {
40
+ this.emitBlock(this.buffer);
41
+ this.buffer = '';
42
+ }
43
+ await this.sending;
44
+ }
45
+ // ---------------------------------------------------------------------------
46
+ // Internal
47
+ // ---------------------------------------------------------------------------
48
+ checkEmit() {
49
+ // 1. Force-split if buffer exceeds maxChars
50
+ while (this.buffer.length >= this.opts.maxChars) {
51
+ const bp = this.findBreakPoint(this.buffer, this.opts.maxChars);
52
+ this.emitBlock(this.buffer.slice(0, bp));
53
+ this.buffer = this.buffer.slice(bp);
54
+ }
55
+ // 2. Emit at paragraph boundary if we have enough text
56
+ if (this.buffer.length >= this.opts.minChars) {
57
+ const bp = this.findBlockBoundary(this.buffer);
58
+ if (bp > 0) {
59
+ this.emitBlock(this.buffer.slice(0, bp));
60
+ this.buffer = this.buffer.slice(bp);
61
+ }
62
+ }
63
+ }
64
+ onIdle() {
65
+ this.idleTimer = null;
66
+ if (this.buffer.length >= this.opts.minChars) {
67
+ this.emitBlock(this.buffer);
68
+ this.buffer = '';
69
+ }
70
+ }
71
+ emitBlock(text) {
72
+ const trimmed = text.trim();
73
+ if (!trimmed)
74
+ return;
75
+ this.blockCount++;
76
+ this.sending = this.sending
77
+ .then(() => this.opts.send(trimmed))
78
+ .catch(() => { });
79
+ }
80
+ /**
81
+ * Find the last paragraph boundary (\n\n) in the buffer.
82
+ * Returns the position after the boundary, or -1 if no suitable boundary
83
+ * exists at or after minChars.
84
+ */
85
+ findBlockBoundary(text) {
86
+ const last = text.lastIndexOf('\n\n');
87
+ if (last < 0 || last < this.opts.minChars)
88
+ return -1;
89
+ return last + 2;
90
+ }
91
+ /**
92
+ * Find the best break point at or before maxPos.
93
+ * Prefers paragraph break > newline > space > maxPos.
94
+ */
95
+ findBreakPoint(text, maxPos) {
96
+ const sub = text.slice(0, maxPos);
97
+ const para = sub.lastIndexOf('\n\n');
98
+ if (para > 0)
99
+ return para + 2;
100
+ const nl = sub.lastIndexOf('\n');
101
+ if (nl > 0)
102
+ return nl + 1;
103
+ const sp = sub.lastIndexOf(' ');
104
+ if (sp > 0)
105
+ return sp + 1;
106
+ return maxPos;
107
+ }
108
+ clearIdleTimer() {
109
+ if (this.idleTimer !== null) {
110
+ clearTimeout(this.idleTimer);
111
+ this.idleTimer = null;
112
+ }
113
+ }
114
+ }
115
+ //# sourceMappingURL=BlockStreamer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BlockStreamer.js","sourceRoot":"","sources":["../src/BlockStreamer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ import type { ChannelConfig, Envelope } from './types.js';
2
+ import { GroupGate } from './GroupGate.js';
3
+ import { SenderGate } from './SenderGate.js';
4
+ import { SessionRouter } from './SessionRouter.js';
5
+ import type { AcpBridge, ToolCallEvent } from './AcpBridge.js';
6
+ export interface ChannelBaseOptions {
7
+ router?: SessionRouter;
8
+ proxy?: string;
9
+ }
10
+ /** Handler for a slash command. Return true if handled, false to forward to agent. */
11
+ type CommandHandler = (envelope: Envelope, args: string) => Promise<boolean>;
12
+ export declare abstract class ChannelBase {
13
+ protected config: ChannelConfig;
14
+ protected bridge: AcpBridge;
15
+ protected groupGate: GroupGate;
16
+ protected gate: SenderGate;
17
+ protected router: SessionRouter;
18
+ protected name: string;
19
+ /** Resolved proxy URL, available to subclasses for adapter-specific clients. */
20
+ protected proxy?: string;
21
+ private instructedSessions;
22
+ private commands;
23
+ /** Per-session promise chain to serialize prompt + send (followup mode). */
24
+ private sessionQueues;
25
+ /** Per-session active prompt tracking for dispatch modes. */
26
+ private activePrompts;
27
+ /** Per-session message buffer for collect mode. */
28
+ private collectBuffers;
29
+ constructor(name: string, config: ChannelConfig, bridge: AcpBridge, options?: ChannelBaseOptions);
30
+ abstract connect(): Promise<void>;
31
+ abstract sendMessage(chatId: string, text: string): Promise<void>;
32
+ abstract disconnect(): void;
33
+ /** Replace the bridge instance (used after crash recovery restart). */
34
+ setBridge(bridge: AcpBridge): void;
35
+ onToolCall(_chatId: string, _event: ToolCallEvent): void;
36
+ /**
37
+ * Called when a prompt actually begins processing (inside the session queue).
38
+ * Override to show a platform-specific working indicator (e.g., typing, reaction).
39
+ * Not called for buffered messages (collect mode) or gated/blocked messages.
40
+ */
41
+ protected onPromptStart(_chatId: string, _sessionId: string, _messageId?: string): void;
42
+ /**
43
+ * Called when a prompt finishes (response sent or cancelled).
44
+ * Override to hide the working indicator.
45
+ */
46
+ protected onPromptEnd(_chatId: string, _sessionId: string, _messageId?: string): void;
47
+ /**
48
+ * Called for each text chunk as the agent streams its response.
49
+ * Override to implement progressive display (e.g., updating an AI card in-place).
50
+ * Default: no-op (chunks are collected internally and delivered via onResponseComplete).
51
+ */
52
+ protected onResponseChunk(_chatId: string, _chunk: string, _sessionId: string): void;
53
+ /**
54
+ * Called when the agent's full response is ready.
55
+ * Override to customize delivery (e.g., finalize an AI card).
56
+ * Default: calls sendMessage() with the full response text.
57
+ */
58
+ protected onResponseComplete(chatId: string, fullText: string, _sessionId: string): Promise<void>;
59
+ /**
60
+ * Register a slash command handler. Subclasses can call this to add
61
+ * platform-specific commands (e.g., /start for Telegram).
62
+ * Overrides shared commands if the same name is registered.
63
+ */
64
+ protected registerCommand(name: string, handler: CommandHandler): void;
65
+ /** Register shared slash commands. Called from constructor. */
66
+ private registerSharedCommands;
67
+ /** Check if a message text matches a registered local command. */
68
+ protected isLocalCommand(text: string): boolean;
69
+ /**
70
+ * Parse a slash command from message text.
71
+ * Returns { command, args } or null if not a slash command.
72
+ */
73
+ private parseCommand;
74
+ handleInbound(envelope: Envelope): Promise<void>;
75
+ protected onPairingRequired(chatId: string, code: string | null): Promise<void>;
76
+ }
77
+ export {};
@@ -0,0 +1,358 @@
1
+ import { BlockStreamer } from './BlockStreamer.js';
2
+ import { GroupGate } from './GroupGate.js';
3
+ import { SenderGate } from './SenderGate.js';
4
+ import { PairingStore } from './PairingStore.js';
5
+ import { SessionRouter } from './SessionRouter.js';
6
+ export class ChannelBase {
7
+ config;
8
+ bridge;
9
+ groupGate;
10
+ gate;
11
+ router;
12
+ name;
13
+ /** Resolved proxy URL, available to subclasses for adapter-specific clients. */
14
+ proxy;
15
+ instructedSessions = new Set();
16
+ commands = new Map();
17
+ /** Per-session promise chain to serialize prompt + send (followup mode). */
18
+ sessionQueues = new Map();
19
+ /** Per-session active prompt tracking for dispatch modes. */
20
+ activePrompts = new Map();
21
+ /** Per-session message buffer for collect mode. */
22
+ collectBuffers = new Map();
23
+ constructor(name, config, bridge, options) {
24
+ this.name = name;
25
+ this.config = config;
26
+ this.bridge = bridge;
27
+ this.proxy = options?.proxy;
28
+ this.groupGate = new GroupGate(config.groupPolicy, config.groups);
29
+ const pairingStore = config.senderPolicy === 'pairing' ? new PairingStore(name) : undefined;
30
+ this.gate = new SenderGate(config.senderPolicy, config.allowedUsers, pairingStore);
31
+ this.router =
32
+ options?.router ||
33
+ new SessionRouter(bridge, config.cwd, config.sessionScope);
34
+ this.registerSharedCommands();
35
+ // When running standalone (no gateway), register toolCall listener directly.
36
+ // In gateway mode, the ChannelManager dispatches events instead.
37
+ if (!options?.router) {
38
+ bridge.on('toolCall', (event) => {
39
+ const target = this.router.getTarget(event.sessionId);
40
+ if (target) {
41
+ this.onToolCall(target.chatId, event);
42
+ }
43
+ });
44
+ }
45
+ }
46
+ /** Replace the bridge instance (used after crash recovery restart). */
47
+ setBridge(bridge) {
48
+ this.bridge = bridge;
49
+ }
50
+ onToolCall(_chatId, _event) { }
51
+ /**
52
+ * Called when a prompt actually begins processing (inside the session queue).
53
+ * Override to show a platform-specific working indicator (e.g., typing, reaction).
54
+ * Not called for buffered messages (collect mode) or gated/blocked messages.
55
+ */
56
+ onPromptStart(_chatId, _sessionId, _messageId) { }
57
+ /**
58
+ * Called when a prompt finishes (response sent or cancelled).
59
+ * Override to hide the working indicator.
60
+ */
61
+ onPromptEnd(_chatId, _sessionId, _messageId) { }
62
+ /**
63
+ * Called for each text chunk as the agent streams its response.
64
+ * Override to implement progressive display (e.g., updating an AI card in-place).
65
+ * Default: no-op (chunks are collected internally and delivered via onResponseComplete).
66
+ */
67
+ onResponseChunk(_chatId, _chunk, _sessionId) { }
68
+ /**
69
+ * Called when the agent's full response is ready.
70
+ * Override to customize delivery (e.g., finalize an AI card).
71
+ * Default: calls sendMessage() with the full response text.
72
+ */
73
+ async onResponseComplete(chatId, fullText, _sessionId) {
74
+ await this.sendMessage(chatId, fullText);
75
+ }
76
+ /**
77
+ * Register a slash command handler. Subclasses can call this to add
78
+ * platform-specific commands (e.g., /start for Telegram).
79
+ * Overrides shared commands if the same name is registered.
80
+ */
81
+ registerCommand(name, handler) {
82
+ this.commands.set(name.toLowerCase(), handler);
83
+ }
84
+ /** Register shared slash commands. Called from constructor. */
85
+ registerSharedCommands() {
86
+ const clearHandler = async (envelope) => {
87
+ const removedIds = this.router.removeSession(this.name, envelope.senderId, envelope.chatId);
88
+ if (removedIds.length > 0) {
89
+ for (const id of removedIds) {
90
+ this.instructedSessions.delete(id);
91
+ }
92
+ await this.sendMessage(envelope.chatId, 'Session cleared. Your next message will start a fresh conversation.');
93
+ }
94
+ else {
95
+ await this.sendMessage(envelope.chatId, 'No active session to clear.');
96
+ }
97
+ return true;
98
+ };
99
+ this.registerCommand('clear', clearHandler);
100
+ this.registerCommand('reset', clearHandler);
101
+ this.registerCommand('new', clearHandler);
102
+ this.registerCommand('help', async (envelope) => {
103
+ const lines = [
104
+ 'Commands:',
105
+ '/help — Show this help',
106
+ '/clear — Clear your session (aliases: /reset, /new)',
107
+ '/status — Show session info',
108
+ ];
109
+ // Platform-specific commands (registered by adapters, not shared ones)
110
+ const sharedCmds = new Set(['help', 'clear', 'reset', 'new', 'status']);
111
+ const platformCmds = [...this.commands.keys()].filter((c) => !sharedCmds.has(c));
112
+ if (platformCmds.length > 0) {
113
+ for (const cmd of platformCmds) {
114
+ lines.push(`/${cmd}`);
115
+ }
116
+ }
117
+ const agentCommands = this.bridge.availableCommands;
118
+ if (agentCommands.length > 0) {
119
+ lines.push('', 'Agent commands (forwarded to Matilda Code):');
120
+ for (const cmd of agentCommands) {
121
+ lines.push(`/${cmd.name} — ${cmd.description}`);
122
+ }
123
+ }
124
+ lines.push('', 'Send any text to chat with the agent.');
125
+ await this.sendMessage(envelope.chatId, lines.join('\n'));
126
+ return true;
127
+ });
128
+ this.registerCommand('status', async (envelope) => {
129
+ const hasSession = this.router.hasSession(this.name, envelope.senderId, envelope.chatId);
130
+ const policy = this.config.senderPolicy;
131
+ const lines = [
132
+ `Session: ${hasSession ? 'active' : 'none'}`,
133
+ `Access: ${policy}`,
134
+ `Channel: ${this.name}`,
135
+ ];
136
+ await this.sendMessage(envelope.chatId, lines.join('\n'));
137
+ return true;
138
+ });
139
+ }
140
+ /** Check if a message text matches a registered local command. */
141
+ isLocalCommand(text) {
142
+ const parsed = this.parseCommand(text);
143
+ return parsed !== null && this.commands.has(parsed.command);
144
+ }
145
+ /**
146
+ * Parse a slash command from message text.
147
+ * Returns { command, args } or null if not a slash command.
148
+ */
149
+ parseCommand(text) {
150
+ if (!text.startsWith('/'))
151
+ return null;
152
+ // Handle /command@botname format (Telegram groups)
153
+ const match = text.match(/^\/([a-zA-Z0-9_]+)(?:@\S+)?\s*(.*)/s);
154
+ if (!match)
155
+ return null;
156
+ return { command: match[1].toLowerCase(), args: match[2].trim() };
157
+ }
158
+ async handleInbound(envelope) {
159
+ // 1. Group gate: policy + allowlist + mention gating
160
+ const groupResult = this.groupGate.check(envelope);
161
+ if (!groupResult.allowed) {
162
+ return; // silently drop — no pairing, no reply
163
+ }
164
+ // 2. Sender gate: allowlist / pairing / open
165
+ const result = this.gate.check(envelope.senderId, envelope.senderName);
166
+ if (!result.allowed) {
167
+ if (result.pairingCode !== undefined) {
168
+ await this.onPairingRequired(envelope.chatId, result.pairingCode);
169
+ }
170
+ return;
171
+ }
172
+ // 3. Slash command handling — before session/agent routing
173
+ const parsed = this.parseCommand(envelope.text);
174
+ if (parsed) {
175
+ const handler = this.commands.get(parsed.command);
176
+ if (handler) {
177
+ const handled = await handler(envelope, parsed.args);
178
+ if (handled)
179
+ return;
180
+ }
181
+ // Unrecognized commands fall through to the agent
182
+ }
183
+ const sessionId = await this.router.resolve(this.name, envelope.senderId, envelope.chatId, envelope.threadId, this.config.cwd);
184
+ // 3.5. Bang (!) shell command — direct execution, no LLM
185
+ if (envelope.text.startsWith('!')) {
186
+ const cmd = envelope.text.slice(1).trim();
187
+ const bridgeShellCommand = this.bridge['shellCommand'];
188
+ if (cmd && typeof bridgeShellCommand === 'function') {
189
+ try {
190
+ const result = (await bridgeShellCommand(sessionId, cmd));
191
+ const longestRun = Math.max(0, ...Array.from((result.output || '').matchAll(/`+/g), (m) => m[0].length));
192
+ const fence = '`'.repeat(Math.max(3, longestRun + 1));
193
+ const output = result.output
194
+ ? `${fence}\n${result.output}\n${fence}`
195
+ : '(no output)';
196
+ const exitLine = result.exitCode !== null && result.exitCode !== 0
197
+ ? `\nExit code: ${result.exitCode}`
198
+ : '';
199
+ await this.sendMessage(envelope.chatId, `$ ${cmd}\n${output}${exitLine}`);
200
+ }
201
+ catch (error) {
202
+ await this.sendMessage(envelope.chatId, `Shell command failed: ${error instanceof Error ? error.message : String(error)}`);
203
+ }
204
+ return;
205
+ }
206
+ }
207
+ // Prepend referenced (quoted) message text for reply context
208
+ let promptText = envelope.text;
209
+ if (envelope.referencedText) {
210
+ promptText = `[Replying to: "${envelope.referencedText}"]\n\n${promptText}`;
211
+ }
212
+ // Resolve attachments: extract image for bridge, append file paths to text
213
+ let imageBase64 = envelope.imageBase64;
214
+ let imageMimeType = envelope.imageMimeType;
215
+ if (envelope.attachments?.length) {
216
+ const filePaths = [];
217
+ for (const att of envelope.attachments) {
218
+ if (att.type === 'image' && att.data && !imageBase64) {
219
+ imageBase64 = att.data;
220
+ imageMimeType = att.mimeType;
221
+ }
222
+ else if (att.filePath) {
223
+ const label = att.type === 'file' ? 'file' : att.type;
224
+ const name = att.fileName ? ` "${att.fileName}"` : '';
225
+ filePaths.push(`User sent a ${label}${name}. It has been saved to: ${att.filePath}`);
226
+ }
227
+ }
228
+ if (filePaths.length > 0) {
229
+ promptText = promptText + '\n\n' + filePaths.join('\n');
230
+ }
231
+ }
232
+ // Prepend channel instructions on first message of a session
233
+ if (this.config.instructions && !this.instructedSessions.has(sessionId)) {
234
+ promptText = `${this.config.instructions}\n\n${promptText}`;
235
+ this.instructedSessions.add(sessionId);
236
+ }
237
+ // Resolve dispatch mode: per-group override → channel config → default
238
+ const groupCfg = envelope.isGroup
239
+ ? this.config.groups[envelope.chatId] || this.config.groups['*']
240
+ : undefined;
241
+ const mode = groupCfg?.dispatchMode || this.config.dispatchMode || 'steer';
242
+ const active = this.activePrompts.get(sessionId);
243
+ if (active) {
244
+ // A prompt is already running for this session
245
+ switch (mode) {
246
+ case 'collect': {
247
+ // Buffer the message; it will be coalesced when the active prompt finishes
248
+ let buffer = this.collectBuffers.get(sessionId);
249
+ if (!buffer) {
250
+ buffer = [];
251
+ this.collectBuffers.set(sessionId, buffer);
252
+ }
253
+ buffer.push({ text: promptText, envelope });
254
+ return;
255
+ }
256
+ case 'steer': {
257
+ // Cancel the running prompt, then fall through to send a new one
258
+ active.cancelled = true;
259
+ await this.bridge.cancelSession(sessionId).catch(() => { });
260
+ // Wait for the active prompt to finish winding down
261
+ await active.done;
262
+ // Prepend a cancellation note so the agent understands context
263
+ promptText = `[The user sent a new message while you were working. Their previous request has been cancelled.]\n\n${promptText}`;
264
+ break;
265
+ }
266
+ case 'followup': {
267
+ // Chain onto the session queue (existing sequential behavior)
268
+ break;
269
+ }
270
+ default: {
271
+ // Exhaustive check — should never happen
272
+ const _exhaustive = mode;
273
+ throw new Error(`Unknown dispatch mode: ${_exhaustive}`);
274
+ }
275
+ }
276
+ }
277
+ // Run the prompt (with followup-mode serialization for safety)
278
+ const prev = this.sessionQueues.get(sessionId) ?? Promise.resolve();
279
+ const useBlockStreaming = this.config.blockStreaming === 'on';
280
+ const current = prev.then(async () => {
281
+ // Register this prompt as active
282
+ let doneResolve = () => { };
283
+ const done = new Promise((r) => {
284
+ doneResolve = r;
285
+ });
286
+ const promptState = { cancelled: false, done, resolve: doneResolve };
287
+ this.activePrompts.set(sessionId, promptState);
288
+ this.onPromptStart(envelope.chatId, sessionId, envelope.messageId);
289
+ const streamer = useBlockStreaming
290
+ ? new BlockStreamer({
291
+ minChars: this.config.blockStreamingChunk?.minChars ?? 400,
292
+ maxChars: this.config.blockStreamingChunk?.maxChars ?? 1000,
293
+ idleMs: this.config.blockStreamingCoalesce?.idleMs ?? 1500,
294
+ send: (text) => this.sendMessage(envelope.chatId, text),
295
+ })
296
+ : null;
297
+ const onChunk = (sid, chunk) => {
298
+ if (sid === sessionId) {
299
+ this.onResponseChunk(envelope.chatId, chunk, sessionId);
300
+ streamer?.push(chunk);
301
+ }
302
+ };
303
+ this.bridge.on('textChunk', onChunk);
304
+ try {
305
+ const response = await this.bridge.prompt(sessionId, promptText, {
306
+ imageBase64,
307
+ imageMimeType,
308
+ });
309
+ // If cancelled (steer mode), skip sending the response
310
+ if (!promptState.cancelled && response) {
311
+ if (streamer) {
312
+ await streamer.flush();
313
+ }
314
+ else {
315
+ await this.onResponseComplete(envelope.chatId, response, sessionId);
316
+ }
317
+ }
318
+ }
319
+ finally {
320
+ this.bridge.off('textChunk', onChunk);
321
+ this.onPromptEnd(envelope.chatId, sessionId, envelope.messageId);
322
+ this.activePrompts.delete(sessionId);
323
+ // Signal any steer waiter that we're done
324
+ promptState.resolve();
325
+ // Drain collect buffer if any messages accumulated
326
+ const buffer = this.collectBuffers.get(sessionId);
327
+ if (buffer && buffer.length > 0) {
328
+ this.collectBuffers.delete(sessionId);
329
+ const coalesced = buffer.map((b) => b.text).join('\n\n');
330
+ const lastEnvelope = buffer[buffer.length - 1].envelope;
331
+ // Re-enter handleInbound with the coalesced message
332
+ const syntheticEnvelope = {
333
+ ...lastEnvelope,
334
+ text: coalesced,
335
+ // Clear attachments/references — already resolved in original text
336
+ referencedText: undefined,
337
+ attachments: undefined,
338
+ imageBase64: undefined,
339
+ imageMimeType: undefined,
340
+ };
341
+ // Queue the coalesced prompt (don't await to avoid deadlock on the queue)
342
+ this.handleInbound(syntheticEnvelope).catch(() => { });
343
+ }
344
+ }
345
+ });
346
+ this.sessionQueues.set(sessionId, current.catch(() => { }));
347
+ await current;
348
+ }
349
+ async onPairingRequired(chatId, code) {
350
+ if (code) {
351
+ await this.sendMessage(chatId, `Your pairing code is: ${code}\n\nAsk the bot operator to approve you with:\n matilda channel pairing approve ${this.name} ${code}`);
352
+ }
353
+ else {
354
+ await this.sendMessage(chatId, 'Too many pending pairing requests. Please try again later.');
355
+ }
356
+ }
357
+ }
358
+ //# sourceMappingURL=ChannelBase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChannelBase.js","sourceRoot":"","sources":["../src/ChannelBase.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAWnD,MAAM,OAAgB,WAAW;IACrB,MAAM,CAAgB;IACtB,MAAM,CAAY;IAClB,SAAS,CAAY;IACrB,IAAI,CAAa;IACjB,MAAM,CAAgB;IACtB,IAAI,CAAS;IACvB,gFAAgF;IACtE,KAAK,CAAU;IACjB,kBAAkB,GAAgB,IAAI,GAAG,EAAE,CAAC;IAC5C,QAAQ,GAAgC,IAAI,GAAG,EAAE,CAAC;IAC1D,4EAA4E;IACpE,aAAa,GAA+B,IAAI,GAAG,EAAE,CAAC;IAE9D,6DAA6D;IACrD,aAAa,GAGjB,IAAI,GAAG,EAAE,CAAC;IACd,mDAAmD;IAC3C,cAAc,GAGlB,IAAI,GAAG,EAAE,CAAC;IAEd,YACE,IAAY,EACZ,MAAqB,EACrB,MAAiB,EACjB,OAA4B;QAE5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,CAAC;QAE5B,IAAI,CAAC,SAAS,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAElE,MAAM,YAAY,GAChB,MAAM,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACzE,IAAI,CAAC,IAAI,GAAG,IAAI,UAAU,CACxB,MAAM,CAAC,YAAY,EACnB,MAAM,CAAC,YAAY,EACnB,YAAY,CACb,CAAC;QACF,IAAI,CAAC,MAAM;YACT,OAAO,EAAE,MAAM;gBACf,IAAI,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;QAE7D,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAE9B,6EAA6E;QAC7E,iEAAiE;QACjE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;YACrB,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,KAAoB,EAAE,EAAE;gBAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;gBACtD,IAAI,MAAM,EAAE,CAAC;oBACX,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;gBACxC,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAMD,uEAAuE;IACvE,SAAS,CAAC,MAAiB;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,UAAU,CAAC,OAAe,EAAE,MAAqB,IAAS,CAAC;IAE3D;;;;OAIG;IACO,aAAa,CACrB,OAAe,EACf,UAAkB,EAClB,UAAmB,IACZ,CAAC;IAEV;;;OAGG;IACO,WAAW,CACnB,OAAe,EACf,UAAkB,EAClB,UAAmB,IACZ,CAAC;IAEV;;;;OAIG;IACO,eAAe,CACvB,OAAe,EACf,MAAc,EACd,UAAkB,IACX,CAAC;IAEV;;;;OAIG;IACO,KAAK,CAAC,kBAAkB,CAChC,MAAc,EACd,QAAgB,EAChB,UAAkB;QAElB,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAED;;;;OAIG;IACO,eAAe,CAAC,IAAY,EAAE,OAAuB;QAC7D,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IAED,+DAA+D;IACvD,sBAAsB;QAC5B,MAAM,YAAY,GAAmB,KAAK,EAAE,QAAQ,EAAE,EAAE;YACtD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,CAC1C,IAAI,CAAC,IAAI,EACT,QAAQ,CAAC,QAAQ,EACjB,QAAQ,CAAC,MAAM,CAChB,CAAC;YACF,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;oBAC5B,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACrC,CAAC;gBACD,MAAM,IAAI,CAAC,WAAW,CACpB,QAAQ,CAAC,MAAM,EACf,qEAAqE,CACtE,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC;YACzE,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QAC5C,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QAC5C,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;QAE1C,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;YAC9C,MAAM,KAAK,GAAG;gBACZ,WAAW;gBACX,wBAAwB;gBACxB,qDAAqD;gBACrD,6BAA6B;aAC9B,CAAC;YAEF,uEAAuE;YACvE,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;YACxE,MAAM,YAAY,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CACnD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAC1B,CAAC;YACF,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC5B,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;oBAC/B,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;gBACxB,CAAC;YACH,CAAC;YAED,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC;YACpD,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,6CAA6C,CAAC,CAAC;gBAC9D,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;oBAChC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;gBAClD,CAAC;YACH,CAAC;YAED,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,uCAAuC,CAAC,CAAC;YACxD,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAC1D,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;YAChD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CACvC,IAAI,CAAC,IAAI,EACT,QAAQ,CAAC,QAAQ,EACjB,QAAQ,CAAC,MAAM,CAChB,CAAC;YACF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;YACxC,MAAM,KAAK,GAAG;gBACZ,YAAY,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE;gBAC5C,WAAW,MAAM,EAAE;gBACnB,YAAY,IAAI,CAAC,IAAI,EAAE;aACxB,CAAC;YACF,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAC1D,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;IAED,kEAAkE;IACxD,cAAc,CAAC,IAAY;QACnC,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QACvC,OAAO,MAAM,KAAK,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9D,CAAC;IAED;;;OAGG;IACK,YAAY,CAAC,IAAY;QAC/B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACvC,mDAAmD;QACnD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QAChE,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,QAAkB;QACpC,qDAAqD;QACrD,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACnD,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YACzB,OAAO,CAAC,uCAAuC;QACjD,CAAC;QAED,6CAA6C;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;QACvE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;gBACrC,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;YACpE,CAAC;YACD,OAAO;QACT,CAAC;QAED,2DAA2D;QAC3D,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAClD,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;gBACrD,IAAI,OAAO;oBAAE,OAAO;YACtB,CAAC;YACD,kDAAkD;QACpD,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CACzC,IAAI,CAAC,IAAI,EACT,QAAQ,CAAC,QAAQ,EACjB,QAAQ,CAAC,MAAM,EACf,QAAQ,CAAC,QAAQ,EACjB,IAAI,CAAC,MAAM,CAAC,GAAG,CAChB,CAAC;QAEF,yDAAyD;QACzD,IAAI,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAClC,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC1C,MAAM,kBAAkB,GACtB,IAAI,CAAC,MACN,CAAC,cAAc,CAAC,CAAC;YAClB,IAAI,GAAG,IAAI,OAAO,kBAAkB,KAAK,UAAU,EAAE,CAAC;gBACpD,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,CAAC,MAAM,kBAAkB,CAAC,SAAS,EAAE,GAAG,CAAC,CAIvD,CAAC;oBACF,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CACzB,CAAC,EACD,GAAG,KAAK,CAAC,IAAI,CACX,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EACrC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CACnB,CACF,CAAC;oBACF,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC;oBACtD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM;wBAC1B,CAAC,CAAC,GAAG,KAAK,KAAK,MAAM,CAAC,MAAM,KAAK,KAAK,EAAE;wBACxC,CAAC,CAAC,aAAa,CAAC;oBAClB,MAAM,QAAQ,GACZ,MAAM,CAAC,QAAQ,KAAK,IAAI,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC;wBAC/C,CAAC,CAAC,gBAAgB,MAAM,CAAC,QAAQ,EAAE;wBACnC,CAAC,CAAC,EAAE,CAAC;oBACT,MAAM,IAAI,CAAC,WAAW,CACpB,QAAQ,CAAC,MAAM,EACf,KAAK,GAAG,KAAK,MAAM,GAAG,QAAQ,EAAE,CACjC,CAAC;gBACJ,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,IAAI,CAAC,WAAW,CACpB,QAAQ,CAAC,MAAM,EACf,yBAAyB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAClF,CAAC;gBACJ,CAAC;gBACD,OAAO;YACT,CAAC;QACH,CAAC;QAED,6DAA6D;QAC7D,IAAI,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC;QAC/B,IAAI,QAAQ,CAAC,cAAc,EAAE,CAAC;YAC5B,UAAU,GAAG,kBAAkB,QAAQ,CAAC,cAAc,SAAS,UAAU,EAAE,CAAC;QAC9E,CAAC;QAED,2EAA2E;QAC3E,IAAI,WAAW,GAAG,QAAQ,CAAC,WAAW,CAAC;QACvC,IAAI,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC;QAC3C,IAAI,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC;YACjC,MAAM,SAAS,GAAa,EAAE,CAAC;YAC/B,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC;gBACvC,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;oBACrD,WAAW,GAAG,GAAG,CAAC,IAAI,CAAC;oBACvB,aAAa,GAAG,GAAG,CAAC,QAAQ,CAAC;gBAC/B,CAAC;qBAAM,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;oBACxB,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;oBACtD,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;oBACtD,SAAS,CAAC,IAAI,CACZ,eAAe,KAAK,GAAG,IAAI,2BAA2B,GAAG,CAAC,QAAQ,EAAE,CACrE,CAAC;gBACJ,CAAC;YACH,CAAC;YACD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzB,UAAU,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;QAED,6DAA6D;QAC7D,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YACxE,UAAU,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,OAAO,UAAU,EAAE,CAAC;YAC5D,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACzC,CAAC;QAED,uEAAuE;QACvE,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO;YAC/B,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC;YAChE,CAAC,CAAC,SAAS,CAAC;QACd,MAAM,IAAI,GACR,QAAQ,EAAE,YAAY,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,OAAO,CAAC;QAEhE,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAEjD,IAAI,MAAM,EAAE,CAAC;YACX,+CAA+C;YAC/C,QAAQ,IAAI,EAAE,CAAC;gBACb,KAAK,SAAS,CAAC,CAAC,CAAC;oBACf,2EAA2E;oBAC3E,IAAI,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;oBAChD,IAAI,CAAC,MAAM,EAAE,CAAC;wBACZ,MAAM,GAAG,EAAE,CAAC;wBACZ,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;oBAC7C,CAAC;oBACD,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC;oBAC5C,OAAO;gBACT,CAAC;gBACD,KAAK,OAAO,CAAC,CAAC,CAAC;oBACb,iEAAiE;oBACjE,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;oBACxB,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;oBAC3D,oDAAoD;oBACpD,MAAM,MAAM,CAAC,IAAI,CAAC;oBAClB,+DAA+D;oBAC/D,UAAU,GAAG,uGAAuG,UAAU,EAAE,CAAC;oBACjI,MAAM;gBACR,CAAC;gBACD,KAAK,UAAU,CAAC,CAAC,CAAC;oBAChB,8DAA8D;oBAC9D,MAAM;gBACR,CAAC;gBACD,OAAO,CAAC,CAAC,CAAC;oBACR,yCAAyC;oBACzC,MAAM,WAAW,GAAU,IAAI,CAAC;oBAChC,MAAM,IAAI,KAAK,CAAC,0BAA0B,WAAW,EAAE,CAAC,CAAC;gBAC3D,CAAC;YACH,CAAC;QACH,CAAC;QAED,+DAA+D;QAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpE,MAAM,iBAAiB,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,KAAK,IAAI,CAAC;QAC9D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;YACnC,iCAAiC;YACjC,IAAI,WAAW,GAAe,GAAG,EAAE,GAAE,CAAC,CAAC;YACvC,MAAM,IAAI,GAAG,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE;gBACnC,WAAW,GAAG,CAAC,CAAC;YAClB,CAAC,CAAC,CAAC;YACH,MAAM,WAAW,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;YACrE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;YAE/C,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;YAEnE,MAAM,QAAQ,GAAG,iBAAiB;gBAChC,CAAC,CAAC,IAAI,aAAa,CAAC;oBAChB,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,mBAAmB,EAAE,QAAQ,IAAI,GAAG;oBAC1D,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,mBAAmB,EAAE,QAAQ,IAAI,IAAI;oBAC3D,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,sBAAsB,EAAE,MAAM,IAAI,IAAI;oBAC1D,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;iBACxD,CAAC;gBACJ,CAAC,CAAC,IAAI,CAAC;YAET,MAAM,OAAO,GAAG,CAAC,GAAW,EAAE,KAAa,EAAE,EAAE;gBAC7C,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;oBACtB,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;oBACxD,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;gBACxB,CAAC;YACH,CAAC,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YAErC,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE;oBAC/D,WAAW;oBACX,aAAa;iBACd,CAAC,CAAC;gBAEH,uDAAuD;gBACvD,IAAI,CAAC,WAAW,CAAC,SAAS,IAAI,QAAQ,EAAE,CAAC;oBACvC,IAAI,QAAQ,EAAE,CAAC;wBACb,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC;oBACzB,CAAC;yBAAM,CAAC;wBACN,MAAM,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;oBACtE,CAAC;gBACH,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;gBACtC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;gBACjE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBACrC,0CAA0C;gBAC1C,WAAW,CAAC,OAAO,EAAE,CAAC;gBAEtB,mDAAmD;gBACnD,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAClD,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAChC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;oBACtC,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBACzD,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,QAAQ,CAAC;oBACzD,oDAAoD;oBACpD,MAAM,iBAAiB,GAAa;wBAClC,GAAG,YAAY;wBACf,IAAI,EAAE,SAAS;wBACf,mEAAmE;wBACnE,cAAc,EAAE,SAAS;wBACzB,WAAW,EAAE,SAAS;wBACtB,WAAW,EAAE,SAAS;wBACtB,aAAa,EAAE,SAAS;qBACzB,CAAC;oBACF,0EAA0E;oBAC1E,IAAI,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBACxD,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,aAAa,CAAC,GAAG,CACpB,SAAS,EACT,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CACxB,CAAC;QACF,MAAM,OAAO,CAAC;IAChB,CAAC;IAES,KAAK,CAAC,iBAAiB,CAC/B,MAAc,EACd,IAAmB;QAEnB,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,IAAI,CAAC,WAAW,CACpB,MAAM,EACN,yBAAyB,IAAI,oFAAoF,IAAI,CAAC,IAAI,IAAI,IAAI,EAAE,CACrI,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,CAAC,WAAW,CACpB,MAAM,EACN,4DAA4D,CAC7D,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}