修复搜索页面会重复出现搜索框的问题;页面底部支持公安备案,取消社交图标。
This commit is contained in:
parent
0a584bafca
commit
c737db897b
@ -1,7 +1,6 @@
|
||||
---
|
||||
import Hr from "./Hr.astro";
|
||||
import Socials from "./Socials.astro";
|
||||
import '../config'
|
||||
import "../config";
|
||||
import { SITE } from "../config";
|
||||
|
||||
const currentYear = new Date().getFullYear();
|
||||
@ -15,14 +14,34 @@ const { noMarginTop = false } = Astro.props;
|
||||
|
||||
<footer class:list={["w-full", { "mt-auto": !noMarginTop }]}>
|
||||
<Hr noPadding />
|
||||
<div
|
||||
class="flex flex-col items-center justify-between py-6 sm:flex-row-reverse sm:py-4"
|
||||
>
|
||||
<Socials centered />
|
||||
<div class="my-2 flex flex-col items-center whitespace-nowrap sm:flex-row">
|
||||
<div class="flex flex-col items-center py-4 sm:py-3">
|
||||
<div class="flex flex-col sm:flex-row items-center gap-2 mb-2">
|
||||
{SITE.gabeian.enabled && (
|
||||
<div class="flex items-center gap-1">
|
||||
<img src="/assets/gabeian.png" alt="Gabeian" class="h-4 w-4" />
|
||||
<a
|
||||
href="https://beian.mps.gov.cn/#/query/webSearch?code=41168102000247"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
class="underline hover:text-accent hover:no-underline"
|
||||
>
|
||||
{SITE.gabeian.id}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
{SITE.beian.enabled && (
|
||||
<a
|
||||
href="https://beian.miit.gov.cn/"
|
||||
target="_blank"
|
||||
class="underline hover:text-accent hover:no-underline"
|
||||
>
|
||||
{SITE.beian.id}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row items-center whitespace-nowrap">
|
||||
<span>版权所有 © {SITE.created}-{currentYear} {SITE.author}</span>
|
||||
<span class="hidden sm:inline"> | </span>
|
||||
<span>保留所有权利</span>
|
||||
<span class="sm:ml-2">保留所有权利</span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
@ -19,5 +19,13 @@ export const SITE = {
|
||||
url: "https://codeberg.org/blue-cape/astro-paper-zh/src/branch/main/src/data/blog",
|
||||
text: "建议修改",
|
||||
appendFilePath: true,
|
||||
}
|
||||
},
|
||||
beian: {
|
||||
enabled: false,
|
||||
id: "豫ICP备2024095307号-1",
|
||||
},
|
||||
gabeian: {
|
||||
enabled: false,
|
||||
id: "豫公网安备41168102000247号",
|
||||
},
|
||||
} as const;
|
||||
|
@ -1,198 +0,0 @@
|
||||
---
|
||||
title: HTTPS代理理论及实战
|
||||
pubDatetime: 2025-02-12T09:15:06+8:00
|
||||
description: HTTPS代理理论及实战
|
||||
slug: https-proxy
|
||||
tags:
|
||||
- HTTPS代理
|
||||
- 中间人攻击
|
||||
---
|
||||
|
||||
## 场景需求
|
||||
| **场景** | **用途** |
|
||||
|----------------|-------------------------------------------------------------------------|
|
||||
| 开发调试 | 模拟 API 响应,测试客户端逻辑(如支付失败、超时场景) |
|
||||
| 性能优化 | 缓存静态资源,减少重复请求网络延迟 |
|
||||
| 安全测试 | 拦截敏感数据传输,检测明文泄露或弱加密问题 |
|
||||
| 故障排查 | 模拟服务器 5xx 错误,验证客户端容错逻辑 |
|
||||
| 隐私保护 | 通过代理隐藏真实 IP,防止地理位置追踪 |
|
||||
|
||||
<!-- more -->
|
||||
|
||||
---
|
||||
|
||||
## HTTPS 抓包原理
|
||||
|
||||
### 1. HTTPS 加密的基本原理
|
||||
```plaintext
|
||||
HTTPS 握手流程:
|
||||
1. 客户端发送 ClientHello → 协商 TLS 版本和加密套件
|
||||
2. 服务端返回 ServerHello + 证书 → 身份验证
|
||||
3. 客户端验证证书 → 生成预主密钥(Premaster Secret)
|
||||
4. 服务端解密预主密钥 → 生成对称加密密钥(Session Key)
|
||||
5. 双方使用 Session Key 加密通信
|
||||
```
|
||||
|
||||
**关键点**:
|
||||
非对称加密仅用于身份验证和密钥交换,对称加密用于实际数据传输。
|
||||
|
||||
---
|
||||
|
||||
### 2. HTTPS 抓包的核心:中间人攻击(MITM)
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant MITM_Proxy
|
||||
participant Server
|
||||
|
||||
Client->>MITM_Proxy: 请求 HTTPS 连接(ClientHello)
|
||||
MITM_Proxy->>Client: 返回伪造证书
|
||||
Client->>MITM_Proxy: 信任证书并协商密钥
|
||||
MITM_Proxy->>Server: 转发请求并建立真实 HTTPS 连接
|
||||
Server->>MITM_Proxy: 返回真实加密数据
|
||||
MITM_Proxy->>Client: 解密后重新加密返回
|
||||
```
|
||||
|
||||
**必要条件**:客户端必须信任代理工具的根证书(否则浏览器会提示 `NET::ERR_CERT_AUTHORITY_INVALID`)。
|
||||
|
||||
---
|
||||
|
||||
### 3. 抓包工具的具体实现
|
||||
| **工具** | **特点** |
|
||||
|---------------|-------------------------------------------------------------------------|
|
||||
| Fiddler | 图形化界面,支持断点调试和自动化脚本(FiddlerScript) |
|
||||
| Charles | 类似 Fiddler,支持 Map Remote/Local 和 Throttling 功能 |
|
||||
| mitmproxy | 命令行工具,适合自动化场景,支持 Python 脚本扩展 |
|
||||
| Wireshark | 底层抓包,需配合 SSLKEYLOGFILE 解密流量 |
|
||||
|
||||
---
|
||||
|
||||
### 4. 突破 HTTPS 抓包的限制
|
||||
|
||||
#### 场景 1:证书绑定(Certificate Pinning)
|
||||
- **原理**:应用内置服务器证书指纹,拒绝信任系统证书。
|
||||
- **绕过方案**:
|
||||
```bash
|
||||
# Android 使用 Frida 绕过(需 root)
|
||||
frida -U -f com.example.app -l bypass_ssl_pinning.js
|
||||
```
|
||||
|
||||
#### 场景 2:HTTP/2 或 HTTP/3
|
||||
- **对策**:确保代理工具支持最新协议(如 mitmproxy 7.0+ 支持 HTTP/2)。
|
||||
|
||||
#### 场景 3:客户端检测代理
|
||||
- **透明代理方案**:
|
||||
```bash
|
||||
# Linux 使用 iptables 重定向流量
|
||||
iptables -t nat -A OUTPUT -p tcp --dport 443 -j REDIRECT --to-port 8080
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 实战:mitmproxy 使用指南
|
||||
|
||||
### 1. 安装与启动
|
||||
```bash
|
||||
# 安装(推荐 Python 虚拟环境)
|
||||
pip install mitmproxy
|
||||
|
||||
# 启动交互式界面
|
||||
mitmproxy -p 8080 --ssl-insecure
|
||||
|
||||
# 启动 Web 界面(http://localhost:8081)
|
||||
mitmweb
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. 代理配置
|
||||
| **客户端类型** | **配置方法** |
|
||||
|---------------|-----------------------------------------------------------------------------|
|
||||
| 浏览器 | 设置 → 网络设置 → 手动代理:`127.0.0.1:8080` |
|
||||
| Android | Wi-Fi → 修改网络 → 高级选项 → 代理手动 → 输入主机和端口 |
|
||||
| iOS | Wi-Fi → HTTP 代理 → 配置代理 → 手动 |
|
||||
| 命令行工具 | 使用环境变量:<br>`export http_proxy=http://127.0.0.1:8080 https_proxy=http://127.0.0.1:8080` |
|
||||
|
||||
---
|
||||
|
||||
### 3. 证书安装
|
||||
| **系统** | **操作步骤** |
|
||||
|--------------|-----------------------------------------------------------------------------|
|
||||
| Windows | 访问 `http://mitm.it` → 下载证书 → 双击安装到“受信任的根证书颁发机构” |
|
||||
| macOS | 下载证书 → 钥匙串访问 → 添加证书 → 设置为“始终信任” |
|
||||
| Android | 访问 `http://mitm.it` → 下载证书 → 设置 → 安全 → 加密与凭据 → 安装证书 |
|
||||
| iOS | 访问 `http://mitm.it` → 下载描述文件 → 设置 → 已下载描述文件 → 安装 |
|
||||
|
||||
---
|
||||
|
||||
### 4. 基础操作
|
||||
| **快捷键** | **功能** |
|
||||
|-------------|-------------------------------------------------------------------------|
|
||||
| `↑/↓` | 选择请求 |
|
||||
| `Enter` | 查看请求/响应详情 |
|
||||
| `Tab` | 切换请求/响应标签页 |
|
||||
| `/` | 过滤请求(如 `~u example.com` 过滤 URL) |
|
||||
| `w` | 保存会话到文件(`.mitm` 格式) |
|
||||
|
||||
---
|
||||
|
||||
### 5. 高级功能
|
||||
|
||||
#### 脚本示例:修改请求头
|
||||
```python
|
||||
# modify_headers.py
|
||||
from mitmproxy import http
|
||||
|
||||
def request(flow: http.HTTPFlow):
|
||||
flow.request.headers["X-Debug"] = "true"
|
||||
```
|
||||
|
||||
#### 脚本示例:模拟 API 响应
|
||||
```python
|
||||
# mock_api.py
|
||||
from mitmproxy import http
|
||||
|
||||
def request(flow: http.HTTPFlow):
|
||||
if "api.example.com/data" in flow.request.url:
|
||||
flow.response = http.Response.make(
|
||||
200,
|
||||
b'{"status": "success", "data": "mocked"}',
|
||||
{"Content-Type": "application/json"}
|
||||
)
|
||||
```
|
||||
|
||||
**启动命令**:
|
||||
```bash
|
||||
mitmproxy -s modify_headers.py -s mock_api.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. 调试技巧
|
||||
- **实时日志**:通过 `mitmdump -v` 查看详细日志。
|
||||
- **过滤噪声**:使用 `-I` 参数忽略指定域名:
|
||||
```bash
|
||||
mitmproxy -I ".*google.*"
|
||||
```
|
||||
- **性能分析**:按 `m` 标记请求,按 `M` 查看统计信息(如响应时间分布)。
|
||||
|
||||
---
|
||||
|
||||
## 附录
|
||||
|
||||
### 工具对比
|
||||
| **功能** | mitmproxy | Fiddler | Charles |
|
||||
|------------------|-----------|---------|---------|
|
||||
| 跨平台支持 | ✔️ | ❌ (Windows) | ✔️ |
|
||||
| 脚本扩展 | ✔️ (Python) | ✔️ (C#) | ❌ |
|
||||
| 图形化界面 | ❌ (mitmweb 基础) | ✔️ | ✔️ |
|
||||
| 协议支持 | HTTP/1.1, HTTP/2 | HTTP/1.1 | HTTP/1.1, HTTP/2 |
|
||||
|
||||
### 常见问题
|
||||
**Q1:手机无法安装证书?**
|
||||
- 确保已关闭“证书透明性”监控(iOS 设置 → Safari → 高级)。
|
||||
- Android 7+ 需将证书安装到系统级(需 root)。
|
||||
|
||||
**Q2:抓包时出现 `TLS handshake failed`?**
|
||||
- 使用 `--ssl-insecure` 参数忽略证书错误。
|
||||
- 检查客户端是否信任 mitmproxy 的根证书。
|
@ -1,47 +0,0 @@
|
||||
---
|
||||
title: 《七律·和郭沫若同志》——毛泽东
|
||||
pubDatetime: 2025-03-08T20:00:00+08:00
|
||||
description: 毛泽东通过神话重构,将革命话语融入传统叙事,展现独特的政治诗学风格。
|
||||
slug: 七律-和郭沫若同志
|
||||
tags:
|
||||
- 诗歌
|
||||
---
|
||||
## 原文
|
||||
**《七律·和郭沫若同志》**
|
||||
一从大地起风雷,便有精生白骨堆。
|
||||
僧是愚氓犹可训,妖为鬼蜮必成灾。
|
||||
金猴奋起千钧棒,玉宇澄清万里埃。
|
||||
今日欢呼孙大圣,只缘妖雾又重来。
|
||||
|
||||
## 赏析
|
||||
|
||||
### 1. 历史背景与政治隐喻
|
||||
此诗作于1961年,是对郭沫若《看〈孙悟空三打白骨精〉》一诗的和作。时值国际共产主义运动分歧加剧(中苏论战),国内处于经济困难时期。毛泽东借《西游记》中孙悟空三打白骨精的典故,以寓言形式表达对阶级斗争的深刻思考。
|
||||
|
||||
**意象解析:**
|
||||
|
||||
• **"白骨堆"**:象征腐朽落后的反动势力,暗指国际修正主义及国内敌对力量。
|
||||
|
||||
• **"僧"(唐僧)**:指代思想动摇但可争取的中间派,体现"团结—批评—团结"策略。
|
||||
|
||||
• **"妖"(白骨精)**:喻指不可调和的阶级敌人,强调其破坏性本质。
|
||||
|
||||
• **"金猴"(孙悟空)**:无产阶级革命力量的化身,"千钧棒"象征革命武装斗争。
|
||||
|
||||
---
|
||||
|
||||
### 2. 艺术特色
|
||||
|
||||
• **革命浪漫主义**:将神话意象与政治现实结合,如"玉宇澄清"展现理想社会图景。
|
||||
|
||||
• **对比手法**:通过"僧"与"妖"的对比,强化敌我矛盾的不可调和性。
|
||||
|
||||
• **用典创新**:颠覆传统对唐僧的同情式解读,体现阶级分析视角。
|
||||
|
||||
---
|
||||
|
||||
### 3. 哲学内涵
|
||||
尾联"妖雾又重来"揭示斗争长期性,呼应"阶级斗争要年年讲,月月讲"的政治理念。诗中体现的"矛盾斗争推动历史发展"思想,是其辩证法哲学的诗意表达。
|
||||
|
||||
## 思想价值
|
||||
该诗以文艺形式阐述政治主张,体现毛泽东"古为今用"的文艺观。其核心思想——在复杂斗争中保持革命警惕性,对当代仍具启示意义。
|
@ -107,5 +107,3 @@ tags:
|
||||
30. [ ] 《命运之门》
|
||||
31. [ ] 《灯火阑珊》
|
||||
32. [ ] 《阿加莎·克里斯蒂自传》(历时15年完成)
|
||||
|
||||
---
|
||||
|
@ -18,115 +18,129 @@ const backUrl = SITE.showBackButton ? `${Astro.url.pathname}` : "/";
|
||||
</Layout>
|
||||
|
||||
<script>
|
||||
function initSearch() {
|
||||
const pageFindSearch: HTMLElement | null =
|
||||
document.querySelector("#pagefind-search");
|
||||
let searchInstance: any = null;
|
||||
|
||||
if (!pageFindSearch) return;
|
||||
function initSearch() {
|
||||
const pageFindSearch: HTMLElement | null =
|
||||
document.querySelector("#pagefind-search");
|
||||
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
if (!pageFindSearch) return;
|
||||
if (searchInstance) return;
|
||||
|
||||
const onIdle = window.requestIdleCallback || (cb => setTimeout(cb, 1));
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
|
||||
onIdle(async () => {
|
||||
// @ts-expect-error — Missing types for @pagefind/default-ui package.
|
||||
const { PagefindUI } = await import("@pagefind/default-ui");
|
||||
const onIdle = window.requestIdleCallback || (cb => setTimeout(cb, 1));
|
||||
|
||||
// Display warning inn dev mode
|
||||
if (import.meta.env.DEV) {
|
||||
pageFindSearch.innerHTML = `
|
||||
<div class="bg-muted/75 rounded p-4 space-y-4 mb-4">
|
||||
<p><strong>开发模式警告!</strong>在开发期间,您需要至少构建一次项目才能看到搜索结果。</p>
|
||||
<code class="block bg-black text-white px-2 py-1 rounded">pnpm run build</code>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
onIdle(async () => {
|
||||
// @ts-expect-error — Missing types for @pagefind/default-ui package.
|
||||
const { PagefindUI } = await import("@pagefind/default-ui");
|
||||
|
||||
// Init pagefind ui
|
||||
const search = new PagefindUI({
|
||||
element: "#pagefind-search",
|
||||
showSubResults: true,
|
||||
showImages: false,
|
||||
processTerm: function (term: string) {
|
||||
params.set("q", term); // Update the `q` parameter in the URL
|
||||
history.replaceState(history.state, "", "?" + params.toString()); // Push the new URL without reloading
|
||||
// Display warning inn dev mode
|
||||
if (import.meta.env.DEV) {
|
||||
pageFindSearch.innerHTML = `
|
||||
<div class="bg-muted/75 rounded p-4 space-y-4 mb-4">
|
||||
<p><strong>开发模式警告!</strong>在开发期间,您需要至少构建一次项目才能看到搜索结果。</p>
|
||||
<code class="block bg-black text-white px-2 py-1 rounded">pnpm run build</code>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
const backUrl = pageFindSearch?.dataset?.backurl;
|
||||
sessionStorage.setItem("backUrl", backUrl + "?" + params.toString());
|
||||
// Init pagefind ui
|
||||
searchInstance = new PagefindUI({
|
||||
element: "#pagefind-search",
|
||||
showSubResults: true,
|
||||
showImages: false,
|
||||
processTerm: function (term: string) {
|
||||
params.set("q", term); // Update the `q` parameter in the URL
|
||||
history.replaceState(history.state, "", "?" + params.toString()); // Push the new URL without reloading
|
||||
|
||||
return term;
|
||||
},
|
||||
});
|
||||
const backUrl = pageFindSearch?.dataset?.backurl;
|
||||
sessionStorage.setItem("backUrl", backUrl + "?" + params.toString());
|
||||
|
||||
// If search param exists (eg: search?q=astro), trigger search
|
||||
const query = params.get("q");
|
||||
if (query) {
|
||||
search.triggerSearch(query);
|
||||
}
|
||||
|
||||
// Reset search param if search input is cleared
|
||||
const searchInput = document.querySelector(".pagefind-ui__search-input");
|
||||
const clearButton = document.querySelector(".pagefind-ui__search-clear");
|
||||
searchInput?.addEventListener("input", resetSearchParam);
|
||||
clearButton?.addEventListener("click", resetSearchParam);
|
||||
|
||||
function resetSearchParam(e: Event) {
|
||||
if ((e.target as HTMLInputElement)?.value.trim() === "") {
|
||||
history.replaceState(history.state, "", window.location.pathname);
|
||||
}
|
||||
}
|
||||
return term;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("astro:after-swap", initSearch);
|
||||
initSearch();
|
||||
// If search param exists (eg: search?q=astro), trigger search
|
||||
const query = params.get("q");
|
||||
if (query) {
|
||||
searchInstance.triggerSearch(query);
|
||||
}
|
||||
|
||||
// Reset search param if search input is cleared
|
||||
const searchInput = document.querySelector(".pagefind-ui__search-input");
|
||||
const clearButton = document.querySelector(".pagefind-ui__search-clear");
|
||||
searchInput?.addEventListener("input", resetSearchParam);
|
||||
clearButton?.addEventListener("click", resetSearchParam);
|
||||
|
||||
function resetSearchParam(e: Event) {
|
||||
if ((e.target as HTMLInputElement)?.value.trim() === "") {
|
||||
history.replaceState(history.state, "", window.location.pathname);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cleanupSearch() {
|
||||
if (searchInstance) {
|
||||
searchInstance = null;
|
||||
const pageFindSearch = document.querySelector("#pagefind-search");
|
||||
if (pageFindSearch) {
|
||||
pageFindSearch.innerHTML = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("astro:before-swap", cleanupSearch);
|
||||
document.addEventListener("astro:after-swap", initSearch);
|
||||
initSearch();
|
||||
</script>
|
||||
|
||||
<style is:global>
|
||||
#pagefind-search {
|
||||
--pagefind-ui-font: var(--font-mono);
|
||||
--pagefind-ui-text: var(--foreground);
|
||||
--pagefind-ui-background: var(--background);
|
||||
--pagefind-ui-border: var(--border);
|
||||
--pagefind-ui-primary: var(--accent);
|
||||
--pagefind-ui-tag: var(--background);
|
||||
--pagefind-ui-border-radius: 0.375rem;
|
||||
--pagefind-ui-border-width: 1px;
|
||||
--pagefind-ui-image-border-radius: 8px;
|
||||
--pagefind-ui-image-box-ratio: 3 / 2;
|
||||
#pagefind-search {
|
||||
--pagefind-ui-font: var(--font-mono);
|
||||
--pagefind-ui-text: var(--foreground);
|
||||
--pagefind-ui-background: var(--background);
|
||||
--pagefind-ui-border: var(--border);
|
||||
--pagefind-ui-primary: var(--accent);
|
||||
--pagefind-ui-tag: var(--background);
|
||||
--pagefind-ui-border-radius: 0.375rem;
|
||||
--pagefind-ui-border-width: 1px;
|
||||
--pagefind-ui-image-border-radius: 8px;
|
||||
--pagefind-ui-image-box-ratio: 3 / 2;
|
||||
|
||||
form::before {
|
||||
background-color: var(--foreground);
|
||||
}
|
||||
|
||||
input {
|
||||
font-weight: 400;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
input:focus-visible {
|
||||
outline: 1px solid var(--accent);
|
||||
}
|
||||
|
||||
.pagefind-ui__result-title a {
|
||||
color: var(--accent);
|
||||
outline-offset: 1px;
|
||||
outline-color: var(--accent);
|
||||
}
|
||||
|
||||
.pagefind-ui__result-title a:focus-visible,
|
||||
.pagefind-ui__search-clear:focus-visible {
|
||||
text-decoration-line: none;
|
||||
outline-width: 2px;
|
||||
outline-style: dashed;
|
||||
}
|
||||
|
||||
.pagefind-ui__result:last-of-type {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.pagefind-ui__result-nested .pagefind-ui__result-link:before {
|
||||
font-family: system-ui;
|
||||
}
|
||||
form::before {
|
||||
background-color: var(--foreground);
|
||||
}
|
||||
</style>
|
||||
|
||||
input {
|
||||
font-weight: 400;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
input:focus-visible {
|
||||
outline: 1px solid var(--accent);
|
||||
}
|
||||
|
||||
.pagefind-ui__result-title a {
|
||||
color: var(--accent);
|
||||
outline-offset: 1px;
|
||||
outline-color: var(--accent);
|
||||
}
|
||||
|
||||
.pagefind-ui__result-title a:focus-visible,
|
||||
.pagefind-ui__search-clear:focus-visible {
|
||||
text-decoration-line: none;
|
||||
outline-width: 2px;
|
||||
outline-style: dashed;
|
||||
}
|
||||
|
||||
.pagefind-ui__result:last-of-type {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.pagefind-ui__result-nested .pagefind-ui__result-link:before {
|
||||
font-family: system-ui;
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
x
Reference in New Issue
Block a user