docs(client/ios): iOS+iPad 支持设计方案(TestFlight 里程碑)+ 新建 docs 索引
五条工作线:libbox iOS 框架 / Provider 对齐 macOS 修复 / App Group IPC / iPad 布局横屏适配 / TestFlight 分发;头号风险 NE ~50MB 内存红线设双闸。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+105
@@ -0,0 +1,105 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Pangolin 文档索引</title>
|
||||
<style>
|
||||
:root{
|
||||
--bg:#0f1117; --panel:#171a22; --panel2:#1d2129; --fg:#e6e8ee; --fg2:#a8afbd;
|
||||
--accent:#e0884f; --accent2:#5fb0c9; --ok:#5ec27a; --bad:#e06a6a; --warn:#e0b84f;
|
||||
--border:#272c36; --mono:"SF Mono",ui-monospace,Menlo,Consolas,monospace;
|
||||
--sans:-apple-system,"PingFang SC","Helvetica Neue",Arial,sans-serif;
|
||||
}
|
||||
*{box-sizing:border-box}
|
||||
body{margin:0;background:var(--bg);color:var(--fg);font-family:var(--sans);line-height:1.7;font-size:15px}
|
||||
.wrap{max-width:920px;margin:0 auto;padding:48px 24px 96px}
|
||||
h1{font-size:30px;line-height:1.3;margin:0 0 8px;letter-spacing:-.01em}
|
||||
.sub{color:var(--fg2);font-size:15px;margin:0 0 32px}
|
||||
h2{font-size:21px;margin:44px 0 14px;padding-bottom:8px;border-bottom:1px solid var(--border)}
|
||||
a{color:var(--accent2);text-decoration:none}
|
||||
a:hover{text-decoration:underline}
|
||||
.card{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:6px 20px;margin:16px 0}
|
||||
ul{padding-left:0;margin:10px 0;list-style:none}
|
||||
li{margin:12px 0;padding-left:0}
|
||||
.doc-title{font-size:15px;font-weight:600}
|
||||
.desc{color:var(--fg2);font-size:13px;margin:2px 0 0}
|
||||
.tag{display:inline-block;font-size:11px;font-weight:600;padding:1px 8px;border-radius:999px;vertical-align:middle;margin-left:6px}
|
||||
.tag.html{background:rgba(95,176,201,.16);color:var(--accent2)}
|
||||
.tag.md{background:rgba(168,175,189,.14);color:var(--fg2)}
|
||||
.lead{background:linear-gradient(180deg,rgba(224,136,79,.10),transparent);border:1px solid var(--border);border-radius:12px;padding:18px 20px;margin:0 0 8px}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
|
||||
<h1>Pangolin 文档索引</h1>
|
||||
<p class="sub">单一入口:本项目所有设计 / 计划 / 调研 / 排障文档汇总。新增文档须登记于此。</p>
|
||||
|
||||
<div class="lead">
|
||||
<p style="margin:0">家族规范:设计/调研类新文档一律 <strong>HTML</strong>(深色主题、自包含);README / plan / CLAUDE.md / 代码内文档仍按既有形式。历史 <code>.md</code> 保留原状、逐步迁移。</p>
|
||||
</div>
|
||||
|
||||
<h2>设计方案</h2>
|
||||
<div class="card">
|
||||
<ul>
|
||||
<li>
|
||||
<a class="doc-title" href="ios-ipad-support-design.html">iOS + iPad 支持设计方案</a><span class="tag html">HTML</span>
|
||||
<p class="desc">iOS 隧道从 PoC 桩推到真机连通 + TestFlight;五条工作线 + NE 50MB 内存闸门;iPad 布局适配(分支 <code>feature/pangolin-ios</code>)</p>
|
||||
</li>
|
||||
<li>
|
||||
<a class="doc-title" href="技术方案.md">技术方案</a><span class="tag md">MD</span>
|
||||
<p class="desc">总体技术选型与架构</p>
|
||||
</li>
|
||||
<li>
|
||||
<a class="doc-title" href="vpn-core-embedding.md">VPN 核心嵌入(方案B)</a><span class="tag md">MD</span>
|
||||
<p class="desc">嵌入 libbox + 系统 VPN API 替换 sudo sing-box 的完整设计</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h2>实现计划</h2>
|
||||
<div class="card">
|
||||
<ul>
|
||||
<li>
|
||||
<a class="doc-title" href="p1-macos-system-extension.md">P1 macOS 系统扩展</a><span class="tag md">MD</span>
|
||||
<p class="desc">macOS PacketTunnel 系统扩展实现计划</p>
|
||||
</li>
|
||||
<li>
|
||||
<a class="doc-title" href="node-rebuild-checklist.md">节点重建清单</a><span class="tag md">MD</span>
|
||||
<p class="desc">节点重建步骤清单</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h2>知识库 / 调研</h2>
|
||||
<div class="card">
|
||||
<ul>
|
||||
<li>
|
||||
<a class="doc-title" href="vpn-testing-research.md">VPN 测试调研</a><span class="tag md">MD</span>
|
||||
<p class="desc">黑盒测试方法调研</p>
|
||||
</li>
|
||||
<li>
|
||||
<a class="doc-title" href="vpn-test-plan.md">VPN 测试计划</a><span class="tag md">MD</span>
|
||||
<p class="desc">国内外站点矩阵 + 延迟口径</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h2>排障 Runbook</h2>
|
||||
<div class="card">
|
||||
<ul>
|
||||
<li>
|
||||
<a class="doc-title" href="macos-sysext-realize-troubleshooting.html">macOS 系统扩展 realize 失败排障</a><span class="tag html">HTML</span>
|
||||
<p class="desc"><code>OSSystemExtensionErrorDomain code=4</code> 踩坑复盘 —— 改 macOS 隧道前必读</p>
|
||||
</li>
|
||||
<li>
|
||||
<a class="doc-title" href="runbook-scheduler.md">调度器 Runbook</a><span class="tag md">MD</span>
|
||||
<p class="desc">调度器运维手册</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,193 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>iOS + iPad 支持设计方案 — Pangolin</title>
|
||||
<style>
|
||||
:root{
|
||||
--bg:#0f1117; --panel:#171a22; --panel2:#1d2129; --fg:#e6e8ee; --fg2:#a8afbd;
|
||||
--accent:#e0884f; --accent2:#5fb0c9; --ok:#5ec27a; --bad:#e06a6a; --warn:#e0b84f;
|
||||
--border:#272c36; --mono:"SF Mono",ui-monospace,Menlo,Consolas,monospace;
|
||||
--sans:-apple-system,"PingFang SC","Helvetica Neue",Arial,sans-serif;
|
||||
}
|
||||
*{box-sizing:border-box}
|
||||
body{margin:0;background:var(--bg);color:var(--fg);font-family:var(--sans);line-height:1.7;font-size:15px}
|
||||
.wrap{max-width:920px;margin:0 auto;padding:48px 24px 96px}
|
||||
h1{font-size:30px;line-height:1.3;margin:0 0 8px;letter-spacing:-.01em}
|
||||
.sub{color:var(--fg2);font-size:15px;margin:0 0 32px}
|
||||
h2{font-size:21px;margin:48px 0 14px;padding-bottom:8px;border-bottom:1px solid var(--border)}
|
||||
h3{font-size:16px;margin:28px 0 8px;color:var(--accent2)}
|
||||
p{margin:10px 0}
|
||||
code{font-family:var(--mono);font-size:.88em;background:var(--panel2);padding:1px 6px;border-radius:5px;color:#f0d9c4}
|
||||
pre{background:#0a0c11;border:1px solid var(--border);border-radius:10px;padding:14px 16px;overflow-x:auto;font-family:var(--mono);font-size:13px;line-height:1.55;color:#cdd3df}
|
||||
pre .c{color:#6b7385}
|
||||
pre .r{color:var(--bad)}
|
||||
pre .g{color:var(--ok)}
|
||||
pre .y{color:var(--warn)}
|
||||
.tag{display:inline-block;font-size:12px;font-weight:600;padding:2px 9px;border-radius:999px;vertical-align:middle}
|
||||
.tag.bad{background:rgba(224,106,106,.16);color:var(--bad)}
|
||||
.tag.ok{background:rgba(94,194,122,.16);color:var(--ok)}
|
||||
.tag.warn{background:rgba(224,184,79,.16);color:var(--warn)}
|
||||
.tag.info{background:rgba(95,176,201,.16);color:var(--accent2)}
|
||||
.card{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:18px 20px;margin:16px 0}
|
||||
.card.root{border-left:3px solid var(--accent)}
|
||||
.card.risk{border-left:3px solid var(--bad)}
|
||||
.card h3{margin-top:0}
|
||||
table{width:100%;border-collapse:collapse;margin:16px 0;font-size:14px}
|
||||
th,td{text-align:left;padding:9px 12px;border-bottom:1px solid var(--border);vertical-align:top}
|
||||
th{color:var(--fg2);font-weight:600;font-size:13px}
|
||||
td code{font-size:.85em}
|
||||
.ok-c{color:var(--ok)} .bad-c{color:var(--bad)} .warn-c{color:var(--warn)}
|
||||
ul,ol{padding-left:22px;margin:10px 0}
|
||||
li{margin:5px 0}
|
||||
.lead{background:linear-gradient(180deg,rgba(224,136,79,.10),transparent);border:1px solid var(--border);border-radius:12px;padding:18px 20px;margin:0 0 8px}
|
||||
.kbd{font-family:var(--mono);font-size:.85em;color:var(--accent)}
|
||||
.small{color:var(--fg2);font-size:13px}
|
||||
hr{border:none;border-top:1px solid var(--border);margin:40px 0}
|
||||
a{color:var(--accent2)}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
|
||||
<h1>iOS + iPad 支持设计方案</h1>
|
||||
<p class="sub">Pangolin Flutter 客户端 · 目标里程碑 <span class="tag info">TestFlight 公测</span> · 分支 <code>feature/pangolin-ios</code> · 2026-06-22</p>
|
||||
|
||||
<div class="lead">
|
||||
<p style="margin:0"><strong>一句话</strong>:iOS 不是从零起步,而是停在一个 “M3 PoC” 半成品上 —— Xcode 工程、Swift 源码、entitlements、iPad 布局骨架都在,唯一硬阻塞是 <code>Libbox.xcframework</code> 只编了 macOS 切片。本方案把 iOS 隧道从「能编译的桩」推到「真机能连通、扛得住 NE 内存红线、可上 TestFlight」,<strong>iPad 跟着 iPhone 一起好</strong>(同一个 iOS target,非单独版本)。</p>
|
||||
</div>
|
||||
|
||||
<h2>1. 目标与范围</h2>
|
||||
<table>
|
||||
<tr><th>维度</th><th>本轮做</th><th>本轮不做</th></tr>
|
||||
<tr><td>连通性</td><td>iPhone / iPad 真机真正连上网、出网走自有节点</td><td>—</td></tr>
|
||||
<tr><td>分发</td><td>App Store Connect 配置 + 描述文件 + TestFlight 外部测试</td><td>完整 App Store 上架审核合规(隐私清单细节、审核问答)</td></tr>
|
||||
<tr><td>iPad</td><td>布局适配 + 横屏(宽屏主从/侧边栏,6 屏不拉伸)</td><td>Split View / Stage Manager 动态重排、外接键盘/指针/拖拽</td></tr>
|
||||
<tr><td>平台</td><td>iOS 12+,设备族 iPhone + iPad(已是 <code>"1,2"</code>)</td><td>tvOS / visionOS</td></tr>
|
||||
</table>
|
||||
<p class="small">前置条件已具备:付费 Apple Developer 账号(TeamID <code>BYL4KQHMTN</code>),可上 App Store Connect。</p>
|
||||
|
||||
<h2>2. 现状盘点(代码已有什么)</h2>
|
||||
<table>
|
||||
<tr><th>件</th><th>状态</th><th>说明</th></tr>
|
||||
<tr><td>Xcode 工程接线</td><td><span class="tag ok">已有</span></td><td><code>Runner</code> + <code>PacketTunnel</code> 两 target 已接好;设备族 iPhone+iPad;部署目标 iOS 12</td></tr>
|
||||
<tr><td>iOS Swift 源码</td><td><span class="tag warn">PoC 桩</span></td><td><code>PacketTunnelProvider.swift</code>(20KB) / <code>VpnManager.swift</code> / <code>MemoryMonitor.swift</code> 在,但 Provider 未真正接通 libbox</td></tr>
|
||||
<tr><td>entitlements</td><td><span class="tag ok">已有</span></td><td>正确的 iOS 格式:NE <code>packet-tunnel-provider</code> + App Group <code>group.com.pangolin.pangolinVpn</code></td></tr>
|
||||
<tr><td>Bundle ID</td><td><span class="tag ok">已定</span></td><td>主 App <code>com.pangolin.pangolinVpn</code>,扩展 <code>com.pangolin.pangolinVpn.PacketTunnel</code></td></tr>
|
||||
<tr><td>Libbox.xcframework</td><td><span class="tag bad">缺 iOS 切片</span></td><td>当前只有 <code>macos-arm64_x86_64</code>,缺 <code>ios-arm64</code> + <code>ios-arm64-simulator</code></td></tr>
|
||||
<tr><td>DEVELOPMENT_TEAM</td><td><span class="tag bad">未设</span></td><td>iOS 工程未填 team(macOS 已填 <code>BYL4KQHMTN</code>)</td></tr>
|
||||
<tr><td>iPad 布局</td><td><span class="tag warn">骨架</span></td><td><code>shell/tablet_shell.dart</code> + <code>core/responsive/form_factor.dart</code> 起步;<code>design/ui_kits/tablet</code> 有原型</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>iOS Provider 与 macOS 的差距(grep 实测)</h3>
|
||||
<table>
|
||||
<tr><th>关键修复点</th><th>macOS</th><th>iOS</th></tr>
|
||||
<tr><td>后台队列启 libbox(防三方死锁)</td><td class="ok-c">✓</td><td class="warn-c">半(有 DispatchQueue.global,未接启动序列)</td></tr>
|
||||
<tr><td>非空 <code>LibboxOverrideOptions()</code>(防 SIGSEGV)</td><td class="ok-c">✓</td><td class="bad-c">✗</td></tr>
|
||||
<tr><td>阻塞式 <code>startDefaultInterfaceMonitor</code></td><td class="ok-c">✓</td><td class="bad-c">✗</td></tr>
|
||||
<tr><td><code>startOrReloadService</code> 真正拉起 sing-box</td><td class="ok-c">✓</td><td class="bad-c">✗</td></tr>
|
||||
<tr><td>DNS 劫持首条规则</td><td>服务端渲染下发</td><td>服务端渲染下发(同源,无需客户端改)</td></tr>
|
||||
</table>
|
||||
|
||||
<h2>3. 架构决策:iOS Provider 实现策略</h2>
|
||||
<div class="card root">
|
||||
<h3>方案 A —— 移植成独立 iOS 版,两端各自维护 <span class="tag ok">已选</span></h3>
|
||||
<p>仓库本就分 <code>macos/PacketTunnel</code> 与 <code>ios/PacketTunnel</code>。两端是<strong>真分叉</strong>:System Extension vs App Extension、App Group 前缀 <code>BYL4KQHMTN.</code> vs <code>group.</code>、iOS 独有 ~50MB 内存红线。接受可控重复,在 iOS Provider 文件头放一份「与 macOS 的 parity 对照」注释防漂移。</p>
|
||||
<p class="small"><strong>取舍</strong>:成本最低、最贴合现有结构。</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>方案 B(未选)—— 抽公共 Swift core 两端共享</h3>
|
||||
<p>把 interface monitor / libbox 启动序列 / 配置 IPC 抽成共享文件,平台只留差异 shim。无漂移,但要给 ios + macos 两个独立 Flutter 工程都接好跨 target 共享文件,Xcode 这块很折腾。抽象收益压不过两套工程的接线成本。</p>
|
||||
</div>
|
||||
|
||||
<h2>4. 五条工作线</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>① libbox iOS 框架(解阻塞)</h3>
|
||||
<ul>
|
||||
<li>跑 <code>bash scripts/build-libbox.sh apple</code>(不带 platform)→ 产出含 <code>ios-arm64</code>(真机) + <code>ios-arm64-simulator</code> 切片的 <code>Libbox.xcframework</code>,放 <code>client/ios/Frameworks/</code>。</li>
|
||||
<li>Xcode 接线照 macOS 铁律:<strong>只 Link 不 Embed</strong>(静态库);<code>PacketTunnel</code> 设 <code>OTHER_LDFLAGS=""</code> 切断 CocoaPods 继承;<code>otool -L</code> 验扩展二进制零 <code>@rpath</code> 外部依赖。</li>
|
||||
<li>iOS 真机签名走嵌入式 provisioning(比 macOS Developer ID 站外分发简单,无需 sysext 公证/staple)。</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>② iOS Provider 对齐 macOS 修复</h3>
|
||||
<ul>
|
||||
<li>移植四件套:后台队列启 libbox、<strong>非空 <code>LibboxOverrideOptions()</code></strong>、<strong>阻塞式 <code>startDefaultInterfaceMonitor</code></strong>(阻塞到首个 path 更新再返回)、<code>startOrReloadService</code> 真正拉起 sing-box。</li>
|
||||
<li>配置由服务端 <code>BuildClientConfig</code> 渲染原样下发,客户端不拼;DNS 劫持首条规则随配置下发。</li>
|
||||
<li>iOS 专属:接 <code>MemoryMonitor</code>(已写好)在真机跑满配置打点,验 NE 进程峰值 < 设备 jetsam 上限。</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>③ App Group / IPC</h3>
|
||||
<ul>
|
||||
<li>entitlements 已是正确的 iOS <code>group.com.pangolin.pangolinVpn</code>,无需改格式。</li>
|
||||
<li>补 <code>ios/Runner.xcodeproj</code> 的 <code>DEVELOPMENT_TEAM = BYL4KQHMTN</code>(主 App + 扩展两 target)。</li>
|
||||
<li>验 <code>VpnManager.swift</code>(主 App)↔ Provider 经 App Group UserDefaults 通 status/stats(含崩溃恢复读取)。</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>④ iPad UI 适配(布局 + 横屏)</h3>
|
||||
<ul>
|
||||
<li>把 <code>shell/tablet_shell.dart</code> + <code>core/responsive/form_factor.dart</code> 做成完整宽屏主从/侧边栏。</li>
|
||||
<li>6 个 screen(connect / nodes / stats / settings / account / contact)在 iPad 竖/横屏不拉伸不空旷,对照 <code>design/ui_kits/tablet</code> 原型还原。</li>
|
||||
<li>Info.plist 开 iPad 全向 orientation;遵守设计 token 单源(颜色走 token,不硬编码)。</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>⑤ 分发到 TestFlight</h3>
|
||||
<ul>
|
||||
<li><strong>需用户在开发者后台手点</strong>(我给逐步清单):注册 App ID <code>com.pangolin.pangolinVpn</code> + extension ID + 勾 NE capability(packet-tunnel-provider) + 建 App Group。</li>
|
||||
<li>出口合规 <code>ITSAppUsesNonExemptEncryption</code>、Archive、上传、TestFlight 外部测试 beta 审核(比正式审核轻)。</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h2>5. 头号风险:iOS NE 内存红线</h2>
|
||||
<div class="card risk">
|
||||
<p><strong>iOS Network Extension 进程 ~50MB 内存硬顶(旧设备 ~15MB)× sing-box + 远程 rule-set</strong>。<br>
|
||||
配置层 <code>clientconfig.go</code> 的国内分流走<strong>远程拉</strong> <code>geoip-cn.srs</code> / <code>geosite-cn.srs</code>,启动期下载进内存,在 NE 进程里是 jetsam 杀进程的主因。</p>
|
||||
<p style="margin-bottom:0"><strong>两道闸:</strong></p>
|
||||
<ol style="margin-top:6px">
|
||||
<li><strong>先测</strong>:用 <code>MemoryMonitor</code> 在真机跑满配置,拿到峰值 resident 再决定。</li>
|
||||
<li><strong>不够就瘦身</strong>:落 #5 TODO 的<strong>本地 <code>.srs</code> 预取</strong>(避免启动期下载进内存),必要时 iOS 走精简 rule-set。</li>
|
||||
</ol>
|
||||
<p class="small" style="margin-bottom:0">⚠️ <strong>TestFlight 推送以「内存实测通过」为前置闸门</strong> —— 内存不过关不推。</p>
|
||||
</div>
|
||||
|
||||
<h3>其他风险</h3>
|
||||
<table>
|
||||
<tr><th>风险</th><th>缓解</th></tr>
|
||||
<tr><td>iOS Provider 移植引入新死锁/崩溃</td><td>严格照 macos-sysext 排障 runbook 的铁律;真机 device console 验证</td></tr>
|
||||
<tr><td>受限网络封高位端口</td><td>REALITY 数据口优先走节点 443(与 iPhone/macOS 同策略)</td></tr>
|
||||
<tr><td>iPad 布局漂移设计稿</td><td>对照 <code>design/ui_kits/tablet</code> 原型;遵守 token 单源</td></tr>
|
||||
</table>
|
||||
|
||||
<h2>6. 验收标准(Definition of Done)</h2>
|
||||
<ol>
|
||||
<li><code>scripts/build-libbox.sh apple</code> 产出含 iOS 切片的 xcframework,<code>otool -L</code> 验扩展零外部 <code>@rpath</code> 依赖。</li>
|
||||
<li>iPhone 真机:开关 VPN → sing-box 真正起来 → 能打开境外站点(DNS 不失败)。</li>
|
||||
<li>iPad 真机:同上连通;竖/横屏布局对照原型无拉伸/空旷。</li>
|
||||
<li><code>MemoryMonitor</code> 真机峰值 < 设备 jetsam 上限(10 分钟稳定运行不被杀)。</li>
|
||||
<li>成功 Archive 并上传 TestFlight,外部测试者可安装并连通。</li>
|
||||
</ol>
|
||||
|
||||
<h2>7. 不做(YAGNI)</h2>
|
||||
<ul>
|
||||
<li>Split View / Slide Over / Stage Manager 动态重排(窗口变窄回退手机布局即可,不做专门重排)。</li>
|
||||
<li>外接键盘快捷键 / 指针 hover / 拖拽等 iPad 原生交互。</li>
|
||||
<li>完整 App Store 上架审核合规(留待 TestFlight 稳定后另起一轮)。</li>
|
||||
<li>tvOS / visionOS。</li>
|
||||
<li>iOS Provider 与 macOS 抽公共 Swift core(接受可控重复)。</li>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
<p class="small">下一步:进 writing-plans 出逐步实施计划。本文档登记于 <a href="index.html">docs/index.html</a>。</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user