Skip to content

fix(maafw): 运行环境坏了要当场知道,别拖到任务中途 - #500

Merged
qiyinxi merged 1 commit into
devfrom
fix/maafw-env-gate
Aug 31, 2026
Merged

fix(maafw): 运行环境坏了要当场知道,别拖到任务中途#500
qiyinxi merged 1 commit into
devfrom
fix/maafw-env-gate

Conversation

@qiyinxi

@qiyinxi qiyinxi commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

用户机器上的报错:

MaaFW 运行异常: MaaFW runner worker exited without result: 1: from .library import Library
  File "...\maafw-runtime-8113c68.../environment\Lib\site-packages\maa\library.py", line 1, in <module>
    import ctypes
  File "ctypes\__init__.py", line 157, in <module>
AttributeError: class must define a '_type_' attribute

运行池认为环境就绪,直到 worker 起来才炸——而模拟器和游戏已经先被拉起来了。

根因

ctypes/__init__.py 157 行是 class py_object(_SimpleCData):158 行就写着 _type_ = "O"。类体里有而 _ctypes 说没有,只有一种可能:ctypes 的两半(纯 Python 部分与 _ctypes.pyd)来自不同构建。

原来的 verify_python 确实会启动解释器校验,但探针只 import json/platform/sys/sysconfig,而 version、soabi、platform 全部来自解释器二进制——标准库那一半坏了照样报得一模一样。(探针加 ctypes 的改动已随 dev 上的 01a20888 合入。)

本 PR 补三道

1. 装完即验installer._verify_maafw_importable

原来只有 importlib.metadata.version('maafw'),读的是包元数据,装了一半或标准库坏掉时照样报得出版本号。写 manifest 之前真的 import maa 一次,坏环境就不会被记成好的。

2. 跑前自检embedded_manager.describe_unusable_runtime

check() 此前只验模式/脚本 ID/项目路径/用户/模拟器,完全不碰环境。现在解析出该项目会用的 MaaFW requirement,在池里找到匹配的 runtime 才探一次;没建过就不拦,那份环境会在运行时按需准备。

拦在 check() 而不是只靠编辑页:队列与定时任务不经过编辑页,绕不过它;而且此时模拟器和游戏都还没启动。

为此把 requirement 解析抽成 resolve_project_maafw_requirement,与 prepare_runner_environment 内的顺序一致(项目自带原生库的实测版本优先于 requirements.txt 的声明)。实测对 MaaYYs 解析出 maafw==5.13.0b2,与真机日志一致。

3. 向导闸门MaaFWScriptEdit.vue

环境没准备好不让进下一步——首次要下载 MaaFramework,失败时后面每一步都是白填。失败不是死路:提示条里带「重试」。

自检自身出问题(池不可读等)一律放行,不能反过来挡住运行。

验证

  • 后端 830 passed,2 条失败均与本 PR 无关(test_activity_fight_preserves_native_options 是既有的,test_deleted_script_forces_repo_and_resubscribes 来自 feat(BetterGI): 新增更好的原神脚本专项适配 #410
  • 新增 9 项测试;回退实现后以 AttributeError: ... has no attribute '_verify_maafw_importable' 变红
  • 前端 vitest 142 passedvite build 通过
  • 拿 4 个真实池 venv 跑过自检,不误伤

未覆盖

向导守卫是 SFC 里的两行 computed,单测要挂载整页,性价比低,没有前端单测。真正可执行的闸门是后端那道(有测试)。

顺带

useBettergiGuiSession.ts:88 的 typecheck error 与 useScriptApi.ts:1125no-dupe-else-if lint error 都来自 #410,本 PR 未处理。

🤖 Generated with Claude Code

Sourcery 总结

在安装、任务预检和设置向导导航期间,快速失败并阻止使用不可用的 MaaFW 环境。

新功能:

  • 添加运行前验证,在任务开始前检测现有但不可用的 MaaFW 运行时。
  • 在运行时环境准备就绪前,阻止 MaaFW 设置向导继续进行,并支持重试。

错误修复:

  • 在安装期间验证 import maa 是否成功,从而拒绝损坏的 MaaFW 环境,避免在运行时未就绪时记录该环境。
  • 当匹配的 MaaFW 运行时不可用或无法使用时,避免启动模拟器或游戏。

改进:

  • 复用项目的 MaaFW 要求解析逻辑,确保准备和验证期间选择一致的运行时。
  • 对于与现有匹配运行时无关的验证失败,允许其保持非阻塞状态,以便仍可按需准备环境。

测试:

  • 增加对安装期间导入验证和运行时预检门控场景的覆盖。
Original summary in English

Summary by Sourcery

Fail fast on unusable MaaFW environments during installation, task pre-flight checks, and setup wizard navigation.

New Features:

  • Add pre-run validation that detects unusable existing MaaFW runtimes before tasks start.
  • Prevent the MaaFW setup wizard from advancing until the runtime environment is ready, with retry support.

Bug Fixes:

  • Reject broken MaaFW environments during installation by verifying that import maa succeeds before recording the runtime as ready.
  • Avoid starting emulators or games when the matching MaaFW runtime is unavailable or unusable.

Enhancements:

  • Reuse project MaaFW requirement resolution for consistent runtime selection during preparation and validation.
  • Allow validation failures unrelated to a matching existing runtime to remain non-blocking so environments can still be prepared on demand.

Tests:

  • Add coverage for installation-time import validation and runtime pre-flight gating scenarios.

真机现场:用户的 Python 运行时标准库损坏,运行池却认为环境就绪,直到 worker
起来才在 maa/library.py 第 1 行的 import ctypes 处炸掉,抛出 ctypes 内部的
天书——而此时模拟器和游戏已经先被拉起来了。

补三道:

1. 装完即验(installer._verify_maafw_importable)
   原来只有 importlib.metadata.version('maafw'),它读的是包元数据,装了一半
   或解释器标准库坏掉时照样报得出版本号。写 manifest 之前真的 import maa
   一次,坏环境就不会被记成好的。

2. 跑前自检(embedded_manager.describe_unusable_runtime)
   check() 此前只验模式/脚本 ID/项目路径/用户/模拟器,完全不碰环境。现在解析
   出该项目会用的 MaaFW requirement,在池里找到匹配的 runtime 才探一次
   (一个子进程,解释器本来就要起);没建过就不拦,那份环境会在运行时按需准备。

   拦在 check() 而不是只靠编辑页:队列与定时任务不经过编辑页,绕不过 check(),
   而且此时模拟器和游戏都还没启动。

   为此把 requirement 解析抽成 resolve_project_maafw_requirement,与
   prepare_runner_environment 内的顺序一致(项目自带原生库的实测版本优先于
   requirements.txt 的声明)。实测对 MaaYYs 解析出 maafw==5.13.0b2,与真机
   日志一致。

3. 向导闸门(MaaFWScriptEdit.vue)
   环境没准备好不让进下一步——首次要下载 MaaFramework,失败时后面每一步都是
   白填。失败不是死路:提示条里带「重试」,会清掉「这个路径已备好过」的记忆
   重新准备。

自检自身出问题(池不可读等)一律放行,不能反过来挡住运行。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @qiyinxi, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 4 days and 17 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@sourcery-ai

sourcery-ai Bot commented Aug 31, 2026

Copy link
Copy Markdown

审查者指南

本 PR 通过“装完即验、跑前自检、向导闸门”三层防线识别损坏的 MaaFW/Python 运行环境:安装阶段实际执行 import maa,任务执行前只检查已存在的匹配 runtime,编辑向导则在环境准备完成前禁止继续,并为失败场景提供重试。

任务前 MaaFW runtime 验证时序图

sequenceDiagram
    participant Task as 任务执行
    participant Manager as MaaFWEmbeddedManager
    participant Resolver as resolve_project_maafw_requirement
    participant Pool as MaaFWRuntimePoolService
    participant Python as Runtime Python
    Task->>Manager: check()
    Manager->>Resolver: resolve_project_maafw_requirement(project_path)
    Resolver-->>Manager: MaaFW requirement
    Manager->>Pool: list()
    Pool-->>Manager: 现有 runtimes
    alt 存在匹配的 runtime
        Manager->>Python: probe_python_identity()
        alt runtime 可用
            Python-->>Manager: 身份探测成功
            Manager-->>Task: 通过
        else runtime 不可用
            Python-->>Manager: 错误
            Manager-->>Task: MFW runtime 不可用
        end
    else 不存在匹配的 runtime
        Manager-->>Task: 通过,按需准备 runtime
    end
Loading

已安装 MaaFW runtime 验证时序图

sequenceDiagram
    participant Installer as Runtime 安装器
    participant Python as Runtime Python
    participant Manifest as Runtime manifest
    Installer->>Python: import maa
    alt 导入成功
        Python-->>Installer: 成功
        Installer->>Python: _installed_maafw_version()
        Python-->>Installer: MaaFW 版本
        Installer->>Manifest: 写入 runtime 元数据
    else 导入失败
        Python-->>Installer: 导入错误
        Installer-->>Manifest: 拒绝写入 manifest
    end
Loading

MaaFW runtime 环境三层闸门流程图

flowchart TD
    A[安装或准备 MaaFW runtime] --> B[_verify_maafw_importable]
    B -->|import maa 成功| C[写入 runtime manifest]
    B -->|import maa 失败| D[拒绝不可用的 runtime]
    C --> E[任务检查]
    E --> F[resolve_project_maafw_requirement]
    F --> G[查找匹配的现有 runtime]
    G -->|找到 runtime| H[probe_python_identity]
    G -->|未找到 runtime| I[允许检查;运行时准备]
    H -->|探测成功| J[启动任务]
    H -->|探测失败| K[在启动模拟器和游戏前阻止执行]
    A --> L[MaaFWScriptEdit 向导]
    L --> M[runAgentEnvPrepare]
    M -->|envReady| N[允许进入下一步]
    M -->|envFailed| O[显示重试]
    O --> P[retryAgentEnvPrepare]
    P --> M
Loading

文件级变更

变更 详情 文件
在运行池写入 manifest 前验证 MaaFW 可实际导入,避免损坏或半安装环境被标记为可用。
  • 新增子进程级 import maa 探针,保留并截断原始错误信息。
  • 将导入验证置于读取安装版本和写入安装元数据之前。
app/task/MaaFW/tools/core/automas_maafw_runtime_pool/installer.py
tests/task/test_maafw_environment_gate.py
增加运行前的 MaaFW runtime 健康检查,并在任务通用校验阶段拦截已存在且匹配的损坏环境。
  • 抽取项目 MaaFW requirement 解析逻辑,优先使用项目自带原生库的实测版本。
  • 仅探测运行池中与项目 requirement 匹配的已有 runtime,未创建或自检基础设施异常时放行。
  • 通过后台线程执行检查,避免阻塞异步任务校验,并返回面向用户的环境错误。
app/task/MaaFW/embedded_manager.py
app/task/MaaFW/tools/core/automas_maafw_runner/environment.py
tests/task/test_maafw_environment_gate.py
在 MaaFW 脚本编辑向导的首步增加环境准备闸门,并提供失败重试。
  • 只有项目预览数据和运行环境都就绪时才能离开首步。
  • 环境准备失败时显示原因提示和重试操作,重试前清除路径已准备状态以强制重新执行。
frontend/src/views/EditView/Script/MaaFWScriptEdit.vue
更新版本资源以标识本次修复版本。
  • 调整版本元数据。
res/version.json

提示与命令

与 Sourcery 交互

  • 触发新的审查: 在 pull request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 根据审查评论生成 GitHub issue: 回复审查评论,请 Sourcery 根据该评论创建 issue。你也可以使用 @sourcery-ai issue 回复审查评论,以根据该评论创建 issue。
  • 生成 pull request 标题: 在 pull request 标题的任意位置写入 @sourcery-ai,即可随时生成标题。你也可以在 pull request 中评论 @sourcery-ai title,以随时生成或重新生成标题。
  • 生成 pull request 摘要: 在 pull request 正文中任意位置写入 @sourcery-ai summary,即可在指定位置随时生成 PR 摘要。你也可以在 pull request 中评论 @sourcery-ai summary,以随时生成或重新生成摘要。
  • 生成审查者指南: 在 pull request 中评论 @sourcery-ai guide,即可随时生成或重新生成审查者指南。
  • 解决所有 Sourcery 评论: 在 pull request 中评论 @sourcery-ai resolve,即可解决所有 Sourcery 评论。如果你已经处理完所有评论且不想再看到它们,这会很有用。
  • 忽略所有 Sourcery 审查: 在 pull request 中评论 @sourcery-ai dismiss,即可忽略所有现有的 Sourcery 审查。如果你想从新的审查开始,这尤其有用——别忘了评论 @sourcery-ai review 以触发新的审查!

自定义使用体验

访问你的控制面板以:

  • 启用或禁用审查功能,例如 Sourcery 生成的 pull request 摘要、审查者指南等。
  • 更改审查语言。
  • 添加、删除或编辑自定义审查说明。
  • 调整其他审查设置。

获取帮助

Original review guide in English

Reviewer's Guide

本 PR 通过“装完即验、跑前自检、向导闸门”三层防线识别损坏的 MaaFW/Python 运行环境:安装阶段实际执行 import maa,任务执行前只检查已存在的匹配 runtime,编辑向导则在环境准备完成前禁止继续,并为失败场景提供重试。

Sequence diagram for pre-task MaaFW runtime validation

sequenceDiagram
    participant Task as Task execution
    participant Manager as MaaFWEmbeddedManager
    participant Resolver as resolve_project_maafw_requirement
    participant Pool as MaaFWRuntimePoolService
    participant Python as Runtime Python
    Task->>Manager: check()
    Manager->>Resolver: resolve_project_maafw_requirement(project_path)
    Resolver-->>Manager: MaaFW requirement
    Manager->>Pool: list()
    Pool-->>Manager: Existing runtimes
    alt Matching runtime exists
        Manager->>Python: probe_python_identity()
        alt Runtime is usable
            Python-->>Manager: Identity probe succeeds
            Manager-->>Task: Pass
        else Runtime is unusable
            Python-->>Manager: Error
            Manager-->>Task: MFW runtime unavailable
        end
    else No matching runtime exists
        Manager-->>Task: Pass, prepare runtime on demand
    end
Loading

Sequence diagram for validating an installed MaaFW runtime

sequenceDiagram
    participant Installer as Runtime installer
    participant Python as Runtime Python
    participant Manifest as Runtime manifest
    Installer->>Python: import maa
    alt Import succeeds
        Python-->>Installer: Success
        Installer->>Python: _installed_maafw_version()
        Python-->>Installer: MaaFW version
        Installer->>Manifest: Write runtime metadata
    else Import fails
        Python-->>Installer: Import error
        Installer-->>Manifest: Reject manifest write
    end
Loading

Flow diagram for the three MaaFW runtime environment gates

flowchart TD
    A[Install or prepare MaaFW runtime] --> B[_verify_maafw_importable]
    B -->|import maa succeeds| C[Write runtime manifest]
    B -->|import maa fails| D[Reject unusable runtime]
    C --> E[Task check]
    E --> F[resolve_project_maafw_requirement]
    F --> G[Find matching existing runtime]
    G -->|runtime found| H[probe_python_identity]
    G -->|runtime not found| I[Allow check; prepare at runtime]
    H -->|probe succeeds| J[Start task]
    H -->|probe fails| K[Block before emulator and game start]
    A --> L[MaaFWScriptEdit wizard]
    L --> M[runAgentEnvPrepare]
    M -->|envReady| N[Allow next step]
    M -->|envFailed| O[Show retry]
    O --> P[retryAgentEnvPrepare]
    P --> M
Loading

File-Level Changes

Change Details Files
在运行池写入 manifest 前验证 MaaFW 可实际导入,避免损坏或半安装环境被标记为可用。
  • 新增子进程级 import maa 探针,保留并截断原始错误信息。
  • 将导入验证置于读取安装版本和写入安装元数据之前。
app/task/MaaFW/tools/core/automas_maafw_runtime_pool/installer.py
tests/task/test_maafw_environment_gate.py
增加运行前的 MaaFW runtime 健康检查,并在任务通用校验阶段拦截已存在且匹配的损坏环境。
  • 抽取项目 MaaFW requirement 解析逻辑,优先使用项目自带原生库的实测版本。
  • 仅探测运行池中与项目 requirement 匹配的已有 runtime,未创建或自检基础设施异常时放行。
  • 通过后台线程执行检查,避免阻塞异步任务校验,并返回面向用户的环境错误。
app/task/MaaFW/embedded_manager.py
app/task/MaaFW/tools/core/automas_maafw_runner/environment.py
tests/task/test_maafw_environment_gate.py
在 MaaFW 脚本编辑向导的首步增加环境准备闸门,并提供失败重试。
  • 只有项目预览数据和运行环境都就绪时才能离开首步。
  • 环境准备失败时显示原因提示和重试操作,重试前清除路径已准备状态以强制重新执行。
frontend/src/views/EditView/Script/MaaFWScriptEdit.vue
更新版本资源以标识本次修复版本。
  • 调整版本元数据。
res/version.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@qiyinxi
qiyinxi merged commit 5f3f77c into dev Aug 31, 2026
4 checks passed
@qiyinxi
qiyinxi deleted the fix/maafw-env-gate branch September 2, 2026 20:31
qiyinxi added a commit that referenced this pull request Sep 2, 2026
便携版在装有另一份 Python 3.12 的电脑上,MFW 运行环境准备成功、任务一启动就报:

```
File ".../environment/Lib/site-packages/maa/library.py", line 1, in <module>
    import ctypes
File "ctypes/__init__.py", line 157, in <module>
AttributeError: class must define a '_type_' attribute
```

## 根因

便携包随附的 `environment/python` 是 embeddable 发行版。运行池拿它当 venv 引导时,uv 把整套
embeddable 复制进 venv 的 `Scripts\`,**但不带 `python312._pth`**。这个 python 找不到
`Lib\os.py` 这个标准库 landmark,CPython 的 `getpath.py` 就按 Windows 回退规则读注册表
`HKCU\Software\Python\PythonCore\3.12\PythonPath`,把本机系统 Python 3.12.10 的
`Lib;DLLs` 排在 venv `Scripts` 之前——3.12.10 的 `_ctypes.pyd` 装进 3.12.0 的
python312.dll。base 解释器自己 `import ctypes` 是好的,所以 #500 的探针只在 venv
上才会红;没装系统 Python 的机器完全不触发,测试端也就没暴露。

## 改动

- 探针新增 `stdlibLandmark`;没有 landmark 的解释器不再作引导(宿主跳过、configured
报错、`install_python_runtime` fail-closed)
- 无显式 python 约束时改按宿主小版本走池内托管解释器,identity 随之取自它;完整 Python 宿主下 runtime id
逐字节不变
- 运行前自检改按项目实际会用的那份 runtime 探测,不再按 MaaFW 版本随便挑(否则旧坏环境会把新好环境拦下)

## 验证

- `pytest tests/task/test_maafw_*.py`:157 passed;`pytest tests
--collect-only` 退出 0;ruff format 通过
- scratch 池端到端:模拟 embeddable 宿主 → 下载托管 CPython 3.12.13 → 建 venv →
`sys.path` 无注册表条目、`import maa` 通过;embeddable 引导被拒
- 真机 D:\AUTO-MAS(beta.2 热补同样改动):M9A 的 `prepare_runner_environment` 建出新
runtime,venv 内 `import maa` 通过

🤖 Generated with [Claude Code](https://claude.com/claude-code)

## Sourcery 摘要

确保便携式 MaaFW 环境使用自包含且兼容的 Python 运行时,并可靠地拒绝或修复使用可嵌入式解释器创建的环境。

Bug 修复:
- 防止使用可嵌入式 Python 发行版引导 MaaFW 虚拟环境,避免在 Windows 上混用不兼容的标准库和扩展模块。
- 为便携式主机使用兼容的受管理 Python 运行时;当没有可用的自包含引导解释器时,安全地终止操作。
- 使运行前的运行时验证与项目实际使用的运行时保持一致,从而允许修复环境,同时检测不可用的环境。

增强功能:
- 对于完整的 Python 主机,保留其运行时标识;当便携式主机需要运行时时,则从受管理的引导解释器派生运行时标识。
- 在运行时准备期间,为受管理 Python 的安装提供进度报告。

<details>
<summary>Original summary in English</summary>

## Sourcery 总结

确保便携式 MaaFW 环境使用自包含且兼容的 Python 运行时,并可靠地拒绝或替换由可嵌入式解释器创建的环境。

错误修复:
- 防止可嵌入式 Python 发行版引导 MaaFW 虚拟环境,避免在 Windows 上混用不兼容的标准库和扩展模块。
- 对便携式主机使用由池管理的兼容 Python 运行时;当没有可用的自包含引导解释器时,安全地终止操作。
- 在执行前验证项目实际选择的运行时,从而允许修复损坏的环境,而不会因无关的运行时而阻塞。

增强功能:
- 为完整的 Python 主机保留运行时标识;对于便携式主机,则根据受管理的引导解释器生成标识。
- 在准备受管理的 Python 解释器时报告进度。

<details>
<summary>Original summary in English</summary>

## Sourcery 摘要

确保便携式 MaaFW 环境使用自包含且兼容的 Python 运行时,并可靠地拒绝或替换由可嵌入解释器创建的环境。

错误修复:
- 防止可嵌入 Python 发行版在缺少自包含标准库的情况下引导 MaaFW 虚拟环境。
- 对便携式主机使用由池管理的兼容 Python 运行时;当没有有效的引导解释器可用时,安全地终止操作。
- 在执行前验证项目实际选择的运行时,使过时的环境能够得到修复,而不会因无关的运行时而受阻。

增强功能:
- 保留完整 Python 主机的运行时标识,并根据选定的受管理解释器派生便携式主机的标识。
- 安装受管理的 Python 解释器时报告进度。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

Ensure portable MaaFW environments use a self-contained compatible
Python runtime and reliably reject or replace environments created from
embeddable interpreters.

Bug Fixes:
- Prevent embeddable Python distributions from bootstrapping MaaFW
virtual environments without a self-contained standard library.
- Use a compatible pool-managed Python runtime for portable hosts and
fail closed when no valid bootstrap interpreter is available.
- Validate the runtime actually selected for the project before
execution, allowing stale environments to be repaired without blocking
on unrelated runtimes.

Enhancements:
- Preserve runtime identities for complete Python hosts and derive
portable-host identities from the selected managed interpreter.
- Report progress while installing a managed Python interpreter.

</details>

</details>

</details>

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant