From 764b7c703186f0bf5ad77a137f79870bd66138dc Mon Sep 17 00:00:00 2001
From: Michael <m.langguth@fz-juelich.de>
Date: Mon, 18 Jul 2022 13:40:40 +0200
Subject: [PATCH] Integrate Jupyter Notebooks for evaluating IFS forecasts and
 evaluation on shared subdomain.

---
 Jupyter_Notebooks/first_cond_quantile.png     | Bin 36035 -> 0 bytes
 Jupyter_Notebooks/get_era5_forecasts.sh       |  61 ++
 .../get_era5_metrics_netcdf.ipynb             | 394 ++++++++++
 Jupyter_Notebooks/get_metrics_joint_dom.ipynb | 338 ++++++++
 .../juwels_juwelsbooster_compare_old.ipynb    | 684 -----------------
 Jupyter_Notebooks/performance_check.ipynb     | 724 ------------------
 6 files changed, 793 insertions(+), 1408 deletions(-)
 delete mode 100644 Jupyter_Notebooks/first_cond_quantile.png
 create mode 100644 Jupyter_Notebooks/get_era5_forecasts.sh
 create mode 100644 Jupyter_Notebooks/get_era5_metrics_netcdf.ipynb
 create mode 100644 Jupyter_Notebooks/get_metrics_joint_dom.ipynb
 delete mode 100644 Jupyter_Notebooks/juwels_juwelsbooster_compare_old.ipynb
 delete mode 100644 Jupyter_Notebooks/performance_check.ipynb

diff --git a/Jupyter_Notebooks/first_cond_quantile.png b/Jupyter_Notebooks/first_cond_quantile.png
deleted file mode 100644
index 6ff3a7a8a081c4a874d2e2a8c8d3d0d2e47d1fb5..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 36035
zcmeAS@N?(olHy`uVBq!ia0y~yVCrCCVBEmL#=yX!)iLEc0|SF)iEBhjaDG}zd16s2
zgKuI<K~8>2PG*uqS!z*nW`3Trp0S>xjzUIBNkOrdzJ4xTfnI)5y8hj}e?BuXFmM)l
zL>4nJa0`PlBg3pY5)2GI2A(dCAr*7p+%2uSdiC+~kJlx8dZ*~UoFt*3DXVn1x8;kQ
zm${d>W^c)2A*CjbCax6?mkf99o;|Vq^Y6!fzmr=YgqP{(ynp_<P=5FK$<Jd1?^(|m
zJ{Hy8(b3UyLRs#eUIU1=Cr(7b)y2g{g@@HeP*6~i)0r{Q#l^+tP=JGoprGJHgHdVP
z2aEEm-P{6#Dn2tVEc2Xv?CwzkLBWaP3AeZ9hOgP$c_)^yJjkJj_0kg0!`IeE-;L!F
z6cnsv?J-op8_QOHSvidq_jOERyeM(`v_x{Rp|ITTv>wC1y@t<w48QjnzV0!+c_-2j
zWLSAe3FAeHV1^H@W%e6aTVG(!;D5rb$GBf2IcfK{79}MmrFWt$nHCv7(|w@5K(gTP
z#<y%QICwT+)7yCM9itTU#>QWH8mmBw>$c0P1`Z$AeOs@st4*qoQqbJ+>mpnBTiXZx
z3nskoQdd$^dQ>+tZKZ9pkGBHzg%6UuC%66E^W(_3?gO{a@0_RK=YDmG*VI>{Q-fSw
zT#o!za&<5{wuiZfO=ROWwtZdMQQ6BMWlU7bzqjXGXiTt+i_5?HTc@$}%N4x7rki(v
z-`Tgfx6gf_e6-8;<D;W@V~=oX2eG&;P?#Wa<MoR?4hNA1GYprBe#qETB=q1)@^e*2
zy&bD2C@Cp@`hTon-oKqscHYkO63zSf+uz)jd1&GXfyiG9b^Iyp_iEp46^#)1^-rKr
zA>!9X&SMh!3p6%dY<(&sDA;*L&aUP~&HYuO+D7T;e41D|J!YHfW?ouy@bF>5*dD_r
z9up769_{&{<m#~H+Pw|e-c|l#y~DV!wQk!1i3RP3%i0W&vCrUTVTj+o_JNX;(nObp
z1ck%x{OZnaJTW_qSQ-5N{lC4xe}1B}yGF<g0d>DQ3Mwir4fE@Mb#A{`b$YIA-vuRC
zhZ;}ihKmPWWY%_{Y%scZ>vo>*)Q%1hmhFX)-HM){^F2S$*0T1OiT5-eMwzuOtHahR
zB_Hdl`Fb_nrT5hf$?Kcb{ZCEPeSJ>Jy<(!7LR7YQMD}glZ#Sc|e@ACej?CV>cI#2+
zXen107ZsV9eKj+u=|%_bC`kPF=BD$ml9v%%vqbCa>gL$j&vWaQ3S1XsnRjQ0<H06Y
zPA;xR2?v{aWGpV+b?yJ4lnX9fzDMq<Fq~<Wn)K_-%ZjS1OS{YSK?XH4vA(#yT|e{k
zvebWnem*%hwY&KFxs6Fjx$J(uP~P|NSGJ9<?cLZv9QvDjlEefBCtmmX^yK8u!pCf>
zr=}#nxv_DH_w>G#lhutA4lt~X-R(BVqHu<FxnAk3D~0on)6dD6PqQcr<X+U#(b2Md
zbNcyDPp8LQ*^BGN%+QVA_TjR>{l?_ue4yBC=ab!0``b)6YRiL5OTDM)$Im<1%-$|}
zQ)k^mF;Gd#X|AZK=rhZtbDnLrkbpo#e?R}xE>UI$=Qf^@)nUD&+F=6PVLJCJpUaBr
z$N7AFbCZ*gZ<*(0HJykJ4a)9)2G!qkzK5wy3Iqkk#Dc;P4;-VmWE}kU^)=&)u(h*_
zD{t9We+$@KRoW+O?bah<C}B~cAYcE-FmRE}!Ta~;KRY{nbLwfaq$3@U>*My`iR|_8
z?4RN4;__rF7Z+F3j}H%@oS8ZK>+9>2RXl~J=|mp7wA9;kvKnu<n66U&zdv&<3Y%;y
zKW!*~A7@qi$|WE`;P0=m%H{9w<lNlUy8V9L?5C%ve?DjZe#dUFiG56<u-X&k+{Uvo
z{ro(eiVqEHzOy#u-?z)UvcfSSKtR^IY)RhTT`a7uACHR1Z^*o?1}drcR)0S++gzWS
zoliwWqvP7z=*{`}?YyRHJ$?7e#jEOwj*^nn`YXrf>(89G|L^nv-`}~yQStj~W^PJ7
zy$KWnX=hH%GR;1uGgaKSs-#Oy_f#`G{|vj@U7P1G+R+{bs<EEf-`riU&ns>A<X|&9
z!;x<B{$6SGplvykYqp-5Y20p-d1*uPaXzcEHzyW4w|h)fVhvv(_w-1o@VVDL5{6B&
zyUR3X_OV@Q(oj-T`ak)>gM?!}lFsw(YAZfGV2s?9ve19NT|@HBJ;}%W0#}FWmc6;*
z*u=sav9oBY@t@c|6%+aGel#>RF#P-Rm_KNlkLQ|*jdvntD|;X=i?=R&BcbX&ZAtd^
zb)fKic6RpVeYMpLa&|Qy@9*tBIYm?0y8PXe+TY(|b`%_x<U2pd(s^Uj(Hoo7`S0Dk
zS5cwSw<izcGX1krr?+HYesO1~arwJDik_2HeCFHD^_r^1_~G~a{huGU%NPCoQ)!fb
z?#!pBr%%o>T>SYD$i=HdH2vmSIG&qh8M(L0v{P8UEWGrIrN~WC0$KX^(`o%5KYtcJ
zKPQ`Yecjo4w$&>_RthmPGG199KVL}ItKjRa&}04b=l}iveYoW?Gdo|vmW)8ZITi=2
z-|szsYiqVBUwm+uqllp3#Cj1Sp+_}5F}q4KrOa|XTDe45gs+!7CUI?TwENjvraQ~t
zN~wBHNw~Qw^+>0%`We%8aeKWsCLP^T^V8^PmuT|QF3}@>vbSZgPMp2~oTVz)&9DDA
zGw0@}jrsTO4jBGOxwogX=EuW!P#7NTl@8vN;`#3G?&D3Y+!4FW-UdGuP;hKwDS2_B
z(J1xQhN7olt%tAA0jE}*r+0Q1Us)SH{nOLa#SacJ9_x`5PW#`+EA27UNVWL+xuq#5
zC&lckn7FI-b(`h0FE20u`S<(%x%0KZzC1iGU$5fUBe8Bp(;s%O4p0qM^8H;b8?Thh
zGM||dTQUR<la3@D=@9gpV<FgZ;DEy{vs|x<O0GMKpYz?X`OKSrZ4KvTB?%#+LsK+^
zPfXL5-kN>=*{P}8=V}8NuPVPi`+(~IsXd0v|FvJ%3Ah-w`+4YecNZ6zdEcJTuMgT^
zS9@-bC9}iUtg8~nX*?@~mzTX;AGdecX8VVimU?%}+t<y=ma!~qnWh`PDetZogWZn@
z%uY^DF;V<K-^YkP4rZ`toF4zFf`5UcfbJbH6(uF5#3f!+yR^gCP0$Y4bL*9I?G#dF
zIKHQiSK2J)<D;W4{c>}Eetv#=fn&45^R|{2gS<NyRo~y8-CO<LV~&NPu$s?;u(eSV
z$#(*zf9l8FJZF6&YWL4nK9gfEtWvGTl`bwWN?R{4_ctzl<YM>xjj@f5jmKOoQ)%-&
zmGpCS&IO)c9kzCn-(0IZyGpx_Qcr#OdOd!!f@9P2bywF!8b3QTliA^L8?U5s+8N{i
z$>z<ge<{>4&8fTDymqVO!sl~%w+nT4bhrdLIy&~q+0I%Mx!I`ZN5Qjmb6?+?t{tvt
zV`H<U{=eN+t<Xg=JBwOcS~gUCObS~Y_4Uq$>uVy7C#m_K+LU^FhI#(HLl33Tsp@uI
zyQR3!0u<E$ZazCZ`{U=&$<NQtWw^2;usLX{SF2^($45s^GB364E`J}i)Jrt&{5;=1
z6(0}D6hAz~8n!0Fv0F@+K_hI9#PL2^<*F|)^j5aF=uhuWGCP)Her(B)_P?6FhBsqF
z<pc#Mo_O-??CdSs*ZY`Qxi%C(_X}F;b(G)!&w)v*-k`+CaD9FJ@`8tluB;4h&$zf~
zW6jT^X}ZzhLM;A#yPf~><Hv=mr>Fh-bXx!1TdsD&c5kLdhRdWj@OpgVZ&zj5CY7wU
zW04Q2WpMJ%&CN3{3YFyK<VxP(n_K()o8@(XHVOMW8_!89iI0!<n&jP?5xm?laA(m|
zgX=r${#x-$nJg%Kdn;yd)znK%y(g=Bi-m`~#vBN34w=OiADvxp^PVC5tzYt)a0hQ0
z<$0ij!X6aD_wL<e*phj<Ep~U=#g)P8o6`UPXD?ItpSQ%RmFvyz?fp+qPTrhxQHe`j
z@6VO3Ve8|3H>aJosQ#t{$|X-uOx%)pH%fVmvPQUVQXT(~hpK(ij3OM*H+6J$xMc9l
z+ohbCpt!_)dSAD=KGTDjFHfGCX*~Dgg{af&^J|=TmAtelc)$?5tK{L0jmhVE+Bc`4
zUzT%o(;VCCYd<@7`OY@uY8RZbI!fR%vv~ZY9o`F%cXf1}`2XPh{rcsludltizhA!L
z{r>-Q_V)V?j=#CTe}2)^Q-!atXd0!RIZ=MUw!OdqeDV6orCy>z%l&%i&zHZutMqb~
z#>9rzQ3C6kJ>wtkSaP8EgKk$xhsTlPudhO9nP$6n3aQ@MUvDpIoc82;d_Au)-`cHP
za&J$|xw)zE+nY!>ez`OM{{EiN)$Zu%=rhBhk)2<TLBPJQhEK-AVSU_Q5k6(k@W0{r
zc&@PRt36m)>eMePC^&KYm&g6~mzH=6uZ!8~v?b%>i@UqcZL7W%e6we{u_={%s#fTu
zOG~{$wfWI*@yUkC$Cj@v{q)51)%Eq~kM&AhR)5oRZs%j=DAw)#5p%WahibrWiOU}=
z*(H*#7)={H^|U5;ba=E(P;g`d6}~4Yseb(aeR=%;x^oWVGBQ5RY`hik_kQ0|_?RvE
zSWn{bZ*R}@w0Dc^tEHctlXGXs#3v^w2QTxH3=emW6J9q<qk5@f8jry#iOV9#8>UWP
zxI376Dx-Wt&(?40;Zr<aT%P!fN=TeIHC20M&{8f2RxXi*!)?4G8UYGt4onPP9TvDf
zFE;Pq9?yeKtUsU4&i9yW^)>kV?&9ZsbFE5~Zf(hISbY9rkEF5341<N)S}N;hr~6LH
zUHg`&hQ)=kiaFRRes3Ym)&4bGV-G#PcWlPCV>9j^n-RTm{r(<9QTf~XXdRhDi$M*H
z|3{yloqck)xqj&Cu+*=wuAY0#$}LvXcDVZcyTENZk*B6=yC)<lY)(6ybhwT8JWu;{
zy;!CEdwYCloAK)F>#O<AIr05|{rUollRLL8U%9o+&fvbpWF8O6T|c*M{Z?af{};~%
zW{VzW5p%YE=Et6Fy!MW57jtZb+5yK0!4Jff&sbl(b^BqAnV{fA@m+<F*=m1%NxZbg
zGa}n_wwdn5MXuGacC6p`t4mBb%Hn#^JiA&e&q*qk?@EPLy<C2MdHM0fhlGPotclM&
zrkpq(k$pFoZM(s-80IR*;Kt$uE$*-FrIQyuo>8=X_13ae-Rq{B=f~|XeSPhN&N@(`
zc`ZszFUDiJ-`pJq519fNyDcq#e(uZb>-`djNf!OPtG;T9YK0_xes&hrXo}pN7PvL*
zYI<Dp;Wl27z?#U-Onst3d-m)(6r*osd@N`4wP&T}mUm80%{JVh+p{vSr}CeR_c~2?
zkz^lR1+fi+9^J`Rvgy`)w|<lRz#ecyw^c+?kkb@YDg621tQWJxVWCs&jeWJ&huiu2
zg`XYkll9(|a`MKWN@MxjFM`MW<?GWd_7py5TN|}?k;g=(Eg2V^CQJ}ucyzRTd4Wda
zjx610uMXrbVBBy^;&Z3=yWcL7o1~MO8rTn{EZDX6+Wi0X=YKrexkvvKf3dk#a!s#c
zbgyBwe*8Wey;Lzl!OSZw1aEFiO}@1y^Uu%c^AqJ5=iAlJ%DK7e;>KimAr+4Ux3*@_
zG*0Ks-}^OeMs`H@&u_Q$Pfk+h4qoPS@bcx!K})>^MMR#wdUZnjP^fN4Jj2|zTemiR
za<EVCSsm_U$+4$9`R0Dl19Sdgnw7bBZr0kf*=x_v)(Bh_9^xV>*!iaH-5t-jx3=yq
ze=o<7zxS)y?(+A`T)V|8D*pVpzYS_|=ib@^DnqZWjV^w2LeOi9#>XpP{pQ(tUR@Qs
zGIsa2&7wue`($~fOkT{am2f>!+8pwTN!;mv{1HK)WajHJCG~5z@;53kl;19y{E2aH
zgW|&5lNgrES*vpXk53a6oLKPn!$W6K#oWdt=@bwkU|IZZN&fwP42ew-4>q%FhOd(W
z^&mr6h17gLYc8Vo<&9k6_jh-d>;L_U*;UeMQTWIp=?F*Ewj9Z4RZ8a{t+H1PZuod?
z#<l}Y33Io8d%}H=GhePjyg<fXK<95pyWufujjqN0i#j?ycHG*UE&lWK^YjA^j4Z6I
z7x&dxTa~^Nc_xvq`}X#B_3UeF=GatDS{J*!=);49&)b|EUR+#!d2e<3t1BxHH!`z-
z`20E8V#@SKt2#GTOD2~wwl=;m{K8lwnS93Jf%^lKzG<g_IdCpmwDnq>-=n*?C5jm=
zSiZ0_HLQ;Xja_ucFflX#e6#tygiVEkqod;z-`Ue<8mHTRT~YD*+1ZelL9N~5`jZTk
z-9Y`wPtR(rCcHg6+x+F_<@}aKPYztaF5Yl%u66rNo9HL0J96Y)vfnbvtZjccL1c#f
zug_|IjK)vbZe8v4y`N#x<A`VaavL}`7F!Cqx~SOv{qeZ}%lrHC4cl^W8|B<ENIKf}
z^p3oUh|A?=zCT~BUT<*h!^`FKFD>_<pZ-lYW@nM=+1cjL|NQ){;xl7{Td$O$ZB<FD
z^UwJ%w<-nVRnInSC@KBt&ejF>tfIDNP0@)oI<qgn?q{o2>8par$9QXMYJR+0z5c{R
z<>SHEcT|7ZySuwQ{n3%mhUA-jHG`Mge2%EJoW*{z^zxmWlpfCy_H%^w_ncBuQhJmH
zs<~@^etL6zJ3m7*PxA3TUSYoX_x5@p?Gn|D-loII$jBpWHAU9C%*Oab?)`mpZ7M$*
z6h3mXv9*=7tFd@}eSNsal>cW!`)8yxvNo*NFWz9N=JmqzXT$4<5qh8`m%cXj+#JiA
zKOc|Z*;gx_%wzxe%jMwXx)B>1($3B*e1FgO)6>((@9Zo-ImhyI@%o#KT)9D&<Fz%B
zGwti`b{0M5dcVp;<>9J^j0Uk|Gd}58?rDqY?C@wQczH?n&!0a({{4Q>xFT+^Rq(Qw
z*rQ)xU0ofrE@tNb|No>x#kJ22hu7EE{x3YT(XcIYbDClHHJvs-S+6fIE*{=2C3JGf
z68=SoYESBIOxJHM`>n0(V-X<lA}ClnO}_rm#I&=sET1dRF-T<Ml{VusE=akvqp;-d
zt*HkNIDlH&%lzm2y}Gh;{;q3>+xaC;vqXM>f1iGCj^(;FZc7&1b*!8H%uTmRNl9pB
z%)XkLph)`uF4k*`#=$w3#U4|&rWXG{Iaz&Wz(S_q-`}g3y}5B_j^$)FUMZX6D<5~2
zzRtM3jQ98V_v{OjkM~v0(Rt`~&=)kkqT)5BV`K91Pd}f}|9m@tzvbbDTc^#lt)668
zTlMYjZTGcNTP<pSd<fR<W)RnpTN1d~ZHi9hq`$wvPc}?;3tJzzwm{?Ixzx`JT^$`R
zDUObgpm-J047#u-GngT2ONQXH8M4-80V{)4&&{=V-;{E4hFz_ds8&eDv#-ni=6Zd9
zcXwyyXSI9x?tOWAxjpahu7^*bioPoq1dmqy?B|oS@tCaU`{Vcf{hhMbW>;5*D#z{l
zKYyjJfx(2dv$H;44UcE+b3f9|#>-`_`EB#M%FoYyPfgc9-@+;EF<mcq$93l?f~+or
zf)oD-78DpPcJE)7e}5mSm-po4WaIR6a||AScs{>=S=`>LJ9{c8=iJ<6n0`*?)02~*
zuWap;w?DVD__;>R4g-eyHJ><LyTz7fU0oH$>l))%3mO;r$Ii|tv%q7bQpxLUz3lvQ
z7nXPme|vZLG`oBagM)(uL+Yt13!PfI?(8n_KX3nk&RpwqJ5fGnCMM9BQ{<+Ug^tZ^
zcXpTaH|!{U9JDsdwAHzgdn+gu|9D@Enq`)I>VExy-%n3Y&NR!7nz65CbK2QOzO&8l
z?5_uPoei?D>44gD&!iL;6+we)U*6oDT>ShTW55y*!FTueuD0Yo`u2{TK(C=EL-yLe
zPu_uA!heLbb&pB(82Ze!nfdYY@y|b>&lfh&i#cHUY6mE*-q_e|QTWK9_E*WP>+AoA
zXg~P%_4UguD~0=?T{t`2TtE4E-_n4EPV3f9I$^vsOZS=9u^HRv-3YrcQ7mM^KF9o+
zjQO!EWv-yk+P~iF@9!=y_m{W(^TGM~wmFu?Mzz06(k*0cDhxD(mLweSlfAM!ynnHK
zzg=<M;ROp6K;v!O^6q+pQio}_*le@hAd4y2yH<w<ak6nmWt+Fxt>e;R-Nw}I%)gp_
z5BHR<*ZxVpYprVCGO4S><H*<3`ui{JD$VYbv*kLlE_U~ciOTK8|L^UsUKz4d2vqY#
zZb~^b&vv#^>Zz8U$Ii|+XRLUw>mGgb(o*l6JB!ut?k-nPJ2OLXRp%a^wM!oDa@6ww
zw&5-38fLDDZ1<>acc!0>y$<E#Q$g*{oqBP5Jet{fHG-G%xcAE)J$}5MSK7?taH59?
z$JyED>eb)g%&{u%(u>_y@Z`iqgNFth8XcaK)g~%Bv;F%1{{5Y}y;Y@bJQ52EG}h~u
ze|0>=dS&}HtLqutuCYlct1-pzS_$fNF@SO{$cV?sco(_%`|Yp$3mTT0H*X%pnz+5Q
zc9p&^dVGwx=-HW*dn!Mlm}gr(BYREMR*<EjVK#<8fB$mw@u_)D(a>Ape`5dBb(wih
zjos&O)G=OIAFQPGD6IP1n}^4GrKjjdPqVH5c44tQzm2UeCkMxZl9!i2g6#Zq2AP*s
zw&mZKQ<HgjfB*b0QSG30F_z!n-Sxh;B@@(i`T2Buya?aZ-iN2ej{G||Lwn(Sd8W)p
zUVoX%LOY%vGV1K;`0(MOGiYRJna@lH36l(gR&McSZoN|H9Mz1|&n@wtZ3fDOTA`~9
zN?(OcQt=deX64>5r|RA(!@|lcXkC_L_w$Lc-M=5ny8Y_;GU2R8f*qzEx4X~qiShG%
zi*-yJuDhlR2?{1&Ugo<c=jJ47^E{B(laBZKo|$2|GIFz;K-sHVEu6xea&8)dMwxB?
zU%X<@@bdEV<ylu(fvUnrX7))Ig-P45cs|)*bW%AjJ69?@_m+B`?7YGkMhp72L6z9V
zXa@%dP|cWdu<6I|-@>|4CVunnWS`AA*v$U<+wJ_#$;bJkwq_me6jndf;#^-}4=RWs
z8%OFyZRt2USzTM^l=R!JQCa7sb~Ah^FSm4YQAzs!uwDMdEK}{|<9$aDA8vkkclYM%
z?|GZj&T?5yyXZY#PZm_rtPEP3bb6Yu&n%OZmal%Cn``~$#l_}3JBvRbm#+s^?pEvH
zKKvN<_p;U}`^wyZBGSoTQpsr#B~~aYDGBLWmAr76sugNc`^%*A)04!{&(8A5+s%<M
zOcD?ha++<H3$lH=-`qv<`|D(EDkkiy{9o_2=jrL`lTEY3+<GJ&3knQ!Z*6(_dj0;g
z<X)FJ+wFQ=(|b;G)UcQwGIV&#_+hT~X%!_U!Q1TeH3xbmjX_ZhYHMYM9Jg<MeSQ7%
zs;{qNb{4hX*;%}~;GvUI%83Uy?;joQ2K8Q5y{9ou&<@vI<}=f2U(L@uLHrXxJo(fh
zvFk~k?E=FOa($j#bPZ%A^49Ks`O2uX!{f--{QGwQ{(ScT^XCu4ikO{7$NS~g0~fh4
zfRawt*H<6^e!u_t?c1|cG=np4ZhC4w{lxF5)8jitwZ)p*`IqJ1-gd4)Q|RK3C;r<E
zk1=cXD~p7&?P=J2fFr@O?`2+Hn1zVo#PFvN54ZD3oAn%QW*3%`@!41N^Tb?h^9ExX
zy|_Iymif*udVWs!)HL1Gb1aJw`NS4KI>HGWgq@-hSn>Pq_Q(whj5jx>Du=EL$y+(O
zWA%<z{EsYU95>i}&<zmtNL~Au^-Xc0q>GEnBv2=$^3#)r@%!so*w`-ZsVu&<%=h)3
z`oF(QyF@gd=3140`0^#?=BCs?e?Ff-S0EuGa^%EBWl#s<@$vrhdExtNDqEd9MPft+
zgdbN-*(3QwE+T#HR=r)@J33s1%HQ2tSp58)h)%==+v;x<6rI_wt&2T<Wo2-uxV{{N
zu$qrT=A|V$H#Ri7^-6)pC02#3e6;7-xw+Pr@ArOxac{5n_xJaoA82HLx2mt>_6{ut
zF~((#I~!dOuqL0GeryJl-md)}9WG3<yUS9)ytv44Ze_OD6b;4$FE1|#jUv_l{-)wF
zp@CQ0%%J>TOw#c_-UEMse}8#-Ie+EnXQ{uxy#);nPSp-Ks{E8v9_oH1H^wyZn_Ko;
z`3WK!4U1Jbs`l+`w=U!f>U`d{2{Zz7b$fn%m#Fr!Wxlf|>}o77E_Od2<$Zr&Eoe^R
z_qVr;y{GHR*w@W*YUQ##Z(aP1XJ^sVN1M;vDXXZoe0zI)bNTzYQ&Y8{AG_7DqrdR_
z<hW#?AeqazYgkg4of=9H_+-D8HeDEUZ%^gh$D3btcXVX0iP<?x(l~8H!9%A-E}fsQ
z`~%H}EOcV^n{Vg4%xC70ce~%8n5KI>_&6&&d+-tu!FBQb&-F+eYsBo>pxvdvUNiZO
zS$6I{ae2wYow<v0vfr|1zxBw@EmP3{pgKW##`ASXogF7;Km7IeHE7I_OH^w^%1NPT
z=jY3()q8kwtc~8T=H4d*n#D>y+_o|Q{yu|;AFjvOKRq+kn8Bq}s5O88-)VEL%e7>>
zKFnIPBx&v4ytRKNJlL+(T)l37?2FN{9K&OGjE=>a9s85e^Re=gL~_r|{2t5no}KAE
zk?B2^zpncT3Kp)GulvymZQ1PEvq!=(iG^3nq~P8E-|zQ(&N9)QtnRNCzAi?_s-#2C
zw#p(}BLDtA-_>DjHDY&}tc~9O?Be7t+wa#&=jZ2xO3TvEQ7kSD$v(ab+#6J6^x~P^
zxl<J%)GBcNxGEw1e`7LeVB(vD-2<Ty-G*vq7E|0^T>dRx9lrk3ia_O6AuA94{QO)q
zWQD-)vbT$(x97R^N=;p`K;hNZ)$RwISa+7b7K^X@sT#dKkJotb*;%I9C+68&L%YaL
ztlWz{O<m?a+tiTJ^D?F9W_k~&!Lc_+$3pn-#+{Ma%zgaDGZu%{;kEhMxslm#b+X^e
zWv{jG+t=UOaA;wwfrER(jICvzTg&+SJohFue~mA#ba8odKYB-j;^*h*)vLa|0FD0I
z|NGHgey@_fA#`=vM1w>p(CEg-q@xy9Uo_T6Z!cTdCL|!>u)FN7M(8RLb^m!Ppoy&8
z+j{Tqt$zIQ<E<@IJNB5xY@Os4F0*=>3`-b8W`pXn8F3cVZtU(;Uf{d&nq7(G#H7a@
z$FDovFF$H{sOsxt<~3Wt_ZZec$S9rjs0ox<gqxb1=k~Y#{qx77<b}Z7TU(3QO|1F;
zE_PM;`g5<YuI?06X8Zi?>|)1ew!~>Cch~>7+gbel*@uURE2^qKfjWMW+Wc;i`b6`_
z)pfa9U5i@{R&U)lZ|gRO3;gaGcNkN)UF$0kv|y3wPOh4}-^pH`_iyFL&c}Lo+w^&o
zd)6DKtu{=1{q*$o!%HV9DNUTZbz1(upKU%fjanr=jMC0Xq+86fueakAQc3vw>ME#H
zB&_atVMF5K<<|nfefzd7?d+^Qzu)Z!&F<~1{jDX_wWnb<Q&LsJH{sRGeGYHjbxI-o
zZK(KE=HxRPGQ#E8w_IcUzyA8hYkpg=J==QiS?!i(%R4&$ls`W|A5@Wmriqe|_ZjBi
z+G6l~eaud$e}8_023ic0jy!0WuS@v(>8Z`X@{i^BYmc9rsy%o9@9*!=FY}#!Vy5x(
z)2|disTGGh^svQLC*59re0O?m2wRWg;zs_)?`yXnm%Cl6_$7Ukx}WE#8+L+%obK16
zo}HWPeQix-<hC5i!be9Ee|>rR<^BEpm1kB2F7}wFBN@FdXQAh0HPC#f*HkUb@AIw8
z`=m^>0yd}lMs3MB2x?V+`1DCBYD)&Ffh>JmwN}8nQX*N7e@TCuiK&0i@hIs}tMc=D
zB)PA!dPQZ=kBRtf(Wek0b=)JX$MBv*;DXz$^}0JcT1wyDvHbJrPsGL~RtC`E*{La-
zOFSkrH3+Nw1#HWS<dd~>`Sj#u<c<PG*DjI5dGbO+hrYbL{PNmb>Fs%UmBQ9Ue0g{G
z_RgMp9e=FX$?V$7$WimARKMi+GWBiyKh<>{o6%|U%kdifI_cy|ZTpfKTkL+xF@G^Q
zc7<cEa-o?3!=Av^yE;1dbe@}UfBw`|?M`WPz2awQ5|4I?f*g^p8@szqwf5H+8M~Sp
z>tc5oeR*-w;9<f2eYGO`aWeMy_IY=Axi0mZdSiROeD3XSS2<EA{-3xyN`QUG3%m1|
z)xJE>_s@}M_`+Xn&(y)^b7Z657qtaFTfc47=F(6Sx*4;(toO%9*~=H7ot)ghv-o+?
zA{Wj{>i&EOw&mUi)&9@V&sQ&gb_UeCdUJDg`%X6x4-V6;D-RwVY*z7`Go$eFvB2ei
zbC<KN>Nv6g@wTlql!ewF)lvHNY0cI%vrN1F=2{t+zl&KFwpJ>wJ|IBAca{mLk)xJ%
zWkt=mo9QL5u4tZ#I<2Uvc<$Ok(A?ls@9Ci7l}AUrpI_SLab(HX8S#s!hPb$>JhHC+
zW%Bg&^yQVGpMfTvKvU&s{(-c#a0-9A8Xh0Gz=07IP1o1O&VBgd)KqPgygM`e=2}^v
z2aSXUFY^hs5UFg95fbP%yf2w-WV3PYW<#}$!nZd`CztI8O}ad?x)zmoW=3OwKR;;I
zMBJW=GxP1|YX-}_7Pzywdb&~SsepYol}yacGcAkNq|I^^d}o=Q`<#Aumg}=KGiO?t
z>s?;%|NPQY@4Ph=J&rtEC3YmMq4;icvX4lD%7jmykCPZ~#)PN|3KlkYi|YsNtEmK~
z-?h=(S43^q`u*)~@wy75^m8(xF-!gZf1E&V$-+l0zO&6rzbW6@o-eQJHDy8M<}}ds
zPS8@Xjm6LXgw*}sJe$?&60>g3vuB>K9Ceh0IFED)HZ!yHfhHwDGraBcbsdIn-qZC0
z7do+S%f0Oen&RG+!YQg1QZP?kNa&FI{F*~2CMt9C@Te3%I?^L$+V$(}>uiB84~t;%
z*vV5qc{?8m2L^_X$;Z=9PEvhyclUM4cWr#Kr*7x(Kf5jWcE-g;tm=MqIE48aZES2n
z1$JX&BWUvZ!GXr**CNFxepuL`p`^6l2ei_qjaRw)+nX;hFCX7&>p#y%#dp>e=XSn{
zcC}Si-`|1y+&_Q6-#^nVS88L@QKkoPZf<^ad;9sydoM07zPTZhd9u3yH3bnt@uF0R
znrk&yvy$CiRGMyVOlE(-_q*KQs;`d@HnW3L#sq=mhawae6+v@!XJ#4~e|qBi>)YGY
z6P4XTQy~n;ub3qt>rpIzcE%**Lc@Xu3JjA}z1<c%wcZI+pLpWb)LMahgJU*3y-xWb
zn{nW{UG_pB!HMQ){{H?hX^_C6?B1thVKL*%%3$NvQzECP>2e=9)+@a-Y^~IE{dmx%
z3MiZS%rvq*|Nr&+{TX+6neHxo%LGa(clOmr>$WN7Jz3RYaoqL0pr9al(twpq1eB8`
zl3!d{$lT1%uNJl@!lvfOgkN7@Z%#QWv}ezrAD>R^XI@=3bu<6Nt=ZRK+}x~wd6_S>
z%)x>`KR$-63OPA9R7fyJL}2Y!-`GNVLBYbcI|?69GEVpFF$DEzn^?J-Hq`tqk}}Bv
zjg2hznws?Q&rcQKSyw9K3JMHBLFe8l0~!m@ySocCc93+W<Kenh9Ve3SSf1_e=-AT;
z>IvMddaYaZ<OJh^DVo6_zI{7(`}XYH+w+5$dWnKo0?e@}{PFE}{>sSB&w{Ua2&r<-
zwJuM)xX88U=hNvaCnp`fdR1Uz{er+VN=l!Cn3$L{?(efb+9kTU@bNJgHmh9|j`vE7
z=jZ2xhTs;tbVh8?lP!IH?dg@3!RHEoe0b;#nssa86rOYa^XJdWXJ?smwJWVx1P$1n
z;9eWIS1LX}9yFqUWkn!pQtFzO+M*p5AC;b-np(UrZ&SiSCa-BaFKx>I{`&gk*RM_W
z|Lc;D^?3gM^|e#p-cC*~Yq3CO?92atf`XOnvaheZxFs|A)HL1GCnu|)oT@Dzy)7s4
zKm(&ow^;9ayWc$`nn4?~uj}2~l6kmOSbfgJ5660?fBgIzxFsX-+xz?e$9g0q_tjW_
ze0;qAV65wryWsU5=S5^>d=56TT9&*J0FAZ1zdv6uc9(!@RtP9#{rvRQvg(UQ=A|VM
zZ|Cn<^`B>Ru6Y0Nch<MIW*`6g`T55$UzUWgkNfiKDtCT<zWFr|m$+%5^(Rke%JHgb
zhOLnRwdUOW<<8~KG){kZq*J)&*URNHRwWuf7CfAsiAOpFK}}qzRxVI!0U7@I#Aew4
zYr>8{$Br#w31ag9+ncyH_VF*FzwbXiJDa^d@9wL2NgW-3)IsI3CFkEif9Bjiuu<>R
zwYAYJV|E&e>%|;6e!LyjIxfFgdAu^l!GWRh(GkXk^Yd&$>nlKW!L__kdy{)^rma2u
z`d!hE$*1KFrIRl)#xwqu&*l1?>3lz0p=<SNRVAUBZ}09Fx3{-9%emnI8aoJEE9E&!
z<>2AN%?A!RNSS0DXkz6C_07J#xCk0-KKEdI{r|c@fBsawUb{VFUybE4iJF?44<A1k
z7O!=AQvbBiuH$lJh=cnBh7V6ZRVyhyQu_Y>e)@?CilAQjfddYp^#VHzAA?psFldLZ
zSy1=)*PVT}vlqE`f4UkTKhY@FivhIoWP+kIsGZ)}*r?(;sipY&xsTs&=kMO^rSyqw
zhqA&m=2;Qh(|0_)r=%p5_4d|QP%-!8L*jvt5tTPKBp&INo*unDFK}yCC@53Bxv>#6
z3A!SB`?}(pdq89R*VaZCe|Zu3e5Z3e-_>6yl>}R?nI1`A$<k1I6m~7@*O!-vA0BQ$
zIm=W#c$v>akBLeQpz*>!S?f;^4l=*Gw)XUslao88&DVY2v&?rksH$MtlzRHum6gGo
zAuA^AUZte;@PI7iN8<(UhH1T9zx7GK(^nGGjLhcb;7}-gb3-C|hEXcl>1n!)tG~Yk
zrRdAc{eu@ev4Ym)U0UJ^>QW!=7UwVKP3G~OtakMF?b&sIe_h;JoW97l``I$7PLGPh
z(;8{XX9Nz2|B&AC??_(u+T1svoc^*)9o11<znhtz@4~83?WE&<Z)H3_b!?rsul6^n
z9$&My<kgkV^LD>^^!4=_zP-JD{AjoMT;YWKd#k5&i|b9$i?!N*#Z_fbrpV@MH$!vA
zD#n8jdGqS-yqQ;7?&6}f;P?0UpKqqmH_W+Vz{Je#IYmP-{ro&t*Deu;H#asmpPH&&
z{OwI7Xm!*iRd3J`i$Ixx*CLlr&?J80qa%uLJrZ2)N`iB&)s{;!=&%Y!X5Zg-ZCUN3
zrTa@=T;du{v#(81cIN}F{Ygkr04)SO(8#>RV`5V~zx<^gg~>(F&z*gGdb*@-l}YvY
zccpEI<Lm!UeRFfOamon+CT8Z9K})-4XDchMd(vmu!P%g{cB}cFf_%Y=9Ot9FPfydG
zX_(A*Ah<aoY;Bb5-m0%V3Lmo_?G}GNJAa>I<faq`&`iR)xz@(@|7sX&YHDT}rFO9`
z>~Jx9m*E)0pHg_Z*40IcHJOJ~Naeuk)7=M~*+Ju8piv742L@0(C}w973oGl!ijPUx
z)<!?)X}=bw6|&;MpP!#Q<!r4ExA7+b{`QuuU1{Qk)9foHlJ7B!F)BCAudJHDb?uhG
zbg@_VmlQ+=3%4I`=P&;Er?N{_o6Ul4(j43BX+4t0Oa}G;YHDh0K@*!>v#ur`>ybQ{
z`cZCs)>SRL|9^^?`OI8Y*Cv#iIiahX>Cxg3-}gvIXRo!EtNnjoM8Ne(EE6-cq-Bu`
zXl0;d6U(_qm41+4y{2kyto)oNq~>$t(a~<rz(p(!ptV1;*3-1Z*BO+&2zYLJ?Uupf
zIj&05tS;ZbILdUmX?1t}Nsr#1x3u!}vp4tlN;ep#o)VCe;jwVKw<2)yi>s@}9UUFF
zWL@pLxY+&i+qb-+QD{(uBzk+^Q3>bGX=mrG?d57$di1FwW9{4bud2H`TvW>6-&<P$
z|6k3=qv9<sEuaJlnhseRw3NZ3?2W|J)6<_{Sm?aOZ|<z6-qR;(hwCxO*;E{OaIjg@
zEJp$~-{>=QlILVK%fkyhICi8@=$dS(HqB6NsiE35?suVQBsSlXD843<?EE~rre?q4
zu`lMw<`^HlV|;9l@v#){_eGr@f1*QIg(N;XF_EF<-JO|tcb5mR3ej|OasrJ9NgAg;
zd2w-Z&8L&<GL}V0B>Bv9Z@Ij?vs2OrJk<#r%iCN1J!oT+Yk8QvOPq7w%h%~Wn%q2$
z_gHxndJS(k+FiR9f9U15jSaR3?p(M&88jw<x>zAZO>koU+U)D=Kx^Y9jngLB*Vi#@
z%fIjU^wd<#@^><Jc6K_kyQc6+8nsyFUs(|dn!NUzX=IpujOY0lb0sDJqT>ovHy!9d
zAoxJ~0n-GY72GKdS}n;QH6d*b3+8SuD|?a7Jcn5=BD=jMubVH1X;)PC@;{fqns~Un
z9J>7J>1oi~6#w~l=W-7oJO~<SIdH%sYFp09IhMsAzI=J|`Mmw|+TY*K)wO(of4}^j
z^`454O2X=XpgPc{U+%7MsbHmW1~|>dTP)kQ^2?7Bvtttc39JIwqomhO&a+ikSjODP
z^mFajXgTY5?hj6NUuz3<5SjR);Nv4#(3rNEZd8k5+uPgQKfl}k-s=1M$jxn0TeAuw
zgMo(@xpvPfmb$m6ax!Rmxb$_{zkk2;K`W6%xF?$TGcBtArSObJ&Cc?A;*00{g*Ihn
zTbC@f*SFjF_fhiiLk7owNF{HRO5PT?uf{TlTU}{l_tt4Ui=R(Y^%fJ;jdD3N!%)&V
zjpyd(bat8M5UucaJ}ZNkR{Z#&7+?EUwEo}E<;F64@%!e0R>76N3i<Q*@69clldV@P
zE9EPcvm9YRaC!4)t0R1O|KHjS>$Ce#(U`cqTUkjEwDM9Te4R|MwE44NUtdqr3~sZn
z{`TSHad}}?FA<RCpjOq!B-YSXArHU2ynJPSynMkHi)(A6r>_cKUG(mbC6|cCgBVv=
zmnZiN+#O=rd5n%NsjXRTs3v+rKH_zoQ7p&bnNK?3ddl5aR}y*$njioz1N-yiBWPiT
z{r^A4nU|In+PSTZ-mVuH7Y7>IOFcbJP(RLwK};vY0o1pLE~<QUW8<3m{qu5enn*Tx
z{HcB?arBPx@v1ZIy@vJ7&kJpi=`!45sM@j6=XfE@!Al3k7?OL;14LdtYx~sUq4Fu?
z0Ox@d6O}u~bfxCkev|Z^WKows*CbO&*1GJ;!^7>M&R(amx{z_&8OU<D>+50{`^+=~
zji8uhUfQusN=c}3N6iGT217N;KF!oFrjL!;2i_mZ$bS2?U{|`1%;F`CW=w}0o*ppG
zeyf@6!@t1%f(U5gK^LR`oM&#$AudnqKYn=V+{P<??9^24pP$d$cS@PQdH*K;{Jf<#
zKR^BW{d=-aWzoLB-=ew1bT}M5JUBpA#y4*sPEOF0(<MPmy`nf>pMZ*8ar-2*V=l(W
zdf0*@vUf*i-`{*Kjpy%8+dYR8SL`{^cOkqa!QsX4#)ZG#85TEo9te{Oem~`+Oox(?
zoLT-opLsTwFRrhbumAtoeE+{+tBdDvop!L9eX><)7N{;??l;$>?9B{g89A$x4k1;q
zfDH+bese4s8`|61r)r0XS%^#wKeV)e#@em?y@quMg2L~af4TR%z~|K8J%7dA<xl)u
zr#Z31#jX6^orjbC?Le#TL8YXkGaIOR{_)XKMvIys2C1i~J^k_V@e=>}^WN|K-6vyN
z#2_Fdas*T+Utcf({r!D)&q*qCtV+H5C%ZnGT6|n#s;onq`JHf=BWtg%iFE$<<|e30
zWw^VmH2M3xyP!dgY+YHak_U6k?>)S-GMGogpn;j4&*JdIcXxMdMr=^9t@`rd-{0S$
zIIjKuEpSbQVR@LRi;_k;PtZ%In&ci!&OaG<FLDOC9O31YvpMnc@$r*0jn$3Q&M5fL
zvuSu-SUgoL6x1uQEPC<))X+{o)^qN2+POKM^XJP$%k-7O%Y)X%SeA!6yC^Z1vm7~k
zAo_rj!Uc(9$qE~lsO;P<^C{jgPo{3VR`lmb;iaYC><#nh%U@jVzTB~yt)i+*NJ7Hn
z@v&Y|i?2gWSL*Sx-o?4Mw^dZM)b5z9A8%)4V*^?QaJY?Ex$Mo2cPsijT$J8%bnF*2
z6X@!2u>hr^*xhBIWub5G?w)>SW$@#N4;?3~`7-?Y`F#G$@bz-$`S+G&TwGN1_v>}g
zh)_fI_jel$9y&>x=k*x2y}7v=+_0<@ocQ6{q=t;1lZ-N(uHD;y&8+aKt*gr&MHQ8n
zlatjiZ%+5myT8x(&5eyWH>dNj47Qf*0S#=ty1IIE)z_?~V?8JT{QSH!e*eDWFCXRW
z|A5xSf@0e+>Bs`VxmFCInlxyg)RIliCm0iYEYo^UzFhRXt7FHRdwZ)jqqb<|-rn}~
z+uPeAYon%uVrgTNE5oz1v)w^M4tuLiL8Z@;PGOUb3k=CTAn$~(4inLjn{&9G|MBC;
z&bPK?#uvB?PW<q2mHV0R1!rtICa`@dx>)P#5|i}o%uG-v4{gS`a0;&oT+DV%LN9)w
zPb-(`ja{YMA0Ho2KRHP?WJSQi%6H%I*ZbezmJ6!S=FOY;<=x%c_x4tUW)VR>C?(@?
z)+4qDo*$bb?`*%_;FwK5$GolA_=*B|y12x3*8Kd$*w?55il@9gI~Z#I{e1rA)z$6=
z3lwIV=bxKlnA{<%J?-<J%FoX}UUZjd3|Qd6xXge4y04R6kGzf9bY-65G6n<T6D`S`
zUe(Wfbw4V5aZB~WI7Qv9>Owz3-3?Z5u?ve_xzqn2yu93hGN{whCvWcu>IGJOPyo%)
zUtHvRZfbyB`S*9RT;h5@o72u_Twc~&?3*T7D6hNq`69cHYq$2V-5S}LVR0xi@xW(G
zecNEciPvwf3SIr-<Hv*7uTRh4|M%KX+tgE2BC=oJ+^jBXl=9%i!^5B@#Eaegtqwmt
zIa&SZi^csrN?(gHfR^yy-j=&1|9;%V0GBxFb#YnxM?h;oJDw$k--~v6vVT|ETPaXy
z{@ff(h9~Fd&IXNaeE<FXH>l@uZjPn%vokY6TYT*7>>83wK3`cG3>pw+WMn+jFF)Tf
z`51$Z>HCEp9lLk_$yd#OE0g^;H2i+J%ai@!>77}o+QrY#9K3yd_QS*Nn=>z~6+JuS
z>EXel8?{9t{oI_G9R-aGo!d91pO;Iwu&MiFvDAC|veMVrSXfv<gTGZ@Up;*$)!AV)
z-&*aIm|*4NGjpw{AM2H74%m_rxXge4yBy1y{dKliSA{-)b#?WVlat$7xy3+pbO$bG
zS!7;PsrvHb;9To+j~NDvpsA0o+1JaWV_jV0+U8|<bnJ0h8@2VsRBdr#HJ^mLyGm0|
zP3b&vz#;3}8qbT1Tsb*75*{7t%(=JcrX(MuS>7Fw-DPh<+XG5pT}iyZua>J_>62Rk
z_o9vy!g}%h&KziDmNZJ?fObc6?(VvJGrZvEr>CINr-lZGE^+;He|~<Rt35X&d+y>{
z-6EP!%l+npR==2LUn_~Ob#eKp3mWaP0S&*UoSxRpDXey3xxf7LGJbykcXxIk{{4Qx
z|J7BY8?PDV-?O>4F7`D~d-eBsOA8(z%DJ`WWF@GjEW+pdr1$Z*hK!z%2FHF#BzH+C
zC+%7-qonj8!*osbcD=1xS08<PdU}dRVAHv|*4E$8&opjl;S}0X_BIMMceFA2c*czl
zipL~C4SSmk1JK;x`u+bNUG}#xP4;zh`DeYI#U<G%`T^4h?g-{R!n^)fC!aa~PGfS1
zOI&{xuQ;Ur16s|#|L-^H%*)H3etLTP$=TV{)qH0O*jAP7`~R<cnr^h)qa&S+pz*w)
zpPxUU>~E)NU?315A1|gG^#l~tf6VpxJC4nmb|B(G^#Z-b@X(*a7dA@>7S3E7y}d2d
z^vn0}%YA2?Ra8`fRy9si_df?3oxHLFv;Y;f`T#t8y|4E7B>i|h(7H{~ii)?}?}K{9
z`Fp=ko1Lwy^y&VN<OyEs54f{)`IFB~KFub>uxsZ+A0;8rr)OtRzqU4dvTn3l)b_mI
z_ICE;{qoCmZf*jN$ful~WLW>N=3f2(zXs1^cbD~o+95(hPVIcM5=JQ;hRLh8_jI`M
zyyNJ|Yz#ervz)!-^{z!79x0$j=b&W+?R>H)rt8ZyfYRXuiN-s7tIPNOc*MPC>z4fc
z^AZoY2`ans9N3swv?b$Whm@(-$w{io*VaUWR*xNO<=(y4PD$zELD^b?^$eNwHoupB
zu;z7_lG4PJn^I4McBg>amv3)vJskD=&i3TveD~^p=eqUDc!GTY`~7}N^Sn96GXFjv
zmj|sszqr`l`uxhUwX+T_>~QgT$I+qP;NNTbQtozIuOVlnpT#e=u8uuMpoUfA;Wp3~
zIM6`$nh3*v|9)ln7_zXlU*1ue{OQTb!%MxV|M+s*|K|35`JbPkvp@Lt_4SWmzk>Eu
z6!ytj9(r`No0IQa&?hCKjXRYUzOl+NR5!#ka`!NQV?KDm!F-CRi_!{F?J$dI-o@_y
z=Wc9Fj@(_Q`||Sg=iBesDJLFk0p)ZV%OcQN92<{>!<LMT8?J52xTv%#<>a9)nU_C&
z`LZN_e;uf$sS!Bujh(KN(8e8m_!n*c)@7)se?d@#TZUKnI7`Bot>31tKCPl8c)3^F
z9F)F6l~TdOL!c!~Jd#EQ|NqryU0ZYV)Ku+{U%sTAnPIpk`}#S_KcKmmW;R~XMA3r?
z!PHk*R)U5&=Ux>QER>wi=927Vl3?*+>((*>gA-G~i%&f9@M2MU;p1bekB)SLR^9g7
z|C^x^xM)MdK_*a@a(8z*Xdtin*%?LOStg0+`bD+HuCI?*_nTwUBVpJyO*h(V`b}ZM
zPM$N5=WdBDa!!87^mNVE`W;`6J=Dm*x2Np&wYBf`+B}w&|NT{JRrbcCPsZ}arKR38
zYC*A-bhPWw-|zR2^hi$r`1ttcC7#01cb&8@d!rDyr{dg(iZ?e5_w3#4InQS2>eY%$
zd1;7IJL@{tdyFaNhihF`n7~VCrs+x-KR=gxVuIqGeYLlD=6`u{5j1$e|Np<)udc2J
zH9lsU<#rjiH8e2nDtY;64*$oC`e$EWS{iI2GSTC->}Q2C#(jpz=CIUlS(kT6WFp7Y
zTU)bB-rSg2`S}@Rz={CHw6n8Z-`v<}S@?+M>8YuYK~qa!Q#wE^*Ec4)KHq8o=L2)@
z?QKuLyu4gdQ8B@?IIXFv>BE;VCE=i99B$Bv36BcHG{)~ehRb^mm&;YpEpeXd@`N{e
zZR*EIM?r;V<>zM)-@ZM&B5?7K$NlyvW*92p-Bqd#no_f=m=Lx$s_@H;z;p|n>Tf!x
z+1HkMP1TxXS33)|n5Ob`np?lz+5!!wrs^nx`oo4>dpl12KNEF&N8#fg1rM2AyF?P7
zotc?(X2wL_=xqT@y+lC^;&+w2oMB&Y2ilA<Ph3F2;oKa{omF48HYOcS`taZ&s3X53
z@b1U!3p-A{J}G<oj!EHH+yA`DKGHI;9o3n?G0CpoTEA<1h!T^4jLez0x3`1l1Lfr8
zeCAqBy<h)dHa<SSskwP&@N&NUb-#537r7)}Sl|e%;xjHTYTfC!CSv1<&!3a;@2l;R
zHt(CF8N6$ynUd0a{ptNlb#o<?Uom}dG&}I?!hGMxHP>zhpSSj3Jj3<S{Qdjw_wCyU
z8pNDm_v@tPFNuVgmzLIix#$k6a5p44f|_!_zPx1IQS;O2?(T9>;df<qIDY|)uWy;I
z()q=KXYw)}O^(%kS(LnHYjJGgwDcD|XSQAQ<NkZ+o<uNT2Je@m;F&H;TS2SbDn2B%
z@k+Y|1PGj*tp5DX&CQ@OH)->{fSpCD*Vf1TuZh?Q+R@7^ZFWS$*~5e5@-pAW;p^jK
z_SelVeSHnIU2~CJ@2Ua~rB6)nUX&RBw!AH$f2yR?foJX!YyJ;Eg?EQBx5mWE2{!Ud
zn}Hf!d@>dcpryl-RwWvsb^4%<Z{E}OK=UlOwq_e=UQ!WK@n8Ur9)SYx@-knBDSEN9
zI)&9&&0pAY!n^4B{b`x=H|jD5aIWAtDakFIBg7Qg(CweIpQGl(lY_@3;tz-`fZDfl
z786e_D}D}Islt}6JJUEl?bnx=B6=}1KpVAI1So=*^-fap{PFAc`pW-*zcYeXcF(W-
zr3spkvapx|sz}n#NMv1KC;M#TmX3};#?$?alh@k*?73c+{np`uv`l|xeD$?kE3e(!
zbM4liP9fEz@<JCS@G3J^FA>lPa-Xa<Xy<tCuP=(Ay$ARA&j%GakB|3TA69HIY<s`|
z|GWtk1a585Ki|mAz9M*e-=T#aC-#5YWt;y~_&e(nZ3lx1pss!c_d5MPk0(VhFRAv)
zSUN3q>XVbL{rzoe+}^4mKYl!T|K7iqOVpzH8IPoKTFS*muAsFC44^D?V`DOCY3m~Q
z{&S!~oll>X^6z=v-5=xf#J=)w*nE8kmK~3eUAxtOz-+-6;oV-$(y{SM6HgqBI{oJ6
zX3(-L(8Thuudf*@s;fae*k+mM`+@RK!9ynJcD~g6`)WZpv9Pln*Zry3ly=tZ{k^?&
zuWQHb*Z}fJ{gb}HGxP0|i%kx&ui)@0$n88N!FtB{SPq*R!`g-?2U5(Zd8!<;Dtf|E
zS68<tax+^2kJ`@a?|L5}9ZkNwtMtm6$jRB)*G<%qw-eKg@wm06Pw&jXfB&}R+`MGT
z0cx_$+U4f*M6~F*^0R;EZ+v60;N)R!+qK1{f8#YhlVd6jzaGudsOAqi7`6K8f0ww0
z2M#!Zs&O_R3DC+c&j|{Qpk>gBhuc8OPAhcPhr|5#58l2#du3&C=EX&<$0Xj}-+z9A
zV>4(1!qL%j&);viedbt9Tot-{*KRK*CBZK1u%ODja@p;PYyS%UxODfaK<9~9S63e|
zzhBGlu-L6v!Zb^SQ&=tK<Rn#4N7=gkUBEIQ$!BL~I$v7i$+)BPvl^&fbzz~iL^7x^
z>fFw!>Nm&Y-I}frkCrEW?q`lRyuEg7`7bG{<Rr$OYq!?#*cGGn$SU{Nmc-}h=K9RD
znR#icck$z6yr8|>zrMci6jlcpKc?B&c#6+O=kImhSMw9pKDoTix0nyKJth47Q}4Hu
z$xV$-*KVCXe`7lPjhwZ$i>-t*SK3aj|Ms}wepBh|uwP$aKffa;A<?mXxjLu;G}o&1
z(Zj>-pmoZglhp*x^I{mn*2Q=}I?{P^vO52R4A(E;z8yP#`n2p-fr%bY-fwp<=YM4H
z>+!5Ld6lGKCj+SPZRe8(ZQ}(k<4}m-SJRLjHM{8Psg3F9=Pg&;vk%mxu_{e^cV{Q4
zUdX+@?cvj>N2BxiKHavfqr*i_kF(?03=@Z4$IYJd*3S8}<AsCqgDIe8sSnjvR9YmB
z(=P0-E(aZY0NSw+X$vzgh~Hla8ZrgttgYF{KRi4PS}w%kJzZ~U>FaATdnyF;^Ydq!
zWG=dRQb|b<v@+nBgT2ga-RK0H#Au=17ta+ItnEIfqVzD~{k^?Ee*WB;c$kgh)Ku-`
zOFSogOjhFsHRqjLx#n1vc9p!mv@zqN((}iUPfypsye`%{Jv(`#lIsk^WVV?`sYReJ
zjFNUZ>yeuWtYj1mc>4r)yzfkwV`yKq^*U(r0Vlh%dtb`oHeS&5*2Tr{!RzB}*MR1+
z40CUp*x1;B29|1neK~mfvT(zL2MJuFT1O@-yLU($s~v9RT?}qs@3}TvuA{>xLXWd!
z;b)F{EC$D>uxzu<7TMgfXC`!Xff1C13m+d_8o$5pNVj;u{r^9cLCu7(uR@ESo;upZ
z$~`Yjv`0vlYj5@Uw10no`pmbxYpJ-cqhm+=X?H_+7pbE<6R);%i-T5Q|NHkZ=l;IC
zH<dU*E1N;nVBhc8_fMZLzSzD0*!lDP{QUfDwu07aSeL&8%|IR4_(ZP3@V`l)uZzkb
z$gEOwk0$dLwtI|w=HJL&yY*#kyp~{P<iUdnK}S2-)&2q<CITw2w&mW|2w1@IKq3RQ
zW)9l3I=`p#v&TFeONR9G^NwD>K7D@OFV6h@e65fb4y!^|itxC)#3}2&e~{d>l3@)?
z62r_!W(zmH<t$DNzLRu6N!{L4Y5eo^bI_nRXkh|q9b)<WI4%*518bwVYXmN0G0nPi
z;PBz*R&Mc6xAXT;w5cpwv-MnNcHOU+>W_}~o(9GLOrxc{SF0!~`4_nJfADYUbZEVB
zzIN?a)rK4g5t)a9E^*F#tG_REXk^N{zi;jo&EQQXFM~iEns05%1WiD73adW@ZI}&P
z8wFZJWmWo$q0jx|)m5RO>37iH3(&Mo`TICf@|@-@IPv-fYo?^M2kbIyTc=$(e&^aP
zXNP(j#vqqC=a-k4t9wn+0JSsz{{9}kHp)~lb{A-R0#tf!Ogj2#`TV-1kB^QX>6gD>
z8P_eQ8?mp(611f2+L}n6_<eVNo``gDiL-zAqFI88B{F-h;WMKNToqg1+_QA}%kLTo
zIxr#S{5)HeoEriS%Y0`Ct%)!+N;|`0;imKb<>hwJ5R7T|u^EQRa~98(H_y7FvB;(K
zPz$H<7mrAnC%g~(#EvvO%)0PBy0P!rjFe+DTpYw7v`C*)QR?4W_t)y}t*y%b^K3wC
z)`ivm7#=))=y<G064czBX_UIiy<ZNrk_og3QPMcg;_$;RQSFRtYi1Uw6oHNe*p@RB
zRJ%wYl4bm;t>FFQcb&yAxp|Cw4DXre?^@`i)Rf%0=jG+)lQo0Y)codj7`BD2jS|$4
zvpHZW3ObC%bH1Ied!Nk0<l~@$(w0T8-Ao0~&&ft@&+~nHYU)hWY%%*kADXRKD=R7e
zSDtR4wC$Q-&6~ew$v$NZWcmWn?guSeOLTRKNqBv2Eoh^*ZuB;WfISt3YCbbSN0Ko7
z`}Z$oML?r*`nd^ax!`@F`)Yn3nsa}FBQu|@Rm<|_>Y(xRsal~$-mxw&PxcpPaxXGe
zn`OAH+3?u&i)PtxC9~g_WWTj&br$^o^4?zS=xsTQm7kt~_6)9x-7O|BFYn~!^x^Yo
z<@9rN=2(~a-P>Eex&D7$x&;p(U)qTYiXu7@6F{qYbfe9-<=k|-zAkoa$h?jd(x;Y!
zHs!Y;n~~@c8GbL^WnS7^RRx6uH}eY~9q9xu4fD7EJ0)Uc661!%!)&WUS09_I9e!ex
zDmUnm1<T@RJjHW8C#zlDo*&NuI^yHPLg$a)>WcnV3kp_F-tqYQ@4pUKpb=#!Sv%0w
z>8XI#VY<&9Ch0_O0(JkBj&>bA+|CbbBD;2rJw4Vd%_C<sBX)P0ttcO3)V3VYpP!zB
z4$fHY-Va)j-pO!BP{5wmj`MA`hLT>%|9`c=zQ6D9@8{qD@0WJ;_PnQ0PEJnj`}y&>
zyypx9MbP%?@O3die*eA<8i%nuy*=;lqTuCzG5hOe8T9q_LAlp!y58GQzdAZReiR(H
z>9B2xIKY>DhVy|<ALnNIjn{5H%F~$c(XuV=tQ2S?!^6Yvj2V}fa4Ng?C<HEYX-H-%
z`ughX&#%|xL9-p8RzvOYZ!VoeM=N_lJ+5D0Ul;%RQMfK{@2NXGi|+=B3kq_^zvJjQ
z*ub{9V@JnUvH1A-W&ZQ|EaX)EXPI<9I{N?r_YI&9(CgQy|Nj228MK50)ZdKV_5VGm
zkc`Zk3k#iJ-rsM3@ZdqvQ9SqdR`1@Ur=;{q>fMZI%UV{y*A$v5nG9Nr85b7^nwkXd
zy2`k?h_T@5DN(J^RYyRlEqwcy_UXyVAHROJMauuYvNG5t>q>|HzaPvEda=6<Qcei$
z*|X<Pki4KEXZ^E4_R^pCpPrq4J@4+Wt9OqI6yDmNFaP}9+{exQb__DL{O9M{djI;;
zH&tit)*gBLd3kqtfu>!&rfMBMGt<~}s#fTX*PwoM`Mt_^Y4f}ZCYeE?CeBQw)R;JV
zLBVh%#CB%g$x|eg@0lIzF*=rGdQ7I?M1PUtvc-naY|E#3swjcl-g~RRgVt=B<lMMm
zIpN6d+qWh8{O4M^etUEC<&BNX7Z<sL23kO)^8T&P4M#eKFE4Op1`UY4ySrPI&(%eV
zbGkj~gb3z;M=pwg)K?G}&@Cy?Qm_xWfAy(Q<>kLW9`|p_zTPLS?w8QBFluX7qS`7x
zPEOF0BGA%D7FO24jY+Pc*=Nw0NzC*0`~N9<P0@IAe!hIe#l`Nzrdd}E`scd3s3d`A
zQ1lDVv_^>S;J2yCx$l;+L;94;r(;&Nzf5GUN<cj|2G9V`$;s-$3mh1q8-mJ&bulx8
zm-~IZ7M*XHc!=fI_4V><UszdL4O31Cu<=T{tO{9qV`s5?;iDske)-BuN)y|ynUVw_
zIA`ZJ7^<BT{;kL4c{f09qWPq))3UCv+F1L$43w!3G%{!2-)9@R*y`VPJ|3PYkNfS@
zZf(hAVP^+5C64t<Kc92!*~G=}{h&JZ->=vDJ%(4-#YPLqb$7TVz2oRm{J%k8vEY0t
zt6*g?D?2-AhO);HG}7TYS<Nu*j6~29kB2tT&fEWA;?^q_v$Lob)F;ZlWug_fM&cQ0
zedgI&uI+rX92^`E-fq92_U_KkJ^%mxUbk*iN5>wwJBA*q#uvU={(i+E9TOoo(friU
z&(AZjtPljPA<xqeT_tkA?)O?_nR|Pyr$=qg3S8vExh`g>)9Y(%EejqT2!1GV;QICH
z&(6*k77%clYgKw<Z}s*=3p+Y?s4DO=X-OxCG4~d%S@fyVFpV!jR^m~cQRkj(O-)Up
zlU&~K`ONqE`T6vJe}2a7srb0^@ie_yuSqJN5t~vtUtU`J_`Lo9C#UuItN6{aIKL<F
z=clKjO_iV#m4i*JNBZUM_pDY@Qp#tT&hC=^_Pv9tg06wE!2yE>8UbgccE1e0e_7&j
zc28t>&(6f2jmKt~oVQS$XP7q6@LAf6?0JT2?^f$|pV+^(?r&Am^K-t-{pNyBwVJ9G
znsk1it%~QQBb8^qzP=9XZ>|hoEe2Zt;6LB)$M4_4OFSkTT;EmxUJf*k__?@O%G9Fl
zjYO}M=_QR+LBYbJ(>5K~Zpp9RD%t2`!L~MK<F#d*udU-*9({}<jQQ{XhcnhU-f`G@
zAv`Z3&SI+jlh&r@=FCe=K-)Es-oHP8OXlTGH9w2$emrD<Zd7qCYMJkBw@*(_f`;-e
zi=Kc^zT=Uz`LWVb4KyB=e{T=y_^sUA+bp-M`^>no^sA8I#Ow2|*;ZOaX7@9=#}v#r
zWH>e>{ajaG&&eib5wVTe{)z57%m3rD#OJ=P-x4aO2R`uxotqWaJ$<^kZPk|r>F4Kx
zmJICte`cmJXtn&^-Q~ijSs`uw@_x_H&7G?}L!Oh5FYQQ&An4SD0|y-LRX(3<@L9R5
zqr>K8toF(jlVfKLkI5JvyTkd{^0vg}gR)N<xtJI&o+Z|#Fc+|EJeelsxnxV--zu}*
zU;pF8K#l76_xAEg7#xt~b9Qo)uqx4bd1-0#^K)}WbRq=m>+5%wzyB9vVN>=-;%K+{
z^78lhK--b_)mDSnUaX7R855;1C|J39N3!Zvp#%OF%QpWMJbtI$v*DCOY_iYJ3w2%V
zrikpwk&m8nD=NF!aC*hLJw3-H;tz;dJQGS)`hV<bw>YTgE`ELvv@`PU?d^|Wz65od
zJm*+!{JaBnz|+p6)IM43w(Z-^laKW*3|$>|K1cA+%jNS|L~qw)WMowFpEoCRb6Vy~
z8$rQJ&374&f0%ACF4=aiE@kc8w6%XZJec3`-2Lx#Y{tQb%zpn~hAPc@)v&c})mF3h
zTg~22p3K+1XU&2I3dee--Iw{y1P$H9#l?Y+-kC6A!{t^sHnvMky~Q`BpFcNI*&Vcn
z<M+3>pw7hk+L$+wA2+wRvv1A5e(e7J_=f>5E^)K0e<`G~zKY6bmb;&^c5iNvBwx+v
zN!KNr&(t3@Tpsr+O1#14n8fE5q8BaNO4Ru7s((85_viEZppy3P?sDdUg-)!XBPiN<
z604(f?(LbGb#+zY$49Q9>CGD(lQS<ZIce-JyFPk*U((U8hYue*f(pW|+2SjMmtW&Z
z6%_m#e&=FS1zX3rIkguXHtQD)X1^89e%mO%=iR=Png5uQ9=_=Q;o+#DmiSw>YmX2p
zJGu2ry}7q{Ht0OEoSQ~rYa#^Iz(owG5xb)x@!WiS|D#=^mIV(Od}o{0YJIr7r*bm%
zuq#l3d1s!QuT-nEpy1EzcP=(r$Vepg+{{>O`#oc^;j`QY@*i%l-nY<DO|x%b%S<Qp
zRNlFdKTO&BZPwPZ{f5ud6TC9+J2hw?;Ob477OtwH(J^6yz#`Xf&~b7<{(L@fS@z~e
z@Z!mgVQZs~w#(O@I6K=MG?e)Gc>nXm{Ps0zH-5j}em~>Z7R}}U^VO=pyzr0p25rtM
za(B?-JHpr}nf&kBfA*Ck9JTR}HtuV_7IpiF=$*}?eII_F=wE0*n`yK2{p;+<m{&X5
z>$Bh5+f?0cA+LUYWpKM)?JtH4J3d~n-?Bb_zu)C$zCT|spU=U=v!v|ptsZ%MyE98}
z^n-S1$L*~$EPE5d@ag&a^LKU@S3aLxerUUql9JHFnaA1Q?RwUBOy<9Mdvtd0t^(~d
z+LIthpoEo+JI6VT>%}an{{HUF?B_FzZL_bfd2?&)>y<Av)@;>@*uW4UAOG&&UhgIr
z&KV||LZ;c*YMzyzpJVAf(<l|RFfeej+tbVb_DjRp$N9&GySV(b1??t#Yy8}=PbcQz
z`p&IpYgfP5e3S(}<frcMufo^Y)*4KXwU>MZ+DqTe#{1*-`u(7D<anh_65ia{sNyl<
z!OrXcvrIHW)#<vkbIkLX{HykHafvfDHSgGyB(5K~q~ztLAHRPy2W(7o1tm|=V4VzT
z1^yJx;1{>HYJ(O{6h1lvTCSoMy2|GBF3<+*sxL1<9rYD~i#Mg56nb>D+r3A^@X%gA
zB_*MqJ9HJKl7pBu8Q-gakIcTlW1oxCdbdR`ogMP_cA%3L-`v<3vM%Q5%4E=<h-Nlk
z(B=?OYOVYGt4G@W-OROZ*P@=CpAVWT2hBi$hS-lufToASL)=|lloZR?ESbdjgX_fq
zjNljk(!cI81;)hcP5l4p`TTmd;AK8byr=W=^Yicf`AquJvEJWTIvyQ3;NaFLb8>>B
zGbm(0V`}g2>^%QAyW;Ds(5UTsXCEEyW(2MBy0^DF%Tz>gV!_isu_G@Xv=%5AFjTx~
zGwRqQ6uvHIVeoQ4P<Ni+?nlGb)#1rKptX|zvb%F{n@O4FocQ_q`P|P6ezQz8&jeNV
zM{ms%^_^|@^v}=FN4iA23m+e|EpN&Z6r31-QkKzB{=$){-A8!8i&dtA#`8dvv_((3
z?%lfw8r%hC6c^6h40Ye%#oGP-61>c3=AmYGe$Xz~_}Z^mi=UfrxprxxGyAcAd47k7
zhgw1VJ6>Me`;GaRtBXogfxClEa}@7W-m<T+LT_!$J$<N^n^7ZjlS=S%zuK%$n+DVD
zYoKEZK*`X-fdRDS@6(f$=W`Nkjz~E7NEm`vHa|GfSn~SX+m#nIm6U|$-7(}(Qa-@1
zk-c{B<4d#Kh0iuiRD$vdXamEmE1ICvOFX`&asB%D!Mcs0BgVX^>(zX}TMkk)!!X&X
z?oS2i^nf#Apnd&)^7ekmdL$V^5z)>kt5p5%jo!-X9UXt{&o;l9S1IsZGTDe(-6=e1
z=f5wC>r=jpObpkn`tkzQJq}$RW?230&GKdI7(ui28CO?{%E`%r1`1Y%t_E!;ouuab
z>rA$sby-gvuXNF;C!T-){sk?jkBf`rYFAQvWcDt@F^B04OH-q_&EFkAdn0V07G^p2
z+%U_z0Uq^;-)Hk6<E`;Ao3A&%-`QCVnhWWbHZOX7j2G0t1TF3eUw^Oox74}0*3--0
z-VziLH~`ve(j}^0@%?UjY@n{7U?tyHg{F4tca{thTq>Kc?aN*3`}@f2Uaoeb!n-?*
z+t1Cl4qg*sC}o;;<Y>1zV~3P!){KITwW+tZWd8W^12k<28n^%z2D{7O7qc${O)Kmw
zeGNL+fr*J}MeJ^~-R18=-NK32o2=PZsxa)^a_wHh;k~YLr`GTP*R_7V{_%eK<A)D7
zPt%PSGS9oSywAGm35Ra<wkKCs2D7lT7QVcs3ToANi|Nj@mOTqvNz=^6Yf=2HXY<sL
zi~H>^eKA#1`gE(no%>OhLbvog?N3gi2#wsF21=NZkM~bDPWLm*zjp@I=l%4lNKRZt
z<j9AIhfmJ8w>Qtf_vFULWYEy%T<h{nn^I5L^Hi6=zX#g7Dxwk40216$m<*~;D%b8<
z%({_z!wHFE*&j2Pv#(58%Uf8v(xoBm>Z*^&<?A0jed-E2;^5X+?RoR&CHCFiSG#+2
z>xI*&x$EoeK|O@?^K3h%zTW)reRo%Bw?*M2hJbZ3me9`a-#d?8U0m**l-2F{-T3A}
zj7)O~)BK9eK9|Ck6DIusUz>7afuo3aSP$q_xz*w84IX}YcXu~vKmDfE(?Zr|IiPmW
zogIZgU$5W);`a9U#fR^K2HK`-iN3zRzC2Gme%~HY%X`nZJ0JD0ILN%#?cQ;9WAbs(
z@Z<xILI%*;l6QBN`rCer-Cd@;Z{I!@?`b^#{{Eo3qwnwTzP!KxfADKv`=Zy^bV0i{
z!sBaMLC5oH1TFEfxaQ&F^5iP0SN=D))_>yh*c}Cp2b<ZAOJ9XBF*ASs^eO4diHYYb
zx#aoVL9tT({oS80m;LvAK4-lqb~orGxQ#hCjXpg+{rygL&aEw-pw9T48-__oIu8E$
z_&D>{mdqX3eO+9hgcclEPE$|z(Mk5nO73~y-7oetA9O(5e7jnY`F6I#>V7I38Xf(1
zzdHW@{%&6^^!ok2-+c1&^5^DQIu{fe)c^U&Ui<r7>g{d0=XpWL&GAT?bSSxY6}-7&
zc(3+*EGYaor=2wcoriKyBJU+jYR}4+$AQJ?F8KazczbNd%L7u`Z?C`8nC=p@J^#L1
z?XNF)_EZWtfbwv~hlHA%nt4{=K)EmbI$wQ#J?OZhpU>xm7R_mguTu$M7xTYje)jcs
zhIw}^nwpwkTv>TJc=3E!7ngf1dijnf$3mE=F@`tD9e8|J>o}wCX7%-;QQ|qw0ic5*
zwq{)gtwxnL&wKLw{r-9_nW*fUcC}XT_x;w3i;KInv$!2pHm;AiH_N~G=T1S!T2%`R
z2~g+SxcpsA-QTa_ZoN`V3pA9J@>R-pwr*#>k+wEBv8S^u`ASh-_S>>#pHP{}8T;Q}
za{B8YmG%DXrqb78pf#DG&8U}_dasPys`a4a&+k1G4}-QfUB5nkwt4;}tI{k`hiqHU
zO;Fo(XYup8cY8rK`R25<poKQ`Yd(4IxZ>{O65|b?P)HI>NPO{I{qoCF8SS+lf3y`9
z6?NkG&3SaR8?=^hnoeZX^5yF8eKLh|pVxrT4CoM41`Qq0G)jGRYO1zQ^tPUPw$+<*
zZ*P0v=A5m|Ev|Ru`0;j7$y)fxg^7vj(AqjBCCILU?F}vGZ%$|1@n+W|4;Rp)fL~u<
zA7AL)&d?#O&bM#hKG5!oCnqP{f8Qf(U3OtlW%0eL*Seso0np*2Q#6I8&2knvG%}sH
zeSc}GH)wPabl5{*=lb+>b3jMd#^oM$adEkGL{_(BKf~T0!$Nt`T8=me>x8A!r&RJc
z7^j~rcyU1ybcE%Kz{M7|zf6?f`)cwm_LRS$SA6I-D8aqBpa`nutx8`V>65jdC(S3n
zRVwZ5tf{Kr(*(4`bkzLko$<H->jGMQvAIi0Nl6b>t=k<)d!X<^xbOHG+eVoK(GI5O
zQ#|h}fDS-8Gt+pAb~s<dG~MV)MyXy|*Vg<zbk!5IVdnHS-IH@HjemZ6n*8U-$0sKy
zHoxEh|DXJG)0&i9TQZ^h9t~@Mm0Vil`B`g~ijvZ&sKTELq72DCTnP*TVjes(M>pzy
zUViP?Wj*~1^-CPJ)`3og2CdgwzFhtG_I&l)Utjb~@AXQXzqqzmT04B*lA@=lKr1Ri
z6LO&4E=#?qFTWODcO>fc-QDG#lE!Kb>i+YdJfB~G?E3Za&r)3-E&)<Y9xdzKw03Ly
znyqKoZq;0~_2QbXC)aHCy?>-YV;$)DtEep*poN<|%HPXfT@_mW?8&wBpb`0+ni|jw
zG0+hspPrn2a(1?OeSLk^w>LlU6jc2ERSG(=M=Na2i#dAgrLV61`1w;)1~e`A?34SM
zV>3)0q_f{ProTDO;<N4AzW1++PQHG9VWIPtb+NPW?k)$N#BrokIP=z)m)y>`K<y*p
zxbXFHb6;Lw4w5=E6SO@0r2V}8X=kOR%=6C7G)@Q2=YS5Xir$v9epi-~lG1wB@+}I}
z7#`WA$LB2A@w!WCJ?N~#iRSrnW$*9#9_x_=?aPecku!JeG|;92<8;4CDxOY<S~zDK
zBr?g@d|<5p{_gMbg3AB@YOTuOftI#|=7vG%Lq0z@7t|^cTDc>2rR}_V|36Ip(x5h3
zc)5z_Bmn^dhqt%3f(nPiM>g-vx!c`^<L>V&?FJQ!ox<vm-o8D1XJ>KdjSUa&*+4M@
z8hryTah{?P2wGkA^6u{M-0b^0IyziT^fDbyj+vMq`;*x7liA&3&aW4rlh^AWka^%A
zKE*T6etZ7?XQ0gmRbOA(NZCwP^%kr9{nlJeFXl)8!w(-h*Wa&xZ@XvDo*$38_2;Z@
z>y<LCdZ_&J>FMd4)6dHprJOj>#w!i75j5tf5>#|`f1RR3!Heq8N1nT{W18IXaQ&xa
z$7cMnaPyhY7W6oRxr+6|^{DEv8y`PneB7Y5aP~Cjw`;eW$E8+2$-KTkKK;v!i=eYZ
zUteF(yrJ;18<)5qkHg7Hs{cR!0cG(;uH2w@{_AUNe?IEg|M2Nk)ylBL?EG>T*S+gZ
z5|-xP-Ztw?l#7d!>GUlMQQ6NUvc03Sy_xni^UBrMy$L-Rb^B&i^+(bBc9tK^F36tX
zGhyjsyl+!@=ek4Qf|wWD<_7OYr@P7(e}5MX8VcD}@)C5A%yr0#wQC|aHaWF&?fviv
zbc___oOn>(&&k7+^5Mb3DLRp#TGzHIDk_4;WqTxziyj_gJ+M(EzF*E(gwNGQ<x=r!
zn~ryBJu4d)iyE%m`fZw_8utc%jij}A1*&`mW%_p;M`!c@yZqIJ|IvPN8JV8`etvd7
z3%1SEbs{G*GP4D2$+$S(>OW|*D)scVJ-^@W2CX;+9T21HB?9U)JwDd^f8*5;phd*l
z*Lt>QUuQBXdlO;z@5kf+ahigHodPEOi)KG_tl>SvD92FlY%hMq&?4<|^6?yocMSS@
zrzTBLTB~Yt<KkuouPGWeKOVM&M!Q2-hkd-AzkhFt1?Yszef##A<lLC>?(Xj5x3^5I
zzP@sOc&PQ}=JfOSe(}j`!E3$F&zrk7`}!n}K&5@Z-&up&SrgS=b~Q-sV*8?yFl(!s
zMoDqdgH5$-EKR@sU3#JR{H{KvqaAi$$=?S$lx;^r;xeC^kM3OCobC@ge`}^uYFyT%
zm+r!G)fE*Nb{3~wmA^Z)%y;$-t5Pk{1`EyLWi{`1f}+W-SL(;lpMnAcpcSe&c9-j4
zT^(Mp`c+s^u+!t-jfRXK$(){z`V~_v9?gk3z<(f8rdH^GI`WE<U;5L#E`Zjs9q*F`
z9h_SK_pA8jWxmCI0exb+QgU+o|CB2p9%9Y9y2|zZJX_E<u691zMa9q0frh2)>+7So
z<@`L<u(SGm-ZcGqKhVzKU$56kZpje*^<GU$=~GVrCmFfqhM)Qt&#o*sU-<CD@(cY_
z*KGYRZ~cyG!U>6Fxvff4?vFfVcKQEP&DQM}(*;eO%(1VR<LBoGP4hG`GRIZTw93{6
zomLgTKF%cn-W(=YF3=*LMQ**PzP!8~Z;|-zF=)~3mdwkbDb$yjmj2cc1qHwdPynpm
z+mw82mblTeBWz)hW+W}2v-R7_lRN%H#%)%}CqYJTPI>Prddl_n_4Vh|<LekfH7IB@
zxcq+Y_oeGWOTj>U-zq<=1uyqYeR5(V=%Cy#QEgD~CuoVs$NuN>yUTjh&d$2HEjQY0
zx*o5?=Crf_o?C&AvsTLktshun!4%<j;P=VD*KW;R{~>N;<5df`Wg*N-Qprhe@Ajpw
zt<6|_H^1kn<cy@AkGyxyStC9!5<K&1%l3O!-Q41O0{U?_pxpWS+1dD4fkqZ;d*p1Z
zOb)m6FR%Xoj)jdaXnmY5s6Pl<tpATYn%6w<j>q1rub}#yolhp={k^>|okCATLqNw2
z1{G8~m>he;HjPQMV9N{JlT7P%6qqU-m=?b0x81m2WrN<A+S&x04O(A57cID}t>eDr
z;memNn^?I$rf6K;|LXbn;^%&#RXCvSJ|>w$%<O!iNm|fS8BSrf2_`R%k8@kvR(xpq
z_xHDP(h&|PCnwM*`-mL{3qcL|6Z@a^i5)p<v24mpHW>!Fw&!QpY<*o(CQ$on$7>6<
zi_`ued~<X2&&U1tGt6?O0vEX`W?x&QU;A!v^>@&12*zn=Kuaq?W7W(3WP_IZoc#3k
z^val>pSag=%)YJ%I=!y!{k>kpHaXiWgMtSRi(I?E#jjFTQWDbKsSFxJjL5F9dN}cu
z+YH-kv$L~I4@Y_TN|~+*S$WBO{_l)KuR#aoWn54IHMyRio(?*4kC~mXW@V^vQ&SUY
zi^1_eS!L%oo-;FzpDztd5)>4im|lF`#Js(L=ida52OkS8N?u%;&ez`WUvYP3u==|@
zJDpdDt@W6w#0uIteq}|V{@y3CS5^ehw5c@8y}d0JS{Ew)pLlxuE#qTTnA@1AuHCvk
zuH?^bg-v=}zo%Hdxw-kd_uTJ)zuyNf?Km|>)A`Gbi=gum;^N{!6PRUhZ|&W1KEcC-
z<MFZH$ET)hgT~N9LtI^4j(B>%-T6>(^VV<AFL18mmrmwmyguLVh*){)&L{V08l`fr
zjo$t*{NaZ~t=ynh#j(4~0(Y0?K07=6_}1*}8Ta;BHnZ_oJyZ~B2wv_7+68}YO=PoS
z8>lAsnQ64QORKY^!$Si++x6wh#;%jR55xri9ML{<HFZ+``}h0**S#$Gk#Xp?jAfC4
zX;ug*r_L};1|1@FdwYKRtu2}QpzW!k(WX8b%ZSZsyq!X-NiQ!g1vL#o+m@R{tRBrs
z-Y|Eo*$v+B)9W+8zq<>nB0=ZhZOsa00Nr4*G3jW=tt~I@=T(1s5%}lNpB*(njX=8<
zBQ`XAd3kwr$;+TsVQYT{X)gpd6vNg=eSEw9J`-p;CTQZ}(UH#o)lXeqT%KsY<LEGK
zILg(&e)-<&?~mTUKfkm1xkdRqnc3#~plK%-&|wVc8fGZF^A$Zg@$t@U7FJf!yi^;n
zwA)mz&>MTJ&Dr_oQht1RSn}cmqrU$7>3YH6-`xeB&DSZaEe1NPG4t{={k=!#b##EX
zxN&r77p_^f=@{>KF`3gBa_{b%dUm$?=E~1$$NFSJhx##sPIvhE>9qb~8F}q6omnQC
zPP@zW&GUbpn`;eQSMm4z{q$>VB0)7Gv<tfT!=Jyuzk~Me-mCv#%h1Lrd+O`!>!1e1
zoTnm!f)hVH?rX4Mn<0CP>5H*Hf6&3G>N7`EyFQrZ-a694DSTr~rf@sIJm2Q`hxzSG
z*w%l)SKaSDT@SSSWRkkS->Q(6D<U>36+Svr`Ox;={r%?;G%|x4X}VEc5)L-8f{t1K
z^6F~$zrVl#KVEWmd*0ooi;G-AM@{Vi_p2MUaQejs#U4Y@f{OS1e!tsa%Lux1=h7X+
zvu7VS2h6K1&VDPs)$G=5yR&C!8mD_q*OP5*Yy_|Ovo6p3^!&X4zM7vE|NnlE&tmy#
z|MTzn`yao4RjvN^1~f&{DXcz8%~uL^WYEJyt@EqzfllQxOkz3Q&j0+~-Q5gF`ebKU
zeSP(J^-fT~I8M~J`0+fkBWX735?((*`EssRsgi}o3^rb=2ag{&FJJy#d*?UM>A?5)
zTHF8op=?|ACE?kbnL3f1TEujt46?3hBpvVjd#9LR-p=ReC-6}X44~<o$jxb>0&s?*
z>GWM49UZ%O>|r%js=6B`@c#b(^9_v5plT`g^fXqP%SZOSYLx9)+p{iUAyek1C5aCX
zG#=>`Zhv`sdGJ!Nsp9kgKRC$z{E9hf;oH&f>|fr3f`#^56?UbswB>Y<-j<{2KhK6o
z+KeYYK3>kQhU0_R;fJl<;wxfzn}N;)zOo`v#<psTUF|Q>2}R%D-28k8d|(D>)#19h
zy<82`r;BTcuS<cIJL?6(>(e=teVCJd-aUU)e_P`7O6}7k6F~<OE^_VOlz-pODD~8l
zCRXl$g$XD2fBn&N9dvYK`1-gXzkY41{G66{X2!wq_v`=P*~wY{{+=&rC*rNG+Iy?N
zm*x3S*So7-eMeVGNojo>=vD)@X@+UaAEXWVZzT2nyeTpHPp5M*!{3;|WgRQBA(y7i
zGR@vp{M?UAOy|d`b+un!1ls+0zzjN*{msqImNh>NKqdC^<L#g!q&1P7)3*ghWlNgp
z$$$=?K0nVk<-~->sI6IhHx+eubevfIe3jUddk$g?I46i^a6e%(lT6;UYXy(styfo9
zM{Z1F1sz}W=t!qazue!cG3FW?9iWq8K?y%-saN36qSUObtB#(UstwxYz5o9|>z9|7
zRzKSb8n#b5+6B6Qgq>gR!Ryzj&&{>gjNSD`TXS|tM@I{PcyH1=#xI+%o#Xynb3o!V
z^9G(Dhb4mVMeRQ7n%Y^gW^2joYrGAhJtr!jlfsMcx(ml0?-XutWM(%?I>G@uwPdbU
zsf1;b%F3XnRqu9&uZvN1?~?(oZus%>v2pFMl2zgB|9PEKRZ>!Vcsf+KV`YPEfBuGR
z^H{r>{~cI=Y=)4YmUl~X59o3x&}Je&S*t(KU*FwdKmXp|YS5|vt3p@1P0<L<xV=pm
z<o~y~w(7*}_#l5+(cw@FC+N%?Rqtsj-{0K@7sL4i(|wAQdn_5hY`RwWxu^Et0igvf
zA6PHA3#aZr4;sS+_0K1%a(hlzOa1lbB`B*oHnUw^6{@|+t+sCQ=KcHa8yg#+oO>(L
z3|c^AV{6+f^tAWac}*pyiF20iER5xT6t>{i=CX+F_wDa~3%+>0=#z_tzuxTc`*&4-
zR$Cjj_0eH|`z2XdSLNK@HB~cs8EE*NPu9w1ciG!{(%?x|<20V1pPnwxySs~pg@vI{
zG#b?FaJgr*j;rH7!^&Pm&UsreM@h3>VO_?sJSJqB`MrhC?I)(`N>9}eSJTjVQNQmT
zXb1YokDy}#Q%+85ov7?S$sp0mEbq>VFE1~9PSLnneBQSFoy^lyQx^v>_XC}FIZ4%f
z-zUzUpbB<tjFHFDsNF2blb_UE9b;M>8#u26bd(+o8`~s{!bkNrUw+$&>&JmtM7+MX
zw&ue@cF+<k&`}#3laF6o<~v(FuK4AprJzCf)#2+WDL68votfcyb=CPC4KYE%iRK+)
zL6y#bzunFUjWtDVOfsza@SwhQ-PUP0H>XdwtuC{%wFTW7@a@gbko9qMnc4Y3TfFxh
z$khFMxg0dtx;lJ4=yIe#fB%B|sV+(!;l9Pn>jMf34CY#uGA$^7e^14G+MA{4ZOh(B
z)Ya92j${B$vaH|#Z`PHS!JDhTzN$C1Pu!Ms^TVf4Nk=*aw`5=E<LCdoPEkooDDXx6
zSMv*BUS9tA{X1xc;@pBCN(T=f1f3W4=jZ3iiq33IOiVwX&CUm{EdKZJ-+u`{{rG)8
zprg2ob(ugT6??0{fBJY_URwrqT(yDT%x7wgil3U8i|fa!6hAw2XGbAu5oFMEzq#V`
zKu5DiZOLfdzTF&DX5QOV3A#Z<(l{+(kxOU&p6fdbA4^!5>6E{_bMW-(ZqT|ngTzDO
z5z2ys6R&qK+Zo9HNE&noH|S^{P|m)-?r;C`d;9C>@2mYCv?@dsbb#+n<8;ve4A9z{
z@9*xO=V@0|RQ&Vn^?Hy?MKpsx+)SSjx;;rNY|V*dz0#2IWZbH-kLleE4QmyZC-U-d
z|NVSE-z5K@OnyFST=&$@;^&~WHd)PgQO3nZ=WXBL*qFS;f4&?8KR>@#_&T5S^K3N(
z797xC-`vr0;<blvht!f!$2d4R6f7)eY`<5<{b1+A57*X4gJ!XpdQTS;5;_Fh8Wgw3
zB6ztUXn(o?+~@D#gI1$T*wt7Zleo0h+kLW{ug7dNUC=@EZ@1s)`@RcQ5WaS0{KyMh
zH7BMYcV<uJXHZo-zw%6Yd~NIe`SRc2-DO^oc6L_D>ubF=KR?-)zS)+08#DxPdYUft
zf~v2tK+6>xA~&bC2J3>FOTG&lez1WKQGI-@_weDv%@rRX*>3%RsFfR(;LgrAPhPt;
zbahzC%S){#FE81azB$$_4LYnsJA56B%;|?efBl-I<~!@dy0(svjy;M>pxga?nD4Pq
zVrD$xwqW_zvj54)k1!u&40STsWxo}joxfw-mPA%Iwo98*z1M6ld3R@K%+4aq?~&P{
zqZ4eazk&AogF5XqjnhB9+x_0|bChY;74YIG&=#j_YojkO^%kF`=KHE^73c;`X{Aj)
zN%y!+7&kGbGBW?k>iJmn2C-;mUUv7-ErE;OHdcSnyR^*L8+1e2?S2_cr)z5>U*6iP
zeM|y0oB8bQ?D^7sjGIzUI=#8E@#Wp!=IVZP5}urx2re@}P4Teox+yW4`37sswrg@G
z$5I%-F}kkVD(%#-$@J&viy8I1;wpNR?5e(K*xA{Ejt~dklCsQ4vZ=Wlv^zKXSdXHH
zM#m&oZ=>8>CeKeicF()B<KP5E=Mxi^*?Xl-nI1elJG-T&#pbi&){c%2iwu!smC7T3
zERubE7HAf5SqSdhsqp{*i=PvD56CVM_|VU2Xk+uryW;=9TF`A>GmTPze7zq3^TT0&
z(82rpd%ub;cI#b~d3l*c@|@?aY-~oEmsHqzBo1uNz7AUBT>AQ&YSfmDbAlH@7eM}3
zxdhtODV@L~Ang7?J9TZXz%Faef}3{N=47qidTfUG!r${sZDBiK0^@d-ygURNTD`oS
z-?dvT_3y8*paVWY#}}PcpAR~Z?)k^+Z*LM0HnG-xy&68pqL8WK(b4YDN5$g>bfdO}
z$Jq%A3U=<e2Oh)V`BHf>QFZOs*G~8AS^qGpFz;gO?lo*(yS4oP^xx6h%b9`?e(d;J
zzw=l(sF(#U(EIV@hk%TX&s42Y3EQeK!HXxG=ifV1{eJKBKXVL|-9S4Yr)q^B+M?G5
zN{Kz@W(rKnutADzw`L#keXzmsS^fj70O8{fQ@9<Jl6xwzbY;k#)GB;oH=Ub<Lm_ro
z38=sXEicW!rUSa;U|a6(8Rq$N*Vn}+zqzrI0koZUj%D#A`}(?9S691#d~~!^NVUtl
zOIJxrN$`NQw7}Y};SJjVAHP)l@>KNKPkjZkzI`42zZAuee6*-~9Gt$}VNJwF(8NhA
zm#C8891GCa576O;r>E;P3qUsaI6pel3912(_sM4If|~i^k9v7K^iNAnW_0&{xc)$@
z0_z3g3WhZd8?L=GKlX>mhx2VThXG`8;o(ZZxmKW^`4c7xJl}R@WpMDmno6yZ6#{7&
zIzb)vjy+m}b_$O;np7L~9AX|QeP9o`5cT`V<Hx@aR3wDHc>dJEdivB)lAoTQZePA!
z-L*?(Va?A^pfy`Mk()GlKzAtZ==#8TF{)Zh<G;}HSazwl`p&qxNh+Q@%HB#DCLJj#
z4|H*HQ4#9Y(O$V{Be>!|a#aM>N_SD=VFlf`NbP%Rd$wM?n_BT$GFgvVJ+@?b%K=gG
zyRS=^zCYl2zj+_?g>r^pd=B>yDzAT4?UB3I_Y2p$&&PrsY7R>zZ;Q(Qylc12yCvvK
zf62wk+JY{mM7}fki23=Da`6YI3$Umb{OTwI8Z|Ju0=|S$DNzG-%|M5T1Xo8sNAeky
z<THWEXKa(tq$Zy+O7@wi-q)GlGc&zsr{u3$={=pVmnrQJIyU3Su^Ata&0t=5|6peF
z8I@$8CiTAV4fh!v43Axx*nCZ*_%P_E*UWi^J}v+F7<vqIdkl~F8h-CJyxn8ydN+32
zhm;=8w4TVk9!u$8_xGL@{@rW1Y`@{Nm>2)$U-uZ^yc2RK{G7z)(-NDHN)&5<dB0!2
z$I#ASMtI?VW`<;+=;Sl+F1&v@&G4Civd_`u-`sz^e^9uvUT=+I+M(pzN>|GT=7|X0
zmx*pva}Zmglh6>~YdEi8_Os~(X$|pTr+Cj4=NcaNEqai<z<Ppg28RgqzRE{CI{wHq
z9D%MN<oGKqk^G7&x$%5M%mKHArG{!#qq)WQB{5bv@EzEj{^mVj3F9s1pAFsz^pDNB
zp{JerLyNJ7Q-tXrdsD%mzvBNlCM*3aXDDEM(fIiP%RL9A9#kj$^j-Kn@u4-t0SV~s
zw%V6!*dLyYT76ym2U8J)ScUqR;%OJox5`^DJMs9q%NFqfMh?bDF5BKS9Jl8a^Z0z^
z8^?cHhS?37{yEk>Jf-C~V?zEjEI64wpSM8n#pfH_UL43haQ^O7-sSHV!~}Rk`qtb(
znEZ7Q+Yi@e?;HMSzd!SMjn+Dwe}5H~x^@eeh`1hokuk?`X8+<85kr>Lo@1<wdGc0d
z^a%I%J)Wl_-x)0=YCNmsVn^Ve3!T3Yc^p}g5MwB%EWzUFIK@?PimT1%<144{d;hKa
z?)ur+ZC;e`n}7aq$^BiWtNrG#s(xQtn$_6bu<}6N0gDH}s`A-$3tjjhNp&pIJHUB>
zC!vb#U2DCCTFN3jcAaDOrQ6-jSf(+}U;4S~isQVpwalJ#8|n{M2X5|JC_82S)ExF4
zM>qAfZ<Zh2Z>{$;J7Al@eW~*9ONUEQlh_^|`^56fo86r8`^=k{cYdh4<TzWH?U9s=
zRQXm8bB2GiFS66TFF)07=-2t1!sPM4e#W}3+LvbRO04j|B(Aw*T}eROw{^|y8L}CR
ziyjtd$Un{IZ7sS!*>4@Q8l&*#%DXQdF6F(n-XO9=(BjOQxaEE&3NKR@sDF4YH2t*`
z`|2(Of$WYY^OrGh^OdbN+TL^Mc+6XFA4WItsP$}%!h6GBFnGRZ=4XEY__6P`jHt!U
z3M;}@Vw?GAOC+ReXX*O$&fs~&_lEP2)DB(y#N~UHGSzF|d{i)wj?1pRWi6Yn>oC_?
zX2;^07RFrvXWUdjpnl-?q<P2hYBPV}<dA2W?H#o6yT_!4buVwdI#m$0pgBdxZkivz
z(Pq_|6{QQC(;|XP12l_2ZcM*h^zbg!W95r?%-v!=*JGEM1jn27wD&1`S9|%+<Vb$l
zUh-?x65EE&4X1-5s;@cf-|7A!UcZ*{UEmAdmmv!bqIcT9PM9jlmc(ngdFK!I^`;uK
zua|u8{1GuF&ZNiwHEYSj3Y%M5uHGdR(iYnGP2atLrtT@%%<on!8cc)OrzWMHR@uw*
zh1o4#?<@1W^}Qjc=~DkbzGmOUp|H|;1Al=Z@6%OUlh!f!9qK*2y$BSrsV^Gp*<U%b
z^FPq8O4%toe@U6;yU6VKRuQQ!jXT&BR;u3%{vq-~aD!=qogLd#K?dXBtCy%Z2u||z
z+}_6^XSn&~>bO_0CiNUP{BdN8bE977CcXnT#?jaAl`<$~a@Xjb4G+Gcmud5i$9Q%;
zzZJte#=PlYnCuvzhtx<ek<Qi%m7Y{}u6o&Jz5`~H%8uXu$K!dpky~|dYrRT+Pk-pX
z&1{dtWIfFpjz2p8ujz{ngO1T=*R-^^vFr?!*0IR3raclaWqat&P`g~NBq2?nSw8)+
zite%b&E}VW7Tns%7pA#&o|~-uXZ8!S?=61|M6~UfabvW8{wTL;x0d*_$9xHoqfW=G
z%6>UGJxjCn%Sv|HC7*b87dIdLx~Mti*yRtBf4m!~H{RPiZDsH2=yiYleXdWvbu1@=
z^8?R^tx>0AkA9k7{jELi(Uxr4B}RQL_k7>}bKZ0LK||FgN6xuD%DTnD>#Z_YJ9{p4
z6kq`%h9f%96gZkd$X%iXBqG4#D43|g24T9kG)jQg35W=?B|)?VxS%LpEjo$q`8S1s
zA(yfz)oHBs6)&59Mfs_vg|J!Br7vR3F1ud}@C>cp7c|RvowsVHv!}TCEQQQ@OZqSW
zZx0KeW>lF!C*_Y@^z*ID6kY~+{twNz^iq83<Y}x@tC$(I_Niw3lDC(OfAlR`I>~N|
zN#LaoYVT%Fn)lS%C^6gnm&c`K-#gdMfAe|#OuO$c@A+%-l7DAU+;L9*7BqcJ-;&vv
zcfa-Z{5@qy{G`5VCT6zBPpj@#f0^g`JN41sIVT_AT$aMsG);&tX~V8hwl&>57!PnC
z_|G7I-Jvh>K%(xR<@^PlTPyc%J19P}j?IGY{;V9X57nOkZyu}6@0o7RbA*kLHO!hh
z@Y4QA)!*;&emPdI8Tod?7TtXUzup~KdVul3%OBe&x=-2peD;C9mtS@`?U<>1y!`Tw
z_@Fxde4~%z%->TF*&Vv?y0>BS$JQD0ldo)VQu<?Z_q&(c8=VL9KWr=HE||aMtI?<R
ztarHYwCS_e3tbSm;D5o>Gj&T~S6!vo|EpXnoK0ea(QjE-YfnD2W`pA28C&i?=+{VA
z@rsiEacI?^PrGOOu1%|2-H>_UTiUlswKtxgcR%u<;oT~@y7ofY+cm95YgkX5*%#57
z^3U+^-iv4MWj@{$);9UW-lM-~-Q45z!*<fCw`;3yKCpgZf1uzwd)CcAC2!3h@YHng
z%HC|gbgeZ%dtLs~-+T0pH$ON2_>bYtf&1>svnSSPeY<z$-T?z+>2B%j<`2IrEMxaG
znAi0iZ2t4_(PEXi{5tF&rQiFOv>y3xv%=_Nv&0(BJsde2E3=Q)7SCET-*Z-LzU@}S
zh9!qpZS`Mnev%}sn>jltY0|aHUsgZa7pd}6v8F$}=%dum8LFidOO`HKdGhJk#wEX1
zODCI%ymw`eh%5O2<kMcSOD3MDFWv9{^e)3Qe!5BAB_YrE-oH5S6<<_I+h&n2BUZtA
zf4#-*;})Lhy<X{OPFiwab+1;Yzo)EftX}4}B|km+W4)F{d#q;9o5S=+?eRCMIi10t
zdwr&tv@c0k_4PCAoxUac((jIt^kS9RwP!Xk@65ih!t3!#Z^D*<OB$ZDpMH9&@si0i
zf2q}+sh3{Q(GA{Nrk43x<@A)0c{3-yo3bVJ*}sW9Hf{=alfQg<>!E-yIm?|=yviOQ
z^(L3>Tax*sZ1(P@*}qTSoiN`kO6R4gXS{Z}|I2xWKc?j}1PA|e);{rC;%7m>>ZE60
zyJ9a*ySi$>QBGI>^lyd#nr7BUF3OqPsQj_^c0FGS(?8|n^V$cbr@S+?l`(hA&-PL<
zj_&w=>U)k>oUjjT-^495?|j|EysuVnk`-e*bN@60KJK6WnxA{v9ZOe!jjJy_GSRl-
z;19Xgw#5$@e~fGV+90QS?)L%a1C9q259~Uy^5w1kM&?5C*YSmqQ=5INwm+8N-`(){
zWB*AWsrT77LNn%BzHiyRU5weD@z=xs-|Cs)^hnP%UtaQ$_XhV3?Yp-HCHT)UpF48b
zP5hz!fz`&9HLMX6p4f4fyV|zDKbX7r%4?Sgy)ic|9xy*BO-Q)(c=mxgA@iaOr{9}d
z(SP*(ERTBGJEHkJZfCDA$(gq<JWBs^u&s~JQ#+v<tbZ)8e$}6Ju6^kjzteYatGAx@
z+4TMR-HG#={GUJBYkl?M(F5Cq_w+aZHZH6R*f;krOH4a|<BPdpz9&uEU%acH{Xt;O
z`8!Q^`{rdow=F8-J$t>-t?i@c{(lbU53GL}e@vM4T3}DE9>Xs4!0_EmtTu(DS2ISN
zPrk1C^48sz|Js%m`7&Nx@Ah}<#IHL<-tSxTymVG)eMncm$UR0Q;UB?z=jxYR?0$CW
z_>v#8Md$xl@2rshSX-xVqUgTxEstK|TIml_yY`7lOxpSFtVo>~_x$&T2R3W}{@1JA
z_a?BI@ll6zb&A~_>!so!)ed}b6g|MK>G$yIZ?1R$wC?P-`@s3(cFe5X505>V`LbsD
zlzTsSR_s5w|4L?#!n_%eYPNS8@%R>6Jv-Fz`*3gZLvhugyOw=EeW~)h&m6r2F;R&M
zmp&BQTZ!B8ng7{#zNOauXswp`_xi@nvrmFoOjq3bq3e}ut1tUAX6e*J=R98Co3s1B
zs8O3dFWV#GofYoOKkR#1Gry!RW@g21^Q-4hO{vvgP~BA@vF`7laHW3<QE3Y2n68~|
z{m&~goBOuG*2xdgp0Hlx^RM@lSL$r%WaaAjBL91`uEa}PvfkmS@oaW9m3yE1I!5VV
z@{Wb^2A9@*e1AKqbF*q*MEq3F-|T<p7P#u|op_-7$L<x%|CkG0ygr{%d!n~x?!nY`
z<p+*?=1t+&m)OB>vUIx8%U)%kBNnS_TDmPGVk^1L<DN0^XL5UZEOHwAnKMSu_kQ4i
zvf_!;n;9_?#=%v4gZJ2e6#ue!=a+Zu9M=79<UjLf;WQDoi}K~Fz9&wavqeb1KdCw8
zai#I>$Q>8Yh%xhTH#z*|&@a^w*2dDIN~c7$<(j{R{ra7vcQ5+DwMnx|i>EKRRHbQf
z@r>QdfMxGgKb^k*I^)iP7gNvue%$u5R`pe*(5EN2B^f5wO^8|7UC^BDwrfi;=ghEa
z>Sx}3_PJ;M$aYHQ+`6{!_nw}<@M_P8PbEj^AKagucK*@Z%KLZzYDd@Kv^jIe@960&
zs{;FXxBjwzXj)RrU8tJdXg`1P*&I(Uy&c{C=a*PYuYbMxs==1W5`X3foZ7ob^q*c-
z-}al173V+e&z`h*W>IZsTK@AdA}p&#4Of^(#9H$FfBH}JL*BF2`Ke{^_GJJ19Wv8I
ze98XS!r<bf>z|)5y}?s{aBJJT1KXA`K1;pCHvN6C&~@#J@85geVy@tjUt_<-XAA4j
z&#AsG<wvR~M_DB<yi}Fh>oYggXX3mwIWw2A{%GH);IDq?XiV4HqUS%$+Ll}{WPT|1
zV2(;O`-7iGMr(DR-uk8c@`UkXmx%1ox3>6L{19mMEl$*quJ1M2oO$5ufv=xBji)m|
ze>6E_o&UwYgSVeIPcl1q!kkn7bNNKmp6ETi{~dqm?unJ--jk5VnrwEueTVh^4-XZM
z&*r$Q7Hw}j)PE@Vw#HwD6*CM3ny*eZUy~?SZ24)gRcmBlbL0Lg9se_bMgO=^%DicB
z`qOFqP8f-26bU&9pE-Q|j%?(!UthkImq|uyP2^|r-2KqjY;ptRGw+%!U0$!3Mv1)C
z<o$EMh3#;ioZY+47k?FZM(+IVwzvJqjKdq#%F5K{zl~Bze#q{>Jf`BFg|51@<8twU
zTOZ=Wl-2}&suWFQ$PZL{CuVYHU##kkn_QmLAF@5to9W#ecc{qrEo-ts&7EiJ2R2T6
z_VD}{{?m81-#HT(Ww}!Ond%+aI)j4CTBnRTyoA`2F3g+JAT4cscFoF}9rcG|``nqr
z(+;tRO*k%*uwY5^*)@0CGctee);oIayzq|$|6Nn7w77g&&P}|s_d(jU^9pu5n0|7-
zJO2N0@BQYYcZasAM8DISdd+*Qh0uJS;0M(e@9!Nc`Ny*F$$7VD-o0DezBaV(+#u|A
zB-$&v)?wDxE@`#k1L<Lp^)7kM==s0k#?>?Ha@5|PGLn2hRn}wK_Mm<D9&9^sHFxU9
zCAyQnEzX~N`TmW_d+8l|?iVUnc&P7D|64JsF(b`e<!<xt?&%NMzQ%^?J8*mMy&KMa
zScP|kknv2_ugvo{&p0Ww#V}EU?Jb*ev_`!2TQ<+x%>9q|vP3_8yyV!-n{(65A}`H7
zur!nBQumMcp9i=$?PQME`L5>~{@~a%wjVk7AD;YBZG6-=`qJYAU00Y5xy+T0E$cs!
z{o{Bxdri@ag)f)Z>+ZYpb;g!ICxY(u-dwX#eWiAuOxdC7w{NPN=X?k?j*fbDPs@P)
z{Y@#2m*;nIm(QAccJ-3DRT{_FP0BmU+q(YI<ho;`J&wlG>M!+bcpjPlaC#H}NSK?C
z<(%<m&9hHFvJ}i)!hQMg{Y766oy}*O?e&ZCp7oX^XX1|Ez7z7``AS~Bqpxe`dU0i>
zsm1^JbMT6DmHxfmcX{V?S|2{MZl%gvu1`^lFOw2lmRNsCPtcB8pC6pl6F$3pl46zl
zJ?VWi@hQJz_N=`->yd2#_nNq=cP_emR54iiT>5ow!?B0CKUmgH{<xL@`SbUy1;ZKs
z_pJYFA@p8wZomHo$p-!7n?27i;eOR-AkbXaI<t3ziLm(!wuiZUHsl;%;&bIabN2^T
zeXEC$zpyd-=7p!Goqo!FHLj^XM(?0~$oY#8x~f^`M-)rh&4~S>bK~hGK8ADt-}Bm~
z1A{+44Vbpn=Gm$8%pH9HJI)?XFDhH|^KMGn!o)w9lvUT|yEkj^UNz(9^hs?G9v_}}
z=&3EE#LcFvm2CEhc;8ijFwEqCY@E4SrrE#BLU6w8K9TFECx@6_`y5nr_w42mg(c@7
z*b9B?_PgKXZ@0_lXubG+%Rj9((mSL-%-r<3@!=2tK5s3}B{OZ+R+dltpSEZDC*~TN
zC$>|U1Zt+0O<r>T!>?+A`Z77@bH2hWZgt)MxUER0K+$e?z1ctIj2Sccs>koC5wKI<
zHL-BU4%YdKH7uFD9>%j3Ugp-AeSCjw1COqf<P-Ntn_u}Kc^WI9KmBoIZE}(K2Cab3
zla-DFEZH)d$G%;5us7B=S5)J;C1a{1Q!kWPvrfZQcpul#k^}AjJ*?M^Ht$_M*F9kW
z5hHU@f9rzTou=JKKYKHVcFzv_rM-DgpuiNBm@^=$fY>y~>XdWp+XL+me|V@K@b@Z1
zla)F|4%B0Nn8XL}#Bp?SFdIVpa~euKM?n2Lj-~}21_I3xrqUq?9-1lqQ6HF`=AROK
S`yvAa1B0ilpUXO@geCwFN#}Y1

diff --git a/Jupyter_Notebooks/get_era5_forecasts.sh b/Jupyter_Notebooks/get_era5_forecasts.sh
new file mode 100644
index 00000000..f01bc770
--- /dev/null
+++ b/Jupyter_Notebooks/get_era5_forecasts.sh
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+
+yr=$1
+
+indir=/p/fastdata/slmet/slmet111/met_data/ecmwf/era5/grib/${yr}
+indir_ref=/p/project/deepacf/deeprain/video_prediction_shared_folder/results/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/savp/20210901T090059_gong1_savp_cv12/
+outdir=/p/scratch/deepacf/deeprain/video_prediction_shared_folder/era5_forecast_ref/${yr}
+
+if [[ ! -d "${outdir}" ]]; then
+    mkdir ${outdir}
+fi
+
+hh_s=6
+hh_e=12
+
+declare -a hh_list=(18)
+
+for hh in ${hh_list[@]}; do
+    hh0=$(printf "%02d" ${hh})
+
+    # slice and retrieve 2m temperature from forecast-files
+    for mm in {01..12};
+        do sf_files=(`ls ${indir}/${mm}/fc_${hh0}/*_{6..12}_sf_fc.grb`);
+            for sf_file in ${sf_files[*]};
+                do newfile=`basename "${sf_file}"`
+                newfile="${outdir}/${newfile/.grb/.nc}"
+                echo "Processing file '${newfile}'"
+                cdo --eccodes -f nc copy -selname,2t -sellonlatbox,0.,27.3,38.4,54.9 ${sf_file} ${newfile}
+            done
+        done
+
+    date1=`date -d "${yr}0101" '+%Y%m%d'`
+    date2=`date -d "${yr}0101 ${hh0}" '+%Y-%m-%d %H:%M:00'`
+    date_end=`date -d "{yr}1231 ${hh0}" '+%Y%m%d'`
+
+    while [[ "$date1" -le "$date_end" ]]; do
+	outfile=${outdir}/${date1}${hh0}_allfc.nc
+        echo "Merging forecats for run at ${date2}..."
+        cdo mergetime ${outdir}/${date1}_${hh}00_*.nc ${outfile}
+        echo "Manipulate attributes and dimensions..."
+        ncrename -O -v 2t,2t_era5_fcst ${outfile} ${outfile}
+        ncap2 -O -s init_time=0 ${outfile} ${outfile}
+        ncatted -O -a calendar,init_time,a,c,"proleptic_gregorian" -a units,init_time,a,c,"hours since ${date2}" ${outfile} ${outfile}
+        ncrename -O -d time,fcst_hour -v time,fcst_hour ${outfile} ${outfile}
+        ncap2 -O -s 'fcst_hour=int(fcst_hour)' ${outfile} ${outfile}
+	
+	# add reference data as possible
+	patt=${indir_ref}/vfp_date_${date1}${hh0}_sample_ind*.nc
+	if ls $patt 1>/dev/null 2<&1; then
+	   file_src=`ls $patt`
+	   ncks -d fcst_hour,5,11 -v 2t_ref,2t_persistence_fcst -A ${file_src} ${outfile}
+	else 
+	   echo "Could not find reference data for ${date2}..."
+	   mv ${outfile} "${oufile/.nc/_ref_miss.nc}"
+	fi
+
+        date1="$(date -u --date="$date1 tomorrow" '+%Y%m%d')"
+        date2="$(date -u --date="$date2 tomorrow" '+%Y-%m-%d %H:%M:00')"
+   done
+done
+    
diff --git a/Jupyter_Notebooks/get_era5_metrics_netcdf.ipynb b/Jupyter_Notebooks/get_era5_metrics_netcdf.ipynb
new file mode 100644
index 00000000..9a07a3a2
--- /dev/null
+++ b/Jupyter_Notebooks/get_era5_metrics_netcdf.ipynb
@@ -0,0 +1,394 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5272c6d8-2d18-4de1-a437-5fe6461ca743",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import os, sys\n",
+    "sys.path.append(\"../utils/\")\n",
+    "import xarray as xr\n",
+    "import numpy as np\n",
+    "import pandas as pd\n",
+    "\n",
+    "from statistical_evaluation import perform_block_bootstrap_metric, avg_metrics, calculate_cond_quantiles, Scores"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "61e6b683-b9c6-4691-9c1f-130324ddb7a8",
+   "metadata": {},
+   "source": [
+    "# Evaluation of the ERA5 short-range forecasts\n",
+    "\n",
+    "Define the path to the file and load the data."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "453ad6f2-5655-47bf-8f39-7a1d73b059ab",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "indir = \"/p/home/jusers/langguth1/juwels/video_prediction_shared_folder/results/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/era5_forecast\"\n",
+    "yr=2019\n",
+    "\n",
+    "era5_fcst_file = os.path.join(indir, \"{0}_era5_short_range_fcst.nc\".format(yr))\n",
+    "\n",
+    "if not os.path.isfile(era5_fcst_file):\n",
+    "    raise FileNotFoundError(\"Could not find file with all ERA5 forecasts '{0}'\".format(era5_fcst_file))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "459fa9bf-dbd0-48ee-8184-ccfec9ddbd59",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "era5_fcst = xr.open_dataset(era5_fcst_file)\n",
+    "print(era5_fcst)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "07b1324f-c6df-45c8-b77a-e334c2bb2966",
+   "metadata": {},
+   "source": [
+    "Next we initialize the function for calculating the MSE and call it to evaluate the ERA5 and persistence forecasts. <br>\n",
+    "If you require further evaluation metrics, just expand the cell accordingly, e.g. add the following lines <br>\n",
+    "```\n",
+    "ssim_func = Scores(\"ssim\", [\"lat\", \"lon\"]).score_func \n",
+    "\n",
+    "ssim_era5_all = ssim_func(data_fcst=era5_fcst[varname_fcst], data_ref=era5_fcst[varname_ref])\n",
+    "ssim_per_all = (data_fcst=era5_fcst[varname_per], data_ref=era5_fcst[varname_ref])\n",
+    "```\n",
+    "in case you want to evaluate the SSIM as well."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "e066baeb-3190-4012-a0c1-ace1100be3aa",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "fdata_clim = os.path.join(\"/p/project/deepacf/deeprain/video_prediction_shared_folder/preprocessedData/T2monthly/\", \"climatology_t2m_1991-2020.nc\")\n",
+    "\n",
+    "data = xr.open_dataset(fdata_clim)\n",
+    "\n",
+    "# copied from load_climdata in main_visualize_postprocess.py\n",
+    "var=\"var167\"\n",
+    "dt_clim = data[var]\n",
+    "\n",
+    "lon_dom = np.arange(0., 27.5, 0.3)\n",
+    "lat_dom = np.arange(54.9, 38.1, -0.3)\n",
+    "\n",
+    "# get the coordinates of the data after running CDO\n",
+    "coords = dt_clim.coords\n",
+    "nlat, nlon = len(coords[\"lat\"]), len(coords[\"lon\"])\n",
+    "# modify it our needs\n",
+    "coords_new = dict(coords)\n",
+    "coords_new.pop(\"time\")\n",
+    "coords_new[\"month\"] = np.arange(1, 13)\n",
+    "coords_new[\"hour\"] = np.arange(0, 24)\n",
+    "# initialize a new data array with explicit dimensions for month and hour\n",
+    "data_clim_new = xr.DataArray(\n",
+    "    np.full((12, 24, nlat, nlon), np.nan),\n",
+    "    coords=coords_new,\n",
+    "    dims=[\"month\", \"hour\", \"lat\", \"lon\"],\n",
+    ")\n",
+    "# do the reorganization\n",
+    "for month in np.arange(1, 13):\n",
+    "    data_clim_new.loc[dict(month=month)] = dt_clim.sel(\n",
+    "        time=dt_clim[\"time.month\"] == month\n",
+    "    )\n",
+    "\n",
+    "data_clim = data_clim_new.sel(lon=lons, lat=lats, tolerance=0.01, method=\"nearest\")\n",
+    "print(data_clim[\"lat\"])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "0dd70ea1-9341-4b7a-9086-405ee75c6a64",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from tqdm import tqdm\n",
+    "from skimage.metrics import structural_similarity as ssim\n",
+    "\n",
+    "# overwrite some score-functions which inherently expect a separate fcst_hour-dimension next to batch_size \n",
+    "\n",
+    "def calc_acc_batch(data_fcst, data_ref,  **kwargs):\n",
+    "    \"\"\"\n",
+    "    Calculate acc ealuation metric of forecast data w.r.t reference data\n",
+    "    :param data_fcst: forecasted data (xarray with dimensions [batch, fore_hours, lat, lon])\n",
+    "    :param data_ref: reference data (xarray with dimensions [batch, fore_hours, lat, lon])\n",
+    "    :param data_clim: climatology data (xarray with dimensions [monthly, hourly, lat, lon])\n",
+    "    :return: averaged acc for each batch example [batch, fore_hours]\n",
+    "    \"\"\"\n",
+    "    \n",
+    "    print(\"Start calculating ACC\")\n",
+    "    if \"data_clim\" in kwargs:\n",
+    "        data_clim = kwargs[\"data_clim\"]\n",
+    "    else:\n",
+    "        raise KeyError(\"%{0}: climatological data must be parsed to calculate the ACC.\".format(method))        \n",
+    "\n",
+    "    batch_size = data_fcst.shape[0]\n",
+    "    acc = np.ones([batch_size])*np.nan\n",
+    "    for i in tqdm(range(batch_size)):\n",
+    "        img_fcst = data_fcst[i, ...]\n",
+    "        img_ref = data_ref[i, ...]\n",
+    "        # get the forecast time\n",
+    "        img_month = img_fcst[\"fcst_hour\"].dt.month.values\n",
+    "        img_hour = img_fcst[\"fcst_hour\"].dt.hour.values\n",
+    "        img_clim = data_clim.sel(month=img_month, hour=img_hour)               \n",
+    "\n",
+    "        img1_ = img_ref - img_clim\n",
+    "        img2_ = img_fcst - img_clim\n",
+    "        cor1 = np.sum(img1_*img2_)\n",
+    "        cor2 = np.sqrt(np.sum(img1_**2)*np.sum(img2_**2))\n",
+    "        acc[i] = cor1/cor2\n",
+    "        \n",
+    "    # convert to data array \n",
+    "    acc = xr.DataArray(acc, coords={\"fcst_hour\": data_fcst[\"fcst_hour\"]}, dims=[\"fcst_hour\"])\n",
+    "    return acc\n",
+    "\n",
+    "def calc_ssim_batch(data_fcst, data_ref, **kwargs):\n",
+    "    \"\"\"\n",
+    "    Calculate ssim ealuation metric of forecast data w.r.t reference data\n",
+    "    :param data_fcst: forecasted data (xarray with dimensions [batch, fore_hours, lat, lon])\n",
+    "    :param data_ref: reference data (xarray with dimensions [batch, fore_hours, lat, lon])\n",
+    "    :return: averaged ssim for each batch example, shape is [batch,fore_hours]\n",
+    "    \"\"\"\n",
+    "    method = Scores.calc_ssim_batch.__name__\n",
+    "    batch_size = np.array(data_ref).shape[0]\n",
+    "    ssim_pred = []\n",
+    "    for i in tqdm(range(batch_size)):\n",
+    "        ssim_pred.append(ssim(data_ref[i, ...],data_fcst[i,...]))\n",
+    "        \n",
+    "    # convert to data array \n",
+    "    ssim_pred = xr.DataArray(np.asarray(ssim_pred), coords={\"fcst_hour\": data_fcst[\"fcst_hour\"]}, dims=[\"fcst_hour\"])    \n",
+    "    return ssim_pred"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "e76c4db9-f4da-4664-8054-fdd99cf5f64b",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# to get and configure the score-functions\n",
+    "score_dims = [\"lat\", \"lon\"]\n",
+    "scores = [\"mse\", \"ssim\", \"acc\", \"texture\"]\n",
+    "# the reference data\n",
+    "varname_ref, varname_fcst, varname_per = \"2t_ref\", \"2t_era5_fcst\", \"2t_persistence_fcst\"\n",
+    "\n",
+    "# initialize empty dictionaries to store the score functions and to save the corresponding results\n",
+    "score_data = {}\n",
+    "for score in scores:\n",
+    "    # overwrite functions that are incompatble here\n",
+    "    if score == \"acc\":\n",
+    "        score_func = calc_acc_batch\n",
+    "    elif score == \"ssim\":\n",
+    "        score_func = calc_ssim_batch\n",
+    "    else:\n",
+    "        score_func = Scores(score, score_dims).score_func\n",
+    "    # parsing the persistence forecast as float32 increases throughput by a factor of 10!\n",
+    "    score_data[score] = {\"era5_all\": score_func(data_fcst=era5_fcst[varname_fcst], data_ref=era5_fcst[varname_ref], data_clim=data_clim,),\n",
+    "                         \"per_all\": score_func(data_fcst=era5_fcst[varname_per].astype(\"float32\"), data_ref=era5_fcst[varname_ref], data_clim=data_clim)}   "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "c612a06f-e193-4d4a-85a4-1adc11fde81e",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "print(score_data[\"mse\"][\"era5_all\"])\n",
+    "print(score_data[\"ssim\"][\"era5_all\"])\n",
+    "print(score_data[\"texture\"][\"era5_all\"])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "b91695dc-7d3f-47de-8e67-03e5675aeac1",
+   "metadata": {},
+   "source": [
+    "Next, we initialize the data arrays to store the metrics for each forecast hour. <br>\n",
+    "Note that the ERA5 short-range forecasts only start twice a day at 06 and 18 UTC, respectively. Besides, the have only data starting from lead time 6 hours, but for consistency with the video prediction models, the data arrays cover all lead times between forecast hour 1 and 12. The unavailable values will be set to None."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "95611d9c-7551-466d-84b6-ca24be2d3977",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "init_times = [6, 18]\n",
+    "fcst_hours = np.arange(1, 13)\n",
+    "nhours = len(fcst_hours)\n",
+    "nboots=1000\n",
+    "\n",
+    "# MSE\n",
+    "mse_era5_fcst = xr.DataArray(np.empty(nhours, dtype=object), coords={\"fcst_hour\": fcst_hours}, dims=[\"fcst_hour\"])\n",
+    "mse_era5_fcst_boot = xr.DataArray(np.empty((nhours, nboots), dtype=object),\n",
+    "                                  coords={\"fcst_hour\": fcst_hours, \"iboot\": np.arange(nboots)},\n",
+    "                                  dims=[\"fcst_hour\", \"iboot\"])\n",
+    "\n",
+    "mse_per_fcst = xr.DataArray(np.empty(nhours, dtype=object), coords={\"fcst_hour\": fcst_hours}, dims=[\"fcst_hour\"])\n",
+    "mse_per_fcst_boot = xr.DataArray(np.empty((nhours, nboots), dtype=object),\n",
+    "                                 coords={\"fcst_hour\": fcst_hours, \"iboot\": np.arange(nboots)},\n",
+    "                                 dims=[\"fcst_hour\", \"iboot\"])\n",
+    "\n",
+    "# SSMI\n",
+    "ssim_era5_fcst, ssim_per_fcst = mse_era5_fcst.copy(), mse_per_fcst.copy()\n",
+    "ssim_era5_fcst_boot, ssim_per_fcst_boot = mse_per_fcst_boot.copy(), mse_per_fcst_boot.copy()\n",
+    "\n",
+    "# ACC\n",
+    "acc_era5_fcst, acc_per_fcst = mse_era5_fcst.copy(), mse_per_fcst.copy()\n",
+    "acc_era5_fcst_boot, acc_per_fcst_boot = mse_per_fcst_boot.copy(), mse_per_fcst_boot.copy()\n",
+    "\n",
+    "# ACC\n",
+    "txtr_era5_fcst, txtr_per_fcst = mse_era5_fcst.copy(), mse_per_fcst.copy()\n",
+    "txtr_era5_fcst_boot, txtr_per_fcst_boot = mse_per_fcst_boot.copy(), mse_per_fcst_boot.copy()\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e5700456-043b-4656-8ac4-759f42fc03c4",
+   "metadata": {},
+   "source": [
+    "Finally, we populate the initialized data arrays by looping over the forecast hours for which data is available. <br>\n",
+    "Additionally, we perform block bootstrapping to estimate the uncertainty of our evaluation metrics."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f3ea77c8-60c1-48bd-8285-95d6af66217a",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def handle_scores(scores1_all, scores_ref_all, fhh):\n",
+    "    \n",
+    "    scores1 = scores1_all.sel(fcst_hour=(scores1_all.fcst_hour.dt.hour.isin(fhh)))\n",
+    "    scores_ref = scores_ref_all.sel(fcst_hour=(scores_ref_all.fcst_hour.dt.hour.isin(fhh)))\n",
+    "    score1_mean, score_ref_mean = scores1.mean(), scores_ref.mean()\n",
+    "    # two runs per day -> 2*7 correpsonds to a block length of one week\n",
+    "    score1_boot = perform_block_bootstrap_metric(scores1, \"fcst_hour\", 2*7)\n",
+    "    score_ref_boot = perform_block_bootstrap_metric(scores_ref, \"fcst_hour\", 2*7)\n",
+    "    \n",
+    "    return score1_mean, score_ref_mean, score1_boot, score_ref_boot\n",
+    "    \n",
+    "\n",
+    "for fh in fcst_hours[5::]:\n",
+    "    print(\"Handling scores for forecast hour '{0:0d}'\".format(fh))\n",
+    "    fh_curr = (init_times + fh)%24\n",
+    "    # MSE\n",
+    "    mse_era5_fcst[fh-1], mse_per_fcst[fh-1], mse_era5_fcst_boot[fh-1, :], mse_per_fcst_boot[fh-1, :] = handle_scores(score_data[\"mse\"][\"era5_all\"],\n",
+    "                                                                                                                     score_data[\"mse\"][\"per_all\"], fh_curr)\n",
+    "    # SSIM\n",
+    "    ssim_era5_fcst[fh-1], ssim_per_fcst[fh-1], ssim_era5_fcst_boot[fh-1, :], ssim_per_fcst_boot[fh-1, :] = handle_scores(score_data[\"ssim\"][\"era5_all\"],\n",
+    "                                                                                                                         score_data[\"ssim\"][\"per_all\"], fh_curr)\n",
+    "    # ACC\n",
+    "    acc_era5_fcst[fh-1], acc_per_fcst[fh-1], acc_era5_fcst_boot[fh-1, :], acc_per_fcst_boot[fh-1, :] = handle_scores(score_data[\"acc\"][\"era5_all\"],\n",
+    "                                                                                                                     score_data[\"acc\"][\"per_all\"], fh_curr)  \n",
+    "    # TEXTURE\n",
+    "    txtr_era5_fcst[fh-1], txtr_per_fcst[fh-1], txtr_era5_fcst_boot[fh-1, :], txtr_per_fcst_boot[fh-1, :] = handle_scores(score_data[\"texture\"][\"era5_all\"],\n",
+    "                                                                                                                         score_data[\"texture\"][\"per_all\"], fh_curr)\n",
+    "    \n",
+    "    #mse_era5_curr = mse_era5_all.sel(fcst_hour=(mse_era5_all.fcst_hour.dt.hour.isin(fh_curr)))\n",
+    "    #mse_per_curr = mse_per_all.sel(fcst_hour=(mse_per_all.fcst_hour.dt.hour.isin(fh_curr)))\n",
+    "    #mse_era5_fcst[fh-1], mse_per_fcst[fh-1] = mse_era5_curr.mean(), mse_per_curr.mean()\n",
+    "    ## two runs per day -> 2*7 correpsonds to a block length of one week\n",
+    "    #mse_era5_fcst_boot[fh-1, :] = perform_block_bootstrap_metric(mse_era5_curr, \"fcst_hour\", 2*7)\n",
+    "    #mse_per_fcst_boot[fh-1, :] = perform_block_bootstrap_metric(mse_per_curr, \"fcst_hour\", 2*7)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5ec002e6-cb1b-4c66-9ed0-9f5e2bd3fae9",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "print(mse_era5_fcst)\n",
+    "print(ssim_era5_fcst)\n",
+    "print(acc_era5_fcst)\n",
+    "print(txtr_era5_fcst)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "276f4f4c-e926-4009-9198-c4e43271e87d",
+   "metadata": {},
+   "source": [
+    "Finally, we put the data arrays into a joint dataset and save the results into the netCDF-file."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "88ccbdce-5d6a-4c40-971c-ebe9a05a8c88",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# create Dataset and save to netCDF-file\n",
+    "ds_mse = xr.Dataset({\"2t_era5_mse_avg\": mse_era5_fcst, \"2t_era5_mse_bootstrapped\": mse_era5_fcst_boot, \n",
+    "                     \"2t_persistence_mse_avg\": mse_per_fcst, \"2t_persistence_mse_bootstrapped\": mse_per_fcst_boot,\n",
+    "                    # SSIM\n",
+    "                    \"2t_era5_ssim_avg\": ssim_era5_fcst, \"2t_era5_mse_bootstrapped\": ssim_era5_fcst_boot, \n",
+    "                    \"2t_persistence_ssim_avg\": ssim_per_fcst, \"2t_persistence_mse_bootstrapped\": ssim_per_fcst_boot,\n",
+    "                    # ACC\n",
+    "                    \"2t_era5_acc_avg\": acc_era5_fcst, \"2t_era5_acc_bootstrapped\": acc_era5_fcst_boot, \n",
+    "                    \"2t_persistence_acc_avg\": acc_per_fcst, \"2t_persistence_acc_bootstrapped\": acc_per_fcst_boot,\n",
+    "                    # TEXTURE \n",
+    "                    \"2t_era5_texture_avg\": txtr_era5_fcst, \"2t_era5_texture_bootstrapped\": txtr_era5_fcst_boot, \n",
+    "                    \"2t_persistence_texture_avg\": txtr_per_fcst, \"2t_persistence_texture_bootstrapped\": txtr_per_fcst_boot,                     \n",
+    "                    })\n",
+    "\n",
+    "outfile = os.path.join(indir, \"evaluation_metrics.nc\")\n",
+    "\n",
+    "print(\"Save evaluation metrics to '{0}'\".format(outfile))\n",
+    "ds_mse.to_netcdf(outfile)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "a7678cc4-7333-402a-bcf4-1bc15712255d",
+   "metadata": {},
+   "source": [
+    "## DONE!"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "PyDeepLearning-1.1",
+   "language": "python",
+   "name": "pydeeplearning"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.8.5"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/Jupyter_Notebooks/get_metrics_joint_dom.ipynb b/Jupyter_Notebooks/get_metrics_joint_dom.ipynb
new file mode 100644
index 00000000..e54043e1
--- /dev/null
+++ b/Jupyter_Notebooks/get_metrics_joint_dom.ipynb
@@ -0,0 +1,338 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "d636ee12-e299-485f-b84d-6f35c05fa766",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import os, sys\n",
+    "import glob\n",
+    "sys.path.append(\"../utils/\")\n",
+    "import xarray as xr\n",
+    "import numpy as np\n",
+    "import pandas as pd\n",
+    "\n",
+    "from statistical_evaluation import perform_block_bootstrap_metric, avg_metrics, calculate_cond_quantiles, Scores"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "8510684d-9374-4e40-bc1c-4d69181c925c",
+   "metadata": {},
+   "source": [
+    "# Evaluation over a smaller (joint) domain\n",
+    "\n",
+    "The following cells will first merge all forecast files under `indir` into a single netCDF-file.<br>\n",
+    "Then the data is sliced to the domain defined by `lonlatbox` and all subsequent evaluation is performed on this smaller domain.<br>\n",
+    "The evaluation metrics are then saved to a file under `indir` named `evaluation_metrics_<nlon>x<nlat>.nc` where `nlat` and `nlon` denote the number of grid points/pixels in latitude and longitude direction of the smaller domain, respectively. <br>\n",
+    "\n",
+    "Thus, first let's define the basic parameters:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "440b15fa-ecd4-4bb4-9100-ede5abb2b04f",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "indir = \"/p/project/deepacf/deeprain/video_prediction_shared_folder/results/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/savp/20210901T090059_gong1_savp_cv12/\"\n",
+    "model = \"savp\"\n",
+    "# define domain. [3., 24.3, 40.2, 53.1] corresponds to the smallest domain tested in the GMD paper\n",
+    "lonlatbox = [3., 24.3, 40.2, 53.1]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "fd759f01-2561-4615-8056-036bdee6e2c7",
+   "metadata": {},
+   "source": [
+    "Next, we perform a first merging step. For computational efficiency, we merge max. 1000 files in the first step.<br>\n",
+    "Since the data is not sorted by the dimension `init_time` when querying along the sample index, we sort it before saving to intermediate files.<br>\n",
+    "\n",
+    "Given that the merging step has already been performed, no further processing is required.<br>\n",
+    "If this is not the case, we start with the sample indices between 0 and 999:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "e6726da3-d774-4eda-89d6-e315a865bb99",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def get_fname_ndigits(indir, prefix, suffix, n, patt=\"[0-9]\"):\n",
+    "    flist = []\n",
+    "    for i in range(1, n+1):\n",
+    "        fn_search = os.path.join(indir, \"{0}{1}{2}\".format(prefix, i*patt, suffix))\n",
+    "        flist = flist + glob.glob(fn_search)\n",
+    "    \n",
+    "    if len(flist) == 0:\n",
+    "        raise FileNotFoundError(\"Could not find any file under '{0}' with prefix '{1}' and suffix '{2}' containing digits.\".format(indir, prefix, suffix))\n",
+    "    return flist\n",
+    "\n",
+    "# get list of files with sample index between 0 and 999.\n",
+    "vfp_list = get_fname_ndigits(indir, \"vfp_date_*sample_ind_\", \".nc\", 3)\n",
+    "outfile = os.path.join(indir, \"vfp_{0}_forecasts_sample_ind_0_999.nc\".format(model))\n",
+    "\n",
+    "if not os.path.isfile(outfile):\n",
+    "    print(\"File '{0}' does not exist. \\n Start reading data with sample index between 0 and 999 from '{1}'...\".format(outfile, indir))\n",
+    "    data_all = xr.open_mfdataset(vfp_list, concat_dim=\"init_time\", combine=\"nested\", decode_cf=True).load()\n",
+    "    data_all = data_all.sortby(\"init_time\")\n",
+    "    print(\"Data loaded successfully. Save merged data to '{0}'.\".format(outfile))\n",
+    "    data_all.to_netcdf(outfile, encoding={'init_time':{'units': \"seconds since 1900-01-01 00:00:00\"}})"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "1c0222c0-386d-44f4-9532-4e824b14828c",
+   "metadata": {},
+   "source": [
+    "Then, we proceed with the rest. "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "54f4aa3e-3a39-496e-ae97-65f79d9cd598",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "for i in np.arange(1, 9):\n",
+    "    outfile = os.path.join(indir, \"vfp_{0}_forecasts_sample_ind_{1:d}000_{1:d}999.nc\".format(model, i))\n",
+    "    if not os.path.isfile(outfile):\n",
+    "        print(\"File '{0}' does not exist. Start reading data with sample index between {1:d}000 and {1:d}999 from '{2}'...\".format(outfile, i, indir))\n",
+    "        data_all = xr.open_mfdataset(os.path.join(indir, \"vfp_date_*sample_ind_{0}???.nc\".format(i)), concat_dim=\"init_time\", combine=\"nested\", decode_cf=True).load()\n",
+    "        data_all = data_all.sortby(\"init_time\")\n",
+    "        print(\"Data loaded successfully. Save merged data to '{0}'.\".format(outfile))\n",
+    "        data_all.to_netcdf(outfile, encoding={'init_time':{'units': \"seconds since 1900-01-01 00:00:00\"}})"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "bdf16158-0ce5-40a3-848d-f574a1b9d622",
+   "metadata": {},
+   "source": [
+    "Still, xarray's `open_mfdataset`-method would not be able to concatenate all data since the `init_time`-dimension is not montonically increasing/decreasing when looping through the files. <br>\n",
+    "Thus, we have to merge the data manually.\n",
+    "The merged dataset is then saved to separate datafile for later computation.\n",
+    "\n",
+    "If the data has already been merged, we simply read the data from the corresponding netCDF-file."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "92f15edf-c23f-4803-b3c5-618305194de5",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "outfile_all = os.path.join(indir, \"vfp_{0}_forecasts_all.nc\".format(model))\n",
+    "\n",
+    "if not os.path.isfile(outfile_all):\n",
+    "    \n",
+    "    print(\"netCDF-file with all forecasts '{0}' does not exist yet. Start merging and sorting all precursor files.\".format(outfile))\n",
+    "    all_files = sorted(glob.glob(os.path.join(indir, \"vfp_{0}_forecasts_sample_ind_*.nc\".format(model))))\n",
+    "    \n",
+    "    if len(all_files) == 0:\n",
+    "        raise FileNotFoundError(\"Could not find any precursor files.\")\n",
+    "\n",
+    "    for i, f in enumerate(all_files):\n",
+    "        print(\"Processing file '{0}'\".format(f))\n",
+    "        tmp = xr.open_dataset(os.path.join(indir, f)).load()\n",
+    "        if i == 0:\n",
+    "            all_fcst = tmp.copy()\n",
+    "        else:\n",
+    "            print(\"Start merging\")\n",
+    "            all_fcst = xr.merge([all_fcst, tmp])   \n",
+    "\n",
+    "    # sort by init_time-dimension...\n",
+    "    all_fcst = all_fcst.sortby(\"init_time\")\n",
+    "    # ... and save to file\n",
+    "    print(\"Finally, write all merged and sorted data to '{0}'.\".format(outfile_all))\n",
+    "    all_fcst.to_netcdf(outfile_all)\n",
+    "else:\n",
+    "    all_fcst = xr.open_dataset(outfile_all).load()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "0fcf1cb1-ba0d-4262-8e23-12ba44b6e2d0",
+   "metadata": {},
+   "source": [
+    "Now, we slice the dataset to the domain of interest (defined by `lonlatbox`)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "ede23e56-5be8-48be-b584-0eb8741acbf3",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "all_fcst_sl = all_fcst.sel({\"lon\": slice(lonlatbox[0], lonlatbox[1]), \"lat\": slice(lonlatbox[3], lonlatbox[2])}) \n",
+    "print(all_fcst_sl)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e21b89c8-57ab-4070-9b4c-ec0fe24c37b9",
+   "metadata": {},
+   "source": [
+    "Next we initialize the function for calculating the MSE and call it to evaluate the ERA5 and persistence forecasts. <br>\n",
+    "If you require further evaluation metrics, just expand the cell accordingly, e.g. add the following lines <br>\n",
+    "```\n",
+    "ssim_func = Scores(\"ssim\", [\"lat\", \"lon\"]).score_func \n",
+    "\n",
+    "ssim_era5_all = ssim_func(data_fcst=era5_fcst[varname_fcst], data_ref=era5_fcst[varname_ref])\n",
+    "ssim_per_all = (data_fcst=era5_fcst[varname_per], data_ref=era5_fcst[varname_ref])\n",
+    "```\n",
+    "in case you want to evaluate the SSIM as well."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "c2b70b80-6b86-4674-b051-6a23aaa821ea",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "mse_func = Scores(\"mse\", [\"lat\", \"lon\"]).score_func\n",
+    "varname_ref, varname_fcst, varname_per = \"2t_ref\", \"2t_{0}_fcst\".format(model), \"2t_persistence_fcst\"\n",
+    "\n",
+    "mse_model_all = mse_func(data_fcst=all_fcst_sl[varname_fcst], data_ref=all_fcst_sl[varname_ref])\n",
+    "mse_per_all = mse_func(data_fcst=all_fcst_sl[varname_per], data_ref=all_fcst_sl[varname_ref])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "7745356d-ad44-47b6-9655-8d6db3433b1a",
+   "metadata": {},
+   "source": [
+    "Then, we initialize the data arrays to store the desired evaluation metrics..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b49db031-126c-44b1-b649-4f70587fac89",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "fcst_hours = all_fcst_sl[\"fcst_hour\"]\n",
+    "nhours = len(fcst_hours)\n",
+    "nboots=1000\n",
+    "\n",
+    "mse_model_fcst = xr.DataArray(np.empty(nhours, dtype=object), coords={\"fcst_hour\": fcst_hours}, dims=[\"fcst_hour\"])\n",
+    "mse_model_fcst_boot = xr.DataArray(np.empty((nhours, nboots), dtype=object),\n",
+    "                                  coords={\"fcst_hour\": fcst_hours, \"iboot\": np.arange(nboots)},\n",
+    "                                  dims=[\"fcst_hour\", \"iboot\"])\n",
+    "mse_per_fcst = xr.DataArray(np.empty(nhours, dtype=object), coords={\"fcst_hour\": fcst_hours}, dims=[\"fcst_hour\"])\n",
+    "mse_per_fcst_boot = xr.DataArray(np.empty((nhours, nboots), dtype=object),\n",
+    "                                 coords={\"fcst_hour\": fcst_hours, \"iboot\": np.arange(nboots)},\n",
+    "                                 dims=[\"fcst_hour\", \"iboot\"])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "55967405-02d1-46e8-b3c3-8952d0e28bd2",
+   "metadata": {},
+   "source": [
+    "... and populate them by looping over all forecast hours."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5090e71c-f20f-43e6-94f6-71cbd0b6006d",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "for i, fh in enumerate(fcst_hours):\n",
+    "    mse_model_curr = mse_model_all.sel(fcst_hour=fh)\n",
+    "    mse_per_curr = mse_per_all.sel(fcst_hour=fh)\n",
+    "    mse_model_fcst[fh-1], mse_per_fcst[fh-1] = mse_model_curr.mean(), mse_per_curr.mean()\n",
+    "\n",
+    "    mse_model_fcst_boot[i, :] = perform_block_bootstrap_metric(mse_model_curr, \"init_time\", 24*7)\n",
+    "    mse_per_fcst_boot[i, :] = perform_block_bootstrap_metric(mse_per_curr, \"init_time\", 24*7)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "d526324d-5d19-4193-8208-e609d9c65205",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "print(mse_model_fcst)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b42cd738-b966-4b24-ad13-351d9b88f9e8",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "print(mse_model_fcst)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "b13c7287-7a8c-4133-bccc-f250bf25dad7",
+   "metadata": {},
+   "source": [
+    "Finally, we put the data arrays into a joint dataset and save the results into the netCDF-file."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "7cd455ee-4749-46dd-8095-9e43744a1563",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# create Dataset and save to netCDF-file\n",
+    "ds_mse = xr.Dataset({\"2t_{0}_mse_avg\".format(model): mse_model_fcst, \"2t_{0}_mse_bootstrapped\".format(model): mse_model_fcst_boot, \n",
+    "                     \"2t_persistence_mse_avg\": mse_per_fcst, \"2t_persistence_mse_bootstrapped\": mse_per_fcst_boot})\n",
+    "\n",
+    "outfile = os.path.join(indir, \"evaluation_metrics_{0:d}x{1:d}.nc\".format(len(all_fcst_sl[\"lon\"]), len(all_fcst_sl[\"lat\"])))\n",
+    "\n",
+    "print(\"Save evaluation metrics to '{0}'\".format(outfile))\n",
+    "print(ds_mse)\n",
+    "ds_mse.to_netcdf(outfile)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "69bb9464-6fdb-489b-ba59-0170040144ee",
+   "metadata": {},
+   "source": [
+    "## Done!"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "PyDeepLearning-1.1",
+   "language": "python",
+   "name": "pydeeplearning"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.8.5"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/Jupyter_Notebooks/juwels_juwelsbooster_compare_old.ipynb b/Jupyter_Notebooks/juwels_juwelsbooster_compare_old.ipynb
deleted file mode 100644
index d788742d..00000000
--- a/Jupyter_Notebooks/juwels_juwelsbooster_compare_old.ipynb
+++ /dev/null
@@ -1,684 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "code",
-   "execution_count": 16,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import os, glob\n",
-    "import math\n",
-    "import pickle\n",
-    "import numpy as np\n",
-    "import xarray as xr\n",
-    "import matplotlib\n",
-    "matplotlib.use('Agg')\n",
-    "from matplotlib.transforms import Affine2D\n",
-    "from matplotlib.patches import Polygon\n",
-    "import matplotlib.pyplot as plt\n",
-    "%matplotlib inline\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 2,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "base = \"/p/project/deepacf/deeprain/video_prediction_shared_folder/models/\"+ \\\n",
-    "       \"era5-Y2010toY2222M01to12-160x128-2970N1500W-T2_MSL_gph500/convLSTM/\"\n",
-    "fname_timing_train = \"/timing_training_time.pkl\"\n",
-    "fname_timing_total = \"/timing_total_time.pkl\"\n",
-    "\n",
-    "fname_timing_iter = \"timing_per_iteration_time.pkl\""
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 3,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# some auxiliary functions\n",
-    "def orderOfMagnitude(number):\n",
-    "    return np.floor(np.log(number, 10))\n",
-    "\n",
-    "def total_times(infile):\n",
-    "    with open(infile,'rb') as tfile:\n",
-    "        #print(\"Opening pickle time: '{0}'\".format(infile))\n",
-    "        total_time_sec = pickle.load(tfile)\n",
-    "    return np.asarray(total_time_sec/60)\n",
-    "\n",
-    "def log_total_times(infile):\n",
-    "    total_time_min = total_times(infile)\n",
-    "    return np.log(total_time_min)\n",
-    "\n",
-    "\n",
-    "def get_time_dict(base, wildcardspec, tfilename, gpu_id_str=\"gpu\", llog = False):\n",
-    "    time_dict = {}\n",
-    "    flist_hpc = sorted(glob.glob(base + wildcardspec))\n",
-    "    wrapper = total_times\n",
-    "    if llog: wrapper = log_total_times\n",
-    "    for tfile in flist_hpc: \n",
-    "        ngpus = get_ngpus(tfile, gpu_id_str)\n",
-    "        time_dict[\"{0:d} GPU(s)\".format(ngpus)] = wrapper(tfile + tfilename)\n",
-    "    return time_dict\n",
-    "\n",
-    "def get_ngpus(fname, search_str, max_order=3):\n",
-    "    \"\"\"\n",
-    "    Tries to get numbers in the vicinty of search_str which is supposed to be a substring in fname.\n",
-    "    First seaches for numbers right before the occurence of search_str, then afterwards.\n",
-    "    :param fname: file name from which number should be inferred\n",
-    "    :param search_str: seach string for which number identification is considered to be possible\n",
-    "    :param max_order: maximum order of retrieved number (default: 3 -> maximum number is 999 then)\n",
-    "    :return num_int: integer of number in the vicintity of search string. \n",
-    "    \"\"\"\n",
-    "    \n",
-    "    ind_gpu_info = fname.lower().find(search_str)\n",
-    "    if ind_gpu_info == -1:\n",
-    "        raise ValueError(\"Unable to find search string '{0}' in file name '{1}'\".format(search_str, fname))\n",
-    "    \n",
-    "    # init loops\n",
-    "    fname_len = len(fname)\n",
-    "    success, flag = False, True\n",
-    "    indm = 1\n",
-    "    ind_sm, ind_sp = 0, 0\n",
-    "\n",
-    "    # check occurence of numbers in front of search string\n",
-    "    while indm < max_order and flag:\n",
-    "        if ind_gpu_info - indm > 0:\n",
-    "            if fname[ind_gpu_info - indm].isnumeric():\n",
-    "                ind_sm += 1\n",
-    "                success = True\n",
-    "            else:\n",
-    "                flag = False\n",
-    "        else:\n",
-    "            flag = False\n",
-    "        indm += 1\n",
-    "  \n",
-    "\n",
-    "    if not success: # check occurence of numbers after search string\n",
-    "        ind_gpu_info = ind_gpu_info + len(search_str)\n",
-    "        flag = True\n",
-    "        indm = 0\n",
-    "        while indm < max_order and flag: \n",
-    "            if ind_gpu_info + indm < fname_len:\n",
-    "                if fname[ind_gpu_info + indm].isnumeric():\n",
-    "                    ind_sp += 1\n",
-    "                    success = True\n",
-    "                else:\n",
-    "                    flag = False\n",
-    "            else:\n",
-    "                flag = False\n",
-    "            indm += 1\n",
-    "            \n",
-    "        if success:\n",
-    "            return(int(fname[ind_gpu_info:ind_gpu_info+ind_sp]))\n",
-    "        else:\n",
-    "            raise ValueError(\"Search string found in fname, but unable to infer number of GPUs.\")\n",
-    "\n",
-    "    else:\n",
-    "        return(int(fname[ind_gpu_info-ind_sm:ind_gpu_info]))\n",
-    "        \n",
-    "        \n",
-    "    "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 4,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Total computation with 16 GPU(s): 152.50984706878663\n",
-      "Total computation with 32 GPU(s): 81.80640578667322\n",
-      "Total computation with 4 GPU(s): 554.5182513117791\n",
-      "Total computation with 64 GPU(s): 45.01537701288859\n",
-      "Total computation with 8 GPU(s): 287.91878341039023\n"
-     ]
-    }
-   ],
-   "source": [
-    "# Juwels\n",
-    "wildcard_juwels = '20210115T135325_langguth1_test_venv_juwels_container*old'\n",
-    "total_time_min_juwels = get_time_dict(base, wildcard_juwels, fname_timing_total, \"gpus\")\n",
-    "training_time_min_juwels = get_time_dict(base, wildcard_juwels, fname_timing_train, \"gpus\")\n",
-    "for key in training_time_min_juwels.keys():\n",
-    "    print(\"Total computation with {0}: {1}\".format(key, training_time_min_juwels[key]))\n",
-    "\n",
-    "overhead_time_juwels = {}\n",
-    "for key in training_time_min_juwels.keys() & total_time_min_juwels.keys():\n",
-    "    overhead_time_juwels[key] = total_time_min_juwels[key] - training_time_min_juwels[key]\n",
-    "    \n",
-    "#print('Juwels total time in minutes', get_time_d)\n",
-    "#print('Juwels total training time in minutes', training_time_min_juwels)\n",
-    "#overhead_time_juwels = np.array(total_time_min_juwels) - np.array(training_time_min_juwels)\n",
-    "#print('Juwels overhead time in minutes', overhead_time_juwels)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 5,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Total computation with 1 GPU(s): 566.7376739541689\n",
-      "Total computation with 4 GPU(s): 159.4931242307027\n",
-      "Total computation with 8 GPU(s): 92.15467914342881\n",
-      "Total computation with 16 GPU(s): 46.11619712909063\n",
-      "Total computation with 32 GPU(s): 33.09077355464299\n",
-      "Total computation with 64 GPU(s): 23.24405464331309\n"
-     ]
-    }
-   ],
-   "source": [
-    "# Juwels booster\n",
-    "wildcard_booster = '2020*gong1_booster_gpu*'\n",
-    "total_time_min_booster = get_time_dict(base, wildcard_booster, fname_timing_total)\n",
-    "training_time_min_booster = get_time_dict(base, wildcard_booster, fname_timing_train)\n",
-    "for key in training_time_min_booster.keys():\n",
-    "    print(\"Total computation with {0}: {1}\".format(key, training_time_min_booster[key]))\n",
-    "\n",
-    "#print('Juwels Booster total time in minutes', list_times(base, wildcard_booster, filename_timing_total))\n",
-    "#print('Juwels Booster total training time in minutes', list_times(base, wildcard_booster, filename_timing_train))\n",
-    "overhead_time_booster = {}\n",
-    "for key in training_time_min_booster.keys() & total_time_min_booster.keys():\n",
-    "    overhead_time_booster[key] = total_time_min_booster[key] - training_time_min_booster[key]\n",
-    "#print('Juwels overhead time in minutes', overhead_time_booster)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 6,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "def time_per_iteration_mean_std(infile):\n",
-    "    with open(infile, 'rb') as tfile:\n",
-    "        time_per_iteration_list = pickle.load(tfile) \n",
-    "        \n",
-    "    time_per_iteration = np.array(time_per_iteration_list)\n",
-    "    return np.mean(time_per_iteration), np.std(time_per_iteration)\n",
-    "\n",
-    "def iter_stat(base, wildcardspec, gpu_id_str=\"gpu\"):\n",
-    "    stat_iter_dict = {}\n",
-    "    flist_hpc = sorted(glob.glob(base + wildcardspec))\n",
-    "    for tdir in flist_hpc: \n",
-    "        ngpus = get_ngpus(tdir, gpu_id_str)\n",
-    "        ftname = os.path.join(tdir, fname_timing_iter)\n",
-    "        mean_loc, std_loc = time_per_iteration_mean_std(ftname)\n",
-    "        stat_iter_dict[\"{0:d} GPU(s)\".format(ngpus)] = {\"mean\": mean_loc , \"std\": std_loc}\n",
-    "    return stat_iter_dict\n",
-    "\n",
-    "def time_per_iteration_all(infile):\n",
-    "    with open(infile,'rb') as tfile:\n",
-    "        time_per_iteration_list = pickle.load(tfile)\n",
-    "    return np.asarray(time_per_iteration_list)\n",
-    "\n",
-    "def all_iter(base, wildcardspec, gpu_id_str=\"gpu\"):\n",
-    "    iter_dict = {}\n",
-    "    flist_hpc = sorted(glob.glob(base + wildcardspec))\n",
-    "    for tdir in flist_hpc: \n",
-    "        ngpus = get_ngpus(tdir, gpu_id_str)\n",
-    "        ftname = os.path.join(tdir, fname_timing_iter)\n",
-    "        iter_dict[\"{0:d} GPU(s)\".format(ngpus)] = time_per_iteration_all(ftname)\n",
-    "    return iter_dict    \n",
-    "    "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 30,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "JUWELS (0.6151515198034729, 0.20104178037750603)\n",
-      "Booster (0.3521572324468615, 0.3656996619706779)\n"
-     ]
-    }
-   ],
-   "source": [
-    "# Juwels\n",
-    "print('JUWELS', time_per_iteration_mean_std('/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2010toY2222M01to12-160x128-2970N1500W-T2_MSL_gph500/convLSTM/20201210T140958_stadtler1_comparison_1node_1gpu/timing_per_iteration_time.pkl'))\n",
-    "# Booster\n",
-    "print('Booster', time_per_iteration_mean_std('/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2010toY2222M01to12-160x128-2970N1500W-T2_MSL_gph500/convLSTM/20201210T141910_gong1_booster_gpu1/timing_per_iteration_time.pkl'))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 31,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Juwels mean and standart deviation {'16 GPU(s)': {'mean': 0.8209993402058342, 'std': 0.2627643291319852}, '32 GPU(s)': {'mean': 0.8590118098249986, 'std': 0.4078450977768068}, '4 GPU(s)': {'mean': 0.7445914211655112, 'std': 0.13789611351045}, '64 GPU(s)': {'mean': 0.9353915504630987, 'std': 0.6640973670265782}, '8 GPU(s)': {'mean': 0.7804724221628322, 'std': 0.21824334555299446}}\n"
-     ]
-    }
-   ],
-   "source": [
-    "# Juwels\n",
-    "print('Juwels mean and standart deviation',iter_stat(base, wildcard_juwels))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 9,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Booster mean and standart deviation {'1 GPU(s)': {'mean': 0.3521572324468615, 'std': 0.3656996619706779}, '4 GPU(s)': {'mean': 0.41844419631014446, 'std': 0.5273198599590724}, '8 GPU(s)': {'mean': 0.48867375665101026, 'std': 0.4378652997442439}, '16 GPU(s)': {'mean': 0.4786909431320202, 'std': 0.49638173862734053}, '32 GPU(s)': {'mean': 0.6439339113469129, 'std': 1.4395666886291258}, '64 GPU(s)': {'mean': 0.8176603168024377, 'std': 2.1044189535471185}}\n"
-     ]
-    }
-   ],
-   "source": [
-    "# Booster\n",
-    "print('Booster mean and standart deviation',iter_stat(base, wildcard_booster))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 34,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Plotting \n",
-    "# Bar plot of total time and training time --> overhead time\n",
-    "\n",
-    "# dictionaries with the total times\n",
-    "tot_time_juwels_dict = get_time_dict(base, wildcard_juwels, fname_timing_total)\n",
-    "tot_time_booster_dict= get_time_dict(base, wildcard_booster, fname_timing_total)\n",
-    "\n",
-    "# dictionaries with the training times\n",
-    "train_time_juwels_dict = get_time_dict(base, wildcard_juwels, fname_timing_train)\n",
-    "train_time_booster_dict = get_time_dict(base, wildcard_booster, fname_timing_train)\n",
-    "\n",
-    "# get sorted arrays\n",
-    "# Note: The times for Juwels are divided by 2, since the experiments have been performed with an epoch number of 20\n",
-    "#       instead of 10 (as Bing and Scarlet did)\n",
-    "ngpus_sort = sorted([int(ngpu.split()[0]) for ngpu in tot_time_juwels_dict.keys()])\n",
-    "nexps = len(ngpus_sort)\n",
-    "tot_time_juwels = np.array([tot_time_juwels_dict[\"{0:d} GPU(s)\".format(key)] for key in ngpus_sort])/2.\n",
-    "tot_time_booster = np.array([tot_time_booster_dict[\"{0:d} GPU(s)\".format(key)] for key in ngpus_sort])\n",
-    "\n",
-    "train_time_juwels = np.array([train_time_juwels_dict[\"{0:d} GPU(s)\".format(key)] for key in ngpus_sort])/2.\n",
-    "train_time_booster = np.array([train_time_booster_dict[\"{0:d} GPU(s)\".format(key)] for key in ngpus_sort])\n",
-    "\n",
-    "overhead_juwels = tot_time_juwels - train_time_juwels \n",
-    "overhead_booster= tot_time_booster - train_time_booster\n",
-    "\n",
-    "names = [\"Juwels\", \"Juwels Booster\"]"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 31,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "400.0\n",
-      "278.0\n",
-      "100.0\n",
-      "2.0\n"
-     ]
-    }
-   ],
-   "source": [
-    "plot_computation_times(tot_time_juwels, tot_time_booster, labels, [\"Juwels\", \"Juwels Booster\"], \\\n",
-    "                       \"./total_computation_time\", log_yvals=False)\n",
-    "\n",
-    "plot_computation_times(overhead_juwels, overhead_booster, labels, [\"Juwels\", \"Juwels Booster\"], \\\n",
-    "                       \"./overhead_time\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 12,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "#print(labels)\n",
-    "#raise ValueError(\"Stop!\")\n",
-    "#x = np.arange(len(labels))  # the label locations\n",
-    "#width = 0.35  # the width of the bars\n",
-    "\n",
-    "#fig, ax = plt.subplots()\n",
-    "#rects1 = ax.bar(x - width/2, np.round(tot_time_juwels, 2), width, label='Juwels')\n",
-    "#rects2 = ax.bar(x + width/2, np.round(tot_time_booster, 2), width, label='Booster')\n",
-    "\n",
-    "def plot_computation_times(times1, times2, ngpus, names, plt_fname, log_yvals = False):\n",
-    "    \n",
-    "    nlabels = len(ngpus)\n",
-    "    x_pos = np.arange(nlabels)\n",
-    "    \n",
-    "    bar_width = 0.35\n",
-    "    ytitle = \"Time\"\n",
-    "    ymax = np.ceil(np.maximum(np.max(times1)/100. + 0.5, np.max(times2)/100. + 0.5))*100.\n",
-    "    print(ymax)    \n",
-    "    if log_yvals: \n",
-    "        times1, times2 = np.log(times1), np.log(times2)\n",
-    "        ytitle = \"LOG(Time) [min]\"\n",
-    "        ymax = np.ceil(np.maximum(np.max(times1)+0.5, np.max(times2) + 0.5))\n",
-    "    \n",
-    "    # create plot object\n",
-    "    fig, ax = plt.subplots()\n",
-    "    # create data bars\n",
-    "    rects1 = ax.bar(x_pos - bar_width/2, np.round(times1, 2), bar_width, label=names[0])\n",
-    "    rects2 = ax.bar(x_pos + bar_width/2, np.round(times2, 2), bar_width, label=names[1])\n",
-    "    # customize plot appearance\n",
-    "    # Add some text for labels, title and custom x-axis tick labels, etc.\n",
-    "    ax.set_ylabel(ytitle)\n",
-    "    ax.set_title('Comparison {0} and {1} with convLSTM model'.format(*names))\n",
-    "    ax.set_xticks(x_pos)\n",
-    "    ax.set_xticklabels(labels)\n",
-    "    ax.set_xlabel('# GPUs')\n",
-    "    print(np.ceil(np.maximum(np.max(times1)+0.5, np.max(times2) + 0.5)))\n",
-    "    ax.set_ylim(0., ymax)\n",
-    "    ax.legend()\n",
-    "                \n",
-    "    # add labels\n",
-    "    autolabel(ax, rects1)\n",
-    "    autolabel(ax, rects2)\n",
-    "    plt.savefig(plt_fname+\".png\")\n",
-    "    plt.close()\n",
-    "    \n",
-    "\n",
-    "def autolabel(ax, rects):\n",
-    "    \"\"\"Attach a text label above each bar in *rects*, displaying its height.\"\"\"\n",
-    "    for rect in rects:\n",
-    "        height = rect.get_height()\n",
-    "        ax.annotate('{}'.format(height),\n",
-    "                    xy=(rect.get_x() + rect.get_width() / 2, height),\n",
-    "                    xytext=(0, 3),  # 3 points vertical offset\n",
-    "                    textcoords=\"offset points\",\n",
-    "                    ha='center', va='bottom')\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 13,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Plot mean + std \n",
-    "# Juwels\n",
-    "dict_stat_juwels = iter_stat(base, wildcard_juwels, gpu_id_str=\"gpu\")\n",
-    "#print(dict_stat_juwels)\n",
-    "iter_mean_juwels = np.array([dict_stat_juwels[\"{0:d} GPU(s)\".format(key)][\"mean\"] for key in labels])\n",
-    "iter_std_juwels = np.array([dict_stat_juwels[\"{0:d} GPU(s)\".format(key)][\"std\"] for key in labels])\n",
-    "\n",
-    "dict_stat_booster = iter_stat(base, wildcard_booster, gpu_id_str=\"gpu\")\n",
-    "iter_mean_booster = np.array([dict_stat_booster[\"{0:d} GPU(s)\".format(key)][\"mean\"] for key in labels])\n",
-    "iter_std_booster = np.array([dict_stat_booster[\"{0:d} GPU(s)\".format(key)][\"std\"] for key in labels])"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 29,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "(21225,)\n"
-     ]
-    }
-   ],
-   "source": [
-    "iter_time_juwels = all_iter(base, wildcard_juwels)\n",
-    "iter_time_booster= all_iter(base, wildcard_booster)\n",
-    "\n",
-    "max_iter_juwels = np.shape(iter_time_booster[\"{0:d} GPU(s)\".format(labels[0])])[0]\n",
-    "max_iter_booster = np.shape(iter_time_booster[\"{0:d} GPU(s)\".format(labels[0])])[0]\n",
-    "\n",
-    "arr_iter_juwels = np.full((nexps, max_iter_juwels), np.nan)\n",
-    "arr_iter_booster= np.full((nexps, max_iter_booster), np.nan)\n",
-    "\n",
-    "\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 37,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# box plot instead of errorbar plot\n",
-    "# Juwels\n",
-    "#data_juwels = list_time_per_iteration_all_runs(base, wildcard_juwels)\n",
-    "data_juwels = all_iter(base, wildcard_juwels, gpu_id_str=\"gpu\")\n",
-    "# Booster\n",
-    "#data_booster = list_time_per_iteration_all_runs(base, wildcard_booster)\n",
-    "data_booster = all_iter(base, wildcard_booster, gpu_id_str=\"gpu\")\n",
-    "def simple_boxplot(time_per_iteration_data, title):\n",
-    "    # Multiple box plots on one Axes\n",
-    "    fig, ax = plt.subplots()\n",
-    "    ax.set_title(title)\n",
-    "    ax.boxplot(time_per_iteration_data, showfliers=False) # Outliers for initialization are disturbing \n",
-    "    plt.xticks([1, 2, 3, 4, 5 ,6], ['1', '4', '8', '16', '32', '64'])\n",
-    "    #plt.savefig('boxplot_'+title)\n",
-    "    #plt.close()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 86,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "886\n",
-      "64.08639097213745\n",
-      "31.232596397399902\n",
-      "(1326,)\n",
-      "***********\n",
-      "2100\n",
-      "4.405388832092285\n",
-      "29.095214366912842\n",
-      "(2653,)\n",
-      "***********\n",
-      "36981\n",
-      "7.751298189163208\n",
-      "26.409477949142456\n",
-      "(42450,)\n",
-      "***********\n",
-      "3843\n",
-      "66.00082683563232\n",
-      "29.385547637939453\n",
-      "(21225,)\n"
-     ]
-    }
-   ],
-   "source": [
-    "print(np.argmax(data_booster[\"64 GPU(s)\"]))\n",
-    "print(np.max(data_booster[\"64 GPU(s)\"]))\n",
-    "print(data_booster[\"64 GPU(s)\"][0])\n",
-    "print(np.shape(data_booster[\"64 GPU(s)\"]))\n",
-    "print(\"***********\")\n",
-    "\n",
-    "print(np.argmax(data_juwels[\"64 GPU(s)\"][1::]))\n",
-    "print(np.max(data_juwels[\"64 GPU(s)\"][1::]))\n",
-    "print(data_juwels[\"64 GPU(s)\"][0])\n",
-    "print(np.shape(data_juwels[\"64 GPU(s)\"]))\n",
-    "print(\"***********\")\n",
-    "\n",
-    "print(np.argmax(data_juwels[\"4 GPU(s)\"][1::]))\n",
-    "print(np.max(data_juwels[\"4 GPU(s)\"][1::]))\n",
-    "print(data_juwels[\"4 GPU(s)\"][0])\n",
-    "print(np.shape(data_juwels[\"4 GPU(s)\"]))\n",
-    " \n",
-    "print(\"***********\")\n",
-    "print(np.argmax(data_booster[\"4 GPU(s)\"][1::]))\n",
-    "print(np.max(data_booster[\"4 GPU(s)\"][1::]))\n",
-    "print(data_booster[\"4 GPU(s)\"][0])\n",
-    "print(np.shape(data_booster[\"4 GPU(s)\"]))\n",
-    "\n",
-    "#simple_boxplot(data_juwels, 'Juwels')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "simple_boxplot(data_booster, 'Booster')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 81,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Try more fancy box plot \n",
-    "def more_fancy_boxplot(time_per_iteration_data1, time_per_iteration_data2, ngpu_list, title):\n",
-    "    nexps = len(ngpu_list)\n",
-    "    # Shuffle data: EXPECT JUWELS FIRST FOR THE LEGEND! NOT GENERIC!\n",
-    "    data = []\n",
-    "    for i in np.arange(nexps):\n",
-    "        data.append(time_per_iteration_data1[\"{0} GPU(s)\".format(ngpu_list[i])])\n",
-    "        data.append(time_per_iteration_data2[\"{0} GPU(s)\".format(ngpu_list[i])])\n",
-    "     \n",
-    "    # trick to get list with duplicated entries\n",
-    "    xlabels = [val for val in ngpu_list for _ in (0, 1)]\n",
-    "\n",
-    "    # Multiple box plots on one Axes\n",
-    "    #fig, ax = plt.subplots()\n",
-    "    fig = plt.figure(figsize=(6,4))\n",
-    "    ax = plt.axes([0.1, 0.15, 0.75, 0.75])   \n",
-    "    \n",
-    "    ax.set_title(title)\n",
-    "    bp = ax.boxplot(data, notch=0, sym='+', vert=1, whis=1.5, showfliers=False) # Outliers for initialization are disturbing\n",
-    "    plt.xticks(np.arange(1, nexps*2 +1), xlabels)\n",
-    "    ax.set_xlabel('# GPUs')\n",
-    "    ax.set_ylabel('Seconds')\n",
-    "    \n",
-    "    # Reference: https://matplotlib.org/3.1.1/gallery/statistics/boxplot_demo.html \n",
-    "    box_colors = ['darkkhaki', 'royalblue']\n",
-    "    num_boxes = len(data)\n",
-    "    medians = np.empty(num_boxes)\n",
-    "    for i in range(num_boxes):\n",
-    "        box = bp['boxes'][i]\n",
-    "        boxX = []\n",
-    "        boxY = []\n",
-    "        for j in range(5):\n",
-    "            boxX.append(box.get_xdata()[j])\n",
-    "            boxY.append(box.get_ydata()[j])\n",
-    "        box_coords = np.column_stack([boxX, boxY])\n",
-    "        # Alternate between Dark Khaki and Royal Blue\n",
-    "        ax.add_patch(Polygon(box_coords, facecolor=box_colors[i % 2]))\n",
-    "        # Now draw the median lines back over what we just filled in\n",
-    "        med = bp['medians'][i]\n",
-    "        medianX = []\n",
-    "        medianY = []\n",
-    "        for j in range(2):\n",
-    "            medianX.append(med.get_xdata()[j])\n",
-    "            medianY.append(med.get_ydata()[j])\n",
-    "            ax.plot(medianX, medianY, 'k')\n",
-    "        medians[i] = medianY[0]\n",
-    "        # Finally, overplot the sample averages, with horizontal alignment\n",
-    "        # in the center of each box\n",
-    "        ax.plot(np.average(med.get_xdata()), np.average(data[i]),\n",
-    "                color='w', marker='*', markeredgecolor='k')\n",
-    "    \n",
-    "    # Finally, add a basic legend\n",
-    "    fig.text(0.9, 0.15, 'Juwels',\n",
-    "             backgroundcolor=box_colors[0], color='black', weight='roman',\n",
-    "             size='small')\n",
-    "    fig.text(0.9, 0.09, 'Booster',\n",
-    "             backgroundcolor=box_colors[1],\n",
-    "             color='white', weight='roman', size='small')\n",
-    "    #fig.text(0.90, 0.015, '*', color='white', backgroundcolor='silver',\n",
-    "    #         weight='roman', size='medium')\n",
-    "    fig.text(0.9, 0.03, '* Mean', color='white', backgroundcolor='silver',\n",
-    "             weight='roman', size='small')\n",
-    "\n",
-    "    \n",
-    "    plt.savefig('fancy_boxplot_'+title.replace(' ', '_'))\n",
-    "    plt.close()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 82,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "more_fancy_boxplot(data_juwels, data_booster, ngpus_sort, 'Time needed to iterate one step')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "flist_hpc1 = sorted(glob.glob(base + wildcard_juwels))\n",
-    "flist_hpc2 = sorted(glob.glob(base + wildcard_booster))\n",
-    "\n",
-    "\n",
-    "        \n",
-    "\n",
-    "print(get_ngpus(flist_hpc1[2], \"gpu\"))\n",
-    "print(get_ngpus(flist_hpc1[0], \"gpu\"))\n",
-    "\n",
-    "print(get_ngpus(flist_hpc2[2], \"gpu\"))\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.8.5"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 4
-}
diff --git a/Jupyter_Notebooks/performance_check.ipynb b/Jupyter_Notebooks/performance_check.ipynb
deleted file mode 100644
index 3caf9018..00000000
--- a/Jupyter_Notebooks/performance_check.ipynb
+++ /dev/null
@@ -1,724 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "code",
-   "execution_count": 108,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "## import all required modules\n",
-    "import os, glob\n",
-    "import numpy as np\n",
-    "import pickle\n",
-    "# for plotting\n",
-    "import matplotlib\n",
-    "matplotlib.use('Agg')\n",
-    "from matplotlib.transforms import Affine2D\n",
-    "from matplotlib.patches import Polygon\n",
-    "import matplotlib.pyplot as plt\n",
-    "%matplotlib inline"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 144,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "## some auxiliary functions\n",
-    "#\n",
-    "#colors = ['darkkhaki', 'royalblue']\n",
-    "colors = [\"midnightblue\", \"darkorange\"]\n",
-    "\n",
-    "def val_order(number):\n",
-    "    return int(np.floor(np.log10(number)))\n",
-    "#\n",
-    "# ****************************************************************************************************\n",
-    "#\n",
-    "def get_ngpus(fname, search_str, max_order=3):\n",
-    "    \"\"\"\n",
-    "    Tries to get numbers in the vicinty of search_str which is supposed to be a substring in fname.\n",
-    "    First seaches for numbers right before the occurence of search_str, then afterwards.\n",
-    "    :param fname: file name from which number should be inferred\n",
-    "    :param search_str: seach string for which number identification is considered to be possible\n",
-    "    :param max_order: maximum order of retrieved number (default: 3 -> maximum number is 999 then)\n",
-    "    :return num_int: integer of number in the vicintity of search string. \n",
-    "    \"\"\"\n",
-    "    \n",
-    "    ind_gpu_info = fname.lower().find(search_str)\n",
-    "    if ind_gpu_info == -1:\n",
-    "        raise ValueError(\"Unable to find search string '{0}' in file name '{1}'\".format(search_str, fname))\n",
-    "    \n",
-    "    # init loops\n",
-    "    fname_len = len(fname)\n",
-    "    success, flag = False, True\n",
-    "    indm = 1\n",
-    "    ind_sm, ind_sp = 0, 0\n",
-    "    # check occurence of numbers in front of search string\n",
-    "    while indm < max_order and flag:\n",
-    "        if ind_gpu_info - indm > 0:\n",
-    "            if fname[ind_gpu_info - indm].isnumeric():\n",
-    "                ind_sm += 1\n",
-    "                success = True\n",
-    "            else:\n",
-    "                flag = False\n",
-    "        else:\n",
-    "            flag = False\n",
-    "        indm += 1\n",
-    "    # end while-loop\n",
-    "    if not success: # check occurence of numbers after search string\n",
-    "        ind_gpu_info = ind_gpu_info + len(search_str)\n",
-    "        flag = True\n",
-    "        indm = 0\n",
-    "        while indm < max_order and flag: \n",
-    "            if ind_gpu_info + indm < fname_len:\n",
-    "                if fname[ind_gpu_info + indm].isnumeric():\n",
-    "                    ind_sp += 1\n",
-    "                    success = True\n",
-    "                else:\n",
-    "                    flag = False\n",
-    "            else:\n",
-    "                flag = False\n",
-    "            indm += 1\n",
-    "        # end while-loop    \n",
-    "        if success:\n",
-    "            return(int(fname[ind_gpu_info:ind_gpu_info+ind_sp]))\n",
-    "        else:\n",
-    "            raise ValueError(\"Search string found in fname, but unable to infer number of GPUs.\")\n",
-    "\n",
-    "    else:\n",
-    "        return(int(fname[ind_gpu_info-ind_sm:ind_gpu_info]))\n",
-    "#\n",
-    "# ****************************************************************************************************\n",
-    "#\n",
-    "# functions for computing time\n",
-    "def compute_time_tot(infile):\n",
-    "    with open(infile,'rb') as tfile:\n",
-    "        #print(\"Opening pickle time: '{0}'\".format(infile))\n",
-    "        total_time_sec = pickle.load(tfile)\n",
-    "    return np.asarray(total_time_sec/60)\n",
-    "#\n",
-    "# ****************************************************************************************************\n",
-    "#\n",
-    "def compute_time_tot_log(infile):\n",
-    "    total_time_min = compute_time_tot(infile)\n",
-    "    return np.log(total_time_min)\n",
-    "#\n",
-    "# ****************************************************************************************************\n",
-    "#\n",
-    "def get_time_dict(base, wildcardspec, tfilename, gpu_id_str=\"gpu\", llog = False):\n",
-    "    time_dict = {}\n",
-    "    flist_hpc = sorted(glob.glob(base + wildcardspec))\n",
-    "    print(flist_hpc)\n",
-    "    wrapper = compute_time_tot\n",
-    "    if llog: wrapper = compute_time_tot_log\n",
-    "    for tfile in flist_hpc: \n",
-    "        ngpus = get_ngpus(tfile, gpu_id_str)\n",
-    "        time_dict[\"{0:d} GPU(s)\".format(ngpus)] = wrapper(tfile + tfilename)\n",
-    "    return time_dict\n",
-    "#\n",
-    "def calc_speedup(comp_time, ngpus, l_ideal= False):\n",
-    "    nn = np.shape(ngpus)[0]\n",
-    "    if l_ideal:\n",
-    "        spd_data = np.array(ngpus, dtype=float)\n",
-    "    else:\n",
-    "        spd_data = comp_time\n",
-    "\n",
-    "    spd_up = spd_data[0:nn-1]/spd_data[1::]\n",
-    "    \n",
-    "    if l_ideal: spd_up = 1./spd_up\n",
-    "\n",
-    "    return spd_up\n",
-    "#\n",
-    "# ****************************************************************************************************\n",
-    "#\n",
-    "# functions for iteration time data    \n",
-    "def iter_time_mean_std(infile):\n",
-    "    with open(infile, 'rb') as tfile:\n",
-    "        time_per_iteration_list = pickle.load(tfile) \n",
-    "        \n",
-    "    time_per_iteration = np.array(time_per_iteration_list)\n",
-    "    return np.mean(time_per_iteration), np.std(time_per_iteration)\n",
-    "#\n",
-    "# ****************************************************************************************************\n",
-    "#\n",
-    "def iter_stat(base, wildcardspec, gpu_id_str=\"gpu\"):\n",
-    "    stat_iter_dict = {}\n",
-    "    flist_hpc = sorted(glob.glob(base + wildcardspec))\n",
-    "    for tdir in flist_hpc: \n",
-    "        ngpus = get_ngpus(tdir, gpu_id_str)\n",
-    "        ftname = os.path.join(tdir, fname_timing_iter)\n",
-    "        mean_loc, std_loc = iter_time_mean_std(ftname)\n",
-    "        stat_iter_dict[\"{0:d} GPU(s)\".format(ngpus)] = {\"mean\": mean_loc , \"std\": std_loc}\n",
-    "    return stat_iter_dict\n",
-    "#\n",
-    "# ****************************************************************************************************\n",
-    "#\n",
-    "def read_iter_time(infile):\n",
-    "    with open(infile,'rb') as tfile:\n",
-    "        time_per_iteration_list = pickle.load(tfile)\n",
-    "    return np.asarray(time_per_iteration_list)\n",
-    "#\n",
-    "# ****************************************************************************************************\n",
-    "#\n",
-    "def get_iter_time_all(base, wildcardspec, gpu_id_str=\"gpu\"):\n",
-    "    iter_dict = {}\n",
-    "    flist_hpc = sorted(glob.glob(base + wildcardspec))\n",
-    "    for tdir in flist_hpc: \n",
-    "        ngpus = get_ngpus(tdir, gpu_id_str)\n",
-    "        ftname = os.path.join(tdir, fname_timing_iter)\n",
-    "        iter_dict[\"{0:d} GPU(s)\".format(ngpus)] = read_iter_time(ftname)\n",
-    "    return iter_dict   \n",
-    "#\n",
-    "# ****************************************************************************************************\n",
-    "#\n",
-    "# functions for plotting\n",
-    "def autolabel(ax, rects, rot=45):\n",
-    "    \"\"\"Attach a text label above each bar in *rects*, displaying its height.\"\"\"\n",
-    "    scal = 1\n",
-    "    if rot <0.:\n",
-    "        scal = -1\n",
-    "    for rect in rects:\n",
-    "        height = rect.get_height()\n",
-    "        ax.annotate('{}'.format(height),\n",
-    "                    xy=(rect.get_x() + rect.get_width()*scal, height),\n",
-    "                    xytext=(0, 3),  # 3 points vertical offset\n",
-    "                    textcoords=\"offset points\",\n",
-    "                    ha='center', va='bottom', rotation=rot)\n",
-    "#\n",
-    "# ****************************************************************************************************\n",
-    "#\n",
-    "def plot_computation_time(times1, times2, ngpus, names, plt_fname, log_yvals = False):\n",
-    "    \n",
-    "    nlabels = len(ngpus)\n",
-    "    x_pos = np.arange(nlabels)\n",
-    "    \n",
-    "    bar_width = 0.35\n",
-    "    ytitle = \"Time [min]\"\n",
-    "    max_time = np.maximum(np.max(times1), np.max(times2))\n",
-    "    time_order = val_order(max_time)\n",
-    "    ymax = np.ceil(max_time/(10**time_order) + 0.5)*(10**time_order) + 10**time_order\n",
-    "   # np.ceil(np.maximum(np.max(times1)/100. + 0.5, np.max(times2)/100. + 0.5))*100.\n",
-    "    if log_yvals: \n",
-    "        times1, times2 = np.log(times1), np.log(times2)\n",
-    "        ytitle = \"LOG(Time) [min]\"\n",
-    "        ymax = np.ceil(np.maximum(np.max(times1)+0.5, np.max(times2) + 0.5))\n",
-    "    \n",
-    "    # create plot object\n",
-    "    fig, ax = plt.subplots()\n",
-    "    # create data bars\n",
-    "    rects1 = ax.bar(x_pos - bar_width/2, np.round(times1, 2), bar_width, label=names[0], color=colors[0])\n",
-    "    rects2 = ax.bar(x_pos + bar_width/2, np.round(times2, 2), bar_width, label=names[1], color=colors[1])\n",
-    "    # customize plot appearance\n",
-    "    # Add some text for labels, title and custom x-axis tick labels, etc.\n",
-    "    ax.set_ylabel(ytitle)\n",
-    "    ax.set_title('Comparison {0} and {1} with convLSTM model'.format(*names))\n",
-    "    ax.set_xticks(x_pos)\n",
-    "    ax.set_xticklabels(ngpus)\n",
-    "    ax.set_xlabel('# GPUs')\n",
-    "    ax.set_ylim(0., ymax)\n",
-    "    ax.legend()\n",
-    "                \n",
-    "    # add labels\n",
-    "    autolabel(ax, rects1)\n",
-    "    autolabel(ax, rects2)\n",
-    "    print(\"Saving plot in file: {0}.png ...\".format(plt_fname))\n",
-    "    plt.savefig(plt_fname+\".png\")\n",
-    "    plt.close()\n",
-    "#\n",
-    "# ****************************************************************************************************\n",
-    "#\n",
-    "def plot_speedup(comp_time_hpc1, comp_time_hpc2, ngpus, names):\n",
-    "    fig = plt.figure(figsize=(6,4))\n",
-    "    ax = plt.axes([0.1, 0.15, 0.75, 0.75])   \n",
-    "    \n",
-    "    spd_up1 = calc_speedup(comp_time_hpc1, ngpus)\n",
-    "    spd_up2 = calc_speedup(comp_time_hpc2, ngpus)\n",
-    "    spd_ideal= calc_speedup(comp_time_hpc2, ngpus, l_ideal=True)\n",
-    "    \n",
-    "    plt.plot(spd_up1/spd_ideal, label= names[0], c=colors[0], lw=1.5)\n",
-    "    plt.plot(spd_up2/spd_ideal, label= names[1], c=colors[1], lw=1.5)\n",
-    "    plt.plot(spd_ideal/spd_ideal, label= \"Ideal\", c=\"r\", lw=3.)\n",
-    "    \n",
-    "    xlabels = []\n",
-    "    for i in np.arange(len(ngpus)-1):\n",
-    "        xlabels.append(\"{0} -> {1}\".format(ngpus[i], ngpus[i+1]))\n",
-    "    plt.xticks(np.arange(0, len(ngpus)-1), xlabels)\n",
-    "    ax.set_xlim(-0.5, len(ngpus)-1.5)\n",
-    "    ax.set_ylim(0.5, 1.5)\n",
-    "    legend = ax.legend(loc='upper left')\n",
-    "    ax.set_xlabel('GPU usage')\n",
-    "    ax.set_ylabel('Ratio Speedup factor') \n",
-    "    \n",
-    "    plt_fname = \"speed_up_{0}_vs_{1}.png\".format(*names)\n",
-    "    print(\"Saving plot in file: {0}.png ...\".format(plt_fname))\n",
-    "    plt.savefig(\"speed_up_{0}_vs_{1}.png\".format(*names))\n",
-    "#\n",
-    "# ****************************************************************************************************\n",
-    "#\n",
-    "def boxplot_iter_time(time_per_iteration_data1, time_per_iteration_data2, ngpu_list, names):\n",
-    "    nexps = len(ngpu_list)\n",
-    "    # create data lists for boxplot-routine\n",
-    "    data = []\n",
-    "    for i in np.arange(nexps):\n",
-    "        data.append(time_per_iteration_data1[\"{0} GPU(s)\".format(ngpu_list[i])])\n",
-    "        data.append(time_per_iteration_data2[\"{0} GPU(s)\".format(ngpu_list[i])])\n",
-    "     \n",
-    "    # trick to get list with duplicated entries\n",
-    "    xlabels = [val for val in ngpu_list for _ in (0, 1)]\n",
-    "\n",
-    "    # Multiple box plots on one Axes\n",
-    "    #fig, ax = plt.subplots()\n",
-    "    fig = plt.figure(figsize=(6,4))\n",
-    "    ax = plt.axes([0.1, 0.15, 0.75, 0.75])   \n",
-    "    \n",
-    "    ax.set_title(\"Time per iteration step\")\n",
-    "    bp = ax.boxplot(data, notch=0, sym='+', vert=1, whis=1.5, showfliers=False) # Outliers for initialization are disturbing\n",
-    "    plt.xticks(np.arange(1, nexps*2 +1), xlabels)\n",
-    "    ax.set_xlabel('# GPUs')\n",
-    "    ax.set_ylabel('Time [s]')\n",
-    "    \n",
-    "    # Reference: https://matplotlib.org/3.1.1/gallery/statistics/boxplot_demo.html \n",
-    "    box_colors = colors\n",
-    "    num_boxes = len(data)\n",
-    "    medians = np.empty(num_boxes)\n",
-    "    for i in range(num_boxes):\n",
-    "        box = bp['boxes'][i]\n",
-    "        boxX = []\n",
-    "        boxY = []\n",
-    "        for j in range(5):\n",
-    "            boxX.append(box.get_xdata()[j])\n",
-    "            boxY.append(box.get_ydata()[j])\n",
-    "        box_coords = np.column_stack([boxX, boxY])\n",
-    "        # Alternate between Dark Khaki and Royal Blue\n",
-    "        ax.add_patch(Polygon(box_coords, facecolor=box_colors[i % 2]))\n",
-    "        # Now draw the median lines back over what we just filled in\n",
-    "        med = bp['medians'][i]\n",
-    "        medianX = []\n",
-    "        medianY = []\n",
-    "        for j in range(2):\n",
-    "            medianX.append(med.get_xdata()[j])\n",
-    "            medianY.append(med.get_ydata()[j])\n",
-    "            ax.plot(medianX, medianY, 'k')\n",
-    "        medians[i] = medianY[0]\n",
-    "        # Finally, overplot the sample averages, with horizontal alignment\n",
-    "        # in the center of each box\n",
-    "        ax.plot(np.average(med.get_xdata()), np.average(data[i]),\n",
-    "                color='w', marker='*', markeredgecolor='k', markersize=10)\n",
-    "    \n",
-    "    # Finally, add a basic legend\n",
-    "    fig.text(0.86, 0.15, names[0],\n",
-    "             backgroundcolor=box_colors[0], color='white', weight='roman',\n",
-    "             size='small')\n",
-    "    fig.text(0.86, 0.09, names[1],\n",
-    "             backgroundcolor=box_colors[1],\n",
-    "             color='white', weight='roman', size='small')\n",
-    "    #fig.text(0.90, 0.015, '*', color='white', backgroundcolor='silver',\n",
-    "    #         weight='roman', size='medium')\n",
-    "    #fig_transform =  ax.figure.transFigure #+ ax.transAxes.inverted() #+ ax.figure.transFigure.inverted()\n",
-    "    #ax.plot(0.1, 0.03, marker='*', markersize=30, color=\"w\", markeredgecolor=\"k\", transform=fig_transform)\n",
-    "    fig.text(0.86, 0.03, '* Mean', color='black', backgroundcolor='white', \n",
-    "             weight='roman', size='small', bbox=dict(facecolor='none', edgecolor='k'))\n",
-    "\n",
-    "    plt_fname = \"boxplot_iter_time_{0}_vs_{1}\".format(*names)\n",
-    "    print(\"Saving plot in file: {0}.png ...\".format(plt_fname))\n",
-    "    plt.savefig(plt_fname+\".png\")\n",
-    "    plt.close()\n",
-    "    \n",
-    "    "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 110,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "## some basic settings\n",
-    "base_dir = \"/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/\"\n",
-    "\n",
-    "wildcard_hpc1 = '20210325T095504_langguth1_juwels_container_[1-9]*gpu*'  # search pattern for finding the experiments\n",
-    "wildcard_hpc2 = '20210325T095504_langguth1_jwb_container_[1-9]*gpu*'\n",
-    "\n",
-    "gpu_id_str = [\"gpu\", \"gpu\"]               # search substring to get the number of GPUs used in the experiments,\n",
-    "                                          # e.g. \"gpu\" if '64gpu' is a substring in the experiment directory\n",
-    "                                          # or \"ngpu\" if 'ngpu64' is a substring in the experiment directory\n",
-    "                                          # -> see wilcard-variables above\n",
-    "names_hpc = [\"Juwels\", \"Booster\"]\n",
-    "\n",
-    "# name of pickle files tracking computing time\n",
-    "fname_timing_train = \"/timing_training_time.pkl\"\n",
-    "fname_timing_total = \"/timing_total_time.pkl\"\n",
-    "\n",
-    "fname_timing_iter = \"timing_per_iteration_time.pkl\"\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 111,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "['/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_juwels_container_16gpus', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_juwels_container_1gpu', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_juwels_container_32gpus', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_juwels_container_4gpus', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_juwels_container_64gpus', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_juwels_container_8gpus']\n",
-      "['/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_jwb_container_16gpus', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_jwb_container_1gpu', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_jwb_container_32gpus', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_jwb_container_4gpus', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_jwb_container_64gpus', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_jwb_container_8gpus']\n",
-      "{'16 GPU(s)': array(53.40843068), '1 GPU(s)': array(930.4968381), '32 GPU(s)': array(45.96871045), '4 GPU(s)': array(217.45655225), '64 GPU(s)': array(35.7369519), '8 GPU(s)': array(106.4218419)}\n",
-      "{'16 GPU(s)': array(34.26928383), '1 GPU(s)': array(492.70926997), '32 GPU(s)': array(35.05492661), '4 GPU(s)': array(100.99109779), '64 GPU(s)': array(30.98471271), '8 GPU(s)': array(49.63896298)}\n",
-      "['/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_juwels_container_16gpus', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_juwels_container_1gpu', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_juwels_container_32gpus', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_juwels_container_4gpus', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_juwels_container_64gpus', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_juwels_container_8gpus']\n",
-      "['/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_jwb_container_16gpus', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_jwb_container_1gpu', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_jwb_container_32gpus', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_jwb_container_4gpus', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_jwb_container_64gpus', '/p/project/deepacf/deeprain/video_prediction_shared_folder/models/era5-Y2007-2019M01to12-92x56-3840N0000E-2t_tcc_t_850/convLSTM_container/20210325T095504_langguth1_jwb_container_8gpus']\n"
-     ]
-    }
-   ],
-   "source": [
-    "## evaluate computing time\n",
-    "# dictionaries with the total times\n",
-    "tot_time_hpc1_dict = get_time_dict(base_dir, wildcard_hpc1, fname_timing_total, gpu_id_str=gpu_id_str[0])\n",
-    "tot_time_hpc2_dict= get_time_dict(base_dir, wildcard_hpc2, fname_timing_total, gpu_id_str=gpu_id_str[1])\n",
-    "\n",
-    "print(tot_time_hpc1_dict)\n",
-    "print(tot_time_hpc2_dict)\n",
-    "\n",
-    "# dictionaries with the training times\n",
-    "train_time_hpc1_dict = get_time_dict(base_dir, wildcard_hpc1, fname_timing_train, gpu_id_str=gpu_id_str[0])\n",
-    "train_time_hpc2_dict = get_time_dict(base_dir, wildcard_hpc2, fname_timing_train, gpu_id_str=gpu_id_str[1])\n",
-    "\n",
-    "# get sorted arrays\n",
-    "# Note: The times for Juwels are divided by 2, since the experiments have been performed with an epoch number of 20\n",
-    "#       instead of 10 (as Bing and Scarlet did)\n",
-    "ngpus_sort = sorted([int(ngpu.split()[0]) for ngpu in tot_time_hpc1_dict.keys()])\n",
-    "nexps = len(ngpus_sort)\n",
-    "tot_time_hpc1 = np.array([tot_time_hpc1_dict[\"{0:d} GPU(s)\".format(key)] for key in ngpus_sort])\n",
-    "tot_time_hpc1[0] = tot_time_hpc1[0]#*2.\n",
-    "tot_time_hpc2 = np.array([tot_time_hpc2_dict[\"{0:d} GPU(s)\".format(key)] for key in ngpus_sort])\n",
-    "\n",
-    "train_time_hpc1 = np.array([train_time_hpc1_dict[\"{0:d} GPU(s)\".format(key)] for key in ngpus_sort])\n",
-    "train_time_hpc1[0] = train_time_hpc1[0]#*2.\n",
-    "train_time_hpc2 = np.array([train_time_hpc2_dict[\"{0:d} GPU(s)\".format(key)] for key in ngpus_sort])\n",
-    "\n",
-    "overhead_hpc1 = tot_time_hpc1 - train_time_hpc1\n",
-    "overhead_hpc2= tot_time_hpc2 - train_time_hpc2"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 112,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "[492.70926997 100.99109779  49.63896298  34.26928383  35.05492661\n",
-      "  30.98471271]\n",
-      "Saving plot in file: ./total_computation_time_Juwels_vs_Booster.png ...\n",
-      "Saving plot in file: ./overhead_time_Juwels_vs_Booster.png ...\n",
-      "Saving plot in file: speed_up_Juwels_vs_Booster.png.png ...\n"
-     ]
-    },
-    {
-     "data": {
-      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXcAAAEFCAYAAAAYKqc0AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/d3fzzAAAACXBIWXMAAAsTAAALEwEAmpwYAAA010lEQVR4nO3dd3hUZfbA8e9JCAQIzSQgEJqKSJFEWmyAgAIiihQRFYG1YENl7e4urmuvu66u5afrigoiiqKABZUiiIgQJNIFUSGClAhIqCnn98d7EyOkTMhMbjI5n+e5DzN37tx77iScefPe955XVBVjjDHhJcLvAIwxxgSfJXdjjAlDltyNMSYMWXI3xpgwZMndGGPCkCV3Y4wJQ1X8DqCk4uLitHnz5n6HYYwxvktJSdmhqvEFvVbhknvz5s1ZsmSJ32EYY4zvROSnwl6zbhljjAlDltyNMSYMWXI3xpgwVOH63AuSmZlJWloaBw4c8DuUcis6OpqEhASioqL8DsUYUwbCIrmnpaVRq1Ytmjdvjoj4HU65o6qkp6eTlpZGixYt/A7HGFMGwqJb5sCBA8TGxlpiL4SIEBsba3/ZGFOJhEVyByyxF8M+H2Mql7BJ7uVBTExMSPZ777338sQTT4Rk38aY8GTJ3RhjwpAl9yCbO3cu/fv3z3s+ZswYxo8fz+LFixk0aBAA77//PtWrV+fQoUMcOHCA4447DoDvv/+evn370rFjR7p27cqaNWuO2P/TTz9NmzZtaN++PcOGDSubkzLGVDhhMVomv3vumcrKlT8HdZ9t2zbmvvsGlmofp5xyCsuWLQNg/vz5tGvXjsWLF5OVlUVycjIAo0eP5oUXXqBly5YsWrSI66+/ntmzZ/9hP4888gg//PAD1apVY9euXaWKyRgTvsIuuZdXVapU4fjjj2f16tV8/fXX3HLLLcybN4/s7Gy6du1KRkYGX375JRdddFHeew4ePHjEftq3b89ll13GhRdeyIUXXliGZ2CMqUjCLrmXtoVdWlWqVCEnJyfvef7hh926deOjjz4iKiqKs88+m1GjRpGdnc3jjz9OTk4OdevWzWvdF+aDDz5g3rx5TJ8+nQcffJDly5dTpUrY/RiNMaVkfe5B1qxZM1atWsXBgwfZtWsXs2bNynuta9euPPXUU5x22mnEx8eTnp7O2rVradeuHbVr16ZFixa8/fbbgLvxKDU19Q/7zsnJYdOmTfTo0YNHH32U3bt3k5GRUabnZ4ypGKzJFyRZWVlUq1aNJk2aMHToUNq1a0eLFi045ZRT8rZJTk5m69atdOvWDXBdLL/88kveGPSJEydy3XXX8cADD5CZmcmwYcNITEzMe392djbDhw9n9+7dqCo33XQTdevWLdPzNMZUDKKqfsdQIp06ddLD67mvXr2a1q1b+xSRk5qaytVXX83XX3/taxxFKQ+fkzEmeEQkRVU7FfRayLplROR/IrJNRFYUs11nEckSkSGhiiXUXnjhBS655BIeeOABv0MxxhggtH3u44G+RW0gIpHAo8AnIYwj5K699lpWrVpF7969/Q7FGGOAECZ3VZ0H/FrMZjcC7wDbQhWHMcZURr6NlhGRxsBA4PkAth0tIktEZMn27dtDH5wxxlRwfg6FfAq4U1VzittQVV9U1U6q2ik+vsCJvo0xxuTj51DITsCb3jDAOKCfiGSp6ns+xmSMMWHBt5a7qrZQ1eaq2hyYAlxfkRN7ZGQkSUlJJCYm0qFDB7788sug7v+hhx4K6v6MMeEtlEMhJwELgVYikiYiV4rItSJybaiO6afq1auzbNkyUlNTefjhh7n77ruDuv+jSe7Z2dlBjcEYU3GEcrTMJaraUFWjVDVBVV9W1RdU9YUCth2lqlNCFUtZ++2336hXrx7gygjcfvvttGvXjpNPPpnJkycXuX7Lli1069aNpKQk2rVrx/z587nrrrvYv38/SUlJXHbZZQBMmDCBLl26kJSUxDXXXJOXyGNiYrj11ltJTExk4cKFPpy9MaY8CL/yA3PGwrZlwd1n/STo8VSRm+Qm3wMHDrBly5a8Ur3vvvtuXot+x44ddO7cmW7duvHll18WuP6NN96gT58+/PWvfyU7O5t9+/bRtWtX/vOf/+QVFVu9ejWTJ09mwYIFREVFcf311zNx4kRGjBjB3r17SU5O5sknnwzuZ2CMqVDCL7n7JLdbBmDhwoWMGDGCFStW8MUXX3DJJZcQGRlJgwYN6N69O4sXLy50fefOnbniiivIzMzkwgsvJCkp6YhjzZo1i5SUFDp37gy4L5b69esDru9/8ODBZXXaxphyKvySezEt7LJw2mmnsWPHDo5mTH63bt2YN28eH3zwAaNGjeKWW25hxIgRf9hGVRk5ciQPP/zwEe+Pjo4mMjLyqGM3xoQHK/kbAmvWrCE7O5vY2Fi6du3K5MmTyc7OZvv27cybN48uXboUuv6nn36iQYMGXH311Vx11VUsXboUgKioKDIzMwHo1asXU6ZMYds2d2Pvr7/+yk8//eTb+Rpjyp/wa7n7JLfPHVzL+tVXXyUyMpKBAweycOFCEhMTEREee+wxjj322ELXv/rqqzz++ONERUURExPDa6+9Brgp+Nq3b0+HDh2YOHEiDzzwAL179yYnJ4eoqCieffZZmjVr5uMnYIwpT6zkbyVin5Mx4cWXkr/GGGP8Y8ndGGPCkCV3Y4wJQ5bcjTEmDFlyN8aYMGTJ3RhjwpAl9yCJiYkpcP2oUaOYMuXoaqLde++9PPHEE6UJyxhTSVlyN8aYMGTJPchUlTFjxtCqVSvOPvvsvBIBACkpKXTv3p2OHTvSp08ftmzZAsBLL71E586dSUxMZPDgwezbt8+v8I0xYSL8krtI6JYATJ06lbVr17Jq1Spee+21vBmZMjMzufHGG5kyZQopKSlcccUV/PWvfwVg0KBBLF68mNTUVFq3bs3LL78cso/HGFM5WG2ZIJs3b15eKd9GjRrRs2dPANauXcuKFSs455xzADdLUsOGDQFYsWIFf/vb39i1axcZGRn06dPHt/iNMeHBknsZUVXatm1b4OxIo0aN4r333iMxMZHx48czd+7csg/QGBNWwq9bRjV0SwC6deuWV8p3y5YtzJkzB4BWrVqxffv2vOSemZnJypUrAdizZw8NGzYkMzOTiRMnhuZzMcZUKtZyD7KBAwcye/Zs2rRpQ9OmTTnttNMAqFq1KlOmTOGmm25i9+7dZGVlMXbsWNq2bcv9999PcnIy8fHxJCcns2fPHp/PwhhT0VnJ30rEPidjwouV/DXGmErGkrsxxoQhS+7GGBOGwia5V7RrB2XNPh9jKpewSO7R0dGkp6dbAiuEqpKenk50dLTfoRhjykhYDIVMSEggLS2N7du3+x1KuRUdHU1CQoLfYRhjykhYJPeoqChatGjhdxjGGFNuhEW3jDHGmD+y5G6MMWGoyOQuIpEiYsVOjDGmgikyuatqNtBMRKqWUTzGGGOCIJALqhuABSIyDdibu1JV/xmyqMorVVjyJJx8FUTX9TsaY4wpVCB97t8DM7xta+VbKp+tS2D+XfBqO/hxpt/RGGNMoYptuavqPwBEJMZ7nhHIjkXkf0B/YJuqtivg9cuAOwEB9gDXqWpq4KH74NjOcOlC+GgkvNMXTr4aznoSqlbO7zpjTPlVbMtdRNqJyDfASmCliKSISNsA9j0e6FvE6z8A3VX1ZOB+4MUA9um/YzvD5Uuh8x2w4mV49WTYONvvqIwx5g8C6ZZ5EbhFVZupajPgVuCl4t6kqvOAX4t4/UtV3ek9/QqoOLdPVomGbo/CsC8gsiq83QtmjYHMvcW/1xhjykAgyb2mqs7JfaKqc4GaQY7jSuCjIO8z9BqdBpcvgw5jYdlz8FoipH3hd1TGGBNQct8gIuNEpLm3/A03giYoRKQHLrnfWcQ2o0VkiYgsKXf1Y6JqQI9/wcVzQXNgcjeYeytk7vc7MmNMJRZIcr8CiAfeBd4B4oA/BePgItIe+C8wQFXTC9tOVV9U1U6q2ik+Pj4Yhw6+hG4w4ltIvBZS/gmvnwJbFvkdlTGmkgokuZ+tqjepagdV7aiqY4FzSntgEWmK+8K4XFW/K+3+yoWqMXD2czDkU8jaD5NOh/l3Q9ZBvyMzxlQygST3uwNc9wciMglYCLQSkTQRuVJErhWRa71N7gFigedEZJmILCl0ZxVNs7Nh5HJo+yf4+hGY0BG2pvgdlTGmEpHCJrgQkXOBfsBQYHK+l2oDbVS1S+jDO1KnTp10yZIK9D3ww0fwyVWwdysk/xVO/asbYWOMMaUkIimq2qmg14pquW8GlgAHgJR8yzSgT7CDDFstzoWRK6D1pfDVfTAxGbZ/63dUxpgwV2jLPW8DkdrAXq+IGCISCVRT1X1lEN8RKlzLPb/178Ono+HATjjt79DlTogIi/lSjDE+ONqWe65PgOr5nlcHPgtGYJXOCQNg5EpoOQgW/M1dcE1f7XdUxpgwFEhyj85fT8Z7XCN0IYW5GnHQ/03o/xbs2uCGTC5+HHKy/Y7MGBNGAknue0WkQ+4TEekI2B06pdXqIhi10vXJz7vD3fy0c53fURljwkQgyX0s8LaIzBeRL3AjZ8aENKrKomYDuOBd6DcB0le58gVL/+3udDXGmFIIpOTvYhE5CWjlrVqrqpmhDasSEYHWl0GTHvDJ1TBnLKybCn3+B3WP8zs6Y0wFFegE2a2ANkAH4BIRGRG6kCqpmEYwcIZL6tu+gdfaQ+oLbvYnY4wpoUDquf8deMZbegCPAReEOK7KSQTa/cnd3drodPjsOpjSG37b6HdkxpgKJpCW+xCgF/CLqv4JSATqhDSqyq52Uxg8E85+AbYsdBOCLP+fteKNMQELJLnvV9UcIMu7oWkb0CS0YRlEIPEa14qvfwp8ciVM7Q8Zm/2OzBhTAQSS3JeISF3c7EspwFJcQTBTFuq0gKGzoce/YdMcGN8WVk2wVrwxpkiFJncROcN7+GdV3aWqL+BK/Y70umdMWZEI6HATjEiF2Dbw0eUwbZArRmaMMQUoquX+tPdvXitdVX9UVat65Zd6LeHiedDtcVdtcnxbWPuW31EZY8qhosa5Z4rIi0CCiDx9+IuqelPowjKFioiEzrfBcf3g41Ew42L47h3o9awrbWCMMRTdcu8PzMaVGkgpYDF+im0Dl3wJZz4I66fCq21h3Xt+R2WMKScKbbmr6g7gTRFZraqpZRiTCVREFUj+CxzXHz4aCdMGQuvh0PNpiK7nd3TGGB8VO1rGEnsFEN8eLvva1Yhf+ya82g42fOh3VMYYHwVafsCUd5FRcPq9cOkiqFYPpp4HM6+Eg7v9jswY4wNL7uGmQQcYngJd7oaV493drT/Z3CrGVDaB1JaJFZFnRGSpiKSIyL9FJLYsgjNHqUo16PqQu+BapQZMOcfVqTmUUfx7jTFhIZCW+5u4kgODcXVmtuNqulc6OTk5ZGQc8DuMwDVMhsu/gY63QOr/uUqTmz73OypjTBkIZILsFara7rB1y1X15JBGVgg/J8jetOlXkpPvp1GjurRs2eCIJTY2xpe4ApL2BcwcBbu+hw43w5kPQZTNlmhMRVbUBNnFTtYBfCIiw4DcWyGHADODFVxFEh0dxV139WPduq2sW7eVN974in37DuW9Xq9eTVq2rH9E0m/UqC4RET5f3kg405UvmHeXm+3phw+hz3hofLq/cRljQiKQlvseoCaQO/dbBLDXe6yqWjt04R3Jz5b74XJycti8eTfr12/NS/i5y6+/7s3brnr1qpxwwpFJv3nzOKKiIss+8I2zYeYVsGcTdLwVzrgPqkSXfRzGmFIpquVebHIvb8pTci9KenrGEQl/3bqtbN68K2+bKlUiaN487oikf8IJ9alRo1poAzy0Bz6/Db59EY5pDee+Csd2Du0xjTFBVarkLiLdClqvqvOCEFuJVZTkXpi9ew/ma+lvy0v6P/64g+zs3yfGbty4npfs6+dL+iHo1/9xphsPv/cX6HIXnDrOjbYxxpR7pU3u0/M9jQa6ACmq2jN4IQauoif3whw6lMWPP+44oqW/fv02Dhz4fT7yY46pScuWDTjxxN8Tfm6/vogc3cEP7IK5f3bj4uNOhnNfg/pJwTgtY0wIBbVbRkSaAE+p6uBgBFdS4ZrcC5OTk8PPP+8qIOlvZefOfXnb1axZ7Q/9+rlJv3nzWKpUCbBf//vp8Olo2L/DteC73O3ufDXGlEvBTu4CrFTVNsEIrqQqW3IvjKoW0q+/jS1bduVtFxUVSYsWcUck/eOPr0+NGlWP3PH+dJh9E6x5Axp0hL7jIa7dkdsZY3xX2m6ZZ4DcjSKAJOBHVR0ezCADZcm9eBkZB1i/ftsRif+nn9Lz+vVFhISEeoclfdfyr1evpqsR/9l1cGg3nPYPV0M+IpCRs8aYslLa5D4y39MsXGJfEMT4SsSS+9E7eDCLH3/cntfC/+67X1i3bisbNmz/Q79+XFwMLVs2IOnEaIYfO4EWWZ9zKLYTUee/jsSe5OMZGGPys6GQpkjZ2Tmkpf16xAie9eu3snv3Pga0+o4He82hRlQWr2/ox/Kqg4mLr0tcXAyxsTHExcXkPY6NjaF69QK6e4wxQXdUyV1ElvN7d8wRVLV9cMIrGUvuZUdV2b59D+vWbSVt7Urab32Q1lWXsHRbM0ZP78/mXQVfbK1ZsxqxsTWJi6uVl/AP/wJwr9UkNjaGqlWtu8eYo3G0yb2Z9/AG79/XvX+H4+5MvauYg/4PN1XftsNr03ivC/BvoB+wDxilqkuLORdL7n5ShVWvwWfXonVOYN95H7BjXw3S0/eyY8ceduzIID3dLbmP86/LzMwucLe1a0cX+EVwzDG5j2vlfVnUq1cj8NE/xoS50va5f6Oqpxy2bqmqdijmfd2ADOC1QpJ7P+BGXHJPBv6tqslFBoMl93Jh42yYej7UbgoXzYKYRsW+RVX57bcD7Nixp8gvgPyPc3KO/N0UEerWrfGHLqGC/jrI/bKoW7e6/3V9jAmR0hYOExE5I/ciqoicTmDT880TkeZFbDIAl/gV+EpE6opIQ1XdEkBMxk9Ne8Lgj+HdfjC5O1w0G2o3KfItIkKdOtWpU6c6xx9fv9hD5OTksHPnPn799Y9/FRz+RbBmzRbS0/eyc+feAvcTGRnBMcfUPOJL4MgvBvdlULt29NHfDGZMORJIcr8S+J+I1PGe7wKuCMKxGwOb8j1P89aV7+Ru//EPsx6uahr0vUYAsd7SsrQ7Syt1OMYUrRwOTCk2uatqCpCYm9xVtcwn5RSR0cBogKZNg59IjDEm3AQyzV4DEXkZeFNVd4tIGxG5MgjH/hnI/7d8grfuCKr6oqp2UtVO8fHxQTi0McaEt0CuNI3HTc6Re9XsO2BsEI49DRghzqnA7grR365qS0HLtlR4Ng6ebwg7VvkfT4iXd99ZQqOGY3ni8Y98j8WWcrCUQ4Ek9zhVfQtvsg5VzQIKHtOWj4hMAhYCrUQkTUSuFJFrReRab5MPgQ3AeuAl4PqjOQFTTsS3h6FzQXPgrbNgxwq/IwqpQYM6MmRIJ5566hMWLdrgdzjGHCGQoZBzcZNjf6qqHbxW9qOq2r0M4juCDYUs535dC2/3hKyDcNFnYV06OCPjAL17P0lmZjaffnobdevanLSmbBU1FDKQlvstuC6U40VkAfAabny6MUc6phUM/dxNvv12T9ia4ndEIRMTE82zzw5n69bd3HnnW1S0Uh4mvAUyXn0p0B04HbgGaKuq34Y6MFOB1TsBLv4cqtaBt3vBlkV+RxQyp5zSjNtvP5fp01OZNCl8z9NUPIGMlqkB3AWMVdUVQHMR6R/yyEzFVqeFS/DV42DKOZD2hd8RhcwNN/TkzDNbMm7cVNat2+p3OMYAgXXLvAIcAk7znv8MPBCyiEz4qN3UddHUbAjv9oVNc/2OKCQiIiJ4+unLiI6O4vrrX+fgwSy/QzImoOR+vKo+BmQCqOo+wG7TNIGp1di14Gs3c+UKfvrM74hC4thj6/Cvfw1j5cqfefjhGX6HY0xAyf2QiFQHV/5XRI4HDoY0KhNeah4LQ+dA3RNgan/44WO/IwqJ3r3bMWrUmbz44ufMmbPa73BMJRdIcv878DHQREQmArOAO0IalQk/Neq7BB/bBt4f4CbjDkPjxp3PSSc15Oab32D79j1+h2MqsUBGy3wKDAJGAZOATqo6N7RhmbBUPdaVCI5PhGmDYN27fkcUdNWrV+X55y8nI+MgY8e+QU5Ojt8hmUoq0ELX3YFeQA+ga+jCMWEvuh4M+RQadIbpQ2HNZL8jCrpWrRry978PYM6cNfz3v/P8DsdUUoEMhXwOuBZYDqwArhGRZ0MdmAlj1erAkJnQ6DT48FJYNcHviIJuxIjT6dOnHQ8+OIPly63msCl7gbTcewJ9VPUVVX0FN3NSz9CGZcJe1Vpuwo+E7vDRCFgx3u+IgkpEeOKJi4mNjeH6619n3z4bg2DKViDJfT2Qv4h6E2+dMaUTVRMGzoBm58DMP8G3L/odUVDFxsbwzDOXsWHDdsaNm+p3OKaSCSS51wJWi8hcr4jYKqC2iEwTkWkhjc6Ev6gacOH70KIffHoNfBNePX5nnNGSMWN6MWnSIqZPX+Z3OKYSCWSavXtCHoWp3KpEwwXvwoyLYfYYyDkEHf/sd1RBc9ttfVmwYB233z6ZU05pSkLCMX6HZCqBQIZCfq6qn+Muph4DZOSu89YbU3pVqsH5b8OJQ2DuLfD1o35HFDRRUZE8++xwcnKUG26YQFZWsdMhGFNqhSZ3EZkhIu28xw1xyf0K4HURGVs24ZlKJTIKzpsEJ10C8++Chff7HVHQNGsWxyOPXMTixT/w1FOf+h2OqQSKarm38KpAAvwJN1nH+UAyLskbE3wRVeDc16HN5fDlPbBgXLmdxqykbPYmU5aKSu6Z+R73wk2Lh6ruwZtyz5iQiIiEPq9Auyvhqwdg/t1hk+AfemgwTZocw5gxE9i1a5/f4ZgwVlRy3yQiN4rIQKADrr4MXhGxqLIIzlRiEZHQ+0VIvBYWPwqf3xoWCT4mJprnnrvcZm8yIVdUcr8SaIurKXOxqu7y1p+Kq/FuTGhJBPR6Dk65CVL+BbNvdBNwV3A2e5MpC4UOhVTVbbiyA4evnwPMCWVQxuQRgR5PQWRVWPIE5GTC2c+7xF+B3XBDT+bP/45x46bSuXMLWrZs4HdIJsxU7P8hpnIQgW6PQfJf3F2sM6+EnIo9nNBmbzKhZsndVAwicMYDcNq9sHI8fDwScip2QrTZm0woWXI3FYcInP53OPNBWD0RPrgMsjOLf185ZrM3mVAJpORvgohMFZHtIrJNRN4RkYSyCM6YAiX/Bbo9Dt+95UoWZB/yO6JSsdmbTCgE0nJ/BZgGNAQaAdOx0TLGb51vgx7/hvVTYdpgyKq4JXXzz9508802e5MJjkCSe7xXyz3LW8YD8SGOy5jidbjJDZXcMAPevxAy9/sd0VHLnb1p7lybvckERyDJPV1EhotIpLcMB9JDHZgxAUm6Dnr/F36cCe+dD5kV965Pm73JBFMgyf0KYCjwC7AFGIKrNWNM+XDyldB3PGyaA+/2g0MZfkd0VGz2JhNMgZT8/UlVL1DVeFWtr6oXqurGsgjOmIC1HQHnToCfv4B3+sLB3/yO6KjY7E0mWAq9Q1VE7lDVx0TkGeCIAhiqelNIIzOmpFpf4soGf3AJvNMbBn0M0XX9jqrEcmdveuaZzzjrrJM4//wkv0MyFVBRMzHlDrpdUhaBGBMUJw6BiCiYfhFMORsGfwLVK97MRzZ7kymtQrtlVHW693Cfqr6afwEq7lUrE/5OGAAD3oMdK+DtnrBvu98RlZjN3mRKK5ALqncHuM6Y8uO4fnDhNNi5Ft7qAXu3+h1RidnsTaY0ippm71yvv72xiDydbxkPBFTUQ0T6ishaEVkvIncV8HpTEZkjIt+IyLci0u+oz8SYwzXvDQM/gN0/wFtnQcZmvyMqsT/O3vS93+GYCqSolvtmXH/7ASAl3zIN6FPcjkUkEngWOBdoA1wiIm0O2+xvwFuqegowDHiupCdgTJGa9oTBH8OeNJjcHX7b5HdEJfbgg272phtusNmbTOCK6nNP9frXTzisz/1dVd0ZwL67AOtVdYOqHgLeBAYcfhigtve4Du4LxZjgSugKg2fCvm3wVnfY/aPfEZVIrVpu9qZt236z2ZtMwALpc28uIlNEZJWIbMhdAnhfYyB/MynNW5ffvcBwEUnDzdF6YyBBG1NijU+HIZ/CgZ2uBb+rYk1QbbM3mZIKtHDY87h+9h7Aa8CEIB3/EmC8qiYA/YDXRY6cYkdERovIEhFZsn17xRv5YMqJhl3golmQmQGTu8HOdX5HVCI33NCTM89sybhxU1m3ruJdIDZlK5DkXl1VZwHi3a16L3BeAO/7GWiS73mCty6/K4G3AFR1IRANxB2+I1V9UVU7qWqn+HirWWZKoUEHGDrHlQme3B3SK04NdZu9yZREIMn9oNeaXiciY0RkIBATwPsWAy1FpIWIVMVdMJ122DYbgV4AItIal9ytaW5CK749XDzXTbb91lluPHwFYbM3mUAFktxvBmoANwEdgcuBEcW9SVWzgDHATNzdrm+p6koRuU9ELvA2uxW4WkRSgUnAKLWrRaYsxLaBiz+HiCow+SzYtszviAJmszeZQEhJc6k3xHGYqk4MTUhF69Spky5ZYhURTJDsXO/uYs3McKUKju3kd0QB2b//EOed9xQ7duxh1qw7iI+v5XdIxgcikqKqBf7SFnUTU20RuVtE/iMivcUZA6zHlQA2puKrd4JrwVetA2/3gs1f+R1RQKpXr8pzz9nsTaZwRXXLvA60ApYDVwFzgIuAgap6+Hh1YyquOi1cgq8R76pJpn3hd0QBOemkhtxzzwU2e5MpUFHJ/ThVHaWq/4cbstgG6KOqy8okMmPKUu2mMPRzqNkQ3u0Lm+b6HVFARo48w2ZvMgUqKrln5j5Q1WwgTVUPhD4kY3xSq7Frwddu5mZ0+ukzvyMqls3eZApTVHJPFJHfvGUP0D73sYhUzGlujClOzWPdOPi6J8DU/vDDx35HVCybvckUpKjaMpGqWttbaqlqlXyPaxf2PmMqvBr1XYKPbQPvD4Dvpxf/Hp/lzt40adIipk9f5nc4phwIZJy7MZVP9VhXqiA+EaYNgnXv+h1RsW67rS8dOjTj9tsnk5b2q9/hGJ9ZcjemMNH1XLGxBp1h+lBYM9nviIpkszeZ/Cy5G1OUanVgyExodDp8eCmsClbNvNCw2ZtMLkvuxhSnai0Y/BEkdIePRsCKV/yOqEg2e5MBS+7GBCaqJgycAc3OgZlXQOoLfkdUJJu9yVhyNyZQUTXgwvfhuPPgs+tg1o2udHA5ZLM3GUvuxpRElWi4YCp0vAWW/Qfe6lFuJ9622ZsqN0vuxpRUZBSc9SSc9yZsT4UJHSFtvt9RFchmb6q8LLkbc7ROuhguXeQuuL7dE5b+G8pZ94fN3lR5WXI3pjTi2sJli6HFeTBnLHw4HDL3+h3VH9jsTZWTJXdjSqtaHRjwLpz5IKyZBG+cWu4m37bZmyofS+7GBINEQPJfYPDH7gLrxM7lribNuHHnc9JJDbn55jfYvn2P3+GYELPkbkwwNe8Nw1OgzvHw3gWwYBzklI8yADZ7U+Viyd2YYKvTHIZ9AW3/BF894EoH7y8fhbzyz9700ks2e1M4s+RuTChEVYc+L8PZL8DGWW645NZv/I4K+H32pocestmbwpkld2NCRQQSr4Fh8yEnC948HVa+6ndUNntTJWHJ3ZhQa5gMl6dAw9Pg41Hw2fW+ly2w2ZvCnyV3Y8pCjfow5BPodDukPg+Tu8Oen30NyWZvCm+W3I0pKxFVoPtjcP7bsGMFTOgAmz73NSSbvSl8WXI3pqydOAQu+xqq1YO3e8GSf/pWtsBmbwpfltyN8UNsa5fgTxgAn98KM4bBoQxfQrHZm8KTJXdj/FKtNpw/Bbo+AuumwBvJ8OtaX0IZNKgjgwd3tNmbSqg818mX8hxcQTp16qRLlizxOwxjguunWfDBMMg+CH1fg5YXlnkIe/YcoHfvJ8jMzOazz26nbt0aZR5DeXbwYBarV29m2bKNLFu2idTUjQwc2IGbbjrHt5hEJEVVOxX0WpWyDsYYU4BmvVzZgmmDYdpA6HI3nHE/RESWWQi5szcNGPA0d9zxFv/3fyMRkTI7fnmSnZ3D+vVbWbZsk5fMN7J69WYOHXLXJGJjY0hKakLTprE+R1o4S+7GlBe1m7obnmbfCF8/DFuXQL83oEZcmYWQO3vTww9/wKRJi7j00lPL7Nh+UVU2bkzPS+SpqZtYvjyNvXvdzV0xMdVITGzCVVd1JympCUlJTWncuF65/+KzbhljyqNv/wuzb4CaDeGCd6BBxzI7dE5ODsOGvUBKyk98/PEttGzZoMyOXRa2bfstr2slN5nv3Olq8FerVoW2bRuTmOiSeFJSU44/Pp6IiPJ5ebKobhlL7saUV78shmlDYN9W6PUcnHxF2R36l9306vU4jRrVZcaMsVSrVjH/yN+9ez+pqS6B5yb0LVt2ARARIZx0UsO8RJ6Y2ISTTmpI1aoV51wtuRtTUe3bAR9cAhs/g/ajocfTUKVamRz6k09WMGrUy4we3Z17772wTI5ZGvv2HWLlyp9JTd3IN9+4hL5hw/a811u0iCMxsSlJSU1ITGzKySc3pkaNsvksQ8UuqBpTUdWIcxOALPgbfP0IbFvmhk/WbhLyQ+efval791b06NE65McMVGZmNmvWbCE19ffulbVrfyE729Wob9iwDomJTRk6tDOJia5VXtlG/4S05S4ifYF/A5HAf1X1kQK2GQrcCyiQqqqXFrVPa7mbSmvdVPh4JERGQ/83oWnPkB9y//5DnHfeU+zYsYdZs+4gPr5WyI95uJycHDZs2JGvRb6RlSs3c+BAJgB169b4Q9dKUlJTjj22TpnH6QdfumVEJBL4DjgHSAMWA5eo6qp827QE3gJ6qupOEamvqtuK2q8ld1Oppa+BaYNg51p381On21xp4RBas2YL/fr9i1NPPZ4JE64O6cVFVeXnn3d5LXLXtZKauok9ew4Abjap9u0T/pDImzWLLfcjV0LFr26ZLsB6Vd3gBfEmMABYlW+bq4FnVXUnQHGJ3ZhKL/YkuGwRzLwS5t0BWxZB31egauha1LmzN/3lL+/w0kvzuOaas4K27/T0jHwXO92yY4crwxAVFUnr1g0ZOLBDXl95y5YNqFKl7Mb+V2ShTO6NgU35nqcByYdtcyKAiCzAdd3cq6ofH74jERkNjAZo2rRpSII1psKoWgv6T4aUZJh3J0xcCRdMdYk/REaOPIPPP1/LQw/N4PTTT+DkkxNKvI+MjAN8+22a1yJ3feWbNrlKlCJCy5b16dmzdV4ib926EdHRUcE+lUojlN0yQ4C+qnqV9/xyIFlVx+TbZgaQCQwFEoB5wMmququw/Vq3jDH5bJwDMy6GrP3QdzycODhkh0pPz+Ccc56gZs1qzJx5S5EjTQ4ezGLVqp/zbtP/5puNrF+/La8WS5Mmx+SNWklKakr79gnExESHLPZw5Ve3zM9A/kv6Cd66/NKARaqaCfwgIt8BLXH988aY4jTtAZcvdWULpg+BznfAmQ+62vFBljt709ChzzNu3FSefHIY4G7V/+67X/ISubtVfwuZme5W/fj4WiQmNmHAgFPy+spjY2OCHp/5o1Am98VASxFpgUvqw4DDR8K8B1wCvCIicbhumg0hjMmY8FMrAS6eB3NuhsWPubIF570JNeKDfqjc2ZueeeYzMjOz2bTpV779No39+920gbVqRZOY2ITRo7vn3eHZqFHdSnvB00+hHgrZD3gK15/+P1V9UETuA5ao6jRxP/Engb5ANvCgqr5Z1D6tW8aYIqx4BT67zk3rd8E7cGznoB8iMzObIUOeZfnyNNq2bZxXbyUxsSnHHRdXbm/VD0d2h6oxlcnWpW645N4t0PM/0P7qoB8iOzsHVbWRKz4rKrnbV6wx4aZBB1c+OOEs+HQ0zLwKsg4E9RCRkRGW2PduhYzNfkdRKEvuxoSj6rEw6ENI/iuseBne7Aq//eR3VBXb/nRY9y7MGgPj28ILx0LKv/yOqlBWW8aYcBURCWc+4PrdPxoBr3d0ZQuane13ZBXDwd/g5/mwcbZbtqcCClVqQEJXaDMSjuvnd5SFsuRuTLg7YQBcttj1w7/TB854ELrcGfKyBRVO5j74eQFsmgObZsMvS0CzIbIaNDodzrgPmvRwX5aRVf2OtliW3I2pDI45ES79Cj65Cr64G3752t30VK2235H5J+sg/LLo95b5lq8gJ9PdI3BsF0i+G5r0hEanQZWKd4OVJXdjKouqMXDeJGh4Knx+G0zsDAOmQmwbvyMrGzlZrjW+aba7s3fzAndnr0RA/Q7Q8c+uZd74TPdZVXCW3I2pTESg41g3omb6UJjYBfq8Aq0u8juy4MvJdv3km+a4lvnP8+HQHvdafHs3+UmTnpDQDaLr+hpqKFhyN6YySujmhktOvwhmDIUtt0K3R0JStqDMqEL6KpfIN82BtLlwYKd7rV4raD3ctcybnBWSu3fLmwr8kzTGlEqtxnDxXJh7C6Q8CdtSXLXJGvX9jiwwqrBr/e8t801zYJ9XNbxOCzhhoJvQpEkPiGnkb6w+sORuTGUWWRV6/cddQPzsGni9g5vGr9GpfkdWsN82/p7IN86GjDS3PqYRNOvtEnnTHi65V3KW3I0x0HaE64eeNggmd4OeT0P7a/wfLrn3F3fxc5M3omW3V1ewepyXyHu6fvN6Lf2PtZyx5G6MceonwWVL4KPhrvjYlq+g1/MQVb3sYtifDpvm/t4y/3W1W1+tjiun0OFml9Tj2rpRLqZQltyNMb+rfgwMnAFf/gO+ug+2f+uqS4aqm+Pgbkib//vwxNy7QKNqQuOu0O5PrnUen+TuuDUBs+RujPkjiYAz/uGVLRgOEzrBeW9A8z6l33fm3t/vAt0429We1xx3F2jjM+CM+/PdBWpT7JWGJXdjTMGO7++6aaYNgnfOdYk3+e6SdYdkHXTdOxtnu9b5lkW/3wXa8FRX2KxpT/e4At4FWp5ZcjfGFK7eCXDpQvhkNCz4m1e24NXCb/rJznSt8dwRLZsXuHLDEgENOkLHW9xolkZnhMVdoOVZhZusQ0S2A37XLo0Ddvgcg58q+/mDfQZgnwH4/xk0U9UC78iqcMm9PBCRJYXNflIZVPbzB/sMwD4DKN+fgY0lMsaYMGTJ3RhjwpAl96Pzot8B+Kyynz/YZwD2GUA5/gysz90YY8KQtdyNMSYMVdrkLiL/E5FtIrIixMcZLCIqIuXyirqIRIrINyIyIwT7ThKRr0RkmYgsEZEuwT7G0RCRP4vIShFZISKTRCSod8+IyEXe/nMO/7mLSHsRWei9vjzYxy4ipkJ/30XkRhFZ48X0WJCP20xElnq/AytF5FpvfQ0R+SDfcR8J5nELiCNaRL4WkVTveP/I99pEEVnr/T78T0SCfmtscT93EZkW9FykqpVyAboBHYAVJXhPvRIeoxYwD/gK6OT3ORcS4y3AG8CMYH8GwCfAud7jfsDccnC+jYEfgOre87eAUUE+79ZAK2Bu/p877qbBb4FE73ksEFlG513g7zvQA/gMqOY9rx/kz6Jqvn3HAD8CjYAaQI9828zP/V0J0fkLEOM9jgIWAafm+90Ub5kEXBfkz6DInzswyPs/GHAuCmSptC13VZ0H/FrCt73nfcNeICKB3N17P/AocKDEAZYBEUkAzgP+W4K3LfFaOj1Fiq2xqkDuDMx1gM1HEWYoVAGqez/DGgQWV8DnraqrVXVtAS/1Br5V1VRvu3RVzS5p8EejiN/364BHVPWgt922AHZ3sdfKvVVEipzSSFUP5e4bqIbXW6Cq+1R1Tu42wFIgIbCzKTl1MrynUd6i3msfeq8r8HWAcdzu/SVwjYgUN8t4oT93EYnBNbAeKPlZFa3SJvejdBbwT2AIsFpEHhKREwraUEQ6AE1U9YMyjK+kngLuAHJK8J4Tca2bMcAqEfmLiBQ2zc1Y4HER2QQ8Adx99KEGh6r+7MWyEdgC7FbVTwJ4a0nOu6h9qIjM9Loq7ijh+0PhRKCriCwSkc9FpHNxb1DVF4BzcV+M80Rkioj0FSm46IyINBGRb4FNwKOquvmw1+sC5wOzSnkuRfK6IJcB24BPVXXRYa9HAZcDHxe3L1X9i7ftccBSEXlFRM4sZPOifu73A08C+0p8QgEEWWkXoDlH+acQrkX6IJAFDD7stQjcn+TNvedzKWfdMkB/4Dnv8VkE2C1z2D7ica3+LKBLAa8/nfvZAEOBz8rBedcDZnuxRwHvAcODed75tvvDzx24DdclFIdLjAuBXmV47kf8vgMrgGdwXRJdvPikBPsUXLfGZmBaMds2wrWMG+RbVwX4CBhbhp9DXWAO0O6w9S8BTx3F/iKB4cBu4OkCXi/w5w4k5X5mpclFhS3Wci9E7re8t9yXb311EbkUeBfoA9wMfHrY22sB7YC5IvIjcCowrZxdVD0DuMCL702gp4hMyL+B1+LK/Qyuzbe+johcA0wDWgJX4PoUDzcS9zkBvI1LHn47G/hBVberaiYuvtPzbxCE8y5MGjBPVXeo6j7gQ1w/uJ/SgHfV+Rr3V1xc/g1E5MHcz+Ow9V2A53Bf4m9RzF9m6lrsK4Cu+Va/CKxT1adKeR4BU9VduOTeN3ediPwd96V9S0Hv8Vrmy0Tkw3zrRER6Aq8C9+A+hycLeHthP/fTgE7e/8EvgBNFZG6pTzBXWX1blseFEn5bAo/hvoH/A5xSgvfNpZy13A+L7ywCv6A6AfgeeARoWcy2q4GzvMe9gJRycK7JwEpcC0pw/zFvDOZ5F/Zzx/3VsNQ7dhXchczzyvDcj/h9B64F7vMen4jrOimy5Y7Xh4y7YD4UqFrEtgn8fvG6HvAdcLL3/AHgHSCiDM49HqjrPa6Ou4Db33t+FfBlbpwB7u8yYK0Xfz+KuDAeyM+9pLkooBjL6hervC24/tMtQCbum/XKAN7TD4g+imOFU3K/AKgS4LZnAilAKm50Qke/z9WL6x/AGlwr8nW80RxBPO+B3u/UQWArMDPfa8O9L5cVwGNleM4F/r7jRqpM8OJZCvQMYF8dcdUIAznuOd4XQar372hvfQLuguZqYJm3XBXC828PfOPFsAK4J99rWbgv7tw47glgf2cC8SU4fpE/91Akd7tD1RhjwpD1uRtjTBiy5G6MMWHIkrsxxoQhS+7GGBOGLLkbY0wYsuRuwoqINBCRN0Rkg4ikeJX4BnqvnSUiu72bUVZ7N64gIqNE5D+H7WduObvpzJgSseRuwoZX0Os93N2Ax6lqR2AYfywENV9Vk4BOwHCvBpAxYceSuwknPYFD6gpbAaCqP6nqM4dvqKp7cTdYFVj4rTAi8qOIxHmPO+XeLi4i3fOVLPhGRGqJSIyIzPKKRS0XkQH59jNOXA3xL8TVlL/NW3+8iHzs/dUxX0ROOpoPwphAytYaU1G0xd1lWSwRicXV/LkfKLYSYgBuA25Q1QVeGdfcMs8DVfU37wvhKxGZhvurYTCQiCtethT3RQOu1sq1qrpORJJxtVt6BiE+U8lYcjdhS0Sexd0mfkhVcxN4VxH5Blcg6xFVXVlE33pJbt9eAPxTRCbiCnGleSVkHxKRbt7xGgMNcEXb3lfVA8ABEZnuxRuDK2L2tvxeMr5aCWIwJo8ldxNOVuJaxACo6g1ei3lJvm3mq2r/w96XjivulN8xwI4CjpHF792ZeVOlqeojIvIBrv7QAhHpg/vLIB5XUyfTq/5X1LR6EcAu75qAMaVife4mnMwGokXkunzragTwvsXAGSJyLLi+dFyLeVMB2/6IK5wF+b5IROR4VV2uqo96+zsJN/vUNi+x9wCaeZsvAM4XN69nDK62Pqr6G/CDiFzk7VNEJDGA+I05grXcTdhQVRWRC4F/ebPdbAf2AncW876tInIz8KE3m1AGcImqFjRD1T+Al0Xkfly1z1xjvQSeg/sL4iNcXf/pIrIc99fDGu94i72+929xVSOX4yZ6AFdK9nkR+RuuP/5NXEVFY0rEqkIa4wMRiVHVDBGpgZtEfbSqBnQx2JhAWMvdGH+8KCJtcH3wr1piN8FmLXdjjAlDdkHVGGPCkCV3Y4wJQ5bcjTEmDFlyN8aYMGTJ3RhjwpAld2OMCUP/D4LzvOpD9rk/AAAAAElFTkSuQmCC\n",
-      "text/plain": [
-       "<Figure size 432x288 with 1 Axes>"
-      ]
-     },
-     "metadata": {
-      "needs_background": "light"
-     },
-     "output_type": "display_data"
-    }
-   ],
-   "source": [
-    "# plot the computing time\n",
-    "print(tot_time_hpc2)\n",
-    "plot_computation_time(tot_time_hpc1, tot_time_hpc2, ngpus_sort, names_hpc, \\\n",
-    "                       \"./total_computation_time_{0}_vs_{1}\".format(*names_hpc), log_yvals=False)\n",
-    "\n",
-    "plot_computation_time(overhead_hpc1, overhead_hpc2, ngpus_sort, names_hpc, \\\n",
-    "                       \"./overhead_time_{0}_vs_{1}\".format(*names_hpc))\n",
-    "# plot speed-up factors\n",
-    "plot_speedup(tot_time_hpc1, tot_time_hpc2, ngpus_sort, names_hpc)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 113,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "## evaluate iteration time\n",
-    "# get iteration times\n",
-    "iter_data_hpc1 = get_iter_time_all(base_dir, wildcard_hpc1, gpu_id_str=gpu_id_str[0])\n",
-    "iter_data_hpc2 = get_iter_time_all(base_dir, wildcard_hpc2, gpu_id_str=gpu_id_str[1])"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 114,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Saving plot in file: boxplot_iter_time_Juwels_vs_Booster.png ...\n"
-     ]
-    }
-   ],
-   "source": [
-    "# plot the iteration time in box plots\n",
-    "boxplot_iter_time(iter_data_hpc1, iter_data_hpc2, ngpus_sort, names_hpc)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 115,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "def get_slowiter(iter_time, threshold):\n",
-    "    inds_slow = np.where(iter_time > threshold)[0]\n",
-    "    return iter_time[inds_slow], np.shape(inds_slow)[0]\n",
-    "\n",
-    "def ana_slowiter(itertime1, itertime2, thres, names):\n",
-    "    slowt1, nslow1 = get_slowiter(itertime1, thres)\n",
-    "    slowt2, nslow2 = get_slowiter(itertime2, thres)\n",
-    "    \n",
-    "    if nslow1 > 0:\n",
-    "        print(\"{0:d} slow iteration steps on {1} with averaged time of {2:5.2f}s (max: {3:5.2f}s)\"\\\n",
-    "              .format(nslow1, names[0], np.mean(slowt1), np.max(slowt1)))\n",
-    "    else: \n",
-    "        print(\"No slow iterations on {0}\".format(names[0]))\n",
-    "        \n",
-    "    if nslow2 > 0:\n",
-    "        print(\"{0:d} slow iteration steps on {1} with averaged time of {2:5.2f}s (max: {3:5.2f}s)\"\\\n",
-    "              .format(nslow2, names[1], np.mean(slowt2), np.max(slowt2)))\n",
-    "    else: \n",
-    "        print(\"No slow iterations on {0}\".format(names[1]))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 116,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "***** Analyse single GPUs experiments *****\n",
-      "1 slow iteration steps on Juwels with averaged time of  5.18s (max:  5.18s)\n",
-      "No slow iterations on Booster\n",
-      "***** Analyse 4 GPUs experiments *****\n",
-      "No slow iterations on Juwels\n",
-      "No slow iterations on Booster\n",
-      "***** Analyse 8 GPUs experiments *****\n",
-      "No slow iterations on Juwels\n",
-      "No slow iterations on Booster\n",
-      "***** Analyse 32 GPUs experiments *****\n",
-      "No slow iterations on Juwels\n",
-      "No slow iterations on Booster\n",
-      "***** Analyse 32 GPUs experiments *****\n",
-      "No slow iterations on Juwels\n",
-      "No slow iterations on Booster\n",
-      "***** Analyse 64 GPUs experiments *****\n",
-      "No slow iterations on Juwels\n",
-      "No slow iterations on Booster\n"
-     ]
-    }
-   ],
-   "source": [
-    "    \n",
-    "## settings\n",
-    "names = [\"Juwels\", \"Booster\"]\n",
-    "slowiter_time = 5.       # arbitrary threshold for slow iteration steps\n",
-    "\n",
-    "# analyze single GPU experiments\n",
-    "print(\"***** Analyse single GPUs experiments *****\")\n",
-    "itertime_juwels = iter_data_hpc1[\"1 GPU(s)\"]\n",
-    "itertime_booster = iter_data_hpc2[\"1 GPU(s)\"]\n",
-    "\n",
-    "ana_slowiter(itertime_juwels[1:], itertime_booster[1:], slowiter_time, names)\n",
-    "\n",
-    "# analyze 4 GPUs experiments\n",
-    "print(\"***** Analyse 4 GPUs experiments *****\")\n",
-    "itertime_juwels = iter_data_hpc1[\"4 GPU(s)\"]\n",
-    "itertime_booster = iter_data_hpc2[\"4 GPU(s)\"]\n",
-    "\n",
-    "ana_slowiter(itertime_juwels[1:], itertime_booster[1:], slowiter_time, names)\n",
-    "\n",
-    "# analyze 8 GPUs experiments\n",
-    "print(\"***** Analyse 8 GPUs experiments *****\")\n",
-    "itertime_juwels = iter_data_hpc1[\"8 GPU(s)\"]\n",
-    "itertime_booster = iter_data_hpc2[\"8 GPU(s)\"]\n",
-    "\n",
-    "ana_slowiter(itertime_juwels[1:], itertime_booster[1:], slowiter_time, names)\n",
-    "\n",
-    "# analyze 16 GPUs experiments\n",
-    "print(\"***** Analyse 32 GPUs experiments *****\")\n",
-    "itertime_juwels = iter_data_hpc1[\"16 GPU(s)\"]\n",
-    "itertime_booster = iter_data_hpc2[\"16 GPU(s)\"]\n",
-    "\n",
-    "ana_slowiter(itertime_juwels[1:], itertime_booster[1:], slowiter_time, names)\n",
-    "\n",
-    "# analyze 32 GPUs experiments\n",
-    "print(\"***** Analyse 32 GPUs experiments *****\")\n",
-    "itertime_juwels = iter_data_hpc1[\"32 GPU(s)\"]\n",
-    "itertime_booster = iter_data_hpc2[\"32 GPU(s)\"]\n",
-    "\n",
-    "ana_slowiter(itertime_juwels[1:], itertime_booster[1:], slowiter_time, names)\n",
-    "\n",
-    "# analyze 64 GPUs experiments\n",
-    "print(\"***** Analyse 64 GPUs experiments *****\")\n",
-    "itertime_juwels = iter_data_hpc1[\"64 GPU(s)\"]\n",
-    "itertime_booster = iter_data_hpc2[\"64 GPU(s)\"]\n",
-    "\n",
-    "ana_slowiter(itertime_juwels[1:], itertime_booster[1:], slowiter_time, names)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "# Summary\n",
-    "- Occasionally, a few iteration steps are slow\n",
-    "- However, performance degradation seems to be much worser on Booster than on Juwels\n",
-    "- Higher chance for slow iteration steps on Booster in general"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 157,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "def boxplot_iter_total_time(iteration_time, total_time, ngpu_list, name, log_yvals=False):\n",
-    "    nexps = len(ngpu_list)\n",
-    "    bar_width = 0.35\n",
-    "    # create data lists for boxplot-routine\n",
-    "    iter_time_all = []\n",
-    "    for i in np.arange(nexps):\n",
-    "        iter_time_all.append(iteration_time[\"{0} GPU(s)\".format(ngpu_list[i])])\n",
-    "     \n",
-    "    # trick to get list with duplicated entries\n",
-    "    xlabels = [val for val in ngpu_list for _ in (0, 1)]\n",
-    "    nlabels = len(xlabels)\n",
-    "\n",
-    "    # Multiple box plots on one Axes\n",
-    "    #fig, ax = plt.subplots()\n",
-    "    fig = plt.figure(figsize=(6,4))\n",
-    "    ax = plt.axes([0.1, 0.15, 0.75, 0.75])   \n",
-    "    \n",
-    "    bp = ax.boxplot(iter_time_all, positions=np.arange(0, nlabels, 2), notch=0, sym='+', vert=1, showfliers=False, widths=bar_width) # Outliers for initialization are disturbing\n",
-    "    ax.set_xlabel('# GPUs')\n",
-    "    ax.set_ylabel('Time [s]')\n",
-    "    \n",
-    "    # Reference: https://matplotlib.org/3.1.1/gallery/statistics/boxplot_demo.html \n",
-    "    num_boxes = len(iter_time_all)\n",
-    "    medians = np.empty(num_boxes)\n",
-    "    for i in range(num_boxes):\n",
-    "        box = bp['boxes'][i]\n",
-    "        boxX = []\n",
-    "        boxY = []\n",
-    "        for j in range(5):\n",
-    "            boxX.append(box.get_xdata()[j])\n",
-    "            boxY.append(box.get_ydata()[j])\n",
-    "        box_coords = np.column_stack([boxX, boxY])\n",
-    "        ax.add_patch(Polygon(box_coords, facecolor=colors[1]))\n",
-    "        # Now draw the median lines back over what we just filled in\n",
-    "        med = bp['medians'][i]\n",
-    "        medianX = []\n",
-    "        medianY = []\n",
-    "        for j in range(2):\n",
-    "            medianX.append(med.get_xdata()[j])\n",
-    "            medianY.append(med.get_ydata()[j])\n",
-    "            ax.plot(medianX, medianY, 'k')\n",
-    "        medians[i] = medianY[0]\n",
-    "        # Finally, overplot the sample averages, with horizontal alignment\n",
-    "        # in the center of each box\n",
-    "        ax.plot(np.average(med.get_xdata()), np.average(iter_time_all[i]),\n",
-    "                color='w', marker='*', markeredgecolor='k', markersize=10)\n",
-    "    \n",
-    "    ax2 = ax.twinx()\n",
-    "    x_pos = np.arange(1, nlabels+1 ,2)\n",
-    "    \n",
-    "    ytitle = \"Time [min]\"\n",
-    "    max_time = np.max(total_time)\n",
-    "    time_order = val_order(max_time)\n",
-    "    ymax = np.ceil(max_time/(10**time_order) + 0.5)*(10**time_order) + 10**time_order\n",
-    "    # np.ceil(np.maximum(np.max(times1)/100. + 0.5, np.max(times2)/100. + 0.5))*100.\n",
-    "    if log_yvals: \n",
-    "        total_time = np.log(total_time)\n",
-    "        ytitle = \"LOG(Time) [min]\"\n",
-    "        ymax = np.ceil(np.max(total_time) + 0.5)\n",
-    "    \n",
-    "    # create data bars\n",
-    "    rects = ax2.bar(x_pos, np.round(total_time, 2), bar_width, label=names, color=colors[0])\n",
-    "    # customize plot appearance\n",
-    "    # Add some text for labels, title and custom x-axis tick labels, etc.\n",
-    "    ax2.set_ylabel(ytitle)\n",
-    "    ax2.set_xticks(np.arange(0, nlabels))\n",
-    "    ax2.set_xticklabels(xlabels)\n",
-    "    ax2.set_xlabel('# GPUs')\n",
-    "    ax2.set_ylim(0., ymax)\n",
-    "                \n",
-    "    # add labels\n",
-    "    autolabel(ax2, rects, rot=45)     \n",
-    "\n",
-    "    plt_fname = \"iter+tot_time_{0}_vs_{1}\".format(*names)\n",
-    "    print(\"Saving plot in file: {0}.png ...\".format(plt_fname))\n",
-    "    #plt.show()\n",
-    "    plt.savefig(plt_fname+\".png\")\n",
-    "    plt.close()\n",
-    "    \n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 158,
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Saving plot in file: iter+tot_time_Juwels_vs_Booster.png ...\n"
-     ]
-    }
-   ],
-   "source": [
-    "boxplot_iter_total_time(iter_data_hpc2, tot_time_hpc2, ngpus_sort, names_hpc[1])"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.8.5"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 4
-}
-- 
GitLab