From a36fa8b4d4f2d5937dae48c1b912848fb4b1dba9 Mon Sep 17 00:00:00 2001 From: Kevin Gorham Date: Wed, 27 Nov 2019 09:24:00 -0500 Subject: [PATCH] Added startup workflows. - added home screen banner and logic to show/hide messages - added no balance banner and behavior - added landing and backup screens - fixed and finished receive screen - added back buttons - switched from rounded to cut corners - added sound and vibration - added ability to detect dev environment and adjust behavior --- app/src/main/AndroidManifest.xml | 2 + app/src/main/assets/sound_receive_small.mp3 | Bin 0 -> 50225 bytes .../java/cash/z/ecc/android/ZcashWalletApp.kt | 11 +- .../cash/z/ecc/android/di/AppComponent.kt | 6 +- .../main/java/cash/z/ecc/android/ext/View.kt | 31 ++ .../cash/z/ecc/android/ui/MainActivity.kt | 49 ++- .../android/ui/detail/WalletDetailFragment.kt | 10 +- .../z/ecc/android/ui/home/HomeFragment.kt | 79 +++- .../ecc/android/ui/receive/ReceiveFragment.kt | 5 +- .../z/ecc/android/ui/send/SendFragment.kt | 10 +- .../z/ecc/android/ui/setup/BackupFragment.kt | 63 +++ .../z/ecc/android/ui/setup/LandingFragment.kt | 89 ++++ .../main/res/drawable/background_banner.xml | 7 + .../res/drawable/background_title_primary.xml | 7 + .../res/drawable/ic_arrow_back_black_24dp.xml | 9 + app/src/main/res/drawable/ic_logo_landing.xml | 55 +++ app/src/main/res/layout/fragment_address.xml | 19 + app/src/main/res/layout/fragment_backup.xml | 187 ++++++++ app/src/main/res/layout/fragment_confirm.xml | 19 + app/src/main/res/layout/fragment_detail.xml | 14 + app/src/main/res/layout/fragment_home.xml | 403 ++++++++++-------- app/src/main/res/layout/fragment_landing.xml | 83 ++++ app/src/main/res/layout/fragment_memo.xml | 19 + .../main/res/layout/fragment_placeholder.xml | 35 -- app/src/main/res/layout/fragment_receive.xml | 296 +++++++------ app/src/main/res/layout/fragment_send.xml | 14 + .../res/layout/fragment_wallet_import.xml | 19 + .../main/res/layout/fragment_wallet_new.xml | 19 + .../main/res/navigation/mobile_navigation.xml | 23 +- app/src/main/res/values/strings.xml | 2 +- app/src/main/res/values/styles.xml | 22 +- 31 files changed, 1237 insertions(+), 370 deletions(-) create mode 100644 app/src/main/assets/sound_receive_small.mp3 create mode 100644 app/src/main/java/cash/z/ecc/android/ext/View.kt create mode 100644 app/src/main/java/cash/z/ecc/android/ui/setup/BackupFragment.kt create mode 100644 app/src/main/java/cash/z/ecc/android/ui/setup/LandingFragment.kt create mode 100644 app/src/main/res/drawable/background_banner.xml create mode 100644 app/src/main/res/drawable/background_title_primary.xml create mode 100644 app/src/main/res/drawable/ic_arrow_back_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_logo_landing.xml create mode 100644 app/src/main/res/layout/fragment_address.xml create mode 100644 app/src/main/res/layout/fragment_backup.xml create mode 100644 app/src/main/res/layout/fragment_confirm.xml create mode 100644 app/src/main/res/layout/fragment_landing.xml create mode 100644 app/src/main/res/layout/fragment_memo.xml delete mode 100644 app/src/main/res/layout/fragment_placeholder.xml create mode 100644 app/src/main/res/layout/fragment_wallet_import.xml create mode 100644 app/src/main/res/layout/fragment_wallet_new.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d438d98..92a013f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ xmlns:android="http://schemas.android.com/apk/res/android" package="cash.z.ecc.android"> + + K4! zOdwNqb!2I8ATcsjLQqWr000C4001#GF#r1COi3dE00kjby;Ti>0EOyEO`#+KC@wEG zxr_h=`98v04BX@Lp)00^N3P%t;*eHJXK*p^R#mQQ~P0zi>3D%nsz0L zYSII7-ZO*8HusyaUt&OjOil<0hmfyczt#z4_weAr!1Got?Y-~xUi{Hw$0^e@H*I_P z+y9I#SmvB8>)!u4f67hQzc;<-7+Fm)FmqR#nZE&G;(hT6r0E*?jy>-;>9t9vOX#O0O%qZ4?v%YA(4_nX*b0$6*TzjLf0@w*SQ( zhjPS8VI4-6%$?O^YZc(;zXiLHl?YhxnsvEwJZZ$0u89U}9V};89+e>gNF$HBf-=R? z0l)5C0XECwxE@lbYh5)i(jdD#ccd^9`-X6USY$Osx!;U!H2K=D+}-$oZZ2Jj6WQBe zpNvvr8^48C2Jol4t(7ff0j2D9t~3Wh?|GCwsCdJy*V-HpO)6`T<(cl^y1*^tPj3!> z9PK41FsWnz|NsC0{rX|Dcw())H{Bi3E)tg5qH41R) z=-pX-s~Vh+2Sc&w@OnNQk4K}h0YTb9P}a2JmUueu5TD_x+}d*C{3~T|B{yB`nik7* zpOiHFjzm&4-J?zgy0cak-QSn#^md=fgSl@Hs}z<+6w%0jA-H^WEivr_4SK^=v3|Of zF+R)ku%_{+;hTXZS_I+?FheE8Lj97>}igv)ASN+|p*5Ubx`^`y2)Rc9(Pe$k+>fC=Zljju1Sq1!4 zowuKPh7jBTKg#y=)*t`>|Ni^DbXBcX`9(<;cyXOOZh ztmWDZLh_x55hg}X$n~1cc~Uby?QHCfipa`|B0WhkCgo;re&(TOoeEZ}Te9gr4UwKa z)8h;iPe;wKU%gW;!GA~)Tb?IXif9*uUA4p9ukyngT*BtWvkyzHnT{oy_dHZCruqJJ zzECzd&a8hjnmQAo6E}f)&l}V3w;pIraSq51PDbJ~EO;*^e$w_?;Y#NTEIrm6Pg&dSt|JI+TmJ!&B} zVrFk)QL-tu3(nfzBxN!F+I2-;EXi4zRZVU;bBiI{9#yE3u*RYApD>)M!sM$>AF7ln zpD13lK~}0-lMf&;Xudj6uo?QN-$o$$pui9a=DX~#4#F5=qO{0w!CK~lhWzC zQQ14i$RmX8^@CB$e1=~)$XmK)Kai+KKqP&%c zEcS~lDr8B76ocO2kKsMTWc>?dvf)dGdY#2gw(`;DRXA1) z#<{bYw~L4{qRAfbpF?hf@#1w7TbQCCTGPtpbS2iJ~Waz${N)i@Nj$@?pRuVC0 zQ6vX}!amJ|wMf`wj|Flb+}>}Q3!;^UY`-v^>4?@`quKxZ;%oq5Du4){f71Eve-hFV z3U55m$Y2fsQ|G;v%p$>Qyz@SZ5eSr&=48PvsCpi{Bnag|F&GI9&P#=IK@=;ADF6>3 zP$&fBP&5~Vu-{xA<~h-nAon379R3|<5|pu_hFUF^es@gyJYZ5&jSLuSwBgdiz^!7V zIr#pn*Qz&7X;t{Fm%4HbI~%i+`o0vhIIGbJlqp!aWi9s9S!b&=&BO5LzUi&Jq$|s~ z9_Jx%R4N}saDILv1dR$bAFyjl(?!96`7dUH#=yr4o7ME(^0#->iul!SPRSi&MP#>q zVGolgo#9!PerNy*CIY_NVw>qKM%(CY7`E)$nR7P()gwo*eyd!gj}uLZ=x0_$S9a_D zl6FAE`S1UddhFhFC%dy2YWQBZZew_B$d@eEFskR5c}-XbC5s1?EQ1{Q^RYZ+mhh1m zYj`Bbj%?Xyb$!&YTs!!1q0$BQs1ezwix$&&>1GC)ajMwE9+9EJRmrBiJd*px8FcyO zGc*=v;$C7sQza5EY*DLqO_8_NARoj%iUe<}Vg@z7@fRz0YR+{s8Yv<`x%#d*7GRYB~W!pNvvPSe-{-ZhFuoJX+pO-aqAy8WgA!Bx| zIua5^X;?-a=0bsyaKTo!CxwkWI}*{y2`zkUH{PRqUPOu3*U7>13B}n~u)_O}I`{V< z!qsJeu*DdNn1obRwc?@fBpsPy_|`n+yGx#_?&tOHyHgT=E1x1|7?uTyyAZ*qmSkHx z)8o_MLPSQFvVj4_GT$HOTa{c%LB@BN*o{mS*KK;jcOVY)Da2jOMdJ{^3>4>TCo0~- z>MIRT8G*e*szMh8kiSGHPDVLmR|gvzP&{5uhm&sbpF@WJ>`ZKG^`=QH4m6mBGHH?X zGIb$$%2hIm+&>hm13?nju#q&^b#$jW(6w8dz2X>;M?ZDbjtnM)Iz_2az{GGkC?hHl zL}H`A9Byokipc6Vc#_6H*`KN~t6o+(Nd@cUea%M1^7*}}qHweKQn4$0+3zK8xl%L6 zLJbFuNJ4bBC=sb-`r8(hipxS|hWBzpgG8Pem{1B4^ii__kU_pN_j0PC`_=Mdp#PIM+%lNJ_c+UI9fkGc$*p# z;n|7UhFd)>Ss878(2D4ZbMVo+Rg&Q`5!u5f!v!Su@!K4UxhyX~e9p8qhJ{5hi3NsL z$MUI*!e*}(`%sg~2n(rGY`~##5hWb4n6{UFry4xQ>J}y9ZrkmnB!j^saVgNWdCq_? z1&vp|m*b%n-jZDw!+}#QGsWVaHsX9KkLGqODO=T*f>J?pWRf+*+wExXfM69XSZ?8) znoe9itt34`_8Uq@eM-57?X}_jsuw163a=?NAh`*5wz$r zp&%2CRaP}ryOvgPBqBdBx#R~cNowG<469u)lipPGWC&VTY70Dec-wP>8SP)kyss+S z%rcOP(1`HQ$aF&C8s|!h#uPVjFX>jvrPQ#>OsuYFWoRbsu|A3~1%;1JM9!D}c zx>gpmiAIH=vqkWeb4u2_WL6}~qk>EOi;vDQ;1V6scqnA-WT?JBt~fAj<5Enm#H@qu z3JS%is*jaY=@FlkT|76)*?Dqd@%x?~KKms?)-6LF9Wh>Du;gkVP|@DRvq+aAfg_;t za%FJ8;{#^T7Q`iTl7&1q~DhyZ;U!cw6=3m$nh(go0HA!ZVC(J5?w@;T4o1}N8a}$&s zp)1ARZE1lbc&Z_;VyE4mDuu~nQM!7snWWNZP@k;UR92T(c2A^8fCyus9jGe@Ko~>; zfiN;MGCI*Drh-m897wcaN;jg@@}d#($f!Jhe05CNvrh@f>+rC33H^y?!Vw}Q!dXTZ zTZ~k?(|I;HG%+Z?gu(KYB6`ykgvRwlhQ-KF;7UC!VBwawBQ@#E`44FUv}v2wrIM{A zXt2|dm5S(fLq@Epqp38ydDhZXi^UdV4!|XEs%-T(D5q~p%$GuVVly* zYNM4*@Cx-o?sGLH(A7&MHU=kHx9KC@S1wKUQF4C3T~0v^Lpgm~qcb};B!v-)Jf?C& zU#EmA`+_v=C9zNg85%7kP{)4#Lfo%iwn(~H9&3~}ntFD1S$B3>BViIxlEA7*BT`3u ziW-KOlyStRKZ)wKFs+P@97l}G7%GtcQb?qXe4|OzD{CRl%yz4iCnA{$|N7!=U0NRi z7vO@`dGBO$+;D1sHIL3D?g>ff<^Ic1!D+mfKJY{}i1FI!@YRsf@HpW^Wn?ms^SusH z7j&V}exJu1F>_>OW>`L5-I?w+xRS<(hzTA~vE&Jz~Y7z@aQn+Q!AD-nvqNz;X5 zWGhm!X4ySLWS@%{7mkmru^M-^Zh4io_5z_;0TdT-6Ct0eN;sxOn3C&4R3<7Jt7)o) zY|{?7$`)PTg!i%qzqV^;+LYyr#(Y30tvF=iky%B?mVM~1&E6|c?jJ@F!Lgn%W-`HC zsx5g^dH5RoGfl`=%cVwEGZ{nx2cSH})G8tfJB^FX%3GmhcBdTyI~ z+j?&GIN;hj%LA8pM2ZzHXKY29bm*$SN7cJsH^!3tw5BQa#Aa+y?i zWu`VMO?7QE%g>doB?(ALO<_dQCEB|LWX7L6GsP@fEt^zcFB6GHRV7kw){ZK1W6i)~ z$;je5$c(7t9<`dX=rOk$uO)=YD|nRP^z$iBqJ9N}l@iL-!lTu5E8l1?;mpF59m+Ry zD~=eZ0l+;Y(0M4B3$eC|o@g*9grbictgO!uQ!TY%5CXiEqZ|!XL2^}K_EZZ>8FCf| zCNsTu#7;%%*i#7MeNMNUEQI*Rb9!JCqUv~{)kL`YQj?JuG*8D9CL#KJCzNoB(EeqL zqf#l3)xnhISg@2a~ zut94^?gJemo}H8a_WfSYMMnBxHcsSZRQij*lX66Z8N+hEf9R$^)J~(J8+QTxHufR^ z1zI_hVo)RF{J)=w$aro~^VJqDVS$NAAcx|mT5~CvY7)SoG6#y_>}7i@ zk_DKR?_JO(rPf{2VQ-8SX$TO-_?Tu2MQz#qT)-4ePGnZH7|xenW{x6eK1NazKonYX z>C3e}bot}otGl?YK?c=;>ddX|rM>U=uMe}ce(En8NAV1IKV4Xzn*4EWTCvHbwDqe> zy96^z!B`fqwyaxEeU%E7KD{%LvzGU~_eMXEn27=F0^d3Bd}qzkn>9bZF*F=et=219 zwM%@##hakKd5ZYB>$nc}5y5Tx+fyLpO~QKNEU{oji|I$1_j>@VE-LmGceE%QQOA)Y zewQ~4rzw6|)Hw06y1TpChkfmd0uJX*|=-(e>1bPPhN@UFiSqm%& zxqcqx5b+Vga0-Ba8K_BPDaPVKGI_d&PS178FHT&eZaE2IoGb@GU&R@-`DJoSnE(3X zY^QB3fC*lK)Oq+$;c&<%OA!A15wdK(OAV;8HO`;1qThQ(5`rC?1et@8xm(hoYb7Z6o8|vy{*40UbfnM z@hp~MgTBMu`!p8kVzS!Sa>g-sYvG4tlTv8h`?mZy1yltQFw$+gLCYv=kF%D`-FO}; zhAsmvjzAQ&&sR95G~PgAIal`c^oh|^^dMvNsAD6b{u z$O!}SK0MVWsB?h@l^B&fQ#K~aa;TMT;*AyiL5iU_O#(zskw|oPazV-q)Jc}izRZ$C zG((ldiJiH*t^q>YPg_>tLwyyR&f${q4wnI%h+Uz$Pi0zuH6hr7I=chrr|c+dbcCPE zc$+^JuOrIB%)HHcQ?X%DhAtsH9!rKP^%cG1bnpofC66s4DBy?yhE-uM`R~c<5RW!4=Ast(0&B zQ{nu!z4HVd&$KL_l~4{3VbbFBvS)8|%bIts?%cOuZ}-Ep?Q&#*gE|n>#zI#l$|2%z zC>|lA#APw3QR~8{Y?IAbzIg?vw{z9SEY<`hOAIFULNh38fbcC|Fs6={%aoQ$2-*4uyzA2^(mSdpt zR3-oV;!IjzG5`mzgH!qMW^nj$dVf9az8~rhN#-&0#0|lzJjdhUTH{$YBWnucO{kfe z;z4et4akN#L{#D1k<$MzabZ#t#oVhCEt6Vfh3mF%`9!5wj>K3snAGFQ>`t66p-lx7 z1o}8E2LUNlt40uEE!c zfZ9DdtQgx`#?f;RDkxqx1hHC$p8Ty%jkdP`%u-?ID(&6A)s_H`bfB4zv*x9=`CT1I z^R@ZLhNB0Y%O_7#!z1U_+S7vNh+?W)5Vd6KXRxCwT-ar7(iIT7W%}uK!qwZNM`|&Y z#re%Z+Sw8t+eUc!zEND`S?KySXi=A-2k693s1{T6w3%hB`8Q$i5C@z)*%PSHr#N3Z zziJ$IZ!WG1>7VLrWSIik7XvwReMOdhIC<^12kh=r;i%*+TN;oUq=!7vu{>RA!&5h< zqA4)Pt9Uj`FPo;bw;6S0n%RI?K8qc6My+CMjuGP_ z3s`GZVDNoMCcS40Xt?t8HxSMIkdOdQ(Ih$!OJgHpJQysq_UxTO=^Pih@4*% zFEi_6mRX@ZILm@?p2Y3ho;~jiZER2J4-9JV=~CGdjz=@_+IJ2X4tD$ZI>1{%UL|JtTX!*PYh9z}YRz+%X>PC1?ar?VwJC(2H|5#wO@b4B3 zN0ga1x`x8`C8<)WL)0*JX>M~6U8kAu`Bi%NGL_|8TPvK2N#Iu@N1?WI?6{*zNcBw( zvZwYt0rEd4n!}k`!iJW5w}_2oK!jyKRN~^4wj;tV7OIr0{PTq?|+1GKXGZKp{I%8>-|(r~&?qd7~_Za!B?VEsRYTAkTC!V(t}a?_Fi^4MpeS{sT?HsQkyXz!qairq^eE z&S7F|V^T@Cc#t^;QTuwQER~1aEyn6*!(x$sBiQP0ax~w)fU=JlAiP7JVmi6wBi$-o z-fC5D&B1bF(}DjM$AqVWeiPv`Q~*R7BPC)oJ^L(1w~3Vk7_U&gQ#Tw#`jFtW#C`1K z&Do+xR4}rq3(;{s&ZyAhu3T<#Eh`*f9*of)DvNAZd^Wki%B4b%(w;7zJbh|unZB5R zDQMzwIi2N%m_16%w$r;%qSn5yaO(FT=CP7Sm;{r7k!S`LhjJnhumOZ7`KZkd-4O&b zZGzWokiZKfo_*ckBs{B}VG>xbUc&6N5yHDyHVfLn7IZVL-YbB^@`-{V^l>^i zv}_&YZ)=@W&v7*IKIp2O3<0A0yzg2B5|;$#}4i@#-{AQ8G@BW3gUH8Hte7 z7ebVDiY8Os!X?4*=&V8&V;G(#AVMDg}Glf~$|9H;wQnMD0S zr&J1-^feM@#Vjb)jhfQC(L312U_}ZYLbE{5l^raoyqj(zyu2aELEMW&lGB?lC=y1% zAI4Ggfn_Em7(mc%$)+H_X+a`lCXMszD*Q=`BE=d5n-cRY3)WGDL@^{pgd$tcEV8{h zBgRH5NyKx|u9WUrkmpV!BeyOy9R6%zhLu@A7-A?J4kYsB85Obl&a%M5+NLVW6D=8z zny)%~>Wtc}gj3HqYeg#Qd^IHNGYlwgf|kHvR}a(5O2E7O9=od0Xd#8Gp$o_dYeD&j|>Zq8lX^;@}2wR83NGCfQrOjL6>ZpAV; z{l^YhM1=sHT2mXowTAxfjmiNC24M7=NNM!u|7VZjUlVahoaOazroQWH2jX)wy{8}M z(9$8UET?kImm(}WhEjEEl@F>uU8Wd+3hUkLpSHp!iZSIoTiw61xxd}Mb9!y}Qx$)z z+N9~?!p19fC__`KGtf(ypV1_i3ql zd5@$(kY3;doMd=)7;5ZI#-fcXtkxI0_jXa$8j(3+*Yb`^5U5lMh~3`k7`26vfu|7E zIEC<5SU@B(Cz1zkpcTa^Pq)=+tO9&K?plCF)BV1Bl|*@Iptw|^6aqvSApq-bz+-5S z47lKxjV)|LCBR2@|N7!=W&u0^3l4-(`x$?*jgOkIFs7bpq7Ogk<^IE(LFqiqGuUfE zLd(A^V7U>PaipS~w3P^VFhLOnmVpJWRC7Thxmsv$jgE^$X)JuX5E>9eZP`*Vw?%=Z zTQGFmQ#n`6Xn0h^f^9K~>n&2W>wKSQCR~x}p0pA2OqQwC?XYhgIs``3>@}A zfLTs7$%00O=L0Ka`3r0`v8XZjc1tP zGNob|=Otyx$#INz8;j0m-5fs+QgCUXisQi$VU!MPlIIwMpoOtR#N9rwttyOu*<~Tg zKAk5U6wH#bv8kXnu7{u)0nz~dHr939cYCL%ZfGNyOUr_=Pk&pFrw0d(8>IhxmD^xw(Jbm5H^A6pg zZd`tG>1)3O6kmT~HQo+iKIGojkslp0n zh&2MBB)>ApdD@ILoEy73l_C}Rgt{u= zCQG3YB~r#&McRYqQAmPcvekutU{#9pLy*gRH(`gh=2VxK3lH&xtsg|Out0GyOX2>7{knCTiMg=pqG7}xz%`l(ieyeKi zPFovN%7*3S$!K|&emGou{<-abwbnSSeR!55T=kdLo}W4{yUZXUU6ih^A?H4jz0g*@%byt9mrvQW}mo3puW{jGkiPj2m- zmf<&Jy19A$B2uu!I5;v1+HCi0S37YOxa>@rqK_V0nzP?Owp_`{`DFPDg|Nw5CS3M= z?zDNu+N4RLQC$vSnabNW!Ka?dl@P{c9@*InyH`e zWdZ~PaR_!yOAJGdCyPh2{a+|PgcBct_gA9@h{%qJC_~*4;Y>XlkK#=WOAuLHamOq; zfROHn42c2I#HgXMEIcS26aV_+OgOqG00%yTQhASOvhVO(KRxWe9X1P1<}o?Tx4~(= z_9po$U@O{&<)$s-f#93OSu`AN&RedRG0Bt*D!%N}I>7Qoqanuc@4xIjRN5{`?7FT-bL~?Gr#CD&%J@z+t z?$iTjuIg^)Kehx243fq_k0z7M#5<~=Rv+iBcCw&XC0oR7_hWJrCAl!2a96HUY_CyI z*5J4yNQJhwT$annOAK3%#UinAk2)krq37aKi>MWO6MJ3E(+m3p%DtOpp8n3b;`!mN%d z$FI|abXS&@tj^_dh=x9SbpwL2v`SY!J!O_SFmjB3K}&tAYiN6;fo=$;XpqN42`h=? zj29}sR#tpT08+=XV$FNno-nL7zdt%&=c!vw>s!9v<{nN<<-JTp{~7=gJON?g5Cj&H zgt2&VkVLt_)+L#i-E9%cfrSK)TuWAa_B$Pi^)2#nuz&qTJ17@YY?hN)?r0yyAHjY{_l=+_94rX3$xdig!)Un(4{ zFiJd`z+zhj_TACCv3 zT12M8K}48#Y`ufU=@lM`=trv7C1{Rdm2rb(!U5RUZ$zc%Ay`*z*!iRSS$maG`>Rjg z*wsRIZPN2^70-u=UobshuwIcWrVrB|T4jW$<*x&V$bqCMTf*r$qc7i8n;OiLZzy0? z2)4k9I`5vKDhgv+=3ifgiYzaDu62GDu;PnR%p9>-I*ns-2Z&tnRcQy{LgYKlv(HdyNtH1x>Vh0 zq_?u|uI`)jrIzlVJ5rXDI~6O<;}erv_;y`A9-Dcq;~w~2%}6JiO#Hi8!L#KvG9SqR z002O3Wh~Ol5h|yD&B|WgyR$!PnbXt~eKZV@X_7u+S?K;+njX<>IXooI7{&6>UwDLygoc#eGhp(!Gn86PLku(+dyEf$CKQjMXyo^_J3%-#HOcF7Fdg?(Oxm5>jXs zlT~?8N*~fBtPQ1yRjZW^(IKy_D95{TMz7`Hd(EV*kbgDhA?HddEj z7;BI6!YvhAr`mabRb3epNH7bn_l{(PD%4O~QB*;=(v-AgaaC zcbajK5Mg}FF&MoRtq6bPP~52oRb#iP9z^aq@BF$$5mAI>Y^y;pWDvQ(#_7VJqT_#akWkY@Db8B-lilvShmEI*nu`6WKoAJqK+-s$R9FSA{hwjR6@4>`iUFBY zO@^ISqhuQiF58YM&GKO*rcHY#G`YJ|NrS*bLZ!WGT@}^ zfB*hEP}KK3=?X}M1;Lq_R7r;!M_dIsgZ5gVp~%-~i>&de7!C037-c zPv#}>!;Qh}JjA{DAuE2?toDVy$-PC3OhwZR+1lCc&j)ZAnc+_f^91Ztxy91+wJL{2 z_2bid4pVCS-62J`TbSZXp~dSPc~-`Nqi~W8EYA8@-x0Tem{DLcTd?a;;=+W)(B|-# zu8W$vMR&WF1+7>ZY>ne;H18Iew&0spGPAKO-|8kM*`?wC`X+%S?+2iClId0h6Ow6( ziRy^ROH4~F;bIl7j!~p7MpX(*s#UFtDu=3&XG1fJKDssLq4fu&6rvF%TIl3jVYu_} z4=FZ7CMrHMFFB@I>$tkGff&jV^F3^0H_I%K4aQ5-@tTi5I#%lEe#=)`cH5&`$|Vg6 zDhlU5C#ox>OP`Uvjz*iDIqI!xHI%<#GXNVwGQ3xwROMf$HLIhu*C{S(5k%^(l$YKn zXR4T&hu%m?0*((S1A)1y)P7x1J;XX`S1$MniRIf1#WDf}3z^_40RbRX-G*W!e%c-0 zL{O0GD?nI}aAc7}CT3Vb$bkBTL4!-K)zyYHI_{N>*i0GF^&DDfR(j7>H5@0>^XTp| zed4&jW{DQh?YMAU`l1|b-&x7>Sj@6dG>pvfRV0ZJNYwWpnL$baumM-ZNS;OB~(@@gZJSuP7T( z+3NC18>sR~n__;?l!^M-p^C|d^s83gnzgQ3+uK?|h7AOm3XkZhwnKF7VL<&29d?>+ zk`gzjnaU^)ieQ8YKs>zQM%x9UlUb%p6euHVf-y~Y1LO&U$YPWiIU$3LqK7xRdoq5o zsP_DjC{yPeCC_tW?DwXkS}Y8+yonjQ+1!-R=r37Jea6De}HoS&|s^BY8?^7-Qg#!}H^ko-l{*H^x9 zK3v&)^k}g11GMx=u@U44Y@gMY8rClXk>`%oWvo0U5g|N_B_)49)E&TVd8zdZ)P(`% z;>){u*@LgIEILeG6=aP!76iCcPQ*v69NF*(5!m(av{OpFu6oha!|J$iiwt?S=LQZZ zemL)YR$8<7zV}<_iKTUQyL}W?xB7A%EBVIH&mvC$`r=GGe_{XzMjJA-k-sr;5dIN7KkjI|sMch!kml=W^u(zO!y;+y=!=-PYA+?%QT+aPIk zXexq3?Hx%e_>?CgptyLjka~~M;8@0;EH4q&+QnGPh+dzZqQhD+aOW*b>Vq}!UXWqg z{Sp`~guZxOLXEGQrzf_hzF6A}KR>rU7z|GN? zZF?mr3lJ`)GpUPW=9dmmUVi)Y`8ZbH+w+&5h>`)TpJmscpS-WxEt#3Cy{T4bKBq3V z`01B6@a?ROkN^l)$`sT_4{mmJUMCzMH&!lHJyQ#IE+RTUT2)7@+!B&3tLH{dtsh>A zYSe2T+^!kE}Wv$HKErrDK1!1Pcw^JPYRgalhbMG z4dnY0w@+ACfx?_?)n4kqaj#rkH}I|1N&P3D)v^LckD2VM2ef*{Ad1q9QUFY}mr6IC zbVO)cCsb5Oerh!uo#*&O%Dc?XJTmth1QCi5j3Nk{45l)KG)_q+(5Tv>!^KgoAW{U( zf}(up3m8iq<&D4*c?shdlleH=bq$>n3|=O>!6>rlmztCF?XB*~WXW}BpIr0<%TEqx zFa)zty6aT;8*6=1=G11@CbYU?IeA7db)EN|y52f`{jj7mxxw<+ODD}*I(A_t*nH&W z+a@Vb$<5B4iGeA?b3Ag@K@uWM)!nk>J6T?KcIQ>nvYOtMQ?up-Xm(zR;Tp_Qr;YI$ zJfVu(viX}ig#lQ=#KNZ#)P~=j}6ANQwAx>~8qc|V& zQ7mnR=|YB>2kQ~eU7VIxP3`L?O9Dm##BAdge!ERSZBj1^K_(M(ZBHHB3vz{AxN=c7 zs;qx8J)<41-OBcjM9Kk_Ydm0bqh8fb3YJDzW7Od(pQo5v zohhT1=;6udmDEk@Ljp-3#Syf*2{dQ1Yx(4pt zxOl}#2I_6THtHvAuq&ud^5U@#7G|dR>KG{|C=i>kc$C$i3W>U%`)OLqAOIsJ&qQ;^ zDQjyR;ihzuvg3x;KJSXNsAoq*u5}AC(^kYze{UbQx0i2}|N7!=kz}8M7+`_YdF*&n zzK{xEJkP#mt_?@$z3sy-!6>|QKS}u}8@X$5P3s#Y`fYc{rSGRe7=SPcy{3LrSw`g= zmCkpa?gUa#+IfwK5~C7CixvSrkm%-a)X2Uh_h6dZdF295_i<$Q0b~H@izUU}Ja9VZdCW3ikEU#(L>h&(!(KQLldT#;$T%tnh-wmp?42Hj9Gb8hh)K{EvG8M| z3X?4jeyuvqC19C?Xr7zL@VOcyzMnT4Qqq^BaC(js=47STNpghfvFd70S_fLO7P>=8 z@d_RxBP0hYJ}0C2tU?X;#?(TU9-v}6o`x_*Ck?W(`Ph6Os8I<&qnDFF?>GIMi_@g2Ba~WnT7jYtEDxfE2E5J+?98>$Etc^aP-SekaLYVSlOB2KvWuW*5zJL zZ4F&gEIqutgPSsOSmzfKJ09eGDtai@Z?MG<=f0vxdxs|NDoNpdU|W43dtr>G$_&W{ zTmTe#Pca*~JttOm62y{1S-NhhTreXVgZKZotdAKa`3>4BHRNPMcWKZRH}wAU$G+~C zj5=Hnvl_oS%pa{n#u(dU?n-V94aRqg-$@N+wi)`Xb64R^%=1*bjggUGruiO0_=30Z zoIz~en_{BZe=nCB#8)b$S=}gF;lO~NRxwG4Ev}zu70+N~+XEa^+*|;%e{JiN>omtt z*2;6}^SMaO=S(j>sJ6YIH<2|KbPg&~dd1r}uZ(BtK zOqK!J?=HJTfgg6-oz`NHGOU0cW}4_Vw|R-OnG&+K#*pu~t?Us3-z=;0^}npOg}|+T zMyE2UZKWxyJh-Q$oeZPk>Rcw76a@HNP?3U@CTe03T+JnU12*i5PoF3xym?Uxa}k+J zO%LVUa{4&;DhdGD10ou7u9y&$sJ^Y5MEb4GN(A#`;DbCbDA#l)tj6nel+(t$xOG2M zCV6Qc$-3ZGIRS)qLB`amWmN|f+Ie!UZy9Eo3}(7)(Q#59=Wwm+lX*UdrVF&`}kus@EfzBYUBo3XnumKxS|~i|vL~UqESm_og{7FOakoc5e;s^#5sIt?8fhh=~jp4IEWLHY4|m$c<2!8cyk%~l$5o(2aKwMinQeB1Ypc{R)+X8uzqj<+|fJWDcJIkmOmlyLeLeWED#~?G zof&LHE;A>HmNePj7Nx8rCI>Iw>&orBn`L&y&;=w(j*~?;fXUP(8tQRGhpIm~+MBpSbT#fU5~qQ7VI<^}Z6A6U*HQ`%flAH0dFAS_x02kJFk zGfaJuwv;epD7+8%K6+CixK0uDIi(3 zmUxS{2Zvl}l1Gm7YT8KSD^jK8XizP7Bn0!_T)@1cJ2eAQ93rb(V5(@{J$nQ$;b*W| zQZ6ZiOdtfRGL@z4=&+wy-(F&*cM7ZFhs?Z2RLj2BMu`lelHN0%%fR|1>Qr%xRW6k> zld|;4bvdHrC!V}nUQ;27<$2D`sy~^Sg+!uPgn*!2)se15A_M{;O5no;EQaPrs=}a_ zm?%?TfQZ`Whn4`tM5?SIFuuu3f}u({snsRLAsJCH(*T;!Jc} zzJLe;g3|hl}x3h3>J8BVQvz#jqI$rhnCw%@F|a~ z`EwQrD(BQJvC3~NT%~0ff<56R9A`TxeFfmTC+QjtRn{>m){v;5uq)R>+Tx0C7l0J*ecJRALao z{4|O-%QYX*$GeeN#J_#Ah*2 zY98BKqxUGS&UZNNmIX`3&8gMurCWw|b~?eU40o|xq-Crn_ZTh}f|Z@N?aVY-SDPxr z#YJNj(cZ}CWHAhg+^a9nG8W_@deEc9z8MHp6ZK=r&YRks*^QCR%1nK}|t)>G{(nV@tnXMsmAj z#V#JqMf z911fjc>FK&qg!J+AH`tuH%rS3rIjpB45D6GjWXb0(rPtQag_gIDCT2bvPyccjmS$2u%J))o;*LH_x0k3H4Hkp%a&^{oLpSt_EQkHi(rh7CeY zBio3-6a~t6RNd-Q*k^BKAvUC`uE|}x@)mOq#$XmgT^JDo?Ro{BUCiZ)tJM{K)78{q ztl>k;?627xm84`LTT-%Vz=*u7&HQeRktKwK5r%Uf^DoCqtH6qdN0kb;y{ttPojd4y z5Q@rH(&`^}8ssq`NJ25oXzePwh!|Ahvd9j9*pm_qgrLsqLbBFsu_CdSBHSU?UdTbs zs}p=(b%ia+HG}>D8Bj75!0!^uOBYq$!X03)^i7u{U;spKQu#B8^Y+s@jf%i)S~QG) znTbFYbNBIK>;Z;E@Rdj#yX$HZFqz!ixSWRmxLOBshDj|&T)iv3DVpErmQ$gqgGUW| zcRdFu|N7!=Tm-&=3eP|SBvEu$?Rd7# zP*9XkCWy6JtUfJq*Ji&zIsFI27V}V|GpDH31SLq8<2fZmM8r)@T*CkKNHhW?XgUT$ zfK0j*i;c-xuZLP5Z;j$umqV9?feutIj)F?BPBJbIgJ^4$(X200$a-B|(v&lap}@*H z3Q2&I9%fnmjXxRGvCrd>%YvjNO?NMdaXc>%ki+pPeyiNqXKAM9{U(L9pU7jwjxu3b zp({_tQxj^jr7IyQZ!*}(TDXO`x3)1nP$3SF!uY_Xg6B$0x#o1?eIe_2Uoy}{pn@b1 zqrrAvgP_nB##LDdEM|K;&thc1?V~k$P!YXoz@!^lcCY)H+1y z;yRIH7%)$z;EF-as{l$BP(xT1D1xOLJtpX$lt*Z;nF7=z#E79U=IAX}vNfTzaSAQS zU_MBfG_hi88!9pOYO9MeUvMeQ$+XIaHYiG1NAsDaWk6?QGX;uvxQR7%urldl5@RjN z`jtIpwNLVRj3+93_5VayZ4B%jo65F}BR%_E`fu4tuKcM(I0tYq863E9R#R zwnt{n!&|0{$Y0rX+-0vXnG9Y0cWD?D3n`1oo}9ZbpNhtv*a}4{k3VqZw%R|;rKLyZ z@5}D)!BK6*otgI)Qz}safk8~9&TmXhT!TwMQt@_KGrI>qw2m}06opQ#$eZmdf18O= zM1gSv7TQ1#+PApXF7a*lkq`k8hYSc;5^v$Vsg~%8=!!g&2TLn@w-ZY%TlzSvWv*42 z&ZKbemusoB9{>8{Y^_|ufC_tq(fRMg@~@C;e=Q8oD+&!k^^E`uxWQ@qn*af#5YaS; zz|`^MOEtxulV*&0BpTGAHiO4($-`*0zcOvWytAl|GBDoUlF9S@w9k0-#uAm6R~L$;jcs<=9GfU`BTc zIHIewrpn{C1!U71OUVK=q*Wq!pz8)!WGQWxKxhgTKFRdcU$#`WVNdd`YU*~7NysA> z>9R^?2Tw>mzlj$WWeBe3vjsO{ZaHNaT9+bY#_h0#oQ*qeV;J0G+y?){k%i7(OAhQ2 z8Fv|602TxeZV+q`D0t|vkQP<{2!~jDeXMoH=|&(&c|PRPH~Nw-OL{2@jq-j`i(JN$ z^ngZ!HONfM=EUQZ_0j;CJh$#(@G>z#6}f6|o?CZ1_N>Mw_g{F$4X9$ibuhxO&e!dY zS+!D$az9afc|&3WCM>CJ!Jt&#lem_nHl z2eO`vA?79JM4*g`Kv=p8{Z;?{T6)vd>!$9SY=Q;E8&a7{(5^yFj{8>^eiVxIC5cOU^bHqNdn2axqQIkHb)Z0 z!eHTvij0nvCyo@03HkN1l3FH8Ou_n%kvfVf_C=j&_Ij(W1iwk-G;o+CiIQccC=)3y zCpB}9vuo-xCrk^*NNT#RtIW;Zs=Aol+oY(VN==+(qREm>!7O2EEG(tffJcW}{=@=_ z(An0EbrMR}yza2Zi1;T0>1L^W9hSfE3kGuA#v-3GmI(_+*)GW0?#ca-vct`a^V*_*?k>}V_$IJcp;s;F6|t44vkMCIaenmUSLs4 zik9Z4qH($VQYdOmEsD$MtzMvjq|s+OQwBfOl_xE z(L>LSUBZj7m+q}eWA_u2!<8ta^|fv{ZZSzIq@}g;w|bT{GkW!F8k8+pCXtry*jDyR z=FGZs2!4n2&wT#jzCY`lDKF06S1bSj|NsBtyR{~%tWH#xK{Ph&>-ls4|NsB-&h_hc z=5n!T%C5}lXogCF0005fEN1g6f0>60LvO=atxJD*q7CU_Vd0@{68XhWwN-X6jDUUtGv%NI{`gb zorX~iJM2xFyb7JsXEAn16@j6)5!WIbXUwtSmP7ViGfQc2+w`qU1dQq?=)3BD)`rY;QY*$LhoxkT7}HS_`$nf&?vqPVS+eP-IzJ`r6;4$MFR&;#XdDuA z07)7NWw6Ewy4*J{O&9}FZT^}@zF>B_2y$9vgHZ?tb2_Y**^oUGPNbnZ78SiL`V6^m z8n&YYafcYo1+x>FjmzyzD&24`F;U`-RuF+r<84j$dKI7l|NsB&!w}>8ycBV{USF-WsRkEq{Fa(6e2#dCO}HF0~2ryBU%+ zDPqBUA2f{m&zz|WHs5IIgv?>c%*~Z(vqpPpPrHR{Tg$!Pw3ipQUpeLlFLAn7}g1~W~|k@xth80sH%L5dfmLjeA=yby*+zJ zk-pXQ-Elj6thTq}3o5niD}~ypjKf{wx-`vJvex{uV(&fk>t5MrPdQ?-b4X3Csu&Hj zK7gKp&f^Q^mo>B}uVitV&tO1V9|6C_C1iL_NBM@4glKUzcpHnfFn2dCS2-f+baIt4~p63h{#M@!4= z$9RZB)5~UrvL(U`n&t6sBX4aBN-;D2=+~}C;Dj*B{!?v*pozs>-Hh3@M3|znk9teE zUsQOBP*>iY(eE~!Y;Vw9e$B5}CCt?!+`r=Gae1ZT5=YrAsiG9M{&$ zDZIue`3y;oaWd5lNri&o;rCw|#g4%;)6A7mof}lii`wb!>NQpglapJ)s)HMH4_n67ln&Um)Kmp#ne4R|6@cUC8hQdvF5}O$k~1@ zJoD#)fy#1n;#%ijG=0>=UmYchaa7hd536AO{Pm44z^xPbju&YIYY!u_(QUXL=AnT( zo?U6fcu~TZGsrGcUQ0vq81;)WU$$aaOYRI<$9y#Kf)5(dBB)P8mx9+3M|* z`=kG)vNoy7}X-NE!G_Z-y zQhHd8wIr%tbMixep&xM&!$qCe%8ls`+PNrAId`+r+BI;PTx~KUR$MGADmtMIW2v)B zk}iT|W@c1N1OPvYV+s6vou<1XG%v@>p<07!D$fw;OQOuRGHtw`oC=esG5qG%QKZf_ zrFyX`vWbxdLQ;1AF#_~3e6*GXDuaL7@_a$Jryp8J>YkCT!*Juwr4?JFHlUk}Ie!o5 z4$G<9)HLk4F9k+Ixn9?LQ51UDO66Xx?M-7&+d*yXLrP%#%`ZnS!hWSL0+cLh4hDBx zqw_M~R+hnVrnzcb>#`vs=wxEZ9FnlJ5D4L6P&NqDYY+x8;6MPvrl0rOoIb1GO)Y+y z1hHUZOO`UH3F??HZ0go!5xdYb<#Xbs>MLWD@$%ZRbHyEtg~9I>pbwvSFYs~Pm$5(9}Vk+ zL(I}B2Qp!31yfW`OWKnyt6H9ar0xSfLut2`9H`2e8?QSJ4(*FA9+r>*2_KntTC1Ho z1pK!s%Ka3B&?Gnx6+uBk08!{~Fy7tF|N7u;UOK@53de)ZaqQKQx)5qV84Ro^A`3t4 zKNHHtz$pCjvf=+l9wCpFbsunaynu+QT0T1#G||eVXF_yAXM{{WMI^&`g@|+QVMfJi z+S~qXId_`?zgtht@RDV; z^6@b+`$&lh0w5*`VN)+A-FCfBv-tqMj3x%Nn>m?Yu~vU8Sub>5=pQo@kxLeV94&}k zJ050%bSHT`iD+G)>!&l&^D$ZCi-Fa4LE3W;)G)&xgj(a{Uipe4|PbV){;vGqG)Q8wVPNsaQ-OJzXl9TnwfaTn9?tF=(~g zN*ed7-H|)A58TAP^ktxjm?Xm%7!9YfXh&GOdoILzEzZ=e)9xxl9!ZC8xO}xD%h|=j8>x7inV4^*M1oF0eU{_2az7>GII9tXs(u#ZfVmCA zNDgs`wjcpeCSXa67!R?&h8*Yva3kj=MuQFbx+utLwsaAq`YX|%$8%4eY$7%>&H=by zNx}LohKay&iu!?G%F@DhE=#hY(LRNL3zO7w&^ZL~Z5PFpxcw>+17z^XxH7H_RI_^7 zLkWDbBT5jjCE%nu2ch98GZhSq(?@WjL0w+dc)6AV+_dD2kyyaQe}XVNN=5Ubpz{ZB(lmDv?NY-5txg$8iUJj75vt3VHGkCTYXz%bK9&q%AMxdC5x$9WE&`4G(|N7!=K1;cP3EYFwdGF0|st{^VJZpX| z77sOt=Y0aezv(@Jrf9D~iRcdbfS!Q znktm?6e7aPs3j&6nOa*>t!1?uLQA><#w#&8EzApOx9RhxN`#*1(N;JS4X6< zo~J4t_>3p$7Tc8(O(cnDDk_pIMNL@B{ZzV?ESt#^nJk@M(AZV zU6qAYs`UXYwYa7emc(6=&{9PmQN@(7CeIB;`m5Q4%%aYUOW0sB_PXjMizj{E7_0JU zgnI}El{*WFo+{j2vE=5BwFFL^gTqOL^|$Dw4xu2ru2PS%wph&F2JXjKn~?>}-`NW< zgQVsCFBEC|bQ|`5)ZcgV1$Wr{NL^^kg!hHCpIY}*8X1_HX=v`A3hGq4W6>5Q|1QG> z24pi;9h_xOQ~d=#vWFSxX{#ixYJRbOi=1JGA%KP%MkNwppar#%Jdku<<%VDk|7Qh8T7LB;aC@G~?t7DASeOv$DT+26kYO}?rTwYMY z*!EMhFmOgNClD(Zq}v@YfBD#G-V|YiFo=qFnk8ORW3Xy)VKgRIdW2yR&{*n(XMmwd zEGut6kEp{c8T`EWHE5r5ibBdlLt+q&VgJK*YD!SwkoWi1*4|348~>>L>Ex5zbT{#>&Wpv=Ui?q6i!!nSlajjLSv?$5_^_%kQI07f+wK)=Y=_;9r&-u6L*$jnd+$T-J7N!I;cXLWsFQx2?3p zYHWKZF`e1WI#1q)nh*&ea>YB$K*w#{c%V>%kzb(i(b2dOUo zMMkIln>#;TX*^5BQ>`Wkn+J)XEc0i7z@G=~^n9s3Vi^dP0+JP&XHY5a5=1IB%5mrtiecV~58yEY1)RkYV{~2!aDK6w%teTL zMDS9}=x{5^Y8Ysg%5%m!ZW*rX@m}$m-$W*khSR}bE$xiw`Sh2JdLO3Rq72Hi*sFX& z&c!mFMTcqi^RZUx3vzI0H&@-L4!5VOZbTD{;{J|4m1@B!Zi;&$E|0~P<%Xi)WlCO8 zG_ajdjJd?qlmWoz^vEt}!o9fkUQ{7U*ix%4B&^0GR0LV*(IIy(51iT$<~0ka>xFAd znbz3dHm;#3R@hYryArJ!o`Q`n(xE1!6FGQM9SPXfKMo?4>O`XM&YWW#i56)kaGvn@ z72Y2|qv=%2!#xUUwbOto2MMls6{%;ab1Jd5$|bb^?yT)_?(g-ikVF8`8G<{il6i!L zx6!sffCie<6CJFq12$M!nJ!Ri;U0l&kV6cpb301pEnW;6Ggw2n0=|vK+G}uh#2)0r zqfAKC*E?H>tdc+RGx~pOIuTdLB>5!LO*(Ct|{6pzmbBgr&{_9RL7sEK6jB35&ZmM4#OV!2Y#)_*@rWn8jyMQ&}8 znhT6;yIEZ|#D@Lh{1?IDOc|S@AxpRxX0tPZq!Masd1idosxO7oM(1OZXSMojEqN6a z0l_RJ9AxlzSToxYh_?p%Gxf8>3@z?VK}|(7E;%?ZG^&?)nu(}ytZ4)h#!=)WN!D|9 zO08OBLRp&DRjf;-^i^@IDy7pBr*+bGm4n%I#ObEnZmCaoxR$uu*cSs;eQ#2b>B7lj zhD_o|Hc?u#r7_u})0Ip?$5GPn`RTKSX^h_(ePvGBEkPSd*;xc9r6Z;iGi;5iho`SI z`RS44;WTYr+7vYnp<(mL5nV_xnG#8r4wscrmAcCeNAah%n6md(g?n1=63aB%i3-%S z#;DnYEEkX?+3EN~*HI9tvnpZgOVTzsyMODw+P8tVby#k$Yd?Wh=L_pnH$HK%8o7~#op|h~6P^aqHEz(I?%&Ny0*B7#=V$1*f;!Jscga8Ksf6{sE zeR9yx`foii&RgyQN9VCTLv6lkJoLYDBk1Us9LZ=oe#2HDQS;5xR+f432;wAS$(+d{ zH1!X{Z;cZfLzdzzlj-P>o;VB-Fg|T*NQDelN*!ZYi&F5;$NpdC!Ks7XC#f_llB*9G5KO8BF$JE0(NibUY8F;D8I7$bw`mNeNS@6~$5}^hHOeKcGIey+ z(%7o4v8u@$wXU)LzxvMQi3ytPv|^~|08;UuU2ALzOSmc4QdycNVj4E`GDu-uo4H0p zQL`CG(in(#`Bv@<%Tn!DlSn$hB(A=Fd-%hggqCg|4)qvm2$y%BMu;Q>|X$OBt}ivO!DMS7LuQ%n$j=Cb4jg8xpf7CIndhW5n+80 z%w!?#3x@4CFt#6OKDyOJ^EISGb~LC|c%Wn%6oZ;W)B;k1hRAd+7M6%$Y!W6y`ebZr zk>kpVg(pO)h>6!$87{Q#G)5r0CEAL25j+853U)XoNs>hpRnkKRQ-QHrAsIqOV&Os9 zFA^b1gffgaPRGeQyGC1n{r;9+BMnPA!p$*2>oLo)klVsB93vA%|T zt1&@V{tO;B6ihd|lUS&CXMJsH08p{iU(`vXP;iG}?@OIWVsz0m&DqPFAoDqiAhMFQ zQ7%Q9;^KOiISta-UyG2GRUw4~n7D1Ug|5kKUnUFcwzR`?c>f^DRFQEwh}f^xfHW|% z6MT(yX_Pf4Bo;&?7?kXekfw8d?0AJ7qC}Y?#;Jfp6tPj}q73kMut86QnM`jN=S(MQ zZ^E5C!o!Cnmn;z#hf^kBrWZ`oHIwGH;9)0LlCPK5j(2NU(mkF*EC963JU_bn&MP~U zD|;+ABukRP$bD`CY7;ub8fcJqR#bxb*Qa7RFyJu`i8Kz0#&*7u!)5WTO38ovReP%NxIqy%ML0%(!-+8=(>? zO(RU*0jTpb)C4HEp~u?u6U97uS%%{*Ej%2BIZ$2~F_r07Bhl~I@g~moOj{7^JuRni zl&%xKe-;aiiI~E~KVYg6?k(&?)`N#hotfKJX|*p@_cT%&&7ZV z5Q0y6@5XZZuqppNnD%Q94>PCZUjmpu=={S!sYZsG_Ae%7vdm4oa||O*7+i>`iiQGD z9g+kR=_thE4(7?oRe?*dska;(l?ss*3kQ;&JB*#&Nh@Bz5a!?b5|YgAtJUQZ&exfj z-k6rnWi=_1Zl&6KEBBhzS{zGf>L0leITJ7Zy2ol%jn$Uj&l-Fs8BrAY00E~d`jR&ZF>Oqur#cS;-a)_~525P^LfRCO zI8g?HIYQf;5zDg(!Au#)f*dS`g*zP&HPmW$#cOIQBy6bBaSe5c=bWeq6zpkL$0A}Q zGJ*4A!Vq2=R3_n&ZnG|(cnY0*J5J*`d7YIk9tx|21d58oNcN}%9QC;jNh@7OX)ckb zON|Y_?ET1Gi&cxT$OSvgj@?v}0bYk8gRx0dMS;}aajZNcWyB3cgfq07iK&hmobBEVJ!xcp$qrl)4nM{0S!;E3i8XRNC#h;Ao#hvJj_1L4R zA_*PPdT$2|QXxy+8Z#b4d84MomNeddB|osNTyK zWMgmntWa#4nTLy;mw#kLfCKzl!h#cInIdw<<=9<^h`4~10x*AvVR30RjUtvtH>BC| z(n6b4&c`7(G)h-x3F6w;hBFvOGvzf4X>m_8zD^U9B}|1a2uvk;!ks9|qeIn&TTwGn zF(MdOMf`efh9wk7Q-Yb|`O2C%jG^FClDeS>6FIy~t!1@y^-6*2Ze{}9dn(obuq}Q%C@lGDUao8xFAwFEx8bJO_<3<%2bgGC2=uH6R`{yh4JYor!iixS1{Hw zeHbK_4wUY0ml)(l!CtjsHd9G3u^QBdFAqM<>V?^MTS0+F8x##6ib|Q}UG;w>Gf}G+ zWRlp^TZ_LurnfgSC!x14nSG0@0s}RzB9)L4#Cai(Tf&;mYLn@5p30k5rPtvz(34MaldGE#YqmOz&B@E7K5(_!(V_C|{y{LTiE--zq&ttA4t|DM+6bpdB3=^%M zIWDgoOLccvg!G$QUr!anrk3J_98EBE>3mJcmMA`jjW|+hc@Ai>sEjIK5|-iMZP5CN zh=@9-m{4)$$2-P!$8-hZnNim=ZNKy8GeWX8#i(lg=kD_B*3cZag`VpA{mi`8#5*_E z#E1$ijLB%tUFGZ~M~RdtoRJ74tX>~LBFts4!j8z>6P;1iWef44I|||STP^z6jnzn` zH)^f+QF%(xPeweG(FHveT;RV3=wcSxns|P)uGBQ5vGds6{+!4PBTzwDl;214C|5 zbb6k0Zl*S`9|T z`=E|U?94Zi3p!kNe{(wQ<`P<0vKbW)7Z!DdtaaT?{g=3yYO4Z(qKc8mywm#`xpMUt zZqQYmvzBb5MlLEEY9LINinGX0*Gn3jh@iVU&|leg z#c=nsSvz4^qvj;Tr;H84iuE+g82G zDZbdK{DIiHXVSMY8H_?>QWQgu!s8Sy)g#sk+O$B)a%HDyRZ9{e01ffxccRBSD7^>( z`3(X160v|9CK!eeQF1rZgW#k@lQ)|~3Pu$mzAnM+;9Qxdj7XVE0pwkToEwKiEc)%l zIO9Xk1NBU>UO_r&!8{TqwKFjJQ>b97*h-fI;z~+Z!^F8EB$aDG%=wAEQkH71=@RpX zZX+=DXaYE4%bkHl-E}_8oQn3=dtz%!TDogNFNEYY-06}rYvBrd8hi0Z=yg34#mV?zNl=3^8%? zY6}_e1{`K2oo>U?Gso7zmqHTq71u%$Cy#r64opPXBT~c4Q zewqq`ZCASn&D_RG|G$}?i~IPHAWc#~4j{D;jKCNfR{!z4Npx^8gqnw2T#Qc=O3NsT z<^THPY-UTqfC{{V%lYri@~^L2A2EoIB_%!B)f}= zgRqQvbP9@Y#DVs(F;+xJbnHvqOv}gm!ifUL;z7X}2Sa&0Qi&_$l-^}HO+sc~QAUtS z$G|#gB?%`*{6|TOIOZWCmf~TKgrn3fy&DHia~Uw)a2JId+Ob+G=ISOH=!PL`wxQ@- zLK24IxUwwd9S(NoF}`oB5QX!cVn=FZZhW@=a;9fehNR>jM-qV8XGT9wt4jiPPR7DP z+>h9av_e)gjU-Lj6{>ShrC~=5xwpu2ZNW~gVl&0e9$^7J3+Ub;&)y*zY*F+~(9orL zK}U|;pH+>54`FAzf3(sP8j3$)qa`_2Dw8QZjRMPyoclVPjRlk~VF_qWur;+V+36P( z*{vUlX*t@)qH>B}*tZ~y!7ahtzabheHZ;;i`Gy~fzP}dmj8Dv2)ts*CdUKblxTMS|qP5!he|#wbLk8neV)<|3KU9$?TJm2qM6Ab^>ouS}i5n3s>7SUs zp881{c9JlH%!(^aWe!d9Zcz5cWW1gf!xkaShNpm}Nd{*(})5CYG_;oMEY|V$4 zhO2pRtVogrQhCWBmNkb1up}^a5wTDJ8XbT!>e9g`Gw|?il1@oA2B(xM76;MPs9Xlf z(U_@xby7hwP?-69saifKDzb#DmqzQZ>qF92j7CmEI$B~*dm%kb$&@f&0KmKrA<=3< z$U@weL(d;T!gpMaKh2xhmAf*sXJ|`Y6KzM+BI}}!qwkm@X2$E=#bSoJ}Un4M9 z(|e8CD+#ZdWnEq9tc z)M_>7QntNvjRSX3Q*-8?)6nKE%B;bQs_S&ht;%(IxOiUHqKT;vbLt&x8kI+D&6zQs zV{lHKq|hzX!lSgcOfHe200{y7>Ylja~Ho+^{@A%=R}Fn7J#v^YhkfUEW^wH%7j^<<6V^3Y)8D za_cxuYuVY4F@Z_e=B_#b?v6*c2hYHcFHF4D6 zQVhmW~Q;msNpcDC#9LDTRWe;7=M+7Xy>U%Fm7!{7FY&FD9#G3g0YH z3TAd9wMKJQ7asenx@sX0ZD=l1Q!we4mUPnL3LUO!M3EclxMP6Fwnlc^u8N}^fun}X zd5p1E6e`=bVXlpYx%= z^0~x!rIp(aQ>-uL%DPvG<_I&eGq%|vZk|1a?i|&caoB6KnKkE}ri|^bEk;_z4)bu8ajOaQ zN(yCTc`&W!jS7nY`r=HT_q+fHm3+;8G2jCB5Lv&cyZ~q_FF*MF00m4%=RY5S07pBh zV=JA=tVs&vIh21F(h4(8^@FjMh2K-NPbOeMqLEn7=>o#Rd zs^UzSg(Kg_Q1dBTcC82LbwUFc(jOZzGm7iV=yQKvGy$`IMn zkwolFP7WYA4&0vGUVWd&*}GuBszh>j-c0Evl+NxdVA@2G!8#d(aCsl}jBOheC~HkA z&|S#2C~=;KH6?^ft-x{kcEkGT(p93X+vosIN=2ZtB8_3DF?i(LQ>2z8bdAGqzX zoWkYU+&L|B;?@V;rOFX zb>lE2^6N8r!whAN-Rp7^G9wee6pusgrO5to4Fqx0re+TeP!I-c!=lequ+ExPjiEbm z?Y`1QAo%<~kq?wDDjZc~S_>@!@bw!uWz>!{wJ&7Ss?x_o4v5r%-?>dAW@c-xOBj0= zd{P`p?6kIQ`Q)sCr=8{=dgWRxe{y>8>}Btud0h&tdabs*OXZtMg6pIjY%n%=2z!?u z*>sNVy;xM)l}VjvV;N(%-}YYe_8O4kRvnb%DWj86K@kdgeoJHj5C8xF|Bt(G`>j%9 zj*&MfBhYj>7!ePX`}Q|B#qRNjSYsXM;2}^YEpQ2xOb<2^=yJ0 z4bt*VTuC$X3}c$fL=rKSnw|#H`u9O>4V}GFM(qH$DJ!!RR?F=g4|1F}h|m{9dd?{n z)quY&+FcIm?_>;_W6#jP@5;jA2y2ftGX=~x+M0gtyK*=38HZzV#rE3d#5CwM_{(hS zMdWS+afYFWi6d^2Sp1fLX8hd~?@2c_>_F6zJib=nzmG$=G_Ki~!I0zqMTDN*2`qh} z3J;P%x`G{eZJV+-Od|u{!J~OAoX~~erGi|#cxF))kW=9}`9*NKK`f?>V|pQKEey)( zWtVcb0ZO0i)@5?q2)&wT|N7!=C+~Ft34nx7e?I^Kp>Jv*<{$uM5(_!!vGfXmK&QO( zAo;^QZ_4apO=5zIc2heots$C-z;xd!-aX12?G1W(%tgv$j!ZdXtOqAZf@eESj-+N` z+oIiTHf-Si!16q$Fe2k>aEXh%t@-WxmT#qWf?NZ|pfm@_aCz9hf!HW5n8Egl6&bft z#x~|JsrrbY`uUZ)#YT#XNny}#iKvchE!M84GDeafj#C3T>s^-_wg7 zB}+9vwls=}bzhwHkH=Rx-Pde=8q&2iDj%FEC?|YtRGvH(h|+^*bIK%=7=jO}6}_IwRo78iRIgV8)TdD!Oq5`iQ{(E1%&c(BbWNQ(5Rft#==NI}ZlSL4NZ9I`ZCQrFj`JUF-b&94~glW_5m@1LiC zZ*dR%Qc2bl`1ep5{;iq zut}B`3vl&GE!GanM`tI@E;JfCm_XP5J46BH^%EuQ89lUJo#|8piZYYS=?zB;`GETIU_DUJ7t34yUb$s` z8MT7B-CL!VkY9$83TlF#Y|~w>;LgvCW!)IJio4WH#5!-IB!DW6R)#MLL6X4m;3!VL z8X#s&DH#UG=|llIc^5u-esqSgwp%1GJaD4PS{ss%5Dr^We=Q##mQ(R9T5{5X-3ZXS zKOQu&{y2$(IrU3o1LIQaT9M{#Cks-pT6}6|xRg2{uX+JlZE5As5GZ1LR5t;k`7|XT zi{t+b$JAm(Ei4DMq1@>?DQSGG=Lw7%lsYnhEuH!hNid({WL6Oi?>c-wDHm$y6Rs2) z9=L5-_7Ww|E+fTPw^mlcEfG+-AdIcarV;2pO9+{ZAdD;CFi#$NV@-_726*~@`B15S z7CU?>Z`UUg1wxrsm1FzHtDI6DD|)Esj_%O!5bU?a$N(cICpQLVlw*Np0j8s2&S*vZ?P~`e#|Ih>Iw2Yy;672q{2&A{>wwR@NfvmSe~DveZOZvjc;cJQsGTHckRk=d z%R6D>%0?9(DFx&g)rYlwV0C(#tA~k?{f#sWq%)L9iEA^oH0dNksXJdkJ|V&-W;wig zJ7Pl}A+ec|<-(FGskwHJsu<>wb7x>X->8$gMHMXbDcF_JmDyBoI5L@g!cr4#RWi|I zCDW9nL5h%s^2CG8ViWQ*0nwUsGt=_g*G!*3v&c^>Kj;hXAr%xIq!W)2S0zrQHD1R3 zr1yNDiy60g^?kU1;?cTl`zh+< z{&S}n?$%bPj^OF`=T$%~)2i2uw?f$<#?9*qw)drFYI~0sl!YR-KEyY*O}563G|;Ec z;n#N6TK1TS$)|^x|Hje)xvZh2=+S9Emuk}da-OfFq?Gg)^w~Z-T#jRrtwWc}XbXp^ zQ(_vcxsa|l9G}s4sz)SZ8^#)~Q4J!h${&f=lbDRecZgd&kfXG-wnU|*XKQ%J3jg}zOj0YkfCt2a&iU+qu=%iA-#zTkUnUDV z=dt{Y^TB5P_CJwDBZEvv#3WjoQ0+OY(_a@ z(e`;!&P;WJHdvd)+l)572r4{MnE$igp_8kbTEgo(bMwwh^ZF z4B8bHUTQ1AeG|3iDmqz>A=#MnwJ)f4PRa)=T1xqeor|ef5EZc$U+W()7CiuNgu*iM zR^{gtGb@x4&h|*|8Gf^U#b`_2T&W-=QWkcgi7+*z4;7)HDLW~YDFXji=jzr+%y6Tl zZ2fb#=`HmFmDiGLxEhkePi_@GAJ+}(TdhWeschQgm8Y;!*UYb+ZAKjF|Fjw1#rAHV z^XnOo5cXBW9M05?*2C!E71VF@oJ(a^DrP2L8|xb&h4o0Tstdvrz(t)WqvkboOyxbJ z((Y;GTZB{e=Ze7_3O3^%TA6&Gda$i}^@Wv@$1F=L=W-tWyD4ysiiA|&yY&mPyk)OK zaVi7EEI$x*RzT%kCM^omq@N;jNZ$K zP@Cq8`N73i7DiI)L)ptQeqVs?on=rQU$^cDcbDKWgS$Hf_rcxWT>`<~CAhl}?(Xiv zo!}5Wfsha+T=MDMI_IAE+^SRce)@M!b#?7MyLQzx)4zUJcki{rzUAjhWAO*L1FIxh zP~p>T_dQoFhyAn{GL6j8nhxbCwcs?WqFITg^=6}4e=*pG$9!a`^_AwuU%FSjvO15b zaCHY8wM1TJUv=g$6i)MSJd&O!knLf*%K|a7=Q~|p6WCxI7pg7`WOE5IJ zCX{m-VVBbwRCCjTqgTO?E|*T$*36nQ;ZT1fi}7f(9A(Q^YD<}oY=Cjd>PJ&7(b^-= zF4-ry*u0X(xF1PI@?>SRrpoirSL0Z1$3|9$Ngkwfy|l<(3RcfYG|oMl$zys{FV{9t zjX%MP&`6g$*@A2TBxF#-HgXL~bu75m_In&*Gowree;zirj9w!&g3v8yEiTws9}}tF zgHoA5w*1c9j-|9?uD;{ba?ocuarzEE(-WFC! zZYIpPUwQ!RI6C$0@Fe6iV=+l15MV=w<@xsgyYNCRTwC2JqC}ZoJgSG;{M>UdnK9L; z0#=p{wY}?Sbn#|3XBLGG7_($1ku}-Hdvq}Fdi^HzobQ=*Z*<}os_$zLHcRQyWR+b) z(fhgko6(Z!qIl*wD;628R+*k$YrCDdwmjzAoqe7k(gl-ZaDF=QjQJNJGL*+;Z5ZmV zbS#PEQ`7)*eGuGIw>`W-X+tNlooe+~Z0g7Si3QMvi!`BYs39e&(xG`sTyo+ht~UMW zNN)1H)l!`kxn!2N>L1Hh-zBFiWWrsRk+I9vNTC)Z_c3AS5^kep55lWu&%}&On>GH3 zlA|kO4Lw62(-wSU+u7ji!y{|hU+h;5|D9j+B+9~_nX5$*egdQyDxUiw?~Oa7btT`@ zAD4sZQ`5FQtBh4eR7;E=4T6cwvK*3aiyo0zPzySD!94!-M{A^%EOQjTdMJ&a_-P8nyva>FU}AJeesfz)rL<+ z9val7Lf^4||w_&(yOG5AHoa(N7wx`K%_BA*V;zBUZM zbm1U~1Af4KSY&02TUCha>WqzoAv`yWhs^HuzOI(mwIL3=FUSMHD&5q%=`&nRj1ZiY zEJt%^kWR&!zqUD?K3kZ|m9Q|7C@~$tsQTjj?sqPWYZO!%(f+yT#GvE>OD%G26(t*W zxAHr7t@rGeEi|?_ZX{Z%59+PqslNu%#`wAqT`t--wt6ihE7+i*3Fr#}&=wo6B(&IU z%X$vBnWE>JDySd)xW}oDSWl$_`NRj+hFl9F4npnvvLkYf(bClQAxV)IN{i=(k%csw zPjW{sPDKc!d_Y914_XmpkqvmrpiYi4Vp1<1y!8CFoLDdLDGNeQdyJGJeI~)rBt(1y zM6m~!zfjO7eS?B#n3OrjT2Pw`p)%b}on1Z(XCi-R%?c~HRN#=S2`#Xcx?y|X zI2u0B9ab4{CGx>5W9PR_ZINH;m$Dt}>vg21x5kdI@-^Mo6MkAy@g-S;fuk+HtDK`p z4*$dyCgR{kLX@IJNHro%!M~-gn z;%Jfpa2rZkf9r7`dFMSGMC1_NC8LXzrAQc`U>n#rGzhzDUc>{S{lo#_E>-q~mdYbc|eAyQ%czO7PJrcYJYbJ_G zr{l>of&d*^O#Axz)nBc6D>fgP4g;5JdnHk4rp^f9?q!%Mj3B=~Q`h?-{HwQOriwXU z71iKl(KOkYWb=eHdq{6?c3^E1y!5ag(}D&ASmVsqlw*?{4T%reijzYTjZY=j#ypXV zLsL@LNk(u;9wLrr%o8W8miFVo=e|1KdO585J_KLy+>m zk6#gI8LBu~Yy+CO5DjSNn;x?@qU>5FHsYdllyQsZsx%=p$pjv`PAI~CFjRQWdHbfW z8ceO6Jfx_Q`!WIM=tE?tCyA5@ajmLKyA5u1L1^|#kHTAC&bdN9&Ci6^WdtTYe(eQF zLV-;Dot=Fqet*M<;KddI!fFuM`|>SMJI3!%!awFr#F4l!O@Ga34O$8PI_cc}{ljlG z6uX{Ma5alsyH&7lPbxBQ+DGvX*kum(dD1EU6(@`56>##yE+X<31Y;_&N$W)3H0`r!R6+Yx(Mj2d)Yjo3V=Y51t$AAl1+I8T4`RLnEpD&7V^w6YbZ8g-)79a2 z$3&^U@>A5&byO_o5Pf~{BwP7Dw{5XDhg-o$md6!i^QJGx-4j23D?xC{qTc6AtK?Al zVZw33i^N}y+n>~pPIpd3x_bZI>3U)8ZcOww>_q%jl*@bk=5|fW2t(uZrzo>LYEiFz z$NoWmW0mtd;1H+i)%E_*z3pfKML2( z0g#?oPpo$u7y3KRvD#l2cQxC{dlG=>6%1y&wXP!o{)KT$!ar4ZyviWGE``R7Q~XHi zBmZ1^t%qh}(`;tRIB*FXQ3I z3++x^i$nVshvQ^1TfG-M>@G{3m8qqWqktmSA0ZZo`GO`+$wKg2gy}9x)3p-(*i%P2 zZ|@7Ftz>)|{c_ygD;oaZ6~!}lNM2wX@PoynUpQQH=|~!s+LYc@kz;4$xuaw{tb0*b>^LPlF+N3}3)4IokvwMgL-od6P06$(M zzv^$)-9!BK&h7Q4cbpO?RmE^)sRlyFC=x>RIpHY@lyeeHKU#|;>dZz`&F^O;5*B8; zau;@`Cx6y5z*H`lATSpO!I1m-aAd`-wZH~6RJzG zCHWdBng*Jjf7&Vm+@TbgA|&Vv*03-KSYaL7n6ZZt#PwBlJvR>zX7ZG@_+Ah0sHsm} z(LSMsFL{u~(&5T5feKR61&Uc$rMgxay`<#tTQUg841b{jy$@`6!&Qd29};||Z^SSZOIQqk#+J&4nas40T5&TxhJ z^<*8PKy@0M=55$yBUYJ+0-e)&+_Gpyd~~GvL@*QfaAqfA%~ViWi>B;_Hr_!9L@rhz zt;lgvOeY1zaH18MMDeM=KWvMjt;KeG4-rbNpyr@c!~>bJ7`AhQee-OV#F?mIaD~FZ zmZ>nyc}V~2Z+L#1CC+J|ESRz@vl*#mB8(#%vAL?*4!N2l+$1*Mx_5G>qv7Q>s{6Rs zS=Am;*Xf03n$R?SR&7_CH-B2UQyx^t8ilhUW~7_Nqu1Tv{rEXBZk51o^o*#Q!wy9G zLiLuZR44;0eU7PdIP5i6Z*q2d`>cY)xY%$`4hVuYs9kDZ zl`8=6hV=dA$n|8`KXv?ms+dYmVee1@$OT9+_W&@w(O9)_KrSAhL5iNp5q?EqLiNg0Nk9|vdgqEoIc6r~j!|8UE;w2(6jIC%>K!%u zS|zy~k;{|Xsw2)Mmn~|uT_?ZS$Ff~`|$+59VfI)NWR2_^L$SkInZT6M|X2dv}TZTPt zB-_%*$F9Y<;sK3hd%F29!_H_Yc73xu=;vnHS+^DsGSjoI9{h#o zd)Mw%WVY+@_}J;ma%V>j&rr$s%6n~l>Ik+z?K>XAT5N*J`o1E zCCt4!1+09=MI6k?Q(XxnG4qa}N}atemoC3KB#_TaKYmYQpyPn%i;0+IHTueGYzU(k zT^K&(06$R}YtPGCezU^^-p>p>V#|?(UC|?dd*;i|&KIXy4nW89<2%d?yS%^~&_QwS zgd$)*w=!AAZZj+WBe;sJW)enPB0J@e3^0ACma83sLs5Ic zfu(~qEZ(yff}&wC{RcFs_E~hh^g1qA^-6G+o2$_UGIDwppY#&${1HkuAf(xMVW(WF zD`t#%T)GO$y?RsE4o;HL=Au9YSs1cZKV6uSX+YvO6Gi6wHy0I44re(wtWq%nrtTYa zFU$JjTGvw-Cz-8D{hFn$Wg{3@Qg=){lE_V%>)$kqNWsz4MTttv;lj^fZ3)lfPTFY1bOVSmiaPLY+-RvqjzXq1r*qAB-{Ve2elGgQ zuYLS7+nA{a>>A0}axZuMxYPWSmFB5a;8Z92%3&xH2}uzSxV$pRlJlt3i!D7!vmmMMP3x$VL%gfAcSW$DZnBCOkt^&nDX-2E7ZTfa!t2dy}lEQItN;Pd% zn*D$5P|64?7sCIG>pkaFdb|n+b;v8rhZe&huIdO3=vsie;?R-fHjh1J9`rHjsWAOm z7fVEl8xM?{+L=}z{^GTF2G;cK!a49OW<)HKnXy_%I_(r_+m^tbpcB7gW=S(o$)H$D zGG~^GfaqfRg79BT)VlB zF`TX}7odcs7>EV0%BT<&p$#0Ig!GdkC|kJx^cE@K?@z+k(w3vGu4(on2N$zRBS9+9 zYCSJ5C@Pi4R2?fBDLOtO`ddC8MJR=h$BsEV zN#k4!jfnx9cnH~--7Sqb)IoPL8M1Km zp}+_fZ-3sorQCUum5AtCBxLP81SCP?;6cw}s*ZA%A1Tq!$^z;&?X66#kl0c_%a^>Q zaI#+9Q!B2uYz+5G8EPyS9RoBhH;VWnJC9@B^sFSa_krTGrl%4o8Lqj;4u zn${CIweV4ra%&5}a9w{(>_;IP(ql;W+=f|iiyS3m5~ZxZ%B_d&0>z^L$K`7Ad?6^N zI$y^_G9Knya~FD-&iI_QD&>o_YKw)S@ef<^`Yg-wF9~9n=Wwn?;xx`G%IDYb1miDy z`U8mtr_{yl*kyX^_CcK@%)^3d``LJu!2Vy2tAT2N2!5{KPF;Pi#f#Mb;F6(0h$f`7 z1C}1Hj7H%zCcqp*W-(Vc|DX|+H%(C;We}MfV@_vf#8--;3OV;|zdozbe39?fX3GsB zW~^sP*DS2)+!X3|XFbt%Mm2q0w=dAzp}BVJGp-3pFa7y}dE>^aZ2Ri1CZw-ntcj}Ll?vk`i?Y;L}i6L@m~4hnbD>&B8egnHx4)$$@u$t@POZNirC`6fWm)?338lU z+q9CILh=ZX&7#pQWV0onUq#kq%{t-3=G>bxyC8Vu?)P@|0;T#~%EcoA*$J-dQ5tbv zVJ-KQt!iDG5PV5=1;{c=;^efmU*F_Dr3O^|nPF-3>N_Q#Cik1q5GXfw!MIJdY4 zx%zsa+<}coTTq!xAv))KkwiWcc#gE$bv8+N5Z2RRyk|SH-kX@c0!BI6GfVQ#vfFj< z&nqEZv-ZE6t4>9p_i_DNyk*Ku5_Z$}MTqcN(#F-h2>UvDo&fSJuJ_?$a z*b9vUwrc57zvYr-Hf)ORlGEGy+4T+;9GqBe#5oCusSd<5Q|Md;BO*J2Ny+Ey<4+v% zdIJw%v>W=g+W50s5Y(jT$u!M*G^;uL)W+?lA*u3OlJuD;3H?}-d(j$n3AtdC9&P4q z2KW!`&+m1OM9l4G5WgRd^gE++6I~eua@4mAtIz|7P2Aia|Ar6qDD^=I3L#@>H)*%u zUFdp*FXjx(5#F8lbWWcQf<8oM@N@kP<7DsXVA#|unZ9X1OU<<(T|15K1Nk9Y_aS3MZ%&RaI110=I_AWE2&2 zfC{tVG00GvHniwplgP`cz-^DGdR~66RHl6ShkMack$R=(N`_Ihg81jKE;SmOvZG}e z2fL*iiIh}+hkzB8SWhd`N;hmnN$c1)>BFo3XJrNBXWosm=6f4;U$h|PSjXxPjnA(} zA;RrnJ{2B%NxHRFMf+lZhz{k!b{s2F72?ie}O{3NLZ)Bgyrkrqou*4{UpKw z1*fnvy!x{0Pt6|1^Xy|ZtEX`(L&(&3DR3dm(VAK(QMX3$U4dRb;@tIC_?b%nodthO zi+JuQVj0z3c?o_LmAWjJ7)4#vUmvjCHcOZhD$n?_kYpM*H7`?G2YGp-&6|9X^FBFo zHWcr*3K|Z@IgKhc+p5&7_gK@B_sWVlyW28LCgh50IiBC*8i!|EJ4qYfTM&|eQ5bwN z#uFp;PZEj*D!S(LCQw>f@)lH;AO1FQ`9EQ{0n5Q%icZ4r*|h>|8iEcN0Wd}1Pbx}E1&Hns#sSJ_KS*W?NU${xVE2jz5n#=L ztYYvsq$bd@+Q2%MNERzxaW%*`C`f5kVkUMqD$-0D3~V5VN6F=StgMgekj^IR#kYFg zJmz5UQikL0;T>(F!?*<1VC3+Y5pt7Gf>2e<;h-_7cMxlejtQv)AtrP`BD9TQJs7CO z_sU=zM;G<}MqW>7_4~Yw90*b8gP@IBQcbi=$uhCzVooh=+2aSDlwsmH`4dAzt%j(5 zZu=yi4>v)O8=WM*@^s!i^+o>Z9K2m|prVfq^|1ucBU!Rq>rX zRb7&1+?8G94k=uy$D=M<_rGr+X51^Ta3ShXFEMd1k( zk>Fb^{B+sz*@WJQMGy12#`gE3bAwsW{XqxX#T`GYo9r>-a%FTqV$E~GZ$aOE#D_q& zuJsoucc8Chi2}0~6h`GZdFI#a*J~x{8PpWQSP4|iVv6$z^F}K?DpC|V z+xjYwPUN)c&H+m}`5^TuoLad`!HAc4VW@+YFf9tIBxsSsbY6p}n5o;MlNqfh+Nwx< zDti$ic~t!YEK0u8qz7cAU;{W1vYGWJA!V5gP)k}=$F#&vWkMSZfyWB^YA|Tl)*Qa` z4;M1nEyQ6!l;X4;Jj@G&4aA>73Wp2L_@?9Tj*V$LliNcpl$A#ZS7(Eni4*rM>m4Qv zq_72iqC#n-0fDJh04}8|HVXS5e0xXGY|v~`A$me@vkr*z`PMN8JQvTH8voxZI*F2%`Sqju4dgDNAn zF}rSq4YeXf%Z*Qb+#ipseDTCLYzui+udjDMc&3y=hUx=RsJ>M&eMJ-nz}Owtu~tPK z(NF7_f45V_sv1 zG+TcCG?#JV{T`07pWm)_tBpL}J8pja>><*C$#fLuUe|A4#qIvHfxs%e5PPdE9F?+A z+0@EO=tJyt9;{-hk*rD<6C@p$s&XR27{+}vmB@xn)E$fGM=S28(6w5?g%^d6B_|$x zlx^Qx(Fv{u2uMPeO=8B5F<8sWBz`T7TgQj@K%pZ7ksud(4>ySd%UcFaHZzB|I#iI) z))9S{!1SwM*EXJ|pHdJ+7+V#@$H9O@Gf{Ee#dl^=b%is1#2=UP>M5}TP+my%RHj36 z88x*OF`!H^223Pvf|6TLSnRIk)-8qcvojXxh(dcW8#@{v2%YO_cXlI*)T1d2vLoz7 z(M(TV3*8aeaHH*JB{(zPytG>td_O*yC^z%Vf7SQ*^lE)MGnTjb3SLk1pIrATgVrUWEW7p|j(bYsF(>rg8oFEcG`-Bj$b+0O=q^%$~@2C=0b? zR~Vy`u670G(xD%@wgu=h{%Ji$N`myhpJb2{8NTwJm>HsJi>lq~?fSLvXuI)UEhyv& zaU@7d>2$q~H&3qX>9zZi@M*L}dYgz_V$|yO26ya2x#ti!-f0y8c+`u{(+3wrp|%XFF@$o(l&M3@&x6JRLE+~h0mR*hUXV$N2R)v`BM4=&4fDGM z$&W-W+}|MsK&~KcXlOd047%cn4_N~KZLmz}F7t^;RM5?|Rgq=SW#BcRNxh&_)=|$y zoAOyzq4q1`FnV(>&waP~!q`lGZIXeYWUL?J2M-yecR{EmQ1Tfb_z#1sA8PciU>|vL zd-d!)&D*BRCvn(tp`&Z#DKx+qZ_jH@Q)xjU5h@>G#y-C)_g~;SNC1)E!m$VMcto3G8Ddc7P-Q=6G(h- z7Lgp71x4Ez)2$W1GsEY+3;al_pN`{Etp`=ootWHir~_WREv zpeZ^^M2>kA#KeKKBqRcrsCjCQ`Amb@$}qTG+94iBVs@*UbTWJ>8LO3NR!kS)_geC> z@cXEuDnHO~xoikme91Sh9+$QNd>VKqe|BXHChQDeN48>xun|~PRHEjt5_Do*zxZ$l zn{l>Mi=_4LY@YPXEAJvtIag=4EtA_vPtkfMxnY+_`hs;@hnSME%`KtF`Il9x$v}bI4HSzUwDwIl$%&v5A@ob@86GQbB z79E9{4`J_XaGm`%3J2`XLCF3gA{WHgLpcsMyTSx@b|I**aaRSID5SLF`4=v z6vG&T3EkFFG9ZE3`#l7)lf*HX;y{SyTIJQ$jc9CA%98l8=ix2V?-=jj8tqDs7j>_*s>j?aBBVs6*T{s8wG03G!ZmK4+5QZ$^mQ)D*};8lsug){GN#>if0XKyb_8-q$(xq!Bi1m zNO{wVUQ_ZVg+@FXfP_=Vs7YF5X}at4^g&PBZCRxF9!o<**)P@@SR7#_#zA`_mKtb? zW)_cvKs4YW9}i@ZA=)(=kilfjl&Cqu8k5F)l02>ssfB_9n?jj-!i&M8tJuS^BB#S7 zTMrZ_iic6CVx!_Ry2%_VSxynHB=Z{=;#Es8LfTDO%=Mfz6fT#tR)hq7G+w!~%#B=1 zm1d)}s+Aaf>AXug)m;wZjpz_LpxCx~Okm;;L}#hLMjoonR6R!+8o4dDi`oy`7g1vn z_#7KdX_7`wlJTf4ZR4p}V3w=H3pi7GceT-EUI;iH`*>IURK&H`A7(mpw(K?6YWoX? z*R{eR?o@X0rRpPwc;Z`)BUA_^cDUYubCg&d*bO zC0;cK+OB76YLYBUAEw)wpvKY3k|Dx|_dk+_WZB$nUflx?40m4zB>OV$W}4+F@J+jd zZ~Cl<&bKc8FC}eY>Cs4nn&&{7qD}J3PpW&eHAjg`+!d#jucy1O-=5xX8JwEj3*D{{Z~v)3=l%YGnM{)Y655xX;-`y%F~CG@_aLm$VmZFjet2V^=Rop$&r zoSw>)774a!D$ErAI3Nx(D{nqxS8HohMmw=&NC1td*^W${sAA)7zz0+T&yT)8STJT# z1r?y!&MB!%t39Epo5!VUlAft;r--H>FA2H}43T8%D$5b8i#sY2N_gC`D_L&K&M`?` zk-6lJsWCmWrJSBEuD1k(Ia^qA(~wT?DRE-Fa~A@dowZ}AH^VQ&=)SM3MY+XSyZFJ6 zPiMy4*nFWqre7Y z%k0DTO~Xj>Lz$QY66*UU(UQJt`i-P^n$%Sz+GAg~)0nqA+iofu9Zbk+eKiXTX~bb! zlpQsYQV&>@DKuG(X_#oT_e!C%$6L06%q1NctW_rx20?ak*qvKE2O)+!`pA zsX+k+!xQ=nraY|G;Xd(n;;|4uG6~pcRd)KM3fDgZ(pcu?6}IzTu4zp;FdC(|EB;HO{wGVeQRMEbLmk>Gz5uD zWtm&3PMb)oBM+z8!yv7uHLQ+59^@ewMUO;FbtEA*(viooC0{F{vSQCf^?k}FCE4u_ z3SgcA5C*)rQuo;n*SF=_3`O?C8c_gL>6`DQ!r)D8t)Wd+lAGk`QcCmOtJbVqv1?7c z?;kCC?{|OYGLp|cLZBbsqA0oSqY%9~ElqV+{P)YWG||OwMH6l$k-)#Zw<-nELhkqn z9!gQ{#U3Sbt`wMvxKz>DR903ARPt5TudjDBxw1(VHblZJdlL-EA%*p?@WF)^cu~QH z8r-Va$f2V1TxgPicK|4QUhcLLM06RA@tF~i_2gWld??U5$OcFeHnz9CCrzJFGT#A* z5>(m35KiZpj>kFbb~Gs%iFFICp!iXVUcM^6U4WUqj+TN+EHR-iN8gj+(I-Miqim2vS?*XQ0C9A3PH^vuEa9pll#tMEMTJa6NgbPhKLx;P;h4rKNMeP z&A;{a_v@2utIjMS4i*eeLWdI+9VA^yQ%$g(nYo;K^O%Y!YL{Y($_R%;uvROof;be7 z+R$GbjYp-CSy-bOi^PZ!I0FFS<`$gKLxI!bius&|Ur{CZ#-lGhiF{skCd?8h|5P#A z`ZZI2V#wb>lthxaiJ9MA(%^G!6|NW&B4J|8MM35~4BKXwk=QjRvOJ>D zYKat8%W3kGzjR_>0$NX3<TY`!Z`#;+#St zRV>A}qzo=yFqg%e44qO~X#W9)|D{p*XZZhCfxk}S$q<0?4FIrxqW~fRfJX6_`S9)Y z7Yc8OTtNT;>_0!)|5oRJ#{W+W{PQ3CpA`DH_5TBff1A|*O!O}m_y-FAQl5Wj=RZ*R pcdGr*T>rfS|3Klt*XG~c^A8mM&4T|k-G8INKT!B@g!%V3{~v(t5)=Rc literal 0 HcmV?d00001 diff --git a/app/src/main/java/cash/z/ecc/android/ZcashWalletApp.kt b/app/src/main/java/cash/z/ecc/android/ZcashWalletApp.kt index 86f56ca..2ff8780 100644 --- a/app/src/main/java/cash/z/ecc/android/ZcashWalletApp.kt +++ b/app/src/main/java/cash/z/ecc/android/ZcashWalletApp.kt @@ -1,6 +1,7 @@ package cash.z.ecc.android import android.content.Context +import android.os.Build import cash.z.ecc.android.di.DaggerAppComponent import dagger.android.AndroidInjector import dagger.android.DaggerApplication @@ -40,4 +41,12 @@ class ZcashWalletApp : DaggerApplication() { ogHandler.uncaughtException(t, e) } } -} \ No newline at end of file +} + + +fun ZcashWalletApp.isEmulator(): Boolean { + val goldfish = Build.HARDWARE.contains("goldfish"); + val emu = (System.getProperty("ro.kernel.qemu", "")?.length ?: 0) > 0; + val sdk = Build.MODEL.toLowerCase().contains("sdk") + return goldfish || emu || sdk; +} diff --git a/app/src/main/java/cash/z/ecc/android/di/AppComponent.kt b/app/src/main/java/cash/z/ecc/android/di/AppComponent.kt index e031930..0bf9cfd 100644 --- a/app/src/main/java/cash/z/ecc/android/di/AppComponent.kt +++ b/app/src/main/java/cash/z/ecc/android/di/AppComponent.kt @@ -6,6 +6,8 @@ import cash.z.ecc.android.ui.detail.WalletDetailFragmentModule import cash.z.ecc.android.ui.home.HomeFragmentModule import cash.z.ecc.android.ui.receive.ReceiveFragmentModule import cash.z.ecc.android.ui.send.SendFragmentModule +import cash.z.ecc.android.ui.setup.BackupFragmentModule +import cash.z.ecc.android.ui.setup.LandingFragmentModule import dagger.Component import dagger.android.AndroidInjector import dagger.android.support.AndroidSupportInjectionModule @@ -23,7 +25,9 @@ import javax.inject.Singleton HomeFragmentModule::class, ReceiveFragmentModule::class, SendFragmentModule::class, - WalletDetailFragmentModule::class + WalletDetailFragmentModule::class, + LandingFragmentModule::class, + BackupFragmentModule::class ] ) interface AppComponent : AndroidInjector { diff --git a/app/src/main/java/cash/z/ecc/android/ext/View.kt b/app/src/main/java/cash/z/ecc/android/ext/View.kt new file mode 100644 index 0000000..4754a76 --- /dev/null +++ b/app/src/main/java/cash/z/ecc/android/ext/View.kt @@ -0,0 +1,31 @@ +package cash.z.ecc.android.ext + +import android.view.View +import android.view.View.* +import cash.z.ecc.android.ui.MainActivity + +fun View.goneIf(isGone: Boolean) { + visibility = if (isGone) GONE else VISIBLE +} + +fun View.invisibleIf(isInvisible: Boolean) { + visibility = if (isInvisible) INVISIBLE else VISIBLE +} + +fun View.onClickNavTo(navResId: Int) { + setOnClickListener { + (context as? MainActivity)?.navController?.navigate(navResId) + ?: throw IllegalStateException("Cannot navigate from this activity. " + + "Expected MainActivity but found ${context.javaClass.simpleName}") + } +} + +fun View.onClickNavUp() { + setOnClickListener { + (context as? MainActivity)?.navController?.navigateUp() + ?: throw IllegalStateException( + "Cannot navigate from this activity. " + + "Expected MainActivity but found ${context.javaClass.simpleName}" + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/cash/z/ecc/android/ui/MainActivity.kt b/app/src/main/java/cash/z/ecc/android/ui/MainActivity.kt index f74984f..80b650a 100644 --- a/app/src/main/java/cash/z/ecc/android/ui/MainActivity.kt +++ b/app/src/main/java/cash/z/ecc/android/ui/MainActivity.kt @@ -4,7 +4,10 @@ import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.graphics.Color +import android.media.MediaPlayer import android.os.Bundle +import android.os.Vibrator +import android.util.Log import android.view.View import android.view.WindowManager import android.view.inputmethod.InputMethodManager @@ -14,7 +17,6 @@ import androidx.navigation.NavController import androidx.navigation.findNavController import cash.z.ecc.android.R import cash.z.ecc.android.di.annotation.ActivityScope -import com.google.android.material.snackbar.Snackbar import dagger.Module import dagger.android.ContributesAndroidInjector import dagger.android.support.DaggerAppCompatActivity @@ -22,7 +24,7 @@ import dagger.android.support.DaggerAppCompatActivity class MainActivity : DaggerAppCompatActivity() { lateinit var navController: NavController - private var snackbar: Snackbar? = null + private val mediaPlayer: MediaPlayer = MediaPlayer() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -34,7 +36,10 @@ class MainActivity : DaggerAppCompatActivity() { WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS ) - setWindowFlag(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, false)// | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, false) + setWindowFlag( + WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, + false + )// | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, false) } private fun setWindowFlag(bits: Int, on: Boolean) { @@ -47,6 +52,7 @@ class MainActivity : DaggerAppCompatActivity() { } win.attributes = winParams } + private fun initNavigation() { navController = findNavController(R.id.nav_host_fragment) navController.addOnDestinationChangedListener { _, _, _ -> @@ -58,9 +64,34 @@ class MainActivity : DaggerAppCompatActivity() { } } + fun playSound(fileName: String) { + mediaPlayer.apply { + if (isPlaying) stop() + try { + reset() + assets.openFd(fileName).let { afd -> + setDataSource(afd.fileDescriptor, afd.startOffset, afd.length) + } + prepare() + start() + } catch (t: Throwable) { + Log.e("SDK_ERROR", "ERROR: unable to play sound due to $t") + } + } + } + + // TODO: spruce this up with API 26 stuff + fun vibrateSuccess() { + val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator + if (vibrator.hasVibrator()) { + vibrator.vibrate(longArrayOf(0, 200, 200, 100, 100, 800), -1) + } + } + fun copyAddress(view: View) { // TODO: get address from synchronizer - val address = "zs1qduvdyuv83pyygjvc4cfcuc2wj5flnqn730iigf0tjct8k5ccs9y30p96j2gvn9gzyxm6q0vj12c4" + val address = + "zs1qduvdyuv83pyygjvc4cfcuc2wj5flnqn730iigf0tjct8k5ccs9y30p96j2gvn9gzyxm6q0vj12c4" val clipboard: ClipboardManager = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager clipboard.setPrimaryClip( @@ -74,14 +105,6 @@ class MainActivity : DaggerAppCompatActivity() { private fun showMessage(message: String, action: String) { Toast.makeText(this, message, Toast.LENGTH_SHORT).show() -// val view = findViewById(android.R.id.content) -// if (snackbar == null) { -// snackbar = Snackbar.make(view, "$message", Snackbar.LENGTH_INDEFINITE) -// .setAction(action) { /*auto-close*/ } -// } else { -// snackbar?.setText(message) -// } -// if (snackbar?.isShownOrQueued == false) snackbar?.show() } } @@ -89,5 +112,5 @@ class MainActivity : DaggerAppCompatActivity() { abstract class MainActivityModule { @ActivityScope @ContributesAndroidInjector - abstract fun contributeMainActivity(): MainActivity + abstract fun contributeActivity(): MainActivity } \ No newline at end of file diff --git a/app/src/main/java/cash/z/ecc/android/ui/detail/WalletDetailFragment.kt b/app/src/main/java/cash/z/ecc/android/ui/detail/WalletDetailFragment.kt index 3afdbd7..0080a20 100644 --- a/app/src/main/java/cash/z/ecc/android/ui/detail/WalletDetailFragment.kt +++ b/app/src/main/java/cash/z/ecc/android/ui/detail/WalletDetailFragment.kt @@ -1,8 +1,11 @@ package cash.z.ecc.android.ui.detail +import android.os.Bundle import android.view.LayoutInflater +import android.view.View import cash.z.ecc.android.databinding.FragmentDetailBinding import cash.z.ecc.android.di.annotation.FragmentScope +import cash.z.ecc.android.ext.onClickNavUp import cash.z.ecc.android.ui.base.BaseFragment import dagger.Module import dagger.android.ContributesAndroidInjector @@ -10,6 +13,11 @@ import dagger.android.ContributesAndroidInjector class WalletDetailFragment : BaseFragment() { override fun inflate(inflater: LayoutInflater): FragmentDetailBinding = FragmentDetailBinding.inflate(inflater) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding.backButton.onClickNavUp() + } } @@ -17,5 +25,5 @@ class WalletDetailFragment : BaseFragment() { abstract class WalletDetailFragmentModule { @FragmentScope @ContributesAndroidInjector - abstract fun contributeWalletDetailFragment(): WalletDetailFragment + abstract fun contributeFragment(): WalletDetailFragment } \ No newline at end of file diff --git a/app/src/main/java/cash/z/ecc/android/ui/home/HomeFragment.kt b/app/src/main/java/cash/z/ecc/android/ui/home/HomeFragment.kt index 63fa9a1..af2ce96 100644 --- a/app/src/main/java/cash/z/ecc/android/ui/home/HomeFragment.kt +++ b/app/src/main/java/cash/z/ecc/android/ui/home/HomeFragment.kt @@ -3,10 +3,15 @@ package cash.z.ecc.android.ui.home import android.os.Bundle import android.view.LayoutInflater import android.view.View +import android.widget.TextView import cash.z.ecc.android.R import cash.z.ecc.android.databinding.FragmentHomeBinding import cash.z.ecc.android.di.annotation.FragmentScope +import cash.z.ecc.android.ext.goneIf +import cash.z.ecc.android.ext.onClickNavTo import cash.z.ecc.android.ui.base.BaseFragment +import cash.z.ecc.android.ui.home.HomeFragment.BannerAction.* +import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.Module import dagger.android.ContributesAndroidInjector @@ -16,14 +21,74 @@ class HomeFragment : BaseFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - binding.hitAreaReceive.setOnClickListener { - mainActivity?.navController?.navigate(R.id.action_nav_home_to_nav_receive) + // TODO: trigger this from presenter + onNoFunds() + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + binding.hitAreaReceive.onClickNavTo(R.id.action_nav_home_to_nav_receive) + binding.iconDetail.onClickNavTo(R.id.action_nav_home_to_nav_detail) + binding.textDetail.onClickNavTo(R.id.action_nav_home_to_nav_detail) + binding.hitAreaScan.onClickNavTo(R.id.action_nav_home_to_nav_send) + + binding.textBannerAction.setOnClickListener { + onBannerAction(BannerAction.from((it as? TextView)?.text?.toString())) } - binding.iconDetail.setOnClickListener { - mainActivity?.navController?.navigate(R.id.action_nav_home_to_nav_detail) + } + + private fun onBannerAction(action: BannerAction) { + when (action) { + LEARN_MORE -> { + MaterialAlertDialogBuilder(activity) + .setMessage("To make full use of this wallet, deposit funds to your address or tap the faucet to trigger a tiny automatic deposit.\n\nFaucet funds are made available for the community by the community for testing. So please be kind enough to return what you borrow!") + .setTitle("No Balance") + .setCancelable(true) + .setPositiveButton("Tap Faucet") { dialog, _ -> + dialog.dismiss() + setBanner("Tapping faucet...", CANCEL) + } + .setNegativeButton("View Address") { dialog, _ -> + dialog.dismiss() + mainActivity?.navController?.navigate(R.id.action_nav_home_to_nav_receive) + } + .show() + } + CANCEL -> { + // TODO: trigger banner / balance update + onNoFunds() + } } - binding.hitAreaScan.setOnClickListener { - mainActivity?.navController?.navigate(R.id.action_nav_home_to_nav_send) + } + + private fun onNoFunds() { + setBanner("No Balance", LEARN_MORE) + } + + private fun setBanner(message: String = "", action: BannerAction = CLEAR) { + with(binding) { + val hasMessage = !message.isEmpty() || action != CLEAR + groupBalance.goneIf(hasMessage) + groupBanner.goneIf(!hasMessage) + layerLock.goneIf(!hasMessage) + + textBannerMessage.text = message + textBannerAction.text = action.action + } + } + + enum class BannerAction(val action: String) { + LEARN_MORE("Learn More"), + CANCEL("Cancel"), + CLEAR(""); + + companion object { + fun from(action: String?): BannerAction { + values().forEach { + if (it.action == action) return it + } + throw IllegalArgumentException("Invalid BannerAction: $action") + } } } } @@ -33,5 +98,5 @@ class HomeFragment : BaseFragment() { abstract class HomeFragmentModule { @FragmentScope @ContributesAndroidInjector - abstract fun contributeHomeFragment(): HomeFragment + abstract fun contributeFragment(): HomeFragment } \ No newline at end of file diff --git a/app/src/main/java/cash/z/ecc/android/ui/receive/ReceiveFragment.kt b/app/src/main/java/cash/z/ecc/android/ui/receive/ReceiveFragment.kt index 58986fa..3b7c5b8 100644 --- a/app/src/main/java/cash/z/ecc/android/ui/receive/ReceiveFragment.kt +++ b/app/src/main/java/cash/z/ecc/android/ui/receive/ReceiveFragment.kt @@ -12,6 +12,8 @@ import androidx.lifecycle.lifecycleScope import cash.z.android.qrecycler.QRecycler import cash.z.ecc.android.databinding.FragmentReceiveBinding import cash.z.ecc.android.di.annotation.FragmentScope +import cash.z.ecc.android.ext.onClickNavTo +import cash.z.ecc.android.ext.onClickNavUp import cash.z.ecc.android.ui.base.BaseFragment import cash.z.ecc.android.ui.util.AddressPartNumberSpan import dagger.Module @@ -39,6 +41,7 @@ class ReceiveFragment : BaseFragment() { text_address_part_7, text_address_part_8 ) + binding.backButton.onClickNavUp() } override fun onAttach(context: Context) { @@ -81,5 +84,5 @@ class ReceiveFragment : BaseFragment() { abstract class ReceiveFragmentModule { @FragmentScope @ContributesAndroidInjector - abstract fun contributeReceiveFragment(): ReceiveFragment + abstract fun contributeFragment(): ReceiveFragment } \ No newline at end of file diff --git a/app/src/main/java/cash/z/ecc/android/ui/send/SendFragment.kt b/app/src/main/java/cash/z/ecc/android/ui/send/SendFragment.kt index 380655c..c4e572b 100644 --- a/app/src/main/java/cash/z/ecc/android/ui/send/SendFragment.kt +++ b/app/src/main/java/cash/z/ecc/android/ui/send/SendFragment.kt @@ -1,8 +1,11 @@ package cash.z.ecc.android.ui.send +import android.os.Bundle import android.view.LayoutInflater +import android.view.View import cash.z.ecc.android.databinding.FragmentSendBinding import cash.z.ecc.android.di.annotation.FragmentScope +import cash.z.ecc.android.ext.onClickNavUp import cash.z.ecc.android.ui.base.BaseFragment import dagger.Module import dagger.android.ContributesAndroidInjector @@ -10,6 +13,11 @@ import dagger.android.ContributesAndroidInjector class SendFragment : BaseFragment() { override fun inflate(inflater: LayoutInflater): FragmentSendBinding = FragmentSendBinding.inflate(inflater) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding.backButton.onClickNavUp() + } } @@ -17,5 +25,5 @@ class SendFragment : BaseFragment() { abstract class SendFragmentModule { @FragmentScope @ContributesAndroidInjector - abstract fun contributeSendFragment(): SendFragment + abstract fun contributeFragment(): SendFragment } diff --git a/app/src/main/java/cash/z/ecc/android/ui/setup/BackupFragment.kt b/app/src/main/java/cash/z/ecc/android/ui/setup/BackupFragment.kt new file mode 100644 index 0000000..7068c89 --- /dev/null +++ b/app/src/main/java/cash/z/ecc/android/ui/setup/BackupFragment.kt @@ -0,0 +1,63 @@ +package cash.z.ecc.android.ui.setup + +import android.os.Bundle +import android.text.SpannableString +import android.text.Spanned +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import android.widget.Toast +import cash.z.ecc.android.R +import cash.z.ecc.android.databinding.FragmentBackupBinding +import cash.z.ecc.android.di.annotation.FragmentScope +import cash.z.ecc.android.ui.base.BaseFragment +import cash.z.ecc.android.ui.util.AddressPartNumberSpan +import dagger.Module +import dagger.android.ContributesAndroidInjector + +class BackupFragment : BaseFragment() { + + override fun inflate(inflater: LayoutInflater): FragmentBackupBinding = + FragmentBackupBinding.inflate(inflater) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + with(binding) { + applySpan( + textAddressPart1, + textAddressPart2, + textAddressPart3, + textAddressPart4, + textAddressPart5, + textAddressPart6, + textAddressPart7, + textAddressPart8 + ) + } + binding.buttonPositive.setOnClickListener { + onEnterWallet() + } + } + + private fun onEnterWallet() { + Toast.makeText(activity, "Backup verification coming soon! For now, enjoy your new wallet!", Toast.LENGTH_LONG).show() + mainActivity?.navController?.navigate(R.id.action_nav_backup_to_nav_home) + } + + private fun applySpan(vararg textViews: TextView) { + val thinSpace = "\u2005" // 0.25 em space + textViews.forEachIndexed { index, textView -> + textView.text = SpannableString("${index + 1}$thinSpace${textView.text}").apply { + setSpan(AddressPartNumberSpan(), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + } + } + } +} + + +@Module +abstract class BackupFragmentModule { + @FragmentScope + @ContributesAndroidInjector + abstract fun contributeFragment(): BackupFragment +} \ No newline at end of file diff --git a/app/src/main/java/cash/z/ecc/android/ui/setup/LandingFragment.kt b/app/src/main/java/cash/z/ecc/android/ui/setup/LandingFragment.kt new file mode 100644 index 0000000..5e999dc --- /dev/null +++ b/app/src/main/java/cash/z/ecc/android/ui/setup/LandingFragment.kt @@ -0,0 +1,89 @@ +package cash.z.ecc.android.ui.setup + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.widget.Toast +import cash.z.ecc.android.R +import cash.z.ecc.android.ZcashWalletApp +import cash.z.ecc.android.databinding.FragmentLandingBinding +import cash.z.ecc.android.di.annotation.FragmentScope +import cash.z.ecc.android.isEmulator +import cash.z.ecc.android.ui.base.BaseFragment +import dagger.Module +import dagger.android.ContributesAndroidInjector + +class LandingFragment : BaseFragment() { + private var skipCount: Int = 0 + + override fun inflate(inflater: LayoutInflater): FragmentLandingBinding = + FragmentLandingBinding.inflate(inflater) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding.buttonPositive.setOnClickListener { + when (binding.buttonPositive.text.toString().toLowerCase()) { + "new" -> onNewWallet() + "backup" -> onBackupWallet() + } + } + binding.buttonNegative.setOnClickListener { + when (binding.buttonNegative.text.toString().toLowerCase()) { + "restore" -> onRestoreWallet() + else -> onSkip(++skipCount) + } + } + } + + private fun onSkip(count: Int) { + when (count) { + 1 -> { + binding.textMessage.text = + "Are you sure? Without a backup, funds can be lost FOREVER!" + binding.buttonNegative.text = "Later" + } + 2 -> { + binding.textMessage.text = + "You can't backup later. You're probably going to lose your funds!" + binding.buttonNegative.text = "I've been warned" + } + else -> { + onEnterWallet() + } + } + } + + private fun onRestoreWallet() { + if (ZcashWalletApp.instance.isEmulator()) { + onEnterWallet() + } else { + Toast.makeText(activity, "Coming soon!", Toast.LENGTH_SHORT).show() + } + } + + private fun onNewWallet() { + binding.textMessage.text = "Wallet created! Congratulations!" + binding.buttonNegative.text = "Skip" + binding.buttonPositive.text = "Backup" + mainActivity?.playSound("sound_receive_small.mp3") + mainActivity?.vibrateSuccess() + } + + private fun onBackupWallet() { + skipCount = 0 + mainActivity?.navController?.navigate(R.id.action_nav_landing_to_nav_backup) + } + + private fun onEnterWallet() { + + skipCount = 0 + mainActivity?.navController?.navigate(R.id.action_nav_landing_to_nav_home) + } +} + +@Module +abstract class LandingFragmentModule { + @FragmentScope + @ContributesAndroidInjector + abstract fun contributeFragment(): LandingFragment +} \ No newline at end of file diff --git a/app/src/main/res/drawable/background_banner.xml b/app/src/main/res/drawable/background_banner.xml new file mode 100644 index 0000000..5c45e99 --- /dev/null +++ b/app/src/main/res/drawable/background_banner.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/background_title_primary.xml b/app/src/main/res/drawable/background_title_primary.xml new file mode 100644 index 0000000..5c45e99 --- /dev/null +++ b/app/src/main/res/drawable/background_title_primary.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrow_back_black_24dp.xml b/app/src/main/res/drawable/ic_arrow_back_black_24dp.xml new file mode 100644 index 0000000..beafea3 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_back_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_logo_landing.xml b/app/src/main/res/drawable/ic_logo_landing.xml new file mode 100644 index 0000000..ef31e7a --- /dev/null +++ b/app/src/main/res/drawable/ic_logo_landing.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_address.xml b/app/src/main/res/layout/fragment_address.xml new file mode 100644 index 0000000..8b12740 --- /dev/null +++ b/app/src/main/res/layout/fragment_address.xml @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_backup.xml b/app/src/main/res/layout/fragment_backup.xml new file mode 100644 index 0000000..515d55f --- /dev/null +++ b/app/src/main/res/layout/fragment_backup.xml @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_confirm.xml b/app/src/main/res/layout/fragment_confirm.xml new file mode 100644 index 0000000..fc88c16 --- /dev/null +++ b/app/src/main/res/layout/fragment_confirm.xml @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_detail.xml b/app/src/main/res/layout/fragment_detail.xml index 1f4ab0e..2700275 100644 --- a/app/src/main/res/layout/fragment_detail.xml +++ b/app/src/main/res/layout/fragment_detail.xml @@ -7,6 +7,20 @@ android:background="@drawable/background_home" xmlns:tools="http://schemas.android.com/tools"> + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + app:layout_constraintVertical_chainStyle="spread_inside" + app:layout_constraintWidth_percent="@dimen/calculator_button_width_percent" /> + app:layout_constraintDimensionRatio="H,1:1" + app:layout_constraintEnd_toEndOf="@id/guide_keys" + app:layout_constraintStart_toStartOf="@id/guide_keys" + app:layout_constraintTop_toTopOf="@id/guide_keys" + app:layout_constraintVertical_chainStyle="spread_inside" + app:layout_constraintWidth_percent="@dimen/calculator_button_width_percent" /> + app:layout_constraintVertical_chainStyle="spread_inside" + app:layout_constraintWidth_percent="@dimen/calculator_button_width_percent" /> + app:layout_constraintWidth_percent="@dimen/calculator_button_width_percent" /> + app:layout_constraintWidth_percent="@dimen/calculator_button_width_percent" /> + app:layout_constraintWidth_percent="@dimen/calculator_button_width_percent" /> @@ -295,20 +222,67 @@ android:background="@drawable/background_button_rounded" android:gravity="center" android:text="Send Amount" - android:textColor="#000000" android:textAppearance="@style/TextAppearance.MaterialComponents.Body1" + android:textColor="#000000" app:layout_constraintEnd_toEndOf="@id/guide_keys" app:layout_constraintStart_toStartOf="@id/guide_keys" app:layout_constraintTop_toBottomOf="@id/guide_keys" /> - + - + + + + + + + + @@ -326,7 +301,99 @@ android:layout_height="68dp" android:layout_marginEnd="24dp" android:background="@android:color/transparent" + android:elevation="6dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@id/guideline_hit_area_top" /> + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_landing.xml b/app/src/main/res/layout/fragment_landing.xml new file mode 100644 index 0000000..6f85813 --- /dev/null +++ b/app/src/main/res/layout/fragment_landing.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_memo.xml b/app/src/main/res/layout/fragment_memo.xml new file mode 100644 index 0000000..b7d2264 --- /dev/null +++ b/app/src/main/res/layout/fragment_memo.xml @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_placeholder.xml b/app/src/main/res/layout/fragment_placeholder.xml deleted file mode 100644 index 3c51294..0000000 --- a/app/src/main/res/layout/fragment_placeholder.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_receive.xml b/app/src/main/res/layout/fragment_receive.xml index b41acaa..36a221c 100644 --- a/app/src/main/res/layout/fragment_receive.xml +++ b/app/src/main/res/layout/fragment_receive.xml @@ -1,5 +1,6 @@ - - - - - - + + + app:layout_constraintWidth_percent="0.84988" + app:srcCompat="@drawable/ic_shield" /> + app:srcCompat="@drawable/ic_zcash_white" /> - - - + app:layout_constraintTop_toTopOf="@id/image_shield" + app:layout_constraintVertical_bias="0.924"> + + + - - - + android:backgroundTint="#282828" + app:layout_constraintEnd_toEndOf="@id/image_shield" + app:layout_constraintStart_toStartOf="@id/image_shield" + app:layout_constraintTop_toBottomOf="@id/image_shield"> - + - + - + - + - + - + - + - - + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_send.xml b/app/src/main/res/layout/fragment_send.xml index 6844730..12b86d8 100644 --- a/app/src/main/res/layout/fragment_send.xml +++ b/app/src/main/res/layout/fragment_send.xml @@ -7,6 +7,20 @@ android:background="@drawable/background_home" xmlns:tools="http://schemas.android.com/tools"> + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_wallet_new.xml b/app/src/main/res/layout/fragment_wallet_new.xml new file mode 100644 index 0000000..b7d2264 --- /dev/null +++ b/app/src/main/res/layout/fragment_wallet_new.xml @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml index 3636cc2..55a5133 100644 --- a/app/src/main/res/navigation/mobile_navigation.xml +++ b/app/src/main/res/navigation/mobile_navigation.xml @@ -4,7 +4,28 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/mobile_navigation" - app:startDestination="@+id/nav_home"> + app:startDestination="@+id/nav_landing"> + + + + + + + + + Zcash Wallet - Your Zcash shielded address + Your Shielded Address diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index d9ed9cd..29b38a5 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,11 +1,15 @@ - - + + + + + +