dsh-mobile 0.2.0 → 0.2.2

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/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  Notable changes to DSH Mobile are recorded here. GitHub Releases remain the source for downloadable packages and complete generated commit notes.
4
4
 
5
+ ## 0.2.2 - 2026-08-27
6
+
7
+ - Detect LAN and remote pairing links automatically after a QR scan, independent of the currently selected connection page.
8
+ - Clarify QR, network, firewall, certificate, and pairing failures so users can identify the shortest recovery path.
9
+
10
+ ## 0.2.1 - 2026-08-25
11
+
12
+ - Add a stable Android app download entry to the desktop Mobile Access panel.
13
+
5
14
  ## 0.2.0 - 2026-08-24
6
15
 
7
16
  - Add independent LAN and remote access flows with separate paired-device stores.
package/README.en.md CHANGED
@@ -16,13 +16,13 @@
16
16
 
17
17
  <p align="center"><a href="README.md">简体中文</a> · <a href="CHANGELOG.md">Changelog</a></p>
18
18
 
19
- > DSH Mobile 0.2.0 is a DeepSeek Harness community plugin for the DeepSeek Harness 0.1.1 series (verified with 0.1.1-rc.2); the native app supports Android only.
19
+ > DSH Mobile 0.2.2 is a DeepSeek Harness community plugin for the DeepSeek Harness 0.1.1 series (verified with 0.1.1-rc.2); the native app supports Android only.
20
20
  >
21
- > **0.2.0 update**: adds optional remote access and improves mobile loading performance.
21
+ > **0.2.2 update**: pairing scans now select the LAN or remote path automatically, with clearer QR, network, firewall, certificate, and pairing errors for faster connection troubleshooting.
22
22
  >
23
- > Upgrading the app from 0.1.3 or earlier requires one uninstall and re-pair; older app builds can still use the 0.2.0 LAN path.
23
+ > Upgrading the app from 0.1.3 or earlier requires one uninstall and re-pair; older app builds can still use the 0.2.2 LAN path.
24
24
 
25
- <p align="center"><a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.2.0/dsh-mobile-android-v0.2.0.apk"><strong>Download Android app 0.2.0</strong></a> · <a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.2.0">Release notes and checksums</a></p>
25
+ <p align="center"><a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.2.2/dsh-mobile-android-v0.2.2.apk"><strong>Download Android app 0.2.2</strong></a> · <a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.2.2">Release notes and checksums</a></p>
26
26
 
27
27
  DSH Mobile is a DeepSeek Harness plugin that lets a mobile browser or the Android app connect over a protected LAN or an optional Tailscale Funnel or cpolar remote path. Local and remote access keep the same sessions, Workspaces, messages, and tools while using separate switches and paired-device stores without modifying DeepSeek Harness source.
28
28
 
@@ -127,6 +127,8 @@ It can also drive computer capabilities the phone can use, like reading the mach
127
127
 
128
128
  Two kinds of changes are supported: the phone UI itself (theme, layout, buttons), and computer capabilities the phone can use (browsing computer files, running programs on the computer). `/mobile` hands the request to the DSH agent, which edits files under the local DSH configuration directory (`$DSH_HOME/mobile-access/`); the phone client applies them automatically. UI changes live in `mobile.css`/`mobile.js`. Computer capabilities come from extensions under `extensions/`, whose `host.mjs` runs with the local user's privileges on the computer. DeepSeek Harness source is not modified.
129
129
 
130
+ <sub>You can even use an extension to connect to SillyTavern running on the same computer, give it a lightweight mobile frontend, and open it from the same app.</sub>
131
+
130
132
  > `host.mjs` has the same privileges as a local program. Create and run only computer-side extensions that you understand and trust.
131
133
 
132
134
  The examples above, applied:
@@ -174,6 +176,8 @@ See [SECURITY.md](SECURITY.md).
174
176
 
175
177
  | DSH Mobile | Verified DeepSeek Harness releases |
176
178
  | --- | --- |
179
+ | `0.2.2` | `0.1.0-rc.5`, `0.1.0-rc.6`, `0.1.0-rc.7`, `0.1.1-rc.2` |
180
+ | `0.2.1` | `0.1.0-rc.5`, `0.1.0-rc.6`, `0.1.0-rc.7`, `0.1.1-rc.2` |
177
181
  | `0.2.0` | `0.1.0-rc.5`, `0.1.0-rc.6`, `0.1.0-rc.7`, `0.1.1-rc.2` |
178
182
  | `0.1.4` | `0.1.0-rc.5`, `0.1.0-rc.6`, `0.1.0-rc.7`, `0.1.1-rc.2` |
179
183
 
package/README.md CHANGED
@@ -23,13 +23,13 @@
23
23
  <a href="README.en.md">English</a>
24
24
  </p>
25
25
 
26
- > DSH Mobile 0.2.0 是 DeepSeek Harness 社区插件,适配 DeepSeek Harness 0.1.1 系列(已验证 0.1.1-rc.2);原生 App 仅支持 Android。
26
+ > DSH Mobile 0.2.2 是 DeepSeek Harness 社区插件,适配 DeepSeek Harness 0.1.1 系列(已验证 0.1.1-rc.2);原生 App 仅支持 Android。
27
27
  >
28
- > **0.2.0 更新**:新增可选远程访问,并优化移动端加载体验。
28
+ > **0.2.2 更新**:扫码后自动识别局域网或远程连接,并细化二维码、网络、防火墙、证书与配对错误提示,便于快速排查连接问题。
29
29
  >
30
- > 从 0.1.3 或更早 App 升级时需卸载旧版并重新配对一次;旧版 App 仍可使用 0.2.0 的局域网功能。
30
+ > 从 0.1.3 或更早 App 升级时需卸载旧版并重新配对一次;旧版 App 仍可使用 0.2.2 的局域网功能。
31
31
 
32
- <p align="center"><a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.2.0/dsh-mobile-android-v0.2.0.apk"><strong>下载 Android App 0.2.0</strong></a> · <a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.2.0">版本说明与校验文件</a></p>
32
+ <p align="center"><a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.2.2/dsh-mobile-android-v0.2.2.apk"><strong>下载 Android App 0.2.2</strong></a> · <a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.2.2">版本说明与校验文件</a></p>
33
33
 
34
34
  DSH Mobile 是一个 DeepSeek Harness 插件,让手机浏览器或 Android App 通过局域网,或可选的 Tailscale Funnel、cpolar 远程通道连接电脑,继续使用同一份会话、工作区、消息和工具。局域网与远程访问分别启停、分别管理设备,且都不修改 DeepSeek Harness 源码。
35
35
 
@@ -134,6 +134,8 @@ Tailscale Funnel 覆盖范围广,但在中国大陆网络下可能不稳定。
134
134
 
135
135
  `/mobile` 把需求交给 DSH 对话中的 agent,由它直接修改本机 `$DSH_HOME/mobile-access/` 下的文件,保存后手机端自动生效。改动分两类:界面和交互在 `mobile.css`/`mobile.js`;需要电脑能力时用 `extensions/` 下的扩展,其 `host.mjs` 以本机用户权限在电脑上运行。不修改 DeepSeek Harness 源码。
136
136
 
137
+ <sub>你甚至可以通过扩展连接电脑上运行的酒馆(</sub>
138
+
137
139
  > `host.mjs` 与本机程序拥有相同权限;仅创建和运行你理解并信任的电脑端扩展。
138
140
 
139
141
  示例的实际效果:
@@ -184,6 +186,8 @@ flowchart LR
184
186
 
185
187
  | DSH Mobile | 已验证的 DeepSeek Harness |
186
188
  | ------------ | -------------------------------------------------------- |
189
+ | `0.2.2` | `0.1.0-rc.5`、`0.1.0-rc.6`、`0.1.0-rc.7`、`0.1.1-rc.2` |
190
+ | `0.2.1` | `0.1.0-rc.5`、`0.1.0-rc.6`、`0.1.0-rc.7`、`0.1.1-rc.2` |
187
191
  | `0.2.0` | `0.1.0-rc.5`、`0.1.0-rc.6`、`0.1.0-rc.7`、`0.1.1-rc.2` |
188
192
  | `0.1.4` | `0.1.0-rc.5`、`0.1.0-rc.6`、`0.1.0-rc.7`、`0.1.1-rc.2` |
189
193
 
package/lib/client.js CHANGED
@@ -481,6 +481,12 @@ window.__ModuleLoader__.load({
481
481
  close.type = "button";
482
482
  close.textContent = "×";
483
483
  close.setAttribute("aria-label", "收起移动访问");
484
+ const appDownload = element("a", "dsh-mobile-control__app-download");
485
+ appDownload.href = "https://github.com/saya-ch/dsh-mobile/releases/latest";
486
+ appDownload.target = "_blank";
487
+ appDownload.rel = "noopener noreferrer";
488
+ appDownload.textContent = "下载 Android App";
489
+ appDownload.setAttribute("aria-label", "前往 GitHub Releases 下载最新版 Android App");
484
490
  const switcher = element("div", "dsh-mobile-control__switcher");
485
491
  const lanTab = element("button", "dsh-mobile-control__tab is-active");
486
492
  lanTab.type = "button";
@@ -726,7 +732,7 @@ window.__ModuleLoader__.load({
726
732
  actions.append(toggle, pair, linkPair);
727
733
  lanView.append(access, qrBox, status, extensionStatus, actions, manageRow, devicePanel);
728
734
  remoteView.append(remoteIntro, providerSection, cpolarSetup, tailscaleInfo, remoteAccess, remoteQr, remoteStatus, remoteGuide, remoteActions, remoteManageRow, remoteDevicePanel);
729
- panel.append(header, switcher, lanView, remoteView);
735
+ panel.append(header, appDownload, switcher, lanView, remoteView);
730
736
  root.append(panel);
731
737
  document.body.append(root);
732
738
  let running = false;
@@ -1651,6 +1657,7 @@ window.__ModuleLoader__.load({
1651
1657
  .dsh-mobile-control{position:fixed;z-index:1000;left:16px;bottom:112px;font:14px/1.45 system-ui;color:var(--dsw-alias-label-primary,#16181d)}
1652
1658
  .dsh-mobile-control__panel{box-sizing:border-box;width:min(380px,calc(100vw - 32px));max-height:calc(100vh - 140px);overflow-y:auto;padding:16px;border:1px solid var(--dsw-alias-border-subtle,#e1e5eb);border-radius:18px;background:var(--dsw-alias-bg-layer-2,#fff);box-shadow:0 18px 50px rgb(15 23 42 / 18%)}
1653
1659
  .dsh-mobile-control__header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px}.dsh-mobile-control__panel h2{margin:0;font-size:17px;line-height:24px}.dsh-mobile-control__close{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:0;border-radius:10px;background:transparent;color:inherit;font-size:24px;line-height:1;cursor:pointer}.dsh-mobile-control__close:hover{background:var(--dsw-alias-interactive-bg-hover,#f1f3f6)}
1660
+ .dsh-mobile-control__app-download{display:flex;align-items:center;justify-content:space-between;box-sizing:border-box;min-height:38px;margin:0 0 10px;padding:8px 11px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:11px;background:var(--dsw-alias-bg-layer-1,#f7f8fa);color:var(--dsw-alias-label-primary,#16181d);font:600 12px/1.3 system-ui;text-decoration:none}.dsh-mobile-control__app-download::after{color:#2563eb;font-size:14px;content:"↗"}.dsh-mobile-control__app-download:hover{border-color:#9fb9e8;background:#f5f8ff;color:#1d4ed8}
1654
1661
  .dsh-mobile-control__switcher{display:grid;grid-template-columns:1fr 1fr;gap:4px;margin:0 0 14px;padding:4px;border-radius:12px;background:var(--dsw-alias-bg-layer-1,#f3f5f8)}.dsh-mobile-control__tab{min-height:36px;border:0;border-radius:9px;background:transparent;color:var(--dsw-alias-label-secondary,#606873);font:600 13px/1 system-ui;cursor:pointer}.dsh-mobile-control__tab.is-active{background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);box-shadow:0 1px 3px rgb(15 23 42 / 10%)}.dsh-mobile-control__view[hidden]{display:none}.dsh-mobile-control__intro{margin:0 0 12px;color:var(--dsw-alias-label-secondary,#606873);font-size:12px;line-height:1.55}.dsh-mobile-control__view.is-remote .dsh-mobile-control__actions{display:grid;grid-template-columns:1fr 1fr;gap:8px}.dsh-mobile-control__view.is-remote .dsh-mobile-control__actions button[hidden]{display:none}
1655
1662
  .dsh-mobile-control__provider-section{position:relative;margin:0 0 12px}.dsh-mobile-control__section-title{margin:0 0 8px;color:var(--dsw-alias-label-primary,#16181d);font:650 13px/1.4 system-ui}.dsh-mobile-control__provider-section>.dsh-mobile-control__section-title{padding-right:42px}.dsh-mobile-control__provider-choices{display:grid;gap:8px}.dsh-mobile-control__provider{display:flex;flex-direction:column;gap:5px;min-height:68px;padding:11px 12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:#fff;color:inherit;text-align:left;cursor:pointer;transition:border-color 160ms ease,background-color 160ms ease,box-shadow 160ms ease}.dsh-mobile-control__provider:hover{border-color:#9fb9e8;background:#f8fbff}.dsh-mobile-control__provider.is-selected{border-color:#2563eb;background:#f5f8ff;box-shadow:0 0 0 1px #2563eb inset}.dsh-mobile-control__provider:disabled{cursor:wait;opacity:.62}.dsh-mobile-control__provider-top{display:flex;align-items:center;justify-content:space-between;gap:8px}.dsh-mobile-control__provider-top strong{font-size:13px}.dsh-mobile-control__provider-badge{flex:none;padding:3px 7px;border-radius:999px;background:#e8f0ff;color:#1d4ed8;font:650 10px/1.2 system-ui}.dsh-mobile-control__provider-badge.is-cpolar{background:#eaf8f2;color:#087454}.dsh-mobile-control__provider-description{color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.45}.dsh-mobile-control__provider-info{position:absolute;z-index:5;top:-13px;right:-8px}.dsh-mobile-control__provider-info-button{display:flex;align-items:center;justify-content:center;width:44px;height:44px;padding:0;border:0;border-radius:50%;background:transparent;color:#475569;cursor:pointer;touch-action:manipulation}.dsh-mobile-control__provider-info-button:hover{background:#f1f5f9;color:#1d4ed8}.dsh-mobile-control__provider-info-glyph{display:flex;align-items:center;justify-content:center;box-sizing:border-box;width:18px;height:18px;border:1.5px solid currentColor;border-radius:50%;font:700 12px/1 system-ui}.dsh-mobile-control__provider-info-popover{position:absolute;z-index:6;top:38px;right:4px;box-sizing:border-box;width:min(292px,calc(100vw - 72px));padding:10px 12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:12px;background:var(--dsw-alias-bg-layer-2,#fff);box-shadow:0 10px 28px rgb(15 23 42 / 16%)}.dsh-mobile-control__provider-info-popover[hidden]{display:none}.dsh-mobile-control__provider-info-popover strong,.dsh-mobile-control__provider-info-popover span{display:block}.dsh-mobile-control__provider-info-popover strong{margin-bottom:3px;font-size:12px}.dsh-mobile-control__provider-info-popover span{color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.55}
1656
1663
  .dsh-mobile-control__cpolar-setup{margin:0 0 12px;padding:12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:#fff}.dsh-mobile-control__cpolar-setup[hidden],.dsh-mobile-control__cpolar-account[hidden],.dsh-mobile-control__details[hidden],.dsh-mobile-control__view.is-remote .dsh-mobile-control__actions[hidden],.dsh-mobile-control__danger[hidden]{display:none}.dsh-mobile-control__component-status,.dsh-mobile-control__component-note{margin:0 0 10px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.55}.dsh-mobile-control__cpolar-setup>.dsh-mobile-control__primary{width:100%;min-height:44px;padding:9px 12px;border-radius:10px;font:600 12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__cpolar-account{margin-top:10px}.dsh-mobile-control__link-row{display:flex;flex-wrap:wrap;gap:6px 12px;margin:0 0 10px}.dsh-mobile-control__text-link{color:#2563eb;font-size:11px;text-decoration:none}.dsh-mobile-control__text-link:hover{text-decoration:underline}.dsh-mobile-control__token-label{display:flex;flex-direction:column;gap:5px;margin:0 0 8px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px}.dsh-mobile-control__token{box-sizing:border-box;width:100%;min-height:44px;padding:9px 10px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:#fff;color:inherit;font:16px/1.4 system-ui}.dsh-mobile-control__cpolar-connect{display:flex;align-items:center;justify-content:center;box-sizing:border-box;width:100%;min-height:44px;padding:10px 14px;border-radius:12px;font:650 13px/1.2 system-ui;cursor:pointer;transition:background-color 160ms ease,border-color 160ms ease,opacity 160ms ease}.dsh-mobile-control__cpolar-connect:hover:not(:disabled){border-color:#1d4ed8;background:#1d4ed8}.dsh-mobile-control__cpolar-connect:active:not(:disabled){border-color:#1e40af;background:#1e40af}.dsh-mobile-control__cpolar-connect:disabled{cursor:wait;opacity:.55}.dsh-mobile-control__details{margin:10px 0 0;border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb);padding-top:9px}.dsh-mobile-control__details>summary{min-height:30px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:30px;cursor:pointer}.dsh-mobile-control__details-body{display:flex;flex-wrap:wrap;align-items:center;gap:7px 12px;padding:4px 0}.dsh-mobile-control__details-body p{flex:1 0 100%;margin:0;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5}.dsh-mobile-control__storage{display:block;flex:1 0 100%;max-width:100%;overflow:hidden;padding:7px 8px;border-radius:8px;background:#f3f5f8;color:#475569;font:10px/1.4 ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__danger{flex:1 0 100%;min-height:38px;margin-top:3px;padding:7px 10px;border:1px solid #dc2626;border-radius:9px;background:transparent;color:#b91c1c;font:12px/1.3 system-ui;cursor:pointer}
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["createElement"],"sources":["../src/native-mobile.ts","../src/client.ts"],"sourcesContent":["/** Mobile feature and compatibility rules applied to DSH React surfaces. */\nexport const NATIVE_MOBILE_STYLES = `\n@media (max-width:720px) {\n html.dsh-native-mobile-active,html.dsh-native-mobile-active body { width:100%; height:100%; overflow:hidden; }\n html.dsh-native-mobile-active { --dsh-mobile-motion-duration:200ms; --dsh-mobile-motion-ease:cubic-bezier(.22,1,.36,1); }\n html.dsh-native-mobile-active :is(a,button,[role=\"button\"],[role=\"tab\"],[tabindex]) { -webkit-tap-highlight-color:transparent; }\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [role=\"treeitem\"] { -webkit-tap-highlight-color:transparent; touch-action:manipulation; }\n html.dsh-native-mobile-active[data-dsh-mobile-input=\"touch\"] :is(a,button,[role=\"button\"],[role=\"tab\"],[tabindex]):focus { outline:none !important; }\n html.dsh-native-mobile-active [role=\"tooltip\"] { display:none !important; }\n /* Touch has no persistent hover affordance: keep workspace rows neutral after a tap. */\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] { --dsw-alias-interactive-bg-hover:transparent !important; }\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [role=\"treeitem\"]:is(:hover,:active,:focus,[aria-selected=\"true\"]),\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [class*=\"_sessionRow\"][class*=\"_selected\"],\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [class*=\"_searchResultRow\"][class*=\"_selected\"] { background:transparent !important; outline:0 !important; box-shadow:none !important; }\n /* Sidebar row menus are hover-only on desktop. Touch has no hover, so keep\n the ellipsis action visible and give it a reliable hit target. */\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [class*=\"_rowActions\"] { display:inline-flex !important; align-items:center !important; gap:8px !important; }\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [class*=\"_sessionRow\"] [class*=\"_time\"] { display:none !important; }\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [class*=\"_rowActions\"] button { box-sizing:border-box !important; width:32px !important; min-width:32px !important; height:32px !important; min-height:32px !important; }\n [data-dsh-mobile-frame] { grid-template-columns:0 minmax(0,1fr) 0 !important; width:100% !important; height:100dvh !important; overflow:hidden !important; }\n [data-dsh-mobile-center] { grid-column:2 !important; width:100vw !important; min-width:0 !important; }\n [data-dsh-mobile-center] > * { min-width:0 !important; }\n [data-dsh-mobile-header] { box-sizing:border-box !important; width:calc(100% - 16px) !important; margin:0 8px !important; min-width:0; padding-top:max(4px,env(safe-area-inset-top)) !important; padding-right:8px !important; padding-left:42px !important; }\n [data-dsh-mobile-header] [class*=\"_titleRow\"] { box-sizing:border-box !important; display:flex !important; align-items:center !important; min-width:0; min-height:32px !important; height:32px !important; gap:6px !important; padding:0 6px !important; }\n [data-dsh-mobile-header] [class*=\"_titleCluster\"] { min-width:0; }\n [data-dsh-mobile-header] [class*=\"_crumbs\"] { min-width:0; overflow:hidden; }\n [data-dsh-mobile-header] [class*=\"_crumb\"] { max-width:46vw; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }\n [data-dsh-mobile-header] [class*=\"_headerActions\"] { min-width:0; overflow-x:auto; scrollbar-width:none; }\n [data-dsh-mobile-header] [class*=\"_headerActions\"]::-webkit-scrollbar { display:none; }\n [data-dsh-mobile-header] [class*=\"_headerUtilities\"] { gap:2px !important; }\n [data-dsh-mobile-header] [class*=\"_sessionLogButton\"] { width:40px; min-width:40px; padding:0 !important; overflow:hidden; color:transparent; font-size:0 !important; }\n [data-dsh-mobile-header] [class*=\"_sessionLogButton\"] > * { display:none !important; }\n [data-dsh-mobile-header] [class*=\"_sessionLogButton\"]::after { color:var(--dsw-text, #171a21); content:\"日志\"; font-size:11px; font-weight:600; }\n [data-dsh-mobile-header] [class*=\"_tabs\"] { box-sizing:border-box !important; width:max-content !important; max-width:calc(100% - 58px) !important; min-height:28px !important; height:28px !important; margin-top:0 !important; padding-left:6px !important; padding-right:6px !important; overflow-x:auto; scrollbar-width:none; }\n [data-dsh-mobile-header] [class*=\"_tab\"] { padding-bottom:5px !important; }\n [data-dsh-mobile-header] [class*=\"_tabs\"]::-webkit-scrollbar { display:none; }\n [data-dsh-mobile-sidebar] { position:fixed !important; z-index:240 !important; inset:0 auto 0 0 !important; width:0 !important; overflow:visible !important; }\n [data-dsh-mobile-sidebar-root] { position:fixed !important; z-index:241 !important; inset:max(env(safe-area-inset-top),0px) auto 0 0 !important; height:auto !important; transition:width 180ms var(--dsh-mobile-motion-ease),box-shadow 180ms ease !important; }\n [data-dsh-mobile-sidebar][data-open=\"true\"] [data-dsh-mobile-sidebar-root] { width:min(88vw,340px) !important; padding-top:0 !important; box-shadow:18px 0 46px rgb(15 23 42 / 18%); }\n [data-dsh-mobile-sidebar][data-open=\"true\"] [data-dsh-mobile-sidebar-root] [class*=\"_logoRow\"] { height:52px !important; padding:4px 0 4px 4px !important; margin-bottom:4px !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-sidebar-root] { width:0 !important; border:0 !important; background:transparent !important; box-shadow:none !important; overflow:visible !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-sidebar-root] > :not(:has([data-dsh-mobile-toggle])) { display:none !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-sidebar-root] > :has([data-dsh-mobile-toggle]) { position:fixed !important; z-index:244 !important; top:env(safe-area-inset-top) !important; left:0 !important; box-sizing:border-box !important; width:50px !important; height:52px !important; padding:4px !important; border:0 !important; background:transparent !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-sidebar-root] > :has([data-dsh-mobile-toggle]) > :not([data-dsh-mobile-toggle]) { display:none !important; }\n [data-dsh-mobile-toggle] { width:44px !important; height:44px !important; min-width:44px !important; min-height:44px !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-toggle] > svg[class*=\"_railFish\"] { transform:translateY(-4px) !important; }\n .dsh-native-mobile-backdrop { position:fixed; z-index:235; inset:env(safe-area-inset-top) 0 0; border:0; background:rgb(15 23 42 / 32%); }\n .dsh-native-mobile-backdrop:not([hidden]) { animation:dsh-mobile-fade-in var(--dsh-mobile-motion-duration) ease-out; }\n .dsh-native-mobile-backdrop[hidden] { display:none; }\n [data-dsh-mobile-details] { position:fixed !important; z-index:250 !important; inset:0 0 0 auto !important; width:min(94vw,460px) !important; max-width:none !important; transform:translateX(100%); transition:transform var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); background:var(--dsw-bg, #fff); box-shadow:-18px 0 46px rgb(15 23 42 / 18%); }\n [data-dsh-mobile-details][data-open=\"true\"] { transform:translateX(0); }\n [data-dsh-mobile-handle] { display:none !important; }\n [data-dsh-mobile-settings] { flex-direction:column !important; width:100vw !important; height:100dvh !important; max-width:none !important; border-radius:0 !important; animation:dsh-mobile-panel-in var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); }\n [data-dsh-mobile-settings-nav] { flex:none !important; width:100% !important; padding:max(14px,env(safe-area-inset-top)) 12px 8px !important; gap:10px !important; border-bottom:1px solid var(--dsw-alias-border-subtle,#e8ebef); }\n [data-dsh-mobile-settings-nav] [class*=\"_navTitle\"] { padding:0 8px !important; font-size:18px !important; line-height:28px !important; }\n [data-dsh-mobile-settings-list] { flex-direction:row !important; gap:4px !important; overflow-x:auto !important; scrollbar-width:none; }\n [data-dsh-mobile-settings-list]::-webkit-scrollbar { display:none; }\n [data-dsh-mobile-settings-list] [class*=\"_navCell\"] { flex:0 0 auto !important; min-width:max-content !important; height:44px !important; padding:10px 12px !important; }\n [data-dsh-mobile-settings-list] [aria-current=\"true\"] { border-color:transparent !important; outline:0 !important; box-shadow:none !important; }\n [data-dsh-mobile-settings-content] { flex:1 1 auto !important; width:100% !important; min-height:0 !important; }\n [data-dsh-mobile-settings-header] { height:48px !important; min-height:48px !important; padding:10px 12px 6px !important; }\n [data-dsh-mobile-settings-header] [class*=\"_close\"] { width:36px !important; height:36px !important; }\n [data-dsh-mobile-settings-options] { box-sizing:border-box !important; width:100% !important; padding:4px 16px max(24px,env(safe-area-inset-bottom)) !important; overflow-x:hidden !important; }\n [data-dsh-mobile-settings-options] > * { width:100% !important; min-width:0 !important; }\n [data-dsh-mobile-settings-options] [data-slot=\"settings.general.item\"] > [class*=\"_row\"] { flex-direction:column !important; align-items:stretch !important; gap:12px !important; }\n [data-dsh-mobile-settings-options] [data-slot=\"settings.general.item\"] [class*=\"_rowText\"] { width:100% !important; padding-right:0 !important; }\n [data-dsh-mobile-settings-options] [data-slot=\"settings.general.item\"] [class*=\"_selector\"] { box-sizing:border-box !important; align-self:flex-start !important; justify-content:space-between !important; min-width:0 !important; min-height:44px !important; max-width:100% !important; }\n [data-dsh-mobile-settings-options] :is(input,select,textarea,button) { max-width:100%; }\n [data-dsh-mobile-settings-options] :is(input,select,textarea) { box-sizing:border-box; width:100%; min-width:0; }\n [data-dsh-mobile-settings-options] [class*=\"_head\"] { min-width:0; flex-wrap:wrap; }\n [data-dsh-mobile-settings-content][data-dsh-mobile-view-transition=\"true\"],\n [data-dsh-mobile-view][data-dsh-mobile-view-transition=\"true\"] { animation:dsh-mobile-view-in var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); }\n [data-dsh-mobile-center] textarea { font-size:16px !important; }\n /* Markdown tables use content-sized columns. Small tables fill the phone;\n wider tables keep readable cells and scroll inside their own region. */\n [data-dsh-mobile-table-scroll] { box-sizing:border-box; width:100%; max-width:100%; overflow-x:auto; overscroll-behavior-x:contain; -webkit-overflow-scrolling:touch; }\n [data-dsh-mobile-table-scroll] table { display:table !important; width:max-content !important; min-width:100% !important; max-width:none !important; table-layout:auto !important; }\n [data-dsh-mobile-table-scroll] :is(th,td) { box-sizing:border-box; min-width:8ch; max-width:32ch; overflow-wrap:anywhere; word-break:break-word; vertical-align:top; }\n [data-dsh-mobile-center] pre { max-width:100%; overflow-x:auto; }\n [data-dsh-mobile-center] :is(img,video,canvas,svg) { max-width:100%; }\n [data-dsh-mobile-message-scroll] { box-sizing:border-box !important; width:100% !important; padding:8px 10px 20px !important; }\n [data-dsh-mobile-history-loader] { position:relative !important; min-height:1px !important; }\n [data-dsh-mobile-history-loader] button:not(:disabled) { position:absolute !important; width:1px !important; height:1px !important; margin:-1px !important; padding:0 !important; clip-path:inset(50%) !important; opacity:0 !important; overflow:hidden !important; pointer-events:none !important; }\n [data-dsh-mobile-history-loader] button:disabled { min-height:28px !important; padding:4px 12px !important; }\n [data-dsh-mobile-message-column] { box-sizing:border-box !important; width:100% !important; max-width:none !important; margin:0 !important; padding:0 !important; gap:10px !important; }\n [data-dsh-mobile-message-column] > * { width:100% !important; max-width:100% !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] { box-sizing:border-box !important; display:grid !important; grid-template-columns:16px minmax(0,1fr) !important; grid-auto-rows:auto !important; align-items:center !important; column-gap:6px !important; width:100% !important; height:auto !important; min-height:40px !important; padding:4px 0 !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > [class*=\"_leading\"] { grid-column:1 !important; grid-row:1 !important; margin-right:0 !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > [class*=\"_title\"] { grid-column:2 !important; grid-row:1 !important; min-width:0 !important; overflow:hidden !important; text-overflow:ellipsis !important; white-space:nowrap !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > :is([class*=\"_sep\"],[class*=\"_separator\"]) { display:none !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > :is([class*=\"_summary\"],[class*=\"_fileLink\"]) { grid-column:2 !important; grid-row:2 !important; width:100% !important; min-width:0 !important; max-width:100% !important; overflow:hidden !important; line-height:19px !important; text-overflow:ellipsis !important; white-space:nowrap !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > [class*=\"_summarySuffix\"] { grid-column:2 !important; grid-row:3 !important; margin-left:0 !important; }\n [data-dsh-mobile-message-column] [data-context-fields] > * { display:grid !important; grid-template-columns:minmax(72px,30%) minmax(0,1fr) !important; gap:4px 10px !important; }\n [data-dsh-mobile-message-column] [class*=\"_ioSection\"] { grid-template-columns:1fr !important; row-gap:4px !important; }\n [data-dsh-mobile-message-column] [class*=\"_body\"] { max-width:100% !important; overflow-wrap:anywhere; }\n [data-dsh-mobile-center] [data-composer-card] ~ [class*=\"_root\"],\n [data-dsh-mobile-center] [data-composer-card] ~ * [class*=\"_root\"] { box-sizing:border-box !important; width:100% !important; max-width:100% !important; margin-bottom:-6px !important; padding:3px 4px 0 !important; font-size:11px !important; line-height:18px !important; white-space:normal !important; overflow:visible !important; text-overflow:clip !important; }\n [data-dsh-mobile-center] [data-composer-card] ~ [class*=\"_root\"] [class*=\"_sep\"],\n [data-dsh-mobile-center] [data-composer-card] ~ * [class*=\"_root\"] [class*=\"_sep\"] { margin:0 6px !important; }\n /* Message runtime details are inline on desktop. Give the clock/runtime\n label its own wrapping row on narrow screens so TTFT and throughput do\n not push the action buttons or clip at the viewport edge. */\n [data-dsh-mobile-center] [class*=\"_actions\"]:has(> [class*=\"_timeStart\"]),\n [data-dsh-mobile-center] [class*=\"_actions\"]:has(> [class*=\"_timeEnd\"]) { box-sizing:border-box !important; width:100% !important; flex-wrap:wrap !important; justify-content:flex-end !important; height:auto !important; min-height:28px !important; row-gap:2px !important; }\n [data-dsh-mobile-center] [class*=\"_timeStart\"],\n [data-dsh-mobile-center] [class*=\"_timeEnd\"] { box-sizing:border-box !important; flex:1 1 100% !important; order:2 !important; min-width:0 !important; max-width:100% !important; padding:0 !important; line-height:20px !important; text-align:center !important; white-space:normal !important; overflow-wrap:anywhere !important; }\n [data-dsh-mobile-center] [class*=\"_timeStart\"] { box-sizing:border-box !important; flex:1 1 100% !important; order:2 !important; min-width:0 !important; max-width:100% !important; padding:0 !important; line-height:20px !important; text-align:center !important; white-space:normal !important; overflow-wrap:anywhere !important; }\n [data-dsh-mobile-center] [class*=\"_timeStart\"] [class*=\"_runTimeDot\"],\n [data-dsh-mobile-center] [class*=\"_timeEnd\"] [class*=\"_runTimeDot\"] { margin:0 6px !important; }\n /* Keep the context meter's legend rows as readable label/value pairs.\n Generic mobile flex rules can otherwise place the rows side by side and\n break Chinese labels in the middle of a word. */\n [data-dsh-mobile-center] [role=\"dialog\"][aria-label*=\"上下文\"],\n [data-dsh-mobile-center] [role=\"dialog\"][aria-label*=\"Context\"] { width:min(264px,calc(100vw - 32px)) !important; min-width:0 !important; max-width:calc(100vw - 32px) !important; }\n [data-dsh-mobile-center] [role=\"dialog\"][aria-label*=\"上下文\"] [class*=\"_rows\"],\n [data-dsh-mobile-center] [role=\"dialog\"][aria-label*=\"Context\"] [class*=\"_rows\"] { display:block !important; }\n [data-dsh-mobile-center] [role=\"dialog\"][aria-label*=\"上下文\"] [class*=\"_rows\"] > [class*=\"_row\"],\n [data-dsh-mobile-center] [role=\"dialog\"][aria-label*=\"Context\"] [class*=\"_rows\"] > [class*=\"_row\"] { display:flex !important; align-items:center !important; justify-content:space-between !important; width:100% !important; min-width:0 !important; white-space:nowrap !important; }\n [data-dsh-mobile-center] [role=\"dialog\"][aria-label*=\"上下文\"] :is(dt,dd),\n [data-dsh-mobile-center] [role=\"dialog\"][aria-label*=\"Context\"] :is(dt,dd) { white-space:nowrap !important; word-break:keep-all !important; }\n .dsh-mobile-branch-toast { position:fixed; z-index:300; top:max(12px,env(safe-area-inset-top)); left:50%; max-width:calc(100vw - 32px); box-sizing:border-box; padding:7px 14px; border:1px solid rgb(15 23 42 / 10%); border-radius:999px; background:rgb(15 23 42 / 92%); color:#fff; font-size:13px; line-height:20px; text-align:center; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; opacity:0; pointer-events:none; transform:translate(-50%,-8px); transition:opacity 160ms ease,transform 160ms ease; }\n .dsh-mobile-branch-toast[data-visible=\"true\"] { opacity:1; transform:translate(-50%,0); }\n [data-dsh-mobile-center] [class*=\"_composer\"] { padding-left:8px !important; padding-right:8px !important; padding-bottom:max(8px,env(safe-area-inset-bottom)) !important; }\n /* The desktop composer intentionally wraps whole toolbar groups. On a phone,\n dynamic model and status labels made that row alternate between one and\n two lines. Keep two stable columns and let only the model label shrink. */\n [data-dsh-mobile-composer-row] { display:grid !important; grid-template-columns:max-content minmax(0,1fr) !important; align-items:center !important; gap:4px 8px !important; }\n [data-dsh-mobile-composer-tools] { display:flex !important; flex-wrap:nowrap !important; width:max-content !important; min-width:0 !important; max-width:max-content !important; gap:6px !important; }\n [data-dsh-mobile-composer-trailing] { display:flex !important; flex-wrap:nowrap !important; width:100% !important; min-width:0 !important; max-width:100% !important; gap:6px !important; margin-left:0 !important; justify-content:flex-end !important; }\n [data-dsh-mobile-composer-model] { flex:1 1 0 !important; width:auto !important; min-width:0 !important; max-width:none !important; }\n [data-dsh-mobile-composer-model-trigger] { box-sizing:border-box !important; width:100% !important; max-width:100% !important; min-width:0 !important; padding-left:6px !important; padding-right:4px !important; }\n [data-dsh-mobile-composer-model-label] { flex:1 1 auto !important; max-width:none !important; min-width:0 !important; overflow:hidden !important; text-overflow:ellipsis !important; white-space:nowrap !important; }\n [data-dsh-mobile-center] [class*=\"_root\"]:has(> [class*=\"_card\"] textarea) { box-sizing:border-box !important; width:100% !important; padding:0 0 8px !important; }\n [data-dsh-mobile-center] [class*=\"_root\"]:has(> [class*=\"_card\"] textarea) > [class=\"\"]:last-child { display:none !important; }\n}\n@keyframes dsh-mobile-fade-in { from { opacity:0; } }\n@keyframes dsh-mobile-panel-in { from { opacity:.72; transform:translateY(6px); } }\n@keyframes dsh-mobile-view-in { from { opacity:.58; transform:translateY(5px); } }\n@media (max-width:420px) {\n [data-dsh-mobile-header] [class*=\"_headerActions\"] { max-width:42vw; }\n [data-dsh-mobile-settings-options] [data-slot=\"settings.general.item\"] [class*=\"_selector\"] { align-self:stretch !important; width:100% !important; }\n [data-dsh-mobile-message-column] [data-context-fields] > * { grid-template-columns:1fr !important; }\n}\n@media (prefers-reduced-motion:reduce) {\n [data-dsh-mobile-sidebar-root],[data-dsh-mobile-details] { transition:none !important; }\n .dsh-native-mobile-backdrop:not([hidden]),[data-dsh-mobile-settings],\n [data-dsh-mobile-settings-content][data-dsh-mobile-view-transition=\"true\"],\n [data-dsh-mobile-view][data-dsh-mobile-view-transition=\"true\"] { animation:none !important; }\n}\n`\n\nfunction classToken(element: Element, suffix: string): boolean {\n return Array.from(element.classList).some(value => value.endsWith(suffix))\n}\n\nfunction firstByClassSuffix(root: ParentNode, suffix: string): HTMLElement | undefined {\n return Array.from(root.querySelectorAll<HTMLElement>('[class]')).find(element => classToken(element, suffix))\n}\n\nconst AUTO_HISTORY_THRESHOLD_PX = 64\n\n/** Whether a user-driven scroll moved upward into the automatic history-loading zone. */\nexport function shouldAutoLoadEarlier(previousTop: number, currentTop: number): boolean {\n return currentTop <= AUTO_HISTORY_THRESHOLD_PX && currentTop < previousTop - 0.5\n}\n\n/** Add mobile semantics without replacing feature trees. */\nexport function installNativeMobileSurface(): () => void {\n document.documentElement.classList.add('dsh-native-mobile-active')\n const setInputMode = (mode: 'keyboard' | 'touch'): void => {\n document.documentElement.dataset.dshMobileInput = mode\n }\n const onPointerDown = (event: PointerEvent): void => {\n if (event.pointerType === 'touch' || event.pointerType === 'pen') setInputMode('touch')\n }\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Tab' || event.key.startsWith('Arrow')) setInputMode('keyboard')\n }\n document.addEventListener('pointerdown', onPointerDown, true)\n document.addEventListener('keydown', onKeyDown, true)\n const backdrop = document.createElement('button')\n backdrop.type = 'button'\n backdrop.className = 'dsh-native-mobile-backdrop'\n backdrop.hidden = true\n backdrop.setAttribute('aria-label', '关闭工作区导航')\n document.body.append(backdrop)\n const branchToast = document.createElement('div')\n branchToast.className = 'dsh-mobile-branch-toast'\n branchToast.setAttribute('role', 'status')\n branchToast.setAttribute('aria-live', 'polite')\n document.body.append(branchToast)\n let branchToastTimer = 0\n const showBranchToast = (): void => {\n const header = document.querySelector<HTMLElement>('[data-dsh-mobile-header]')\n const title = header === null ? undefined : header.querySelector<HTMLElement>('[class*=\"_crumbCurrent\"]')?.textContent?.trim()\n branchToast.textContent = title === undefined ? '当前分支' : `当前分支:${title}`\n branchToast.dataset.visible = 'true'\n if (branchToastTimer !== 0) window.clearTimeout(branchToastTimer)\n branchToastTimer = window.setTimeout(() => {\n branchToast.removeAttribute('data-visible')\n branchToastTimer = 0\n }, 1600)\n }\n const onBranchClick = (event: MouseEvent): void => {\n if (!(event.target instanceof Element)) return\n const branch = event.target.closest<HTMLButtonElement>('button[aria-label*=\"分支\"],button[aria-label*=\"Branch\"],button[aria-label*=\"branch\"]')\n if (branch === null || branch.hasAttribute('disabled') || branch.getAttribute('aria-disabled') === 'true') return\n window.setTimeout(showBranchToast, 80)\n }\n document.addEventListener('click', onBranchClick, true)\n let frame: HTMLElement | undefined\n let sidebar: HTMLElement | undefined\n let sidebarRoot: HTMLElement | undefined\n let toggle: HTMLButtonElement | undefined\n let viewArea: HTMLElement | undefined\n let scheduled = 0\n let transitionFrame = 0\n let transitionRestartFrame = 0\n let transitionTimer = 0\n let transitionTarget: HTMLElement | undefined\n let historyScroller: HTMLElement | undefined\n let historyPreviousTop = 0\n const historyLoadButton = (): HTMLButtonElement | undefined => {\n const loader = historyScroller === undefined ? undefined : firstByClassSuffix(historyScroller, '_older')\n return loader?.querySelector<HTMLButtonElement>('button') ?? undefined\n }\n const onHistoryScroll = (): void => {\n if (historyScroller === undefined) return\n const currentTop = Math.max(0, historyScroller.scrollTop)\n const shouldLoad = shouldAutoLoadEarlier(historyPreviousTop, currentTop)\n historyPreviousTop = currentTop\n if (!shouldLoad) return\n const button = historyLoadButton()\n if (button === undefined || button.disabled || button.getAttribute('aria-disabled') === 'true') return\n button.click()\n }\n const bindHistoryScroller = (next: HTMLElement | undefined): void => {\n if (historyScroller === next) return\n historyScroller?.removeEventListener('scroll', onHistoryScroll)\n historyScroller = next\n historyPreviousTop = next?.scrollTop ?? 0\n historyScroller?.addEventListener('scroll', onHistoryScroll, { passive: true })\n }\n const animateNavigation = (event: MouseEvent): void => {\n if (!(event.target instanceof Element)) return\n const trigger = event.target.closest<HTMLElement>('button,a,[role=\"tab\"],[aria-selected]')\n if (trigger === null || trigger.hasAttribute('disabled') || trigger.getAttribute('aria-disabled') === 'true') return\n if (trigger.getAttribute('aria-selected') === 'true' || trigger.getAttribute('aria-current') === 'true') return\n const settingsNavigation = trigger.closest('[data-dsh-mobile-settings-list]') !== null\n const conversationNavigation = trigger.matches('[role=\"tab\"]')\n const sidebarNavigation = trigger.closest('[data-dsh-mobile-sidebar-root]') !== null\n && trigger.closest('[data-dsh-mobile-toggle]') === null\n if (!settingsNavigation && !conversationNavigation && !sidebarNavigation) return\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return\n if (transitionFrame !== 0) cancelAnimationFrame(transitionFrame)\n if (transitionRestartFrame !== 0) cancelAnimationFrame(transitionRestartFrame)\n transitionFrame = requestAnimationFrame(() => {\n transitionFrame = 0\n const target = settingsNavigation\n ? document.querySelector<HTMLElement>('[data-dsh-mobile-settings-content]')\n : viewArea\n if (target === null || target === undefined) return\n transitionTarget?.removeAttribute('data-dsh-mobile-view-transition')\n target.removeAttribute('data-dsh-mobile-view-transition')\n transitionRestartFrame = requestAnimationFrame(() => {\n transitionRestartFrame = 0\n transitionTarget = target\n target.dataset.dshMobileViewTransition = 'true'\n if (transitionTimer !== 0) clearTimeout(transitionTimer)\n transitionTimer = window.setTimeout(() => {\n target.removeAttribute('data-dsh-mobile-view-transition')\n if (transitionTarget === target) transitionTarget = undefined\n transitionTimer = 0\n }, 240)\n })\n })\n }\n document.addEventListener('click', animateNavigation)\n\n const sync = (): void => {\n scheduled = 0\n frame = firstByClassSuffix(document, '_frame')\n const dedicatedCenter = document.querySelector<HTMLElement>('.dshm-main') ?? undefined\n if (frame !== undefined) frame.dataset.dshMobileFrame = 'true'\n sidebar = frame === undefined\n ? document.querySelector<HTMLElement>('.dshm-drawer') ?? undefined\n : firstByClassSuffix(frame, '_sidebarCol')\n const center = frame === undefined ? dedicatedCenter : firstByClassSuffix(frame, '_centerCol')\n const details = frame === undefined ? undefined : firstByClassSuffix(frame, '_detailsCol')\n const handle = frame === undefined ? undefined : firstByClassSuffix(frame, '_handle')\n if (center === undefined) {\n bindHistoryScroller(undefined)\n return\n }\n if (center !== undefined) {\n center.dataset.dshMobileCenter = 'true'\n center.querySelector<HTMLElement>('header')?.setAttribute('data-dsh-mobile-header', 'true')\n viewArea = firstByClassSuffix(center, '_viewArea')\n if (viewArea !== undefined) viewArea.dataset.dshMobileView = 'true'\n const conversation = center.querySelector<HTMLElement>('[data-conversation-scroll]')\n bindHistoryScroller(conversation ?? undefined)\n const historyLoader = conversation === null ? undefined : firstByClassSuffix(conversation, '_older')\n if (historyLoader !== undefined) {\n historyLoader.dataset.dshMobileHistoryLoader = 'true'\n historyLoader.setAttribute('aria-live', 'polite')\n const button = historyLoader.querySelector<HTMLButtonElement>('button')\n if (button !== null) {\n button.tabIndex = -1\n if (button.disabled) button.removeAttribute('aria-hidden')\n else button.setAttribute('aria-hidden', 'true')\n }\n }\n const messageColumn = conversation === null ? undefined : firstByClassSuffix(conversation, '_column')\n const messageScroll = messageColumn?.parentElement\n if (messageColumn !== undefined && messageScroll !== null && messageScroll !== undefined && classToken(messageScroll, '_scroll')) {\n messageColumn.dataset.dshMobileMessageColumn = 'true'\n messageScroll.dataset.dshMobileMessageScroll = 'true'\n }\n for (const table of center.querySelectorAll<HTMLTableElement>('table')) {\n const parent = table.parentElement\n if (parent?.dataset.dshMobileTableScroll === 'true') continue\n const wrapper = document.createElement('div')\n wrapper.dataset.dshMobileTableScroll = 'true'\n table.before(wrapper)\n wrapper.append(table)\n }\n const composerCard = center.querySelector<HTMLElement>('[data-composer-card]')\n const composerRow = composerCard?.querySelector<HTMLElement>(':scope > [data-input-scroll]')?.nextElementSibling\n if (composerRow instanceof HTMLElement) {\n composerRow.dataset.dshMobileComposerRow = 'true'\n const groups = Array.from(composerRow.children).filter((child): child is HTMLElement => child instanceof HTMLElement)\n const composerTools = groups[0]\n const composerTrailing = groups.at(-1)\n if (composerTools !== undefined) composerTools.dataset.dshMobileComposerTools = 'true'\n if (composerTrailing !== undefined && composerTrailing !== composerTools) {\n composerTrailing.dataset.dshMobileComposerTrailing = 'true'\n const modelTrigger = composerTrailing.querySelector<HTMLButtonElement>('button[aria-label^=\"选择模型\"],button[aria-label^=\"Select model\"]')\n if (modelTrigger !== null) {\n modelTrigger.dataset.dshMobileComposerModelTrigger = 'true'\n modelTrigger.parentElement?.setAttribute('data-dsh-mobile-composer-model', 'true')\n modelTrigger.querySelector<HTMLElement>('[class*=\"_triggerLabel\"]')?.setAttribute('data-dsh-mobile-composer-model-label', 'true')\n }\n }\n }\n }\n if (handle !== undefined) handle.dataset.dshMobileHandle = 'true'\n if (details !== undefined) {\n details.dataset.dshMobileDetails = 'true'\n const lastColumn = frame?.style.gridTemplateColumns.trim().split(/\\s+/).at(-1)\n details.dataset.open = String(lastColumn !== undefined && lastColumn !== '0px' && lastColumn !== '0')\n }\n const settings = Array.from(document.querySelectorAll<HTMLElement>('[role=\"dialog\"]')).find(dialog => {\n const directNav = Array.from(dialog.children).find(child => child instanceof HTMLElement && classToken(child, '_nav'))\n return directNav !== undefined\n })\n if (settings !== undefined) {\n settings.dataset.dshMobileSettings = 'true'\n const nav = Array.from(settings.children).find(child => child instanceof HTMLElement && classToken(child, '_nav')) as HTMLElement | undefined\n const content = Array.from(settings.children).find(child => child instanceof HTMLElement && classToken(child, '_content')) as HTMLElement | undefined\n if (nav !== undefined) {\n nav.dataset.dshMobileSettingsNav = 'true'\n firstByClassSuffix(nav, '_navList')?.setAttribute('data-dsh-mobile-settings-list', 'true')\n }\n if (content !== undefined) {\n content.dataset.dshMobileSettingsContent = 'true'\n firstByClassSuffix(content, '_header')?.setAttribute('data-dsh-mobile-settings-header', 'true')\n firstByClassSuffix(content, '_options')?.setAttribute('data-dsh-mobile-settings-options', 'true')\n }\n }\n if (sidebar === undefined) return\n sidebar.dataset.dshMobileSidebar = 'true'\n toggle = firstByClassSuffix(sidebar, '_toggle') as HTMLButtonElement | undefined\n let candidate = toggle?.parentElement\n while (candidate !== undefined && candidate !== null && candidate !== sidebar && !classToken(candidate, '_root')) candidate = candidate.parentElement\n sidebarRoot = candidate !== sidebar && candidate !== null ? candidate : undefined\n if (sidebarRoot === undefined) return\n sidebarRoot.dataset.dshMobileSidebarRoot = 'true'\n for (const brand of sidebarRoot.querySelectorAll<HTMLElement>('[class*=\"_fallbackBrandName\"]')) {\n if (brand.textContent?.trim() === 'DSH Local Build') brand.textContent = 'DeepSeek Harness'\n }\n if (toggle !== undefined) toggle.dataset.dshMobileToggle = 'true'\n const collapsed = classToken(sidebarRoot, '_collapsed')\n sidebar.dataset.open = String(!collapsed)\n backdrop.hidden = collapsed\n }\n const schedule = (): void => { if (scheduled === 0) scheduled = requestAnimationFrame(sync) }\n const observer = new MutationObserver(schedule)\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'style', 'disabled'] })\n backdrop.addEventListener('click', () => { if (sidebar?.dataset.open === 'true') toggle?.click() })\n sync()\n return () => {\n observer.disconnect()\n document.removeEventListener('click', onBranchClick, true)\n if (branchToastTimer !== 0) window.clearTimeout(branchToastTimer)\n branchToast.remove()\n if (scheduled !== 0) cancelAnimationFrame(scheduled)\n if (transitionFrame !== 0) cancelAnimationFrame(transitionFrame)\n if (transitionRestartFrame !== 0) cancelAnimationFrame(transitionRestartFrame)\n if (transitionTimer !== 0) clearTimeout(transitionTimer)\n transitionTarget?.removeAttribute('data-dsh-mobile-view-transition')\n historyScroller?.removeEventListener('scroll', onHistoryScroll)\n document.removeEventListener('pointerdown', onPointerDown, true)\n document.removeEventListener('keydown', onKeyDown, true)\n document.removeEventListener('click', animateNavigation)\n backdrop.remove()\n document.documentElement.classList.remove('dsh-native-mobile-active')\n delete document.documentElement.dataset.dshMobileInput\n }\n}\n","import { createElement } from 'react'\nimport { installNativeMobileSurface, NATIVE_MOBILE_STYLES } from './native-mobile.js'\n\ninterface ClientContext {\n effect(effect: () => void | (() => void), label?: string): void\n get(name: 'connection'): MobileConnectionHandle\n slots: {\n inject(key: string, callback: () => (() => void)): () => void\n register(options: { name: string; id: string }, component: (props: { wide: boolean }) => unknown): () => void\n }\n}\n\ninterface MobileConnectionHandle {\n isLoopback: boolean\n}\n\ninterface MobileExtensionContext {\n readonly document: Document\n readonly request: (path: string, init?: RequestInit) => Promise<Response>\n readonly root: HTMLElement\n readonly window: Window\n}\n\ntype MobileExtensionMount = (context: MobileExtensionContext) => void | (() => void)\ntype MobileSurfacePlacement = 'page' | 'sidebar-action' | 'header-action' | 'composer-dock' | 'settings-section' | 'overlay'\ninterface MobileSurface {\n readonly id: string\n readonly placement: MobileSurfacePlacement\n readonly label: string\n mount(container: HTMLElement): void | (() => void)\n}\ninterface MobileClientApi {\n readonly host: {\n invoke(action: string, input: unknown): Promise<unknown>\n fetch(path: string, init?: RequestInit): Promise<Response>\n }\n readonly ui: {\n registerSurface(surface: MobileSurface): () => void\n open(surfaceId: string): void\n close(surfaceId: string): void\n toast(message: string): void\n }\n readonly native: {\n capabilities(): Promise<readonly string[]>\n invoke(action: string, input?: unknown): Promise<unknown>\n }\n readonly signal: AbortSignal\n readonly document: Document\n readonly window: Window\n}\ninterface MobileClientDefinition {\n readonly apiVersion: 1\n readonly id: string\n activate(api: MobileClientApi): void | (() => void) | Promise<void | (() => void)>\n}\n\ndeclare global {\n interface Window {\n dshMobile?: {\n register(mount: MobileExtensionMount): void\n define(definition: MobileClientDefinition): void\n }\n __DSH_MOBILE_FRONTEND__?: 'dedicated'\n __DSH_MOBILE_NATIVE__?: {\n capabilities(): Promise<readonly string[]> | readonly string[]\n invoke(action: string, input?: unknown): Promise<unknown>\n }\n }\n}\n\nconst queuedDefinitions: MobileClientDefinition[] = []\nlet queuedLegacyMount: MobileExtensionMount | undefined\nif (typeof window !== 'undefined' && window.dshMobile === undefined) {\n window.dshMobile = {\n register: mount => { queuedLegacyMount = mount },\n define: definition => { queuedDefinitions.push(definition) },\n }\n}\n\nfunction isLoopbackHost(hostname: string): boolean {\n return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1' || hostname === '[::1]'\n}\n\n/**\n * Match DSH's client-side privilege hint to the authenticated mobile gateway.\n * The gateway authenticates the paired device and forwards allowed requests to\n * DSH's loopback listener, so settings RPCs receive the same Host-side checks\n * as the desktop page even though the phone's visible URL is a LAN address.\n */\nexport function trustAuthenticatedGatewayConnection(connection: MobileConnectionHandle): () => void {\n const previous = connection.isLoopback\n connection.isLoopback = true\n return () => { connection.isLoopback = previous }\n}\n\nfunction element<K extends keyof HTMLElementTagNameMap>(tag: K, className?: string): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag)\n if (className !== undefined) node.className = className\n return node\n}\n\nasync function requestJson(path: string, init?: RequestInit): Promise<Record<string, unknown>> {\n const response = await fetch(path, { ...init, headers: { 'content-type': 'application/json', ...init?.headers } })\n const body = await response.json() as Record<string, unknown>\n if (!response.ok) throw new Error(typeof body.error === 'string' ? body.error : `HTTP ${String(response.status)}`)\n return body\n}\n\nfunction officialFunnelSetupUrl(value: unknown): string {\n if (typeof value !== 'string' || value.length > 2048) return ''\n let url: URL\n try { url = new URL(value) } catch { return '' }\n const normalized = url.toString().replace(/\\/$/u, '')\n if (normalized === 'https://tailscale.com/s/no-funnel' || normalized === 'https://tailscale.com/s/https') return normalized\n if (url.protocol !== 'https:' || url.hostname !== 'login.tailscale.com' || url.port !== ''\n || url.username !== '' || url.password !== '') return ''\n return url.toString()\n}\n\nfunction installControl(): { remove: () => void; toggle: () => void } {\n const root = element('div', 'dsh-mobile-control')\n const panel = element('section', 'dsh-mobile-control__panel'); panel.hidden = true\n panel.setAttribute('aria-label', '移动访问')\n const header = element('header', 'dsh-mobile-control__header')\n const title = element('h2'); title.textContent = '移动访问'\n const close = element('button', 'dsh-mobile-control__close'); close.type = 'button'; close.textContent = '×'; close.setAttribute('aria-label', '收起移动访问')\n const switcher = element('div', 'dsh-mobile-control__switcher')\n const lanTab = element('button', 'dsh-mobile-control__tab is-active'); lanTab.type = 'button'; lanTab.textContent = '局域网'\n const remoteTab = element('button', 'dsh-mobile-control__tab'); remoteTab.type = 'button'; remoteTab.textContent = '远程'\n lanTab.setAttribute('aria-pressed', 'true'); remoteTab.setAttribute('aria-pressed', 'false'); switcher.append(lanTab, remoteTab)\n const lanView = element('div', 'dsh-mobile-control__view')\n const access = element('div', 'dsh-mobile-control__access'); access.hidden = true\n const accessLabel = element('span', 'dsh-mobile-control__access-label'); accessLabel.textContent = '浏览器访问'\n const accessLink = element('a', 'dsh-mobile-control__access-link'); accessLink.target = '_blank'; accessLink.rel = 'noreferrer'\n access.append(accessLabel, accessLink)\n const qrBox = element('div', 'dsh-mobile-control__qr'); qrBox.hidden = true\n const status = element('p', 'dsh-mobile-control__status'); status.textContent = '正在读取状态…'\n const extensionStatus = element('p', 'dsh-mobile-control__extensions'); extensionStatus.hidden = true\n const actions = element('div', 'dsh-mobile-control__actions')\n const toggle = element('button', 'dsh-mobile-control__secondary'); toggle.type = 'button'\n const pair = element('button', 'dsh-mobile-control__primary'); pair.type = 'button'; pair.textContent = '生成并复制密钥'\n const linkPair = element('button', 'dsh-mobile-control__secondary'); linkPair.type = 'button'; linkPair.textContent = '复制配对链接'\n const manageRow = element('div', 'dsh-mobile-control__manage-row')\n const manageDevices = element('button', 'dsh-mobile-control__manage'); manageDevices.type = 'button'; manageDevices.textContent = '管理配对设备'\n const resetAll = element('button', 'dsh-mobile-control__manage'); resetAll.type = 'button'; resetAll.textContent = '清除所有设备'\n manageRow.append(manageDevices, resetAll)\n const devicePanel = element('div', 'dsh-mobile-control__devices'); devicePanel.hidden = true\n const remoteView = element('div', 'dsh-mobile-control__view is-remote'); remoteView.hidden = true\n const remoteIntro = element('p', 'dsh-mobile-control__intro'); remoteIntro.textContent = '选择更适合你的远程通道。切换或关闭远程访问不会影响局域网。'\n const providerSection = element('section', 'dsh-mobile-control__provider-section')\n const providerHeading = element('h3', 'dsh-mobile-control__section-title'); providerHeading.textContent = '选择连接方式'\n const providerInfo = element('div', 'dsh-mobile-control__provider-info')\n const providerInfoButton = element('button', 'dsh-mobile-control__provider-info-button'); providerInfoButton.type = 'button'; providerInfoButton.setAttribute('aria-label', '查看远程连接安全与网络说明'); providerInfoButton.setAttribute('aria-expanded', 'false'); providerInfoButton.setAttribute('aria-controls', 'dsh-mobile-provider-info'); providerInfoButton.setAttribute('aria-describedby', 'dsh-mobile-provider-info')\n const providerInfoGlyph = element('span', 'dsh-mobile-control__provider-info-glyph'); providerInfoGlyph.textContent = 'i'; providerInfoGlyph.setAttribute('aria-hidden', 'true')\n const providerInfoPopover = element('div', 'dsh-mobile-control__provider-info-popover'); providerInfoPopover.id = 'dsh-mobile-provider-info'; providerInfoPopover.setAttribute('role', 'tooltip'); providerInfoPopover.hidden = true\n const providerInfoTitle = element('strong'); providerInfoTitle.textContent = '你始终可以放心'\n const providerInfoText = element('span'); providerInfoText.textContent = '只有已配对设备能进入 DSH。cpolar 按需安装并可彻底清理;Tailscale 在中国大陆网络下可能连接缓慢、中断或无法使用,国内网络建议优先尝试 cpolar。'\n providerInfoButton.append(providerInfoGlyph); providerInfoPopover.append(providerInfoTitle, providerInfoText); providerInfo.append(providerInfoButton, providerInfoPopover)\n const providerChoices = element('div', 'dsh-mobile-control__provider-choices'); providerChoices.setAttribute('role', 'radiogroup'); providerChoices.setAttribute('aria-label', '远程连接方式')\n const tailscaleChoice = element('button', 'dsh-mobile-control__provider'); tailscaleChoice.type = 'button'; tailscaleChoice.setAttribute('role', 'radio'); tailscaleChoice.setAttribute('aria-checked', 'true')\n const tailscaleChoiceTop = element('span', 'dsh-mobile-control__provider-top')\n const tailscaleChoiceName = element('strong'); tailscaleChoiceName.textContent = 'Tailscale Funnel'\n const tailscaleChoiceBadge = element('span', 'dsh-mobile-control__provider-badge'); tailscaleChoiceBadge.textContent = '内置'\n const tailscaleChoiceDescription = element('span', 'dsh-mobile-control__provider-description'); tailscaleChoiceDescription.textContent = '覆盖更广;中国大陆网络可能不稳定,首次需登录并允许 Funnel。'\n tailscaleChoiceTop.append(tailscaleChoiceName, tailscaleChoiceBadge); tailscaleChoice.append(tailscaleChoiceTop, tailscaleChoiceDescription)\n const cpolarChoice = element('button', 'dsh-mobile-control__provider'); cpolarChoice.type = 'button'; cpolarChoice.setAttribute('role', 'radio'); cpolarChoice.setAttribute('aria-checked', 'false')\n const cpolarChoiceTop = element('span', 'dsh-mobile-control__provider-top')\n const cpolarChoiceName = element('strong'); cpolarChoiceName.textContent = 'cpolar'\n const cpolarChoiceBadge = element('span', 'dsh-mobile-control__provider-badge is-cpolar'); cpolarChoiceBadge.textContent = '国内网络优先'\n const cpolarChoiceDescription = element('span', 'dsh-mobile-control__provider-description'); cpolarChoiceDescription.textContent = '按需安装官方组件,适合国内网络环境。'\n cpolarChoiceTop.append(cpolarChoiceName, cpolarChoiceBadge); cpolarChoice.append(cpolarChoiceTop, cpolarChoiceDescription)\n providerChoices.append(tailscaleChoice, cpolarChoice); providerSection.append(providerHeading, providerInfo, providerChoices)\n const cpolarSetup = element('section', 'dsh-mobile-control__cpolar-setup'); cpolarSetup.hidden = true\n const cpolarSetupTitle = element('h3', 'dsh-mobile-control__section-title'); cpolarSetupTitle.textContent = '准备 cpolar'\n const cpolarComponentStatus = element('p', 'dsh-mobile-control__component-status'); cpolarComponentStatus.textContent = '正在检查组件…'\n const cpolarInstall = element('button', 'dsh-mobile-control__primary'); cpolarInstall.type = 'button'; cpolarInstall.textContent = '安装官方组件'\n const cpolarAccount = element('div', 'dsh-mobile-control__cpolar-account'); cpolarAccount.hidden = true\n const cpolarAccountText = element('p', 'dsh-mobile-control__component-note'); cpolarAccountText.textContent = '登录 cpolar 官网后复制 Authtoken。令牌只保存在本机插件私有目录,不会显示在页面或日志中。'\n const cpolarAccountLinks = element('div', 'dsh-mobile-control__link-row')\n const cpolarSignup = element('a', 'dsh-mobile-control__text-link'); cpolarSignup.href = 'https://dashboard.cpolar.com/signup'; cpolarSignup.target = '_blank'; cpolarSignup.rel = 'noopener noreferrer'; cpolarSignup.textContent = '注册 cpolar'\n const cpolarDashboard = element('a', 'dsh-mobile-control__text-link'); cpolarDashboard.href = 'https://dashboard.cpolar.com/auth'; cpolarDashboard.target = '_blank'; cpolarDashboard.rel = 'noopener noreferrer'; cpolarDashboard.textContent = '打开控制台获取令牌'\n cpolarAccountLinks.append(cpolarSignup, cpolarDashboard)\n const cpolarTokenLabel = element('label', 'dsh-mobile-control__token-label'); cpolarTokenLabel.textContent = 'Authtoken'\n const cpolarToken = element('input', 'dsh-mobile-control__token'); cpolarToken.type = 'password'; cpolarToken.autocomplete = 'off'; cpolarToken.spellcheck = false; cpolarToken.placeholder = '粘贴 cpolar Authtoken'; cpolarTokenLabel.append(cpolarToken)\n const cpolarConfigure = element('button', 'dsh-mobile-control__primary dsh-mobile-control__cpolar-connect'); cpolarConfigure.type = 'button'; cpolarConfigure.textContent = '保存并连接'\n cpolarAccount.append(cpolarAccountText, cpolarAccountLinks, cpolarTokenLabel, cpolarConfigure)\n const cpolarDetails = element('details', 'dsh-mobile-control__details')\n const cpolarDetailsSummary = element('summary'); cpolarDetailsSummary.textContent = '组件来源与清理说明'\n const cpolarDetailsBody = element('div', 'dsh-mobile-control__details-body')\n const cpolarDetailsText = element('p'); cpolarDetailsText.textContent = '仅在你点击安装后从 cpolar 官网下载并校验固定版本。不会写入系统服务、开机启动、注册表或 PATH。'\n const cpolarStorage = element('code', 'dsh-mobile-control__storage'); cpolarStorage.textContent = '插件私有目录'\n const cpolarOfficial = element('a', 'dsh-mobile-control__text-link'); cpolarOfficial.href = 'https://www.cpolar.com/download'; cpolarOfficial.target = '_blank'; cpolarOfficial.rel = 'noopener noreferrer'; cpolarOfficial.textContent = '官方下载安装页'\n const cpolarTerms = element('a', 'dsh-mobile-control__text-link'); cpolarTerms.href = 'https://www.cpolar.com/tos'; cpolarTerms.target = '_blank'; cpolarTerms.rel = 'noopener noreferrer'; cpolarTerms.textContent = '服务条款'\n const cpolarPurge = element('button', 'dsh-mobile-control__danger'); cpolarPurge.type = 'button'; cpolarPurge.textContent = '彻底移除 cpolar 组件与配置'\n cpolarDetailsBody.append(cpolarDetailsText, cpolarStorage, cpolarOfficial, cpolarTerms, cpolarPurge); cpolarDetails.append(cpolarDetailsSummary, cpolarDetailsBody)\n cpolarSetup.append(cpolarSetupTitle, cpolarComponentStatus, cpolarInstall, cpolarAccount, cpolarDetails)\n const tailscaleInfo = element('details', 'dsh-mobile-control__details')\n const tailscaleInfoSummary = element('summary'); tailscaleInfoSummary.textContent = 'Tailscale 使用说明'\n const tailscaleInfoBody = element('div', 'dsh-mobile-control__details-body')\n const tailscaleInfoText = element('p'); tailscaleInfoText.textContent = '运行组件已随插件提供。首次连接会打开 Tailscale 官方登录和 Funnel 授权页;插件不会接触你的账号密码。'\n tailscaleInfoBody.append(tailscaleInfoText); tailscaleInfo.append(tailscaleInfoSummary, tailscaleInfoBody)\n const remoteAccess = element('div', 'dsh-mobile-control__access'); remoteAccess.hidden = true\n const remoteAccessLabel = element('span', 'dsh-mobile-control__access-label'); remoteAccessLabel.textContent = '远程地址'\n const remoteAccessLink = element('a', 'dsh-mobile-control__access-link'); remoteAccessLink.target = '_blank'; remoteAccessLink.rel = 'noreferrer'; remoteAccess.append(remoteAccessLabel, remoteAccessLink)\n const remoteQr = element('div', 'dsh-mobile-control__qr'); remoteQr.hidden = true\n const remoteStatus = element('p', 'dsh-mobile-control__status'); remoteStatus.textContent = '正在读取远程状态…'; remoteStatus.setAttribute('aria-live', 'polite')\n const remoteGuide = element('section', 'dsh-mobile-control__guide'); remoteGuide.hidden = true; remoteGuide.setAttribute('aria-label', 'Tailscale Funnel 启用步骤')\n const remoteGuideTitle = element('h3', 'dsh-mobile-control__guide-title'); remoteGuideTitle.textContent = '远程访问设置 · 第 2 步'\n const remoteGuideSummary = element('p', 'dsh-mobile-control__guide-summary'); remoteGuideSummary.textContent = 'Tailscale 登录已完成。还需为这台电脑允许 Funnel,官方页面会同时启用 HTTPS。'\n const remoteGuideSteps = element('ol', 'dsh-mobile-control__guide-steps')\n for (const text of ['打开当前节点的 Tailscale 官方授权页。', '确认启用 Funnel;无需再次登录 DSH。', '返回 DSH,插件会自动检查并建立连接。']) {\n const item = element('li'); item.textContent = text; remoteGuideSteps.append(item)\n }\n const remoteGuideNote = element('p', 'dsh-mobile-control__guide-note'); remoteGuideNote.textContent = '需要使用 Owner、Admin 或 Network admin 账号。'\n const remoteGuideActions = element('div', 'dsh-mobile-control__guide-actions')\n const remoteSetup = element('button', 'dsh-mobile-control__primary'); remoteSetup.type = 'button'; remoteSetup.textContent = '继续完成 Funnel 授权'\n const remoteSetupRetry = element('button', 'dsh-mobile-control__secondary'); remoteSetupRetry.type = 'button'; remoteSetupRetry.textContent = '已完成,立即重试'\n remoteGuideActions.append(remoteSetup, remoteSetupRetry); remoteGuide.append(remoteGuideTitle, remoteGuideSummary, remoteGuideSteps, remoteGuideNote, remoteGuideActions)\n const remoteActions = element('div', 'dsh-mobile-control__actions')\n const remoteToggle = element('button', 'dsh-mobile-control__primary'); remoteToggle.type = 'button'; remoteToggle.textContent = '启用远程访问'\n const remoteLogin = element('button', 'dsh-mobile-control__primary'); remoteLogin.type = 'button'; remoteLogin.textContent = '继续登录'; remoteLogin.hidden = true\n const remoteReconnect = element('button', 'dsh-mobile-control__secondary'); remoteReconnect.type = 'button'; remoteReconnect.textContent = '重新连接'; remoteReconnect.hidden = true\n const remotePair = element('button', 'dsh-mobile-control__secondary'); remotePair.type = 'button'; remotePair.textContent = '生成远程配对二维码'; remotePair.disabled = true\n remoteActions.append(remoteToggle, remoteLogin, remoteReconnect, remotePair)\n const remoteManageRow = element('div', 'dsh-mobile-control__manage-row')\n const remoteDevices = element('button', 'dsh-mobile-control__manage'); remoteDevices.type = 'button'; remoteDevices.textContent = '管理远程设备'; remoteDevices.disabled = true\n const remoteReset = element('button', 'dsh-mobile-control__manage'); remoteReset.type = 'button'; remoteReset.textContent = '退出并清除远程登录'\n remoteManageRow.append(remoteDevices, remoteReset)\n const remoteDevicePanel = element('div', 'dsh-mobile-control__devices'); remoteDevicePanel.hidden = true\n header.append(title, close); actions.append(toggle, pair, linkPair)\n lanView.append(access, qrBox, status, extensionStatus, actions, manageRow, devicePanel)\n remoteView.append(remoteIntro, providerSection, cpolarSetup, tailscaleInfo, remoteAccess, remoteQr, remoteStatus, remoteGuide, remoteActions, remoteManageRow, remoteDevicePanel)\n panel.append(header, switcher, lanView, remoteView); root.append(panel); document.body.append(root)\n let running = false\n let origin = ''\n let remoteRunning = false\n let remoteReady = false\n let remoteProvider: 'tailscale' | 'cpolar' = 'tailscale'\n let remoteLoginUrl = ''\n let remoteSetupUrl = ''\n let remoteSetupPending = false\n let remoteSetupOpenedAt = 0\n let remoteReconnectBusy = false\n let remoteProviderBusy = false\n let cpolarInstalled = false\n let cpolarConfigured = false\n let providerInfoPinned = false\n let providerInfoHovered = false\n const syncProviderInfo = (): void => {\n const open = providerInfoPinned || providerInfoHovered || providerInfo.contains(document.activeElement)\n providerInfoPopover.hidden = !open\n providerInfoButton.setAttribute('aria-expanded', String(open))\n }\n providerInfo.addEventListener('pointerenter', () => { providerInfoHovered = true; syncProviderInfo() })\n providerInfo.addEventListener('pointerleave', () => { providerInfoHovered = false; syncProviderInfo() })\n providerInfo.addEventListener('focusin', syncProviderInfo)\n providerInfo.addEventListener('focusout', () => { window.setTimeout(syncProviderInfo, 0) })\n providerInfoButton.addEventListener('click', () => { providerInfoPinned = !providerInfoPinned; syncProviderInfo() })\n providerInfoButton.addEventListener('keydown', event => {\n if (event.key !== 'Escape') return\n providerInfoPinned = false\n providerInfoHovered = false\n providerInfoPopover.hidden = true\n providerInfoButton.setAttribute('aria-expanded', 'false')\n })\n const selectView = (remote: boolean): void => {\n lanView.hidden = remote\n remoteView.hidden = !remote\n lanTab.classList.toggle('is-active', !remote)\n remoteTab.classList.toggle('is-active', remote)\n lanTab.setAttribute('aria-pressed', String(!remote))\n remoteTab.setAttribute('aria-pressed', String(remote))\n title.textContent = remote ? '远程访问' : '局域网访问'\n }\n lanTab.addEventListener('click', () => { selectView(false) })\n remoteTab.addEventListener('click', () => { selectView(true); loadRemote() })\n const setOpen = (open: boolean): void => {\n panel.hidden = !open\n for (const trigger of document.querySelectorAll('.dsh-mobile-control__trigger')) trigger.setAttribute('aria-expanded', String(open))\n }\n const render = (data: Record<string, unknown>): void => {\n running = data.running === true\n origin = running && typeof data.origin === 'string' ? data.origin : ''\n access.hidden = origin === ''\n accessLink.href = origin\n accessLink.textContent = origin\n accessLink.title = origin\n status.classList.toggle('is-running', running)\n status.textContent = running ? '局域网访问已开启。' : '局域网访问已关闭。'\n const extensionData = data.extensions\n if (extensionData !== null && typeof extensionData === 'object') {\n const loaded = typeof (extensionData as { loaded?: unknown }).loaded === 'number' ? (extensionData as { loaded: number }).loaded : 0\n const failed = typeof (extensionData as { failed?: unknown }).failed === 'number' ? (extensionData as { failed: number }).failed : 0\n extensionStatus.hidden = false\n extensionStatus.textContent = failed === 0 ? `扩展:${String(loaded)} 个已加载` : `扩展:${String(loaded)} 个已加载,${String(failed)} 个加载失败`\n } else extensionStatus.hidden = true\n if (!running) qrBox.hidden = true\n toggle.textContent = running ? '关闭局域网访问' : '开启局域网访问'\n pair.disabled = !running\n linkPair.disabled = !running\n manageDevices.disabled = !running\n resetAll.disabled = !running\n }\n const showQr = (svg: string, target: HTMLDivElement = qrBox): void => {\n target.replaceChildren()\n if (svg === '') { target.hidden = true; return }\n const image = element('img')\n image.alt = '配对二维码'\n image.width = 176\n image.height = 176\n image.src = `data:image/svg+xml;base64,${btoa(svg)}`\n target.hidden = false\n target.append(image)\n }\n const openPairing = (target: 'key' | 'link'): void => {\n void requestJson('/api/mobile-access/lan/pairing/open', { method: 'POST', body: '{}' }).then(async data => {\n const value = target === 'key'\n ? (typeof data.appKey === 'string' ? data.appKey : '')\n : (typeof data.pairUrl === 'string' ? data.pairUrl : '')\n showQr(typeof data.qrSvg === 'string' ? data.qrSvg : '')\n if (value === '') { status.textContent = '无法生成配对密钥。'; return }\n try {\n await navigator.clipboard.writeText(value)\n status.textContent = target === 'key'\n ? '配对密钥已复制,请粘贴到 Android App。'\n : '配对链接已复制,发给手机后 App 粘贴或浏览器打开即可配对。'\n } catch {\n status.textContent = `请复制${target === 'key' ? '配对密钥' : '配对链接'}:${value}`\n status.classList.add('is-key')\n }\n }, error => { status.textContent = String(error) }).finally(() => {\n pair.disabled = !running\n linkPair.disabled = !running\n })\n }\n toggle.addEventListener('click', () => { toggle.disabled = true; void requestJson('/api/mobile-access/lan/control', { method: 'POST', body: JSON.stringify({ running: !running }) }).then(render, error => { status.textContent = String(error) }).finally(() => { toggle.disabled = false }) })\n const formatTime = (ms: unknown): string => typeof ms === 'number' ? new Date(ms).toLocaleString() : ''\n const renderDevices = (data: Record<string, unknown>): void => {\n const devices = Array.isArray(data.devices) ? data.devices as Record<string, unknown>[] : []\n devicePanel.replaceChildren()\n if (devices.length === 0) {\n const empty = element('p', 'dsh-mobile-control__device-empty'); empty.textContent = '暂无配对设备。'\n devicePanel.append(empty)\n return\n }\n for (const device of devices) {\n const row = element('div', 'dsh-mobile-control__device')\n const label = element('span', 'dsh-mobile-control__device-label')\n label.textContent = typeof device.label === 'string' ? device.label : '设备'\n const meta = element('span', 'dsh-mobile-control__device-meta'); meta.textContent = `到期 ${formatTime(device.expiresAt)}`\n const revoke = element('button', 'dsh-mobile-control__device-revoke'); revoke.type = 'button'; revoke.textContent = '撤销'\n const id = typeof device.id === 'string' ? device.id : ''\n revoke.addEventListener('click', () => {\n void requestJson('/api/mobile-access/lan/devices/revoke', { method: 'POST', body: JSON.stringify({ deviceId: id }) })\n .then(loadDevices, error => { status.textContent = String(error) })\n })\n row.append(label, meta, revoke)\n devicePanel.append(row)\n }\n }\n const loadDevices = (): void => {\n void requestJson('/api/mobile-access/lan/devices').then(renderDevices, error => { status.textContent = String(error) })\n }\n manageDevices.addEventListener('click', () => {\n const show = devicePanel.hidden\n devicePanel.hidden = !show\n if (show) loadDevices()\n })\n resetAll.addEventListener('click', () => {\n if (!window.confirm('确定要移除所有配对设备吗?此操作会立即终止已连接设备。')) return\n void requestJson('/api/mobile-access/lan/devices/reset', { method: 'POST', body: JSON.stringify({ confirm: true }) })\n .then(loadDevices, error => { status.textContent = String(error) })\n })\n const renderRemote = (data: Record<string, unknown>): void => {\n remoteRunning = data.running === true\n remoteProvider = data.provider === 'cpolar' ? 'cpolar' : 'tailscale'\n const cpolar = remoteProvider === 'cpolar'\n tailscaleChoice.classList.toggle('is-selected', !cpolar)\n cpolarChoice.classList.toggle('is-selected', cpolar)\n tailscaleChoice.setAttribute('aria-checked', String(!cpolar))\n cpolarChoice.setAttribute('aria-checked', String(cpolar))\n tailscaleChoice.disabled = remoteProviderBusy\n cpolarChoice.disabled = remoteProviderBusy\n cpolarSetup.hidden = !cpolar\n tailscaleInfo.hidden = cpolar\n remoteReset.textContent = cpolar ? '关闭并清除远程设备' : '退出并清除远程登录'\n const providers = data.providers !== null && typeof data.providers === 'object' ? data.providers as Record<string, unknown> : {}\n const cpolarProvider = providers.cpolar !== null && typeof providers.cpolar === 'object' ? providers.cpolar as Record<string, unknown> : {}\n const component = cpolarProvider.component !== null && typeof cpolarProvider.component === 'object'\n ? cpolarProvider.component as Record<string, unknown>\n : {}\n cpolarInstalled = component.installed === true\n cpolarConfigured = component.configured === true\n cpolarChoiceBadge.textContent = cpolarConfigured ? '已就绪' : cpolarInstalled ? '已安装' : '国内网络优先'\n const cpolarSupported = component.supported !== false\n const componentVersion = typeof component.version === 'string' ? component.version : ''\n const componentDownloadBytes = typeof component.downloadBytes === 'number' ? component.downloadBytes : 0\n const componentStorage = typeof component.storagePath === 'string' ? component.storagePath : 'DSH Mobile 插件私有目录'\n cpolarStorage.textContent = componentStorage\n cpolarStorage.title = componentStorage\n cpolarInstall.hidden = cpolarInstalled || !cpolarSupported\n cpolarInstall.textContent = componentDownloadBytes > 0\n ? `安装官方组件 · ${(componentDownloadBytes / 1024 / 1024).toFixed(1)} MB`\n : '安装官方组件'\n cpolarInstall.disabled = remoteProviderBusy\n cpolarAccount.hidden = !cpolarInstalled || cpolarConfigured\n cpolarConfigure.disabled = remoteProviderBusy\n cpolarPurge.hidden = !cpolarInstalled && !cpolarConfigured\n cpolarComponentStatus.textContent = !cpolarSupported\n ? '当前仅支持 Windows x64。你仍可选择内置的 Tailscale Funnel。'\n : !cpolarInstalled\n ? '尚未安装。只有点击下方按钮后,才会从 cpolar 官网下载固定版本。'\n : !cpolarConfigured\n ? `官方组件 ${componentVersion} 已校验,下一步只需保存账号令牌。`\n : `官方组件 ${componentVersion} 与本机账号配置已就绪。`\n const state = typeof data.state === 'string' ? data.state : 'error'\n const errorCode = typeof data.errorCode === 'string' ? data.errorCode : ''\n const remoteOrigin = typeof data.origin === 'string' ? data.origin : ''\n remoteLoginUrl = typeof data.loginUrl === 'string' ? data.loginUrl : ''\n const candidateSetupUrl = cpolar ? '' : officialFunnelSetupUrl(data.setupUrl)\n const fallbackSetupUrls: Record<string, string> = {\n funnel_permission_required: 'https://tailscale.com/s/no-funnel',\n funnel_https_required: 'https://tailscale.com/s/https',\n funnel_start_failed: 'https://tailscale.com/s/no-funnel',\n }\n remoteSetupUrl = candidateSetupUrl !== '' ? candidateSetupUrl : (fallbackSetupUrls[errorCode] ?? '')\n const needsFunnelSetup = state === 'error' && remoteSetupUrl !== ''\n remoteReady = remoteRunning && state === 'ready' && remoteOrigin !== ''\n remoteAccess.hidden = !remoteReady\n remoteAccessLink.href = remoteOrigin\n remoteAccessLink.textContent = remoteOrigin\n remoteAccessLink.title = remoteOrigin\n remoteStatus.classList.toggle('is-running', remoteReady)\n const labels: Record<string, string> = {\n off: '远程访问未启用。局域网访问不受影响。',\n unavailable: cpolar ? 'cpolar 尚未安装或未完成本机账号配置。' : '当前电脑缺少 Funnel 运行组件,请重新安装完整插件包。',\n starting: cpolar ? '正在连接 cpolar 国内节点…' : '正在启动 Tailscale 安全通道…',\n 'needs-login': '需要在浏览器完成一次 Tailscale 登录。插件不会读取你的密码。',\n connecting: cpolar ? '公网地址已分配,正在启动 DSH 认证网关…' : '登录完成,正在建立公开 HTTPS 地址…',\n ready: '远程访问已就绪。只有已配对设备可以进入 DSH。',\n error: '远程连接未建立。可重新连接,局域网访问仍可正常使用。',\n }\n const errorLabels: Record<string, string> = {\n funnel_permission_required: '登录已完成。请继续授权 Funnel,完成后会自动建立远程连接。',\n funnel_https_required: '登录已完成。请继续授权 Funnel,官方页面会同时启用 HTTPS。',\n funnel_start_failed: '登录已完成。请继续完成 Tailscale Funnel 的首次授权。',\n tailscale_dns_missing: 'Tailscale 暂未提供远程地址。请重新连接并确认已完成登录。',\n gateway_start_failed: '远程网关启动失败。请重新连接,局域网访问不受影响。',\n control_channel_failed: '远程组件连接中断。请重新连接。',\n cpolar_component_missing: 'cpolar 官方组件尚未安装。请先完成上方准备步骤。',\n cpolar_component_invalid: 'cpolar 组件校验失败。请彻底移除后重新安装。',\n cpolar_config_missing: 'cpolar 尚未保存账号令牌。请先完成上方准备步骤。',\n cpolar_config_invalid: 'cpolar 本机配置无效。请重新保存账号令牌。',\n cpolar_port_unavailable: '无法分配本机远程网关端口,请重试。',\n cpolar_launch_failed: 'cpolar 客户端未能启动。',\n cpolar_start_timeout: '连接 cpolar 国内节点超时,请重新连接。',\n cpolar_stopped: 'cpolar 连接已停止。',\n cpolar_exited: 'cpolar 连接意外退出,请重新连接。',\n cpolar_invalid_output: 'cpolar 返回了无法识别的状态。',\n cpolar_invalid_origin: 'cpolar 返回的公网地址未通过校验。',\n }\n remoteStatus.textContent = remoteSetupPending && needsFunnelSetup\n ? 'Tailscale 官方页面已打开。完成启用后返回 DSH,这里会自动重新连接。'\n : (state === 'error' ? (errorLabels[errorCode] ?? labels.error!) : (labels[state] ?? labels.error!))\n remoteGuide.hidden = !needsFunnelSetup\n remoteSetup.disabled = remoteSetupUrl === '' || remoteReconnectBusy\n remoteSetupRetry.disabled = remoteReconnectBusy\n remoteToggle.textContent = remoteRunning ? '关闭远程访问' : '启用远程访问'\n remoteToggle.disabled = remoteProviderBusy || (cpolar && (!cpolarInstalled || !cpolarConfigured))\n remoteLogin.hidden = cpolar || state !== 'needs-login' || remoteLoginUrl === ''\n remoteReconnect.hidden = needsFunnelSetup || (state !== 'error' && state !== 'unavailable')\n || (cpolar && (!cpolarInstalled || !cpolarConfigured))\n remoteActions.hidden = cpolar && (!cpolarInstalled || !cpolarConfigured)\n remotePair.disabled = !remoteReady\n remoteDevices.disabled = !remoteReady\n if (!remoteReady) remoteQr.hidden = true\n if (!needsFunnelSetup) remoteSetupPending = false\n }\n const loadRemote = (): void => {\n void requestJson('/api/mobile-access/remote/control').then(renderRemote, error => { remoteStatus.textContent = String(error) })\n }\n const chooseRemoteProvider = (provider: 'tailscale' | 'cpolar'): void => {\n if (remoteProviderBusy || provider === remoteProvider) return\n if (remoteRunning && !window.confirm('切换连接方式会先关闭当前远程通道。局域网和配对设备不会受影响,是否继续?')) return\n remoteProviderBusy = true\n tailscaleChoice.disabled = true\n cpolarChoice.disabled = true\n remoteStatus.textContent = provider === 'cpolar' ? '正在切换到 cpolar…' : '正在切换到 Tailscale Funnel…'\n void requestJson('/api/mobile-access/remote/provider', { method: 'POST', body: JSON.stringify({ provider }) })\n .then(renderRemote, error => { remoteStatus.textContent = String(error) })\n .finally(() => { remoteProviderBusy = false; loadRemote() })\n }\n tailscaleChoice.addEventListener('click', () => { chooseRemoteProvider('tailscale') })\n cpolarChoice.addEventListener('click', () => { chooseRemoteProvider('cpolar') })\n cpolarInstall.addEventListener('click', () => {\n if (remoteProviderBusy) return\n const accepted = window.confirm('将从 cpolar 官方网站下载并校验固定版本(约 7.3 MB),仅解压到 DSH Mobile 私有目录。不会安装系统服务、写入 PATH/注册表或设置开机启动。是否继续?')\n if (!accepted) return\n remoteProviderBusy = true\n cpolarInstall.disabled = true\n cpolarInstall.textContent = '正在下载并校验…'\n remoteStatus.textContent = '正在安装 cpolar 官方组件。完成前请保持 DSH 运行。'\n void requestJson('/api/mobile-access/remote/cpolar/component/install', { method: 'POST', body: JSON.stringify({ confirm: true }) })\n .then(renderRemote, error => { remoteStatus.textContent = `组件安装失败:${String(error)}` })\n .finally(() => { remoteProviderBusy = false; loadRemote() })\n })\n cpolarConfigure.addEventListener('click', () => {\n if (remoteProviderBusy) return\n const authtoken = cpolarToken.value.trim()\n if (authtoken.length < 20 || /\\s/u.test(authtoken)) {\n remoteStatus.textContent = '请粘贴 cpolar 控制台提供的完整 Authtoken。'\n cpolarToken.focus()\n return\n }\n remoteProviderBusy = true\n cpolarConfigure.disabled = true\n cpolarConfigure.setAttribute('aria-busy', 'true')\n cpolarConfigure.textContent = '正在保存…'\n void requestJson('/api/mobile-access/remote/cpolar/configure', { method: 'POST', body: JSON.stringify({ authtoken }) })\n .then(() => {\n cpolarToken.value = ''\n remoteStatus.textContent = '账号配置已保存,正在建立 cpolar 远程通道…'\n return requestJson('/api/mobile-access/remote/control', { method: 'POST', body: JSON.stringify({ running: true }) })\n })\n .then(renderRemote, error => { remoteStatus.textContent = `配置失败:${String(error)}` })\n .finally(() => { remoteProviderBusy = false; cpolarConfigure.setAttribute('aria-busy', 'false'); cpolarConfigure.textContent = '保存并连接'; loadRemote() })\n })\n cpolarPurge.addEventListener('click', () => {\n if (remoteProviderBusy) return\n if (!window.confirm('彻底移除 DSH Mobile 私有目录中的 cpolar 组件、令牌配置和运行日志?不会影响局域网、DSH 数据或系统中的其他程序。')) return\n remoteProviderBusy = true\n cpolarPurge.disabled = true\n remoteStatus.textContent = '正在关闭通道并清理 DSH Mobile 管理的 cpolar 文件…'\n void requestJson('/api/mobile-access/remote/cpolar/component/purge', { method: 'POST', body: JSON.stringify({ confirm: true }) })\n .then(renderRemote, error => { remoteStatus.textContent = `清理失败:${String(error)}` })\n .finally(() => { remoteProviderBusy = false; cpolarPurge.disabled = false; loadRemote() })\n })\n remoteToggle.addEventListener('click', () => {\n remoteToggle.disabled = true\n void requestJson('/api/mobile-access/remote/control', { method: 'POST', body: JSON.stringify({ running: !remoteRunning }) })\n .then(renderRemote, error => { remoteStatus.textContent = String(error) })\n .finally(loadRemote)\n })\n remoteLogin.addEventListener('click', () => {\n if (remoteLoginUrl !== '') window.open(remoteLoginUrl, '_blank', 'noopener,noreferrer')\n })\n const reconnectRemote = (): void => {\n if (remoteReconnectBusy) return\n remoteReconnectBusy = true\n remoteReconnect.disabled = true\n remoteSetup.disabled = true\n remoteSetupRetry.disabled = true\n remoteStatus.textContent = remoteProvider === 'cpolar' ? '正在重新连接 cpolar 国内节点…' : '正在确认 Tailscale 设置并重新连接…'\n void requestJson('/api/mobile-access/remote/reconnect', { method: 'POST', body: '{}' })\n .then(renderRemote, error => { remoteStatus.textContent = String(error) })\n .finally(() => {\n remoteReconnectBusy = false\n remoteReconnect.disabled = false\n remoteSetup.disabled = remoteSetupUrl === ''\n remoteSetupRetry.disabled = false\n })\n }\n remoteReconnect.addEventListener('click', reconnectRemote)\n remoteSetupRetry.addEventListener('click', () => { remoteSetupPending = false; reconnectRemote() })\n remoteSetup.addEventListener('click', () => {\n if (remoteSetupUrl === '') return\n remoteSetupPending = true\n remoteSetupOpenedAt = Date.now()\n remoteStatus.textContent = 'Tailscale 官方页面已打开。完成启用后返回 DSH,这里会自动重新连接。'\n window.open(remoteSetupUrl, '_blank', 'noopener,noreferrer')\n })\n const retryAfterSetup = (): void => {\n if (!remoteSetupPending || document.visibilityState === 'hidden' || Date.now() - remoteSetupOpenedAt < 800) return\n remoteSetupPending = false\n reconnectRemote()\n }\n window.addEventListener('focus', retryAfterSetup)\n document.addEventListener('visibilitychange', retryAfterSetup)\n remotePair.addEventListener('click', () => {\n remotePair.disabled = true\n void requestJson('/api/mobile-access/remote/pairing/open', { method: 'POST', body: '{}' }).then(async data => {\n const pairUrl = typeof data.pairUrl === 'string' ? data.pairUrl : ''\n showQr(typeof data.qrSvg === 'string' ? data.qrSvg : '', remoteQr)\n if (pairUrl !== '') {\n try { await navigator.clipboard.writeText(pairUrl) } catch { /* QR remains the primary remote handoff. */ }\n }\n remoteStatus.textContent = '远程配对二维码已生成。请在 App 的“远程访问”中扫描。'\n }, error => { remoteStatus.textContent = String(error) }).finally(() => { remotePair.disabled = !remoteReady })\n })\n const renderRemoteDevices = (data: Record<string, unknown>): void => {\n const devices = Array.isArray(data.devices) ? data.devices as Record<string, unknown>[] : []\n remoteDevicePanel.replaceChildren()\n if (devices.length === 0) {\n const empty = element('p', 'dsh-mobile-control__device-empty'); empty.textContent = '暂无远程配对设备。'; remoteDevicePanel.append(empty); return\n }\n for (const device of devices) {\n const row = element('div', 'dsh-mobile-control__device')\n const label = element('span', 'dsh-mobile-control__device-label'); label.textContent = typeof device.label === 'string' ? device.label : '设备'\n const meta = element('span', 'dsh-mobile-control__device-meta'); meta.textContent = `到期 ${formatTime(device.expiresAt)}`\n const revoke = element('button', 'dsh-mobile-control__device-revoke'); revoke.type = 'button'; revoke.textContent = '撤销'\n const id = typeof device.id === 'string' ? device.id : ''\n revoke.addEventListener('click', () => {\n void requestJson('/api/mobile-access/remote/devices/revoke', { method: 'POST', body: JSON.stringify({ deviceId: id }) })\n .then(loadRemoteDevices, error => { remoteStatus.textContent = String(error) })\n })\n row.append(label, meta, revoke); remoteDevicePanel.append(row)\n }\n }\n const loadRemoteDevices = (): void => {\n void requestJson('/api/mobile-access/remote/devices').then(renderRemoteDevices, error => { remoteStatus.textContent = String(error) })\n }\n remoteDevices.addEventListener('click', () => {\n const show = remoteDevicePanel.hidden\n remoteDevicePanel.hidden = !show\n if (show) loadRemoteDevices()\n })\n remoteReset.addEventListener('click', () => {\n const prompt = remoteProvider === 'cpolar'\n ? '关闭 cpolar 远程通道并移除所有远程配对设备?不会修改你的 cpolar 账号或其他隧道。'\n : '退出电脑上的 Tailscale 登录并移除所有远程配对设备?局域网配置不会改变。'\n if (!window.confirm(prompt)) return\n void requestJson('/api/mobile-access/remote/reset', { method: 'POST', body: JSON.stringify({ confirm: true }) })\n .then(renderRemote, error => { remoteStatus.textContent = String(error) })\n })\n pair.addEventListener('click', () => { pair.disabled = true; openPairing('key') })\n linkPair.addEventListener('click', () => { linkPair.disabled = true; openPairing('link') })\n close.addEventListener('click', () => { setOpen(false) })\n const dismiss = (event: PointerEvent): void => {\n if (panel.hidden || !(event.target instanceof Node)) return\n if (!providerInfo.contains(event.target)) {\n providerInfoPinned = false\n providerInfoHovered = false\n syncProviderInfo()\n }\n if (!panel.contains(event.target) && !document.querySelector('.dsh-mobile-control__trigger')?.contains(event.target)) setOpen(false)\n }\n document.addEventListener('pointerdown', dismiss)\n void requestJson('/api/mobile-access/lan/control').then(render, error => { status.textContent = String(error) })\n loadRemote()\n const remotePoll = window.setInterval(() => { if (!panel.hidden && !remoteView.hidden) loadRemote() }, 1_500)\n return { remove: () => { window.clearInterval(remotePoll); window.removeEventListener('focus', retryAfterSetup); document.removeEventListener('visibilitychange', retryAfterSetup); document.removeEventListener('pointerdown', dismiss); root.remove() }, toggle: () => { setOpen(panel.hidden !== false) } }\n}\n\nfunction mobileRequest(path: string, init: RequestInit = {}): Promise<Response> {\n const target = new URL(path, location.href)\n if (target.origin !== location.origin) throw new TypeError('mobile extension requests must stay on the DSH origin')\n const headers = new Headers(init.headers)\n const method = (init.method ?? 'GET').toUpperCase()\n if (method !== 'GET' && method !== 'HEAD') {\n const csrf = document.cookie.split(';').map(value => value.trim()).find(value => value.startsWith('dsh_ma_csrf='))?.slice(12)\n if (csrf !== undefined) headers.set('x-dsh-mobile-csrf', csrf)\n }\n return fetch(target, { ...init, headers, credentials: 'same-origin', cache: 'no-store', redirect: 'error' })\n}\n\nfunction installCustomAssets(): () => void {\n const legacyStyle = element('style'); legacyStyle.dataset.plugin = 'dsh-mobile-custom'; document.head.append(legacyStyle)\n const previous = window.dshMobile\n let legacyMount: MobileExtensionMount | undefined = queuedLegacyMount\n let legacySource = ''\n let legacyRoot: HTMLElement | undefined\n let legacyDispose: (() => void) | undefined\n const definitions = new Map<string, MobileClientDefinition>()\n const active = new Map<string, { readonly controller: AbortController; readonly dispose: () => void; readonly surfaces: Map<string, { readonly dispose: () => void; readonly container: HTMLElement }> }>()\n const styleNodes = new Map<string, HTMLStyleElement>()\n const styleEtags = new Map<string, string>()\n const scriptDigests = new Map<string, string>()\n let manifestEtag = ''\n let expectedDefinitionId: string | undefined\n const SURFACE_HOST_STYLES: Readonly<Record<string, string>> = {\n 'sidebar-action': 'position:fixed;z-index:1100;top:calc(env(safe-area-inset-top) + 8px);left:8px;display:flex;flex-direction:column;gap:6px;pointer-events:none',\n 'header-action': 'position:fixed;z-index:1100;top:calc(env(safe-area-inset-top) + 8px);right:8px;display:flex;flex-direction:column;gap:6px;pointer-events:none',\n 'composer-dock': 'position:fixed;z-index:1100;bottom:calc(env(safe-area-inset-bottom) + 8px);left:50%;transform:translateX(-50%);display:flex;flex-direction:column;gap:6px;pointer-events:none',\n 'settings-section': 'position:fixed;z-index:1100;inset:auto 8px calc(env(safe-area-inset-bottom) + 72px) 8px;max-height:40vh;overflow:auto;pointer-events:none',\n }\n const surfaceHost = (placement: string): HTMLElement | undefined => {\n const existing = document.querySelector<HTMLElement>(`[data-dsh-mobile-surface-host=\"${placement}\"]`)\n if (existing !== null) return existing\n const style = SURFACE_HOST_STYLES[placement]\n if (style === undefined) return undefined\n const host = element('div'); host.dataset.dshMobileSurfaceHost = placement; host.style.cssText = style\n document.body.append(host); return host\n }\n const shellLayer = (): HTMLElement => {\n const existing = document.querySelector<HTMLElement>('[data-dsh-mobile-extension-layer]')\n if (existing !== null) return existing\n const layer = element('div'); layer.dataset.dshMobileExtensionLayer = 'true'; layer.style.cssText = 'position:fixed;inset:0;z-index:1200;pointer-events:none;overflow:hidden'\n document.body.append(layer); return layer\n }\n const toast = (message: string): void => {\n const node = element('div'); node.textContent = message; node.style.cssText = 'position:absolute;top:16px;left:50%;transform:translateX(-50%);padding:9px 14px;border-radius:999px;background:#1f2937;color:white;font:14px system-ui;pointer-events:auto;box-shadow:0 8px 24px #0003'\n shellLayer().append(node); window.setTimeout(() => node.remove(), 2600)\n }\n const materializeNativeFile = (value: unknown): unknown => {\n if (typeof value !== 'object' || value === null || !('base64' in value) || !('name' in value)) return value\n const candidate = value as { base64?: unknown; name?: unknown; type?: unknown }\n if (typeof candidate.base64 !== 'string' || typeof candidate.name !== 'string') return value\n try {\n const encoded = atob(candidate.base64)\n const bytes = Uint8Array.from(encoded, character => character.charCodeAt(0))\n return new File([bytes], candidate.name, { type: typeof candidate.type === 'string' ? candidate.type : 'application/octet-stream' })\n } catch {\n return value\n }\n }\n const invokeNative = async (action: string, input?: unknown): Promise<unknown> => {\n const bridge = window.__DSH_MOBILE_NATIVE__\n if (bridge !== undefined) return materializeNativeFile(await bridge.invoke(action, input))\n if (action === 'share' && typeof navigator.share === 'function') { await navigator.share((input ?? {}) as ShareData); return { ok: true } }\n if (action === 'clipboard.read' && navigator.clipboard !== undefined) return { text: await navigator.clipboard.readText() }\n if (action === 'clipboard.write' && navigator.clipboard !== undefined) { await navigator.clipboard.writeText(typeof input === 'object' && input !== null && 'text' in input ? String((input as { text: unknown }).text) : ''); return { ok: true } }\n if (action === 'files.pick' || action === 'camera.capture') {\n const inputElement = element('input'); inputElement.type = 'file'; inputElement.accept = action === 'camera.capture' ? 'image/*' : '*/*'; if (action === 'camera.capture') inputElement.capture = 'environment';\n return new Promise<File | undefined>(resolve => { inputElement.onchange = () => resolve(inputElement.files?.[0]); inputElement.click() })\n }\n throw new Error('native capability is unavailable')\n }\n const makeApi = (id: string, controller: AbortController): MobileClientApi => {\n const surfaces = active.get(id)?.surfaces ?? new Map()\n const mountSurface = (surface: MobileSurface): (() => void) => {\n if (!/^[a-z][a-z0-9-]{0,63}$/u.test(surface.id) || surface.label.length > 120) throw new Error('invalid mobile surface')\n const container = element('section'); container.dataset.dshMobileSurface = surface.id; container.hidden = surface.placement === 'page' || surface.placement === 'overlay'; container.style.cssText = surface.placement === 'page' || surface.placement === 'overlay' ? 'position:absolute;inset:0;overflow:auto;background:var(--dsw-alias-bg-layer-1,#fff);padding:16px;pointer-events:auto' : 'pointer-events:auto'\n const host = surface.placement === 'page' || surface.placement === 'overlay' ? shellLayer() : surfaceHost(surface.placement) ?? shellLayer()\n host.append(container)\n const mounted = surface.mount(container)\n const dispose = (): void => { if (typeof mounted === 'function') mounted(); container.remove() }\n surfaces.set(surface.id, { dispose, container });\n return () => { if (surfaces.get(surface.id)?.dispose === dispose) surfaces.delete(surface.id); dispose() }\n }\n return {\n host: {\n invoke: (action: string, input: unknown) => mobileRequest(`/mobile-access/extensions/${encodeURIComponent(id)}/actions/${encodeURIComponent(action)}`, { method: 'POST', body: JSON.stringify(input ?? {}) }).then(async response => { const value = await response.json() as unknown; if (!response.ok) throw new Error(typeof value === 'object' && value !== null && 'error' in value ? String((value as { error: unknown }).error) : `HTTP ${String(response.status)}`); return value }),\n fetch: (path: string, init?: RequestInit) => {\n if (!path.startsWith('/') || path.startsWith('//') || path.includes('://')\n || path.split('/').some(part => part === '..' || part === '.')) throw new TypeError('extension routes must be relative')\n return mobileRequest(`/mobile-access/extensions/${encodeURIComponent(id)}/routes${path}`, init)\n },\n },\n ui: { registerSurface: mountSurface, open: id => { const entry = surfaces.get(id); if (entry !== undefined) entry.container.hidden = false }, close: id => { const entry = surfaces.get(id); if (entry !== undefined) entry.container.hidden = true }, toast },\n native: { capabilities: async () => { const bridge = window.__DSH_MOBILE_NATIVE__; return bridge === undefined ? ['files.pick', 'camera.capture', 'share', 'clipboard.read', 'clipboard.write'] : bridge.capabilities() }, invoke: invokeNative },\n signal: controller.signal, document, window,\n }\n }\n const activateDefinition = async (definition: MobileClientDefinition): Promise<void> => {\n const previousActive = active.get(definition.id)\n const controller = new AbortController()\n const surfaces = new Map<string, { readonly dispose: () => void; readonly container: HTMLElement }>()\n active.set(definition.id, { controller, surfaces, dispose: () => { controller.abort(); for (const surface of surfaces.values()) surface.dispose(); surfaces.clear() } })\n try {\n const cleanup = await definition.activate(makeApi(definition.id, controller))\n const current = active.get(definition.id)\n if (current === undefined || current.controller !== controller) { if (typeof cleanup === 'function') cleanup(); return }\n const oldDispose = current.dispose\n active.set(definition.id, { ...current, dispose: () => { if (typeof cleanup === 'function') cleanup(); oldDispose() } })\n previousActive?.dispose()\n } catch {\n active.get(definition.id)?.dispose(); active.delete(definition.id); if (previousActive !== undefined) active.set(definition.id, previousActive)\n }\n }\n const define = (definition: MobileClientDefinition): void => {\n if (definition.apiVersion !== 1 || !/^[a-z][a-z0-9-]{0,63}$/u.test(definition.id) || typeof definition.activate !== 'function') return\n if (expectedDefinitionId !== undefined && definition.id !== expectedDefinitionId) return\n definitions.set(definition.id, definition)\n if (started) void activateDefinition(definition)\n }\n let started = false\n window.dshMobile = Object.freeze({ register: mount => { legacyMount = mount }, define })\n for (const definition of queuedDefinitions.splice(0)) define(definition)\n let legacyJsEtag = ''\n let legacyJsModified = ''\n const refreshLegacy = async (): Promise<void> => {\n try {\n const headers: Record<string, string> = {}\n if (legacyJsEtag !== '') headers['if-none-match'] = legacyJsEtag\n if (legacyJsModified !== '') headers['if-modified-since'] = legacyJsModified\n const response = await fetch('/mobile-access/custom.js', { credentials: 'same-origin', cache: 'no-store', headers })\n if (response.status === 304) return\n if (!response.ok) return\n legacyJsEtag = response.headers.get('etag') ?? ''\n legacyJsModified = response.headers.get('last-modified') ?? ''\n const next = await response.text(); if (next === legacySource) return; legacySource = next; legacyMount = undefined\n const script = element('script'); script.textContent = `${next}\\n//# sourceURL=dsh-mobile-custom.js`; document.head.append(script); script.remove()\n const mount = legacyMount as MobileExtensionMount | undefined\n if (mount === undefined) return\n const nextRoot = element('div'); nextRoot.dataset.dshMobileExtension = 'true'; document.body.append(nextRoot)\n const nextDispose = mount({ document, request: mobileRequest, root: nextRoot, window })\n legacyDispose?.(); legacyRoot?.remove(); legacyRoot = nextRoot; legacyDispose = typeof nextDispose === 'function' ? nextDispose : undefined\n } catch { /* Preserve the last good customization during reconnects. */ }\n }\n const refreshExtensions = async (): Promise<void> => {\n try {\n const headers: Record<string, string> = {}\n if (manifestEtag !== '') headers['if-none-match'] = manifestEtag\n const response = await fetch('/mobile-access/extensions/manifest', { credentials: 'same-origin', cache: 'no-store', headers })\n if (response.status === 304) return\n if (!response.ok) return\n manifestEtag = response.headers.get('etag') ?? ''\n const payload = await response.json() as { extensions?: unknown }\n const entries = Array.isArray(payload.extensions) ? payload.extensions as Record<string, unknown>[] : []\n const seen = new Set<string>()\n for (const entry of entries) {\n if (typeof entry.id !== 'string') continue\n seen.add(entry.id)\n const cssUrl = typeof entry.styleUrl === 'string' ? entry.styleUrl : undefined\n if (cssUrl !== undefined) {\n const cssHeaders: Record<string, string> = {}\n const storedEtag = styleEtags.get(entry.id)\n if (storedEtag !== undefined) cssHeaders['if-none-match'] = storedEtag\n const cssResponse = await fetch(cssUrl, { credentials: 'same-origin', cache: 'no-store', headers: cssHeaders })\n if (cssResponse.status === 304) { /* unchanged */ }\n else if (cssResponse.ok) {\n const nextEtag = cssResponse.headers.get('etag'); if (nextEtag !== null && nextEtag !== '') styleEtags.set(entry.id, nextEtag)\n const css = await cssResponse.text(); const oldStyle = styleNodes.get(entry.id)\n if (oldStyle?.textContent !== css) {\n const node = element('style'); node.dataset.dshMobileExtensionStyle = entry.id; node.textContent = css; document.head.append(node); styleNodes.set(entry.id, node); oldStyle?.remove()\n }\n } else continue\n }\n const scriptUrl = typeof entry.scriptUrl === 'string' ? entry.scriptUrl : undefined\n if (scriptUrl !== undefined) {\n const scriptHeaders: Record<string, string> = {}\n const storedDigest = scriptDigests.get(entry.id)\n if (storedDigest !== undefined) scriptHeaders['if-none-match'] = storedDigest\n const scriptResponse = await fetch(scriptUrl, { credentials: 'same-origin', cache: 'no-store', headers: scriptHeaders })\n if (scriptResponse.status === 304) { /* unchanged */ }\n else if (scriptResponse.ok) {\n const source = await scriptResponse.text(); const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(source)); const key = [...new Uint8Array(digest)].map(value => value.toString(16).padStart(2, '0')).join('');\n if (scriptDigests.get(entry.id) !== key) {\n scriptDigests.set(entry.id, key)\n expectedDefinitionId = entry.id\n try { const script = element('script'); script.textContent = `${source}\\n//# sourceURL=dsh-mobile-extension-${entry.id}.js`; document.head.append(script); script.remove() }\n finally { expectedDefinitionId = undefined }\n }\n } else continue\n }\n const definition = definitions.get(entry.id); if (definition !== undefined && !active.has(entry.id)) await activateDefinition(definition)\n }\n for (const [id, current] of active) if (!seen.has(id) && !definitions.has(id) && id !== 'legacy-custom') { current.dispose(); active.delete(id); styleNodes.get(id)?.remove(); styleNodes.delete(id); styleEtags.delete(id); scriptDigests.delete(id) }\n } catch { /* A temporary reconnect failure must not tear down the last good UI. */ }\n }\n started = true\n for (const definition of definitions.values()) void activateDefinition(definition)\n void refreshLegacy(); void refreshExtensions(); void refreshCssLegacy(legacyStyle)\n const timer = window.setInterval(() => { void refreshLegacy(); void refreshExtensions(); void refreshCssLegacy(legacyStyle) }, 3_000)\n return () => { clearInterval(timer); started = false; legacyDispose?.(); legacyRoot?.remove(); legacyStyle.remove(); for (const current of active.values()) current.dispose(); for (const node of styleNodes.values()) node.remove(); const layer = document.querySelector('[data-dsh-mobile-extension-layer]'); layer?.remove(); for (const host of document.querySelectorAll('[data-dsh-mobile-surface-host]')) host.remove(); if (previous === undefined) delete window.dshMobile; else window.dshMobile = previous }\n}\n\nlet cssEtag = ''\nlet cssModified = ''\nasync function refreshCssLegacy(style: HTMLStyleElement): Promise<void> {\n try {\n const headers: Record<string, string> = {}\n if (cssEtag !== '') headers['if-none-match'] = cssEtag\n if (cssModified !== '') headers['if-modified-since'] = cssModified\n const response = await fetch('/mobile-access/custom.css', { credentials: 'same-origin', cache: 'no-store', headers })\n if (response.status === 304) return\n if (response.ok) {\n cssEtag = response.headers.get('etag') ?? ''\n cssModified = response.headers.get('last-modified') ?? ''\n style.textContent = await response.text()\n }\n } catch { /* Preserve the last good style during reconnects. */ }\n}\n\nconst CONTROL_STYLES = `\n.dsh-mobile-control{position:fixed;z-index:1000;left:16px;bottom:112px;font:14px/1.45 system-ui;color:var(--dsw-alias-label-primary,#16181d)}\n.dsh-mobile-control__panel{box-sizing:border-box;width:min(380px,calc(100vw - 32px));max-height:calc(100vh - 140px);overflow-y:auto;padding:16px;border:1px solid var(--dsw-alias-border-subtle,#e1e5eb);border-radius:18px;background:var(--dsw-alias-bg-layer-2,#fff);box-shadow:0 18px 50px rgb(15 23 42 / 18%)}\n.dsh-mobile-control__header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px}.dsh-mobile-control__panel h2{margin:0;font-size:17px;line-height:24px}.dsh-mobile-control__close{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:0;border-radius:10px;background:transparent;color:inherit;font-size:24px;line-height:1;cursor:pointer}.dsh-mobile-control__close:hover{background:var(--dsw-alias-interactive-bg-hover,#f1f3f6)}\n.dsh-mobile-control__switcher{display:grid;grid-template-columns:1fr 1fr;gap:4px;margin:0 0 14px;padding:4px;border-radius:12px;background:var(--dsw-alias-bg-layer-1,#f3f5f8)}.dsh-mobile-control__tab{min-height:36px;border:0;border-radius:9px;background:transparent;color:var(--dsw-alias-label-secondary,#606873);font:600 13px/1 system-ui;cursor:pointer}.dsh-mobile-control__tab.is-active{background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);box-shadow:0 1px 3px rgb(15 23 42 / 10%)}.dsh-mobile-control__view[hidden]{display:none}.dsh-mobile-control__intro{margin:0 0 12px;color:var(--dsw-alias-label-secondary,#606873);font-size:12px;line-height:1.55}.dsh-mobile-control__view.is-remote .dsh-mobile-control__actions{display:grid;grid-template-columns:1fr 1fr;gap:8px}.dsh-mobile-control__view.is-remote .dsh-mobile-control__actions button[hidden]{display:none}\n.dsh-mobile-control__provider-section{position:relative;margin:0 0 12px}.dsh-mobile-control__section-title{margin:0 0 8px;color:var(--dsw-alias-label-primary,#16181d);font:650 13px/1.4 system-ui}.dsh-mobile-control__provider-section>.dsh-mobile-control__section-title{padding-right:42px}.dsh-mobile-control__provider-choices{display:grid;gap:8px}.dsh-mobile-control__provider{display:flex;flex-direction:column;gap:5px;min-height:68px;padding:11px 12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:#fff;color:inherit;text-align:left;cursor:pointer;transition:border-color 160ms ease,background-color 160ms ease,box-shadow 160ms ease}.dsh-mobile-control__provider:hover{border-color:#9fb9e8;background:#f8fbff}.dsh-mobile-control__provider.is-selected{border-color:#2563eb;background:#f5f8ff;box-shadow:0 0 0 1px #2563eb inset}.dsh-mobile-control__provider:disabled{cursor:wait;opacity:.62}.dsh-mobile-control__provider-top{display:flex;align-items:center;justify-content:space-between;gap:8px}.dsh-mobile-control__provider-top strong{font-size:13px}.dsh-mobile-control__provider-badge{flex:none;padding:3px 7px;border-radius:999px;background:#e8f0ff;color:#1d4ed8;font:650 10px/1.2 system-ui}.dsh-mobile-control__provider-badge.is-cpolar{background:#eaf8f2;color:#087454}.dsh-mobile-control__provider-description{color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.45}.dsh-mobile-control__provider-info{position:absolute;z-index:5;top:-13px;right:-8px}.dsh-mobile-control__provider-info-button{display:flex;align-items:center;justify-content:center;width:44px;height:44px;padding:0;border:0;border-radius:50%;background:transparent;color:#475569;cursor:pointer;touch-action:manipulation}.dsh-mobile-control__provider-info-button:hover{background:#f1f5f9;color:#1d4ed8}.dsh-mobile-control__provider-info-glyph{display:flex;align-items:center;justify-content:center;box-sizing:border-box;width:18px;height:18px;border:1.5px solid currentColor;border-radius:50%;font:700 12px/1 system-ui}.dsh-mobile-control__provider-info-popover{position:absolute;z-index:6;top:38px;right:4px;box-sizing:border-box;width:min(292px,calc(100vw - 72px));padding:10px 12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:12px;background:var(--dsw-alias-bg-layer-2,#fff);box-shadow:0 10px 28px rgb(15 23 42 / 16%)}.dsh-mobile-control__provider-info-popover[hidden]{display:none}.dsh-mobile-control__provider-info-popover strong,.dsh-mobile-control__provider-info-popover span{display:block}.dsh-mobile-control__provider-info-popover strong{margin-bottom:3px;font-size:12px}.dsh-mobile-control__provider-info-popover span{color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.55}\n.dsh-mobile-control__cpolar-setup{margin:0 0 12px;padding:12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:#fff}.dsh-mobile-control__cpolar-setup[hidden],.dsh-mobile-control__cpolar-account[hidden],.dsh-mobile-control__details[hidden],.dsh-mobile-control__view.is-remote .dsh-mobile-control__actions[hidden],.dsh-mobile-control__danger[hidden]{display:none}.dsh-mobile-control__component-status,.dsh-mobile-control__component-note{margin:0 0 10px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.55}.dsh-mobile-control__cpolar-setup>.dsh-mobile-control__primary{width:100%;min-height:44px;padding:9px 12px;border-radius:10px;font:600 12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__cpolar-account{margin-top:10px}.dsh-mobile-control__link-row{display:flex;flex-wrap:wrap;gap:6px 12px;margin:0 0 10px}.dsh-mobile-control__text-link{color:#2563eb;font-size:11px;text-decoration:none}.dsh-mobile-control__text-link:hover{text-decoration:underline}.dsh-mobile-control__token-label{display:flex;flex-direction:column;gap:5px;margin:0 0 8px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px}.dsh-mobile-control__token{box-sizing:border-box;width:100%;min-height:44px;padding:9px 10px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:#fff;color:inherit;font:16px/1.4 system-ui}.dsh-mobile-control__cpolar-connect{display:flex;align-items:center;justify-content:center;box-sizing:border-box;width:100%;min-height:44px;padding:10px 14px;border-radius:12px;font:650 13px/1.2 system-ui;cursor:pointer;transition:background-color 160ms ease,border-color 160ms ease,opacity 160ms ease}.dsh-mobile-control__cpolar-connect:hover:not(:disabled){border-color:#1d4ed8;background:#1d4ed8}.dsh-mobile-control__cpolar-connect:active:not(:disabled){border-color:#1e40af;background:#1e40af}.dsh-mobile-control__cpolar-connect:disabled{cursor:wait;opacity:.55}.dsh-mobile-control__details{margin:10px 0 0;border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb);padding-top:9px}.dsh-mobile-control__details>summary{min-height:30px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:30px;cursor:pointer}.dsh-mobile-control__details-body{display:flex;flex-wrap:wrap;align-items:center;gap:7px 12px;padding:4px 0}.dsh-mobile-control__details-body p{flex:1 0 100%;margin:0;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5}.dsh-mobile-control__storage{display:block;flex:1 0 100%;max-width:100%;overflow:hidden;padding:7px 8px;border-radius:8px;background:#f3f5f8;color:#475569;font:10px/1.4 ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__danger{flex:1 0 100%;min-height:38px;margin-top:3px;padding:7px 10px;border:1px solid #dc2626;border-radius:9px;background:transparent;color:#b91c1c;font:12px/1.3 system-ui;cursor:pointer}\n.dsh-mobile-control__access{display:flex;align-items:baseline;gap:6px;min-width:0;margin:0 0 12px}.dsh-mobile-control__access[hidden]{display:none}.dsh-mobile-control__access-label{flex:none;color:var(--dsw-alias-label-secondary,#606873);white-space:nowrap}.dsh-mobile-control__access-label::after{content:\":\"}.dsh-mobile-control__access-link{min-width:0;overflow:hidden;color:#2563eb;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__access-link:hover{text-decoration:underline}.dsh-mobile-control__qr{display:flex;justify-content:center;margin:0 0 12px}.dsh-mobile-control__qr[hidden]{display:none}.dsh-mobile-control__qr img{border-radius:12px;background:#fff;padding:8px}\n.dsh-mobile-control__status{margin:0 0 14px;overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary,#606873)}.dsh-mobile-control__status::before{display:inline-block;width:8px;height:8px;margin-right:7px;border-radius:50%;background:#98a1ad;content:\"\"}.dsh-mobile-control__status.is-running::before{background:#16a36a}.dsh-mobile-control__status.is-key{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;word-break:break-all}\n.dsh-mobile-control__guide{margin:0 0 14px;padding:12px;border:1px solid #bfdbfe;border-radius:12px;background:#eff6ff}.dsh-mobile-control__guide[hidden]{display:none}.dsh-mobile-control__guide-title{margin:0;color:#172554;font:650 13px/1.45 system-ui}.dsh-mobile-control__guide-summary,.dsh-mobile-control__guide-note{margin:4px 0 0;color:#475569;font-size:12px;line-height:1.5}.dsh-mobile-control__guide-steps{margin:8px 0 0;padding-left:20px;color:#1e293b;font-size:12px;line-height:1.6}.dsh-mobile-control__guide-note{color:#64748b}.dsh-mobile-control__guide-actions{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:10px}.dsh-mobile-control__guide-actions button{min-width:0;min-height:44px;padding:8px;border-radius:10px;font:12px/1.25 system-ui;cursor:pointer}.dsh-mobile-control__guide-actions button:disabled{cursor:not-allowed;opacity:.45}\n.dsh-mobile-control__extensions{margin:0 0 12px;color:var(--dsw-alias-label-secondary,#606873);font-size:12px}\n.dsh-mobile-control__actions{display:flex;flex-wrap:nowrap;gap:6px}.dsh-mobile-control__actions button{flex:1 1 0;min-width:0;min-height:40px;padding:8px 4px;border-radius:10px;font:12px/1.2 system-ui;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dsh-mobile-control__secondary{border:1px solid var(--dsw-alias-border-normal,#cfd5dd);background:transparent;color:inherit}.dsh-mobile-control__primary{border:1px solid #2563eb;background:#2563eb;color:#fff}.dsh-mobile-control__actions button:disabled{cursor:not-allowed;opacity:.45}\n.dsh-mobile-control button:focus-visible,.dsh-mobile-control a:focus-visible,.dsh-mobile-control input:focus-visible,.dsh-mobile-control summary:focus-visible{outline:3px solid rgb(37 99 235 / 28%);outline-offset:2px}\n.dsh-mobile-control__trigger{box-sizing:border-box;display:flex;align-items:center;gap:8px;width:calc(100% + 8px);height:34px;margin:4px -4px;padding:6px 2px 6px 10px;border:0;border-radius:12px;background:transparent;color:var(--dsw-alias-label-primary,#16181d);font:14px/22px system-ui;cursor:pointer}.dsh-mobile-control__trigger:hover{background:var(--dsw-alias-interactive-bg-hover,#f1f3f6)}.dsh-mobile-control__trigger.is-rail{width:36px;height:36px;margin:8px 0 10px;padding:0;justify-content:center;border-radius:50%}.dsh-mobile-control__trigger-icon{position:relative;box-sizing:border-box;flex:none;width:14px;height:19px;border:1.7px solid currentColor;border-radius:3px}.dsh-mobile-control__trigger-icon::after{position:absolute;right:4px;bottom:2px;width:4px;height:1.5px;border-radius:2px;background:currentColor;content:\"\"}.dsh-mobile-control__trigger-label{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}\n.dsh-mobile-control__manage-row{display:flex;justify-content:space-between;gap:8px;margin-top:10px}.dsh-mobile-control__manage{flex:1 1 0;min-width:0;min-height:34px;padding:6px 8px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:transparent;color:inherit;font:12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__devices{margin-top:10px;border:1px solid var(--dsw-alias-border-subtle,#e1e5eb);border-radius:10px;padding:8px;max-height:220px;overflow-y:auto}.dsh-mobile-control__device-empty{color:var(--dsw-alias-label-secondary,#606873);font-size:12px;margin:0}.dsh-mobile-control__device{display:flex;align-items:center;gap:8px;padding:6px 2px}.dsh-mobile-control__device + .dsh-mobile-control__device{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__device-label{flex:1 1 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}.dsh-mobile-control__device-meta{flex:none;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;white-space:nowrap}.dsh-mobile-control__device-revoke{flex:none;min-height:28px;padding:4px 8px;border:1px solid #dc2626;border-radius:8px;background:transparent;color:#dc2626;font:12px/1.2 system-ui;cursor:pointer}\n@media (prefers-reduced-motion:reduce){.dsh-mobile-control__provider,.dsh-mobile-control__cpolar-connect{transition:none}}\n`\n\n/** Mount the desktop control or mobile feature enhancements. */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => {\n if (window.__DSH_MOBILE_FRONTEND__ !== 'dedicated') return\n return trustAuthenticatedGatewayConnection(ctx.get('connection'))\n }, 'dsh-mobile: authenticated gateway client trust')\n\n ctx.effect(() => {\n const loopback = isLoopbackHost(location.hostname) && !new URLSearchParams(location.search).has('dsh-mobile-preview')\n const style = element('style'); style.dataset.plugin = 'dsh-mobile'; style.textContent = loopback\n ? CONTROL_STYLES\n : NATIVE_MOBILE_STYLES\n document.head.append(style)\n if (!loopback) {\n const removeCustom = installCustomAssets()\n const removeSurface = installNativeMobileSurface()\n return () => { removeCustom(); removeSurface(); style.remove() }\n }\n const control = installControl()\n const disposeSlot = ctx.slots.inject('sidebar.footer.action', () => ctx.slots.register({ name: 'sidebar.footer.action', id: 'dsh-mobile' }, ({ wide }) => createElement('button', {\n 'aria-expanded': false,\n 'aria-label': '移动访问',\n className: `dsh-mobile-control__trigger${wide ? '' : ' is-rail'}`,\n type: 'button',\n title: '移动访问',\n onClick: control.toggle,\n }, createElement('span', { 'aria-hidden': true, className: 'dsh-mobile-control__trigger-icon' }), wide ? createElement('span', { className: 'dsh-mobile-control__trigger-label' }, '移动访问') : undefined)))\n return () => { disposeSlot(); control.remove(); style.remove() }\n }, 'dsh-mobile: stock mobile adaptation and local control')\n}\n\n/** Client services required by the mobile adaptation. */\nexport const inject: readonly string[] = ['slots']\n"],"mappings":";;;;;;;;;EACA,MAAa,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsJpC,SAAS,WAAW,SAAkB,QAAyB;GAC7D,OAAO,MAAM,KAAK,QAAQ,SAAS,CAAC,CAAC,MAAK,UAAS,MAAM,SAAS,MAAM,CAAC;EAC3E;EAEA,SAAS,mBAAmB,MAAkB,QAAyC;GACrF,OAAO,MAAM,KAAK,KAAK,iBAA8B,SAAS,CAAC,CAAC,CAAC,MAAK,YAAW,WAAW,SAAS,MAAM,CAAC;EAC9G;EAEA,MAAM,4BAA4B;;EAGlC,SAAgB,sBAAsB,aAAqB,YAA6B;GACtF,OAAO,cAAc,6BAA6B,aAAa,cAAc;EAC/E;;EAGA,SAAgB,6BAAyC;GACvD,SAAS,gBAAgB,UAAU,IAAI,0BAA0B;GACjE,MAAM,gBAAgB,SAAqC;IACzD,SAAS,gBAAgB,QAAQ,iBAAiB;GACpD;GACA,MAAM,iBAAiB,UAA8B;IACnD,IAAI,MAAM,gBAAgB,WAAW,MAAM,gBAAgB,OAAO,aAAa,OAAO;GACxF;GACA,MAAM,aAAa,UAA+B;IAChD,IAAI,MAAM,QAAQ,SAAS,MAAM,IAAI,WAAW,OAAO,GAAG,aAAa,UAAU;GACnF;GACA,SAAS,iBAAiB,eAAe,eAAe,IAAI;GAC5D,SAAS,iBAAiB,WAAW,WAAW,IAAI;GACpD,MAAM,WAAW,SAAS,cAAc,QAAQ;GAChD,SAAS,OAAO;GAChB,SAAS,YAAY;GACrB,SAAS,SAAS;GAClB,SAAS,aAAa,cAAc,SAAS;GAC7C,SAAS,KAAK,OAAO,QAAQ;GAC7B,MAAM,cAAc,SAAS,cAAc,KAAK;GAChD,YAAY,YAAY;GACxB,YAAY,aAAa,QAAQ,QAAQ;GACzC,YAAY,aAAa,aAAa,QAAQ;GAC9C,SAAS,KAAK,OAAO,WAAW;GAChC,IAAI,mBAAmB;GACvB,MAAM,wBAA8B;IAClC,MAAM,SAAS,SAAS,cAA2B,0BAA0B;IAC7E,MAAM,QAAQ,WAAW,OAAO,KAAA,IAAY,OAAO,cAA2B,4BAA0B,CAAC,EAAE,aAAa,KAAK;IAC7H,YAAY,cAAc,UAAU,KAAA,IAAY,SAAS,QAAQ;IACjE,YAAY,QAAQ,UAAU;IAC9B,IAAI,qBAAqB,GAAG,OAAO,aAAa,gBAAgB;IAChE,mBAAmB,OAAO,iBAAiB;KACzC,YAAY,gBAAgB,cAAc;KAC1C,mBAAmB;IACrB,GAAG,IAAI;GACT;GACA,MAAM,iBAAiB,UAA4B;IACjD,IAAI,EAAE,MAAM,kBAAkB,UAAU;IACxC,MAAM,SAAS,MAAM,OAAO,QAA2B,0FAAoF;IAC3I,IAAI,WAAW,QAAQ,OAAO,aAAa,UAAU,KAAK,OAAO,aAAa,eAAe,MAAM,QAAQ;IAC3G,OAAO,WAAW,iBAAiB,EAAE;GACvC;GACA,SAAS,iBAAiB,SAAS,eAAe,IAAI;GACtD,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI,YAAY;GAChB,IAAI,kBAAkB;GACtB,IAAI,yBAAyB;GAC7B,IAAI,kBAAkB;GACtB,IAAI;GACJ,IAAI;GACJ,IAAI,qBAAqB;GACzB,MAAM,0BAAyD;IAE7D,QADe,oBAAoB,KAAA,IAAY,KAAA,IAAY,mBAAmB,iBAAiB,QAAQ,EAAA,EACxF,cAAiC,QAAQ,KAAK,KAAA;GAC/D;GACA,MAAM,wBAA8B;IAClC,IAAI,oBAAoB,KAAA,GAAW;IACnC,MAAM,aAAa,KAAK,IAAI,GAAG,gBAAgB,SAAS;IACxD,MAAM,aAAa,sBAAsB,oBAAoB,UAAU;IACvE,qBAAqB;IACrB,IAAI,CAAC,YAAY;IACjB,MAAM,SAAS,kBAAkB;IACjC,IAAI,WAAW,KAAA,KAAa,OAAO,YAAY,OAAO,aAAa,eAAe,MAAM,QAAQ;IAChG,OAAO,MAAM;GACf;GACA,MAAM,uBAAuB,SAAwC;IACnE,IAAI,oBAAoB,MAAM;IAC9B,iBAAiB,oBAAoB,UAAU,eAAe;IAC9D,kBAAkB;IAClB,qBAAqB,MAAM,aAAa;IACxC,iBAAiB,iBAAiB,UAAU,iBAAiB,EAAE,SAAS,KAAK,CAAC;GAChF;GACA,MAAM,qBAAqB,UAA4B;IACrD,IAAI,EAAE,MAAM,kBAAkB,UAAU;IACxC,MAAM,UAAU,MAAM,OAAO,QAAqB,yCAAuC;IACzF,IAAI,YAAY,QAAQ,QAAQ,aAAa,UAAU,KAAK,QAAQ,aAAa,eAAe,MAAM,QAAQ;IAC9G,IAAI,QAAQ,aAAa,eAAe,MAAM,UAAU,QAAQ,aAAa,cAAc,MAAM,QAAQ;IACzG,MAAM,qBAAqB,QAAQ,QAAQ,iCAAiC,MAAM;IAClF,MAAM,yBAAyB,QAAQ,QAAQ,gBAAc;IAC7D,MAAM,oBAAoB,QAAQ,QAAQ,gCAAgC,MAAM,QAC3E,QAAQ,QAAQ,0BAA0B,MAAM;IACrD,IAAI,CAAC,sBAAsB,CAAC,0BAA0B,CAAC,mBAAmB;IAC1E,IAAI,OAAO,WAAW,kCAAkC,CAAC,CAAC,SAAS;IACnE,IAAI,oBAAoB,GAAG,qBAAqB,eAAe;IAC/D,IAAI,2BAA2B,GAAG,qBAAqB,sBAAsB;IAC7E,kBAAkB,4BAA4B;KAC5C,kBAAkB;KAClB,MAAM,SAAS,qBACX,SAAS,cAA2B,oCAAoC,IACxE;KACJ,IAAI,WAAW,QAAQ,WAAW,KAAA,GAAW;KAC7C,kBAAkB,gBAAgB,iCAAiC;KACnE,OAAO,gBAAgB,iCAAiC;KACxD,yBAAyB,4BAA4B;MACnD,yBAAyB;MACzB,mBAAmB;MACnB,OAAO,QAAQ,0BAA0B;MACzC,IAAI,oBAAoB,GAAG,aAAa,eAAe;MACvD,kBAAkB,OAAO,iBAAiB;OACxC,OAAO,gBAAgB,iCAAiC;OACxD,IAAI,qBAAqB,QAAQ,mBAAmB,KAAA;OACpD,kBAAkB;MACpB,GAAG,GAAG;KACR,CAAC;IACH,CAAC;GACH;GACA,SAAS,iBAAiB,SAAS,iBAAiB;GAEpD,MAAM,aAAmB;IACvB,YAAY;IACZ,QAAQ,mBAAmB,UAAU,QAAQ;IAC7C,MAAM,kBAAkB,SAAS,cAA2B,YAAY,KAAK,KAAA;IAC7E,IAAI,UAAU,KAAA,GAAW,MAAM,QAAQ,iBAAiB;IACxD,UAAU,UAAU,KAAA,IAChB,SAAS,cAA2B,cAAc,KAAK,KAAA,IACvD,mBAAmB,OAAO,aAAa;IAC3C,MAAM,SAAS,UAAU,KAAA,IAAY,kBAAkB,mBAAmB,OAAO,YAAY;IAC7F,MAAM,UAAU,UAAU,KAAA,IAAY,KAAA,IAAY,mBAAmB,OAAO,aAAa;IACzF,MAAM,SAAS,UAAU,KAAA,IAAY,KAAA,IAAY,mBAAmB,OAAO,SAAS;IACpF,IAAI,WAAW,KAAA,GAAW;KACxB,oBAAoB,KAAA,CAAS;KAC7B;IACF;IACA,IAAI,WAAW,KAAA,GAAW;KACxB,OAAO,QAAQ,kBAAkB;KACjC,OAAO,cAA2B,QAAQ,CAAC,EAAE,aAAa,0BAA0B,MAAM;KAC1F,WAAW,mBAAmB,QAAQ,WAAW;KACjD,IAAI,aAAa,KAAA,GAAW,SAAS,QAAQ,gBAAgB;KAC7D,MAAM,eAAe,OAAO,cAA2B,4BAA4B;KACnF,oBAAoB,gBAAgB,KAAA,CAAS;KAC7C,MAAM,gBAAgB,iBAAiB,OAAO,KAAA,IAAY,mBAAmB,cAAc,QAAQ;KACnG,IAAI,kBAAkB,KAAA,GAAW;MAC/B,cAAc,QAAQ,yBAAyB;MAC/C,cAAc,aAAa,aAAa,QAAQ;MAChD,MAAM,SAAS,cAAc,cAAiC,QAAQ;MACtE,IAAI,WAAW,MAAM;OACnB,OAAO,WAAW;OAClB,IAAI,OAAO,UAAU,OAAO,gBAAgB,aAAa;YACpD,OAAO,aAAa,eAAe,MAAM;MAChD;KACF;KACA,MAAM,gBAAgB,iBAAiB,OAAO,KAAA,IAAY,mBAAmB,cAAc,SAAS;KACpG,MAAM,gBAAgB,eAAe;KACrC,IAAI,kBAAkB,KAAA,KAAa,kBAAkB,QAAQ,kBAAkB,KAAA,KAAa,WAAW,eAAe,SAAS,GAAG;MAChI,cAAc,QAAQ,yBAAyB;MAC/C,cAAc,QAAQ,yBAAyB;KACjD;KACA,KAAK,MAAM,SAAS,OAAO,iBAAmC,OAAO,GAAG;MAEtE,IADe,MAAM,eACT,QAAQ,yBAAyB,QAAQ;MACrD,MAAM,UAAU,SAAS,cAAc,KAAK;MAC5C,QAAQ,QAAQ,uBAAuB;MACvC,MAAM,OAAO,OAAO;MACpB,QAAQ,OAAO,KAAK;KACtB;KAEA,MAAM,cADe,OAAO,cAA2B,sBACxB,CAAC,EAAE,cAA2B,8BAA8B,CAAC,EAAE;KAC9F,IAAI,uBAAuB,aAAa;MACtC,YAAY,QAAQ,uBAAuB;MAC3C,MAAM,SAAS,MAAM,KAAK,YAAY,QAAQ,CAAC,CAAC,QAAQ,UAAgC,iBAAiB,WAAW;MACpH,MAAM,gBAAgB,OAAO;MAC7B,MAAM,mBAAmB,OAAO,GAAG,EAAE;MACrC,IAAI,kBAAkB,KAAA,GAAW,cAAc,QAAQ,yBAAyB;MAChF,IAAI,qBAAqB,KAAA,KAAa,qBAAqB,eAAe;OACxE,iBAAiB,QAAQ,4BAA4B;OACrD,MAAM,eAAe,iBAAiB,cAAiC,mEAA+D;OACtI,IAAI,iBAAiB,MAAM;QACzB,aAAa,QAAQ,gCAAgC;QACrD,aAAa,eAAe,aAAa,kCAAkC,MAAM;QACjF,aAAa,cAA2B,4BAA0B,CAAC,EAAE,aAAa,wCAAwC,MAAM;OAClI;MACF;KACF;IACF;IACA,IAAI,WAAW,KAAA,GAAW,OAAO,QAAQ,kBAAkB;IAC3D,IAAI,YAAY,KAAA,GAAW;KACzB,QAAQ,QAAQ,mBAAmB;KACnC,MAAM,aAAa,OAAO,MAAM,oBAAoB,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,GAAG,EAAE;KAC7E,QAAQ,QAAQ,OAAO,OAAO,eAAe,KAAA,KAAa,eAAe,SAAS,eAAe,GAAG;IACtG;IACA,MAAM,WAAW,MAAM,KAAK,SAAS,iBAA8B,mBAAiB,CAAC,CAAC,CAAC,MAAK,WAAU;KAEpG,OADkB,MAAM,KAAK,OAAO,QAAQ,CAAC,CAAC,MAAK,UAAS,iBAAiB,eAAe,WAAW,OAAO,MAAM,CACrG,MAAM,KAAA;IACvB,CAAC;IACD,IAAI,aAAa,KAAA,GAAW;KAC1B,SAAS,QAAQ,oBAAoB;KACrC,MAAM,MAAM,MAAM,KAAK,SAAS,QAAQ,CAAC,CAAC,MAAK,UAAS,iBAAiB,eAAe,WAAW,OAAO,MAAM,CAAC;KACjH,MAAM,UAAU,MAAM,KAAK,SAAS,QAAQ,CAAC,CAAC,MAAK,UAAS,iBAAiB,eAAe,WAAW,OAAO,UAAU,CAAC;KACzH,IAAI,QAAQ,KAAA,GAAW;MACrB,IAAI,QAAQ,uBAAuB;MACnC,mBAAmB,KAAK,UAAU,CAAC,EAAE,aAAa,iCAAiC,MAAM;KAC3F;KACA,IAAI,YAAY,KAAA,GAAW;MACzB,QAAQ,QAAQ,2BAA2B;MAC3C,mBAAmB,SAAS,SAAS,CAAC,EAAE,aAAa,mCAAmC,MAAM;MAC9F,mBAAmB,SAAS,UAAU,CAAC,EAAE,aAAa,oCAAoC,MAAM;KAClG;IACF;IACA,IAAI,YAAY,KAAA,GAAW;IAC3B,QAAQ,QAAQ,mBAAmB;IACnC,SAAS,mBAAmB,SAAS,SAAS;IAC9C,IAAI,YAAY,QAAQ;IACxB,OAAO,cAAc,KAAA,KAAa,cAAc,QAAQ,cAAc,WAAW,CAAC,WAAW,WAAW,OAAO,GAAG,YAAY,UAAU;IACxI,cAAc,cAAc,WAAW,cAAc,OAAO,YAAY,KAAA;IACxE,IAAI,gBAAgB,KAAA,GAAW;IAC/B,YAAY,QAAQ,uBAAuB;IAC3C,KAAK,MAAM,SAAS,YAAY,iBAA8B,iCAA+B,GAC3F,IAAI,MAAM,aAAa,KAAK,MAAM,mBAAmB,MAAM,cAAc;IAE3E,IAAI,WAAW,KAAA,GAAW,OAAO,QAAQ,kBAAkB;IAC3D,MAAM,YAAY,WAAW,aAAa,YAAY;IACtD,QAAQ,QAAQ,OAAO,OAAO,CAAC,SAAS;IACxC,SAAS,SAAS;GACpB;GACA,MAAM,iBAAuB;IAAE,IAAI,cAAc,GAAG,YAAY,sBAAsB,IAAI;GAAE;GAC5F,MAAM,WAAW,IAAI,iBAAiB,QAAQ;GAC9C,SAAS,QAAQ,SAAS,MAAM;IAAE,WAAW;IAAM,SAAS;IAAM,YAAY;IAAM,iBAAiB;KAAC;KAAS;KAAS;IAAU;GAAE,CAAC;GACrI,SAAS,iBAAiB,eAAe;IAAE,IAAI,SAAS,QAAQ,SAAS,QAAQ,QAAQ,MAAM;GAAE,CAAC;GAClG,KAAK;GACL,aAAa;IACX,SAAS,WAAW;IACpB,SAAS,oBAAoB,SAAS,eAAe,IAAI;IACzD,IAAI,qBAAqB,GAAG,OAAO,aAAa,gBAAgB;IAChE,YAAY,OAAO;IACnB,IAAI,cAAc,GAAG,qBAAqB,SAAS;IACnD,IAAI,oBAAoB,GAAG,qBAAqB,eAAe;IAC/D,IAAI,2BAA2B,GAAG,qBAAqB,sBAAsB;IAC7E,IAAI,oBAAoB,GAAG,aAAa,eAAe;IACvD,kBAAkB,gBAAgB,iCAAiC;IACnE,iBAAiB,oBAAoB,UAAU,eAAe;IAC9D,SAAS,oBAAoB,eAAe,eAAe,IAAI;IAC/D,SAAS,oBAAoB,WAAW,WAAW,IAAI;IACvD,SAAS,oBAAoB,SAAS,iBAAiB;IACvD,SAAS,OAAO;IAChB,SAAS,gBAAgB,UAAU,OAAO,0BAA0B;IACpE,OAAO,SAAS,gBAAgB,QAAQ;GAC1C;EACF;;;EClVA,MAAM,oBAA8C,CAAC;EACrD,IAAI;EACJ,IAAI,OAAO,WAAW,eAAe,OAAO,cAAc,KAAA,GACxD,OAAO,YAAY;GACjB,WAAU,UAAS;IAAE,oBAAoB;GAAM;GAC/C,SAAQ,eAAc;IAAE,kBAAkB,KAAK,UAAU;GAAE;EAC7D;EAGF,SAAS,eAAe,UAA2B;GACjD,OAAO,aAAa,eAAe,aAAa,eAAe,aAAa,SAAS,aAAa;EACpG;;;;;;;EAQA,SAAgB,oCAAoC,YAAgD;GAClG,MAAM,WAAW,WAAW;GAC5B,WAAW,aAAa;GACxB,aAAa;IAAE,WAAW,aAAa;GAAS;EAClD;EAEA,SAAS,QAA+C,KAAQ,WAA8C;GAC5G,MAAM,OAAO,SAAS,cAAc,GAAG;GACvC,IAAI,cAAc,KAAA,GAAW,KAAK,YAAY;GAC9C,OAAO;EACT;EAEA,eAAe,YAAY,MAAc,MAAsD;GAC7F,MAAM,WAAW,MAAM,MAAM,MAAM;IAAE,GAAG;IAAM,SAAS;KAAE,gBAAgB;KAAoB,GAAG,MAAM;IAAQ;GAAE,CAAC;GACjH,MAAM,OAAO,MAAM,SAAS,KAAK;GACjC,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,QAAQ,OAAO,SAAS,MAAM,GAAG;GACjH,OAAO;EACT;EAEA,SAAS,uBAAuB,OAAwB;GACtD,IAAI,OAAO,UAAU,YAAY,MAAM,SAAS,MAAM,OAAO;GAC7D,IAAI;GACJ,IAAI;IAAE,MAAM,IAAI,IAAI,KAAK;GAAE,QAAQ;IAAE,OAAO;GAAG;GAC/C,MAAM,aAAa,IAAI,SAAS,CAAC,CAAC,QAAQ,QAAQ,EAAE;GACpD,IAAI,eAAe,uCAAuC,eAAe,iCAAiC,OAAO;GACjH,IAAI,IAAI,aAAa,YAAY,IAAI,aAAa,yBAAyB,IAAI,SAAS,MACnF,IAAI,aAAa,MAAM,IAAI,aAAa,IAAI,OAAO;GACxD,OAAO,IAAI,SAAS;EACtB;EAEA,SAAS,iBAA6D;GACpE,MAAM,OAAO,QAAQ,OAAO,oBAAoB;GAChD,MAAM,QAAQ,QAAQ,WAAW,2BAA2B;GAAG,MAAM,SAAS;GAC9E,MAAM,aAAa,cAAc,MAAM;GACvC,MAAM,SAAS,QAAQ,UAAU,4BAA4B;GAC7D,MAAM,QAAQ,QAAQ,IAAI;GAAG,MAAM,cAAc;GACjD,MAAM,QAAQ,QAAQ,UAAU,2BAA2B;GAAG,MAAM,OAAO;GAAU,MAAM,cAAc;GAAK,MAAM,aAAa,cAAc,QAAQ;GACvJ,MAAM,WAAW,QAAQ,OAAO,8BAA8B;GAC9D,MAAM,SAAS,QAAQ,UAAU,mCAAmC;GAAG,OAAO,OAAO;GAAU,OAAO,cAAc;GACpH,MAAM,YAAY,QAAQ,UAAU,yBAAyB;GAAG,UAAU,OAAO;GAAU,UAAU,cAAc;GACnH,OAAO,aAAa,gBAAgB,MAAM;GAAG,UAAU,aAAa,gBAAgB,OAAO;GAAG,SAAS,OAAO,QAAQ,SAAS;GAC/H,MAAM,UAAU,QAAQ,OAAO,0BAA0B;GACzD,MAAM,SAAS,QAAQ,OAAO,4BAA4B;GAAG,OAAO,SAAS;GAC7E,MAAM,cAAc,QAAQ,QAAQ,kCAAkC;GAAG,YAAY,cAAc;GACnG,MAAM,aAAa,QAAQ,KAAK,iCAAiC;GAAG,WAAW,SAAS;GAAU,WAAW,MAAM;GACnH,OAAO,OAAO,aAAa,UAAU;GACrC,MAAM,QAAQ,QAAQ,OAAO,wBAAwB;GAAG,MAAM,SAAS;GACvE,MAAM,SAAS,QAAQ,KAAK,4BAA4B;GAAG,OAAO,cAAc;GAChF,MAAM,kBAAkB,QAAQ,KAAK,gCAAgC;GAAG,gBAAgB,SAAS;GACjG,MAAM,UAAU,QAAQ,OAAO,6BAA6B;GAC5D,MAAM,SAAS,QAAQ,UAAU,+BAA+B;GAAG,OAAO,OAAO;GACjF,MAAM,OAAO,QAAQ,UAAU,6BAA6B;GAAG,KAAK,OAAO;GAAU,KAAK,cAAc;GACxG,MAAM,WAAW,QAAQ,UAAU,+BAA+B;GAAG,SAAS,OAAO;GAAU,SAAS,cAAc;GACtH,MAAM,YAAY,QAAQ,OAAO,gCAAgC;GACjE,MAAM,gBAAgB,QAAQ,UAAU,4BAA4B;GAAG,cAAc,OAAO;GAAU,cAAc,cAAc;GAClI,MAAM,WAAW,QAAQ,UAAU,4BAA4B;GAAG,SAAS,OAAO;GAAU,SAAS,cAAc;GACnH,UAAU,OAAO,eAAe,QAAQ;GACxC,MAAM,cAAc,QAAQ,OAAO,6BAA6B;GAAG,YAAY,SAAS;GACxF,MAAM,aAAa,QAAQ,OAAO,oCAAoC;GAAG,WAAW,SAAS;GAC7F,MAAM,cAAc,QAAQ,KAAK,2BAA2B;GAAG,YAAY,cAAc;GACzF,MAAM,kBAAkB,QAAQ,WAAW,sCAAsC;GACjF,MAAM,kBAAkB,QAAQ,MAAM,mCAAmC;GAAG,gBAAgB,cAAc;GAC1G,MAAM,eAAe,QAAQ,OAAO,mCAAmC;GACvE,MAAM,qBAAqB,QAAQ,UAAU,0CAA0C;GAAG,mBAAmB,OAAO;GAAU,mBAAmB,aAAa,cAAc,eAAe;GAAG,mBAAmB,aAAa,iBAAiB,OAAO;GAAG,mBAAmB,aAAa,iBAAiB,0BAA0B;GAAG,mBAAmB,aAAa,oBAAoB,0BAA0B;GACrZ,MAAM,oBAAoB,QAAQ,QAAQ,yCAAyC;GAAG,kBAAkB,cAAc;GAAK,kBAAkB,aAAa,eAAe,MAAM;GAC/K,MAAM,sBAAsB,QAAQ,OAAO,2CAA2C;GAAG,oBAAoB,KAAK;GAA4B,oBAAoB,aAAa,QAAQ,SAAS;GAAG,oBAAoB,SAAS;GAChO,MAAM,oBAAoB,QAAQ,QAAQ;GAAG,kBAAkB,cAAc;GAC7E,MAAM,mBAAmB,QAAQ,MAAM;GAAG,iBAAiB,cAAc;GACzE,mBAAmB,OAAO,iBAAiB;GAAG,oBAAoB,OAAO,mBAAmB,gBAAgB;GAAG,aAAa,OAAO,oBAAoB,mBAAmB;GAC1K,MAAM,kBAAkB,QAAQ,OAAO,sCAAsC;GAAG,gBAAgB,aAAa,QAAQ,YAAY;GAAG,gBAAgB,aAAa,cAAc,QAAQ;GACvL,MAAM,kBAAkB,QAAQ,UAAU,8BAA8B;GAAG,gBAAgB,OAAO;GAAU,gBAAgB,aAAa,QAAQ,OAAO;GAAG,gBAAgB,aAAa,gBAAgB,MAAM;GAC9M,MAAM,qBAAqB,QAAQ,QAAQ,kCAAkC;GAC7E,MAAM,sBAAsB,QAAQ,QAAQ;GAAG,oBAAoB,cAAc;GACjF,MAAM,uBAAuB,QAAQ,QAAQ,oCAAoC;GAAG,qBAAqB,cAAc;GACvH,MAAM,6BAA6B,QAAQ,QAAQ,0CAA0C;GAAG,2BAA2B,cAAc;GACzI,mBAAmB,OAAO,qBAAqB,oBAAoB;GAAG,gBAAgB,OAAO,oBAAoB,0BAA0B;GAC3I,MAAM,eAAe,QAAQ,UAAU,8BAA8B;GAAG,aAAa,OAAO;GAAU,aAAa,aAAa,QAAQ,OAAO;GAAG,aAAa,aAAa,gBAAgB,OAAO;GACnM,MAAM,kBAAkB,QAAQ,QAAQ,kCAAkC;GAC1E,MAAM,mBAAmB,QAAQ,QAAQ;GAAG,iBAAiB,cAAc;GAC3E,MAAM,oBAAoB,QAAQ,QAAQ,8CAA8C;GAAG,kBAAkB,cAAc;GAC3H,MAAM,0BAA0B,QAAQ,QAAQ,0CAA0C;GAAG,wBAAwB,cAAc;GACnI,gBAAgB,OAAO,kBAAkB,iBAAiB;GAAG,aAAa,OAAO,iBAAiB,uBAAuB;GACzH,gBAAgB,OAAO,iBAAiB,YAAY;GAAG,gBAAgB,OAAO,iBAAiB,cAAc,eAAe;GAC5H,MAAM,cAAc,QAAQ,WAAW,kCAAkC;GAAG,YAAY,SAAS;GACjG,MAAM,mBAAmB,QAAQ,MAAM,mCAAmC;GAAG,iBAAiB,cAAc;GAC5G,MAAM,wBAAwB,QAAQ,KAAK,sCAAsC;GAAG,sBAAsB,cAAc;GACxH,MAAM,gBAAgB,QAAQ,UAAU,6BAA6B;GAAG,cAAc,OAAO;GAAU,cAAc,cAAc;GACnI,MAAM,gBAAgB,QAAQ,OAAO,oCAAoC;GAAG,cAAc,SAAS;GACnG,MAAM,oBAAoB,QAAQ,KAAK,oCAAoC;GAAG,kBAAkB,cAAc;GAC9G,MAAM,qBAAqB,QAAQ,OAAO,8BAA8B;GACxE,MAAM,eAAe,QAAQ,KAAK,+BAA+B;GAAG,aAAa,OAAO;GAAuC,aAAa,SAAS;GAAU,aAAa,MAAM;GAAuB,aAAa,cAAc;GACpO,MAAM,kBAAkB,QAAQ,KAAK,+BAA+B;GAAG,gBAAgB,OAAO;GAAqC,gBAAgB,SAAS;GAAU,gBAAgB,MAAM;GAAuB,gBAAgB,cAAc;GACjP,mBAAmB,OAAO,cAAc,eAAe;GACvD,MAAM,mBAAmB,QAAQ,SAAS,iCAAiC;GAAG,iBAAiB,cAAc;GAC7G,MAAM,cAAc,QAAQ,SAAS,2BAA2B;GAAG,YAAY,OAAO;GAAY,YAAY,eAAe;GAAO,YAAY,aAAa;GAAO,YAAY,cAAc;GAAuB,iBAAiB,OAAO,WAAW;GACxP,MAAM,kBAAkB,QAAQ,UAAU,gEAAgE;GAAG,gBAAgB,OAAO;GAAU,gBAAgB,cAAc;GAC5K,cAAc,OAAO,mBAAmB,oBAAoB,kBAAkB,eAAe;GAC7F,MAAM,gBAAgB,QAAQ,WAAW,6BAA6B;GACtE,MAAM,uBAAuB,QAAQ,SAAS;GAAG,qBAAqB,cAAc;GACpF,MAAM,oBAAoB,QAAQ,OAAO,kCAAkC;GAC3E,MAAM,oBAAoB,QAAQ,GAAG;GAAG,kBAAkB,cAAc;GACxE,MAAM,gBAAgB,QAAQ,QAAQ,6BAA6B;GAAG,cAAc,cAAc;GAClG,MAAM,iBAAiB,QAAQ,KAAK,+BAA+B;GAAG,eAAe,OAAO;GAAmC,eAAe,SAAS;GAAU,eAAe,MAAM;GAAuB,eAAe,cAAc;GAC1O,MAAM,cAAc,QAAQ,KAAK,+BAA+B;GAAG,YAAY,OAAO;GAA8B,YAAY,SAAS;GAAU,YAAY,MAAM;GAAuB,YAAY,cAAc;GACtN,MAAM,cAAc,QAAQ,UAAU,4BAA4B;GAAG,YAAY,OAAO;GAAU,YAAY,cAAc;GAC5H,kBAAkB,OAAO,mBAAmB,eAAe,gBAAgB,aAAa,WAAW;GAAG,cAAc,OAAO,sBAAsB,iBAAiB;GAClK,YAAY,OAAO,kBAAkB,uBAAuB,eAAe,eAAe,aAAa;GACvG,MAAM,gBAAgB,QAAQ,WAAW,6BAA6B;GACtE,MAAM,uBAAuB,QAAQ,SAAS;GAAG,qBAAqB,cAAc;GACpF,MAAM,oBAAoB,QAAQ,OAAO,kCAAkC;GAC3E,MAAM,oBAAoB,QAAQ,GAAG;GAAG,kBAAkB,cAAc;GACxE,kBAAkB,OAAO,iBAAiB;GAAG,cAAc,OAAO,sBAAsB,iBAAiB;GACzG,MAAM,eAAe,QAAQ,OAAO,4BAA4B;GAAG,aAAa,SAAS;GACzF,MAAM,oBAAoB,QAAQ,QAAQ,kCAAkC;GAAG,kBAAkB,cAAc;GAC/G,MAAM,mBAAmB,QAAQ,KAAK,iCAAiC;GAAG,iBAAiB,SAAS;GAAU,iBAAiB,MAAM;GAAc,aAAa,OAAO,mBAAmB,gBAAgB;GAC1M,MAAM,WAAW,QAAQ,OAAO,wBAAwB;GAAG,SAAS,SAAS;GAC7E,MAAM,eAAe,QAAQ,KAAK,4BAA4B;GAAG,aAAa,cAAc;GAAa,aAAa,aAAa,aAAa,QAAQ;GACxJ,MAAM,cAAc,QAAQ,WAAW,2BAA2B;GAAG,YAAY,SAAS;GAAM,YAAY,aAAa,cAAc,uBAAuB;GAC9J,MAAM,mBAAmB,QAAQ,MAAM,iCAAiC;GAAG,iBAAiB,cAAc;GAC1G,MAAM,qBAAqB,QAAQ,KAAK,mCAAmC;GAAG,mBAAmB,cAAc;GAC/G,MAAM,mBAAmB,QAAQ,MAAM,iCAAiC;GACxE,KAAK,MAAM,QAAQ;IAAC;IAA4B;IAA2B;GAAsB,GAAG;IAClG,MAAM,OAAO,QAAQ,IAAI;IAAG,KAAK,cAAc;IAAM,iBAAiB,OAAO,IAAI;GACnF;GACA,MAAM,kBAAkB,QAAQ,KAAK,gCAAgC;GAAG,gBAAgB,cAAc;GACtG,MAAM,qBAAqB,QAAQ,OAAO,mCAAmC;GAC7E,MAAM,cAAc,QAAQ,UAAU,6BAA6B;GAAG,YAAY,OAAO;GAAU,YAAY,cAAc;GAC7H,MAAM,mBAAmB,QAAQ,UAAU,+BAA+B;GAAG,iBAAiB,OAAO;GAAU,iBAAiB,cAAc;GAC9I,mBAAmB,OAAO,aAAa,gBAAgB;GAAG,YAAY,OAAO,kBAAkB,oBAAoB,kBAAkB,iBAAiB,kBAAkB;GACxK,MAAM,gBAAgB,QAAQ,OAAO,6BAA6B;GAClE,MAAM,eAAe,QAAQ,UAAU,6BAA6B;GAAG,aAAa,OAAO;GAAU,aAAa,cAAc;GAChI,MAAM,cAAc,QAAQ,UAAU,6BAA6B;GAAG,YAAY,OAAO;GAAU,YAAY,cAAc;GAAQ,YAAY,SAAS;GAC1J,MAAM,kBAAkB,QAAQ,UAAU,+BAA+B;GAAG,gBAAgB,OAAO;GAAU,gBAAgB,cAAc;GAAQ,gBAAgB,SAAS;GAC5K,MAAM,aAAa,QAAQ,UAAU,+BAA+B;GAAG,WAAW,OAAO;GAAU,WAAW,cAAc;GAAa,WAAW,WAAW;GAC/J,cAAc,OAAO,cAAc,aAAa,iBAAiB,UAAU;GAC3E,MAAM,kBAAkB,QAAQ,OAAO,gCAAgC;GACvE,MAAM,gBAAgB,QAAQ,UAAU,4BAA4B;GAAG,cAAc,OAAO;GAAU,cAAc,cAAc;GAAU,cAAc,WAAW;GACrK,MAAM,cAAc,QAAQ,UAAU,4BAA4B;GAAG,YAAY,OAAO;GAAU,YAAY,cAAc;GAC5H,gBAAgB,OAAO,eAAe,WAAW;GACjD,MAAM,oBAAoB,QAAQ,OAAO,6BAA6B;GAAG,kBAAkB,SAAS;GACpG,OAAO,OAAO,OAAO,KAAK;GAAG,QAAQ,OAAO,QAAQ,MAAM,QAAQ;GAClE,QAAQ,OAAO,QAAQ,OAAO,QAAQ,iBAAiB,SAAS,WAAW,WAAW;GACtF,WAAW,OAAO,aAAa,iBAAiB,aAAa,eAAe,cAAc,UAAU,cAAc,aAAa,eAAe,iBAAiB,iBAAiB;GAChL,MAAM,OAAO,QAAQ,UAAU,SAAS,UAAU;GAAG,KAAK,OAAO,KAAK;GAAG,SAAS,KAAK,OAAO,IAAI;GAClG,IAAI,UAAU;GACd,IAAI,SAAS;GACb,IAAI,gBAAgB;GACpB,IAAI,cAAc;GAClB,IAAI,iBAAyC;GAC7C,IAAI,iBAAiB;GACrB,IAAI,iBAAiB;GACrB,IAAI,qBAAqB;GACzB,IAAI,sBAAsB;GAC1B,IAAI,sBAAsB;GAC1B,IAAI,qBAAqB;GACzB,IAAI,kBAAkB;GACtB,IAAI,mBAAmB;GACvB,IAAI,qBAAqB;GACzB,IAAI,sBAAsB;GAC1B,MAAM,yBAA+B;IACnC,MAAM,OAAO,sBAAsB,uBAAuB,aAAa,SAAS,SAAS,aAAa;IACtG,oBAAoB,SAAS,CAAC;IAC9B,mBAAmB,aAAa,iBAAiB,OAAO,IAAI,CAAC;GAC/D;GACA,aAAa,iBAAiB,sBAAsB;IAAE,sBAAsB;IAAM,iBAAiB;GAAE,CAAC;GACtG,aAAa,iBAAiB,sBAAsB;IAAE,sBAAsB;IAAO,iBAAiB;GAAE,CAAC;GACvG,aAAa,iBAAiB,WAAW,gBAAgB;GACzD,aAAa,iBAAiB,kBAAkB;IAAE,OAAO,WAAW,kBAAkB,CAAC;GAAE,CAAC;GAC1F,mBAAmB,iBAAiB,eAAe;IAAE,qBAAqB,CAAC;IAAoB,iBAAiB;GAAE,CAAC;GACnH,mBAAmB,iBAAiB,YAAW,UAAS;IACtD,IAAI,MAAM,QAAQ,UAAU;IAC5B,qBAAqB;IACrB,sBAAsB;IACtB,oBAAoB,SAAS;IAC7B,mBAAmB,aAAa,iBAAiB,OAAO;GAC1D,CAAC;GACD,MAAM,cAAc,WAA0B;IAC5C,QAAQ,SAAS;IACjB,WAAW,SAAS,CAAC;IACrB,OAAO,UAAU,OAAO,aAAa,CAAC,MAAM;IAC5C,UAAU,UAAU,OAAO,aAAa,MAAM;IAC9C,OAAO,aAAa,gBAAgB,OAAO,CAAC,MAAM,CAAC;IACnD,UAAU,aAAa,gBAAgB,OAAO,MAAM,CAAC;IACrD,MAAM,cAAc,SAAS,SAAS;GACxC;GACA,OAAO,iBAAiB,eAAe;IAAE,WAAW,KAAK;GAAE,CAAC;GAC5D,UAAU,iBAAiB,eAAe;IAAE,WAAW,IAAI;IAAG,WAAW;GAAE,CAAC;GAC5E,MAAM,WAAW,SAAwB;IACvC,MAAM,SAAS,CAAC;IAChB,KAAK,MAAM,WAAW,SAAS,iBAAiB,8BAA8B,GAAG,QAAQ,aAAa,iBAAiB,OAAO,IAAI,CAAC;GACrI;GACA,MAAM,UAAU,SAAwC;IACtD,UAAU,KAAK,YAAY;IAC3B,SAAS,WAAW,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;IACpE,OAAO,SAAS,WAAW;IAC3B,WAAW,OAAO;IAClB,WAAW,cAAc;IACzB,WAAW,QAAQ;IACnB,OAAO,UAAU,OAAO,cAAc,OAAO;IAC7C,OAAO,cAAc,UAAU,cAAc;IAC7C,MAAM,gBAAgB,KAAK;IAC3B,IAAI,kBAAkB,QAAQ,OAAO,kBAAkB,UAAU;KAC/D,MAAM,SAAS,OAAQ,cAAuC,WAAW,WAAY,cAAqC,SAAS;KACnI,MAAM,SAAS,OAAQ,cAAuC,WAAW,WAAY,cAAqC,SAAS;KACnI,gBAAgB,SAAS;KACzB,gBAAgB,cAAc,WAAW,IAAI,MAAM,OAAO,MAAM,EAAE,SAAS,MAAM,OAAO,MAAM,EAAE,QAAQ,OAAO,MAAM,EAAE;IACzH,OAAO,gBAAgB,SAAS;IAChC,IAAI,CAAC,SAAS,MAAM,SAAS;IAC7B,OAAO,cAAc,UAAU,YAAY;IAC3C,KAAK,WAAW,CAAC;IACjB,SAAS,WAAW,CAAC;IACrB,cAAc,WAAW,CAAC;IAC1B,SAAS,WAAW,CAAC;GACvB;GACA,MAAM,UAAU,KAAa,SAAyB,UAAgB;IACpE,OAAO,gBAAgB;IACvB,IAAI,QAAQ,IAAI;KAAE,OAAO,SAAS;KAAM;IAAO;IAC/C,MAAM,QAAQ,QAAQ,KAAK;IAC3B,MAAM,MAAM;IACZ,MAAM,QAAQ;IACd,MAAM,SAAS;IACf,MAAM,MAAM,6BAA6B,KAAK,GAAG;IACjD,OAAO,SAAS;IAChB,OAAO,OAAO,KAAK;GACrB;GACA,MAAM,eAAe,WAAiC;IACpD,YAAiB,uCAAuC;KAAE,QAAQ;KAAQ,MAAM;IAAK,CAAC,CAAC,CAAC,KAAK,OAAM,SAAQ;KACzG,MAAM,QAAQ,WAAW,QACpB,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS,KAChD,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU;KACvD,OAAO,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,EAAE;KACvD,IAAI,UAAU,IAAI;MAAE,OAAO,cAAc;MAAa;KAAO;KAC7D,IAAI;MACF,MAAM,UAAU,UAAU,UAAU,KAAK;MACzC,OAAO,cAAc,WAAW,QAC5B,8BACA;KACN,QAAQ;MACN,OAAO,cAAc,MAAM,WAAW,QAAQ,SAAS,OAAO,GAAG;MACjE,OAAO,UAAU,IAAI,QAAQ;KAC/B;IACF,IAAG,UAAS;KAAE,OAAO,cAAc,OAAO,KAAK;IAAE,CAAC,CAAC,CAAC,cAAc;KAChE,KAAK,WAAW,CAAC;KACjB,SAAS,WAAW,CAAC;IACvB,CAAC;GACH;GACA,OAAO,iBAAiB,eAAe;IAAE,OAAO,WAAW;IAAM,YAAiB,kCAAkC;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,CAAC,QAAQ,CAAC;IAAE,CAAC,CAAC,CAAC,KAAK,SAAQ,UAAS;KAAE,OAAO,cAAc,OAAO,KAAK;IAAE,CAAC,CAAC,CAAC,cAAc;KAAE,OAAO,WAAW;IAAM,CAAC;GAAE,CAAC;GAC/R,MAAM,cAAc,OAAwB,OAAO,OAAO,WAAW,IAAI,KAAK,EAAE,CAAC,CAAC,eAAe,IAAI;GACrG,MAAM,iBAAiB,SAAwC;IAC7D,MAAM,UAAU,MAAM,QAAQ,KAAK,OAAO,IAAI,KAAK,UAAuC,CAAC;IAC3F,YAAY,gBAAgB;IAC5B,IAAI,QAAQ,WAAW,GAAG;KACxB,MAAM,QAAQ,QAAQ,KAAK,kCAAkC;KAAG,MAAM,cAAc;KACpF,YAAY,OAAO,KAAK;KACxB;IACF;IACA,KAAK,MAAM,UAAU,SAAS;KAC5B,MAAM,MAAM,QAAQ,OAAO,4BAA4B;KACvD,MAAM,QAAQ,QAAQ,QAAQ,kCAAkC;KAChE,MAAM,cAAc,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ;KACtE,MAAM,OAAO,QAAQ,QAAQ,iCAAiC;KAAG,KAAK,cAAc,MAAM,WAAW,OAAO,SAAS;KACrH,MAAM,SAAS,QAAQ,UAAU,mCAAmC;KAAG,OAAO,OAAO;KAAU,OAAO,cAAc;KACpH,MAAM,KAAK,OAAO,OAAO,OAAO,WAAW,OAAO,KAAK;KACvD,OAAO,iBAAiB,eAAe;MACrC,YAAiB,yCAAyC;OAAE,QAAQ;OAAQ,MAAM,KAAK,UAAU,EAAE,UAAU,GAAG,CAAC;MAAE,CAAC,CAAC,CAClH,KAAK,cAAa,UAAS;OAAE,OAAO,cAAc,OAAO,KAAK;MAAE,CAAC;KACtE,CAAC;KACD,IAAI,OAAO,OAAO,MAAM,MAAM;KAC9B,YAAY,OAAO,GAAG;IACxB;GACF;GACA,MAAM,oBAA0B;IAC9B,YAAiB,gCAAgC,CAAC,CAAC,KAAK,gBAAe,UAAS;KAAE,OAAO,cAAc,OAAO,KAAK;IAAE,CAAC;GACxH;GACA,cAAc,iBAAiB,eAAe;IAC5C,MAAM,OAAO,YAAY;IACzB,YAAY,SAAS,CAAC;IACtB,IAAI,MAAM,YAAY;GACxB,CAAC;GACD,SAAS,iBAAiB,eAAe;IACvC,IAAI,CAAC,OAAO,QAAQ,6BAA6B,GAAG;IACpD,YAAiB,wCAAwC;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,KAAK,CAAC;IAAE,CAAC,CAAC,CAClH,KAAK,cAAa,UAAS;KAAE,OAAO,cAAc,OAAO,KAAK;IAAE,CAAC;GACtE,CAAC;GACD,MAAM,gBAAgB,SAAwC;IAC5D,gBAAgB,KAAK,YAAY;IACjC,iBAAiB,KAAK,aAAa,WAAW,WAAW;IACzD,MAAM,SAAS,mBAAmB;IAClC,gBAAgB,UAAU,OAAO,eAAe,CAAC,MAAM;IACvD,aAAa,UAAU,OAAO,eAAe,MAAM;IACnD,gBAAgB,aAAa,gBAAgB,OAAO,CAAC,MAAM,CAAC;IAC5D,aAAa,aAAa,gBAAgB,OAAO,MAAM,CAAC;IACxD,gBAAgB,WAAW;IAC3B,aAAa,WAAW;IACxB,YAAY,SAAS,CAAC;IACtB,cAAc,SAAS;IACvB,YAAY,cAAc,SAAS,cAAc;IACjD,MAAM,YAAY,KAAK,cAAc,QAAQ,OAAO,KAAK,cAAc,WAAW,KAAK,YAAuC,CAAC;IAC/H,MAAM,iBAAiB,UAAU,WAAW,QAAQ,OAAO,UAAU,WAAW,WAAW,UAAU,SAAoC,CAAC;IAC1I,MAAM,YAAY,eAAe,cAAc,QAAQ,OAAO,eAAe,cAAc,WACvF,eAAe,YACf,CAAC;IACL,kBAAkB,UAAU,cAAc;IAC1C,mBAAmB,UAAU,eAAe;IAC5C,kBAAkB,cAAc,mBAAmB,QAAQ,kBAAkB,QAAQ;IACrF,MAAM,kBAAkB,UAAU,cAAc;IAChD,MAAM,mBAAmB,OAAO,UAAU,YAAY,WAAW,UAAU,UAAU;IACrF,MAAM,yBAAyB,OAAO,UAAU,kBAAkB,WAAW,UAAU,gBAAgB;IACvG,MAAM,mBAAmB,OAAO,UAAU,gBAAgB,WAAW,UAAU,cAAc;IAC7F,cAAc,cAAc;IAC5B,cAAc,QAAQ;IACtB,cAAc,SAAS,mBAAmB,CAAC;IAC3C,cAAc,cAAc,yBAAyB,IACjD,aAAa,yBAAyB,OAAO,KAAA,CAAM,QAAQ,CAAC,EAAE,OAC9D;IACJ,cAAc,WAAW;IACzB,cAAc,SAAS,CAAC,mBAAmB;IAC3C,gBAAgB,WAAW;IAC3B,YAAY,SAAS,CAAC,mBAAmB,CAAC;IAC1C,sBAAsB,cAAc,CAAC,kBACjC,iDACA,CAAC,kBACC,wCACA,CAAC,mBACC,QAAQ,iBAAiB,qBACzB,QAAQ,iBAAiB;IACjC,MAAM,QAAQ,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ;IAC5D,MAAM,YAAY,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;IACxE,MAAM,eAAe,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;IACrE,iBAAiB,OAAO,KAAK,aAAa,WAAW,KAAK,WAAW;IACrE,MAAM,oBAAoB,SAAS,KAAK,uBAAuB,KAAK,QAAQ;IAM5E,iBAAiB,sBAAsB,KAAK,oBAAqB;KAJ/D,4BAA4B;KAC5B,uBAAuB;KACvB,qBAAqB;IAE0D,EAAE,cAAc;IACjG,MAAM,mBAAmB,UAAU,WAAW,mBAAmB;IACjE,cAAc,iBAAiB,UAAU,WAAW,iBAAiB;IACrE,aAAa,SAAS,CAAC;IACvB,iBAAiB,OAAO;IACxB,iBAAiB,cAAc;IAC/B,iBAAiB,QAAQ;IACzB,aAAa,UAAU,OAAO,cAAc,WAAW;IACvD,MAAM,SAAiC;KACrC,KAAK;KACL,aAAa,SAAS,2BAA2B;KACjD,UAAU,SAAS,sBAAsB;KACzC,eAAe;KACf,YAAY,SAAS,2BAA2B;KAChD,OAAO;KACP,OAAO;IACT;IAoBA,aAAa,cAAc,sBAAsB,mBAC7C,6CACC,UAAU,UAAW;KApBxB,4BAA4B;KAC5B,uBAAuB;KACvB,qBAAqB;KACrB,uBAAuB;KACvB,sBAAsB;KACtB,wBAAwB;KACxB,0BAA0B;KAC1B,0BAA0B;KAC1B,uBAAuB;KACvB,uBAAuB;KACvB,yBAAyB;KACzB,sBAAsB;KACtB,sBAAsB;KACtB,gBAAgB;KAChB,eAAe;KACf,uBAAuB;KACvB,uBAAuB;IAIW,EAAE,cAAc,OAAO,QAAW,OAAO,UAAU,OAAO;IAC9F,YAAY,SAAS,CAAC;IACtB,YAAY,WAAW,mBAAmB,MAAM;IAChD,iBAAiB,WAAW;IAC5B,aAAa,cAAc,gBAAgB,WAAW;IACtD,aAAa,WAAW,sBAAuB,WAAW,CAAC,mBAAmB,CAAC;IAC/E,YAAY,SAAS,UAAU,UAAU,iBAAiB,mBAAmB;IAC7E,gBAAgB,SAAS,oBAAqB,UAAU,WAAW,UAAU,iBACvE,WAAW,CAAC,mBAAmB,CAAC;IACtC,cAAc,SAAS,WAAW,CAAC,mBAAmB,CAAC;IACvD,WAAW,WAAW,CAAC;IACvB,cAAc,WAAW,CAAC;IAC1B,IAAI,CAAC,aAAa,SAAS,SAAS;IACpC,IAAI,CAAC,kBAAkB,qBAAqB;GAC9C;GACA,MAAM,mBAAyB;IAC7B,YAAiB,mCAAmC,CAAC,CAAC,KAAK,eAAc,UAAS;KAAE,aAAa,cAAc,OAAO,KAAK;IAAE,CAAC;GAChI;GACA,MAAM,wBAAwB,aAA2C;IACvE,IAAI,sBAAsB,aAAa,gBAAgB;IACvD,IAAI,iBAAiB,CAAC,OAAO,QAAQ,sCAAsC,GAAG;IAC9E,qBAAqB;IACrB,gBAAgB,WAAW;IAC3B,aAAa,WAAW;IACxB,aAAa,cAAc,aAAa,WAAW,kBAAkB;IACrE,YAAiB,sCAAsC;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,CAAC;IAAE,CAAC,CAAC,CAC3G,KAAK,eAAc,UAAS;KAAE,aAAa,cAAc,OAAO,KAAK;IAAE,CAAC,CAAC,CACzE,cAAc;KAAE,qBAAqB;KAAO,WAAW;IAAE,CAAC;GAC/D;GACA,gBAAgB,iBAAiB,eAAe;IAAE,qBAAqB,WAAW;GAAE,CAAC;GACrF,aAAa,iBAAiB,eAAe;IAAE,qBAAqB,QAAQ;GAAE,CAAC;GAC/E,cAAc,iBAAiB,eAAe;IAC5C,IAAI,oBAAoB;IAExB,IAAI,CADa,OAAO,QAAQ,0FACpB,GAAG;IACf,qBAAqB;IACrB,cAAc,WAAW;IACzB,cAAc,cAAc;IAC5B,aAAa,cAAc;IAC3B,YAAiB,sDAAsD;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,KAAK,CAAC;IAAE,CAAC,CAAC,CAChI,KAAK,eAAc,UAAS;KAAE,aAAa,cAAc,UAAU,OAAO,KAAK;IAAI,CAAC,CAAC,CACrF,cAAc;KAAE,qBAAqB;KAAO,WAAW;IAAE,CAAC;GAC/D,CAAC;GACD,gBAAgB,iBAAiB,eAAe;IAC9C,IAAI,oBAAoB;IACxB,MAAM,YAAY,YAAY,MAAM,KAAK;IACzC,IAAI,UAAU,SAAS,MAAM,MAAM,KAAK,SAAS,GAAG;KAClD,aAAa,cAAc;KAC3B,YAAY,MAAM;KAClB;IACF;IACA,qBAAqB;IACrB,gBAAgB,WAAW;IAC3B,gBAAgB,aAAa,aAAa,MAAM;IAChD,gBAAgB,cAAc;IAC9B,YAAiB,8CAA8C;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,UAAU,CAAC;IAAE,CAAC,CAAC,CACpH,WAAW;KACV,YAAY,QAAQ;KACpB,aAAa,cAAc;KAC3B,OAAO,YAAY,qCAAqC;MAAE,QAAQ;MAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,KAAK,CAAC;KAAE,CAAC;IACrH,CAAC,CAAC,CACD,KAAK,eAAc,UAAS;KAAE,aAAa,cAAc,QAAQ,OAAO,KAAK;IAAI,CAAC,CAAC,CACnF,cAAc;KAAE,qBAAqB;KAAO,gBAAgB,aAAa,aAAa,OAAO;KAAG,gBAAgB,cAAc;KAAS,WAAW;IAAE,CAAC;GAC1J,CAAC;GACD,YAAY,iBAAiB,eAAe;IAC1C,IAAI,oBAAoB;IACxB,IAAI,CAAC,OAAO,QAAQ,qEAAqE,GAAG;IAC5F,qBAAqB;IACrB,YAAY,WAAW;IACvB,aAAa,cAAc;IAC3B,YAAiB,oDAAoD;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,KAAK,CAAC;IAAE,CAAC,CAAC,CAC9H,KAAK,eAAc,UAAS;KAAE,aAAa,cAAc,QAAQ,OAAO,KAAK;IAAI,CAAC,CAAC,CACnF,cAAc;KAAE,qBAAqB;KAAO,YAAY,WAAW;KAAO,WAAW;IAAE,CAAC;GAC7F,CAAC;GACD,aAAa,iBAAiB,eAAe;IAC3C,aAAa,WAAW;IACxB,YAAiB,qCAAqC;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,CAAC,cAAc,CAAC;IAAE,CAAC,CAAC,CACzH,KAAK,eAAc,UAAS;KAAE,aAAa,cAAc,OAAO,KAAK;IAAE,CAAC,CAAC,CACzE,QAAQ,UAAU;GACvB,CAAC;GACD,YAAY,iBAAiB,eAAe;IAC1C,IAAI,mBAAmB,IAAI,OAAO,KAAK,gBAAgB,UAAU,qBAAqB;GACxF,CAAC;GACD,MAAM,wBAA8B;IAClC,IAAI,qBAAqB;IACzB,sBAAsB;IACtB,gBAAgB,WAAW;IAC3B,YAAY,WAAW;IACvB,iBAAiB,WAAW;IAC5B,aAAa,cAAc,mBAAmB,WAAW,wBAAwB;IACjF,YAAiB,uCAAuC;KAAE,QAAQ;KAAQ,MAAM;IAAK,CAAC,CAAC,CACpF,KAAK,eAAc,UAAS;KAAE,aAAa,cAAc,OAAO,KAAK;IAAE,CAAC,CAAC,CACzE,cAAc;KACb,sBAAsB;KACtB,gBAAgB,WAAW;KAC3B,YAAY,WAAW,mBAAmB;KAC1C,iBAAiB,WAAW;IAC9B,CAAC;GACL;GACA,gBAAgB,iBAAiB,SAAS,eAAe;GACzD,iBAAiB,iBAAiB,eAAe;IAAE,qBAAqB;IAAO,gBAAgB;GAAE,CAAC;GAClG,YAAY,iBAAiB,eAAe;IAC1C,IAAI,mBAAmB,IAAI;IAC3B,qBAAqB;IACrB,sBAAsB,KAAK,IAAI;IAC/B,aAAa,cAAc;IAC3B,OAAO,KAAK,gBAAgB,UAAU,qBAAqB;GAC7D,CAAC;GACD,MAAM,wBAA8B;IAClC,IAAI,CAAC,sBAAsB,SAAS,oBAAoB,YAAY,KAAK,IAAI,IAAI,sBAAsB,KAAK;IAC5G,qBAAqB;IACrB,gBAAgB;GAClB;GACA,OAAO,iBAAiB,SAAS,eAAe;GAChD,SAAS,iBAAiB,oBAAoB,eAAe;GAC7D,WAAW,iBAAiB,eAAe;IACzC,WAAW,WAAW;IACtB,YAAiB,0CAA0C;KAAE,QAAQ;KAAQ,MAAM;IAAK,CAAC,CAAC,CAAC,KAAK,OAAM,SAAQ;KAC5G,MAAM,UAAU,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU;KAClE,OAAO,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,IAAI,QAAQ;KACjE,IAAI,YAAY,IACd,IAAI;MAAE,MAAM,UAAU,UAAU,UAAU,OAAO;KAAE,QAAQ,CAA+C;KAE5G,aAAa,cAAc;IAC7B,IAAG,UAAS;KAAE,aAAa,cAAc,OAAO,KAAK;IAAE,CAAC,CAAC,CAAC,cAAc;KAAE,WAAW,WAAW,CAAC;IAAY,CAAC;GAChH,CAAC;GACD,MAAM,uBAAuB,SAAwC;IACnE,MAAM,UAAU,MAAM,QAAQ,KAAK,OAAO,IAAI,KAAK,UAAuC,CAAC;IAC3F,kBAAkB,gBAAgB;IAClC,IAAI,QAAQ,WAAW,GAAG;KACxB,MAAM,QAAQ,QAAQ,KAAK,kCAAkC;KAAG,MAAM,cAAc;KAAa,kBAAkB,OAAO,KAAK;KAAG;IACpI;IACA,KAAK,MAAM,UAAU,SAAS;KAC5B,MAAM,MAAM,QAAQ,OAAO,4BAA4B;KACvD,MAAM,QAAQ,QAAQ,QAAQ,kCAAkC;KAAG,MAAM,cAAc,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ;KACzI,MAAM,OAAO,QAAQ,QAAQ,iCAAiC;KAAG,KAAK,cAAc,MAAM,WAAW,OAAO,SAAS;KACrH,MAAM,SAAS,QAAQ,UAAU,mCAAmC;KAAG,OAAO,OAAO;KAAU,OAAO,cAAc;KACpH,MAAM,KAAK,OAAO,OAAO,OAAO,WAAW,OAAO,KAAK;KACvD,OAAO,iBAAiB,eAAe;MACrC,YAAiB,4CAA4C;OAAE,QAAQ;OAAQ,MAAM,KAAK,UAAU,EAAE,UAAU,GAAG,CAAC;MAAE,CAAC,CAAC,CACrH,KAAK,oBAAmB,UAAS;OAAE,aAAa,cAAc,OAAO,KAAK;MAAE,CAAC;KAClF,CAAC;KACD,IAAI,OAAO,OAAO,MAAM,MAAM;KAAG,kBAAkB,OAAO,GAAG;IAC/D;GACF;GACA,MAAM,0BAAgC;IACpC,YAAiB,mCAAmC,CAAC,CAAC,KAAK,sBAAqB,UAAS;KAAE,aAAa,cAAc,OAAO,KAAK;IAAE,CAAC;GACvI;GACA,cAAc,iBAAiB,eAAe;IAC5C,MAAM,OAAO,kBAAkB;IAC/B,kBAAkB,SAAS,CAAC;IAC5B,IAAI,MAAM,kBAAkB;GAC9B,CAAC;GACD,YAAY,iBAAiB,eAAe;IAC1C,MAAM,SAAS,mBAAmB,WAC9B,qDACA;IACJ,IAAI,CAAC,OAAO,QAAQ,MAAM,GAAG;IAC7B,YAAiB,mCAAmC;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,KAAK,CAAC;IAAE,CAAC,CAAC,CAC7G,KAAK,eAAc,UAAS;KAAE,aAAa,cAAc,OAAO,KAAK;IAAE,CAAC;GAC7E,CAAC;GACD,KAAK,iBAAiB,eAAe;IAAE,KAAK,WAAW;IAAM,YAAY,KAAK;GAAE,CAAC;GACjF,SAAS,iBAAiB,eAAe;IAAE,SAAS,WAAW;IAAM,YAAY,MAAM;GAAE,CAAC;GAC1F,MAAM,iBAAiB,eAAe;IAAE,QAAQ,KAAK;GAAE,CAAC;GACxD,MAAM,WAAW,UAA8B;IAC7C,IAAI,MAAM,UAAU,EAAE,MAAM,kBAAkB,OAAO;IACrD,IAAI,CAAC,aAAa,SAAS,MAAM,MAAM,GAAG;KACxC,qBAAqB;KACrB,sBAAsB;KACtB,iBAAiB;IACnB;IACA,IAAI,CAAC,MAAM,SAAS,MAAM,MAAM,KAAK,CAAC,SAAS,cAAc,8BAA8B,CAAC,EAAE,SAAS,MAAM,MAAM,GAAG,QAAQ,KAAK;GACrI;GACA,SAAS,iBAAiB,eAAe,OAAO;GAChD,YAAiB,gCAAgC,CAAC,CAAC,KAAK,SAAQ,UAAS;IAAE,OAAO,cAAc,OAAO,KAAK;GAAE,CAAC;GAC/G,WAAW;GACX,MAAM,aAAa,OAAO,kBAAkB;IAAE,IAAI,CAAC,MAAM,UAAU,CAAC,WAAW,QAAQ,WAAW;GAAE,GAAG,IAAK;GAC5G,OAAO;IAAE,cAAc;KAAE,OAAO,cAAc,UAAU;KAAG,OAAO,oBAAoB,SAAS,eAAe;KAAG,SAAS,oBAAoB,oBAAoB,eAAe;KAAG,SAAS,oBAAoB,eAAe,OAAO;KAAG,KAAK,OAAO;IAAE;IAAG,cAAc;KAAE,QAAQ,MAAM,WAAW,KAAK;IAAE;GAAE;EAC/S;EAEA,SAAS,cAAc,MAAc,OAAoB,CAAC,GAAsB;GAC9E,MAAM,SAAS,IAAI,IAAI,MAAM,SAAS,IAAI;GAC1C,IAAI,OAAO,WAAW,SAAS,QAAQ,MAAM,IAAI,UAAU,uDAAuD;GAClH,MAAM,UAAU,IAAI,QAAQ,KAAK,OAAO;GACxC,MAAM,UAAU,KAAK,UAAU,MAAA,CAAO,YAAY;GAClD,IAAI,WAAW,SAAS,WAAW,QAAQ;IACzC,MAAM,OAAO,SAAS,OAAO,MAAM,GAAG,CAAC,CAAC,KAAI,UAAS,MAAM,KAAK,CAAC,CAAC,CAAC,MAAK,UAAS,MAAM,WAAW,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE;IAC5H,IAAI,SAAS,KAAA,GAAW,QAAQ,IAAI,qBAAqB,IAAI;GAC/D;GACA,OAAO,MAAM,QAAQ;IAAE,GAAG;IAAM;IAAS,aAAa;IAAe,OAAO;IAAY,UAAU;GAAQ,CAAC;EAC7G;EAEA,SAAS,sBAAkC;GACzC,MAAM,cAAc,QAAQ,OAAO;GAAG,YAAY,QAAQ,SAAS;GAAqB,SAAS,KAAK,OAAO,WAAW;GACxH,MAAM,WAAW,OAAO;GACxB,IAAI,cAAgD;GACpD,IAAI,eAAe;GACnB,IAAI;GACJ,IAAI;GACJ,MAAM,8BAAc,IAAI,IAAoC;GAC5D,MAAM,yBAAS,IAAI,IAAuL;GAC1M,MAAM,6BAAa,IAAI,IAA8B;GACrD,MAAM,6BAAa,IAAI,IAAoB;GAC3C,MAAM,gCAAgB,IAAI,IAAoB;GAC9C,IAAI,eAAe;GACnB,IAAI;GACJ,MAAM,sBAAwD;IAC5D,kBAAkB;IAClB,iBAAiB;IACjB,iBAAiB;IACjB,oBAAoB;GACtB;GACA,MAAM,eAAe,cAA+C;IAClE,MAAM,WAAW,SAAS,cAA2B,kCAAkC,UAAU,GAAG;IACpG,IAAI,aAAa,MAAM,OAAO;IAC9B,MAAM,QAAQ,oBAAoB;IAClC,IAAI,UAAU,KAAA,GAAW,OAAO,KAAA;IAChC,MAAM,OAAO,QAAQ,KAAK;IAAG,KAAK,QAAQ,uBAAuB;IAAW,KAAK,MAAM,UAAU;IACjG,SAAS,KAAK,OAAO,IAAI;IAAG,OAAO;GACrC;GACA,MAAM,mBAAgC;IACpC,MAAM,WAAW,SAAS,cAA2B,mCAAmC;IACxF,IAAI,aAAa,MAAM,OAAO;IAC9B,MAAM,QAAQ,QAAQ,KAAK;IAAG,MAAM,QAAQ,0BAA0B;IAAQ,MAAM,MAAM,UAAU;IACpG,SAAS,KAAK,OAAO,KAAK;IAAG,OAAO;GACtC;GACA,MAAM,SAAS,YAA0B;IACvC,MAAM,OAAO,QAAQ,KAAK;IAAG,KAAK,cAAc;IAAS,KAAK,MAAM,UAAU;IAC9E,WAAW,CAAC,CAAC,OAAO,IAAI;IAAG,OAAO,iBAAiB,KAAK,OAAO,GAAG,IAAI;GACxE;GACA,MAAM,yBAAyB,UAA4B;IACzD,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,EAAE,YAAY,UAAU,EAAE,UAAU,QAAQ,OAAO;IACtG,MAAM,YAAY;IAClB,IAAI,OAAO,UAAU,WAAW,YAAY,OAAO,UAAU,SAAS,UAAU,OAAO;IACvF,IAAI;KACF,MAAM,UAAU,KAAK,UAAU,MAAM;KACrC,MAAM,QAAQ,WAAW,KAAK,UAAS,cAAa,UAAU,WAAW,CAAC,CAAC;KAC3E,OAAO,IAAI,KAAK,CAAC,KAAK,GAAG,UAAU,MAAM,EAAE,MAAM,OAAO,UAAU,SAAS,WAAW,UAAU,OAAO,2BAA2B,CAAC;IACrI,QAAQ;KACN,OAAO;IACT;GACF;GACA,MAAM,eAAe,OAAO,QAAgB,UAAsC;IAChF,MAAM,SAAS,OAAO;IACtB,IAAI,WAAW,KAAA,GAAW,OAAO,sBAAsB,MAAM,OAAO,OAAO,QAAQ,KAAK,CAAC;IACzF,IAAI,WAAW,WAAW,OAAO,UAAU,UAAU,YAAY;KAAE,MAAM,UAAU,MAAO,SAAS,CAAC,CAAe;KAAG,OAAO,EAAE,IAAI,KAAK;IAAE;IAC1I,IAAI,WAAW,oBAAoB,UAAU,cAAc,KAAA,GAAW,OAAO,EAAE,MAAM,MAAM,UAAU,UAAU,SAAS,EAAE;IAC1H,IAAI,WAAW,qBAAqB,UAAU,cAAc,KAAA,GAAW;KAAE,MAAM,UAAU,UAAU,UAAU,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU,QAAQ,OAAQ,MAA4B,IAAI,IAAI,EAAE;KAAG,OAAO,EAAE,IAAI,KAAK;IAAE;IACnP,IAAI,WAAW,gBAAgB,WAAW,kBAAkB;KAC1D,MAAM,eAAe,QAAQ,OAAO;KAAG,aAAa,OAAO;KAAQ,aAAa,SAAS,WAAW,mBAAmB,YAAY;KAAO,IAAI,WAAW,kBAAkB,aAAa,UAAU;KAClM,OAAO,IAAI,SAA0B,YAAW;MAAE,aAAa,iBAAiB,QAAQ,aAAa,QAAQ,EAAE;MAAG,aAAa,MAAM;KAAE,CAAC;IAC1I;IACA,MAAM,IAAI,MAAM,kCAAkC;GACpD;GACA,MAAM,WAAW,IAAY,eAAiD;IAC5E,MAAM,WAAW,OAAO,IAAI,EAAE,CAAC,EAAE,4BAAY,IAAI,IAAI;IACrD,MAAM,gBAAgB,YAAyC;KAC7D,IAAI,CAAC,0BAA0B,KAAK,QAAQ,EAAE,KAAK,QAAQ,MAAM,SAAS,KAAK,MAAM,IAAI,MAAM,wBAAwB;KACvH,MAAM,YAAY,QAAQ,SAAS;KAAG,UAAU,QAAQ,mBAAmB,QAAQ;KAAI,UAAU,SAAS,QAAQ,cAAc,UAAU,QAAQ,cAAc;KAAW,UAAU,MAAM,UAAU,QAAQ,cAAc,UAAU,QAAQ,cAAc,YAAY,yHAAyH;KAEhY,CADa,QAAQ,cAAc,UAAU,QAAQ,cAAc,YAAY,WAAW,IAAI,YAAY,QAAQ,SAAS,KAAK,WAAW,EAAA,CACtI,OAAO,SAAS;KACrB,MAAM,UAAU,QAAQ,MAAM,SAAS;KACvC,MAAM,gBAAsB;MAAE,IAAI,OAAO,YAAY,YAAY,QAAQ;MAAG,UAAU,OAAO;KAAE;KAC/F,SAAS,IAAI,QAAQ,IAAI;MAAE;MAAS;KAAU,CAAC;KAC/C,aAAa;MAAE,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC,EAAE,YAAY,SAAS,SAAS,OAAO,QAAQ,EAAE;MAAG,QAAQ;KAAE;IAC3G;IACA,OAAO;KACL,MAAM;MACJ,SAAS,QAAgB,UAAmB,cAAc,6BAA6B,mBAAmB,EAAE,EAAE,WAAW,mBAAmB,MAAM,KAAK;OAAE,QAAQ;OAAQ,MAAM,KAAK,UAAU,SAAS,CAAC,CAAC;MAAE,CAAC,CAAC,CAAC,KAAK,OAAM,aAAY;OAAE,MAAM,QAAQ,MAAM,SAAS,KAAK;OAAc,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,OAAO,UAAU,YAAY,UAAU,QAAQ,WAAW,QAAQ,OAAQ,MAA6B,KAAK,IAAI,QAAQ,OAAO,SAAS,MAAM,GAAG;OAAG,OAAO;MAAM,CAAC;MAC3d,QAAQ,MAAc,SAAuB;OAC3C,IAAI,CAAC,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,IAAI,KAAK,KAAK,SAAS,KAAK,KACpE,KAAK,MAAM,GAAG,CAAC,CAAC,MAAK,SAAQ,SAAS,QAAQ,SAAS,GAAG,GAAG,MAAM,IAAI,UAAU,mCAAmC;OACzH,OAAO,cAAc,6BAA6B,mBAAmB,EAAE,EAAE,SAAS,QAAQ,IAAI;MAChG;KACF;KACA,IAAI;MAAE,iBAAiB;MAAc,OAAM,OAAM;OAAE,MAAM,QAAQ,SAAS,IAAI,EAAE;OAAG,IAAI,UAAU,KAAA,GAAW,MAAM,UAAU,SAAS;MAAM;MAAG,QAAO,OAAM;OAAE,MAAM,QAAQ,SAAS,IAAI,EAAE;OAAG,IAAI,UAAU,KAAA,GAAW,MAAM,UAAU,SAAS;MAAK;MAAG;KAAM;KAC7P,QAAQ;MAAE,cAAc,YAAY;OAAE,MAAM,SAAS,OAAO;OAAuB,OAAO,WAAW,KAAA,IAAY;QAAC;QAAc;QAAkB;QAAS;QAAkB;OAAiB,IAAI,OAAO,aAAa;MAAE;MAAG,QAAQ;KAAa;KAChP,QAAQ,WAAW;KAAQ;KAAU;IACvC;GACF;GACA,MAAM,qBAAqB,OAAO,eAAsD;IACtF,MAAM,iBAAiB,OAAO,IAAI,WAAW,EAAE;IAC/C,MAAM,aAAa,IAAI,gBAAgB;IACvC,MAAM,2BAAW,IAAI,IAA+E;IACpG,OAAO,IAAI,WAAW,IAAI;KAAE;KAAY;KAAU,eAAe;MAAE,WAAW,MAAM;MAAG,KAAK,MAAM,WAAW,SAAS,OAAO,GAAG,QAAQ,QAAQ;MAAG,SAAS,MAAM;KAAE;IAAE,CAAC;IACvK,IAAI;KACF,MAAM,UAAU,MAAM,WAAW,SAAS,QAAQ,WAAW,IAAI,UAAU,CAAC;KAC5E,MAAM,UAAU,OAAO,IAAI,WAAW,EAAE;KACxC,IAAI,YAAY,KAAA,KAAa,QAAQ,eAAe,YAAY;MAAE,IAAI,OAAO,YAAY,YAAY,QAAQ;MAAG;KAAO;KACvH,MAAM,aAAa,QAAQ;KAC3B,OAAO,IAAI,WAAW,IAAI;MAAE,GAAG;MAAS,eAAe;OAAE,IAAI,OAAO,YAAY,YAAY,QAAQ;OAAG,WAAW;MAAE;KAAE,CAAC;KACvH,gBAAgB,QAAQ;IAC1B,QAAQ;KACN,OAAO,IAAI,WAAW,EAAE,CAAC,EAAE,QAAQ;KAAG,OAAO,OAAO,WAAW,EAAE;KAAG,IAAI,mBAAmB,KAAA,GAAW,OAAO,IAAI,WAAW,IAAI,cAAc;IAChJ;GACF;GACA,MAAM,UAAU,eAA6C;IAC3D,IAAI,WAAW,eAAe,KAAK,CAAC,0BAA0B,KAAK,WAAW,EAAE,KAAK,OAAO,WAAW,aAAa,YAAY;IAChI,IAAI,yBAAyB,KAAA,KAAa,WAAW,OAAO,sBAAsB;IAClF,YAAY,IAAI,WAAW,IAAI,UAAU;IACzC,IAAI,SAAS,mBAAwB,UAAU;GACjD;GACA,IAAI,UAAU;GACd,OAAO,YAAY,OAAO,OAAO;IAAE,WAAU,UAAS;KAAE,cAAc;IAAM;IAAG;GAAO,CAAC;GACvF,KAAK,MAAM,cAAc,kBAAkB,OAAO,CAAC,GAAG,OAAO,UAAU;GACvE,IAAI,eAAe;GACnB,IAAI,mBAAmB;GACvB,MAAM,gBAAgB,YAA2B;IAC/C,IAAI;KACF,MAAM,UAAkC,CAAC;KACzC,IAAI,iBAAiB,IAAI,QAAQ,mBAAmB;KACpD,IAAI,qBAAqB,IAAI,QAAQ,uBAAuB;KAC5D,MAAM,WAAW,MAAM,MAAM,4BAA4B;MAAE,aAAa;MAAe,OAAO;MAAY;KAAQ,CAAC;KACnH,IAAI,SAAS,WAAW,KAAK;KAC7B,IAAI,CAAC,SAAS,IAAI;KAClB,eAAe,SAAS,QAAQ,IAAI,MAAM,KAAK;KAC/C,mBAAmB,SAAS,QAAQ,IAAI,eAAe,KAAK;KAC5D,MAAM,OAAO,MAAM,SAAS,KAAK;KAAG,IAAI,SAAS,cAAc;KAAQ,eAAe;KAAM,cAAc,KAAA;KAC1G,MAAM,SAAS,QAAQ,QAAQ;KAAG,OAAO,cAAc,GAAG,KAAK;KAAuC,SAAS,KAAK,OAAO,MAAM;KAAG,OAAO,OAAO;KAClJ,MAAM,QAAQ;KACd,IAAI,UAAU,KAAA,GAAW;KACzB,MAAM,WAAW,QAAQ,KAAK;KAAG,SAAS,QAAQ,qBAAqB;KAAQ,SAAS,KAAK,OAAO,QAAQ;KAC5G,MAAM,cAAc,MAAM;MAAE;MAAU,SAAS;MAAe,MAAM;MAAU;KAAO,CAAC;KACtF,gBAAgB;KAAG,YAAY,OAAO;KAAG,aAAa;KAAU,gBAAgB,OAAO,gBAAgB,aAAa,cAAc,KAAA;IACpI,QAAQ,CAAgE;GAC1E;GACA,MAAM,oBAAoB,YAA2B;IACnD,IAAI;KACF,MAAM,UAAkC,CAAC;KACzC,IAAI,iBAAiB,IAAI,QAAQ,mBAAmB;KACpD,MAAM,WAAW,MAAM,MAAM,sCAAsC;MAAE,aAAa;MAAe,OAAO;MAAY;KAAQ,CAAC;KAC7H,IAAI,SAAS,WAAW,KAAK;KAC7B,IAAI,CAAC,SAAS,IAAI;KAClB,eAAe,SAAS,QAAQ,IAAI,MAAM,KAAK;KAC/C,MAAM,UAAU,MAAM,SAAS,KAAK;KACpC,MAAM,UAAU,MAAM,QAAQ,QAAQ,UAAU,IAAI,QAAQ,aAA0C,CAAC;KACvG,MAAM,uBAAO,IAAI,IAAY;KAC7B,KAAK,MAAM,SAAS,SAAS;MAC3B,IAAI,OAAO,MAAM,OAAO,UAAU;MAClC,KAAK,IAAI,MAAM,EAAE;MACjB,MAAM,SAAS,OAAO,MAAM,aAAa,WAAW,MAAM,WAAW,KAAA;MACrE,IAAI,WAAW,KAAA,GAAW;OACxB,MAAM,aAAqC,CAAC;OAC5C,MAAM,aAAa,WAAW,IAAI,MAAM,EAAE;OAC1C,IAAI,eAAe,KAAA,GAAW,WAAW,mBAAmB;OAC5D,MAAM,cAAc,MAAM,MAAM,QAAQ;QAAE,aAAa;QAAe,OAAO;QAAY,SAAS;OAAW,CAAC;OAC9G,IAAI,YAAY,WAAW,KAAK,CAAkB,OAC7C,IAAI,YAAY,IAAI;QACvB,MAAM,WAAW,YAAY,QAAQ,IAAI,MAAM;QAAG,IAAI,aAAa,QAAQ,aAAa,IAAI,WAAW,IAAI,MAAM,IAAI,QAAQ;QAC7H,MAAM,MAAM,MAAM,YAAY,KAAK;QAAG,MAAM,WAAW,WAAW,IAAI,MAAM,EAAE;QAC9E,IAAI,UAAU,gBAAgB,KAAK;SACjC,MAAM,OAAO,QAAQ,OAAO;SAAG,KAAK,QAAQ,0BAA0B,MAAM;SAAI,KAAK,cAAc;SAAK,SAAS,KAAK,OAAO,IAAI;SAAG,WAAW,IAAI,MAAM,IAAI,IAAI;SAAG,UAAU,OAAO;QACvL;OACF,OAAO;MACT;MACA,MAAM,YAAY,OAAO,MAAM,cAAc,WAAW,MAAM,YAAY,KAAA;MAC1E,IAAI,cAAc,KAAA,GAAW;OAC3B,MAAM,gBAAwC,CAAC;OAC/C,MAAM,eAAe,cAAc,IAAI,MAAM,EAAE;OAC/C,IAAI,iBAAiB,KAAA,GAAW,cAAc,mBAAmB;OACjE,MAAM,iBAAiB,MAAM,MAAM,WAAW;QAAE,aAAa;QAAe,OAAO;QAAY,SAAS;OAAc,CAAC;OACvH,IAAI,eAAe,WAAW,KAAK,CAAkB,OAChD,IAAI,eAAe,IAAI;QAC1B,MAAM,SAAS,MAAM,eAAe,KAAK;QAAG,MAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,IAAI,YAAY,CAAC,CAAC,OAAO,MAAM,CAAC;QAAG,MAAM,MAAM,CAAC,GAAG,IAAI,WAAW,MAAM,CAAC,CAAC,CAAC,KAAI,UAAS,MAAM,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE;QACrO,IAAI,cAAc,IAAI,MAAM,EAAE,MAAM,KAAK;SACvC,cAAc,IAAI,MAAM,IAAI,GAAG;SAC/B,uBAAuB,MAAM;SAC7B,IAAI;UAAE,MAAM,SAAS,QAAQ,QAAQ;UAAG,OAAO,cAAc,GAAG,OAAO,uCAAuC,MAAM,GAAG;UAAM,SAAS,KAAK,OAAO,MAAM;UAAG,OAAO,OAAO;SAAE,UACnK;UAAE,uBAAuB,KAAA;SAAU;QAC7C;OACF,OAAO;MACT;MACA,MAAM,aAAa,YAAY,IAAI,MAAM,EAAE;MAAG,IAAI,eAAe,KAAA,KAAa,CAAC,OAAO,IAAI,MAAM,EAAE,GAAG,MAAM,mBAAmB,UAAU;KAC1I;KACA,KAAK,MAAM,CAAC,IAAI,YAAY,QAAQ,IAAI,CAAC,KAAK,IAAI,EAAE,KAAK,CAAC,YAAY,IAAI,EAAE,KAAK,OAAO,iBAAiB;MAAE,QAAQ,QAAQ;MAAG,OAAO,OAAO,EAAE;MAAG,WAAW,IAAI,EAAE,CAAC,EAAE,OAAO;MAAG,WAAW,OAAO,EAAE;MAAG,WAAW,OAAO,EAAE;MAAG,cAAc,OAAO,EAAE;KAAE;IACxP,QAAQ,CAA2E;GACrF;GACA,UAAU;GACV,KAAK,MAAM,cAAc,YAAY,OAAO,GAAG,mBAAwB,UAAU;GACjF,cAAmB;GAAG,kBAAuB;GAAG,iBAAsB,WAAW;GACjF,MAAM,QAAQ,OAAO,kBAAkB;IAAE,cAAmB;IAAG,kBAAuB;IAAG,iBAAsB,WAAW;GAAE,GAAG,GAAK;GACpI,aAAa;IAAE,cAAc,KAAK;IAAG,UAAU;IAAO,gBAAgB;IAAG,YAAY,OAAO;IAAG,YAAY,OAAO;IAAG,KAAK,MAAM,WAAW,OAAO,OAAO,GAAG,QAAQ,QAAQ;IAAG,KAAK,MAAM,QAAQ,WAAW,OAAO,GAAG,KAAK,OAAO;IAA8E,SAApD,cAAc,mCAA0C,CAAC,EAAE,OAAO;IAAG,KAAK,MAAM,QAAQ,SAAS,iBAAiB,gCAAgC,GAAG,KAAK,OAAO;IAAG,IAAI,aAAa,KAAA,GAAW,OAAO,OAAO;SAAgB,OAAO,YAAY;GAAS;EACzf;EAEA,IAAI,UAAU;EACd,IAAI,cAAc;EAClB,eAAe,iBAAiB,OAAwC;GACtE,IAAI;IACF,MAAM,UAAkC,CAAC;IACzC,IAAI,YAAY,IAAI,QAAQ,mBAAmB;IAC/C,IAAI,gBAAgB,IAAI,QAAQ,uBAAuB;IACvD,MAAM,WAAW,MAAM,MAAM,6BAA6B;KAAE,aAAa;KAAe,OAAO;KAAY;IAAQ,CAAC;IACpH,IAAI,SAAS,WAAW,KAAK;IAC7B,IAAI,SAAS,IAAI;KACf,UAAU,SAAS,QAAQ,IAAI,MAAM,KAAK;KAC1C,cAAc,SAAS,QAAQ,IAAI,eAAe,KAAK;KACvD,MAAM,cAAc,MAAM,SAAS,KAAK;IAC1C;GACF,QAAQ,CAAwD;EAClE;EAEA,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;EAmBvB,SAAgB,MAAM,KAA0B;GAC9C,IAAI,aAAa;IACf,IAAI,OAAO,4BAA4B,aAAa;IACpD,OAAO,oCAAoC,IAAI,IAAI,YAAY,CAAC;GAClE,GAAG,gDAAgD;GAEnD,IAAI,aAAa;IACf,MAAM,WAAW,eAAe,SAAS,QAAQ,KAAK,CAAC,IAAI,gBAAgB,SAAS,MAAM,CAAC,CAAC,IAAI,oBAAoB;IACpH,MAAM,QAAQ,QAAQ,OAAO;IAAG,MAAM,QAAQ,SAAS;IAAc,MAAM,cAAc,WACrF,iBACA;IACJ,SAAS,KAAK,OAAO,KAAK;IAC1B,IAAI,CAAC,UAAU;KACb,MAAM,eAAe,oBAAoB;KACzC,MAAM,gBAAgB,2BAA2B;KACjD,aAAa;MAAE,aAAa;MAAG,cAAc;MAAG,MAAM,OAAO;KAAE;IACjE;IACA,MAAM,UAAU,eAAe;IAC/B,MAAM,cAAc,IAAI,MAAM,OAAO,+BAA+B,IAAI,MAAM,SAAS;KAAE,MAAM;KAAyB,IAAI;IAAa,IAAI,EAAE,YAAA,GAAWA,MAAAA,cAAAA,CAAc,UAAU;KAChL,iBAAiB;KACjB,cAAc;KACd,WAAW,8BAA8B,OAAO,KAAK;KACrD,MAAM;KACN,OAAO;KACP,SAAS,QAAQ;IACnB,IAAA,GAAGA,MAAAA,cAAAA,CAAc,QAAQ;KAAE,eAAe;KAAM,WAAW;IAAmC,CAAC,GAAG,QAAA,GAAOA,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAW,oCAAoC,GAAG,MAAM,IAAI,KAAA,CAAS,CAAC,CAAC;IACxM,aAAa;KAAE,YAAY;KAAG,QAAQ,OAAO;KAAG,MAAM,OAAO;IAAE;GACjE,GAAG,uDAAuD;EAC5D;;EAGA,MAAa,SAA4B,CAAC,OAAO"}
1
+ {"version":3,"file":"client.js","names":["createElement"],"sources":["../src/native-mobile.ts","../src/client.ts"],"sourcesContent":["/** Mobile feature and compatibility rules applied to DSH React surfaces. */\nexport const NATIVE_MOBILE_STYLES = `\n@media (max-width:720px) {\n html.dsh-native-mobile-active,html.dsh-native-mobile-active body { width:100%; height:100%; overflow:hidden; }\n html.dsh-native-mobile-active { --dsh-mobile-motion-duration:200ms; --dsh-mobile-motion-ease:cubic-bezier(.22,1,.36,1); }\n html.dsh-native-mobile-active :is(a,button,[role=\"button\"],[role=\"tab\"],[tabindex]) { -webkit-tap-highlight-color:transparent; }\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [role=\"treeitem\"] { -webkit-tap-highlight-color:transparent; touch-action:manipulation; }\n html.dsh-native-mobile-active[data-dsh-mobile-input=\"touch\"] :is(a,button,[role=\"button\"],[role=\"tab\"],[tabindex]):focus { outline:none !important; }\n html.dsh-native-mobile-active [role=\"tooltip\"] { display:none !important; }\n /* Touch has no persistent hover affordance: keep workspace rows neutral after a tap. */\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] { --dsw-alias-interactive-bg-hover:transparent !important; }\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [role=\"treeitem\"]:is(:hover,:active,:focus,[aria-selected=\"true\"]),\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [class*=\"_sessionRow\"][class*=\"_selected\"],\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [class*=\"_searchResultRow\"][class*=\"_selected\"] { background:transparent !important; outline:0 !important; box-shadow:none !important; }\n /* Sidebar row menus are hover-only on desktop. Touch has no hover, so keep\n the ellipsis action visible and give it a reliable hit target. */\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [class*=\"_rowActions\"] { display:inline-flex !important; align-items:center !important; gap:8px !important; }\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [class*=\"_sessionRow\"] [class*=\"_time\"] { display:none !important; }\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [class*=\"_rowActions\"] button { box-sizing:border-box !important; width:32px !important; min-width:32px !important; height:32px !important; min-height:32px !important; }\n [data-dsh-mobile-frame] { grid-template-columns:0 minmax(0,1fr) 0 !important; width:100% !important; height:100dvh !important; overflow:hidden !important; }\n [data-dsh-mobile-center] { grid-column:2 !important; width:100vw !important; min-width:0 !important; }\n [data-dsh-mobile-center] > * { min-width:0 !important; }\n [data-dsh-mobile-header] { box-sizing:border-box !important; width:calc(100% - 16px) !important; margin:0 8px !important; min-width:0; padding-top:max(4px,env(safe-area-inset-top)) !important; padding-right:8px !important; padding-left:42px !important; }\n [data-dsh-mobile-header] [class*=\"_titleRow\"] { box-sizing:border-box !important; display:flex !important; align-items:center !important; min-width:0; min-height:32px !important; height:32px !important; gap:6px !important; padding:0 6px !important; }\n [data-dsh-mobile-header] [class*=\"_titleCluster\"] { min-width:0; }\n [data-dsh-mobile-header] [class*=\"_crumbs\"] { min-width:0; overflow:hidden; }\n [data-dsh-mobile-header] [class*=\"_crumb\"] { max-width:46vw; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }\n [data-dsh-mobile-header] [class*=\"_headerActions\"] { min-width:0; overflow-x:auto; scrollbar-width:none; }\n [data-dsh-mobile-header] [class*=\"_headerActions\"]::-webkit-scrollbar { display:none; }\n [data-dsh-mobile-header] [class*=\"_headerUtilities\"] { gap:2px !important; }\n [data-dsh-mobile-header] [class*=\"_sessionLogButton\"] { width:40px; min-width:40px; padding:0 !important; overflow:hidden; color:transparent; font-size:0 !important; }\n [data-dsh-mobile-header] [class*=\"_sessionLogButton\"] > * { display:none !important; }\n [data-dsh-mobile-header] [class*=\"_sessionLogButton\"]::after { color:var(--dsw-text, #171a21); content:\"日志\"; font-size:11px; font-weight:600; }\n [data-dsh-mobile-header] [class*=\"_tabs\"] { box-sizing:border-box !important; width:max-content !important; max-width:calc(100% - 58px) !important; min-height:28px !important; height:28px !important; margin-top:0 !important; padding-left:6px !important; padding-right:6px !important; overflow-x:auto; scrollbar-width:none; }\n [data-dsh-mobile-header] [class*=\"_tab\"] { padding-bottom:5px !important; }\n [data-dsh-mobile-header] [class*=\"_tabs\"]::-webkit-scrollbar { display:none; }\n [data-dsh-mobile-sidebar] { position:fixed !important; z-index:240 !important; inset:0 auto 0 0 !important; width:0 !important; overflow:visible !important; }\n [data-dsh-mobile-sidebar-root] { position:fixed !important; z-index:241 !important; inset:max(env(safe-area-inset-top),0px) auto 0 0 !important; height:auto !important; transition:width 180ms var(--dsh-mobile-motion-ease),box-shadow 180ms ease !important; }\n [data-dsh-mobile-sidebar][data-open=\"true\"] [data-dsh-mobile-sidebar-root] { width:min(88vw,340px) !important; padding-top:0 !important; box-shadow:18px 0 46px rgb(15 23 42 / 18%); }\n [data-dsh-mobile-sidebar][data-open=\"true\"] [data-dsh-mobile-sidebar-root] [class*=\"_logoRow\"] { height:52px !important; padding:4px 0 4px 4px !important; margin-bottom:4px !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-sidebar-root] { width:0 !important; border:0 !important; background:transparent !important; box-shadow:none !important; overflow:visible !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-sidebar-root] > :not(:has([data-dsh-mobile-toggle])) { display:none !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-sidebar-root] > :has([data-dsh-mobile-toggle]) { position:fixed !important; z-index:244 !important; top:env(safe-area-inset-top) !important; left:0 !important; box-sizing:border-box !important; width:50px !important; height:52px !important; padding:4px !important; border:0 !important; background:transparent !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-sidebar-root] > :has([data-dsh-mobile-toggle]) > :not([data-dsh-mobile-toggle]) { display:none !important; }\n [data-dsh-mobile-toggle] { width:44px !important; height:44px !important; min-width:44px !important; min-height:44px !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-toggle] > svg[class*=\"_railFish\"] { transform:translateY(-4px) !important; }\n .dsh-native-mobile-backdrop { position:fixed; z-index:235; inset:env(safe-area-inset-top) 0 0; border:0; background:rgb(15 23 42 / 32%); }\n .dsh-native-mobile-backdrop:not([hidden]) { animation:dsh-mobile-fade-in var(--dsh-mobile-motion-duration) ease-out; }\n .dsh-native-mobile-backdrop[hidden] { display:none; }\n [data-dsh-mobile-details] { position:fixed !important; z-index:250 !important; inset:0 0 0 auto !important; width:min(94vw,460px) !important; max-width:none !important; transform:translateX(100%); transition:transform var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); background:var(--dsw-bg, #fff); box-shadow:-18px 0 46px rgb(15 23 42 / 18%); }\n [data-dsh-mobile-details][data-open=\"true\"] { transform:translateX(0); }\n [data-dsh-mobile-handle] { display:none !important; }\n [data-dsh-mobile-settings] { flex-direction:column !important; width:100vw !important; height:100dvh !important; max-width:none !important; border-radius:0 !important; animation:dsh-mobile-panel-in var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); }\n [data-dsh-mobile-settings-nav] { flex:none !important; width:100% !important; padding:max(14px,env(safe-area-inset-top)) 12px 8px !important; gap:10px !important; border-bottom:1px solid var(--dsw-alias-border-subtle,#e8ebef); }\n [data-dsh-mobile-settings-nav] [class*=\"_navTitle\"] { padding:0 8px !important; font-size:18px !important; line-height:28px !important; }\n [data-dsh-mobile-settings-list] { flex-direction:row !important; gap:4px !important; overflow-x:auto !important; scrollbar-width:none; }\n [data-dsh-mobile-settings-list]::-webkit-scrollbar { display:none; }\n [data-dsh-mobile-settings-list] [class*=\"_navCell\"] { flex:0 0 auto !important; min-width:max-content !important; height:44px !important; padding:10px 12px !important; }\n [data-dsh-mobile-settings-list] [aria-current=\"true\"] { border-color:transparent !important; outline:0 !important; box-shadow:none !important; }\n [data-dsh-mobile-settings-content] { flex:1 1 auto !important; width:100% !important; min-height:0 !important; }\n [data-dsh-mobile-settings-header] { height:48px !important; min-height:48px !important; padding:10px 12px 6px !important; }\n [data-dsh-mobile-settings-header] [class*=\"_close\"] { width:36px !important; height:36px !important; }\n [data-dsh-mobile-settings-options] { box-sizing:border-box !important; width:100% !important; padding:4px 16px max(24px,env(safe-area-inset-bottom)) !important; overflow-x:hidden !important; }\n [data-dsh-mobile-settings-options] > * { width:100% !important; min-width:0 !important; }\n [data-dsh-mobile-settings-options] [data-slot=\"settings.general.item\"] > [class*=\"_row\"] { flex-direction:column !important; align-items:stretch !important; gap:12px !important; }\n [data-dsh-mobile-settings-options] [data-slot=\"settings.general.item\"] [class*=\"_rowText\"] { width:100% !important; padding-right:0 !important; }\n [data-dsh-mobile-settings-options] [data-slot=\"settings.general.item\"] [class*=\"_selector\"] { box-sizing:border-box !important; align-self:flex-start !important; justify-content:space-between !important; min-width:0 !important; min-height:44px !important; max-width:100% !important; }\n [data-dsh-mobile-settings-options] :is(input,select,textarea,button) { max-width:100%; }\n [data-dsh-mobile-settings-options] :is(input,select,textarea) { box-sizing:border-box; width:100%; min-width:0; }\n [data-dsh-mobile-settings-options] [class*=\"_head\"] { min-width:0; flex-wrap:wrap; }\n [data-dsh-mobile-settings-content][data-dsh-mobile-view-transition=\"true\"],\n [data-dsh-mobile-view][data-dsh-mobile-view-transition=\"true\"] { animation:dsh-mobile-view-in var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); }\n [data-dsh-mobile-center] textarea { font-size:16px !important; }\n /* Markdown tables use content-sized columns. Small tables fill the phone;\n wider tables keep readable cells and scroll inside their own region. */\n [data-dsh-mobile-table-scroll] { box-sizing:border-box; width:100%; max-width:100%; overflow-x:auto; overscroll-behavior-x:contain; -webkit-overflow-scrolling:touch; }\n [data-dsh-mobile-table-scroll] table { display:table !important; width:max-content !important; min-width:100% !important; max-width:none !important; table-layout:auto !important; }\n [data-dsh-mobile-table-scroll] :is(th,td) { box-sizing:border-box; min-width:8ch; max-width:32ch; overflow-wrap:anywhere; word-break:break-word; vertical-align:top; }\n [data-dsh-mobile-center] pre { max-width:100%; overflow-x:auto; }\n [data-dsh-mobile-center] :is(img,video,canvas,svg) { max-width:100%; }\n [data-dsh-mobile-message-scroll] { box-sizing:border-box !important; width:100% !important; padding:8px 10px 20px !important; }\n [data-dsh-mobile-history-loader] { position:relative !important; min-height:1px !important; }\n [data-dsh-mobile-history-loader] button:not(:disabled) { position:absolute !important; width:1px !important; height:1px !important; margin:-1px !important; padding:0 !important; clip-path:inset(50%) !important; opacity:0 !important; overflow:hidden !important; pointer-events:none !important; }\n [data-dsh-mobile-history-loader] button:disabled { min-height:28px !important; padding:4px 12px !important; }\n [data-dsh-mobile-message-column] { box-sizing:border-box !important; width:100% !important; max-width:none !important; margin:0 !important; padding:0 !important; gap:10px !important; }\n [data-dsh-mobile-message-column] > * { width:100% !important; max-width:100% !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] { box-sizing:border-box !important; display:grid !important; grid-template-columns:16px minmax(0,1fr) !important; grid-auto-rows:auto !important; align-items:center !important; column-gap:6px !important; width:100% !important; height:auto !important; min-height:40px !important; padding:4px 0 !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > [class*=\"_leading\"] { grid-column:1 !important; grid-row:1 !important; margin-right:0 !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > [class*=\"_title\"] { grid-column:2 !important; grid-row:1 !important; min-width:0 !important; overflow:hidden !important; text-overflow:ellipsis !important; white-space:nowrap !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > :is([class*=\"_sep\"],[class*=\"_separator\"]) { display:none !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > :is([class*=\"_summary\"],[class*=\"_fileLink\"]) { grid-column:2 !important; grid-row:2 !important; width:100% !important; min-width:0 !important; max-width:100% !important; overflow:hidden !important; line-height:19px !important; text-overflow:ellipsis !important; white-space:nowrap !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > [class*=\"_summarySuffix\"] { grid-column:2 !important; grid-row:3 !important; margin-left:0 !important; }\n [data-dsh-mobile-message-column] [data-context-fields] > * { display:grid !important; grid-template-columns:minmax(72px,30%) minmax(0,1fr) !important; gap:4px 10px !important; }\n [data-dsh-mobile-message-column] [class*=\"_ioSection\"] { grid-template-columns:1fr !important; row-gap:4px !important; }\n [data-dsh-mobile-message-column] [class*=\"_body\"] { max-width:100% !important; overflow-wrap:anywhere; }\n [data-dsh-mobile-center] [data-composer-card] ~ [class*=\"_root\"],\n [data-dsh-mobile-center] [data-composer-card] ~ * [class*=\"_root\"] { box-sizing:border-box !important; width:100% !important; max-width:100% !important; margin-bottom:-6px !important; padding:3px 4px 0 !important; font-size:11px !important; line-height:18px !important; white-space:normal !important; overflow:visible !important; text-overflow:clip !important; }\n [data-dsh-mobile-center] [data-composer-card] ~ [class*=\"_root\"] [class*=\"_sep\"],\n [data-dsh-mobile-center] [data-composer-card] ~ * [class*=\"_root\"] [class*=\"_sep\"] { margin:0 6px !important; }\n /* Message runtime details are inline on desktop. Give the clock/runtime\n label its own wrapping row on narrow screens so TTFT and throughput do\n not push the action buttons or clip at the viewport edge. */\n [data-dsh-mobile-center] [class*=\"_actions\"]:has(> [class*=\"_timeStart\"]),\n [data-dsh-mobile-center] [class*=\"_actions\"]:has(> [class*=\"_timeEnd\"]) { box-sizing:border-box !important; width:100% !important; flex-wrap:wrap !important; justify-content:flex-end !important; height:auto !important; min-height:28px !important; row-gap:2px !important; }\n [data-dsh-mobile-center] [class*=\"_timeStart\"],\n [data-dsh-mobile-center] [class*=\"_timeEnd\"] { box-sizing:border-box !important; flex:1 1 100% !important; order:2 !important; min-width:0 !important; max-width:100% !important; padding:0 !important; line-height:20px !important; text-align:center !important; white-space:normal !important; overflow-wrap:anywhere !important; }\n [data-dsh-mobile-center] [class*=\"_timeStart\"] { box-sizing:border-box !important; flex:1 1 100% !important; order:2 !important; min-width:0 !important; max-width:100% !important; padding:0 !important; line-height:20px !important; text-align:center !important; white-space:normal !important; overflow-wrap:anywhere !important; }\n [data-dsh-mobile-center] [class*=\"_timeStart\"] [class*=\"_runTimeDot\"],\n [data-dsh-mobile-center] [class*=\"_timeEnd\"] [class*=\"_runTimeDot\"] { margin:0 6px !important; }\n /* Keep the context meter's legend rows as readable label/value pairs.\n Generic mobile flex rules can otherwise place the rows side by side and\n break Chinese labels in the middle of a word. */\n [data-dsh-mobile-center] [role=\"dialog\"][aria-label*=\"上下文\"],\n [data-dsh-mobile-center] [role=\"dialog\"][aria-label*=\"Context\"] { width:min(264px,calc(100vw - 32px)) !important; min-width:0 !important; max-width:calc(100vw - 32px) !important; }\n [data-dsh-mobile-center] [role=\"dialog\"][aria-label*=\"上下文\"] [class*=\"_rows\"],\n [data-dsh-mobile-center] [role=\"dialog\"][aria-label*=\"Context\"] [class*=\"_rows\"] { display:block !important; }\n [data-dsh-mobile-center] [role=\"dialog\"][aria-label*=\"上下文\"] [class*=\"_rows\"] > [class*=\"_row\"],\n [data-dsh-mobile-center] [role=\"dialog\"][aria-label*=\"Context\"] [class*=\"_rows\"] > [class*=\"_row\"] { display:flex !important; align-items:center !important; justify-content:space-between !important; width:100% !important; min-width:0 !important; white-space:nowrap !important; }\n [data-dsh-mobile-center] [role=\"dialog\"][aria-label*=\"上下文\"] :is(dt,dd),\n [data-dsh-mobile-center] [role=\"dialog\"][aria-label*=\"Context\"] :is(dt,dd) { white-space:nowrap !important; word-break:keep-all !important; }\n .dsh-mobile-branch-toast { position:fixed; z-index:300; top:max(12px,env(safe-area-inset-top)); left:50%; max-width:calc(100vw - 32px); box-sizing:border-box; padding:7px 14px; border:1px solid rgb(15 23 42 / 10%); border-radius:999px; background:rgb(15 23 42 / 92%); color:#fff; font-size:13px; line-height:20px; text-align:center; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; opacity:0; pointer-events:none; transform:translate(-50%,-8px); transition:opacity 160ms ease,transform 160ms ease; }\n .dsh-mobile-branch-toast[data-visible=\"true\"] { opacity:1; transform:translate(-50%,0); }\n [data-dsh-mobile-center] [class*=\"_composer\"] { padding-left:8px !important; padding-right:8px !important; padding-bottom:max(8px,env(safe-area-inset-bottom)) !important; }\n /* The desktop composer intentionally wraps whole toolbar groups. On a phone,\n dynamic model and status labels made that row alternate between one and\n two lines. Keep two stable columns and let only the model label shrink. */\n [data-dsh-mobile-composer-row] { display:grid !important; grid-template-columns:max-content minmax(0,1fr) !important; align-items:center !important; gap:4px 8px !important; }\n [data-dsh-mobile-composer-tools] { display:flex !important; flex-wrap:nowrap !important; width:max-content !important; min-width:0 !important; max-width:max-content !important; gap:6px !important; }\n [data-dsh-mobile-composer-trailing] { display:flex !important; flex-wrap:nowrap !important; width:100% !important; min-width:0 !important; max-width:100% !important; gap:6px !important; margin-left:0 !important; justify-content:flex-end !important; }\n [data-dsh-mobile-composer-model] { flex:1 1 0 !important; width:auto !important; min-width:0 !important; max-width:none !important; }\n [data-dsh-mobile-composer-model-trigger] { box-sizing:border-box !important; width:100% !important; max-width:100% !important; min-width:0 !important; padding-left:6px !important; padding-right:4px !important; }\n [data-dsh-mobile-composer-model-label] { flex:1 1 auto !important; max-width:none !important; min-width:0 !important; overflow:hidden !important; text-overflow:ellipsis !important; white-space:nowrap !important; }\n [data-dsh-mobile-center] [class*=\"_root\"]:has(> [class*=\"_card\"] textarea) { box-sizing:border-box !important; width:100% !important; padding:0 0 8px !important; }\n [data-dsh-mobile-center] [class*=\"_root\"]:has(> [class*=\"_card\"] textarea) > [class=\"\"]:last-child { display:none !important; }\n}\n@keyframes dsh-mobile-fade-in { from { opacity:0; } }\n@keyframes dsh-mobile-panel-in { from { opacity:.72; transform:translateY(6px); } }\n@keyframes dsh-mobile-view-in { from { opacity:.58; transform:translateY(5px); } }\n@media (max-width:420px) {\n [data-dsh-mobile-header] [class*=\"_headerActions\"] { max-width:42vw; }\n [data-dsh-mobile-settings-options] [data-slot=\"settings.general.item\"] [class*=\"_selector\"] { align-self:stretch !important; width:100% !important; }\n [data-dsh-mobile-message-column] [data-context-fields] > * { grid-template-columns:1fr !important; }\n}\n@media (prefers-reduced-motion:reduce) {\n [data-dsh-mobile-sidebar-root],[data-dsh-mobile-details] { transition:none !important; }\n .dsh-native-mobile-backdrop:not([hidden]),[data-dsh-mobile-settings],\n [data-dsh-mobile-settings-content][data-dsh-mobile-view-transition=\"true\"],\n [data-dsh-mobile-view][data-dsh-mobile-view-transition=\"true\"] { animation:none !important; }\n}\n`\n\nfunction classToken(element: Element, suffix: string): boolean {\n return Array.from(element.classList).some(value => value.endsWith(suffix))\n}\n\nfunction firstByClassSuffix(root: ParentNode, suffix: string): HTMLElement | undefined {\n return Array.from(root.querySelectorAll<HTMLElement>('[class]')).find(element => classToken(element, suffix))\n}\n\nconst AUTO_HISTORY_THRESHOLD_PX = 64\n\n/** Whether a user-driven scroll moved upward into the automatic history-loading zone. */\nexport function shouldAutoLoadEarlier(previousTop: number, currentTop: number): boolean {\n return currentTop <= AUTO_HISTORY_THRESHOLD_PX && currentTop < previousTop - 0.5\n}\n\n/** Add mobile semantics without replacing feature trees. */\nexport function installNativeMobileSurface(): () => void {\n document.documentElement.classList.add('dsh-native-mobile-active')\n const setInputMode = (mode: 'keyboard' | 'touch'): void => {\n document.documentElement.dataset.dshMobileInput = mode\n }\n const onPointerDown = (event: PointerEvent): void => {\n if (event.pointerType === 'touch' || event.pointerType === 'pen') setInputMode('touch')\n }\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Tab' || event.key.startsWith('Arrow')) setInputMode('keyboard')\n }\n document.addEventListener('pointerdown', onPointerDown, true)\n document.addEventListener('keydown', onKeyDown, true)\n const backdrop = document.createElement('button')\n backdrop.type = 'button'\n backdrop.className = 'dsh-native-mobile-backdrop'\n backdrop.hidden = true\n backdrop.setAttribute('aria-label', '关闭工作区导航')\n document.body.append(backdrop)\n const branchToast = document.createElement('div')\n branchToast.className = 'dsh-mobile-branch-toast'\n branchToast.setAttribute('role', 'status')\n branchToast.setAttribute('aria-live', 'polite')\n document.body.append(branchToast)\n let branchToastTimer = 0\n const showBranchToast = (): void => {\n const header = document.querySelector<HTMLElement>('[data-dsh-mobile-header]')\n const title = header === null ? undefined : header.querySelector<HTMLElement>('[class*=\"_crumbCurrent\"]')?.textContent?.trim()\n branchToast.textContent = title === undefined ? '当前分支' : `当前分支:${title}`\n branchToast.dataset.visible = 'true'\n if (branchToastTimer !== 0) window.clearTimeout(branchToastTimer)\n branchToastTimer = window.setTimeout(() => {\n branchToast.removeAttribute('data-visible')\n branchToastTimer = 0\n }, 1600)\n }\n const onBranchClick = (event: MouseEvent): void => {\n if (!(event.target instanceof Element)) return\n const branch = event.target.closest<HTMLButtonElement>('button[aria-label*=\"分支\"],button[aria-label*=\"Branch\"],button[aria-label*=\"branch\"]')\n if (branch === null || branch.hasAttribute('disabled') || branch.getAttribute('aria-disabled') === 'true') return\n window.setTimeout(showBranchToast, 80)\n }\n document.addEventListener('click', onBranchClick, true)\n let frame: HTMLElement | undefined\n let sidebar: HTMLElement | undefined\n let sidebarRoot: HTMLElement | undefined\n let toggle: HTMLButtonElement | undefined\n let viewArea: HTMLElement | undefined\n let scheduled = 0\n let transitionFrame = 0\n let transitionRestartFrame = 0\n let transitionTimer = 0\n let transitionTarget: HTMLElement | undefined\n let historyScroller: HTMLElement | undefined\n let historyPreviousTop = 0\n const historyLoadButton = (): HTMLButtonElement | undefined => {\n const loader = historyScroller === undefined ? undefined : firstByClassSuffix(historyScroller, '_older')\n return loader?.querySelector<HTMLButtonElement>('button') ?? undefined\n }\n const onHistoryScroll = (): void => {\n if (historyScroller === undefined) return\n const currentTop = Math.max(0, historyScroller.scrollTop)\n const shouldLoad = shouldAutoLoadEarlier(historyPreviousTop, currentTop)\n historyPreviousTop = currentTop\n if (!shouldLoad) return\n const button = historyLoadButton()\n if (button === undefined || button.disabled || button.getAttribute('aria-disabled') === 'true') return\n button.click()\n }\n const bindHistoryScroller = (next: HTMLElement | undefined): void => {\n if (historyScroller === next) return\n historyScroller?.removeEventListener('scroll', onHistoryScroll)\n historyScroller = next\n historyPreviousTop = next?.scrollTop ?? 0\n historyScroller?.addEventListener('scroll', onHistoryScroll, { passive: true })\n }\n const animateNavigation = (event: MouseEvent): void => {\n if (!(event.target instanceof Element)) return\n const trigger = event.target.closest<HTMLElement>('button,a,[role=\"tab\"],[aria-selected]')\n if (trigger === null || trigger.hasAttribute('disabled') || trigger.getAttribute('aria-disabled') === 'true') return\n if (trigger.getAttribute('aria-selected') === 'true' || trigger.getAttribute('aria-current') === 'true') return\n const settingsNavigation = trigger.closest('[data-dsh-mobile-settings-list]') !== null\n const conversationNavigation = trigger.matches('[role=\"tab\"]')\n const sidebarNavigation = trigger.closest('[data-dsh-mobile-sidebar-root]') !== null\n && trigger.closest('[data-dsh-mobile-toggle]') === null\n if (!settingsNavigation && !conversationNavigation && !sidebarNavigation) return\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return\n if (transitionFrame !== 0) cancelAnimationFrame(transitionFrame)\n if (transitionRestartFrame !== 0) cancelAnimationFrame(transitionRestartFrame)\n transitionFrame = requestAnimationFrame(() => {\n transitionFrame = 0\n const target = settingsNavigation\n ? document.querySelector<HTMLElement>('[data-dsh-mobile-settings-content]')\n : viewArea\n if (target === null || target === undefined) return\n transitionTarget?.removeAttribute('data-dsh-mobile-view-transition')\n target.removeAttribute('data-dsh-mobile-view-transition')\n transitionRestartFrame = requestAnimationFrame(() => {\n transitionRestartFrame = 0\n transitionTarget = target\n target.dataset.dshMobileViewTransition = 'true'\n if (transitionTimer !== 0) clearTimeout(transitionTimer)\n transitionTimer = window.setTimeout(() => {\n target.removeAttribute('data-dsh-mobile-view-transition')\n if (transitionTarget === target) transitionTarget = undefined\n transitionTimer = 0\n }, 240)\n })\n })\n }\n document.addEventListener('click', animateNavigation)\n\n const sync = (): void => {\n scheduled = 0\n frame = firstByClassSuffix(document, '_frame')\n const dedicatedCenter = document.querySelector<HTMLElement>('.dshm-main') ?? undefined\n if (frame !== undefined) frame.dataset.dshMobileFrame = 'true'\n sidebar = frame === undefined\n ? document.querySelector<HTMLElement>('.dshm-drawer') ?? undefined\n : firstByClassSuffix(frame, '_sidebarCol')\n const center = frame === undefined ? dedicatedCenter : firstByClassSuffix(frame, '_centerCol')\n const details = frame === undefined ? undefined : firstByClassSuffix(frame, '_detailsCol')\n const handle = frame === undefined ? undefined : firstByClassSuffix(frame, '_handle')\n if (center === undefined) {\n bindHistoryScroller(undefined)\n return\n }\n if (center !== undefined) {\n center.dataset.dshMobileCenter = 'true'\n center.querySelector<HTMLElement>('header')?.setAttribute('data-dsh-mobile-header', 'true')\n viewArea = firstByClassSuffix(center, '_viewArea')\n if (viewArea !== undefined) viewArea.dataset.dshMobileView = 'true'\n const conversation = center.querySelector<HTMLElement>('[data-conversation-scroll]')\n bindHistoryScroller(conversation ?? undefined)\n const historyLoader = conversation === null ? undefined : firstByClassSuffix(conversation, '_older')\n if (historyLoader !== undefined) {\n historyLoader.dataset.dshMobileHistoryLoader = 'true'\n historyLoader.setAttribute('aria-live', 'polite')\n const button = historyLoader.querySelector<HTMLButtonElement>('button')\n if (button !== null) {\n button.tabIndex = -1\n if (button.disabled) button.removeAttribute('aria-hidden')\n else button.setAttribute('aria-hidden', 'true')\n }\n }\n const messageColumn = conversation === null ? undefined : firstByClassSuffix(conversation, '_column')\n const messageScroll = messageColumn?.parentElement\n if (messageColumn !== undefined && messageScroll !== null && messageScroll !== undefined && classToken(messageScroll, '_scroll')) {\n messageColumn.dataset.dshMobileMessageColumn = 'true'\n messageScroll.dataset.dshMobileMessageScroll = 'true'\n }\n for (const table of center.querySelectorAll<HTMLTableElement>('table')) {\n const parent = table.parentElement\n if (parent?.dataset.dshMobileTableScroll === 'true') continue\n const wrapper = document.createElement('div')\n wrapper.dataset.dshMobileTableScroll = 'true'\n table.before(wrapper)\n wrapper.append(table)\n }\n const composerCard = center.querySelector<HTMLElement>('[data-composer-card]')\n const composerRow = composerCard?.querySelector<HTMLElement>(':scope > [data-input-scroll]')?.nextElementSibling\n if (composerRow instanceof HTMLElement) {\n composerRow.dataset.dshMobileComposerRow = 'true'\n const groups = Array.from(composerRow.children).filter((child): child is HTMLElement => child instanceof HTMLElement)\n const composerTools = groups[0]\n const composerTrailing = groups.at(-1)\n if (composerTools !== undefined) composerTools.dataset.dshMobileComposerTools = 'true'\n if (composerTrailing !== undefined && composerTrailing !== composerTools) {\n composerTrailing.dataset.dshMobileComposerTrailing = 'true'\n const modelTrigger = composerTrailing.querySelector<HTMLButtonElement>('button[aria-label^=\"选择模型\"],button[aria-label^=\"Select model\"]')\n if (modelTrigger !== null) {\n modelTrigger.dataset.dshMobileComposerModelTrigger = 'true'\n modelTrigger.parentElement?.setAttribute('data-dsh-mobile-composer-model', 'true')\n modelTrigger.querySelector<HTMLElement>('[class*=\"_triggerLabel\"]')?.setAttribute('data-dsh-mobile-composer-model-label', 'true')\n }\n }\n }\n }\n if (handle !== undefined) handle.dataset.dshMobileHandle = 'true'\n if (details !== undefined) {\n details.dataset.dshMobileDetails = 'true'\n const lastColumn = frame?.style.gridTemplateColumns.trim().split(/\\s+/).at(-1)\n details.dataset.open = String(lastColumn !== undefined && lastColumn !== '0px' && lastColumn !== '0')\n }\n const settings = Array.from(document.querySelectorAll<HTMLElement>('[role=\"dialog\"]')).find(dialog => {\n const directNav = Array.from(dialog.children).find(child => child instanceof HTMLElement && classToken(child, '_nav'))\n return directNav !== undefined\n })\n if (settings !== undefined) {\n settings.dataset.dshMobileSettings = 'true'\n const nav = Array.from(settings.children).find(child => child instanceof HTMLElement && classToken(child, '_nav')) as HTMLElement | undefined\n const content = Array.from(settings.children).find(child => child instanceof HTMLElement && classToken(child, '_content')) as HTMLElement | undefined\n if (nav !== undefined) {\n nav.dataset.dshMobileSettingsNav = 'true'\n firstByClassSuffix(nav, '_navList')?.setAttribute('data-dsh-mobile-settings-list', 'true')\n }\n if (content !== undefined) {\n content.dataset.dshMobileSettingsContent = 'true'\n firstByClassSuffix(content, '_header')?.setAttribute('data-dsh-mobile-settings-header', 'true')\n firstByClassSuffix(content, '_options')?.setAttribute('data-dsh-mobile-settings-options', 'true')\n }\n }\n if (sidebar === undefined) return\n sidebar.dataset.dshMobileSidebar = 'true'\n toggle = firstByClassSuffix(sidebar, '_toggle') as HTMLButtonElement | undefined\n let candidate = toggle?.parentElement\n while (candidate !== undefined && candidate !== null && candidate !== sidebar && !classToken(candidate, '_root')) candidate = candidate.parentElement\n sidebarRoot = candidate !== sidebar && candidate !== null ? candidate : undefined\n if (sidebarRoot === undefined) return\n sidebarRoot.dataset.dshMobileSidebarRoot = 'true'\n for (const brand of sidebarRoot.querySelectorAll<HTMLElement>('[class*=\"_fallbackBrandName\"]')) {\n if (brand.textContent?.trim() === 'DSH Local Build') brand.textContent = 'DeepSeek Harness'\n }\n if (toggle !== undefined) toggle.dataset.dshMobileToggle = 'true'\n const collapsed = classToken(sidebarRoot, '_collapsed')\n sidebar.dataset.open = String(!collapsed)\n backdrop.hidden = collapsed\n }\n const schedule = (): void => { if (scheduled === 0) scheduled = requestAnimationFrame(sync) }\n const observer = new MutationObserver(schedule)\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'style', 'disabled'] })\n backdrop.addEventListener('click', () => { if (sidebar?.dataset.open === 'true') toggle?.click() })\n sync()\n return () => {\n observer.disconnect()\n document.removeEventListener('click', onBranchClick, true)\n if (branchToastTimer !== 0) window.clearTimeout(branchToastTimer)\n branchToast.remove()\n if (scheduled !== 0) cancelAnimationFrame(scheduled)\n if (transitionFrame !== 0) cancelAnimationFrame(transitionFrame)\n if (transitionRestartFrame !== 0) cancelAnimationFrame(transitionRestartFrame)\n if (transitionTimer !== 0) clearTimeout(transitionTimer)\n transitionTarget?.removeAttribute('data-dsh-mobile-view-transition')\n historyScroller?.removeEventListener('scroll', onHistoryScroll)\n document.removeEventListener('pointerdown', onPointerDown, true)\n document.removeEventListener('keydown', onKeyDown, true)\n document.removeEventListener('click', animateNavigation)\n backdrop.remove()\n document.documentElement.classList.remove('dsh-native-mobile-active')\n delete document.documentElement.dataset.dshMobileInput\n }\n}\n","import { createElement } from 'react'\nimport { installNativeMobileSurface, NATIVE_MOBILE_STYLES } from './native-mobile.js'\n\ninterface ClientContext {\n effect(effect: () => void | (() => void), label?: string): void\n get(name: 'connection'): MobileConnectionHandle\n slots: {\n inject(key: string, callback: () => (() => void)): () => void\n register(options: { name: string; id: string }, component: (props: { wide: boolean }) => unknown): () => void\n }\n}\n\ninterface MobileConnectionHandle {\n isLoopback: boolean\n}\n\ninterface MobileExtensionContext {\n readonly document: Document\n readonly request: (path: string, init?: RequestInit) => Promise<Response>\n readonly root: HTMLElement\n readonly window: Window\n}\n\ntype MobileExtensionMount = (context: MobileExtensionContext) => void | (() => void)\ntype MobileSurfacePlacement = 'page' | 'sidebar-action' | 'header-action' | 'composer-dock' | 'settings-section' | 'overlay'\ninterface MobileSurface {\n readonly id: string\n readonly placement: MobileSurfacePlacement\n readonly label: string\n mount(container: HTMLElement): void | (() => void)\n}\ninterface MobileClientApi {\n readonly host: {\n invoke(action: string, input: unknown): Promise<unknown>\n fetch(path: string, init?: RequestInit): Promise<Response>\n }\n readonly ui: {\n registerSurface(surface: MobileSurface): () => void\n open(surfaceId: string): void\n close(surfaceId: string): void\n toast(message: string): void\n }\n readonly native: {\n capabilities(): Promise<readonly string[]>\n invoke(action: string, input?: unknown): Promise<unknown>\n }\n readonly signal: AbortSignal\n readonly document: Document\n readonly window: Window\n}\ninterface MobileClientDefinition {\n readonly apiVersion: 1\n readonly id: string\n activate(api: MobileClientApi): void | (() => void) | Promise<void | (() => void)>\n}\n\ndeclare global {\n interface Window {\n dshMobile?: {\n register(mount: MobileExtensionMount): void\n define(definition: MobileClientDefinition): void\n }\n __DSH_MOBILE_FRONTEND__?: 'dedicated'\n __DSH_MOBILE_NATIVE__?: {\n capabilities(): Promise<readonly string[]> | readonly string[]\n invoke(action: string, input?: unknown): Promise<unknown>\n }\n }\n}\n\nconst queuedDefinitions: MobileClientDefinition[] = []\nlet queuedLegacyMount: MobileExtensionMount | undefined\nif (typeof window !== 'undefined' && window.dshMobile === undefined) {\n window.dshMobile = {\n register: mount => { queuedLegacyMount = mount },\n define: definition => { queuedDefinitions.push(definition) },\n }\n}\n\nfunction isLoopbackHost(hostname: string): boolean {\n return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1' || hostname === '[::1]'\n}\n\n/**\n * Match DSH's client-side privilege hint to the authenticated mobile gateway.\n * The gateway authenticates the paired device and forwards allowed requests to\n * DSH's loopback listener, so settings RPCs receive the same Host-side checks\n * as the desktop page even though the phone's visible URL is a LAN address.\n */\nexport function trustAuthenticatedGatewayConnection(connection: MobileConnectionHandle): () => void {\n const previous = connection.isLoopback\n connection.isLoopback = true\n return () => { connection.isLoopback = previous }\n}\n\nfunction element<K extends keyof HTMLElementTagNameMap>(tag: K, className?: string): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag)\n if (className !== undefined) node.className = className\n return node\n}\n\nasync function requestJson(path: string, init?: RequestInit): Promise<Record<string, unknown>> {\n const response = await fetch(path, { ...init, headers: { 'content-type': 'application/json', ...init?.headers } })\n const body = await response.json() as Record<string, unknown>\n if (!response.ok) throw new Error(typeof body.error === 'string' ? body.error : `HTTP ${String(response.status)}`)\n return body\n}\n\nfunction officialFunnelSetupUrl(value: unknown): string {\n if (typeof value !== 'string' || value.length > 2048) return ''\n let url: URL\n try { url = new URL(value) } catch { return '' }\n const normalized = url.toString().replace(/\\/$/u, '')\n if (normalized === 'https://tailscale.com/s/no-funnel' || normalized === 'https://tailscale.com/s/https') return normalized\n if (url.protocol !== 'https:' || url.hostname !== 'login.tailscale.com' || url.port !== ''\n || url.username !== '' || url.password !== '') return ''\n return url.toString()\n}\n\nfunction installControl(): { remove: () => void; toggle: () => void } {\n const root = element('div', 'dsh-mobile-control')\n const panel = element('section', 'dsh-mobile-control__panel'); panel.hidden = true\n panel.setAttribute('aria-label', '移动访问')\n const header = element('header', 'dsh-mobile-control__header')\n const title = element('h2'); title.textContent = '移动访问'\n const close = element('button', 'dsh-mobile-control__close'); close.type = 'button'; close.textContent = '×'; close.setAttribute('aria-label', '收起移动访问')\n const appDownload = element('a', 'dsh-mobile-control__app-download'); appDownload.href = 'https://github.com/saya-ch/dsh-mobile/releases/latest'; appDownload.target = '_blank'; appDownload.rel = 'noopener noreferrer'; appDownload.textContent = '下载 Android App'; appDownload.setAttribute('aria-label', '前往 GitHub Releases 下载最新版 Android App')\n const switcher = element('div', 'dsh-mobile-control__switcher')\n const lanTab = element('button', 'dsh-mobile-control__tab is-active'); lanTab.type = 'button'; lanTab.textContent = '局域网'\n const remoteTab = element('button', 'dsh-mobile-control__tab'); remoteTab.type = 'button'; remoteTab.textContent = '远程'\n lanTab.setAttribute('aria-pressed', 'true'); remoteTab.setAttribute('aria-pressed', 'false'); switcher.append(lanTab, remoteTab)\n const lanView = element('div', 'dsh-mobile-control__view')\n const access = element('div', 'dsh-mobile-control__access'); access.hidden = true\n const accessLabel = element('span', 'dsh-mobile-control__access-label'); accessLabel.textContent = '浏览器访问'\n const accessLink = element('a', 'dsh-mobile-control__access-link'); accessLink.target = '_blank'; accessLink.rel = 'noreferrer'\n access.append(accessLabel, accessLink)\n const qrBox = element('div', 'dsh-mobile-control__qr'); qrBox.hidden = true\n const status = element('p', 'dsh-mobile-control__status'); status.textContent = '正在读取状态…'\n const extensionStatus = element('p', 'dsh-mobile-control__extensions'); extensionStatus.hidden = true\n const actions = element('div', 'dsh-mobile-control__actions')\n const toggle = element('button', 'dsh-mobile-control__secondary'); toggle.type = 'button'\n const pair = element('button', 'dsh-mobile-control__primary'); pair.type = 'button'; pair.textContent = '生成并复制密钥'\n const linkPair = element('button', 'dsh-mobile-control__secondary'); linkPair.type = 'button'; linkPair.textContent = '复制配对链接'\n const manageRow = element('div', 'dsh-mobile-control__manage-row')\n const manageDevices = element('button', 'dsh-mobile-control__manage'); manageDevices.type = 'button'; manageDevices.textContent = '管理配对设备'\n const resetAll = element('button', 'dsh-mobile-control__manage'); resetAll.type = 'button'; resetAll.textContent = '清除所有设备'\n manageRow.append(manageDevices, resetAll)\n const devicePanel = element('div', 'dsh-mobile-control__devices'); devicePanel.hidden = true\n const remoteView = element('div', 'dsh-mobile-control__view is-remote'); remoteView.hidden = true\n const remoteIntro = element('p', 'dsh-mobile-control__intro'); remoteIntro.textContent = '选择更适合你的远程通道。切换或关闭远程访问不会影响局域网。'\n const providerSection = element('section', 'dsh-mobile-control__provider-section')\n const providerHeading = element('h3', 'dsh-mobile-control__section-title'); providerHeading.textContent = '选择连接方式'\n const providerInfo = element('div', 'dsh-mobile-control__provider-info')\n const providerInfoButton = element('button', 'dsh-mobile-control__provider-info-button'); providerInfoButton.type = 'button'; providerInfoButton.setAttribute('aria-label', '查看远程连接安全与网络说明'); providerInfoButton.setAttribute('aria-expanded', 'false'); providerInfoButton.setAttribute('aria-controls', 'dsh-mobile-provider-info'); providerInfoButton.setAttribute('aria-describedby', 'dsh-mobile-provider-info')\n const providerInfoGlyph = element('span', 'dsh-mobile-control__provider-info-glyph'); providerInfoGlyph.textContent = 'i'; providerInfoGlyph.setAttribute('aria-hidden', 'true')\n const providerInfoPopover = element('div', 'dsh-mobile-control__provider-info-popover'); providerInfoPopover.id = 'dsh-mobile-provider-info'; providerInfoPopover.setAttribute('role', 'tooltip'); providerInfoPopover.hidden = true\n const providerInfoTitle = element('strong'); providerInfoTitle.textContent = '你始终可以放心'\n const providerInfoText = element('span'); providerInfoText.textContent = '只有已配对设备能进入 DSH。cpolar 按需安装并可彻底清理;Tailscale 在中国大陆网络下可能连接缓慢、中断或无法使用,国内网络建议优先尝试 cpolar。'\n providerInfoButton.append(providerInfoGlyph); providerInfoPopover.append(providerInfoTitle, providerInfoText); providerInfo.append(providerInfoButton, providerInfoPopover)\n const providerChoices = element('div', 'dsh-mobile-control__provider-choices'); providerChoices.setAttribute('role', 'radiogroup'); providerChoices.setAttribute('aria-label', '远程连接方式')\n const tailscaleChoice = element('button', 'dsh-mobile-control__provider'); tailscaleChoice.type = 'button'; tailscaleChoice.setAttribute('role', 'radio'); tailscaleChoice.setAttribute('aria-checked', 'true')\n const tailscaleChoiceTop = element('span', 'dsh-mobile-control__provider-top')\n const tailscaleChoiceName = element('strong'); tailscaleChoiceName.textContent = 'Tailscale Funnel'\n const tailscaleChoiceBadge = element('span', 'dsh-mobile-control__provider-badge'); tailscaleChoiceBadge.textContent = '内置'\n const tailscaleChoiceDescription = element('span', 'dsh-mobile-control__provider-description'); tailscaleChoiceDescription.textContent = '覆盖更广;中国大陆网络可能不稳定,首次需登录并允许 Funnel。'\n tailscaleChoiceTop.append(tailscaleChoiceName, tailscaleChoiceBadge); tailscaleChoice.append(tailscaleChoiceTop, tailscaleChoiceDescription)\n const cpolarChoice = element('button', 'dsh-mobile-control__provider'); cpolarChoice.type = 'button'; cpolarChoice.setAttribute('role', 'radio'); cpolarChoice.setAttribute('aria-checked', 'false')\n const cpolarChoiceTop = element('span', 'dsh-mobile-control__provider-top')\n const cpolarChoiceName = element('strong'); cpolarChoiceName.textContent = 'cpolar'\n const cpolarChoiceBadge = element('span', 'dsh-mobile-control__provider-badge is-cpolar'); cpolarChoiceBadge.textContent = '国内网络优先'\n const cpolarChoiceDescription = element('span', 'dsh-mobile-control__provider-description'); cpolarChoiceDescription.textContent = '按需安装官方组件,适合国内网络环境。'\n cpolarChoiceTop.append(cpolarChoiceName, cpolarChoiceBadge); cpolarChoice.append(cpolarChoiceTop, cpolarChoiceDescription)\n providerChoices.append(tailscaleChoice, cpolarChoice); providerSection.append(providerHeading, providerInfo, providerChoices)\n const cpolarSetup = element('section', 'dsh-mobile-control__cpolar-setup'); cpolarSetup.hidden = true\n const cpolarSetupTitle = element('h3', 'dsh-mobile-control__section-title'); cpolarSetupTitle.textContent = '准备 cpolar'\n const cpolarComponentStatus = element('p', 'dsh-mobile-control__component-status'); cpolarComponentStatus.textContent = '正在检查组件…'\n const cpolarInstall = element('button', 'dsh-mobile-control__primary'); cpolarInstall.type = 'button'; cpolarInstall.textContent = '安装官方组件'\n const cpolarAccount = element('div', 'dsh-mobile-control__cpolar-account'); cpolarAccount.hidden = true\n const cpolarAccountText = element('p', 'dsh-mobile-control__component-note'); cpolarAccountText.textContent = '登录 cpolar 官网后复制 Authtoken。令牌只保存在本机插件私有目录,不会显示在页面或日志中。'\n const cpolarAccountLinks = element('div', 'dsh-mobile-control__link-row')\n const cpolarSignup = element('a', 'dsh-mobile-control__text-link'); cpolarSignup.href = 'https://dashboard.cpolar.com/signup'; cpolarSignup.target = '_blank'; cpolarSignup.rel = 'noopener noreferrer'; cpolarSignup.textContent = '注册 cpolar'\n const cpolarDashboard = element('a', 'dsh-mobile-control__text-link'); cpolarDashboard.href = 'https://dashboard.cpolar.com/auth'; cpolarDashboard.target = '_blank'; cpolarDashboard.rel = 'noopener noreferrer'; cpolarDashboard.textContent = '打开控制台获取令牌'\n cpolarAccountLinks.append(cpolarSignup, cpolarDashboard)\n const cpolarTokenLabel = element('label', 'dsh-mobile-control__token-label'); cpolarTokenLabel.textContent = 'Authtoken'\n const cpolarToken = element('input', 'dsh-mobile-control__token'); cpolarToken.type = 'password'; cpolarToken.autocomplete = 'off'; cpolarToken.spellcheck = false; cpolarToken.placeholder = '粘贴 cpolar Authtoken'; cpolarTokenLabel.append(cpolarToken)\n const cpolarConfigure = element('button', 'dsh-mobile-control__primary dsh-mobile-control__cpolar-connect'); cpolarConfigure.type = 'button'; cpolarConfigure.textContent = '保存并连接'\n cpolarAccount.append(cpolarAccountText, cpolarAccountLinks, cpolarTokenLabel, cpolarConfigure)\n const cpolarDetails = element('details', 'dsh-mobile-control__details')\n const cpolarDetailsSummary = element('summary'); cpolarDetailsSummary.textContent = '组件来源与清理说明'\n const cpolarDetailsBody = element('div', 'dsh-mobile-control__details-body')\n const cpolarDetailsText = element('p'); cpolarDetailsText.textContent = '仅在你点击安装后从 cpolar 官网下载并校验固定版本。不会写入系统服务、开机启动、注册表或 PATH。'\n const cpolarStorage = element('code', 'dsh-mobile-control__storage'); cpolarStorage.textContent = '插件私有目录'\n const cpolarOfficial = element('a', 'dsh-mobile-control__text-link'); cpolarOfficial.href = 'https://www.cpolar.com/download'; cpolarOfficial.target = '_blank'; cpolarOfficial.rel = 'noopener noreferrer'; cpolarOfficial.textContent = '官方下载安装页'\n const cpolarTerms = element('a', 'dsh-mobile-control__text-link'); cpolarTerms.href = 'https://www.cpolar.com/tos'; cpolarTerms.target = '_blank'; cpolarTerms.rel = 'noopener noreferrer'; cpolarTerms.textContent = '服务条款'\n const cpolarPurge = element('button', 'dsh-mobile-control__danger'); cpolarPurge.type = 'button'; cpolarPurge.textContent = '彻底移除 cpolar 组件与配置'\n cpolarDetailsBody.append(cpolarDetailsText, cpolarStorage, cpolarOfficial, cpolarTerms, cpolarPurge); cpolarDetails.append(cpolarDetailsSummary, cpolarDetailsBody)\n cpolarSetup.append(cpolarSetupTitle, cpolarComponentStatus, cpolarInstall, cpolarAccount, cpolarDetails)\n const tailscaleInfo = element('details', 'dsh-mobile-control__details')\n const tailscaleInfoSummary = element('summary'); tailscaleInfoSummary.textContent = 'Tailscale 使用说明'\n const tailscaleInfoBody = element('div', 'dsh-mobile-control__details-body')\n const tailscaleInfoText = element('p'); tailscaleInfoText.textContent = '运行组件已随插件提供。首次连接会打开 Tailscale 官方登录和 Funnel 授权页;插件不会接触你的账号密码。'\n tailscaleInfoBody.append(tailscaleInfoText); tailscaleInfo.append(tailscaleInfoSummary, tailscaleInfoBody)\n const remoteAccess = element('div', 'dsh-mobile-control__access'); remoteAccess.hidden = true\n const remoteAccessLabel = element('span', 'dsh-mobile-control__access-label'); remoteAccessLabel.textContent = '远程地址'\n const remoteAccessLink = element('a', 'dsh-mobile-control__access-link'); remoteAccessLink.target = '_blank'; remoteAccessLink.rel = 'noreferrer'; remoteAccess.append(remoteAccessLabel, remoteAccessLink)\n const remoteQr = element('div', 'dsh-mobile-control__qr'); remoteQr.hidden = true\n const remoteStatus = element('p', 'dsh-mobile-control__status'); remoteStatus.textContent = '正在读取远程状态…'; remoteStatus.setAttribute('aria-live', 'polite')\n const remoteGuide = element('section', 'dsh-mobile-control__guide'); remoteGuide.hidden = true; remoteGuide.setAttribute('aria-label', 'Tailscale Funnel 启用步骤')\n const remoteGuideTitle = element('h3', 'dsh-mobile-control__guide-title'); remoteGuideTitle.textContent = '远程访问设置 · 第 2 步'\n const remoteGuideSummary = element('p', 'dsh-mobile-control__guide-summary'); remoteGuideSummary.textContent = 'Tailscale 登录已完成。还需为这台电脑允许 Funnel,官方页面会同时启用 HTTPS。'\n const remoteGuideSteps = element('ol', 'dsh-mobile-control__guide-steps')\n for (const text of ['打开当前节点的 Tailscale 官方授权页。', '确认启用 Funnel;无需再次登录 DSH。', '返回 DSH,插件会自动检查并建立连接。']) {\n const item = element('li'); item.textContent = text; remoteGuideSteps.append(item)\n }\n const remoteGuideNote = element('p', 'dsh-mobile-control__guide-note'); remoteGuideNote.textContent = '需要使用 Owner、Admin 或 Network admin 账号。'\n const remoteGuideActions = element('div', 'dsh-mobile-control__guide-actions')\n const remoteSetup = element('button', 'dsh-mobile-control__primary'); remoteSetup.type = 'button'; remoteSetup.textContent = '继续完成 Funnel 授权'\n const remoteSetupRetry = element('button', 'dsh-mobile-control__secondary'); remoteSetupRetry.type = 'button'; remoteSetupRetry.textContent = '已完成,立即重试'\n remoteGuideActions.append(remoteSetup, remoteSetupRetry); remoteGuide.append(remoteGuideTitle, remoteGuideSummary, remoteGuideSteps, remoteGuideNote, remoteGuideActions)\n const remoteActions = element('div', 'dsh-mobile-control__actions')\n const remoteToggle = element('button', 'dsh-mobile-control__primary'); remoteToggle.type = 'button'; remoteToggle.textContent = '启用远程访问'\n const remoteLogin = element('button', 'dsh-mobile-control__primary'); remoteLogin.type = 'button'; remoteLogin.textContent = '继续登录'; remoteLogin.hidden = true\n const remoteReconnect = element('button', 'dsh-mobile-control__secondary'); remoteReconnect.type = 'button'; remoteReconnect.textContent = '重新连接'; remoteReconnect.hidden = true\n const remotePair = element('button', 'dsh-mobile-control__secondary'); remotePair.type = 'button'; remotePair.textContent = '生成远程配对二维码'; remotePair.disabled = true\n remoteActions.append(remoteToggle, remoteLogin, remoteReconnect, remotePair)\n const remoteManageRow = element('div', 'dsh-mobile-control__manage-row')\n const remoteDevices = element('button', 'dsh-mobile-control__manage'); remoteDevices.type = 'button'; remoteDevices.textContent = '管理远程设备'; remoteDevices.disabled = true\n const remoteReset = element('button', 'dsh-mobile-control__manage'); remoteReset.type = 'button'; remoteReset.textContent = '退出并清除远程登录'\n remoteManageRow.append(remoteDevices, remoteReset)\n const remoteDevicePanel = element('div', 'dsh-mobile-control__devices'); remoteDevicePanel.hidden = true\n header.append(title, close); actions.append(toggle, pair, linkPair)\n lanView.append(access, qrBox, status, extensionStatus, actions, manageRow, devicePanel)\n remoteView.append(remoteIntro, providerSection, cpolarSetup, tailscaleInfo, remoteAccess, remoteQr, remoteStatus, remoteGuide, remoteActions, remoteManageRow, remoteDevicePanel)\n panel.append(header, appDownload, switcher, lanView, remoteView); root.append(panel); document.body.append(root)\n let running = false\n let origin = ''\n let remoteRunning = false\n let remoteReady = false\n let remoteProvider: 'tailscale' | 'cpolar' = 'tailscale'\n let remoteLoginUrl = ''\n let remoteSetupUrl = ''\n let remoteSetupPending = false\n let remoteSetupOpenedAt = 0\n let remoteReconnectBusy = false\n let remoteProviderBusy = false\n let cpolarInstalled = false\n let cpolarConfigured = false\n let providerInfoPinned = false\n let providerInfoHovered = false\n const syncProviderInfo = (): void => {\n const open = providerInfoPinned || providerInfoHovered || providerInfo.contains(document.activeElement)\n providerInfoPopover.hidden = !open\n providerInfoButton.setAttribute('aria-expanded', String(open))\n }\n providerInfo.addEventListener('pointerenter', () => { providerInfoHovered = true; syncProviderInfo() })\n providerInfo.addEventListener('pointerleave', () => { providerInfoHovered = false; syncProviderInfo() })\n providerInfo.addEventListener('focusin', syncProviderInfo)\n providerInfo.addEventListener('focusout', () => { window.setTimeout(syncProviderInfo, 0) })\n providerInfoButton.addEventListener('click', () => { providerInfoPinned = !providerInfoPinned; syncProviderInfo() })\n providerInfoButton.addEventListener('keydown', event => {\n if (event.key !== 'Escape') return\n providerInfoPinned = false\n providerInfoHovered = false\n providerInfoPopover.hidden = true\n providerInfoButton.setAttribute('aria-expanded', 'false')\n })\n const selectView = (remote: boolean): void => {\n lanView.hidden = remote\n remoteView.hidden = !remote\n lanTab.classList.toggle('is-active', !remote)\n remoteTab.classList.toggle('is-active', remote)\n lanTab.setAttribute('aria-pressed', String(!remote))\n remoteTab.setAttribute('aria-pressed', String(remote))\n title.textContent = remote ? '远程访问' : '局域网访问'\n }\n lanTab.addEventListener('click', () => { selectView(false) })\n remoteTab.addEventListener('click', () => { selectView(true); loadRemote() })\n const setOpen = (open: boolean): void => {\n panel.hidden = !open\n for (const trigger of document.querySelectorAll('.dsh-mobile-control__trigger')) trigger.setAttribute('aria-expanded', String(open))\n }\n const render = (data: Record<string, unknown>): void => {\n running = data.running === true\n origin = running && typeof data.origin === 'string' ? data.origin : ''\n access.hidden = origin === ''\n accessLink.href = origin\n accessLink.textContent = origin\n accessLink.title = origin\n status.classList.toggle('is-running', running)\n status.textContent = running ? '局域网访问已开启。' : '局域网访问已关闭。'\n const extensionData = data.extensions\n if (extensionData !== null && typeof extensionData === 'object') {\n const loaded = typeof (extensionData as { loaded?: unknown }).loaded === 'number' ? (extensionData as { loaded: number }).loaded : 0\n const failed = typeof (extensionData as { failed?: unknown }).failed === 'number' ? (extensionData as { failed: number }).failed : 0\n extensionStatus.hidden = false\n extensionStatus.textContent = failed === 0 ? `扩展:${String(loaded)} 个已加载` : `扩展:${String(loaded)} 个已加载,${String(failed)} 个加载失败`\n } else extensionStatus.hidden = true\n if (!running) qrBox.hidden = true\n toggle.textContent = running ? '关闭局域网访问' : '开启局域网访问'\n pair.disabled = !running\n linkPair.disabled = !running\n manageDevices.disabled = !running\n resetAll.disabled = !running\n }\n const showQr = (svg: string, target: HTMLDivElement = qrBox): void => {\n target.replaceChildren()\n if (svg === '') { target.hidden = true; return }\n const image = element('img')\n image.alt = '配对二维码'\n image.width = 176\n image.height = 176\n image.src = `data:image/svg+xml;base64,${btoa(svg)}`\n target.hidden = false\n target.append(image)\n }\n const openPairing = (target: 'key' | 'link'): void => {\n void requestJson('/api/mobile-access/lan/pairing/open', { method: 'POST', body: '{}' }).then(async data => {\n const value = target === 'key'\n ? (typeof data.appKey === 'string' ? data.appKey : '')\n : (typeof data.pairUrl === 'string' ? data.pairUrl : '')\n showQr(typeof data.qrSvg === 'string' ? data.qrSvg : '')\n if (value === '') { status.textContent = '无法生成配对密钥。'; return }\n try {\n await navigator.clipboard.writeText(value)\n status.textContent = target === 'key'\n ? '配对密钥已复制,请粘贴到 Android App。'\n : '配对链接已复制,发给手机后 App 粘贴或浏览器打开即可配对。'\n } catch {\n status.textContent = `请复制${target === 'key' ? '配对密钥' : '配对链接'}:${value}`\n status.classList.add('is-key')\n }\n }, error => { status.textContent = String(error) }).finally(() => {\n pair.disabled = !running\n linkPair.disabled = !running\n })\n }\n toggle.addEventListener('click', () => { toggle.disabled = true; void requestJson('/api/mobile-access/lan/control', { method: 'POST', body: JSON.stringify({ running: !running }) }).then(render, error => { status.textContent = String(error) }).finally(() => { toggle.disabled = false }) })\n const formatTime = (ms: unknown): string => typeof ms === 'number' ? new Date(ms).toLocaleString() : ''\n const renderDevices = (data: Record<string, unknown>): void => {\n const devices = Array.isArray(data.devices) ? data.devices as Record<string, unknown>[] : []\n devicePanel.replaceChildren()\n if (devices.length === 0) {\n const empty = element('p', 'dsh-mobile-control__device-empty'); empty.textContent = '暂无配对设备。'\n devicePanel.append(empty)\n return\n }\n for (const device of devices) {\n const row = element('div', 'dsh-mobile-control__device')\n const label = element('span', 'dsh-mobile-control__device-label')\n label.textContent = typeof device.label === 'string' ? device.label : '设备'\n const meta = element('span', 'dsh-mobile-control__device-meta'); meta.textContent = `到期 ${formatTime(device.expiresAt)}`\n const revoke = element('button', 'dsh-mobile-control__device-revoke'); revoke.type = 'button'; revoke.textContent = '撤销'\n const id = typeof device.id === 'string' ? device.id : ''\n revoke.addEventListener('click', () => {\n void requestJson('/api/mobile-access/lan/devices/revoke', { method: 'POST', body: JSON.stringify({ deviceId: id }) })\n .then(loadDevices, error => { status.textContent = String(error) })\n })\n row.append(label, meta, revoke)\n devicePanel.append(row)\n }\n }\n const loadDevices = (): void => {\n void requestJson('/api/mobile-access/lan/devices').then(renderDevices, error => { status.textContent = String(error) })\n }\n manageDevices.addEventListener('click', () => {\n const show = devicePanel.hidden\n devicePanel.hidden = !show\n if (show) loadDevices()\n })\n resetAll.addEventListener('click', () => {\n if (!window.confirm('确定要移除所有配对设备吗?此操作会立即终止已连接设备。')) return\n void requestJson('/api/mobile-access/lan/devices/reset', { method: 'POST', body: JSON.stringify({ confirm: true }) })\n .then(loadDevices, error => { status.textContent = String(error) })\n })\n const renderRemote = (data: Record<string, unknown>): void => {\n remoteRunning = data.running === true\n remoteProvider = data.provider === 'cpolar' ? 'cpolar' : 'tailscale'\n const cpolar = remoteProvider === 'cpolar'\n tailscaleChoice.classList.toggle('is-selected', !cpolar)\n cpolarChoice.classList.toggle('is-selected', cpolar)\n tailscaleChoice.setAttribute('aria-checked', String(!cpolar))\n cpolarChoice.setAttribute('aria-checked', String(cpolar))\n tailscaleChoice.disabled = remoteProviderBusy\n cpolarChoice.disabled = remoteProviderBusy\n cpolarSetup.hidden = !cpolar\n tailscaleInfo.hidden = cpolar\n remoteReset.textContent = cpolar ? '关闭并清除远程设备' : '退出并清除远程登录'\n const providers = data.providers !== null && typeof data.providers === 'object' ? data.providers as Record<string, unknown> : {}\n const cpolarProvider = providers.cpolar !== null && typeof providers.cpolar === 'object' ? providers.cpolar as Record<string, unknown> : {}\n const component = cpolarProvider.component !== null && typeof cpolarProvider.component === 'object'\n ? cpolarProvider.component as Record<string, unknown>\n : {}\n cpolarInstalled = component.installed === true\n cpolarConfigured = component.configured === true\n cpolarChoiceBadge.textContent = cpolarConfigured ? '已就绪' : cpolarInstalled ? '已安装' : '国内网络优先'\n const cpolarSupported = component.supported !== false\n const componentVersion = typeof component.version === 'string' ? component.version : ''\n const componentDownloadBytes = typeof component.downloadBytes === 'number' ? component.downloadBytes : 0\n const componentStorage = typeof component.storagePath === 'string' ? component.storagePath : 'DSH Mobile 插件私有目录'\n cpolarStorage.textContent = componentStorage\n cpolarStorage.title = componentStorage\n cpolarInstall.hidden = cpolarInstalled || !cpolarSupported\n cpolarInstall.textContent = componentDownloadBytes > 0\n ? `安装官方组件 · ${(componentDownloadBytes / 1024 / 1024).toFixed(1)} MB`\n : '安装官方组件'\n cpolarInstall.disabled = remoteProviderBusy\n cpolarAccount.hidden = !cpolarInstalled || cpolarConfigured\n cpolarConfigure.disabled = remoteProviderBusy\n cpolarPurge.hidden = !cpolarInstalled && !cpolarConfigured\n cpolarComponentStatus.textContent = !cpolarSupported\n ? '当前仅支持 Windows x64。你仍可选择内置的 Tailscale Funnel。'\n : !cpolarInstalled\n ? '尚未安装。只有点击下方按钮后,才会从 cpolar 官网下载固定版本。'\n : !cpolarConfigured\n ? `官方组件 ${componentVersion} 已校验,下一步只需保存账号令牌。`\n : `官方组件 ${componentVersion} 与本机账号配置已就绪。`\n const state = typeof data.state === 'string' ? data.state : 'error'\n const errorCode = typeof data.errorCode === 'string' ? data.errorCode : ''\n const remoteOrigin = typeof data.origin === 'string' ? data.origin : ''\n remoteLoginUrl = typeof data.loginUrl === 'string' ? data.loginUrl : ''\n const candidateSetupUrl = cpolar ? '' : officialFunnelSetupUrl(data.setupUrl)\n const fallbackSetupUrls: Record<string, string> = {\n funnel_permission_required: 'https://tailscale.com/s/no-funnel',\n funnel_https_required: 'https://tailscale.com/s/https',\n funnel_start_failed: 'https://tailscale.com/s/no-funnel',\n }\n remoteSetupUrl = candidateSetupUrl !== '' ? candidateSetupUrl : (fallbackSetupUrls[errorCode] ?? '')\n const needsFunnelSetup = state === 'error' && remoteSetupUrl !== ''\n remoteReady = remoteRunning && state === 'ready' && remoteOrigin !== ''\n remoteAccess.hidden = !remoteReady\n remoteAccessLink.href = remoteOrigin\n remoteAccessLink.textContent = remoteOrigin\n remoteAccessLink.title = remoteOrigin\n remoteStatus.classList.toggle('is-running', remoteReady)\n const labels: Record<string, string> = {\n off: '远程访问未启用。局域网访问不受影响。',\n unavailable: cpolar ? 'cpolar 尚未安装或未完成本机账号配置。' : '当前电脑缺少 Funnel 运行组件,请重新安装完整插件包。',\n starting: cpolar ? '正在连接 cpolar 国内节点…' : '正在启动 Tailscale 安全通道…',\n 'needs-login': '需要在浏览器完成一次 Tailscale 登录。插件不会读取你的密码。',\n connecting: cpolar ? '公网地址已分配,正在启动 DSH 认证网关…' : '登录完成,正在建立公开 HTTPS 地址…',\n ready: '远程访问已就绪。只有已配对设备可以进入 DSH。',\n error: '远程连接未建立。可重新连接,局域网访问仍可正常使用。',\n }\n const errorLabels: Record<string, string> = {\n funnel_permission_required: '登录已完成。请继续授权 Funnel,完成后会自动建立远程连接。',\n funnel_https_required: '登录已完成。请继续授权 Funnel,官方页面会同时启用 HTTPS。',\n funnel_start_failed: '登录已完成。请继续完成 Tailscale Funnel 的首次授权。',\n tailscale_dns_missing: 'Tailscale 暂未提供远程地址。请重新连接并确认已完成登录。',\n gateway_start_failed: '远程网关启动失败。请重新连接,局域网访问不受影响。',\n control_channel_failed: '远程组件连接中断。请重新连接。',\n cpolar_component_missing: 'cpolar 官方组件尚未安装。请先完成上方准备步骤。',\n cpolar_component_invalid: 'cpolar 组件校验失败。请彻底移除后重新安装。',\n cpolar_config_missing: 'cpolar 尚未保存账号令牌。请先完成上方准备步骤。',\n cpolar_config_invalid: 'cpolar 本机配置无效。请重新保存账号令牌。',\n cpolar_port_unavailable: '无法分配本机远程网关端口,请重试。',\n cpolar_launch_failed: 'cpolar 客户端未能启动。',\n cpolar_start_timeout: '连接 cpolar 国内节点超时,请重新连接。',\n cpolar_stopped: 'cpolar 连接已停止。',\n cpolar_exited: 'cpolar 连接意外退出,请重新连接。',\n cpolar_invalid_output: 'cpolar 返回了无法识别的状态。',\n cpolar_invalid_origin: 'cpolar 返回的公网地址未通过校验。',\n }\n remoteStatus.textContent = remoteSetupPending && needsFunnelSetup\n ? 'Tailscale 官方页面已打开。完成启用后返回 DSH,这里会自动重新连接。'\n : (state === 'error' ? (errorLabels[errorCode] ?? labels.error!) : (labels[state] ?? labels.error!))\n remoteGuide.hidden = !needsFunnelSetup\n remoteSetup.disabled = remoteSetupUrl === '' || remoteReconnectBusy\n remoteSetupRetry.disabled = remoteReconnectBusy\n remoteToggle.textContent = remoteRunning ? '关闭远程访问' : '启用远程访问'\n remoteToggle.disabled = remoteProviderBusy || (cpolar && (!cpolarInstalled || !cpolarConfigured))\n remoteLogin.hidden = cpolar || state !== 'needs-login' || remoteLoginUrl === ''\n remoteReconnect.hidden = needsFunnelSetup || (state !== 'error' && state !== 'unavailable')\n || (cpolar && (!cpolarInstalled || !cpolarConfigured))\n remoteActions.hidden = cpolar && (!cpolarInstalled || !cpolarConfigured)\n remotePair.disabled = !remoteReady\n remoteDevices.disabled = !remoteReady\n if (!remoteReady) remoteQr.hidden = true\n if (!needsFunnelSetup) remoteSetupPending = false\n }\n const loadRemote = (): void => {\n void requestJson('/api/mobile-access/remote/control').then(renderRemote, error => { remoteStatus.textContent = String(error) })\n }\n const chooseRemoteProvider = (provider: 'tailscale' | 'cpolar'): void => {\n if (remoteProviderBusy || provider === remoteProvider) return\n if (remoteRunning && !window.confirm('切换连接方式会先关闭当前远程通道。局域网和配对设备不会受影响,是否继续?')) return\n remoteProviderBusy = true\n tailscaleChoice.disabled = true\n cpolarChoice.disabled = true\n remoteStatus.textContent = provider === 'cpolar' ? '正在切换到 cpolar…' : '正在切换到 Tailscale Funnel…'\n void requestJson('/api/mobile-access/remote/provider', { method: 'POST', body: JSON.stringify({ provider }) })\n .then(renderRemote, error => { remoteStatus.textContent = String(error) })\n .finally(() => { remoteProviderBusy = false; loadRemote() })\n }\n tailscaleChoice.addEventListener('click', () => { chooseRemoteProvider('tailscale') })\n cpolarChoice.addEventListener('click', () => { chooseRemoteProvider('cpolar') })\n cpolarInstall.addEventListener('click', () => {\n if (remoteProviderBusy) return\n const accepted = window.confirm('将从 cpolar 官方网站下载并校验固定版本(约 7.3 MB),仅解压到 DSH Mobile 私有目录。不会安装系统服务、写入 PATH/注册表或设置开机启动。是否继续?')\n if (!accepted) return\n remoteProviderBusy = true\n cpolarInstall.disabled = true\n cpolarInstall.textContent = '正在下载并校验…'\n remoteStatus.textContent = '正在安装 cpolar 官方组件。完成前请保持 DSH 运行。'\n void requestJson('/api/mobile-access/remote/cpolar/component/install', { method: 'POST', body: JSON.stringify({ confirm: true }) })\n .then(renderRemote, error => { remoteStatus.textContent = `组件安装失败:${String(error)}` })\n .finally(() => { remoteProviderBusy = false; loadRemote() })\n })\n cpolarConfigure.addEventListener('click', () => {\n if (remoteProviderBusy) return\n const authtoken = cpolarToken.value.trim()\n if (authtoken.length < 20 || /\\s/u.test(authtoken)) {\n remoteStatus.textContent = '请粘贴 cpolar 控制台提供的完整 Authtoken。'\n cpolarToken.focus()\n return\n }\n remoteProviderBusy = true\n cpolarConfigure.disabled = true\n cpolarConfigure.setAttribute('aria-busy', 'true')\n cpolarConfigure.textContent = '正在保存…'\n void requestJson('/api/mobile-access/remote/cpolar/configure', { method: 'POST', body: JSON.stringify({ authtoken }) })\n .then(() => {\n cpolarToken.value = ''\n remoteStatus.textContent = '账号配置已保存,正在建立 cpolar 远程通道…'\n return requestJson('/api/mobile-access/remote/control', { method: 'POST', body: JSON.stringify({ running: true }) })\n })\n .then(renderRemote, error => { remoteStatus.textContent = `配置失败:${String(error)}` })\n .finally(() => { remoteProviderBusy = false; cpolarConfigure.setAttribute('aria-busy', 'false'); cpolarConfigure.textContent = '保存并连接'; loadRemote() })\n })\n cpolarPurge.addEventListener('click', () => {\n if (remoteProviderBusy) return\n if (!window.confirm('彻底移除 DSH Mobile 私有目录中的 cpolar 组件、令牌配置和运行日志?不会影响局域网、DSH 数据或系统中的其他程序。')) return\n remoteProviderBusy = true\n cpolarPurge.disabled = true\n remoteStatus.textContent = '正在关闭通道并清理 DSH Mobile 管理的 cpolar 文件…'\n void requestJson('/api/mobile-access/remote/cpolar/component/purge', { method: 'POST', body: JSON.stringify({ confirm: true }) })\n .then(renderRemote, error => { remoteStatus.textContent = `清理失败:${String(error)}` })\n .finally(() => { remoteProviderBusy = false; cpolarPurge.disabled = false; loadRemote() })\n })\n remoteToggle.addEventListener('click', () => {\n remoteToggle.disabled = true\n void requestJson('/api/mobile-access/remote/control', { method: 'POST', body: JSON.stringify({ running: !remoteRunning }) })\n .then(renderRemote, error => { remoteStatus.textContent = String(error) })\n .finally(loadRemote)\n })\n remoteLogin.addEventListener('click', () => {\n if (remoteLoginUrl !== '') window.open(remoteLoginUrl, '_blank', 'noopener,noreferrer')\n })\n const reconnectRemote = (): void => {\n if (remoteReconnectBusy) return\n remoteReconnectBusy = true\n remoteReconnect.disabled = true\n remoteSetup.disabled = true\n remoteSetupRetry.disabled = true\n remoteStatus.textContent = remoteProvider === 'cpolar' ? '正在重新连接 cpolar 国内节点…' : '正在确认 Tailscale 设置并重新连接…'\n void requestJson('/api/mobile-access/remote/reconnect', { method: 'POST', body: '{}' })\n .then(renderRemote, error => { remoteStatus.textContent = String(error) })\n .finally(() => {\n remoteReconnectBusy = false\n remoteReconnect.disabled = false\n remoteSetup.disabled = remoteSetupUrl === ''\n remoteSetupRetry.disabled = false\n })\n }\n remoteReconnect.addEventListener('click', reconnectRemote)\n remoteSetupRetry.addEventListener('click', () => { remoteSetupPending = false; reconnectRemote() })\n remoteSetup.addEventListener('click', () => {\n if (remoteSetupUrl === '') return\n remoteSetupPending = true\n remoteSetupOpenedAt = Date.now()\n remoteStatus.textContent = 'Tailscale 官方页面已打开。完成启用后返回 DSH,这里会自动重新连接。'\n window.open(remoteSetupUrl, '_blank', 'noopener,noreferrer')\n })\n const retryAfterSetup = (): void => {\n if (!remoteSetupPending || document.visibilityState === 'hidden' || Date.now() - remoteSetupOpenedAt < 800) return\n remoteSetupPending = false\n reconnectRemote()\n }\n window.addEventListener('focus', retryAfterSetup)\n document.addEventListener('visibilitychange', retryAfterSetup)\n remotePair.addEventListener('click', () => {\n remotePair.disabled = true\n void requestJson('/api/mobile-access/remote/pairing/open', { method: 'POST', body: '{}' }).then(async data => {\n const pairUrl = typeof data.pairUrl === 'string' ? data.pairUrl : ''\n showQr(typeof data.qrSvg === 'string' ? data.qrSvg : '', remoteQr)\n if (pairUrl !== '') {\n try { await navigator.clipboard.writeText(pairUrl) } catch { /* QR remains the primary remote handoff. */ }\n }\n remoteStatus.textContent = '远程配对二维码已生成。请在 App 的“远程访问”中扫描。'\n }, error => { remoteStatus.textContent = String(error) }).finally(() => { remotePair.disabled = !remoteReady })\n })\n const renderRemoteDevices = (data: Record<string, unknown>): void => {\n const devices = Array.isArray(data.devices) ? data.devices as Record<string, unknown>[] : []\n remoteDevicePanel.replaceChildren()\n if (devices.length === 0) {\n const empty = element('p', 'dsh-mobile-control__device-empty'); empty.textContent = '暂无远程配对设备。'; remoteDevicePanel.append(empty); return\n }\n for (const device of devices) {\n const row = element('div', 'dsh-mobile-control__device')\n const label = element('span', 'dsh-mobile-control__device-label'); label.textContent = typeof device.label === 'string' ? device.label : '设备'\n const meta = element('span', 'dsh-mobile-control__device-meta'); meta.textContent = `到期 ${formatTime(device.expiresAt)}`\n const revoke = element('button', 'dsh-mobile-control__device-revoke'); revoke.type = 'button'; revoke.textContent = '撤销'\n const id = typeof device.id === 'string' ? device.id : ''\n revoke.addEventListener('click', () => {\n void requestJson('/api/mobile-access/remote/devices/revoke', { method: 'POST', body: JSON.stringify({ deviceId: id }) })\n .then(loadRemoteDevices, error => { remoteStatus.textContent = String(error) })\n })\n row.append(label, meta, revoke); remoteDevicePanel.append(row)\n }\n }\n const loadRemoteDevices = (): void => {\n void requestJson('/api/mobile-access/remote/devices').then(renderRemoteDevices, error => { remoteStatus.textContent = String(error) })\n }\n remoteDevices.addEventListener('click', () => {\n const show = remoteDevicePanel.hidden\n remoteDevicePanel.hidden = !show\n if (show) loadRemoteDevices()\n })\n remoteReset.addEventListener('click', () => {\n const prompt = remoteProvider === 'cpolar'\n ? '关闭 cpolar 远程通道并移除所有远程配对设备?不会修改你的 cpolar 账号或其他隧道。'\n : '退出电脑上的 Tailscale 登录并移除所有远程配对设备?局域网配置不会改变。'\n if (!window.confirm(prompt)) return\n void requestJson('/api/mobile-access/remote/reset', { method: 'POST', body: JSON.stringify({ confirm: true }) })\n .then(renderRemote, error => { remoteStatus.textContent = String(error) })\n })\n pair.addEventListener('click', () => { pair.disabled = true; openPairing('key') })\n linkPair.addEventListener('click', () => { linkPair.disabled = true; openPairing('link') })\n close.addEventListener('click', () => { setOpen(false) })\n const dismiss = (event: PointerEvent): void => {\n if (panel.hidden || !(event.target instanceof Node)) return\n if (!providerInfo.contains(event.target)) {\n providerInfoPinned = false\n providerInfoHovered = false\n syncProviderInfo()\n }\n if (!panel.contains(event.target) && !document.querySelector('.dsh-mobile-control__trigger')?.contains(event.target)) setOpen(false)\n }\n document.addEventListener('pointerdown', dismiss)\n void requestJson('/api/mobile-access/lan/control').then(render, error => { status.textContent = String(error) })\n loadRemote()\n const remotePoll = window.setInterval(() => { if (!panel.hidden && !remoteView.hidden) loadRemote() }, 1_500)\n return { remove: () => { window.clearInterval(remotePoll); window.removeEventListener('focus', retryAfterSetup); document.removeEventListener('visibilitychange', retryAfterSetup); document.removeEventListener('pointerdown', dismiss); root.remove() }, toggle: () => { setOpen(panel.hidden !== false) } }\n}\n\nfunction mobileRequest(path: string, init: RequestInit = {}): Promise<Response> {\n const target = new URL(path, location.href)\n if (target.origin !== location.origin) throw new TypeError('mobile extension requests must stay on the DSH origin')\n const headers = new Headers(init.headers)\n const method = (init.method ?? 'GET').toUpperCase()\n if (method !== 'GET' && method !== 'HEAD') {\n const csrf = document.cookie.split(';').map(value => value.trim()).find(value => value.startsWith('dsh_ma_csrf='))?.slice(12)\n if (csrf !== undefined) headers.set('x-dsh-mobile-csrf', csrf)\n }\n return fetch(target, { ...init, headers, credentials: 'same-origin', cache: 'no-store', redirect: 'error' })\n}\n\nfunction installCustomAssets(): () => void {\n const legacyStyle = element('style'); legacyStyle.dataset.plugin = 'dsh-mobile-custom'; document.head.append(legacyStyle)\n const previous = window.dshMobile\n let legacyMount: MobileExtensionMount | undefined = queuedLegacyMount\n let legacySource = ''\n let legacyRoot: HTMLElement | undefined\n let legacyDispose: (() => void) | undefined\n const definitions = new Map<string, MobileClientDefinition>()\n const active = new Map<string, { readonly controller: AbortController; readonly dispose: () => void; readonly surfaces: Map<string, { readonly dispose: () => void; readonly container: HTMLElement }> }>()\n const styleNodes = new Map<string, HTMLStyleElement>()\n const styleEtags = new Map<string, string>()\n const scriptDigests = new Map<string, string>()\n let manifestEtag = ''\n let expectedDefinitionId: string | undefined\n const SURFACE_HOST_STYLES: Readonly<Record<string, string>> = {\n 'sidebar-action': 'position:fixed;z-index:1100;top:calc(env(safe-area-inset-top) + 8px);left:8px;display:flex;flex-direction:column;gap:6px;pointer-events:none',\n 'header-action': 'position:fixed;z-index:1100;top:calc(env(safe-area-inset-top) + 8px);right:8px;display:flex;flex-direction:column;gap:6px;pointer-events:none',\n 'composer-dock': 'position:fixed;z-index:1100;bottom:calc(env(safe-area-inset-bottom) + 8px);left:50%;transform:translateX(-50%);display:flex;flex-direction:column;gap:6px;pointer-events:none',\n 'settings-section': 'position:fixed;z-index:1100;inset:auto 8px calc(env(safe-area-inset-bottom) + 72px) 8px;max-height:40vh;overflow:auto;pointer-events:none',\n }\n const surfaceHost = (placement: string): HTMLElement | undefined => {\n const existing = document.querySelector<HTMLElement>(`[data-dsh-mobile-surface-host=\"${placement}\"]`)\n if (existing !== null) return existing\n const style = SURFACE_HOST_STYLES[placement]\n if (style === undefined) return undefined\n const host = element('div'); host.dataset.dshMobileSurfaceHost = placement; host.style.cssText = style\n document.body.append(host); return host\n }\n const shellLayer = (): HTMLElement => {\n const existing = document.querySelector<HTMLElement>('[data-dsh-mobile-extension-layer]')\n if (existing !== null) return existing\n const layer = element('div'); layer.dataset.dshMobileExtensionLayer = 'true'; layer.style.cssText = 'position:fixed;inset:0;z-index:1200;pointer-events:none;overflow:hidden'\n document.body.append(layer); return layer\n }\n const toast = (message: string): void => {\n const node = element('div'); node.textContent = message; node.style.cssText = 'position:absolute;top:16px;left:50%;transform:translateX(-50%);padding:9px 14px;border-radius:999px;background:#1f2937;color:white;font:14px system-ui;pointer-events:auto;box-shadow:0 8px 24px #0003'\n shellLayer().append(node); window.setTimeout(() => node.remove(), 2600)\n }\n const materializeNativeFile = (value: unknown): unknown => {\n if (typeof value !== 'object' || value === null || !('base64' in value) || !('name' in value)) return value\n const candidate = value as { base64?: unknown; name?: unknown; type?: unknown }\n if (typeof candidate.base64 !== 'string' || typeof candidate.name !== 'string') return value\n try {\n const encoded = atob(candidate.base64)\n const bytes = Uint8Array.from(encoded, character => character.charCodeAt(0))\n return new File([bytes], candidate.name, { type: typeof candidate.type === 'string' ? candidate.type : 'application/octet-stream' })\n } catch {\n return value\n }\n }\n const invokeNative = async (action: string, input?: unknown): Promise<unknown> => {\n const bridge = window.__DSH_MOBILE_NATIVE__\n if (bridge !== undefined) return materializeNativeFile(await bridge.invoke(action, input))\n if (action === 'share' && typeof navigator.share === 'function') { await navigator.share((input ?? {}) as ShareData); return { ok: true } }\n if (action === 'clipboard.read' && navigator.clipboard !== undefined) return { text: await navigator.clipboard.readText() }\n if (action === 'clipboard.write' && navigator.clipboard !== undefined) { await navigator.clipboard.writeText(typeof input === 'object' && input !== null && 'text' in input ? String((input as { text: unknown }).text) : ''); return { ok: true } }\n if (action === 'files.pick' || action === 'camera.capture') {\n const inputElement = element('input'); inputElement.type = 'file'; inputElement.accept = action === 'camera.capture' ? 'image/*' : '*/*'; if (action === 'camera.capture') inputElement.capture = 'environment';\n return new Promise<File | undefined>(resolve => { inputElement.onchange = () => resolve(inputElement.files?.[0]); inputElement.click() })\n }\n throw new Error('native capability is unavailable')\n }\n const makeApi = (id: string, controller: AbortController): MobileClientApi => {\n const surfaces = active.get(id)?.surfaces ?? new Map()\n const mountSurface = (surface: MobileSurface): (() => void) => {\n if (!/^[a-z][a-z0-9-]{0,63}$/u.test(surface.id) || surface.label.length > 120) throw new Error('invalid mobile surface')\n const container = element('section'); container.dataset.dshMobileSurface = surface.id; container.hidden = surface.placement === 'page' || surface.placement === 'overlay'; container.style.cssText = surface.placement === 'page' || surface.placement === 'overlay' ? 'position:absolute;inset:0;overflow:auto;background:var(--dsw-alias-bg-layer-1,#fff);padding:16px;pointer-events:auto' : 'pointer-events:auto'\n const host = surface.placement === 'page' || surface.placement === 'overlay' ? shellLayer() : surfaceHost(surface.placement) ?? shellLayer()\n host.append(container)\n const mounted = surface.mount(container)\n const dispose = (): void => { if (typeof mounted === 'function') mounted(); container.remove() }\n surfaces.set(surface.id, { dispose, container });\n return () => { if (surfaces.get(surface.id)?.dispose === dispose) surfaces.delete(surface.id); dispose() }\n }\n return {\n host: {\n invoke: (action: string, input: unknown) => mobileRequest(`/mobile-access/extensions/${encodeURIComponent(id)}/actions/${encodeURIComponent(action)}`, { method: 'POST', body: JSON.stringify(input ?? {}) }).then(async response => { const value = await response.json() as unknown; if (!response.ok) throw new Error(typeof value === 'object' && value !== null && 'error' in value ? String((value as { error: unknown }).error) : `HTTP ${String(response.status)}`); return value }),\n fetch: (path: string, init?: RequestInit) => {\n if (!path.startsWith('/') || path.startsWith('//') || path.includes('://')\n || path.split('/').some(part => part === '..' || part === '.')) throw new TypeError('extension routes must be relative')\n return mobileRequest(`/mobile-access/extensions/${encodeURIComponent(id)}/routes${path}`, init)\n },\n },\n ui: { registerSurface: mountSurface, open: id => { const entry = surfaces.get(id); if (entry !== undefined) entry.container.hidden = false }, close: id => { const entry = surfaces.get(id); if (entry !== undefined) entry.container.hidden = true }, toast },\n native: { capabilities: async () => { const bridge = window.__DSH_MOBILE_NATIVE__; return bridge === undefined ? ['files.pick', 'camera.capture', 'share', 'clipboard.read', 'clipboard.write'] : bridge.capabilities() }, invoke: invokeNative },\n signal: controller.signal, document, window,\n }\n }\n const activateDefinition = async (definition: MobileClientDefinition): Promise<void> => {\n const previousActive = active.get(definition.id)\n const controller = new AbortController()\n const surfaces = new Map<string, { readonly dispose: () => void; readonly container: HTMLElement }>()\n active.set(definition.id, { controller, surfaces, dispose: () => { controller.abort(); for (const surface of surfaces.values()) surface.dispose(); surfaces.clear() } })\n try {\n const cleanup = await definition.activate(makeApi(definition.id, controller))\n const current = active.get(definition.id)\n if (current === undefined || current.controller !== controller) { if (typeof cleanup === 'function') cleanup(); return }\n const oldDispose = current.dispose\n active.set(definition.id, { ...current, dispose: () => { if (typeof cleanup === 'function') cleanup(); oldDispose() } })\n previousActive?.dispose()\n } catch {\n active.get(definition.id)?.dispose(); active.delete(definition.id); if (previousActive !== undefined) active.set(definition.id, previousActive)\n }\n }\n const define = (definition: MobileClientDefinition): void => {\n if (definition.apiVersion !== 1 || !/^[a-z][a-z0-9-]{0,63}$/u.test(definition.id) || typeof definition.activate !== 'function') return\n if (expectedDefinitionId !== undefined && definition.id !== expectedDefinitionId) return\n definitions.set(definition.id, definition)\n if (started) void activateDefinition(definition)\n }\n let started = false\n window.dshMobile = Object.freeze({ register: mount => { legacyMount = mount }, define })\n for (const definition of queuedDefinitions.splice(0)) define(definition)\n let legacyJsEtag = ''\n let legacyJsModified = ''\n const refreshLegacy = async (): Promise<void> => {\n try {\n const headers: Record<string, string> = {}\n if (legacyJsEtag !== '') headers['if-none-match'] = legacyJsEtag\n if (legacyJsModified !== '') headers['if-modified-since'] = legacyJsModified\n const response = await fetch('/mobile-access/custom.js', { credentials: 'same-origin', cache: 'no-store', headers })\n if (response.status === 304) return\n if (!response.ok) return\n legacyJsEtag = response.headers.get('etag') ?? ''\n legacyJsModified = response.headers.get('last-modified') ?? ''\n const next = await response.text(); if (next === legacySource) return; legacySource = next; legacyMount = undefined\n const script = element('script'); script.textContent = `${next}\\n//# sourceURL=dsh-mobile-custom.js`; document.head.append(script); script.remove()\n const mount = legacyMount as MobileExtensionMount | undefined\n if (mount === undefined) return\n const nextRoot = element('div'); nextRoot.dataset.dshMobileExtension = 'true'; document.body.append(nextRoot)\n const nextDispose = mount({ document, request: mobileRequest, root: nextRoot, window })\n legacyDispose?.(); legacyRoot?.remove(); legacyRoot = nextRoot; legacyDispose = typeof nextDispose === 'function' ? nextDispose : undefined\n } catch { /* Preserve the last good customization during reconnects. */ }\n }\n const refreshExtensions = async (): Promise<void> => {\n try {\n const headers: Record<string, string> = {}\n if (manifestEtag !== '') headers['if-none-match'] = manifestEtag\n const response = await fetch('/mobile-access/extensions/manifest', { credentials: 'same-origin', cache: 'no-store', headers })\n if (response.status === 304) return\n if (!response.ok) return\n manifestEtag = response.headers.get('etag') ?? ''\n const payload = await response.json() as { extensions?: unknown }\n const entries = Array.isArray(payload.extensions) ? payload.extensions as Record<string, unknown>[] : []\n const seen = new Set<string>()\n for (const entry of entries) {\n if (typeof entry.id !== 'string') continue\n seen.add(entry.id)\n const cssUrl = typeof entry.styleUrl === 'string' ? entry.styleUrl : undefined\n if (cssUrl !== undefined) {\n const cssHeaders: Record<string, string> = {}\n const storedEtag = styleEtags.get(entry.id)\n if (storedEtag !== undefined) cssHeaders['if-none-match'] = storedEtag\n const cssResponse = await fetch(cssUrl, { credentials: 'same-origin', cache: 'no-store', headers: cssHeaders })\n if (cssResponse.status === 304) { /* unchanged */ }\n else if (cssResponse.ok) {\n const nextEtag = cssResponse.headers.get('etag'); if (nextEtag !== null && nextEtag !== '') styleEtags.set(entry.id, nextEtag)\n const css = await cssResponse.text(); const oldStyle = styleNodes.get(entry.id)\n if (oldStyle?.textContent !== css) {\n const node = element('style'); node.dataset.dshMobileExtensionStyle = entry.id; node.textContent = css; document.head.append(node); styleNodes.set(entry.id, node); oldStyle?.remove()\n }\n } else continue\n }\n const scriptUrl = typeof entry.scriptUrl === 'string' ? entry.scriptUrl : undefined\n if (scriptUrl !== undefined) {\n const scriptHeaders: Record<string, string> = {}\n const storedDigest = scriptDigests.get(entry.id)\n if (storedDigest !== undefined) scriptHeaders['if-none-match'] = storedDigest\n const scriptResponse = await fetch(scriptUrl, { credentials: 'same-origin', cache: 'no-store', headers: scriptHeaders })\n if (scriptResponse.status === 304) { /* unchanged */ }\n else if (scriptResponse.ok) {\n const source = await scriptResponse.text(); const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(source)); const key = [...new Uint8Array(digest)].map(value => value.toString(16).padStart(2, '0')).join('');\n if (scriptDigests.get(entry.id) !== key) {\n scriptDigests.set(entry.id, key)\n expectedDefinitionId = entry.id\n try { const script = element('script'); script.textContent = `${source}\\n//# sourceURL=dsh-mobile-extension-${entry.id}.js`; document.head.append(script); script.remove() }\n finally { expectedDefinitionId = undefined }\n }\n } else continue\n }\n const definition = definitions.get(entry.id); if (definition !== undefined && !active.has(entry.id)) await activateDefinition(definition)\n }\n for (const [id, current] of active) if (!seen.has(id) && !definitions.has(id) && id !== 'legacy-custom') { current.dispose(); active.delete(id); styleNodes.get(id)?.remove(); styleNodes.delete(id); styleEtags.delete(id); scriptDigests.delete(id) }\n } catch { /* A temporary reconnect failure must not tear down the last good UI. */ }\n }\n started = true\n for (const definition of definitions.values()) void activateDefinition(definition)\n void refreshLegacy(); void refreshExtensions(); void refreshCssLegacy(legacyStyle)\n const timer = window.setInterval(() => { void refreshLegacy(); void refreshExtensions(); void refreshCssLegacy(legacyStyle) }, 3_000)\n return () => { clearInterval(timer); started = false; legacyDispose?.(); legacyRoot?.remove(); legacyStyle.remove(); for (const current of active.values()) current.dispose(); for (const node of styleNodes.values()) node.remove(); const layer = document.querySelector('[data-dsh-mobile-extension-layer]'); layer?.remove(); for (const host of document.querySelectorAll('[data-dsh-mobile-surface-host]')) host.remove(); if (previous === undefined) delete window.dshMobile; else window.dshMobile = previous }\n}\n\nlet cssEtag = ''\nlet cssModified = ''\nasync function refreshCssLegacy(style: HTMLStyleElement): Promise<void> {\n try {\n const headers: Record<string, string> = {}\n if (cssEtag !== '') headers['if-none-match'] = cssEtag\n if (cssModified !== '') headers['if-modified-since'] = cssModified\n const response = await fetch('/mobile-access/custom.css', { credentials: 'same-origin', cache: 'no-store', headers })\n if (response.status === 304) return\n if (response.ok) {\n cssEtag = response.headers.get('etag') ?? ''\n cssModified = response.headers.get('last-modified') ?? ''\n style.textContent = await response.text()\n }\n } catch { /* Preserve the last good style during reconnects. */ }\n}\n\nconst CONTROL_STYLES = `\n.dsh-mobile-control{position:fixed;z-index:1000;left:16px;bottom:112px;font:14px/1.45 system-ui;color:var(--dsw-alias-label-primary,#16181d)}\n.dsh-mobile-control__panel{box-sizing:border-box;width:min(380px,calc(100vw - 32px));max-height:calc(100vh - 140px);overflow-y:auto;padding:16px;border:1px solid var(--dsw-alias-border-subtle,#e1e5eb);border-radius:18px;background:var(--dsw-alias-bg-layer-2,#fff);box-shadow:0 18px 50px rgb(15 23 42 / 18%)}\n.dsh-mobile-control__header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px}.dsh-mobile-control__panel h2{margin:0;font-size:17px;line-height:24px}.dsh-mobile-control__close{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:0;border-radius:10px;background:transparent;color:inherit;font-size:24px;line-height:1;cursor:pointer}.dsh-mobile-control__close:hover{background:var(--dsw-alias-interactive-bg-hover,#f1f3f6)}\n.dsh-mobile-control__app-download{display:flex;align-items:center;justify-content:space-between;box-sizing:border-box;min-height:38px;margin:0 0 10px;padding:8px 11px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:11px;background:var(--dsw-alias-bg-layer-1,#f7f8fa);color:var(--dsw-alias-label-primary,#16181d);font:600 12px/1.3 system-ui;text-decoration:none}.dsh-mobile-control__app-download::after{color:#2563eb;font-size:14px;content:\"↗\"}.dsh-mobile-control__app-download:hover{border-color:#9fb9e8;background:#f5f8ff;color:#1d4ed8}\n.dsh-mobile-control__switcher{display:grid;grid-template-columns:1fr 1fr;gap:4px;margin:0 0 14px;padding:4px;border-radius:12px;background:var(--dsw-alias-bg-layer-1,#f3f5f8)}.dsh-mobile-control__tab{min-height:36px;border:0;border-radius:9px;background:transparent;color:var(--dsw-alias-label-secondary,#606873);font:600 13px/1 system-ui;cursor:pointer}.dsh-mobile-control__tab.is-active{background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);box-shadow:0 1px 3px rgb(15 23 42 / 10%)}.dsh-mobile-control__view[hidden]{display:none}.dsh-mobile-control__intro{margin:0 0 12px;color:var(--dsw-alias-label-secondary,#606873);font-size:12px;line-height:1.55}.dsh-mobile-control__view.is-remote .dsh-mobile-control__actions{display:grid;grid-template-columns:1fr 1fr;gap:8px}.dsh-mobile-control__view.is-remote .dsh-mobile-control__actions button[hidden]{display:none}\n.dsh-mobile-control__provider-section{position:relative;margin:0 0 12px}.dsh-mobile-control__section-title{margin:0 0 8px;color:var(--dsw-alias-label-primary,#16181d);font:650 13px/1.4 system-ui}.dsh-mobile-control__provider-section>.dsh-mobile-control__section-title{padding-right:42px}.dsh-mobile-control__provider-choices{display:grid;gap:8px}.dsh-mobile-control__provider{display:flex;flex-direction:column;gap:5px;min-height:68px;padding:11px 12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:#fff;color:inherit;text-align:left;cursor:pointer;transition:border-color 160ms ease,background-color 160ms ease,box-shadow 160ms ease}.dsh-mobile-control__provider:hover{border-color:#9fb9e8;background:#f8fbff}.dsh-mobile-control__provider.is-selected{border-color:#2563eb;background:#f5f8ff;box-shadow:0 0 0 1px #2563eb inset}.dsh-mobile-control__provider:disabled{cursor:wait;opacity:.62}.dsh-mobile-control__provider-top{display:flex;align-items:center;justify-content:space-between;gap:8px}.dsh-mobile-control__provider-top strong{font-size:13px}.dsh-mobile-control__provider-badge{flex:none;padding:3px 7px;border-radius:999px;background:#e8f0ff;color:#1d4ed8;font:650 10px/1.2 system-ui}.dsh-mobile-control__provider-badge.is-cpolar{background:#eaf8f2;color:#087454}.dsh-mobile-control__provider-description{color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.45}.dsh-mobile-control__provider-info{position:absolute;z-index:5;top:-13px;right:-8px}.dsh-mobile-control__provider-info-button{display:flex;align-items:center;justify-content:center;width:44px;height:44px;padding:0;border:0;border-radius:50%;background:transparent;color:#475569;cursor:pointer;touch-action:manipulation}.dsh-mobile-control__provider-info-button:hover{background:#f1f5f9;color:#1d4ed8}.dsh-mobile-control__provider-info-glyph{display:flex;align-items:center;justify-content:center;box-sizing:border-box;width:18px;height:18px;border:1.5px solid currentColor;border-radius:50%;font:700 12px/1 system-ui}.dsh-mobile-control__provider-info-popover{position:absolute;z-index:6;top:38px;right:4px;box-sizing:border-box;width:min(292px,calc(100vw - 72px));padding:10px 12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:12px;background:var(--dsw-alias-bg-layer-2,#fff);box-shadow:0 10px 28px rgb(15 23 42 / 16%)}.dsh-mobile-control__provider-info-popover[hidden]{display:none}.dsh-mobile-control__provider-info-popover strong,.dsh-mobile-control__provider-info-popover span{display:block}.dsh-mobile-control__provider-info-popover strong{margin-bottom:3px;font-size:12px}.dsh-mobile-control__provider-info-popover span{color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.55}\n.dsh-mobile-control__cpolar-setup{margin:0 0 12px;padding:12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:#fff}.dsh-mobile-control__cpolar-setup[hidden],.dsh-mobile-control__cpolar-account[hidden],.dsh-mobile-control__details[hidden],.dsh-mobile-control__view.is-remote .dsh-mobile-control__actions[hidden],.dsh-mobile-control__danger[hidden]{display:none}.dsh-mobile-control__component-status,.dsh-mobile-control__component-note{margin:0 0 10px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.55}.dsh-mobile-control__cpolar-setup>.dsh-mobile-control__primary{width:100%;min-height:44px;padding:9px 12px;border-radius:10px;font:600 12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__cpolar-account{margin-top:10px}.dsh-mobile-control__link-row{display:flex;flex-wrap:wrap;gap:6px 12px;margin:0 0 10px}.dsh-mobile-control__text-link{color:#2563eb;font-size:11px;text-decoration:none}.dsh-mobile-control__text-link:hover{text-decoration:underline}.dsh-mobile-control__token-label{display:flex;flex-direction:column;gap:5px;margin:0 0 8px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px}.dsh-mobile-control__token{box-sizing:border-box;width:100%;min-height:44px;padding:9px 10px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:#fff;color:inherit;font:16px/1.4 system-ui}.dsh-mobile-control__cpolar-connect{display:flex;align-items:center;justify-content:center;box-sizing:border-box;width:100%;min-height:44px;padding:10px 14px;border-radius:12px;font:650 13px/1.2 system-ui;cursor:pointer;transition:background-color 160ms ease,border-color 160ms ease,opacity 160ms ease}.dsh-mobile-control__cpolar-connect:hover:not(:disabled){border-color:#1d4ed8;background:#1d4ed8}.dsh-mobile-control__cpolar-connect:active:not(:disabled){border-color:#1e40af;background:#1e40af}.dsh-mobile-control__cpolar-connect:disabled{cursor:wait;opacity:.55}.dsh-mobile-control__details{margin:10px 0 0;border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb);padding-top:9px}.dsh-mobile-control__details>summary{min-height:30px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:30px;cursor:pointer}.dsh-mobile-control__details-body{display:flex;flex-wrap:wrap;align-items:center;gap:7px 12px;padding:4px 0}.dsh-mobile-control__details-body p{flex:1 0 100%;margin:0;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5}.dsh-mobile-control__storage{display:block;flex:1 0 100%;max-width:100%;overflow:hidden;padding:7px 8px;border-radius:8px;background:#f3f5f8;color:#475569;font:10px/1.4 ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__danger{flex:1 0 100%;min-height:38px;margin-top:3px;padding:7px 10px;border:1px solid #dc2626;border-radius:9px;background:transparent;color:#b91c1c;font:12px/1.3 system-ui;cursor:pointer}\n.dsh-mobile-control__access{display:flex;align-items:baseline;gap:6px;min-width:0;margin:0 0 12px}.dsh-mobile-control__access[hidden]{display:none}.dsh-mobile-control__access-label{flex:none;color:var(--dsw-alias-label-secondary,#606873);white-space:nowrap}.dsh-mobile-control__access-label::after{content:\":\"}.dsh-mobile-control__access-link{min-width:0;overflow:hidden;color:#2563eb;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__access-link:hover{text-decoration:underline}.dsh-mobile-control__qr{display:flex;justify-content:center;margin:0 0 12px}.dsh-mobile-control__qr[hidden]{display:none}.dsh-mobile-control__qr img{border-radius:12px;background:#fff;padding:8px}\n.dsh-mobile-control__status{margin:0 0 14px;overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary,#606873)}.dsh-mobile-control__status::before{display:inline-block;width:8px;height:8px;margin-right:7px;border-radius:50%;background:#98a1ad;content:\"\"}.dsh-mobile-control__status.is-running::before{background:#16a36a}.dsh-mobile-control__status.is-key{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;word-break:break-all}\n.dsh-mobile-control__guide{margin:0 0 14px;padding:12px;border:1px solid #bfdbfe;border-radius:12px;background:#eff6ff}.dsh-mobile-control__guide[hidden]{display:none}.dsh-mobile-control__guide-title{margin:0;color:#172554;font:650 13px/1.45 system-ui}.dsh-mobile-control__guide-summary,.dsh-mobile-control__guide-note{margin:4px 0 0;color:#475569;font-size:12px;line-height:1.5}.dsh-mobile-control__guide-steps{margin:8px 0 0;padding-left:20px;color:#1e293b;font-size:12px;line-height:1.6}.dsh-mobile-control__guide-note{color:#64748b}.dsh-mobile-control__guide-actions{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:10px}.dsh-mobile-control__guide-actions button{min-width:0;min-height:44px;padding:8px;border-radius:10px;font:12px/1.25 system-ui;cursor:pointer}.dsh-mobile-control__guide-actions button:disabled{cursor:not-allowed;opacity:.45}\n.dsh-mobile-control__extensions{margin:0 0 12px;color:var(--dsw-alias-label-secondary,#606873);font-size:12px}\n.dsh-mobile-control__actions{display:flex;flex-wrap:nowrap;gap:6px}.dsh-mobile-control__actions button{flex:1 1 0;min-width:0;min-height:40px;padding:8px 4px;border-radius:10px;font:12px/1.2 system-ui;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dsh-mobile-control__secondary{border:1px solid var(--dsw-alias-border-normal,#cfd5dd);background:transparent;color:inherit}.dsh-mobile-control__primary{border:1px solid #2563eb;background:#2563eb;color:#fff}.dsh-mobile-control__actions button:disabled{cursor:not-allowed;opacity:.45}\n.dsh-mobile-control button:focus-visible,.dsh-mobile-control a:focus-visible,.dsh-mobile-control input:focus-visible,.dsh-mobile-control summary:focus-visible{outline:3px solid rgb(37 99 235 / 28%);outline-offset:2px}\n.dsh-mobile-control__trigger{box-sizing:border-box;display:flex;align-items:center;gap:8px;width:calc(100% + 8px);height:34px;margin:4px -4px;padding:6px 2px 6px 10px;border:0;border-radius:12px;background:transparent;color:var(--dsw-alias-label-primary,#16181d);font:14px/22px system-ui;cursor:pointer}.dsh-mobile-control__trigger:hover{background:var(--dsw-alias-interactive-bg-hover,#f1f3f6)}.dsh-mobile-control__trigger.is-rail{width:36px;height:36px;margin:8px 0 10px;padding:0;justify-content:center;border-radius:50%}.dsh-mobile-control__trigger-icon{position:relative;box-sizing:border-box;flex:none;width:14px;height:19px;border:1.7px solid currentColor;border-radius:3px}.dsh-mobile-control__trigger-icon::after{position:absolute;right:4px;bottom:2px;width:4px;height:1.5px;border-radius:2px;background:currentColor;content:\"\"}.dsh-mobile-control__trigger-label{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}\n.dsh-mobile-control__manage-row{display:flex;justify-content:space-between;gap:8px;margin-top:10px}.dsh-mobile-control__manage{flex:1 1 0;min-width:0;min-height:34px;padding:6px 8px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:transparent;color:inherit;font:12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__devices{margin-top:10px;border:1px solid var(--dsw-alias-border-subtle,#e1e5eb);border-radius:10px;padding:8px;max-height:220px;overflow-y:auto}.dsh-mobile-control__device-empty{color:var(--dsw-alias-label-secondary,#606873);font-size:12px;margin:0}.dsh-mobile-control__device{display:flex;align-items:center;gap:8px;padding:6px 2px}.dsh-mobile-control__device + .dsh-mobile-control__device{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__device-label{flex:1 1 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}.dsh-mobile-control__device-meta{flex:none;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;white-space:nowrap}.dsh-mobile-control__device-revoke{flex:none;min-height:28px;padding:4px 8px;border:1px solid #dc2626;border-radius:8px;background:transparent;color:#dc2626;font:12px/1.2 system-ui;cursor:pointer}\n@media (prefers-reduced-motion:reduce){.dsh-mobile-control__provider,.dsh-mobile-control__cpolar-connect{transition:none}}\n`\n\n/** Mount the desktop control or mobile feature enhancements. */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => {\n if (window.__DSH_MOBILE_FRONTEND__ !== 'dedicated') return\n return trustAuthenticatedGatewayConnection(ctx.get('connection'))\n }, 'dsh-mobile: authenticated gateway client trust')\n\n ctx.effect(() => {\n const loopback = isLoopbackHost(location.hostname) && !new URLSearchParams(location.search).has('dsh-mobile-preview')\n const style = element('style'); style.dataset.plugin = 'dsh-mobile'; style.textContent = loopback\n ? CONTROL_STYLES\n : NATIVE_MOBILE_STYLES\n document.head.append(style)\n if (!loopback) {\n const removeCustom = installCustomAssets()\n const removeSurface = installNativeMobileSurface()\n return () => { removeCustom(); removeSurface(); style.remove() }\n }\n const control = installControl()\n const disposeSlot = ctx.slots.inject('sidebar.footer.action', () => ctx.slots.register({ name: 'sidebar.footer.action', id: 'dsh-mobile' }, ({ wide }) => createElement('button', {\n 'aria-expanded': false,\n 'aria-label': '移动访问',\n className: `dsh-mobile-control__trigger${wide ? '' : ' is-rail'}`,\n type: 'button',\n title: '移动访问',\n onClick: control.toggle,\n }, createElement('span', { 'aria-hidden': true, className: 'dsh-mobile-control__trigger-icon' }), wide ? createElement('span', { className: 'dsh-mobile-control__trigger-label' }, '移动访问') : undefined)))\n return () => { disposeSlot(); control.remove(); style.remove() }\n }, 'dsh-mobile: stock mobile adaptation and local control')\n}\n\n/** Client services required by the mobile adaptation. */\nexport const inject: readonly string[] = ['slots']\n"],"mappings":";;;;;;;;;EACA,MAAa,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsJpC,SAAS,WAAW,SAAkB,QAAyB;GAC7D,OAAO,MAAM,KAAK,QAAQ,SAAS,CAAC,CAAC,MAAK,UAAS,MAAM,SAAS,MAAM,CAAC;EAC3E;EAEA,SAAS,mBAAmB,MAAkB,QAAyC;GACrF,OAAO,MAAM,KAAK,KAAK,iBAA8B,SAAS,CAAC,CAAC,CAAC,MAAK,YAAW,WAAW,SAAS,MAAM,CAAC;EAC9G;EAEA,MAAM,4BAA4B;;EAGlC,SAAgB,sBAAsB,aAAqB,YAA6B;GACtF,OAAO,cAAc,6BAA6B,aAAa,cAAc;EAC/E;;EAGA,SAAgB,6BAAyC;GACvD,SAAS,gBAAgB,UAAU,IAAI,0BAA0B;GACjE,MAAM,gBAAgB,SAAqC;IACzD,SAAS,gBAAgB,QAAQ,iBAAiB;GACpD;GACA,MAAM,iBAAiB,UAA8B;IACnD,IAAI,MAAM,gBAAgB,WAAW,MAAM,gBAAgB,OAAO,aAAa,OAAO;GACxF;GACA,MAAM,aAAa,UAA+B;IAChD,IAAI,MAAM,QAAQ,SAAS,MAAM,IAAI,WAAW,OAAO,GAAG,aAAa,UAAU;GACnF;GACA,SAAS,iBAAiB,eAAe,eAAe,IAAI;GAC5D,SAAS,iBAAiB,WAAW,WAAW,IAAI;GACpD,MAAM,WAAW,SAAS,cAAc,QAAQ;GAChD,SAAS,OAAO;GAChB,SAAS,YAAY;GACrB,SAAS,SAAS;GAClB,SAAS,aAAa,cAAc,SAAS;GAC7C,SAAS,KAAK,OAAO,QAAQ;GAC7B,MAAM,cAAc,SAAS,cAAc,KAAK;GAChD,YAAY,YAAY;GACxB,YAAY,aAAa,QAAQ,QAAQ;GACzC,YAAY,aAAa,aAAa,QAAQ;GAC9C,SAAS,KAAK,OAAO,WAAW;GAChC,IAAI,mBAAmB;GACvB,MAAM,wBAA8B;IAClC,MAAM,SAAS,SAAS,cAA2B,0BAA0B;IAC7E,MAAM,QAAQ,WAAW,OAAO,KAAA,IAAY,OAAO,cAA2B,4BAA0B,CAAC,EAAE,aAAa,KAAK;IAC7H,YAAY,cAAc,UAAU,KAAA,IAAY,SAAS,QAAQ;IACjE,YAAY,QAAQ,UAAU;IAC9B,IAAI,qBAAqB,GAAG,OAAO,aAAa,gBAAgB;IAChE,mBAAmB,OAAO,iBAAiB;KACzC,YAAY,gBAAgB,cAAc;KAC1C,mBAAmB;IACrB,GAAG,IAAI;GACT;GACA,MAAM,iBAAiB,UAA4B;IACjD,IAAI,EAAE,MAAM,kBAAkB,UAAU;IACxC,MAAM,SAAS,MAAM,OAAO,QAA2B,0FAAoF;IAC3I,IAAI,WAAW,QAAQ,OAAO,aAAa,UAAU,KAAK,OAAO,aAAa,eAAe,MAAM,QAAQ;IAC3G,OAAO,WAAW,iBAAiB,EAAE;GACvC;GACA,SAAS,iBAAiB,SAAS,eAAe,IAAI;GACtD,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI,YAAY;GAChB,IAAI,kBAAkB;GACtB,IAAI,yBAAyB;GAC7B,IAAI,kBAAkB;GACtB,IAAI;GACJ,IAAI;GACJ,IAAI,qBAAqB;GACzB,MAAM,0BAAyD;IAE7D,QADe,oBAAoB,KAAA,IAAY,KAAA,IAAY,mBAAmB,iBAAiB,QAAQ,EAAA,EACxF,cAAiC,QAAQ,KAAK,KAAA;GAC/D;GACA,MAAM,wBAA8B;IAClC,IAAI,oBAAoB,KAAA,GAAW;IACnC,MAAM,aAAa,KAAK,IAAI,GAAG,gBAAgB,SAAS;IACxD,MAAM,aAAa,sBAAsB,oBAAoB,UAAU;IACvE,qBAAqB;IACrB,IAAI,CAAC,YAAY;IACjB,MAAM,SAAS,kBAAkB;IACjC,IAAI,WAAW,KAAA,KAAa,OAAO,YAAY,OAAO,aAAa,eAAe,MAAM,QAAQ;IAChG,OAAO,MAAM;GACf;GACA,MAAM,uBAAuB,SAAwC;IACnE,IAAI,oBAAoB,MAAM;IAC9B,iBAAiB,oBAAoB,UAAU,eAAe;IAC9D,kBAAkB;IAClB,qBAAqB,MAAM,aAAa;IACxC,iBAAiB,iBAAiB,UAAU,iBAAiB,EAAE,SAAS,KAAK,CAAC;GAChF;GACA,MAAM,qBAAqB,UAA4B;IACrD,IAAI,EAAE,MAAM,kBAAkB,UAAU;IACxC,MAAM,UAAU,MAAM,OAAO,QAAqB,yCAAuC;IACzF,IAAI,YAAY,QAAQ,QAAQ,aAAa,UAAU,KAAK,QAAQ,aAAa,eAAe,MAAM,QAAQ;IAC9G,IAAI,QAAQ,aAAa,eAAe,MAAM,UAAU,QAAQ,aAAa,cAAc,MAAM,QAAQ;IACzG,MAAM,qBAAqB,QAAQ,QAAQ,iCAAiC,MAAM;IAClF,MAAM,yBAAyB,QAAQ,QAAQ,gBAAc;IAC7D,MAAM,oBAAoB,QAAQ,QAAQ,gCAAgC,MAAM,QAC3E,QAAQ,QAAQ,0BAA0B,MAAM;IACrD,IAAI,CAAC,sBAAsB,CAAC,0BAA0B,CAAC,mBAAmB;IAC1E,IAAI,OAAO,WAAW,kCAAkC,CAAC,CAAC,SAAS;IACnE,IAAI,oBAAoB,GAAG,qBAAqB,eAAe;IAC/D,IAAI,2BAA2B,GAAG,qBAAqB,sBAAsB;IAC7E,kBAAkB,4BAA4B;KAC5C,kBAAkB;KAClB,MAAM,SAAS,qBACX,SAAS,cAA2B,oCAAoC,IACxE;KACJ,IAAI,WAAW,QAAQ,WAAW,KAAA,GAAW;KAC7C,kBAAkB,gBAAgB,iCAAiC;KACnE,OAAO,gBAAgB,iCAAiC;KACxD,yBAAyB,4BAA4B;MACnD,yBAAyB;MACzB,mBAAmB;MACnB,OAAO,QAAQ,0BAA0B;MACzC,IAAI,oBAAoB,GAAG,aAAa,eAAe;MACvD,kBAAkB,OAAO,iBAAiB;OACxC,OAAO,gBAAgB,iCAAiC;OACxD,IAAI,qBAAqB,QAAQ,mBAAmB,KAAA;OACpD,kBAAkB;MACpB,GAAG,GAAG;KACR,CAAC;IACH,CAAC;GACH;GACA,SAAS,iBAAiB,SAAS,iBAAiB;GAEpD,MAAM,aAAmB;IACvB,YAAY;IACZ,QAAQ,mBAAmB,UAAU,QAAQ;IAC7C,MAAM,kBAAkB,SAAS,cAA2B,YAAY,KAAK,KAAA;IAC7E,IAAI,UAAU,KAAA,GAAW,MAAM,QAAQ,iBAAiB;IACxD,UAAU,UAAU,KAAA,IAChB,SAAS,cAA2B,cAAc,KAAK,KAAA,IACvD,mBAAmB,OAAO,aAAa;IAC3C,MAAM,SAAS,UAAU,KAAA,IAAY,kBAAkB,mBAAmB,OAAO,YAAY;IAC7F,MAAM,UAAU,UAAU,KAAA,IAAY,KAAA,IAAY,mBAAmB,OAAO,aAAa;IACzF,MAAM,SAAS,UAAU,KAAA,IAAY,KAAA,IAAY,mBAAmB,OAAO,SAAS;IACpF,IAAI,WAAW,KAAA,GAAW;KACxB,oBAAoB,KAAA,CAAS;KAC7B;IACF;IACA,IAAI,WAAW,KAAA,GAAW;KACxB,OAAO,QAAQ,kBAAkB;KACjC,OAAO,cAA2B,QAAQ,CAAC,EAAE,aAAa,0BAA0B,MAAM;KAC1F,WAAW,mBAAmB,QAAQ,WAAW;KACjD,IAAI,aAAa,KAAA,GAAW,SAAS,QAAQ,gBAAgB;KAC7D,MAAM,eAAe,OAAO,cAA2B,4BAA4B;KACnF,oBAAoB,gBAAgB,KAAA,CAAS;KAC7C,MAAM,gBAAgB,iBAAiB,OAAO,KAAA,IAAY,mBAAmB,cAAc,QAAQ;KACnG,IAAI,kBAAkB,KAAA,GAAW;MAC/B,cAAc,QAAQ,yBAAyB;MAC/C,cAAc,aAAa,aAAa,QAAQ;MAChD,MAAM,SAAS,cAAc,cAAiC,QAAQ;MACtE,IAAI,WAAW,MAAM;OACnB,OAAO,WAAW;OAClB,IAAI,OAAO,UAAU,OAAO,gBAAgB,aAAa;YACpD,OAAO,aAAa,eAAe,MAAM;MAChD;KACF;KACA,MAAM,gBAAgB,iBAAiB,OAAO,KAAA,IAAY,mBAAmB,cAAc,SAAS;KACpG,MAAM,gBAAgB,eAAe;KACrC,IAAI,kBAAkB,KAAA,KAAa,kBAAkB,QAAQ,kBAAkB,KAAA,KAAa,WAAW,eAAe,SAAS,GAAG;MAChI,cAAc,QAAQ,yBAAyB;MAC/C,cAAc,QAAQ,yBAAyB;KACjD;KACA,KAAK,MAAM,SAAS,OAAO,iBAAmC,OAAO,GAAG;MAEtE,IADe,MAAM,eACT,QAAQ,yBAAyB,QAAQ;MACrD,MAAM,UAAU,SAAS,cAAc,KAAK;MAC5C,QAAQ,QAAQ,uBAAuB;MACvC,MAAM,OAAO,OAAO;MACpB,QAAQ,OAAO,KAAK;KACtB;KAEA,MAAM,cADe,OAAO,cAA2B,sBACxB,CAAC,EAAE,cAA2B,8BAA8B,CAAC,EAAE;KAC9F,IAAI,uBAAuB,aAAa;MACtC,YAAY,QAAQ,uBAAuB;MAC3C,MAAM,SAAS,MAAM,KAAK,YAAY,QAAQ,CAAC,CAAC,QAAQ,UAAgC,iBAAiB,WAAW;MACpH,MAAM,gBAAgB,OAAO;MAC7B,MAAM,mBAAmB,OAAO,GAAG,EAAE;MACrC,IAAI,kBAAkB,KAAA,GAAW,cAAc,QAAQ,yBAAyB;MAChF,IAAI,qBAAqB,KAAA,KAAa,qBAAqB,eAAe;OACxE,iBAAiB,QAAQ,4BAA4B;OACrD,MAAM,eAAe,iBAAiB,cAAiC,mEAA+D;OACtI,IAAI,iBAAiB,MAAM;QACzB,aAAa,QAAQ,gCAAgC;QACrD,aAAa,eAAe,aAAa,kCAAkC,MAAM;QACjF,aAAa,cAA2B,4BAA0B,CAAC,EAAE,aAAa,wCAAwC,MAAM;OAClI;MACF;KACF;IACF;IACA,IAAI,WAAW,KAAA,GAAW,OAAO,QAAQ,kBAAkB;IAC3D,IAAI,YAAY,KAAA,GAAW;KACzB,QAAQ,QAAQ,mBAAmB;KACnC,MAAM,aAAa,OAAO,MAAM,oBAAoB,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,GAAG,EAAE;KAC7E,QAAQ,QAAQ,OAAO,OAAO,eAAe,KAAA,KAAa,eAAe,SAAS,eAAe,GAAG;IACtG;IACA,MAAM,WAAW,MAAM,KAAK,SAAS,iBAA8B,mBAAiB,CAAC,CAAC,CAAC,MAAK,WAAU;KAEpG,OADkB,MAAM,KAAK,OAAO,QAAQ,CAAC,CAAC,MAAK,UAAS,iBAAiB,eAAe,WAAW,OAAO,MAAM,CACrG,MAAM,KAAA;IACvB,CAAC;IACD,IAAI,aAAa,KAAA,GAAW;KAC1B,SAAS,QAAQ,oBAAoB;KACrC,MAAM,MAAM,MAAM,KAAK,SAAS,QAAQ,CAAC,CAAC,MAAK,UAAS,iBAAiB,eAAe,WAAW,OAAO,MAAM,CAAC;KACjH,MAAM,UAAU,MAAM,KAAK,SAAS,QAAQ,CAAC,CAAC,MAAK,UAAS,iBAAiB,eAAe,WAAW,OAAO,UAAU,CAAC;KACzH,IAAI,QAAQ,KAAA,GAAW;MACrB,IAAI,QAAQ,uBAAuB;MACnC,mBAAmB,KAAK,UAAU,CAAC,EAAE,aAAa,iCAAiC,MAAM;KAC3F;KACA,IAAI,YAAY,KAAA,GAAW;MACzB,QAAQ,QAAQ,2BAA2B;MAC3C,mBAAmB,SAAS,SAAS,CAAC,EAAE,aAAa,mCAAmC,MAAM;MAC9F,mBAAmB,SAAS,UAAU,CAAC,EAAE,aAAa,oCAAoC,MAAM;KAClG;IACF;IACA,IAAI,YAAY,KAAA,GAAW;IAC3B,QAAQ,QAAQ,mBAAmB;IACnC,SAAS,mBAAmB,SAAS,SAAS;IAC9C,IAAI,YAAY,QAAQ;IACxB,OAAO,cAAc,KAAA,KAAa,cAAc,QAAQ,cAAc,WAAW,CAAC,WAAW,WAAW,OAAO,GAAG,YAAY,UAAU;IACxI,cAAc,cAAc,WAAW,cAAc,OAAO,YAAY,KAAA;IACxE,IAAI,gBAAgB,KAAA,GAAW;IAC/B,YAAY,QAAQ,uBAAuB;IAC3C,KAAK,MAAM,SAAS,YAAY,iBAA8B,iCAA+B,GAC3F,IAAI,MAAM,aAAa,KAAK,MAAM,mBAAmB,MAAM,cAAc;IAE3E,IAAI,WAAW,KAAA,GAAW,OAAO,QAAQ,kBAAkB;IAC3D,MAAM,YAAY,WAAW,aAAa,YAAY;IACtD,QAAQ,QAAQ,OAAO,OAAO,CAAC,SAAS;IACxC,SAAS,SAAS;GACpB;GACA,MAAM,iBAAuB;IAAE,IAAI,cAAc,GAAG,YAAY,sBAAsB,IAAI;GAAE;GAC5F,MAAM,WAAW,IAAI,iBAAiB,QAAQ;GAC9C,SAAS,QAAQ,SAAS,MAAM;IAAE,WAAW;IAAM,SAAS;IAAM,YAAY;IAAM,iBAAiB;KAAC;KAAS;KAAS;IAAU;GAAE,CAAC;GACrI,SAAS,iBAAiB,eAAe;IAAE,IAAI,SAAS,QAAQ,SAAS,QAAQ,QAAQ,MAAM;GAAE,CAAC;GAClG,KAAK;GACL,aAAa;IACX,SAAS,WAAW;IACpB,SAAS,oBAAoB,SAAS,eAAe,IAAI;IACzD,IAAI,qBAAqB,GAAG,OAAO,aAAa,gBAAgB;IAChE,YAAY,OAAO;IACnB,IAAI,cAAc,GAAG,qBAAqB,SAAS;IACnD,IAAI,oBAAoB,GAAG,qBAAqB,eAAe;IAC/D,IAAI,2BAA2B,GAAG,qBAAqB,sBAAsB;IAC7E,IAAI,oBAAoB,GAAG,aAAa,eAAe;IACvD,kBAAkB,gBAAgB,iCAAiC;IACnE,iBAAiB,oBAAoB,UAAU,eAAe;IAC9D,SAAS,oBAAoB,eAAe,eAAe,IAAI;IAC/D,SAAS,oBAAoB,WAAW,WAAW,IAAI;IACvD,SAAS,oBAAoB,SAAS,iBAAiB;IACvD,SAAS,OAAO;IAChB,SAAS,gBAAgB,UAAU,OAAO,0BAA0B;IACpE,OAAO,SAAS,gBAAgB,QAAQ;GAC1C;EACF;;;EClVA,MAAM,oBAA8C,CAAC;EACrD,IAAI;EACJ,IAAI,OAAO,WAAW,eAAe,OAAO,cAAc,KAAA,GACxD,OAAO,YAAY;GACjB,WAAU,UAAS;IAAE,oBAAoB;GAAM;GAC/C,SAAQ,eAAc;IAAE,kBAAkB,KAAK,UAAU;GAAE;EAC7D;EAGF,SAAS,eAAe,UAA2B;GACjD,OAAO,aAAa,eAAe,aAAa,eAAe,aAAa,SAAS,aAAa;EACpG;;;;;;;EAQA,SAAgB,oCAAoC,YAAgD;GAClG,MAAM,WAAW,WAAW;GAC5B,WAAW,aAAa;GACxB,aAAa;IAAE,WAAW,aAAa;GAAS;EAClD;EAEA,SAAS,QAA+C,KAAQ,WAA8C;GAC5G,MAAM,OAAO,SAAS,cAAc,GAAG;GACvC,IAAI,cAAc,KAAA,GAAW,KAAK,YAAY;GAC9C,OAAO;EACT;EAEA,eAAe,YAAY,MAAc,MAAsD;GAC7F,MAAM,WAAW,MAAM,MAAM,MAAM;IAAE,GAAG;IAAM,SAAS;KAAE,gBAAgB;KAAoB,GAAG,MAAM;IAAQ;GAAE,CAAC;GACjH,MAAM,OAAO,MAAM,SAAS,KAAK;GACjC,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,QAAQ,OAAO,SAAS,MAAM,GAAG;GACjH,OAAO;EACT;EAEA,SAAS,uBAAuB,OAAwB;GACtD,IAAI,OAAO,UAAU,YAAY,MAAM,SAAS,MAAM,OAAO;GAC7D,IAAI;GACJ,IAAI;IAAE,MAAM,IAAI,IAAI,KAAK;GAAE,QAAQ;IAAE,OAAO;GAAG;GAC/C,MAAM,aAAa,IAAI,SAAS,CAAC,CAAC,QAAQ,QAAQ,EAAE;GACpD,IAAI,eAAe,uCAAuC,eAAe,iCAAiC,OAAO;GACjH,IAAI,IAAI,aAAa,YAAY,IAAI,aAAa,yBAAyB,IAAI,SAAS,MACnF,IAAI,aAAa,MAAM,IAAI,aAAa,IAAI,OAAO;GACxD,OAAO,IAAI,SAAS;EACtB;EAEA,SAAS,iBAA6D;GACpE,MAAM,OAAO,QAAQ,OAAO,oBAAoB;GAChD,MAAM,QAAQ,QAAQ,WAAW,2BAA2B;GAAG,MAAM,SAAS;GAC9E,MAAM,aAAa,cAAc,MAAM;GACvC,MAAM,SAAS,QAAQ,UAAU,4BAA4B;GAC7D,MAAM,QAAQ,QAAQ,IAAI;GAAG,MAAM,cAAc;GACjD,MAAM,QAAQ,QAAQ,UAAU,2BAA2B;GAAG,MAAM,OAAO;GAAU,MAAM,cAAc;GAAK,MAAM,aAAa,cAAc,QAAQ;GACvJ,MAAM,cAAc,QAAQ,KAAK,kCAAkC;GAAG,YAAY,OAAO;GAAyD,YAAY,SAAS;GAAU,YAAY,MAAM;GAAuB,YAAY,cAAc;GAAkB,YAAY,aAAa,cAAc,sCAAsC;GACnV,MAAM,WAAW,QAAQ,OAAO,8BAA8B;GAC9D,MAAM,SAAS,QAAQ,UAAU,mCAAmC;GAAG,OAAO,OAAO;GAAU,OAAO,cAAc;GACpH,MAAM,YAAY,QAAQ,UAAU,yBAAyB;GAAG,UAAU,OAAO;GAAU,UAAU,cAAc;GACnH,OAAO,aAAa,gBAAgB,MAAM;GAAG,UAAU,aAAa,gBAAgB,OAAO;GAAG,SAAS,OAAO,QAAQ,SAAS;GAC/H,MAAM,UAAU,QAAQ,OAAO,0BAA0B;GACzD,MAAM,SAAS,QAAQ,OAAO,4BAA4B;GAAG,OAAO,SAAS;GAC7E,MAAM,cAAc,QAAQ,QAAQ,kCAAkC;GAAG,YAAY,cAAc;GACnG,MAAM,aAAa,QAAQ,KAAK,iCAAiC;GAAG,WAAW,SAAS;GAAU,WAAW,MAAM;GACnH,OAAO,OAAO,aAAa,UAAU;GACrC,MAAM,QAAQ,QAAQ,OAAO,wBAAwB;GAAG,MAAM,SAAS;GACvE,MAAM,SAAS,QAAQ,KAAK,4BAA4B;GAAG,OAAO,cAAc;GAChF,MAAM,kBAAkB,QAAQ,KAAK,gCAAgC;GAAG,gBAAgB,SAAS;GACjG,MAAM,UAAU,QAAQ,OAAO,6BAA6B;GAC5D,MAAM,SAAS,QAAQ,UAAU,+BAA+B;GAAG,OAAO,OAAO;GACjF,MAAM,OAAO,QAAQ,UAAU,6BAA6B;GAAG,KAAK,OAAO;GAAU,KAAK,cAAc;GACxG,MAAM,WAAW,QAAQ,UAAU,+BAA+B;GAAG,SAAS,OAAO;GAAU,SAAS,cAAc;GACtH,MAAM,YAAY,QAAQ,OAAO,gCAAgC;GACjE,MAAM,gBAAgB,QAAQ,UAAU,4BAA4B;GAAG,cAAc,OAAO;GAAU,cAAc,cAAc;GAClI,MAAM,WAAW,QAAQ,UAAU,4BAA4B;GAAG,SAAS,OAAO;GAAU,SAAS,cAAc;GACnH,UAAU,OAAO,eAAe,QAAQ;GACxC,MAAM,cAAc,QAAQ,OAAO,6BAA6B;GAAG,YAAY,SAAS;GACxF,MAAM,aAAa,QAAQ,OAAO,oCAAoC;GAAG,WAAW,SAAS;GAC7F,MAAM,cAAc,QAAQ,KAAK,2BAA2B;GAAG,YAAY,cAAc;GACzF,MAAM,kBAAkB,QAAQ,WAAW,sCAAsC;GACjF,MAAM,kBAAkB,QAAQ,MAAM,mCAAmC;GAAG,gBAAgB,cAAc;GAC1G,MAAM,eAAe,QAAQ,OAAO,mCAAmC;GACvE,MAAM,qBAAqB,QAAQ,UAAU,0CAA0C;GAAG,mBAAmB,OAAO;GAAU,mBAAmB,aAAa,cAAc,eAAe;GAAG,mBAAmB,aAAa,iBAAiB,OAAO;GAAG,mBAAmB,aAAa,iBAAiB,0BAA0B;GAAG,mBAAmB,aAAa,oBAAoB,0BAA0B;GACrZ,MAAM,oBAAoB,QAAQ,QAAQ,yCAAyC;GAAG,kBAAkB,cAAc;GAAK,kBAAkB,aAAa,eAAe,MAAM;GAC/K,MAAM,sBAAsB,QAAQ,OAAO,2CAA2C;GAAG,oBAAoB,KAAK;GAA4B,oBAAoB,aAAa,QAAQ,SAAS;GAAG,oBAAoB,SAAS;GAChO,MAAM,oBAAoB,QAAQ,QAAQ;GAAG,kBAAkB,cAAc;GAC7E,MAAM,mBAAmB,QAAQ,MAAM;GAAG,iBAAiB,cAAc;GACzE,mBAAmB,OAAO,iBAAiB;GAAG,oBAAoB,OAAO,mBAAmB,gBAAgB;GAAG,aAAa,OAAO,oBAAoB,mBAAmB;GAC1K,MAAM,kBAAkB,QAAQ,OAAO,sCAAsC;GAAG,gBAAgB,aAAa,QAAQ,YAAY;GAAG,gBAAgB,aAAa,cAAc,QAAQ;GACvL,MAAM,kBAAkB,QAAQ,UAAU,8BAA8B;GAAG,gBAAgB,OAAO;GAAU,gBAAgB,aAAa,QAAQ,OAAO;GAAG,gBAAgB,aAAa,gBAAgB,MAAM;GAC9M,MAAM,qBAAqB,QAAQ,QAAQ,kCAAkC;GAC7E,MAAM,sBAAsB,QAAQ,QAAQ;GAAG,oBAAoB,cAAc;GACjF,MAAM,uBAAuB,QAAQ,QAAQ,oCAAoC;GAAG,qBAAqB,cAAc;GACvH,MAAM,6BAA6B,QAAQ,QAAQ,0CAA0C;GAAG,2BAA2B,cAAc;GACzI,mBAAmB,OAAO,qBAAqB,oBAAoB;GAAG,gBAAgB,OAAO,oBAAoB,0BAA0B;GAC3I,MAAM,eAAe,QAAQ,UAAU,8BAA8B;GAAG,aAAa,OAAO;GAAU,aAAa,aAAa,QAAQ,OAAO;GAAG,aAAa,aAAa,gBAAgB,OAAO;GACnM,MAAM,kBAAkB,QAAQ,QAAQ,kCAAkC;GAC1E,MAAM,mBAAmB,QAAQ,QAAQ;GAAG,iBAAiB,cAAc;GAC3E,MAAM,oBAAoB,QAAQ,QAAQ,8CAA8C;GAAG,kBAAkB,cAAc;GAC3H,MAAM,0BAA0B,QAAQ,QAAQ,0CAA0C;GAAG,wBAAwB,cAAc;GACnI,gBAAgB,OAAO,kBAAkB,iBAAiB;GAAG,aAAa,OAAO,iBAAiB,uBAAuB;GACzH,gBAAgB,OAAO,iBAAiB,YAAY;GAAG,gBAAgB,OAAO,iBAAiB,cAAc,eAAe;GAC5H,MAAM,cAAc,QAAQ,WAAW,kCAAkC;GAAG,YAAY,SAAS;GACjG,MAAM,mBAAmB,QAAQ,MAAM,mCAAmC;GAAG,iBAAiB,cAAc;GAC5G,MAAM,wBAAwB,QAAQ,KAAK,sCAAsC;GAAG,sBAAsB,cAAc;GACxH,MAAM,gBAAgB,QAAQ,UAAU,6BAA6B;GAAG,cAAc,OAAO;GAAU,cAAc,cAAc;GACnI,MAAM,gBAAgB,QAAQ,OAAO,oCAAoC;GAAG,cAAc,SAAS;GACnG,MAAM,oBAAoB,QAAQ,KAAK,oCAAoC;GAAG,kBAAkB,cAAc;GAC9G,MAAM,qBAAqB,QAAQ,OAAO,8BAA8B;GACxE,MAAM,eAAe,QAAQ,KAAK,+BAA+B;GAAG,aAAa,OAAO;GAAuC,aAAa,SAAS;GAAU,aAAa,MAAM;GAAuB,aAAa,cAAc;GACpO,MAAM,kBAAkB,QAAQ,KAAK,+BAA+B;GAAG,gBAAgB,OAAO;GAAqC,gBAAgB,SAAS;GAAU,gBAAgB,MAAM;GAAuB,gBAAgB,cAAc;GACjP,mBAAmB,OAAO,cAAc,eAAe;GACvD,MAAM,mBAAmB,QAAQ,SAAS,iCAAiC;GAAG,iBAAiB,cAAc;GAC7G,MAAM,cAAc,QAAQ,SAAS,2BAA2B;GAAG,YAAY,OAAO;GAAY,YAAY,eAAe;GAAO,YAAY,aAAa;GAAO,YAAY,cAAc;GAAuB,iBAAiB,OAAO,WAAW;GACxP,MAAM,kBAAkB,QAAQ,UAAU,gEAAgE;GAAG,gBAAgB,OAAO;GAAU,gBAAgB,cAAc;GAC5K,cAAc,OAAO,mBAAmB,oBAAoB,kBAAkB,eAAe;GAC7F,MAAM,gBAAgB,QAAQ,WAAW,6BAA6B;GACtE,MAAM,uBAAuB,QAAQ,SAAS;GAAG,qBAAqB,cAAc;GACpF,MAAM,oBAAoB,QAAQ,OAAO,kCAAkC;GAC3E,MAAM,oBAAoB,QAAQ,GAAG;GAAG,kBAAkB,cAAc;GACxE,MAAM,gBAAgB,QAAQ,QAAQ,6BAA6B;GAAG,cAAc,cAAc;GAClG,MAAM,iBAAiB,QAAQ,KAAK,+BAA+B;GAAG,eAAe,OAAO;GAAmC,eAAe,SAAS;GAAU,eAAe,MAAM;GAAuB,eAAe,cAAc;GAC1O,MAAM,cAAc,QAAQ,KAAK,+BAA+B;GAAG,YAAY,OAAO;GAA8B,YAAY,SAAS;GAAU,YAAY,MAAM;GAAuB,YAAY,cAAc;GACtN,MAAM,cAAc,QAAQ,UAAU,4BAA4B;GAAG,YAAY,OAAO;GAAU,YAAY,cAAc;GAC5H,kBAAkB,OAAO,mBAAmB,eAAe,gBAAgB,aAAa,WAAW;GAAG,cAAc,OAAO,sBAAsB,iBAAiB;GAClK,YAAY,OAAO,kBAAkB,uBAAuB,eAAe,eAAe,aAAa;GACvG,MAAM,gBAAgB,QAAQ,WAAW,6BAA6B;GACtE,MAAM,uBAAuB,QAAQ,SAAS;GAAG,qBAAqB,cAAc;GACpF,MAAM,oBAAoB,QAAQ,OAAO,kCAAkC;GAC3E,MAAM,oBAAoB,QAAQ,GAAG;GAAG,kBAAkB,cAAc;GACxE,kBAAkB,OAAO,iBAAiB;GAAG,cAAc,OAAO,sBAAsB,iBAAiB;GACzG,MAAM,eAAe,QAAQ,OAAO,4BAA4B;GAAG,aAAa,SAAS;GACzF,MAAM,oBAAoB,QAAQ,QAAQ,kCAAkC;GAAG,kBAAkB,cAAc;GAC/G,MAAM,mBAAmB,QAAQ,KAAK,iCAAiC;GAAG,iBAAiB,SAAS;GAAU,iBAAiB,MAAM;GAAc,aAAa,OAAO,mBAAmB,gBAAgB;GAC1M,MAAM,WAAW,QAAQ,OAAO,wBAAwB;GAAG,SAAS,SAAS;GAC7E,MAAM,eAAe,QAAQ,KAAK,4BAA4B;GAAG,aAAa,cAAc;GAAa,aAAa,aAAa,aAAa,QAAQ;GACxJ,MAAM,cAAc,QAAQ,WAAW,2BAA2B;GAAG,YAAY,SAAS;GAAM,YAAY,aAAa,cAAc,uBAAuB;GAC9J,MAAM,mBAAmB,QAAQ,MAAM,iCAAiC;GAAG,iBAAiB,cAAc;GAC1G,MAAM,qBAAqB,QAAQ,KAAK,mCAAmC;GAAG,mBAAmB,cAAc;GAC/G,MAAM,mBAAmB,QAAQ,MAAM,iCAAiC;GACxE,KAAK,MAAM,QAAQ;IAAC;IAA4B;IAA2B;GAAsB,GAAG;IAClG,MAAM,OAAO,QAAQ,IAAI;IAAG,KAAK,cAAc;IAAM,iBAAiB,OAAO,IAAI;GACnF;GACA,MAAM,kBAAkB,QAAQ,KAAK,gCAAgC;GAAG,gBAAgB,cAAc;GACtG,MAAM,qBAAqB,QAAQ,OAAO,mCAAmC;GAC7E,MAAM,cAAc,QAAQ,UAAU,6BAA6B;GAAG,YAAY,OAAO;GAAU,YAAY,cAAc;GAC7H,MAAM,mBAAmB,QAAQ,UAAU,+BAA+B;GAAG,iBAAiB,OAAO;GAAU,iBAAiB,cAAc;GAC9I,mBAAmB,OAAO,aAAa,gBAAgB;GAAG,YAAY,OAAO,kBAAkB,oBAAoB,kBAAkB,iBAAiB,kBAAkB;GACxK,MAAM,gBAAgB,QAAQ,OAAO,6BAA6B;GAClE,MAAM,eAAe,QAAQ,UAAU,6BAA6B;GAAG,aAAa,OAAO;GAAU,aAAa,cAAc;GAChI,MAAM,cAAc,QAAQ,UAAU,6BAA6B;GAAG,YAAY,OAAO;GAAU,YAAY,cAAc;GAAQ,YAAY,SAAS;GAC1J,MAAM,kBAAkB,QAAQ,UAAU,+BAA+B;GAAG,gBAAgB,OAAO;GAAU,gBAAgB,cAAc;GAAQ,gBAAgB,SAAS;GAC5K,MAAM,aAAa,QAAQ,UAAU,+BAA+B;GAAG,WAAW,OAAO;GAAU,WAAW,cAAc;GAAa,WAAW,WAAW;GAC/J,cAAc,OAAO,cAAc,aAAa,iBAAiB,UAAU;GAC3E,MAAM,kBAAkB,QAAQ,OAAO,gCAAgC;GACvE,MAAM,gBAAgB,QAAQ,UAAU,4BAA4B;GAAG,cAAc,OAAO;GAAU,cAAc,cAAc;GAAU,cAAc,WAAW;GACrK,MAAM,cAAc,QAAQ,UAAU,4BAA4B;GAAG,YAAY,OAAO;GAAU,YAAY,cAAc;GAC5H,gBAAgB,OAAO,eAAe,WAAW;GACjD,MAAM,oBAAoB,QAAQ,OAAO,6BAA6B;GAAG,kBAAkB,SAAS;GACpG,OAAO,OAAO,OAAO,KAAK;GAAG,QAAQ,OAAO,QAAQ,MAAM,QAAQ;GAClE,QAAQ,OAAO,QAAQ,OAAO,QAAQ,iBAAiB,SAAS,WAAW,WAAW;GACtF,WAAW,OAAO,aAAa,iBAAiB,aAAa,eAAe,cAAc,UAAU,cAAc,aAAa,eAAe,iBAAiB,iBAAiB;GAChL,MAAM,OAAO,QAAQ,aAAa,UAAU,SAAS,UAAU;GAAG,KAAK,OAAO,KAAK;GAAG,SAAS,KAAK,OAAO,IAAI;GAC/G,IAAI,UAAU;GACd,IAAI,SAAS;GACb,IAAI,gBAAgB;GACpB,IAAI,cAAc;GAClB,IAAI,iBAAyC;GAC7C,IAAI,iBAAiB;GACrB,IAAI,iBAAiB;GACrB,IAAI,qBAAqB;GACzB,IAAI,sBAAsB;GAC1B,IAAI,sBAAsB;GAC1B,IAAI,qBAAqB;GACzB,IAAI,kBAAkB;GACtB,IAAI,mBAAmB;GACvB,IAAI,qBAAqB;GACzB,IAAI,sBAAsB;GAC1B,MAAM,yBAA+B;IACnC,MAAM,OAAO,sBAAsB,uBAAuB,aAAa,SAAS,SAAS,aAAa;IACtG,oBAAoB,SAAS,CAAC;IAC9B,mBAAmB,aAAa,iBAAiB,OAAO,IAAI,CAAC;GAC/D;GACA,aAAa,iBAAiB,sBAAsB;IAAE,sBAAsB;IAAM,iBAAiB;GAAE,CAAC;GACtG,aAAa,iBAAiB,sBAAsB;IAAE,sBAAsB;IAAO,iBAAiB;GAAE,CAAC;GACvG,aAAa,iBAAiB,WAAW,gBAAgB;GACzD,aAAa,iBAAiB,kBAAkB;IAAE,OAAO,WAAW,kBAAkB,CAAC;GAAE,CAAC;GAC1F,mBAAmB,iBAAiB,eAAe;IAAE,qBAAqB,CAAC;IAAoB,iBAAiB;GAAE,CAAC;GACnH,mBAAmB,iBAAiB,YAAW,UAAS;IACtD,IAAI,MAAM,QAAQ,UAAU;IAC5B,qBAAqB;IACrB,sBAAsB;IACtB,oBAAoB,SAAS;IAC7B,mBAAmB,aAAa,iBAAiB,OAAO;GAC1D,CAAC;GACD,MAAM,cAAc,WAA0B;IAC5C,QAAQ,SAAS;IACjB,WAAW,SAAS,CAAC;IACrB,OAAO,UAAU,OAAO,aAAa,CAAC,MAAM;IAC5C,UAAU,UAAU,OAAO,aAAa,MAAM;IAC9C,OAAO,aAAa,gBAAgB,OAAO,CAAC,MAAM,CAAC;IACnD,UAAU,aAAa,gBAAgB,OAAO,MAAM,CAAC;IACrD,MAAM,cAAc,SAAS,SAAS;GACxC;GACA,OAAO,iBAAiB,eAAe;IAAE,WAAW,KAAK;GAAE,CAAC;GAC5D,UAAU,iBAAiB,eAAe;IAAE,WAAW,IAAI;IAAG,WAAW;GAAE,CAAC;GAC5E,MAAM,WAAW,SAAwB;IACvC,MAAM,SAAS,CAAC;IAChB,KAAK,MAAM,WAAW,SAAS,iBAAiB,8BAA8B,GAAG,QAAQ,aAAa,iBAAiB,OAAO,IAAI,CAAC;GACrI;GACA,MAAM,UAAU,SAAwC;IACtD,UAAU,KAAK,YAAY;IAC3B,SAAS,WAAW,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;IACpE,OAAO,SAAS,WAAW;IAC3B,WAAW,OAAO;IAClB,WAAW,cAAc;IACzB,WAAW,QAAQ;IACnB,OAAO,UAAU,OAAO,cAAc,OAAO;IAC7C,OAAO,cAAc,UAAU,cAAc;IAC7C,MAAM,gBAAgB,KAAK;IAC3B,IAAI,kBAAkB,QAAQ,OAAO,kBAAkB,UAAU;KAC/D,MAAM,SAAS,OAAQ,cAAuC,WAAW,WAAY,cAAqC,SAAS;KACnI,MAAM,SAAS,OAAQ,cAAuC,WAAW,WAAY,cAAqC,SAAS;KACnI,gBAAgB,SAAS;KACzB,gBAAgB,cAAc,WAAW,IAAI,MAAM,OAAO,MAAM,EAAE,SAAS,MAAM,OAAO,MAAM,EAAE,QAAQ,OAAO,MAAM,EAAE;IACzH,OAAO,gBAAgB,SAAS;IAChC,IAAI,CAAC,SAAS,MAAM,SAAS;IAC7B,OAAO,cAAc,UAAU,YAAY;IAC3C,KAAK,WAAW,CAAC;IACjB,SAAS,WAAW,CAAC;IACrB,cAAc,WAAW,CAAC;IAC1B,SAAS,WAAW,CAAC;GACvB;GACA,MAAM,UAAU,KAAa,SAAyB,UAAgB;IACpE,OAAO,gBAAgB;IACvB,IAAI,QAAQ,IAAI;KAAE,OAAO,SAAS;KAAM;IAAO;IAC/C,MAAM,QAAQ,QAAQ,KAAK;IAC3B,MAAM,MAAM;IACZ,MAAM,QAAQ;IACd,MAAM,SAAS;IACf,MAAM,MAAM,6BAA6B,KAAK,GAAG;IACjD,OAAO,SAAS;IAChB,OAAO,OAAO,KAAK;GACrB;GACA,MAAM,eAAe,WAAiC;IACpD,YAAiB,uCAAuC;KAAE,QAAQ;KAAQ,MAAM;IAAK,CAAC,CAAC,CAAC,KAAK,OAAM,SAAQ;KACzG,MAAM,QAAQ,WAAW,QACpB,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS,KAChD,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU;KACvD,OAAO,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,EAAE;KACvD,IAAI,UAAU,IAAI;MAAE,OAAO,cAAc;MAAa;KAAO;KAC7D,IAAI;MACF,MAAM,UAAU,UAAU,UAAU,KAAK;MACzC,OAAO,cAAc,WAAW,QAC5B,8BACA;KACN,QAAQ;MACN,OAAO,cAAc,MAAM,WAAW,QAAQ,SAAS,OAAO,GAAG;MACjE,OAAO,UAAU,IAAI,QAAQ;KAC/B;IACF,IAAG,UAAS;KAAE,OAAO,cAAc,OAAO,KAAK;IAAE,CAAC,CAAC,CAAC,cAAc;KAChE,KAAK,WAAW,CAAC;KACjB,SAAS,WAAW,CAAC;IACvB,CAAC;GACH;GACA,OAAO,iBAAiB,eAAe;IAAE,OAAO,WAAW;IAAM,YAAiB,kCAAkC;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,CAAC,QAAQ,CAAC;IAAE,CAAC,CAAC,CAAC,KAAK,SAAQ,UAAS;KAAE,OAAO,cAAc,OAAO,KAAK;IAAE,CAAC,CAAC,CAAC,cAAc;KAAE,OAAO,WAAW;IAAM,CAAC;GAAE,CAAC;GAC/R,MAAM,cAAc,OAAwB,OAAO,OAAO,WAAW,IAAI,KAAK,EAAE,CAAC,CAAC,eAAe,IAAI;GACrG,MAAM,iBAAiB,SAAwC;IAC7D,MAAM,UAAU,MAAM,QAAQ,KAAK,OAAO,IAAI,KAAK,UAAuC,CAAC;IAC3F,YAAY,gBAAgB;IAC5B,IAAI,QAAQ,WAAW,GAAG;KACxB,MAAM,QAAQ,QAAQ,KAAK,kCAAkC;KAAG,MAAM,cAAc;KACpF,YAAY,OAAO,KAAK;KACxB;IACF;IACA,KAAK,MAAM,UAAU,SAAS;KAC5B,MAAM,MAAM,QAAQ,OAAO,4BAA4B;KACvD,MAAM,QAAQ,QAAQ,QAAQ,kCAAkC;KAChE,MAAM,cAAc,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ;KACtE,MAAM,OAAO,QAAQ,QAAQ,iCAAiC;KAAG,KAAK,cAAc,MAAM,WAAW,OAAO,SAAS;KACrH,MAAM,SAAS,QAAQ,UAAU,mCAAmC;KAAG,OAAO,OAAO;KAAU,OAAO,cAAc;KACpH,MAAM,KAAK,OAAO,OAAO,OAAO,WAAW,OAAO,KAAK;KACvD,OAAO,iBAAiB,eAAe;MACrC,YAAiB,yCAAyC;OAAE,QAAQ;OAAQ,MAAM,KAAK,UAAU,EAAE,UAAU,GAAG,CAAC;MAAE,CAAC,CAAC,CAClH,KAAK,cAAa,UAAS;OAAE,OAAO,cAAc,OAAO,KAAK;MAAE,CAAC;KACtE,CAAC;KACD,IAAI,OAAO,OAAO,MAAM,MAAM;KAC9B,YAAY,OAAO,GAAG;IACxB;GACF;GACA,MAAM,oBAA0B;IAC9B,YAAiB,gCAAgC,CAAC,CAAC,KAAK,gBAAe,UAAS;KAAE,OAAO,cAAc,OAAO,KAAK;IAAE,CAAC;GACxH;GACA,cAAc,iBAAiB,eAAe;IAC5C,MAAM,OAAO,YAAY;IACzB,YAAY,SAAS,CAAC;IACtB,IAAI,MAAM,YAAY;GACxB,CAAC;GACD,SAAS,iBAAiB,eAAe;IACvC,IAAI,CAAC,OAAO,QAAQ,6BAA6B,GAAG;IACpD,YAAiB,wCAAwC;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,KAAK,CAAC;IAAE,CAAC,CAAC,CAClH,KAAK,cAAa,UAAS;KAAE,OAAO,cAAc,OAAO,KAAK;IAAE,CAAC;GACtE,CAAC;GACD,MAAM,gBAAgB,SAAwC;IAC5D,gBAAgB,KAAK,YAAY;IACjC,iBAAiB,KAAK,aAAa,WAAW,WAAW;IACzD,MAAM,SAAS,mBAAmB;IAClC,gBAAgB,UAAU,OAAO,eAAe,CAAC,MAAM;IACvD,aAAa,UAAU,OAAO,eAAe,MAAM;IACnD,gBAAgB,aAAa,gBAAgB,OAAO,CAAC,MAAM,CAAC;IAC5D,aAAa,aAAa,gBAAgB,OAAO,MAAM,CAAC;IACxD,gBAAgB,WAAW;IAC3B,aAAa,WAAW;IACxB,YAAY,SAAS,CAAC;IACtB,cAAc,SAAS;IACvB,YAAY,cAAc,SAAS,cAAc;IACjD,MAAM,YAAY,KAAK,cAAc,QAAQ,OAAO,KAAK,cAAc,WAAW,KAAK,YAAuC,CAAC;IAC/H,MAAM,iBAAiB,UAAU,WAAW,QAAQ,OAAO,UAAU,WAAW,WAAW,UAAU,SAAoC,CAAC;IAC1I,MAAM,YAAY,eAAe,cAAc,QAAQ,OAAO,eAAe,cAAc,WACvF,eAAe,YACf,CAAC;IACL,kBAAkB,UAAU,cAAc;IAC1C,mBAAmB,UAAU,eAAe;IAC5C,kBAAkB,cAAc,mBAAmB,QAAQ,kBAAkB,QAAQ;IACrF,MAAM,kBAAkB,UAAU,cAAc;IAChD,MAAM,mBAAmB,OAAO,UAAU,YAAY,WAAW,UAAU,UAAU;IACrF,MAAM,yBAAyB,OAAO,UAAU,kBAAkB,WAAW,UAAU,gBAAgB;IACvG,MAAM,mBAAmB,OAAO,UAAU,gBAAgB,WAAW,UAAU,cAAc;IAC7F,cAAc,cAAc;IAC5B,cAAc,QAAQ;IACtB,cAAc,SAAS,mBAAmB,CAAC;IAC3C,cAAc,cAAc,yBAAyB,IACjD,aAAa,yBAAyB,OAAO,KAAA,CAAM,QAAQ,CAAC,EAAE,OAC9D;IACJ,cAAc,WAAW;IACzB,cAAc,SAAS,CAAC,mBAAmB;IAC3C,gBAAgB,WAAW;IAC3B,YAAY,SAAS,CAAC,mBAAmB,CAAC;IAC1C,sBAAsB,cAAc,CAAC,kBACjC,iDACA,CAAC,kBACC,wCACA,CAAC,mBACC,QAAQ,iBAAiB,qBACzB,QAAQ,iBAAiB;IACjC,MAAM,QAAQ,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ;IAC5D,MAAM,YAAY,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;IACxE,MAAM,eAAe,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;IACrE,iBAAiB,OAAO,KAAK,aAAa,WAAW,KAAK,WAAW;IACrE,MAAM,oBAAoB,SAAS,KAAK,uBAAuB,KAAK,QAAQ;IAM5E,iBAAiB,sBAAsB,KAAK,oBAAqB;KAJ/D,4BAA4B;KAC5B,uBAAuB;KACvB,qBAAqB;IAE0D,EAAE,cAAc;IACjG,MAAM,mBAAmB,UAAU,WAAW,mBAAmB;IACjE,cAAc,iBAAiB,UAAU,WAAW,iBAAiB;IACrE,aAAa,SAAS,CAAC;IACvB,iBAAiB,OAAO;IACxB,iBAAiB,cAAc;IAC/B,iBAAiB,QAAQ;IACzB,aAAa,UAAU,OAAO,cAAc,WAAW;IACvD,MAAM,SAAiC;KACrC,KAAK;KACL,aAAa,SAAS,2BAA2B;KACjD,UAAU,SAAS,sBAAsB;KACzC,eAAe;KACf,YAAY,SAAS,2BAA2B;KAChD,OAAO;KACP,OAAO;IACT;IAoBA,aAAa,cAAc,sBAAsB,mBAC7C,6CACC,UAAU,UAAW;KApBxB,4BAA4B;KAC5B,uBAAuB;KACvB,qBAAqB;KACrB,uBAAuB;KACvB,sBAAsB;KACtB,wBAAwB;KACxB,0BAA0B;KAC1B,0BAA0B;KAC1B,uBAAuB;KACvB,uBAAuB;KACvB,yBAAyB;KACzB,sBAAsB;KACtB,sBAAsB;KACtB,gBAAgB;KAChB,eAAe;KACf,uBAAuB;KACvB,uBAAuB;IAIW,EAAE,cAAc,OAAO,QAAW,OAAO,UAAU,OAAO;IAC9F,YAAY,SAAS,CAAC;IACtB,YAAY,WAAW,mBAAmB,MAAM;IAChD,iBAAiB,WAAW;IAC5B,aAAa,cAAc,gBAAgB,WAAW;IACtD,aAAa,WAAW,sBAAuB,WAAW,CAAC,mBAAmB,CAAC;IAC/E,YAAY,SAAS,UAAU,UAAU,iBAAiB,mBAAmB;IAC7E,gBAAgB,SAAS,oBAAqB,UAAU,WAAW,UAAU,iBACvE,WAAW,CAAC,mBAAmB,CAAC;IACtC,cAAc,SAAS,WAAW,CAAC,mBAAmB,CAAC;IACvD,WAAW,WAAW,CAAC;IACvB,cAAc,WAAW,CAAC;IAC1B,IAAI,CAAC,aAAa,SAAS,SAAS;IACpC,IAAI,CAAC,kBAAkB,qBAAqB;GAC9C;GACA,MAAM,mBAAyB;IAC7B,YAAiB,mCAAmC,CAAC,CAAC,KAAK,eAAc,UAAS;KAAE,aAAa,cAAc,OAAO,KAAK;IAAE,CAAC;GAChI;GACA,MAAM,wBAAwB,aAA2C;IACvE,IAAI,sBAAsB,aAAa,gBAAgB;IACvD,IAAI,iBAAiB,CAAC,OAAO,QAAQ,sCAAsC,GAAG;IAC9E,qBAAqB;IACrB,gBAAgB,WAAW;IAC3B,aAAa,WAAW;IACxB,aAAa,cAAc,aAAa,WAAW,kBAAkB;IACrE,YAAiB,sCAAsC;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,CAAC;IAAE,CAAC,CAAC,CAC3G,KAAK,eAAc,UAAS;KAAE,aAAa,cAAc,OAAO,KAAK;IAAE,CAAC,CAAC,CACzE,cAAc;KAAE,qBAAqB;KAAO,WAAW;IAAE,CAAC;GAC/D;GACA,gBAAgB,iBAAiB,eAAe;IAAE,qBAAqB,WAAW;GAAE,CAAC;GACrF,aAAa,iBAAiB,eAAe;IAAE,qBAAqB,QAAQ;GAAE,CAAC;GAC/E,cAAc,iBAAiB,eAAe;IAC5C,IAAI,oBAAoB;IAExB,IAAI,CADa,OAAO,QAAQ,0FACpB,GAAG;IACf,qBAAqB;IACrB,cAAc,WAAW;IACzB,cAAc,cAAc;IAC5B,aAAa,cAAc;IAC3B,YAAiB,sDAAsD;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,KAAK,CAAC;IAAE,CAAC,CAAC,CAChI,KAAK,eAAc,UAAS;KAAE,aAAa,cAAc,UAAU,OAAO,KAAK;IAAI,CAAC,CAAC,CACrF,cAAc;KAAE,qBAAqB;KAAO,WAAW;IAAE,CAAC;GAC/D,CAAC;GACD,gBAAgB,iBAAiB,eAAe;IAC9C,IAAI,oBAAoB;IACxB,MAAM,YAAY,YAAY,MAAM,KAAK;IACzC,IAAI,UAAU,SAAS,MAAM,MAAM,KAAK,SAAS,GAAG;KAClD,aAAa,cAAc;KAC3B,YAAY,MAAM;KAClB;IACF;IACA,qBAAqB;IACrB,gBAAgB,WAAW;IAC3B,gBAAgB,aAAa,aAAa,MAAM;IAChD,gBAAgB,cAAc;IAC9B,YAAiB,8CAA8C;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,UAAU,CAAC;IAAE,CAAC,CAAC,CACpH,WAAW;KACV,YAAY,QAAQ;KACpB,aAAa,cAAc;KAC3B,OAAO,YAAY,qCAAqC;MAAE,QAAQ;MAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,KAAK,CAAC;KAAE,CAAC;IACrH,CAAC,CAAC,CACD,KAAK,eAAc,UAAS;KAAE,aAAa,cAAc,QAAQ,OAAO,KAAK;IAAI,CAAC,CAAC,CACnF,cAAc;KAAE,qBAAqB;KAAO,gBAAgB,aAAa,aAAa,OAAO;KAAG,gBAAgB,cAAc;KAAS,WAAW;IAAE,CAAC;GAC1J,CAAC;GACD,YAAY,iBAAiB,eAAe;IAC1C,IAAI,oBAAoB;IACxB,IAAI,CAAC,OAAO,QAAQ,qEAAqE,GAAG;IAC5F,qBAAqB;IACrB,YAAY,WAAW;IACvB,aAAa,cAAc;IAC3B,YAAiB,oDAAoD;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,KAAK,CAAC;IAAE,CAAC,CAAC,CAC9H,KAAK,eAAc,UAAS;KAAE,aAAa,cAAc,QAAQ,OAAO,KAAK;IAAI,CAAC,CAAC,CACnF,cAAc;KAAE,qBAAqB;KAAO,YAAY,WAAW;KAAO,WAAW;IAAE,CAAC;GAC7F,CAAC;GACD,aAAa,iBAAiB,eAAe;IAC3C,aAAa,WAAW;IACxB,YAAiB,qCAAqC;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,CAAC,cAAc,CAAC;IAAE,CAAC,CAAC,CACzH,KAAK,eAAc,UAAS;KAAE,aAAa,cAAc,OAAO,KAAK;IAAE,CAAC,CAAC,CACzE,QAAQ,UAAU;GACvB,CAAC;GACD,YAAY,iBAAiB,eAAe;IAC1C,IAAI,mBAAmB,IAAI,OAAO,KAAK,gBAAgB,UAAU,qBAAqB;GACxF,CAAC;GACD,MAAM,wBAA8B;IAClC,IAAI,qBAAqB;IACzB,sBAAsB;IACtB,gBAAgB,WAAW;IAC3B,YAAY,WAAW;IACvB,iBAAiB,WAAW;IAC5B,aAAa,cAAc,mBAAmB,WAAW,wBAAwB;IACjF,YAAiB,uCAAuC;KAAE,QAAQ;KAAQ,MAAM;IAAK,CAAC,CAAC,CACpF,KAAK,eAAc,UAAS;KAAE,aAAa,cAAc,OAAO,KAAK;IAAE,CAAC,CAAC,CACzE,cAAc;KACb,sBAAsB;KACtB,gBAAgB,WAAW;KAC3B,YAAY,WAAW,mBAAmB;KAC1C,iBAAiB,WAAW;IAC9B,CAAC;GACL;GACA,gBAAgB,iBAAiB,SAAS,eAAe;GACzD,iBAAiB,iBAAiB,eAAe;IAAE,qBAAqB;IAAO,gBAAgB;GAAE,CAAC;GAClG,YAAY,iBAAiB,eAAe;IAC1C,IAAI,mBAAmB,IAAI;IAC3B,qBAAqB;IACrB,sBAAsB,KAAK,IAAI;IAC/B,aAAa,cAAc;IAC3B,OAAO,KAAK,gBAAgB,UAAU,qBAAqB;GAC7D,CAAC;GACD,MAAM,wBAA8B;IAClC,IAAI,CAAC,sBAAsB,SAAS,oBAAoB,YAAY,KAAK,IAAI,IAAI,sBAAsB,KAAK;IAC5G,qBAAqB;IACrB,gBAAgB;GAClB;GACA,OAAO,iBAAiB,SAAS,eAAe;GAChD,SAAS,iBAAiB,oBAAoB,eAAe;GAC7D,WAAW,iBAAiB,eAAe;IACzC,WAAW,WAAW;IACtB,YAAiB,0CAA0C;KAAE,QAAQ;KAAQ,MAAM;IAAK,CAAC,CAAC,CAAC,KAAK,OAAM,SAAQ;KAC5G,MAAM,UAAU,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU;KAClE,OAAO,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,IAAI,QAAQ;KACjE,IAAI,YAAY,IACd,IAAI;MAAE,MAAM,UAAU,UAAU,UAAU,OAAO;KAAE,QAAQ,CAA+C;KAE5G,aAAa,cAAc;IAC7B,IAAG,UAAS;KAAE,aAAa,cAAc,OAAO,KAAK;IAAE,CAAC,CAAC,CAAC,cAAc;KAAE,WAAW,WAAW,CAAC;IAAY,CAAC;GAChH,CAAC;GACD,MAAM,uBAAuB,SAAwC;IACnE,MAAM,UAAU,MAAM,QAAQ,KAAK,OAAO,IAAI,KAAK,UAAuC,CAAC;IAC3F,kBAAkB,gBAAgB;IAClC,IAAI,QAAQ,WAAW,GAAG;KACxB,MAAM,QAAQ,QAAQ,KAAK,kCAAkC;KAAG,MAAM,cAAc;KAAa,kBAAkB,OAAO,KAAK;KAAG;IACpI;IACA,KAAK,MAAM,UAAU,SAAS;KAC5B,MAAM,MAAM,QAAQ,OAAO,4BAA4B;KACvD,MAAM,QAAQ,QAAQ,QAAQ,kCAAkC;KAAG,MAAM,cAAc,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ;KACzI,MAAM,OAAO,QAAQ,QAAQ,iCAAiC;KAAG,KAAK,cAAc,MAAM,WAAW,OAAO,SAAS;KACrH,MAAM,SAAS,QAAQ,UAAU,mCAAmC;KAAG,OAAO,OAAO;KAAU,OAAO,cAAc;KACpH,MAAM,KAAK,OAAO,OAAO,OAAO,WAAW,OAAO,KAAK;KACvD,OAAO,iBAAiB,eAAe;MACrC,YAAiB,4CAA4C;OAAE,QAAQ;OAAQ,MAAM,KAAK,UAAU,EAAE,UAAU,GAAG,CAAC;MAAE,CAAC,CAAC,CACrH,KAAK,oBAAmB,UAAS;OAAE,aAAa,cAAc,OAAO,KAAK;MAAE,CAAC;KAClF,CAAC;KACD,IAAI,OAAO,OAAO,MAAM,MAAM;KAAG,kBAAkB,OAAO,GAAG;IAC/D;GACF;GACA,MAAM,0BAAgC;IACpC,YAAiB,mCAAmC,CAAC,CAAC,KAAK,sBAAqB,UAAS;KAAE,aAAa,cAAc,OAAO,KAAK;IAAE,CAAC;GACvI;GACA,cAAc,iBAAiB,eAAe;IAC5C,MAAM,OAAO,kBAAkB;IAC/B,kBAAkB,SAAS,CAAC;IAC5B,IAAI,MAAM,kBAAkB;GAC9B,CAAC;GACD,YAAY,iBAAiB,eAAe;IAC1C,MAAM,SAAS,mBAAmB,WAC9B,qDACA;IACJ,IAAI,CAAC,OAAO,QAAQ,MAAM,GAAG;IAC7B,YAAiB,mCAAmC;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,KAAK,CAAC;IAAE,CAAC,CAAC,CAC7G,KAAK,eAAc,UAAS;KAAE,aAAa,cAAc,OAAO,KAAK;IAAE,CAAC;GAC7E,CAAC;GACD,KAAK,iBAAiB,eAAe;IAAE,KAAK,WAAW;IAAM,YAAY,KAAK;GAAE,CAAC;GACjF,SAAS,iBAAiB,eAAe;IAAE,SAAS,WAAW;IAAM,YAAY,MAAM;GAAE,CAAC;GAC1F,MAAM,iBAAiB,eAAe;IAAE,QAAQ,KAAK;GAAE,CAAC;GACxD,MAAM,WAAW,UAA8B;IAC7C,IAAI,MAAM,UAAU,EAAE,MAAM,kBAAkB,OAAO;IACrD,IAAI,CAAC,aAAa,SAAS,MAAM,MAAM,GAAG;KACxC,qBAAqB;KACrB,sBAAsB;KACtB,iBAAiB;IACnB;IACA,IAAI,CAAC,MAAM,SAAS,MAAM,MAAM,KAAK,CAAC,SAAS,cAAc,8BAA8B,CAAC,EAAE,SAAS,MAAM,MAAM,GAAG,QAAQ,KAAK;GACrI;GACA,SAAS,iBAAiB,eAAe,OAAO;GAChD,YAAiB,gCAAgC,CAAC,CAAC,KAAK,SAAQ,UAAS;IAAE,OAAO,cAAc,OAAO,KAAK;GAAE,CAAC;GAC/G,WAAW;GACX,MAAM,aAAa,OAAO,kBAAkB;IAAE,IAAI,CAAC,MAAM,UAAU,CAAC,WAAW,QAAQ,WAAW;GAAE,GAAG,IAAK;GAC5G,OAAO;IAAE,cAAc;KAAE,OAAO,cAAc,UAAU;KAAG,OAAO,oBAAoB,SAAS,eAAe;KAAG,SAAS,oBAAoB,oBAAoB,eAAe;KAAG,SAAS,oBAAoB,eAAe,OAAO;KAAG,KAAK,OAAO;IAAE;IAAG,cAAc;KAAE,QAAQ,MAAM,WAAW,KAAK;IAAE;GAAE;EAC/S;EAEA,SAAS,cAAc,MAAc,OAAoB,CAAC,GAAsB;GAC9E,MAAM,SAAS,IAAI,IAAI,MAAM,SAAS,IAAI;GAC1C,IAAI,OAAO,WAAW,SAAS,QAAQ,MAAM,IAAI,UAAU,uDAAuD;GAClH,MAAM,UAAU,IAAI,QAAQ,KAAK,OAAO;GACxC,MAAM,UAAU,KAAK,UAAU,MAAA,CAAO,YAAY;GAClD,IAAI,WAAW,SAAS,WAAW,QAAQ;IACzC,MAAM,OAAO,SAAS,OAAO,MAAM,GAAG,CAAC,CAAC,KAAI,UAAS,MAAM,KAAK,CAAC,CAAC,CAAC,MAAK,UAAS,MAAM,WAAW,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE;IAC5H,IAAI,SAAS,KAAA,GAAW,QAAQ,IAAI,qBAAqB,IAAI;GAC/D;GACA,OAAO,MAAM,QAAQ;IAAE,GAAG;IAAM;IAAS,aAAa;IAAe,OAAO;IAAY,UAAU;GAAQ,CAAC;EAC7G;EAEA,SAAS,sBAAkC;GACzC,MAAM,cAAc,QAAQ,OAAO;GAAG,YAAY,QAAQ,SAAS;GAAqB,SAAS,KAAK,OAAO,WAAW;GACxH,MAAM,WAAW,OAAO;GACxB,IAAI,cAAgD;GACpD,IAAI,eAAe;GACnB,IAAI;GACJ,IAAI;GACJ,MAAM,8BAAc,IAAI,IAAoC;GAC5D,MAAM,yBAAS,IAAI,IAAuL;GAC1M,MAAM,6BAAa,IAAI,IAA8B;GACrD,MAAM,6BAAa,IAAI,IAAoB;GAC3C,MAAM,gCAAgB,IAAI,IAAoB;GAC9C,IAAI,eAAe;GACnB,IAAI;GACJ,MAAM,sBAAwD;IAC5D,kBAAkB;IAClB,iBAAiB;IACjB,iBAAiB;IACjB,oBAAoB;GACtB;GACA,MAAM,eAAe,cAA+C;IAClE,MAAM,WAAW,SAAS,cAA2B,kCAAkC,UAAU,GAAG;IACpG,IAAI,aAAa,MAAM,OAAO;IAC9B,MAAM,QAAQ,oBAAoB;IAClC,IAAI,UAAU,KAAA,GAAW,OAAO,KAAA;IAChC,MAAM,OAAO,QAAQ,KAAK;IAAG,KAAK,QAAQ,uBAAuB;IAAW,KAAK,MAAM,UAAU;IACjG,SAAS,KAAK,OAAO,IAAI;IAAG,OAAO;GACrC;GACA,MAAM,mBAAgC;IACpC,MAAM,WAAW,SAAS,cAA2B,mCAAmC;IACxF,IAAI,aAAa,MAAM,OAAO;IAC9B,MAAM,QAAQ,QAAQ,KAAK;IAAG,MAAM,QAAQ,0BAA0B;IAAQ,MAAM,MAAM,UAAU;IACpG,SAAS,KAAK,OAAO,KAAK;IAAG,OAAO;GACtC;GACA,MAAM,SAAS,YAA0B;IACvC,MAAM,OAAO,QAAQ,KAAK;IAAG,KAAK,cAAc;IAAS,KAAK,MAAM,UAAU;IAC9E,WAAW,CAAC,CAAC,OAAO,IAAI;IAAG,OAAO,iBAAiB,KAAK,OAAO,GAAG,IAAI;GACxE;GACA,MAAM,yBAAyB,UAA4B;IACzD,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,EAAE,YAAY,UAAU,EAAE,UAAU,QAAQ,OAAO;IACtG,MAAM,YAAY;IAClB,IAAI,OAAO,UAAU,WAAW,YAAY,OAAO,UAAU,SAAS,UAAU,OAAO;IACvF,IAAI;KACF,MAAM,UAAU,KAAK,UAAU,MAAM;KACrC,MAAM,QAAQ,WAAW,KAAK,UAAS,cAAa,UAAU,WAAW,CAAC,CAAC;KAC3E,OAAO,IAAI,KAAK,CAAC,KAAK,GAAG,UAAU,MAAM,EAAE,MAAM,OAAO,UAAU,SAAS,WAAW,UAAU,OAAO,2BAA2B,CAAC;IACrI,QAAQ;KACN,OAAO;IACT;GACF;GACA,MAAM,eAAe,OAAO,QAAgB,UAAsC;IAChF,MAAM,SAAS,OAAO;IACtB,IAAI,WAAW,KAAA,GAAW,OAAO,sBAAsB,MAAM,OAAO,OAAO,QAAQ,KAAK,CAAC;IACzF,IAAI,WAAW,WAAW,OAAO,UAAU,UAAU,YAAY;KAAE,MAAM,UAAU,MAAO,SAAS,CAAC,CAAe;KAAG,OAAO,EAAE,IAAI,KAAK;IAAE;IAC1I,IAAI,WAAW,oBAAoB,UAAU,cAAc,KAAA,GAAW,OAAO,EAAE,MAAM,MAAM,UAAU,UAAU,SAAS,EAAE;IAC1H,IAAI,WAAW,qBAAqB,UAAU,cAAc,KAAA,GAAW;KAAE,MAAM,UAAU,UAAU,UAAU,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU,QAAQ,OAAQ,MAA4B,IAAI,IAAI,EAAE;KAAG,OAAO,EAAE,IAAI,KAAK;IAAE;IACnP,IAAI,WAAW,gBAAgB,WAAW,kBAAkB;KAC1D,MAAM,eAAe,QAAQ,OAAO;KAAG,aAAa,OAAO;KAAQ,aAAa,SAAS,WAAW,mBAAmB,YAAY;KAAO,IAAI,WAAW,kBAAkB,aAAa,UAAU;KAClM,OAAO,IAAI,SAA0B,YAAW;MAAE,aAAa,iBAAiB,QAAQ,aAAa,QAAQ,EAAE;MAAG,aAAa,MAAM;KAAE,CAAC;IAC1I;IACA,MAAM,IAAI,MAAM,kCAAkC;GACpD;GACA,MAAM,WAAW,IAAY,eAAiD;IAC5E,MAAM,WAAW,OAAO,IAAI,EAAE,CAAC,EAAE,4BAAY,IAAI,IAAI;IACrD,MAAM,gBAAgB,YAAyC;KAC7D,IAAI,CAAC,0BAA0B,KAAK,QAAQ,EAAE,KAAK,QAAQ,MAAM,SAAS,KAAK,MAAM,IAAI,MAAM,wBAAwB;KACvH,MAAM,YAAY,QAAQ,SAAS;KAAG,UAAU,QAAQ,mBAAmB,QAAQ;KAAI,UAAU,SAAS,QAAQ,cAAc,UAAU,QAAQ,cAAc;KAAW,UAAU,MAAM,UAAU,QAAQ,cAAc,UAAU,QAAQ,cAAc,YAAY,yHAAyH;KAEhY,CADa,QAAQ,cAAc,UAAU,QAAQ,cAAc,YAAY,WAAW,IAAI,YAAY,QAAQ,SAAS,KAAK,WAAW,EAAA,CACtI,OAAO,SAAS;KACrB,MAAM,UAAU,QAAQ,MAAM,SAAS;KACvC,MAAM,gBAAsB;MAAE,IAAI,OAAO,YAAY,YAAY,QAAQ;MAAG,UAAU,OAAO;KAAE;KAC/F,SAAS,IAAI,QAAQ,IAAI;MAAE;MAAS;KAAU,CAAC;KAC/C,aAAa;MAAE,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC,EAAE,YAAY,SAAS,SAAS,OAAO,QAAQ,EAAE;MAAG,QAAQ;KAAE;IAC3G;IACA,OAAO;KACL,MAAM;MACJ,SAAS,QAAgB,UAAmB,cAAc,6BAA6B,mBAAmB,EAAE,EAAE,WAAW,mBAAmB,MAAM,KAAK;OAAE,QAAQ;OAAQ,MAAM,KAAK,UAAU,SAAS,CAAC,CAAC;MAAE,CAAC,CAAC,CAAC,KAAK,OAAM,aAAY;OAAE,MAAM,QAAQ,MAAM,SAAS,KAAK;OAAc,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,OAAO,UAAU,YAAY,UAAU,QAAQ,WAAW,QAAQ,OAAQ,MAA6B,KAAK,IAAI,QAAQ,OAAO,SAAS,MAAM,GAAG;OAAG,OAAO;MAAM,CAAC;MAC3d,QAAQ,MAAc,SAAuB;OAC3C,IAAI,CAAC,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,IAAI,KAAK,KAAK,SAAS,KAAK,KACpE,KAAK,MAAM,GAAG,CAAC,CAAC,MAAK,SAAQ,SAAS,QAAQ,SAAS,GAAG,GAAG,MAAM,IAAI,UAAU,mCAAmC;OACzH,OAAO,cAAc,6BAA6B,mBAAmB,EAAE,EAAE,SAAS,QAAQ,IAAI;MAChG;KACF;KACA,IAAI;MAAE,iBAAiB;MAAc,OAAM,OAAM;OAAE,MAAM,QAAQ,SAAS,IAAI,EAAE;OAAG,IAAI,UAAU,KAAA,GAAW,MAAM,UAAU,SAAS;MAAM;MAAG,QAAO,OAAM;OAAE,MAAM,QAAQ,SAAS,IAAI,EAAE;OAAG,IAAI,UAAU,KAAA,GAAW,MAAM,UAAU,SAAS;MAAK;MAAG;KAAM;KAC7P,QAAQ;MAAE,cAAc,YAAY;OAAE,MAAM,SAAS,OAAO;OAAuB,OAAO,WAAW,KAAA,IAAY;QAAC;QAAc;QAAkB;QAAS;QAAkB;OAAiB,IAAI,OAAO,aAAa;MAAE;MAAG,QAAQ;KAAa;KAChP,QAAQ,WAAW;KAAQ;KAAU;IACvC;GACF;GACA,MAAM,qBAAqB,OAAO,eAAsD;IACtF,MAAM,iBAAiB,OAAO,IAAI,WAAW,EAAE;IAC/C,MAAM,aAAa,IAAI,gBAAgB;IACvC,MAAM,2BAAW,IAAI,IAA+E;IACpG,OAAO,IAAI,WAAW,IAAI;KAAE;KAAY;KAAU,eAAe;MAAE,WAAW,MAAM;MAAG,KAAK,MAAM,WAAW,SAAS,OAAO,GAAG,QAAQ,QAAQ;MAAG,SAAS,MAAM;KAAE;IAAE,CAAC;IACvK,IAAI;KACF,MAAM,UAAU,MAAM,WAAW,SAAS,QAAQ,WAAW,IAAI,UAAU,CAAC;KAC5E,MAAM,UAAU,OAAO,IAAI,WAAW,EAAE;KACxC,IAAI,YAAY,KAAA,KAAa,QAAQ,eAAe,YAAY;MAAE,IAAI,OAAO,YAAY,YAAY,QAAQ;MAAG;KAAO;KACvH,MAAM,aAAa,QAAQ;KAC3B,OAAO,IAAI,WAAW,IAAI;MAAE,GAAG;MAAS,eAAe;OAAE,IAAI,OAAO,YAAY,YAAY,QAAQ;OAAG,WAAW;MAAE;KAAE,CAAC;KACvH,gBAAgB,QAAQ;IAC1B,QAAQ;KACN,OAAO,IAAI,WAAW,EAAE,CAAC,EAAE,QAAQ;KAAG,OAAO,OAAO,WAAW,EAAE;KAAG,IAAI,mBAAmB,KAAA,GAAW,OAAO,IAAI,WAAW,IAAI,cAAc;IAChJ;GACF;GACA,MAAM,UAAU,eAA6C;IAC3D,IAAI,WAAW,eAAe,KAAK,CAAC,0BAA0B,KAAK,WAAW,EAAE,KAAK,OAAO,WAAW,aAAa,YAAY;IAChI,IAAI,yBAAyB,KAAA,KAAa,WAAW,OAAO,sBAAsB;IAClF,YAAY,IAAI,WAAW,IAAI,UAAU;IACzC,IAAI,SAAS,mBAAwB,UAAU;GACjD;GACA,IAAI,UAAU;GACd,OAAO,YAAY,OAAO,OAAO;IAAE,WAAU,UAAS;KAAE,cAAc;IAAM;IAAG;GAAO,CAAC;GACvF,KAAK,MAAM,cAAc,kBAAkB,OAAO,CAAC,GAAG,OAAO,UAAU;GACvE,IAAI,eAAe;GACnB,IAAI,mBAAmB;GACvB,MAAM,gBAAgB,YAA2B;IAC/C,IAAI;KACF,MAAM,UAAkC,CAAC;KACzC,IAAI,iBAAiB,IAAI,QAAQ,mBAAmB;KACpD,IAAI,qBAAqB,IAAI,QAAQ,uBAAuB;KAC5D,MAAM,WAAW,MAAM,MAAM,4BAA4B;MAAE,aAAa;MAAe,OAAO;MAAY;KAAQ,CAAC;KACnH,IAAI,SAAS,WAAW,KAAK;KAC7B,IAAI,CAAC,SAAS,IAAI;KAClB,eAAe,SAAS,QAAQ,IAAI,MAAM,KAAK;KAC/C,mBAAmB,SAAS,QAAQ,IAAI,eAAe,KAAK;KAC5D,MAAM,OAAO,MAAM,SAAS,KAAK;KAAG,IAAI,SAAS,cAAc;KAAQ,eAAe;KAAM,cAAc,KAAA;KAC1G,MAAM,SAAS,QAAQ,QAAQ;KAAG,OAAO,cAAc,GAAG,KAAK;KAAuC,SAAS,KAAK,OAAO,MAAM;KAAG,OAAO,OAAO;KAClJ,MAAM,QAAQ;KACd,IAAI,UAAU,KAAA,GAAW;KACzB,MAAM,WAAW,QAAQ,KAAK;KAAG,SAAS,QAAQ,qBAAqB;KAAQ,SAAS,KAAK,OAAO,QAAQ;KAC5G,MAAM,cAAc,MAAM;MAAE;MAAU,SAAS;MAAe,MAAM;MAAU;KAAO,CAAC;KACtF,gBAAgB;KAAG,YAAY,OAAO;KAAG,aAAa;KAAU,gBAAgB,OAAO,gBAAgB,aAAa,cAAc,KAAA;IACpI,QAAQ,CAAgE;GAC1E;GACA,MAAM,oBAAoB,YAA2B;IACnD,IAAI;KACF,MAAM,UAAkC,CAAC;KACzC,IAAI,iBAAiB,IAAI,QAAQ,mBAAmB;KACpD,MAAM,WAAW,MAAM,MAAM,sCAAsC;MAAE,aAAa;MAAe,OAAO;MAAY;KAAQ,CAAC;KAC7H,IAAI,SAAS,WAAW,KAAK;KAC7B,IAAI,CAAC,SAAS,IAAI;KAClB,eAAe,SAAS,QAAQ,IAAI,MAAM,KAAK;KAC/C,MAAM,UAAU,MAAM,SAAS,KAAK;KACpC,MAAM,UAAU,MAAM,QAAQ,QAAQ,UAAU,IAAI,QAAQ,aAA0C,CAAC;KACvG,MAAM,uBAAO,IAAI,IAAY;KAC7B,KAAK,MAAM,SAAS,SAAS;MAC3B,IAAI,OAAO,MAAM,OAAO,UAAU;MAClC,KAAK,IAAI,MAAM,EAAE;MACjB,MAAM,SAAS,OAAO,MAAM,aAAa,WAAW,MAAM,WAAW,KAAA;MACrE,IAAI,WAAW,KAAA,GAAW;OACxB,MAAM,aAAqC,CAAC;OAC5C,MAAM,aAAa,WAAW,IAAI,MAAM,EAAE;OAC1C,IAAI,eAAe,KAAA,GAAW,WAAW,mBAAmB;OAC5D,MAAM,cAAc,MAAM,MAAM,QAAQ;QAAE,aAAa;QAAe,OAAO;QAAY,SAAS;OAAW,CAAC;OAC9G,IAAI,YAAY,WAAW,KAAK,CAAkB,OAC7C,IAAI,YAAY,IAAI;QACvB,MAAM,WAAW,YAAY,QAAQ,IAAI,MAAM;QAAG,IAAI,aAAa,QAAQ,aAAa,IAAI,WAAW,IAAI,MAAM,IAAI,QAAQ;QAC7H,MAAM,MAAM,MAAM,YAAY,KAAK;QAAG,MAAM,WAAW,WAAW,IAAI,MAAM,EAAE;QAC9E,IAAI,UAAU,gBAAgB,KAAK;SACjC,MAAM,OAAO,QAAQ,OAAO;SAAG,KAAK,QAAQ,0BAA0B,MAAM;SAAI,KAAK,cAAc;SAAK,SAAS,KAAK,OAAO,IAAI;SAAG,WAAW,IAAI,MAAM,IAAI,IAAI;SAAG,UAAU,OAAO;QACvL;OACF,OAAO;MACT;MACA,MAAM,YAAY,OAAO,MAAM,cAAc,WAAW,MAAM,YAAY,KAAA;MAC1E,IAAI,cAAc,KAAA,GAAW;OAC3B,MAAM,gBAAwC,CAAC;OAC/C,MAAM,eAAe,cAAc,IAAI,MAAM,EAAE;OAC/C,IAAI,iBAAiB,KAAA,GAAW,cAAc,mBAAmB;OACjE,MAAM,iBAAiB,MAAM,MAAM,WAAW;QAAE,aAAa;QAAe,OAAO;QAAY,SAAS;OAAc,CAAC;OACvH,IAAI,eAAe,WAAW,KAAK,CAAkB,OAChD,IAAI,eAAe,IAAI;QAC1B,MAAM,SAAS,MAAM,eAAe,KAAK;QAAG,MAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,IAAI,YAAY,CAAC,CAAC,OAAO,MAAM,CAAC;QAAG,MAAM,MAAM,CAAC,GAAG,IAAI,WAAW,MAAM,CAAC,CAAC,CAAC,KAAI,UAAS,MAAM,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE;QACrO,IAAI,cAAc,IAAI,MAAM,EAAE,MAAM,KAAK;SACvC,cAAc,IAAI,MAAM,IAAI,GAAG;SAC/B,uBAAuB,MAAM;SAC7B,IAAI;UAAE,MAAM,SAAS,QAAQ,QAAQ;UAAG,OAAO,cAAc,GAAG,OAAO,uCAAuC,MAAM,GAAG;UAAM,SAAS,KAAK,OAAO,MAAM;UAAG,OAAO,OAAO;SAAE,UACnK;UAAE,uBAAuB,KAAA;SAAU;QAC7C;OACF,OAAO;MACT;MACA,MAAM,aAAa,YAAY,IAAI,MAAM,EAAE;MAAG,IAAI,eAAe,KAAA,KAAa,CAAC,OAAO,IAAI,MAAM,EAAE,GAAG,MAAM,mBAAmB,UAAU;KAC1I;KACA,KAAK,MAAM,CAAC,IAAI,YAAY,QAAQ,IAAI,CAAC,KAAK,IAAI,EAAE,KAAK,CAAC,YAAY,IAAI,EAAE,KAAK,OAAO,iBAAiB;MAAE,QAAQ,QAAQ;MAAG,OAAO,OAAO,EAAE;MAAG,WAAW,IAAI,EAAE,CAAC,EAAE,OAAO;MAAG,WAAW,OAAO,EAAE;MAAG,WAAW,OAAO,EAAE;MAAG,cAAc,OAAO,EAAE;KAAE;IACxP,QAAQ,CAA2E;GACrF;GACA,UAAU;GACV,KAAK,MAAM,cAAc,YAAY,OAAO,GAAG,mBAAwB,UAAU;GACjF,cAAmB;GAAG,kBAAuB;GAAG,iBAAsB,WAAW;GACjF,MAAM,QAAQ,OAAO,kBAAkB;IAAE,cAAmB;IAAG,kBAAuB;IAAG,iBAAsB,WAAW;GAAE,GAAG,GAAK;GACpI,aAAa;IAAE,cAAc,KAAK;IAAG,UAAU;IAAO,gBAAgB;IAAG,YAAY,OAAO;IAAG,YAAY,OAAO;IAAG,KAAK,MAAM,WAAW,OAAO,OAAO,GAAG,QAAQ,QAAQ;IAAG,KAAK,MAAM,QAAQ,WAAW,OAAO,GAAG,KAAK,OAAO;IAA8E,SAApD,cAAc,mCAA0C,CAAC,EAAE,OAAO;IAAG,KAAK,MAAM,QAAQ,SAAS,iBAAiB,gCAAgC,GAAG,KAAK,OAAO;IAAG,IAAI,aAAa,KAAA,GAAW,OAAO,OAAO;SAAgB,OAAO,YAAY;GAAS;EACzf;EAEA,IAAI,UAAU;EACd,IAAI,cAAc;EAClB,eAAe,iBAAiB,OAAwC;GACtE,IAAI;IACF,MAAM,UAAkC,CAAC;IACzC,IAAI,YAAY,IAAI,QAAQ,mBAAmB;IAC/C,IAAI,gBAAgB,IAAI,QAAQ,uBAAuB;IACvD,MAAM,WAAW,MAAM,MAAM,6BAA6B;KAAE,aAAa;KAAe,OAAO;KAAY;IAAQ,CAAC;IACpH,IAAI,SAAS,WAAW,KAAK;IAC7B,IAAI,SAAS,IAAI;KACf,UAAU,SAAS,QAAQ,IAAI,MAAM,KAAK;KAC1C,cAAc,SAAS,QAAQ,IAAI,eAAe,KAAK;KACvD,MAAM,cAAc,MAAM,SAAS,KAAK;IAC1C;GACF,QAAQ,CAAwD;EAClE;EAEA,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;EAoBvB,SAAgB,MAAM,KAA0B;GAC9C,IAAI,aAAa;IACf,IAAI,OAAO,4BAA4B,aAAa;IACpD,OAAO,oCAAoC,IAAI,IAAI,YAAY,CAAC;GAClE,GAAG,gDAAgD;GAEnD,IAAI,aAAa;IACf,MAAM,WAAW,eAAe,SAAS,QAAQ,KAAK,CAAC,IAAI,gBAAgB,SAAS,MAAM,CAAC,CAAC,IAAI,oBAAoB;IACpH,MAAM,QAAQ,QAAQ,OAAO;IAAG,MAAM,QAAQ,SAAS;IAAc,MAAM,cAAc,WACrF,iBACA;IACJ,SAAS,KAAK,OAAO,KAAK;IAC1B,IAAI,CAAC,UAAU;KACb,MAAM,eAAe,oBAAoB;KACzC,MAAM,gBAAgB,2BAA2B;KACjD,aAAa;MAAE,aAAa;MAAG,cAAc;MAAG,MAAM,OAAO;KAAE;IACjE;IACA,MAAM,UAAU,eAAe;IAC/B,MAAM,cAAc,IAAI,MAAM,OAAO,+BAA+B,IAAI,MAAM,SAAS;KAAE,MAAM;KAAyB,IAAI;IAAa,IAAI,EAAE,YAAA,GAAWA,MAAAA,cAAAA,CAAc,UAAU;KAChL,iBAAiB;KACjB,cAAc;KACd,WAAW,8BAA8B,OAAO,KAAK;KACrD,MAAM;KACN,OAAO;KACP,SAAS,QAAQ;IACnB,IAAA,GAAGA,MAAAA,cAAAA,CAAc,QAAQ;KAAE,eAAe;KAAM,WAAW;IAAmC,CAAC,GAAG,QAAA,GAAOA,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAW,oCAAoC,GAAG,MAAM,IAAI,KAAA,CAAS,CAAC,CAAC;IACxM,aAAa;KAAE,YAAY;KAAG,QAAQ,OAAO;KAAG,MAAM,OAAO;IAAE;GACjE,GAAG,uDAAuD;EAC5D;;EAGA,MAAa,SAA4B,CAAC,OAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-mobile",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "private": false,
5
5
  "description": "DeepSeek Harness 移动端适配与安全访问插件,支持局域网、远程连接、Android App 和手机浏览器。",
6
6
  "type": "module",