From 4acfe47bbef6738ee0d8955cfa90ec278158438d Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 22 Aug 2021 18:38:55 +0800 Subject: [PATCH] support sheetName --- CHANGELOG.md | 1 + .../java/cn/hutool/poi/excel/ExcelUtil.java | 12 +++---- .../poi/excel/sax/Excel03SaxReader.java | 20 ++++++----- .../poi/excel/sax/Excel07SaxReader.java | 31 ++++++++++++------ .../hutool/poi/excel/sax/ExcelSaxReader.java | 2 ++ .../cn/hutool/poi/excel/ExcelSaxReadTest.java | 12 +++++++ hutool-poi/src/test/resources/aaa.xlsx | Bin 11430 -> 11888 bytes 7 files changed, 54 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 962fef4f4..4350c21c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ * 【poi 】 增加EscapeStrCellSetter(issue#I466ZZ@Gitee) * 【poi 】 ExcelBase增加renameSheet、cloneSheet(issue#I466ZZ@Gitee) * 【core 】 ListUtil增加splitAvg方法(pr#397@Gitee) +* 【poi 】 Excel07SaxReader支持数字类型sheet名称、支持sheetName:名称前缀(issue#I46OMA@Gitee) ### 🐞Bug修复 * 【core 】 修复MapUtil.sort比较器不一致返回原map的问题(issue#I46AQJ@Gitee) diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelUtil.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelUtil.java index f122f1a3e..17860c8ae 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelUtil.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelUtil.java @@ -75,13 +75,13 @@ public class ExcelUtil { * 通过Sax方式读取Excel,同时支持03和07格式 * * @param file Excel文件 - * @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet + * @param idOrRidOrSheetName Excel中的sheet id或rid编号或sheet名称,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet * @param rowHandler 行处理器 * @since 5.4.4 */ - public static void readBySax(File file, String idOrRid, RowHandler rowHandler) { + public static void readBySax(File file, String idOrRidOrSheetName, RowHandler rowHandler) { final ExcelSaxReader reader = ExcelSaxUtil.createSaxReader(ExcelFileUtil.isXlsx(file), rowHandler); - reader.read(file, idOrRid); + reader.read(file, idOrRidOrSheetName); } /** @@ -102,14 +102,14 @@ public class ExcelUtil { * 通过Sax方式读取Excel,同时支持03和07格式 * * @param in Excel流 - * @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet + * @param idOrRidOrSheetName Excel中的sheet id或rid编号或sheet名称,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet * @param rowHandler 行处理器 * @since 5.4.4 */ - public static void readBySax(InputStream in, String idOrRid, RowHandler rowHandler) { + public static void readBySax(InputStream in, String idOrRidOrSheetName, RowHandler rowHandler) { in = IoUtil.toMarkSupportStream(in); final ExcelSaxReader reader = ExcelSaxUtil.createSaxReader(ExcelFileUtil.isXlsx(in), rowHandler); - reader.read(in, idOrRid); + reader.read(in, idOrRidOrSheetName); } // ------------------------------------------------------------------------------------ Read by Sax end diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java index 0cdd3f054..9319e5d27 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java @@ -196,7 +196,8 @@ public class Excel03SaxReader implements HSSFListener, ExcelSaxReader { // sheetIndex需转换为rid final SheetRidReader ridReader = new SheetRidReader().read(xssfReader); - final int sheetIndex; - Integer rid; - try { - sheetIndex = Integer.parseInt(idOrRidOrSheetName); - rid = ridReader.getRidBySheetIdBase0(sheetIndex); - return (null != rid) ? rid : sheetIndex; - } catch (NumberFormatException ignore) { - // 非数字,可能为sheet名称 - rid = ridReader.getRidByNameBase0(idOrRidOrSheetName); + if (StrUtil.startWithIgnoreCase(idOrRidOrSheetName, SHEET_NAME_PREFIX)) { + // name:开头的被认为是sheet名称直接处理 + idOrRidOrSheetName = StrUtil.removePrefixIgnoreCase(idOrRidOrSheetName, SHEET_NAME_PREFIX); + final Integer rid = ridReader.getRidByNameBase0(idOrRidOrSheetName); if (null != rid) { return rid; } + } else { + // 尝试查找名称 + Integer rid = ridReader.getRidByNameBase0(idOrRidOrSheetName); + if (null != rid) { + return rid; + } + + try { + final int sheetIndex = Integer.parseInt(idOrRidOrSheetName); + rid = ridReader.getRidBySheetIdBase0(sheetIndex); + // 如果查找不到对应index,则认为用户传入的直接是rid + return ObjectUtil.defaultIfNull(rid, sheetIndex); + } catch (NumberFormatException ignore) { + // 非数字,说明非index,且没有对应名称,抛出异常 + } } throw new IllegalArgumentException("Invalid rId or id or sheetName: " + idOrRidOrSheetName); } // --------------------------------------------------------------------------------------- Private method end -} \ No newline at end of file +} diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxReader.java index eef707551..5c084f115 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxReader.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ExcelSaxReader.java @@ -17,6 +17,8 @@ public interface ExcelSaxReader { // sheet r:Id前缀 String RID_PREFIX = "rId"; + // sheet name前缀 + String SHEET_NAME_PREFIX = "sheetName:"; /** * 开始读取Excel diff --git a/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelSaxReadTest.java b/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelSaxReadTest.java index 3429d9356..cda21e304 100644 --- a/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelSaxReadTest.java +++ b/hutool-poi/src/test/java/cn/hutool/poi/excel/ExcelSaxReadTest.java @@ -32,6 +32,17 @@ public class ExcelSaxReadTest { ExcelUtil.readBySax("aaa.xlsx", 0, createRowHandler()); } + @Test + public void excel07ByNameTest() { + // 工具化快速读取 + // sheet名称是区分大小写的 + ExcelUtil.readBySax("aaa.xlsx", "Sheet1", createRowHandler()); + // 纯数字名称也支持 + ExcelUtil.readBySax("aaa.xlsx", "12", createRowHandler()); + // 前缀支持 + ExcelUtil.readBySax("aaa.xlsx", "sheetName:12", createRowHandler()); + } + @Test public void excel07FromStreamTest() { // issue#1225 非markSupport的流读取会错误 @@ -51,6 +62,7 @@ public class ExcelSaxReadTest { public void excel03ByNameTest() { Excel03SaxReader reader = new Excel03SaxReader(createRowHandler()); reader.read("aaa.xls", "校园入学"); + reader.read("aaa.xls", "sheetName:校园入学"); } @Test(expected = POIException.class) diff --git a/hutool-poi/src/test/resources/aaa.xlsx b/hutool-poi/src/test/resources/aaa.xlsx index ed2ebf3583eff1e8a6e94fcd76c355959a7d1617..97ba4bfad4896ed3f8ce77993130fa92665fad10 100644 GIT binary patch delta 4269 zcmZ9PbyO5uyT)l8a)2SFV_+zWkv`N&r*xMf-5>}D2L>2YVul70R7$!-Bt$@DBn9b4 zM3IslVlJL-Ro;?^4Tso4QRB0AsEN&Y1uYFA%*;!UUh!Ul#*L z*t_F;55wc1A(eTInwpBLo8G9tAW!`eyfDCB&ol3C%yk_x2-%M9;+)p@N_7qRis9?( z@TsJ&j;S}Qq?nXMq#N378Hq?p`gi z=*;K=9TzGGuf0YsxK%RlQWW)xY@^R00LWk3D&cw2qg?&PG(y{+ZSV&!s5=eXk1U4R zlTkSJmt$78wXf1T@4R@n*QOR4)SOlly3iu(6nqtD+GWJ2&eymrm94+Q+=X|)w*Q)Q z-~;qnk4I-r-5+GT=GWx86&{T@4G8qzNIamtq+{B2>dl+@RMZ?E=eOIfciCF4b#b&T zAMK#@?2>?t+KV`ba|eF;*1l{dovM&t8WQp3ZAtXEwZTo9_<`1S&J-U_JR{cked2rv zyv2Pnohl=`sDMu_=ADDzizQiM4*ai|tA5_ic=Z%>3bh-$xOItj{2uJ9$ci&p(ynj0 zs0yWNHZa-@d$#IuEBoD7O{-shClRx!h zNP&;Dm=&F*XB*x`)0}O`+lDIFzR`(%*vdUMh3j3uW7xP`r6coM{#X$MEmQ2G^W}fQ->q8-8)a-8&L= zEfq6dTr||%s{n25ix2}L_p*1Cpl`Dg-y{HTSxl09SuXPtBBbuGL_Cu?EKin0dJ?QV z#ZeQrbcKOSCw$L-nyR%pJcG);ybm-Yu*$Ld9<08+%n+@iU9cs$l{ua^PADUnzqDK; z|3JEiXrBl$=hAf4rOy=jf~eot!DEaGl57fJSf8lLtrXesywEiDVnR~u`d4hHr_FdW zl?uFyY^Qlj@G})iPJe3AE#&f3AIewL3-OWG`wOT(6>l-5jfIhx+)Hq7pB^|gjqNxc zk0)k3f^u#s3i>x2*w4+qEL-PE{blpa+yCs4iC=_?*LVva?uVv`$*3UbMJ z@(RB=d_Wwuo}#-X=Bwy{t@+H0bpJN<<6y*&Rm>SHn><%wMK()1snXI~YiRY_f6Z`% zNDeF#Rxcb!D`EVlR4#-V7C4w@6aU0uC8KROL4q%a-%o)g&N}VDZj&+)Zn4zBs>y30 zbyz6IRrO>1X(zv6YuLud1Wk#Mae=v~Ik%@eM^>|NoSYFLyTko0e_njKbVH$xY^6j@ zflRIowY+6kAM+TlJ_4UH9oFb?0qm3ld^hGk*9XLop8r1Ke+~#uQ6YP$OrcgQv4JUzM?3wKBc6XocnbXP^k8i&6S#j3eD<*RFRiREuEhsFf z^GCd>;Z2?)VT0)HBBLK$)IM6t7-(~TaNca~=PI>+p-KZwm764KNbrur`NW+7`Be<% zvCil0tU`_r4wic=7J7u1Cu{=UpG)s-8TTh0%cpM^v zY9QDuxl8{El|d`^Zh8VEggv;1ww1jn_3@~wic0k9ojmx4^=NDHS+$N-HWcf6;eE?? zD2GwRZI^C7s+a$1a2{!AP~ca2IBDmu{Y2uXd)Oc}8@U@Z@$A7&X*xlvneg45IvA?} zyV#TEk0X0`MMhSkAxSRMK(i1{%qx`R{L2it`(2o)!GD*E?dd)0Bc7E}2vA76lDN7; zXEuRG!scU$Tw0ROp;x3QJ#8|YW#`ZPoux6o+5?oAWrxG6AAP9Ju2bn5;Z7l>!cRoa zMO|#i_l{~Q{V-11R1?CFG=9dVAe-N_rC8FC>Zx%w2B7Xsv78+Lf;j$6{mPrQj+s;Y zdml0UN+8sb)5#H-(nkg^0;w`3!dgv@kdJrF1sY5xOpF9XH8DaY4OPjR zAVCT}T6DFMpsi67+W42YS0=?#a^{W~N=2JZ#iLg)a;;x^Ttc4w_LYSE?JMVUGJak9 zta8BuaZ@Iip3HBAY{XEiRqdPP`(HxurGBD<&(HpC8 zx9TPa6Y~kIwLSWwPeZjP`lV2!1i1sFO9mgXKWPs?%twIv=6?x&+`8qY+mF_Wh!y@Zr?$-%d^z3JZwby)p4u|1ojN ze@q;u<@-(y7`vB=h-N8TcaL`Nz8g2T}QnLY_sh3o-+mEsK8;`7k=o?+IB!YfQ%P~S>Z+*YOh?uYyj9Sg zx;Pm_1qWPLdbQG6QyWoPyLHW6VO@vXdmBOKM{F6iB8g?O^(mwD*rkVrq93MLbJwSo zJ_N11YFm-HzO9BKoLlzJ7p~JNnHe=E+Hpx@vyrkE!);OgCfD6r4f${$A*Eg{E@qM4 z@gSt#iLVm%q@-Je`nhFi$y-q4m}y+QuN=E6ZHP<&>+?0zlECmHKc#k+N^v2z=6nPrlM%=O8-IoWhpc3jH5Eb(sMb1xArL4b z&TQg!l2%Q7e+QaXw7aBON3BT#|FogIh4F6hpzPy)Q{j2`>sr+SpC~OX=;cIN9)1|z z^zrdA59t*3Ixpv_0JKy3+iV>HnQ})>P_R!x$`%s7{)B5zM8#;WfiE#5Ers)diPoog zZhqMFVQZ%&@t9^|%?4XBZ2w1nW+#vKo3IV%$@EweNmOQ+Q2Nx%kYN@xW%`O3ou5t9 zG;#6eW(_GaR+Zd0?!N63BF}8r1K8iIw~g9>voge-fro6gq4NT(`?B5tW)2kosh8}A zJfbmszy-b;&34IlKbo|-8#wPx`}tX&B?z}9xFO|BB?;34wkQ~UH;cDrFdz*$f$V7c zAv-NRk%rP#eD}IYo?5;R-}fjyc~e;MHOERS10K#D63twwm(cePJDJ|XZ_(E>|F-xv zFUR}x27Mfk5YJGDkO+iFf?gsaZDgZMB`2Q52Zgbr>)E;Bz1oE0K;#}`5BSxm@eL`> zQ0W+hO4vaWb=^+sV$ZJgqHg~ZNI~GmtuP_&I}@-}GQoI*bt^1``ggjV=)s}=h;y9s zy^A*Cne^AyQcSQJvPg)oUa3D*U+?wE0E3tg;GveIVZWFe!(2dwo`nvk-tEDMgxB69 z-g%W0^&-Y_NKk%M#c<4m1$BG1N2arsdE!TehDzPg@I9Wo&&g>{@v06ypW}F@Y}sOH zG##5ky!o@8w$^Fik5}VM|~`0y=4YkRt@+< zpRdF_?z6nqwCF(!`=GNcdm3UOI`oBfR$a-#_N8gmL`=~w(3cnYgQJ#S>vgK8|I!6a zdk_=LAz(iaPrzHq0Pod)55j5bl^4oJDFMbsZ%>g^aEoIrkHrLIFgEJFv!`VGC@Tq@C)ve;b^BoPlqtmDXgaYMt zc20@7Wxu6aNmSdb*~R2glH~R~N-F2%zpWU6{UQ0S=qA}!8-w|{@Zr5FlVUgAX?DUk zE~ed+%*q2gRc*)El}$WC_6BmH3@P5TjrWHe{Z=F2-}YPcR$dd&;hpm$2w#)>g?njl zKS1Xn?BO-7sypxoA;Ks-+~aP~5+XeFbM;fdP8Od@jmfmUzzj3(8`S9Y1luEgZWc{u zwKkJF7I7~bgASy637mK~rQqYBI#=_-hX_+<$}e`y(kp4ThnJ{6KyRj@U5t1dWkNm! zPP*x+V_hdCE|Aj!Vi)W1)J)SJvdqjDaY+BL)_|pI#n>3Q$bJ+74b5s_nKavJZm279 zu!Q6*?`xFmjIcW=87!Ai>gf7g*S$$ZG6W2dmv+^c++ct*4zMz$bH(MCAZ zMbfjG;miB8dI~)q03MyWeld#$3xt5b)rWa534-4oMxdHI- z&~N|?+Fc09`tQ#O50B~h%ivFWO^)s+XF*3mKuje!)`KPbZ^1m(jes8A1);zF@74U@ zq89WnM2%n$guW}NMDTzW{Ya35^&i8!p{L~LsSNtF-tWMj6J0N;Owh)KCg$Y(y+8Ch zCy?S_Ne4HYl-4=jk>Ce`#B_0lrGwJ}qh&1=i5upn! zXuPpG&x?#mC3tP%`rhePQ>9+pX}xz6ZB1m78;Z*C>QI(9MqHh}3K${0!`gYAml*nV z(THcs%RM@kiPsSqVR830S<5)KU^zx|V8{gGV+I)(Yu^M|YjuUSEI_VKDrRW$aGdX2 zn3%um^fc*#x{Moq=5aDoLmJQY8r6mByK4F9dwEn(Q$}$dK_TF;+@%-Xj4mH&UQE!t zLWD4P9v-Kf6?&5D=G=Mvm_4GpBFx3*Wn~rMxr#1n+Yh*Cl}W3GdfA>GiET5Q^#k)) z0(qKls?&V9-$oUU2DHTJl)Uij{vPT~^&72sTI8uX5xY`C=x52^S)`Xu8A|)T8lVP^ zgNVFAa8H_9)|IBTYZvEHt|-cNn8c^9Va!2Ot=F1R<4T&6ROUbTLFqe8cY2K6&lRZb zN^>r%sCk_F_(=yB3V@i9x76KcwRImBbef{XB6P=%8wD`1M*l-9v@L6F{GaAo=Ynh3 zYU-Md;{y14tVcK%GCHs8^aqVx>aN1wywo^HMa1!^Ou_a*hJKMT$FFD?hM;vpU}sYC z)4Rzk!YN{Tr5aNM40ZJ~yX1pAhZSK{P4g)n?hnHXk67E~^K)*Po~I~kbfmN_Jz2=L+Adv=St0QMW$~rt3 z{C2eB)jx<-s%X0(ZX(IOXm~lW%CA$VHCM(6$(3P$mPHGiikD#h+QU2-<#$%=cQWvI zg08vBrzzoyI(UlWruH4VPS3q2L`?zcP{R;lLo|sv9*HQ(*Sqr;x;0b}83)qP@-KCv z|4`QvPNK>}VBkL0D6f${=YE(h+5@qf@K1g6<@!&predeKfJ+*c$ly+HaA;lLYL_3( z%*Q=?-$x^onER`kX?$4LCi~ih)fHQNK@4rs5|AmtCYPZ*?{`65!)dK zUL2$jJCjV(c``9q@472fWo`UDc32DdlVW49$9(|=n|eV;$Bgfk;)*A@h`hu3Yyg|H z?{Ik*qsNz-j+ncLv+acqVY-&fjY~_?$T+fAR!Y@5{@_IxScptmbBxzesXc?=3*uXJ z1N-bv@2MF`U(;gbC9&EoJTexihu0fi)dV%~5=ot{cFrP79U}X^5Y>kag$%&h0a~ZH@hdRi#Ub_QG6tf@G_9!LUXp>l06GiO(Y@)H*ZMJ)Z zDLYe_=&{T2aPW)ge`V&y^tw$nkj(M3#KlKpz@>|OWZYYsn-Ki9Z$4jaP zu?GB&@wNm?Rrw==9xKeSt&d#5th5OufOvn-uGeEiZlA+GmjJW*oi~dBlpdSPo}e%B zZpyr;u-|pjd|pn6!N1xDw7-Sg4|o%^Y3MuLrPD#zp#ZB3tyi)-nWWVH<_&)B8ezWs zB1X2+$p6n9z&IYT46}rvR=WCNKhXN4r9f%L#)a}F;7A&wN9H8ZwYX!V>MlXgaH7}T zu)8xt#FDI{e}u9np(m94(@dj@Isk%^X~Q1NB2=-5gcm@9!+SikIfSYT%-j`}gbC%C zymABsb$nmyNqX^Neo=e>+hAfYC(g=s$z#g6F;7X$QKN6|2z{(?rWXKVTlTs5+k?&r zA^-LBpTk_!}{Z(c>@5ZL_NWaKhA1a}1?fFQ2H7WB*=`2()+WEp6v}}48DiIlubC$$lj`hKN{{@! zuht!`oXyrN5~M50!ZM!x763VXouAOAa79i(sb}4Ju6;E4Vg>vVI~kb}(*q7Q@}hKC z=O7)pSrQ$j=1=bbavE_x3Bno=LMpc2Q>=MiF`X2XG@1|esnak(xvQIy`q%`uR13;r zH|@L;j?tC%?5XeN=!KDw#?yjN&`8=*3*|3uPRkPZ@PPO6c#TCjXpdnja87Zxx^sIB zLxUo(WSbnYu+UG~X2etVkF!#W!$}#)am*BbRB{w{tNCxL0NqUSqDA5XQI&dw)G<(qAhq3Sv5Ni7U50bRH_I6e5N zacXuXO7rD1$1Pm1FW9MmGs-S%L&vLJ8o%E$s;X)Vh#b6^U`v&vS?qEXOyr2M6v%Lb zA;Tkf@*)D#DT%%`fUpWBZv$U#|9nUCIq8C()aJgDgmGd-B{ zR3f5cqIRnY1eHKzh^z3qm12Q{N#eUnFJ_Rx-V%>T)x;^6gO268s1Yus+R@Y2z1`(g zq;nPi05>@Wxs$tkmqlNMUWk_n^)T%<%S!4yv2xyPoj;O-ON&*7xWJyZ>{X7 z4Q$;x5kzFI-(;mujo5YbK6%LSCUfFT7wETQRlINhjdJFOT43PR9?qKX@kES)g?0_{ zT-NPKb>TCC`tsIjUM=)m7}@sZ1U3yV*h0q?NhEjtoP9s%+baOwE~-3hj!c~O7MZZ7 z_=7F_oC=bBzATP?$Q+an8Q+!%T3zm$QY5YXIszRa!#&y_4OrXH)7i@_U0K z-hV1>P1mKF^D`jQh4zX&*`-3I5>;eWcR}5T@aZpRm9nv|A{Ck@XyL2zf2qWI9V3<%L9Gu7wHGBoC z@Zg>RlP1aFa;jGy6kvrEafS<=(N*4NFUjDqWAS@*f^@nBn8;Lwo(ZIaLq5rI$oymR z8IFgov{=a6W%tmy!mEZ*{USfA<5{ErtcdY|0|4!NpQl@Af`wp~J}8}KTXor zJqNSpzjJhG-lmpjFB2&>m#>oF5ghUUxXlx)Lc3sUJxHZsW^9|0tro-47%&+ey08kk299ZTuBr^8xWi5^810VsF_HN+Bb+HrGFjai;K zY|KD%-9o-dAEd!PaU>s<7?;$$FW2P#7JVF+u-2?Ce5J4N&}vBncMu|^1qM11kfN^yz8kyfojfHX9s&bwq?J~zx7@F>Chj_m7!jTT0ZW7Ech@1l+`<=a za3zHTq8s(xS83B}sR@FMZlAVCNsd4w=*~-mEy};pkpMLdHcD?(2%&q}K6k z3xDo&YW6TN&(k0$w>d?Pfwsucj?$yu&eqJ$!V9Yh+n4mCG!SFR4>r1e;&{uE2GC>L z(D3H~Jp_XgeGP&fI*zI>(nUHW-gB4ztk-?yyy9bRi0FGg|B^xqohaA!%?s|uleS|k zZXdN-_31_e)^Tt)eRaS{Y?3g~X;MNzo%ZwX)D)k!t$*mG4Pik-e@^4`&vK$En4i49S>7$5PMXuIBIdJJcrE>1vRMQ~Yt!vmYo_ z*_Ts9M%b+%Aa72OcHRg_qU2{Tyq08=KC8Fvv+zr~?~?<7G+HD909a|jEJFE`4C_t0 zB1ZlZf4m9MeV*nC#*}^PDvR)yG3?^o_><&>$thfU6)pPAZbhk;Ocq&2mG9wYMz?IH z%)jThnKTgjvFw-1au$1y>(;4`{I5#^U*YYrGY0Q4(a{X)`?0E;*d0m^BrfVwAmv{l zveytTTw4?x0%Q44zYM^^VZ{0OC_xEAg+ZFPz4Qga|LQVO-cTsZ|5uU!)ia|$LY46- zX;C-O2Y8vxD7YXy>puzV7ML=892~lT2g1p}g9;Xe