From fb8ba861e28eda0079daa44fb1ea3ed17745f1d2 Mon Sep 17 00:00:00 2001 From: Maxim Lysak <101627549+maxmnemonic@users.noreply.github.com> Date: Tue, 12 Nov 2024 15:20:55 +0100 Subject: [PATCH] fix: Handling of single-cell tables in DOCX backend (#314) * Handling of single-cell tables in DOCX backend Signed-off-by: Maksym Lysak * returned try-catch on tables handling Signed-off-by: Maksym Lysak * cleaned Signed-off-by: Maksym Lysak * proceed processing the content of single cell table as if its just part of the body Signed-off-by: Maksym Lysak * Added example of trickly 1 cell table docx Signed-off-by: Maksym Lysak --------- Signed-off-by: Maksym Lysak Co-authored-by: Maksym Lysak --- docling/backend/msword_backend.py | 16 ++++++++-------- tests/data/docx/tablecell.docx | Bin 0 -> 15180 bytes 2 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 tests/data/docx/tablecell.docx diff --git a/docling/backend/msword_backend.py b/docling/backend/msword_backend.py index 08529ea..eb7b75c 100644 --- a/docling/backend/msword_backend.py +++ b/docling/backend/msword_backend.py @@ -130,7 +130,6 @@ class MsWordDocumentBackend(DeclarativeDocumentBackend): def walk_linear(self, body, docx_obj, doc) -> DoclingDocument: for element in body: tag_name = etree.QName(element).localname - # Check for Inline Images (drawings or blip elements) found_drawing = etree.ElementBase.xpath( element, ".//w:drawing", namespaces=self.xml_namespaces @@ -201,7 +200,6 @@ class MsWordDocumentBackend(DeclarativeDocumentBackend): label_str = "" label_level = 0 if parts[0] == "Heading": - # print("{} - {}".format(parts[0], parts[1])) label_str = parts[0] label_level = self.str_to_int(parts[1], default=None) if parts[1] == "Heading": @@ -217,19 +215,16 @@ class MsWordDocumentBackend(DeclarativeDocumentBackend): if paragraph.text is None: # _log.warn(f"paragraph has text==None") return - text = paragraph.text.strip() # if len(text)==0 # keep empty paragraphs, they seperate adjacent lists! # Common styles for bullet and numbered lists. # "List Bullet", "List Number", "List Paragraph" - # TODO: reliably identify wether list is a numbered list or not + # Identify wether list is a numbered list or not # is_numbered = "List Bullet" not in paragraph.style.name is_numbered = False - p_style_name, p_level = self.get_label_and_level(paragraph) numid, ilevel = self.get_numId_and_ilvl(paragraph) - # print("numid: {}, ilevel: {}, text: {}".format(numid, ilevel, text)) if numid == 0: numid = None @@ -450,8 +445,13 @@ class MsWordDocumentBackend(DeclarativeDocumentBackend): for row in table.rows: # Calculate the max number of columns num_cols = max(num_cols, sum(get_colspan(cell) for cell in row.cells)) - # if row.cells: - # num_cols = max(num_cols, len(row.cells)) + + if num_rows == 1 and num_cols == 1: + cell_element = table.rows[0].cells[0] + # In case we have a table of only 1 cell, we consider it furniture + # And proceed processing the content of the cell as though it's in the document body + self.walk_linear(cell_element._element, docx_obj, doc) + return # Initialize the table grid table_grid = [[None for _ in range(num_cols)] for _ in range(num_rows)] diff --git a/tests/data/docx/tablecell.docx b/tests/data/docx/tablecell.docx new file mode 100644 index 0000000000000000000000000000000000000000..6fa7f01703318469ea90cf86781e72046d2747f5 GIT binary patch literal 15180 zcmeIZWmFx@)-JqoclY4V!rk57U4y%8aCf)h!QGtz!9BPIC%8KSE_>f|?%pTwzTY>- z{rkSX#;VcXvz}Qkv*w&#^^~Fv7&tlr5&#VV0Ehw13HBNvK>&a+5C8xg02)+B#NN)u z%+AF?)ziVuS&zZP*5*S2I4D&f0Q9~7|7`z_pFm^sm{mU`ve05Hp zE-&uVe=^0P*h*&nAvD77Z^PQzg(J%j!bsZGpE#ictB_ro9fYCz0EneYiBl)z9>hTs z_KU)~c-B7;kU2+fO)gmpLVyA)MubQ$A7}b;kfFfWpR`$4Hb_$lGipbQx^}x9DM)wA zP)W9(_O>BcGS)dXzeD$;`$X$nZz` zKi%@babNt~tyd=YzIRJ_!SkS(pqVbEm0s*Zd7#PkD)urIw2qW4+Ukdr=@Vbk_Gm=!_DbL^NvNmhOvoAva~#zc@6-KQ@-mp_7px?8yrIhZ z#JWQX+9z@RU_T1frLoY*$MyZF*ZZb=l+?-`V?}*Shik(KB+pJTu7t(C=$tw7D(op4 zhzOyB$%lymKKp#sMb&=&8M%)mzoHgm)^U!s zaExtqhn}D86>O8mNsT&rHTdMuU+tVu3HW+w574ccv;KthAFh~JL0PAB&&Hw^D=Q$F zki6xWDM(ba>EDo`Q(5|$B&zCZY*u+tUc6u+HbSDUR=bh83#Cj?u6x6aM9(mS1`Q`D z65&>~d-E8cuLmE9AyHQ%_=F+oAgq@qoFA1hD^{Bcz|jB!senQ4Mm+qsHGUj_L!IbK zfSO6Nyhtp!MxDjYNo#?ags1*7Sfpi*28X)mG|C;Ii=4wtVcBN@P+`--PTbw7HUw8D z5DwjrLZKr!VUkl?E2z!d>mJuoe$}G{me$~UF1w(zer}<+`AKz?QG#J_HpbO%{mnN+ z)2fP^TuvyCuEtGj#w_ean>Br{=|h+^ET^eu$649*$Iz9HFYG-`{U{EIzLp(yw&}SN zb8|Qg=*XYH;luXx=}_Q!TsZDjsLrZXv$H%l0-nIXMjwoi6%5pphoTY`>THs+^p_7< zR+2a*78*BYa5=~pLm{671E-b7L|BD8!_)?Nf9OFju1KQP2PYAfwdbLP-_(O`Bc72T zA9gJH87TVFEO&DjkZ**!xy#ll6il}PWFXB2j8r!y_KhT9hugIp+gJB1$>OLP0~K`y z8|kdz!VMg_XXbKm+6b|lF^Mkyi0c=wFpnA~FnhvN1&Zt2fO|t=pQJ#nTtCDw^+ek8 zr)-WyX1{_Je^3yVgI-Sq<&5VuU%xRQ>~88S-&z=Bm(scf!WXg5$VHqGP%hG~n-?tD z{9Fz2lA83p%v(9}>fzv%vnhukfh*s3hNCxR)g=g?-&t{k0UBXitv$d2Dy*T7b08iv z>u4mU&J4leOwbOG+Hpc;au*A)ayLo7^`!DW;&NK~k(WtYReqeIruU9i5hD?o|S1BJMnh~6<+{>X2wPH`w?(O758;f~c} zQYBR6|J`@0C}KE|(gJQ_NQwUslzCkD8 z779}5QdEqPfI|}dP>uBR{S{Z<7&Q`et1A%?mRdgGbg-TGMR5bW>jt*fnhF~|`VX#v zG?p$Af!b&W@RiNAi&-dmRnxFz3V+d2T{Vb^4~mhA>W#e9d#Bq8!UVz!UXyR0vgI>w z2>sBZp0Z7#Q|<|TlyOpz6wYitSo?Kv!PN0q!_b*rl?Eo9yP zS|!I?4NbQ=y{V3WP+Z7A6O(;-IOyvf))pRtW^$h;V+= z@!YAjA5NT6MNsd;%GgIr4tmsdtY5d&wnS-a_m=t;hO^x|jFTv>!<>+n+{48AlQXZD zcX1iNEdK%#=X#A>J~eoE-v8CTH*`l4K)gHtW-tH%9{>&Vr+fe3Indvo{J--dkoV7& z_uBuxx5}i6KhpHz^N{YKC2x8jTM?K9XX*f5oqG^d?-!9EN_MZhC6T#VaB8+`2eK)(D zTT=Xb(T$Sz7)vBup-`f`iEv(#f-g1t%J(qHr-d+OT#NiKz!xSsn66*p(wTMUrq-FO z#liK~nsG(v_`cjf4-Pb)_qv{$Kq$iehTQhh=a{Y_tiU zm_zzAV`i4r#emaakYQJF%JDW=WurrR0~$q%SSK;-phuShE1lkleyDFJCXeTiN6x;` z04#iIAcp6tVWtGcfjfnEqBXfrf7*%1FP1)_ULxwuZq+*dA@Oyv`qj>QlLMg>(kyOb zolU-dN6B!LjmjI|?ZS7F$OR8lKd63a0kNCwtmUOHU@asP&J^K21Raoxn|TB-zWuY-e))nd4J6>7KkONiwY2XhQXfFo1-AqvQ%m7 z)#skf7n#*Pj}}q=W6-HZ4b{{ehsr*HT;}Y^9A`NzSLyhYo>#BCgP#o&J=wljBg=(E zz5IxzMhP9TNwswMi|)B^FApXcKNU7!ZwJ!cc!4{)FBgXm8-8ybw|#lH^GW6c0-jH| z=AV4tLLh#aU$nvt^f7I3LUKd2SkhrxWB>>n(vmnMKQPGLB*piG)8N2)(UE}pnn1ub zZbA+>?&wj>h9Eq=UgZcqFdEAQ(0@HvvH>7bk%Ns^TDMp4)94sw1mBG;*GG3CY(?0f zZKb9Sjj0auHJ9Ow59fJCNv8E9lS=~F#Ic~YzVY`h)gFW7FpnPU`o}S13)--apzyO7 zlp(iAnjEI3#N^$y7-a=@7z#$ny+D6Xmu%zsP**1UjdADMf!ff<4BkXp{7eL8S(31N zX^xQ->-#J*33{}7xO3LHTr=~5ei*a8*1DgddR>GmD9~ouSJD!Pt02khKW7t1CSL-SCq)pZ^s%F|S!Dca7ZbcbBrY(iRfjMMs z7koktYYCAXG_Ss`)k_vyDSaIig2TLHLcvi;uRr2qRHQsUSKO4;I$~nto1$$mHVsWX zzklbU$JGA`SU*%W-lY*Q1f(ZLdxl%xhekCCBr%Nr0QubPLMsM;k40j|V_Ek_&Cbql zr4Qk@s(^BE#F-}Vt@@Fd^6S&WS+vEhiE)oEkPN1Z0$}0;VVa_0D6)I3IXT3;ZAbAz$xd3FhjtZq zY=WtmAfNX*Jj(mNw`3{2*u81g#WMS?^Lm=E!o9>*SWNFwG_@f+P;{K4n0pn)^1+ib6; zui?l?q<}{zz4bAXD#VBkDem;l`OdY)p-f02!#GX6z#d^+oC&(riQycH|mI2`7p(3Mh?^@CF_KMELxjn|1b7E#uUOX(-?6yLE2+ z6qYjBmm)1k|5BCN9DyHe#0JJ{yS_ncsqHP!dhVZ(%jF{$1(2oZB1hn@BI`o5XRMWZ zh63|g*C|*lCd04!5t<9t36PK5m0R5Ot!H<W z*02mm9Hu-sAz${VkwV#8(4ws;#AmBq1N{mYkOD(F5P98MFNmZI!>R59ZO$To)hVby z>UgjBT<`Pir>&$FvsSCXsF*l6uPrlV@GRixy9k+FaBYiLh>e$y*>|4Q*04=e?l((aPmS&Z!W3e|?j% zYHT~*_30nO;P-xuWD;-yfEWI6AIr{WE-sdK=FWeFz(#dj`&CZ(SHG_>VPA8BF{evX zR&)f3tZi-<%|??Bxn?@@!AAq}yT!{6Z!c8Kk+V%4tay700_QZ@d4O@q{H4{Ris)P$UG?At_*_>!B1J<|_!*Xr61C&Zy zkbY^{xC2cc8$IMa2J;e0hNOEzn2tcnI-T+PNV%W70UM{7^cd+--FlzJ33DZo`AM<& z9xi!frN)>5V=9Eo*+VScSMdyWy$6edT*OpI4OD&kQT@Epk1%O8E_FO{lb>h4E|J8z zNfOY0XWYJK$0j;NtQ>18s44pj*-n}vT7P)n{7W-u&8{t;st_45*$9cI%)F50ZA);x zpW(7FC5ty5!t^I>@gxVarhTre=Ki!7V?Bk5y&-_gL#Y_o@`JQ$2z3(+T?ux;hHrgJ zc<+rPsb$DGVycx=z<02~(-@JSfNO$8szuFWjL`sF;?~qa?k-^;bT5!3S>eJa zOt)&+ipGot!(Nmi1c3~1Yb8T8E&7pTg+Xl1b0MFjD+vkEkL_d-Khi}@o&+yp0~JO% zcy|WEv@JoS-JV{=!3E#|&O482$%FffTNvW)p{!jAEZ(TJ(&cOk%ELPPg0`I*EXt{x zfncCb&7oJs$|trt_KY-}G`^%gO?_|v%r5&5U}l~ISlV!I&ZTbg#~VCSI_E*NS0PA& z!fgXs#5YRw2D*b=ownRTZs7u9J-Q?A%uxjvkEqP|L5B0G zZz`rJNalrU32!l8he(ta15v}wnNUVqS?r{AOjs}Ghw8;uUX^v4A5x_Py{xaP85wai zI&;y^F5vs4zm-U8nO9nfw1S(QHPgTJ6bNf#OyZj*s|?LDW^LU#p-_i zX#CiM?mD069Z_Damo1GfRz<$`6w64d;hM@#i>UGfUha8$D73=sdbmu9J31Bnna6Z& z>B#uUTV}JFyqT3WdX17ATS|^?P?^MtTM3v-HtrAD2jfQIGP_OPw6RgpGFEcd=K!~k z1JnGZ&j$#fZI(tzD5JQwPD~vs@wk?Uhus)g$#hxor(NtUcfaJRo;W(rZcT}v!H&XY zdw3aYxi{#tVw1xb3qqvDV}3XKq(v8=D7@RU-yDtW*$V&5f;WfN!3GGlg@P!$gJbw9 zxm7TbZMl~2M?{~NG|!2Dr_rD`7iO@QE4OVXfG@F_7PV}Q`nc6&OVm2`TJiRe4u$$w zBYFJ&(+ui8sYd;GUTx=UYi#E9?o$5nDC23Xv8(LJq33YB1mNrE%9LZx$o92iHnn1S z=);&@#pElfsZaq$KCKgDHz-ermofKZ zHG7{fVQ$q)GI#4Qec~6;pRkd!97mIdpoH^QNPgMcUk9GIpa7Q=CDScHf+{SshTwSS zx#N(P9i_3=7wMwDC>npMG3kxhtg27XtBQxY!e6A$b)q&dKzBG}+AuU*Z1q@-OO@<| zFad*C%r-6?Is57WB|>2l`%y2R0~DP0W{qK#C>l25vK$OnJm6~uq9t?e4N(-_P(mkz zC3ozuyHtZ?(WImCIv9gfpOFJOSwF7+9xfA|LF6ykuUreu%!L_0z-D3a;3pr(pyR%l zlQRn7$flD}pbEbf<%fspNfOTAX;gJN@|B+)7dL%q+%VsAb{2KZq*-4Y=vB+yvvo5xv1CkVkDs^)Ut(MtU){HxQhe^2yHm972U!|=@jAz@;(gF=HMfZB3XGm7?#@NBMn~lk-f+IxGn;YFbJ9o35m75`U}iQGE+P$`H&C(RgLb78 z)Ho2Idp0@FRO2qIiycYID5KJBLoh!yO>{Qd zpx8t zWcLHTo6#FtyCBx(xtS3+gDV-SRQjc1X$ZWlf>)LLfZm(@K{AdaRyqn~s*{OuQM zpS4^576v3~()Ht3htA{S7)%Q zmGY&oN34Gunt>owm{LUs0JzEk0HlBSeP8?!%Ci4(n5r&V!O-;MGYDD+%6B78kb zrFz=YR5Bgw#g$l-k&$a;?8tCIe>nftl$wn;5bS!U4_?#8=!>Zpblcy}A)TLCi}6~B z-fnF(zzsb0ziD~#b3bi4pkJ_#7jSm*5c#%s`8l$~Mkanik*QD4jU)7AdRkQY^tKv@ zR1_ zoHHP$%TI_;L?|x-NpT*OIPueQ*uZ?tYh+e=nP`_6C0t9JZd*+$pYKMo`3oxjJFpF! zS7KIVIfyLP@$BKIQv0DZ6}{dyBSReB|5c}-5HKjpi#l^C4kcBWGWG8L_~PuO>$ZG~ zR#0hsI-iq=v=~6Q9uM|p8m>ZtJ1vgrmvbvjdf!mqYuj5q)@sZF|ShKV~njw$x4X62$9_D56SI}{_4S4O31I8@axUs6#$o5MJ|7)3OBJ- z(v(<@ZTrFP)`V4_f7y+jc~X&|O@u(5USdNfPwM!j_}u>yaKwNg zhC9QFSeNgJuPwa8Srj>iU-y;% zqkw!b2rgb6+=tu+*4DSyklfvG?%q#TUbcFbV|1c1%Z&BXWSMJad?ZKOEplhXm4Qf= z&a}MPm5TdG1|L#kHY7Az?pySmhapn*Xt5Z0IP? zCJGs2Q3Q`WD{*|F<+n>x)gh4uy&e}1eY&9ATB-YE0?S%Y!cowSL z<(J{RYC9+}m4kQ;bx6jUbd(nMmRA{Bx0N;+Rl-N)D|o4ux4~|$E1Fzu{kR~yL!Lqu zL2jC$NUu~S4TEuD% zalWmtBAo}V+K|u6axt>{r)g<@lwp=tf%!FL?{lY+iKrh=#_3DOy#iNo6%X1G2_w&p zOC1#+|BaPJ-XzhvwC@?|Q??mhoW(T%p6*7HsuRgKyk^})DX4&EQC%P8%P>Rsq6ukOB634h3#}fO#%5}JG#WED(z_Ho9(gWjw%i4yf=S`^N?UG!W zBTLd!E$^Wv%xd;ov(3j5ywnmtdZR3JKKc}S4!Vw;i_E?Is#u4WJptF)pAOx#48Zaj zovc%*qLumy2!)PL3lW-LG3?O_i1^QbnU1UXXmP8Ag(MvBQ&V=yKiZu{TwqRE-f+iQ zcqlB&?~Xbs1=lo^4)hbQ(_D*>@9?m)p9JP^$e{G9&;gj`nLtG3|34TqD7mWP8M$hBASO+)ARLBpUPw6+ z+YQ$L3yuNv|DipX$C5VD!}f_+XoFjqA9WjV-%}3f%%7F)@T}H|%8yd;D&88P)3n@( z8u>jq)gQ$L;yqHoWzZ<`FjTCz9;HIhg-qqvwC7&b%|La#jPSzcS7(4;NEyf|s${sd zb=txtc1op{tfm?+a2-Z=HZbgiR2^z*{NnU!6D)r?mJ@@fT7~<6@!Eu0hWVR_(*6I4a7jFr5Db5ng)07d zS1M30lp0-(OJew^QsO|YdB9+<74)7QTkuhVwwe-qsW_8O#twy1D)Cvc4bFC8gV{j> zz1Bj`a$?A42E9-<&7|XUqFg3kKG54PxSO>dMbU@b=;B*@{xp0?{;$$OGZ|aeXSn$o z|1Y>{^ju}{$DdVq>c7aBzr(VubereI*%)-J3ReU;JKpc~|0aINHYxF41fK+7mb~w~ zD#whauKl5h{aueT-h8V~SjEjpH5-3X7RCkg~aL60G|~Jt*4^vhJlz{oUT5 z&EIOsUFju*#*)q(HN7S*W4^q9->J$@3FpkB9Fk)(G7jK#?MOS{7adXfq!kNk!J7gU zx6uL;6lfc;IX4-${a9(WYKlWKai&A6xgv=zp9l-n04l@+<(3$UfE_=5Zj~Bq7Dga? zk$`i`*Ln>ZJ|*ec0d=pn8IR-38A`Ur8!I=j*2*oWr7X5Cex|W6KQ0rv+Ad?XC|m4( z%0n4yj7u3k$)Eija5ZR$gGC!j+Z!S?aBJzq% zMCvN}_Vh-(-jVOeGEFLD6C0i#NXX-J}1|eG6gUU%*UoiRH~) z{&k`Np zjol;&CVULb{6ylPI=?pqIlKFIH)qg?+%6B!+^H+t2z=G&e@uerF+lSWRJD|(G>EFu z`*q5EDddv`mU-j)n&3*?^lVFA1srxYqW(rZ8jPJYGM%Eh;ykxZP3;V`MW92py!vA+aHpVlo{uZCjl7^p}h7}1O2B-Q3yndb=>*QAeZr(<*L(WSxV zE`A?bY9B8rmfu6J)-u*#s*yOuSzDdKPvAbnny+2E?j(Hv$e>rn#q?9h+pTJGCZgV` zc3vj5e8!2b#hG`i((Ns~$-4Db{hnRu77~_R!|<~)I|Nm7`s}UpTR57>YRdA%H*&iZ zI&g`g=GMrPE`8r3ThD<|nX@`!sq{FO>2y%UN}-b+6`F0}poZE8Fl!+QW&vjpzJ5T!|?Z^7Lq@yJA z4aL^x=N{$iv z2yDVl!-n{I*4+n(_vf>#L2T}@amg!Wd`qdgW~(x1XhapIs+S@^o_r;%Z+~+d3SZ!e zohvLm14{s^g7lXX;izV<3{G_qePgrXDZ#5|md>S-F7$Y&NFJk$^Qg|rIL44Ygy%O=x7#Dk=0aA_F$v(cb#MyB`P=hcZe=_dXcQ&JiiD;91*v%jn=g z9Cyio#nDd(9yhJ}wjHlLI+@Ge!SGwSK;R)bzcZFg8&}a!UToP~O|-)MsEwwDdhd{z zoE&}G>^~w@8W4*=F`E{(GB(s3szu*MUw@#jC4sMllmN=ysEcMkA++>;vN;YA)rl%y zTsdg{xx<@V54HnTs-6TxG8zSeo*3BKKbsynB&UG$`fO&@Z^z*{xl2&$fFfmOIl?O~euMisE4( ztha88x@1N0`l|I5=!^Vub*3@;xveUC3`1Ujn4o>VZlsIu-QRmmp!hY#r|a{N??d5M zTGQ&CrhE?bx540#@2d$^jf`!~{um72O_7SrVnl!E8a)vq-^0iZmrIE^h#h?in^fiF z83eCb68EDR>p5>A){zp=50h34LLG0|7`hIVJ0of?xLA+{({S3C=$gJyFQVCVV!Q6? z0iF$ZLxm0}qf6Ik^q6c4j0=2f-;iY?NAO4o8qpk#PsLD|2mx5l0|gaQWR1;>8$Un- zZ)uQ4-zrCW%0;E%4Xy&S^pL~0rtKM@Fe68q<(H!hQVhSh{t|2ejgS_elv$c(Z<%J7 zF8QLK46>OmrgROyb>$zCh$-n%j!`;(USx*-qOgr2!w#ildB9?Zyn`v{r?FQQ%fR@FPHMS~Cj*|Y?j3%Sj>LFDG zifOc%iOwQ`zljp!HWSlFoCCErjC3NHiH0!Fd=%hFFd4o%U`Hf}Gk}X=(9qtp8@m5I z$u_gLVBij7U?c%ChHNx3R6~l=%{fWxXf6B3D@CeS$_9>N}UP$uX$zq!raMd#>HMpcOGk z=c%5uFRMeTVG}+5^_x~5d!jshuyjUu5$TRjs=njpl3T*fTWA!~17^#czJpmuBR@ei zTv_x}82hM+<(wIU<3n&;gbwoUjG55aP%xJ(Ygq#{+msPLa8D0EnW{G z{%GLIs|1l8*nZDHPE%y|tSdUddy3O{>qL2Hk-byL6rJoHoPj3xPJbHaJC*)_sAKPs zE;><9q5lJV=(*f4B!qkVFKm9SdTFK0^Qq~ag_nq1HvJgV{#D04Y0Wz3I}DvXL{pwz zo$(4t_3(Fwm8Emw2~^@BRO*iT3urgZ*&+8-wXrnvW756gY=$$9t=*#;lbU9m1FE>u zXog@lMK*&s;I`SbID@ISg35TF!jJpq%!%B&nQRNmwuiV5s6#E9frZ)JkvhGKNRbCr zBg-Gk+>1}ZIr|j@!T0DWP=1i;^#))A|VE^p7Jr~tC0rig9!`&zJ14M##*e?9;!2LW6A5nkr%74 zVD|D0I-WvB3;my7B;eir|qRdksaOPz!>+;4!1dzQ{>5Q?r{v2#m4;j4#E`6G#}y^8=5GZg&p|-}{@z}3 zhTNW+O>E`oJfHB^U+-Rqb{ifW^RC-!?PHCR1VaBJl7N8Hzo%LMyln7)zm&hqe^^AQ zDD$5R{&Qi|Ur+!b_dUD#+cKx$fxoZ#_zT+e&hY#%>py;n|0kpPFE9X*^UjL-|Kb<_ zuIYDD>0i3`5dSX})8AG6PRRL7#mW1O`kxo`cY4n6@ZYE3|AO=3{tNyelkvaff1kqp z3(rOP@8Gq-_!5E!0inG0{@nb|E}Tpgz+y8(v1Jo@E_^p@A&@=>wlpEfL&$) q;J*a<-{Jr1YyS?9W&0caU!GS{2IAek008*+AIQ6fvT^=#^uGW|^j)X` literal 0 HcmV?d00001