From 617bc8f36db60b5f71b305e987d9ced278f6448e Mon Sep 17 00:00:00 2001 From: airmang <38392618+airmang@users.noreply.github.com> Date: Sat, 3 Oct 2026 02:36:48 +0900 Subject: [PATCH] fix(layout): lay a table cell out at its width on the table grid The cells of a column need not be as wide as each other (hp:cellSz). Hancom lays a cell out on the table's grid: the columns are stacked from the left, each ending at the farthest of its cells' starts plus their widths (and the table's cell spacing), so a column is as wide as its widest cell of its own and a merged cell wider than its columns widens the last of them. A cell reaches from its first column's start to its last column's end, wider than its own width when another row pushes those ends apart. Cell lines without a cache are now broken, and rows measured, at that width. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 7 ++++ src/hwpx/layout/pages.py | 34 ++++++++++++++++-- ...ble_column_as_wide_as_its_widest_cell.hwpx | Bin 0 -> 7992 bytes .../pages_table_column_of_equal_cells.hwpx | Bin 0 -> 8000 bytes ...s_table_columns_stacked_from_the_left.hwpx | Bin 0 -> 7934 bytes ..._merged_cell_widening_its_last_column.hwpx | Bin 0 -> 8000 bytes .../pages_table_with_cell_spacing.hwpx | Bin 0 -> 8013 bytes .../pages_table_without_cell_spacing.hwpx | Bin 0 -> 7992 bytes tests/test_layout_page_estimate.py | 27 ++++++++++++++ 9 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 tests/fixtures/hancom_saved/pages_table_column_as_wide_as_its_widest_cell.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_table_column_of_equal_cells.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_table_columns_stacked_from_the_left.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_table_merged_cell_widening_its_last_column.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_table_with_cell_spacing.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_table_without_cell_spacing.hwpx diff --git a/CHANGELOG.md b/CHANGELOG.md index 22f7af94..7ffb4d97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,13 @@ 높이 그대로다. - 세로쓰기 칸이 있는 흐르는 표는 쪽 끝에서 나뉘지 않고, 나누지 않게 둔 표처럼 통째로 다음 쪽으로 간다. 기준 문단 줄과 그 뒤 글은 앞 쪽에 남는다. +- 쪽 수 추정(실험, `estimate_pages`)이 표 칸의 글을 칸 자신의 폭(`hp:cellSz`)에서 나누던 것을 고친다. 같은 열의 + 칸들이 폭이 다르면 한/글은 칸을 표 격자의 폭으로 놓는다. + - 열은 왼쪽부터 쌓는다. 열마다 그 열에서 끝나는 칸들의 시작 + 폭(+ 칸 간격 `cellSpacing`) 가운데 가장 먼 곳에서 + 끝난다. 그래서 열은 그 열 낱칸 가운데 가장 넓은 것만큼 넓고, 여러 열을 합친 칸이 그 열들보다 넓으면 넘침이 + 마지막 열에 붙는다. + - 칸은 첫 열의 시작부터 마지막 열의 끝까지다. 다른 행 때문에 자기 폭보다 넓어질 수 있다. + - 줄 캐시가 없는 칸의 줄 나눔과 행 높이에 쓴다(`_grid_widths`). - 쪽 수 추정(실험, `estimate_pages`)이 줄 캐시 없는 표 칸에서 글자처럼 둔 표 옆에 글 앞·뒤로 둔 개체가 있는 문단을 지원 밖(`a nested table`)으로 두던 것을 고친다. - 그런 개체는 자리를 차지하지 않으므로, 그 문단은 표 혼자인 문단처럼 표 높이의 한 줄이다. diff --git a/src/hwpx/layout/pages.py b/src/hwpx/layout/pages.py index e92dcb9a..5f2ac633 100644 --- a/src/hwpx/layout/pages.py +++ b/src/hwpx/layout/pages.py @@ -782,8 +782,9 @@ def _table_rows(measure: _Measure, table: Any) -> tuple[list[_Row], list[tuple[i nested: set[int] = set() # rows with a cell holding a table headers: set[int] = set() # rows with a header cell of their own firsts: dict[int, int] = {} # each row's tallest first line of a cell of its own + widths = _grid_widths(table) for tc in (tc for tr in table.findall(f"{HP}tr") for tc in tr.findall(f"{HP}tc")): - row, span = _cell_row(measure, table, tc), _row_span(tc) + row, span = _cell_row(measure, table, tc, widths.get(tc)), _row_span(tc) address = tc.find(f"{HP}cellAddr") first = int(address.get("rowAddr", 0)) if address is not None else len(rows) cells.append((first, span, row)) @@ -818,6 +819,33 @@ def _table_rows(measure: _Measure, table: Any) -> tuple[list[_Row], list[tuple[i [(place[first], span, cell) for first, span, cell in cells]) +def _grid_widths(table: Any) -> dict[Any, int]: + """Each cell's width on the table's column grid, as Hancom lays its text out: from the left, each column + starts at the farthest of the ends its cells to the left reach (a cell's start plus its ``hp:cellSz`` width + and the table's cell spacing) -- a column as wide as its widest cell of its own, and a merged cell wider + than its columns widening the last of them -- and a cell reaches from its first column's start to its last + column's end, wider than its own width when another row's cells push those ends apart. Empty for a table + whose cells give no column starts to stand on.""" + + spacing = int(table.get("cellSpacing", 0) or 0) + places: dict[Any, tuple[int, int, int]] = {} # cell: (first column, column after its last, width) + for tc in (tc for tr in table.findall(f"{HP}tr") for tc in tr.findall(f"{HP}tc")): + address, span = tc.find(f"{HP}cellAddr"), tc.find(f"{HP}cellSpan") + if address is None: + return {} + first = int(address.get("colAddr", 0)) + places[tc] = (first, first + (1 if span is None else int(span.get("colSpan", 1))), + int(tc.find(f"{HP}cellSz").get("width", 0))) + starts = {0: 0} + for end in sorted({stop for _, stop, _ in places.values()}): + reach = [starts[first] + width + spacing for first, stop, width in places.values() + if stop == end and first in starts] + if not reach: + return {} + starts[end] = max(reach) + return {tc: starts[stop] - starts[first] - spacing for tc, (first, stop, _) in places.items() if first in starts} + + def _row_span(cell: Any) -> int: span = cell.find(f"{HP}cellSpan") return 1 if span is None else int(span.get("rowSpan", 1)) @@ -953,7 +981,7 @@ def _page_break(table: Any) -> str: return table.get("pageBreak", "CELL") -def _cell_row(measure: _Measure, table: Any, cell: Any) -> _Row: +def _cell_row(measure: _Measure, table: Any, cell: Any, width: int | None = None) -> _Row: if _vertical(cell): # its lines go across it, the row as declared: one block, not split margins = cell_margins_of(cell, table) vertical = margins.top + margins.bottom @@ -977,7 +1005,7 @@ def _cell_row(measure: _Measure, table: Any, cell: Any) -> _Row: drawn = _drawn_lines(measure, paragraphs) # lines as Hancom drew them, below it or beside it size = cell.find(f"{HP}cellSz") margins = cell_margins_of(cell, table) - inner = int(size.get("width", 0)) - margins.left - margins.right + inner = (int(size.get("width", 0)) if width is None else width) - margins.left - margins.right content, lines, pitch, char_size = measure.stack(paragraphs, inner, caches=True) # Hancom starts the cell's first line below its first paragraph's spacing before (the lines as drawn # take that room already) diff --git a/tests/fixtures/hancom_saved/pages_table_column_as_wide_as_its_widest_cell.hwpx b/tests/fixtures/hancom_saved/pages_table_column_as_wide_as_its_widest_cell.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..8762a90f3db59ea61875282618362c643343c72d GIT binary patch literal 7992 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/pages_table_column_of_equal_cells.hwpx b/tests/fixtures/hancom_saved/pages_table_column_of_equal_cells.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..266ab6d18af3a4cfdfd59b8ae22ff97ef607fc39 GIT binary patch literal 8000 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/pages_table_merged_cell_widening_its_last_column.hwpx b/tests/fixtures/hancom_saved/pages_table_merged_cell_widening_its_last_column.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..c21cab35419ea129a4d6e20ebc838cbfa819af8d GIT binary patch literal 8000 zcmZ{J1zc2J^Z(M_ExC&z-L<6D(%m4E3oNyCs+4r6v>-?bNJvPRv`R@yw{)j~|K)k! z-|O@EdH=hgbMLw5&V28jx#!H>nbA~1K_vzJ{R0Am52Y1I5Eu6i6VaStPEZeD7pR4c zizCd+!UG0(=C<>8VfTZ%X#R^)=TCtKhB@0xfb?`BoFX6wcMl6^YYRuXGgJcP3v~xENJ)y@d5J2@LiGPeVnBd6 zyNlX+Nr3D;JX}P%xxKx;x$GI>x%qf_dAa}dG!TP_g)P)W`nU8F zAOj6;IZbU1S$Q2D4Q&vElZ8FpO#&o{=)s)td%X8OD>wLGJxfoRqqVxHlO+^!2O&4y zT>``hx|iiYV%^UN!TS&WNPrao5{f~?#s+2uWk6indOH3^@?Rbhx8(n+?_SG5z;p8_ zM^Ib<;6=&bx|fAJdqAB%+_~+b7S>R=do}KvYQSgv$$qh+Ueri@A}$R`t6m7@7^)^V z!sck4c|sghlGraeu$)vNvLGMCS&v5kBVWQgNWM9o%eZ!i;c-ZPc%EJR$lw)zj?_bW z-k66rWF~KVCDUcUW?i)kpS(D+5wUu4IzTd%LMJ=LpU}$9F6L_#TpxxWCh`5%u%AMM z7j&SzgAPD4<6_qKGMD4|@sUDPTd^!pLd3_ty)ARINnWpWx5nt`Xj<9?P&qB$UUoD1 zwyXMccBVlJjSCGp!6hxpB@hR~<#Jk@on$6clg+TjsaJp@sOm_h3{z2p^@rw1w54DQ zF6vr?U7D6H)}Dr0PHJnDAM$v>!R7)zKX4bhwqc^Rfo28#xYp=8IwDq6bJF`P!Xs`Y zFUf1GU+H+IJV~JF85BnUnt)Yu^^8d&SKS?SY%m@a{mOn4cCMLkZ}SB7D2&(@A#Jqs?Q4Ku5;UB!x?d-+2YjDK6CRc29UaTFk+H*zU_! z^4D0+bRcSiAasd=juA^e{k4ooNmwOi^i$s(hK*~VQh#vV7Ra*3J%_$Q{?f+Xes?}I z(cYeMb7*<|bJ6s6i#>R44A|h`%4o#b5;hSYf@Fv??@+ zwXWKjrg7!*jw!`L-(*MAthsqc)yVCJn~wP!?a_ISf^V2yVl~aMKI&7LWzO+2e=5u( zNOY(!gyO1pZ^Y-){Pg6ZUVqkVL#Df+d$>M6WfsspioF5i%=xxkVO%*wUeN}vP|vJ$;SSQGXLle+lLL__&RGl4q3DCo^>y^Yikw%M>xfr1X*YblU7 zV4ksCfRUs%n8u%c8e@m+WjIYaKKhSfQ+w+L?0NE#vHe=5^bv2MNTuxfu1r&AFfiZ; z^=JN|;-8T9s~s*-=83wEkEcKp+8F8USLZ=q3u^4vT|i0m2cH#9DN)LkpNK_S8`UDI z%Dt5A|M1$JPF3wHu7(nPz%rvi$+$xsih)iEq)u-$Zy2|y;{s-6!8Qu@4dlyg-%oft z!4bkO>Xs+dv=sqi3|pWF!5lTnHQc8B7%_tjT zWbV~i5zr;_zTc_p6d!h;3w{6Psj6nA$`0zsO^Zi3M}hx!q?2RW&}Y z6N`+w8{De0;Xo9}A4gi07CGm%p?YHqPoi`WAd`k$(~_Ji?+8g%Dno*|JPYkIaj}Ot z8GANQEYK`gedXNWI2sPrM#0eddo*z3NomPxylm{e+I`ylM_qnMx7aUPWeM=arr6x% zdSok3sh=VfCs1t?#=0hCs4#CZHLmDghVq1Em5Q?DUj>@ zryDeG?0YAg;X<%X$L>ntxlO0HOxq>)(p#>zph|rKD8s%?>#$DS<9QtSg;vZtwM+EJ zTQjuQ?8(PEFVIf;SYAIpSs6%mN%Hha(zd?Sit~^BUP4Ns+@FgRi#_Vi!ryVU-(H9c={oolm&D@8kPtZ#*62Mx}YbTa*>fN(emHq>s}rh z*t&es-mRVp=h|u}61;J0S}p**3ZH3%{?bE#-t4L>-1DA2gjQ&c!^;ncOLvgnXKNxk><6p3m;2@-sW*+|YX z(7mz8JkU8iSe*LCm{WgHFE&jiRO&OIi`nUUVK1!@wh8Q=Mg35-LamaIN=|yJZ;fGlv)kR_Z*?D}3YSz%J~LE*YqE~+Q6{XhQ_;Iz zKw1Imzq4S9ecCKsG9^|=JK-W68#a-(lj?2%C1O>iBs>q z+C*AkKbP+%^JnzQ`Vb1*Dd4C?**cBPW?Rsi&?rlbwBDxjIKMGQ?I#owIWA!!Uh_e7 z#}Ur?(dfdrvqv&j8&n<6mnTxWpd#E9*Yg$}zlc~<`;HLetDUalzAzk&hG`(b6YDI!GgqnthmlW;QZ9c3qw(?R+8uyWb zIF)+ejRyfZ@f*_Y5NTCBo?vdOCaUWjlA_21+{T2~6}cizP&A3rTIo_Xc;Q{jafa)3 zs*VxxHSMY+epcxR$0E5IRZ|Dio$Rw|{!TmL0Xr(U@2UKmnLxz-0y4gSyD0P89m`q{ z@ZKO*Mf%^P{QY+C{vK5;*Z*p_j!R|hPFay64PnQGG;=|Qv?*)cAhTZ*T!q3%2dS)U z-~2_a9hU929#gc&Z=Lfczg8KYwc;VmUK0za3V+#zj&WKVm2mi&7r!D5Dh->Gho$0z z_qJI%RX!Xeh~G`eF`rL35A2VQ)g>C)aC`vEK?oq2%p^fG)cbxatSnR>GhO!myJ^Py z4FjUoa&`{x+JW=}&8|Wuu11i8crvXSAtRd*JICj7n3#04%5(+M>(R9J3F)vLgU|Zb zbafwNd8pRWl;L!~BezUtx5qHKQ+N(j}zKx9s%j6&czqEH3}z3(rBpw)eB* zqB@HYJg_1D?J@eqG0c=sd!}9|logkgzKFSA4B4IFV?1Fm;Pm^@s617KPDzwIx{g}^ z?59`#eB*6^@7J7J`A^g{7hifNaGlUiZuP;gkR6DR&q5@6XZMGP#$@8zXmnq{&6Hjo z(`WKo<=}xu$toV&9Gyng zymOME_6@Z5lQ=o!ATZ11H!C=72lVcT(-$mxmE=rXM>dVNiThrio=q*@oo=(Qgq@ds z*{|Ee5K!HotxdyJgS6*MkJYL*)n0CKl1vwD0CR%KBGpt2bH*!ORl)XA5GA>jN`qvI zN{}Z0$PypAoDr^^5{jG}^6~i4LFL`0t~N+h^iFsog_6#bmrf8bw~I#H9+^%sthkC& z1BjQqLL(lEDjrIiyJ9KcBjBU#en?7kNNVMy9DS5Bw!}KzsiWMX6Sd6B-K(P>Qp|^; z0Y=gQhZWaQYB1sD&Vzl}uzc8f#has#c8fZ7azbo{k%pbK1JVGxYCSI_KkYKUV`g~Q zOT;-En&PpR-TxJdbtBo3mmZ@|PD)#wsE(M=^Y)|HgTN-gJ1N-lF#Kr%1+CD2Vu|ib z{#CGr>Q!U6A&}^sS-=T1%L4&!jBVTaipXpU-*fxp28!hNU%=qV7w>oQL?$R{1oPLm zwd#+_zuuiqnB7q$xxXZ=Cki{tB^A~HB5AM<>Jx+gkK+wK_&hjYGF>jTbYx1bc_by7 zBOX8=p2 zh;2ciIC55@=+on#5CJASvQ(0#LQ5yX#JcAq_PFZe5SZ7gfkkb=*afY_|4GwBO7Gb3{lJ#7N$07j2|mSYH`D8{1hd_N~IH zb+>FGDrfY!iz&>^!bGqLpjrIM)_;*wim1q;4iva)>G6Mi)h&biHQHeX$>OK_Y z`716l{^B+ZA$~zddY%#zDiw@sl&?dmWb{t+rE+2U;8R^$b43Ppp6SjG0ncO4N|RI? zZSY2t30v`66?cl~0#Jhg(#le7PO&KU6PrGfME3sHT~T{3U5e!0nmjT4Fz*+}Bz(P9 zMFXxU6zXPT|X+2U@xOtvg|nyT93x(y-*sTy&HM@(oW`)~HDT!OYVKRB!Cmw8(}0!rH=ZE(9~Lp0dkm;^vjq z-L%#|lX0ye-hWGMNh-kh6HEaCGkTbmG5N!oSZvcJ2S=KYcuiW31TSQ>^W1tI^|ny) zNR6ad8D*x7mmEZTvDA&;Qz?Y$e_?8`p+}ohW=U^a7+;#QVGe>z$))VoReU)WO;OV? zBwDrdHxik*HsA?BJz*yiVNZj53Rl`(KQxtp91~oG5`4@;U&zvV6?jF+r;f5hK@%hG ze;$~OjhT$c$Alfm#uM{s6HS8JY$Y|py*}2J@i<4ch*E+iNn-`1L=Eorhz+H+NFgun z3W3j%tS0nR=yH^>;kKKvMht$Vdsn=$J|opS)0NXTMs<9o$bkg5qtwSJDp=1ZGA}9E z@#B<~KhoT*RS=0Y-@9J1_o~+<)2SaCt^W{t7);?t@J8yK zyqMSu%WF-gIIa4!_ZM5j%hH+?@xcNpse)tKORYc+P$vIAZ;?zsofz=tt>117zG4hF z7McBt&cStW4)R?YOWdqm#eiqWm8pC3L#tU>in4>RqR^8-m`Y=nhsgUr)I;nZ#7ykxd>W2Xn;x0$nT>T(Kf2WI`rC?WFHrrIeK)^-RJ)7p@b_ z5VG2PH{57g)#}8QV?B|#=;}F|A<6BQkK0mAA@0YGG8m0k z9*oxGeEzA2;{ujacgz_|cIg$^x0Q)!Wq;7{iZ%!L&sCb~IA9MgPF5A09u8Cbs6d z`>&-La%15w$ywFHO`@+qlf#33DGXdWB9PsXwkbs%#l8Q3XLD~b6<*ySdU z5~lk#02+OlCQW%kl{$*#o5>~fQYh=mu*$GiZ79E4ns?_1A}K?;Y;djo$?WwJ)}S$r zv%;aq*VlohyLR69#(L=JfmT%g9#W74qs}6sX6l7 zgpWTxuHu3D4XLbm9BM~8VQ`h0$;0G{2Gs(Sp8B2q$4wJIsl2B4r%i{zss#OXzfNxh z%$}dkKVIfcaoIyhRt+`VdJFVCm?v!;Z41$aYfs- z3D9)KM>_1CKW_2CgymRmP|^IJ?iidIN~)Z_C^`qkBSlZ-5q>2Bm{uqw`KS(u!K?q2!z`&cN>#aQZqKECdA{MW0!qoQQgjKwK6 z9PnqskL;auDq~qf0xf;GOiYYY&zc_YKqV%#ET6E-Z^hw%`{4zIZ(piYaeHQzPkuJI z6ik`=QRT@k-B`=P-zNQ}QyNwHBjqa!z+gS{(3Ex1+@&Qr)THZRkqImYb*48{pVRPu zOe>wm_%(**d2fZ_lX8fSxz9zMkExfNwrG!F8sUTCKzpu;5$C#6)*b0$3@F6gZzKO* z#nH*DUv2(Q&kaKBrb1+{1HS21%=pjXJf3g~33PjQ>8)q}&bA^KEk*5$lH!Ko)CWgGbzaDyc6OKMJ@wW8dX^-?E1_He;#gOWTHaHF z7GHvvYTCYS51Kpd?bdOd*Tda!(@Gb`8b154q+Q`RzO6HEAfTNyDV^lciE|PQZyJ>l z`qfLDeUu;aGkLVzm1dr={KcvoJaD!Ccw~CyNjP$H3R(Hq07Sk`E(JEyb00n zQ@omPP%jwNn_JV(OBd?n!R6uOvAXV82Rq0zqAn*Li{{gD<2%ugUX8{fKJjUE#9dV1 zsr}$vmyblz#jb=~gYw-HwH{55ttF@F_{&!?Hr#6;pxlyME4MrmhmIzTI*!>Xu(6K( zhY+boXV4zR!zmD{VnoUl;12chK%|1*?>{Cy4wNH1^G^?PB2N>xpU=f8;5;p)teEno6+izf@KKzm?A$>~%M9MD zWyN~<$|Zv!AD+vW6~igeonAua%1p7s)T{#{cfWG_+S1N(VW@Q87|I_Nl|L}PpMg)_ zq|q5gVcbenC*+pp@$i+xOGLPd9nG^$O5>>_VMm$99TU?&BQ9c>n z5YVhUqd(r}73EN17KS)Z3*>yOgMAji((8J&9&)d-a`=fH#T`pFRwT_5nLqtVP7mAMfqZtqilk^L^-z9r-@PoE-4X0nMk zG=j;V3fA3S-)xwmNDIY;$T;BX@4gIz4$sDVdTu?YSq`L9O4k(9tY(H7xGh{fUjPjJ zcrtzS!*^V4{IZBk`QMwT*lBv8eW9*^U z1Jp*%v1|w3h{@MBnd+7>OrqOCt+q6t$zMh2qj_Q8(eHCb+^|A-o@JQ?ENQzqY86BV zRh|gGt~ysXQ!;psr6GTmF}@#MdrF3PnVvFgSZ|9u8 ziJG~vs!0DEZI1BU&^#H~V=I<|JjQ}VeGgflK@|_*{qn|PL&*N!zRTN(K)s3)f@tM2 zk@K`(Okz;XhZ4)^XE*Rp8d2rdb35Ui%Fv8-JbXP>A5=E7v_yi$U0se96YCpv%BEXx zwyVC!k-wnof# zV}Wt}WLmFvggyARKT^l*UNvj69J+#w-OMu}rRHQBajIi#(`-nxJXci%m1_&|{1u4H z_e=T#$}Jm$qFcWjG8(gMXIwBj5@e=?PYwEm7{Jg(C z>-|Z;N)w(u@GO8odVKQprpKu6Y%*$8Y8TrW~mVrrl~m zAw5$VhxTrdm(nNq%VtN&F`Jq8o7NMDk~U6rn1-)4ggy0Pk^bIXyWIX`kUKH|){4=M=I!<#)%?izz; zA-Y?1K5N5fwuiP@F5b!O!v9tqoPFtuD`LxqA=-WL_g}l^WZ?|6fx3I#+iSsC73^*v zT(nA1?E#!ZE_>H6_#Duy9|e5DmZ@du*gDiqvd9j{h1loB~8#E}=_ zQ?h+)oS?p$ydbG<)zuM`+(Jl-QtRkK;E*KRQ;GAe5EyiS{=f3&pIm=dEAMIl<^m(m|0y2c&+j+m z|E|;h#rN0ad=RVazt-t@)$UJ#KSS!@0QmU-0QhHs{U^kqPW(5-BH}&$510NYz@HBI zH-I%_fBe%O|H=8MFZ<1@L-CIl@-NT!C&r&9{WnGep>N z``w(A=l;7-&-C zx|Xblmb#3bwzj$!klMk_*2z^I$Pep593Ok!k39=lr@wmU?ht!RHFpPdFzgOYZYMW! zAP?|Smj8(LI3F1AKlCFGRQO9MYIQ3shy|D$c4h5u{};)Bd4QY}|EIo3Ez{rH&{86baLF$ zbXJ7V-}XwR%Zy~*vL~8v_3VAUsk+ijiEM^y_j+g|;T*rcm zYOB+2fY6+s>g`Oew}8+(hpbiSPKL@7FS*gdUIs zv93v#PtS5o>9r8g!R5C^8?y1{2^<=G+OPOUt0(i^e3!&mst*U}-0fdXh5OLl)~e)g zQJX1&WY_^n;sfnt=DKO;>XIbZDb8^hcIY(5{3a(JgzE@MN zy-lsV&6#g8Y94n84_&DVWkew>c{|-uKHZG1h9v@gyHIZ>xsPTt>QyMOO_?VN^aL!? zcJa~Tw*->=5`9D7=LilXFULaK2{g8~Tt-_W3Ys{oRZJiAq!Fr=nLLng$_%9O+adeP z8&L8Sw0X170n9vCv+{E1D@L3k$Vl=wv-$+8Cj66B0YV%GV71i?hZ~0 z^H=Q@z9P!TBm&A@@a5-s0yPC}y8yc;zwIEFpEO05BG9FoV=3Mc_9KlD%wr8F5<}I= zcM}SIqPkD#f*n&pujHUSSzEMN#*QuWASne`VQx3~5N1GSM5MBW~C^f&?vB61Ha8;>@xw*GPF9jPz2s}@;&TrtU3ce&7P zg;})=c)WPhZJZdF_zY!+E&9fF-Rlsp(5&|&O!>JbZL-M4mnBnpQtNQa*Bm{sfk%{s zMvZ+RL^7PQ*C<(Cu-*44b=N35MT0$MTMDbxmT9C}*C^~ZDSF(`VuvY29aB0*cHWsF zwq(yd(|&_^!NZjI@_cK9g`IHq1u2T392PQxmW{A9`EP$&3YLpCCUDN1fit}ggk-`e?; z)~?^yfcCvF6?!Mz0-M`B3N22@ybB$-SbT(Xqlk;enszEAwdPG z|G|tt=4G>B>8xlS#k8|vOz3pheu}3pV-DEY(s7(CyA4iUO_Z_jvhYZ;V%n(Q{q7qb zhM>73rw%Xkh8FF3Ki`hIORR}g?x6v#((M{+4tPwQv}23+Y2SSNZoz^h&UQ3KUr4UJ zTOBDz9I=e%&t{HNR4hz9t$LplayZ_)BHG#Oz$t*jlSSeE%S?IfZxAMXn~NE#iUk|~ zE`^lb$U-(3cbNwIhh|nEd}a0R~-0`#G6)x#V4AtTW@*O7%QnfSw_5{#2#hm*k<#5(n&dS?uI+vzB+DU4gV}uC+~i@9-6uT8*tR_g?`FSqv@aALx#1fPuSA-PcW2C6 zmA@#DeZ72t75DDqgoSDBeFXD>V)o%f%O?REh1QDjqg2EAki!VW_%LWjA9~HV?(XxN zjkh~L#BI0Q^Sx%C+)F3Bx^gd;erK7^2pikTSY(PcWSKCvDwDTTqPFGi}? zcL&85PMCsQ7$T^O!{pCR(Liu{i(edZjL{h1vMyVU0*t~p+<3oQExi08`7FcbTZ*9>hAt=%`TWfMLe zB&|sQdz81|=EL8ks^xkkHk%lv)@~#f$xFs_R8qmP2@hTc2v`a-D+fuz5I)>v zW>@}n1|$CPEtcVO+Hv4$e4;MF(2DJouq+50gu;LyFh_Reqs+`i3Z3h;?LSC0(rXwH zA(OSSbJOyt;%jyhz;`hO6~+;2&IuS=1=-lYjzvMCTu`DcjM|K%sE<#FSv5;S|7P9+%YE+snMk2w@9p6N#fA!O& zeyQ=^&wC_iL9Ux@?rOMa8p8qU`MsX73uqtY<+U7v)Y0{c&WKPf8!FvW!$){zs-U(4sfk+ErrPUWcKmOJTQoTVgb}JLMLCm|E-J#dksw9c^Gf|B;!28t z?mD?x2!dD$N$$G2SP!3+kEi}kJ`a+Rvr(s)e#8_4M+v1m>jgJ~ zW-2$0T?RC`Qzm}r3`|e?IFa|P<0>Mu#l0_W&l-r6+J4alM!fmBk0~@wLe5{Xsij$e zMl|y9W7_0_49+bWrye)-G?ze7od!;wWl#@K*!L_>|C86#%T?pGB6EBCgc?Rki5xLM zq5wB|c7i@U?9fP51Fh=1M1@&>&OFsO*Gf&d=T}MFk|63IBJR8Cqnh9Q*UdDU;S5=p z_3$DV1>!i(V3FZ+8mgwt1{ofxTX3meCBsecQ=8 z!GTyrjks}VI7+E(>Ch4z*h`ddrKsN!3?ii2MDMr8n?1drs9YTmOm7E3D2ffZaK!}= zXn;x+aTI6#NyQa1v+WO&_}eZ0;%#?xfo$PY*wGRXTE$z*SC%*WuO{|aO1!JkYu(Jh z;Fi<++C&!>pn`ILIkCGvBu@1GLjHGD;?u>SSBeY(oY4XRgs?c}zfp-B*y1r1-uoDr_zs$>V$mxV;W$t$pUsD}Jx%=r^5q6?C|IU$RCSHpZfbvQA+kXy5Z+3B zu5l4hej73|?75Rg`k-y@H1$ny(VQ4Pp4aDi*tgBQP0$I&?{==4Ze|%TRi5u~f2V(n zKk=3?d_vcxEi>2-8_bdt$bMZnkdp<(sElE!o#kZA!d3yI+fMi0za1T742m z<2F!;edTizO1j3NY~IC#%j2B7`wmo}1_~v8$(^4}RVpNl+7wD$;EefO3mg>{y{f9=XLBv_T}2AG=^#BdGOlf%6gj6=HoOeQBwyK@ z9r@J{4>!;%%FIX3kHyw*#)Wp2^2`|_LaaejolC(2B`TXEcAZ`u->*f`yu8p}XjBjA zwD@0#F;_|(Rx^zS@9LKWG!R~33h)_M>=2Kmf>BeALZ$s>GF4_Hy4@I%8j;7Te9yH* zs^LY?QnaHCBnGHv4LWq@y~#GmfswSW)16GzjJQLMC+S@8HHLFE2K_`lUn0_N6DKRy z&As=0&6^H*7-EXe`mUtC7OH{o>HR9zABWX;_ z$oZUDTIbDdh7g|54mxj!5JL``(>X)EhM8sGpUHin=oz15P3YRst}0-ok0*_0EA-rC zGT|&6XEaaWl!&SUwZ5wg{DyTRWQ=P1^4TrxKChFjzy|Lxwh#~<*w>I9*w$KdH zDm*n)2dV4Oc%5skgW7DOU?uaqeLN)NF7(^f(rOERfelJDblZEHs(X8%P2*uGJ3U#3 ze(B;035$QJQRb`t{qG$o7gjr}A4f{e8DG^U9VclsHgW=pDUav>6~UE47>_|8Y{UJ|v3 zEassP$UT@U_4G->-1$XloMz%U<&3TU&K0hIQKZ3Y17^F1J=B&0Jxlluu z=$RLL&0Ta*&qu$U^1eQZTnL)V{jx)yy#ZXHM!N7Z3~v{7j7(osaJ@A^hQ_tBDzAj=pdoOJ1EYp>XCgtu{QS6 zS&u%CiuKwSy3_2-A06D}9s1`kOX&5@9@C@`Dohp{+jqUF*ctgQ;UUa5cq^3_J42#6HlJ-i=hhSumA1l> zFVk_1!DH_I(2EMEPPEJd-Y-CdXIXFDbJB%;Y@VqB^Y2H#V3FI6#Uj|V;;)RlQDf(X zHnPku&UPE?5bRaC2zNBrl)JWqUeHP*%zjQMXaMv!;0=k^Jaf47;SMP4GfIuY zp?mwfG%@PU-F{vz)vvSRpT}(z%YMI>x|9!-rVSV5X8g3RV?=OuJOOf+I0!1H^ts>` z=9L&FwCgN1=F{X9#G)xtTP6Mv=&qvf6xHNqG?%Q6z^e|<+yh$A%T=tJ7k#@>EceXT zS_Jp8pKbT&H;G6}5j)Gdk$gKZC-P0`Fl)dX>e88UY>j#JRt*mBnzQ0e%H`I>ctfwC zsrmBe5g`&a8-k{aLp3VMhL>xOtt)SC0)CCAiF|y`=yv4VC;s*I9c3J4J9t0g^MQyu zXtPF{Z;JmHu7rGDIpYG&`Rr?UZsP_!+J-2so&mpKH+F|%$E{OiUAwdHJtZOAm-hpE z-%1xi$Uh%+Xl%vFHD}+1hS%E*@n_dBiSXrD$Y0Awj-5+QY4}y2pGp4Pwc9Zml zdKj!dCVMqp!5$E>C#Qz1hYr{a$^rF)e&6(|gB)iWl9dxAYP-2cqT?m;o=<$oWM}tk zw8vOc+t=|Db>Ga&aU)nhSTsW>;DJXaZOv%y!Rq9L=QVM#X%F(heW`Br_QX~`D3B%) z5^VbP+!YS+Z#hy7e}H>n&nJfEjbZsufEySJh2@3a9=|Ny<5ZQOaN~sjQc7>m`iPuR zH3uXbe}4L8RK~+rI!RHX_~V1G_UTwuUx4?@m3Q%>e&k+~EqVrfbQcmq^^o!^Ho8+K zwtho?CN(DsZ&HYpZGQdv#<*DP@v%}wN5RDjdc;Ni-s{C^dGwb>Bo(vn6k?Yne4oY0 z%P#E{HBFp)H7%G=(wsA}3!HLUvZC4fy3$KYT^NYh>6^8IL~b_@BVXFst_&0}8$);_ zBMSy5k20``n$$ZYiS-?q&XF#}c7M@rQT=oVyg|O~o{H+c*IL2z%(es~a)l+1TTK%lM z<0>5bEICb398+WsS>ortj9xbL2uFeYd5T{hwP zJ)gtGKr8HBZaZ=nBllBy!2GxJ#G>}v@!$b~IwSz#v1IYz&(TNa!LsEXHqKT#x4@YDhGnj}3VTPS!!q+?ZMy=# za#YFugwMAThsID?Q-pO6Hn$t5iBm&RK+<-YdI!M);L(K`clX_A2x8r2LS zeb?oy*UNx`ofqHkcDyG=m(EJeTeeoovq(51*4n!|g6xQvn-omnG<9Jp5!%37^Tc%2YFlpy1vQYPP0w&HO4x8qW{)jQW@>R0gy=GxVK;=1qUe%?NiK2cUs=C~1#^h08?FAv`b$ap)q6F1D&m2t`17)r2l5>t2?I-auKEPmo|cTl_44Fm{__hUI;9NsR`H#2Rdx) z&n@qeNSf|BS#J8CMM!yV_HKD0IKJP2|FZsYLDEe2LhdFdv~QIPDz4d&H_n6V-mUG_ z^5w}!!|s@=P7F;fFQI0hwjh*O>oZxL&P}r>(}|04iK}S_=)EbSdaTNX>NgfR8LpeE zfy#|#r-F5m^ZYf{0LiWucG3o)y4HGwJhmF?3;TG63}IIFY8zB8zReTIlji=-bbW(2 zW&tK&1Q-6WdsON4Q%_(UZ~@l-KN}Ecd0uM{+ro3>yh(|-n~T2G2`p21KPD4}{1ZSU z+SGBE@bzeK!LwVhO2a8>;FTY5)HJgfxA}XH9=(xi6|`spcMeLUo4N%)PAwgtYF-IB z`%Tg^g0fBETuVK3q6==6X`%uDm633AY0~?Tdp7WTs(K~S)yf_yB#I{TP8v5shrAZP zZ_D9|AzCeF#8Pubv4|fIxkyk<2q43%U3W>>&r zgIncRT;R4P#$bJ1P7{lLpWKBAiQDp5KTz)cHMI~}*o9gTUR;YH$l1xw_>4a1HYm?W z<<#tc{?Hh(0Mgl|^x7CTu|Bazb@oi!6#Vzrb7Eb6;R4%op|JKC3I5k^IhZ*@tiW#2 zM|;g5qm0(Yg@ITJtUY!jmd!r!3A_aK>P6DLVM)-QUtoL({h6LI8+R-+sZ7in+Mf13 zLotDkSPXu}X;!9hgB{p6mmeUxr}BO5d2SIXS+Qk&*?&j^@g;G%94AM(uCWoGFH6n4 zI+o14u{P$FuE{Dm4P`iZg1<}wOe9zp?a%7v<0t??4e$?mJpW%U^G~inOP7zde{%`L z&i|<-KF;qq%Z3NcM0!LfIs8w-vC%x{{Z-BwEZWX-fQ$74k37_9w=lCjB=?4#__>@DBt3C&Hf_ v`ZvPb)Bh>O|9FvquI}F$B;^0V_~%;JP)3A#Apigk_V=AcAx+olAFvNG`B+EC_;9(jna-2m;a|At2qL(jX!!-5nDC zm*;tZug~M>{qKIxz2}}g^SyKCo-=c2MpFe1ofPo*4+IE0kX9f;UfeY-WOIT$!4N*K zFbh{#N4S**0`B6>W%tze(KEQK=D!#PZ(m=KqW}PR4F}2S1#|a65_5VxIf_Xl4-Eeq z5C`*ca)TLQ&Q>ngaA#X_u%0fILm159fv|A4ws3TDhKYlHU>;xwNeMAKFA+sqsQ%wb z3`h`X4-q>raj+c%;VQz#_4MgePCE-EkQ1ks3#WtoonTImT)f;oJY4^I8khlLVGBb@ z|CU}HY@nenr>U(WE3c!Yp$%qmvaok?7Y7Rreh=UdX5{f~?#s+Q$V?bWndOH3^@?Rb>m&E_6?@r4g zz;pA*hcH|K;6?G@x|elvM!=jA9$a=X3u~DBof>ydHC$%<$$qh+pVx?Y6TkCMsh$sE zAF3ucy3gJ?^O!igIKE$CU@0MAcwRn`qaK5NBTw8qP`){g)3|nqK`OXDEZ44WWbhI{ zTarnhCz{EI%;Zh4M4IfE%*z&`;}^#^!d5R%21tgI=wzq);##;KiTW4?)rVq+ihoNT zex}gi1smvUrvs48xSF-T%wd0ibg0nOS|rOI7ye;)chlT#ipT5By)h~(ik3DGTt8$>gm0^%X<4OaGb4^Kb4ZwkNx}LntN-&eD$zs^#(96Fkpz27Z3|CQt_lM+# zwBp>)qwWDdG8hkxO0}PYpJ^uJ*g8_D&6||G z{DHF`y;7NYElo5+dA{Cx8k9v<6NY&hUG1v=IxsasAg1_0`-r8U{z^Ja0(NmJ{q(nnVdL5-)bAa)_%p3>&tPv*KeuwV z-JZ=%wzZ{SA6On;EtuYHJ_=eH12y=zFdFfG44n)MMzKaM1N^Lo6A;DM;~v-a@zPH^ zv?w%)w*0U$P2tSt8B>aZy~&EAS#kG_tdZLZGad6W+NJXvg)}_h5B=+RVRs^!^%{BYR?}+_-Xvyu1}w zuAX(Hu2%aqrS50;w-)2(QK#_Gg_=+nEb5{+lMQ8)%>?TBBH%Z(^)`~*_sxdA^A&XH zUQ2?X0_GUI_!&uBf@plnzuw#Cd>KYlhL5=sWNL3ce}9fVcxc9db!OB&Nx=L@%H2|#26!eoq87NHLv!_x)UT}PW4IA6o^)q_*gX3 z+Nc&qRqmxk|NGbGbgF8Xu{A)*{=*psAmcV|$URITh&rv+ykXp)juVug312JFH;^y2 zt(f$5a#8$t-cIW)qGAdZRN+P~JH8gI$z$IHI5hdM2eVy)3amvCb5r}$d?6frnjv`m znl3;iweh!OihZJbR5LG~lc9d{2;R&!MtoD}76quZBDCY>r2MULxbTU&Za$eJP@>~> zM%n0I#%_%j0bM*##dcMP*s$~Wkc!VwR5c@1w$VSVTd?393J_>4xjr}m!Ix3a>^>Q& zs_}9jTcm%##;qzH4nT9z2|L!5i->p_B|jlw z_j2FB*7d#iPW5CM=VmjJz_nA;Qa&IxY^D|VOAqsTvzw|=&sD=r^L$^NhI;@!T9L(G zAof|A3%?V=!uq4bRvEQ1d2g6sM62M1<4&7SVZpeCQ|E%pfKJX_y)||08!$KJ5#yvy3f5x59F2&@W$b1xieq8}f6vsB&u3aL8trCT$Dzo7mdD+t|Yr#6M1tU z@S69V+YfQh4oBxFPFZBC)+pPZFODU1z=gO;Zf75Ho`uJl+P4Q2Uv75}_l4rzYxoM{ zlSozd>5N&b3J~RWtXJr-;@SK@W@R3G6Tv#5l(l=?@?H?6*jgUGmtqtbvKwI(7lugh z!>Re&-F;lM@@C^y+MkdMKo#%V;rzSLEbSn~^A@me%yo4yPF7siHvE`SN z(zq-JVwCEA*9Zbg`~=GE5NXvbJb|2KO?0<6B!vDS>Y3L&?Xfr2tNE=w=4xRlR=O!37 zI!I|<`{plV?a(Z*)#$<%KI`nyd9})ztmRA(cbgt^sPL6e>KLb_Pzr^OdGRU2Vbbtv zd3Z7|WOs{|L*@MulDOn+?1QsO=YhS^vATF88}|1QIVb@X>j6pN4E5eK71oE8h?!3N z{+$$K{e}S%YB@Ux5A6VY{$@8p5;r4g{wp%A89^hPU^~a>u~=Aiv&wY&QL9n3^>JzN zY=ckw)^v3rqJ0MUXT_+y?W!43ORzqn=am~>XwB#gnsf>(^Da5Dq>^EzVsrWyoqG-n zv{uZDiRdg)A?`zc+oJV}qaOgBc1^vGf#nxdKFGPA57`~#-+TNhpX1s4M&;>3OdwIt z=qh@>-<4PWT;q+u&zJ03`EKf&^Upn#xK5ZRH~J7a=r+{bdp-iQqw77BF_~Bv2Hls5 znRn+$^clQX*?8b(pLK3@qTw1lc|texaA6hD!WP;xJ1zNl20HRE1@zbDH{0`bWaUgY zhbQ4RB~IehJ^|Lx#E(ze3CuG1%<>P~0KI!*^!bZk#o1HV5ly45Vm_BAr_&3!CtHt} zL(hso@6~PI<5%69txdsFgSO>KkJYL*)n06JkbKQw17!!2MX0G3WRF+6sY2`{p-OVc zl?I6vm0(T$kwsoiIU`&-B{VrT)T8mC{mR=5U2U+Y$gR+P5|GZ5hfV-5r;|p^9+gfY zw5STG0m92!rV$H47YhOAEL)28@OvwJ9FUS6kXm^wM;#`OEwT=G=qR`AL@u#%_3Eex z7xCWHfS_nVLW^pE8q9b(a}aMfY;QImvF515ox%>C>|k3Vlws#A{}h0(TF=Xf?j6RG z2Mi^>L>!|bNr;uK{x2x3Yl((D^!MuIB(=4P>WFzgZ$5ZY1vEXom4qJ+yFBrypcUMU zFVQ)mfI-LZuN%9x9E9-tA)T zUhI}dl94cXC{gILKqn1;T`p}kEXcP{1P0?-_bqi}KV&U1Z zhETq4WF8R0t)jko@T5CStFGxXQW!c)6t5*~T#^o=r`kntx5imeU5r&Oehx}&2f%3y z4Y`TLg?2z-<*`?^M*@k3<+9W5w~-|4E&bwc*E2!v;nD=r61UogYf0zUmj-@g+Y3cL zRXDXCmLG}A7=7)c3-Yj`Ilo*uJZ=-l`hMN}cT}=wSp6>f9spp>2mp{F0fK^69Yb$eO#q-1KWA6Rc?rAB}&%U6&ZP2>W zFt=dlXRYuK8TXa(e1lI|LPo^YDG_mj?^U@3YFhYtKOICav6r33HHO(-iDz6sVUf|K z$t|wEZmIPfRD4Uk_m-HLW`gYsLIH&oIhwp<_JuPGufG%@Iw(2gF_|yVxB@A;x>?q< zdj?TOI(}Ye9Mp#{QZqfkR`PMqWwcJJIibDMisN`21k0dBYb|GH_4^63@vEFRjxxw| ztns9Bt8PdQ8CUbdIFgOyQj2qJxyWtyVci@@P@?cmvF~bSDfn>pU=R3y4~tWx()8zO z-w=4~8>B0hR+b9a8kr8X07JOG&TJ&GuZpbCrcJ0E7RFL`RIUsb9f~Mzd&+!`R1_V1 zXi}7c)oP)!Ckr;?_Q|bqI|_XTF4S(WeElrd*8iaJxC1@*OO;0G5mvwSOJl+CA3f1J z=EV*fHg$dxKU$rIo}$N^@BUo2ej6slUrFHET$olH&2A#xR8vZ6KCgyu;R1wH8R^^)u@0`r_8l4#Yqy9ps%#H2|o_XgFIk!iVd)1n&CLS9ww7kbp$;X;G? zN!4lXns}d(!EWPGKx2u(bI-)+SjN8h4_Iun18{JU~XFkzk9|X<|MuEnF$1}wfUr^VX zDn4+mgM7~6QCzZv&MG>~M(H)CD>CCoz1|pRbxj;Nbwgjh#FG?-Y$VfIIIK-f^In95 z;v|1<(*JsPb-wSLp|SiSe7860#o?7y6qA?+uIaR((~#E=n%Y-xoivQLch8%+pJ=3 z944i6&^fPBJ1!-$qUXj!EIsR6^Dx@Su5)O}Syr0IG~I;H4(Iv7qt*_d$dgO|BO$Y3&?KKb|Ues3*_% zrT*wh70t!B_!KYBsBDJqAV4vc%?g}vVSGZ7m}Q)ua9;&W&02~TM+MlBF`;`3sHw$x zXKy?wt7md@Z1$_*<~ntM{`Ml~?5vM|&&-y-ykErB`bJ28s+dF?4^vYHQ@R~pfBAix z;OcuVB@}-h5VHgfhQfLpouR$2pIQ?8L0@*qz+JxeUfYHB>kr3ndmnZy=C*{@uQVsB z(LG0I+is3G6EJ6J%?I-1G3S)1PPE1t6fjR87F>2Gh#HNBYSmd8@5-uWMKVt%+C;!4 zgjGh+s=H-g8y-^6PrKyjL**KD{#00bt?dc}Sb{M(N|@fYsXL;CL!WV_4kYP!R`;IOA$ zn(kh@FmD7W!W;2p^;sQ!Khuc1j5I;V!#xs*IFavo><6BAqa*Hu`nImOsOM^Cwg>6_ z&UcG@q`auul&$HlJ@}pcsC;HlcJ09dKc8qAzd5j12o3@T!C#tF9lN6d{w+na(J8D4 z`E&|oiWr&d1bDy@2xJP_LHay0vwl00)vL!3#X_>k7YFV)!q`IaP zy+W^UF2lY3k`efikNer~9A))>MU8JRaQzL$^+<+Ld!k2B8BsEH;ddiucH)$TPDpyWzrl0QM zaMVF<#fU++#mVoCO>M7l%5mw08Cg7;Me})n@DbZ)`Z<*jpS*pTPCuRWQ?HkLJ(Scu z;{necwv|J80#hJ&s4)I@On}Yq3g<}eGET0Pc0Fy@u+3H7HFy5d2gym&!k7YE_#98? zewG~nn8TS2Wp&+%s_cR^4fK2@KatyUn@o~{BZ0E~XzdkLbRsra+9;2VZU|)7mEQl# zCKWgoka~@KrD&D{D3#JQ1vRT5Kn>jI&!5i&1~wjlz25K{ z7o9sQvTRvfq{#$wMl7{=bp$(*&o?QWzi8^hRU$`=R6I;G0!J{H^`(z7X;Gm!YK~<& z=!Q?dw#iVpgkuri3~IHea8Laz#2n2HeHvAfBkYbHvh9~?;=icv>Zp|;5m&o%>jlO1ax-^i9+c3aSeA zCup;U-iGALz@@An=I1iz$Lk|xxd&AcK6_=2!-mkk+dbE}Od!4T5rQb?G2ye6UMym8 z^!sAVD8Fl$4jK{VA7^$#*OejZX?Xa0s@~{qWGV3k@jJTg%O=*>n82nRF1E`)sR(KB z)!sF4bmw;~s2`VaPk_zTkL53uL;Du#5#n0?#G|~}p4~bwEg#WV8a7AFbz?xWd}La$ zb%YRn+8?N2>0UN#Jv?xO6uFzHL*JQ`X~e3IseNTbk>$Ru8mL^Ecgb6Zx_-N$9{_IJ z5G1bfYiKVwC=jSqK6Z?IkPdmIQEi9K&A)o!e9+v#nr2}5!XnV@qtLA6zt<3b8uJ7i zas$pH+y7?+A}!BztM%}vtfJB=*uH!%LZOuOI*00iZ zNgVL==Zl(T_2#jB$JwL*Wm5Hiw4f&^o$+PeEI*gFE^jrTguLS_WhrUtDtM-)o;AUZ zD9Sv+P~hAcl2n}du42m$RbNfND7sq33k#@Zrr@G^8NAD9<@=@#r4X*&VnHE2QxJ<$ zvdaVX&iTCF9(=@Rrv0Yn*l_=~rKIh z65J$pVZdLl1!(N3bpD!{4a)Dru7`bJiXhG2$VvZzGvhI+z)$be?0J0K7&r^n-K6tg z88)*$u*G(Lnz$W_4#cyFQBuFw6& z_t)dRk*n*!*6DY(?oWU}L+RfD`1t<-_-A1KC&Zs#{5QlD@;&_zpZ+JnpAPspz+>e8 z_@_Jmlk-ns_M20M;vXyIU!Ltxj6Y5KZ;Wu@KQ! None: _assert_like_hancom(estimate_pages(_without_caches(data)), data, 15) +@pytest.mark.parametrize("name", ["pages_table_with_cell_spacing", "pages_table_without_cell_spacing"]) +def test_a_table_with_cell_spacing_lays_its_cells_out_at_their_own_widths(name: str) -> None: + # A table 46196 wide: one cell over its three columns, then cells of 15000, 21000 and 9800 with a cell + # spacing of 198 (10196 without it), the last holding ten "가" (9720), every cell declared 282 tall. With + # the spacing the second row's cells add up to the first row's, and Hancom lays each cell out at its own + # width: the ten characters on two lines (one line without the spacing). The height it saved is its rows' + # and the spacing above, between and below them. + doc = HwpxDocument.open(_without_caches((FIXTURES / f"{name}.hwpx").read_bytes())) + table = next(doc.oxml.sections[0].element.iter(f"{HP}tbl")) + rows = page_layout._rows(page_layout._Measure(getattr(doc, "_root")), table) + spacing = int(table.get("cellSpacing")) + + assert [row.lines for row in rows] == [1, 2 if spacing else 1] + assert sum(row.height for row in rows) + (len(rows) + 1) * spacing == int(table.find(f"{HP}sz").get("height")) + + def test_a_table_set_not_to_split_taller_than_a_page_takes_the_next_one() -> None: # 50 rows under its anchor line: it moves on to the next page, which holds nothing else, and the text # after it stays under its anchor line on the first page.