|
什么是传染病动力学?numpy和matplotlib用python实现传染病模型SI模型SIS模型SIR模型SEIR模型 什么是传染病动力学?最近,在报道疫情的众多新闻中,相信大家也看到过一些来预测新型冠状病毒会导致感染肺炎的人数。你一定好奇,这个人数要怎么预测呢?预测人数又有什么用呢? 事实上,从学科方向来说,这类研究属于传染病动力学,就是用数学模型去描述传染病在人群中传播的规律,从而预测患病人数,进而指导政府制定措施和政策去控制传染病的传播。% d% }4 `& L* y3 C
这类研究最早可追溯到18世纪Daniel Bernoulli对天花的研究,而我们今天所要介绍的SIR模型是1927年Kermack与McKendrick在为了研究伦敦黑死病而提出的,是传染病动力学中最基础的模型。 介绍了传染病模型的背景信息,不知道现在你对传染病模型更有兴趣,还是执着地对python更有兴趣呢?不论哪种,这篇文章会满足你所有的好奇心。 numpy和matplotlib首先,安装一下这节课我们需要使用的两个python包,numpy和matplotlib。
( M( I# K- E2 w$ f/ U$ lnumpy-是python进行科学和矩阵运算最常用的包。 用numpy建立一维数组,存储和计算每天传染病人数的数据。
7 n9 b, h" A* @! m7 yimport numpy as np import matplotlib.pyplot as plt 用matplotlib绘制传染病人数随天数变化的曲线,给出模型预测人数变化的直观认识。 好啦,下面开始用python实现传染病模型吧。 用python实现传染病模型为了让大家能够更好地理解,我们先不直接说SIR模型,我们从最简单的开始。 SI模型首先想象这样一个场景,一个城市有 个人,假设没有人出生和死亡,忽然有一天有 个人感染了病毒成为了患者,如果每天每个患者能够有效传染 个人,那么第二天患病人数是多少呢?最简单的答案是: ,也就是说每天都会新增 个患者。那这样以来,在无限远的将来会有无穷多的人被感染,显然这是不合理的,那错在哪里?仔细思考,你一定发现了,已经患病的人就不能再被传染了,所以我们有必要把人群分为两类,易感者(S-susceptiable)和感染者(I-infective)(你猜的没错,这就是SIR中S和I的含义,R的含义之后介绍再讲)。为了之后方便计算我们记易感者和感染者在人群中的比例为 ,那么 。我们重新考虑上面的问题,顺便来个示意图: Image Name这样的话,每天新增的患者数为 ,也就是总传染人数乘以易感者所占的人群比例。, S; [0 @- b, }9 D/ D
那么每天的感染者比例的增加量就是 。我们假设城市有一千万(N=10的7次方)人,每个患者每天接触感染每天0.8人(lamda=0.8),初始感染人数为45人(i0 = 45/N),我们来模拟70天(T=70)的情况。 # population" X3 X8 _0 ]+ l1 V" ^* s/ f
N = 1e7
/ U. p- c7 D6 n3 D1 l& ?# simuation Time / Day
* I7 V2 |2 u$ h) x8 W5 {+ CT = 70
* G, Y& \9 a4 h- A* [# susceptiable ratio' O: t( d5 }( R2 ]4 }
s = np.zeros([T])$ W1 r- o$ \+ X t9 o5 R2 T
# infective ratio
6 S2 R6 J2 ^) yi = np.zeros([T])7 S& ~7 F3 q# k3 o
# contact rate. A; }# A: w) v! d# W
lamda = 0.8
7 l0 [9 f3 L, p! }5 z3 x
* @# h* t: k$ y0 [, T9 P# initial infective people
' n/ q" `' K: o' l0 u* ?1 ?% ei[0] = 45.0 / N
! [9 R+ b8 n7 W$ y( N* ?. e1 Z3 Q/ ~. n* D8 u
for t in range(T-1):/ @: w6 A8 E* B% D+ d* h, F @& W2 P/ e
i[t + 1] = i[t] + i[t] * lamda * (1.0 - i[t])9 P+ \! N9 i$ ~9 s3 ?5 c
+ ?) q" k' g4 u. Q& b
8 }1 T' e) p2 u! r) l- O3 J
: T5 B' U, p# D/ J相信其他语句大家都明白,新知识是这两行:/ ?9 U) o6 q# j
# g) H9 f! W* O
+ D2 o0 S& ]; E( Y& O$ k- ss = np.zeros([T])2 ]5 ^7 a( g. d. p1 ~8 m
i = np.zeros([T])9 e: v: c8 S! |: P7 F
! U9 o; i7 X& I9 ^+ F
这两句话的意思是一样的,就是利用numpy(已被我们重新命名为np)的函数(zeros())来建立一个所有元素都是零的数组,而给的参数决定了这个数组的维度。比如:% V! O: M4 L! w( l- `: W
) a, A+ _+ m0 _9 C4 G
a = np.zeros([2,3])) r, ^" {5 @' l# r5 M
a3 D* ?$ l! @; O$ y
- o# F3 h& Z7 X. oarray([[0., 0., 0.],
8 @' b3 n$ g8 v4 X% Z- I3 f [0., 0., 0.]])
) t8 V/ c/ w& |, e; m! [5 G
. Z6 K4 c+ n" c( x0 `3 k/ d+ C% ^ V- ~
array([0., 0., 0., 0., 0.])
& s& x7 g# p, X: U, Z: V# N' t; ]4 J; S
% w2 K( T; A+ r% A/ |4 G
类似的还有产生元素全部是1的数组的函数np.ones():( _! s9 i6 z& f9 g5 `& M0 |5 z1 T
2 O( z- G. K t. |0 ]
a = np.ones([5])8 ^7 y$ Q- F4 T3 B. O+ H; m. H
a
$ v. }' n3 Y8 b; y* }
. [( e& M' j( I: Y7 O/ k karray([1., 1., 1., 1., 1.])
! ` ], b- J( u8 ]8 w. s, O$ V7 C$ w5 S8 h x2 X- k
9 j$ C! l) h& A+ u& ^& A, `. Q9 R d0 {
a = np.ones([2,3])
$ K! @: T1 f- H3 y+ T/ q* Ma
$ {4 `; A/ W# N* ~4 D
! g1 q" x% g; V: }6 y0 I1 h- Q1 w+ u4 {" \7 P( ^
array([[1., 1., 1.],
) E) P, `- u7 {) i( Q9 u% ~ [1., 1., 1.]])
! h- z3 J$ j0 g, A: w. [6 C2 R! A5 {( X0 a2 u- t7 H
" }7 J( p$ z9 {! P4 f/ @! C; \plt.plot(i)
7 D/ i. O5 z6 _! p/ v
1 y9 e' y( g& o2 J6 ^$ X0 S; D
7 n* I' m* q8 u/ b5 t. b- [[<matplotlib.lines.Line2D at 0x7f0c2768d6d8>]
* i/ \& \1 f/ D! C
- [. e- f; I# D9 X+ O
6 M1 t5 T* ?/ t9 x![]()
+ t1 _! [5 i6 Z4 D" L# j4 _
5 n# K9 B8 x; ?( x4 S
. d; L5 u, v) D, L( ~9 ~实现SI模型的核心代码是第三个cell的第11,12行:/ Y' m$ C: v/ m! g
6 }; i( f% ^5 |. M/ ]( u
for t in range(T-1):
: @; `% K: b8 _ i[t + 1] = i[t] + i[t] * lamda * (1.0 - i[t])0 v1 l$ D; i& Y. d$ |4 @: h' T' q
, p) H# \+ ^8 H1 j: _就是我们建立的数学模型,利用python的for循环语句累加迭代的方式把每天的增加量叠加到感染者比例上。 运行代码完成计算,我们利用matplotlib的pyplot来画出感染者的随天数的变化曲线: % }( h1 P8 T' {" A4 o) b) v1 _
fig, ax = plt.subplots(figsize=(8,4))
9 p* u7 N9 r! Y. e" |ax.plot(i, c='r', lw=2)% F; _- B/ c( T6 |0 w. O9 [1 h
ax.set_xlabel('Day',fontsize=20): ^+ V3 X1 I* _! G+ G0 C
ax.set_ylabel('Infective Ratio', fontsize=20)- I. ^: k" T6 a8 F- r/ }$ U/ B
ax.grid(1): M" c$ ]( x: S
plt.xticks(fontsize=20)& S6 |+ l! m( x1 j1 U4 u1 Y
plt.yticks(fontsize=20);
$ U, o! \' o" |' U0 ?$ r, V, R% ]" I* c( R8 w
4 q; ]" ~$ ?1 R) Z9 x # a0 i" z* M1 }* c. _# h I# a
. I4 I5 M$ z1 P9 G' a# L# }
从这个结果看到,大约在25天左右,全部人群都会变成感染者,感染率 。
6 I. r- |0 k) o在程序中我们假设每天每个患者传染0.8个人,你可以改变lamda的值,观察全部人群感染的天数的变化。
- s* m- x: s6 C* w$ N( K认真思考你会知道,lamda的现实意义就是该城市的卫生水平,衡量的是消毒,隔离这些措施执行得怎么样。回到传染病模型,按照SI模型计算的结果,我们全人类都会患病,这好可怕!原因是我们忽略了一个很重要的因素,那就是我们有奋斗在一线的医护人员,我们会被治愈!所以SI模型只适合研究具有高传染风险又不能被治愈的病(比如HIV)。 但是对于其他病,我们是可以靠医疗和自身免疫系统康复的,那么紧接着的一个问题就是,被治愈后还会再被传染上嘛?根据这个问题的回答不同,我们有了两个不同的模型,SIR 和 SIS。现在可以揭晓,SIR的R的含义了,就是移出者(Removed),现实含义就是指被治愈后不会再被感染的人。而SIS表示治愈后仍然还是易感者。下面我们用python来分别实现这两个模型。 SIS模型为了实现这个模型,我们需要引入新的一个参数,治愈率 。好啦,先上我们的新示意图: Image Name和SI模型做比较,区别就是计算感染者的增加数时要减去被治愈的人数。5 N0 O0 d* y& [
所以这时候每天的增加的感染者为: ,; h9 y- s/ r s+ A1 R
增加的感染率为: 。
& r9 [% Q: U* ?! a; f模型完成啦,修改python代码:& [, J; h+ A2 |' d
# susceptiable ratio
3 `! w2 N0 E5 G6 n; fs = np.zeros([T])! G( R4 _+ t a- H) }$ C/ r; N
# infective ratio
0 M! _( T& m8 n1 f5 K& Si = np.zeros([T])) L& B0 ^: D: z. t( y
# v/ e5 Q3 K# `+ B& _9 R6 Q
# contact rate
8 s) |$ G$ R, Elamda = 1.0- |" ^8 Q: |9 E x7 J
# recover rate- |2 k' T( @, k1 | H! H
gamma = 0.5 % D( M& l G2 O
; P' K6 i$ W N# C% [. q# initial infective people: O+ R: f, X; l3 [$ ^
i[0] = 45.0 / N' x0 H" b% L4 g( j& Y. T
% ^: }* q0 \4 q. Y2 k
for t in range(T-1):
( X( z) W8 Y$ f! B d3 h i[t + 1] = i[t] + i[t] * lamda * (1.0 - i[t]) - gamma*i[t]0 B: E, {2 ?4 N/ b
" N" ^& t/ t' ]( K( ~3 D
: a8 b3 a" L n; q2 ^
7 a/ |6 ^8 ?! G8 s0 C
运行代码,我们画出曲线(代码和SI模型的画图完全一样):0 W$ Q' n; i) O Z
7 {1 @' I: S' r
fig, ax = plt.subplots(figsize=(8,4)), }4 M* `- R. `
ax.plot(i, c='r', lw=2)$ H( V, r. i$ N' V3 m5 I3 g
ax.set_xlabel('Day',fontsize=20)1 m! Y/ Z6 t' x
ax.set_ylabel('Infective Ratio', fontsize=20)
. C; e% b0 N# o7 g9 D# Jax.grid(1)/ |3 h8 s# S, n
plt.xticks(fontsize=20): ^5 g, z9 {/ V0 Q$ o
plt.yticks(fontsize=20);
; K! @, [# K# Y7 r4 \6 Z+ K4 b C( G* X5 F+ s# X/ H
0 T! [& i) X8 r
# H6 c, z' z' `: E; t
5 Z9 F% E2 Q9 Y: X行代码,我们画出曲线(代码和SI模型的画图完全一样)$ O8 R# j+ C" C1 n
可以看到,达到最大感染率的时间退后10天左右,最后感染和治愈达到动态平衡,人群中有始终有一半的人感染着。所以,SIS模型适合研究具有传染性和反复性的流行病,比如常见流感。同样的,感兴趣的话,改变lamda和gamma的值,观察曲线的变化。和lamda不同的是,gamma的现实意义就是对这种疾病的治疗水平。 SIR模型加入了移出者,被治愈的病人不会再被传染,先上我们的新示意图: Image NameSIR 模型+ a- T! B( k& g
注意到这里,人群被分成了三类,不再只有I和S,所以相比于之前的模型,我们需要找到新的约束关系。现在我们需要分别计算三种人每天的增加量了: - u! ~2 Q/ n/ ~ F6 B: e# j6 f
- 易感者:每天都在被传染,所以一直在减少,减少量为被传染的人数:
- 感染者:增加了被感染的人,减少了治愈的人:
- 移出者:增加了治愈的人:
, E$ ^8 w! s9 S! a
建模完成,修改python代码,并且假设人群普遍易感,新型疾病,初始没有移出者。 1 [' @: o8 f, Z! w- |5 `& s/ d0 Q
# population0 \$ ?& X" U% h: T+ t, i
N = 1e7 + 10 + 51 l; F+ U2 h5 w( ]" [/ x: H; r
# simuation Time / Day
) z* H- Q" ?( _1 @% ~T = 170
7 p- \' l% J# c+ W$ y) D# susceptiable ratio
0 F ^4 c1 s" r; [s = np.zeros([T])! x# l" A p8 V
# infective ratio n. f @$ c# C' ~
i = np.zeros([T])
& C; r3 z8 }2 Q# remove ratio' j1 P0 F$ Z' w. T) Q/ q; |4 T
r = np.zeros([T])
/ G7 D7 m' {% _# V
6 O1 p5 f/ n* n% ?0 B# contact rate2 ~! m) k) r6 t1 ~& k
lamda = 0.2586( Y4 @, _6 P! e
# recover rate
4 H' ~. }# ^ dgamma = 0.0821& i/ A- H* V9 \! ]& ^) w0 l
" S* ~+ E2 v3 O& d6 F* H) w
# initial infective people; K/ u7 }/ Q9 I \
i[0] = 10.0 / N
4 V# f- \ Z/ gs[0] = 1e7 / N1 p: @3 n2 a3 F. n+ O( p
for t in range(T-1):
, `, I/ k" V/ |1 F0 L8 h6 z6 r i[t + 1] = i[t] + i[t] * lamda * s[t] - gamma*i[t]
( \! O0 Y% o3 p s[t + 1] = s[t] - lamda * s[t] * i[t]
9 ]% h9 W- l# Q- ^ r[t + 1] = r[t] + gamma*i[t]/ D/ |, T5 {( g! D/ b* j- C
0 X6 C0 T+ C8 U, i! v" R
fig, ax = plt.subplots(figsize=(10,6))
* l% a8 ^7 s. @! i: C7 pax.plot(s, c='b', lw=2, label='S')
: S' V7 g4 @6 e& U' L$ Kax.plot(i, c='r', lw=2, label='I')- `/ m2 _! y5 i+ U
ax.plot(r, c='g', lw=2, label='R')
' j1 V+ V. |: y& @7 Qax.set_xlabel('Day',fontsize=20)
4 [* R: ?$ t2 |5 ?0 g1 W: `. Aax.set_ylabel('Infective Ratio', fontsize=20)/ V( `6 g4 J- P/ z
ax.grid(1)7 W/ n; I1 g. E
plt.xticks(fontsize=20)
# a0 X- q; `$ `/ u* B3 Eplt.yticks(fontsize=20)" T2 k* x" |+ a P4 I4 o3 |" E
plt.legend();
4 O! _8 x5 M! k3 L
5 A" a' M; Z5 h' v
. Y2 v( @" S2 u* ~$ }- h![]()
; b) |" `( v; I$ n, ~* O, P
; e; E* y5 K) e( d% |/ K0 H感染人数峰值发生在一个月左右,最大感染人数不到人群的20%, 但是最终人群的80%都会得此病(就是最终的移出者的比例)。SIR模型适合研究没有潜伏期的急性传染病,治疗后能够痊愈并具有抗病性。 到这里,虽然不准确,我们也可以先用SIR模型来分析一下此次疫情,武汉新型冠状病毒的传染病动力学! 模型有了,其实就是确定参数的问题。一开始就有人做了这个工作: Image Name于教授给的参数是参考了非典的, ,初始易感人数为一千万, 初始感染10人,初始移出者5人,那么我们的城市总人数 , 带入我们的模型得到结果:重现于教授的模型# Y7 M3 o# [$ [ x: h. z
高峰和尾声日期的推测基本相符。
/ P( m$ W* p- n3 u. V# susceptiable ratio
3 h2 \1 L! g" F0 N0 g1 |' Is = np.zeros([T])% x s/ A9 _2 n/ c0 z" q# v* R
# infective ratio
. }# A% t/ ]/ h. K/ [4 v/ zi = np.zeros([T])4 Y: I) ]& `- U1 w8 z" k, K
# removed ratio
2 Z% \4 D& P! G4 wr = np.zeros([T])
6 K8 A$ N. ?% V* N m; t7 m& C+ _2 {3 f/ C3 z, t
# birth ratio
' l/ N! }5 G9 x1 F% u& s- Y; {3 l* V6 L2 N. Ib = 20.0 / N9 S; r) n+ u3 A+ ]$ Z! v" a
# death ratio
! ]4 u5 `- Y0 `+ v) w6 q8 Ld = 10.0 / N
2 U$ {6 }2 u! U" }9 z7 L2 {9 M* `
$ K5 C2 n) y! M3 w `# contact rate5 G+ t7 R( L0 V K% [
y = 1.5; Z* ]/ e2 v( K/ B9 W
# recover rate$ o$ f6 d1 g& M4 L$ ^. @- d
u = 0.8 # 1 / infective_period. f& Y' E0 @# k# D
9 s2 `# s4 _* C
# sigma = y / u
5 i" V. |) w* e# J' B: |( e X5 b7 a
# initial infective people
" B4 @5 Z( [: S+ K O% B( vi[0] = 45.0 / N
2 } p% m, \% Os[0] = 1 - i[0]: E1 u' W/ d4 A4 z4 l
for t in range(T-1):$ y4 S1 P5 J0 `' [$ q
i[t+1] = i[t] + i[t] * y * s[t] - u*i[t] - d*i[t]
/ Y# B/ e- e" i1 n' ?. {( c) _5 M, g s[t+1] = s[t] - y * s[t] * i[t] + b - d*s[t]. E5 B7 k" K5 a# i0 S B0 C
r[t+1] = r[t] + u*i[t] - d*r[t]0 X E+ e& C3 a& v6 ^" E9 [7 T
4 C1 q* B# H( D2 z# w. e) i* kplt.plot(i)7 e6 Z- S# B Y+ G! C# J$ x, J. R
plt.plot(s)4 F+ Y1 E# ?1 n" x: m/ \
plt.plot(r)
3 \4 C; U& w* Z/ q* eplt.plot(np.diff(i),ls='--')3 h h4 ~' C; W& ?
8 @ \1 v. H8 V6 V( s9 U9 E, J4 {0 e4 L+ O( G' x; `( w0 m
[<matplotlib.lines.Line2D at 0x7f77796e8518>]
: @ w n1 E$ I; r0 E j/ @
1 v5 x$ f" b+ [# r) E![]()
, k4 b6 O+ K* ]' S [9 ]' N# M( D( R9 i
SEIR模型但是,SIR模型和实际情况的出入会比较大,因为忽略了太多因素了,比如说潜伏期,比如说政策调控,药物,出生死亡等等。下面我们可以和前面一样,把潜伏期考虑进去,新增一个人群,叫潜伏者E(exposed): Image NameSEIR模型4 R; g( S- @( }; E$ W$ H3 l, b
同样的我们需要计算各人群每天的增加量: S:每天减少: 5 G( P" V: O& m1 D
E:每天增加传染,减少发病:
3 I) ~' H! m4 N: T2 SI:每天增加发病,减少治愈: # U8 c9 Z/ g6 E3 I& J" W; j
R:每天增加治愈: 3 E" J: k5 Z( e% n4 ^% d! B$ d/ c: ?) R
建模完成,修改我们的python程序,这里的 可以理解为潜伏期的倒数。给的4天。新型冠状病毒给目前临床的潜伏期是3-14天。. P0 Q0 t( r2 L8 O( ~4 Z* U5 }$ ^
# population
8 I: c7 {0 v1 \8 zN = 1e7 + 10 + 5
; m7 P: S# |' V! r( W3 v4 E# simuation Time / Day
$ Q& f' K0 f: ST = 170
$ {" S0 U6 ?" r+ o" z* Y4 m, j7 n1 \6 T# susceptiable ratio9 x8 r' h4 S3 v& b1 j) V4 |/ f
s = np.zeros([T])
6 u7 h' ^0 b. F5 w) e# exposed ratio
5 ~. v# ?$ b7 r$ S! E. re = np.zeros([T])
' N6 O! b$ G% L; P1 |# infective ratio
5 }" N; B% y2 G" D. @i = np.zeros([T])
; G: ?2 ^( q- J/ @$ U9 q( r, N# remove ratio
- a: T4 h4 S* k, N8 Gr = np.zeros([T])" |6 a0 T! w1 B, E) G/ p* H
% |# E+ _( ]" F: A6 _
# contact rate+ a' t9 _/ ~* M( D. M; ]0 U
lamda = 0.5
3 Q. i+ @# o0 {7 c) T% Z# recover rate+ _# I& R) [( h- J, ]! b
gamma = 0.0821
; n% k% Z6 I! l$ z n+ r0 g# exposed period
+ }0 B7 r+ u( c2 n$ Bsigma = 1 / 4+ s- Q8 J- e$ K0 F, h
. {* }9 W+ H9 |0 m% I0 ~6 G# initial infective people) |# J+ `! w7 k+ Y" s3 Q
i[0] = 10.0 / N
9 V% I5 U4 v) Fs[0] = 1e7 / N
# G& N: V+ `8 G8 d+ T3 Ge[0] = 40.0 / N
4 g' U% s* g8 f' t: [: F6 qfor t in range(T-1):6 [( \+ M" i! ~
s[t + 1] = s[t] - lamda * s[t] * i[t]
9 {9 |1 J" z! n/ S8 }! Z e[t + 1] = e[t] + lamda * s[t] * i[t] - sigma * e[t]
5 W4 r0 O9 ~5 {, v7 |( z i[t + 1] = i[t] + sigma * e[t] - gamma * i[t]
e: M. `" @9 @- z, w" ?) T, ~ r[t + 1] = r[t] + gamma * i[t]# `) S6 s2 n% h8 }5 \# Z1 E
& O6 M2 E8 X. w, g* Q; _
5 S8 c) ^" g1 m* b
fig, ax = plt.subplots(figsize=(10,6))
( G o; h! y3 y$ j" K/ b, Kax.plot(s, c='b', lw=2, label='S')' |# j7 y& o" v, C$ D. o- H8 G
ax.plot(e, c='orange', lw=2, label='E')0 i; v1 F1 u* P! I# Q* K
ax.plot(i, c='r', lw=2, label='I')
$ s! y/ J, {. R& \ax.plot(r, c='g', lw=2, label='R')
9 J0 m) M" Q% U% P3 ~" D3 @7 ~ax.set_xlabel('Day',fontsize=20)
( a& c* p/ A; }- }$ C4 rax.set_ylabel('Infective Ratio', fontsize=20)9 w- h2 p3 z0 ]- ~ H
ax.grid(1)
/ `% I& m, t6 y% {9 iplt.xticks(fontsize=20)
+ O: v7 H9 W- z: @7 splt.yticks(fontsize=20)# d7 Z6 R$ h U- v, f
plt.legend();
% y d% U' F$ y/ i8 F# L+ T6 ?! B/ @, U; x: e9 S( S. z
4 G" a0 b1 d0 s# C
![]()
& M& Q! R4 f6 E% g1 R7 J; M- g5 A
9 ~& p% `/ ?- R! G$ {% p6 V按照模型的结果,此次疫情可能真的要持续到 三四月份。这个接触率 真的非常影响表现,模型给的是个常数,但是由于政府措施的原因,这应该是个变化的值。$ x) n6 g6 E* @4 f
还有治愈率 也是。没有完美的模型,但是随着考虑因素的增多,就会越来越接近实际情况,从而指导政府的疫情方针政策的制定。$ V5 j2 v2 [+ i
$ _; g- V1 m/ o' }& T5 r$ l6 B# i! N- }. p: A w/ ]
! d7 h+ a8 s1 n* j
& e/ Q( y9 P5 j% `# K
|