From 95b2a1cf1dbee9204afae38bf48e87744eefc45a Mon Sep 17 00:00:00 2001 From: Dominik Stadler Date: Sat, 10 Jan 2026 09:11:52 +0100 Subject: [PATCH] Avoid NPE with broken files when reading xls file --- .../poi/hssf/usermodel/HSSFPatriarch.java | 3 + .../poi/hssf/model/TestDrawingAggregate.java | 92 ++++++++++-------- ...29fca9087fe21bca4a80c8bc472a661c98d860.xls | Bin 0 -> 82944 bytes 3 files changed, 54 insertions(+), 41 deletions(-) create mode 100644 test-data/spreadsheet/crash-e329fca9087fe21bca4a80c8bc472a661c98d860.xls diff --git a/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java b/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java index ff2485cf6b..8421df2b65 100644 --- a/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java +++ b/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java @@ -558,6 +558,9 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing !file.getName().equals("clusterfuzz-testcase-minimized-POIHSSFFuzzer-5285517825277952.xls") && - !file.getName().equals("clusterfuzz-testcase-minimized-POIHSSFFuzzer-4977868385681408.xls")). + !file.getName().equals("clusterfuzz-testcase-minimized-POIHSSFFuzzer-4977868385681408.xls") && + !file.getName().equals("crash-e329fca9087fe21bca4a80c8bc472a661c98d860.xls")). map(Arguments::of); } @@ -359,8 +361,9 @@ class TestDrawingAggregate { // the sheet's drawing is not aggregated assertEquals(394, records.size(), "wrong size of sheet records stream"); // the last record before the drawing block - assertTrue(records.get(18) instanceof RowRecordsAggregate, - "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName()); + assertInstanceOf(RowRecordsAggregate.class, records.get(18), + "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass() + .getSimpleName()); // records to be aggregated List dgRecords = records.subList(19, 389); @@ -380,7 +383,7 @@ class TestDrawingAggregate { } // the first record after the drawing block - assertTrue(records.get(389) instanceof WindowTwoRecord, "records.get(389) is expected to be Window2"); + assertInstanceOf(WindowTwoRecord.class, records.get(389), "records.get(389) is expected to be Window2"); // aggregate drawing records. // The subrange [19, 388] is expected to be replaced with a EscherAggregate object @@ -389,12 +392,13 @@ class TestDrawingAggregate { EscherAggregate agg = (EscherAggregate) records.get(loc); assertEquals(25, records.size(), "wrong size of the aggregated sheet records stream"); - assertTrue(records.get(18) instanceof RowRecordsAggregate, - "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName()); - assertTrue(records.get(19) instanceof EscherAggregate, - "records.get(19) is expected to be EscherAggregate but was " + records.get(19).getClass().getSimpleName()); - assertTrue(records.get(20) instanceof WindowTwoRecord, - "records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName()); + assertInstanceOf(RowRecordsAggregate.class, records.get(18), + "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass() + .getSimpleName()); + assertInstanceOf(EscherAggregate.class, records.get(19), + "records.get(19) is expected to be EscherAggregate but was " + records.get(19).getClass().getSimpleName()); + assertInstanceOf(WindowTwoRecord.class, records.get(20), + "records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName()); byte[] dgBytesAfterSave = agg.serialize(); assertEquals(dgBytes.length, dgBytesAfterSave.length, "different size of drawing data before and after save"); @@ -423,8 +427,9 @@ class TestDrawingAggregate { // the sheet's drawing is not aggregated assertEquals(32, records.size(), "wrong size of sheet records stream"); // the last record before the drawing block - assertTrue(records.get(18) instanceof RowRecordsAggregate, - "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName()); + assertInstanceOf(RowRecordsAggregate.class, records.get(18), + "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass() + .getSimpleName()); // records to be aggregated List dgRecords = records.subList(19, 26); @@ -444,7 +449,7 @@ class TestDrawingAggregate { byte[] dgBytes = toByteArray(dgRecords); // the first record after the drawing block - assertTrue(records.get(26) instanceof WindowTwoRecord, "records.get(26) is expected to be Window2"); + assertInstanceOf(WindowTwoRecord.class, records.get(26), "records.get(26) is expected to be Window2"); // aggregate drawing records. // The subrange [19, 38] is expected to be replaced with a EscherAggregate object @@ -453,12 +458,13 @@ class TestDrawingAggregate { EscherAggregate agg = (EscherAggregate) records.get(loc); assertEquals(26, records.size(), "wrong size of the aggregated sheet records stream"); - assertTrue(records.get(18) instanceof RowRecordsAggregate, - "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName()); - assertTrue(records.get(19) instanceof EscherAggregate, - "records.get(19) is expected to be EscherAggregate but was " + records.get(19).getClass().getSimpleName()); - assertTrue(records.get(20) instanceof WindowTwoRecord, - "records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName()); + assertInstanceOf(RowRecordsAggregate.class, records.get(18), + "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass() + .getSimpleName()); + assertInstanceOf(EscherAggregate.class, records.get(19), + "records.get(19) is expected to be EscherAggregate but was " + records.get(19).getClass().getSimpleName()); + assertInstanceOf(WindowTwoRecord.class, records.get(20), + "records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName()); byte[] dgBytesAfterSave = agg.serialize(); assertEquals(dgBytes.length, dgBytesAfterSave.length, "different size of drawing data before and after save"); @@ -504,8 +510,9 @@ class TestDrawingAggregate { // the sheet's drawing is not aggregated assertEquals(46, records.size(), "wrong size of sheet records stream"); // the last record before the drawing block - assertTrue(records.get(18) instanceof RowRecordsAggregate, - "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName()); + assertInstanceOf(RowRecordsAggregate.class, records.get(18), + "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass() + .getSimpleName()); // records to be aggregated List dgRecords = records.subList(19, 39); @@ -525,7 +532,7 @@ class TestDrawingAggregate { byte[] dgBytes = toByteArray(dgRecords); // the first record after the drawing block - assertTrue(records.get(39) instanceof WindowTwoRecord, "records.get(39) is expected to be Window2"); + assertInstanceOf(WindowTwoRecord.class, records.get(39), "records.get(39) is expected to be Window2"); // aggregate drawing records. // The subrange [19, 38] is expected to be replaced with a EscherAggregate object @@ -534,12 +541,13 @@ class TestDrawingAggregate { EscherAggregate agg = (EscherAggregate) records.get(loc); assertEquals(27, records.size(), "wrong size of the aggregated sheet records stream"); - assertTrue(records.get(18) instanceof RowRecordsAggregate, - "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName()); - assertTrue(records.get(19) instanceof EscherAggregate, - "records.get(19) is expected to be EscherAggregate but was " + records.get(19).getClass().getSimpleName()); - assertTrue(records.get(20) instanceof WindowTwoRecord, - "records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName()); + assertInstanceOf(RowRecordsAggregate.class, records.get(18), + "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass() + .getSimpleName()); + assertInstanceOf(EscherAggregate.class, records.get(19), + "records.get(19) is expected to be EscherAggregate but was " + records.get(19).getClass().getSimpleName()); + assertInstanceOf(WindowTwoRecord.class, records.get(20), + "records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName()); byte[] dgBytesAfterSave = agg.serialize(); assertEquals(dgBytes.length, dgBytesAfterSave.length, "different size of drawing data before and after save"); @@ -561,8 +569,9 @@ class TestDrawingAggregate { // the sheet's drawing is not aggregated assertEquals(315, records.size(), "wrong size of sheet records stream"); // the last record before the drawing block - assertTrue(records.get(21) instanceof RowRecordsAggregate, - "records.get(21) is expected to be RowRecordsAggregate but was " + records.get(21).getClass().getSimpleName()); + assertInstanceOf(RowRecordsAggregate.class, records.get(21), + "records.get(21) is expected to be RowRecordsAggregate but was " + records.get(21).getClass() + .getSimpleName()); // records to be aggregated List dgRecords = records.subList(22, 300); @@ -581,7 +590,7 @@ class TestDrawingAggregate { byte[] dgBytes = toByteArray(dgRecords); // the first record after the drawing block - assertTrue(records.get(300) instanceof WindowTwoRecord, "records.get(300) is expected to be Window2"); + assertInstanceOf(WindowTwoRecord.class, records.get(300), "records.get(300) is expected to be Window2"); // aggregate drawing records. // The subrange [19, 299] is expected to be replaced with a EscherAggregate object @@ -590,12 +599,13 @@ class TestDrawingAggregate { EscherAggregate agg = (EscherAggregate) records.get(loc); assertEquals(38, records.size(), "wrong size of the aggregated sheet records stream"); - assertTrue(records.get(21) instanceof RowRecordsAggregate, - "records.get(21) is expected to be RowRecordsAggregate but was " + records.get(21).getClass().getSimpleName()); - assertTrue(records.get(22) instanceof EscherAggregate, - "records.get(22) is expected to be EscherAggregate but was " + records.get(22).getClass().getSimpleName()); - assertTrue(records.get(23) instanceof WindowTwoRecord, - "records.get(23) is expected to be Window2 but was " + records.get(23).getClass().getSimpleName()); + assertInstanceOf(RowRecordsAggregate.class, records.get(21), + "records.get(21) is expected to be RowRecordsAggregate but was " + records.get(21).getClass() + .getSimpleName()); + assertInstanceOf(EscherAggregate.class, records.get(22), + "records.get(22) is expected to be EscherAggregate but was " + records.get(22).getClass().getSimpleName()); + assertInstanceOf(WindowTwoRecord.class, records.get(23), + "records.get(23) is expected to be Window2 but was " + records.get(23).getClass().getSimpleName()); byte[] dgBytesAfterSave = agg.serialize(); assertEquals(dgBytes.length, dgBytesAfterSave.length, "different size of drawing data before and after save"); @@ -737,8 +747,8 @@ class TestDrawingAggregate { sheet.aggregateDrawingRecords(drawingManager, false); assertEquals(2, records.size(), "drawing was not fully aggregated"); - assertTrue(records.get(0) instanceof EscherAggregate, "expected EscherAggregate"); - assertTrue(records.get(1) instanceof EOFRecord, "expected EOFRecord"); + assertInstanceOf(EscherAggregate.class, records.get(0), "expected EscherAggregate"); + assertInstanceOf(EOFRecord.class, records.get(1), "expected EOFRecord"); EscherAggregate agg = (EscherAggregate) records.get(0); byte[] dgBytesAfterSave = agg.serialize(); @@ -902,8 +912,8 @@ class TestDrawingAggregate { sheet.aggregateDrawingRecords(drawingManager, false); assertEquals(2, records.size(), "drawing was not fully aggregated"); - assertTrue(records.get(0) instanceof EscherAggregate, "expected EscherAggregate"); - assertTrue(records.get(1) instanceof EOFRecord, "expected EOFRecord"); + assertInstanceOf(EscherAggregate.class, records.get(0), "expected EscherAggregate"); + assertInstanceOf(EOFRecord.class, records.get(1), "expected EOFRecord"); EscherAggregate agg = (EscherAggregate) records.get(0); diff --git a/test-data/spreadsheet/crash-e329fca9087fe21bca4a80c8bc472a661c98d860.xls b/test-data/spreadsheet/crash-e329fca9087fe21bca4a80c8bc472a661c98d860.xls new file mode 100644 index 0000000000000000000000000000000000000000..e0dddca5225621b4063245c62d8b5c58642edac6 GIT binary patch literal 82944 zcmeHw3w%`7o&T9Uh7dp|fEeZB6;T2P42p^xAwYOP62nuakRh2s%H+W$;i0HeQEA1N zwzk@qw%A&0t8Lvr-4-ggw52WGrK{W8uKh3DwOhCA?xwB#Uv^i^|NA}n+}E5lVQ#$L z|0_42GiP#V=68SZ^E=k%-~mA(ZpPg%Y<>@^!R){i6Kl5&3$P7$tU# z>0-l``!1P{-wXV5LqU!F-ox^Bl6*Z6uQBm;`I}$JJ2S;a;sm~b_U?mtCa>byJdqKt zA}P}1zvojt7({13_bb3fVP*LA1n4+>_YpG7@af^4pH3_qFN(zlLQI-G>C(zeFRj`< z^~Q}A&OaNcPAs|v9$Zmf_uHcq`!-Iz3e67b$!QL`COnIWd)4?p$)Zkpx)(KIXYi@Bmw z+z@=2O+oN^5;fl==g##Wdabwu+TlIa`MvvG=g0EV{$E}#o&f)2mjZ`N@mB?7v%sZi ztV!ZVyq}JH`X>{MZW5n{SaSUAHqjtbqFKD79{_X3lMtB?zzjUQzo%z^KCx)2_zW=Z z7ep>hbYMHgQ{q|?+YE}QfdeM0`I*g={=ebCn1t_7^6}IDJzr}CUndrA7oQbZ=X&U7 z2*Lgd#h^dZ`<&n6=iUQ@pE-}aM|@7qF+DDu9l0KB{$B9$bH&_#X}&`|4K5lO?E&|& z*C{uB%Zz{rg`e9zI4#D|sfvF)YsuPvIcD)b{GNUP4d#75S;Ydt;0bvP(h@uOCJr$T&xfn;b$A;m(x);BZ z4Ra4}3^jc`1RvYqJu6;_m7oZ*=HZz5C$UA06r%4|ek|gB7G7hB#0pVwz;}o&pKua| z@1H@rS`6zOh5C75R3h$)4FzM5#cJ?cBPRZiydQ!008)ZxzvSP+#y1i45F#PrY4f_f zlTF*&QtjQ=tQj+#&Vtn?VkFps-;nLX4jB`Hka1Xng-`5jC#n~K!pBAn@pF{FM;QUT zA3;t5N&%Xtk@9_+#5w`^Z+`Z7f3j+(#h&PB}N{Xq^4 za^O$K0mmO?KY(r2;|Laq%2tz+RsmX0=Ub=e+V4)!jfu7Rq(s~)bJoyvGCPFYWD=Dz!&|%^&hEAd;Hd5XrM#F>*_S}2?!Z5@a@>1Vpn?6iT zunEAuZ^`(G(I5W`)c-|DRq-#b{x3m%!oO1aKY#3eKUNUOuNc4Z-B8dpR{RVwpTNCp z^vn~C!+`S*_@vZ_%Uk%5_b$Zu;A`>Q8}RE3@!PnHBz}fil^1{AllALw;n%!J9EZx^ zOp@PyT^wPI*0*H^vcqH*)$E)XnJixG>rgcgrVqnF!s-;X&7iC z-0@|(X&U3wG~A^Lk-tq-XHUA*BWeYR0=e=s5j9*RYWB>52r8k7DnoWwCu%r|BHYSR z`4BZ4hQq6xL4Q5SvAViDGO1>(wcVOs)pm8Y`n(Oaje`0Wi_!SAFB6R;G#d90h{n;N zje;8^9>r_6;6{K(!mS>i4~-*S!NGaiG&W^Ysdi6tt3e%vDlZdN=V?^EJOHW$GsKcA zo9Ee7od>E2cg2`|sJhUl>LQ0KS8~lgZJk!rwp3TQV{ngwLff^`Y;}VhsZm&QRe0SL za2F%tEcyz^qt@j%5)=~d#`E)`aE43am5RddOtQVJC6%!iw7bJK9Z`=2%~!ZIw?Gg@eJ%LkX)i`Anw!vGOve3QaRRvc^Bn!R6hd67 zgj{75@@P;?h-*! ztT7r{uNxz?#?ojH3no6;_wS|lQqh1EG~A*vOKc<>MMoW4hv0X9Kn4V6kbg7 zaG5APU!!naND8l2UiCU-%W*y^B*a(yq0kdt!lkgxqp%rX6(qUsd<#f&Vj2@kV>ObV z3rW%(MbcccA8gBZsbfJBAs)FXx6nM2M!F;cXGa%1Gp+4DiZ*~Ex;9=WiZ0M7Dw!2d z4Qs_jsfG*DDC-nm0E!6lk#Pg2sHvmJPtoRcP*ko_v>_x#i$Mn)^Ch56r>Gnh5n_7$ zfGO%is&%`kbwP^s#_mEzkry#Ph3AKln3qYqs>E_Ryq~Rm7lJOrt(}k$T}D6H*^%Be zeOD&g>5DS>+?igBNMyIulY{s}L+xTy;nZ>EgNwWD(+_yvQ2sniOIm$E3Qp!KSub zS%mEeVPo+?UZxOboF=s;*Mygvg+bj`kjLz^sjVId@(8!`;(Vkw!6grx?U0w{=DSkK zwCCiX0F@ZymzT+ZjMv2X7_iB|b+*JhctX;*-slm>gFZssmlu7bT>237JM?uX)9F-q z>+PPwZ39spEa7Dm-2_c^uMI$S3FzgcQZsMEsJpJ26F?f_j=3Zs(Ouw@hG^U&t*bke z>TcSWt(p&mKF036OhTKe32pYZ;e@tHHDjBNLYoN62r-=(Wx-}l3d>3-x1=C7w_&~+ z6nV{g0T=8t+mC&*xB;?r4(zHY6G} zp*;=qFk4DqCVQKtk+(YpdHiu3JPC!?ZuBIRKpr6;xhx;@jIn+zLgDV#mR9uJS}@(O zIhAhRnab>O)bi7yu)kRUQjNkBp(sp<9kQ8AU{J;s7+(qs3GtE3^P%uOSAg&to&b~0 zo$4uJYO89m?s#ZbVz0Oxq)l<24v_O%#`bEW%As$%m{$ zmnoFPbJl*y6&lbfoI&DrG|E!*(S=aD1z=UU5DuJvq;xz=FDmAUmLu@T6) z7KpDR>rGc2q$Msc2Q7qqydPS;4krM}%hdc%(eQmPH1CD-q6Omj$Q}O|o|TR76yQs^ zFID8j`^hfvFB76+;p)1z4GR{oF0D^>bf#0*!W})WopSEPN;rv3Yck#C2xkP+8XzXyI_sguyEdrrMJ#o zv$SrNLmRVno?FjAEsFZy2~6h4Y$KYgXuA)on=0J5!@^ojo)O}1s98)fb>k@BPh$8- zoQ<)k9#lVj+Ju0ID3lcHaefSgzGaR0xp-rmpF%rQXvTd9r^+mT_m5L9Yz|5q3WZ%~ zD_0CdFg7-iRQj>eIW!a4)L<~=?Q_VMeX|_mu;Z7Y!pFo+h12Beew_4Jsyd59z2a18 zjVyr-F?|SwOMfUFW^@A*y>UE5Nrw3Y5a!zHGSRETNl)=Ds@Fv zX|42RW7VcQ)rd@7?0{gH;NxWy%)AH%!%2frO2M$!&1jwy%<-B13ueA1nAtamH6t>3 zID$7gX#|X>6wG{JL%18S@?(=rFju;s3@xH`TUYL4%plFk+LdbEx~;p?O1S|=Q!?GU z1(xJ@X+@C5mB5FWNfrx0cQmaE`@$oTE|k<5(uOfir?OkR>Z|?K>u$C-w|@L5+x`4w zfns45ltLF-+oPb_EnTg`>7@Wpy5TO=^yB5w`oW13BcT@vyx_u2qrVG*4dJF|`8kwJ zKLS~U15bmo1Y;rL_F!a76wG*uyvKif(jigx}SQHnY8HPo=MuXN)s{ zgI`aTzo!lAIj-f3Vs9L~=BE5}T!ti~-Hr+7L(VP}WF@FU|IIK1iz<&0XWt zdaV!(_B5qCy5uAiJvcyc?F4W}-?Ipf(KRmJy7tLA!I5-vNc(6sLS!WCY#zigtKQbW zXRi12K*wn%KtyGw2|2t)KHI}w*^SXkg;VVf{o}Ms>BrlTY>P!rK^f9$tT{1B=hG^M z(<=d-be*l!bhczpIGr7fPCI)bB#|1E`A15Xs@)vbkifbGkus`uI(LPV3HLb!5_KGszi& ztnKl*Z0CTPe2qX=Y@FlANtgZ_P5Rc{u+nE3aiNS<6Bw;9P1aZgYzX&_05-X#KhHJC z`9X8+q-i>RO}FtVU8!cgIhg?%uCKG{1X%aMHs_HgxJz9tMG3z43iJHQM2y4ufG~l#O;gqiN=QiHlo+4dL#cpO0jwxst(D%mrT5 z>vVrAOT8hE1u7%q%d!3eKS#_gFOwK<1Un zRgG0yM!Pa=N^fQ9f^Dfbq~FulYL#is_W4Ga|Ccc0mA3N0fisM*2f;j?!n_id?SMGMX(ksOJ6msDzbGKgBj@?)l7^UdW^vJP6naZ2$ zv!w10%(P+_ywX~iZ0hN0vvwvicqoT7tjq!PT9TSZTr@f2)e9~QYpZm&d&56YX`sEG8Ep)5+!)C1Y3ItMOmYhbXPdSq+qbH5*&&#H zTn5BS#Bj{|nGH0#V@0(gyV;@`;bk|g7KF(ZCD1niPI@M6sD&%Lb;in!MnZhG9~OAo z%|J(Ep1V4SnWFZcsXdtBraB&_-iO|ZHToXD@o5StF1GkO8YV^9swqM*unn7@As3EI zMVM)f+_r)XgnMK~Zbk6YGmWmPClR?RBUI*WRbaTj4IaDFHPf~Zq`G@D2u8a1bf&D1 z7OMp#kNCH%Gn0fhbCeR6?JQh#gBR(qXE;{;CK%O73F0zY@wN!9n4_TV3fOhF(!>Pj zc{dV|Lo5C4(u0szCA_zvdS%l}oCuJ$j#I0`Y1S$~PI~HfyTZvcD62M%L0Q-m$e#Q$ z3tf|JJmO+I@F2vK0X%{}#WSd^8I>>(*IXRIuYeew8I>l%rz2xB8|bUiBoZL&Y~o_@ zQMTZpsPi*fZ=l;0PF_;=G0EgGGb7{Rat(Y}T=W*qHzrlF7`c&ftLy#P{EI zLRBV91k667Ly`IR?UAZ-ErdgWtg}guVcQs6Ro)1YtgA|=!pT#W#)SiM@Uzf0A1c07 zc)h_p#Ic1dXvi%9&%xi|I`|ufaH6by9K5$+6)nJ2$AV|Ub>GmBSayH~Q3YTL zaUI5w>AG3#V%ed@l3wj+gf5nhCYF~&i-rB7o8U+2ylae8d@{g>aEsRXu?bqRCzf@t zSk|-MWh~*C1?Ks9y&v_FwIY?2E2EbnBvayg1aM#Nhdo|f^0dpIXB2yw>*#2yL`BbG2cTRS--P*u zU6>8EQ=9O~U)X($WLsxihA~=PLU_K8hgG*^HMwiw(yb(56P4DMWTvS@&TH&yO18J- z5ssN0DokKAP5Ux6blr;QZ{K@SA?JeQ1jt%9lWt`u$JhE5Q;%?Z03s^WB`)^VQr0?7 zJqo9d>-;$B5zbDe$TQ6qC3wkuLCs6}hRWE*Rp3bB@t8eiWtE>6#8q=Q(#dOYxJ}zUn6~;jRcHlvXF9q<(#q_|upEcZ{q_ZQ_ePvd^ zxHQ`U3_;wrXnLG^KPFk+5t%F)#4VFSoF!{r7I!FFJaemG7J75ISK;IZaaBvgHisNv zS&1lt&biKDj&ZRU*br{*ZGLQWNrZcR@v6oG4YAr@YQ7$8=$&+F!24h_Rv@}|yiqxX zQ6<5c4dc#8g|SL@BKith>%zc_|3;!Rd840vy-m6+GMtJpR}Ul~t$J<)!j&4TM)tOy4A27&TU|=>*{?<25$za z)@}NJ;1pGynZWcw#+i1l<8;5m>5)diBy^k}h)`D>V|54yXwwbkyk^r6D4Z&jew=h& zeNfZY#Ik|t>RNc<0`cp@^~P@NgTRJxj|Z^HrK>l(x{A4BOZGHpl0E6xCTy^$2BbZ0 zwbpjGa!jcIzUh3lNytmc%ak(TukoNUG!ID2T6kFw>u)fQj_n5z2=|FCeu?D81E;Up z<@Pbj0(Q-Vqh(g^F|8#59_YIHuE=zgLDD+-QQ9zTT{qvQbaP*mpA$Mx?*>j$*>DwR zh;d8HK4_@Pue@8~G`_iioF0mdPsQTd*c#x%np@B4e0oUX^pyZkdSHJ*;pFvSE0%}p zO(if#%O3LDXbkKR01rZ3k@E8L*$^+4llOR3@8{xX@(HIK5Zlbm$y79gK`m#o|D6qW5d`9t=S*L$6JMOrtc@`+m?%h)=Zo`JRj3N|#>X>^81` zyL1{-&nhdKwslPNKL7xmjLOTDa`-@GD#y9un^ekywXSj>P%5|goqp1F(|iOtMP-@- z2Uyt?+*s>4J)&?Lv%P?b2nn{_J z;NBOe@$L@+4??U>`+1W~RRf#aE>asCR9f@v7p&HTUsK=hpP{MFrnV+ceKax&un}oO zAwbr;Ry?XCFuu)Cxh{dnGzpvvAptszEqFR-F*O-1CN8jBOd}zFC4fgR2?Tdjb_Q~i zEh%(6Fhi-CgFdB(fgzu}C`RA{&nhod;PPQbuot*ktHK5@Fm9YA!sXuyu@#1p&HlLf zFvup{1MPnH=OViTaClX7Evct?&b$75TtCK-E9B43q02`=a8$l1A+?QUn6>UBO6$@c zezJA{_)#TcVvo|(1NG4PrB6@ zCL97Dg!p;@k6bEY-uW?T2~G>yi)UYe=khWI1Rv8VOVs6083)R_)`Z!y?MBKz2FeKW zjU9dt=c4RSs_Y++P_Yu?ogkZIL9BJf!tOPVyniy|CtL3-eL~^nd7S-VR@kmm0z$C6 zO56F+tRz%id;-`IZgZC(n_NN&Zb)Kww1!m&fxyhaA&IHEI}Ey`ay&xHf<|VR#bG6j zz1@E5bt8XVGX+r}#uO6h3ftZH4x0?hid6{_s$q4O0V1}68UuB)Gc`@-x#rxL-H0yToDa{UcgHz${AdN&9dnX+RY~tcm zz=m-5?aW64fhBO-Bz50p5|if@P=zvg37pCEKB1}GiID2H0}N-h*JUIY8#Ol)V)L$i zh`riXH>`tq6z!ZUSCQI{sZ8z3v^!<25Fr-lnes9z-=`y0z6_qi)}6Jke4kdzSH0WM z0p0MQ)Fe@JbN+@;$3sa_?Yazj#1VNQ2>^&M1@Opa`1!ft{sY|tNa0F}i&+X!M<#`0 zaT;d`a|GmcENO`HW0)CbH-*pa@k>FE`<{sqCsEK0>WdMWFz(Vd;~9lh?d|>J^!W&J z>WgiKMHGv^7`G6LTf^o2-q;`YeIsm+-A{({1(`;Pwk^u-8qIvs0A_lf$% z9e{N{eNo{wd~g3aJsT-b8KfDBQ@3GEDJGs(I6ZL=oW2B{q6>R=z}{@{W6DQ;N#Rs| zXa9Wqa)f;9jqzlbV$mDB!8qddWrfpA=fLSJ5#n?##`O-x$Vc(?7+s&fqHs#z)jyxU z8YxaZdWbk(W%QX}RX7#h-9JuWk4&G4%T#H1$6_;#IDK8=bSQw6-kOe5eDYH2OIGLK zn)1gLm~X+wyHgE16c?j_2O+)@z$4h2dPm|o$M;m@cXC;_GX=OggRRZ&keR*mGW^+> zDQbBxQrTaMSuNyug<*_7CZ1D#KH2M+z0T({jnBtI@|g>e?M2eMpN*3vjfB{Ij~|a* zd=4D6!R7A`pIfl1%wsg>%~KHaGBNrHh>FTVa&F*@aFBMb8~zc+=<0j@1nPmw(Fk!8 zI5&JhaI$M1r=tp|m(GFHw<5!d3Q#Maltc2Yb)3GXa7y3j=aa6G`!t2zzb1dfA0nQ` z^ubny(I+vBQg_sGu@86!v#&?TEuXs5WfycmT_7i?yXr7<`=OB;}U&)KWKo-zIpr1aj@%FNSI(^^B zL0`q%FakV=iP1KF=Goxi0DXjbO2iFZG!&d~Hm}(hfTv>Y@I1%pTcl&V)s)M&KFEA-c zccJ+nB47$+z8je!c!)r;R1Rh|Ov>?HC5ROd`H9vA@x2^^C|Ms?5Rfj~KYQF~2wKc+ zg^i2v0Vl$JB7jp+5MEJTTgp?2g znkDspC8?7KbV+gW!a0-VL}WN|ic~TBQLIah;oS*^)8vQy$LR+V;&eJzAp5_kV@1Xl zBR^0$9SPv%wK2}2O!#@$(ebB3>v9nsT!EBWUtys^mnUK;ddyP*+%@mA_;fn!Q4c8f*a}z4&es3$yvH;?LzlVt>vI=C>VKW+^L}sU4E1O zQ5IbTcO%83Ggb{#Wj)7evOiMhQTslRt~mvx#Mk1Dz_13zxhBBO3VURSGlnC_@NVd@ zF)BqZNFc)j2d|xJ?%`<`C{Os@kYUP&txtrzv zY4ZLR^7USMr&nTc!@sP6Ts|xA!6z>iaeHlU^M0TF_CERgxR@lrL3(1cjp8qOomP#& z>A6F(LZARp@01u7h_96rry}|PP|&<|nEk)N*7m$e73f4M!H!h+`?nc5YU3vKzSO1rQO8%9~|M_F* z`>}$!r22fpcifg~toRvVK7sF4BZ5!hH^h&dIF$NuiDR!&-n#$=*F}F{bBTCL^t?4h zTnO;XFlW^>+3|xcdnJ^X@|K^XgH?;W3sQ+*1Fqs zuQ*OYY9h%rZH-x=(e(O&Xc__Ta#u7S?x43G1)zy=>mSWcljm56yEKh(XyT609#Pn( zUm1d#s6vgX>ehh>iYHW%s4`=IsSrdFZsTM55H;EjS>cA{-t%2J+zO{<;ylpVRc%*0 z=U8E{A2AB*SBw)1M&sGMOoA)YXgn|=8o9qeY2-HJy5NdHBjI*_I3F5ExPpTtv}u%Q zLU@wHcICd)PrLxlF|lHes#gX;mF-DLm7S!^-V3f6R1t3PNAjWSLYJzG9I9N&HTSf2 za-)$hb;z7!bf(Ih)OCnP_TB-Ioj^PERjIDr6jdjC2*@Vf z!-sN{?fK5Y9Brwtoe(D|%%V4ImtxBq1sVyOojKa316xWI&ECk?N#K_6EKtTFS1KWM z^iQX@1k@7ZvmeV%t>;z8xN3|T$XPt$?OEg5Xd-?}okT(n*7Np5HL}KU4@VX!{7`pi z8Oa(7vIw!}6S>LqQUS)ph_epK#*!FVsCOp)(4nXLJ&d?iqc9zkLJl3%|8RI)7hEYQ zB*gN=xheDn$8)lHRl~Emf>R{9-KdGhr_|TXLK~)$bR;B6a}-J3CqXA^7)T<-zPv~Z zp4hIYjLOZMJT+`9IwjSEq?^=mxJJ?NbT~Dv#W+9Jkh?7C6b%POgm~ide1v4AsHvj| zTX(rKdf^-tjnF9C7?PsJpo411JsNb1Mt~whJp9Q4Q-rnL*m1z6=!*f0^yd6LMUgWO z)+?UD^TSQkWNu=aq^k;^HABQyG(#c}Ul_HHm)g#8kPjm2YmncC`vCbbo9;iYC_ z>)%$8XJI79)K(`z9^p2AIv=S`P~NSYn(dI6<>tFmNo#2d_)%*m~}{V){|$c=9nR;oGgIR>5tZgR^1*>Xq!|sw%I7O z(V&bF59dW$(CORjZ_~*wsdUN zmTPR6+?0yy%I`vToYw?dA1t!Cg+1hLfoGh ziNO=p`P2Cb zZoDfvcs|F}(j8a}ZYLTvp?w5S65AEZ%j6_4(8${xf;@I%+TckTWVIVT$ps*f5c~2X z&lu~sss-<$5Oc@SQB7lbA+yI(%Wa_W;(jPB*C;$0ib782XEVn|1ttNOgF-?)@k~Af zJkJ#%I((i0aXz{mb2Y=E*m>q)>+KAfT&M{0Vy^L>;T_89!fr%c%;ooBc4f9+PDF|W zoixBb{P}#y;^J0b)l32}TvcleXNX9~?9HT4ZmKp$A{S}2r18w>kvuLH_r#DLFL^!& z+%Pw?2Jg?}eF^rM|;Y&fWIZN5y-d}h_51pZt6#01X>99Oh2@E9Zmq1m#O(3 zr{Q}fH1Cl2pX~DfG9elkuC80#uwdcp()v_KCk|`y4)9p% z4AD8l8G-c1WFT^ST;EU=vEwyjhwlilXe6~5igr2&vExB3;g&y}n^-TU6Ljkhb+v03 ztg#vv&Renc)_H4|)~#}AW0uZy>-xNy35qsn4$8ns=Rg*&RxG?Ch5E$V7=l!Lf>gzy z`6;wJQ_c9TGsr(Ni{Jg@bQVi`5?RK;zw~nWGbj`~omdhd(3nwmc`v|+%#d4Vv%b5TpbU${vCYI{1utr1>!x6f{MMEs6 z1kB~YhHwu)mycM2%S<`Ye5E|lM;eiP1W?L74@{m_h||2-ow8fqxbUy?H_2iOkdCHJ zVTWo2l7-{~Yh4yolq@>`+)usU&Q&N`ynVAR7FIziLSWVy*f!u)p>Qhsh94(gKc*_2 zyb%AD(E7pc??*x}Xtrg>vEQk{hHwuDu#p@!v~z)+!2)HbI4;3)p@Chf9fkNFkg&)J zTqcE>78&zNW&-BGY%*(IA*Lzj_kOc~=3k*Pe@%CI<0SKcCylerIQoFOe~pA&e#DPW zF6IXY-dEsAwzPA?p2O*dpxRbCGp8#7Iy%!!zzq^t);gyv6{pVxXwyw^y5e*crdNfz zS+~OUstU+?9jECEr-MiR{MJoxhQi4+y*CCReIZ6E>0>Nb!zPZA^s+|6t@xH78$Q|; zVon90c~x`&2sw_8L{=9LK1sDV?ZL5_u1^l^I_qf0Z}97>^7qsXJ;QaSqPR&6>zj=4 z^@`e_{4-qa&5nW=(Ei34)``Y3#$DD(h$YYGrqzq(u5xL`Ao7AeP3ev!p?LR7WyWQvpdlA}D>6AyUoU_h zsIRPbIm}XW=>4`|4!WznM&abS%6;HkxRDKl7z->I#g-e>{?`B-!Y%)f9~=J8lZMy1 zc>4|IwE!KJ6_UfdWkbnY=k&FT(`N#-=~j51;&e0(C1(P%p|oe?X6ItAQ#c(w?&r5I z{n-j9Px_O0g_S-7hzn(mn!qT9X_CflU_-bS-}PgYOZxL%Tbv)X#ZJz7QzyE5AuIOf z44yX)t2G>_HP}bE1XwWSnrvtY4I&kwpQe-tkvoegKR4{y8O{&kE&%YG-91A^E9qh?g?u!Tu5yp>>13VF&6t?4G`{zwpPRZBE&xu^cm__3ATE@&8K(sbr}7{7k5g@Ae8Otf z0?w^x&Ha9KKGiCmo(-xb;em^@-mW>uC-0rqruruSItXx_@wI*8WlPPO4IP-Miq zGaYH&yV+sE)Jm&4v&S9A=yY~5hFoVjXG*{?;$Q!G#!n|5759TaUZyp^OF&XIu7cwk zlq_9^S;9+{gb$zcBy8H6XsIUQR|gLdzNnclJ;G*aRi) z&Dxml4$xk2ucU6MTd}&dA+@!KCs;f3w6JMEwh2Ra8!b~$J69xSl3Or`#Xj%ZUO+bl zvyQp&xpk? z6zFKoYrzmFDD9GIqV~XS(cA z5a;9HuFgyn*321AuAceY`cjG ztZZ#09;aUPD~%q6tW?5_CNLr{%=ejbTB&f__L3hbJ@2|oGpNaX!x)q$H-ctU&kZ=U zc@r0_fCnLpzxLz7hk8xDXHZ!)DS0k@9R{tFSi0#5{_}-L-ID)+&}F0Al^m^1(DP7qV8Z3dA6F;7H_B!&%i+ zOOMLAkVL_xDh-jU%C!&gM9|!L(R7K40?jHZhc}L~G6l8}%NELn%t$vVmlmnke+r?IE}7N$Jdu-E}8_W@|aJi;#I zRCcy@^&qL_bs7A}KeTo7>?uQB;`P;0o@LD}NubiArlrGSk!{ z=QDOSCEMHa6{n&5?G;C{t-gJk%w)adc{I_)TyUJ;i?wbh>y??D32o{#tI30Y&uMK*HbBp4W*O;Az4&}RKkfT`(RF}cLq3bQcgAglz>BoZ)^?a$P zmE&Bk#0nl;E1d`@kf(68;Fcjr<>(PPVA6tHBh`Xhv=&UZvDP_$tKzu$AAU-8j^Czn zy!P%e9Jg?oEjwwyE;Mg3dmHc|#K!`7=;G~kHGMLT9 z^o@}+eKGoAWIAh|=^GW(JO8$SroTgD`jJpf=RD}+z(b%rV+!Qo0Xzt?SogJC(E0NIg_lrxj4Zsk@{S?u{H53FclL2gsOctblnGE8%nYby4+oWW1 zI=}-xh}*1i^5Xqjyo-fyL=>46Lf^@d;h$=BPY zWMnuMi^do?(qLU{Y$uZnr@nLGv?WrUxD^I*S}X;V&8IC2r~QB5KcAW+#Hl{U%`A#V zeQcQ#rzVAy^=kh(HAjjQH=-a;tBl$9W`)yp0i1N>PAQx`<6d!3c;il>6MS46_iBTy ziQ{xpES3S>`d|Aw#7CQ=iYcyfS0EP~bg~FWx&23`E!kdaN;w`Kb`--k_GPl^mdIp4 z2g~ioIk&;Q?RbllLDfI_sn%_JD{zV`&P*VU!#LBfbw9IJ;dJ60IBkoJPqby8j=;J> z3MSj8w<(+&f8*zquB)vICr?+$+&d6mT?-G)cx=6~+u90j2=`0?8$Q~kt2es3in(D+ z_B3abJ?Yja3!Bu~1Ja(hYG*D7+9;<@x@+W7^c(HV)Hi*n#)Ib2JRpd*@Uk4%-(Vaa zdnb56xG%rvmq=bbaQcc}NvDrV7O-m`7@@4Ra*t_s2Y8^{%XY>0@2oL|D=M-QfC^? zQf(OeyF-tv8A9fMO{XF^8k4;Z#4^3ZT35wRrHZrv*-x}?vO9oNR3@8{xX@(HIPFk4 zojM0jnaKFW-SfFC6l-p!r1L4GaN71Sem?0Y+of>wOtyAkIFsFk5gtwjZ8XR$jwpE=Vcl%>elFe zBm}(-y*2?dr=FPU?FPMs_;OzKR=V^8XSZ?n+ojWxdR7@Y*ZLPAx01BtGDXBak*OT# zhHp|S2iCgE^(d8lw$CqW-86Rsr>IO*AhlpmaAU3Gv{T`<uvz~v4_uot*Yejse% z0^>$XfD6A9ILGoyjs0r^0FW|McUeTf$um zCofDm4guynGDS;hv5A68=wV%4+yy)c@l*g0KGfuk%sV~?Ex}Rwi{eM!9Un~r!QC2V zV;;<(G7gk;5;IfZ+l`dn4ax}dseku#I2UDqQf2Q|q(%{^C$OKOJ=>kNu2{WFv3k$= z$=1_8_b8k^k8=Rb3fommKnQkMX}bZNIL>Fm_LP8I{vUp9atR^06^Yr=8de0>WCd6}I4K1F8~b|3@~BV?#yK9q2u;{CS& z^3$x_!Tky+&kpv2Q{n9(jYJoFCmlv-bU&~mT=AwK8$R0PW&=y$v_&?)$s{Jvi(_zx zpK_PLnLO_Un!23~sct)fIHSETBe4&FSVBCV7qM5n>NYF?FvF@y?Z#B5_GH?fGWKy8 zKDLgKmr3~^j8yqDcn({4*18jZP$}PYZ~4Wo8~%Px61DHj-|*SGQxa6WE(0EMBr1>u z0L1z~`tiu6cKNyA{sZ0mbGYAkMJ9z}aXPkHj)0twB@I!2OuS1;q2jEcdOhxYcZ4{J zf@Vmf7=a1nE?qO;t#C?+AI0Ps@M6-|ha$wOFSZrWC>DJ&Zb_`;^pL{o%sFs65GhXF z7MVD;q1JIapl~`E>z_{#M~KtuSUb8;)GO}%tK;;rqfZ6>b(l54Tb&l>0pF>>W%S4mSWKxyTLf(bWq{ccMhE1 z7a>l^VqEXQd=yWO(e>$l3a9-={qyPlk>XT^Hk&wIW%QZvS2$V4{p0k3$n=T0OqF(b zEH=Z4(+3nz&joPOThm7rpS&=7#Y6eGrVJ%3FyDfUcc&V3C@vlW9)wsQ_w$Ai^@2F> zbe}Ret{G)7%f`%NIp4QA)9P*dJq6p)mjMDVQ#WP6dc?q}mTJ`*_!KNxIs1;AjA$it1P9Ih{oeAKiE96H=Rw>he&Q5j*4&-n6L&UR~KG=#d`Xpvi>W(@t zJ_0-l@nET+H+-mP_}=vGa@X*2s;Qy(W-VS>?{1WE53*$C0L06b82+dt&FP-rjqeqS zUhzsO0*`^w>?iyjM`D?>fFA{cgt%>3J_H7`fCd8n^sNtM0rl?pp&ay8J{(4X$1pM4 zrq4VZ{1E6P#NOfm-SmAd2Yq`((zgtroAO(3hyvr{W1x=^8%O+U>C;`*$3b6IZnH|x z_$xtX*F5v@56*hq9@G8K@wAaBWfDIwO9KeQ;j@T*a zOg|hU(**_y?1js$bsv0KG5xubex~a-g3#nq#)gemf8nC2j=!UN!Az9 zydW_vFH<1%smKJu!vl(?axkM|QjSk4K_o`?FNh~{2x9nq!wQ0AGg9Zc&k(ej*$NxS zk>}XO6L7Z$a0&{-YpmzGJ5VmI)NqtRM3uVIbtGlpRPM;YWG#F0%2R}=k?^0QeSb{ys8gJJEHIdO89=VrwX zYbfI4v!ID^&-6o+w}VXJ^vj0iF6{Y%ynkyl-DPD`O)2ct=$@a2F&6jqOUK+uq$9G= zBBkw>+82v|7tMy0)j%N%YEjpTT(Q_S;kG=2WU( zq|&^{spczNn=&0;9WCA1xUDIbmU`HG@0hip|Kqn~HTYaiIRBG9zqH@?jydt>`Y201Xuf&cF~kgNaC{&~S)|M;&D z%@~*X047UZQTZQVsKveFtb5H!1Xw6c@GvL9TmXlhH=taAl15=Jpc{pKcjg90qwGT& zi*f*kxdA6v@Jqbsv;XleJ2$}JF6r6UooxHg6WcL+g#Gw=rKJ)k-sY?);$h59FsW3Z z+?tw+6s7&nx=PN#kvA`qdm3$?mq{fhR{oo7TD#M!E-_pIV)B8=tjCf(`#=PV3vuN~ zq+wMO6Hu&%Wcyb9j)?L@T(6=K7hV-8ep&v9=i%+(HOPTM z4h(W&kOPAp805ep2L?GX$bmr)402$Q1OI1pfPGQ+IoStgAC=uY_LpL8U{alXMvyadIJQuTY%%45fF(~JwuwT!_uG7E+KLSuhvIgw;G zY8*r*PnO_zkeoiqBU|U7aH3uf$~=_$C<{<(Q5K>sLRpNm1Z648GL+>g?B}jTS%p%E zQjc;oN(0Jjlr<=8QP!cXM_~?x{d`U*z71s~$~#atp=?HJL`kA-L1{v1MoFQxps+i? z4FxF=x$D4o)M=D9ly;O3lunc#C>fM4lx~zBl$|KMP4VvLEGLDDOsj2;~6E!zh0|d-m*mQ6EHkAIketK7jHF$_G*S z`J<>GL-{buM^HYBatP&PDE#~_Rrr4J`rpTa253?TG{=JGx1-KTje(HzyvAbokb`{z zeq)vJ)t)DWil*dV&wk^?-#m5ei5O+>++2^RXT)~c0P&!fhr33J0{8jEBi~;?dQnV% zwHTJ$1FLF-C6e}~;6jVUiFdkTe;v}^a>1>@^9iXCCEw@2hrkkip}(!g6PhFrDJg+) P_{<&v{U73k)${)sggj&4 literal 0 HcmV?d00001