From 356725611a987bf61e0f2ed543cf3770bda33c20 Mon Sep 17 00:00:00 2001 From: airmang <38392618+airmang@users.noreply.github.com> Date: Sat, 3 Oct 2026 00:01:41 +0900 Subject: [PATCH] fix(layout): split a square-wrapped table over the page end as Hancom does A table wrapped square, flowing with the text and allowed to split, whose band passed the body's foot was followed only through the layout caches. Hancom splits it over the page end as a flowing table, between rows or cell lines, and the lines on each page it reaches go beside its part there: on its first page from its top to the foot, on a page it fills all of them, on its last page from the top down to its end. Without the caches the section is now laid out again with the table flowing as a flowing table and its bands set page by page, the lines reaching them broken again beside them. A page may hold two such bands (one table's end and another's start); a paragraph reaching both is not followed. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 10 ++- src/hwpx/layout/pages.py | 79 +++++++++++++++--- .../pages_square_table_1548_down_split.hwpx | Bin 0 -> 9720 bytes ...square_table_split_between_cell_lines.hwpx | Bin 0 -> 9812 bytes ...s_square_table_split_in_a_merged_cell.hwpx | Bin 0 -> 9775 bytes ...s_square_table_split_over_three_pages.hwpx | Bin 0 -> 10584 bytes ...square_table_split_text_on_both_sides.hwpx | Bin 0 -> 9782 bytes ...quare_table_wide_split_text_beside_it.hwpx | Bin 0 -> 9545 bytes tests/test_layout_page_estimate.py | 32 ++++--- 9 files changed, 93 insertions(+), 28 deletions(-) create mode 100644 tests/fixtures/hancom_saved/pages_square_table_1548_down_split.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_square_table_split_between_cell_lines.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_square_table_split_in_a_merged_cell.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_square_table_split_over_three_pages.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_square_table_split_text_on_both_sides.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_square_table_wide_split_text_beside_it.hwpx diff --git a/CHANGELOG.md b/CHANGELOG.md index a49e3740..d4ba2b21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,14 +6,20 @@ ### 고침 +- 쪽 수 추정(실험, `estimate_pages`)이 글과 함께 움직이고 나뉠 수 있는 어울림(SQUARE) 표가 본문 바닥을 넘을 때, + 줄 캐시가 없으면 지원 밖으로 두던 것을 고친다. + - 한/글은 그런 표를 흐르는 표처럼 쪽 끝에서 행 사이나 칸 줄 사이로 나눈다. 표가 걸친 쪽마다 곁 줄은 그 쪽 + 부분 곁으로 간다. 첫 쪽은 표 위부터 바닥까지, 표가 쪽을 다 덮으면 그 쪽 모든 줄, 마지막 쪽은 맨 위부터 표 + 끝까지다. + - 이제 그 표를 흐르는 표처럼 놓아 쪽마다 띠를 두고, 띠에 닿는 줄을 다시 나눈다. + - 한 쪽에 띠가 둘이면(앞 표의 끝과 다음 표의 시작) 둘 다 둔다. 한 문단이 두 띠에 걸치면 지원 밖이다. - 쪽 수 추정(실험, `estimate_pages`)이 글과 함께 움직이는 어울림(SQUARE) 그림·도형이 본문 바닥을 넘을 때, 줄 캐시가 없으면 지원 밖으로 두던 것을 고친다. - 한/글은 그 개체를 띄움과 상관없이 다음 쪽 본문 맨 위로 옮긴다. 개체가 있던 쪽의 줄은 모두 전체 폭이다. 다음 쪽에서 줄 위가 개체 아래 끝보다 위인 줄은 개체 곁으로 간다. - 이제 그 쪽들을 다시 놓는다. 개체 문단과 뒤 문단을 전체 폭으로 나누고, 다음 쪽 맨 위의 개체 곁에서 줄을 다시 나눈다. 그 자리에 개체·각주가 든 문단이나 표가 오면 지원 밖이다. - - 나누지 않게 둔 어울림 표도 그렇게 옮겨 간다. 나뉘는 어울림 표는 쪽 끝에서 나뉘므로 전처럼 캐시가 있을 때만 - 따른다. + - 나누지 않게 둔 어울림 표도 그렇게 옮겨 간다. 나뉘는 어울림 표는 쪽 끝에서 나뉜다(아래 항목). - 문단 줄 아래로 띄워 위아래로 둔 그림·도형도, 문단이 놓인 자리에서 개체 발이 바닥을 넘으면 다음 쪽 맨 위로 옮겨 간다. 문단 줄은 제자리에 남고, 다음 쪽에서 개체에 닿는 줄은 그 아래로 간다. 캐시가 있을 때도 전에는 문단째 다음 쪽으로 보냈다. diff --git a/src/hwpx/layout/pages.py b/src/hwpx/layout/pages.py index b478abe9..e92dcb9a 100644 --- a/src/hwpx/layout/pages.py +++ b/src/hwpx/layout/pages.py @@ -84,10 +84,12 @@ and its outer margins take (a drop cap is such an object), or, with text on both sides, is two pieces at one height, the left one first -- a table by the height of its rows; a picture or drawing, or a table set not to split, whose band passes the body's foot - goes on alone to the next page's body top, whatever its offset: the lines of its own page are the whole width, and the - lines on the next page whose top is above its foot go beside it (without layout caches, broken - again there; a paragraph holding objects or a table there is not followed), while such a table - is followed only through the layout caches; a line beside an object with text on both sides is + goes on alone to the next page's body top, whatever its offset: the lines of its own page are the + whole width, and the lines on the next page whose top is above its foot go beside it (without + layout caches, broken again there; a paragraph holding objects or a table there is not + followed), while a table that may split is split over the page end as a flowing table, the lines + on each page it reaches beside its part there (on a page it fills, all of them); a line beside an + object with text on both sides is two pieces even when its text ends in the first or it has none (the second empty) -- and wrapped square with no room beside it (less than 1440 on each side its text flow allows), it pushes the text below it like a top-and-bottom object; a table flowing with the text is laid out row by row -- split between cell lines, moved row @@ -1121,6 +1123,10 @@ class _Para: #: how far such an object pushed the paragraph's first line down (its band's foot is measured from where #: that line stood before) wrap_shift: int = 0 + #: a table wrapped square anchored here, flowing with the text and allowed to split, that goes on over the + #: page end: it as it flows, how far below the paragraph's first line it starts, and its band beside the + #: text (see :meth:`_Paginator._span_bands`) + spans: tuple[_FlowTable, int, _Wrap] | None = None #: such an object alone in this empty paragraph, its foot this far below the paragraph's top (the line is #: as tall as that): past the body's foot it goes on to the next page's top, the empty line staying moves: int = 0 @@ -1998,6 +2004,22 @@ def _square_sides(obj: Any, page: _Page) -> tuple[int, int]: return left, right +def _spans(measure: _Measure, page: _Page, table: Any) -> tuple[_FlowTable, int, _Wrap]: + """A table wrapped square that splits over the page end: it as a flowing table, its offset below its + paragraph's first line, and its band beside the text (top and bottom set page by page).""" + + offset = int(table.find(f"{HP}pos").get("vertOffset", 0)) + if offset < 0 or offset >= 1 << 31: + raise _Unsupported("a square-wrapped table placed up from its paragraph past the page foot") + rows, cells = _table_rows(measure, table) + margin = table.find(f"{HP}outMargin") + ends = (0, 0) if margin is None else (_margin(margin, "top"), _margin(margin, "bottom")) + flowing = _FlowTable(rows, table.get("pageBreak", "CELL"), table.get("repeatHeader") == "1", ends, + tuple(cells), caption=_caption(measure, table), cut=_spare_cut(table)) + left, right = _square_sides(table, page) + return flowing, offset, _Wrap(0, 0, page.column_width - left - right, split=left if left and right else 0) + + def _wrapped_paragraph(measure: _Measure, page: _Page, paragraph: Any, wrap: _Wrap | None, moved: bool = False) -> tuple[_Para, _Wrap | None]: """The paragraph with the lines beside a square-wrapped object's band narrower, and the band as the next paragraph sees it. With *moved*, the object went on to the next page's top: none here.""" @@ -2019,6 +2041,9 @@ def _wrapped_paragraph(measure: _Measure, page: _Page, paragraph: Any, wrap: _Wr # followed) alone = objects[0] if len(objects) == 1 and objects[0].find(f"{HP}pos").get("treatAsChar") != "1" else None obj = square if square is not None else pusher if pusher is not None else alone + if obj is not None and obj is square and wrap is None and _local(obj) == "tbl" \ + and obj.get("pageBreak", "CELL") != "NONE": # it splits over the page end instead + return replace(_paragraph(measure, page, paragraph, None, obj), spans=_spans(measure, page, obj)), None if obj is None or wrap is not None or _local(obj) == "tbl" and (obj is not square or obj.get("pageBreak", "CELL") != "NONE"): raise _Unsupported("a square-wrapped or offset top-and-bottom object past the page foot") @@ -2567,8 +2592,9 @@ def __init__(self, body: int, columns: int, notes: _NoteShape, self.reserved: dict[int, int] = {} # frames a table starting past its anchor takes: where text starts self.wrap_frame = -1 # the frame a square-wrapped object's band is on self.wrap_moved = False # that band passed the body's foot: the object went on to the next page - #: frame -> the band of a square-wrapped object that went on to its top (see :attr:`_Para.moved`) - self.squares: dict[int, _Wrap] = {} + #: frame -> the bands of square-wrapped objects there that the text there is broken beside: one that + #: went on to its top (see :attr:`_Para.moved`), the parts of tables split over its ends + self.squares: dict[int, list[_Wrap]] = {} #: a flowing table's band no line has reached yet: its frame, top, bottom there (None when it goes #: on over the page end), and the frame and position where the lines after it go on self.band: tuple[int, int, int | None, int, int] | None = None @@ -2955,6 +2981,9 @@ def _breaks(self, para: _Para, start: int) -> tuple[int, bool]: def _lay(self, index: int, paras: list[_Para], para: _Para, start: int, broke: bool) -> bool: """Place the lines of *para*; False when its notes ended the page after it.""" + if para.spans is not None: # a table wrapped square going on over the page end: its bands, page by page + self._span_bands(para.spans, start) + para = replace(para, spans=None) para = self._at_band(self._at_width(para, 0), 0, start) remaining, first_chunk = para.lines, True fresh = self.last_vp is None or broke @@ -3015,14 +3044,38 @@ def _at_band(self, para: _Para, line: int, start: int) -> _Para: """*para* with its lines from *line* on, laid from *start* down, broken again beside the band of a square-wrapped object set at the current frame's top when they reach it.""" - band = self.squares.get(self.frame) - if band is None or start >= band.bottom: + bands = sorted((band for band in self.squares.get(self.frame, ()) if band.bottom > start), + key=lambda band: band.top) + if not bands: return para - if para.blank: # an empty line: two empty pieces beside an object with text on both sides - return _in_two_pieces(para) if band.split and para.lines == 1 and not para.cached else para + band = bands[0] + if para.blank: # an empty line reaching it: two empty pieces beside an object with text on both sides + reaches = start + para.height(line) > band.top + return _in_two_pieces(para) if reaches and band.split and para.lines == 1 and not para.cached else para if para.reflow is None: raise _Unsupported("objects, notes or a layout cache beside a square-wrapped object moved to the next page") - return para.reflow.banded(para, line, replace(band, top=band.top - start, bottom=band.bottom - start)) + again = para.reflow.banded(para, line, replace(band, top=band.top - start, bottom=band.bottom - start)) + if len(bands) > 1 and start + again.span(0, again.lines) > bands[1].top: + raise _Unsupported("a paragraph beside two square-wrapped objects on a page") + return again + + def _span_bands(self, spans: tuple[_FlowTable, int, _Wrap], start: int) -> None: + """The bands of a table wrapped square, anchored in the paragraph being laid from *start*, that goes + on over the page end: it flows as a flowing table from its top, and on each page it reaches the lines + go beside its part there -- on its first page from its top to the foot, on a page it fills the whole + page, on its last page from the top down to its end.""" + + table, offset, band = spans + top = start + offset + last, end = _flow_table(table, self.frame, top + table.above, self.body) + for frame in range(self.frame, last + 1): + part = replace(band, top=top if frame == self.frame else 0, + bottom=end + table.below if frame == last else self.body) + if self.bands.get(frame) or self.sides.get(frame) or frame in self.reserved \ + or any(other.top < part.bottom and part.top < other.bottom for other in self.squares.get(frame, ())): + raise _Unsupported("a square-wrapped table going on over the page end beside other objects") + self.squares.setdefault(frame, []).append(part) + self.table_end = max(self.table_end, last) def _move_band(self, band: _Wrap) -> None: """A square-wrapped object anchored in the paragraph being laid, flowing with the text, went past the @@ -3031,12 +3084,12 @@ def _move_band(self, band: _Wrap) -> None: target = self.frame + 1 if band.bottom > self.body or self.bands.get(target) or self.sides.get(target) or target in self.reserved \ - or target in self.squares: + or any(other.top < band.bottom for other in self.squares.get(target, ())): raise _Unsupported("an object going on to the next page's top beside other objects") if band.push: # a top-and-bottom one: the lines reaching it go below it self.bands[target] = [(band.top, band.bottom)] else: - self.squares[target] = band + self.squares.setdefault(target, []).append(band) self.table_end = max(self.table_end, target) def _next_frame(self, para: _Para, count: int, first_chunk: bool) -> int: diff --git a/tests/fixtures/hancom_saved/pages_square_table_1548_down_split.hwpx b/tests/fixtures/hancom_saved/pages_square_table_1548_down_split.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..d7e70ebdabd96d9bf0554458b8dbbf118fbfd56a GIT binary patch literal 9720 zcmZ{K1zcN8(|1~mTX9O!;2s=`TX1(M?(S|yi@Q^#IK{nKaVzcxN^zIqlwx1#ectEZ z+u!pg*>h%RXZ~k)vU+9}Wnf-l1OEDu0Rm5iC9t5Gr-T4awwAW0E}jmih7Jxkmd1uI zmiBhc7VZx8UX~7u|5D_9$oYx;3;=ja$WTQ$QzvJrFq4O^4WA(NLi!&DKahn91SB=J zGqyLev@_=is;Pn*xq+n4E{1j{hBo$gru;xpQ)eKlpa7qR+Z#zyu=-y}q)-q$=QkE^ z{6GsA7l${@%nW{O0WeZM-+qjnF*7k;u?uB@u2t*Zk4+kom)L8i z^`yGt(C~RX=ggd(>|lqKqY7G;W0_Q0YQ#wkD=7+r@NmFIY2b_xTl{RN zWlLnd^Q*9Qda3lzzKLezpi`85ey`S&GOLLfda+l7sjtRl4HXED(Rnrw6-Py2GA6q1 z)PE$_`RQU?>XR&zQ{`?tZ83PhDGML$_ykATmY`!k3!}z#7+z@XWnYLJ!+gl5+#$bz zD<|a5s);avY5i%CV2^^8DyAX!U0LfbF6d)xtXdvxeW+xXqVeH-Ye-!QQlDmgFt+Le z?xbdlCJpMUX44xiHc?+Oh#45c5ZO?V6cv8Hv9i|xv~zV_AQLe1I;FOp1wLlc2Bx?r51pugiKq^fx3 zp8NhDQu%O^MA}?GbmZ4TYwFTuh_>p0kPfhZCt#~ZE>!?@7<4?OL|L>n< z(veGIIi`%mX?93o^SsRpOd`ALL3`C!?vBU1OZb4v?Uic}$8CnLPw<@;uGb_jHqN*< zuM{11c|BG@@amTV=T|SUQF@w=($!(}st&I&vq)y5*)h)Et#kIS!Sn7T2Nd5Rv%iUJ zt842la1|M0hj9!w!t3Jh1K#b+A3cdZm4mx(qetfa7zecOUY|G5ZpfWNCoK0vF*0^> z3I^F$1T>vV`PL0MKw@}@%9Q8oyY;V<Jc$Uv=u@-UC^w?x29?j=jASz2{D987T#=7x8<+C4%>^)XuBS`}6LUf~Z6LodLShs>vzW+MBt>LE3cS#Zxj)_M znn{AtM8@C8B)|l-u&yY1lmxNVzFR}QYB`#lL`qoT;TrJN#n4m8n&)u!7rXP`m3@Lo$gjta;SQ*rGhJPn?Oe(_Y9hTfNB#=Bq`%#&^}Sr zvh>h}|7@6)67~>m_@N)J{==G+zFC^7n_;wQUKZ0Xo%!4+lxcf~ng^GHM}1_G!~bxn zE+dDnCY$AsaDFG*2*xG*B{h>x0?H@zI#redJ0BFH$o8u|%+zf}hp`}G!c}XctnSIT z+Hzlek>)(Q=QmIjE>8<$zu#e3mnj6GGVGoaq8moX$fdio3cZbRfds3cSZ;G$Cw*Gw z${ZdgD4PFRWI1Wimx|1hGYm`gBB+Nl1Isi>-b{DoO`5geoJYxC?i#6P?&R&dSA72D zV2HiC30eY5>HN3c3=uRK z9b~Np#D$6;gXS_xSurub(NsQ*>ZQUozceD8fXc; zj3)=4IboP;F?TK9@_aAHu{J`>745f^M778AI2jz+GHRs%;jJdJl1(^Gj`zd1F>w`f zGm+3>*O)bIG1@FAIyz-*9p0yKMWsYM6af;|@w^08Fw27%muAl;UEyct``hSgul#9r zLDG)R0-*3Wu^2?j(-PMvaVrOX&w6FWPa#&N<*Jbv&s4{|I#;W_h=;sKh`*r8U@O}R zlYM#i;0Q5n)#bI}QrD1^D$w>j_f38j#|%MQ+AI?R&PKe3lwFhHU|Fgz0?peWOOhm; z&KP&q?X%{VqVoq3+rWblN<86u$vQI!Sw0dRTAl9Q-2Q8LZgT1foYiA*Uw9{1bd{3P=VQol@T!7ZP!+1nO) zmct$jv>g2O9P4c)+HI*j1y({ThyIqn#)w^9svzF;7x-BAM$%RZ2Hp;j<)R1)5T=iATQgTj0G;5>{y{HjArZ=6fU~Dv~=hMQ)o`Yz#C;xc$8eRF6moUB2KEgZNTY`G3A%4twV6F(FrK2t<`h4Bh{4g!U6839<#4}nL~!0Dx4W(E#|&gvYy zqh%et0%_BRM5(`wa#M*?msOgm%$nSM8&O`zpQJ8NR)_;zxQty`Xld5qCoMD0x^bnb zO&OA;j+x}90xgG1=S)qp)2|Rqmqi>|80jCy91=7Bz)vsiXI&CCxiAPeV2w{}$EbAQ zZ2Qn1H(K?6SU=}Z*t^x5tWA~{ z%`bcg=QYWko_#iQ+e%1fX~izf+Y3N&Bq4^Pm=P6%ZO>HfS!L}4Qe*rEqCHo0Iq7Fv zhXvmDszmz}*X66p^s~7F70}`(tF{s-!=OGIec{NszFTJ}JaDoybrP2d?XwbC=gQ1E z>!Tbhh>9;?ipA#U>c}QJWW(QeOqW}%_w~ZT_PSLBXHbQI*$3`?S9-p-U9q6mHBZb6 zBw~3O^y2-)nT9)bxzd_3T#VB^XZ*mh9j$tXFm6<_4@F7#_lS-eXvlUL=#f3-f#aMH zuJ)#K^x>9#{J<(}9R(z`xQX_#z|r2;d{p#>pN}wpiFI|a3+jHdJ4htdEnI#d0O?T~=k>XB{Nwzia%yp zQmKMh{mlX+jONB1hO1J*w_c%rp8L-eQ3Yleo0{y8UL5zQY6xG+2=u`328RO%rQXpv z3i)~69LM zV)puTz7TxA5QOY?C%!%k4{78RY~vGbau4a@)1-t|TINobh%S`~C^4WSA6Q%qP~d@6 z;DHi^3Y3W1`_K83@%fTz9?JnG8DWUV;R~Xw(ZZ_HKy5>Wp`k&Zlq_H6k-i!uCM2s6 zM+$176_3IGFUO-9c-PCGN7iY7zx!XAC*%FT3CU(2c3(ElWgnUajc+s+{qILJb1kOY z2ugD9mk5RzrtzwZ{BIq9T?+<-CaciDJS!#$$nW)F!Z01SUpv&-zu)R01IYzfhk&AD z3Q9cBSUfP58VR9#{%sip)77C6Bx(%f;hH4=`-g>#_jqL7)DvP#43j1$FM}vCbcSnO zd@s-XE?SGz%LM&-@7Hc$7Wg$~^K2*1(9~LJt40Z@gf(qxu3yCsVJJ>g$ir`24Ia&Zdxc~!$?SBpGh+qdpn$Aa8F{(#cYc?IwVle)@WVM`hRKtb;Lym zay2j}(o*79dLAKDnz}W!U?AUHMZ|4&z?8H7X|Vp;96TJK$bN6Z`CHi{otKF`v)`Uk zWunvZ++YcWuy#^rthP`WyngfL;*Ccg85Ky(DwTFyL2TUBIyfxhVyVJsw7}GIVzQ=b zv)7Z^W!&2T3mKNt1pEeiM^Xt-p|8|0oSX}5MVritM66! zBV+3QBmBQNF>14e+E%ClKw}L6fCJsu{C5-MY-;?pa|Hco8)Lumw2cY&+9#tQ(@y|@ z5V9WD%GVpxU0_)p4otBKM-*qJz!~sHnj+R_f1hU&kt^hkG(qg8iOpXxbQ@CJy7JN9 zOiWsSj-JCT6l*aOw&0_AC|k!(yXU#tHh=s5G4=W2FYduJP`EqqZoqO)pvMQ2-r9XPix0=M=yk`3tXUGeHsmvx)AcGTl1+5+ztROq?_3(`-XAhbpUo$YG-?rQ-cBBj^nz+xs=}dm=@}x{Cf^v^bIT%_Z=Ro1B=&)0L(LVuCEh)X+|_M$?f6p zi9@?tyBiUuYrrRcs(bNxA!Z!?auH6)#}odpHF07SZzsBEW+q+YKc&*Y;^C?77X#C` zHyC8+f8zGM?sX7~+$aTXGv;=D@@40H^SugCM?z{dx}#i=RdP(-c-N#pico;bUhPVZ zohtk?vN6cTC{;)!NHV%*w{^Pa?tF7YsPI`zEgDZ~9^B;vf8141*WQWCOwIbL@)=U{ z#_KK=QZq&wzonxKZ|~UbW7JrA67=4K^-g9pYSP-_Y_|?%nh_t=&PbYT(8qecI9tY- z=vO&t=-J2U*YYIS@YGygK13R&xSKDW0Ezu)4OX1IRm4?PdMv{NZ^yU>+BY5&$CTI6 zHVC(|7E~x*4$yNWh)XhR!+ac_9OL2plwV?q%TtEYk-;kYGQuhq&Ao7(JM^6wC| zkkSafy%ns@b{VD&D))J7^2wc)uS_lYa52}PQ@fGxtV(F7Y)|*=Lbf79Z4M7ZBzXK& z735}*phE3Px52}616Z`HH%`s2Lo9pGa9%Y>BKdY&ESy=BZT`#78k+@|GCkg)1|8ky z=J)ZSk_6jk;)F(YJpT`r3w5=0r@CsC^-=gKgE`$fVG^Kq)0N65MPPg5RnTRDx$z;3 z#yGIrV<*%9?s_XH2cmf+QEd?!SRBDwYuIO7EsjajvnoD#`u12+*0t;QEV7E>^)j)1 zAZqZmt1X^NRE;|O>Ct3CWw=EkV>k$?-9^y^pQr-UB^JelW}F17aF|-^DYdccS#>ek zcHuK9R%c&0n!Jco6`eWd-Wr+Zbvz@ef5WPT?l@kAjg@CRNwMZ)^$shuBrFd8@Pd0J zTl>_-x-*fWG?Fi7jU(IEx^KG79K)VCJNH}ZKv;!Z19>YPHxX6?hC88j*p6iuzY;1Z z#+j@tIP7z_Xj)|bSau0q8Nw3SiagVsPjVtsB2hEqFR;L%`PQ1?18ycG zs(m2%WgiILa`~#4LlYdFSrQp{V7RW7x{q@W6<^ONi2}&k@Mds{IH0CrG|0_>XT-4` zk1cgQ*9lO_tu~ioMfhV|ldP82yE(pz&kVLAhw)U3cA8CFHEsMBID)NS!VvjB*_tu{ z#h)2OM)|gujq0$kOFwHsphV6L0*N&57!)kUY6qR^&K5I~PT09s2OB$(IMevhr z8-Gi~v17oBZY&k?J{Uf$=z3#hre|cpgwR@c)Ia5^8beMUY$)<(uFg>1OHsX2^{dWF z!SzW=73rJd;EloEo#J-tVQP3Kr_#3U>=?A`+x!?DO5@oysgwd^!DOOuM<@y0pXct{ zznoN!1hSvZFLTvxD*wuG+Uf#+>CW&W6q_s|e16OEg>NE=drwY4bCX_h_D*ZhCp3*v zCEW{CjC#nf_}T$F^ziRh5mK^j)XVx(t7K4$gY=yJgVvgmcBLkVlT!(2Ao_2Gvhy!P z^#B6qhI>+Q{TU=(iDW0t$^zV-ITllq148+Fe6LXHTbME(zI#upQ0NHI@IMpJ*29)J z#{alh^R-r%9-cJbkY-ut1z<)^>npXXV1oFm=8ZqyJZ0;dPHn2Z%+*)pQU>h)`LCdQ zI?9gJG5L9)tQ1q^ttr(g#rxPhe>_a{;v*LBvPk1ye=r)ub;1hE?`daHd{-$hjMD(5gR6RGVhDHJcqRmCO*pn=E+CjyD=G3^?l)-FBGA88^ z27(pKWTQ{P-^-FJ)FLEoBZ%^j+M>Q&CI_P8qTG816g!;niNC1jBaCN!{mWq^h7v_RM(!Y^o7Tj6O&kxIcW+)CLJPrjPnOK`~v%zDr#p|bAY=ETYg&S zWwGw<7;Odu-j{f{(Ejg@=^KW5koV&B&_{j93kR)cTAG_M*p49Py_j=vv3$SeE^M2{Q7`zO=L~6 zT)(Fg;*y6bkq))esUyb0$XL4B4_Y56Pw=;PgK=hI)@a<0(h)uH)R*aSsyh?T>B?vG zF$Q)f>x{+^MwkmY`hU7E|S+rUwg=E_Z`!m zy2||to6p@z#5`oS81hp&YjWL-r@1XdZ^XQ=&t(D9=Olqh4qG~iolfSw3E&ZnVc-$& zHugY?U1Q-39XP=!?!oeSuCR*87eIaTBD?b`vqsAoQhb7)-90_WyR&_h?O{W^(TKr5 z#SsB+r4mnclMAIf$RLz^SPCxYpCu8$C05lC*R<{F5oq&M@@Pe#rK*gnX)FBf9W_hl z_l1iKmgB%x#qKEWa4}}6^7rjg^f8^vuefx@68cMDv20$kgz1q9cun{X{F|bjGM2IP98XnN@UT`zmyerrZot zW_-595PPfK#`DcdzAq4nba>atixcGVi@1H??@0U;JR@E2=8r6kXS5912m{Cd|%xnyeO&VI- zL8FpRCT0zZ!*)TSm*W0?PIDgbq}7B27$Ou?)ksKIGiY<)Me`K}cT{23N@1%>XENQV zImcFQUYgCjA0jh0fX(?Z$;?ZVOSN^)@9ry5h`GtBT`76GXY0^pN zlYXi7zupPOHprl2Sw=Lr4ojd20EKd+-9^7MJKAKLs9#6U6;f^_`Y>*G+i(ZUAO0*j zi(M35U~ak0(hd0_#y(|zCGx7KVM11PMVJtLJ&~UXvN^yJBxOu^RdKc*3+A1P$raZ6 zh(kO~rr(o37;Bb_Km0Beo)5VVe6`m}zl2uh_G_mRVOD_UPDh_QDU;yaa=#PvIRMZA2LL=p*Z=z}Y}}22?PMml)>oF9=&2Ea8$?nG=TO{_(3((M7(FJx*_Nk|Yis zogLWW2?Y9N9@WFGou*m5ln?~4h&8JEVQ_%y_)@g1>z)wd+Pha$X^NbRHB?{?rytk8 zKLA6!Z@=B`dQS5$pA{RmZ?6(&;xmP>b@p@xS>yg_ku>mY=|Pdgg^7?nP16E~QYO8|`bt_~N+SnRLHsm*`Z%!u0tfYHTGAY>07;>HmXf2UjPlPPt$5uK1VO3X zgDaAj*Hi`7Md~v|SzLu7xgwTA#x(i4Z9!X8`w+a53MN;jXktv_7gx4wQWev=$Juu9^>uQZ4`$%^ROt76~Y2D90; zH({U}O%}t3qm-k<<-(@?`E{)7O{)^ki6c+3lR-MT)Br~zMs`Z>8{IQe&`tGF)#eZT zkLzHE#h)ZY_6aX5y%2S!8dxS-Iw2Yfe+wYvZRxs; zA35G%a_?2IRl4;u3YC%WYcvd@SV6vP&^ z9^dm7`+3oUO-A6rLT-TIzU;f1a{=lKo4I2YUa{ zp_ixn{jK=F&zJnx`~5f%XzTj#==Aq#lRp9ee7E~I06*G40RH)=_fLpFS0H~wEWZAq z>ybYJ{+xjS1|TH*_jLTH=AU!f-5fVjQX#Xk@26M7Q zz_c(sDBR4-&O#Whr78V{4@~RiY+`3-Vgt8>34=XgPGDM55g|)g0a*!Y?LU!d5g>L> z0+z1AU`uCbdjSp(H#awSOA`c;Ejtv>ZteI>Fk2fAE(j+l$6rqa(>j}2z?{YYkzN@5 zLPcFtRb53wN<%|M9ZYL$@(S)K41R{7tn7YKoWCfjBm57_)WyoiOxeZO6o#ll$PITA z26KUb$?}(2zxspV{g-}(!Lok{MXO?NZUu$WB61ckHh(nvn+MDx@_*|4rDZxmGU+m7 z5;g!(R{5vyCE#|>Fgs@_4ojGc8O-sQ8utuTV&=Pv?pcwY1*GWBSbceJ}ZU2ChfZA7lJVo34o=xlJ)zd0e$`WHVKvyCK#GHN_9RbmD?Q znm>rgbdq(Lah7%J1PHk$UP~UBOJkT|nHbXIpih6Q_~3igzC0q50T`r6{!qq=9zAFF zw(1A|heM3w(V=b9^s<2uPcImt0P>xlkHZT!JbTlh%hI_@lgC2P3Do?xMPm&`eI3pY zD&H;L^4;DZRNS2=(l*rg?fJB^z?|z$aF^{d(g4vVHL+b`w9(X-lC=8*Ut<{q&x4#C2KBoBN5!Dyd&WA%z>lvnFEc;zj2{`F-wh! zg?`8@0pcvI#)ycX|1{?5_w*cMV{R*19RJquy{A1rR3_3Ou1^p0;vt#;nv zr*9J#^l~qW=s3{|tr|arNRsTTGoEN~*ODbF*GYU0@<-|LpdyzBew_qiUrCG@S0L#R zakEw$x#5ky1#&Hv=VRK&CSNu?113%k)#*^859!8@m3PExOrs{|61a=xsEldBr-sqD zM_U~ei3iLPaktU&C_$WDOKR@Lft(-wRxr;S_ol`k#?SKe_IMcJ8>(bZKXdVwyz$yr z)Q?JHca9(;MVj(>jisyFZwV+(ciU=Vy_S&etNPwp&Ks~vt|yXnj7W=+5AkNQjB(Mp z?-@RDcCvDk=XS)4bN(_2ZVD9%}UOzbxC*zYZBG&y_hys@bwTF&zbQZ_N|hXchZm#wKX zKac6ZROSjZXW^Y!^2 zhcn~1(KV4%7pl7VuF6OT^;CrP?9Lh8Y?N*r5;=^<~I_9tWzm*YLo8sn3blb_|zzN+CdwVuaKd~)(X^AgoQI6A-EZTlb zSjJpWpfuiwa)r)CnP*2uC2y>vdlxQg6idCqIEZXRF2)hfbQdIM{_dQna#;~_9X0Nm zKMoY7ZCft@i_J(zW6B;CyVOa&vN!UmRabo<{Hml(GvX9UbEKnvxzdxm&ufsn6;}bI zZYM_9igf32VA5nDXv3@hLP@URrO(OhqO{J`}!4U{Bt1zulbikD@a#XJSxThily;-9%*e{&bL0sp@mddy!KUFCXkrMx&W*!l9f=#=$&FlQglj z6aJ?T`40C-f&1U%>N*Pp%SOjL$EEk62b@P-joSh|efzo`TX=Io=Q5X2=?I<<-l;1K7Lmnm3=VQ zm+Ep>(rx(=SMYQ1Ry^j23K!)g`|ifBPvP6dj{*fx9*`2kP32$38++N`mq}p6AF$^( zIV5YEc-bXS&`E6e#j_G~9_6vlLOgA=(`R{^vtpiC;x~Ynuz6W)_VJ?IzqEhmYK0*O znss)LE}an8@vSJ~1@;kfppA1@ev@%6cJ4iwzuJY0CB0w-i3My2S*@Z<@EBJz$MpsD z=1CHJvbx)d)%JJkze0B1(@Y*I?BSd5H18M6=riHb;7K2Dw0M242${3xdKn(zx))hg z(2J`<1V?J)MY?K4YAdRZR%DK?>xY-s2q$VQ(-jh-7A}Aa3$4sQ`p7Gc zbFH1LzGMte)Fw!D)j-rET4#U#`jl;nTD~-V&(hRrFM5~y$s%c5VK>*jgxRTakTF+W zY72ga+j{fc&#^<5A%pwOjIfll8mXX9oJ^>fVl{de+;J&|Pp@?dllJ0apF+ENwnF`u zt25U*8+BTRj8CeQcs#mnls45KmZrXQUf7%kOGi-Rt4f+a!m#c98gpFnVfNvtxHU{T zZ$lYvy`ufBU`u5J{Lp3Ld@SvFsz3uWcgFQn4U%qL8wH%*gVui5+X@R9t4J9mroydP zlh!*ocgoCF!ht*z%9rD`xjNsoNeW)`bs09`ll($4`(tzURX9&zxo_!PzI+!pq2_JL zz~vPWg7Syd$|%5hJG&DfZ-7cA)x*U2M|n=90ij#EwU0yja3tRrCBknp9nx{J?C^mR zo%8`CJa;Z|m=ari?xXhu7 ztyZ+{RR!q&4}nDzoY~vuHGyxqAIH-Za~+&%m5fBZZYNK&4TTvUETaT>4MTkJdUHCI zyfE=$ml@9s6kmVM9~!YEYbURZ-VRsypZW59hyS*5G_ug#a$V=?z2~#rBQ1=6I&wp4 zzup1=UO7Kzhvz-c1IcgNOs3&pzzQRtP9 zs_*SkMvmoFGkJ0L?L7Iw>^Mnfk?*y`&kNBY$k+(573m$hfBqMDc6`_Xd}Y_j=ys!x z4x$uP6%2`tE-3am=5!}e`$UQ0^KDM=8LxVC@Q?`~I#8V`e0w*08bU(H$22Ob_IS*! z7%z|!UvHq=`Ssax*J;zcv{F%D!P}KZ(=ve+S)XV-DpKlDL6ul|wU?0yoS*?3E z>D$`$bB~t};$jS?(pBSALk?FcN!gf~HCFyoNyYc-2YdGB``%ilDReX;@trRPC;Ey- zdUy%^lQT$wk=F)$ z0nq7dxM$5`-q(b zV;eRaCUrnAzc-8WWSss0txZ9FGDbicZYIkbeE}-queHRL8Uu;>Z-R1!Ppg`wRE1p(n%--wTIn-AA=X&4=<78)NOC!g#K!edU#g-H4GT;9T?Zuh3@nZK61ULPMH zcg&CoD^g>}qtlr09l->`=0;I-_TE{QzKW}u0H1ODCSHAaU&O6vt1aNLN~=7TQ!+{07tq+}UifIOon|@4z`cv|w_|U+Pgl>2u8b)a zZ)OR{Bi;|$4~ILaO9A6;Ca7`e#6XGx^}X}UNR}^L5@=3oaL2JG0gV;Y#J-u+ieC})*@~Vdifm#0ZvwVS}qH22dw$bcH4nOb267)}R!IuRyI5h-w^W`!vYk^DW zjZB#mN81xL4+MAckpls=kKbQ!-GcE6`t_&FBMz>|T(LM7ijO*nlR%yKC+0(Rm^@0Il@B*_}eT=|&81Y#!Ohhq~Q zvzlio4yhqqCLrP$!+exz*Cxp%@vF2NI6Gd~a_TpSi))_GckVpmOU!R&T51p->9~)8 zgcA?AD9lRZ`PMYG$i393dgCywC!)*_6VnvrpwTCwoV)<7WjZWEYVDlGFo-(Jo#M`j*HhL934lX9*Z>ayyw<>f7lpUdm}589k#XsO~c zCUW&n=gB^*=?>U+RjTvM*==HL%qF_EiVIasc6WFvwYuNoMbJ4e)ayE-3670JC0Sw8 zV#zj~C^YIfO$UB}7_{p>&Z0F6$>F1x>uzRTHacHCprYQL!gitoY%4yJuO%E?;LtyV z=Vr9V%IErLp5)YH2k3ldFCgS%ctb9^p_c-^cp2@RqveNJi~*WBBf6NdP<8?FNlm4Rz=VhhA!hRc49MXtvBy~Qcmo6S zcv@Cscw5d(B8e>*7mYY%@^H5c916K6E;7xnKrovOQ;>z7RB^7$#qdw=e)@a)?HfnW z7mlCki6Y1?*a!3O#(y3QiyHX3%z8CFH8iyP0@}+sD=;4jjLU}IO|If}O+RJndg0E^ zTXAw&l0%W098vs&<^Az+LpHkFllgvX^;Te#FD29L_@CQ2H9%uoB39Np|3+0J6IXb&MsUzi0;&_3eYXiBce zy>(Z8qC&R*?wx=3sI*oPr!fZDZc5RVd?w6RQ_7Dk5-;%EW1$9WwncFtaAcZHy#*+{ zeX?C;MBe3rKDNPQOYVLZ96S7F?f3NJ`rzjehmJJ@p$`lwCh?v5yV|R!ai8)@PmvVY)1bP`eiHdXBhZ@R#rhtUiJtltA|{=( zo{KhuK}Ycs|CBT&5}L1YtSZwSs#6mA1r!93s!+2EA*ZC5EZ3C&vhe`fQoBI{Ckx+{ zhn1dPv#B^bN+4Y|&?3lyA_?D_j&_EdGBA+bo8D&Q92LMU&CWfjjF9D%<2AA|wHqBi z0X#9AT%X=%3k|KE&MXzLX3ikcI;i|x2S7+x*bnLHfC^44{wF6O$~yJCne7iuUzf>E z*e)Q(K)fT;nj#@Y7N4yS;*JOLqD(QFz*0wVNfExY8fT=Iv3C5U@0b;n9 zIXMS}_F!7Xs+qW|=FM-Nsj2sq9t#YtZ*JXHstESf2wtl>>h6E@{VF=M@T2Z6Gg)FS zb`1m7Wl5fI)1=bsGTND-7nck(*4K6;MX~;Pg(QxyeuJ4~byZ%Bykesk)3p+x)7q}`a=bL>ZZ$~tIeKc8y;=!bk3+zLu z4?w02QcN7&!jkuQUBSgp^|IT+%OkovFbRwoLor`6v)YX`_vuM4!`@`N(;82Nh1?qA zOp{^CWUeV=ewdA7&5)Y)m)J{tpP}=<kFp<`!&(adeB) zEx<(Qa!V~u9D-f5Dt~k=!`xm&A}TD3ePZg-os-y4Fb<5l5NK=cn8<9|59`OqSOdb~ zPWWZ}&Qd+R+(;wlR|2r_YN{vd*h=7>_iW({-_6v(*4bfPxy6HfFy!eaZ=Va@Gnb)a z%^7o1n7HkTQ7ibRGDYSJB;h8mZ4z6fP&8wUzjHu|DYoBtV)jTO_wae)DNwJ_ODhJ+#}yAl5;~!LXaSzW`GCPhM%;a z^LTo|Jm}tv?>fACoa&T)D`Z*HZ1Z3}35zaPRXS>eGS90_)rKfGN?cdhkeRr6IWhyw zzI^k$t&r$RRyOMC^JZ;gD=x~|!jn~VaPw=hbC^sRRuyL_(h{_@LmO$96t}b=%K`&J z;@*8uwqPLx(qm<(xT@C@!RQ%u>hje%7Td2DsMZqU*)cl{R-z^0sqP3Gk6N;dSi0(# zrVJ}Q88**rc%8Qbknj^SRpcD^DoeFRNMmZKWr(+oXKc4WfO;`IlAjztAT44y%@isR zp&QYWTx{z3`33Rx?S#oaj&6Up1>ph8mZ&v18p^hmIA{9JOLC`SqsqNyU4dtIn+Q8m z{2^&UXzDc{R#Q(=VEM6H8t%?Tvyj8Koy;AcxNzP9)sUm{)&Zuc=)DGiFEr8Ed{D>d zZVR5M?&g1TTceWgdp>z0>T_~)aPN|JzjiT_eY^3q#@E32s=?{@EW0B6_T*>Nee>nQ zyWt3qR`;Wg7ckhnG6QYb{<%MiJAMP}UfGM~mxd<;+v4_dknY_s8nfrdqcf3uYd{`c z--#~Q)fn+<^&2EyAtaH=sPdx8ONpUQnwK%@df}o`=W)urCbA9aI6ignyQ%Fc&rg4T z{h9M_I(I5eL>m9|v4V5=m<)M{NQ*UyoTzf@V8BX}raO{z7wKd_@G^^MEj>hU}jl<;5;o;8pSf-jwt)({()6K=*0>gEB(SmHiu)qnYxQM|f;vA2T zNEb@IKM?L7HDh{2)_BZUc$gpxW$GwhT&Z`^SkNL(p)`0ECezKAT>{Z*dbomYBd_Q| z4YBlQi?!B<>!wsaJx_u&GcBs{c=U#rh)|(8*Zj>xv5M1h9WfaS~}d6>h&b5+)=;vDdphNt=Xa480G|&(H*yfT%B<` zR<#BN(fCaO={*J~U?OLn+=~rF^IG@d%_#Vju=G}qN zDu1`j$H%)76!I2A_4q|M^LU-eks+Tg(FXf=sq2a`^sPSM>4Jwd^P4|>+b2FIWmfLGKxvlxL=5K6 zhlh;xTWITA9rkMGThB;{&IVvcm9>gq2Oc1ffZU8xY_Gb9P3!N1c8d%q}rX3Mia- zZ|>z&n=&fUeSU_4n z?LsAVKK!&^h_dwDT29Rf-mL~@IZUxn1LnfBSTiD@Jnc*^CUba1vdY+`0Va03vK?-2 zdwiiIcis@p9Uh+BH@=^SOWdf^5l-^LZs7#&ROtIX!zRstyUUdPc>xpARVWI=V~pso zl9Z;{6FFsR4k*I!X<}uE@OV0!nSV?eunUCXN%?j;PPzNZYl-Bwmza~jQb;!mw^imf*w<4{+EuKa z=jxxR-j0}Gf4qU@57diJf{LOFEUXqdKOel6eEQY;T%4@>GSXHZ1cF4u0OXvVN8l} z-sl-IC1yN5Z^ZM}o5jI?nBTqFw(lrJ=_`AO^Izo&MeMW_AOip&(Exy7p8LN~S$-)G z;WTEqv^USx8i>z;;N1|(yU{m?Fi4Rdbd+eaH^4-VALB@KdP))u{5;@JMWvkAEp^0~ z-PtD_l9&@}`_AJfMU(i9NN)>uU=)KbiC=SfW2Bv#U_%^2NZ;6tXDnH!^GS-x;Nb)*p;j!H?Q8Ek~UH3OI;f{h(FafACi^KM_Xt5o3$ecry@5tA(LoTer0UE0HwiVq`sT-d2! zUVWT@%Au~wRn09TWwSw63M$LLxR>5RLkNkCW6rYiO%I@R-#|J+I|N=OEiu)P2cJ z;x(I*?i(q#8S7kjOZ+OQqFkp`ZY2ZyRCwC40^U|8%somE{j4Tc4R^~7#=U?mfvnYj!oe*r)N^tD~oJ8{Nu4lkGpj$hf&WANlV{V?Q(D^zw zZ93*aU|fNO<4t?YTAEzkV-g|cCHS;N&-xQ^&uosr=#Jvrs9siqbfR3#*rMNn2&y4T zs1yf#sFuM?0x#ANg&$edZ${f#mO96)kW>|rkU@Ve1qhK4!6d&2@%$>bN;@U{ljTN{jU-7pPlV@jNg~^ ze=rJY{-uF`E%3i1{63-oLD;7IpHlpf7y0|>{s)7G{$CjX9_y+KsEAz%0C9Xe?htf?>*5YUg9LX8?zXtQyE{P_hv1UnmH@#$KyY`5;Q!{{`(4R- z|J~Cw)l$z?*K~JHb+w`_>l?d@$WjSZbG zL3S(_ZuShGmiCJOVdQ$s{fP$+1@$W-Ll|969i1SJncZz|1cV_M^1liM0j$hG0J*81 zG04Qy&Rh_nrYgzA10Z*DHncM_v;oVG1ULqP1D_$*un z0T#~A_IxZXZfK<;d4Zt5)ZkMx274FzR! zMP&ss2^AFuWdOOYp%utc5WoqcEbV?#tiLE@N6;UXk&C5`iM)%gktw7GA~(oM5Woib zCCgu8{pt^d_h0%E1W5fM6uE+#nWeEQIV5N9V)I9nzj**GLjR|}Us|SsN+npONB)n17M|lzb}uOu`n}VbG*p}-l#UX9h)>FFLKn$ z$fwqKHBssJ=t=j$p%L(R&6+tn+Pxf9jxKCfj$>A3t(71zs-i3cz{3F+WB}9N>nmTXOaf{J|uOecgvmB1NEm6mO23C#vFrvuV6I6s3%W}xB+$q0* zFZafaO%q}6%DQ}jXpfSOI<_&+zoPXX518K?r&hq$5Gs|eXnYuEeNtbF^hGlv7)SL0 zZ$dLwlNNPVvzZT@UCc-P#7q*w5ZO?V92I`9sjANJtZQ{lC<|)%Rcc)&D}3yN$%mQ) z%(_#A((#d9g3QXHI*uDkV<@8i{>IUzdak3np2|$NiqwfPcr2v=b>VnDVLykflj@R{ zN1n&Wld7l7Wb)4qgGaudbf(VDhG?ty2pLe;{zA4|uf+@HmOdTUe;e`q`25qZ+3!cW zYzA^^9OtBQ1nmy_D_-5~z+{T+UNpkCN;iD|UE(J!9?v`w9FG~gKG6?0xIUBgxOn5b zf--c}rS&)=;p;mCu5X^6BMh{iWvfHx)t#OlGe~A)Ik8S&t+ODP;5oP91Iq6wGk*{_ zRyWq!lGPN%oyM^=2(L$_o0d_ZSg`Upm}jZgjA<_tA`p{Gm%8+%GIWgx#VN@f%@y^zFSEKOoS4!G2deLUOg zo=!fYjY@coO@s|*Wm{2lFAZX?^It=}ZaJErKuVnFpou zSwka4#dG<^mJ=X>G-S@)p_e2tf_kYku}y>I&E605rCa;Xx|iBfUHBAt)adcl#s>rEjjB!l}Pk4^tT*Bx+AEw@DHNjk+9hD~?Tcio+LQ z(@bOeu2C?!2agy7h)B;RL;73bG7!))Nv#plP4P(8Fi8M>;?BX~*PYT66v_;kB(HEu zLgXT2j~%WY*p+UU^EkdNHbG-oG}1)m!iYj^7O2o)5X;pXbE8? zyat>*Vw!5PbT8iX{;0&YHbTo2`)VhJ3c_|j9q8XOYGPRSQWIUtA)b1Tziiu-w2HWy zL~O8Y%oe^7W0o5ele)DI?_IQ_QYsOOa1z}KQ;I5_?aq%!yXTyt@UtrHK4!`jJcTYy z-nm%_5cw`1izszg>e4J>Wv}nipsZLPVpUeD8g&V+I@aB_TJ1?X=rv5*fhLQiY$rm| z0sZ7~V%Ykg--cUVLr%I-+xNmJIGM(CyJOdn)>zvZl?oT%~i0-x(06}Ik&4>R8rjxGg~mMkS{ z?>L+k&e~P)ldy0jPR2-0piW22e#X&461+)bPTg^T-2Uz>RZy7LF{uT&bg>4qE%c~- zc_`F!@Y7?ouZd*0r9nNc+unm6r?I&rD05YchR(Fr?;9pi#hhbvS3jN<%Au>hUaxb; zdth|I@O@D;nsvKmE3QfTw0Z(nq+U|f$>Q^$(>c@}%kz6oRv8gi*{WsbI(`&_>RF4(eZM+UkcMHd$iKhnB+uST_qX*EDeE_0{$$;u4rV}rjz(OPb$e!96xa$IAIq#F_|1%nLR;I z$2NKm)TRrGR>z2TRf$%Ar!-!bJ+Y}9Sy?ZbtS(Pcg!{5+38$#Y(yY-}Ms|vA<62Rh zDkNDQE7?^AQV(gJJ2}b0utF+R5qV@`q<<89NXoQKkWuuNZBfkR(jeG?Eg`)fv&wC= z?L$xeNOjooF)fv8T4lXNa1$%d%bz0kI_B&NX+<3On%F5viKb2AU%7U|{a0(VH(6UW zI|K|aYE!s8zSziZDR-4=FBb$_v4L_IB_dMc#ujUW7*R3MCf4+ zB9(_lFWEnwZhSzOE2|yF!#pc+A_xrM(Q04}=Rphj`X#H<3i$FnErN&kVNfB|WL zT8B5jp0`IcWVxoB7|B&PBQm^!Z?$6IN(a((Ld9VPy^UBMWa&>*2rQ|AQV@bu5P}fI z3KWPr>o5W#1Og!lIqQxBUnt#WkWX=pPjOzm%M6_*C$7@5bg4vkt3*PGeiiw^k~$~_ zUN{9_2tlksg_yGsBalKMkV5-h300aIj%XY)FQytJq8bCxHbfX49N9er$t)`;i<49JX z#cUfLU47~%ogeU;q=gy32Is{rf)YpI9>ZAb51=oZC zqhkw8J!)e!EVNalMN-3?w=~zU;|DPnCn)7&%_NEl zcp@})B1~=3W3d9TMc%FdBQ=pJVb&;K;>pi#ymSQq9zAUCsD)wB8+Y zQvh8Ij7hYVc$8owWy{jGrsoah`>IKJtPYrSx620_pl9LX1Vs1y3NLiu73*Lm@y>jQ zrp`jA=e@-i3SsM_%3N)sDSXA(amnXiPeBb7w@RbiRuCU^u?`MTyxjQcJyB?CIX+R_ zyxr%);yh;U*Fk}8G!DOk-kDs=TjV2shnsupd1Fa(2zB*=0EBV?`9$6r9)L2Qy9asJ zFBeRPJ;VRki?NPp7Aio6f)ZaptU0;hdT`5R4_a9!A07$` zb;)es`?h8A;cHP#vmz=w^IMvDKjiZ{HF5CSylj@vG_RMICuxvD^o8?lIrFsoj zZIT6d9h0x?mo)=wS+l&v5OEQPEsQt6JdWT=r2}>hJDMM9`R4Wt+GGkWm1CwK1(1ZN z%k)yC!}d4?qtBzH=D-Xi{beP5!Ya8P=;A`dSFk#Igg(l4{T>oWBeOxr;Pw?)^jQA; z(_N+SQB9Yx{euuNk>-2r!ECUIxE&|lgEze<^%CYMw8Z&MQ@u$+?Hj3SF+-H{V6X^J zIe(CWGFy^`M7b|7!e{njeF@nv${6d`_BU#9VO+yEV)pnd_O3e z>o3;<_vFhX=Z2-SjSMej@&>!zOV0$9BMOk)J68mK6%BO*NN&m{v#IX5?<|PbfiqX$ z#Q0}gANsaZxWn%!>^|TZSve#hz>KsnF*5kMpBPS2_&hTXxzvK;m!|r&eY&0nXnxBEG;h2Kchlbf3>UsLfM-~1*hcA3ib1)1i-=re*?=? zPteKF{N|^_4b-4Iz#m(J6xm3N$P z$y4$I+UrZ(q6<_TNeZ!%Vcy3iT1~61cnl$r)y0A7QER4Mc3D+9RmWCfELZq>_Hu|D z+c;XL+eEK^QUhU2wT7lNvOZ>y&Ia}CEIlTL!S6d*;-m%{W6Vn{EDFQnm~~KfMOl!u z=1(&Ybl`@gH<7uyk%8QrP-w`GCtJlwKIeGD&m1|u;nRM_T z5+4g#$x+&|Fc}C<2!0H& zOxc3DwUSU<;zf?4wKUOL6kE7KoEC=HdMd1vd9R^H#{>?gLS$Lh7srYYYyolWlqTfV zKE~rDV+_(Y8^1_B@qRvee*b*57pmc{8r>D_p^H0>%5W0MH2L!r9E(^od^nON^6~*o z=e4)98xNu@hCHbOv0}tgLBvTcH7;5~1OX~WHw?V`8l_tpdmdWPAORRjQTF)qg`B4w z2SdpMD@Vc$EgI+&*EJKjFcrSC@Zd38TCl%X2s6I3sg{8cz`+!?GX`Yv2#4()R)hASi|7Laszz|1-M7NPf0e zJc_+SuJsoLGO(?&m~5*AhAYyxl!i}~x=0oFME21@SEW}J1SX=q{pxERtAvL81za%r zDj4hc1I#&ay03?IrzHuLD0#$OiZ(ev8UiCe^|_vL ztiHm8K#Plf&oG&;I6@ZK=<1_CwnbO4>EZ?SNw|npp2G?osIPo8#-@0^ zUBHJWiiP1}!qim;c|1`L(wvYlO*G?%`D$x@LNp*JANb-wU?rC3jvw{Y(G<8x=H3WalK z#mv~-PN6-4%pdb|bwgHrPaEL&qik?$nn`;()1$zvtDXeAXR`xxS@5fmD+@|l!RHn@ zA@yGI=ZDImbgUUR8<&VRHkm}Q=Zgn?Mk)9&NoLtk@Eb-g^X2Z!CwXt)p_j=EMka39 z)X#kOn_d#;UCubZPH=3w*?F5G>7g#!o*_sKywgJzq~n)poPpg(9~+|>d$JK5gU+4$ zw2THl<&oZ%%{J#wa$>|^M^kGtB&Q7`Q}>~}8=Nuya9i*rmLQ2c&jKff$O(ni^+uPCDn%zm zRU?4rP=jHHui(qf%9nSX_!g8>-;${rzhi>J zpLKmFaDTzAU3Nck|Fl;!CUn0)PuA&iee>)&_H=e{uJG*mINw>-`S7Fl=}uuz;o0MH z$uH;mSmopvUti$)yn?=7W2=hIOYQhi;`u{4stxIuJ6-QXfh(rKB9MZ3i|m@pJQ&M5 z3YzF{Ed{Kq|@sH*@DNic!uL z?lb{Csi!>(Riuxp_DHi)3x)DpIb7cc!G%CgZz0j^QO-)su!j`z5*u1`rYt{qTsRhV zx2TL)ZVJev*>f$%^n*5MuB$xh;|ruz!)`UrNv;!hma5w5jneIl(Gm7+aep9m$#9EH zm^w>NZM1Rm_W9^UeI_vV&g6x)ex;>*vuAg-DKQymuA4k*PcRQ^c;5A_HD`lPJMb&p zXh^04KaGM077DQ+;rF4PUk>M zaY9L<_o96$ANBf-2;n(KcCwTDiItcMcYZ7f6rmoevnba_2c>OKj!sNP!H`K;xoRzL zljyZ8eqkF`$sFUaS28xXn!O?XSvULI#QjPXci86V62?&~29ut@D^@;KEtHO*OPB_W zYIiDzSME@&0pi-agzMAK)e$%Xog1^W{Sf*k^{4A5?IFUSXx2Z946W zAx5`# zzO%{CPx|7=O$cZygsK8RU-PSL#^(l|uV`^;-ZK^7X$zM5e|PGrgky`)AyGYBNTljl zSWwZ?)Ya0|jYZMXRn^qpnc3Ohd1OpPruPjF+^SE$oBP`VuPN%XVBIe<5-(mhl9Ep| zGrCetCIh~!y}@S={A3}*lAQ6Qd;K0i5V_3dOkFtR;o?l8d8*AfIPA_}5+8gql~mDN zzqWODTDpk16$y|;nxya=5Mq<09>C!p-$X!+TVoXn?LQ?T?KO5sQCLM32%tHAk<*3k z4)ZGmKi2J}!?K|$cOJd?g=57xWF#}wMWoXtXV4Dc7v}lKIBlNQ?4Tmahb)19^`xTu zBD|~&Sy=CG@tbf*l3&Z&l|Zz}YE@X27`D0!?O$kB&*C|fXx-$I&(HlNQhmZ&#l#{8m zGbHlq^vf4^iIbCsWyJ`6mPv2Ts)A3bnFrua=$yfhiMd*dCP_;bS3P;DoQ+5I2Y9U9 zcoZLLMD8b9A!jf}_rl@S4#}>fBZI2ZHJbA>$yo^4lR`jNc}*9a69OG4Co&P;`Io22 z5ts4%K0l)0BI^|re4KM35x5@Z_#{AFacwQFq!0S4WK4IOW}ktc56Yp>ie}>IO)n*M zpvGUPYE=Q?Io;ZhwskVzXi8sy4q=as%paUO&OpO!QRt4u*RWfuL%`3Axw?ky6MoDu4EDH0|lrru2 z<`0h_QAl}S)3{LagIPD&vCOl)Z7aqui)b^*=92H!zP{QC#WBdFW?e!wwhm9E3;>4m zpgqL+n;mU3k2kC%=e<#GBKa_8cHj5_1P^@@p1~=ODKxiSV(mHkAkHyqeJx5@+c^GC zY(<1v@@5>I1hhH86((m&B>Z^39Vf{@9h)bjm5)n0M4{iCF%V~#Mlj@`1uuZyCV9Qr z#juE0?RvM?iev`d{Sy8hsF^YQg~Glw|1Im@KZw&Bt@-J z)enOMOve^uTwM0v5U=?YN~bGwDb`X;YB(<6_$)&W?&^Mj*!7s=Upg-_YTsTZ&LUur zSnKNT4zk8uZjmzZZRtgk#)FNNI!o6AL{L@sXG~Hm5xw}VIQhX^HGDSLEK}ad5&`q^ zn^H$AaQ3+vZXz$#EvhPq#}P5)z&lIFZ&lgeMhP4dP<_FfTXQX=FRhV_s338cF?Af+ zaEXihGd+3sr4U(>TegyermXVMds=oZ?euF$CaPQG$oIpj_r#mDbzlWqesb1@?58WMZf|?*OwYac|U-gI8y3*ge|FpXYev8)LI|{IkryiPFn}I(ls=F4FmMsxEF>0JBG;8sit8e6L1ld{y!5Cvhw&S zjab33V)&-SThB*ds|Hp`m5qxLL2EF~*qh{#bS&hn= zzo?JSyhDoSa$zRbzHMCOU{O|Ot7R9Gu-PK4z^T{*%(pkuB|2b686;|Q-e~hCmnM}} z?OVX8%c++{*UGvg5J>C41u5PJ9kCmG6;whOTPn93;)~1|#=a~+VkL0T8QJLyI;YoH zE@;2dJjpc@c3&|O^I_1}3YB2^Zk^9;fm!2JobR+PKy7|fNfC?wnB4o)GH%;n;ZU~c zd3rGr+>6*``eQ8uCwn(1;}i0{)3>)AWS~};i>J>4i;}8)r0$zz`sSzRi1uztTipLu z8;D_5*8wu+LLuqb-sRuxmaUr-ha0-u9H(J znJnEtvFtx2^imH$T!Mu;T#WSL{{6%FzmKK-!S~1G+##du@73v_ zLn^-m{Jtan4}cKbzX1NdKm0qy@82K)KwuO9&##f+0e&~Y{{X0v{MQ`+&iT77`-fAM z^j{<7KbGxxjNg~^e=z*W{-uF`E%3i1{63-oLFlFUpHlpf7y0|>{s-d@@Gp#ik99@a Vmk=ui1%(9pdqHec&g);f{|6!en6>}_ literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/pages_square_table_split_over_three_pages.hwpx b/tests/fixtures/hancom_saved/pages_square_table_split_over_three_pages.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..d34a3b26f3de35cbc450d261fe3f038788b6149c GIT binary patch literal 10584 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 AzW@LL literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/pages_square_table_split_text_on_both_sides.hwpx b/tests/fixtures/hancom_saved/pages_square_table_split_text_on_both_sides.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..e5039a903461b5b20267301a45627617ba7676f2 GIT binary patch literal 9782 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 CQjvrJ literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/pages_square_table_wide_split_text_beside_it.hwpx b/tests/fixtures/hancom_saved/pages_square_table_wide_split_text_beside_it.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..bd36e624aef8f7261aff79c715733b78d46ed3e3 GIT binary patch literal 9545 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 SprDW;Uk}Kf)C6IKg8F}u2K9OX literal 0 HcmV?d00001 diff --git a/tests/test_layout_page_estimate.py b/tests/test_layout_page_estimate.py index e4790a4c..6745dcd4 100644 --- a/tests/test_layout_page_estimate.py +++ b/tests/test_layout_page_estimate.py @@ -52,6 +52,16 @@ "pages_square_picture_moved_from_8000_down": 3, # placed 8000 down from its paragraph: at the top too "pages_square_table_not_split_moved_to_the_next_page": 3, # a table of six rows at the column's left, # set not to split: the same + # A table wrapped square at the column's left (rows of two columns, 10 pt text spaced 160%), flowing with + # the text and allowed to split, its band past the body's foot: Hancom splits it over the page end as a + # flowing table, and the lines on each page it reaches go beside its part there: + "pages_square_table_split_between_cell_lines": 3, # 15000 wide, split between the lines of a row of four + "pages_square_table_split_in_a_merged_cell": 3, # the same through a cell merged over three rows + "pages_square_table_split_over_three_pages": 3, # 25 rows: all the lines of the page it fills beside it + "pages_square_table_1548_down_split": 3, # placed 1548 down: its paragraph's line above it the whole width + "pages_square_table_split_text_on_both_sides": 3, # in the middle: the lines in two pieces + "pages_square_table_wide_split_text_beside_it": 2, # 45626 wide, 2562 left beside it: two characters a + # line there "pages_picture_1319_down_moved_to_the_next_page": 3, # a picture 8000 tall placed top and bottom 1319 # below its empty paragraph's line: alone at the # next page's top, the line staying, the lines @@ -1197,27 +1207,23 @@ def test_a_page_break_in_a_row_holding_a_table_beside_a_taller_cell_is_unsupport @pytest.mark.parametrize( - ("name", "followed"), + "name", [ - ("pages_picture_square_past_the_page_foot", True), # its paragraph's three lines the page's last - ("pages_picture_square_past_the_page_foot_mid_paragraph", True), # its first line the page's last - ("pages_table_square_past_the_page_foot", False), # a table wrapped square alone in its paragraph + "pages_picture_square_past_the_page_foot", # its paragraph's three lines the page's last + "pages_picture_square_past_the_page_foot_mid_paragraph", # its first line the page's last + "pages_table_square_past_the_page_foot", # a table wrapped square alone in its paragraph ], ) -def test_a_square_object_past_the_page_foot_goes_on_at_the_next_page(name: str, followed: bool) -> None: +def test_a_square_object_past_the_page_foot_goes_on_at_the_next_page(name: str) -> None: # A picture wrapped square from its paragraph's top, 8000 tall, its band past the body's foot: Hancom # sets it alone at the next page's top, the lines beside it there narrower and the lines left above the - # foot as wide as the column. With the caches the lines stay where the caches put them; without them - # they are broken again beside it there. A table wrapped square is split over the page end instead, its - # band going on at the next page's top: not followed without the caches. + # foot as wide as the column. A table wrapped square is split over the page end instead, its band going + # on at the next page's top as tall as what is left of it. With the caches the lines stay where the + # caches put them; without them they are broken again beside it there. data = (FIXTURES / f"{name}.hwpx").read_bytes() _assert_like_hancom(estimate_pages(data), data, 2) - if followed: - _assert_like_hancom(estimate_pages(_without_caches(data)), data, 2) - else: - assert estimate_pages(_without_caches(data)).unsupported == ( - "section 0: a square-wrapped or offset top-and-bottom object past the page foot",) + _assert_like_hancom(estimate_pages(_without_caches(data)), data, 2) def test_a_top_and_bottom_table_not_split_offset_past_the_page_foot_is_unsupported() -> None: