OpenCode Deployer commited on
Commit ·
8299d46
1
Parent(s): 8d3455e
update
Browse files- Dockerfile copy +23 -42
- Dockerfile.backup +0 -53
- NETWORK.md +0 -185
- NETWORK_OPTIMIZATION.md +0 -48
- backups/test.md +0 -1
- deep-diagnose.sh +0 -246
- docker-compose.yml +0 -49
- push.sh +20 -0
- service/health-check.sh +0 -35
Dockerfile copy
CHANGED
|
@@ -4,58 +4,39 @@ FROM ubuntu:22.04
|
|
| 4 |
# 设置环境变量避免交互式提示
|
| 5 |
ENV DEBIAN_FRONTEND=noninteractive
|
| 6 |
|
| 7 |
-
|
| 8 |
-
RUN
|
| 9 |
-
apt-get install -y curl cron && \
|
| 10 |
-
curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \
|
| 11 |
-
apt-get install -y nodejs && \
|
| 12 |
-
apt-get clean && \
|
| 13 |
-
rm -rf /var/lib/apt/lists/*
|
| 14 |
-
|
| 15 |
-
# 全局安装 OpenCode AI
|
| 16 |
-
RUN npm install -g opencode-ai
|
| 17 |
-
|
| 18 |
-
# 验证安装
|
| 19 |
-
RUN which opencode && \
|
| 20 |
-
opencode --version
|
| 21 |
-
|
| 22 |
-
# 复制并设置启动脚本
|
| 23 |
-
COPY start-services.sh /start-services.sh
|
| 24 |
-
RUN chmod +x /start-services.sh
|
| 25 |
|
| 26 |
# 创建 OpenCode 全局配置目录
|
| 27 |
-
RUN mkdir -p /root/.config/opencode /root/.config/claude
|
| 28 |
-
|
| 29 |
-
# 复制全局配置文件
|
| 30 |
-
COPY AGENTS.md /root/.config/opencode/AGENTS.md
|
| 31 |
-
COPY config/claude/CLAUDE.md /root/.config/claude/CLAUDE.md
|
| 32 |
|
| 33 |
-
#
|
| 34 |
-
RUN
|
| 35 |
|
| 36 |
-
# 添加健康检查
|
| 37 |
-
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
| 38 |
-
|
| 39 |
|
| 40 |
# 暴露 Hugging Face Spaces 标准端口
|
| 41 |
EXPOSE 7860
|
| 42 |
|
| 43 |
-
# 设置网络环境变量
|
| 44 |
-
ENV HTTP_PROXY=
|
| 45 |
-
ENV HTTPS_PROXY=
|
| 46 |
-
ENV NO_PROXY=localhost,127.0.0.1,0.0.0.0
|
| 47 |
|
| 48 |
-
# 明确禁用服务器认证,确保公开访问
|
| 49 |
-
# 清除所有可能导致认证的环境变量
|
| 50 |
-
ENV OPENCODE_SERVER_PASSWORD=""
|
| 51 |
-
ENV OPENCODE_SERVER_USERNAME=""
|
| 52 |
-
ENV OPENCODE_AUTH_REQUIRED=false
|
| 53 |
|
| 54 |
-
# 优化网络配置
|
| 55 |
-
ENV NODE_OPTIONS="--max-http-header-size=16384 --max-old-space-size=2048"
|
| 56 |
|
| 57 |
-
# 网络优化设置
|
| 58 |
-
ENV NODE_OPTIONS="--max-http-header-size=16384 --max-old-space-size=2048"
|
| 59 |
|
| 60 |
# 设置调试级别
|
| 61 |
ENV NODE_ENV=production
|
|
@@ -64,4 +45,4 @@ ENV LOG_LEVEL=info
|
|
| 64 |
# 使用 opencode serve 启动服务器
|
| 65 |
# 这将启动 API 服务器,内置 Web 界面
|
| 66 |
# 添加 CORS 支持以允许跨域访问
|
| 67 |
-
CMD ["/start-services.sh"]
|
|
|
|
| 4 |
# 设置环境变量避免交互式提示
|
| 5 |
ENV DEBIAN_FRONTEND=noninteractive
|
| 6 |
|
| 7 |
+
COPY service/ /service
|
| 8 |
+
RUN chmod +x /service/*.sh
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
# 创建 OpenCode 全局配置目录
|
| 11 |
+
# RUN mkdir -p /root/.config/opencode /root/.config/claude
|
| 12 |
+
COPY .config/ /root/.config
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
+
# # 将 /root/.config 目录及子目录下所有的 .md 文件权限修改为:644
|
| 15 |
+
# RUN find /root/.config -type f -name "*.md" -exec chmod 644 {} \;
|
| 16 |
|
| 17 |
+
# # 添加健康检查
|
| 18 |
+
# HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
| 19 |
+
# CMD curl -f http://localhost:7860/global/health || exit 1
|
| 20 |
|
| 21 |
# 暴露 Hugging Face Spaces 标准端口
|
| 22 |
EXPOSE 7860
|
| 23 |
|
| 24 |
+
# # 设置网络环境变量
|
| 25 |
+
# ENV HTTP_PROXY=
|
| 26 |
+
# ENV HTTPS_PROXY=
|
| 27 |
+
# ENV NO_PROXY=localhost,127.0.0.1,0.0.0.0
|
| 28 |
|
| 29 |
+
# # 明确禁用服务器认证,确保公开访问
|
| 30 |
+
# # 清除所有可能导致认证的环境变量
|
| 31 |
+
# ENV OPENCODE_SERVER_PASSWORD=""
|
| 32 |
+
# ENV OPENCODE_SERVER_USERNAME=""
|
| 33 |
+
# ENV OPENCODE_AUTH_REQUIRED=false
|
| 34 |
|
| 35 |
+
# # 优化网络配置
|
| 36 |
+
# ENV NODE_OPTIONS="--max-http-header-size=16384 --max-old-space-size=2048"
|
| 37 |
|
| 38 |
+
# # 网络优化设置
|
| 39 |
+
# ENV NODE_OPTIONS="--max-http-header-size=16384 --max-old-space-size=2048"
|
| 40 |
|
| 41 |
# 设置调试级别
|
| 42 |
ENV NODE_ENV=production
|
|
|
|
| 45 |
# 使用 opencode serve 启动服务器
|
| 46 |
# 这将启动 API 服务器,内置 Web 界面
|
| 47 |
# 添加 CORS 支持以允许跨域访问
|
| 48 |
+
CMD ["/service/start-services.sh"]
|
Dockerfile.backup
DELETED
|
@@ -1,53 +0,0 @@
|
|
| 1 |
-
# 使用 Ubuntu 基础镜像以确保更好的兼容性
|
| 2 |
-
FROM ubuntu:22.04
|
| 3 |
-
|
| 4 |
-
# 设置环境变量避免交互式提示
|
| 5 |
-
ENV DEBIAN_FRONTEND=noninteractive
|
| 6 |
-
|
| 7 |
-
# 安装 Node.js 和必要依赖
|
| 8 |
-
RUN apt-get update && \
|
| 9 |
-
apt-get install -y curl && \
|
| 10 |
-
curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \
|
| 11 |
-
apt-get install -y nodejs && \
|
| 12 |
-
apt-get clean && \
|
| 13 |
-
rm -rf /var/lib/apt/lists/*
|
| 14 |
-
|
| 15 |
-
# 全局安装 OpenCode AI
|
| 16 |
-
RUN npm install -g opencode-ai
|
| 17 |
-
|
| 18 |
-
# 验证安装
|
| 19 |
-
RUN which opencode && \
|
| 20 |
-
opencode --version
|
| 21 |
-
|
| 22 |
-
# 添加健康检查
|
| 23 |
-
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
| 24 |
-
CMD curl -f http://localhost:7860/global/health || exit 1
|
| 25 |
-
|
| 26 |
-
# 暴露 Hugging Face Spaces 标准端口
|
| 27 |
-
EXPOSE 7860
|
| 28 |
-
|
| 29 |
-
# 设置网络环境变量
|
| 30 |
-
ENV HTTP_PROXY=
|
| 31 |
-
ENV HTTPS_PROXY=
|
| 32 |
-
ENV NO_PROXY=localhost,127.0.0.1,0.0.0.0
|
| 33 |
-
|
| 34 |
-
# 明确禁用服务器认证,确保公开访问
|
| 35 |
-
# 清除所有可能导致认证的环境变量
|
| 36 |
-
ENV OPENCODE_SERVER_PASSWORD=
|
| 37 |
-
ENV OPENCODE_SERVER_USERNAME=
|
| 38 |
-
ENV OPENCODE_AUTH_REQUIRED=false
|
| 39 |
-
|
| 40 |
-
# 优化网络配置
|
| 41 |
-
ENV NODE_OPTIONS="--max-http-header-size=16384 --max-old-space-size=2048"
|
| 42 |
-
|
| 43 |
-
# 网络优化设置
|
| 44 |
-
ENV NODE_OPTIONS="--max-http-header-size=16384 --max-old-space-size=2048"
|
| 45 |
-
|
| 46 |
-
# 设置调试级别
|
| 47 |
-
ENV NODE_ENV=production
|
| 48 |
-
ENV LOG_LEVEL=info
|
| 49 |
-
|
| 50 |
-
# 使用 opencode serve 启动服务器
|
| 51 |
-
# 这将启动 API 服务器,内置 Web 界面
|
| 52 |
-
# 添加 CORS 支持以允许跨域访问
|
| 53 |
-
CMD ["opencode", "serve", "--port", "7860", "--hostname", "0.0.0.0", "--cors", "*"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NETWORK.md
DELETED
|
@@ -1,185 +0,0 @@
|
|
| 1 |
-
# 网络配置指南
|
| 2 |
-
|
| 3 |
-
## 问题说明
|
| 4 |
-
|
| 5 |
-
OpenCode AI Web Interface 在部署到 Hugging Face Spaces 后,在某些地区可能会遇到网络访问限制问题。
|
| 6 |
-
|
| 7 |
-
### 常见错误信息
|
| 8 |
-
|
| 9 |
-
#### 连接错误
|
| 10 |
-
```
|
| 11 |
-
Error: Could not connect to server. Is there a server running at `https://airsltd-hfoc.hf.space`?
|
| 12 |
-
```
|
| 13 |
-
|
| 14 |
-
#### 认证错误 (401)
|
| 15 |
-
```
|
| 16 |
-
HTTP 401 Unauthorized
|
| 17 |
-
WWW-Authenticate: Basic realm="Secure Area"
|
| 18 |
-
```
|
| 19 |
-
|
| 20 |
-
#### 请求挂起
|
| 21 |
-
```
|
| 22 |
-
Provisional headers are shown
|
| 23 |
-
```
|
| 24 |
-
|
| 25 |
-
## 解决方案
|
| 26 |
-
|
| 27 |
-
### 方案一:使用网络代理(推荐)
|
| 28 |
-
|
| 29 |
-
如果您有可用的代理服务,可以通过以下方式配置:
|
| 30 |
-
|
| 31 |
-
#### 1. 浏览器代理配置
|
| 32 |
-
- 在浏览器中设置 HTTP/HTTPS 代理
|
| 33 |
-
- 访问 `https://airsltd-hfoc.hf.space`
|
| 34 |
-
|
| 35 |
-
#### 2. 系统代理配置
|
| 36 |
-
```bash
|
| 37 |
-
# 设置代理环境变量
|
| 38 |
-
export HTTPS_PROXY=http://proxy.example.com:8080
|
| 39 |
-
export HTTP_PROXY=http://proxy.example.com:8080
|
| 40 |
-
export NO_PROXY=localhost,127.0.0.1
|
| 41 |
-
```
|
| 42 |
-
|
| 43 |
-
### 方案二:使用 VPN
|
| 44 |
-
|
| 45 |
-
- 连接到可用的 VPN 服务
|
| 46 |
-
- 确保可以访问 Hugging Face 域名
|
| 47 |
-
- 重新访问应用
|
| 48 |
-
|
| 49 |
-
### 方案三:本地部署
|
| 50 |
-
|
| 51 |
-
如果网络问题持续存在,可以考虑本地部署:
|
| 52 |
-
|
| 53 |
-
#### 1. 安装 OpenCode AI
|
| 54 |
-
```bash
|
| 55 |
-
# 使用 npm 安装
|
| 56 |
-
npm install -g opencode-ai
|
| 57 |
-
|
| 58 |
-
# 或使用 Homebrew
|
| 59 |
-
brew install opencode-ai/tap/opencode
|
| 60 |
-
```
|
| 61 |
-
|
| 62 |
-
#### 2. 启动本地服务
|
| 63 |
-
```bash
|
| 64 |
-
# 启动 Web 界面
|
| 65 |
-
opencode serve --port 7860 --hostname 0.0.0.0 --cors "*"
|
| 66 |
-
|
| 67 |
-
# 访问本地服务
|
| 68 |
-
# http://localhost:7860
|
| 69 |
-
```
|
| 70 |
-
|
| 71 |
-
## 技术细节
|
| 72 |
-
|
| 73 |
-
### CORS 配置
|
| 74 |
-
|
| 75 |
-
当前部署已配置 CORS 支持:
|
| 76 |
-
```dockerfile
|
| 77 |
-
CMD ["opencode", "serve", "--port", "7860", "--hostname", "0.0.0.0", "--cors", "*"]
|
| 78 |
-
```
|
| 79 |
-
|
| 80 |
-
### 网络环境变量
|
| 81 |
-
|
| 82 |
-
Docker 容器中已配置以下环境变量:
|
| 83 |
-
```dockerfile
|
| 84 |
-
ENV HTTP_PROXY=
|
| 85 |
-
ENV HTTPS_PROXY=
|
| 86 |
-
ENV NO_PROXY=localhost,127.0.0.1,0.0.0.0
|
| 87 |
-
```
|
| 88 |
-
|
| 89 |
-
### 健康检查端点
|
| 90 |
-
|
| 91 |
-
您可以通过以下端点检查服务状态:
|
| 92 |
-
```bash
|
| 93 |
-
curl https://airsltd-hfoc.hf.space/global/health
|
| 94 |
-
```
|
| 95 |
-
|
| 96 |
-
正常响应:
|
| 97 |
-
```json
|
| 98 |
-
{"healthy":true,"version":"1.1.21"}
|
| 99 |
-
```
|
| 100 |
-
|
| 101 |
-
## 故障排除
|
| 102 |
-
|
| 103 |
-
### 1. 401 认证错误
|
| 104 |
-
如果遇到 HTTP 401 错误:
|
| 105 |
-
|
| 106 |
-
**原因分析:**
|
| 107 |
-
- 服务器启用了基本认证
|
| 108 |
-
- 环境变量 `OPENCODE_SERVER_PASSWORD` 被设置
|
| 109 |
-
- Hugging Face Spaces 可能自动设置了认证
|
| 110 |
-
|
| 111 |
-
**解决方案:**
|
| 112 |
-
```bash
|
| 113 |
-
# 运行深度诊断
|
| 114 |
-
./deep-diagnose.sh
|
| 115 |
-
|
| 116 |
-
# 本地部署(推荐)
|
| 117 |
-
./start-local.sh
|
| 118 |
-
|
| 119 |
-
# 手动清理环境变量
|
| 120 |
-
unset OPENCODE_SERVER_PASSWORD
|
| 121 |
-
unset OPENCODE_SERVER_USERNAME
|
| 122 |
-
export OPENCODE_AUTH_REQUIRED=false
|
| 123 |
-
```
|
| 124 |
-
|
| 125 |
-
### 2. "Provisional headers are shown" 错误
|
| 126 |
-
这个错误表示请求被阻止或挂起:
|
| 127 |
-
|
| 128 |
-
**立即解决:**
|
| 129 |
-
- 清除浏览器缓存和 Cookie
|
| 130 |
-
- 尝试无痕模式
|
| 131 |
-
- 检查浏览器控制台的具体错误
|
| 132 |
-
|
| 133 |
-
**技术解决:**
|
| 134 |
-
- 运行 `./deep-diagnose.sh` 获取详细分析
|
| 135 |
-
- 使用本地部署避免网络问题
|
| 136 |
-
- 检查 CORS 配置
|
| 137 |
-
|
| 138 |
-
### 3. 检查服务状态
|
| 139 |
-
访问健康检查端点确认服务是否正常运行:
|
| 140 |
-
```bash
|
| 141 |
-
curl https://airsltd-hfoc.hf.space/global/health
|
| 142 |
-
```
|
| 143 |
-
|
| 144 |
-
### 4. 清除浏览器缓存
|
| 145 |
-
- Chrome: Ctrl+Shift+Delete → 清除缓存
|
| 146 |
-
- 重新加载页面
|
| 147 |
-
- 尝试无痕模式
|
| 148 |
-
|
| 149 |
-
### 5. 检查网络连接
|
| 150 |
-
```bash
|
| 151 |
-
# 测试域名解析
|
| 152 |
-
nslookup airsltd-hfoc.hf.space
|
| 153 |
-
|
| 154 |
-
# 测试连接
|
| 155 |
-
ping airsltd-hfoc.hf.space
|
| 156 |
-
|
| 157 |
-
# 深度网络诊断
|
| 158 |
-
./diagnose-network.sh
|
| 159 |
-
```
|
| 160 |
-
|
| 161 |
-
### 6. 检查防火墙设置
|
| 162 |
-
确保防火墙允许访问 Hugging Face Spaces 域名。
|
| 163 |
-
|
| 164 |
-
### 7. 尝试不同浏览器
|
| 165 |
-
有时浏览器扩展或设置会影响连接。
|
| 166 |
-
|
| 167 |
-
## 获取帮助
|
| 168 |
-
|
| 169 |
-
如果问题仍然存在,请:
|
| 170 |
-
|
| 171 |
-
1. 查看 [OpenCode 官方文档](https://opencode.ai/docs/network/)
|
| 172 |
-
2. 在 GitHub 上提交 Issue
|
| 173 |
-
3. 联系技术支持
|
| 174 |
-
|
| 175 |
-
## 备用访问方式
|
| 176 |
-
|
| 177 |
-
我们正在部署到更多平台以提供备用访问方式:
|
| 178 |
-
|
| 179 |
-
- **ModelScope**: 即将上线
|
| 180 |
-
- **Gitee AI**: 即将上线
|
| 181 |
-
- **本地部署**: 详见上方说明
|
| 182 |
-
|
| 183 |
-
---
|
| 184 |
-
|
| 185 |
-
最后更新:2026-01-15
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NETWORK_OPTIMIZATION.md
DELETED
|
@@ -1,48 +0,0 @@
|
|
| 1 |
-
# 网络优化说明
|
| 2 |
-
|
| 3 |
-
## 修复的 "Provisional headers are shown" 错误
|
| 4 |
-
|
| 5 |
-
### 更新内容
|
| 6 |
-
|
| 7 |
-
1. **CORS 配置优化**
|
| 8 |
-
- 添加了完整的 CORS 环境变量
|
| 9 |
-
- 明确指定允许的请求方法和头部
|
| 10 |
-
- 禁用凭据传递以简化 CORS 处理
|
| 11 |
-
|
| 12 |
-
2. **网络参数调整**
|
| 13 |
-
- 增加 HTTP 头部大小限制到 16KB
|
| 14 |
-
- 设置 Node.js 内存限制为 2GB
|
| 15 |
-
- 添加请求超时设置(30秒)
|
| 16 |
-
|
| 17 |
-
3. **健康检查**
|
| 18 |
-
- 每30秒检查服务状态
|
| 19 |
-
- 启动前5秒等待期
|
| 20 |
-
- 最多重试3次
|
| 21 |
-
|
| 22 |
-
### 技术细节
|
| 23 |
-
|
| 24 |
-
```dockerfile
|
| 25 |
-
# 网络优化
|
| 26 |
-
ENV NODE_OPTIONS="--max-http-header-size=16384 --max-old-space-size=2048"
|
| 27 |
-
|
| 28 |
-
# 优化的启动命令
|
| 29 |
-
CMD ["opencode", "serve", "--port", "7860", "--hostname", "0.0.0.0", "--cors", "*"]
|
| 30 |
-
```
|
| 31 |
-
|
| 32 |
-
### 预期效果
|
| 33 |
-
|
| 34 |
-
1. 减少因 CORS 预检请求失败导致的 "Provisional headers are shown" 错误
|
| 35 |
-
2. 提高大文件 JavaScript 的下载成功率
|
| 36 |
-
3. 改善网络不稳定情况下的用户体验
|
| 37 |
-
4. 增强服务稳定性监控
|
| 38 |
-
|
| 39 |
-
### 验证方法
|
| 40 |
-
|
| 41 |
-
1. 重新部署后检查浏览器开发者工具 Network 标签
|
| 42 |
-
2. 观察 JavaScript 文件加载是否正常
|
| 43 |
-
3. 检查健康检查端点:`https://airsltd-hfoc.hf.space/global/health`
|
| 44 |
-
|
| 45 |
-
---
|
| 46 |
-
|
| 47 |
-
更新日期:2026-01-15
|
| 48 |
-
版本:v0.0.1-network-optimization
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backups/test.md
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
就是修改用来重新构建而已
|
|
|
|
|
|
deep-diagnose.sh
DELETED
|
@@ -1,246 +0,0 @@
|
|
| 1 |
-
#!/bin/bash
|
| 2 |
-
|
| 3 |
-
# OpenCode AI Web Interface - 深度诊断脚本
|
| 4 |
-
# 用于诊断 "Provisional headers are shown" 和 401 错误
|
| 5 |
-
|
| 6 |
-
set -e
|
| 7 |
-
|
| 8 |
-
# 颜色定义
|
| 9 |
-
RED='\033[0;31m'
|
| 10 |
-
GREEN='\033[0;32m'
|
| 11 |
-
YELLOW='\033[1;33m'
|
| 12 |
-
BLUE='\033[0;34m'
|
| 13 |
-
NC='\033[0m' # No Color
|
| 14 |
-
|
| 15 |
-
print_info() {
|
| 16 |
-
echo -e "${BLUE}ℹ️ $1${NC}"
|
| 17 |
-
}
|
| 18 |
-
|
| 19 |
-
print_success() {
|
| 20 |
-
echo -e "${GREEN}✅ $1${NC}"
|
| 21 |
-
}
|
| 22 |
-
|
| 23 |
-
print_warning() {
|
| 24 |
-
echo -e "${YELLOW}⚠️ $1${NC}"
|
| 25 |
-
}
|
| 26 |
-
|
| 27 |
-
print_error() {
|
| 28 |
-
echo -e "${RED}❌ $1${NC}"
|
| 29 |
-
}
|
| 30 |
-
|
| 31 |
-
print_header() {
|
| 32 |
-
echo -e "${BLUE}"
|
| 33 |
-
echo "=================================="
|
| 34 |
-
echo " OpenCode AI 深度诊断工具"
|
| 35 |
-
echo "=================================="
|
| 36 |
-
echo -e "${NC}"
|
| 37 |
-
}
|
| 38 |
-
|
| 39 |
-
# 测试不同的端点
|
| 40 |
-
test_endpoints() {
|
| 41 |
-
local base_url="https://airsltd-hfoc.hf.space"
|
| 42 |
-
|
| 43 |
-
print_info "测试不同的 API 端点..."
|
| 44 |
-
|
| 45 |
-
# 测试健康检查端点
|
| 46 |
-
print_info "测试 /global/health 端点..."
|
| 47 |
-
local health_response=$(curl -s -w "HTTPSTATUS:%{http_code}" "$base_url/global/health" 2>/dev/null || echo "HTTPSTATUS:000")
|
| 48 |
-
local http_code=$(echo $health_response | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
|
| 49 |
-
local response_body=$(echo $health_response | sed -e 's/HTTPSTATUS:.*//g')
|
| 50 |
-
|
| 51 |
-
if [ "$http_code" = "200" ]; then
|
| 52 |
-
print_success "健康检查端点正常 (200)"
|
| 53 |
-
echo "响应: $response_body"
|
| 54 |
-
elif [ "$http_code" = "401" ]; then
|
| 55 |
-
print_error "健康检查端点需要认证 (401)"
|
| 56 |
-
echo "响应: $response_body"
|
| 57 |
-
print_warning "可能原因:"
|
| 58 |
-
echo "1. 服务器设置了密码保护"
|
| 59 |
-
echo "2. 环境变量 OPENCODE_SERVER_PASSWORD 被设置"
|
| 60 |
-
echo "3. 需要配置认证头"
|
| 61 |
-
elif [ "$http_code" = "403" ]; then
|
| 62 |
-
print_error "健康检查端点访问被禁止 (403)"
|
| 63 |
-
echo "响应: $response_body"
|
| 64 |
-
else
|
| 65 |
-
print_warning "健康检查端点返回状态码: $http_code"
|
| 66 |
-
echo "响应: $response_body"
|
| 67 |
-
fi
|
| 68 |
-
|
| 69 |
-
echo ""
|
| 70 |
-
|
| 71 |
-
# 测试根路径
|
| 72 |
-
print_info "测试根路径 / ..."
|
| 73 |
-
local root_response=$(curl -s -w "HTTPSTATUS:%{http_code}" "$base_url/" 2>/dev/null || echo "HTTPSTATUS:000")
|
| 74 |
-
local root_http_code=$(echo $root_response | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
|
| 75 |
-
|
| 76 |
-
if [ "$root_http_code" = "200" ]; then
|
| 77 |
-
print_success "根路径正常 (200)"
|
| 78 |
-
elif [ "$root_http_code" = "401" ]; then
|
| 79 |
-
print_error "根路径需要认证 (401)"
|
| 80 |
-
else
|
| 81 |
-
print_warning "根路径返回状态码: $root_http_code"
|
| 82 |
-
fi
|
| 83 |
-
|
| 84 |
-
echo ""
|
| 85 |
-
|
| 86 |
-
# 测试 OpenAPI 文档端点
|
| 87 |
-
print_info "测试 /doc 端点..."
|
| 88 |
-
local doc_response=$(curl -s -w "HTTPSTATUS:%{http_code}" "$base_url/doc" 2>/dev/null || echo "HTTPSTATUS:000")
|
| 89 |
-
local doc_http_code=$(echo $doc_response | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
|
| 90 |
-
|
| 91 |
-
if [ "$doc_http_code" = "200" ]; then
|
| 92 |
-
print_success "API 文档端点正常 (200)"
|
| 93 |
-
elif [ "$doc_http_code" = "401" ]; then
|
| 94 |
-
print_error "API 文档端点需要认证 (401)"
|
| 95 |
-
else
|
| 96 |
-
print_warning "API 文档端点返回状态码: $doc_http_code"
|
| 97 |
-
fi
|
| 98 |
-
|
| 99 |
-
echo ""
|
| 100 |
-
}
|
| 101 |
-
|
| 102 |
-
# 测试带认证的请求
|
| 103 |
-
test_with_auth() {
|
| 104 |
-
local base_url="https://airsltd-hfoc.hf.space"
|
| 105 |
-
|
| 106 |
-
print_info "测试带基本认证的请求..."
|
| 107 |
-
|
| 108 |
-
# 尝试使用默认凭据
|
| 109 |
-
print_info "尝试使用默认凭据 (opencode:opencode)..."
|
| 110 |
-
local auth_response=$(curl -s -w "HTTPSTATUS:%{http_code}" -u "opencode:opencode" "$base_url/global/health" 2>/dev/null || echo "HTTPSTATUS:000")
|
| 111 |
-
local auth_http_code=$(echo $auth_response | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
|
| 112 |
-
|
| 113 |
-
if [ "$auth_http_code" = "200" ]; then
|
| 114 |
-
print_success "使用默认凭据认证成功 (200)"
|
| 115 |
-
print_warning "服务器需要基本认证,用户名: opencode, 密码: opencode"
|
| 116 |
-
elif [ "$auth_http_code" = "401" ]; then
|
| 117 |
-
print_error "默认凭据认证失败 (401)"
|
| 118 |
-
else
|
| 119 |
-
print_warning "使用默认凭据返回状态码: $auth_http_code"
|
| 120 |
-
fi
|
| 121 |
-
|
| 122 |
-
echo ""
|
| 123 |
-
}
|
| 124 |
-
|
| 125 |
-
# 检查响应头
|
| 126 |
-
check_response_headers() {
|
| 127 |
-
local base_url="https://airsltd-hfoc.hf.space"
|
| 128 |
-
|
| 129 |
-
print_info "检查响应头信息..."
|
| 130 |
-
|
| 131 |
-
print_info "获取根路径的响应头..."
|
| 132 |
-
local headers=$(curl -s -I "$base_url/" 2>/dev/null || echo "无法获取响应头")
|
| 133 |
-
|
| 134 |
-
if [ -n "$headers" ]; then
|
| 135 |
-
echo "$headers" | while IFS= read -r line; do
|
| 136 |
-
if [ -n "$line" ]; then
|
| 137 |
-
echo " $line"
|
| 138 |
-
fi
|
| 139 |
-
done
|
| 140 |
-
|
| 141 |
-
# 检查重要的头
|
| 142 |
-
if echo "$headers" | grep -qi "www-authenticate"; then
|
| 143 |
-
print_error "检测到 WWW-Authenticate 头,服务器需要认证"
|
| 144 |
-
fi
|
| 145 |
-
|
| 146 |
-
if echo "$headers" | grep -qi "access-control-allow-origin"; then
|
| 147 |
-
print_success "检测到 CORS 头"
|
| 148 |
-
else
|
| 149 |
-
print_warning "未检测到 CORS 头,可能导致跨域问题"
|
| 150 |
-
fi
|
| 151 |
-
else
|
| 152 |
-
print_error "无法获取响应头"
|
| 153 |
-
fi
|
| 154 |
-
|
| 155 |
-
echo ""
|
| 156 |
-
}
|
| 157 |
-
|
| 158 |
-
# 分析 "Provisional headers are shown" 问题
|
| 159 |
-
analyze_provisional_headers() {
|
| 160 |
-
print_info "分析 'Provisional headers are shown' 问题..."
|
| 161 |
-
echo ""
|
| 162 |
-
print_warning "这个错误通常由以下原因引起:"
|
| 163 |
-
echo ""
|
| 164 |
-
echo "1. 🚫 请求被阻止或挂起"
|
| 165 |
-
echo " - CORS 策略阻止"
|
| 166 |
-
echo " - 网络中间件拦截"
|
| 167 |
-
echo " - 防火墙或安全策略"
|
| 168 |
-
echo ""
|
| 169 |
-
echo "2. 🔐 认证问题"
|
| 170 |
-
echo " - 服务器需要认证但未提供凭据"
|
| 171 |
-
echo " - 认证凭据错误或过期"
|
| 172 |
-
echo " - 认证方式不匹配"
|
| 173 |
-
echo ""
|
| 174 |
-
echo "3. 🌐 网络问题"
|
| 175 |
-
echo " - 代理服务器配置问题"
|
| 176 |
-
echo " - DNS 解析问题"
|
| 177 |
-
echo " - 连接超时"
|
| 178 |
-
echo ""
|
| 179 |
-
echo "4. 🖥️ 浏览器问题"
|
| 180 |
-
echo " - 浏览器扩展拦截"
|
| 181 |
-
echo " - 缓存问题"
|
| 182 |
-
echo " - 安全策略过于严格"
|
| 183 |
-
echo ""
|
| 184 |
-
}
|
| 185 |
-
|
| 186 |
-
# 提供解决方案
|
| 187 |
-
provide_solutions() {
|
| 188 |
-
print_info "提供解决方案建议..."
|
| 189 |
-
echo ""
|
| 190 |
-
echo -e "${YELLOW}=== 立即解决方案 ===${NC}"
|
| 191 |
-
echo ""
|
| 192 |
-
echo "1. 🔄 清除浏览器缓存和 Cookie"
|
| 193 |
-
echo " - Chrome: Ctrl+Shift+Delete → 清除缓存"
|
| 194 |
-
echo " - 尝试无痕模式访问"
|
| 195 |
-
echo ""
|
| 196 |
-
echo "2. 🔍 检查浏览器控制台"
|
| 197 |
-
echo " - F12 打开开发者工具"
|
| 198 |
-
echo " - 查看 Console 和 Network 标签页"
|
| 199 |
-
echo " - 寻找具体的错误信息"
|
| 200 |
-
echo ""
|
| 201 |
-
echo "3. 🌐 尝试不同网络"
|
| 202 |
-
echo " - 切换 WiFi/移动网络"
|
| 203 |
-
echo " - 使用 VPN 或代理"
|
| 204 |
-
echo " - 尝试手机热点"
|
| 205 |
-
echo ""
|
| 206 |
-
echo ""
|
| 207 |
-
echo -e "${YELLOW}=== 技术解决方案 ===${NC}"
|
| 208 |
-
echo ""
|
| 209 |
-
echo "1. 🏠 本地部署"
|
| 210 |
-
echo " ./start-local.sh"
|
| 211 |
-
echo " 访问: http://localhost:7860"
|
| 212 |
-
echo ""
|
| 213 |
-
echo "2. 🔧 服务器配置"
|
| 214 |
-
echo " - 检查 OPENCODE_SERVER_PASSWORD 环境变量"
|
| 215 |
-
echo " - 确保设置为空或未设置"
|
| 216 |
-
echo " - 重新部署服务器"
|
| 217 |
-
echo ""
|
| 218 |
-
echo "3. 🐛 代码调试"
|
| 219 |
-
echo " - 检查服务器日志"
|
| 220 |
-
echo " - 验证 CORS 配置"
|
| 221 |
-
echo " - 测试 API 端点"
|
| 222 |
-
echo ""
|
| 223 |
-
}
|
| 224 |
-
|
| 225 |
-
# 主函数
|
| 226 |
-
main() {
|
| 227 |
-
print_header
|
| 228 |
-
|
| 229 |
-
# 执行深度诊断
|
| 230 |
-
test_endpoints
|
| 231 |
-
test_with_auth
|
| 232 |
-
check_response_headers
|
| 233 |
-
analyze_provisional_headers
|
| 234 |
-
provide_solutions
|
| 235 |
-
|
| 236 |
-
print_info "深度诊断完成!"
|
| 237 |
-
echo ""
|
| 238 |
-
print_info "建议的下一步操作:"
|
| 239 |
-
echo "1. 查看浏览器控制台的具体错误信息"
|
| 240 |
-
echo "2. 尝试本地部署验证功能"
|
| 241 |
-
echo "3. 如果是认证问题,需要重新部署服务器"
|
| 242 |
-
echo "4. 检查 Hugging Face Spaces 的部署日志"
|
| 243 |
-
}
|
| 244 |
-
|
| 245 |
-
# 运行主函数
|
| 246 |
-
main "$@"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docker-compose.yml
DELETED
|
@@ -1,49 +0,0 @@
|
|
| 1 |
-
version: '3.8'
|
| 2 |
-
|
| 3 |
-
services:
|
| 4 |
-
opencode-web:
|
| 5 |
-
build:
|
| 6 |
-
context: .
|
| 7 |
-
dockerfile: Dockerfile
|
| 8 |
-
container_name: opencode-web-interface
|
| 9 |
-
ports:
|
| 10 |
-
- "7860:7860"
|
| 11 |
-
environment:
|
| 12 |
-
# 网络代理配置(根据需要修改)
|
| 13 |
-
- HTTP_PROXY=
|
| 14 |
-
- HTTPS_PROXY=
|
| 15 |
-
- NO_PROXY=localhost,127.0.0.1,0.0.0.0
|
| 16 |
-
|
| 17 |
-
# OpenCode 服务器配置
|
| 18 |
-
- OPENCODE_SERVER_PORT=7860
|
| 19 |
-
- OPENCODE_SERVER_HOSTNAME=0.0.0.0
|
| 20 |
-
|
| 21 |
-
restart: unless-stopped
|
| 22 |
-
networks:
|
| 23 |
-
- opencode-network
|
| 24 |
-
|
| 25 |
-
# 可选:添加反向代理(Nginx)
|
| 26 |
-
nginx:
|
| 27 |
-
image: nginx:alpine
|
| 28 |
-
container_name: opencode-nginx
|
| 29 |
-
ports:
|
| 30 |
-
- "80:80"
|
| 31 |
-
- "443:443"
|
| 32 |
-
volumes:
|
| 33 |
-
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
| 34 |
-
- ./ssl:/etc/nginx/ssl:ro
|
| 35 |
-
depends_on:
|
| 36 |
-
- opencode-web
|
| 37 |
-
restart: unless-stopped
|
| 38 |
-
networks:
|
| 39 |
-
- opencode-network
|
| 40 |
-
profiles:
|
| 41 |
-
- with-nginx
|
| 42 |
-
|
| 43 |
-
networks:
|
| 44 |
-
opencode-network:
|
| 45 |
-
driver: bridge
|
| 46 |
-
|
| 47 |
-
volumes:
|
| 48 |
-
opencode-data:
|
| 49 |
-
driver: local
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
push.sh
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
git add .
|
| 2 |
git commit -m "update"
|
| 3 |
git push
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
|
| 3 |
+
OS_TYPE=$(uname -s)
|
| 4 |
+
|
| 5 |
+
case "$OS_TYPE" in
|
| 6 |
+
Darwin*)
|
| 7 |
+
echo "当前系统是 macOS。"
|
| 8 |
+
ssh-add ~/.ssh/id_ed25519_airsltd_mac
|
| 9 |
+
;;
|
| 10 |
+
Linux*)
|
| 11 |
+
echo "当前系统是 Linux。"
|
| 12 |
+
;;
|
| 13 |
+
CYGWIN*|MINGW*|MSYS*)
|
| 14 |
+
echo "当前系统是 Windows。"
|
| 15 |
+
;;
|
| 16 |
+
*)
|
| 17 |
+
echo "未知的系统: $OS_TYPE"
|
| 18 |
+
;;
|
| 19 |
+
esac
|
| 20 |
git add .
|
| 21 |
git commit -m "update"
|
| 22 |
git push
|
| 23 |
+
|
service/health-check.sh
DELETED
|
@@ -1,35 +0,0 @@
|
|
| 1 |
-
#!/bin/bash
|
| 2 |
-
|
| 3 |
-
# 健康检查函数
|
| 4 |
-
health_check() {
|
| 5 |
-
local max_retries=3
|
| 6 |
-
local retry_count=0
|
| 7 |
-
local interval=30
|
| 8 |
-
local timeout=10
|
| 9 |
-
local start_period=5
|
| 10 |
-
|
| 11 |
-
echo "等待服务启动 ($start_period 秒)..."
|
| 12 |
-
sleep $start_period
|
| 13 |
-
|
| 14 |
-
while [ $retry_count -lt $max_retries ]; do
|
| 15 |
-
echo "执行健康检查 (尝试 $((retry_count + 1))/$max_retries)..."
|
| 16 |
-
|
| 17 |
-
if curl -f --max-time $timeout http://localhost:7860/global/health; then
|
| 18 |
-
echo "健康检查通过"
|
| 19 |
-
return 0
|
| 20 |
-
else
|
| 21 |
-
echo "健康检查失败"
|
| 22 |
-
retry_count=$((retry_count + 1))
|
| 23 |
-
if [ $retry_count -lt $max_retries ]; then
|
| 24 |
-
echo "等待 $interval 秒后重试..."
|
| 25 |
-
sleep $interval
|
| 26 |
-
fi
|
| 27 |
-
fi
|
| 28 |
-
done
|
| 29 |
-
|
| 30 |
-
echo "健康检查最终失败"
|
| 31 |
-
return 1
|
| 32 |
-
}
|
| 33 |
-
|
| 34 |
-
# 调用健康检查
|
| 35 |
-
health_check
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|