From 501dc8c76064c9000b237c2037703290762a844f Mon Sep 17 00:00:00 2001 From: Jayaram Kancherla Date: Fri, 24 Jun 2022 19:57:06 -0400 Subject: [PATCH] Support for a multi-modal analysis of ADT + RNA (#125) * Added new parameter elements for ADT, integrated analysis. * Support multiple modalities in the marker selection. * Support multiple modalities in diagnostic plots. * Use latest multi-modal-aware version of bakana. * Added a logo to the repo for safety. Co-authored-by: LTLA --- assets/logos/kana-small-cropped.png | Bin 0 -> 65370 bytes package.json | 4 +- src/App.js | 127 +++- src/components/Analysis/Analysis.css | 4 + src/components/Analysis/index.js | 907 ++++++++++++++++++------ src/components/Gallery/index.js | 72 +- src/components/Markers/index.js | 35 +- src/components/Plots/DimPlot.js | 14 +- src/components/Plots/ImgPlot.js | 2 +- src/components/Plots/PCABarPlot.js | 2 +- src/components/Plots/QCPlotMgr.js | 30 +- src/components/Plots/ViolinPlotBasic.js | 7 +- src/components/Plots/uDimPlot.js | 17 +- src/context/AppContext.js | 27 +- src/workers/scran.worker.js | 80 ++- 15 files changed, 993 insertions(+), 335 deletions(-) create mode 100644 assets/logos/kana-small-cropped.png diff --git a/assets/logos/kana-small-cropped.png b/assets/logos/kana-small-cropped.png new file mode 100644 index 0000000000000000000000000000000000000000..c22c1d5ac38f39840d0c9623735877719e41e43d GIT binary patch literal 65370 zcmeFZ^;aFivoA_;2u^~#26uM}uyJ?S&Bh&qB|wni?(S?HHm<>f>&7LxyZg)c+eVx=r>kZnRF!4XQHfAtU|`Sza?MaEP9 zRq!?vN)j+Ib+I2`%n<&yDJ0g1%`|y9Id9eR2 zh1Jc2`)~RK^M4fi!qVvff#}(4>bmPHDGFLRIk1{pI+O2mzABBok|pyf`UTW)zVr} zU0UXUcmLNCp#r+QI}5V0d3kxUdU3Hjx!SOC2nYzUv2(IU~%(tbT{*6ade~p zUm*XDBW>ko;cDybZtLVo@gH0>b0-gX5h|+x82Ufue~r`K*82Zia&-IOZvAtR?LQJW z4pw%y|AYOntMGrgf-0`IR{t#j2Vay!_`fv&KfM2KN0{wD#{XY~`Cp#?7x$m5qNu`b z|7Y4nQ3;JVkzioNVF1z+n%*ByI&GsY^*lH3IjLPY8W`CB zL!0FKrjX#?#Cua%4uXNYDd@VPH@%38D2NEKyv#VEk6)YeF-ss(awB--Gx7 zib=9|Re$?O#O^jIuvEi=Hv{VK+x|59{@_HO{`3rueOGT*c=SX<1oxh?T2(C)l?j?o zFP>@!zc}7s9JpRQ{jt2=2)wHyAGvy;%zbidlUnnHM!C8diYySGs)lMetD&QxXbWjI zEE57Xx7V^O%$7flr~qE88WA(rM0 z%sIGdH$Q>9A2E+lhD0_-$=?Si-{ie~YxPK1jH)IOShYL?O-WXXpqFR*5KeY&C3il! zd$o%egn+>P+4r@0hWDC)E2qn>%P6(qLU6Ot;kD!n1-L6cyO{vb^7mgB291SgO$$h} zV3U`dcW29y_ZO4*K1VzIGLR#rVzVk63(lVm#3-e@$W<7%fpzH-_f7B(ZavZX_KVFW9iQUBL-m@j^zUSubZn&N29a!;OIeB zNT0Z~m3xI?b1PBNNdB@!%h!8vH_I)#UTVOX-*Ffmi$A^P_>q>x{<5nC&1AZR1Km!{ zvFe_p`tC%U+WWq19f7`YG83qtm;o&k9n%Vvkf?a-SAwq4276c$O9G2sa9nANk2sN) zwY>QWs1F&AJsi6imqvw=?GWlQoh*Xr_i zsBnmR2$NUqK64Q$e0$cl9I=<p8d{=?Z9v?Kr@lyQouPwxQ>Z7YD-u}SqPC4wn`}!e;Z=4LQ6xvY;^&||x>2x1 zH^b(4tX1*?u48pa#AhZ8E+{=7o6dEW*B;BoG}oI=4TZmtxRv*BL`(7M;>;%CK2aPw zj|{plls$tABI7~^_xCZ!+R7J(5pg<0%EoF5ABi5!yRb|`fRf-2@+vQN*or2p$6IDQ z6aFPriA5c%%x%T^Mx%Am*aH>*0tX%J`Qihf3j3_21)N^2X_{h=4M7AKi8AK89efa* z>e4qN7Dl96JF>qw_NZ*v_pg1`H>K&-5^4$G8^KQ>rj}u!xAib_5|%&*OK5qaNaT%Y z!G>AM?cz8no+eA9k=kRu6{_E-SonK(5UsDq*o>cES{ZZBH-n-795v0{FP^Qc7W1u6 zfJb+LfXmyNvHzFLBQ5JonTr$1%WnXnqEN~4_`OS3ZgX!ot0qpvEXb_k zGgWg2%9<#s{^z`M0sA_GQvgmCEA^`;*j_<;!oCXe5eMAIm|(>NlOec}#|G(bAP^y) zu@smY*5?ka5GXUBG6)tgw<0L%B0U-C?{&myMij6`gWaY00$2$NiH_5jq#aF0|VbWC;Pre&Y63dj%C?0GI!V0svbS*sa?mIN0x9Slf!A2W6zu&R_2 z>l_rRJm)O^Ju8To4>d7+sDCn!20BkE|{`1X{dM0;W`*=V& zFC9^5@TwTXv>?AG{Sj3@n2(|k*>z8SRIWD>c*maBsG`%C8Y|EtsaIOyP zn4*6cYQC_yudq7cHi_Bks4o?t4fTGlcX&=OstWJDGM!!~`HUrVQI|20TG866aazEV zD#viTX?>zo$lZoG9r~TL{Tu!}ld<^)WJXqDgV98HPX6?&q+x}ijOa%1*lobbVsHKx z1iB2!!X@IUJ{1TSZp@*cUY5bddovI@)pn2(W_+*~SdS9NspQ+ftaeax*M}BEd?hFx zw@o0m4aQ1MO<+Kyz>vNHw6!YvXzuPC7F%}bkX&GrB~CZ8gPz3Kg8>rwP@&VK#R+XJ ztcW0?nrJ00lXOvy*N0AUSkuE#Ljm{CYg&&q&u6Zt4a|NcZX{zYc|=UH<+k-%WbM7* z-^Y6!^0gRkQeF*!_;Wq>f8$sv!y`V}+riGYuKOp@49^K>FqUbUeu@8RIUKIfKAf4s z_%)X)HsdRg84WrWj@X00rlrx?mkrcqa1Cz`au$t&V26VE27xf)o3l5C*89*O6$yLH z8ipqd4|4-Udqo-Fh8X|q8-xxdviY~wvu};~#Nbm+#h3&+=bKbe^i={Z%)h1j5qI-q zo;Rb^MKL@Pi)!p71O2iXUXCj;kM^QU>HG7N!}) z@_01c^HJC(R6@78cFcBu*j|3w%(U|1g6%phA%TVW%M=bZnf`>?-2eNBqmZI?2ZBV2 zu;|adBM-m0k`)8@M9)}R**5RMW^Z3(yC_YIw86n1@vsZl3??LmHT7aTa^qGw!aTR@ z^SEE!b*j?Ga?x44UmgR~tn3zXk_o?q(rA=ZG_H1f0!rFHm1K?bn<`}eCJ$Et?WwUr zxY@PF2VnlJwWwYeo3o2E6^l3j=2*|Xas3_Z2t9mku*CtvcWrunUbv8I$SYEEFy}uU zg2oIE=~k)1$GK&9H6LVYm~0@y52R|kf)5*h`#w3S$^HSOGHAN0_L z<(fsgu$3>yNg@8i!3+4o-wz9E0f~(ar_Mk&QN0Yf)NjvrT=^Ny5PclBz=byhS@dmY z6^WjG=3P|^@r5A@k^r8L$HifRsqzTtI8T{uYZCt&BK{ssat_>l{ZvZ1#2vLnVETST zq>6rnzAf7J%X$>&abZ*6-@xdl&Wo)-yy)MU<~Vo^JmRLneIXR#p~$Y+exCmDu> z`eV53O=7nXoO#q8Z@TgXcl>9~0mfjgAJ1b!*9YbUW0Gtm$+V6u!PGCDY_w?o6pz!) zz)aYsmis*Vep5Ta8WY7-kZVlBgRnzBG;?574(B*GpU@FwLOV6{BNX?+@bJbTvD9f8 znwp_PTD*nivmkaZ!L&2fWNmd6(B-O4Sp^SUol;XIpfA2ngmc!E|V* z6gEiSBqjn@@J`E*Z?%ZFO++$NM6C_!xFiumoXfz+1rpBDzF!L6!=*4~&a(HZQQJjN*tY+NMmjr2-iKkpQ#A<^EG zkrVNEB%*wo=o(l`PSEu5OHg!~y+61eEN__yG=>sClvHu_U14TUYM&n)ZrqDtT%&-K zMpK(9)H`Kt7vtD_r7AzIL{bXb3(H2E#d9YhUEU6?+mP>I_NkEw!YXz+m4{mcakGuGkPTr?Gn00wCPqHENm&St`$k6z>*SJ zQa-Hf?{_}-`T3-*3S%D@)5=<2MDkO+edoSd^b74}2ZwXVH;7N$ zQ~Vtt*e-e-8n#@cGxq*V@25?=swqL(Hqf0;{N&5<+!-Cj*g7g@UiR~KAFoZcLchWa z1Dk+HJ3k|VJr4Vv7(}a$kU-ZRE3ksJ>9%;r$EftCE*SzM3}hzVl;urxmjsg75EH4+ zIim}X9#d@4c3R4pdN<$J)CYPF=2PV-c-u-QIopO-T7g_3Z-ll9mLlJ`|Ga$ZJc?(S z@NK4O4ohEFkljD2`_QQQ?XqlIEg08Y@>{o-d5xT?ySzWp_1k%hkJH5MwLFheA1%$r@>NBU{t>tX*UIt<~hl@-5PdKA}+s#0!=7M%GLdkvZ-3i}VAH%PBfHMry# zoS^~EUKGcGL=Q=lVbX^M_jm=)f`DAU3)J)F+ARX(+_`~YS*qn*yRGxl*#hIXc{zs5a|V??WiJFKKn(T|8!(2lZ(4&@VEg=5S{H7j2hxio1ITRM)^ zaEiI$*O}y!-tSv~0{*jw)oQP8z&6U*0i;?e@nN{^_BoX(bJ4cAM`{wU$SU1*)@usI zRiap{99c$(b_q5pl_He42?~-nFq#nNg1ZFWwx;m9lgyp&j@o_^t@(c6APc6E2uxxK z^#LRXXU*>LU=lgs@QO;({uV4j1}0?CZ}XKqu$vyvo)SYnkduo>fyyHY)8?(Jm!m1pn=!)3CNVT z|F?&2=noc;0%g)tSl~FGc9n z7L88@MEfk&9!kV?zwo9DnXh=OuBp3UNso9d?zqR23-XXV8uQk9`b!Wbfg8P+X-yQ7 zl9@3v!d_+E*UT_WLYeQZv{3+EzFp6YKC13kMFDV#AN-0wy5FBfXnp$e+>Gh62}Sra zAKxwSKM$8Go7Bkz^hlX|T29_|d%K;&)FgN4Cehffx(?)hp*G|7EBE1*OA0QgBsen{ zt>nRZQdbgTw<|{&ILux$`*!wOtY&MqIyaSN#IEICG=nW{#cr&?ZCsKxyRSpeh=i7d z`6taxahjuqem047bb1K6U8mve>K(aeqJ*90Jq!17oh zs~$NFgd0bSU`9%@w0OoMT9Vkm6ZS-l`*flIHFl}Q+_yOB*u37zs;Y8*{ zo|eTEEuiJR#{cb-4eJ$5{!Tustsd6{6FD|I{DPBeK>@3z&(cGB5zLz5Ut+QYtN8G^k+ z3TZj1ne_9HZuy&I$2k{&z^adnuYV^hwz z{)UlK!>zoX=Fj5V79-Wbh1sdShNhiv%O9EoPDAy5q#Yo7GaeNF<$*IShcY|Wdv7OL zFhg7e1`1xx2Epjd7SA;)Sz8DI4PbV}9>?FyU&5<~?k{6SADhv+)r>+v5xM?;QTUYl zs4?Mz7pWoUK{@PhB$NGu?(0(D@X4x?nas^-kofPxmALV~-8lWlXq(|{cb}N%YkL)& zwpW_h0a08=MAy&rl&c@}pAYouVG|rxWfi6xaNF;DZS$Up->*`if+Q?0$;rFlxVm*K zA}X2@RyJA?3+>c0HoaXUMME~?>{l`)_v85Wy${1qOy(L=MMtzXBOCM`E(34*0w3#A z-^1Q!ClkIti8TV4SQn$VTT8?&^rN@pSbxmOf-IK*_6z3=!zU1>_PZdO6^;`HZKr*= zCGTT?vu9UZpt$)a*t(!ny$q&|b@TVH%2GQ(`+X=B$5FjK8ZWJwKwF-m3N6sKx3{8B znRm(Ev2(zXzT5}Z4dx#cRsg^}x;PbhAC=mXA>Fjv0ZxB0_nMXOJhG|;tLzvvl&5#f zLY3=CZaplJ$XmtTqoo78W`{e)_yZ@~%YM{0H0UI-m)E(r_Y$X;qJUHpyK zn6X;s6jD6>ip6+7cuPa?u->m|fvH!(?R#-4zl!T-k`$^u{yZ~@;L?F=n-R)<*x}f9 za%%CxPEfvZVX`(b_;3n$3{Ut6X3FTU90?D3+XLiH7hm_~X$?zg^?_VU_Ao#pT90o& z=C>C~tclfgug!Uji3e4{&)h^bWEaFdt{35I>*1*nVCjYgah6)^oJMzRFKWc!PCOHm zM4<$8sc;HNVhfZvcTJ>r{*1rzz^+x0aHn$RxCFr5=I`AiKVMTkW8{GV!Ci&+alUpc?%Z{)A? zjdaH?jW-$LOOtb2XW0IWG@P$k3vh-OKdb=L+!>|M^ftefntA!OswCuMOc+K<4*S>b zA-_KuMfTjmmvkGqgwoL{;N}UC6>Z$=t!7vvz{@3z>Vn$L8L}yKolV z4iL~o+1X6vnG~JZpss8Zhnc$rbx>jTBoP|q^D*_{z&CQ7>gI&X&Y|o3?XMI{A+h)y z&4ITEi3B)@StQ7(k2K14x=ts3QbA!Y?$!eUNL;P4P17;46(t8mZ`z5+$OB1N@q?3? z0+P}p#V&Eqas_EnG4DYmiF*^ln6lX(S7>Uh_D5GZha@gqhj40l_8f52$V8{qkXN_B zuk-Yk4l7Q#t07&{gPn=x_O0O0apB@b0e4&8PRDoY0BHM0*!xhkL|oi^=- zsto$!Wc`wc(}5!-3N(}7D9=3HJZ#tny-UFg@W1_(umj>h_VLl z6!sr^#!N9%i4XK?uGSUIwayMhP_+@o!90p`h&)<#8_cdWqQhN81B9eG!%ZHz`sf%L z^AGkDk{XU!&0rIA!Yp*#74IsS`ixL-Mo^|G-;H4<1lZ0Mt^0IeH?JVkRf#=bbgWva zj*3SZR@r(kmCe`V46pPz`XZ347Hm7;qrx)3G|@SNMVP>J=@*SfgpHlMp@WEr@i^8u zBeNkNG$*5%T5P1hY@AuFCP)l%tO{Vl#6#at+yAuuS&X{MmaMs~JiVitEQ1~*!#cto zFYvsjMQrPFJac$-Ht-Xvf1CdpO?kr@!__L}P8kc&Sbj=a371{701}+?=UD#VVXka2 zS}RN=jq=!BczJw=t}%L5@-pW%k%>fu<<#`-b-pdG5>4q|WxB*&kf zqfLm5N0KjPe<+>Ofr8^Sw++iT1w-%l2$osu9zol~?2&|aC&G~;8@=vjB}a_?+PGC} z>wz{0J_ng0;BfdVsMXAe#fZPK$6qT1L_5^K%owa#G#>wH^U3TGT#Uy& zPh*)Yt?0Hklm2)#_&lM#0?dudEEZ5H=tlsvaBCP#;p}wk;8}x{w;$jnQ*N;B%p6xk zxlc_4xOERH?w#^)UGMTARSoTz>xlwKU-VO$$oa_^R?^6%z_jH|8Ff-zpf8e-)6Y!0Cx73Q@!oz5fa`g!&0r3D-UO_0MqB z)f6=cONS{Et)EldX0J1e8Q1mQb{o}X#HOLk4RMSv|6(NqR$oQwhbDne-U_ZO5itEHGJ`pJCkzU8e6&i)^8pl7@UC!@?Gfr3|s zP@6E(eop#C=ylaXzLFwGm~L|U-QSOdOpjH+lNN(ClOFWYK4IZhP$2h4M!Ut^08%1l znA8T1GZUivMNtP|CjK=0+&9z7)oeEvmFAkSBrpqH070S+2FN+fbb$DnBOEa06@QNZ+F*szQ4^OH7m1e2n!SyxefvB+-f>Ky6??y53QXaTGcH)h&EX8! zgxR}3@o|_V4rkXZedOrf#fvV;Vn?3V{-+Mf#nI0@Db!A)`lws+1<=YB`*M$efsSHy zZ$~j{jqD7X;mCqL>oddvPyTGLsk4LHY8kuR2ThObat&aOwz+m*fZ8@Ne@@yKwJ|%a zP-wZ-V=NMTR^E+rnQ`1LfklcRm|*9E`8BuldZPuW8|qgsl3>V?D)ujOCBUJb;}YZW zQza?wd&@^@sTRL^h+NB>L}IbPw5~w{T|{b8`MA?-BN|G6)2Jw%)K~sZUveH@P^me9 zjA~S&M_4Bi&3{&L!)%4Sxy1TVjO;1YCtze-_Fpt>d+5PoO@gOGZROR5-e$m^fc;lV zzd}nc(%6T|FpaBzCvpQNnm1SA$82O$8G2AkX97pRdj`ofrM21y!>fTL^=~DeFjcJv zC(_fb(e=g?MS@SVg{w(F{Eo!-)WuWg9C$t)mtBg9`O+ay;-(?q_PWxUi4~IxkBE?q zaw1HG<>@1Vs#YzcrLzY%>p!okHM|t~(N;tI5?WNajHH2>)LP(g{uk0fSm>Ws3bbH_ z)=xtog8Ik_bQ140rXc4M%1^0C${`!;pM$Jo%*nV|Qv~7~ZLPINZN=3hs$3f8YzR9v z6Ej=D<8^C#>JbH05%nG}-#sg?8v=9*ypl<-_;9<7hy)3l9CrY#B0zzX2ckQYLM9FQF3@h3`hYs?Qtbda`F*TBy7Bxgx zkqSJ558+@ywM{PSI&j=wk|CZ{6&pgn!ixT%;ianP@T6sJ?xsFr_l@j2(r7$sm2al& z4(7&p9V{ld11l)(6~JbANofFe<}8fMV`;aAVgI{5^(>P~qQ*3w;^WDjXkWG*lW?0J zQB{TpJRfTcbs{WjHT2|#&y3BlRdkA%k7`U1g>dAE6$)z=rSy_(g7?UN0ouToG{TRM z1*~!h1e>}2s#WRMLp;{xj(Je|LpIns)e$rC9we!PPdF;2u?d){m{CH6B3mEaK5fc! zU=GIf(|&robmlO0RX$}u7mz>YHfbU|FU=s#j`2`jpj-^|M-{738w)OUH$P*tMeF@8 z6N3RVK!<-GqJYUj?;{WL$EPryAm|Y4cYm5rKjQyr?)zep`1+B1Ihb9Lqvsr&0I~AF z6$RWlgXgTu+3HyPlDpA}KsIIke#s3ZFgk52FHnk-{D|LZz!sRV(NSC9elBDT1p$>j zoBC+>Tm^90$A2212WO8;6ijd~+R4wQuN>@VaAbeB2AB8w9o(Gx8!hUPi`XmyIMJN! zswIU+*sed3@^wSGL7sCr+U5ZQW1?9{lL*gLIFg+uIYai}Y)pACbTW$vCnI1~AWrI@ zS(!d=Uc4o?V#875*P@ZUcDScWhq-np7FNW zRXkUVx&jQH`&ON|##vit-H1U%(MQp;M#P#?v7LIJMC=d;niA3Idf zm%(tGtiDZKa@(-$1kt#Ib3rqeoIPr0I1V5i*Nv;<&$WrR^U0a{G56We;=1>|C+)f~ zIz-CxIY|4SC1sYVK5IhPUaHBOB8=hnD+P*n;N@G4S7dKmVJL9w(7=QV5Ke@^BN|F~ zaO>M?_es`^yz1)9K#v4uBne(gYu1HapmzYLA)+f(e;=8_o79DS;i#Bd+=iIo~b3aOMNDGIm+ z8*FHz*fGl~pGYl|6x{MX@PB(L=1^Quka5R8xd7lJ7n5(Ag<2<1#LwT4ddiV?@_DN~ zl~dW}zi~fi!v}-oX7EFE%7kTQJzty9=s+QUJl`^~&w1#;3hfIPu7kMk&6iL?Qab(D z4VpI4KtRjw_z_KjHln{4*TF^U-lIPd#vkPgW#%r{{3dT>A(hAQDN4N|0Fj5$A^i!G zGrI1&Y5Xz#dQ~F_5y|bDNgFlX5>vsb$ztE)RW-9HBs4S*&ElT#cNhruw-tq|6h)cG zOh4Y}rs?`@ukdeH@dO&fiPc$dn_AWJ$i6X>xto%C1+MITGO7ozm4zG;9f!@0BB#_X zp4(&8K;0Q$FK@?-S)y7E+$?d9guzKZ>{=uW+h5EymCBB76!OM0Gge`}xm~(<>Beny z@wY(opbIoH3Y}s)i*8%mbR3oJ1C6Ih@j&1Hx0KUP5563n;pEAL5DNs23_6}yOF!Qf z;1|c|7Z6#zJ;86Y_WSRGNkXdvRm-o_A1e0t)UI`fuZ?#&J}yc5wKMu?*O)KuO`&BC zgn^m{GP`y+yNPf{`*i-GWv~txGhUmmpTy+XwT0cuyA^QR&}ggF+}|rz#zh&+%CHWs z|Kc1i4&jNwIabG-4fl%sV=OqEa`RFv`YjhHoyt8AiwVgwR!~Tl$|LphdqPoqnz9MP z^bG#Nkbz0;?A%lthhM!vSa67$uMdOZb*$PrkeLY^GP2c z&QTPu?jj(AGMG7 zE+8odR&vELS@>liG3$KHes1KkCJTznV0xWKi*(8AMi>iv0-B{s2ze6+RvxQ;ip~A) zViL#-3D2>3lkc%dIG!80_`clH$2hNM>oi{(SZpQrsjB;cMm~FiMf52~ zPN(!flbdGfIP6-H+(zd(IIYlkQbdRxEEk~M?I&XW0krPsd&_?dQ zGIi`rI$JKnv`Kan;XCOO9X2H^OYe!$9aQFZK#a%|w;RXbg?hH?%9*^yTAv~dCY28h7eZEBz5kBOVwSl8SYvkC=-P?P$#w zc$i-Nbg=f&_lsE7;o#Wf9d|-=g{jnlUWv}kQfcn{q z6qC?2|HK>9L%u7RN}`V=A@K#V49@el~2+JviVTR~cP z3XI07=sh?3CdDK4W!^&7Yl^RPfgdIR>9QC+O>R_*b_{G_?slmao@a~b&>)L8v({%( zoxVv6mgFD}p62&gz@*Ao+R5bzA+HD1bvb=pc zw>g@PR0Z2Sm!qFO(D?j6Doq8mqyGqgo{Jbr{@u*Lx*mpUqtP}u&UXpm@=Okqd(@VA6@T|f&tDL+5cCMa!E-!{~3g5rqBJFdaXS`#0>{pJuF(*`+KyxLnq3TA~ zbfs4xvNi)_u`rZB#iNri24SnviGM4{UTx=4_L?*36px!@2{Bw z7$s=I{*|eEl^VhmyfAv8|=s_X3XkO zkuWtj3}GKW4EG6Gk97(QsL=P~(00;VRGZt=d0bhS<+#pply zPDtauNZ3z`hHsuum}2xdZ4>B! zHQ%4_^YI;a7Jwtv!Sc;7;dstxUh|6&H*1Q73=cV(bifNJdqD4k^apB-fbZHdO^Cgzxo z+*(6J_V5Fa$>&oeuQ$$yY}Orr8@C1CaJ_5k63;Un+OskLpktFV*A+vfo~~0st%4J> zRSKkrt2$D|-|D^mQO1{YZA#&wzTOk=4{FTPd*}|l!f(}|{(h)xY)z~`s`&SB*O)EN z?$js1(>z6B_npdngMX@te(B($`+ZJh{I2snSj^TiiZJNOVhK?Ua_z(YV;h_4WWPO7 zm8CFvX8(vgW0nnDj4o;C zTh7kNg9QjH_sDqv02pDe!qBll>3?@<$(M|{K>@i-t`0&%yE7a>)SGb!_*|~`MD!V^ zP;d5v&i;|^`zp3jlVx3-{rHq&wd3vFog?AkY-{d_IWe+F+gkTw!nG`pTn_$URUwil zUu>d3mudj=eOUbsIv|Om#kv9?)n{f+eGKalVEYh1M&F!VXQXU&*T-UfzP9b|2jHw5 zIE*UeA4v&K2LigO8)(t%E!d`)KMwzfWQxEQSqy5TO*GP17p5q0R4H*6Zl198Mr~Ww zCg12bCr~K41qiiI(k9Lo2?VP+#1oYUhcDm(sC@~Mp{Ds7V_BNUU%@*>Ax}nt7a9?7 z1q8h(9p=CG>p2#CxeZ88Qr>72N8f&eN~_f-eA7@S>u4ry6^lY`+1-N^5$DJl5eXpZ zwv2uV<|XIJ0WNQVGPI$~u&mO+RpUp`9nksZ&};jgiGQkOjeVGWzIw4yipZ|_BeU;O z%8{rEK}yiKRwCQ<@O#MhEbPJ7@RgkAha$+8|}?}+cWuDq;xeTw}r zGIHv2_-tI5$hO^11Nep~R=5&Z2^b4VsBp3PdI`g_ow*ygi&pCaJ6$Cu!|jk1Hi1zi z9NLi8fSz9G>d)QG-fo+a7;-DsMB(=ILrF5!kk=+WW@PDyvVh}^)QZzXQ!!g4jVp1f z->WH&dT7}cyoZOoV56qsiEnl)U5pl+GD(f`$w2ov`Yluc&$%QJv|+EKpF*K8OLd`(^3g8OZu<{Nip= z(Vsx;wALRF2IrK^r(HQEPnq^RUrw6?pGKiuP3nOQ&*b;b4te2o4F@8tO*I#~kH_do zb2X68`!w6g^!W5%;B%!yYCmYo>nlk1+W%MlJk%JykVE~*DYa;t;q?s#@5}G}RWXQ? z2Qy>#yq$}g6_2uvtByjkEqnMUX$SAbrQ$dUSEUA!01=`wa!RiZ!cH@QXh-!ccWnHUwazH-~G{gtYUV9vA{{_kCZlz zJWc{YE=jr~;K8qQooz zCrK(AA}d5wO3G;?fZ)URsS&OTu-^RdC6F+V8CzZyCDk(VTRB3rx1=5Yzt6Pje$sY07RxTEP+zt@x?%aGL%8>!z z#~f}w^1>=b!*;SBae)s4&jHtVCZAhP>OKDDUAC|m?x_NnuHgf3oB09#FB*wYsa|i$ zT(>&Z{$ir?VDPymx*&!ajow=mPYT|!)6uM(JY)B$wx1jGDvmkdGLEWqyi4xSU^)Im zix~}H2z2%fVWvFG+(}jP)L>cfjG->uNu|$J_^FJuP8LgPxeC|HD=rtX)H(6Hu1B_B zbYk0&uh5-`qN7I9u1WCe1fo!PG+HYbn2wNe+jm(^FYMrA-$(W z!bxV=ieGm^Nej%Va*tb2QFK-OeJCGwm(DtW;xivBU6Q-A@IkE&EY;#sfHKzM7jTe{ zyqi~(yvI9QAk?nBfrGg+$sMzkP;1LAl*3eh;95;dg%*ruM)n1aJ;MT~#GSy^ke{Ih zL{j9Ev}1Zc@s*oZSg4a0iFS7D_hMJ?UguAYrAL7_Y1)mS{l_R?ybVrwfDgup=f#5~ zQ=hh+PRpULdwJHX{@^HdUP@YNja%j&1u9xf&b(udF`1+(KoXib<738}(Z_=FB@dKS z=x4chT-??7={tq|*Xy??HkZWk?7^3Z2D7Gq|1U-*N1A`knWEWjKOY)KK3hQ z3=G?enDj+*B@QYj7wL7Ui+FcT+xH99S>LV2mApWPG%}zvcW$qe+#>nFaypKREZT!R z{@$-Vm~E@k1&<0<$wM-f>JUBqC*B6LLxN^H-OSlH)pr_h&HHq8px>81<~il-t`ov* zc_ke&lK@F_jL@&rgmb4+-=0@-vuSs~bdTDccw#cXWUI%W0!Gz7N^;N-MbjB# zwXYlNG<-YXF(kQi;b-`b6Hp;Y*TC|*@6rVDBlW*fZVb|3jcP6;-E4l_oNSLSfPLit z^P!rvtCJ3!N^Lb>Nq^0RFgH3$5&JD#2i^2|uI1E8UTZHg({B=jqnPp^y3vJ8?23*@s&cJR|VYx%yvXS$-8KsHLbdt&x3PLYGR0 z(8{wXx#>n>PFi3w_q*=l0V|;n?v3Fy2uNPUh|ZmZV_~EJg;)E({{^rjV4!wnu49ah z9`cJ4>bcibQPLx5{85Z+yo**^PDGJ^QC}t^tl@1g1`yg2s!v_xqDmMBb0}VenZ7Jh zQxaPc{3>Zfi=0|lXU#DH$e=OBXFo0%o1;I0jpPP<)K!9-nP>InHaW})o<(Vn>@A=T{Rzwb3MDe^nRC+`-?Rk!OJtt#i96R{s zn-3HH=_RszKg}CgH-z1vFV>Lomf>&$KA#Tkj}Q6y15z9`;acnRq3vSK%xWqY73Y(Iu4K3#2&T9=2lWQPos z7vqfR^q4H@*NDo|V@HaqKPtA*Ee6Z);DENc)4Q}-v)3wL5*4c)J_)J@=8E(t=snkr zG_P+xe`}|B@<;F8WO(Ve!ru0fgQ5~u((|R5|E&*-a)K5})m__38j@6!61dao*kS48 z%SH9~r;?6~gW7&G@m*m4MoXFZ5F-mSwZ4ivBgb4f{Y)He9T9L^)q0f@Ew=vD# zdP70p<0$Ajwz$K+ubxu#s-P`sVQLPe2U`doLw&OTrEtX-3{(t5Cr|w_Ts@dxLeC0% zrwqT;Tg%}T`zVgj(-rkIJS`9n5x9FSl2x!ao&W9W3NQK1@Maoi(YS|QbNQ8<3}fuc zwR~Wv^$Ek86UlQNh#|f%yLHK!4?ov(qtMa4ObFrAgoD4dj3e`Z>5&dnJ+aNVN5Ai|m^a3& zqbJ@sbdpJTOg^wia^Y%;{9&URUDRzN_WxWQGO;-4HE~y5qTrCd8$i^M4G##cxEgDu z&Pj1snE?jSQ!38KThI9@{&`nE9yKidoWUM(Mcsk`fAY+aEaGR1f=A@){ zBZ6o6m64wIN~ z)y}lD(`xZ2p`t5_LCOax!Wi@(IGy43Z@N7^5!bm*SOy27)5MJOJk3@8kdDL&=A>@J zf!Dn2H|AP|X4S#YuoN5oX?n7(4Tz(rLl=K`pC+}>%%7)x(${l3RTm zt#{j)`BAf_8PvQ=xIE^WMYBqfUbI!_Rdb|fQng{8I|iYUZcg#7ma???Domrt@dbNI zzb}Z`>yTK@#d!U~`u!BktoZ3)(TCJq<%n4NWLj^r?j0{0YA3}= zz9lxpya=g9lq8GUHYUS=J@f-{o>$qA%wM}(jjgPQ7E6L_fKW|!H8GHY8OLdIX|bb7XG z5hB8CxHz&J_7#`hfpA&=zRI3z5dSv`J0dp^vSi(`q!#70kM*V2G8kM`vRIo-zn$jF z>t4Sz9DjF~%lFm}nnSc$ng>TmcB|u%tvgHmH}}3N&)?@8Nw5w{15k5i{3o9s4KluI z-+(B|KlD@5O6VK79kl-(ID$M8#-Y5e+ac1$^PnBaS>6us6idv+_2{r9Ck|@;5C=QU z;xOmHW_~4D4qA4?I>C;UAD6{3&)X0!XA9bSk2BlwE~M&3Or$@ES@1Yc?O&cb6=uOU zY1HQZ(EXdeo@W20skK*{^_H1c_Lat^F#rAG&~un|?gW{dU?_F%y014c1`(2gsm+p{ zh+&)P-fB)389p`l>9=DHCPj0Qv+`aZJd3OIc=$S@lY?xmGr-QqKy65hXWQkC(gFIV z=IQ+x@(YFsK;ECKzz<49r&7(e_D9nG0H7?B0Qd6*HLaGGls)A+9A>PCPlTpBBe`F8U>u7K#Tx#!NFzpnBESnqkv-%$~K)J>J!l{$HN->9wnINxgF^d8aVISj$<5}HAOtEt5j zlBXu953f*u?G3>&HD0t?tLu$wZW>a1e5YDkL0b*sI)AEv+SRw_@hEKfN2PHTkb2Bz zkQiMaovEJMSY{UCP&m39=SmZqOX5hbeDHkx(oE=5GY%j+u-h3rQ*F?JfI-2fcAWKQ zOf3g6pGP|iO^N-GqB-#4w}U7{)^s@FyD+u!rHFS0sq!7tcvm{UJ8)|nFs~~ddy-(J zuZ_E8%wYBL!_^UWT04N(0H1lkuMY1 z$Z7ZY_yNvMly`#!u3RM{zM=2bnF>Xf~3#sPWqL9B7N4L5f7=)j|Dr zwqmhh$;d3}f3RIT`$+VdKlBOG$Lt0q%kuw3>l=^*mbd}CCuU2!SR} zzcuS=hSMj_nUU*VOnbDqHof}}c&L*pMAU_*n-H{R2->CaJyKidIp;ceL;L68Jgvcz z{rU&`?;v7ZDQDWs{KY3bM+$N9xBiY@%2Mcm@9xx}&r^h`7=TCth!Zbt z%a&W`ZI6v{Oe$ws5uc~Bu(M>*5*h+xH8g_$)`w4nsH9v&nx;@S)cU?L{ULHEA#8)DAS}V6l`R&5g&X_coT~Z~<2aj-he66&jJBfPCE{-np@zER#g3c1VvU zf*}a{E*aZNjevei##++kqXy&{^W~hyW)MnEg@%JL>bRi&&PX`f6)NTy?wi^cnS`UL% zJR@qCsDmPs3ZENIe+;bT(RNm-hC?=|Me{?m1c55#%s{z3FYI>)WJ&L=MR7n&3=u8n zBO}?(^EzVY;# z2)AG?D`)meyd+I+e6}L;I{l0quVqYtnh9NZ@c0|W?5ws*(j`fAR-q=v;huB5+PMwF zGgxU6YwP3;zFC;^(R8T^GxpY2&(VHAWjS!#x+=ci1xf?$9ib+8$<{evbD&y0%TWhQ zl~jHwvtWJcIvj)BODm1|t7i5ET#ju zo$eYlY81(m&h7d;xF(^)f|{P_j@jp%q8*^B`8mj#zAtV|SgcqHn|=&Ng138Y_sIuK zEtQ1Hyv)RsKfL{uCw;;e(a2ezcx?HQ46Z?-%%_vRU60W}7pGPer$hi!!&eZ9b)2$V zmYbsoU-qZ=!}8ji3V)CIMws$kmc6GgC_8cU`g?!c8OzLq2sZjeO!L%+VVvHTSFOV>Qic zzC$~Qi0U2sS zxD;bzIm=M7Pw{%5BN2@VA4JRUJ(cz-y1H0m#?tml>MmELDVIbnnN#q{c;eivjkJ!uV^wH9WEG3w1%7AaDq=CtoKfakaFbRgnhu;zzyLDCb`t|6a6>Iv@LE0^7 z+E_(HWatN$_P4IU3vzs&WGBsRj)Nq zR=+d!eD%Bh>09%OR#`+?$L>Y^k6y#{b`{Og4|ZOuUMKAtv{pv^R$HS}vrDL`)%w8h z8{y|`%ksH9&rsdel!HDe6X*0CWg9KiHtl89(hb1boq_FftG4M7=3dlZUm z@gK3}7w2_%NGNKm5mOPoGLcC0&le1PA^oq=jvNt@4Q7)Tuz`S0vX?<+38KxuOI`hAng1|L0a>=#^HQjzdF8AkGC z{b<_s1;R-XP6CiHnpM$K{Y(SUhTvSGT#^VAo8iY7o!XYL=Q-_ZHnKMSJv zs|AsAox+jzjcVcY?c$$>HciKQ9pIaKeD_OiBT7_9sgtt9Pmh)3R8u(ZTONs(rhPL4g|5GOUv9k%2#jM2n?&WSdGPwkWW<1q z2Z)ErN6q)-9Xg5;(hd980=bgB7`JG>4ssq^Otp<$v~HzqNOK zl&rp^=l;q+{~Pp|08~PAQm1|dvywvr`nn&OnhSzoR#O#YsMW2D*(|jD61IR20TZTXz`tN zHrgOzEY1Xxy$Pw3bQ|zPpEs8o`rkhJUv|IPe2PG(Hz2ts(zrRReW4Z`lQB_3pRmX; z`TK=``OEvRON$vo!3TH*}%JotysrMzF*PAr6amzN)w%CK}B=dJibtp9b;ALM>Rk{DF!8k1M$!B*V^Xg zv`Ii?XVHypLU2j%@fPG`{`$RY=?tcD+T6?k;KK*UY`=xtXZkn(?g#djw-5Zy&v(_% z9Ykt!WmtwgOZ2Tcx=X11^S3@&x9<&w)B8cLpXU?=%Bx7C@vb9a_h#qR-c~ta=3L#HAa_nXc@<Ke+L`^fSN}EX$#E9ZNHHbbR5*2Y$Q|8q^+DwtLGfsWJ71 zN^{*oq|l{OM2V-*+(REt9K*@8#8EAtX1N zQD3f6{)`B}IXxCWTdp@~Wb-(Af7v?psU??|UHM*qSEkwPd*ybJtKPCWL9+0_l4R|) zm>o>0hLlG`APLr^;rEW6ZAIwR?SSJlGqp&V>X}w{+`cnE7$E3uOzNyHJK^%St4~XL zvo=#x?BNBzb-_>z0_=Z{3|mj!xT7%W4r{-be2i2z=UM;0HXg@ zEw`A>CP8wLG!Ud_LH$a?UkE2|#U*7HAx{PpRV(q8p-WM=kF{RH2kCx9QPrgQ1i@Mt@W*lh)8uDdB-@9r&^F^nX$E!dDX&llJll@# z`XEwY(|g5lfAp?bu3N6^?r3==GXFjk<}O+#2MdYPTqy~ROT?!R+t(rBYG?*&50Vp_ zXtYhqgrrD^|7gpcA*s?QP0@GfV zu7~Nf;!H=PsD-A~d^&?w0;iU2i08w)IEYxjl1F?!xr0x#?OHRTGfQ>oHx`=D=@$9& zCFl#}Q?sv{O3NY9cArZfeXR9LIQaV#cN`P4WUaqE^|t-W$v!lhHYq)M}(rb6GthldElJA#I@9S@61Qx1SY608G&_Bc*a zb7DswZ~&C6o8%zq8?iI@Om64t8|5gzOZrI! z*(sNK+nrumYbQ`cOEu z>%6W=s2mv2x9@^k>5z}(r(~YgTo{Slfz+}YvcWayKGJ?A7BYSUr*5aIA2pFo8BEkj z^_uf+rD{G-VJcIzb7yN- z-Dkg`gFjzr<^u3H*TMJL(uc^!nI%J#DQErZxL%vU>W~9QbvG!eqUq4SC!E?TgEx0( zUGdc#BBqt=8#2Rl24{SHw~P^Wlw^#UUHkRB+FO3fm1L`4*x7GM*1{YwQtiPYT_ZzB zi29n}`;b3A%sCm$ZmF?!6J(HVb zg+5BYiAqW|C)n{gh=exbd*tHJ9_HRL0&#@z4Sb<=-YxVBJplXcwj2x`dQGZf#DOCG zMclz}!!0PDSxUp(6mOw*12nDX9*LrZpo6+TS^8d`V*zO2@b#-`VrD#p3Dwz$k0Ny( zEEn-roJFYoNb8&U$=r=F1TQo$hF{g|&4qB-b^z8l#kf~xkZlpQ`)&{nXAc@X>llOO zQ4@XB9E^)!75;G03&&8~r2aa9iz@_jER(I4A~DRkJIBGLWi4V>Msi zgM|6AC0VsWm`_c?gLYo~6itI_tzzk#n@d56Tq?&k37z@3a(pVtmnOpoq-l^Bu+?KM z&`qBpPCB#evpRq6PDFWk2B0Fr(uv&=5B0u%X6?`>SL^q7HCNxR5Va;t4VLCX#pvyl ztBEm!m9lSqbpLhv?e6vcy00GJzF*6KXv*zk&H7v!(`ty{uG43SUuOQP5t6VxBqw&x zc4&%Z%G8DdZ~%$Ula9w;J7zvHOU#9qIkayHKP&EApK2VdZG5{P#O3n&i}BI?p;ku2 zRJ3k|)H$eyiIWQy?LoeeRH&0ZrHc!O>5>wY16rF0Xld=P^ z5WL1RF<)ninWH8KCkQhZg$(~c2@3VOp-C*-Afy2wHXDNNPmPOsssU2l>R)N8rA^q1 zttT;S5@OHp-@AjkuQ9` zD74xc&ke1nS}n+iCPd5YwMHOWK9`d5`lUf9f1SZ4Cv}V{V`1r22^|RxHK&W6^l#Mr zN?Rme>%N6E69t8*;w zJU!m7);62f-Q{Lzvw%D05fCW--XmNfPkm<)2u%=VL*JzxIw?C>I|q9TNe*F2=vliF zzF?S6$8`xKDmoprJ{cyRg#0LO*^%DGjOMy)`YdT`SU!MRZ3vA~8K5xlK+<-d#Y0~7 zTT#p-*+Lw2Ny%@uP3|lvNzF+P1`JH>H(y4Z=ZiOK-a?(84T*AqF|XcFli@U>9URoe z!}HD)!QB9(4hTBRFCL&Q=5nvp@vy!$^i*ghKGXbA9M+-t{~7tQ2({p}e6?II?rhws zFO&AGLr*a56in-B`VQgGuomA3Srq!HNh}ZzK`6t27px|t_9fERt&Z1fVXRc!LNteH zkgw|x9uK8yh44qy;sp>>3wRGxW9vT**M9K8W)dA>fLfhL5WXC zQ(!Nx*Kk&xw{X9q3-qT_lOy4@yp}`r82XV2U*TOPN5%rPeK3=10D{b#!FBsm(NgF=d!v zBw>BG6Pb^7jox#xnt-c(Ye_vYmD=v{Ek<#x<4V57iTyN0z0J&() z2$Vn>NYrTSngxehI)}GX$k$XvVV6Xy;nMMahZ%?ZoVJD`Txh~1UTV6Il1%oZ*FS2R zG!^Q5wZ2*KsWn$mo<-}2HY?@e2qbz3$L^gylTKs}-y-^_i1%bz1v@wg0ZB#(#|%}V z50idXWiU`h?`fJG%C`=mk`;ZTyoSD7cBm6Q0=A!w+bP{42&z%pB|mEaHAm{GF2U1$ zV#nO!_zw5+JMt6z86L_rTfSqXw}VWW#~Ee_sy|qTFgXZ2^U*=Y_+OGtuP0wKI=Dnr zZJp`nAz<&Myv~d$wOVS~G~xV5+nQzX>ek%_C^P2Tbo40#guJl1}U|ojjLt5Rn&k4>E=x9QGydM4qq=o&?W_u^8nkLtu?W0?$ewVx8jJQ7M7?_>4kn}ioQuYk-yNmRQ>kw zN8*^|$^5ISyaiFZ$9bP?J{M~_8aP(cbKTi>`0f41@Q;Pr?xn#~1QT83x}#`=PFF9m zj-%^ReuZU&HV8VZGx;mbxK!Ke{fw_BQPEFJEthNh`Jy6?`4__Wc`HiAU|%#dYP>I7ws5S*=Jo^&n~1LbeZj|1fw;Uml`); z@W^7Mk#M=D=YB;(We5gMeH$|q)qTj8K2y#H9A-(IrolkD*WC*XIKmT}1_$pgW(f}B zye?iY4f&1v%{Od4#@gWE!OP;{wnr2S*^$J2-al=$X!|y!NGXW?&E(IxvSjLpu1zD9MS1 zlF5x7rk!?Zj2zAA^rRzpdUlK@-p&59?R`(8InwMH10^5&SZFF5LGx6ilRKDUCV})x zP~dl=A+ST!tm)uKR_LguP9>inQ!^FXF7`RokzM4ym@o`5s*FJ>^;9vPX1g)2@6`&8 zizJWqA*oW6ML5ywBg}|$pmiA>2Y*SFJ|%b1C>XcM5CobG4Jdhv&<;kob^tcSgP|$R zlXY{{#N~7>n{{VBTV^A%$E-W*OFuvNPwS*jDotN%uKYd3Z|goJe)P7eY^hPS2rK>o zVqJN0bv#}|N9-MlkLFCTEb($ZL`{GCHN6U%kt|7qb(X5^jJj}Oc)pcVBRQddok#@lk~CTHvYZ0ie@qKesvqGr4I9JOEuw>_8?qUN>y z=k>j|&!#?S6O=}6orKDJ?GSoIhkBnn{R_o)3jZuMU2!7kI*VCzqNYO0*g;l|7-2~p zwN)F_6V?3HyTrU2u+ z0@4`3lwuqyF>cs9AujG*FYr7w*{(kL)JAplE)npF4|HasSVi86`+PrM!?7#n5Fik5 zfpiFJNpvJP)WIxT8Z|hQq|z1A5$cCT$EOBK!t=)1bajRh3~e@CI9Wd~2bNgsf;Z-I zNYH(>L7La>RQD@|5^;AC9*KFcoTZmP;U)`@+#t^U5yM`UN zCKH$X@!FQvd#R;s^pbb$^E?j0a$qRtp>nx{e%5|iCmA>l*|1PusqQpp7$|2VI=PX} zFQaXErh7F=#h)}ULc(4PQ;h?*rBnOnAf&cqhBx{F<60asInliz6<*p;iIpVbQiJC{ zeFm*jHu? zSK7-d{Og<Fsc`7xdO0IlXF~qSYJ>>!ABDVdw z3crnb?=!t$x%t$onDwWL@aEHJ!w0qG3*x84IyW#rmVHCfc-kkG``8BC!%nOzZOu2l zCZ@z{n7$Lumyyn0{JEUG-<%!Y^qL0erZMsF5LyR^_Gd3TMnJ&v;W&AW76!pu!2v$y z;0PSO(cs`%yvt`s&r$NgPdhK)(2B1}O(%LJia|=BEIXD<>&wx(skxGj+2zy8Zym!`xY+c)uQwAd`C|HqNDQ&|BcWd1kB$(;^zS$R;ghm@-qhF2V0R>J8Z)* zxK}>qoAU||?UFPTSbj~Ag;d3^-gQ0aVB+BCUoC&yI2Rf$wQPrL?RR zfab{KQS0oCroxuPu!;1mQ>*0!h5>$$4De=5qfrZXP?7wq-&{h|sEKmkWqug$HN`p8 zQIhZtNRvfo4KR}o8m>WPgP8Cvd0g$BYeXuxHz$=8%+)LrCIY{xgGgOpR!XTovGE!1 zgn3ZE$P1yJDn||QVl?+suifg)Xavoh+Hm*P^;?l=d!9=~`M=b?x$mqQ*Gi}K_E4Gq zr+L@bWPf14))`{pw{Ouk!VG(q?=A@=x;&2UY5>blUPM{c+5Ik~Gql0W8`tujqa^Q? zb9$whRi*s!-`{d=hYi@2hmWJw{cJGb!?8hTq(MAP73nGmRhTh8~k^WHYQdX5_?zX zs|?uXN|v(>3toHwQV*8(nGSxEs#UZeI_MgFG=eZv7J@}rchGJb+sT<*F~f`eoa`*e z;693TujU^I0?Tm}rG-zG<|7AsYs9v>OqhZNVnnG$uO4F^g`|hz$qU%RKiDt?moto*4QKtNh;U5kY z@Rx`@zE|Gb7WN+V_g<1!ANx+{?A`yJetV5E=+)m}k-3As``#SSAGnhPG!%`9`(F=mb`8+D&p0I;kgD)Zbl_s+Q!~be(h>!}~mvw5V!+DGARktv4&0UcQ-ME0AtPm3L`zDXf`*+1wPA=%QD=sJH!Hn$gH zGdkiG%z;K!w~NzH%XI;LvzsEFY4$62qIU7-MV|&cUgKAp7mrAE>dVGAy=LA3lKv zjXKVq`ZPm9_{fD18QXrV-MVYsFAhj_T&Bn8&%VHC*t)IrJy8X*^g89$Y?dU!>l|zJ^rHWqcbX6F9t{6{{Gva`d_=Jw$?)HFhOT%L}$Y! z*l8)AS9e8rZe@$y!J2%F_TKfHhM~0}wPJ^B{@hY~6=$-cgKTW|uFnC44gP!m*v*f> z_JwzEfn*0eHCH;hUvJFCayOwtzy!G1WgRr$-VH_IT7*XM79;DVOd61MqFLm~G((|f z`n6B~t**p01~Q9E`ZWe6{c0?*8VQM+S{8>(O=lztoDB3>>bm$ixn7+!;Pfq$REMUF zYn!@WD7#=>CNg**2W~@693%e@&MxPoqrU!SYU*6pX98m5{bL3o*D`SBMI5{}yD5gG zxQ*t{8G{Y3XFiH9rCa?zGwJ?f>nqWQjMFChw2apq^MO_P)M2i(ESgrsbmK+I|9!Mf z4TzUS;x@le$0EwMko}AGW<>OeWdu4B-T7Hs6yfsOFYUlIS4HoJ?D8c&7Z+t46 zX?@+d^Zipl|7n}TpAntxm5*T-{PNJH>W5n|f-6bE*C*EYVGz@^Xy+uRTckJkR3RKb zWookR2in!I|I9CTHP_jOG#QGwH`Sjjv_J7wmaMzKCK%=S!z~@aeQS_FpJxW3M+Ufw zZP);*%x4a*)i;~xI8F;9q=RkP`$)3XR_ep%#0R5x?X3fD`?e&s*%Z&2gS(FMzDNoN zd1)~NFiJrilPnov(}kN0F{JI30>yoLyWh_o$HnWP+(Bo29qG-R=f;N@3IR8E8hze{rpxZA)p)ru`5-=FmceCxO7Y75 zf(XhHIp26)UOR{-$;OvAnOQj=k?Wl~X!&Pu;}`je;#!0AGwtfyZG3c_%w@$?F^tKC z>{UxE&G5?_L9>-|a0IBnl*534gQd>s>qKTZpyoDOB1xA+sagU%OuHPPJe}DkJ{z3# z(~ECZFHSDRfIqua{4&(V6!V+uJcs}Mxpv^`&DHAeFe}$%*3xfl6>XO@0lk;kmN@v^ zf!xO78>;32XA>%#!=fAanxykjsT-2_bFbe@IZ7&aM28dK9`&!J^nrf2MD0~=&T#;q z>}*wk+G|lT?pLc9U#}b^sbc!<9E# zmEOCTnWf+FJMUyBid8`7t3q`m@xH2j*PVOrz31M0&i{Vq|D{3AbGOO7wymVGVTA*a zF?6-9wN4hbyWk2*ovzdd+$+kfA+S^SpY3rMAVlk@_G7ysHb4sVnuXNxMOp5LM3M4` zv59Md)tW5=Lw$P&NZ~Vu2E@E^*8xrK0G$^$t`}cqVE=yW^AS~-h%X%`n~FQly-Z;X z2k@w!(zi(`|8zXS8_$3_8}0bNwN3;Z2b}<{nO|=KaH$4CV5jqS2Ruq+fVsH4K1bVw zWx5^*W6#rLQ~?&-!4EdjK16B*fzz>jlacPocgTo6{}jQM+N(zaSNk}fk1VRge0Hk$ z`n_MHn3kC5L| zpHE8F_H|2omYk+%cMdQgQOQ(pSwAA|9n|oiBIl&%d3%G(blT`G~|G^030->&f-?3Gn~E&;0S7jTa_-} zvDEQ8H4mRm>P8w~Z|{yy&)xh~HCr=<&UMs>u!%28u#0c0lE@p%{k zrY1~ZD=sL2prQPpQ!iSM)qAaBP7;t#HFr`cDL4R@K9d4R0mk2zUgp_N=AAg9ef(t8 z-|ZuVfR{0jNg5fnSO?KGs6%{?MszAr51~E%(D4ZoaQY4kYW%#?_emCapB801+R~d( z8^?3NTq2whl=%E5agVf@rIHB2Y2ehIt6>m;4%R_VsescPKiWbcVh^p1)H8 zPDnm^EP<-i7r?;Pz4r*1XGS zwrK+wk{T^To_Iz)P$7BpA=-5bU99OhZhX=RnqJWdPF*M>Yo z3#2>#2o*GTeLO92rMVg;E6fM{-`ZB01HM07>%50XUW9<%Y?u_;Kqq!SnQc za5gFOFUj%rjFFO@zZxs)Cp5d=!o+xDa|+O;!*jY*YO@4X4!BYyxR2K>_)=@9hRc#~ zH=kxLgAdP8cMSw;(iXhEkN;7o^04r4 zno_4H0q|=36islNaiuzue!+%Iyi!eo8}&wNvUbGwHSx61Ng5_?X~mDD^qi#kjgoGP z2g|*Z_)NLM`<8ywde{2#;MDu6p5@fm1e{kqIW-O03)Snf&OLN`U*);IK~O>VJ?yD2 z0v3G+c8+J+y+|{lVr~dBU!OJmp$~zye2uB5DC60Ne=6JJaF$_){kKihRu$W7EkeCq zVt}J~&sc6*&w!I{R-x4P*F{Z7|vptsB9-UFGo8Q6#Qh%=`OzqIzm(D8H?NaKi+&{K$ zFSFiy-JPk`)*C{aoV)DvzwRwnPFMYl}vx(z0dL#jk1LMFZ$)~vhwG81u#oWCk zwNJgcVA_JIrW>^eX;lJWwuwN%CBck?r@kv{hWG~NANM2LH<@MffFsBfL|e)zE{jAl z23zZrN##b`v}|>pR*hI`@xh|yt4UzfGV|0 zIr`EvQYHAzjBd{1v({GhLOPM&!DxQA@aB56EQI(>tpcdC!@TQ!uA+tZl-vLcArNa zW)DB|U#SJ!ivGy+4MlandZajAiptTrB-s_JVtDMl;eVlilzE`~viguFF`7X2!I<*h= zanFe$T(8o{b)^1C>*d63P1Cy9gEq>2s0Dm<8gc+yKtj+mFWr}C$HIA8Y6Ux-XBWmp zleLI8YYB&R2euBK(m7|fTXvW_##`1e%9)l*EIW8>N_3!296G5Z7LbMZgdJn>=4G}n zI}ZPOoal(@RiYEMydz}Vi%wTP4Rx`Tb)}_Lm-}b2v&l;zn!3SldFp(uIXFN1%IubR zn~#Tq}W0nBSkFPGo2>7R3{m1#}du5AmQ4ue^MQ!4Pz zq;_%d)Pe%9H2{oDYLF}tTP?_p<|XTFWsrNRdNtU#T{ngXN_KjIhgz*UOq@M9y*ohu zs`(@X=4z0sPGBYV(C?Z#lbUoAj-&tTd&|HcN&Cv&CGv*)BHR%(`Cww!^87ymrofn{hr1XpS|mvC8F zrq3ynhO4`}6!Z!!ByZoZm?kGQq5ylfHR;2GcSti}?YdK)ykDC1^2NkT->fXm`9FYK zYERqFuR6_qxn%6lHTq_zFFyCTf%xO%-6j3FDwfhVS6d7b4B78$CNvKsjRJ7;9rYZW za73TQY{+)(Y|=0GXFPZvfU#l*c1Y7S{-y18wU4A8UFiLxH^xjnX;AlF$6VZYj;n$^q z+6gooLZw+8r1c}Ryc(?w)v*9{-JJgyH!c-F1Z4Svps(2PR^NzYO6Q<2PdyS^N5D!3 zFZI;%B=^bZE6DO0Gn!K(Po44SfxJE=F}U*_v;)3*ED)ano*8eqn|(%jRurEhw_7aM z@Z%CgJTviBv1fWmEwqgjqO^OZr?j?rOni>4OUetAPTQyWtb30q(4`5i1z$eLrV}z6 zPJmT0jn(=}@zuL;7Pm?Rp25CEa3%1FbL2vu3a-Ko=&5cC8{*WRdZsSyv_Z^yerlk*KJW4p!p+Z1$J8RGgj{I<%=q(S{(hWl<>2vrN+p7S2ypLijjVf zvDsV<;M}feYkZ~@=0dewI=DA-5k~XX{nG$gbvNDP-SK;arveE5!T9CqHtjmI^Y0p+ zn7_1ohX4RT07*naR6s~D)eZofM`P8F!+Hf(xja{^XtLaHhoO_Y36nbkWcpXB2@^QE ztf&RCGxNsB%T689AF!@WSqF8ySWS?281@#H78Y18K`tSfU0JPX@Y4`+DgVU^e%vSj zxvsW{v%A*E8N|AS^5bCWAgHz{0~Iwn=90TjqFeoo1QE7}?JgOt8VAb+MT5O(+8P%c zi?!B?e%|)QQ9P{&xKcL!+bH9ZD(k)AEgGrTQpp#~@OkeGZwMlPb z8Z-)0l1(WJl(+DUQk$jURSV`!{cEH*(0nXsls-&qCvLS20DMYO$M3EGq8P+4YXm~k zZcQ@H&X9T3*0zz^RmT9$TIBdB&mfR$j6&zVQ6 zy)Q8zKe64l@hmdqeo+rUJR1DeK$^RUq&j@seBM%>KFid>J|je*`W%~z-2e}hR;&H= zW6gKNxsD^NeB7-T(~!shZ)g8y@!HVE;>RN|)UKm;m_1I^+Juuhr;<%>ThXm}0aW6N zW${Ict8=QPX(F9fJ+Mtx*GtDXDT z2IeS1O@fQd(TLkqX&IEEzKuweQ!b$`!v{;#U@HJ@bO3^0e6M`|{OBXSV?!RH1ybuj zLIsUoA5RN>b^2!U)1IS+&hG7i9_0sp$LV?t%yy-4UVmY3yyzik-<6JD1~^lKG#3|e zbT_h4a#FQPn)ljJ*SGLu%c`ssr312^X!H~OM(4{5lr>s(7Xh}CY0&-zEs0-%$OI1c zcJa~i#wvc;x61bT0<>1^qOA3%y{sdNeVCG``GL#ZKfE<99i(3e6HQQRvo_G~ILN5A ziAW#@z7{~1;vguL(1;tvnq06NF5AV6PuDM0bs=dB6Fq}lXnzJS=e$qBV@3m+qK2kT z6|gnkLkCXgxX<1b0n0e%JZmt;iA0KzqN_j47qCK7aktei)%CIPT|s)o%Ty{h8u6zGS0IQ^kM%?q3vV=WlbEd&P;h z{ol`|;pM>52>K}Tl>2}yc2v%KvR+)QuWfVtgT%64ifv{2XtP?u*p(kw^An4fvF>f~ zRx6v&fl{GiWU51cOPB;bNBTbc!tM#of%dbMw>};1gIyk8ua%BUB(k17g_)gX*5+0e zyh!=r{+?V?)d{BVyC0My_bWLXFNlW*UM6WL4T;Qdj8YN|Th^{+BYFkO$FSIXEV ze2X}=>)fvC(D|u3D1vZ$zj?PDCPLrqhLd}0w|al`cvtWKjr|@|3#_1t8d*#J7B?{q zDqjP1sfGHFL+6V3I|fn3mjdv-G(SYZrDKr7!NJ%_L%$58 z6X1oHEOG@Wc)RP+m~f07qMWo^0w*;o4%hZhM3z+{71Wf)VszGYLg8SKuYnqtdw$JD z2c}Qhj;Y5^L$R~btSE>Rz$K}5^lY_*3r$UJ%R!rDje~=sj_(dK$#V!F1+IS?&5w=a zb%f@MC8O{h6U?*cCC63sW0`0d+C$LmeD1U@6J|EF1+I&Jot-r!CX=D1bGvyD*q1-t zWQ$QWOdfjKF2P{}4{E-(7z#G+7ST$_ty2);0Gfm|_^)Z6)QMiLhs2^o49;56Cl!)_T~ ztauAz+1j@+X4iae9q&)PN7h#BdxEzrfAz43eVsK&Tke{~s@RXMQNVMsKKfD2ews65 z@bo-5+;UHfEcU%m$7D)hs~)eZRab|rBZY)RoF$XZ70_0$ROE}E?cA`MNM z(~$aGpaHPzZ@b63XD5DCcgr2cd!79Ntwq2}srakW3&r(HPx1Sh4WC_{EP6Lo$>WPf z2XuCMmaf+{7Ddr(L>S^%k-l1*4>c2N{PSg3)8yBcJXv-I>c<37@nJ{@k-98^4lld& z8-TFXsZgBvEBj^G4O`kS$$$D_$u>`x1?s}Y$RKaW5#2U3_C5YJ*(rKlJ14egiLw;1 zlRK!AH4gdw9IOl=Sj5Don6!8mosaFA!BXUMgc!k=0$tcS%Dv+l^ov{D+q3!#w0&*Yqi)xB$s>JBPW@a{3Rwvhi;5|KP9n z-O>wT_7d#LJg-S`k@^H;FITT(Zq(C=!G<#)y*Cp8P9T=4CE`RrLq9%SCVv(fYjX2F z^;O7P5S!v2K>^-lqlo1-OHYbh(tCvRqz2a0bLO*^p9xLYiqDYuiP~b>`}eVl9UD2{JT70<3*k9swA>FoV?CsJynbg;es zcFeEDz67*|wx@kwws^0}9>+(HU#`bzJ=VA!lD0>oxE8O$O1!T0XUXJzP9GF~V7mVJ z@Qe}A68uH;@RO^q%_MN=X0%saqgB&{QCvXexvdc$80W|hiDsveWi$~QIcT}HcKl{J zesE~9_eKdnTiY9rn7&qveaT01`uJd6nLb?mp=Q_}G1%3<8My@oQfjhJA6wgwC=_&! z3{;CX%z~N*Wp5XB88Ny97}ME(olbpmh4fRa4Tumoqt2g3>($wCk9)VbI|oQ}gOey) zt9hJ8vs`cM0x+S<#ld}n=$v_|989HitI}Qc0k{M?<0Y7Wd0~wnGm22KQ{j`vLEP?H z2WJOm{jkb7quPN=wU9ds`xDEpU{bU*)^{NFEvmm$M-t~l#}W~V?5KZ$owGh(;rGQc zjApbm@}Fdb0qCeGx-<5bZo*^pF7xZ3os)-h>0pb4VHW+ee$etPXRlchjUieeJ72>L zyeiFhcaQWIucN_fC;`r_Cd|pP2hWiY8Gq?%vlhy@BL0~0oLN_iXUqP?C`PjjV&d zSKFR(5q9!wVYUO0J9%ml0Fi)QY~16|3N#H8jq2cS)ZH>1Qt{RZq&T6N_dRks#Itlm z?V4(fuCt7No7(%hE{oZ(`QF64!_-q`eH*~eZGz0$$@k3NqM_0>&7z^k^}>EHe5SVB zE48E=Wu4LmQV}(19hC8GH_AG?b9~I6aZfof%WdG`q*+h`Qng|ht}G`1tQ;|zr`Gmy zqKWW+ah=hCMh>1iwu+W&6GBn?C+HdUwGvqMK`?5hsKDy%aVTK8_ZzHlCl_Ib0<(N7kM|2p!g8&}W%{VkmvG8x!{(<|pSzJLgbpkEZ z-4>$kFz?Lb!F^_r|%_q<7TE zOD&tneyiy;jQ3OFoAV;tDINbuX_tPk`MaeT!--x;dbL(T(#nW-H&PC*bDm`eY-k`b zK?<_QioQ?7?cdiq?lphm_iDBN=l{vSz4wi+w^$M!_>^#Wn0RjuBoJV%^K3cwfAa3D zm1C{%s-+a))PVcJ&6a#HCt%Vag6-dZ{Yme%+uScpnoA!71TUanGs*J{JU1K=4R!K2 zv~+$Ke%^GhD7UT`W9N@!(t@xS4NdDBBlgC-TzDT4;Z44)gK_ z2;n_Q?Cu_b>jbQ1&}G}?YjK~v-uca-cA#zP^E}69`Z4R1f6MJcp@@jKJy?zoDrPte z>+DN6NJwql9pODxlVv@dfTX06q6VV?m!PWXAR?5KYT;J9_)wxA-{0~w`62;R)iQUF zeSP=!$MQV&u^PF2hju&`rolC$2=@c7I9x;lI#rV;nP^A&U!^EP0oBP-%)Wlz(r$t+ z%V`3&S2u6bgdbLdW{eCut<{#zh_RPTS!#vYHg1ul2=6|eUU7k4Th zII;I_M-U3Qa;~aJo|)Crw;W(@P9on=4ZQwDa z1WtA&Neg9OLf5v@X*hTaz%&=ysVIKarkd=!twpUEFpQ^1)1&(elA=!L&21qs zv-9$pb~3%tNLX&U#<%6(g0h1yyZvS)iu`HIg*as$-_^(%d8bd77pyi((SOD!^cwwg zRTp7vBrP84jxfJy2J{R1t>&}bFG~t;b(SZgD-;Gwx{Y?yq?f^Tmj({&;a+h(BL=-E zCglzOGxk0O!RRXWe+4qj=Qgk5(0&Vgg}yNTTxuE(PAq-I%sr?RvtjvJlN9DZG$xs& ztI9DvQ|TWB-vVfJ8p`~BY%?V#J`UKrL%YbGq$W!yd>x~eYc0dY-CZC`Fd!MKIS(&x z+=w#2&Y!`K>0ECIOS`ux_N;8)X}rNg$# zkCk3Hnk2QIZN_Q>_I)oYF=`#IKHX;f@qm;1h2=~{bfYE0*mOoW>_v&(a} z*x!jym3<*D86;+I17z9nZK2^`Z{shR-{r`f1Ek?*0dREt3ZU%z^QX~vL9c^pP+4LB z{Ys7!bgH>e#hAWTr$$$TnO*t?{j|zN4i4k|Ud0s1rQqz285)h2CPU}9XwT7s_3+!; z?>RKe@3g?dAK7-!_0Z3~OqAg0>Qek=GogU%JO&9t@^ zr zLL@t#+FY3XQjSBN=2Q1%5$ENJ6117TTHg=9)btD3?!f+J zvyPEf${$vLhK7eM_Y8;*iuxu^Vgl1#CSj+*N$sEc@ob$OOyIuRak+xu)1n}Yws~gj z25kp$WnTv}sWl8*fSD?Mm>dXvS?%&uRA}nn)ozU5o8=hNdX#W-#}OZJ>wE=}d$lP6m(IKX2p4~Nsg@l(E6of2KRKIBcm!A zy2FH|iPGciSLL(|W-S4o?C>4bD+9Q`VS*|n4b_L~j6X}AniOT2e-a{yQu0&~mFI`L zCky}14qhwz+GmTQ&Z**SXMg%6PAiUanf8cxf%Z17k)Jva?fO*3^TT`MKi|(7^m*5O zZ$B(PAql`IGa*_hG}D&%z4IRXHYXAAQvsDkAHd2u!mc`fc09KGb@Qh$o!UoJNPT7U zt>W3SOHtLrKu>6LB*hd^sEOIH7(F+0Y#>0C?XbxQm|#Q-1h2(+Ne~se|2$WoLHi?3 zg!VeV8D38M;jG!mXg^y^bKpHHuwKhJ72LSHf9c145tgMWa2oYekH<*9S8080vMA@H zR;u;|gjUM@f=R<~6rfr%0jGak05GEi^|$hV$keXCnn2GFUEMNtZa<>w5HKll-Am-4 zXPIdkbYh>LOGYXEtA_eG2f&jNgk2q+drfq7fA<>cuGZ6)2)YIUWNNfNxX~7ogYH9) z>d3;7_iIe|-vSMQwf{EzME20ZT@9AzK|xhF{#Aml7h!TgznBJ~_q!6%>Lapn3Q#48 zQIjO7TIWsD30@OkGr&slqu5v2q4))?iOkaJ{5qOlnD;f@>WUasjGAe zU}TbJHJZXA110>EdO~Mw&$A8CB}nT797@@s7Gr?FZ*IID6bw>4$o4K!)L%=g3ISb! zN}rB+hA>&M-Q)gd_00fLf~xG$ZbaHR38w{K{yholZJ*l)R31+trIavnP0SA#Cwo%V z*7ACLac$;A(NS71{^W)4M43v!f;ok{y zrW#5UqaUHa5iG2A@FrmLT5rdBd!J$i-6r|@)LwBaAqMSisDeQR9%{^8PVWLA8rZb- zcM{;}%a{OE0#BL(BR3%DR#{SuWILpaovIB>;4P}>#{&Mh9bDv>KkL+AN{%b*(BI4g z0l3(<*3LUaKWLpcTX0`7zt+xM4@y}Wz|f9q(I~=ufUMw`qP}Vw5Dk!O0zm3_297Qk z2798Oq3em};^Q<}_tP@;b#DeO!@1+DLAT&#m{(9LhM9R%T?G{broxf6FcIp1)zeuG zt(Di_icg2&OZO5lzq6g-7C>7=>TiKY>($?Ok9AM|t#ojgZb4wB21~$Y_v&D~07#hx zRNcnuUFUWq4J8>Jz~nZ#wo=@H+F_nDM)hf;6JY6dE_ku46o_fK3a%^O9?gIPqBS~Q zJCPN%5LG(}$~Zu}&6n)&2TunbgkQOKEJih&AJKZosM~r43TyayU2g9Qzc7J;nzKc~ z(*(e=4In5Oyxh@G*RA%akAbHHkg~))o^9MiI&)fIaHRRh@;!i_Fd5ph(SE_|PBo^HQPg4?Js1N6 z`z4s023&h`?oQlS=eQLi`d*dLJh@I2qgu><21LP+W=jXkF0@v2XpX%9YLYbj84akm z>Kx`D&)faoPlI4OV*(@qd4jT&<~D>Q>*ttAJ#3H3fT>CUG6AJLS6=rONLqi^@)V}U zYWP`6%V4S=eXewVH^T7@K3$50r;k&zR%&;hdEL_^m^RT={flS*0h35;@mm*uP`r5b zSH)M({455)#r2Nj!qDa7l~cbcs+*X9%SmIoyRJ`S{;lQ{_^sXL-r%#hwTc!i1x|P@ zUOU=aQ023NQ*@kw1G;y>^+~%K2q8-QbnJ-tQvj_-+p@mONzzPulH9|Ot^8bBA{RUo zIV(?WO@_vEd8=IXtS^Rn`E#4x$EC5*w)EW9e2s|-%7XohU`LQ9P!Z5{Pe61En5kW2 ztZSbm)>8j2PSrCDiUU3@y}tN>;riUrq%#rI5-J$M%SvbRU-g{gDrrdD(r4SYaR1mL z)>(7y&j}I)qD%#N`b@d!CZ@`!8tsCbD?dD=KQ&U2{aV+#Ppr2t!Liq5e=6wO1aP^n znf)f@71d+w=-Dv|qhV`m|*zR?uqc;J&!b zM>b!6o{t*RP8{EjHngq#x{{yW4Y;rbV1liN)ZYS0l~MoxjXfVz3rHaPqy7`cwh6>RNLd2^ajwJ zonDyd1y892E{aJV;8(9X*~N?@hga+$xM0;If#HZ(Q*Ds@wrqUP?? zAla#R8kQ;LUlTRwWv&1$rvO@K11#Wo!N8ap-eGRWwOonzph3c+ot*}1zDWWv@2TPd zXq(x2=MF#a25lwa-H|i^rsdSoseab5LmG%F&n9oD1J6CcPZ7IFnT49C4oREV9P1_1HwORh+6bQ zQ_~@^%05}yBq-Ua^XJjJeUGxAl>Dm~|0Yc1>l-CP($|Y;hA+jtaCQ1*u>_!6t(J>Z z1C#ijkP@cvb^x#Drp?fBt+CIOkW(D@`!ml*3L&2-wM7Oc^VYH)nKK*(|4%~h) z0TY(de4kHMB_^*AY$e1329TnNq%j@&Y}RCEJJjjwLY4RoDq~xq>Chm=oZvwMA@8*P5 zcM`{UwO9``6=qrnr)saHV-RGWKDrvfNG>czhxVyCfnk!MVc=`Jn|;)7wUucHuANiF zXN&X07puKuZ^5;q#cD|XEzkg1^|#$)-SgR{iQ?4iT=BDR9FQ@eomyEaTIfjBWC*?l zGirs59-0PZ>Ev#QH;U#CcC0SdgcFfM$SEU;hq$WKh2wPaGKa_dI z+F9>QFJLeqp`C+T6W7VTCBK$h4<8t}2&C5H93a_43)Vp$(mc>*FtGbYS1ZQ=FSt@G zXP!m<%;xBXG#h@JBojk=&gPK2in;4WSkdjgyN;}c_C|A>TB7YPi5WYoEYT6O9Q`q? z9nAi@}XKpC!Xs+dNt2OE;Hd!RcsL8o6q4_hq@@<&- zeZFqdRw;^BLQEsfU59RKq|2O|%U7x$=^#y;5{sm!3i4G67V) z$2hrrxoWSff~^i&-J6T6cPqv5VUjn2+TFHRO(xpdx$(2_7D#X1zISWv@VHyR0Z#uU zS=x=X>w$knO#l?&h`s{yjFnND%;d> zZBW+pHagI#MftJj(Q0|VYOeGtQ#5-@k}81wG|6r!cXP;T2Gr@-;Y<-+t%b3S`=O=> zAR|wdZR^*wkYtXdk)8g4^>{NViQpi5f2HP%@a!1qE zQRp88X8L9+YNrHR0x6x@M>l7K!CbKFIziTMGSt}V5q|WS`YMj;%hfi{G_~8SSHDnP znmkiXE&}Z4M~b->a!gL1E*4fhig(7($MWJ@JK$?7G+7r%-Y;%UldlmCmL|kfQyQcm z;k5R&>(-sN2nMhX-)uP@0Ru*dN~w`N?7XW99{Dc&`I5zZqok)pJ(UG~GEy7(ET!_f zRZ{t#=fu6!6PMPd-<=v#eU{4m_*fYraSTnSnFMr#KRbCd2siujLfo$m-lU#OcS5`4 zz9ls8om2D?9NGv&!ASqjX`V}5CWySN5~;Ta#e&i|25kxeO_N*lf#PkW-|-_cu05Io z5QOQ_S>MNO_H#e$OfA9{JCmD-8T-G?$nMVWAJL4~fq5^=`aT1))QW{eJKMZRaW0fs zGz%t8WU8YX?U{59I<)J5Ho*0FP0mLI;r1)bejnwBC7AM0(M;%{nk+?H21U)4U}~Tj zYX<&RzV~Z5w~tNY6N~mrF(08CtO}Z}6C5*cbyVAk5cH&6F(is^C3W!CNQW1~CoV z@pxXECk0lX*U|N*;%yxBU+)>g0e>yDSGJc?kOHkwqX-z}2l_?JxiFF3k(3j&Ao@eT z>}4sJ2TRp_N@N_GAqXD>$aqfxB$i1po*l6*oJ@K4*3PFjwvPA3HCbd-&#Hb~Jjr$m zX42a9>)qSwtN~&?4}zm~S5w%(=M#?z`zF(%jQr?7^$TO0!?pEGK@?UNC2n5 zZG8!+_0G_c>F96Nqh=#>5hi#>E=vekpNA$wM|J_j8GN|>%knt1SZb|)=b3*3Ge4O6leNx;#;*+ymb8SVxR+>iq_TQ+`#o> zYKc6crIn(yyi}B1fSWB<0N9fWz%a46z|+)57dCH2B5>Q#_7-sa9C`opT~Bk{cRrdk z-6_|l=g4U;?~{?Aig>~tMMHL`?wOZz&G~8B*~b!Tt8@Af3QvXsSpw({0yU4$?cCou z#2$V!kmv?vXddjITnLagfJSG%!p9sSWad~u(RFK~K`pIlj%!7m)DapbeV#PGx&B^g z@p-4#Fl@8l=UYc~0Z$9yO!2+2bv|q^O(&|!HNS%qun~>IkNePWvByV{VUhMtl3!R9Gn`fTg)m z&DBUhTw+YQ{Ge&DCOHm|4f=d<6;rb<#T)Mvv;t%MJbqZNn_p@T6QTR9>6qJ)x?7+D zu;S@!!iItX4c-hW>5`0jTBn(QnbDD8a4@sEo9f_4V< zNCGi|l^vBGuMuqee5rZUbfhxbbvoXw36o*oXh;35rkQ3?Wt8NnSzd2B6GV$rPnZ%$ z?GNt$Xzp6jVL`2c)3}--BMH4PiRvPCR00;aC9xH4X>LYMQmHgB+Lb3C(-;b(g#KMh z+Q+?}S5h5m&t1#j*eH>Xl*zT=op z)#8nt&lTVM;Omi)`^x00;_bUn7c(op3@)YO`J?X?X9unk8F&iqR&scDkP#TD$r4Dd zZI+62gExvcfK_iBG$%yLd9V5~Ej|g^ZG!%b($@jPa+7yy`WjdR5&(m){ zKbJHQW=T($&qaPV0uRKqlYm7o>C`g2pTylyW=*FW4~%7Zj^UDhkeqwn&~r$Z>PN_a zMN^pMnu_2`(Zn}D+*5R+$r5zwU)2qNlzv+MwD|e%uZ0trgsu5B&H~R6nQNafb zQ=shV`f$lprSDd)IRIBY`+zs|sqO|^YNKqs2=w7nqh0ARb()WzX)4PHh@wq2{o5y6 z-VQiEYPeTTd~C|+wE+;be6!$=^=hpwuLevrsM{)w^!IFco03g~c^WGp@RR+paQO-! ztkv}$kflG?>>^RxOy9oDhYybKI=pkZpl^^+basJfjI=rLUvDdJ+`;u^wHb4vk%fsr zOLJmF>TiJtz^cFP9_yaZFHA%VoSSe%DQb~!m%9Tr`Q>V^LbVS%EthL%JYRjaQf`y2 z{VGv>ngLU?=VTJ{ZFe7giKM+q8ZMXBs+6Kru*2}Ee1Y-xm;G`y`3cbMRCG)aGZqB} zUW%qkft4MsK)|TMZ0fpIOIZCJ4D}|h?f@YE2GheJ4u;Qe-Ynj1J_W2wq@V&4^S2pZ z?|>*!O<)MXN;{`8@@Qn5AWiMK{qxr~q0LGwcGkJMwte@U13;1lvQkafVu$FIIxS*v zT3a^CQ4u)A?rd^!5Cl4QmjQ-?Yk{49Hu2n0UYZF(;vIafGUt^EiX|u2tZ1$}#gKi; zG6PW6s26_Ja&g-n_)X{G;t=T0VwnjT9?Y(zBqkQr@{kR3rnfKx-Y-U^7lNb1PkFfK!`Ap-=Fq(!U&_ z{psP$p~-rq`CK^WOWCl{R0#lMTYKZuyP8kN`kz z`_!btHI5*Nh#hv9OV3tDSv{*Z?9!^imOCApvc(+BDH($Cv{9P*;HJY@N;9Bk+%9pcKrp?JezeryJ8D;(wGJJFEtbra5{uH0 zTZjEF;=WmAZjbY4x);gdY6!y6oV-~Om7Uvlc9(2aZC0jVc>by7&}dn|xd#=sS31IH zXZWQR&Ku2D3ponGfem?t7D#aU5h`fx`gmHPoleA8&B4!TJfrWr(Nu*`6|b-C>?ccf>L=MKu)_!(t7$h4NSV=P=pco0FPrxQXLuvy7l~e^4AeU4N$$6H}3V@@5 zP!Q^UcA&Jqg(v!G3Ce79^##$%GjF>mu`|paxviXmRo?Ej*12<|LPG^O@SbI$WGWr? zGVMkzQk}J^)l^d&wR7vUF z2LryW`ZGLZy+}NF1Zs1+ zwl3z^F}L5`Jmrdx^7L9MlJ@x^4+1H*oz(F4tbvdU;-+m3cYWMbkuT5 z)8;OvcLm9=>eEMp$jQd)*Dt5t@j`r8ko;k1P&B#VcL{|Zc*({jB6}x^a zB|Eu$^4Sk-vAKey?@AcemSbH<=+&?VQb;mtU>vI9ubEuf4d20`FRa<9tpPW|?0*ZBqc8&Qhz?kRby_D_W zdHu@d@p7Q?8PVj~14EPG-D}DW-}+W5?=>HfbSx`COA|_GQ2I%LE01?$_ESL;cL=dP&15?m=JSe7!jb898;hkjW8B`q;`W&2*|XTUof(1B}@67G&krzI+W_!N?8MQin^P|>U(KPWluSk7^KzqNU=1OOFL50rVl_gvu&_oG1 zI%eiE_oehXrjqe^rPY+r)CfZN6&S4%v1e4@I#WTIf2&03*-l2+uCtuAQHdPXvy8Wn zX=)#@H_<$JO|^Bk=Y5H~yab>#(Q_C15bx2^s9ke#HU-WQ8aQbg1dUQe2(mN}N{pHT z*ZoKSt^f4f>0<8R@Da;nTq^2%I$04c_jKPHj1+jfJ}`%hWN^vR{P z|NYzcx~$gcx6c0nE!KGP=Ix8&&@PFnB9GNIc&@(j)Q>R(qV3?Fm>`l+hxSSQL@z540xS!3~H;d)nj-`{d={{rP_t&&>DkJJi3wZ+Z9P zpa0Q+3myl!2MYJ~x&N_C%L#I&JzbMuv^2l7Pl99_aO^%(ns=zRv|3l|h>wHq+FUOz zmp@HkrTvRQNl}xv(w%Z0hKY_3Ld|W9q~tMD&}-J`O7Nu*)oN#=LNHQKpCu_BR0uJxjXn^ z5Nb>3b*<71&{_^Q>MWAdCOCAxtak5R`ZxfpQOlB zb$$AH@zRO6s8w=}ZLmr_8();oV6*P8zJT0K3 z@g01h9K__el1x<46gdagMj^v!snl%Q{b>r!H&1qT{i+0H@?3?(Cgr3%Ax%kJ{7h?KxWn{{_jjtKQaf|@0?7|6AHn6FTGOn1rFdfZ+`EK%jE^-nPim_)<*mYEuJ4l3e?50+ z@uR}z^~)44OJe$97GDf-yna{8CFKkG7nQ?ipaa+>rgZKpvy_zh`5Q z$Jzoqp-XSDfa%T0T0bUp{t32JyRQ(T=gkt_=)4~ORdlfF%TvZ2ft301@T0N1{OLrmZ)?Rsv&OZ&orW(E(xS+mUdNF`k7aE?!CT~G}DJ6rs@^oO9wf*{$q2g-u zP;u(s1SZmS%@2wW%sBvaoBaO8??wXU;HFyZ48N%y4VcU9b*lNUzkMeBt>nPc!QJ6i zqEQn$o3L38R{{b&zrh5#Ros|4Rt$E|P!i1}+N^4|wK(2;8&gXg`&NpZfUUu<>0)`k zEqvnkdOlCOoD>>%7U^~OY801*R0(Lrst5ekx`_He#1GKq%2Y~I=93^6#CGxS- zlu~R?-ko`mRBA83YMa_;mx`Wo0Q(2G!(qMu7JOO&CdojhYbaqtoH#X%W@{<5R;3jJ zNI2i}GJd55*r=(}MA%1ezh;7lWK;Je)%|2{*Gc}cO9oe_W6aL*u9JpA?UlY&0j5|d z(8?)v+@{Pg;$DIcxT6h#i@%n%4GpQk1sVXW{EYcBcZNj+zIG5W#X9usxvuS#oV|~fN zd%x{ANA%zTKuO1S9owZ>sPd;nyBe#D5REFML>ihZ=jNQ+thQpLXFLc;n=z$p1}x)~ zr8cXx0t-E+Lp5N6v6g1cPQFJ6ROBo(2<5|?>7;2A;`rzLnV?gePs?dry0Tl;>da^EBqgxV}MP~&GIwFM+4=XHD?XYh@q?^Bay z&O=Ry?ej}P%DI9cmZrh(afnLWNCgJpm63zlsU3Hs0BgH0^?)sS-`~R*Pl%2M&j9hsWoyc zd8bi@c3u*X$~Ps*vhz@rBt?QO>Vh<37AALq7{G?!(*2Vuf#{Puz>ddMBF2p#&0}0| zBWjG!trg9fAn+7Pr`2Blu>Uwt?Ic3ob(~ML-&I`rLw*Do{{6?&7b3FDG&0@f;Zxgl z*hCH02TjL|uWh_r{9g4noZMIU#buREfNF#!1pWEVm!gRTFR$Hv0Z_Dm)3p_>tXE)Z z?+)_NFP?h6_^Y@61)8U+Vv%UTCPvqhuJK~Db3Dv}>l^S%q2;RJzD^*4F#Z5 zV>JOCgW4?rHZTtgO9WjpiXYG$YDyhRV0{O7fM9}6{@NP|zEUrc*6+Zsd{KG5S8Q*Q z|I+sCb(Kpy-8n*S&Rs%S=A%z{hk7JCxv#h5BPS^*(mgpBfJ%A;+0NBenP_>X2lofG zTg&DJR#G`}H@&$=O-6prR)0u!5`m+fdDpB%6m-^s7pe?(tr(Q&XVw zop-(!)7=q+pF93$_%{i-o*B9n4(3s4pFbt|tgcL-Dq7Jrb+j%;x*SH@;&aE|3~iN; z?M4M&rOfHR>p?QAL%U`}eXOKmc5@$onPZBm0je&bc=9;OwUsJ3+XeGPR;H zNj3N@s7pX?_x6vUU+n7)nub>RuT1tl3s8~_bh*1@nwN_)26)_(}M(9^?qG2FpJ+TLLWsSZ^0O zYQf3nQu@F?e68|iuBf5GdNS?2hofv2J@{ZBNCD#bhiW<{_BXbPe~K+*^8 zeWAsY57TX8Hl5C^{5e=`0F;bQ+^-1S%KZ6HQ>4qL#t~c@ zDVU=K|Ml3r#h;BO{u@EpX9ZkoD)cWCYf3=+S(a=HG);}7Sx_=iwOHl_R3!3LGWhz{ z-3zh2-=EcuN+DajTCt~xuLO&`WV*j1P0lFVD@8M(X>xRgF9DpSXy|AGc=45@qx(~X zS4s3d9dr*%0KUP_X(%6_Ef(+(Yeoy!Ro;K%;{9Gnz2zk&Rg9Qif*e6WDpC4fv zAf-8e<2|;^cVjB+w%sC(vW_gi_kLgn|5o%QYSxp7S1#i;0WW?zMm?f=aJQ(9YQ=X- zt|@64W=H$bP&L69)e(MH%~hh|ARyIM!3aVVK({R}1JdBB0vO1;z6$xMiJBuV4a>EY z+hfn@esb+|(FBrb%2nmGy>%u2%ni5*!@7i^f-gm8^?JkzzuR-8#heM*8}uC;{Q zQVp(GV=nQmnE=vWmUF)}WfI!1Ah&g4AEJ3sHg{RkmwS>HTwoTmtVd|P$GNLMRL?9;6%zm}O@-$8Q`8hmeV_yUJld=_I+#@e z)g?4pb{;>%@5v7CosPjsr*or1r$b#!05f16xXZPwB5 zJHV~=DZZulGVfs_6C75cWoMmNp_X1jL5rb;Aj<}t_oeTV^ zvpC$_c00m9=t?CV?deS9r4`JB`fN3%{uXGoUj1$NSoajbXnK=K)O0z1AqsBVARd*x z^X;yoVhwH5`yKs-389VdTjTRWjnW*PS*Oq_nOa9btLuO)S(Psn-KQpOp`{YQC_%RU zowg*QQZH!o^IXg?s0r}vGq<*#=6`FFXvqKoJpf5WK~z}V{#h{#?ym(u8>KU_$`0)h zx@w)<1zbmAUjN3q9|K-Gi_X$w_&`0V{Ku^mIAy88!fv8x%+YXo zmp98}3LuO!ya`>y5`0->bHf0yCQ^xDUP1$;57uzkWYm%CKj_o`dkcgfqWJ%WrT?u&-1!y*E zfH98o%jPq#*q5li(x++#099Is^c4`L#!3-vnHr~r8L^G1!4^EP<;GeAh_x+{Mu@(! zZ9ZwY*4itip8ALadn=kLJ3&Fu zc)7iJwf9(|L%M&0EjyEAq}OrV7=QJGA33eE{0JcR4w|r^^d2p~J#s$kthe4=XJdNs zTOjAj%V(OkRe3p2UEf(=3ZEv|Nu4l*lep<@mND6>$!f(M_;>GqBTRPfIH6yiITf0x zT*rQ0I1?k7=a10R;(! z40>_9IxfrV$S&=}Dt~UD0yt&AE9;x54$GNE(`jNwCp!cV_5wNgv1avT@}%uovWZY0 zD>z_~y$hvN-96Nz-rUhCe z&2EYsqcy(Lq-dB&8zq1ec==taD*p^ohs&4}Gd)5Fc?|_YMkWs6tDx3P5g_eX{^Hwz zw(mErp1gwlJ+DUjC)WafnBo)xlA^Y1H^|D`E6slMIER}L(D{>)cV3z}Q@nVbG&bOr z47AiFX|mI7s0J(VAC>RpN0QN>U4J>E2Tk6r21_vb&fW9Hw=VpkXeTw!t(npI>uKX- zV`;E>fASm=g*U>vePykT|JNEmTInOAg?x%j8)#4fU#%@w-o<;N;o8S3J<+27{xAQ{ zzTeG1|D*rzUNZM3U}Y~tYGw3N@~``s9OSzIPQs?~=AL2{rhe073D(wWXLAioa_T;U zw1`op<5CM~PR@En4VEBley}SX)lGh^`SI?#k>pRMnGns^S_du@x2KEwq25Rcoq!h_ zIr0w5)fYaf+knqA;k@)s<)2!uhCH|hG#yq*^xRgKVAOlK87%K$)rLGm3p6xXkI;CZ z#ICB_1yik<_=c)W0lM^^8ZVg(F5NE8e)?8vQdHcQ!IjH8oj-^3yMXNqj`R9PeOCRW zY>$RKS_`~2mPli*MH8QYf}#wJ1Y6mmeYj&1(6k(2Oegf`kG@mwomE>MU9_cf0>L%7 zLvVM3ySuw*!^Yh`NPyt(&c@x{onXP8jk{~}oxbVc(9fx>x~^xfT64`g#yjMh??c5} zbs0WaFJtDMs|(3l`gdxXKK!=s?A?z+8)P z`@_(|+-lHy+`eHoCh54XG&K%AQ&=~VmcgjIu2Fm#*~+BX>{Arp=4Z)M3$4!g*645k ziRZ1+o!7J4uGT%xz<#;HO zkMdn>5R7u9=i6<>Gjiq_tWNUezKi+v)5mB3s}@E#@`Rwc!#Z+EiHMOjcPzi4WqjGz zTHP2 zE_5Nr)Ygw9b01bE(pUlRA#aLSS{yXUN_ezMBoy2K;>3mv1;>f|$=n&*clnrvKnn_Q z!ig8*CuP^xVzKbbUWZRDCS&r*5pq^I8=S$xADy{|c@D?lo4W4nw;thY)Bx1WHY8jY zV{cB?Quq!^&j}z*rNp<^!ZpBX_`RZo^f~65?!xgI3gGpYFzi$CEACsdeM;$irwl7| z^YpV&olWo*l6^iC*5!6{52L8Y+i@Tsl0q6>vz#mxq9BA7N(`mNh*zM}nB{=U2>Fw0 zscJ_8E+s=@v9_O6^yiTS&pLw5bNq1Vm_I?1q)CI;!bFn>7eD&l@7tV6|5L#^5Nw;8BP7 zzZxP5b&~<66!Tg2FZd7tD#bk_8zC-`D#-EM0<-*q%U*gN_r6v{+1@03na>upWOqg@cXR zd&-b26Yb8~t?MpLBPY=1q*fv~yaO~jbf4`OYSh^vp?Wxw%UkJ0^ve@oG14pCNR#pF zyas(jB4du8O?l6B6!8bHF#=L^iEpsdWu=NAGGXc^V)MyT&dd|xjE~yXJ~zkKU6bL zg7&MvGe{LMNmpp=9>rJO>R6NF9PoX; zA$Y$$PWg8qJ=4(Xbc{QA3Q%(NedZa+lN)3&xWF~5r!b+@{}m~MQn7KrXI0$aREHOH zX#+`l%-bB?ri6e(ui*Qvbu`7qqYFuR2U$$l5Zv<TAAIMhVd;41C7s@!AE{ zLpp?f0O`ayH)_!eqXck46!T`@j7jlMcT9@vEe6W_5uF2}Eji7NfeAZ-22=YlJm|Nk z+>qN18e-RCJ7#47DX2B_<;TkeYHZ+xT2~$> z@33DkgIvlBPU3pjy@^up!w)c5W`y+hfy}%-cRy1N|O@mK3FGoSxUP4_IJ_URJI~u zIQqXx7>!gk3x_57e@GDg@}^aPuZlMyG?vmOn?@aJaxGe94Et9Vd_!GOgQ^}fVnwfJ z!ouj&-u614HEu>nw2c>oD#|c^Pu9ME&qq!6kBm7xpqR%>Eo!LKMA}G2n%hErLZG6k z+;U%F7u0i6G&>k<^{r33HL+bKWsE6vg3;)+C|Tv2(%&XaP0w8J2yC}##yQ?y)LR@8 z2~7FB8N7^bsuHMSq}9md>(W?i$3fb6?zVQ}BNp7aiNg=EPe6JMu@+)ba%t3Y?cW1x z(3EFe%XNpsW%hD$7z;Sv8^KozmWr&E2>{Hn+v3bQD?6}!oG$O1+SL|)JFmux8vg~F%)V8yg{Yue z--+HOO2>J8jo^+dxooFP5dPQuZ=R74NW!HeN9FPNwgf>PVmD_t7>fSmcKowd>jb4e z`z45FoVJR4hdFAcSjcmmfA3WfsV%I-Pe`pd$w!Y^3aBY~P9pH~5GUsld2>=Vf!p2k zBzi?ClNZe~kN18&FXPjF9tPb`-G}qZhAwT5W_-+c2(hn(tbEIyF3CG3j5(dbf=9c5 zM`#cQXsUt@Xf9Val4S>+sJUG=xM2PA(i;+W3N+}uE=JcJo_UVab$j5WPBF!?#=MIf z{=j{XZN^)=bi)QarR6V9CdQ){kT}KI87>&Ds|)RCe6&MzIoMmqf4QcLlNOCK2N#=( z(Uw>#9-g{=z-U3SG|Od!hMHuZtd_p!Cz^@DxS;jW9=3V4>t}wG*(z6+rM~H(w^O>- z#fLbNX}TAT+0V`6ad<4M!mPbP=H+3W3H+?B`h*>k4=&l?mhcJ@?mxgelknh>6M+O` zh~zDq{2AMK%!$X}mN5+A8}@d+gxezaYKgJ5pAFuT)RNrH(<+G3!}By#8`4XEe{f%LRHHq|oAPw#~Ba zY%#F_R&!`)yHoOsOyh#*e0p7;u@T3R+{>^wR8kyUD%H!T5T^kFifz z2*N|GX&xXAC<2!-~yvO@xbH8GW^D3>%JdRKIQ5{px>|SE!wBH?9 z-Ip43JZbSi1D&WZNZ&P`bP>{T>z#CP+}`Tyqqci#dp}+Bj|s{y(8F%L zTU?hKggLZgd3D$Ua%!IcNiW0T{_h~m@AKTCsFX&*ZFYiZ?2T6=3io~n3%N`n4H1sG z$!*v_v<jG(5eZ=jpGR=(9(Y3EPL48 z>(<+}iF5`L&FqH;Sb@lSWLyZ2vuB|=?bg3-k*&4OkNf}Xdvz92l#(fP?!wnJng4`I z$-;7~(agwBLOV#wPy+H^+-cnSA zT7O(@4FY?vO2`S&B6H`ikx#Ys4nrN7zx>yw6mDEAj6r;A=^aJoSir!XDfZ!`{LIcapj zlltH#XwuTg=jY`dajAEP4!QJ%a)_Aze?(6VcoEGV8#r5I1lf>@g342|F44abYJ-H* zpCGaER-)(i469*UOG!aUS$$}vw@6R>)Q=>K3n@-iJa2Ku%LRm4QHCvpUFV!3~hR*U_ zF!ubN;A>XctAmpM1sX#>qF%L9cy$KWqTlvUHe%HxD=h$Hn@hBAq;z0@`-vsuEg0!V z#|IZR$Qr|zsw9`9Tk*7BnWLhA%8m`ZsBw;0ELs3NJRO6j!J$DPP(hKAT8pFkwNbZs zWoq(zqo`XKK#0TfE408npfcE@F&0edw3izf@_GIy))%&@@N3WlVOyLG0vIO3q~Jk= zf1T8<+uBwVes;~5>%0i_8>9k+-VS1HY ztHQgMi6lJ`5vGP7c$wZe*}q^0JHaKQt~8~%diqmr!4#nKP3y<5&cl^gs@Q@RM_3KA zb

#q*-h?_#<#`a9uVYSma^V=uh@9^DxYhtSmD|I6pf$jD>kWI4nw=;L<{3Bw-g^E^~NNj+6bl#^8F!4a9Rs!JD=$hz1i zchuLNr3O*++?j`b#ljTd6pkyn{t+xi{&YY-(@bTs;lBPu`vdA*H53zjjn}_+?ddm< zMBm#4)fFpTG3TNS4IHAarCDV>gMacI+ot~9Js_-NA%##?9%~ea%16h7?xbclYk9jt z#z4)m(W7sz8%i%6FB&r4q@SRETiVPyIS5b{%3tN)zN+b@VlfIhPSluj$58uZ%RXxP zVliKyv4T;6Sbfp!F(N`cH|9SlZ*L1NkE4>#UO!~;CWLl(n56#<+3Mjd5$VM2K}R|r zzYlzzMO9r`7EH80wwZ+k$`^|x`)H@}j_0vy?ZV@LmoH2>c>BX|6h zH$e+?zTCTLL6OLW`BYQtgac=Ngxid>H7+z0s@sxNpup7Y(uWr3j7-J!mm z8qUDSo?j%~}|>Om0!w(YJ#Ew+5e})aYpQCbaJh6i}SQDkpdADihW2 zs8R;8T0adfB2%z$-ka`%Sz4>OAWZ<(9lxgN5v&JK^PY9KTPJ$}5B!fO z9nv?jbm<>hPt~^m%gZnJO6Z&|P!ZpC>Cc<->GR@yWahTL2$1x@j&EOXw2l3m`Vs${ zyYAFJkEEBoN4-cSsUnvo!MHHtLO3Fe$I`9ejJ_e|=5k4pFkvq9Df`@=Dw!$MvO09I`;i@c zs|w*|dUPN)5ms>4?*m(dmrVFl&@*X0(Hwl4NC=3xhj*=Rk`Lyd8mAz%pp+A!zcvWq z#?tuqz^$Yaun(JN1y>{O5l|ypvMj#3wtZ0da|A<^AWWleCaP<%1er#bxD+e{&h4P1iy2KW)gn|}Z%ODvOuN_Dj5G(o|DqK=&% zXy0}0=NPD)?wbFa1&FwUPw-Hm%e~MqJo+rgr$y*TONcrs%Ht4s>W=vvy_moeX9bq} z?l6t3IUz{Nm`7m0+tRn{zOf%pGg2;Cc3eS>63W1qadi>rzl zsia2FH`?{TTfDf&s1S?yDEBy-nj0k1e|`BT45L}V^X+ScVK0pJXMm~&A;u7!ATz;( zZr{^G4wFBu)s|fBT_%aeItRP46Wt%D08JR*Y!JD}#FlI}RiMIwrc?XNqZLuB zpzlVON z%0zP{saSL#QETwC2_|Q8kX*IS%?$~9#KY^M_u#3j7SF@b1< z+#uv@@<*VE2V2b1Y|{Cb{`ITeqd|gzt8vOA)K=schOX#S8V8>l*3NHYlQMQkN7!;O z|9B)61lqtVro&GYDZS0`-RR6){uI4cg3uI=qJmHE0l0RyvVe05wVT3=C64g0HsL3O zCIhNmKe-Ncw*UFxXN>IV>aqG7Yek^uZT`aWpZTGYBt32xpyP?n91PDo5VK6GB zh(EV%>I|5Jigpk<Y!Lh^`A2{6I53NNOgY5@#P2P6aWTfcEBiOEHeL2}Qvv9wa5U z^>GIB*L>Z+@yFd7yQNRhknaNdZ0`}oHJP`jlaJ4HA$)2i_+CJ~nAe%2?)t;to_ zrdQ1ue(V96xknr@dDuPuOCw~50o6*1wLLx1_6gv<9GT2+m*d76pKlu<7?f#2jNPxf z91U8s(5(pq81v3f@GdzjD_bvxZJsE~RApeC={!M2$x{t(-M*YLF2n#a?|(35?QlNN zfjzFUTV+7B;I@t|aPlqGw1khm+jx#2Gl}Mq(-ek;TBOrvw<Q_Y^wNxBD2uQ4;ZXf8y9nJ9C{!t#NV6xpum`dg&f3`lC=cY(Z5B^&37!w zAQV(md+Uwrz%{b)QSc!|y=>=iPlTKscx)_`xtu}c|XL5)}$5*4?tP5$-2}vpsc*y|!TN{0nenu*3$kHM1=4Kz{W?MH# zs&qt;ekdW3uSTo@2&mb@>xs`(e?v}+oOzS@{D4S$@xNJ%4L+UyBG+hItczZV&@zQ; z!1O-N$0Vs-elG|74YAlXf2+G8i;q7k#Z2VQpFfd5CpnIeg%omTHEdfw80d>x(|o=a z{gXC0oKNwn=OQ2O&OQ6R!~^9{D6L_CEvsQ10=!WK- zH6$L)2e$jBK;kGE@dMQ2+enjt|9Ey3A_yB=_md^3Tv(Phs0KS40aGN2i7#{LZORK?_zfG1i2mz;B$bs~{;NM0e=KB=Fr0mg*D7OP1x}nE z8Mbq$NDpwqrvP{HN(8}T9p>&>=z-CV)xpWMf)3Kjyji{#XYR}mWCQ=*d*{KTvU(FZ zR?#b&k(B9Iat=Vc4#xvtm5@S17OngQYDvyAd8TZ69w#RP`CIwM`u53Q^?}?u)qYkx zxZmAIVGemG#p8!*VGg?gC<6z{N{>5DHlo7BUx2qVQ|Z-rNK4lk*R9TamI2>D+#!>U zkFbYTyt2Wc=+Z34!(57oEP$Fm{UK~kS({#M{|HH2x`ta_$c2G*rWO!xEi*m+q<$S^GRv)F;RK;Ho@J+m)l$El&~ zwGtyQU|OOX#oGI{hJ&C9V$_xP?*8@M0lGPCPihc$Zh5QBcq)h9LWUNi-`IcBA(3SVM(Pb#~vytjUVM7)ynmt+J|FVli11TfAjCeCn(@X@h)|3rqQiw8-J;?>AxNr%z}K|TgY0-`=s|6OBb)}KOzilbUw+;{C%7{`!(*g z7BCP$ArYcLoekxVOCHc$jZT)y(6WZcnL<8g><1fN)|kDu9^V%5m(vdqf$}CC+S}gZj%QnU7s_T0sF1}rRU^@dEu?uf z-;1<~;OnY)FfwBit)291LEkS098K%mTDf#$<)%^aqVDEs89TL2IKye?bjvO0yHh*Rl%7>r`hgjWhBAnR#xIX-YLAo}N4fhDq$Xza2E z7-%Dml(VP3t17kxjAJrI=Gjs_b#LUXI8q$Z+4Pey6l3URE6_+g*=x-PHdul&#|ipkTIltqzDTv;F83Hm!-C{R zN8-K1BkWkZb51LtuBO>+FmUbL1IFY57X2MviBDFQ!iN&3%bcmCOGcQ(h zlrsSVD?mFSl~YD2Ej+G7SKTsTm;L>G@l)@ze%5a9#(UDIyYi*kbaX71d`u=ha?BJ8 z!O;|+I_4n3)sfrkue4#33ySB$E$oSw%<`YeB zD>#s$Gj!bMko7i+qud39MBy4XzSmL6cl(56jh40!ZG7DAmH21fD!_C7sv-F5rA#dZ z+mpUf!1VR#F{apN)%_hwwP4%r`tjjNSCWy;ar766vBN)`<(Y1$HFZmM-Pbzk+PrWt zxCz4y#p%+g3?Qq~1tHb<{;`Y3-7-g1(@{Vq&rSNwS5uHRB{os49@>e9nwEndnO2iN zXe5{u2ZY<&AU!JFO4t>9X9FIvZ9QMe2N87;i!-nAk_&u^w|B}aRP#`>EJ0^x!_t~B zZuyHwU5H|wYjwZgTPZcZH3LIOp39>mT_-(?{{HQt=9_{f>1A83vBD&!vfyIA9mjDC zBh4ag3Z>~+R z_T6d}Wg|U%>EK@bek^yATA+hfr?Vr1>PiuUxmB*;_WZ7n3WH{x2GYMhk3Re*j(f;t z%q~64YEF`dy|l-|Pv5@EfL7c}K04FG@y>dM=EJiP=nd(oRC@ydxDHpwZfww`Ewj!B z7_)oCv(MX3R(eUeP6ujzG%3{D*nbCqNLMTBWWi3u-v7h7{iEQyuh&14r%h$e_x9m* z;vQh|Eot@Yt{!yO+(rt^fUCBaltlxk3APYjY|1EEDNm_jW_&6tv0 zWmVMZUuY(yQtoR}lp!%dznEke$(k;0|AYmmf(|ZrlCXrj1(lDH zP|UfupH2FR;v0X^;(dvv$^NQk!ZJ**Iqb3i^wRaQ|D{7v_SI?gLGK|#m?A&CH{Wq| zE8T%5nQ&qqrrvD7?^$$)(~-i+|45B?&Z$Vd`8(nyQtP0622E~e6m>F_elV_CT(9U{ zczRvX%X5u>g))-eZ&he?b|K#3(_#IczqmW~#k=PR4WLZu5@$g1V7>0sXn*Tbp>KjMhl_U&zpF?> z&_*oM_6>LU1M7ChCY{uMz?T5o1H}^;G^Fo)sguDfYgyd6i>r;GC zVE@sON8Q!56>~~RL1TdFOB6i|lW+`l*Dq26X%TC|T|y?33X^ut)mZo|-wLhp3Q23S zw#R;7X*<3U97o;g!KiDV0b5qR%VYHlqx#>>5fst6J1ry%5m{58w8BJ~j;yaKJ&d^Jgh1?cKp&B;LxFRIOz6S{iKTh;HoxQo7x zxLofsz{gIZC-^F75WxSzs@oqEQrhhya4#nHnr=-dCE!LoC0vf;-j?w! z_T$xFs}pGS4w~L1oN&WJCqy5C%^c#|?z3p3j*dW_gfPTu*vkt?mMp!^AoU+uJPV4t z`b_z$2+!DjEAThu+o(kc@Cv=7Gp>s z;2`gl6aA}qM6KBj?0i1kooff($Q0BxFo74_T90QQr_FrZbj2-cg6i#ASYz`dwFi;I z7mjcIpO`@h9V_qtSJmB4t9%y?+dhAJbDMEg zb8764R5q5t=5K8_tM?F^^Wls;m2NRhJLQUV%2X}BzKv%2{6D>jg_peDl0eP-_qJNZ z=g9mSc>XOQYPFq%b}6Ax?G6iax~|7C2G-Qp`(27(rT&*R$A3uHsP5H9n_hLHu~h7j zp#w4Kr!hah1t7sJWU#Q1&pwLBaEPefMcRfRp)U{RLQINK_pNszOm=aH{RR1^Xnp1W zG+?+!h{rGDC0v^z^_^->z9EP;>F;png5Iey64bwp%koJ%7BGjFlv315DYM@;YH7wN zCql~#FT(ZW)@=6DZPfUM+8bLWmt&zdR8{vZAwRhv+?)etoXD&{7KPS3&N{*QnL8W0 zrD{BA5Yv-rXUP^I!b)CebhFGJMqqRc0D$>dVJ&FDXx0IDV?4{KYp-8VQ8@4}nZjTd z6~kJtZ)VuNLzOLhm+56Y;=!Ed-ya=fXR4WWC+;PTO9g{oXSLPErhMWzBN)P**0vu= zirA2$cLDsiYxV<)ogVi@gTUG!uDCLVE0a;ME2jHx22Atv(xhmqc$tlNVLAY4s>kHz zP#}s&2Wx3qtbFVD3B9{bN!8HIuteC$%wWTi;dtETGw@=s)d^~FQ z2hGF#)}NdfeSD~!)=*o~U}!Ze@09WQA=rVv`YB_I7jz5b{!aeg@RC%Xg^S-Ox^iKs zp#{^iqx|%6e@Pw#3hQi0`nr0bV*3{Nu!m;-glWX|cQv!i9nen-6?91ofC7P9F1qS2 zh~I=Q8y0wTvSrq}VX&yoTa3|CB>E<2w+XO&H@`4mOEp%Kl}aNB7kh=wM<<$@G!ZYt zGI+P3L`0MQ^RH}8SRAO(Pc!Nkco^1QXz;q%F<|>8=jjVx^I3@juK+Y2a+Vq-^-b`s zlYby}4layexsq$ZK2ji$u=K8{-3ohyoBH=tDR?jB*A~|v8_LKE@9m|ZGFtbR<$hBn zYX!~CP7GqCS^ZU;_kL=6TMI@@H5gH8oyTqV4N*@57rhgv>HJH}o}_U!QY)$9;A^_B zlTgyG!au=Y7j=lk{CcvW4YRllA1`Q@>BJL322^e+{pj4lj(Zp(&JTfo$_aC(QHb~^ ztMlijEI}t=&mtd=@XW~Q(e|!$R|)4qBG&dzq=e{4J#~ z<@xDh(U1MKz&gF?z*5Iwc^=DEbqs;CFmCk*VtA!f7H%{Ma(c^bg6p(}k+~h5SVDxI z#gubjX*PXr%n(kgyW*gB7-$#~?^uko1hjq6es$}xJ{2ke1sBV&ddn~_q<@l5QB-Ju z$EHr20mxCw=wgCf$xFTCM9!}Dst%<1M^A}=S>jFp(U;+5N!Q7vkA$invF&SWw!|S@ zUUmmgnrCKagsA=jBi6PuN@M}osb)G=%G=+(te1ucfmRq~f^YxaRS!LkYSmR>o&lDV zoi_(IMKi2}iJR>&MZcP2?Hjhue+~nr7QIX-(Dc2zv*e${Y-AjCaJ{Jm_u$=ya`>AR z8wKV&y@M@_NpTtenxRoh=2L!OoJK|h<6*-}BVR8MfAITiGvS?hzWF%iaJs&n<1WEpweO7-xITL*zODi5 zDILA*`DHqL1Zkqhn49CX$-I$4taxk7ZfxxorD#|J+^z_`KC4W1Zu0X`$MQ~E(Itx8 zjVP8K499oW!FEt8Z42ut4iaVDJ=9_NY6KYIuieEbDkqJ z=mTxSF`t`UPfZbUKKAmg$hE7~r-?nw=V=NJx9X*G==K#_>ffLCHmb-{VP^;L+@NG)a+sxgzTP`#|9dHwyI$6fZ?*@2pRe z>b;pGnI#ewmIoW`+LZAkX_`o&^(vuAA3eB{WWUw zhe^GoZC<+K5kXz!YMY$!r-a^f(-l}qL)wxI0f+~%dH?h>X;=|V{<#pLKu2X>XFGS9 zbc_j~Q&t0Ltc=SJa$~$hL{FepdAl3_0Ks&2d%YV=z&*^uB+s?+wtt1>Ojrq}s4YZB zW-?zr0D%>|xJ@rbo6O8=4dePxM?!xTF{mu};0PKo2-~h7(d|8o8`pN!+T8&j&=s_c zYf>?W!zJRwW&jMD;ULL?JAlw)o59+*KM#?VH| zZ2O%C(Pc<5F8$~?=vIxQK$hc2Vmr0EI3ePv*gJrhgn=m;2HDjvDr`gye~IqlY$B$wwt6D4I$GE5eujGLmH=k4paz?WTLB%tL&rdst}HMlzZbnsVO^ zr9>HcB<0f-Mj5i+ckla=Uu-A!26NAW`r>nAJgeah$)A}-kX3shk(0p~)Tm+jrJ6$(b)AX|tgMcWvz-etgD%44tGO-4DR7_Qu#ggAArb(Xm;Gb5A*#}VGa zjR8jVy)C_?#Y0cD@A%hlr{M&fqq)Zve+|6FCA0Xj&FKPXQO;hi%MwfBl zg608*G(AgC%M$(mc~U9kUSSTG3MjS%DWvv-LUy&XXGZlWan1X{+MrOL}~s_=a6?$>U!ZdHsOZEQRi zoY~P)FwZiO)Go+dGiA7m^J}c_xZtJRXh3U;t3r>y92ugqglZQr@KwKJTcv~T$%nW8 z2QA8P&b$yTd(M zdo9Doj(L0?B*^2N_K0U1bWO__dm?wwSc|XgNrt4)DK+{MKN)Dyx`042)5^yJgU*c{ z<@mN(%35abfTwWX;Fhm?mOb9z-HLE3h?f;8(AC81OS zRs36;S-MQGRYR`4shpdZ?eV~UVRxC=fhdYdvziGT>3crN3qkciTG}joi zgwbe(gyzFWqcLNlHu3P5X+k8VNm5orqIR8W+vo{feGOsrX{Vb`%^^CFwcUF4AoTdP zDDiCUx5#f#vEWbFEf4z=F87Y8%e4 { const [initDims, setInitDims] = useState(null); const [qcDims, setQcDims] = useState(null); + const [inputData, setInputData] = useState(null); + // loaders for UI components const [showDimPlotLoader, setShowDimPlotLoader] = useState(true); const [showMarkerLoader, setShowMarkerLoader] = useState(true); @@ -92,7 +94,7 @@ const App = () => { const [colorByAnnotation, setColorByAnnotation] = useState("clusters"); // PCA - const [pcaVarExp, setPcaVarExp] = useState(null); + const [pcaVarExp, setPcaVarExp] = useState({}); // Cluster Data // which cluster is selected @@ -133,6 +135,10 @@ const App = () => { // request annotation column const [reqAnnotation, setReqAnnotation] = useState(null); + // modality + const [modality, setModality] = useState(null); + const [selectedModality, setSelectedModality] = useState(null); + // props for dialogs const loadingProps = { autoFocus: true, @@ -150,7 +156,7 @@ const App = () => { setGeneColSel, setLoadParams, setInitLoadState, inputFiles, annotationCols, setAnnotationCols, annotationObj, setAnnotationObj, preInputFiles, - setPreInputFilesStatus } = useContext(AppContext); + setPreInputFilesStatus, geneColSel } = useContext(AppContext); // initializes various things on the worker side useEffect(() => { @@ -180,13 +186,14 @@ const App = () => { // request worker for new markers // if either the cluster or the ranking changes useEffect(() => { + if (selectedCluster !== null && selectedModality != null) { - if (selectedCluster !== null) { let type = String(selectedCluster).startsWith("cs") ? "getMarkersForSelection" : "getMarkersForCluster"; scranWorker.postMessage({ "type": type, "payload": { + "modality": selectedModality, "cluster": selectedCluster, "rank_type": clusterRank, } @@ -194,7 +201,7 @@ const App = () => { add_to_logs("info", `--- ${type} sent ---`); } - }, [selectedCluster, clusterRank]); + }, [selectedCluster, clusterRank, selectedModality]); // compute markers in the worker // when a new custom selection of cells is made through the UI @@ -233,17 +240,18 @@ const App = () => { // get expression for a gene from worker useEffect(() => { - if (reqGene) { + if (reqGene != null && selectedModality != null) { scranWorker.postMessage({ "type": "getGeneExpression", "payload": { - "gene": reqGene + "gene": reqGene, + "modality": selectedModality } }); add_to_logs("info", `--- Request gene expression for gene:${reqGene} sent ---`); } - }, [reqGene]); + }, [reqGene, selectedModality]); useEffect(() => { @@ -390,6 +398,17 @@ const App = () => { } }, [preInputFiles, wasmInitialized]); + useEffect(() => { + if (selectedModality) { + setGenesInfo(inputData.genes[selectedModality]); + if (geneColSel[selectedModality] == null) { + let tmp = geneColSel; + tmp[selectedModality] = Object.keys(inputData.genes[selectedModality])[0] + setGeneColSel(tmp); + } + } + }, [selectedModality]); + // callback for all responses from workers // all interactions are logged and shown on the UI scranWorker.onmessage = (msg) => { @@ -429,13 +448,25 @@ const App = () => { } setIndexedDBState(false); } else if (payload.type === "inputs_DATA") { - setInitDims(`${payload.resp.dimensions.num_genes} genes, ${payload.resp.dimensions.num_cells} cells`); - setGenesInfo(payload.resp.genes); - setGeneColSel(Object.keys(payload.resp.genes)[0]); + var info = []; + if ("RNA" in payload.resp.num_genes) { + info.push(`${payload.resp.num_genes.RNA} genes`); + } + if ("ADT" in payload.resp.num_genes) { + info.push(`${payload.resp.num_genes.ADT} ADTs`); + } + info.push(`${payload.resp.num_cells} cells`); + + setInitDims(info.join(", ")); + setInputData(payload.resp); if (payload.resp?.annotations) { setAnnotationCols(Object.values(payload.resp.annotations)); } + + let pmods = Object.keys(payload.resp.genes); + setModality(pmods); + } else if (payload.type === "quality_control_DATA") { const { resp } = payload; @@ -453,14 +484,52 @@ const App = () => { resp["ranges"] = ranges; setQcData(resp); - setQcDims(`${resp.retained}`); setShowQCLoader(false); + } else if (payload.type === "adt_quality_control_DATA") { + const { resp } = payload; + + if (resp) { + var ranges = {}, data = resp["data"], all = {}; + + for (const [group, gvals] of Object.entries(data)) { + for (const [key, val] of Object.entries(gvals)) { + if (!all[key]) all[key] = [Infinity, -Infinity]; + let [min, max] = getMinMax(val); + if (min < all[key][0]) all[key][0] = min; + if (max > all[key][1]) all[key][1] = max; + } + ranges[group] = all; + } + + resp["ranges"] = ranges; + + let prevQC = {...qcData}; + for (const key in data) { + prevQC["data"][`adt_${key}`] = data[key]; + let tval = resp["thresholds"][key]; + if (key === "sums") { + tval = null; + } + prevQC["thresholds"][`adt_${key}`] = tval; + prevQC["ranges"][`adt_${key}`] = ranges[key]; + } + + setQcData(prevQC); + } + + setShowQCLoader(false); + } else if (payload.type === "cell_filtering_DATA") { + setQcDims(`${payload.resp.retained}`); } else if (payload.type === "feature_selection_DATA") { const { resp } = payload; setFSelectionData(resp); } else if (payload.type === "pca_DATA") { const { resp } = payload; - setPcaVarExp(resp); + setPcaVarExp({RNA: resp["var_exp"]}); + setShowPCALoader(false); + } else if (payload.type === "adt_pca_DATA") { + const { resp } = payload; + setPcaVarExp({...pcaVarExp, ADT: resp["var_exp"]}); setShowPCALoader(false); } else if (payload.type === "choose_clustering_DATA") { const { resp } = payload; @@ -499,20 +568,25 @@ const App = () => { } else if (payload.type === "marker_detection_DATA") { if (!selectedCluster) { // show markers for the first cluster + if (selectedModality == null) { + setSelectedModality(modality[0]); + } setSelectedCluster(0); } } else if (payload.type === "tsne_DATA") { const { resp } = payload; setTsneData(resp); - let tmp = [...redDims]; - tmp.push("TSNE"); + if (redDims.indexOf("TSNE") == -1) { + let tmp = [...redDims]; + tmp.push("TSNE"); + setRedDims(tmp); + } // once t-SNE is available, set this as the default display if (!defaultRedDims) { setDefaultRedDims("TSNE"); } - setRedDims(tmp); // also don't show the pong game anymore setShowGame(false); setShowAnimation(false); @@ -525,9 +599,11 @@ const App = () => { setUmapData(resp); // enable UMAP selection - let tmp = [...redDims]; - tmp.push("UMAP"); - setRedDims(tmp); + if (redDims.indexOf("UMAP") == -1) { + let tmp = [...redDims]; + tmp.push("UMAP"); + setRedDims(tmp); + } setShowGame(false); setShowAnimation(false); @@ -575,8 +651,15 @@ const App = () => { setIndexedDBState(false); } else if (payload.type === "loadedParameters") { const { resp } = payload; + + resp["ann"] = {}; + resp["ann"]["approximate"] = resp["batch_correction"]["approximate"]; setLoadParams(resp); + if (!resp?.combine_embeddings?.weights) { + resp["combine_embeddings"]["weights"] = {}; + } + if (resp?.custom_selections?.selections) { let cluster_count = clusterColors.length + Object.keys(resp?.custom_selections?.selections).length; let cluster_colors = null; @@ -606,6 +689,10 @@ const App = () => { setShowCellLabelLoader(false); } else if (payload.type === "PREFLIGHT_INPUT_DATA") { const { resp } = payload; + if (resp.details.features) { + let pmods = Object.keys(resp.details.features); + setModality(pmods); + } setPreInputFilesStatus(resp.details); } else if (payload.type === "custom_selections_DATA") { } else if (payload.type === "tsne_CACHE" || payload.type === "umap_CACHE") { @@ -685,6 +772,7 @@ const App = () => { setClusHighlightLabel={setClusHighlightLabel} colorByAnnotation={colorByAnnotation} setColorByAnnotation={setColorByAnnotation} + selectedModality={selectedModality} /> : showGame ?

{ gene={gene} clusterColors={clusterColors} setReqGene={setReqGene} + modality={modality} + selectedModality={selectedModality} + setSelectedModality={setSelectedModality} /> :
{ if (loadParams && tabSelected === "load") { setTmpInputParams(loadParams); + console.log(loadParams); } }, [loadParams]); @@ -161,87 +163,98 @@ const AnalysisDialog = ({ useEffect(() => { if (tmpInputFiles) { - if (tabSelected === "new") { - let all_valid = true; - // tmpInputFiles.forEach((x, ix) => - for (let ix = 0; ix < tmpInputFiles.length; ix++) { - let x = tmpInputFiles[ix]; - if ( - (x?.mtx && !(inputText[ix]?.mtx.toLowerCase().endsWith("mtx") || - inputText[ix]?.mtx.toLowerCase().endsWith("mtx.gz") - )) || - (x?.genes && !(inputText[ix]?.genes.toLowerCase().endsWith("tsv") || - inputText[ix]?.genes.toLowerCase().endsWith("tsv.gz") - )) || - (x?.annotations && !(inputText[ix]?.annotations.toLowerCase().endsWith("tsv") || - inputText[ix]?.annotations.toLowerCase().endsWith("tsv.gz") - )) - ) { - all_valid = false; - } - if ( - x?.h5 && !( - inputText[ix]?.h5.toLowerCase().endsWith("hdf5") || - inputText[ix]?.h5.toLowerCase().endsWith("h5") || - inputText[ix]?.h5.toLowerCase().endsWith("h5ad") - ) - ) { + if(tmpInputFiles.length == 0) { + setTmpInputValid(false); + } else { + if (tabSelected === "new") { + let all_valid = true; + + // tmpInputFiles.forEach((x, ix) => + for (let ix = 0; ix < tmpInputFiles.length; ix++) { + let x = tmpInputFiles[ix]; + + if ( + (x?.mtx && !(inputText[ix]?.mtx.toLowerCase().endsWith("mtx") || + inputText[ix]?.mtx.toLowerCase().endsWith("mtx.gz") + )) || + (x?.genes && !(inputText[ix]?.genes.toLowerCase().endsWith("tsv") || + inputText[ix]?.genes.toLowerCase().endsWith("tsv.gz") + )) || + (x?.annotations && !(inputText[ix]?.annotations.toLowerCase().endsWith("tsv") || + inputText[ix]?.annotations.toLowerCase().endsWith("tsv.gz") + )) + ) { + all_valid = false; + } + + if ( + x?.h5 && !( + inputText[ix]?.h5.toLowerCase().endsWith("hdf5") || + inputText[ix]?.h5.toLowerCase().endsWith("h5") || + inputText[ix]?.h5.toLowerCase().endsWith("h5ad") + ) + ) { + all_valid = false; + } + + if (x.format === "MatrixMarket") { + if (!x.mtx) all_valid = false; + } else { + if (!x.h5) all_valid = false; + } + }; + + let tnames = tmpInputFiles.map(x => x.name); + if ([...new Set(tnames)].length != tmpInputFiles.length) { all_valid = false; } - - if (x.format === "MatrixMarket") { - if (!x.mtx) all_valid = false; - } else { - if (!x.h5) all_valid = false; - } - }; - - let tnames = tmpInputFiles.map(x => x.name); - if ([...new Set(tnames)].length != tmpInputFiles.length) { - all_valid = false; - } - - setTmpInputValid(all_valid); - - if (all_valid && tmpInputFiles.length > 0) { - let mapFiles = {}; - for (const f of tmpInputFiles) { - mapFiles[f.name] = f + + setTmpInputValid(all_valid); + + if (all_valid && tmpInputFiles.length > 0) { + let mapFiles = {}; + for (const f of tmpInputFiles) { + mapFiles[f.name] = f + } + + setPreInputFiles({ + "files": mapFiles, + }); } - - setPreInputFiles({ - "files": mapFiles, - }); - } - - } else if (tabSelected === "load") { - - if (inputText?.[0]?.file == null) { - setTmpInputValid(true); - } else { - if (!tmpInputFiles?.[0]?.file) { - setTmpInputValid(false); + + } else if (tabSelected === "load") { + + if (inputText?.[0]?.file == null) { + setTmpInputValid(true); } else { - if (loadImportFormat === "kana" && - inputText?.[0]?.file != null && !(inputText?.[0]?.file.toLowerCase().endsWith("kana") - ) - ) { - setTmpInputValid(false); - } else if (loadImportFormat === "kanadb" && tmpInputFiles?.[0]?.file === null) { + if (!tmpInputFiles?.[0]?.file) { setTmpInputValid(false); } else { - setTmpInputValid(true); + if (loadImportFormat === "kana" && + inputText?.[0]?.file != null && !(inputText?.[0]?.file.toLowerCase().endsWith("kana") + ) + ) { + setTmpInputValid(false); + } else if (loadImportFormat === "kanadb" && tmpInputFiles?.[0]?.file === null) { + setTmpInputValid(false); + } else { + setTmpInputValid(true); + } } } } } - if (!loadParams && (tmpInputFiles[0]?.batch !== undefined && tmpInputFiles[0]?.batch !== "none") || (tmpInputFiles.length > 1)) { - setTmpInputParams({ - ...tmpInputParams, - "pca": { ...tmpInputParams["pca"], "pca-correction": "mnn" } - }) + if(tmpInputFiles.length > 1 || + (tmpInputFiles.length == 1 && (tmpInputFiles[0]?.batch && tmpInputFiles[0]?.batch.toLowerCase() != "none")) + ) { + setTmpInputParams({ ...tmpInputParams, + "batch_correction": { + ...tmpInputParams["batch_correction"], + "method": "mnn" + } + }); } } }, [tmpInputFiles]); @@ -266,7 +279,7 @@ const AnalysisDialog = ({ all_valid = false; } - if (!x.mtx) all_valid = false; + if (!x.mtx && (sinputText?.mtx !== "Choose Matrix Market file")) all_valid = false; } else if (x.format === "10X") { if (x?.h5 && !( @@ -277,7 +290,7 @@ const AnalysisDialog = ({ all_valid = false; } - if (!x.h5) all_valid = false; + if (!x.h5 && (sinputText?.file !== "Choose file...")) all_valid = false; } else if ( x.format === "H5AD") { @@ -288,7 +301,7 @@ const AnalysisDialog = ({ all_valid = false; } - if (!x.h5) all_valid = false; + if (!x.h5 && (sinputText?.file !== "Choose file...")) all_valid = false; } // setTmpInputValid(all_valid); @@ -510,6 +523,121 @@ const AnalysisDialog = ({

} + {showStepHelper === 9 && + +

+ Build the index for the nearest neighbor search. + This is used for a variety of steps including the graph-based clustering, t-SNE and UMAP. +

+

+ Approximate: + Use an approximate neighbor search algorithm - in this case, the Annoy method. + This sacrifices some search accuracy for speed, which is usually acceptable for single-cell applications. + Otherwise, an exact algorithm is used. +

+
+ } + {showStepHelper === 10 && + +

+ Remove batch effects between cells from different samples. + This places all cells in a common coordinate space for consistent clustering and visualization. + Otherwise, the interpretation of downstream analysis results may be complicated by large sample-sample differences, + obscuring the heterogeneity within samples that is usually of interest. +

+

+ Correction method: + Which correction method to use - no correction, linear regression or mutual nearest neighbor (MNN) correction. + MNN correction is the default and handles situations with differences in cell type composition across samples. + Linear regression is simpler but assumes that all samples have the same proportions of cell types, with a consistent batch effect in each cell type. + Users may also choose not to correct if, e.g., the sample-sample differences are interesting. +

+

+ Number of neighbors: + Number of neighbors to use to identify MNN pairs. + Using larger values will yield a more stable correction but also increases the risk of incorrectly merging unrelated populations across samples. +

+
+ } + {showStepHelper === 11 && + +

+ Remove low-quality cells based on the ADT counts. + This uses the number of detected features and, if available, the total count for isotype (IgG) controls. + Cells with few detected features or high isotype counts are filtered out; + this is combined with the RNA-based filters to ensure that cells are only retained if they are informative in both modalities. + We again use an outlier-based approach to define the filter threshold for each metric. +

+

+ Number of MADs: + Number of median absolute deviations (MADs) from the median, + used to define a filter threshold in the appropriate direction for each QC metric. + Increasing this value will reduce the stringency of the filtering. +

+

+ Isotype prefix: + Prefix to use to identify features in the dataset that are isotype controls. + This is not case-sensitive. +

+
+ } + {showStepHelper === 12 && + +

+ Log-normalize the ADT count data. + This involves some more work than the RNA counterpart as the composition biases can be much stronger in ADT data. + We use a simple approach where we cluster cells based on their ADT counts, + normalize for composition biases between clusters using an median-based method, + normalize for library size differences between cells within clusters, + and then combine both to obtain per-cell factors. +

+

+ Number of clusters: + Number of clusters to use in the initial k-means clustering. + This clustering will not be used in any downstream steps; it is only used here to separate major subpopulations with strong DE. + Any rough clustering is fine and it should not be necessary to spend much time fine-tuning this parameter. + Overclustering is acceptable - and possibly even desirable - provided that each cluster still contains enough cells for stable median calculations. +

+

+ Number of PCs: + Number of principal components to use for the clustering. + We perform a PCA to compress the data for faster clustering - this has no bearing on later choices of the number of PCs. + Again, as long as a reasonable clustering is obtained, it should not be necessary to spend much time fine-tuning this parameter. + In fact, if the requested number of PCs is greater than the number of ADTs, this parameter will have no effect. +

+
+ } + {showStepHelper === 13 && + +

+ Perform a principal components analysis (PCA) on the log-normalized ADT matrix. + As for RNA, the PCA is used for compression and denoising prior to downstream steps like clustering and visualization. + However, unlike RNA, no feature selection is performed here as there are relatively few ADTs in the first place. +

+

+ Number of PCs: + Number of principal components with the highest variance to retain in downstream analyses. + Larger values will capture more biological signal at the cost of increasing noise and computational work. + If more PCs are requested than ADTs are available, the latter is used instead. +

+
+ } + {showStepHelper === 14 && + +

+ Combine PC embeddings from multiple modalities. + This yields a single matrix that can be used in downstream analyses like clustering, + allowing us to incorporate information from multiple modalities. + By default, each modality is given equal weight in the combined matrix. +

+

+ Modality weights: + Weight for each modality. + A larger value indicates that the corresponding modality will contribute more to the population heterogeneity in the combined embedding. + A value of zero indicates that the corresponding modality should be ignored in downstream analysis. +

+
+ } ) } @@ -518,10 +646,10 @@ const AnalysisDialog = ({ return (
-
2 +
setShowStepHelper(2)}> - Quality control + Quality control (RNA)
@@ -571,10 +699,10 @@ const AnalysisDialog = ({ return (
-
3 +
setShowStepHelper(3)}> - Feature Selection + Feature selection (RNA)
@@ -602,10 +730,10 @@ const AnalysisDialog = ({ return (
-
4 +
setShowStepHelper(4)}> - Principal components analysis + Principal components analysis (RNA)
@@ -631,25 +759,6 @@ const AnalysisDialog = ({ placeholder="25" value={tmpInputParams["pca"]["pca-npc"]} onValueChange={(nval, val) => { setTmpInputParams({ ...tmpInputParams, "pca": { ...tmpInputParams["pca"], "pca-npc": nval } }) }} /> - { - (tmpInputFiles.length > 1 || (tmpInputFiles.length == 1 && tmpInputFiles[0]?.batch && tmpInputFiles[0]?.batch.toLowerCase() != "none") - || (loadParams && loadParamsFor === loadImportFormat)) && - }
@@ -660,7 +769,7 @@ const AnalysisDialog = ({ return (
-
5 +
setShowStepHelper(5)}> Clustering @@ -707,17 +816,6 @@ const AnalysisDialog = ({ placeholder="10" value={tmpInputParams["cluster"]["clus-k"]} onValueChange={(nval, val) => { setTmpInputParams({ ...tmpInputParams, "cluster": { ...tmpInputParams["cluster"], "clus-k": nval } }) }} /> -