From 20a2af90ff5ff391d86712585f7a9aa859e226fe Mon Sep 17 00:00:00 2001 From: virvar Date: Sun, 27 Mar 2016 17:59:03 +0300 Subject: [PATCH] Show fake contacts Former-commit-id: 2d8119be646ec4b4d3770b5368cfa032ee30ae5b --- syng-im/images/att.png | Bin 0 -> 651 bytes syng-im/images/delivered.png | Bin 0 -> 316 bytes syng-im/images/logo.png | Bin 0 -> 526 bytes syng-im/images/mic.png | Bin 0 -> 529 bytes syng-im/images/nav-back.png | Bin 0 -> 985 bytes syng-im/images/no-photo.png | Bin 0 -> 23384 bytes syng-im/images/online.png | Bin 0 -> 307 bytes syng-im/images/play.png | Bin 0 -> 898 bytes syng-im/images/seen.png | Bin 0 -> 284 bytes syng-im/images/smile.png | Bin 0 -> 584 bytes syng-im/src/syng_im/android/core.cljs | 8 +- .../components/contact_list/contact.cljs | 104 ++++++++++++++++++ .../components/contact_list/contact_list.cljs | 96 ++++++++++++++++ syng-im/src/syng_im/components/react.cljs | 41 ++++++- syng-im/src/syng_im/components/resources.cljs | 12 ++ syng-im/src/syng_im/db.cljs | 5 +- syng-im/src/syng_im/handlers.cljs | 9 +- syng-im/src/syng_im/models/contacts.cljs | 83 ++++++++++++++ syng-im/src/syng_im/subs.cljs | 8 +- syng-im/src/syng_im/utils/utils.cljs | 38 +++++++ 20 files changed, 397 insertions(+), 7 deletions(-) create mode 100644 syng-im/images/att.png create mode 100644 syng-im/images/delivered.png create mode 100644 syng-im/images/logo.png create mode 100644 syng-im/images/mic.png create mode 100644 syng-im/images/nav-back.png create mode 100755 syng-im/images/no-photo.png create mode 100644 syng-im/images/online.png create mode 100644 syng-im/images/play.png create mode 100644 syng-im/images/seen.png create mode 100644 syng-im/images/smile.png create mode 100644 syng-im/src/syng_im/components/contact_list/contact.cljs create mode 100644 syng-im/src/syng_im/components/contact_list/contact_list.cljs create mode 100644 syng-im/src/syng_im/components/resources.cljs create mode 100644 syng-im/src/syng_im/models/contacts.cljs create mode 100644 syng-im/src/syng_im/utils/utils.cljs diff --git a/syng-im/images/att.png b/syng-im/images/att.png new file mode 100644 index 0000000000000000000000000000000000000000..bafc26837d8ee48cd1539646bba84521877076e2 GIT binary patch literal 651 zcmV;60(AX}P)0vJg| zK~yNum6AYB&1a{ zV?nhkutm@!5Ngvv>KmR86$Ayfun%j|XyGP5=Dl~?C}}eW{Z@y24!?W&-z%)({Mf|a z5J5Mh$AMa46BWn;=rk}afp;~VOnw89<#wvz_Mv(WFiS_Xz)Yoxb-<3LdPdb89z3xB zwE(0Xw-fp?0*(S0!yN!M`aqx&7zaN6WpY==j%))EW!3`O4mzK)?Wv3T zS6j*~v;b4Nc+5sb*UG8Oaasas2YkhUE-AlyqHtp{VfR{yPN1B$7X4Fck%ygy!X;6;3-niAM|Jtr_^LWk`ue30KvIr-8uT$R z8TjSst=86`T_bL@hV+oCMyk2Q@XLriy=mJY{^X@9odtJT-~{l}7|vvD`z`;80Gulp zYikz0C%{1<0A2v^D~Dw~n~2?8Q?w+j377pIRlN+x`7I;J! z19e;nVMZs7*%cr?C7!;n><^g4gymF2*kv{Vg-&|9IEF}Eu06Nk%c)SN?c;OXf;**! zE0=O-cvyPrbvj=#?Pz@P=EbdRuXKb~l(OsoYi#4_QwZM+{_Fd^g5hh{&-B>=CKu1E>^@}3^n-ntlCMGJ?SK71PceA9`njxg HN@xNAnD>Mv literal 0 HcmV?d00001 diff --git a/syng-im/images/logo.png b/syng-im/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..02e05bf0a9e7ffa9d97f1ce62515ba616d5f8d79 GIT binary patch literal 526 zcmV+p0`dKcP)ug zK~z}7?UuVsLQx#YzrS;@Xpuv&sYoIV+Nwd#TpWs~8fs{^DT`izNDq>`H8&>&t)ggd zjzv-QAczba1W~#7*N`-&-p6r>{Eg@S?)iPr@9{kc=-7WZvid_Tlks*d$~G8l3>vC0 zzW_MnO8G>KMoVo2*v#c-z;q5^_;(L}Vpf*5xj;cWKs=lE6T}sO{-%zMBB>Ne1cMJ| z_7&zy>9A$+Z^r>c=L4x3*vjWeS?7BT)nZnKPYVQ|rDVX+5whCcr0cUXOVDq5zL*AO z0(@8>aDJBtAdFfH09y!es6;7g0EtNC72pfg*$0xxq0pPuF=X(bsZubCLZN-L`F1p36-V;}W0|i-&t87>kK;_}VtWMmpUq6t!R@_z#4u;+{H+PJi0c0in2d z9RvpeU)59HaUw*kj+=~m#Q^|~Noe$O2LSAr0N`o%QEmPbs`Yi0s$=c8FJxnZjwdME QQ~&?~07*qoM6N<$f`KF7*Z=?k literal 0 HcmV?d00001 diff --git a/syng-im/images/mic.png b/syng-im/images/mic.png new file mode 100644 index 0000000000000000000000000000000000000000..9f5e8fc0a7d279ff73f43a1acb4cbd953739679c GIT binary patch literal 529 zcmV+s0`C2ZP)dMi-L&w2e=4YR9*@lg|vl^Zep?a?UjV6 z;8JvPDOka&qpN~a#V(b^mZ%l9@4n-p(HNiB$+O*a&-viq?`QO=IbInyF$t7`#ULhj zC-tT7jCCJc)yi3n2R(CMroM4>&-C5(j^X?|;u62>U{TSDZo_*5d&yH~`~Ft?C;h)t z)T)jg!^8W5n~mq2gSl%2$2?4& zf@8b^hQ9AyxBGV}FshH`B zd;0m7;FX!(Znl>P2WINAMZVwA@h=~v!Cgu1VQVbDV&a_4ru&lGssX$kkB><92-t~K zGkji!Y>nVUm@WgSfIFq-4;7o63qOEenYdVvRJ@M30Br3ddI@o@l+&&C}fJvmKW!y{d%rYk*U{IrTMmO@i&EA_k>j4 zk{z{L+TNVwbE{ghB}DV9yqC=srK}q>=FV^5cSvqe+6>8k^KaMqzu$X*Pv!fwJPt0{ zL8W@@+nK9c0&RF7l&+YQ!**4Qd%~pf+iw^0&gf_K+3{livi$Ao8`nNv#QSfd-}7(1 zEZhvM^j@ue#B0|S6cFF}{lJUoTyKglnkrje{IF;J=3CE#0@>_yN{=OeU~PzAx1RCG zzK}y1hd+mHzLOW+VZC3}*V%wS;m5Bn(>7~#*Ppp1zk~ah6MI-VJKL_kk{$alTwgf3 z=cqE-@c&x<%*&=t+jciZ@|Oq8@840iZ~Eiw z>T>gnHckJoTe9qWL-Xm=%AS=Uj2&vlbGZcMzQ5^QB%@$#&HSoxPjvMzjt6n#e|b+7 z`|h`jUvgc2=3K^Gm-QL%Jl3oC=9yP_kBp4V(OW0Wa<+hgfvU+&lcxltbQp}K7c2P9>L&V`*+%e2S7q)!! z@%R4D{NtkQ?#V23r$>KWtmEKykN;cU_xz=M#JfbrbIliVZ!L>?uB>tPy2x^Wel_c| zI*t>@wI4etzN@mZwc2%(X-QE`*vjqJ?V(Q!;(tvwoB<3ob?yn*_%yqgxjbcN5EY-> z{!K2Q?Vvx<=vRRvD`r(XxW^o?^S{z_p5^zxhe~sfoxJ%u%FW!CVLF3DW31B2qP4R2 zXPK5P5oDQunvI`v$H&g1*$)0!qvnFr;o@uSLMQYv%_t7^WO<*mb#Lo$OL2z2AOEaE qzPAU~2s&^~jT8{X4ss{{XJ~uOIZ>Ofm<5;#89ZJ6T-G@yGywpJ`mn12 literal 0 HcmV?d00001 diff --git a/syng-im/images/no-photo.png b/syng-im/images/no-photo.png new file mode 100755 index 0000000000000000000000000000000000000000..2889cf44207d05574338509df17a34adb93327ee GIT binary patch literal 23384 zcmbrkbx>Tv^DlakAi*KH!vZ0=yL)g+aQEO6+=9C-4ncwhNpN?U#oZl(I|P@v`F`K4 zU%je(|G0JM)Smfl_jJ#kt|L9&{krhF0bqWVmXiixU;qFHdH}Cmu(@&)5{4>j%F=QQ zQvYGV#@m|OxxljmfStXovzm-Jg_gDs1>!n@2oMA4055=OZ0h1DrlO(%{BPUM+&}FA zFwOK&*Z+3d|C)hfX6|ANT_6&a&1>rD>i7@GL-9LPD`PV#E`VZ2XXpZ< zc;X-3k02URBDJ=hs8UJCE|KfkwLSbs#{hPwLQ~p*H(p%d!7QP6=>;%9ujW zj({iN43)41te~=tQ0iB}1u%#97Ero5^st4FfVO|O|JMV+|Jc;Ug5#e)=q00m1b{c& zudi1h001!)0G`8MUmx>cU!U^<0B!*QI+OlK-XRHU&QmBo{(oqoEC9d=0)YDV|Dl-_ z0zd=Q#sq7Q#?Hq7nFkJfhPAK&fXgBPK+^^Q9H_0|>i*yI|7&lk?tl7${CNP-@CE>d zQ2DGK%YX!cgn)pE@CFGH5fK>~=`HFzG*lE6R6=YVjCZ6&+IV*)VnFtBh4un0(S zi12X#9y(Y!EciE+*lc15I8>^}PTvv`-?9IwI>*JM7FX+<+{8Dz0C8|is5^rtO#}02 zXf>*#dI(_vxc}cI&{<*O;NL)5@38>b|F=Ph{AUp`uvl==32;>5#i)$mu~T!1JH2^b z0#KpTLpfN02(Xa+?j9D;c~!w@B04p7OzIeq@qqANO)zT^Sq9X%hW#-=D-#bD9W0I* zufd5v!@edNrU-B=Xhd3S9^d5-KQCQ#?e^H(e^(~e~HV6 z!CBu#{uzJi^VN??%qIhvx~lSoR=T5ReTgvaPswQluxr|{XV z=fIyP>z5E6YIT3!=7fvc7-iWOol#TZ=W!e}2WrTt*oiwwRI6Y5Jw>xU`gX<8ConDU2!2a-qNsx3$e3g&?$9bjzKx!%_6BK0o?2GI{rI_Z&f&cfgxdVpZUB<#NBS|E|R{oeQES zC|5bSd%;!M$rJwIAV1%N6T```;Uq^KG>XaV8KnEj#ADGy{=-ysfJDpubb-3Lg~tN2 zTbqu#MUb`16~h!=my0f$Rez*6*W^OKpSHE#!eKswl@7OXQ}=}KqDNn3Z&}1?D%a;G z4FV&Lvxz<0Gk4(j$NlIjI*=j4M0N>q$!gzO6n+K5x=4cFZEx2FfWO?I=^eP#m`}hw zxJjTiE=`D5PMqr-n0<&f-Lk~#(GfXa@s72TPmYT}Hy^O^7+i32%={~I_{*K|Udwp^ zd~AUqK!gz)_mB(xW=nCp2wY3zE8zL4&!GD4%wf)yjc*Ne1LGA?vD0;B?F$>Aq+E$W zJK7QZbDD{znYPGW%ILFVTY{>Z8E>mCRZb3D*d8uQJ<9Gn2m@9E17>~vCIN)(u6?kC zpo2J0B)P?co~NiU>md z!aPw)R}69#X&m2rz~Pd6*;33(#ida`zbsL$T{>l`98iruq&1os#cVGc!k|djW6W;2 z-eFjg;*oHMg(fsIOp#3NPVUrXq=aA4XOie&>vVt0AGu#A-1*{!_>z`L9Ez9FGg!)J z*_zt=0>V%khV&2nu=jdE7Qb+oF);9u(J8GVT&?o0VfP|Av1|X*F|WV5>h588T5-ZNc7t7a8`~24@y;Fjl75yFtAfH*;uk zj%`iK34`@rvk)Wuu#mKd;j?bfU*(5}h@&fUlNl~geMRHDklbnGkup2K^AU;^FK##TPe^Sk1)x z(XhrQPUIyc<)RZ>SrZ!zn6?jrstVJnEZvhY9>e=bEMik-Z%ghqnu^QNw#U|>pqa3AKX`V*-Lf@%)+3Nbn^0#~#^ ztQkf&nPC&^60?`VffbJ>1!zaXw(nIt)R;&Ry`?7(E zf}lT|#^P&(8;7jhQrwb3q~)&V^#Pzt0N$`@he7=YM*hAzlctm1>P~T*%$XlwZ%x!yqQ9F?hj0N9Yo53dF`}_)2O8^BGmfQXF^|E?M z9?Y9Bk;!i#b?>Qqox!e=M$TY43Ix6KNHZj}$p5?za45tT)C*J)=|Nzi{X4Bb7quE6 zN&oZDrA=_JBEo!^78ATZ4$=Y=c($$qiSuGzsFVq@C z#Tx1e%mu)nwOFd)1ON*Z{MhoPa{(vi zM^cm7%;&x9-8@+#EOqauS6D8OH@GUD}ec{!lvT1_=u>0 z4f5BAF6tdA<%MQLh1jmf`(;k&0 z(fk@KJI$u6`{{P7NN2-@G=BI5+37I2O9?8Q0w$6jA(*uX@@pNXF@A}d!~~H51RTb( zgWb6}Cs%y`GDqowhIb7uaVJA=(dY%9_kggK;8MT6y^MPtrrTw zx~WDpr{iG^p9*g(Yf6}UZ1*iWe~SC zjo4n06?xbAbiA>l)jJ;BCMW(3M#pK<#-to@s67?^WXn*Z-rJTTyBljXXp$U@hPR79 z8=Hj-9*`h(O&d)PE5Rc^+YdC}-i6@q$lzEqiJY*`ix|lGkAu{eAl?hc5Yvo}_iJ;A z9V}gRxw?cCGOTg5+~GfoRdK5X+miV>bRduE#L_``^7aEo)y!0<*~W=|#J_uGQsZyL zb{Nmb1k0?!q+Qe}^)C~bLTJ>LAaBCtsP0YkoZ6Vl7Po6oKWfaTkdTIrI>^al zgR6!+tH&szQ9FXbG+{(=$(j?9KC$2%NkKB`KVN4|$dnu`w%I{E+`rE>g(gOlvw9rw1h-UQYR@9VVrbHCyXx&bvj$ zB*(1C+M2YQj%Z>K6ROg7^t<8Oo7g54!DPno8{HDJWTieuj^Z|@Lq}L9Su0&G*z=OFnobf=IIrdW_fH;p z5?W;^HZ+YW?=S@Q;Pc+&XlM=($6-_5CR7jYy2ZLDuBz+qs^26sjSsRJhUCq0Eu~0) z>r30ID&H+-b>2S>3)}8eX0e^wKDsx)?I+!RJ9VHl;u-YqQP2ftL_|)BwC}GMQh!4B zJ;_LD;5?#pyHz%yl(s75qW#kVxy8EvtZ;thO>Mkr6A53fE8NpS{N--zi|5@3YpM(I z-Z@U?<*N+qUP`4hW3w{|VET0$`;bE>{gM@6+ny6;nVXR*3UDh#VpC#wg1bgXX z#n0Xa(g|H+jllI?Q5`L+2fsO)OEz{HkUv1B}W`9>8uM^p#cePd4H=*~Q=vK^zRvhfk**cG4R$WYz z(^r57B|vsBrS%#BY$qf+pM_!uUjeHy%Dyp}is(qVg&?bKf*T!|G;zW24ZKqLI7D;d zl*|H%WMEZBSK#&qxWUqaj0#&Y~m=c8U{(5f3L*k$CMA6WHtLp-J_pf6<7(9cdnU? zi^(LP8NoCkYFo}Mtndupa+Pf-Bm|0yG*1r=q%GKbeeh_EuZkTT_TI_XZ2D8-h`Z}x zCdpTBO3XMZhKOP%KDCGU09Tzd`33DpgJ08^T3Sg4p6%P?dqu7SyQbywBAOq)fjXGm zLkkzCRwMw-=AoYb{o?Yds;$_xdw@ELM!7^nA|H)2NiB6DypMTjnE1n$)L`DNc~ zkp9>fG<}bqzu5mdp$@X8d+T<~vT051bSWI7@BKI*)ICY@ru%kzd{NNOCcX3KA&m3V zz4~DCf)y{Goa}@P0*hnL5-j}+AeYl7JQldVL76o;*6iShpjmCBSutBGv2?$@JwA1{ z$Hu6s+CNBII-5lk-{V*fZoOm1` zM?fG)lcLPE%oZGLh5BdMURLcHBks5%aLT+gVm1Vw6PDmvV_&k~xJ3#lJ>$yI%C@H2 zEq6qZFfRq$u-C@n)BZz$+RFZK+l#^9t_$p@9ig(}cOQc9o=K;AFw$eBhB7$#v=hf< z&6urTfjYd2vY`ZLkmu+Pj z6A}9q8pMH;XQOltS9)_*(WKckm6@7y+msv2E>@Pol2^p9i?q3WtugId->$?#XhhsF zOK3rzA>pAI|XNl5f&$^f=R8nOc> z)hKyJB7L-FBtf~vO`*s7VyUL|+BuKWx)j}Gx851nL4#xy?l%4Qh|ZVKsg0}p#E%K| z<`3;=-!8bOYK*+lnqa1V6UB%L866lAV%KyXZZGdkh|R}b8eFpM>0GQ_i28qT=6NpB zrpVNSc}2PWf~IG62g3Wi%^QdX_*v@aLhL-eIodIl1Wxdl1AgA zH;=Qmp#8~$iB^WwX$P^Azh`;Swfu)u2*Y=B`LXJ99f$6}5^jDC*dO^( zbenMo^*DtBH-!bPmsg4RhF-2Apgwna|2nwHC)4p6Kd+L#h(z%_{YJ;a5eg9!qSfHY z4|Xd9!28+YfSytEuN;dV!E;YDRzKU2EUc2=VmCxS4dInQcjZ4tk^j3%2a6(u!0$03 zP|6#8MTM+VG$oLk-U@6?J_%`w(*Dx(cN`=FemWC=E5Huo8c(dI5syqoBol6%9ViQ1 zWiNC#DvuQX9FWs!zRH}|KX9Xh=L&X>r+iNviReHrrvB4~XmbmR$PSk}3agxi(eCks zP=Pn~v`&v6vm-jbE@{Fy6p;|Pc}utt1mSO5L77M1bhuR?70YV)z+GX&Ah$L2bD{aU zn~FA-`SYzDm7wE#f(421$PHL+URkMx_x@F8HGzHu;aRt|5Y-)77f=v&D}46fa{L-u zPT_5vuVv|nN}=J(X$LfWjP;#sF?P=6u(4ZPJY)#{t4|P;867{K*^3N$4}IBS-KcwJ z&!NTjSQ6E7=M5hFrzFJgqp#jnh`oYhni;J217*eel0yONFNj~~v0^$;>SwZA*g9dA zmCZ@&b&b{r38@PoGh0xFt@!F!VC6@pv4ZB`w~fWDvSn>offeisyd z%MQ9^El^HZ=MyfKSuy)OSGu5}%uP(?`gnEr!HMIJuB^0PVRI~#omt&jyQXWTw4BxL zB78EJf)jHNMcMWRmswViNz-2x^LV&C*2J0&ozL9Tc(S`KX`CvELO65^S>bY#QlMUT zvjYnF1Uaez;ykF^N%8HwAycYd60X)IjN7C}!A#Y<7wy??sp_dBZK*pa42w@r`?X2{ zvJxhhF&otZkG~8!IwtUw#RPmC)ECl+{sN-h^ITzgbL{2Zcdk{5e(mREh{~^>L6{%? zK4N2tr?R;AD$rhw{@s8OnU#8*a(+4TmPUA_XkOej9mgb5$hT;PDsehi&d2|~eS0_A zK7a)CGj^pst~5uk3&YaOy+)#>f+}=0oiWXEi!)Gfv+umFXnGUVge!(5^yTpKV=`_a z{SYMQMn=klf@m4Hcdc~>{Y`&y@-oS8AP=$2PE+iz(h*br)%B->?JKUq5|4eHUcUD$ zH<*ec;!-ASZtlCe@o)Fse!6rD5Ua@1#8qzz!AfCXevQX1mhE8onPojGjZ0hp%4i=S zFY%=#0u|Gqf0G1+?Ztql9>#yIVeC>;FRGavJvgak_khdEtrb#h8;G5S{GYZ;cR6C-x|pNzlAF3T&wKug*idA|r(HygIDr zL&r$(CC0D1LNQF+cp|i#+~hJgHJBPuJ!&7sf+(a)CR6@%DI`GYAmAYJS|Na-Ad4NK zToEW^PKOIqsX;uzkrrw9lN*?#jeD}(iN(HV;S|cq-dN{c?P^&xAD`lm7V%vNt#3(3 zitGyPq#}o9kd4X)1i3ZaB9>^2T+m6q0>x)w!>!NZ|M;;uo}bQ7B^?c|WIdIb+a2B7@=;NIL`jU+_r2@c3`Vkvt7vmG2#>eyFvWGagw5M|-Ps)=bF|WW~;S1fq zKXmi@q`IB+13F?M9PRkCO+EaUalO6q+;~P2lyCIh@Cs}d+Xz)o|82F>joy-UL8sWA z=iEl7s}hX&QW!aCERUJ2Z3z#Qx+Y%KjrPK)K=oK`aSGspByQr|?enB1?5HQoZ7Y?JZso?fk*AFFr9QRt-CU*iYV<$k2ps@Zr zFWgipH^@j0EBYu`YF<(a83rI$Q?W-xYkiu0kD@qnL2>7dIoVf7O>h}=`iyA~(v7pU zE$e0RGX+-=XB_UA_fJT#vz8Fl)V~#uD*qL;l}gRG$F;Wuz%Lhh>!EZjthgrd*ImW)c;Px2}xkmlY^s4m^;N0}|^h zrw)%TSp6Vbi#BlO)*-8Z41{ZtWmRfLcE)v2BD)*rXcvKlpq@W zQEr+7{y+XL6&Sc*8c+W?p02Y#v*(X(SW;e5+wxR(<9y*49g`F}|MD|uTmCQSD}XIn zbwgs9PnKNfd2G`W!7{V`Bzrlq;N%w_POmfX_wyCVVwstKk|NW3#K+$sEJD$J`0gKG zAVB6Ho-Dahw5tVkX9O8agn@E zC)4HdWgg;q$UWQAA6QIxBBoxj#mki2iF!oD-{)IobYjFvUbhK9t@~}{K;4lsa>LgL zjil#b;qKrSaPs)x8n`JRdo_y8#p-&W)D=+EtiJ)-qT?SHq{wa(HzLdyb2(FE1tNd= zouEy(k>RV0n_DS}Z>Uz9Wk>?)>R;ZgQjU7Vb!<(fbI6^SP{29&N89x{rBRl%MFA%xE_xyw1N}ABoqsQ- zcqaG?>aC3816X!c8Epf(nej)BmA_o@e&Le{Uu(m+JJC}^iRgZ+aD8&VHn|de&Q6V> zck9iI9~AomG2+agKqgt;|NF+)kqgOLXNnBFlrm&I+*u_h*2um9p@~?prQ2O0$*B{4 z_G9fvKgzGX#%>%17|UuY!uvfeu!vXqk7{zxZozU6J!QO&CI*w+3zw7D!o*Rbb^MX`lK#&5Ne7a-RR?KPgD4LCYmYH+e zWYyQ6u)3rpEK8 z$zDSzWb_@TaRP5K`>55 z+)krR4B2#QiA3NyPTAiYuiq9m)jhYlk(CSTJ%;n)l2uOcn_0F%{}8A{$wLSA?F|xJ>0+! zR1j>?oM-EFe>sx5(rYzqk@4q!q!=7!if$_My42R&+qK|LK_qRoI5cT@rkn9E$Jn$iSvC)9B}ieD`a^J-RJn8{#fz(4Il`Oi0n z@Miv4cp>d*n!Itp6}I%;(4BbBRXRSpIxwb~kga|vS}vT{T;^kbKWF^sS*zw17&0B~ z=YN^Sy3l1}sI5x09SVv)j%9uGx9|_a1E*RfAGoeH;&c=?!t{nTUD*cx*E=PrpL`eK zd2ezNsT2iA-x^!B#FwIp40mfMgSmQz5x0dFjs}M|0;2vLkmYj=-oVS1f9ZXy!2WbC z0UAa~+M>yCcV_%c3hbJ~Y8mPu*&HNQ$2X0tvv!W_QYj$7A1i~L0nQ7543EzyU43Y?oj-No@)s(2w_VP0x zz(&rbJ06x$&Jj7S)uFTG;0$kp>{ziU^!K9(&p+c098QRD9O8>ZcB`GsWb&;{^@l5U zT^r0~iFy?5N0;*|imkyL(@{YSidy@hPGk(bCMnK1Xt5gN(eUlw3G5JB3yaqC;j()8f%(KJjz5mg*50!OB6M&NFe}u%60az8Ai;M zPFYS3Fe~8~1GqrV1-~W%=Va!R52B$T6N^MiCY7axKmlZB9^`hcIp}TiH>^!TmYRz9 zk1ReYqXMRdkhrqw+~r7j&9-Y@;~YZmaz>}2Y;Mop&$%m4qzq_*eu7r3#4Qls4EZe6 zV9j6$h?kyz;y@fWLZ^qp96FsVZF2?R-1SACTeNhiFr=9 zVaW{nIB6|PHLwM(-?&_)d=HVe#Z|1dfmLwbHeoExlaOY?ZrI1uV=_#)I&QMe2zWuE zVOjU3Dz~awLyPJ@FIJu1I8-kXhe==WpaIEE+~yI)g06=tx#k-&C1d?L?wSH@ERdlmv8Sv*FTEAn-)#bJxOk7-acptx_k5Z z6S^>U=!giOve;&eeFfeh$-4d48R6BLb3_4oK9+3?SPK3akU}y&`{Qj6YK|d#`-=hy zJQ9A!I}<(5r0I@g5p1hSuV3iOB|bV-T|Zxk6CfS^b}7L`HOU zIIojQysw?TFlrQ(dV`0+Wv3HKGe}&llF}ci-(O>PM(W(Lc z(;%Z|%4)`TXI0saajhW4`9cy~Zri?loV|uz&P&%Q5k(C^1_`Z%w2q?1ZMA(6!XYQ7 zTIl-PL>@Wd%Obg=kFO9h+kY_pYl4drMLnI(yYZzT`_2$9ID8m@{UY zD@?>-oI#k+z5xc0-+pdcr`h)R1o9di!IT*l5br;Je8yU^V;~$wOP+`@tJv}nf1$K8 zuzFWx=A62(wb{=Z*#yXHO^b(vyovQ>I4pC5J*UFBWjJLw1jUk;NI$|vEiu|MNwhGZ zk*(KyahZ%oYpo<&MIBH}Gf&Wt8a4E_)VIZF_nSUzR`<*E#9uV5wINTN+yu$zkW6PX zpxBIc51VfK#ZEe2h~`cm-PzVE&5|nb@IJ{Ir@FCAf%*`W*!8jH0CtlsHU)9nf^>kY zsrC;$zzD06RWfHD0SZtGAOaUaH?Uy212#0dDWw2DWw`?o00AXaAc}u|;x^lspzai! z`8HTxRw7N)nOroH+v*UVD45!iCc&c+rxNDLrr-T=K)B$Obyr4b#`XCy10JJesb8Qd z)}s4I7^gN-@RIFB1oe=0ME5<64IS!I*yKz5Zd+_Bf`lKKW5hr0D@tC{=D-PlvY@u7 zFUO2!T%TnT#k-3}gaDuT6|xCy{t-n#GFzz~`vEe1jE^7IadasVj=$=SvFlh(Cz(%E z4{st`WL}Hb5#&(c5YMZ{nY9vCn29jUN}9%;nA`Pk!4@afEoNDOEfaopLyjgWykg&Z zrGDXj{s7lMH}54Q=H_?SOXaoxrHVBdjEc`~n~sR=;%?(7^zm%}6;Mc++BxDgx)}7J z?qDuDzh_Qcq1qYIQ6EfF%+|0C@0|BA4w=H4YEeP#9`*tI{38MUY<0EPNhwqJA&&3nlGZ(~gx%b|$ zfccS5IXvH;HbFWgdZ-1SAX#q3+o>y;_PDPrE7li=iA7HFdN6`yO7|}0zU99izT2FT zaOfGbR8&=6{OL=o+XzInkCI>mFuQ%l->*%&DH~W4bC~p|1#M>bJVz#{@tzp5?TEgV zF(na`b8*x?C*#NTci?GFIn&vM$ZY;)&<|n+xAco{I*83$T$n`SbB$&2mpw_CdkMMA zPCKpB8Wcug()rO#J>d!JdNHegTFkc)A&C*d58!9{a8gNH@t{2AEfRSFV#Qo+L_0^> z0zU`rl-&d!sPXmGwhx((Cuj0}YeF+#xI9NUd&ns8-XE{5zWG8}XZJblw|V{d<*ic! z#ROkHuSce>R=FYlG?B5qW+BRN3H?Nqim(}oqK!`ZZfU%qXYiQ?%0JsCjCern9acV1 z+@u8ZMID_Rh$V+`CzL3L@jMQiF)@?33eML`pAyK`{mE)ruTv-JTP8Ge{c4X(U9l;0 z$@~09fT{T7$W1>+aK26_Y6kBBZEa3Ejims6O#F#dHC{?pHnp)8SD2G!j`X)%ITQbuV(fy02GOdnsx=vH!>qY)Z}w(7|pJs4l$7MuZrj&Qj?n! z4VB}Ug-I*`1M(5tYZBCm>{E!%C;Y(WedX@JeEvuuSNGO~$aCO?VpLe^mba3Fy|xaxb=tB}e3Oah zu~lL6{^>;HS$>`^#MH)qlO)XJ;wd#3u6jQTE}>4IbIkqXqJ44?{dnDK#d@hFuC-hQ zq5?Tiap_q9(=5-abh^IPCU#L9G>A2;;Y}ztw(>?^@SBgGU$k)6!q~~iIlf3LN$8z# zYsxw?R%2S#_JG)L-0HHw4})f^0f>2&@4nk@G4Ls=9k20jzbVj2=~svOW8=NJfgm7D z(#NP|u*IXbZY0B6yP7?`!Du6k_6MT8aA{A(=~9z1JX}=GWVK7Mv~lC^0Ix-LPtH}5 z{$m4^FBn79Ca>2g|CUF1aDOlM+T`ze{@TbFY{Jl-znWQ)K6ij_Jk06#O{)9k=M*z4 zG<9|yT_>)h^TJm9LOcySm>Ex6W0)I8TtDmbbOVA{V2V}YfjK&U`nLsN`Labol=Zrl zP)>C1P74ps%9C?w&?Sl~u{-=HO&ULRY$Q74TiUA~f0OfVeX91D+ygK2AjQrgqGdf> zhluqj=oj0If57wVlh*syz_;ItR!x?DW1}dJbBa}Kmt~|F++`C>%v`nRVCY=r1rRNI z^BGh|+{q*|PVweOh45m|T#fJ=!kvX9E>^bY>m{l-na4kDqID+=F# zA_qV~V0eOp4H|>b>P{G3=|844l4CWS^~7%|VM#$7bfP2$InX;3tds@IS5N}=&anT5 zF`*Fw7@cX66?t9Gc;!?uI+}pruTO%EgCUcG9(wc^mluW+BJjb)cvJkri_?)h`SB0s zEzCXR8R6K%yG&LoCM#<{fmMB@2Do2lHy0zlV%dkLTG`&r3eg z@(%k3?wf*j8)lqJoj?3lMLq;^W^zX)TwGWMUTzgq+KWuN49W}D9oOn z0&-gAx_C*%H>eEUePs|UvbpEek~WT_HXydMsju0|9`W$ac8^HfzbrI%U+@GB!P7?O z?z#G_jD7~RO6a;-9DdUgbaRtgo%whbG;4;KozA7;K_~$v=H&-LMU6;4;BWWQh5TM43u>OP@I^-ldmx zl8Y^g$)Or4B!3tyaE|CRvsg0_J9gLJteG+PMXczvPcG)J3cRQ0t?G{1FnGhvX*vG# zb9~YJxmagQHzkQb?mWI-;yFg(T9@bOCVku?;6I5=Y&lQ>!B6@jlMEQJ90+N$Ptm6F z7c{H1k#&}^9Sm#BJs%BO&Qe{3IZhrmdR~?k>D9~Yz)JQURyV#L|z?t==3B55Xs}h-u-wVs+|&*R>s9$_5R|#8{Hr$PNUtKWdrAbB7*e z;>i*Zt%J`em)k5~fg@-C`B4XG$dLYyRwi3G&LIOetP@BsON_kxmFI-6)ePo&duc%V za9eJ0Z@JUr;PAK7f2;jn9DL6>xlDcMNUG=sgAQoxd>(u-I#eSrtgCZj;dX0~Xkn&u zRGs+u%Fq};W%?E9V}T0bEJ%9hHYQ-bX~Fme8XaPlTIFV=i51vsg;p2H@^5f2E*t0} zZ=BpTfR3@v>VDJ4eIr8-%Vzw0D+NB*ae%X+%VCAxiSAG3X^!Ybi-_^EdYOdsvQ#EFQe)7UkhN5_Reu9XrLh5>>zAg_yl1>#RGv zGi9?zclG$_S-q9krjbFI1m2PF6j#rlz>Zd}9MMIxbtC}|zDd7VRCm0VeznMP3O(cg z^o=TOORA}2=evnB@`>k>v`A~be8(g0yaN1ib=OE678I{v`SEToHV8#$F7;DZ$wxhC zg`Id(S(xLg%urMDPfNI{Af>IcPwC6=&CIz%3*h6}MnEUdTHCg~=L4&8wf4ht>F*8f zB2e6kBj5I_u4BS;&5j!4E(#X9+PQv~5+*kHM|Nq-kjZmI+eEXGaz3K^|?@}ipaRCzP z+Q)_pP4It1O^3cK!OhT^JOJI!2Jp#&65$3A&Fc`Q=j+)eLLx8qvPZt4#n&{uV>)2n z=tBNlRsQIY2ITvw&{FXKwDm?|+1GmRwn)pr^Uc=cWSrU%XwcrFS6Ul6M2~7c&FbbW zdz$KckRcqU4rWd6xuSX|PP%DyytsNpKA8A`A7N;jm4(8I^+@M1Y>vPGy?g5PV1;6m zvyGW=18hqNyGBMj)Q}JpQEYOn(o}|^IIRAnkZL6;QZu}mdx&A=5%Q;Cc1raioo#T7 z%2(#*x3fV7w33R~X`q)x=c*%vJd`?h&G-fxLqRzLTv@LC*5-8)aJRQP^Fak3N^DK|N%@uLxa71{YAO)?hff zcRyJhf$4yAo!zXi-8RChXUmT>jbTrM!Ic$)V9Rmp0#9a_*dtp{l4xgB6&~N%nVfaW zdEWEEF$@#Di6QwoEO@eSp3-4SR5bN4HjVv9vlIzn36kHIOI8e->_6R}to4-4TYpirO_bBT!Z!^$o_W?P3JgDxF?utF6H3ny{ZZ$f7E_YV$hpR=c4$_hJF zlA7)bgJtzLC3$jRtbeOT>!TKsVu#+Gw@DYh8L3$vs6U4 zZw2pqUj=KCKFB01J+ZlAgN5^x?I;zbEPMKj;S*9vjl!3?iO+u9A0(*tCX~gKERbTF zR#J?|Mgv0YLO;@NUnrsrR|r;Y2E*(!X~uXH`{z$`K0Toy1<1n1rAbpjP~$o`HhA7? zrW?Dt)ZQzTE}O!ZhYL34V_Q9!O#L_`e&-_8a^Amvsog5)3IQwcFZPwzRcm{`vkEK| zp{d5Go#H-h&GYsDJdpYd3|c#PBCo9V=Ibcct+UlgU+x-gT&puW%UirvZRUv=Xc;so zqWbNs;}KK+j3+Oj*|8zgRzIwbReVEAZ^jod>u<$e;rCH?Ki+4CJ!qXhopHan0DiyeQkv6N;&43t#0=J^iG+ftePAVO;OSXrn7rnp27ua!6ngq@L zwzIz+;vx^UKBd}(xU1~mo&BX z#zBQ}Nd}RyF%J2vJgQ&6D5Wuh`Ws?}q~XW8tJ+kN=9Hd3UfgUwy}20Hor|Gy>uoEm zt(tvkeMr!?gP)YjCf8VG7i3vTZe(-IO4v1rTxXVRfI}gw|6tUf&od`*FBVy9vGuC| zORA-B#>CG2SN8~(L#-V`A)gGP`Me`f3FT?h_vUrUmCHR1mugl^3Pju)BU)&aTi%1K zr-Bd(0aFH($)7ea5Ic;o6CHHY){e0)%+fb)WiEOsXqY}-`nBhmg16ejT}P%GQ|KJy zCzY$Kr=B&p%3H!HpZd0_hBm+Jfwsog*!OU$vh%iXK7IPJ;K3Mk>SWiL1G10~B=+e) zr0B0J3WLb*H=u+Y!GUdqV!D)LzJL0&--M89YV*n2KwkEFXHxg!z2aXr`CvsnzBn#g zW(_Ay4_T6--)HY=YCXZF#9Jcc@t;W+JEpGkl4B^&H2fGONr@NG(B((3J&}?$!hG+` zve6Z{=W$am;fsCKAqIngN6E?62VB|Nio$Je5)AAT7DuwkG}}2GgQjy0s@B3D=UyUz zerEJ!a`b=~v=5<$CSfNqEDF5ytUb9KurMjfzBZ2=TgUV|q1rifW6d>Zz^FYU^q#CC ztJea2r5kt0D2V2~0w6@AJc3RFgt@o*#PUIq=Ly-ri#pQ~Ue$GB%yLpfGYfUqe%|zI zX*auN-(9@OrdRw`1 z5ohf^mVBVk1l$_LFvDii#R{&V&spg}2k=%r2HUK%5y2k($~zVejoK~6p;(WgFrzvV zD{+Y(=bH2{CGVqFV@V0!&ttZaHc!tT@HbCeC0x`sW5KZv0`G-PmPq%gpwv z$ra`kxs2*}4%FuFsPQ6EvAlW?)6TUH-=o12CGv^9m=~;fzg%Yv)KwkwneZpezrWvc z`*uR=;pE>ekbk2oGvQ1soRi9|S78ZP04~Wp4S2hjLzz_ppx8M0bD6${L7>(#>_1uA zgZV6{*l?VTyTll);rV;Oo{D{6t-(*mFW&ozzSv_P`tU&z=gURQ3D*eXnL$`G?#pCLbHiV~4r))r)r(hP zE;8S@e2Nh!ELdAFO#K^d=e2sHQ)RqowwQ^%hLejJe9%tG$SvMqip$Tt(J2dLn^L2B zM-Wb+33R%mL!{eWe&hn#1YyZWEjtLHHD4)XpkGV9d^mo4m#4MX4Fgwvg`ytB<{lQ( z9lom4gLMwO8_4&B6|H50orw;g6?3i9RT(NE2aRyay?nfOB8|x7CsN(&mAHL}^yg?7 znnRzPD2UeOvz5rO^pIJ+w=evFpOWfnXHJP6bfM0fiiybn1HDF+c;|Qb8oBx`piF=2 zXzn7FQkig6T^EitU>+$b5G*2WfaKhMJ}j&RfYP1>Dffg|Y^ zM1Yeu@-A7E{DY+|FQW52X-nJc1zl>FD=$3*+n?T*-V3JVLNpCF3abFQ0Uj)T-%XL& zb?1h6<(#CFWXfrH3(}bSgcqvhLXg6|MM@RFO!*x zq7E8!wXuC&GmE`4PHfM+Xzi59qf^zDdh&|{_;SRJAM|vN3yurknvQZ6e3U@e2-d_l zU8`%sRc6tdu07!8C~`%=bop5Eu$h~liK=ZP(_%dF{^uxP|6#X({bma#4@uz)s95^5 z&G3q&zws!Tt*dLDhEZr|gD-EuP*UYuZh+dl{wK}2X~v{k2*if4>1%dvlfA411;eaP zkcqQ29nO9O&XKx>4PQlS%%3d+K?+!}##28Ov7p7VabwkiDK;jNYFCqAgwp=K{IA{0jK1VC$rLF;n0e4tp>i{Op-8; z%a5Vga*2Xq&PL&9I}AR-zNKBCK+{bZS*{s1d|C;ZJlR|FNgZjs;NVvK^^E zdVJgyckD!B>Tq=#-3)8Q>B2KA>Zu+7k z@Gk#EK@scv*$3$~6p4yyh=N(YdhDi#ORI73b?rntPH3-d%c^sK0*3*&m0*b=xaP!( zsQq)kOV9vr0K&!x+U~S7E2d3>Z!(jF(-7L>roX~AB#U<-PR4{2Dg3T+CM(l=_{5Hk zlwx;_HDnAFkJ32tGAB;-R0wPz#L0@J^HOp<`L_`>Rnm=wRFQz)tfs6&Fn}_HZ7%G| zONA#A?yTul^;l)Ul3hrOt%&M_R&6(su3lq0^8T1ID|g;#;yOCI$*_e;Ug}B+mcBt$ z0p+c}7jofRI$EbC9KNI)rfaA*|i6u3^``8{?y_IGsiz4FJ z)>*6WGn2#I48K$9h7n@*Y%7CY|E2tP;}S7loGDs}Ew-dWG-CPIoH|-es!G<#yRi>| zvoseYc*I3FqvETwOh4s`6Y)CDBzZqmx=@WW9Gp{+U4+0*OTfg?c44j zcNfP5qo)+sW%FTKZjkK+V&wwWjXtM``{L(*8=3)Y%ix$U2Prz=RWia(tNn|?S3o?k zJ@PqA7H&z$DrnO5s}J4wAN>AhYXP-+?%pDQWW2Y;#jOJzVm5m7F6cVju8@pc3zPI? z$9zd9gq&h0j&F}aW4B03r3<~4X`R+|d56du5IBIv|D09(?w+Y2QCeQ?c7MrUzvJ)( zT}Zc@Fm+Kn(+#xy3VeG7W^wvbsd&Hf_P4goEoC+RrW+usO4wa~>??Q2(U?q`sphmZ zh3EEIro%iB<8W*p=c)80TF1H$|K1LNtQ56bj>y#NUMe>2A2U>>bRFG?uf5NMofTBU$v+tk=@OKzp}LuawmRA z7w>$PS!Z*1-+xs`Ny#Mfdy5J=CTU?E<8Hr*D@cnkI!-7H$l@J3s@g2_OQ}7MATSm+Ru?w7kC0h>=v>FU_H<7=*=q1|M69xQBjBs* zx_FVj>jvYRY4KudNg23V$6>NKdK1wT#K(`k4u18@${21J7PwV%-{h`h(f2chqmZCh+1CFWEpTcct|XD5$+aqF``m-ao^99C)ue)CGc0;<>*tF^`c{` znzmVWA0WHrI&8VG5FqSrc3WqcCC<)+1N4of{cA~fLkI0+JWZ~(zdxGKb|17R28?-M zY*;Gv#MiXdFFmSs&q^{Y2I;+f`!Q-JjgK<2k$=hUk6MBX2=PU^Xk&N>P|jC0HCg7I$K zcA9;AEx3@ln1i@l0sBXiE!xh}nL&mp&?BPEc2i7~TJ3%gGeL7(D3#~YyZ$u0Fk-LD zM?P$y@{gi>8>fvgvp6`T{#;FI_pSc>S^!0r4lG^PGb8e7T@zcZr0t8OO|b}Gd%&A_ zR>+t%R(n^-;B$!RRby7gH=>4X`^m(65$23(Fou%qK(QEQlZpL#EmjO%5VnOavN}{} z9?KItqCRx8S<@4eK?G4+Y{yhbb&tt$IS%3k@3AT|BBsqYkv+GD{%EV4#1?l;lXmm@ zEejpQ(4!)zR9&hl%+BM)(Do1gvqR;{Qk=^xPXzIMOBH?x`6E&QK|%7^)`Dwf;Ov#;kGlN;qmRl-rEZ!T~Z@SMJQv=T@cOMaOXdKBZlQRp!5V6vde$lYe@&18ZW)YD0 zv(&N=vIy|A*edw}?FNVdd98E~*gqljaT}S<>rsFQ^-!_~yxYl=_B?JSb3E4V&)&F> zdLS2Hu~tJw=L#kP!xL=Y;h|SCh{*6T@BBNW(H6+jL!zgh6XUnEZh@3$lHEbHJg%)@ z(yzTPcpSQfFc4p4kB>x01d}Kri}FQ^jUfL3hbMAtWsTJ%KUmn=8`{^h`a{x3@3oy2g}a zW->tPaCa4&RpWcO&f|ogjV_+%_qCR1Pt-$Oy>08sNHXrBt9J}E>Y>ippXZIWD79N5!t*ipa9 zM)vL$yn$ToM(dFq_A}%SX*JT;J6Xx^a+??+)3+;4s7zwVJVbksC5epvXFcz6@ZZgJ zVUO94NAw%hqwzJqi%$sQj06)+i;2yBql3cL8C|lV57eZn$k@h$eoIdd>>j(U@|OZfaTPbD~zr zl=Eb!oz_wA;>s>NquPvzgqyShzigTttAeCVw$3r=W3&zaD~a*Mk(*TTr{a#Cdm>DG zWCn<(Z4EmyxvVitdhbP5YljhT-1*wjYq-I%i5k)3H_2vNOJ=e*=V_rZt|Zj)WPniz zfh>Dls2)f&WZ?wyYzD}N9zdgZN%$(FY@s|nFB~NPdMPku@zDhP^H;NBFKBxkzf>{{ zie2u(QpzXAB zNV_n|xQBF1*2SLKZ+SKZas+bxO4r8jCv&j8)(nFjteK82b6sG8TdzXHos(n7GY^8T zzPHUrSk}!j&Al?~s5Z|f69b&r0y*@*&qXk&3j9|M1+Aldo&DA(=bHT>=mu!cbSqW7Io3}oZJH&*DI(HGaq zcZ3u1RkO8X)({*Ex&hHu%a|~1;p~FXF?+a{(1o12vr^)YrkT@7T;fgos!~1AdsxPo z$m30D+_>}sXf#g9YTcq>mlcski)0z*e+z7Lq0Iajqv#!s(Yqsz?Nc&et>u6Kna!Zn z)G@t1`TH%?NaRVqvpb0$wus){{P>S0S+S>&lkCqHN93i^ z>vw-8%cu%FTI#m}MJvk*d9DCAUV7~90QQ3@HI9v>nicMZY4AINr0lxXkAIdtT>ULv zz=nfGeAi<9Vqo^ex_osV`IUL*nxV#MYXGI(&ZZuFu32rHB}mQd^6E?V-9CBS{rZWYg>r$_=n!Hn6xJ6bzIiF2mRgbu*!`f zPbmSrtj=&UPxv; z`arDd_9D9c(4l;0w*>jCSyBgrs<0c_+T9s~U?GlhH@4gUE39m%M>%VpeNCq=90Q0{ zhoR;IA2)^kO|nVqt~&rEV7%mhj)dRX{ndC8Uk&g)5PZU_WT`Bl#*2Y6lrSA=hHb zDj6|IB+_g*QEd+um2Kp?>WE}9)@sP~LUJwKTOGQ2 zsz_3LDh7DL_;cnzKb~u_2y>f!H__YDejf?GoXH=b&&6@Lkkd{`k>*ETuiYvt=rZ<+WYo!o4?0NsCYn)IzNvo6zd8yhmi1*)Ao$y zg|_y3A7^yGsN&+{#UL$)AlGfr%-^ZqQtgA{i@Op?KyTS-H}W2SsI&9p(y`p>EXYOh zw{oyruA``C=1DgL8p_(mkUi-vYm}^6B%>NLI{by$_5h4f0x&oDm9zR6k?hNs6J$6@ zeZI;5WneWfHq6#dFBhkh-hC4}vFl}=M{w${q>t>nGONbX&56{}?N8!pE}_F#hUz&6 zEj~c)oP7F(Oi0&6;sw=$)syW`X8>k98sJNJ9#{GM*PDrQl^%@UAVdy1ISzGL2b$Ah zLQPjg$KA)pKrQk*(VP)xGTv6X$=RN2k;*NQovYDKW^CBS%~;ht zHNT@BuRX-L04|XHaO1*3-1Am-=aD%d0zg#p0pT47qU(zMPIuT+2Nt+>zna)!JN=X& zMTut++>lS2H>PSbFc{tk4=!swv9w$r1#(~B9usO@NH{?x1q@H`2s?8`8aP<6Zj~B# zb0fG~gl5aLhbvd|o;XNBa~xa+RVsoeKahz zpa4zG@INC3lL;RIXYRFo2W#(rL z;kGOr-CK?O0O53Z^7*c^VJw-#>b!!4Il+z%JTr;yZ9;DedCCDy|(0;?5k_7-w)5{;H;0>p_6wGpl!sbX>Tw- z*E8g(M&T2Q-|X{0%k$)|#cnO|f;rtFOJPh>V|@Sxi!>2G3)@B8Um?{4iNHCdkps_l zekm*iy$)cHB$~3*qMoOQ3t!BD2m-cP{Fn@LH~;`AW$3cBWJYLS*M6%ft6>(p$Q)e) zymI^G3ZB5s{TYdD<=f&M4E%d zn*6U|J>LUkF6ieAzs9}_e0kpvCR2%U5k&V;J$Owkl7{zW5=gE`niri6kL>ogA!Cf6 zR(Oq|Ze3efs>yU}&l~*>ij9gM$fNTrRldq|)u43FY!L=x!q{8R*edZR ztsGqUL*1drG!ATy;i1i@mY~YUw)@8L*5vGgYMSH_V#?e%M=aIII8gN^V;3i+bV)^R zobj>T7^ukPggHx;evM8hr;nE47-`3T6R{r!k?j+^-qX2&ZqU)o z&?6d@Q1?tGHkYt?UC57!Kq86R8SkCt&v`qSE^JXr@;c_*(V)`t{>fGOFQk6Lzsm%)|)E^jxxgHeCa9r59Fxf)hK) z2hmHBogdaqEZy>}O*w0zBz$Nsl4yqP7)atGtzFYv4oDQKfo|EtsTI;19gqm*I^Q)? z(h=p@nFAjr#`%isfak(sl19C?#kc*Zp;t8d`|bzJTyfi6 z9p*fik7~$Hofk43W`VNuJgWZyKgmac{{XA&FgOFjCxHBX`YGg?8AAma{Ok(zREs2u zz=k!h4z_{Qs-@6NvTaruHfcEz7f#85yDC2dX8wuFeSHD>=0aG!zYQN$0TnN*JFR^hBQZ*8^OKT#R#3<0I)|pKYBMi zYBDOx~36-KY0deQ+SHI`;&UZI?8hIW-sb!K(OB7*LFH8yj|HXJc-)EeW6t_g9V12 z#U6){_f{DG9v&UV`a=T>GYj$BB+<0!^5J=vf~6#o;jtI_-BQ%F zZ9}uO9K0E2WMh8=sJHrsv(pYZ$7gm1-g}}sOpZui*T&cJG=kDOqn$s|OCRI=GTLWr z^75hrX0ld}Wy61%NAY_>4+M;t8SZ0-;6G~zmi(8WONeyMR!D31B-=@+Vu(LYe1CPL0J6A19JjTAjM3nSW{1VZ1^cx?$6vF>Mgxg10bC7@6~ zzKXt_9fO~di!X)Hytl~uACf(z;Ee5BC|nES7Wo@wo)Nuo=157pWL4-Drgm2^Se2YD zb7FDcSDI)Z-B+z?jXEBM4w(pJqlvscN2%-hsauPVcpDI*AMSDrDcVWfew;USv6Q(T zFvq|Xog?Rwu=lJ1#M@p?6`$82haXO!Miw>9X`t7VJ*fMm^FUvh$MtgYTljgb{{U&5 z5Yr_wMq2XW8D``i!0NV!nj~hKnAn zYcGZq=h1WLcQafOs8chVtBDj3!jyVGA>-mLp=-J0`p!eBZqvFihYN9_CwfDbDjHVF zGUgCL!Yl#4%Q=;ic>ocy+!cRO$-4sg9KsIM$0dWX=#(S&IWWE+De*`o08M!= zpQ8`3h(85q3{>D(UaGTp0)=fs5W$PQJVL$v)^cUU)9L5H1#G6sJTbeUB})wVG%a1o zJW!uy%-7^>x-hwOIhk)8bG2d&u;}=Bx^-1G00v{K_ff`av;_cpjn`FLF};_mx48c3 j?ui&{u7{ce*8;#U{b^{lv%`%e&fF|J@>$QK*JuCP2z{ld literal 0 HcmV?d00001 diff --git a/syng-im/images/online.png b/syng-im/images/online.png new file mode 100644 index 0000000000000000000000000000000000000000..1d5193e578586d431c0f66705c41a785b972809e GIT binary patch literal 307 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&kwj^(N7l!{JxM1({$v_d#0*}aI z1_m)z5N7lYQuzQBWH0gbb!C6RBra@es(te26`;@oPZ!4!jq_6{8S*tb2)NGg?o^!E zcPwgMgS!En-@>)M?i&}n>N6V39W+kJRg_h0VcO4|?Qx-Ly3eNiXZ}XJH+w7+U$|uR zl63Lsdf&g^I2;nR>i?3t?VTzOA~($5PurulW6wK=oM+xj`Uz<=4Z<5{dvG;If6lYC zSvMuuSN?vXrQWq|nW+u74soK)#tt{HJqb;GdXK^IgY0ARy-_(5os34+2kXCN&14j6 xIKllvwmjjR?DP}dYkb`7U%xnN_$|AJfhYBe+QV!=MWA08JYD@<);T3K0RTmfavJ~u literal 0 HcmV?d00001 diff --git a/syng-im/images/play.png b/syng-im/images/play.png new file mode 100644 index 0000000000000000000000000000000000000000..078b1e29c7e384a5aa181f39b271d3cefafcd85d GIT binary patch literal 898 zcmV-|1AY97P)MEAf?PWzRu8q7C0=X$bZ zjjGxVl;XVS+o)bjn8d)7UBk<1Lp=2L|; zxFwH!QS53mJkaquLacdjv?|QZcCZbEUJSa4~EuWHfvArHZ}Rl@_n@<0IQ$; zk|dazYpcoL6vCUE7*e!?oz)4S$s5`bVxhgh4yYjm5~X&bz2Wq_IdQkC$?wfg%mPo5 zG3lL9Ko6C44n+;Xp1k;5nFRolr}IMQ41iG(wdI{u9yft}B-`%>$yosTtF`e3+vpAF z1crU*FMu&brpAeUHx0?;HliZOP15Melm;=|zk2NP;jgMCzvDx)4jxWFD58}HDBsR_ zdW!ZFc>8_w8sEcH5KJe5m0Jc%)rH`C%Z}hZ^c>OeuMz&{OEea9$Uv!4C~|GWdn|kv zFSEDp1FQojPP1r{0eo)%e4bzt{wl|L&u@T;+Yrh7_XtmnI&Hpe3Ct_xx{?E<5yF#K ziQb$6+jcrJ=Pes%1)kmB+m+~#*NIGyVTb-nabacF5|x{Xo=SV@@BPX0l@a2<+)9t% zaKi$ofR7wM6bYk|uxlC9R{2%{9<(>yPQ}EUKt38@S%ul2ZWVS9mOb(l`bkRki+{TT zfI`n>Q?s&^^#w4O*`=J{mIC(hV~FDZ{xGU7nIupn@0N59Mc3K8!k)`xAfIK3p*Pqy z@b!j9w_wS0PGNF~9o1ODT&QhRw=MnsaTAZ#p?Ym+V!(`A`nrscCO3ruDCiwo4DHoQ zfzMs8Ir<(Za$fy!;j_DI(Op%Q|8IYywf?9W^9tzmK-r@*AqQ9n{s4YfmAmHgO_G5N)66f;rH{GCIiO-9lthz6M<028@YGhaR~nH`nov7fcLTGs!u!j ZGR%~9yu8X~Lod+L44$rjF6*2UngCN>Yj6Mn literal 0 HcmV?d00001 diff --git a/syng-im/images/smile.png b/syng-im/images/smile.png new file mode 100644 index 0000000000000000000000000000000000000000..e64022a14fcbbae4d6ea4932efb3326e5269ec8f GIT binary patch literal 584 zcmV-O0=NB%P)N0lHaVRnVA%=y6MsMZtB%L%^dg*)z%~ zhE*&ktR-0#oY@=%K-cIik2WlOJ&CvRZxVY{Z#)W>+v=blc?DVn+OaMQfS-)XX(9;r9?&}1Nr~31#u_6`)BZzwr><0<= zF-@_!dyZX8IWm?98wGltxR)x#ga1H=Ch>c50000js {:view-id :chat}) + [navigator {:initial-route (clj->js {:view-id :contact-list}) :render-scene (fn [route nav] (log/debug "route" route) (when *nav-render* @@ -40,9 +41,12 @@ view-id (keyword view-id)] (init-back-button-handler! nav) (case view-id + :contact-list (r/as-element [contact-list + {:navigator nav}]) :chat (r/as-element [chat {:navigator nav}])))))}]) (defn init [] (dispatch-sync [:initialize-db]) (dispatch [:initialize-protocol]) + (dispatch [:load-syng-contacts]) (.registerComponent app-registry "SyngIm" #(r/reactify-component app-root))) diff --git a/syng-im/src/syng_im/components/contact_list/contact.cljs b/syng-im/src/syng_im/components/contact_list/contact.cljs new file mode 100644 index 0000000000..7bd7879948 --- /dev/null +++ b/syng-im/src/syng_im/components/contact_list/contact.cljs @@ -0,0 +1,104 @@ +(ns syng-im.components.contact-list.contact + (:require [syng-im.components.react :refer [view text image touchable-highlight]] + [syng-im.components.resources :as res] + ;; [messenger.comm.intercom :as intercom :refer [show-chat]] + ;; [messenger.components.chat.chat :refer [chat]] + )) + +(defn contact-view [contact] + (let [{:keys [name photo-path delivery-status datetime new-messages-count + online whisper-identity]} contact] + [touchable-highlight {:onPress (fn [] + ;; TODO + ;; (show-chat nav whisper-identity) + )} + [view {:style {:flexDirection "row" + :marginTop 5 + :marginBottom 5 + :paddingLeft 15 + :paddingRight 15 + :height 75}} + [view {:width 54 + :height 54} + ;;; photo + [view {:width 54 + :height 54 + :borderRadius 50 + :backgroundColor "#FFFFFF" + :elevation 6} + [image {:source (if (< 0 (count photo-path)) + {:uri photo-path} + res/user-no-photo) + :style {:borderWidth 2 + :borderColor "#FFFFFF" + :borderRadius 50 + :width 54 + :height 54 + :position "absolute"}}]] + ;;; online + (when online + [view {:position "absolute" + :top 41 + :left 36 + :width 12 + :height 12 + :borderRadius 50 + :backgroundColor "#FFFFFF" + :elevation 6} + [image {:source res/online-icon + :style {:width 12 + :height 12}}]])] + [view {:style {:flexDirection "column" + :marginLeft 7 + :marginRight 10 + :flex 1 + :position "relative"}} + ;;; name + [text {:style {:fontSize 15 + :fontFamily "Avenir-Roman"}} name] + ;;; last message + [text {:style {:color "#AAB2B2" + :fontFamily "Avenir-Roman" + :fontSize 14 + :marginTop 2 + :paddingRight 10}} + (str "Hi, I'm " name)]] + [view {:style {:flexDirection "column"}} + ;;; delivery status + [view {:style {:flexDirection "row" + :position "absolute" + :top 0 + :right 0}} + (when delivery-status + [image {:source (if (= (keyword delivery-status) :seen) + res/seen-icon + res/delivered-icon) + :style {:marginTop 5}}]) + ;;; datetime + [text {:style {:fontFamily "Avenir-Roman" + :fontSize 11 + :color "#AAB2B2" + :letterSpacing 1 + :lineHeight 15 + :marginLeft 5}} + datetime]] + ;;; new messages count + (when (< 0 new-messages-count) + [view {:style {:position "absolute" + :right 0 + :bottom 24 + :width 18 + :height 18 + :backgroundColor "#6BC6C8" + :borderColor "#FFFFFF" + :borderRadius 50 + :alignSelf "flex-end"}} + [text {:style {:width 18 + :height 17 + :fontFamily "Avenir-Roman" + :fontSize 10 + :color "#FFFFFF" + :lineHeight 19 + :textAlign "center" + :top 1}} + new-messages-count]])]]])) diff --git a/syng-im/src/syng_im/components/contact_list/contact_list.cljs b/syng-im/src/syng_im/components/contact_list/contact_list.cljs new file mode 100644 index 0000000000..31f4f6ecf3 --- /dev/null +++ b/syng-im/src/syng_im/components/contact_list/contact_list.cljs @@ -0,0 +1,96 @@ +(ns syng-im.components.contact-list.contact-list + (:require-macros + [natal-shell.data-source :refer [data-source clone-with-rows]] + [natal-shell.core :refer [with-error-view]]) + (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] + [syng-im.components.react :refer [view text image touchable-highlight + navigator list-view toolbar-android + list-item]] + [syng-im.components.resources :as res] + [syng-im.components.contact-list.contact :refer [contact-view]] + [syng-im.utils.logging :as log] + ;; [messenger.comm.intercom :as intercom] + ;; [messenger.components.contact-list.contact :refer [contact]] + ;; [messenger.components.iname :as in] + )) + +(defn render-row [row section-id row-id] + (list-item (contact-view (js->clj row :keywordize-keys true)))) + +;; (defn load-contacts [] +;; (intercom/load-syng-contacts)) + +;; (defui ContactList +;; static in/IName +;; (get-name [this] +;; :contacts/contacts) +;; static om/IQuery +;; (query [this] +;; '[:contacts-ds]) +;; Object +;; (componentDidMount [this] +;; (load-contacts)) +;; (render [this] +;; (let [{{contacts-ds :contacts-ds} :contacts/contacts} (om/props this) +;; {:keys [nav]} (om/get-computed this)] +;; (view {:style {:flex 1 +;; :backgroundColor "white"}} +;; (toolbar-android {:logo res/logo-icon +;; :title "Chats" +;; :titleColor "#4A5258" +;; :style {:backgroundColor "white" +;; :height 56 +;; :elevation 2}}) +;; (when contacts-ds +;; (list-view {:dataSource contacts-ds + ;; :renderRow (partial render-row nav) +;; :style {:backgroundColor "white"}})))))) + +;; (def contact-list (om/factory ContactList)) + +(defn get-data-source [contacts] + (clone-with-rows (data-source {:rowHasChanged (fn [row1 row2] + (not= row1 row2))}) + contacts)) + +(defn contacts-list-re-frame [contacts] + (let [contacts-ds (get-data-source contacts)] + [view {:style {:flex 1 + :backgroundColor "white"}} + [toolbar-android {:logo res/logo-icon + :title "Chats" + :titleColor "#4A5258" + :style {:backgroundColor "white" + :height 56 + :elevation 2}}] + (when contacts-ds + [list-view {:dataSource contacts-ds + :renderRow render-row + :style {:backgroundColor "white"}}] + ) + ])) + + + + + +(def logo-img (js/require "./images/cljs.png")) + + +(defn alert [title] + (.alert (.-Alert js/React) title)) + +(defn contact-list [{:keys [navigator]}] + (let [greeting (subscribe [:get-greeting]) + contacts (subscribe [:get-contacts])] + (fn [] + (contacts-list-re-frame @contacts) + + ;; [view {:style {:flex-direction "column" :margin 40 :align-items "center"}} + ;; [text {:style {:font-size 30 :font-weight "100" :margin-bottom 20 :text-align "center"}} (str @greeting " " (count @contacts))] + ;; [image {:source logo-img + ;; :style {:width 80 :height 80 :margin-bottom 30}}] + ;; [touchable-highlight {:style {:background-color "#999" :padding 10 :border-radius 5} + ;; :on-press #(alert "HELLO!")} + ;; [text {:style {:color "white" :text-align "center" :font-weight "bold"}} "press me"]]] + ))) diff --git a/syng-im/src/syng_im/components/react.cljs b/syng-im/src/syng_im/components/react.cljs index ac65dc7a4c..18ea53dd47 100644 --- a/syng-im/src/syng_im/components/react.cljs +++ b/syng-im/src/syng_im/components/react.cljs @@ -8,4 +8,43 @@ (def text (r/adapt-react-class (.-Text js/React))) (def view (r/adapt-react-class (.-View js/React))) (def image (r/adapt-react-class (.-Image js/React))) -(def touchable-highlight (r/adapt-react-class (.-TouchableHighlight js/React))) \ No newline at end of file +(def touchable-highlight (r/adapt-react-class (.-TouchableHighlight js/React))) +(def toolbar-android (r/adapt-react-class (.-ToolbarAndroid js/React))) +(def list-view (r/adapt-react-class (.-ListView js/React))) + +(defn list-item [component] + (r/as-element component)) + +;; (do +;; (def activity-indicator-ios (r/adapt-react-class (.-ActivityIndicatorIOS js/React))) +;; (def animated-image (r/adapt-react-class (.-Animated.Image js/React))) +;; (def animated-text (r/adapt-react-class (.-Animated.Text js/React))) +;; (def animated-view (r/adapt-react-class (.-Animated.View js/React))) +;; (def date-picker-ios (r/adapt-react-class (.-DatePickerIOS js/React))) +;; (def drawer-layout-android (r/adapt-react-class (.-DrawerLayoutAndroid js/React))) +;; (def image (r/adapt-react-class (.-Image js/React))) +;; (def list-view (r/adapt-react-class (.-ListView js/React))) +;; (def map-view (r/adapt-react-class (.-MapView js/React))) +;; (def modal (r/adapt-react-class (.-Modal js/React))) +;; (def navigator (r/adapt-react-class (.-Navigator js/React))) +;; (def navigator-ios (r/adapt-react-class (.-NavigatorIOS js/React))) +;; (def picker-ios (r/adapt-react-class (.-PickerIOS js/React))) +;; (def progress-bar-android (r/adapt-react-class (.-ProgressBarAndroid js/React))) +;; (def progress-view-ios (r/adapt-react-class (.-ProgressViewIOS js/React))) +;; (def pull-to-refresh-view-android (r/adapt-react-class (.-PullToRefreshViewAndroid js/React))) +;; (def scroll-view (r/adapt-react-class (.-ScrollView js/React))) +;; (def segmented-control-ios (r/adapt-react-class (.-SegmentedControlIOS js/React))) +;; (def slider-ios (r/adapt-react-class (.-SliderIOS js/React))) +;; (def switch (r/adapt-react-class (.-Switch js/React))) +;; (def tab-bar-ios (r/adapt-react-class (.-TabBarIOS js/React))) +;; (def tab-bar-ios-item (r/adapt-react-class (.-TabBarIOS.Item js/React))) +;; (def text (r/adapt-react-class (.-Text js/React))) +;; (def text-input (r/adapt-react-class (.-TextInput js/React))) +;; (def toolbar-android (r/adapt-react-class (.-ToolbarAndroid js/React))) +;; (def touchable-highlight (r/adapt-react-class (.-TouchableHighlight js/React))) +;; (def touchable-native-feedback (r/adapt-react-class (.-TouchableNativeFeedback js/React))) +;; (def touchable-opacity (r/adapt-react-class (.-TouchableOpacity js/React))) +;; (def touchable-without-feedback (r/adapt-react-class (.-TouchableWithoutFeedback js/React))) +;; (def view (r/adapt-react-class (.-View js/React))) +;; (def view-pager-android (r/adapt-react-class (.-ViewPagerAndroid js/React))) +;; (def web-view (r/adapt-react-class (.-WebView js/React)))) diff --git a/syng-im/src/syng_im/components/resources.cljs b/syng-im/src/syng_im/components/resources.cljs new file mode 100644 index 0000000000..7403226612 --- /dev/null +++ b/syng-im/src/syng_im/components/resources.cljs @@ -0,0 +1,12 @@ +(ns syng-im.components.resources) + +(def logo-icon (js/require "./images/logo.png")) +(def nav-back-icon (js/require "./images/nav-back.png")) +(def user-no-photo (js/require "./images/no-photo.png")) +(def online-icon (js/require "./images/online.png")) +(def seen-icon (js/require "./images/seen.png")) +(def delivered-icon (js/require "./images/delivered.png")) +(def play (js/require "./images/play.png")) +(def mic (js/require "./images/mic.png")) +(def smile (js/require "./images/smile.png")) +(def att (js/require "./images/att.png")) diff --git a/syng-im/src/syng_im/db.cljs b/syng-im/src/syng_im/db.cljs index 2859bd43cc..1369ed6fb5 100644 --- a/syng-im/src/syng_im/db.cljs +++ b/syng-im/src/syng_im/db.cljs @@ -6,7 +6,8 @@ ;; initial state of app-db (def app-db {:greeting "Hello Clojure in iOS and Android!" - :identity-password "replace-me-with-user-entered-password"}) + :identity-password "replace-me-with-user-entered-password" + :contacts []}) (def protocol-initialized-path [:protocol-initialized]) @@ -14,4 +15,4 @@ (def identity-password-path [:identity-password]) (def current-chat-id-path [:chat :current-chat-id]) (defn arrived-message-path [chat-id] - [:chat chat-id :arrived-message-id]) \ No newline at end of file + [:chat chat-id :arrived-message-id]) diff --git a/syng-im/src/syng_im/handlers.cljs b/syng-im/src/syng_im/handlers.cljs index 859aa85a44..24c4ff176e 100644 --- a/syng-im/src/syng_im/handlers.cljs +++ b/syng-im/src/syng_im/handlers.cljs @@ -7,6 +7,7 @@ [syng-im.protocol.protocol-handler :refer [make-handler]] [syng-im.models.protocol :refer [update-identity set-initialized]] + [syng-im.models.contacts :as contacts] [syng-im.models.messages :refer [save-message new-message-arrived]] [syng-im.utils.logging :as log])) @@ -49,8 +50,14 @@ (save-message chat-id msg) (new-message-arrived db chat-id msg-id))) +;; -- Contacts -------------------------------------------------------------- + +(register-handler :load-syng-contacts + (fn [db [_ value]] + (contacts/load-syng-contacts db))) + ;; -- Something -------------------------------------------------------------- (register-handler :set-greeting (fn [db [_ value]] - (assoc db :greeting value))) \ No newline at end of file + (assoc db :greeting value))) diff --git a/syng-im/src/syng_im/models/contacts.cljs b/syng-im/src/syng_im/models/contacts.cljs new file mode 100644 index 0000000000..8c7bfab55b --- /dev/null +++ b/syng-im/src/syng_im/models/contacts.cljs @@ -0,0 +1,83 @@ +(ns syng-im.models.contacts + (:require [cljs.core.async :as async :refer [chan put! !]] + [re-frame.core :refer [subscribe dispatch dispatch-sync]] + [syng-im.utils.utils :refer [log toast]] + [syng-im.persistence.realm :as realm])) + +(def fake-contacts? true) + +(def react-native-contacts (js/require "react-native-contacts")) + +(defn- generate-contact [n] + {:name (str "Contact " n) + :photo-path "" + :phone-numbers [{:label "mobile" :number (apply str (repeat 7 n))}] + :delivery-status (if (< (rand) 0.5) :delivered :seen) + :datetime "15:30" + :new-messages-count (rand-int 3) + :online (< (rand) 0.5)}) + +(defn- generate-contacts [n] + (map generate-contact (range 1 (inc n)))) + +(defn load-phone-contacts [] + (let [ch (chan)] + (if fake-contacts? + (put! ch {:error nil, :contacts (generate-contacts 10)}) + (.getAll react-native-contacts + (fn [error raw-contacts] + (put! ch + {:error error + :contacts + (when (not error) + (log raw-contacts) + (map (fn [contact] + ;; (toast (str contact)) + (merge contact + (generate-contact 1) + {:name (:givenName contact) + :photo-path (:thumbnailPath contact) + :phone-numbers (:phoneNumbers contact)})) + (js->clj raw-contacts :keywordize-keys true)))})))) + ch)) + +(defn- get-contacts [] + (if fake-contacts? + [{:phone-number "123" + :whisper-identity "abc" + :name "fake" + :photo-path ""}] + (realm/get-list "Contact"))) + +(defn load-syng-contacts [db] + (let [contacts (map (fn [contact] + (merge contact + {:delivery-status (if (< (rand) 0.5) :delivered :seen) + :datetime "15:30" + :new-messages-count (rand-int 3) + :online (< (rand) 0.5)})) + (get-contacts))] + (assoc db :contacts contacts))) + +(defn- create-contact [{:keys [phone-number whisper-identity name photo-path]}] + (realm/create "Contact" + {:phone-number phone-number + :whisper-identity whisper-identity + :name (or name "") + :photo-path (or photo-path "")})) + +(defn- contact-exist? [contacts contact] + (some #(= (:phone-number contact) (:phone-number %)) contacts)) + +(defn- add-contacts [contacts] + (realm/write (fn [] + (let [db-contacts (get-contacts)] + (dorun (map (fn [contact] + (if (not (contact-exist? db-contacts contact)) + (create-contact contact) + ;; TODO else override? + )) + contacts)))))) + +(defn save-syng-contacts [syng-contacts] + (add-contacts syng-contacts)) diff --git a/syng-im/src/syng_im/subs.cljs b/syng-im/src/syng_im/subs.cljs index 9bacfd9e3a..9fcace1759 100644 --- a/syng-im/src/syng_im/subs.cljs +++ b/syng-im/src/syng_im/subs.cljs @@ -6,4 +6,10 @@ :get-greeting (fn [db _] (reaction - (get @db :greeting)))) \ No newline at end of file + (get @db :greeting)))) + +(register-sub + :get-contacts + (fn [db _] + (reaction + (get @db :contacts)))) diff --git a/syng-im/src/syng_im/utils/utils.cljs b/syng-im/src/syng_im/utils/utils.cljs new file mode 100644 index 0000000000..964878c4cc --- /dev/null +++ b/syng-im/src/syng_im/utils/utils.cljs @@ -0,0 +1,38 @@ +(ns syng-im.utils.utils + (:require-macros + [natal-shell.async-storage :refer [get-item set-item]] + [natal-shell.alert :refer [alert]] + [natal-shell.toast-android :as toast])) + +;; (def server-address "http://rpc0.syng.im:20000/") +(def server-address "http://10.0.3.2:3000/") + +(defn log [obj] + (.log js/console obj)) + +(defn toast [s] + (toast/show s (toast/long))) + +(defn on-error [error] + (toast (str "error: " error))) + +(defn http-post + ([action data on-success] + (http-post action data on-success nil)) + ([action data on-success on-error] + (-> (.fetch js/window + (str server-address action) + (clj->js {:method "POST" + :headers {:accept "application/json" + :content-type "application/json"} + :body (.stringify js/JSON (clj->js data))})) + (.then (fn [response] + (log response) + (.text response))) + (.then (fn [text] + (let [json (.parse js/JSON text) + obj (js->clj json :keywordize-keys true)] + (on-success obj)))) + (.catch (or on-error + (fn [error] + (toast (str error))))))))