From a9743826bd5959d94935c311dd5e49f0e97ec158 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Mon, 18 Dec 2017 17:20:41 -0800 Subject: [PATCH] IDMAP: Warn when RROs overlay non-overlayable resources First pass at getting overlays to respect which resources should be overlaid. First step is to call it out but not enforce. Bug: 64980941 Test: manual (inspect the warnings at boot) Change-Id: I40baee1110d4bc1e54e7f2f9d3b73ffabb067f90 --- libs/androidfw/ResourceTypes.cpp | 19 +++++++++++++++++- libs/androidfw/tests/data/basic/basic.apk | Bin 3207 -> 3124 bytes .../tests/data/basic/basic_de_fr.apk | Bin 1524 -> 1327 bytes .../tests/data/basic/basic_hdpi-v4.apk | Bin 1306 -> 1151 bytes .../tests/data/basic/basic_xhdpi-v4.apk | Bin 1312 -> 1155 bytes .../tests/data/basic/basic_xxhdpi-v4.apk | Bin 1310 -> 1155 bytes libs/androidfw/tests/data/basic/build | 18 ++++++++++------- .../tests/data/basic/res/values/values.xml | 5 +++++ libs/androidfw/tests/data/overlay/build | 4 +++- libs/androidfw/tests/data/overlay/overlay.apk | Bin 2442 -> 5211 bytes 10 files changed, 37 insertions(+), 9 deletions(-) diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 3fe75cffaa713..5b95c81db24eb 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -6880,6 +6880,9 @@ status_t ResTable::createIdmap(const ResTable& overlay, return UNKNOWN_ERROR; } + // The number of resources overlaid that were not explicitly marked overlayable. + size_t forcedOverlayCount = 0u; + KeyedVector map; // overlaid packages are assumed to contain only one package group @@ -6919,6 +6922,7 @@ status_t ResTable::createIdmap(const ResTable& overlay, continue; } + uint32_t typeSpecFlags = 0u; const String16 overlayType(resName.type, resName.typeLen); const String16 overlayName(resName.name, resName.nameLen); uint32_t overlayResID = overlay.identifierForName(overlayName.string(), @@ -6926,14 +6930,23 @@ status_t ResTable::createIdmap(const ResTable& overlay, overlayType.string(), overlayType.size(), overlayPackage.string(), - overlayPackage.size()); + overlayPackage.size(), + &typeSpecFlags); if (overlayResID == 0) { + // No such target resource was found. if (typeMap.entryMap.isEmpty()) { typeMap.entryOffset++; } continue; } + // Now that we know this is being overlaid, check if it can be, and emit a warning if + // it can't. + if ((dtohl(typeConfigs->typeSpecFlags[entryIndex]) & + ResTable_typeSpec::SPEC_OVERLAYABLE) == 0) { + forcedOverlayCount++; + } + if (typeMap.overlayTypeId == -1) { typeMap.overlayTypeId = Res_GETTYPE(overlayResID) + 1; } @@ -7012,6 +7025,10 @@ status_t ResTable::createIdmap(const ResTable& overlay, typeData += entryCount * 2; } + if (forcedOverlayCount > 0) { + ALOGW("idmap: overlaid %zu resources not marked overlayable", forcedOverlayCount); + } + return NO_ERROR; } diff --git a/libs/androidfw/tests/data/basic/basic.apk b/libs/androidfw/tests/data/basic/basic.apk index 0c17328e86b229b37518c24388213c219d2e5ab4..18ef75e91dedc0c9fbb63bfc7b0b0a34b0782af7 100644 GIT binary patch literal 3124 zcmds3eP~-%6hHZnv7OP3u58tYcC}@;Y13|Hpp4XQMV5YKYlVT6B~4z|Xp@ZhUivjz z>sB0!A03nVfzpDLt)N3t5S(J^U&W2lx#3_qsSZE3fiRF!ooxQj&3o-jT{l?kKb~+n z=iYPgIlp`Exi2Rav{;Fp_|f2qi45d{-jIsP=|rqKl1juSMfLS2yE4Nk@+SiBO~0<+ zaQLYin{{ZDv*F3Xiv7!GR$cQ?_y+qc_O1NQ`NPAFg{9ZmUbuMX)bCe5GGBZxc5dsz z9p9BVzVn6YudwU*w0+IHmydmT`jyYhf=|EgNw%cBja>!ykxz1}}| z)ZIEU^zutz7S^A0jhy|ve`no+y;om

frXn>UV+x32&8Np-Xf{NwD-LqpItuo%oB%h9=f!p5Lqe6kkME zqGYB#Vd63}Q4#e*qPVhz$x2;^ECW9d-Uu!!x%;umnlh&HtIa+I#*)lYCabmtjb|;oxfxdLHy5Fy9rI zWE0qme5v@!(CyTPQ6F-d5#?$}CfSlej(5TC5SmI7Mv~ZJ6D#_#PlDZs-7 zLgtH+n4plZL!#2i4PF5*2A6~VV6L6bV8+)5-T@Z=Z4p(Kxgc29lGV!3^j~%2aKxmP zl2H4|;YekY9TK+a8gG)NxIZgu$!>4&l#-HPS86FgKaoAXiglG5Zhqr@$5~qz^Q(rrrF!FxBM*L=w6`YeN{cIWEq6laHQ6>tY(d|7;{1{3 zM=)UKFMUK&Bvq--q@wBMZv5{nQp~6Js_mT##jA9tGhH!nhvdyMyIi55Nkq|`Sz}Yj z&1^2+rnQ~#z}S}MI(P_2yG=WCCkG`t;Sc6GSg4oN{fVteQ*QrdbXbg&1CXH`o4B66u8 literal 3207 zcmds3drXs86u&JkWel_#Aj-sah74r3fKDV?a8)#6QXCmX%|ejU2d_Rzzm|tFp_pO9 zwm+%~kujGNVHq3BHmxJXEz^tYa-*ZsY7yMJcDt?D zSG?~ly}H|f-kZ`OAJV**yL-=ZO;*Od?|n@3oUKJmw3<`M6!Erwq<6~%petYPxoK-JOg z)Aea*dUe}sZ)RLJ1oZEW9Gbb`qw7fy9_YWeH8B3=!f5lF!F4AJOr5*3GcR8mPwPK@ zW!U}xfh}`4t`1HO_o`pPh*>+I;Jhx^Ws4Nsozd>CKBdx^I3US9lZsC)xN;&iZ4 z5G-yX&*LyT?JX_~G_%g#?yhQR6f{DE(_=Gh>MWW??!?4UO7VCy?*>o4gj8Dd6PJv`$0?T7IW@H`A$vkLe z9_A`y4l}AafyfNK4i*8ji9hiF{nFqtl86a}ml zw;oLAy#s6jE6^`DK6K{si_V#JItdp)>w5TAT%r@I2h$Tu9?^m4EL=0f>O#g2XrWn4 zlHem7)f9;)mGI<%3&Fd=`@s!hdSSg_+Rp%38NnHv3=uU=h9WYN(wX_^1gS799>msh z^yFV`3FV@hxAOT@U@s(-J)TtomjzE-xKFB+KY2-Sc1AiubuhYeHCv07-a-6T5b23! zaszuCf@rUTTm=5NMEz8=xX9y_7bL?EgIWoJd|{ioMtp=Z6)}X5ViZ{+e6}|B zOF(wY4?G+s?LSt2s|$e=O6KyxaQh?*p;cPT zhnC-sKT45TL}41Ewp`%2%>9OR;R@F}cBp;|KZnW@dtWsJ)}r0Ar$L>{H=gn_&~ zZgUtfy{mL~AzujV8xq?}-&LyrH1ZLJ-yJ#OqTGR0Js$>iyAvG2zS0cqH0 zU9>K9TNV?Ln=aT(FNNIB6BvLY#uZUa66+cmP2xwA=*=wFrSNh2=x!Iymw{$P^F?lY jVgeqBT`j$^MH3tgC6HX-D$11nA6_9cdG^WIc`{(fvz_@eFe zo|LRQ=9&C=&FyP{1?Dtnf8db%z-M)mYyvktGvulbOKpPebJESvB=D)Z9GnJ*5mYOAP<3|YqdO?cmh=X|S=m>axSih90c<;~W0CaK{m zdLP%Xx%FP}^}FE9-w#C!MbF%8>zE{Jw5HYdidj0Nxw5|N)jL~43Qye%xnAM*`RX^j z*_?;6Vw_w$iv058kAJ+oKf-2p+XD9b`;QJw71}5L7MovC6|DJQdHdm;{W11MyO$N7 z}s*2Zm)269Yp4IDEmu z3Jl+MHTGWxm>C#Am=7pelv1j#D2!#qz`&%yxCZF1dZ4~!hJ1!x z20eyEhCGH8h9V#@6G-bZBmqT=f$U_Un&Au-py@pWN`w3g3U?164U8Z-(15c*IRzMd zK+MEo&tM3pfuYL41`M$hU>Ifs!!jMn2bp66mIo3b0JK8|!UB^Zb68nRfSJk=N*ggS zF$sX<6l6Cria>Gi0K$w+Aq+J@K1@6Y$aVl?5J*Xd(BzOHe{g_p0{aW>We^_}96O4KVj0=POX@gbJ{fRWJj<3bABAgaHXa XzoKTw0B=?{kUSF*)&l7{;G75m1^VWK literal 1524 zcmds1ZAg=G5WnZyiw2g0l3GTSvWQ|(nJ=U{KP31TOR{8&b8b^7bBpKMY6D-hA}FK~ z4eNuwV33w5zNMd}2nlOxMTvqI)Q2IsMUYUI-Tn0;4Ga9*joaP*?)Ja?-~V>nOqo0k zcnAcjZRN@`3fcoXfGi#$6aZ3fCc$noWgBdk60_(~yDF^CYsoq1H6a&fYG)f#>U2uw z#Wbb0yruln?Ql)O**#5dwPV8vU3~BdOVXwL)vvF_-0{5W@K*o$7M$aL5&F!Vck0;W z+xfw$iGcU=q;tFdL50J6T{2%$dy~*NG^UH!MKpFiwiRU*dc(3u9y&WC2XeWdv3hgK zj;b_AwpFR0Z5T+My0O^P`5=Fz{?=$;@6XWQzPWLSYkKH}Yv5$e>F?c7e4cl4$I}ZY z59J;$O#k$}f7HLF_;6hQOxy6BtG?OyF{vebDseD*+tb99gv#<5&i{qm?%DMDx>Wvi|r{g^%y3)J4{O;z<3tjhoH65?Ut$KIOXG7flOLeQ3H4b~k8h2fH)4L!8 zAl`(KU>5C8!DtrM20=9P5X3y#S>PZFDpAUjCE6z`C^sXMeFS*}oB=ZkAc7N&PzEa4 zzb1MB(EyAT@nZnXa@=Z!Vt`k14y>>SRU_D;0@N690~6-3H6{;i*e zEDIZg0s<7ZR3^1C1zxyNz-`c&z_M}ejYZ2AJYeWZE@J&rwnwnDQMR}I+1uGSw<{m_ z`XcA)_q(e2l7s#0BGr3G`9Bu_5vxCH|H0p8QC^GugW6QD(3eiEd#o!}LjCqIRBpJ% z=+S9A(Z4hM8&lsF=eUe@g{#xnNWXsd^U}7BMQ2aEw>+IN1%z@HO_u!#%{UWrzZrz3cB)>v&1qp?)CZY zKbC#@kiPY7=1-yhaWPDXH_w?Youz-~fA`UftD7tNOZPVYzN#*l_>pVghU3eE3S~C% ze)BtE#dzDKm-ia)U;pU8i!a<~-Lt)}|G%xs_Ah#`{~g*J_x=3ueT)I#>>L>k&*x|X zgLMiM1495fsKFr&4C+~lyVryOMM0R4fsvsowK%`DC^@xQFR`dNnSqIc2P_4O5=I6Y z1`RL`)(jG0P=GQ)6bnm6Nb05q;1$V_I)XUJvHV@PDkV@P2r0`f9}v>rne zP^1{hP6nzO&OiYaa6pg&r9o^^IC=nSW)KGoK;a4lz&yYp0K`lT_6&wl+6YLq0Yj_= z7>1d^uuKQ?LFVXyX&?atXz{_$o|2kZoLN!{lwx8M0IG)AiEJ-W$bpe5grNXQE&(J6 z#0c;K&ID#sqQHMB04e4G`UFBlyd2=o2o`|lcI3nf%I&BCOWubW09J^RhLN>r1A_!L UMF)7ZvVl}E0bwnWegh5-04Ct&DgXcg literal 1306 zcmWIWW@Zs#U}E54U}%`nXl=2BU5Jr^A%Ka2L70Jo!7(qTC_gjBH!&|WEw#8ruOc_6 zbfTf(VFv-%|F>EsIs{xqM5cs@_&GObEL^f+iSsee1jatm=n#=Pjlu;Seuo1y9=xp( zJk}Chd-lxz{q<>YBRbD1pUm_Z_lvrI-sszW6Qg6?U?Gp z*DIcH726Z@VD~)F-`S$y(|+&U-t&F)&iZ?wSOdU82n;Q75MFMZk}bi^zyQL0K%t`4 z;{4L0M4CI%j`3^0rt7#U<3big!_fC2>=14y$lWH6*K6fk6h#F!Kq9{?kz z9>`2)$Y;o9&|^qs$OFn30eP7~T8|+KC{he$Cxg@vW1s*GJT{>JHUMc*ID!BuEGGbI zkT?vOz!*T92Z&{W7!=-iKr FZvd0s=!5_O diff --git a/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk b/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk index a240d4c06c1db8a56e6548063a347fd6f2280780..103f6565bb066728da4291d6964d415053fcfbc1 100644 GIT binary patch literal 1155 zcmWIWW@cev-~d8~hWU&PNI)3KcFapD%Fj&kP0Y(oOD!(ZtH{kMowU*Kuz`r{`p47S z#5h+-NJz|_;33X-ra^|?^FMNW@hjgF{#&{=^=9tgq(2_ zmooIWdbT67YU=%0Uso!>f8AK>n)~wc{Bz0cCkURcaeewe{DAKZ@50AIfs!!jMn2brS-rhxP930H_*bC$hajAqPgL5QYLI zxdf0P5F>yC-1WeWN)-4H1t7&7K%YQph?fJr8NmXu9FLqjK{*~3V9Eb51HcL~5;3y& ZJfOo-lXQSLD;r1!6A;z{=?~!0006E1>!JVv literal 1312 zcmWIWW@Zs#U}E54U}%`n*mJn4ON5buA%uy6L70Jo!7(qTC_gjBH!&|WEw#8ruOc_6 zbfT@_VF!WM`?p#oI*#;fXlSg|nA65|(aF=Zv!zG)0F#XNHUU=Ga|bvrSe8H3@%Zqz zLh#suHS^M*y`4ROYqF|Ux61O^xz?GX_scGIZa*Mb!NmQ6C+>iD1@rra71F7zO4rO( znu(qUqnWA@&muFdOtj%^wwLkM}GNncDc)wnzwNm@VoL3X)s+Z`MEM%8m5V4u} zcBExt^LNpEVtN-j>?ai$N#El9U6)W(m?QyCo?hdfMtN8%)rPX!(afWfdmvNz!*T9m7#(mgCT{XfFTni%A~;f z02np(KwdIKK0_{p9z!BS9#BOQke3Oh^%#*ZFae!e K3sl$(_6-0W)a63} diff --git a/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk b/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk index fd3d9b233084e7edbd33c49d1f5544568eb0e59a..61369d5067862d7dd1b7ab2cb8c97d371b60d9a2 100644 GIT binary patch literal 1155 zcmWIWW@cev-~d8~hWU&PNI)3KcFapD%Fj&kP0Y(oOD!(ZtH{kMowV2Quz^Tx|Kop4 zbe$b#B_w7}$dHr}VCLq|XIvQ2w7~Ot}9JZ1Uo`#W>I-|u>_fA6K~|2yxc1H9QemhJhh zt_=*=IZO-;0pPF(2Qe_LWu68sj{u5-FdtB`D784hv?w{XSTC`tIGKro2P^}M5=I6Y z1|2XB)(a9~P=GQ)6dPMbMMg?NCRm6`fl&cyVm*+P%#hEJ%b>@Q$dJd7!cYX{WddnE zh9sa!F_4`M)-Zet1yJAtK?altu|Z+!0i>Bh94OF$F@Q8MA20|2F%yG5gCUeQ0@7^2 z5Gw(OVJ0vv(}8?Kal+1?lA2eXSyBlygGm5rE5uG@dx1g@j7%X61xRuUAVDBTfCq5b z12Za7;6D_A6mtN50-+&Z4)A6K3&3(ba{2`2cvOHT|HBLbE5wqF5eDP{9gdo)1H4(; PK=MpLSPP^-fI|ZSH7Dr! literal 1310 zcmWIWW@Zs#U}E54U}%`n==JWJzYrq>LkJTCgD?XFgJWJwQGRBMZ(?3%T555LUPW$B z=|o$Plku8ZSANejmI2PQIXKg#xS zBqzB08-MxXypyhF-3BOE<3cdc|e6yz0QS6k586>9Tp?Z@tHU^^w~VS00AHnfp(-tG!Wr%g#d2 z7o|5|ZxyTBd7!*n?d|)}JGbAiey4x${j-0Sr_}?%K?n>ja1dVPGJ%&VvJfM6Lke3Oh^%#*Kv)E1voYiVd6mGhECq^y_{CtEOkfzN z1NrR0aLogXqyl-VU>&Sr6_r4JsX%#Fpzb0d1epN>Aoqamhq(_VrT`+KfE^fPsX!A! z@l^uV!^9-OAOVyI=>bMH2snT+NL&QS0Et1(1B-$D159XO45S=jn32f`m~s$u5kR&D z5F@|?xU*Ogf>>Gqp#UVw0d@h1hFA%5mjX~6WCqk62OtxUVg6wS3WD4Y1P&k!^A9Ml zVEzg4W@Hj)#$6Zzl>&hR!?s2cjiqRU832+7m1gK!5iAZiz!_*KYQ_xkW(B7kCZIEG KfeO39z5xK@o$V6< diff --git a/libs/androidfw/tests/data/basic/build b/libs/androidfw/tests/data/basic/build index d619800d6fc55..5682ed4d30413 100755 --- a/libs/androidfw/tests/data/basic/build +++ b/libs/androidfw/tests/data/basic/build @@ -19,11 +19,15 @@ set -e PATH_TO_FRAMEWORK_RES=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/android.jar -aapt package \ - -M AndroidManifest.xml \ - -S res \ - -A assets \ +aapt2 compile --dir res -o compiled.flata +aapt2 link \ -I $PATH_TO_FRAMEWORK_RES \ - --split hdpi --split xhdpi --split xxhdpi --split fr,de \ - -F basic.apk \ - -f + --manifest AndroidManifest.xml \ + -A assets \ + --split basic_hdpi-v4.apk:hdpi \ + --split basic_xhdpi-v4.apk:xhdpi \ + --split basic_xxhdpi-v4.apk:xxhdpi \ + --split basic_de_fr.apk:de,fr \ + -o basic.apk \ + compiled.flata +rm compiled.flata diff --git a/libs/androidfw/tests/data/basic/res/values/values.xml b/libs/androidfw/tests/data/basic/res/values/values.xml index 638c9832ab4cd..6c474596b5cd1 100644 --- a/libs/androidfw/tests/data/basic/res/values/values.xml +++ b/libs/androidfw/tests/data/basic/res/values/values.xml @@ -60,4 +60,9 @@ 2 3 + + + + + diff --git a/libs/androidfw/tests/data/overlay/build b/libs/androidfw/tests/data/overlay/build index 112f373ead30f..716b1bd9db647 100755 --- a/libs/androidfw/tests/data/overlay/build +++ b/libs/androidfw/tests/data/overlay/build @@ -17,4 +17,6 @@ set -e -aapt package -M AndroidManifest.xml -S res -F overlay.apk -f +aapt2 compile --dir res -o compiled.flata +aapt2 link --manifest AndroidManifest.xml -o overlay.apk compiled.flata +rm compiled.flata diff --git a/libs/androidfw/tests/data/overlay/overlay.apk b/libs/androidfw/tests/data/overlay/overlay.apk index 40bf17c5951aeb10bac70685fecb83f667d9bfeb..33f961117c44813051de2bb0c64a8fcf2496b0a9 100644 GIT binary patch literal 5211 zcmds*e{5A}8OPsVXkp!O6&6+}X|PKWm+eB&{oT33HqtD`b=Pjeg)M~A7Ft$r$L$Y+ z2qTrC64FdU2&)JV4N+8BU`{23#A?Vw3=zyaM-0v;@&}T-kcB95)z5pLKJUYl{pbGj zG@riD{hoWz_dM^t?>Fb1;>sB_otw>{+j*qI-LcK1e!SFK?(6A%y1mr1zN>#Axn)!D z;H!_0j4iKO@lx&DN51>Pyen&;tlxEGm)ksl?$pBhdza37zqnxd$(QfnlDcOsI{L!j zCX-)#rT3>#;hBv(N(*8$J{_D`qLx=zQ(F+ro zo_V?{x%c0@9(yOcG5D9wJHK}+cd2^(z4umhH$409lGiIH5B~7s#lN|?|Lo~#>*sTS zJyJL^@#c<`y8o%H+|qcAKkEgzaJuxv zoH+wbWb{biP*=IPeXDbcg%wY6)K}Qo;riSrmvrr})d}#a<%+ob@Sgw9V~(*WT6R~p%qraTG$8!umipg z``{29gE!y|{0=U{pI`!Rz%B6KVKv+bb+8yB_%bv@5mrMdlwb=C!(KQ5KY-)#CY*z} z;WGH&*){k8Zo|w3zb>eSdUzPJupC<8IamYTP=;^7Zg>?&;YV-+eg$Ljdl-lJ;W~T> zQ!smmb8}$(=Ra1JiOI84AK+=i-3&Kv6BA;`iL&tL;Q?3#5i~&ytb%n=f^D!H_Q7E|4sXF2T!brd4Q|2|RL`P+sD~sp zLNm0%8rTR!FbpFw3di6SoP!H64ihj5x1oxVo(pyG5M<#AXoc0V9?Gx-_P_x+3Mb$U zoQKPB6|TcANZdvL@Bl1=2%4Y;R>3+b!8X_p``|Dfhqqu1F2WVK1~*{}s;lWA>LCe@ z&SRvQ+-qQu(7x<&Q6wcaTaw zqTmtXCwn8O9#MSm{u7Z?kI1P<6la|5RgcK2N95Ea6+BYGBNaSS!6OwsQo$n?JW}yI zdAC&XNCl5{@JI)bbnr+Ak96=z2aj~{NC%H}@JI)bOz_AAk4*5$1dmMc$OMl}@W=#@ zOz_AAk8JSB29Ip;$OeyW@W=*_Z1Bhik8JSB29I3u$OVsF@W=&^T=2*Rk6iG`1&>_t z$OVsl@W=;`eDKHzk9_dR2akO4$On&n@W=;`LhvXAk3#S$1dl@SCO3~V{6|Mb>)Y`8Xt^JD8+OHX@W%X-qz727Qs+(^^ z+@ejF1i0am_WQpjKCR$s+k|?TM zzmh7dTfdSls$0L3E~;Ctk=E9)ejDhljxF8T3f%8P^w$M zl2WQ$zmim{TfdT4s%yV~^=e-ET77-3{rXyceXafaT77-3{rXyceXafa+I%gqd}^4l z<(1dX*Ye8i=4*N7b@R2n^1Au@vyja6*DdBNS22Emd}Y3JC8N6e%GHeO<||h;s++In zl|Q=qT3&hGd@ZlMZoZaRUN>LME3ccc<(2QmeC29K&eQVBzsJ5`%PX(j_iK6Ob^CrT zuY9uGJj?Zucv)Wg_gKG@SF_`12t7PaXy>lCkLzT=`FrUiBe!R=anHF}YsMO=g*kJ2 zN&{URy2_82%k5hmTxDha%z|tB!IC_;=;`zyOC)OCeT*C?#%mRc=iJWe*Is`fmc#$L z)dUBB^)4H?FE!j2#G9|VEePl2-{bxL=Fh2{QMFI&obZf27~?6``S8ywroES|w`!lB zcOvcw@7SuivLc=qeUf+Qv#fcX&&Rhi1pii8-uI1 zya{5jPXEHK=J$W%J5NCq#{E+~6B_1~eOV^ALc{TYgo1ug~?%w`Kn`1b~A9=wom&yq#0A?g%>r0|@g0g^E&(^Gl18Q;YQyi;9z( z7{-i(KIk3(tr&xo>_n;VF?fx0oiQe^0f$9F6J?$ z1Np2#xgsEhl(Fm#Ho!7Bm!SZtx{|>TD9-_u$pfm+1)Gr%HUm`707$(NZR=6MB;YEDkn+9cUqH10ukil?@~ha#Agj{tk{E01GJn;s5{u