i{F. 節t,Ryiqd8 7fD $H@Iy}%EjUk?+bͳg3.i8ک\~];U[nl)oh)!z7$]k7O9+Uq*Wnug\l/r$A]OҮ_V[ l(/GK!{#X&vB\_W9)okyj]SS5qW] oWsAZ䞼AZO~)< 7}T>x,.M™Ym\ӸT3JǺtLi%Nʶb/>W]Ǯ0WY$נJqX|Om~ϟ^>Tx4_ހr } ~s]eVhև#[m7A|?}>4|xy~zz^ZoJzZ|B3'o_Z7^퓗?ek|!l_'gM+yjI7hnj |v6`ΣwEQ&׋G7MƯiDBijJbYz^ɫgfykPݽv0uwW'|I‘vvl6 >_}u<-|iZ_2~5,ÿq#|xEXo[}ۛij?_5>Y_im%ׯe/X؏k_^o˛@ͼ7?py7oDϟ?uQW=X[ԛoσAQ6V)7)e;I@OA' nod)?"ap,p#:(\צO|J9ѓpa_/߿]۠l2h)wt__/Q\U7Vzp_ȕu34+(`~~ N3pK~ hokMY΍io_o?DdDzۘ.nO(TUDPמh]›|HoOC~>wխԋ]SU&W W,mG {'_1}ѧݾoP[Ho_K3z|]wg~KV6rr\Ewp퇏yaDDOOo?Ձ𥂛rҊ.k-&m:'GT:T^cݓʂM!$6xcD ×ɿӭh.ۛϷ]$~k4x܌O~.-Tˏo$~>ib/h>-k{K)^R_fyK׏7A+d{qׯTۓU7]^: <]VNM5*6L"Lb"l/xZ>ۏayy[_^KDrwAR_&ɷo( ת)_~|;|l|&_~O屺]{P)/e W_3~U2ߟ?G}=CoAܔ7-) }#>{7.n军hZG~~}LJ'oߣ\% @]ؿ,_~Ŗ~y kg|`~.Fm0H?X)4_נ%rKAO^H?8^Da1?Tp9D$}W8٣Nßz6]w1z ٠kH-V_7^?~|  6kܾrqO/s;|K_Bk_9$ߟo^/O?痿OP6sd.VJz?1՚| ۷oQ%B/oW ^[?~<|(~kGȴ@e߀syޗU8)^<={ti7n eqṕolkPp:} `ZS̾)Qk@مgD3[Hsp{x د~?W6?+Nu͛W]=#R3篊7#~y~3~GN{ԯ-\Es=<7F3:"tdz ̯d~ nG~u7@ !O:_~`@?@ .cۛ@M-tu {an ؓ7K4b /!R_YnR[GDl7I1qdH!j^@%XA?͛~3[dm}F֭U<._j7OqBFH+ҡC9ᯗQg>~G80-2x $ؗϏAm@'䢉#^^o_‹\߫_-uΘD׍|0?"hxo= ȲN]/@eON'Y3(7c!9¼˷?i?ޜ?a/P{z˷oXȭa7'"V?_EWq—7+/_܄-FO=y3+r|=yI'c>o2&!{7No} B_YojTXo}wP_@O MYs$ 틯0an{s;춸r9:臘Et1cය?XqHOӃmp#jO [szyo/؏?~_> ~z ^yP+٧'+R`) .ۦc!Hq/{AY09'D\F^0)@o5W3`?[z .OMGooUH ^y N&^ݽr}@Sc&_̛e$ոiTY3[[S3@Znjo~<@tipnU*C_|,fu/o??)U Lq}|({FC?P_"xA @<0%0ݿeB>~A8)^" (V@ Dճ[ .t_6m Y`={޽u}ef!XN+<}|5"|Q>#pOB*9>`bQBc(g γ RZ3VРp {:3EaTNژ3| D.xTƉBͣ7t|?_ү2y5cඁ|3jq=VO_ӯ~_K"Oo&m" c+ï>a~&o_+8}~z&܂~?_߂z~yz6+isXG6=+/`-c ~ʯ߀_9.`o~?ƀݷkءG_!=8]W?g g~{ ~i_ruJoYegs,fKVwE^]˹i<*^]'Y|<(z_0F{hb~h`o \N~Mk#Klջn6j㵊W4wymDUhIGKJtOmdS8eõb4pTHpثfM)U$yJWk+DWئIjI}`2s+h9g_vUgp:xݬfq{ã).@^~3NF"FzFϳon߹gA>Jvm|^!5a`絿>qR*xi˼e -@}fBMA(UOq&NZN[  zzÛW5J`*P_kQeOx_(lټNk8JdzXf8UOI1G3!/.fn`ۓt aǚxA'`ZbT6Ev'Yn"Jt8`;I|K83;'oֲd]64/ ! 'AY\ۦ*ڦ߁{/w7~v7?Î<.~{Wo?/ծ-VRrdC>j<2K~hDxʋ8 'ݭ``k9MW綷cݱ>8NW*MU\&]Iq<+vU~&;.<&~cZEyE(. K1LsHºd#jMRͧǻү*A۠Ks(}pk@1\P*~G".LKpHS71[m"Y*J0{9h5 mc@ ٟ8bHgcĹvJZz;q N!B%C \h+Bz~>{HTw)Ɋ-ð[`&^h2'otlwd :pd^'oj6VR;"XV]Cb1NJXR#Q2#T8g! v@%=N5Uƌ:tMA>\ϣX }${$2]UĆ+&G+a܌uO,^3PuM$v&k*~kh'P@ZPuzՆL!/EУIVxuT~@mC m\KorxmN.c;aw/`&Ww4!=/"D o H.@pL}eu3Fp%56Z ֹ_~5cNN &5I61}69+pL6I5$S(_6~!F*vkYމd ϊN`{z rs`q8}kc ,6/k|U2My-߾׃jt2Љ>vV 'n9aVȑ0;GQ:ޙwUd6[ӭj6Նa}jD7W·.4U7Ppº =0/ 2Eȥ} ,EV넬~b`EHV7<:cSmYy1yY:t8Bh…jҐ;9cˣ4ÚGl\%y(IyYp [ax%KLݸetJKc ]*H{ЛS; , >T[X/ٌ=\y #rg/@I8$Gw ڣ~(Uj"HH~Mր4@›IKn}*cbv۬KMg, +I!m\H2;~BaT1xq\qGE*O˰I f}̛y V(僵nW&0U$kךoJzb\wW l|“_d8P epN(]h9d+1!pǷ <ÃM8hd**BxqryPXzw[[tuD5ॅGalxRq}PgYd** ҫJ,-uNΌ|׎*<"dnGN_;Dy,s-S[;lQ5[a`Rdqg0;W+(ymsK8f-%b\äs"\XS U  Mm9+2%TjrLS~5Z_HK dej uѫuFlL녹qfL::9NDukQ5'e6lFs 00 NpLiz O]SiN]Jvͯ,9 uԤNfljyIw9s2r]iQS4 68ϳ.sb b)se.wte,af s*:ނP;cMĎ`K ǚP,{Ep_oB0}J?~w~jЯ [5onSe[yGi }E"wQ5`{Iϡ[ yaNu9ZMȮ"Ah`3/O%Aiܭ_S5B|&)(vtr6>UIߣɵ?eiycE !kYfND :8ch'E}dX+a{C m1(^Uv#5w˻k5c ՘1,)#.vkpU;C?1g.x$!WDvSQS #ҍ6>`L d L2S +|vͦX:Lg 8& `iCZ]ױByhmwIԙuݚC;xD.B %̓fōJו%!&o!yw!וOPN]z$uA mp\iN:ڂ_NL Ղ{(/UҠ%G鎗L] X8 -ԈBWwy#w<徣L*&P7n0tILwQQ`yMFlp2$9y,G_w?*V?j;l *1y~i@8y{Qmwm<p!t&cnuw[D[ ~Zd/J޿Ɔ7A/rP8=a}{7وq. s6 Rgll 8C!";1vqyq%ާ| /sg6[EKNF|kRc ik}}(~ Z*(Ek֩HK26S"gna *=Y0` 8h]+0>EV0TO0np#PniNOj`3N"= :u!"`I@*Ǐ :'76| "O0 !'/~_h*F'%2/*qD($ Ϙ;t踗A@׬4'-TќASu~I)"Gn\D~yU5~2oMX&<{TRSG5:0nX#dCzRf+16~V7e%&k:\REYe~UűPKzmܘ/ZvNSEĸ,~ ^9ËюL!B܆'cwݢA8DɅH L4o =odN.b1rkZ@gη~FMg˸vG~SׅhP~ǃKSO Uh u#o\lSZ5/ $* C ($3 q@O\^:7xsprG<xW$ƅVY9bɁ̄):眇 m FdIE4m/8+p{vm1[ N kWuP*;49^ŤhnV5I+ֆ{O t.3A⠜&Fdp<#[Q]N݇4QG ׻/ŎZ2IK'U e BT̾ @{cڲԿ ?3te0a 1",R0KHF-׋;gRRCY?~H$ )@qJ:0z:Rܱ{ԥHwM-M.^_;Rr}F GL_1v4. J!dkć eDCb _\Ithc霉WIl <`sd=̫ח="kr|NSe;|+u~}rU_bRxPo҆*q^V~rCzJcQ}V~йtwz2^ൽ=agp 63a^hs.7D0ܗZ~F六JЪw$m(yl*3*5򠷁/ingn ` ٨d7.] \!_:|r5* ΖOW~7oic0.>*WբNdꄩy$] %3SnԗSN# Lq.ı`#@ Iݸvy@~Jצ'h5(Tk̳Bjx zV"[%l/nF4-hvFo5%?v67Ac`C屘f@311j=}-H3x d`);dyʑ=RrƛEsfq;4Bͱ񭝣m<^/f~ij(֎_t.㔛4x }^Ő| _A˞&%ۀ[O\@BL#rz{L]N4IϮ:7TRC!Y:&vyܐ D䈉')5M|wZ^' /WQa%Tb W:/ Y!)p kzk9 #Bk#a$1Q.sk2o499Z+k'r>oyT qF@G&E|1?7W(H&n`TTwJ(Dʫ'sEr_;g3cA 8 lh`LT:˧٨QePwo.罪 J ;ѡXg~[Ż1=&ĺ8 TJIVFPgbg$jp ZB"-ukZS Has7;H蕄@ȺbjOGp=9(Hnsy\ (/{Tx,Ϳo߼}۷.R<04윁zev܏3U||pa`Ry 7jL_AGv^}}nJIm 1ZϞHu4ϰX-0zlk!kμVw`vʝI@OJ{Ռ E dsJ80[}!s72w1ԒNb) RWEO? O;EZ^Sz2-]*Xķ䁖 ];2q.`ME@0^C*ZժFjj,0+Ăta{1 n|M ׬ChQzxo!=tϰ%:iyc]](䆀FVL(+ *㰩N}Q's @{=I|^By^ISE0&lЏe:59GgEWl6 !&=Į t )k|q;%a(nnYu|",{kfڮA/:b"kM|$i`lm&0wP-lEb#f RgGaU '9<塠mQwġP(]򍐒٘+Lʔבꬮ`a@Bl M N @CeDppϼhzp JxN|?ھrH'Jy"%&>Fu/h9nnMs` juY0{b "q]82W9¨^_EpP$3%1 On0ΠrC=aulX$hZd&{/3s`!I5Ho <顝4b^ZfQ woe%2#anfQ.6q1J 2Z U ^Kԍ+YEh0xİdӰ()Rzk;6(W}ȠFcy$L W̥eq_{L>Aq)}ETLv; zw*o">mudf B$d&զ!͎}.ۈl;'=>xN5UjvZ(+b/opN`q)hM>R; RKvʢ bS ԝU{HuS&5 1vƴS Q#do{J X'f l.H0cdRَ#^\sW~}1Cuia4%W7j?Qt0~|vN9; 麍VAޱAȯ}&~41p?=030U.`0? *&cz6I&řwZ͓G=wAB4y&w7vЙnHH4Pb!"O8qW632f.6sb?pS0 Cg O83LlxlQf}X`3*+?C:9qUBSswux0[QmgHK@r{GR\+͜XV;MTֺz6v$`k]K"94lIpr"9oQ- 0 Nmlg .Z4<;R?kc ֱvb8rlmuQ*\xyKDXq 4͏jQzd űȕ@tT g Kt;]ƿy*vJ< Mנ'jл܊@ag4YPhYx<&wal yNQ!eiMy51z~xY +ˎwQ:4>y(PFoʿ2!c~;c_$AX)AȻTa"Xb*d݋"oW@P.%PKR1Q>'kzCh§{?b)ze!h3nbd>p} <uy*i$ a zu=OW2- p2уު+Π;U,@4HÆ )bP~8ǮГ+`F0o0Gg^ r0Cݔj&iH)L!| u&qxJ 9H)DIZC\ϋf[%9eV]%tDl{݆>p> sCHu! WQ7c 9BS;t\>,T=X[D;0§eGuI{" =R?\)M: BZk&E D:myҤYEeaƆ]2t^;;5hĝL8:jbl;s&`H4o*–yP+zmꧠNw'7t=wz#'锭5.Tz(`˻S$GK٢t:,`|(v>73ux\ׇsp6c3'o|G^'c'pOG:q(-pz~wJ$Q' 9'-腀DNwpr5ƑQN0DH \睤5)5g\M+e:~'X4abs^[a* G!qȠɊ×~B僬}$Q~ԩ빗u˱أx%ʭj;8)E`eMFOOSQ=``D4ʀVҘOh [&Ѧ`_Lr [wx `)MHR!(Gib6=CDO( f c>Fq1'ZbM7PDt1k18ܭS"q6 ~E~\WHxX_7jPׇ˝usWfTlK4Asul+Nf8!YZyl 2܋`a MoBGyZm\ˊ#ƴKgĤwzlL;᭯Ecp~aHTes&;Ӕu \7*k[*5rjX iJ@70Ob!n-M >ēAZ˲Giܒb6$2τ8M;} 1k0ݪmcl zW%wR@me%RH`T!oeO #YVbfգ4W'p: b|g`25BOޔZ ٥QBf2_=hIsv ]ͫ{IeC7Y&1Bwot*M5WdQ ƯkxR;YL_bz"1dYwN>3Zn@ 9|[7,̡X@HdJag.|<ޜERt8TfNۀCO=![nQd>)56WQm^Nl/$2XSWlиD"t,# +c* ޽BIAm8 gsGrL+n h^ڡ^kwrcr0@plG|HsHk:Ho8W pB;ۦKzeL$5nf^`GY$IKz4ԕdS; ?c)60l_BGEyӑ0 =F[V{de*XMNi?Пɗ &*ώbJBď;n9P Rv0 ]4# $#0qiC4QTҝq~B'|'Ϋ΀;i<β%u (=:/8?w6?{= nzO#g3׺*&Uum=k&?2@d qnL[r#UL)Txe5$[U +dl;'@~B ;OLy$<]hnStwz#l:g4#jhx 62 19ۑzl,MO: 6"XPYwԖ>&X9rsAv굸)#]#b5k.ZT)sip<)98aHf "C݉0.8Ov|p+ ,LglyGtkkWAwyȍ8lSPST/XL>22ME/$ ;kYY0Bs<|Yg4=)'NrBgcy+CkqZjNhDfi 6&yB~t ءq1"d ܖdHi"@,w\? eL>ۻ鏉#6&cDh1wۄNq];8'*DM }gaL,B[7]]0 byau${:5( ,-pMʹeEG%zfsU7Ut4|VKs7ӫ:r=}Wfw a-@D 5T;@ۜ-Qq1 U5w[ge('ȧFO>U G4'(_@q_=2t!FzHDŽMͲSQVMn*{CpEۿmX: ;e{Nz펻6砫=pp 5#'vy.bi'>ڵzh猥8Mʠo}N9.h$$x@v)0{eΙ&7.9& ?Ϥ4=`%#~=(V^U)*=/NEo XI h6V?J9ĬŇ&+434_T+ܝ:jd%Uu"F6NUs7DbǞ xX̌Gx +/S!|,lDZ[Mc Zm sĖ|A>8=14 hośV5FY%5lmX{Td/IѮn(.=s ;tL3o%yRlFL9F 9EU0͇^Qi:blME0¨=VJ9\`ڌ=z?;|,#$=7iYl/XpD0mk9 " b/ +{. z555R+V:d󆛯 &14Metf*`7Ȱf ႛvt4S taJU&rD6PXQ8`ʦ7$MD)68@q?O 2w,gC8# S׫?hpl;Ti'H@ٔPf{=&QY>#rUmjҐf¼@w4ۼTy7r$VIN띿xأ cB%sus PQ-UYZ3^1#,< ;}%>Q$\V.+ ̎)ԷYQZ̀w8úH.< xt=kf@,+ݰzvp0w[ NCG\:hٺ0|QDi3a &Q2sL>`}|EG1Ǔ(K x1t14 4݆z.*$sB;;-@\cWEyQ Ovd3>:|yzl$W7n^4*<]񝸦Yg$5w[gG1 P{{M_,eD>b'Х1WdB*Lwui+F?\*Aɉ \ V'ڝ(uJ,A\#H'[k[a^J [9 Z{@oÁ\tUӃX_?]kD}VH,$Si2v$>2OFf#3t@,?n٘$5X1x][:ΨtJ!]-E'q= Ƞ2h4\II :˜)y8x͘Tig#5]IF$DSR. v &:a EIv:7iH%( ! .ԁ4hN2[aH;RȽ:iλ1!cP.$*E(̺t][jL $ c ҷiAN>NHP6dAK6KC%%}%=]R Riw}i:QcKSCp$[~8d8 OGgeA/ e^nqgE^2 J-n\j'Dw ? W0e$Kl\&|^!naphV10C&/ޒcdQuӇap.$j '=uov˂鞦|{#*0 6wbP@ւ:P S0}=gEH*ueGg P3l:"vǭ]k}MvSoAb^--7_i[jm7m>/93>] I` Ĭ>sP$ FVĈ! C' q L}Dg!RKUCkЎy7F3rZ1#_G$# xp?ps|tkάKuC?x2w4,#l uW KHCX"zd=pUȊ81a|BI8CC% k~:3fshϺ΅ul8C xScl\%1EVxCӻz<>9k- xPrOjdaI^Hq9cڠbbL0tʡbn#XXԂCuH?Sr)\p.ݽ4{۝ A\d :ޏNSjq xq@tX򌊚7[({x&b'vײoX 6{h"ފyLq ]|uzax`#Fp*){|l{$X.U{9AN}aVt$ɡC ^Op}I{nU ?c4o8}R"FvY씢ޯRKYq9)-Wp? L,Q3 H`8@~40cĠ8 k291Fmw1n Ȼc2; &BKCE2IgY QXj6<yt 4I;Iǻ 5yzБ{{s/ lcFscqip;u26wy Bv`CI"%N4{CQ45F ^c[;kxѱ*1v *-v!Kl^˼]WQ}{l+J&UOU1;pF{S, $at٧a8N}Ap{pl6WލMo6kiH \@) 'y͘HV]湳m6mۮm(t`]P:3nf]Тh?4ɮYK;t@ڬ-Xy31/{L ~GӇ HQy2$I߉FAV'Bر1o:c}+&fEw;ӥB&u[ TDfh|w0+` *phԬ6H ܸtBv _va.hyE\M\7b]o0`?tϻ#>gk7P.^^IrT(1.P@G(21@6U'@jc[`0칚qU[\gpYl]nwȴ)(YSW,m-3]YPEy`i4¤rSi\dfQG2މ̾eP rW{0vR' S#c\|7ĄG0 8~ Ȼ;3tSlLL0,y&Dn221m_89D?'(|:̧vjr%y2!\̐#GA懭|Ƃa=8ʈi<1TA݅I;UTZlض 6uJ.ل?@SDfVHPDCZ8". ?pɨ˿t&IE&vUMQ1`4! 04s}WM1 ԋw"Be:(HfyF9J. m\$M&=ӯ'S Z?$huu!\]صtWĆtin} `{쀸-}JH]i0Ыp0E5RtF{jk 侽sv3C,XZw+^I 9Wz 'ޮIGp{*)̷K -pQaP3b#2kSL=\Q%x2 #kX;8:tΦ}1}Ȯ-؍FRGoijqe6WI8 D+NOi0.CvPQWlx| 8c̶bWkG+]oc.lEџ{ !Þns<!/l闀wQžI1uCElrȊl,UbLT|t36 J&P߯OH|J0ygg Sj 4u 2`a\!em F1dgݜܻ;,/%f4%^4!kە(F+amw2<c:s=.4FH*2h3ƥs"g:ztmvW)ezҹyYD(ڠ͓nI\sT1bx?c[qr>$Zbt"Sݔo.ΣI2ϭ?eY_H( =<}Nާl$m"L-zB-Sq<taNc{EMQx)êʢfCh>ۀۉf$Mr\7ZzEI5H"ql>?:-Hp\tFwłq5${B/)<3A&LK6b!0qgQƷ{ԃǵtGSp1 `xb8lV`pFH"MR4R UyG"pXAG BiǎXGC;@'~MwK\ܓQ1Pki뙥*D5yӔ`M)V 9ƕÍ]AdRoFي. +ԁ\Rf9B WzM7 I8uÑ S2zK0U’"2{iU~9W;#Cv}3r|4{ >vh3ǿ=f `3D c/G|r9X -6hf+؁ a|")jXǚFb = :K_ J5b!3dhBLΝ)&iWP-b⤘L UX MN.V4ÌqOGds1O6v-3] jR|X J;'ƁgF+^94(D7lt}SF, >wg]Hv.&?M OlC?Cu\ 1Y?u":eis@[4c7:`:N)_{Y{rsiv 93; qcwX;]4Uq՚ *3 )1l8k瑣$H&Nz1;(~JG~1=(:82ӂka Oכ"pTL8s<n%Ykدo8!éf/c>$ Y ^LD.\Kݧ2 @:3jcž%`ւ67\#)[#-޳'Xs=?NzsjYt:w6ZQ[K,uJPdu|-Iz٢߆oWzg] J`[ܜ'pq㻤$ACV5qM 2?2ߡRtPmVi"sFMFRʑG 8{?mv@(w%@ tgeR 5..BP>ɩ=_` ^&V=Y{dp9qHH ܀A0LH{ӄp;Yɝ.1izkQڅ>:I*ݪ{TTj"`fhVxh0&[9Z)mqwckgrpao2m{ґ'+d("sʀmcAxE\ˏN'˟=tqEćfs0g]Mv~af hʚ1FNwd =],Z6RQ = 얪D/]TK,3OSS:syDx76pyU|+cF%C FRnWd%+<;SZW,QX.R7+hߧݭXv|[%k:qE10JӼQCOlcu7>gxz^юˠӫќw{Cc(:Ū|F;2Ⱦs@גoM$ˆ鴚  uM64:g>3Cq8ޠJbO>l'-] ❟La=|kg]J (>(W}N8o`jZdN,Lis I qyc9R5l?RמHѱ4$PTO$opͫ/zEä(>>indq)Ƣ'%OtR54ø;];(nrvg&E"NwSgz9tizE~Ì"n"f9ϼM5 m ʀv<{;&{iɩ wᘡ1C{6Wb*L* x>vAUv'#6Qw٪Sm;169fT=KUuwY\;@Avg,J-]ul'꧵[o“Bҽc <ȸa529|EѨY$=\ƬJo:NKp1C, 1> FnY~brw(: B$xBT@Y$ tjZݞ:I6ݺIn+Y-@So<9M!y!r U?O$ڠҏ1۞  RGw  52 IidN ^J(&qqq !yJ*ʦn2M#|f(?"^f"tSR춥LQQE]+IG+{_GQM$xFz^"3t%G;MvWO;AD@%Vtlw+MKNe%r#K0d^TSvu}&=ʹfFH$o陗j/OggJi (]6;j@"s>}d! ueJ)Jt>\=b_,-bkTy'tRBG'=wܱ-dKEA9`B4IrNL~|p*9IЕ>bsnS¼U ض8Q疺K-a< ?=py<^GㄊP6P JLA^I3p669J'O.E okrRa(>;T:7#HFp-RsW"#P'(tFA}X3nO$i1:oՌs@3'Z]"s]B?2ip -!.1&z֧/ -E[,"y4b9H<*l(OwS>szO~<@랒Oa} (!D\"lםFҤaþ*<.?RL6 N4u'oBe0!s/E!$L_ϓ6Z%vMA%hHPq,X2mF'1%206 my&Nf?_yzI!UbEl7txRi"OC xs's"y8QNSFI>h R CvAveeY|0r%mxƜySEgxrEWAi~Kd 'nJ%?@$Nqα.{P>Bl][$>ao\. wRhjrsk< `D7q&1[4>KlEayt|.35CYK~ʞ_إB\UP\9DrwÜD C'7qJj&4B)NqA=%'r0" =ovq'{z0, =GGE+9D;* lAC tBR]#*ҿm.n9`pQnBtO~edxhTVY1ϟףo@![ , F{K'(`˰˜VpS'OpEnfsEScS5{pJ L'iH [_\%1ȄUF6n˵Y$ce:%}/(&Irw#x{هB1Uz5(T F>#Ɗ>LBus A fq EzƁ2{q\#ܙ>0s#^\sW~}ѭhm~钧X"Ů4tw.yOyI'm{vJ%?uƵz@TL'Yƍ#{8̣Mc7ը:{vfF+Yx6x2 %9'ֈVyxk#ys#0٠8Y9v0Xk&Aݑc pKhgm\\A-p0Ǜ"yY Nj݆Y:wNgW$TO^tj ψxxXfAaeX IV]i4G8þCC`x.GX |/!B3kY܋2GPT]Bb޷=AE6]3Nod%_H9t8DN!ʠlİǵnL>AAEh1|Pw(Aqg3]&[MiRDـF]cT|tq=$(l+ Na項8A\T lNB)ӊ%8'5([q>5$ B:}H :/pՃM#g%[X_0􏁣9A fW8ChH RWtmdW/Ǝ ¦ Q1>O6-\\+t*"FG3F@^i"n$剩?d&u2;Ni\՘ 'wL~Xgh>+j&vJDfLwjU^3|ßV5gm_&+4ZmX%-<HWa; py2*:wI,Cȁ&[26;ԇۏ3䮂4&[46g`FH*r?zRuMvn"af{bMG0P9,[@q2x7/v' L]"Jx\/yPG!cVY]P/)iH+a {7ehG}D<+m3~<.\3ODD*sbXegYLWEs^="k󅜱S |XzMC^ !e2_(&Jב  ~ijQIg'z6ظYγXWmzaP&&a6$h&S25}k66'Z N=OrZLPQ'98/=ˌ;Fa;goxob8X"F蒑q@N,h,ЛqAOt|ٺ-"p(3JmeRCYw|eh%t\ K6%Jf678IoD:ﮚq4KρpJx#w%P7 innf|6EsF 'tLp*0lItw6d.>Bȷn çGzl*I5eC`/[ʪ$KČ)J!- qU",z$u# 6ZgAa6HٻTc J$5-P>, EaB'ޯs7T0d%Q>P>Ye?ԸD3쉃}vNDh0p@oBu}͓fHR#R>ZUt]BO7F"Q(ZmC)㥘ę$^Irb 1_ɧ1/R9z"KR.$pߕ} L,658:O v't|Bއ&f $Myyd=a f^N_i鋧557u&07$&1CbTUtRUҺwFf6NҼsr9hr:bDNt Fvbh.ӥH.)۵iE|\*μ}WC2ZI>əVaTӬ$K6Z䧰(3}S88pע)}DN8# arX -&& ޔjxH⌂RS4L9wҲ:78qi4M)GcL.Ƭ$^`ܶ]8;2:|ãW >avi"8t5N T\>vL dG|&c<$,dkeʺw+cw+g`Hv" =#-Q6Awk#8cbPd,41``^N_9YsX3= BI F;Ai6h`2jLqڨF)vG-L);[sZ*Eׇp'l]\t=JHG.L gu($o?}`;wR)gcyI&AM4adBI8 +҄=^k7-sh();Cs۪Y Rn*Wnv}F#\>'MV.j vg!*jX=6F  H%px߃\"sGi zQ.!ty|t"^i~ w l׆0CBBUx|٠C , ԡ]@qT2 #c['CS^ȶTik/^g(ڃ*tw%A )Qp˩=Bձe@(mZc8$1"F$qyޥin#,'i-ˇjނ H9LLކ8:uC&30{|o&4qfo4 TY5ԙ7neҍGGMe$U:_;6aZP4"zNjTsDa=M#dgUL qq;}{E'Q(Ա=$~OLInѡ~.y}/# X\wTL nHI ֠>bJQ9ɁVCQz 4@.,;nCcdd)<8pZ rgf3c!Y慳gAZE,7:l.pdO hY&ٝ5LS`Q,dD@NtuQWSLm68Cz[bgxW00V ]d:"V]]*&wyQ9KS6+ԩq-Ǿa]<!4 3tDu`dž} 5v/zd=qWsUsl}M ĤÈ)J 9}{ Љ2CY+uF=`C"ZKѧscXNE15/ \wy9i@N%`'W5 }>R֖ ,~լcPtwyJxn[Ćr"ؠ F03&<\gRQp ί+t<\ l0C o i*Bbq52f j$ ĝzs`clDGnϧ_GV˸3{tt'uHBҐ:W|u9{STq܉3BAfϨ Hx'+idĚb:8Mf:e>żl8Ehe Fg뷠^inUnlr~u|ܟ :'&lýރb@.5ŻUpQ^\0#MP 0ռA.J%H>0jQ@ F}䭆_ ;=5ZeT{sӔh# $yܔ|z+I|)<6Ί{v͇T8A(̓uUǩ?pKCΎ}Z&'~rYUO5>:lՌ1%f!g*ƒ}SJ1[a朓\%t=#xco0Hj%jXBw|QoBO'r@bQc2kFaE!/<2i/ѕ{&Tl. 6] ĪA3$?Y &c0; wS0`0 ZBwt 5@T~sLFC>2Z7'wۂKڂ(|,){Q Aw B4akZT&ԤNg \/kTzOU%U?g*Q\` +yC¶(Lp:$~MRP9L8vCT5ϑֆ;(lEe\huzSsb-sg&2ŮN'+n6Lbu0 rLj_yqxpx]缳JB[ H32y7FD<(10a8!ZE\,֌v͂:܍ A)&!/t* ƘrX#SCF*%xTbq [A/%qhx%;WŔVMOu5 фSӉi&YRK. txC\mVIțWYoj;n|:j<V=n6-G 属23jIÙ3#7W>zl0'=ZJD<-&elqjL9?:#MzA|s6MٸxKz[y"!PFq܈hy#?[<O1{lΚ `3vͭwebg,s mUkMnqX6Z[`KqnYTaٻa?E4aeպ5 8riܪ5˵V/]LBKgF{}1doL^UUtSկl6b1c EaRjOĽfe o;*C㎜_6B9aةLM)d uDqsc6Z)!eqj$+݄WxNۮKMv9RLmlAa[Fot|l3=% .mwC$Yؼ*VF\/F=brOܪ@m{vF;hO{sl#h~$:UiXTBצPC%⛷ҐBztPLΙ >+';ݻ>:j Hkþ+m:bEN P$$ !Z߉݈&ws:/wy6Zjz!6gH_]:gJ0BԝRd%juRh{'ٜ ]q- &q]H!`A\uOaGboAM UH]c`Bۛ~3yh4f%f%YI@W43v4"^1%4sLYo^Iˎf۸ۑ!f2gF6"3Auh~*>i绝ok]oV|47) >f]G*զowa{uWM٠)pٔ =ɫ.|lʢrA/\s.w o;On^ y$%BG^2u\ [DW2k` hÅɜs&7Ttc27t9ɇ\G~CGF6y-nOv5%0y!H/kOSϩ7RzΥy1g)3yLL֞<Ū;"E8Yi/TvGŅhK*j YJG%MlۚhP}`6[uOa/IUrսZP,Iїwzz݆k+lY'RPUNtS2T"+5=E-%xJSqӬVmj2 hK^n9&e.k'f,C@f:{M X~xN84؉fҿ %msogP/͆ s=,8IBt_`XRpkΆi<덺9VcTwÉ :]X_|< >CAN]&Oׄp4I[Xc~9C.[-P"cǃBo {1Q@|BD=ȰSOwa1OW%"}4 ZDy"ƕqom0 /^:DYǰ=k9 5EmxPj/t611M^{~1wjrFX{ɹqe7BH![$+ilWAf!qc*(iG8 ;ʩ=f5A aΝV?V*2ZKZ}߼vÛWo_ NMTm:\%bG,EjlŗC 4Im#_c2A lØ s0k?`t#!.ݸ`ڥ;\YҮYmvTo$q^*(YtkY/ Q[j"MSN" uczu SL]zﭡO~OMkkĉԤư:.&z*ܼyo>hXoo5Yݿ_~=Qb;aomU܃mqD8oN7r018Rj]x-Bah{*)>V{wPuLC(b{ Z8a׹p7R903@|$ؖT$Z}FP:rpзI_D6Coմ<#zFVJ0Tq5x=:z(ݖ"Oȥl.juSPp"~EܽV`OFצ׶=ѝ̾h%kg0M ==Zlv- What is gRPC?
grpc

Most times, when we want to bridge the communication between two services, developers opt to use REST API. This however, presents a problem when trying to communicate between two services using different networks or languages. This is where gRPC comes in.
gRPC is a high performance Remote Procedure Call (RPC) framework. gRPC offers many advantages to REST. Both are API standards, allowing for communication between systems. However, they differ in the message formats, and error codes they use. In order to understand the benefits/advancements of gRPC, let’s take a look at remote procedure calls.

Remote Procedure Calls – What Are They

A Remote Procedure Call (RPC) is when one computer causes a process/subroutine to run on another computer. Usually this call is written as if it were to occur on the first computer. Remote calls are usually slower and less reliable than local calls and are treated as a form of inter-process communication, the only difference being that the processes have different address-spaces ( they each have access to physically separate memory addresses).
RPCs are a request-response protocol. They follow the standard of clients requesting access to resources, and the server side responding to those requests. RPC calls can be blocking (client stops its program until the server response is received), or asynchronous (client continues execution, and processes the server response in the background when it arrives).

Typical RPC Flow

Below is how RPC events typically take place between a client and a server:

  1. The client calls the client stub (a client-side object that is responsible for communication).
  2. The client stub takes the parameters from the client (received in the above call) and creates a message with them in it.
  3. It then calls upon the system to send the message.
  4. The client OS handles the sending of the message from the client to the server machine.
  5. The server OS receives the message, and unpacks the parameters.
  6. The server stub calls a server procedure to process the remote call, and sends a response. The response is sent in reverse steps.

Since this process is very standard, many RPC systems have been created to allow for inter-platform RPCs. These typically use interface description language, which is used to generate code on each client and server platforms.

So What Is gRPC?

gRPC is an open source RPC framework created by Google. It is based on “Stubby”, the proprietary RPC framework previously developed and used by Google. gRPC allows the definition of methods, along with their parameters and return types. Clients using gRPC can access these methods using their stub, and treat them as a local object. Servers using gRPC implement these methods, and handle client calls via a separate gRPC server. gRPC supports many languages, and the client/server can use the supported language of their choosing. In order to do so, gRPC needs to convert the data being transferred into a format that can be understood by both languages. This is where protocol buffers (also known as protobufs or protobuf) come in.

Protocol Buffers

Before objects in one language can be used in another, it needs to be converted into a format which is interpretable by the second language. Objects are usually converted into bytes in a process called serialization. Serialized objects can theoretically be used by any language, as the object itself can be recreated from the serialized form whenever necessary. This is what protocol buffers are used to do.

Advantages

There are also many advantages to using protocol buffers instead of other formats like JSON. For example, protocol buffers offer:

  1. Compact storage
  2. Fast parsing
  3. Cross-language compatability
  4. Automatically generated classes/code

Another major advantage to protocol buffers is that proto definitions can be updated without damaging old code. The old code can simply run by ignoring the newly added data.

A Small Example On Protocol Buffers

You can define the structure of your serializable data using a ‘.proto’ file. Each object is stored as a message. Think of the message as a struct, filled with multiple variable-value fields. Here is an example:

message Car {
  string make = 1;
  string model = 2;
  int32 year = 3;
  bool is_hybrid = 4;
  int32 mpg = 5;
  int32 tank_gallons = 6;
}

You can then use a compiler to make a code file filled with getters/setters for each field in every message of your proto file. The compiler, protoc, can be used to compile proto files into the language of your choice. The compiler will also create methods to both serialize and recreate the object from the gRPC messages. Lastly, the code generated from the proto file will include both client and server code. This includes services. Below is another example of the service we can use with our car example.

service CalculateTotalMilesOnFullTank {
  rpc GetTotalMilesOnFullTank (MPG) returns (TotalMiles) {}
}
message MPG {
  int32 mpg = 1;
  int32 tank_gallons = 2;
}
message TotalMiles {
  int32 total_miles = 1;
}

After serialization, the clients and servers will be sending these “proto requests” and “proto response” instead of regular requests/responses. The current protocol buffers version is proto3, and this is the version recommended by gRPC. It can be installed in each language individually, however, I’ve found that Python and GoLang implementations are the quickest/easiest to install.

So Then What’s The Difference Between gRPC & REST?

Both are APIs used to create a standardized interface for systems to communicate with each other. And both types of API standards have their own separate benefits. Using a specific standard depends on the project at hand. If your project is meant to handle high loads (due to lower latency), two-way communication, and you also want simplicity in your code, you should use the gRPC framework. However, if your project will require statelessness, self-contained messages, and language agnosticity, then REST is the better framework for it. Keep in mind that gRPC can still allow for communication between systems with different languages, it’s just that some features offered by gRPC are language dependent. Lastly, gRPC uses HTTP/2 which offers many more benefits than REST APIs HTTP/1.1.

Conclusion

In this blog, we learned what Remote Procedure Calls are, what gRPC is and its advantages over REST API. We even went a little bit into protocol buffers with some example code, to see how gRPC code is set up by the developer to be generated by the compiler protoc. Lastly, once we had understood a bit more about gRPC, we went back into how REST API compares to gRPC.
You can read more about gRPC here , and even get started with some sample code in the langauge of your choosing here.

Leave a Comment

Your email address will not be published. Required fields are marked *

2

Thank You!

Your e-Book is on its way to your inbox!

For any queries or feedback, write to us at hello@capten.ai