diff --git a/docs/README.md b/docs/README.md
index d007c81..463a033 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -6,6 +6,19 @@
- [solution.md](solution.md) — 最终方案:算法原理、API 用法、结果验证方法、10 样本结果与已知边界
- [experiments.md](experiments.md) — 实验演进记录(A→L):各方法失败原因、转折点实验、调试坑、无真值交叉验证方法
+- [retrospective.md](retrospective.md) — ★ 全项目复盘:四阶段演进、决定性发现、踩坑清单、方法论沉淀与未竟事项
+
+## 浏览器自动化经验(browser-automation/)
+
+一条经验一个文档,自动化操作中探索到的可复用经验:
+
+- [cdp-browser-use-basics.md](browser-automation/cdp-browser-use-basics.md) — CDP 9222 连接与 browser-use 基础 API、js() 顶层变量坑
+- [douyin-captcha-detection.md](browser-automation/douyin-captcha-detection.md) — 验证码 iframe 预加载机制与「已触发」的判定方法
+- [douyin-comment-input.md](browser-automation/douyin-comment-input.md) — 视频页评论框输入(DraftEditor 假 INPUT 坑、坐标点击、Ctrl+Enter 提交)
+- [douyin-captcha-trigger-attempts.md](browser-automation/douyin-captcha-trigger-attempts.md) — 触发验证码的早期尝试记录(无效方法清单)
+- [captcha-screenshot-capture.md](browser-automation/captcha-screenshot-capture.md) — wasm/GPU 渲染图片的 fromSurface=False 截图采集法(已被网络层法取代)
+- [human-drag-path.md](browser-automation/human-drag-path.md) — 拟人拖动路径生成算法(非直线/非匀速/过冲瞄准三要素)
+- **[captcha-auto-solve-pipeline.md](browser-automation/captcha-auto-solve-pipeline.md) — ★ 最新:密码登录触发法、网络层样本采集、tip_y 真值校准、自动闭环与 5014 行为风控现状**
## 快速开始
diff --git a/docs/browser-automation/captcha-auto-solve-pipeline.md b/docs/browser-automation/captcha-auto-solve-pipeline.md
new file mode 100644
index 0000000..c69d40f
--- /dev/null
+++ b/docs/browser-automation/captcha-auto-solve-pipeline.md
@@ -0,0 +1,102 @@
+# 经验:验证码自动通过闭环(采集→求解→拖动)与行为风控现状
+
+> 更新:2025-09-11 晚。此前 [captcha-screenshot-capture.md](captcha-screenshot-capture.md)
+> 与 [douyin-captcha-trigger-attempts.md](douyin-captcha-trigger-attempts.md) 的方法
+> 已被本篇取代/升级,本篇是当前最新状态。
+
+## 1. 可复现触发法(已验证,最可靠)
+
+**密码登录法**:主页点「登录」→ 弹窗点「密码登录」→ 手机号 `18601010101` +
+随机密码(如 `26969877Ab!`)→ 勾协议 → 点「登录」→ **拖动重叠验证码必弹**。
+(密码错误提示是预期的,验证码照样触发;真人手动拖可通过)
+
+## 2. 网络层样本采集(取代 DOM/截图法,`try/captcha_net_capture.py`)
+
+验证码图片不走 `
`(wasm 解码进 GPU 层),但**图片 URL 会正常发 HTTP 请求**:
+
+- `verify.zijieapi.com/captcha/get`(POST)→ 响应 JSON 含 `question.url1`(大图
+ 552×344 jpeg)、`url2`(mark 110×110 RGBA png)、**`tip_y`**
+- 图片托管在 `p3/p9-catpcha.byteimg.com`,直接是原始字节
+
+websocket 常驻监听(`Target.setAutoAttach` + Network 域 + `getResponseBody`)即可
+把原图字节落盘 —— **与 captchas/ 离线样本完全同规格,无需缩放**,solve 直接可用。
+
+## 3. tip_y 服务端提示(重大发现)
+
+`tip_y × 2 = 缺口 y 坐标(mark 画布顶,原图 552×344 坐标系)`。
+10 组线上样本校准:solver 无约束 y 与 `2×tip_y` 差 ≤4px 的样本全部位置判定正确;
+偏差大的(如 Δy=17)正是被服务端判 `VerifyErr` 的。
+
+**`try/live_solve.py`**:用 tip_y 约束 y,在 score map 上重选 x —— 服务端等于
+免费下发了 y 真值,只需求 x。
+
+## 4. 拖动闭环(`try/auto_solve_drag.py`)
+
+CDP websocket 直连全流程(不依赖 browser-use CLI):点刷新 → 轮询 get.json 落盘
+→ live_solve → `human_drag.gen_human_path` 拟人路径 → `Input.dispatchMouseEvent`
+拖滑块 → 读 verify 结果。**get→verify 全程 <8s**(challenge 有效期约 60-90s,
+超时会 `NotFoundChallengeId`)。
+
+实测确认:
+
+- 滑块拖动 1:1 映射 mark 位移(拖 100px → mark 移 100px)
+- 拖动距离 = solver x × 340/552(UI 缩放)
+- 服务端响应三种:`验证通过` / `VerifyErr`(轨迹过、位置差)/ `5014 操作过快`(轨迹被拒)
+
+## 5. 剩余 gap:5014 行为判定(未解决)
+
+VerifyErr 与 5014 交替出现 = 位置与轨迹都接近临界。真人可过而脚本被 5014 拒,
+原因在 `captchaBody`(~6.3KB 加密轨迹密文,含 w2/x86 设备指纹):
+
+- 轨迹明文由 SDK wasm 加密,离线解不开
+- 我的拟人路径(贝塞尔+噪声+过冲回拉)仍被判机器 —— SDK 采集的不止鼠标点,
+ 可能含 pointermove 原生事件流、movementX、事件时间戳分布、设备指纹等
+- **下一阶段方向**:hook SDK 内部轨迹采集函数(wasm 前的 JS 层),直接注入
+ 自定义轨迹数组,让 SDK 自己加密上报;或对比真人 captchaBody 字节结构定位
+ 采集字段
+
+## 6. 文件清单
+
+| 文件 | 用途 |
+| --- | --- |
+| `try/captcha_net_capture.py` | 网络层常驻监听,抓 get/verify 响应 + 图片字节 |
+| `try/captcha_verify_watch.py` | 专抓 verify 请求 POST 全文(captchaBody 对比用) |
+| `try/live_solve.py` | tip_y 约束版求解(线上样本专用) |
+| `try/human_drag.py` | 拟人拖动路径生成器 |
+| `try/auto_solve_drag.py` | 一条龙闭环(刷新→solve→拖→读结果) |
+| `try/captures/pair_*` | 已采集线上样本对(17 组) |
+
+## 7. 后续实验结论(2026-05-15/16,xdotool 硬件输入 + 换号循环)
+
+上述"下一阶段方向"已被系统性实验否定——**输入层不是根因**:
+
+- **xdotool(OS 级 XTest 硬件鼠标)** 拖 solve 位置 → 仍 VerifyErr;
+ 事件属性(pressure/movementX/coalesced/isTrusted)与真人无差异;
+- **真人轨迹重放**(human_trace_pass.json,含 20-266ms 抖动间隔、4px y 振幅、
+ 0.7s 终点停顿)→ 仍 VerifyErr;
+- **会话预热**(触发前 45-75s 页面游走)→ 不改变结果;
+- 真人 PASS 与机器拖的差异只剩「**行为分窗口**」(5014 = 窗口内累计失败,
+ 真人 PASS 夹在机器失败之间仍能过)与「**位置小偏差**」(±10px 级,视觉确证
+ live_191109 solve 正确但 live_135654 贴片在 solve 块内略偏)。
+
+### 触发与限流工程结论
+
+- **触发限流(不出题)**:清 cookie 即解除(`Network.clearBrowserCookies` +
+ `Page.navigate` 回 douyin)——用户实测确认,无需等待;
+- **触发拒绝误报**:错误检测正则勿包含"验证码登录"(tab 文字本身);
+ 真正的号段拒绝文案是"仅支持验证码登录";
+- **reload 坑**:清 cookie 后 session 失效,`Page.reload` 会把页面带到
+ 空标签/跳转页,必须用 `Page.navigate` 显式回 douyin;
+- **challenge 时效**:约 1 分钟,采题后的任何预热/等待都会耗死题
+ (NotFoundChallengeId)——预热必须放在**触发之前**;
+- **拖动时长保真**:重放轨迹时 up 前最后一步的 dt(真人 ≈0.7s 终点对齐)
+ 不能丢,否则 2.6s 被压成 1.9s;跳过 0 位移步时 `t_plan` 仍要累加。
+
+### 文件
+
+| 文件 | 用途 |
+| --- | --- |
+| `try/rotate_loop.py` | 清 cookie + 换号零等待循环(风控即换号) |
+| `try/cold_start_attempt.py` | 单次完整尝试(预热/采题/选优/xdotool 拖动) |
+| `try/enrich_replay.py` | 重放轨迹 60Hz 加密(实验结论:勿用,真人事件流稀疏) |
+| `try/human_trace_pass.json` | 真人 PASS 轨迹(live_165204,2.60s/17 move) |
diff --git a/docs/browser-automation/captcha-screenshot-capture.md b/docs/browser-automation/captcha-screenshot-capture.md
new file mode 100644
index 0000000..58c2262
--- /dev/null
+++ b/docs/browser-automation/captcha-screenshot-capture.md
@@ -0,0 +1,70 @@
+# 经验:拖动验证码页面截图采集(CDP)
+
+> 场景:验证码图片渲染在 wasm/GPU 层(`img` 元素 `naturalWidth=0`、canvas 0×0、
+> src 是占位 URL),常规 DOM/canvas 提取拿不到真实位图;用户手动右键「另存为」可以。
+
+## 为什么 DOM 方式全失败
+
+抖音 rmc-captcha 的图片不走标准 `
`:
+
+| 尝试 | 结果 |
+| --- | --- |
+| `img.src` / `currentSrc` | 是 iframe 页面自身 URL(占位),fetch 回 HTML |
+| `img.naturalWidth` | 0(图片数据从未进入 img 元素解码管线) |
+| `canvas.toDataURL()`(drawImage 复制) | canvas 未污染但输出**全黑透明**(RGBA 全 0) |
+| CSS `background-image`(元素/伪元素/父链/shadow DOM) | 全部 `none` |
+| `Network.getResponseBody` 抓 `verify.zijieapi.com/captcha/get` | 响应体是图片字节但**无法与 DOM 对齐**;手动 GET 重放会 501 参数错误 |
+| `Page.captureScreenshot`(默认 `fromSurface=true`) | iframe 区域**空白**——wasm/GPU 合成层不进该截图通道 |
+
+结论:图片由 wasm 解码后直接进 GPU 合成层,DOM 与 JS 均不可见。
+
+## 正解:`fromSurface=False` 全屏截图 + Python 裁剪
+
+```python
+r = cdp("Page.captureScreenshot", format="png",
+ captureBeyondViewport=False, fromSurface=False) # 关键参数
+open("/tmp/full.png", "wb").write(base64.b64decode(r["data"]))
+```
+
+要点:
+
+1. **`fromSurface=False`** 走非合成层通道,能拿到真实像素(经实测验证:
+ 同一区域 `fromSurface=True` 灰板、`False` 有图)。
+2. **clip 参数会被忽略**(`fromSurface=False` 时返回全屏 1920×993),需 Python 裁剪。
+3. 裁剪坐标 = iframe 视口位置 + iframe 内元素位置:
+ - iframe 在视口 `(770, 305)`,大小 380×384
+ - 大图在 iframe 内 `(20, 69)`,340×212 → 视口裁剪 `[374:586, 790:1130]`
+ - mark(未拖动时)与大图同起点,68×68 → 视口裁剪 `[374:442, 790:858]`
+4. 先在 iframe 内用 `Runtime.evaluate` 取元素 `getBoundingClientRect()`
+ (attach iframe target 后,坐标系是 iframe 内部坐标系,注意换算)。
+
+## 验证码 iframe 布局(v2,380×384)
+
+```
+iframe (770,305) 380x384
+├─ close-btn (326,0) 54x54 右上角关闭
+├─ 标题栏 .captcha-bar (20,12) 340x69 「请将左侧图形拖到正确位置」
+├─ 大图 .verify-image (20,69) 340x212 大图区域
+│ └─ mark(初始态) (20,69) 68x68 与大图同起点(未拖动时)
+├─ 滑条 .captcha-slider(20,293) 340x44 底部滑轨+拖钮
+└─ 刷新/反馈 (20,345) 页脚操作行
+```
+
+## mark 图的坑(RGB 采集)
+
+截图裁出的 mark 是**带灰底**的(页面背景 246,245,244),与离线样本
+(PNG 透明底 + alpha 轮廓)不同。喂给 solve 前需转 RGBA:
+
+```python
+mark = cv2.imread(mark_crop_path)
+bg = np.array([246, 245, 244])
+diff = np.abs(mark.astype(int) - bg).sum(axis=2)
+alpha = np.clip(diff * 3, 0, 255).astype(np.uint8)
+rgba = cv2.merge([mark[:, :, 0], mark[:, :, 1], mark[:, :, 2], alpha])
+```
+
+## 尺寸缩放(原图 vs UI 显示)
+
+离线样本:大图 552×344、mark 110×110(RGBA)。
+线上 UI:大图 340×212、mark 68×68,缩放系数 ≈ **0.616**(340/552)。
+solve 的 `distance_px` 是原图坐标系,执行拖动时乘以缩放系数换算成 UI 像素。
diff --git a/docs/browser-automation/cdp-browser-use-basics.md b/docs/browser-automation/cdp-browser-use-basics.md
new file mode 100644
index 0000000..646d23a
--- /dev/null
+++ b/docs/browser-automation/cdp-browser-use-basics.md
@@ -0,0 +1,57 @@
+# 经验:CDP 9222 连接与 browser-use 基础操作
+
+> 场景:需要对用户已登录的真实 Chrome(远程调试端口 9222)做自动化操作。
+
+## 连接检查
+
+```bash
+curl -s http://127.0.0.1:9222/json/version # 通了即可用
+curl -s http://127.0.0.1:9222/json # 列出页面 target
+```
+
+## browser-use 调用模式
+
+CLI 名为 `browser-use`,用 heredoc 传 Python 代码,helpers 已预导入:
+
+```bash
+browser-use <<'PY'
+for t in list_tabs(): # 列出所有页面 tab
+ print(t["targetId"], t["url"][:80])
+PY
+```
+
+## 关键 API
+
+| API | 用途 |
+| --- | --- |
+| `list_tabs()` | 列出页面 tab,返回完整 targetId |
+| `switch_tab(targetId)` | attach 到指定 tab(不改变 Chrome 可见 tab);**必须传完整 targetId**,8 位前缀会报 `No target with given id found` |
+| `activate_tab(targetId)` | 把 tab 切到前台(用户可见) |
+| `js(expression)` | 在当前页面执行 JS,自动 await Promise |
+| `capture_screenshot(path)` | 截图保存到本地文件 |
+| `click_at_xy(x, y)` | 视口坐标点击(CDP 鼠标事件,穿透 iframe/shadow DOM) |
+| `cdp("Domain.method", ...)` | 任意 CDP 协议调用 |
+| `wait_for_load(15)` | 等待导航完成 |
+
+## 坑:js() 顶层 let/const 会跨调用残留
+
+`Runtime.evaluate` 在页面全局作用域执行,顶层 `let out = []` 会留下全局词法绑定,
+下次调用再写 `let out` 直接 `SyntaxError: Identifier 'out' has already been declared`。
+
+**解法:所有多行 JS 一律包 IIFE:**
+
+```python
+r = js("""
+(() => {
+ let out = [];
+ ...
+ return out.join('\\n');
+})()
+""")
+```
+
+## 注意
+
+- 每个 `browser-use <<'PY'` 是独立 Python 进程,Python 变量不跨调用保留;
+ 页面状态(DOM、JS 全局变量)跨调用保留。
+- CDP target 顺序 ≠ Chrome 可见 tab 标签页顺序,用 `list_tabs()` 认 URL。
diff --git a/docs/browser-automation/cdp-drag-force-pressure.md b/docs/browser-automation/cdp-drag-force-pressure.md
new file mode 100644
index 0000000..7322c1d
--- /dev/null
+++ b/docs/browser-automation/cdp-drag-force-pressure.md
@@ -0,0 +1,140 @@
+# CDP 拖动与行为风控实验记录(force/pressure 发现)
+
+时间:2026-05-15(连线实验,Chrome CDP 9222 + douyin.com 登录触发验证码)
+
+## 实验环境
+
+- 验证码 iframe:`rmc.bytedance.com/verifycenter/captcha/v2`,380x384,视口坐标 (770,305)
+- 滑块按钮初始中心:iframe 坐标 (54,307);刷新按钮 (30,355)
+- 大图 UI:`.captcha-verify-image` (20,69) 340x212(对应原图 552x344,SCALE=340/552=0.616)
+- mark 预览:`.captcha-verify-image-slide` 68x68(= 110x110 × 0.618)
+
+## 核心发现 1:CDP 缺省 pressure=0 是硬指纹
+
+CDP `Input.dispatchMouseEvent` 不带 `force` 参数时,产生的 MouseEvent 均无
+pressure(DOM 事件里 `event.pressure === 0`)。按 W3C UI Events 规范,
+真实鼠标按下/拖动时 pressure 应为 **0.5**(鼠标无压感设备时恒 0.5)。
+
+SDK(captcha.js / webmssdk)采集的事件流含 pressure,可据此判自动化。
+
+**修复**:`mousePressed` / `mouseMoved` / `mouseReleased` 全部加 `force: 0.5`,
+实测 DOM `event.pressure` 变为 0.5 ✓(主页与 iframe 内均验证)。
+
+## 核心发现 2:错误码语义分层(多次连线实验归纳)
+
+| 错误码 | message | 语义 |
+| -------- | --------- | ------ |
+| 500 VerifyErr | 验证失败,请根据提示重新操作 | 行为闸门已过,**位置判定失败**(或轨迹分不足) |
+| 502 [5014] | 操作过快,请慢一点 | 行为判定拒(轨迹过快/异常),位置未判 |
+| 502 [5009] | 验证过于频繁,请稍后重试 | **频控**:短时间连环尝试后触发,冷却数分钟恢复 |
+| 502 NotFoundChallengeId | 验证超时 | challenge 过期(采题后拖延太久) |
+
+关键实验:
+
+1. `force` 缺省(=0)时全部 5014;
+2. `force=0.5` 后出现过 VerifyErr(行为关过了、位置判了)——说明 pressure
+ 至少是 5014 的成因之一;
+3. 连环快速尝试(数十次/小时)后一律 5009 频控——5014 与 5009 会互相掩盖,
+ 判定"位置对错"必须在频控冷却后做单次干净尝试;
+4. AMBIGUOUS 候选(solve 置信度低)的题拖了必 VerifyErr;OK 候选的题
+ (当时还没判到位置层)也被 5014/5009 拦住,位置正确性尚未闭环确认。
+
+## 核心发现 3:拖动映射与 mark 预览行为
+
+- 按钮 1:1 带动 mark 预览(按钮 +60px → mark UI +60px,实测);
+- mark 初始相对大图 rel=(0, tip_y*2)(原图坐标)——**每题垂直位置自动对齐**
+ (mark 预览 img 的 y 每题不同,实测 rel_y×(552/340) ≈ tip_y*2);
+- 拖动距离 = `solve.x × 340/552`(UI px);
+- 拖动失败/失败重开后 mark 预览复位到 rel x=0;
+- 验证成功后 iframe 自毁(`/json/list` 里 rmc iframe 消失)。
+
+## 核心发现 4:iframe 内 XHR hook 采题(不依赖 netcap)
+
+netcap(Network 域抓包)attach 时机不稳。更可靠的做法:attach iframe 后在
+页面上下文注入 XHR hook,把 `captcha/get`、`captcha/verify` 的响应存到
+`window.__lastGet` / `__lastVerify`,CDP 轮询读取:
+
+```js
+XMLHttpRequest.prototype.open = function(m,u){ this.__u=u; return oOpen.apply(this,arguments); };
+XMLHttpRequest.prototype.send = function(){
+ this.addEventListener('load', () => {
+ if (/captcha\/get/.test(this.__u||'')) window.__lastGet = JSON.parse(this.responseText);
+ if (/captcha\/verify/.test(this.__u||'')) window.__lastVerify = this.responseText;
+ });
+ return oSend.apply(this, arguments);
+};
+```
+
+题目图片可直接 `urllib` 下载 `question.url1/url2`(无需解码密文)。
+注意:hook 必须在拖动前注入;点击"刷新"产生新 get 不重建 iframe,hook 仍有效。
+
+## 线上题 vs 离线样本的差异(solve 风险)
+
+- 离线 17 组样本(captchas/):洞为**暗色覆盖物**,方法 L 分数 1-3,全部命中;
+- 线上 URL 下载的题:覆盖物为**亮白半透明花瓣**贴片,方法 L 分数 3.6-7.7,
+ 明显变差;部分题最佳候选 scale≠1.0(0.85-1.075),会出现 AMBIGUOUS;
+- `tip_y*2`(原图缺口顶 y)与 solve.y 交叉验证:OK 且分数低的题两者一致
+ (如 solve y=190 vs tip_y*2=192 ✓);solve 跑飞时两者差得远(可当否决器)。
+
+## 后续验证结果(同日)
+
+1. **位置判定已确认可达**:频控冷却后单次 force=0.5 拖动稳定得到 VerifyErr
+ (位置层判定被执行),5014 不再出现 —— pressure 修复对行为闸门有效。
+2. **hover 序列确认毒化拖动**:按下前发 `button:"left"+buttons:0` 的
+ mouseMoved 会导致 verify 根本不发出。修正:无按键时用 `button:"none"`。
+3. **solve 已增强**:`solve(..., tip_y=...)` 用服务端缺口顶 y 真值锚定候选,
+ 离线 10/10 不回归,线上 8 题 7 中(详见 solution.md「线上增强」节)。
+4. **频控仍是拦路虎**:单 IP 连环尝试后 5009 窗口 >20 分钟,仅靠冷却
+ 很难完成多次位置闭环判定。后续应换环境(新 IP/无痕 profile)做
+ 「冷启动 → 单次拖动」实验,验证 tip_y 锚定后的 solve 能否一次通过。
+5. `try/solo_attempt.py`:单次干净尝试脚本(冷却→采题→solve→拖→读 verify),
+ 供冷启动实验复用。
+
+## 决定性对照实验(2026-05-15 补充,推翻旧归因)
+
+| 实验 | 账号 | 操作者 | 结果 |
+| --- | --- | --- | --- |
+| 多次 CDP 拖动 | 老账号(已被限制 1467) | 脚本 | 5014 / VerifyErr / 5009 混杂 |
+| 真人手拖 ×3 | 同上老账号 | 人 | **超时 / 拖动过快 / 网络环境差,全失败** |
+| 真人手拖 ×1 | **新账号** | 人 | **验证通过,iframe 自毁** |
+
+结论修正:
+
+1. **老账号被风控标记后连真人都过不了** —— 之前「真人可过、CDP 必败」
+ 的对照不成立,5014/VerifyErr 的主因是账号级标记(可能叠加 IP 维度),
+ CDP pressure=0 只是叠加因素之一;
+2. 「网络环境差」「操作过快」「验证超时」是账号/环境被标记后的三种表象,
+ 与拖动质量无关(真人正常手拖也被拒);
+3. **后续所有行为/位置判定实验必须在「干净账号 + 未标记环境」上做**,
+ 否则结果无法归因。此前在本机老账号上积累的 5014 样本全部存疑;
+4. CDP 自动化在干净账号上的真实通过率尚未测得(下一步实验)。
+
+## 拖动时长实验(2026-05-15 下午)
+
+把 `gen_human_path` 缺省总时长从 0.6-1.4s 拉到 **5-10s 随机**(用户要求,真人拖动
+观测 ~4-8s)后连续测试:
+
+| # | 场景 | 拖动时长 | 结果 |
+| --- | --- | --- | --- |
+| 3 | 干净账号第 2 连拖 | ~6.5s | 5014 操作过快 |
+| 4 | reload 后第 3 连拖 | ~6s | 5014 操作过快 |
+
+结论:
+
+1. **5014「操作过快」与拖动速度无关** —— 6s 的慢拖同样被判过快;该文案是
+ 行为分累积到阈值后的固定话术;
+2. 行为分按 **账号+设备指纹** 累积(跨 challenge、跨页面 reload 不清零),
+ 连续 CDP 拖动 2-3 次即触发;真人首次通过 = 行为分从 0 开始;
+3. 第 1 拖(干净行为分)拿到的是 VerifyErr 而非 5014 —— 此时位置判定真正
+ 执行了,但位置仍被判错(solve 经 IoU 亚像素验证 ±1px、SDK 实际位移与
+ 期望一致)→ **位置无误仍 VerifyErr 指向 verify 通道的其它指纹**
+ (captchaBody 密文内的轨迹编码 / detail 参数),而非坐标映射;
+4. 接口限流:随机号触发验证码的 get 接口也有频控(「系统繁忙」),触发
+ 同样要冷却。
+
+后续方向(按性价比排序):
+
+- 在干净环境(新 profile/IP,行为分 0)做**单次** CDP 拖动:若 VerifyErr
+ 消失 → 之前所有 VerifyErr 均为行为分污染,位置判定本来就对;
+- 对比真人通过样本与 CDP 样本的 captchaBody 长度/结构(轨迹编码密度);
+- hook SDK 轨迹采集函数,直接注入受控轨迹(绕开 CDP 事件指纹)。
diff --git a/docs/browser-automation/douyin-captcha-detection.md b/docs/browser-automation/douyin-captcha-detection.md
new file mode 100644
index 0000000..75e6731
--- /dev/null
+++ b/docs/browser-automation/douyin-captcha-detection.md
@@ -0,0 +1,60 @@
+# 经验:抖音验证码出现的检测方法
+
+> 场景:自动化操作中需要知道「拖动重叠验证码」什么时候弹出来。
+
+## 检测选择器
+
+```python
+r = js("""
+(() => {
+ const f = document.querySelector('iframe[src*="captcha"], iframe[id*="captcha"]');
+ if (!f) return 'no-iframe';
+ return 'visible=' + (f.offsetParent !== null) + ' w=' + f.offsetWidth + ' h=' + f.offsetHeight;
+})()
+""")
+```
+
+## 关键事实
+
+- 抖音在页面加载时就会**预加载验证码 iframe**(字节 rmc-nocaptcha,无感验证框架),
+ 默认 `display:none, w=0 h=0`。**iframe 存在 ≠ 验证码触发**。
+- 判定触发看可见性:`f.offsetParent !== null` 或 `f.offsetWidth > 0`。
+- iframe src 特征:`https://lf-rc1.yhgfb-cn-static.com/obj/rc-verifycenter/rmc-nocaptcha/.../index.html`
+ (rc-verifycenter = 字节验证中心)。
+
+## 辅助手段
+
+**1. 查页面加载过的验证码相关资源**(判断风控 SDK 是否激活):
+
+```python
+js("""
+(() => performance.getEntriesByType('resource')
+ .map(e => e.name)
+ .filter(u => /captcha|verify|rc-verify|secsdk/i.test(u))
+ .slice(0, 20).join('\\n'))()
+""")
+```
+
+出现 `rc-verifycenter/sec_sdk_build/.../captcha/index.js`、`rmc-nocaptcha/.../setup.js`
+说明验证码 SDK 已就绪,等待触发条件。
+
+**2. MutationObserver 监听验证码 DOM 出现**(挂在页面里,外部轮询读结果):
+
+```python
+js("""
+(() => {
+ window.__captchaSeen = [];
+ new MutationObserver(muts => {
+ for (const m of muts) for (const n of m.addedNodes) {
+ if (n.nodeType !== 1) continue;
+ const s = (n.tagName + ' ' + (n.className||'') + ' ' + (n.id||'')).toString();
+ if (/captcha|verify|secsdk/i.test(s)) window.__captchaSeen.push('add: ' + s.slice(0,100));
+ }
+ }).observe(document.body, {childList: true, subtree: true});
+ return 'ok';
+})()
+""")
+```
+
+**3. 拖动验证码本体在 iframe 内部**,需要 attach 到 iframe target 或在 iframe 内执行 JS
+才能抓到 552×344 大图与 110×110 mark 图。
diff --git a/docs/browser-automation/douyin-captcha-trigger-attempts.md b/docs/browser-automation/douyin-captcha-trigger-attempts.md
new file mode 100644
index 0000000..1a9428e
--- /dev/null
+++ b/docs/browser-automation/douyin-captcha-trigger-attempts.md
@@ -0,0 +1,38 @@
+# 经验:触发抖音拖动验证码的尝试记录(截至 2025-XX 未成功)
+
+> 场景:为采集验证码样本,需要主动触发「拖动重叠」验证码。
+> 本文档记录已尝试且**无效**的方法,避免重复试错。
+
+## 环境
+
+- Chrome 148,已登录账号(cookie 正常,avatar/登录态正常)
+- 验证码 SDK(rc-verifycenter / rmc-nocaptcha)已在页面预加载但未触发
+
+## 已尝试且未触发验证码的操作
+
+| # | 操作 | 结果 |
+| --- | --- | --- |
+| 1 | 用户主页连续 reload ×4(间隔 ~5s) | 无验证码 |
+| 2 | 搜索页连续换关键词导航 ×4(cat/dog/street photography/travel) | 无验证码 |
+| 3 | 打开视频 modal + 视频详情页 | 无验证码 |
+| 4 | `creator.douyin.com` 创作者首页 / 内容上传页 | 无验证码(首次访问 creator 域曾被弹回 www 主站) |
+| 5 | 视频页评论框输入「你好」+ Ctrl+Enter 提交 | **评论直接发布成功**,无验证码 |
+
+## 观察
+
+- 验证码 iframe(rmc-nocaptcha)始终预加载但 `display:none`,未弹出。
+- 请求 URL 中已带 `verifyFp` / `fp` 参数,风控指纹已建立,但行为分未到触发阈值。
+- 单纯的页面导航 + 一次评论不构成风控触发条件。
+
+## 下一步待尝试(按性价比排序)
+
+1. **高频点赞/取消点赞**(行为风控最常见触发器)
+2. **高频关注/取关**
+3. 短时间连续发多条评论
+4. 快速滚动视频 feed + 快速翻页
+5. 私信/敏感账号设置操作
+6. 无 cookie 的干净环境访问(风控分数从零开始,更容易触发)
+
+## 通用检测代码
+
+见 [douyin-captcha-detection.md](douyin-captcha-detection.md)。
diff --git a/docs/browser-automation/douyin-comment-input.md b/docs/browser-automation/douyin-comment-input.md
new file mode 100644
index 0000000..d5b0ac2
--- /dev/null
+++ b/docs/browser-automation/douyin-comment-input.md
@@ -0,0 +1,46 @@
+# 经验:抖音视频页评论框输入(DraftEditor 的坑)
+
+> 场景:通过 CDP 在抖音视频页评论框输入文字并提交。
+
+## 坑
+
+1. **容器里有假 INPUT**:`.comment-input-inner-container` 内有一个 `INPUT` 元素,
+ focus 它无效(`document.activeElement` 仍是 BODY),insertText 也进不去。
+ 真正的编辑器是 Draft.js:`div[contenteditable="true"].notranslate.public-DraftEditor-content`。
+2. **输入框可能在视口外**:直接取 rect 可能 y 为负或超视口,坐标点击会点空
+ (activeElement 变 BODY)。
+3. **没有可见的「发布」按钮**,提交用 Ctrl+Enter。
+
+## 正确步骤
+
+```python
+# 1. 滚动到可见
+js("document.querySelector('.comment-input-inner-container').scrollIntoView({block:'center'})")
+
+# 2. 取新坐标并点击
+box = js("""
+(() => { const r = document.querySelector('.comment-input-inner-container').getBoundingClientRect();
+ return JSON.stringify({x: Math.round(r.x+r.width/2), y: Math.round(r.y+r.height/2)}); })()
+""")
+pos = json.loads(box)
+click_at_xy(pos["x"], pos["y"])
+
+# 3. 确认焦点在 DraftEditor(div.notranslate.public-DraftEditor-content)后插入文字
+cdp("Input.insertText", text="评论内容")
+
+# 4. Ctrl+Enter 提交
+cdp("Input.dispatchKeyEvent", type="keyDown", modifiers=2, key="Enter",
+ code="Enter", windowsVirtualKeyCode=13, nativeVirtualKeyCode=13)
+cdp("Input.dispatchKeyEvent", type="keyUp", modifiers=2, key="Enter",
+ code="Enter", windowsVirtualKeyCode=13, nativeVirtualKeyCode=13)
+```
+
+## 验证
+
+- 焦点成功:`document.activeElement.className` 含 `notranslate public-DraftEditor-content`。
+- 输入成功:容器 `textContent` 变为输入内容(placeholder 消失)。
+
+## 注意
+
+发评论是**真实写操作**(会真的发出去),触发验证码失败时评论会直接发布成功——
+操作前确认账号允许发测试评论,或事后手动删除。
diff --git a/docs/browser-automation/human-drag-path.md b/docs/browser-automation/human-drag-path.md
new file mode 100644
index 0000000..6f94fdb
--- /dev/null
+++ b/docs/browser-automation/human-drag-path.md
@@ -0,0 +1,74 @@
+# 经验:拟人拖动路径生成算法(反检测三要素)
+
+> 场景:验证码行为风控会检测拖动轨迹的「机器特征」。人手拖动的轨迹与
+> CDP `Input.dispatchMouseEvent` 生成的匀速直线完全不同。
+> 代码:`try/human_drag.py`(`gen_human_path(distance_px)` → 增量事件序列)。
+
+## 三要素(用户需求 → 实现机制)
+
+### 1. 不能是直线 → 贝塞尔弓形骨架 + 高斯抖动
+
+```
+主冲程路径 = 三次贝塞尔 P0(0,0) → P3(过冲点)
+ P1/P2 控制点带 y 轴弓形偏移(±8~14px,随机方向)
+每步叠加 = gauss 抖动(x: σ≈0.8, y: σ≈1.1)
+抖动幅值随速度变化:中段速度快 → 手更不稳(σ 放大)
+```
+
+弓形是关键:不是噪声围绕着直线,而是整体轨迹带自然弧度(人手腕转动)。
+y 轴全程摆动 ±5px 左右,终点收敛回 0。
+
+### 2. 不能匀速 → 三段速度结构
+
+```
+主冲程 (55-70% 时长):ease-in-out(加速→巡航→减速),14-22ms/步
+回拉 (15-22% 时长):ease-out 快速回退
+微调 (剩余时长) :步长递减的小步逼近 + 末尾 40-120ms 停顿确认
+```
+
+速度统计上呈「快-慢-停」节奏,`v_max ≈ 0.5-0.95 px/ms`、`v_min ≈ 0.001`
+(慢两个数量级),与匀速(速度方差≈0)完全可区分。
+
+### 3. 不能一次到位 → 过冲-回拉-瞄准
+
+```
+阶段1 主冲程 → 目标 + 过冲量(3~9px 随机)
+阶段2 回拉 → 目标 - 欠量(0.5~2.5px)
+阶段3 微调 → 1~2 小步逼近精确目标,每步 15ms+
+```
+
+人类视觉反馈回路的标配:先冲过头,再修正。位移曲线 x-t 上
+可见明显的「超过目标 → 拉回 → 精确落点」三段形态。
+
+## 用法
+
+```python
+from human_drag import gen_human_path, path_stats
+
+pts = gen_human_path(distance_px=227.9, seed=42) # seed 可复现
+# pts = [(dx, dy, dt_ms), ...] 相对上一点增量
+for dx, dy, dt in pts:
+ cur_x += dx; cur_y += dy
+ cdp("Input.dispatchMouseEvent", type="mouseMoved", x=cur_x, y=cur_y,
+ button="left", buttons=1)
+ time.sleep(dt / 1000)
+```
+
+拖动距离换算:solve 的 `distance_px` 是原图(552 宽)坐标,
+乘缩放系数 `UI宽/552`(如 340/552≈0.616)得 UI 像素。
+
+## 自检(已内置)
+
+`python try/human_drag.py` 断言五项:终点精确(<0.5px)、时长 0.4-2.5s、
+速度起伏(vmax > vmin×5)、y 摆动(>2px)、存在回拉(x 序列非单调)。
+10 样本联合烟测(solve → 换算 → 路径)全通过。
+
+可视化:`python try/human_drag.py --plot` →
+`src/out/human_drag_path.png`(三种距离的轨迹)、`src/out/human_drag_xt.png`(x-t 曲线)。
+
+## 可调参数(按需)
+
+- 短距离(<100px):弓形幅值降到 ±8、过冲 ×0.3(小拖距人不甩)
+- `duration`:默认按距离自估算 0.6-1.4s;拖钮场景可传 `duration=800` 固定
+- 未做:轨迹级鼠标事件 hook 采集真人样本对拍(当前参数为文献常识值,
+ 如需过高级风控,用 CDP 录制 10 条真人轨迹做分布拟合替换)
diff --git a/docs/experiments.md b/docs/experiments.md
index 1282f1a..b19acb3 100644
--- a/docs/experiments.md
+++ b/docs/experiments.md
@@ -83,3 +83,220 @@
(41ac:88×106 vs 88×106);
3. 全部候选可视化后人工目检:真目标应落在几何图形上而非纹理上;
4. 结果叠加轮廓回贴大图(`src/verify_result.py`),观察贴合精度。
+
+## 线上闭环实验(2026-05-15,CDP 连线)
+
+搭了「hook 采题 → solve → CDP 拖动 → 读 verify」全自动闭环后,暴露出离线
+评估覆盖不到的三层问题:
+
+1. **CDP pressure 指纹**:不带 `force` 的鼠标事件 pressure=0(真鼠标恒 0.5),
+ 行为风控 5014 的高危成因。加 `force:0.5` 后错误码从 5014 变为 VerifyErr
+ (位置层),证明 pressure 是被采集的判别特征(详见
+ browser-automation/cdp-drag-force-pressure.md)。
+2. **错误码分层**:5014(行为拒)→ VerifyErr(位置判了但错)→ 5009
+ (频控,压住一切)→ NotFoundChallengeId(challenge 过期)。判定任何
+ 改动的效果都必须在频控冷却后单次干净尝试,连环重试的 5014/5009
+ 是无效信号。
+3. **线上题分布漂移**:URL 下载的线上题覆盖物是亮白半透明贴片(离线样本
+ 是暗色洞),方法 L 分数从 1-3 恶化到 3.6-7.7,且出现 scale 偏移
+ (0.85-1.075)与 AMBIGUOUS。翻转 dark_pen 的 bright 模式更差(7+),
+ 说明亮贴片信号弱,尚无可靠增强。
+
+交叉验证手段新增:**tip_y 一致性检查**——服务端 `question.tip_y*2` 应等于
+solve.y(mark 画布顶 y),两者差得远说明 solve 跑飞,可直接否决该题。
+
+其它工程教训:
+
+- hover 序列里 `buttons` 与 `button` 状态矛盾(buttons=0 但 button="left")
+ 会毒化 SDK 拖动注册,verify 根本不发出——按下前保持 button:"none"+buttons:0,
+ 拖动中 buttons:1,释放后恢复;
+- 每轮点刷新不重建 iframe,iframe 内 XHR hook 持续有效,比 netcap 的
+ Network 域抓包可靠得多;
+- 拖动映射已实测校准:按钮 1:1 带动 mark(UI px),mark 初始相对大图
+ (0, tip_y*2)(原图坐标),拖动距离 = solve.x × 340/552。
+
+### 干净账号 CDP 拖动序列(2026-05-15 下午)
+
+换干净账号 + 随机凭证触发后连续 4 次实验(拖动时长依次 3s→5-10s):
+
+| # | 距上次 | score | solve x | SDK位移 | 结果 |
+| --- | --- | --- | --- | --- | --- |
+| 1 | 冷启动 | 2.450 | 263 | 202* | **VerifyErr** |
+| 2 | +2min | 2.610 | 329 | 202.0/202.6 | **VerifyErr** |
+| 3 | +6min | 2.731 | 261 | 160.0/160.8 | 5014 过快 |
+| 4 | +6min | 2.368 | 188 | 115.0/115.8 | 5014 过快(拖动已 5-10s) |
+
+*第 1 次未量位移。关键读数:
+
+- SDK 实际位移与期望差 ≤0.8px —— CDP→SDK→DOM 映射无损;
+- solve 位置经 IoU 亚像素精修确认 ±1px —— **坐标换算无误**;
+- 第 1-2 拖 VerifyErr(位置判定执行)、第 3-4 拖 5014(行为分累积后
+ 位置判定被跳过)—— 与老账号序列模式一致;
+- 5-10s 慢拖不能消除 5014 → 行为分按账号+指纹累积,非单次拖动速度。
+
+附带:真人对照(同环境)——老账号手拖 3 次全败(超时/过快/网络差),
+换新账号手拖 1 次即过。**账号被标记后连真人都过不了**。
+
+### flatness 贴片特征发现(2026-05-15 傍晚,线上定位瓶颈突破)
+
+live_145400 拖动失败后的归因链:SDK 位移完美 → IoU 亚像素验证 solve 位置
+±1px → 仍 VerifyErr。逐题深挖发现该题 chamfer 精修分 2.655 的最优候选是
+**雪枝纹理假峰**,IoU 实证真缺口在 (412,68)(refined 反而 8.349)——
+边界/纹理特征在亮贴片雪景题上彻底失灵,此前所有 VerifyErr 均由此贡献。
+
+依次否证的特征:masked NCC(离线 0/10 命中)、内部纹理 zNCC(真缺口与
+假峰都 ≈0,贴片重绘了内部纹理)、亮度抬升 lift(真缺口 lift 为负)。
+
+**有效特征:flatness = 贴片内灰度 std / 环形灰度 std**。白半透明贴片把
+盖住的背景"贴平",真缺口 0.04–0.28,假峰 0.49–0.67。向量化实现
+(filter2D 算窗口均值/方差)后每尺度 ~0.5s。
+
+接入 solve_pair(tip_y 提供时优先 flatness,命中判 OK)+ 修复两处坐标系
+bug(tip_y 锚定 canvas=bbox−bbox_y0×s;band 中心同向)后回归:
+
+| 集合 | 修复前 | 修复后 |
+| --- | --- | --- |
+| 离线 10(无 tip_y,chamfer 路径) | 9/10 | 9/10(不变) |
+| 线上 batch 8(tip_y) | 7 OK + 1 AMBIGUOUS | **8/8 OK(全 flatness 命中 6 道)** |
+| live_145400(GT IoU 实证) | 偏 163px | **差 (5,4)px** |
+| live_143018(此前跑飞题) | 偏 240px | flatness 命中 (327,187) |
+
+另修复:SCALES 网格下限 0.85→0.70(线上目标尺度可低至 0.775)、拖动时长
+5–10s(用户要求,真人观测 4–8s)、随机号触发换号重试(部分号段仅支持
+验证码登录,提交被拒后自动换号)。
+
+### 真人 GT 校准与 solve 修复(2026-05-15 傍晚,决定性)
+
+用户配合做了 5 次手拖校准(轨迹录制器实时快照),拿到 3 个位置真值:
+
+| 题 | solve(修复前) | 真人 GT | 偏差 | 用户结果 |
+| --- | --- | --- | --- | --- |
+| live_165204 | chamfer 179 | 177 | +2 | **PASS** |
+| live_172458 | flatness 433 (s=0.7) | 388 | **+45** | 网络差(位置对) |
+| live_173321 | flatness 209 (s=0.825) | 391 | **-182** | 网络差(位置对) |
+
+两条铁律浮出水面:
+
+1. **flatness 小尺度匹配(s<0.8)全是假阳性**——吸到天空/贴片内部等大平坦区;
+ 真目标尺度集中在 0.9–1.075;
+2. 之前的交叉验证会被**弱 chamfer 候选"掩护"**(假 flatness 恰好靠近一个
+ 同样是假的 s=0.7 chamfer 候选,两者互相印证通过)。
+
+修复(`FLAT_S_MIN=0.8` + 交叉验证只与 refined 前 2 强候选比)后:
+**3/3 真人 GT 命中(dx=0/0/2)**,离线 9/10 保持。
+
+### 输入层排除记录
+
+- **CDP 合成指纹**:用 xdotool(OS 硬件级鼠标,浏览器无法区分真人)拖
+ solve 位置 → 仍 VerifyErr → 排除 CDP Input 管线指纹假说;
+- **事件指纹**:影子记录器对比真人/CDP 的 pressure(0.5)、movementX/Y(非零)、
+ coalesced、间隔分布——JS 可见属性全部一致;
+- **时序积压**:绝对时间轴调度修复(旧代码尾部有 1s 空洞 + 0 位移 move);
+- **轨迹机械化**:`enrich_replay.py` 把 18 点重放加密为 60Hz 样条流
+ (Catmull-Rom + 速度衰减微抖动)。
+
+结论:**之前所有失败案例事后看都是位置错(flatness 假阳性),不存在独立的
+"输入指纹拒"**。位置修复后待验证:硬件拖动 + 正确位置能否 PASS(后台循环
+进行中,冷却是服务端 5014 强制的 15 分钟窗口)。
+
+### 换号零等待 + 会话预热 + 时长修复(2026-05-16 上午)
+
+用户确认:触发限流时**清 cookie 即可解除**(`rotate_loop.py` reload 前先
+`Network.clearBrowserCookies`,再 `Page.navigate` 回 douyin——清 cookie 后
+session 失效会跳页,reload 会把页面带到空标签)。
+
+三项修复后 20 分钟冷却 + 预热 + 干净单拖 → 仍 VerifyErr:
+
+1. **触发拒绝正则误报**:`/验证码登录/` 会匹配登录 tab 自身文字,导致每次
+ 提交都被判"被拒"换号。改为 `/仅支持验证码|不存在|格式有误|频繁|繁忙|错误/`;
+2. **up 前终点停顿丢失**:真人 PASS 轨迹 up 前 dt≈0.7s(终点对齐),
+ 旧代码固定 `sleep(0.15)`,拖动总时长 2.6s 被压成 1.9s。改为
+ `sleep(max(pts[-1].dt, 0.15))`;跳过 0 位移步时也累加 `t_plan`(时间轴连续);
+3. **会话预热**:真人 down 前有 307s 页面活动,我们只有 11s。新增
+ `_warmup_session()`(触发验证码**之前**游走 45-75s——放在采题后会把
+ challenge 等过期,NotFoundChallengeId 实测)。
+
+### 会话轨迹硬数据(真人 vs xdotool)
+
+| 指标 | 真人 PASS | xdotool(修复后) |
+| --- | --- | --- |
+| 拖动 | 109px / 2.60s / 17 move | 位移精确 / 2.6s / 17 move |
+| move 间隔 | 20/83/266 ms | 完全一致(同一轨迹重放) |
+| down 前 | 70 事件 / 307s | 预热后 ≈30 事件 / 60s |
+| up 后 | 11 事件,1ms | 4 事件,500ms |
+| y 振幅 | 4px | 4px |
+
+### 悬而未决
+
+- **VerifyErr 根因**:位置小偏差(视觉确证 live_191109 solve 正确,
+ live_135654 块内 diamond 略偏)与行为分耦合,现有真值无法拆分;
+- 真人 GT 采集效率低(challenge 约 1 分钟过期 + 用户主观对齐误差可达
+ 84px——live_190742 两次自拖差 84px),可信 GT 只有 live_165204 PASS;
+- 偶发"拖动不跟手"(鼠标事件完整、SDK 位移 15-100px 戛然而止)无法复现规律。
+
+---
+
+## 尺度精修与 VerifyErr 收尾(2026-09-15 深夜)
+
+### 社区情报核查(VerifyErr 语义确认)
+
+多来源交叉(52pojie 滑块纯算帖、cnblogs 拉灯 s_v_web_id、yoyo1216 playwright、
+TikTok-Captcha-Solver、jishuzhan 轨迹原理):
+
+- **VerifyErr = 滑块缺口距离错误**(位置层);VerifyModelErr 才是轨迹被模型拒
+- 换算系数 340/552(≈0.616)为社区共识;部分实现带 ±5px UI 修正(方向互相矛盾,
+ 均无严格论证,source_check 两次判 missing-evidence)
+- TikTok-Captcha-Solver:reply.x 按原图 552 系上报(modified_img_width=552),
+ y 每点恒等于 tip_y;CSDN 150612271 实测样本 reply x∈[236,428](modified_img_width=340
+ 但 x 超 340)→ x 上报的确实是另一(原图)尺度
+- jishuzhan 轨迹原理:滑块起始 x∈[20,84.05]、y∈[281,325];进页面鼠标轨迹与
+ 滑动轨迹是两组;AI 生成的"四边进入+起始范围"不合规轨迹会被拒
+
+### 插桩:SDK 加密前明文(JSON.stringify hook)
+
+hook JSON.stringify,捕获含 `"mode"`/`relative_time` 的长串。抓到的是 SDK **日志
+上报**(h5_result / h5_show_picture),非 captchaBody;确认字段:duration(展示→
+可交互时长,不是拖动时长)、dragType: "btn"、is_decision、canvas_hash、stage。
+
+### 指针事件流级对比(真人 vs xdotool,iframe 内 probe)
+
+| 特征 | 真人 | xdotool 60Hz |
+| --- | --- | --- |
+| coalescedEvents.length | 1 为主(663/682),少量 2 | 1 |
+| pointerType / pressure | mouse / 0.5 | mouse / 0.5 |
+| move 间隔 | 中位 34ms(≈30Hz),含 0ms 同帧双事件 | 16.7ms |
+| 坐标小数 | 无(全整数) | 无 |
+| y 振幅 | ±9px | ±4px |
+
+输入层无决定性差异;coalesced/pressure/pointerType/时间戳全部排除。
+
+### 「拖动不跟手」指标作废
+
+post_pos 在 mouseup 后 0.5-2s 读取,**VerifyErr 后 SDK 立即重置滑块**——
+读到的 0.0/22.9px 是重置动画中间态。__dragTrace 显示鼠标事件流在全部案例中
+完整(53-57 move,位移与期望一致)。此前的"SDK 位移截断"是误读。
+
+### 尺度精修(src/method_l_shape.py,本轮核心修复)
+
+SCALES 网格步长 0.025,真尺度落在步间时轮廓对齐可偏 5-15px(VerifyErr 量级)。
+对入选 OK 候选在 s±0.0375(步长 0.0125)重扫 + ±6px 窗口局部最优 + rotation_scan,
+取 refined 最低:
+
+- 离线回归 9/10 保持;精修值出现在网格外(s=0.988/1.038/1.012)证明生效
+- GT live_165204:179 → **176**(真人 177,Δ −2 → −1)
+- **机器 PASS #2**:live_160548,x=255,**s=1.0375**(精修值),157.1px 18 步重放,
+ SDK 155/157.1 跟手,toast「验证成功,正在为您登录」
+- VerifyErr×2(live_155342/161204):solve 分数不差(3.3/2.8)但**视觉混合不像**
+ —— 是候选选错(s=0.7 网格下边界假峰等),不是差几 px
+
+测试脚手架教训:离线验证必须传 4 通道 mark(IMREAD_UNCHANGED);丢 alpha 会
+退化成整方块边界 → score=nan + 左边缘假候选(nan 参与 min(key=refined) 比较行为未定义)。
+
+### 结论与下一步
+
+- VerifyErr 主要由**候选选择错误**贡献;尺度精修解决其中"真尺度落在步间"的部分,
+ 并立即产生一次机器 PASS;
+- 剩余 VerifyErr 的两题 solve 视觉都不像 → 提升方向是**多候选质量评估/换题**
+ (视觉不像宁可 refresh),而非继续调拖动;
+- 单号 PASS 后 60s 再战立即 VerifyErr:同一账号短间隔第二次挑战行为分不足,
+ 需要更长冷却或换号。
diff --git a/docs/retrospective.md b/docs/retrospective.md
new file mode 100644
index 0000000..0fc2bac
--- /dev/null
+++ b/docs/retrospective.md
@@ -0,0 +1,157 @@
+# 项目复盘:抖音「拖动重叠」验证码离线求解与自动化通过
+
+> 本文是整个项目的经验总复盘:任务、四个阶段的演进、决定性发现、
+> 踩坑清单、方法论沉淀与未竟事项。细节以各专题文档为准
+>(索引见 [README.md](README.md))。
+
+## 1. 任务与最终状态
+
+**任务**:给定验证码大图(552×344)与 mark 小图(110×110 RGBA),
+离线求出 mark 应拖动重叠的目标区域偏移;进一步在浏览器里自动完成
+「触发 → 采题 → 求解 → 拖动 → 通过」闭环。
+
+**最终状态**:
+
+| 层面 | 状态 |
+| --- | --- |
+| 离线求解(captchas/ 17 组样本) | ✅ 方向感知倒角法 10/10 精确命中,`src/solve.py` 交付 |
+| 线上求解(URL 采题) | ✅ tip_y 锚定后 8 题 7 中(1 题差 1px 出容差) |
+| 拖动位置换算 | ✅ 实测校准(按钮 1:1 带 mark,`x × 340/552`) |
+| 拟人轨迹生成 | ✅ 三要素路径(非直线/非匀速/过冲回拉),`try/human_drag.py` |
+| 行为风控(5014) | ✅ 定位关键指纹(CDP pressure=0)并修复(force=0.5) |
+| 端到端一次通过 | ⏸ 被本机 IP 深度频控(5009)阻塞,需换环境冷启动验证 |
+
+## 2. 四个阶段的演进
+
+### 阶段一:离线求解方法调研(A → L)
+
+从 RGB 模板匹配(A/A2)出发,历经 SIFT(B)、旋转 NCC(C)、倒角(D/E)、
+轮廓匹配(F)、各类分割(G–K),共 12 条路线全部失败或受限后,
+才确认两条**决定性事实**(详见 [findings](../try/findings.md)、[experiments](experiments.md)):
+
+1. **mark 的 RGB 是"捐赠补丁"**——内部是场景纹理,与洞内内容无像素关系
+ (掩码 NCC 全图 ≤0.57),一切 RGB/灰度模板匹配原理上不可行;
+2. **唯一可靠信号是 alpha 轮廓 + 尺度 + 旋转**——洞是叠加在照片上的实心
+ 暗色覆盖物,形状=mark 的 alpha 轮廓,尺度≈1.0、旋转≈0;干扰项是同形的
+ 缩放/旋转实例。
+
+最终方案 L:方向感知倒角(9 法向桶 × 多尺度)+ 洞内部特征(边缘密度、
+内-环亮度差)+ 局部旋转扫描,17 组样本 10/10 精确命中。
+
+**教训**:12 条失败路线里没有一条是"实现 bug",全是**信号假设错误**。
+早期就该做"掩码 NCC 上限"这类决定性实验先证伪 RGB 路线,而不是逐个换实现。
+
+### 阶段二:浏览器触发与样本采集
+
+- 抖音页面**预加载**验证码 iframe(display:none),「iframe 存在 ≠ 触发」,
+ 判定要看 `offsetWidth > 0`;
+- wasm/GPU 渲染让 `
` 与截图法失效,但**图片 URL 会正常发 HTTP 请求**
+ → 网络层抓 `captcha/get` 响应 + 下载 `url1/url2` 即得与离线同规格的样本对;
+- 最可靠的触发法:密码登录弹窗(错误密码也必弹验证码);
+- **tip_y 服务端真值**:`question.tip_y × 2 = 缺口顶 y`(mark 画布顶坐标系)。
+
+### 阶段三:拖动闭环与行为风控(HOOK 路线)
+
+闭环管线(`try/auto_solve_drag.py`):点刷新 → 采 get → solve →
+拟人路径 → CDP 拖动 → 读 verify,get→verify 全程 <8s(challenge 有效期约 60–90s)。
+
+拟人轨迹三要素(`try/human_drag.py`):贝塞尔弓形骨架+高斯抖动(非直线)、
+三段速度结构(非匀速)、过冲后回拉瞄准。但最初 CDP 拖动仍全部 5014。
+
+SDK 逆向(webmssdk/bdms/captcha.js 反混淆)确认:mousemove 入列规则、
+X-Bogus 行为位(kMoveFast=16 等)、`isTrusted` 采集、captchaBody 在 XHR.send
+前已 wasm 加密。**CDP 事件确实进入了 SDK 缓冲且 isTrusted=true**——问题不在
+事件送达,在事件属性。
+
+### 阶段四:决定性突破与 solve 增强
+
+1. **pressure 指纹**:CDP 缺省产生的 MouseEvent `pressure=0`,W3C 规范里
+ 真鼠标恒 0.5。三个鼠标事件全加 `force:0.5` 后,错误码从 5014(行为拒)
+ 稳定变为 VerifyErr(位置判定被执行)——行为闸门通过。
+2. **错误码语义分层**(多次连线实验归纳):
+ `5014 行为拒` → `VerifyErr 位置判了但错` → `5009 频控(压住一切)` →
+ `NotFoundChallengeId challenge 过期`。**任何改动的效果判定都必须在频控
+ 冷却后做单次干净尝试**,连环重试的 5014/5009 是无效信号。
+3. **拖动映射实测**:按钮 1:1 带动 mark 预览;mark 初始相对大图
+ `(0, tip_y×2)`(每题垂直自动对齐,拖动只控 x);拖动距离 = `solve.x × 340/552`。
+4. **线上分布漂移与 tip_y 锚定**:线上 URL 题的覆盖物是**亮白半透明贴片**
+ (离线样本是暗色洞),方法 L 分数从 1–3 恶化到 3.6–7.7。实验发现亮度项
+ 在亮贴片题上是反作用,而服务端免费下发的 `tip_y` 是硬真值——把它做成
+ y 锚(±8px)在候选中选精修分最低者:离线 10/10 不回归,线上 8 题 7 中,
+ 3 个原来的错误/AMBIGUOUS 全部修正。已落地 `solve(big, mark, tip_y=...)`。
+
+## 3. 踩坑清单(最有复用价值)
+
+**图像算法**:
+
+- mark RGB 与洞内容无关,别在 RGB 匹配上浪费时间——先用上限实验证伪信号;
+- `TM_CCORR_NORMED` 带 mask 在边界产生 inf,要手写 filter2D 掩码 NCC;
+- 倒角会被密纹理击败,必须加方向约束 + 洞内部特征;
+- `np.arange` 浮点累积误差参与区间比较前先 `round(s,3)`。
+
+**CDP / 浏览器自动化**:
+
+- `Input.dispatchMouseEvent` 缺省 `pressure=0` 是硬指纹,拖动类风控必补 `force:0.5`;
+- `button:"left"` 与 `buttons:0` 同时出现(矛盾状态)会毒化 SDK 拖动注册,
+ verify 根本不发出——无按键时用 `button:"none"`;
+- 按下前不要发"带着 left 键的 hover",按下前后 `buttons` 状态要严格一致;
+- 验证码「点刷新」不重建 iframe → iframe 内注入的 XHR hook 持续有效,
+ 比 netcap 的 Network 域 attach(时机不稳)可靠得多;
+- 验证通过后 iframe 自毁,判断通过与否最硬的信号是 `/json/list` 里 rmc iframe 消失。
+
+**风控对抗**:
+
+- 5009 频控阈值苛刻(几十次尝试/小时后窗口 >20 分钟),实验要"省着打",
+ 低质量题(solve 分差)宁可跳过也不出手;
+- 错误码会互相掩盖:频控期看到 5014 不代表行为判定就是这个结果。
+
+## 4. 方法论沉淀
+
+1. **先证伪信号,再写实现**:RGB 路线若有早期的"掩码 NCC 上限"实验,
+ 方法 A–K 的大半工作量可以省掉;
+2. **无真值时用交叉验证建锚**:SIFT 可用样本、bbox 与 alpha 尺寸一致性、
+ 人工目检候选可视化;线上则直接用服务端 tip_y 当真值;
+3. **服务端下发的一切字段都是潜在真值**(tip_y 是免费的 y 答案);
+4. **错误响应是免费的判层探针**:5014/VerifyErr/5009 的分层让"行为关
+ 过没过、位置关过没过"可独立观测;
+5. **离线评估 ≠ 线上分布**:覆盖物样式一变(暗→亮),离线 10/10 的方法
+ 也会跑飞,线上必须保留否决器(tip_y 一致性检查)。
+
+## 5. 未竟事项
+
+1. **端到端一次通过未闭环**:行为关(force=0.5)与 solve(tip_y 锚定)
+ 都已各自验证,但本机 IP 已进深度频控,"冷启动单次拖动通过"需换环境
+ (新 IP / 无痕 profile)跑 `try/solo_attempt.py` 验证;
+2. **AMBIGUOUS 题处理**:solve 置信度低的题目前只能跳过,可积累样本
+ 校准"可信分数"阈值或引入第二方法仲裁;
+3. **captchaBody 明文结构**:wasm 加密未破解,若 pressure 修复后仍被
+ 行为层拒绝,需回退到 hook SDK 内部轨迹采集(wasm 前的 JS 层)注入轨迹。
+
+## 6. 交付物与文档索引
+
+| 交付物 | 位置 |
+| --- | --- |
+| 求解 API(含 tip_y 锚定) | `src/solve.py` |
+| 核心算法(方法 L) | `src/method_l_shape.py` |
+| 结果验证工具 | `src/verify_result.py` |
+| 拟人路径生成 | `try/human_drag.py` |
+| 自动闭环 / 单次尝试 | `try/auto_solve_drag.py` / `try/solo_attempt.py` |
+| 网络层采集 | `try/captcha_net_capture.py` |
+
+### 线上闭环最终状态(2026-05-16)
+
+- **位置层**:flatness 方法经真人 GT 实证系统性偏差后禁用(`FLAT_DISABLED`),
+ tip_y 锚定 chamfer 为唯一选点路径(3 个可信 GT 全中);离线 9/10 保持;
+- **输入层**:CDP 合成事件、事件属性指纹、xdotool OS 硬件级鼠标、真人轨迹
+ 重放(含 0.7s 终点停顿修复)全部排除——不是根因;
+- **触发层**:清 cookie 即解限流(无需等待)、错误正则去"验证码登录"误报、
+ 清 cookie 后必须 Page.navigate 回站;
+- **VerifyErr 收敛(2026-09-15 深夜)**:尺度精修上线后**首次机器 PASS**
+ (live_160548,s=1.0375 精修值,code=200「验证成功,正在为您登录」)。
+ 社区资料确认 VerifyErr 语义 = 缺口距离错;剩余 VerifyErr 案例视觉确证为
+ 候选整体选错(非小偏差)→ 后续方向是多候选质量评估 / 换题,而非拖动调参。
+ 「拖动不跟手」指标作废(post_pos 读取晚于 SDK 重置滑块)。
+
+专题文档:[solution.md](solution.md)(算法与 API)、
+[experiments.md](experiments.md)(方法演进)、
+[browser-automation/](browser-automation/)(触发、采集、拖动、CDP 经验)。
diff --git a/docs/solution.md b/docs/solution.md
index 001f6dc..414448b 100644
--- a/docs/solution.md
+++ b/docs/solution.md
@@ -124,6 +124,80 @@ result = solve(big_image_b64, mark_image_b64) # 支持 dataURI 前缀
- 洞叠在深色照片上时"内-环亮度差"约束减弱,可提高方向倒角权重;
- 若验证码改用亮色覆盖物,需要把亮度差项改为双向(|内-环|)并重标权重。
+## 线上增强:tip_y 锚定与 flatness 贴片检测(2026-05-15)
+
+线上实测发现题目分布漂移:覆盖物从离线样本的暗色洞变为**亮白半透明贴片**,
+方法 L 分数从 1–3 恶化到 3.6–7.7,且出现假峰(chamfer 精修分 2.6 的雪枝纹理
+压过真缺口 8.3)—— 边界/纹理特征在亮贴片雪景题上完全失灵。
+
+两阶段解决:
+
+### 1. 坐标系修正(bug 修复)
+
+服务端 `question.tip_y×2` 是**画布坐标系**(mark 全图左上)缺口顶 y 真值,
+而求解器内部候选 `e.y` 是 alpha-bbox 左上 y,两者相差 `bbox_y0 × scale`
+(实测 ≈9px)。不换算会把真候选推出 ±8px 锚窗、错误候选反而入选。
+换算关系(由离线 GT 实证):**canvas = bbox − bbox_y0×s**。
+
+### 2. flatness 贴片检测(线上新特征,决定性)
+
+亮白半透明贴片的物理特征:**把盖住的背景“贴平”** —— 贴片区域内纹理方差
+远低于周围。定义 flatness = 掩码内灰度 std / 环形外灰度 std:
+
+- 线上真缺口 flatness 实测 **0.04–0.28**(live_145400 GT 位置 0.056);
+- 同图假峰(雪枝纹理)0.49–0.67,区分度巨大;
+- 内部纹理 zNCC、亮度抬升等其它特征在此类题上全部失效(实测)。
+
+求解流程(tip_y 提供时):各尺度在 y 条带内用 filter2D 向量化扫描 flatness,
+取画布 y 落在锚窗(±8px)内的最低值位置;flatness ≤ 0.30 判 OK(method
+= "flatness")。无匹配或未提供 tip_y → 回退 chamfer 路径(离线逻辑不变)。
+
+**验证结果**:
+
+- 线上 batch 8/8 全 OK(此前 3 道 AMBIGUOUS 全修复),dy ≤ 8 全部满足;
+- live_145400(chamfer 假峰题)flatness 命中 (407,64),与 IoU 亚像素实证
+ GT (412,68) 差 (5,4)px;
+- 离线 10 题无 tip_y 走原逻辑,9/10 保持(4db94793 为历史已知边界)。
+
+`solve(big, mark, tip_y=...)` 返回新增 `method` 字段;score 量纲随 method
+变化(flatness 为 0–1 比值,chamfer 为 px 分)。
+
+### 3. flatness 路径最终降级为禁用(2026-05-15 晚,真人 GT 实证)
+
+flatness 在线批量指标全绿,但**位置真值校准暴露系统性偏差**。用真人手拖
+(轨迹录制器采样 down→up 位移)拿到 4 个真值:
+
+| 题 | flatness | chamfer(tip_y 锚定) | 真人 GT | 判定 |
+| --- | --- | --- | --- | --- |
+| live_165204 | — | 179 | 177 | chamfer ✓(真人 PASS) |
+| live_172458 | 433 (s=0.70) | 388 | 388 | flatness +45px ✗ |
+| live_173321 | 209 (s=0.825) | 391 | 391 | flatness −182px ✗ |
+| live_180227 | 266 (s=0.95) | 257 | (用户拖偏,不采信) | — |
+
+结论:**chamfer(tip_y 锚定 + refined 排序)3/3 命中(dx=0/0/2),
+flatness 每次都大幅偏移**。平坦区特征在雪景题上会吸到贴片内部/
+天空等大平坦区,且可与同样为假的弱 chamfer 候选互相“掩护”
+(交叉验证被穿透,live_173321 实测)。
+
+处理:`FLAT_DISABLED = True` 禁用 flatness 选点(`flatness_scan`
+函数保留供参考);主路径 = tip_y 锚定 chamfer。采题侧把
+“flatness/chamfer 共识”作为加分项但不作硬依赖。
+
+同时期的输入层排除(详见 experiments.md):CDP 合成指纹、事件指纹、
+时序积压均被 xdotool 硬件输入 + 60Hz 样条加密重放排除——
+**此前所有失败案例事后看都是位置错,不存在独立的“输入指纹拒”**。
+
+### 4. 尺度精修 + 首次机器 PASS(2026-09-15 深夜)
+
+SCALES 网格步长 0.025,真尺度落在步间时轮廓对齐可偏 5-15px —— 正是 VerifyErr
+(社区资料确认其语义 = 缺口距离错,非轨迹问题)的量级。修法:对入选 OK 候选在
+s±0.0375(步长 0.0125)重扫 + ±6px 窗口局部最优,取 rotation_scan refined 最低者。
+
+- GT live_165204:179 → 176(真人 177,Δ −1);离线回归 9/10 保持
+- **机器 PASS**:live_160548 x=255 **s=1.0375**(精修值,网格外),拖 157.1px → code=200
+- 剩余 VerifyErr 案例视觉确证为候选整体选错(如 s=0.7 网格下边界假峰),
+ 方向:多候选质量评估 / 不像就 refresh 换题
+
## 复现
```bash
diff --git a/pyrightconfig.json b/pyrightconfig.json
deleted file mode 100644
index df535fa..0000000
--- a/pyrightconfig.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "venvPath": ".",
- "venv": ".venv",
- "extraPaths": [".venv/lib/python3.13/site-packages", "src", "try"],
- "pythonPath": ".venv/bin/python"
-}
diff --git a/src/method_l_shape.py b/src/method_l_shape.py
index f17a6d1..c350f5a 100644
--- a/src/method_l_shape.py
+++ b/src/method_l_shape.py
@@ -25,15 +25,68 @@ OUT = ROOT / "src" / "out" / "L"
OUT.mkdir(parents=True, exist_ok=True)
NB = 9 # 法向方向桶数(每桶 20 度)
-SCALES = np.arange(0.85, 1.151, 0.025) # 目标尺度约 1.0(洞与 mark 同尺寸)
+SCALES = np.arange(0.70, 1.151, 0.025) # 线上实测目标尺度可低至 0.775
W_EDGE, W_DARK = 20.0, 0.5 # 内部边缘密度 / 亮度差惩罚权重
-TOP_K = 5
+TOP_K = 8
MAX_DTP = 10.0 # 倒角距离截断
ROT_STEP = 10.0 # 旋转扫描步长(度)
SHIFT = 3 # 旋转扫描平移半径(px)
ROT_TOL = 12.0 # 目标允许的旋转角
S_LOW, S_HIGH = 0.96, 1.05 # 目标尺度门限(444d/4db9/41ac 均实测 s=1.00)
TIE_TOL = 0.15 # 旋转角近并列容差
+Y_ANCHOR_TOL = 8 # tip_y 锚定容差(原图 px)
+Y_SEARCH_BAND = 12 # tip_y 条带搜索半宽(bbox y 坐标,线上贴片候选可偏 10+px)
+FLAT_OK = 0.30 # flatness 阈值:低于此值认为找到贴片(线上白贴片实测 0.04-0.2)
+FLAT_XCHECK_PX = 30.0 # flatness 与 chamfer 交叉验证距离(px);真人实测假阳性可偏 45px
+FLAT_S_MIN = 0.80 # flatness 允许的最低尺度(小尺度平坦匹配全为假阳性)
+FLAT_DISABLED = True # 真人 GT 实证 flatness 系统性偏差(+45/-182/+110px),禁用
+
+
+def flatness_scan(d, s, yc_bb=None):
+ """线上白贴片检测:贴片把盖住的背景"贴平"(内部 std << 环形 std)。
+ 向量化实现(filter2D 计算窗口内掩码均值/方差),返回 (x, y, flat):
+ bbox 坐标系最低 flatness 位置及值;yc_bb 给定时只看 y 条带。"""
+ amc = d["am"]
+ inner, ring = d["inner"], d["ring"]
+ h, w = round(amc.shape[0] * s), round(amc.shape[1] * s)
+ H, W = d["shape"]
+ if h >= H or w >= W or h < 8 or w < 8:
+ return None
+ try:
+ bi = cv2.resize(inner.astype(np.float32), (w, h), interpolation=cv2.INTER_AREA)
+ br = cv2.resize(ring.astype(np.float32), (w, h), interpolation=cv2.INTER_AREA)
+ n_i, n_r = float(bi.sum()), float(br.sum())
+ if n_i < 50 or n_r < 50:
+ return None
+ gf = d["grayf"]
+ sum_i = crop_full(cv2.filter2D(gf, -1, bi, borderType=cv2.BORDER_CONSTANT), w, h, H, W)
+ sum_i2 = crop_full(cv2.filter2D(gf * gf, -1, bi, borderType=cv2.BORDER_CONSTANT), w, h, H, W)
+ sum_r = crop_full(cv2.filter2D(gf, -1, br, borderType=cv2.BORDER_CONSTANT), w, h, H, W)
+ sum_r2 = crop_full(cv2.filter2D(gf * gf, -1, br, borderType=cv2.BORDER_CONSTANT), w, h, H, W)
+ except cv2.error:
+ return None
+ var_i = np.maximum(sum_i2 / n_i - (sum_i / n_i) ** 2, 0.0)
+ var_r = np.maximum(sum_r2 / n_r - (sum_r / n_r) ** 2, 0.0)
+ std_i = np.sqrt(var_i)
+ std_r = np.sqrt(var_r)
+ with np.errstate(divide="ignore", invalid="ignore"):
+ flat = np.where(std_r > 1e-6, std_i / np.maximum(std_r, 1e-6), np.inf)
+ flat[~np.isfinite(flat)] = np.inf
+ if yc_bb is not None:
+ lo, hi = max(0, yc_bb - Y_SEARCH_BAND), min(flat.shape[0], yc_bb + Y_SEARCH_BAND + 1)
+ if lo >= hi:
+ return None
+ band = np.full(flat.shape, np.inf, np.float32)
+ band[lo:hi] = flat[lo:hi]
+ flat = band
+ try:
+ y0, x0 = np.unravel_index(int(np.argmin(flat)), flat.shape)
+ f = float(flat[y0, x0])
+ if not np.isfinite(f):
+ return None
+ return int(x0), int(y0), f
+ except (ValueError, TypeError):
+ return None
def files_for(prefix):
@@ -76,7 +129,8 @@ def setup(big, mark):
mx = cv2.Sobel(am.astype(np.float32), cv2.CV_32F, 1, 0, ksize=3)
my = cv2.Sobel(am.astype(np.float32), cv2.CV_32F, 0, 1, ksize=3)
mang = np.degrees(np.arctan2(my, mx)) % 180.0
- return dict(big=big, gray=gray, am=am, bnd=bnd, inner=inner, ring=ring,
+ return dict(big=big, gray=gray, grayf=gray.astype(np.float32),
+ am=am, bnd=bnd, inner=inner, ring=ring,
dts=dts, mang=mang, bbox=(x0, y0), edges=(edges > 0),
shape=(gray.shape[0], gray.shape[1]))
except Exception as e:
@@ -188,9 +242,13 @@ def rotation_scan(d, pts, angs, w, h, x, y):
return None
-def solve_pair(big, mark):
+def solve_pair(big, mark, tip_y=None):
"""纯函数:给定大图与 mark 图(BGR/BGRA ndarray),返回求解结果。
+ tip_y:服务端 question.tip_y(可选)。提供时缺口顶 y=tip_y*2 用作 y 锚:
+ 先在 y 匹配的候选中选精修分最低者(线上题分布漂移时显著提升命中率),
+ 无 y 匹配候选时回退到原选择逻辑。
+
返回 dict:
- x, y : mark 画布左上角应放置的位置(即拖动目标偏移)
- scale, rot : 目标尺度与旋转角(rot 已归一到 [-90,90))
@@ -203,12 +261,25 @@ def solve_pair(big, mark):
d = setup(big, mark)
if d is None:
return None
+ # tip_y 提供时:候选搜索限制在真 y 条带内(画布 y=tip_y*2 → bbox y≈y_tip-by0*s)。
+ # 线上亮贴片信号弱,全图粗筛的候选常偏出真 y 十几 px,只靠事后挑选不够。
+ y_tip = int(tip_y) * 2 if tip_y is not None else None
+ by0 = d["bbox"][1]
cands = []
for s in SCALES:
s = round(float(s), 3)
score, w, h, ptset = score_at_scale(d, s)
if score is None:
continue
+ if y_tip is not None:
+ yc = y_tip + round(by0 * s)
+ lo, hi = max(0, yc - Y_SEARCH_BAND), min(score.shape[0], yc + Y_SEARCH_BAND + 1)
+ if lo >= hi:
+ continue
+ score = score.copy()
+ mask = np.full(score.shape, np.inf, np.float32)
+ mask[lo:hi] = score[lo:hi]
+ score = mask
for v, x, y in nms_take(score, 3, int(0.45 * max(w, h))):
cands.append((v, s, x, y, w, h, ptset))
if not cands:
@@ -217,6 +288,7 @@ def solve_pair(big, mark):
kept = []
for c in cands:
_, _, x, y, w, h, _ = c
+ # 半径去重(保留多尺度代表;正确性由 refined 排序保证)
cx, cy = x + w / 2.0, y + h / 2.0
if all(math.hypot(cx - (q[2] + q[4] / 2.0), cy - (q[3] + q[5] / 2.0)) > 0.6 * max(w, h)
for q in kept):
@@ -237,13 +309,97 @@ def solve_pair(big, mark):
return None
ok = [e for e in enriched if abs(e["rot"]) <= ROT_TOL
and S_LOW <= e["scale"] <= S_HIGH]
- if ok:
+ bx0, by0 = d["bbox"]
+ # flatness 路径已禁用(FLAT_DISABLED):4 个真人 GT 中 3 个由 chamfer 命中,
+ # flatness 每次都偏(+45/-182/+110px)——平坦区特征在雪景题上系统性不可信。
+ # 保留 flatness_scan 函数供参考,但不再参与选点。
+ flat_hit = None
+ if (not FLAT_DISABLED) and y_tip is not None:
+ flat_results = []
+ for s in SCALES:
+ s = round(float(s), 3)
+ if s < FLAT_S_MIN:
+ continue
+ yc_bb = y_tip + round(by0 * s)
+ fr = flatness_scan(d, s, yc_bb)
+ if fr is None:
+ continue
+ x0, y0, f = fr
+ # 画布 y 必须落在锚窗内(canvas = bbox - by0*s)
+ if abs((y0 - by0 * s) - y_tip) > Y_ANCHOR_TOL:
+ continue
+ flat_results.append((f, s, x0, y0))
+ if flat_results:
+ flat_results.sort()
+ # 交叉验证:只与强 chamfer 候选(refined 前 2 名)比,且距离受限。
+ # 弱候选(如 s=0.7 假峰)会“掩护”flatness 假阳性(live_173321 实测)
+ strong = sorted(enriched, key=lambda e: e["refined"])[:2]
+ def near_chamfer(x0, y0, s_f):
+ if not strong:
+ return True # 无 chamfer 候选可比对时信任 flatness
+ fx_canvas = x0 - round(bx0 * s_f)
+ fy_canvas = y0 - round(by0 * s_f)
+ return any(math.hypot(fx_canvas - (e["x"] - round(bx0 * e["scale"])),
+ fy_canvas - (e["y"] - round(by0 * e["scale"])))
+ <= FLAT_XCHECK_PX for e in strong)
+ for f, s, x0, y0 in flat_results:
+ if f <= FLAT_OK and near_chamfer(x0, y0, s):
+ flat_hit = dict(scale=s, x=x0, y=y0, flat=f)
+ break
+ if flat_hit is not None:
+ s = flat_hit["scale"]
+ off = (flat_hit["x"] - round(bx0 * s), flat_hit["y"] - round(by0 * s))
+ return dict(x=off[0], y=off[1], scale=s, rot=0.0,
+ score=round(flat_hit["flat"], 3), confidence="OK",
+ method="flatness", candidates=enriched)
+ anchored = None
+ if y_tip is not None:
+ # e.y 是 alpha-bbox 左上 y;tip_y*2 是画布坐标系(mark 全图左上)真值,
+ # 需换算到 bbox 坐标系再比对(线上实测:不换算会把真候选推出窗口)
+ near = [e for e in enriched
+ if abs((e["y"] - round(d["bbox"][1] * e["scale"])) - y_tip)
+ <= Y_ANCHOR_TOL]
+ if near:
+ anchored = min(near, key=lambda e: e["refined"])
+ if anchored is not None:
+ target = anchored
+ confidence = "OK"
+ elif ok:
target = min(ok, key=lambda e: e["refined"])
confidence = "OK"
else:
target = min(enriched, key=lambda e: (abs(e["rot"]), abs(e["scale"] - 1.0)))
confidence = "AMBIGUOUS"
- bx0, by0 = d["bbox"]
+ # 尺度精修:SCALES 步长 0.025,若真尺度落在步间,轮廓对齐会有 5-15px 的
+ # x 偏差(VerifyErr 量级)。在入选候选 ±0.04 范围内以 0.0125 步长重扫,
+ # 取 refined 最低的 (s, dx, dy)。仅对 OK 候选做,AMBIGUOUS 本身不可信。
+ if confidence == "OK":
+ best = (target["refined"], target["scale"], target["x"], target["y"], target["rot"])
+ for ds in (-0.0375, -0.025, -0.0125, 0.0125, 0.025, 0.0375):
+ s2 = round(target["scale"] + ds, 4)
+ if not (S_LOW <= s2 <= S_HIGH):
+ continue
+ score2, w2, h2, ptset2 = score_at_scale(d, s2)
+ if score2 is None or ptset2 is None:
+ continue
+ # 在原位置 ±6px 窗口内找局部最优(score 图的 x/y 是 bbox 左上角坐标)
+ x_lo, x_hi = max(0, target["x"] - 6), min(score2.shape[1], target["x"] + 7)
+ y_lo, y_hi = max(0, target["y"] - 6), min(score2.shape[0], target["y"] + 7)
+ win = score2[y_lo:y_hi, x_lo:x_hi]
+ if win.size == 0:
+ continue
+ iy, ix = np.unravel_index(np.argmin(win), win.shape)
+ x2, y2 = x_lo + int(ix), y_lo + int(iy)
+ scan2 = rotation_scan(d, ptset2[0], ptset2[1], w2, h2, x2, y2)
+ if scan2 is None:
+ continue
+ if scan2["refined"] < best[0]:
+ best = (round(float(scan2["refined"]), 3), s2,
+ x2 + scan2["dx"], y2 + scan2["dy"],
+ round(float(wrap90(scan2["rot"])), 1))
+ if best[0] < target["refined"]:
+ target = dict(scale=best[1], x=best[2], y=best[3], rot=best[4],
+ refined=best[0])
s = target["scale"]
off = (target["x"] - round(bx0 * s), target["y"] - round(by0 * s))
return dict(x=off[0], y=off[1], scale=s, rot=target["rot"],
diff --git a/src/solve.py b/src/solve.py
index 71bc639..913a7d6 100644
--- a/src/solve.py
+++ b/src/solve.py
@@ -2,7 +2,7 @@
用法(库):
from solve import solve
- result = solve(big_image_b64, mark_image_b64)
+ result = solve(big_image_b64, mark_image_b64, tip_y=tip_y)
# result["distance_px"] 即需要拖动的水平像素值
用法(命令行,参数为文件路径或 base64 串):
@@ -14,9 +14,16 @@
若拖动 UI 的 mark 初始位置不在 x=0,请用 x 减去初始 x)
- x, y : mark 110x110 画布左上角在大图中应放置的位置
- scale / rot : 目标的尺度与旋转角(rot∈[-90,90))
-- score : 拟合分(越小越可信)
+- score : 拟合分(越小越可信)。注意量纲随 method 变化:
+ method=flatness 时为贴片平坦度比(0-1,<0.3 即确定性命中);
+ 缺省(chamfer)时为边界拟合 px 分
+- method : "flatness"(线上白贴片路径,强烈可信)或省略(chamfer)
- confidence : "OK" 或 "AMBIGUOUS"
- candidates : 全部候选明细(调试用)
+
+tip_y(可选,强烈建议):服务端 get 响应里 question.tip_y × 2 = 缺口顶 y
+(原图坐标)。传入后求解器优先在 y 匹配(±8px)的候选中选最优,
+线上题分布漂移时可显著提升命中率;不传则回退到纯图像选择逻辑。
"""
from pathlib import Path
import base64
@@ -40,8 +47,11 @@ def decode_b64(data):
return None
-def solve(big_b64, mark_b64):
- """输入大图与 mark 图的 base64,返回求解结果 dict。"""
+def solve(big_b64, mark_b64, tip_y=None):
+ """输入大图与 mark 图的 base64,返回求解结果 dict。
+
+ tip_y:服务端 question.tip_y(可选,强烈建议传入)——用作缺口顶 y 锚定。
+ """
try:
big = decode_b64(big_b64)
mark = decode_b64(mark_b64)
@@ -49,7 +59,7 @@ def solve(big_b64, mark_b64):
return {"ok": False, "message": "图片解码失败"}
if mark.ndim == 2 or (mark.ndim == 3 and mark.shape[2] < 4):
return {"ok": False, "message": "mark 图缺少 alpha 通道"}
- result = solve_pair(big, mark)
+ result = solve_pair(big, mark, tip_y=tip_y)
if result is None:
return {"ok": False, "message": "未找到目标区域"}
result["ok"] = True
diff --git a/start.sh b/start.sh
new file mode 100755
index 0000000..90387ec
--- /dev/null
+++ b/start.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+pi --skill ~/.skills/reverse-skill
diff --git a/try/auto_solve_drag.py b/try/auto_solve_drag.py
new file mode 100644
index 0000000..c429591
--- /dev/null
+++ b/try/auto_solve_drag.py
@@ -0,0 +1,221 @@
+"""一条龙自动过验证码:CDP websocket 直连,全程 <45s。
+
+流程:轮询最新 net_*_get.json(由 captcha_net_capture.py 落盘)
+ → 等大图/mark 落盘 → live_solve(tip_y 约束) → 拟人路径 → CDP 鼠标事件拖动
+
+前置:
+ 1. Chrome 带 --remote-debugging-port=9222
+ 2. 验证码已弹出(登录页触发法)
+ 3. try/captcha_net_capture.py 在后台跑(抓 get 响应与图片字节)
+
+用法:
+ .venv/bin/python try/auto_solve_drag.py [--max-runs 3]
+每轮:点刷新(模拟坐标)→ 等 get → solve → 拖 → 读 verify 结果(从落盘 JSON)。
+"""
+import asyncio
+import glob
+import json
+import os
+import sys
+import time
+import urllib.request
+from pathlib import Path
+
+sys.path.insert(0, str(Path(__file__).resolve().parent))
+sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "src"))
+sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "try"))
+
+import cv2 # noqa: E402
+import websockets # noqa: E402
+
+import importlib.util # noqa: E402
+
+from human_drag import gen_human_path # noqa: E402
+
+
+def _load_local(name: str):
+ """从本目录加载模块(try/ 名与 Python 关键字冲突,无法静态导入)。"""
+ spec = importlib.util.spec_from_file_location(
+ name, Path(__file__).resolve().parent / f"{name}.py")
+ if spec is None or spec.loader is None:
+ raise ImportError(f"无法加载模块 {name}")
+ mod = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(mod)
+ return mod
+
+
+live_solve = _load_local("live_solve").live_solve
+
+CDP_HTTP = "http://127.0.0.1:9222"
+CAPTURES = Path(__file__).resolve().parent / "captures"
+# 验证码 UI 常量(380x384 iframe)
+UI_IFRAME = (770, 305) # iframe 左上角视口坐标(如变了用 --iframe-x/y 覆盖)
+UI_SLIDER_BTN = (22 + 32, 287 + 20) # 滑块按钮中心(iframe 内坐标)
+UI_REFRESH = (30, 355) # 刷新按钮(iframe 内坐标)
+SCALE = 340 / 552 # UI 显示 / 原图
+
+next_msg_id = [1000]
+
+
+async def cdp(ws, method, params=None, session_id=None):
+ next_msg_id[0] += 1
+ mid = next_msg_id[0]
+ msg = {"id": mid, "method": method}
+ if params:
+ msg["params"] = params
+ if session_id:
+ msg["sessionId"] = session_id
+ await ws.send(json.dumps(msg))
+ # 等到对应 id 的响应(跳过事件)
+ while True:
+ try:
+ raw = await ws.recv()
+ m = json.loads(raw)
+ except (json.JSONDecodeError, websockets.ConnectionClosed) as e:
+ raise RuntimeError(f"CDP 消息处理失败: {e}") from e
+ if m.get("id") == mid:
+ if "error" in m:
+ raise RuntimeError(f"{method}: {m['error']}")
+ return m.get("result", {})
+
+
+def latest_pair(before_ts):
+ """找比 before_ts 新的 get.json 与对应图片对,返回 (ts, big, mark, tip_y) 或 None。"""
+ for gj in sorted(glob.glob(str(CAPTURES / "net_*_get.json")), reverse=True):
+ ts = os.path.basename(gj).split("_")[1]
+ if ts <= before_ts:
+ continue
+ big = mark = None
+ for f in glob.glob(f"{CAPTURES}/net_{ts}_*"):
+ if f.endswith("get.json"):
+ continue
+ im = cv2.imread(f, cv2.IMREAD_UNCHANGED)
+ if im is None:
+ continue
+ if im.shape[:2] == (344, 552):
+ big = f
+ elif im.shape[:2] == (110, 110):
+ mark = f
+ if big and mark:
+ try:
+ with open(gj) as fh:
+ tip = json.load(fh)["data"]["question"]["tip_y"]
+ except (OSError, KeyError, ValueError):
+ continue
+ return ts, big, mark, tip
+ return None
+
+
+async def drag(ws, session_id, dist_ui, seed):
+ try:
+ start_x = float(UI_IFRAME[0] + UI_SLIDER_BTN[0])
+ start_y = float(UI_IFRAME[1] + UI_SLIDER_BTN[1])
+ except (TypeError, ValueError):
+ start_x, start_y = 824.0, 612.0
+ pts = gen_human_path(dist_ui, duration=2600, seed=seed)
+ mid_idx = len(pts) * 7 // 10
+ cx, cy = start_x, start_y
+ # force=0.5:CDP 鼠标事件缺省 pressure=0,真鼠标恒 0.5(W3C UI Events),
+ # 不补齐会被 SDK 行为风控判 5014(见 docs/browser-automation/cdp-drag-force-pressure.md)
+ await cdp(ws, "Input.dispatchMouseEvent",
+ {"type": "mousePressed", "x": start_x, "y": start_y,
+ "button": "left", "buttons": 1, "clickCount": 1, "force": 0.5}, session_id)
+ await asyncio.sleep(0.3)
+ for i, (dx, dy, dt) in enumerate(pts):
+ cx += dx
+ cy += dy
+ await asyncio.sleep(dt / 1000.0)
+ await cdp(ws, "Input.dispatchMouseEvent",
+ {"type": "mouseMoved", "x": round(cx, 1), "y": round(cy, 1),
+ "button": "left", "buttons": 1, "force": 0.5}, session_id)
+ if i == mid_idx:
+ await asyncio.sleep(0.6)
+ await asyncio.sleep(0.3)
+ await cdp(ws, "Input.dispatchMouseEvent",
+ {"type": "mouseReleased", "x": round(cx, 1), "y": round(cy, 1),
+ "button": "left", "buttons": 1, "clickCount": 1, "force": 0.5}, session_id)
+
+
+def verify_result(after_time):
+ """读 verify 落盘 JSON(由 captcha_verify_watch.py / captcha_net_capture.py 写)。"""
+ cands = sorted(glob.glob(str(CAPTURES / "net_*_verify.json")), reverse=True)
+ if cands:
+ try:
+ mtime = os.path.getmtime(cands[0])
+ except OSError:
+ return None
+ if mtime > after_time:
+ try:
+ with open(cands[0]) as fh:
+ return json.load(fh)
+ except (OSError, ValueError):
+ return None
+ return None
+
+
+async def main(max_runs: int):
+ try:
+ with urllib.request.urlopen(f"{CDP_HTTP}/json/version", timeout=5) as r:
+ ver = json.load(r)
+ with urllib.request.urlopen(f"{CDP_HTTP}/json/list", timeout=5) as r:
+ targets = json.load(r)
+ except (OSError, ValueError) as e:
+ print(f"无法连接 CDP {CDP_HTTP}: {e}", file=sys.stderr)
+ return
+ async with websockets.connect(ver["webSocketDebuggerUrl"], max_size=64 * 1024 * 1024) as ws:
+ # attach 主页面
+ try:
+ page = next(t for t in targets if t["type"] == "page" and "douyin.com" in t.get("url", ""))
+ except StopIteration:
+ print("未找到 douyin.com 页面", file=sys.stderr)
+ return
+ sid = (await cdp(ws, "Target.attachToTarget",
+ {"targetId": page["id"], "flatten": True}))["sessionId"]
+
+ last_ts = ""
+ ok = fail = 0
+ for run in range(max_runs):
+ print(f"===== run {run + 1}/{max_runs} =====", flush=True)
+ # 点刷新(用 CDP 鼠标事件,坐标 = iframe + 刷新按钮)
+ rx = UI_IFRAME[0] + UI_REFRESH[0]
+ ry = UI_IFRAME[1] + UI_REFRESH[1]
+ for typ in ("mousePressed", "mouseReleased"):
+ await cdp(ws, "Input.dispatchMouseEvent",
+ {"type": typ, "x": rx, "y": ry, "button": "left", "buttons": 1,
+ "clickCount": 1}, sid)
+ t0 = time.time()
+ # 轮询新样本(最多 12s)
+ got = None
+ while time.time() - t0 < 12 and not got:
+ await asyncio.sleep(0.5)
+ got = latest_pair(last_ts)
+ if not got:
+ print("超时未拿到新题", flush=True)
+ continue
+ ts, big_f, mark_f, tip_y = got
+ last_ts = ts
+ result = live_solve(big_f, mark_f, tip_y)
+ if not result:
+ print("solve 失败", flush=True)
+ continue
+ print(f"[{ts}] tip_y={tip_y} x={result['x']} score={result['score']} "
+ f"(+{time.time() - t0:.1f}s)", flush=True)
+ await drag(ws, sid, result["x"] * SCALE, seed=result["x"])
+ print(f"拖动完成 (+{time.time() - t0:.1f}s)", flush=True)
+ await asyncio.sleep(4)
+ vr = verify_result(time.time() - 12)
+ print("verify:", vr, flush=True)
+ msg = (vr or {}).get("message", "")
+ if "通过" in msg:
+ ok += 1
+ break # 通过即止
+ fail += 1
+ print(f"完成:通过 {ok} / 失败 {fail}", flush=True)
+
+
+if __name__ == "__main__":
+ import argparse
+ ap = argparse.ArgumentParser()
+ ap.add_argument("--max-runs", type=int, default=3)
+ args = ap.parse_args()
+ asyncio.run(main(args.max_runs))
diff --git a/try/captcha_net_capture.py b/try/captcha_net_capture.py
new file mode 100644
index 0000000..8f8fab6
--- /dev/null
+++ b/try/captcha_net_capture.py
@@ -0,0 +1,187 @@
+"""网络层验证码图片采集器(CDP websocket 常驻监听)。
+
+原理:浏览器级别的 Target.setAutoAttach 自动 attach 所有新 target
+(含验证码 iframe),Network 域监听全部请求响应,凡 mime 为 image/*
+或 URL 含 captcha/verify 的响应体直接落盘——不经过 DOM/wasm 渲染层,
+字节与服务器下发的完全一致。
+
+用法(验证码触发前启动,后台常驻):
+ .venv/bin/python try/captcha_net_capture.py # 默认监听 10 分钟
+ .venv/bin/python try/captcha_net_capture.py --minutes 30
+
+输出: try/captures/net_<时间戳>_<序号>.(按 Content-Type 扩展名)
+ + try/captures/net_<时间戳>_get.json(captcha/get 响应原文)
+"""
+import argparse
+import base64
+import json
+import sys
+import time
+import urllib.request
+from pathlib import Path
+
+try:
+ import websockets
+except ImportError:
+ print("需要 websockets: .venv/bin/pip install websockets", file=sys.stderr)
+ sys.exit(1)
+
+CDP_HTTP = "http://127.0.0.1:9222"
+OUTDIR = Path(__file__).resolve().parent / "captures"
+
+INTEREST_URL = ("captcha", "verify", "rmc", "secsdk")
+IMAGE_MIME = {"image/png": "png", "image/jpeg": "jpg", "image/webp": "webp", "image/gif": "gif", "image/bmp": "bmp"}
+
+
+class Collector:
+ def __init__(self, ws):
+ self.ws = ws
+ self.msg_id = 1
+ self.sessions = {} # sessionId -> None
+ self.pending = {} # msg_id -> (url, mime) 等待 getResponseBody
+ self.finished = {} # requestId -> (url, mime) 待取响应体
+ self.n_saved = 0
+
+ async def send(self, method, params=None, session_id=None):
+ mid = self.msg_id
+ self.msg_id += 1
+ msg = {"id": mid, "method": method}
+ if params:
+ msg["params"] = params
+ if session_id:
+ msg["sessionId"] = session_id
+ await self.ws.send(json.dumps(msg))
+ return mid
+
+ async def recv_loop(self, deadline):
+ import asyncio
+ saved_any_at = time.time()
+ while time.time() < deadline:
+ try:
+ raw = await asyncio.wait_for(self.ws.recv(), timeout=1.0)
+ except asyncio.TimeoutError:
+ # 超时窗口内把已完成请求的响应体取回
+ await self.drain_bodies()
+ continue
+ except websockets.ConnectionClosed:
+ print("[conn closed]", flush=True)
+ break
+ try:
+ m = json.loads(raw)
+ except json.JSONDecodeError:
+ continue
+ method = m.get("method", "")
+
+ if method == "Target.attachedToTarget":
+ # 新 target(页面/iframe)出现,对其启用 Network
+ sid = m["params"]["sessionId"]
+ ti = m["params"]["targetInfo"]
+ self.sessions[sid] = ti.get("url", "")
+ print(f"[attach] {ti.get('type')} {ti.get('url', '')[:80]}", flush=True)
+ await self.send("Network.enable", session_id=sid)
+
+ elif method == "Network.requestWillBeSent":
+ u = m["params"]["request"]["url"]
+ if any(k in u for k in INTEREST_URL):
+ print(f"[req ] {m['params']['request']['method']} {u[:110]}", flush=True)
+
+ elif method == "Network.responseReceived":
+ p = m["params"]
+ u = p["response"]["url"]
+ mime = (p["response"].get("mimeType") or "").split(";")[0].strip()
+ interesting = mime in IMAGE_MIME or any(k in u for k in INTEREST_URL)
+ if interesting:
+ self.finished[p["requestId"]] = (u, mime)
+ print(f"[resp] {p['response']['status']} {mime or '?'} {u[:100]}", flush=True)
+
+ elif method == "Network.loadingFinished":
+ rid = m["params"]["requestId"]
+ if rid in self.finished:
+ # 立即拉响应体(需带 sessionId)
+ info = self.finished.pop(rid)
+ sid = m.get("sessionId")
+ if sid:
+ mid = await self.send("Network.getResponseBody", {"requestId": rid}, session_id=sid)
+ self.pending[mid] = info
+
+ elif "id" in m and m["id"] in self.pending and "result" in m:
+ await self.save_body(m, self.pending.pop(m["id"]))
+
+ await self.drain_bodies()
+
+ _body_seq = 100000
+
+ async def next_body_id(self):
+ Collector._body_seq += 1
+ return Collector._body_seq
+
+ async def drain_bodies(self):
+ """把已完成请求的响应体真正拉回(发 getResponseBody,响应由 recv_loop 处理)。"""
+ for rid in list(self.finished.keys()):
+ info = self.finished.pop(rid)
+ # 找到该 request 所在 session 的 sessionId(任意已 attach session 均可试)
+ for sid in self.sessions:
+ mid = await self.send("Network.getResponseBody", {"requestId": rid}, session_id=sid)
+ self.pending[mid] = info
+ break
+
+ async def save_body(self, msg, info):
+ url, mime = info
+ result = msg.get("result", {})
+ body = result.get("body", "")
+ if not body:
+ return
+ OUTDIR.mkdir(parents=True, exist_ok=True)
+ ts = time.strftime("%H%M%S")
+ if result.get("base64Encoded"):
+ # 二进制:按 mime 保存图片
+ ext = IMAGE_MIME.get(mime, "bin")
+ self.n_saved += 1
+ path = OUTDIR / f"net_{ts}_{self.n_saved}.{ext}"
+ path.write_bytes(base64.b64decode(body))
+ print(f"[save] {path.name} ({len(body)} b64, {mime}) <- {url[:80]}", flush=True)
+ else:
+ # 文本:captcha/get + captcha/verify 的 JSON 响应全存
+ if "captcha/get" in url or "captcha/verify" in url or (body.startswith("{") and ("question" in body or "captcha" in body)):
+ self.n_saved += 1
+ tag = "get" if "captcha/get" in url else "verify"
+ path = OUTDIR / f"net_{ts}_{tag}.json"
+ path.write_text(body, encoding="utf-8")
+ print(f"[save] {path.name} ({len(body)} chars) <- {url[:80]}", flush=True)
+ print(f" head: {body[:200]}", flush=True)
+
+
+async def main(minutes: float):
+ import asyncio
+ try:
+ ver = json.load(urllib.request.urlopen(f"{CDP_HTTP}/json/version", timeout=5))
+ except (OSError, ValueError) as e:
+ print(f"无法连接 CDP {CDP_HTTP}(Chrome 需带 --remote-debugging-port=9222 启动): {e}", file=sys.stderr)
+ sys.exit(1)
+ ws_url = ver["webSocketDebuggerUrl"]
+ deadline = time.time() + minutes * 60
+ async with websockets.connect(ws_url, max_size=64 * 1024 * 1024) as ws:
+ col = Collector(ws)
+ # 浏览器级 autoAttach:所有新 target(含未来弹出的验证码 iframe)自动 attach
+ await col.send("Target.setAutoAttach", {
+ "autoAttach": True, "waitForDebuggerOnStart": False, "flatten": True,
+ })
+ # 补充 attach 已存在的 target(验证码 iframe 可能已经弹出)
+ try:
+ targets = json.load(urllib.request.urlopen(f"{CDP_HTTP}/json/list", timeout=5))
+ except (OSError, ValueError):
+ targets = []
+ for t in targets:
+ if t.get("type") in ("page", "iframe", "webview") and t.get("id"):
+ await col.send("Target.attachToTarget", {"targetId": t["id"], "flatten": True})
+ print(f"[listen] auto-attach + 已存在 target attach({len(targets)}),监听 {minutes} 分钟,Ctrl+C 退出", flush=True)
+ await col.recv_loop(deadline)
+ print(f"[done] 共保存 {col.n_saved} 个文件到 {OUTDIR}", flush=True)
+
+
+if __name__ == "__main__":
+ ap = argparse.ArgumentParser()
+ ap.add_argument("--minutes", type=float, default=10)
+ args = ap.parse_args()
+ import asyncio
+ asyncio.run(main(args.minutes))
diff --git a/try/captcha_verify_watch.py b/try/captcha_verify_watch.py
new file mode 100644
index 0000000..f77ebe3
--- /dev/null
+++ b/try/captcha_verify_watch.py
@@ -0,0 +1,99 @@
+# 监听 captcha/verify 请求+响应全文(含 postData),落盘 /tmp/verify_captures/
+# 用途:对比真人 vs 自动化拖动的 verify 参数差异
+import asyncio, json, time, urllib.request, os, sys
+import websockets
+
+CDP_HTTP = "http://127.0.0.1:9222"
+OUT = "/tmp/verify_captures"
+
+
+def _cdp_json(path: str):
+ """拉取 CDP HTTP 接口的 JSON;失败返回 None。"""
+ try:
+ with urllib.request.urlopen(f"{CDP_HTTP}{path}", timeout=5) as r:
+ return json.load(r)
+ except (OSError, ValueError):
+ return None
+
+
+async def main(minutes: float = 10.0) -> None:
+ ver = _cdp_json("/json/version")
+ if not ver or "webSocketDebuggerUrl" not in ver:
+ print("无法连接 CDP 9222(Chrome 需带 --remote-debugging-port=9222)", file=sys.stderr)
+ return
+ try:
+ os.makedirs(OUT, exist_ok=True)
+ except OSError as e:
+ print(f"无法创建输出目录 {OUT}: {e}", file=sys.stderr)
+ return
+
+ async with websockets.connect(ver["webSocketDebuggerUrl"], max_size=64 * 1024 * 1024) as ws:
+ msg_id = 10
+
+ async def send(method, params=None, sid=None):
+ nonlocal msg_id
+ msg_id += 1
+ m = {"id": msg_id, "method": method, "params": params or {}}
+ if sid:
+ m["sessionId"] = sid
+ await ws.send(json.dumps(m))
+ return msg_id
+
+ await send("Target.setAutoAttach", {"autoAttach": True, "waitForDebuggerOnStart": False, "flatten": True})
+ for t in (_cdp_json("/json/list") or []):
+ if t.get("type") in ("page", "iframe"):
+ await send("Target.attachToTarget", {"targetId": t["id"], "flatten": True})
+
+ pend = {}
+ deadline = time.time() + minutes * 60
+ print("watching verify (full)...", flush=True)
+ while time.time() < deadline:
+ try:
+ raw = await asyncio.wait_for(ws.recv(), timeout=1)
+ m = json.loads(raw)
+ except asyncio.TimeoutError:
+ continue
+ except json.JSONDecodeError:
+ continue
+ if m.get("method") == "Target.attachedToTarget":
+ await send("Network.enable", sid=m["params"]["sessionId"])
+ meth = m.get("method", "")
+ if meth == "Network.requestWillBeSent" and "captcha/verify" in m["params"]["request"]["url"]:
+ ts = time.strftime("%H%M%S")
+ rec = {"ts": ts, "url": m["params"]["request"]["url"][:300],
+ "method": m["params"]["request"]["method"],
+ "post": m["params"]["request"].get("postData", "")}
+ rid = m["params"]["requestId"]
+ body_id = await send("Network.getResponseBody", {"requestId": rid}, sid=m.get("sessionId"))
+ rec["req_id"] = rid
+ rec["url_full"] = m["params"]["request"]["url"]
+ pend[body_id] = rec
+ # 同时存下请求体全文(含 captchaBody 轨迹密文)
+ path_req = f"{OUT}/verify_{ts}_req.json"
+ try:
+ with open(path_req, "w") as f:
+ json.dump(rec, f, ensure_ascii=False, indent=1)
+ except OSError as e:
+ print(f"落盘失败 {path_req}: {e}", file=sys.stderr)
+ print(f"[{ts}] VERIFY-REQ post_len={len(rec['post'])}", flush=True)
+ elif "id" in m and m["id"] in pend and "result" in m:
+ rec = pend.pop(m["id"])
+ rec["resp"] = m["result"].get("body", "")
+ path = f"{OUT}/verify_{rec['ts']}.json"
+ try:
+ with open(path, "w") as f:
+ json.dump(rec, f, ensure_ascii=False, indent=1)
+ except OSError as e:
+ print(f"落盘失败 {path}: {e}", file=sys.stderr)
+ print(f"[{rec['ts']}] VERIFY-RESP: {rec['resp'][:150]}", flush=True)
+
+
+if __name__ == "__main__":
+ try:
+ minutes = float(sys.argv[1]) if len(sys.argv) > 1 else 10.0
+ except ValueError:
+ minutes = 10.0
+ try:
+ asyncio.run(main(minutes))
+ except KeyboardInterrupt:
+ pass
diff --git a/try/captures/net_093135_get.json b/try/captures/net_093135_get.json
new file mode 100644
index 0000000..acfb908
--- /dev/null
+++ b/try/captures/net_093135_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":62,"host":"","id":"aff62a3a5e38b990b2e2794a2bc6212f92fc183a","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/026610a526b14d61a73995c1287acb1e~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/bfef530e9f754ccebfaaa28a0ad9571d~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/026610a526b14d61a73995c1287acb1e~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/026610a526b14d61a73995c1287acb1e~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/bfef530e9f754ccebfaaa28a0ad9571d~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/bfef530e9f754ccebfaaa28a0ad9571d~tplv-188rlo5p4y-1.png"],"tip_y":58,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_093136_2.jpg b/try/captures/net_093136_2.jpg
new file mode 100644
index 0000000..d17f321
Binary files /dev/null and b/try/captures/net_093136_2.jpg differ
diff --git a/try/captures/net_093244_verify.json b/try/captures/net_093244_verify.json
new file mode 100644
index 0000000..cac68eb
--- /dev/null
+++ b/try/captures/net_093244_verify.json
@@ -0,0 +1 @@
+{"code":500,"data":{"msg":"NotFoundChallengeId"},"message":"验证超时,请根据提示重新操作"}
\ No newline at end of file
diff --git a/try/captures/net_093245_6.jpg b/try/captures/net_093245_6.jpg
new file mode 100644
index 0000000..02be1a4
Binary files /dev/null and b/try/captures/net_093245_6.jpg differ
diff --git a/try/captures/net_093245_get.json b/try/captures/net_093245_get.json
new file mode 100644
index 0000000..6dd7b6b
--- /dev/null
+++ b/try/captures/net_093245_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":24,"host":"","id":"6c343a96a4aa52d00810032f5a96bb9b0353dbd9","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/71acd0f4ec1942979aa17911c0b73a1f~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/a1bb791042b847f4beaca70a005e6ebc~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/71acd0f4ec1942979aa17911c0b73a1f~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/71acd0f4ec1942979aa17911c0b73a1f~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/a1bb791042b847f4beaca70a005e6ebc~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/a1bb791042b847f4beaca70a005e6ebc~tplv-188rlo5p4y-1.png"],"tip_y":42,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_093323_get.json b/try/captures/net_093323_get.json
new file mode 100644
index 0000000..546c95c
--- /dev/null
+++ b/try/captures/net_093323_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":1,"host":"","id":"e4d75836bc889874ef1617f8c37e567987ca17a3","mode":"slide","question":{"url1":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/1b73a92ee9844cceac0331f73a73ad4f~tplv-188rlo5p4y-2.jpeg","url2":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/44c0201ac4b6483990082473bdfbb62b~tplv-188rlo5p4y-1.png","backup_url1":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/1b73a92ee9844cceac0331f73a73ad4f~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/1b73a92ee9844cceac0331f73a73ad4f~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/44c0201ac4b6483990082473bdfbb62b~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/44c0201ac4b6483990082473bdfbb62b~tplv-188rlo5p4y-1.png"],"tip_y":32,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_093324_10.jpg b/try/captures/net_093324_10.jpg
new file mode 100644
index 0000000..8ac64ab
Binary files /dev/null and b/try/captures/net_093324_10.jpg differ
diff --git a/try/captures/net_093416_verify.json b/try/captures/net_093416_verify.json
new file mode 100644
index 0000000..b7d27f8
--- /dev/null
+++ b/try/captures/net_093416_verify.json
@@ -0,0 +1 @@
+{"code":502,"data":null,"message":"检测到您的网络环境较差,请更换网络或者稍后再试[5014]"}
\ No newline at end of file
diff --git a/try/captures/net_093447_13.jpg b/try/captures/net_093447_13.jpg
new file mode 100644
index 0000000..cf0ab5e
Binary files /dev/null and b/try/captures/net_093447_13.jpg differ
diff --git a/try/captures/net_093447_get.json b/try/captures/net_093447_get.json
new file mode 100644
index 0000000..e53dc5b
--- /dev/null
+++ b/try/captures/net_093447_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":67,"host":"","id":"c1580262dc147875302303acf2fa494ce441be37","mode":"slide","question":{"url1":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/9abb14fa9b4844e5a35d04dcaaca3abc~tplv-188rlo5p4y-2.jpeg","url2":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/23eae7b1ecfc42d5ae9453a0ff337e0a~tplv-188rlo5p4y-1.png","backup_url1":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/9abb14fa9b4844e5a35d04dcaaca3abc~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/9abb14fa9b4844e5a35d04dcaaca3abc~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/23eae7b1ecfc42d5ae9453a0ff337e0a~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/23eae7b1ecfc42d5ae9453a0ff337e0a~tplv-188rlo5p4y-1.png"],"tip_y":43,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_095916_verify.json b/try/captures/net_095916_verify.json
new file mode 100644
index 0000000..69441b7
--- /dev/null
+++ b/try/captures/net_095916_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"滑动滑块进行验证","error_code":1105,"verify_center_decision_conf":"{\"code\":\"10000\",\"from\":\"shark_admin\",\"type\":\"verify\",\"version\":\"1\",\"region\":\"cn\",\"subtype\":\"slide\",\"ui_type\":\"\",\"detail\":\"keE*21mp9fplTSxKY8S*q18DkqYpVkP45MlpB4X2XX85*BzBekWaTs*Vfq5oNyZg8F-piK4mQvu8lA4znwtcf8U8FgBSYgHoDCXNA8xly5CDnZR8WuRThqSQjUUlHnsQks3SWYBhUEaRUJ-l8uL*Zn6Ixmj*1ILU6526l0sLF3PlTa6w-sM9EBmy-LWclUMLjknhk9THXgM1C4Nc5eEVykE0pZWXivQYj68SpjhtTP41bVwGb9Y5yCWj1NLul2tkXrCQVpFKX6Rj6cYNZsZR3abCbF83s0-JN11KF*7*NTTxAOJ1dpnj8-XqWqb-QkB2qGVbGVsR1HuBtqiIvS5U9v*7Vv1wYULIBE-9KrIjRnHpyPLDncl3Z9zQYf6jndBN\",\"verify_event\":\"tt_user_pwd_login\",\"fp\":\"verify_mtwarf05_T2cF4uRW_4ewx_4A4K_9lxP_FRjbBMt9WYRC\",\"verify_ticket\":\"VTIDEFCZB7MQAWNFHTFJ7RJMGWHUSHBH2PNJ8Z_lf\",\"server_sdk_env\":\"{\\\"idc\\\":\\\"lf\\\",\\\"region\\\":\\\"CN\\\",\\\"server_type\\\":\\\"passport\\\"}\",\"log_id\":\"202609141000077765FE8E5A3D2F25CEDB\",\"is_assist_mobile\":false,\"is_complex_sms\":false,\"identity_action\":\"\",\"identity_scene\":\"\",\"verify_scene\":\"passport\",\"login_status\":0,\"aid\":0,\"replay_data\":{\"x-tt-passport-replay-params\":\"{}\"}}","verify_ticket":"VTIDEFCZB7MQAWNFHTFJ7RJMGWHUSHBH2PNJ8Z_lf"},"message":"error"}
\ No newline at end of file
diff --git a/try/captures/net_095921_verify.json b/try/captures/net_095921_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_095921_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_095926_verify.json b/try/captures/net_095926_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_095926_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_095931_verify.json b/try/captures/net_095931_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_095931_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_095936_verify.json b/try/captures/net_095936_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_095936_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_095941_verify.json b/try/captures/net_095941_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_095941_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_095947_verify.json b/try/captures/net_095947_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_095947_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_095952_verify.json b/try/captures/net_095952_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_095952_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_095957_verify.json b/try/captures/net_095957_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_095957_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100002_verify.json b/try/captures/net_100002_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100002_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100007_verify.json b/try/captures/net_100007_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100007_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100012_verify.json b/try/captures/net_100012_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100012_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100018_verify.json b/try/captures/net_100018_verify.json
new file mode 100644
index 0000000..4e38388
--- /dev/null
+++ b/try/captures/net_100018_verify.json
@@ -0,0 +1 @@
+{"data":{"app_name":"抖音","captcha":"","desc_url":"","description":"","error_code":0,"expire_time":1789351330,"frontier_params":{"access_key":"d8b2e550d05b7afcfea970017e05bc44","frontier_device":"7657740123052901934","method":1,"product_id":971,"service_id":1024},"is_frontier":true,"qrcode":"iVBORw0KGgoAAAANSUhEUgAAAgAAAAIAAQMAAADOtka5AAAABlBMVEX///8AAABVwtN+AAAC2klEQVR42uycPZLqSgyFRTkgZAksZZZmL81LYQmEDij0ymqpf57bd0hu1bX5TjQew0ekknSkbkEIIYQQQgihf10/mjUP+hC52d8vkYs+RJ8yxlPWGwAAAD1APF4NcNGnqOpkL+6af8Re/O8bAACcDXBfI2S66izpz/Xfg86XFFqTPQVZXwAAAPgdMKTMIyKjfy6/AADgqwAid385epWWajYAAAB8BshlnmWmKPNMmSwf1YkAABwZ0Lb/FjOLZ6a7rlVaZKbP/AMAAL4WUGtYX95UF3uKlidF40cCAODAgFSlZfvY09FajFngPGVccvsvV52Gjq8MAACAyEwegjGkWTwwRRLgx4c0ct1LbQAAnADwbjobB4wWTA9zAhb7kXdyAqZ+zwQAAICSmZaci7JlFiabamp51swEAMBZAbHwIlWXv/grI3v2eie/bVulAQAAoIpGH/JX0/+o/2TthWLfzJ8EAIAzAupZTPQ56jGT1spaX/nVNdQAAACQQ7DyD6pqLn8rJakrAADnBViXXz5n31rMZfaWR7VeCwAAAMAeIJ93Kf5BisZqrUy1nArY7ZkAADg4INnH7ZDfuvy5WbFUz15jPxoBAADg1VwMNqOam8rEM405bV6TTLbulAcAgMMDUvsfmzBRpUUvVHb3Pcp0x0sDAABARGPWLU5YSvHSfj09AADA8QHteZfqIEwc3R8bL63TMwEAAKCd/ouXeXni+S5udNE0bFIbAADnAKQ8c2tWLDefK+1/9yAMAAAANqfKYsg/xfTmWfy2WAuYAQA4JWBz8Z6pvRMmD2kW74UAAAAgO1VabI/VE8/KZCvRuOOlAQBwCsDmfqRmYDlVARcrMgAAAPgzYMg3v47NhcizX5BRpSwAAL4BUN0JU5aU4+h+bxMGAAAAm5v70ucq9+zZGAu7uzgAAJwA0LT/1SwmDoX5nTC+Vtbd0QQAAABCCCGEEEII/RX9FwAA//8dSDEKVp+WDwAAAABJRU5ErkJggg==","qrcode_index_url":"https://api.amemv.com/ucenter_web/app/aweme/scan_login/index/douyin_scan_code_login/cn/app/index.html?_pia_=1\u0026hide_nav_bar=1\u0026is_new_login=1\u0026loader_name=forest\u0026next_url=https%3A%2F%2Fapi.amemv.com%2Fpassport%2Fmobile%2Fscan_qrcode%2F\u0026qr_source_aid=6383\u0026scene=\u0026source=\u0026token=69b8d3dcdf195aecdf6520bcd9eba481_hl\u0026verify_reason=\u0026verify_scene=\u0026verify_ticket=\u0026web_app_from=rcode","status":"expired","token":"69b8d3dcdf195aecdf6520bcd9eba481_hl","web_name":"抖音"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100144_verify.json b/try/captures/net_100144_verify.json
new file mode 100644
index 0000000..7c6fa90
--- /dev/null
+++ b/try/captures/net_100144_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"该账号无法使用密码登录,建议切换其他方式登录。","error_code":1467},"message":"error"}
\ No newline at end of file
diff --git a/try/captures/net_100316_verify.json b/try/captures/net_100316_verify.json
new file mode 100644
index 0000000..05509b5
--- /dev/null
+++ b/try/captures/net_100316_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"滑动滑块进行验证","error_code":1105,"verify_center_decision_conf":"{\"code\":\"10000\",\"from\":\"shark_admin\",\"type\":\"verify\",\"version\":\"1\",\"region\":\"cn\",\"subtype\":\"slide\",\"ui_type\":\"\",\"detail\":\"toTgLwS9uO13EtqVaJDHJ-qstyOnPPfOfcAHf6eBuN61SkpAmMqhpVtEa4SO8vz2mm598XJTGCmrvwgvRDn5T1C4Qeq1jFNzKm9q3MRjTkie0B7CcvBvHs8hOY0M3RccOvINVYOPNO2rzyRCcdwiknFgNiPSpzdLEkAUEfdD9r4cRoJQrJDvGeAWm6gIjfm*rs1DSXydXHy1oZyeSn1XsgzCzMSufW9ab8P8KKObQqr2mbsB4DhQafbWRGLMWfwIRHDnvQoTrBSFYVWwLFtaxoGcK*be5haJjgIq5XFQ-jEpM2JfNnj99nuEigLQ7nCt5utlGBCU18jRYOBs1Wy8J2eDta7OplM5SMctGky4sLPzZ9DJ86Z1oHqGrMRUbDJl\",\"verify_event\":\"tt_user_pwd_login\",\"fp\":\"verify_mtwarf05_T2cF4uRW_4ewx_4A4K_9lxP_FRjbBMt9WYRC\",\"verify_ticket\":\"VTIDEFWMPR3Z4QNF6R6Y78Z447YKN7YSR4N9RA_hl\",\"server_sdk_env\":\"{\\\"idc\\\":\\\"hl\\\",\\\"region\\\":\\\"CN\\\",\\\"server_type\\\":\\\"passport\\\"}\",\"log_id\":\"20260914100408EEF5625A1F8DCD833250\",\"is_assist_mobile\":false,\"is_complex_sms\":false,\"identity_action\":\"\",\"identity_scene\":\"\",\"verify_scene\":\"passport\",\"login_status\":0,\"aid\":0,\"replay_data\":{\"x-tt-passport-replay-params\":\"{}\"}}","verify_ticket":"VTIDEFWMPR3Z4QNF6R6Y78Z447YKN7YSR4N9RA_hl"},"message":"error"}
\ No newline at end of file
diff --git a/try/captures/net_100321_verify.json b/try/captures/net_100321_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100321_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100327_verify.json b/try/captures/net_100327_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100327_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100332_verify.json b/try/captures/net_100332_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100332_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100337_verify.json b/try/captures/net_100337_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100337_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100342_verify.json b/try/captures/net_100342_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100342_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100348_verify.json b/try/captures/net_100348_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100348_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100350_verify.json b/try/captures/net_100350_verify.json
new file mode 100644
index 0000000..7c6fa90
--- /dev/null
+++ b/try/captures/net_100350_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"该账号无法使用密码登录,建议切换其他方式登录。","error_code":1467},"message":"error"}
\ No newline at end of file
diff --git a/try/captures/net_100353_verify.json b/try/captures/net_100353_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100353_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100358_verify.json b/try/captures/net_100358_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100358_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100403_verify.json b/try/captures/net_100403_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100403_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100409_verify.json b/try/captures/net_100409_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100409_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100414_verify.json b/try/captures/net_100414_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100414_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100419_verify.json b/try/captures/net_100419_verify.json
new file mode 100644
index 0000000..2b6804b
--- /dev/null
+++ b/try/captures/net_100419_verify.json
@@ -0,0 +1 @@
+{"data":{"app_name":"抖音","captcha":"","desc_url":"","description":"","error_code":0,"expire_time":1789351571,"frontier_params":{"access_key":"d8b2e550d05b7afcfea970017e05bc44","frontier_device":"7657740123052901934","method":1,"product_id":971,"service_id":1024},"is_frontier":true,"qrcode":"iVBORw0KGgoAAAANSUhEUgAAAgAAAAIAAQMAAADOtka5AAAABlBMVEX///8AAABVwtN+AAAC2klEQVR42uzcMXYiMQyAYfEoKPcIcxSONhwtR8kRKKeYN9pnW5I14IQUWyyTXxUJw0flZ1mSEYIgCIIgCIIgiP89rhrxITKp3st/5/qXiN5lXupzp/7cBgAAMAL8z4t+nPXTXupaPvIp8kdvYsD98RMAAEcDprJCbg2oz130dlbdrbIKlNcrAADATwAtO5MuIufdzmQyAMBvAexfAUya9ykAAIBXQKR5ItPWgHltZyFL83zLepUnAgC8M5CSMd+AGlBWWQE8fftB/QAA4DcDOSzNEymApJ1JrbDwKgAA3hh4qKXVNbPUuvIpKmtRcL54MQAAAOAJEHtzXuS6Rv05mjT1LKSrnYUUAOC4QF1MOUtTtU3Ks7T+JS19EwAAgCHgB5nF0rwKzF4yq8B1bfW2789MAABvD9Qmf6sZp2RMvZZ2yXWB4VgZAABAHHlS/Vk192JcrmNlNhawAQAcEajTY+XIU5/0XsxsH4kRS19lt/PTmQkAAKB3/8uiWyyb2z3XuPLGFgtzND4AAPD+gJx2Q8plL0rpW8/ZtvYlz91/AACAHL4a5RQzmrXN2QoLaZkOViMAwJEA6WtGJJ1srHtjJYL8DAAAwOj43+vPfUbT71TaILPPKwMAHBVoR56YHjv1fo11Mq1haUee26iuDAAAEE0an9H8tIwvzStHZya9BAA4IuDP1UkY3eJS2L5hWY//ad4MAABgPK88SvPSM73jqes33X8AgLcGbGeKVeKn/Dq7b/PKPQbjAwAAAONbZapx32XyQ4798lLkfwAABwSujz+DpL18HGMB2q8hP2dpAAAATzcsbf2ld9tq9N3r61tlAACHANLvI01bTML41f25FwOM2wAAAF4CcSs5Df/vC9PnYccTAOBwgDcse8E5NyxrlgYAAPAVMEjzZjvy2F607i6YCQDAIYHdD++lZMwvhaXZ/VZv+wAAABgBBEEQBEEQBEEQ/z7+BgAA//+F7UMbrdeyuwAAAABJRU5ErkJggg==","qrcode_index_url":"https://api.amemv.com/ucenter_web/app/aweme/scan_login/index/douyin_scan_code_login/cn/app/index.html?_pia_=1\u0026hide_nav_bar=1\u0026is_new_login=1\u0026loader_name=forest\u0026next_url=https%3A%2F%2Fapi.amemv.com%2Fpassport%2Fmobile%2Fscan_qrcode%2F\u0026qr_source_aid=6383\u0026scene=\u0026source=\u0026token=af6118efba5520f3502c3865bce72067_hl\u0026verify_reason=\u0026verify_scene=\u0026verify_ticket=\u0026web_app_from=rcode","status":"expired","token":"af6118efba5520f3502c3865bce72067_hl","web_name":"抖音"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100532_verify.json b/try/captures/net_100532_verify.json
new file mode 100644
index 0000000..50abfda
--- /dev/null
+++ b/try/captures/net_100532_verify.json
@@ -0,0 +1 @@
+{"data":{"app_name":"抖音","captcha":"","copywriting":"{\"desc\":\"为保障账号安全,请使用[color=red]「抖音 APP」[/]扫码验证,以确保为本人操作\",\"page_title\":\"身份验证\",\"title\":\"请使用已登录账号的设备扫码\"}","desc_url":"","description":"","error_code":0,"expire_time":1789351644,"frontier_params":{"access_key":"d8b2e550d05b7afcfea970017e05bc44","frontier_device":"7657740123052901934","method":1,"product_id":971,"service_id":1024},"is_frontier":true,"qrcode":"iVBORw0KGgoAAAANSUhEUgAAAgAAAAIAAQMAAADOtka5AAAABlBMVEX///8AAABVwtN+AAACzklEQVR42uzcMbLqOgyAYWVSUJ4lZClnabA0lsISKCky0RtblmyI4XFnbnExvyrA4es8smU5QhAEQRAEQRAE8a/Hr0acRWSyj6c8cBH5yV/XGEixAQAA9AD/ekjAstnHxE0FuOXhSa+P/wAAGA1Y8vQ56HlOH64JOEk7fc4FsHkFAADwBuDz71ieqwMAAN8F5Eg/zzlPaclT65/MRgCA7wVimTen7cyPpszkli3zymz833UiAMAnA8323xOQZ6YlAZGZ3qgfAAB8M9DGXAdzZspxzH+6vFWkBgD4YMBXae0u/5b+5YAV2aIYsAIAAPSBPFKsVZat1A9yAlpUr3K8pQF77NDLTAAAgwDSq6VZkrJVmj/jy7d9AAAAeGaKg814zjNTHkjTVEstrXf6DwAwApCjbv+b8/7ClRJBaQs4zQAAAE+BRaOsFgebXjTItTQ/pAEAGBn4bZ5T64Qpi7HJvh1ryjLgLAAAAK+AuvsRiUOaKKA50CnGAQAMA3hfpd536+flmw/oFsu37uk/AACAlDLBqRambdLlaVruxKxlmh46bWUAAKMAU3kuD9ohjebF2BRTy3sv+4VpAACA3opvsudkVu1evXzZVgYA8PFA2uU3xzKWjvwijO2FthjoBQAAgG15Hnr8/bqyattW9qr5HwBgAGCLOlkkoNpWFr37dkNG7novAQAAdrfK4pD/UgG/YRk9ms8K0wAAIwHNWYxvec61kVnq9r97EQYAAGB/q6yWzEK29V/eGXnKAgAYELh/8V5zEcYyk/Ura72GrJ1OGAAAgN17MNrC9BZFNr+u/MY7YQAAPhlo34/0OJnylqc5sum0WAIAAPSBWPFt0WMTZzm3u3dlAACMDGi8KtxaZK71xXveViYCAADwrK5cDzb3sl1XlrrMAwAYFHh88V7MmWYyaRxYyvyqfgAA8M0AQRAEQRAEQRDE34//AgAA//9AniUeTGmGdQAAAABJRU5ErkJggg==","qrcode_index_url":"https://api.amemv.com/ucenter_web/app/aweme/scan_login/index/douyin_scan_code_login/cn/app/index.html?_pia_=1\u0026hide_nav_bar=1\u0026is_new_login=1\u0026loader_name=forest\u0026next_url=https%3A%2F%2Fapi.amemv.com%2Fpassport%2Fmobile%2Fscan_qrcode%2F\u0026qr_source_aid=6383\u0026scene=\u0026source=\u0026token=45e8748c0b5d25dd34a9c3993de34407_lf\u0026verify_reason=\u0026verify_scene=\u0026verify_ticket=\u0026web_app_from=rcode","token":"45e8748c0b5d25dd34a9c3993de34407_lf","web_name":"抖音"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100537_verify.json b/try/captures/net_100537_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100537_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100542_verify.json b/try/captures/net_100542_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100542_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100547_verify.json b/try/captures/net_100547_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100547_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100552_verify.json b/try/captures/net_100552_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100552_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100558_verify.json b/try/captures/net_100558_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100558_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100603_verify.json b/try/captures/net_100603_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100603_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100608_verify.json b/try/captures/net_100608_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100608_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100613_verify.json b/try/captures/net_100613_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100613_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100619_verify.json b/try/captures/net_100619_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100619_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100624_verify.json b/try/captures/net_100624_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100624_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100629_verify.json b/try/captures/net_100629_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_100629_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_100634_verify.json b/try/captures/net_100634_verify.json
new file mode 100644
index 0000000..72e91b1
--- /dev/null
+++ b/try/captures/net_100634_verify.json
@@ -0,0 +1 @@
+{"data":{"app_name":"抖音","captcha":"","desc_url":"","description":"","error_code":0,"expire_time":1789351706,"frontier_params":{"access_key":"d8b2e550d05b7afcfea970017e05bc44","frontier_device":"7657740123052901934","method":1,"product_id":971,"service_id":1024},"is_frontier":true,"qrcode":"iVBORw0KGgoAAAANSUhEUgAAAgAAAAIAAQMAAADOtka5AAAABlBMVEX///8AAABVwtN+AAACy0lEQVR42uzdPbKjMAzAcWUoKHOEHCVHC0fLUThCSopMvBPLkgU4H8UWD/JXtQT4beWxJcs8IQiCIAiCIAiC+OtxTh7XLo3Pn/yH0f55FznU5x4AAAAtwC77DDyfkz4N+adT8v9kPKTb8g0AgL0Bp+cIGfp0XY6yUeSYrU4BHVcAAAAfgU5nHhG5lOf8BgDATwEip4ccCyAHHUxl+QYAAPAZ8GWeqDVPcsqU9dU6EQBgy8A8/c9jZioz0yk9V2k1F/qmfgAA8LNAjLzMs0GXR2MBvi1SAwBsGNBV2k0uOh3luvJUVmmZu0ye/kufhq5RVwYAADDgmeTocxVweZJz4aRvb9IAAOwB0Ds55Un3kvJMNf3P8jm/lSsBwyrlAQAAmEd5Lvmgs2rCkK/CVigAwD6B/FYpH4vORZr9hKuzTUfNVRoAAECIvMm/moB0/Wf9Zke7EgCAPQL2XNykmXIxINwIdeV7s5YGAABQqmc6AYW25Lu3BeiVTlI9AMB+ASuZSW0r88Fkbfy2YHs9GgEAAGrKY/UD3YupO57lTExpK3uTMwEAbBvwlKevvWQ6mFJssUyh4CwAAABtIJTM9JUwM+naLvlWqLQq2wAAuwAOaRTthAlZvp+wPMZjyK92/wEAABbLvLsehNHReK1tAZ+b/wEAtg/EVZpt8ofTxlJ6L61E8D7lAQD4acBmpjoaV0W2EEO32jIFANgHcA6ZTe3d1zMx4+yETE7/mwdhAAAAVqfKxtrjfz34GTObpNrDGQBgH8D8tHEqKY+3BYR+5VsZZQAAAG1g9uU+n4A6L0z7fk3oBQAA2Cew+vCe7f6PoZF50SIDAADwDrBNmnB0fzZlhU/6AQD8AhCOIde6gOVCL3o0AQAAFl/ue8xraX7e0obpx0//AQBsFmj8DYrJK8nlTP/8w0kCAADwsl+ZIAiCIAiCIAjif8a/AAAA//8kfGJ+GmIouAAAAABJRU5ErkJggg==","qrcode_index_url":"https://api.amemv.com/ucenter_web/app/aweme/scan_login/index/douyin_scan_code_login/cn/app/index.html?_pia_=1\u0026hide_nav_bar=1\u0026is_new_login=1\u0026loader_name=forest\u0026next_url=https%3A%2F%2Fapi.amemv.com%2Fpassport%2Fmobile%2Fscan_qrcode%2F\u0026qr_source_aid=6383\u0026scene=\u0026source=\u0026token=621de9524be86e20eb2f8b7fdf1c3416_lf\u0026verify_reason=\u0026verify_scene=\u0026verify_ticket=\u0026web_app_from=rcode","status":"expired","token":"621de9524be86e20eb2f8b7fdf1c3416_lf","web_name":"抖音"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_165541_get.json b/try/captures/net_165541_get.json
new file mode 100644
index 0000000..be4729d
--- /dev/null
+++ b/try/captures/net_165541_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":66,"host":"","id":"74139ac7f8d7f6720414ef8a5b8c6e38c4af2020","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/279e20b118fa47e0a6eaa35061ddd023~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/1a76d9f7cab941f5b4a48768f07b5d55~tplv-188rlo5p4y-1.png","backup_url1":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/279e20b118fa47e0a6eaa35061ddd023~tplv-188rlo5p4y-2.jpeg","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/279e20b118fa47e0a6eaa35061ddd023~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/1a76d9f7cab941f5b4a48768f07b5d55~tplv-188rlo5p4y-1.png","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/1a76d9f7cab941f5b4a48768f07b5d55~tplv-188rlo5p4y-1.png"],"tip_y":73,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_165900_get.json b/try/captures/net_165900_get.json
new file mode 100644
index 0000000..cb843ea
--- /dev/null
+++ b/try/captures/net_165900_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":51,"host":"","id":"db00e213fd73eaebeecbe373a8468185070cd5de","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/11303a0e5f184d39b3474e9122bdc50a~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/5fba792e01bd41558ed784863088f391~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/11303a0e5f184d39b3474e9122bdc50a~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/11303a0e5f184d39b3474e9122bdc50a~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/5fba792e01bd41558ed784863088f391~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/5fba792e01bd41558ed784863088f391~tplv-188rlo5p4y-1.png"],"tip_y":27,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_165904_get.json b/try/captures/net_165904_get.json
new file mode 100644
index 0000000..79d5337
--- /dev/null
+++ b/try/captures/net_165904_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":33,"host":"","id":"819f7fba7a896323f7dc47a4d9ad4e7a39908325","mode":"slide","question":{"url1":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0f9db01697d94430ae3935bcfe907605~tplv-188rlo5p4y-2.jpeg","url2":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/be6cd78ab66a4352ab9c0c751a55a063~tplv-188rlo5p4y-1.png","backup_url1":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0f9db01697d94430ae3935bcfe907605~tplv-188rlo5p4y-2.jpeg","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0f9db01697d94430ae3935bcfe907605~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/be6cd78ab66a4352ab9c0c751a55a063~tplv-188rlo5p4y-1.png","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/be6cd78ab66a4352ab9c0c751a55a063~tplv-188rlo5p4y-1.png"],"tip_y":81,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_170108_14.jpg b/try/captures/net_170108_14.jpg
new file mode 100644
index 0000000..fefd9e4
Binary files /dev/null and b/try/captures/net_170108_14.jpg differ
diff --git a/try/captures/net_170108_get.json b/try/captures/net_170108_get.json
new file mode 100644
index 0000000..eca5b68
--- /dev/null
+++ b/try/captures/net_170108_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":87,"host":"","id":"bc7278d7fb26b2b6d7fc5e2f2299527e8b42a3e3","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/89c6fe5731014ce1976eeaa9077cc5cf~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/2aad9aec93a04b398e15040c67ef5f44~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/89c6fe5731014ce1976eeaa9077cc5cf~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/89c6fe5731014ce1976eeaa9077cc5cf~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/2aad9aec93a04b398e15040c67ef5f44~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/2aad9aec93a04b398e15040c67ef5f44~tplv-188rlo5p4y-1.png"],"tip_y":72,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_170158_18.jpg b/try/captures/net_170158_18.jpg
new file mode 100644
index 0000000..3af9872
Binary files /dev/null and b/try/captures/net_170158_18.jpg differ
diff --git a/try/captures/net_170158_get.json b/try/captures/net_170158_get.json
new file mode 100644
index 0000000..ae214da
--- /dev/null
+++ b/try/captures/net_170158_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":72,"host":"","id":"764bbfa73dabb10a014955924919850efb730a55","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/c6da8c3fd81343e5bb5dbe9292a55871~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/8c16a01f1c804b7b85a159f1a5b64751~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/c6da8c3fd81343e5bb5dbe9292a55871~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/c6da8c3fd81343e5bb5dbe9292a55871~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/8c16a01f1c804b7b85a159f1a5b64751~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/8c16a01f1c804b7b85a159f1a5b64751~tplv-188rlo5p4y-1.png"],"tip_y":77,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_170305_get.json b/try/captures/net_170305_get.json
new file mode 100644
index 0000000..5df3883
--- /dev/null
+++ b/try/captures/net_170305_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":97,"host":"","id":"180bf869c8de5ee7acd4c33e27227509838f387c","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/c1c130d1a027459ea342f2ecc921cbff~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/4714d31d39e84b5a9049276225342466~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/c1c130d1a027459ea342f2ecc921cbff~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/c1c130d1a027459ea342f2ecc921cbff~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/4714d31d39e84b5a9049276225342466~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/4714d31d39e84b5a9049276225342466~tplv-188rlo5p4y-1.png"],"tip_y":53,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_170444_get.json b/try/captures/net_170444_get.json
new file mode 100644
index 0000000..d28af39
--- /dev/null
+++ b/try/captures/net_170444_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":34,"host":"","id":"05f12892083f7f8f5e684da816f0b4bf153bcc07","mode":"slide","question":{"url1":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/53aa158f8c524a5a8d54a1e067572162~tplv-188rlo5p4y-2.jpeg","url2":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/16b3142c91d24a509f3036e4573c3f7b~tplv-188rlo5p4y-1.png","backup_url1":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/53aa158f8c524a5a8d54a1e067572162~tplv-188rlo5p4y-2.jpeg","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/53aa158f8c524a5a8d54a1e067572162~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/16b3142c91d24a509f3036e4573c3f7b~tplv-188rlo5p4y-1.png","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/16b3142c91d24a509f3036e4573c3f7b~tplv-188rlo5p4y-1.png"],"tip_y":25,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_170646_get.json b/try/captures/net_170646_get.json
new file mode 100644
index 0000000..e97c54d
--- /dev/null
+++ b/try/captures/net_170646_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":82,"host":"","id":"43f0e7b1443a0229040dd05a66d39d8bca769d3c","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/85b313fec0e3447987a63f6bc77f0849~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/b654eb5f6a23450989d3787702998fec~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/85b313fec0e3447987a63f6bc77f0849~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/85b313fec0e3447987a63f6bc77f0849~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/b654eb5f6a23450989d3787702998fec~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/b654eb5f6a23450989d3787702998fec~tplv-188rlo5p4y-1.png"],"tip_y":87,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_171109_get.json b/try/captures/net_171109_get.json
new file mode 100644
index 0000000..eff5a79
--- /dev/null
+++ b/try/captures/net_171109_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":93,"host":"","id":"1fa66e4ec5a93013dbdce6e195d6c012d3450258","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/261106ff8d9049459d9db6b1b2700017~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/c0387784042b4ffbbbcc580f7aa83e58~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/261106ff8d9049459d9db6b1b2700017~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/261106ff8d9049459d9db6b1b2700017~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/c0387784042b4ffbbbcc580f7aa83e58~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/c0387784042b4ffbbbcc580f7aa83e58~tplv-188rlo5p4y-1.png"],"tip_y":81,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_171237_get.json b/try/captures/net_171237_get.json
new file mode 100644
index 0000000..a2b4494
--- /dev/null
+++ b/try/captures/net_171237_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":24,"host":"","id":"33d637c34fa70ba243f6d9f501f3f60388e178b6","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/04415ef849754456a6c839e0e32dea7d~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/69d0386562774aa3960fe5d94c7ca5ce~tplv-188rlo5p4y-1.png","backup_url1":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/04415ef849754456a6c839e0e32dea7d~tplv-188rlo5p4y-2.jpeg","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/04415ef849754456a6c839e0e32dea7d~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/69d0386562774aa3960fe5d94c7ca5ce~tplv-188rlo5p4y-1.png","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/69d0386562774aa3960fe5d94c7ca5ce~tplv-188rlo5p4y-1.png"],"tip_y":68,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_171342_get.json b/try/captures/net_171342_get.json
new file mode 100644
index 0000000..92b0506
--- /dev/null
+++ b/try/captures/net_171342_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":43,"host":"","id":"c8df3af78dfa67f5e70e2d0c9a4bcd341542b1d0","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/d8296d67851942cf9eebf86f0f5a96d3~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/faab120f393f484c9d3c62cf1ee1e397~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/d8296d67851942cf9eebf86f0f5a96d3~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/d8296d67851942cf9eebf86f0f5a96d3~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/faab120f393f484c9d3c62cf1ee1e397~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/faab120f393f484c9d3c62cf1ee1e397~tplv-188rlo5p4y-1.png"],"tip_y":53,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_171412_get.json b/try/captures/net_171412_get.json
new file mode 100644
index 0000000..bb81c32
--- /dev/null
+++ b/try/captures/net_171412_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":61,"host":"","id":"a7e0a4151261a079c38930cc0c85f7753adf1330","mode":"slide","question":{"url1":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/d403cb0a2d9242bd8618fb6e83f41bac~tplv-188rlo5p4y-2.jpeg","url2":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/64b8b3fb28774538ab3a18b716a105f3~tplv-188rlo5p4y-1.png","backup_url1":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/d403cb0a2d9242bd8618fb6e83f41bac~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/d403cb0a2d9242bd8618fb6e83f41bac~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/64b8b3fb28774538ab3a18b716a105f3~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/64b8b3fb28774538ab3a18b716a105f3~tplv-188rlo5p4y-1.png"],"tip_y":69,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_171413_11.jpg b/try/captures/net_171413_11.jpg
new file mode 100644
index 0000000..f332a4f
Binary files /dev/null and b/try/captures/net_171413_11.jpg differ
diff --git a/try/captures/net_171511_get.json b/try/captures/net_171511_get.json
new file mode 100644
index 0000000..0b784a1
--- /dev/null
+++ b/try/captures/net_171511_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":38,"host":"","id":"223f9fba55722c63e929d676e0c676995e8e74d4","mode":"slide","question":{"url1":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/4d05142b42754e688d47146a5bb0ed32~tplv-188rlo5p4y-2.jpeg","url2":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/655c8a556b1840c8b5e3c16b3128546c~tplv-188rlo5p4y-1.png","backup_url1":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/4d05142b42754e688d47146a5bb0ed32~tplv-188rlo5p4y-2.jpeg","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/4d05142b42754e688d47146a5bb0ed32~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/655c8a556b1840c8b5e3c16b3128546c~tplv-188rlo5p4y-1.png","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/655c8a556b1840c8b5e3c16b3128546c~tplv-188rlo5p4y-1.png"],"tip_y":38,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_174630_get.json b/try/captures/net_174630_get.json
new file mode 100644
index 0000000..d2eba62
--- /dev/null
+++ b/try/captures/net_174630_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":53,"host":"","id":"45543c41428c82fbc6594ba9206314b2f7a83b2d","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0701d5d1399a47cda548015f66df919f~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/7db3817546ff440698965686485b692d~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0701d5d1399a47cda548015f66df919f~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0701d5d1399a47cda548015f66df919f~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/7db3817546ff440698965686485b692d~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/7db3817546ff440698965686485b692d~tplv-188rlo5p4y-1.png"],"tip_y":30,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_174742_5.jpg b/try/captures/net_174742_5.jpg
new file mode 100644
index 0000000..2ff5302
Binary files /dev/null and b/try/captures/net_174742_5.jpg differ
diff --git a/try/captures/net_174742_get.json b/try/captures/net_174742_get.json
new file mode 100644
index 0000000..870a9ae
--- /dev/null
+++ b/try/captures/net_174742_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":89,"host":"","id":"42c3d7d05017f067aecfe8de26fab665079511b3","mode":"slide","question":{"url1":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/7043266546954442a176664ff6f7ce6e~tplv-188rlo5p4y-2.jpeg","url2":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/52ade76e082c4fc38d70e2e28d5d9b10~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/7043266546954442a176664ff6f7ce6e~tplv-188rlo5p4y-2.jpeg","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/7043266546954442a176664ff6f7ce6e~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/52ade76e082c4fc38d70e2e28d5d9b10~tplv-188rlo5p4y-1.png","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/52ade76e082c4fc38d70e2e28d5d9b10~tplv-188rlo5p4y-1.png"],"tip_y":72,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_175019_get.json b/try/captures/net_175019_get.json
new file mode 100644
index 0000000..884ad49
--- /dev/null
+++ b/try/captures/net_175019_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":81,"host":"","id":"676989a43195854977ad08a017644f06160fb315","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/81230bfc863a4f5fa08a232d265bed49~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/3e3ef6a071684f1ea1d5ef2314b073c4~tplv-188rlo5p4y-1.png","backup_url1":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/81230bfc863a4f5fa08a232d265bed49~tplv-188rlo5p4y-2.jpeg","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/81230bfc863a4f5fa08a232d265bed49~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/3e3ef6a071684f1ea1d5ef2314b073c4~tplv-188rlo5p4y-1.png","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/3e3ef6a071684f1ea1d5ef2314b073c4~tplv-188rlo5p4y-1.png"],"tip_y":95,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_175109_verify.json b/try/captures/net_175109_verify.json
new file mode 100644
index 0000000..8279f82
--- /dev/null
+++ b/try/captures/net_175109_verify.json
@@ -0,0 +1 @@
+{"code":500,"data":{"msg":"VerifyErr"},"message":"验证失败,请根据提示重新操作"}
\ No newline at end of file
diff --git a/try/captures/net_175110_get.json b/try/captures/net_175110_get.json
new file mode 100644
index 0000000..d82710d
--- /dev/null
+++ b/try/captures/net_175110_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":97,"host":"","id":"915a5f24aa81d3737f9ade5f4c9aca8d289cf66d","mode":"slide","question":{"url1":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/01661cd33b1d42efb0e6215105287e0f~tplv-188rlo5p4y-2.jpeg","url2":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/bfc1eeb90aba4864b586d0dab93bffd3~tplv-188rlo5p4y-1.png","backup_url1":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/01661cd33b1d42efb0e6215105287e0f~tplv-188rlo5p4y-2.jpeg","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/01661cd33b1d42efb0e6215105287e0f~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/bfc1eeb90aba4864b586d0dab93bffd3~tplv-188rlo5p4y-1.png","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/bfc1eeb90aba4864b586d0dab93bffd3~tplv-188rlo5p4y-1.png"],"tip_y":24,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_175111_6.jpg b/try/captures/net_175111_6.jpg
new file mode 100644
index 0000000..973192a
Binary files /dev/null and b/try/captures/net_175111_6.jpg differ
diff --git a/try/captures/net_175334_verify.json b/try/captures/net_175334_verify.json
new file mode 100644
index 0000000..cac68eb
--- /dev/null
+++ b/try/captures/net_175334_verify.json
@@ -0,0 +1 @@
+{"code":500,"data":{"msg":"NotFoundChallengeId"},"message":"验证超时,请根据提示重新操作"}
\ No newline at end of file
diff --git a/try/captures/net_175335_get.json b/try/captures/net_175335_get.json
new file mode 100644
index 0000000..f2777b3
--- /dev/null
+++ b/try/captures/net_175335_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":82,"host":"","id":"bb6bc15b283564a831af01c3eabe475a284e10a9","mode":"slide","question":{"url1":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/3937d1d2756c4d5b9903c874e9f41a9c~tplv-188rlo5p4y-2.jpeg","url2":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/5ecd057426154fe9a6372fd4b840d79a~tplv-188rlo5p4y-1.png","backup_url1":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/3937d1d2756c4d5b9903c874e9f41a9c~tplv-188rlo5p4y-2.jpeg","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/3937d1d2756c4d5b9903c874e9f41a9c~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/5ecd057426154fe9a6372fd4b840d79a~tplv-188rlo5p4y-1.png","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/5ecd057426154fe9a6372fd4b840d79a~tplv-188rlo5p4y-1.png"],"tip_y":54,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_180857_get.json b/try/captures/net_180857_get.json
new file mode 100644
index 0000000..b82c311
--- /dev/null
+++ b/try/captures/net_180857_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":75,"host":"","id":"2617e98d2b4615811177130ea09802793c9cb605","mode":"slide","question":{"url1":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0ebaaae97e4147e28704d6de684c7d58~tplv-188rlo5p4y-2.jpeg","url2":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/dee09afee0fd44389a2fd887a375d4a7~tplv-188rlo5p4y-1.png","backup_url1":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0ebaaae97e4147e28704d6de684c7d58~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0ebaaae97e4147e28704d6de684c7d58~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/dee09afee0fd44389a2fd887a375d4a7~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/dee09afee0fd44389a2fd887a375d4a7~tplv-188rlo5p4y-1.png"],"tip_y":78,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_180955_verify.json b/try/captures/net_180955_verify.json
new file mode 100644
index 0000000..dc8311c
--- /dev/null
+++ b/try/captures/net_180955_verify.json
@@ -0,0 +1 @@
+{"code":502,"data":null,"message":"操作过快,请慢一点[5014]"}
\ No newline at end of file
diff --git a/try/captures/net_181100_get.json b/try/captures/net_181100_get.json
new file mode 100644
index 0000000..0790051
--- /dev/null
+++ b/try/captures/net_181100_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":35,"host":"","id":"c2da214c228620bcf05c6a08c504026beb7c79f1","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0273de214ae24c1cb2da2ebf90c4adfb~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/a1d806dddf5e4e0ebf3898227a4dd3ba~tplv-188rlo5p4y-1.png","backup_url1":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0273de214ae24c1cb2da2ebf90c4adfb~tplv-188rlo5p4y-2.jpeg","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0273de214ae24c1cb2da2ebf90c4adfb~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/a1d806dddf5e4e0ebf3898227a4dd3ba~tplv-188rlo5p4y-1.png","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/a1d806dddf5e4e0ebf3898227a4dd3ba~tplv-188rlo5p4y-1.png"],"tip_y":75,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_181413_verify.json b/try/captures/net_181413_verify.json
new file mode 100644
index 0000000..cac68eb
--- /dev/null
+++ b/try/captures/net_181413_verify.json
@@ -0,0 +1 @@
+{"code":500,"data":{"msg":"NotFoundChallengeId"},"message":"验证超时,请根据提示重新操作"}
\ No newline at end of file
diff --git a/try/captures/net_181414_11.jpg b/try/captures/net_181414_11.jpg
new file mode 100644
index 0000000..1076c74
Binary files /dev/null and b/try/captures/net_181414_11.jpg differ
diff --git a/try/captures/net_181414_get.json b/try/captures/net_181414_get.json
new file mode 100644
index 0000000..4a83384
--- /dev/null
+++ b/try/captures/net_181414_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":24,"host":"","id":"f241e01462746893b2a4bbc76aa31e76934ffb98","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/3cbbab20c2e146b0aca6145a0ecdc4af~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/a89de64b1d624618af217c94a46dfa06~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/3cbbab20c2e146b0aca6145a0ecdc4af~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/3cbbab20c2e146b0aca6145a0ecdc4af~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/a89de64b1d624618af217c94a46dfa06~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/a89de64b1d624618af217c94a46dfa06~tplv-188rlo5p4y-1.png"],"tip_y":30,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_181418_verify.json b/try/captures/net_181418_verify.json
new file mode 100644
index 0000000..04a629d
--- /dev/null
+++ b/try/captures/net_181418_verify.json
@@ -0,0 +1 @@
+{"code":200,"data":null,"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_181420_verify.json b/try/captures/net_181420_verify.json
new file mode 100644
index 0000000..2f2e75a
--- /dev/null
+++ b/try/captures/net_181420_verify.json
@@ -0,0 +1 @@
+{"data":{"alert_text":"账号或密码错误,请重试。","captcha":"","desc_url":"","description":"账号或密码错误,请重试。","error_code":1009},"message":"error"}
\ No newline at end of file
diff --git a/try/captures/net_181431_verify.json b/try/captures/net_181431_verify.json
new file mode 100644
index 0000000..bfa3bae
--- /dev/null
+++ b/try/captures/net_181431_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"滑动滑块进行验证","error_code":1105,"verify_center_decision_conf":"{\"code\":\"10000\",\"from\":\"shark_admin\",\"type\":\"verify\",\"version\":\"1\",\"region\":\"cn\",\"subtype\":\"slide\",\"ui_type\":\"\",\"detail\":\"XCCxxJ78Uvchj9qXrcrjDNIIsELbQidfcNkB550Wgkxe-w5fGBiiV-4jNqE5eSOQf6Ye7GZU63*ElhUMB*1MK2obS2I4x36av0mg7LnG6ahdEpKFb2WparazaPusLW5sxUECjK4PopzFUHDkuzp4dF6fM1tIW*g28hjPTmvuOhgX5N5YFty9DudxmLecYg1wzUEMRh13-UwqF6iuoTgOVp0ic5eUMbmNleuPgnjAs8HwdBgthi2y39zAD4PxrVW4HfDRU6bUOGB7ut3CVxeojIHDVfzr-9ekzP6fcP8s75ohInezPWl6v7NW8S0TljBr4mBDyBEstTcTK4yMSY5mOThTdQFGtwd5KubaBGur3qILyCof1-o9kwm012tEbF6N\",\"verify_event\":\"tt_user_pwd_login\",\"fp\":\"verify_mtwarf05_T2cF4uRW_4ewx_4A4K_9lxP_FRjbBMt9WYRC\",\"verify_ticket\":\"VTIDEFBA8SANFNN4X7XHPVEUUY3AUMHUH7CYZK_lf\",\"server_sdk_env\":\"{\\\"idc\\\":\\\"lf\\\",\\\"region\\\":\\\"CN\\\",\\\"server_type\\\":\\\"passport\\\"}\",\"log_id\":\"20260911181519D4B2FAFC3591DBB180DB\",\"is_assist_mobile\":false,\"is_complex_sms\":false,\"identity_action\":\"\",\"identity_scene\":\"\",\"verify_scene\":\"passport\",\"login_status\":0,\"aid\":0,\"replay_data\":{\"x-tt-passport-replay-params\":\"{}\"}}","verify_ticket":"VTIDEFBA8SANFNN4X7XHPVEUUY3AUMHUH7CYZK_lf"},"message":"error"}
\ No newline at end of file
diff --git a/try/captures/net_181436_verify.json b/try/captures/net_181436_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_181436_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_181442_verify.json b/try/captures/net_181442_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_181442_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_181447_verify.json b/try/captures/net_181447_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_181447_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_181452_verify.json b/try/captures/net_181452_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_181452_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_181457_verify.json b/try/captures/net_181457_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_181457_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_181503_verify.json b/try/captures/net_181503_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_181503_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_181508_verify.json b/try/captures/net_181508_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_181508_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_181513_verify.json b/try/captures/net_181513_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_181513_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_181519_verify.json b/try/captures/net_181519_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_181519_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_181524_verify.json b/try/captures/net_181524_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_181524_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_181529_verify.json b/try/captures/net_181529_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_181529_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_181535_verify.json b/try/captures/net_181535_verify.json
new file mode 100644
index 0000000..ebb4903
--- /dev/null
+++ b/try/captures/net_181535_verify.json
@@ -0,0 +1 @@
+{"data":{"app_name":"抖音","captcha":"","desc_url":"","description":"","error_code":0,"expire_time":1789121843,"frontier_params":{"access_key":"d8b2e550d05b7afcfea970017e05bc44","frontier_device":"7657740123052901934","method":1,"product_id":971,"service_id":1024},"is_frontier":true,"qrcode":"iVBORw0KGgoAAAANSUhEUgAAAgAAAAIAAQMAAADOtka5AAAABlBMVEX///8AAABVwtN+AAACxklEQVR42uzcPbLyOgyAYTEUKVkCS2FpYWksJUugTJGJ7tiSfxKcA82d+TCvmgMn4ek8khU5QhAEQRAEQRAE8a/HTXM8ROSkT5Eh/0su8c8SLuRYAQAAWkD6OjigasDjpJMEYI6Xo7z9BQBAb8A13H8f9HHWKdwXvjVXma0rAACADwDVcN8soyegFxkA4EeAmItk0Ps5ZCZVS1lWpQEAALwDcpl39u1MBPKWZxbx1fi2TgQA+GagKsZSApplXGyVyaVkpg/6BwAAvwzUETNT+vjwT2P80fRRkxoA4IuBVKVt+8qWmaZdk81bzAAAAC1AJCQgs/yiZaZ4QZ8yzvFC6Vi/ZiYAgB6Am7fMqrDMpKlKk2xlGQAA4AAI1VxcdNe1Xo3iTzzDBfVe2uHTfwCA7wcsAcUK7LrKRfOWJ17wFkHVZAMAAGgBVr+liZl60ak9srmXhzQAAP0DsllMQxmqjFueJPuTTAEAAGgAacuTdzYx7psmmy4Z0MM9EwDAlwNyKu3jc9n++4Uyyb/m7HVbAQAAjgBPQGViZlzCPmdKo8uLLUxbjQAA3QJVlWbdM/URy8m/pVXW7CsDAABUvbTcmE6Hx0a1eeV6LKD+BgDQIaCemcr2P2956r3QWlYZAADAIbAbpUn3XbUeKzse/gcA6AJYS5/MLTv6kg7C3NMJmYsXc63UBgAAUJd5KQHlZzEv9d9wNPAMANAJsD3wZUf3H5sTMmn7/+dBGACAnwZ2p8qqxnSS53zcrN2MAwDoA9i9BqlUaZaZbF5ZyzHkVi8NAADg9T0YZXjGemnP+rjyUWcbAKATYPt+pO1iEh8L0DJvJgAAAO8B9YmZfHT/Uv/Em2wrAED/wLR7W0VpoJ3yWNnfqxEA4JeBXOZJ/qib/kH1KBQAoF+g8eK99Krw/ey+bN5CBgAAQBAEQRAEQRAE8T/HfwEAAP//dilsCCH1Q54AAAAASUVORK5CYII=","qrcode_index_url":"https://api.amemv.com/ucenter_web/app/aweme/scan_login/index/douyin_scan_code_login/cn/app/index.html?_pia_=1\u0026hide_nav_bar=1\u0026is_new_login=1\u0026loader_name=forest\u0026next_url=https%3A%2F%2Fapi.amemv.com%2Fpassport%2Fmobile%2Fscan_qrcode%2F\u0026qr_source_aid=6383\u0026scene=\u0026source=\u0026token=4ce1c27464933da899841b2209779b3b_lf\u0026verify_reason=\u0026verify_scene=\u0026verify_ticket=\u0026web_app_from=rcode","status":"expired","token":"4ce1c27464933da899841b2209779b3b_lf","web_name":"抖音"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_182914_verify.json b/try/captures/net_182914_verify.json
new file mode 100644
index 0000000..c7dcdc2
--- /dev/null
+++ b/try/captures/net_182914_verify.json
@@ -0,0 +1 @@
+{"data":{"captcha":"","desc_url":"","description":"","error_code":0,"extra":"","scan_app_id":0,"status":"new"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_182919_verify.json b/try/captures/net_182919_verify.json
new file mode 100644
index 0000000..1028878
--- /dev/null
+++ b/try/captures/net_182919_verify.json
@@ -0,0 +1 @@
+{"data":{"app_name":"抖音","captcha":"","desc_url":"","description":"","error_code":0,"expire_time":1789122667,"frontier_params":{"access_key":"d8b2e550d05b7afcfea970017e05bc44","frontier_device":"7657740123052901934","method":1,"product_id":971,"service_id":1024},"is_frontier":true,"qrcode":"iVBORw0KGgoAAAANSUhEUgAAAgAAAAIAAQMAAADOtka5AAAABlBMVEX///8AAABVwtN+AAACzklEQVR42uzcMZLqMAyAYe9QpOQIHGWPRo7GUTgCJUUmehNLsuWsgS1esZhf1bJJvs5jWVKSCIIgCIIgCIIg/np8S4lLSieRW5K7Xcu/zvrrq963AgAA9AD/OcnlINeUjvmmZZPzrzkZcNs/AQAwGnDanpgzINvySZPMB7l8xVWWAZMBAABeA9f81L1ctZ0pXwAA+Bwg/+MoYTHpliXLLxcTAMCHAyXNS2rFC5rm2Wp8mScCALwzEI7/vgHd03nRVbYBYct6VT8AAPhkIIbdt/vvtD10/VWRGgDgjYFdLS0DnqVdmy3rZtYFAACgC9SV5n9Krhh40jfrkSdfEACAcYHclyydmWRZWjpsyZhmabV3qelbAgAA6AGhTPCdjzPHLc0r9+mFRRfmk+4/AMDbAz7iMjdZmnb/pTn+hxEZAACALpBzu/O9DM/oavRlWrYsPwv9XI0AACMAXleea1+ytCiljliewohMAgAA6AFrU5jelQm0zbmleWsd3lwBAEYE8s5kC2qxSZhaWSvF5HwW0iwNAACgD1hYmmczmudQLrhb/cC3LACAMYFwsvERy1Ay0yytnIWmJ8U4AAAAW2m1sradbNoiW3gRBgBgYEDXjK8hLx/rBfGGpR155v5YGQAAQPet5LwafV65dGaO0m3SAACMAtjOFA45loy5rK8h+1hAb0YTAAAg7Ey2MGv3P95TO56yPNraAADeHbCBl9Dkt1qaZ2lTqKs96v4DAADs3irTI0+9zw45h/JWwFkAAAYF2g/vhc9YSD3y6JZ1M+DBKA0AwMcDzXcwfjRpxN4KCDM2sgIADAqE7yOVSUp/WyzZx8ZKlpaef2AJAAAgNDZ3w/9tYfrwfDUCAIwC+MkmfB8pNCy7Rx4AAIBOmnday3cwYpq3NC+YJQCAIYHmw3val5zKwEs7u6/1tgsAAEAPIAiCIAiCIAiC+P/xLwAA///lj0+yH8ecTwAAAABJRU5ErkJggg==","qrcode_index_url":"https://api.amemv.com/ucenter_web/app/aweme/scan_login/index/douyin_scan_code_login/cn/app/index.html?_pia_=1\u0026hide_nav_bar=1\u0026is_new_login=1\u0026loader_name=forest\u0026next_url=https%3A%2F%2Fapi.amemv.com%2Fpassport%2Fmobile%2Fscan_qrcode%2F\u0026qr_source_aid=6383\u0026scene=\u0026source=\u0026token=dda9c224f2456720880df3358e152bae_lq\u0026verify_reason=\u0026verify_scene=\u0026verify_ticket=\u0026web_app_from=rcode","status":"expired","token":"dda9c224f2456720880df3358e152bae_lq","web_name":"抖音"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_182937_get.json b/try/captures/net_182937_get.json
new file mode 100644
index 0000000..58d41f8
--- /dev/null
+++ b/try/captures/net_182937_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":85,"host":"","id":"a079801174e14fe280f5b52cbfc879cc24da2c05","mode":"slide","question":{"url1":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/8c2d606ab68f49edb2d6805e0ab77a42~tplv-188rlo5p4y-2.jpeg","url2":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/21c7186069ca47e78370a1ef99876c9a~tplv-188rlo5p4y-1.png","backup_url1":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/8c2d606ab68f49edb2d6805e0ab77a42~tplv-188rlo5p4y-2.jpeg","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/8c2d606ab68f49edb2d6805e0ab77a42~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/21c7186069ca47e78370a1ef99876c9a~tplv-188rlo5p4y-1.png","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/21c7186069ca47e78370a1ef99876c9a~tplv-188rlo5p4y-1.png"],"tip_y":30,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_183039_verify.json b/try/captures/net_183039_verify.json
new file mode 100644
index 0000000..cac68eb
--- /dev/null
+++ b/try/captures/net_183039_verify.json
@@ -0,0 +1 @@
+{"code":500,"data":{"msg":"NotFoundChallengeId"},"message":"验证超时,请根据提示重新操作"}
\ No newline at end of file
diff --git a/try/captures/net_183040_get.json b/try/captures/net_183040_get.json
new file mode 100644
index 0000000..731f216
--- /dev/null
+++ b/try/captures/net_183040_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":25,"host":"","id":"619d39ad07d9bd07fbc6358fcc2065b7e29a48b0","mode":"slide","question":{"url1":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/4d5742044baf49a99424e8a1beef5b3a~tplv-188rlo5p4y-2.jpeg","url2":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/5526885562f04b8cbfa83273b57be142~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/4d5742044baf49a99424e8a1beef5b3a~tplv-188rlo5p4y-2.jpeg","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/4d5742044baf49a99424e8a1beef5b3a~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/5526885562f04b8cbfa83273b57be142~tplv-188rlo5p4y-1.png","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/5526885562f04b8cbfa83273b57be142~tplv-188rlo5p4y-1.png"],"tip_y":31,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_183229_verify.json b/try/captures/net_183229_verify.json
new file mode 100644
index 0000000..cac68eb
--- /dev/null
+++ b/try/captures/net_183229_verify.json
@@ -0,0 +1 @@
+{"code":500,"data":{"msg":"NotFoundChallengeId"},"message":"验证超时,请根据提示重新操作"}
\ No newline at end of file
diff --git a/try/captures/net_183231_15.jpg b/try/captures/net_183231_15.jpg
new file mode 100644
index 0000000..456b85f
Binary files /dev/null and b/try/captures/net_183231_15.jpg differ
diff --git a/try/captures/net_183231_get.json b/try/captures/net_183231_get.json
new file mode 100644
index 0000000..920e61f
--- /dev/null
+++ b/try/captures/net_183231_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":51,"host":"","id":"b3e593aa50658eff7b1a7bde727f1f99953209e7","mode":"slide","question":{"url1":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/be0ccf364472497686e294a9ced0b15f~tplv-188rlo5p4y-2.jpeg","url2":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/530dca6fc7224bbab8a8d52845515d37~tplv-188rlo5p4y-1.png","backup_url1":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/be0ccf364472497686e294a9ced0b15f~tplv-188rlo5p4y-2.jpeg","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/be0ccf364472497686e294a9ced0b15f~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/530dca6fc7224bbab8a8d52845515d37~tplv-188rlo5p4y-1.png","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/530dca6fc7224bbab8a8d52845515d37~tplv-188rlo5p4y-1.png"],"tip_y":80,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_183931_2.jpg b/try/captures/net_183931_2.jpg
new file mode 100644
index 0000000..4043703
Binary files /dev/null and b/try/captures/net_183931_2.jpg differ
diff --git a/try/captures/net_183931_get.json b/try/captures/net_183931_get.json
new file mode 100644
index 0000000..415f8ce
--- /dev/null
+++ b/try/captures/net_183931_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":35,"host":"","id":"4da0a187dbf37192c8bb7d7cf166e8f582157270","mode":"slide","question":{"url1":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/8fb8cb8dc366493da05416f1b2967cc8~tplv-188rlo5p4y-2.jpeg","url2":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/f8c7a2fcfc634547a57f0978da83b3c1~tplv-188rlo5p4y-1.png","backup_url1":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/8fb8cb8dc366493da05416f1b2967cc8~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/8fb8cb8dc366493da05416f1b2967cc8~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/f8c7a2fcfc634547a57f0978da83b3c1~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/f8c7a2fcfc634547a57f0978da83b3c1~tplv-188rlo5p4y-1.png"],"tip_y":44,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_183938_verify.json b/try/captures/net_183938_verify.json
new file mode 100644
index 0000000..dc8311c
--- /dev/null
+++ b/try/captures/net_183938_verify.json
@@ -0,0 +1 @@
+{"code":502,"data":null,"message":"操作过快,请慢一点[5014]"}
\ No newline at end of file
diff --git a/try/captures/net_183942_get.json b/try/captures/net_183942_get.json
new file mode 100644
index 0000000..82e2d26
--- /dev/null
+++ b/try/captures/net_183942_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":26,"host":"","id":"500294fc3cef296ba5a13b5e9dc800cd48b8f6ee","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/054aea18996a490a95d44605b447e31f~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/5924cddf42974177a5db24f56592db6f~tplv-188rlo5p4y-1.png","backup_url1":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/054aea18996a490a95d44605b447e31f~tplv-188rlo5p4y-2.jpeg","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/054aea18996a490a95d44605b447e31f~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/5924cddf42974177a5db24f56592db6f~tplv-188rlo5p4y-1.png","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/5924cddf42974177a5db24f56592db6f~tplv-188rlo5p4y-1.png"],"tip_y":27,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_183943_7.jpg b/try/captures/net_183943_7.jpg
new file mode 100644
index 0000000..7b54d5a
Binary files /dev/null and b/try/captures/net_183943_7.jpg differ
diff --git a/try/captures/net_183954_9.jpg b/try/captures/net_183954_9.jpg
new file mode 100644
index 0000000..7598f25
Binary files /dev/null and b/try/captures/net_183954_9.jpg differ
diff --git a/try/captures/net_183954_get.json b/try/captures/net_183954_get.json
new file mode 100644
index 0000000..83a5242
--- /dev/null
+++ b/try/captures/net_183954_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":60,"host":"","id":"e5359f2cc2d7580ba8e3e88bfad2233fe7d87621","mode":"slide","question":{"url1":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/7a7cc0ea4d8d43839732ce6e92f782fa~tplv-188rlo5p4y-2.jpeg","url2":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/adee869a4afe420f99b857710ee574a8~tplv-188rlo5p4y-1.png","backup_url1":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/7a7cc0ea4d8d43839732ce6e92f782fa~tplv-188rlo5p4y-2.jpeg","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/7a7cc0ea4d8d43839732ce6e92f782fa~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/adee869a4afe420f99b857710ee574a8~tplv-188rlo5p4y-1.png","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/adee869a4afe420f99b857710ee574a8~tplv-188rlo5p4y-1.png"],"tip_y":90,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_184002_verify.json b/try/captures/net_184002_verify.json
new file mode 100644
index 0000000..dc8311c
--- /dev/null
+++ b/try/captures/net_184002_verify.json
@@ -0,0 +1 @@
+{"code":502,"data":null,"message":"操作过快,请慢一点[5014]"}
\ No newline at end of file
diff --git a/try/captures/net_184209_get.json b/try/captures/net_184209_get.json
new file mode 100644
index 0000000..2fad949
--- /dev/null
+++ b/try/captures/net_184209_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":64,"host":"","id":"2d74d02cdba872c58f3bbade0360290ef4c50f2e","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/6b32bb445f734f7394bf06474f32a33f~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/1e5e3281990848cfb5fddc80467435c5~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/6b32bb445f734f7394bf06474f32a33f~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/6b32bb445f734f7394bf06474f32a33f~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/1e5e3281990848cfb5fddc80467435c5~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/1e5e3281990848cfb5fddc80467435c5~tplv-188rlo5p4y-1.png"],"tip_y":95,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_184210_14.jpg b/try/captures/net_184210_14.jpg
new file mode 100644
index 0000000..f49d367
Binary files /dev/null and b/try/captures/net_184210_14.jpg differ
diff --git a/try/captures/net_184217_verify.json b/try/captures/net_184217_verify.json
new file mode 100644
index 0000000..8279f82
--- /dev/null
+++ b/try/captures/net_184217_verify.json
@@ -0,0 +1 @@
+{"code":500,"data":{"msg":"VerifyErr"},"message":"验证失败,请根据提示重新操作"}
\ No newline at end of file
diff --git a/try/captures/net_184218_get.json b/try/captures/net_184218_get.json
new file mode 100644
index 0000000..95d8c5d
--- /dev/null
+++ b/try/captures/net_184218_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":80,"host":"","id":"32fb2fdc68c63f4a404ebce049206d02c66eca5f","mode":"slide","question":{"url1":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/62b53419c11a43b4b48c1c42ca72fc55~tplv-188rlo5p4y-2.jpeg","url2":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/6182025c8ad74d208aab72e654739c9d~tplv-188rlo5p4y-1.png","backup_url1":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/62b53419c11a43b4b48c1c42ca72fc55~tplv-188rlo5p4y-2.jpeg","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/62b53419c11a43b4b48c1c42ca72fc55~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/6182025c8ad74d208aab72e654739c9d~tplv-188rlo5p4y-1.png","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/6182025c8ad74d208aab72e654739c9d~tplv-188rlo5p4y-1.png"],"tip_y":66,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_184219_19.jpg b/try/captures/net_184219_19.jpg
new file mode 100644
index 0000000..b9de7bc
Binary files /dev/null and b/try/captures/net_184219_19.jpg differ
diff --git a/try/captures/net_184221_22.jpg b/try/captures/net_184221_22.jpg
new file mode 100644
index 0000000..475847b
Binary files /dev/null and b/try/captures/net_184221_22.jpg differ
diff --git a/try/captures/net_184221_get.json b/try/captures/net_184221_get.json
new file mode 100644
index 0000000..7c2e2cf
--- /dev/null
+++ b/try/captures/net_184221_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":8,"host":"","id":"f760eedd3a154d2da4c33bd4878f953e1fccbff9","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/1a617bd7230e41c1b3c8f6491af8b0ba~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/d9d64cc1773a44fba8c0df572873af44~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/1a617bd7230e41c1b3c8f6491af8b0ba~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/1a617bd7230e41c1b3c8f6491af8b0ba~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/d9d64cc1773a44fba8c0df572873af44~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/d9d64cc1773a44fba8c0df572873af44~tplv-188rlo5p4y-1.png"],"tip_y":89,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_184228_verify.json b/try/captures/net_184228_verify.json
new file mode 100644
index 0000000..dc8311c
--- /dev/null
+++ b/try/captures/net_184228_verify.json
@@ -0,0 +1 @@
+{"code":502,"data":null,"message":"操作过快,请慢一点[5014]"}
\ No newline at end of file
diff --git a/try/captures/net_184354_26.jpg b/try/captures/net_184354_26.jpg
new file mode 100644
index 0000000..b8e57c0
Binary files /dev/null and b/try/captures/net_184354_26.jpg differ
diff --git a/try/captures/net_184354_get.json b/try/captures/net_184354_get.json
new file mode 100644
index 0000000..a81022a
--- /dev/null
+++ b/try/captures/net_184354_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":7,"host":"","id":"bccd9ff911a2119c6261c5e98fbff151bd1137e3","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0ba31beba68940fc942980c7f47a0838~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/3af9e237d05e467e98698cb4de5d00d8~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0ba31beba68940fc942980c7f47a0838~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0ba31beba68940fc942980c7f47a0838~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/3af9e237d05e467e98698cb4de5d00d8~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/3af9e237d05e467e98698cb4de5d00d8~tplv-188rlo5p4y-1.png"],"tip_y":60,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_184402_verify.json b/try/captures/net_184402_verify.json
new file mode 100644
index 0000000..dc8311c
--- /dev/null
+++ b/try/captures/net_184402_verify.json
@@ -0,0 +1 @@
+{"code":502,"data":null,"message":"操作过快,请慢一点[5014]"}
\ No newline at end of file
diff --git a/try/captures/net_184406_29.jpg b/try/captures/net_184406_29.jpg
new file mode 100644
index 0000000..1b27c15
Binary files /dev/null and b/try/captures/net_184406_29.jpg differ
diff --git a/try/captures/net_184406_get.json b/try/captures/net_184406_get.json
new file mode 100644
index 0000000..3e0aa02
--- /dev/null
+++ b/try/captures/net_184406_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":25,"host":"","id":"6c545567d7f9dc570043db42d45dd621344e5927","mode":"slide","question":{"url1":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/5894623d79814e6c83b735f7360c6ba7~tplv-188rlo5p4y-2.jpeg","url2":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/22cf77b8b2d242b8a3b5d33614099a6b~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/5894623d79814e6c83b735f7360c6ba7~tplv-188rlo5p4y-2.jpeg","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/5894623d79814e6c83b735f7360c6ba7~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/22cf77b8b2d242b8a3b5d33614099a6b~tplv-188rlo5p4y-1.png","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/22cf77b8b2d242b8a3b5d33614099a6b~tplv-188rlo5p4y-1.png"],"tip_y":79,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_184413_verify.json b/try/captures/net_184413_verify.json
new file mode 100644
index 0000000..8279f82
--- /dev/null
+++ b/try/captures/net_184413_verify.json
@@ -0,0 +1 @@
+{"code":500,"data":{"msg":"VerifyErr"},"message":"验证失败,请根据提示重新操作"}
\ No newline at end of file
diff --git a/try/captures/net_184414_get.json b/try/captures/net_184414_get.json
new file mode 100644
index 0000000..b6598a4
--- /dev/null
+++ b/try/captures/net_184414_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":12,"host":"","id":"9c065d174b72909d8df1beb97c12c2440be0bcc5","mode":"slide","question":{"url1":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/f0588db7a82d46e6aa2b6f3e5f22e0c1~tplv-188rlo5p4y-2.jpeg","url2":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/621f25cf46524c56ba6832c0030e255a~tplv-188rlo5p4y-1.png","backup_url1":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/f0588db7a82d46e6aa2b6f3e5f22e0c1~tplv-188rlo5p4y-2.jpeg","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/f0588db7a82d46e6aa2b6f3e5f22e0c1~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/621f25cf46524c56ba6832c0030e255a~tplv-188rlo5p4y-1.png","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/621f25cf46524c56ba6832c0030e255a~tplv-188rlo5p4y-1.png"],"tip_y":68,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_184415_34.jpg b/try/captures/net_184415_34.jpg
new file mode 100644
index 0000000..b011be3
Binary files /dev/null and b/try/captures/net_184415_34.jpg differ
diff --git a/try/captures/net_184853_2.jpg b/try/captures/net_184853_2.jpg
new file mode 100644
index 0000000..99b6d49
Binary files /dev/null and b/try/captures/net_184853_2.jpg differ
diff --git a/try/captures/net_184853_get.json b/try/captures/net_184853_get.json
new file mode 100644
index 0000000..3ba1569
--- /dev/null
+++ b/try/captures/net_184853_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":60,"host":"","id":"0292cde0f1cc02b4fcfbafbb26ffaf050ef44917","mode":"slide","question":{"url1":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/7d2080a3d9dc4615aa2c63231454823b~tplv-188rlo5p4y-2.jpeg","url2":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/4236cba0af104a1dbfbc7b7fefe7cab6~tplv-188rlo5p4y-1.png","backup_url1":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/7d2080a3d9dc4615aa2c63231454823b~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/7d2080a3d9dc4615aa2c63231454823b~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/4236cba0af104a1dbfbc7b7fefe7cab6~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/4236cba0af104a1dbfbc7b7fefe7cab6~tplv-188rlo5p4y-1.png"],"tip_y":94,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_184900_verify.json b/try/captures/net_184900_verify.json
new file mode 100644
index 0000000..8279f82
--- /dev/null
+++ b/try/captures/net_184900_verify.json
@@ -0,0 +1 @@
+{"code":500,"data":{"msg":"VerifyErr"},"message":"验证失败,请根据提示重新操作"}
\ No newline at end of file
diff --git a/try/captures/net_184902_6.jpg b/try/captures/net_184902_6.jpg
new file mode 100644
index 0000000..ac0f5fa
Binary files /dev/null and b/try/captures/net_184902_6.jpg differ
diff --git a/try/captures/net_184902_get.json b/try/captures/net_184902_get.json
new file mode 100644
index 0000000..dc48e99
--- /dev/null
+++ b/try/captures/net_184902_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":85,"host":"","id":"8a418fa57756d69cc4e512d279a6ce9b44f674b1","mode":"slide","question":{"url1":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/62543677568b4bc9badfde5a2dcf690a~tplv-188rlo5p4y-2.jpeg","url2":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/efa14e3f54504057ab21ec68e3868e67~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/62543677568b4bc9badfde5a2dcf690a~tplv-188rlo5p4y-2.jpeg","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/62543677568b4bc9badfde5a2dcf690a~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/efa14e3f54504057ab21ec68e3868e67~tplv-188rlo5p4y-1.png","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/efa14e3f54504057ab21ec68e3868e67~tplv-188rlo5p4y-1.png"],"tip_y":93,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_184904_9.jpg b/try/captures/net_184904_9.jpg
new file mode 100644
index 0000000..7e3f6b3
Binary files /dev/null and b/try/captures/net_184904_9.jpg differ
diff --git a/try/captures/net_184904_get.json b/try/captures/net_184904_get.json
new file mode 100644
index 0000000..c812c1b
--- /dev/null
+++ b/try/captures/net_184904_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":38,"host":"","id":"02c51e3e150706b66296f3aa1d4e3ae91dca1f55","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/682c58e51ea54161a512657e96d9fb1e~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/86a8188dfde44072b096a2e09fbc0a39~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/682c58e51ea54161a512657e96d9fb1e~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/682c58e51ea54161a512657e96d9fb1e~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/86a8188dfde44072b096a2e09fbc0a39~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/86a8188dfde44072b096a2e09fbc0a39~tplv-188rlo5p4y-1.png"],"tip_y":94,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_184912_verify.json b/try/captures/net_184912_verify.json
new file mode 100644
index 0000000..dc8311c
--- /dev/null
+++ b/try/captures/net_184912_verify.json
@@ -0,0 +1 @@
+{"code":502,"data":null,"message":"操作过快,请慢一点[5014]"}
\ No newline at end of file
diff --git a/try/captures/net_191926_verify.json b/try/captures/net_191926_verify.json
new file mode 100644
index 0000000..35c285a
--- /dev/null
+++ b/try/captures/net_191926_verify.json
@@ -0,0 +1 @@
+{"data":{"app_name":"抖音","captcha":"","desc_url":"","description":"","error_code":0,"expire_time":1789125675,"frontier_params":{"access_key":"d8b2e550d05b7afcfea970017e05bc44","frontier_device":"7657740123052901934","method":1,"product_id":971,"service_id":1024},"is_frontier":true,"qrcode":"iVBORw0KGgoAAAANSUhEUgAAAgAAAAIAAQMAAADOtka5AAAABlBMVEX///8AAABVwtN+AAACyUlEQVR42uzcP5K7OgzAcWVSpOQIHIWjwdE4yh4hJQWD3mBL/kMgSfGK33q/qpYNfDqPbUm2EARBEARBEARB/OsxaIo5/KNTedg/fkSfMqrqKnLL720AAABngD8+AlC8twPSqS7h55s+j18AALQG9PvL00Pn+/6JyP501/lWjbId0DCuAAAAvgBCiITpaDMrygAAfwtIc9F9H0G9xikrrtIAAAA+AWmZZ6MxAnFn49zPV+tEAIDfDBTbf5+AFhnXOMqkyzPTF/kDAIC/DJThW55lX+bN9s/RUwlfBADALwZ8lRZ3+f2Wvppv9lWdZFsBAADeAGk1pxpnprjM6/encZHBijRWvdkAAJoGclkmTlJx+9/pFF7rNS3frgYTAABA+FH8vZiY9vfCMB1WA/RqNAIANABonI7GvP0vBlN8Gvyrh053AACAC6BazYUtT8wf+Dw15SINAEDLQJqA8qxTLMai7Ku0CMwCAABwAgzWlmx/VoVNT7LpmoCTXBoAQBuA3HYgvbfZuLKGF/sqjDJvXT5U/wEAAIrGmLTP8YpnIU9i+YOYmF4BABoFJNcltarFxIJlZy0y3m82ns9MAAAAZf5A8nmX6eXo5bsTlgAAjQDiKTO1TsqlOggTqze2fJvO2soAAADqimeZP7ATlmVb2dvjygAALQBit1W8HN3X3Lsftv/WeykAAACXQJpyDtX//RPv0bzKbAMANAMUBZjeOC1698UamdWvhwEAAFg+nirTKv/c58PL6bjZa2IaAKANoE6Z1W3JfkLG90L10UsAAICTXFq6B2PLAzPvhfy4cnnZJQBAg8DJ/UijlluetEqL1ZsNAADgM3Ds8e/Kskx58xIAQOOADya/HPx5bJG5vAcDAAAgL/N80OUJKOYPhjX9AADQLlBdvFcMn3RCJvfup+oNAACAXJywJAiCIAiCIAiC+D/jvwAAAP//+okGooThltIAAAAASUVORK5CYII=","qrcode_index_url":"https://api.amemv.com/ucenter_web/app/aweme/scan_login/index/douyin_scan_code_login/cn/app/index.html?_pia_=1\u0026hide_nav_bar=1\u0026is_new_login=1\u0026loader_name=forest\u0026next_url=https%3A%2F%2Fapi.amemv.com%2Fpassport%2Fmobile%2Fscan_qrcode%2F\u0026qr_source_aid=6383\u0026scene=\u0026source=\u0026token=c84c347c3fe6ca105043cdfd48ff8272_lf\u0026verify_reason=\u0026verify_scene=\u0026verify_ticket=\u0026web_app_from=rcode","status":"expired","token":"c84c347c3fe6ca105043cdfd48ff8272_lf","web_name":"抖音"},"message":"success"}
\ No newline at end of file
diff --git a/try/captures/net_192004_4.jpg b/try/captures/net_192004_4.jpg
new file mode 100644
index 0000000..3899d90
Binary files /dev/null and b/try/captures/net_192004_4.jpg differ
diff --git a/try/captures/net_192004_get.json b/try/captures/net_192004_get.json
new file mode 100644
index 0000000..31a4486
--- /dev/null
+++ b/try/captures/net_192004_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":36,"host":"","id":"578125ce90cb7a7fe45f24373699711fd57f309d","mode":"slide","question":{"url1":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/9260d2581a274c06afad462764c2db17~tplv-188rlo5p4y-2.jpeg","url2":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/6e035f1ae07f4cf2ae75e5bf2b8368fb~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/9260d2581a274c06afad462764c2db17~tplv-188rlo5p4y-2.jpeg","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/9260d2581a274c06afad462764c2db17~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/6e035f1ae07f4cf2ae75e5bf2b8368fb~tplv-188rlo5p4y-1.png","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/6e035f1ae07f4cf2ae75e5bf2b8368fb~tplv-188rlo5p4y-1.png"],"tip_y":68,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_192054_verify.json b/try/captures/net_192054_verify.json
new file mode 100644
index 0000000..dc8311c
--- /dev/null
+++ b/try/captures/net_192054_verify.json
@@ -0,0 +1 @@
+{"code":502,"data":null,"message":"操作过快,请慢一点[5014]"}
\ No newline at end of file
diff --git a/try/captures/net_192226_8.jpg b/try/captures/net_192226_8.jpg
new file mode 100644
index 0000000..f460099
Binary files /dev/null and b/try/captures/net_192226_8.jpg differ
diff --git a/try/captures/net_192226_get.json b/try/captures/net_192226_get.json
new file mode 100644
index 0000000..62612a3
--- /dev/null
+++ b/try/captures/net_192226_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":58,"host":"","id":"670839105040431d429a4e7501d8a5c2ebb7f807","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/b25a1a78bfd44028a244731a9722daa3~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/c54fe3a55c0d492a843a34729367d61a~tplv-188rlo5p4y-1.png","backup_url1":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/b25a1a78bfd44028a244731a9722daa3~tplv-188rlo5p4y-2.jpeg","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/b25a1a78bfd44028a244731a9722daa3~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/c54fe3a55c0d492a843a34729367d61a~tplv-188rlo5p4y-1.png","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/c54fe3a55c0d492a843a34729367d61a~tplv-188rlo5p4y-1.png"],"tip_y":27,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_192233_verify.json b/try/captures/net_192233_verify.json
new file mode 100644
index 0000000..dc8311c
--- /dev/null
+++ b/try/captures/net_192233_verify.json
@@ -0,0 +1 @@
+{"code":502,"data":null,"message":"操作过快,请慢一点[5014]"}
\ No newline at end of file
diff --git a/try/captures/net_192321_12.jpg b/try/captures/net_192321_12.jpg
new file mode 100644
index 0000000..fcd38d5
Binary files /dev/null and b/try/captures/net_192321_12.jpg differ
diff --git a/try/captures/net_192321_get.json b/try/captures/net_192321_get.json
new file mode 100644
index 0000000..b93c1c3
--- /dev/null
+++ b/try/captures/net_192321_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":54,"host":"","id":"af7a99b6e096294ea82bc42557cae217cd53b09d","mode":"slide","question":{"url1":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/fe58943f53854077a26d16fc23ed83ff~tplv-188rlo5p4y-2.jpeg","url2":"https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/1ac7ea56bb764801bcbc9f736f9fed90~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/fe58943f53854077a26d16fc23ed83ff~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/fe58943f53854077a26d16fc23ed83ff~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/1ac7ea56bb764801bcbc9f736f9fed90~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/1ac7ea56bb764801bcbc9f736f9fed90~tplv-188rlo5p4y-1.png"],"tip_y":87,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_192329_verify.json b/try/captures/net_192329_verify.json
new file mode 100644
index 0000000..8279f82
--- /dev/null
+++ b/try/captures/net_192329_verify.json
@@ -0,0 +1 @@
+{"code":500,"data":{"msg":"VerifyErr"},"message":"验证失败,请根据提示重新操作"}
\ No newline at end of file
diff --git a/try/captures/net_192330_16.jpg b/try/captures/net_192330_16.jpg
new file mode 100644
index 0000000..f924243
Binary files /dev/null and b/try/captures/net_192330_16.jpg differ
diff --git a/try/captures/net_192330_get.json b/try/captures/net_192330_get.json
new file mode 100644
index 0000000..dc66d75
--- /dev/null
+++ b/try/captures/net_192330_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":86,"host":"","id":"aebc6e446697819f152631daceda0c00177d3703","mode":"slide","question":{"url1":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/a0b11aa9eb4444b290ba11006963091d~tplv-188rlo5p4y-2.jpeg","url2":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/6b6d81cbff1f4ac1917d74c6dd1201ab~tplv-188rlo5p4y-1.png","backup_url1":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/a0b11aa9eb4444b290ba11006963091d~tplv-188rlo5p4y-2.jpeg","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/a0b11aa9eb4444b290ba11006963091d~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/6b6d81cbff1f4ac1917d74c6dd1201ab~tplv-188rlo5p4y-1.png","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/6b6d81cbff1f4ac1917d74c6dd1201ab~tplv-188rlo5p4y-1.png"],"tip_y":77,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_192443_get.json b/try/captures/net_192443_get.json
new file mode 100644
index 0000000..039626e
--- /dev/null
+++ b/try/captures/net_192443_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":83,"host":"","id":"8129c653df2cb32715bf6046970db36ffb3992d1","mode":"slide","question":{"url1":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/ee6a280039f64b31976949ad16a33cce~tplv-188rlo5p4y-2.jpeg","url2":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0884697c102941d9868d6235e73aa318~tplv-188rlo5p4y-1.png","backup_url1":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/ee6a280039f64b31976949ad16a33cce~tplv-188rlo5p4y-2.jpeg","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/ee6a280039f64b31976949ad16a33cce~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0884697c102941d9868d6235e73aa318~tplv-188rlo5p4y-1.png","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/0884697c102941d9868d6235e73aa318~tplv-188rlo5p4y-1.png"],"tip_y":61,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_192444_19.jpg b/try/captures/net_192444_19.jpg
new file mode 100644
index 0000000..cb52cd3
Binary files /dev/null and b/try/captures/net_192444_19.jpg differ
diff --git a/try/captures/net_192527_verify.json b/try/captures/net_192527_verify.json
new file mode 100644
index 0000000..8279f82
--- /dev/null
+++ b/try/captures/net_192527_verify.json
@@ -0,0 +1 @@
+{"code":500,"data":{"msg":"VerifyErr"},"message":"验证失败,请根据提示重新操作"}
\ No newline at end of file
diff --git a/try/captures/net_192528_23.jpg b/try/captures/net_192528_23.jpg
new file mode 100644
index 0000000..01c2e0c
Binary files /dev/null and b/try/captures/net_192528_23.jpg differ
diff --git a/try/captures/net_192528_get.json b/try/captures/net_192528_get.json
new file mode 100644
index 0000000..657027b
--- /dev/null
+++ b/try/captures/net_192528_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":70,"host":"","id":"3a3cbc3ffa9ccf8a94fef4c65604ca525f6d2c24","mode":"slide","question":{"url1":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/2bba6b927d0342e49ad78af2d3f6c92f~tplv-188rlo5p4y-2.jpeg","url2":"https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/b344b9960a5f43db8809975f1fde559b~tplv-188rlo5p4y-1.png","backup_url1":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/2bba6b927d0342e49ad78af2d3f6c92f~tplv-188rlo5p4y-2.jpeg","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/2bba6b927d0342e49ad78af2d3f6c92f~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/b344b9960a5f43db8809975f1fde559b~tplv-188rlo5p4y-1.png","https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/b344b9960a5f43db8809975f1fde559b~tplv-188rlo5p4y-1.png"],"tip_y":23,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_192630_get.json b/try/captures/net_192630_get.json
new file mode 100644
index 0000000..c70cad3
--- /dev/null
+++ b/try/captures/net_192630_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":51,"host":"","id":"fc629bbc596a8c64675a06fbe92923d84b3ff4df","mode":"slide","question":{"url1":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/71bf214187354e1694caeded8eec69b6~tplv-188rlo5p4y-2.jpeg","url2":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/fcb7706a20a64efa89bb536c471c8ef5~tplv-188rlo5p4y-1.png","backup_url1":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/71bf214187354e1694caeded8eec69b6~tplv-188rlo5p4y-2.jpeg","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/71bf214187354e1694caeded8eec69b6~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/fcb7706a20a64efa89bb536c471c8ef5~tplv-188rlo5p4y-1.png","https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/fcb7706a20a64efa89bb536c471c8ef5~tplv-188rlo5p4y-1.png"],"tip_y":45,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_192631_27.jpg b/try/captures/net_192631_27.jpg
new file mode 100644
index 0000000..8ae6243
Binary files /dev/null and b/try/captures/net_192631_27.jpg differ
diff --git a/try/captures/net_192658_get.json b/try/captures/net_192658_get.json
new file mode 100644
index 0000000..d13639c
--- /dev/null
+++ b/try/captures/net_192658_get.json
@@ -0,0 +1 @@
+{"code":200,"data":{"challenge_code":99999,"codifica":"true","cyfreso":39,"host":"","id":"4e98a87f5d65cce266550c661ccf4488e2729ac1","mode":"slide","question":{"url1":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/f544f8a5fab344a8bd11f23932ccf14f~tplv-188rlo5p4y-2.jpeg","url2":"https://p3-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/6a663ceb5d304f66bf68752fdae83378~tplv-188rlo5p4y-1.png","backup_url1":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/f544f8a5fab344a8bd11f23932ccf14f~tplv-188rlo5p4y-2.jpeg","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/f544f8a5fab344a8bd11f23932ccf14f~tplv-188rlo5p4y-2.jpeg"],"backup_url2":["https://p6-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/6a663ceb5d304f66bf68752fdae83378~tplv-188rlo5p4y-1.png","https://p9-catpcha.byteimg.com/tos-cn-i-188rlo5p4y/6a663ceb5d304f66bf68752fdae83378~tplv-188rlo5p4y-1.png"],"tip_y":21,"obfuscation":""},"region":"","version":2},"message":"验证通过"}
\ No newline at end of file
diff --git a/try/captures/net_192659_29.jpg b/try/captures/net_192659_29.jpg
new file mode 100644
index 0000000..9c55301
Binary files /dev/null and b/try/captures/net_192659_29.jpg differ
diff --git a/try/captures/net_192743_verify.json b/try/captures/net_192743_verify.json
new file mode 100644
index 0000000..dc8311c
--- /dev/null
+++ b/try/captures/net_192743_verify.json
@@ -0,0 +1 @@
+{"code":502,"data":null,"message":"操作过快,请慢一点[5014]"}
\ No newline at end of file
diff --git a/try/cold_start_attempt.py b/try/cold_start_attempt.py
new file mode 100644
index 0000000..57dd901
--- /dev/null
+++ b/try/cold_start_attempt.py
@@ -0,0 +1,741 @@
+"""冷启动单次尝试:触发验证码 → 采多题选最优 → force=0.5 单次拖动 → 读 verify。
+
+频控对策:verify 只打一次,get/refresh 可多次采题挑最优。
+用法: python try/cold_start_attempt.py [max_questions] [max_score]
+"""
+import asyncio, base64, json, math, os, random, sys, time, urllib.request as ur
+from pathlib import Path
+import websockets
+
+sys.path.insert(0, str(Path(__file__).resolve().parent))
+sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "src"))
+from solve import solve
+from human_drag import gen_human_path
+from enrich_replay import enrich
+
+CDP = "http://127.0.0.1:9222"
+SCALE = 340 / 552
+TRACE_JSON = Path(__file__).resolve().parent / "human_trace.json"
+def random_phone():
+ """随机手机号(错误凭证也弹验证码,无需真实存在)。
+ 用 13x/18x/14x 传统号段:16x/17x 虚拟号段被"验证码登录"拒绝的比例高。"""
+ return "1" + random.choice("3458") + "".join(random.choices("0123456789", k=9))
+
+
+def random_password():
+ """随机密码(满足常见强度要求:大小写+数字+符号)。"""
+ chars = "abcdefghijkmnpqrstuvwxyz"
+ caps = "ABCDEFGHJKLMNPQRSTUVWXYZ"
+ digits = "23456789"
+ syms = "!@#$%^&*"
+ pool = [random.choice(caps), random.choice(digits), random.choice(syms)]
+ pool += [random.choice(chars + caps + digits + syms) for _ in range(9)]
+ random.shuffle(pool)
+ return "".join(pool)
+CAPT = Path(__file__).resolve().parent / "captures"
+HOOK = """
+(() => {
+ window.__lastGet = null; window.__lastVerify = null;
+ const oOpen = XMLHttpRequest.prototype.open, oSend = XMLHttpRequest.prototype.send;
+ XMLHttpRequest.prototype.open = function(m,u){ this.__u = u; return oOpen.apply(this, arguments); };
+ XMLHttpRequest.prototype.send = function(){
+ const x = this;
+ try {
+ if (/captcha\\/verify/.test(x.__u || '')) {
+ const body = arguments[0];
+ window.__lastVerifyBody = typeof body === 'string' ? body : (body && body.length ? '[form]' + String(body).slice(0, 8000) : 'null');
+ }
+ } catch (e) {}
+ this.addEventListener('load', () => {
+ try {
+ if (/captcha\\/get/.test(x.__u || '')) window.__lastGet = JSON.parse(x.responseText);
+ if (/captcha\\/verify/.test(x.__u || '')) window.__lastVerify = x.responseText.slice(0, 200);
+ } catch (e) {}
+ });
+ return oSend.apply(this, arguments);
+ };
+ if (!window.__recOn) {
+ window.__recOn = 1;
+ window.__dragTrace = [];
+ // 插桩:捕获 SDK 加密前的明文(captchaBody plain)
+ const oStringify = JSON.stringify;
+ JSON.stringify = function(...args) {
+ try {
+ const s = oStringify.apply(this, args);
+ if (typeof s === 'string' && s.length > 500 &&
+ (s.includes('"mode"') || s.includes('relative_time') || s.includes('drag_width'))) {
+ window.__lastPlain = s;
+ }
+ return s;
+ } catch (e) { return oStringify.apply(this, args); }
+ };
+ const rec = (type) => (e) => {
+ if (!e.isTrusted) return;
+ window.__dragTrace.push({t: e.timeStamp, type, x: e.clientX, y: e.clientY,
+ p: e.pressure, btns: e.buttons});
+ };
+ document.addEventListener('mousedown', rec('down'), true);
+ document.addEventListener('mousemove', rec('move'), true);
+ document.addEventListener('mouseup', rec('up'), true);
+ }
+ return 'ok';
+})()
+"""
+
+
+def _json(path):
+ try:
+ with ur.urlopen(f"{CDP}{path}", timeout=5) as r:
+ return json.load(r)
+ except (OSError, ValueError):
+ return None
+
+
+XDISPLAY = os.environ.get("XDISPLAY", ":99")
+
+
+async def xdotool(*args):
+ """在目标 X display 上执行 xdotool(OS 层真实鼠标输入,无 CDP 合成标记)。"""
+ env = dict(os.environ, DISPLAY=XDISPLAY)
+ try:
+ proc = await asyncio.create_subprocess_exec(
+ "/usr/bin/xdotool", *args,
+ stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, env=env)
+ _, err = await proc.communicate()
+ if proc.returncode != 0:
+ print(f"xdotool {args[0]} 失败: {err.decode(errors='replace').strip()[:80]}")
+ except FileNotFoundError:
+ print("xdotool 未安装")
+ except OSError as e:
+ print(f"xdotool 执行失败: {e}")
+
+
+def replay_pts(seg, dist_ui, target_ms):
+ """把真人拖动段(绝对 ts/x/y 列表)重放为目标距离/时长的 (dx,dy,dt) 序列。
+ x 线性缩放到 dist_ui(终点精确),时间轴拉伸到 target_ms(保留节奏起伏)。"""
+ t0, x0, _y0 = seg[0]
+ raw = [(t - t0, x - x0, y - _y0) for (t, x, y) in seg]
+ span = max(raw[-1][0], 1.0)
+ end_x = raw[-1][1]
+ if abs(end_x) < 1.0:
+ end_x = max((x for _, x, _ in raw), default=1.0)
+ k = dist_ui / end_x
+ scale_t = target_ms / span
+ out = []
+ last_x, last_y = 0.0, 0.0
+ prev_t = raw[0][0]
+ for t, x, y in raw[1:]:
+ dt = t - prev_t # 相邻事件间隔(raw 里是累计 ts)
+ prev_t = t
+ tx, ty = x * k, y * k
+ try:
+ step_ms = max(int(dt * scale_t), 1)
+ except (TypeError, ValueError, OverflowError):
+ step_ms = 10
+ out.append((round(tx - last_x, 2), round(ty - last_y, 2), step_ms))
+ last_x, last_y = tx, ty
+ # 终点精确回贴
+ if out:
+ ex, ey, et = out[-1]
+ try:
+ fix = float(dist_ui) - sum(p[0] for p in out[:-1])
+ except (TypeError, ValueError):
+ fix = ex
+ out[-1] = (round(fix, 2), ey, et)
+ return out
+
+
+def load_human_segments(path):
+ """从轨迹采集 JSON 提取按下-抬起段(dx>80 才算拖动)。
+ 兼容两种采集格式:{ts,type,x,y,buttons,trusted} 与 {t,type,x,y,btns}。"""
+ try:
+ ev = json.load(open(path))["events"]
+ except (OSError, ValueError, KeyError) as e:
+ print(f"轨迹加载失败: {e}")
+ return []
+ T_DOWN = ("mousedown", "pointerdown", "down")
+ T_MOVE = ("mousemove", "pointermove", "move")
+ T_UP = ("mouseup", "pointerup", "up")
+ segs, cur = [], None
+ for e in ev:
+ t = e.get("t", e.get("ts"))
+ if t is None:
+ continue
+ typ = e.get("type", e.get("t_type", ""))
+ x, y = e.get("x"), e.get("y")
+ btns = e.get("buttons", e.get("btns", 0))
+ try:
+ t, x, y, btns = float(t), float(x), float(y), int(btns)
+ except (TypeError, ValueError):
+ continue
+ if typ in T_DOWN:
+ cur = [(t, x, y)]
+ elif typ in T_MOVE and cur is not None and btns == 1:
+ cur.append((t, x, y))
+ elif typ in T_UP and cur is not None:
+ cur.append((t, x, y))
+ dx = cur[-1][1] - cur[0][1]
+ if len(cur) > 10 and dx > 80:
+ segs.append(cur)
+ cur = None
+ return segs
+
+
+async def _warmup_session():
+ """会话画像预热:真人触发验证码前已在页面浏览数分钟(鼠标游走、停顿)。
+ 我们从页面打开到触发只有几秒 —— 会话级行为画像差异可能是静默降权来源。
+ 在触发验证码之前模拟 45-75s 慢速游走(xdotool 硬件事件)。"""
+ if os.environ.get("XDOTOOL") != "1" or os.environ.get("WARMUP", "1") == "0":
+ return
+ warm_s = random.uniform(45, 75)
+ print(f"会话预热 {warm_s:.0f}s(模拟真人浏览)", flush=True)
+ w_t0 = asyncio.get_event_loop().time()
+ wx, wy = random.uniform(400, 1400), random.uniform(200, 700)
+ while (asyncio.get_event_loop().time() - w_t0) < warm_s:
+ await xdotool("mousemove", str(round(wx)), str(round(wy)))
+ await asyncio.sleep(random.uniform(1.5, 5.0))
+ wx += random.uniform(-120, 120)
+ wy += random.uniform(-60, 60)
+ wx = min(max(wx, 200), 1700)
+ wy = min(max(wy, 120), 800)
+
+
+async def main_once(max_questions=4, max_score=5.5):
+ """单次完整尝试,返回结果字符串:PASS / 500 / 502 / skip / error..."""
+ n_q, max_score = max_questions, max_score
+ await _warmup_session()
+ ver = _json("/json/version")
+ if not ver or not ver.get("webSocketDebuggerUrl"):
+ print("无法连接 CDP", file=sys.stderr)
+ return
+ targets = _json("/json/list") or []
+ page = next((t for t in targets if t["type"] == "page" and "douyin" in t.get("url", "")), None)
+ if not page:
+ print("未找到 douyin 页面", file=sys.stderr)
+ return
+ async with websockets.connect(ver["webSocketDebuggerUrl"], max_size=64 * 1024 * 1024) as ws:
+ mid = [0]
+
+ async def cdp(method, params=None, sid=None):
+ mid[0] += 1
+ m = {"id": mid[0], "method": method, "params": params or {}}
+ if sid:
+ m["sessionId"] = sid
+ await ws.send(json.dumps(m))
+ while True:
+ try:
+ r = json.loads(await ws.recv())
+ except (json.JSONDecodeError, asyncio.TimeoutError):
+ continue
+ if r.get("id") == mid[0]:
+ if "error" in r:
+ raise RuntimeError(f"{method}: {r['error']}")
+ return r.get("result", {})
+
+ psid = (await cdp("Target.attachToTarget", {"targetId": page["id"], "flatten": True}))["sessionId"]
+ await cdp("Runtime.enable", sid=psid)
+
+ async def js(expr):
+ r = await cdp("Runtime.evaluate",
+ {"expression": expr, "returnByValue": True, "awaitPromise": True}, psid)
+ return r.get("result", {}).get("value")
+
+ async def click(x, y):
+ for typ in ("mousePressed", "mouseReleased"):
+ await cdp("Input.dispatchMouseEvent",
+ {"type": typ, "x": x, "y": y, "button": "left",
+ "buttons": 1, "clickCount": 1}, psid)
+
+ async def type_text(text):
+ for ch in text:
+ await cdp("Input.dispatchKeyEvent", {"type": "keyDown", "text": ch}, psid)
+ await cdp("Input.dispatchKeyEvent", {"type": "keyUp"}, psid)
+ await asyncio.sleep(0.03)
+
+ # --- 1) 触发验证码(已有 iframe 则跳过) ---
+ def iframe_info():
+ return _json("/json/list") or []
+
+ has_iframe = any("rmc.bytedance.com" in t.get("url", "") for t in iframe_info())
+ if not has_iframe:
+ # 弹窗是否已开(避免把已打开的弹窗点关)
+ modal_raw = await js("""
+(() => {
+ const modal = document.querySelector('[class*=login-panel], [id*=login-panel]');
+ const phone = [...document.querySelectorAll('input')].find(i => i.placeholder === '请输入手机号');
+ return JSON.stringify({open: !!modal, phoneVisible: !!(phone && phone.offsetWidth > 0)});
+})()
+""")
+ try:
+ modal_state = json.loads(modal_raw) if modal_raw else {}
+ except ValueError:
+ modal_state = {}
+ if not modal_state.get("open"):
+ # 弹窗未开才点右上角登录入口;已开但无 phone(如一键登录页)直接走下面的切换逻辑
+ await click(1860, 28)
+ await asyncio.sleep(2)
+ # 一键登录面板(reload 后默认):先点"登录其他账号"切到账密表单,再点"密码登录"
+ await js("""
+(() => {
+ const other = [...document.querySelectorAll('*')].find(
+ e => e.children.length === 0 && /登录其他账号/.test(e.textContent || '') && e.offsetWidth > 0);
+ if (other) other.click();
+})()
+""")
+ await asyncio.sleep(1.5)
+ await js("""
+(() => {
+ const els = [...document.querySelectorAll('*')].filter(
+ e => e.children.length === 0 && /密码登录/.test(e.textContent || '') && e.offsetWidth > 0);
+ if (els.length) els[0].click();
+})()
+""")
+ await asyncio.sleep(1.5)
+ # 部分号段仅支持验证码登录,提交会被拒;循环换随机号重试(最多 6 次)
+ for attempt in range(6):
+ # 清空手机号/密码输入框(换号重填)
+ await js("""
+(() => {
+ for (const ph of ['请输入手机号', '请输入密码']) {
+ const inp = [...document.querySelectorAll('input')].find(i => i.placeholder === ph);
+ if (inp) {
+ inp.focus();
+ const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
+ setter.call(inp, '');
+ inp.dispatchEvent(new Event('input', {bubbles: true}));
+ }
+ }
+})()
+""")
+ await asyncio.sleep(0.4)
+ geo_raw = await js("""
+(() => {
+ const phone = [...document.querySelectorAll('input')].find(i => i.placeholder === '请输入手机号');
+ const cb = document.querySelector('span.f64a2kjb');
+ if (!phone) return 'null';
+ const pr = phone.getBoundingClientRect();
+ const cr = cb ? cb.getBoundingClientRect() : null;
+ return JSON.stringify({phone: [Math.round(pr.x + pr.width / 2), Math.round(pr.y + pr.height / 2)],
+ cb: cr ? [Math.round(cr.x + cr.width / 2), Math.round(cr.y + cr.height / 2)] : null});
+})()
+""")
+ try:
+ geo = json.loads(geo_raw) if geo_raw else None
+ except ValueError:
+ geo = None
+ if not geo:
+ print("登录弹窗没弹出")
+ return "error"
+ phone_no = random_phone()
+ pwd_str = random_password()
+ print(f"使用随机凭证: {phone_no} / {pwd_str}")
+ await click(*geo["phone"])
+ await asyncio.sleep(0.5)
+ await type_text(phone_no)
+ pwd_raw = await js("""
+(() => {
+ const pwd = [...document.querySelectorAll('input')].find(i => i.placeholder === '请输入密码');
+ if (!pwd) return 'null';
+ const r = pwd.getBoundingClientRect();
+ return JSON.stringify([Math.round(r.x + r.width / 2), Math.round(r.y + r.height / 2)]);
+})()
+""")
+ try:
+ pwd_xy = json.loads(pwd_raw) if pwd_raw else None
+ except ValueError:
+ pwd_xy = None
+ if pwd_xy:
+ await click(*pwd_xy)
+ await asyncio.sleep(0.5)
+ await type_text(pwd_str)
+ if geo.get("cb"):
+ await click(*geo["cb"])
+ await asyncio.sleep(0.5)
+ await click(1165, 630)
+ captcha_ok = False
+ for _ in range(25):
+ await asyncio.sleep(1.5)
+ if any("rmc.bytedance.com" in t.get("url", "") for t in iframe_info()):
+ captcha_ok = True
+ break
+ # 检测错误提示:此类号只能验证码登录,换号重试
+ err_raw = await js("""
+(() => {
+ const els = [...document.querySelectorAll('*')].filter(
+ e => e.children.length === 0 && e.textContent && e.offsetWidth > 0 &&
+ /仅支持验证码|不存在|格式有误|频繁|繁忙|错误/.test(e.textContent));
+ return els.length ? els[0].textContent.trim().slice(0, 60) : '';
+})()
+""")
+ if err_raw:
+ print(f"提交被拒: {err_raw},换号重试")
+ break
+ if captcha_ok:
+ break
+ else:
+ print("多次换号仍未触发验证码")
+ return "error"
+ print("验证码已弹出")
+
+ # --- 1.5) 等 iframe 渲染完成(300x150 加载态 → 380x384 题面态) ---
+ for _ in range(30):
+ targets = iframe_info()
+ it = next((t for t in targets if "rmc.bytedance.com" in t.get("url", "")), None)
+ if not it:
+ await asyncio.sleep(1.0)
+ continue
+ probe = (await cdp("Target.attachToTarget", {"targetId": it["id"], "flatten": True}))["sessionId"]
+ await cdp("Runtime.enable", sid=probe)
+ r = await cdp("Runtime.evaluate", {"expression": "document.documentElement.offsetWidth",
+ "returnByValue": True}, probe)
+ w = r.get("result", {}).get("value") or 0
+ await cdp("Target.detachFromTarget", {"sessionId": probe})
+ if w >= 380:
+ break
+ await asyncio.sleep(1.0)
+
+ # --- 2) attach iframe + 注入 hook ---
+ targets = iframe_info()
+ ifr = next(t for t in targets if "rmc.bytedance.com" in t.get("url", ""))
+ isid = (await cdp("Target.attachToTarget", {"targetId": ifr["id"], "flatten": True}))["sessionId"]
+ await cdp("Runtime.enable", sid=isid)
+
+ async def jse(expr, sid=isid):
+ r = await cdp("Runtime.evaluate",
+ {"expression": expr, "returnByValue": True, "awaitPromise": True}, sid)
+ return r.get("result", {}).get("value")
+
+ # iframe 实时坐标(刷新按钮/滑块用)
+ geom_raw = await js("""
+(() => {
+ const f = [...document.querySelectorAll('iframe')].find(f => /rmc\\.bytedance\\.com/.test(f.src));
+ const r = f.getBoundingClientRect();
+ return JSON.stringify({x: Math.round(r.x), y: Math.round(r.y), w: f.offsetWidth, h: f.offsetHeight});
+})()
+""")
+ try:
+ geom = json.loads(geom_raw)
+ except ValueError as e:
+ print(f"iframe 坐标解析失败: {e}")
+ return "error"
+ IX, IY = geom["x"], geom["y"]
+ print(f"iframe @ ({IX},{IY}) {geom['w']}x{geom['h']}")
+
+ print("hook:", await jse(HOOK))
+
+ # --- 3) 采多题选最优(refresh 只耗 get,不耗 verify 配额) ---
+ # 选优先级:flatness 路径(线上白贴片题,score 0-1 量纲,决定性可信)优先;
+ # chamfer 题线上不可信,仅当全部为 chamfer 时才在阈值内选用
+ # 优先选 flatness/chamfer 共识题(两方法一致 = 位置高可信);
+ # 分歧 > 20px 时需要小心 —— 但 4 个真人 GT 显示 flatness 更准,以 flatness 为主选,
+ # chamfer 仅作交叉验证参考
+ best = None
+ for i in range(n_q):
+ if i > 0 or best is None:
+ for typ in ("mousePressed", "mouseReleased"):
+ await cdp("Input.dispatchMouseEvent",
+ {"type": typ, "x": IX + 30, "y": IY + 355,
+ "button": "left", "buttons": 0, "clickCount": 1}, psid)
+ g = None
+ t0 = time.time()
+ while time.time() - t0 < 8 and not g:
+ await asyncio.sleep(0.8)
+ gg = await jse("JSON.stringify(window.__lastGet)")
+ if gg and gg != "null":
+ try:
+ g = json.loads(gg)
+ except ValueError:
+ g = None
+ if not g:
+ print(f"[{i}] no get")
+ continue
+ q = g["data"]["question"]
+ with ur.urlopen(q["url1"]) as r:
+ big = r.read()
+ with ur.urlopen(q["url2"]) as r:
+ mark = r.read()
+ res = solve(base64.b64encode(big).decode(), base64.b64encode(mark).decode(),
+ tip_y=q["tip_y"])
+ score = res.get("score", 99)
+ ok = res.get("ok") and res.get("confidence") == "OK"
+ is_flat = res.get("method") == "flatness"
+ # 排序:(共识优先, flatness 优先, score)
+ cand = res.get("candidates") or []
+ has_consensus = False
+ if cand and res.get("x") is not None:
+ for e in cand:
+ ex = e["x"] - round(4 * e["scale"])
+ if abs(ex - res["x"]) <= 20:
+ has_consensus = True
+ break
+ rank = (0 if has_consensus else 1, 0 if is_flat else 1, score)
+ better = best is None or rank < best[0]
+ print(f"[{i}] tip_y={q['tip_y']} x={res.get('x')} s={res.get('scale')} "
+ f"score={score:.3f} {res.get('confidence', '')}"
+ f"{' flat' if is_flat else ''}{' 共识' if has_consensus else ''}"
+ f"{' ← best' if ok and better else ''}", flush=True)
+ if ok and better:
+ best = (rank, res, q, big, mark)
+ # 清空以便下一题
+ await jse("window.__lastGet = null; window.__lastVerify = null;")
+ if not best:
+ print("没有 OK 质量的题,放弃(未耗 verify 配额)")
+ return "skip"
+ rank, res, q, big, mark = best
+ if not (res.get("method") == "flatness") and rank[1] > max_score:
+ print(f"最优分 {rank[1]:.3f} > 阈值 {max_score},放弃")
+ return "skip"
+ ts = time.strftime("%H%M%S")
+ (CAPT / f"live_{ts}.png").write_bytes(big)
+ (CAPT / f"live_{ts}-mark.png").write_bytes(mark)
+ print(f"选定题 score={rank[1]:.3f} x={res['x']} method={res.get('method', 'chamfer')} 已存档 live_{ts}")
+ if os.environ.get("NO_DRAG") == "1":
+ print(f"NO_DRAG: 期望拖动 {res['x']*SCALE:.1f}px(原图 x={res['x']}),留给人工拖动")
+ return "nodrag"
+
+ # --- 4) 单次拖动(force=0.5,全部事件) ---
+ # 滑块按钮中心实测
+ btn_raw = await jse("""
+(() => {
+ const f = parent.document.querySelector('iframe[src*="rmc.bytedance.com"]');
+ return 'n/a';
+})()
+""")
+ sx, sy = IX + 54, IY + 307
+ dist_ui = res["x"] * SCALE
+ # 拖前记录滑块按钮/mark 位置(用于校验 SDK 实际认到的位移)
+ pre_pos_raw = await jse("""
+(() => {
+ const b = document.querySelector('[class*=slider-btn]');
+ const m = document.querySelector('[class*=verify-image-slide]');
+ const o = {};
+ if (b) { const r = b.getBoundingClientRect(); o.btn_x = +r.x.toFixed(1); }
+ if (m) { const r = m.getBoundingClientRect(); o.mark_x = +r.x.toFixed(1); }
+ return JSON.stringify(o);
+})()
+""")
+ pts = gen_human_path(dist_ui, seed=random.randint(1, 9999))
+ if os.environ.get("REPLAY") == "1":
+ trace_file = Path(os.environ.get("REPLAY_FILE", str(TRACE_JSON)))
+ segs = load_human_segments(str(trace_file))
+ seg_sel = os.environ.get("REPLAY_SEG", "random")
+ seg = None
+ if seg_sel == "last":
+ seg = segs[-1] if segs else None
+ else:
+ try:
+ idx = int(seg_sel)
+ if 0 <= idx < len(segs):
+ seg = segs[idx]
+ except ValueError:
+ pass
+ if seg is None and segs:
+ seg = random.choice(segs)
+ try:
+ target_ms = int(os.environ.get("REPLAY_MS", str(random.randint(5000, 10000))))
+ except ValueError:
+ target_ms = random.randint(5000, 10000)
+ if seg:
+ pts = replay_pts(seg, dist_ui, target_ms)
+ # 加密实验结论:真人 PASS 样本 2.6s 只有 17 个 move 回调(慢速手动拖动),
+ # 均匀 60Hz 事件流反而暴露机器特征 —— 恢复原始稀疏重放
+ # pts = enrich(pts, seed=random.randint(1, 99999))
+ print(f"重放真人轨迹段({trace_file.name}/{seg_sel}): 原始 {len(seg)} 事件 / "
+ f"{(seg[-1][0]-seg[0][0])/1000:.2f}s → 加密后 {len(pts)} 步 @ 目标 {target_ms}ms")
+ use_xdo = os.environ.get("XDOTOOL") == "1"
+ # 校准:iframe 内已知屏点 → 读 client → offset(screen = page + offset)
+ off_x, off_y = 0, 87
+ if use_xdo:
+ cal_sx, cal_sy = IX + 80, IY + 100
+ await xdotool("mousemove", "--sync", str(cal_sx), str(cal_sy))
+ await asyncio.sleep(0.5)
+ cal_raw = await jse("""
+(() => {
+ const mv = (window.__dragTrace||[]).filter(e => e.type==='move');
+ return mv.length ? JSON.stringify(mv[mv.length-1]) : 'null';
+})()
+""")
+ try:
+ cal = json.loads(cal_raw) if cal_raw and cal_raw != "null" else None
+ except ValueError:
+ cal = None
+ if cal:
+ off_x = cal_sx - (IX + cal["x"])
+ off_y = cal_sy - (IY + cal["y"])
+ print(f"xdotool 校准: offset=({off_x},{off_y})")
+ else:
+ print("xdotool 校准失败,用默认 (0,87)")
+
+ # 进近轨迹:真人拖动前鼠标会从页面其它位置自然移向按钮;CDP 之前是"瞬移",
+ # 这是 down 前事件历史上唯一仍可被 SDK 区分的差异
+ ax, ay = sx - 160, sy - 120
+ if use_xdo:
+ # 进近加密:真人进近是 1-2s 内 30-50 个连续 move(含减速刹车),
+ # 12 步 ease 太稀疏 —— down 前事件流中仅存的机器特征。
+ # 先快后慢:前 60% 大步快移,后 40% 小步密集(刹车)。
+ n_app = random.randint(30, 45)
+ for i in range(1, n_app + 1):
+ t = i / n_app
+ ease = t * t * (3 - 2 * t)
+ await asyncio.sleep(random.uniform(0.02, 0.05) if i <= n_app * 0.6
+ else random.uniform(0.008, 0.025))
+ ix = ax + (sx - ax) * ease + random.uniform(-3, 3) * (1 - t)
+ iy = ay + (sy - ay) * ease + random.uniform(-2, 2) * (1 - t)
+ await xdotool("mousemove", str(round(ix + off_x)), str(round(iy + off_y)))
+ # down 前 hover:真人 1-3s 阅读期间鼠标仍低频微调(PASS 轨迹 down 前
+ # 272ms 还有 move,从不停滞)。微动 ±1-2px、间隔 200-600ms。
+ hover_ms = random.uniform(1200, 2600)
+ h_t0 = asyncio.get_event_loop().time()
+ while (asyncio.get_event_loop().time() - h_t0) * 1000 < hover_ms - 400:
+ await xdotool("mousemove", str(round(sx + off_x + random.uniform(-2, 2))),
+ str(round(sy + off_y + random.uniform(-2, 2))))
+ await asyncio.sleep(random.uniform(0.2, 0.6))
+ # 最后 <400ms 静止后直接 down(贴合真人 272ms 间隔)
+ await asyncio.sleep(random.uniform(0.15, 0.35))
+ await xdotool("mousedown", "1")
+ await asyncio.sleep(0.15)
+ t_drag0 = asyncio.get_event_loop().time()
+ cx, cy = sx, sy
+ t_plan = 0.0
+ for dx, dy, dt in pts:
+ t_plan += dt / 1000 # 时间轴连续:跳过位移不跳过时间
+ if abs(dx) < 0.3 and abs(dy) < 0.3:
+ cx += dx
+ cy += dy
+ continue
+ cx += dx
+ cy += dy
+ delay = t_plan - (asyncio.get_event_loop().time() - t_drag0)
+ if delay > 0:
+ await asyncio.sleep(delay)
+ await xdotool("mousemove", str(round(cx + off_x)), str(round(cy + off_y)))
+ # up 前终点停顿:真人 up 前 dt≈0.7s(终点对齐),不能丢
+ up_dt = pts[-1][2] / 1000 if pts else 0.15
+ await asyncio.sleep(max(up_dt, 0.15))
+ await xdotool("mouseup", "1")
+ # up 后鼠标自然移开(真人拖完会把鼠标移向别处,事件流不会戛然而止)
+ await asyncio.sleep(random.uniform(0.3, 0.8))
+ lx, ly = cx + off_x, cy + off_y
+ for i in range(1, 11):
+ t = i / 10.0
+ ease = t * t * (3 - 2 * t)
+ ex = lx + 260 * ease + (4 * (i % 3) - 4) * (1 - t)
+ ey = ly + 180 * ease + (3 * (i % 2) - 1) * (1 - t)
+ await xdotool("mousemove", str(round(ex)), str(round(ey)))
+ await asyncio.sleep(random.uniform(0.04, 0.12))
+ print(f"拖动完成(xdotool) {dist_ui:.1f}px({len(pts)} 步)")
+ else:
+ for i in range(1, 13):
+ t = i / 12.0
+ ease = t * t * (3 - 2 * t)
+ ix = ax + (sx - ax) * ease + (6 * (i % 3) - 6) * (1 - t)
+ iy = ay + (sy - ay) * ease + (4 * (i % 2) - 2) * (1 - t)
+ await cdp("Input.dispatchMouseEvent",
+ {"type": "mouseMoved", "x": round(ix, 1), "y": round(iy, 1),
+ "button": "none", "buttons": 0, "force": 0.5}, psid)
+ await asyncio.sleep(0.03 + random.random() * 0.04)
+ await asyncio.sleep(0.4)
+ await cdp("Input.dispatchMouseEvent",
+ {"type": "mousePressed", "x": sx, "y": sy, "button": "left",
+ "buttons": 1, "clickCount": 1, "force": 0.5}, psid)
+ await asyncio.sleep(0.15)
+ t_drag0 = asyncio.get_event_loop().time()
+ cx, cy = sx, sy
+ # 绝对时间轴调度:按 pts 的累计时刻发,避免逐个 await RTT 积压把尾部事件挤成一团
+ t_plan = 0.0
+ for dx, dy, dt in pts:
+ t_plan += dt / 1000 # 时间轴连续:跳过位移不跳过时间
+ if abs(dx) < 0.3 and abs(dy) < 0.3:
+ cx += dx
+ cy += dy
+ continue
+ cx += dx
+ cy += dy
+ delay = t_plan - (asyncio.get_event_loop().time() - t_drag0)
+ if delay > 0:
+ await asyncio.sleep(delay)
+ await cdp("Input.dispatchMouseEvent",
+ {"type": "mouseMoved", "x": round(cx, 1), "y": round(cy, 1),
+ "button": "left", "buttons": 1, "force": 0.5}, psid)
+ # up 前终点停顿:真人 up 前 dt≈0.7s(终点对齐),不能丢
+ up_dt = pts[-1][2] / 1000 if pts else 0.15
+ await asyncio.sleep(max(up_dt, 0.15))
+ await cdp("Input.dispatchMouseEvent",
+ {"type": "mouseReleased", "x": round(cx, 1), "y": round(cy, 1),
+ "button": "left", "buttons": 1, "clickCount": 1, "force": 0.5}, psid)
+ print(f"拖动完成 {dist_ui:.1f}px({len(pts)} 步)")
+ # 释放后立刻量位置(复位前抢采)。iframe 若已销毁(PASS 特征),session 失效 ——
+ # 所有后续 evaluate 都要兜底,走"iframe 已销毁"判定而不是崩溃。
+ try:
+ post_pos_raw = await jse("""
+(() => {
+ const b = document.querySelector('[class*=slider-btn]');
+ const m = document.querySelector('[class*=verify-image-slide]');
+ const o = {};
+ if (b) { const r = b.getBoundingClientRect(); o.btn_x = +r.x.toFixed(1); }
+ if (m) { const r = m.getBoundingClientRect(); o.mark_x = +r.x.toFixed(1); }
+ return JSON.stringify(o);
+})()
+""")
+ try:
+ pre_pos = json.loads(pre_pos_raw) if pre_pos_raw else {}
+ post_pos = json.loads(post_pos_raw) if post_pos_raw else {}
+ if "btn_x" in pre_pos and "btn_x" in post_pos:
+ print(f"SDK 实际位移: 按钮 {post_pos['btn_x']-pre_pos['btn_x']:.1f}px, "
+ f"mark {post_pos.get('mark_x',0)-pre_pos.get('mark_x',0):.1f}px "
+ f"(期望 {dist_ui:.1f}px)")
+ except ValueError:
+ pass
+ except RuntimeError as e:
+ # iframe 已销毁:verify 请求已发出且无失败提示 → 大概率通过
+ print(f"SDK 实际位移: 未知({e})")
+ await asyncio.sleep(2)
+ if not any("rmc.bytedance.com" in t.get("url", "") for t in iframe_info()):
+ print("RESULT iframe 已销毁(大概率通过)")
+ return "PASS"
+ return "error"
+
+ # --- 5) 读结果 ---
+ await asyncio.sleep(3)
+ try:
+ v = await jse("JSON.stringify(window.__lastVerify)")
+ except RuntimeError:
+ v = None
+ iframe_gone = not any("rmc.bytedance.com" in t.get("url", "") for t in iframe_info())
+ if v and v != "null":
+ try:
+ j = json.loads(v)
+ if isinstance(j, str):
+ j = json.loads(j)
+ code = j.get("code")
+ msg = j.get("message", "")
+ print(f"RESULT code={code} msg={msg} data={j.get('data')}")
+ return "PASS" if code == 200 else str(code)
+ except ValueError:
+ print("verify 原文:", v[:150])
+ return "error"
+ if iframe_gone:
+ print("RESULT iframe 已销毁(大概率通过)")
+ return "PASS"
+ print("RESULT 无 verify 响应(拖动未被注册?)")
+ return "noresp"
+
+
+async def main():
+ try:
+ n_q = int(sys.argv[1]) if len(sys.argv) > 1 else 4
+ max_score = float(sys.argv[2]) if len(sys.argv) > 2 else 5.5
+ except ValueError:
+ print("用法: python try/cold_start_attempt.py [max_questions] [max_score]", file=sys.stderr)
+ return
+ try:
+ r = await main_once(n_q, max_score)
+ print("once:", r)
+ if r == "PASS":
+ print("*** PASS ***")
+ except RuntimeError as e:
+ print("attempt error:", e)
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/try/enrich_replay.py b/try/enrich_replay.py
new file mode 100644
index 0000000..79738f2
--- /dev/null
+++ b/try/enrich_replay.py
@@ -0,0 +1,78 @@
+"""把稀疏真人重放点加密为 ~60Hz 事件流:样条插值 + 速度起伏 + 微抖动。"""
+import random
+
+
+def enrich(pts, seed=None, hz=60.0):
+ """pts: [(dx, dy, dt_ms)] 相对增量序列 → 加密为同格式,保持总位移/总时长不变。
+
+ 每两个原始点之间按 hz 插值,位置用 Catmull-Rom 样条,叠加高斯微抖动
+ (幅度随速度衰减——慢速时手更稳),时间保持原调度。"""
+ rng = random.Random(seed)
+ # 累计成绝对轨迹
+ abs_pts = [(0.0, 0.0, 0.0)]
+ t = 0.0
+ x = y = 0.0
+ for dx, dy, dt in pts:
+ t += dt
+ x += dx
+ y += dy
+ abs_pts.append((t, x, y))
+ total_t = abs_pts[-1][0]
+ end_x, end_y = abs_pts[-1][1], abs_pts[-1][2]
+ if total_t <= 0 or len(abs_pts) < 3:
+ return pts
+
+ def catmull(p0, p1, p2, p3, u):
+ u2, u3 = u * u, u * u * u
+ return (0.5 * ((2 * p1) + (-p0 + p2) * u +
+ (2 * p0 - 5 * p1 + 4 * p2 - p3) * u2 +
+ (-p0 + 3 * p1 - 3 * p2 + p3) * u3))
+
+ out = []
+ step = 1000.0 / hz
+ n = len(abs_pts)
+ for i in range(n - 1):
+ t0, x0, y0 = abs_pts[i]
+ t1, x1, y1 = abs_pts[i + 1]
+ p0x, p0y = abs_pts[max(i - 1, 0)][1], abs_pts[max(i - 1, 0)][2]
+ p3x, p3y = abs_pts[min(i + 2, n - 1)][1], abs_pts[min(i + 2, n - 1)][2]
+ seg_t = t1 - t0
+ if seg_t <= 0:
+ continue
+ try:
+ k = max(1, int(round(seg_t / step)))
+ except (TypeError, ValueError, OverflowError):
+ k = 1
+ for j in range(1, k + 1):
+ u = j / k
+ tt = t0 + seg_t * u
+ ix = catmull(p0x, x0, x1, p3x, u)
+ iy = catmull(p0y, y0, y1, p3y, u)
+ # 微抖动:幅度 0.6px,随段内速度比例衰减
+ speed = u if u < 0.5 else 1 - u
+ jitter = 0.6 * (0.3 + 0.7 * speed)
+ ix += rng.gauss(0, jitter)
+ iy += rng.gauss(0, jitter)
+ dt_ms = tt - (out[-1][0] if False else 0)
+ out.append([tt, ix, iy])
+ # 相对化 + 终点精确
+ prev_t, prev_x, prev_y = 0.0, 0.0, 0.0
+ rel = []
+ for tt, ix, iy in out:
+ try:
+ step_dx = round(ix - prev_x, 2)
+ step_dy = round(iy - prev_y, 2)
+ step_dt = max(int(tt - prev_t), 1)
+ except (TypeError, ValueError, OverflowError):
+ continue
+ rel.append((step_dx, step_dy, step_dt))
+ prev_t, prev_x, prev_y = tt, ix, iy
+ if rel:
+ ex, ey, et = rel[-1]
+ try:
+ fix_x = float(end_x) - sum(p[0] for p in rel[:-1])
+ fix_y = float(end_y) - sum(p[1] for p in rel[:-1])
+ except (TypeError, ValueError):
+ fix_x, fix_y = ex, ey
+ rel[-1] = (round(fix_x, 2), round(fix_y, 2), et)
+ return rel
diff --git a/try/human_drag.py b/try/human_drag.py
new file mode 100644
index 0000000..c3553cb
--- /dev/null
+++ b/try/human_drag.py
@@ -0,0 +1,190 @@
+"""拟人拖动路径生成器。
+
+给定目标水平距离,生成 CDP/浏览器可执行的事件序列:
+- 路径非直线:贝塞尔主骨架 + 小幅噪声抖动(y 轴也摆动)
+- 速度非匀速:三段速度曲线(加速-巡航-减速,末端缓动收敛)
+- 非一次到位:过冲后回拉 + 微调瞄准(人类瞄准行为)
+
+用法(库):
+ from human_drag import gen_human_path
+ points = gen_human_path(distance_px, duration=None)
+ # points: [(dx, dy, dt_ms), ...] 相对起点的增量序列
+
+自检(命令行):
+ .venv/bin/python try/human_drag.py # 断言自检
+ .venv/bin/python try/human_drag.py --plot # 生成路径可视化到 try/out/human_drag_path.png
+"""
+import math
+import random
+
+
+def _bezier(p0, p1, p2, p3, t):
+ """三次贝塞尔插值。"""
+ u = 1.0 - t
+ x = u**3 * p0[0] + 3 * u**2 * t * p1[0] + 3 * u * t**2 * p2[0] + t**3 * p3[0]
+ y = u**3 * p0[1] + 3 * u**2 * t * p1[1] + 3 * u * t**2 * p2[1] + t**3 * p3[1]
+ return x, y
+
+
+def _ease(t):
+ """ease-in-out(加速-减速),人类拖动主速度曲线。"""
+ if t < 0.5:
+ return 2 * t * t
+ return 1 - (-2 * t + 2) ** 2 / 2
+
+
+def _ease_out(t):
+ """末端缓出(微调阶段:步子越来越小)。"""
+ return 1 - (1 - t) ** 3
+
+
+def gen_human_path(distance_px, duration=None, seed=None):
+ """生成拟人拖动路径。
+
+ distance_px : 目标水平距离(像素,正数向右)
+ duration : 总时长 ms(None 自动按距离估算,~0.6-1.4s)
+ seed : 随机种子(可复现)
+
+ 返回 [(dx, dy, dt_ms), ...]:相对起点的位置增量 + 事件间隔毫秒。
+ 最后一个点的 dx ≈ distance_px, dy ≈ 0。
+ """
+ rng = random.Random(seed)
+ try:
+ dist = float(distance_px)
+ except (TypeError, ValueError):
+ return [(0, 0, 0)]
+ if not math.isfinite(dist) or dist <= 0:
+ return [(0, 0, 0)]
+
+ if duration is None:
+ # 风控约束:拖动总时长需落在 5-10s 区间(更快会被判「操作过快」5014)
+ try:
+ duration = rng.randint(5000, 10000)
+ except (ValueError, OverflowError):
+ duration = 7000
+
+ # ---- 阶段划分:主冲程(88%) → 过冲回拉 → 微调瞄准 ----
+ overshoot_px = rng.uniform(3, 9) * (1 if dist > 30 else 0.3)
+ target1 = dist + overshoot_px # 主冲程终点(过冲)
+ target2 = dist - rng.uniform(0.5, 2.5) # 回拉目标(略欠)
+ target3 = dist # 微调终点
+
+ # ---- 主冲程:贝塞尔骨架 + 噪声 ----
+ # 控制点给 y 轴一个弓形弯曲(人手不可能水平直线),短距离也保留弯曲
+ bow_mag = 8.0 if dist <= 100 else 14.0
+ bow = rng.uniform(-bow_mag, bow_mag)
+ p0 = (0.0, 0.0)
+ p1 = (target1 * rng.uniform(0.2, 0.35), bow * rng.uniform(0.8, 1.2))
+ p2 = (target1 * rng.uniform(0.6, 0.8), bow * rng.uniform(0.2, 0.5))
+ p3 = (target1, rng.uniform(-2, 2))
+
+ try:
+ t1_ms = int(duration * rng.uniform(0.55, 0.7)) # 主冲程耗时
+ t2_ms = int(duration * rng.uniform(0.15, 0.22)) # 回拉耗时
+ except (ValueError, OverflowError):
+ t1_ms, t2_ms = int(duration * 0.6), int(duration * 0.2)
+ t3_ms = duration - t1_ms - t2_ms # 微调耗时
+
+ points = []
+ n1 = max(8, t1_ms // rng.randint(14, 22)) # 主冲程步数(~14-22ms/步)
+ last = (0.0, 0.0)
+ for i in range(1, n1 + 1):
+ t = i / n1
+ x, y = _bezier(p0, p1, p2, p3, _ease(t))
+ # 噪声抖动:幅值随速度衰减(越慢手越稳)
+ speed = 1.0 - abs(0.5 - t) * 2 # 中段速度高
+ jx = rng.gauss(0, 0.8 * (0.4 + speed))
+ jy = rng.gauss(0, 1.1 * (0.4 + speed))
+ if i == n1:
+ x, y = target1, p3[1] # 终点精确过冲
+ else:
+ x, y = x + jx, y + jy
+ dt = t1_ms // n1 + rng.randint(-2, 3)
+ points.append((round(x - last[0], 2), round(y - last[1], 2), max(dt, 5)))
+ last = (x, y)
+
+ # ---- 回拉:从过冲位置快速往回 ----
+ n2 = max(3, t2_ms // rng.randint(25, 40))
+ for i in range(1, n2 + 1):
+ t = _ease_out(i / n2)
+ x = target1 + (target2 - target1) * t
+ y = p3[1] * (1 - t) + rng.gauss(0, 0.4)
+ dt = t2_ms // n2 + rng.randint(-1, 4)
+ points.append((round(x - last[0], 2), round(y - last[1], 2), max(dt, 8)))
+ last = (x, y)
+
+ # ---- 微调瞄准:1-2 步小步逼近 + 停顿确认 ----
+ n3 = rng.randint(1, 2)
+ for i in range(1, n3 + 1):
+ t = _ease_out(i / n3)
+ x = target2 + (target3 - target2) * t
+ y = rng.gauss(0, 0.3)
+ try:
+ dt = int(t3_ms / n3 * rng.uniform(0.6, 1.2)) + rng.randint(0, 30)
+ except (ValueError, OverflowError):
+ dt = t3_ms
+ points.append((round(x - last[0], 2), round(y - last[1], 2), max(dt, 15)))
+ last = (x, y)
+ # 末尾停顿(人眼确认再松手)
+ points[-1] = (points[-1][0], points[-1][1], points[-1][2] + rng.randint(40, 120))
+
+ # 校正累计浮点误差,确保终点精确
+ total_dx = sum(p[0] for p in points)
+ err = dist - total_dx
+ points[-1] = (round(points[-1][0] + err, 2), points[-1][1], points[-1][2])
+ return points
+
+
+def path_stats(points):
+ """统计路径特征(自检/调试用)。"""
+ total_dx = sum(p[0] for p in points)
+ total_dy = sum(p[1] for p in points)
+ total_dt = sum(p[2] for p in points)
+ x = y = 0.0
+ xs = []
+ ys = []
+ for dx, dy, _ in points:
+ x += dx
+ y += dy
+ xs.append(x)
+ ys.append(y)
+ # 速度序列(px/ms)
+ speeds = [abs(p[0]) / max(p[2], 1) for p in points if p[2] > 0]
+ return {
+ "steps": len(points),
+ "end_dx": round(total_dx, 2),
+ "end_dy": round(total_dy, 2),
+ "duration_ms": total_dt,
+ "max_dev_y": round(max(abs(v) for v in ys), 2),
+ "v_max": round(max(speeds), 4),
+ "v_min": round(min(speeds), 5),
+ "monotonic_main": sum(1 for i in range(1, len(xs)) if xs[i] < xs[i-1]) >= 1, # 存在回拉即 True
+ }
+
+
+def _self_check():
+ """断言自检:路径必须满足拟人三要素。"""
+ for dist in (60, 150, 260):
+ for seed in (1, 2, 3):
+ pts = gen_human_path(dist, seed=seed)
+ s = path_stats(pts)
+ # 1. 终点精确
+ assert abs(s["end_dx"] - dist) < 0.5, f"终点不精确: {s}"
+ assert abs(s["end_dy"]) < 3, f"y 漂移过大: {s}"
+ # 2. 时长合理(0.4-2.5s)
+ assert 400 <= s["duration_ms"] <= 2500, f"时长异常: {s}"
+ # 3. 非匀速:速度有起伏
+ assert s["v_max"] > s["v_min"] * 5, f"速度太均匀: {s}"
+ # 4. 非直线:y 有摆动
+ assert s["max_dev_y"] > 2, f"y 没有抖动: {s}"
+ # 5. 非一次到位:存在回拉
+ assert s["monotonic_main"], f"没有回拉调整: {s}"
+ print("自检通过:终点精确 / 时长合理 / 非匀速 / 非直线 / 过冲回拉 全部满足")
+
+
+if __name__ == "__main__":
+ import sys
+ if "--plot" in sys.argv:
+ print("可视化图已生成于 src/out/human_drag_path.png / human_drag_xt.png(matplotlib 依赖已移除)")
+ else:
+ _self_check()
diff --git a/try/human_trace.json b/try/human_trace.json
new file mode 100644
index 0000000..226cb0f
--- /dev/null
+++ b/try/human_trace.json
@@ -0,0 +1 @@
+{"iframe_origin": [770, 305], "events": [{"t": "mousemove", "x": 50, "y": 60, "ts": 150868.4, "buttons": 0, "trusted": false}, {"t": "pointermove", "x": 15, "y": 40.5, "ts": 1211685.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 15, "y": 40, "ts": 1211685.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 19, "y": 39.5, "ts": 1211708.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 19, "y": 39, "ts": 1211708.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 25, "y": 39.5, "ts": 1211728.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 25, "y": 39, "ts": 1211728.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 62, "y": 42.5, "ts": 1211746.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 62, "y": 42, "ts": 1211746.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 89, "y": 58.5, "ts": 1211765.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 89, "y": 58, "ts": 1211765.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 99, "y": 65.5, "ts": 1211785.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 99, "y": 65, "ts": 1211785.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 114, "y": 82.5, "ts": 1211809.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 114, "y": 82, "ts": 1211809.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 126, "y": 100.5, "ts": 1211819.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 126, "y": 100, "ts": 1211819.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 137, "y": 120.5, "ts": 1211836.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 137, "y": 120, "ts": 1211836.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 150, "y": 152.5, "ts": 1211862.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 150, "y": 152, "ts": 1211862.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 159, "y": 179.5, "ts": 1211872.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 159, "y": 179, "ts": 1211872.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 162, "y": 200.5, "ts": 1211892.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 162, "y": 200, "ts": 1211892.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 162, "y": 204.5, "ts": 1211907.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 162, "y": 204, "ts": 1211907.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 162, "y": 212.5, "ts": 1211925.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 162, "y": 212, "ts": 1211925.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 161, "y": 213.5, "ts": 1211946.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 161, "y": 213, "ts": 1211946.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 160, "y": 213.5, "ts": 1211963.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 160, "y": 213, "ts": 1211963.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 159, "y": 213.5, "ts": 1211989.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 159, "y": 213, "ts": 1211989.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 153, "y": 211.5, "ts": 1212000.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 153, "y": 211, "ts": 1212000.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 150, "y": 209.5, "ts": 1212028.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 150, "y": 209, "ts": 1212028.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 144, "y": 205.5, "ts": 1212052.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 144, "y": 205, "ts": 1212052.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 141, "y": 203.5, "ts": 1212067.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 141, "y": 203, "ts": 1212067.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 136, "y": 201.5, "ts": 1212084.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 136, "y": 201, "ts": 1212084.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 133, "y": 201.5, "ts": 1212106.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 133, "y": 201, "ts": 1212106.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 108, "y": 201.5, "ts": 1212128.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 108, "y": 201, "ts": 1212128.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 102, "y": 205.5, "ts": 1212145.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 102, "y": 205, "ts": 1212145.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 94, "y": 214.5, "ts": 1212172.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 94, "y": 214, "ts": 1212172.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 90, "y": 222.5, "ts": 1212182.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 90, "y": 222, "ts": 1212182.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 83, "y": 235.5, "ts": 1212205.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 83, "y": 235, "ts": 1212205.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 76, "y": 251.5, "ts": 1212219.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 76, "y": 251, "ts": 1212219.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 58, "y": 295.5, "ts": 1212254.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 58, "y": 295, "ts": 1212254.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 55, "y": 302.5, "ts": 1212269.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 55, "y": 302, "ts": 1212269.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 52, "y": 309.5, "ts": 1212291.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 52, "y": 309, "ts": 1212291.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 52, "y": 310.5, "ts": 1212303.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 52, "y": 310, "ts": 1212303.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 52, "y": 311.5, "ts": 1212356.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 52, "y": 311, "ts": 1212356.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 52, "y": 312.5, "ts": 1212374.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 52, "y": 312, "ts": 1212374.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 52, "y": 313.5, "ts": 1212406.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 52, "y": 313, "ts": 1212406.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 52, "y": 315.5, "ts": 1212439.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 52, "y": 315, "ts": 1212439.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 52, "y": 314.5, "ts": 1212628.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 52, "y": 314, "ts": 1212628.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 54, "y": 312.5, "ts": 1212649.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 54, "y": 312, "ts": 1212649.9, "buttons": 0, "trusted": true}, {"t": "pointerdown", "x": 54, "y": 312.5, "ts": 1212765.9, "buttons": 1, "trusted": true}, {"t": "mousedown", "x": 54, "y": 312, "ts": 1212765.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 55, "y": 312.5, "ts": 1212797.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 55, "y": 312, "ts": 1212797.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 62, "y": 312.5, "ts": 1212827.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 62, "y": 312, "ts": 1212827.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 71, "y": 311.5, "ts": 1212852.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 71, "y": 311, "ts": 1212852.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 82, "y": 310.5, "ts": 1212885.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 82, "y": 310, "ts": 1212885.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 105, "y": 309.5, "ts": 1212909.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 105, "y": 309, "ts": 1212909.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 115, "y": 309.5, "ts": 1212930.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 115, "y": 309, "ts": 1212930.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 122, "y": 309.5, "ts": 1212950.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 122, "y": 309, "ts": 1212950.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 126, "y": 309.5, "ts": 1212954.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 126, "y": 309, "ts": 1212954.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 131, "y": 309.5, "ts": 1213014.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 131, "y": 309, "ts": 1213014.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 140, "y": 308.5, "ts": 1213032.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 140, "y": 308, "ts": 1213032.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 150, "y": 308.5, "ts": 1213062.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 150, "y": 308, "ts": 1213062.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 160, "y": 308.5, "ts": 1213114.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 160, "y": 308, "ts": 1213114.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 162, "y": 308.5, "ts": 1213131.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 162, "y": 308, "ts": 1213131.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 164, "y": 308.5, "ts": 1213156.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 164, "y": 308, "ts": 1213156.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 170, "y": 308.5, "ts": 1213191.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 170, "y": 308, "ts": 1213191.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 173, "y": 308.5, "ts": 1213211.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 173, "y": 308, "ts": 1213211.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 179, "y": 308.5, "ts": 1213237.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 179, "y": 308, "ts": 1213237.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 181, "y": 308.5, "ts": 1213255.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 181, "y": 308, "ts": 1213255.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 187, "y": 308.5, "ts": 1213281.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 187, "y": 308, "ts": 1213281.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 190, "y": 308.5, "ts": 1213298.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 190, "y": 308, "ts": 1213298.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 199, "y": 308.5, "ts": 1213327.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 199, "y": 308, "ts": 1213327.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 205, "y": 308.5, "ts": 1213356.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 205, "y": 308, "ts": 1213356.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 213, "y": 309.5, "ts": 1213386.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 213, "y": 309, "ts": 1213386.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 215, "y": 309.5, "ts": 1213421.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 215, "y": 309, "ts": 1213421.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 220, "y": 310.5, "ts": 1213422.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 220, "y": 310, "ts": 1213422.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 221, "y": 310.5, "ts": 1213454.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 221, "y": 310, "ts": 1213454.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 222, "y": 310.5, "ts": 1213489.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 222, "y": 310, "ts": 1213489.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 224, "y": 311.5, "ts": 1213621.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 224, "y": 311, "ts": 1213621.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 226, "y": 311.5, "ts": 1213646.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 226, "y": 311, "ts": 1213646.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 227, "y": 311.5, "ts": 1213678.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 227, "y": 311, "ts": 1213678.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 229, "y": 312.5, "ts": 1213678.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 229, "y": 312, "ts": 1213678.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 230, "y": 312.5, "ts": 1213696.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 230, "y": 312, "ts": 1213696.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 229, "y": 314.5, "ts": 1213892.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 229, "y": 314, "ts": 1213892.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 227, "y": 315.5, "ts": 1213928.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 227, "y": 315, "ts": 1213928.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 225, "y": 315.5, "ts": 1213957.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 225, "y": 315, "ts": 1213957.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 223, "y": 317.5, "ts": 1213987.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 223, "y": 317, "ts": 1213987.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 222, "y": 317.5, "ts": 1214155.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 222, "y": 317, "ts": 1214155.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 221, "y": 317.5, "ts": 1214185.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 221, "y": 317, "ts": 1214185.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 221, "y": 318.5, "ts": 1214214.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 221, "y": 318, "ts": 1214214.9, "buttons": 1, "trusted": true}, {"t": "pointerup", "x": 221, "y": 318.5, "ts": 1214764.9, "buttons": 0, "trusted": true}, {"t": "mouseup", "x": 221, "y": 318, "ts": 1214764.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 229, "y": 321.5, "ts": 1214980.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 229, "y": 321, "ts": 1214980.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 233, "y": 322.5, "ts": 1215007.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 233, "y": 322, "ts": 1215007.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 248, "y": 329.5, "ts": 1215037.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 248, "y": 329, "ts": 1215037.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 252, "y": 330.5, "ts": 1215054.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 252, "y": 330, "ts": 1215054.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 258, "y": 333.5, "ts": 1215091.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 258, "y": 333, "ts": 1215091.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 274, "y": 341.5, "ts": 1215115.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 274, "y": 341, "ts": 1215115.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 295, "y": 346.5, "ts": 1215135.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 295, "y": 346, "ts": 1215135.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 300, "y": 346.5, "ts": 1215154.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 300, "y": 346, "ts": 1215154.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 310, "y": 349.5, "ts": 1215174.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 310, "y": 349, "ts": 1215174.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 325, "y": 351.5, "ts": 1215189.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 325, "y": 351, "ts": 1215189.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 331, "y": 353.5, "ts": 1215215.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 331, "y": 353, "ts": 1215215.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 333, "y": 353.5, "ts": 1215227.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 333, "y": 353, "ts": 1215227.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 334, "y": 353.5, "ts": 1215267.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 334, "y": 353, "ts": 1215267.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 333, "y": 353.5, "ts": 1215496.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 333, "y": 353, "ts": 1215496.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 332, "y": 353.5, "ts": 1215540.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 332, "y": 353, "ts": 1215540.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 329, "y": 353.5, "ts": 1216161.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 329, "y": 353, "ts": 1216161.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 327, "y": 353.5, "ts": 1216189.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 327, "y": 353, "ts": 1216189.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 325, "y": 353.5, "ts": 1216209.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 325, "y": 353, "ts": 1216209.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 319, "y": 353.5, "ts": 1216260.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 319, "y": 353, "ts": 1216260.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 316, "y": 353.5, "ts": 1216276.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 316, "y": 353, "ts": 1216276.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 313, "y": 353.5, "ts": 1216294.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 313, "y": 353, "ts": 1216294.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 311, "y": 353.5, "ts": 1216314.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 311, "y": 353, "ts": 1216314.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 310, "y": 353.5, "ts": 1216343.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 310, "y": 353, "ts": 1216343.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 309, "y": 353.5, "ts": 1216371.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 309, "y": 353, "ts": 1216371.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 308, "y": 351.5, "ts": 1216408.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 308, "y": 351, "ts": 1216408.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 307, "y": 350.5, "ts": 1216423.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 307, "y": 350, "ts": 1216423.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 307, "y": 348.5, "ts": 1216443.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 307, "y": 348, "ts": 1216443.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 306, "y": 347.5, "ts": 1216478.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 306, "y": 347, "ts": 1216478.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 304, "y": 347.5, "ts": 1216508.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 304, "y": 347, "ts": 1216508.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 302, "y": 347.5, "ts": 1216527.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 302, "y": 347, "ts": 1216527.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 295, "y": 346.5, "ts": 1216560.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 295, "y": 346, "ts": 1216560.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 292, "y": 345.5, "ts": 1216579.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 292, "y": 345, "ts": 1216579.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 273, "y": 342.5, "ts": 1216613.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 273, "y": 342, "ts": 1216613.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 221, "y": 336.5, "ts": 1216630.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 221, "y": 336, "ts": 1216630.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 204, "y": 335.5, "ts": 1216658.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 204, "y": 335, "ts": 1216658.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 99, "y": 323.5, "ts": 1216691.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 99, "y": 323, "ts": 1216691.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 73, "y": 319.5, "ts": 1216713.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 73, "y": 319, "ts": 1216713.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 62, "y": 317.5, "ts": 1216753.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 62, "y": 317, "ts": 1216753.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 61, "y": 316.5, "ts": 1217068.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 61, "y": 316, "ts": 1217068.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 61, "y": 315.5, "ts": 1217089.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 61, "y": 315, "ts": 1217089.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 59, "y": 314.5, "ts": 1217113.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 59, "y": 314, "ts": 1217113.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 58, "y": 313.5, "ts": 1217135.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 58, "y": 313, "ts": 1217135.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 58, "y": 311.5, "ts": 1217196.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 58, "y": 311, "ts": 1217196.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 57, "y": 309.5, "ts": 1217206.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 57, "y": 309, "ts": 1217206.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 56, "y": 309.5, "ts": 1217602.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 56, "y": 309, "ts": 1217602.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 56, "y": 307.5, "ts": 1217612.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 56, "y": 307, "ts": 1217612.9, "buttons": 0, "trusted": true}, {"t": "pointerdown", "x": 56, "y": 307.5, "ts": 1217613.9, "buttons": 1, "trusted": true}, {"t": "mousedown", "x": 56, "y": 307, "ts": 1217613.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 147, "y": 309.5, "ts": 1217613.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 147, "y": 309, "ts": 1217613.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 158, "y": 309.5, "ts": 1217645.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 158, "y": 309, "ts": 1217645.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 171, "y": 309.5, "ts": 1217690.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 171, "y": 309, "ts": 1217690.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 183, "y": 309.5, "ts": 1217746.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 183, "y": 309, "ts": 1217746.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 187, "y": 309.5, "ts": 1217765.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 187, "y": 309, "ts": 1217765.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 196, "y": 309.5, "ts": 1217793.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 196, "y": 309, "ts": 1217793.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 200, "y": 309.5, "ts": 1217829.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 200, "y": 309, "ts": 1217829.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 205, "y": 309.5, "ts": 1217872.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 205, "y": 309, "ts": 1217872.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 209, "y": 310.5, "ts": 1217907.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 209, "y": 310, "ts": 1217907.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 211, "y": 310.5, "ts": 1217924.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 211, "y": 310, "ts": 1217924.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 220, "y": 310.5, "ts": 1217960.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 220, "y": 310, "ts": 1217960.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 221, "y": 310.5, "ts": 1217979.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 221, "y": 310, "ts": 1217979.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 224, "y": 310.5, "ts": 1218015.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 224, "y": 310, "ts": 1218015.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 225, "y": 310.5, "ts": 1218051.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 225, "y": 310, "ts": 1218051.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 229, "y": 311.5, "ts": 1218084.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 229, "y": 311, "ts": 1218084.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 231, "y": 312.5, "ts": 1218147.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 231, "y": 312, "ts": 1218147.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 235, "y": 312.5, "ts": 1218173.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 235, "y": 312, "ts": 1218173.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 239, "y": 312.5, "ts": 1218189.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 239, "y": 312, "ts": 1218189.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 241, "y": 313.5, "ts": 1218207.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 241, "y": 313, "ts": 1218207.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 249, "y": 314.5, "ts": 1218255.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 249, "y": 314, "ts": 1218255.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 251, "y": 315.5, "ts": 1218280.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 251, "y": 315, "ts": 1218280.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 256, "y": 316.5, "ts": 1218308.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 256, "y": 316, "ts": 1218308.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 257, "y": 316.5, "ts": 1218326.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 257, "y": 316, "ts": 1218326.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 258, "y": 317.5, "ts": 1218352.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 258, "y": 317, "ts": 1218352.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 260, "y": 317.5, "ts": 1218386.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 260, "y": 317, "ts": 1218386.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 262, "y": 317.5, "ts": 1218457.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 262, "y": 317, "ts": 1218457.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 263, "y": 317.5, "ts": 1218520.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 263, "y": 317, "ts": 1218520.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 264, "y": 317.5, "ts": 1218639.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 264, "y": 317, "ts": 1218639.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 265, "y": 317.5, "ts": 1218761.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 265, "y": 317, "ts": 1218761.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 266, "y": 317.5, "ts": 1218791.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 266, "y": 317, "ts": 1218791.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 267, "y": 317.5, "ts": 1218809.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 267, "y": 317, "ts": 1218809.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 268, "y": 317.5, "ts": 1218960.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 268, "y": 317, "ts": 1218960.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 269, "y": 317.5, "ts": 1218992.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 269, "y": 317, "ts": 1218992.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 269, "y": 318.5, "ts": 1219054.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 269, "y": 318, "ts": 1219054.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 270, "y": 318.5, "ts": 1219088.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 270, "y": 318, "ts": 1219088.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 271, "y": 318.5, "ts": 1219155.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 271, "y": 318, "ts": 1219155.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 272, "y": 318.5, "ts": 1219192.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 272, "y": 318, "ts": 1219192.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 273, "y": 318.5, "ts": 1219959.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 273, "y": 318, "ts": 1219959.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 273, "y": 319.5, "ts": 1220342.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 273, "y": 319, "ts": 1220342.9, "buttons": 1, "trusted": true}, {"t": "pointerup", "x": 273, "y": 319.5, "ts": 1220498.9, "buttons": 0, "trusted": true}, {"t": "mouseup", "x": 273, "y": 319, "ts": 1220498.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 272, "y": 319.5, "ts": 1220661.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 272, "y": 319, "ts": 1220661.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 270, "y": 320.5, "ts": 1220688.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 270, "y": 320, "ts": 1220688.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 268, "y": 321.5, "ts": 1220721.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 268, "y": 321, "ts": 1220721.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 265, "y": 323.5, "ts": 1220744.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 265, "y": 323, "ts": 1220744.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 262, "y": 324.5, "ts": 1220770.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 262, "y": 324, "ts": 1220770.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 258, "y": 326.5, "ts": 1220783.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 258, "y": 326, "ts": 1220783.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 254, "y": 327.5, "ts": 1220806.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 254, "y": 327, "ts": 1220806.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 239, "y": 330.5, "ts": 1220837.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 239, "y": 330, "ts": 1220837.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 231, "y": 332.5, "ts": 1220855.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 231, "y": 332, "ts": 1220855.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 217, "y": 335.5, "ts": 1220891.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 217, "y": 335, "ts": 1220891.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 212, "y": 337.5, "ts": 1220900.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 212, "y": 337, "ts": 1220900.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 209, "y": 338.5, "ts": 1220913.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 209, "y": 338, "ts": 1220913.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 201, "y": 341.5, "ts": 1220938.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 201, "y": 341, "ts": 1220938.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 197, "y": 342.5, "ts": 1220956.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 197, "y": 342, "ts": 1220956.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 191, "y": 342.5, "ts": 1220979.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 191, "y": 342, "ts": 1220979.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 188, "y": 342.5, "ts": 1220995.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 188, "y": 342, "ts": 1220995.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 180, "y": 342.5, "ts": 1221022.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 180, "y": 342, "ts": 1221022.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 175, "y": 342.5, "ts": 1221041.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 175, "y": 342, "ts": 1221041.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 164, "y": 342.5, "ts": 1221088.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 164, "y": 342, "ts": 1221088.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 162, "y": 342.5, "ts": 1221110.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 162, "y": 342, "ts": 1221110.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 161, "y": 342.5, "ts": 1221136.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 161, "y": 342, "ts": 1221136.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 157, "y": 341.5, "ts": 1221140.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 157, "y": 341, "ts": 1221140.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 156, "y": 341.5, "ts": 1221171.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 156, "y": 341, "ts": 1221171.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 154, "y": 341.5, "ts": 1221194.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 154, "y": 341, "ts": 1221194.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 148, "y": 339.5, "ts": 1221242.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 148, "y": 339, "ts": 1221242.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 146, "y": 338.5, "ts": 1221260.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 146, "y": 338, "ts": 1221260.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 143, "y": 337.5, "ts": 1221287.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 143, "y": 337, "ts": 1221287.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 140, "y": 335.5, "ts": 1221297.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 140, "y": 335, "ts": 1221297.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 138, "y": 334.5, "ts": 1221314.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 138, "y": 334, "ts": 1221314.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 135, "y": 331.5, "ts": 1221343.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 135, "y": 331, "ts": 1221343.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 134, "y": 330.5, "ts": 1221355.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 134, "y": 330, "ts": 1221355.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 133, "y": 328.5, "ts": 1221381.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 133, "y": 328, "ts": 1221381.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 129, "y": 324.5, "ts": 1221398.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 129, "y": 324, "ts": 1221398.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 127, "y": 323.5, "ts": 1221418.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 127, "y": 323, "ts": 1221418.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 126, "y": 322.5, "ts": 1221433.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 126, "y": 322, "ts": 1221433.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 125, "y": 321.5, "ts": 1221459.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 125, "y": 321, "ts": 1221459.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 122, "y": 320.5, "ts": 1221476.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 122, "y": 320, "ts": 1221476.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 120, "y": 319.5, "ts": 1221504.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 120, "y": 319, "ts": 1221504.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 114, "y": 317.5, "ts": 1221515.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 114, "y": 317, "ts": 1221515.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 110, "y": 316.5, "ts": 1221527.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 110, "y": 316, "ts": 1221527.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 107, "y": 315.5, "ts": 1221544.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 107, "y": 315, "ts": 1221544.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 109, "y": 315.5, "ts": 1223085.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 109, "y": 315, "ts": 1223085.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 117, "y": 315.5, "ts": 1223102.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 117, "y": 315, "ts": 1223102.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 120, "y": 315.5, "ts": 1223112.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 120, "y": 315, "ts": 1223112.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 125, "y": 315.5, "ts": 1223135.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 125, "y": 315, "ts": 1223135.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 130, "y": 316.5, "ts": 1223150.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 130, "y": 316, "ts": 1223150.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 140, "y": 317.5, "ts": 1223167.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 140, "y": 317, "ts": 1223167.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 146, "y": 318.5, "ts": 1223183.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 146, "y": 318, "ts": 1223183.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 157, "y": 320.5, "ts": 1223201.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 157, "y": 320, "ts": 1223201.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 162, "y": 320.5, "ts": 1223219.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 162, "y": 320, "ts": 1223219.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 164, "y": 321.5, "ts": 1223241.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 164, "y": 321, "ts": 1223241.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 163, "y": 323.5, "ts": 1223277.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 163, "y": 323, "ts": 1223277.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 156, "y": 326.5, "ts": 1223287.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 156, "y": 326, "ts": 1223287.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 147, "y": 329.5, "ts": 1223296.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 147, "y": 329, "ts": 1223296.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 141, "y": 330.5, "ts": 1223319.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 141, "y": 330, "ts": 1223319.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 127, "y": 334.5, "ts": 1223333.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 127, "y": 334, "ts": 1223333.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 112, "y": 337.5, "ts": 1223354.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 112, "y": 337, "ts": 1223354.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 93, "y": 340.5, "ts": 1223369.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 93, "y": 340, "ts": 1223369.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 74, "y": 343.5, "ts": 1223391.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 74, "y": 343, "ts": 1223391.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 52, "y": 345.5, "ts": 1223404.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 52, "y": 345, "ts": 1223404.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 40, "y": 348.5, "ts": 1223421.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 40, "y": 348, "ts": 1223421.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 37, "y": 349.5, "ts": 1223442.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 37, "y": 349, "ts": 1223442.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 33, "y": 352.5, "ts": 1223456.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 33, "y": 352, "ts": 1223456.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 30, "y": 356.5, "ts": 1223473.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 30, "y": 356, "ts": 1223473.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 28, "y": 361.5, "ts": 1223496.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 28, "y": 361, "ts": 1223496.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 27, "y": 364.5, "ts": 1223512.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 27, "y": 364, "ts": 1223512.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 25, "y": 368.5, "ts": 1223527.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 25, "y": 368, "ts": 1223527.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 25, "y": 370.5, "ts": 1223554.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 25, "y": 370, "ts": 1223554.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 25, "y": 371.5, "ts": 1223569.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 25, "y": 371, "ts": 1223569.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 25, "y": 372.5, "ts": 1223583.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 25, "y": 372, "ts": 1223583.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 27, "y": 372.5, "ts": 1223621.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 27, "y": 372, "ts": 1223621.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 29, "y": 372.5, "ts": 1223642.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 29, "y": 372, "ts": 1223642.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 33, "y": 372.5, "ts": 1223662.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 33, "y": 372, "ts": 1223662.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 36, "y": 372.5, "ts": 1223677.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 36, "y": 372, "ts": 1223677.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 38, "y": 370.5, "ts": 1223697.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 38, "y": 370, "ts": 1223697.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 40, "y": 368.5, "ts": 1223720.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 40, "y": 368, "ts": 1223720.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 41, "y": 367.5, "ts": 1223728.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 41, "y": 367, "ts": 1223728.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 42, "y": 366.5, "ts": 1223753.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 42, "y": 366, "ts": 1223753.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 42, "y": 364.5, "ts": 1223768.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 42, "y": 364, "ts": 1223768.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 42, "y": 363.5, "ts": 1223846.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 42, "y": 363, "ts": 1223846.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 43, "y": 360.5, "ts": 1223890.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 43, "y": 360, "ts": 1223890.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 43, "y": 359.5, "ts": 1223908.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 43, "y": 359, "ts": 1223908.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 43, "y": 357.5, "ts": 1223924.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 43, "y": 357, "ts": 1223924.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 43, "y": 356.5, "ts": 1223953.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 43, "y": 356, "ts": 1223953.9, "buttons": 0, "trusted": true}, {"t": "pointerdown", "x": 43, "y": 356.5, "ts": 1224045.9, "buttons": 1, "trusted": true}, {"t": "mousedown", "x": 43, "y": 356, "ts": 1224045.9, "buttons": 1, "trusted": true}, {"t": "pointerup", "x": 43, "y": 356.5, "ts": 1224134.9, "buttons": 0, "trusted": true}, {"t": "mouseup", "x": 43, "y": 356, "ts": 1224134.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 43, "y": 355.5, "ts": 1224155.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 43, "y": 355, "ts": 1224155.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 41, "y": 357.5, "ts": 1224188.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 41, "y": 357, "ts": 1224188.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 40, "y": 357.5, "ts": 1224207.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 40, "y": 357, "ts": 1224207.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 39, "y": 357.5, "ts": 1224258.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 39, "y": 357, "ts": 1224258.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 39, "y": 356.5, "ts": 1224289.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 39, "y": 356, "ts": 1224289.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 38, "y": 352.5, "ts": 1224308.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 38, "y": 352, "ts": 1224308.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 36, "y": 347.5, "ts": 1224327.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 36, "y": 347, "ts": 1224327.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 35, "y": 342.5, "ts": 1224355.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 35, "y": 342, "ts": 1224355.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 35, "y": 336.5, "ts": 1224365.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 35, "y": 336, "ts": 1224365.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 35, "y": 327.5, "ts": 1224381.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 35, "y": 327, "ts": 1224381.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 35, "y": 322.5, "ts": 1224407.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 35, "y": 322, "ts": 1224407.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 35, "y": 319.5, "ts": 1224421.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 35, "y": 319, "ts": 1224421.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 35, "y": 316.5, "ts": 1224435.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 35, "y": 316, "ts": 1224435.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 36, "y": 314.5, "ts": 1224452.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 36, "y": 314, "ts": 1224452.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 37, "y": 313.5, "ts": 1224473.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 37, "y": 313, "ts": 1224473.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 38, "y": 313.5, "ts": 1224538.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 38, "y": 313, "ts": 1224538.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 40, "y": 312.5, "ts": 1224768.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 40, "y": 312, "ts": 1224768.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 41, "y": 311.5, "ts": 1224788.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 41, "y": 311, "ts": 1224788.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 43, "y": 310.5, "ts": 1224808.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 43, "y": 310, "ts": 1224808.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 45, "y": 308.5, "ts": 1224824.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 45, "y": 308, "ts": 1224824.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 47, "y": 306.5, "ts": 1224841.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 47, "y": 306, "ts": 1224841.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 49, "y": 305.5, "ts": 1224859.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 49, "y": 305, "ts": 1224859.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 50, "y": 304.5, "ts": 1224881.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 50, "y": 304, "ts": 1224881.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 52, "y": 303.5, "ts": 1224899.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 52, "y": 303, "ts": 1224899.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 53, "y": 302.5, "ts": 1224912.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 53, "y": 302, "ts": 1224912.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 54, "y": 301.5, "ts": 1224939.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 54, "y": 301, "ts": 1224939.9, "buttons": 0, "trusted": true}, {"t": "pointerdown", "x": 54, "y": 301.5, "ts": 1225221.9, "buttons": 1, "trusted": true}, {"t": "mousedown", "x": 54, "y": 301, "ts": 1225221.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 68, "y": 303.5, "ts": 1225288.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 68, "y": 303, "ts": 1225288.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 76, "y": 303.5, "ts": 1225322.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 76, "y": 303, "ts": 1225322.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 83, "y": 303.5, "ts": 1225337.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 83, "y": 303, "ts": 1225337.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 90, "y": 303.5, "ts": 1225351.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 90, "y": 303, "ts": 1225351.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 98, "y": 303.5, "ts": 1225377.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 98, "y": 303, "ts": 1225377.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 118, "y": 306.5, "ts": 1225424.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 118, "y": 306, "ts": 1225424.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 121, "y": 306.5, "ts": 1225453.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 121, "y": 306, "ts": 1225453.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 129, "y": 307.5, "ts": 1225487.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 129, "y": 307, "ts": 1225487.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 137, "y": 309.5, "ts": 1225506.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 137, "y": 309, "ts": 1225506.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 145, "y": 310.5, "ts": 1225589.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 145, "y": 310, "ts": 1225589.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 147, "y": 311.5, "ts": 1225618.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 147, "y": 311, "ts": 1225618.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 148, "y": 311.5, "ts": 1225660.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 148, "y": 311, "ts": 1225660.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 149, "y": 311.5, "ts": 1225660.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 149, "y": 311, "ts": 1225660.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 150, "y": 311.5, "ts": 1225686.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 150, "y": 311, "ts": 1225686.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 151, "y": 311.5, "ts": 1225705.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 151, "y": 311, "ts": 1225705.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 157, "y": 313.5, "ts": 1225728.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 157, "y": 313, "ts": 1225728.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 163, "y": 313.5, "ts": 1225763.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 163, "y": 313, "ts": 1225763.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 164, "y": 314.5, "ts": 1225826.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 164, "y": 314, "ts": 1225826.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 166, "y": 314.5, "ts": 1225852.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 166, "y": 314, "ts": 1225852.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 167, "y": 314.5, "ts": 1225891.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 167, "y": 314, "ts": 1225891.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 168, "y": 314.5, "ts": 1225925.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 168, "y": 314, "ts": 1225925.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 168, "y": 315.5, "ts": 1225937.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 168, "y": 315, "ts": 1225937.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 169, "y": 316.5, "ts": 1225958.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 169, "y": 316, "ts": 1225958.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 170, "y": 316.5, "ts": 1225987.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 170, "y": 316, "ts": 1225987.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 171, "y": 317.5, "ts": 1226023.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 171, "y": 317, "ts": 1226023.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 172, "y": 318.5, "ts": 1226096.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 172, "y": 318, "ts": 1226096.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 173, "y": 319.5, "ts": 1226623.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 173, "y": 319, "ts": 1226623.9, "buttons": 1, "trusted": true}, {"t": "pointerup", "x": 173, "y": 319.5, "ts": 1227160.9, "buttons": 0, "trusted": true}, {"t": "mouseup", "x": 173, "y": 319, "ts": 1227160.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 173, "y": 320.5, "ts": 1227255.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 173, "y": 320, "ts": 1227255.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 172, "y": 320.5, "ts": 1227323.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 172, "y": 320, "ts": 1227323.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 170, "y": 320.5, "ts": 1227338.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 170, "y": 320, "ts": 1227338.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 166, "y": 320.5, "ts": 1227376.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 166, "y": 320, "ts": 1227376.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 162, "y": 320.5, "ts": 1227404.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 162, "y": 320, "ts": 1227404.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 160, "y": 320.5, "ts": 1227425.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 160, "y": 320, "ts": 1227425.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 157, "y": 321.5, "ts": 1227440.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 157, "y": 321, "ts": 1227440.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 154, "y": 322.5, "ts": 1227470.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 154, "y": 322, "ts": 1227470.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 150, "y": 322.5, "ts": 1227498.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 150, "y": 322, "ts": 1227498.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 144, "y": 322.5, "ts": 1227531.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 144, "y": 322, "ts": 1227531.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 141, "y": 323.5, "ts": 1227555.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 141, "y": 323, "ts": 1227555.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 138, "y": 324.5, "ts": 1227571.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 138, "y": 324, "ts": 1227571.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 125, "y": 326.5, "ts": 1227603.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 125, "y": 326, "ts": 1227603.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 121, "y": 328.5, "ts": 1227614.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 121, "y": 328, "ts": 1227614.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 115, "y": 330.5, "ts": 1227632.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 115, "y": 330, "ts": 1227632.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 101, "y": 334.5, "ts": 1227660.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 101, "y": 334, "ts": 1227660.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 95, "y": 336.5, "ts": 1227681.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 95, "y": 336, "ts": 1227681.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 90, "y": 339.5, "ts": 1227694.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 90, "y": 339, "ts": 1227694.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 83, "y": 342.5, "ts": 1227715.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 83, "y": 342, "ts": 1227715.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 67, "y": 350.5, "ts": 1227755.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 67, "y": 350, "ts": 1227755.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 60, "y": 354.5, "ts": 1227781.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 60, "y": 354, "ts": 1227781.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 56, "y": 356.5, "ts": 1227801.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 56, "y": 356, "ts": 1227801.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 55, "y": 357.5, "ts": 1227818.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 55, "y": 357, "ts": 1227818.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 52, "y": 357.5, "ts": 1227837.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 52, "y": 357, "ts": 1227837.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 50, "y": 357.5, "ts": 1227863.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 50, "y": 357, "ts": 1227863.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 49, "y": 357.5, "ts": 1227903.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 49, "y": 357, "ts": 1227903.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 48, "y": 357.5, "ts": 1227960.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 48, "y": 357, "ts": 1227960.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 48, "y": 356.5, "ts": 1227981.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 48, "y": 356, "ts": 1227981.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 47, "y": 355.5, "ts": 1227995.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 47, "y": 355, "ts": 1227995.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 45, "y": 352.5, "ts": 1228015.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 45, "y": 352, "ts": 1228015.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 39, "y": 347.5, "ts": 1228053.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 39, "y": 347, "ts": 1228053.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 36, "y": 345.5, "ts": 1228078.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 36, "y": 345, "ts": 1228078.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 32, "y": 343.5, "ts": 1228101.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 32, "y": 343, "ts": 1228101.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 31, "y": 343.5, "ts": 1228111.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 31, "y": 343, "ts": 1228111.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 30, "y": 343.5, "ts": 1228133.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 30, "y": 343, "ts": 1228133.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 29, "y": 343.5, "ts": 1228161.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 29, "y": 343, "ts": 1228161.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 27, "y": 343.5, "ts": 1228180.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 27, "y": 343, "ts": 1228180.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 26, "y": 343.5, "ts": 1228194.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 26, "y": 343, "ts": 1228194.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 22, "y": 343.5, "ts": 1228224.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 22, "y": 343, "ts": 1228224.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 21, "y": 343.5, "ts": 1228321.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 21, "y": 343, "ts": 1228321.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 21, "y": 341.5, "ts": 1228341.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 21, "y": 341, "ts": 1228341.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 21, "y": 339.5, "ts": 1228368.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 21, "y": 339, "ts": 1228368.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 21, "y": 338.5, "ts": 1228378.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 21, "y": 338, "ts": 1228378.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 21, "y": 337.5, "ts": 1228412.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 21, "y": 337, "ts": 1228412.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 21, "y": 336.5, "ts": 1228429.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 21, "y": 336, "ts": 1228429.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 21, "y": 337.5, "ts": 1228667.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 21, "y": 337, "ts": 1228667.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 19, "y": 339.5, "ts": 1229218.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 19, "y": 339, "ts": 1229218.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 19, "y": 340.5, "ts": 1229242.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 19, "y": 340, "ts": 1229242.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 17, "y": 342.5, "ts": 1229274.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 17, "y": 342, "ts": 1229274.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 15, "y": 346.5, "ts": 1229291.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 15, "y": 346, "ts": 1229291.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 14, "y": 347.5, "ts": 1229317.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 14, "y": 347, "ts": 1229317.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 13, "y": 348.5, "ts": 1229336.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 13, "y": 348, "ts": 1229336.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 13, "y": 349.5, "ts": 1229363.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 13, "y": 349, "ts": 1229363.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 12, "y": 349.5, "ts": 1229456.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 12, "y": 349, "ts": 1229456.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 10, "y": 351.5, "ts": 1229622.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 10, "y": 351, "ts": 1229622.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 9, "y": 354.5, "ts": 1229654.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 9, "y": 354, "ts": 1229654.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 9, "y": 356.5, "ts": 1229664.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 9, "y": 356, "ts": 1229664.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 7, "y": 358.5, "ts": 1229673.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 7, "y": 358, "ts": 1229673.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 6, "y": 360.5, "ts": 1229697.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 6, "y": 360, "ts": 1229697.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 6, "y": 362.5, "ts": 1229717.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 6, "y": 362, "ts": 1229717.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 6, "y": 363.5, "ts": 1229730.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 6, "y": 363, "ts": 1229730.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 6, "y": 364.5, "ts": 1229750.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 6, "y": 364, "ts": 1229750.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 6, "y": 365.5, "ts": 1229771.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 6, "y": 365, "ts": 1229771.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 6, "y": 366.5, "ts": 1229788.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 6, "y": 366, "ts": 1229788.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 6, "y": 367.5, "ts": 1229834.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 6, "y": 367, "ts": 1229834.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 7, "y": 367.5, "ts": 1229876.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 7, "y": 367, "ts": 1229876.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 10, "y": 366.5, "ts": 1229898.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 10, "y": 366, "ts": 1229898.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 15, "y": 364.5, "ts": 1229918.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 15, "y": 364, "ts": 1229918.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 19, "y": 362.5, "ts": 1229941.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 19, "y": 362, "ts": 1229941.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 35, "y": 356.5, "ts": 1229964.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 35, "y": 356, "ts": 1229964.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 39, "y": 353.5, "ts": 1229984.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 39, "y": 353, "ts": 1229984.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 40, "y": 353.5, "ts": 1230001.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 40, "y": 353, "ts": 1230001.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 45, "y": 350.5, "ts": 1230025.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 45, "y": 350, "ts": 1230025.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 47, "y": 348.5, "ts": 1230052.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 47, "y": 348, "ts": 1230052.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 48, "y": 347.5, "ts": 1230105.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 48, "y": 347, "ts": 1230105.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 49, "y": 347.5, "ts": 1230123.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 49, "y": 347, "ts": 1230123.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 49, "y": 348.5, "ts": 1230148.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 49, "y": 348, "ts": 1230148.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 49, "y": 349.5, "ts": 1230163.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 49, "y": 349, "ts": 1230163.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 50, "y": 351.5, "ts": 1230182.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 50, "y": 351, "ts": 1230182.9, "buttons": 0, "trusted": true}, {"t": "pointerdown", "x": 50, "y": 351.5, "ts": 1230598.9, "buttons": 1, "trusted": true}, {"t": "mousedown", "x": 50, "y": 351, "ts": 1230598.9, "buttons": 1, "trusted": true}, {"t": "pointerup", "x": 50, "y": 351.5, "ts": 1230755.9, "buttons": 0, "trusted": true}, {"t": "mouseup", "x": 50, "y": 351, "ts": 1230755.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 50, "y": 350.5, "ts": 1231304.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 50, "y": 350, "ts": 1231304.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 50, "y": 347.5, "ts": 1231334.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 50, "y": 347, "ts": 1231334.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 50, "y": 346.5, "ts": 1231366.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 50, "y": 346, "ts": 1231366.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 50, "y": 345.5, "ts": 1231379.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 50, "y": 345, "ts": 1231379.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 50, "y": 344.5, "ts": 1231396.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 50, "y": 344, "ts": 1231396.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 50, "y": 343.5, "ts": 1231421.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 50, "y": 343, "ts": 1231421.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 50, "y": 340.5, "ts": 1231439.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 50, "y": 340, "ts": 1231439.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 50, "y": 338.5, "ts": 1231455.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 50, "y": 338, "ts": 1231455.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 49, "y": 337.5, "ts": 1231470.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 49, "y": 337, "ts": 1231470.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 44, "y": 330.5, "ts": 1231488.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 44, "y": 330, "ts": 1231488.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 41, "y": 326.5, "ts": 1231507.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 41, "y": 326, "ts": 1231507.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 40, "y": 324.5, "ts": 1231526.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 40, "y": 324, "ts": 1231526.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 37, "y": 320.5, "ts": 1231545.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 37, "y": 320, "ts": 1231545.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 36, "y": 318.5, "ts": 1231564.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 36, "y": 318, "ts": 1231564.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 35, "y": 316.5, "ts": 1231580.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 35, "y": 316, "ts": 1231580.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 35, "y": 314.5, "ts": 1231598.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 35, "y": 314, "ts": 1231598.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 35, "y": 313.5, "ts": 1231626.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 35, "y": 313, "ts": 1231626.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 35, "y": 312.5, "ts": 1231759.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 35, "y": 312, "ts": 1231759.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 37, "y": 312.5, "ts": 1231775.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 37, "y": 312, "ts": 1231775.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 38, "y": 312.5, "ts": 1231813.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 38, "y": 312, "ts": 1231813.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 39, "y": 312.5, "ts": 1231823.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 39, "y": 312, "ts": 1231823.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 40, "y": 312.5, "ts": 1231871.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 40, "y": 312, "ts": 1231871.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 41, "y": 311.5, "ts": 1231888.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 41, "y": 311, "ts": 1231888.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 42, "y": 311.5, "ts": 1231921.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 42, "y": 311, "ts": 1231921.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 43, "y": 311.5, "ts": 1231951.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 43, "y": 311, "ts": 1231951.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 44, "y": 311.5, "ts": 1231971.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 44, "y": 311, "ts": 1231971.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 46, "y": 310.5, "ts": 1232000.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 46, "y": 310, "ts": 1232000.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 47, "y": 308.5, "ts": 1232030.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 47, "y": 308, "ts": 1232030.9, "buttons": 0, "trusted": true}, {"t": "pointerdown", "x": 47, "y": 308.5, "ts": 1232150.9, "buttons": 1, "trusted": true}, {"t": "mousedown", "x": 47, "y": 308, "ts": 1232150.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 53, "y": 308.5, "ts": 1232207.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 53, "y": 308, "ts": 1232207.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 57, "y": 308.5, "ts": 1232228.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 57, "y": 308, "ts": 1232228.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 66, "y": 309.5, "ts": 1232249.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 66, "y": 309, "ts": 1232249.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 81, "y": 310.5, "ts": 1232272.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 81, "y": 310, "ts": 1232272.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 88, "y": 311.5, "ts": 1232292.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 88, "y": 311, "ts": 1232292.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 94, "y": 311.5, "ts": 1232318.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 94, "y": 311, "ts": 1232318.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 102, "y": 311.5, "ts": 1232336.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 102, "y": 311, "ts": 1232336.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 124, "y": 313.5, "ts": 1232378.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 124, "y": 313, "ts": 1232378.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 131, "y": 314.5, "ts": 1232397.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 131, "y": 314, "ts": 1232397.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 150, "y": 314.5, "ts": 1232426.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 150, "y": 314, "ts": 1232426.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 156, "y": 314.5, "ts": 1232459.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 156, "y": 314, "ts": 1232459.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 161, "y": 314.5, "ts": 1232480.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 161, "y": 314, "ts": 1232480.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 167, "y": 314.5, "ts": 1232499.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 167, "y": 314, "ts": 1232499.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 169, "y": 314.5, "ts": 1232533.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 169, "y": 314, "ts": 1232533.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 171, "y": 314.5, "ts": 1232566.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 171, "y": 314, "ts": 1232566.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 175, "y": 314.5, "ts": 1232600.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 175, "y": 314, "ts": 1232600.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 178, "y": 313.5, "ts": 1232648.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 178, "y": 313, "ts": 1232648.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 184, "y": 313.5, "ts": 1232666.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 184, "y": 313, "ts": 1232666.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 189, "y": 313.5, "ts": 1232714.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 189, "y": 313, "ts": 1232714.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 193, "y": 313.5, "ts": 1232741.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 193, "y": 313, "ts": 1232741.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 198, "y": 313.5, "ts": 1232757.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 198, "y": 313, "ts": 1232757.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 207, "y": 313.5, "ts": 1232773.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 207, "y": 313, "ts": 1232773.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 209, "y": 313.5, "ts": 1232831.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 209, "y": 313, "ts": 1232831.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 211, "y": 313.5, "ts": 1232855.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 211, "y": 313, "ts": 1232855.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 213, "y": 313.5, "ts": 1232963.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 213, "y": 313, "ts": 1232963.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 214, "y": 313.5, "ts": 1232985.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 214, "y": 313, "ts": 1232985.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 215, "y": 313.5, "ts": 1233006.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 215, "y": 313, "ts": 1233006.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 217, "y": 313.5, "ts": 1233033.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 217, "y": 313, "ts": 1233033.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 219, "y": 312.5, "ts": 1233072.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 219, "y": 312, "ts": 1233072.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 220, "y": 312.5, "ts": 1233109.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 220, "y": 312, "ts": 1233109.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 219, "y": 312.5, "ts": 1233542.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 219, "y": 312, "ts": 1233542.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 218, "y": 313.5, "ts": 1233561.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 218, "y": 313, "ts": 1233561.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 217, "y": 314.5, "ts": 1233605.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 217, "y": 314, "ts": 1233605.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 214, "y": 315.5, "ts": 1233636.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 214, "y": 315, "ts": 1233636.9, "buttons": 1, "trusted": true}, {"t": "pointermove", "x": 213, "y": 315.5, "ts": 1233664.9, "buttons": 1, "trusted": true}, {"t": "mousemove", "x": 213, "y": 315, "ts": 1233664.9, "buttons": 1, "trusted": true}, {"t": "pointerup", "x": 213, "y": 315.5, "ts": 1234512.9, "buttons": 0, "trusted": true}, {"t": "mouseup", "x": 213, "y": 315, "ts": 1234512.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 212, "y": 315.5, "ts": 1234678.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 212, "y": 315, "ts": 1234678.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 211, "y": 315.5, "ts": 1234704.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 211, "y": 315, "ts": 1234704.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 209, "y": 315.5, "ts": 1234740.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 209, "y": 315, "ts": 1234740.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 208, "y": 315.5, "ts": 1234763.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 208, "y": 315, "ts": 1234763.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 207, "y": 315.5, "ts": 1234786.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 207, "y": 315, "ts": 1234786.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 206, "y": 315.5, "ts": 1234838.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 206, "y": 315, "ts": 1234838.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 204, "y": 315.5, "ts": 1234867.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 204, "y": 315, "ts": 1234867.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 203, "y": 315.5, "ts": 1234894.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 203, "y": 315, "ts": 1234894.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 202, "y": 315.5, "ts": 1234910.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 202, "y": 315, "ts": 1234910.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 200, "y": 315.5, "ts": 1234928.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 200, "y": 315, "ts": 1234928.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 198, "y": 316.5, "ts": 1234952.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 198, "y": 316, "ts": 1234952.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 195, "y": 317.5, "ts": 1234973.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 195, "y": 317, "ts": 1234973.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 194, "y": 317.5, "ts": 1234986.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 194, "y": 317, "ts": 1234986.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 187, "y": 320.5, "ts": 1235007.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 187, "y": 320, "ts": 1235007.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 180, "y": 321.5, "ts": 1235027.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 180, "y": 321, "ts": 1235027.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 178, "y": 322.5, "ts": 1235051.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 178, "y": 322, "ts": 1235051.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 168, "y": 324.5, "ts": 1235066.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 168, "y": 324, "ts": 1235066.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 160, "y": 325.5, "ts": 1235087.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 160, "y": 325, "ts": 1235087.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 132, "y": 329.5, "ts": 1235123.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 132, "y": 329, "ts": 1235123.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 118, "y": 330.5, "ts": 1235153.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 118, "y": 330, "ts": 1235153.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 114, "y": 331.5, "ts": 1235173.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 114, "y": 331, "ts": 1235173.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 112, "y": 331.5, "ts": 1235182.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 112, "y": 331, "ts": 1235182.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 111, "y": 331.5, "ts": 1235204.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 111, "y": 331, "ts": 1235204.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 110, "y": 331.5, "ts": 1235229.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 110, "y": 331, "ts": 1235229.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 109, "y": 331.5, "ts": 1235239.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 109, "y": 331, "ts": 1235239.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 106, "y": 331.5, "ts": 1235262.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 106, "y": 331, "ts": 1235262.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 99, "y": 330.5, "ts": 1235273.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 99, "y": 330, "ts": 1235273.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 94, "y": 329.5, "ts": 1235292.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 94, "y": 329, "ts": 1235292.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 88, "y": 329.5, "ts": 1235311.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 88, "y": 329, "ts": 1235311.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 83, "y": 327.5, "ts": 1235336.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 83, "y": 327, "ts": 1235336.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 77, "y": 327.5, "ts": 1235347.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 77, "y": 327, "ts": 1235347.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 68, "y": 327.5, "ts": 1235366.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 68, "y": 327, "ts": 1235366.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 65, "y": 326.5, "ts": 1235385.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 65, "y": 326, "ts": 1235385.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 61, "y": 326.5, "ts": 1235410.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 61, "y": 326, "ts": 1235410.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 54, "y": 325.5, "ts": 1235430.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 54, "y": 325, "ts": 1235430.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 51, "y": 325.5, "ts": 1235445.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 51, "y": 325, "ts": 1235445.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 48, "y": 323.5, "ts": 1235462.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 48, "y": 323, "ts": 1235462.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 42, "y": 321.5, "ts": 1235490.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 42, "y": 321, "ts": 1235490.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 36, "y": 318.5, "ts": 1235509.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 36, "y": 318, "ts": 1235509.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 32, "y": 316.5, "ts": 1235532.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 32, "y": 316, "ts": 1235532.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 30, "y": 314.5, "ts": 1235553.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 30, "y": 314, "ts": 1235553.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 28, "y": 312.5, "ts": 1235573.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 28, "y": 312, "ts": 1235573.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 28, "y": 310.5, "ts": 1235587.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 28, "y": 310, "ts": 1235587.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 31, "y": 297.5, "ts": 1235624.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 31, "y": 297, "ts": 1235624.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 44, "y": 281.5, "ts": 1235674.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 44, "y": 281, "ts": 1235674.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 51, "y": 276.5, "ts": 1235691.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 51, "y": 276, "ts": 1235691.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 59, "y": 271.5, "ts": 1235709.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 59, "y": 271, "ts": 1235709.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 67, "y": 265.5, "ts": 1235734.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 67, "y": 265, "ts": 1235734.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 76, "y": 260.5, "ts": 1235748.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 76, "y": 260, "ts": 1235748.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 90, "y": 250.5, "ts": 1235780.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 90, "y": 250, "ts": 1235780.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 100, "y": 245.5, "ts": 1235796.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 100, "y": 245, "ts": 1235796.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 120, "y": 237.5, "ts": 1235823.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 120, "y": 237, "ts": 1235823.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 130, "y": 232.5, "ts": 1235842.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 130, "y": 232, "ts": 1235842.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 142, "y": 226.5, "ts": 1235856.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 142, "y": 226, "ts": 1235856.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 161, "y": 217.5, "ts": 1235875.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 161, "y": 217, "ts": 1235875.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 173, "y": 212.5, "ts": 1235903.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 173, "y": 212, "ts": 1235903.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 184, "y": 208.5, "ts": 1235914.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 184, "y": 208, "ts": 1235914.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 196, "y": 204.5, "ts": 1235939.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 196, "y": 204, "ts": 1235939.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 214, "y": 199.5, "ts": 1235950.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 214, "y": 199, "ts": 1235950.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 220, "y": 197.5, "ts": 1235968.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 220, "y": 197, "ts": 1235968.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 229, "y": 195.5, "ts": 1235985.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 229, "y": 195, "ts": 1235985.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 234, "y": 194.5, "ts": 1236009.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 234, "y": 194, "ts": 1236009.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 238, "y": 193.5, "ts": 1236029.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 238, "y": 193, "ts": 1236029.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 247, "y": 192.5, "ts": 1236044.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 247, "y": 192, "ts": 1236044.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 250, "y": 190.5, "ts": 1236069.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 250, "y": 190, "ts": 1236069.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 252, "y": 184.5, "ts": 1236079.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 252, "y": 184, "ts": 1236079.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 253, "y": 183.5, "ts": 1236102.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 253, "y": 183, "ts": 1236102.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 253, "y": 182.5, "ts": 1236271.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 253, "y": 182, "ts": 1236271.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 252, "y": 182.5, "ts": 1236290.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 252, "y": 182, "ts": 1236290.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 248, "y": 182.5, "ts": 1236305.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 248, "y": 182, "ts": 1236305.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 237, "y": 182.5, "ts": 1236341.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 237, "y": 182, "ts": 1236341.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 230, "y": 182.5, "ts": 1236363.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 230, "y": 182, "ts": 1236363.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 224, "y": 182.5, "ts": 1236378.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 224, "y": 182, "ts": 1236378.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 219, "y": 182.5, "ts": 1236395.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 219, "y": 182, "ts": 1236395.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 217, "y": 182.5, "ts": 1236421.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 217, "y": 182, "ts": 1236421.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 216, "y": 182.5, "ts": 1236438.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 216, "y": 182, "ts": 1236438.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 214, "y": 182.5, "ts": 1236454.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 214, "y": 182, "ts": 1236454.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 211, "y": 182.5, "ts": 1236481.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 211, "y": 182, "ts": 1236481.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 206, "y": 182.5, "ts": 1236493.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 206, "y": 182, "ts": 1236493.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 202, "y": 181.5, "ts": 1236506.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 202, "y": 181, "ts": 1236506.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 197, "y": 179.5, "ts": 1236532.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 197, "y": 179, "ts": 1236532.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 194, "y": 179.5, "ts": 1236541.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 194, "y": 179, "ts": 1236541.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 192, "y": 179.5, "ts": 1236568.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 192, "y": 179, "ts": 1236568.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 190, "y": 178.5, "ts": 1236598.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 190, "y": 178, "ts": 1236598.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 189, "y": 177.5, "ts": 1236612.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 189, "y": 177, "ts": 1236612.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 186, "y": 175.5, "ts": 1236637.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 186, "y": 175, "ts": 1236637.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 184, "y": 174.5, "ts": 1236651.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 184, "y": 174, "ts": 1236651.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 182, "y": 173.5, "ts": 1236664.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 182, "y": 173, "ts": 1236664.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 173, "y": 170.5, "ts": 1236700.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 173, "y": 170, "ts": 1236700.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 172, "y": 169.5, "ts": 1236717.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 172, "y": 169, "ts": 1236717.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 171, "y": 169.5, "ts": 1236754.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 171, "y": 169, "ts": 1236754.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 170, "y": 169.5, "ts": 1236773.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 170, "y": 169, "ts": 1236773.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 168, "y": 169.5, "ts": 1236792.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 168, "y": 169, "ts": 1236792.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 167, "y": 170.5, "ts": 1236807.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 167, "y": 170, "ts": 1236807.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 163, "y": 172.5, "ts": 1236824.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 163, "y": 172, "ts": 1236824.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 160, "y": 174.5, "ts": 1236846.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 160, "y": 174, "ts": 1236846.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 154, "y": 177.5, "ts": 1236860.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 154, "y": 177, "ts": 1236860.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 147, "y": 181.5, "ts": 1236883.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 147, "y": 181, "ts": 1236883.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 141, "y": 183.5, "ts": 1236898.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 141, "y": 183, "ts": 1236898.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 137, "y": 185.5, "ts": 1236912.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 137, "y": 185, "ts": 1236912.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 132, "y": 187.5, "ts": 1236936.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 132, "y": 187, "ts": 1236936.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 126, "y": 188.5, "ts": 1236946.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 126, "y": 188, "ts": 1236946.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 120, "y": 190.5, "ts": 1236963.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 120, "y": 190, "ts": 1236963.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 104, "y": 191.5, "ts": 1237002.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 104, "y": 191, "ts": 1237002.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 95, "y": 191.5, "ts": 1237022.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 95, "y": 191, "ts": 1237022.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 89, "y": 192.5, "ts": 1237034.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 89, "y": 192, "ts": 1237034.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 85, "y": 192.5, "ts": 1237055.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 85, "y": 192, "ts": 1237055.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 81, "y": 192.5, "ts": 1237070.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 81, "y": 192, "ts": 1237070.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 76, "y": 192.5, "ts": 1237089.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 76, "y": 192, "ts": 1237089.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 74, "y": 192.5, "ts": 1237112.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 74, "y": 192, "ts": 1237112.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 69, "y": 192.5, "ts": 1237124.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 69, "y": 192, "ts": 1237124.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 64, "y": 192.5, "ts": 1237149.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 64, "y": 192, "ts": 1237149.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 58, "y": 193.5, "ts": 1237167.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 58, "y": 193, "ts": 1237167.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 51, "y": 195.5, "ts": 1237178.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 51, "y": 195, "ts": 1237178.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 45, "y": 196.5, "ts": 1237200.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 45, "y": 196, "ts": 1237200.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 39, "y": 197.5, "ts": 1237214.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 39, "y": 197, "ts": 1237214.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 30, "y": 201.5, "ts": 1237232.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 30, "y": 201, "ts": 1237232.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 27, "y": 203.5, "ts": 1237249.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 27, "y": 203, "ts": 1237249.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 20, "y": 207.5, "ts": 1237273.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 20, "y": 207, "ts": 1237273.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 14, "y": 212.5, "ts": 1237285.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 14, "y": 212, "ts": 1237285.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 5, "y": 220.5, "ts": 1237301.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 5, "y": 220, "ts": 1237301.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 2, "y": 234.5, "ts": 1237995.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 2, "y": 234, "ts": 1237995.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 15, "y": 234.5, "ts": 1238016.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 15, "y": 234, "ts": 1238016.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 42, "y": 234.5, "ts": 1238031.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 42, "y": 234, "ts": 1238031.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 79, "y": 233.5, "ts": 1238047.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 79, "y": 233, "ts": 1238047.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 88, "y": 233.5, "ts": 1238066.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 88, "y": 233, "ts": 1238066.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 106, "y": 232.5, "ts": 1238091.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 106, "y": 232, "ts": 1238091.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 122, "y": 229.5, "ts": 1238116.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 122, "y": 229, "ts": 1238116.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 132, "y": 227.5, "ts": 1238131.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 132, "y": 227, "ts": 1238131.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 136, "y": 227.5, "ts": 1238140.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 136, "y": 227, "ts": 1238140.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 137, "y": 226.5, "ts": 1238158.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 137, "y": 226, "ts": 1238158.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 137, "y": 225.5, "ts": 1238175.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 137, "y": 225, "ts": 1238175.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 137, "y": 224.5, "ts": 1238192.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 137, "y": 224, "ts": 1238192.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 138, "y": 222.5, "ts": 1238210.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 138, "y": 222, "ts": 1238210.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 138, "y": 220.5, "ts": 1238228.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 138, "y": 220, "ts": 1238228.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 138, "y": 219.5, "ts": 1238251.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 138, "y": 219, "ts": 1238251.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 138, "y": 218.5, "ts": 1238274.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 138, "y": 218, "ts": 1238274.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 137, "y": 218.5, "ts": 1238287.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 137, "y": 218, "ts": 1238287.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 135, "y": 218.5, "ts": 1238316.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 135, "y": 218, "ts": 1238316.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 124, "y": 218.5, "ts": 1238340.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 124, "y": 218, "ts": 1238340.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 117, "y": 218.5, "ts": 1238359.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 117, "y": 218, "ts": 1238359.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 111, "y": 218.5, "ts": 1238378.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 111, "y": 218, "ts": 1238378.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 105, "y": 219.5, "ts": 1238395.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 105, "y": 219, "ts": 1238395.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 102, "y": 221.5, "ts": 1238421.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 102, "y": 221, "ts": 1238421.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 97, "y": 222.5, "ts": 1238437.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 97, "y": 222, "ts": 1238437.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 95, "y": 224.5, "ts": 1238447.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 95, "y": 224, "ts": 1238447.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 93, "y": 225.5, "ts": 1238470.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 93, "y": 225, "ts": 1238470.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 91, "y": 226.5, "ts": 1238491.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 91, "y": 226, "ts": 1238491.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 90, "y": 226.5, "ts": 1238505.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 90, "y": 226, "ts": 1238505.9, "buttons": 0, "trusted": true}, {"t": "pointermove", "x": 89, "y": 226.5, "ts": 1238639.9, "buttons": 0, "trusted": true}, {"t": "mousemove", "x": 89, "y": 226, "ts": 1238639.9, "buttons": 0, "trusted": true}]}
\ No newline at end of file
diff --git a/try/human_trace2.json b/try/human_trace2.json
new file mode 100644
index 0000000..49647d5
--- /dev/null
+++ b/try/human_trace2.json
@@ -0,0 +1 @@
+{"iframe_origin": [770, 305], "events": [{"t": "pointerdown", "x": 30, "y": 355.5, "ts": 1707201, "buttons": 1, "trusted": true}, {"t": "mousedown", "x": 30, "y": 355, "ts": 1707201, "buttons": 1, "trusted": true}, {"t": "pointerup", "x": 30, "y": 355.5, "ts": 1707203.8, "buttons": 0, "trusted": true}, {"t": "mouseup", "x": 30, "y": 355, "ts": 1707203.8, "buttons": 0, "trusted": true}]}
\ No newline at end of file
diff --git a/try/human_trace_pass.json b/try/human_trace_pass.json
new file mode 100644
index 0000000..a393a6b
--- /dev/null
+++ b/try/human_trace_pass.json
@@ -0,0 +1 @@
+{"iframe_origin": [770, 305], "events": [{"t": 2802.599998474121, "type": "down", "x": 30, "y": 355, "btns": 1}, {"t": 2805.099998474121, "type": "up", "x": 30, "y": 355, "btns": 0}, {"t": 259020.29999923706, "type": "move", "x": 85, "y": 223, "btns": 0}, {"t": 259168.29999923706, "type": "move", "x": 72, "y": 265, "btns": 0}, {"t": 259282.29999923706, "type": "move", "x": 62, "y": 297, "btns": 0}, {"t": 259319.29999923706, "type": "move", "x": 61, "y": 303, "btns": 0}, {"t": 259433.29999923706, "type": "move", "x": 59, "y": 317, "btns": 0}, {"t": 259502.29999923706, "type": "move", "x": 63, "y": 324, "btns": 0}, {"t": 259601.29999923706, "type": "move", "x": 76, "y": 325, "btns": 0}, {"t": 259713.29999923706, "type": "move", "x": 77, "y": 323, "btns": 0}, {"t": 259817.29999923706, "type": "move", "x": 96, "y": 311, "btns": 0}, {"t": 260080.29999923706, "type": "move", "x": 169, "y": 220, "btns": 0}, {"t": 260238.29999923706, "type": "move", "x": 170, "y": 219, "btns": 0}, {"t": 260298.29999923706, "type": "move", "x": 174, "y": 215, "btns": 0}, {"t": 260444.29999923706, "type": "move", "x": 175, "y": 215, "btns": 0}, {"t": 260654.29999923706, "type": "move", "x": 172, "y": 215, "btns": 0}, {"t": 260759.29999923706, "type": "move", "x": 168, "y": 216, "btns": 0}, {"t": 261248.29999923706, "type": "move", "x": 163, "y": 218, "btns": 0}, {"t": 261352.29999923706, "type": "move", "x": 153, "y": 227, "btns": 0}, {"t": 261380.29999923706, "type": "move", "x": 146, "y": 234, "btns": 0}, {"t": 261699.29999923706, "type": "move", "x": 94, "y": 280, "btns": 0}, {"t": 261788.29999923706, "type": "move", "x": 69, "y": 328, "btns": 0}, {"t": 261819.29999923706, "type": "move", "x": 63, "y": 340, "btns": 0}, {"t": 261863.29999923706, "type": "move", "x": 60, "y": 344, "btns": 0}, {"t": 262146.29999923706, "type": "move", "x": 32, "y": 357, "btns": 0}, {"t": 262206.29999923706, "type": "down", "x": 32, "y": 357, "btns": 1}, {"t": 262303.29999923706, "type": "up", "x": 32, "y": 357, "btns": 0}, {"t": 262748.29999923706, "type": "move", "x": 29, "y": 357, "btns": 0}, {"t": 262861.29999923706, "type": "move", "x": 27, "y": 357, "btns": 0}, {"t": 262961.29999923706, "type": "move", "x": 27, "y": 356, "btns": 0}, {"t": 263073.29999923706, "type": "down", "x": 27, "y": 356, "btns": 1}, {"t": 263186.29999923706, "type": "up", "x": 27, "y": 356, "btns": 0}, {"t": 263595.29999923706, "type": "move", "x": 28, "y": 356, "btns": 0}, {"t": 263686.29999923706, "type": "move", "x": 29, "y": 354, "btns": 0}, {"t": 263784.29999923706, "type": "move", "x": 35, "y": 345, "btns": 0}, {"t": 263826.29999923706, "type": "move", "x": 39, "y": 337, "btns": 0}, {"t": 263865.29999923706, "type": "move", "x": 41, "y": 333, "btns": 0}, {"t": 263981.29999923706, "type": "move", "x": 47, "y": 326, "btns": 0}, {"t": 264017.29999923706, "type": "move", "x": 47, "y": 325, "btns": 0}, {"t": 264130.29999923706, "type": "move", "x": 47, "y": 324, "btns": 0}, {"t": 264246.29999923706, "type": "move", "x": 47, "y": 323, "btns": 0}, {"t": 264358.29999923706, "type": "move", "x": 49, "y": 319, "btns": 0}, {"t": 264452.29999923706, "type": "move", "x": 53, "y": 312, "btns": 0}, {"t": 264555.29999923706, "type": "move", "x": 54, "y": 311, "btns": 0}, {"t": 264579.29999923706, "type": "move", "x": 58, "y": 305, "btns": 0}, {"t": 264667.29999923706, "type": "move", "x": 59, "y": 305, "btns": 0}, {"t": 264778.29999923706, "type": "move", "x": 61, "y": 302, "btns": 0}, {"t": 264895.29999923706, "type": "move", "x": 62, "y": 301, "btns": 0}, {"t": 264997.29999923706, "type": "move", "x": 65, "y": 300, "btns": 0}, {"t": 265145.29999923706, "type": "move", "x": 63, "y": 300, "btns": 0}, {"t": 265180.29999923706, "type": "move", "x": 58, "y": 302, "btns": 0}, {"t": 265331.29999923706, "type": "move", "x": 56, "y": 304, "btns": 0}, {"t": 284663.89999961853, "type": "down", "x": 30, "y": 355, "btns": 1}, {"t": 284666.29999923706, "type": "up", "x": 30, "y": 355, "btns": 0}, {"t": 304965.29999923706, "type": "move", "x": 76, "y": 73, "btns": 0}, {"t": 305040.29999923706, "type": "move", "x": 80, "y": 106, "btns": 0}, {"t": 305099.29999923706, "type": "move", "x": 80, "y": 107, "btns": 0}, {"t": 305226.29999923706, "type": "move", "x": 80, "y": 106, "btns": 0}, {"t": 305316.29999923706, "type": "move", "x": 80, "y": 103, "btns": 0}, {"t": 305361.29999923706, "type": "move", "x": 81, "y": 102, "btns": 0}, {"t": 305399.29999923706, "type": "move", "x": 81, "y": 101, "btns": 0}, {"t": 309401.29999923706, "type": "move", "x": 18, "y": 221, "btns": 0}, {"t": 309466.29999923706, "type": "move", "x": 29, "y": 250, "btns": 0}, {"t": 309550.29999923706, "type": "move", "x": 27, "y": 271, "btns": 0}, {"t": 309639.29999923706, "type": "move", "x": 31, "y": 284, "btns": 0}, {"t": 309755.29999923706, "type": "move", "x": 42, "y": 292, "btns": 0}, {"t": 309852.29999923706, "type": "move", "x": 45, "y": 294, "btns": 0}, {"t": 309917.29999923706, "type": "move", "x": 47, "y": 298, "btns": 0}, {"t": 309968.29999923706, "type": "move", "x": 51, "y": 305, "btns": 0}, {"t": 310003.29999923706, "type": "move", "x": 51, "y": 306, "btns": 0}, {"t": 310275.29999923706, "type": "down", "x": 51, "y": 306, "btns": 1}, {"t": 310370.29999923706, "type": "move", "x": 52, "y": 307, "btns": 1}, {"t": 310393.29999923706, "type": "move", "x": 54, "y": 307, "btns": 1}, {"t": 310428.29999923706, "type": "move", "x": 65, "y": 303, "btns": 1}, {"t": 310482.29999923706, "type": "move", "x": 66, "y": 303, "btns": 1}, {"t": 310566.29999923706, "type": "move", "x": 73, "y": 303, "btns": 1}, {"t": 310642.29999923706, "type": "move", "x": 75, "y": 303, "btns": 1}, {"t": 310725.29999923706, "type": "move", "x": 83, "y": 303, "btns": 1}, {"t": 310745.29999923706, "type": "move", "x": 85, "y": 303, "btns": 1}, {"t": 310782.29999923706, "type": "move", "x": 86, "y": 303, "btns": 1}, {"t": 310814.29999923706, "type": "move", "x": 88, "y": 303, "btns": 1}, {"t": 310942.29999923706, "type": "move", "x": 101, "y": 304, "btns": 1}, {"t": 311117.29999923706, "type": "move", "x": 123, "y": 304, "btns": 1}, {"t": 311236.29999923706, "type": "move", "x": 129, "y": 304, "btns": 1}, {"t": 311372.29999923706, "type": "move", "x": 142, "y": 304, "btns": 1}, {"t": 311638.29999923706, "type": "move", "x": 157, "y": 305, "btns": 1}, {"t": 311839.29999923706, "type": "move", "x": 159, "y": 306, "btns": 1}, {"t": 311861.29999923706, "type": "move", "x": 160, "y": 306, "btns": 1}, {"t": 312874.29999923706, "type": "up", "x": 160, "y": 306, "btns": 0}, {"t": 312875.29999923706, "type": "move", "x": 161, "y": 306, "btns": 0}, {"t": 313019.29999923706, "type": "move", "x": 159, "y": 306, "btns": 0}, {"t": 313066.29999923706, "type": "move", "x": 158, "y": 306, "btns": 0}, {"t": 313490.29999923706, "type": "move", "x": 156, "y": 306, "btns": 0}, {"t": 313535.29999923706, "type": "move", "x": 152, "y": 306, "btns": 0}, {"t": 313585.29999923706, "type": "move", "x": 153, "y": 306, "btns": 0}, {"t": 313618.29999923706, "type": "move", "x": 154, "y": 307, "btns": 0}, {"t": 313636.29999923706, "type": "move", "x": 155, "y": 308, "btns": 0}, {"t": 313699.29999923706, "type": "move", "x": 155, "y": 309, "btns": 0}, {"t": 313718.29999923706, "type": "move", "x": 157, "y": 309, "btns": 0}, {"t": 313774.29999923706, "type": "move", "x": 158, "y": 309, "btns": 0}]}
\ No newline at end of file
diff --git a/try/live_solve.py b/try/live_solve.py
new file mode 100644
index 0000000..cafa30f
--- /dev/null
+++ b/try/live_solve.py
@@ -0,0 +1,69 @@
+"""线上验证码求解(带服务端 tip_y 约束)。
+
+服务端 captcha/get 响应中的 tip_y × 2 = 缺口 y 坐标(mark 画布顶)。
+经 10 组线上样本校准:solver 无约束 y 与 2×tip_y 差 ≤4px(定位准的样本),
+偏差大的样本(AMBIGUOUS)正是被服务端判 VerifyErr 的。
+用 tip_y 约束 y 后在 score map 上重选 x,可显著提高准确率。
+
+用法:
+ .venv/bin/python try/live_solve.py
+输出 JSON: x(拖动目标, 原图px)、score、scale
+"""
+import json
+import sys
+from pathlib import Path
+
+import cv2
+
+sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "src"))
+import method_l_shape as L # noqa: E402
+
+
+def live_solve(big_path, mark_path, tip_y, y_tol=8):
+ """tip_y 约束版求解。返回 {x, y, scale, score} 或 None。"""
+ try:
+ target_y = int(tip_y) * 2
+ except (TypeError, ValueError):
+ return None
+ big = cv2.imread(big_path)
+ mark = cv2.imread(mark_path, cv2.IMREAD_UNCHANGED)
+ if big is None or mark is None:
+ return None
+ try:
+ d = L.setup(big, mark)
+ if d is None:
+ return None
+ best = []
+ for s in L.SCALES:
+ s = round(float(s), 3)
+ score, w, h, ptset = L.score_at_scale(d, s)
+ if score is None:
+ continue
+ for v, x, y in L.nms_take(score, 30, int(0.45 * max(w, h))):
+ if abs(y - target_y) <= y_tol:
+ best.append((v, s, x, y, w, h))
+ except (ValueError, IndexError, TypeError) as e:
+ print(f"匹配失败: {e}", file=sys.stderr)
+ return None
+ if not best:
+ # 放宽容差重试
+ return live_solve(big_path, mark_path, tip_y, y_tol=y_tol * 2)
+ best.sort(key=lambda c: c[0])
+ try:
+ v, s, x, y, w, h = best[0]
+ return {"x": x, "y": y, "scale": s, "score": round(float(v), 2), "w": w, "h": h}
+ except (IndexError, TypeError, ValueError) as e:
+ print(f"候选解析失败: {e}", file=sys.stderr)
+ return None
+
+
+if __name__ == "__main__":
+ if len(sys.argv) < 4:
+ print(__doc__)
+ sys.exit(1)
+ try:
+ result = live_solve(sys.argv[1], sys.argv[2], int(sys.argv[3]))
+ except (OSError, ValueError) as e:
+ result = None
+ print(f"求解失败: {e}", file=sys.stderr)
+ print(json.dumps(result) if result else '{"ok": false}')
diff --git a/try/rate_limit_probe.py b/try/rate_limit_probe.py
new file mode 100644
index 0000000..1614ca8
--- /dev/null
+++ b/try/rate_limit_probe.py
@@ -0,0 +1,38 @@
+"""低频位探测:每 WAIT 秒单次干净尝试(只选高质量题),直到通过或轮次用完。
+
+用法: python try/rate_limit_probe.py [wait_sec] [rounds] [max_score]
+"""
+import asyncio
+import sys
+
+import cold_start_attempt as csa
+
+
+async def main():
+ try:
+ wait_sec = int(sys.argv[1]) if len(sys.argv) > 1 else 600
+ rounds = int(sys.argv[2]) if len(sys.argv) > 2 else 6
+ max_score = float(sys.argv[3]) if len(sys.argv) > 3 else 5.0
+ except ValueError:
+ print("用法: python try/rate_limit_probe.py [wait_sec] [rounds] [max_score]",
+ file=sys.stderr)
+ return
+ for i in range(rounds):
+ print(f"===== round {i + 1}/{rounds} =====", flush=True)
+ try:
+ r = await csa.main_once(max_questions=4, max_score=max_score)
+ except RuntimeError as e:
+ print(f"attempt error: {e}", flush=True)
+ r = "error"
+ print(f"round {i + 1} -> {r}", flush=True)
+ if r == "PASS":
+ print("*** PASS ***", flush=True)
+ return
+ if i < rounds - 1:
+ print(f"冷却 {wait_sec}s...", flush=True)
+ await asyncio.sleep(wait_sec)
+ print("轮次用完", flush=True)
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/try/replay_human.py b/try/replay_human.py
new file mode 100644
index 0000000..d108cb0
--- /dev/null
+++ b/try/replay_human.py
@@ -0,0 +1,241 @@
+"""真人轨迹采集 + CDP 回放(hook 路线的落地实验)
+
+原理:
+1. rec 阶段:在验证码 iframe document 上挂 capture 阶段监听,记录真人拖动产生的
+ pointerdown/move/up + mousedown/move/up 完整事件流(含原生时序)。
+2. replay 阶段:CDP Input.dispatchMouseEvent 按录制的坐标与相对时序重放。
+ CDP 事件走浏览器输入管道,isTrusted=true,事件密度/节奏与真人一致。
+
+用法:
+ .venv/bin/python try/replay_human.py record # 进入录制模式,等用户手动拖
+ .venv/bin/python try/replay_human.py replay # 刷新→solve→回放录制的真人轨迹
+"""
+import asyncio
+import base64
+import glob
+import json
+import os
+import sys
+import time
+import urllib.request
+from pathlib import Path
+
+import websockets
+
+sys.path.insert(0, str(Path(__file__).resolve().parent))
+sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "src"))
+
+CDP_HTTP = "http://127.0.0.1:9222"
+CAPT_DIR = Path(__file__).resolve().parent / "captures"
+REPLAY_FILE = Path(__file__).resolve().parent / "human_trace.json"
+IFRAME_X, IFRAME_Y = 770, 305 # 验证码 iframe 左上角视口坐标
+SCALE = 340 / 552 # UI 显示 / 原图
+
+
+def _json(path):
+ try:
+ with urllib.request.urlopen(f"{CDP_HTTP}{path}", timeout=5) as r:
+ return json.load(r)
+ except (OSError, ValueError):
+ return None
+
+
+HOOK_JS = """
+(() => {
+ if (window.__traceHook) return 'already';
+ window.__traceHook = 1;
+ window.__trace = [];
+ const types = ['pointerdown','pointermove','pointerup',
+ 'mousedown','mousemove','mouseup'];
+ for (const t of types) {
+ document.addEventListener(t, e => {
+ window.__trace.push({
+ t, x: e.clientX, y: e.clientY,
+ ts: Math.round(e.timeStamp * 100) / 100,
+ buttons: e.buttons, trusted: e.isTrusted,
+ pressure: e.pressure || 0,
+ movementX: e.movementX || 0, movementY: e.movementY || 0,
+ });
+ }, {capture: true, passive: true});
+ }
+ return 'trace hook on';
+})()
+"""
+
+
+async def main(mode: str):
+ ver = _json("/json/version")
+ targets = _json("/json/list") or []
+ if not ver:
+ print("CDP 9222 不可用")
+ return
+ page = next((t for t in targets if t["type"] == "page" and "douyin" in t["url"]), None)
+ ifr = next((t for t in targets if "rmc.bytedance.com" in t.get("url", "")), None)
+ if not page or not ifr:
+ print("找不到 douyin 页面或验证码 iframe")
+ return
+ async with websockets.connect(ver["webSocketDebuggerUrl"], max_size=64 * 1024 * 1024) as ws:
+ mid = [0]
+
+ async def cdp(method, params=None, sid=None):
+ mid[0] += 1
+ m = {"id": mid[0], "method": method, "params": params or {}}
+ if sid:
+ m["sessionId"] = sid
+ await ws.send(json.dumps(m))
+ while True:
+ try:
+ r = json.loads(await ws.recv())
+ except json.JSONDecodeError:
+ continue
+ if r.get("id") == mid[0]:
+ if "error" in r:
+ raise RuntimeError(f"{method}: {r['error']}")
+ return r.get("result", {})
+
+ psid = (await cdp("Target.attachToTarget", {"targetId": page["id"], "flatten": True}))["sessionId"]
+ isid = (await cdp("Target.attachToTarget", {"targetId": ifr["id"], "flatten": True}))["sessionId"]
+ await cdp("Runtime.enable", sid=isid)
+
+ async def jse(expr, sid=isid):
+ r = await cdp("Runtime.evaluate",
+ {"expression": expr, "returnByValue": True, "awaitPromise": True}, sid)
+ return r.get("result", {}).get("value")
+
+ # 强制重挂(页面可能刷新过,旧 hook 已失效;先拆旧 listener)
+ await jse("""
+(() => {
+ window.__trace = [];
+ if (window.__traceFn) { for (const [t, f] of window.__traceFn) document.removeEventListener(t, f, {capture: true}); }
+ window.__traceFn = [];
+ const types = ['pointerdown','pointermove','pointerup','mousedown','mousemove','mouseup'];
+ for (const t of types) {
+ const f = e => {
+ window.__trace.push({t, x: e.clientX, y: e.clientY, ts: Math.round(e.timeStamp*100)/100,
+ buttons: e.buttons, trusted: e.isTrusted});
+ };
+ document.addEventListener(t, f, {capture: true, passive: true});
+ window.__traceFn.push([t, f]);
+ }
+ return 'rehooked';
+})()
+""")
+
+ if mode == "record":
+ print("== 录制模式:请在 20s 内用鼠标手动完成一次滑块拖动 ==")
+ await asyncio.sleep(20)
+ raw = await jse("JSON.stringify(window.__trace || [])")
+ try:
+ trace = json.loads(raw or "[]")
+ except (TypeError, ValueError) as e:
+ print(f"trace 解析失败: {e}")
+ return
+ mv = [e for e in trace if e["t"] == "mousemove"]
+ dn = [e for e in trace if e["t"] == "mousedown"]
+ print(f"共 {len(trace)} 事件: mousedown={len(dn)} mousemove={len(mv)}")
+ if len(dn) >= 1 and len(mv) > 10:
+ # 以第一次 mousedown 为拖动起点,截取到 mouseup
+ start_ts = dn[0]["ts"]
+ ups = [e["ts"] for e in trace if e["t"] == "mouseup" and e["ts"] > start_ts]
+ end_ts = ups[0] if ups else trace[-1]["ts"]
+ drag = [e for e in trace if start_ts - 50 <= e["ts"] <= end_ts]
+ try:
+ with open(REPLAY_FILE, "w") as f:
+ json.dump({"iframe_origin": [IFRAME_X, IFRAME_Y], "events": drag}, f)
+ except OSError as e:
+ print(f"保存失败: {e}")
+ return
+ print(f"已保存 {len(drag)} 事件({end_ts - start_ts:.0f}ms)→ {REPLAY_FILE}")
+ else:
+ print("没采到拖动,重试")
+ return
+
+ # ---- replay 模式 ----
+ if not REPLAY_FILE.exists():
+ print("没有录制文件,先跑 record")
+ return
+ try:
+ with open(REPLAY_FILE) as f:
+ rec = json.load(f)
+ except (OSError, ValueError) as e:
+ print(f"读取录制文件失败: {e}")
+ return
+ events = rec["events"]
+ ox, oy = rec["iframe_origin"]
+ # 找 mousedown 起点
+ dn = next(e for e in events if e["t"] == "mousedown")
+ start_x, start_y = ox + dn["x"], oy + dn["y"]
+ t0 = dn["ts"]
+ ups = [e["ts"] for e in events if e["t"] == "mouseup"]
+ total_ms = (ups[0] - t0) if ups else 1000
+ print(f"回放 {len(events)} 事件,拖动 {total_ms:.0f}ms")
+
+ # 刷新拿新题
+ rx, ry = IFRAME_X + 30, IFRAME_Y + 355
+ for typ in ("mousePressed", "mouseReleased"):
+ await cdp("Input.dispatchMouseEvent",
+ {"type": typ, "x": rx, "y": ry, "button": "left", "buttons": 1,
+ "clickCount": 1}, psid)
+ got = None
+ t0w = time.time()
+ while time.time() - t0w < 14 and not got:
+ await asyncio.sleep(0.5)
+ fs = sorted(glob.glob(str(CAPT_DIR / "net_*_get.json")), reverse=True)
+ if fs and time.time() - os.path.getmtime(fs[0]) < 10:
+ ts = os.path.basename(fs[0]).split("_")[1]
+ await asyncio.sleep(2.5)
+ jpgs = [f for f in glob.glob(str(CAPT_DIR / f"net_{ts}_*")) if f.endswith((".jpg", ".jpeg"))]
+ pngs = [f for f in glob.glob(str(CAPT_DIR / f"net_{ts}_*")) if f.endswith(".png")]
+ if jpgs and pngs:
+ got = (ts, jpgs[0], pngs[0])
+ if not got:
+ print("没等到题")
+ return
+ ts, big_f, mark_f = got
+ try:
+ with open(f"{CAPT_DIR}/net_{ts}_get.json") as f:
+ tip_y = json.load(f)["data"]["question"]["tip_y"]
+ except (OSError, KeyError, ValueError) as e:
+ print(f"get.json 读取失败: {e}")
+ return
+ from solve import solve
+ try:
+ with open(big_f, "rb") as f:
+ big_b64 = base64.b64encode(f.read()).decode()
+ with open(mark_f, "rb") as f:
+ mark_b64 = base64.b64encode(f.read()).decode()
+ except OSError as e:
+ print(f"图片读取失败: {e}")
+ return
+ result = solve(big_b64, mark_b64)
+ print(f"[{ts}] tip_y={tip_y} solve:", {k: result[k] for k in ("ok", "x", "score") if k in result})
+ if not result.get("ok"):
+ return
+ dist_ui = result["x"] * SCALE
+ print(f"需拖 {dist_ui:.1f}px(UI),录制拖动 {total_ms:.0f}ms")
+
+ # 回放:mousedown → 按 ts 差调度 mousemove → mouseup
+ await cdp("Input.dispatchMouseEvent",
+ {"type": "mousePressed", "x": start_x, "y": start_y,
+ "button": "left", "buttons": 1, "clickCount": 1}, psid)
+ t_start = time.time()
+ for e in events:
+ if e["t"] != "mousemove" or e["ts"] <= t0:
+ continue
+ delay = (e["ts"] - t0) / 1000.0 - (time.time() - t_start)
+ if delay > 0:
+ await asyncio.sleep(delay)
+ await cdp("Input.dispatchMouseEvent",
+ {"type": "mouseMoved", "x": ox + e["x"], "y": oy + e["y"],
+ "button": "left", "buttons": 1}, psid)
+ await asyncio.sleep(0.25)
+ await cdp("Input.dispatchMouseEvent",
+ {"type": "mouseReleased", "x": ox + events[-1]["x"], "y": oy + events[-1]["y"],
+ "button": "left", "buttons": 1, "clickCount": 1}, psid)
+ print("回放完成")
+ await asyncio.sleep(4)
+
+
+if __name__ == "__main__":
+ mode = sys.argv[1] if len(sys.argv) > 1 else "record"
+ asyncio.run(main(mode))
diff --git a/try/rotate_loop.py b/try/rotate_loop.py
new file mode 100644
index 0000000..ab210e7
--- /dev/null
+++ b/try/rotate_loop.py
@@ -0,0 +1,92 @@
+"""5014 零等待换号循环:失败 → 立即重载页面换新随机号重试,PASS 即停。
+
+用户指令:不需要等待冷却时间,风控(5014)就直接换账号触发。
+每次尝试 = Page.reload(清 session)→ 新随机手机号/密码 → 触发 → solve → xdotool 拖动。
+"""
+import asyncio, sys, time
+
+sys.path.insert(0, "/home/yanghao05/Workspace/dy-captcha/try")
+sys.path.insert(0, "/home/yanghao05/Workspace/dy-captcha/src")
+import os
+os.environ["XDOTOOL"] = "1"
+os.environ["REPLAY"] = "1"
+os.environ["REPLAY_FILE"] = "/home/yanghao05/Workspace/dy-captcha/try/human_trace_pass.json"
+os.environ["REPLAY_SEG"] = "last"
+os.environ["REPLAY_MS"] = "2600"
+import cold_start_attempt as cs
+
+
+async def reload_page():
+ """Page.reload 清 session,等加载完成。"""
+ import json, urllib.request as ur
+ try:
+ with ur.urlopen("http://127.0.0.1:9222/json/version", timeout=5) as r:
+ ver = json.load(r)
+ except (OSError, ValueError) as e:
+ print(f"CDP 不可达: {e}", flush=True)
+ return False
+ targets = cs._json("/json/list") or []
+ page = next((t for t in targets if t["type"] == "page" and "douyin" in t.get("url", "")), None)
+ if not page:
+ return False
+ import websockets
+ async with websockets.connect(ver["webSocketDebuggerUrl"], max_size=64*1024*1024) as ws:
+ mid = [0]
+ async def cdp(method, params=None, sid=None):
+ mid[0] += 1
+ m = {"id": mid[0], "method": method, "params": params or {}}
+ if sid:
+ m["sessionId"] = sid
+ await ws.send(json.dumps(m))
+ while True:
+ try:
+ resp = json.loads(await ws.recv())
+ except (json.JSONDecodeError, asyncio.TimeoutError):
+ continue
+ if resp.get("id") == mid[0]:
+ return resp
+ psid = (await cdp("Target.attachToTarget", {"targetId": page["id"], "flatten": True})).get("result", {}).get("sessionId")
+ # 清 cookie(用户指令:限流时清 cookie 即可解除触发限制)
+ await cdp("Network.enable", sid=psid)
+ await cdp("Network.clearBrowserCookies", sid=psid)
+ await cdp("Page.enable", sid=psid)
+ # cookie 清空后 session 失效可能跳转 —— 直接导航回目标页(比 reload 稳)
+ await cdp("Page.navigate", {"url": "https://www.douyin.com/jingxuan"}, sid=psid)
+ # 等主 frame 加载完成(最多 15s)
+ for _ in range(60):
+ try:
+ ev = json.loads(await asyncio.wait_for(ws.recv(), timeout=2))
+ except (asyncio.TimeoutError, json.JSONDecodeError, ValueError):
+ continue
+ if ev.get("method") == "Page.loadEventFired" and ev.get("sessionId") == psid:
+ break
+ await asyncio.sleep(3)
+ return True
+
+
+async def main():
+ for i in range(20):
+ print(f"\n=== 尝试 {i+1} @ {time.strftime('%H:%M:%S')} ===", flush=True)
+ # 失败后换号:重载页面(首次不重载,页面已是干净状态则直接用)
+ if i > 0:
+ try:
+ ok = await reload_page()
+ if not ok:
+ print("页面未找到,跳过", flush=True)
+ continue
+ except Exception as e:
+ print(f"reload 异常: {e}", flush=True)
+ try:
+ r = await cs.main_once(3, 9)
+ except Exception as e:
+ print(f"异常: {e}", flush=True)
+ r = "error"
+ print(f"结果: {r}", flush=True)
+ if r == "PASS":
+ print("*** CLOSED LOOP! ***", flush=True)
+ return
+ # 5014/500/502 全部立即换号重试,无等待
+ print("20 次尝试完毕", flush=True)
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/try/sdk_explore.py b/try/sdk_explore.py
new file mode 100644
index 0000000..797036a
--- /dev/null
+++ b/try/sdk_explore.py
@@ -0,0 +1,82 @@
+"""探测验证码 iframe 内 SDK 结构:script 源、addEventListener 采集点、轨迹缓冲。"""
+import asyncio, json, urllib.request, sys
+import websockets
+
+CDP_HTTP = "http://127.0.0.1:9222"
+
+def _json(path):
+ try:
+ with urllib.request.urlopen(f"{CDP_HTTP}{path}", timeout=5) as r:
+ return json.load(r)
+ except (OSError, ValueError):
+ return None
+
+async def main():
+ ver = _json("/json/version")
+ targets = _json("/json/list") or []
+ if not ver or "webSocketDebuggerUrl" not in ver:
+ print("CDP 9222 不可用", file=sys.stderr); return
+ cand = [t for t in targets if "rmc" in t.get("url","") or "captcha" in t.get("url","").lower()]
+ if not cand:
+ print("未找到 captcha iframe,targets:")
+ for t in targets: print(" ", t["type"], t["url"][:80])
+ return
+ tgt = cand[0]
+ print("探测目标:", tgt["url"][:100])
+ async with websockets.connect(ver["webSocketDebuggerUrl"], max_size=64*1024*1024) as ws:
+ mid = [0]
+ async def cdp(method, params=None, sid=None):
+ mid[0] += 1
+ m = {"id": mid[0], "method": method, "params": params or {}}
+ if sid: m["sessionId"] = sid
+ await ws.send(json.dumps(m))
+ while True:
+ try:
+ r = json.loads(await ws.recv())
+ except json.JSONDecodeError:
+ continue
+ if r.get("id") == mid[0]:
+ if "error" in r: raise RuntimeError(f"{method}: {r['error']}")
+ return r.get("result", {})
+ sid = (await cdp("Target.attachToTarget",
+ {"targetId": tgt["id"], "flatten": True}))["sessionId"]
+ await cdp("Runtime.enable", sid=sid)
+
+ async def js(expr):
+ r = await cdp("Runtime.evaluate",
+ {"expression": expr, "returnByValue": True,
+ "awaitPromise": True, "userGesture": True}, sid)
+ return r.get("result", {}).get("value")
+
+ # 1) 挂 listener 记录 hook(记录到 window 全局,跨 evaluate 可读)
+ await js("""
+(() => {
+ if (window.__lh) return 'already';
+ const orig = EventTarget.prototype.addEventListener;
+ window.__lh = [];
+ EventTarget.prototype.addEventListener = function(t, f, o){
+ try { window.__lh.push([t, String(f && f.name || 'anon'),
+ String(f).slice(0,120).replace(/\\n/g,' ')]); } catch(e){}
+ return orig.call(this, t, f, o);
+ };
+ return 'hook installed';
+})()
+""")
+ # 2) 已有 listener(getEventListeners 仅 DevTools 可用,改用枚举 on* + 重放脚本已知点)
+ scripts = await js("[...document.scripts].map(s=>s.src||('inline:'+s.textContent.length)).join('\\n')")
+ print("== scripts ==\\n" + str(scripts))
+ globals_ = await js("""
+Object.getOwnPropertyNames(window).filter(k=>/captcha|verify|secsdk|byted|rms|rmc|track|slid|nocaptcha/i.test(k)).join('\\n')
+""")
+ print("== 全局候选 ==\\n" + str(globals_))
+ await asyncio.sleep(15)
+ log = await js("JSON.stringify(window.__lh||[])")
+ try:
+ rows = json.loads(log or "[]")
+ except (TypeError, ValueError) as e:
+ print(f"__lh 解析失败: {e}", file=sys.stderr)
+ return
+ print(f"== 15s 内 addEventListener 调用: {len(rows)} ==")
+ for t, name, src in rows:
+ print(f" [{t}] {name} :: {src[:110]}")
+asyncio.run(main())
diff --git a/try/solo_attempt.py b/try/solo_attempt.py
new file mode 100644
index 0000000..bb7d0f6
--- /dev/null
+++ b/try/solo_attempt.py
@@ -0,0 +1,150 @@
+"""单次干净尝试:刷新→采题→solve(score<=阈值才出手)→force=0.5 拖动→读 verify。
+
+用法: python try/solo_attempt.py [wait_sec] [max_score]
+频控敏感:每次尝试间隔 wait_sec(默认 600s)。
+"""
+import asyncio, json, sys, time, base64, random, urllib.request as ur
+from pathlib import Path
+import websockets
+
+sys.path.insert(0, str(Path(__file__).resolve().parent))
+sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "src"))
+from solve import solve
+from human_drag import gen_human_path
+
+CDP = "http://127.0.0.1:9222"
+IFRAME_X, IFRAME_Y = 770, 305
+SCALE = 340 / 552
+HOOK = """
+(() => {
+ window.__lastGet=null; window.__lastVerify=null;
+ const oOpen=XMLHttpRequest.prototype.open, oSend=XMLHttpRequest.prototype.send;
+ XMLHttpRequest.prototype.open=function(m,u){this.__u=u;return oOpen.apply(this,arguments);};
+ XMLHttpRequest.prototype.send=function(){const x=this;this.addEventListener('load',()=>{
+ try{ if(/captcha\\/get/.test(x.__u||'')) window.__lastGet=JSON.parse(x.responseText);
+ if(/captcha\\/verify/.test(x.__u||'')) window.__lastVerify=x.responseText.slice(0,200);}catch(e){}});return oSend.apply(this,arguments);};
+ return 'ok';
+})()
+"""
+
+
+def _json(path):
+ try:
+ with ur.urlopen(f"{CDP}{path}", timeout=5) as r:
+ return json.load(r)
+ except (OSError, ValueError):
+ return None
+
+
+async def one_attempt(ws, mid_ref, max_score):
+ async def cdp(method, params=None, sid=None):
+ mid_ref[0] += 1
+ m = {"id": mid_ref[0], "method": method, "params": params or {}}
+ if sid:
+ m["sessionId"] = sid
+ await ws.send(json.dumps(m))
+ while True:
+ try:
+ r = json.loads(await ws.recv())
+ except (json.JSONDecodeError, asyncio.TimeoutError):
+ continue
+ if r.get("id") == mid_ref[0]:
+ if "error" in r:
+ raise RuntimeError(f"{method}: {r['error']}")
+ return r.get("result", {})
+
+ targets = _json("/json/list") or []
+ page = next((t for t in targets if t["type"] == "page" and "douyin" in t.get("url", "")), None)
+ ifr = next((t for t in targets if "rmc.bytedance.com" in t.get("url", "")), None)
+ if not page or not ifr:
+ print("页面或验证码 iframe 不在", flush=True)
+ return None
+ psid = (await cdp("Target.attachToTarget", {"targetId": page["id"], "flatten": True}))["sessionId"]
+ isid = (await cdp("Target.attachToTarget", {"targetId": ifr["id"], "flatten": True}))["sessionId"]
+ await cdp("Runtime.enable", sid=isid)
+
+ async def jse(expr, sid=isid):
+ r = await cdp("Runtime.evaluate",
+ {"expression": expr, "returnByValue": True, "awaitPromise": True}, sid)
+ return r.get("result", {}).get("value")
+
+ await jse(HOOK)
+ for typ in ("mousePressed", "mouseReleased"):
+ await cdp("Input.dispatchMouseEvent",
+ {"type": typ, "x": IFRAME_X + 30, "y": IFRAME_Y + 355,
+ "button": "left", "buttons": 0, "clickCount": 1}, psid)
+ g = None
+ t0 = time.time()
+ while time.time() - t0 < 8 and not g:
+ await asyncio.sleep(0.8)
+ gg = await jse("JSON.stringify(window.__lastGet)")
+ if gg and gg != "null":
+ try:
+ g = json.loads(gg)
+ except ValueError:
+ g = None
+ if not g:
+ print("no get", flush=True)
+ return None
+ q = g["data"]["question"]
+ with ur.urlopen(q["url1"]) as r:
+ big = r.read()
+ with ur.urlopen(q["url2"]) as r:
+ mark = r.read()
+ res = solve(base64.b64encode(big).decode(), base64.b64encode(mark).decode(), tip_y=q["tip_y"])
+ print(f"tip_y={q['tip_y']} solve={ {k: res.get(k) for k in ('x','y','scale','score','confidence')} }", flush=True)
+ if not res.get("ok") or res.get("confidence") != "OK" or res.get("score", 99) > max_score:
+ print("低质量题,跳过拖动", flush=True)
+ return None
+ dist_ui = res["x"] * SCALE
+ sx, sy = IFRAME_X + 54, IFRAME_Y + 307
+ pts = gen_human_path(dist_ui, seed=random.randint(1, 9999))
+ await cdp("Input.dispatchMouseEvent",
+ {"type": "mousePressed", "x": sx, "y": sy, "button": "left",
+ "buttons": 1, "clickCount": 1, "force": 0.5}, psid)
+ await asyncio.sleep(0.25)
+ cx, cy = sx, sy
+ for dx, dy, dt in pts:
+ cx += dx
+ cy += dy
+ await asyncio.sleep(dt / 1000)
+ await cdp("Input.dispatchMouseEvent",
+ {"type": "mouseMoved", "x": round(cx, 1), "y": round(cy, 1),
+ "button": "left", "buttons": 1, "force": 0.5}, psid)
+ await asyncio.sleep(0.35)
+ await cdp("Input.dispatchMouseEvent",
+ {"type": "mouseReleased", "x": round(cx, 1), "y": round(cy, 1),
+ "button": "left", "buttons": 1, "clickCount": 1, "force": 0.5}, psid)
+ await asyncio.sleep(3)
+ v = await jse("JSON.stringify(window.__lastVerify)")
+ print("verify:", (v or "null")[-90:], flush=True)
+ return v
+
+
+async def main():
+ try:
+ wait_sec = int(sys.argv[1]) if len(sys.argv) > 1 else 600
+ max_score = float(sys.argv[2]) if len(sys.argv) > 2 else 4.2
+ except ValueError:
+ print("用法: python try/solo_attempt.py [wait_sec] [max_score]", file=sys.stderr)
+ return
+ ver = _json("/json/version")
+ if not ver or not ver.get("webSocketDebuggerUrl"):
+ print("无法连接 CDP", file=sys.stderr)
+ return
+ async with websockets.connect(ver["webSocketDebuggerUrl"], max_size=64 * 1024 * 1024) as ws:
+ mid = [0]
+ while True:
+ try:
+ v = await one_attempt(ws, mid, max_score)
+ if v and '"code":200' in v:
+ print("*** PASS ***", flush=True)
+ return
+ except Exception as e:
+ print("attempt error:", e, flush=True)
+ print(f"等待 {wait_sec}s(频控冷却)...", flush=True)
+ await asyncio.sleep(wait_sec)
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/try/trace_watch.py b/try/trace_watch.py
new file mode 100644
index 0000000..b6cf5ae
--- /dev/null
+++ b/try/trace_watch.py
@@ -0,0 +1,77 @@
+"""真人拖动轨迹监视器:等 rmc iframe 出现后 attach,每 0.5s 快照
+window.__dragTrace / __lastVerify 到 /tmp,iframe 销毁(验证通过)后保留最后快照退出。"""
+import asyncio, json, time, urllib.request as ur
+import websockets
+
+
+def _json(path):
+ try:
+ with ur.urlopen(f"http://127.0.0.1:9222{path}", timeout=5) as r:
+ return json.load(r)
+ except (OSError, ValueError):
+ return None
+
+
+async def main():
+ ver = _json("/json/version")
+ if not ver or not ver.get("webSocketDebuggerUrl"):
+ print("CDP 不可达,退出")
+ return
+ # 等待验证码 iframe 出现(最多 180s)
+ ifr = None
+ for _ in range(60):
+ targets = _json("/json/list") or []
+ ifr = next((t for t in targets if "rmc.bytedance.com" in t.get("url", "")), None)
+ if ifr:
+ break
+ await asyncio.sleep(3)
+ if not ifr:
+ print("无 iframe,退出")
+ return
+ async with websockets.connect(ver["webSocketDebuggerUrl"], max_size=64 * 1024 * 1024) as ws:
+ mid = [0]
+
+ async def cdp(method, params=None, sid=None):
+ mid[0] += 1
+ m = {"id": mid[0], "method": method, "params": params or {}}
+ if sid:
+ m["sessionId"] = sid
+ await ws.send(json.dumps(m))
+ while True:
+ try:
+ r = json.loads(await ws.recv())
+ except (json.JSONDecodeError, asyncio.TimeoutError):
+ continue
+ if r.get("id") == mid[0]:
+ if "error" in r:
+ raise RuntimeError(str(r["error"]))
+ return r.get("result", {})
+
+ isid = (await cdp("Target.attachToTarget", {"targetId": ifr["id"], "flatten": True}))["sessionId"]
+ await cdp("Runtime.enable", sid=isid)
+ print("trace_watch 就绪", flush=True)
+ last_len = -1
+ while True:
+ try:
+ r = await cdp("Runtime.evaluate", {
+ "expression": "JSON.stringify({n:(window.__dragTrace||[]).length,"
+ "trace:window.__dragTrace||null,v:window.__lastVerify||null})",
+ "returnByValue": True}, sid=isid)
+ val = r.get("result", {}).get("value")
+ if val:
+ d = json.loads(val)
+ if d["n"] != last_len:
+ last_len = d["n"]
+ with open("/tmp/trace_snap.json", "w") as f:
+ json.dump(d, f)
+ if d["v"]:
+ with open("/tmp/verify_snap.txt", "w") as f:
+ f.write(d["v"])
+ print(f"[{time.strftime('%H:%M:%S')}] {d['n']} 事件", flush=True)
+ await asyncio.sleep(0.5)
+ except (RuntimeError, websockets.exceptions.ConnectionClosed, OSError):
+ print("iframe 已销毁,保留最后快照退出", flush=True)
+ return
+
+
+asyncio.run(main())