|
什么是传染病动力学?numpy和matplotlib用python实现传染病模型SI模型SIS模型SIR模型SEIR模型 什么是传染病动力学?最近,在报道疫情的众多新闻中,相信大家也看到过一些来预测新型冠状病毒会导致感染肺炎的人数。你一定好奇,这个人数要怎么预测呢?预测人数又有什么用呢? 事实上,从学科方向来说,这类研究属于传染病动力学,就是用数学模型去描述传染病在人群中传播的规律,从而预测患病人数,进而指导政府制定措施和政策去控制传染病的传播。0 P: I3 b$ V: l
这类研究最早可追溯到18世纪Daniel Bernoulli对天花的研究,而我们今天所要介绍的SIR模型是1927年Kermack与McKendrick在为了研究伦敦黑死病而提出的,是传染病动力学中最基础的模型。 介绍了传染病模型的背景信息,不知道现在你对传染病模型更有兴趣,还是执着地对python更有兴趣呢?不论哪种,这篇文章会满足你所有的好奇心。 numpy和matplotlib首先,安装一下这节课我们需要使用的两个python包,numpy和matplotlib。
5 Z6 _' h7 `! s' pnumpy-是python进行科学和矩阵运算最常用的包。 用numpy建立一维数组,存储和计算每天传染病人数的数据。
$ \* P5 ]* }* A* X% A* F7 Limport numpy as np import matplotlib.pyplot as plt 用matplotlib绘制传染病人数随天数变化的曲线,给出模型预测人数变化的直观认识。 好啦,下面开始用python实现传染病模型吧。 用python实现传染病模型为了让大家能够更好地理解,我们先不直接说SIR模型,我们从最简单的开始。 SI模型首先想象这样一个场景,一个城市有 个人,假设没有人出生和死亡,忽然有一天有 个人感染了病毒成为了患者,如果每天每个患者能够有效传染 个人,那么第二天患病人数是多少呢?最简单的答案是: ,也就是说每天都会新增 个患者。那这样以来,在无限远的将来会有无穷多的人被感染,显然这是不合理的,那错在哪里?仔细思考,你一定发现了,已经患病的人就不能再被传染了,所以我们有必要把人群分为两类,易感者(S-susceptiable)和感染者(I-infective)(你猜的没错,这就是SIR中S和I的含义,R的含义之后介绍再讲)。为了之后方便计算我们记易感者和感染者在人群中的比例为 ,那么 。我们重新考虑上面的问题,顺便来个示意图: Image Name这样的话,每天新增的患者数为 ,也就是总传染人数乘以易感者所占的人群比例。
; Z& g0 f: a, P- l$ u+ j4 @5 A c那么每天的感染者比例的增加量就是 。我们假设城市有一千万(N=10的7次方)人,每个患者每天接触感染每天0.8人(lamda=0.8),初始感染人数为45人(i0 = 45/N),我们来模拟70天(T=70)的情况。 # population2 A7 v. ~9 T; H B4 p- _2 ?
N = 1e7
1 j2 x2 F7 f6 @$ t# simuation Time / Day
) \* L( [2 j% c& ~" c! q! HT = 70
$ u% O- I" S+ }# ^8 Q& [3 |8 z# susceptiable ratio- F- v" f4 I S% I/ |
s = np.zeros([T])
9 W& A2 b7 e5 e7 [1 s0 ~; D# infective ratio- C C; m" ?) s/ V7 D0 ?6 p" |
i = np.zeros([T])
; w" A0 O s# T. `3 H# contact rate8 }- j5 N: @$ y
lamda = 0.82 P" J9 ^2 H; @
. {8 E* r" t* ^5 q
# initial infective people( v( x# A0 i( `1 I( e- b) Q
i[0] = 45.0 / N
( B& a% ]* ]; s; I# Q3 ^. a5 z5 T0 f) j" e4 w2 J6 a) T. m( {
for t in range(T-1):
/ A6 R3 `: B7 U; ^( E& g7 ^4 v7 H i[t + 1] = i[t] + i[t] * lamda * (1.0 - i[t])
" V% X7 m- j. J0 ^( U! a% r9 |) X! O1 ?& N" v
. \; ~! T5 d/ J; S9 Y9 o* ]) @ o4 _) v9 D/ {3 E
相信其他语句大家都明白,新知识是这两行:
6 g9 ]# _/ ^9 ]1 p) u* w8 o
8 v0 V9 `' B1 m# ]
* S' Z7 A% `/ E& [% ws = np.zeros([T])# V9 W: l3 E2 h+ }
i = np.zeros([T])
# l4 Z' `/ x! g$ N3 Y
! r' i$ w. W; s% A1 t ^3 f" a这两句话的意思是一样的,就是利用numpy(已被我们重新命名为np)的函数(zeros())来建立一个所有元素都是零的数组,而给的参数决定了这个数组的维度。比如:
0 x1 s: G; M3 e/ j1 t( Z) w9 e, S: y, U! _/ c* A! M3 P7 S
a = np.zeros([2,3])
$ h& E2 B) _6 w( u/ e3 z5 r% Fa
. ]) |2 p Y7 p. R6 p4 Q0 u$ l! ]! A/ \0 b O: F
array([[0., 0., 0.],
" j. M6 M% R0 ]6 |* K4 a [0., 0., 0.]]). x; ~. T6 j% B( k+ `0 p
3 E8 ]: _8 `' s/ b0 @: D% W$ l/ [/ L# q7 {
array([0., 0., 0., 0., 0.])1 E. a% }" \ l2 D7 j
# A9 k2 d+ k4 t9 C
# M' h8 |4 V" Y& e; c& V类似的还有产生元素全部是1的数组的函数np.ones():% y& O3 m" Z4 |0 F0 n
6 f& v% {) |4 s4 g0 i
a = np.ones([5])1 o3 L* r' V( Q. n' c
a* u' D8 @. O5 H5 `, X
: d+ Z( A1 t$ w* }array([1., 1., 1., 1., 1.])
: v& T `/ O3 Y, A* ]& w$ y, P0 y0 {3 P7 w% l( k2 S; X
& `5 V2 e2 C- R, L' ^
a = np.ones([2,3])
" m2 Q* D$ @1 C: h U9 c7 ?a
4 ^( S. {* f3 h: Y9 k3 j7 a; V; _8 d$ ]' B* K& m8 [0 \5 p( m0 X
# b& W* b- Q( n" @: z2 [array([[1., 1., 1.],
. T! F5 Z' A! X5 x' ? U% k [1., 1., 1.]])+ |1 p& V, e. I8 I* n+ U9 g( w
6 o+ P4 r& a! @+ h3 R, T: f; v, j: y7 n7 u) O' L2 m
plt.plot(i)) O$ C( A, A2 C; I5 l4 \
+ C" e4 j5 b' G& s
" X. Q; W7 j% Z4 n. e ]1 q0 t
[<matplotlib.lines.Line2D at 0x7f0c2768d6d8>]( B" U$ w- F; y9 r+ ]+ d
/ n+ a# U! _( ^+ I& I
1 |# {$ M( ?4 ~3 {![]()
" j; E: }7 F3 j$ _* l( Y2 S: `5 x! }4 d% K: C
- w1 j+ `* Y1 a. P6 ~9 d
实现SI模型的核心代码是第三个cell的第11,12行:7 x( K6 S8 h, ]9 n
9 `( j9 i4 J: U8 Q9 o+ \
for t in range(T-1):
B2 c( ], B& @1 P1 U0 ?/ S) S i[t + 1] = i[t] + i[t] * lamda * (1.0 - i[t])8 t6 {2 ? a9 }$ ]
; ^, K W9 D! F! l; O3 B" R
就是我们建立的数学模型,利用python的for循环语句累加迭代的方式把每天的增加量叠加到感染者比例上。 运行代码完成计算,我们利用matplotlib的pyplot来画出感染者的随天数的变化曲线:
8 G$ y* x1 Q2 I) E- Jfig, ax = plt.subplots(figsize=(8,4))5 i2 V; J: U9 J
ax.plot(i, c='r', lw=2)
( P5 D8 S: D3 U$ n/ b, k/ K6 pax.set_xlabel('Day',fontsize=20)# c5 d. F f8 E- u0 Y( `/ Q6 ~
ax.set_ylabel('Infective Ratio', fontsize=20)
9 @2 H3 M" y7 jax.grid(1)
2 |' N$ q/ k) ]( o9 vplt.xticks(fontsize=20)
5 v! |9 H) j! a2 g0 I" ~- kplt.yticks(fontsize=20);) M% h! |0 T( x
' E* |9 y* j* w& s6 O5 k% ^% s- d2 ^4 o& [
, \3 E( m" s' g: `4 e2 U
: g* H7 z& W8 R- N: L7 _# B
从这个结果看到,大约在25天左右,全部人群都会变成感染者,感染率 。% x" @" }+ x9 o* U& f9 D9 L6 n! @
在程序中我们假设每天每个患者传染0.8个人,你可以改变lamda的值,观察全部人群感染的天数的变化。# ^. s6 q1 v% w+ G9 \# O
认真思考你会知道,lamda的现实意义就是该城市的卫生水平,衡量的是消毒,隔离这些措施执行得怎么样。回到传染病模型,按照SI模型计算的结果,我们全人类都会患病,这好可怕!原因是我们忽略了一个很重要的因素,那就是我们有奋斗在一线的医护人员,我们会被治愈!所以SI模型只适合研究具有高传染风险又不能被治愈的病(比如HIV)。 但是对于其他病,我们是可以靠医疗和自身免疫系统康复的,那么紧接着的一个问题就是,被治愈后还会再被传染上嘛?根据这个问题的回答不同,我们有了两个不同的模型,SIR 和 SIS。现在可以揭晓,SIR的R的含义了,就是移出者(Removed),现实含义就是指被治愈后不会再被感染的人。而SIS表示治愈后仍然还是易感者。下面我们用python来分别实现这两个模型。 SIS模型为了实现这个模型,我们需要引入新的一个参数,治愈率 。好啦,先上我们的新示意图: Image Name和SI模型做比较,区别就是计算感染者的增加数时要减去被治愈的人数。
$ J" Y1 @8 [( G" j所以这时候每天的增加的感染者为: ,/ n; P' S+ u4 [
增加的感染率为: 。' E9 o% o* ~4 }+ c. z& h3 P5 H* g
模型完成啦,修改python代码:
. l& I7 @3 O; J0 E# susceptiable ratio
, C! y2 u5 w- ]. qs = np.zeros([T])3 ]" f* ]! ~! x" t1 e
# infective ratio' B6 Q5 Z, c. y) N+ S- o, I
i = np.zeros([T])- E1 C' c, x+ i" g* R2 Q7 `: t
$ c: D# }$ t; e3 u- | l; o# contact rate
$ H7 l6 m8 c2 i! glamda = 1.0) ]2 |9 Y# B$ ?0 }0 S/ F8 Q
# recover rate
, `9 T/ b. X7 S2 xgamma = 0.5
' O: k+ s: R. d% q R% |
/ X. W2 e. W O1 M7 `# initial infective people
' d1 {5 `' ~5 J6 L( |- ]* o4 d2 b! o; W/ yi[0] = 45.0 / N
: t0 b( N7 H' f; y* v. y$ @, `( a
for t in range(T-1):
1 P# U0 V: u) @ i[t + 1] = i[t] + i[t] * lamda * (1.0 - i[t]) - gamma*i[t]# S2 m2 a4 M" _) D# a6 d; i) Q& ]
+ {' V2 c/ [) s; k- c2 h0 F
8 b ]: s% P* V) ]- R& A
: ~- v9 R' B6 [运行代码,我们画出曲线(代码和SI模型的画图完全一样):
/ Z& f, N2 @& }/ s j
: f8 k5 n' f- g5 |" Z2 U) k: nfig, ax = plt.subplots(figsize=(8,4))
) M* y% z9 e; ]5 _ax.plot(i, c='r', lw=2)
. i/ A; c/ Q% p/ t7 I6 W' C7 Pax.set_xlabel('Day',fontsize=20)
T+ \3 i6 }5 Q c8 \+ N0 u2 @/ ]ax.set_ylabel('Infective Ratio', fontsize=20)' e/ \1 P7 z& H0 [0 A# _( p: K' H
ax.grid(1)
- Y2 P9 Y/ W2 [0 g1 ]% _plt.xticks(fontsize=20)
. A! p, B7 R9 V9 gplt.yticks(fontsize=20);7 s( C% o. [0 ~8 Z9 K6 O* y
8 \* d% F+ k2 n3 w6 }8 m 9 p1 X3 P' h! {
3 y* D! v" }$ z) N* F) I) g& Z3 l4 V
行代码,我们画出曲线(代码和SI模型的画图完全一样)
( `$ G) R* o- ^4 H可以看到,达到最大感染率的时间退后10天左右,最后感染和治愈达到动态平衡,人群中有始终有一半的人感染着。所以,SIS模型适合研究具有传染性和反复性的流行病,比如常见流感。同样的,感兴趣的话,改变lamda和gamma的值,观察曲线的变化。和lamda不同的是,gamma的现实意义就是对这种疾病的治疗水平。 SIR模型加入了移出者,被治愈的病人不会再被传染,先上我们的新示意图: Image NameSIR 模型- X: E" n/ Z8 o2 v
注意到这里,人群被分成了三类,不再只有I和S,所以相比于之前的模型,我们需要找到新的约束关系。现在我们需要分别计算三种人每天的增加量了: ( e- r7 Z& @- z$ N
- 易感者:每天都在被传染,所以一直在减少,减少量为被传染的人数:
- 感染者:增加了被感染的人,减少了治愈的人:
- 移出者:增加了治愈的人:
5 G( }4 i# v* H+ q" W( x
建模完成,修改python代码,并且假设人群普遍易感,新型疾病,初始没有移出者。
" e2 W2 g* n" Y/ N! X* B5 i# population/ s: w! |, E& ~7 f. R- \' c
N = 1e7 + 10 + 5
1 _0 N% j- |0 K+ T! K; Z; N) i# simuation Time / Day
( C1 V% Z" [, t8 i0 ]T = 170( K& h4 C; K& C; r
# susceptiable ratio
" R, H5 b7 R3 {) J; A J5 d i8 H' V" rs = np.zeros([T])
+ Z/ m: s" e8 w0 W) j# infective ratio3 `/ Q- \2 \, x% [$ d- u* J
i = np.zeros([T])( `- i, [& T5 N
# remove ratio
2 Z/ t& E- Y8 s9 H6 q+ G2 t- Ar = np.zeros([T])
" ~1 f4 [9 R( D8 d7 |- w, j, q" j# D' V
9 ?; O1 X% z$ K8 C- N( k# contact rate
! {$ a( P; x. E1 P8 h: k5 Elamda = 0.2586
# N# W' {& `$ P3 ]& W# t# recover rate. t+ a+ F/ \6 S2 S* d J
gamma = 0.0821& ?! e, I1 Y1 R
% \3 ~* R {$ m" f R {
# initial infective people2 h8 j3 z( u3 v* a( G% V
i[0] = 10.0 / N
1 B( [6 {& Z6 o7 @6 Ps[0] = 1e7 / N
4 D/ i) j6 Q7 m cfor t in range(T-1):& j6 a) X2 L! U- l3 I) w4 F
i[t + 1] = i[t] + i[t] * lamda * s[t] - gamma*i[t]# M F( h7 w+ o0 N) X, {, _4 S) {
s[t + 1] = s[t] - lamda * s[t] * i[t]( a9 }; ^) Q- k( ?' L7 i% M
r[t + 1] = r[t] + gamma*i[t]) y4 s0 F2 h% \
/ S: N/ V! n. P* d$ T, i5 xfig, ax = plt.subplots(figsize=(10,6))5 T. ?3 ~, W- r
ax.plot(s, c='b', lw=2, label='S')# }: O: S1 f3 L7 {1 ?3 O' g
ax.plot(i, c='r', lw=2, label='I')
( I+ \, p6 b9 \: [# q Aax.plot(r, c='g', lw=2, label='R')! j0 m0 K2 K! g9 ^9 [
ax.set_xlabel('Day',fontsize=20)
# r% b' | }+ \' [% t- H9 U$ |ax.set_ylabel('Infective Ratio', fontsize=20)6 ?, w; s. V/ \' f
ax.grid(1)! E! {+ b: M8 G& U" y
plt.xticks(fontsize=20)
3 h r5 S" j0 w( @, S8 l. splt.yticks(fontsize=20)
) y9 p- P0 g: z* y! ~plt.legend();8 v+ m B: m& t) p7 [
8 F2 k# x. L+ |0 X3 J
" M6 R% f3 M& \
: m8 _* R: L8 B- @4 D; }. I- v
" A% a- w) f5 |1 i: _
感染人数峰值发生在一个月左右,最大感染人数不到人群的20%, 但是最终人群的80%都会得此病(就是最终的移出者的比例)。SIR模型适合研究没有潜伏期的急性传染病,治疗后能够痊愈并具有抗病性。 到这里,虽然不准确,我们也可以先用SIR模型来分析一下此次疫情,武汉新型冠状病毒的传染病动力学! 模型有了,其实就是确定参数的问题。一开始就有人做了这个工作: Image Name于教授给的参数是参考了非典的, ,初始易感人数为一千万, 初始感染10人,初始移出者5人,那么我们的城市总人数 , 带入我们的模型得到结果:重现于教授的模型' c# Y! H9 ~4 }
高峰和尾声日期的推测基本相符。 ; o9 [, ^" \4 \ w9 q% P, V
# susceptiable ratio
- b# K- d7 C, e6 S! Bs = np.zeros([T])- d1 \- I/ g1 P" C, Y
# infective ratio- F4 @5 R$ b% }2 T$ v! q
i = np.zeros([T]). B4 j% k/ k" Y4 d# p
# removed ratio
, }0 C2 k' ^5 d% d3 A) W' [8 Rr = np.zeros([T])+ Y6 `$ F: w! r' Q
! K; c+ r- [! O
# birth ratio) W1 B0 l! X2 S2 W0 w1 j
b = 20.0 / N3 E4 q, w: M+ _8 q. z0 S5 D) ^) x
# death ratio! I: Z s) A( }7 q" h1 V$ W
d = 10.0 / N7 N9 b, N0 q# J6 [
7 T; v7 Z. W. |( y8 ^7 E# contact rate
. f9 S6 p' K8 [y = 1.5, \6 k* n9 V5 h+ w! P2 N, P
# recover rate2 F$ ^4 L2 a' J5 h( [
u = 0.8 # 1 / infective_period1 t! f# {# W% e+ M8 l0 s
# x$ j; ~5 V3 ? G' Y, v
# sigma = y / u% |; a# v" c6 @
+ r3 Z* L2 {& X) H# initial infective people
) G* Q$ u) q8 b/ M0 l$ a* ]i[0] = 45.0 / N
7 c7 S/ e: N) w8 T, K' a0 |+ _ }s[0] = 1 - i[0]" O' i+ w; u( {8 H
for t in range(T-1):
; f4 `# e4 K* W4 @+ t5 m, N i[t+1] = i[t] + i[t] * y * s[t] - u*i[t] - d*i[t]" p9 X# U9 Y9 V
s[t+1] = s[t] - y * s[t] * i[t] + b - d*s[t]
6 @( V1 D" q! @5 ~2 C" H2 l r[t+1] = r[t] + u*i[t] - d*r[t]
I" y( ~$ Q+ r6 G2 l2 w
( T" x* [/ `0 Y7 |/ f# A3 Yplt.plot(i)
$ x1 \: W9 Q2 q5 k' K3 P$ @, V; W! nplt.plot(s)8 \7 f, a/ b1 j5 ]: Y& o
plt.plot(r)
1 z6 z* s& U& R! Wplt.plot(np.diff(i),ls='--')# ^+ \/ p; q, _+ A, W/ U
+ [! N, w4 t( ~$ V( s6 f$ d- R
' a8 R8 d3 r, P[<matplotlib.lines.Line2D at 0x7f77796e8518>]
6 ], K" H. N8 M+ M( D- \1 i8 J ?1 X2 j5 ~
! D0 W( }/ J- p. v0 N
: m$ L) P. x# HSEIR模型但是,SIR模型和实际情况的出入会比较大,因为忽略了太多因素了,比如说潜伏期,比如说政策调控,药物,出生死亡等等。下面我们可以和前面一样,把潜伏期考虑进去,新增一个人群,叫潜伏者E(exposed): Image NameSEIR模型# j0 q. z3 o7 C3 F# r0 H
同样的我们需要计算各人群每天的增加量: S:每天减少: 6 N! ?+ }, |3 i6 j1 ^ q
E:每天增加传染,减少发病:
9 f) M* n/ H$ x \+ b" O. fI:每天增加发病,减少治愈:
( K0 y& m% S8 Y8 |R:每天增加治愈:
$ U# O4 m8 I3 V- R Q, l: G建模完成,修改我们的python程序,这里的 可以理解为潜伏期的倒数。给的4天。新型冠状病毒给目前临床的潜伏期是3-14天。9 Z- O1 k' D& m( H* i
# population
2 ?# Q$ `; C4 Y& X/ T& J$ K" HN = 1e7 + 10 + 5
0 y2 c4 ]9 E0 R# simuation Time / Day
" W( X. J- b) C8 oT = 170
8 A* L7 |2 f, l* n! ?# susceptiable ratio2 ]! O4 E: F) E8 e' d4 V. Z2 A K
s = np.zeros([T])
% F) _+ S* h6 T1 C# exposed ratio, h# f' e. \4 `
e = np.zeros([T])
7 s/ n' |7 Y6 e( Q6 P7 Y, i+ g0 F# infective ratio% b, c6 k. ]* n
i = np.zeros([T])4 S: V5 u {0 ~- _- `/ W; n5 u
# remove ratio
+ x* n5 V9 S5 H$ Jr = np.zeros([T])
& h& K4 c4 v7 G% h, q% w' c
0 h8 P* _& \7 C4 S9 d3 O# contact rate
* W* K& e7 h: {. dlamda = 0.5
( L: m. I! c7 g f# recover rate* i% j4 ^/ P1 j) F( O* a- b
gamma = 0.0821- M9 p% s. M% v! K. f
# exposed period( k8 [# }- B Q2 M+ Y
sigma = 1 / 4& E: k6 _& `" f' }0 }
* U2 i: l; I; h' S# ~
# initial infective people
$ \4 n; H" D$ M7 fi[0] = 10.0 / N
) d: k! y V+ i, S9 c. cs[0] = 1e7 / N
" J' F4 L; F6 j) Y1 Xe[0] = 40.0 / N" _# Q. ?7 p) ?+ S+ c, @5 W* I
for t in range(T-1):# x; Y+ u% ?3 x. e) c. p
s[t + 1] = s[t] - lamda * s[t] * i[t]9 E/ U4 u9 F. s+ b4 H! h" J( D
e[t + 1] = e[t] + lamda * s[t] * i[t] - sigma * e[t]
* X8 D% P4 O( i1 L. o# { i[t + 1] = i[t] + sigma * e[t] - gamma * i[t] o0 w1 c7 b! W9 _' S- m2 v- z
r[t + 1] = r[t] + gamma * i[t]
% R) l9 L/ V1 o( S6 ?7 {$ P
0 G; U* L1 a; y: {1 }1 N
0 F) s2 j' m9 C# C! \& ~0 E# lfig, ax = plt.subplots(figsize=(10,6))
0 }% j) D6 J2 \6 Y; ~+ {ax.plot(s, c='b', lw=2, label='S'). H2 V8 v6 F% }( }* j
ax.plot(e, c='orange', lw=2, label='E')# q; Y1 P. s, U y6 z. I
ax.plot(i, c='r', lw=2, label='I')
. J# z, Z5 G! M2 }: _0 Max.plot(r, c='g', lw=2, label='R')7 k0 n+ e0 v& n) w }
ax.set_xlabel('Day',fontsize=20)- R0 K" t: b2 Z( E& C( _
ax.set_ylabel('Infective Ratio', fontsize=20)
, S4 d; ]8 D$ O0 o7 dax.grid(1)* Y1 }* J$ p# U* y
plt.xticks(fontsize=20)
* f; G: a. n; q% y8 b( x8 E& aplt.yticks(fontsize=20)
y0 G& g3 q" k2 N+ g1 ?plt.legend();* [2 w/ `6 g9 s9 Q/ }. y4 [
& b* g5 j" H$ d+ h
7 W) w5 A/ H9 Q - t: c3 P) u" Q5 b) G- ~9 N# ?
- Y( O0 E2 ~% A5 i1 o
按照模型的结果,此次疫情可能真的要持续到 三四月份。这个接触率 真的非常影响表现,模型给的是个常数,但是由于政府措施的原因,这应该是个变化的值。
* p6 H3 `, [! i还有治愈率 也是。没有完美的模型,但是随着考虑因素的增多,就会越来越接近实际情况,从而指导政府的疫情方针政策的制定。
8 U# r. k% Q- q3 |( @
1 \1 N% \) s* x s# @' ~( y" Y
: r* c& I- g! O( T9 F9 ^, @
% Z( t# x* b% ? |