|
什么是传染病动力学?numpy和matplotlib用python实现传染病模型SI模型SIS模型SIR模型SEIR模型 什么是传染病动力学?最近,在报道疫情的众多新闻中,相信大家也看到过一些来预测新型冠状病毒会导致感染肺炎的人数。你一定好奇,这个人数要怎么预测呢?预测人数又有什么用呢? 事实上,从学科方向来说,这类研究属于传染病动力学,就是用数学模型去描述传染病在人群中传播的规律,从而预测患病人数,进而指导政府制定措施和政策去控制传染病的传播。0 n R, H+ O2 p) ^+ O- G, `, E2 H
这类研究最早可追溯到18世纪Daniel Bernoulli对天花的研究,而我们今天所要介绍的SIR模型是1927年Kermack与McKendrick在为了研究伦敦黑死病而提出的,是传染病动力学中最基础的模型。 介绍了传染病模型的背景信息,不知道现在你对传染病模型更有兴趣,还是执着地对python更有兴趣呢?不论哪种,这篇文章会满足你所有的好奇心。 numpy和matplotlib首先,安装一下这节课我们需要使用的两个python包,numpy和matplotlib。
/ @# s8 \- `' [( B0 m5 L( O0 p$ enumpy-是python进行科学和矩阵运算最常用的包。 用numpy建立一维数组,存储和计算每天传染病人数的数据。
/ A9 M) U( I k4 e+ D$ V/ Dimport numpy as np import matplotlib.pyplot as plt 用matplotlib绘制传染病人数随天数变化的曲线,给出模型预测人数变化的直观认识。 好啦,下面开始用python实现传染病模型吧。 用python实现传染病模型为了让大家能够更好地理解,我们先不直接说SIR模型,我们从最简单的开始。 SI模型首先想象这样一个场景,一个城市有 个人,假设没有人出生和死亡,忽然有一天有 个人感染了病毒成为了患者,如果每天每个患者能够有效传染 个人,那么第二天患病人数是多少呢?最简单的答案是: ,也就是说每天都会新增 个患者。那这样以来,在无限远的将来会有无穷多的人被感染,显然这是不合理的,那错在哪里?仔细思考,你一定发现了,已经患病的人就不能再被传染了,所以我们有必要把人群分为两类,易感者(S-susceptiable)和感染者(I-infective)(你猜的没错,这就是SIR中S和I的含义,R的含义之后介绍再讲)。为了之后方便计算我们记易感者和感染者在人群中的比例为 ,那么 。我们重新考虑上面的问题,顺便来个示意图: Image Name这样的话,每天新增的患者数为 ,也就是总传染人数乘以易感者所占的人群比例。
" W, E( ]: N' X3 _" |9 z2 N; V# P那么每天的感染者比例的增加量就是 。我们假设城市有一千万(N=10的7次方)人,每个患者每天接触感染每天0.8人(lamda=0.8),初始感染人数为45人(i0 = 45/N),我们来模拟70天(T=70)的情况。 # population
8 _' n2 J9 j6 ]* R' C" ?N = 1e7
% c8 [" k. W" g" ? f% v9 _5 ~( j# simuation Time / Day
! x0 }: d5 t# u7 q$ gT = 70) P6 q1 p n! P8 s8 ~
# susceptiable ratio7 U. _5 ]; |, A+ i `3 ?3 W
s = np.zeros([T])
7 s" @/ a( j# Q! C# infective ratio- Q$ |% P L; t) w4 A) {
i = np.zeros([T])
, g# V9 J& K4 d# contact rate7 B. o# o6 t2 ~: z8 P
lamda = 0.8; [9 k t, v- l, V. P
* r4 `& I$ m$ l0 F ?/ A: N. Z
# initial infective people
4 Y1 [, {# N7 F5 g( A3 ri[0] = 45.0 / N
$ O+ U. N& g' q4 Z/ k# I
" T( g m( m- afor t in range(T-1):
# R+ g& z3 ^. q- [6 d5 D, a1 g b S i[t + 1] = i[t] + i[t] * lamda * (1.0 - i[t]), r- a! z1 b0 e7 o* |8 l
7 E! B! B/ A$ w6 W4 Q5 _. R9 J3 c( q
H6 m" U5 l; d, h2 ?) w' I相信其他语句大家都明白,新知识是这两行:' I# Y2 t, P8 g- n
9 g: A- Q0 B* v W3 k9 c
7 p# ~7 z( c' J9 @' k5 fs = np.zeros([T])$ F" v' q( \5 j- y- a1 Z% ^9 Z+ Y
i = np.zeros([T])
1 Y" y! Z7 j4 l* A1 j2 l3 @. v" i4 ]
1 d* n4 L$ n- x$ g8 e这两句话的意思是一样的,就是利用numpy(已被我们重新命名为np)的函数(zeros())来建立一个所有元素都是零的数组,而给的参数决定了这个数组的维度。比如:
8 @" X5 W# u0 s5 W
# P, y8 t' `. f4 i* pa = np.zeros([2,3])
2 v P3 E6 r0 `( u3 {, T! Aa
% a. f8 [! b* q: l+ ` l/ P: _* r7 Z* Y1 f/ ~: l6 a, n
array([[0., 0., 0.],
; P# `3 C- e9 p) f0 U* R: l; k [0., 0., 0.]])5 e8 y3 ?4 G. n$ n3 u# K: L
* {' `+ [! I# o. U
5 L; w1 V9 D; C. p' H1 t+ L
array([0., 0., 0., 0., 0.])7 _, g G2 X, `* z' @$ n
$ C& r9 G% @. y0 O, O4 C
4 m5 ]0 O. D; k, c9 u3 j! W
类似的还有产生元素全部是1的数组的函数np.ones():% d: j! k/ Y# O- N2 Z/ `
* l1 z" n0 _7 L# ]
a = np.ones([5])
Y" B! p: ], V3 ]6 O) |& `a5 D! K( [/ r! K. E" `# Q' P& \
9 V0 j' {7 f! c l& _. t, k" F
array([1., 1., 1., 1., 1.])
* u& P% W' f, \( X# ^& G* o) g9 q: I/ x3 _, ?8 T& Z( e
1 [% g _7 I9 M) O$ ]- a+ ]a = np.ones([2,3])
( V+ t, J' e" t' m" q& [a: r1 A) q' C8 }$ U6 K
+ t! C h; Y& f
, B4 Y1 `* |4 y* o9 v) Q, m: Q
array([[1., 1., 1.],
, ^- Q. K: ~# f! U [1., 1., 1.]])
% l6 M1 ?7 S) h, ]4 { f- k5 } Q0 A( H* r. i$ G8 H
) s5 G" \$ M' a8 B8 Z/ J' O
plt.plot(i)
& a- c- g v+ c6 I# M2 H7 m. g4 @. C
$ ]. k: l5 E" N { y: ?7 w1 ^[<matplotlib.lines.Line2D at 0x7f0c2768d6d8>]
( N) _1 k% P3 L2 r% g% G) x, a; {) M& k
1 a6 e; j2 x S% H( j
2 {, W( p& m, h- u6 b+ M1 z- O/ e![]()
. I- Q6 M4 o8 j# Y% `5 u' z& s
1 B! V" r. X; y% D6 n' t/ X, Y5 o" }$ h% R( N
实现SI模型的核心代码是第三个cell的第11,12行:
3 E; F. l* P6 v( W9 N4 M
% X$ b+ y' P/ G( J) | ]6 S4 Pfor t in range(T-1):
+ o9 I, a2 |: L4 d5 a8 v i[t + 1] = i[t] + i[t] * lamda * (1.0 - i[t])
2 A! y4 p2 s x+ H6 M
p' ]" O0 t) E- F! v/ C就是我们建立的数学模型,利用python的for循环语句累加迭代的方式把每天的增加量叠加到感染者比例上。 运行代码完成计算,我们利用matplotlib的pyplot来画出感染者的随天数的变化曲线:
9 {5 c; H. Y# S. H2 {+ k2 y+ Sfig, ax = plt.subplots(figsize=(8,4))
) }. a, z4 V8 B: k( @! j# A( C4 ]ax.plot(i, c='r', lw=2)
2 J! a. I, o* u; `, P- Z0 H, ~+ Q3 nax.set_xlabel('Day',fontsize=20)# @( \9 d) {; W0 L5 E9 L5 Y- N- k
ax.set_ylabel('Infective Ratio', fontsize=20)3 C' X4 @, r' _4 D, g; K _
ax.grid(1)
3 d8 O# y) d. r; _plt.xticks(fontsize=20)0 V: b6 d& [( E, ]. @7 l
plt.yticks(fontsize=20);
% ^7 V5 ~" R" h' j8 f. s9 b7 \7 A8 l! G. e7 t' H
+ [' G$ J4 T R! |![]()
6 l. A, I( U; c- O& {% P1 e; n# _) l7 H! D: I
从这个结果看到,大约在25天左右,全部人群都会变成感染者,感染率 。 n \4 x7 Y) P" ^' L) \
在程序中我们假设每天每个患者传染0.8个人,你可以改变lamda的值,观察全部人群感染的天数的变化。* [% R; f+ m# j: f; Y% r+ K
认真思考你会知道,lamda的现实意义就是该城市的卫生水平,衡量的是消毒,隔离这些措施执行得怎么样。回到传染病模型,按照SI模型计算的结果,我们全人类都会患病,这好可怕!原因是我们忽略了一个很重要的因素,那就是我们有奋斗在一线的医护人员,我们会被治愈!所以SI模型只适合研究具有高传染风险又不能被治愈的病(比如HIV)。 但是对于其他病,我们是可以靠医疗和自身免疫系统康复的,那么紧接着的一个问题就是,被治愈后还会再被传染上嘛?根据这个问题的回答不同,我们有了两个不同的模型,SIR 和 SIS。现在可以揭晓,SIR的R的含义了,就是移出者(Removed),现实含义就是指被治愈后不会再被感染的人。而SIS表示治愈后仍然还是易感者。下面我们用python来分别实现这两个模型。 SIS模型为了实现这个模型,我们需要引入新的一个参数,治愈率 。好啦,先上我们的新示意图: Image Name和SI模型做比较,区别就是计算感染者的增加数时要减去被治愈的人数。
# @2 B6 z3 m9 A4 \8 s- a3 F: d所以这时候每天的增加的感染者为: ,
; a' ?4 I* }) C增加的感染率为: 。' X* J+ Y- i6 D
模型完成啦,修改python代码: T( n* B: _3 E' h" o
# susceptiable ratio: Y$ h3 B) j9 V; g2 E4 i: M
s = np.zeros([T])
* J4 ]7 } V; g6 V V0 [ r* T! g# infective ratio ^' x. D/ `; b; @
i = np.zeros([T]). l! R% `: j [7 H0 c
( [7 {. M, ]% x; s2 W# contact rate
' h4 R! Q+ @" [2 z& v+ K5 j' |, M; @lamda = 1.0
& t$ A( D4 J2 f7 }. a# recover rate' z+ m6 g# Z. u B2 P5 x
gamma = 0.5
' M7 F0 I# j/ |. D: c2 w" }3 s1 u4 o" V5 n
# initial infective people
" ?3 |; M3 _$ y, O c$ R4 li[0] = 45.0 / N
0 a; n3 x P: [$ n. p
" m3 I- F& p: Q9 k1 Efor t in range(T-1):) ]4 M. E2 `" a
i[t + 1] = i[t] + i[t] * lamda * (1.0 - i[t]) - gamma*i[t]
; h% d R4 D8 i
- B e: j8 Z6 y+ T5 K+ _2 T/ ^$ _0 z. r% m
) \. i: x+ i% m. R! i
运行代码,我们画出曲线(代码和SI模型的画图完全一样):
) @3 N! g, L! Y! a
) x/ I# r0 T8 ^3 `1 l) afig, ax = plt.subplots(figsize=(8,4))' c' Y0 N$ [% Y, |( G
ax.plot(i, c='r', lw=2)
2 m- D3 E0 u F$ Nax.set_xlabel('Day',fontsize=20)
* ` _, o- S0 B1 k( nax.set_ylabel('Infective Ratio', fontsize=20)
2 q* f5 f3 ~) T' _6 T8 aax.grid(1)' C. r# Q4 W+ u- |/ p
plt.xticks(fontsize=20)+ V, Q9 ]# D3 ]
plt.yticks(fontsize=20);
# I) @! s9 F- \' U" T. s; J
" |) p2 j# z- z4 l' v" ~" o![]()
7 q, C6 h9 {: P! Y; n" t* \2 I0 B% }5 y- e/ b7 v
' G# h, q- _# z# a2 h+ N
行代码,我们画出曲线(代码和SI模型的画图完全一样)
: S1 J; H1 K; u/ e可以看到,达到最大感染率的时间退后10天左右,最后感染和治愈达到动态平衡,人群中有始终有一半的人感染着。所以,SIS模型适合研究具有传染性和反复性的流行病,比如常见流感。同样的,感兴趣的话,改变lamda和gamma的值,观察曲线的变化。和lamda不同的是,gamma的现实意义就是对这种疾病的治疗水平。 SIR模型加入了移出者,被治愈的病人不会再被传染,先上我们的新示意图: Image NameSIR 模型! ~2 x$ L$ B) `9 u9 `
注意到这里,人群被分成了三类,不再只有I和S,所以相比于之前的模型,我们需要找到新的约束关系。现在我们需要分别计算三种人每天的增加量了: # ^ k! p* S5 f; \- `
- 易感者:每天都在被传染,所以一直在减少,减少量为被传染的人数:
- 感染者:增加了被感染的人,减少了治愈的人:
- 移出者:增加了治愈的人: : \" N& z; j7 i) a( J0 C% F
建模完成,修改python代码,并且假设人群普遍易感,新型疾病,初始没有移出者。 + m5 o+ `; _" T4 K5 G4 R, J- R
# population( I; M, h/ Y' X
N = 1e7 + 10 + 5. L! [( M7 J, l! z
# simuation Time / Day# u) h. G) m+ o" z
T = 170
; i4 t$ a- D3 \- l7 h3 _# susceptiable ratio* h$ x& d* h2 e0 q, N& X" m p
s = np.zeros([T])
: j; E- s4 O4 O6 e/ k& q# infective ratio
" V+ U0 c$ S- ]3 v' \# {# _: ^i = np.zeros([T])
. ?# v- s: }2 U& t' m# remove ratio
, x$ Y+ T8 D# y4 G& ]r = np.zeros([T])7 t" T- H% o& I( V
5 X' M9 z3 l0 H. O
# contact rate, [4 X* ]4 y- P
lamda = 0.2586
1 L# W+ _& Q1 `& B$ p8 H" w# recover rate
" v8 s3 ^# y) y% lgamma = 0.0821+ j7 Y. L" A' d% \
- y) \: _/ f- ?1 _
# initial infective people. |" C$ A7 `6 J+ `$ L I6 f
i[0] = 10.0 / N& ^2 o2 b; {! G/ b. j
s[0] = 1e7 / N
t [. ?: Z3 M/ h5 S0 ]& {for t in range(T-1):0 R% ^1 |" O# ?& U# @
i[t + 1] = i[t] + i[t] * lamda * s[t] - gamma*i[t]& G6 ?0 Q8 C& A: k+ O! d+ X: [
s[t + 1] = s[t] - lamda * s[t] * i[t]! U" i1 S6 Q$ Y* |
r[t + 1] = r[t] + gamma*i[t]
% g7 v+ M: T" b# e* O
8 T- v* i$ u7 O1 E+ ufig, ax = plt.subplots(figsize=(10,6))
3 I, n4 t; A3 W. ~- b/ f* max.plot(s, c='b', lw=2, label='S')
" y) A* R4 Z+ f) [' d3 uax.plot(i, c='r', lw=2, label='I')
9 i! C0 g% ?1 F3 a `( jax.plot(r, c='g', lw=2, label='R')
; h* E0 ?/ {! Z" C: p6 Y% Oax.set_xlabel('Day',fontsize=20)
9 V" j9 A2 N; B1 \' |. u/ B7 E2 ~ax.set_ylabel('Infective Ratio', fontsize=20)" c3 n2 [- W2 A- p
ax.grid(1)% R* z+ |, z! V% [: N
plt.xticks(fontsize=20)9 I$ [" J8 e- S% I1 P/ Q
plt.yticks(fontsize=20)% d/ y5 z& z, {/ ~) R
plt.legend();
- }6 C/ @+ M& r$ h) Q
, l0 ?/ E' T* _# j) `# {
( o9 M4 c/ c) G4 z% G9 H% F![]()
( n! X1 h+ a% b( g
: z+ s4 ?) d) Z8 Z感染人数峰值发生在一个月左右,最大感染人数不到人群的20%, 但是最终人群的80%都会得此病(就是最终的移出者的比例)。SIR模型适合研究没有潜伏期的急性传染病,治疗后能够痊愈并具有抗病性。 到这里,虽然不准确,我们也可以先用SIR模型来分析一下此次疫情,武汉新型冠状病毒的传染病动力学! 模型有了,其实就是确定参数的问题。一开始就有人做了这个工作: Image Name于教授给的参数是参考了非典的, ,初始易感人数为一千万, 初始感染10人,初始移出者5人,那么我们的城市总人数 , 带入我们的模型得到结果:重现于教授的模型& O: d2 P! z" H: K
高峰和尾声日期的推测基本相符。
+ j9 b6 v# P/ J6 T2 ]: L+ ?0 v# susceptiable ratio2 {1 {; m l9 u
s = np.zeros([T])
; m2 W a; \4 ~8 I0 F9 [# infective ratio9 {% [7 k+ ]% [- C9 ~ c
i = np.zeros([T])
7 @. ~( `* K: d; h# removed ratio! g% X; B+ s- p, s$ ^5 Y
r = np.zeros([T]), H8 ?- I M) O+ a! P
+ M8 U2 E* T- { u! E( R# birth ratio# E+ d+ m+ d' c- Z
b = 20.0 / N( X% e4 K! |' }! F3 A2 M+ X
# death ratio
, E2 v. M: K( Qd = 10.0 / N% P' x) m! s: |2 J7 j6 Z9 M# X! N) Y
8 f, J8 v5 `/ R3 s7 _# contact rate
% D7 N$ O$ W: |" ?y = 1.52 n$ W. H2 N) r7 {- V9 J
# recover rate" E5 H$ H) ~8 C1 h& K" x
u = 0.8 # 1 / infective_period8 |* g+ t8 e3 V) p0 P+ T: U+ L
; N! s! A% D5 \; K# r# sigma = y / u
7 w2 E2 r: E* X( h6 H
; M8 [+ z: C8 X1 w9 w+ S# initial infective people
0 c- b- k, I/ b+ Q/ Xi[0] = 45.0 / N
0 o7 s8 a" H$ i Vs[0] = 1 - i[0]
k4 ^ t" y9 ^/ f2 m: xfor t in range(T-1):
8 S2 f( \( G0 ]+ r) l1 C$ B i[t+1] = i[t] + i[t] * y * s[t] - u*i[t] - d*i[t]
0 i" U: ]6 T) r6 g8 A& U3 ~ s[t+1] = s[t] - y * s[t] * i[t] + b - d*s[t] {. u8 Q5 I' K3 i
r[t+1] = r[t] + u*i[t] - d*r[t]. f; C$ g( m! Q9 ]' R
3 U5 [; O& A8 E: ^) ^
plt.plot(i)+ Z& E* u; R5 Q6 w; K. {: f. k- a
plt.plot(s)+ z' Z' D4 a$ f
plt.plot(r)7 g: L# ~3 W# }( m
plt.plot(np.diff(i),ls='--')$ \( a$ x" ?9 G& i% w: @; h
( A- m' B; u u
3 z/ k5 |# ?% |1 d6 }2 ~5 V[<matplotlib.lines.Line2D at 0x7f77796e8518>]
) _; B- {' e/ l4 H
1 _' B& M e [. f8 i$ M ' u. H( a4 d2 p* U
5 F- B0 j) z* x BSEIR模型但是,SIR模型和实际情况的出入会比较大,因为忽略了太多因素了,比如说潜伏期,比如说政策调控,药物,出生死亡等等。下面我们可以和前面一样,把潜伏期考虑进去,新增一个人群,叫潜伏者E(exposed): Image NameSEIR模型% i% x( I5 W& |6 V n. F" V' B$ `/ H
同样的我们需要计算各人群每天的增加量: S:每天减少:
0 E# M1 P8 {) c7 Z7 @/ iE:每天增加传染,减少发病:
+ q: P1 q- r$ u' y7 z& t+ oI:每天增加发病,减少治愈:
+ k: l1 o) g: I; pR:每天增加治愈: & [1 f P' ^3 D1 U6 C6 L: k
建模完成,修改我们的python程序,这里的 可以理解为潜伏期的倒数。给的4天。新型冠状病毒给目前临床的潜伏期是3-14天。
5 N/ R v( O- j+ v5 A ]$ c# population- ~! S2 b3 h6 {, N8 Y/ K, g" z
N = 1e7 + 10 + 5# z1 v3 W. x- M) S. C) x. E( Z
# simuation Time / Day
. H; }$ ~# H* X6 MT = 170
5 b4 H/ l( C) r3 ~ C6 f6 X$ K# susceptiable ratio5 Q0 J, p( G( f- c3 C d7 P3 N
s = np.zeros([T])
( i2 k2 i6 q8 x8 _# exposed ratio5 h0 w* V7 Q3 Y1 l5 b1 |
e = np.zeros([T])8 P) o% ?3 x5 }$ z
# infective ratio
0 _& A# Y/ G1 n" x+ L. G3 ?3 Ri = np.zeros([T])! h" \; H+ X; C
# remove ratio3 y. G( Z7 k7 e
r = np.zeros([T])/ K( h% F5 K+ n, N! n/ j
* X( x+ }1 \( j3 w8 z# contact rate
0 }. t8 M% e% M5 v: blamda = 0.50 \) M- I; T$ H
# recover rate9 S2 g& ~3 a8 `+ Q8 \7 L( v% Y# i
gamma = 0.0821
) C0 s' Z! e6 ^* s; w0 T1 _# exposed period A1 m; H% M0 e8 f
sigma = 1 / 4) B1 G4 _/ ~- n" I, }
/ Y" l8 z# p W* P
# initial infective people& ~0 E& m3 U; c! M1 {$ q
i[0] = 10.0 / N
1 @7 {4 M1 G, x7 |# R- G4 Is[0] = 1e7 / N+ B$ a1 G8 B! B; R% k2 F5 G
e[0] = 40.0 / N
+ A% b0 ^/ O9 N1 @. d# ~# wfor t in range(T-1):
% }& A1 S, E A6 }5 S) {) W$ k7 U s[t + 1] = s[t] - lamda * s[t] * i[t]
# ^( H7 P! {8 Y) c8 y/ y e[t + 1] = e[t] + lamda * s[t] * i[t] - sigma * e[t]1 x' Y. ^# b8 s+ P. f, ~# V9 j
i[t + 1] = i[t] + sigma * e[t] - gamma * i[t]
( i6 k. n8 e+ d% s: J* d9 m# D# C( x r[t + 1] = r[t] + gamma * i[t]4 T, T8 Q- D& f$ X4 O
6 V! ^6 k. M* o# A
2 i. T$ e5 F dfig, ax = plt.subplots(figsize=(10,6))/ G/ w+ ]' |/ U& t7 z @7 M" Q9 @
ax.plot(s, c='b', lw=2, label='S')6 G$ W }! U$ |% h
ax.plot(e, c='orange', lw=2, label='E')$ q: C$ c4 Y! C; r4 u, u
ax.plot(i, c='r', lw=2, label='I')
, }5 G# {: ^6 w! j, \ax.plot(r, c='g', lw=2, label='R')
: Y( g( e% d+ h6 f/ N0 lax.set_xlabel('Day',fontsize=20)
$ S& }) O/ ]3 A! dax.set_ylabel('Infective Ratio', fontsize=20)
, s* r& ?1 d. y+ D6 l8 ~. Kax.grid(1)7 o$ Q" H+ j- X6 i# k3 b
plt.xticks(fontsize=20)
: g% o0 `/ I: y2 e/ y2 k; O8 mplt.yticks(fontsize=20)4 x, J9 l! f& V. I
plt.legend();
0 C+ j4 d1 D: [. E3 M* M1 v, d8 U! s. a$ e- q+ S$ A5 F
# y& j1 `. c7 M8 O9 O$ u+ M1 b! W![]()
) i0 N) S/ i" |! {. [ j1 h7 Z
1 ^' A& Q* E# C# h$ ?( e6 N按照模型的结果,此次疫情可能真的要持续到 三四月份。这个接触率 真的非常影响表现,模型给的是个常数,但是由于政府措施的原因,这应该是个变化的值。' [, x0 H/ y5 m0 Z4 {- w
还有治愈率 也是。没有完美的模型,但是随着考虑因素的增多,就会越来越接近实际情况,从而指导政府的疫情方针政策的制定。& A1 O7 b; l; v* x! K" E: G3 ]' Q; x
" j2 p& X7 z4 l* t* N
. p& H2 Q+ E, y# z% \$ ~ h$ m6 [" Z
3 A H( m. p) @7 P0 V2 i
|