@yfwu2020/dsh-selection-explain 0.11.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -4
- package/lib/chat-context.js +84 -0
- package/lib/chat-context.js.map +1 -0
- package/lib/client.js +427 -110
- package/lib/client.js.map +4 -4
- package/lib/config-values.js +2 -0
- package/lib/config-values.js.map +1 -1
- package/lib/host/analyze.js +127 -26
- package/lib/host/analyze.js.map +1 -1
- package/lib/host/chat-context.js +155 -0
- package/lib/host/chat-context.js.map +1 -0
- package/lib/host/chat-materials.js +64 -0
- package/lib/host/chat-materials.js.map +1 -0
- package/lib/host/config.js +2 -1
- package/lib/host/config.js.map +1 -1
- package/lib/host/history-attachments.js +17 -53
- package/lib/host/history-attachments.js.map +1 -1
- package/lib/host/history-store.js +75 -62
- package/lib/host/history-store.js.map +1 -1
- package/lib/host/http.js +2 -1
- package/lib/host/http.js.map +1 -1
- package/lib/host/promote.js +0 -1
- package/lib/host/promote.js.map +1 -1
- package/lib/host/settings-store.js +17 -18
- package/lib/host/settings-store.js.map +1 -1
- package/lib/settings.js +3 -1
- package/lib/settings.js.map +1 -1
- package/lib/types/chat-context.d.ts +53 -0
- package/lib/types/config-values.d.ts +6 -0
- package/lib/types/host/chat-context.d.ts +31 -0
- package/lib/types/host/chat-materials.d.ts +16 -0
- package/lib/types/host/config.d.ts +4 -2
- package/lib/types/host/history-attachments.d.ts +7 -40
- package/lib/types/host/history-store.d.ts +1 -0
- package/lib/types/host/types.d.ts +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ DSH 中的翻译、上下文解读与语音追问。
|
|
|
8
8
|
|
|
9
9
|
[快速安装](#install) · [语音输入](#voice) · [功能一览](#read) · [使用与设置](#settings)
|
|
10
10
|
|
|
11
|
-
`DSH 插件` · `v0.
|
|
11
|
+
`DSH 插件` · `v0.12.0` · `MIT`
|
|
12
12
|
|
|
13
13
|
</div>
|
|
14
14
|
|
|
@@ -96,6 +96,13 @@ DSH 中的翻译、上下文解读与语音追问。
|
|
|
96
96
|
| 阅读代码 | 选中代码,查看注释与原代码交替呈现的解释 |
|
|
97
97
|
| 用图表理解复杂问题 | 将**输出偏好**切为网页,模型可生成 HTML 页面 |
|
|
98
98
|
|
|
99
|
+
长对话默认显示最近 **40 条消息**,点击消息区顶部的 **显示更早的消息** 可继续往前查看。收起小窗会释放回答区域的网页预览,重开后恢复显示;完整对话、输入草稿和待发送附件仍会保留。
|
|
100
|
+
|
|
101
|
+
小窗追问按**容量预算**组织模型上下文,不再固定截取最近 20 条消息。预算内保留原文和图片顺序;接近上限时,将较早的完整问答分批整理为摘要,最近问答保持原文。可在 **设置 → 模型 → 对话记忆** 调整输入预算,默认 32,768 tokens;宿主能提供模型容量时还会自动收紧,并预留回答与工具空间。用量为估算,整理摘要会产生额外模型调用;摘要失败会明确报错,不静默丢弃原文。
|
|
102
|
+
|
|
103
|
+
图片与文件保存在宿主附件库,历史只存引用。图片不再按“两张/4 MiB”、文件不再按“八个”滚动淘汰,而是随上下文段一起保留或压缩。启用工具时,模型可用小窗材料工具重新取得旧图、旧文件路径或已压缩的原始消息;文件正文仍由宿主读取工具按需解析。附件丢失或格式不支持时会说明原因。引用保留选中原文;较早的小窗引用会补充附近内容,主会话引用在加入时取得一次上下文快照。
|
|
104
|
+
|
|
105
|
+
|
|
99
106
|
<a id="install"></a>
|
|
100
107
|
|
|
101
108
|
## 快速安装
|
|
@@ -113,11 +120,11 @@ dsh plugin --profile web add @yfwu2020/dsh-selection-explain
|
|
|
113
120
|
<details>
|
|
114
121
|
<summary>安装 Release 构建包</summary>
|
|
115
122
|
|
|
116
|
-
将下载的 `.tgz` 放到当前目录,以 v0.
|
|
123
|
+
将下载的 `.tgz` 放到当前目录,以 v0.12.0 为例:
|
|
117
124
|
|
|
118
125
|
```bash
|
|
119
126
|
mkdir -p ~/.dsh/plugins/dsh-selection-explain
|
|
120
|
-
tar -xzf yfwu2020-dsh-selection-explain-0.
|
|
127
|
+
tar -xzf yfwu2020-dsh-selection-explain-0.12.0.tgz -C ~/.dsh/plugins/dsh-selection-explain --strip-components=1
|
|
121
128
|
dsh plugin --profile web add ~/.dsh/plugins/dsh-selection-explain
|
|
122
129
|
```
|
|
123
130
|
|
|
@@ -179,7 +186,7 @@ dsh plugin --profile web remove @yfwu2020/dsh-selection-explain
|
|
|
179
186
|
|
|
180
187
|
插件不将录音保存为音频文件,也不把音频附到会话;小窗录音由 DSH 配置的识别服务处理,是否经过云端取决于该服务。输入法语音由输入法本身处理,插件接收输入框中写入的文字。
|
|
181
188
|
|
|
182
|
-
解读历史默认保留最近 **20 条**,以明文存储在 `~/.dsh/selection-explain/history.json`。可在 **设置 → 数据** 中调整,设为 `0`
|
|
189
|
+
解读历史默认保留最近 **20 条**,以明文存储在 `~/.dsh/selection-explain/history.json`。可在 **设置 → 数据** 中调整,设为 `0` 停止保存新历史;已有历史不会因此清空。数量超过上限时,按最后更新时间淘汰最旧的小窗历史,已升格的记录也参与淘汰;升格后的正式会话不受影响。
|
|
183
190
|
|
|
184
191
|
支持 DSH 界面与可注入的侧边栏 HTML 预览。输入框、源码视图、外部站点浏览器标签页,以及部分第三方预览不触发划词(直接通过独立 URL 加载、无法注入划词桥的页面)。模型回答与联网查证仍可能出错。
|
|
185
192
|
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
export const CHAT_REQUEST_BYTES = 512 * 1024;
|
|
2
|
+
export const EMPTY_DIGEST = '811c9dc5';
|
|
3
|
+
export function readContextState(raw) {
|
|
4
|
+
if (!raw || typeof raw !== 'object')
|
|
5
|
+
return null;
|
|
6
|
+
const s = raw;
|
|
7
|
+
if (s.version !== 1 || !Number.isSafeInteger(s.through) || s.through < 0
|
|
8
|
+
|| !/^[a-f0-9]{8}$/.test(s.source) || !/^[a-f0-9]{8}$/.test(s.digest)
|
|
9
|
+
|| typeof s.summary !== 'string' || s.summary.length > 12000
|
|
10
|
+
|| (s.through > 0 && !s.summary.trim()))
|
|
11
|
+
return null;
|
|
12
|
+
if (s.background !== null && (!s.background || typeof s.background.transcript !== 'string'
|
|
13
|
+
|| s.background.transcript.length > 200000 || typeof s.background.marked !== 'boolean'))
|
|
14
|
+
return null;
|
|
15
|
+
if (s.sessionId !== undefined && (typeof s.sessionId !== 'string' || s.sessionId.length > 500))
|
|
16
|
+
return null;
|
|
17
|
+
return { version: 1, ...(typeof s.sessionId === 'string' ? { sessionId: s.sessionId } : {}), source: s.source, through: s.through, digest: s.digest, summary: s.summary,
|
|
18
|
+
background: s.background ? { transcript: s.background.transcript, marked: s.background.marked } : null };
|
|
19
|
+
}
|
|
20
|
+
function modelTurn(turn) {
|
|
21
|
+
if (turn.contextExcluded)
|
|
22
|
+
return { role: turn.role === 'assistant' ? 'assistant' : 'user',
|
|
23
|
+
text: turn.role === 'assistant' ? '(该轮未生成回答。)' : '(该提问未提交给模型,原始内容仍保存在界面历史中;需要时请重新引用必要部分。)' };
|
|
24
|
+
return { role: turn.role === 'assistant' ? 'assistant' : 'user', text: turn.sent || turn.text || '',
|
|
25
|
+
...(turn.attachments?.length ? { attachments: turn.attachments } : {}) };
|
|
26
|
+
}
|
|
27
|
+
/** Rolling consistency fingerprint, not an authorization credential. */
|
|
28
|
+
export function historyDigest(turns, initial = EMPTY_DIGEST) {
|
|
29
|
+
let hash = Number.parseInt(initial, 16) >>> 0;
|
|
30
|
+
for (const raw of turns) {
|
|
31
|
+
const t = modelTurn(raw);
|
|
32
|
+
const text = JSON.stringify([t.role, t.text, (t.attachments || []).map(a => [a.kind, a.ref.attachmentId])]) + '\n';
|
|
33
|
+
for (let i = 0; i < text.length; i++)
|
|
34
|
+
hash = Math.imul(hash ^ text.charCodeAt(i), 16777619) >>> 0;
|
|
35
|
+
}
|
|
36
|
+
return hash.toString(16).padStart(8, '0');
|
|
37
|
+
}
|
|
38
|
+
export function contextSource(session, text, context, initial) {
|
|
39
|
+
return historyDigest([{ role: 'user', text: JSON.stringify([session, text, context, initial]) }]);
|
|
40
|
+
}
|
|
41
|
+
/** Validate once, then serialize only the original, uncompressed suffix. */
|
|
42
|
+
export function prepareChatHistory(turns, rawState) {
|
|
43
|
+
const visible = turns.filter(t => !t.hidden);
|
|
44
|
+
let state = readContextState(rawState);
|
|
45
|
+
if (state && (state.through > visible.length || historyDigest(visible.slice(0, state.through)) !== state.digest))
|
|
46
|
+
state = null;
|
|
47
|
+
const start = state?.through || 0;
|
|
48
|
+
const materials = [];
|
|
49
|
+
const seen = new Set();
|
|
50
|
+
visible.forEach((turn, index) => {
|
|
51
|
+
for (const item of turn.attachments || []) {
|
|
52
|
+
const key = item.kind + ':' + item.ref.attachmentId;
|
|
53
|
+
if (!seen.has(key)) {
|
|
54
|
+
seen.add(key);
|
|
55
|
+
materials.push({ kind: item.kind, ref: item.ref, turn: index });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return { history: visible.slice(start).map(modelTurn), historyStart: start, contextState: state, materials };
|
|
60
|
+
}
|
|
61
|
+
/** Conservative estimate: ASCII ~3 chars/token; other UTF-16 units ~1 token. */
|
|
62
|
+
export function estimateTextTokens(text) {
|
|
63
|
+
let ascii = 0;
|
|
64
|
+
for (let i = 0; i < text.length; i++)
|
|
65
|
+
if (text.charCodeAt(i) <= 127)
|
|
66
|
+
ascii++;
|
|
67
|
+
return Math.ceil(ascii / 3) + text.length - ascii;
|
|
68
|
+
}
|
|
69
|
+
export function contextBudget(configured, window, output = 8192, tools = 2048) {
|
|
70
|
+
if (!window || !Number.isFinite(window) || window <= 0)
|
|
71
|
+
return configured;
|
|
72
|
+
return Math.floor(Math.min(configured, window * 0.8, window - output - tools));
|
|
73
|
+
}
|
|
74
|
+
/** A cut is always before a user message; at least the newest complete pair stays verbatim. */
|
|
75
|
+
export function chooseCompactionEnd(turns, target, price) {
|
|
76
|
+
let remaining = turns.reduce((n, t) => n + price(t), 0);
|
|
77
|
+
for (let i = 0; i < turns.length - 2; i++) {
|
|
78
|
+
remaining -= price(turns[i]);
|
|
79
|
+
if (i + 1 > 0 && turns[i + 1].role === 'user' && remaining <= target)
|
|
80
|
+
return i + 1;
|
|
81
|
+
}
|
|
82
|
+
return -1;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=chat-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-context.js","sourceRoot":"","sources":["../src/chat-context.ts"],"names":[],"mappings":"AAuBA,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,GAAG,IAAI,CAAA;AAC5C,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAA;AAEtC,MAAM,UAAU,gBAAgB,CAAC,GAAY;IAC3C,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IAChD,MAAM,CAAC,GAAG,GAAmB,CAAA;IAC7B,IAAI,CAAC,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,GAAG,CAAC;WACnE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;WAClE,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,KAAK;WACzD,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAAE,OAAO,IAAI,CAAA;IACtD,IAAI,CAAC,CAAC,UAAU,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,IAAI,OAAO,CAAC,CAAC,UAAU,CAAC,UAAU,KAAK,QAAQ;WACrF,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,MAAM,IAAI,OAAO,CAAC,CAAC,UAAU,CAAC,MAAM,KAAK,SAAS,CAAC;QAAE,OAAO,IAAI,CAAA;IACtG,IAAI,CAAC,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IAC3G,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO;QACrK,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;AAC5G,CAAC;AAED,SAAS,SAAS,CAAC,IAAc;IAC/B,IAAI,IAAI,CAAC,eAAe;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM;YACvF,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,yCAAyC,EAAE,CAAA;IAC9F,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE;QACjG,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAA;AAC5E,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,aAAa,CAAC,KAA0B,EAAE,OAAO,GAAG,YAAY;IAC9E,IAAI,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,CAAA;IAC7C,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,CAAA;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;QAClH,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE;YAAE,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;IACnG,CAAC;IACD,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;AAC3C,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,IAAY,EAAE,OAAe,EAAE,OAAe;IAC3F,OAAO,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AACnG,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,kBAAkB,CAAC,KAA0B,EAAE,QAAiB;IAC9E,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;IAC5C,IAAI,KAAK,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAA;IACtC,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC;QAAE,KAAK,GAAG,IAAI,CAAA;IAC9H,MAAM,KAAK,GAAG,KAAK,EAAE,OAAO,IAAI,CAAC,CAAA;IACjC,MAAM,SAAS,GAAmB,EAAE,CAAA;IACpC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC9B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC;YAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAA;YACnD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAAC,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;YAAC,CAAC;QACxG,CAAC;IACH,CAAC,CAAC,CAAA;IACF,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,CAAA;AAC9G,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,GAAG;YAAE,KAAK,EAAE,CAAA;IAC5E,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,KAAK,CAAA;AACnD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,UAAkB,EAAE,MAAe,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,GAAG,IAAI;IAC5F,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,UAAU,CAAA;IACzE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,CAAC,CAAA;AAChF,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,mBAAmB,CAAC,KAA0B,EAAE,MAAc,EAAE,KAA8B;IAC5G,IAAI,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,SAAS,IAAI,MAAM;YAAE,OAAO,CAAC,GAAG,CAAC,CAAA;IACpF,CAAC;IACD,OAAO,CAAC,CAAC,CAAA;AACX,CAAC"}
|