From 61f780dba8db34aadf827a2922443c9fd54f4ca4 Mon Sep 17 00:00:00 2001
From: Rainer Klute This class is a simple sample application showing how to create a property
diff --git a/src/java/org/apache/poi/hpsf/IllegalPropertySetDataException.java b/src/java/org/apache/poi/hpsf/IllegalPropertySetDataException.java
index 378b1874d..3ad7de6e0 100644
--- a/src/java/org/apache/poi/hpsf/IllegalPropertySetDataException.java
+++ b/src/java/org/apache/poi/hpsf/IllegalPropertySetDataException.java
@@ -66,7 +66,7 @@ package org.apache.poi.hpsf;
* @version $Id$
* @since 2002-05-26
*/
-public class IllegalPropertySetDataException extends HPSFRuntimeException
+public class IllegalPropertySetDataException extends HPSFRuntimeException
{
/**
diff --git a/src/java/org/apache/poi/hpsf/MutablePropertySet.java b/src/java/org/apache/poi/hpsf/MutablePropertySet.java
index 8a236643d..f9f1333ee 100644
--- a/src/java/org/apache/poi/hpsf/MutablePropertySet.java
+++ b/src/java/org/apache/poi/hpsf/MutablePropertySet.java
@@ -106,6 +106,7 @@ public class MutablePropertySet extends PropertySet
* one section it is added right here. */
sections = new LinkedList();
sections.add(new MutableSection());
+ sectionCount = 1;
}
@@ -123,7 +124,7 @@ public class MutablePropertySet extends PropertySet
byteOrder = ps.getByteOrder();
format = ps.getFormat();
osVersion = ps.getOSVersion();
- classID = new ClassID(ps.getClassID().getBytes(), 0);
+ setClassID(ps.getClassID());
clearSections();
for (final Iterator i = ps.getSections().iterator(); i.hasNext();)
{
diff --git a/src/java/org/apache/poi/hpsf/MutableSection.java b/src/java/org/apache/poi/hpsf/MutableSection.java
index fce86980e..e60edf5bd 100644
--- a/src/java/org/apache/poi/hpsf/MutableSection.java
+++ b/src/java/org/apache/poi/hpsf/MutableSection.java
@@ -60,7 +60,9 @@ import java.io.OutputStream;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
+import org.apache.poi.hpsf.wellknown.PropertyIDMap;
import org.apache.poi.util.LittleEndian;
/**
@@ -129,7 +131,7 @@ public class MutableSection extends Section
for (int i = 0; i < pa.length; i++)
mpa[i] = new MutableProperty(pa[i]);
setProperties(mpa);
- dictionary = s.dictionary;
+ setDictionary(s.getDictionary());
}
@@ -247,13 +249,27 @@ public class MutableSection extends Section
public void setProperty(final Property p)
{
final long id = p.getID();
+ removeProperty(id);
+ preprops.add(p);
+ dirty = true;
+ propertyCount = preprops.size();
+ }
+
+
+
+ /**
+ * Removes a property. Writes the section's dictionary. Overwrites the super class' method to cope with a redundancy:
* the property count is maintained in a separate member variable, but
@@ -426,7 +528,77 @@ public class MutableSection extends Section
*/
public Property[] getProperties()
{
- return (Property[]) preprops.toArray(new Property[0]);
+ properties = (Property[]) preprops.toArray(new Property[0]);
+ return properties;
+ }
+
+
+
+ /**
+ * Gets a property. FIXME (2): This method ensures that properties and
+ * preprops are in sync. Cleanup this awful stuff! Sets the section's dictionary. All keys in the dictionary must be
+ * {@see java.lang.Long} instances, all values must be
+ * {@see java.lang.String}s. This method overwrites the properties with IDs
+ * 0 and 1 since they are reserved for the dictionary and the dictionary's
+ * codepage. Setting these properties explicitly might have surprising
+ * effects. An application should never do this but always use this
+ * method. Codepage 1200 denotes Unicode. The property's ID. Compares two properties. Please beware that a property with ID == 0 is
+ * a special case: It does not have a type, and its value is the section's
+ * dictionary.null
if there is no such property
+ */
+ public Object getProperty(final long id)
+ {
+ getProperties();
+ return super.getProperty(id);
+ }
+
+
+
+ /**
+ * mark
operation.
- * @throws UnexpectedPropertySetTypeException if the property
- * set's type is unexpected.
* @throws IOException if some I/O problem occurs.
*/
public static PropertySet create(final InputStream stream)
diff --git a/src/java/org/apache/poi/hpsf/Section.java b/src/java/org/apache/poi/hpsf/Section.java
index 9a27a3ded..efe74015c 100644
--- a/src/java/org/apache/poi/hpsf/Section.java
+++ b/src/java/org/apache/poi/hpsf/Section.java
@@ -93,8 +93,7 @@ public class Section
* section. For example, if the format ID of the first {@link
* Section} contains the bytes specified by
* org.apache.poi.hpsf.wellknown.SectionIDMap.SUMMARY_INFORMATION_ID
- * the section (and thus the property set) is a
- * SummaryInformation.
Gets the section's dictionary. A dictionary allows an application to + * use human-readable property names instead of numeric property IDs. It + * contains mappings from property IDs to their associated string + * values. The dictionary is stored as the property with ID 0. The codepage + * for the strings in the dictionary is defined by property with ID 1.
+ * + * @return the dictionary ornull
if the section does not have
+ * a dictionary.
+ */
+ public Map getDictionary()
+ {
+ return dictionary;
+ }
+
}
diff --git a/src/java/org/apache/poi/hpsf/VariantSupport.java b/src/java/org/apache/poi/hpsf/VariantSupport.java
index 6e9d96c60..3bc0c39c3 100644
--- a/src/java/org/apache/poi/hpsf/VariantSupport.java
+++ b/src/java/org/apache/poi/hpsf/VariantSupport.java
@@ -252,7 +252,7 @@ public class VariantSupport extends Variant
final int i1 = o1 + (i * 2);
final int i2 = i1 + 1;
final int high = src[i2] << 8;
- final int low = src[i1] & 0xff;
+ final int low = src[i1] & 0x00ff;
final char c = (char) (high | low);
b.append(c);
}
@@ -352,8 +352,8 @@ public class VariantSupport extends Variant
char[] s = Util.pad4((String) value);
for (int i = 0; i < s.length; i++)
{
- final int high = (int) ((s[i] & 0xff00) >> 8);
- final int low = (int) (s[i] & 0x00ff);
+ final int high = (int) ((s[i] & 0x0000ff00) >> 8);
+ final int low = (int) (s[i] & 0x000000ff);
final byte highb = (byte) high;
final byte lowb = (byte) low;
out.write(lowb);
@@ -386,13 +386,14 @@ public class VariantSupport extends Variant
}
case Variant.VT_I4:
{
- length += TypeWriter.writeToStream(out, ((Long) value).intValue());
+ length += TypeWriter.writeToStream(out,
+ ((Long) value).intValue());
break;
}
case Variant.VT_FILETIME:
{
long filetime = Util.dateToFileTime((Date) value);
- int high = (int) ((filetime >> 32) & 0xFFFFFFFFL);
+ int high = (int) ((filetime >> 32) & 0x00000000FFFFFFFFL);
int low = (int) (filetime & 0x00000000FFFFFFFFL);
length += TypeWriter.writeUIntToStream
(out, 0x0000000FFFFFFFFL & low);
diff --git a/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java b/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java
index 30cb43e82..855e0c94e 100644
--- a/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java
+++ b/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java
@@ -141,7 +141,7 @@ public class PropertyIDMap extends HashMap
* document */
public static final int PID_APPNAME = 18;
- /** ID of the property that denotes... FIXME (2)
*/ + /**FIXME (2): ID of the property that denotes...
*/ public static final int PID_SECURITY = 19; diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java b/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java index 5d7ff30e7..4e6d2a212 100644 --- a/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java +++ b/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java @@ -65,7 +65,6 @@ import java.util.List; import junit.framework.Assert; import junit.framework.TestCase; -import org.apache.poi.hpsf.ClassID; import org.apache.poi.hpsf.DocumentSummaryInformation; import org.apache.poi.hpsf.HPSFException; import org.apache.poi.hpsf.MarkUnsupportedException; @@ -288,7 +287,7 @@ public class TestBasic extends TestCase { final InputStream in = new ByteArrayInputStream(psf1[j].getBytes()); - final PropertySet psIn = PropertySetFactory.create(in); + PropertySetFactory.create(in); } } } diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java b/src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java index 9d8df67d8..7ca404f2d 100644 --- a/src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java +++ b/src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java @@ -15,7 +15,6 @@ import org.apache.poi.hpsf.NoPropertySetStreamException; import org.apache.poi.hpsf.PropertySet; import org.apache.poi.hpsf.PropertySetFactory; import org.apache.poi.hpsf.SummaryInformation; -import org.apache.poi.hpsf.UnexpectedPropertySetTypeException; /** *Test case for OLE2 files with empty properties. An empty property's type diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java b/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java index 75f941d80..d62378dff 100644 --- a/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java +++ b/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java @@ -66,12 +66,14 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Date; -import java.util.Iterator; +import java.util.HashMap; +import java.util.Map; import junit.framework.Assert; import junit.framework.TestCase; import org.apache.poi.hpsf.HPSFRuntimeException; +import org.apache.poi.hpsf.IllegalPropertySetDataException; import org.apache.poi.hpsf.MutableProperty; import org.apache.poi.hpsf.MutablePropertySet; import org.apache.poi.hpsf.MutableSection; @@ -570,7 +572,7 @@ public class TestWrite extends TestCase final InputStream in = new ByteArrayInputStream(psf1[i].getBytes()); final PropertySet psIn = PropertySetFactory.create(in); - final MutablePropertySet psOut = copy(psIn); + final MutablePropertySet psOut = new MutablePropertySet(psIn); final ByteArrayOutputStream psStream = new ByteArrayOutputStream(); psOut.write(psStream); @@ -602,75 +604,134 @@ public class TestWrite extends TestCase } catch (Exception ex) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - Throwable t = ex; - while (t != null) - { - t.printStackTrace(pw); - if (t instanceof HPSFRuntimeException) - t = ((HPSFRuntimeException) t).getReason(); - else - t = null; - if (t != null) - pw.println("Caused by:"); - } - pw.close(); - try - { - sw.close(); - } - catch (IOException ex2) - { - ex.printStackTrace(); - } - String msg = sw.toString(); - fail(msg); + handle(ex); } } /** - *
Creates a copy of a {@link PropertySet}.
- * - * @param ps the property set to copy - * @return the copy + *Tests writing and reading back a proper dictionary.
*/ - private MutablePropertySet copy(final PropertySet ps) + public void testDictionary() { - MutablePropertySet copy = new MutablePropertySet(); - copy.setByteOrder(ps.getByteOrder()); - copy.setClassID(ps.getClassID()); - copy.setFormat(ps.getFormat()); - copy.setOSVersion(ps.getOSVersion()); - copy.clearSections(); - - /* Copy the sections. */ - for (final Iterator i1 = ps.getSections().iterator(); i1.hasNext();) + try { - final Section s1 = (Section) i1.next(); - final MutableSection s2 = new MutableSection(); - s2.setFormatID(s1.getFormatID()); + final File copy = File.createTempFile("Test-HPSF", "ole2"); + copy.deleteOnExit(); - /* Copy the properties. */ - final Property[] pa = s1.getProperties(); - for (int i2 = 0; i2 < pa.length; i2++) - { - final Property p1 = pa[i2]; - final MutableProperty p2 = new MutableProperty(); - p2.setID(p1.getID()); - p2.setType(p1.getType()); - p2.setValue(p1.getValue()); - s2.setProperty(p2); - } - copy.addSection(s2); + /* Write: */ + final OutputStream out = new FileOutputStream(copy); + final POIFSFileSystem poiFs = new POIFSFileSystem(); + final MutablePropertySet ps1 = new MutablePropertySet(); + final MutableSection s = (MutableSection) ps1.getSections().get(0); + final Map m = new HashMap(3, 1.0f); + m.put(new Long(1), "String 1"); + m.put(new Long(2), "String 2"); + m.put(new Long(3), "String 3"); + s.setDictionary(m); + s.setFormatID(SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID); + int codepage = Property.CP_UNICODE; + s.setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, + new Integer(codepage)); + poiFs.createDocument(ps1.toInputStream(), "Test"); + poiFs.writeFilesystem(out); + out.close(); + + /* Read back: */ + final POIFile[] psf = Util.readPropertySets(copy); + Assert.assertEquals(1, psf.length); + final byte[] bytes = psf[0].getBytes(); + final InputStream in = new ByteArrayInputStream(bytes); + final PropertySet ps2 = PropertySetFactory.create(in); + + /* Compare the property set stream with the corresponding one + * from the origin file and check whether they are equal. */ + assertEquals(ps1, ps2); + } + catch (Exception ex) + { + handle(ex); } - return copy; } + /** + *Tests writing and reading back a proper dictionary with an invalid + * codepage. (HPSF writes Unicode dictionaries only.)
+ */ + public void testDictionaryWithInvalidCodepage() + { + try + { + final File copy = File.createTempFile("Test-HPSF", "ole2"); + copy.deleteOnExit(); + + /* Write: */ + final OutputStream out = new FileOutputStream(copy); + final POIFSFileSystem poiFs = new POIFSFileSystem(); + final MutablePropertySet ps1 = new MutablePropertySet(); + final MutableSection s = (MutableSection) ps1.getSections().get(0); + final Map m = new HashMap(3, 1.0f); + m.put(new Long(1), "String 1"); + m.put(new Long(2), "String 2"); + m.put(new Long(3), "String 3"); + s.setDictionary(m); + s.setFormatID(SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID); + int codepage = 12345; + s.setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, + new Integer(codepage)); + poiFs.createDocument(ps1.toInputStream(), "Test"); + poiFs.writeFilesystem(out); + out.close(); + fail("This testcase did not detect the invalid codepage value."); + } + catch (IllegalPropertySetDataException ex) + { + assertTrue(true); + } + catch (Exception ex) + { + handle(ex); + } + } + + + + /** + *Handles unexpected exceptions in testcases.
+ * + * @param ex The exception that has been thrown. + */ + private void handle(final Exception ex) + { + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw); + Throwable t = ex; + while (t != null) + { + t.printStackTrace(pw); + if (t instanceof HPSFRuntimeException) + t = ((HPSFRuntimeException) t).getReason(); + else + t = null; + if (t != null) + pw.println("Caused by:"); + } + pw.close(); + try + { + sw.close(); + } + catch (IOException ex2) + { + ex.printStackTrace(); + } + fail(sw.toString()); + } + + /** *Runs the test cases stand-alone.
*/ diff --git a/src/testcases/org/apache/poi/hpsf/data/TestSectionDictionary.doc b/src/testcases/org/apache/poi/hpsf/data/TestSectionDictionary.doc new file mode 100644 index 0000000000000000000000000000000000000000..6114a76572d64e4c2a737eaae149246175b18854 GIT binary patch literal 83456 zcmeFZ2{=|=+xWe&BvdLC6`4g!LKKROB~v5~k_?w2^OO*p5t%BIC`2klWF8wtN~Q`K zQW+y;PS+m3b1V1bzMuR4-k#_G{g31Qj-y>aYusx%*IMT~_pq!lup01EJjWpT`=60OG;J#q?RGO--{>LpYam41Gmd5MsFCjHd;d}H|LFO(6VQ!4 zx>%wo7~Ls<#2_e0;twK3KGBJhM3NZ7SRqXe6EU=4A?owoQ^gZnMTS+8;Ze}$!|FS$^>rxI0r0j`G2!Zk*C>v3D4CU3K@^vT|G}35d1mYv! z7o~q?c{FxuhX&FPiAo5Cb}MMNf_8|Z{g6lYzQA<}AJ>T@tgU1$mUvmNo8ViAS`i?R z(5QqkB%K~oB>SW;y0#c86eERDBkh+$kbx<{8|Zx`qsSXBOSP%XZ+IZpu&9J^`1Ml@ zGyEP1m9s Ea=6EUM|%XXqfSPGFLM?=~PRSsxD;e zh)F#nmvVBz7`_N2H%}E=kTzH-du3s&bSUBcHLRJ4K^oE0NHWZg?MpF(|4YC}l_6m? z`Wo)Fz;0?|pURdm*UdyV_^sr|j6NUpYB+8p%2TGX(&V(jWnw0hy9usz!WeBDJ>*NV zlc)%zrgB-H`Y6>xX6 6JB?P;LJLMU iMTeXNBQgD7z;E-Yq awc){!+okH2Wql;vpMI@#e zTKOtZrK+YdD!D~csk-ZKvpdm|W>{**by5^W%I5dHDZan)Gqt*~(L-*Iq&ShAqcO AFaWcgfbdCjJ8!Mdp0$}7b@eDP(IyJolxsAjC`T) zyd;#-tYNgKLfJ-hc6GU5XmxdcO^wQ;{iV3IyPBwJWbYq8L=t5;RlP-Sy-Ia^_*6+> zlRI`0&CnA@2R7pxiY$7FI7-5_lp>-QRdE92jR;{akm)g$c%+HfGGhAZP9mfQdc(wQ zaZyZDQpH7W65fOUp{<(OF&;N|xM<;vO06pH#*Muwt|`Mvde1`H3#5q~CFsz5bP)`r zcoK`|FzHJTh#~^<@P7TkW>u%!_4Ox&6U9u zL%ZZ jST;+VP;iOdUSZwk3wI%O^s z$JCri_%4(^A@p)_%3dapsYj7$utM2w!!C`}O!Om8dyk=<|B_iR-h)mXAH%aSV}r)W z$OxnyO3_fg`I)w9^n7Pv#xVP78 S^3e$~b6u-_P($^NTV68BR^ukQm?H`1x| 8jd`9VQo!kBoGKBpV6H14XP4QLNK zfN@|Vm=26hxe2@tegP<7Q5JLn$zUv42A%_VAeyJZyWk`!N+ucthVmj4+zXb2cfcuN zWLC8N&&~tWiWYINecWqdpL>z<@AKDJ2)Q!~HMrLYruCTm*BbN%gMpFaBybm)0p FyEuUpls^ngM+*JJ8^)Xih(4SpMAs%-EFtws+i$x}!d!-C=%*cUSkQ2l88suy^ zs{#;(TVu`L;2Ka-$ecRdV?}t53F8UryrojP_1hvId8X>ZRZ(j;e&>i8)qUY>#t?vC zTT$UmVeY e`P{PAeVLXxv qyOr zvXGmfXNWtRxVPl;_2+bk5^_y`UphtsScL6OI%Xng8VC_Pp=OEcQtVxNQ9Aw E0MDHkTb*O{ccw#(`BQ*4rvy4^A_PYYG1BO z6Zd{NJ!EJYu?D1RN+`9YuY?Bi#9u-y2w#{|IzjlcCSGpIhT`@Fl#nSACZBRk$d{fe z-6zRsPw*ymE>15brwXC{^ui2n!n}qQzkzOhS(>MDG7WdUG}Jrn>O@H;?CQmJsx)Ky zX}C}-?)5ISpm9Feh3N);y!67<%0a1CvZ6$oRZ4s#tBXCdIn%(`LuHWYD{m7GpV1+eZY_#qa+reJzF8s5__ts3|weA*?o_j=T&s-GTGTa-4 zV?8I%Sg(l_*85_=bwup6z7kJbXT>s0iF>RFIo>KNhglV5U#q6 eEGm Pg{tG})6fkMKr{ai0@E2foPsjbA)d6>3x zfZF{g`eQ2w*K%2#cGglP$!=)PBvDR|6X%#%{z$A5o5eOdz4tM;zG8S~W2!{U3Zfcq z#qcxGDkOSYRYjb2ortvth>F%!k>7em{3hSVlshZlljY=#vV(k7rppK9VmU)@mlLS5 zX^dZol9wB)$#Jr%RZkYOipfaJD?+W$5W?%?54l17BIk-9 ?^*K?Vwmk9F?WT z5g92CB9jAhs7U?4R96G)${6ZORdnlGbaL$F>I(Vy*OiFCx QjI5RmL+?xZop|1*xtxJ?;Vb1kAP;Bh7r%k`uPOJ`zbNm> zfINKT=E01&&<$MudFX`ua^=0{#?n{JgRi_BGs%=lS$4q;Xv3mGEIF$}SsSC%7zAP5 zCFO2LR35^F<697;y#xk*MaLOHYYEV8(pA@iThyH!Bjh~l|_%mLe! z_bqODA0d`sRz`XWyG*^l`tmN$L_&^JM)ni8pgDa*q9fuJTEP}t#ac0iMYi#@i?J-; zjid`m5qHos?qmcxM_f-W>4bsQNxX@akI_bcVFVK?Z(=Ock7 e<)SxAn*{@iH @0RO9lMc!Xc7I;?Ud&z=@I=Hr^V4T)W)(Y zEQ_(Rp^P{zV#E$i)iq2E&7>xe!pKX+L~bqGGhvlLo$i8u>PiVcN$G5666#sB);6@) z4(ji#)a2dN@OP*gA5hyrMIU}m9nTT<=pS1Phms3Ns0CyuTQz2g(sHq=C?6A5fQDCF`_oWu1^W;hSl_E$3M;%k|b4`LeY^erT WEdQ`Q4#)i zW7UARV(g n{1^ki8PL$6bVaa(=#U}Ne+YkIOcM*f}t zjs5rzWc4Vr^3WH(&Hc~)_>h3PgF*qas)2ud*}?6Dehz3?tS=y|46YaV3R`HFyawyPIooG@il%Y|`h14)iq+`-m+23Vur=m)dhn8Rm}o4!ik`Bu7%gLn zRZu)kn$OS&y@geEoOWhIt+Z8weyg15V_hT0S+&GMtD)FpH4*Pwt;M%ioUlBdMJZ1= zQODC$wD2T~_pP1c7?#fu)|*0GdqsZF2coR!V^Pa i+*Lv;z9D; >`)SR&ukfFQ1U*c^WBK$zQ}$c}(0dcZ+%QDQ5o`p)aP85}O)icacRs9>bjCD0ohV z_Y^ot`aj%<)uXP=qpr-MuB2S9u8@C!A66u=u23i1%T-+CWDl _Pe-Ud2&kRVMQdG_ J`L+%+Hn>WH!Y1JexoA6gwL z0U!U$)sd39`3kO%1Xo8;u>U$s_CJ|czz8KTt0ScX+X})8u8ss(N6d^gRl)5qssxNs z%!;__FI>IK^Wf^p#rr7&S4YYO$ZDD^tN(qgBV_~f@Qs^?;Oa PT>P S4aLU`k=o%uMyCP 0=gUZnhn#wQ`)6P)uaoL6%v> z7Lq4r|8Si4Jo$nr6G0aK=B$l*?qTVw2OG^2*htYr+`{(h49 b7%3`QGZ(kvM6
0-hf$r(j zz~}X#Zk~pSDjjc=`a7|>rps&KMT!%x@2|9C?wWdzdpzvoXQ30<^o$buA};qVB)-}m z?X$KcT;BCS8lh|x4M)O8zDD5YO%9j*I8{_AJC$Ri59;FPoO-GZGjgj(Xy3bx{v0F9 zjZv4A*|{<5hJ^V~T&C9`iMnnw9C5ki=ZkuAVm-Qqaf~obxKTgJ@o{)1K7GeoT|RgF z`OJ-B*uD7Y@;QdH<_nY?V~iDMDq}s^GcZ5tF?IH$pBu}Z|NhE$V>Js23nPFpmK7M& z-7FIj*Nyo)F g>?-sU8R=YB;He`%>-k7pblbJD=*=u#2NM`irQ$!q2B#AmZYvr`)q> zraA|RSNu=^Z<=f%Kc<-m{%@LQ;Q#Cn%j3^fPyf$pn}6Dc YrO z$Q)$UX T*(O0GR&2WFUW=KC33lm{F(Rs_}}-FN!Si lDOSS&G%lA ziS#k%GU#axmC9&%88NFAhdL=+v+YiZkCP`pdH~EkH9o;tUGB!$ycJRAo*llc za5O%rK~q#8Z(G0>1I+IOQ%3^ppz9mFT%82gg}oBKl{frN6VVOKc&apIF1Y&M)K}GX zBK+K9@;UQ#HAOSeavW1$=6!Mh|3@=_9vfY0bd$wa|9IL~99#O^p-b8^3hK-ltUL9r zo9KhD`9Hz+i97$SJ2ATQ*MU$qh;PPZ?L Wi2y^p~)4lUy!zs1lZ&65;* zR`c_Z_WXC(^KV=vZ(#GVY-#j(SUyt*g5xFbFM)>l=l7V#rzejyFG_XWTDRWj-KKa^ b7lbhGdj9A2nu(vAZyD<&6ukcDO5pziX9Sc% literal 0 HcmV?d00001