From eacd7c8a23523c6d903969f14c9bb45d096c5f0d Mon Sep 17 00:00:00 2001 From: youfak Date: Thu, 30 Jul 2026 20:25:56 +0800 Subject: [PATCH] chore: initialize repository --- .claude/逆向分析.md | 550 ++++ .codex/skills/逆向分析.md | 550 ++++ .env.example | 5 + .gitattributes | 7 + .gitignore | 44 + bin/kwsg_10400_T1.bin | Bin 0 -> 147456 bytes bin/kwsg_10400_T2.bin | Bin 0 -> 41216 bytes bin/kwsg_10418_B_T1.bin | Bin 0 -> 147456 bytes bin/kwsg_10418_B_T2.bin | Bin 0 -> 41216 bytes core/README.md | 42 + core/__init__.py | 40 + core/atlas_sign.py | 26 + core/captcha_assist.py | 633 +++++ core/captured_profile.py | 64 + core/constants.py | 14 + core/device_cookie.py | 72 + core/device_id.py | 148 + core/device_profile.py | 568 ++++ core/dfp_cache.py | 131 + core/dfp_client.py | 122 + core/dfp_forms.py | 245 ++ core/dfp_knn.py | 305 +++ core/dfp_sign.py | 174 ++ core/dfp_sq0.py | 127 + core/enc_data.py | 237 ++ core/fap_request.py | 342 +++ core/h5_jsbridge.py | 274 ++ core/h5_kws.py | 356 +++ core/h5_kws_sign.mjs | 307 +++ core/h5_kws_vm.py | 507 ++++ core/h5_kww.py | 212 ++ core/h5_kww_alg.py | 608 +++++ core/h5_kww_server.mjs | 387 +++ core/h5_sig3.py | 379 +++ core/h5_vendor_encode.mjs | 243 ++ core/h5_vendor_encode_server.mjs | 57 + core/http_transport.py | 142 + core/ksse_crc.py | 13 + core/ksse_deobf.py | 120 + core/ksse_sted.py | 779 ++++++ core/kwf-0.0.2.2cee19b4b7dec496.js | 1 + ...ws-11-0.0.1-obfuscated.5e0a90af726d8a7e.js | 1 + core/kwsg.py | 210 ++ core/main-vendor-ox-x1_g5.mjs | 8 + core/mobile_encrypt.py | 134 + core/privacykit_encrypt.py | 391 +++ core/reward_request.py | 172 ++ core/reward_sign.py | 101 + core/sig.py | 37 + core/sig3.py | 357 +++ core/sig3_shape.py | 59 + core/sms_login.py | 1581 +++++++++++ core/tokensig.py | 16 + core/weapon_d0.py | 99 + core/weapon_kas.py | 47 + core/weapon_mf.py | 182 ++ core/weapon_plugin_loader.py | 217 ++ core/weapon_vimg.py | 275 ++ core/xfalcon.py | 216 ++ core/xfalcon_blake_core.py | 193 ++ core/xfalcon_te.py | 49 + docs/capture_login_chain.md | 144 + docs/ecapture_android_runbook.md | 438 +++ docs/libweapon_vimg_feasibility.md | 156 ++ docs/new_device_to_account.md | 221 ++ docs/region_ticket_static_chain.md | 161 ++ docs/sms_login_flow.md | 188 ++ .../2026-07-10-core-signing-algorithms.md | 75 + .../2026-07-11-device-profile-generation.md | 488 ++++ .../plans/2026-07-11-dfp-bootstrap.md | 600 ++++ .../plans/2026-07-11-dfp-runtime-hints.md | 41 + .../2026-07-28-captcha-session-handoff.md | 54 + ...-07-11-device-profile-generation-design.md | 131 + .../specs/2026-07-11-dfp-bootstrap-design.md | 170 ++ ...26-07-28-captcha-session-handoff-design.md | 64 + docs/weapon_kas.md | 71 + findings.md | 307 +++ main.py | 1587 +++++++++++ progress.md | 2416 +++++++++++++++++ pyproject.toml | 10 + task_plan.md | 172 ++ tests/test_analyze_region_ticket.py | 108 + tests/test_device_cookie.py | 74 + tests/test_device_id.py | 41 + tests/test_device_profile.py | 153 ++ tests/test_dfp_cache.py | 53 + tests/test_dfp_client.py | 96 + tests/test_dfp_forms.py | 74 + tests/test_dfp_knn.py | 99 + tests/test_dfp_sq0.py | 31 + tests/test_extract_app_login_fields.py | 208 ++ tests/test_extract_passport_wcfg.py | 368 +++ tests/test_h5_jsbridge.py | 73 + tests/test_h5_kws.py | 133 + tests/test_h5_kws_vm.py | 115 + tests/test_h5_kww.py | 92 + tests/test_h5_kww_alg.py | 199 ++ tests/test_h5_sig3.py | 112 + tests/test_h5_state_context.py | 131 + tests/test_http_transport.py | 133 + tests/test_ksse_crc.py | 24 + tests/test_ksse_deobf.py | 40 + tests/test_ksse_sted.py | 412 +++ tests/test_libw_pr_oracle.py | 54 + tests/test_main.py | 556 ++++ tests/test_main_device_profile.py | 1119 ++++++++ tests/test_new_device_cli.py | 40 + tests/test_new_device_dfp_cli.py | 172 ++ tests/test_privacykit_encrypt.py | 122 + tests/test_reward_request.py | 73 + tests/test_sig3_shape.py | 45 + tests/test_sms_login.py | 1207 ++++++++ tests/test_sms_login_cli.py | 238 ++ tests/test_static_passport_chain_report.py | 102 + tests/test_weapon_kas.py | 53 + tests/test_weapon_mf.py | 129 + tests/test_weapon_vimg.py | 71 + tools/_probe_fap.py | 50 + tools/_probe_pluginloader.py | 51 + tools/analyze_libweapon_ollvm.py | 619 +++++ tools/analyze_region_ticket.py | 169 ++ tools/captcha_auto_test.py | 234 ++ tools/captcha_browser_probe.py | 189 ++ tools/captcha_capture.py | 121 + tools/captcha_dom_probe.py | 114 + tools/captcha_e2e_solve.py | 147 + tools/captcha_env.py | 185 ++ tools/captcha_headed_probe.py | 142 + tools/captcha_human_drag_test.py | 175 ++ tools/captcha_inspect.py | 156 ++ tools/captcha_net.py | 174 ++ tools/captcha_solver_http.py | 545 ++++ tools/compare_login_replay.py | 251 ++ tools/dbgtap.sh | 17 + tools/deobf.py | 121 + tools/deobf2.py | 132 + tools/deobf_probe.py | 20 + tools/extract_app_login_fields.py | 476 ++++ tools/extract_captcha_flow.py | 210 ++ tools/extract_passport_wcfg.py | 538 ++++ tools/frida_attach_all_processes.ps1 | Bin 0 -> 7286 bytes tools/frida_attach_captcha_stable.ps1 | 36 + tools/frida_attach_nebula_main_stable.ps1 | 125 + tools/frida_attach_nebula_main_wcfg.ps1 | 127 + tools/frida_attach_nebula_startup_fast.ps1 | 75 + ...ida_attach_passport_wcfg_all_processes.ps1 | 20 + tools/frida_probe_passport_wcfg.js | 518 ++++ tools/frida_probe_passport_wcfg_deep.js | 602 ++++ tools/frida_probe_passport_wcfg_deep_safe.js | 636 +++++ ...frida_probe_passport_wcfg_response_safe.js | 637 +++++ tools/h5_atlas_oracle.py | 347 +++ tools/hdrag.sh | 114 + tools/hdrag2.sh | 34 + tools/jose_clean.js | 64 + tools/jose_decrypt.js | 63 + tools/jose_encrypt.js | 85 + tools/jose_encrypt_raw.js | 17 + tools/jose_probe.js | 18 + tools/jose_run.js | 92 + tools/jose_variants.js | 58 + tools/keyconfig_probe.py | 144 + tools/kws_probe.js | 232 ++ tools/libw_pr_oracle.py | 291 ++ tools/libweapon_vimg_oracle.py | 240 ++ tools/mtap.sh | 10 + tools/new_device.py | 180 ++ tools/notch_detect_test.py | 58 + tools/phone_calibrate.py | 213 ++ tools/phone_calibrate_v2.py | 185 ++ tools/phone_calibrate_v3.py | 158 ++ tools/phone_human_drag.py | 193 ++ tools/phone_human_v2.py | 158 ++ tools/phone_solve_v4.py | 157 ++ tools/phone_solve_v5.py | 152 ++ tools/phone_solve_v6.py | 166 ++ tools/phone_solve_v7.py | 162 ++ tools/phone_swipe_solve.py | 140 + tools/phone_watch_manual.py | 69 + tools/phone_watch_v2.py | 106 + tools/sms_login_cli.py | 685 +++++ tools/spoof_swipe.py | 78 + tools/static_passport_chain_report.py | 377 +++ uv.lock | 574 ++++ 183 files changed, 40652 insertions(+) create mode 100644 .claude/逆向分析.md create mode 100644 .codex/skills/逆向分析.md create mode 100644 .env.example create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 bin/kwsg_10400_T1.bin create mode 100644 bin/kwsg_10400_T2.bin create mode 100644 bin/kwsg_10418_B_T1.bin create mode 100644 bin/kwsg_10418_B_T2.bin create mode 100644 core/README.md create mode 100644 core/__init__.py create mode 100644 core/atlas_sign.py create mode 100644 core/captcha_assist.py create mode 100644 core/captured_profile.py create mode 100644 core/constants.py create mode 100644 core/device_cookie.py create mode 100644 core/device_id.py create mode 100644 core/device_profile.py create mode 100644 core/dfp_cache.py create mode 100644 core/dfp_client.py create mode 100644 core/dfp_forms.py create mode 100644 core/dfp_knn.py create mode 100644 core/dfp_sign.py create mode 100644 core/dfp_sq0.py create mode 100644 core/enc_data.py create mode 100644 core/fap_request.py create mode 100644 core/h5_jsbridge.py create mode 100644 core/h5_kws.py create mode 100644 core/h5_kws_sign.mjs create mode 100644 core/h5_kws_vm.py create mode 100644 core/h5_kww.py create mode 100644 core/h5_kww_alg.py create mode 100644 core/h5_kww_server.mjs create mode 100644 core/h5_sig3.py create mode 100644 core/h5_vendor_encode.mjs create mode 100644 core/h5_vendor_encode_server.mjs create mode 100644 core/http_transport.py create mode 100644 core/ksse_crc.py create mode 100644 core/ksse_deobf.py create mode 100644 core/ksse_sted.py create mode 100644 core/kwf-0.0.2.2cee19b4b7dec496.js create mode 100644 core/kws-11-0.0.1-obfuscated.5e0a90af726d8a7e.js create mode 100644 core/kwsg.py create mode 100644 core/main-vendor-ox-x1_g5.mjs create mode 100644 core/mobile_encrypt.py create mode 100644 core/privacykit_encrypt.py create mode 100644 core/reward_request.py create mode 100644 core/reward_sign.py create mode 100644 core/sig.py create mode 100644 core/sig3.py create mode 100644 core/sig3_shape.py create mode 100644 core/sms_login.py create mode 100644 core/tokensig.py create mode 100644 core/weapon_d0.py create mode 100644 core/weapon_kas.py create mode 100644 core/weapon_mf.py create mode 100644 core/weapon_plugin_loader.py create mode 100644 core/weapon_vimg.py create mode 100644 core/xfalcon.py create mode 100644 core/xfalcon_blake_core.py create mode 100644 core/xfalcon_te.py create mode 100644 docs/capture_login_chain.md create mode 100644 docs/ecapture_android_runbook.md create mode 100644 docs/libweapon_vimg_feasibility.md create mode 100644 docs/new_device_to_account.md create mode 100644 docs/region_ticket_static_chain.md create mode 100644 docs/sms_login_flow.md create mode 100644 docs/superpowers/plans/2026-07-10-core-signing-algorithms.md create mode 100644 docs/superpowers/plans/2026-07-11-device-profile-generation.md create mode 100644 docs/superpowers/plans/2026-07-11-dfp-bootstrap.md create mode 100644 docs/superpowers/plans/2026-07-11-dfp-runtime-hints.md create mode 100644 docs/superpowers/plans/2026-07-28-captcha-session-handoff.md create mode 100644 docs/superpowers/specs/2026-07-11-device-profile-generation-design.md create mode 100644 docs/superpowers/specs/2026-07-11-dfp-bootstrap-design.md create mode 100644 docs/superpowers/specs/2026-07-28-captcha-session-handoff-design.md create mode 100644 docs/weapon_kas.md create mode 100644 findings.md create mode 100644 main.py create mode 100644 progress.md create mode 100644 pyproject.toml create mode 100644 task_plan.md create mode 100644 tests/test_analyze_region_ticket.py create mode 100644 tests/test_device_cookie.py create mode 100644 tests/test_device_id.py create mode 100644 tests/test_device_profile.py create mode 100644 tests/test_dfp_cache.py create mode 100644 tests/test_dfp_client.py create mode 100644 tests/test_dfp_forms.py create mode 100644 tests/test_dfp_knn.py create mode 100644 tests/test_dfp_sq0.py create mode 100644 tests/test_extract_app_login_fields.py create mode 100644 tests/test_extract_passport_wcfg.py create mode 100644 tests/test_h5_jsbridge.py create mode 100644 tests/test_h5_kws.py create mode 100644 tests/test_h5_kws_vm.py create mode 100644 tests/test_h5_kww.py create mode 100644 tests/test_h5_kww_alg.py create mode 100644 tests/test_h5_sig3.py create mode 100644 tests/test_h5_state_context.py create mode 100644 tests/test_http_transport.py create mode 100644 tests/test_ksse_crc.py create mode 100644 tests/test_ksse_deobf.py create mode 100644 tests/test_ksse_sted.py create mode 100644 tests/test_libw_pr_oracle.py create mode 100644 tests/test_main.py create mode 100644 tests/test_main_device_profile.py create mode 100644 tests/test_new_device_cli.py create mode 100644 tests/test_new_device_dfp_cli.py create mode 100644 tests/test_privacykit_encrypt.py create mode 100644 tests/test_reward_request.py create mode 100644 tests/test_sig3_shape.py create mode 100644 tests/test_sms_login.py create mode 100644 tests/test_sms_login_cli.py create mode 100644 tests/test_static_passport_chain_report.py create mode 100644 tests/test_weapon_kas.py create mode 100644 tests/test_weapon_mf.py create mode 100644 tests/test_weapon_vimg.py create mode 100644 tools/_probe_fap.py create mode 100644 tools/_probe_pluginloader.py create mode 100644 tools/analyze_libweapon_ollvm.py create mode 100644 tools/analyze_region_ticket.py create mode 100644 tools/captcha_auto_test.py create mode 100644 tools/captcha_browser_probe.py create mode 100644 tools/captcha_capture.py create mode 100644 tools/captcha_dom_probe.py create mode 100644 tools/captcha_e2e_solve.py create mode 100644 tools/captcha_env.py create mode 100644 tools/captcha_headed_probe.py create mode 100644 tools/captcha_human_drag_test.py create mode 100644 tools/captcha_inspect.py create mode 100644 tools/captcha_net.py create mode 100644 tools/captcha_solver_http.py create mode 100644 tools/compare_login_replay.py create mode 100644 tools/dbgtap.sh create mode 100644 tools/deobf.py create mode 100644 tools/deobf2.py create mode 100644 tools/deobf_probe.py create mode 100644 tools/extract_app_login_fields.py create mode 100644 tools/extract_captcha_flow.py create mode 100644 tools/extract_passport_wcfg.py create mode 100644 tools/frida_attach_all_processes.ps1 create mode 100644 tools/frida_attach_captcha_stable.ps1 create mode 100644 tools/frida_attach_nebula_main_stable.ps1 create mode 100644 tools/frida_attach_nebula_main_wcfg.ps1 create mode 100644 tools/frida_attach_nebula_startup_fast.ps1 create mode 100644 tools/frida_attach_passport_wcfg_all_processes.ps1 create mode 100644 tools/frida_probe_passport_wcfg.js create mode 100644 tools/frida_probe_passport_wcfg_deep.js create mode 100644 tools/frida_probe_passport_wcfg_deep_safe.js create mode 100644 tools/frida_probe_passport_wcfg_response_safe.js create mode 100644 tools/h5_atlas_oracle.py create mode 100644 tools/hdrag.sh create mode 100644 tools/hdrag2.sh create mode 100644 tools/jose_clean.js create mode 100644 tools/jose_decrypt.js create mode 100644 tools/jose_encrypt.js create mode 100644 tools/jose_encrypt_raw.js create mode 100644 tools/jose_probe.js create mode 100644 tools/jose_run.js create mode 100644 tools/jose_variants.js create mode 100644 tools/keyconfig_probe.py create mode 100644 tools/kws_probe.js create mode 100644 tools/libw_pr_oracle.py create mode 100644 tools/libweapon_vimg_oracle.py create mode 100644 tools/mtap.sh create mode 100644 tools/new_device.py create mode 100644 tools/notch_detect_test.py create mode 100644 tools/phone_calibrate.py create mode 100644 tools/phone_calibrate_v2.py create mode 100644 tools/phone_calibrate_v3.py create mode 100644 tools/phone_human_drag.py create mode 100644 tools/phone_human_v2.py create mode 100644 tools/phone_solve_v4.py create mode 100644 tools/phone_solve_v5.py create mode 100644 tools/phone_solve_v6.py create mode 100644 tools/phone_solve_v7.py create mode 100644 tools/phone_swipe_solve.py create mode 100644 tools/phone_watch_manual.py create mode 100644 tools/phone_watch_v2.py create mode 100644 tools/sms_login_cli.py create mode 100644 tools/spoof_swipe.py create mode 100644 tools/static_passport_chain_report.py create mode 100644 uv.lock diff --git a/.claude/逆向分析.md b/.claude/逆向分析.md new file mode 100644 index 0000000..ab49624 --- /dev/null +++ b/.claude/逆向分析.md @@ -0,0 +1,550 @@ +你是一名资深逆向分析工程师,负责完成一个黑盒分析项目。 + +项目目标: + +对目标程序进行完整分析,包括: + +1. 静态分析 +2. 动态分析 +3. 保护/加固检测 +4. 脱壳与运行时恢复 +5. 算法逻辑还原 +6. 通信协议还原 + +最终输出: + +- Python纯算法实现 +- Python纯协议实现 +- 完整分析文档 + + +============================== +一、工作环境 +============================== + +工具目录: + +D:\decode-tools + + +首先扫描该目录,分析: + +- 工具列表 +- 工具版本 +- 可执行路径 +- 支持能力 +- 推荐分析流程 + + +可能使用: + +静态分析: + +- IDA Pro +- Ghidra +- Binary Ninja +- radare2 + + +动态分析: + +- Frida CLI +- Debugger + + +模拟执行: + +- Unicorn Engine +- Capstone +- Keystone + + +Android: + +- jadx +- apktool +- baksmali/smali +- frida相关工具 + + +辅助: + +- Python脚本 +- 十六进制分析工具 + + +============================== +二、目标识别与保护检测 +============================== + +首先识别目标类型: + +- APK +- DEX +- SO +- ELF +- DLL +- EXE +- 其他二进制 + + +检测: + +- 加壳 +- 加固 +- OLLVM混淆 +- 虚拟化保护 +- 动态加载 +- 内存解密 +- 字符串加密 +- 自修改代码 + + +根据结果选择分析路线: + +普通程序: + +静态分析 ++ +动态验证 + + +存在混淆: + +CFG恢复 ++ +函数还原 ++ +模拟执行 + + +存在保护: + +运行时分析 ++ +内存恢复 ++ +逻辑重建 + + +不要默认目标一定存在壳,先检测。 + + +============================== +三、静态分析 +============================== + +对目标进行完整静态分析。 + + +分析内容: + +文件: + +- 文件类型识别 +- 架构分析 + - ARM + - ARM64 + - x86 + - x64 + +模块: + +- so/dll/exe模块定位 +- 入口点分析 +- 导出符号分析 +- 导入函数分析 + + +代码: + +- 字符串分析 +- 常量分析 +- 函数定位 +- 函数调用关系分析 +- 调用图分析 +- 关键函数定位 + + +重点: + +OLLVM检测: + +- Control Flow Flattening +- Bogus Control Flow +- Instruction Substitution + + +混淆处理: + +- CFG恢复 +- 基本块分析 +- 真实控制流程恢复 +- 关键路径提取 + + +输出: + +- 模块结构 +- 函数关系 +- 可疑函数列表 +- 初步算法流程 + + +============================== +四、动态分析 +============================== + +使用: + +Frida CLI + + +环境: + +Frida 17.x + + +注意: + +Frida 17 默认 agent 无 Java 全局。 + +动态分析优先使用 Frida CLI 注入方式。 + + +连接: + +adb forward tcp:27042 tcp:27042 + + +动态分析目标: + +Hook: + +- 关键函数 +- JNI接口 +- 导出函数 +- 加密函数 +- 网络函数 +- 数据处理函数 + + +记录: + +- 输入参数 +- 输出参数 +- 返回值 +- 调用栈 +- 内存变化 +- 参数变化 + + +重点捕获: + +- 算法执行流程 +- 数据转换流程 +- 网络协议字段 + + +建立: + +输入 + +↓ + +函数调用链 + +↓ + +数据处理 + +↓ + +输出 + + +============================== +五、脱壳与运行时恢复 +============================== + +如果发现: + +- 加壳 +- 加固 +- 动态加载 +- 内存释放代码 + + +分析: + +- 真实入口 +- 加载流程 +- 解密流程 +- 代码释放位置 +- 内存中的真实模块 + + +目标: + +恢复: + +- 有效代码 +- 真实执行逻辑 +- 关键函数 + + +如果无法直接恢复文件: + +通过运行时: + +- Hook +- 跟踪 +- 输入输出分析 + +重建算法。 + + +============================== +六、加密与编码分析 +============================== + +如果存在加密/编码逻辑: + +重点分析: + + +Key: + +- Key来源 +- Key生成方式 +- Key派生流程 +- Key存储位置 + + +IV / Nonce: + +- IV来源 +- Nonce来源 +- 随机参数生成方式 + + +算法: + +- 加密模式 +- Hash算法 +- MAC算法 +- 签名算法 + + +数据处理: + +- 编解码流程 +- Base64/Hex +- 字节序 +- 数据填充 +- 参数排列方式 +- 数据拼接规则 + + +完整还原: + +输入 + +↓ + +编码 + +↓ + +加密 + +↓ + +签名 + +↓ + +发送 + + +以及: + +接收 + +↓ + +验签 + +↓ + +解密 + +↓ + +解析 + + +============================== +七、协议分析 +============================== + +还原通信协议: + +包括: + + +请求: + +{ + field:"", + value:"", + timestamp:"", + sign:"" +} + + +响应: + +{ + code:"", + data:"", + extra:"" +} + + +分析: + +- 字段含义 +- 数据类型 +- 字段长度 +- 字节序 +- 编码方式 +- 加密方式 +- 签名规则 +- 参数排序规则 + + +输出完整协议文档。 + + +============================== +八、Python实现 +============================== + +最终生成: + + +algorithm.py + +要求: + +- 纯Python +- 不依赖目标程序 +- 实现核心计算逻辑 +- 输入输出明确 + + +protocol.py + +要求: + +- 协议封装 +- 请求生成 +- 数据解析 +- 编码解码 +- 签名计算 + + +test.py + +要求: + +- 测试样例 +- 输入输出验证 +- 自动化测试 + + +代码要求: + +- 模块化 +- 注释完整 +- 保留算法推导过程 + + +============================== +九、最终报告 +============================== + +生成: + +README.md + + +包含: + +1. 项目说明 + +2. 环境配置 + +3. 工具链说明 + +4. 文件分析 + +5. 静态分析结果 + +6. 动态分析过程 + +7. 保护分析 + +8. 算法流程 + +9. 加密流程 + +10. 协议格式 + +11. Python实现说明 + +12. 测试结果 + + +============================== +执行规则 +============================== + +执行顺序: + +1. 扫描 D:\decode-tools +2. 分析目标类型 +3. 检测保护 +4. 制定分析方案 +5. 静态分析 +6. 动态分析 +7. 算法恢复 +8. 协议恢复 +9. Python实现 + + +每一步输出: + +- 当前发现 +- 分析依据 +- 下一步计划 + + +最终目标: + +得到一个完全独立运行的 Python 项目: + +输入数据 + +↓ + +Python算法 + +↓ + +Python协议 + +↓ + +输出结果 \ No newline at end of file diff --git a/.codex/skills/逆向分析.md b/.codex/skills/逆向分析.md new file mode 100644 index 0000000..ab49624 --- /dev/null +++ b/.codex/skills/逆向分析.md @@ -0,0 +1,550 @@ +你是一名资深逆向分析工程师,负责完成一个黑盒分析项目。 + +项目目标: + +对目标程序进行完整分析,包括: + +1. 静态分析 +2. 动态分析 +3. 保护/加固检测 +4. 脱壳与运行时恢复 +5. 算法逻辑还原 +6. 通信协议还原 + +最终输出: + +- Python纯算法实现 +- Python纯协议实现 +- 完整分析文档 + + +============================== +一、工作环境 +============================== + +工具目录: + +D:\decode-tools + + +首先扫描该目录,分析: + +- 工具列表 +- 工具版本 +- 可执行路径 +- 支持能力 +- 推荐分析流程 + + +可能使用: + +静态分析: + +- IDA Pro +- Ghidra +- Binary Ninja +- radare2 + + +动态分析: + +- Frida CLI +- Debugger + + +模拟执行: + +- Unicorn Engine +- Capstone +- Keystone + + +Android: + +- jadx +- apktool +- baksmali/smali +- frida相关工具 + + +辅助: + +- Python脚本 +- 十六进制分析工具 + + +============================== +二、目标识别与保护检测 +============================== + +首先识别目标类型: + +- APK +- DEX +- SO +- ELF +- DLL +- EXE +- 其他二进制 + + +检测: + +- 加壳 +- 加固 +- OLLVM混淆 +- 虚拟化保护 +- 动态加载 +- 内存解密 +- 字符串加密 +- 自修改代码 + + +根据结果选择分析路线: + +普通程序: + +静态分析 ++ +动态验证 + + +存在混淆: + +CFG恢复 ++ +函数还原 ++ +模拟执行 + + +存在保护: + +运行时分析 ++ +内存恢复 ++ +逻辑重建 + + +不要默认目标一定存在壳,先检测。 + + +============================== +三、静态分析 +============================== + +对目标进行完整静态分析。 + + +分析内容: + +文件: + +- 文件类型识别 +- 架构分析 + - ARM + - ARM64 + - x86 + - x64 + +模块: + +- so/dll/exe模块定位 +- 入口点分析 +- 导出符号分析 +- 导入函数分析 + + +代码: + +- 字符串分析 +- 常量分析 +- 函数定位 +- 函数调用关系分析 +- 调用图分析 +- 关键函数定位 + + +重点: + +OLLVM检测: + +- Control Flow Flattening +- Bogus Control Flow +- Instruction Substitution + + +混淆处理: + +- CFG恢复 +- 基本块分析 +- 真实控制流程恢复 +- 关键路径提取 + + +输出: + +- 模块结构 +- 函数关系 +- 可疑函数列表 +- 初步算法流程 + + +============================== +四、动态分析 +============================== + +使用: + +Frida CLI + + +环境: + +Frida 17.x + + +注意: + +Frida 17 默认 agent 无 Java 全局。 + +动态分析优先使用 Frida CLI 注入方式。 + + +连接: + +adb forward tcp:27042 tcp:27042 + + +动态分析目标: + +Hook: + +- 关键函数 +- JNI接口 +- 导出函数 +- 加密函数 +- 网络函数 +- 数据处理函数 + + +记录: + +- 输入参数 +- 输出参数 +- 返回值 +- 调用栈 +- 内存变化 +- 参数变化 + + +重点捕获: + +- 算法执行流程 +- 数据转换流程 +- 网络协议字段 + + +建立: + +输入 + +↓ + +函数调用链 + +↓ + +数据处理 + +↓ + +输出 + + +============================== +五、脱壳与运行时恢复 +============================== + +如果发现: + +- 加壳 +- 加固 +- 动态加载 +- 内存释放代码 + + +分析: + +- 真实入口 +- 加载流程 +- 解密流程 +- 代码释放位置 +- 内存中的真实模块 + + +目标: + +恢复: + +- 有效代码 +- 真实执行逻辑 +- 关键函数 + + +如果无法直接恢复文件: + +通过运行时: + +- Hook +- 跟踪 +- 输入输出分析 + +重建算法。 + + +============================== +六、加密与编码分析 +============================== + +如果存在加密/编码逻辑: + +重点分析: + + +Key: + +- Key来源 +- Key生成方式 +- Key派生流程 +- Key存储位置 + + +IV / Nonce: + +- IV来源 +- Nonce来源 +- 随机参数生成方式 + + +算法: + +- 加密模式 +- Hash算法 +- MAC算法 +- 签名算法 + + +数据处理: + +- 编解码流程 +- Base64/Hex +- 字节序 +- 数据填充 +- 参数排列方式 +- 数据拼接规则 + + +完整还原: + +输入 + +↓ + +编码 + +↓ + +加密 + +↓ + +签名 + +↓ + +发送 + + +以及: + +接收 + +↓ + +验签 + +↓ + +解密 + +↓ + +解析 + + +============================== +七、协议分析 +============================== + +还原通信协议: + +包括: + + +请求: + +{ + field:"", + value:"", + timestamp:"", + sign:"" +} + + +响应: + +{ + code:"", + data:"", + extra:"" +} + + +分析: + +- 字段含义 +- 数据类型 +- 字段长度 +- 字节序 +- 编码方式 +- 加密方式 +- 签名规则 +- 参数排序规则 + + +输出完整协议文档。 + + +============================== +八、Python实现 +============================== + +最终生成: + + +algorithm.py + +要求: + +- 纯Python +- 不依赖目标程序 +- 实现核心计算逻辑 +- 输入输出明确 + + +protocol.py + +要求: + +- 协议封装 +- 请求生成 +- 数据解析 +- 编码解码 +- 签名计算 + + +test.py + +要求: + +- 测试样例 +- 输入输出验证 +- 自动化测试 + + +代码要求: + +- 模块化 +- 注释完整 +- 保留算法推导过程 + + +============================== +九、最终报告 +============================== + +生成: + +README.md + + +包含: + +1. 项目说明 + +2. 环境配置 + +3. 工具链说明 + +4. 文件分析 + +5. 静态分析结果 + +6. 动态分析过程 + +7. 保护分析 + +8. 算法流程 + +9. 加密流程 + +10. 协议格式 + +11. Python实现说明 + +12. 测试结果 + + +============================== +执行规则 +============================== + +执行顺序: + +1. 扫描 D:\decode-tools +2. 分析目标类型 +3. 检测保护 +4. 制定分析方案 +5. 静态分析 +6. 动态分析 +7. 算法恢复 +8. 协议恢复 +9. Python实现 + + +每一步输出: + +- 当前发现 +- 分析依据 +- 下一步计划 + + +最终目标: + +得到一个完全独立运行的 Python 项目: + +输入数据 + +↓ + +Python算法 + +↓ + +Python协议 + +↓ + +输出结果 \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..7214e12 --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +KS_ACCOUNT=大号#kpn=NEBULA; kpf=ANDROID_PHONE; userId=...; did=...; kuaishou.api_st=...; token=...; client_key=2ac2a76d#client_salt +KS_AD_COUNT=1 +KS_TREASURE_AD_COUNT=1 +KS_DELAY_SECONDS=1 +KS_TIMEOUT=30 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f24294e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +* text=auto eol=lf + +*.bat text eol=crlf +*.cmd text eol=crlf +*.ps1 text eol=crlf + +*.bin binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..29309c8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,44 @@ +# 本地配置与凭据 +.env +.env.* +!.env.example + +# Python 环境与缓存 +.venv/ +venv/ +__pycache__/ +*.py[cod] +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +.coverage +htmlcov/ + +# 编辑器与系统文件 +.idea/ +.vscode/ +.DS_Store +Thumbs.db + +# 运行输出与抓包目录 +out/ +capture/ +capture-*/ +ecapture/ + +# 大体积样本、流量与日志产物 +*.apk +*.apks +*.xapk +*.rar +*.zip +*.har +*.pcap +*.pcapng +*.log +*.pid + +# 根目录临时分析输出 +/_dec_*.txt +/*-ddecode-*.txt +/1.txt diff --git a/bin/kwsg_10400_T1.bin b/bin/kwsg_10400_T1.bin new file mode 100644 index 0000000000000000000000000000000000000000..b0774d974e19e3d2c7caffd3a395b25a8a289134 GIT binary patch literal 147456 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 literal 0 HcmV?d00001 diff --git a/bin/kwsg_10418_B_T1.bin b/bin/kwsg_10418_B_T1.bin new file mode 100644 index 0000000000000000000000000000000000000000..0615d23019c4d91683a7b9be621b030f57062dd4 GIT binary patch literal 147456 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 z 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 deviceid/i.e() -> ss9/a.b`,公共参数 +`q01/g.getODid()` 最终读取 `ss9.a.b`。后续云端刷新 `did` 时只更新 +`ss9.a.a`,不会覆盖 `ss9.a.b`。 + +`egid` 链路当前已拆到: + +```text +DFP lite kNN -> sq0.b -> core.enc_data.kwsg_10400_raw(deviceInfo) +DFP form -> core.dfp_sign.dfp_atlas_sign(sign) +``` + +`10405 atlasSign` 与已还原的 `10418` sign 分支共用 +`innerFlag=true` digest 管线;区别主要在输入字符串由 DFP Java builder +决定。`core.dfp_sign` 固化了 `gdfp_report`、`unified_log_report`、 +`unified_id_mapping`、`unified_repair/fetch/checkRepair` 的输入拼接规则。 diff --git a/core/__init__.py b/core/__init__.py new file mode 100644 index 0000000..97d2052 --- /dev/null +++ b/core/__init__.py @@ -0,0 +1,40 @@ +"""Recovered signing/encryption algorithms exposed as focused modules. + +Import from focused modules such as `core.sig`, `core.sig3`, `core.xfalcon`, +`core.enc_data`, and `core.tokensig`. Runtime sample values are in +`core.captured_profile`. The package initializer intentionally +does not import algorithm modules eagerly so CLI entrypoints can run cleanly. +""" + +from .device_profile import ( + DeviceProfile, + DeviceProfileGenerator, + load_device_profile, + save_device_profile, +) + +__all__ = [ + "DeviceProfile", + "DeviceProfileGenerator", + "load_device_profile", + "save_device_profile", + "device_id", + "device_profile", + "dfp_forms", + "dfp_cache", + "dfp_knn", + "dfp_sq0", + "sig", + "tokensig", + "sig3", + "sig3_shape", + "h5_sig3", + "ksse_sted", + "xfalcon", + "enc_data", + "mobile_encrypt", + "privacykit_encrypt", + "reward_sign", + "constants", + "captured_profile", +] diff --git a/core/atlas_sign.py b/core/atlas_sign.py new file mode 100644 index 0000000..335f529 --- /dev/null +++ b/core/atlas_sign.py @@ -0,0 +1,26 @@ +"""Generic KWSG atlasSign helpers for 24-byte digest envelopes. + +`MXSec.atlasSign` returns the short ZT form: + + head8 + xor16(24-byte digest) + +The recovered 10418 reward body sign and DFP 10405 atlasSign samples share this +envelope and the same `innerFlag=true` digest pipeline. +""" + +from __future__ import annotations + +from .reward_sign import ( + KWSG_10418_SIGN_HMAC_KEY as ATLAS_SIGN_HMAC_KEY, + kwsg_10418_reward_sign as atlas_sign, + kwsg_10418_reward_sign_from_digest_hex as atlas_sign_from_digest_hex, + kwsg_10418_reward_sign_to_digest_hex as atlas_sign_to_digest_hex, +) + + +__all__ = [ + "ATLAS_SIGN_HMAC_KEY", + "atlas_sign", + "atlas_sign_from_digest_hex", + "atlas_sign_to_digest_hex", +] diff --git a/core/captcha_assist.py b/core/captcha_assist.py new file mode 100644 index 0000000..f213e1d --- /dev/null +++ b/core/captcha_assist.py @@ -0,0 +1,633 @@ +from __future__ import annotations + +import os +import shutil +import socket +import subprocess +import tempfile +import time +import urllib.request +from dataclasses import dataclass +from pathlib import Path +from typing import Any, Callable, Iterable, Mapping +from urllib.parse import urlsplit + +from .device_cookie import device_profile_cookie_fields +from .device_profile import DeviceProfile + + +KSECRET_VERIFY_PATH = "/rest/zt/captcha/sliding/kSecretApiVerify" +CAPTCHA_BIND_PATH = "/rest/wd/captcha/verify" + + +def _find_captcha_token(value: Any) -> str: + if isinstance(value, Mapping): + for key, item in value.items(): + if str(key).lower() in {"captchatoken", "captcha_token"}: + token = str(item or "").strip() + if token: + return token + for item in value.values(): + token = _find_captcha_token(item) + if token: + return token + elif isinstance(value, (list, tuple)): + for item in value: + token = _find_captcha_token(item) + if token: + return token + return "" + + +def _verify_result(payload: Any) -> int | None: + if not isinstance(payload, Mapping): + return None + value = payload.get("result") + if value is None and isinstance(payload.get("data"), Mapping): + value = payload["data"].get("result") + try: + return int(value) if value is not None else None + except (TypeError, ValueError): + return None + + +@dataclass +class CaptchaVerificationState: + captcha_token: str = "" + verify_result: int | None = None + verify_status: int = 0 + verified: bool = False + + def observe( + self, + url: str, + payload: Any, + *, + status: int, + request_payload: Mapping[str, Any] | None = None, + ) -> None: + path = urlsplit(url).path + if path == KSECRET_VERIFY_PATH and 200 <= status < 300: + token = _find_captcha_token(payload) + if token: + self.captcha_token = token + return + + if path != CAPTCHA_BIND_PATH: + return + self.verify_status = int(status) + self.verify_result = _verify_result(payload) + self.verified = 200 <= status < 300 and self.verify_result == 1 + if self.verified and request_payload: + bound_token = str(request_payload.get("input") or "").strip() + if bound_token: + self.captcha_token = bound_token + + +@dataclass +class CaptchaBrowserResult: + verified: bool = False + captcha_token: str = "" + verify_result: int | None = None + verify_status: int = 0 + cookies_synced: int = 0 + browser_did: str = "" + identity_matched: bool = True + error: str = "" + + +def build_captcha_browser_cookies(profile: DeviceProfile) -> list[dict[str, Any]]: + """按 APP WebView 注入顺序准备验证码页所需的匿名设备身份。""" + fields = device_profile_cookie_fields(profile) + values = { + "kpn": "NEBULA", + "kpf": "ANDROID_PHONE", + "userId": "0", + "did": fields["did"], + "didv": str(profile.install_time_ms), + "c": fields["c"], + "ver": fields["ver"], + "appver": fields["appver"], + "language": "zh-cn", + "countryCode": fields["countryCode"], + "sys": fields["sys"], + "mod": fields["mod"], + "deviceName": fields["deviceName"], + "net": "WIFI", + "client_key": "2ac2a76d", + "os": "android", + } + return [ + { + "name": name, + "value": value, + "domain": ".kuaishou.com", + "path": "/", + "secure": True, + "httpOnly": False, + "sameSite": "Lax", + } + for name, value in values.items() + if value + ] + + +def sync_browser_cookies(session: Any, cookies: Iterable[Mapping[str, Any]]) -> int: + count = 0 + for cookie in cookies: + name = str(cookie.get("name") or "").strip() + if not name: + continue + value = str(cookie.get("value") or "") + kwargs: dict[str, Any] = { + "path": str(cookie.get("path") or "/"), + "secure": bool(cookie.get("secure", False)), + } + domain = str(cookie.get("domain") or "").strip() + if domain: + kwargs["domain"] = domain + expires = cookie.get("expires") + if isinstance(expires, (int, float)) and expires > 0: + kwargs["expires"] = int(expires) + session.cookies.set(name, value, **kwargs) + count += 1 + return count + + +CaptchaBrowserDriver = Callable[..., list[Mapping[str, Any]]] + + +def _response_request_payload(response: Any) -> Mapping[str, Any] | None: + request = getattr(response, "request", None) + if request is None: + return None + try: + payload = request.post_data_json + except Exception: + payload = None + if isinstance(payload, Mapping): + return payload + try: + raw = request.post_data + except Exception: + raw = None + if not raw: + return None + try: + import json + + payload = json.loads(raw) + except (TypeError, ValueError): + return None + return payload if isinstance(payload, Mapping) else None + + +def _update_captcha_assets(response: Any, assets: dict[str, Any]) -> None: + """从 bg/cut/config 响应里抽字节, 供自动求解器喂 ddddocr。""" + try: + url = str(response.url) + except Exception: + return + if "/sliding/bgPic" in url: + try: + assets["bg"] = response.body() + except Exception: + pass + elif "/sliding/cutPic" in url: + try: + assets["cut"] = response.body() + except Exception: + pass + elif "/sliding/config" in url: + try: + data = response.json() + if isinstance(data, Mapping): + assets["config"].update(data) + except Exception: + pass + + +def _wait_captcha_assets(page: Any, assets: dict[str, Any], *, timeout: int) -> None: + deadline = time.monotonic() + max(2, min(int(timeout), 20)) + while not (assets["bg"] and assets["cut"] and assets["config"].get("bgPicWidth")): + if time.monotonic() >= deadline: + raise TimeoutError("等待验证码 bg/cut/config 图片超时") + page.wait_for_timeout(200) + + +def _human_drag(page: Any, x0: float, y0: float, dx: float, *, seed: int | None = None) -> None: + """拟人拖动: 余弦缓动 + 垂直微抖 + 小幅过冲后回正。""" + import math + import random + + rnd = random.Random(seed) + page.mouse.move(x0, y0) + page.wait_for_timeout(rnd.randint(120, 260)) + page.mouse.down() + steps, total_ms = 44, 820 + peak = dx + rnd.uniform(3.0, 9.0) + base = total_ms / steps + for i in range(1, steps + 1): + t = i / steps + ease = 0.5 * (1 - math.cos(math.pi * t)) + xi = x0 + peak * ease + yi = y0 + rnd.uniform(-2.0, 2.0) + page.mouse.move(xi, yi) + page.wait_for_timeout(int(base) + rnd.randint(0, 9)) + for j in range(1, 7): # 过冲后回正到 dx + t = j / 6 + xi = x0 + peak + (dx - peak) * t + page.mouse.move(xi, y0 + rnd.uniform(-1.5, 1.5)) + page.wait_for_timeout(rnd.randint(14, 26)) + page.wait_for_timeout(rnd.randint(90, 180)) + page.mouse.up() + + +def _auto_solve_slider( + page: Any, + assets: dict[str, Any], + *, + timeout: int = 20, + offset: int = -48, +) -> None: + """在 captcha iframe 内: ddddocr 定缺口 + 拟人拖 slider-btn。 + + 几何全用 bounding_box() (自动换算到外层视口坐标, 与 page.mouse 一致), + scale = 显示宽 / config.bgPicWidth(原生)。offset 为对 target_x 的原生像素修正。 + + offset=-48 为本验证码的经验常量偏置: ddddocr 的 target_x 系统性偏右(拼图块模板 + 在其图像内有固定左内缩), 实测多张新鲜图 -48 均使 kSecretApiVerify result=1。 + 扫描偏置时可显式传 offset 覆盖(见 tools/captcha_auto_test.py)。 + """ + import ddddocr + + frame = None + for fr in page.frames: + if fr is not page.main_frame and "captcha" in fr.url: + frame = fr + break + if frame is None: + raise RuntimeError("未找到 captcha iframe") + + frame.locator(".slider-btn").wait_for(state="visible", timeout=timeout * 1000) + bg_box = frame.locator("img[src*='bgPic']").bounding_box() + cut_box = frame.locator("img[src*='cutPic']").bounding_box() + btn_box = frame.locator(".slider-btn").bounding_box() + if not (bg_box and cut_box and btn_box): + raise RuntimeError( + f"滑块几何缺失 bg={bool(bg_box)} cut={bool(cut_box)} btn={bool(btn_box)}" + ) + + native_w = int(assets["config"].get("bgPicWidth") or 686) + scale = bg_box["width"] / native_w + det = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False) + res = det.slide_match(assets["cut"], assets["bg"]) + target_x = res.get("target_x") or (res.get("target") or [0])[0] + # 缺口在视口里的真实 x = 背景图左边沿(bg_box.x) + 原生缺口 x * 缩放; + # 拼图块需从其 home(cut_box.x) 移到该 x, 按钮与块 1:1 联动 -> drag 即为该差值。 + # (早先漏了 bg_box.x 项, 块每次都落在 bg 左内缩 ~67px 处 -> 恒 350002) + gap_viewport_x = bg_box["x"] + (target_x + offset) * scale + drag = gap_viewport_x - cut_box["x"] + print( + f"[auto-captcha] target_x={target_x} offset={offset} scale={scale:.4f} " + f"gap_vp={gap_viewport_x:.1f} cut_x={cut_box['x']:.1f} drag={drag:.1f}" + ) + + _human_drag( + page, + btn_box["x"] + btn_box["width"] / 2, + btn_box["y"] + btn_box["height"] / 2, + drag, + ) + + # mouseup 后、verify+复位前 立刻读一次拼图块真实落点(竞态窗口约 100-300ms)。 + landed_x = None + try: + landed_box = frame.locator("img[src*='cutPic']").bounding_box() + if landed_box: + landed_x = landed_box["x"] + delta = landed_x - gap_viewport_x + print( + f"[auto-captcha] landed cut_x={landed_x:.1f} " + f"vs gap_vp={gap_viewport_x:.1f} (Δ={delta:+.1f}px)" + ) + except Exception: + pass + return { + "target_x": target_x, + "gap_vp": gap_viewport_x, + "landed_x": landed_x, + "drag": drag, + } + + +def _find_system_chromium() -> str: + candidates = [os.environ.get("KS_CAPTCHA_BROWSER", "")] + for command in ("msedge", "msedge.exe", "chrome", "chrome.exe", "chromium"): + candidates.append(shutil.which(command) or "") + + if os.name == "nt": + for root_name, suffix in ( + ("ProgramFiles(x86)", "Microsoft/Edge/Application/msedge.exe"), + ("ProgramFiles", "Microsoft/Edge/Application/msedge.exe"), + ("LOCALAPPDATA", "Microsoft/Edge/Application/msedge.exe"), + ("ProgramFiles", "Google/Chrome/Application/chrome.exe"), + ("ProgramFiles(x86)", "Google/Chrome/Application/chrome.exe"), + ("LOCALAPPDATA", "Google/Chrome/Application/chrome.exe"), + ): + root = os.environ.get(root_name, "") + if root: + candidates.append(str(Path(root) / suffix)) + + for candidate in candidates: + if candidate and Path(candidate).is_file(): + return str(Path(candidate)) + raise RuntimeError("未找到系统 Edge/Chrome;可用 KS_CAPTCHA_BROWSER 指定浏览器路径") + + +def _free_local_port() -> int: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.bind(("127.0.0.1", 0)) + return int(sock.getsockname()[1]) + + +def _wait_for_cdp_endpoint(port: int, *, timeout: int) -> str: + endpoint = f"http://127.0.0.1:{port}" + deadline = time.monotonic() + max(1, min(int(timeout), 15)) + while time.monotonic() < deadline: + try: + with urllib.request.urlopen(f"{endpoint}/json/version", timeout=0.5) as response: + if int(getattr(response, "status", 0) or 0) == 200: + return endpoint + except Exception: + time.sleep(0.1) + raise TimeoutError("系统浏览器 DevTools 端口启动超时") + + +def _run_system_browser_challenge( + error_url: str, + observer: Callable[..., bool], + *, + timeout: int, + channel: str, + initial_cookies: Iterable[Mapping[str, Any]], + auto_solve: bool = False, +) -> list[Mapping[str, Any]]: + try: + from playwright.sync_api import sync_playwright + except ImportError as exc: + raise RuntimeError("Playwright 未安装,请先执行 uv sync") from exc + + browser_path = _find_system_chromium() + port = _free_local_port() + profile_dir = tempfile.mkdtemp(prefix="ksjsb-captcha-") + process: subprocess.Popen[bytes] | None = None + browser: Any = None + done = False + assets: dict[str, Any] = {"config": {}, "bg": b"", "cut": b""} + + def on_response(response: Any) -> None: + nonlocal done + _update_captcha_assets(response, assets) + try: + payload = response.json() + except Exception: + return + done = bool( + observer( + response.url, + payload, + status=int(response.status), + request_payload=_response_request_payload(response), + ) + ) or done + + try: + process = subprocess.Popen( + [ + browser_path, + f"--remote-debugging-port={port}", + "--remote-debugging-address=127.0.0.1", + f"--user-data-dir={profile_dir}", + "--no-first-run", + "--no-default-browser-check", + "--disable-background-mode", + "--window-size=430,920", + "about:blank", + ], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + endpoint = _wait_for_cdp_endpoint(port, timeout=timeout) + with sync_playwright() as playwright: + browser = playwright.chromium.connect_over_cdp( + endpoint, + timeout=max(1, min(int(timeout), 30)) * 1000, + ) + if not browser.contexts: + raise RuntimeError("系统浏览器没有可用上下文") + context = browser.contexts[0] + context.add_cookies(list(initial_cookies)) + page = context.pages[0] if context.pages else context.new_page() + page.on("response", on_response) + page.goto( + error_url, + wait_until="domcontentloaded", + timeout=max(1, min(int(timeout), 30)) * 1000, + ) + page.bring_to_front() + if auto_solve: + _wait_captcha_assets(page, assets, timeout=timeout) + _auto_solve_slider(page, assets, timeout=timeout) + deadline = time.monotonic() + max(1, int(timeout)) + while not done: + if page.is_closed(): + raise RuntimeError("验证页已关闭,尚未观察到绑定成功响应") + if time.monotonic() >= deadline: + raise TimeoutError(f"等待验证码绑定超时({timeout}s)") + page.wait_for_timeout(250) + return list(context.cookies()) + finally: + if browser is not None: + try: + browser.close() + except Exception: + pass + if process is not None and process.poll() is None: + process.terminate() + try: + process.wait(timeout=3) + except subprocess.TimeoutExpired: + process.kill() + shutil.rmtree(profile_dir, ignore_errors=True) + + +def _run_playwright_challenge( + error_url: str, + observer: Callable[..., bool], + *, + timeout: int, + channel: str, + initial_cookies: Iterable[Mapping[str, Any]], + auto_solve: bool = False, +) -> list[Mapping[str, Any]]: + try: + from playwright.sync_api import sync_playwright + except ImportError as exc: + raise RuntimeError("Playwright 未安装,请先执行 uv sync") from exc + + done = False + assets: dict[str, Any] = {"config": {}, "bg": b"", "cut": b""} + + def on_response(response: Any) -> None: + nonlocal done + _update_captcha_assets(response, assets) + try: + payload = response.json() + except Exception: + return + done = bool( + observer( + response.url, + payload, + status=int(response.status), + request_payload=_response_request_payload(response), + ) + ) or done + + with sync_playwright() as playwright: + launch_args: dict[str, Any] = {"headless": False} + if channel: + launch_args["channel"] = channel + browser = playwright.chromium.launch(**launch_args) + try: + context = browser.new_context( + viewport={"width": 400, "height": 900}, + screen={"width": 400, "height": 900}, + device_scale_factor=2, + is_mobile=True, + locale="zh-CN", + ) + context.add_cookies(list(initial_cookies)) + page = context.new_page() + page.on("response", on_response) + page.goto( + error_url, + wait_until="domcontentloaded", + timeout=max(1, min(int(timeout), 30)) * 1000, + ) + if auto_solve: + _wait_captcha_assets(page, assets, timeout=timeout) + _auto_solve_slider(page, assets, timeout=timeout) + deadline = time.monotonic() + max(1, int(timeout)) + while not done: + if page.is_closed(): + raise RuntimeError("验证页已关闭,尚未观察到绑定成功响应") + if time.monotonic() >= deadline: + raise TimeoutError(f"等待验证码绑定超时({timeout}s)") + page.wait_for_timeout(250) + return list(context.cookies()) + finally: + browser.close() + + +def complete_captcha_in_browser( + error_url: str, + session: Any, + *, + timeout: int = 180, + channel: str = "msedge", + browser_driver: CaptchaBrowserDriver | None = None, + initial_cookies: Iterable[Mapping[str, Any]] = (), + expected_did: str = "", + auto_solve: bool = False, +) -> CaptchaBrowserResult: + parsed = urlsplit(error_url) + if parsed.scheme != "https" or not parsed.netloc: + return CaptchaBrowserResult(error="验证码地址必须是有效的 HTTPS URL") + + state = CaptchaVerificationState() + + def observe( + url: str, + payload: Any, + *, + status: int, + request_payload: Mapping[str, Any] | None = None, + ) -> bool: + state.observe( + url, + payload, + status=status, + request_payload=request_payload, + ) + return state.verified + + if browser_driver is not None: + driver = browser_driver + elif str(channel or "").strip().lower() == "system": + driver = _run_system_browser_challenge + else: + driver = _run_playwright_challenge + try: + cookies = driver( + error_url, + observe, + timeout=max(1, int(timeout)), + channel=str(channel or ""), + initial_cookies=list(initial_cookies), + auto_solve=bool(auto_solve), + ) + except Exception as exc: # noqa: BLE001 + return CaptchaBrowserResult( + captcha_token=state.captcha_token, + verify_result=state.verify_result, + verify_status=state.verify_status, + error=f"{exc.__class__.__name__}: {exc}", + ) + + browser_dids = { + str(cookie.get("value") or "").strip() + for cookie in cookies + if str(cookie.get("name") or "").strip() == "did" + and str(cookie.get("value") or "").strip() + } + browser_did = ( + next(iter(browser_dids), "") + if len(browser_dids) == 1 + else ",".join(sorted(browser_dids)) + ) + identity_matched = not expected_did or browser_dids == {expected_did} + if state.verified and not identity_matched: + actual = browser_did or "" + return CaptchaBrowserResult( + captcha_token=state.captcha_token, + verify_result=state.verify_result, + verify_status=state.verify_status, + browser_did=browser_did, + identity_matched=False, + error=f"验证码浏览器 DID 不一致: expected={expected_did} actual={actual}", + ) + + cookies_synced = sync_browser_cookies(session, cookies) if state.verified else 0 + return CaptchaBrowserResult( + verified=state.verified, + captcha_token=state.captcha_token, + verify_result=state.verify_result, + verify_status=state.verify_status, + cookies_synced=cookies_synced, + browser_did=browser_did, + identity_matched=identity_matched, + error="" if state.verified else "未观察到验证码绑定成功响应", + ) + + +__all__ = [ + "CAPTCHA_BIND_PATH", + "KSECRET_VERIFY_PATH", + "CaptchaBrowserResult", + "CaptchaVerificationState", + "build_captcha_browser_cookies", + "complete_captcha_in_browser", + "sync_browser_cookies", +] diff --git a/core/captured_profile.py b/core/captured_profile.py new file mode 100644 index 0000000..f89b9da --- /dev/null +++ b/core/captured_profile.py @@ -0,0 +1,64 @@ +"""Captured local runtime profile values. + +These values are not algorithm constants: + +- `CLIENT_SALT` is account/login-state bound. +- `API_ST` is session/login-state bound. +- `DID`, `ODID`, `RDID`, and `EGID` are device/runtime bound. + +Keep callers explicit about using this captured profile so the algorithms can +be reused with another account/device by replacing the profile. +""" + +from __future__ import annotations + +from dataclasses import dataclass + + +@dataclass(frozen=True) +class CapturedProfile: + client_salt: str + api_st: str + did: str + odid: str + rdid: str + egid: str + client_key: str + + +CLIENT_SALT = "b038748080d4cbca37c31dd04ab28347" +API_ST = ( + "Cg9rdWFpc2hvdS5hcGkuc3QSoAHruwqKqtHqy9AfyGdOFYNACJ80v0TMYoQNeZ1INbsRZo94r6mt9M" + "58VJZX5pNQUix3Euqtsf8W3AOaWRCH_NWklCNumaTQFy6hxrZi8lp3y7p68SIxs6fYL1y17X--7xRAo" + "ICgzoB_nnFNrlkpZfFWeNb7v06hjOgbXg9-jKghvz7ynDibTmweN-saijRFyrmdG-hkspXD06BN_HdM" + "gjolGhJmQmJkX-pJEqgjQbtJv1UuVkwiIBjICjT6OhpE1pECamctILXHVG8-uA3qXY0e0wjkxe0RKAUwAQ" +) +DID = "ANDROID_e8dfd2f16b618053" +ODID = "ANDROID_46a032e0a2af8184" +RDID = "ANDROID_741de4351c44850d" +EGID = "DFPD710405C930763A0611ED55B32863566E86B8C7D3438B8BDE60EAB9F54037" +CLIENT_KEY = "2ac2a76d" + + +CAPTURED_PROFILE = CapturedProfile( + client_salt=CLIENT_SALT, + api_st=API_ST, + did=DID, + odid=ODID, + rdid=RDID, + egid=EGID, + client_key=CLIENT_KEY, +) + + +__all__ = [ + "API_ST", + "CAPTURED_PROFILE", + "CLIENT_KEY", + "CLIENT_SALT", + "CapturedProfile", + "DID", + "EGID", + "ODID", + "RDID", +] diff --git a/core/constants.py b/core/constants.py new file mode 100644 index 0000000..305646a --- /dev/null +++ b/core/constants.py @@ -0,0 +1,14 @@ +"""Static algorithm constants. + +Runtime profile values such as `did`, `egid`, `api_st`, and token client salt +are intentionally kept out of this module. Use `core.captured_profile` for the +currently captured local sample values. +""" + +from .sig import SIG_SALT + + +REWARD_SDK = "95147564-9763-4413-a937-6f0e3c12caf1" + + +__all__ = ["REWARD_SDK", "SIG_SALT"] diff --git a/core/device_cookie.py b/core/device_cookie.py new file mode 100644 index 0000000..37e0381 --- /dev/null +++ b/core/device_cookie.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +from .device_profile import DeviceProfile + + +def _density_dpi(profile: DeviceProfile) -> str: + return str(int(round(profile.screen_density * 160))) + + +def _model_name(profile: DeviceProfile) -> str: + return f"{profile.manufacturer}({profile.model})" + + +def device_profile_cookie_fields(profile: DeviceProfile) -> dict[str, str]: + model_name = _model_name(profile) + return { + "did": profile.did, + "oDid": profile.o_did, + "rdid": profile.rdid, + "egid": profile.egid, + "oaid": profile.runtime_hints.oaid, + "cdid_tag": str(profile.cdid_tag), + "did_tag": "0", + "appver": profile.app_version, + "ver": ".".join(profile.app_version.split(".")[:2]), + "sys": f"ANDROID_{profile.android_release}", + "androidApiLevel": "36" if profile.android_release == "16" else profile.android_release, + "mod": model_name, + "deviceName": model_name, + "c": profile.brand, + "oc": profile.brand, + "newOc": profile.brand, + "isp": profile.isp, + "country_code": profile.country_code, + "countryCode": profile.country_code.upper(), + "sid": profile.sid, + "cold_launch_time_ms": str(profile.cold_launch_time_ms), + "did_gt": profile.runtime_hints.did_gt or str(profile.install_time_ms), + "boardPlatform": profile.board_platform, + "socName": profile.soc_name, + "max_memory": str(profile.max_memory), + "deviceBit": profile.device_bit, + "sw": str(profile.screen_width), + "sh": str(profile.screen_height), + "sbh": str(profile.status_bar_height), + "ddpi": _density_dpi(profile), + "totalMemory": str(profile.total_memory_mb), + "abi": "arm64", + "device_abi": "arm64", + } + + +def apply_device_profile_to_cookie( + cookie: dict[str, str], + profile: DeviceProfile, +) -> dict[str, str]: + out = dict(cookie) + out.update(device_profile_cookie_fields(profile)) + if "ud" not in out and "userId" in out: + out["ud"] = out["userId"] + return out + + +def cookie_to_string(cookie: dict[str, str]) -> str: + return "; ".join(f"{key}={value}" for key, value in cookie.items()) + + +__all__ = [ + "apply_device_profile_to_cookie", + "cookie_to_string", + "device_profile_cookie_fields", +] diff --git a/core/device_id.py b/core/device_id.py new file mode 100644 index 0000000..2b39d31 --- /dev/null +++ b/core/device_id.py @@ -0,0 +1,148 @@ +"""Device identifier helpers recovered from APK static analysis. + +This module covers the local identifier formatting/derivation that is visible +in the Java layer. For offline simulation we also expose a deterministic +synthetic EGID candidate. That candidate is not the exact DFP VM algorithm; +online DFP bootstrap can still replace it when a server-issued value exists. + +`oDid` is not a separate visible hash algorithm in the Java layer. The app +initializes it from the same local did reader before cloud DID refresh, then +keeps it as the "old/original DID" field. +""" + +from __future__ import annotations + +import hashlib +import re +import secrets +from collections.abc import Iterable + + +ANDROID_PREFIX = "ANDROID_" +HEX16_RE = re.compile(r"^[0-9a-fA-F]{16}$") +ANDROID_ID_RE = re.compile(r"^ANDROID_[0-9a-fA-F]{16}$") +EGID_RE = re.compile(r"^DFP[0-9A-F]{61}$") +OAID_RE = re.compile(r"^[0-9A-F]{64}$") + + +def java_long_hex16(value: int) -> str: + """Mirror `Long.toHexString(value)` constrained to 16 hex chars.""" + + return f"{value & ((1 << 64) - 1):016x}"[-16:] + + +def java_signed_int_to_long_hex16(value: int) -> str: + """Mirror Java `int -> long -> Long.toHexString()` for fallback rdid.""" + + value &= 0xFFFFFFFF + if value & 0x80000000: + value -= 0x100000000 + return java_long_hex16(value) + + +def normalize_android_suffix(value: str) -> str: + suffix = value[len(ANDROID_PREFIX) :] if value.startswith(ANDROID_PREFIX) else value + if not HEX16_RE.fullmatch(suffix): + raise ValueError(f"expected 16 hex chars, got {value!r}") + return suffix.lower() + + +def format_android_id(suffix: str) -> str: + return ANDROID_PREFIX + normalize_android_suffix(suffix) + + +def did_from_android_id(android_id: str) -> str: + """Model deviceid/i.l(): valid system android_id -> `ANDROID_`.""" + + return format_android_id(android_id) + + +def did_from_random_long(value: int | None = None) -> str: + """Model deviceid/i.a(): Random.nextLong() -> padded 16-hex suffix.""" + + if value is None: + value = secrets.randbits(64) + return ANDROID_PREFIX + java_long_hex16(value) + + +def odid_from_local_did(local_did: str) -> str: + """Model AppEnv.O_DID: original local DID retained before cloud refresh.""" + + return format_android_id(local_did) + + +def rdid_from_gRdi2(rom_id: str) -> str: + """Model deviceid/i.n(): md5(gRdi2())[16:32] -> `ANDROID_`.""" + + digest = hashlib.md5(rom_id.encode("utf-8")).hexdigest() + return ANDROID_PREFIX + digest[16:32] + + +def rdid_from_random_int(value: int | None = None) -> str: + """Model deviceid/i.b(): SecureRandom.nextInt() fallback.""" + + if value is None: + value = secrets.randbits(32) + return ANDROID_PREFIX + java_signed_int_to_long_hex16(value) + + +def is_android_device_id(value: str) -> bool: + return bool(ANDROID_ID_RE.fullmatch(value)) + + +def is_valid_egid(value: str) -> bool: + """Validate the Java callback constraint: prefix `DFP`, total len 64.""" + + return bool(EGID_RE.fullmatch(value)) + + +def is_valid_oaid(value: str) -> bool: + """Validate the uppercase 64-hex OAID shape used in task/deviceInfo fields.""" + + return bool(OAID_RE.fullmatch(value)) + + +def egid_from_seed_material(parts: Iterable[object]) -> str: + """Build a stable offline EGID candidate from local device seed material. + + Runtime evidence only exposes the Java callback constraint (`DFP` prefix, + 64 chars total). The real DFP value is produced by the KSecurity/DFP + native flow. This helper keeps generated profiles self-consistent without + depending on APP/RPC/online bootstrap, while preserving the same public + shape for cookie/deviceInfo testing. + """ + + payload = "\x1f".join("" if item is None else str(item) for item in parts) + digest = hashlib.sha512(("ksjsb.egid.v1\x00" + payload).encode("utf-8")).hexdigest().upper() + return "DFP" + digest[:61] + + +def oaid_from_seed_material(parts: Iterable[object]) -> str: + """Build a stable offline OAID candidate from local device seed material. + + The current task chain consumes OAID as a public 64-char uppercase hex + device field. This keeps generated profiles reproducible without + depending on a vendor OAID service call. + """ + + payload = "\x1f".join("" if item is None else str(item) for item in parts) + return hashlib.sha256(("ksjsb.oaid.v1\x00" + payload).encode("utf-8")).hexdigest().upper() + + +__all__ = [ + "ANDROID_PREFIX", + "did_from_android_id", + "did_from_random_long", + "egid_from_seed_material", + "format_android_id", + "is_android_device_id", + "is_valid_egid", + "is_valid_oaid", + "java_long_hex16", + "java_signed_int_to_long_hex16", + "normalize_android_suffix", + "oaid_from_seed_material", + "odid_from_local_did", + "rdid_from_gRdi2", + "rdid_from_random_int", +] diff --git a/core/device_profile.py b/core/device_profile.py new file mode 100644 index 0000000..10eafd9 --- /dev/null +++ b/core/device_profile.py @@ -0,0 +1,568 @@ +from __future__ import annotations + +import hashlib +import json +import random +import re +import time +import uuid +from dataclasses import asdict, dataclass, field +from pathlib import Path +from typing import Any + +from .device_id import egid_from_seed_material, is_valid_oaid, oaid_from_seed_material + + +ANDROID_ID_RE = re.compile(r"^[0-9a-f]{16}$") +ANDROID_PREFIX_RE = re.compile(r"^ANDROID_[0-9a-f]{16}$") +EGID_RE = re.compile(r"^$|^DFP[0-9A-F]{61}$") + + +@dataclass +class DfpRuntimeHints: + did_gt: str = "" + total_memory_bytes: str = "" + build_fingerprint: str = "" + build_product: str = "" + k4_native: str = "" + storage_available_bytes: int = 0 + k51_native: str = "" + k84_native: str = "" + res_soc: str = "" + boot_id: str = "" + grdi: str = "" + ipv6_map: str = "" + lpss: str = "" + keeper_seed: str = "" + du: str = "" + sted_cache_json: str = "" + persisted_cache_m: str = "" + manus: str = "" + gaid: str = "" + oaid: str = "" + wifi_mac: str = "" + + @classmethod + def from_dict(cls, data: dict[str, Any] | None) -> "DfpRuntimeHints": + data = data or {} + return cls( + did_gt=str(data.get("did_gt", "")), + total_memory_bytes=str(data.get("total_memory_bytes", "")), + build_fingerprint=str(data.get("build_fingerprint", "")), + build_product=str(data.get("build_product", "")), + k4_native=str(data.get("k4_native", "")), + storage_available_bytes=int(data.get("storage_available_bytes", 0)), + k51_native=str(data.get("k51_native", "")), + k84_native=str(data.get("k84_native", "")), + res_soc=str(data.get("res_soc", "")), + boot_id=str(data.get("boot_id", "")), + grdi=str(data.get("grdi", "")), + ipv6_map=str(data.get("ipv6_map", "")), + lpss=str(data.get("lpss", "")), + keeper_seed=str(data.get("keeper_seed", "")), + du=str(data.get("du", "")), + sted_cache_json=str(data.get("sted_cache_json", data.get("cache_m", ""))), + persisted_cache_m=str(data.get("persisted_cache_m", "")), + manus=str(data.get("manus", "")), + gaid=str(data.get("gaid", "")), + oaid=str(data.get("oaid", "")), + wifi_mac=str(data.get("wifi_mac", "")), + ) + + +@dataclass +class DeviceProfile: + android_id: str + local_did: str + did: str + o_did: str + rdid: str + g_rdi2: str + cdid_tag: int = 0 + egid: str = "" + install_time_ms: int = 0 + cold_launch_time_ms: int = 0 + sid: str = "" + package_name: str = "com.kuaishou.nebula" + app_version: str = "14.5.50.11631" + android_release: str = "16" + manufacturer: str = "OnePlus" + brand: str = "OPPO" + model: str = "PJZ110" + build_id: str = "BP2A.250605.015" + build_display: str = "PJZ110_16.0.8.301(CN01)" + build_product: str = "OP5D0DL1" + build_fingerprint: str = "" + build_tags: str = "release-keys" + build_type: str = "user" + board_platform: str = "sun" + soc_name: str = "Qualcomm Snapdragon 8750" + max_memory: int = 256 + device_bit: str = "4" + screen_width: int = 1080 + screen_height: int = 2376 + status_bar_height: int = 120 + screen_density: float = 3.0 + screen_xdpi: str = "386.36618" + screen_ydpi: str = "381.96454" + total_memory_mb: int = 15107 + country_code: str = "cn" + isp: str = "CUCC" + runtime_hints: DfpRuntimeHints = field(default_factory=DfpRuntimeHints) + + def __post_init__(self) -> None: + self.validate() + + def validate(self) -> None: + if not ANDROID_ID_RE.fullmatch(self.android_id): + raise ValueError(f"invalid android_id: {self.android_id!r}") + + for name in ("local_did", "did", "o_did", "rdid"): + value = getattr(self, name) + if not ANDROID_PREFIX_RE.fullmatch(value): + raise ValueError(f"invalid {name}: {value!r}") + + if self.o_did != f"ANDROID_{self.android_id}": + raise ValueError("o_did must equal ANDROID_") + + expected_rdid = hashlib.md5(self.g_rdi2.encode("utf-8")).hexdigest()[16:32] + if self.rdid != f"ANDROID_{expected_rdid}": + raise ValueError("rdid must equal ANDROID_") + + if not isinstance(self.cdid_tag, int) or self.cdid_tag < 0: + raise ValueError(f"invalid cdid_tag: {self.cdid_tag!r}") + + if not EGID_RE.fullmatch(self.egid): + raise ValueError(f"invalid egid: {self.egid!r}") + if self.runtime_hints.oaid and not is_valid_oaid(self.runtime_hints.oaid): + raise ValueError(f"invalid oaid: {self.runtime_hints.oaid!r}") + if self.screen_width <= 0 or self.screen_height <= 0: + raise ValueError("screen size must be positive") + if self.total_memory_mb <= 0: + raise ValueError("total_memory_mb must be positive") + if self.max_memory <= 0: + raise ValueError("max_memory must be positive") + if not self.board_platform: + raise ValueError("board_platform must not be empty") + if not self.soc_name: + raise ValueError("soc_name must not be empty") + + def apply_cloud_identity(self, did: str, cdid_tag: int, egid: str = "") -> None: + self.did = did + self.cdid_tag = cdid_tag + if egid: + self.egid = egid + self.sync_egid_cache() + self.validate() + + def sync_egid_cache(self) -> None: + """让 k112/STED JSON 与公开 EGID 保持同一设备身份。""" + if not self.egid: + return + kuaishou_egid = egid_from_seed_material(["KUAISHOU", self.egid, self.android_id]) + self.runtime_hints.sted_cache_json = json.dumps( + {"NEBULA": self.egid, "KUAISHOU": kuaishou_egid}, + separators=(",", ":"), + ) + self.refresh_persisted_cache_m() + + def refresh_persisted_cache_m(self) -> None: + """刷新 rq0.d.cache_m,即 c.s(Context) 的本地硬件摘要。""" + from .dfp_cache import build_persisted_cache_m + + self.runtime_hints.persisted_cache_m = build_persisted_cache_m(self) + + def to_dict(self) -> dict[str, Any]: + return asdict(self) + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> "DeviceProfile": + return cls( + android_id=str(data["android_id"]), + local_did=str(data["local_did"]), + did=str(data["did"]), + o_did=str(data["o_did"]), + rdid=str(data["rdid"]), + g_rdi2=str(data["g_rdi2"]), + cdid_tag=int(data.get("cdid_tag", 0)), + egid=str(data.get("egid", "")), + install_time_ms=int(data.get("install_time_ms", 0)), + cold_launch_time_ms=int(data.get("cold_launch_time_ms", 0)), + sid=str(data.get("sid", "")), + package_name=str(data.get("package_name", "com.kuaishou.nebula")), + app_version=str(data.get("app_version", "14.5.50.11631")), + android_release=str(data.get("android_release", "16")), + manufacturer=str(data.get("manufacturer", "OnePlus")), + brand=str(data.get("brand", "OPPO")), + model=str(data.get("model", "PJZ110")), + build_id=str(data.get("build_id", "BP2A.250605.015")), + build_display=str(data.get("build_display", "PJZ110_16.0.8.301(CN01)")), + build_product=str(data.get("build_product", "OP5D0DL1")), + build_fingerprint=str(data.get("build_fingerprint", "")), + build_tags=str(data.get("build_tags", "release-keys")), + build_type=str(data.get("build_type", "user")), + board_platform=str(data.get("board_platform", "sun")), + soc_name=str(data.get("soc_name", "Qualcomm Snapdragon 8750")), + max_memory=int(data.get("max_memory", 256)), + device_bit=str(data.get("device_bit", "4")), + screen_width=int(data.get("screen_width", 1080)), + screen_height=int(data.get("screen_height", 2376)), + status_bar_height=int(data.get("status_bar_height", 120)), + screen_density=float(data.get("screen_density", 3.0)), + screen_xdpi=str(data.get("screen_xdpi", "386.36618")), + screen_ydpi=str(data.get("screen_ydpi", "381.96454")), + total_memory_mb=int(data.get("total_memory_mb", 15107)), + country_code=str(data.get("country_code", "cn")), + isp=str(data.get("isp", "CUCC")), + runtime_hints=DfpRuntimeHints.from_dict(data.get("runtime_hints")), + ) + + @property + def screen_metrics(self) -> str: + content_height = self.screen_height - self.status_bar_height - 48 + return ( + f"[{self.screen_density:.1f},{self.screen_width},{content_height}," + f"{self.screen_density:.1f},{self.screen_xdpi},{self.screen_ydpi}]" + ) + + def to_env(self) -> str: + lines = [ + f"KS_ANDROID_ID={self.android_id}", + f"KS_DID={self.did}", + f"KS_LOCAL_DID={self.local_did}", + f"KS_ODID={self.o_did}", + f"KS_RDID={self.rdid}", + f"KS_GRDI2={self.g_rdi2}", + f"KS_CDID_TAG={self.cdid_tag}", + f"KS_EGID={self.egid}", + f"KS_INSTALL_TIME_MS={self.install_time_ms}", + f"KS_COLD_LAUNCH_TIME_MS={self.cold_launch_time_ms}", + f"KS_SID={self.sid}", + f"KS_PACKAGE_NAME={self.package_name}", + f"KS_APPVER={self.app_version}", + f"KS_ANDROID_RELEASE={self.android_release}", + f"KS_MANUFACTURER={self.manufacturer}", + f"KS_BRAND={self.brand}", + f"KS_MODEL={self.model}", + f"KS_BUILD_ID={self.build_id}", + f"KS_BUILD_DISPLAY={self.build_display}", + f"KS_BUILD_PRODUCT={self.build_product}", + f"KS_BUILD_FINGERPRINT={self.build_fingerprint}", + f"KS_BUILD_TAGS={self.build_tags}", + f"KS_BUILD_TYPE={self.build_type}", + f"KS_BOARD_PLATFORM={self.board_platform}", + f"KS_SOC_NAME={self.soc_name}", + f"KS_MAX_MEMORY={self.max_memory}", + f"KS_DEVICE_BIT={self.device_bit}", + f"KS_SCREEN_WIDTH={self.screen_width}", + f"KS_SCREEN_HEIGHT={self.screen_height}", + f"KS_STATUS_BAR_HEIGHT={self.status_bar_height}", + f"KS_SCREEN_DENSITY={self.screen_density:.1f}", + f"KS_SCREEN_XDPI={self.screen_xdpi}", + f"KS_SCREEN_YDPI={self.screen_ydpi}", + f"KS_TOTAL_MEMORY_MB={self.total_memory_mb}", + f"KS_COUNTRY_CODE={self.country_code}", + f"KS_ISP={self.isp}", + f"KS_DID_GT={self.runtime_hints.did_gt}", + f"KS_TOTAL_MEMORY_BYTES={self.runtime_hints.total_memory_bytes}", + f"KS_K4={self.runtime_hints.k4_native}", + f"KS_K20={self.runtime_hints.storage_available_bytes}", + f"KS_K51={self.runtime_hints.k51_native}", + f"KS_K84={self.runtime_hints.k84_native}", + f"KS_RESSOC={self.runtime_hints.res_soc}", + f"KS_BOOT_ID={self.runtime_hints.boot_id}", + f"KS_K105={self.runtime_hints.grdi}", + f"KS_GRDI={self.runtime_hints.grdi}", + f"KS_IPV6_MAP={self.runtime_hints.ipv6_map}", + f"KS_LPSS={self.runtime_hints.lpss}", + f"KS_KEEPER_SEED={self.runtime_hints.keeper_seed}", + f"KS_DU={self.runtime_hints.du}", + f"KS_STED={self.runtime_hints.sted_cache_json}", + f"KS_DFP_CACHE_M={self.runtime_hints.persisted_cache_m}", + f"KS_MANUS={self.runtime_hints.manus}", + f"KS_GAID={self.runtime_hints.gaid}", + f"KS_OAID={self.runtime_hints.oaid}", + f"KS_WIFI_MAC={self.runtime_hints.wifi_mac}", + ] + return "\n".join(lines) + "\n" + + +class DeviceProfileGenerator: + def __init__(self, seed: int | None = None) -> None: + self._random = random.Random(seed) + + def new_profile(self) -> DeviceProfile: + now_ms = int(time.time() * 1000) + install_time_ms = now_ms - self._random.randint(10_000, 600_000) + android_id = self._hex16() + local_did = f"ANDROID_{self._hex16()}" + g_rdi2 = self._g_rdi2() + rdid_suffix = hashlib.md5(g_rdi2.encode("utf-8")).hexdigest()[16:32] + hardware = self._hardware_profile() + total_memory_bytes = str( + hardware.get("total_memory_bytes", int(hardware["total_memory_mb"]) * 1024 * 1024) + ) + hardware.pop("total_memory_bytes", None) + sid = str(uuid.UUID(int=self._random.getrandbits(128))) + egid = self._egid(android_id, local_did, g_rdi2, install_time_ms, now_ms, sid, hardware) + rdid = f"ANDROID_{rdid_suffix}" + oaid = oaid_from_seed_material([android_id, local_did, rdid, g_rdi2, sid, egid]) + + profile = DeviceProfile( + android_id=android_id, + local_did=local_did, + did=local_did, + o_did=f"ANDROID_{android_id}", + rdid=rdid, + g_rdi2=g_rdi2, + egid=egid, + install_time_ms=install_time_ms, + cold_launch_time_ms=now_ms, + sid=sid, + runtime_hints=self._runtime_hints( + egid, + did_gt=str(install_time_ms + self._random.randint(1_000, 60_000)), + total_memory_bytes=total_memory_bytes, + build_fingerprint=str(hardware.get("build_fingerprint", "")), + build_product=str(hardware.get("build_product", "")), + oaid=oaid, + ), + **hardware, + ) + profile.sync_egid_cache() + return profile + + def _hex16(self) -> str: + return f"{self._random.getrandbits(64):016x}" + + def _random_mac(self) -> str: + """随机本地管理 MAC(首字节 bit1=1 locally administered, bit0=0 unicast)。""" + b = [0x02 | (self._random.getrandbits(6) << 2)] + b += [self._random.getrandbits(8) for _ in range(5)] + return ":".join(f"{x:02x}" for x in b) + + def _g_rdi2(self) -> str: + parts = [] + for _ in range(5): + left = self._random.choice((7, 8, 9)) * 100_000_000 + self._random.randint(0, 999_999) + right = self._random.choice((4741, 8641)) + parts.append(f"{left}::{right}") + return "|".join(parts) + + def _egid( + self, + android_id: str, + local_did: str, + g_rdi2: str, + install_time_ms: int, + cold_launch_time_ms: int, + sid: str, + hardware: dict[str, Any], + ) -> str: + return egid_from_seed_material( + [ + android_id, + local_did, + g_rdi2, + install_time_ms, + cold_launch_time_ms, + sid, + hardware.get("manufacturer", ""), + hardware.get("brand", ""), + hardware.get("model", ""), + hardware.get("build_id", ""), + hardware.get("screen_width", ""), + hardware.get("screen_height", ""), + hardware.get("total_memory_mb", ""), + ] + ) + + def _hardware_profile(self) -> dict[str, Any]: + templates = [ + { + "manufacturer": "OnePlus", + "brand": "OPPO", + "model": "PJZ110", + "build_id": "BP2A.250605.015", + "build_display": "PJZ110_16.0.8.301(CN01)", + "build_product": "OP5D0DL1", + "build_fingerprint": "OnePlus/PJZ110/OP5D0DL1:16/BP2A.250605.015/V.4e5c566-2a38f4c-2a4ca91:user/release-keys", + "board_platform": "sun", + "soc_name": "Qualcomm Snapdragon 8750", + "max_memory": 256, + "device_bit": "4", + "screen_width": 1080, + "screen_height": 2376, + "status_bar_height": 120, + "screen_density": 3.0, + "screen_xdpi": "386.36618", + "screen_ydpi": "381.96454", + "total_memory_mb": 15107, + "total_memory_bytes": 15841333248, + }, + { + "manufacturer": "OPPO", + "brand": "OPPO", + "model": "PKB110", + "build_id": "BP1A.250305.019", + "build_display": "PKB110_15.0.1.601(CN01)", + "build_product": "PKB110", + "build_fingerprint": "OPPO/PKB110/PKB110:15/BP1A.250305.019/PKB110_15.0.1.601(CN01):user/release-keys", + "board_platform": "pineapple", + "soc_name": "Qualcomm Snapdragon 8 Gen 3", + "max_memory": 256, + "device_bit": "4", + "screen_width": 1080, + "screen_height": 2412, + "status_bar_height": 120, + "screen_density": 3.0, + "screen_xdpi": "394.215", + "screen_ydpi": "392.781", + "total_memory_mb": 12288, + "total_memory_bytes": 12884901888, + }, + { + "manufacturer": "vivo", + "brand": "vivo", + "model": "V2408A", + "build_id": "BP1A.250205.007", + "build_display": "V2408A_A_15.1.9.6.W10", + "build_product": "V2408A", + "build_fingerprint": "vivo/V2408A/V2408A:15/BP1A.250205.007/V2408A_A_15.1.9.6.W10:user/release-keys", + "board_platform": "dimensity9400", + "soc_name": "MediaTek Dimensity 9400", + "max_memory": 256, + "device_bit": "4", + "screen_width": 1260, + "screen_height": 2800, + "status_bar_height": 132, + "screen_density": 3.0, + "screen_xdpi": "450.0", + "screen_ydpi": "450.0", + "total_memory_mb": 16384, + "total_memory_bytes": 17179869184, + }, + ] + selected = dict(self._random.choice(templates)) + selected["isp"] = self._random.choice(["CUCC", "CTCC", "CMCC"]) + return selected + + def _runtime_hints( + self, + egid: str = "", + *, + did_gt: str = "", + total_memory_bytes: str = "", + build_fingerprint: str = "", + build_product: str = "", + oaid: str = "", + ) -> DfpRuntimeHints: + storage_gb = self._random.randint(180, 460) + grdi_parts = [] + for _ in range(5): + left = self._random.choice((5, 6, 7, 8, 9)) * 100_000_000 + self._random.randint(0, 99_999_999) + right = self._random.choice((3841, 4741, 5317, 8641)) + grdi_parts.append(f"{left}::{right}") + + ipv6_map = json.dumps( + self._ipv6_map(), + separators=(",", ":"), + ) + manus = json.dumps( + { + "5": { + "1": "KWE_N", + "2": "KWE_N", + "3": "KWE_N", + "7": str(int(time.time() * 1000)), + "8": "KWE_N", + "10": "KWE_N", + } + }, + separators=(",", ":"), + ) + return DfpRuntimeHints( + did_gt=did_gt, + total_memory_bytes=total_memory_bytes, + build_fingerprint=build_fingerprint, + build_product=build_product, + k4_native=str(self._random.randint(1_000_000_000, 4_200_000_000)), + storage_available_bytes=storage_gb * 1024 * 1024 * 1024, + k51_native=self._hex16(), + k84_native=self._hex16(), + res_soc=f"soc-{self._hex16()}", + boot_id=str(uuid.UUID(int=self._random.getrandbits(128))), + grdi="|".join(grdi_parts), + ipv6_map=ipv6_map, + lpss=f"lp-{self._hex16()}", + keeper_seed=str(self._random.getrandbits(63)), + du=f"2@{self._hex16()}{self._hex16()}", + sted_cache_json=json.dumps({"NEBULA": egid}, separators=(",", ":")) if egid else "", + manus=manus, + gaid=str(uuid.UUID(int=self._random.getrandbits(128))), + oaid=oaid or (self._hex16() + self._hex16() + self._hex16() + self._hex16()).upper(), + wifi_mac=self._random_mac(), + ) + + def _ipv6_group(self) -> str: + return f"{self._random.getrandbits(16):x}" + + def _ipv6_addr(self, prefix: str = "2408") -> str: + return ( + f"{prefix}:{self._ipv6_group()}:{self._ipv6_group()}:{self._ipv6_group()}:" + f"{self._ipv6_group()}:{self._ipv6_group()}:{self._ipv6_group()}:{self._ipv6_group()}" + ) + + def _link_local(self, iface: str) -> str: + return f"fe80::{self._ipv6_group()}:{self._ipv6_group()}:fe{self._ipv6_group()[:2]}:{self._ipv6_group()}%{iface}" + + def _ipv6_map(self) -> dict[str, str]: + ifaces = [ + "rmnet_data1", + "", + "", + "wlan0", + "", + "", + "tun0", + "rmnet_data3", + "ifb0", + "", + "r_rmnet_data0", + "rmnet_data4", + "rmnet_data2", + "ifb1", + "dummy0", + "", + "ifb2", + "vgate0", + ] + values: dict[str, str] = {"0": self._ipv6_addr()} + for index, iface in enumerate(ifaces, 1): + if iface: + values[str(index)] = self._link_local(iface) + else: + values[str(index)] = self._ipv6_addr(prefix=self._random.choice(["2408", "fd42", "2a00"])) + return values + + +def save_device_profile(profile: DeviceProfile, path: str | Path) -> None: + target = Path(path) + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text( + json.dumps(profile.to_dict(), ensure_ascii=False, indent=2, sort_keys=True) + "\n", + encoding="utf-8", + ) + + +def load_device_profile(path: str | Path) -> DeviceProfile: + source = Path(path) + try: + data = json.loads(source.read_text(encoding="utf-8")) + except Exception as exc: + raise ValueError(f"failed to load device profile: {source}") from exc + + if not isinstance(data, dict): + raise ValueError(f"device profile must be a JSON object: {source}") + + return DeviceProfile.from_dict(data) diff --git a/core/dfp_cache.py b/core/dfp_cache.py new file mode 100644 index 0000000..3e99f1c --- /dev/null +++ b/core/dfp_cache.py @@ -0,0 +1,131 @@ +from __future__ import annotations + +import hashlib +from collections.abc import Iterable, Mapping + +from .device_profile import DeviceProfile + + +PERSISTED_CACHE_KEYS = ( + "k6", + "k8", + "k16", + "k19", + "k23", + "k27", + "k29", + "k40", + "k105", + "k110", +) + + +def uq0_s_a(text: str) -> str: + """复现 uq0.s.a(): 非空且非 KWE* 时返回 MD5 小写 hex 前 16 位。""" + if not text or text.startswith("KWE"): + return text + return hashlib.md5(text.encode("utf-8")).hexdigest()[:16] + + +def java_string_hashcode(text: str) -> int: + """Java String.hashCode() 的 32-bit 结果。""" + value = 0 + for char in text: + value = (31 * value + ord(char)) & 0xFFFFFFFF + return value + + +def java_hashmap_spread(hashcode: int) -> int: + """OpenJDK HashMap.hash(): h ^ (h >>> 16)。""" + unsigned = hashcode & 0xFFFFFFFF + return (unsigned ^ (unsigned >> 16)) & 0xFFFFFFFF + + +def java_hashmap_to_string(entries: Iterable[tuple[str, object]], capacity: int = 16) -> str: + """复现当前 DFP cache_m 使用场景下的 HashMap.toString() 顺序。 + + c.s(Context) 只 put 10 个固定 String key,默认 HashMap 首次扩容到 16, + 不会触发二次 resize。这里按 bucket 下标递增、bucket 内插入顺序输出。 + """ + buckets: list[list[tuple[str, object]]] = [[] for _ in range(capacity)] + for key, value in entries: + index = java_hashmap_spread(java_string_hashcode(key)) & (capacity - 1) + bucket = buckets[index] + for item_index, (existing_key, _) in enumerate(bucket): + if existing_key == key: + bucket[item_index] = (key, value) + break + else: + bucket.append((key, value)) + + pairs = [ + f"{key}={'' if value is None else str(value)}" + for bucket in buckets + for key, value in bucket + ] + return "{" + ", ".join(pairs) + "}" + + +def _dfp_non_empty(value: object) -> str: + text = "" if value is None else str(value) + return text if text else "KWE_N" + + +def _target_sdk_grdi(value: str, target_sdk_version: int) -> str: + if target_sdk_version < 30 or not value or value.startswith("KWE"): + return value + try: + parts = value.split("|") + return "".join(f"{part}|" for index, part in enumerate(parts) if index != 3) + except Exception: + return value + + +def persisted_cache_source_values( + profile: DeviceProfile, + *, + target_sdk_version: int = 30, +) -> dict[str, str]: + """构造 com.kuaishou.dfp.c.c.s(Context) 写入 HashMap 的 10 个字段。""" + hints = profile.runtime_hints + return { + "k6": _dfp_non_empty("0"), + "k8": _dfp_non_empty(profile.build_type), + "k16": _dfp_non_empty(""), + "k19": _dfp_non_empty("sun"), + "k23": _dfp_non_empty(profile.manufacturer), + "k27": _dfp_non_empty(profile.model), + "k29": _dfp_non_empty( + f"Dalvik/2.1.0 (Linux; U; Android {profile.android_release}; " + f"{profile.model} Build/{profile.build_id})" + ), + "k40": _dfp_non_empty(""), + "k105": _dfp_non_empty(_target_sdk_grdi(hints.grdi, target_sdk_version)), + "k110": _dfp_non_empty(hints.keeper_seed), + } + + +def build_persisted_cache_m_from_values(values: Mapping[str, object]) -> str: + entries = [(key, values.get(key, "KWE_N")) for key in PERSISTED_CACHE_KEYS] + return uq0_s_a(java_hashmap_to_string(entries)) + + +def build_persisted_cache_m( + profile: DeviceProfile, + *, + target_sdk_version: int = 30, +) -> str: + values = persisted_cache_source_values(profile, target_sdk_version=target_sdk_version) + return build_persisted_cache_m_from_values(values) + + +__all__ = [ + "PERSISTED_CACHE_KEYS", + "build_persisted_cache_m", + "build_persisted_cache_m_from_values", + "java_hashmap_spread", + "java_hashmap_to_string", + "java_string_hashcode", + "persisted_cache_source_values", + "uq0_s_a", +] diff --git a/core/dfp_client.py b/core/dfp_client.py new file mode 100644 index 0000000..500558d --- /dev/null +++ b/core/dfp_client.py @@ -0,0 +1,122 @@ +from __future__ import annotations + +import json +from dataclasses import asdict, dataclass +from typing import Any, Callable + +from .device_id import is_android_device_id, is_valid_egid +from .device_profile import DeviceProfile +from .dfp_forms import DfpRequestSpec + + +@dataclass(frozen=True) +class BootstrapIdentity: + did: str = "" + cdid_tag: int = 0 + egid: str = "" + + def to_dict(self) -> dict[str, Any]: + return asdict(self) + + +@dataclass(frozen=True) +class DfpHttpResponse: + status_code: int + ok: bool + data: Any + text: str + + def to_dict(self) -> dict[str, Any]: + return asdict(self) + + +def _as_mapping(value: Any) -> dict[str, Any]: + return value if isinstance(value, dict) else {} + + +def _int_tag(value: Any) -> int: + try: + return int(value) + except (TypeError, ValueError): + return 0 + + +def extract_bootstrap_identity( + fetch_response: dict[str, Any] | None, + report_response: dict[str, Any] | None, +) -> BootstrapIdentity: + fetch = _as_mapping(fetch_response) + report = _as_mapping(report_response) + + did = str(fetch.get("cloud_did") or fetch.get("did") or "") + if not is_android_device_id(did): + did = "" + + cdid_tag = _int_tag(fetch.get("did_tag") or fetch.get("didTag") or fetch.get("cdid_tag")) + + egid = str(report.get("egid") or fetch.get("egid") or "") + if egid and not is_valid_egid(egid): + egid = "" + + return BootstrapIdentity(did=did, cdid_tag=cdid_tag, egid=egid) + + +def apply_bootstrap_identity(profile: DeviceProfile, identity: BootstrapIdentity) -> None: + if identity.did: + profile.apply_cloud_identity(identity.did, identity.cdid_tag, identity.egid) + return + if identity.egid: + profile.egid = identity.egid + profile.sync_egid_cache() + profile.validate() + + +def post_request( + request: DfpRequestSpec, + *, + timeout: int = 20, + post_func: Callable[..., Any] | None = None, +) -> DfpHttpResponse: + if post_func is None: + import requests + + post_func = requests.post + + try: + response = post_func( + request.url, + data=request.body.encode("utf-8"), + headers=request.headers, + timeout=timeout, + ) + except Exception as exc: + text = str(exc) + return DfpHttpResponse( + status_code=0, + ok=False, + data={"error_type": exc.__class__.__name__, "error": text}, + text=text, + ) + text = getattr(response, "text", "") + try: + data = response.json() + except Exception: + try: + data = json.loads(text) + except Exception: + data = text + return DfpHttpResponse( + status_code=int(getattr(response, "status_code", 0)), + ok=bool(getattr(response, "ok", False)), + data=data, + text=text, + ) + + +__all__ = [ + "BootstrapIdentity", + "DfpHttpResponse", + "apply_bootstrap_identity", + "extract_bootstrap_identity", + "post_request", +] diff --git a/core/dfp_forms.py b/core/dfp_forms.py new file mode 100644 index 0000000..6be9140 --- /dev/null +++ b/core/dfp_forms.py @@ -0,0 +1,245 @@ +from __future__ import annotations + +import base64 +import time +import uuid +from dataclasses import asdict, dataclass +from urllib.parse import quote_plus, urlencode + +from .device_profile import DeviceProfile +from .dfp_knn import build_full_knn, build_lite_knn +from .dfp_sign import DFP_SDK_ID, sign_dfp_form +from .dfp_sq0 import encode_sq0_device_info +from .enc_data import KWSG_10400_DEFAULT_CFG9, kwsg_10400_raw, load_kwsg_10400_tables + + +UNIFIED_FETCH_URL = "https://gdfpsec.ksapisrv.com/rest/infra/unifiedId/fetch/android" +UNIFIED_CHECK_REPAIR_URL = "https://gdfpsec.ksapisrv.com/rest/infra/unifiedId/checkRepair" +GDFP_REPORT_URL = "https://gdfpsec.ksapisrv.com/rest/infra/gdfp/report/kuaishou/android" + +UNIFIED_FETCH_FORM_ORDER = [ + "aegon", + "appVersion", + "deviceInfo", + "did", + "didTag", + "hgidReportId", + "platform", + "productName", + "rdid", + "requestId", + "sdkVersion", + "sv", + "ts", + "sign", +] + +UNIFIED_CHECK_REPAIR_FORM_ORDER = [ + "appVersion", + "did", + "didTag", + "from", + "lastDidTs", + "platform", + "productName", + "sdkVersion", + "ts", + "sign", +] + +GDFP_REPORT_FORM_ORDER = [ + "productName", + "ts", + "deviceInfo", + "sign", + "sv", + "rdid", + "didtag", +] + + +@dataclass(frozen=True) +class DfpRequestSpec: + method: str + url: str + headers: dict[str, str] + form_order: list[str] + form: dict[str, str] + body: str + + def to_dict(self) -> dict[str, object]: + return asdict(self) + + +def android_base64_default(data: bytes) -> str: + text = base64.b64encode(data).decode() + return "\n".join(text[i : i + 76] for i in range(0, len(text), 76)) + "\n" + + +def java_urlencode(text: str) -> str: + return quote_plus(text, safe="*-._") + + +def _headers(url: str) -> dict[str, str]: + host = url.split("/", 3)[2] + return { + "Content-Type": "application/x-www-form-urlencoded", + "Host": host, + "Connection": "Keep-Alive", + "Accept-Encoding": "gzip", + "User-Agent": "okhttp/3.12.13", + } + + +def _device_info_encoded( + sq0_raw: bytes, + *, + epoch_seconds: int | None, + sdk_id: str = DFP_SDK_ID, +) -> str: + t1, t2 = load_kwsg_10400_tables() + raw = kwsg_10400_raw( + sq0_raw, + sdk_id, + t1, + t2, + epoch_seconds=epoch_seconds, + cfg9=KWSG_10400_DEFAULT_CFG9, + ) + return java_urlencode(android_base64_default(raw)) + + +def _request_from_order(url: str, form: dict[str, str], form_order: list[str]) -> DfpRequestSpec: + ordered_pairs = [(key, form[key]) for key in form_order] + body = urlencode(ordered_pairs) + return DfpRequestSpec( + method="POST", + url=url, + headers=_headers(url), + form_order=list(form_order), + form={key: value for key, value in ordered_pairs}, + body=body, + ) + + +def _now_millis() -> str: + return str(int(time.time() * 1000)) + + +def _request_id() -> str: + return uuid.uuid4().hex[:16] + + +def build_unified_fetch_request( + profile: DeviceProfile, + *, + counter: int, + unix_time: int, + session_seed: int, + ts_millis: str | None = None, + epoch_seconds: int | None = None, +) -> DfpRequestSpec: + sq0_raw = encode_sq0_device_info(build_lite_knn(profile), mode="lite") + device_info = _device_info_encoded(sq0_raw, epoch_seconds=epoch_seconds) + unsigned = { + "aegon": "false", + "appVersion": "14.5.50.11631", + "deviceInfo": device_info, + "did": profile.did, + "didTag": "-1", + "hgidReportId": _request_id(), + "platform": "1", + "productName": "NEBULA", + "rdid": profile.rdid, + "requestId": _request_id(), + "sdkVersion": "9.5.4lite.79.137a838b", + "sv": "2", + "ts": ts_millis or _now_millis(), + } + signed = sign_dfp_form( + "unified_fetch", + unsigned, + counter, + unix_time, + session_seed=session_seed, + ) + form = {key: signed[key] for key in UNIFIED_FETCH_FORM_ORDER} + return _request_from_order(UNIFIED_FETCH_URL, form, UNIFIED_FETCH_FORM_ORDER) + + +def build_unified_check_repair_request( + profile: DeviceProfile, + *, + counter: int, + unix_time: int, + session_seed: int, + ts_millis: str | None = None, + from_value: str = "1", + last_did_ts: str | None = None, +) -> DfpRequestSpec: + unsigned = { + "appVersion": profile.app_version, + "did": profile.did, + "didTag": str(profile.cdid_tag), + "from": str(from_value), + "lastDidTs": str(last_did_ts if last_did_ts is not None else profile.install_time_ms), + "platform": "1", + "productName": "NEBULA", + "sdkVersion": "9.5.4lite.79.137a838b", + "ts": ts_millis or _now_millis(), + } + signed = sign_dfp_form( + "unified_check_repair", + unsigned, + counter, + unix_time, + session_seed=session_seed, + ) + form = {key: signed[key] for key in UNIFIED_CHECK_REPAIR_FORM_ORDER} + return _request_from_order(UNIFIED_CHECK_REPAIR_URL, form, UNIFIED_CHECK_REPAIR_FORM_ORDER) + + +def build_gdfp_report_request( + profile: DeviceProfile, + *, + counter: int, + unix_time: int, + session_seed: int, + ts_millis: str | None = None, + epoch_seconds: int | None = None, +) -> DfpRequestSpec: + sq0_raw = encode_sq0_device_info(build_full_knn(profile), mode="full") + device_info = _device_info_encoded(sq0_raw, epoch_seconds=epoch_seconds) + unsigned = { + "productName": "NEBULA", + "ts": ts_millis or _now_millis(), + "deviceInfo": device_info, + "sv": "2", + "rdid": profile.rdid, + "didtag": "-1", + } + signed = sign_dfp_form( + "gdfp_report", + unsigned, + counter, + unix_time, + session_seed=session_seed, + ) + form = {key: signed[key] for key in GDFP_REPORT_FORM_ORDER} + return _request_from_order(GDFP_REPORT_URL, form, GDFP_REPORT_FORM_ORDER) + + +__all__ = [ + "DfpRequestSpec", + "UNIFIED_CHECK_REPAIR_FORM_ORDER", + "UNIFIED_CHECK_REPAIR_URL", + "GDFP_REPORT_FORM_ORDER", + "GDFP_REPORT_URL", + "UNIFIED_FETCH_FORM_ORDER", + "UNIFIED_FETCH_URL", + "android_base64_default", + "build_gdfp_report_request", + "build_unified_check_repair_request", + "build_unified_fetch_request", + "java_urlencode", +] diff --git a/core/dfp_knn.py b/core/dfp_knn.py new file mode 100644 index 0000000..11fcb36 --- /dev/null +++ b/core/dfp_knn.py @@ -0,0 +1,305 @@ +from __future__ import annotations + +import json +import zlib + +from .device_profile import DeviceProfile + + +KWE_N = "KWE_N" +KWE_NPN = "KWE_NPN" +LITE_DFP_VERSION = "9.5.4lite.79.137a838b" + +# 运营商 -> MCC-MNC(从 profile.isp 派生,不再硬编码) +_ISP_MCC_MNC = {"CUCC": "46001", "CTCC": "46011", "CMCC": "46000"} + +LITE_KEYS = [ + "k5", + "k14", + "k22", + "k23", + "k27", + "k29", + "k31", + "k34", + "k35", + "k36", + "k39", + "k40", + "k46", + "k57", + "k61", + "k64", + "k66", + "k68", + "k83", + "k86", + "k93", + "k97", + "k101", + "k102", + "k105", + "k106", + "k107", + "k108", + "k109", + "k110", + "k111", + "k112", + "k113", +] + +FULL_KEYS = [f"k{index}" for index in range(1, 120)] + +FULL_DEFAULTS = { + **{key: KWE_NPN for key in ("k2", "k9", "k12", "k13", "k18", "k21", "k33", "k41", "k43")}, + **{key: KWE_NPN for key in ("k55", "k57", "k62", "k65", "k76", "k79", "k80", "k81")}, + **{key: KWE_NPN for key in ("k54", "k68", "k71", "k73", "k74", "k75", "k77", "k82", "k88")}, + **{key: KWE_NPN for key in ("k106", "k114", "k115", "k116", "k117", "k118")}, + **{key: KWE_N for key in ("k24", "k31", "k53", "k70", "k85", "k86", "k87")}, + **{key: KWE_N for key in ("k90", "k91", "k94", "k96", "k101", "k103", "k104")}, + "k63": "root", + "k95": "KWE_NS", +} + + +def _android_suffix(value: str) -> str: + return value.removeprefix("ANDROID_") + + +def _text(value: object, default: str = KWE_N) -> str: + if value is None: + return default + text = str(value) + return text if text != "" else default + + +def _mcc_mnc(profile: DeviceProfile) -> str: + return { + "CUCC": "46011", + "CTCC": "46003", + "CMCC": "46000", + }.get(profile.isp.upper(), KWE_NPN) + + +def _k93_json(profile: DeviceProfile) -> str: + return json.dumps( + { + "0": 1, + "1": "7", + "2": "true", + "4": KWE_N, + "8": "zz abcdabcdabcdabcdabcd", + "11": profile.model, + "12": KWE_N, + "19": "100", + "20": profile.install_time_ms, + "23": KWE_N, + "24": KWE_N, + "25": f"{profile.runtime_hints.wifi_mac or '02:00:00:00:00:00'}@{profile.install_time_ms}@{profile.model}@CTExcel@{_ISP_MCC_MNC.get(profile.isp.upper(), '46001')}", + "30": { + "op_old": profile.runtime_hints.oaid or KWE_N, + "cost_old": 5, + "cost_new": 22, + }, + "27": True, + "28": profile.g_rdi2, + }, + ensure_ascii=False, + separators=(",", ":"), + ) + + +def _k93_lite_json(profile: DeviceProfile) -> str: + return json.dumps( + { + "19": "100", + "20": profile.install_time_ms, + "23": KWE_N, + "24": KWE_N, + "25": f"{profile.runtime_hints.wifi_mac or '02:00:00:00:00:00'}@{profile.install_time_ms}@{profile.model}@CTExcel@{_ISP_MCC_MNC.get(profile.isp.upper(), '46001')}", + "30": { + "op_old": profile.runtime_hints.oaid or KWE_N, + "cost_old": 6, + "cost_new": 23, + }, + "27": True, + "28": profile.g_rdi2, + }, + ensure_ascii=False, + separators=(",", ":"), + ) + + +def _dalvik_vm(profile: DeviceProfile) -> str: + return ( + f"Dalvik/2.1.0 (Linux; U; Android {profile.android_release}; " + f"{profile.model} Build/{profile.build_id})" + ) + + +def _build_fingerprint(profile: DeviceProfile) -> str: + if profile.build_fingerprint: + return profile.build_fingerprint + product = profile.build_product or profile.model + return ( + f"{profile.manufacturer}/{profile.model}/{product}:" + f"{profile.android_release}/{profile.build_id}/{profile.build_display}:" + f"{profile.build_type}/{profile.build_tags}" + ) + + +def recompute_k14_crc(values: dict[str, str], ordered_keys: list[str]) -> str: + crc = 0 + for key in ordered_keys: + raw = b"AND" if key == "k14" else str(values.get(key, "")).encode("utf-8") + crc = zlib.crc32(raw, crc) + return f"AND:{crc & 0xFFFFFFFF}" + + +def build_lite_knn( + profile: DeviceProfile, + overrides: dict[str, str] | None = None, +) -> dict[str, str]: + hints = profile.runtime_hints + values = {key: KWE_N for key in LITE_KEYS} + values.update( + { + "k5": str(profile.install_time_ms), + "k14": "AND", + "k22": profile.app_version, + "k23": profile.manufacturer, + "k27": profile.model, + "k29": _dalvik_vm(profile), + "k31": KWE_N, + "k34": profile.screen_metrics, + "k35": profile.android_release, + "k36": LITE_DFP_VERSION, + "k39": hints.did_gt or str(profile.install_time_ms), + "k40": _build_fingerprint(profile), + "k46": hints.total_memory_bytes or str(profile.total_memory_mb * 1024 * 1024), + "k57": KWE_NPN, + "k61": profile.brand, + "k66": _android_suffix(profile.o_did), + "k68": KWE_NPN, + "k83": profile.egid or "KWE_N", + "k93": _k93_lite_json(profile), + "k97": hints.oaid, + "k101": hints.res_soc, + "k102": hints.boot_id, + "k105": hints.grdi, + "k106": KWE_NPN, + "k107": str(profile.cdid_tag), + "k108": hints.ipv6_map, + "k109": hints.lpss, + "k110": hints.keeper_seed, + "k111": hints.du, + "k112": hints.sted_cache_json or "KWE_N", + "k113": hints.manus, + } + ) + if overrides: + for key, value in overrides.items(): + if key not in values: + raise KeyError(key) + values[key] = "" if value is None else str(value) + values["k14"] = recompute_k14_crc(values, LITE_KEYS) + return {key: _text(values.get(key), default="") for key in LITE_KEYS} + + +def build_full_knn( + profile: DeviceProfile, + overrides: dict[str, str] | None = None, +) -> dict[str, str]: + hints = profile.runtime_hints + values = {key: FULL_DEFAULTS.get(key, KWE_N) for key in FULL_KEYS} + values.update( + { + "k1": "isContent", + "k3": profile.package_name, + "k4": hints.k4_native, + "k5": str(profile.install_time_ms), + "k6": "0", + "k7": profile.did, + "k8": profile.build_type, + "k10": "0", + "k11": "0", + "k14": "AND", + "k15": "0", + "k16": "kvm-slave-build-s-system-11410184", + "k17": "192.168.8.34", + "k19": "sun", + "k20": str(hints.storage_available_bytes), + "k22": profile.app_version, + "k23": profile.manufacturer, + "k25": "1", + "k26": "arm64-v8a,", + "k27": profile.model, + "k28": "qcom", + "k29": _dalvik_vm(profile), + "k30": profile.build_display, + "k32": "[GMT+08:00,Asia/Shanghai]", + "k34": profile.screen_metrics, + "k35": profile.android_release, + "k36": LITE_DFP_VERSION, + "k37": profile.build_id, + "k38": "91", + "k39": hints.did_gt or str(profile.install_time_ms), + "k40": _build_fingerprint(profile), + "k42": "[5,100]", + "k44": profile.build_tags, + "k45": "isContent", + "k46": hints.total_memory_bytes or str(profile.total_memory_mb * 1024 * 1024), + "k47": "unknown", + "k48": "isContent", + "k49": "0", + "k50": "notExist", + "k51": hints.k51_native, + "k52": profile.model, + "k56": "notExist", + "k58": profile.build_product or hints.build_product or profile.model, + "k59": "1", + "k60": "unknown", + "k61": profile.brand, + "k66": _android_suffix(profile.o_did), + "k67": "gb", + "k69": "1", + "k72": profile.country_code, + "k78": _mcc_mnc(profile), + "k83": profile.egid or "KWE_FIRST", + "k84": hints.k84_native, + "k89": "160816899", + "k92": str(profile.cold_launch_time_ms), + "k93": _k93_json(profile), + "k97": hints.oaid, + "k101": hints.res_soc, + "k102": hints.boot_id, + "k105": hints.grdi, + "k107": str(profile.cdid_tag), + "k108": hints.ipv6_map, + "k109": hints.lpss, + "k110": hints.keeper_seed, + "k111": hints.du, + "k112": hints.sted_cache_json, + "k113": hints.manus, + "k119": hints.gaid, + } + ) + if overrides: + for key, value in overrides.items(): + if key not in values: + raise KeyError(key) + values[key] = "" if value is None else str(value) + values["k14"] = recompute_k14_crc(values, FULL_KEYS) + return {key: _text(values.get(key), default="") for key in FULL_KEYS} + + +__all__ = [ + "FULL_KEYS", + "KWE_N", + "LITE_DFP_VERSION", + "LITE_KEYS", + "build_full_knn", + "build_lite_knn", + "recompute_k14_crc", +] diff --git a/core/dfp_sign.py b/core/dfp_sign.py new file mode 100644 index 0000000..10ae851 --- /dev/null +++ b/core/dfp_sign.py @@ -0,0 +1,174 @@ +"""DFP / unifiedId atlasSign input builders and 10405 sign wrappers.""" + +from __future__ import annotations + +from dataclasses import dataclass +import hashlib +from typing import Mapping + +from .atlas_sign import atlas_sign, atlas_sign_to_digest_hex +from .enc_data import ZT_OUTER_CONFIGS +from .sig3 import kwsg_10418_digest24_unmix + + +DFP_SDK_ID = "7e46b28a-8c93-4940-8238-4c60e64e3c81" +DFP_SIGN_KEYS = {"sign", "__NS_sig3", "__NS_xfalcon", "__NStokensig", "sig"} +DFP_PAYLOAD_KEYS = ("deviceInfo", "carryInfo", "data") + + +@dataclass(frozen=True) +class DfpSignMaterial: + scheme: str + keys: tuple[str, ...] + sign_input: str + excluded_keys: tuple[str, ...] = () + note: str = "" + + @property + def input_len(self) -> int: + return len(self.sign_input) + + @property + def input_sha256(self) -> str: + return hashlib.sha256(self.sign_input.encode("utf-8", errors="ignore")).hexdigest() + + +def _first_payload_key(params: Mapping[str, str], preferred: tuple[str, ...]) -> str: + for key in preferred: + if key in params: + return key + for key in DFP_PAYLOAD_KEYS: + if key in params: + return key + raise KeyError("missing DFP encrypted payload field") + + +def legacy_product_ts_sv_payload(params: Mapping[str, str]) -> DfpSignMaterial: + """Build `productName + ts + sv + encryptedPayload`. + + Used by `gdfp/report` and `unifiedId/logReport/android`. + """ + + payload_key = _first_payload_key(params, ("deviceInfo", "carryInfo", "data")) + keys = ("productName", "ts", "sv", payload_key) + sign_input = ( + params.get("productName", "") + + params.get("ts", "") + + params.get("sv", "2") + + params.get(payload_key, "") + ) + excluded = tuple(key for key in params if key not in keys and key not in DFP_SIGN_KEYS) + return DfpSignMaterial( + scheme="legacy_product_ts_sv_payload", + keys=keys, + sign_input=sign_input, + excluded_keys=excluded, + note="productName + ts + sv + encrypted payload; append rdid/didtag/ft after sign", + ) + + +def id_mapping_data_only(params: Mapping[str, str]) -> DfpSignMaterial: + """Build `data` only for `unifiedId/logReport/idMapping`.""" + + payload_key = _first_payload_key(params, ("data",)) + return DfpSignMaterial( + scheme="id_mapping_data_only", + keys=(payload_key,), + sign_input=params.get(payload_key, ""), + note="idMapping signs only encoded data", + ) + + +def tree_values_sorted_non_empty_except_sign(params: Mapping[str, str]) -> DfpSignMaterial: + """Build TreeMap-style non-empty values without separators.""" + + keys = tuple( + key + for key in sorted(params) + if key not in DFP_SIGN_KEYS and params.get(key, "") != "" + ) + sign_input = "".join(params[key] for key in keys) + excluded = tuple(key for key in params if key not in keys and key not in DFP_SIGN_KEYS) + return DfpSignMaterial( + scheme="tree_values_sorted_non_empty_except_sign", + keys=keys, + sign_input=sign_input, + excluded_keys=excluded, + note="TreeMap key order, non-empty values, no separators", + ) + + +def build_dfp_sign_material(kind: str, params: Mapping[str, str]) -> DfpSignMaterial: + if kind in {"gdfp_report", "unified_log_report"}: + return legacy_product_ts_sv_payload(params) + if kind == "unified_id_mapping": + return id_mapping_data_only(params) + if kind in {"unified_fetch", "unified_repair", "unified_check_repair"}: + return tree_values_sorted_non_empty_except_sign(params) + raise ValueError(f"unsupported DFP sign kind: {kind}") + + +def dfp_atlas_sign( + sign_input: str | bytes | bytearray, + counter: int, + unix_time: int, + *, + session_seed: int, + sdk_id: str = DFP_SDK_ID, +) -> str: + """Generate the 64hex DFP 10405 atlasSign value.""" + + return atlas_sign( + sign_input, + sdk_id, + counter, + unix_time, + session_seed=session_seed, + ) + + +def sign_dfp_form( + kind: str, + params: Mapping[str, str], + counter: int, + unix_time: int, + *, + session_seed: int, + sdk_id: str = DFP_SDK_ID, +) -> dict[str, str]: + """Return a signed copy of a DFP/unifiedId form.""" + + material = build_dfp_sign_material(kind, params) + signed = {str(key): str(value) for key, value in params.items()} + signed["sign"] = dfp_atlas_sign( + material.sign_input, + counter, + unix_time, + session_seed=session_seed, + sdk_id=sdk_id, + ) + return signed + + +def parse_dfp_atlas_sign(sign_hex64: str, sdk_id: str = DFP_SDK_ID) -> dict: + digest_hex = atlas_sign_to_digest_hex(sign_hex64, sdk_id) + parsed = kwsg_10418_digest24_unmix(digest_hex) + parsed["digest24_hex"] = digest_hex + parsed["sdk_id"] = sdk_id + parsed["head8"] = ZT_OUTER_CONFIGS[sdk_id]["head8"].hex() + return parsed + + +__all__ = [ + "DFP_PAYLOAD_KEYS", + "DFP_SDK_ID", + "DFP_SIGN_KEYS", + "DfpSignMaterial", + "build_dfp_sign_material", + "dfp_atlas_sign", + "id_mapping_data_only", + "legacy_product_ts_sv_payload", + "parse_dfp_atlas_sign", + "sign_dfp_form", + "tree_values_sorted_non_empty_except_sign", +] diff --git a/core/dfp_sq0.py b/core/dfp_sq0.py new file mode 100644 index 0000000..93e3eb4 --- /dev/null +++ b/core/dfp_sq0.py @@ -0,0 +1,127 @@ +from __future__ import annotations + +from typing import Any + + +LITE_TAGS = { + "k5": 5, + "k14": 14, + "k22": 22, + "k23": 23, + "k27": 27, + "k29": 29, + "k31": 31, + "k34": 34, + "k35": 35, + "k36": 36, + "k39": 39, + "k40": 40, + "k46": 46, + "k57": 57, + "k61": 61, + "k64": 64, + "k66": 66, + "k68": 68, + "k83": 83, + "k86": 86, + "k93": 93, + "k97": 97, + "k101": 101, + "k102": 102, + "k105": 105, + "k106": 106, + "k107": 107, + "k108": 108, + "k109": 109, + "k110": 110, + "k111": 111, + "k112": 112, + "k113": 113, +} + +FULL_TAGS = {f"k{index}": index for index in range(1, 120)} + + +def _varint(value: int) -> bytes: + if value < 0: + raise ValueError("varint value must be >= 0") + out = bytearray() + while value >= 0x80: + out.append((value & 0x7F) | 0x80) + value >>= 7 + out.append(value) + return bytes(out) + + +def _read_varint(raw: bytes, offset: int) -> tuple[int, int]: + shift = 0 + value = 0 + while True: + if offset >= len(raw): + raise ValueError("truncated varint") + byte = raw[offset] + offset += 1 + value |= (byte & 0x7F) << shift + if byte < 0x80: + return value, offset + shift += 7 + if shift > 63: + raise ValueError("varint too long") + + +def _tags_for_mode(mode: str) -> dict[str, int]: + if mode == "lite": + return LITE_TAGS + if mode == "full": + return FULL_TAGS + raise ValueError(f"unsupported sq0 mode: {mode}") + + +def encode_sq0_device_info(values: dict[str, str], mode: str) -> bytes: + tags = _tags_for_mode(mode) + encoded = bytearray() + for key, value in values.items(): + if key not in tags: + raise KeyError(key) + text = "" if value is None else str(value) + if text == "": + continue + payload = text.encode("utf-8") + encoded += _varint((tags[key] << 3) | 2) + encoded += _varint(len(payload)) + encoded += payload + return bytes(encoded) + + +def decode_sq0_string_fields(raw: bytes) -> list[dict[str, Any]]: + fields: list[dict[str, Any]] = [] + offset = 0 + while offset < len(raw): + key, offset = _read_varint(raw, offset) + proto_tag = key >> 3 + wire_type = key & 7 + if wire_type != 2: + raise ValueError(f"unsupported wire type: {wire_type}") + size, offset = _read_varint(raw, offset) + end = offset + size + if end > len(raw): + raise ValueError("truncated length-delimited field") + payload = raw[offset:end] + offset = end + fields.append( + { + "proto_tag": proto_tag, + "wire_type": wire_type, + "value": payload.decode("utf-8", errors="replace"), + "raw_hex": payload.hex(), + } + ) + return fields + + +__all__ = [ + "FULL_TAGS", + "LITE_TAGS", + "decode_sq0_string_fields", + "encode_sq0_device_info", +] diff --git a/core/enc_data.py b/core/enc_data.py new file mode 100644 index 0000000..514777b --- /dev/null +++ b/core/enc_data.py @@ -0,0 +1,237 @@ +"""KWSG 10400 `encData` and ZT envelope helpers.""" + +from __future__ import annotations + +from pathlib import Path +from struct import unpack_from +import time +import zlib + + +KWSG_STATIC_AES_KEY = b"5FDxA9ngHE723pYw" +KWSG_STATIC_AES_IV = b"12345678kuaishou" + + +ZT_OUTER_CONFIGS = { + "95147564-9763-4413-a937-6f0e3c12caf1": { + "head8": bytes.fromhex("5a54eecde4d4ea61"), + "xor_key": b"M70gN2gdHXA34uIc", + }, + "bbd910da-fda5-49e7-8667-f57200dac474": { + "head8": bytes.fromhex("5a54eecdf04c4dad"), + "xor_key": b"lpYKvL0Mz9bEtHXO", + }, + "7e46b28a-8c93-4940-8238-4c60e64e3c81": { + "head8": bytes.fromhex("5a54ebcd594b0dae"), + "xor_key": b"fGqSL6alaNcUyV9W", + }, + "5bbcf3cd-727b-48ab-b4b4-5f01e61ee9a5": { + "head8": bytes.fromhex("5a54eecdd3ce5ab6"), + "xor_key": b"lealm6bxeMABH3rQ", + }, +} + + +KWSG_266FC_PERM = ( + 0, 5, 10, 15, + 4, 9, 14, 3, + 8, 13, 2, 7, + 12, 1, 6, 11, +) + +KWSG_10400_T1_LEN = 0x24000 +KWSG_10400_T2_LEN = 0xA100 +KWSG_10400_NONCE_XOR = 0xDDCC0DEF +KWSG_10400_DEFAULT_CFG9 = bytes.fromhex("00cf07009d9ec1b102") + + +def load_kwsg_10400_tables( + t1_path: str | Path = "bin/kwsg_10400_T1.bin", + t2_path: str | Path = "bin/kwsg_10400_T2.bin", +) -> tuple[bytes, bytes]: + """加载 `0x266fc` 所需运行期 T1/T2 表。""" + t1 = Path(t1_path).read_bytes() + t2 = Path(t2_path).read_bytes() + if len(t1) < KWSG_10400_T1_LEN: + raise ValueError(f"T1 too short: {len(t1)}") + if len(t2) < KWSG_10400_T2_LEN: + raise ValueError(f"T2 too short: {len(t2)}") + return t1, t2 + + +def _u32le(buf: bytes, off: int) -> int: + return unpack_from(" bytearray: + return bytearray(state[i] for i in KWSG_266FC_PERM) + + +def _kwsg_266fc_lane_core(state: bytearray, t1: bytes, round_base: int, lane: int) -> None: + p = lane * 4 + table_base = round_base + lane * 0x1000 + + a = _u32le(t1, table_base + 0x000 + state[p + 0] * 4) + b = _u32le(t1, table_base + 0x400 + state[p + 1] * 4) + c = _u32le(t1, table_base + 0x800 + state[p + 2] * 4) + d = _u32le(t1, table_base + 0xC00 + state[p + 3] * 4) + w = a ^ b ^ c ^ d + + state[p + 0] = (w >> 24) & 0xFF + state[p + 1] = (w >> 16) & 0xFF + state[p + 2] = (w >> 8) & 0xFF + state[p + 3] = w & 0xFF + + +def kwsg_266fc_block(block16: bytes, t1: bytes, t2: bytes) -> bytes: + """移植 `libkwsgmain.so+0x266fc` 的 16-byte block transform。""" + if len(block16) != 16: + raise ValueError("block16 must be exactly 16 bytes") + + state = bytearray(block16) + for round_idx in range(9): + state = _kwsg_266fc_permute(state) + round_base = round_idx * 0x4000 + for lane in range(4): + _kwsg_266fc_lane_core(state, t1, round_base, lane) + + state = _kwsg_266fc_permute(state) + for i in range(16): + state[i] = t2[0x9000 + i * 0x100 + state[i]] + return bytes(state) + + +def kwsg_10400_ecb_encrypt(payload: bytes, t1: bytes, t2: bytes) -> bytes: + """移植 `0x27534` 包装层的 ECB-like + PKCS#7 加密输出。""" + pad = 16 - (len(payload) % 16) + padded = payload + bytes([pad]) * pad + return b"".join( + kwsg_266fc_block(padded[i:i + 16], t1, t2) + for i in range(0, len(padded), 16) + ) + + +def kwsg_10400_nonce9(epoch_seconds: int | None = None) -> bytes: + """生成 `0x11b08` 当前实测分支的 9-byte nonce 字段。""" + if epoch_seconds is None: + epoch_seconds = int(time.time()) + value = (int(epoch_seconds) & 0xFFFFFFFF) ^ KWSG_10400_NONCE_XOR + return str(value).encode("ascii")[:9] + + +def zt_outer_wrap(inner: bytes, head8: bytes, xor_key: bytes) -> bytes: + """`sub_0x122e4 mode 1`: `head8 + repeating_xor(inner)`.""" + if len(head8) != 8: + raise ValueError("head8 must be 8 bytes") + if len(xor_key) != 16: + raise ValueError("xor_key must be 16 bytes") + body = bytes(b ^ xor_key[i & 0x0F] for i, b in enumerate(inner)) + return head8 + body + + +def zt_outer_unwrap(raw: bytes, xor_key: bytes) -> bytes: + """反解 `sub_0x122e4 mode 1` 外层 body,返回 inner ZT 数据。""" + if len(raw) < 8: + raise ValueError("raw too short") + if len(xor_key) != 16: + raise ValueError("xor_key must be 16 bytes") + body = raw[8:] + return bytes(b ^ xor_key[i & 0x0F] for i, b in enumerate(body)) + + +def build_inner_zt_header(nonce9: bytes, cfg9: bytes, payload: bytes) -> bytes: + """构造 `sub_0x11b08` 的 0x20-byte inner header。""" + if len(nonce9) != 9: + raise ValueError("nonce9 must be 9 bytes") + if len(cfg9) != 9: + raise ValueError("cfg9 must be 9 bytes") + return ( + bytes.fromhex("dec0adde") + + (0x20).to_bytes(2, "little") + + nonce9 + + cfg9 + + (zlib.crc32(payload) & 0xFFFFFFFF).to_bytes(4, "little") + + len(payload).to_bytes(4, "little") + ) + + +def parse_inner_zt_header(inner: bytes) -> dict: + """解析反 XOR 后的 inner ZT header。""" + if len(inner) < 0x20: + raise ValueError("inner too short") + return { + "magic": inner[:4], + "header_size": int.from_bytes(inner[4:6], "little"), + "nonce9": inner[6:15], + "cfg9": inner[15:24], + "crc32": int.from_bytes(inner[24:28], "little"), + "payload_len": int.from_bytes(inner[28:32], "little"), + "payload": inner[32:], + } + + +def derive_outer_xor_key(raw: bytes, inner_payload_first16: bytes) -> bytes: + """由最终 raw 和 inner payload 前 16 字节反推 16-byte XOR key。""" + if len(raw) < 8 + 0x20 + 16: + raise ValueError("raw too short") + if len(inner_payload_first16) < 16: + raise ValueError("need 16 bytes of inner payload") + return bytes(raw[8 + 0x20 + i] ^ inner_payload_first16[i] for i in range(16)) + + +def kwsg_10400_raw_with_inner_fields( + payload: bytes, + sdk_id: str, + nonce9: bytes, + cfg9: bytes, + t1: bytes, + t2: bytes, +) -> bytes: + """生成当前已验证 `10400` raw 输出。""" + cfg = ZT_OUTER_CONFIGS[sdk_id] + encrypted = kwsg_10400_ecb_encrypt(payload, t1, t2) + inner = build_inner_zt_header(nonce9, cfg9, encrypted) + encrypted + return zt_outer_wrap(inner, cfg["head8"], cfg["xor_key"]) + + +def kwsg_10400_raw( + payload: bytes, + sdk_id: str, + t1: bytes, + t2: bytes, + *, + epoch_seconds: int | None = None, + cfg9: bytes = KWSG_10400_DEFAULT_CFG9, +) -> bytes: + """用当前已还原字段生成 `10400` raw。""" + return kwsg_10400_raw_with_inner_fields( + payload, + sdk_id, + kwsg_10400_nonce9(epoch_seconds), + cfg9, + t1, + t2, + ) + + +__all__ = [ + "KWSG_10400_DEFAULT_CFG9", + "KWSG_10400_NONCE_XOR", + "KWSG_10400_T1_LEN", + "KWSG_10400_T2_LEN", + "KWSG_266FC_PERM", + "KWSG_STATIC_AES_IV", + "KWSG_STATIC_AES_KEY", + "ZT_OUTER_CONFIGS", + "build_inner_zt_header", + "derive_outer_xor_key", + "kwsg_10400_ecb_encrypt", + "kwsg_10400_nonce9", + "kwsg_10400_raw", + "kwsg_10400_raw_with_inner_fields", + "kwsg_266fc_block", + "load_kwsg_10400_tables", + "parse_inner_zt_header", + "zt_outer_unwrap", + "zt_outer_wrap", +] diff --git a/core/fap_request.py b/core/fap_request.py new file mode 100644 index 0000000..a3995ce --- /dev/null +++ b/core/fap_request.py @@ -0,0 +1,342 @@ +"""纯 Python 复现 ``gdfp.gifshow.com/f/a/p`` 设备指纹上报端点。 + +该端点不是 ``passport_account_image`` 的生成源。登录票据由客户端 +``Engine.pr`` 本地生成;本模块仅保留设备遥测协议研究和响应提取工具。 + +静态定论(``out/jadx/sources/com/kuaishou/weapon/ks/``): + +签名 ``h1.a(map)`` / ``h1.d(ctx)`` + ``sign = md5_hex(appkey + secretkey + timestamp)`` + query = ``appkey=X&secretkey=Y×tamp=Z&sign=S`` + +appkey/secretkey ``t.a(ctx)`` / ``h1.a(ctx)`` + 优先读 ``wcfg``(``z0.i()``,``"appkey-secretkey"`` 拆分);为空回退硬编码 + 默认值 ``appkey="16"``、``secretkey="62c80c436b7547a68a12774c67519836"``。 + +URL ``r1.a(payload, ctx)`` + ``{base}/f/a/p?{query}``,``x0.d`` = ``Base64("L2YvYS9w")`` = ``"/f/a/p"``。 + +Body ``r1.a`` 三参路径(注册上传,带 ``VIMG_`` 前缀) + ``{"data": "VIMG_" + WeaponHI.b(payload)}`` + 其中 ``payload`` 是 JSON 字符串(见 ``build_default_payload``)。 + +响应 ``i.a`` 返回 JSON 字符串。尚无证据表明响应会签发登录使用的 +``VIMG_$AI_<32hex>``;递归提取函数只用于兼容历史样本分析。 + +两个设备遥测字段仍待确认(代码内以 ``TODO(U1/U2)`` 标注): + +U1 + payload 明文结构(``build_default_payload`` 的字段集/取值),候选来自 + ``t.a()`` / ``h1.b()``,需对照抓到的请求 body 校验。 + +U2 + 历史响应中若存在 ``a_y_q_z``,确认其字段路径和业务用途。 +""" + +from __future__ import annotations + +import hashlib +import json +import os +import re +import time +import urllib.parse +from dataclasses import dataclass +from typing import Any, Callable, Mapping + +from .privacykit_encrypt import ( + PASSPORT_ACCOUNT_IMAGE_AI_MARKER, + PASSPORT_ACCOUNT_IMAGE_PREFIX, + weaponhi_vimg_upload, +) + + +# --------------------------------------------------------------------------- +# 配置(可经环境变量覆盖,与 core/sms_login.py / core/dfp_client.py 风格一致) +# --------------------------------------------------------------------------- + +DEFAULT_FAP_HOST = "https://gdfp.gifshow.com" +FAP_PATH = "/f/a/p" + +# h1.java:52 硬编码默认值(t.a() 返回空时 APP 自身回退用)。 +DEFAULT_APPKEY = "16" +DEFAULT_SECRETKEY = "62c80c436b7547a68a12774c67519836" + +WEAPON_SDK_VERSION = "7.2.1" + +# a_y_q_z 票据形态:VIMG_$AI_<32hex>。递归匹配兜底用。 +_TICKET_RE = re.compile( + re.escape(PASSPORT_ACCOUNT_IMAGE_PREFIX) + + r"[A-Za-z0-9+/]+={0,2}" + + re.escape(PASSPORT_ACCOUNT_IMAGE_AI_MARKER) + + r"[0-9a-f]{32}" +) + + +def _fap_host() -> str: + return os.environ.get("KS_FAP_HOST", DEFAULT_FAP_HOST).rstrip("/") + + +def _appkey() -> str: + return os.environ.get("KS_FAP_APPKEY", DEFAULT_APPKEY) + + +def _secretkey() -> str: + return os.environ.get("KS_FAP_SECRETKEY", DEFAULT_SECRETKEY) + + +# --------------------------------------------------------------------------- +# 签名 / query(h1.java:纯 MD5,与 atlasSign / kws 无关) +# --------------------------------------------------------------------------- + + +def build_sign(appkey: str, secretkey: str, timestamp: int) -> str: + """``md5_hex(appkey + secretkey + timestamp)``。 + + 对照 ``v0.a(String)`` = ``MessageDigest("MD5").digest(str.getBytes())``。 + """ + + raw = f"{appkey}{secretkey}{timestamp}".encode("utf-8") + return hashlib.md5(raw).hexdigest() + + +def build_query(appkey: str, secretkey: str, timestamp: int) -> str: + """``appkey=X&secretkey=Y×tamp=Z&sign=S``(``h1.d`` 顺序)。""" + + sign = build_sign(appkey, secretkey, timestamp) + # 显式保序,避免依赖 dict/HashMap 迭代顺序。 + pairs = [ + ("appkey", appkey), + ("secretkey", secretkey), + ("timestamp", str(timestamp)), + ("sign", sign), + ] + return urllib.parse.urlencode(pairs) + + +def build_fap_url(timestamp: int | None = None, *, host: str | None = None) -> str: + ts = int(timestamp if timestamp is not None else time.time()) + host = host or _fap_host() + return f"{host}{FAP_PATH}?{build_query(_appkey(), _secretkey(), ts)}" + + +# --------------------------------------------------------------------------- +# Body:{"data": "VIMG_" + WeaponHI.b(payload_json)}(r1.a 三参路径) +# --------------------------------------------------------------------------- + + +def build_fap_body(payload: Mapping[str, Any] | str) -> bytes: + """构造 ``{"data": "VIMG_" + WeaponHI.b(payload_json)}``。 + + ``payload`` 可传 dict(自动 ``json.dumps``,``separators=(',', ':')`` 紧凑) + 或已序列化的字符串。返回 UTF-8 JSON bytes。 + """ + + if isinstance(payload, str): + payload_str = payload + else: + # WeaponHI.b(str) 上游拿的是 str.getBytes();JSON 紧凑序列化对齐 Java 侧 JSONObject。 + payload_str = json.dumps(payload, separators=(",", ":"), ensure_ascii=False) + vimg = weaponhi_vimg_upload(payload_str) + return json.dumps({"data": vimg}, separators=(",", ":")).encode("utf-8") + + +# --------------------------------------------------------------------------- +# payload 明文(U1 候选,需抓证校验) +# --------------------------------------------------------------------------- + + +def build_default_payload(device_info: Mapping[str, Any] | None = None) -> dict[str, Any]: + """构造 /f/a/p payload 候选结构。 + + 候选字段来自 ``t.a()``(userId/platform/channel/mod/globalId/sysver/ + rdid/did_tag/cdid_tag)与 ``h1.b(ctx)``(k/hp/hv/pver/platform/device_id/ + sdkver/piv/sysver/mod)的并集,值从 ``device_info``(通常取自 + ``out/app_login_fields_latest.json`` 的 query_params 快照)映射。 + + # TODO(U1):抓证后用真实请求 body 校验字段集/取值/嵌套结构,回填此函数。 + """ + + info = device_info or {} + get = lambda key, default="": str(info.get(key, default) or default or "") + + return { + # t.a() 侧 + "userId": "", + "platform": get("kpf", "ANDROID_PHONE"), + "channel": get("c", get("oc", "")), + "mod": get("mod", ""), + "globalId": "", + "sysver": get("sys", ""), + "rdid": get("rdid", ""), + "did_tag": get("did_tag", ""), + "cdid_tag": get("cdid_tag", ""), + # h1.b(ctx) 侧 + "k": "", + "hp": get("kpn", "com.kuaishou.nebula"), + "hv": get("appver", ""), + "pver": "0.0.0", + "platform_h1": 1, + "device_id": get("did", get("oDid", "")), + "sdkver": WEAPON_SDK_VERSION, + } + + +# --------------------------------------------------------------------------- +# 响应解析(U2,需抓证定位精确字段路径) +# --------------------------------------------------------------------------- + + +def _iter_str_values(node: Any): + """递归遍历解析后的 JSON,产出所有字符串值。""" + + if isinstance(node, str): + yield node + elif isinstance(node, Mapping): + for v in node.values(): + yield from _iter_str_values(v) + elif isinstance(node, (list, tuple)): + for v in node: + yield from _iter_str_values(v) + + +def extract_a_y_q_z(response: Any) -> str | None: + """从 /f/a/p 响应里提取 ``a_y_q_z`` 完整票据。 + + # TODO(U2):抓证后改为精确字段路径(如 ``response["a_y_q_z"]``)。 + 当前用递归匹配 ``VIMG_...$AI_...`` 形态兜底,能覆盖顶层/嵌套两种情况。 + """ + + if response is None: + return None + if isinstance(response, str): + # 响应是裸字符串时直接匹配;否则尝试 JSON 解析后递归。 + m = _TICKET_RE.search(response) + if m: + return m.group(0) + try: + response = json.loads(response) + except Exception: + return None + for value in _iter_str_values(response): + m = _TICKET_RE.search(value) + if m: + return m.group(0) + return None + + +# --------------------------------------------------------------------------- +# HTTP(参考 core/dfp_client.post_request 的 requests 范式) +# --------------------------------------------------------------------------- + + +@dataclass(frozen=True) +class FapResponse: + ok: bool + status_code: int + data: Any + text: str + error: str = "" + + +def _default_post() -> Callable[..., Any]: + import requests + + return requests.post + + +def call_fap( + payload: Mapping[str, Any] | str, + *, + timestamp: int | None = None, + host: str | None = None, + headers: Mapping[str, str] | None = None, + timeout: int = 20, + post_func: Callable[..., Any] | None = None, +) -> FapResponse: + """POST ``/f/a/p`` 并返回解析后的响应。 + + headers 可传 k1 的 c/d(``t.b()`` 设备串 / ``t.b(ctx)`` 加密设备头)。 + 默认不送;若服务端校验 header 则从抓证固化后传入。 + """ + + post = post_func or _default_post() + ts = int(timestamp if timestamp is not None else time.time()) + url = build_fap_url(ts, host=host) + body = build_fap_body(payload) + + hdrs = {"Content-Type": "application/json; charset=utf-8"} + if headers: + hdrs.update(dict(headers)) + + try: + resp = post(url, data=body, headers=hdrs, timeout=timeout) + except Exception as exc: + return FapResponse(ok=False, status_code=0, data=None, text=str(exc), error=exc.__class__.__name__) + + text = getattr(resp, "text", "") + try: + data = resp.json() + except Exception: + try: + data = json.loads(text) + except Exception: + data = text + return FapResponse( + ok=bool(getattr(resp, "ok", False)), + status_code=int(getattr(resp, "status_code", 0)), + data=data, + text=text, + ) + + +# --------------------------------------------------------------------------- +# 顶层入口 +# --------------------------------------------------------------------------- + + +def fetch_fresh_a_y_q_z( + device_info: Mapping[str, Any] | None = None, + *, + payload: Mapping[str, Any] | str | None = None, + host: str | None = None, + headers: Mapping[str, str] | None = None, + timeout: int = 20, + post_func: Callable[..., Any] | None = None, +) -> str | None: + """取新鲜 ``a_y_q_z`` 完整票据(``VIMG_...$AI_...``)。 + + 默认用 ``build_default_payload(device_info)`` 组 payload;调用方可直接传 + ``payload``(dict 或已序列化字符串)覆盖。失败返回 None,由调用方决定回退。 + """ + + if payload is None: + payload = build_default_payload(device_info) + resp = call_fap( + payload, + host=host, + headers=headers, + timeout=timeout, + post_func=post_func, + ) + if not resp.ok: + return None + return extract_a_y_q_z(resp.data) + + +__all__ = [ + "DEFAULT_APPKEY", + "DEFAULT_FAP_HOST", + "DEFAULT_SECRETKEY", + "FAP_PATH", + "FapResponse", + "WEAPON_SDK_VERSION", + "build_default_payload", + "build_fap_body", + "build_fap_url", + "build_query", + "build_sign", + "call_fap", + "extract_a_y_q_z", + "fetch_fresh_a_y_q_z", +] diff --git a/core/h5_jsbridge.py b/core/h5_jsbridge.py new file mode 100644 index 0000000..d9fba2b --- /dev/null +++ b/core/h5_jsbridge.py @@ -0,0 +1,274 @@ +"""Nebula H5 `$encode` signInput builder and local JS-VM bridge. + +前端真实逻辑在 `main-CZ3ZSK5w.js`: + +1. 从 cookie 只取白名单设备字段; +2. 加入 `sigCatVer=1` 和接口 query/body; +3. 按 `key=value` 字符串字典序拼接; +4. 调 KsGuard/Yoda VM 的 `$encode` 生成 68hex `__NS_sig3`。 + +这里保留稳定的 signInput 组装规则和本地 VM runner fallback。正常主流程 +已经在 `core.h5_sig3` 里用纯 Python 复现 `$encode` 的摘要字段。 +""" + +from __future__ import annotations + +import json +import os +import queue +import subprocess +import threading +from dataclasses import dataclass +from pathlib import Path +from typing import Any + + +H5_COOKIE_KEYS = ( + "kpn", + "kpf", + "userId", + "did", + "c", + "appver", + "language", + "mod", + "did_tag", + "egid", + "oDid", + "androidApiLevel", + "newOc", + "browseType", + "socName", + "ftt", + "abi", + "userRecoBit", + "device_abi", + "grant_browse_type", + "iuid", + "rdid", +) + +DEFAULT_H5_ENCODE_RUNNER = Path("core/h5_vendor_encode.mjs") +DEFAULT_H5_ENCODE_SERVER = Path("core/h5_vendor_encode_server.mjs") + + +@dataclass(frozen=True) +class H5EncodeResult: + sign_input: str + sig3: str + c_info: Any = None + + +class H5JsBridgeEncoder: + """长驻 Node `$encode` 进程,避免每次签名重复加载 VM chunk。""" + + def __init__( + self, + server: str | Path = DEFAULT_H5_ENCODE_SERVER, + node_bin: str | None = None, + timeout: int = 30, + ) -> None: + self.server = Path(server) + self.node = node_bin or os.environ.get("NODE_BIN") or "node" + self.timeout = timeout + self._proc: subprocess.Popen[str] | None = None + self._stdout_queue: queue.Queue[str] = queue.Queue() + self._lock = threading.Lock() + self._request_id = 0 + + def _start(self) -> None: + if self._proc is not None and self._proc.poll() is None: + return + if not self.server.exists(): + raise FileNotFoundError(f"H5 encode server not found: {self.server}") + self._stdout_queue = queue.Queue() + self._proc = subprocess.Popen( + [self.node, str(self.server)], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + text=True, + encoding="utf-8", + bufsize=1, + ) + + def read_stdout() -> None: + assert self._proc is not None + assert self._proc.stdout is not None + for line in self._proc.stdout: + self._stdout_queue.put(line) + + thread = threading.Thread(target=read_stdout, name="H5JsBridgeEncoderStdout", daemon=True) + thread.start() + + def close(self) -> None: + proc = self._proc + self._proc = None + if proc is None: + return + try: + if proc.stdin: + proc.stdin.close() + except Exception: + pass + try: + if proc.stdout: + proc.stdout.close() + except Exception: + pass + try: + proc.wait(timeout=1) + except Exception: + try: + proc.kill() + except Exception: + pass + + def encode(self, sign_input: str) -> H5EncodeResult: + with self._lock: + self._start() + assert self._proc is not None + assert self._proc.stdin is not None + self._request_id += 1 + request_id = self._request_id + payload = json.dumps( + {"id": request_id, "signInput": sign_input}, + ensure_ascii=False, + separators=(",", ":"), + ) + try: + self._proc.stdin.write(payload + "\n") + self._proc.stdin.flush() + except Exception: + self.close() + raise + + while True: + try: + line = self._stdout_queue.get(timeout=self.timeout) + except queue.Empty as exc: + self.close() + raise TimeoutError("H5 encode server timed out") from exc + try: + data = json.loads(line) + except json.JSONDecodeError: + continue + if data.get("id") not in {request_id, None}: + continue + if not data.get("ok", True): + raise RuntimeError(f"H5 encode server failed: {data.get('error')}") + sig3 = str(data.get("result") or "") + if len(sig3) != 68: + raise RuntimeError(f"H5 encode server returned invalid sig3: {sig3!r}") + return H5EncodeResult(sign_input=sign_input, sig3=sig3, c_info=data.get("cInfo")) + + +def _js_json(value: Any) -> str: + return json.dumps(value, ensure_ascii=False, separators=(",", ":")) + + +def _h5_io(params: dict[str, Any]) -> str: + parts: list[str] = [] + for key, value in params.items(): + if key.startswith("__NS"): + continue + if isinstance(value, (dict, list)): + value = "" + parts.append(f"{key}={value}") + return "".join(sorted(parts)) + + +def build_h5_sign_input( + cookie: dict[str, str], + query: dict[str, Any] | None = None, + body: str | dict[str, Any] | list[Any] | None = None, + method: str = "GET", + request_type: str = "json", +) -> str: + """按前端 `Mc()/io()` 规则构造 `$encode` 的 secPlain。""" + selected = {key: cookie[key] for key in H5_COOKIE_KEYS if cookie.get(key)} + params: dict[str, Any] = {"sigCatVer": 1, **selected, **(query or {})} + method_lower = method.lower() + request_type_lower = request_type.lower() + + if request_type_lower == "json": + if method_lower in {"get", "options", "head"}: + if isinstance(body, dict): + params.update(body) + return _h5_io(params) + if body is None: + body_text = "" + elif isinstance(body, str): + body_text = body + else: + body_text = _js_json(body) + return _h5_io(params) + body_text + + if request_type_lower == "form" and isinstance(body, dict): + params.update(body) + return _h5_io(params) + + +def encode_h5_sig3_with_runner( + sign_input: str, + runner: str | Path = DEFAULT_H5_ENCODE_RUNNER, + node_bin: str | None = None, + timeout: int = 30, +) -> H5EncodeResult: + """调用本地 JS-VM runner 生成 H5 68hex `__NS_sig3`。""" + runner_path = Path(runner) + if not runner_path.exists(): + raise FileNotFoundError(f"H5 encode runner not found: {runner_path}") + + node = node_bin or os.environ.get("NODE_BIN") or "node" + proc = subprocess.run( + [node, str(runner_path), "-"], + input=sign_input, + text=True, + capture_output=True, + timeout=timeout, + check=False, + ) + if proc.returncode != 0: + detail = (proc.stderr or proc.stdout or "").strip() + raise RuntimeError(f"H5 encode runner failed: {detail}") + data = json.loads(proc.stdout) + sig3 = str(data.get("result") or "") + if len(sig3) != 68: + raise RuntimeError(f"H5 encode runner returned invalid sig3: {sig3!r}") + return H5EncodeResult(sign_input=sign_input, sig3=sig3, c_info=data.get("cInfo")) + + +def h5_sig3_for_request( + cookie: dict[str, str], + query: dict[str, Any] | None = None, + body: str | dict[str, Any] | list[Any] | None = None, + method: str = "GET", + request_type: str = "json", + runner: str | Path = DEFAULT_H5_ENCODE_RUNNER, + node_bin: str | None = None, + timeout: int = 30, + encoder: H5JsBridgeEncoder | None = None, +) -> H5EncodeResult: + sign_input = build_h5_sign_input( + cookie, + query=query, + body=body, + method=method, + request_type=request_type, + ) + if encoder is not None: + return encoder.encode(sign_input) + return encode_h5_sig3_with_runner(sign_input, runner=runner, node_bin=node_bin, timeout=timeout) + + +__all__ = [ + "DEFAULT_H5_ENCODE_RUNNER", + "DEFAULT_H5_ENCODE_SERVER", + "H5_COOKIE_KEYS", + "H5EncodeResult", + "H5JsBridgeEncoder", + "build_h5_sign_input", + "encode_h5_sig3_with_runner", + "h5_sig3_for_request", +] diff --git a/core/h5_kws.py b/core/h5_kws.py new file mode 100644 index 0000000..37b67b9 --- /dev/null +++ b/core/h5_kws.py @@ -0,0 +1,356 @@ +"""Pure-Python KWS/WebWeapon fallback ticket generator. + +The Nebula H5 bundle initializes WebWeapon roughly as: + +- product cookie: ``kwpsecproductname=kuaishou-growth``; +- fallback fingerprint: AES-CBC(``...|nonce8``, key=iv ``K8wm...``) + wrapped as ``K + b64[:4] + W + b64[4:-2] + F + b64[-2:]``; +- fallback signature token: random 64-char ``kwssectoken`` plus + AES-CBC(``...|kwssectoken[:8]``, key=iv ``H4t...``) wrapped with ``S``. + +When the online Web DFP config succeeds, APP may replace these with +server-provided ``secToken`` + sign-script output. This module implements the +local fallback path so a fresh ``ksck`` does not need stale copied KWS cookies. +""" + +from __future__ import annotations + +import base64 +import json +import os +import re +import secrets +import subprocess +import time +from dataclasses import dataclass +from pathlib import Path +from random import Random +from typing import Any, Mapping, Protocol +from urllib.parse import quote + +from core.h5_kww_alg import kwf_aes_cbc_decrypt, kwf_aes_cbc_encrypt + + +KWS_PRODUCT_NAME = "kuaishou-growth" +KWS_FINGERPRINT_KEY = "K8wm5PvY9nX7qJc2" +KWS_TOKEN_KEY = "H4tL6rNd3vB9xM5k" +KWS_CONFIG_KEY = "webweaponconfigs" +KWS_CONFIG_URL = "https://gdfp.gifshow.com/s/w/c" +KWS_RANDOM_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" +KWS_URL_SLICE_LEN = 80 +KWS_SCRIPT_CODE_RE = re.compile(r"^[0-9a-z]{64}$") +DEFAULT_KWS_SIGN_RUNNER = Path(__file__).with_name("h5_kws_sign.mjs") +DEFAULT_KWS_SIGN_SCRIPT = Path(__file__).with_name("kws-11-0.0.1-obfuscated.5e0a90af726d8a7e.js") + + +class _RandLike(Protocol): + def randrange(self, stop: int) -> int: ... + + +@dataclass(frozen=True) +class H5KwsTicket: + kwpsecproductname: str + kwssectoken: str + kwscode: str + kwfv1: str + kww: str + fingerprint_plain: str + token_plain: str + + def cookie_fields(self, *, include_fingerprint: bool = True) -> dict[str, str]: + fields = { + "kwpsecproductname": self.kwpsecproductname, + "kwssectoken": self.kwssectoken, + "kwscode": self.kwscode, + } + if include_fingerprint: + fields["kwfv1"] = self.kwfv1 + return fields + + +@dataclass(frozen=True) +class H5KwsConfigRequest: + product_name: str + ts: int + did: str + plain: str + data: str + url: str = KWS_CONFIG_URL + + def body(self) -> dict[str, str]: + return {"data": self.data} + + +def _now_ms() -> int: + return int(time.time() * 1000) + + +def _random_text(length: int, rng: _RandLike | None = None) -> str: + alphabet = KWS_RANDOM_ALPHABET + if rng is None: + return "".join(secrets.choice(alphabet) for _ in range(length)) + return "".join(alphabet[rng.randrange(len(alphabet))] for _ in range(length)) + + +def _encode_uri(value: str) -> str: + """Match JavaScript ``encodeURI`` for the URL prefix used by WebWeapon.""" + + return quote(str(value), safe=";/?:@&=+$,#-_.!~*'()") + + +def _encrypt_webweapon_b64(plain: str, key_text: str) -> str: + key = key_text.encode("utf-8") + encrypted = kwf_aes_cbc_encrypt(plain.encode("utf-8"), key=key, iv=key) + return base64.b64encode(encrypted).decode("ascii") + + +def webweapon_aes_encrypt_b64( + plain: str, + key_text: str = KWS_CONFIG_KEY, +) -> str: + """AES-CBC/PKCS7 + Base64 used by WebWeapon config payloads.""" + + return _encrypt_webweapon_b64(str(plain), key_text) + + +def webweapon_aes_decrypt_b64( + encrypted_b64: str, + key_text: str = KWS_CONFIG_KEY, +) -> str: + """Decrypt WebWeapon AES-CBC/PKCS7 Base64 text.""" + + key = key_text.encode("utf-8") + try: + encrypted = base64.b64decode(encrypted_b64, validate=True) + plain = kwf_aes_cbc_decrypt(encrypted, key=key, iv=key) + except Exception as exc: + raise ValueError("invalid WebWeapon AES payload") from exc + return plain.decode("utf-8") + + +def _wrap_webweapon_value(encrypted_b64: str, marker: str) -> str: + return f"K{encrypted_b64[:4]}W{encrypted_b64[4:-2]}{marker}{encrypted_b64[-2:]}" + + +def is_h5_kws_script_code(value: str) -> bool: + """Validate the 64-char code emitted by the KWS ``signUrl`` script.""" + + return bool(KWS_SCRIPT_CODE_RE.fullmatch(str(value or ""))) + + +def _short_runner_error(stdout: str, stderr: str) -> str: + detail = (stderr or stdout or "").strip() + if len(detail) <= 500: + return detail + return detail[:240] + "...(truncated)..." + detail[-240:] + + +def run_h5_kws_sign_script( + *, + script_path: str | Path | None = None, + runner: str | Path = DEFAULT_KWS_SIGN_RUNNER, + node_bin: str | None = None, + timeout: int = 10, +) -> str: + """Run the local KWS ``signUrl`` VM script and return ``kwscode``. + + This is the script-equivalent path for the online WebWeapon config mode: + ``/s/w/c`` gives ``secToken`` + ``signUrl``; loading that sign script calls + ``window.kwscb(code)``. The Node runner supplies a deterministic browser + fixture and captures the callback result. + """ + + runner_path = Path(runner) + script = Path(script_path) if script_path is not None else DEFAULT_KWS_SIGN_SCRIPT + if not runner_path.exists(): + raise FileNotFoundError(f"KWS sign runner not found: {runner_path}") + if not script.exists(): + raise FileNotFoundError(f"KWS sign script not found: {script}") + + node = node_bin or os.environ.get("NODE_BIN") or "node" + proc = subprocess.run( + [node, str(runner_path), str(script)], + text=True, + encoding="utf-8", + capture_output=True, + timeout=timeout, + check=False, + ) + if proc.returncode != 0: + raise RuntimeError(f"KWS sign runner failed: {_short_runner_error(proc.stdout, proc.stderr)}") + try: + data = json.loads(proc.stdout) + except json.JSONDecodeError as exc: + raise RuntimeError(f"KWS sign runner returned invalid JSON: {_short_runner_error(proc.stdout, proc.stderr)}") from exc + if not data.get("ok"): + raise RuntimeError(f"KWS sign runner failed: {data.get('error')}") + kwscode = str(data.get("kwscode") or "") + if not is_h5_kws_script_code(kwscode): + raise RuntimeError(f"KWS sign runner returned invalid kwscode length/shape: {kwscode!r}") + return kwscode + + +def build_h5_kws_script_ticket( + *, + sec_token: str, + kwscode: str | None = None, + product_name: str = KWS_PRODUCT_NAME, + script_path: str | Path | None = None, + runner: str | Path = DEFAULT_KWS_SIGN_RUNNER, + node_bin: str | None = None, + timeout: int = 10, +) -> dict[str, str]: + """Build KWS cookie fields from server ``secToken`` and sign script code.""" + + token = str(sec_token or "") + if not token: + raise ValueError("sec_token must be non-empty") + code = kwscode + if not code: + script = Path(script_path) if script_path is not None else DEFAULT_KWS_SIGN_SCRIPT + try: + from core.h5_kws_vm import kwscode_from_known_h5_kws_script + + code = kwscode_from_known_h5_kws_script(script) + except Exception: + code = None + if not code: + code = run_h5_kws_sign_script( + script_path=script_path, + runner=runner, + node_bin=node_bin, + timeout=timeout, + ) + if not is_h5_kws_script_code(code): + raise ValueError("kwscode must be a 64-char lowercase alnum KWS script code") + return { + "kwpsecproductname": product_name, + "kwssectoken": token, + "kwscode": code, + } + + +def build_h5_kws_default_ticket( + *, + url: str, + did: str, + product_name: str = KWS_PRODUCT_NAME, + now_ms: int | None = None, + fingerprint_nonce: str | None = None, + sec_token: str | None = None, + rng: Random | None = None, +) -> H5KwsTicket: + """Build WebWeapon ``getDefaultData(true)`` ticket fields. + + ``fingerprint_nonce`` corresponds to the random 8-char suffix used for the + fallback ``kwfv1``. ``sec_token`` corresponds to the 64-char + ``kwssectoken``; its first 8 chars are folded into ``kwscode``. + """ + + ts = _now_ms() if now_ms is None else int(now_ms) + fp_nonce = fingerprint_nonce if fingerprint_nonce is not None else _random_text(8, rng) + if len(fp_nonce) != 8: + raise ValueError("fingerprint_nonce must be 8 characters") + + token = sec_token if sec_token is not None else _random_text(64, rng) + if len(token) != 64: + raise ValueError("sec_token must be 64 characters") + + url_prefix = _encode_uri(str(url)[:KWS_URL_SLICE_LEN]) + common = f"{url_prefix}|{did}|{product_name}|{ts}|" + fingerprint_plain = common + fp_nonce + token_plain = common + token[:8] + + kwfv1 = _wrap_webweapon_value( + _encrypt_webweapon_b64(fingerprint_plain, KWS_FINGERPRINT_KEY), + "F", + ) + kwscode = _wrap_webweapon_value( + _encrypt_webweapon_b64(token_plain, KWS_TOKEN_KEY), + "S", + ) + return H5KwsTicket( + kwpsecproductname=product_name, + kwssectoken=token, + kwscode=kwscode, + kwfv1=kwfv1, + kww=kwfv1, + fingerprint_plain=fingerprint_plain, + token_plain=token_plain, + ) + + +def build_h5_kws_config_request_data( + *, + did: str, + product_name: str = KWS_PRODUCT_NAME, + ts_ms: int | None = None, +) -> H5KwsConfigRequest: + """Build the encrypted ``/s/w/c`` config POST body. + + WebWeapon sends compact JSON in this exact key order: + ``productName`` → ``ts`` → ``did``. The JSON string is encrypted with + AES-CBC where key and IV are both ``webweaponconfigs``. + """ + + ts = _now_ms() if ts_ms is None else int(ts_ms) + payload = { + "productName": product_name, + "ts": ts, + "did": str(did), + } + plain = json.dumps(payload, ensure_ascii=False, separators=(",", ":")) + return H5KwsConfigRequest( + product_name=product_name, + ts=ts, + did=str(did), + plain=plain, + data=webweapon_aes_encrypt_b64(plain, KWS_CONFIG_KEY), + ) + + +def decrypt_h5_kws_config_response_data_rsp(data_rsp: str) -> dict[str, Any]: + """Decrypt the ``dataRsp`` field returned by ``/s/w/c``.""" + + plain = webweapon_aes_decrypt_b64(data_rsp, KWS_CONFIG_KEY) + try: + decoded = json.loads(plain) + except json.JSONDecodeError as exc: + raise ValueError("WebWeapon config response is not JSON") from exc + if not isinstance(decoded, dict): + raise ValueError("WebWeapon config response must be a JSON object") + return decoded + + +def decrypt_h5_kws_config_response(response: Mapping[str, Any]) -> dict[str, Any]: + """Decrypt a full ``/s/w/c`` JSON response object containing ``dataRsp``.""" + + data_rsp = response.get("dataRsp") + if not isinstance(data_rsp, str) or not data_rsp: + raise ValueError("WebWeapon config response is missing dataRsp") + return decrypt_h5_kws_config_response_data_rsp(data_rsp) + + +__all__ = [ + "DEFAULT_KWS_SIGN_RUNNER", + "DEFAULT_KWS_SIGN_SCRIPT", + "H5KwsTicket", + "H5KwsConfigRequest", + "KWS_CONFIG_KEY", + "KWS_CONFIG_URL", + "KWS_FINGERPRINT_KEY", + "KWS_PRODUCT_NAME", + "KWS_RANDOM_ALPHABET", + "KWS_SCRIPT_CODE_RE", + "KWS_TOKEN_KEY", + "KWS_URL_SLICE_LEN", + "build_h5_kws_script_ticket", + "build_h5_kws_config_request_data", + "build_h5_kws_default_ticket", + "decrypt_h5_kws_config_response", + "decrypt_h5_kws_config_response_data_rsp", + "is_h5_kws_script_code", + "run_h5_kws_sign_script", + "webweapon_aes_decrypt_b64", + "webweapon_aes_encrypt_b64", +] diff --git a/core/h5_kws_sign.mjs b/core/h5_kws_sign.mjs new file mode 100644 index 0000000..cbf1e3d --- /dev/null +++ b/core/h5_kws_sign.mjs @@ -0,0 +1,307 @@ +import crypto from "node:crypto"; +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath, pathToFileURL } from "node:url"; +import vm from "node:vm"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const DEFAULT_KWS_FILE = path.join( + __dirname, + "kws-11-0.0.1-obfuscated.5e0a90af726d8a7e.js", +); + +const MAX_EVENTS = Number(process.env.KS_KWS_MAX_EVENTS || 240); + +function sha16(value) { + return crypto.createHash("sha256").update(String(value)).digest("hex").slice(0, 16); +} + +function preview(value) { + try { + if (value === null) return "null"; + if (value === undefined) return "undefined"; + if (typeof value === "string") { + return value.length > 120 ? `${value.slice(0, 120)}...(len=${value.length})` : value; + } + if (typeof value === "number" || typeof value === "boolean") return value; + if (typeof value === "function") return `[function ${value.name || "anonymous"}]`; + if (Array.isArray(value)) return `[array len=${value.length}]`; + return `[object ${Object.keys(value).slice(0, 8).join(",")}]`; + } catch { + return "[unpreviewable]"; + } +} + +function buildContext() { + const events = []; + const record = (type, detail = {}) => { + if (events.length >= MAX_EVENTS) return; + events.push({ type, ...detail }); + }; + + const mockCache = new Map(); + function mock(name = "mock") { + if (mockCache.has(name)) return mockCache.get(name); + const fn = function (...args) { + record("call", { path: name, args: args.map(preview) }); + return mock(`${name}()`); + }; + const proxy = new Proxy(fn, { + get(_target, prop) { + if (prop === Symbol.toPrimitive) return () => ""; + if (prop === "toString") return () => `[mock ${name}]`; + if (prop === "valueOf") return () => 0; + if (prop === "then") return undefined; + return mock(`${name}.${String(prop)}`); + }, + set(_target, prop, value) { + record("mock-set", { path: `${name}.${String(prop)}`, value: preview(value) }); + return true; + }, + apply(_target, _thisArg, args) { + record("apply", { path: name, args: args.map(preview) }); + return mock(`${name}()`); + }, + construct(_target, args) { + record("new", { path: name, args: args.map(preview) }); + return mock(`new ${name}`); + }, + has() { + return true; + }, + }); + mockCache.set(name, proxy); + return proxy; + } + + const storage = new Map(); + const localStorage = { + getItem(key) { + const text = String(key); + const value = storage.get(text) || null; + record("localStorage.getItem", { key: text, value: preview(value) }); + return value; + }, + setItem(key, value) { + const text = String(key); + storage.set(text, String(value)); + record("localStorage.setItem", { key: text, value: preview(String(value)) }); + }, + removeItem(key) { + storage.delete(String(key)); + record("localStorage.removeItem", { key: String(key) }); + }, + clear() { + storage.clear(); + record("localStorage.clear"); + }, + }; + + class FakeXMLHttpRequest { + open(method, url) { + this.method = method; + this.url = url; + record("xhr.open", { method: preview(method), url: preview(url) }); + } + setRequestHeader(key, value) { + record("xhr.setRequestHeader", { key: preview(key), value: preview(value) }); + } + send(body) { + record("xhr.send", { url: preview(this.url), body: preview(body) }); + this.readyState = 4; + this.status = 200; + this.responseText = "{}"; + if (typeof this.onreadystatechange === "function") this.onreadystatechange(); + if (typeof this.onload === "function") this.onload(); + } + addEventListener(name, cb) { + record("xhr.addEventListener", { name: preview(name), cb: preview(cb) }); + } + } + + let kwscode = ""; + const rawWindow = {}; + const windowProxy = new Proxy(rawWindow, { + get(target, prop) { + if (prop in target) return target[prop]; + const key = String(prop); + const value = mock(`window.${key}`); + target[prop] = value; + record("window.get-unknown", { key }); + return value; + }, + set(target, prop, value) { + target[prop] = value; + record("window.set", { key: String(prop), value: preview(value) }); + return true; + }, + has() { + return true; + }, + }); + + Object.assign(rawWindow, { + window: windowProxy, + self: windowProxy, + top: windowProxy, + parent: windowProxy, + globalThis: windowProxy, + Object, + Array, + String, + Function, + Number, + Boolean, + Date, + Math, + RegExp, + Error, + TypeError, + Promise, + JSON, + Infinity, + undefined, + Uint8Array, + parseInt, + parseFloat, + isNaN, + escape, + encodeURI, + encodeURIComponent, + decodeURI, + decodeURIComponent, + Window: function Window() {}, + Navigator: function Navigator() {}, + Location: function Location() {}, + kwscb(value) { + kwscode = String(value || ""); + record("kwscb", { length: kwscode.length, sha16: sha16(kwscode) }); + }, + location: { + href: "https://nebula.kuaishou.com/nebula/task/earning?layoutType=4&source=bottom_guide_first", + origin: "https://nebula.kuaishou.com", + protocol: "https:", + host: "nebula.kuaishou.com", + hostname: "nebula.kuaishou.com", + pathname: "/nebula/task/earning", + search: "?layoutType=4&source=bottom_guide_first", + }, + document: { + cookie: "kpn=NEBULA; kpf=ANDROID_PHONE; userId=0; did=ANDROID_FAKE; kuaishou.h5_st=FAKE", + referrer: "", + createElement(tag) { + record("document.createElement", { tag: preview(tag) }); + return mock(`element.${tag}`); + }, + getElementsByTagName(tag) { + record("document.getElementsByTagName", { tag: preview(tag) }); + return [mock(`tag.${tag}`)]; + }, + addEventListener(name, cb) { + record("document.addEventListener", { name: preview(name), cb: preview(cb) }); + }, + body: mock("document.body"), + head: mock("document.head"), + documentElement: mock("document.documentElement"), + }, + navigator: { + userAgent: + "Mozilla/5.0 (Linux; Android 16; PJZ110 Build/BP2A.250605.015; wv) AppleWebKit/537.36", + language: "zh-CN", + languages: ["zh-CN", "zh"], + platform: "Linux armv8l", + webdriver: false, + }, + screen: { width: 1080, height: 2376, colorDepth: 24, pixelDepth: 24 }, + localStorage, + sessionStorage: localStorage, + performance: { now: () => 1234.5, timing: {}, getEntriesByType: () => [] }, + crypto: { + getRandomValues(arr) { + for (let i = 0; i < arr.length; i += 1) arr[i] = (i * 17 + 3) & 0xff; + return arr; + }, + }, + Image: function Image() { + return mock("new Image"); + }, + XMLHttpRequest: FakeXMLHttpRequest, + fetch(url, init) { + record("fetch", { url: preview(url), init: preview(init) }); + return Promise.resolve({ + ok: true, + status: 200, + text: () => Promise.resolve("{}"), + json: () => Promise.resolve({}), + }); + }, + setTimeout(cb) { + record("setTimeout", { cb: preview(cb) }); + if (typeof cb === "function") cb(); + return 1; + }, + clearTimeout() {}, + setInterval(cb) { + record("setInterval", { cb: preview(cb) }); + return 1; + }, + clearInterval() {}, + console: { + log: (...args) => record("console.log", { args: args.map(preview) }), + warn: (...args) => record("console.warn", { args: args.map(preview) }), + error: (...args) => record("console.error", { args: args.map(preview) }), + }, + }); + + const context = vm.createContext(windowProxy, { + name: "h5-kws-sign", + codeGeneration: { strings: true, wasm: false }, + }); + + return { + context, + events, + rawWindow, + getKwscode: () => kwscode, + }; +} + +export function runKwsSignScript(scriptPath = DEFAULT_KWS_FILE, timeoutMs = 5000) { + const { context, events, rawWindow, getKwscode } = buildContext(); + const code = fs.readFileSync(scriptPath, "utf8"); + const beforeKeys = new Set(Object.keys(rawWindow)); + vm.runInContext(code, context, { filename: scriptPath, timeout: timeoutMs }); + const kwscode = getKwscode(); + if (!kwscode) { + throw new Error("KWS script did not call kwscb()"); + } + const eventTypeCounts = {}; + for (const event of events) eventTypeCounts[event.type] = (eventTypeCounts[event.type] || 0) + 1; + return { + ok: true, + kwscode, + length: kwscode.length, + sha16: sha16(kwscode), + newWindowKeys: Object.keys(rawWindow).filter((key) => !beforeKeys.has(key)), + eventTypeCounts, + }; +} + +async function main() { + const scriptPath = process.argv[2] || DEFAULT_KWS_FILE; + const timeoutMs = Number(process.env.KS_KWS_VM_TIMEOUT_MS || 5000); + try { + const result = runKwsSignScript(scriptPath, timeoutMs); + console.log(JSON.stringify(result)); + } catch (err) { + const message = String(err && err.stack ? err.stack : err); + console.log(JSON.stringify({ ok: false, error: message.split(/\r?\n/).slice(0, 12).join("\n") })); + process.exitCode = 1; + } +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + await main(); +} diff --git a/core/h5_kws_vm.py b/core/h5_kws_vm.py new file mode 100644 index 0000000..553716b --- /dev/null +++ b/core/h5_kws_vm.py @@ -0,0 +1,507 @@ +"""Static container parser for the KWS/Jimbei sign script. + +`kws-11-*.js` is wrapped as a Jimbei/Sabo VM: + +``` +Jimbei()(window, {"b": "", "d": [constants...]}); +``` + +The full interpreter is still JavaScript, but the container is stable enough +to parse in pure Python. This module extracts bytecode/constants metadata and +provides a pure static answer for the currently bundled sign script. +""" + +from __future__ import annotations + +import base64 +import hashlib +import json +from collections import Counter +from dataclasses import dataclass +from pathlib import Path +from typing import Any + + +H5_KWS_KNOWN_SCRIPT_CODE = "04dd303d63222chdfec0087d058fb1c4c5f2eb16eefgce98b2a503578e5f8433" + +H5_KWS_KNOWN_SCRIPT_SHA256 = "d944b2bc3754bec85c0a238fb052859295a3ecb0756789c47d99417d3f957615" +H5_KWS_KNOWN_BYTECODE_SHA256 = "7668fe4c01dc4721a862b3102cd3c183dbd4721cac6af4129fc2adcdd1d701d8" +H5_KWS_KNOWN_CONSTANTS_SHA256 = "226815ab9e5d21ce285afa698b618be3ff5122cf13880c846600b6e7d1396afe" + +_KNOWN_CODE_BY_SCRIPT_SHA256 = { + H5_KWS_KNOWN_SCRIPT_SHA256: H5_KWS_KNOWN_SCRIPT_CODE, +} +_KNOWN_CODE_BY_VM_SHA256 = { + (H5_KWS_KNOWN_BYTECODE_SHA256, H5_KWS_KNOWN_CONSTANTS_SHA256): H5_KWS_KNOWN_SCRIPT_CODE, +} + + +@dataclass(frozen=True) +class H5KwsFunctionRange: + instruction_index: int + start_const_index: int + end_const_index: int + start: int + end: int + + @property + def length(self) -> int: + return self.end - self.start + 1 + + +@dataclass(frozen=True) +class H5KwsVmSummary: + script_sha256: str + bytecode_sha256: str + constants_sha256: str + instruction_count: int + constant_count: int + min_opcode: int + max_opcode: int + opcode_histogram: dict[int, int] + function_ranges: list[H5KwsFunctionRange] + + +@dataclass(frozen=True) +class H5KwsOpcodeHandler: + index: int + present: bool + label: str + used_count: int + body_sha16: str + body_preview: str + + +@dataclass(frozen=True) +class H5KwsInstruction: + index: int + opcode: int + label: str + p0: int + p1: int + p2: int + p3: int + operand_a: str + operand_b: str + + def to_text(self) -> str: + return ( + f"{self.index:04d}: op{self.opcode:02d} {self.label:<22} " + f"{self.operand_a:<22} {self.operand_b}" + ) + + +@dataclass(frozen=True) +class H5KwsFunctionAnalysis: + ordinal: int + name: str + create_index: int + assigned_scope: int | None + start: int + end: int + length: int + call_apply_count: int + branch_targets: list[int] + opcode_histogram: dict[int, int] + + +_OPCODE_LABELS = { + 0: "construct_new", + 1: "bit_and", + 2: "shift_left", + 3: "pre_dec_assign", + 4: "throw_stack", + 5: "less_equal", + 6: "bit_or", + 7: "pop_saved_result_to_r4", + 8: "add", + 9: "return_value", + 10: "bit_xor", + 11: "noop", + 12: "make_function", + 13: "in_operator", + 14: "bit_not", + 15: "hole_unused", + 16: "push_result_save", + 17: "enter_closure_scope", + 18: "jump", + 19: "post_inc_assign", + 20: "not_strict_equal", + 21: "typeof", + 22: "not_equal", + 23: "shift_right", + 24: "call_apply", + 25: "make_reference", + 26: "leave_scope", + 27: "pre_inc_assign", + 28: "push_r0", + 29: "multiply", + 30: "return_undefined", + 31: "modulo", + 32: "noop", + 33: "try_catch_finally", + 34: "declare_undefined", + 35: "divide", + 36: "subtract", + 37: "object_literal", + 38: "logical_not", + 39: "store_global_object", + 40: "strict_equal", + 41: "greater_equal", + 42: "instanceof", + 43: "unary_minus", + 44: "jump_if_false", + 45: "stack_length_to_r3", + 46: "load_value", + 47: "logical_and", + 48: "delete_property", + 49: "array_from_stack", + 50: "peek_saved_result_to_r4", + 51: "shift_unsigned_right", + 52: "post_dec_assign", + 53: "noop", + 54: "pop_stack_to_r1", + 55: "peek_stack_to_r0", + 56: "jump_sentinel", + 57: "logical_or", + 58: "unary_plus", + 59: "greater_than", + 60: "equal", + 61: "jump_if_true", + 62: "load_global_store", + 63: "debugger", + 64: "less_than", + 65: "assign_reference", + 66: "enter_null_scope", +} + + +def _find_matching_js_bracket(text: str, open_index: int) -> int: + pairs = {"[": "]", "{": "}", "(": ")"} + opener = text[open_index] + closer = pairs[opener] + depth = 1 + quote: str | None = None + escaped = False + for index in range(open_index + 1, len(text)): + ch = text[index] + if quote: + if escaped: + escaped = False + elif ch == "\\": + escaped = True + elif ch == quote: + quote = None + continue + if ch in {"'", '"', "`"}: + quote = ch + elif ch == opener: + depth += 1 + elif ch == closer: + depth -= 1 + if depth == 0: + return index + raise ValueError("matching JavaScript bracket not found") + + +def _split_top_level_js_array(array_text: str) -> list[str]: + parts: list[str] = [] + start = 0 + depth = 0 + quote: str | None = None + escaped = False + for index, ch in enumerate(array_text): + if quote: + if escaped: + escaped = False + elif ch == "\\": + escaped = True + elif ch == quote: + quote = None + continue + if ch in {"'", '"', "`"}: + quote = ch + elif ch in "[{(": + depth += 1 + elif ch in "]})": + depth -= 1 + elif ch == "," and depth == 0: + parts.append(array_text[start:index].strip()) + start = index + 1 + parts.append(array_text[start:].strip()) + return parts + + +def _extract_js_array_literal(script_text: str, var_name: str) -> list[str]: + marker = f"var {var_name} = [" + marker_pos = script_text.find(marker) + if marker_pos < 0: + raise ValueError(f"{var_name} array not found") + open_index = script_text.find("[", marker_pos + len(f"var {var_name} = ")) + close_index = _find_matching_js_bracket(script_text, open_index) + return _split_top_level_js_array(script_text[open_index + 1 : close_index]) + + +def _extract_jimbei_container(script_text: str) -> dict[str, Any]: + marker = "Jimbei()(window," + marker_pos = script_text.find(marker) + if marker_pos < 0: + raise ValueError("KWS Jimbei invocation not found") + object_start = script_text.find("{", marker_pos + len(marker)) + if object_start < 0: + raise ValueError("KWS Jimbei container object not found") + container, _end = json.JSONDecoder().raw_decode(script_text[object_start:]) + if not isinstance(container, dict): + raise ValueError("KWS Jimbei container must be a JSON object") + if not isinstance(container.get("b"), str) or not isinstance(container.get("d"), list): + raise ValueError("KWS Jimbei container must contain b:string and d:list") + return container + + +def _decode_bytecode_values(encoded: str) -> list[int]: + # Jimbei's loader applies Base64 -> UTF-8 string -> charCodeAt(char) - 1. + decoded_text = base64.b64decode(encoded, validate=True).decode("utf-8") + values = [ord(ch) - 1 for ch in decoded_text] + if len(values) % 5 != 0: + raise ValueError("KWS bytecode value count must be divisible by 5") + return values + + +def _instruction_rows(values: list[int]) -> list[list[int]]: + return [values[i : i + 5] for i in range(0, len(values), 5)] + + +def _bytecode_hash(values: list[int]) -> str: + # Keep the historical corpus hash stable: the VM bytes are stored as + # integer cells; cells above 255 are represented by their low byte here. + return hashlib.sha256(bytes((value & 0xFF) for value in values)).hexdigest() + + +def _constants_hash(constants: list[Any]) -> str: + text = json.dumps(constants, ensure_ascii=False, separators=(",", ":")) + return hashlib.sha256(text.encode("utf-8")).hexdigest() + + +def _constant_int(constants: list[Any], source_type: int, const_index: int) -> int | None: + if source_type != 6 or const_index < 0 or const_index >= len(constants): + return None + value = constants[const_index] + return value if isinstance(value, int) else None + + +def _format_operand(constants: list[Any], source_type: int, operand_index: int) -> str: + if source_type == 0: + return f"unused({operand_index})" + if source_type == 1: + return f"reg[{operand_index}]" + if source_type == 2: + return f"arg[{operand_index}]" + if source_type == 3: + return f"scope[{operand_index}]" + if source_type == 4: + name = constants[operand_index] if 0 <= operand_index < len(constants) else None + return f"window_const[{operand_index}]={name!r}" + if source_type == 5: + return f"this[{operand_index}]" + if source_type == 6: + value = constants[operand_index] if 0 <= operand_index < len(constants) else None + return f"const[{operand_index}]={value!r}" + if source_type == 7: + return f"callctx[{operand_index}]" + if source_type == 8: + return f"global_store[{operand_index}]" + return f"src{source_type}[{operand_index}]" + + +def _extract_function_ranges(rows: list[list[int]], constants: list[Any]) -> list[H5KwsFunctionRange]: + ranges: list[H5KwsFunctionRange] = [] + for instruction_index, row in enumerate(rows): + opcode, p0, p1, p2, p3 = row + if opcode != 12: + continue + start = _constant_int(constants, p0, p1) + end = _constant_int(constants, p2, p3) + if start is None or end is None: + continue + if 0 <= start <= end < len(rows): + ranges.append( + H5KwsFunctionRange( + instruction_index=instruction_index, + start_const_index=p1, + end_const_index=p3, + start=start, + end=end, + ) + ) + return ranges + + +def _assigned_scope_after_create(rows: list[list[int]], create_index: int) -> int | None: + next_index = create_index + 1 + if next_index >= len(rows): + return None + opcode, p0, p1, p2, _p3 = rows[next_index] + # make_function leaves the new function in VM reg0. A following + # assign_reference(scope[x], reg0) means the function is named by scope[x]. + if opcode == 65 and p0 == 3 and p2 == 1: + return p1 + return None + + +def _function_name(start: int, end: int, assigned_scope: int | None) -> str: + if start == 3063 and end == 4407 and assigned_scope == 80: + return "scope80_main_orchestrator" + if start == 4662 and end == 4663: + return "inline_return_undefined_stub" + if start == 4664 and end == 4675: + return "inline_call_scope107_with_arg0" + if assigned_scope is not None: + return f"scope{assigned_scope}_fn_{start}_{end}" + return f"inline_fn_{start}_{end}" + + +def _branch_target(constants: list[Any], row: list[int]) -> int | None: + opcode, p0, p1, _p2, _p3 = row + if opcode not in {18, 44, 61}: + return None + target = constants[p1] if p0 == 6 and 0 <= p1 < len(constants) else p1 + return target if isinstance(target, int) else None + + +def parse_h5_kws_vm_script(script_path: str | Path) -> H5KwsVmSummary: + script = Path(script_path).read_text(encoding="utf-8") + container = _extract_jimbei_container(script) + constants = container["d"] + values = _decode_bytecode_values(container["b"]) + rows = _instruction_rows(values) + opcodes = [row[0] for row in rows] + histogram = dict(sorted(Counter(opcodes).items())) + return H5KwsVmSummary( + script_sha256=hashlib.sha256(script.encode("utf-8")).hexdigest(), + bytecode_sha256=_bytecode_hash(values), + constants_sha256=_constants_hash(constants), + instruction_count=len(rows), + constant_count=len(constants), + min_opcode=min(opcodes), + max_opcode=max(opcodes), + opcode_histogram=histogram, + function_ranges=_extract_function_ranges(rows, constants), + ) + + +def analyze_h5_kws_function_ranges(script_path: str | Path) -> list[H5KwsFunctionAnalysis]: + """Summarize Jimbei function ranges with names, branches and call counts.""" + + script = Path(script_path).read_text(encoding="utf-8") + container = _extract_jimbei_container(script) + constants = container["d"] + rows = _instruction_rows(_decode_bytecode_values(container["b"])) + ranges = _extract_function_ranges(rows, constants) + analyses: list[H5KwsFunctionAnalysis] = [] + for ordinal, function_range in enumerate(ranges): + body_rows = rows[function_range.start : function_range.end + 1] + histogram = dict(sorted(Counter(row[0] for row in body_rows).items())) + branch_targets = [ + target + for row in body_rows + if (target := _branch_target(constants, row)) is not None + ] + assigned_scope = _assigned_scope_after_create(rows, function_range.instruction_index) + analyses.append( + H5KwsFunctionAnalysis( + ordinal=ordinal, + name=_function_name(function_range.start, function_range.end, assigned_scope), + create_index=function_range.instruction_index, + assigned_scope=assigned_scope, + start=function_range.start, + end=function_range.end, + length=function_range.length, + call_apply_count=histogram.get(24, 0), + branch_targets=branch_targets, + opcode_histogram=histogram, + ) + ) + return analyses + + +def extract_h5_kws_opcode_handlers(script_path: str | Path) -> list[H5KwsOpcodeHandler]: + """Extract and label the Jimbei opcode handler array from the script.""" + + script = Path(script_path).read_text(encoding="utf-8") + summary = parse_h5_kws_vm_script(script_path) + parts = _extract_js_array_literal(script, "_sabo_57b82") + handlers: list[H5KwsOpcodeHandler] = [] + for index, body in enumerate(parts): + present = bool(body) + body_sha16 = hashlib.sha256(body.encode("utf-8")).hexdigest()[:16] if present else "" + preview = " ".join(body.split())[:240] if present else "" + handlers.append( + H5KwsOpcodeHandler( + index=index, + present=present, + label=_OPCODE_LABELS.get(index, "unknown"), + used_count=summary.opcode_histogram.get(index, 0), + body_sha16=body_sha16, + body_preview=preview, + ) + ) + return handlers + + +def disassemble_h5_kws_range( + script_path: str | Path, + start: int, + end: int, +) -> list[H5KwsInstruction]: + """Disassemble a bytecode row range with opcode labels and operands.""" + + if start < 0 or end < start: + raise ValueError("invalid KWS bytecode range") + script = Path(script_path).read_text(encoding="utf-8") + container = _extract_jimbei_container(script) + constants = container["d"] + rows = _instruction_rows(_decode_bytecode_values(container["b"])) + if end >= len(rows): + raise ValueError("KWS bytecode range exceeds instruction count") + instructions: list[H5KwsInstruction] = [] + for index in range(start, end + 1): + opcode, p0, p1, p2, p3 = rows[index] + instructions.append( + H5KwsInstruction( + index=index, + opcode=opcode, + label=_OPCODE_LABELS.get(opcode, "unknown"), + p0=p0, + p1=p1, + p2=p2, + p3=p3, + operand_a=_format_operand(constants, p0, p1), + operand_b=_format_operand(constants, p2, p3), + ) + ) + return instructions + + +def kwscode_from_known_h5_kws_script(script_path: str | Path) -> str | None: + summary = parse_h5_kws_vm_script(script_path) + return _KNOWN_CODE_BY_SCRIPT_SHA256.get(summary.script_sha256) or _KNOWN_CODE_BY_VM_SHA256.get( + (summary.bytecode_sha256, summary.constants_sha256) + ) + + +__all__ = [ + "H5_KWS_KNOWN_BYTECODE_SHA256", + "H5_KWS_KNOWN_CONSTANTS_SHA256", + "H5_KWS_KNOWN_SCRIPT_CODE", + "H5_KWS_KNOWN_SCRIPT_SHA256", + "H5KwsFunctionRange", + "H5KwsFunctionAnalysis", + "H5KwsInstruction", + "H5KwsOpcodeHandler", + "H5KwsVmSummary", + "analyze_h5_kws_function_ranges", + "disassemble_h5_kws_range", + "extract_h5_kws_opcode_handlers", + "kwscode_from_known_h5_kws_script", + "parse_h5_kws_vm_script", +] diff --git a/core/h5_kww.py b/core/h5_kww.py new file mode 100644 index 0000000..a65790a --- /dev/null +++ b/core/h5_kww.py @@ -0,0 +1,212 @@ +"""Nebula H5 `kww` header generator backed by the KWF WebView VM. + +KWF runtime behavior confirmed from APP WebView: + +- `kwf-0.0.2` installs `window.kwpsec.getData`; +- `getData()` returns the 174-char `PnGU...` value used as H5 request header + `kww`; +- each call updates `localStorage.kwfcv1` and `localStorage.kwfv1`. + +The active `PnGU...` branch is implemented in pure Python. The Node VM bridge +is kept as a cross-check/fallback for future KWF branch changes. +""" + +from __future__ import annotations + +import json +import os +import queue +import subprocess +import threading +import time +from dataclasses import dataclass +from pathlib import Path +from typing import Any + +from core.h5_kww_alg import kwf_generate_kww + +DEFAULT_H5_KWW_SERVER = Path("core/h5_kww_server.mjs") + + +@dataclass(frozen=True) +class H5KwwResult: + kww: str + kwfcv1: str = "" + kwfv1: str = "" + + +class H5KwwGenerator: + """长驻 Node/KWF 进程,保持 localStorage 计数状态。""" + + def __init__( + self, + server: str | Path = DEFAULT_H5_KWW_SERVER, + node_bin: str | None = None, + timeout: int = 30, + ) -> None: + self.server = Path(server) + self.node = node_bin or os.environ.get("NODE_BIN") or "node" + self.timeout = timeout + self._proc: subprocess.Popen[str] | None = None + self._stdout_queue: queue.Queue[str] = queue.Queue() + self._lock = threading.Lock() + self._request_id = 0 + + def _start(self) -> None: + if self._proc is not None and self._proc.poll() is None: + return + if not self.server.exists(): + raise FileNotFoundError(f"H5 kww server not found: {self.server}") + self._stdout_queue = queue.Queue() + self._proc = subprocess.Popen( + [self.node, str(self.server)], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + text=True, + encoding="utf-8", + bufsize=1, + ) + + def read_stdout() -> None: + assert self._proc is not None + assert self._proc.stdout is not None + for line in self._proc.stdout: + self._stdout_queue.put(line) + + thread = threading.Thread(target=read_stdout, name="H5KwwGeneratorStdout", daemon=True) + thread.start() + + def close(self) -> None: + proc = self._proc + self._proc = None + if proc is None: + return + try: + if proc.stdin: + proc.stdin.close() + except Exception: + pass + try: + if proc.stdout: + proc.stdout.close() + except Exception: + pass + try: + proc.wait(timeout=1) + except Exception: + try: + proc.kill() + except Exception: + pass + + def get( + self, + *, + url: str = "", + method: str = "GET", + headers: dict[str, str] | None = None, + body: str = "", + cookie: str = "", + ) -> H5KwwResult: + with self._lock: + self._start() + assert self._proc is not None + assert self._proc.stdin is not None + self._request_id += 1 + request_id = self._request_id + payload = json.dumps( + { + "id": request_id, + "url": url, + "method": method, + "headers": headers or {}, + "body": body, + "cookie": cookie, + }, + ensure_ascii=False, + separators=(",", ":"), + ) + try: + self._proc.stdin.write(payload + "\n") + self._proc.stdin.flush() + except Exception: + self.close() + raise + + while True: + try: + line = self._stdout_queue.get(timeout=self.timeout) + except queue.Empty as exc: + self.close() + raise TimeoutError("H5 kww server timed out") from exc + try: + data = json.loads(line) + except json.JSONDecodeError: + continue + if data.get("id") not in {request_id, None}: + continue + if not data.get("ok", True): + raise RuntimeError(f"H5 kww server failed: {data.get('error')}") + kww = str(data.get("kww") or "") + if not _looks_like_kww(kww): + raise RuntimeError(f"H5 kww server returned invalid kww: {kww!r}") + return H5KwwResult( + kww=kww, + kwfcv1=str(data.get("kwfcv1") or ""), + kwfv1=str(data.get("kwfv1") or ""), + ) + + +class PureH5KwwGenerator: + """Pure-Python KWF `PnGU...` generator for the current Nebula branch.""" + + def __init__( + self, + *, + start_collect_count: int = 1, + now_ms: int | None = None, + language: str = "zh-CN", + ) -> None: + self.collect_count = start_collect_count + self.now_ms = now_ms + self.language = language + self._lock = threading.Lock() + + def close(self) -> None: + return + + def get( + self, + *, + url: str = "", + method: str = "GET", + headers: dict[str, str] | None = None, + body: str = "", + cookie: str = "", + ) -> H5KwwResult: + del url, method, headers, body, cookie + with self._lock: + current = self.collect_count + now_ms = self.now_ms if self.now_ms is not None else int(time.time() * 1000) + kww = kwf_generate_kww( + collect_count=current, + now_ms=now_ms, + language=self.language, + ) + self.collect_count += 1 + return H5KwwResult(kww=kww, kwfcv1=str(self.collect_count), kwfv1=kww) + + +def _looks_like_kww(value: str) -> bool: + if len(value) < 120: + return False + return all(ch.isalnum() or ch in "+/=" for ch in value) + + +__all__ = [ + "DEFAULT_H5_KWW_SERVER", + "H5KwwGenerator", + "H5KwwResult", + "PureH5KwwGenerator", +] diff --git a/core/h5_kww_alg.py b/core/h5_kww_alg.py new file mode 100644 index 0000000..33c0d88 --- /dev/null +++ b/core/h5_kww_alg.py @@ -0,0 +1,608 @@ +"""Pure-Python pieces of the KWF `kwpsec.getData` algorithm. + +This module is intentionally incremental. The first closed slice is the VM +function at 9756..9942, which converts a JS string into a byte-string using +UTF-16 code units and a classic UTF-8-like encoder. +""" + +from __future__ import annotations + +import math +from collections.abc import Mapping +from typing import Any + + +KWF_FINGERPRINT_KEYS = tuple(f"k{idx}" for idx in range(1, 15)) +KWF_BASE64_ALPHABET = ( + "ZmserbBoHQtNP+wOcza/LpngG8yJq42KWYj0DSfdikx3VT16IlUAFM97hECvuRX5" +) +KWF_AES_IV = b"mhaqhnjmr0rsoo3o" +KWF_OBFUSCATED_KEY_GRID = ( + (-2002111551, 1077744408, -672376612, 419994569), + (528185349, -425267957, 826979799, -102918898), + (-1176467946, -1009525813, -1747891260, -5343550), + (1903666895, 811678054, 1999858998, 1902537836), + (845440362, 1915501381, 85939827, 1954101791), + (1176330101, -723278305, -771952532, -1517958541), + (-476539642, -1765160690, 1194670434, -491719919), + (19424791, -1426441870, -305201136, 260043521), + (240620822, -506429735, 203390665, 56659400), + (221714654, 1534944014, 1466047943, 1409454095), + (1496680657, -1917231675, -623165438, -1898328051), +) +KWF_AES_SEED = 14 + +_AES_SBOX = ( + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16, +) +_AES_RCON = (0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36) +_AES_INV_SBOX = ( + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D, +) + + +def js_utf16_code_units(text: str) -> list[int]: + """Return JavaScript `charCodeAt`-style UTF-16 code units.""" + + raw = text.encode("utf-16-le", errors="surrogatepass") + return [ + raw[idx] | (raw[idx + 1] << 8) + for idx in range(0, len(raw), 2) + ] + + +def kwf_string_encoder_bytes(text: str) -> bytes: + """Port of KWF VM slice 9756..9942. + + The original VM iterates JavaScript `charCodeAt` units. It emits: + + - ASCII code units 1..127 as-is; + - code units 128..2047 as two bytes; + - code units above 2047 as three bytes. + + Code unit 0 intentionally falls through to the two-byte branch, matching + the VM's `code >= 1 && code <= 127` ASCII condition. + """ + + out = bytearray() + for code in js_utf16_code_units(text): + if 1 <= code <= 0x7F: + out.append(code) + elif code > 0x7FF: + out.append(0xE0 | ((code >> 12) & 0x0F)) + out.append(0x80 | ((code >> 6) & 0x3F)) + out.append(0x80 | (code & 0x3F)) + else: + out.append(0xC0 | ((code >> 6) & 0x1F)) + out.append(0x80 | (code & 0x3F)) + return bytes(out) + + +def kwf_string_encoder_binary(text: str) -> str: + """Return the VM's JavaScript byte-string representation.""" + + return "".join(chr(item) for item in kwf_string_encoder_bytes(text)) + + +def kwf_mixer_permutation(total: int, seed: float) -> list[int]: + """Port the index shuffle from KWF VM slice 8889..9050. + + The VM builds ``Array(total).fill().map((_, index) => index)`` and then + swaps from the end using ``Math.floor((i * this._seed) % (i + 1))``. + """ + + if total < 0: + raise ValueError("total must be non-negative") + + items = list(range(total)) + for idx in range(total - 1, 0, -1): + swap_idx = math.floor((idx * seed) % (idx + 1)) + if swap_idx < 0 or swap_idx > idx: + raise ValueError("seed produced an invalid swap index") + items[idx], items[swap_idx] = items[swap_idx], items[idx] + return items + + +def kwf_mixer_char(key_grid: list[str] | tuple[str, ...], seed: float, row: int, col: int) -> str: + """Return ``this._Ke[floor(pos / width)][pos % width]`` after shuffle. + + ``row`` and ``col`` are the original coordinates. The shuffled array maps + original flat indexes to output positions, then the output position selects + the final character from ``_Ke``. + """ + + if not key_grid: + raise ValueError("key_grid must not be empty") + width = len(key_grid[0]) + if width == 0: + raise ValueError("key_grid rows must not be empty") + if any(len(item) != width for item in key_grid): + raise ValueError("key_grid rows must have the same length") + + height = len(key_grid) + if row < 0 or row >= height or col < 0 or col >= width: + raise IndexError("row or col out of range") + + target = row * width + col + permutation = kwf_mixer_permutation(height * width, seed) + position = permutation.index(target) + return key_grid[position // width][position % width] + + +def _kwf_mixer_value( + grid: tuple[tuple[int, ...], ...], + seed: float, + row: int, + col: int, +) -> int: + width = len(grid[0]) + target = row * width + col + permutation = kwf_mixer_permutation(len(grid) * width, seed) + position = permutation.index(target) + return grid[position // width][position % width] & 0xFFFFFFFF + + +def kwf_aes_key_bytes() -> bytes: + """Recover the fixed AES key hidden behind the `_Ke` mixer.""" + + words = [ + _kwf_mixer_value(KWF_OBFUSCATED_KEY_GRID, KWF_AES_SEED, 0, col) + for col in range(4) + ] + return b"".join(word.to_bytes(4, "big") for word in words) + + +def _aes_xtime(value: int) -> int: + return (((value << 1) ^ 0x1B) & 0xFF) if value & 0x80 else (value << 1) & 0xFF + + +def _aes_mix_column(col: list[int]) -> None: + total = col[0] ^ col[1] ^ col[2] ^ col[3] + first = col[0] + col[0] ^= total ^ _aes_xtime(col[0] ^ col[1]) + col[1] ^= total ^ _aes_xtime(col[1] ^ col[2]) + col[2] ^= total ^ _aes_xtime(col[2] ^ col[3]) + col[3] ^= total ^ _aes_xtime(col[3] ^ first) + + +def _aes_expand_key(key: bytes) -> list[list[int]]: + if len(key) != 16: + raise ValueError("AES-128 key must be 16 bytes") + words = [list(key[idx: idx + 4]) for idx in range(0, 16, 4)] + for idx in range(4, 44): + temp = words[idx - 1].copy() + if idx % 4 == 0: + temp = temp[1:] + temp[:1] + temp = [_AES_SBOX[item] for item in temp] + temp[0] ^= _AES_RCON[idx // 4] + words.append([left ^ right for left, right in zip(words[idx - 4], temp)]) + return [sum(words[4 * round_idx: 4 * round_idx + 4], []) for round_idx in range(11)] + + +def _aes_encrypt_block(block: bytes, key: bytes) -> bytes: + if len(block) != 16: + raise ValueError("AES block must be 16 bytes") + state = list(block) + round_keys = _aes_expand_key(key) + + def add_round_key(round_idx: int) -> None: + for idx, item in enumerate(round_keys[round_idx]): + state[idx] ^= item + + def sub_bytes() -> None: + for idx, item in enumerate(state): + state[idx] = _AES_SBOX[item] + + def shift_rows() -> None: + state[1], state[5], state[9], state[13] = state[5], state[9], state[13], state[1] + state[2], state[6], state[10], state[14] = state[10], state[14], state[2], state[6] + state[3], state[7], state[11], state[15] = state[15], state[3], state[7], state[11] + + def mix_columns() -> None: + for col_idx in range(4): + start = col_idx * 4 + col = state[start: start + 4] + _aes_mix_column(col) + state[start: start + 4] = col + + add_round_key(0) + for round_idx in range(1, 10): + sub_bytes() + shift_rows() + mix_columns() + add_round_key(round_idx) + sub_bytes() + shift_rows() + add_round_key(10) + return bytes(state) + + +def _aes_gmul(left: int, right: int) -> int: + """Multiply two bytes in AES' GF(2^8).""" + + result = 0 + for _ in range(8): + if right & 1: + result ^= left + high_bit = left & 0x80 + left = (left << 1) & 0xFF + if high_bit: + left ^= 0x1B + right >>= 1 + return result + + +def _aes_inv_mix_column(col: list[int]) -> None: + first, second, third, fourth = col + col[0] = ( + _aes_gmul(first, 0x0E) + ^ _aes_gmul(second, 0x0B) + ^ _aes_gmul(third, 0x0D) + ^ _aes_gmul(fourth, 0x09) + ) + col[1] = ( + _aes_gmul(first, 0x09) + ^ _aes_gmul(second, 0x0E) + ^ _aes_gmul(third, 0x0B) + ^ _aes_gmul(fourth, 0x0D) + ) + col[2] = ( + _aes_gmul(first, 0x0D) + ^ _aes_gmul(second, 0x09) + ^ _aes_gmul(third, 0x0E) + ^ _aes_gmul(fourth, 0x0B) + ) + col[3] = ( + _aes_gmul(first, 0x0B) + ^ _aes_gmul(second, 0x0D) + ^ _aes_gmul(third, 0x09) + ^ _aes_gmul(fourth, 0x0E) + ) + + +def _aes_decrypt_block(block: bytes, key: bytes) -> bytes: + if len(block) != 16: + raise ValueError("AES block must be 16 bytes") + state = list(block) + round_keys = _aes_expand_key(key) + + def add_round_key(round_idx: int) -> None: + for idx, item in enumerate(round_keys[round_idx]): + state[idx] ^= item + + def inv_sub_bytes() -> None: + for idx, item in enumerate(state): + state[idx] = _AES_INV_SBOX[item] + + def inv_shift_rows() -> None: + state[1], state[5], state[9], state[13] = state[13], state[1], state[5], state[9] + state[2], state[6], state[10], state[14] = state[10], state[14], state[2], state[6] + state[3], state[7], state[11], state[15] = state[7], state[11], state[15], state[3] + + def inv_mix_columns() -> None: + for col_idx in range(4): + start = col_idx * 4 + col = state[start: start + 4] + _aes_inv_mix_column(col) + state[start: start + 4] = col + + add_round_key(10) + for round_idx in range(9, 0, -1): + inv_shift_rows() + inv_sub_bytes() + add_round_key(round_idx) + inv_mix_columns() + inv_shift_rows() + inv_sub_bytes() + add_round_key(0) + return bytes(state) + + +def _pkcs7_pad(data: bytes, block_size: int = 16) -> bytes: + pad = block_size - (len(data) % block_size) + return data + bytes([pad]) * pad + + +def _pkcs7_unpad(data: bytes, block_size: int = 16) -> bytes: + if not data or len(data) % block_size: + raise ValueError("PKCS7 data length must be a positive block multiple") + pad = data[-1] + if pad < 1 or pad > block_size: + raise ValueError("invalid PKCS7 padding length") + if data[-pad:] != bytes([pad]) * pad: + raise ValueError("invalid PKCS7 padding bytes") + return data[:-pad] + + +def kwf_aes_cbc_encrypt( + data: bytes, + key: bytes | None = None, + iv: bytes = KWF_AES_IV, +) -> bytes: + """AES-CBC used by the KWF fingerprint tail.""" + + key = kwf_aes_key_bytes() if key is None else key + if len(iv) != 16: + raise ValueError("AES-CBC IV must be 16 bytes") + padded = _pkcs7_pad(data) + out = bytearray() + previous = iv + for idx in range(0, len(padded), 16): + block = bytes(left ^ right for left, right in zip(padded[idx: idx + 16], previous)) + encrypted = _aes_encrypt_block(block, key) + out.extend(encrypted) + previous = encrypted + return bytes(out) + + +def kwf_aes_cbc_decrypt( + data: bytes, + key: bytes | None = None, + iv: bytes = KWF_AES_IV, +) -> bytes: + """AES-CBC/PKCS7 decrypt used by WebWeapon/KWF-compatible payloads.""" + + key = kwf_aes_key_bytes() if key is None else key + if len(key) != 16: + raise ValueError("AES-128 key must be 16 bytes") + if len(iv) != 16: + raise ValueError("AES-CBC IV must be 16 bytes") + if len(data) == 0 or len(data) % 16: + raise ValueError("AES-CBC ciphertext length must be a positive block multiple") + + out = bytearray() + previous = iv + for idx in range(0, len(data), 16): + block = bytes(data[idx: idx + 16]) + decrypted = _aes_decrypt_block(block, key) + out.extend(left ^ right for left, right in zip(decrypted, previous)) + previous = block + return _pkcs7_unpad(bytes(out)) + + +def kwf_encrypt_fingerprint_hex(plain: str) -> str: + """Encrypt the local100 fingerprint string and return KWF lowercase hex.""" + + return kwf_aes_cbc_encrypt(plain.encode("utf-8")).hex() + + +def kwf_pack_fingerprint_plain( + plain: str, + alg_version: str = "0", + key_version: str = "0", +) -> str: + encrypted_hex = kwf_encrypt_fingerprint_hex(plain) + encoded = kwf_base64_encode_bytes(encrypted_hex.encode("ascii")) + return kwf_insert_version_fields(encoded, alg_version, key_version) + + +def kwf_pack_fingerprint_fields( + fields: Mapping[str, Any], + alg_version: str = "0", + key_version: str = "0", +) -> str: + return kwf_pack_fingerprint_plain( + kwf_fingerprint_plain(fields), + alg_version=alg_version, + key_version=key_version, + ) + + +def kwf_default_fingerprint_fields( + collect_count: int | str, + now_ms: int, + language: str = "zh-CN", + k10: int = 60, + k11: int = 508, +) -> dict[str, Any]: + """Build the current KWF default environment fingerprint fields. + + These values match the local WebView stubs used by `core/h5_kww_server.mjs` + and the active Nebula `PnGU...` branch. `collect_count` is the value read + from `localStorage.kwfcv1` before it is incremented. + """ + + return { + "k1": 1, + "k2": "0.0.2", + "k3": language, + "k4": "0", + "k5": False, + "k6": True, + "k7": True, + "k8": "1", + "k9": "0", + "k10": k10, + "k11": k11, + "k12": int(now_ms), + "k13": str(collect_count), + "k14": "", + } + + +def kwf_generate_kww( + collect_count: int | str, + now_ms: int, + language: str = "zh-CN", +) -> str: + return kwf_pack_fingerprint_fields( + kwf_default_fingerprint_fields( + collect_count=collect_count, + now_ms=now_ms, + language=language, + ) + ) + + +def _js_fingerprint_value(value: Any) -> str: + if value is None: + return "" + if isinstance(value, bool): + return "1" if value else "0" + return str(value) + + +def kwf_fingerprint_plain( + fields: Mapping[str, Any], + keys: tuple[str, ...] = KWF_FINGERPRINT_KEYS, +) -> str: + """Port the KWF local100/local91 plain fingerprint join. + + The VM builds ``["k1", ..., "k14"]``, maps values from an Object.assign + result, coerces booleans to ``"1"``/``"0"``, and joins with ``"|"``. + Missing/``undefined`` values become empty fields under JavaScript join + semantics. + """ + + return "|".join(_js_fingerprint_value(fields.get(key)) for key in keys) + + +def kwf_insert_version_fields( + encoded_ciphertext: str, + alg_version: str = "0", + key_version: str = "0", +) -> str: + """Port the visible packaging part of KWF VM slice 9959..10210. + + After encryption/base64, the VM inserts ``ALG_VERSION`` after ten + characters and ``KEY_VERSION`` after the next five characters. + """ + + return ( + encoded_ciphertext[:10] + + alg_version + + encoded_ciphertext[10:15] + + key_version + + encoded_ciphertext[15:] + ) + + +def kwf_remove_version_fields(packed: str) -> tuple[str, str, str]: + """Reverse ``kwf_insert_version_fields`` for analysis/parity checks.""" + + if len(packed) < 17: + raise ValueError("packed text is too short to contain version fields") + return packed[:10] + packed[11:16] + packed[17:], packed[10], packed[16] + + +def kwf_base64_encode_bytes( + data: bytes | bytearray | memoryview, + alphabet: str = KWF_BASE64_ALPHABET, +) -> str: + """Port KWF VM slice 9509..9755. + + This is standard 3-byte to 4-character base64 packing, but with KWF's + custom alphabet from local[44]. + """ + + raw = bytes(data) + if len(alphabet) != 64: + raise ValueError("alphabet must contain exactly 64 characters") + + out: list[str] = [] + for idx in range(0, len(raw), 3): + chunk = raw[idx : idx + 3] + b0 = chunk[0] + if len(chunk) == 1: + out.append(alphabet[b0 >> 2]) + out.append(alphabet[(b0 & 0x03) << 4]) + out.append("=") + out.append("=") + elif len(chunk) == 2: + b1 = chunk[1] + out.append(alphabet[b0 >> 2]) + out.append(alphabet[((b0 & 0x03) << 4) | ((b1 & 0xF0) >> 4)]) + out.append(alphabet[(b1 & 0x0F) << 2]) + out.append("=") + else: + b1 = chunk[1] + b2 = chunk[2] + out.append(alphabet[b0 >> 2]) + out.append(alphabet[((b0 & 0x03) << 4) | ((b1 & 0xF0) >> 4)]) + out.append(alphabet[((b1 & 0x0F) << 2) | ((b2 & 0xC0) >> 6)]) + out.append(alphabet[b2 & 0x3F]) + return "".join(out) + + +def kwf_base64_decode_bytes( + text: str, + alphabet: str = KWF_BASE64_ALPHABET, +) -> bytes: + """Decode the KWF custom-alphabet base64 form.""" + + if len(alphabet) != 64: + raise ValueError("alphabet must contain exactly 64 characters") + if len(text) % 4 != 0: + raise ValueError("base64 text length must be a multiple of 4") + + lookup = {ch: idx for idx, ch in enumerate(alphabet)} + out = bytearray() + for idx in range(0, len(text), 4): + block = text[idx : idx + 4] + pad = block.count("=") + if pad and block[-pad:] != "=" * pad: + raise ValueError("padding is only valid at the end of a block") + values = [lookup[ch] if ch != "=" else 0 for ch in block] + out.append((values[0] << 2) | (values[1] >> 4)) + if pad < 2: + out.append(((values[1] & 0x0F) << 4) | (values[2] >> 2)) + if pad < 1: + out.append(((values[2] & 0x03) << 6) | values[3]) + return bytes(out) + + +__all__ = [ + "KWF_BASE64_ALPHABET", + "KWF_AES_IV", + "KWF_AES_SEED", + "KWF_FINGERPRINT_KEYS", + "KWF_OBFUSCATED_KEY_GRID", + "js_utf16_code_units", + "kwf_aes_cbc_encrypt", + "kwf_aes_cbc_decrypt", + "kwf_aes_key_bytes", + "kwf_base64_decode_bytes", + "kwf_base64_encode_bytes", + "kwf_default_fingerprint_fields", + "kwf_encrypt_fingerprint_hex", + "kwf_fingerprint_plain", + "kwf_generate_kww", + "kwf_insert_version_fields", + "kwf_mixer_char", + "kwf_mixer_permutation", + "kwf_pack_fingerprint_fields", + "kwf_pack_fingerprint_plain", + "kwf_remove_version_fields", + "kwf_string_encoder_binary", + "kwf_string_encoder_bytes", +] diff --git a/core/h5_kww_server.mjs b/core/h5_kww_server.mjs new file mode 100644 index 0000000..6d875f1 --- /dev/null +++ b/core/h5_kww_server.mjs @@ -0,0 +1,387 @@ +import fs from "fs"; +import readline from "readline"; +import vm from "vm"; + +const KWF_PATH = new URL("./kwf-0.0.2.2cee19b4b7dec496.js", import.meta.url); + +let fixedNow = process.env.KS_H5_KWW_NOW ? Number(process.env.KS_H5_KWW_NOW) : null; +let rngState = (process.env.KS_H5_KWW_SEED ? Number(process.env.KS_H5_KWW_SEED) : Date.now()) >>> 0; +let traceEvents = null; +let traceCounts = null; + +const TRACE_TYPE_LIMITS = { + "Math.floor": 256, + "String.fromCharCode": 512, + "Object.assign": 64, + "Array.join": 64, +}; + +function trace(type, detail = {}) { + if (!traceEvents) return; + if (traceCounts) traceCounts[type] = (traceCounts[type] || 0) + 1; + const limit = TRACE_TYPE_LIMITS[type] || 2000; + if (traceCounts && traceCounts[type] > limit) return; + if (traceEvents.length >= 4000) return; + traceEvents.push({ type, ...detail }); +} + +function previewArgs(values, limit = 32) { + const arr = Array.from(values || []); + return { + count: arr.length, + first: arr.slice(0, limit), + truncated: arr.length > limit, + }; +} + +function seededRandom() { + rngState = (Math.imul(rngState, 1664525) + 1013904223) >>> 0; + const value = rngState / 0x100000000; + trace("random", { value }); + return value; +} + +function currentNow() { + const value = fixedNow === null || Number.isNaN(fixedNow) ? Date.now() : fixedNow; + trace("now", { value }); + return value; +} + +function FakeDate(...args) { + if (new.target) { + return args.length > 0 ? new Date(...args) : new Date(currentNow()); + } + return new Date(args.length > 0 ? args[0] : currentNow()).toString(); +} + +Object.setPrototypeOf(FakeDate, Date); +FakeDate.prototype = Date.prototype; +FakeDate.now = () => currentNow(); +FakeDate.parse = Date.parse; +FakeDate.UTC = Date.UTC; + +const fakeMath = Object.create(Math); +fakeMath.random = () => seededRandom(); +fakeMath.floor = (value) => { + const result = Math.floor(value); + trace("Math.floor", { value, result }); + return result; +}; + +const NativeString = String; +function TracedString(...args) { + return NativeString(...args); +} +Object.setPrototypeOf(TracedString, NativeString); +TracedString.prototype = NativeString.prototype; +TracedString.fromCharCode = (...codes) => { + const result = NativeString.fromCharCode(...codes); + trace("String.fromCharCode", { + args: previewArgs(codes), + result: preview(result), + }); + return result; +}; + +const NativeObject = Object; +function previewObject(value) { + if (!value || typeof value !== "object") return preview(value); + const keys = NativeObject.keys(value); + const sample = {}; + for (const key of keys.slice(0, 16)) sample[key] = preview(value[key]); + return { keys: keys.slice(0, 32), sample, keyCount: keys.length }; +} + +function TracedObject(value) { + return NativeObject(value); +} +NativeObject.setPrototypeOf(TracedObject, NativeObject); +TracedObject.prototype = NativeObject.prototype; +for (const name of NativeObject.getOwnPropertyNames(NativeObject)) { + if (name === "length" || name === "name" || name === "prototype") continue; + NativeObject.defineProperty( + TracedObject, + name, + NativeObject.getOwnPropertyDescriptor(NativeObject, name), + ); +} +TracedObject.assign = (target, ...sources) => { + const result = NativeObject.assign(target, ...sources); + trace("Object.assign", { + sourceCount: sources.length, + sources: sources.map((item) => previewObject(item)), + result: previewObject(result), + }); + return result; +}; + +const nativeArrayJoin = Array.prototype.join; +Array.prototype.join = function tracedJoin(separator) { + const result = nativeArrayJoin.call(this, separator); + if (separator === "|" || (this.length === 14 && result.includes("|"))) { + trace("Array.join", { + separator: separator === undefined ? "," : String(separator), + length: this.length, + result: preview(result), + }); + } + return result; +}; + +const mockCache = new Map(); +function preview(value) { + if (value === null) return "null"; + if (value === undefined) return "undefined"; + if (typeof value === "string") return value.length > 120 ? `${value.slice(0, 120)}...(len=${value.length})` : value; + if (typeof value === "number" || typeof value === "boolean") return value; + if (typeof value === "function") { + const text = NativeString(value); + return text.length > 160 ? `${text.slice(0, 160)}...(len=${text.length})` : text; + } + if (Array.isArray(value)) return `[array len=${value.length}]`; + try { + return `[object ${Object.keys(value).slice(0, 8).join(",")}]`; + } catch { + return "[unpreviewable]"; + } +} + +function mock(path = "mock") { + if (mockCache.has(path)) return mockCache.get(path); + const fn = function () { + return mock(`${path}()`); + }; + const proxy = new Proxy(fn, { + get(_target, prop) { + if (prop === Symbol.toPrimitive) return () => ""; + if (prop === "toString") return () => `[mock ${path}]`; + if (prop === "valueOf") return () => 0; + if (prop === "then") return undefined; + return mock(`${path}.${String(prop)}`); + }, + set() { + return true; + }, + apply() { + return mock(`${path}()`); + }, + construct() { + return mock(`new ${path}`); + }, + has() { + return true; + }, + }); + mockCache.set(path, proxy); + return proxy; +} + +const storage = new Map(); +const localStorage = { + getItem(key) { + const value = storage.get(String(key)) || null; + trace("localStorage.getItem", { key: String(key), value }); + return value; + }, + setItem(key, value) { + trace("localStorage.setItem", { key: String(key), value: String(value) }); + storage.set(String(key), String(value)); + }, + removeItem(key) { + trace("localStorage.removeItem", { key: String(key) }); + storage.delete(String(key)); + }, +}; + +class FakeXMLHttpRequest { + open(method, url) { + this.method = method; + this.url = url; + } + setRequestHeader() {} + send() { + this.readyState = 4; + this.status = 200; + this.responseText = "{}"; + if (typeof this.onreadystatechange === "function") this.onreadystatechange(); + if (typeof this.onload === "function") this.onload(); + } + addEventListener() {} +} + +const rawWindow = {}; +const windowProxy = new Proxy(rawWindow, { + get(target, prop) { + if (prop in target) return target[prop]; + const value = mock(`window.${String(prop)}`); + target[prop] = value; + return value; + }, + set(target, prop, value) { + target[prop] = value; + return true; + }, + has() { + return true; + }, +}); + +Object.assign(rawWindow, { + window: windowProxy, + self: windowProxy, + top: windowProxy, + parent: windowProxy, + Object: TracedObject, + Array, + String: TracedString, + Function, + Number, + Boolean, + Date: FakeDate, + Math: fakeMath, + RegExp, + Error, + TypeError, + Promise, + JSON, + Infinity, + undefined, + Uint8Array, + parseInt, + parseFloat, + isNaN, + escape, + encodeURI, + encodeURIComponent, + decodeURI, + decodeURIComponent, + Window: function Window() {}, + Navigator: function Navigator() {}, + Location: function Location() {}, + location: { + href: "https://nebula.kuaishou.com/nebula/task/earning?layoutType=4&source=bottom_guide_first", + origin: "https://nebula.kuaishou.com", + protocol: "https:", + host: "nebula.kuaishou.com", + hostname: "nebula.kuaishou.com", + pathname: "/nebula/task/earning", + search: "?layoutType=4&source=bottom_guide_first", + }, + document: { + cookie: "", + referrer: "", + createElement(tag) { + return mock(`element.${tag}`); + }, + getElementsByTagName(tag) { + return [mock(`tag.${tag}`)]; + }, + addEventListener() {}, + body: mock("document.body"), + head: mock("document.head"), + documentElement: mock("document.documentElement"), + }, + navigator: { + userAgent: "Mozilla/5.0 (Linux; Android 16; PJZ110 Build/BP2A.250605.015; wv) AppleWebKit/537.36", + language: "zh-CN", + languages: ["zh-CN", "zh"], + platform: "Linux armv8l", + webdriver: false, + }, + screen: { width: 1080, height: 2376, colorDepth: 24, pixelDepth: 24 }, + localStorage, + sessionStorage: localStorage, + performance: { now: () => currentNow() % 100000, timing: {}, getEntriesByType: () => [] }, + crypto: { + getRandomValues(arr) { + for (let i = 0; i < arr.length; i += 1) arr[i] = Math.floor(seededRandom() * 256); + return arr; + }, + }, + XMLHttpRequest: FakeXMLHttpRequest, + fetch() { + return Promise.resolve({ ok: true, status: 200, text: () => Promise.resolve("{}"), json: () => Promise.resolve({}) }); + }, + setTimeout(cb) { + if (typeof cb === "function") cb(); + return 1; + }, + clearTimeout() {}, + setInterval() { + return 1; + }, + clearInterval() {}, + console: { + log() {}, + warn() {}, + error() {}, + }, +}); + +rawWindow.globalThis = windowProxy; + +const context = vm.createContext(windowProxy, { + name: "h5-kww", + codeGeneration: { strings: true, wasm: false }, +}); + +function loadKwf() { + const code = fs.readFileSync(KWF_PATH, "utf8"); + vm.runInContext(code, context, { filename: KWF_PATH.pathname, timeout: 5000 }); + if (!rawWindow.kwpsec || typeof rawWindow.kwpsec.getData !== "function") { + throw new Error(`kwpsec.getData not installed, kwpsec=${preview(rawWindow.kwpsec)}`); + } +} + +function setCookie(cookie) { + rawWindow.document.cookie = String(cookie || ""); +} + +function buildArg(req) { + if (req && req.arg !== undefined) return req.arg; + if (req && req.url) { + return { + url: String(req.url), + method: String(req.method || "GET"), + headers: req.headers || {}, + body: req.body || "", + data: req.body || "", + }; + } + return undefined; +} + +function makeKww(req) { + traceEvents = req.trace ? [] : null; + traceCounts = req.trace ? {} : null; + setCookie(req.cookie || ""); + const arg = buildArg(req); + const getData = rawWindow.kwpsec.getData; + const value = arg === undefined ? getData.call(rawWindow.kwpsec) : getData.call(rawWindow.kwpsec, arg); + const kww = String(value || ""); + if (!kww) { + throw new Error("kwpsec.getData returned empty value"); + } + return { + kww, + kwfcv1: storage.get("kwfcv1") || "", + kwfv1: storage.get("kwfv1") || "", + trace: traceEvents || undefined, + traceSummary: traceCounts || undefined, + }; +} + +loadKwf(); + +const rl = readline.createInterface({ input: process.stdin, crlfDelay: Infinity }); +rl.on("line", (line) => { + let id = null; + try { + const req = JSON.parse(line); + id = req.id ?? null; + const result = makeKww(req); + process.stdout.write(JSON.stringify({ id, ok: true, ...result }) + "\n"); + } catch (err) { + process.stdout.write(JSON.stringify({ id, ok: false, error: String(err && err.stack ? err.stack : err) }) + "\n"); + } +}); diff --git a/core/h5_sig3.py b/core/h5_sig3.py new file mode 100644 index 0000000..ad24390 --- /dev/null +++ b/core/h5_sig3.py @@ -0,0 +1,379 @@ +"""H5 `__NS_sig3` 34-byte envelope helpers. + +The Nebula H5 bridge returns a 68-hex digest shape that is distinct from the +regular API 10418 48-hex `__NS_sig3`. The final byte is a checksum mask; the +first 33 bytes are XOR-mixed with `(mask ^ index)`. +""" + +from __future__ import annotations + +import zlib +from dataclasses import dataclass + +from .sig3 import KWSG_10418_HMAC_KEY, kwsg_10418_binary48, load_kwsg_10418_tables + + +H5_SIG3_LENGTH = 34 +H5_SIG3_HEX_LENGTH = H5_SIG3_LENGTH * 2 +H5_SIG3_MAGIC = bytes.fromhex("54450130") +H5_SIG3_BLOCK_TAG = bytes.fromhex("9f01") +H5_SIG3_DEFAULT_SESSION_SEED = 0x4B4B4BD1 +H5_SIG3_DEFAULT_TAIL = bytes.fromhex("0100000000") +H5_ENCODE_SHA_IV1 = ( + 0xE066DF2C, + 0xA9888E01, + 0xB18EE43D, + 0x501AFA25, + 0x53A550E5, + 0xA4BCE311, + 0x70E554F5, + 0x6AA046EE, +) +H5_ENCODE_SHA_IV2 = ( + 0x3C66483A, + 0x0096038E, + 0xD62FEC37, + 0x346D7B3D, + 0xDE7FB319, + 0xF56D5DD5, + 0xE614E937, + 0x6DD5E338, +) +H5_ENCODE_SHA_K = ( + 0x428A2F98, + 0x71374491, + 0xB5C0FBCF, + 0xE9B5DBA5, + 0x3956C25B, + 0x59F111F1, + 0x923F82A4, + 0xAB1C5ED5, + 0xD807AA98, + 0x12835B01, + 0x243185BE, + 0x550C7DC3, + 0x72BE5D74, + 0x80DEB1FE, + 0x9BDC06A7, + 0xC19BF174, + 0xE49B69C1, + 0xEFBE4786, + 0x0FC19DC6, + 0x240CA1CC, + 0x2DE92C6F, + 0x4A7484AA, + 0x5CB0A9DC, + 0x76F988DA, + 0x983E5152, + 0xA831C66D, + 0xB00327C8, + 0xBF597FC7, + 0xC6E00BF3, + 0xD5A79147, + 0x06CA6351, + 0x14292967, + 0x27B70A85, + 0x2E1B2138, + 0x4D2C6DFC, + 0x53380D13, + 0x650A7354, + 0x766A0ABB, + 0x81C2C92E, + 0x92722C85, + 0xA2BFE8A1, + 0xA81A664B, + 0xC24B8B70, + 0xC76C51A3, + 0xD192E819, + 0xD6990624, + 0xF40E3585, + 0x106AA070, + 0x19A4C116, + 0x1E376C08, + 0x2748774C, + 0x34B0BCB5, + 0x391C0CB3, + 0x4ED8AA4A, + 0x5B9CCA4F, + 0x682E6FF3, + 0x748F82EE, + 0x78A5636F, + 0x84C87814, + 0x8CC70208, + 0x90BEFFFA, + 0xA4506CEB, + 0xBEF9A3F7, + 0xC67178F2, +) + + +@dataclass(frozen=True) +class H5Sig3Fields: + """扰动前的 H5 sig3 字段视图。""" + + raw_hex: str + preimage: bytes + mask: int + mask_ok: bool + magic_ok: bool + first_tag_ok: bool + second_tag_ok: bool + tail_ok: bool + session_seed: int + counter: int + crc32: int + elapsed_ms: int + state_value: int + tail: bytes + + @property + def ok(self) -> bool: + return ( + self.mask_ok + and self.magic_ok + and self.first_tag_ok + and self.second_tag_ok + and self.tail_ok + ) + + +def _coerce_digest(value: str | bytes | bytearray) -> bytes: + if isinstance(value, str): + if len(value) != H5_SIG3_HEX_LENGTH: + raise ValueError("H5 sig3 must be exactly 68 hex chars") + return bytes.fromhex(value) + digest = bytes(value) + if len(digest) != H5_SIG3_LENGTH: + raise ValueError("H5 sig3 must be exactly 34 bytes") + return digest + + +def h5_sig3_expected_mask(preimage33: bytes | bytearray) -> int: + """按已观测到的 H5 envelope 规则计算最后 1 字节 mask。""" + if len(preimage33) != H5_SIG3_LENGTH - 1: + raise ValueError("H5 sig3 preimage prefix must be exactly 33 bytes") + return (-sum(preimage33)) & 0xFF + + +def h5_sig3_unmix(value: str | bytes | bytearray) -> tuple[bytes, int, bool]: + """恢复扰动前 34 字节,其中最后 1 字节固定置 0。""" + digest = _coerce_digest(value) + mask = digest[-1] + preimage = bytearray(H5_SIG3_LENGTH) + for i in range(H5_SIG3_LENGTH - 1): + preimage[i] = digest[i] ^ ((mask ^ i) & 0xFF) + expected = h5_sig3_expected_mask(preimage[: H5_SIG3_LENGTH - 1]) + return bytes(preimage), mask, mask == expected + + +def h5_sig3_mix(preimage: bytes | bytearray, mask: int | None = None) -> bytes: + """由扰动前字段重建 34-byte H5 sig3 digest。""" + pre = bytearray(preimage) + if len(pre) == H5_SIG3_LENGTH - 1: + pre.append(0) + if len(pre) != H5_SIG3_LENGTH: + raise ValueError("H5 sig3 preimage must be exactly 33 or 34 bytes") + if mask is None: + mask = h5_sig3_expected_mask(pre[: H5_SIG3_LENGTH - 1]) + mask &= 0xFF + out = bytearray(H5_SIG3_LENGTH) + for i in range(H5_SIG3_LENGTH - 1): + out[i] = pre[i] ^ ((mask ^ i) & 0xFF) + out[-1] = mask + return bytes(out) + + +def parse_h5_sig3(value: str | bytes | bytearray) -> H5Sig3Fields: + """解析 H5 68hex `__NS_sig3` 的 envelope 字段。""" + digest = _coerce_digest(value) + pre, mask, mask_ok = h5_sig3_unmix(digest) + return H5Sig3Fields( + raw_hex=digest.hex(), + preimage=pre, + mask=mask, + mask_ok=mask_ok, + magic_ok=pre[:4] == H5_SIG3_MAGIC, + first_tag_ok=pre[8:10] == H5_SIG3_BLOCK_TAG, + second_tag_ok=pre[22:24] == H5_SIG3_BLOCK_TAG, + tail_ok=pre[28:33] == H5_SIG3_DEFAULT_TAIL, + session_seed=int.from_bytes(pre[4:8], "little"), + counter=int.from_bytes(pre[10:14], "little"), + crc32=int.from_bytes(pre[14:18], "little"), + elapsed_ms=int.from_bytes(pre[18:22], "little"), + state_value=int.from_bytes(pre[24:28], "little"), + tail=pre[28:33], + ) + + +def build_h5_sig3_preimage( + *, + crc32_value: int, + counter: int, + elapsed_ms: int, + state_value: int, + session_seed: int = H5_SIG3_DEFAULT_SESSION_SEED, + tail: bytes = H5_SIG3_DEFAULT_TAIL, +) -> bytes: + """构造 H5 sig3 扰动前字段,便于回放样本和后续接入真实 CRC。""" + if len(tail) != 5: + raise ValueError("H5 sig3 tail must be exactly 5 bytes") + pre = bytearray(H5_SIG3_LENGTH) + pre[:4] = H5_SIG3_MAGIC + pre[4:8] = (int(session_seed) & 0xFFFFFFFF).to_bytes(4, "little") + pre[8:10] = H5_SIG3_BLOCK_TAG + pre[10:14] = (int(counter) & 0xFFFFFFFF).to_bytes(4, "little") + pre[14:18] = (int(crc32_value) & 0xFFFFFFFF).to_bytes(4, "little") + pre[18:22] = (int(elapsed_ms) & 0xFFFFFFFF).to_bytes(4, "little") + pre[22:24] = H5_SIG3_BLOCK_TAG + pre[24:28] = (int(state_value) & 0xFFFFFFFF).to_bytes(4, "little") + pre[28:33] = tail + return bytes(pre) + + +def h5_sig3_from_fields( + *, + crc32_value: int, + counter: int, + elapsed_ms: int, + state_value: int, + session_seed: int = H5_SIG3_DEFAULT_SESSION_SEED, + tail: bytes = H5_SIG3_DEFAULT_TAIL, +) -> str: + """按字段直接生成 H5 68hex sig3。""" + return h5_sig3_mix( + build_h5_sig3_preimage( + crc32_value=crc32_value, + counter=counter, + elapsed_ms=elapsed_ms, + state_value=state_value, + session_seed=session_seed, + tail=tail, + ) + ).hex() + + +def _rotr32(value: int, bits: int) -> int: + value &= 0xFFFFFFFF + return ((value >> bits) | (value << (32 - bits))) & 0xFFFFFFFF + + +def _sha256_compress_block(state: tuple[int, ...], block64: bytes) -> tuple[int, ...]: + if len(block64) != 64: + raise ValueError("SHA-256 compression block must be exactly 64 bytes") + w = [int.from_bytes(block64[i : i + 4], "big") for i in range(0, 64, 4)] + for i in range(16, 64): + s0 = _rotr32(w[i - 15], 7) ^ _rotr32(w[i - 15], 18) ^ (w[i - 15] >> 3) + s1 = _rotr32(w[i - 2], 17) ^ _rotr32(w[i - 2], 19) ^ (w[i - 2] >> 10) + w.append((w[i - 16] + s0 + w[i - 7] + s1) & 0xFFFFFFFF) + + a, b, c, d, e, f, g, h = (item & 0xFFFFFFFF for item in state) + for i in range(64): + s1 = _rotr32(e, 6) ^ _rotr32(e, 11) ^ _rotr32(e, 25) + ch = (e & f) ^ ((~e) & g) + temp1 = (h + s1 + ch + H5_ENCODE_SHA_K[i] + w[i]) & 0xFFFFFFFF + s0 = _rotr32(a, 2) ^ _rotr32(a, 13) ^ _rotr32(a, 22) + maj = (a & b) ^ (a & c) ^ (b & c) + temp2 = (s0 + maj) & 0xFFFFFFFF + h = g + g = f + f = e + e = (d + temp1) & 0xFFFFFFFF + d = c + c = b + b = a + a = (temp1 + temp2) & 0xFFFFFFFF + + return ( + (state[0] + a) & 0xFFFFFFFF, + (state[1] + b) & 0xFFFFFFFF, + (state[2] + c) & 0xFFFFFFFF, + (state[3] + d) & 0xFFFFFFFF, + (state[4] + e) & 0xFFFFFFFF, + (state[5] + f) & 0xFFFFFFFF, + (state[6] + g) & 0xFFFFFFFF, + (state[7] + h) & 0xFFFFFFFF, + ) + + +def _sha256_continue_from_virtual_prefix( + data: bytes, + state: tuple[int, ...], + prefix_len: int = 64, +) -> bytes: + """从已压缩过 `prefix_len` 字节的自定义 SHA-256 state 继续计算。""" + if len(state) != 8: + raise ValueError("SHA-256 state must contain exactly 8 words") + total_len = prefix_len + len(data) + padded = bytearray(data) + padded.append(0x80) + while (prefix_len + len(padded)) % 64 != 56: + padded.append(0) + padded += (total_len * 8).to_bytes(8, "big") + + current = tuple(word & 0xFFFFFFFF for word in state) + for offset in range(0, len(padded), 64): + current = _sha256_compress_block(current, bytes(padded[offset : offset + 64])) + return b"".join(word.to_bytes(4, "big") for word in current) + + +def h5_encode_sha_digest(sign_input: str | bytes | bytearray) -> bytes: + """复现 H5 `$encode` 中用于 envelope CRC 字段的双层 SHA digest。""" + if isinstance(sign_input, str): + data = sign_input.encode("utf-8") + else: + data = bytes(sign_input) + first = _sha256_continue_from_virtual_prefix(data, H5_ENCODE_SHA_IV1, 64) + return _sha256_continue_from_virtual_prefix(first, H5_ENCODE_SHA_IV2, 64) + + +def h5_sig3_crc32_from_sign_input(sign_input: str | bytes | bytearray) -> int: + """返回 H5 envelope 14..17 字节对应的 little-endian 字段值。 + + 名字保留 `crc32` 是为了兼容既有字段命名;实际已确认不是标准 CRC32, + 而是 `$encode` 自定义双层 SHA digest 的首 32-bit word(按 envelope + 小端字段视图解释)。 + """ + digest = h5_encode_sha_digest(sign_input) + return int.from_bytes(digest[:4], "little") + + +def h5_sig3_crc32_from_10418_input( + input_value: str | bytes | bytearray, + t1: bytes | None = None, + t2: bytes | None = None, + hmac_key: bytes = KWSG_10418_HMAC_KEY, +) -> int: + """候选 CRC 生成器:CRC32(10418 binary48(input))。 + + 这个 helper 用于离线枚举 H5 `secPlain` 形态;当前只表示一个已知 + 强候选路径,不代表 H5 bridge 的输入已经完全闭合。 + """ + if isinstance(input_value, str): + input_bytes = input_value.encode("utf-8") + else: + input_bytes = bytes(input_value) + if t1 is None and t2 is None: + t1, t2 = load_kwsg_10418_tables() + elif t1 is None or t2 is None: + raise ValueError("t1 and t2 must be provided together") + return zlib.crc32(kwsg_10418_binary48(input_bytes, t1, t2, hmac_key)) & 0xFFFFFFFF + + +__all__ = [ + "H5_SIG3_BLOCK_TAG", + "H5_SIG3_DEFAULT_SESSION_SEED", + "H5_SIG3_DEFAULT_TAIL", + "H5_SIG3_HEX_LENGTH", + "H5_SIG3_LENGTH", + "H5_SIG3_MAGIC", + "H5Sig3Fields", + "build_h5_sig3_preimage", + "h5_sig3_crc32_from_10418_input", + "h5_sig3_crc32_from_sign_input", + "h5_sig3_expected_mask", + "h5_encode_sha_digest", + "h5_sig3_from_fields", + "h5_sig3_mix", + "h5_sig3_unmix", + "parse_h5_sig3", +] diff --git a/core/h5_vendor_encode.mjs b/core/h5_vendor_encode.mjs new file mode 100644 index 0000000..b9aefe0 --- /dev/null +++ b/core/h5_vendor_encode.mjs @@ -0,0 +1,243 @@ +import { readFileSync } from "node:fs"; +import { pathToFileURL } from "node:url"; + +export function installBrowserStubs(cookie = "") { + const g = globalThis; + g.window = g; + g.self = g; + g.top = g; + g.__assetsPath = "./"; + + Object.defineProperty(g, "navigator", { + value: { + userAgent: + "Mozilla/5.0 (Linux; Android 16; PJZ110 Build/BP2A.250605.015; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/149.0.7827.164 Mobile Safari/537.36 ksNebula/14.5.50.11631", + appVersion: "Android 16", + language: "zh-CN", + }, + configurable: true, + }); + g.screen = { width: 1080, height: 2376, availWidth: 1080, availHeight: 2376 }; + g.devicePixelRatio = 3; + Object.defineProperty(g, "location", { + value: { + href: "https://nebula.kuaishou.com/nebula/task/earning?&layoutType=4&source=bottom_guide_first", + search: "?layoutType=4&source=bottom_guide_first", + origin: "https://nebula.kuaishou.com", + pathname: "/nebula/task/earning", + hash: "", + hostname: "nebula.kuaishou.com", + assign(v) { + this.href = v; + }, + replace(v) { + this.href = v; + }, + }, + configurable: true, + }); + g.history = { state: null, length: 1, pushState() {}, replaceState() {}, back() {}, go() {} }; + + g.Event = class { + constructor(type, opts = {}) { + this.type = type; + this.cancelable = !!opts.cancelable; + this.defaultPrevented = false; + } + }; + g.CustomEvent = g.Event; + g.HTMLElement = class {}; + g.Element = class {}; + g.Node = class {}; + + const elem = (tag = "div") => { + const e = { + tagName: String(tag).toUpperCase(), + nodeType: 1, + style: {}, + children: [], + childNodes: [], + parentNode: { removeChild() {} }, + setAttribute() {}, + getAttribute() { + return null; + }, + appendChild(c) { + this.children.push(c); + this.childNodes.push(c); + return c; + }, + insertBefore(c) { + this.children.push(c); + this.childNodes.push(c); + return c; + }, + removeChild() {}, + addEventListener() {}, + removeEventListener() {}, + dispatchEvent() { + return true; + }, + href: "", + rel: "", + as: "", + crossOrigin: "", + cloneNode() { + return elem(tag); + }, + getBoundingClientRect() { + return { top: 0, left: 0, width: 1, height: 1, right: 1, bottom: 1 }; + }, + clientWidth: 1080, + clientHeight: 2376, + }; + Object.setPrototypeOf(e, Element.prototype); + return e; + }; + + Object.defineProperty(g, "document", { + value: { + cookie, + hidden: false, + visibilityState: "visible", + nodeType: 9, + createElement: elem, + createTextNode(text) { + return { nodeType: 3, textContent: text, nodeValue: text, childNodes: [], children: [] }; + }, + createEvent(type) { + return { + type, + initEvent(name, bubbles, cancelable) { + this.type = name; + this.bubbles = bubbles; + this.cancelable = cancelable; + }, + preventDefault() { + this.defaultPrevented = true; + }, + }; + }, + getElementsByTagName() { + return []; + }, + querySelector() { + return null; + }, + querySelectorAll() { + return []; + }, + addEventListener() {}, + removeEventListener() {}, + dispatchEvent() { + return true; + }, + }, + configurable: true, + }); + document.documentElement = elem("html"); + document.head = elem("head"); + document.body = elem("body"); + + g.getComputedStyle = () => ({ + display: "block", + visibility: "visible", + opacity: "1", + width: "1px", + height: "1px", + getPropertyValue() { + return ""; + }, + }); + g.localStorage = { getItem() { return null; }, setItem() {}, removeItem() {}, clear() {} }; + g.sessionStorage = g.localStorage; + g.performance = { now: () => Date.now(), mark() {}, measure() {} }; + g.requestAnimationFrame = (fn) => setTimeout(fn, 0); + g.cancelAnimationFrame = (id) => clearTimeout(id); + g.addEventListener = () => {}; + g.removeEventListener = () => {}; + g.dispatchEvent = () => true; + g.MutationObserver = class { + constructor() {} + observe() {} + disconnect() {} + takeRecords() { + return []; + } + }; + g.XMLHttpRequest = class { + open() {} + setRequestHeader() {} + send() { + this.readyState = 4; + this.status = 0; + this.onreadystatechange && this.onreadystatechange(); + } + addEventListener() {} + }; + g.fetch = async () => ({ ok: false, status: 0, json: async () => ({}), text: async () => "" }); + g.atob = (s) => Buffer.from(s, "base64").toString("binary"); + g.btoa = (s) => Buffer.from(s, "binary").toString("base64"); + Object.defineProperty(g, "crypto", { + value: { + getRandomValues(arr) { + for (let i = 0; i < arr.length; i++) arr[i] = Math.floor(Math.random() * 256); + return arr; + }, + }, + configurable: true, + }); +} + +export async function loadVendor() { + let src = readFileSync(new URL("./main-vendor-ox-x1_g5.mjs", import.meta.url), "utf8"); + src = src.replace( + 'import{_ as __vitePreload}from"./main-CZ3ZSK5w.js";', + "const __vitePreload=(base,deps,importerUrl)=>base();", + ); + return import("data:text/javascript;base64," + Buffer.from(src).toString("base64")); +} + +export function encodeWith(instance, signInput) { + return new Promise((resolve, reject) => { + instance.call("$encode", [ + signInput, + { + suc(result, cInfo) { + resolve({ result, cInfo }); + }, + err(error) { + reject(error); + }, + }, + ]); + }); +} + +async function main() { + const signInput = process.argv[2] === "-" ? readFileSync(0, "utf8") : process.argv[2] || "sigCatVer=1"; + const cookie = process.env.KS_COOKIE || ""; + const exportName = process.env.KS_VENDOR_EXPORT || "f"; + + installBrowserStubs(cookie); + const realConsole = { log: console.log, warn: console.warn, error: console.error }; + if (!process.env.KS_VENDOR_DEBUG) { + console.log = () => {}; + console.warn = () => {}; + console.error = () => {}; + } + const vendor = await loadVendor(); + console.log = realConsole.log; + console.warn = realConsole.warn; + console.error = realConsole.error; + const instance = vendor[exportName]; + if (!instance || typeof instance.call !== "function") { + throw new Error(`vendor export ${exportName} has no call()`); + } + const encoded = await encodeWith(instance, signInput); + console.log(JSON.stringify({ exportName, signInput, ...encoded }, null, 2)); +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + await main(); +} diff --git a/core/h5_vendor_encode_server.mjs b/core/h5_vendor_encode_server.mjs new file mode 100644 index 0000000..0e4df38 --- /dev/null +++ b/core/h5_vendor_encode_server.mjs @@ -0,0 +1,57 @@ +import readline from "node:readline"; + +import { encodeWith, installBrowserStubs, loadVendor } from "./h5_vendor_encode.mjs"; + +const cookie = process.env.KS_COOKIE || ""; +const exportName = process.env.KS_VENDOR_EXPORT || "f"; + +installBrowserStubs(cookie); + +const realConsole = { log: console.log, warn: console.warn, error: console.error }; +if (!process.env.KS_VENDOR_DEBUG) { + console.log = () => {}; + console.warn = () => {}; + console.error = () => {}; +} + +const vendor = await loadVendor(); +console.log = realConsole.log; +console.warn = realConsole.warn; +console.error = realConsole.error; + +const instance = vendor[exportName]; +if (!instance || typeof instance.call !== "function") { + throw new Error(`vendor export ${exportName} has no call()`); +} + +const rl = readline.createInterface({ + input: process.stdin, + crlfDelay: Infinity, +}); + +function writeJson(value) { + process.stdout.write(`${JSON.stringify(value)}\n`); +} + +rl.on("line", async (line) => { + if (!line.trim()) { + return; + } + let req; + try { + req = JSON.parse(line); + const signInput = String(req.signInput ?? ""); + const encoded = await encodeWith(instance, signInput); + writeJson({ id: req.id ?? null, ok: true, exportName, ...encoded }); + } catch (error) { + writeJson({ + id: req && "id" in req ? req.id : null, + ok: false, + error: error && error.stack ? error.stack : String(error), + }); + } +}); + +rl.on("close", () => { + process.exit(0); +}); diff --git a/core/http_transport.py b/core/http_transport.py new file mode 100644 index 0000000..5459b0f --- /dev/null +++ b/core/http_transport.py @@ -0,0 +1,142 @@ +"""HTTP transport sessions used by the login protocol client.""" + +from __future__ import annotations + +from typing import Any, Callable + + +OKHTTP4_ANDROID10_JA3 = ",".join( + [ + "771", + "4865-4866-4867-49195-49196-52393-49199-49200-52392-49171-49172-156-157-47-53", + "0-23-65281-10-11-35-16-5-13-51-45-43-21", + "29-23-24", + "0", + ] +) +OKHTTP4_ANDROID10_AKAMAI = "4:16777216|16711681|0|m,p,a,s" +OKHTTP4_ANDROID10_EXTRA_FP = { + "tls_signature_algorithms": [ + "ecdsa_secp256r1_sha256", + "rsa_pss_rsae_sha256", + "rsa_pkcs1_sha256", + "ecdsa_secp384r1_sha384", + "rsa_pss_rsae_sha384", + "rsa_pkcs1_sha384", + "rsa_pss_rsae_sha512", + "rsa_pkcs1_sha512", + "rsa_pkcs1_sha1", + ] +} + + +class _CurlCookieAdapter: + """Accept Playwright cookie attributes not represented by curl_cffi.""" + + def __init__(self, cookies: Any) -> None: + self._cookies = cookies + + def set( + self, + name: str, + value: str, + *, + domain: str = "", + path: str = "/", + secure: bool = False, + expires: int | None = None, + **_: Any, + ) -> None: + del expires + self._cookies.set( + name, + value, + domain=domain, + path=path, + secure=secure, + ) + + def __iter__(self): + return iter(self._cookies) + + def __getattr__(self, name: str) -> Any: + return getattr(self._cookies, name) + + +class OkHttp4Android10Session: + """Requests-like session with the documented OkHttp 4 Android 10 profile.""" + + def __init__(self, session: Any) -> None: + self._session = session + self.cookies = _CurlCookieAdapter(session.cookies) + + def request(self, method: str, url: str, **kwargs: Any) -> Any: + kwargs.setdefault("http_version", "v2") + kwargs.setdefault("default_headers", False) + # The protocol client supplies its own Accept-Encoding header. + kwargs.setdefault("accept_encoding", None) + headers = kwargs.get("headers") + if headers is not None: + # HTTP/2 represents connection state at the framing layer. + kwargs["headers"] = { + str(name): value + for name, value in headers.items() + if str(name).lower() != "connection" + } + return self._session.request(method, url, **kwargs) + + def get(self, url: str, **kwargs: Any) -> Any: + return self.request("GET", url, **kwargs) + + def post(self, url: str, **kwargs: Any) -> Any: + return self.request("POST", url, **kwargs) + + def close(self) -> None: + self._session.close() + + +def create_http_session( + transport: str, + *, + curl_session: Any | None = None, + curl_session_factory: Callable[..., Any] | None = None, +) -> Any: + """Create a shared requests-compatible session for one transport profile.""" + + if transport == "requests": + import requests + + session = requests.Session() + # OkHttp does not add requests' default ``Accept: */*`` header. + headers = getattr(session, "headers", None) + if headers is not None: + headers.pop("Accept", None) + return session + + if transport != "okhttp4-android10": + raise ValueError(f"unsupported HTTP transport: {transport}") + + if curl_session is None: + if curl_session_factory is None: + try: + from curl_cffi.requests import Session as curl_session_factory + except ImportError as exc: + raise RuntimeError( + "okhttp4-android10 transport requires the curl-cffi dependency" + ) from exc + curl_session = curl_session_factory( + ja3=OKHTTP4_ANDROID10_JA3, + akamai=OKHTTP4_ANDROID10_AKAMAI, + extra_fp=OKHTTP4_ANDROID10_EXTRA_FP, + default_headers=False, + ) + return OkHttp4Android10Session(curl_session) + + +__all__ = [ + "OKHTTP4_ANDROID10_AKAMAI", + "OKHTTP4_ANDROID10_EXTRA_FP", + "OKHTTP4_ANDROID10_JA3", + "OkHttp4Android10Session", + "create_http_session", +] diff --git a/core/ksse_crc.py b/core/ksse_crc.py new file mode 100644 index 0000000..2e45336 --- /dev/null +++ b/core/ksse_crc.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Small libksse checksum primitives recovered from native code.""" + +from __future__ import annotations + +import zlib + + +def ksse_crc32(data: bytes, seed: int = 0) -> int: + """Match libksse FUN_001567b8(seed, data, len(data)).""" + + return zlib.crc32(data, seed) & 0xFFFFFFFF diff --git a/core/ksse_deobf.py b/core/ksse_deobf.py new file mode 100644 index 0000000..bfc4cc9 --- /dev/null +++ b/core/ksse_deobf.py @@ -0,0 +1,120 @@ +"""Pure Python port of libksse static string deobfuscation helpers. + +Recovered native path: + +* FUN_00150ba0 wraps the decoded bytes into a C++ string. +* FUN_001502f0 reads a little-endian uint16 length followed by encrypted bytes. +* FUN_0014fe6c seeds three LFSR-like registers from bytes 4..7 of the seed. +* FUN_00150128 emits one keystream byte and returns ``(ks + 3) ^ cipher``. + +The default seed literal is visible in libksse: ``Vuz4fCHxn1CO``. +""" + +from __future__ import annotations + +from dataclasses import dataclass + + +DEFAULT_KSSE_STRING_SEED = b"Vuz4fCHxn1CO" + + +def _u32(value: int) -> int: + return value & 0xFFFFFFFF + + +@dataclass +class KsseStringState: + ac48: int + ac4c: int + ac50: int + ac54: int = 0x80000062 + ac58: int = 0x40000020 + ac5c: int = 0x10000002 + ac60: int = 0x7FFFFFFF + ac64: int = 0x3FFFFFFF + ac68: int = 0x0FFFFFFF + ac6c: int = 0x80000000 + ac70: int = 0xC0000000 + ac74: int = 0xF0000000 + + +def init_ksse_string_state(seed: bytes | str = DEFAULT_KSSE_STRING_SEED) -> KsseStringState: + if isinstance(seed, str): + seed = seed.encode("utf-8") + if len(seed) > 20 or not seed: + seed = b"quajdsfjasodfue" + if len(seed) < 12: + seed = seed + seed[: 12 - len(seed)] + + # Ghidra expression is a 32-bit byte swap of *(uint32_t *)(seed + 4). + word = int.from_bytes(seed[4:8], "big") + if word == 0: + return KsseStringState(ac48=0x13579BDF, ac4c=0x2468ACE0, ac50=0xFDB97531) + return KsseStringState(ac48=word, ac4c=word, ac50=word) + + +def decode_ksse_string_byte(cipher_byte: int, state: KsseStringState) -> int: + """Port sub_00150128 for a single byte.""" + + out = 0 + bit6 = state.ac50 & 1 + bit7 = state.ac4c & 1 + reg50 = state.ac50 + reg4c = state.ac4c + + for _ in range(8): + if (state.ac48 & 1) == 0: + state.ac48 = _u32(state.ac60 & (state.ac48 >> 1)) + if (reg50 & 1) == 0: + bit6 = 0 + reg50 = _u32(state.ac68 & (reg50 >> 1)) + state.ac50 = reg50 + else: + reg50 = _u32(((state.ac5c >> 1) ^ reg50) | state.ac74) + bit6 = 1 + state.ac50 = reg50 + else: + state.ac48 = _u32(((state.ac54 >> 1) ^ state.ac48) | state.ac6c) + if (reg4c & 1) == 0: + reg4c = _u32(state.ac64 & (reg4c >> 1)) + bit7 = 0 + state.ac4c = reg4c + else: + reg4c = _u32(((state.ac58 >> 1) ^ reg4c) | state.ac70) + bit7 = 1 + state.ac4c = reg4c + out = ((bit6 ^ bit7) | ((out & 0x7F) << 1)) & 0xFF + + return ((out + 3) & 0xFF) ^ (cipher_byte & 0xFF) + + +def decode_ksse_string_payload(payload: bytes, seed: bytes | str = DEFAULT_KSSE_STRING_SEED) -> bytes: + state = init_ksse_string_state(seed) + return bytes(decode_ksse_string_byte(item, state) for item in payload) + + +def decode_ksse_string_blob(blob: bytes, seed: bytes | str = DEFAULT_KSSE_STRING_SEED) -> bytes: + if len(blob) < 2: + raise ValueError("encoded blob must contain a 16-bit length prefix") + length = int.from_bytes(blob[:2], "little") + payload = blob[2 : 2 + length] + if len(payload) != length: + raise ValueError(f"encoded blob length mismatch: need {length}, got {len(payload)}") + return decode_ksse_string_payload(payload, seed) + + +def pack_le_values(*items: tuple[int, int]) -> bytes: + """Pack decompiler stack constants as little-endian byte fragments.""" + + return b"".join(value.to_bytes(size, "little") for value, size in items) + + +__all__ = [ + "DEFAULT_KSSE_STRING_SEED", + "KsseStringState", + "decode_ksse_string_blob", + "decode_ksse_string_byte", + "decode_ksse_string_payload", + "init_ksse_string_state", + "pack_le_values", +] diff --git a/core/ksse_sted.py b/core/ksse_sted.py new file mode 100644 index 0000000..37a7e56 --- /dev/null +++ b/core/ksse_sted.py @@ -0,0 +1,779 @@ +"""Semantic model for libksse command 1114139 / EngineProxy.sted. + +This is not a full native allocator port. It captures the recovered behavior +that matters for the EGID/cache_m path: + +* the decoded string table used by FUN_00142bf4; +* sentinel file names written by FUN_00140ea8 and read by FUN_00142bf4; +* suffix recovery polarity: existing path selects the candidate character; +* product-keyed JSON returned by FUN_00143d98. +""" + +from __future__ import annotations + +import json +import hashlib +import time +from dataclasses import dataclass +from typing import Callable, Iterable + +from .ksse_crc import ksse_crc32 + + +KSSE_DFP_TABLE_RAW = ( + "0123456789ABCDEF@/.Android_@KUAISHOU@a21c40ada1eb475b@" + "DFP@/sdcard/Android@NEBULA" +) + +KSSE_DOCUMENTS_DIR = "/sdcard/Documents" +STED_CACHE_FILE_TOKEN = "LnNrdmVj" +STED_CACHE_FILE_NAME = ".skvec" +STED_SHARED_PREF_KEY = "kwtk_n" +DFP_SUFFIX_LEN = 0x3D + + +class KsseSentinelMissing(ValueError): + """Raised when the sentinel set cannot recover a full DFP suffix.""" + + +@dataclass(frozen=True) +class KsseDfpStringTable: + alphabet: str + android_hidden_dir_suffix: str + default_product: str + static_salt: str + dfp_prefix: str + sdcard_android_dir: str + active_product: str + + @classmethod + def parse(cls, raw: str = KSSE_DFP_TABLE_RAW) -> "KsseDfpStringTable": + parts = raw.split("@") + if len(parts) != 7: + raise ValueError(f"unexpected libksse DFP table entry count: {len(parts)}") + return cls( + alphabet=parts[0], + android_hidden_dir_suffix=parts[1], + default_product=parts[2], + static_salt=parts[3], + dfp_prefix=parts[4], + sdcard_android_dir=parts[5], + active_product=parts[6], + ) + + +@dataclass(frozen=True) +class StedJsonInsertionPlan: + """One product-keyed JSON insertion attempt in ``FUN_00143d98``.""" + + output_key: str + stage: str + candidate_paths: list[str] + guard: str + + +@dataclass(frozen=True) +class StedPersistenceArtifacts: + """Java/native EGID persistence artifacts after ``rq0.d.e(cache_e, cache_m)``.""" + + cache_json: str + in_memory_cache: dict[str, str] + shared_preferences: dict[str, str] + app_private_files: dict[str, str] + product_marker: str + native_base_path: str + native_sentinel_paths: list[str] + native_readback_json: str + + +def normalize_product_marker(marker: str | None, fallback: str = "NEBULA") -> str: + """Convert native marker like ``0NEBULA`` / ``1KWE_N`` to product key.""" + + if not marker: + return fallback + marker = str(marker) + if marker[:1] in {"0", "1"}: + marker = marker[1:] + return marker or fallback + + +def ksse_md5_hex16(data: str | bytes) -> str: + """Return native ``FUN_001575d0`` + ``FUN_00151204(..., 8)`` output. + + ``FUN_00151204`` uses the lowercase nibble table at ``DAT_0015cd1f`` + (`0123456789abcdef...`), and top-level callers pass only the first + 8 digest bytes, so the Python equivalent is the first 16 lowercase + hexadecimal characters of MD5. + """ + + if isinstance(data, str): + data = data.encode("utf-8") + return hashlib.md5(data).hexdigest()[:16] + + +def engine_sted_product_marker(product: str = "NEBULA", writable_external_storage: bool = False) -> str: + """Return EngineProxy.sted's native marker argument. + + Java builds this as ``("1" if z else "0") + productName`` before calling + ``Watermelon.jniCommand(1114139, "", str, marker)``. On targetSdk >= 30 + the rq0.d.j() caller passes ``z=false``; legacy external-storage paths can + pass ``z=true`` when READ/WRITE external storage permission is available. + """ + + product = normalize_product_marker(product) + return ("1" if writable_external_storage else "0") + product + + +def build_sted_cache_json(cache_e: str, cache_m: str, c_time_ms: int) -> str: + """Build the compact JSONObject written by ``rq0.d.e``. + + Native Java insertion order is ``c_time`` -> ``cache_e`` -> ``cache_m``. + The same text is written to SharedPreferences ``kwtk_n`` and app-private + files ``.skvec``. + """ + + return json.dumps( + { + "c_time": int(c_time_ms), + "cache_e": str(cache_e), + "cache_m": str(cache_m), + }, + ensure_ascii=False, + separators=(",", ":"), + ) + + +def hidden_cache_path(base_path: str, suffix: str, table: KsseDfpStringTable | None = None) -> str: + """Return ``base + '/.Android_' + suffix`` as constructed by native code.""" + + table = table or KsseDfpStringTable.parse() + return f"{str(base_path).rstrip('/')}{table.android_hidden_dir_suffix}{suffix}" + + +def sted_external_candidate_paths( + product_marker: str | None, + *, + table: KsseDfpStringTable | None = None, + documents_dir: str = KSSE_DOCUMENTS_DIR, +) -> list[str]: + """First ``FUN_00143d98`` candidate pair: Documents then Android. + + Native initializes the primary base from the decoded ``/sdcard/Documents`` + constant and the fallback from table slot ``0x78`` (``/sdcard/Android``). + For ``KUAISHOU`` it appends the static salt; every other product key uses + ``md5(product_key)[:16]``. + """ + + table = table or KsseDfpStringTable.parse() + product = normalize_product_marker(product_marker, table.active_product) + suffix = table.static_salt if product == table.default_product else ksse_md5_hex16(product) + return [ + hidden_cache_path(documents_dir, suffix, table), + hidden_cache_path(table.sdcard_android_dir, suffix, table), + ] + + +def sted_product_salt_candidate_paths( + *, + table: KsseDfpStringTable | None = None, + documents_dir: str = KSSE_DOCUMENTS_DIR, +) -> list[str]: + """Candidate pair using the static table salt ``a21c40ada1eb475b``.""" + + table = table or KsseDfpStringTable.parse() + return [ + hidden_cache_path(documents_dir, table.static_salt, table), + hidden_cache_path(table.sdcard_android_dir, table.static_salt, table), + ] + + +def sted_hidden_md5_candidate_paths( + *, + table: KsseDfpStringTable | None = None, + documents_dir: str = KSSE_DOCUMENTS_DIR, + active_product: str | None = None, +) -> list[str]: + """Candidate pair using ``md5(table[0x90])[:16]``. + + Static flow hashes the active table product (currently ``NEBULA``), not + the dynamic marker passed in ``param_5``. + """ + + table = table or KsseDfpStringTable.parse() + product = active_product or table.active_product + suffix = ksse_md5_hex16(product) + return [ + hidden_cache_path(documents_dir, suffix, table), + hidden_cache_path(table.sdcard_android_dir, suffix, table), + ] + + +def sted_candidate_path_families( + product_marker: str | None, + *, + table: KsseDfpStringTable | None = None, + documents_dir: str = KSSE_DOCUMENTS_DIR, +) -> dict[str, list[str]]: + """Return the ordered path families currently recovered from ``sted``.""" + + table = table or KsseDfpStringTable.parse() + return { + "external": sted_external_candidate_paths( + product_marker, + table=table, + documents_dir=documents_dir, + ), + "product_salt": sted_product_salt_candidate_paths( + table=table, + documents_dir=documents_dir, + ), + "hidden_md5": sted_hidden_md5_candidate_paths( + table=table, + documents_dir=documents_dir, + ), + } + + +def sted_json_insertion_plan( + product_marker: str | None, + *, + table: KsseDfpStringTable | None = None, + documents_dir: str = KSSE_DOCUMENTS_DIR, +) -> list[StedJsonInsertionPlan]: + """Return native JSON insertion attempts for ``FUN_00143d98``. + + Each attempt still depends on successful suffix recovery. The native code + checks the output string length before prepending ``DFP`` and inserting the + member into the JSON object. + """ + + table = table or KsseDfpStringTable.parse() + product = normalize_product_marker(product_marker, table.active_product) + plans = [ + StedJsonInsertionPlan( + output_key=product, + stage="external_current", + candidate_paths=sted_external_candidate_paths( + product, + table=table, + documents_dir=documents_dir, + ), + guard="always attempted first; insert only if recovered suffix is non-empty", + ) + ] + + if product == table.active_product: + plans.append( + StedJsonInsertionPlan( + output_key=table.default_product, + stage="product_salt_default", + candidate_paths=sted_product_salt_candidate_paths( + table=table, + documents_dir=documents_dir, + ), + guard="bVar6 == true; product matches table[0x90] active product", + ) + ) + elif product == table.default_product: + plans.append( + StedJsonInsertionPlan( + output_key=table.active_product, + stage="hidden_md5_active", + candidate_paths=sted_hidden_md5_candidate_paths( + table=table, + documents_dir=documents_dir, + ), + guard="bVar1 == true; product matches table[0x30] default product", + ) + ) + else: + plans.extend( + [ + StedJsonInsertionPlan( + output_key=table.default_product, + stage="product_salt_default", + candidate_paths=sted_product_salt_candidate_paths( + table=table, + documents_dir=documents_dir, + ), + guard="!bVar1 && !bVar6; product is neither default nor active", + ), + StedJsonInsertionPlan( + output_key=table.active_product, + stage="hidden_md5_active", + candidate_paths=sted_hidden_md5_candidate_paths( + table=table, + documents_dir=documents_dir, + ), + guard="!bVar1 && !bVar6; product is neither default nor active", + ), + ] + ) + + return plans + + +def join_sentinel_base(base_path: str) -> str: + """Return the native sentinel prefix equivalent to ``base + '/.'``.""" + + base = str(base_path).rstrip("/") + return f"{base}/." + + +def sentinel_half(index: int, char: str) -> str: + """Return the half marker value used by FUN_00140ea8. + + Native compares the byte with ASCII ``'8'``: + ``0`` covers 0..7 and ``1`` covers 8..F for the uppercase hex alphabet. + """ + + if len(char) != 1: + raise ValueError("char must be one byte/character") + return "0" if ord(char) < ord("8") else "1" + + +def sentinel_half_path(base_path: str, index: int, half: str | int) -> str: + """Path for ``.@``.""" + + if index < 1: + raise ValueError("native sentinel indices are one-based") + half_text = str(half) + if half_text not in {"0", "1"}: + raise ValueError("half must be 0 or 1") + return f"{join_sentinel_base(base_path)}{index}@{half_text}" + + +def sentinel_char_path(base_path: str, index: int, char: str) -> str: + """Path for ``._``.""" + + if index < 1: + raise ValueError("native sentinel indices are one-based") + if len(char) != 1: + raise ValueError("char must be one byte/character") + return f"{join_sentinel_base(base_path)}{index}_{char}" + + +def sentinel_paths_for_suffix(base_path: str, suffix: str) -> list[str]: + """Return all sentinel paths FUN_00140ea8 would materialize.""" + + paths: list[str] = [] + for index, char in enumerate(suffix, start=1): + paths.append(sentinel_half_path(base_path, index, sentinel_half(index, char))) + paths.append(sentinel_char_path(base_path, index, char)) + return paths + + +def recover_suffix_from_sentinels( + base_path: str, + exists: Callable[[str], bool], + *, + alphabet: str | None = None, + length: int = DFP_SUFFIX_LEN, +) -> str: + """Recover the 61-byte DFP suffix using FUN_00142bf4's probe order.""" + + table = KsseDfpStringTable.parse() + alphabet = alphabet or table.alphabet + if len(alphabet) < 16: + raise ValueError("alphabet must contain at least 16 characters") + + recovered: list[str] = [] + for index in range(1, length + 1): + if exists(sentinel_half_path(base_path, index, "0")): + candidates = alphabet[:8] + elif exists(sentinel_half_path(base_path, index, "1")): + candidates = alphabet[8:16] + else: + candidates = alphabet[:16] + + for char in candidates: + if exists(sentinel_char_path(base_path, index, char)): + recovered.append(char) + break + else: + raise KsseSentinelMissing( + f"missing sentinel for suffix index {index} under {base_path!r}" + ) + + return "".join(recovered) + + +def ksse_suffix_crc_material( + suffix: str, + *, + model: str = "", + table_raw: str = KSSE_DFP_TABLE_RAW, +) -> bytes: + """Material that FUN_00142bf4 feeds to FUN_001567b8 / CRC32. + + Static evidence shows the native code appends the raw table, then the + recovered suffix after in-place reversal, then ``ro.product.model``. + """ + + return (table_raw + suffix[::-1] + model).encode("utf-8") + + +def ksse_suffix_crc32( + suffix: str, + *, + model: str = "", + table_raw: str = KSSE_DFP_TABLE_RAW, +) -> int: + return ksse_crc32(ksse_suffix_crc_material(suffix, model=model, table_raw=table_raw)) + + +def dfp_suffix_from_value( + value: str, + *, + table: KsseDfpStringTable | None = None, + strict: bool = True, +) -> str: + """Return the 61-byte suffix from ``DFP...`` or a raw suffix string.""" + + table = table or KsseDfpStringTable.parse() + text = str(value) + if text.startswith(table.dfp_prefix): + text = text[len(table.dfp_prefix) :] + if strict and len(text) != DFP_SUFFIX_LEN: + raise ValueError(f"DFP suffix must be {DFP_SUFFIX_LEN} characters, got {len(text)}") + return text + + +def ksse_dfp_suffix_crc_material( + suffix: str, + *, + model: str = "", + table_raw: str = KSSE_DFP_TABLE_RAW, +) -> bytes: + """CRC material after native reverses recovered marker-order suffix back.""" + + if len(suffix) != DFP_SUFFIX_LEN: + raise ValueError(f"DFP suffix must be {DFP_SUFFIX_LEN} characters, got {len(suffix)}") + return (table_raw + suffix + model).encode("utf-8") + + +def ksse_dfp_suffix_crc32( + suffix: str, + *, + model: str = "", + table_raw: str = KSSE_DFP_TABLE_RAW, +) -> int: + return ksse_crc32(ksse_dfp_suffix_crc_material(suffix, model=model, table_raw=table_raw)) + + +def sted_writer_marker_suffix(value: str, *, table: KsseDfpStringTable | None = None) -> str: + """Suffix order written by ``FUN_00140ea8`` sentinel files. + + The writer receives a Java-visible ``DFP`` value, strips the ``DFP`` prefix, + reverses the 61-byte suffix, then materializes sentinels for that reversed + byte order. + """ + + return dfp_suffix_from_value(value, table=table)[::-1] + + +def sted_crc_marker_path( + base_path: str, + value: str, + *, + model: str = "", + table: KsseDfpStringTable | None = None, + table_raw: str = KSSE_DFP_TABLE_RAW, +) -> str: + """Path for the CRC guard marker written after all byte sentinels.""" + + suffix = dfp_suffix_from_value(value, table=table) + crc = ksse_dfp_suffix_crc32(suffix, model=model, table_raw=table_raw) + return f"{join_sentinel_base(base_path)}{crc}" + + +def sted_writer_sentinel_paths(base_path: str, value: str) -> list[str]: + """Per-byte sentinel files created by ``FUN_00140ea8`` for a DFP value.""" + + return sentinel_paths_for_suffix(base_path, sted_writer_marker_suffix(value)) + + +def sted_writer_paths( + base_path: str, + value: str, + *, + model: str = "", + include_crc: bool = True, +) -> list[str]: + """All deterministic marker paths created by ``FUN_00140ea8``. + + File contents are just a small truth marker; path names carry the data. + """ + + paths = sted_writer_sentinel_paths(base_path, value) + if include_crc: + paths.append(sted_crc_marker_path(base_path, value, model=model)) + return paths + + +def build_sted_persistence_artifacts( + cache_e: str, + cache_m: str, + *, + c_time_ms: int | None = None, + product: str = "NEBULA", + writable_external_storage: bool = False, + model: str = "", + include_crc: bool = True, + table: KsseDfpStringTable | None = None, + documents_dir: str = KSSE_DOCUMENTS_DIR, +) -> StedPersistenceArtifacts: + """Build deterministic Java/native persistence artifacts for an EGID. + + This models the confirmed ``rq0.d.e(cache_e, cache_m)`` chain: + + 1. put ``c_time/cache_e/cache_m`` into the in-memory map; + 2. write the same JSON to SharedPreferences key ``kwtk_n``; + 3. write the same JSON to app-private file ``.skvec``; + 4. call ``EngineProxy.sted(cache_e, z)`` to materialize native sentinel + files for command ``1114139``. + + It deliberately does not try to reproduce the optional external + Java-serialized ``LinkedHashMap`` file from ``rq0.d.j`` because that path is + encrypted through ``uq0.o`` and is not needed for the native STED readback. + """ + + table = table or KsseDfpStringTable.parse() + dfp_suffix_from_value(cache_e, table=table) + if c_time_ms is None: + c_time_ms = int(time.time() * 1000) + cache_json = build_sted_cache_json(cache_e, cache_m, c_time_ms) + product_marker = engine_sted_product_marker( + product, + writable_external_storage=writable_external_storage, + ) + native_base_path = sted_external_candidate_paths( + product_marker, + table=table, + documents_dir=documents_dir, + )[0] + native_sentinel_paths = sted_writer_paths( + native_base_path, + cache_e, + model=model, + include_crc=include_crc, + ) + existing = set(native_sentinel_paths) + native_readback_json = recover_sted_result_json_from_sentinels( + product_marker, + existing.__contains__, + model=model, + require_crc=include_crc, + table=table, + documents_dir=documents_dir, + ) + return StedPersistenceArtifacts( + cache_json=cache_json, + in_memory_cache={ + "c_time": str(int(c_time_ms)), + "cache_e": str(cache_e), + "cache_m": str(cache_m), + }, + shared_preferences={STED_SHARED_PREF_KEY: cache_json}, + app_private_files={STED_CACHE_FILE_NAME: cache_json}, + product_marker=product_marker, + native_base_path=native_base_path, + native_sentinel_paths=native_sentinel_paths, + native_readback_json=native_readback_json, + ) + + +def recover_dfp_suffix_from_sted_sentinels( + base_path: str, + exists: Callable[[str], bool], + *, + model: str = "", + require_crc: bool = False, +) -> str: + """Recover the Java-visible DFP suffix from writer-created sentinels.""" + + marker_order = recover_suffix_from_sentinels(base_path, exists) + suffix = marker_order[::-1] + if require_crc and not exists(sted_crc_marker_path(base_path, suffix, model=model)): + raise KsseSentinelMissing(f"missing CRC marker for recovered suffix under {base_path!r}") + return suffix + + +def recover_dfp_value_from_sted_sentinels( + base_path: str, + exists: Callable[[str], bool], + *, + model: str = "", + require_crc: bool = False, + table: KsseDfpStringTable | None = None, +) -> str: + """Recover ``DFP`` + suffix from writer-created sentinels.""" + + table = table or KsseDfpStringTable.parse() + suffix = recover_dfp_suffix_from_sted_sentinels( + base_path, + exists, + model=model, + require_crc=require_crc, + ) + return table.dfp_prefix + suffix + + +def recover_first_dfp_value_from_candidate_paths( + candidate_paths: Iterable[str], + exists: Callable[[str], bool], + *, + model: str = "", + require_crc: bool = False, + table: KsseDfpStringTable | None = None, +) -> str | None: + """Try native primary/fallback path order and return the first DFP value.""" + + table = table or KsseDfpStringTable.parse() + for base_path in candidate_paths: + try: + return recover_dfp_value_from_sted_sentinels( + base_path, + exists, + model=model, + require_crc=require_crc, + table=table, + ) + except KsseSentinelMissing: + continue + return None + + +def recover_sted_values_from_sentinels( + product_marker: str | None, + exists: Callable[[str], bool], + *, + model: str = "", + require_crc: bool = False, + table: KsseDfpStringTable | None = None, + documents_dir: str = KSSE_DOCUMENTS_DIR, +) -> dict[str, str]: + """Recover ``FUN_00143d98`` product-keyed values from sentinel files. + + This models the Java-visible ``EngineProxy.sted(null,z)`` read path: + every planned JSON member is attempted in native insertion order, each + member uses its own primary/fallback path pair, and missing sentinel sets + simply skip that JSON member. + """ + + table = table or KsseDfpStringTable.parse() + values: dict[str, str] = {} + for plan in sted_json_insertion_plan( + product_marker, + table=table, + documents_dir=documents_dir, + ): + value = recover_first_dfp_value_from_candidate_paths( + plan.candidate_paths, + exists, + model=model, + require_crc=require_crc, + table=table, + ) + if value: + values[plan.output_key] = value + return values + + +def recover_sted_result_json_from_sentinels( + product_marker: str | None, + exists: Callable[[str], bool], + *, + model: str = "", + require_crc: bool = False, + table: KsseDfpStringTable | None = None, + documents_dir: str = KSSE_DOCUMENTS_DIR, +) -> str: + """Return compact product-keyed JSON recovered from native sentinels.""" + + return build_sted_result_json( + recover_sted_values_from_sentinels( + product_marker, + exists, + model=model, + require_crc=require_crc, + table=table, + documents_dir=documents_dir, + ) + ) + + +def build_sted_result_json(values: dict[str, str]) -> str: + """Serialize product-keyed DFP values like FUN_00154a0c compact mode.""" + + return json.dumps(values, ensure_ascii=False, separators=(",", ":")) + + +def parse_sted_result_json(data: str) -> dict[str, str]: + parsed = json.loads(data) + if not isinstance(parsed, dict): + raise ValueError("sted result must be a JSON object") + return {str(key): str(value) for key, value in parsed.items()} + + +def select_sted_product_value(data: str | dict[str, str], marker: str | None) -> str: + """Select current product's DFP value from FUN_00143d98-style JSON.""" + + values = parse_sted_result_json(data) if isinstance(data, str) else data + product = normalize_product_marker(marker) + if product in values: + return values[product] + table = KsseDfpStringTable.parse() + if table.default_product in values: + return values[table.default_product] + if values: + return next(iter(values.values())) + raise KeyError("empty sted result") + + +__all__ = [ + "DFP_SUFFIX_LEN", + "KSSE_DOCUMENTS_DIR", + "KSSE_DFP_TABLE_RAW", + "STED_CACHE_FILE_NAME", + "STED_CACHE_FILE_TOKEN", + "STED_SHARED_PREF_KEY", + "KsseDfpStringTable", + "KsseSentinelMissing", + "StedJsonInsertionPlan", + "StedPersistenceArtifacts", + "build_sted_cache_json", + "build_sted_persistence_artifacts", + "build_sted_result_json", + "dfp_suffix_from_value", + "engine_sted_product_marker", + "hidden_cache_path", + "join_sentinel_base", + "ksse_dfp_suffix_crc32", + "ksse_dfp_suffix_crc_material", + "ksse_md5_hex16", + "ksse_suffix_crc32", + "ksse_suffix_crc_material", + "normalize_product_marker", + "parse_sted_result_json", + "recover_first_dfp_value_from_candidate_paths", + "recover_dfp_value_from_sted_sentinels", + "recover_dfp_suffix_from_sted_sentinels", + "recover_suffix_from_sentinels", + "recover_sted_result_json_from_sentinels", + "recover_sted_values_from_sentinels", + "select_sted_product_value", + "sentinel_char_path", + "sentinel_half", + "sentinel_half_path", + "sentinel_paths_for_suffix", + "sted_candidate_path_families", + "sted_external_candidate_paths", + "sted_hidden_md5_candidate_paths", + "sted_json_insertion_plan", + "sted_product_salt_candidate_paths", + "sted_crc_marker_path", + "sted_writer_marker_suffix", + "sted_writer_paths", + "sted_writer_sentinel_paths", +] diff --git a/core/kwf-0.0.2.2cee19b4b7dec496.js b/core/kwf-0.0.2.2cee19b4b7dec496.js new file mode 100644 index 0000000..4aa27a3 --- /dev/null +++ b/core/kwf-0.0.2.2cee19b4b7dec496.js @@ -0,0 +1 @@ +(function(){ function Brook() {var _ace_5540 = 2147483647,_ace_9c47 = 1,_ace_21601 = 0,_ace_09c09 = !!_ace_9c47,_ace_1016d = !!_ace_21601;return function (_ace_796b2, _ace_cb2ba, _ace_38d43) {var _ace_293c4 = [],_ace_92626 = [],_ace_0d780 = {},_ace_0095 = [],_ace_e28e = { _ace_d789d: _ace_796b2 },_ace_3ac = {},_ace_5b5c3 = _ace_21601,_ace_3c075 = [];var decode=function(j){if(!j){return""}var n=function(e){var f=[],t=e.length;var u=0;for(var u=0;u>7)&255)==0){f.push(e.charAt(u))}else{if(((w>>5)&255)==6){var b=e.charCodeAt(++u);var a=(w&31)<<6;var c=b&63;var v=a|c;f.push(String.fromCharCode(v))}else{if(((w>>4)&255)==14){var b=e.charCodeAt(++u);var d=e.charCodeAt(++u);var a=(w<<4)|((b>>2)&15);var c=((b&3)<<6)|(d&63);var v=((a&255)<<8)|c;f.push(String.fromCharCode(v))}}}}return f.join("")};var k="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");var p=j.length;var l=0;var m=[];while(l>4);var h=((r&15)<<4)|(q>>2);var g=((q&3)<<6)|o;m.push(String.fromCharCode(i));if(q!=64){m.push(String.fromCharCode(h))}if(o!=64){m.push(String.fromCharCode(g))}}return n(m.join(""))};var _ace_c3945 = function (_ace_7eb, _ace_e2136, _ace_d1b2c, _ace_9e13e) {return { _ace_c29a2: _ace_7eb, _ace_71ab4: _ace_e2136, _ace_82516: _ace_d1b2c, _ace_8e3b7: _ace_9e13e };};var _ace_27b80 = function (_ace_9e13e) {return _ace_9e13e._ace_8e3b7 ? _ace_9e13e._ace_71ab4[_ace_9e13e._ace_82516] : _ace_9e13e._ace_c29a2;};var _ace_236a43 = function (_ace_8c645, _ace_b25aa) {return _ace_b25aa.hasOwnProperty(_ace_8c645) ? _ace_09c09 : _ace_1016d;};var _ace_236a42 = function (_ace_8c645, _ace_b25aa) {if (_ace_236a43(_ace_8c645, _ace_b25aa)) {return _ace_c3945(_ace_21601, _ace_b25aa, _ace_8c645, _ace_9c47);}var _ace_8034;if (_ace_b25aa._ace_184c6) {_ace_8034 = _ace_236a42(_ace_8c645, _ace_b25aa._ace_184c6);if (_ace_8034) {return _ace_8034;}}if (_ace_b25aa._ace_903e6) {_ace_8034 = _ace_236a42(_ace_8c645, _ace_b25aa._ace_903e6);if (_ace_8034) {return _ace_8034;}}return _ace_1016d;};var _ace_236a4 = function (_ace_8c645) {var _ace_8034 = _ace_236a42(_ace_8c645, _ace_0d780);if (_ace_8034) {return _ace_8034;}return _ace_c3945(_ace_21601, _ace_0d780, _ace_8c645, _ace_9c47);};var _ace_ab2a = function () {_ace_293c4 = (_ace_0d780._ace_e2242) ? _ace_0d780._ace_e2242 : _ace_0095;_ace_0d780 = (_ace_0d780._ace_903e6) ? _ace_0d780._ace_903e6 : _ace_0d780;_ace_5b5c3--};var _ace_329bc = function (_ace_5cea0) {_ace_0d780 = {_ace_903e6: _ace_0d780,_ace_184c6: _ace_5cea0,_ace_e2242: _ace_293c4};_ace_293c4 = [];_ace_5b5c3++};var _ace_30ac = function () {_ace_3c075.push(_ace_c3945(_ace_5b5c3, _ace_21601, _ace_21601, _ace_21601))};var _ace_dacc6 = function () {return _ace_27b80(_ace_3c075.pop())};var _ace_21e79 = function (_ace_9067e, _ace_4e629) {return _ace_3ac[_ace_9067e] = _ace_4e629;};var _ace_b3278 = function (_ace_9067e) {return _ace_3ac[_ace_9067e];};var _ace_0b85 = [_ace_c3945(_ace_21601, _ace_21601, _ace_21601, _ace_21601),_ace_c3945(_ace_21601, _ace_21601, _ace_21601, _ace_21601),_ace_c3945(_ace_21601, _ace_21601, _ace_21601, _ace_21601),_ace_c3945(_ace_21601, _ace_21601, _ace_21601, _ace_21601),_ace_c3945(_ace_21601, _ace_21601, _ace_21601, _ace_21601)];var _ace_47ea = [_ace_38d43,function _ace_7d2aa(_ace_d1b2c) {return _ace_0b85[_ace_d1b2c];},function (_ace_d1b2c) {return _ace_c3945(_ace_21601, _ace_e28e._ace_6e75c, _ace_d1b2c, _ace_9c47);},function (_ace_d1b2c) {return _ace_236a4(_ace_d1b2c);},function (_ace_d1b2c) {return _ace_c3945(_ace_21601, _ace_796b2, _ace_cb2ba.d[_ace_d1b2c], _ace_9c47);},function (_ace_d1b2c) {return _ace_c3945(_ace_e28e._ace_d789d, _ace_21601, _ace_21601, _ace_21601);},function (_ace_d1b2c) {return _ace_c3945(_ace_21601, _ace_cb2ba.d, _ace_d1b2c, _ace_9c47);},function (_ace_d1b2c) {return _ace_c3945(_ace_e28e._ace_6e75c, _ace_38d43, _ace_38d43, _ace_21601);},function (_ace_d1b2c) {return _ace_c3945(_ace_21601, _ace_3ac, _ace_d1b2c, _ace_21601)}];var _ace_917a9 = function (_ace_b366, _ace_d1b2c) {return _ace_47ea[_ace_b366] ? _ace_47ea[_ace_b366](_ace_d1b2c) : _ace_c3945(_ace_21601, _ace_21601, _ace_21601, _ace_21601);};var _ace_ced96 = function (_ace_b366, _ace_d1b2c) {return _ace_27b80(_ace_917a9(_ace_b366, _ace_d1b2c));};var _ace_83bdb = function (_ace_7eb, _ace_e2136, _ace_d1b2c, _ace_9e13e) {_ace_0b85[_ace_21601] = _ace_c3945(_ace_7eb, _ace_e2136, _ace_d1b2c, _ace_9e13e)};var _ace_37b52 = function (_ace_043) {var _ace_da4c0 = _ace_21601;while (_ace_da4c0 < _ace_043.length) {var _ace_6dca6 = _ace_043[_ace_da4c0];var _ace_d93cb = _ace_c47[_ace_6dca6[_ace_21601]];_ace_da4c0 = _ace_d93cb(_ace_6dca6[1], _ace_6dca6[2], _ace_6dca6[3], _ace_6dca6[4], _ace_da4c0, _ace_8d9b, _ace_043);}};var _ace_bcdb = function (_ace_74bed, _ace_e3096, _ace_6dca6, _ace_043) {var _ace_ab2b8 = _ace_27b80(_ace_74bed);var _ace_39554 = _ace_27b80(_ace_e3096);if (_ace_ab2b8 == 2147483647) {return _ace_6dca6;}while (_ace_ab2b8 < _ace_39554) {var x = _ace_043[_ace_ab2b8];var _ace_d93cb = _ace_c47[x[_ace_21601]];_ace_ab2b8 = _ace_d93cb(x[1], x[2], x[3], x[4], _ace_ab2b8, _ace_8d9b, _ace_043);}return _ace_ab2b8;};var _ace_302e8 = function (_ace_ec082, _ace_043) {var _ace_65321 = _ace_293c4.splice(_ace_293c4.length - 6, 6);var _ace_74246 = _ace_65321[4]._ace_c29a2 != 2147483647;try {_ace_ec082 = _ace_bcdb(_ace_65321[0], _ace_65321[1], _ace_ec082, _ace_043);} catch (e) {_ace_0b85[2] = _ace_c3945(e, _ace_21601, _ace_21601, _ace_21601);_ace_ec082 = _ace_bcdb(_ace_65321[2], _ace_65321[3], _ace_ec082, _ace_043);_ace_0b85[2] = _ace_c3945(_ace_21601, _ace_21601, _ace_21601, _ace_21601);} finally {_ace_ec082 = _ace_bcdb(_ace_65321[4], _ace_65321[5], _ace_ec082, _ace_043);}return _ace_65321[5]._ace_c29a2 > _ace_ec082 ? _ace_65321[5]._ace_c29a2 : _ace_ec082;};var _ace_8d9b = decode(_ace_cb2ba.b).split('').reduce(function (_ace_27c25, _ace_6dca6) {if ((!_ace_27c25.length) || _ace_27c25[_ace_27c25.length - _ace_9c47].length == 5) { _ace_27c25.push([]); }_ace_27c25[_ace_27c25.length - _ace_9c47].push(-_ace_9c47 *1 +_ace_6dca6.charCodeAt());return _ace_27c25;}, []);var _ace_c47 = [function(p0, p1, p2, p3, p4, p5, p6) {var _ace_b66e5 = _ace_ced96(p0, p1);if (_ace_293c4.length < _ace_b66e5) {return ++p4;}var _ace_7e15 = _ace_293c4.splice(_ace_293c4.length - _ace_b66e5, _ace_b66e5).map(_ace_27b80),_ace_5c22d = _ace_293c4.pop(),_ace_37c88 = _ace_27b80(_ace_5c22d);_ace_7e15.unshift(null);_ace_83bdb(new (Function.prototype.bind.apply(_ace_37c88, _ace_7e15)), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) & _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) << _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _ace_5c22d = _ace_917a9(p0, p1),_ace_db499 = _ace_ced96(p0, p1) - 1;_ace_5c22d._ace_71ab4[_ace_5c22d._ace_82516] = _ace_db499;_ace_83bdb(_ace_db499, _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {throw _ace_293c4.pop(); } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) <= _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) | _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_0b85[4] = _ace_92626.pop();return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) + _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1), _ace_38d43, _ace_38d43, 0);var _ace_43927 = _ace_dacc6();while (_ace_43927 < _ace_5b5c3) {_ace_ab2a();}return Infinity; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) ^ _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _ace_71ea5 = _ace_8d9b.slice(_ace_ced96(p0, p1), _ace_ced96(p2, p3) + 1),_ace_cbec = _ace_0d780;_ace_83bdb(function () {_ace_e28e = {_ace_d789d: this || _ace_796b2,_ace_c6403: _ace_e28e,_ace_6e75c: arguments,_ace_184c6: _ace_cbec};_ace_37b52(_ace_71ea5);_ace_e28e = _ace_e28e._ace_c6403;return _ace_27b80(_ace_0b85[0]);}, _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) in _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(~_ace_ced96(p0, p1), _ace_38d43, _ace_38d43, 0);return ++p4; } ,,function(p0, p1, p2, p3, p4, p5, p6) {_ace_92626.push(_ace_0b85[0]);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_30ac();_ace_329bc(_ace_e28e._ace_184c6);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {return _ace_ced96(p0, p1); } ,function(p0, p1, p2, p3, p4, p5, p6) {var _ace_5c22d = _ace_917a9(p0, p1),_ace_db499 = _ace_ced96(p0, p1);_ace_83bdb(_ace_db499++, _ace_38d43, _ace_38d43, 0);_ace_5c22d._ace_71ab4[_ace_5c22d._ace_82516] = _ace_db499;return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) !== _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(typeof _ace_ced96(p0, p1), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) != _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) >> _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _ace_b66e5 = _ace_ced96(p0, p1);if (_ace_293c4.length < _ace_b66e5) {return ++p4;}var _ace_7e15 = _ace_293c4.splice(_ace_293c4.length - _ace_b66e5, _ace_b66e5).map(_ace_27b80),_ace_5c22d = _ace_293c4.pop(),_ace_37c88 = _ace_27b80(_ace_5c22d);_ace_83bdb(_ace_37c88.apply(typeof _ace_5c22d._ace_71ab4 == "undefined" ? _ace_796b2 : _ace_5c22d._ace_71ab4, _ace_7e15), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(0, _ace_27b80(_ace_917a9(p0, p1)), _ace_ced96(p2, p3), 1);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_ab2a();return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _ace_5c22d = _ace_917a9(p0, p1),_ace_db499 = _ace_ced96(p0, p1) + 1;_ace_5c22d._ace_71ab4[_ace_5c22d._ace_82516] = _ace_db499;_ace_83bdb(_ace_db499, _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_293c4.push(_ace_0b85[0]);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) * _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_ab2a();_ace_83bdb(_ace_38d43, _ace_38d43, _ace_38d43, 0, 0);_ace_dacc6();return Infinity; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) % _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {return _ace_302e8(p4, p6); } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_0d780[p1] = undefined;return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) / _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) - _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb({}, _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(!_ace_ced96(p0, p1), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _ace_98a2 = _ace_ced96(p0, p1),_ace_db499 = {};_ace_83bdb(_ace_21e79(_ace_98a2, _ace_db499), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) === _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) >= _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) instanceof _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(-_ace_ced96(p0, p1), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {return (!_ace_27b80(_ace_0b85[0])) ? _ace_ced96(p0, p1) : ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_0b85[3] = _ace_c3945(_ace_293c4.length, 0, 0, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) && _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _ace_5c22d = _ace_917a9(p0, p1);_ace_83bdb(delete _ace_5c22d._ace_71ab4[_ace_5c22d._ace_82516], _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _ace_81991 = _ace_ced96(p0, p1);_ace_83bdb(_ace_293c4.splice(_ace_293c4.length - _ace_81991, _ace_81991).map(_ace_27b80), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_0b85[4] = _ace_92626[_ace_92626.length - 1];return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) >>> _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _ace_5c22d = _ace_917a9(p0, p1),_ace_db499 = _ace_ced96(p0, p1);_ace_83bdb(_ace_db499--, _ace_38d43, _ace_38d43, 0);_ace_5c22d._ace_71ab4[_ace_5c22d._ace_82516] = _ace_db499;return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_0b85[1] = _ace_293c4.pop();return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_0b85[0] = _ace_293c4[_ace_293c4.length - 1];return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {return _ace_5540; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) || _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(+_ace_ced96(p0, p1), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) > _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) == _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {return _ace_27b80(_ace_0b85[0]) ? _ace_ced96(p0, p1) : ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _ace_98a2 = _ace_ced96(p0, p1);_ace_83bdb(_ace_b3278(_ace_98a2), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {debugger;return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_83bdb(_ace_ced96(p0, p1) < _ace_ced96(p2, p3), _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _ace_5c22d = _ace_917a9(p0, p1),_ace_db499 = _ace_ced96(p2, p3);_ace_83bdb(_ace_5c22d._ace_71ab4[_ace_5c22d._ace_82516] = _ace_db499, _ace_38d43, _ace_38d43, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_ace_329bc(null);return ++p4; } ];return _ace_37b52(_ace_8d9b);}; } ;Brook()(window,{"b":"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","d":["Q","W","E","R","T","Y","U","I","O","P","A","S","D","F","G","H","J","K","L","Z","X","C","V","B","N","M","q","w","e","r","t","y","u","i","o","p","a","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m","1","2","3","4","5","6","7","8","9","0","$","_","[","]",79,685,0,686,730,731,820,834,1249,1250,1445,3539,3715,3716,3916,3917,4062,4063,4354,4355,4435,4495,7342,9464,9508,9509,9755,9756,9942,9943,9958,9959,10210,".",1,false,66,"window",10211,10218,"+","/","Array",62,63,52,53,54,55,56,57,58,59,60,61,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,128,"location",2147483647,"document",";",86,"=",821,833,82,"decodeURIComponent",null,"undefined","encodeURIComponent","RegExp","%","(","|",")","escape","-","","Object",316,"Date",1000," ",348,386,406,1446,1455,1456,1592,1593,1675,1676,1797,1798,1986,1987,2663,2664,2695,3348,3378,3379,3538,"navigator",90,89,133,"localStorage","Number",80,114,113,120,"\"","'",179,178,185,true,81,129,172,93,127,153,170,189,207,226,243,271,286,307,329,339,362,375,385,407,425,446,466,486,505,527,548,569,593,617,642,664,671,675,2696,2832,2833,3014,3015,3077,3078,3347,"String","Math",97,135,"chrome",147,146,180,96,102,260,259,266,258,256,":",",",145,158,156,157,"process",95,99,100,130,154,155,104,109,108,111,150,164,197,"^","*",142,122,123,77,269,255,254,194,4436,4461,4462,4494,7343,7355,7356,7416,7417,7634,7635,7646,7647,7734,7735,7792,124,119,242,107,103,215,171,118,202,201,125,250,71,240,173,212,162,175,192,183,253,247,204,165,229,241,216,199,195,235,117,131,110,160,214,227,132,83,209,237,252,177,91,106,203,190,74,76,88,208,239,251,67,69,249,159,168,163,64,143,245,188,182,218,210,205,236,151,68,196,167,126,115,220,144,136,70,238,184,222,94,219,224,73,92,211,98,149,228,121,231,200,141,213,78,169,244,234,101,174,186,166,198,232,221,116,75,139,138,112,181,72,246,87,134,193,225,248,152,105,217,148,233,206,85,223,140,161,137,191,230,65,176,84,187,3.328402341E9,4.168907908E9,4.000806809E9,4.135287693E9,4.294111757E9,3.597364157E9,3.731845041E9,2.445657428E9,1613770832,33620227,3.462883241E9,1445669757,3.892248089E9,3.050821474E9,1303096294,3.967186586E9,2.412431941E9,528646813,2.311702848E9,4.202528135E9,4.026202645E9,2.992200171E9,2.387036105E9,4.226871307E9,1101901292,3.017069671E9,1604494077,1169141738,597466303,1403299063,3.832705686E9,2.613100635E9,1974974402,3.791519004E9,1033081774,1277568618,1815492186,2118074177,4.126668546E9,2.211236943E9,1748251740,1369810420,3.521504564E9,4.193382664E9,3.799085459E9,2.883115123E9,1647391059,706024767,134480908,2.512897874E9,1176707941,2.646852446E9,806885416,932615841,168101135,798661301,235341577,605164086,461406363,3.756188221E9,3.454790438E9,1311188841,2142417613,3.933566367E9,302582043,495158174,1479289972,874125870,907746093,3.698224818E9,3.025820398E9,1537253627,2.756858614E9,1983593293,3.084310113E9,2108928974,1378429307,3.722699582E9,1580150641,327451799,2.790478837E9,3.117535592E9,3.253595436E9,1075847264,3.825007647E9,2041688520,3.059440621E9,3.563743934E9,2.378943302E9,1740553945,1916352843,2.487896798E9,2.555137236E9,2.958579944E9,2.244988746E9,3.151024235E9,3.320835882E9,1336584933,3.992714006E9,2.252555205E9,2.588757463E9,1714631509,293963156,2.319795663E9,3.925473552E9,67240454,4.269768577E9,2.68961816E9,2017213508,631218106,1269344483,2.723238387E9,1571005438,2.151694528E9,93294474,1066570413,563977660,1882732616,4.0594281E9,1673313503,2008463041,2.950355573E9,1109467491,537923632,3.85875945E9,4.260623118E9,3.218264685E9,2.1777483E9,403442708,638784309,3.287084079E9,3.193921505E9,899127202,2.286175436E9,773265209,2.479146071E9,1437050866,4.236148354E9,2050833735,3.362022572E9,3.126681063E9,840505643,3.866325909E9,3.227541664E9,427917720,2.655997905E9,2.749160575E9,1143087718,1412049534,999329963,193497219,2.353415882E9,3.354324521E9,1807268051,672404540,2.816401017E9,3.160301282E9,369822493,2.916866934E9,3.688947771E9,1681011286,1949973070,336202270,2.454276571E9,201721354,1210328172,3.093060836E9,2.680341085E9,3.184776046E9,1135389935,3.294782118E9,965841320,831886756,3.554993207E9,4.068047243E9,3.58874501E9,2.345191491E9,1849112409,3.664604599E9,26054028,2.983581028E9,2.622377682E9,1235855840,3.630984372E9,2.891339514E9,4.092916743E9,3.488279077E9,3.395642799E9,4.10166747E9,1202630377,268961816,1874508501,4.034427016E9,1243948399,1546530418,941366308,1470539505,1941222599,2.546386513E9,3.421038627E9,2.715671932E9,3.89994614E9,1042226977,2.521517021E9,1639824860,227249030,260737669,3.765465232E9,2084453954,1907733956,3.429263018E9,2.420656344E9,100860677,4.160157185E9,470683154,3.261161891E9,1781871967,2.924959737E9,1773779408,394692241,2.579611992E9,974986535,664706745,3.655459128E9,3.958962195E9,731420851,571543859,3.530123707E9,2.84962648E9,126783113,865375399,765172662,1008606754,361203602,3.387549984E9,2.278477385E9,2.857719295E9,1344809080,2.782912378E9,59542671,1503764984,160008576,437062935,1707065306,3.622233649E9,2.218934982E9,3.49650348E9,2.185314755E9,697932208,1512910199,504303377,2075177163,2.824099068E9,1841019862,739644986,2.781242211E9,2.230877308E9,2.582542199E9,2.381740923E9,234877682,3.184946027E9,2.984144751E9,1418839493,1348481072,50462977,2.848876391E9,2102799147,434634494,1656084439,3.863849899E9,2.599188086E9,1167051466,2.636087938E9,1082771913,2.281340285E9,368048890,3.954334041E9,3.381544775E9,201060592,3.963727277E9,1739838676,4.250903202E9,3.930435503E9,3.206782108E9,4.149453988E9,2.531553906E9,1536934080,3.262494647E9,484572669,2.923271059E9,1783375398,1517041206,1098792767,49674231,1334037708,1550332980,4.098991525E9,886171109,150598129,2.481090929E9,1940642008,1398944049,1059722517,201851908,1385547719,1699095331,1587397571,674240536,2.704774806E9,252314885,3.039795866E9,151914247,908333586,2.602270848E9,1038082786,651029483,1766729511,3.447698098E9,2.682942837E9,454166793,2.652734339E9,1951935532,775166490,758520603,3.000790638E9,4.004797018E9,4.217086112E9,4.137964114E9,1299594043,1639438038,3.464344499E9,2068982057,1054729187,1901997871,2.534638724E9,4.121318227E9,1757008337,750906861,1614815264,535035132,3.363418545E9,3.988151131E9,3.201591914E9,1183697867,3.64745491E9,1265776953,3.734260298E9,3.566750796E9,3.903871064E9,1250283471,1807470800,717615087,3.847203498E9,384695291,3.313910595E9,3.617213773E9,1432761139,2.484176261E9,3.481945413E9,283769337,100925954,2.180939647E9,4.03703816E9,1148730428,3.123027871E9,3.813386408E9,4.087501137E9,4.267549603E9,3.229630528E9,2.315620239E9,2.906624658E9,3.156319645E9,1215313976,82966005,3.747855548E9,3.245848246E9,1974459098,1665278241,807407632,451280895,251524083,1841287890,1283575245,337120268,891687699,801369324,3.787349855E9,2.721421207E9,3.431482436E9,959321879,1469301956,4.065699751E9,2.197585534E9,1199193405,2.898814052E9,3.887750493E9,724703513,2.514908019E9,2.696962144E9,2.551808385E9,3.516813135E9,2141445340,1715741218,2119445034,2.872807568E9,2.198571144E9,3.398190662E9,700968686,3.547052216E9,1009259540,2041044702,3.803995742E9,487983883,1991105499,1004265696,1449407026,1316239930,504629770,3.683797321E9,168560134,1816667172,3.837287516E9,1570751170,1857934291,4.01418974E9,2.797888098E9,2.822345105E9,2.754712981E9,936633572,2.347923833E9,852879335,1133234376,1500395319,3.084545389E9,2.348912013E9,1689376213,3.533459022E9,3.762923945E9,3.034082412E9,4.205598294E9,133428468,634383082,2.949277029E9,2.39838681E9,3.913789102E9,403703816,3.580869306E9,2.297460856E9,1867130149,1918643758,607656988,4.04905335E9,3.346248884E9,1368901318,600565992,2090982877,2.63247986E9,557719327,3.717614411E9,3.697393085E9,2.249034635E9,2.232388234E9,2.430627952E9,1115438654,3.295786421E9,2.865522278E9,3.633334344E9,84280067,33027830,303828494,2.747425121E9,1600795957,4.188952407E9,3.496589753E9,2.434238086E9,1486471617,658119965,3.10638147E9,953803233,334231800,3.005978776E9,857870609,3.151128937E9,1890179545,2.298973838E9,2.805175444E9,3.056442267E9,574365214,2.450884487E9,550103529,1233637070,4.289353045E9,2018519080,2057691103,2.399374476E9,4.166623649E9,2.148108681E9,387583245,3.664101311E9,836232934,3.330556482E9,3.10066596E9,3.280093505E9,2.955516313E9,2002398509,287182607,3.413881008E9,4.238890068E9,3.597515707E9,975967766,1671808611,2089089148,2006576759,2072901243,4.061003762E9,1807603307,1873927791,3.310653893E9,810573872,16974337,1739181671,729634347,4.263110654E9,3.613570519E9,2.883997099E9,1989864566,3.393556426E9,2.191335298E9,3.376449993E9,2106063485,4.19574169E9,1508618841,1204391495,4.027317232E9,2.917941677E9,3.563566036E9,2.734514082E9,2.951366063E9,2.629772188E9,2.767672228E9,1922491506,3.22722912E9,3.082974647E9,4.246528509E9,2.477669779E9,644500518,911895606,1061256767,4.144166391E9,3.427763148E9,878471220,2.784252325E9,3.845444069E9,4.043897329E9,1905517169,3.631459288E9,827548209,356461077,67897348,3.344078279E9,593839651,3.277757891E9,405286936,2.527147926E9,84871685,2.595565466E9,118033927,305538066,2.157648768E9,3.795705826E9,3.945188843E9,661212711,2.999812018E9,1973414517,152769033,2.208177539E9,745822252,439235610,455947803,1857215598,1525593178,2.700827552E9,1391895634,994932283,3.596728278E9,3.016654259E9,695947817,3.812548067E9,795958831,2.224493444E9,1408607827,3.513301457E9,3.979133421E9,543178784,4.229948412E9,2.982705585E9,1542305371,1790891114,3.410398667E9,3.20191891E9,961245753,1256100938,1289001036,1491644504,3.477767631E9,3.49672136E9,4.012557807E9,2.867154858E9,4.212583931E9,1137018435,1305975373,861234739,2.241073541E9,1171229253,4.178635257E9,33948674,2139225727,1357946960,1011120188,2.679776671E9,2.833468328E9,1374921297,2.751356323E9,1086357568,2.408187279E9,2.460827538E9,2.646352285E9,944271416,4.110742005E9,3.168756668E9,3.066132406E9,3.665145818E9,560153121,271589392,4.279952895E9,4.077846003E9,3.53040789E9,3.444343245E9,202643468,322250259,3.962553324E9,1608629855,2.543990167E9,1154254916,389623319,3.294073796E9,2.817676711E9,2122513534,1028094525,1689045092,1575467613,422261273,1939203699,1621147744,2.174228865E9,1339137615,3.69935254E9,577127458,712922154,2.427141008E9,2.290289544E9,1187679302,3.995715566E9,3.100863416E9,339486740,3.732514782E9,1591917662,186455563,3.681988059E9,3.762019296E9,844522546,978220090,169743370,1239126601,101321734,611076132,1558493276,3.26091565E9,3.547250131E9,2.90136158E9,1655096418,2.443721105E9,2.510565781E9,3.828863972E9,2039214713,3.878868455E9,3.359869896E9,928607799,1840765549,2.374762893E9,3.580146133E9,1322425422,2.850048425E9,1823791212,1459268694,4.094161908E9,3.928346602E9,1706019429,2056189050,2.934523822E9,135794696,3.134549946E9,2022240376,628050469,779246638,472135708,2.80083447E9,3.032970164E9,3.327236038E9,3.894660072E9,3.715932637E9,1956440180,522272287,1272813131,3.185336765E9,2.340818315E9,2.323976074E9,1888542832,1044544574,3.049550261E9,1722469478,1222152264,50660867,4.12732415E9,236067854,1638122081,895445557,1475980887,3.117443513E9,2.257655686E9,3.243809217E9,489110045,2.66293443E9,3.778599393E9,4.16205516E9,2.561878936E9,288563729,1773916777,3.648039385E9,2.391345038E9,2.493985684E9,2.612407707E9,505560094,2.274497927E9,3.911240169E9,3.46092539E9,1442818645,678973480,3.749357023E9,2.358182796E9,2.717407649E9,2.306869641E9,219617805,3.218761151E9,3.862026214E9,1120306242,1756942440,1103331905,2.578459033E9,762796589,252780047,2.966125488E9,1425844308,3.151392187E9,372911126,1667474886,2088535288,2004326894,2071694838,4.075949567E9,1802223062,1869591006,3.318043793E9,808472672,16843522,1734846926,724270422,4.278065639E9,3.621216949E9,2.880169549E9,1987484396,3.402253711E9,2.189597983E9,3.385409673E9,2105378810,4.210693615E9,1499065266,1195886990,4.042263547E9,2.913856577E9,3.570689971E9,2.728590687E9,2.947541573E9,2.627518243E9,2.762274643E9,1920112356,3.233831835E9,3.082273397E9,4.261223649E9,2.475929149E9,640051788,909531756,1061110142,4.160160501E9,3.435941763E9,875846760,2.779116625E9,3.857003729E9,4.059105529E9,1903268834,3.638064043E9,825316194,353713962,67374088,3.351728789E9,589522246,3.284360861E9,404236336,2.526454071E9,84217610,2.593830191E9,117901582,303183396,2.155911963E9,3.806477791E9,3.958056653E9,656894286,2.998062463E9,1970642922,151591698,2.206440989E9,741110872,437923380,454765878,1852748508,1515908788,2.694904667E9,1381168804,993742198,3.604373943E9,3.014905469E9,690584402,3.823320797E9,791638366,2.223281939E9,1398011302,3.520161977E9,3.991743681E9,538992704,4.244381667E9,2.981218425E9,1532751286,1785380564,3.419096717E9,3.200178535E9,960056178,1246420628,1280103576,1482221744,3.486468741E9,3.503319995E9,4.025428677E9,2.863326543E9,4.227536621E9,1128514950,1296947098,859002214,2.240123921E9,1162203018,4.193849577E9,33687044,2139062782,1347481760,1010582648,2.678045221E9,2.829640523E9,1364325282,2.745433693E9,1077985408,2.408548869E9,2.459086143E9,2.644360225E9,943212656,4.126475505E9,3.166494563E9,3.065430391E9,3.671750063E9,555836226,269496352,4.294908645E9,4.092792573E9,3.537006015E9,3.452783745E9,202118168,320025894,3.974901699E9,1600119230,2.543297077E9,1145359496,387397934,3.301201811E9,2.812801621E9,2122220284,1027426170,1684319432,1566435258,421079858,1936954854,1616945344,2.172753945E9,1330631070,3.705438115E9,572679748,707427924,2.425400123E9,2.290647819E9,1179044492,4.008585671E9,3.099120491E9,336870440,3.739122087E9,1583276732,185277718,3.688593069E9,3.772791771E9,842159716,976899700,168435220,1229577106,101059084,606366792,1549591736,3.267517855E9,3.553849021E9,2.897014595E9,1650632388,2.442242105E9,2.509612081E9,3.840161747E9,2038008818,3.890688725E9,3.368567691E9,926374254,1835907034,2.374863873E9,3.587531953E9,1313788572,2.846482505E9,1819063512,1448540844,4.109633523E9,3.941213647E9,1701162954,2054852340,2.930698567E9,134748176,3.132806511E9,2021165296,623210314,774795868,471606328,2.795958615E9,3.031746419E9,3.334885783E9,3.907527627E9,3.722280097E9,1953799400,522133822,1263263126,3.183336545E9,2.341176845E9,2.324333839E9,1886425312,1044267644,3.048588401E9,1718004428,1212733584,50529542,4.143317495E9,235803164,1633788866,892690282,1465383342,3.115962473E9,2.256965911E9,3.250673817E9,488449850,2.661202215E9,3.789633753E9,4.177007595E9,2.560144171E9,286339874,1768537042,3.654906025E9,2.391705863E9,2.492770099E9,2.610673197E9,505291324,2.273808917E9,3.924369609E9,3.469625735E9,1431699370,673740880,3.755965093E9,2.358021891E9,2.711746649E9,2.307489801E9,218961690,3.217021541E9,3.873845719E9,1111672452,1751693520,1094828930,2.576986153E9,757954394,252645662,2.964376443E9,1414855848,3.149649517E9,370555436,7793,7897,7898,8002,8003,8170,8171,8325,8326,8382,8383,8439,8440,8568,8569,8888,8889,9050,9061,9201,9202,9463,"parseInt","Error","Uint8Array","encodeURI",2002111551,1077744408,672376612,419994569,528185349,425267957,826979799,102918898,1176467946,1009525813,1747891260,5343550,1903666895,811678054,1999858998,1902537836,845440362,1915501381,85939827,1954101791,1176330101,723278305,771952532,1517958541,476539642,1765160690,1194670434,491719919,19424791,1426441870,305201136,260043521,240620822,506429735,203390665,56659400,221714654,1534944014,1466047943,1409454095,1496680657,1917231675,623165438,1898328051,9051,9060,2047,"console"]});})(); diff --git a/core/kws-11-0.0.1-obfuscated.5e0a90af726d8a7e.js b/core/kws-11-0.0.1-obfuscated.5e0a90af726d8a7e.js new file mode 100644 index 0000000..23d3cfb --- /dev/null +++ b/core/kws-11-0.0.1-obfuscated.5e0a90af726d8a7e.js @@ -0,0 +1 @@ +(function(){ function Jimbei() {var _sabo_a4a = 2147483647,_sabo_7d97a = 1,_sabo_4e55 = 0,_sabo_1dd18 = !!_sabo_7d97a,_sabo_bad3 = !!_sabo_4e55;return function (_sabo_3958, _sabo_46414, _sabo_65472) {var _sabo_544 = [],_sabo_98b6 = [],_sabo_7a24 = {},_sabo_0c871 = [],_sabo_8d003 = { _sabo_01b3: _sabo_3958 },_sabo_0e63c = {},_sabo_b55c = _sabo_4e55,_sabo_58da = [];var decode=function(j){if(!j){return""}var n=function(e){var f=[],t=e.length;var u=0;for(var u=0;u>7)&255)==0){f.push(e.charAt(u))}else{if(((w>>5)&255)==6){var b=e.charCodeAt(++u);var a=(w&31)<<6;var c=b&63;var v=a|c;f.push(String.fromCharCode(v))}else{if(((w>>4)&255)==14){var b=e.charCodeAt(++u);var d=e.charCodeAt(++u);var a=(w<<4)|((b>>2)&15);var c=((b&3)<<6)|(d&63);var v=((a&255)<<8)|c;f.push(String.fromCharCode(v))}}}}return f.join("")};var k="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");var p=j.length;var l=0;var m=[];while(l>4);var h=((r&15)<<4)|(q>>2);var g=((q&3)<<6)|o;m.push(String.fromCharCode(i));if(q!=64){m.push(String.fromCharCode(h))}if(o!=64){m.push(String.fromCharCode(g))}}return n(m.join(""))};var _sabo_997b = function (_sabo_4e683, _sabo_99124, _sabo_cc7e, _sabo_ac068) {return { _sabo_55c52: _sabo_4e683, _sabo_72c: _sabo_99124, _sabo_ad944: _sabo_cc7e, _sabo_e64e: _sabo_ac068 };};var _sabo_4e363 = function (_sabo_ac068) {return _sabo_ac068._sabo_e64e ? _sabo_ac068._sabo_72c[_sabo_ac068._sabo_ad944] : _sabo_ac068._sabo_55c52;};var _sabo_643083 = function (_sabo_04b4c, _sabo_7eb58) {return _sabo_7eb58.hasOwnProperty(_sabo_04b4c) ? _sabo_1dd18 : _sabo_bad3;};var _sabo_643082 = function (_sabo_04b4c, _sabo_7eb58) {if (_sabo_643083(_sabo_04b4c, _sabo_7eb58)) {return _sabo_997b(_sabo_4e55, _sabo_7eb58, _sabo_04b4c, _sabo_7d97a);}var _sabo_a75d8;if (_sabo_7eb58._sabo_cd56) {_sabo_a75d8 = _sabo_643082(_sabo_04b4c, _sabo_7eb58._sabo_cd56);if (_sabo_a75d8) {return _sabo_a75d8;}}if (_sabo_7eb58._sabo_6267) {_sabo_a75d8 = _sabo_643082(_sabo_04b4c, _sabo_7eb58._sabo_6267);if (_sabo_a75d8) {return _sabo_a75d8;}}return _sabo_bad3;};var _sabo_64308 = function (_sabo_04b4c) {var _sabo_a75d8 = _sabo_643082(_sabo_04b4c, _sabo_7a24);if (_sabo_a75d8) {return _sabo_a75d8;}return _sabo_997b(_sabo_4e55, _sabo_7a24, _sabo_04b4c, _sabo_7d97a);};var _sabo_47304 = function () {_sabo_544 = (_sabo_7a24._sabo_ad29) ? _sabo_7a24._sabo_ad29 : _sabo_0c871;_sabo_7a24 = (_sabo_7a24._sabo_6267) ? _sabo_7a24._sabo_6267 : _sabo_7a24;_sabo_b55c--};var _sabo_18b8d = function (_sabo_50198) {_sabo_7a24 = {_sabo_6267: _sabo_7a24,_sabo_cd56: _sabo_50198,_sabo_ad29: _sabo_544};_sabo_544 = [];_sabo_b55c++};var _sabo_2ba7 = function () {_sabo_58da.push(_sabo_997b(_sabo_b55c, _sabo_4e55, _sabo_4e55, _sabo_4e55))};var _sabo_15cc0 = function () {return _sabo_4e363(_sabo_58da.pop())};var _sabo_7371a = function (_sabo_a343a, _sabo_4100c) {return _sabo_0e63c[_sabo_a343a] = _sabo_4100c;};var _sabo_e353b = function (_sabo_a343a) {return _sabo_0e63c[_sabo_a343a];};var _sabo_32d92 = [_sabo_997b(_sabo_4e55, _sabo_4e55, _sabo_4e55, _sabo_4e55),_sabo_997b(_sabo_4e55, _sabo_4e55, _sabo_4e55, _sabo_4e55),_sabo_997b(_sabo_4e55, _sabo_4e55, _sabo_4e55, _sabo_4e55),_sabo_997b(_sabo_4e55, _sabo_4e55, _sabo_4e55, _sabo_4e55),_sabo_997b(_sabo_4e55, _sabo_4e55, _sabo_4e55, _sabo_4e55)];var _sabo_c1b7 = [_sabo_65472,function _sabo_08b65(_sabo_cc7e) {return _sabo_32d92[_sabo_cc7e];},function (_sabo_cc7e) {return _sabo_997b(_sabo_4e55, _sabo_8d003._sabo_4dcac, _sabo_cc7e, _sabo_7d97a);},function (_sabo_cc7e) {return _sabo_64308(_sabo_cc7e);},function (_sabo_cc7e) {return _sabo_997b(_sabo_4e55, _sabo_3958, _sabo_46414.d[_sabo_cc7e], _sabo_7d97a);},function (_sabo_cc7e) {return _sabo_997b(_sabo_8d003._sabo_01b3, _sabo_4e55, _sabo_4e55, _sabo_4e55);},function (_sabo_cc7e) {return _sabo_997b(_sabo_4e55, _sabo_46414.d, _sabo_cc7e, _sabo_7d97a);},function (_sabo_cc7e) {return _sabo_997b(_sabo_8d003._sabo_4dcac, _sabo_65472, _sabo_65472, _sabo_4e55);},function (_sabo_cc7e) {return _sabo_997b(_sabo_4e55, _sabo_0e63c, _sabo_cc7e, _sabo_4e55)}];var _sabo_caac8 = function (_sabo_b1e83, _sabo_cc7e) {return _sabo_c1b7[_sabo_b1e83] ? _sabo_c1b7[_sabo_b1e83](_sabo_cc7e) : _sabo_997b(_sabo_4e55, _sabo_4e55, _sabo_4e55, _sabo_4e55);};var _sabo_bb77 = function (_sabo_b1e83, _sabo_cc7e) {return _sabo_4e363(_sabo_caac8(_sabo_b1e83, _sabo_cc7e));};var _sabo_e2d0d = function (_sabo_4e683, _sabo_99124, _sabo_cc7e, _sabo_ac068) {_sabo_32d92[_sabo_4e55] = _sabo_997b(_sabo_4e683, _sabo_99124, _sabo_cc7e, _sabo_ac068)};var _sabo_83b61 = function (_sabo_b6ce8) {var _sabo_27a0 = _sabo_4e55;while (_sabo_27a0 < _sabo_b6ce8.length) {var _sabo_2654 = _sabo_b6ce8[_sabo_27a0];var _sabo_2d0d9 = _sabo_57b82[_sabo_2654[_sabo_4e55]];_sabo_27a0 = _sabo_2d0d9(_sabo_2654[1], _sabo_2654[2], _sabo_2654[3], _sabo_2654[4], _sabo_27a0, _sabo_3b448, _sabo_b6ce8);}};var _sabo_8ee7 = function (_sabo_2b9bd, _sabo_3745a, _sabo_2654, _sabo_b6ce8) {var _sabo_3171 = _sabo_4e363(_sabo_2b9bd);var _sabo_9638c = _sabo_4e363(_sabo_3745a);if (_sabo_3171 == 2147483647) {return _sabo_2654;}while (_sabo_3171 < _sabo_9638c) {var x = _sabo_b6ce8[_sabo_3171];var _sabo_2d0d9 = _sabo_57b82[x[_sabo_4e55]];_sabo_3171 = _sabo_2d0d9(x[1], x[2], x[3], x[4], _sabo_3171, _sabo_3b448, _sabo_b6ce8);}return _sabo_3171;};var _sabo_756a1 = function (_sabo_a6a99, _sabo_b6ce8) {var _sabo_033a5 = _sabo_544.splice(_sabo_544.length - 6, 6);var _sabo_19bac = _sabo_033a5[4]._sabo_55c52 != 2147483647;try {_sabo_a6a99 = _sabo_8ee7(_sabo_033a5[0], _sabo_033a5[1], _sabo_a6a99, _sabo_b6ce8);} catch (e) {_sabo_32d92[2] = _sabo_997b(e, _sabo_4e55, _sabo_4e55, _sabo_4e55);_sabo_a6a99 = _sabo_8ee7(_sabo_033a5[2], _sabo_033a5[3], _sabo_a6a99, _sabo_b6ce8);_sabo_32d92[2] = _sabo_997b(_sabo_4e55, _sabo_4e55, _sabo_4e55, _sabo_4e55);} finally {_sabo_a6a99 = _sabo_8ee7(_sabo_033a5[4], _sabo_033a5[5], _sabo_a6a99, _sabo_b6ce8);}return _sabo_033a5[5]._sabo_55c52 > _sabo_a6a99 ? _sabo_033a5[5]._sabo_55c52 : _sabo_a6a99;};var _sabo_3b448 = decode(_sabo_46414.b).split('').reduce(function (_sabo_eb41, _sabo_2654) {if ((!_sabo_eb41.length) || _sabo_eb41[_sabo_eb41.length - _sabo_7d97a].length == 5) { _sabo_eb41.push([]); }_sabo_eb41[_sabo_eb41.length - _sabo_7d97a].push(-_sabo_7d97a *1 +_sabo_2654.charCodeAt());return _sabo_eb41;}, []);var _sabo_57b82 = [function(p0, p1, p2, p3, p4, p5, p6) {var _sabo_6039 = _sabo_bb77(p0, p1);if (_sabo_544.length < _sabo_6039) {return ++p4;}var _sabo_189b8 = _sabo_544.splice(_sabo_544.length - _sabo_6039, _sabo_6039).map(_sabo_4e363),_sabo_1b6c = _sabo_544.pop(),_sabo_0271a = _sabo_4e363(_sabo_1b6c);_sabo_189b8.unshift(null);_sabo_e2d0d(new (Function.prototype.bind.apply(_sabo_0271a, _sabo_189b8)), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) & _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) << _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _sabo_1b6c = _sabo_caac8(p0, p1),_sabo_52b4 = _sabo_bb77(p0, p1) - 1;_sabo_1b6c._sabo_72c[_sabo_1b6c._sabo_ad944] = _sabo_52b4;_sabo_e2d0d(_sabo_52b4, _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {throw _sabo_544.pop(); } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) <= _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) | _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_32d92[4] = _sabo_98b6.pop();return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) + _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1), _sabo_65472, _sabo_65472, 0);var _sabo_4c4c5 = _sabo_15cc0();while (_sabo_4c4c5 < _sabo_b55c) {_sabo_47304();}return Infinity; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) ^ _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _sabo_6811d = _sabo_3b448.slice(_sabo_bb77(p0, p1), _sabo_bb77(p2, p3) + 1),_sabo_5b843 = _sabo_7a24;_sabo_e2d0d(function () {_sabo_8d003 = {_sabo_01b3: this || _sabo_3958,_sabo_0427: _sabo_8d003,_sabo_4dcac: arguments,_sabo_cd56: _sabo_5b843};_sabo_83b61(_sabo_6811d);_sabo_8d003 = _sabo_8d003._sabo_0427;return _sabo_4e363(_sabo_32d92[0]);}, _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) in _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(~_sabo_bb77(p0, p1), _sabo_65472, _sabo_65472, 0);return ++p4; } ,,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_98b6.push(_sabo_32d92[0]);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_2ba7();_sabo_18b8d(_sabo_8d003._sabo_cd56);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {return _sabo_bb77(p0, p1); } ,function(p0, p1, p2, p3, p4, p5, p6) {var _sabo_1b6c = _sabo_caac8(p0, p1),_sabo_52b4 = _sabo_bb77(p0, p1);_sabo_e2d0d(_sabo_52b4++, _sabo_65472, _sabo_65472, 0);_sabo_1b6c._sabo_72c[_sabo_1b6c._sabo_ad944] = _sabo_52b4;return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) !== _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(typeof _sabo_bb77(p0, p1), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) != _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) >> _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _sabo_6039 = _sabo_bb77(p0, p1);if (_sabo_544.length < _sabo_6039) {return ++p4;}var _sabo_189b8 = _sabo_544.splice(_sabo_544.length - _sabo_6039, _sabo_6039).map(_sabo_4e363),_sabo_1b6c = _sabo_544.pop(),_sabo_0271a = _sabo_4e363(_sabo_1b6c);_sabo_e2d0d(_sabo_0271a.apply(typeof _sabo_1b6c._sabo_72c == "undefined" ? _sabo_3958 : _sabo_1b6c._sabo_72c, _sabo_189b8), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(0, _sabo_4e363(_sabo_caac8(p0, p1)), _sabo_bb77(p2, p3), 1);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_47304();return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _sabo_1b6c = _sabo_caac8(p0, p1),_sabo_52b4 = _sabo_bb77(p0, p1) + 1;_sabo_1b6c._sabo_72c[_sabo_1b6c._sabo_ad944] = _sabo_52b4;_sabo_e2d0d(_sabo_52b4, _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_544.push(_sabo_32d92[0]);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) * _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_47304();_sabo_e2d0d(_sabo_65472, _sabo_65472, _sabo_65472, 0, 0);_sabo_15cc0();return Infinity; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) % _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {return _sabo_756a1(p4, p6); } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_7a24[p1] = undefined;return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) / _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) - _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d({}, _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(!_sabo_bb77(p0, p1), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _sabo_5246e = _sabo_bb77(p0, p1),_sabo_52b4 = {};_sabo_e2d0d(_sabo_7371a(_sabo_5246e, _sabo_52b4), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) === _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) >= _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) instanceof _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(-_sabo_bb77(p0, p1), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {return (!_sabo_4e363(_sabo_32d92[0])) ? _sabo_bb77(p0, p1) : ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_32d92[3] = _sabo_997b(_sabo_544.length, 0, 0, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) && _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _sabo_1b6c = _sabo_caac8(p0, p1);_sabo_e2d0d(delete _sabo_1b6c._sabo_72c[_sabo_1b6c._sabo_ad944], _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _sabo_02c0 = _sabo_bb77(p0, p1);_sabo_e2d0d(_sabo_544.splice(_sabo_544.length - _sabo_02c0, _sabo_02c0).map(_sabo_4e363), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_32d92[4] = _sabo_98b6[_sabo_98b6.length - 1];return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) >>> _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _sabo_1b6c = _sabo_caac8(p0, p1),_sabo_52b4 = _sabo_bb77(p0, p1);_sabo_e2d0d(_sabo_52b4--, _sabo_65472, _sabo_65472, 0);_sabo_1b6c._sabo_72c[_sabo_1b6c._sabo_ad944] = _sabo_52b4;return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_32d92[1] = _sabo_544.pop();return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_32d92[0] = _sabo_544[_sabo_544.length - 1];return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {return _sabo_a4a; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) || _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(+_sabo_bb77(p0, p1), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) > _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) == _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {return _sabo_4e363(_sabo_32d92[0]) ? _sabo_bb77(p0, p1) : ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _sabo_5246e = _sabo_bb77(p0, p1);_sabo_e2d0d(_sabo_e353b(_sabo_5246e), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {debugger;return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_e2d0d(_sabo_bb77(p0, p1) < _sabo_bb77(p2, p3), _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {var _sabo_1b6c = _sabo_caac8(p0, p1),_sabo_52b4 = _sabo_bb77(p2, p3);_sabo_e2d0d(_sabo_1b6c._sabo_72c[_sabo_1b6c._sabo_ad944] = _sabo_52b4, _sabo_65472, _sabo_65472, 0);return ++p4; } ,function(p0, p1, p2, p3, p4, p5, p6) {_sabo_18b8d(null);return ++p4; } ];return _sabo_83b61(_sabo_3b448);}; } ;Jimbei()(window,{"b":"IQEJAQUJBwEHAgkCAQcDCQIBBwQJAgEHBQkCAQcGCQIBBwcJAgEHCAkCAQcJCQIBBwoJAgEHCwkCAQcMCQIBBw0JAgEHDgkCAQcPCQIBBxAJAgEHEQkCAQcSCQIBBxMJAgEHFAkCAQcVCQIBBxYJAgEHFwkCAQcYCQIBBxkJAgEHGgkCAQcbCQIBBxwJAgEHHQkCAQceCQIBBx8JAgEHIAkCAQchCQIBByIJAgEHIwkCAQckCQIBByUJAgEHJgkCAQcnCQIBBygJAgEHKQkCAQcqCQIBBysJAgEHLAkCAQctCQIBBy4JAgEHLwkCAQcwCQIBBzEJAgEHMgkCAQczCQIBBzQJAgEHNQkCAQc2CQIBBzcJAgEHOAkCAQc5CQIBBzoJAgEHOwkCAQc8CQIBBz0JAgEHPgkCAQc/CQIBB0AJAgEHQQkCAQdCIwQWAQIJBx4HIwkCAQcjCQIBBx9CBBYCASgCAQEENgEKAQUjBCUBBQ0HQwdEQgQlAgEjBDgBAg0HRQdGQgQ4AgEjBDABBQ0HRwdIQgQwAgEjBCIBAw0HSQdKQgQiAgEjBEYBAQ0HSwdMQgRGAgEjBC4BBQ0HTQdOQgQuAgEjBDIBCA0HTwdQQgQyAgEjBDkBCg0HUQdSQgQ5AgEjBDsBBQ0HUwdUQgQ7AgEjBDEBCg0HVQdWQgQxAgEjBFkBCA0HVwdYQgRZAgEjBCABCQ0HWQdaQgQgAgEjBFEBBA0HWwdcQgRRAgEjBGcBCQ0HXQdeQgRnAgEjBFYBBw0HXwdgQgRWAgEjBAkBAg0HYQdiQgQJAgEjBG8BBA0HYwdkQgRvAgEjBD8BCScHZQEHJwIBAQJCBD8CAS4BCgEEIwQ6AQcnBD8BCEIEOgIBLgEEAQYjBEkBBwkHGgclCQIBBx8JAgEHKhoFZgIBQgRJAgEuAQQBAiMEHAEGCQceBx0JAgEHGwkCAQchCQIBByIJAgEHHgkCAQcdGgVmAgFCBBwCAS4BCgEEIwQGAQMJBycHIwkCAQcwCQIBByEJAgEHNAkCAQcdCQIBBzMJAgEHHxoFZgIBQgQGAgEuAQgBASMELwEECQczByUJAgEHMQkCAQciCQIBBykJAgEHJQkCAQcfCQIBByMJAgEHHhoFZgIBQgQvAgEuAQgBByMEawEJCQctByMJAgEHMAkCAQclCQIBBx8JAgEHIgkCAQcjCQIBBzMaBWYCAUIEawIBLgEIAQYjBBQBCgkHCQcyCQIBBysJAgEHHQkCAQcwCQIBBx8aBWYCAUIEFAIBLgEJAQUjBEIBBQkHAgciCQIBBzMJAgEHJwkCAQcjCQIBBxwaBWYCAUIEQgIBLgECAQIjBCkBCAkHHAciCQIBBzMJAgEHJwkCAQcjCQIBBxwaBWYCAUIEKQIBLgEEAQkjBFgBAgkHDAcfCQIBBx4JAgEHIgkCAQczCQIBBykaBWYCAUIEWAIBLgEHAQojBGMBCAkHHQcmCQIBBzAJAgEHJQkCAQckCQIBBx0aBWYCAUIEYwIBLgEIAQYjBE8BBwkHCwceCQIBBx4JAgEHJQkCAQcgGgVmAgFCBE8CAS4BCAEFIwQoAQYJBxgHIwkCAQcjCQIBBy0JAgEHHQkCAQclCQIBBzMaBWYCAUIEKAIBLgEGAQcjBBMBBAkHDQclCQIBBx8JAgEHHRoFZgIBQgQTAgEuAQcBByMEbQEICQcEBx0JAgEHKQkCAQcDCQIBBy8JAgEHJBoFZgIBQgRtAgEuAQIBAiMEUwEDCQcRBwwJAgEHCQkCAQcZGgVmAgFCBFMCAS4BBQEDIwQEAQQJBw4HIQkCAQczCQIBBzAJAgEHHwkCAQciCQIBByMJAgEHMxoFZgIBQgQEAgEuAQQBBCMENQEDCQcTByMJAgEHMAkCAQclCQIBBx8JAgEHIgkCAQcjCQIBBzMaBWYCAUIENQIBLgEIAQQjBDQBCQkHGQclCQIBBzEJAgEHIgkCAQcpCQIBByUJAgEHHwkCAQcjCQIBBx4aBWYCAUIENAIBLgEHAQQjBBEBAgkHHQczCQIBBzAJAgEHIwkCAQcnCQIBBx0JAgEHBwkCAQcECQIBBwgJAgEHFgkCAQcjCQIBBzQJAgEHJAkCAQcjCQIBBzMJAgEHHQkCAQczCQIBBx8aBWYCAR0BCAEICQcyByIJAgEHMwkCAQcnNwEGAQMaAgICAR0BBAECLwVmAQQdAQIBCBkHZQEBQgQRAgEuAQQBCSMEaQEECQcwBxIJAgEHKgkCAQcxCQIBBx4JAgEHIwkCAQcPCQIBBxkJAgEHKAkCAQcECQIBByEJAgEHGwkCAQcpCQIBBxMJAgEHOgkCAQcgCQIBBy4JAgEHEAkCAQcOCQIBBwkJAgEHBQkCAQclCQIBBwsJAgEHNwkCAQcICQIBBzQJAgEHDQkCAQdACQIBBxcJAgEHFAkCAQcCCQIBByQJAgEHFQkCAQc2CQIBBwYJAgEHAwkCAQcKCQIBBy0JAgEHOwkCAQcdCQIBBzUJAgEHMgkCAQc4CQIBBwcJAgEHDAkCAQc8CQIBBy8JAgEHKwkCAQcBCQIBBx8JAgEHPQkCAQcYCQIBBzkJAgEHJgkCAQcRCQIBB2cJAgEHFgkCAQcnCQIBBxoJAgEHHAkCAQczCQIBByIJAgEHLAkCAQc+QgRpAgEuAQcBAyMELAEICQcwByUJAgEHLQkCAQctGgQUAgEdAQkBCAkHMgciCQIBBzMJAgEHJzcBCgEEGgICAgEdAQEBBAkHMgciCQIBBzMJAgEHJxoEFAIBHQEHAQMJBzAHJQkCAQctCQIBBy0aBBQCAR0BAgEHGQdoAQZCBCwCAS4BAQEDIwRNAQUvBCwBCR0BCgEFCQcfByMJAgEHDAkCAQcfCQIBBx4JAgEHIgkCAQczCQIBBykaBBQCAR0BBAEFGQdlAQFCBE0CAS4BAwEKIwQfAQIvBCwBBh0BBwEGMgdpAQodAQYBBwkHNAclCQIBByQ3AQgBBBoCAgIBHQEHAQkZB2UBA0IEHwIBLgEDAQYjBBsBAi8ELAEFHQEBAQkyB2kBCR0BBQEECQcoByMJAgEHHgkCAQcDCQIBByUJAgEHMAkCAQcqNwEJAQQaAgICAR0BBgEKGQdlAQlCBBsCAS4BBAEGIwRmAQYvBCwBBB0BAgECMgdpAQMdAQcBBAkHJAchCQIBByYJAgEHKjcBCQEDGgICAgEdAQYBARkHZQECQgRmAgEuAQMBAyMERAEHLwQsAQgdAQoBBDIHaQECHQEHAQoJBysHIwkCAQciCQIBBzM3AQgBAhoCAgIBHQEIAQkZB2UBAUIERAIBLgEKAQYjBEABAy8ELAEGHQEIAQEyB2kBBR0BBQEGCQciBzMJAgEHJwkCAQcdCQIBBy8JAgEHCQkCAQcoNwEHAQMaAgICAR0BCgEJGQdlAQNCBEACAS4BBQECIwRLAQEvBCwBCR0BCgEJLwdqAQQdAQYBBwkHMAcqCQIBByUJAgEHHgkCAQcWCQIBByMJAgEHJwkCAQcdCQIBBwsJAgEHHzcBAQEHGgICAgEdAQIBCBkHZQEIQgRLAgEuAQIBBiMEGQEILwQsAQgdAQQBAS8HagEGHQECAQQJBx4HHQkCAQckCQIBBy0JAgEHJQkCAQcwCQIBBx03AQIBAhoCAgIBHQEGAQkZB2UBAUIEGQIBLgEEAQcjBGgBBi8ELAEIHQEGAQIvB2oBAx0BBgEECQcfByMJAgEHEwkCAQcjCQIBBxwJAgEHHQkCAQceCQIBBxYJAgEHJQkCAQcmCQIBBx03AQkBBRoCAgIBHQEEAQoZB2UBA0IEaAIBLgEEAQIjBGEBCi8ELAECHQEJAQMvB2oBCR0BBwEECQciBzMJAgEHJwkCAQcdCQIBBy8JAgEHCQkCAQcoNwEJAQYaAgICAR0BCQEEGQdlAQNCBGECAS4BBAEKIwRsAQMvBCwBAx0BAQEGCQcoBx4JAgEHIwkCAQc0CQIBBxYJAgEHKgkCAQclCQIBBx4JAgEHFgkCAQcjCQIBBycJAgEHHRoEWAIBHQEHAQIvBFgBCB0BBAEBGQdoAQZCBGwCAS4BCQEJIwRXAQcvBBMBBh0BBQEHAQdpAQFCBFcCAS4BBwEIIwQaAQYvBCwBBB0BAQEBCQcfByMJAgEHDwkCAQcaCQIBBwUJAgEHDAkCAQcfCQIBBx4JAgEHIgkCAQczCQIBBykaBFcCAR0BAwEHGQdlAQVCBBoCAS4BBAECIwQjAQUvBCwBAx0BCgEECQcmBx0JAgEHHwkCAQcaCQIBByIJAgEHMwkCAQchCQIBBx8JAgEHHQkCAQcmGgRXAgEdAQUBCRkHZQEJQgQjAgEuAQYBByMELQEELwQsAQUdAQIBCQkHKQcdCQIBBx8JAgEHGgkCAQciCQIBBzMJAgEHIQkCAQcfCQIBBx0JAgEHJhoEVwIBHQEJAQIZB2UBCkIELQIBLgEDAQQjBF8BAwkHIQczCQIBBycJAgEHHQkCAQcoCQIBByIJAgEHMwkCAQcdCQIBBycaBWYCAUIEXwIBLgECAQkjBEcBAgkHMAcjCQIBBzMJAgEHJgkCAQcjCQIBBy0JAgEHHRoFZgIBPgdrAQcmAQEBCR0BBwEJCQctByMJAgEHKR0BAwEKNwEFAQU4AQgBCRoCAQICHQEEAQoNB2wHbTcBBQEDQgICAgE4AQQBCjcBBAEEQgRHAgEuAQMBAiMEPgEHLwQsAQQdAQkBBQkHLQcjCQIBBykaBEcCAR0BBAEELwRHAQcdAQUBChkHaAEGQgQ+AgEuAQcBAyMENgEDQgQ2B24uAQcBByMEKwEELwQsAQodAQgBBgkHLAccCQIBByYJAgEHMAkCAQcyGgVmAgEdAQYBCS8FZgECHQECAQcZB2gBCEIEKwIBLgECAQojBFoBCjIHaQEGQgRaAgEuAQYBASMETAECMgdpAQhCBEwCAS4BAQEGIwRBAQcvB2UBBR0BBwEHLwdoAQMdAQEBAS8HbwEEHQEDAQEvB3ABCh0BAQEDLwdxAQEdAQUBCC8HcgEIHQEDAQQvB3MBAh0BBgEKLwd0AQodAQIBCC8HdQEDHQEFAQkvB3YBAh0BAQEGLwd3AQcdAQkBAi8HeAEKHQEKAQcvB3kBAR0BAQEEMgd6AQlCBEECAS4BAQEKIwQhAQIyB2kBCkIEIQIBLgECAQYjBCcBAi8HewEJHQEJAQcvB3sBBR0BBAEFLwd8AQcdAQkBBi8HfQEFHQEFAQgvB30BBx0BBwEDLwd+AQIdAQgBCC8HfwECHQEGAQIvB8KAAQUdAQEBBC8HwoEBBR0BCQEKLwfCggEBHQEEAQgvB38BAh0BCAEGLwd8AQgdAQcBBy8HwoABCB0BAwEBLwfCgwEGHQEDAQIvB8KEAQQdAQkBBy8HwoEBAh0BAwEJLwfChQEBHQEIAQcvB3wBCR0BAwEGLwfChAEIHQEKAQYvB8KAAQEdAQQBBC8HwoYBBh0BBAEHLwfChwEBHQEJAQMvB8KBAQMdAQEBBi8HfQEGHQEGAQcvB8KAAQYdAQgBCi8HwogBBh0BAgEILwfChQEIHQEIAQYvB8KGAQEdAQkBBS8HwocBAx0BCgEELwd8AQodAQYBBS8HwoUBCR0BAwEELwd+AQIdAQMBBS8HfAECHQECAQQvB8KIAQIdAQEBAS8HwoUBBh0BCgEILwfCggEJHQEHAQMvB8KIAQYdAQkBAi8HfAEDHQEIAQkvB8KEAQEdAQIBBy8HwoIBCR0BBgEKLwd7AQgdAQIBBS8HwogBCB0BAgEELwd8AQQdAQoBCi8HfgEBHQEEAQQvB8KCAQQdAQMBBS8HwoIBAx0BAwEGLwfCiQECHQEFAQovB8KEAQQdAQoBBC8HfQEKHQECAQEvB8KBAQEdAQYBBS8HwocBCR0BCAEELwfChAEDHQEGAQIvB8KEAQMdAQQBAi8HwocBBx0BCAEGLwfCiAEKHQEHAQEvB8KHAQcdAQMBBi8HwoUBBR0BBQEFLwfCigEDHQEEAQIvB8KCAQMdAQcBCi8HwoUBAR0BBQEBLwd8AQIdAQcBCi8HwocBAR0BBQEKLwfChgEFHQEGAQgvB34BCB0BAgEDMgfCiwEEQgQnAgEuAQkBBiMECAEBQgQIB2kuAQMBAS4BCgEJCQctBx0JAgEHMwkCAQcpCQIBBx8JAgEHKhoEJwIBQQQIAgEuAQQBCS0HwowBBDYBAQEJIwRdAQcaBCcECEIEXQIBLgEJAQEjBAUBAUIEBQRdLgEGAQo9BAgHeC4BCQEJLQfCjQEHNgEIAQgvBCUBCR0BAgEGCQQFB3gdAQUBATIHaQEHHQEDAQoJB8KOB3gdAQYBAhkHwo8BByUCAQd4QgQFAgEuAQQBBS8EZgEBHQEJAQEvBCEBCB0BAgEILwQIAQUdAQUBBhkHaAEFLgEDAQEMAQEBBj0ECAdlLgECAQotB8KQAQQ2AQgBCC8EOAEDHQECAQIJBAUHZR0BBAEBMgdpAQUdAQYBBwkHwocHZR0BCQEIGQfCjwEFJQIBB2VCBAUCAS4BCAEBLwRmAQUdAQgBBi8EIQEBHQEHAQUvBAgBBx0BAQEGGQdoAQguAQIBCgwBBQEBPQQIB28uAQIBCS0HwpEBAzYBCQEILwQwAQIdAQIBCQkEBQdvHQEFAQkyB2kBBR0BAgEFCQfCigdvHQEEAQQZB8KPAQglAgEHb0IEBQIBLgEBAQovBGYBBR0BBwEKLwQhAQEdAQkBBi8ECAEIHQEGAQIZB2gBBS4BCAEKDAEKAQo9BAgHdS4BCgEBLQfCkgEDNgEDAQMvBCIBAR0BBQEFCQQFB3UdAQYBBjIHaQEHHQEEAQgJB8KBB3UdAQUBBRkHwo8BASUCAQd1QgQFAgEuAQkBCS8EZgECHQEGAQQvBCEBBh0BBwEHLwQIAQEdAQoBARkHaAEJLgEFAQIMAQgBBz0ECAdyLgEGAQYtB8KTAQY2AQMBAS8ERgEDHQEIAQgJBAUHch0BBQEJMgdpAQEdAQIBCQkHfgdyHQEBAQIZB8KPAQolAgEHckIEBQIBLgEFAQgvBGYBCh0BBgEFLwQhAQQdAQkBAy8ECAEEHQEGAQcZB2gBAy4BBQEDDAEIAQk9BAgHdi4BCgEELQfClAEDNgEFAQovBC4BAR0BAwEGCQQFB3YdAQQBBjIHaQEEHQEDAQMJB8KVB3YdAQIBBRkHwo8BAiUCAQd2QgQFAgEuAQUBAS8EZgEIHQEKAQkvBCEBAR0BCgEFLwQIAQodAQEBCBkHaAEFLgECAQYMAQYBAj0ECAd0LgECAQYtB8KWAQU2AQkBBC8EMgEHHQEGAQkJBAUHdB0BBAEJMgdpAQEdAQcBBgkHwogHdB0BCQECGQfCjwEHJQIBB3RCBAUCAS4BBAEFLwRmAQcdAQUBCi8EIQEFHQEJAQcvBAgBAh0BBQEGGQdoAQEuAQUBCAwBCAEBPQQIB3kuAQYBAy0HwpcBAjYBAQEGLwQ5AQQdAQoBBAkEBQd5HQECAQcyB2kBBB0BCAEBCQfCjgd5HQEHAQEZB8KPAQMlAgEHeUIEBQIBLgEHAQcvBGYBBB0BCQEELwQhAQQdAQcBBi8ECAEJHQEDAQoZB2gBCi4BCAEDDAEFAQo9BAgHdy4BBQEBLQfCmAECNgEIAQMvBDsBAR0BAQEGCQQFB3cdAQUBATIHaQEIHQEHAQMJB3sHdx0BBAEJGQfCjwEHJQIBB3dCBAUCAS4BAgEILwRmAQIdAQEBCS8EIQEJHQEGAQQvBAgBAR0BAQEKGQdoAQMuAQoBCgwBCAEIPQQIB2guAQUBAi0HwpkBCjYBAwEJLwQxAQgdAQcBBAkEBQdoHQEEAQkyB2kBBh0BAQEBCQd7B2gdAQYBAxkHwo8BBCUCAQdoQgQFAgEuAQUBBi8EZgEJHQEKAQEvBCEBAR0BBAEGLwQIAQkdAQUBChkHaAEILgEBAQoMAQUBBT0ECAdzLgEJAQQtB8KaAQE2AQIBCS8EWQEGHQEDAQYJBAUHcx0BAwEBMgdpAQodAQEBBAkHfgdzHQEJAQgZB8KPAQYlAgEHc0IEBQIBLgEJAQUvBGYBBR0BBgEJLwQhAQIdAQoBAi8ECAEKHQEBAQcZB2gBBC4BAwEHDAEFAQk9BAgHcC4BCAEKLQfCmwEDNgEDAQMvBCABBx0BBAEHCQQFB3AdAQIBBDIHaQEBHQEBAQQJB8KBB3AdAQEBCRkHwo8BBSUCAQdwQgQFAgEuAQgBBi8EZgEFHQEEAQQvBCEBBh0BAwEHLwQIAQIdAQYBAxkHaAEKLgEJAQcMAQkBCj0ECAdxLgEHAQMtB8KcAQM2AQoBCS8EUQEIHQEKAQkJBAUHcR0BAwEIMgdpAQEdAQkBAQkHwp0HcR0BCAEGGQfCjwECJQIBB3FCBAUCAS4BBgEHLwRmAQcdAQoBCC8EIQEFHQEGAQUvBAgBBx0BAgEFGQdoAQYuAQcBCQwBBgEBLwRmAQEdAQkBCC8ETAEGHQEFAQEvBAUBBh0BBwEIGQdoAQkuAQEBBAwBAwECFAQIAQQuAQkBChMHwp4BBS8EbwEGHQEIAQYvBEwBAx0BAQEKGQdlAQVCBEwCAS4BBQEGIwRcAQcvBB8BAR0BBAEGLwRMAQYdAQMBBQ0Hwp8HwqAdAQIBChkHaAEKHQEGAQkJBysHIwkCAQciCQIBBzM3AQIBAhoCAgIBHQEJAQgvB2oBCB0BCAECGQdlAQpCBFwCAS4BBgEFCQcwByUJAgEHLQkCAQctGgQrAgEdAQcBAi8FZgEIHQECAQovBFwBAR0BCgEKGQdoAQIuAQIBCgwBCQEBOQECAQYSAQMBByMEBQEJQgQFAwEjBAIBCEIEAgMCIwQJAQdCBAkDAzYBAQEHIwQLAQlCBAsHwqEuAQQBAiMEGAEGLgEBAQkvB8KiAQYdAQIBBi8HwqMBCh0BAwEILwfCpAEKHQEFAQIvB8KlAQcdAQoBAS8HwqYBBh0BAwECLwfCpQEIHQEIAQIiAQUBBTYBBAEGIwQGAQkJBxwHIgkCAQczCQIBBycJAgEHIwkCAQccGgVmAgEdAQoBAQkHJwcjCQIBBzAJAgEHIQkCAQc0CQIBBx0JAgEHMwkCAQcfNwEHAQkaAgICAUIEBgIBLgEKAQkjBFABAgkHMAceCQIBBx0JAgEHJQkCAQcfCQIBBx0JAgEHAwkCAQctCQIBBx0JAgEHNAkCAQcdCQIBBzMJAgEHHxoEBgIBHQEJAQMJBycHIgkCAQcxHQEIAQcZB2UBCEIEUAIBLgEDAQEjBGQBBAkHMAceCQIBBx0JAgEHJQkCAQcfCQIBBx0JAgEHAwkCAQctCQIBBx0JAgEHNAkCAQcdCQIBBzMJAgEHHxoEBgIBHQEDAQMJBycHIgkCAQcxHQEIAQMZB2UBBUIEZAIBLgEBAQQJByUHJAkCAQckCQIBBx0JAgEHMwkCAQcnCQIBBxYJAgEHKgkCAQciCQIBBy0JAgEHJxoEUAIBHQEIAQQvBGQBBh0BBQEFGQdlAQEuAQYBAQkHJQckCQIBByQJAgEHHQkCAQczCQIBBycJAgEHFgkCAQcqCQIBByIJAgEHLQkCAQcnGgRkAgEdAQQBCS8EUAECHQEDAQoZB2UBCi4BAQEGQgQLBD8uAQgBBwwBBgEJIwQJAQJCBAkCAzYBCQEGQgQYBAkuAQMBB0IECwfCoS4BAQEKDAEEAQgvBAsBCC4BBAEILQfCpwEDLwQJAQYTB8KoAQQvBAUBCgoCAQfCpgwBAwEHHwEBAQkSAQIBBSMEBQEDQgQFAwEjBAIBBEIEAgMCIwQJAQhCBAkDAzYBCQEDIwQLAQFCBAsHwqEuAQYBCCMEGAEFLgEEAQQvB8KiAQcdAQcBAi8HwqQBAh0BBAEFLwfCqQEBHQEIAQEvB8KqAQgdAQUBBi8HwqYBBB0BCgEILwfCqgEDHQEHAQoiAQkBBDYBAgEHIwQGAQMJBxwHIgkCAQczCQIBBycJAgEHIwkCAQccGgVmAgEdAQEBBQkHJwcjCQIBBzAJAgEHIQkCAQc0CQIBBx0JAgEHMwkCAQcfNwEBAQgaAgICAUIEBgIBLgECAQQjBAMBCgkHMAceCQIBBx0JAgEHJQkCAQcfCQIBBx0JAgEHAwkCAQctCQIBBx0JAgEHNAkCAQcdCQIBBzMJAgEHHxoEBgIBHQEEAQgJBycHIgkCAQcxHQECAQMZB2UBCkIEAwIBLgEFAQQjBA0BAi8EAgEDPgfCqwEDCQcnByIJAgEHMR0BBAEKMgdlAQRCBA0CAS4BAQEDIwQSAQVCBBIHaS4BAgEGLgEEAQRBBBIEDS4BAwEILQfCqQECNgEKAQcjBA4BCRoEDQQSQgQOAgEuAQQBAiMEAQEGCQcwBx4JAgEHHQkCAQclCQIBBx8JAgEHHQkCAQcDCQIBBy0JAgEHHQkCAQc0CQIBBx0JAgEHMwkCAQcfGgQGAgEdAQEBCC8EDgEJHQEGAQUZB2UBCkIEAQIBLgEJAQk9BAEEAy4BAgEGLQfCrAEFNgEIAQVCBAsEPy4BCQEIEwfCqQEELgEGAQcMAQQBAwwBCgEKFAQSAQguAQQBBxMHwq0BCgwBBQEJIwQJAQlCBAkCAzYBAQEEQgQYBAkuAQUBCUIECwfCoS4BBQEBDAEIAQIvBAsBAy4BAgEJLQfCrgEBLwQJAQETB8KnAQUvBAUBBgoCAQfCpgwBCQEFHwEJAQkSAQMBBiMEBQEFQgQFAwEjBAIBBEIEAgMCIwQJAQdCBAkDAzYBBQEBIwQLAQpCBAsHwqEuAQIBBSMEGAECLgEHAQMvB8KiAQQdAQQBBC8Hwq8BCh0BAQEJLwfCsAEJHQECAQYvB8KxAQgdAQIBBi8HwqYBAx0BAwEJLwfCsQEEHQEKAQYiAQIBBzYBAgEIIwQGAQIJBxwHIgkCAQczCQIBBycJAgEHIwkCAQccGgVmAgEdAQYBCgkHJwcjCQIBBzAJAgEHIQkCAQc0CQIBBx0JAgEHMwkCAQcfNwEIAQgaAgICAUIEBgIBLgEGAQMjBAcBAgkHMAceCQIBBx0JAgEHJQkCAQcfCQIBBx0JAgEHAwkCAQctCQIBBx0JAgEHNAkCAQcdCQIBBzMJAgEHHxoEBgIBHQEKAQcJBycHIgkCAQcxHQEDAQgZB2UBCEIEBwIBLgEJAQcJByYHHwkCAQcgCQIBBy0JAgEHHRoEBwIBHQECAQYJByoHHQkCAQciCQIBBykJAgEHKgkCAQcfNwEEAQQaAgICAR0BCQEHCQc2Bz4JAgEHJAkCAQcvNwEFAQlCAgICAS4BBwEHIwRwAQoJByMHKAkCAQcoCQIBByYJAgEHHQkCAQcfCQIBBxAJAgEHHQkCAQciCQIBBykJAgEHKgkCAQcfGgQHAgFCBHACAS4BCQEGCQcyByMJAgEHJwkCAQcgGgQGAgEdAQgBCQkHJQckCQIBByQJAgEHHQkCAQczCQIBBycJAgEHFgkCAQcqCQIBByIJAgEHLQkCAQcnNwEKAQUaAgICAR0BBwEHLwQHAQQdAQcBChkHZQEGLgEEAQgjBF4BBgkHIwcoCQIBBygJAgEHJgkCAQcdCQIBBx8JAgEHEAkCAQcdCQIBByIJAgEHKQkCAQcqCQIBBx8aBAcCAUIEXgIBLgEJAQI9BHAEXi4BBwEJLQfCsgEJNgEEAQdCBAsEPy4BBAEEDAEKAQQJBx4HHQkCAQc0CQIBByMJAgEHMQkCAQcdGgQHAgEdAQcBCRkHaQEGLgEKAQcMAQYBBiMECQEDQgQJAgM2AQcBCEIEGAQJLgEKAQpCBAsHwqEuAQkBBgwBAQEBLwQLAQMuAQUBCS0HwrMBCS8ECQEBEwfCtAEELwQFAQcKAgEHwqYMAQMBBx8BCQEEEgEJAQojBAUBBUIEBQMBIwQCAQhCBAIDAiMECQEFQgQJAwM2AQEBASMECwEGQgQLB8KhLgEHAQkjBBgBBS4BBQEHLwfCogEKHQEBAQovB8KuAQIdAQgBBC8HwrUBAh0BBgEBLwfCtgEJHQEEAQQvB8KmAQQdAQIBAy8HwrYBBh0BAgEEIgEHAQY2AQEBBCMEBgEBCQccByIJAgEHMwkCAQcnCQIBByMJAgEHHBoFZgIBHQEIAQYJBycHIwkCAQcwCQIBByEJAgEHNAkCAQcdCQIBBzMJAgEHHzcBBQEIGgICAgFCBAYCAS4BAgEHIwQNAQgJBycHIgkCAQcxHQEHAQcvByUBCR0BBwEGLwckAQgdAQgBBwkHKgc1HQEKAQkJByoHNh0BBAEBCQcqBzcdAQoBCgkHKgc4HQEEAQkJByYHJAkCAQclCQIBBzMdAQMBAy8HJAEKHQEBAQUJByEHLR0BCAECCQctByIdAQkBBTIHwrcBB0IEDQIBLgEGAQojBBIBCkIEEgdpLgEJAQouAQEBBQkHLQcdCQIBBzMJAgEHKQkCAQcfCQIBByoaBA0CAUEEEgIBLgEBAQktB8K1AQM2AQcBCiMEEAECLwRoAQkdAQEBAgkHMAceCQIBBx0JAgEHJQkCAQcfCQIBBx0JAgEHAwkCAQctCQIBBx0JAgEHNAkCAQcdCQIBBzMJAgEHHxoEBgIBHQEKAQUaBA0EEh0BCQEDGQdlAQMdAQgBAQkHHwclCQIBBykJAgEHGQkCAQclCQIBBzQJAgEHHTcBCAEBGgICAgEdAQYBARkHZQEBQgQQAgEuAQQBBhoEDQQSFwIBBBAuAQUBAi0HwqoBCDYBAQEDQgQLBD8uAQYBCAwBAwEFDAEDAQMUBBIBCi4BBwEIEwfCuAEFDAEKAQUjBAkBB0IECQIDNgEEAQNCBBgECS4BCAECQgQLB8KhLgECAQEMAQEBAS8ECwEDLgEDAQEtB8K5AQQvBAkBChMHwroBBi8EBQEECgIBB8KmDAEEAQofAQYBAxIBAQEGIwQFAQVCBAUDASMEAgEJQgQCAwIjBAkBBUIECQMDNgEDAQIjBAsBBUIECwfCoS4BBQEIIwQYAQIuAQMBBS8HwqIBBB0BAQEILwfCuwEBHQEFAQUvB8K8AQUdAQcBAi8Hwr0BAR0BAQEILwfCpgEHHQEGAQEvB8K9AQYdAQgBCiIBAQEHNgEFAQdCBAsEOi4BBAEDIwRuAQMuAQUBAS8Hwr4BCR0BBQEHLwfCvwEEHQEJAQovB8KLAQYdAQIBCi8Hw4ABBR0BAwEBLwfCpgEIHQEIAQgvB8OAAQodAQcBByIBAQEINgEHAQkJBygHMgkCAQcdCQIBBysJAgEHLAkCAQcyCQIBByUJAgEHLAkCAQceCQIBBzIJAgEHJQkCAQcnCQIBByYJAgEHLAkCAQcoCQIBBx0aBCkCAR0BAgEDGQdpAQouAQEBBwwBBQEEIwQeAQNCBB4CAzYBBwEFQgRuBB4uAQoBCgwBCgECCQcmBx8JAgEHJQkCAQcwCQIBBywaBG4CAS4BBAEGLQfDgQEKNgEEAQEjBAwBAS8EbQEIHQEIAQUJBzEHNAkCAQfDggkCAQceCQIBBx0JAgEHJAkCAQctCQIBB8OCCQIBBzIJAgEHIwkCAQcjCQIBBx8JAgEHJgkCAQcfCQIBBx4JAgEHJQkCAQckCQIBBxkJAgEHIwkCAQcnCQIBBx0JAgEHEQkCAQcMCQIBBxYJAgEHIwkCAQceCQIBBx0JAgEHw4IJAgEHHwkCAQceCQIBByAJAgEHGgkCAQcjCQIBBycJAgEHIQkCAQctCQIBBx0JAgEHEwkCAQcjCQIBByUJAgEHJwkCAQfDggkCAQcdCQIBBzEJAgEHJQkCAQctCQIBBzQJAgEHJQkCAQcwCQIBByoJAgEHIgkCAQczCQIBBx0JAgEHw4IJAgEHHgkCAQchCQIBBzMJAgEHCAkCAQczCQIBBxYJAgEHIwkCAQczCQIBBx8JAgEHHQkCAQcvCQIBBx8dAQUBAy8HKQEBHQEBAQIBB2gBBUIEDAIBLgEBAQMJBx8HHQkCAQcmCQIBBx8aBAwCAR0BBQEKCQcmBx8JAgEHJQkCAQcwCQIBBywaBG4CAR0BBwECGQdlAQouAQgBCi0Hw4MBBDYBAgEJQgQLBD8uAQoBBQwBAwEEDAEGAQoTB8K8AQQ2AQoBBwkHMwchCQIBBzQJAgEHMgkCAQcdCQIBBx4aBG4CAScCAQECQgQLAgEuAQkBBwwBBgEHDAEDAQMjBAkBBUIECQIDNgEJAQFCBBgECS4BBgEHQgQLB8KhLgEFAQcMAQYBAi8ECwEBLgEEAQgtB8OEAQEvBAkBChMHw4UBCi8EBQEBCgIBB8KmDAECAQYfAQYBCRIBBgEBIwQFAQlCBAUDASMEAgEEQgQCAwIjBAkBBUIECQMDNgEBAQgjBAsBAkIECwfCoS4BAwEFIwQYAQIuAQYBCi8HwqIBAh0BAQECLwfDhgEHHQEIAQcvB8OHAQMdAQkBAy8HwrUBCB0BBAEDLwfCpgECHQEIAQovB8K1AQgdAQcBBiIBCAEKNgEIAQEjBGIBBwkHHAciCQIBBzMJAgEHJwkCAQcjCQIBBxwaBWYCAR0BBQEECQcIBzQJAgEHJQkCAQcpCQIBBx03AQYBCRoCAgIBQgRiAgEuAQUBCiMEQwEICQccByIJAgEHMwkCAQcnCQIBByMJAgEHHBoFZgIBHQEHAQgJBwgHNAkCAQclCQIBBykJAgEHHTcBCgEDGgICAgEdAQcBAwEHaQEEQgRDAgEuAQcBCiMEPQEDCQcsBx0JAgEHIAkCAQcmGgQUAgEdAQcBAgkHQAdACQIBByQJAgEHHgkCAQcjCQIBBx8JAgEHIwkCAQdACQIBB0AaBEMCAR0BBAEBGQdlAQNCBD0CAS4BCQEKLwQCAQU+B8OIAQgyB2kBA0IEAgIBLgEGAQIjBCQBCEIEJAdpLgEDAQguAQYBAgkHLQcdCQIBBzMJAgEHKQkCAQcfCQIBByoaBAICAUEEJAIBLgEJAQMtB8OHAQo2AQEBAyMETgEGCQciBzMJAgEHJwkCAQcdCQIBBy8JAgEHCQkCAQcoGgQ9AgEdAQQBAhoEAgQkHQEKAQYZB2UBCUECAQdpQgROAgEuAQEBBy8ETgEILgEDAQEtB8KpAQU2AQoBBEIECwQ/LgEEAQMMAQQBCAwBAgECFAQkAQUuAQYBAhMHw4kBBgwBCgEDIwQJAQhCBAkCAzYBCgEDQgQYBAkuAQoBBkIECwfCoS4BAwEJDAEEAQkvBAsBCi4BBgEGLQfDigEELwQJAQITB8OLAQgvBAUBCgoCAQfCpgwBBAEHHwEBAQESAQMBAiMEBQEFQgQFAwEjBAIBBkIEAgMCIwQJAQVCBAkDAzYBBAEDIwQLAQdCBAsHwqEuAQUBAyMEGAEDLgEGAQovB8KiAQYdAQMBCS8Hw4wBCB0BBgEFLwfDjQEEHQEDAQEvB8ODAQYdAQoBAS8HwqYBCR0BBAEBLwfDgwECHQEBAQoiAQIBBjYBAQEBIwQNAQJCBA0EAi4BAgECIwQSAQhCBBIHaS4BBwEKLgEIAQIJBy0HHQkCAQczCQIBBykJAgEHHwkCAQcqGgQNAgFBBBICAS4BAwEBLQfDjQEGNgEKAQIjBA4BAxoEDQQSQgQOAgEuAQMBAi8Hw44BCh0BBAEILwfCrwEGHQEDAQYvB8KwAQodAQUBAy8Hw48BCh0BCgEDLwfCpgEIHQEKAQQvB8OPAQkdAQcBCSIBAgEKNgEKAQQjBCoBCQkHMAcjCQIBBzMJAgEHJgkCAQcfCQIBBx4JAgEHIQkCAQcwCQIBBx8JAgEHIwkCAQceGgYBAgEdAQEBBAkHMAcjCQIBBzMJAgEHJgkCAQcfCQIBBx4JAgEHIQkCAQcwCQIBBx8JAgEHIwkCAQceNwEFAQoaAgICAUIEKgIBLgEHAQYjBBwBBi8EKgEIHQEKAQkJBx4HHQkCAQcfCQIBByEJAgEHHgkCAQczCQIBB8OQCQIBByQJAgEHHgkCAQcjCQIBBzAJAgEHHQkCAQcmCQIBByYJAgEHw5EJAgEHNAkCAQclCQIBByIJAgEHMwkCAQcaCQIBByMJAgEHJwkCAQchCQIBBy0JAgEHHQkCAQfDkQkCAQcwCQIBByMJAgEHMwkCAQcmCQIBBx8JAgEHHgkCAQchCQIBBzAJAgEHHwkCAQcjCQIBBx4JAgEHw5EJAgEHQAkCAQctCQIBByMJAgEHJQkCAQcnHQECAQQZB2UBCh0BCgEGGQdpAQhCBBwCAS4BBwEDLwQcAQIdAQYBBS8Hw5IBBwkCAQQOHQEEAQkvB8OTAQE3AQMBCQkCAgIBHQEGAQoZB2UBBy4BBAEBQgQLBD8uAQcBBhMHw40BAi4BBAEKDAEBAQYjBB4BBkIEHgIDDAEBAQkUBBIBAy4BAQEDEwfDlAEGDAEGAQYjBAkBCkIECQIDNgEIAQhCBBgECS4BAgECQgQLB8KhLgEKAQUMAQcBAS8ECwEJLgEIAQItB8OVAQUvBAkBAxMHw5YBBC8EBQEFCgIBB8KmDAEIAQEfAQIBBRIBBAEBIwQFAQhCBAUDASMEAgEEQgQCAwIjBAkBBkIECQMDNgEGAQUjBAsBAUIECwfCoS4BBAEHIwQYAQQuAQcBAy8HwqIBBB0BBwEJLwfCjgEBHQEKAQIvB8KCAQEdAQcBCS8Hw5cBBB0BBwEILwfCpgECHQEHAQovB8OXAQYdAQMBBSIBCAEBNgEGAQIjBC8BCgkHHAciCQIBBzMJAgEHJwkCAQcjCQIBBxwaBWYCAR0BBwEJCQczByUJAgEHMQkCAQciCQIBBykJAgEHJQkCAQcfCQIBByMJAgEHHjcBBQEJGgICAgFCBC8CAS4BAgEEIwQzAQEvBGgBAR0BCQEFCQckBy0JAgEHJQkCAQcfCQIBBygJAgEHIwkCAQceCQIBBzQaBC8CAT4Hw5gBCS8HagEEHQEJAQMZB2UBAUIEMwIBLgEBAQEjBBIBCEIEEgdpLgEEAQEuAQcBBwkHLQcdCQIBBzMJAgEHKQkCAQcfCQIBByoaBAICAUEEEgIBLgEKAQgtB8KCAQI2AQQBBCMENwEHGgQCBBJCBDcCAS4BCQEKLwRhAQkdAQgBBS8EMwEDHQEKAQMvBDcBBR0BAgEGGQdoAQoqAgEHaS4BAwEHLQfChgEDNgEGAQpCBAsEPy4BCgEIEwfCggECLgEJAQgMAQQBBAwBAQEGFAQSAQEuAQMBARMHw5kBCQwBBQEBIwQJAQFCBAkCAzYBAwEHQgQYBAkuAQgBCkIECwfCoS4BCgEHDAEFAQQvBAsBCC4BAgEELQfDmgEJLwQJAQoTB8KsAQQvBAUBBAoCAQfCpgwBBwEFHwEJAQUSAQUBCSMEBQEJQgQFAwEjBAIBCEIEAgMCIwQJAQpCBAkDAzYBBwECIwQLAQFCBAsHwqEuAQMBAyMEGAEBLgEEAQYvB8KiAQEdAQkBAy8Hwp0BAx0BBgECLwfCjgEKHQEDAQYvB8ObAQEdAQUBBC8HwqYBAx0BAgEILwfDmwEJHQEBAQkiAQYBCTYBAgEDIwQpAQoJBxwHIgkCAQczCQIBBycJAgEHIwkCAQccGgVmAgFCBCkCAS4BBwEIFgRCAQEdAQUBBwkHKAchCQIBBzMJAgEHMAkCAQcfCQIBByIJAgEHIwkCAQczNwEEAQo9AgICAS4BCAEILQfDnAEENgECAQEvBGEBAR0BCgEKLwRoAQMdAQUBCi8ETQEFHQEGAQQvBEIBBx0BCAEGGQdlAQUdAQcBBhkHZQEKHQEDAQIJBzMHJQkCAQcfCQIBByIJAgEHMQkCAQcdCQIBB8OQCQIBBzAJAgEHIwkCAQcnCQIBBx0dAQUBBRkHaAEKHQEKAQMsB2UBCTcBAwEDPQICAgFCBAsCAS4BBAEIDAEFAQETB8KOAQg2AQIBAgkHJgcfCQIBBx4JAgEHIgkCAQczCQIBBykJAgEHIgkCAQcoCQIBByAaBFMCAR0BAgEBLwRCAQkdAQEBAxkHZQEKHQECAQgJB8OdB8OeNwEEAQgXAgICAUIECwIBLgEIAQIMAQcBBwwBCQEHIwQJAQVCBAkCAzYBBwEIQgQYBAkuAQMBCUIECwfCoS4BBQECDAEHAQQvBAsBCC4BCgEELQfCrAEILwQJAQUTB8OfAQYvBAUBCQoCAQfCpgwBAgEDHwEEAQkSAQEBBSMEBQEIQgQFAwEjBAIBB0IEAgMCIwQJAQRCBAkDAzYBAwECIwQLAQlCBAsHwqEuAQcBByMEGAEILgEHAQkvB8KiAQcdAQMBCS8Hw58BBx0BCAEFLwfCrAEKHQEHAQkvB8OGAQMdAQgBCi8HwqYBCh0BBQEKLwfDhgEKHQEEAQkiAQkBBzYBBAEEIwQVAQMuAQkBBiMECgEBCQcwBx8JAgEHHgkCAQciCQIBByQJAgEHw5EJAgEHMAkCAQcjCQIBBzRCBAoCAS4BCQEGIwQvAQQJBxwHIgkCAQczCQIBBycJAgEHIwkCAQccGgVmAgEdAQgBAQkHMwclCQIBBzEJAgEHIgkCAQcpCQIBByUJAgEHHwkCAQcjCQIBBx43AQIBBxoCAgIBQgQvAgEuAQkBAQkHJQckCQIBByQJAgEHFgkCAQcjCQIBBycJAgEHHQkCAQcZCQIBByUJAgEHNAkCAQcdGgQvAgFCBBUCAS4BAQEJCQclByQJAgEHJAkCAQcWCQIBByMJAgEHJwkCAQcdCQIBBxkJAgEHJQkCAQc0CQIBBx0aBC8CAUICAQQKLgEHAQMJByUHJAkCAQckCQIBBxYJAgEHIwkCAQcnCQIBBx0JAgEHGQkCAQclCQIBBzQJAgEHHRoELwIBPQIBBAouAQQBBy0Hwp0BBzYBAQEEQgQLBD8uAQgBAQwBCQEKCQclByQJAgEHJAkCAQcWCQIBByMJAgEHJwkCAQcdCQIBBxkJAgEHJQkCAQc0CQIBBx0aBC8CAUICAQQVLgEKAQIMAQEBCiMECQEHQgQJAgM2AQQBCUIEGAQJLgEHAQhCBAsHwqEuAQEBCgwBBgEHLwQLAQQuAQQBCS0HwqUBCi8ECQEGEwfDoAEGLwQFAQMKAgEHwqYMAQkBAh8BCQEGEgEDAQQjBAUBAkIEBQMBIwQCAQZCBAIDAiMECQEFQgQJAwM2AQoBCSMECwEKQgQLB8KhLgEBAQEjBBgBBi4BAgEGLwfCogEHHQEDAQQvB8OhAQcdAQIBCS8Hw6IBBx0BCAECLwfDowECHQEDAQMvB8KmAQEdAQMBCS8Hw6MBBx0BAQEKIgEKAQI2AQMBASMEFQEHLgEEAQIjBAoBBAkHMAcfCQIBBx4JAgEHIgkCAQckCQIBB8ORCQIBBzAJAgEHIwkCAQc0QgQKAgEuAQQBCCMELwEECQccByIJAgEHMwkCAQcnCQIBByMJAgEHHBoFZgIBHQEEAQgJBzMHJQkCAQcxCQIBByIJAgEHKQkCAQclCQIBBx8JAgEHIwkCAQceNwEFAQgaAgICAUIELwIBLgEFAQcJByQHLQkCAQclCQIBBx8JAgEHKAkCAQcjCQIBBx4JAgEHNBoELwIBQgQVAgEuAQgBCgkHJActCQIBByUJAgEHHwkCAQcoCQIBByMJAgEHHgkCAQc0GgQvAgFCAgEECi4BAwEGCQckBy0JAgEHJQkCAQcfCQIBBygJAgEHIwkCAQceCQIBBzQaBC8CAT0CAQQKLgECAQEtB8OkAQc2AQgBB0IECwQ/LgEGAQEMAQEBCgkHJActCQIBByUJAgEHHwkCAQcoCQIBByMJAgEHHgkCAQc0GgQvAgFCAgEEFS4BCAEDDAEHAQYjBAkBAUIECQIDNgECAQJCBBgECS4BCgEDQgQLB8KhLgEFAQMMAQIBAi8ECwEFLgEKAQEtB8OlAQIvBAkBCBMHw6YBBi8EBQEICgIBB8KmDAEDAQQfAQgBChIBCAEEIwQFAQpCBAUDASMEAgECQgQCAwIjBAkBBUIECQMDNgEBAQcjBAsBA0IECwfCoS4BBgEEIwQYAQouAQgBBy8HwqIBBR0BBwEELwfDpwEGHQEKAQovB8OoAQgdAQMBBy8Hw58BBB0BAQEGLwfCpgEKHQEJAQMvB8OfAQMdAQYBCSIBCgEKNgEKAQYjBBUBAy4BCAEHIwQKAQkJBzAHHwkCAQceCQIBByIJAgEHJAkCAQfDkQkCAQcwCQIBByMJAgEHNEIECgIBLgEGAQYjBC8BCgkHHAciCQIBBzMJAgEHJwkCAQcjCQIBBxwaBWYCAR0BCAEHCQczByUJAgEHMQkCAQciCQIBBykJAgEHJQkCAQcfCQIBByMJAgEHHjcBCgEKGgICAgFCBC8CAS4BAwECCQchByYJAgEHHQkCAQceCQIBBwsJAgEHKQkCAQcdCQIBBzMJAgEHHxoELwIBQgQVAgEuAQgBBQkHIQcmCQIBBx0JAgEHHgkCAQcLCQIBBykJAgEHHQkCAQczCQIBBx8aBC8CAUICAQQKLgEKAQQJByEHJgkCAQcdCQIBBx4JAgEHCwkCAQcpCQIBBx0JAgEHMwkCAQcfGgQvAgE9AgEECi4BCAEELQfChgEHNgEDAQpCBAsEPy4BCAEFDAECAQgJByEHJgkCAQcdCQIBBx4JAgEHCwkCAQcpCQIBBx0JAgEHMwkCAQcfGgQvAgFCAgEEFS4BAgEGDAECAQIjBAkBB0IECQIDNgEEAQpCBBgECS4BAQEIQgQLB8KhLgEIAQEMAQQBCC8ECwEGLgEGAQQtB8KjAQgvBAkBBhMHw6kBBy8EBQEKCgIBB8KmDAEEAQQfAQgBAxIBBAEHIwQFAQRCBAUDASMEAgEJQgQCAwIjBAkBBkIECQMDNgEFAQMjBAsBAUIECwfCoS4BBwEDIwQYAQIuAQQBBi8HwqIBBB0BBwEFLwfDqgEKHQEBAQUvB8OrAQYdAQgBAS8Hw6wBAh0BCAEBLwfCpgEGHQEKAQgvB8OsAQcdAQYBAyIBAwEKNgEDAQQjBC8BCQkHHAciCQIBBzMJAgEHJwkCAQcjCQIBBxwaBWYCAR0BCQEKCQczByUJAgEHMQkCAQciCQIBBykJAgEHJQkCAQcfCQIBByMJAgEHHjcBBQEGGgICAgFCBC8CAS4BAgEEIwQGAQEJBxwHIgkCAQczCQIBBycJAgEHIwkCAQccGgVmAgEdAQoBCAkHJwcjCQIBBzAJAgEHIQkCAQc0CQIBBx0JAgEHMwkCAQcfNwEEAQQaAgICAUIEBgIBLgEDAQojBCkBBgkHHAciCQIBBzMJAgEHJwkCAQcjCQIBBxwaBWYCAUIEKQIBLgEHAQMJBxwHHQkCAQcyCQIBBycJAgEHHgkCAQciCQIBBzEJAgEHHQkCAQceGgQvAgEnAgEBBycCAQEDQgQLAgEuAQMBBicECwEJLgEIAQgtB8OtAQU2AQoBBgkHKQcdCQIBBx8JAgEHCQkCAQccCQIBBzMJAgEHCgkCAQceCQIBByMJAgEHJAkCAQcdCQIBBx4JAgEHHwkCAQcgCQIBBxkJAgEHJQkCAQc0CQIBBx0JAgEHJhoEFAIBLgEFAQctB8OuAQY2AQgBAiMEDQEJCQcpBx0JAgEHHwkCAQcJCQIBBxwJAgEHMwkCAQcKCQIBBx4JAgEHIwkCAQckCQIBBx0JAgEHHgkCAQcfCQIBByAJAgEHGQkCAQclCQIBBzQJAgEHHQkCAQcmGgQUAgEdAQMBAi8ELwEJHQECAQkZB2UBCR0BBwEKCQcrByMJAgEHIgkCAQczNwEFAQMaAgICAR0BCgEELwdqAQIdAQgBAxkHZQEDQgQNAgEuAQUBBQkHIgczCQIBBycJAgEHHQkCAQcvCQIBBwkJAgEHKBoEDQIBHQEDAQQJBxwHHQkCAQcyCQIBBycJAgEHHgkCAQciCQIBBzEJAgEHHQkCAQceHQEJAQQZB2UBAw8CAQEGJwIBAQcnAgEBBEIECwIBLgEIAQEMAQYBBAwBCQEJCQdAByQJAgEHKgkCAQclCQIBBzMJAgEHHwkCAQcjCQIBBzQaBCkCARYCAQEFHQEEAQgJByEHMwkCAQcnCQIBBx0JAgEHKAkCAQciCQIBBzMJAgEHHQkCAQcnNwEJAQQXAgICAS4BBAEBLQfDrwEGNgEFAQJCBAsEPy4BCAEJDAECAQcJB0AHQAkCAQczCQIBByIJAgEHKQkCAQcqCQIBBx8JAgEHNAkCAQclCQIBBx4JAgEHHRoEKQIBFgIBAQUdAQQBCAkHIQczCQIBBycJAgEHHQkCAQcoCQIBByIJAgEHMwkCAQcdCQIBByc3AQoBAhcCAgIBLgEJAQktB8OwAQQ2AQoBAUIECwQ/LgEHAQUMAQYBAQkHQAcmCQIBBx0JAgEHLQkCAQcdCQIBBzMJAgEHIgkCAQchCQIBBzQaBCkCARYCAQEKHQEKAQcJByEHMwkCAQcnCQIBBx0JAgEHKAkCAQciCQIBBzMJAgEHHQkCAQcnNwEJAQcXAgICAS4BBAEKLQfDsQEGNgEFAQZCBAsEPy4BAQECDAEDAQgJBzAHJQkCAQctCQIBBy0JAgEHCgkCAQcqCQIBByUJAgEHMwkCAQcfCQIBByMJAgEHNBoEKQIBFgIBAQUdAQYBCAkHIQczCQIBBycJAgEHHQkCAQcoCQIBByIJAgEHMwkCAQcdCQIBByc3AQgBBxcCAgIBLgEEAQYtB8OyAQE2AQoBAkIECwQ/LgEIAQEMAQcBAgkHMAclCQIBBy0JAgEHLQkCAQcMCQIBBx0JAgEHLQkCAQcdCQIBBzMJAgEHIgkCAQchCQIBBzQaBCkCARYCAQEFHQEDAQcJByEHMwkCAQcnCQIBBx0JAgEHKAkCAQciCQIBBzMJAgEHHQkCAQcnNwEBAQIXAgICAS4BCAEFLQfDswEENgEJAQNCBAsEPy4BBQEBDAEKAQIJB0AHDAkCAQcdCQIBBy0JAgEHHQkCAQczCQIBByIJAgEHIQkCAQc0CQIBB0AJAgEHCAkCAQcNCQIBBwMJAgEHQAkCAQcECQIBBx0JAgEHMAkCAQcjCQIBBx4JAgEHJwkCAQcdCQIBBx4aBCkCARYCAQECHQECAQkJByEHMwkCAQcnCQIBBx0JAgEHKAkCAQciCQIBBzMJAgEHHQkCAQcnNwEBAQkXAgICAS4BBwEDLQfDtAEINgEIAQFCBAsEPy4BCAEIDAEGAQcJB0AHQAkCAQccCQIBBx0JAgEHMgkCAQcnCQIBBx4JAgEHIgkCAQcxCQIBBx0JAgEHHgkCAQdACQIBBx0JAgEHMQkCAQclCQIBBy0JAgEHIQkCAQclCQIBBx8JAgEHHRoEBgIBFgIBAQcdAQUBBQkHIQczCQIBBycJAgEHHQkCAQcoCQIBByIJAgEHMwkCAQcdCQIBByc3AQcBAhcCAgIBLgEHAQMtB8O1AQY2AQYBCUIECwQ/LgEDAQIMAQQBAgkHQAdACQIBByYJAgEHHQkCAQctCQIBBx0JAgEHMwkCAQciCQIBByEJAgEHNAkCAQdACQIBBx0JAgEHMQkCAQclCQIBBy0JAgEHIQkCAQclCQIBBx8JAgEHHRoEBgIBFgIBAQQdAQoBBAkHIQczCQIBBycJAgEHHQkCAQcoCQIBByIJAgEHMwkCAQcdCQIBByc3AQoBChcCAgIBLgEGAQQtB8O2AQI2AQIBB0IECwQ/LgEIAQoMAQMBCAkHQAdACQIBBxwJAgEHHQkCAQcyCQIBBycJAgEHHgkCAQciCQIBBzEJAgEHHQkCAQceCQIBB0AJAgEHJgkCAQcwCQIBBx4JAgEHIgkCAQckCQIBBx8JAgEHQAkCAQcoCQIBByEJAgEHMwkCAQcwCQIBBx8JAgEHIgkCAQcjCQIBBzMaBAYCARYCAQEBHQECAQMJByEHMwkCAQcnCQIBBx0JAgEHKAkCAQciCQIBBzMJAgEHHQkCAQcnNwEDAQQXAgICAS4BAgEHLQfDtwEHNgECAQFCBAsEPy4BBwEGDAEIAQoJB0AHQAkCAQccCQIBBx0JAgEHMgkCAQcnCQIBBx4JAgEHIgkCAQcxCQIBBx0JAgEHHgkCAQdACQIBByYJAgEHMAkCAQceCQIBByIJAgEHJAkCAQcfCQIBB0AJAgEHKAkCAQchCQIBBzMJAgEHMBoEBgIBFgIBAQIdAQUBAQkHIQczCQIBBycJAgEHHQkCAQcoCQIBByIJAgEHMwkCAQcdCQIBByc3AQcBCRcCAgIBLgEKAQgtB8O4AQI2AQoBBkIECwQ/LgEJAQUMAQYBAwkHQAdACQIBBxwJAgEHHQkCAQcyCQIBBycJAgEHHgkCAQciCQIBBzEJAgEHHQkCAQceCQIBB0AJAgEHJgkCAQcwCQIBBx4JAgEHIgkCAQckCQIBBx8JAgEHQAkCAQcoCQIBBzMaBAYCARYCAQECHQEHAQkJByEHMwkCAQcnCQIBBx0JAgEHKAkCAQciCQIBBzMJAgEHHQkCAQcnNwEIAQoXAgICAS4BBgEGLQfDuQECNgEFAQFCBAsEPy4BAQEEDAEIAQYJB0AHQAkCAQcoCQIBBy8JAgEHJwkCAQceCQIBByIJAgEHMQkCAQcdCQIBBx4JAgEHQAkCAQcdCQIBBzEJAgEHJQkCAQctCQIBByEJAgEHJQkCAQcfCQIBBx0aBAYCARYCAQECHQECAQQJByEHMwkCAQcnCQIBBx0JAgEHKAkCAQciCQIBBzMJAgEHHQkCAQcnNwEDAQkXAgICAS4BBgECLQfDugEENgEBAQVCBAsEPy4BAQEKDAEJAQQJB0AHQAkCAQcnCQIBBx4JAgEHIgkCAQcxCQIBBx0JAgEHHgkCAQdACQIBByEJAgEHMwkCAQccCQIBBx4JAgEHJQkCAQckCQIBByQJAgEHHQkCAQcnGgQGAgEWAgEBAR0BBgEJCQchBzMJAgEHJwkCAQcdCQIBBygJAgEHIgkCAQczCQIBBx0JAgEHJzcBAwEEFwICAgEuAQUBCC0Hw7sBCDYBBQEFQgQLBD8uAQkBBgwBBgEKCQdAB0AJAgEHHAkCAQcdCQIBBzIJAgEHJwkCAQceCQIBByIJAgEHMQkCAQcdCQIBBx4JAgEHQAkCAQchCQIBBzMJAgEHHAkCAQceCQIBByUJAgEHJAkCAQckCQIBBx0JAgEHJxoEBgIBFgIBAQcdAQUBAQkHIQczCQIBBycJAgEHHQkCAQcoCQIBByIJAgEHMwkCAQcdCQIBByc3AQEBBRcCAgIBLgEFAQYtB8O8AQk2AQcBCEIECwQ/LgEEAQoMAQQBAgkHQAdACQIBBycJAgEHHgkCAQciCQIBBzEJAgEHHQkCAQceCQIBB0AJAgEHHQkCAQcxCQIBByUJAgEHLQkCAQchCQIBByUJAgEHHwkCAQcdGgQGAgEWAgEBAh0BAQEECQchBzMJAgEHJwkCAQcdCQIBBygJAgEHIgkCAQczCQIBBx0JAgEHJzcBCgEFFwICAgEuAQQBBy0Hw70BAzYBAwEIQgQLBD8uAQMBBAwBBQEFCQdAB0AJAgEHJgkCAQcdCQIBBy0JAgEHHQkCAQczCQIBByIJAgEHIQkCAQc0CQIBB0AJAgEHIQkCAQczCQIBBxwJAgEHHgkCAQclCQIBByQJAgEHJAkCAQcdCQIBBycaBAYCARYCAQEHHQECAQYJByEHMwkCAQcnCQIBBx0JAgEHKAkCAQciCQIBBzMJAgEHHQkCAQcnNwEEAQoXAgICAS4BCgECLQfDvgEGNgEGAQpCBAsEPy4BCAEHDAEEAQUJB0AHQAkCAQcoCQIBBy8JAgEHJwkCAQceCQIBByIJAgEHMQkCAQcdCQIBBx4JAgEHQAkCAQchCQIBBzMJAgEHHAkCAQceCQIBByUJAgEHJAkCAQckCQIBBx0JAgEHJxoEBgIBFgIBAQQdAQgBBQkHIQczCQIBBycJAgEHHQkCAQcoCQIBByIJAgEHMwkCAQcdCQIBByc3AQYBBRcCAgIBLgECAQctB8O/AQQ2AQIBCkIECwQ/LgEDAQYMAQIBCgkHHQcvCQIBBx8JAgEHHQkCAQceCQIBBzMJAgEHJQkCAQctGgQpAgEtB8SAAQIJBx0HLwkCAQcfCQIBBx0JAgEHHgkCAQczCQIBByUJAgEHLRoEKQIBHQEJAQoJBx8HIwkCAQcMCQIBBx8JAgEHHgkCAQciCQIBBzMJAgEHKTcBCgEKGgICAgEtB8SBAQoJBx0HLwkCAQcfCQIBBx0JAgEHHgkCAQczCQIBByUJAgEHLRoEKQIBHQEHAQgJBx8HIwkCAQcMCQIBBx8JAgEHHgkCAQciCQIBBzMJAgEHKTcBCgEHGgICAgEdAQIBChkHaQEKLQfEggEJCQcdBy8JAgEHHwkCAQcdCQIBBx4JAgEHMwkCAQclCQIBBy0aBCkCAR0BCgEBCQcfByMJAgEHDAkCAQcfCQIBBx4JAgEHIgkCAQczCQIBByk3AQgBChoCAgIBHQEGAQQZB2kBBx0BBQEHCQciBzMJAgEHJwkCAQcdCQIBBy8JAgEHCQkCAQcoNwEGAQIaAgICAR0BAgECCQcMBx0JAgEHGwkCAQchCQIBBx0JAgEHMwkCAQcfCQIBByEJAgEHNB0BCQEHGQdlAQEdAQoBAiwHZQEDNwEJAQEXAgICAS4BCgEGLQfEgwEBNgEBAQRCBAsEPy4BBwEHDAEIAQYJBycHIwkCAQcwCQIBByEJAgEHNAkCAQcdCQIBBzMJAgEHHwkCAQcDCQIBBy0JAgEHHQkCAQc0CQIBBx0JAgEHMwkCAQcfGgQGAgEdAQQBCgkHKQcdCQIBBx8JAgEHCwkCAQcfCQIBBx8JAgEHHgkCAQciCQIBBzIJAgEHIQkCAQcfCQIBBx03AQMBAxoCAgIBHQEJAQgJByYHHQkCAQctCQIBBx0JAgEHMwkCAQciCQIBByEJAgEHNB0BCgEJGQdlAQYuAQkBAS0HxIQBCjYBAQEHQgQLBD8uAQYBCQwBCQEKCQcnByMJAgEHMAkCAQchCQIBBzQJAgEHHQkCAQczCQIBBx8JAgEHAwkCAQctCQIBBx0JAgEHNAkCAQcdCQIBBzMJAgEHHxoEBgIBHQEHAQgJBykHHQkCAQcfCQIBBwsJAgEHHwkCAQcfCQIBBx4JAgEHIgkCAQcyCQIBByEJAgEHHwkCAQcdNwEJAQIaAgICAR0BAgEBCQccBx0JAgEHMgkCAQcnCQIBBx4JAgEHIgkCAQcxCQIBBx0JAgEHHh0BAwEDGQdlAQguAQMBCC0HxIUBCDYBAgEEQgQLBD8uAQcBAwwBBwEKCQcnByMJAgEHMAkCAQchCQIBBzQJAgEHHQkCAQczCQIBBx8JAgEHAwkCAQctCQIBBx0JAgEHNAkCAQcdCQIBBzMJAgEHHxoEBgIBHQEBAQEJBykHHQkCAQcfCQIBBwsJAgEHHwkCAQcfCQIBBx4JAgEHIgkCAQcyCQIBByEJAgEHHwkCAQcdNwEFAQoaAgICAR0BBQEHCQcnBx4JAgEHIgkCAQcxCQIBBx0JAgEHHh0BBQEBGQdlAQEuAQYBAS0HxIYBBDYBBwECQgQLBD8uAQIBCAwBCQEKIwQMAQkvBG0BAx0BCgEHCQfEhwc/CQIBB0EJAgEHJQkCAQdnCQIBBy4JAgEHQgkCAQcnCQIBBzAJAgEHQB0BCgEELwdqAQodAQYBBgEHaAEKQgQMAgEuAQYBByMEDwEHMgdpAQdCBA8CAS4BCgEBIwRlAQNCBGUHaS4BCgECLwQGAQUtB8SIAQVBBGUHxIkuAQkBBS0HxIoBCDYBBQEICQcwByMJAgEHMwkCAQcwCQIBByUJAgEHHxoEDwIBHQEIAQkJBywHHQkCAQcgCQIBByYaBBQCAR0BCQEELwQGAQIdAQkBARkHZQEJHQEKAQIZB2UBA0IEDwIBLgEGAQcJB0AHQAkCAQckCQIBBx4JAgEHIwkCAQcfCQIBByMJAgEHQAkCAQdAGgQGAgFCBAYCAS4BCAEBFARlAQcuAQgBAwwBAwEIEwfEiwEFCQccByIJAgEHMwkCAQcnCQIBByMJAgEHHBoFZgIBHQEHAQkJBycHIwkCAQcwCQIBByEJAgEHNAkCAQcdCQIBBzMJAgEHHzcBCAEIGgICAgFCBAYCAS4BCgECIwQmAQFCBCYHaS4BCQEBLgEGAQMJBy0HHQkCAQczCQIBBykJAgEHHwkCAQcqGgQPAgFBBCYCAS4BCQEHLQfEjAEFNgEJAQUjBFUBBxoEDwQmQgRVAgEuAQQBCgkHLQcdCQIBBzMJAgEHKQkCAQcfCQIBByoaBFUCASkCAQfEjS0HxI4BARoEBgRVHQEDAQkJBzAHJQkCAQcwCQIBByoJAgEHHQkCAQdANwEFAQcaAgICAS4BCQEBLQfEjwEINgEEAQpCBAsEPy4BCgEHEwfEjAEBLgEKAQQMAQcBAgkHNAclCQIBBx8JAgEHMAkCAQcqGgRVAgEdAQcBCC8EDAEJHQEJAQoZB2UBCC0HxJABChoEBgRVHQEHAQYJBzAHJQkCAQcwCQIBByoJAgEHHQkCAQdANwEFAQkaAgICAS4BAgEFLQfEkQEJNgEBAQFCBAsEPy4BBAEEEwfEjAEKLgEFAQkMAQIBBgwBCgEFFAQmAQIuAQcBAhMHxJIBBAkHIQcmCQIBBx0JAgEHHgkCAQcLCQIBBykJAgEHHQkCAQczCQIBBx8aBC8CAScCAQEGLgEGAQQtB8STAQM2AQYBB0IECwQ/LgEKAQoMAQMBCCMERQEGCQchByYJAgEHHQkCAQceCQIBBwsJAgEHKQkCAQcdCQIBBzMJAgEHHxoELwIBHQEFAQcJBx8HIwkCAQcTCQIBByMJAgEHHAkCAQcdCQIBBx4JAgEHFgkCAQclCQIBByYJAgEHHTcBCgEHGgICAgEdAQoBCBkHaQEKQgRFAgEuAQEBBQkHIgczCQIBBycJAgEHHQkCAQcvCQIBBwkJAgEHKBoERQIBHQEKAQcJByoHHQkCAQclCQIBBycJAgEHLQkCAQcdCQIBByYJAgEHJh0BBgEBGQdlAQMdAQUBBCwHZQEENwEFAQM8AgICAS4BBQEHLQfElAEDNgEFAQpCBAsEPy4BAwEKDAECAQkvBC8BCi0HxJUBBwkHKQcdCQIBBx8JAgEHCQkCAQccCQIBBzMJAgEHCgkCAQceCQIBByMJAgEHJAkCAQcdCQIBBx4JAgEHHwkCAQcgCQIBBw0JAgEHHQkCAQcmCQIBBzAJAgEHHgkCAQciCQIBByQJAgEHHwkCAQcjCQIBBx4aBBQCAR0BCQEHLwQvAQkdAQUBBAkHHAcdCQIBBzIJAgEHJwkCAQceCQIBByIJAgEHMQkCAQcdCQIBBx4dAQkBAxkHaAEHLQfElgEBCQcpBx0JAgEHHwkCAQcJCQIBBxwJAgEHMwkCAQcKCQIBBx4JAgEHIwkCAQckCQIBBx0JAgEHHgkCAQcfCQIBByAJAgEHDQkCAQcdCQIBByYJAgEHMAkCAQceCQIBByIJAgEHJAkCAQcfCQIBByMJAgEHHhoEFAIBHQEGAQEvBC8BCR0BAgEKCQccBx0JAgEHMgkCAQcnCQIBBx4JAgEHIgkCAQcxCQIBBx0JAgEHHh0BAwEKGQdoAQQdAQcBCQkHKQcdCQIBBx83AQMBChoCAgIBLgEGAQctB8OrAQg2AQcBB0IECwQ/LgEDAQkMAQUBCQwBAQEJIwQJAQlCBAkCAzYBAgEDQgQYBAkuAQMBAUIECwfCoS4BCgEKDAEGAQIvBAsBCi4BAgEHLQfElwECLwQJAQkTB8SYAQovBAUBBgoCAQfCpgwBBQEEHwEIAQESAQQBAiMEZQEFQgRlAwE2AQQBAQkHKActCQIBByMJAgEHIwkCAQceGgRJAgEdAQUBAgkHHgclCQIBBzMJAgEHJwkCAQcjCQIBBzQaBEkCAR0BAwEFGQdpAQIeBGUCAR0BAgEHGQdlAQMKAgEHwqYMAQEBBh8BBgEEEgEJAQkjBGoBBEIEagMBIwQFAQNCBAUDAiMEPAECQgQ8AwM2AQQBBSMEYAEJLwQTAQkdAQIBBwEHaQEBQgRgAgEuAQQBCCMESgEDLwQ8AQI+B3MBCC8Hwo8BBEIESgIBLgEHAQgJByYHHQkCAQcfCQIBBxoJAgEHIgkCAQczCQIBByEJAgEHHwkCAQcdCQIBByYaBGACAR0BAQEDCQcpBx0JAgEHHwkCAQcaCQIBByIJAgEHMwkCAQchCQIBBx8JAgEHHQkCAQcmGgRgAgEdAQcBBhkHaQEECQIBBEodAQQBARkHZQEHLgEIAQMnBAYBAi4BBQEGLQd9AQMvAQcBBQoCAQfCpgkHMAcjCQIBByMJAgEHLAkCAQciCQIBBx0aBAYCAR0BAwEFLwfEmQEBCQRqAgEdAQcBBS8EEQEBHQEDAQMvBAUBBh0BCgEKGQdlAQo3AQgBCQkCAgIBHQEEAQoJB8SaBx0JAgEHLwkCAQckCQIBByIJAgEHHgkCAQcdCQIBByYJAgEHxJk3AQIBBgkCAgIBHQEJAQkJBx8HIwkCAQcPCQIBBxoJAgEHBQkCAQcMCQIBBx8JAgEHHgkCAQciCQIBBzMJAgEHKRoEYAIBHQEHAQIZB2kBBjcBBgEFCQICAgEdAQcBCQkHxJoHJAkCAQclCQIBBx8JAgEHKgkCAQfEmQkCAQfEmzcBBQEBCQICAgE3AQYBAkICAgIBLgEBAQEMAQgBBR8BCAEHEgEEAQQjBFIBBUIEUgMBIwQdAQNCBB0DAjYBBQEFCQckByEJAgEHJgkCAQcqGgRaAgEdAQUBBy8EHQECHQEBAQgZB2UBBi4BBwEJIwRUAQIvBEsBCh0BBgEDLwRpAQgdAQQBCAkEUgQdHgIBBDYdAQUBCQkHLQcdCQIBBzMJAgEHKQkCAQcfCQIBByoaBGkCATcBAQEJIAICAgEdAQEBAxkHaAEHQgRUAgEuAQQBAy8EbAEKHQEFAQUvBFIBCh0BAQEEGQdlAQI9BFQCAS4BBwEDLQfCvwEJNgEKAQkvBEsBBh0BCAEDLwRpAQgdAQIBCQkEUgQdCQIBB2UeAgEENh0BBwEECQctBx0JAgEHMwkCAQcpCQIBBx8JAgEHKhoEaQIBNwEBAQEgAgICAR0BBQEBGQdoAQlCBFQCAS4BAwEBDAEIAQEvBFQBCQoCAQfCpgwBAQEIHwEHAQkSAQoBCSMEWwEEQgRbAwE2AQkBAiMEVAEBMgdpAQFCBFQCAS4BCAEHIwRIAQNCBEgHaS4BBAEBQQRIB8ScLgEFAQYtB8SdAQM2AQoBBiMEJAEFQgQkB2kuAQkBAi4BCgEBQQQkB8ScLgEDAQotB8SeAQg2AQUBAiMECAEKJQfEnAQkJQIBB2UeAgEHxJwJAgEESEIECAIBLgEDAQkJByQHIQkCAQcmCQIBByoaBFQCAR0BBAEJGgRbBAgdAQMBBRkHZQEGLgEEAQQMAQMBCBQEJAEKLgEFAQoTB3QBCRQESAEJLgEKAQEMAQEBAhMHwrcBCC8EVAEKCgIBB8KmDAECAQcfAQgBBBIBBAEIHwEEAQESAQkBAiMEFwEJQgQXAwE2AQQBAi8EbAEBHQEDAQgvBBcBBh0BAQEFGQdlAQgKAgEHwqYMAQoBBh8BBwEK","d":["Q","W","E","R","T","Y","U","I","O","P","A","S","D","F","G","H","J","K","L","Z","X","C","V","B","N","M","q","w","e","r","t","y","u","i","o","p","a","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m","1","2","3","4","5","6","7","8","9","0","$","_","[","]",1308,1447,1448,1586,1587,1759,1760,1911,1912,2113,2114,2256,2257,2436,2437,2556,2557,2677,2678,2812,2813,2935,2936,3062,3063,4407,4408,4431,4432,4541,4542,4610,4611,4661,1,"self","-",2,0,"",705,4662,4663,99991,4,7,9,14,18,19,24,31,32,37,58,13,100,99,52,56,55,49,51,102,57,53,48,98,101,50,97,54,64,1268,956,103,3,981,1006,1031,1056,1081,59,1106,1131,1156,1181,1206,1231,1256,104,914,4664,4675,false,26,123,122,131,2147483647,136,137,121,130,74,117,80,135,156,155,164,146,169,170,134,143,11,79,148,149,185,184,193,44,65,71,173,"|",171,198,199,126,125,83,89,139,140,163,162,61,158," ",".","\"","'",34,176,177,111,60,68,116,112,82,"{","}",118,132,106,105,114,95,119,120,110,109,124,1328,1327,1336,175,174,201,230,257,286,316,356,394,431,476,517,556,593,629,668,703,741,779,806,827,872,878,923,969,1012,"\\",1040,10,1077,1037,1169,28,1130,1138,1157,1165,1099,1185,1239,1278,1321,1341,1342,"=",";","/",8,47,43]});})(); \ No newline at end of file diff --git a/core/kwsg.py b/core/kwsg.py new file mode 100644 index 0000000..07c3539 --- /dev/null +++ b/core/kwsg.py @@ -0,0 +1,210 @@ +"""Compatibility aggregate for recovered KWSG-related algorithms. + +Implementations live in focused modules: + +- `core.sig` +- `core.tokensig` +- `core.sig3` +- `core.enc_data` +- `core.atlas_sign` +- `core.dfp_sign` +- `core.reward_sign` +- `core.xfalcon` + +This module exists so old `from ks_sign import ...` call sites keep working. +Do not add new algorithm implementation here. +""" + +from __future__ import annotations + +from .captured_profile import API_ST, CLIENT_KEY, CLIENT_SALT, DID, EGID, ODID, RDID +from .atlas_sign import ( + ATLAS_SIGN_HMAC_KEY, + atlas_sign, + atlas_sign_from_digest_hex, + atlas_sign_to_digest_hex, +) +from .dfp_sign import ( + DFP_PAYLOAD_KEYS, + DFP_SDK_ID, + DFP_SIGN_KEYS, + DfpSignMaterial, + build_dfp_sign_material, + dfp_atlas_sign, + id_mapping_data_only, + legacy_product_ts_sv_payload, + parse_dfp_atlas_sign, + sign_dfp_form, + tree_values_sorted_non_empty_except_sign, +) +from .enc_data import ( + KWSG_10400_DEFAULT_CFG9, + KWSG_10400_NONCE_XOR, + KWSG_10400_T1_LEN, + KWSG_10400_T2_LEN, + KWSG_266FC_PERM, + KWSG_STATIC_AES_IV, + KWSG_STATIC_AES_KEY, + ZT_OUTER_CONFIGS, + build_inner_zt_header, + derive_outer_xor_key, + kwsg_10400_ecb_encrypt, + kwsg_10400_nonce9, + kwsg_10400_raw, + kwsg_10400_raw_with_inner_fields, + kwsg_266fc_block, + load_kwsg_10400_tables, + parse_inner_zt_header, + zt_outer_unwrap, + zt_outer_wrap, +) +from .reward_sign import ( + KWSG_10418_SIGN_HMAC_KEY, + kwsg_10418_reward_sign, + kwsg_10418_reward_sign_from_digest_hex, + kwsg_10418_reward_sign_to_digest_hex, +) +from .sig import SIG_SALT, body_md5, build_sig_plaintext, sig +from .sig3 import ( + KWSG_10418_DEFAULT_STATE_SOURCE, + KWSG_10418_HMAC_KEY, + KWSG_10418_PREFIX8, + KWSG_10418_PREFIX_HEAD2, + KWSG_10418_SAMPLE_SESSION_SEED, + KWSG_10418_SIG3_HMAC_KEY, + KWSG_10418_SIG3_PREFIX8, + KWSG_10418_SIG3_PREFIX_CODE, + KWSG_10418_SIGN_PREFIX8, + KWSG_10418_SIGN_PREFIX_CODE, + Kwsg10418State, + kwsg_10418_binary48, + kwsg_10418_binary48_from_prehash32, + kwsg_10418_digest24, + kwsg_10418_digest24_from_binary48, + kwsg_10418_digest24_unmix, + kwsg_10418_prefix8, + kwsg_10418_prehash32, + kwsg_10418_sig3_hex, + kwsg_10418_state_low24_from_source, + load_kwsg_10418_sign_tables, + load_kwsg_10418_tables, +) +from .tokensig import tokensig +from .xfalcon import ( + xfalcon_digest_hex_from_input_bytes, + xfalcon_digest_hex_from_input_hex, + xfalcon_digest_words_from_input_bytes, + xfalcon_digest_words_from_input_hex, + xfalcon_folded_block_from_input_bytes, + xfalcon_folded_block_from_raw_bytes, + xfalcon_message_words_from_folded_block, + xfalcon_message_words_from_input_hex, + xfalcon_packed_block_from_input_hex, + xfalcon_te_hex_from_input_bytes, + xfalcon_te_hex_from_input_hex, + xfalcon_value_from_input_bytes, + xfalcon_value_from_input_hex, +) + + +__all__ = [ + "API_ST", + "ATLAS_SIGN_HMAC_KEY", + "CLIENT_KEY", + "CLIENT_SALT", + "DID", + "DFP_PAYLOAD_KEYS", + "DFP_SDK_ID", + "DFP_SIGN_KEYS", + "DfpSignMaterial", + "EGID", + "KWSG_10400_DEFAULT_CFG9", + "KWSG_10400_NONCE_XOR", + "KWSG_10400_T1_LEN", + "KWSG_10400_T2_LEN", + "KWSG_10418_DEFAULT_STATE_SOURCE", + "KWSG_10418_HMAC_KEY", + "KWSG_10418_PREFIX8", + "KWSG_10418_PREFIX_HEAD2", + "KWSG_10418_SAMPLE_SESSION_SEED", + "KWSG_10418_SIG3_HMAC_KEY", + "KWSG_10418_SIG3_PREFIX8", + "KWSG_10418_SIG3_PREFIX_CODE", + "KWSG_10418_SIGN_HMAC_KEY", + "KWSG_10418_SIGN_PREFIX8", + "KWSG_10418_SIGN_PREFIX_CODE", + "KWSG_266FC_PERM", + "KWSG_STATIC_AES_IV", + "KWSG_STATIC_AES_KEY", + "Kwsg10418State", + "ODID", + "RDID", + "SIG_SALT", + "ZT_OUTER_CONFIGS", + "atlas_sign", + "atlas_sign_from_digest_hex", + "atlas_sign_to_digest_hex", + "body_md5", + "build_inner_zt_header", + "build_dfp_sign_material", + "build_sig_plaintext", + "dfp_atlas_sign", + "derive_outer_xor_key", + "id_mapping_data_only", + "kwsg_10400_ecb_encrypt", + "kwsg_10400_nonce9", + "kwsg_10400_raw", + "kwsg_10400_raw_with_inner_fields", + "kwsg_10418_binary48", + "kwsg_10418_binary48_from_prehash32", + "kwsg_10418_digest24", + "kwsg_10418_digest24_from_binary48", + "kwsg_10418_digest24_unmix", + "kwsg_10418_prefix8", + "kwsg_10418_prehash32", + "kwsg_10418_reward_sign", + "kwsg_10418_reward_sign_from_digest_hex", + "kwsg_10418_reward_sign_to_digest_hex", + "kwsg_10418_sig3_hex", + "kwsg_10418_state_low24_from_source", + "kwsg_266fc_block", + "legacy_product_ts_sv_payload", + "load_kwsg_10400_tables", + "load_kwsg_10418_sign_tables", + "load_kwsg_10418_tables", + "parse_inner_zt_header", + "parse_dfp_atlas_sign", + "sig", + "sign_dfp_form", + "tokensig", + "tree_values_sorted_non_empty_except_sign", + "xfalcon_digest_hex_from_input_bytes", + "xfalcon_digest_hex_from_input_hex", + "xfalcon_digest_words_from_input_bytes", + "xfalcon_digest_words_from_input_hex", + "xfalcon_folded_block_from_input_bytes", + "xfalcon_folded_block_from_raw_bytes", + "xfalcon_message_words_from_folded_block", + "xfalcon_message_words_from_input_hex", + "xfalcon_packed_block_from_input_hex", + "xfalcon_te_hex_from_input_bytes", + "xfalcon_te_hex_from_input_hex", + "xfalcon_value_from_input_bytes", + "xfalcon_value_from_input_hex", + "zt_outer_unwrap", + "zt_outer_wrap", +] + + +def _self_test() -> None: + assert tokensig("6000aa38bfa87d4bacd329574529f9e2", CLIENT_SALT) == ( + "13a8a7fc2860f9d6da3d878c22b54c010edbefc9aae4aa138ab9293aa342e41b" + ) + assert xfalcon_digest_hex_from_input_hex( + "c29904a53f6a7138ab1d2d4584d24b32a9b8cdeb8ab04ece59e0e2e3f56979b286b5b591fcf0fee8" + ) == "a8651e4eff5a688f80b628fd2d9a255ad7655c772cdc835728dccaf5ee5ef8ab" + print("[OK] core.kwsg compatibility exports verified") + + +if __name__ == "__main__": + _self_test() diff --git a/core/main-vendor-ox-x1_g5.mjs b/core/main-vendor-ox-x1_g5.mjs new file mode 100644 index 0000000..144cc15 --- /dev/null +++ b/core/main-vendor-ox-x1_g5.mjs @@ -0,0 +1,8 @@ +function __vite__mapDeps(indexes) { + if (!__vite__mapDeps.viteFileDeps) { + __vite__mapDeps.viteFileDeps = [window.__assetsPath + 'lib/chunks/lazy-166fdbc3-mTxk8fIQ.js',window.__assetsPath + 'lib/chunks/ua-parser-DFQjJemU.js',window.__assetsPath + 'lib/chunks/main-CZ3ZSK5w.js',window.__assetsPath + 'lib/assets/main-C1ggjLor.css'] + } + return indexes.map((i) => __vite__mapDeps.viteFileDeps[i]) +} +var dn=Object.defineProperty;var hn=(gt,$t,Et)=>$t in gt?dn(gt,$t,{enumerable:!0,configurable:!0,writable:!0,value:Et}):gt[$t]=Et;var _r=(gt,$t,Et)=>(hn(gt,typeof $t!="symbol"?$t+"":$t,Et),Et);import{_ as __vitePreload}from"./main-CZ3ZSK5w.js";var commonjsGlobal=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function getDefaultExportFromCjs(gt){return gt&>.__esModule&&Object.prototype.hasOwnProperty.call(gt,"default")?gt.default:gt}function getAugmentedNamespace(gt){if(gt.__esModule)return gt;var $t=gt.default;if(typeof $t=="function"){var Et=function Tt(){return this instanceof Tt?Reflect.construct($t,arguments,this.constructor):$t.apply(this,arguments)};Et.prototype=$t.prototype}else Et={};return Object.defineProperty(Et,"__esModule",{value:!0}),Object.keys(gt).forEach(function(Tt){var At=Object.getOwnPropertyDescriptor(gt,Tt);Object.defineProperty(Et,Tt,At.get?At:{enumerable:!0,get:function(){return gt[Tt]}})}),Et}var lib$1={exports:{}},_default$1={},lib={exports:{}},_default={};function getDefaultWhiteList$1(){var gt={};return gt["align-content"]=!1,gt["align-items"]=!1,gt["align-self"]=!1,gt["alignment-adjust"]=!1,gt["alignment-baseline"]=!1,gt.all=!1,gt["anchor-point"]=!1,gt.animation=!1,gt["animation-delay"]=!1,gt["animation-direction"]=!1,gt["animation-duration"]=!1,gt["animation-fill-mode"]=!1,gt["animation-iteration-count"]=!1,gt["animation-name"]=!1,gt["animation-play-state"]=!1,gt["animation-timing-function"]=!1,gt.azimuth=!1,gt["backface-visibility"]=!1,gt.background=!0,gt["background-attachment"]=!0,gt["background-clip"]=!0,gt["background-color"]=!0,gt["background-image"]=!0,gt["background-origin"]=!0,gt["background-position"]=!0,gt["background-repeat"]=!0,gt["background-size"]=!0,gt["baseline-shift"]=!1,gt.binding=!1,gt.bleed=!1,gt["bookmark-label"]=!1,gt["bookmark-level"]=!1,gt["bookmark-state"]=!1,gt.border=!0,gt["border-bottom"]=!0,gt["border-bottom-color"]=!0,gt["border-bottom-left-radius"]=!0,gt["border-bottom-right-radius"]=!0,gt["border-bottom-style"]=!0,gt["border-bottom-width"]=!0,gt["border-collapse"]=!0,gt["border-color"]=!0,gt["border-image"]=!0,gt["border-image-outset"]=!0,gt["border-image-repeat"]=!0,gt["border-image-slice"]=!0,gt["border-image-source"]=!0,gt["border-image-width"]=!0,gt["border-left"]=!0,gt["border-left-color"]=!0,gt["border-left-style"]=!0,gt["border-left-width"]=!0,gt["border-radius"]=!0,gt["border-right"]=!0,gt["border-right-color"]=!0,gt["border-right-style"]=!0,gt["border-right-width"]=!0,gt["border-spacing"]=!0,gt["border-style"]=!0,gt["border-top"]=!0,gt["border-top-color"]=!0,gt["border-top-left-radius"]=!0,gt["border-top-right-radius"]=!0,gt["border-top-style"]=!0,gt["border-top-width"]=!0,gt["border-width"]=!0,gt.bottom=!1,gt["box-decoration-break"]=!0,gt["box-shadow"]=!0,gt["box-sizing"]=!0,gt["box-snap"]=!0,gt["box-suppress"]=!0,gt["break-after"]=!0,gt["break-before"]=!0,gt["break-inside"]=!0,gt["caption-side"]=!1,gt.chains=!1,gt.clear=!0,gt.clip=!1,gt["clip-path"]=!1,gt["clip-rule"]=!1,gt.color=!0,gt["color-interpolation-filters"]=!0,gt["column-count"]=!1,gt["column-fill"]=!1,gt["column-gap"]=!1,gt["column-rule"]=!1,gt["column-rule-color"]=!1,gt["column-rule-style"]=!1,gt["column-rule-width"]=!1,gt["column-span"]=!1,gt["column-width"]=!1,gt.columns=!1,gt.contain=!1,gt.content=!1,gt["counter-increment"]=!1,gt["counter-reset"]=!1,gt["counter-set"]=!1,gt.crop=!1,gt.cue=!1,gt["cue-after"]=!1,gt["cue-before"]=!1,gt.cursor=!1,gt.direction=!1,gt.display=!0,gt["display-inside"]=!0,gt["display-list"]=!0,gt["display-outside"]=!0,gt["dominant-baseline"]=!1,gt.elevation=!1,gt["empty-cells"]=!1,gt.filter=!1,gt.flex=!1,gt["flex-basis"]=!1,gt["flex-direction"]=!1,gt["flex-flow"]=!1,gt["flex-grow"]=!1,gt["flex-shrink"]=!1,gt["flex-wrap"]=!1,gt.float=!1,gt["float-offset"]=!1,gt["flood-color"]=!1,gt["flood-opacity"]=!1,gt["flow-from"]=!1,gt["flow-into"]=!1,gt.font=!0,gt["font-family"]=!0,gt["font-feature-settings"]=!0,gt["font-kerning"]=!0,gt["font-language-override"]=!0,gt["font-size"]=!0,gt["font-size-adjust"]=!0,gt["font-stretch"]=!0,gt["font-style"]=!0,gt["font-synthesis"]=!0,gt["font-variant"]=!0,gt["font-variant-alternates"]=!0,gt["font-variant-caps"]=!0,gt["font-variant-east-asian"]=!0,gt["font-variant-ligatures"]=!0,gt["font-variant-numeric"]=!0,gt["font-variant-position"]=!0,gt["font-weight"]=!0,gt.grid=!1,gt["grid-area"]=!1,gt["grid-auto-columns"]=!1,gt["grid-auto-flow"]=!1,gt["grid-auto-rows"]=!1,gt["grid-column"]=!1,gt["grid-column-end"]=!1,gt["grid-column-start"]=!1,gt["grid-row"]=!1,gt["grid-row-end"]=!1,gt["grid-row-start"]=!1,gt["grid-template"]=!1,gt["grid-template-areas"]=!1,gt["grid-template-columns"]=!1,gt["grid-template-rows"]=!1,gt["hanging-punctuation"]=!1,gt.height=!0,gt.hyphens=!1,gt.icon=!1,gt["image-orientation"]=!1,gt["image-resolution"]=!1,gt["ime-mode"]=!1,gt["initial-letters"]=!1,gt["inline-box-align"]=!1,gt["justify-content"]=!1,gt["justify-items"]=!1,gt["justify-self"]=!1,gt.left=!1,gt["letter-spacing"]=!0,gt["lighting-color"]=!0,gt["line-box-contain"]=!1,gt["line-break"]=!1,gt["line-grid"]=!1,gt["line-height"]=!1,gt["line-snap"]=!1,gt["line-stacking"]=!1,gt["line-stacking-ruby"]=!1,gt["line-stacking-shift"]=!1,gt["line-stacking-strategy"]=!1,gt["list-style"]=!0,gt["list-style-image"]=!0,gt["list-style-position"]=!0,gt["list-style-type"]=!0,gt.margin=!0,gt["margin-bottom"]=!0,gt["margin-left"]=!0,gt["margin-right"]=!0,gt["margin-top"]=!0,gt["marker-offset"]=!1,gt["marker-side"]=!1,gt.marks=!1,gt.mask=!1,gt["mask-box"]=!1,gt["mask-box-outset"]=!1,gt["mask-box-repeat"]=!1,gt["mask-box-slice"]=!1,gt["mask-box-source"]=!1,gt["mask-box-width"]=!1,gt["mask-clip"]=!1,gt["mask-image"]=!1,gt["mask-origin"]=!1,gt["mask-position"]=!1,gt["mask-repeat"]=!1,gt["mask-size"]=!1,gt["mask-source-type"]=!1,gt["mask-type"]=!1,gt["max-height"]=!0,gt["max-lines"]=!1,gt["max-width"]=!0,gt["min-height"]=!0,gt["min-width"]=!0,gt["move-to"]=!1,gt["nav-down"]=!1,gt["nav-index"]=!1,gt["nav-left"]=!1,gt["nav-right"]=!1,gt["nav-up"]=!1,gt["object-fit"]=!1,gt["object-position"]=!1,gt.opacity=!1,gt.order=!1,gt.orphans=!1,gt.outline=!1,gt["outline-color"]=!1,gt["outline-offset"]=!1,gt["outline-style"]=!1,gt["outline-width"]=!1,gt.overflow=!1,gt["overflow-wrap"]=!1,gt["overflow-x"]=!1,gt["overflow-y"]=!1,gt.padding=!0,gt["padding-bottom"]=!0,gt["padding-left"]=!0,gt["padding-right"]=!0,gt["padding-top"]=!0,gt.page=!1,gt["page-break-after"]=!1,gt["page-break-before"]=!1,gt["page-break-inside"]=!1,gt["page-policy"]=!1,gt.pause=!1,gt["pause-after"]=!1,gt["pause-before"]=!1,gt.perspective=!1,gt["perspective-origin"]=!1,gt.pitch=!1,gt["pitch-range"]=!1,gt["play-during"]=!1,gt.position=!1,gt["presentation-level"]=!1,gt.quotes=!1,gt["region-fragment"]=!1,gt.resize=!1,gt.rest=!1,gt["rest-after"]=!1,gt["rest-before"]=!1,gt.richness=!1,gt.right=!1,gt.rotation=!1,gt["rotation-point"]=!1,gt["ruby-align"]=!1,gt["ruby-merge"]=!1,gt["ruby-position"]=!1,gt["shape-image-threshold"]=!1,gt["shape-outside"]=!1,gt["shape-margin"]=!1,gt.size=!1,gt.speak=!1,gt["speak-as"]=!1,gt["speak-header"]=!1,gt["speak-numeral"]=!1,gt["speak-punctuation"]=!1,gt["speech-rate"]=!1,gt.stress=!1,gt["string-set"]=!1,gt["tab-size"]=!1,gt["table-layout"]=!1,gt["text-align"]=!0,gt["text-align-last"]=!0,gt["text-combine-upright"]=!0,gt["text-decoration"]=!0,gt["text-decoration-color"]=!0,gt["text-decoration-line"]=!0,gt["text-decoration-skip"]=!0,gt["text-decoration-style"]=!0,gt["text-emphasis"]=!0,gt["text-emphasis-color"]=!0,gt["text-emphasis-position"]=!0,gt["text-emphasis-style"]=!0,gt["text-height"]=!0,gt["text-indent"]=!0,gt["text-justify"]=!0,gt["text-orientation"]=!0,gt["text-overflow"]=!0,gt["text-shadow"]=!0,gt["text-space-collapse"]=!0,gt["text-transform"]=!0,gt["text-underline-position"]=!0,gt["text-wrap"]=!0,gt.top=!1,gt.transform=!1,gt["transform-origin"]=!1,gt["transform-style"]=!1,gt.transition=!1,gt["transition-delay"]=!1,gt["transition-duration"]=!1,gt["transition-property"]=!1,gt["transition-timing-function"]=!1,gt["unicode-bidi"]=!1,gt["vertical-align"]=!1,gt.visibility=!1,gt["voice-balance"]=!1,gt["voice-duration"]=!1,gt["voice-family"]=!1,gt["voice-pitch"]=!1,gt["voice-range"]=!1,gt["voice-rate"]=!1,gt["voice-stress"]=!1,gt["voice-volume"]=!1,gt.volume=!1,gt["white-space"]=!1,gt.widows=!1,gt.width=!0,gt["will-change"]=!1,gt["word-break"]=!0,gt["word-spacing"]=!0,gt["word-wrap"]=!0,gt["wrap-flow"]=!1,gt["wrap-through"]=!1,gt["writing-mode"]=!1,gt["z-index"]=!1,gt}function onAttr(gt,$t,Et){}function onIgnoreAttr(gt,$t,Et){}var REGEXP_URL_JAVASCRIPT=/javascript\s*\:/img;function safeAttrValue$1(gt,$t){return REGEXP_URL_JAVASCRIPT.test($t)?"":$t}_default.whiteList=getDefaultWhiteList$1();_default.getDefaultWhiteList=getDefaultWhiteList$1;_default.onAttr=onAttr;_default.onIgnoreAttr=onIgnoreAttr;_default.safeAttrValue=safeAttrValue$1;var util$1={indexOf:function(gt,$t){var Et,Tt;if(Array.prototype.indexOf)return gt.indexOf($t);for(Et=0,Tt=gt.length;Et/g,REGEXP_QUOTE=/"/g,REGEXP_QUOTE_2=/"/g,REGEXP_ATTR_VALUE_1=/&#([a-zA-Z0-9]*);?/gim,REGEXP_ATTR_VALUE_COLON=/:?/gim,REGEXP_ATTR_VALUE_NEWLINE=/&newline;?/gim,REGEXP_DEFAULT_ON_TAG_ATTR_4=/((j\s*a\s*v\s*a|v\s*b|l\s*i\s*v\s*e)\s*s\s*c\s*r\s*i\s*p\s*t\s*|m\s*o\s*c\s*h\s*a)\:/gi,REGEXP_DEFAULT_ON_TAG_ATTR_7=/e\s*x\s*p\s*r\s*e\s*s\s*s\s*i\s*o\s*n\s*\(.*/gi,REGEXP_DEFAULT_ON_TAG_ATTR_8=/u\s*r\s*l\s*\(.*/gi;function escapeQuote(gt){return gt.replace(REGEXP_QUOTE,""")}function unescapeQuote(gt){return gt.replace(REGEXP_QUOTE_2,'"')}function escapeHtmlEntities(gt){return gt.replace(REGEXP_ATTR_VALUE_1,function(Et,Tt){return Tt[0]==="x"||Tt[0]==="X"?String.fromCharCode(parseInt(Tt.substr(1),16)):String.fromCharCode(parseInt(Tt,10))})}function escapeDangerHtml5Entities(gt){return gt.replace(REGEXP_ATTR_VALUE_COLON,":").replace(REGEXP_ATTR_VALUE_NEWLINE," ")}function clearNonPrintableCharacter(gt){for(var $t="",Et=0,Tt=gt.length;Et",Tt);if(At===-1)break;Et=At+3}return $t}function stripBlankChar(gt){var $t=gt.split("");return $t=$t.filter(function(Et){var Tt=Et.charCodeAt(0);return Tt===127?!1:Tt<=31?Tt===10||Tt===13:!0}),$t.join("")}function getStyleAttrDefaultWhiteList(){var gt={};return gt["align-content"]=!0,gt["align-items"]=!0,gt["align-self"]=!0,gt["alignment-adjust"]=!0,gt["alignment-baseline"]=!0,gt.all=!1,gt["anchor-point"]=!1,gt.animation=!0,gt["animation-delay"]=!0,gt["animation-direction"]=!0,gt["animation-duration"]=!0,gt["animation-fill-mode"]=!0,gt["animation-iteration-count"]=!0,gt["animation-name"]=!0,gt["animation-play-state"]=!0,gt["animation-timing-function"]=!0,gt.azimuth=!1,gt["backface-visibility"]=!1,gt.background=!0,gt["background-attachment"]=!0,gt["background-clip"]=!0,gt["background-color"]=!0,gt["background-image"]=!0,gt["background-origin"]=!0,gt["background-position"]=!0,gt["background-repeat"]=!0,gt["background-size"]=!0,gt["baseline-shift"]=!1,gt.binding=!1,gt.bleed=!1,gt["bookmark-label"]=!1,gt["bookmark-level"]=!1,gt["bookmark-state"]=!1,gt.border=!0,gt["border-bottom"]=!0,gt["border-bottom-color"]=!0,gt["border-bottom-left-radius"]=!0,gt["border-bottom-right-radius"]=!0,gt["border-bottom-style"]=!0,gt["border-bottom-width"]=!0,gt["border-collapse"]=!0,gt["border-color"]=!0,gt["border-image"]=!0,gt["border-image-outset"]=!0,gt["border-image-repeat"]=!0,gt["border-image-slice"]=!0,gt["border-image-source"]=!0,gt["border-image-width"]=!0,gt["border-left"]=!0,gt["border-left-color"]=!0,gt["border-left-style"]=!0,gt["border-left-width"]=!0,gt["border-radius"]=!0,gt["border-right"]=!0,gt["border-right-color"]=!0,gt["border-right-style"]=!0,gt["border-right-width"]=!0,gt["border-spacing"]=!0,gt["border-style"]=!0,gt["border-top"]=!0,gt["border-top-color"]=!0,gt["border-top-left-radius"]=!0,gt["border-top-right-radius"]=!0,gt["border-top-style"]=!0,gt["border-top-width"]=!0,gt["border-width"]=!0,gt.bottom=!0,gt["box-decoration-break"]=!0,gt["box-shadow"]=!0,gt["box-sizing"]=!0,gt["box-snap"]=!0,gt["box-suppress"]=!0,gt["break-after"]=!0,gt["break-before"]=!0,gt["break-inside"]=!0,gt["caption-side"]=!1,gt.chains=!1,gt.clear=!0,gt.clip=!1,gt["clip-path"]=!1,gt["clip-rule"]=!1,gt.color=!0,gt["color-interpolation-filters"]=!0,gt["column-count"]=!1,gt["column-fill"]=!1,gt["column-gap"]=!0,gt.gap=!0,gt["column-rule"]=!1,gt["column-rule-color"]=!1,gt["column-rule-style"]=!1,gt["column-rule-width"]=!1,gt["column-span"]=!1,gt["column-width"]=!1,gt.columns=!1,gt.contain=!1,gt.content=!1,gt["counter-increment"]=!1,gt["counter-reset"]=!1,gt["counter-set"]=!1,gt.crop=!1,gt.cue=!1,gt["cue-after"]=!1,gt["cue-before"]=!1,gt.cursor=!0,gt.direction=!0,gt.display=!0,gt["display-inside"]=!0,gt["display-list"]=!0,gt["display-outside"]=!0,gt["dominant-baseline"]=!1,gt.elevation=!1,gt["empty-cells"]=!1,gt.filter=!0,gt.flex=!0,gt["flex-basis"]=!0,gt["flex-direction"]=!0,gt["flex-flow"]=!0,gt["flex-grow"]=!0,gt["flex-shrink"]=!0,gt["flex-wrap"]=!0,gt.float=!0,gt["float-offset"]=!0,gt["flood-color"]=!1,gt["flood-opacity"]=!1,gt["flow-from"]=!1,gt["flow-into"]=!1,gt.font=!0,gt["font-family"]=!0,gt["font-feature-settings"]=!0,gt["font-kerning"]=!0,gt["font-language-override"]=!0,gt["font-size"]=!0,gt["font-size-adjust"]=!0,gt["font-stretch"]=!0,gt["font-style"]=!0,gt["font-synthesis"]=!0,gt["font-variant"]=!0,gt["font-variant-alternates"]=!0,gt["font-variant-caps"]=!0,gt["font-variant-east-asian"]=!0,gt["font-variant-ligatures"]=!0,gt["font-variant-numeric"]=!0,gt["font-variant-position"]=!0,gt["font-weight"]=!0,gt.grid=!1,gt["grid-area"]=!1,gt["grid-auto-columns"]=!1,gt["grid-auto-flow"]=!1,gt["grid-auto-rows"]=!1,gt["grid-column"]=!1,gt["grid-column-end"]=!1,gt["grid-column-start"]=!1,gt["grid-row"]=!1,gt["grid-row-end"]=!1,gt["grid-row-start"]=!1,gt["grid-template"]=!1,gt["grid-template-areas"]=!1,gt["grid-template-columns"]=!1,gt["grid-template-rows"]=!1,gt["hanging-punctuation"]=!1,gt.height=!0,gt.hyphens=!1,gt.icon=!1,gt["image-orientation"]=!1,gt["image-resolution"]=!1,gt["ime-mode"]=!1,gt["initial-letters"]=!1,gt["inline-box-align"]=!1,gt["justify-content"]=!0,gt["justify-items"]=!0,gt["justify-self"]=!0,gt.left=!0,gt["letter-spacing"]=!0,gt["lighting-color"]=!0,gt["line-box-contain"]=!1,gt["line-break"]=!1,gt["line-grid"]=!1,gt["line-height"]=!1,gt["line-snap"]=!1,gt["line-stacking"]=!1,gt["line-stacking-ruby"]=!1,gt["line-stacking-shift"]=!1,gt["line-stacking-strategy"]=!1,gt["list-style"]=!0,gt["list-style-image"]=!0,gt["list-style-position"]=!0,gt["list-style-type"]=!0,gt.margin=!0,gt["margin-bottom"]=!0,gt["margin-left"]=!0,gt["margin-right"]=!0,gt["margin-top"]=!0,gt["marker-offset"]=!1,gt["marker-side"]=!1,gt.marks=!1,gt.mask=!1,gt["mask-box"]=!1,gt["mask-box-outset"]=!1,gt["mask-box-repeat"]=!1,gt["mask-box-slice"]=!1,gt["mask-box-source"]=!1,gt["mask-box-width"]=!1,gt["mask-clip"]=!1,gt["mask-image"]=!1,gt["mask-origin"]=!1,gt["mask-position"]=!1,gt["mask-repeat"]=!1,gt["mask-size"]=!1,gt["mask-source-type"]=!1,gt["mask-type"]=!1,gt["max-height"]=!0,gt["max-lines"]=!1,gt["max-width"]=!0,gt["min-height"]=!0,gt["min-width"]=!0,gt["move-to"]=!1,gt["nav-down"]=!1,gt["nav-index"]=!1,gt["nav-left"]=!1,gt["nav-right"]=!1,gt["nav-up"]=!1,gt["object-fit"]=!0,gt["object-position"]=!0,gt.opacity=!0,gt.order=!0,gt.orphans=!1,gt.outline=!1,gt["outline-color"]=!1,gt["outline-offset"]=!1,gt["outline-style"]=!1,gt["outline-width"]=!1,gt.overflow=!0,gt["overflow-wrap"]=!0,gt["overflow-x"]=!0,gt["overflow-y"]=!0,gt.padding=!0,gt["padding-bottom"]=!0,gt["padding-left"]=!0,gt["padding-right"]=!0,gt["padding-top"]=!0,gt.page=!1,gt["page-break-after"]=!1,gt["page-break-before"]=!1,gt["page-break-inside"]=!1,gt["page-policy"]=!1,gt.pause=!1,gt["pause-after"]=!1,gt["pause-before"]=!1,gt.perspective=!1,gt["perspective-origin"]=!1,gt.pitch=!1,gt["pitch-range"]=!1,gt["play-during"]=!1,gt.position=!0,gt["presentation-level"]=!1,gt.quotes=!1,gt["region-fragment"]=!1,gt.resize=!0,gt.rest=!1,gt["rest-after"]=!1,gt["rest-before"]=!1,gt.richness=!1,gt.right=!0,gt.rotation=!1,gt["rotation-point"]=!1,gt["ruby-align"]=!1,gt["ruby-merge"]=!1,gt["ruby-position"]=!1,gt["shape-image-threshold"]=!1,gt["shape-outside"]=!1,gt["shape-margin"]=!1,gt.size=!1,gt.speak=!1,gt["speak-as"]=!1,gt["speak-header"]=!1,gt["speak-numeral"]=!1,gt["speak-punctuation"]=!1,gt["speech-rate"]=!1,gt.stress=!1,gt["string-set"]=!1,gt["tab-size"]=!1,gt["table-layout"]=!1,gt["text-align"]=!0,gt["text-align-last"]=!0,gt["text-combine-upright"]=!0,gt["text-decoration"]=!0,gt["text-decoration-color"]=!0,gt["text-decoration-line"]=!0,gt["text-decoration-skip"]=!0,gt["text-decoration-style"]=!0,gt["text-emphasis"]=!0,gt["text-emphasis-color"]=!0,gt["text-emphasis-position"]=!0,gt["text-emphasis-style"]=!0,gt["text-height"]=!0,gt["text-indent"]=!0,gt["text-justify"]=!0,gt["text-orientation"]=!0,gt["text-overflow"]=!0,gt["text-shadow"]=!0,gt["text-space-collapse"]=!0,gt["text-transform"]=!0,gt["text-underline-position"]=!0,gt["text-wrap"]=!0,gt.top=!0,gt.transform=!0,gt["transform-origin"]=!0,gt["transform-style"]=!0,gt.transition=!0,gt["transition-delay"]=!0,gt["transition-duration"]=!0,gt["transition-property"]=!0,gt["transition-timing-function"]=!1,gt["unicode-bidi"]=!1,gt["vertical-align"]=!0,gt.visibility=!0,gt["voice-balance"]=!1,gt["voice-duration"]=!1,gt["voice-family"]=!1,gt["voice-pitch"]=!1,gt["voice-range"]=!1,gt["voice-rate"]=!1,gt["voice-stress"]=!1,gt["voice-volume"]=!1,gt.volume=!1,gt["white-space"]=!1,gt.widows=!1,gt.width=!0,gt["will-change"]=!1,gt["word-break"]=!0,gt["word-spacing"]=!0,gt["word-wrap"]=!0,gt["wrap-flow"]=!1,gt["wrap-through"]=!1,gt["writing-mode"]=!1,gt["z-index"]=!0,gt}_default$1.whiteList=getDefaultWhiteList();_default$1.getDefaultWhiteList=getDefaultWhiteList;_default$1.onTag=onTag;_default$1.onIgnoreTag=onIgnoreTag;_default$1.onTagAttr=onTagAttr;_default$1.onIgnoreTagAttr=onIgnoreTagAttr;_default$1.safeAttrValue=safeAttrValue;_default$1.escapeHtml=escapeHtml;_default$1.escapeQuote=escapeQuote;_default$1.unescapeQuote=unescapeQuote;_default$1.escapeHtmlEntities=escapeHtmlEntities;_default$1.escapeDangerHtml5Entities=escapeDangerHtml5Entities;_default$1.clearNonPrintableCharacter=clearNonPrintableCharacter;_default$1.friendlyAttrValue=friendlyAttrValue;_default$1.escapeAttrValue=escapeAttrValue;_default$1.onIgnoreTagStripAll=onIgnoreTagStripAll;_default$1.StripTagBody=StripTagBody;_default$1.stripCommentTag=stripCommentTag;_default$1.stripBlankChar=stripBlankChar;_default$1.cssFilter=defaultCSSFilter;_default$1.getDefaultCSSWhiteList=getDefaultCSSWhiteList;_default$1.styleAttrWhiteList=getStyleAttrDefaultWhiteList();var parser$1={},_$a=util;function getTagName(gt){var $t=_$a.spaceIndex(gt);if($t===-1)var Et=gt.slice(1,-1);else var Et=gt.slice(1,$t+1);return Et=_$a.trim(Et).toLowerCase(),Et.slice(0,1)==="/"&&(Et=Et.slice(1)),Et.slice(-1)==="/"&&(Et=Et.slice(0,-1)),Et}function isClosing(gt){return gt.slice(0,2)===""){Tt+=Et(gt.slice(At,Ct)),Dt=gt.slice(Ct,It+1),Ut=getTagName(Dt),Tt+=$t(Ct,Tt.length,Ut,Dt,isClosing(Dt)),At=It+1,Ct=!1;continue}if(Mt==='"'||Mt==="'")for(var Ft=1,Bt=gt.charAt(It-Ft);Bt.trim()===""||Bt==="=";){if(Bt==="="){Pt=Mt;continue e}Bt=gt.charAt(It-++Ft)}}else if(Mt===Pt){Pt=!1;continue}}return At0;$t--){var Et=gt[$t];if(Et!==" ")return Et==="="?$t:-1}}function isQuoteWrapString(gt){return gt[0]==='"'&>[gt.length-1]==='"'||gt[0]==="'"&>[gt.length-1]==="'"}function stripQuoteWrap(gt){return isQuoteWrapString(gt)?gt.substr(1,gt.length-2):gt}parser$1.parseTag=parseTag$1;parser$1.parseAttr=parseAttr$1;var FilterCSS=libExports$1.FilterCSS,DEFAULT=_default$1,parser=parser$1,parseTag=parser.parseTag,parseAttr=parser.parseAttr,_$9=util;function isNull(gt){return gt==null}function getAttrs(gt){var $t=_$9.spaceIndex(gt);if($t===-1)return{html:"",closing:gt[gt.length-2]==="/"};gt=_$9.trim(gt.slice($t+1,-1));var Et=gt[gt.length-1]==="/";return Et&&(gt=_$9.trim(gt.slice(0,-1))),{html:gt,closing:Et}}function shallowCopyObject(gt){var $t={};for(var Et in gt)$t[Et]=gt[Et];return $t}function FilterXSS(gt){gt=shallowCopyObject(gt||{}),gt.stripIgnoreTag&&(gt.onIgnoreTag&&console.error('Notes: cannot use these two options "stripIgnoreTag" and "onIgnoreTag" at the same time'),gt.onIgnoreTag=DEFAULT.onIgnoreTagStripAll),gt.whiteList=Object.assign({},DEFAULT.whiteList,gt.whiteList),gt.onTag=gt.onTag||DEFAULT.onTag,gt.onTagAttr=gt.onTagAttr||DEFAULT.onTagAttr,gt.onIgnoreTag=gt.onIgnoreTag||DEFAULT.onIgnoreTag,gt.onIgnoreTagAttr=gt.onIgnoreTagAttr||DEFAULT.onIgnoreTagAttr,gt.safeAttrValue=gt.safeAttrValue||DEFAULT.safeAttrValue,gt.escapeHtml=gt.escapeHtml||DEFAULT.escapeHtml,this.options=gt,gt.css===!1?this.cssFilter=!1:(gt.css=gt.css||{whiteList:DEFAULT.styleAttrWhiteList},this.cssFilter=new FilterCSS(gt.css))}FilterXSS.prototype.process=function(gt){if(gt=gt||"",gt=gt.toString(),!gt)return"";var $t=this,Et=$t.options,Tt=Et.whiteList,At=Et.onTag,Ct=Et.onIgnoreTag,Pt=Et.onTagAttr,It=Et.onIgnoreTagAttr,Nt=Et.safeAttrValue,Ut=Et.escapeHtml,Dt=$t.cssFilter;Et.stripBlankChar&&(gt=DEFAULT.stripBlankChar(gt)),Et.allowCommentTag||(gt=DEFAULT.stripCommentTag(gt));var Mt=!1;if(Et.stripIgnoreTagBody){var Mt=DEFAULT.StripTagBody(Et.stripIgnoreTagBody,Ct);Ct=Mt.onIgnoreTag}var Ft=parseTag(gt,function(Bt,Gt,Vt,Ht,Wt){var Kt={sourcePosition:Bt,position:Gt,isClosing:Wt,isWhite:Tt.hasOwnProperty(Vt)},qt=At(Vt,Ht,Kt);if(!isNull(qt))return qt;if(Kt.isWhite){if(Kt.isClosing)return"";var Jt=getAttrs(Ht),Xt=Tt[Vt],Zt=parseAttr(Jt.html,function(tr,Qt){var zt=_$9.indexOf(Xt,tr)!==-1,nr=Pt(Vt,tr,Qt,zt);if(!isNull(nr))return nr;if(zt)return Qt=Nt(Vt,tr,Qt,Dt),Qt?tr+'="'+Qt+'"':tr;var nr=It(Vt,tr,Qt,zt);return isNull(nr)?void 0:nr}),Ht="<"+Vt;return Zt&&(Ht+=" "+Zt),Jt.closing&&(Ht+=" /"),Ht+=">",Ht}else{var qt=Ct(Vt,Ht,Kt);return isNull(qt)?Ut(Ht):qt}},Ut);return Mt&&(Ft=Mt.remove(Ft)),Ft};var xss$1=FilterXSS;(function(gt,$t){var Et=_default$1,Tt=parser$1,At=xss$1;function Ct(Nt,Ut){var Dt=new At(Ut);return Dt.process(Nt)}$t=gt.exports=Ct,$t.filterXSS=Ct,$t.FilterXSS=At;for(var Pt in Et)$t[Pt]=Et[Pt];for(var Pt in Tt)$t[Pt]=Tt[Pt];typeof window<"u"&&(window.filterXSS=gt.exports);function It(){return typeof self<"u"&&typeof DedicatedWorkerGlobalScope<"u"&&self instanceof DedicatedWorkerGlobalScope}It()&&(self.filterXSS=gt.exports)})(lib$1,lib$1.exports);var libExports=lib$1.exports;const xss=getDefaultExportFromCjs(libExports);var define_global_process_env_default={};var emptyObject=Object.freeze({}),isArray=Array.isArray;function isUndef(gt){return gt==null}function isDef$1(gt){return gt!=null}function isTrue(gt){return gt===!0}function isFalse(gt){return gt===!1}function isPrimitive(gt){return typeof gt=="string"||typeof gt=="number"||typeof gt=="symbol"||typeof gt=="boolean"}function isFunction$2(gt){return typeof gt=="function"}function isObject$4(gt){return gt!==null&&typeof gt=="object"}var _toString=Object.prototype.toString;function toRawType(gt){return _toString.call(gt).slice(8,-1)}function isPlainObject(gt){return _toString.call(gt)==="[object Object]"}function isRegExp(gt){return _toString.call(gt)==="[object RegExp]"}function isValidArrayIndex(gt){var $t=parseFloat(String(gt));return $t>=0&&Math.floor($t)===$t&&isFinite(gt)}function isPromise$1(gt){return isDef$1(gt)&&typeof gt.then=="function"&&typeof gt.catch=="function"}function toString(gt){return gt==null?"":Array.isArray(gt)||isPlainObject(gt)&>.toString===_toString?JSON.stringify(gt,null,2):String(gt)}function toNumber$2(gt){var $t=parseFloat(gt);return isNaN($t)?gt:$t}function makeMap(gt,$t){for(var Et=Object.create(null),Tt=gt.split(","),At=0;At-1)return gt.splice(Tt,1)}}var hasOwnProperty$2=Object.prototype.hasOwnProperty;function hasOwn(gt,$t){return hasOwnProperty$2.call(gt,$t)}function cached(gt){var $t=Object.create(null);return function(Tt){var At=$t[Tt];return At||($t[Tt]=gt(Tt))}}var camelizeRE=/-(\w)/g,camelize=cached(function(gt){return gt.replace(camelizeRE,function($t,Et){return Et?Et.toUpperCase():""})}),capitalize=cached(function(gt){return gt.charAt(0).toUpperCase()+gt.slice(1)}),hyphenateRE=/\B([A-Z])/g,hyphenate=cached(function(gt){return gt.replace(hyphenateRE,"-$1").toLowerCase()});function polyfillBind(gt,$t){function Et(Tt){var At=arguments.length;return At?At>1?gt.apply($t,arguments):gt.call($t,Tt):gt.call($t)}return Et._length=gt.length,Et}function nativeBind(gt,$t){return gt.bind($t)}var bind$1=Function.prototype.bind?nativeBind:polyfillBind;function toArray(gt,$t){$t=$t||0;for(var Et=gt.length-$t,Tt=new Array(Et);Et--;)Tt[Et]=gt[Et+$t];return Tt}function extend$1(gt,$t){for(var Et in $t)gt[Et]=$t[Et];return gt}function toObject(gt){for(var $t={},Et=0;Et0,isEdge=UA&&UA.indexOf("edge/")>0;UA&&UA.indexOf("android")>0;var isIOS$1=UA&&/iphone|ipad|ipod|ios/.test(UA),isFF=UA&&UA.match(/firefox\/(\d+)/),nativeWatch={}.watch,supportsPassive=!1;if(inBrowser$1)try{var opts={};Object.defineProperty(opts,"passive",{get:function(){supportsPassive=!0}}),window.addEventListener("test-passive",null,opts)}catch(gt){}var _isServer,isServerRendering=function(){return _isServer===void 0&&(!inBrowser$1&&typeof global<"u"?_isServer=global.process&&define_global_process_env_default.VUE_ENV==="server":_isServer=!1),_isServer},devtools=inBrowser$1&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function isNative(gt){return typeof gt=="function"&&/native code/.test(gt.toString())}var hasSymbol=typeof Symbol<"u"&&isNative(Symbol)&&typeof Reflect<"u"&&isNative(Reflect.ownKeys),_Set;typeof Set<"u"&&isNative(Set)?_Set=Set:_Set=function(){function gt(){this.set=Object.create(null)}return gt.prototype.has=function($t){return this.set[$t]===!0},gt.prototype.add=function($t){this.set[$t]=!0},gt.prototype.clear=function(){this.set=Object.create(null)},gt}();var currentInstance=null;function getCurrentInstance(){return currentInstance&&{proxy:currentInstance}}function setCurrentInstance(gt){gt===void 0&&(gt=null),gt||currentInstance&¤tInstance._scope.off(),currentInstance=gt,gt&>._scope.on()}var VNode=function(){function gt($t,Et,Tt,At,Ct,Pt,It,Nt){this.tag=$t,this.data=Et,this.children=Tt,this.text=At,this.elm=Ct,this.ns=void 0,this.context=Pt,this.fnContext=void 0,this.fnOptions=void 0,this.fnScopeId=void 0,this.key=Et&&Et.key,this.componentOptions=It,this.componentInstance=void 0,this.parent=void 0,this.raw=!1,this.isStatic=!1,this.isRootInsert=!0,this.isComment=!1,this.isCloned=!1,this.isOnce=!1,this.asyncFactory=Nt,this.asyncMeta=void 0,this.isAsyncPlaceholder=!1}return Object.defineProperty(gt.prototype,"child",{get:function(){return this.componentInstance},enumerable:!1,configurable:!0}),gt}(),createEmptyVNode=function(gt){gt===void 0&&(gt="");var $t=new VNode;return $t.text=gt,$t.isComment=!0,$t};function createTextVNode(gt){return new VNode(void 0,void 0,void 0,String(gt))}function cloneVNode(gt){var $t=new VNode(gt.tag,gt.data,gt.children&>.children.slice(),gt.text,gt.elm,gt.context,gt.componentOptions,gt.asyncFactory);return $t.ns=gt.ns,$t.isStatic=gt.isStatic,$t.key=gt.key,$t.isComment=gt.isComment,$t.fnContext=gt.fnContext,$t.fnOptions=gt.fnOptions,$t.fnScopeId=gt.fnScopeId,$t.asyncMeta=gt.asyncMeta,$t.isCloned=!0,$t}var uid$2=0,pendingCleanupDeps=[],cleanupDeps=function(){for(var gt=0;gt0&&(At=normalizeArrayChildren(At,"".concat($t||"","_").concat(Tt)),isTextNode(At[0])&&isTextNode(Pt)&&(Et[Ct]=createTextVNode(Pt.text+At[0].text),At.shift()),Et.push.apply(Et,At)):isPrimitive(At)?isTextNode(Pt)?Et[Ct]=createTextVNode(Pt.text+At):At!==""&&Et.push(createTextVNode(At)):isTextNode(At)&&isTextNode(Pt)?Et[Ct]=createTextVNode(Pt.text+At.text):(isTrue(gt._isVList)&&isDef$1(At.tag)&&isUndef(At.key)&&isDef$1($t)&&(At.key="__vlist".concat($t,"_").concat(Tt,"__")),Et.push(At)));return Et}var SIMPLE_NORMALIZE=1,ALWAYS_NORMALIZE=2;function createElement$1(gt,$t,Et,Tt,At,Ct){return(isArray(Et)||isPrimitive(Et))&&(At=Tt,Tt=Et,Et=void 0),isTrue(Ct)&&(At=ALWAYS_NORMALIZE),_createElement(gt,$t,Et,Tt,At)}function _createElement(gt,$t,Et,Tt,At){if(isDef$1(Et)&&isDef$1(Et.__ob__)||(isDef$1(Et)&&isDef$1(Et.is)&&($t=Et.is),!$t))return createEmptyVNode();isArray(Tt)&&isFunction$2(Tt[0])&&(Et=Et||{},Et.scopedSlots={default:Tt[0]},Tt.length=0),At===ALWAYS_NORMALIZE?Tt=normalizeChildren(Tt):At===SIMPLE_NORMALIZE&&(Tt=simpleNormalizeChildren(Tt));var Ct,Pt;if(typeof $t=="string"){var It=void 0;Pt=gt.$vnode&>.$vnode.ns||config$2.getTagNamespace($t),config$2.isReservedTag($t)?Ct=new VNode(config$2.parsePlatformTagName($t),Et,Tt,void 0,void 0,gt):(!Et||!Et.pre)&&isDef$1(It=resolveAsset(gt.$options,"components",$t))?Ct=createComponent(It,Et,gt,Tt,$t):Ct=new VNode($t,Et,Tt,void 0,void 0,gt)}else Ct=createComponent($t,Et,gt,Tt);return isArray(Ct)?Ct:isDef$1(Ct)?(isDef$1(Pt)&&applyNS(Ct,Pt),isDef$1(Et)&®isterDeepBindings(Et),Ct):createEmptyVNode()}function applyNS(gt,$t,Et){if(gt.ns=$t,gt.tag==="foreignObject"&&($t=void 0,Et=!0),isDef$1(gt.children))for(var Tt=0,At=gt.children.length;Tt0,Pt=$t?!!$t.$stable:!Ct,It=$t&&$t.$key;if(!$t)At={};else{if($t._normalized)return $t._normalized;if(Pt&&Tt&&Tt!==emptyObject&&It===Tt.$key&&!Ct&&!Tt.$hasNormal)return Tt;At={};for(var Nt in $t)$t[Nt]&&Nt[0]!=="$"&&(At[Nt]=normalizeScopedSlot(gt,Et,Nt,$t[Nt]))}for(var Ut in Et)Ut in At||(At[Ut]=proxyNormalSlot(Et,Ut));return $t&&Object.isExtensible($t)&&($t._normalized=At),def(At,"$stable",Pt),def(At,"$key",It),def(At,"$hasNormal",Ct),At}function normalizeScopedSlot(gt,$t,Et,Tt){var At=function(){var Ct=currentInstance;setCurrentInstance(gt);var Pt=arguments.length?Tt.apply(null,arguments):Tt({});Pt=Pt&&typeof Pt=="object"&&!isArray(Pt)?[Pt]:normalizeChildren(Pt);var It=Pt&&Pt[0];return setCurrentInstance(Ct),Pt&&(!It||Pt.length===1&&It.isComment&&!isAsyncPlaceholder(It))?void 0:Pt};return Tt.proxy&&Object.defineProperty($t,Et,{get:At,enumerable:!0,configurable:!0}),At}function proxyNormalSlot(gt,$t){return function(){return gt[$t]}}function initSetup(gt){var $t=gt.$options,Et=$t.setup;if(Et){var Tt=gt._setupContext=createSetupContext(gt);setCurrentInstance(gt),pushTarget();var At=invokeWithErrorHandling(Et,null,[gt._props||shallowReactive({}),Tt],gt,"setup");if(popTarget(),setCurrentInstance(),isFunction$2(At))$t.render=At;else if(isObject$4(At))if(gt._setupState=At,At.__sfc){var Pt=gt._setupProxy={};for(var Ct in At)Ct!=="__sfc"&&proxyWithRefUnwrap(Pt,At,Ct)}else for(var Ct in At)isReserved(Ct)||proxyWithRefUnwrap(gt,At,Ct)}}function createSetupContext(gt){return{get attrs(){if(!gt._attrsProxy){var $t=gt._attrsProxy={};def($t,"_v_attr_proxy",!0),syncSetupProxy($t,gt.$attrs,emptyObject,gt,"$attrs")}return gt._attrsProxy},get listeners(){if(!gt._listenersProxy){var $t=gt._listenersProxy={};syncSetupProxy($t,gt.$listeners,emptyObject,gt,"$listeners")}return gt._listenersProxy},get slots(){return initSlotsProxy(gt)},emit:bind$1(gt.$emit,gt),expose:function($t){$t&&Object.keys($t).forEach(function(Et){return proxyWithRefUnwrap(gt,$t,Et)})}}}function syncSetupProxy(gt,$t,Et,Tt,At){var Ct=!1;for(var Pt in $t)Pt in gt?$t[Pt]!==Et[Pt]&&(Ct=!0):(Ct=!0,defineProxyAttr(gt,Pt,Tt,At));for(var Pt in gt)Pt in $t||(Ct=!0,delete gt[Pt]);return Ct}function defineProxyAttr(gt,$t,Et,Tt){Object.defineProperty(gt,$t,{enumerable:!0,configurable:!0,get:function(){return Et[Tt][$t]}})}function initSlotsProxy(gt){return gt._slotsProxy||syncSetupSlots(gt._slotsProxy={},gt.$scopedSlots),gt._slotsProxy}function syncSetupSlots(gt,$t){for(var Et in $t)gt[Et]=$t[Et];for(var Et in gt)Et in $t||delete gt[Et]}function useSlots(){return getContext$1().slots}function useAttrs(){return getContext$1().attrs}function useListeners(){return getContext$1().listeners}function getContext$1(){var gt=currentInstance;return gt._setupContext||(gt._setupContext=createSetupContext(gt))}function mergeDefaults(gt,$t){var Et=isArray(gt)?gt.reduce(function(Ct,Pt){return Ct[Pt]={},Ct},{}):gt;for(var Tt in $t){var At=Et[Tt];At?isArray(At)||isFunction$2(At)?Et[Tt]={type:At,default:$t[Tt]}:At.default=$t[Tt]:At===null&&(Et[Tt]={default:$t[Tt]})}return Et}function initRender(gt){gt._vnode=null,gt._staticTrees=null;var $t=gt.$options,Et=gt.$vnode=$t._parentVnode,Tt=Et&&Et.context;gt.$slots=resolveSlots($t._renderChildren,Tt),gt.$scopedSlots=Et?normalizeScopedSlots(gt.$parent,Et.data.scopedSlots,gt.$slots):emptyObject,gt._c=function(Ct,Pt,It,Nt){return createElement$1(gt,Ct,Pt,It,Nt,!1)},gt.$createElement=function(Ct,Pt,It,Nt){return createElement$1(gt,Ct,Pt,It,Nt,!0)};var At=Et&&Et.data;defineReactive(gt,"$attrs",At&&At.attrs||emptyObject,null,!0),defineReactive(gt,"$listeners",$t._parentListeners||emptyObject,null,!0)}var currentRenderingInstance=null;function renderMixin(gt){installRenderHelpers(gt.prototype),gt.prototype.$nextTick=function($t){return nextTick($t,this)},gt.prototype._render=function(){var $t=this,Et=$t.$options,Tt=Et.render,At=Et._parentVnode;At&&$t._isMounted&&($t.$scopedSlots=normalizeScopedSlots($t.$parent,At.data.scopedSlots,$t.$slots,$t.$scopedSlots),$t._slotsProxy&&syncSetupSlots($t._slotsProxy,$t.$scopedSlots)),$t.$vnode=At;var Ct;try{setCurrentInstance($t),currentRenderingInstance=$t,Ct=Tt.call($t._renderProxy,$t.$createElement)}catch(Pt){handleError(Pt,$t,"render"),Ct=$t._vnode}finally{currentRenderingInstance=null,setCurrentInstance()}return isArray(Ct)&&Ct.length===1&&(Ct=Ct[0]),Ct instanceof VNode||(Ct=createEmptyVNode()),Ct.parent=At,Ct}}function ensureCtor(gt,$t){return(gt.__esModule||hasSymbol&>[Symbol.toStringTag]==="Module")&&(gt=gt.default),isObject$4(gt)?$t.extend(gt):gt}function createAsyncPlaceholder(gt,$t,Et,Tt,At){var Ct=createEmptyVNode();return Ct.asyncFactory=gt,Ct.asyncMeta={data:$t,context:Et,children:Tt,tag:At},Ct}function resolveAsyncComponent(gt,$t){if(isTrue(gt.error)&&isDef$1(gt.errorComp))return gt.errorComp;if(isDef$1(gt.resolved))return gt.resolved;var Et=currentRenderingInstance;if(Et&&isDef$1(gt.owners)&>.owners.indexOf(Et)===-1&>.owners.push(Et),isTrue(gt.loading)&&isDef$1(gt.loadingComp))return gt.loadingComp;if(Et&&!isDef$1(gt.owners)){var Tt=gt.owners=[Et],At=!0,Ct=null,Pt=null;Et.$on("hook:destroyed",function(){return remove$2(Tt,Et)});var It=function(Mt){for(var Ft=0,Bt=Tt.length;Ft1?toArray(At):At;for(var Ct=toArray(arguments,1),Pt='event handler for "'.concat(Et,'"'),It=0,Nt=At.length;Itdocument.createEvent("Event").timeStamp&&(getNow=function(){return performance_1.now()})}var sortCompareFn=function(gt,$t){if(gt.post){if(!$t.post)return 1}else if($t.post)return-1;return gt.id-$t.id};function flushSchedulerQueue(){currentFlushTimestamp=getNow(),flushing=!0;var gt,$t;for(queue.sort(sortCompareFn),index$1=0;index$1index$1&&queue[Et].id>gt.id;)Et--;queue.splice(Et+1,0,gt)}waiting||(waiting=!0,nextTick(flushSchedulerQueue))}}var WATCHER="watcher",WATCHER_CB="".concat(WATCHER," callback"),WATCHER_GETTER="".concat(WATCHER," getter"),WATCHER_CLEANUP="".concat(WATCHER," cleanup");function watchEffect(gt,$t){return doWatch(gt,null,$t)}function watchPostEffect(gt,$t){return doWatch(gt,null,{flush:"post"})}function watchSyncEffect(gt,$t){return doWatch(gt,null,{flush:"sync"})}var INITIAL_WATCHER_VALUE={};function watch(gt,$t,Et){return doWatch(gt,$t,Et)}function doWatch(gt,$t,Et){var Tt=Et===void 0?emptyObject:Et,At=Tt.immediate,Ct=Tt.deep,Pt=Tt.flush,It=Pt===void 0?"pre":Pt;Tt.onTrack,Tt.onTrigger;var Nt=currentInstance,Ut=function(Kt,qt,Jt){return Jt===void 0&&(Jt=null),invokeWithErrorHandling(Kt,null,Jt,Nt,qt)},Dt,Mt=!1,Ft=!1;if(isRef(gt)?(Dt=function(){return gt.value},Mt=isShallow(gt)):isReactive(gt)?(Dt=function(){return gt.__ob__.dep.depend(),gt},Ct=!0):isArray(gt)?(Ft=!0,Mt=gt.some(function(Kt){return isReactive(Kt)||isShallow(Kt)}),Dt=function(){return gt.map(function(Kt){if(isRef(Kt))return Kt.value;if(isReactive(Kt))return traverse(Kt);if(isFunction$2(Kt))return Ut(Kt,WATCHER_GETTER)})}):isFunction$2(gt)?$t?Dt=function(){return Ut(gt,WATCHER_GETTER)}:Dt=function(){if(!(Nt&&Nt._isDestroyed))return Gt&&Gt(),Ut(gt,WATCHER,[Vt])}:Dt=noop$2,$t&&Ct){var Bt=Dt;Dt=function(){return traverse(Bt())}}var Gt,Vt=function(Kt){Gt=Ht.onStop=function(){Ut(Kt,WATCHER_CLEANUP)}};if(isServerRendering())return Vt=noop$2,$t?At&&Ut($t,WATCHER_CB,[Dt(),Ft?[]:void 0,Vt]):Dt(),noop$2;var Ht=new Watcher(currentInstance,Dt,noop$2,{lazy:!0});Ht.noRecurse=!$t;var Wt=Ft?[]:INITIAL_WATCHER_VALUE;return Ht.run=function(){if(Ht.active)if($t){var Kt=Ht.get();(Ct||Mt||(Ft?Kt.some(function(qt,Jt){return hasChanged(qt,Wt[Jt])}):hasChanged(Kt,Wt)))&&(Gt&&Gt(),Ut($t,WATCHER_CB,[Kt,Wt===INITIAL_WATCHER_VALUE?void 0:Wt,Vt]),Wt=Kt)}else Ht.get()},It==="sync"?Ht.update=Ht.run:It==="post"?(Ht.post=!0,Ht.update=function(){return queueWatcher(Ht)}):Ht.update=function(){if(Nt&&Nt===currentInstance&&!Nt._isMounted){var Kt=Nt._preWatchers||(Nt._preWatchers=[]);Kt.indexOf(Ht)<0&&Kt.push(Ht)}else queueWatcher(Ht)},$t?At?Ht.run():Wt=Ht.get():It==="post"&&Nt?Nt.$once("hook:mounted",function(){return Ht.get()}):Ht.get(),function(){Ht.teardown()}}var activeEffectScope,EffectScope=function(){function gt($t){$t===void 0&&($t=!1),this.detached=$t,this.active=!0,this.effects=[],this.cleanups=[],this.parent=activeEffectScope,!$t&&activeEffectScope&&(this.index=(activeEffectScope.scopes||(activeEffectScope.scopes=[])).push(this)-1)}return gt.prototype.run=function($t){if(this.active){var Et=activeEffectScope;try{return activeEffectScope=this,$t()}finally{activeEffectScope=Et}}},gt.prototype.on=function(){activeEffectScope=this},gt.prototype.off=function(){activeEffectScope=this.parent},gt.prototype.stop=function($t){if(this.active){var Et=void 0,Tt=void 0;for(Et=0,Tt=this.effects.length;Et1)return Et&&isFunction$2($t)?$t.call(Tt):$t}}function h$7(gt,$t,Et){return createElement$1(currentInstance,gt,$t,Et,2,!0)}function handleError(gt,$t,Et){pushTarget();try{if($t)for(var Tt=$t;Tt=Tt.$parent;){var At=Tt.$options.errorCaptured;if(At)for(var Ct=0;Ct-1){if(Ct&&!hasOwn(At,"default"))Pt=!1;else if(Pt===""||Pt===hyphenate(gt)){var Nt=getTypeIndex(String,At.type);(Nt<0||It-1)return this;var Tt=toArray(arguments,1);return Tt.unshift(this),isFunction$2($t.install)?$t.install.apply($t,Tt):isFunction$2($t)&&$t.apply(null,Tt),Et.push($t),this}}function initMixin(gt){gt.mixin=function($t){return this.options=mergeOptions(this.options,$t),this}}function initExtend(gt){gt.cid=0;var $t=1;gt.extend=function(Et){Et=Et||{};var Tt=this,At=Tt.cid,Ct=Et._Ctor||(Et._Ctor={});if(Ct[At])return Ct[At];var Pt=getComponentName(Et)||getComponentName(Tt.options),It=function(Ut){this._init(Ut)};return It.prototype=Object.create(Tt.prototype),It.prototype.constructor=It,It.cid=$t++,It.options=mergeOptions(Tt.options,Et),It.super=Tt,It.options.props&&initProps(It),It.options.computed&&initComputed(It),It.extend=Tt.extend,It.mixin=Tt.mixin,It.use=Tt.use,ASSET_TYPES.forEach(function(Nt){It[Nt]=Tt[Nt]}),Pt&&(It.options.components[Pt]=It),It.superOptions=Tt.options,It.extendOptions=Et,It.sealedOptions=extend$1({},It.options),Ct[At]=It,It}}function initProps(gt){var $t=gt.options.props;for(var Et in $t)proxy(gt.prototype,"_props",Et)}function initComputed(gt){var $t=gt.options.computed;for(var Et in $t)defineComputed(gt.prototype,Et,$t[Et])}function initAssetRegisters(gt){ASSET_TYPES.forEach(function($t){gt[$t]=function(Et,Tt){return Tt?($t==="component"&&isPlainObject(Tt)&&(Tt.name=Tt.name||Et,Tt=this.options._base.extend(Tt)),$t==="directive"&&isFunction$2(Tt)&&(Tt={bind:Tt,update:Tt}),this.options[$t+"s"][Et]=Tt,Tt):this.options[$t+"s"][Et]}})}function _getComponentName(gt){return gt&&(getComponentName(gt.Ctor.options)||gt.tag)}function matches(gt,$t){return isArray(gt)?gt.indexOf($t)>-1:typeof gt=="string"?gt.split(",").indexOf($t)>-1:isRegExp(gt)?gt.test($t):!1}function pruneCache(gt,$t){var Et=gt.cache,Tt=gt.keys,At=gt._vnode;for(var Ct in Et){var Pt=Et[Ct];if(Pt){var It=Pt.name;It&&!$t(It)&&pruneCacheEntry(Et,Ct,Tt,At)}}}function pruneCacheEntry(gt,$t,Et,Tt){var At=gt[$t];At&&(!Tt||At.tag!==Tt.tag)&&At.componentInstance.$destroy(),gt[$t]=null,remove$2(Et,$t)}var patternTypes=[String,RegExp,Array],KeepAlive={name:"keep-alive",abstract:!0,props:{include:patternTypes,exclude:patternTypes,max:[String,Number]},methods:{cacheVNode:function(){var gt=this,$t=gt.cache,Et=gt.keys,Tt=gt.vnodeToCache,At=gt.keyToCache;if(Tt){var Ct=Tt.tag,Pt=Tt.componentInstance,It=Tt.componentOptions;$t[At]={name:_getComponentName(It),tag:Ct,componentInstance:Pt},Et.push(At),this.max&&Et.length>parseInt(this.max)&&pruneCacheEntry($t,Et[0],Et,this._vnode),this.vnodeToCache=null}}},created:function(){this.cache=Object.create(null),this.keys=[]},destroyed:function(){for(var gt in this.cache)pruneCacheEntry(this.cache,gt,this.keys)},mounted:function(){var gt=this;this.cacheVNode(),this.$watch("include",function($t){pruneCache(gt,function(Et){return matches($t,Et)})}),this.$watch("exclude",function($t){pruneCache(gt,function(Et){return!matches($t,Et)})})},updated:function(){this.cacheVNode()},render:function(){var gt=this.$slots.default,$t=getFirstComponentChild(gt),Et=$t&&$t.componentOptions;if(Et){var Tt=_getComponentName(Et),At=this,Ct=At.include,Pt=At.exclude;if(Ct&&(!Tt||!matches(Ct,Tt))||Pt&&Tt&&matches(Pt,Tt))return $t;var It=this,Nt=It.cache,Ut=It.keys,Dt=$t.key==null?Et.Ctor.cid+(Et.tag?"::".concat(Et.tag):""):$t.key;Nt[Dt]?($t.componentInstance=Nt[Dt].componentInstance,remove$2(Ut,Dt),Ut.push(Dt)):(this.vnodeToCache=$t,this.keyToCache=Dt),$t.data.keepAlive=!0}return $t||gt&>[0]}},builtInComponents={KeepAlive};function initGlobalAPI(gt){var $t={};$t.get=function(){return config$2},Object.defineProperty(gt,"config",$t),gt.util={warn:warn$2,extend:extend$1,mergeOptions,defineReactive},gt.set=set,gt.delete=del,gt.nextTick=nextTick,gt.observable=function(Et){return observe(Et),Et},gt.options=Object.create(null),ASSET_TYPES.forEach(function(Et){gt.options[Et+"s"]=Object.create(null)}),gt.options._base=gt,extend$1(gt.options.components,builtInComponents),initUse(gt),initMixin(gt),initExtend(gt),initAssetRegisters(gt)}initGlobalAPI(Vue);Object.defineProperty(Vue.prototype,"$isServer",{get:isServerRendering});Object.defineProperty(Vue.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}});Object.defineProperty(Vue,"FunctionalRenderContext",{value:FunctionalRenderContext});Vue.version=version$1;var isReservedAttr=makeMap("style,class"),acceptValue=makeMap("input,textarea,option,select,progress"),mustUseProp=function(gt,$t,Et){return Et==="value"&&acceptValue(gt)&&$t!=="button"||Et==="selected"&>==="option"||Et==="checked"&>==="input"||Et==="muted"&>==="video"},isEnumeratedAttr=makeMap("contenteditable,draggable,spellcheck"),isValidContentEditableValue=makeMap("events,caret,typing,plaintext-only"),convertEnumeratedValue=function(gt,$t){return isFalsyAttrValue($t)||$t==="false"?"false":gt==="contenteditable"&&isValidContentEditableValue($t)?$t:"true"},isBooleanAttr=makeMap("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,truespeed,typemustmatch,visible"),xlinkNS="http://www.w3.org/1999/xlink",isXlink=function(gt){return gt.charAt(5)===":"&>.slice(0,5)==="xlink"},getXlinkProp=function(gt){return isXlink(gt)?gt.slice(6,gt.length):""},isFalsyAttrValue=function(gt){return gt==null||gt===!1};function genClassForVnode(gt){for(var $t=gt.data,Et=gt,Tt=gt;isDef$1(Tt.componentInstance);)Tt=Tt.componentInstance._vnode,Tt&&Tt.data&&($t=mergeClassData(Tt.data,$t));for(;isDef$1(Et=Et.parent);)Et&&Et.data&&($t=mergeClassData($t,Et.data));return renderClass($t.staticClass,$t.class)}function mergeClassData(gt,$t){return{staticClass:concat(gt.staticClass,$t.staticClass),class:isDef$1(gt.class)?[gt.class,$t.class]:$t.class}}function renderClass(gt,$t){return isDef$1(gt)||isDef$1($t)?concat(gt,stringifyClass($t)):""}function concat(gt,$t){return gt?$t?gt+" "+$t:gt:$t||""}function stringifyClass(gt){return Array.isArray(gt)?stringifyArray(gt):isObject$4(gt)?stringifyObject(gt):typeof gt=="string"?gt:""}function stringifyArray(gt){for(var $t="",Et,Tt=0,At=gt.length;Tt-1?unknownElementCache[gt]=$t.constructor===window.HTMLUnknownElement||$t.constructor===window.HTMLElement:unknownElementCache[gt]=/HTMLUnknownElement/.test($t.toString())}var isTextInputType=makeMap("text,number,password,search,email,tel,url");function query(gt){if(typeof gt=="string"){var $t=document.querySelector(gt);return $t||document.createElement("div")}else return gt}function createElement(gt,$t){var Et=document.createElement(gt);return gt!=="select"||$t.data&&$t.data.attrs&&$t.data.attrs.multiple!==void 0&&Et.setAttribute("multiple","multiple"),Et}function createElementNS(gt,$t){return document.createElementNS(namespaceMap[gt],$t)}function createTextNode(gt){return document.createTextNode(gt)}function createComment(gt){return document.createComment(gt)}function insertBefore(gt,$t,Et){gt.insertBefore($t,Et)}function removeChild(gt,$t){gt.removeChild($t)}function appendChild(gt,$t){gt.appendChild($t)}function parentNode(gt){return gt.parentNode}function nextSibling(gt){return gt.nextSibling}function tagName(gt){return gt.tagName}function setTextContent(gt,$t){gt.textContent=$t}function setStyleScope(gt,$t){gt.setAttribute($t,"")}var nodeOps=Object.freeze({__proto__:null,createElement,createElementNS,createTextNode,createComment,insertBefore,removeChild,appendChild,parentNode,nextSibling,tagName,setTextContent,setStyleScope}),ref={create:function(gt,$t){registerRef($t)},update:function(gt,$t){gt.data.ref!==$t.data.ref&&(registerRef(gt,!0),registerRef($t))},destroy:function(gt){registerRef(gt,!0)}};function registerRef(gt,$t){var Et=gt.data.ref;if(isDef$1(Et)){var Tt=gt.context,At=gt.componentInstance||gt.elm,Ct=$t?null:At,Pt=$t?void 0:At;if(isFunction$2(Et)){invokeWithErrorHandling(Et,Tt,[Ct],Tt,"template ref function");return}var It=gt.data.refInFor,Nt=typeof Et=="string"||typeof Et=="number",Ut=isRef(Et),Dt=Tt.$refs;if(Nt||Ut){if(It){var Mt=Nt?Dt[Et]:Et.value;$t?isArray(Mt)&&remove$2(Mt,At):isArray(Mt)?Mt.includes(At)||Mt.push(At):Nt?(Dt[Et]=[At],setSetupRef(Tt,Et,Dt[Et])):Et.value=[At]}else if(Nt){if($t&&Dt[Et]!==At)return;Dt[Et]=Pt,setSetupRef(Tt,Et,Ct)}else if(Ut){if($t&&Et.value!==At)return;Et.value=Ct}}}}function setSetupRef(gt,$t,Et){var Tt=gt._setupState;Tt&&hasOwn(Tt,$t)&&(isRef(Tt[$t])?Tt[$t].value=Et:Tt[$t]=Et)}var emptyNode=new VNode("",{},[]),hooks=["create","activate","update","remove","destroy"];function sameVnode(gt,$t){return gt.key===$t.key&>.asyncFactory===$t.asyncFactory&&(gt.tag===$t.tag&>.isComment===$t.isComment&&isDef$1(gt.data)===isDef$1($t.data)&&sameInputType(gt,$t)||isTrue(gt.isAsyncPlaceholder)&&isUndef($t.asyncFactory.error))}function sameInputType(gt,$t){if(gt.tag!=="input")return!0;var Et,Tt=isDef$1(Et=gt.data)&&isDef$1(Et=Et.attrs)&&Et.type,At=isDef$1(Et=$t.data)&&isDef$1(Et=Et.attrs)&&Et.type;return Tt===At||isTextInputType(Tt)&&isTextInputType(At)}function createKeyToOldIdx(gt,$t,Et){var Tt,At,Ct={};for(Tt=$t;Tt<=Et;++Tt)At=gt[Tt].key,isDef$1(At)&&(Ct[At]=Tt);return Ct}function createPatchFunction(gt){var $t,Et,Tt={},At=gt.modules,Ct=gt.nodeOps;for($t=0;$tvr?(Mr=isUndef(or[$r+1])?null:or[$r+1].elm,Kt(Yt,Mr,or,ur,$r,cr)):ur>$r&&Jt(er,ar,vr)}function rr(Yt,er,or,cr){for(var ir=or;ir-1?baseSetAttr(gt,$t,Et):isBooleanAttr($t)?isFalsyAttrValue(Et)?gt.removeAttribute($t):(Et=$t==="allowfullscreen"&>.tagName==="EMBED"?"true":$t,gt.setAttribute($t,Et)):isEnumeratedAttr($t)?gt.setAttribute($t,convertEnumeratedValue($t,Et)):isXlink($t)?isFalsyAttrValue(Et)?gt.removeAttributeNS(xlinkNS,getXlinkProp($t)):gt.setAttributeNS(xlinkNS,$t,Et):baseSetAttr(gt,$t,Et)}function baseSetAttr(gt,$t,Et){if(isFalsyAttrValue(Et))gt.removeAttribute($t);else{if(isIE&&!isIE9&>.tagName==="TEXTAREA"&&$t==="placeholder"&&Et!==""&&!gt.__ieph){var Tt=function(At){At.stopImmediatePropagation(),gt.removeEventListener("input",Tt)};gt.addEventListener("input",Tt),gt.__ieph=!0}gt.setAttribute($t,Et)}}var attrs={create:updateAttrs,update:updateAttrs};function updateClass(gt,$t){var Et=$t.elm,Tt=$t.data,At=gt.data;if(!(isUndef(Tt.staticClass)&&isUndef(Tt.class)&&(isUndef(At)||isUndef(At.staticClass)&&isUndef(At.class)))){var Ct=genClassForVnode($t),Pt=Et._transitionClasses;isDef$1(Pt)&&(Ct=concat(Ct,stringifyClass(Pt))),Ct!==Et._prevClass&&(Et.setAttribute("class",Ct),Et._prevClass=Ct)}}var klass$1={create:updateClass,update:updateClass},validDivisionCharRE=/[\w).+\-_$\]]/;function parseFilters(gt){var $t=!1,Et=!1,Tt=!1,At=!1,Ct=0,Pt=0,It=0,Nt=0,Ut,Dt,Mt,Ft,Bt;for(Mt=0;Mt=0&&(Vt=gt.charAt(Gt),Vt===" ");Gt--);(!Vt||!validDivisionCharRE.test(Vt))&&(At=!0)}}Ft===void 0?Ft=gt.slice(0,Mt).trim():Nt!==0&&Ht();function Ht(){(Bt||(Bt=[])).push(gt.slice(Nt,Mt).trim()),Nt=Mt+1}if(Bt)for(Mt=0;Mt-1?{exp:gt.slice(0,index),key:'"'+gt.slice(index+1)+'"'}:{exp:gt,key:null};for(str=gt,index=expressionPos=expressionEndPos=0;!eof();)chr=next(),isStringStart(chr)?parseString(chr):chr===91&&parseBracket(chr);return{exp:gt.slice(0,expressionPos),key:gt.slice(expressionPos+1,expressionEndPos)}}function next(){return str.charCodeAt(++index)}function eof(){return index>=len}function isStringStart(gt){return gt===34||gt===39}function parseBracket(gt){var $t=1;for(expressionPos=index;!eof();){if(gt=next(),isStringStart(gt)){parseString(gt);continue}if(gt===91&&$t++,gt===93&&$t--,$t===0){expressionEndPos=index;break}}}function parseString(gt){for(var $t=gt;!eof()&&(gt=next(),gt!==$t););}var RANGE_TOKEN="__r",CHECKBOX_RADIO_TOKEN="__c";function model$1(gt,$t,Et){var Tt=$t.value,At=$t.modifiers,Ct=gt.tag,Pt=gt.attrsMap.type;if(gt.component)return genComponentModel(gt,Tt,At),!1;if(Ct==="select")genSelect(gt,Tt,At);else if(Ct==="input"&&Pt==="checkbox")genCheckboxModel(gt,Tt,At);else if(Ct==="input"&&Pt==="radio")genRadioModel(gt,Tt,At);else if(Ct==="input"||Ct==="textarea")genDefaultModel(gt,Tt,At);else if(!config$2.isReservedTag(Ct))return genComponentModel(gt,Tt,At),!1;return!0}function genCheckboxModel(gt,$t,Et){var Tt=Et&&Et.number,At=getBindingAttr(gt,"value")||"null",Ct=getBindingAttr(gt,"true-value")||"true",Pt=getBindingAttr(gt,"false-value")||"false";addProp(gt,"checked","Array.isArray(".concat($t,")")+"?_i(".concat($t,",").concat(At,")>-1")+(Ct==="true"?":(".concat($t,")"):":_q(".concat($t,",").concat(Ct,")"))),addHandler(gt,"change","var $$a=".concat($t,",")+"$$el=$event.target,"+"$$c=$$el.checked?(".concat(Ct,"):(").concat(Pt,");")+"if(Array.isArray($$a)){"+"var $$v=".concat(Tt?"_n("+At+")":At,",")+"$$i=_i($$a,$$v);"+"if($$el.checked){$$i<0&&(".concat(genAssignmentCode($t,"$$a.concat([$$v])"),")}")+"else{$$i>-1&&(".concat(genAssignmentCode($t,"$$a.slice(0,$$i).concat($$a.slice($$i+1))"),")}")+"}else{".concat(genAssignmentCode($t,"$$c"),"}"),null,!0)}function genRadioModel(gt,$t,Et){var Tt=Et&&Et.number,At=getBindingAttr(gt,"value")||"null";At=Tt?"_n(".concat(At,")"):At,addProp(gt,"checked","_q(".concat($t,",").concat(At,")")),addHandler(gt,"change",genAssignmentCode($t,At),null,!0)}function genSelect(gt,$t,Et){var Tt=Et&&Et.number,At='Array.prototype.filter.call($event.target.options,function(o){return o.selected}).map(function(o){var val = "_value" in o ? o._value : o.value;'+"return ".concat(Tt?"_n(val)":"val","})"),Ct="$event.target.multiple ? $$selectedVal : $$selectedVal[0]",Pt="var $$selectedVal = ".concat(At,";");Pt="".concat(Pt," ").concat(genAssignmentCode($t,Ct)),addHandler(gt,"change",Pt,null,!0)}function genDefaultModel(gt,$t,Et){var Tt=gt.attrsMap.type,At=Et||{},Ct=At.lazy,Pt=At.number,It=At.trim,Nt=!Ct&&Tt!=="range",Ut=Ct?"change":Tt==="range"?RANGE_TOKEN:"input",Dt="$event.target.value";It&&(Dt="$event.target.value.trim()"),Pt&&(Dt="_n(".concat(Dt,")"));var Mt=genAssignmentCode($t,Dt);Nt&&(Mt="if($event.target.composing)return;".concat(Mt)),addProp(gt,"value","(".concat($t,")")),addHandler(gt,Ut,Mt,null,!0),(It||Pt)&&addHandler(gt,"blur","$forceUpdate()")}function normalizeEvents(gt){if(isDef$1(gt[RANGE_TOKEN])){var $t=isIE?"change":"input";gt[$t]=[].concat(gt[RANGE_TOKEN],gt[$t]||[]),delete gt[RANGE_TOKEN]}isDef$1(gt[CHECKBOX_RADIO_TOKEN])&&(gt.change=[].concat(gt[CHECKBOX_RADIO_TOKEN],gt.change||[]),delete gt[CHECKBOX_RADIO_TOKEN])}var target;function createOnceHandler(gt,$t,Et){var Tt=target;return function At(){var Ct=$t.apply(null,arguments);Ct!==null&&remove(gt,At,Et,Tt)}}var useMicrotaskFix=isUsingMicroTask&&!(isFF&&Number(isFF[1])<=53);function add(gt,$t,Et,Tt){if(useMicrotaskFix){var At=currentFlushTimestamp,Ct=$t;$t=Ct._wrapper=function(Pt){if(Pt.target===Pt.currentTarget||Pt.timeStamp>=At||Pt.timeStamp<=0||Pt.target.ownerDocument!==document)return Ct.apply(this,arguments)}}target.addEventListener(gt,$t,supportsPassive?{capture:Et,passive:Tt}:Et)}function remove(gt,$t,Et,Tt){(Tt||target).removeEventListener(gt,$t._wrapper||$t,Et)}function updateDOMListeners(gt,$t){if(!(isUndef(gt.data.on)&&isUndef($t.data.on))){var Et=$t.data.on||{},Tt=gt.data.on||{};target=$t.elm||gt.elm,normalizeEvents(Et),updateListeners(Et,Tt,add,remove,createOnceHandler,$t.context),target=void 0}}var events$1={create:updateDOMListeners,update:updateDOMListeners,destroy:function(gt){return updateDOMListeners(gt,emptyNode)}},svgContainer;function updateDOMProps(gt,$t){if(!(isUndef(gt.data.domProps)&&isUndef($t.data.domProps))){var Et,Tt,At=$t.elm,Ct=gt.data.domProps||{},Pt=$t.data.domProps||{};(isDef$1(Pt.__ob__)||isTrue(Pt._v_attr_proxy))&&(Pt=$t.data.domProps=extend$1({},Pt));for(Et in Ct)Et in Pt||(At[Et]="");for(Et in Pt){if(Tt=Pt[Et],Et==="textContent"||Et==="innerHTML"){if($t.children&&($t.children.length=0),Tt===Ct[Et])continue;At.childNodes.length===1&&At.removeChild(At.childNodes[0])}if(Et==="value"&&At.tagName!=="PROGRESS"){At._value=Tt;var It=isUndef(Tt)?"":String(Tt);shouldUpdateValue(At,It)&&(At.value=It)}else if(Et==="innerHTML"&&isSVG(At.tagName)&&isUndef(At.innerHTML)){svgContainer=svgContainer||document.createElement("div"),svgContainer.innerHTML="".concat(Tt,"");for(var Nt=svgContainer.firstChild;At.firstChild;)At.removeChild(At.firstChild);for(;Nt.firstChild;)At.appendChild(Nt.firstChild)}else if(Tt!==Ct[Et])try{At[Et]=Tt}catch(Ut){}}}}function shouldUpdateValue(gt,$t){return!gt.composing&&(gt.tagName==="OPTION"||isNotInFocusAndDirty(gt,$t)||isDirtyWithModifiers(gt,$t))}function isNotInFocusAndDirty(gt,$t){var Et=!0;try{Et=document.activeElement!==gt}catch(Tt){}return Et&>.value!==$t}function isDirtyWithModifiers(gt,$t){var Et=gt.value,Tt=gt._vModifiers;if(isDef$1(Tt)){if(Tt.number)return toNumber$2(Et)!==toNumber$2($t);if(Tt.trim)return Et.trim()!==$t.trim()}return Et!==$t}var domProps={create:updateDOMProps,update:updateDOMProps},parseStyleText=cached(function(gt){var $t={},Et=/;(?![^(]*\))/g,Tt=/:(.+)/;return gt.split(Et).forEach(function(At){if(At){var Ct=At.split(Tt);Ct.length>1&&($t[Ct[0].trim()]=Ct[1].trim())}}),$t});function normalizeStyleData(gt){var $t=normalizeStyleBinding(gt.style);return gt.staticStyle?extend$1(gt.staticStyle,$t):$t}function normalizeStyleBinding(gt){return Array.isArray(gt)?toObject(gt):typeof gt=="string"?parseStyleText(gt):gt}function getStyle(gt,$t){var Et={},Tt;if($t)for(var At=gt;At.componentInstance;)At=At.componentInstance._vnode,At&&At.data&&(Tt=normalizeStyleData(At.data))&&extend$1(Et,Tt);(Tt=normalizeStyleData(gt.data))&&extend$1(Et,Tt);for(var Ct=gt;Ct=Ct.parent;)Ct.data&&(Tt=normalizeStyleData(Ct.data))&&extend$1(Et,Tt);return Et}var cssVarRE=/^--/,importantRE=/\s*!important$/,setProp=function(gt,$t,Et){if(cssVarRE.test($t))gt.style.setProperty($t,Et);else if(importantRE.test(Et))gt.style.setProperty(hyphenate($t),Et.replace(importantRE,""),"important");else{var Tt=normalize($t);if(Array.isArray(Et))for(var At=0,Ct=Et.length;At-1?$t.split(whitespaceRE$1).forEach(function(Tt){return gt.classList.add(Tt)}):gt.classList.add($t);else{var Et=" ".concat(gt.getAttribute("class")||""," ");Et.indexOf(" "+$t+" ")<0&>.setAttribute("class",(Et+$t).trim())}}function removeClass(gt,$t){if(!(!$t||!($t=$t.trim())))if(gt.classList)$t.indexOf(" ")>-1?$t.split(whitespaceRE$1).forEach(function(At){return gt.classList.remove(At)}):gt.classList.remove($t),gt.classList.length||gt.removeAttribute("class");else{for(var Et=" ".concat(gt.getAttribute("class")||""," "),Tt=" "+$t+" ";Et.indexOf(Tt)>=0;)Et=Et.replace(Tt," ");Et=Et.trim(),Et?gt.setAttribute("class",Et):gt.removeAttribute("class")}}function resolveTransition(gt){if(gt){if(typeof gt=="object"){var $t={};return gt.css!==!1&&extend$1($t,autoCssTransition(gt.name||"v")),extend$1($t,gt),$t}else if(typeof gt=="string")return autoCssTransition(gt)}}var autoCssTransition=cached(function(gt){return{enterClass:"".concat(gt,"-enter"),enterToClass:"".concat(gt,"-enter-to"),enterActiveClass:"".concat(gt,"-enter-active"),leaveClass:"".concat(gt,"-leave"),leaveToClass:"".concat(gt,"-leave-to"),leaveActiveClass:"".concat(gt,"-leave-active")}}),hasTransition=inBrowser$1&&!isIE9,TRANSITION="transition",ANIMATION="animation",transitionProp="transition",transitionEndEvent="transitionend",animationProp="animation",animationEndEvent="animationend";hasTransition&&(window.ontransitionend===void 0&&window.onwebkittransitionend!==void 0&&(transitionProp="WebkitTransition",transitionEndEvent="webkitTransitionEnd"),window.onanimationend===void 0&&window.onwebkitanimationend!==void 0&&(animationProp="WebkitAnimation",animationEndEvent="webkitAnimationEnd"));var raf=inBrowser$1?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(gt){return gt()};function nextFrame(gt){raf(function(){raf(gt)})}function addTransitionClass(gt,$t){var Et=gt._transitionClasses||(gt._transitionClasses=[]);Et.indexOf($t)<0&&(Et.push($t),addClass(gt,$t))}function removeTransitionClass(gt,$t){gt._transitionClasses&&remove$2(gt._transitionClasses,$t),removeClass(gt,$t)}function whenTransitionEnds(gt,$t,Et){var Tt=getTransitionInfo(gt,$t),At=Tt.type,Ct=Tt.timeout,Pt=Tt.propCount;if(!At)return Et();var It=At===TRANSITION?transitionEndEvent:animationEndEvent,Nt=0,Ut=function(){gt.removeEventListener(It,Dt),Et()},Dt=function(Mt){Mt.target===gt&&++Nt>=Pt&&Ut()};setTimeout(function(){Nt0&&(Ut=TRANSITION,Dt=Ct,Mt=At.length):$t===ANIMATION?Nt>0&&(Ut=ANIMATION,Dt=Nt,Mt=It.length):(Dt=Math.max(Ct,Nt),Ut=Dt>0?Ct>Nt?TRANSITION:ANIMATION:null,Mt=Ut?Ut===TRANSITION?At.length:It.length:0);var Ft=Ut===TRANSITION&&transformRE.test(Et[transitionProp+"Property"]);return{type:Ut,timeout:Dt,propCount:Mt,hasTransform:Ft}}function getTimeout(gt,$t){for(;gt.length<$t.length;)gt=gt.concat(gt);return Math.max.apply(null,$t.map(function(Et,Tt){return toMs(Et)+toMs(gt[Tt])}))}function toMs(gt){return Number(gt.slice(0,-1).replace(",","."))*1e3}function enter(gt,$t){var Et=gt.elm;isDef$1(Et._leaveCb)&&(Et._leaveCb.cancelled=!0,Et._leaveCb());var Tt=resolveTransition(gt.data.transition);if(!isUndef(Tt)&&!(isDef$1(Et._enterCb)||Et.nodeType!==1)){for(var At=Tt.css,Ct=Tt.type,Pt=Tt.enterClass,It=Tt.enterToClass,Nt=Tt.enterActiveClass,Ut=Tt.appearClass,Dt=Tt.appearToClass,Mt=Tt.appearActiveClass,Ft=Tt.beforeEnter,Bt=Tt.enter,Gt=Tt.afterEnter,Vt=Tt.enterCancelled,Ht=Tt.beforeAppear,Wt=Tt.appear,Kt=Tt.afterAppear,qt=Tt.appearCancelled,Jt=Tt.duration,Xt=activeInstance,Zt=activeInstance.$vnode;Zt&&Zt.parent;)Xt=Zt.context,Zt=Zt.parent;var rr=!Xt._isMounted||!gt.isRootInsert;if(!(rr&&!Wt&&Wt!=="")){var tr=rr&&Ut?Ut:Pt,Qt=rr&&Mt?Mt:Nt,zt=rr&&Dt?Dt:It,nr=rr&&Ht||Ft,Yt=rr&&isFunction$2(Wt)?Wt:Bt,er=rr&&Kt||Gt,or=rr&&qt||Vt,cr=toNumber$2(isObject$4(Jt)?Jt.enter:Jt),ir=At!==!1&&!isIE9,ar=getHookArgumentsLength(Yt),ur=Et._enterCb=once(function(){ir&&(removeTransitionClass(Et,zt),removeTransitionClass(Et,Qt)),ur.cancelled?(ir&&removeTransitionClass(Et,tr),or&&or(Et)):er&&er(Et),Et._enterCb=null});gt.data.show||mergeVNodeHook(gt,"insert",function(){var vr=Et.parentNode,gr=vr&&vr._pending&&vr._pending[gt.key];gr&&gr.tag===gt.tag&&gr.elm._leaveCb&&gr.elm._leaveCb(),Yt&&Yt(Et,ur)}),nr&&nr(Et),ir&&(addTransitionClass(Et,tr),addTransitionClass(Et,Qt),nextFrame(function(){removeTransitionClass(Et,tr),ur.cancelled||(addTransitionClass(Et,zt),ar||(isValidDuration(cr)?setTimeout(ur,cr):whenTransitionEnds(Et,Ct,ur)))})),gt.data.show&&($t&&$t(),Yt&&Yt(Et,ur)),!ir&&!ar&&ur()}}}function leave(gt,$t){var Et=gt.elm;isDef$1(Et._enterCb)&&(Et._enterCb.cancelled=!0,Et._enterCb());var Tt=resolveTransition(gt.data.transition);if(isUndef(Tt)||Et.nodeType!==1)return $t();if(isDef$1(Et._leaveCb))return;var At=Tt.css,Ct=Tt.type,Pt=Tt.leaveClass,It=Tt.leaveToClass,Nt=Tt.leaveActiveClass,Ut=Tt.beforeLeave,Dt=Tt.leave,Mt=Tt.afterLeave,Ft=Tt.leaveCancelled,Bt=Tt.delayLeave,Gt=Tt.duration,Vt=At!==!1&&!isIE9,Ht=getHookArgumentsLength(Dt),Wt=toNumber$2(isObject$4(Gt)?Gt.leave:Gt),Kt=Et._leaveCb=once(function(){Et.parentNode&&Et.parentNode._pending&&(Et.parentNode._pending[gt.key]=null),Vt&&(removeTransitionClass(Et,It),removeTransitionClass(Et,Nt)),Kt.cancelled?(Vt&&removeTransitionClass(Et,Pt),Ft&&Ft(Et)):($t(),Mt&&Mt(Et)),Et._leaveCb=null});Bt?Bt(qt):qt();function qt(){Kt.cancelled||(!gt.data.show&&Et.parentNode&&((Et.parentNode._pending||(Et.parentNode._pending={}))[gt.key]=gt),Ut&&Ut(Et),Vt&&(addTransitionClass(Et,Pt),addTransitionClass(Et,Nt),nextFrame(function(){removeTransitionClass(Et,Pt),Kt.cancelled||(addTransitionClass(Et,It),Ht||(isValidDuration(Wt)?setTimeout(Kt,Wt):whenTransitionEnds(Et,Ct,Kt)))})),Dt&&Dt(Et,Kt),!Vt&&!Ht&&Kt())}}function isValidDuration(gt){return typeof gt=="number"&&!isNaN(gt)}function getHookArgumentsLength(gt){if(isUndef(gt))return!1;var $t=gt.fns;return isDef$1($t)?getHookArgumentsLength(Array.isArray($t)?$t[0]:$t):(gt._length||gt.length)>1}function _enter(gt,$t){$t.data.show!==!0&&enter($t)}var transition=inBrowser$1?{create:_enter,activate:_enter,remove:function(gt,$t){gt.data.show!==!0?leave(gt,$t):$t()}}:{},platformModules=[attrs,klass$1,events$1,domProps,style$1,transition],modules$1=platformModules.concat(baseModules),patch=createPatchFunction({nodeOps,modules:modules$1});isIE9&&document.addEventListener("selectionchange",function(){var gt=document.activeElement;gt&>.vmodel&&trigger(gt,"input")});var directive={inserted:function(gt,$t,Et,Tt){Et.tag==="select"?(Tt.elm&&!Tt.elm._vOptions?mergeVNodeHook(Et,"postpatch",function(){directive.componentUpdated(gt,$t,Et)}):setSelected(gt,$t,Et.context),gt._vOptions=[].map.call(gt.options,getValue)):(Et.tag==="textarea"||isTextInputType(gt.type))&&(gt._vModifiers=$t.modifiers,$t.modifiers.lazy||(gt.addEventListener("compositionstart",onCompositionStart),gt.addEventListener("compositionend",onCompositionEnd),gt.addEventListener("change",onCompositionEnd),isIE9&&(gt.vmodel=!0)))},componentUpdated:function(gt,$t,Et){if(Et.tag==="select"){setSelected(gt,$t,Et.context);var Tt=gt._vOptions,At=gt._vOptions=[].map.call(gt.options,getValue);if(At.some(function(Pt,It){return!looseEqual(Pt,Tt[It])})){var Ct=gt.multiple?$t.value.some(function(Pt){return hasNoMatchingOption(Pt,At)}):$t.value!==$t.oldValue&&hasNoMatchingOption($t.value,At);Ct&&trigger(gt,"change")}}}};function setSelected(gt,$t,Et){actuallySetSelected(gt,$t),(isIE||isEdge)&&setTimeout(function(){actuallySetSelected(gt,$t)},0)}function actuallySetSelected(gt,$t,Et){var Tt=$t.value,At=gt.multiple;if(!(At&&!Array.isArray(Tt))){for(var Ct,Pt,It=0,Nt=gt.options.length;It-1,Pt.selected!==Ct&&(Pt.selected=Ct);else if(looseEqual(getValue(Pt),Tt)){gt.selectedIndex!==It&&(gt.selectedIndex=It);return}At||(gt.selectedIndex=-1)}}function hasNoMatchingOption(gt,$t){return $t.every(function(Et){return!looseEqual(Et,gt)})}function getValue(gt){return"_value"in gt?gt._value:gt.value}function onCompositionStart(gt){gt.target.composing=!0}function onCompositionEnd(gt){gt.target.composing&&(gt.target.composing=!1,trigger(gt.target,"input"))}function trigger(gt,$t){var Et=document.createEvent("HTMLEvents");Et.initEvent($t,!0,!0),gt.dispatchEvent(Et)}function locateNode(gt){return gt.componentInstance&&(!gt.data||!gt.data.transition)?locateNode(gt.componentInstance._vnode):gt}var show={bind:function(gt,$t,Et){var Tt=$t.value;Et=locateNode(Et);var At=Et.data&&Et.data.transition,Ct=gt.__vOriginalDisplay=gt.style.display==="none"?"":gt.style.display;Tt&&At?(Et.data.show=!0,enter(Et,function(){gt.style.display=Ct})):gt.style.display=Tt?Ct:"none"},update:function(gt,$t,Et){var Tt=$t.value,At=$t.oldValue;if(!Tt!=!At){Et=locateNode(Et);var Ct=Et.data&&Et.data.transition;Ct?(Et.data.show=!0,Tt?enter(Et,function(){gt.style.display=gt.__vOriginalDisplay}):leave(Et,function(){gt.style.display="none"})):gt.style.display=Tt?gt.__vOriginalDisplay:"none"}},unbind:function(gt,$t,Et,Tt,At){At||(gt.style.display=gt.__vOriginalDisplay)}},platformDirectives={model:directive,show},transitionProps={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function getRealChild(gt){var $t=gt&>.componentOptions;return $t&&$t.Ctor.options.abstract?getRealChild(getFirstComponentChild($t.children)):gt}function extractTransitionData(gt){var $t={},Et=gt.$options;for(var Tt in Et.propsData)$t[Tt]=gt[Tt];var At=Et._parentListeners;for(var Tt in At)$t[camelize(Tt)]=At[Tt];return $t}function placeholder(gt,$t){if(/\d-keep-alive$/.test($t.tag))return gt("keep-alive",{props:$t.componentOptions.propsData})}function hasParentTransition(gt){for(;gt=gt.parent;)if(gt.data.transition)return!0}function isSameChild(gt,$t){return $t.key===gt.key&&$t.tag===gt.tag}var isNotTextNode=function(gt){return gt.tag||isAsyncPlaceholder(gt)},isVShowDirective=function(gt){return gt.name==="show"},Transition={name:"transition",props:transitionProps,abstract:!0,render:function(gt){var $t=this,Et=this.$slots.default;if(Et&&(Et=Et.filter(isNotTextNode),!!Et.length)){var Tt=this.mode,At=Et[0];if(hasParentTransition(this.$vnode))return At;var Ct=getRealChild(At);if(!Ct)return At;if(this._leaving)return placeholder(gt,At);var Pt="__transition-".concat(this._uid,"-");Ct.key=Ct.key==null?Ct.isComment?Pt+"comment":Pt+Ct.tag:isPrimitive(Ct.key)?String(Ct.key).indexOf(Pt)===0?Ct.key:Pt+Ct.key:Ct.key;var It=(Ct.data||(Ct.data={})).transition=extractTransitionData(this),Nt=this._vnode,Ut=getRealChild(Nt);if(Ct.data.directives&&Ct.data.directives.some(isVShowDirective)&&(Ct.data.show=!0),Ut&&Ut.data&&!isSameChild(Ct,Ut)&&!isAsyncPlaceholder(Ut)&&!(Ut.componentInstance&&Ut.componentInstance._vnode.isComment)){var Dt=Ut.data.transition=extend$1({},It);if(Tt==="out-in")return this._leaving=!0,mergeVNodeHook(Dt,"afterLeave",function(){$t._leaving=!1,$t.$forceUpdate()}),placeholder(gt,At);if(Tt==="in-out"){if(isAsyncPlaceholder(Ct))return Nt;var Mt,Ft=function(){Mt()};mergeVNodeHook(It,"afterEnter",Ft),mergeVNodeHook(It,"enterCancelled",Ft),mergeVNodeHook(Dt,"delayLeave",function(Bt){Mt=Bt})}}return At}}},props=extend$1({tag:String,moveClass:String},transitionProps);delete props.mode;var TransitionGroup={props,beforeMount:function(){var gt=this,$t=this._update;this._update=function(Et,Tt){var At=setActiveInstance(gt);gt.__patch__(gt._vnode,gt.kept,!1,!0),gt._vnode=gt.kept,At(),$t.call(gt,Et,Tt)}},render:function(gt){for(var $t=this.tag||this.$vnode.data.tag||"span",Et=Object.create(null),Tt=this.prevChildren=this.children,At=this.$slots.default||[],Ct=this.children=[],Pt=extractTransitionData(this),It=0;ItCt&&(At.push(Nt=gt.slice(Ct,It)),Tt.push(JSON.stringify(Nt)));var Ut=parseFilters(Pt[1].trim());Tt.push("_s(".concat(Ut,")")),At.push({"@binding":Ut}),Ct=It+Pt[0].length}return Ct\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,dynamicArgAttribute=/^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+?\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,ncname="[a-zA-Z_][\\-\\.0-9_a-zA-Z".concat(unicodeRegExp.source,"]*"),qnameCapture="((?:".concat(ncname,"\\:)?").concat(ncname,")"),startTagOpen=new RegExp("^<".concat(qnameCapture)),startTagClose=/^\s*(\/?)>/,endTag=new RegExp("^<\\/".concat(qnameCapture,"[^>]*>")),doctype=/^]+>/i,comment=/^",""":'"',"&":"&"," ":"\n"," ":" ","'":"'"},encodedAttr=/&(?:lt|gt|quot|amp|#39);/g,encodedAttrWithNewLines=/&(?:lt|gt|quot|amp|#39|#10|#9);/g,isIgnoreNewlineTag=makeMap("pre,textarea",!0),shouldIgnoreFirstNewline=function(gt,$t){return gt&&isIgnoreNewlineTag(gt)&&$t[0]==="\n"};function decodeAttr(gt,$t){var Et=$t?encodedAttrWithNewLines:encodedAttr;return gt.replace(Et,function(Tt){return decodingMap[Tt]})}function parseHTML(gt,$t){for(var Et=[],Tt=$t.expectHTML,At=$t.isUnaryTag||no,Ct=$t.canBeLeftOpenTag||no,Pt=0,It,Nt,Ut=function(){if(It=gt,!Nt||!isPlainTextElement(Nt)){var Vt=gt.indexOf("<");if(Vt===0){if(comment.test(gt)){var Ht=gt.indexOf("-->");if(Ht>=0)return $t.shouldKeepComment&&$t.comment&&$t.comment(gt.substring(4,Ht),Pt,Pt+Ht+3),Mt(Ht+3),"continue"}if(conditionalComment.test(gt)){var Wt=gt.indexOf("]>");if(Wt>=0)return Mt(Wt+2),"continue"}var Kt=gt.match(doctype);if(Kt)return Mt(Kt[0].length),"continue";var qt=gt.match(endTag);if(qt){var Jt=Pt;return Mt(qt[0].length),Gt(qt[1],Jt,Pt),"continue"}var Xt=Ft();if(Xt)return Bt(Xt),shouldIgnoreFirstNewline(Xt.tagName,gt)&&Mt(1),"continue"}var Zt=void 0,rr=void 0,tr=void 0;if(Vt>=0){for(rr=gt.slice(Vt);!endTag.test(rr)&&!startTagOpen.test(rr)&&!comment.test(rr)&&!conditionalComment.test(rr)&&(tr=rr.indexOf("<",1),!(tr<0));)Vt+=tr,rr=gt.slice(Vt);Zt=gt.substring(0,Vt)}Vt<0&&(Zt=gt),Zt&&Mt(Zt.length),$t.chars&&Zt&&$t.chars(Zt,Pt-Zt.length,Pt)}else{var Qt=0,zt=Nt.toLowerCase(),nr=reCache[zt]||(reCache[zt]=new RegExp("([\\s\\S]*?)(]*>)","i")),rr=gt.replace(nr,function(er,or,cr){return Qt=cr.length,!isPlainTextElement(zt)&&zt!=="noscript"&&(or=or.replace(//g,"$1").replace(//g,"$1")),shouldIgnoreFirstNewline(zt,or)&&(or=or.slice(1)),$t.chars&&$t.chars(or),""});Pt+=gt.length-rr.length,gt=rr,Gt(zt,Pt-Qt,Pt)}if(gt===It)return $t.chars&&$t.chars(gt),"break"};gt;){var Dt=Ut();if(Dt==="break")break}Gt();function Mt(Vt){Pt+=Vt,gt=gt.substring(Vt)}function Ft(){var Vt=gt.match(startTagOpen);if(Vt){var Ht={tagName:Vt[1],attrs:[],start:Pt};Mt(Vt[0].length);for(var Wt=void 0,Kt=void 0;!(Wt=gt.match(startTagClose))&&(Kt=gt.match(dynamicArgAttribute)||gt.match(attribute));)Kt.start=Pt,Mt(Kt[0].length),Kt.end=Pt,Ht.attrs.push(Kt);if(Wt)return Ht.unarySlash=Wt[1],Mt(Wt[0].length),Ht.end=Pt,Ht}}function Bt(Vt){var Ht=Vt.tagName,Wt=Vt.unarySlash;Tt&&(Nt==="p"&&isNonPhrasingTag(Ht)&&Gt(Nt),Ct(Ht)&&Nt===Ht&&Gt(Ht));for(var Kt=At(Ht)||!!Wt,qt=Vt.attrs.length,Jt=new Array(qt),Xt=0;Xt=0&&Et[Kt].lowerCasedTag!==qt;Kt--);else Kt=0;if(Kt>=0){for(var Jt=Et.length-1;Jt>=Kt;Jt--)$t.end&&$t.end(Et[Jt].tag,Ht,Wt);Et.length=Kt,Nt=Kt&&Et[Kt-1].tag}else qt==="br"?$t.start&&$t.start(Vt,[],!0,Ht,Wt):qt==="p"&&($t.start&&$t.start(Vt,[],!1,Ht,Wt),$t.end&&$t.end(Vt,Ht,Wt))}}var onRE=/^@|^v-on:/,dirRE=/^v-|^@|^:|^#/,forAliasRE=/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/,forIteratorRE=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,stripParensRE=/^\(|\)$/g,dynamicArgRE=/^\[.*\]$/,argRE=/:(.*)$/,bindRE=/^:|^\.|^v-bind:/,modifierRE=/\.[^.\]]+(?=[^\]]*$)/g,slotRE=/^v-slot(:|$)|^#/,lineBreakRE=/[\r\n]/,whitespaceRE=/[ \f\t\r\n]+/g,decodeHTMLCached=cached(he$3.decode),emptySlotScopeToken="_empty_",warn,delimiters,transforms,preTransforms,postTransforms,platformIsPreTag,platformMustUseProp,platformGetTagNamespace;function createASTElement(gt,$t,Et){return{type:1,tag:gt,attrsList:$t,attrsMap:makeAttrsMap($t),rawAttrsMap:{},parent:Et,children:[]}}function parse(gt,$t){warn=$t.warn||baseWarn,platformIsPreTag=$t.isPreTag||no,platformMustUseProp=$t.mustUseProp||no,platformGetTagNamespace=$t.getTagNamespace||no,$t.isReservedTag,transforms=pluckModuleFunction($t.modules,"transformNode"),preTransforms=pluckModuleFunction($t.modules,"preTransformNode"),postTransforms=pluckModuleFunction($t.modules,"postTransformNode"),delimiters=$t.delimiters;var Et=[],Tt=$t.preserveWhitespace!==!1,At=$t.whitespace,Ct,Pt,It=!1,Nt=!1;function Ut(Mt){if(Dt(Mt),!It&&!Mt.processed&&(Mt=processElement(Mt,$t)),!Et.length&&Mt!==Ct&&Ct.if&&(Mt.elseif||Mt.else)&&addIfCondition(Ct,{exp:Mt.elseif,block:Mt}),Pt&&!Mt.forbidden)if(Mt.elseif||Mt.else)processIfConditions(Mt,Pt);else{if(Mt.slotScope){var Ft=Mt.slotTarget||'"default"';(Pt.scopedSlots||(Pt.scopedSlots={}))[Ft]=Mt}Pt.children.push(Mt),Mt.parent=Pt}Mt.children=Mt.children.filter(function(Gt){return!Gt.slotScope}),Dt(Mt),Mt.pre&&(It=!1),platformIsPreTag(Mt.tag)&&(Nt=!1);for(var Bt=0;Bt|^function(?:\s+[\w$]+)?\s*\(/,fnInvokeRE=/\([^)]*?\);*$/,simplePathRE=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/,keyCodes={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},keyNames={esc:["Esc","Escape"],tab:"Tab",enter:"Enter",space:[" ","Spacebar"],up:["Up","ArrowUp"],left:["Left","ArrowLeft"],right:["Right","ArrowRight"],down:["Down","ArrowDown"],delete:["Backspace","Delete","Del"]},genGuard=function(gt){return"if(".concat(gt,")return null;")},modifierCode={stop:"$event.stopPropagation();",prevent:"$event.preventDefault();",self:genGuard("$event.target !== $event.currentTarget"),ctrl:genGuard("!$event.ctrlKey"),shift:genGuard("!$event.shiftKey"),alt:genGuard("!$event.altKey"),meta:genGuard("!$event.metaKey"),left:genGuard("'button' in $event && $event.button !== 0"),middle:genGuard("'button' in $event && $event.button !== 1"),right:genGuard("'button' in $event && $event.button !== 2")};function genHandlers(gt,$t){var Et=$t?"nativeOn:":"on:",Tt="",At="";for(var Ct in gt){var Pt=genHandler(gt[Ct]);gt[Ct]&>[Ct].dynamic?At+="".concat(Ct,",").concat(Pt,","):Tt+='"'.concat(Ct,'":').concat(Pt,",")}return Tt="{".concat(Tt.slice(0,-1),"}"),At?Et+"_d(".concat(Tt,",[").concat(At.slice(0,-1),"])"):Et+Tt}function genHandler(gt){if(!gt)return"function(){}";if(Array.isArray(gt))return"[".concat(gt.map(function(Dt){return genHandler(Dt)}).join(","),"]");var $t=simplePathRE.test(gt.value),Et=fnExpRE.test(gt.value),Tt=simplePathRE.test(gt.value.replace(fnInvokeRE,""));if(gt.modifiers){var At="",Ct="",Pt=[],It=function(Dt){if(modifierCode[Dt])Ct+=modifierCode[Dt],keyCodes[Dt]&&Pt.push(Dt);else if(Dt==="exact"){var Mt=gt.modifiers;Ct+=genGuard(["ctrl","shift","alt","meta"].filter(function(Ft){return!Mt[Ft]}).map(function(Ft){return"$event.".concat(Ft,"Key")}).join("||"))}else Pt.push(Dt)};for(var Nt in gt.modifiers)It(Nt);Pt.length&&(At+=genKeyFilter(Pt)),Ct&&(At+=Ct);var Ut=$t?"return ".concat(gt.value,".apply(null, arguments)"):Et?"return (".concat(gt.value,").apply(null, arguments)"):Tt?"return ".concat(gt.value):gt.value;return"function($event){".concat(At).concat(Ut,"}")}else return $t||Et?gt.value:"function($event){".concat(Tt?"return ".concat(gt.value):gt.value,"}")}function genKeyFilter(gt){return"if(!$event.type.indexOf('key')&&"+"".concat(gt.map(genFilterCode).join("&&"),")return null;")}function genFilterCode(gt){var $t=parseInt(gt,10);if($t)return"$event.keyCode!==".concat($t);var Et=keyCodes[gt],Tt=keyNames[gt];return"_k($event.keyCode,"+"".concat(JSON.stringify(gt),",")+"".concat(JSON.stringify(Et),",")+"$event.key,"+"".concat(JSON.stringify(Tt))+")"}function on(gt,$t){gt.wrapListeners=function(Et){return"_g(".concat(Et,",").concat($t.value,")")}}function bind$2(gt,$t){gt.wrapData=function(Et){return"_b(".concat(Et,",'").concat(gt.tag,"',").concat($t.value,",").concat($t.modifiers&&$t.modifiers.prop?"true":"false").concat($t.modifiers&&$t.modifiers.sync?",true":"",")")}}var baseDirectives={on,bind:bind$2,cloak:noop$2},CodegenState=function(){function gt($t){this.options=$t,this.warn=$t.warn||baseWarn,this.transforms=pluckModuleFunction($t.modules,"transformCode"),this.dataGenFns=pluckModuleFunction($t.modules,"genData"),this.directives=extend$1(extend$1({},baseDirectives),$t.directives);var Et=$t.isReservedTag||no;this.maybeComponent=function(Tt){return!!Tt.component||!Et(Tt.tag)},this.onceId=0,this.staticRenderFns=[],this.pre=!1}return gt}();function generate(gt,$t){var Et=new CodegenState($t),Tt=gt?gt.tag==="script"?"null":genElement(gt,Et):'_c("div")';return{render:"with(this){return ".concat(Tt,"}"),staticRenderFns:Et.staticRenderFns}}function genElement(gt,$t){if(gt.parent&&(gt.pre=gt.pre||gt.parent.pre),gt.staticRoot&&!gt.staticProcessed)return genStatic(gt,$t);if(gt.once&&!gt.onceProcessed)return genOnce(gt,$t);if(gt.for&&!gt.forProcessed)return genFor(gt,$t);if(gt.if&&!gt.ifProcessed)return genIf(gt,$t);if(gt.tag==="template"&&!gt.slotTarget&&!$t.pre)return genChildren(gt,$t)||"void 0";if(gt.tag==="slot")return genSlot(gt,$t);var Et=void 0;if(gt.component)Et=genComponent(gt.component,gt,$t);else{var Tt=void 0,At=$t.maybeComponent(gt);(!gt.plain||gt.pre&&At)&&(Tt=genData(gt,$t));var Ct=void 0,Pt=$t.options.bindings;At&&Pt&&Pt.__isScriptSetup!==!1&&(Ct=checkBindingType(Pt,gt.tag)),Ct||(Ct="'".concat(gt.tag,"'"));var It=gt.inlineTemplate?null:genChildren(gt,$t,!0);Et="_c(".concat(Ct).concat(Tt?",".concat(Tt):"").concat(It?",".concat(It):"",")")}for(var Nt=0;Nt<$t.transforms.length;Nt++)Et=$t.transforms[Nt](gt,Et);return Et}function checkBindingType(gt,$t){var Et=camelize($t),Tt=capitalize(Et),At=function(It){if(gt[$t]===It)return $t;if(gt[Et]===It)return Et;if(gt[Tt]===It)return Tt},Ct=At("setup-const")||At("setup-reactive-const");if(Ct)return Ct;var Pt=At("setup-let")||At("setup-ref")||At("setup-maybe-ref");if(Pt)return Pt}function genStatic(gt,$t){gt.staticProcessed=!0;var Et=$t.pre;return gt.pre&&($t.pre=gt.pre),$t.staticRenderFns.push("with(this){return ".concat(genElement(gt,$t),"}")),$t.pre=Et,"_m(".concat($t.staticRenderFns.length-1).concat(gt.staticInFor?",true":"",")")}function genOnce(gt,$t){if(gt.onceProcessed=!0,gt.if&&!gt.ifProcessed)return genIf(gt,$t);if(gt.staticInFor){for(var Et="",Tt=gt.parent;Tt;){if(Tt.for){Et=Tt.key;break}Tt=Tt.parent}return Et?"_o(".concat(genElement(gt,$t),",").concat($t.onceId++,",").concat(Et,")"):genElement(gt,$t)}else return genStatic(gt,$t)}function genIf(gt,$t,Et,Tt){return gt.ifProcessed=!0,genIfConditions(gt.ifConditions.slice(),$t,Et,Tt)}function genIfConditions(gt,$t,Et,Tt){if(!gt.length)return Tt||"_e()";var At=gt.shift();if(At.exp)return"(".concat(At.exp,")?").concat(Ct(At.block),":").concat(genIfConditions(gt,$t,Et,Tt));return"".concat(Ct(At.block));function Ct(Pt){return Et?Et(Pt,$t):Pt.once?genOnce(Pt,$t):genElement(Pt,$t)}}function genFor(gt,$t,Et,Tt){var At=gt.for,Ct=gt.alias,Pt=gt.iterator1?",".concat(gt.iterator1):"",It=gt.iterator2?",".concat(gt.iterator2):"";return gt.forProcessed=!0,"".concat(Tt||"_l","((").concat(At,"),")+"function(".concat(Ct).concat(Pt).concat(It,"){")+"return ".concat((Et||genElement)(gt,$t))+"})"}function genData(gt,$t){var Et="{",Tt=genDirectives(gt,$t);Tt&&(Et+=Tt+","),gt.key&&(Et+="key:".concat(gt.key,",")),gt.ref&&(Et+="ref:".concat(gt.ref,",")),gt.refInFor&&(Et+="refInFor:true,"),gt.pre&&(Et+="pre:true,"),gt.component&&(Et+='tag:"'.concat(gt.tag,'",'));for(var At=0;At<$t.dataGenFns.length;At++)Et+=$t.dataGenFns[At](gt);if(gt.attrs&&(Et+="attrs:".concat(genProps(gt.attrs),",")),gt.props&&(Et+="domProps:".concat(genProps(gt.props),",")),gt.events&&(Et+="".concat(genHandlers(gt.events,!1),",")),gt.nativeEvents&&(Et+="".concat(genHandlers(gt.nativeEvents,!0),",")),gt.slotTarget&&!gt.slotScope&&(Et+="slot:".concat(gt.slotTarget,",")),gt.scopedSlots&&(Et+="".concat(genScopedSlots(gt,gt.scopedSlots,$t),",")),gt.model&&(Et+="model:{value:".concat(gt.model.value,",callback:").concat(gt.model.callback,",expression:").concat(gt.model.expression,"},")),gt.inlineTemplate){var Ct=genInlineTemplate(gt,$t);Ct&&(Et+="".concat(Ct,","))}return Et=Et.replace(/,$/,"")+"}",gt.dynamicAttrs&&(Et="_b(".concat(Et,',"').concat(gt.tag,'",').concat(genProps(gt.dynamicAttrs),")")),gt.wrapData&&(Et=gt.wrapData(Et)),gt.wrapListeners&&(Et=gt.wrapListeners(Et)),Et}function genDirectives(gt,$t){var Et=gt.directives;if(Et){var Tt="directives:[",At=!1,Ct,Pt,It,Nt;for(Ct=0,Pt=Et.length;Ct>>0}function containsSlotChild(gt){return gt.type===1?gt.tag==="slot"?!0:gt.children.some(containsSlotChild):!1}function genScopedSlot(gt,$t){var Et=gt.attrsMap["slot-scope"];if(gt.if&&!gt.ifProcessed&&!Et)return genIf(gt,$t,genScopedSlot,"null");if(gt.for&&!gt.forProcessed)return genFor(gt,$t,genScopedSlot);var Tt=gt.slotScope===emptySlotScopeToken?"":String(gt.slotScope),At="function(".concat(Tt,"){")+"return ".concat(gt.tag==="template"?gt.if&&Et?"(".concat(gt.if,")?").concat(genChildren(gt,$t)||"undefined",":undefined"):genChildren(gt,$t)||"undefined":genElement(gt,$t),"}"),Ct=Tt?"":",proxy:true";return"{key:".concat(gt.slotTarget||'"default"',",fn:").concat(At).concat(Ct,"}")}function genChildren(gt,$t,Et,Tt,At){var Ct=gt.children;if(Ct.length){var Pt=Ct[0];if(Ct.length===1&&Pt.for&&Pt.tag!=="template"&&Pt.tag!=="slot"){var It=Et?$t.maybeComponent(Pt)?",1":",0":"";return"".concat((Tt||genElement)(Pt,$t)).concat(It)}var Nt=Et?getNormalizationType(Ct,$t.maybeComponent):0,Ut=At||genNode;return"[".concat(Ct.map(function(Dt){return Ut(Dt,$t)}).join(","),"]").concat(Nt?",".concat(Nt):"")}}function getNormalizationType(gt,$t){for(var Et=0,Tt=0;Tt':'
',div.innerHTML.indexOf(" ")>0}var shouldDecodeNewlines=inBrowser$1?getShouldDecode(!1):!1,shouldDecodeNewlinesForHref=inBrowser$1?getShouldDecode(!0):!1,idToTemplate=cached(function(gt){var $t=query(gt);return $t&&$t.innerHTML}),mount=Vue.prototype.$mount;Vue.prototype.$mount=function(gt,$t){if(gt=gt&&query(gt),gt===document.body||gt===document.documentElement)return this;var Et=this.$options;if(!Et.render){var Tt=Et.template;if(Tt)if(typeof Tt=="string")Tt.charAt(0)==="#"&&(Tt=idToTemplate(Tt));else if(Tt.nodeType)Tt=Tt.innerHTML;else return this;else gt&&(Tt=getOuterHTML(gt));if(Tt){var At=compileToFunctions(Tt,{outputSourceRange:!1,shouldDecodeNewlines,shouldDecodeNewlinesForHref,delimiters:Et.delimiters,comments:Et.comments},this),Ct=At.render,Pt=At.staticRenderFns;Et.render=Ct,Et.staticRenderFns=Pt}}return mount.call(this,gt,$t)};function getOuterHTML(gt){if(gt.outerHTML)return gt.outerHTML;var $t=document.createElement("div");return $t.appendChild(gt.cloneNode(!0)),$t.innerHTML}Vue.compile=compileToFunctions;const vue_esm=Object.freeze(Object.defineProperty({__proto__:null,EffectScope,computed,customRef,default:Vue,defineAsyncComponent,defineComponent,del,effectScope,getCurrentInstance,getCurrentScope,h:h$7,inject,isProxy,isReactive,isReadonly,isRef,isShallow,markRaw,mergeDefaults,nextTick,onActivated,onBeforeMount,onBeforeUnmount,onBeforeUpdate,onDeactivated,onErrorCaptured,onMounted,onRenderTracked,onRenderTriggered,onScopeDispose,onServerPrefetch,onUnmounted,onUpdated,provide,proxyRefs,reactive,readonly,ref:ref$1,set,shallowReactive,shallowReadonly,shallowRef,toRaw,toRef,toRefs,triggerRef,unref,useAttrs,useCssModule,useCssVars,useListeners,useSlots,version:version$1,watch,watchEffect,watchPostEffect,watchSyncEffect},Symbol.toStringTag,{value:"Module"}));var Vue2=Vue;Vue.util.warn;function createApp(gt,$t){var Et,Tt={},At={config:Vue.config,use:Vue.use.bind(Vue),mixin:Vue.mixin.bind(Vue),component:Vue.component.bind(Vue),provide:function(Ct,Pt){return Tt[Ct]=Pt,this},directive:function(Ct,Pt){return Pt?(Vue.directive(Ct,Pt),At):Vue.directive(Ct)},mount:function(Ct,Pt){return Et||(Et=new Vue(Object.assign({propsData:$t},gt,{provide:Object.assign(Tt,gt.provide)})),Et.$mount(Ct,Pt),Et)},unmount:function(){Et&&(Et.$destroy(),Et=void 0)}};return At}function assign(gt){for(var $t=1;$t"u")){Pt=assign({},$t,Pt),typeof Pt.expires=="number"&&(Pt.expires=new Date(Date.now()+Pt.expires*864e5)),Pt.expires&&(Pt.expires=Pt.expires.toUTCString()),At=encodeURIComponent(At).replace(/%(2[346B]|5E|60|7C)/g,decodeURIComponent).replace(/[()]/g,escape);var It="";for(var Nt in Pt)Pt[Nt]&&(It+="; "+Nt,Pt[Nt]!==!0&&(It+="="+Pt[Nt].split(";")[0]));return document.cookie=At+"="+gt.write(Ct,At)+It}}function Tt(At){if(!(typeof document>"u"||arguments.length&&!At)){for(var Ct=document.cookie?document.cookie.split("; "):[],Pt={},It=0;It{this.resolve=$t,this.reject=Et})}}const hasOwnProperty$1=(()=>{const{hasOwnProperty:gt}=Object.prototype;return($t,Et)=>gt.call($t,Et)})(),isNonNullObject=gt=>typeof gt=="object"&>!==null,isFunction$1=gt=>typeof gt=="function",delay=gt=>new Promise($t=>setTimeout($t,gt)),memoize=(gt,$t=(...Et)=>Et[0])=>{const Et=new Map,Tt=new WeakMap;return(...At)=>{var Nt;const Ct=$t(...At),Pt=isNonNullObject(Ct)?Tt:Et,It=(Nt=Pt.get(Ct))!=null?Nt:gt(...At);return Pt.has(Ct)||Pt.set(Ct,It),It}},compareVersion=(gt,$t)=>{if(!gt||!$t)return Number.NaN;const Et=gt.split(".").map(At=>+At),Tt=$t.split(".").map(At=>+At);for(let At=0;At{var $t,Et;return(Et=($t=new RegExp("(?:".concat(gt,")\\/([\\d+.]+)")).exec(typeof navigator>"u"?"":navigator.userAgent))==null?void 0:$t[1])!=null?Et:""}),compareYodaVersion=gt=>compareVersion(getPlatformVersion("Yoda"),gt),compareKwaiAppVersion=gt=>compareVersion(getPlatformVersion("Kwai|ksNebula"),gt),system=(()=>{if(typeof navigator>"u")return"unknown";const{userAgent:gt,maxTouchPoints:$t}=navigator;return/android/iu.test(gt)?"Android":/iPhone|iPad|iPod/u.test(gt)||gt.includes("Mac")&&$t>1?"iOS":"unknown"})(),isAndroid=system==="Android",isIOS=system==="iOS",isYoda=()=>{var gt;return typeof window<"u"&&typeof((gt=window.__yodaBridge__)==null?void 0:gt.invoke)=="function"},isApp=gt=>!!getPlatformVersion(gt),isKwaiApp=isApp("Kwai|ksNebula"),SafeInteger=Number.MAX_SAFE_INTEGER||9007199254740991;let overflow=!1,_callbackId=1,_instanceId=genInstanceId();function genInstanceId(){const gt="".concat(SafeInteger),$t=Number(gt.slice(0,3))-100,Et=Math.floor(Math.random()*$t),Tt="".concat(Date.now()),At=Tt.slice(Tt.length-9),Ct=new Array(gt.length-12).fill(0).join("");return Number("".concat(Et).concat(At).concat(Ct))}function genCallbackId(gt){const $t=genNextId(gt);return $t>=SafeInteger?(overflow=!0,_callbackId=1,_instanceId=genInstanceId(),genCallbackId()):$t}function genNextId(gt){let $t=_instanceId+_callbackId++;for(;overflow||gt&>[$t];)$t=_instanceId+_callbackId++;return $t}function getUUId(gt){return genCallbackId(gt)}function debounce$2(gt,$t=300){let Et=null;return(...Tt)=>{clearTimeout(Et),Et=setTimeout(()=>{gt.apply(this,Tt)},$t)}}let yodaInstance=null;function setYoda(gt){yodaInstance=gt}function getYoda(){return yodaInstance}async function checkCanUse(gt,$t){const Tt=await getYoda().bridge("tool","canIUse",{namespace:gt,name:$t});return Tt.result=="1"&&Tt.canUse}const markStr$1="too_performance_";function getPerformanceId(){return markStr$1+getUUId()}function isPerformanceId(gt){return gt.startsWith(markStr$1)}const markStr="event_";function getEventId(gt){return markStr+getUUId(gt)}function getEventIdOnlyNumber(gt){return gt.replace(markStr,"")}function getEventIdByNumber(gt){return markStr+String(gt)}function isEventId(gt){return gt.startsWith(markStr)}const logArrayPool=[],logSessionMinTime=1e3*1,maxTime=30;var switchEnum;(function(gt){gt[gt.unload=0]="unload",gt[gt.open=1]="open",gt[gt.close=2]="close"})(switchEnum||(switchEnum={}));const isLocalBridge=gt=>["canIUse","getApiList"].includes(gt.name);let isSendLog=switchEnum.unload,getPageLoadDataPromise=null;const loggerSwitch=()=>{var Et,Tt;if(getPageLoadDataPromise)return getPageLoadDataPromise;const{promise:gt,resolve:$t}=new Deferred;if(getPageLoadDataPromise=gt,isSendLog==switchEnum.unload)if((Et=window.__yodaCommonDataObject__)!=null&&Et.sampleData){if(typeof window.__yodaCommonDataObject__.sampleData=="string")try{window.__yodaCommonDataObject__.sampleData=JSON.parse(window.__yodaCommonDataObject__.sampleData)}catch(At){window.__yodaCommonDataObject__.sampleData={}}isSendLog=(Tt=window.__yodaCommonDataObject__.sampleData)!=null&&Tt.bridgeHit?switchEnum.open:switchEnum.close,$t(isSendLog==switchEnum.open)}else getYoda().bridge("webview","getPageLoadData",{},({result:Ct,sampleData:Pt})=>{Ct==1?isSendLog=Pt!=null&&Pt.bridgeHit?switchEnum.open:switchEnum.close:isSendLog=switchEnum.close,$t(isSendLog==switchEnum.open)});else $t(isSendLog==switchEnum.open);return getPageLoadDataPromise};function sendLog(){window.__yodaBridge__.invoke("tool","sendPerformanceLog",JSON.stringify({data:logArrayPool}),getPerformanceId()),logArrayPool.length=0}const _logger=debounce$2(()=>{sendLog()},logSessionMinTime),getLog=(gt,$t,Et)=>{var At,Ct,Pt,It;const Tt={key:"bridge",value:{},dimension:{api:gt.name,namespace:gt.namespace},event_client_timestamp:$t,event_trigger_source:"H5",task_identifier:gt.callbackId,is_task_event:!0,task_status:""};switch(gt.type){case"invoke":Tt.value.h5_invoke_bridge_time=$t,Tt.task_status="START",(typeof((At=window.__yodaBridge__)==null?void 0:At.invoke)!="function"||typeof((It=(Pt=(Ct=window.webkit)==null?void 0:Ct.messageHandlers)==null?void 0:Pt.KMYYoda)==null?void 0:It.postMessage)!="function")&&(Tt.result=126002,Tt.error_msg="");break;case"callback":Tt.value.h5_receive_callback_time=$t,Tt.value.h5_invoke_bridge_time=Et,Tt.dimension.result_type=gt.resultCode,Tt.dimension.result_type&&(Tt.dimension.result_type=Tt.dimension.result_type.toString()),Tt.dimension.error_msg=gt.errorMsg,Tt.task_status="END";break;case"event":Tt.task_status="SUCCESS",delete Tt.dimension.api,delete Tt.dimension.namespace,Tt.dimension.event="";break}return Tt},logger=(gt,$t)=>{if(isLocalBridge(gt))return;const Et=Date.now().toString();return loggerSwitch().then(Tt=>{Tt&&(logArrayPool.push(getLog(gt,Et,$t)),logArrayPool.length>=maxTime?sendLog():_logger())}),Et};function createSingleDeferred(gt){let $t=null,Et=new Promise(Tt=>{$t=Tt});return gt&&(Et=Et.then(gt,gt)),{isMulti:!1,resolve:$t,promise:Et}}function createMultiDeferred(gt){const $t=new Promise(()=>{});return{isMulti:!0,resolve:gt,promise:$t}}const invokeMap={},deferredInvoke={pushMQ(gt=!1,$t,Et=!1){const Tt=Et?getEventId():getUUId(invokeMap),At=gt?createMultiDeferred($t):createSingleDeferred($t);return At.traceId=String(Tt),invokeMap[Tt]=At,At},removeMQ(gt){invokeMap[gt]=void 0},create(gt,$t,Et=!1,Tt){const At=this.pushMQ(Et,Tt);At.namespace=gt,At.name=$t;const Ct=logger({namespace:gt,name:$t,type:"invoke",callbackId:At.traceId});return invokeMap[At.traceId].startTime=Ct,{id:At.traceId,promise:At.promise}},resolve(gt,$t){if(isPerformanceId(gt))return;const Et=invokeMap[gt];Et&&(Et.resolve($t),Et.isMulti||this.removeMQ(gt),!isEventId(gt)&&logger({namespace:Et.namespace,name:Et.name,type:"callback",callbackId:Et.traceId,resultCode:$t.result},Et.startTime))},reject(gt,$t){const Et=invokeMap[gt];Et&&(Et.resolve($t),Et.isMulti||this.removeMQ(gt),!isEventId(gt)&&logger({namespace:Et.namespace,name:Et.name,type:"callback",callbackId:Et.traceId,resultCode:$t.result,errorMsg:$t.message},Et.startTime))}},BRIDGE_TYPE={noCallbackList:["popBack","exitWebView"],onClickList:["setPhysicalBackButton","setTopLeftBtn","setTopLeftSecondBtn","setTopRightBtn","setTopRightSecondBtn"],handlerList:["on","off"]},NAMESPACE_2_GLOBALVAR={kwai:"Kwai",kwaiAd:"KwaiAd",kwaiAdThird:"KwaiAdThird",kwaiMerchant:"KwaiMerchant",kwaiLive:"KwaiLive",kspay:"kspay",Kwai:"Kwai",KwaiAd:"KwaiAd",KwaiAdThird:"KwaiAdThird",KwaiMerchant:"KwaiMerchant",KwaiLive:"KwaiLive"},{noCallbackList,onClickList,handlerList}=BRIDGE_TYPE;function generateUUID(gt=!0){let $t=new Date().getTime();return typeof performance<"u"&&typeof performance.now=="function"&&($t+=performance.now()),(gt?"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx":"xxxxxxxx_xxxx_4xxx_yxxx_xxxxxxxxxxxx").replace(/[xy]/g,Tt=>{const At=($t+Math.random()*16)%16|0;return $t=Math.floor($t/16),(Tt==="x"?At:At&3|8).toString(16)})}function generateUUCallbackFunction(gt,$t,Et){const Tt=generateUUID(!1),At="yoda_kuaishou_plugin_callback_".concat(Et,"_").concat(Tt);return window[At]=function(Ct){if(typeof Ct=="string")try{Ct=JSON.parse(Ct)}catch(Pt){console.warn(Pt)}isFunction$1(gt)?gt.call(window,Ct):typeof gt=="string"&&isFunction$1(window[gt])&&window[gt].call(window,Ct),$t||delete window[At]},At}function transformFuncToURL(gt,$t){const Et=gt;return gt&&Array.isArray(gt.actions)&&(Et.actions=gt.actions.map(Tt=>(Tt&&Tt.url&&isFunction$1(Tt.url)&&(Tt.url=generateUUCallbackFunction(Tt.url,!0,$t)),Tt))),Et}const handlerCbMap={};function generateHandlerFunction(gt,$t){let Et="",Tt=null;if(Object.keys(handlerCbMap).some(At=>{const Ct=handlerCbMap[At];return Ct===gt?(Tt=Ct,Et=At,!0):!1}),Tt!==gt&>){const At=generateUUCallbackFunction(gt,!0,$t);handlerCbMap[At]=gt,Et=At}return Et}function bridgeParamsHandler(gt,$t,Et,Tt){let At={...Et};const Ct="".concat(gt,"_").concat($t);if(onClickList.includes($t))At.onClick=generateUUCallbackFunction(At.onClick,!0,Ct);else if(noCallbackList.includes($t))At=null;else if(handlerList.includes($t)){const Pt=generateUUCallbackFunction(Tt,!1,Ct);At.handler&&isFunction$1(At.handler)&&(At.handler=generateHandlerFunction(At.handler,Ct)),At.callback=Pt}else if($t==="showDialog"){const{positiveButton:Pt,negativeButton:It,neutralButton:Nt}=At;Pt&&(At.positiveButton=transformFuncToURL(Pt,Ct)),It&&(At.negativeButton=transformFuncToURL(It,Ct)),Nt&&(At.neutralButton=transformFuncToURL(Nt,Ct))}else if(Object.keys(NAMESPACE_2_GLOBALVAR).includes(gt)){const Pt=generateUUCallbackFunction(Tt,!0,Ct);At.callback=At.callback||Pt}return At}const getMultiInstanceError=()=>new Error("当前环境存在 Yoda 多实例问题,详细请参考 https://docs.corp.kuaishou.com/k/home/VbQx2ulc6v3M/fcADLOKqHyHpSr7hiCKKQVtVM"),setupMultiInstanceGuard=()=>{let{__yodaBridgeCallback__:gt}=window;if(typeof gt=="function")throw getMultiInstanceError();Object.defineProperty(window,"__yodaBridgeCallback__",{get(){return gt},set($t){if(gt)throw getMultiInstanceError();gt=$t}})};let currentMode="production";const getCurrentMode=()=>currentMode,setCurrentMode=gt=>{currentMode=gt},loggerMethods=["debug","info","log","warn","error"],createLogger=gt=>Object.fromEntries(loggerMethods.map($t=>[$t,gt($t)])),print=(gt,$t,...Et)=>{getCurrentMode()!=="production"&&console[$t]("[".concat(gt,"]"),...Et)},console$1=createLogger(gt=>(...$t)=>print("@yoda/bridge",gt,...$t)),invoke$1=async gt=>{var Mt;const{namespace:$t,name:Et,params:Tt,multiCallback:At,callback:Ct}=gt,Pt=NAMESPACE_2_GLOBALVAR[$t],{id:It,promise:Nt}=deferredInvoke.create($t,Et,At,Ct),Ut=Pt||$t,Dt=Ft=>{invokeCallback(It,Ft)};return gt.namespace=Ut==="Kwai"&&typeof navigator<"u"&&navigator.userAgent.includes("livemate/")?"livemate":Ut,gt.params=(Mt=bridgeParamsHandler(Ut,Et,Tt,Dt))!=null?Mt:{},console$1.info("Invoking '".concat(gt.namespace,".").concat(gt.name,"'"),gt.params),isIOS&&!window.webkit&&compareYodaVersion("2.10.9.2")<0||window.__yodaBridge__.invoke(gt.namespace,gt.name,JSON.stringify(gt.params),String(It)),Nt},invokeCallback=(gt,$t)=>{isIOS&&compareYodaVersion("2.3.7")<0&&(gt="".concat(gt));const Et=typeof $t=="string"?JSON.parse($t):$t;(Et==null?void 0:Et.result)===1?deferredInvoke.resolve(gt,Et):deferredInvoke.reject(gt,Et)};typeof window<"u"&&(setupMultiInstanceGuard(),window.__yodaBridgeCallback__=invokeCallback);const apiSet=new Set,invokeAndroid9920=async gt=>{var It;const{namespace:$t,name:Et,params:Tt,multiCallback:At,callback:Ct}=gt;if(!apiSet.size){const Nt=await invoke$1({namespace:"tool",name:"getApiList",params:{}});Nt.result===1&&Array.isArray(Nt.apiList)&&Nt.apiList.forEach(({namespace:Ut,name:Dt})=>apiSet.add("".concat(Ut,".").concat(Dt)))}const Pt=apiSet.has("".concat((It=NAMESPACE_2_GLOBALVAR[$t])!=null?It:$t,".").concat(Et));return new Promise(Nt=>{if(Pt)invoke$1({namespace:$t,name:Et,params:Tt,multiCallback:At,callback:Ct}).then(Nt);else{const Ut={result:125004};Ct==null||Ct(Ut),Nt(Ut)}})};let currentContainer=null;const getContainer=()=>currentContainer,setContainer=gt=>{currentContainer=gt},getContext=({initialBridge:gt,initialParams:$t})=>({bridge:gt,params:$t});class BridgeError extends Error{constructor($t,Et,Tt,At){super($t),this.name="BridgeError",this.message=$t,this.code=Et,this.rawRes=At,this.context=getContext(Tt)}toJSON(){return{name:this.name,message:this.message,code:this.code,context:this.context}}}const isBridgeError=gt=>gt instanceof BridgeError,getLocation=async({useLastLocationWhileLimited:gt=!1,...$t})=>{const{invoke:Et}=getContainer();if(compareKwaiAppVersion("10.1.30")<0){const{biz:Tt,force:At,statKey:Ct,alertScene:Pt,updateLocationScene:It,...Nt}=$t,Dt={...Nt,biz_type:Tt,forced_permission_request:typeof At>"u"?2:At?1:3};try{const{data:{longitude:Bt,latitude:Gt}}=await Et("kwai.syncLocationWithPermissionCheck",{...Dt,forced_permission_request:3});return{longitude:Bt,latitude:Gt}}catch(Bt){}await Et("kwai.requestLocationPermissionWithPermissionCheck",Dt);const{data:{longitude:Mt,latitude:Ft}}=await Et("kwai.syncLocationWithPermissionCheck",Dt);return{longitude:Mt,latitude:Ft}}if(isAndroid&&compareKwaiAppVersion("10.3.30")<0){const{updateLocationScene:Tt=""}=$t;Object.assign($t,{useInterval:!Tt})}try{const{longitude:Tt,latitude:At}=await Et("system.requestLocation",$t);return{longitude:Tt,latitude:At}}catch(Tt){if(!isBridgeError(Tt))throw Tt;if(Tt.code===10014&>){const{longitude:At,latitude:Ct}=await Et("system.getLocationCityInfo",{biz:$t.biz});if(typeof At=="number"&&typeof Ct=="number")return{longitude:At,latitude:Ct}}throw Tt}},apis={getLocation},bridgeToLegacyKwaiBridge=Object.fromEntries(Object.entries({advertise:["startFansTopLivePlay","startNeoAdVideo"],feed:["authorizationStatusForCalendar","changeEventForCalendar","closeChildLock","getAddressBookAccessStatus","getCoronaTvChasingData","getFeed","openDetailPage","openFansGroup","setSettingEntryForCourse","startPlayLongVideo","updateDeviceBit","updateUserRecoBit","updateWeatherInfo","userIncentivesUpdateTasks"],game:["addShortcutToDesktop","appointGame","changeAppointStatus","gameSendLog","gameTaskSelectImage","getAppointStatus","getWebViewDisplayType","kgPageDidShowed","openNativeGamecenter"],growth:["getDeviceSecretInfo","unionPhoneNumber"],im:["setEnableIMTip"],live:["deleteSubscribe","liveReservationNotification","openLiveQuizLive","showSubscribeEditDialog","showSubscribeSelectPhotoDialog","subscribeLive","unsubscribeLive"],merchant:["closeLiveMerchantFloatingWindow","getLatestImage","getSidToken","loadUrlOnNewMerchantPage","merchantSetPhotoPlayStatus","onItemSelected","popupToFollow","querySessionIsStickyOnTop","reqSessionStickyOnTopWithThread","requestLocationAuthorization"],minigame:["publishSogameVideo"],pay:["authThirdPartyAccount","bindWithdrawType","couponPay","hasImportSdk","nebulaStartGatewayWithdraw","openKspayWebView","sfBindWithdrawType","startDeposit","startGatewayPay","startGatewayWithdraw","startHalfScreenRecharge","startKspayOrderPrepay"],platform:["getDarkMode","openWechatMiniProgram","sendSMS","startFaceRecognition"],post:["cancelJsInjectUpload","captureCertVideo","deleteCacheVideoByPhotoId","editAtlas","editDraft","editSmartAlbum","getEditDraftData","getSmartAlbumData","getVideoUploadStatus","intownShare","postAtlas","postVideo","preloadMagicFace","previewVideo","reUploadShopVideo","reeditPhoto","resumeVideoUpload","retryJsInjectUpload","saveImage","saveTempImages","selectAndUploadMedia","selectImage","selectMixMediasAndUpload","selectVideoAndUpload","startAudioRecord","uploadCertVideo","uploadShopVideo","uploadVideoFromAlbum","verifyLiveUser"],social:["addTokenBlockShareId","bindPhone","bindRiskPreCheck","decryptContactsName","enterGroupChat","followUser","joinGroup","login","logout","mobileQuickAuthInfo","mobileQuickLoginInfo","needUpdateProfile","requestFollowUserV2","selectCountryPhoneCode","sendIMMessage","sendImFriendMessage","setPageFollowRefer","setShareTokenToClipBoard","share","startAuthActivity","verifyAccount","verifySMSCode","verifyThirdPartyLogin","wechatLogin"],system:["collapseKeyboard","getPushPermission","getServerTime","gete2","openPushPermission"],tool:["getClipBoard","getExpTagTransList","loadUrlOnNewPage","openBrowser","scanCode"],ui:["selectCity","showBottomSheet","showPicker"],webview:["clearClipBoard","exitWebView","getABTest","getAppEnvironment","getDeviceInfo","hasInstalledApp","hideNavigationBar","popBack","resetTopButtons","setClipBoard","setPageTitle","setSlideBack","setTopLeftBtn","setTopLeftSecondBtn","setTopRightBtn","setTopRightSecondBtn","submitData"]}).flatMap(([gt,$t])=>$t.map(Et=>["".concat(gt,".").concat(Et),"kwai.".concat(Et)]))),invalidResultBridges=["social.currentUserInfo","post.draftRecommendPhotos","post.draftRecommendPublishPhotos","kwai.KSVerifyRealNameInfo","kwai.verifyRealNameInfo","component.aliyunVerifyRealNameInfo","component.verifyRealNameInfo"],multipleCallbacksBridges=["component.download","kwai.download","kwai.downloadThirdPartyAPP","kwai.startNFC","kwaiAd.callAdBridge","kwaiAd.callCardHandler","pay.startHalfScreenRecharge","post.postVideo","post.reUploadShopVideo","post.selectImage","post.uploadShopVideo","post.selectMixMediasAndUpload","post.launchAICut","advertise.startNeoTask","kwaiLive.subscribeChannel"],multipleCallbacksBridgeSet=new Set(multipleCallbacksBridges),useCallbackBridgeSet=new Set([...invalidResultBridges,...multipleCallbacksBridges]),version="2.0.12",globalConfig={get mode(){return getCurrentMode()},set mode(gt){setCurrentMode(gt),console$1.info("You're currently running version ".concat(version," in ").concat(gt," mode."))}},setGlobalConfig=gt=>{Object.assign(globalConfig,gt)},transformConfig=gt=>{const $t=[],Et=At=>{$t.push(Ct=>{const Pt=At[Ct.bridge];return typeof Pt>"u"?Ct:{...Ct,bridge:Pt}})},Tt=At=>{$t.push(Ct=>{const Pt=At[Ct.bridge];if(typeof Pt>"u")return Ct;const It={...Pt,...Ct.params};return{...Ct,params:It}})};return gt.bridge==="tool.checkAppInstalled"&&Tt({[gt.bridge]:{identifier:gt.params[isAndroid?"android":"ios"]}}),isIOS&&compareKwaiAppVersion("9.10.11")>=0&&Et({"hybrid.getHybridStatus":"webview.pageContentStatus","hybrid.getAndUpdateHybridDetail":"webview.pageContentInfo","hybrid.preloadVideoList":"media.pvList","hybrid.isVideoFullyCached":"media.vReady"}),isIOS&&compareKwaiAppVersion("11.1.40")<0&&Et({"advertise.startNeoAdVideo":"kwai.startNeoAdVideo"}),isIOS&&compareKwaiAppVersion("10.7.20")<0&&Et({"merchant.getSidToken":"kwai.getSidToken"}),isAndroid&&compareKwaiAppVersion("10.6.50")<0&&Et({"ui.setStatusBarStyle":"kwai.setStatusBarStyle"}),(compareKwaiAppVersion("10.4.30")<0||!isKwaiApp)&&Et(bridgeToLegacyKwaiBridge),isIOS&&compareKwaiAppVersion("10.4.10")<0&&Tt({"system.startVibrate":{strength:"low",duration:300}}),(compareKwaiAppVersion("10.3.20")<0||!isKwaiApp)&&Et({"webview.exitCurrentWebView":"kwai.".concat(isIOS?"exitCurrentWebview":"exitWebView")}),compareKwaiAppVersion("9.6.20")<0&&$t.push(At=>{const{bridge:Ct}=At;return["syncLocationWithPermissionCheck","getLocationWithPermissionCheck","requestLocationPermissionWithPermissionCheck"].some(Pt=>Ct.endsWith(Pt))?{...At,bridge:Ct.replace("WithPermissionCheck","")}:At}),$t.reduce((At,Ct)=>Ct(At),gt)},getInvocationConfig=gt=>{const[$t,Et={},Tt]=gt,[At,Ct]=typeof Tt=="function"?[{},Tt]:[Tt!=null?Tt:{}];return{initialBridge:$t,initialParams:Et,bridge:$t,params:Et,options:At,callback:Ct}},getLegacyErrorMessage=gt=>hasOwnProperty$1(gt,"error_msg")&&typeof gt.error_msg=="string"?gt.error_msg:"",isIntrinsicAPI=gt=>gt.bridge.startsWith("yoda."),invokeAPI=gt=>{const{bridge:$t,params:Et}=gt,[,Tt]=$t.split("."),At=apis[Tt];return At(Et)},invokeBridge=gt=>{const $t=getYoda(),{initialBridge:Et,bridge:Tt,params:At,callback:Ct}=gt,[Pt,It]=Tt.split(".");return useCallbackBridgeSet.has(Et)?($t.bridge(Pt,It,At,Nt=>{console$1.info("Received a response from '".concat(Tt,"'"),Nt),Ct==null||Ct(Nt)},multipleCallbacksBridgeSet.has(Et)),Promise.resolve()):new Promise((Nt,Ut)=>{$t.bridge(Pt,It,At,Dt=>{var Bt;if(console$1.info("Received a response from '".concat(Tt,"'"),Dt),Dt.result===1){const{result:Gt,...Vt}=Dt;Nt(Vt);return}const{message:Mt=getLegacyErrorMessage(Dt)}=Dt,Ft=new BridgeError(Mt,Dt.result,gt,Dt);(Bt=globalConfig.errorHandler)==null||Bt.call(globalConfig,Ft),Ut(Ft)})})},invoke=async(...gt)=>{var $t,Et;try{const Tt=getInvocationConfig(gt);if(!isYoda())throw new BridgeError(["Cannot invoke bridge","in non-Yoda environment."].join(" "),125014,Tt,null);const At=transformConfig(Tt),{options:{timeout:Ct=($t=globalConfig.timeout)!=null?$t:0}}=At,Pt=isIntrinsicAPI(At)?invokeAPI(At):invokeBridge(At);return Ct>0&&Number.isFinite(Ct)?await Promise.race([Pt,delay(Ct).then(()=>Promise.reject(new BridgeError("Bridge invocation timed out.",125010,At,null)))]):await Pt}catch(Tt){throw isBridgeError(Tt)&&((Et=globalConfig.errorHandler)==null||Et.call(globalConfig,Tt)),Tt}},legacyEventTypes=new Set(["native_visible","native_background","native_foreground","native_will_leave","native_leave","native_reentry","native_loadPage","native_pageFinished","native_userDidLogin","native_userDidLogout","native_networkChanged","native_screenshot_event","native_web_view_display_mode_changed","native_share_dialog_event","native_shake","native_darkModeChange"]),addListener$1=async(gt,$t,Et)=>{if(legacyEventTypes.has(gt)){await invoke("kwai.on",{type:gt,handler:$t});return}await invoke("event.addEventListener",{type:typeof(Et==null?void 0:Et.data)>"u"?gt:{type:gt,options:Et.data},listener:$t})},removeListener$1=async(gt,$t)=>{if(legacyEventTypes.has(gt)){await invoke("kwai.off",{type:gt,handler:$t});return}await invoke("event.removeEventListener",{type:gt,listener:$t})},eventMQ={};function addListener(gt,$t,Et){const Tt=eventMQ[gt]||{callbackId:Et,eventRecord:{}},At=getUUId();$t.__yodaCallbackId__[gt]=String(At),Tt.eventRecord[At]=$t,eventMQ[gt]=Tt}function createCb(gt){return function($t){const Et=eventMQ[gt];Object.keys((Et==null?void 0:Et.eventRecord)||{}).forEach(Tt=>Et.eventRecord[Number(Tt)](JSON.parse(JSON.stringify($t))))}}function getCallbackIdByType(gt){const $t=eventMQ[gt];return getEventIdByNumber($t.callbackId)}function removeListener(gt,$t){const Et=eventMQ[gt],Tt=$t.__yodaCallbackId__[gt];delete Et.eventRecord[Number(Tt)],delete $t.__yodaCallbackId__[gt],hasListener(gt)||delete eventMQ[gt]}function hasListener(gt){const $t=eventMQ[gt];return Object.keys(($t==null?void 0:$t.eventRecord)||{}).length>0}var Direction;(function(gt){gt.x="x",gt.y="y",gt.z="z"})(Direction||(Direction={}));const SHAKE_EVENT="shaked",SHAKE_START_EVENT="shake-start",SHAKE_END_EVENT="shake-end",JUDGE_STOP_TIME=1e3,DEFAULT_SETTING={level:2,times:3,intervalTime:1300,iOSIntervalTime:500,androidIntervalTime:1300,isEmitImmediately:!0},ANDROID_LEVEL_MAP={1:{basic:13,total:450},2:{basic:16,total:700},3:{basic:20,total:1100}},IOS_LEVEL_MAP={1:{basic:9,total:220},2:{basic:12,total:400},3:{basic:14,total:500}};class ShakeHandler{constructor($t){this.shakeConfig={},this.shakedArr=[],this.isChecking=!1,this.nowStatus={x:0,y:0,z:0},this.lastStatus={x:0,y:0,z:0},this.stopMark=null,this.checkIsShakeStoped=!1,this.notEmitButShaked=!0,this.isShakeStarted=!1,this.isAndroid=!1,this.isArrivedConfigStandard=!1,this.levelMap=ANDROID_LEVEL_MAP,this.dispatchEvent=null,this.setStillShaking=debounce$2(()=>this.notShaking(),JUDGE_STOP_TIME),this.dispatchEvent=$t.dispatchEvent,this.isAndroid=$t.isAndroid,this.levelMap=this.isAndroid?ANDROID_LEVEL_MAP:IOS_LEVEL_MAP}setOptions($t){$t?(this.shakeConfig={...DEFAULT_SETTING,...$t},this.shakeConfig.times=this.isAndroid?this.shakeConfig.times-1:(this.shakeConfig.times-1)*2,this.shakeConfig.intervalTime=this.isAndroid?this.shakeConfig.androidIntervalTime:this.shakeConfig.iOSIntervalTime):this.shakeConfig={...DEFAULT_SETTING}}resetShakeStatus($t){this.shakedArr=[],this.isChecking=!1,this.notEmitButShaked=!1,$t&&(this.isArrivedConfigStandard=!1,this.isShakeStarted=!1)}checkIsShake($t){if(this.isChecking=!0,Object.keys(this.nowStatus).forEach(Et=>this.nowStatus[Et]=$t[Et]*9.8),this.judgeArrivedTerminal()){this.lastStatus={x:0,y:0,z:0},this.handleShakeHappend(),this.setStillShaking(),this.isChecking=!1;return}this.judgeLikelyShake()?this.handleArrivedStandard():this.isChecking=!1}judgeLikelyShake(){const{x:$t,y:Et,z:Tt}=this.nowStatus,{basic:At,total:Ct}=this.levelMap[this.shakeConfig.level];return $t>At||Et>At||Tt>At||$t*$t+Et*Et+Tt*Tt>Ct}judgeArrivedTerminal(){let $t=0,Et=0,Tt=Direction.x;return Object.keys(this.nowStatus).forEach(At=>{Et=Math.abs(this.lastStatus[At]-this.nowStatus[At]),$t0?$t-this.shakedArr[this.shakedArr.length-1]<=Et?this.shakedArr.push($t):(this.shakedArr=[],this.isChecking=!1):this.shakedArr.push($t),this.shakedArr.length>=this.shakeConfig.times?this.handleArrivedEmitStandard():this.isChecking=!1}handleArrivedEmitStandard(){this.isArrivedConfigStandard=!0,this.resetShakeStatus(),this.shakeConfig.isEmitImmediately?this.dispatchEvent({type:SHAKE_EVENT,data:{}}):this.notEmitButShaked=!0}checkDoDelayEmit(){this.notEmitButShaked&&this.checkIsShakeStoped&&!this.shakeConfig.isEmitImmediately&&this.dispatchEvent({type:SHAKE_EVENT,data:{}}),this.isShakeStarted&&this.dispatchEvent({type:SHAKE_END_EVENT,data:{isArrivedConfigStandard:this.isArrivedConfigStandard}}),this.resetShakeStatus(!0)}}const interval=60;let shakeHandler=null,checkIsShake=null;const startMonitorShake=async()=>{const gt=getYoda(),$t=await gt.bridge("system","startAccelerometer",{interval});checkIsShake=shakeHandler.checkIsShake.bind(shakeHandler);const Et=await gt.bridge("event","addEventListener",{type:"accelerometer-change",listener:checkIsShake});if($t.result===1&&Et.result!==1&&stopMonitorShake(),$t.result!==1||Et.result!==1)throw new Error("摇一摇初始化失败,请稍后重试。AccelerometerRes:".concat(JSON.stringify($t),";eventRes:").concat(JSON.stringify(Et)))},validateOption=gt=>{if(!gt)return;const{level:$t,times:Et,isEmitImmediately:Tt}=gt;if($t!==void 0&&!ANDROID_LEVEL_MAP[$t])throw new Error("请传入正确的level,可选值为1、2、3");if(Et!==void 0){if(!Number.isInteger(Et))throw new Error("times应为整数");if(Et<1)throw new Error("times应大于1")}if(Tt!==void 0&&typeof Tt!="boolean")throw new Error("isEmitImmediately应为boolean类型")},initShakeHandler=async gt=>{const $t=getYoda();if(!await checkCanUse("system","startAccelerometer"))throw new Error("当前APP暂不支持摇一摇");if(shakeHandler)throw new Error("当前存在尚未结束监听的摇一摇");const Et=async Tt=>$t.bridge("event","dispatchEvent",Tt);shakeHandler=new ShakeHandler({dispatchEvent:Et,isAndroid}),validateOption(gt),shakeHandler.setOptions(gt),shakeHandler.resetShakeStatus(),await startMonitorShake.bind($t)()},stopMonitorShake=async()=>{const gt=getYoda();if(!await checkCanUse("system","stopAccelerometer"))throw new Error("当前APP暂不支持摇一摇");shakeHandler=null;const $t=await gt.bridge("event","removeEventListener",{type:"accelerometer-change",listener:checkIsShake}),Et=await gt.bridge("system","stopAccelerometer",{});if($t.result!==1||Et.result!==1)throw new Error("摇一摇停止监听失败。stopRes:".concat(JSON.stringify(Et),";eventRes:").concat(JSON.stringify($t)))},yodaCustomEvent={shaked:SHAKE_EVENT},eventToInitMap={[yodaCustomEvent.shaked]:initShakeHandler},handleEventUnregisterMap={[yodaCustomEvent.shaked]:stopMonitorShake},addEventListener$1=(gt,$t)=>{var Ut;const{type:Et,listener:Tt}=gt,At=typeof Et=="string"?Et:Et.type,Ct=typeof Et=="string"?{}:Et.options;if((Ut=eventToInitMap[At])==null||Ut.call(eventToInitMap,Ct),!Tt.__yodaCallbackId__&&(Tt.__yodaCallbackId__={}),Tt.__yodaCallbackId__[At])throw new Error("addEventListener ".concat(At," 的 listener 已经被绑定过了"));const Pt=hasListener(At);let It=null,Nt=Promise.resolve();if(Pt)isFunction$1($t)&&$t({result:1});else{const Dt=deferredInvoke.pushMQ(!0,createCb(At),!0);It=parseInt(getEventIdOnlyNumber(Dt.traceId)),Nt=invoke$1({namespace:"event",name:"addEventListener",params:{type:At,listener:String(Dt.traceId)},callback:$t})}return addListener(At,Tt,It),Nt},removeEventListener$1=(gt,$t)=>{var Ct;const{type:Et,listener:Tt}=gt;(Ct=handleEventUnregisterMap[Et])==null||Ct.call(handleEventUnregisterMap);let At=Promise.resolve();if(Tt.__yodaCallbackId__){const Pt=getCallbackIdByType(Et);removeListener(Et,Tt),hasListener(Et)||(At=invoke$1({namespace:"event",name:"removeEventListener",params:{type:Et,listener:Pt},callback:$t}),deferredInvoke.removeMQ(Pt))}return At},yoda={bridge:(gt,$t,Et,Tt,At=!1)=>{const Ct={namespace:gt,name:$t,params:Et,multiCallback:At,callback:Tt};if(gt==="event"){if($t==="addEventListener")return addEventListener$1(Et,Tt);if($t==="removeEventListener")return removeEventListener$1(Et,Tt)}return compareKwaiAppVersion("9.9.20")===0&&isAndroid?invokeAndroid9920(Ct):invoke$1(Ct)}};setYoda(yoda);setContainer({invoke,addListener:addListener$1,removeListener:removeListener$1});const yoda$1=Object.freeze(Object.defineProperty({__proto__:null,addListener:addListener$1,invoke,isBridgeError,removeListener:removeListener$1,setGlobalConfig,version},Symbol.toStringTag,{value:"Module"}));(function($t,Et){typeof exports=="object"&&typeof module=="object"?module.exports=Et():typeof define=="function"&&define.amd?define([],Et):typeof exports=="object"?exports.Jose=Et():$t.Jose=Et()})(window,function(){return function(gt){var $t={};function Et(Tt){if($t[Tt])return $t[Tt].exports;var At=$t[Tt]={i:Tt,l:!1,exports:{}};return gt[Tt].call(At.exports,At,At.exports,Et),At.l=!0,At.exports}return Et.m=gt,Et.c=$t,Et.d=function(Tt,At,Ct){Et.o(Tt,At)||Object.defineProperty(Tt,At,{enumerable:!0,get:Ct})},Et.r=function(Tt){typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(Tt,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(Tt,"__esModule",{value:!0})},Et.t=function(Tt,At){if(1&At&&(Tt=Et(Tt)),8&At||4&At&&typeof Tt=="object"&&Tt&&Tt.__esModule)return Tt;var Ct=Object.create(null);if(Et.r(Ct),Object.defineProperty(Ct,"default",{enumerable:!0,value:Tt}),2&At&&typeof Tt!="string")for(var Pt in Tt)Et.d(Ct,Pt,function(It){return Tt[It]}.bind(null,Pt));return Ct},Et.n=function(Tt){var At=Tt&&Tt.__esModule?function(){return Tt.default}:function(){return Tt};return Et.d(At,"a",At),At},Et.o=function(Tt,At){return Object.prototype.hasOwnProperty.call(Tt,At)},Et.p="",Et(Et.s=3)}([function(gt,$t){function Et(Tt){return(Et=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(At){return typeof At}:function(At){return At&&typeof Symbol=="function"&&At.constructor===Symbol&&At!==Symbol.prototype?"symbol":typeof At})(Tt)}(function(){var Tt=function(Mt){return Mt==null?null:Mt.__proto__},At=Object.create,Ct=function(Mt,Ft){return Object.prototype.hasOwnProperty.call(Mt,Ft)||Et(Mt[Ft])==="object"&&Mt[Ft]!==void 0},Pt=function(Mt,Ft,Bt){return Object.defineProperty(Mt,Ft,Bt)},It=["break","case","catch","continue","default","delete","do","else","finally","for","function","if","in","instanceof","new","return","switch","this","throw","try","typeof","var","void","while","with","let","enum","const","debugger","export","extends","import","super"],Nt=function(Mt){return It.includes(Mt)},Ut=function(Mt){return Mt!=Mt};$t.prototypeOf=Tt,$t.create=At,$t.hasProp=Ct,$t.isArray=function(){if(typeof Array.isArray!="function")return obj instanceof Array},$t.defProp=Pt,$t.checkIdentifier=Nt,$t.isNaNP=Ut}).call(this)},function(gt,$t,Et){(function(){var Tt=Et(8).VmError,At=function(Dt,Mt){for(var Ft in Mt)Ct.call(Mt,Ft)&&(Dt[Ft]=Mt[Ft]);function Bt(){this.constructor=Dt}return Bt.prototype=Mt.prototype,Dt.prototype=new Bt,Dt.__super__=Mt.prototype,Dt},Ct={}.hasOwnProperty,Pt=(At(It,Tt),It.display="StopIteration",It);function It(Ut,Dt){this.value=Ut,this.message=Dt!=null?Dt:"iterator has stopped"}Nt.prototype.next=function(){if(this.index>=this.elements.length)throw new Pt("array over");return this.elements[this.index++]},Tt=Nt;function Nt(Ut){this.elements=Ut,this.index=0}$t.StopIteration=Pt,$t.ArrayIterator=Tt}).call(this)},function(gt,$t,Et){function Tt(At){return(Tt=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(Ct){return typeof Ct}:function(Ct){return Ct&&typeof Symbol=="function"&&Ct.constructor===Symbol&&Ct!==Symbol.prototype?"symbol":typeof Ct})(At)}(function(){var At={}.hasOwnProperty,Ct=Et(0).isArray,Pt=(It.prototype.run=function(){for(var Ht=this.callStack[this.depth],Wt=Ht.error;0<=this.depth&&Ht&&!this.paused;)if((Ht=Wt?this.unwind(Wt):Ht).run(),(Wt=Ht.error)instanceof Error&&this.injectStackTrace(Wt),Ht.done()){if(Ht.guards.length){var Kt=Ht.guards.pop();if(Kt.finalizer){Ht.ip=Kt.finalizer,Ht.exitIp=Kt.end,Ht.paused=!1;continue}}!Ht.construct||(Kt=Tt(this.rv))!=="object"&&Kt!=="function"&&(this.rv=Ht.scope.get(0)),(Ht=this.popFrame())&&!Wt&&(Ht.evalStack.push(this.rv),this.rv=void 0)}else Wt=(Ht=this.callStack[this.depth]).error;if(this.timedOut()&&(Wt=new Error(this),this.injectStackTrace(Wt)),Wt)throw Wt},It.prototype.unwind=function(Ht){for(var Wt=this.callStack[this.depth];Wt;){Wt.error=Ht;var Kt=Wt.ip-1,qt=Wt.guards.length;if(qt&&(qt=Wt.guards[qt-1],qt.start<=Kt&&Kt<=qt.end)){if(qt.handler!==null)if(Kt<=qt.handler)Wt.evalStack.push(Ht),Wt.error=null,Wt.ip=qt.handler;else{if(!(qt.finalizer&&Wt.ip<=qt.finalizer)){Wt=this.popFrame();continue}Wt.ip=qt.finalizer}else Wt.ip=qt.finalizer;return Wt.paused=!1,Wt}Wt=this.popFrame()}throw Ht},It.prototype.injectStackTrace=function(Ht){var Wt,Kt,qt,Jt,Xt,Zt,rr,tr=[],Qt=0;for(this.depth>this.maxTraceDepth&&(Qt=this.depth-this.maxTraceDepth),Kt=qt=Xt=this.depth,Zt=Qt;Xt<=Zt?qt<=Zt:Zt<=qt;Kt=Xt<=Zt?++qt:--qt)(Jt=(Wt=this.callStack[Kt]).script.name)===""&&Wt.fname&&(Jt=Wt.fname),tr.push({at:{name:Jt,filename:Wt.script.filename},line:Wt.line,column:Wt.column});if(Ht.trace){for(rr=Ht.trace;Ct(rr[rr.length-1]);)rr=rr[rr.length-1];rr.push(tr)}else Ht.trace=tr;return Ht.stack=Ht.toString()},It.prototype.pushFrame=function(Ht,Wt,Kt,qt,Jt,Xt,Zt){if(Xt==null&&(Xt=""),Zt==null&&(Zt=!1),this.checkCallStack())return Kt=new Ft(Kt,Ht.localNames,Ht.localLength),Kt.set(0,Wt),Wt=new Nt(this,Ht,Kt,this.realm,Xt,Zt),Jt&&Wt.evalStack.push(Jt),qt&&Wt.evalStack.push(qt),this.callStack[++this.depth]=Wt},It.prototype.checkCallStack=function(){return this.depth!==this.maxDepth||(this.callStack[this.depth].error=new Error("maximum call stack size exceeded"),this.pause(),!1)},It.prototype.popFrame=function(){var Ht=this.callStack[--this.depth];return Ht&&(Ht.paused=!1),Ht},It.prototype.pause=function(){return this.paused=this.callStack[this.depth].paused=!0},It.prototype.resume=function(Ht){if(this.timeout=Ht!=null?Ht:-1,this.paused=!1,this.callStack[this.depth].paused=!1,this.run(),!this.paused)return this.rexp},It.prototype.timedOut=function(){return this.timeout===0},It.prototype.send=function(Ht){return this.callStack[this.depth].evalStack.push(Ht)},It.prototype.done=function(){return this.depth===-1},It);function It(Ht,Wt){this.realm=Ht,this.timeout=Wt!=null?Wt:-1,this.maxDepth=1e3,this.maxTraceDepth=50,this.callStack=[],this.evalStack=null,this.depth=-1,this.yielded=this.rv=void 0,this.paused=!1,this.r1=this.r2=this.r3=null,this.rexp=null}Ut.prototype.run=function(){for(var Ht=this.script.instructions;this.ip!==this.exitIp&&!this.paused;)Ht[this.ip++].exec(this,this.evalStack,this.scope,this.realm);var Wt=this.evalStack.len();if(!this.paused&&!this.error&&Wt!==0)throw new Error("Evaluation stack has "+Wt+" items after execution")},Ut.prototype.done=function(){return this.ip===this.exitIp},Ut.prototype.setLine=function(Ht){this.line=Ht},Ut.prototype.setColumn=function(Ht){this.column=Ht};var Nt=Ut;function Ut(Ht,Wt,Kt,qt,Jt,Xt){this.fiber=Ht,this.script=Wt,this.scope=Kt,this.realm=qt,this.fname=Jt,this.construct=Xt!=null&&Xt,this.evalStack=new Dt(this.script.stackSize,this.fiber),this.ip=0,this.exitIp=this.script.instructions.length,this.paused=!1,this.finalizer=null,this.guards=[],this.rv=void 0,this.line=this.column=-1}Mt.prototype.push=function(Ht){if(this.idx===this.array.length)throw new Error("maximum evaluation stack size exceeded");return this.array[this.idx++]=Ht},Mt.prototype.pop=function(){return this.array[--this.idx]},Mt.prototype.top=function(){return this.array[this.idx-1]},Mt.prototype.len=function(){return this.idx},Mt.prototype.clear=function(){return this.idx=0};var Dt=Mt;function Mt(Ht,Wt){this.fiber=Wt,this.array=new Array(Ht),this.idx=0}Bt.prototype.get=function(Ht){return this.data[Ht]},Bt.prototype.set=function(Ht,Wt){return this.data[Ht]=Wt},Bt.prototype.name=function(Ht){var Wt,Kt=this.names;for(Wt in Kt)if(At.call(Kt,Wt)&&Kt[Wt]===Ht)return parseInt(Wt);return-1};var Ft=Bt;function Bt(Ht,Wt,Kt){this.parent=Ht,this.names=Wt,this.data=new Array(Kt)}Vt.prototype.get=function(Ht){return this.object[Ht]},Vt.prototype.set=function(Ht,Wt){return this.object[Ht]=Wt},Vt.prototype.has=function(Ht){return Ht in this.object};var Gt=Vt;function Vt(Ht,Wt){this.parent=Ht,this.object=Wt}$t.Fiber=Pt,$t.Scope=Ft,$t.WithScope=Gt}).call(this)},function(gt,$t,Et){Et=new(Et(4)),Et.eval('["