dsh-remote-control 1.0.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/LICENSE +21 -0
- package/cordis.patch.yml +21 -0
- package/dist/bundle/index.js +33956 -0
- package/dist/src/core/clock.d.ts +45 -0
- package/dist/src/core/clock.js +83 -0
- package/dist/src/core/clock.js.map +1 -0
- package/dist/src/core/keys.d.ts +98 -0
- package/dist/src/core/keys.js +176 -0
- package/dist/src/core/keys.js.map +1 -0
- package/dist/src/core/pairing-window.d.ts +95 -0
- package/dist/src/core/pairing-window.js +92 -0
- package/dist/src/core/pairing-window.js.map +1 -0
- package/dist/src/core/runtime.d.ts +104 -0
- package/dist/src/core/runtime.js +491 -0
- package/dist/src/core/runtime.js.map +1 -0
- package/dist/src/core/sleep-policy.d.ts +81 -0
- package/dist/src/core/sleep-policy.js +134 -0
- package/dist/src/core/sleep-policy.js.map +1 -0
- package/dist/src/core/window.d.ts +88 -0
- package/dist/src/core/window.js +185 -0
- package/dist/src/core/window.js.map +1 -0
- package/dist/src/index.d.ts +70 -0
- package/dist/src/index.js +882 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/platform/carrier-services.d.ts +96 -0
- package/dist/src/platform/carrier-services.js +982 -0
- package/dist/src/platform/carrier-services.js.map +1 -0
- package/dist/src/platform/guard.d.ts +60 -0
- package/dist/src/platform/guard.js +124 -0
- package/dist/src/platform/guard.js.map +1 -0
- package/dist/src/platform/mock-kernel.d.ts +95 -0
- package/dist/src/platform/mock-kernel.js +180 -0
- package/dist/src/platform/mock-kernel.js.map +1 -0
- package/dist/src/platform/qr.d.ts +28 -0
- package/dist/src/platform/qr.js +80 -0
- package/dist/src/platform/qr.js.map +1 -0
- package/dist/src/platform/sleep-posix.d.ts +17 -0
- package/dist/src/platform/sleep-posix.js +91 -0
- package/dist/src/platform/sleep-posix.js.map +1 -0
- package/dist/src/ports/index.d.ts +246 -0
- package/dist/src/ports/index.js +2 -0
- package/dist/src/ports/index.js.map +1 -0
- package/dist/src/shell/config.d.ts +56 -0
- package/dist/src/shell/config.js +212 -0
- package/dist/src/shell/config.js.map +1 -0
- package/dist/src/shell/pairing-text.d.ts +38 -0
- package/dist/src/shell/pairing-text.js +22 -0
- package/dist/src/shell/pairing-text.js.map +1 -0
- package/dist/src/shell/status.d.ts +39 -0
- package/dist/src/shell/status.js +119 -0
- package/dist/src/shell/status.js.map +1 -0
- package/dist/src/transport/relay.d.ts +107 -0
- package/dist/src/transport/relay.js +359 -0
- package/dist/src/transport/relay.js.map +1 -0
- package/dist/tests/carrier-events.test.d.ts +1 -0
- package/dist/tests/carrier-events.test.js +88 -0
- package/dist/tests/carrier-events.test.js.map +1 -0
- package/dist/tests/carrier-services.test.d.ts +1 -0
- package/dist/tests/carrier-services.test.js +562 -0
- package/dist/tests/carrier-services.test.js.map +1 -0
- package/dist/tests/carrier-vocabulary.test.d.ts +1 -0
- package/dist/tests/carrier-vocabulary.test.js +149 -0
- package/dist/tests/carrier-vocabulary.test.js.map +1 -0
- package/dist/tests/clock-probe-timers.test.d.ts +1 -0
- package/dist/tests/clock-probe-timers.test.js +73 -0
- package/dist/tests/clock-probe-timers.test.js.map +1 -0
- package/dist/tests/command-result.test.d.ts +1 -0
- package/dist/tests/command-result.test.js +185 -0
- package/dist/tests/command-result.test.js.map +1 -0
- package/dist/tests/config.test.d.ts +1 -0
- package/dist/tests/config.test.js +223 -0
- package/dist/tests/config.test.js.map +1 -0
- package/dist/tests/guard.test.d.ts +1 -0
- package/dist/tests/guard.test.js +175 -0
- package/dist/tests/guard.test.js.map +1 -0
- package/dist/tests/ids-and-keys.test.d.ts +1 -0
- package/dist/tests/ids-and-keys.test.js +211 -0
- package/dist/tests/ids-and-keys.test.js.map +1 -0
- package/dist/tests/pairing-text.test.d.ts +1 -0
- package/dist/tests/pairing-text.test.js +62 -0
- package/dist/tests/pairing-text.test.js.map +1 -0
- package/dist/tests/pairing-window.test.d.ts +1 -0
- package/dist/tests/pairing-window.test.js +165 -0
- package/dist/tests/pairing-window.test.js.map +1 -0
- package/dist/tests/relay-client.test.d.ts +1 -0
- package/dist/tests/relay-client.test.js +557 -0
- package/dist/tests/relay-client.test.js.map +1 -0
- package/dist/tests/runtime.test.d.ts +1 -0
- package/dist/tests/runtime.test.js +963 -0
- package/dist/tests/runtime.test.js.map +1 -0
- package/dist/tests/sleep.test.d.ts +1 -0
- package/dist/tests/sleep.test.js +264 -0
- package/dist/tests/sleep.test.js.map +1 -0
- package/dist/tests/status.test.d.ts +1 -0
- package/dist/tests/status.test.js +238 -0
- package/dist/tests/status.test.js.map +1 -0
- package/dist/tests/window.test.d.ts +1 -0
- package/dist/tests/window.test.js +210 -0
- package/dist/tests/window.test.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { CmdPayload, EvPayload, SessionSummary } from 'dsh-remote-wire';
|
|
2
|
+
import type { KernelPort } from '../ports/index.js';
|
|
3
|
+
import { type WindowOptions } from './window.js';
|
|
4
|
+
import type { KeepAwake } from './sleep-policy.js';
|
|
5
|
+
import type { Clock } from '../ports/index.js';
|
|
6
|
+
/** 出站通道:core 只负责"该发什么",加密与投递由 shell 提供。 */
|
|
7
|
+
export interface RuntimeTransport {
|
|
8
|
+
/** 发给某一条配对会话(回执用)。返回 false 表示没有活的对端。 */
|
|
9
|
+
reply(conversationId: string, payload: EvPayload): boolean;
|
|
10
|
+
/** 发给所有已配对的会话(会话列表、防休眠状态这类广播)。返回**收到这条广播的会话数**,0 表示没发出去。 */
|
|
11
|
+
broadcast(payload: EvPayload): number;
|
|
12
|
+
/** 此刻是否有能收这条会话消息的对端(审批要不要认领的判据)。 */
|
|
13
|
+
hasPeer(conversationId: string): boolean;
|
|
14
|
+
/** 当前活跃的配对会话 id。 */
|
|
15
|
+
conversationIds(): string[];
|
|
16
|
+
/** 把一条会话标为不可用(复核 R1:解不开/没人接时主动作废)。 */
|
|
17
|
+
voidConversation?(conversationId: string): void;
|
|
18
|
+
}
|
|
19
|
+
export interface RuntimeOptions {
|
|
20
|
+
/** 会话列表的全量刷新周期。事件驱动之外还要有一条兜底,因为旧实现断连期间会丢事件。 */
|
|
21
|
+
listingRefreshMs: number;
|
|
22
|
+
window?: Partial<WindowOptions>;
|
|
23
|
+
/** 审批等待手机回应的上限;超时返回 decline,把决定权交还桌面 UI。 */
|
|
24
|
+
approvalTimeoutMs: number;
|
|
25
|
+
/** 提问等待上限;超时返回 null(提问服务没有 next 可交还)。 */
|
|
26
|
+
questionTimeoutMs: number;
|
|
27
|
+
/** 发指令前自动恢复归档会话。关掉它就要接受"归档会话被宿主 gate 直接拒掉"。 */
|
|
28
|
+
unarchiveOnPrompt: boolean;
|
|
29
|
+
log?: (message: string, fields?: Record<string, string | number | boolean | undefined>) => void;
|
|
30
|
+
}
|
|
31
|
+
export declare class HostRuntime {
|
|
32
|
+
private readonly kernel;
|
|
33
|
+
private readonly transport;
|
|
34
|
+
private readonly sleep;
|
|
35
|
+
private readonly clock;
|
|
36
|
+
private readonly options;
|
|
37
|
+
private readonly window;
|
|
38
|
+
private readonly pending;
|
|
39
|
+
private unsubscribe;
|
|
40
|
+
private detachSink;
|
|
41
|
+
private refreshTimer;
|
|
42
|
+
/** 被合并掉的那次推送:定时器 + 最后一次触发它的原因。 */
|
|
43
|
+
private mergeTimer;
|
|
44
|
+
private mergePendingReason;
|
|
45
|
+
private sessions;
|
|
46
|
+
private started;
|
|
47
|
+
private stopped;
|
|
48
|
+
private lastPushAt;
|
|
49
|
+
constructor(kernel: KernelPort, transport: RuntimeTransport, sleep: KeepAwake, clock: Clock, options?: Partial<RuntimeOptions>);
|
|
50
|
+
/** 挂接内核。任何一步失败都只降级,不抛(外层 apply() 的红线)。 */
|
|
51
|
+
start(): void;
|
|
52
|
+
stop(): void;
|
|
53
|
+
/** 手机发来的命令。`conversationId` 是配对通道 id,与载荷里的 sessionId 不是一回事(F3)。 */
|
|
54
|
+
handleCommand(cmd: CmdPayload, conversationId: string): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* 出站计数(进 status.json 的 `outbound`)。
|
|
57
|
+
*
|
|
58
|
+
* 为什么必须有:真机取证时手机报"没收到工具行",第一件要分清楚的事是
|
|
59
|
+
* **插件到底没发,还是发了但路上丢了**。没有这组计数,这个问题只能靠猜。
|
|
60
|
+
* `*_no_peer` 是"发了但回执说没有对端",那是另一种故障(配对已经不在了)。
|
|
61
|
+
*/
|
|
62
|
+
private readonly outboundCount;
|
|
63
|
+
get stats(): Record<string, number>;
|
|
64
|
+
private countOutbound;
|
|
65
|
+
private broadcast;
|
|
66
|
+
private replyTo;
|
|
67
|
+
/** 内核事件入口。合帧与顺序规则都在这几行里。 */
|
|
68
|
+
private onKernelEvent;
|
|
69
|
+
/**
|
|
70
|
+
* 推一次全量会话列表(F7/F8)。
|
|
71
|
+
*
|
|
72
|
+
* 相邻两次推送之间至少隔一个"合并窗口",因为内核可以在一个 turn 里连发十几条
|
|
73
|
+
* `sessions-changed`;列表是全量快照,合并掉中间几次没有信息损失。
|
|
74
|
+
*
|
|
75
|
+
* **但"合并"不等于"丢掉"**(第一版就是把它写成了丢掉):被合并的那一次必须变成一次
|
|
76
|
+
* 尾随推送,否则最后那次变化永远没人告知手机——F8 要求"任何会改变会话状态的动作
|
|
77
|
+
* 之后都必须额外推一条 session_changed",而手机不看 `ev.result.data.sessions`,
|
|
78
|
+
* 于是"发完指令列表却停在旧状态"最长要等到 15 秒的兜底刷新。
|
|
79
|
+
*/
|
|
80
|
+
pushSessions(reason: string): Promise<SessionSummary[]>;
|
|
81
|
+
private refreshLoop;
|
|
82
|
+
/**
|
|
83
|
+
* 平台发起一次审批。
|
|
84
|
+
*
|
|
85
|
+
* **没有在线对端就返回 `'decline'`**,让适配器去调平台的 `next()` 把决定权交还桌面 UI;
|
|
86
|
+
* 超时同样返回 `'decline'`(我们已经把卡片发出去了,但手机迟迟没点,
|
|
87
|
+
* 与其替用户决定,不如让桌面去决定)。
|
|
88
|
+
*/
|
|
89
|
+
private onApprovalRequest;
|
|
90
|
+
private onQuestionRequest;
|
|
91
|
+
private settleApproval;
|
|
92
|
+
private settleQuestion;
|
|
93
|
+
private settle;
|
|
94
|
+
/**
|
|
95
|
+
* 挑一条配对通道把这轮交互发出去。
|
|
96
|
+
*
|
|
97
|
+
* 为什么不能按 sessionId 精确定位:手机是在**配对通道**上收消息的,
|
|
98
|
+
* 而"哪个 DSH 会话属于哪条通道"只有手机端知道(它按 payload.sessionId 过滤显示)。
|
|
99
|
+
* 现网拓扑恒为 1 host : 1 client,所以"挑一条有对端的通道"就是正解;
|
|
100
|
+
* 将来若真要一个主机配多部手机,需要的是**广播给所有通道**再让手机按 sessionId 过滤。
|
|
101
|
+
*/
|
|
102
|
+
private pickConversation;
|
|
103
|
+
private log;
|
|
104
|
+
}
|
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* runtime — HostRuntime:内核事件 → 手机载荷,以及手机命令 → 内核调用。
|
|
3
|
+
*
|
|
4
|
+
* 这一层**不认识 cordis**,也不认识 socket:它只通过 `KernelPort` 与
|
|
5
|
+
* `RuntimeTransport` 说话,所以审批闭环、归档恢复、合帧顺序这些真正难验证的行为
|
|
6
|
+
* 都能在纯内存里测出来(旧实现做不到,它的测试全靠手写 cordis 替身)。
|
|
7
|
+
*
|
|
8
|
+
* 四条必须在这里守住的协议义务(编号对应 docs/DESIGN.md §2):
|
|
9
|
+
*
|
|
10
|
+
* - **F8 列表推送义务**:会话列表的唯一数据源是 `ev.session_changed`,
|
|
11
|
+
* `ev.result.data.sessions` 手机**不看**。所以每次 `cmd.list_sessions`、
|
|
12
|
+
* 以及任何会改变会话状态的动作之后,都必须**额外推一条 session_changed**。
|
|
13
|
+
* - **F9 done 帧不可丢**:文本收尾由 `DeltaWindow` 负责,本层只保证
|
|
14
|
+
* "非 delta 事件之前先 flush 同会话缓冲",否则工具行会插到它自己的文本前面。
|
|
15
|
+
* - **F10 decision 逐字**:手机端回传的是我们下发的 `options[].id`,
|
|
16
|
+
* 所以这里的选项 id 必须是**稳定机器名**,且 `'reject'` 这个词不能改——
|
|
17
|
+
* 小程序用它判断"拒绝之后界面该不该继续显示运行中"。
|
|
18
|
+
* - **F11 两个无会话归属的载荷**:`ev.session_changed` / `ev.keep_awake_state`
|
|
19
|
+
* 由 `outbound.ts` 的构造器产出,参数表里就没有 sessionId。
|
|
20
|
+
*/
|
|
21
|
+
import { randomUUID } from 'node:crypto';
|
|
22
|
+
import { keepAwakeState, messageDelta, permissionRequest, questionRequest, result as resultOf, runState, sessionChanged, sessionHistory, toolEvent, } from 'dsh-remote-wire/outbound';
|
|
23
|
+
import { DeltaWindow, DEFAULT_WINDOW_OPTIONS } from './window.js';
|
|
24
|
+
const APPROVAL_OPTIONS = [
|
|
25
|
+
// 'reject' 这个词是手机端的行为分支条件,不能改(F10)。
|
|
26
|
+
{ id: 'approve', label: '允许一次' },
|
|
27
|
+
{ id: 'reject', label: '拒绝' },
|
|
28
|
+
];
|
|
29
|
+
const DEFAULTS = {
|
|
30
|
+
listingRefreshMs: 15_000,
|
|
31
|
+
approvalTimeoutMs: 180_000,
|
|
32
|
+
questionTimeoutMs: 300_000,
|
|
33
|
+
unarchiveOnPrompt: true,
|
|
34
|
+
};
|
|
35
|
+
/** 一次列表最多给手机多少条会话(与中继侧的会话上限同源,取证 §5.3)。 */
|
|
36
|
+
const LISTING_LIMIT = 100;
|
|
37
|
+
/** 一次历史翻页默认给多少条(协议上界 200,这里更保守:一帧要装得下)。 */
|
|
38
|
+
const HISTORY_LIMIT = 40;
|
|
39
|
+
/** 相邻两条 `ev.session_changed` 的最小间隔;小于它就改成尾随推送。 */
|
|
40
|
+
const SESSION_MERGE_MS = 500;
|
|
41
|
+
export class HostRuntime {
|
|
42
|
+
kernel;
|
|
43
|
+
transport;
|
|
44
|
+
sleep;
|
|
45
|
+
clock;
|
|
46
|
+
options;
|
|
47
|
+
window;
|
|
48
|
+
pending = new Map();
|
|
49
|
+
unsubscribe;
|
|
50
|
+
detachSink;
|
|
51
|
+
refreshTimer;
|
|
52
|
+
/** 被合并掉的那次推送:定时器 + 最后一次触发它的原因。 */
|
|
53
|
+
mergeTimer;
|
|
54
|
+
mergePendingReason = 'merged';
|
|
55
|
+
sessions = [];
|
|
56
|
+
started = false;
|
|
57
|
+
stopped = false;
|
|
58
|
+
lastPushAt = 0;
|
|
59
|
+
constructor(kernel, transport, sleep, clock, options = {}) {
|
|
60
|
+
this.kernel = kernel;
|
|
61
|
+
this.transport = transport;
|
|
62
|
+
this.sleep = sleep;
|
|
63
|
+
this.clock = clock;
|
|
64
|
+
this.options = { ...DEFAULTS, ...options };
|
|
65
|
+
this.window = new DeltaWindow((delta) => this.broadcast(delta), this.clock, {
|
|
66
|
+
...DEFAULT_WINDOW_OPTIONS,
|
|
67
|
+
...options.window,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/** 挂接内核。任何一步失败都只降级,不抛(外层 apply() 的红线)。 */
|
|
71
|
+
start() {
|
|
72
|
+
if (this.started)
|
|
73
|
+
return;
|
|
74
|
+
this.started = true;
|
|
75
|
+
try {
|
|
76
|
+
this.unsubscribe = this.kernel.subscribe((event) => this.onKernelEvent(event));
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
this.log('kernel subscribe failed', { message: messageOf(error) });
|
|
80
|
+
}
|
|
81
|
+
const detach = this.kernel.attachInteractionSink?.({
|
|
82
|
+
approval: (info) => this.onApprovalRequest(info),
|
|
83
|
+
question: (info) => this.onQuestionRequest(info),
|
|
84
|
+
});
|
|
85
|
+
if (detach)
|
|
86
|
+
this.detachSink = detach;
|
|
87
|
+
void this.pushSessions('start');
|
|
88
|
+
this.refreshTimer = this.clock.setTimeout(() => this.refreshLoop(), this.options.listingRefreshMs);
|
|
89
|
+
}
|
|
90
|
+
stop() {
|
|
91
|
+
if (this.stopped)
|
|
92
|
+
return;
|
|
93
|
+
this.stopped = true;
|
|
94
|
+
this.window.stop();
|
|
95
|
+
try {
|
|
96
|
+
this.unsubscribe?.();
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
/* 退订失败无所谓,进程要走了 */
|
|
100
|
+
}
|
|
101
|
+
this.detachSink?.();
|
|
102
|
+
if (this.refreshTimer !== undefined)
|
|
103
|
+
this.clock.clearTimeout(this.refreshTimer);
|
|
104
|
+
if (this.mergeTimer !== undefined) {
|
|
105
|
+
this.clock.clearTimeout(this.mergeTimer);
|
|
106
|
+
this.mergeTimer = undefined;
|
|
107
|
+
}
|
|
108
|
+
for (const [id, item] of [...this.pending])
|
|
109
|
+
this.settle(id, undefined);
|
|
110
|
+
}
|
|
111
|
+
/** 手机发来的命令。`conversationId` 是配对通道 id,与载荷里的 sessionId 不是一回事(F3)。 */
|
|
112
|
+
async handleCommand(cmd, conversationId) {
|
|
113
|
+
const reply = (ok, extras = {}) => {
|
|
114
|
+
this.replyTo(conversationId, resultOf(cmd.cmdId, ok, extras));
|
|
115
|
+
};
|
|
116
|
+
try {
|
|
117
|
+
switch (cmd.t) {
|
|
118
|
+
case 'cmd.list_sessions': {
|
|
119
|
+
const sessions = await this.pushSessions('list');
|
|
120
|
+
reply(true, { data: { sessions } });
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
case 'cmd.send_prompt': {
|
|
124
|
+
if (this.options.unarchiveOnPrompt && this.kernel.ensureRunnable) {
|
|
125
|
+
const ready = await this.kernel.ensureRunnable(cmd.sessionId);
|
|
126
|
+
if (!ready.ok) {
|
|
127
|
+
reply(false, { message: ready.message ?? '会话无法恢复' });
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const sent = await this.kernel.sendPrompt(cmd.sessionId, cmd.text);
|
|
132
|
+
reply(sent.ok, sent.message ? { message: sent.message } : {});
|
|
133
|
+
if (sent.ok) {
|
|
134
|
+
this.sleep.markActive();
|
|
135
|
+
void this.pushSessions('prompt'); // F8:状态变了就要额外推一次
|
|
136
|
+
}
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
case 'cmd.interrupt': {
|
|
140
|
+
const done = await this.kernel.interrupt(cmd.sessionId);
|
|
141
|
+
reply(done.ok, done.message ? { message: done.message } : {});
|
|
142
|
+
void this.pushSessions('interrupt');
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
case 'cmd.resolve_permission': {
|
|
146
|
+
const settled = this.settleApproval(cmd.requestId, cmd.decision);
|
|
147
|
+
reply(settled, settled ? {} : { message: '这个审批请求已经不在挂起状态' });
|
|
148
|
+
void this.pushSessions('permission');
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
case 'cmd.answer': {
|
|
152
|
+
const settled = this.settleQuestion(cmd.requestId, cmd.answers);
|
|
153
|
+
reply(settled, settled ? { data: { answered: cmd.requestId } } : { message: '这个提问已经不在挂起状态' });
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
case 'cmd.keep_awake': {
|
|
157
|
+
const snapshot = this.sleep.setEnabled(cmd.enabled, cmd.idleReleaseSec);
|
|
158
|
+
this.broadcast(keepAwakeState(snapshot));
|
|
159
|
+
reply(true);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
case 'cmd.new_session': {
|
|
163
|
+
// 能力缺失时**明确拒绝**(与 cmd.session_history 同一条原则):回一个假的
|
|
164
|
+
// sessionId 让手机一路走下去,失败点会跑到很远的地方 —— 用户看到的是
|
|
165
|
+
// "新建了一个会话,但发什么都失败",而病根在宿主没有这个服务。
|
|
166
|
+
const create = this.kernel.newSession;
|
|
167
|
+
if (!create) {
|
|
168
|
+
reply(false, { message: '主机这一代不支持新建会话(内核端口没有 newSession 能力)' });
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const made = await create.call(this.kernel);
|
|
172
|
+
if (!made.ok || !made.sessionId) {
|
|
173
|
+
reply(false, { message: made.message ?? '新建会话失败' });
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
reply(true, { data: { sessionId: made.sessionId } });
|
|
177
|
+
// 状态变了就要额外推一次列表(F8):手机新建完回到列表时那条会话必须已经在,
|
|
178
|
+
// 靠 15 秒的兜底刷新等它出现是不可接受的。
|
|
179
|
+
void this.pushSessions('new-session');
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
case 'cmd.session_history': {
|
|
183
|
+
// 能力缺失时**明确拒绝**:回一张空页在手机上是"这个会话没内容",
|
|
184
|
+
// 那是一个会让人查错方向的假事实。能力面差异是真实存在的(见 KernelPort)。
|
|
185
|
+
const read = this.kernel.readHistory;
|
|
186
|
+
if (!read) {
|
|
187
|
+
reply(false, { message: '主机这一代不支持读取历史(内核端口没有 readHistory 能力)' });
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const page = await read.call(this.kernel, cmd.sessionId, {
|
|
191
|
+
...(cmd.beforeSeq === undefined ? {} : { beforeSeq: cmd.beforeSeq }),
|
|
192
|
+
limit: cmd.limit ?? HISTORY_LIMIT,
|
|
193
|
+
});
|
|
194
|
+
// 条目走**与实时流同一批出站构造器**:形状一致才谈得上"同一套渲染路径"。
|
|
195
|
+
const items = [];
|
|
196
|
+
for (const event of page.events) {
|
|
197
|
+
const item = historyWireItem(event);
|
|
198
|
+
if (item)
|
|
199
|
+
items.push(item);
|
|
200
|
+
}
|
|
201
|
+
this.replyTo(conversationId, sessionHistory({
|
|
202
|
+
sessionId: cmd.sessionId,
|
|
203
|
+
cmdId: cmd.cmdId,
|
|
204
|
+
items,
|
|
205
|
+
...(page.nextBeforeSeq === undefined ? {} : { nextBeforeSeq: page.nextBeforeSeq }),
|
|
206
|
+
}));
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
// 兜底回执:手机端至少要看到"这条命令失败了",否则 UI 会静默卡在原地。
|
|
213
|
+
// cmdId 一定回原值,因为对答靠它匹配。
|
|
214
|
+
reply(false, { message: messageOf(error) });
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* 出站计数(进 status.json 的 `outbound`)。
|
|
219
|
+
*
|
|
220
|
+
* 为什么必须有:真机取证时手机报"没收到工具行",第一件要分清楚的事是
|
|
221
|
+
* **插件到底没发,还是发了但路上丢了**。没有这组计数,这个问题只能靠猜。
|
|
222
|
+
* `*_no_peer` 是"发了但回执说没有对端",那是另一种故障(配对已经不在了)。
|
|
223
|
+
*/
|
|
224
|
+
outboundCount = {};
|
|
225
|
+
get stats() {
|
|
226
|
+
return { ...this.outboundCount };
|
|
227
|
+
}
|
|
228
|
+
countOutbound(payload, sent) {
|
|
229
|
+
const key = payload.t.replace(/^ev\./, '');
|
|
230
|
+
this.outboundCount[key] = (this.outboundCount[key] ?? 0) + 1;
|
|
231
|
+
if (sent === false)
|
|
232
|
+
this.outboundCount[`${key}_no_peer`] = (this.outboundCount[`${key}_no_peer`] ?? 0) + 1;
|
|
233
|
+
}
|
|
234
|
+
broadcast(payload) {
|
|
235
|
+
// 广播也要报"有没有人收到":只数帧不数对端,就会在真机上出现
|
|
236
|
+
// "计数说发了 4 帧、手机一帧都没收到"这种无从对账的局面。
|
|
237
|
+
this.countOutbound(payload, this.transport.broadcast(payload) > 0);
|
|
238
|
+
}
|
|
239
|
+
replyTo(conversationId, payload) {
|
|
240
|
+
this.countOutbound(payload, this.transport.reply(conversationId, payload));
|
|
241
|
+
}
|
|
242
|
+
/** 内核事件入口。合帧与顺序规则都在这几行里。 */
|
|
243
|
+
onKernelEvent(event) {
|
|
244
|
+
switch (event.kind) {
|
|
245
|
+
case 'delta': {
|
|
246
|
+
// **一条带正文的 done 必须先把正文推进窗口**。内核没有 token 级增量:一条消息
|
|
247
|
+
// 就是一条完整的 `assistant/message`(正文与 done 同到)。第一版在这里只走
|
|
248
|
+
// `complete()`,而 complete 对"缓冲区里根本没有这条消息"的情形发的是 **done-only 帧**
|
|
249
|
+
// ——于是 `textOf` 辛苦读出来的回复被整个丢掉,手机上收到一帧空文本 + done,
|
|
250
|
+
// 而"⑧ 流式输出到达 / ⑨ 有 done"两条断言照样绿(真机取证抓到的正是这个)。
|
|
251
|
+
if (event.text)
|
|
252
|
+
this.window.push(event.sessionId, event.messageId, event.text, event.role);
|
|
253
|
+
if (event.done)
|
|
254
|
+
this.window.complete(event.sessionId, event.messageId, event.role);
|
|
255
|
+
if (event.text)
|
|
256
|
+
this.sleep.markActive();
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
case 'tool':
|
|
260
|
+
// 非 delta 事件之前必须先 flush 同会话缓冲,否则工具行会插进它自己的文本里。
|
|
261
|
+
this.window.flushSession(event.sessionId);
|
|
262
|
+
this.broadcast(toolEvent(event));
|
|
263
|
+
this.sleep.markActive();
|
|
264
|
+
return;
|
|
265
|
+
case 'run-state':
|
|
266
|
+
this.window.flushSession(event.sessionId);
|
|
267
|
+
this.broadcast(runState(event));
|
|
268
|
+
if (event.state === 'running')
|
|
269
|
+
this.sleep.markActive();
|
|
270
|
+
void this.pushSessions('run-state');
|
|
271
|
+
return;
|
|
272
|
+
case 'title':
|
|
273
|
+
void this.pushSessions('title');
|
|
274
|
+
return;
|
|
275
|
+
case 'sessions-changed':
|
|
276
|
+
void this.pushSessions(event.reason ?? 'changed');
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* 推一次全量会话列表(F7/F8)。
|
|
282
|
+
*
|
|
283
|
+
* 相邻两次推送之间至少隔一个"合并窗口",因为内核可以在一个 turn 里连发十几条
|
|
284
|
+
* `sessions-changed`;列表是全量快照,合并掉中间几次没有信息损失。
|
|
285
|
+
*
|
|
286
|
+
* **但"合并"不等于"丢掉"**(第一版就是把它写成了丢掉):被合并的那一次必须变成一次
|
|
287
|
+
* 尾随推送,否则最后那次变化永远没人告知手机——F8 要求"任何会改变会话状态的动作
|
|
288
|
+
* 之后都必须额外推一条 session_changed",而手机不看 `ev.result.data.sessions`,
|
|
289
|
+
* 于是"发完指令列表却停在旧状态"最长要等到 15 秒的兜底刷新。
|
|
290
|
+
*/
|
|
291
|
+
async pushSessions(reason) {
|
|
292
|
+
if (this.stopped)
|
|
293
|
+
return this.sessions;
|
|
294
|
+
try {
|
|
295
|
+
const listed = await this.kernel.listSessions(LISTING_LIMIT);
|
|
296
|
+
this.sessions = listed.map((item) => item.summary);
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
// 读失败时**保留上一次已知的快照**再照常广播:把列表清成空白比停在旧状态更糟
|
|
300
|
+
// (手机会以为会话全没了),而 keep_awake 那一侧的状态仍然必须送达(M25)。
|
|
301
|
+
this.log('list sessions failed', { message: messageOf(error), reason });
|
|
302
|
+
}
|
|
303
|
+
// 判窗口用的是"数据到手"的时刻,不是进入函数的时刻:内核读列表可能很慢,
|
|
304
|
+
// 用进入时刻会让一次 400ms 的读直接吃掉整个合并窗口。
|
|
305
|
+
const now = this.clock.now();
|
|
306
|
+
const sinceLast = now - this.lastPushAt;
|
|
307
|
+
if (sinceLast < SESSION_MERGE_MS && reason !== 'start' && reason !== 'list') {
|
|
308
|
+
this.mergePendingReason = reason;
|
|
309
|
+
if (this.mergeTimer === undefined) {
|
|
310
|
+
this.mergeTimer = this.clock.setTimeout(() => {
|
|
311
|
+
this.mergeTimer = undefined;
|
|
312
|
+
void this.pushSessions(this.mergePendingReason);
|
|
313
|
+
}, SESSION_MERGE_MS - sinceLast);
|
|
314
|
+
}
|
|
315
|
+
return this.sessions;
|
|
316
|
+
}
|
|
317
|
+
this.lastPushAt = now;
|
|
318
|
+
if (this.mergeTimer !== undefined) {
|
|
319
|
+
// 这一条全量快照已经把待推的内容覆盖到了,尾随推送不必再发(否则会多发一条重复列表)。
|
|
320
|
+
this.clock.clearTimeout(this.mergeTimer);
|
|
321
|
+
this.mergeTimer = undefined;
|
|
322
|
+
}
|
|
323
|
+
this.broadcast(sessionChanged(this.sessions, reason));
|
|
324
|
+
this.broadcast(keepAwakeState(this.sleep.snapshot()));
|
|
325
|
+
return this.sessions;
|
|
326
|
+
}
|
|
327
|
+
refreshLoop() {
|
|
328
|
+
if (this.stopped)
|
|
329
|
+
return;
|
|
330
|
+
void this.pushSessions('refresh');
|
|
331
|
+
this.window.flushRound();
|
|
332
|
+
this.refreshTimer = this.clock.setTimeout(() => this.refreshLoop(), this.options.listingRefreshMs);
|
|
333
|
+
}
|
|
334
|
+
// ── 人工交互:审批与提问 ────────────────────────────────────────────
|
|
335
|
+
/**
|
|
336
|
+
* 平台发起一次审批。
|
|
337
|
+
*
|
|
338
|
+
* **没有在线对端就返回 `'decline'`**,让适配器去调平台的 `next()` 把决定权交还桌面 UI;
|
|
339
|
+
* 超时同样返回 `'decline'`(我们已经把卡片发出去了,但手机迟迟没点,
|
|
340
|
+
* 与其替用户决定,不如让桌面去决定)。
|
|
341
|
+
*/
|
|
342
|
+
async onApprovalRequest(info) {
|
|
343
|
+
const conversationId = this.pickConversation(info.sessionId);
|
|
344
|
+
if (!conversationId || !this.transport.hasPeer(conversationId))
|
|
345
|
+
return 'decline';
|
|
346
|
+
const id = `ap_${randomUUID().slice(0, 8)}`;
|
|
347
|
+
this.sleep.hold(id);
|
|
348
|
+
const answered = await new Promise((resolve) => {
|
|
349
|
+
const timer = this.clock.setTimeout(() => {
|
|
350
|
+
this.pending.delete(id);
|
|
351
|
+
resolve('decline');
|
|
352
|
+
}, this.options.approvalTimeoutMs);
|
|
353
|
+
this.pending.set(id, {
|
|
354
|
+
conversationId,
|
|
355
|
+
sessionId: info.sessionId,
|
|
356
|
+
resolve: (value) => resolve(value === undefined ? 'decline' : value),
|
|
357
|
+
timer,
|
|
358
|
+
});
|
|
359
|
+
info.signal?.addEventListener('abort', () => this.settle(id, 'cancelled'), { once: true });
|
|
360
|
+
this.replyTo(conversationId, permissionRequest({
|
|
361
|
+
requestId: id,
|
|
362
|
+
sessionId: info.sessionId,
|
|
363
|
+
action: info.action,
|
|
364
|
+
...(info.reason === undefined ? {} : { reason: info.reason }),
|
|
365
|
+
options: APPROVAL_OPTIONS,
|
|
366
|
+
}));
|
|
367
|
+
});
|
|
368
|
+
this.sleep.releaseHold(id);
|
|
369
|
+
// 结算点(settleApproval)已经把手机的 'approve'/'reject' 翻成平台词汇了,
|
|
370
|
+
// 这里不再翻第二次——两处映射表迟早会分叉。
|
|
371
|
+
return answered;
|
|
372
|
+
}
|
|
373
|
+
async onQuestionRequest(info) {
|
|
374
|
+
const conversationId = this.pickConversation(info.sessionId);
|
|
375
|
+
if (!conversationId || !this.transport.hasPeer(conversationId))
|
|
376
|
+
return null;
|
|
377
|
+
const id = `q_${randomUUID().slice(0, 8)}`;
|
|
378
|
+
this.sleep.hold(id);
|
|
379
|
+
const answer = await new Promise((resolve) => {
|
|
380
|
+
const timer = this.clock.setTimeout(() => {
|
|
381
|
+
this.pending.delete(id);
|
|
382
|
+
resolve(null);
|
|
383
|
+
}, this.options.questionTimeoutMs);
|
|
384
|
+
this.pending.set(id, {
|
|
385
|
+
conversationId,
|
|
386
|
+
sessionId: info.sessionId,
|
|
387
|
+
resolve: (value) => resolve(value ?? null),
|
|
388
|
+
timer,
|
|
389
|
+
options: info.questions,
|
|
390
|
+
});
|
|
391
|
+
info.signal?.addEventListener('abort', () => this.settle(id, null), { once: true });
|
|
392
|
+
this.replyTo(conversationId, questionRequest({
|
|
393
|
+
requestId: id,
|
|
394
|
+
sessionId: info.sessionId,
|
|
395
|
+
questions: info.questions,
|
|
396
|
+
}));
|
|
397
|
+
});
|
|
398
|
+
this.sleep.releaseHold(id);
|
|
399
|
+
return answer;
|
|
400
|
+
}
|
|
401
|
+
settleApproval(requestId, decision) {
|
|
402
|
+
const item = this.pending.get(requestId);
|
|
403
|
+
if (!item)
|
|
404
|
+
return false;
|
|
405
|
+
// F10:手机逐字回传我们下发的 options[].id;'reject' 之外的一律视为放行一次。
|
|
406
|
+
const outcome = decision === 'reject' ? 'rejected' : 'allowed-once';
|
|
407
|
+
this.settle(requestId, outcome);
|
|
408
|
+
return true;
|
|
409
|
+
}
|
|
410
|
+
settleQuestion(requestId, answers) {
|
|
411
|
+
const item = this.pending.get(requestId);
|
|
412
|
+
if (!item)
|
|
413
|
+
return false;
|
|
414
|
+
// 平台的答案里 selected 装的是**选项 label**(不是我们的 id),所以这里要翻回去。
|
|
415
|
+
const byQuestion = new Map((item.options ?? []).map((question) => [question.id, question]));
|
|
416
|
+
const value = {
|
|
417
|
+
answers: answers.map((answer) => {
|
|
418
|
+
const question = byQuestion.get(answer.questionId);
|
|
419
|
+
const selected = (question?.options ?? [])
|
|
420
|
+
.filter((option) => answer.selected.includes(option.id))
|
|
421
|
+
.map((option) => option.label);
|
|
422
|
+
return {
|
|
423
|
+
id: answer.questionId,
|
|
424
|
+
selected,
|
|
425
|
+
...(answer.freeText === undefined ? {} : { custom: answer.freeText }),
|
|
426
|
+
};
|
|
427
|
+
}),
|
|
428
|
+
};
|
|
429
|
+
this.settle(requestId, value);
|
|
430
|
+
return true;
|
|
431
|
+
}
|
|
432
|
+
settle(id, value) {
|
|
433
|
+
const item = this.pending.get(id);
|
|
434
|
+
if (!item)
|
|
435
|
+
return;
|
|
436
|
+
this.pending.delete(id);
|
|
437
|
+
this.clock.clearTimeout(item.timer);
|
|
438
|
+
item.resolve(value);
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* 挑一条配对通道把这轮交互发出去。
|
|
442
|
+
*
|
|
443
|
+
* 为什么不能按 sessionId 精确定位:手机是在**配对通道**上收消息的,
|
|
444
|
+
* 而"哪个 DSH 会话属于哪条通道"只有手机端知道(它按 payload.sessionId 过滤显示)。
|
|
445
|
+
* 现网拓扑恒为 1 host : 1 client,所以"挑一条有对端的通道"就是正解;
|
|
446
|
+
* 将来若真要一个主机配多部手机,需要的是**广播给所有通道**再让手机按 sessionId 过滤。
|
|
447
|
+
*/
|
|
448
|
+
pickConversation(_sessionId) {
|
|
449
|
+
const ids = this.transport.conversationIds();
|
|
450
|
+
if (ids.length === 0)
|
|
451
|
+
return undefined;
|
|
452
|
+
return ids.find((id) => this.transport.hasPeer(id)) ?? ids[0];
|
|
453
|
+
}
|
|
454
|
+
log(message, fields) {
|
|
455
|
+
this.options.log?.(message, fields);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
function messageOf(error) {
|
|
459
|
+
return String(error?.message ?? error);
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* `KernelEvent` → 历史条目。
|
|
463
|
+
*
|
|
464
|
+
* 运行态 / 标题 / 列表变化在历史里没有位置——它们是"此刻"的事,回放历史不该去改顶栏;
|
|
465
|
+
* 返回 `undefined` 由调用方丢掉。
|
|
466
|
+
*
|
|
467
|
+
* `done` 恒为 `true`:历史里的消息是**已经写完的**。不置的话手机上正文末尾会挂着一个
|
|
468
|
+
* 一直闪的光标,看起来像还在生成。
|
|
469
|
+
*/
|
|
470
|
+
function historyWireItem(event) {
|
|
471
|
+
if (event.kind === 'delta') {
|
|
472
|
+
return messageDelta({
|
|
473
|
+
messageId: event.messageId,
|
|
474
|
+
delta: event.text,
|
|
475
|
+
done: true,
|
|
476
|
+
...(event.role === undefined ? {} : { role: event.role }),
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
if (event.kind === 'tool') {
|
|
480
|
+
return toolEvent({
|
|
481
|
+
callId: event.callId,
|
|
482
|
+
phase: event.phase,
|
|
483
|
+
...(event.tool === undefined ? {} : { tool: event.tool }),
|
|
484
|
+
...(event.title === undefined ? {} : { title: event.title }),
|
|
485
|
+
...(event.argsPreview === undefined ? {} : { argsPreview: event.argsPreview }),
|
|
486
|
+
...(event.resultPreview === undefined ? {} : { resultPreview: event.resultPreview }),
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
return undefined;
|
|
490
|
+
}
|
|
491
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/core/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,OAAO,EACL,cAAc,EACd,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,MAAM,IAAI,QAAQ,EAClB,QAAQ,EACR,cAAc,EACd,cAAc,EACd,SAAS,GACV,MAAM,0BAA0B,CAAA;AAEjC,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAsB,MAAM,aAAa,CAAA;AAwCrF,MAAM,gBAAgB,GAAG;IACvB,oCAAoC;IACpC,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE;IAChC,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE;CAC9B,CAAA;AAED,MAAM,QAAQ,GAAmB;IAC/B,gBAAgB,EAAE,MAAM;IACxB,iBAAiB,EAAE,OAAO;IAC1B,iBAAiB,EAAE,OAAO;IAC1B,iBAAiB,EAAE,IAAI;CACxB,CAAA;AAED,2CAA2C;AAC3C,MAAM,aAAa,GAAG,GAAG,CAAA;AACzB,2CAA2C;AAC3C,MAAM,aAAa,GAAG,EAAE,CAAA;AACxB,kDAAkD;AAClD,MAAM,gBAAgB,GAAG,GAAG,CAAA;AAE5B,MAAM,OAAO,WAAW;IAgBH;IACA;IACA;IACA;IAlBF,OAAO,CAAgB;IACvB,MAAM,CAAa;IACnB,OAAO,GAAG,IAAI,GAAG,EAA8B,CAAA;IACxD,WAAW,CAA0B;IACrC,UAAU,CAA0B;IACpC,YAAY,CAAS;IAC7B,kCAAkC;IAC1B,UAAU,CAAS;IACnB,kBAAkB,GAAG,QAAQ,CAAA;IAC7B,QAAQ,GAAqB,EAAE,CAAA;IAC/B,OAAO,GAAG,KAAK,CAAA;IACf,OAAO,GAAG,KAAK,CAAA;IACf,UAAU,GAAG,CAAC,CAAA;IAEtB,YACmB,MAAkB,EAClB,SAA2B,EAC3B,KAAgB,EAChB,KAAY,EAC7B,UAAmC,EAAE;QAJpB,WAAM,GAAN,MAAM,CAAY;QAClB,cAAS,GAAT,SAAS,CAAkB;QAC3B,UAAK,GAAL,KAAK,CAAW;QAChB,UAAK,GAAL,KAAK,CAAO;QAG7B,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAA;QAC1C,IAAI,CAAC,MAAM,GAAG,IAAI,WAAW,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE;YAC1E,GAAG,sBAAsB;YACzB,GAAG,OAAO,CAAC,MAAM;SAClB,CAAC,CAAA;IACJ,CAAC;IAED,0CAA0C;IAC1C,KAAK;QACH,IAAI,IAAI,CAAC,OAAO;YAAE,OAAM;QACxB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QACnB,IAAI,CAAC;YACH,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAA;QAChF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,GAAG,CAAC,yBAAyB,EAAE,EAAE,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACpE,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,qBAAqB,EAAE,CAAC;YACjD,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC;YAChD,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC;SACjD,CAAC,CAAA;QACF,IAAI,MAAM;YAAE,IAAI,CAAC,UAAU,GAAG,MAAM,CAAA;QACpC,KAAK,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAA;QAC/B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;IACpG,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,OAAO;YAAE,OAAM;QACxB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QACnB,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAA;QAClB,IAAI,CAAC;YACH,IAAI,CAAC,WAAW,EAAE,EAAE,CAAA;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,mBAAmB;QACrB,CAAC;QACD,IAAI,CAAC,UAAU,EAAE,EAAE,CAAA;QACnB,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QAC/E,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YAClC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;YACxC,IAAI,CAAC,UAAU,GAAG,SAAS,CAAA;QAC7B,CAAC;QACD,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;YAAE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,CAAC,CAAA;IACxE,CAAC;IAED,mEAAmE;IACnE,KAAK,CAAC,aAAa,CAAC,GAAe,EAAE,cAAsB;QACzD,MAAM,KAAK,GAAG,CAAC,EAAW,EAAE,SAA+D,EAAE,EAAQ,EAAE;YACrG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,CAAA;QAC/D,CAAC,CAAA;QACD,IAAI,CAAC;YACH,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC;gBACd,KAAK,mBAAmB,CAAC,CAAC,CAAC;oBACzB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAA;oBAChD,KAAK,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAA;oBACnC,OAAM;gBACR,CAAC;gBACD,KAAK,iBAAiB,CAAC,CAAC,CAAC;oBACvB,IAAI,IAAI,CAAC,OAAO,CAAC,iBAAiB,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;wBACjE,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;wBAC7D,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;4BACd,KAAK,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,QAAQ,EAAE,CAAC,CAAA;4BACpD,OAAM;wBACR,CAAC;oBACH,CAAC;oBACD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC,CAAA;oBAClE,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;oBAC7D,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;wBACZ,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAA;wBACvB,KAAK,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAA,CAAC,iBAAiB;oBACpD,CAAC;oBACD,OAAM;gBACR,CAAC;gBACD,KAAK,eAAe,CAAC,CAAC,CAAC;oBACrB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;oBACvD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;oBAC7D,KAAK,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAA;oBACnC,OAAM;gBACR,CAAC;gBACD,KAAK,wBAAwB,CAAC,CAAC,CAAC;oBAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAA;oBAChE,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,CAAA;oBAC5D,KAAK,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,CAAA;oBACpC,OAAM;gBACR,CAAC;gBACD,KAAK,YAAY,CAAC,CAAC,CAAC;oBAClB,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;oBAC/D,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAA;oBAC7F,OAAM;gBACR,CAAC;gBACD,KAAK,gBAAgB,CAAC,CAAC,CAAC;oBACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,cAAc,CAAC,CAAA;oBACvE,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAA;oBACxC,KAAK,CAAC,IAAI,CAAC,CAAA;oBACX,OAAM;gBACR,CAAC;gBACD,KAAK,iBAAiB,CAAC,CAAC,CAAC;oBACvB,mDAAmD;oBACnD,2CAA2C;oBAC3C,kCAAkC;oBAClC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAA;oBACrC,IAAI,CAAC,MAAM,EAAE,CAAC;wBACZ,KAAK,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,oCAAoC,EAAE,CAAC,CAAA;wBAC/D,OAAM;oBACR,CAAC;oBACD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;oBAC3C,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;wBAChC,KAAK,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,QAAQ,EAAE,CAAC,CAAA;wBACnD,OAAM;oBACR,CAAC;oBACD,KAAK,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;oBACpD,yCAAyC;oBACzC,yBAAyB;oBACzB,KAAK,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,CAAA;oBACrC,OAAM;gBACR,CAAC;gBACD,KAAK,qBAAqB,CAAC,CAAC,CAAC;oBAC3B,qCAAqC;oBACrC,6CAA6C;oBAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAA;oBACpC,IAAI,CAAC,IAAI,EAAE,CAAC;wBACV,KAAK,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,qCAAqC,EAAE,CAAC,CAAA;wBAChE,OAAM;oBACR,CAAC;oBACD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,SAAS,EAAE;wBACvD,GAAG,CAAC,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;wBACpE,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,aAAa;qBAClC,CAAC,CAAA;oBACF,yCAAyC;oBACzC,MAAM,KAAK,GAAkB,EAAE,CAAA;oBAC/B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;wBAChC,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,CAAC,CAAA;wBACnC,IAAI,IAAI;4BAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;oBAC5B,CAAC;oBACD,IAAI,CAAC,OAAO,CACV,cAAc,EACd,cAAc,CAAC;wBACb,SAAS,EAAE,GAAG,CAAC,SAAS;wBACxB,KAAK,EAAE,GAAG,CAAC,KAAK;wBAChB,KAAK;wBACL,GAAG,CAAC,IAAI,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC;qBACnF,CAAC,CACH,CAAA;oBACD,OAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,wCAAwC;YACxC,wBAAwB;YACxB,KAAK,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC7C,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACc,aAAa,GAA2B,EAAE,CAAA;IAC3D,IAAI,KAAK;QACP,OAAO,EAAE,GAAG,IAAI,CAAC,aAAa,EAAE,CAAA;IAClC,CAAC;IAEO,aAAa,CAAC,OAAkB,EAAE,IAAc;QACtD,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;QAC1C,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;QAC5D,IAAI,IAAI,KAAK,KAAK;YAAE,IAAI,CAAC,aAAa,CAAC,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;IAC5G,CAAC;IAEO,SAAS,CAAC,OAAkB;QAClC,iCAAiC;QACjC,iCAAiC;QACjC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;IACpE,CAAC;IAEO,OAAO,CAAC,cAAsB,EAAE,OAAkB;QACxD,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAA;IAC5E,CAAC;IAED,4BAA4B;IACpB,aAAa,CAAC,KAAkB;QACtC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,iDAAiD;gBACjD,oDAAoD;gBACpD,gEAAgE;gBAChE,iDAAiD;gBACjD,8CAA8C;gBAC9C,IAAI,KAAK,CAAC,IAAI;oBAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;gBAC1F,IAAI,KAAK,CAAC,IAAI;oBAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;gBAClF,IAAI,KAAK,CAAC,IAAI;oBAAE,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAA;gBACvC,OAAM;YACR,CAAC;YACD,KAAK,MAAM;gBACT,+CAA+C;gBAC/C,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;gBACzC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;gBAChC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAA;gBACvB,OAAM;YACR,KAAK,WAAW;gBACd,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;gBACzC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;gBAC/B,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;oBAAE,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAA;gBACtD,KAAK,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAA;gBACnC,OAAM;YACR,KAAK,OAAO;gBACV,KAAK,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAA;gBAC/B,OAAM;YACR,KAAK,kBAAkB;gBACrB,KAAK,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,IAAI,SAAS,CAAC,CAAA;gBACjD,OAAM;QACV,CAAC;IACH,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,YAAY,CAAC,MAAc;QAC/B,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAA;QACtC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,CAAA;YAC5D,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACpD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,0CAA0C;YAC1C,+CAA+C;YAC/C,IAAI,CAAC,GAAG,CAAC,sBAAsB,EAAE,EAAE,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;QACzE,CAAC;QACD,uCAAuC;QACvC,gCAAgC;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAA;QAC5B,MAAM,SAAS,GAAG,GAAG,GAAG,IAAI,CAAC,UAAU,CAAA;QACvC,IAAI,SAAS,GAAG,gBAAgB,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YAC5E,IAAI,CAAC,kBAAkB,GAAG,MAAM,CAAA;YAChC,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;gBAClC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE;oBAC3C,IAAI,CAAC,UAAU,GAAG,SAAS,CAAA;oBAC3B,KAAK,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;gBACjD,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC,CAAA;YAClC,CAAC;YACD,OAAO,IAAI,CAAC,QAAQ,CAAA;QACtB,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,GAAG,CAAA;QACrB,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YAClC,6CAA6C;YAC7C,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;YACxC,IAAI,CAAC,UAAU,GAAG,SAAS,CAAA;QAC7B,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;QACrD,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;QACrD,OAAO,IAAI,CAAC,QAAQ,CAAA;IACtB,CAAC;IAEO,WAAW;QACjB,IAAI,IAAI,CAAC,OAAO;YAAE,OAAM;QACxB,KAAK,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAA;QACjC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAA;QACxB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;IACpG,CAAC;IAED,6DAA6D;IAE7D;;;;;;OAMG;IACK,KAAK,CAAC,iBAAiB,CAAC,IAK/B;QACC,MAAM,cAAc,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC5D,IAAI,CAAC,cAAc,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,cAAc,CAAC;YAAE,OAAO,SAAS,CAAA;QAChF,MAAM,EAAE,GAAG,MAAM,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAA;QAC3C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACnB,MAAM,QAAQ,GAAG,MAAM,IAAI,OAAO,CAAmB,CAAC,OAAO,EAAE,EAAE;YAC/D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE;gBACvC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;gBACvB,OAAO,CAAC,SAAS,CAAC,CAAA;YACpB,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAA;YAClC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE;gBACnB,cAAc;gBACd,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,KAA0B,CAAC;gBAC1F,KAAK;aACN,CAAC,CAAA;YACF,IAAI,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;YAC1F,IAAI,CAAC,OAAO,CACV,cAAc,EACd,iBAAiB,CAAC;gBAChB,SAAS,EAAE,EAAE;gBACb,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC7D,OAAO,EAAE,gBAAgB;aAC1B,CAAC,CACH,CAAA;QACH,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;QAC1B,wDAAwD;QACxD,wBAAwB;QACxB,OAAO,QAAQ,CAAA;IACjB,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,IAI/B;QACC,MAAM,cAAc,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC5D,IAAI,CAAC,cAAc,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,cAAc,CAAC;YAAE,OAAO,IAAI,CAAA;QAC3E,MAAM,EAAE,GAAG,KAAK,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAA;QAC1C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACnB,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,CAAoC,CAAC,OAAO,EAAE,EAAE;YAC9E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE;gBACvC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;gBACvB,OAAO,CAAC,IAAI,CAAC,CAAA;YACf,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAA;YAClC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE;gBACnB,cAAc;gBACd,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAE,KAAgD,IAAI,IAAI,CAAC;gBACtF,KAAK;gBACL,OAAO,EAAE,IAAI,CAAC,SAAS;aACxB,CAAC,CAAA;YACF,IAAI,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;YACnF,IAAI,CAAC,OAAO,CACV,cAAc,EACd,eAAe,CAAC;gBACd,SAAS,EAAE,EAAE;gBACb,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,SAAS,EAAE,IAAI,CAAC,SAAS;aAC1B,CAAC,CACH,CAAA;QACH,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;QAC1B,OAAO,MAAM,CAAA;IACf,CAAC;IAEO,cAAc,CAAC,SAAiB,EAAE,QAAgB;QACxD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACxC,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAA;QACvB,qDAAqD;QACrD,MAAM,OAAO,GAAqB,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,cAAc,CAAA;QACrF,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;QAC/B,OAAO,IAAI,CAAA;IACb,CAAC;IAEO,cAAc,CAAC,SAAiB,EAAE,OAAqB;QAC7D,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACxC,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAA;QACvB,sDAAsD;QACtD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;QAC3F,MAAM,KAAK,GAA+B;YACxC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;gBAC9B,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;gBAClD,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,OAAO,IAAI,EAAE,CAAC;qBACvC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;qBACvD,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;gBAChC,OAAO;oBACL,EAAE,EAAE,MAAM,CAAC,UAAU;oBACrB,QAAQ;oBACR,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;iBACtE,CAAA;YACH,CAAC,CAAC;SACH,CAAA;QACD,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;QAC7B,OAAO,IAAI,CAAA;IACb,CAAC;IAEO,MAAM,CAAC,EAAU,EAAE,KAAc;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACjC,IAAI,CAAC,IAAI;YAAE,OAAM;QACjB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QACvB,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACnC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IACrB,CAAC;IAED;;;;;;;OAOG;IACK,gBAAgB,CAAC,UAAkB;QACzC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,EAAE,CAAA;QAC5C,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAA;QACtC,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAA;IAC/D,CAAC;IAEO,GAAG,CAAC,OAAe,EAAE,MAA8D;QACzF,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IACrC,CAAC;CACF;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,MAAM,CAAE,KAAe,EAAE,OAAO,IAAI,KAAK,CAAC,CAAA;AACnD,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,eAAe,CAAC,KAAkB;IACzC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC3B,OAAO,YAAY,CAAC;YAClB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,KAAK,EAAE,KAAK,CAAC,IAAI;YACjB,IAAI,EAAE,IAAI;YACV,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;SAC1D,CAAC,CAAA;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC1B,OAAO,SAAS,CAAC;YACf,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;YACzD,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;YAC5D,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;YAC9E,GAAG,CAAC,KAAK,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC;SACrF,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC"}
|