跳转至

Inferring Comprehensive Cohort Causal Effects in the Presence of Unmeasured Confounding and Missing Outcomes

作者: Shiyao Xu, Razieh Nabi, Martin Underwood, Daniel Scharfstein
主题: 因果推断
相关性: 8/10
链接: https://arxiv.org/abs/2606.28741


一、领域脉络与小综述

这个方向是什么

这个子方向要解决的根本问题是:如何利用混合设计临床研究(综合队列研究,CCS)的数据,在同时存在未测量混杂(在观察性研究臂中)和结局随机缺失(在两臂中)的情况下,对整个队列(RCT + OBS)的因果效应进行可靠的推断和敏感性分析。其核心挑战在于,既要利用RCT的内部有效性,又要借助OBS的更大样本量和代表性,同时必须正视OBS中因患者偏好选择治疗而产生的未测量混杂,以及两臂中常见的结局缺失问题。当前该方向正处于从“假设无未测量混杂”向“允许并量化未测量混杂”过渡的阶段,本文是这一过渡中的具体推进。

发展脉络(history)

  1. 奠基工作:综合队列研究(CCS)设计的提出与早期分析

    • Olschewski & Scheurlen (1985):首次提出CCS设计,即患者可选择进入RCT或平行OBS,旨在提高试验的代表性。
    • 早期分析(1990s-2000s):如Schmoor et al. (1996, 2008)、Brooks et al. (2000) 等,主要关注分别估计RCT和OBS内部的效应,或进行简单的合并,但通常假设OBS中无未测量混杂(即条件可忽略性)。
  2. 主要进展:从“分别估计”到“估计综合队列因果效应(CCCE)”

    • Lu et al. (2019):首次系统定义了CCCE,并提出了在两种假设下(可解释的RCT选择 vs. OBS中无未测量混杂)的识别与半参数有效估计方法。这是本文的直接前驱。
    • Dahabreh et al. (2019, 2021):系统发展了将RCT结果推广(generalize/transport)到目标人群的框架,包括嵌套和非嵌套设计。其核心假设是条件交换性(R ⊥ Y(t) | X),即RCT和OBS参与者在给定协变量后是可交换的。
    • Parikh et al. (2025):提出双重机器学习方法,结合RCT和OBS数据,并提供了一个可检验外部有效性和可忽略性假设的证伪检验。
  3. 当前Frontier:引入敏感性分析以应对未测量混杂

    • Dahabreh et al. (2026):在推广RCT结果的框架下,首次引入了全局敏感性分析,通过参数化偏离条件交换性假设(R ⊥ Y(t) | X)的程度来评估结论的稳健性。这是本文在敏感性分析方面的主要对标工作。
    • Nabi et al. (2024):在纯观察性研究中,利用半参数理论推导了平均因果效应(ACE)的有效影响函数,并将其参数化为敏感性参数,提出了一个基于一步偏差校正的估计量。本文直接借鉴了其技术路线。
  4. 本文的位置:本文是上述两条线索的交汇与扩展。它继承了Lu et al. (2019) 对CCCE的聚焦,但放弃了“OBS中无未测量混杂”的强假设,转而采用Nabi et al. (2024) 的敏感性分析框架来建模OBS中的未测量混杂。同时,它扩展了Dahabreh et al. (2026) 的敏感性分析框架,使其能处理结局随机缺失(MAR)的问题。因此,本文填补了“在CCS设计中,同时处理OBS未测量混杂和结局缺失”这一方法论空白。

子线索聚类

  1. CCCE的识别与估计(无/有未测量混杂)

    • 代表工作:Lu et al. (2019), Dahabreh et al. (2019, 2021), Parikh et al. (2025), 本文
    • 核心问题:如何定义和识别整个队列的平均因果效应?需要哪些假设(如条件交换性、无未测量混杂)?如何构造高效或稳健的估计量?
    • 本文贡献:在OBS中引入敏感性参数γ_t来放松“无未测量混杂”假设,并推导了相应的识别公式和有效影响函数。
  2. RCT结果推广/运输的敏感性分析

    • 代表工作:Dahabreh et al. (2026), Lesko et al. (2017), Degtiar & Rose (2021)。
    • 核心问题:当RCT参与者与目标人群不可交换时,如何量化这种偏差对结论的影响?
    • 本文贡献:将Dahabreh et al. (2026) 的敏感性分析框架(基于R ⊥ Y(t) | X)扩展到了CCS设定,并证明了其与本文主框架(基于T ⊥ Y(t) | X, R=0)之间的对偶关系。
  3. 观察性研究中未测量混杂的半参数敏感性分析

    • 代表工作:Nabi et al. (2024), Scharfstein et al. (2021)。
    • 核心问题:在纯观察性研究中,如何利用影响函数构造一个参数化未测量混杂的估计量,并建立其渐近性质?
    • 本文贡献:将Nabi et al. (2024) 的技术(EIF推导、一步估计、Huber截断)从纯OBS设定移植到CCS设定,并处理了RCT和OBS两臂的结局缺失问题。

这个方向在追问的核心问题

  1. CCCE的识别:在CCS设计中,识别CCCE所需的最小假设集是什么?能否在同时存在未测量混杂和结局缺失的情况下实现非参数识别?
  2. 高效估计:在给定识别假设下,CCCE的半参数效率界是什么?如何构造达到该效率界的估计量?
  3. 敏感性分析的统一框架:能否建立一个统一的敏感性分析框架,同时处理OBS中的未测量混杂和RCT与OBS之间的选择偏差,并允许研究者探索不同偏差来源的联合影响?
  4. 缺失数据的处理:当结局缺失机制复杂(如非随机缺失)时,如何将敏感性分析框架扩展到缺失数据机制本身?

⚠️ 作者的framing

  • 作者的缺口frame:作者将缺口frame为“现有方法要么假设OBS中无未测量混杂(如Lu et al. 2019),要么在推广RCT结果时假设RCT与OBS可交换(如Dahabreh et al. 2026),但没有一个方法能同时处理OBS中的未测量混杂和两臂中的结局缺失,并估计CCCE”。因此,本文被定位为“显然的下一步”:将Nabi et al. (2024) 的OBS敏感性分析技术嫁接到Lu et al. (2019) 的CCCE框架中,并处理MAR缺失。
  • 被淡化/回避的竞争路线
    • 工具变量(IV)方法:如果存在有效的工具变量,可以识别OBS中的因果效应而无需依赖敏感性参数。作者在introduction中完全没有提及IV方法作为替代方案。这可能是因为在TOIB研究中难以找到有效的IV,但作为方法论论文,回避这一重要竞争路线是一个值得注意的点。
    • 近端因果推断(Proximal Causal Inference):该方法利用负对照(negative controls)来校正未测量混杂,是另一种不依赖敏感性参数的方法。作者同样未提及。
    • 对缺失数据机制的敏感性分析:作者在讨论中提到了可以扩展到非随机缺失(MNAR),但本文仅处理了MAR。对于MAR假设本身是否合理,没有进行敏感性分析。
  • 什么明显该被引/该存在、却没出现在intro里?
    • Proximal Causal Inference:如Tchetgen Tchetgen et al. (2020) 等。这是处理未测量混杂的另一个主流半参数框架,与本文的敏感性分析框架形成鲜明对比。作者未引用,可能是一个值得研究者去查的“缺失环节”。
    • 工具变量方法在数据融合中的应用:例如,利用RCT中的随机化作为OBS中未测量混杂的工具变量。这类方法在计量经济学中很常见,但在因果推断文献中也有讨论。作者未提及。

张力

未见明显对立引用。所有被引工作基本在同一个共识框架下(潜在结果、半参数理论)进行,只是假设的强弱和关注点不同。一个潜在的“张力”是:Dahabreh et al. (2026) 的敏感性分析框架(基于R ⊥ Y(t) | X)与本文的主框架(基于T ⊥ Y(t) | X, R=0)在概念上是正交的,但作者在Section 4中证明了它们之间存在对偶关系,并利用这种关系进行了分析。这更像是一种互补而非对立。

二、最核心、最简单的例子 / 数学问题

第一步:把符号、模型、可观测数据交代清楚

  • 符号

    • X:基线协变量向量(可观测)。
    • R:研究类型指示符,R=1表示进入RCT,R=0表示进入OBS(可观测)。
    • T:处理指示符,T=1表示新药(如外用布洛芬),T=0表示对照(如口服布洛芬)(可观测)。
    • Y:结局变量(如WOMAC疼痛评分)(部分可观测)。
    • M:结局缺失指示符,M=1表示Y被观测到,M=0表示Y缺失(可观测)。
    • Y(t):潜在结局,即如果(可能反事实地)接受处理T=t时的结局(不可观测)。
    • ψ_t = E[Y(t)]:目标estimand,即整个队列在T=t下的平均潜在结局。CCCE = ψ_1 - ψ_0。
    • γ_t:敏感性参数,量化OBS中未测量混杂的程度(非识别参数,由研究者设定)。
    • s_t(Y):预先指定的Y的函数,用于定义混杂的方向(如递增函数)。
    • F_{t,r}(y|x) = P(Y ≤ y | T=t, R=r, X=x):给定T, R, X下Y的条件分布(不可直接观测,因为Y有缺失)。
    • \tilde{F}_{t,r}(y|x) = P(Y ≤ y | T=t, R=r, X=x, M=1):给定T, R, X且Y被观测到时Y的条件分布(可直接从数据估计)。
    • \mu_{t,r}(h(Y); x) = E[h(Y) | T=t, R=r, X=x]:Y的函数的条件期望。
    • \tilde{\mu}_{t,r}(h(Y); x) = E[h(Y) | T=t, R=r, X=x, M=1]:Y的函数的条件期望(仅基于观测到的Y)。
    • \pi_{t,r}(x) = P(T=t | R=r, X=x):处理倾向性得分。
    • \eta_1(x, r, t) = P(M=1 | X=x, R=r, T=t):结局缺失倾向性得分(即Y被观测到的概率)。
    • g_r(x) = P(R=r | X=x):研究类型选择倾向性得分。
  • 模型

    • 数据生成机制:一个综合队列研究,患者先根据协变量X选择进入RCT或OBS。在RCT中,T被随机分配(与X和潜在结果独立)。在OBS中,T由患者偏好决定,可能受X和未测量混杂U的影响。结局YTR下生成,但可能随机缺失。
    • 关键假设
      1. 一致性:观测到的TY等于相应的潜在变量。
      2. 正性:所有处理/研究类型组合都有正概率。
      3. RCT中的随机化T ⊥ {Y(t), X} | R=1
      4. OBS中的混杂由γ_t控制:这是核心假设。它假设OBS中处理组和对照组的潜在结果分布差异,完全由一个参数γ_t和一个函数s_t(Y)来刻画。当γ_t=0时,OBS中无未测量混杂。
      5. 结局随机缺失(MAR)M ⊥ Y | T, X, R。即给定T, X, R后,Y是否缺失与Y本身无关。
  • 可观测数据

    • 研究者实际能观测到的是\tilde{O} = (X, R, T, M, Y:M=1)
    • 即:每个患者的X, R, T, M都能观测到。只有当M=1时,Y才能被观测到。
    • 想要但观测不到的量Y(t)(潜在结局),以及当M=0时的Y。识别ψ_t需要依靠上述假设,将ψ_t表示为可观测数据分布的泛函。

第二步:讲最小内核

本文的核心思路是:将OBS中的未测量混杂问题,通过一个敏感性参数γ_t,转化为一个可处理的、关于可观测数据分布的泛函估计问题。

最简特例:假设我们只关心ψ_t = E[Y(t)],且假设没有结局缺失(即M=1对所有个体成立),并且RCT中的处理是完全随机的(π_{t,1}(x) = π_{t,1},一个常数)。同时,假设OBS中只有两个处理组T=01)。

在这个特例下,识别公式(3)退化为:

ψ_t = ψ_{t,1} * P(R=1) + ψ_{t,0}(γ_t) * P(R=0)

其中: - ψ_{t,1} = E[Y | T=t, R=1]。由于RCT中处理随机化,E[Y(t)|R=1]可以直接用RCT中T=t组的样本均值估计。 - ψ_{t,0}(γ_t) = E[ Y | T=t, R=0] * P(T=t|R=0) + E[ Y * exp(γ_t * s_t(Y)) / E[exp(γ_t * s_t(Y)) | T=t, R=0] | T=1-t, R=0] * P(T=1-t|R=0)

核心思路: 1. 问题:在OBS中,我们无法直接估计E[Y(t)|R=0],因为TY(t)可能因未测量混杂而相关。例如,病情更重的患者可能更倾向于选择某种治疗,导致E[Y|T=1, R=0]不能代表E[Y(1)|R=0]。 2. 关键想法:作者不试图“消除”混杂,而是用一个参数γ_t量化混杂的方向和强度。这个参数通过一个指数倾斜(exponential tilting)模型(公式1)将T=1-t组的潜在结果分布与T=t组的观测结果分布联系起来。 3. 如何工作:公式(1)说:OBS中,T=1-t组患者的潜在结果Y(t)的分布,等于T=t组患者观测结果Y的分布,再乘以一个权重exp(γ_t * s_t(Y))。如果s_t(Y)是递增函数,那么γ_t > 0意味着T=1-t组的患者倾向于有更高的Y(t)值(即更差的结局),这正好对应了“病情更重的患者选择另一种治疗”的混杂模式。 4. 结果:通过这个倾斜模型,E[Y(t)|R=0]就可以表示为OBS中可观测数据的加权平均,权重依赖于γ_t。因此,对于任意给定的γ_tψ_t就变成了一个可识别的、关于可观测数据分布的泛函。研究者可以变化γ_t的值,观察ψ_t的估计值如何变化,从而评估结论对未测量混杂的敏感程度。

一句话总结:本文的核心数学贡献是,在MAR缺失数据的设定下,推导出这个依赖于γ_t的泛函ψ_t(\tilde{P}; γ_t)非参数有效影响函数(EIF),并基于此构造了一个√n-一致、渐近正态的估计量。

三、这篇论文做了什么

三句话

  1. 研究问题:在综合队列研究(CCS)中,如何估计整个队列的平均因果效应(CCCE),同时处理观察性研究(OBS)臂中的未测量混杂和两臂中的结局随机缺失(MAR)?
  2. 核心工具/方法:基于半参数理论的敏感性分析框架。推导了CCCE的非参数有效影响函数(EIF),并将其参数化为一个敏感性参数γ_t。提出了一个基于样本分割(sample-splitting)和Huber截断的一步偏差校正估计量。
  3. 主要结论:在正确的模型设定下,该估计量是√n-一致的、渐近正态的,并且是半参数有效的。当处理倾向性得分和缺失倾向性得分被错误指定时,只要结局模型正确,该估计量仍然一致(双稳健性的一种形式)。在TOIB研究和模拟研究中验证了方法的性能。

关键设定与假设

  • 设定n个独立同分布的观测\tilde{O}_i = (X_i, R_i, T_i, M_i, Y_i:M_i=1)。目标estimand是ψ_t = E[Y(t)],CCCE = ψ_1 - ψ_0。
  • 假设
    • A1 (一致性):标准假设。
    • A2 (正性):标准假设,确保所有条件概率非零。
    • A3 (RCT随机化)T ⊥ {Y(t), X} | R=1。这是RCT的核心优势,本文将其放宽到条件随机化(A3'),但最终估计量在A3下是有效的。
    • A4 (OBS混杂由γ_t控制)这是本文最关键的假设。它通过一个指数倾斜模型(公式1)参数化了OBS中TY(t)之间的依赖关系。相比“无未测量混杂”(γ_t=0),这是一个更弱的假设,因为它允许混杂存在,但假设其结构是已知的(由s_t(Y)和γ_t刻画)。相比Dahabreh et al. (2026) 的假设(R ⊥ Y(t) | X),这是一个不同的假设,它关注的是OBS内部的处理选择,而非RCT与OBS之间的选择。
    • A5 (结局MAR)M ⊥ Y | T, X, R。这是一个标准但不可检验的假设。本文在讨论中提到了可以将其扩展到MNAR。

主要结果

  • 定理1 (影响函数):推导了ψ_t(\tilde{P}; γ_t)的非参数影响函数ϕ_t(\tilde{P}; γ_t)(\tilde{O})(公式4-6)。这个EIF是构造一步估计量的基础,其结构揭示了估计量对各个 nuisance 参数的依赖关系。
  • 定理2 (渐近正态性):在正确的模型设定(Section 3.2中的GAM、单指标模型)和正则条件下,一步截断估计量\hat{ψ}^†_t(γ_t)是√n-一致的、渐近正态的,且渐近方差等于EIF的方差,因此是半参数有效的。
    • 必要条件|Y||exp(γ_t s_t(Y))|有界;π_{t,r}(X), η_1(X,r,t), μ_{t,0}(exp(γ_t s_t(Y)); X)远离0。
    • 解决的技术难点:证明中需要处理样本分割、Huber截断带来的偏差,以及多个 nuisance 参数(\tilde{F}_{t,r}, π_{t,r}, η_1)的估计误差。关键是通过二阶余项(remainder term) 的分析(Lemma 3),证明只要每个 nuisance 参数的估计误差达到n^{-2/5},它们的乘积项就是o_p(n^{-1/2}),从而不影响√n收敛速度。
  • Lemma 5 (双稳健性):当处理倾向性得分π_{t,r}(X)和缺失倾向性得分η_1(X,r,t)被错误指定时,只要结局模型\tilde{F}_{t,r}(y|X)被正确指定且以o_p(n^{-1/2})的速率估计,估计量仍然是√n-一致的。这提供了一种重要的稳健性保证。
  • Lemma 10 (γ_t与γ'_t的对偶性):证明了本文的敏感性参数γ_t(控制OBS内混杂)与Dahabreh et al. (2026) 的敏感性参数γ'_t(控制RCT-OBS选择偏差)之间存在一一对应关系。这意味着,对其中一个参数的信念会约束另一个参数的可能取值,为敏感性分析提供了交叉验证。

证明路线与技术技巧

  • 整体路线
    1. 识别:在假设A1-A5下,将ψ_t表示为可观测数据分布的泛函(公式3)。
    2. EIF推导:在非参数模型下,通过计算目标泛函对各个 nuisance 参数的路径导数(pathwise derivative),找到其非参数有效影响函数ϕ_t。这一步是半参数理论的标准技术,但计算量很大,需要处理多个 nuisance 参数和缺失数据机制。
    3. 一步估计量构造:基于EIF,构造一个“plug-in”估计量加上一个“偏差校正项”的形式:\hat{ψ}_t = 1/K Σ_k [1/n_k Σ_{i in fold k} υ_t(\hat{\tilde{P}}^{(-k)}; γ_t)(\tilde{O}_i)]。其中υ_t是EIF中与ψ_t无关的部分。
    4. Huber截断:为了处理极端υ_t值带来的方差问题,对υ_t进行Huber截断,得到\hat{ψ}^†_t。截断阈值通过一个数据自适应的方法(公式8-9)选择。
    5. 渐近分析:将√n(\hat{ψ}^†_t - ψ_t)分解为三部分:截断偏差、EIF的样本均值、以及剩余项。证明截断偏差和剩余项都是o_p(1),从而收敛到EIF样本均值的正态分布。
  • 关键跳跃点
    • 二阶余项分析(Lemma 3):这是证明的核心。它展示了ψ_t的估计误差可以表示为多个 nuisance 参数估计误差的乘积之和。这个结构使得只要每个 nuisance 参数估计得“足够好”(n^{-2/5}),它们的乘积就是o_p(n^{-1/2}),从而允许使用灵活的机器学习方法估计 nuisance 参数。
    • Huber截断的渐近可忽略性:证明截断过程不会引入额外的渐近偏差,这依赖于截断阈值的巧妙选择(与log(n)/n相关)。
  • 技术技巧点名
    • 有效影响函数(EIF):核心工具,用于构造高效估计量和进行渐近分析。
    • 样本分割(Sample-splitting / Cross-fitting):用于打破 nuisance 参数估计与主估计之间的依赖关系,简化渐近理论。
    • Huber截断(Huberization):用于处理影响函数中可能出现的极端值,保证有限样本下的稳健性,同时不破坏渐近性质。
    • 二阶余项展开:用于分析估计误差的结构,是证明双稳健性和n^{-1/4}速率的理论基础。
    • 单指标模型(Single Index Model):用于对条件分布\tilde{F}_{t,r}(y|X)进行降维建模,使其能以n^{-2/5}的速率被估计。

真实例子与应用

  • 数据/场景:TOIB研究,一个比较外用 vs. 口服布洛芬治疗老年人慢性膝痛的CCS。数据包含RCT(273人)和OBS(290人),结局是12个月后的WOMAC疼痛评分,有约20%的缺失。
  • 方法应用
    1. 模型设定:使用GAM估计π_{t,r}(X)η_1(X,r,t);使用单指标模型估计\tilde{F}_{t,r}(y|X)。选择s_t(Y) = Φ((Y-60)/25),一个递增函数,意味着γ_t>0表示选择另一种治疗的患者倾向于有更差的结局。
    2. 敏感性分析:让γ_1γ_0[-2, 2]范围内变化,估计CCCE、RTCE和PPCE。
    3. 结果
      • γ_1 = γ_0 = 0(无未测量混杂)时,CCCE的估计值为-0.24(95% CI: -4.28, 3.81),表明两种治疗无显著差异。
      • 敏感性分析(图4)显示,在γ_1, γ_0 ∈ [-2, 2]的几乎所有组合下,CCCE的95%置信区间都落在预设的等效界值[-10, 10]内。结论对未测量混杂是稳健的。
      • 通过对比γ_tγ'_t(图5),发现如果假设RCT和OBS可交换(γ'_t=0),则对应的γ_t不为0,暗示OBS中存在未测量混杂,反之亦然。这展示了两种敏感性分析框架的对偶性。
  • 例子想说明什么:该例子旨在验证所提出方法的实用性,并展示如何通过敏感性分析来评估因果结论对未测量混杂的稳健性。它说明了即使在存在缺失数据的情况下,该方法也能给出有意义的推断,并且其结论在合理的混杂范围内是稳健的。

🔎 结论是否比证明窄

  • 窄结论1:定理2的√n一致性和渐近正态性是在正确的模型设定(Section 3.2中的GAM和单指标模型)下证明的。作者在introduction和讨论中有时会泛泛地声称该方法“允许灵活建模(如机器学习)”,但严格证明中要求nuisance参数的估计速率达到n^{-2/5}。虽然这个速率对很多非参数/机器学习方法来说是合理的,但定理2本身并未直接证明使用任意黑箱机器学习方法时的渐近性质。这是一个值得注意的“证明窄于claim”的点。
  • 窄结论2:Lemma 5(双稳健性)的证明依赖于结局模型\tilde{F}_{t,r}(y|X)被正确指定且以o_p(n^{-1/2})的速率估计。这是一个非常强的条件。在实际应用中,很难保证一个非参数模型能以n^{-1/2}的速率被估计。因此,这种“双稳健性”更多是一种理论上的保证,而非实践中可以轻易依赖的性质。作者在正文中对此的表述“robust to mis-specification of π_{1,r}(X) and η_1(X, r, t)”是准确的,但读者可能高估其实际稳健性。

四、开放问题

  1. 非随机缺失(MNAR)的扩展:本文仅处理了MAR缺失。作者在讨论中提到了“可以沿着Scharfstein and Irizarry [2003]的思路扩展到偏离MAR假设的情况”。这是一个明确的开放问题:如何为CCS设计中的缺失数据机制本身引入敏感性参数,并与OBS中未测量混杂的敏感性分析相结合?扎根点:Section 7, 第一段。

  2. RCT中非依从性的处理:本文假设RCT中完全依从。作者在讨论中承认,当存在非依从时,“需要额外的假设”,并提出了一个可能的解决方案(假设RCT中实际接受的处理在给定X后是随机的)。但并未给出完整的理论。这是一个开放问题:如何在一个统一的敏感性分析框架下,同时处理RCT中的非依从性和OBS中的未测量混杂?扎根点:Section 7, 第三段。

  3. 敏感性参数选择的指导:本文的敏感性分析依赖于研究者指定γ_t的范围。虽然提供了诱导估计(图3b)来帮助专家判断,但缺乏一个系统的、数据驱动的或基于贝叶斯的方法来整合关于γ_t的先验知识。如何为γ_t的选择提供更严谨的统计指导(例如,基于专家 elicitation 或历史数据)是一个开放问题。扎根点:Section 5, 关于“Subject matter experts could utilize this information to determine plausible range”的讨论。

  4. 与Proximal Causal Inference的联系:如前所述,本文完全回避了近端因果推断(PCI)这一竞争框架。一个有趣的开放问题是:本文的敏感性分析框架与PCI框架之间是否存在理论上的联系?能否将PCI中的负对照(negative controls)视为一种特殊的、数据驱动的敏感性参数选择方式?扎根点:第一节的“⚠️ 作者的framing”中提到的“缺失环节”。


Maintained by 陈星宇 · Homepage · Source on GitHub

评论