From 3b35214983e382e34b4342dde5c91e9280c5b3d1 Mon Sep 17 00:00:00 2001 From: John McNamara Date: Tue, 17 Jun 2014 01:08:21 +0100 Subject: [PATCH] Initial work on row/col formatting. --- src/worksheet.c | 24 ++++++++++++----- test/functional/src/test_row_col_format01.c | 23 ++++++++++++++++ test/functional/src/test_row_col_format02.c | 25 ++++++++++++++++++ test/functional/src/test_row_col_format03.c | 23 ++++++++++++++++ test/functional/test_row_col_format.py | 24 +++++++++++++++++ .../xlsx_files/row_col_format01.xlsx | Bin 0 -> 7029 bytes .../xlsx_files/row_col_format02.xlsx | Bin 0 -> 7361 bytes .../xlsx_files/row_col_format03.xlsx | Bin 0 -> 7044 bytes 8 files changed, 112 insertions(+), 7 deletions(-) create mode 100644 test/functional/src/test_row_col_format01.c create mode 100644 test/functional/src/test_row_col_format02.c create mode 100644 test/functional/src/test_row_col_format03.c create mode 100644 test/functional/test_row_col_format.py create mode 100644 test/functional/xlsx_files/row_col_format01.xlsx create mode 100644 test/functional/xlsx_files/row_col_format02.xlsx create mode 100644 test/functional/xlsx_files/row_col_format03.xlsx diff --git a/src/worksheet.c b/src/worksheet.c index cb11b43a..c2ff3bb1 100644 --- a/src/worksheet.c +++ b/src/worksheet.c @@ -615,7 +615,7 @@ _write_formula_num_cell(lxw_worksheet *self, lxw_cell *cell) } /* - * Calculate the "spans" attribute of the tag. This is an XLSX + * Calculate the "spans" attribute of the tag. This is an XLSX * optimisation and isn't strictly required. However, it makes comparing * files easier. * @@ -656,7 +656,7 @@ _calculate_spans(struct lxw_row *row, char *span, int32_t *block_num) * Write out a generic worksheet cell. */ STATIC void -_write_cell(lxw_worksheet *self, lxw_cell *cell) +_write_cell(lxw_worksheet *self, lxw_cell *cell, lxw_format *row_format) { struct xml_attribute_list attributes; struct xml_attribute *attribute; @@ -672,6 +672,11 @@ _write_cell(lxw_worksheet *self, lxw_cell *cell) if (index) _PUSH_ATTRIBUTES_INT("s", index); } + else if (row_format) { + int32_t index = _get_xf_index(row_format); + if (index) + _PUSH_ATTRIBUTES_INT("s", index); + } if (cell->type == STRING_CELL) _PUSH_ATTRIBUTES_STR("t", "s"); @@ -711,17 +716,22 @@ _write_rows(lxw_worksheet *self) TAILQ_FOREACH(row, self->table, list_pointers) { - if ((int32_t) row->row_num / 16 > block_num) - _calculate_spans(row, spans, &block_num); + if (TAILQ_EMPTY(row->cells)) { + /* Row data only. No cells. */ + _write_row(self, row, NULL); + } + else { + /* Row and cell data. */ + if ((int32_t) row->row_num / 16 > block_num) + _calculate_spans(row, spans, &block_num); - if (!TAILQ_EMPTY(row->cells)) { _write_row(self, row, spans); TAILQ_FOREACH(cell, row->cells, list_pointers) { - _write_cell(self, cell); + _write_cell(self, cell, row->format); } + _xml_end_tag(self->file, "row"); } - _xml_end_tag(self->file, "row"); } } diff --git a/test/functional/src/test_row_col_format01.c b/test/functional/src/test_row_col_format01.c new file mode 100644 index 00000000..988fd58d --- /dev/null +++ b/test/functional/src/test_row_col_format01.c @@ -0,0 +1,23 @@ +/***************************************************************************** + * Test cases for libxlsxwriter. + * + * Simple test case to test worksheet set_row() and set_column(). + * + * Copyright 2014, John McNamara, jmcnamara@cpan.org + * + */ + +#include "xlsxwriter.h" + +int main() { + + lxw_workbook *workbook = new_workbook("test_row_col_format01.xlsx"); + lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL); + + lxw_format *bold = workbook_add_format(workbook); + format_set_bold(bold); + + worksheet_set_row(worksheet, 0, 15, bold, NULL); + + return workbook_close(workbook); +} diff --git a/test/functional/src/test_row_col_format02.c b/test/functional/src/test_row_col_format02.c new file mode 100644 index 00000000..7c50b3c9 --- /dev/null +++ b/test/functional/src/test_row_col_format02.c @@ -0,0 +1,25 @@ +/***************************************************************************** + * Test cases for libxlsxwriter. + * + * Simple test case to test worksheet set_row() and set_column(). + * + * Copyright 2014, John McNamara, jmcnamara@cpan.org + * + */ + +#include "xlsxwriter.h" + +int main() { + + lxw_workbook *workbook = new_workbook("test_row_col_format02.xlsx"); + lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL); + + lxw_format *bold = workbook_add_format(workbook); + format_set_bold(bold); + + worksheet_set_row(worksheet, 0, 15, bold, NULL); + + worksheet_write_string(worksheet, 0, 0, "Foo", NULL); + + return workbook_close(workbook); +} diff --git a/test/functional/src/test_row_col_format03.c b/test/functional/src/test_row_col_format03.c new file mode 100644 index 00000000..9a391844 --- /dev/null +++ b/test/functional/src/test_row_col_format03.c @@ -0,0 +1,23 @@ +/***************************************************************************** + * Test cases for libxlsxwriter. + * + * Simple test case to test worksheet set_row() and set_column(). + * + * Copyright 2014, John McNamara, jmcnamara@cpan.org + * + */ + +#include "xlsxwriter.h" + +int main() { + + lxw_workbook *workbook = new_workbook("test_row_col_format03.xlsx"); + lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL); + + lxw_format *italic = workbook_add_format(workbook); + format_set_italic(italic); + + worksheet_set_column(worksheet, 0, 0, 8.43, italic, NULL); + + return workbook_close(workbook); +} diff --git a/test/functional/test_row_col_format.py b/test/functional/test_row_col_format.py new file mode 100644 index 00000000..04121b16 --- /dev/null +++ b/test/functional/test_row_col_format.py @@ -0,0 +1,24 @@ +############################################################################### +# +# Tests for libxlsxwriter. +# +# Copyright (c), 2014, John McNamara, jmcnamara@cpan.org +# + +import base_test_class + +class TestCompareXLSXFiles(base_test_class.XLSXBaseTest): + """ + Test file created with libxlsxwriter against a file created by Excel. + + """ + + def test_row_colformat01(self): + self.run_exe_test('test_row_col_format01') + + def test_row_colformat02(self): + self.run_exe_test('test_row_col_format02') + + # def test_row_colformat03(self): + # self.run_exe_test('test_row_col_format03') + diff --git a/test/functional/xlsx_files/row_col_format01.xlsx b/test/functional/xlsx_files/row_col_format01.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..8ddfcb746eaa144756b936518e3f83829a6aef91 GIT binary patch literal 7029 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 literal 0 HcmV?d00001 diff --git a/test/functional/xlsx_files/row_col_format02.xlsx b/test/functional/xlsx_files/row_col_format02.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..906659c5e6ff27a8987f3948ef997b322da1d996 GIT binary patch literal 7361 zcmeHM2Uk;B*G}j~qzHo2dy|e51S8UfK#;0br57oo_g+Kqy(u6~X;PJ<0i^d5kVsK_ zCxU>~H##%#%rJg`;Qi)g<(`#w@3U9V+0QYhp!{ z##eAT^a7d3YVaBE7vp&QSBXVyb=EbZM$YbJ20!$N6qGizMdW3tXJ7LYMv3z4$wCEb~gOlUxi{)w3rqkb7J9TJWetu}o*eAn^3EAMHJp zSi&zJ>rvZpFv9m7y#kW7tA&XW=WHN5r{w7jY4+_V69?l`7@2PjZbH^ohPl?=-jXK! zk7gE;sW~D!iT#m|*c`E!2*Yn|+>vPS$F*_WHkSR^tOEPI{d5BzCTU2o{Ss#>nIgBR zdSaJzKQ6}S>TNa!y#o%G!X*^fKMFF zY@7u6e_WaJdj1Ww|C#WLN*Kfh)}@YZg(jJW<25@4g6A(9l@%J9H5uNsZ86qH=d(#2 z><429LQGJ@`^$rO^=7t~tTY+vj0IHM-g4cm5;69gcM@C+Mn{>izEK2`?k{G?=_#$3Vt;fi6IPqGs*{7t%JE89wRQV*w z5l;#5z3@xHN0Q%P*NZ}7?gC3b#;Gb%QaM*7dR-S~%!x||QNp%`HO5sBabGwqW5l&L;>jC_^mL-SH1Cn2gf0&Y> z$cC3yXh(|0d&jzq`|r7NiJ5r_jE-QhU3pMdPc$+!6KGkOmUw<}*%n3XO|;}AJ7~ee zh8A7GhszgT)KGUoBTWx4tx8>vkEQctPjFgh>6^|F zTyT~??%}RLebq}@obB#PjDGpA5hnXcpx6i$L} zdS!$qz#l?+n5CS9;#S{g{`QZN@1 z9IGW)-&Q)Dl$@Q$cFM6vBoAx1UZa0iippFx-1t12hRy2l%3d>b5Xt4}5=rkSGMZng zVq(*I=Y=cdn;91Ba=E?ih!GHfUW^h6b!+Qcm{Ep2^3Zb4By8#l(^aa2nigxb?Pt2T z)Iaa%!O<;#i}ag5>hCGt&J-15^Ma$)Mdoq?@9dM_FOe3Db%K|^>=Nt6xph)}61o6& z{>s}wQbUl4h$w4Eoaz&COKcWgHRodP@0!|8Vi&J8+Sn-A;fs%O_bqFF_Nl%l*h8%y z$Z(n$dp68#V(LkGz#s`-$(Pn2J#(%jR>W_-+O3dQKCVArz!B^q*#FfOtfI`Q>x2EP zKy8n3dzyjS>}t%H^0!TQvNUouGu3c*w6e2s`Vpt1{r8Ak1<67_H_y?xZrGL*lPivd z3|(0PN=r;hiD-yu45MhN`R_8s&bn+%W>Q~ORA$(R660CT2@SWkZBA{g7|OCnJD5w8 zGE%Ozy3WgvjR}N@DY}U3@wNqvL)wVd4Yu?h$9le2zNU=ISB7U;cv+(I`-RBU0v?S_ z;a01Amb-tK04XA@R?@S_=Qd*Nf#@*xEXnU{arUq=`?-i34MYS= zkgS>dh*bKZ{EJj-o%T$dwBd8U5a{zq9~0;i3c@3x_S2&nn@*Kye0xJm!q*3zJhrVg z!3K1d)#2TE0v_nf`MyIA%XNwFcZ{UlVEYtRk1{5A*6)@Sex)-l+*e`@A3x||VkO9B zyUV!O#?>8%ehEu>D3eq0pya;oMjK(d^X zefEohJPP5X|FY$y(|bbcuY6}&ux9tHTjpNKaRH1&|Cwi23)ve2@c;k~+8-^<&ojf> z(#+OO;OAB72YWYk9>7qyDBqDzx-mJ!Y&q*_@m(S&t1`==wC#3b3|8qW+8TLMBZ@w> zQ}h17wzo#9z{X8M8{Q$TM(11(y|6OuBdUD`$ZMKjr4c+@^!T>x2Yib za~T%4MF-SNgK|%JJD714Wa;G=da6XrkU-RF(&w%`HIt>VJ%v2pHu#Xq!$y9u5}cCR zuo(hj&rFWkGotD3m1Gv`gEqh`10RuVc3?3Ar{P-2(s6V4R?&UcC{`vfFX89ldos`w zR1f@srl|w62Fwi);DBaP;Ys8mMWqMKQVE^mIw)+giLWRdX;K(X3K7TD)$s`L{g`n1#JY=DZB`D@a26k0c0(@X z+nIb>;_wasjd|fsyIQrf#zU;rZ|v!M*(ycD5VI;-k}fbZb%%D`+{ddQK^yl$EM@20 zfNMR`G6=;N0t0yGXS7mt!9ykAibfK~ zj+bgj?)dN@0fwYPsiNaEI86h6;9vM-vv?`ev{p%x5aeKH>P1Lava(=`9e@?+`ePggUTu zvO2U-wUKF9;9d@JC0xxRqMs`hH#cjz>=5ntND9q`{Wy2p&6GaaxX_Ytnbv3lZ~(HP z=ZBEk%k1)KyMrQw9G8qAw$mGWYj-q8nsnAS>tJb#5JNimr{h4zTOxG4ba8211ZqzOy-cipmy0;1n z1bvWTMvA30^z9sOy5xAeFK{Xn-zzUGmAer7hjRK4cy^qnXzn))#lN=cw*?+u&GN;T zY36Y`X2`tHug-OwFW=*e(_`7K9V@YRHT6*XAYEk=dc!IVa#ANm)4uPG# z(>|#bozq3sffAzjvbs3%oOHrXC9W}*(`d^Rw-0G*#T~csW~k=t>Phr8bRZi!T!@$U z=ZMzEAPY1&K>Nvz`^@;Xo6CgP`ubL>KG?d}fKt1-`K?E#Pt|HdelqlHu<$KaCwV)_ zD5uiojSe50vGqP+{6bhETX1JhgG7UrVKp9MIXI7pE*KQR(70s95}>SzPrIl+(WiRn;C&AilxK~!zlDg3s-51%%X;&{{WFUJn~Wq! zNo>tbFSzs?r&*OTKQ@yq#Jgb7qe#2#ec6ld7GQlfsHCgBCD350Sq!ay6+tYp+H@yA z<_13pXXLON%K9eqI>T3ok$n#PS0SBTzzU`5L!+zjr{gMuNscuVKbn4T%`8(E5+i(S zuVJ*=Qc$UZPr*EXIpsMCiAZuNAo3~YcjM%aG9FE_KuB~P zPlU^SteT>{mo5D&Wy>IiO^Gla&I9MY!n+TrqqsG8v$EvCl{AEGtuUj&?ERcdNA7Ws z`4HC-R7Geu>w3a=^DX?d)qze95w1m~(ddxr{-E5Ak6N3a)siT$$cUA2xlFCW*H~#( zb%75v_A9ts#p`wTs!~KBTbs59P^aDuMKm!(=0@;W?^d3xeHJ-(kcJh@_yTIF5cPP_ zORac$M+vr)ar|+v_Bhdr^fibAMV-;Yvcx*wI-Mu>MVY&IjBNNm>YVtfm@N0F_YQP_ zh!k~wYSf8zwRus3sOHq54CVNEuLIQKJ~SAt5IDuoME=F9AHjb=M?Z(w8SnCkA@28Bv`D1t4!@(~5>MNcJ-UZ$n?*t+Ru_=6TxLY^s1$ z`JzcrL5u3jW@C`hSp@FtG_kWG!BbZOImcR=PellP{zWUT(~r|Ce`T`5n?9)n>xLp1yXSCiOg?~0YT z{L%r5Rj=>g#W+9*;{b9@Z)yrNQFVmbI|-P;9L;_cJ^yV&TFs6#C`t__t1=&jF780X~G*e zkS1CE6lAGwbgRG&+(ITa@cqw!nd;fCiR&QQUm8uSfEK*^AFWR{G;#m`$5 zVWGy3`UiXO3SDZj8Nu5R!UJmGDs@X(!=IGAlgMQ42#pBK$E{e<*Ho^@KF*-eb}m_v z)RM54w3*Zv>tN;b;4Z!|*fvzxVK!D;-fCR}4p(UWu-5HM!@ap2^dxXoppZpW9pY_WDDpy&=c$FoJ>kCjL?bYvHk`fNEdN|Hv`j59%(w z`5Ex-%`(hL`)qfw?VDpQ*Y_xiyAw%GCuXPkfAm>EEIy1R@avaFe|YPU`4_K_RF(d2 z;P3MHAHW|o3=q1D2ms(- z0RXN8W`X*$4)(4vdsn0TUXCyqLq1PCTgF@@kTV;Af&Tx$>;IkyUM2Lay%ivlKU6#m zTH=kEej|k|vKiPz+Q`XZyrE<^#_#ocg3-CrJ_3>0GN9T@i1WHRlL%F-nY4HM zG;v6V$AGr-ptW|9O9S3=s112qx3z%gYe}#0M;j$tacwlFlegNd$^>8<*!oWwGN|MZ z2Z@J@YIruBpjWV0sX>{dQyePNN#{osQ^5+Lm@4tXMaktc{ixE*!ja)?k0vX&Pc?8Y zefB`tm8ZT<5=n)Aep*bbB*RD1nnJf*2ym}Dw2_-+Sb4eQBiy=w*(udS_)>PlqM#Ha z(6BL!+Q$R{E-x_w8h^>I8f^iVZ)nP>pp%CHFbFhqhS|FC^L>9Z=DzzktNzbqQ&jv1 zbP^GEZ!0#-E}nk1SH#UJXi`yZV!BV?&bq}=6P?E@b$Aer8K`WA96nh2a7TY;YuV~P z1IUzL?QJ8cbfu7~&nIiovaAQh*`~}ER%AUiF(8wN(=)b4p81Jsrk_rW-b6;yG$x+0 zm$m=K@`hXlrT9s@;}<0MPA1CKcAW#5o-uSL z2S1JAaA#xtf*KgbP3wLV#*+w{BFPUdl;r1&g1IO?9zTvnju0kJ}{jMy`mu#(bVvHmNf zXGLf5MOD{bo`I2S+yq2KStsJ$0G~^IGoRuyC(}Uh)LtUntqPNkjr<+nxCl@GvX<=6 zb*;f(nw>!U^W0|_!#rl@-eiaL5~{0tG6tg;uC)Y8I879NiYet|24nf`!A=4LyXFuz z6$U-Oe-xl?IidMpw9`T8@{Z^ar@Od%*}`1DCu6miY9vyCq=oW?A$ZHMD}c`~t~xZN zT}B^2P3H9*HgOC;Dl5>!#Yv29k6JeG{t$FmIMZuy*{U;(ZzirvX|kKq@>@k-XE3`p z?QQ8c2I6gqM!YmunE~P5p<(kA*4fs1>bn+?)Vl%F5wTd3!2K+${((NvBnDFl41X)L zUHqMt+sUWqiGu~b;Hk)ym0%vWI2 zV&!yLj$B@S*={LJruNZW*$VA?y4Zpt zzy;coqVNUzfJCzQsusCkCtk8OL9JgMY&+mjeAL*z%^of0SJNPqwi3HISpAfq6`Aqw zPAC17bzBlj3_ESgAZOgk8dD%x%`DxA7rB$y@};$!mGEM2UY;PrN1L!s24oT-H0#TG zR%a`8NMtt|_2ebnbN8i7Ew_*pe}3yS_LA*s&vvfl&9v&=Mp}X`LLCJrm^#+EUS?n( zt%;-#j_9j}+W9ywBT;dWB~j_IqlJiJ8%kI0v4c#gCrZjEnii2x#Iq z&VN`MFYU21tF_>Lf)4E8&*8N~w)#M906>fOdqw{v&s;5Gb};@Q&zs)^zoDz{fD|Qb zBcAYJbak-fsHMemi)Wj2sZ8bSg0KH6W`0(FD!1~rh>w9WSLo)oRFo4<=$bP5Qb5( zrH=>v97;J5}n8$KfV*dkQAIe zIxdyNJkT#}fiLE6py>d>fz%+SQnuBAW~4cGA4~N<@>Bp3dyT;Rb>@@Hug6;ZUyl>M zgno!&xNtpN9Y(!n;N`WL=Zgti=y*Qsf3Wh2A@5G6|K2W&a>-M-^YY{^N88z%*DVr3 zOQzvS{;acujlRg&kn{7V9=09300sG@*t>GM`ir=9JGibwa3?kn7N=J7wE_CAJ%-g^b&B?QD23w0e3UiqVNMrpT4;&4LTj=JI0ReJ@hKBI%I`>bkZ67>U1|nn)TGQ=wfIK5h(W@Ovi#vw}e1Epx6}7{FS4`Sklcc&94(~&rSlN z5Y1J3c{&xSs$f0~M=V98yVVu{7thxS%iV3OJSg43Jfq&BphiVS-1o}C45Z5`sN0!b zprkm^LKr!b|Mk)em0pCwk-ULA_l~O+l|swSxHq-~cEA&gbbn0Q7H+pw`ZNW;dz`m< z^SrLRJd)emu@dXlya%Tn0^cyb6RU-*8FkRW9klHvCc7_w1nl9N_Ipm+GyRe>P+Zti zPVY)s<_o+{DCbAD^JvR6kFFHWqHa;_8S*c+bwv7Fy2=}woQP7#OGHOgkOc}7pkp-S zIWsox;r7XAeSNFM0Af>PNTyTN(&$y;SGg9Sm!!HIEGVksa@SsYlmj|(quY<_y?DKpaTPXRIV6`G6bufaZ(6ou4p33TA!Re@m>eX0J~HmPI+`R&ExP{# zF^(BNM$dqpcauz~BXSme+>iJESjeop94|d-@+2vdv*`TxduzQSA(v9>VU=Q+`X%ll z;^*2yh|j4*A&jer?eA2PRSfwc+ zCZoHuZ~h0bmpWzbWd(h$z`81Mac_BRpy6_h80sDcf`EUmSu!r>1|K^|q_H{7PsaC?I`Ef^DnaWKuJZncSlg-xr3N0K`rm?HZ zIYdN4NpL`<2nWxl9_D**P5cSPCq!K1VvJN5B3$h;*IkssoBOe!q1EBw5W&Tfdp=%3pFKUNAGbuQHs?l&h8 z^GfeGp21%TurGK+yEOPZLg|>`UIA72rI7Z%KgK7lb+b(%gS|7>-P=Y;dP?p^jga`* z6F*>dP%#||uOl77D9L@tEZYkL=b}qwdX=z>-rHhzx*-4_{%IUO7SpLlvdVsj%&X)r z!(>({-it8qFrMo?2Vo#m(T^e(#fR?1AtYZ5Q}bc%b86jLr>_DSh(aJTOmx4-8?-s#*bUHwAVO*T~lgaunb&Nons#M8w((7;Gp8(NV5E?Lm` zZYQ#6F~dTahEzXGLl;XJ%+-be$M!?FqBMWhh|Mf0;^gg4s~oJ7eDZtR2p}G+v8j)} z(%Of`2a0U7$SA@MC!p+aT7NM~O<9^(wLl;vyb8V5=gigqP=|IldH0K-iyMbL>!yv} zuq>B4$&$5~mnKMH!xTpMt`mIeXgr#NKd!S$=Sic4p`+UTWJ85v=}i&Qhj^xI*<4F+y6KAffJmQ zI@Z1v8C!o<_R3PV-#vCs9+A|&>aKGyx?b9$Oi4)VwZ7+gjtB&wfQV;tvW(2+KJ8ZU z`4H?4FKLeWL%JR!kWHo`beM6ZL9x&u;&_a%{{HUx2hK4!CDD%8MLYf)x@R+YFw<~$ zaCG4}b8v?JG5h?ej}3G!v9T2E60z449Kc@v&MMRvt5k zyPqBwGL$BH&BF#yGgq2dVtxG*Rrj&R$MndvdqPz3doDc6Rd1p&){P9jTxoFgr3Vg@p zLNT2{i$E{9xUnreGfiBey5gQy8a*Qzj?K!sEue&Zf%2{xIiDQj5qkORye~MTyWXXC zE(qN4tUNQy4#~cm`|R58^|M+(->rwyHe=HfnA|Q1uDbT-+NB^!5$FT{G>T^VO!Tvt zQBb{PbY{Qz+(!r=@KKqGXHU zv&+sXQbCqXAS{L-BKyyr;{Zo?hM_rk4c)Mi{K`2KN5_9D_nmBitn_$wjjF!%-jgR&WdGRR14se`BlOQvK~u{qj0u=GCYX)c^m40{N$m(S z5Lo>IN$ksmBrlH{%|^ilhr_MzB#PzlcB_I}q>FM|l^o!v&IX73ZG~>tm<*6@_3(h2 zMrfb7O_)(}n|K;aH#{OV59{@!!F`oF%+pl54Ah;Z==aDpKM3k86qyHnYglnG(Ye^$fBVh3hVwW| z{LZJu<}=ti&YveH5Q7)+-)>C)jMks~Kir>aK>upsuS4NKf#3H>=#=_@7k-ES-kJV{ju8A~pZdFj z-|K{*20}>x_r?EKHT-VnucG(U1^{q@?w9{2fxpB5dVc*1cc%CS{-4uK1B!)?4FG_L O{y@+wD?t7I+y4N|VI