pom.xml0000644000175000017500000000320411312401775011417 0ustar user03user03 vectorgraphics org.freehep 2.1.1 4.0.0 org.freehep freehep-graphicsio FreeHEP GraphicsIO FreeHEP GraphicsIO Base Library freehep-maven Maven FreeHEP http://java.freehep.org/maven2 org.codehaus.mojo exec-maven-plugin 1.0.2 java org.freehep.graphicsio.exportchooser.ImageIOExportFileType org.freehep freehep-graphics2d 2.1.1 org.freehep freehep-export org.freehep freehep-io src/0000755000175000017500000000000011312401775010672 5ustar user03user03src/test/0000755000175000017500000000000011312401767011652 5ustar user03user03src/test/resources/0000755000175000017500000000000011312401767013664 5ustar user03user03src/test/java/0000755000175000017500000000000011312401766012572 5ustar user03user03src/test/java/org/0000755000175000017500000000000011312401766013361 5ustar user03user03src/test/java/org/freehep/0000755000175000017500000000000011312401766014777 5ustar user03user03src/test/java/org/freehep/graphicsio/0000755000175000017500000000000011312401766017127 5ustar user03user03src/test/java/org/freehep/graphicsio/font/0000755000175000017500000000000011312401766020075 5ustar user03user03src/test/java/org/freehep/graphicsio/font/truetype/0000755000175000017500000000000011312401766021756 5ustar user03user03src/test/java/org/freehep/graphicsio/font/truetype/test/0000755000175000017500000000000011312401767022736 5ustar user03user03src/test/java/org/freehep/graphicsio/font/truetype/test/package.html0000644000175000017500000000006011312401767025213 0ustar user03user03 Tests for the TrueType interface. src/test/java/org/freehep/graphicsio/font/truetype/test/GlyphPanel.java0000644000175000017500000000500711312401767025646 0ustar user03user03// Copyright 2001, FreeHEP. package org.freehep.graphicsio.font.truetype.test; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.geom.AffineTransform; import javax.swing.JPanel; import org.freehep.graphicsio.font.truetype.TTFGlyfTable; /** * @author Simon Fischer * @version $Id: GlyphPanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class GlyphPanel extends JPanel { private TTFGlyfTable.Glyph glyph; private Rectangle maxCharBounds; private final static AffineTransform transform = new AffineTransform(); static { transform.scale(0.2, -0.2); transform.translate(1500, -2250); } public GlyphPanel(TTFGlyfTable.Glyph glyph, Rectangle maxCharBounds) { this.glyph = glyph; this.maxCharBounds = maxCharBounds; this.setBackground(Color.white); } public void paint(Graphics g) { Graphics2D g2d = (Graphics2D) g; g2d.setBackground(Color.white); g2d.clearRect(0, 0, 1000, 700); g2d.setTransform(transform); g2d.setColor(new Color(200, 200, 255)); g2d.fill(maxCharBounds); Rectangle bbox = glyph.getShape().getBounds(); g2d.setColor(Color.lightGray); g2d.fill(bbox); g2d.setColor(Color.black); g2d.drawLine(-10000, glyph.yMin, 10000, glyph.yMin); g2d.drawLine(glyph.xMin, -10000, glyph.xMin, 10000); g2d.drawLine(-10000, glyph.yMax, 10000, glyph.yMax); g2d.drawLine(glyph.xMax, -10000, glyph.xMax, 10000); g2d.setFont(new Font("Helvetica", Font.PLAIN, 60)); drawString(g2d, "yMin=" + glyph.yMin, glyph.xMin - 325, glyph.yMin); drawString(g2d, "yMax=" + glyph.yMax, glyph.xMin - 325, glyph.yMax); drawString(g2d, "xMin=" + glyph.xMin, glyph.xMin + 20, glyph.yMin - 75); drawString(g2d, "xMax=" + glyph.xMax, glyph.xMax + 20, glyph.yMin - 75); g2d.fillOval(-10, -10, 21, 21); g2d.fill(glyph.getShape()); g2d.setStroke(new BasicStroke(5)); g2d.setColor(Color.red); g2d.draw(glyph.getShape()); } private void drawString(Graphics2D g2d, String str, int x, int y) { AffineTransform tx = g2d.getTransform(); g2d.translate(0, y); g2d.scale(1, -1); g2d.drawString(str, x, 0); g2d.setTransform(tx); } public Dimension getPreferredSize() { return new Dimension(1000, 700); } } src/test/java/org/freehep/graphicsio/font/truetype/test/TTFFileTest.java0000644000175000017500000000322611312401767025701 0ustar user03user03// Copyright 2001, FreeHEP. package org.freehep.graphicsio.font.truetype.test; import java.awt.Rectangle; import javax.swing.JFrame; import org.freehep.graphicsio.font.truetype.TTFFile; import org.freehep.graphicsio.font.truetype.TTFFont; import org.freehep.graphicsio.font.truetype.TTFGlyfTable; import org.freehep.graphicsio.font.truetype.TTFHeadTable; /** * * @author Mark Donszelmann * @version $Id: TTFFileTest.java 8584 2006-08-10 23:06:37Z duns $ */ public class TTFFileTest { public static void main(String[] args) throws Exception { // String fontName = "win1.4/LucidaBrightRegular.ttf"; String fontName = "linux/LucidaBrightRegular.ttf"; // String fontName = "linux/LucidaBrightItalic.ttf"; // String fontName = "windows/LucidaBrightRegular.ttf"; // String fontName = "windows/LucidaTypewriterRegular.ttf"; if (args.length == 1) { fontName = args[0]; } TTFFont ttf = new TTFFile(fontName); // ttf.readAll(); System.out.println("\n---"); // ttf.show(); TTFGlyfTable.Glyph glyph = ((TTFGlyfTable) ttf.getTable("glyf")) .getGlyph(120); System.out.println(); System.out.println(glyph.toDetailedString()); // bbox chars: 188, 375, 198, 353 Rectangle maxCharBounds = ((TTFHeadTable) ttf.getTable("head")) .getMaxCharBounds(); JFrame frame = new JFrame("TTF Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new GlyphPanel(glyph, maxCharBounds)); frame.pack(); frame.setVisible(true); ttf.close(); } } src/main/0000755000175000017500000000000011312401775011616 5ustar user03user03src/main/resources/0000755000175000017500000000000011312401775013630 5ustar user03user03src/main/resources/META-INF/0000755000175000017500000000000011312401775014770 5ustar user03user03src/main/resources/META-INF/services/0000755000175000017500000000000011312401775016613 5ustar user03user03src/main/resources/META-INF/services/org.freehep.util.export.ExportFileType0000644000175000017500000000030311312401775026154 0ustar user03user03org.freehep.graphicsio.exportchooser.ImageIOExportFileType org.freehep.graphicsio.gif.GIFExportFileType org.freehep.graphicsio.raw.RawExportFileType org.freehep.graphicsio.ppm.PPMExportFileType src/main/resources/META-INF/services/javax.imageio.spi.ImageWriterSpi0000644000175000017500000000020711312401775024743 0ustar user03user03org.freehep.graphicsio.raw.RawImageWriterSpi org.freehep.graphicsio.gif.GIFImageWriterSpi org.freehep.graphicsio.ppm.PPMImageWriterSpi src/main/java/0000755000175000017500000000000011312401775012537 5ustar user03user03src/main/java/overview.html0000644000175000017500000000012711312401775015273 0ustar user03user03 This is the API specification of the FreeHEP VectorGraphics package. src/main/java/org/0000755000175000017500000000000011312401767013327 5ustar user03user03src/main/java/org/freehep/0000755000175000017500000000000011312401767014745 5ustar user03user03src/main/java/org/freehep/graphicsio/0000755000175000017500000000000011312401775017074 5ustar user03user03src/main/java/org/freehep/graphicsio/QuadToCubicPathConstructor.java0000644000175000017500000000256611312401775025176 0ustar user03user03// Copyright 2001 freehep package org.freehep.graphicsio; import java.io.IOException; /** * Implements the Quadratic Bezier Curve PathConstructor functionality in terms * of Cubic Bezier Curves * * @author Mark Donszelmann * @version $Id: QuadToCubicPathConstructor.java 8584 2006-08-10 23:06:37Z duns $ */ public abstract class QuadToCubicPathConstructor extends AbstractPathConstructor { protected QuadToCubicPathConstructor() { super(); } public void move(double x, double y) throws IOException { currentX = x; currentY = y; } public void line(double x, double y) throws IOException { currentX = x; currentY = y; } public void quad(double x1, double y1, double x2, double y2) throws IOException { double xctrl1 = x1 + (currentX - x1) / 3.; double yctrl1 = y1 + (currentY - y1) / 3.; double xctrl2 = x1 + (x2 - x1) / 3.; double yctrl2 = y1 + (y2 - y1) / 3.; cubic(xctrl1, yctrl1, xctrl2, yctrl2, x2, y2); currentX = x2; currentY = y2; } public void cubic(double x1, double y1, double x2, double y2, double x3, double y3) throws IOException { currentX = x3; currentY = y3; } public void closePath(double x0, double y0) throws IOException { currentX = 0; currentY = 0; } } src/main/java/org/freehep/graphicsio/ImageConstants.java0000644000175000017500000001002511312401775022654 0ustar user03user03// Copyright 2003-2007, FreeHEP. package org.freehep.graphicsio; /** * * @author Mark Donszelmann * @author Steffen Greiffenberg * @version $Id: ImageConstants.java 10269 2007-01-09 00:32:55Z duns $ */ public class ImageConstants { private ImageConstants() { } /** * general purpose data compression / decompression */ public static final String ZLIB = "ZLIB"; /** * image format "raw" */ public static final String RAW = "RAW"; /** * image format "portable network graphics" */ public static final String PNG = "PNG"; /** * image format "joint photographic experts group" */ public static final String JPG = "JPG"; /** * image format "joint photographic experts group" */ public static final String JPEG = "JPEG"; /** * image format "graphics interchange format " */ public static final String GIF = "GIF"; /** * image format "portable pixmap" */ public static final String PPM = "PPM"; /** * image format "bitmap" */ public static final String BMP = "BMP"; /** * image format "windows bitmap" */ public static final String WBMP = "WBMP"; /** * image format "enhanced metafile" */ public static final String EMF = "EMF"; /** * image format "java" */ public static final String JAVA = "JAVA"; /** * image format "scalable vector graphic" */ public static final String SVG = "SVG"; /** * image format "shockwave flash" */ public static final String SWF = "SWF"; /** * image / document format "portable document format" */ public static final String PDF = "PDF"; /** * image / document format "postscript" */ public static final String PS = "PS"; /** * key for {@link org.freehep.util.UserProperties} that stores image format */ public static final String WRITE_IMAGES_AS = "WriteImagesAs"; /** * key for {@link org.freehep.util.UserProperties} that * stores a {@link java.awt.Dimension} for image size */ public static final String IMAGE_SIZE = "ImageSize"; /** * value for {@link org.freehep.util.UserProperties} with key * IMAGE_SIZE (alternative for a certain dimension to choose * cmallest image size) */ public static final String SMALLEST = "Smallest Size"; /** * used for ASCII 85 encoding using a {@link org.freehep.util.io.ASCII85OutputStream} * @see org.freehep.graphicsio.ImageGraphics2D#toByteArray(java.awt.image.RenderedImage, String, String, java.util.Properties) */ public final static String ENCODING_ASCII85 = "ASCII85"; /** * zip encoding used for converting Images to byte[] * @see org.freehep.graphicsio.ImageGraphics2D#toByteArray(java.awt.image.RenderedImage, String, String, java.util.Properties) */ public final static String ENCODING_FLATE = "Flate"; /** * used for compressed ASCII 85 encoding using a {@link org.freehep.util.io.ASCII85OutputStream} * @see org.freehep.graphicsio.ImageGraphics2D#toByteArray(java.awt.image.RenderedImage, String, String, java.util.Properties) */ public final static String ENCODING_FLATE_ASCII85 = ENCODING_FLATE + "-" + ENCODING_ASCII85; /** * Discrete Cosine Transform for JPEG uses an ASCII85OutputStream * @see org.freehep.graphicsio.ImageGraphics2D#toByteArray(java.awt.image.RenderedImage, String, String, java.util.Properties) */ public final static String ENCODING_DCT = "DCT"; /** * RGB ColorModel used by org.freehep.graphicsio.pdf.PDFStream and * org.freehep.graphicsio.ps.PSGraphics2D */ public static final String COLOR_MODEL_RGB = "RGB"; /** * Alpha (?) ColorModel used by * org.freehep.graphicsio.swf.DefineBitsJPEG3 */ public static final String COLOR_MODEL_A = "A"; /** * ColorModel used by * org.freehep.graphicsio.swf.DefineBitsLossless */ public static final String COLOR_MODEL_ARGB = "*ARGB"; } src/main/java/org/freehep/graphicsio/TestResults.html0000644000175000017500000005476011312401775022277 0ustar user03user03 Graphics2D Test Results and References

Graphics2D Test Results and References

 

  Encapsulated PostScript Portable Document Format Scalable Vector Graphics Enhanced Metafile Format Macromedia
Flash
Format
Computer Graphics Metafile Graphics Interchange Format Portable Network Graphics
Test Name PS, EPS PDF SVG, SVGZ EMF SWF CGM (Binary, ASCII) GIF PNG
TestPrintColors Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref
TestLineStyles Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref
TestPaint Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref N/A N/A Test Ref
TestSymbols2D Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref
TestImages Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref
TestImage2D Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref N/A N/A Test Ref
TestTaggedString Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref
TestText2D Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref
TestTransforms Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref
TestFonts Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref
TestLabels Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref
TestShapes Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref
TestHTML Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref
TestClip Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref
TestAll Test Ref Test Ref Test Ref Test Ref Test Ref Test Ref N/A N/A Test Ref
  1. To view the PS, EPS results you need a PostScript viewer: GhostScript and GhostView
  2. To view the PDF results you need a PDF Plugin: Adobe Acrobat Reader
  3. To view the SVG results you need a SVG Plugin: Adobe SVG Viewer
  4. To view the EMF results you need to drag the file into a Microsoft Office Product (e.g. Word, PowerPoint, ...)
  5. To view the SWF results you need a Flash Plugin: Macromedia Shockwave FlashPlayer
  6. To view the CGM results you need a CGM Plugin:  Micografx ActiveCGM Browser

 

src/main/java/org/freehep/graphicsio/package.html0000644000175000017500000000054511312401775021361 0ustar user03user03 I/O for different graphics in and output formats.

The classes in this package form a base for use in different output formats.

You need to properly nest calls to "create()" and "dispose()" to allow the different output formats to have their graphics states stored and restored. All swing components do this.

src/main/java/org/freehep/graphicsio/exportchooser/0000755000175000017500000000000011312401772021775 5ustar user03user03src/main/java/org/freehep/graphicsio/exportchooser/package.html0000644000175000017500000000023711312401772024260 0ustar user03user03 Export dialogs/choosers for GraphicsIO, allowing the user to pick a file and format.

@Status Stable, but option box needs reorganization.

src/main/java/org/freehep/graphicsio/exportchooser/ImageIOExportFileType.java0000644000175000017500000001347211312401772026765 0ustar user03user03// Copyright 2003-2007 FreeHEP package org.freehep.graphicsio.exportchooser; import java.util.Iterator; import java.util.List; import java.util.Locale; import javax.imageio.ImageIO; import javax.imageio.ImageWriter; import javax.imageio.spi.IIORegistry; import javax.imageio.spi.ImageReaderSpi; import javax.imageio.spi.ImageWriterSpi; import javax.imageio.spi.RegisterableService; import javax.imageio.spi.ServiceRegistry; import org.freehep.graphicsio.ImageGraphics2D; import org.freehep.util.export.ExportFileType; import org.freehep.util.export.ExportFileTypeRegistry; /** * This class does not work, since the ExportFileTypeRegistry stores Objects by * class. If we automatically generate ImageFileTypes by ImageIO they end up * being all different objects from the same class. The Registry currently then * overwrites the first one with the second and so on. Sun Bug #Submitted. * * @author Mark Donszelmann * @version $Id: ImageIOExportFileType.java 10516 2007-02-06 21:11:19Z duns $ */ public class ImageIOExportFileType implements RegisterableService { /** * This constructor will construct register all image formats available in * ImageIO into ExportFileTypeRegistry. The ImageExportFileTypeRegistration * will deregister itself immediately. */ public ImageIOExportFileType() { // empty, registry is not valid yet } public void onRegistration(ServiceRegistry registry, Class category) { // run over all ImageWriterSpis and store their formats Alphabetically IIORegistry imageRegistry = IIORegistry.getDefaultInstance(); Iterator providers = imageRegistry.getServiceProviders( ImageWriterSpi.class, false); ExportFileTypeRegistry exportRegistry = ExportFileTypeRegistry.getDefaultInstance(null); while (providers.hasNext()) { ImageWriterSpi writerSpi = (ImageWriterSpi) providers.next(); String[] formats = writerSpi.getFileSuffixes(); if ((formats != null) && (formats[0] != null)) { exportRegistry.add(new ImageExportFileType(writerSpi)); } else { System.err.println(getClass() + ": Cannot register " + writerSpi + " because it has no filesuffixes."); } } /* // Look for the last ExportFileType so that these ImageExportFileTypes // are registered neatly behind that one. ExportFileType previous = null; Iterator exportTypes = registry.getServiceProviders( ExportFileType.class, true); while (exportTypes.hasNext()) { previous = (ExportFileType) exportTypes.next(); } // run over all formats and book them as ExportFileTypes Iterator formats = formatSet.iterator(); while (formats.hasNext()) { String format = (String) formats.next(); ExportFileType export = ImageExportFileType.getInstance(format); if (export != null) { registry.registerServiceProvider(export, ExportFileType.class); if (previous != null) { registry.unsetOrdering(ExportFileType.class, previous, export); registry.setOrdering(ExportFileType.class, previous, export); // System.out.println("Ordering set : "+result); } previous = export; } else { System.err.println(getClass() + ": Invalid format: " + format + "."); } } */ registry.deregisterServiceProvider(this, category); } public void onDeregistration(ServiceRegistry registry, Class category) { } public static void main(String[] args) throws Exception { System.out.println("WRITERS"); IIORegistry imageRegistry = IIORegistry.getDefaultInstance(); Iterator providers = imageRegistry.getServiceProviders( ImageWriterSpi.class, false); while (providers.hasNext()) { ImageWriterSpi writerSpi = (ImageWriterSpi) providers.next(); System.out.println(" " + writerSpi); System.out.println(" " + writerSpi.getDescription(Locale.US)); System.out.print(" "); String[] formats = writerSpi.getFileSuffixes(); for (int i = 0; i < formats.length; i++) { System.out.print(formats[i] + ", "); } System.out.println(); } System.out.println(); System.out.println("MIMETYPES"); String[] formats = ImageIO.getWriterMIMETypes(); for (int i = 0; i < formats.length; i++) { System.out.println(" " + formats[i]); ImageWriter writer = ImageGraphics2D .getPreferredImageWriterForMIMEType(formats[i]); String[] suffixes = writer.getOriginatingProvider() .getFileSuffixes(); System.out.print(" "); for (int j = 0; j < suffixes.length; j++) { System.out.print(suffixes[j] + " "); } System.out.println(); System.out.println(" " + writer); } System.out.println(); System.out.println("READERS"); providers = imageRegistry.getServiceProviders(ImageReaderSpi.class, false); while (providers.hasNext()) { System.out.println(" " + providers.next()); } System.out.println(); System.out.println("All ExportFileTypes"); List exportFileTypes = ExportFileType.getExportFileTypes(); Iterator iterator = exportFileTypes.iterator(); while (iterator.hasNext()) { ExportFileType type = (ExportFileType)iterator.next(); System.out.println(" " + type); } } } src/main/java/org/freehep/graphicsio/exportchooser/ImageTypePanel.java0000644000175000017500000000210411312401772025501 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio.exportchooser; import java.util.Properties; import javax.swing.JComboBox; import javax.swing.JLabel; import org.freehep.graphicsio.ImageConstants; import org.freehep.swing.layout.TableLayout; import org.freehep.util.UserProperties; /** * * @author Mark Donszelmann * @version $Id: ImageTypePanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class ImageTypePanel extends OptionPanel { private String key; private String initialType; private JComboBox imageTypeCombo; public ImageTypePanel(Properties user, String rootKey, String[] types) { super("Image Type"); key = rootKey + "." + ImageConstants.WRITE_IMAGES_AS; UserProperties options = new UserProperties(user); initialType = options.getProperty(key); imageTypeCombo = new OptionComboBox(options, key, types); // FREEHEP-575 imageTypeCombo.setSelectedItem(initialType); add(TableLayout.LEFT, new JLabel("Include Images as ")); add(TableLayout.RIGHT, imageTypeCombo); } }src/main/java/org/freehep/graphicsio/exportchooser/OptionTextField.java0000644000175000017500000000143011312401772025717 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio.exportchooser; import java.util.Properties; import javax.swing.JTextField; /** * * @author Mark Donszelmann * @version $Id: OptionTextField.java 8584 2006-08-10 23:06:37Z duns $ */ public class OptionTextField extends JTextField implements Options { protected String initialText; protected String key; public OptionTextField(Properties options, String key, int columns) { super(options.getProperty(key, ""), columns); this.key = key; initialText = getText(); } public boolean applyChangedOptions(Properties options) { if (!getText().equals(initialText)) { options.setProperty(key, getText()); return true; } return false; } } src/main/java/org/freehep/graphicsio/exportchooser/OptionButton.java0000644000175000017500000000157611312401772025315 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio.exportchooser; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Properties; import javax.swing.JButton; import javax.swing.JDialog; /** * * @author Mark Donszelmann * @version $Id: OptionButton.java 8584 2006-08-10 23:06:37Z duns $ */ public class OptionButton extends JButton implements Options { protected String key; public OptionButton(Properties options, String key, String text, final JDialog dialog) { super(text); this.key = key; addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { dialog.setVisible(true); dialog.dispose(); } }); } public boolean applyChangedOptions(Properties options) { return false; } } src/main/java/org/freehep/graphicsio/exportchooser/PageMarginPanel.java0000644000175000017500000001306511312401772025637 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio.exportchooser; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.text.ParseException; import java.util.Properties; import javax.swing.JComboBox; import javax.swing.JFormattedTextField; import javax.swing.JLabel; import org.freehep.graphicsio.PageConstants; import org.freehep.swing.layout.TableLayout; import org.freehep.util.UserProperties; /** * * @author Mark Donszelmann * @version $Id: PageMarginPanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class PageMarginPanel extends OptionPanel { final private static String pageMarginList[] = { "Custom", PageConstants.SMALL, PageConstants.MEDIUM, PageConstants.LARGE }; private String key; private Insets initialMargins; private JComboBox pageMarginCombo; private JFormattedTextField top, left, bottom, right; public PageMarginPanel(Properties user, String rootKey) { super("Page Margins"); key = rootKey + "." + PageConstants.PAGE_MARGINS; UserProperties options = new UserProperties(user); initialMargins = options.getPropertyInsets(key); pageMarginCombo = new JComboBox(pageMarginList); add(TableLayout.LEFT, new JLabel("Preset Margins")); add(TableLayout.RIGHT, pageMarginCombo); add(TableLayout.LEFT, new JLabel("Top")); top = new JFormattedTextField(new TextFieldFormatter()); top.setColumns(10); add(TableLayout.RIGHT, top); add(TableLayout.LEFT, new JLabel("Bottom")); bottom = new JFormattedTextField(new TextFieldFormatter()); bottom.setColumns(10); add(TableLayout.RIGHT, bottom); add(TableLayout.LEFT, new JLabel("Left")); left = new JFormattedTextField(new TextFieldFormatter()); left.setColumns(10); add(TableLayout.RIGHT, left); add(TableLayout.LEFT, new JLabel("Right")); right = new JFormattedTextField(new TextFieldFormatter()); right.setColumns(10); add(TableLayout.RIGHT, right); pageMarginCombo.addItemListener(new ComboListener()); top.addActionListener(new TextFieldListener()); bottom.addActionListener(new TextFieldListener()); left.addActionListener(new TextFieldListener()); right.addActionListener(new TextFieldListener()); // now set the initial values top.setValue(new Integer(initialMargins.top)); bottom.setValue(new Integer(initialMargins.bottom)); left.setValue(new Integer(initialMargins.left)); right.setValue(new Integer(initialMargins.right)); // trigger the changes new TextFieldListener().actionPerformed(null); new ComboListener().itemStateChanged(null); } public boolean applyChangedOptions(Properties options) { boolean changed = false; Insets margins = new Insets(((Number) top.getValue()).intValue(), ((Number) left.getValue()).intValue(), ((Number) bottom .getValue()).intValue(), ((Number) right.getValue()) .intValue()); if (!margins.equals(initialMargins)) { UserProperties.setProperty(options, key, margins); changed = true; } return changed; } private class ComboListener implements ItemListener { public void itemStateChanged(ItemEvent e) { int index = pageMarginCombo.getSelectedIndex(); if (index != 0) { Insets insets = PageConstants.getMargins(pageMarginList[index]); top.setValue(new Integer(insets.top)); bottom.setValue(new Integer(insets.bottom)); left.setValue(new Integer(insets.left)); right.setValue(new Integer(insets.right)); } } } private class TextFieldListener implements ActionListener { public void actionPerformed(ActionEvent event) { Insets margins = new Insets(((Number) top.getValue()).intValue(), ((Number) left.getValue()).intValue(), ((Number) bottom .getValue()).intValue(), ((Number) right.getValue()).intValue()); for (int i = 1; i < pageMarginList.length; i++) { Insets insets = PageConstants.getMargins(pageMarginList[i]); if (margins.equals(insets)) { pageMarginCombo.setSelectedIndex(i); return; } } pageMarginCombo.setSelectedIndex(0); // Custom } } private class TextFieldFormatter extends JFormattedTextField.AbstractFormatter { JFormattedTextField field; public void install(JFormattedTextField field) { super.install(field); this.field = field; } public void uninstall() { field = null; } // only positive (and zero) integer values public Object stringToValue(String text) throws ParseException { try { Integer value = new Integer(text); return value; } catch (NumberFormatException nfe) { Object value = field.getValue(); field.setValue(value); return value; } } public String valueToString(Object value) throws ParseException { if (value == null) return "0"; return value.toString(); } } }src/main/java/org/freehep/graphicsio/exportchooser/PageLayoutPanel.java0000644000175000017500000000253011312401772025672 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio.exportchooser; import java.util.Properties; import javax.swing.JLabel; import org.freehep.graphicsio.PageConstants; import org.freehep.swing.layout.TableLayout; /** * * @author Mark Donszelmann * @version $Id: PageLayoutPanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class PageLayoutPanel extends OptionPanel { public PageLayoutPanel(Properties options, String rootKey) { super("Page Layout"); add(TableLayout.LEFT, new JLabel("Size:")); add(TableLayout.RIGHT, new OptionComboBox(options, rootKey + "." + PageConstants.PAGE_SIZE, PageConstants.getSizeList())); // FIXME: re-add FREEHEP-277, Margins are now Insets // add(TableLayout.LEFT , new JLabel("Margins:")); // add(TableLayout.RIGHT, new OptionComboBox(options, // rootKey+"."+PageConstants.PAGE_MARGINS, // PageConstants.getMarginsList())); add(TableLayout.LEFT, new JLabel("Orientation:")); add(TableLayout.RIGHT, new OptionComboBox(options, rootKey + "." + PageConstants.ORIENTATION, PageConstants .getOrientationList())); add(TableLayout.FULL, new OptionCheckBox(options, rootKey + "." + PageConstants.FIT_TO_PAGE, "Fit to Page")); } } src/main/java/org/freehep/graphicsio/exportchooser/ImagePanel.java0000644000175000017500000000212011312401772024635 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio.exportchooser; import java.util.Properties; import javax.swing.ButtonGroup; import javax.swing.JLabel; import org.freehep.graphicsio.ImageConstants; import org.freehep.swing.layout.TableLayout; /** * * @author Mark Donszelmann * @version $Id: ImagePanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class ImagePanel extends OptionPanel { public ImagePanel(Properties options, String rootKey, String[] formats) { super("Images"); add(TableLayout.FULL, new JLabel("Write Images as")); ButtonGroup group = new ButtonGroup(); OptionRadioButton imageType[] = new OptionRadioButton[formats.length]; for (int i = 0; i < formats.length; i++) { imageType[i] = new OptionRadioButton(options, rootKey + "." + ImageConstants.WRITE_IMAGES_AS, formats[i]); add(TableLayout.FULL, imageType[i]); group.add(imageType[i]); // add(TableLayout.RIGHT, new OptionTextField(options, // rootKey+"."+keys[i], 40)); } } } src/main/java/org/freehep/graphicsio/exportchooser/InfoPanel.java0000644000175000017500000000123011312401772024507 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio.exportchooser; import java.util.Properties; import javax.swing.JLabel; import org.freehep.swing.layout.TableLayout; /** * * @author Mark Donszelmann * @version $Id: InfoPanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class InfoPanel extends OptionPanel { public InfoPanel(Properties options, String rootKey, String[] keys) { super("Info"); for (int i = 0; i < keys.length; i++) { add(TableLayout.LEFT, new JLabel(keys[i])); add(TableLayout.RIGHT, new OptionTextField(options, rootKey + "." + keys[i], 40)); } } } src/main/java/org/freehep/graphicsio/exportchooser/OptionFormattedTextField.java0000644000175000017500000000167511312401772027600 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio.exportchooser; import java.text.Format; import java.util.Properties; import javax.swing.JFormattedTextField; /** * * @author Mark Donszelmann * @version $Id: OptionFormattedTextField.java 8584 2006-08-10 23:06:37Z duns $ */ public class OptionFormattedTextField extends JFormattedTextField implements Options { protected String initialText; protected String key; public OptionFormattedTextField(Properties options, String key, String text, int columns, Format format) { super(format); setText(options.getProperty(key, text)); setColumns(columns); this.key = key; initialText = getText(); } public boolean applyChangedOptions(Properties options) { if (!getText().equals(initialText)) { options.setProperty(key, getText()); return true; } return false; } } src/main/java/org/freehep/graphicsio/exportchooser/ProgressDialog.java0000644000175000017500000000555111312401772025572 0ustar user03user03// Copyright 2001 freehep package org.freehep.graphicsio.exportchooser; import java.awt.BorderLayout; import java.awt.Component; import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JProgressBar; /** * A dialog showing a progress bar and a label. Pressing the cancel button will * call the cancel method on an * ExportGraphicsFileTypeAdaptor.CancelThread. Exceptions occuring * in another thread can be reported to this class and at the end of the thread * queried. * * @author Simon Fischer * @version $Id: ProgressDialog.java 8584 2006-08-10 23:06:37Z duns $ */ public class ProgressDialog extends JDialog { private JProgressBar progressBar; private JLabel label; private int progress; private IOException exception; private AbstractExportFileType.CancelThread thread; public ProgressDialog(Component parent, int steps, String string) { setTitle("Exporting file..."); setModal(true); this.exception = null; this.progress = 0; getContentPane().setLayout(new BorderLayout()); JPanel center = new JPanel(new GridLayout(2, 1)); progressBar = new JProgressBar(0, steps); center.add(progressBar); label = new JLabel(string); center.add(label); getContentPane().add(center, BorderLayout.CENTER); JPanel buttons = new JPanel(new FlowLayout(FlowLayout.CENTER)); JButton cancel = new JButton("Cancel"); cancel.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { cancel(); } }); buttons.add(cancel); getContentPane().add(buttons, BorderLayout.SOUTH); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); pack(); if (parent != null) { Point pLoc = parent.getLocation(); setLocation(pLoc.x + parent.getWidth() / 2 - getWidth() / 2, pLoc.y + parent.getHeight() / 2 - getHeight() / 2); } } public void step(String string) { progressBar.setValue(++progress); label.setText(string); repaint(); } public void exceptionOccured(IOException e) { this.exception = e; } public IOException getException() { return exception; } public void interruptOnCancel(AbstractExportFileType.CancelThread thread) { this.thread = thread; } public void cancel() { if (thread != null) thread.cancel(); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } dispose(); } } src/main/java/org/freehep/graphicsio/exportchooser/OptionComboBox.java0000644000175000017500000000472411312401772025550 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio.exportchooser; import java.awt.Component; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.Properties; import javax.swing.AbstractButton; import javax.swing.JComboBox; /** * * @author Mark Donszelmann * @version $Id: OptionComboBox.java 8584 2006-08-10 23:06:37Z duns $ */ public class OptionComboBox extends JComboBox implements Options { protected String initialSelectedItem; protected String key; public OptionComboBox(Properties options, String key, String[] values) { super(values); setSelectedItem(options.getProperty(key, values[0])); setEnabled(values.length > 1); this.key = key; initialSelectedItem = (String) getSelectedItem(); } public boolean applyChangedOptions(Properties options) { if (!getSelectedItem().equals(initialSelectedItem)) { options.setProperty(key, (String) getSelectedItem()); return true; } return false; } /** * Enables (otherwise disables) the supplied component if this item is * checked. Can be called for multiple components. */ public void enables(final String item, final Component c) { if (c.isEnabled()) { c.setEnabled(getSelectedItem().equals(item)); addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { c.setEnabled(getSelectedItem().equals(item)); } }); } } /** * Shows (otherwise hides) the supplied component if this item is selected. * Can be called for multiple components. */ public void shows(final String item, final Component c) { c.setVisible(getSelectedItem().equals(item)); addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { c.setVisible(getSelectedItem().equals(item)); } }); } /** * Selects (or deselects) the supplied abstract button if this item is * selected. Can be called for multiple components and items. */ public void selects(final String item, final AbstractButton c) { c.setSelected(getSelectedItem().equals(item)); addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { c.setSelected(getSelectedItem().equals(item)); } }); } } src/main/java/org/freehep/graphicsio/exportchooser/Options.java0000644000175000017500000000065311312401772024277 0ustar user03user03// Copyright 2003, FreeHEP package org.freehep.graphicsio.exportchooser; import java.util.Properties; /** * * @author Mark Donszelmann * @version $Id: Options.java 8584 2006-08-10 23:06:37Z duns $ */ public interface Options { /** * Sets all the changed options in the properties object. * * @return true if any options were set */ public boolean applyChangedOptions(Properties options); } src/main/java/org/freehep/graphicsio/exportchooser/OptionPanel.java0000644000175000017500000000246311312401772025075 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio.exportchooser; import java.awt.Component; import java.util.Properties; import javax.swing.BorderFactory; import javax.swing.JPanel; import org.freehep.swing.layout.TableLayout; /** * * @author Mark Donszelmann * @version $Id: OptionPanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class OptionPanel extends JPanel implements Options { public OptionPanel() { this(null); } public OptionPanel(String title) { super(new TableLayout()); if (title != null) setBorder(BorderFactory.createTitledBorder(BorderFactory .createEtchedBorder(), title)); } public void setEnabled(boolean enable) { for (int i = 0; i < getComponentCount(); i++) { Component c = getComponent(i); c.setEnabled(enable); } } public boolean applyChangedOptions(Properties options) { boolean changed = false; for (int i = 0; i < getComponentCount(); i++) { Component c = getComponent(i); if (c instanceof Options) { boolean changedThis = ((Options) c) .applyChangedOptions(options); changed = changed || changedThis; } } return changed; } } src/main/java/org/freehep/graphicsio/exportchooser/ImageSizePanel.java0000644000175000017500000001321611312401772025500 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio.exportchooser; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.text.ParseException; import java.util.Properties; import javax.swing.JComboBox; import javax.swing.JFormattedTextField; import javax.swing.JLabel; import org.freehep.graphics2d.ScreenConstants; import org.freehep.graphicsio.ImageConstants; import org.freehep.swing.layout.TableLayout; import org.freehep.util.UserProperties; /** * * @author Mark Donszelmann * @version $Id: ImageSizePanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class ImageSizePanel extends OptionPanel { final private static String imageSizeList[] = { "ImageSize", "Custom", ScreenConstants.VGA, ScreenConstants.SVGA, ScreenConstants.XGA, ScreenConstants.SXGA, ScreenConstants.SXGA_PLUS, ScreenConstants.UXGA }; private String key; private Dimension initialDimension; private JComboBox imageSizeCombo; private JFormattedTextField imageWidth, imageHeight; public ImageSizePanel(Properties user, String rootKey) { super("Image Size"); key = rootKey + "." + ImageConstants.IMAGE_SIZE; UserProperties options = new UserProperties(user); initialDimension = options.getPropertyDimension(key); imageSizeCombo = new JComboBox(imageSizeList); add(TableLayout.LEFT, new JLabel("Preset Sizes")); add(TableLayout.RIGHT, imageSizeCombo); add(TableLayout.LEFT, new JLabel("Width")); imageWidth = new JFormattedTextField(new TextFieldFormatter()); imageWidth.setColumns(10); add(TableLayout.RIGHT, imageWidth); add(TableLayout.LEFT, new JLabel("Height")); imageHeight = new JFormattedTextField(new TextFieldFormatter()); imageHeight.setColumns(10); add(TableLayout.RIGHT, imageHeight); imageSizeCombo.addItemListener(new ComboListener()); imageWidth.addActionListener(new TextFieldListener()); imageHeight.addActionListener(new TextFieldListener()); // now set the initial values imageWidth.setValue(new Integer(initialDimension.width)); imageHeight.setValue(new Integer(initialDimension.height)); // trigger the changes new TextFieldListener().actionPerformed(null); new ComboListener().itemStateChanged(null); } public boolean applyChangedOptions(Properties options) { boolean changed = false; Dimension size = new Dimension(((Number) imageWidth.getValue()) .intValue(), ((Number) imageHeight.getValue()).intValue()); if (!size.equals(initialDimension)) { options.setProperty(key, size.width + ", " + size.height); changed = true; } return changed; } private class ComboListener implements ItemListener { public void itemStateChanged(ItemEvent e) { int index = imageSizeCombo.getSelectedIndex(); switch (index) { case 0: // ImageSize imageWidth.setEnabled(false); imageHeight.setEnabled(false); imageWidth.setValue(new Integer(0)); imageHeight.setValue(new Integer(0)); break; case 1: // Custom imageWidth.setEnabled(true); imageHeight.setEnabled(true); break; default: // any other preset value imageWidth.setEnabled(true); imageHeight.setEnabled(true); Dimension d = ScreenConstants.getSize(imageSizeList[index]); imageWidth.setValue(new Integer(d.width)); imageHeight.setValue(new Integer(d.height)); break; } } } private class TextFieldListener implements ActionListener { public void actionPerformed(ActionEvent event) { int width = ((Number) imageWidth.getValue()).intValue(); int height = ((Number) imageHeight.getValue()).intValue(); if ((width == 0) && (height == 0)) { imageSizeCombo.setSelectedIndex(0); // ImageSize return; } for (int i = 2; i < imageSizeList.length; i++) { Dimension d = ScreenConstants.getSize(imageSizeList[i]); if ((width == d.width) && (height == d.height)) { imageSizeCombo.setSelectedIndex(i); return; } } imageSizeCombo.setSelectedIndex(1); // Custom } } private class TextFieldFormatter extends JFormattedTextField.AbstractFormatter { JFormattedTextField field; public void install(JFormattedTextField field) { super.install(field); this.field = field; } public void uninstall() { field = null; } // only positive (and zero) integer values public Object stringToValue(String text) throws ParseException { try { Integer value = new Integer(text); if (value.intValue() < 0) throw new NumberFormatException(); return value; } catch (NumberFormatException nfe) { Object value = field.getValue(); field.setValue(value); return value; } } public String valueToString(Object value) throws ParseException { if (value == null) return "0"; return value.toString(); } } }src/main/java/org/freehep/graphicsio/exportchooser/HeadFootDialog.java0000644000175000017500000001127711312401772025461 0ustar user03user03// Copyright 2001 freehep package org.freehep.graphicsio.exportchooser; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import org.freehep.graphics2d.TagString; import org.freehep.graphicsio.MultiPageDocument; /** * @author Simon Fischer * @version $Id: HeadFootDialog.java 8584 2006-08-10 23:06:37Z duns $ */ public class HeadFootDialog extends JDialog implements ActionListener, ItemListener { private static final String[] HF_LABELS = { "Headline", "Footline" }; private JTextField textField[][]; private JCheckBox useCheckBox[]; private TagString text[][]; public HeadFootDialog() { super(); setTitle("Head- and footlines"); setModal(true); getContentPane().setLayout(new BorderLayout()); textField = new JTextField[HF_LABELS.length][]; useCheckBox = new JCheckBox[HF_LABELS.length]; JPanel textPanel = new JPanel(new GridLayout(HF_LABELS.length * 2, 1)); for (int i = 0; i < HF_LABELS.length; i++) { JPanel title = new JPanel(new FlowLayout(FlowLayout.LEFT)); useCheckBox[i] = new JCheckBox(); useCheckBox[i].setSelected(false); useCheckBox[i].addItemListener(this); title.add(useCheckBox[i]); title.add(new JLabel(HF_LABELS[i])); textPanel.add(title); JPanel textFieldPanel = new JPanel(new FlowLayout()); textField[i] = new JTextField[3]; for (int j = 0; j < textField[i].length; j++) { textField[i][j] = new JTextField(10); textField[i][j].setEnabled(false); textFieldPanel.add(textField[i][j]); } textPanel.add(textFieldPanel); } getContentPane().add(textPanel, BorderLayout.CENTER); JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); JButton cancel = new JButton("Cancel"); cancel.setActionCommand("cancel"); cancel.addActionListener(this); buttonPanel.add(cancel); JButton ok = new JButton("Ok"); ok.setActionCommand("ok"); ok.addActionListener(this); buttonPanel.add(ok); getContentPane().add(buttonPanel, BorderLayout.SOUTH); pack(); text = new TagString[useCheckBox.length][]; } public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("ok")) { for (int i = 0; i < useCheckBox.length; i++) { if (useCheckBox[i].isSelected()) { text[i] = new TagString[3]; for (int j = 0; j < textField[i].length; j++) { text[i][j] = new TagString(textField[i][j].getText()); } } else { text[i] = null; } } setVisible(false); } else if (e.getActionCommand().equals("cancel")) { for (int i = 0; i < useCheckBox.length; i++) { useCheckBox[i].setSelected(text[i] != null); for (int j = 0; j < textField[i].length; j++) { if (text[i] != null) { textField[i][j].setText(text[i][j].toString()); textField[i][j].setEnabled(true); } else { textField[i][j].setText(""); textField[i][j].setEnabled(false); } } } setVisible(false); } } public void configure(MultiPageDocument md) { if (text[0] != null) { md.setHeader(new Font("times", Font.PLAIN, 10), text[0][0], text[0][1], text[0][2], 1); } if (text[1] != null) { md.setFooter(new Font("times", Font.PLAIN, 10), text[1][0], text[1][1], text[1][2], 1); } } public void itemStateChanged(ItemEvent e) { for (int i = 0; i < useCheckBox.length; i++) { if (e.getSource() == useCheckBox[i]) { for (int j = 0; j < textField[i].length; j++) { textField[i][j] .setEnabled(e.getStateChange() == ItemEvent.SELECTED); } } } } public static void main(String[] argv) { JDialog d = new HeadFootDialog(); d.setVisible(true); } } src/main/java/org/freehep/graphicsio/exportchooser/AbstractExportFileType.java0000644000175000017500000002400011312401772027243 0ustar user03user03// Copyright 2003-2007, FreeHEP package org.freehep.graphicsio.exportchooser; import java.awt.Component; import java.awt.Dimension; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Properties; import javax.swing.JPanel; import org.freehep.graphics2d.VectorGraphics; import org.freehep.graphicsio.MultiPageDocument; import org.freehep.util.export.ExportFileType; /** * * @author Charles Loomis * @author Mark Donszelmann * @version $Id: AbstractExportFileType.java 12753 2007-06-12 22:32:31Z duns $ */ public abstract class AbstractExportFileType extends ExportFileType { public abstract class CancelThread extends Thread { private boolean stop; private File currentFile; private OutputStream currentOut; ProgressDialog progress; private CancelThread(ProgressDialog progress) { super(); this.progress = progress; this.stop = false; progress.interruptOnCancel(this); } abstract void export() throws IOException; public void cancel() { this.stop = true; } public boolean isStopped() { return stop; } /** * Exports the graphics and afterwards cleans up, i.e. deletes the * current file. Hence, current file must be set to null by the * subclasses export() method when export is finished. Exceptions will * be reported to the ProgressDialog. */ public void run() { try { export(); } catch (IOException e) { if (!stop) { progress.exceptionOccured(e); } } try { cleanUp(); } catch (IOException e) { System.err.println("While cleaning up:"); e.printStackTrace(); } } void setCurrentFile(File file) { this.currentFile = file; } void setCurrentOutputStream(OutputStream out) { this.currentOut = out; } void cleanUp() throws IOException { if (currentOut != null) currentOut.close(); if (currentFile != null) currentFile.delete(); } } private class MultiPageSingleFileExportThread extends CancelThread { private MultiPageDocument mdoc; private VectorGraphics graphics; private Component[] saveTargets; private MultiPageSingleFileExportThread(MultiPageDocument mdoc, VectorGraphics g, Component[] saveTargets, ProgressDialog progress) { super(progress); this.mdoc = mdoc; this.graphics = g; this.saveTargets = saveTargets; this.progress = progress; } private MultiPageSingleFileExportThread(MultiPageDocument mdoc, VectorGraphics g, Component[] saveTargets, ProgressDialog progress, OutputStream out) { this(mdoc, g, saveTargets, progress); setCurrentOutputStream(out); } private MultiPageSingleFileExportThread(MultiPageDocument mdoc, VectorGraphics g, Component[] saveTargets, ProgressDialog progress, File file) { this(mdoc, g, saveTargets, progress); setCurrentFile(file); } void export() throws IOException { graphics.startExport(); for (int i = 0; i < saveTargets.length; i++) { if (isStopped()) return; // Now actually print the components. if ((graphics != null) && (mdoc != null)) { progress.step("Writing page " + (i + 1) + "/" + saveTargets.length + "."); mdoc.openPage(saveTargets[i]); if (isStopped()) return; progress.step("Writing page " + (i + 1) + "/" + saveTargets.length + ".."); saveTargets[i].print(graphics); if (isStopped()) return; progress.step("Writing page " + (i + 1) + "/" + saveTargets.length + "..."); mdoc.closePage(); if (isStopped()) return; } } if (isStopped()) return; progress.step("Writing trailer..."); graphics.endExport(); setCurrentOutputStream(null); setCurrentFile(null); progress.dispose(); } } private class MultipageMultipleFilesExportThread extends CancelThread { private File file; private Component[] saveTargets; private Component parent; private Properties properties; private String creator; private MultipageMultipleFilesExportThread(Component[] saveTargets, File file, ProgressDialog progress, Component parent, Properties properties, String creator) { super(progress); this.file = file; this.saveTargets = saveTargets; this.parent = parent; this.properties = properties; this.creator = creator; } void export() throws IOException { for (int i = 0; i < saveTargets.length; i++) { if (isStopped()) { cleanUp(); return; } progress.step("Page " + (i + 1) + "/" + saveTargets.length + "..."); String filename = file.getAbsolutePath(); int dotIndex = filename.lastIndexOf("."); if (dotIndex == -1) dotIndex = filename.length() - 1; filename = filename.substring(0, dotIndex) + "-" + (i + 1) + filename.substring(dotIndex); File singleFile = new File(filename); setCurrentFile(singleFile); exportToFile(singleFile, saveTargets[i], parent, properties, creator); setCurrentFile(null); } progress.dispose(); } } /** * Delegates to getGraphics(OutputStream, Component); */ public VectorGraphics getGraphics(File file, Component target) throws IOException { return getGraphics( new BufferedOutputStream(new FileOutputStream(file)), target); } /** * Delegates to getGraphics(OutputStream, Dimension); */ public VectorGraphics getGraphics(File file, Dimension dimension) throws IOException { return getGraphics( new BufferedOutputStream(new FileOutputStream(file)), dimension); } /** * The method returns a graphics context specific for this ExportFileType. */ public abstract VectorGraphics getGraphics(OutputStream os, Component printTarget) throws IOException; /** * Returns a graphics context for this ExportFileType. */ public abstract VectorGraphics getGraphics(OutputStream os, Dimension dimension) throws IOException; /** * Show this dialog and save component as the given file type. */ public void exportToFile(OutputStream os, Component target, Component parent, Properties properties, String creator) throws IOException { VectorGraphics g = getGraphics(os, target, properties); if (g != null) { g.setCreator(creator); g.setProperties(properties); g.startExport(); target.print(g); g.endExport(); } } private VectorGraphics getGraphics(OutputStream os, Component target, Properties properties) throws IOException { // NOTE: same as in ExportDialog int w = Integer.parseInt(properties.getProperty("size-w", "-1")); int h = Integer.parseInt(properties.getProperty("size-h", "-1")); return (w >= 0 && h >= 0) ? getGraphics(os, new Dimension(w, h)) : getGraphics(os, target); } private VectorGraphics getGraphics(File file, Component target, Properties properties) throws IOException { // NOTE: same as in ExportDialog int w = Integer.parseInt(properties.getProperty("size-w", "-1")); int h = Integer.parseInt(properties.getProperty("size-h", "-1")); return (w >= 0 && h >= 0) ? getGraphics(file, new Dimension(w, h)) : getGraphics(file, target); } /** * Show this dialog and save component as the given file type. */ public void exportToFile(File file, Component target, Component parent, Properties properties, String creator) throws IOException { exportToFile(new BufferedOutputStream(new FileOutputStream(file)), target, parent, properties, creator); } /** * Save all components as the given file type. If * getConfiguredGraphics(OutputStream, Component[]) does not * return a MultiPageDocument (or null) * saveTargets.length numbered documents are created each of * which contains a single page. */ public void exportToFile(OutputStream os, Component[] targets, Component parent, Properties properties, String creator) throws IOException { ProgressDialog progress = null; Thread exportThread = null; VectorGraphics g = getGraphics(os, targets[0], properties); if ((g != null) && (g instanceof MultiPageDocument)) { g.setCreator(creator); g.setProperties(properties); progress = new ProgressDialog(parent, targets.length * 3 + 2, "Writing header..."); MultiPageDocument mdoc = (MultiPageDocument) g; mdoc.setMultiPage(true); exportThread = new MultiPageSingleFileExportThread(mdoc, g, targets, progress, os); exportThread.start(); progress.setVisible(true); IOException exc = progress.getException(); if (exc != null) throw exc; } else { System.out .println("Cannot write multi files to one output stream."); } } /** * Save all components as the given file type. If * getConfiguredGraphics(File, Component[]) does not return a * MultiPageDocument (or null) saveTargets.length * numbered documents are created each of which contains a single page. */ public void exportToFile(File file, Component[] targets, Component parent, Properties properties, String creator) throws IOException { ProgressDialog progress = null; Thread exportThread = null; VectorGraphics g = getGraphics(file, targets[0], properties); if ((g != null) && (g instanceof MultiPageDocument)) { g.setCreator(creator); g.setProperties(properties); progress = new ProgressDialog(parent, targets.length * 3 + 2, "Writing header..."); MultiPageDocument mdoc = (MultiPageDocument) g; mdoc.setMultiPage(true); exportThread = new MultiPageSingleFileExportThread(mdoc, g, targets, progress, file); } else { progress = new ProgressDialog(parent, targets.length + 2, "Exporting files..."); exportThread = new MultipageMultipleFilesExportThread(targets, file, progress, parent, properties, creator); } exportThread.start(); progress.setVisible(true); IOException e = progress.getException(); if (e != null) throw e; } public boolean applyChangedOptions(JPanel panel, Properties options) { if (panel instanceof Options) { return ((Options) panel).applyChangedOptions(options); } System.err .println(getClass() + ": applyChangedOptions(...), panel does not implement Options interface."); return false; } } src/main/java/org/freehep/graphicsio/exportchooser/FontPanel.java0000644000175000017500000000375311312401772024536 0ustar user03user03// Copyright 2003-2007, FreeHEP. package org.freehep.graphicsio.exportchooser; import java.awt.Component; import java.util.Properties; import org.freehep.graphicsio.FontConstants; import org.freehep.swing.layout.TableLayout; /** * * @author Mark Donszelmann * @version $Id: FontPanel.java 10516 2007-02-06 21:11:19Z duns $ */ public class FontPanel extends OptionPanel { /** * defines the optionpanel for font embedding and text as shapes. * * @param options * @param embeddingRootKey rootkey for {@link String abstractRootKey = AbstractVectorGraphicsIO.class.getName();#EMBED_FONTS} and {@link FontConstants#EMBED_FONTS_AS} * @param shapeRootKey rootkey for {@link FontConstants#TEXT_AS_SHAPES} */ public FontPanel(Properties options, String embeddingRootKey, String shapeRootKey) { super("Fonts"); // to disable / enable for TEXT_AS_SHAPES Component enable = null; // font embedding if (embeddingRootKey != null) { final OptionCheckBox checkBox = new OptionCheckBox( options, embeddingRootKey + "." + FontConstants.EMBED_FONTS, "Embed Fonts as"); add(TableLayout.LEFT, checkBox); final OptionComboBox comboBox = new OptionComboBox( options, embeddingRootKey + "." + FontConstants.EMBED_FONTS_AS, FontConstants .getEmbedFontsAsList()); add(TableLayout.RIGHT, comboBox); checkBox.enables(comboBox); enable = checkBox; } // text es shape if (shapeRootKey != null) { final OptionCheckBox shapeCheckBox = new OptionCheckBox( options, shapeRootKey + "." + FontConstants.TEXT_AS_SHAPES, "Draw text as shapes"); add(TableLayout.FULL, shapeCheckBox); if (enable != null) { shapeCheckBox.disables(enable); } } } } src/main/java/org/freehep/graphicsio/exportchooser/BackgroundPanel.java0000644000175000017500000000621711312401772025705 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio.exportchooser; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Properties; import javax.swing.JColorChooser; import javax.swing.JDialog; import javax.swing.JLabel; import org.freehep.graphics2d.PrintColor; import org.freehep.graphicsio.PageConstants; import org.freehep.swing.layout.TableLayout; import org.freehep.util.UserProperties; /** * * @author Mark Donszelmann * @version $Id: BackgroundPanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class BackgroundPanel extends OptionPanel { private Color initialBackground; private Color background; private JColorChooser colorChooser; private OptionButton colorButton; private String key; public BackgroundPanel(Properties options, String rootKey, boolean hasTransparency) { this(options, rootKey, hasTransparency, "Background"); } public BackgroundPanel(Properties options, String rootKey, boolean hasTransparency, String title) { super(title); key = rootKey + "." + PageConstants.BACKGROUND_COLOR; UserProperties user = new UserProperties(options); initialBackground = user.getPropertyColor(key); if (initialBackground == null) initialBackground = Color.WHITE; background = initialBackground; OptionCheckBox backgroundCheck = new OptionCheckBox(options, rootKey + "." + PageConstants.BACKGROUND, "Background"); colorChooser = new JColorChooser(initialBackground); JDialog dialog = JColorChooser.createDialog(this, "Choose Background Color", true, colorChooser, new ChangeColorListener(), null); colorButton = new OptionButton(options, rootKey, "Select Color", dialog); backgroundCheck.enables(colorButton); String left = title == null ? TableLayout.VERY_LEFT : TableLayout.LEFT; String right = title == null ? TableLayout.VERY_RIGHT : TableLayout.RIGHT; if (hasTransparency) { OptionCheckBox transparentCheck = new OptionCheckBox(options, rootKey + "." + PageConstants.TRANSPARENT, "Transparent"); add(left, transparentCheck); add(right, new JLabel()); transparentCheck.disables(backgroundCheck); } add(left, backgroundCheck); add(right, colorButton); // trigger initial setting new ChangeColorListener().actionPerformed(null); } public boolean applyChangedOptions(Properties options) { boolean changed = super.applyChangedOptions(options); if (!background.equals(initialBackground)) { UserProperties.setProperty(options, key, background); changed = true; } return changed; } class ChangeColorListener implements ActionListener { public void actionPerformed(ActionEvent event) { background = colorChooser.getColor(); colorButton.setBackground(background); colorButton.setForeground(PrintColor.invert(background)); } } } src/main/java/org/freehep/graphicsio/exportchooser/OptionRadioButton.java0000644000175000017500000000347411312401772026273 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio.exportchooser; import java.awt.Component; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.Properties; import javax.swing.JRadioButton; /** * * @author Mark Donszelmann * @version $Id: OptionRadioButton.java 8584 2006-08-10 23:06:37Z duns $ */ public class OptionRadioButton extends JRadioButton implements Options { protected boolean initialState; protected String key; public OptionRadioButton(Properties options, String key, String text) { super(text, new Boolean(options.getProperty(key, "false")) .booleanValue()); this.key = key; initialState = isSelected(); } public boolean applyChangedOptions(Properties options) { if (isSelected() != initialState) { options.setProperty(key, Boolean.toString(isSelected())); return true; } return false; } /** * Enables (otherwise disables) the supplied component if this radiobutton * is checked. Can be called for multiple components. */ public void enables(final Component c) { if (c.isEnabled()) { c.setEnabled(isSelected()); addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { c.setEnabled(isSelected()); } }); } } /** * Shows (otherwise hides) the supplied component if this radiobutton is * checked. Can be called for multiple components. */ public void shows(final Component c) { c.setVisible(isSelected()); addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { c.setVisible(isSelected()); } }); } } src/main/java/org/freehep/graphicsio/exportchooser/OptionCheckBox.java0000644000175000017500000000714411312401772025525 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio.exportchooser; import java.awt.Component; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Properties; import javax.swing.JCheckBox; /** * * @author Mark Donszelmann * @version $Id: OptionCheckBox.java 8584 2006-08-10 23:06:37Z duns $ */ public class OptionCheckBox extends JCheckBox implements Options { protected boolean initialState; protected String key; public OptionCheckBox(Properties options, String key, String text) { super(text, new Boolean(options.getProperty(key, "false")) .booleanValue()); this.key = key; initialState = isSelected(); } public boolean applyChangedOptions(Properties options) { if (isSelected() != initialState) { options.setProperty(key, Boolean.toString(isSelected())); return true; } return false; } /** * Enables (otherwise disables) the supplied component if this checkbox is * checked. Can be called for multiple components. */ public void enables(final Component c) { if (c.isEnabled()) { c.setEnabled(isSelected()); // selecting addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { c.setEnabled(isSelected()); } }); // disabling addPropertyChangeListener("enabled", new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent e) { if (e.getNewValue().equals(Boolean.TRUE)) { c.setEnabled(isSelected()); } else { c.setEnabled(false); } } }); } } /** * Disabled (otherwise enables) the supplied component if this checkbox is * checked. Can be called for multiple components. */ public void disables(final Component c) { if (c.isEnabled()) { c.setEnabled(!isSelected()); // selecting addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { c.setEnabled(!isSelected()); } }); // disabling addPropertyChangeListener("enabled", new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent e) { if (e.getNewValue().equals(Boolean.TRUE)) { c.setEnabled(!isSelected()); } else { c.setEnabled(false); } } }); } } /** * Shows (otherwise hides) the supplied component if this checkbox is * checked. Can be called for multiple components. */ public void shows(final Component c) { c.setVisible(isSelected()); addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { c.setVisible(isSelected()); } }); } /** * Hides (otherwise shows) the supplied component if this checkbox is * checked. Can be called for multiple components. */ public void hides(final Component c) { c.setVisible(!isSelected()); addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { c.setVisible(!isSelected()); } }); } } src/main/java/org/freehep/graphicsio/exportchooser/ImageExportFileType.java0000644000175000017500000001601311312401772026527 0ustar user03user03// Copyright 2000-2007, FreeHEP package org.freehep.graphicsio.exportchooser; import java.awt.Component; import java.awt.Dimension; import java.io.IOException; import java.io.OutputStream; import java.util.Iterator; import java.util.Locale; import java.util.Properties; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.spi.ImageWriterSpi; import javax.swing.JLabel; import javax.swing.JPanel; import org.freehep.graphics2d.VectorGraphics; import org.freehep.graphicsio.ImageGraphics2D; import org.freehep.graphicsio.ImageConstants; import org.freehep.swing.layout.TableLayout; import org.freehep.util.UserProperties; /** * // FIXME, check all options * * @author Mark Donszelmann * @version $Id: ImageExportFileType.java 12753 2007-06-12 22:32:31Z duns $ */ public class ImageExportFileType extends AbstractExportFileType { protected String format; protected ImageWriterSpi spi; protected ImageWriteParam param; protected OptionCheckBox antialias; protected OptionCheckBox antialiasText; protected OptionCheckBox progressive; protected OptionCheckBox compress; protected OptionComboBox compressMode; protected OptionComboBox compressDescription; protected OptionTextField compressQuality; protected ImageExportFileType(String format) { Iterator iterator = ImageIO.getImageWritersByFormatName(format); if (iterator.hasNext()) { ImageWriter writer = (ImageWriter) iterator.next(); this.format = format; this.spi = writer.getOriginatingProvider(); this.param = writer.getDefaultWriteParam(); return; } throw new IllegalArgumentException(getClass() + ": Format not valid: " + format); } public ImageExportFileType(ImageWriterSpi spi) { this.format = spi.getFormatNames()[0]; this.spi = spi; try { this.param = spi.createWriterInstance().getDefaultWriteParam(); } catch (IOException e) { throw new RuntimeException("Failed to create Writer instance", e); } } // FIXME only based on spi class name. public boolean equals(Object obj) { if (obj instanceof ImageExportFileType) { ImageExportFileType type = (ImageExportFileType) obj; return spi.getClass().equals(type.spi.getClass()); } return super.equals(obj); } // FIXME only based on spi class name. public int hashCode() { return spi.getClass().hashCode(); } public static ImageExportFileType getInstance(String format) { format = format.toLowerCase(); if (format.equals(ImageConstants.GIF.toLowerCase())) return exportFileType("org.freehep.graphicsio.gif.GIFExportFileType"); if (format.equals(ImageConstants.PNG.toLowerCase())) return exportFileType("org.freehep.graphicsio.png.PNGExportFileType"); if (format.equals(ImageConstants.JPG.toLowerCase())) return exportFileType("org.freehep.graphicsio.jpg.JPGExportFileType"); if (format.equals(ImageConstants.RAW.toLowerCase())) return exportFileType("org.freehep.graphicsio.raw.RawExportFileType"); if (format.equals(ImageConstants.BMP.toLowerCase())) return exportFileType("org.freehep.graphicsio.bmp.BMPExportFileType"); if (format.equals(ImageConstants.WBMP.toLowerCase())) return exportFileType("org.freehep.graphicsio.wbmp.WBMPExportFileType"); return null; } private static ImageExportFileType exportFileType(String className) { try { Class clazz = Class.forName(className); return (ImageExportFileType) clazz.newInstance(); } catch (Exception e) { System.out.println(e); } return null; } public String getDescription() { return spi.getDescription(Locale.getDefault()); } public String[] getExtensions() { return spi.getFileSuffixes(); } public String[] getMIMETypes() { return spi.getMIMETypes(); } public boolean hasOptionPanel() { return true; } public JPanel createOptionPanel(Properties user) { UserProperties options = new UserProperties(user, ImageGraphics2D .getDefaultProperties(format)); OptionPanel panel = new OptionPanel(format.toUpperCase() + " Format"); String formatKey = ImageGraphics2D.rootKey + "." + format; panel.add(TableLayout.FULL, new BackgroundPanel(options, formatKey, ImageGraphics2D.canWriteTransparent(format), null)); antialias = new OptionCheckBox(options, formatKey + ImageGraphics2D.ANTIALIAS, "Antialias"); panel.add(TableLayout.FULL, antialias); antialiasText = new OptionCheckBox(options, formatKey + ImageGraphics2D.ANTIALIAS_TEXT, "Antialias Text"); panel.add(TableLayout.FULL, antialiasText); progressive = new OptionCheckBox(options, formatKey + ImageGraphics2D.PROGRESSIVE, "Progressive"); if (param.canWriteProgressive()) { panel.add(TableLayout.FULL, progressive); } compress = new OptionCheckBox(options, formatKey + ImageGraphics2D.COMPRESS, "Compress"); if (param.canWriteCompressed()) { if (ImageGraphics2D.canWriteUncompressed(format)) { panel.add(TableLayout.FULL, compress); // NOTE: force compression param .setCompressionMode(options.isProperty(formatKey + ImageGraphics2D.COMPRESS) ? ImageWriteParam.MODE_EXPLICIT : ImageWriteParam.MODE_DISABLED); } } if (param.canWriteCompressed() && (param.getCompressionMode() == ImageWriteParam.MODE_EXPLICIT)) { String[] compressionTypes = param.getCompressionTypes(); JLabel compressModeLabel = new JLabel("Compression Mode"); compressMode = new OptionComboBox(options, formatKey + ImageGraphics2D.COMPRESS_MODE, compressionTypes); if (compressionTypes.length > 1) { panel.add(TableLayout.LEFT, compressModeLabel); panel.add(TableLayout.RIGHT, compressMode); compress.enables(compressModeLabel); compress.enables(compressMode); } /* * FIXME to be connected to the rest String[] * compressionDescriptions = * param.getCompressionQualityDescriptions(); JLabel * compressDescriptionLabel = new JLabel("Quality Mode"); * compressDescription = new OptionComboBox(options, * formatKey+ImageGraphics2D.COMPRESS_DESCRIPTION, * compressionDescriptions); * * if (compressionDescriptions.length > 1) { * panel.add(TableLayout.LEFT, compressDescriptionLabel); * panel.add(TableLayout.RIGHT, compressDescription); * compress.enables(compressDescriptionLabel); * compress.enables(compressDescription); } */ // FIXME check value JLabel compressQualityLabel = new JLabel("Quality Value"); panel.add(TableLayout.LEFT, compressQualityLabel); compressQuality = new OptionTextField(options, formatKey + ImageGraphics2D.COMPRESS_QUALITY, 5); panel.add(TableLayout.RIGHT, compressQuality); compress.enables(compressQualityLabel); compress.enables(compressQuality); // FIXME add slider } return panel; } public VectorGraphics getGraphics(OutputStream os, Component target) throws IOException { return new ImageGraphics2D(os, target, format); } public VectorGraphics getGraphics(OutputStream os, Dimension dimension) throws IOException { return new ImageGraphics2D(os, dimension, format); } public String toString() { return super.toString() + " for " + format + " using " + spi; } } src/main/java/org/freehep/graphicsio/ppm/0000755000175000017500000000000011312401771017664 5ustar user03user03src/main/java/org/freehep/graphicsio/ppm/package.html0000644000175000017500000000032211312401771022142 0ustar user03user03

PPM (Portable PixMap) Output Format.

Writes out ppm files in binary format.

src/main/java/org/freehep/graphicsio/ppm/PPMImageWriterSpi.java0000644000175000017500000000233011312401771023775 0ustar user03user03// Copyright 2003-2006, FreeHEP package org.freehep.graphicsio.ppm; import java.io.IOException; import java.util.Locale; import javax.imageio.ImageTypeSpecifier; import javax.imageio.ImageWriter; import javax.imageio.spi.ImageWriterSpi; /** * @author Mark Donszelmann * @version $Id: PPMImageWriterSpi.java 10113 2006-12-04 15:41:17Z duns $ */ public class PPMImageWriterSpi extends ImageWriterSpi { public PPMImageWriterSpi() { super("FreeHEP Java Libraries, http://java.freehep.org/", "1.0", new String[] { "ppm" }, new String[] { "ppm" }, new String[] { "image/x-portable-pixmap", "image/x-portable-pixmap" }, "org.freehep.graphicsio.ppm.PPMImageWriter", STANDARD_OUTPUT_TYPE, null, false, null, null, null, null, false, null, null, null, null); } public String getDescription(Locale locale) { return "FreeHEP UNIX Portable PixMap Format"; } public ImageWriter createWriterInstance(Object extension) throws IOException { return new PPMImageWriter(this); } public boolean canEncodeImage(ImageTypeSpecifier type) { // FIXME return true; } } src/main/java/org/freehep/graphicsio/ppm/PPMImageWriter.java0000644000175000017500000000407311312401771023327 0ustar user03user03// Copyright 2003, FreeHEP package org.freehep.graphicsio.ppm; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.io.IOException; import javax.imageio.IIOImage; import javax.imageio.ImageTypeSpecifier; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.metadata.IIOMetadata; import javax.imageio.stream.ImageOutputStream; /** * * @version $Id: PPMImageWriter.java 8584 2006-08-10 23:06:37Z duns $ */ public class PPMImageWriter extends ImageWriter { public PPMImageWriter(PPMImageWriterSpi originatingProvider) { super(originatingProvider); } public void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException { if (image == null) throw new IllegalArgumentException("image == null"); if (image.hasRaster()) throw new UnsupportedOperationException("Cannot write rasters"); Object output = getOutput(); if (output == null) throw new IllegalStateException("output was not set"); if (param == null) param = getDefaultWriteParam(); ImageOutputStream ios = (ImageOutputStream) output; RenderedImage ri = image.getRenderedImage(); if (ri instanceof BufferedImage) { BufferedImage bi = (BufferedImage) ri; PPMEncoder encoder = new PPMEncoder(bi, ios); encoder.encode(); } else { throw new IOException("Image not of type BufferedImage"); } } public IIOMetadata convertStreamMetadata(IIOMetadata inData, ImageWriteParam param) { return null; } public IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param) { return null; } public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param) { return null; } public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) { return null; } } src/main/java/org/freehep/graphicsio/ppm/PPMExportFileType.java0000644000175000017500000000152111312401771024026 0ustar user03user03// Copyright 2000-2006, FreeHEP. package org.freehep.graphicsio.ppm; import javax.imageio.spi.IIORegistry; import javax.imageio.spi.ImageWriterSpi; import org.freehep.graphicsio.exportchooser.ImageExportFileType; /** * @author Mark Donszelmann * @author Charles Loomis * @version $Id: PPMExportFileType.java 10113 2006-12-04 15:41:17Z duns $ */ public class PPMExportFileType extends ImageExportFileType { static { try { Class clazz = Class .forName("org.freehep.graphicsio.ppm.PPMImageWriterSpi"); IIORegistry.getDefaultInstance().registerServiceProvider( (ImageWriterSpi)clazz.newInstance(), ImageWriterSpi.class); } catch (Exception e) { System.out.println(e); } } public PPMExportFileType() { super("ppm"); } } src/main/java/org/freehep/graphicsio/ppm/ImageEncoder.java0000644000175000017500000001747711312401771023071 0ustar user03user03package org.freehep.graphicsio.ppm; // ImageEncoder - abstract class for writing out an image // // Copyright (C) 1996 by Jef Poskanzer . All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. // // Visit the ACME Labs Java page for up-to-date versions of this and other // fine Java utilities: http://www.acme.com/java/ //package Acme.JPM.Encoders; import java.awt.Image; import java.awt.image.ColorModel; import java.awt.image.ImageConsumer; import java.awt.image.ImageProducer; import java.io.DataOutput; import java.io.IOException; import java.util.Hashtable; /// Abstract class for writing out an image. //

// A framework for classes that encode and write out an image in // a particular file format. //

// This provides a simplified rendition of the ImageConsumer interface. // It always delivers the pixels as ints in the RGBdefault color model. // It always provides them in top-down left-right order. // If you want more flexibility you can always implement ImageConsumer // directly. //

// Fetch the software.
// Fetch the entire Acme package. //

// @see GifEncoder // @see PpmEncoder // @see Acme.JPM.Decoders.ImageDecoder public abstract class ImageEncoder implements ImageConsumer { protected DataOutput out; private ImageProducer producer; private int width = -1; private int height = -1; private int hintflags = 0; private boolean started = false; private boolean encoding; private IOException iox; private static final ColorModel rgbModel = ColorModel.getRGBdefault(); protected Hashtable props = null; // / Constructor. // @param img The image to encode. // @param out The stream to write the bytes to. public ImageEncoder(Image img, DataOutput dos) throws IOException { this(img.getSource(), dos); } // / Constructor. // @param producer The ImageProducer to encode. // @param out The stream to write the bytes to. public ImageEncoder(ImageProducer producer, DataOutput dos) throws IOException { this.producer = producer; this.out = dos; } // Methods that subclasses implement. // / Subclasses implement this to initialize an encoding. protected abstract void encodeStart(int w, int h) throws IOException; // / Subclasses implement this to actually write out some bits. They // are guaranteed to be delivered in top-down-left-right order. // One int per pixel, index is row * scansize + off + col, // RGBdefault (AARRGGBB) color model. protected abstract void encodePixels(int x, int y, int w, int h, int[] rgbPixels, int off, int scansize) throws IOException; // / Subclasses implement this to finish an encoding. protected abstract void encodeDone() throws IOException; // Our own methods. // / Call this after initialization to get things going. public synchronized void encode() throws IOException { encoding = true; iox = null; producer.startProduction(this); while (encoding) try { wait(); } catch (InterruptedException e) { } if (iox != null) throw iox; } private boolean accumulate = false; private int[] accumulator; private void encodePixelsWrapper(int x, int y, int w, int h, int[] rgbPixels, int off, int scansize) throws IOException { if (!started) { started = true; encodeStart(width, height); if ((hintflags & TOPDOWNLEFTRIGHT) == 0) { accumulate = true; accumulator = new int[width * height]; } } if (accumulate) for (int row = 0; row < h; ++row) System.arraycopy(rgbPixels, row * scansize + off, accumulator, (y + row) * width + x, w); else encodePixels(x, y, w, h, rgbPixels, off, scansize); } private void encodeFinish() throws IOException { if (accumulate) { encodePixels(0, 0, width, height, accumulator, 0, width); accumulator = null; accumulate = false; } } private synchronized void stop() { encoding = false; notifyAll(); } // Methods from ImageConsumer. public void setDimensions(int width, int height) { this.width = width; this.height = height; } public void setProperties(Hashtable props) { this.props = props; } public void setColorModel(ColorModel model) { // Ignore. } public void setHints(int hintflags) { this.hintflags = hintflags; } public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize) { int[] rgbPixels = new int[w]; for (int row = 0; row < h; ++row) { int rowOff = off + row * scansize; for (int col = 0; col < w; ++col) rgbPixels[col] = model.getRGB(pixels[rowOff + col] & 0xff); try { encodePixelsWrapper(x, y + row, w, 1, rgbPixels, 0, w); } catch (IOException e) { iox = e; stop(); return; } } } public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize) { if (model == rgbModel) { try { encodePixelsWrapper(x, y, w, h, pixels, off, scansize); } catch (IOException e) { iox = e; stop(); return; } } else { int[] rgbPixels = new int[w]; for (int row = 0; row < h; ++row) { int rowOff = off + row * scansize; for (int col = 0; col < w; ++col) rgbPixels[col] = model.getRGB(pixels[rowOff + col]); try { encodePixelsWrapper(x, y + row, w, 1, rgbPixels, 0, w); } catch (IOException e) { iox = e; stop(); return; } } } } public void imageComplete(int status) { producer.removeConsumer(this); if (status == ImageConsumer.IMAGEABORTED) iox = new IOException("image aborted"); else { try { encodeFinish(); encodeDone(); } catch (IOException e) { iox = e; } } stop(); } } src/main/java/org/freehep/graphicsio/ppm/PPMEncoder.java0000644000175000017500000001037111312401771022465 0ustar user03user03package org.freehep.graphicsio.ppm; // PpmEncoder - write out an image as a PPM // // Copyright (C)1996,1998 by Jef Poskanzer . All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. // // Visit the ACME Labs Java page for up-to-date versions of this and other // fine Java utilities: http://www.acme.com/java/ //package Acme.JPM.Encoders; import java.awt.Image; import java.awt.image.ImageProducer; import java.io.DataOutput; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; //import org.freehep.graphicsio.ImageEncoder; /// Write out an image as a PPM. //

// Writes an image onto a specified OutputStream in the PPM file format. //

// Fetch the software.
// Fetch the entire Acme package. //

// @see ToPpm public class PPMEncoder extends ImageEncoder { private List comments = new ArrayList(); // / Constructor. // @param img The image to encode. // @param out The stream to write the PPM to. public PPMEncoder(Image img, OutputStream out) throws IOException { super(img, new DataOutputStream(out)); } public PPMEncoder(Image img, DataOutput dos) throws IOException { super(img, dos); } // / Constructor. // @param prod The ImageProducer to encode. // @param out The stream to write the PPM to. public PPMEncoder(ImageProducer prod, OutputStream out) throws IOException { super(prod, new DataOutputStream(out)); } public PPMEncoder(ImageProducer prod, DataOutput dos) throws IOException { super(prod, dos); } public void addComment(String comment) { comments.add(comment); } protected void encodeStart(int width, int height) throws IOException { writeString("P6\n"); for (Iterator i = comments.iterator(); i.hasNext();) { String comment = (String) i.next(); writeString("# " + comment + "\n"); } writeString(width + " " + height + "\n"); writeString("255\n"); } void writeString(String str) throws IOException { byte[] buf = str.getBytes(); out.write(buf); } protected void encodePixels(int x, int y, int w, int h, int[] rgbPixels, int off, int scansize) throws IOException { byte[] ppmPixels = new byte[w * 3]; for (int row = 0; row < h; ++row) { int rowOff = off + row * scansize; for (int col = 0; col < w; ++col) { int i = rowOff + col; int j = col * 3; ppmPixels[j] = (byte) ((rgbPixels[i] & 0xff0000) >> 16); ppmPixels[j + 1] = (byte) ((rgbPixels[i] & 0x00ff00) >> 8); ppmPixels[j + 2] = (byte) (rgbPixels[i] & 0x0000ff); } out.write(ppmPixels); } } protected void encodeDone() throws IOException { // Nothing } } src/main/java/org/freehep/graphicsio/ImageParamConverter.java0000644000175000017500000000117611312401775023637 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio; import java.util.Properties; import javax.imageio.ImageWriteParam; /** * This interface is to be implemented by sub classes of ImageWriteParam to make * properties available to the ImageWriter as an ImageWriteParam object. * * @author Mark Donszelmann * @version $Id: ImageParamConverter.java 8585 2006-08-11 17:39:56Z duns $ */ public interface ImageParamConverter { /** * Returns a subclass of ImageWriteParam with all the instance variable set * according to the properties */ public ImageWriteParam getWriteParam(Properties properties); } src/main/java/org/freehep/graphicsio/MultiPageDocument.java0000644000175000017500000000160211312401775023324 0ustar user03user03package org.freehep.graphicsio; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.io.IOException; import org.freehep.graphics2d.TagString; public interface MultiPageDocument { public void setMultiPage(boolean isMultiPage); public boolean isMultiPage(); /** Set the headline of all pages. */ public void setHeader(Font font, TagString left, TagString center, TagString right, int underlineThickness); /** Set the footline of all pages. */ public void setFooter(Font font, TagString left, TagString center, TagString right, int underlineThickness); /** Start the next page */ public void openPage(Component component) throws IOException; public void openPage(Dimension size, String title) throws IOException; /** End the current page. */ public void closePage() throws IOException; }src/main/java/org/freehep/graphicsio/InfoConstants.java0000644000175000017500000000104011312401775022522 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio; /** * * @author Mark Donszelmann * @version $Id: InfoConstants.java 8584 2006-08-10 23:06:37Z duns $ */ public class InfoConstants { private InfoConstants() { } public static final String CREATOR = "Creator"; public static final String AUTHOR = "Author"; public static final String TITLE = "Title"; public static final String SUBJECT = "Subject"; public static final String KEYWORDS = "Keywords"; public static final String FOR = "For"; } src/main/java/org/freehep/graphicsio/AbstractVectorGraphicsIO.java0000644000175000017500000013256711312401775024614 0ustar user03user03// Copyright 2000-2007, FreeHEP package org.freehep.graphicsio; import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Component; import java.awt.Composite; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.GradientPaint; import java.awt.GraphicsConfiguration; import java.awt.Image; import java.awt.MediaTracker; import java.awt.Paint; import java.awt.Panel; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.Stroke; import java.awt.TexturePaint; import java.awt.Toolkit; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.font.TextLayout; import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.geom.GeneralPath; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; import java.awt.image.CropImageFilter; import java.awt.image.FilteredImageSource; import java.awt.image.ImageFilter; import java.awt.image.ImageObserver; import java.awt.image.RenderedImage; import java.awt.image.renderable.RenderContext; import java.awt.image.renderable.RenderableImage; import java.io.IOException; import java.text.AttributedCharacterIterator; import java.util.Arrays; import java.util.Map; import org.freehep.graphics2d.font.FontEncoder; import org.freehep.graphics2d.font.FontUtilities; import org.freehep.util.images.ImageUtilities; /** * This class provides an abstract VectorGraphicsIO class for specific output * drivers. * * @author Charles Loomis * @author Mark Donszelmann * @author Steffen Greiffenberg * @version $Id: AbstractVectorGraphicsIO.java 12625 2007-06-08 21:43:44Z duns $ */ public abstract class AbstractVectorGraphicsIO extends VectorGraphicsIO { private static final String rootKey = AbstractVectorGraphicsIO.class .getName(); public static final String EMIT_WARNINGS = rootKey + ".EMIT_WARNINGS"; public static final String TEXT_AS_SHAPES = rootKey + "." + FontConstants.TEXT_AS_SHAPES; public static final String EMIT_ERRORS = rootKey + ".EMIT_ERRORS"; public static final String CLIP = rootKey+".CLIP"; /* * ================================================================================ * Table of Contents: ------------------ 1. Constructors & Factory Methods * 2. Document Settings 3. Header, Trailer, Multipage & Comments 3.1 Header & * Trailer 3.2 MultipageDocument methods 4. Create & Dispose 5. Drawing * Methods 5.1. shapes (draw/fill) 5.1.1. lines, rectangles, round * rectangles 5.1.2. polylines, polygons 5.1.3. ovals, arcs 5.1.4. shapes * 5.2. Images 5.3. Strings 6. Transformations 7. Clipping 8. Graphics State / * Settings 8.1. stroke/linewidth 8.2. paint/color 8.3. font 8.4. rendering * hints 9. Auxiliary 10. Private/Utility Methods * ================================================================================ */ private Dimension size; private Component component; private boolean doRestoreOnDispose; private Rectangle deviceClip; /** * Untransformed clipping Area defined by the user */ private Area userClip; private AffineTransform currentTransform; // only for use in writeSetTransform to calculate the difference. private AffineTransform oldTransform = new AffineTransform(); private Composite currentComposite; private Stroke currentStroke; private RenderingHints hints; /* * ================================================================================ * 1. Constructors & Factory Methods * ================================================================================ */ /** * Constructs a Graphics context with the following graphics state: *

* * @param size rectangle specifying the bounds of the image * @param doRestoreOnDispose true if writeGraphicsRestore() should be called * when this graphics context is disposed of. */ protected AbstractVectorGraphicsIO(Dimension size, boolean doRestoreOnDispose) { super(); this.size = size; this.component = null; this.doRestoreOnDispose = doRestoreOnDispose; deviceClip = (size != null ? new Rectangle(0, 0, size.width, size.height) : null); userClip = null; currentTransform = new AffineTransform(); currentComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER); currentStroke = new BasicStroke(1.0f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f, null, 0.0f); super.setColor(Color.BLACK); super.setBackground(Color.BLACK); super.setFont(new Font("Dialog", Font.PLAIN, 12)); // Initialize the rendering hints. hints = new RenderingHints(null); } /** * Constructs a Graphics context with the following graphics state: * * * @param component to be used to initialize the values of the graphics * state * @param doRestoreOnDispose true if writeGraphicsRestore() should be called * when this graphics context is disposed of. */ protected AbstractVectorGraphicsIO(Component component, boolean doRestoreOnDispose) { super(); this.size = component.getSize(); this.component = component; this.doRestoreOnDispose = doRestoreOnDispose; deviceClip = (size != null ? new Rectangle(0, 0, size.width, size.height) : null); userClip = null; GraphicsConfiguration gc = component.getGraphicsConfiguration(); currentTransform = (gc != null) ? gc.getDefaultTransform() : new AffineTransform(); currentComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER); currentStroke = new BasicStroke(1.0f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f, null, 0.0f); super.setFont(component.getFont()); super.setBackground(component.getBackground()); super.setColor(component.getForeground()); // Initialize the rendering hints. hints = new RenderingHints(null); } /** * Constructs a subgraphics context. * * @param graphics context to clone from * @param doRestoreOnDispose true if writeGraphicsRestore() should be called * when this graphics context is disposed of. */ protected AbstractVectorGraphicsIO(AbstractVectorGraphicsIO graphics, boolean doRestoreOnDispose) { super(graphics); this.doRestoreOnDispose = doRestoreOnDispose; size = new Dimension(graphics.size); component = graphics.component; deviceClip = new Rectangle(graphics.deviceClip); userClip = (graphics.userClip != null) ? new Area(graphics.userClip) : null; currentTransform = new AffineTransform(graphics.currentTransform); currentComposite = graphics.currentComposite; currentStroke = graphics.currentStroke; hints = graphics.hints; } /* * ================================================================================ | * 2. Document Settings * ================================================================================ */ public Dimension getSize() { return size; } public Component getComponent() { return component; } /* * ================================================================================ | * 3. Header, Trailer, Multipage & Comments * ================================================================================ */ /* 3.1 Header & Trailer */ public void startExport() { try { writeHeader(); // delegate this to openPage if it is a MultiPage document if (!(this instanceof MultiPageDocument)) { writeGraphicsState(); writeBackground(); } } catch (IOException e) { handleException(e); } } public void endExport() { try { dispose(); writeTrailer(); closeStream(); } catch (IOException e) { handleException(e); } } /** * Called to write the header part of the output. */ public abstract void writeHeader() throws IOException; /** * Called to write the initial graphics state. */ public void writeGraphicsState() throws IOException { writePaint(getPrintColor(getColor())); writeSetTransform(getTransform()); // writeStroke(getStroke()); setClip(getClip()); // Silly assignment, Font is written when String is drawed and "extra" writeFont does not exist // setFont(getFont()); // Silly assignment and "extra" writeComposite does not exist // setComposite(getComposite); } public abstract void writeBackground() throws IOException; /** * Called to write the trailing part of the output. */ public abstract void writeTrailer() throws IOException; /** * Called to close the stream you are writing to. */ public abstract void closeStream() throws IOException; public void printComment(String comment) { try { writeComment(comment); } catch (IOException e) { handleException(e); } } /** * Called to Write out a comment. * * @param comment to be written */ public abstract void writeComment(String comment) throws IOException; /* 3.2 MultipageDocument methods */ protected void resetClip(Rectangle clip) { deviceClip = clip; userClip = null; } /* * ================================================================================ * 4. Create & Dispose * ================================================================================ */ /** * Disposes of the graphics context. If on creation restoreOnDispose was * true, writeGraphicsRestore() will be called. */ public void dispose() { try { // Swing sometimes calls dispose several times for a given // graphics object. Ensure that the grestore is only written // once if this happens. if (doRestoreOnDispose) { writeGraphicsRestore(); doRestoreOnDispose = false; } } catch (IOException e) { handleException(e); } } /** * Writes out the save of a graphics context for a later restore. Some * implementations keep track of this by hand if the output format does not * support it. */ protected abstract void writeGraphicsSave() throws IOException; /** * Writes out the restore of a graphics context. Some implementations keep * track of this by hand if the output format does not support it. */ protected abstract void writeGraphicsRestore() throws IOException; /* * ================================================================================ | * 5. Drawing Methods * ================================================================================ */ /* 5.3. Images */ public boolean drawImage(Image image, int x, int y, ImageObserver observer) { int imageWidth = image.getWidth(observer); int imageHeight = image.getHeight(observer); return drawImage(image, x, y, x + imageWidth, y + imageHeight, 0, 0, imageWidth, imageHeight, null, observer); } public boolean drawImage(Image image, int x, int y, int width, int height, ImageObserver observer) { int imageWidth = image.getWidth(observer); int imageHeight = image.getHeight(observer); return drawImage(image, x, y, x + width, y + height, 0, 0, imageWidth, imageHeight, null, observer); } public boolean drawImage(Image image, int x, int y, int width, int height, Color bgColor, ImageObserver observer) { int imageWidth = image.getWidth(observer); int imageHeight = image.getHeight(observer); return drawImage(image, x, y, x + width, y + height, 0, 0, imageWidth, imageHeight, bgColor, observer); } public boolean drawImage(Image image, int x, int y, Color bgColor, ImageObserver observer) { int imageWidth = image.getWidth(observer); int imageHeight = image.getHeight(observer); return drawImage(image, x, y, x + imageWidth, y + imageHeight, 0, 0, imageWidth, imageHeight, bgColor, observer); } public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) { return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, observer); } public boolean drawImage(Image image, AffineTransform xform, ImageObserver observer) { drawRenderedImage(ImageUtilities.createRenderedImage(image, observer, null), xform); return true; } public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { drawImage(op.filter(img, null), x, y, null); } // NOTE: not tested yet!!! public void drawRenderableImage(RenderableImage image, AffineTransform xform) { drawRenderedImage(image.createRendering(new RenderContext( new AffineTransform(), getRenderingHints())), xform); } /** * Draw and resizes (transparent) image. Calls writeImage(...). * * @param image image to be drawn * @param dx1 destination image bounds * @param dy1 destination image bounds * @param dx2 destination image bounds * @param dy2 destination image bounds * @param sx1 source image bounds * @param sy1 source image bounds * @param sx2 source image bounds * @param sy2 source image bounds * @param bgColor background color * @param observer for updates if image still incomplete * @return true if successful */ public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgColor, ImageObserver observer) { try { int srcX = Math.min(sx1, sx2); int srcY = Math.min(sy1, sy2); int srcWidth = Math.abs(sx2 - sx1); int srcHeight = Math.abs(sy2 - sy1); int width = Math.abs(dx2 - dx1); int height = Math.abs(dy2 - dy1); if ((srcX != 0) || (srcY != 0) || (srcWidth != image.getWidth(observer)) || (srcHeight != image.getHeight(observer))) { // crop the source image ImageFilter crop = new CropImageFilter(srcX, srcY, srcWidth, srcHeight); image = Toolkit.getDefaultToolkit().createImage( new FilteredImageSource(image.getSource(), crop)); MediaTracker mediaTracker = new MediaTracker(new Panel()); mediaTracker.addImage(image, 0); try { mediaTracker.waitForAll(); } catch (InterruptedException e) { handleException(e); } } boolean flipHorizontal = (dx2 < dx1) ^ (sx2 < sx1); // src flipped // and not dest // flipped or // vice versa boolean flipVertical = (dy2 < dy1) ^ (sy2 < sy1); // <=> source // flipped XOR // dest flipped double tx = (flipHorizontal) ? (double) dx2 : (double) dx1; double ty = (flipVertical) ? (double) dy2 : (double) dy1; double sx = (double) width / srcWidth; sx = flipHorizontal ? -1 * sx : sx; double sy = (double) height / srcHeight; sy = flipVertical ? -1 * sy : sy; writeImage(ImageUtilities.createRenderedImage(image, observer, bgColor), new AffineTransform(sx, 0, 0, sy, tx, ty), bgColor); return true; } catch (IOException e) { handleException(e); return false; } } /* * // first use the original orientation int clippingWidth = Math.abs(sx2 - * sx1); int clippingHeight = Math.abs(sy2 - sy1); int sulX = Math.min(sx1, * sx2); int sulY = Math.min(sy1, sy2); Image background = null; if (bgColor != * null) { // Draw the image on the background color // maybe we could crop * it and fill the transparent pixels in one go // by means of a filter. * background = new BufferedImage(clippingWidth, clippingHeight, * BufferedImage.TYPE_INT_ARGB); Graphics bgGfx = background.getGraphics(); * bgGfx.drawImage(image, 0, 0, clippingWidth, clippingWidth, sulX, sulY, * sulX+clippingWidth, sulY+clippingHeight, getPrintColor(bgColor), * observer); } else { // crop the source image ImageFilter crop = new * CropImageFilter(sulX, sulY, clippingWidth, clippingHeight); background = * Toolkit.getDefaultToolkit().createImage(new * FilteredImageSource(image.getSource(), crop)); MediaTracker mediaTracker = * new MediaTracker(new Panel()); mediaTracker.addImage(background, 0); try { * mediaTracker.waitForAll(); } catch (InterruptedException e) { * handleException(e); } } // now flip the image if necessary boolean * flipHorizontal = (dx2 source flipped XOR dest flipped int destWidth = Math.abs(dx2-dx1); * int destHeight = Math.abs(dy2-dy1); try { return writeImage(background, * flipHorizontal ? dx2 : dx1, flipVertical ? dy2 : dy1, flipHorizontal ? * -destWidth : destWidth, flipVertical ? -destHeight : destHeight, (bgColor == * null), observer); } catch (IOException e) { return false; } } */ /** * Draws a rendered image using a transform. * * @param image to be drawn * @param xform transform to be used on the image */ public void drawRenderedImage(RenderedImage image, AffineTransform xform) { try { writeImage(image, xform, null); } catch (Exception e) { handleException(e); } } protected abstract void writeImage(RenderedImage image, AffineTransform xform, Color bkg) throws IOException; /** * Clears rectangle by painting it with the backgroundColor. * * @param x rectangle to be cleared. * @param y rectangle to be cleared. * @param width rectangle to be cleared. * @param height rectangle to be cleared. */ public void clearRect(double x, double y, double width, double height) { Paint temp = getPaint(); setPaint(getBackground()); fillRect(x, y, width, height); setPaint(temp); } /** * Draws the string at (x, y). If TEXT_AS_SHAPES is set * {@link #drawGlyphVector(java.awt.font.GlyphVector, float, float)} is used, otherwise * {@link #writeString(String, double, double)} for a more direct output of the string. * * @param string * @param x * @param y */ public void drawString(String string, double x, double y) { // something to draw? if (string == null || string.equals("")) { return; } // draw strings directly? if (isProperty(TEXT_AS_SHAPES)) { Font font = getFont(); // NOTE, see FVG-199, createGlyphVector does not seem to create the proper glyphcodes // for either ZapfDingbats or Symbol. We use our own encoding which seems to work... String fontName = font.getName(); if (fontName.equals("Symbol") || fontName.equals("ZapfDingbats")) { string = FontEncoder.getEncodedString(string, fontName); // use a standard font, not Symbol. font = new Font("Serif", font.getStyle(), font.getSize()); } // create glyph GlyphVector gv = font.createGlyphVector(getFontRenderContext(), string); // draw it drawGlyphVector(gv, (float) x, (float) y); } else { // write string directly try { writeString(string, x, y); } catch (IOException e) { handleException(e); } } } protected abstract void writeString(String string, double x, double y) throws IOException; /** * Use the transformation of the glyphvector and draw it * * @param g * @param x * @param y */ public void drawGlyphVector(GlyphVector g, float x, float y) { fill(g.getOutline(x, y)); } public void drawString(AttributedCharacterIterator iterator, float x, float y) { // TextLayout draws the iterator as glyph vector // thats why we use it only in the case of TEXT_AS_SHAPES, // otherwise tagged strings are always written as glyphs if (isProperty(TEXT_AS_SHAPES)) { // draws all attributes TextLayout tl = new TextLayout(iterator, getFontRenderContext()); tl.draw(this, x, y); } else { // reset to that font at the end Font font = getFont(); // initial attributes, we us TextAttribute.equals() rather // than Font.equals() because using Font.equals() we do // not get a 'false' if underline etc. is changed Map/**/ attributes = FontUtilities.getAttributes(font); // stores all characters which are written with the same font // if font is changed the buffer will be written and cleared // after it StringBuffer sb = new StringBuffer(); for (char c = iterator.first(); c != AttributedCharacterIterator.DONE; c = iterator.next()) { // append c if font is not changed if (attributes.equals(iterator.getAttributes())) { sb.append(c); } else { // TextLayout does not like 0 length strings if (sb.length() > 0) { // draw sb if font is changed drawString(sb.toString(), x, y); // change the x offset for the next drawing // FIXME: change y offset for vertical text TextLayout tl = new TextLayout( sb.toString(), attributes, getFontRenderContext()); // calculate real width x = x + Math.max( tl.getAdvance(), (float)tl.getBounds().getWidth()); } // empty sb sb = new StringBuffer(); sb.append(c); // change the font attributes = iterator.getAttributes(); setFont(new Font(attributes)); } } // draw the rest if (sb.length() > 0) { drawString(sb.toString(), x, y); } // use the old font for the next string drawing setFont(font); } } /* * ================================================================================ | * 6. Transformations * ================================================================================ */ /** * Get the current transform. * * @return current transform */ public AffineTransform getTransform() { return new AffineTransform(currentTransform); } /** * Set the current transform. Calls writeSetTransform(Transform). * * @param transform to be set */ public void setTransform(AffineTransform transform) { // Fix for FREEHEP-569 oldTransform.setTransform(currentTransform); currentTransform.setTransform(transform); try { writeSetTransform(transform); } catch (IOException e) { handleException(e); } } /** * Transforms the current transform. Calls writeTransform(Transform) * * @param transform to be applied */ public void transform(AffineTransform transform) { currentTransform.concatenate(transform); try { writeTransform(transform); } catch (IOException e) { handleException(e); } } /** * Translates the current transform. Calls writeTransform(Transform) * * @param x amount by which to translate * @param y amount by which to translate */ public void translate(double x, double y) { currentTransform.translate(x, y); try { writeTransform(new AffineTransform(1, 0, 0, 1, x, y)); } catch (IOException e) { handleException(e); } } /** * Rotate the current transform over the Z-axis. Calls * writeTransform(Transform). Rotating with a positive angle theta rotates * points on the positive x axis toward the positive y axis. * * @param theta radians over which to rotate */ public void rotate(double theta) { currentTransform.rotate(theta); try { writeTransform(new AffineTransform(Math.cos(theta), Math.sin(theta), -Math.sin(theta), Math.cos(theta), 0, 0)); } catch (IOException e) { handleException(e); } } /** * Scales the current transform. Calls writeTransform(Transform). * * @param sx amount used for scaling * @param sy amount used for scaling */ public void scale(double sx, double sy) { currentTransform.scale(sx, sy); try { writeTransform(new AffineTransform(sx, 0, 0, sy, 0, 0)); } catch (IOException e) { handleException(e); } } /** * Shears the current transform. Calls writeTransform(Transform). * * @param shx amount for shearing * @param shy amount for shearing */ public void shear(double shx, double shy) { currentTransform.shear(shx, shy); try { writeTransform(new AffineTransform(1, shy, shx, 1, 0, 0)); } catch (IOException e) { handleException(e); } } /** * Writes out the transform as it needs to be concatenated to the internal * transform of the output format. If there is no implementation of an * internal transform, then this method needs to do nothing, BUT all * coordinates need to be transformed by the currentTransform before being * written out. * * @param transform to be written */ protected abstract void writeTransform(AffineTransform transform) throws IOException; /** * Clears any existing transformation and sets the a new one. * The default implementation calls writeTransform using the * inverted affine transform to calculate it. s * * @param transform to be written */ protected void writeSetTransform(AffineTransform transform) throws IOException { try { AffineTransform deltaTransform = new AffineTransform(transform); deltaTransform.concatenate(oldTransform.createInverse()); writeTransform(deltaTransform); } catch (NoninvertibleTransformException e) { // ignored... System.err.println("Warning: (ignored) Could not invert matrix: "+oldTransform); } } /* * ================================================================================ | * 7. Clipping * ================================================================================ */ /** * Gets the current clip in form of a Shape (Rectangle). * * @return current clip */ public Shape getClip() { return (userClip != null) ? new Area(untransformShape(userClip)) : null; } /** * Gets the current clip in form of a Rectangle. * * @return current clip */ public Rectangle getClipBounds() { Shape clip = getClip(); return (clip != null) ? getClip().getBounds() : null; } /** * Gets the current clip in form of a Rectangle. * * @return current clip */ public Rectangle getClipBounds(Rectangle r) { Rectangle bounds = getClipBounds(); if (bounds != null) r.setBounds(bounds); return r; } /** * Clips rectangle. Calls clip(Rectangle). * * @param x rectangle for clipping * @param y rectangle for clipping * @param width rectangle for clipping * @param height rectangle for clipping */ public void clipRect(int x, int y, int width, int height) { clip(new Rectangle(x, y, width, height)); } /** * Clips rectangle. Calls clip(Rectangle2D). * * @param x rectangle for clipping * @param y rectangle for clipping * @param width rectangle for clipping * @param height rectangle for clipping */ public void clipRect(double x, double y, double width, double height) { clip(new Rectangle2D.Double(x, y, width, height)); } /** * Clips rectangle. Calls clip(Rectangle). * * @param x rectangle for clipping * @param y rectangle for clipping * @param width rectangle for clipping * @param height rectangle for clipping */ public void setClip(int x, int y, int width, int height) { setClip(new Rectangle(x, y, width, height)); } /** * Clips rectangle. Calls clip(Rectangle2D). * * @param x rectangle for clipping * @param y rectangle for clipping * @param width rectangle for clipping * @param height rectangle for clipping */ public void setClip(double x, double y, double width, double height) { setClip(new Rectangle2D.Double(x, y, width, height)); } /** * Clips shape. Clears userClip and calls clip(Shape). * * @param s used for clipping */ public void setClip(Shape s) { Shape ts = transformShape(s); userClip = (ts != null) ? new Area(ts) : null; try { writeSetClip(s); } catch (IOException e) { handleException(e); } } /** * Clips using given shape. Dispatches to writeClip(Rectangle), * writeClip(Rectangle2D) or writeClip(Shape). * * @param s used for clipping */ public void clip(Shape s) { Shape ts = transformShape(s); if (userClip != null) { if (ts != null) { userClip.intersect(new Area(ts)); } else { userClip = null; } } else { userClip = (ts != null) ? new Area(ts) : null; } try { writeClip(s); } catch (IOException e) { handleException(e); } } /** * Write out Shape clip. * * @param shape to be used for clipping */ protected abstract void writeClip(Shape shape) throws IOException; /** * Write out Shape clip. * * @param shape to be used for clipping */ protected abstract void writeSetClip(Shape shape) throws IOException; /* * ================================================================================ | * 8. Graphics State * ================================================================================ */ /* 8.1. stroke/linewidth */ /** * Get the current stroke. * * @return current stroke */ public Stroke getStroke() { return currentStroke; } /** * Sets the current stroke. Calls writeStroke if stroke is unequal to the * current stroke. * * @param stroke to be set */ public void setStroke(Stroke stroke) { if (stroke.equals(currentStroke)) { return; } try { writeStroke(stroke); } catch (IOException e) { handleException(e); } currentStroke = stroke; } /** * Writes the current stroke. If stroke is an instance of BasicStroke it * will call writeWidth, writeCap, writeJoin, writeMiterLimit and writeDash, * if any were different than the current stroke. */ protected void writeStroke(Stroke stroke) throws IOException { if (stroke instanceof BasicStroke) { BasicStroke ns = (BasicStroke) stroke; // get the current values for comparison if available, // otherwise set them to -1="undefined" int currentCap = -1, currentJoin = -1; float currentWidth = -1, currentLimit = -1, currentDashPhase = -1; float[] currentDashArray = null; if ((currentStroke != null) && (currentStroke instanceof BasicStroke)) { BasicStroke cs = (BasicStroke) currentStroke; currentCap = cs.getEndCap(); currentJoin = cs.getLineJoin(); currentWidth = cs.getLineWidth(); currentLimit = cs.getMiterLimit(); currentDashArray = cs.getDashArray(); currentDashPhase = cs.getDashPhase(); } // Check the linewidth. float width = ns.getLineWidth(); if (currentWidth != width) { writeWidth(width); } // Check the line caps. int cap = ns.getEndCap(); if (currentCap != cap) { writeCap(cap); } // Check the line joins. int join = ns.getLineJoin(); if (currentJoin != join) { writeJoin(join); } // Check the miter limit and validity of value float limit = ns.getMiterLimit(); if ((currentLimit != limit) && (limit >= 1.0f)) { writeMiterLimit(limit); } // Check to see if there are differences in the phase or dash if(!Arrays.equals(currentDashArray, ns.getDashArray()) || (currentDashPhase != ns.getDashPhase())) { // write the dashing parameters if (ns.getDashArray() != null) { writeDash(ns.getDashArray(), ns.getDashPhase()); } else { writeDash(new float[0], ns.getDashPhase()); } } } } /** * Writes out the width of the stroke. * * @param width of the stroke */ protected void writeWidth(float width) throws IOException { writeWarning(getClass() + ": writeWidth() not implemented."); } /** * Writes out the cap of the stroke. * * @param cap of the stroke */ protected void writeCap(int cap) throws IOException { writeWarning(getClass() + ": writeCap() not implemented."); } /** * Writes out the join of the stroke. * * @param join of the stroke */ protected void writeJoin(int join) throws IOException { writeWarning(getClass() + ": writeJoin() not implemented."); } /** * Writes out the miter limit of the stroke. * * @param limit miter limit of the stroke */ protected void writeMiterLimit(float limit) throws IOException { writeWarning(getClass() + ": writeMiterLimit() not implemented."); } /** * Writes out the dash of the stroke. * * @param dash dash pattern, empty array is solid line * @param phase of the dash pattern */ protected void writeDash(float[] dash, float phase) throws IOException { // for backward compatibility double[] dd = new double[dash.length]; for (int i = 0; i < dash.length; i++) { dd[i] = dash[i]; } writeDash(dd, (double)phase); } /** * Writes out the dash of the stroke. * @deprecated use writeDash(float[], float) * @param dash dash pattern, empty array is solid line * @param phase of the dash pattern */ protected void writeDash(double[] dash, double phase) throws IOException { writeWarning(getClass() + ": writeDash() not implemented."); } /* 8.2 Paint */ public void setColor(Color color) { if (color == null) return; if (color.equals(getColor())) return; try { super.setColor(color); writePaint(getPrintColor(color)); } catch (IOException e) { handleException(e); } } /** * Sets the current paint. Dispatches to writePaint(Color), * writePaint(GradientPaint), writePaint(TexturePaint paint) or * writePaint(Paint). In the case paint is a Color the current color is also * changed. * * @param paint to be set */ public void setPaint(Paint paint) { if (paint == null) return; if (paint.equals(getPaint())) return; try { if (paint instanceof Color) { setColor((Color) paint); } else if (paint instanceof GradientPaint) { super.setPaint(paint); writePaint((GradientPaint) paint); } else if (paint instanceof TexturePaint) { super.setPaint(paint); writePaint((TexturePaint) paint); } else { super.setPaint(paint); writePaint(paint); } } catch (IOException e) { handleException(e); } } /** * Writes out paint as the given color. * * @param color to be written */ protected abstract void writePaint(Color color) throws IOException; /** * Writes out paint as the given gradient. * * @param paint to be written */ protected abstract void writePaint(GradientPaint paint) throws IOException; /** * Writes out paint as the given texture. * * @param paint to be written */ protected abstract void writePaint(TexturePaint paint) throws IOException; /** * Writes out paint. * * @param paint to be written */ protected abstract void writePaint(Paint paint) throws IOException; /* 8.3. font */ /** * Gets the current font render context. This returns an standard * FontRenderContext with anti-aliasing and uses * fractional metrics. * * @return current font render context */ public FontRenderContext getFontRenderContext() { // NOTE: not sure? // Fixed for VG-285 return new FontRenderContext(new AffineTransform(1, 0, 0, 1, 0, 0), true, true); } /** * Gets the fontmetrics. * * @deprecated * @param font to be used for retrieving fontmetrics * @return fontmetrics for given font */ public FontMetrics getFontMetrics(Font font) { return Toolkit.getDefaultToolkit().getFontMetrics(font); } /* 8.4. rendering hints */ /** * Gets a copy of the rendering hints. * * @return clone of table of rendering hints. */ public RenderingHints getRenderingHints() { return (RenderingHints) hints.clone(); } /** * Adds to table of rendering hints. * * @param hints table to be added */ public void addRenderingHints(Map hints) { hints.putAll(hints); } /** * Sets table of rendering hints. * * @param hints table to be set */ public void setRenderingHints(Map hints) { hints.clear(); hints.putAll(hints); } /** * Gets a given rendering hint. * * @param key hint key * @return hint associated to key */ public Object getRenderingHint(RenderingHints.Key key) { return hints.get(key); } /** * Sets a given rendering hint. * * @param key hint key * @param hint to be associated with key */ public void setRenderingHint(RenderingHints.Key key, Object hint) { // extra protection, failed on under MacOS X 10.2.6, jdk 1.4.1_01-39/14 if ((key == null) || (hint == null)) return; hints.put(key, hint); } /** * Sets the current font. * * @param font to be set */ public void setFont(Font font) { if (font == null) return; // FIXME: maybe add delayed setting super.setFont(font); // write the font try { writeFont(font); } catch (IOException e) { handleException(e); } } /** * Writes the font * * @param font to be written */ protected abstract void writeFont(Font font) throws IOException; /* * ================================================================================ | * 9. Auxiliary * ================================================================================ */ /** * Gets current composite. * * @return current composite */ public Composite getComposite() { return currentComposite; } /** * Sets current composite. * * @param composite to be set */ public void setComposite(Composite composite) { currentComposite = composite; } /** * Handles an exception which has been caught. Dispatches exception to * writeWarning for UnsupportedOperationExceptions and writeError for others * * @param exception to be handled */ protected void handleException(Exception exception) { if (exception instanceof UnsupportedOperationException) { writeWarning(exception); } else { writeError(exception); } } /** * Writes out a warning, by default to System.err. * * @param exception warning to be written */ protected void writeWarning(Exception exception) { writeWarning(exception.getMessage()); } /** * Writes out a warning, by default to System.err. * * @param warning to be written */ protected void writeWarning(String warning) { if (isProperty(EMIT_WARNINGS)) { System.err.println(warning); } } /** * Writes out an error, by default the stack trace is printed. * * @param exception error to be reported */ protected void writeError(Exception exception) { throw new RuntimeException(exception); // FIXME decide what we should do /* * if (isProperty(EMIT_ERRORS)) { System.err.println(exception); * exception.printStackTrace(System.err); } */ } protected Shape createShape(double[] xPoints, double[] yPoints, int nPoints, boolean close) { GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); if (nPoints > 0) { path.moveTo((float) xPoints[0], (float) yPoints[0]); for (int i = 1; i < nPoints; i++) { path.lineTo((float) xPoints[i], (float) yPoints[i]); } if (close) path.closePath(); } return path; } private Shape transformShape(AffineTransform at, Shape s) { if (s == null) return null; return at.createTransformedShape(s); } private Shape transformShape(Shape s) { return transformShape(getTransform(), s); } private Shape untransformShape(Shape s) { if (s == null) return null; try { return transformShape(getTransform().createInverse(), s); } catch (NoninvertibleTransformException e) { return null; } } /** * Draws an overline for the text at (x, y). The method is usesefull for * drivers that do not support overlines by itself. * * @param text text for width calulation * @param font font for width calulation * @param x position of text * @param y position of text */ protected void overLine(String text, Font font, float x, float y) { TextLayout layout = new TextLayout(text, font, getFontRenderContext()); float width = Math.max( layout.getAdvance(), (float) layout.getBounds().getWidth()); GeneralPath path = new GeneralPath(); path.moveTo(x, y + (float) layout.getBounds().getY() - layout.getAscent()); path.lineTo(x + width, y + (float) layout.getBounds().getY() - layout.getAscent() - layout.getAscent()); draw(path); } } src/main/java/org/freehep/graphicsio/ImageGraphics2D.java0000644000175000017500000005120311312401775022631 0ustar user03user03// Copyright 2003-2007, FreeHEP. package org.freehep.graphicsio; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.GraphicsConfiguration; import java.awt.Image; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.ByteArrayOutputStream; import java.util.Arrays; import java.util.Comparator; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Properties; import java.util.SortedSet; import java.util.TreeSet; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageOutputStream; import org.freehep.graphics2d.PixelGraphics2D; import org.freehep.util.UserProperties; import org.freehep.util.io.ASCII85OutputStream; import org.freehep.util.io.FlateOutputStream; import org.freehep.util.images.ImageUtilities; import org.freehep.graphicsio.raw.RawImageWriteParam; /** * Generic class for generating bitmap outputs from an image. * * @author Mark Donszelmann * @version $Id: ImageGraphics2D.java 10273 2007-01-09 19:01:32Z duns $ */ public class ImageGraphics2D extends PixelGraphics2D { private final static String alwaysCompressedFormats[] = { ImageConstants.JPG.toLowerCase(), ImageConstants.JPEG.toLowerCase(), ImageConstants.GIF.toLowerCase()}; private final static String nonTransparentFormats[] = { ImageConstants.JPG.toLowerCase(), ImageConstants.JPEG.toLowerCase(), ImageConstants.PPM.toLowerCase()}; public static final String rootKey = "org.freehep.graphicsio"; // our general properties public static final String TRANSPARENT = "." + PageConstants.TRANSPARENT; public static final String BACKGROUND = "." + PageConstants.BACKGROUND; public static final String BACKGROUND_COLOR = "." + PageConstants.BACKGROUND_COLOR; // our image properties public static final String ANTIALIAS = ".Antialias"; public static final String ANTIALIAS_TEXT = ".AntialiasText"; // standard image properties public static final String PROGRESSIVE = ".Progressive"; public static final String COMPRESS = ".Compress"; public static final String COMPRESS_MODE = ".CompressMode"; public static final String COMPRESS_DESCRIPTION = ".CompressDescription"; public static final String COMPRESS_QUALITY = ".CompressQuality"; private static final Map /* UserProperties */defaultProperties = new HashMap(); public static Properties getDefaultProperties(String format) { UserProperties properties = (UserProperties) defaultProperties .get(format); if (properties == null) { properties = new UserProperties(); defaultProperties.put(format, properties); String formatKey = rootKey + "." + format; // set our parameters if (canWriteTransparent(format)) { properties.setProperty(formatKey + TRANSPARENT, true); properties.setProperty(formatKey + BACKGROUND, false); properties .setProperty(formatKey + BACKGROUND_COLOR, Color.GRAY); } else { properties.setProperty(formatKey + BACKGROUND, false); properties .setProperty(formatKey + BACKGROUND_COLOR, Color.GRAY); } // set our parameters properties.setProperty(formatKey + ANTIALIAS, true); properties.setProperty(formatKey + ANTIALIAS_TEXT, true); // copy parameters from specific format ImageWriter writer = getPreferredImageWriter(format); if (writer != null) { ImageWriteParam param = writer.getDefaultWriteParam(); // compression if (param.canWriteCompressed()) { param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); properties.setProperty(formatKey + COMPRESS, true); String[] compressionTypes = param.getCompressionTypes(); String compressionType = param.getCompressionType(); properties.setProperty(formatKey + COMPRESS_MODE, compressionType != null ? compressionType : compressionTypes[0]); properties.setProperty(formatKey + COMPRESS_DESCRIPTION, "Custom"); float compressionQuality = 0.0f; try { compressionQuality = param.getCompressionQuality(); } catch (IllegalStateException e) { // ignored } properties.setProperty(formatKey + COMPRESS_QUALITY, compressionQuality); } else { properties.setProperty(formatKey + COMPRESS, false); properties.setProperty(formatKey + COMPRESS_MODE, ""); properties.setProperty(formatKey + COMPRESS_DESCRIPTION, "Custom"); properties.setProperty(formatKey + COMPRESS_QUALITY, 0.0f); } // progressive if (param.canWriteProgressive()) { properties .setProperty( formatKey + PROGRESSIVE, param.getProgressiveMode() != ImageWriteParam.MODE_DISABLED); } else { properties.setProperty(formatKey + PROGRESSIVE, false); } } else { System.err.println(ImageGraphics2D.class + ": No writer for format '" + format + "'."); } } return properties; } public void setProperties(Properties newProperties) { if (newProperties == null) return; String formatKey = rootKey + "." + format; Properties formatProperties = new Properties(); for (Enumeration e = newProperties.propertyNames(); e.hasMoreElements();) { String key = (String) e.nextElement(); String value = newProperties.getProperty(key); if (key.indexOf("." + format) < 0) { key = formatKey + key; } formatProperties.setProperty(key, value); } super.setProperties(formatProperties); setPropertiesOnGraphics(); } private void setPropertiesOnGraphics() { String formatKey = rootKey + "." + format; if (isProperty(formatKey + ANTIALIAS)) { setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } else { setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); } if (isProperty(formatKey + ANTIALIAS_TEXT)) { setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); } else { setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); } if (isProperty(formatKey + TRANSPARENT)) { setBackground(null); } else if (isProperty(formatKey + BACKGROUND)) { setBackground(getPropertyColor(formatKey + BACKGROUND_COLOR)); } else { setBackground(component != null ? component.getBackground() : Color.WHITE); } } private void setHintsOnGraphics() { if (format.equalsIgnoreCase(ImageConstants.JPG)) { // since we draw JPG on non-transparent background, we cannot blit // compatible images setRenderingHint(KEY_SYMBOL_BLIT, VALUE_SYMBOL_BLIT_OFF); } else { setRenderingHint(KEY_SYMBOL_BLIT, VALUE_SYMBOL_BLIT_ON); } } protected OutputStream os; protected BufferedImage image; protected String format; protected Component component; public ImageGraphics2D(File file, Dimension size, String format) throws FileNotFoundException { this(new FileOutputStream(file), size, format); } public ImageGraphics2D(File file, Component component, String format) throws FileNotFoundException { this(new FileOutputStream(file), component, format); } public ImageGraphics2D(OutputStream os, Dimension size, String format) { super(); init(os, size, format); component = null; } public ImageGraphics2D(OutputStream os, Component component, String format) { super(); this.component = component; init(os, component.getSize(), format); setColor(component.getForeground()); GraphicsConfiguration gc = component.getGraphicsConfiguration(); if (gc != null) setTransform(gc.getDefaultTransform()); } private void init(OutputStream os, Dimension size, String format) { this.os = os; this.format = format; initProperties(getDefaultProperties(format)); // create actual graphics image = createBufferedImage(format, size.width, size.height); setHostGraphics(image.getGraphics()); // set graphics properties setPropertiesOnGraphics(); // set graphics hints setHintsOnGraphics(); // Ensure that a clipping path is set on this graphics // context. This avoids a null pointer exception inside of // a JLayeredPane when printing. hostGraphics.clipRect(0, 0, size.width, size.height); } protected ImageGraphics2D(ImageGraphics2D graphics) { super(graphics); image = graphics.image; os = graphics.os; format = graphics.format; // make sure all hints are copied. setHintsOnGraphics(); } public Graphics create() { return new ImageGraphics2D(this); } public Graphics create(double x, double y, double width, double height) { ImageGraphics2D imageGraphics = new ImageGraphics2D(this); imageGraphics.translate(x, y); imageGraphics.clipRect(0, 0, width, height); return imageGraphics; } public void startExport() { if (getBackground() != null) { clearRect(0.0, 0.0, image.getWidth(), image.getHeight()); } } public void endExport() { try { write(); closeStream(); } catch (IOException e) { handleException(e); } } protected void write() throws IOException { writeImage((RenderedImage) image, format, getProperties(), os); } public void closeStream() throws IOException { os.close(); } /** * Handles an exception which has been caught. Dispatches exception to * writeWarning for UnsupportedOperationExceptions and writeError for others * * @param exception to be handled */ protected void handleException(Exception exception) { System.err.println(exception); } /** * creates an empty image * * @param format e.g. {@link ImageConstants#BMP} or {ImageConstants#PNG} * @param width image width * @param height image height * @return offscreen buffered image */ public static BufferedImage createBufferedImage( String format, int width, int height) { // NOTE: special case for WBMP which only // supports on color band with sample size 1 // (which means black / white with no gray scale) if (ImageConstants.WBMP.equalsIgnoreCase(format)) { return new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY); } // NOTE: special case for JPEG which has no Alpha if (ImageConstants.JPG.equalsIgnoreCase(format)) { return new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); } // NOTE: special case for BMP which has no Alpha if (ImageConstants.BMP.equalsIgnoreCase(format)) { return new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); } return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); } public static BufferedImage generateThumbnail(Component component, Dimension size) { int longSide = Math.max(size.width, size.height); if (longSide < 0) return null; int componentWidth = component.getBounds().width; int componentHeight = component.getBounds().height; BufferedImage image = new BufferedImage(componentWidth, componentHeight, BufferedImage.TYPE_INT_ARGB); Graphics imageGraphics = image.getGraphics(); component.print(imageGraphics); int width = longSide; int height = longSide; if (componentWidth < componentHeight) { width = componentWidth * size.height / componentHeight; } else { height = componentHeight * size.width / componentWidth; } BufferedImage scaled = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics scaledGraphics = scaled.getGraphics(); scaledGraphics.drawImage(image, 0, 0, width, height, null); return scaled; } public static void writeImage(Image image, String format, Properties properties, OutputStream os) throws IOException { // FIXME hardcoded background writeImage( ImageUtilities.createRenderedImage(image, null, Color.black), format, properties, os); } public static void writeImage(RenderedImage image, String format, Properties properties, OutputStream os) throws IOException { ImageWriter writer = getPreferredImageWriter(format); if (writer == null) throw new IOException(ImageGraphics2D.class + ": No writer for format '" + format + "'."); // get the parameters for this format UserProperties user = new UserProperties(properties); ImageWriteParam param = writer.getDefaultWriteParam(); if (param instanceof ImageParamConverter) { param = ((ImageParamConverter) param).getWriteParam(user); } // now set the standard write parameters String formatKey = rootKey + "." + format; if (param.canWriteCompressed()) { if (user.isProperty(formatKey + COMPRESS)) { if (user.getProperty(formatKey + COMPRESS_MODE).equals("")) { param.setCompressionMode(ImageWriteParam.MODE_DEFAULT); } else { param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); param.setCompressionType(user.getProperty(formatKey + COMPRESS_MODE)); param.setCompressionQuality(user.getPropertyFloat(formatKey + COMPRESS_QUALITY)); } } else { if (canWriteUncompressed(format)) { param.setCompressionMode(ImageWriteParam.MODE_DISABLED); } } } if (param.canWriteProgressive()) { if (user.isProperty(formatKey + PROGRESSIVE)) { param.setProgressiveMode(ImageWriteParam.MODE_DEFAULT); } else { param.setProgressiveMode(ImageWriteParam.MODE_DISABLED); } } // write the image ImageOutputStream ios = ImageIO.createImageOutputStream(os); writer.setOutput(ios); writer.write(null, new IIOImage(image, null, null), param); writer.dispose(); ios.close(); } public static ImageWriter getPreferredImageWriter(String format) { return (ImageWriter)getImageWriters(ImageIO .getImageWritersByFormatName(format)).first(); } public static ImageWriter getPreferredImageWriterForMIMEType(String mimeType) { return (ImageWriter)getImageWriters(ImageIO .getImageWritersByMIMEType(mimeType)).first(); } public static SortedSet/**/ getImageWriters(Iterator iterator) { // look for a writer that supports the given format, // BUT prefer our own "org.freehep." // over "com.sun.imageio." over "com.sun.media." over others SortedSet imageWriters = new TreeSet(new Comparator() { private int order(Object o) { String className = o.getClass().getName(); if (className.startsWith("org.freehep.")) { return 0; } else if (className.startsWith("com.sun.imageio.")) { return 1; } else if (className.startsWith("com.sun.media.")) { return 2; } return 3; } public int compare(Object arg0, Object arg1) { int order0 = order(arg0); int order1 = order(arg1); return order0 < order1 ? -1 : order0 > order1 ? 1 : 0; } }); while (iterator.hasNext()) { imageWriters.add((ImageWriter) iterator.next()); } return imageWriters; } public static BufferedImage readImage(String format, InputStream is) throws IOException { Iterator iterator = ImageIO.getImageReadersByFormatName(format.toLowerCase()); if (!iterator.hasNext()) { throw new IOException(ImageGraphics2D.class + ": No reader for format '" + format + "'."); } ImageReader reader = (ImageReader) iterator.next(); ImageInputStream iis = ImageIO.createImageInputStream(is); reader.setInput(iis, true); BufferedImage image = reader.read(0); reader.dispose(); iis.close(); return image; } public static boolean canWriteUncompressed(String format) { // Method forgotten by Sun, BUG# 4856395. // If param.canWriteCompressed() is true, then it may be that // the format always needs to be compressed... GIF and JPG are among of // them. return !Arrays.asList(alwaysCompressedFormats).contains( format.toLowerCase()); } public static boolean canWriteTransparent(String format) { return !Arrays.asList(nonTransparentFormats).contains( format.toLowerCase()); } /** * @param bkg Background color for the image * @return Properties used to create a RAW image * @param code Color encoding, e.g. {@link ImageConstants#COLOR_MODEL_RGB} */ public static UserProperties getRAWProperties(Color bkg, String code) { UserProperties result = new UserProperties(); result.setProperty(RawImageWriteParam.BACKGROUND, bkg); result.setProperty(RawImageWriteParam.CODE, code); result.setProperty(RawImageWriteParam.PAD, 1); return result; } /** * Converts a given image to byte[] * * @throws IOException thrown by {@link #writeImage(java.awt.image.RenderedImage, String, java.util.Properties, java.io.OutputStream)} * @param image Image to convert * @param format e.g. {@link ImageConstants#JPG}, {@link ImageConstants#PNG, {@link ImageConstants#RAW} * @param props Properties for writing, e.g. {@link org.freehep.graphicsio.raw.RawImageWriteParam#BACKGROUND} * @param encoding {@link ImageConstants#ENCODING_ASCII85}, {@link ImageConstants#ENCODING_FLATE} or null * @return bytes representing the image */ public static byte[] toByteArray( RenderedImage image, String format, String encoding, Properties props) throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); OutputStream os = bos; if (ImageConstants.ENCODING_ASCII85.equals(encoding) || ImageConstants.ENCODING_FLATE_ASCII85.equals(encoding)) { os = new ASCII85OutputStream(os); } if (ImageConstants.ENCODING_FLATE.equals(encoding) || ImageConstants.ENCODING_FLATE_ASCII85.equals(encoding)) { os = new FlateOutputStream(os); } // avoid NPE if (props == null) { props = new Properties(); } // write image into the stream ImageGraphics2D.writeImage(image, format.toLowerCase(), props, os); os.close(); // return reulting bytes from stream return bos.toByteArray(); } } src/main/java/org/freehep/graphicsio/FontConstants.java0000644000175000017500000000130511312401775022541 0ustar user03user03// Copyright 2003, FreeHEP. package org.freehep.graphicsio; /** * * @author Mark Donszelmann * @version $Id: FontConstants.java 10271 2007-01-09 18:20:50Z duns $ */ public class FontConstants { private FontConstants() { } // Font Embedding public static final String EMBED_FONTS = "EmbedFonts"; public static final String EMBED_FONTS_AS = "EmbedFontsAs"; public static final String EMBED_FONTS_TYPE1 = "Type1"; public static final String EMBED_FONTS_TYPE3 = "Type3"; public static final String TEXT_AS_SHAPES = "TEXT_AS_SHAPES"; public static final String[] getEmbedFontsAsList() { return new String[] { EMBED_FONTS_TYPE1, EMBED_FONTS_TYPE3 }; } } src/main/java/org/freehep/graphicsio/png/0000755000175000017500000000000011312401770017653 5ustar user03user03src/main/java/org/freehep/graphicsio/png/package.html0000644000175000017500000000025611312401770022137 0ustar user03user03

PNG (Portable Network Graphics) Output Format.

src/main/java/org/freehep/graphicsio/png/PNGEncoder.java0000644000175000017500000005214611312401770022452 0ustar user03user03package org.freehep.graphicsio.png; //package com.keypoint; /** * PngEncoder takes a Java Image object and creates a byte string which can be saved as a PNG file. * The Image is presumed to use the DirectColorModel. * * Thanks to Jay Denny at KeyPoint Software * http://www.keypoint.com/ * who let me develop this code on company time. * * You may contact me with (probably very-much-needed) improvements, * comments, and bug fixes at: * * david@catcode.com * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * A copy of the GNU LGPL may be found at * http://www.gnu.org/copyleft/lesser.html, * * @author J. David Eisenberg * @version 1.4, 31 March 2000 */ /** * Added ImageObserver so that getHeight, getWidth calls work properly. * * @author M.Donszelmann */ import java.awt.Image; import java.awt.Toolkit; import java.awt.image.ImageObserver; import java.awt.image.PixelGrabber; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.zip.CRC32; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; public class PNGEncoder extends Object implements ImageObserver { /** Constant specifying that alpha channel should be encoded. */ public static final boolean ENCODE_ALPHA = true; /** Constant specifying that alpha channel should not be encoded. */ public static final boolean NO_ALPHA = false; /** Constants for filters */ public static final int FILTER_NONE = 0; public static final int FILTER_SUB = 1; public static final int FILTER_UP = 2; public static final int FILTER_LAST = 2; protected byte[] pngBytes; protected byte[] priorRow; protected byte[] leftBytes; protected Image image; protected int width, height; protected int bytePos, maxPos; protected int hdrPos, dataPos, endPos; protected CRC32 crc = new CRC32(); protected long crcValue; protected boolean encodeAlpha; protected int filter; protected int bytesPerPixel; protected int compressionLevel; protected List keys = new ArrayList(); protected List text = new ArrayList(); public PNGEncoder() { this(null, false, FILTER_NONE, 0); } /** * Class constructor specifying Image to encode, with no alpha channel * encoding. * * @param image A Java Image object which uses the DirectColorModel * @see java.awt.Image */ public PNGEncoder(Image image) { this(image, false, FILTER_NONE, 0); } /** * Class constructor specifying Image to encode, and whether to encode * alpha. * * @param image A Java Image object which uses the DirectColorModel * @param encodeAlpha Encode the alpha channel? false=no; true=yes * @see java.awt.Image */ public PNGEncoder(Image image, boolean encodeAlpha) { this(image, encodeAlpha, FILTER_NONE, 0); } /** * Class constructor specifying Image to encode, whether to encode alpha, * and filter to use. * * @param image A Java Image object which uses the DirectColorModel * @param encodeAlpha Encode the alpha channel? false=no; true=yes * @param whichFilter 0=none, 1=sub, 2=up * @see java.awt.Image */ public PNGEncoder(Image image, boolean encodeAlpha, int whichFilter) { this(image, encodeAlpha, whichFilter, 0); } /** * Class constructor specifying Image source to encode, whether to encode * alpha, filter to use, and compression level. * * @param image A Java Image object * @param encodeAlpha Encode the alpha channel? false=no; true=yes * @param whichFilter 0=none, 1=sub, 2=up * @param compLevel 0..9 * @see java.awt.Image */ public PNGEncoder(Image image, boolean encodeAlpha, int whichFilter, int compLevel) { this.image = image; this.encodeAlpha = encodeAlpha; setFilter(whichFilter); if (compLevel >= 0 && compLevel <= 9) { this.compressionLevel = compLevel; } } public void addText(String key, String value) { if ((key == null) || (key.length() == 0)) key = "Comment"; keys.add(key.substring(0, Math.min(79, key.length()))); text.add(value); } /** * Set the image to be encoded * * @param image A Java Image object which uses the DirectColorModel * @see java.awt.Image */ public void setImage(Image image) { this.image = image; pngBytes = null; } /** method to wait for image */ private int imageStatus; public boolean imageUpdate(Image image, int flags, int x, int y, int width, int height) { imageStatus = flags; if (((flags & ALLBITS) == ALLBITS) || ((flags & (ABORT | ERROR)) != 0)) { return false; } return true; } /** * Creates an array of bytes that is the PNG equivalent of the current * image, specifying whether to encode alpha or not. * * @param encodeAlpha boolean false=no alpha, true=encode alpha * @return an array of bytes, or null if there was a problem */ public byte[] pngEncode(boolean encodeAlpha) { byte[] pngIdBytes = { -119, 80, 78, 71, 13, 10, 26, 10 }; if (image == null) { return null; } imageStatus = 0; boolean status = Toolkit.getDefaultToolkit().prepareImage(image, -1, -1, this); if (!status) { while (((imageStatus & (ALLBITS)) == 0) && ((imageStatus & (ABORT | ERROR)) == 0)) { try { Thread.sleep(100); } catch (Exception e) { } } // FIXED: moved this inside the "if (!status)" area if ((imageStatus & (ALLBITS)) == 0) { return null; } } width = image.getWidth(null); height = image.getHeight(null); /* * start with an array that is big enough to hold all the pixels (plus * filter bytes), and an extra 200 bytes for header info */ pngBytes = new byte[((width + 1) * height * 3) + 200]; /* * keep track of largest byte written to the array */ maxPos = 0; bytePos = writeBytes(pngIdBytes, 0); hdrPos = bytePos; writeHeader(); for (Iterator ik = keys.iterator(), iv = text.iterator(); ik.hasNext() && iv.hasNext();) { writeText((String) ik.next(), (String) iv.next()); } dataPos = bytePos; if (writeImageData()) { writeEnd(); pngBytes = resizeByteArray(pngBytes, maxPos); } else { pngBytes = null; } return pngBytes; } /** * Creates an array of bytes that is the PNG equivalent of the current * image. Alpha encoding is determined by its setting in the constructor. * * @return an array of bytes, or null if there was a problem */ public byte[] pngEncode() { return pngEncode(encodeAlpha); } /** * Set the alpha encoding on or off. * * @param encodeAlpha false=no, true=yes */ public void setEncodeAlpha(boolean encodeAlpha) { this.encodeAlpha = encodeAlpha; } /** * Retrieve alpha encoding status. * * @return boolean false=no, true=yes */ public boolean getEncodeAlpha() { return encodeAlpha; } /** * Set the filter to use * * @param whichFilter from constant list */ public void setFilter(int whichFilter) { this.filter = FILTER_NONE; if (whichFilter <= FILTER_LAST) { this.filter = whichFilter; } } /** * Retrieve filtering scheme * * @return int (see constant list) */ public int getFilter() { return filter; } /** * Set the compression level to use * * @param level 0 through 9 */ public void setCompressionLevel(int level) { if (level >= 0 && level <= 9) { this.compressionLevel = level; } } /** * Retrieve compression level * * @return int in range 0-9 */ public int getCompressionLevel() { return compressionLevel; } /** * Increase or decrease the length of a byte array. * * @param array The original array. * @param newLength The length you wish the new array to have. * @return Array of newly desired length. If shorter than the original, the * trailing elements are truncated. */ protected byte[] resizeByteArray(byte[] array, int newLength) { byte[] newArray = new byte[newLength]; int oldLength = array.length; System.arraycopy(array, 0, newArray, 0, Math.min(oldLength, newLength)); return newArray; } /** * Write an array of bytes into the pngBytes array. Note: This routine has * the side effect of updating maxPos, the largest element written in the * array. The array is resized by 1000 bytes or the length of the data to be * written, whichever is larger. * * @param data The data to be written into pngBytes. * @param offset The starting point to write to. * @return The next place to be written to in the pngBytes array. */ protected int writeBytes(byte[] data, int offset) { maxPos = Math.max(maxPos, offset + data.length); if (data.length + offset > pngBytes.length) { pngBytes = resizeByteArray(pngBytes, pngBytes.length + Math.max(1000, data.length)); } System.arraycopy(data, 0, pngBytes, offset, data.length); return offset + data.length; } /** * Write an array of bytes into the pngBytes array, specifying number of * bytes to write. Note: This routine has the side effect of updating * maxPos, the largest element written in the array. The array is resized by * 1000 bytes or the length of the data to be written, whichever is larger. * * @param data The data to be written into pngBytes. * @param nBytes The number of bytes to be written. * @param offset The starting point to write to. * @return The next place to be written to in the pngBytes array. */ protected int writeBytes(byte[] data, int nBytes, int offset) { maxPos = Math.max(maxPos, offset + nBytes); if (nBytes + offset > pngBytes.length) { pngBytes = resizeByteArray(pngBytes, pngBytes.length + Math.max(1000, nBytes)); } System.arraycopy(data, 0, pngBytes, offset, nBytes); return offset + nBytes; } /** * Write a two-byte integer into the pngBytes array at a given position. * * @param n The integer to be written into pngBytes. * @param offset The starting point to write to. * @return The next place to be written to in the pngBytes array. */ protected int writeInt2(int n, int offset) { byte[] temp = { (byte) ((n >> 8) & 0xff), (byte) (n & 0xff) }; return writeBytes(temp, offset); } /** * Write a four-byte integer into the pngBytes array at a given position. * * @param n The integer to be written into pngBytes. * @param offset The starting point to write to. * @return The next place to be written to in the pngBytes array. */ protected int writeInt4(int n, int offset) { byte[] temp = { (byte) ((n >> 24) & 0xff), (byte) ((n >> 16) & 0xff), (byte) ((n >> 8) & 0xff), (byte) (n & 0xff) }; return writeBytes(temp, offset); } /** * Write a single byte into the pngBytes array at a given position. * * @param b The integer to be written into pngBytes. * @param offset The starting point to write to. * @return The next place to be written to in the pngBytes array. */ protected int writeByte(int b, int offset) { byte[] temp = { (byte) b }; return writeBytes(temp, offset); } /** * Write a string into the pngBytes array at a given position. This uses the * getBytes method, so the encoding used will be its default. * * @param s The String to be written into pngBytes. * @param offset The starting point to write to. * @return The next place to be written to in the pngBytes array. * @see java.lang.String#getBytes() */ protected int writeString(String s, int offset) { return writeBytes(s.getBytes(), offset); } /** * Write a PNG "IHDR" chunk into the pngBytes array. */ protected void writeHeader() { int startPos; startPos = bytePos = writeInt4(13, bytePos); bytePos = writeString("IHDR", bytePos); width = image.getWidth(null); height = image.getHeight(null); bytePos = writeInt4(width, bytePos); bytePos = writeInt4(height, bytePos); bytePos = writeByte(8, bytePos); // bit depth bytePos = writeByte((encodeAlpha) ? 6 : 2, bytePos); // direct model bytePos = writeByte(0, bytePos); // compression method bytePos = writeByte(0, bytePos); // filter method bytePos = writeByte(0, bytePos); // no interlace crc.reset(); crc.update(pngBytes, startPos, bytePos - startPos); crcValue = crc.getValue(); bytePos = writeInt4((int) crcValue, bytePos); } protected void writeText(String key, String value) { int startPos; int len = key.length() + 1 + value.length(); startPos = bytePos = writeInt4(len, bytePos); bytePos = writeString("tEXt", bytePos); bytePos = writeString(key, bytePos); bytePos = writeByte(0, bytePos); bytePos = writeString(value, bytePos); crc.reset(); crc.update(pngBytes, startPos, bytePos - startPos); crcValue = crc.getValue(); bytePos = writeInt4((int) crcValue, bytePos); } /** * Perform "sub" filtering on the given row. Uses temporary array leftBytes * to store the original values of the previous pixels. The array is 16 * bytes long, which will easily hold two-byte samples plus two-byte alpha. * * @param pixels The array holding the scan lines being built * @param startPos Starting position within pixels of bytes to be filtered. * @param width Width of a scanline in pixels. */ protected void filterSub(byte[] pixels, int startPos, int width) { int i; int offset = bytesPerPixel; int actualStart = startPos + offset; int nBytes = width * bytesPerPixel; int leftInsert = offset; int leftExtract = 0; for (i = actualStart; i < startPos + nBytes; i++) { leftBytes[leftInsert] = pixels[i]; pixels[i] = (byte) ((pixels[i] - leftBytes[leftExtract]) % 256); leftInsert = (leftInsert + 1) % 0x0f; leftExtract = (leftExtract + 1) % 0x0f; } } /** * Perform "up" filtering on the given row. Side effect: refills the prior * row with current row * * @param pixels The array holding the scan lines being built * @param startPos Starting position within pixels of bytes to be filtered. * @param width Width of a scanline in pixels. */ protected void filterUp(byte[] pixels, int startPos, int width) { int i, nBytes; byte current_byte; nBytes = width * bytesPerPixel; for (i = 0; i < nBytes; i++) { current_byte = pixels[startPos + i]; pixels[startPos + i] = (byte) ((pixels[startPos + i] - priorRow[i]) % 256); priorRow[i] = current_byte; } } /** * Write the image data into the pngBytes array. This will write one or more * PNG "IDAT" chunks. In order to conserve memory, this method grabs as many * rows as will fit into 32K bytes, or the whole image; whichever is less. * * * @return true if no errors; false if error grabbing pixels */ protected boolean writeImageData() { int rowsLeft = height; // number of rows remaining to write int startRow = 0; // starting row to process this time through int nRows; // how many rows to grab at a time byte[] scanLines; // the scan lines to be compressed int scanPos; // where we are in the scan lines int startPos; // where this line's actual pixels start (used for // filtering) byte[] compressedLines; // the resultant compressed lines int nCompressed; // how big is the compressed area? PixelGrabber pg; bytesPerPixel = (encodeAlpha) ? 4 : 3; Deflater scrunch = new Deflater(compressionLevel); ByteArrayOutputStream outBytes = new ByteArrayOutputStream(1024); DeflaterOutputStream compBytes = new DeflaterOutputStream(outBytes, scrunch); try { while (rowsLeft > 0) { nRows = Math.min(32767 / (width * (bytesPerPixel + 1)), rowsLeft); // nRows = rowsLeft; int[] pixels = new int[width * nRows]; pg = new PixelGrabber(image, 0, startRow, width, nRows, pixels, 0, width); try { pg.grabPixels(); } catch (Exception e) { System.err.println("interrupted waiting for pixels!"); return false; } if ((pg.getStatus() & ImageObserver.ABORT) != 0) { System.err.println("image fetch aborted or errored"); return false; } /* * Create a data chunk. scanLines adds "nRows" for the filter * bytes. */ scanLines = new byte[width * nRows * bytesPerPixel + nRows]; if (filter == FILTER_SUB) { leftBytes = new byte[16]; } if (filter == FILTER_UP) { priorRow = new byte[width * bytesPerPixel]; } scanPos = 0; startPos = 1; for (int i = 0; i < width * nRows; i++) { if (i % width == 0) { scanLines[scanPos++] = (byte) filter; startPos = scanPos; } scanLines[scanPos++] = (byte) ((pixels[i] >> 16) & 0xff); scanLines[scanPos++] = (byte) ((pixels[i] >> 8) & 0xff); scanLines[scanPos++] = (byte) ((pixels[i]) & 0xff); if (encodeAlpha) { scanLines[scanPos++] = (byte) ((pixels[i] >> 24) & 0xff); } if ((i % width == width - 1) && (filter != FILTER_NONE)) { if (filter == FILTER_SUB) { filterSub(scanLines, startPos, width); } if (filter == FILTER_UP) { filterUp(scanLines, startPos, width); } } } /* * Write these lines to the output area */ compBytes.write(scanLines, 0, scanPos); startRow += nRows; rowsLeft -= nRows; } compBytes.close(); /* * Write the compressed bytes */ compressedLines = outBytes.toByteArray(); nCompressed = compressedLines.length; crc.reset(); bytePos = writeInt4(nCompressed, bytePos); bytePos = writeString("IDAT", bytePos); crc.update("IDAT".getBytes()); bytePos = writeBytes(compressedLines, nCompressed, bytePos); crc.update(compressedLines, 0, nCompressed); crcValue = crc.getValue(); bytePos = writeInt4((int) crcValue, bytePos); scrunch.finish(); return true; } catch (IOException e) { System.err.println(e.toString()); return false; } } /** * Write a PNG "IEND" chunk into the pngBytes array. */ protected void writeEnd() { bytePos = writeInt4(0, bytePos); bytePos = writeString("IEND", bytePos); crc.reset(); crc.update("IEND".getBytes()); crcValue = crc.getValue(); bytePos = writeInt4((int) crcValue, bytePos); } } src/main/java/org/freehep/graphicsio/font/0000755000175000017500000000000011312401775020042 5ustar user03user03src/main/java/org/freehep/graphicsio/font/FontEmbedder.java0000644000175000017500000001265611312401775023255 0ustar user03user03// Copyright 2001-2005 freehep package org.freehep.graphicsio.font; import java.awt.Font; import java.awt.Shape; import java.awt.font.FontRenderContext; import java.awt.font.GlyphMetrics; import java.awt.font.GlyphVector; import java.awt.geom.GeneralPath; import java.awt.geom.Rectangle2D; import java.io.IOException; import org.freehep.graphics2d.font.CharTable; /** * A FontIncluder that also embeds all glyphs. Subclasses must implement the * writeGlyph method which is called for all defined (up to 256) * characters and the notdefined character. These method calls are bracketed by * openGlyphs() and closeGlyph(). All invocations of * methods that are abstract in this class succeed the method calls of the * superclass FontIncluder (especially closeIncludeFont()!) * All of these calls are again succeeded by closeEmbedFont.
* The abstract methods are called in the following order: *
    *
  • openIncludeFont *
  • writeEncoding *
  • closeIncludeFont *
  • writeWidths *
  • openGlyphs *
  • loop over all glyphs: openGlyphs *
  • closeGlyphs *
  • closeEmbedFont *
* * @author Simon Fischer * @version $Id: FontEmbedder.java 8584 2006-08-10 23:06:37Z duns $ */ public abstract class FontEmbedder extends FontIncluder { public static final String NOTDEF = ".notdef"; /** * Writes a single glyph to the file. A null value for glyphMetrics * indicates the undefined character. In this case the value of * unicodeName equals the value of * NOTDEF (=.notdef). * * @param unicodeName the character's name according to the unicode standard * @param glyph the shape that represents this glyph * @param glyphMetrics the metrics of this glyph */ protected abstract void writeGlyph(String unicodeName, Shape glyph, GlyphMetrics glyphMetrics) throws IOException; /** Writes the character widths to the file. */ protected abstract void writeWidths(double[] widths) throws IOException; /** * Called before the glyph loop starts. Does nothing by default but can be * implemented. */ protected void openGlyphs() throws IOException { } /** * Called after the glyph loop ends. Does nothing by default but can be * implemented. */ protected void closeGlyphs() throws IOException { } protected abstract void closeEmbedFont() throws IOException; private double[] widths; private GlyphVector glyphs; private Font font; // FONTHACK public FontEmbedder(FontRenderContext context) { super(context); } protected double[] getAdvanceWidths() { if (widths == null) { // figure out the widths of the characters if not yet done widths = new double[256]; for (int i = 0; i < widths.length; i++) { widths[i] = glyphs.getGlyphMetrics(i).getAdvance(); // in case of undefined character set to width of undefined // symbol if (getCharName(i) == null) { widths[i] = getUndefinedWidth(); } } } return widths; } protected double getAdvanceWidth(int character) { return getAdvanceWidths()[character]; } protected Shape getGlyph(int i) { // This one-line implementation produces different results under JDK 1.3 // and 1.4 // return glyphs.getGlyphOutline(i); // The substitute code attempts to work around this by using defensive // programming // See code marked FONTHACK elsewhere in this file // Create a GlyphVector for this single character. FontRenderContext orig = getContext(); FontRenderContext frc = new FontRenderContext(null, orig .isAntiAliased(), orig.usesFractionalMetrics()); Shape shape = font.createGlyphVector(frc, new char[] { getUnicode(i) }) .getGlyphOutline(0); return orig.getTransform().createTransformedShape(shape); } protected GlyphMetrics getGlyphMetrics(int i) { return glyphs.getGlyphMetrics(i); } public void includeFont(Font font, CharTable charTable, String name) throws IOException { glyphs = null; widths = null; // FONTHACK: Needed by hacked version of getGlyph() this.font = font; super.includeFont(font, charTable, name); this.glyphs = font.createGlyphVector(getContext(), getUnicode()); writeWidths(getAdvanceWidths()); try { openGlyphs(); // write the glyphs for (int i = 0; i < 256; i++) { if (getCharName(i) != null) { writeGlyph(getCharName(i), getGlyph(i), getGlyphMetrics(i)); } } writeGlyph(NOTDEF, createUndefined(), null); closeGlyphs(); closeEmbedFont(); } catch (Exception e) { e.printStackTrace(); } } private Shape createUndefined() { GeneralPath ud = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 10); ud.append(new Rectangle2D.Double(0, 0, FONT_SIZE, FONT_SIZE), false); ud.append(new Rectangle2D.Double(FONT_SIZE / 20, FONT_SIZE / 20, 18 * FONT_SIZE / 20, 18 * FONT_SIZE / 20), false); return ud; } } src/main/java/org/freehep/graphicsio/font/package.html0000644000175000017500000000011711312401775022322 0ustar user03user03 Utility classes for encoding, including and/or embedding fonts. src/main/java/org/freehep/graphicsio/font/FontIncluder.java0000644000175000017500000001010211312401775023273 0ustar user03user03// Copyright 2001-2005 freehep package org.freehep.graphicsio.font; import java.awt.Font; import java.awt.font.FontRenderContext; import java.awt.geom.Rectangle2D; import java.io.IOException; import org.freehep.graphics2d.font.CharTable; /** * Instances of this class write the information into documents (ps or pdf) that * is necessary in order to include or embed fonts. In order to guarantee a * time-invariant interface the main methods to implement by subclasses * includeFont takes no arguments. All necessary data should be * available by getter methods which can easily be added.
* The abstract methods are called in the following order: *
    *
  • openIncludeFont *
  • writeEncoding *
  • closeIncludeFont *
* * @author Simon Fischer * @version $Id: FontIncluder.java 8584 2006-08-10 23:06:37Z duns $ */ public abstract class FontIncluder { public static final double FONT_SIZE = 1000; // -------------------- abstract methods -------------------- /** * Writes the given information about the font into the file. When this * method is called all getXXX() are guaranteed to return * reasonable values. */ protected abstract void openIncludeFont() throws IOException; /** Writes the encoding table to the file. */ protected abstract void writeEncoding(CharTable charTable) throws IOException; /** Does nothing, but can be implemented by subclasses if necessary. */ protected void closeIncludeFont() throws IOException { } // ----------------------------------------------------------- private FontRenderContext context; private Rectangle2D fontBBox; private Font font; private String fontName; private CharTable charTable; private char[] unicode; private String[] charName; private int noDefinedChars; public FontIncluder(FontRenderContext context) { this.context = context; this.noDefinedChars = -1; } // ----------------------------------------------------------- protected FontRenderContext getContext() { return context; } protected String getFontName() { return fontName; } protected Font getFont() { return font; } protected CharTable getEncodingTable() { return charTable; } protected Rectangle2D getFontBBox() { return fontBBox; } protected String getCharName(int i) { return charName[i]; } protected char getUnicode(int i) { return unicode[i]; } protected char[] getUnicode() { return unicode; } protected int getNODefinedChars() { return noDefinedChars; } // ----------------------------------------------------------- /** * Embed this font to the file. * * @param font The font to include * @param name The name under which this font is addressed within the * document (can be retrieved by getFontName()) */ public void includeFont(Font font, CharTable charTable, String name) throws IOException { unicode = null; charName = null; this.font = font; this.charTable = charTable; this.fontName = name; // figure out the maximum bounding box for all characters this.fontBBox = font.getMaxCharBounds(context); // figure out the unicodes and character names and // create a glyph vector containing the 256 glyphs of the font this.noDefinedChars = 0; this.unicode = new char[256]; this.charName = new String[256]; for (int i = 0; i < unicode.length; i++) { charName[i] = charTable.toName(i); if (charName[i] != null) { unicode[i] = charTable.toUnicode(charName[i]); noDefinedChars++; } else { unicode[i] = 0; } } openIncludeFont(); writeEncoding(charTable); closeIncludeFont(); } protected double getUndefinedWidth() { return FONT_SIZE; } } src/main/java/org/freehep/graphicsio/font/CharstringEncoder.java0000644000175000017500000001123011312401775024306 0ustar user03user03// Copyright 2001 freehep package org.freehep.graphicsio.font; import java.awt.Shape; import java.io.IOException; import java.io.OutputStream; import org.freehep.graphicsio.QuadToCubicPathConstructor; /** * Encoder to encode "CharStrings" used in PostScript and Type 1 Fonts. * * @author Simon Fischer * @version $Id: CharstringEncoder.java 8584 2006-08-10 23:06:37Z duns $ */ public class CharstringEncoder extends QuadToCubicPathConstructor { private static final int LAST_POINT = 0; private static final int HORIZONTAL = 1; private static final int VERTICAL = 2; private static final int BOTH = 3; private OutputStream out; private int currentX, currentY; public CharstringEncoder(OutputStream out) { this.out = out; currentX = currentY = 0; } private int writeNumber(double v) throws IOException { int round = (int) Math.round(v); writeNumber(round); return round; } private void writeNumber(int v) throws IOException { if ((v >= -107) && (v <= 107)) { out.write(v + 139); } else if ((v >= 108) && (v <= 1131)) { int highByte = (v - 108) / 256; out.write(highByte + 247); out.write(v - 108 - 256 * highByte); } else if ((v >= -1131) && (v <= -108)) { int highByte = (v + 108) / 256; out.write(-highByte + 251); out.write(-(v + 108 - 256 * highByte)); } else { out.write(255); // copied from DataOutputStream correct? '>>>'? out.write((v >>> 24) & 0xFF); out.write((v >>> 16) & 0xFF); out.write((v >>> 8) & 0xFF); out.write((v >>> 0) & 0xFF); } } protected void writeCommand(int com) throws IOException { if (com >= 31) throw new IOException("Charstring command out of range: " + com); out.write(com); } protected void writeExtCommand(int com) throws IOException { out.write(12); out.write(com); } // -------------------- PATH CONSTRUCTION -------------------- private void writePoint(double x, double y) throws IOException { currentX += writeNumber(x - currentX); currentY += writeNumber(y - currentY); } private void writeX(double x) throws IOException { currentX += writeNumber(x - currentX); } private void writeY(double y) throws IOException { currentY += writeNumber(y - currentY); } // -------------------- start/end -------------------- public void startChar(double sidebearing, double width) throws IOException { currentX = writeNumber(sidebearing); writeNumber(width); writeCommand(13); } public void endchar() throws IOException { writeCommand(14); } // -------------------- path construction -------------------- private int to(double x, double y) throws IOException { // writePoint(x, y); // return BOTH; int rx = (int) Math.round(x); int ry = (int) Math.round(y); if (rx == currentX) { if (ry == currentY) { return LAST_POINT; } else { writeY(y); return VERTICAL; } } else if (ry == currentY) { writeX(x); return HORIZONTAL; } else { writePoint(x, y); return BOTH; } } public void move(double x, double y) throws IOException { switch (to(x, y)) { case BOTH: writeCommand(21); break; case HORIZONTAL: writeCommand(22); break; case VERTICAL: writeCommand(4); break; case LAST_POINT: break; } super.move(x, y); } public void line(double x, double y) throws IOException { switch (to(x, y)) { case BOTH: writeCommand(5); break; case HORIZONTAL: writeCommand(6); break; case VERTICAL: writeCommand(7); break; case LAST_POINT: break; } super.line(x, y); } public void cubic(double x1, double y1, double x2, double y2, double x3, double y3) throws IOException { writePoint(x1, y1); writePoint(x2, y2); writePoint(x3, y3); writeCommand(8); super.cubic(x1, y1, x2, y2, x3, y3); } public void closePath(double x0, double y0) throws IOException { writeCommand(9); super.closePath(x0, y0); } public void drawPath(Shape s) throws IOException { addPath(s); } } src/main/java/org/freehep/graphicsio/font/truetype/0000755000175000017500000000000011312401775021723 5ustar user03user03src/main/java/org/freehep/graphicsio/font/truetype/TTFHeadTable.java0000644000175000017500000000624711312401775024766 0ustar user03user03// Copyright 2001, FreeHEP. package org.freehep.graphicsio.font.truetype; import java.awt.Rectangle; import java.io.IOException; /** * HEAD Table. * * @author Simon Fischer * @version $Id: TTFHeadTable.java 8584 2006-08-10 23:06:37Z duns $ */ public class TTFHeadTable extends TTFVersionTable { public static final int FDH_MIXED = 0; public static final int FDH_LEFT_TO_RIGHT = 1; public static final int FDH_LEFT_TO_RIGHT_NEUTRAL = 2; public static final int FDH_RIGHT_TO_LEFT = -1; public static final int FDH_RIGHT_TO_LEFT_NEUTRAL = -2; public static final int ITLF_SHORT = 0; public static final int ITLF_LONG = 1; public int fontRevisionMinor, fontRevisionMajor; public long checkSumAdjustment; public long magicNumber; public boolean baseline0, sidebearing0, instrDependOnSize, forcePPEM2Int, instrAlterAdvance; public int unitsPerEm; public byte[] created = new byte[8]; public byte[] modified = new byte[8]; public short xMin, yMin, xMax, yMax; public boolean macBold, macItalic; public int lowestRecPPEM; public short fontDirectionHint; public short indexToLocFormat, glyphDataFormat; public String getTag() { return "head"; } public void readTable() throws IOException { readVersion(); fontRevisionMajor = ttf.readUShort(); fontRevisionMinor = ttf.readUShort(); checkSumAdjustment = ttf.readULong(); magicNumber = ttf.readULong(); ttf.readUShortFlags(); // flags baseline0 = ttf.flagBit(0); sidebearing0 = ttf.flagBit(1); instrDependOnSize = ttf.flagBit(2); forcePPEM2Int = ttf.flagBit(3); instrAlterAdvance = ttf.flagBit(4); unitsPerEm = ttf.readUShort(); ttf.readFully(created); ttf.readFully(modified); xMin = ttf.readShort(); yMin = ttf.readShort(); xMax = ttf.readShort(); yMax = ttf.readShort(); ttf.readUShortFlags(); // macstyle macBold = ttf.flagBit(0); macItalic = ttf.flagBit(1); lowestRecPPEM = ttf.readUShort(); fontDirectionHint = ttf.readShort(); indexToLocFormat = ttf.readShort(); if ((indexToLocFormat != ITLF_LONG) && (indexToLocFormat != ITLF_SHORT)) System.err.println("Unknown value for indexToLocFormat: " + indexToLocFormat); glyphDataFormat = ttf.readShort(); } public String toString() { String str = super.toString() + "\n" + " magicNumber: 0x" + Integer.toHexString((int) magicNumber) + " (" + (magicNumber == 0x5f0f3cf5 ? "ok" : "wrong") + ")\n"; str += " indexToLocFormat: " + indexToLocFormat + " "; if (indexToLocFormat == ITLF_LONG) str += " (long)\n"; else if (indexToLocFormat == ITLF_SHORT) str += "(short)\n"; else str += "(illegal value)\n"; str += " bbox: (" + xMin + "," + yMin + ") : (" + xMax + "," + yMax + ")"; return str; } public Rectangle getMaxCharBounds() { return new Rectangle(xMin, yMin, xMax - xMin, yMax - yMin); } } src/main/java/org/freehep/graphicsio/font/truetype/TTFFile.java0000644000175000017500000000435311312401775024030 0ustar user03user03// Copyright 2001, FreeHEP. package org.freehep.graphicsio.font.truetype; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; /** * Concrete implementation of the TrueType Font, read from a TTF File. * * @author Mark Donszelmann * @version $Id: TTFFile.java 8584 2006-08-10 23:06:37Z duns $ */ public class TTFFile extends TTFFont { private static final String mode = "r"; private String fileName; private RandomAccessFile ttf; private int sfntMajorVersion; private int sfntMinorVersion; private int numberOfTables; private int searchRange; private int entrySelector; private int rangeShift; public TTFFile(String name) throws FileNotFoundException, IOException { fileName = name; ttf = new RandomAccessFile(name, mode); // read table directory ttf.seek(0); sfntMajorVersion = ttf.readUnsignedShort(); sfntMinorVersion = ttf.readUnsignedShort(); numberOfTables = ttf.readUnsignedShort(); searchRange = ttf.readUnsignedShort(); entrySelector = ttf.readUnsignedShort(); rangeShift = ttf.readUnsignedShort(); // read table entries for (int i = 0; i < numberOfTables; i++) { ttf.seek(12 + i * 16); byte b[] = new byte[4]; ttf.readFully(b); String tag = new String(b); int checksum = ttf.readInt(); int offset = ttf.readInt(); int len = ttf.readInt(); TTFInput input = new TTFFileInput(ttf, offset, len, checksum); newTable(tag, input); } } public int getFontVersion() { return sfntMajorVersion; } public void close() throws IOException { super.close(); ttf.close(); } public void show() { super.show(); System.out.println("Font: " + fileName); System.out.println(" sfnt: " + sfntMajorVersion + "." + sfntMinorVersion); System.out.println(" numTables: " + numberOfTables); System.out.println(" searchRange: " + searchRange); System.out.println(" entrySelector: " + entrySelector); System.out.println(" rangeShift: " + rangeShift); } } src/main/java/org/freehep/graphicsio/font/truetype/TTFOS_2Table.java0000644000175000017500000000520511312401775024660 0ustar user03user03// Copyright 2001, FreeHEP. package org.freehep.graphicsio.font.truetype; import java.io.IOException; /** * OS/2 Table. * * @author Simon Fischer * @version $Id: TTFOS_2Table.java 8584 2006-08-10 23:06:37Z duns $ */ public class TTFOS_2Table extends TTFVersionTable { public int version; public short xAvgCharWidth; public int usWeightClass, usWidthClass; public short fsType; public short ySubscriptXSize, ySubscriptYSize, ySubscriptXOffset, ySubscriptYOffset; public short ySuperscriptXSize, ySuperscriptYSize, ySuperscriptXOffset, ySuperscriptYOffset; public short yStrikeoutSize, yStrikeoutPosition; public short sFamilyClass; public byte[] panose = new byte[10]; public long[] ulUnicode = new long[4]; public byte[] achVendID = new byte[4]; public int fsSelection; public int usFirstCharIndex, usLastCharIndes; public int sTypoAscender, sTzpoDescender, sTypoLineGap; public int usWinAscent, usWinDescent; public long[] ulCodePageRange = new long[2]; public String getTag() { return "OS/2"; } public void readTable() throws IOException { version = ttf.readUShort(); xAvgCharWidth = ttf.readShort(); usWeightClass = ttf.readUShort(); usWidthClass = ttf.readUShort(); fsType = ttf.readShort(); ySubscriptXSize = ttf.readShort(); ySubscriptYSize = ttf.readShort(); ySubscriptXOffset = ttf.readShort(); ySubscriptYOffset = ttf.readShort(); ySuperscriptXSize = ttf.readShort(); ySuperscriptYSize = ttf.readShort(); ySuperscriptXOffset = ttf.readShort(); ySuperscriptYOffset = ttf.readShort(); yStrikeoutSize = ttf.readShort(); yStrikeoutPosition = ttf.readShort(); sFamilyClass = ttf.readShort(); ttf.readFully(panose); for (int i = 0; i < ulUnicode.length; i++) ulUnicode[i] = ttf.readULong(); ttf.readFully(achVendID); fsSelection = ttf.readUShort(); usFirstCharIndex = ttf.readUShort(); usLastCharIndes = ttf.readUShort(); sTypoAscender = ttf.readUShort(); sTzpoDescender = ttf.readUShort(); sTypoLineGap = ttf.readUShort(); usWinAscent = ttf.readUShort(); usWinDescent = ttf.readUShort(); ulCodePageRange[0] = ttf.readULong(); ulCodePageRange[1] = ttf.readULong(); } public String getAchVendID() { return new String(achVendID); } public String toString() { return super.toString() + "\n version: " + version + "\n vendor: " + getAchVendID(); } } src/main/java/org/freehep/graphicsio/font/truetype/TTFPostTable.java0000644000175000017500000000347011312401775025045 0ustar user03user03// Copyright 2001, FreeHEP. package org.freehep.graphicsio.font.truetype; import java.io.IOException; /** * POST Table. * * @author Simon Fischer * @version $Id: TTFPostTable.java 8584 2006-08-10 23:06:37Z duns $ */ public class TTFPostTable extends TTFTable { public double format; public double italicAngle; public short underlinePosition, underlineThickness; public long isFixedPitch; public long minMemType42, maxMemType42, minMemType1, maxMemType1; public int[] glyphNameIndex; public String getTag() { return "post"; } public void readTable() throws IOException { format = ttf.readFixed(); italicAngle = ttf.readFixed(); underlinePosition = ttf.readFWord(); underlineThickness = ttf.readFWord(); isFixedPitch = ttf.readULong(); minMemType42 = ttf.readULong(); maxMemType42 = ttf.readULong(); minMemType1 = ttf.readULong(); maxMemType1 = ttf.readULong(); if (format == 2.0) { glyphNameIndex = ttf.readUShortArray(ttf.readUShort()); } else if (format == 2.5) { System.err.println("Format 2.5 for post notimplemented yet."); } } public String toString() { String str = super.toString() + " format: " + format + "\n italic:" + italicAngle + " ulPos:" + underlinePosition + " ulThick:" + underlineThickness + " isFixed:" + isFixedPitch; if (glyphNameIndex != null) { str += "\n glyphNamesIndex[" + glyphNameIndex.length + "] = {"; for (int i = 0; i < glyphNameIndex.length; i++) { if (i % 16 == 0) str += "\n "; str += glyphNameIndex[i] + " "; } str += "\n }"; } return str; } } src/main/java/org/freehep/graphicsio/font/truetype/package.html0000644000175000017500000000036111312401775024204 0ustar user03user03

Interface for TrueType Font information, using a Java Font class or read from a TrueType font file.

Limitations:

  • OpenFontAdapter not tested.
src/main/java/org/freehep/graphicsio/font/truetype/TTFTable.java0000644000175000017500000000351411312401775024176 0ustar user03user03// Copyright 2001, FreeHEP. package org.freehep.graphicsio.font.truetype; import java.io.IOException; /** * Concrete instances derived from this class hold data stored in true type * tables. Right now the data is accessible as public attributes. In some cases * methods may return more convenient objects (such as Shapes instead of point * arrays). * * @author Simon Fischer * @version $Id: TTFTable.java 8584 2006-08-10 23:06:37Z duns $ */ public abstract class TTFTable { public static final String[] TT_TAGS = new String[] { "cmap", "glyf", "head", "hhea", "hmtx", "loca", "maxp", "name", "OS/2", "post" }; public static final Class[] TABLE_CLASSES = new Class[] { TTFCMapTable.class, TTFGlyfTable.class, TTFHeadTable.class, TTFHHeaTable.class, TTFHMtxTable.class, TTFLocaTable.class, TTFMaxPTable.class, TTFNameTable.class, TTFOS_2Table.class, TTFPostTable.class }; private TTFFont ttfFont; TTFInput ttf; private boolean isRead = false; public void init(TTFFont font, TTFInput ttf) throws IOException { this.ttfFont = font; this.ttf = ttf; } public void read() throws IOException { ttf.pushPos(); System.out.print("[" + getTag()); ttf.seek(0); readTable(); isRead = true; System.out.print("]"); ttf.popPos(); } public abstract void readTable() throws IOException; public abstract String getTag(); public boolean isRead() { return isRead; } public TTFTable getTable(String tag) throws IOException { return ttfFont.getTable(tag); } // -------------------------------------------------------------------------------- public String toString() { return ttf + ": [" + getTag() + "/" + getClass().getName() + "]"; } } src/main/java/org/freehep/graphicsio/font/truetype/TTFFont.java0000644000175000017500000000426311312401775024057 0ustar user03user03// Copyright 2001, FreeHEP. package org.freehep.graphicsio.font.truetype; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * TrueType Font with all its tables. * * @author Simon Fischer * @version $Id: TTFFont.java 8584 2006-08-10 23:06:37Z duns $ */ public abstract class TTFFont { private Map entry = new HashMap(); public abstract int getFontVersion(); void newTable(String tag, TTFInput input) throws IOException { entry.put(tag, initTable(tag, input)); } private Object initTable(String name, TTFInput input) throws IOException { TTFTable table = null; for (int i = 0; i < TTFTable.TT_TAGS.length; i++) { if (name.equals(TTFTable.TT_TAGS[i])) { try { table = (TTFTable) TTFTable.TABLE_CLASSES[i].newInstance(); table.init(this, input); return table; } catch (Exception e) { e.printStackTrace(); return null; } } } System.err.println("Table '" + name + "' ignored."); return null; } public void show() { System.out.println("Tables:"); for (Iterator i = entry.values().iterator(); i.hasNext();) { System.out.println(i.next()); } } /** Returns the table with the given tag and reads it if necessary. */ public TTFTable getTable(String tag) throws IOException { TTFTable table = (TTFTable) entry.get(tag); if (!table.isRead()) table.read(); return table; } /** * Reads all tables. This method does not need to be called since the tables * are read on demand (getTable(). It might be useful to call * it in order to print out all available information. */ public void readAll() throws IOException { Iterator i = entry.values().iterator(); while (i.hasNext()) { TTFTable table = (TTFTable) i.next(); if ((table != null) && (!table.isRead())) table.read(); } } public void close() throws IOException { } } src/main/java/org/freehep/graphicsio/font/truetype/TTFInput.java0000644000175000017500000001031411312401775024242 0ustar user03user03package org.freehep.graphicsio.font.truetype; import java.io.IOException; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Stack; /** * Data input for true type files. All methods are named as the data formats in * the true type specification. * * @author Simon Fischer * @version $Id: TTFInput.java 8584 2006-08-10 23:06:37Z duns $ */ public abstract class TTFInput { private Stack filePosStack = new Stack(); private int tempFlags; // --------------- IO --------------- public abstract void seek(long offset) throws IOException; abstract long getPointer() throws IOException; public void pushPos() throws IOException { filePosStack.push(new Long(getPointer())); } public void popPos() throws IOException { seek(((Long) filePosStack.pop()).longValue()); } // ---------- Simple Data Types -------------- public abstract int readRawByte() throws IOException; public abstract int readByte() throws IOException; public abstract short readShort() throws IOException; public abstract int readUShort() throws IOException; public abstract long readULong() throws IOException; public abstract int readLong() throws IOException; public abstract byte readChar() throws IOException; public final short readFWord() throws IOException { return readShort(); } public final int readUFWord() throws IOException { return readUShort(); } public final double readFixed() throws IOException { int major = readShort(); int minor = readShort(); return (double) major + (double) minor / 16384d; } public final double readF2Dot14() throws IOException { int major = readByte(); int minor = readByte(); int fraction = minor + ((major & 0x3f) << 8); int mantissa = major >> 6; if (mantissa >= 2) mantissa -= 4; return (double) mantissa + (double) fraction / 16384d; } // ------------------------------------------------------------ public final void checkShortZero() throws IOException { if (readShort() != 0) { System.err.println("Reserved bit should be 0."); } } public static final boolean checkZeroBit(int b, int bit, String name) throws IOException { if (flagBit(b, bit)) { System.err.println("Reserved bit " + bit + " in " + name + " not 0."); return false; } else { return true; } } // ---------------- Flags -------------------- /** * Reads unsigned short flags into a temporary variable which can be queried * using the flagBit method. */ public void readUShortFlags() throws IOException { tempFlags = readUShort(); } /** * Reads byte flags into a temporary variable which can be queried using the * flagBit method. */ public void readByteFlags() throws IOException { tempFlags = readByte(); } public boolean flagBit(int bit) { return flagBit(tempFlags, bit); } public static boolean flagBit(int b, int bit) { return (b & (1 << bit)) > 0; } // ---------------- Arrays ------------------- public abstract void readFully(byte[] b) throws IOException; public int[] readFFFFTerminatedUShortArray() throws IOException { List values = new LinkedList(); int ushort = -1; do { ushort = readUShort(); values.add(new Integer(ushort)); } while (ushort != 0xFFFF); int[] shorts = new int[values.size()]; Iterator i = values.iterator(); int j = 0; while (i.hasNext()) { shorts[j++] = ((Integer) i.next()).intValue(); } return shorts; } public int[] readUShortArray(int n) throws IOException { int[] temp = new int[n]; for (int i = 0; i < temp.length; i++) temp[i] = readUShort(); return temp; } public short[] readShortArray(int n) throws IOException { short[] temp = new short[n]; for (int i = 0; i < temp.length; i++) temp[i] = readShort(); return temp; } } src/main/java/org/freehep/graphicsio/font/truetype/TTFMaxPTable.java0000644000175000017500000000304211312401775024760 0ustar user03user03// Copyright 2001, FreeHEP. package org.freehep.graphicsio.font.truetype; import java.io.IOException; /** * MAXP Table. * * @author Simon Fischer * @version $Id: TTFMaxPTable.java 8584 2006-08-10 23:06:37Z duns $ */ public class TTFMaxPTable extends TTFVersionTable { public int numGlyphs; public int maxPoints, maxContours; public int maxCompositePoints, maxCompositeContours; public int maxZones; public int maxTwilightPoints; public int maxStorage; public int maxFunctionDefs; public int maxInstructionDefs; public int maxStackElements; public int maxSizeOfInstructions; public int maxComponentElements; public int maxComponentDepth; public String getTag() { return "maxp"; } public void readTable() throws IOException { readVersion(); numGlyphs = ttf.readUShort(); maxPoints = ttf.readUShort(); maxContours = ttf.readUShort(); maxCompositePoints = ttf.readUShort(); maxCompositeContours = ttf.readUShort(); maxZones = ttf.readUShort(); maxTwilightPoints = ttf.readUShort(); maxStorage = ttf.readUShort(); maxFunctionDefs = ttf.readUShort(); maxInstructionDefs = ttf.readUShort(); maxStackElements = ttf.readUShort(); maxSizeOfInstructions = ttf.readUShort(); maxComponentElements = ttf.readUShort(); maxComponentDepth = ttf.readUShort(); } public String toString() { return super.toString() + "\n" + " numGlyphs: " + numGlyphs; } } src/main/java/org/freehep/graphicsio/font/truetype/TTFNameTable.java0000644000175000017500000000566111312401775025004 0ustar user03user03// Copyright 2001, FreeHEP. package org.freehep.graphicsio.font.truetype; import java.io.IOException; /** * NAME Table. * * @author Mark Donszelmann * @version $Id: TTFNameTable.java 8584 2006-08-10 23:06:37Z duns $ */ public class TTFNameTable extends TTFTable { private int format; private int numberOfNameRecords; private int stringStorage; private String[][] name = new String[4][19]; // 18 NameIDs according to // OpenType public String getTag() { return "name"; } // FIXME: fixed decoding for lucida files // PID = 0, -> UnicodeBig (Apple-Unicode-English) // PID = 1, EID = 0, LID = 0; -> Default Encoding (Mac-Roman-English) // PID = 3, EID = 1, LID = 1033; -> UnicodeBig (Win-UGL-ENU) // LID english, other languages ignored public void readTable() throws IOException { format = ttf.readUShort(); numberOfNameRecords = ttf.readUShort(); stringStorage = ttf.readUShort(); for (int i = 0; i < numberOfNameRecords; i++) { int pid = ttf.readUShort(); int eid = ttf.readUShort(); int lid = ttf.readUShort(); int nid = ttf.readUShort(); int stringLen = ttf.readUShort(); int stringOffset = ttf.readUShort(); // long pos = ttf.getFilePointer(); ttf.pushPos(); ttf.seek(stringStorage + stringOffset); byte[] b = new byte[stringLen]; ttf.readFully(b); if (pid == 0) { // Apple Unicode name[pid][nid] = new String(b, "UnicodeBig"); } else if ((pid == 1) && (eid == 0)) { if (lid == 0) { // Mac-Roman-English name[pid][nid] = new String(b, "ISO8859-1"); } // ignore other languages } else if ((pid == 3) && (eid == 1)) { // Win-UGL if (lid == 0x0409) { // ENU name[pid][nid] = new String(b, "UnicodeBig"); } // ignore other languages } else { System.out.println("Unimplemented PID, EID, LID scheme: " + pid + ", " + eid + ", " + lid); System.out.println("NID = " + nid); name[pid][nid] = new String(b, "Default"); } ttf.popPos(); // ttf.seek(pos); } } public String toString() { StringBuffer s = new StringBuffer(); s.append(super.toString() + "\n"); s.append(" format: " + format); for (int i = 0; i < name.length; i++) { for (int j = 0; j < name[i].length; j++) { if (name[i][j] != null) { s.append("\n name[" + i + "][" + j + "]: " + name[i][j]); } } } return s.toString(); } } src/main/java/org/freehep/graphicsio/font/truetype/TTFOpenType.java0000644000175000017500000000222211312401775024705 0ustar user03user03// Copyright 2001, FreeHEP. package org.freehep.graphicsio.font.truetype; import java.awt.font.OpenType; import java.io.IOException; /** * Conrete implementation of a TrueType font, attached to a JavaFont which * implements the OpenType interface. * * FIXME: Test as soon as some Java Fonts implements OpenType. Probably * TTFMemoryInput won't work. Tag names may be different for OpenType and * TrueType. * * @author Simon Fischer * @version $Id: TTFOpenType.java 8584 2006-08-10 23:06:37Z duns $ */ public class TTFOpenType extends TTFFont { private OpenType openType; public TTFOpenType(OpenType openType) throws IOException { this.openType = openType; for (int i = 0; i < TTFTable.TT_TAGS.length; i++) { byte[] data = openType.getFontTable(TTFTable.TT_TAGS[i]); if (data != null) { newTable(TTFTable.TT_TAGS[i], new TTFMemoryInput(data)); } else { System.err.println("No table found for '" + TTFTable.TT_TAGS[i] + "'."); } } } public int getFontVersion() { return openType.getVersion(); } } src/main/java/org/freehep/graphicsio/font/truetype/TTFFileInput.java0000644000175000017500000000425711312401775025053 0ustar user03user03package org.freehep.graphicsio.font.truetype; import java.io.IOException; import java.io.RandomAccessFile; /** * Concrete implementation of the TrueType Input for one Table, read from a TTF * File. * * Reads one table from the file. * * @author Simon Fischer * @version $Id: TTFFileInput.java 8584 2006-08-10 23:06:37Z duns $ */ public class TTFFileInput extends TTFInput { private RandomAccessFile ttf; private long offset, length, checksum; public TTFFileInput(RandomAccessFile file, long offset, long length, long checksum) throws IOException { this.ttf = file; this.offset = offset; this.length = length; this.checksum = checksum; } // --------------- IO --------------- public void seek(long offset) throws IOException { ttf.seek(this.offset + offset); // System.out.println("seek "+(this.offset+offset)); } long getPointer() throws IOException { return ttf.getFilePointer() - offset; } // ---------- Simple Data Types -------------- public int readByte() throws IOException { return ttf.readUnsignedByte(); } public int readRawByte() throws IOException { return ttf.readByte() & 255; } public short readShort() throws IOException { return ttf.readShort(); } public int readUShort() throws IOException { return ttf.readUnsignedShort(); } public int readLong() throws IOException { return ttf.readInt(); } public long readULong() throws IOException { byte[] temp = new byte[4]; ttf.readFully(temp); long l = 0; long weight = 1; for (int i = 0; i < temp.length; i++) { // l |= (temp[3-i]&255) << (8*i); l += (temp[3 - i] & 255) * weight; weight *= 256; } return l; } public byte readChar() throws IOException { return ttf.readByte(); } // ---------------- Arrays ------------------- public void readFully(byte[] b) throws IOException { ttf.readFully(b); } public String toString() { return offset + "-" + (offset + length - 1) + " - " + checksum; } } src/main/java/org/freehep/graphicsio/font/truetype/TTFMemoryInput.java0000644000175000017500000000314611312401775025440 0ustar user03user03package org.freehep.graphicsio.font.truetype; /** * FIXME: These methods are not really tested yet. * * @author Simon Fischer * @version $Id: TTFMemoryInput.java 8584 2006-08-10 23:06:37Z duns $ */ public class TTFMemoryInput extends TTFInput { private byte[] data; private int pointer; public TTFMemoryInput(byte[] data) { this.data = data; } public void seek(long offset) { pointer = (int) offset; } long getPointer() { return pointer; } // ---------- Simple Data Types -------------- public byte readChar() { return data[pointer++]; } public int readRawByte() { return data[pointer++] & 0x00ff; } public int readByte() { return data[pointer++] & 0x00ff; } public short readShort() { int result = data[pointer++]; return (short) ((result << 8) | data[pointer++]); } public int readUShort() { return (data[pointer++] << 8) | data[pointer++]; } public int readLong() { int result = data[pointer++]; return (short) ((result << 24) | data[pointer++] << 16 | data[pointer++] << 8 | data[pointer++]); } public long readULong() { byte[] temp = new byte[4]; readFully(temp); long l = 0; for (int i = 0; i < temp.length; i++) { l |= (temp[3 - i] & 255) << (8 * i); } return l; } // ---------------- Arrays ------------------- public void readFully(byte[] b) { for (int i = 0; i < b.length; i++) { b[i] = data[pointer++]; } } } src/main/java/org/freehep/graphicsio/font/truetype/TTFHMtxTable.java0000644000175000017500000000315311312401775024776 0ustar user03user03// Copyright 2001, FreeHEP. package org.freehep.graphicsio.font.truetype; import java.io.IOException; /** * HMTX Table. * * @author Simon Fischer * @version $Id: TTFHMtxTable.java 8584 2006-08-10 23:06:37Z duns $ */ public class TTFHMtxTable extends TTFTable { public int[] advanceWidth; public short[] leftSideBearing; public short[] leftSideBearing2; public String getTag() { return "hmtx"; } public void readTable() throws IOException { int numberOfHMetrics = ((TTFHHeaTable) getTable("hhea")).numberOfHMetrics; int numGlyphs = ((TTFMaxPTable) getTable("maxp")).numGlyphs; advanceWidth = new int[numberOfHMetrics]; leftSideBearing = new short[numberOfHMetrics]; for (int i = 0; i < numberOfHMetrics; i++) { advanceWidth[i] = ttf.readUFWord(); leftSideBearing[i] = ttf.readFWord(); } leftSideBearing2 = ttf.readShortArray(numGlyphs - numberOfHMetrics); } public String toString() { String str = super.toString(); str += "\n hMetrics[" + advanceWidth.length + "] = {"; for (int i = 0; i < advanceWidth.length; i++) { if (i % 8 == 0) str += "\n "; str += "(" + advanceWidth[i] + "," + leftSideBearing[i] + ") "; } str += "\n }"; str += "\n lsb[" + leftSideBearing2.length + "] = {"; for (int i = 0; i < leftSideBearing2.length; i++) { if (i % 16 == 0) str += "\n "; str += leftSideBearing2[i] + " "; } str += "\n }"; return str; } } src/main/java/org/freehep/graphicsio/font/truetype/TTFGlyfTable.java0000644000175000017500000002737111312401775025027 0ustar user03user03// Copyright 2001-2006, FreeHEP. package org.freehep.graphicsio.font.truetype; import java.awt.Rectangle; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.io.IOException; /** * GLYPH Table. * * @author Simon Fischer * @version $Id: TTFGlyfTable.java 8584 2006-08-10 23:06:37Z duns $ */ public class TTFGlyfTable extends TTFVersionTable { /** * If this variable is set to false then the glyphs will not be read until * they are retrieved with getGlyph(int). */ private static final boolean READ_GLYPHS = false; public abstract class Glyph { public int xMin, yMin, xMax, yMax; public abstract String getType(); public abstract GeneralPath getShape(); public void read() throws IOException { xMin = ttf.readFWord(); yMin = ttf.readFWord(); xMax = ttf.readFWord(); yMax = ttf.readFWord(); } public Rectangle getBBox() { return new Rectangle(xMin, yMin, xMax - xMin, yMax - yMin); } public String toString() { return "[" + getType() + "] (" + xMin + "," + yMin + "):(" + xMax + "," + yMax + ")"; } public String toDetailedString() { return toString(); } } // -------------------------------------------------------------------------------- public class SimpleGlyph extends Glyph { private static final int ON_CURVE = 0; private static final int X_SHORT = 1; private static final int Y_SHORT = 2; private static final int REPEAT_FLAG = 3; private static final int X_SAME = 4; private static final int Y_SAME = 5; private static final int X_POSITIVE = 4; private static final int Y_POSITIVE = 5; public int numberOfContours; public int[] endPtsOfContours; public int[] instructions; public int[] flags; public int[] xCoordinates, yCoordinates; public boolean[] onCurve; public GeneralPath shape; public SimpleGlyph(int numberOfContours) { this.numberOfContours = numberOfContours; this.endPtsOfContours = new int[numberOfContours]; } public String getType() { return "Simple Glyph"; } public void read() throws IOException { super.read(); for (int i = 0; i < endPtsOfContours.length; i++) endPtsOfContours[i] = ttf.readUShort(); instructions = new int[ttf.readUShort()]; for (int i = 0; i < instructions.length; i++) instructions[i] = ttf.readByte(); int numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1; flags = new int[numberOfPoints]; xCoordinates = new int[numberOfPoints]; yCoordinates = new int[numberOfPoints]; onCurve = new boolean[numberOfPoints]; int repeatCount = 0; int repeatFlag = 0; for (int i = 0; i < numberOfPoints; i++) { if (repeatCount > 0) { flags[i] = repeatFlag; repeatCount--; } else { flags[i] = ttf.readRawByte(); if (TTFInput.flagBit(flags[i], REPEAT_FLAG)) { repeatCount = ttf.readByte(); repeatFlag = flags[i]; } } TTFInput.checkZeroBit(flags[i], 6, "flags"); TTFInput.checkZeroBit(flags[i], 7, "flags"); onCurve[i] = TTFInput.flagBit(flags[i], ON_CURVE); } int last = 0; for (int i = 0; i < numberOfPoints; i++) { if (TTFInput.flagBit(flags[i], X_SHORT)) { if (TTFInput.flagBit(flags[i], X_POSITIVE)) { last = xCoordinates[i] = last + ttf.readByte(); } else { last = xCoordinates[i] = last - ttf.readByte(); } } else { if (TTFInput.flagBit(flags[i], X_SAME)) { last = xCoordinates[i] = last; } else { last = xCoordinates[i] = last + ttf.readShort(); } } } last = 0; for (int i = 0; i < numberOfPoints; i++) { if (TTFInput.flagBit(flags[i], Y_SHORT)) { if (TTFInput.flagBit(flags[i], Y_POSITIVE)) { last = yCoordinates[i] = last + ttf.readByte(); } else { last = yCoordinates[i] = last - ttf.readByte(); } } else { if (TTFInput.flagBit(flags[i], Y_SAME)) { last = yCoordinates[i] = last; } else { last = yCoordinates[i] = last + ttf.readShort(); } } } } public String toString() { String str = super.toString() + ", " + numberOfContours + " contours, endPts={"; for (int i = 0; i < numberOfContours; i++) str += (i == 0 ? "" : ",") + endPtsOfContours[i]; str += "}, " + instructions.length + " instructions"; return str; } public String toDetailedString() { String str = toString() + "\n instructions = {"; for (int i = 0; i < instructions.length; i++) { str += Integer.toHexString(instructions[i]) + " "; } return str + "}"; } public GeneralPath getShape() { if (shape != null) { return shape; } shape = new GeneralPath(GeneralPath.WIND_NON_ZERO); int p = 0; for (int i = 0; i < endPtsOfContours.length; i++) { int startIndex = p++; shape.moveTo(xCoordinates[startIndex], yCoordinates[startIndex]); boolean lastOnCurve = true; while (p <= endPtsOfContours[i]) { if (onCurve[p]) { if (lastOnCurve) { shape.lineTo(xCoordinates[p], yCoordinates[p]); } else { shape.quadTo(xCoordinates[p - 1], yCoordinates[p - 1], xCoordinates[p], yCoordinates[p]); } lastOnCurve = true; } else { if (!lastOnCurve) { int x1 = xCoordinates[p - 1]; int y1 = yCoordinates[p - 1]; int x2 = (int)((x1 + xCoordinates[p])/ 2.0); int y2 = (int)((y1 + yCoordinates[p])/ 2.0); shape.quadTo(x1, y1, x2, y2); } lastOnCurve = false; } p++; } if (!onCurve[p - 1]) { shape.quadTo(xCoordinates[p - 1], yCoordinates[p - 1], xCoordinates[startIndex], yCoordinates[startIndex]); } else if ((xCoordinates[p - 1] != xCoordinates[startIndex]) || (yCoordinates[p - 1] != yCoordinates[startIndex])) { shape.closePath(); } } return shape; } } // -------------------------------------------------------------------------------- public class CompositeGlyph extends Glyph { private static final int ARGS_WORDS = 0; private static final int ARGS_XY = 1; private static final int SCALE = 3; private static final int XY_SCALE = 6; private static final int TWO_BY_TWO = 7; private static final int MORE_COMPONENTS = 5; private GeneralPath shape; private int noComponents; public String getType() { return "Composite Glyph"; } public GeneralPath getShape() { return shape; } public void read() throws IOException { super.read(); shape = new GeneralPath(); noComponents = 0; boolean more = true; while (more) { noComponents++; ttf.readUShortFlags(); more = ttf.flagBit(MORE_COMPONENTS); int glyphIndex = ttf.readUShort(); int arg1, arg2; if (ttf.flagBit(ARGS_WORDS)) { arg1 = ttf.readShort(); arg2 = ttf.readShort(); } else { arg1 = ttf.readChar(); arg2 = ttf.readChar(); } AffineTransform t = new AffineTransform(); if (ttf.flagBit(ARGS_XY)) { t.translate(arg1, arg2); } else { System.err .println("TTFGlyfTable: ARGS_ARE_POINTS not implemented."); } if (ttf.flagBit(SCALE)) { double scale = ttf.readF2Dot14(); t.scale(scale, scale); } else if (ttf.flagBit(XY_SCALE)) { double scaleX = ttf.readF2Dot14(); double scaleY = ttf.readF2Dot14(); t.scale(scaleX, scaleY); } else if (ttf.flagBit(TWO_BY_TWO)) { System.err .println("TTFGlyfTable: WE_HAVE_A_TWO_BY_TWO not implemented."); } GeneralPath appendGlyph = (GeneralPath) getGlyph(glyphIndex) .getShape().clone(); appendGlyph.transform(t); shape.append(appendGlyph, false); } } public String toString() { return super.toString() + ", " + noComponents + " components"; } } // -------------------------------------------------------------------------------- public Glyph[] glyphs; private long[] offsets; public String getTag() { return "glyf"; } public void readTable() throws IOException { glyphs = new Glyph[((TTFMaxPTable) getTable("maxp")).numGlyphs]; offsets = ((TTFLocaTable) getTable("loca")).offset; if (READ_GLYPHS) { for (int i = 0; i < glyphs.length; i++) { if ((i > 0) && (offsets[i - 1] == offsets[i])) { glyphs[i] = glyphs[i - 1]; } else { try { getGlyph(i); } catch (IOException e) { System.err.println("While reading glyph #" + i + " (offset " + offsets[i] + "):"); e.printStackTrace(); } } } } } public Glyph getGlyph(int i) throws IOException { if (glyphs[i] != null) { return glyphs[i]; } else { ttf.pushPos(); ttf.seek(offsets[i]); int numberOfContours = ttf.readShort(); if (numberOfContours >= 0) glyphs[i] = new SimpleGlyph(numberOfContours); else glyphs[i] = new CompositeGlyph(); glyphs[i].read(); // System.out.println(i+": "+offsets[i]+"-"+ttf.getPointer()); ttf.popPos(); return glyphs[i]; } } public String toString() { String str = super.toString(); for (int i = 0; i < glyphs.length; i++) str += "\n #" + i + ": " + glyphs[i]; return str; } } src/main/java/org/freehep/graphicsio/font/truetype/TTFHHeaTable.java0000644000175000017500000000301711312401775024722 0ustar user03user03package org.freehep.graphicsio.font.truetype; import java.io.IOException; /** * HHEA Table. * * @author Simon Fischer * @version $Id: TTFHHeaTable.java 8584 2006-08-10 23:06:37Z duns $ */ public class TTFHHeaTable extends TTFVersionTable { public short ascender, descender, lineGap; public int advanceWidthMax; public short minLeftSideBearing, minRightSideBearing; public short xMaxExtent; public short caretSlopeRise, caretSlopeRun; public short metricDataFormat; public int numberOfHMetrics; public String getTag() { return "hhea"; } public void readTable() throws IOException { readVersion(); ascender = ttf.readFWord(); descender = ttf.readFWord(); lineGap = ttf.readFWord(); advanceWidthMax = ttf.readUFWord(); minLeftSideBearing = ttf.readFWord(); minRightSideBearing = ttf.readFWord(); xMaxExtent = ttf.readFWord(); caretSlopeRise = ttf.readShort(); caretSlopeRun = ttf.readShort(); for (int i = 0; i < 5; i++) ttf.checkShortZero(); metricDataFormat = ttf.readShort(); numberOfHMetrics = ttf.readUShort(); } public String toString() { String str = super.toString(); str += "\n asc:" + ascender + " desc:" + descender + " lineGap:" + lineGap + " maxAdvance:" + advanceWidthMax; str += "\n metricDataFormat:" + metricDataFormat + " #HMetrics:" + numberOfHMetrics; return str; } } src/main/java/org/freehep/graphicsio/font/truetype/TTFLocaTable.java0000644000175000017500000000200511312401775024767 0ustar user03user03// Copyright 2001, FreeHEP. package org.freehep.graphicsio.font.truetype; import java.io.IOException; /** * LOCA Table. * * @author Simon Fischer * @version $Id: TTFLocaTable.java 8584 2006-08-10 23:06:37Z duns $ */ public class TTFLocaTable extends TTFTable { public long offset[]; public String getTag() { return "loca"; } public void readTable() throws IOException { short format = ((TTFHeadTable) getTable("head")).indexToLocFormat; int numGlyphs = ((TTFMaxPTable) getTable("maxp")).numGlyphs + 1; offset = new long[numGlyphs]; for (int i = 0; i < numGlyphs; i++) { offset[i] = (format == TTFHeadTable.ITLF_LONG ? ttf.readULong() : ttf.readUShort() * 2); } } public String toString() { String str = super.toString(); for (int i = 0; i < offset.length; i++) { if (i % 16 == 0) str += "\n "; str += offset[i] + " "; } return str; } } src/main/java/org/freehep/graphicsio/font/truetype/TTFVersionTable.java0000644000175000017500000000113411312401775025540 0ustar user03user03// Copyright 2001, FreeHEP. package org.freehep.graphicsio.font.truetype; import java.io.IOException; /** * VERSION Table. * * @author Simon Fischer * @version $Id: TTFVersionTable.java 8584 2006-08-10 23:06:37Z duns $ */ public abstract class TTFVersionTable extends TTFTable { public int minorVersion; public int majorVersion; public void readVersion() throws IOException { majorVersion = ttf.readUShort(); minorVersion = ttf.readUShort(); } public String toString() { return super.toString() + " v" + majorVersion + "." + minorVersion; } } src/main/java/org/freehep/graphicsio/font/truetype/TTFCMapTable.java0000644000175000017500000001233711312401775024742 0ustar user03user03// Copyright 2001, FreeHEP. package org.freehep.graphicsio.font.truetype; import java.io.IOException; /** * CMAP Table. * * @author Simon Fischer * @version $Id: TTFCMapTable.java 8584 2006-08-10 23:06:37Z duns $ */ public class TTFCMapTable extends TTFTable { public class EncodingTable { public int platformID; public int encodingID; public long offset; public int format; public int length; public int version; public TableFormat tableFormat; public void readHeader() throws IOException { platformID = ttf.readUShort(); encodingID = ttf.readUShort(); offset = ttf.readULong(); } public void readBody() throws IOException { ttf.seek(offset); format = ttf.readUShort(); length = ttf.readUShort(); version = ttf.readUShort(); switch (format) { case 0: tableFormat = new TableFormat0(); break; case 4: tableFormat = new TableFormat4(); break; case 2: case 6: System.err.println("Unimplementet encoding table format: " + format); break; default: System.err.println("Illegal value for encoding table format: " + format); break; } if (tableFormat != null) tableFormat.read(); } public String toString() { String str = "[encoding] PID:" + platformID + " EID:" + encodingID + " format:" + format + " v" + version + (tableFormat != null ? tableFormat.toString() : " [no data read]"); return str; } } public abstract class TableFormat { public abstract void read() throws IOException; public abstract int getGlyphIndex(int character); } public class TableFormat0 extends TableFormat { public int[] glyphIdArray = new int[256]; public void read() throws IOException { for (int i = 0; i < glyphIdArray.length; i++) glyphIdArray[i] = ttf.readByte(); } public String toString() { String str = ""; for (int i = 0; i < glyphIdArray.length; i++) { if (i % 16 == 0) str += "\n " + Integer.toHexString(i / 16) + "x: "; String number = glyphIdArray[i] + ""; while (number.length() < 3) number = " " + number; str += number + " "; } return str; } public int getGlyphIndex(int character) { return glyphIdArray[character]; } } public class TableFormat4 extends TableFormat { public int segCount; public int[] endCount, startCount, idRangeOffset; public short[] idDelta; // could be int (ushort) as well public void read() throws IOException { segCount = ttf.readUShort() / 2; // dump the next three ushorts to /dev/null as they guy // who invented them really must have drunk a lot ttf.readUShort(); ttf.readUShort(); ttf.readUShort(); // endCount = readFFFFTerminatedUShortArray(); endCount = ttf.readUShortArray(segCount); int reservedPad = ttf.readUShort(); if (reservedPad != 0) System.err.println("reservedPad not 0, but " + reservedPad + "."); startCount = ttf.readUShortArray(endCount.length); // the deltas should be unsigned, but due to // modulo arithmetic it makes no difference idDelta = ttf.readShortArray(endCount.length); idRangeOffset = ttf.readUShortArray(endCount.length); } public String toString() { String str = "\n " + endCount.length + " sections:"; for (int i = 0; i < endCount.length; i++) str += "\n " + startCount[i] + " to " + endCount[i] + " : " + idDelta[i] + " (" + idRangeOffset[i] + ")"; return str; } public int getGlyphIndex(int character) { return 0; } } public int version; public EncodingTable encodingTable[]; public String getTag() { return "cmap"; } public void readTable() throws IOException { version = ttf.readUShort(); encodingTable = new EncodingTable[ttf.readUShort()]; for (int i = 0; i < encodingTable.length; i++) { encodingTable[i] = new EncodingTable(); encodingTable[i].readHeader(); } for (int i = 0; i < encodingTable.length; i++) { encodingTable[i].readBody(); } } public String toString() { String str = super.toString() + " v" + version; for (int i = 0; i < encodingTable.length; i++) str += "\n " + encodingTable[i]; return str; } } src/main/java/org/freehep/graphicsio/font/FontTable.java0000644000175000017500000001632111312401775022566 0ustar user03user03// Copyright 2001-2007 freehep package org.freehep.graphicsio.font; import java.awt.Font; import java.awt.font.TextAttribute; import java.io.IOException; import java.util.Collection; import java.util.Hashtable; import java.util.Map; import org.freehep.graphics2d.font.CharTable; import org.freehep.graphics2d.font.FontUtilities; import org.freehep.graphics2d.font.Lookup; /** * A table to remember which fonts were used while writing a document. * * @author Simon Fischer * @version $Id: FontTable.java 10516 2007-02-06 21:11:19Z duns $ */ public abstract class FontTable { protected class Entry { private Font font; private String ref; private CharTable encoding; private boolean written; private Entry(Font f, CharTable encoding) { // get attributes of font for the stored default font Map/**/ attributes = FontUtilities.getAttributes(f); // set default font size attributes.put(TextAttribute.SIZE, new Float(FontEmbedder.FONT_SIZE)); // remove font transformations attributes.remove(TextAttribute.TRANSFORM); attributes.remove(TextAttribute.SUPERSCRIPT); this.font = new Font(attributes); this.ref = createFontReference(this.font); this.encoding = encoding; this.written = false; } public Font getFont() { return font; } public String getReference() { return ref; } protected void setReference(String ref) { this.ref = ref; } public CharTable getEncoding() { return encoding; } public void setWritten(boolean written) { this.written = written; } public boolean isWritten() { return written; } public String toString() { return ref + "=" + font; } } private Hashtable table; public FontTable() { this.table = new Hashtable(); } /** * Returns a default CharTable to be used for normal text (not Symbol or * Dingbats). */ public abstract CharTable getEncodingTable(); /** * Called whenever a specific font is used for the first time. Subclasses * may use this method to include the font instantly. This method may change * the value of the reference by calling e.setReference(String) * e.g. if it wants to substitute the font by a standard font that can be * addressed under a name different from the generated one. */ protected abstract void firstRequest(Entry e, boolean embed, String embedAs) throws IOException; /** Creates a unique reference to address this font. */ protected abstract String createFontReference(Font f); protected abstract Font substituteFont(Font font); /** * Returns a name for this font that can be used in the document. A new name * is generated if the font was not used yet. For different fontsizes the * same name is returned. */ public String fontReference(Font font, boolean embed, String embedAs) { // look for stored font font = substituteFont(font); String key = getKey(font); Entry e = (Entry) table.get(key); // create new one if (e == null) { e = new Entry(font, getEncodingTable(font)); try { firstRequest(e, embed, embedAs); } catch (IOException exc) { exc.printStackTrace(); } table.put(key, e); } return e.ref; } /** * To embed all derivations of a font too (with underline, * strikethrough etc.) the key consists all these attributes. * * @param font ist attributes are used * @return something like Helvetica[BOLD:1][ITALIC:0][UNDERLINE:1] */ private String getKey(Font font) { Map/**/ attributes = FontUtilities.getAttributes(font); StringBuffer result = new StringBuffer(font.getName()); // bold result.append("[WEIGHT:"); result.append(attributes.get(TextAttribute.WEIGHT)); result.append("]"); // italic result.append("[POSTURE:"); result.append(attributes.get(TextAttribute.POSTURE)); result.append("]"); // underline is not handled as an font property // result.append("[UNDERLINE:"); // result.append(attributes.get(TextAttribute.UNDERLINE)); // result.append("]"); // strike through is not handled as an font property // result.append("[STRIKETHROUGH:"); // result.append(attributes.get(TextAttribute.STRIKETHROUGH)); // result.append("]"); // SUPERSCRIPT is apllied by font.getTransformation() // leave this as a reminder! // result.append("["); // result.append(attributes.get(TextAttribute.SUPERSCRIPT)); // result.append("]"); // width is not handled as an font property // result.append("[WIDTH:"); // result.append(attributes.get(TextAttribute.WIDTH)); // result.append("]"); return result.toString(); } /** * creates a normalized attribute map, e.g. * java.awt.Font[family=Dialog,name=dialog.bold,style=plain,size=20] * becomes * java.awt.Font[family=Dialog,name=Dialog,style=bold,size=20] * * @param attributes */ public static void normalize(Map/**/ attributes) { // get name String family = (String) attributes.get(TextAttribute.FAMILY); // Java font names could end with ".plain" ".bold" // and ".italic". We have to convert this to an // attribute first if (family.toLowerCase().endsWith(".bold")) { attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); // cut the ".bold" int pos = family.toLowerCase().indexOf(".bold"); family = family.substring(0, pos); } else if (family.toLowerCase().endsWith(".italic")) { attributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); // cut the ".italic" int pos = family.toLowerCase().indexOf(".italic"); family = family.substring(0, pos); } else if (family.toLowerCase().endsWith(".plain")) { // cut the ".plain" int pos = family.toLowerCase().indexOf(".plain"); family = family.substring(0, pos); } // first character up family = family.substring(0, 1).toUpperCase() + family.substring(1, family.length()); attributes.put(TextAttribute.FAMILY, family); } /** * Returns a Collection view of all fonts. The elements of the collection * are Entries. */ public Collection getEntries() { return table.values(); } private CharTable getEncodingTable(Font font) { String fontname = font.getName().toLowerCase(); if (fontname.indexOf("symbol") >= 0) return Lookup.getInstance().getTable("Symbol"); if (fontname.indexOf("zapfdingbats") >= 0) return Lookup.getInstance().getTable("Zapfdingbats"); return getEncodingTable(); } } src/main/java/org/freehep/graphicsio/font/FontEmbedderType1.java0000644000175000017500000002056111312401775024172 0ustar user03user03// Copyright 2001-2005 freehep package org.freehep.graphicsio.font; import java.awt.Shape; import java.awt.font.FontRenderContext; import java.awt.font.GlyphMetrics; import java.awt.geom.Rectangle2D; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import org.freehep.graphics2d.font.CharTable; import org.freehep.util.io.ASCIIHexOutputStream; import org.freehep.util.io.CountedByteOutputStream; import org.freehep.util.io.EEXECEncryption; /** * Font embedder for type 1 fonts. The output can be directly fed into a ps file * or as a FontFile to a pdf file. *

Todo

*
    *
  • use subroutines for accents *
  • add more hints *
* * @author Simon Fischer * @version $Id: FontEmbedderType1.java 8584 2006-08-10 23:06:37Z duns $ */ public class FontEmbedderType1 extends FontEmbedder { /** Defines whether or not eexec encryption is used. */ private static final boolean ENCRYPT = true; /** * Defines whether or not encrypted part should be hex encoded (otherwise it * is binary). */ private static final boolean HEX_ENC = true; /** * Defines whether or not encrypted charstrings should be hex encoded * Ghostview crashes when set to true. The freehep ps interpreter handles it * correctly. */ private static final boolean HEX_ENC_CHARSTRINGS = false; private PrintStream fontFile, encrypted; private CountedByteOutputStream byteCounter; private int asciiEnd, encEnd; // remember the lengths of the three // portions private boolean addZeros; public FontEmbedderType1(FontRenderContext context, OutputStream out, boolean addZeros) { super(context); this.byteCounter = new CountedByteOutputStream(out); this.fontFile = new PrintStream(byteCounter); this.addZeros = addZeros; asciiEnd = encEnd = -1; } protected void writeWidths(double[] w) throws IOException { } protected void writeEncoding(CharTable t) throws IOException { fontFile.println("/Encoding 256 array"); fontFile.println("0 1 255 {1 index exch /.notdef put} for"); // set // undefined // to // .notdef // ?? for (int i = 0; i < 256; i++) { String charName = t.toName(i); if (charName != null) fontFile.println("dup " + i + " /" + charName + " put"); } fontFile.println("readonly def"); } protected void openIncludeFont() throws IOException { // begin clear text ascii portion fontFile.println("%!FontType1-1.0: " + getFont().getName()); // unknown // version // number // fontFile.println("%%CreationDate: " + // DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL). // format(new Date())); fontFile.println("% Generated by: " + getClass().getName()); fontFile.println("11 dict begin"); fontFile.println("/FontInfo 8 dict dup begin"); fontFile.println("/FullName (" + getFont().getPSName() + ") readonly def"); fontFile.println("/FamilyName (" + getFont().getFamily() + ") readonly def"); fontFile.println("end readonly def"); fontFile.println("/FontName /" + getFontName() + " def"); fontFile.println("/PaintType 0 def"); fontFile.println("/FontType 1 def"); fontFile.println("/FontMatrix [" + 1 / FONT_SIZE + " 0.0 0.0 " + 1 / FONT_SIZE + " 0.0 0.0] readonly def"); } protected void closeIncludeFont() { Rectangle2D boundingBox = getFontBBox(); int llx = (int) Math.round(boundingBox.getX()); int lly = (int) Math.round(boundingBox.getY()); int urx = (int) Math.round(boundingBox.getX() + boundingBox.getWidth()); int ury = (int) Math .round(boundingBox.getY() + boundingBox.getHeight()); fontFile.println("/FontBBox {" + llx + " " + lly + " " + urx + " " + ury + "} readonly def"); fontFile.println("currentdict end"); // begin encrypted portion if (ENCRYPT) { fontFile.print("currentfile eexec "); asciiEnd = byteCounter.getCount(); } fontFile.flush(); } protected void openGlyphs() throws IOException { // begin encryption if (ENCRYPT) { if (HEX_ENC) { encrypted = new PrintStream(new EEXECEncryption( new ASCIIHexOutputStream(fontFile), EEXECEncryption.EEXEC_R)); } else { encrypted = new PrintStream(new EEXECEncryption(fontFile, EEXECEncryption.EEXEC_R)); } } else { encrypted = fontFile; } // begin the Private dictionary encrypted.println("dup /Private 8 dict dup begin"); encrypted .println("/RD {string currentfile exch readstring pop} executeonly def"); encrypted.println("/ND {noaccess def} executeonly def"); encrypted.println("/NP {noaccess put} executeonly def"); encrypted.println("/BlueValues [] def"); // ??? encrypted.println("/MinFeature {16 16} def"); encrypted.println("/password 5839 def"); encrypted.print("2 index "); encrypted.println("/CharStrings " + (getNODefinedChars() + 1) + " dict dup begin"); } protected void closeGlyphs() throws IOException { encrypted.println("end"); // end Private encrypted.println("end"); // end CharStrings } protected void closeEmbedFont() throws IOException { encrypted.println("readonly put"); encrypted.println("noaccess put"); encrypted.println("dup /FontName get exch definefont pop"); encrypted.print("mark"); if (ENCRYPT) { encrypted.print(" currentfile closefile "); } encrypted.flush(); encEnd = byteCounter.getCount(); if (!ENCRYPT) asciiEnd = encEnd; if (addZeros) { fontFile.println(); for (int i = 0; i < 16; i++) fontFile.println("00000000000000000000000000000000"); fontFile.println("cleartomark"); } } protected void writeGlyph(String characterName, Shape glyph, GlyphMetrics glyphMetrics) throws IOException { // FIXME: find out why Acrobat Reader displays some characters displaced // when // using the correct sidebearing. A value of 0 looks good double sidebearing = glyphMetrics != null ? glyphMetrics.getLSB() : 0; // double sidebearing = 0; // write the binary charstring to a buffer ByteArrayOutputStream bytes = new ByteArrayOutputStream(); CharstringEncoder charString = (HEX_ENC_CHARSTRINGS ? new CharstringEncoder( new EEXECEncryption(new ASCIIHexOutputStream(bytes), EEXECEncryption.CHARSTRING_R)) : new CharstringEncoder(new EEXECEncryption(bytes, EEXECEncryption.CHARSTRING_R))); charString.startChar(sidebearing, (glyphMetrics != null ? glyphMetrics .getAdvance() : getUndefinedWidth())); // bounds.getWidth()); charString.drawPath(glyph); charString.endchar(); // write the buffer to the encrypted fontFile byte[] binaryString = bytes.toByteArray(); encrypted.print("/" + characterName + " " + binaryString.length + " RD "); for (int i = 0; i < binaryString.length; i++) { encrypted.write(binaryString[i] & 0x00ff); } encrypted.println("ND"); encrypted.flush(); } /** Returns the length of the ascii portion of the output. */ public int getAsciiLength() { return asciiEnd; } /** Returns the length of the encrypted portion of the output. */ public int getEncryptedLength() { return encEnd - asciiEnd; } } src/main/java/org/freehep/graphicsio/VectorGraphicsIO.java0000644000175000017500000000423511312401775023116 0ustar user03user03// Copyright 2000-2002 FreeHEP package org.freehep.graphicsio; import java.awt.Dimension; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintStream; import java.io.PrintWriter; import org.freehep.graphics2d.AbstractVectorGraphics; /** * This class provides specifies added methods for VectorGraphicsIO. All added * methods are declared abstract. * * @author Charles Loomis * @author Mark Donszelmann * @version $Id: VectorGraphicsIO.java 8584 2006-08-10 23:06:37Z duns $ */ public abstract class VectorGraphicsIO extends AbstractVectorGraphics { public VectorGraphicsIO() { super(); } public VectorGraphicsIO(VectorGraphicsIO graphics) { super(graphics); } public abstract Dimension getSize(); public abstract void printComment(String comment); /** * copies the full file referenced by filenam onto the os (PrintWriter). The * file location is relative to the current class * * @param object from which to refer to resource file * @param fileName name of file to be copied * @param os output to copy the file to */ public static void copyResourceTo(Object object, String fileName, PrintStream os) { copyResourceTo(object, fileName, new PrintWriter( new OutputStreamWriter(os))); } public static void copyResourceTo(Object object, String fileName, PrintWriter os) { InputStream is = null; BufferedReader br = null; try { is = object.getClass().getResourceAsStream(fileName); br = new BufferedReader(new InputStreamReader(is)); String s; while ((s = br.readLine()) != null) { os.println(s); } os.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (br != null) br.close(); if (is != null) is.close(); } catch (Exception e) { e.printStackTrace(); } } } } src/main/java/org/freehep/graphicsio/ImageEncoder.java0000644000175000017500000001747311312401775022275 0ustar user03user03package org.freehep.graphicsio; // ImageEncoder - abstract class for writing out an image // // Copyright (C) 1996 by Jef Poskanzer . All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. // // Visit the ACME Labs Java page for up-to-date versions of this and other // fine Java utilities: http://www.acme.com/java/ //package Acme.JPM.Encoders; import java.awt.Image; import java.awt.image.ColorModel; import java.awt.image.ImageConsumer; import java.awt.image.ImageProducer; import java.io.DataOutput; import java.io.IOException; import java.util.Hashtable; /// Abstract class for writing out an image. //

// A framework for classes that encode and write out an image in // a particular file format. //

// This provides a simplified rendition of the ImageConsumer interface. // It always delivers the pixels as ints in the RGBdefault color model. // It always provides them in top-down left-right order. // If you want more flexibility you can always implement ImageConsumer // directly. //

// Fetch the software.
// Fetch the entire Acme package. //

// @see GifEncoder // @see PpmEncoder // @see Acme.JPM.Decoders.ImageDecoder public abstract class ImageEncoder implements ImageConsumer { protected DataOutput out; private ImageProducer producer; private int width = -1; private int height = -1; private int hintflags = 0; private boolean started = false; private boolean encoding; private IOException iox; private static final ColorModel rgbModel = ColorModel.getRGBdefault(); protected Hashtable props = null; // / Constructor. // @param img The image to encode. // @param out The stream to write the bytes to. public ImageEncoder(Image img, DataOutput dos) throws IOException { this(img.getSource(), dos); } // / Constructor. // @param producer The ImageProducer to encode. // @param out The stream to write the bytes to. public ImageEncoder(ImageProducer producer, DataOutput dos) throws IOException { this.producer = producer; this.out = dos; } // Methods that subclasses implement. // / Subclasses implement this to initialize an encoding. protected abstract void encodeStart(int w, int h) throws IOException; // / Subclasses implement this to actually write out some bits. They // are guaranteed to be delivered in top-down-left-right order. // One int per pixel, index is row * scansize + off + col, // RGBdefault (AARRGGBB) color model. protected abstract void encodePixels(int x, int y, int w, int h, int[] rgbPixels, int off, int scansize) throws IOException; // / Subclasses implement this to finish an encoding. protected abstract void encodeDone() throws IOException; // Our own methods. // / Call this after initialization to get things going. public synchronized void encode() throws IOException { encoding = true; iox = null; producer.startProduction(this); while (encoding) try { wait(); } catch (InterruptedException e) { } if (iox != null) throw iox; } private boolean accumulate = false; private int[] accumulator; private void encodePixelsWrapper(int x, int y, int w, int h, int[] rgbPixels, int off, int scansize) throws IOException { if (!started) { started = true; encodeStart(width, height); if ((hintflags & TOPDOWNLEFTRIGHT) == 0) { accumulate = true; accumulator = new int[width * height]; } } if (accumulate) for (int row = 0; row < h; ++row) System.arraycopy(rgbPixels, row * scansize + off, accumulator, (y + row) * width + x, w); else encodePixels(x, y, w, h, rgbPixels, off, scansize); } private void encodeFinish() throws IOException { if (accumulate) { encodePixels(0, 0, width, height, accumulator, 0, width); accumulator = null; accumulate = false; } } private synchronized void stop() { encoding = false; notifyAll(); } // Methods from ImageConsumer. public void setDimensions(int width, int height) { this.width = width; this.height = height; } public void setProperties(Hashtable props) { this.props = props; } public void setColorModel(ColorModel model) { // Ignore. } public void setHints(int hintflags) { this.hintflags = hintflags; } public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize) { int[] rgbPixels = new int[w]; for (int row = 0; row < h; ++row) { int rowOff = off + row * scansize; for (int col = 0; col < w; ++col) rgbPixels[col] = model.getRGB(pixels[rowOff + col] & 0xff); try { encodePixelsWrapper(x, y + row, w, 1, rgbPixels, 0, w); } catch (IOException e) { iox = e; stop(); return; } } } public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize) { if (model == rgbModel) { try { encodePixelsWrapper(x, y, w, h, pixels, off, scansize); } catch (IOException e) { iox = e; stop(); return; } } else { int[] rgbPixels = new int[w]; for (int row = 0; row < h; ++row) { int rowOff = off + row * scansize; for (int col = 0; col < w; ++col) rgbPixels[col] = model.getRGB(pixels[rowOff + col]); try { encodePixelsWrapper(x, y + row, w, 1, rgbPixels, 0, w); } catch (IOException e) { iox = e; stop(); return; } } } } public void imageComplete(int status) { producer.removeConsumer(this); if (status == ImageConsumer.IMAGEABORTED) iox = new IOException("image aborted"); else { try { encodeFinish(); encodeDone(); } catch (IOException e) { iox = e; } } stop(); } } src/main/java/org/freehep/graphicsio/PageConstants.java0000644000175000017500000000766711312401775022530 0ustar user03user03// Copyright 2000, CERN, Geneva, Switzerland and University of Santa Cruz, California, U.S.A. package org.freehep.graphicsio; import java.awt.Dimension; import java.awt.Insets; import java.util.HashMap; import java.util.Map; /** * This class defines a set of constants which describe a page. Convenience * objects are provided for various margins, orientations, rescaling, and * standard page sizes. * * @author Charles Loomis * @author Mark Donszelmann * @version $Id: PageConstants.java 10233 2007-01-03 18:59:24Z duns $ */ public class PageConstants { private PageConstants() { } // Orientation public static final String ORIENTATION = "Orientation"; public static final String PORTRAIT = "Portrait"; public static final String LANDSCAPE = "Landscape"; public static final String BEST_FIT = "Best Fit"; public final static String[] getOrientationList() { return new String[] { PORTRAIT, LANDSCAPE, /* BEST_FIT */}; } // Page Sizes public static final String PAGE_SIZE = "PageSize"; public static final String INTERNATIONAL = "International"; public static final String A3 = "A3"; public static final String A4 = "A4"; public static final String A5 = "A5"; public static final String A6 = "A6"; /** * Value for CUSTOM_PAGE_SIZE and Key for a Dimension * object if custom size is used */ public static final String CUSTOM_PAGE_SIZE = "Custom PageSize"; public static final String LETTER = "Letter"; public static final String LEGAL = "Legal"; public static final String EXECUTIVE = "Executive"; public static final String LEDGER = "Ledger"; public static final String[] getSizeList() { return new String[] { INTERNATIONAL, A4, LETTER, A3, LEGAL, A5, A6, EXECUTIVE, LEDGER }; } public static final Dimension getSize(String size) { return getSize(size, PORTRAIT); } public static final Dimension getSize(String size, String orientation) { Dimension d = (Dimension) sizeTable.get(size); if (orientation.equals(PORTRAIT)) { return d; } else { return new Dimension(d.height, d.width); } } private static final Map sizeTable = new HashMap(); static { sizeTable.put(INTERNATIONAL, new Dimension(595, 791)); sizeTable.put(A3, new Dimension(842, 1191)); sizeTable.put(A4, new Dimension(595, 842)); sizeTable.put(A5, new Dimension(420, 595)); sizeTable.put(A6, new Dimension(298, 420)); sizeTable.put(LETTER, new Dimension(612, 791)); sizeTable.put(LEGAL, new Dimension(612, 1009)); sizeTable.put(EXECUTIVE, new Dimension(539, 720)); sizeTable.put(LEDGER, new Dimension(791, 1225)); } // Margins public static final String PAGE_MARGINS = "PageMargins"; public static final String SMALL = "Small"; public static final String MEDIUM = "Medium"; public static final String LARGE = "Large"; private static final Map marginTable = new HashMap(); static { marginTable.put(SMALL, new Insets(20, 20, 20, 20)); marginTable.put(MEDIUM, new Insets(30, 30, 30, 30)); marginTable.put(LARGE, new Insets(40, 40, 40, 40)); } public static final Insets getMargins(String size) { return (Insets) marginTable.get(size); } public static final Insets getMargins(Insets insets, String orientation) { if (orientation.equals(PORTRAIT)) { return insets; } else { // turn page to right return new Insets(insets.left, insets.bottom, insets.right, insets.top); } } // Fit public static final String FIT_TO_PAGE = "FitToPage"; // FIXME: should move? public static final String TRANSPARENT = "Transparent"; public static final String BACKGROUND = "Background"; public static final String BACKGROUND_COLOR = "BackgroundColor"; } src/main/java/org/freehep/graphicsio/AbstractPathConstructor.java0000644000175000017500000000452511312401775024573 0ustar user03user03// Copyright 2001 freehep package org.freehep.graphicsio; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; import java.io.IOException; /** * Implements some of the PathConstructor functionality * * @author Mark Donszelmann * @version $Id: AbstractPathConstructor.java 8584 2006-08-10 23:06:37Z duns $ */ public abstract class AbstractPathConstructor implements PathConstructor { protected double currentX, currentY; protected AbstractPathConstructor() { currentX = 0; currentY = 0; } public void flush() throws IOException { currentX = 0; currentY = 0; } public boolean addPath(Shape s) throws IOException { return addPath(s, null); } public boolean addPath(Shape s, AffineTransform transform) throws IOException { return addPath(this, s, transform); } public static boolean addPath(PathConstructor out, Shape s, AffineTransform transform) throws IOException { PathIterator path = s.getPathIterator(transform); double[] coords = new double[6]; double pathStartX = 0.; double pathStartY = 0.; while (!path.isDone()) { int segType = path.currentSegment(coords); switch (segType) { case PathIterator.SEG_MOVETO: out.move(coords[0], coords[1]); pathStartX = coords[0]; pathStartY = coords[1]; break; case PathIterator.SEG_LINETO: out.line(coords[0], coords[1]); break; case PathIterator.SEG_QUADTO: out.quad(coords[0], coords[1], coords[2], coords[3]); break; case PathIterator.SEG_CUBICTO: out.cubic(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); break; case PathIterator.SEG_CLOSE: out.closePath(pathStartX, pathStartY); break; } // Move to the next segment. path.next(); } out.flush(); return (path.getWindingRule() == PathIterator.WIND_EVEN_ODD); } public static boolean isEvenOdd(Shape s) { return s.getPathIterator(null).getWindingRule() == PathIterator.WIND_EVEN_ODD; } } src/main/java/org/freehep/graphicsio/CubicToQuadPathConstructor.java0000644000175000017500000001174411312401775025174 0ustar user03user03// Copyright 2001-2004 FreeHEP package org.freehep.graphicsio; import java.awt.geom.Point2D; import java.io.IOException; /** * Implements the Cubic Bezier Curve PathConstructor functionality in terms of * Quadratic Bezier Curves * * Uses the same algorithm published as ActionScript (SWF) by Robert Penner: * * ========================== Cubic Bezier Drawing v1.1 * ========================== recursive quadratic approximation with adjustable * tolerance * * March 4, 2004 * * Robert Penner www.robertpenner.com/tools/bezier_cubic.zip file: * bezier_draw_cubic.as ========================== * * @author Mark Donszelmann * @version $Id: CubicToQuadPathConstructor.java 9319 2006-11-13 22:08:58Z duns $ */ public abstract class CubicToQuadPathConstructor extends AbstractPathConstructor { private double resolutionSq; protected CubicToQuadPathConstructor(double resolution) { super(); resolutionSq = resolution * resolution; } public void move(double x, double y) throws IOException { currentX = x; currentY = y; } public void line(double x, double y) throws IOException { currentX = x; currentY = y; } public void cubic(double x1, double y1, double x2, double y2, double x3, double y3) throws IOException { quadratify(new Point2D.Double(currentX, currentY), new Point2D.Double( x1, y1), new Point2D.Double(x2, y2), new Point2D.Double(x3, y3)); currentX = x3; currentY = y3; } public void closePath(double x0, double y0) throws IOException { currentX = 0; currentY = 0; } public static Point2D intersect(Point2D p1, Point2D p2, Point2D p3, Point2D p4) { double dx1 = p2.getX() - p1.getX(); double dx2 = p3.getX() - p4.getX(); // line are vertical if ((dx1 == 0) && (dx2 == 0)) return null; double dy1 = p2.getY() - p1.getY(); double dy2 = p3.getY() - p4.getY(); // line are horizontal if ((dy1 == 0) && (dy2 == 0)) return null; double m1 = (p2.getY() - p1.getY()) / dx1; double m2 = (p3.getY() - p4.getY()) / dx2; if (dx1 == 0) { // infinity return new Point2D.Double(p1.getX(), m2 * (p1.getX() - p4.getX()) + p4.getY()); } else if (dx2 == 0) { // infinity return new Point2D.Double(p4.getX(), m1 * (p4.getX() - p1.getX()) + p1.getY()); } // lines are parallel if (m1 == m2) return null; double x = (-m2 * p4.getX() + p4.getY() + m1 * p1.getX() - p1.getY()) / (m1 - m2); double y = m1 * (x - p1.getX()) + p1.getY(); return new Point2D.Double(x, y); } public static Point2D midPoint(Point2D a, Point2D b) { return new Point2D.Double((a.getX() + b.getX()) / 2.0, (a.getY() + b .getY()) / 2.0); } public void quadratify(Point2D a, Point2D b, Point2D c, Point2D d) throws IOException { // find intersection between bezier arms Point2D s = intersect(a, b, c, d); if (s == null) return; // find distance between the midpoints double dx = (a.getX() + d.getX() + s.getX() * 4 - (b.getX() + c.getX()) * 3) * .125; double dy = (a.getY() + d.getY() + s.getY() * 4 - (b.getY() + c.getY()) * 3) * .125; // split curve if the quadratic isn't close enough if (dx * dx + dy * dy > resolutionSq) { Point2D p01 = midPoint(a, b); Point2D p12 = midPoint(b, c); Point2D p23 = midPoint(c, d); Point2D p02 = midPoint(p01, p12); Point2D p13 = midPoint(p12, p23); Point2D p03 = midPoint(p02, p13); // recursive call to subdivide curve quadratify(a, p01, p02, p03); quadratify(p03, p13, p23, d); } else { // end recursion by drawing quadratic bezier quad(s.getX(), s.getY(), d.getX(), d.getY()); } } static class Test extends CubicToQuadPathConstructor { public Test(double resolution) { super(resolution); } public void quad(double x1, double y1, double x2, double y2) { System.out.println("Quad: (" + currentX + ", " + currentY + ") (" + x1 + ", " + y1 + ") (" + x2 + ", " + y2 + ")"); currentX = x2; currentY = y2; } } public static void main(String[] args) throws Exception { PathConstructor pc = new Test(0.5); // A, B, C, D pc.move(20, 20); pc.cubic(20, 40, 40, 60, 60, 60); // A, B, D, C pc.move(20, 20); pc.cubic(20, 40, 60, 60, 40, 60); // Intersecting Curve pc.move(183, 149); pc.cubic(189, 291, 256, 347, 295, 244); pc.cubic(334, 141, 286, 216, 214, 228); pc.cubic(142, 240, 142, 256, 176, 284); } } src/main/java/org/freehep/graphicsio/DummyGraphics2D.java0000644000175000017500000002760411312401775022712 0ustar user03user03// Copyright 2000-2006, FreeHEP package org.freehep.graphicsio; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.GraphicsConfiguration; import java.awt.Paint; import java.awt.Rectangle; import java.awt.Shape; import java.awt.TexturePaint; import java.awt.geom.AffineTransform; import java.awt.image.RenderedImage; import java.io.IOException; import org.freehep.graphics2d.VectorGraphics; /** * This class provides a dummy Graphics2D class, which issues warnings for all * non implemented methods. It also describes how to implement these methods. It * serves as an example to start the implementation for a new output format. * * @author Mark Donszelmann * @version $Id: DummyGraphics2D.java 8584 2006-08-10 23:06:37Z duns $ */ public class DummyGraphics2D extends AbstractVectorGraphicsIO { /* * ================================================================================ * Table of Contents: ------------------ 1. Constructors & Factory Methods * 2. Document Settings 3. Header, Trailer, Multipage & Comments 3.1 Header & * Trailer 3.2 MultipageDocument methods 4. Create & Dispose 5. Drawing * Methods 5.1. shapes (draw/fill) 5.1.1. lines, rectangles, round * rectangles 5.1.2. polylines, polygons 5.1.3. ovals, arcs 5.1.4. shapes * 5.2. Images 5.3. Strings 6. Transformations 7. Clipping 8. Graphics State / * Settings 8.1. stroke/linewidth 8.2. paint/color 8.3. font 8.4. rendering * hints 9. Auxiliary 10. Private/Utility Methos * ================================================================================ */ /* * ================================================================================ * 1. Constructors & Factory Methods * ================================================================================ */ public DummyGraphics2D(Dimension size, boolean doRestoreOnDispose) { super(size, doRestoreOnDispose); // Create a graphics context with given imageBounds. // This constructor is used by the user to create the initial graphics // context. // doRestoreOnDispose is used to call writeGraphicsRestore(), // when the graphics context is being disposed off. } protected DummyGraphics2D(AbstractVectorGraphicsIO graphics, boolean doRestoreOnDispose) { super(graphics, doRestoreOnDispose); // Create a graphics context from a given graphics context. // This constructor is used by the system to clone a given graphics // context. // doRestoreOnDispose is used to call writeGraphicsRestore(), // when the graphics context is being disposed off. } /* * ================================================================================ | * 2. Document Settings * ================================================================================ */ /* * ================================================================================ | * 3. Header, Trailer, Multipage & Comments * ================================================================================ */ /* 3.1 Header & Trailer */ public void writeHeader() throws IOException { writeWarning(getClass() + ": writeHeader() not implemented."); // Write out the header to the output stream. } public void writeBackground() throws IOException { writeWarning(getClass() + ": writeBackground() not implemented."); // Write out the background to the output stream. } public void writeTrailer() throws IOException { writeWarning(getClass() + ": writeTrailer() not implemented."); // Write out the trailer to the output stream. } public void closeStream() throws IOException { writeWarning(getClass() + ": closeStream() not implemented."); // Close the output stream. } /* 3.2 MultipageDocument methods */ /* * ================================================================================ * 4. Create & Dispose * ================================================================================ */ public Graphics create() { // Create a new graphics context from the current one. try { // Save the current context for restore later. writeGraphicsSave(); } catch (IOException e) { } // The correct graphics context should be created. return new DummyGraphics2D(this, true); } public Graphics create(double x, double y, double width, double height) { // Create a new graphics context from the current one. try { // Save the current context for restore later. writeGraphicsSave(); } catch (IOException e) { } // The correct graphics context should be created. VectorGraphics graphics = new DummyGraphics2D(this, true); graphics.clipRect(x, y, width, height); return graphics; } protected void writeGraphicsSave() throws IOException { writeWarning(getClass() + ": writeGraphicsSave() not implemented."); // Write a graphics context save. // If the output format does not support this, keep a stack yourself. } protected void writeGraphicsRestore() throws IOException { writeWarning(getClass() + ": writeGraphicsRestore() not implemented."); // Write a graphics context restore. // If the output format does not support this, keep a stack yourself. } /* * ================================================================================ | * 5. Drawing Methods * ================================================================================ */ /* 5.1.4. shapes */ public void draw(Shape shape) { writeWarning(getClass() + ": draw(Shape) not implemented."); // Write out the stroke of the shape. } public void fill(Shape shape) { writeWarning(getClass() + ": fill(Shape) not implemented."); // Write out the fill of the shape. } public void fillAndDraw(Shape shape, Color fillColor) { writeWarning(getClass() + ": fillAndDraw(Shape, Color) not implemented."); // Write out the fill with fillColor and stroke of the shape in // getColor(). } /* 5.2. Images */ public void copyArea(int x, int y, int width, int height, int dx, int dy) { writeWarning(getClass() + ": copyArea(int, int, int, int, int, int) not implemented."); // Mostly unimplemented. } protected void writeImage(RenderedImage image, AffineTransform xform, Color bkg) throws IOException { writeWarning(getClass() + ": writeImage(RenderedImage, AffineTransform, Color) not implemented."); // Write out the image. } /* 5.3. Strings */ protected void writeString(String string, double x, double y) throws IOException { writeWarning(getClass() + ": drawString(String, double, double) not implemented."); // Write out the string. } /* * ================================================================================ | * 6. Transformations * ================================================================================ */ protected void writeTransform(AffineTransform t) throws IOException { writeWarning(getClass() + ": writeTransform(AffineTransform) not implemented."); // Write out the transform to be applied to the internal transform of // the output // format. // You can also use the currentTransform. } protected void writeSetTransform(AffineTransform t) throws IOException { writeWarning(getClass()+": writeTransform(AffineTransform) not implemented."); // Clear the currentTransform and write out the transform to // be applied to the internal transform of the output format. } /* * ================================================================================ | * 7. Clipping * ================================================================================ */ protected void writeClip(Shape s) throws IOException { writeWarning(getClass() + ": writeClip(Shape) not implemented."); // Write out the clip shape. } protected void writeSetClip(Shape s) throws IOException { writeWarning(getClass()+": writeSetClip(Shape) not implemented."); // Write out the clip shape. } /* * ================================================================================ | * 8. Graphics State * ================================================================================ */ /* 8.1. stroke/linewidth */ protected void writeWidth(float width) throws IOException { writeWarning(getClass() + ": writeWidth(float) not implemented."); // Write out the stroke width. } protected void writeCap(int cap) throws IOException { writeWarning(getClass() + ": writeCap(int) not implemented."); // Write out the stroke cap. } protected void writeJoin(int join) throws IOException { writeWarning(getClass() + ": writeJoin(int) not implemented."); // Write out the stroke join. } protected void writeMiterLimit(float limit) throws IOException { writeWarning(getClass() + ": writeMiterLimit(float) not implemented."); // Write out the stroke miter limit. } protected void writeDash(float[] dash, float phase) throws IOException { writeWarning(getClass() + ": writeDash(float[], float) not implemented."); // Write out the stroke dash. } /* 8.2. paint/color */ public void setPaintMode() { writeWarning(getClass() + ": setPaintMode() not implemented."); // Mostly unimplemented. } public void setXORMode(Color c1) { writeWarning(getClass() + ": setXORMode(Color) not implemented."); // Mostly unimplemented. } protected void writePaint(Color p) throws IOException { writeWarning(getClass() + ": writePaint(Color) not implemented."); // Write out the color paint. } protected void writePaint(GradientPaint p) throws IOException { writeWarning(getClass() + ": writePaint(GradientPaint) not implemented."); // Write out the gradient paint. } protected void writePaint(TexturePaint p) throws IOException { writeWarning(getClass() + ": writePaint(TexturePaint) not implemented."); // Write out the texture paint. } protected void writePaint(Paint p) throws IOException { writeWarning(getClass() + ": writePaint(Paint) not implemented for " + p.getClass()); // Write out the paint. } /* 8.3. font */ protected void writeFont(Font font) throws IOException { writeWarning(getClass() + ": writeFont(Font) not implemented."); } /* 8.4. rendering hints */ /* * ================================================================================ | * 9. Auxiliary * ================================================================================ */ public GraphicsConfiguration getDeviceConfiguration() { writeWarning(getClass() + ": getDeviceConfiguration() not implemented."); // Mostly unimplemented return null; } public boolean hit(Rectangle rect, Shape s, boolean onStroke) { writeWarning(getClass() + ": hit(Rectangle, Shape, boolean) not implemented."); // Mostly unimplemented return false; } public void writeComment(String comment) throws IOException { writeWarning(getClass() + ": writeComment(String) not implemented."); // Write out the comment. } public String toString() { return "DummyGraphics"; } } src/main/java/org/freehep/graphicsio/CubicToLinePathConstructor.java0000644000175000017500000001117411312401775025166 0ustar user03user03// Copyright 2001 FreeHEP. package org.freehep.graphicsio; import java.awt.geom.Point2D; import java.io.IOException; import java.util.Stack; /** * Implements cubics by approximating them using a polyline. Useful class for * output formats that do NOT implement bezier curves at all, or if you need * only straight lines. * * @author Mark Donszelmann * @version $Id: CubicToLinePathConstructor.java 8584 2006-08-10 23:06:37Z duns $ */ public abstract class CubicToLinePathConstructor extends QuadToCubicPathConstructor { private double resolution; protected CubicToLinePathConstructor() { this(0.025); } protected CubicToLinePathConstructor(double resolution) { this.resolution = Math.abs(resolution); } public void cubic(double x1, double y1, double x2, double y2, double x3, double y3) throws IOException { // ControlSets are written at the end Stack/**/ controls = new Stack/**/(); // System.out.println("Cubic "+x1+" "+y1+" "+x2+" "+y2+" "+x3+" "+y3); Point2D p0 = new Point2D.Double(currentX, currentY); Point2D p1 = new Point2D.Double(x1, y1); Point2D p2 = new Point2D.Double(x2, y2); Point2D p3 = new Point2D.Double(x3, y3); // ControlSets to create the controls Stack/**/ temps = new Stack/**/(); temps.push(new ControlSet(p0, p1, p2, p3)); while (!temps.empty()) { ControlSet control = (ControlSet) temps.pop(); if (control.breadth() > resolution) { temps.push(control); temps.push(control.bisect()); } else { controls.push(control); } } /*tempSet[l++] = new ControlSet(p0, p1, p2, p3); while (l > 0) { ControlSet control1 = tempSet[--l]; double b = control1.breadth(); if (b > resolution) { ControlSet control3 = control1.bisect(); tempSet[l++] = control1; tempSet[l++] = control3; } else { controls.push(control1); } }*/ // write out control sets // System.out.println(k); while (!controls.empty()) { Point2D p = ((ControlSet)controls.pop()).getPoint(); line(p.getX(), p.getY()); // System.out.println(control2.getPoint()); } // store currentX and currentY super.cubic(x1, y1, x2, y2, x3, y3); } class ControlSet { private Point2D point0; private Point2D point1; private Point2D point2; private Point2D point3; public ControlSet(Point2D p0, Point2D p1, Point2D p2, Point2D p3) { point0 = p0; point1 = p1; point2 = p2; point3 = p3; } public double breadth() { double f0 = point0.getX(); double f4 = point0.getY(); double f1 = point1.getX(); double f5 = point1.getY(); double f2 = point2.getX(); double f6 = point2.getY(); double f3 = point3.getX(); double f7 = point3.getY(); if ((Math.abs(f0 - f3) < resolution) && (Math.abs(f4 - f7) < resolution)) { double f8 = Math.abs(f1 - f0) + Math.abs(f5 - f4); double f10 = Math.abs(f2 - f0) + Math.abs(f6 - f4); return Math.max(f10, f8); } else { double d0 = f4 - f7; double d1 = f3 - f0; double f12 = Math.sqrt(d0 * d0 + d1 * d1); double d2 = f3 * f4 - f0 * f7; double f9 = Math.abs((d0 * f2 + d1 * f6) - d2) / f12; double f11 = Math.abs((d0 * f1 + d1 * f5) - d2) / f12; return Math.max(f9, f11); } } public ControlSet bisect() { Point2D p0 = average(point0, point1); Point2D p1 = average(point1, point2); Point2D p2 = average(point2, point3); Point2D p3 = average(p0, p1); Point2D p4 = average(p1, p2); Point2D p5 = average(p3, p4); ControlSet controlset = new ControlSet(p5, p4, p2, point3); point1 = p0; point2 = p3; point3 = p5; return controlset; } public Point2D average(Point2D p1, Point2D p2) { return new Point2D.Double((p1.getX() + p2.getX()) / 2.0, (p1.getY() + p2.getY()) / 2.0); } public Point2D getPoint() { return point3; } } } src/main/java/org/freehep/graphicsio/VectorGraphics.txt0000644000175000017500000000013311312401775022555 0ustar user03user03For information on the VectorGraphics package see: http://java.freehep.org/vectorgraphics src/main/java/org/freehep/graphicsio/gif/0000755000175000017500000000000011312401774017640 5ustar user03user03src/main/java/org/freehep/graphicsio/gif/Quantize.java0000644000175000017500000007512211312401774022312 0ustar user03user03package org.freehep.graphicsio.gif; /* * @(#)Quantize.java 0.90 9/19/00 Adam Doppelt */ /** * An efficient color quantization algorithm, adapted from the C++ * implementation quantize.c in ImageMagick. The pixels for * an image are placed into an oct tree. The oct tree is reduced in * size, and the pixels from the original image are reassigned to the * nodes in the reduced tree.

* * Here is the copyright notice from ImageMagick: * *

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  Permission is hereby granted, free of charge, to any person obtaining a    %
%  copy of this software and associated documentation files ("ImageMagick"),  %
%  to deal in ImageMagick without restriction, including without limitation   %
%  the rights to use, copy, modify, merge, publish, distribute, sublicense,   %
%  and/or sell copies of ImageMagick, and to permit persons to whom the       %
%  ImageMagick is furnished to do so, subject to the following conditions:    %
%                                                                             %
%  The above copyright notice and this permission notice shall be included in %
%  all copies or substantial portions of ImageMagick.                         %
%                                                                             %
%  The software is provided "as is", without warranty of any kind, express or %
%  implied, including but not limited to the warranties of merchantability,   %
%  fitness for a particular purpose and noninfringement.  In no event shall   %
%  E. I. du Pont de Nemours and Company be liable for any claim, damages or   %
%  other liability, whether in an action of contract, tort or otherwise,      %
%  arising from, out of or in connection with ImageMagick or the use or other %
%  dealings in ImageMagick.                                                   %
%                                                                             %
%  Except as contained in this notice, the name of the E. I. du Pont de       %
%  Nemours and Company shall not be used in advertising or otherwise to       %
%  promote the sale, use or other dealings in ImageMagick without prior       %
%  written authorization from the E. I. du Pont de Nemours and Company.       %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
* * * @version 0.90 19 Sep 2000 * @author Adam Doppelt */ public class Quantize { /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % QQQ U U AAA N N TTTTT IIIII ZZZZZ EEEEE % % Q Q U U A A NN N T I ZZ E % % Q Q U U AAAAA N N N T I ZZZ EEEEE % % Q QQ U U A A N NN T I ZZ E % % QQQQ UUU A A N N T IIIII ZZZZZ EEEEE % % % % % % Reduce the Number of Unique Colors in an Image % % % % % % Software Design % % John Cristy % % July 1992 % % % % % % Copyright 1998 E. I. du Pont de Nemours and Company % % % % Permission is hereby granted, free of charge, to any person obtaining a % % copy of this software and associated documentation files ("ImageMagick"), % % to deal in ImageMagick without restriction, including without limitation % % the rights to use, copy, modify, merge, publish, distribute, sublicense, % % and/or sell copies of ImageMagick, and to permit persons to whom the % % ImageMagick is furnished to do so, subject to the following conditions: % % % % The above copyright notice and this permission notice shall be included in % % all copies or substantial portions of ImageMagick. % % % % The software is provided "as is", without warranty of any kind, express or % % implied, including but not limited to the warranties of merchantability, % % fitness for a particular purpose and noninfringement. In no event shall % % E. I. du Pont de Nemours and Company be liable for any claim, damages or % % other liability, whether in an action of contract, tort or otherwise, % % arising from, out of or in connection with ImageMagick or the use or other % % dealings in ImageMagick. % % % % Except as contained in this notice, the name of the E. I. du Pont de % % Nemours and Company shall not be used in advertising or otherwise to % % promote the sale, use or other dealings in ImageMagick without prior % % written authorization from the E. I. du Pont de Nemours and Company. % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Realism in computer graphics typically requires using 24 bits/pixel to % generate an image. Yet many graphic display devices do not contain % the amount of memory necessary to match the spatial and color % resolution of the human eye. The QUANTIZE program takes a 24 bit % image and reduces the number of colors so it can be displayed on % raster device with less bits per pixel. In most instances, the % quantized image closely resembles the original reference image. % % A reduction of colors in an image is also desirable for image % transmission and real-time animation. % % Function Quantize takes a standard RGB or monochrome images and quantizes % them down to some fixed number of colors. % % For purposes of color allocation, an image is a set of n pixels, where % each pixel is a point in RGB space. RGB space is a 3-dimensional % vector space, and each pixel, pi, is defined by an ordered triple of % red, green, and blue coordinates, (ri, gi, bi). % % Each primary color component (red, green, or blue) represents an % intensity which varies linearly from 0 to a maximum value, cmax, which % corresponds to full saturation of that color. Color allocation is % defined over a domain consisting of the cube in RGB space with % opposite vertices at (0,0,0) and (cmax,cmax,cmax). QUANTIZE requires % cmax = 255. % % The algorithm maps this domain onto a tree in which each node % represents a cube within that domain. In the following discussion % these cubes are defined by the coordinate of two opposite vertices: % The vertex nearest the origin in RGB space and the vertex farthest % from the origin. % % The tree's root node represents the the entire domain, (0,0,0) through % (cmax,cmax,cmax). Each lower level in the tree is generated by % subdividing one node's cube into eight smaller cubes of equal size. % This corresponds to bisecting the parent cube with planes passing % through the midpoints of each edge. % % The basic algorithm operates in three phases: Classification, % Reduction, and Assignment. Classification builds a color % description tree for the image. Reduction collapses the tree until % the number it represents, at most, the number of colors desired in the % output image. Assignment defines the output image's color map and % sets each pixel's color by reclassification in the reduced tree. % Our goal is to minimize the numerical discrepancies between the original % colors and quantized colors (quantization error). % % Classification begins by initializing a color description tree of % sufficient depth to represent each possible input color in a leaf. % However, it is impractical to generate a fully-formed color % description tree in the classification phase for realistic values of % cmax. If colors components in the input image are quantized to k-bit % precision, so that cmax= 2k-1, the tree would need k levels below the % root node to allow representing each possible input color in a leaf. % This becomes prohibitive because the tree's total number of nodes is % 1 + sum(i=1,k,8k). % % A complete tree would require 19,173,961 nodes for k = 8, cmax = 255. % Therefore, to avoid building a fully populated tree, QUANTIZE: (1) % Initializes data structures for nodes only as they are needed; (2) % Chooses a maximum depth for the tree as a function of the desired % number of colors in the output image (currently log2(colormap size)). % % For each pixel in the input image, classification scans downward from % the root of the color description tree. At each level of the tree it % identifies the single node which represents a cube in RGB space % containing the pixel's color. It updates the following data for each % such node: % % n1: Number of pixels whose color is contained in the RGB cube % which this node represents; % % n2: Number of pixels whose color is not represented in a node at % lower depth in the tree; initially, n2 = 0 for all nodes except % leaves of the tree. % % Sr, Sg, Sb: Sums of the red, green, and blue component values for % all pixels not classified at a lower depth. The combination of % these sums and n2 will ultimately characterize the mean color of a % set of pixels represented by this node. % % E: The distance squared in RGB space between each pixel contained % within a node and the nodes' center. This represents the quantization % error for a node. % % Reduction repeatedly prunes the tree until the number of nodes with % n2 > 0 is less than or equal to the maximum number of colors allowed % in the output image. On any given iteration over the tree, it selects % those nodes whose E count is minimal for pruning and merges their % color statistics upward. It uses a pruning threshold, Ep, to govern % node selection as follows: % % Ep = 0 % while number of nodes with (n2 > 0) > required maximum number of colors % prune all nodes such that E <= Ep % Set Ep to minimum E in remaining nodes % % This has the effect of minimizing any quantization error when merging % two nodes together. % % When a node to be pruned has offspring, the pruning procedure invokes % itself recursively in order to prune the tree from the leaves upward. % n2, Sr, Sg, and Sb in a node being pruned are always added to the % corresponding data in that node's parent. This retains the pruned % node's color characteristics for later averaging. % % For each node, n2 pixels exist for which that node represents the % smallest volume in RGB space containing those pixel's colors. When n2 % > 0 the node will uniquely define a color in the output image. At the % beginning of reduction, n2 = 0 for all nodes except a the leaves of % the tree which represent colors present in the input image. % % The other pixel count, n1, indicates the total number of colors % within the cubic volume which the node represents. This includes n1 - % n2 pixels whose colors should be defined by nodes at a lower level in % the tree. % % Assignment generates the output image from the pruned tree. The % output image consists of two parts: (1) A color map, which is an % array of color descriptions (RGB triples) for each color present in % the output image; (2) A pixel array, which represents each pixel as % an index into the color map array. % % First, the assignment phase makes one pass over the pruned color % description tree to establish the image's color map. For each node % with n2 > 0, it divides Sr, Sg, and Sb by n2 . This produces the % mean color of all pixels that classify no lower than this node. Each % of these colors becomes an entry in the color map. % % Finally, the assignment phase reclassifies each pixel in the pruned % tree to identify the deepest node containing the pixel's color. The % pixel's value in the pixel array becomes the index of this node's mean % color in the color map. % % With the permission of USC Information Sciences Institute, 4676 Admiralty % Way, Marina del Rey, California 90292, this code was adapted from module % ALCOLS written by Paul Raveling. % % The names of ISI and USC are not used in advertising or publicity % pertaining to distribution of the software without prior specific % written permission from ISI. % */ final static boolean QUICK = false; final static int MAX_RGB = 255; final static int MAX_NODES = 266817; final static int MAX_TREE_DEPTH = 8; // these are precomputed in advance static int SQUARES[]; static int SHIFT[]; static { SQUARES = new int[MAX_RGB + MAX_RGB + 1]; for (int i= -MAX_RGB; i <= MAX_RGB; i++) { SQUARES[i + MAX_RGB] = i * i; } SHIFT = new int[MAX_TREE_DEPTH + 1]; for (int i = 0; i < MAX_TREE_DEPTH + 1; ++i) { SHIFT[i] = 1 << (15 - i); } } /** * Reduce the image to the given number of colors. The pixels are * reduced in place. * @return The new color palette. */ public static int[] quantizeImage(int pixels[][], int max_colors) { Cube cube = new Cube(pixels, max_colors); cube.classification(); cube.reduction(); cube.assignment(); return cube.colormap; } static class Cube { int pixels[][]; int max_colors; int colormap[]; Node root; int depth; // counter for the number of colors in the cube. this gets // recalculated often. int colors; // counter for the number of nodes in the tree int nodes; Cube(int pixels[][], int max_colors) { this.pixels = pixels; this.max_colors = max_colors; colors = 1; int i = max_colors; // tree_depth = log max_colors // 4 for (depth = 1; i != 0; depth++) { i /= 4; } if (depth > 1) { --depth; } if (depth > MAX_TREE_DEPTH) { depth = MAX_TREE_DEPTH; } else if (depth < 2) { depth = 2; } root = new Node(this); } /* * Procedure Classification begins by initializing a color * description tree of sufficient depth to represent each * possible input color in a leaf. However, it is impractical * to generate a fully-formed color description tree in the * classification phase for realistic values of cmax. If * colors components in the input image are quantized to k-bit * precision, so that cmax= 2k-1, the tree would need k levels * below the root node to allow representing each possible * input color in a leaf. This becomes prohibitive because the * tree's total number of nodes is 1 + sum(i=1,k,8k). * * A complete tree would require 19,173,961 nodes for k = 8, * cmax = 255. Therefore, to avoid building a fully populated * tree, QUANTIZE: (1) Initializes data structures for nodes * only as they are needed; (2) Chooses a maximum depth for * the tree as a function of the desired number of colors in * the output image (currently log2(colormap size)). * * For each pixel in the input image, classification scans * downward from the root of the color description tree. At * each level of the tree it identifies the single node which * represents a cube in RGB space containing It updates the * following data for each such node: * * number_pixels : Number of pixels whose color is contained * in the RGB cube which this node represents; * * unique : Number of pixels whose color is not represented * in a node at lower depth in the tree; initially, n2 = 0 * for all nodes except leaves of the tree. * * total_red/green/blue : Sums of the red, green, and blue * component values for all pixels not classified at a lower * depth. The combination of these sums and n2 will * ultimately characterize the mean color of a set of pixels * represented by this node. */ void classification() { int pixels[][] = this.pixels; int width = pixels.length; int height = pixels[0].length; // convert to indexed color for (int x = width; x-- > 0; ) { for (int y = height; y-- > 0; ) { int pixel = pixels[x][y]; int alpha = (pixel >> 24) & 0xFF; int red = (pixel >> 16) & 0xFF; int green = (pixel >> 8) & 0xFF; int blue = (pixel >> 0) & 0xFF; if (alpha > 0) { // a hard limit on the number of nodes in the tree if (nodes > MAX_NODES) { System.out.println("pruning"); root.pruneLevel(); --depth; } // walk the tree to depth, increasing the // number_pixels count for each node Node node = root; for (int level = 1; level <= depth; ++level) { int id = (((red > node.mid_red ? 1 : 0) << 0) | ((green > node.mid_green ? 1 : 0) << 1) | ((blue > node.mid_blue ? 1 : 0) << 2)); if (node.child[id] == null) { new Node(node, id, level); } node = node.child[id]; node.number_pixels += SHIFT[level]; } ++node.unique; node.total_alpha += alpha; node.total_red += red; node.total_green += green; node.total_blue += blue; } } } } /* * reduction repeatedly prunes the tree until the number of * nodes with unique > 0 is less than or equal to the maximum * number of colors allowed in the output image. * * When a node to be pruned has offspring, the pruning * procedure invokes itself recursively in order to prune the * tree from the leaves upward. The statistics of the node * being pruned are always added to the corresponding data in * that node's parent. This retains the pruned node's color * characteristics for later averaging. */ void reduction() { int threshold = 1; while (colors > max_colors) { colors = 1; threshold = root.reduce(threshold, Integer.MAX_VALUE); } } /** * The result of a closest color search. */ static class Search { int distance; int color_number; } /* * Procedure assignment generates the output image from the * pruned tree. The output image consists of two parts: (1) A * color map, which is an array of color descriptions (RGB * triples) for each color present in the output image; (2) A * pixel array, which represents each pixel as an index into * the color map array. * * First, the assignment phase makes one pass over the pruned * color description tree to establish the image's color map. * For each node with n2 > 0, it divides Sr, Sg, and Sb by n2. * This produces the mean color of all pixels that classify no * lower than this node. Each of these colors becomes an entry * in the color map. * * Finally, the assignment phase reclassifies each pixel in * the pruned tree to identify the deepest node containing the * pixel's color. The pixel's value in the pixel array becomes * the index of this node's mean color in the color map. */ void assignment() { colormap = new int[colors]; // transparent color colormap[0] = 0x00800000; colors = 1; root.colormap(); int pixels[][] = this.pixels; int width = pixels.length; int height = pixels[0].length; Search search = new Search(); // convert to indexed color for (int x = width; x-- > 0; ) { for (int y = height; y-- > 0; ) { int pixel = pixels[x][y]; int alpha = (pixel >> 24) & 0xFF; int red = (pixel >> 16) & 0xFF; int green = (pixel >> 8) & 0xFF; int blue = (pixel >> 0) & 0xFF; if (alpha > 0) { // walk the tree to find the cube containing that color Node node = root; for ( ; ; ) { int id = (((red > node.mid_red ? 1 : 0) << 0) | ((green > node.mid_green ? 1 : 0) << 1) | ((blue > node.mid_blue ? 1 : 0) << 2) ); if (node.child[id] == null) { break; } node = node.child[id]; } if (QUICK) { // if QUICK is set, just use that // node. Strictly speaking, this isn't // necessarily best match. pixels[x][y] = node.color_number; } else { // Find the closest color. search.distance = Integer.MAX_VALUE; node.parent.closestColor(red, green, blue, search); pixels[x][y] = search.color_number; } } else { // transparent pixels[x][y] = 0; } } } } /** * A single Node in the tree. */ static class Node { Cube cube; // parent node Node parent; // child nodes Node child[]; int nchild; // our index within our parent int id; // our level within the tree int level; // our color midpoint int mid_red; int mid_green; int mid_blue; // the pixel count for this node and all children int number_pixels; // the pixel count for this node int unique; // the sum of all pixels contained in this node int total_alpha; int total_red; int total_green; int total_blue; // used to build the colormap int color_number; Node(Cube cube) { this.cube = cube; this.parent = this; this.child = new Node[8]; this.id = 0; this.level = 0; this.number_pixels = Integer.MAX_VALUE; this.mid_red = (MAX_RGB + 1) >> 1; this.mid_green = (MAX_RGB + 1) >> 1; this.mid_blue = (MAX_RGB + 1) >> 1; } Node(Node parent, int id, int level) { this.cube = parent.cube; this.parent = parent; this.child = new Node[8]; this.id = id; this.level = level; // add to the cube ++cube.nodes; if (level == cube.depth) { ++cube.colors; } // add to the parent ++parent.nchild; parent.child[id] = this; // figure out our midpoint int bi = (1 << (MAX_TREE_DEPTH - level)) >> 1; mid_red = parent.mid_red + ((id & 1) > 0 ? bi : -bi); mid_green = parent.mid_green + ((id & 2) > 0 ? bi : -bi); mid_blue = parent.mid_blue + ((id & 4) > 0 ? bi : -bi); } /** * Remove this child node, and make sure our parent * absorbs our pixel statistics. */ void pruneChild() { --parent.nchild; parent.unique += unique; parent.total_alpha += total_alpha; parent.total_red += total_red; parent.total_green += total_green; parent.total_blue += total_blue; parent.child[id] = null; --cube.nodes; cube = null; parent = null; } /** * Prune the lowest layer of the tree. */ void pruneLevel() { if (nchild != 0) { for (int id = 0; id < 8; id++) { if (child[id] != null) { child[id].pruneLevel(); } } } if (level == cube.depth) { pruneChild(); } } /** * Remove any nodes that have fewer than threshold * pixels. Also, as long as we're walking the tree: * * - figure out the color with the fewest pixels * - recalculate the total number of colors in the tree */ int reduce(int threshold, int next_threshold) { if (nchild != 0) { for (int id = 0; id < 8; id++) { if (child[id] != null) { next_threshold = child[id].reduce(threshold, next_threshold); } } } if (number_pixels <= threshold) { pruneChild(); } else { if (unique != 0) { cube.colors++; } if (number_pixels < next_threshold) { next_threshold = number_pixels; } } return next_threshold; } /* * colormap traverses the color cube tree and notes each * colormap entry. A colormap entry is any node in the * color cube tree where the number of unique colors is * not zero. */ void colormap() { if (nchild != 0) { for (int id = 0; id < 8; id++) { if (child[id] != null) { child[id].colormap(); } } } if (unique != 0) { int a = ((total_alpha + (unique >> 1)) / unique); int r = ((total_red + (unique >> 1)) / unique); int g = ((total_green + (unique >> 1)) / unique); int b = ((total_blue + (unique >> 1)) / unique); cube.colormap[cube.colors] = (((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | ((b & 0xFF) << 0)); color_number = cube.colors++; } } /* ClosestColor traverses the color cube tree at a * particular node and determines which colormap entry * best represents the input color. */ void closestColor(int red, int green, int blue, Search search) { if (nchild != 0) { for (int id = 0; id < 8; id++) { if (child[id] != null) { child[id].closestColor(red, green, blue, search); } } } if (unique != 0) { int color = cube.colormap[color_number]; int distance = distance(color, red, green, blue); if (distance < search.distance) { search.distance = distance; search.color_number = color_number; } } } /** * Figure out the distance between this node and som color. */ final static int distance(int color, int r, int g, int b) { return (SQUARES[((color >> 16) & 0xFF) - r + MAX_RGB] + SQUARES[((color >> 8) & 0xFF) - g + MAX_RGB] + SQUARES[((color >> 0) & 0xFF) - b + MAX_RGB]); } public String toString() { StringBuffer buf = new StringBuffer(); if (parent == this) { buf.append("root"); } else { buf.append("node"); } buf.append(' '); buf.append(level); buf.append(" ["); buf.append(mid_red); buf.append(','); buf.append(mid_green); buf.append(','); buf.append(mid_blue); buf.append(']'); return new String(buf); } } } } src/main/java/org/freehep/graphicsio/gif/NeuQuant.java0000644000175000017500000003100211312401774022237 0ustar user03user03package org.freehep.graphicsio.gif; /* NeuQuant Neural-Net Quantization Algorithm * ------------------------------------------ * * Copyright (c) 1994 Anthony Dekker * * NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994. * See "Kohonen neural networks for optimal colour quantization" * in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367. * for a discussion of the algorithm. * See also http://www.acm.org/~dekker/NEUQUANT.HTML * * Any party obtaining a copy of these files from the author, directly or * indirectly, is granted, free of charge, a full and unrestricted irrevocable, * world-wide, paid up, royalty-free, nonexclusive right and license to deal * in this software and documentation files (the "Software"), including without * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons who receive * copies from any such party to do so, with the only requirement being * that this copyright notice remain intact. */ public class NeuQuant { public static final int ncycles = 100; // no. of learning cycles public static final int netsize = 255; // number of colours used public static final int specials = 3; // number of reserved colours used public static final int bgColour = specials-1; // reserved background colour public static final int cutnetsize = netsize - specials; public static final int maxnetpos = netsize-1; public static final int initrad = netsize/8; // for 256 cols, radius starts at 32 public static final int radiusbiasshift = 6; public static final int radiusbias = 1 << radiusbiasshift; public static final int initBiasRadius = initrad*radiusbias; public static final int radiusdec = 30; // factor of 1/30 each cycle public static final int alphabiasshift = 10; // alpha starts at 1 public static final int initalpha = 1< 30) throw new RuntimeException ("Sample must be 1..30"); samplefac = sample; setPixels (pixels); setUpArrays (); } public int getColorCount () { return netsize; } public int[] getColorMap() { // keep entry 0 free for transparent color int[] c = new int[netsize+1]; c[0] = 0x00000000; for (int i=0; inetsize) hi=netsize; int j = i+1; int k = i-1; int q = 0; while ((jlo)) { double a = (alpha * (rad*rad - q*q)) / (rad*rad); q ++; if (jlo) { double [] p = network[k]; p[0] -= (a*(p[0] - b)); p[1] -= (a*(p[1] - g)); p[2] -= (a*(p[2] - r)); k--; } } } private int contest (double b, double g, double r) { // Search for biased BGR values // finds closest neuron (min dist) and updates freq // finds best neuron (min dist-bias) and returns position // for frequently chosen neurons, freq[i] is high and bias[i] is negative // bias[i] = gamma*((1/netsize)-freq[i]) double bestd = Float.MAX_VALUE; double bestbiasd = bestd; int bestpos = -1; int bestbiaspos = bestpos; for (int i=specials; i> radiusbiasshift; if (rad <= 1) rad = 0; // System.err.println("beginning 1D learning: samplepixels=" + samplepixels + " rad=" + rad); int step = 0; int pos = 0; if ((lengthcount%prime1) != 0) step = prime1; else { if ((lengthcount%prime2) !=0) step = prime2; else { if ((lengthcount%prime3) !=0) step = prime3; else step = prime4; } } i = 0; while (i < samplepixels) { int p = pixels [pos / pixels[0].length][pos % pixels[0].length]; int red = (p >> 16) & 0xff; int green = (p >> 8) & 0xff; int blue = (p ) & 0xff; double b = blue; double g = green; double r = red; if (i == 0) { // remember background colour network [bgColour] [0] = b; network [bgColour] [1] = g; network [bgColour] [2] = r; } int j = specialFind (b, g, r); j = j < 0 ? contest (b, g, r) : j; if (j >= specials) { // don't learn for specials double a = (1.0 * alpha) / initalpha; altersingle (a, j, b, g, r); if (rad > 0) alterneigh (a, rad, j, b, g, r); // alter neighbours } pos += step; while (pos >= lengthcount) pos -= lengthcount; i++; if (i%delta == 0) { alpha -= alpha / alphadec; biasRadius -= biasRadius / radiusdec; rad = biasRadius >> radiusbiasshift; if (rad <= 1) rad = 0; } } // System.err.println("finished 1D learning: final alpha=" + (1.0 * alpha)/initalpha + "!"); } private void fix() { for (int i=0; i 255) x = 255; colormap[i][j] = x; } colormap[i][3] = i; } } private void inxbuild() { // Insertion sort of network and building of netindex[0..255] int previouscol = 0; int startpos = 0; for (int i=0; i>1; for (int j=previouscol+1; j>1; for (int j=previouscol+1; j<256; j++) netindex[j] = maxnetpos; // really 256 } public int convert (int pixel) { int alfa = (pixel >> 24) & 0xff; int r = (pixel >> 16) & 0xff; int g = (pixel >> 8) & 0xff; int b = (pixel ) & 0xff; int i = inxsearch(b, g, r); int bb = colormap[i][0]; int gg = colormap[i][1]; int rr = colormap[i][2]; return (alfa << 24) | (rr << 16) | (gg << 8) | (bb); } public int lookup (int pixel) { int r = (pixel >> 16) & 0xff; int g = (pixel >> 8) & 0xff; int b = (pixel ) & 0xff; int i = inxsearch(b, g, r); // compensate for transparent color return i+1; } private int not_used_slow_inxsearch(int b, int g, int r) { // Search for BGR values 0..255 and return colour index int bestd = 1000; // biggest possible dist is 256*3 int best = -1; for (int i = 0; i=0)) { if (i= bestd) i = netsize; // stop iter else { if (dist<0) dist = -dist; int a = p[0] - b; if (a<0) a = -a; dist += a; if (dist=0) { int [] p = colormap[j]; int dist = g - p[1]; // inx key - reverse dif if (dist >= bestd) j = -1; // stop iter else { if (dist<0) dist = -dist; int a = p[0] - b; if (a<0) a = -a; dist += a; if (dist 0) { String msg = "GIFPlainColorMap: Too many colors "+(n+e)+" > "+maxColors; throw new IllegalArgumentException(msg); } return colors; } } src/main/java/org/freehep/graphicsio/gif/package.html0000644000175000017500000000026011312401774022117 0ustar user03user03

GIF (Graphics Interchange Format) Output Format.

src/main/java/org/freehep/graphicsio/gif/GIFExportFileType.java0000644000175000017500000000476311312401774023766 0ustar user03user03// Copyright 2000-2007, FreeHEP. package org.freehep.graphicsio.gif; import java.awt.Component; import java.io.IOException; import java.io.OutputStream; import java.util.Properties; import javax.imageio.spi.IIORegistry; import javax.imageio.spi.ImageWriterSpi; import javax.swing.JLabel; import javax.swing.JPanel; import org.freehep.graphics2d.VectorGraphics; import org.freehep.graphicsio.exportchooser.ImageExportFileType; import org.freehep.graphicsio.exportchooser.OptionCheckBox; import org.freehep.graphicsio.exportchooser.OptionComboBox; import org.freehep.swing.layout.TableLayout; import org.freehep.util.UserProperties; /** * * @author Charles Loomis * @version $Id: GIFExportFileType.java 10516 2007-02-06 21:11:19Z duns $ */ public class GIFExportFileType extends ImageExportFileType { static { try { Class clazz = Class .forName("org.freehep.graphicsio.gif.GIFImageWriterSpi"); IIORegistry.getDefaultInstance().registerServiceProvider( (ImageWriterSpi)clazz.newInstance(), ImageWriterSpi.class); } catch (Exception e) { System.out.println(e); } } public static final String[] quantizeModes = new String[] { "NeuQuant" }; public GIFExportFileType() { super(new GIFImageWriterSpi()); } public boolean hasOptionPanel() { return true; } public JPanel createOptionPanel(Properties user) { UserProperties options = new UserProperties(user, GIFGraphics2D .getDefaultProperties()); JPanel panel = super.createOptionPanel(options); OptionCheckBox quantize = new OptionCheckBox(options, GIFGraphics2D.QUANTIZE_COLORS, "Quantize Colors"); panel.add(TableLayout.FULL, quantize); JLabel quantizeModeLabel = new JLabel("Quantize using "); panel.add(TableLayout.LEFT, quantizeModeLabel); quantize.enables(quantizeModeLabel); OptionComboBox quantizeMode = new OptionComboBox(options, GIFGraphics2D.QUANTIZE_MODE, quantizeModes); panel.add(TableLayout.RIGHT, quantizeMode); quantize.enables(quantizeMode); // disable for now quantize.setEnabled(false); quantizeModeLabel.setEnabled(false); quantizeMode.setEnabled(false); return panel; } public VectorGraphics getGraphics(OutputStream os, Component target) throws IOException { return new GIFGraphics2D(os, target.getSize()); } } src/main/java/org/freehep/graphicsio/gif/GIFGraphics2D.java0000644000175000017500000000460411312401774022763 0ustar user03user03// Copyright 2003-2006, FreeHEP. package org.freehep.graphicsio.gif; import java.awt.Component; import java.awt.Dimension; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStream; import java.util.Properties; import javax.imageio.spi.IIORegistry; import javax.imageio.spi.ImageWriterSpi; import org.freehep.graphicsio.ImageGraphics2D; import org.freehep.util.UserProperties; /** * * @author Mark Donszelmann * @version $Id: GIFGraphics2D.java 9974 2006-11-26 22:00:48Z duns $ */ public class GIFGraphics2D extends ImageGraphics2D { static { try { Class clazz = Class .forName("org.freehep.graphicsio.gif.GIFImageWriterSpi"); IIORegistry.getDefaultInstance().registerServiceProvider( (ImageWriterSpi)clazz.newInstance(), ImageWriterSpi.class); } catch (Exception e) { System.out.println(e); } } private static final String rootKey = GIFGraphics2D.class.getName(); public static final String QUANTIZE_COLORS = rootKey + ".QuantizeColors"; public static final String QUANTIZE_MODE = rootKey + ".QuantizeMode"; private static final UserProperties defaultProperties = new UserProperties(); static { defaultProperties.setProperty(QUANTIZE_COLORS, true); defaultProperties.setProperty(QUANTIZE_MODE, "NeuralNetworkColor"); } public static Properties getDefaultProperties() { return defaultProperties; } public static void setDefaultProperties(Properties newProperties) { defaultProperties.setProperties(newProperties); } public static String version = "$Revision: 9974 $"; public GIFGraphics2D(File file, Dimension size) throws FileNotFoundException { this(new FileOutputStream(file), size); } public GIFGraphics2D(File file, Component component) throws FileNotFoundException { this(new FileOutputStream(file), component); } public GIFGraphics2D(OutputStream os, Dimension size) { super(new BufferedOutputStream(os), size, "gif"); initProperties(getDefaultProperties()); } public GIFGraphics2D(OutputStream os, Component component) { super(new BufferedOutputStream(os), component, "gif"); initProperties(getDefaultProperties()); } } src/main/java/org/freehep/graphicsio/gif/GIFImageWriter.java0000644000175000017500000000442411312401774023254 0ustar user03user03// Copyright 2003, FreeHEP package org.freehep.graphicsio.gif; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.io.IOException; import javax.imageio.IIOImage; import javax.imageio.ImageTypeSpecifier; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.metadata.IIOMetadata; import javax.imageio.stream.ImageOutputStream; /** * * @version $Id: GIFImageWriter.java 8584 2006-08-10 23:06:37Z duns $ */ public class GIFImageWriter extends ImageWriter { public GIFImageWriter(GIFImageWriterSpi originatingProvider) { super(originatingProvider); } public void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException { if (image == null) throw new IllegalArgumentException("image == null"); if (image.hasRaster()) throw new UnsupportedOperationException("Cannot write rasters"); Object output = getOutput(); if (output == null) throw new IllegalStateException("output was not set"); if (param == null) param = getDefaultWriteParam(); ImageOutputStream ios = (ImageOutputStream) output; RenderedImage ri = image.getRenderedImage(); if (ri instanceof BufferedImage) { BufferedImage bi = (BufferedImage) ri; boolean interlaced = param.getProgressiveMode() != ImageWriteParam.MODE_DISABLED; GIFEncoder encoder = new GIFEncoder(bi, ios, interlaced); encoder.encode(); } else { throw new IOException("Image not of type BufferedImage"); } } public IIOMetadata convertStreamMetadata(IIOMetadata inData, ImageWriteParam param) { return null; } public IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param) { return null; } public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param) { return null; } public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) { return null; } public ImageWriteParam getDefaultWriteParam() { return new GIFImageWriteParam(getLocale()); } } src/main/java/org/freehep/graphicsio/gif/NeuQuant.pdf0000644000175000017500000214007511312401774022104 0ustar user03user03%PDF-1.2 % 105 0 obj << /Linearized 1 /O 107 /H [ 10329 5186 ] /L 573501 /E 151677 /N 17 /T 571282 >> endobj xref 105 496 0000000016 00000 n 0000010272 00000 n 0000015515 00000 n 0000015733 00000 n 0000016070 00000 n 0000016321 00000 n 0000016608 00000 n 0000017101 00000 n 0000017199 00000 n 0000017251 00000 n 0000017674 00000 n 0000017946 00000 n 0000018202 00000 n 0000018407 00000 n 0000018621 00000 n 0000018906 00000 n 0000019162 00000 n 0000019378 00000 n 0000019684 00000 n 0000019821 00000 n 0000019873 00000 n 0000020045 00000 n 0000020336 00000 n 0000020594 00000 n 0000020903 00000 n 0000021239 00000 n 0000021488 00000 n 0000021742 00000 n 0000021998 00000 n 0000022205 00000 n 0000022321 00000 n 0000022537 00000 n 0000022786 00000 n 0000023035 00000 n 0000023332 00000 n 0000023627 00000 n 0000023935 00000 n 0000024198 00000 n 0000024564 00000 n 0000024778 00000 n 0000025084 00000 n 0000025311 00000 n 0000025363 00000 n 0000025565 00000 n 0000025739 00000 n 0000025900 00000 n 0000026066 00000 n 0000026325 00000 n 0000026499 00000 n 0000026763 00000 n 0000027010 00000 n 0000027270 00000 n 0000027520 00000 n 0000027732 00000 n 0000027954 00000 n 0000028210 00000 n 0000028468 00000 n 0000028718 00000 n 0000028935 00000 n 0000029124 00000 n 0000029347 00000 n 0000029655 00000 n 0000029915 00000 n 0000030274 00000 n 0000030848 00000 n 0000031189 00000 n 0000031404 00000 n 0000031690 00000 n 0000031945 00000 n 0000032383 00000 n 0000032435 00000 n 0000032659 00000 n 0000032847 00000 n 0000033248 00000 n 0000033699 00000 n 0000034171 00000 n 0000034520 00000 n 0000034799 00000 n 0000035061 00000 n 0000035502 00000 n 0000035868 00000 n 0000036179 00000 n 0000036511 00000 n 0000036865 00000 n 0000037201 00000 n 0000037239 00000 n 0000037515 00000 n 0000037770 00000 n 0000038126 00000 n 0000038449 00000 n 0000038644 00000 n 0000038696 00000 n 0000039073 00000 n 0000039222 00000 n 0000039522 00000 n 0000039858 00000 n 0000040026 00000 n 0000040194 00000 n 0000040464 00000 n 0000040730 00000 n 0000041050 00000 n 0000041249 00000 n 0000041506 00000 n 0000041774 00000 n 0000042006 00000 n 0000042187 00000 n 0000042511 00000 n 0000042903 00000 n 0000043155 00000 n 0000043221 00000 n 0000043455 00000 n 0000043507 00000 n 0000043746 00000 n 0000044035 00000 n 0000044322 00000 n 0000044601 00000 n 0000044817 00000 n 0000045048 00000 n 0000045070 00000 n 0000046075 00000 n 0000046376 00000 n 0000046586 00000 n 0000046942 00000 n 0000047255 00000 n 0000047422 00000 n 0000047727 00000 n 0000047937 00000 n 0000048144 00000 n 0000048481 00000 n 0000048854 00000 n 0000049137 00000 n 0000049424 00000 n 0000049710 00000 n 0000050048 00000 n 0000050394 00000 n 0000050670 00000 n 0000050984 00000 n 0000051267 00000 n 0000051557 00000 n 0000051846 00000 n 0000052154 00000 n 0000052466 00000 n 0000052634 00000 n 0000052942 00000 n 0000053317 00000 n 0000053615 00000 n 0000053858 00000 n 0000054702 00000 n 0000055222 00000 n 0000055274 00000 n 0000055539 00000 n 0000055768 00000 n 0000056044 00000 n 0000056289 00000 n 0000056710 00000 n 0000057051 00000 n 0000057300 00000 n 0000057493 00000 n 0000057700 00000 n 0000057890 00000 n 0000058150 00000 n 0000058317 00000 n 0000058525 00000 n 0000058790 00000 n 0000058842 00000 n 0000059141 00000 n 0000059467 00000 n 0000059736 00000 n 0000060055 00000 n 0000060320 00000 n 0000060614 00000 n 0000060960 00000 n 0000061279 00000 n 0000061720 00000 n 0000062204 00000 n 0000062510 00000 n 0000062809 00000 n 0000063073 00000 n 0000063331 00000 n 0000063694 00000 n 0000064015 00000 n 0000064333 00000 n 0000064681 00000 n 0000065000 00000 n 0000065191 00000 n 0000065479 00000 n 0000065764 00000 n 0000066042 00000 n 0000066412 00000 n 0000066685 00000 n 0000067026 00000 n 0000067309 00000 n 0000067537 00000 n 0000067858 00000 n 0000068069 00000 n 0000068484 00000 n 0000068835 00000 n 0000068887 00000 n 0000069239 00000 n 0000069492 00000 n 0000069702 00000 n 0000070054 00000 n 0000070378 00000 n 0000070699 00000 n 0000070954 00000 n 0000071122 00000 n 0000071288 00000 n 0000071590 00000 n 0000071958 00000 n 0000072282 00000 n 0000072530 00000 n 0000072818 00000 n 0000073127 00000 n 0000073431 00000 n 0000073693 00000 n 0000074035 00000 n 0000074291 00000 n 0000074559 00000 n 0000074843 00000 n 0000075142 00000 n 0000075405 00000 n 0000075715 00000 n 0000076006 00000 n 0000076332 00000 n 0000076620 00000 n 0000076954 00000 n 0000077293 00000 n 0000077572 00000 n 0000077977 00000 n 0000078276 00000 n 0000078538 00000 n 0000078845 00000 n 0000079113 00000 n 0000079396 00000 n 0000079761 00000 n 0000080109 00000 n 0000080393 00000 n 0000080823 00000 n 0000081140 00000 n 0000081545 00000 n 0000081929 00000 n 0000082308 00000 n 0000082608 00000 n 0000082967 00000 n 0000083351 00000 n 0000083770 00000 n 0000084001 00000 n 0000084179 00000 n 0000084577 00000 n 0000085007 00000 n 0000085306 00000 n 0000085681 00000 n 0000085988 00000 n 0000086273 00000 n 0000086531 00000 n 0000086794 00000 n 0000087019 00000 n 0000087246 00000 n 0000087539 00000 n 0000087591 00000 n 0000087870 00000 n 0000088082 00000 n 0000088291 00000 n 0000088553 00000 n 0000088715 00000 n 0000089793 00000 n 0000090179 00000 n 0000090426 00000 n 0000090748 00000 n 0000091069 00000 n 0000091375 00000 n 0000091631 00000 n 0000091933 00000 n 0000092193 00000 n 0000092764 00000 n 0000093188 00000 n 0000093569 00000 n 0000093832 00000 n 0000094227 00000 n 0000094576 00000 n 0000094757 00000 n 0000095295 00000 n 0000095634 00000 n 0000095880 00000 n 0000096270 00000 n 0000096551 00000 n 0000096919 00000 n 0000097231 00000 n 0000097493 00000 n 0000097704 00000 n 0000098025 00000 n 0000098422 00000 n 0000098752 00000 n 0000099074 00000 n 0000099322 00000 n 0000099880 00000 n 0000100119 00000 n 0000100443 00000 n 0000100703 00000 n 0000100983 00000 n 0000101316 00000 n 0000101626 00000 n 0000101823 00000 n 0000102139 00000 n 0000102449 00000 n 0000102663 00000 n 0000102841 00000 n 0000103081 00000 n 0000103398 00000 n 0000103708 00000 n 0000104022 00000 n 0000104335 00000 n 0000104529 00000 n 0000104696 00000 n 0000104921 00000 n 0000105184 00000 n 0000105454 00000 n 0000105764 00000 n 0000105938 00000 n 0000106120 00000 n 0000106455 00000 n 0000106757 00000 n 0000107075 00000 n 0000107346 00000 n 0000107608 00000 n 0000107836 00000 n 0000108030 00000 n 0000108339 00000 n 0000108605 00000 n 0000108870 00000 n 0000109086 00000 n 0000109311 00000 n 0000109571 00000 n 0000109837 00000 n 0000110108 00000 n 0000110367 00000 n 0000110637 00000 n 0000110816 00000 n 0000111067 00000 n 0000111287 00000 n 0000111513 00000 n 0000111780 00000 n 0000112105 00000 n 0000112347 00000 n 0000112665 00000 n 0000112958 00000 n 0000113338 00000 n 0000113545 00000 n 0000113821 00000 n 0000113994 00000 n 0000114261 00000 n 0000114614 00000 n 0000114994 00000 n 0000115165 00000 n 0000115187 00000 n 0000116141 00000 n 0000116398 00000 n 0000116677 00000 n 0000116897 00000 n 0000117147 00000 n 0000117382 00000 n 0000117656 00000 n 0000117902 00000 n 0000117954 00000 n 0000118325 00000 n 0000118570 00000 n 0000118793 00000 n 0000118990 00000 n 0000119171 00000 n 0000119333 00000 n 0000119385 00000 n 0000119552 00000 n 0000119838 00000 n 0000120122 00000 n 0000120413 00000 n 0000120722 00000 n 0000121001 00000 n 0000121308 00000 n 0000121543 00000 n 0000121806 00000 n 0000121992 00000 n 0000122257 00000 n 0000122466 00000 n 0000122663 00000 n 0000123062 00000 n 0000123308 00000 n 0000123461 00000 n 0000123669 00000 n 0000123894 00000 n 0000124124 00000 n 0000124300 00000 n 0000124490 00000 n 0000124724 00000 n 0000124958 00000 n 0000125200 00000 n 0000125456 00000 n 0000125718 00000 n 0000125980 00000 n 0000126002 00000 n 0000126915 00000 n 0000127156 00000 n 0000127344 00000 n 0000127610 00000 n 0000127844 00000 n 0000128020 00000 n 0000128072 00000 n 0000128388 00000 n 0000128664 00000 n 0000128801 00000 n 0000128969 00000 n 0000129150 00000 n 0000129331 00000 n 0000129785 00000 n 0000130227 00000 n 0000130564 00000 n 0000130746 00000 n 0000130768 00000 n 0000131595 00000 n 0000131617 00000 n 0000132544 00000 n 0000132566 00000 n 0000133455 00000 n 0000133829 00000 n 0000133881 00000 n 0000134153 00000 n 0000134398 00000 n 0000134610 00000 n 0000134887 00000 n 0000135129 00000 n 0000135426 00000 n 0000135717 00000 n 0000135999 00000 n 0000136286 00000 n 0000136541 00000 n 0000136823 00000 n 0000137093 00000 n 0000137264 00000 n 0000137452 00000 n 0000137703 00000 n 0000137868 00000 n 0000138154 00000 n 0000138472 00000 n 0000138766 00000 n 0000139032 00000 n 0000139348 00000 n 0000139524 00000 n 0000139576 00000 n 0000139769 00000 n 0000140019 00000 n 0000140266 00000 n 0000140516 00000 n 0000140753 00000 n 0000141022 00000 n 0000141275 00000 n 0000141563 00000 n 0000141879 00000 n 0000142113 00000 n 0000142356 00000 n 0000142563 00000 n 0000142815 00000 n 0000143103 00000 n 0000143320 00000 n 0000143614 00000 n 0000143821 00000 n 0000144067 00000 n 0000144230 00000 n 0000144439 00000 n 0000144477 00000 n 0000144700 00000 n 0000144766 00000 n 0000145246 00000 n 0000145669 00000 n 0000145721 00000 n 0000145972 00000 n 0000146221 00000 n 0000146456 00000 n 0000146700 00000 n 0000146954 00000 n 0000147124 00000 n 0000147353 00000 n 0000147660 00000 n 0000147911 00000 n 0000148099 00000 n 0000148341 00000 n 0000148550 00000 n 0000148718 00000 n 0000149012 00000 n 0000149226 00000 n 0000149443 00000 n 0000149465 00000 n 0000150276 00000 n 0000150480 00000 n 0000150502 00000 n 0000151446 00000 n 0000010329 00000 n 0000015492 00000 n trailer << /Size 601 /Info 104 0 R /Root 106 0 R /Prev 571271 /ID[<9846b24c8858153cada68df2892762d2><9846b24c8858153cada68df2892762d2>] >> startxref 0 %%EOF 106 0 obj << /Type /Catalog /Pages 102 0 R >> endobj 599 0 obj << /S 6754 /Filter /FlateDecode /Length 600 0 R >> stream HWyECIRNyi0u. %llZjY6hXl;zI '颮LZ۴;8y~=Bl mYs(*]O3=wЍk ĝwvήC_X zm ]m{/\JC?[R&0z_Jf  JbF 9:1F l82 CKkDH&c(q(LBf3 xLc3:ƣ,,$t/בwO#>,EN~{qk׹730CRxmQ/"adDž8{)Ags+HXL'H!-zҐD y莘)F!%r4}'d'TLmv &ZWt$h9O [BӘI@8fF,U[ѐX)ҙkdJzwPPs+뇀!]K◺l'vKC>"Mgq=K&,& /T/c^,}| }<űT1 >KЙ )ubp7Q3 L'qcڤS[ ԡk\| R9} H}:W0anx6,}?0}2Lz^6;^h:6LGH2$LBux4vbu#NK츦(7c!GʚpX B[knݼPQչ".&pk:0Uqٸ6 3Žmn7dPCY D*P/YսquxOMƀYKs6Ē]"O$(2_B0zR,d\;W<-;'>A$?VGL3<;::$=Ok|H<J /h+ O?ٵ?P7ߝn=~r6|yn@ 7Pqe|u}']vUCu\s2Pf ;:ջ͝D}HYeaؑ̆Yb޷loJ{.4m2.|/Ke Rq5|t Gg]*B4(|11$B{K\>L -&!zn]W 1lZ+ RHt*G}¬W'!ubv͝g +u%kuO-_(vI[}ǧ:%f< Ed5Vթ[ՀeF2ZMyr)Dk]5DoOg;wȳUT"`[qPpHt$a6$֤bNHYO]@iHËA$5ܜHci4MrW `TcSD вHJ*X~4CL7^ ͆svt\ONx(\ h+?Vj-qsBů~\ǵ+gnԀHJZl ɼT=2˸EբFHX ZhTw!ʣh  $MD!l3AXAA9Q Q[ :#gT*$QhG{#-8H; Z3'k睘EWMPx90\]J;P7;㈒l\?-n1Ėl_.XV 珩},IGD` \恦X@H["XfAx!" "-lI7[4&qm#ATA8zs)P{B [RKtShivXt?nx;`'~X`';B^ *VTuoPro"{۴w8V=.{lQ>q>ͽ8)Ӻ^v T9a*gogӐG/}ƶ2*E!fEvJ}BC'UrA1@ł!=naqˌu-AYS9 rJ?*Է 5^g|6\ݘV[4qZ|uXu5eqĆhQ{fWlfdO}ZZ8kkTv[ ,_\BQo}CEl{Ʀ 63-FDB'}ޯVXjC1kM v&"*'l6@^$Uz^t\m85=oTPYѲTr3tcW@軕 lzS6Ҵ8=P毫s ^@D. q_se5eY@ĐvqQ饀gCV̡ۄWANq>o!cҿ"rI, sQL C$Z>k]N $PRlj&bB+&yf!斸]ݔ'~ 6nhv'ahY-wfE´{5']GɎ7WT5X6/D YU67?8ĭ#3VefTTI|a ]je0K^g@dG /JI 㩉(jIdG7MkHk>ȱ8S獪~j?y}>t>y\{2*Ck3뛜-=xd#}vOkE+*|ɀ M>"!ե">QkE`W #8W]jlpP?p5DhGHCiw5riU;@  tvǃڣ 2'HLi,j^ep@:xp> ޳g>hPӒΣ0Li(*'GT{} BX lUB1=e23|xЈ jh r6M.b:䎬J#mUGcALr~ޗLq9_{w{݌}ڨެqOV(Xݛ@Ț i(p5D2`TKmʏp1 &(G]dG.me' dY-L,Ӊq ?_ϱ9C }mH`?{;F/mjxU9a~BQ u9/9-[)\_|WGy %;$;VK:xO.[M^ZQop[UKmeIޚOZ /D@i9+rh }TZmp_)0`z30s: LfEE lrCHkliBlp;amW8&mrrj$56 bHFc]ۍ[lr ;zc2c#hVr0A:X?6$(N`( L"H+mf(ҥMBM}7tEb,ZvFfD6h_QLȩdn~? `ұK.k2;/-K.yd>֒5SD<X j'2k/>WjON&΂G.5L Vٔ p)󠭂꟮~&+p#gEuki8+hsPTG#cGX7>PVd̑Q0u+nEFs*_Pa=8u Km'ySp3듏i9ܴY:N)?qPC^@:!;[$wTOeaIwxqT+ٲyMCO SLS? ',pU9 ŝu28-#|Q/RMBdL/%  1ص's%'wOy`@9'NG,9H=S> endobj 108 0 obj << /ProcSet [ /PDF /Text /ImageB ] /Font << /T6 526 0 R /T7 575 0 R /T8 572 0 R /T9 516 0 R /T10 468 0 R /T11 488 0 R /T12 252 0 R /T13 278 0 R /T14 399 0 R /T15 379 0 R /T16 114 0 R /T17 129 0 R /T18 196 0 R /T19 211 0 R /T20 175 0 R /T21 184 0 R >> /XObject << /Im1 595 0 R >> /ExtGState << /GS1 598 0 R >> >> endobj 109 0 obj << /Length 176 /Filter /FlateDecode >> stream H$1 0C-=BrM:t+T3:yutPt7rc#tt(~TR,T W3ӕLyfjKLIz'nrvǙZ!1 |ڧC;b I_W)4 c: T2 )b֖`H` endstream endobj 110 0 obj << /Length 211 /Filter /FlateDecode >> stream HT=ABZбQ hƭG*f^aT1aoezd'^ɊA-)ʵ{ r%,ɀ7W9C~!ݤb/gFW`[ 99 ܵΈQ2>s̩Y#RLxYjCg!#(`˃ endstream endobj 111 0 obj << /B8 147 0 R /B9 150 0 R /BA 149 0 R /C1 148 0 R /C3 144 0 R /C6 139 0 R /C7 138 0 R /CB 140 0 R /CC 143 0 R /CF 142 0 R /CP 141 0 R /CQ 151 0 R /CR 161 0 R /CS 160 0 R /CT 159 0 R /CU 162 0 R /CV 165 0 R /CW 164 0 R /CX 163 0 R /CY 158 0 R /CZ 153 0 R /D0 152 0 R /D1 154 0 R /D2 157 0 R /D3 156 0 R /D4 155 0 R /D5 166 0 R /D6 117 0 R /D7 116 0 R /D8 118 0 R /D9 121 0 R /DA 120 0 R /DB 119 0 R /DC 115 0 R /DD 110 0 R /DE 109 0 R >> endobj 112 0 obj << /Type /Encoding /Differences [ 65 /BT 97 /CP /CQ /CR 114 /D6 /D7 /D8 ] >> endobj 113 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 114 0 obj << /Name /T16 /Type /Font /Subtype /Type3 /Resources 146 0 R /FontBBox [ -4 -17 77 51 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 44 /LastChar 122 /Encoding 145 0 R /CharProcs 111 0 R /Widths [ 21 26 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 0 60 0 0 58 60 0 0 0 43 55 0 0 79 0 0 0 0 0 0 0 0 0 38 43 34 43 34 23 38 43 21 23 41 21 65 43 38 43 41 30 30 30 43 41 55 41 41 34 ] >> endobj 115 0 obj << /Length 196 /Filter /FlateDecode >> stream HD= @F7l&{Mֵ QVZZ(ډQ,,s%;K>g|}" 驭ȍU'bl)d1VtN Q ZH<;r6𺎀@rV2j ٨ v%V SrB^W.MSZ_`v endstream endobj 116 0 obj << /Length 180 /Filter /FlateDecode >> stream H<1@%ivX&RhBq-xh,g~rȆǚ͌)4ܭDK&c4`&`%fΚlHقZ4J(ox8PDx+P֪MPh/1~/ mhKCm_ endstream endobj 117 0 obj << /Length 129 /Filter /FlateDecode >> stream H26P0P0b#sccCB.#3(kgk$s≮=R\N \ %E\.\31g)gx`Ca(fP84A\= d endstream endobj 118 0 obj << /Length 138 /Filter /FlateDecode >> stream H26P0P0T5T02U01SH1*22Q +Dr.'~ PK)YKW4Ӆ(AF0!~c D?o|\\\p+ endstream endobj 119 0 obj << /Length 209 /Filter /FlateDecode >> stream H25U0P0T5T05V06RH1*25 (+Dr.'~PK)YKW4ӅC?*?A3 57?(JR@Ȕ=zPîAYRS?p(PHNߎAՓ+ =d endstream endobj 120 0 obj << /Length 180 /Filter /FlateDecode >> stream HL1 @lm.f%XV@--m#x+,l#6)}-YX!g8Hk5ysV!ycsO,m+C,XG.&@RQD↗88'\cE~MvH"Ch} `@|1ai[ endstream endobj 121 0 obj << /Length 140 /Filter /FlateDecode >> stream H21V0P0R5T01P06VH1*2 & Fz@9 ɥ`lw pV0U()*Mt H 4%P ?78#~?'W @G億 endstream endobj 122 0 obj << /Length 230 /Filter /FlateDecode >> stream Htбj0 |/X;N}6c5/!띔Ix u2n/ 'nҍ6ol6Gji]Dfv?EP ӫz G$M@rt;A't 1藓9h jPUAf;'2F rzLJQo.Zsi,_O1 endstream endobj 123 0 obj << /Type /Encoding /Differences [ 46 /BA 64 /BS /BT 67 /BV 77 /C5 100 /CS /CT 103 /CV 107 /CZ 111 /D3 114 /D6 ] >> endobj 124 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 125 0 obj << /Length 97 /Filter /FlateDecode >> stream H21Q0P04F )\\@$l3T5ɹ\N\@Q.}0<}JJS<]?P`  r 0M endstream endobj 126 0 obj << /Length 215 /Filter /FlateDecode >> stream H=n@qisbQ"#"Rr2EЂ9WQ8K/3zOi潲ԱZu:яB$ӞAsa3Sofol$uՋ|wR QhihQ1@|MPs?q9s|9޸r?j uIc$[Ծ~2&TO=i$h`-moKvԶٿ+ʯ)w endstream endobj 127 0 obj << /Length 182 /Filter /FlateDecode >> stream Hl @Y }U@ԩڛ(>GY  C _O(g bݽW'R=Bw'ݕ~nBzQ-Q C #C&1D*riʻ> stream H1N0Dm79}H$V_Z@"T()@lm#.潉Ex(<ַ=7W״w^Gik4>`4yc4) z*]&5S"lQ'ki`nC$:O+iQ2gKdك!xlj_DP*O+o endstream endobj 129 0 obj << /Name /T17 /Type /Font /Subtype /Type3 /Resources 113 0 R /FontBBox [ 2 0 63 52 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 65 /LastChar 116 /Encoding 112 0 R /CharProcs 134 0 R /Widths [ 67 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 43 49 39 0 0 0 0 0 0 0 0 0 0 0 0 0 0 36 35 34 ] >> endobj 130 0 obj << /Length 173 /Filter /FlateDecode >> stream H1 0W2#$жBU0PG B1C7)twx7k]jf׊[6))eerrqK.q+.A?-#<}31W3׮H|@57݄ > stream H2T0P0bSS#CB.c 53T5ɹ\N\ &\@).}gC.}O_T.OL2 070 v i13# IyH$ fm q=<nzcszrr] endstream endobj 132 0 obj << /Length 180 /Filter /FlateDecode >> stream H\= @kr}V@--yaKL]i%o]jU鵐Թg,t]֭dgs$[7ZH|ߤ݊38|6$dHCƧdtdُyFIbOW܀yr#dI )$^( endstream endobj 133 0 obj << /Length 131 /Filter /FlateDecode >> stream H26S0P0bccJ1*26"Fz @"9ɓK?\ؐK(ťx*rypcPl2 ,*0`00O)f`G\\\W endstream endobj 134 0 obj << /BT 122 0 R /CP 132 0 R /CQ 131 0 R /CR 130 0 R /D6 133 0 R /D7 136 0 R /D8 135 0 R >> endobj 135 0 obj << /Length 140 /Filter /FlateDecode >> stream H26Q0P0a sCB.#3 53T5ɹ\N\ Ff\@).}gC.}O_T.OHA 8=Nc?>r 0 endstream endobj 136 0 obj << /Length 173 /Filter /FlateDecode >> stream H,; 1Y L.l jihf9GHba0k([e|`ܔѮZ6\.w=j;{>ePz=7[$X !%]7jjn(˲H F1p(K|p4%  ܏M endstream endobj 137 0 obj << /Length 173 /Filter /FlateDecode >> stream H21Q0P0bCSCCB.cK 53T5ɹ\N\ Ɩ\@).}g PRT 3 Hp߂A$A&20FT QcQ#`D$QfqD'h7r 0{= endstream endobj 138 0 obj << /Length 221 /Filter /FlateDecode >> stream H=@F1$p(kKO"V@--4ZLo()̺c/!e}11A3c0JI>ʸ = 5 o/o %!e>lcFME/ƓЕGΥn3T YI: VTr@O$nPщHMx/j;6?aU 0@ endstream endobj 139 0 obj << /Length 219 /Filter /FlateDecode >> stream HTбJ` t Kٜ N;:*N7nVvkT$d ;y#_ :RJ縹(<|}E-ewlpBuTݐyg @&N'W.cUn-mtO+cl"E.4ҖJZDe)RV4oJ{f/ +ƅIk|?YqVH endstream endobj 140 0 obj << /Length 232 /Filter /FlateDecode >> stream H\=N0Y4{ v$:K H@%(V&>BJG+O<{ƎA:rx,D w=?rZd$)Јթ܎r# O2@jdxVv| vHʼ6Hɤ˅tY*ٞخd5@0f#[%}3h^1AG;ysR՜G/s+[ endstream endobj 141 0 obj << /Length 187 /Filter /FlateDecode >> stream Hl1 @ vS&a\ ji(mN"z/2E; ڈ g#܍YYyӁdGu<`݋6{JR rC\* c SBfJ@a[7 An /%u P$+oP+x\`2<kۺqGRI w,PW~ endstream endobj 142 0 obj << /Length 290 /Filter /FlateDecode >> stream HlпJ@)#d;+E VSV>ZZވ#U"y|NDfLv:;{:"W)RϹ^tUAɅΖp١N))N5GT+e:AuQa 61:~LD۳^rRȠTO1IQ&`$ "T%zHkj6_A*MYU0pkZ5ԆsDUsDUisD-kx)Xkc=⩯拧EvI:.~M endstream endobj 143 0 obj << /Length 138 /Filter /FlateDecode >> stream H25U0P0bSCJ1*2"z @"9ɓK?\ĂK(ť<}JJS<]A~B?AdDOH<```F!\= o endstream endobj 144 0 obj << /Length 230 /Filter /FlateDecode >> stream HT1n0 P  p 8$!@:i -ٹA0 ěìHh=HO2ZQl#/,$azi|m鉊5oqG@'V{p!3 ̑PDKų2#QRkE7Z#VH hh4:(;s!i-? :kI N塖6 G\ endstream endobj 145 0 obj << /Type /Encoding /Differences [ 44 /B8 /B9 /BA 73 /C1 75 /C3 78 /C6 /C7 83 /CB /CC 87 /CF 97 /CP /CQ /CR /CS /CT /CU /CV /CW /CX /CY /CZ /D0 /D1 /D2 /D3 /D4 /D5 /D6 /D7 /D8 /D9 /DA /DB /DC /DD /DE ] >> endobj 146 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 147 0 obj << /Length 126 /Filter /FlateDecode >> stream H22T0P0S54U" CB.K!H H&r9yr+Xr{ =}JJS<]o A??szrrܩ2 endstream endobj 148 0 obj << /Length 99 /Filter /FlateDecode >> stream H2P0P0aSSCCB.#c 53T5ɹ\N\ F\@).}g PRTAg`t=\\\Fi endstream endobj 149 0 obj << /Length 86 /Filter /FlateDecode >> stream H22T0P0bC CB. 13T5ɹ\N\ \ )YKW4Ӆp#4r 0 endstream endobj 150 0 obj << /Length 91 /Filter /FlateDecode >> stream H22S0P0T04Q0 )\\F h`4ֳTHrW02P0w pV0U()*Mtb`GF\\\Rz, endstream endobj 151 0 obj << /Length 183 /Filter /FlateDecode >> stream H1 @P"2)<@lQV@--(^,G) +fg9{׊vc3 8V[J3cfE~:"?aP6&q4)+OA:i ip#1wҫp߈O@Vv7lz׀ @`^ endstream endobj 152 0 obj << /Length 99 /Filter /FlateDecode >> stream H22T0P0bC S#CB.C3 53T5ɹ\N\ f\@).}gC.}O_T.O `AM~0r 0KBj endstream endobj 153 0 obj << /Length 188 /Filter /FlateDecode >> stream H1 @ )V!G^@7hV@--'Jv^C)S,Yۨ<fOϨD\@S1,>Av$zG%RYNz#b i;WiKvB.ދ_j7@2M FX) OpW -V 0 g-R*Հ0 b(4,v endstream endobj 154 0 obj << /Length 171 /Filter /FlateDecode >> stream H23U0P0b3#ccCB.3r t Dr.'~PK)YKW4Ӆ 37a'Pp?p?h@ {dAH`  4'W @y endstream endobj 155 0 obj << /Length 184 /Filter /FlateDecode >> stream H1 @Е+G\@J DSZyP5z%GL1Sy|C(]|J6vאs:t/fl\FA[rDAqlEb(jh>ިz( \4D > 2-DwW!E^Q kb^p#v(C`qR- endstream endobj 156 0 obj << /Length 174 /Filter /FlateDecode >> stream H1 @D/*-Djih/o#"dd>a^rO9H RTNW*-#kMr,~Ŋ]POơޠ3}oz!E"j᪐B#bCi,⪸oXJK0+ endstream endobj 157 0 obj << /Length 136 /Filter /FlateDecode >> stream H21V0P0bccCB.c 53T5ɹ\N\ \@).}gC.}O_T.O?37ggSAPNӔApzrry endstream endobj 158 0 obj << /Length 146 /Filter /FlateDecode >> stream H22V0P5Q54S"SCCB.#43W5ֳ*$r9yr+p{% =}JJS<]C~r 0ĥ=:?y@dC0` endstream endobj 159 0 obj << /Length 180 /Filter /FlateDecode >> stream H\=@`4{ gA j"V@--4Z'Jt^v-P7{3i'<9u)+% #Nc׹uPQ:pڸT[rL8S" 腩4h+1m1CLy?>SOZ3*LxZ 9^#0}XZq$l endstream endobj 160 0 obj << /Length 182 /Filter /FlateDecode >> stream Hα0`L[xB&AMd0PGΔ7td ׈$&c8Q(LgxTp2T*Θurb@z?A"<. 4!c#.lsj. 71ֿ13z8`{U6 5A.v`7F endstream endobj 161 0 obj << /Length 174 /Filter /FlateDecode >> stream H!@PHɘ=Bv[D&VD@@/+CrM?S'7bL&/8eӌs]H2L9eI;Y%.8nv. a+]ܩ`jEt)xM >+KQe;(Ҏ t+ endstream endobj 162 0 obj << /Length 141 /Filter /FlateDecode >> stream H22V0P0b#sScCB.#3 53T5ɹ\N\ Ff\@).}gC.}O_T.O~??I pL^rՓ+  endstream endobj 163 0 obj << /Length 113 /Filter /FlateDecode >> stream H22T0P0bC SCCB.C3 53T5ɹ\N\ f\@).}g PRTy`?C ? ~g.WO@.?J endstream endobj 164 0 obj << /Length 147 /Filter /FlateDecode >> stream H21V0P0bS#CB.c 53T5ɹ\N\ \@).}gC.}O_T.O?g@%~?T"o? ('iJ`P` \= < endstream endobj 165 0 obj << /Length 232 /Filter /FlateDecode >> stream Ht1N@EJai_){pCHR HP@"("\̹".f ˟.hVoVziffnΫkS/L}i^**uUEDyF5MZSrxcؚ{ۿjs%>/'"E&Q2Lcd&K8#r7F5 h/ endstream endobj 166 0 obj << /Length 184 /Filter /FlateDecode >> stream H; @irtltV@-(Z'GQ Rnv]L fq+/ f *Fx]ll2u%K.kiHR_or"<)}J'8|\јXΊ>0fSi>8Gjk^ endstream endobj 167 0 obj << /Length 283 /Filter /FlateDecode >> stream H;N0`G),M7d#KiHPq=L.8H ҅e "94ǶRr-oQ^>D? O+ma6wȷap81+]tK_ } endstream endobj 168 0 obj << /Length 498 /Filter /FlateDecode >> stream HԔ0g"~3^5'< $KqJ\L;Sk'\Ї#3-h#,!5ϝOCҶŅ"8Ǯ*u,> stream HN0utK!D+6K$2 ce)oAb–Yw?;G;j^v(seq89#h;ho8{h[|{>xD"{Y+j hj(:gM@BNeiIyXIϕ|-yZ|,@)hf㎐> 9q/`4/f$}1}kjԨWH4,KYh endstream endobj 170 0 obj << /Length 139 /Filter /FlateDecode >> stream H26U0P0aKSCB.#s 53T5ɹ\N\ F\@).}gC.}O_T.O?bH X-?v4@ q  ? ȘՓ+ P(e endstream endobj 171 0 obj << /Length 210 /Filter /FlateDecode >> stream Hѽ 0>BNڄBT|utPtn7_+#tz&Dqp@~8sWQJ}r$m-FՔ %;.{LfHF?<Ao# +hV*hSJ#> stream Hұ0[LD'?@4:çSFyq&^.MZQcaWh,y4̹AzBC3Hys{|ܟWp .f A)ښIWg}$B`4_!qdQ'>NgpwK}} (8 4 endstream endobj 173 0 obj << /Length 362 /Filter /FlateDecode >> stream HԔMN ih¦Gx\@ ϤIWM؅> endobj 175 0 obj << /Name /T20 /Type /Font /Subtype /Type3 /Resources 215 0 R /FontBBox [ 6 3 43 46 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 3 /LastChar 3 /Encoding 213 0 R /CharProcs 189 0 R /Widths [ 50 ] >> endobj 176 0 obj << /Type /Encoding /Differences [ 67 /BV 75 /C3 78 /C6 /C7 81 /C9 97 /CP 101 /CT /CU 104 /CW /CX 107 /CZ /D0 /D1 /D2 /D3 /D4 114 /D6 /D7 /D8 /D9 119 /DB 122 /DE ] >> endobj 177 0 obj << /Length 325 /Filter /FlateDecode >> stream HlAJ07TB/ L. ]҅;!=ZI tE6M')$|I!)Znqԥ+RwQmpvE)8=]#'YmDqD{({*Y|4@>"Aہu;c$+k"Qsc3f8 4̽8=#}DD31#j{Uagz3f Et=Ĝ25# 4LH{9evKfF~4=\&hyJl '9$i$Oَf(L>F( 0c$3qۈG/d endstream endobj 178 0 obj << /Length 376 /Filter /FlateDecode >> stream H1N@٬d9\@wźɪ&Zyh "rqvcoda??|{m?k?>adwg[yyׇRo}7o2S>d_oR)vDgq]~$x\9q6B> stream H=J@ [f.Iva٭")oV\8'y~'7+_w7y}-__y}6I3130;.ıKlz"LEXgiEI5R/{TpP֦D3hxBI,S#RYd "H橅O>/3/3T3 > stream HAN0!,Hf (%!F&0ѕP.4ƋM8K37/F`3Ygwt>up^m'޷\ٺ*q9%}}y{׹YØH?\3Q[:ѧ@) ON:"lԩQN`yH=#4]uS*&s"-$+qNsc1C]Q/ BQB_B[}!!ځ @2~/[oUi` endstream endobj 181 0 obj << /Length 203 /Filter /FlateDecode >> stream H1 @I#d.1DVQV@-- R:SF,olJWBibbBYec+'a'LD#Pw5'#F()rHQwTMcdwe3RrŽ\_Xo3:8Y.*4kP52rQf)'<t endstream endobj 182 0 obj << /Length 186 /Filter /FlateDecode >> stream H25T0P0T5T01QPH1*21 (XX*Dr.'~1PK)YKW4ӅAɎN ?0l 0H C2?{tԃo4$PՓ+ m endstream endobj 183 0 obj << /Length 365 /Filter /FlateDecode >> stream HұN0`G"y#/i(RH01:":5-C?ۑPՁtK5]RWzv_K!)^NlK>c. YFmipU-؆60 Dƍ={m)g7ch`gS-i; >0:λ6l F),Z>EtqF::ax hf`E4ϸS&{ꆭ9; ~n!d? endstream endobj 184 0 obj << /Name /T21 /Type /Font /Subtype /Type3 /Resources 174 0 R /FontBBox [ 1 -28 98 98 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 67 /LastChar 122 /Encoding 176 0 R /CharProcs 185 0 R /Widths [ 96 0 0 0 0 0 0 0 103 0 0 99 103 0 103 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 66 0 0 0 58 40 0 73 35 0 70 35 111 73 66 73 0 51 52 51 73 0 96 0 0 58 ] >> endobj 185 0 obj << /BV 179 0 R /C3 178 0 R /C6 177 0 R /C7 173 0 R /C9 168 0 R /CP 167 0 R /CT 169 0 R /CU 172 0 R /CW 171 0 R /CX 170 0 R /CZ 180 0 R /D0 194 0 R /D1 188 0 R /D2 190 0 R /D3 193 0 R /D4 192 0 R /D6 191 0 R /D7 187 0 R /D8 182 0 R /D9 181 0 R /DB 183 0 R /DE 186 0 R >> endobj 186 0 obj << /Length 256 /Filter /FlateDecode >> stream H\=J@ [,Gع&q+aU0X--'G XxSŒ#"@#!ĕ\e<_Ƨ^iFWgm\Ic<B Q@+'ưO\UR_/Rؑ-cnȖ2Lȗ}KO5[<#8yɄC<n <134}=}}==x^y {^1X|Y'MG#L endstream endobj 187 0 obj << /Length 278 /Filter /FlateDecode >> stream Hd1N0ERD$a]$R AJ cM|),3ނhf=\my+soRlvpN4+&l õ밙 N7 6GX(R(@̞ffGK{Jc@RJ}u-$iBiFM*-䢔V`Zw,$ZQeSbd33ҩ$Ṗ/؄1l$e5ȳx;# 0c<  endstream endobj 188 0 obj << /Length 260 /Filter /FlateDecode >> stream HұN02Dŏ`K L* K$2 щ@0#x5x "]ΗXn-f.=?Eƫy-jnP8Z]U}6\Q(tAS)h(Y( eW,9q(N4œ@(yǮLҕZ˷/ /f ;PGh?(w U? m7"2: %L2QCEk`4aJj endstream endobj 189 0 obj << /A3 212 0 R >> endobj 190 0 obj << /Length 200 /Filter /FlateDecode >> stream Hѱ 0::(:G:v=/Վurt$AnPR"9 ΘXT{55_J yOhHPQ A` 7rSAϠBU07TQ6KmلyAU`hG_Aʁ@8. peq/0Ý endstream endobj 191 0 obj << /Length 179 /Filter /FlateDecode >> stream H1 @4{ h] *b%Q7(9B1B,X_ψ}*P{QCz`!17jL CC3AlpG)J'pNp~e֔ -cv{݌U|(y@85Ɨ@%O endstream endobj 192 0 obj << /Length 280 /Filter /FlateDecode >> stream HJ@)=,%hCcBU0|֣EωoG1qfvTz$f漴-Vv[3VsEaB&yUكf妾/oX_# ZGD= NaK˔zCECnsM3¯a}"H#4t4bgº/&c⸋I}P9y̼@ʫE),I>GRJ`K_&!w8Y؁ p>mIl!M!ly endstream endobj 193 0 obj << /Length 247 /Filter /FlateDecode >> stream H;0 S1T @[H0q`dr#tP5. H⿶'I0G!&"܅p8qH9ڶo0N_P j!ϧhU+#TD;7 y, +J|ĕ(אzA[5)i(=WF재e63RſWzochR700*ظ/=쬥R ޝ`  endstream endobj 194 0 obj << /Length 119 /Filter /FlateDecode >> stream H26U0P0aCCCB.# ogk$s<,=@r\N \ %E\.\`  P|`S7 k~d`% endstream endobj 195 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 196 0 obj << /Name /T18 /Type /Font /Subtype /Type3 /Resources 124 0 R /FontBBox [ 2 -19 42 51 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 46 /LastChar 114 /Encoding 123 0 R /CharProcs 201 0 R /Widths [ 44 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 44 44 0 44 0 0 0 0 0 0 0 0 0 44 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 44 44 0 44 0 0 0 44 0 0 0 44 0 0 44 ] >> endobj 197 0 obj << /Type /Encoding /Differences [ 46 /BA 65 /BT 68 /BW 72 /C0 101 /CT 104 /CW 107 /CZ 110 /D2 /D3 114 /D6 116 /D8 121 /DD ] >> endobj 198 0 obj << /Length 224 /Filter /FlateDecode >> stream H10pz-$Pu"AM`PGp41ڄMoӀFK ^ o4 4P v<U[Ď> 5=oxBKYw{y+A4AHb[AT~"a9y]?Ba鰘#(6F? `[滑`#/5+ endstream endobj 199 0 obj << /Length 260 /Filter /FlateDecode >> stream Ht=j0p:H ء!cddq@IPI?!!O +MK^pNBo'㒽4>aVCeC#g9^ UC,9 OI86q΍髋U]y؍,ԢpGpC"F.NظxC?&;GC8xh> stream H22W0PbC CCB. @BPAH$r9yr=S!BIQi* b?`71 endstream endobj 201 0 obj << /BA 125 0 R /BS 128 0 R /BT 127 0 R /BV 126 0 R /C5 137 0 R /CS 203 0 R /CT 202 0 R /CV 204 0 R /CZ 207 0 R /D3 206 0 R /D6 208 0 R >> endobj 202 0 obj << /Length 194 /Filter /FlateDecode >> stream Hl1 @ )$$ V QV@--o)~6V.aln-W\Kw-0VrrihvBWՇ-4kx]( $G$$G܌ A-ob7q@x7xCa7c_u endstream endobj 203 0 obj << /Length 190 /Filter /FlateDecode >> stream H10 DЖU H0q`dLY#dP-  yeE3m3=)+K3$#-mJH7Ԃ-5}v D ?iFvBlFѾø#(?HFRɆ!@h^WDL=G endstream endobj 204 0 obj << /Length 244 /Filter /FlateDecode >> stream H|J@'l0M!` A+[A-P^,&_`ΤBFNK ]Ko*96Qm壄[ո_Iew']3ca zi!⒏sC*;P[ Se5[ V1(z H_^Z\,a؋zQ1)nbbQ!kbi`$o3[M#\ endstream endobj 205 0 obj << /Length 123 /Filter /FlateDecode >> stream H27V0P0b3 J1*2"&z @"9ɓK?\̄K(ť`ȥPRT` P `P?Ïy=/ g\Փ+ TO| endstream endobj 206 0 obj << /Length 181 /Filter /FlateDecode >> stream H|=@XL BL6AMD+q=%ab^2}yN) edWt>|"ܱhd 4{Y)-r7c"58be.6# nDFΫs&./%G-.N48 pP E!\y> stream H;@!^@yZP&Rhekq@IAX!ZES^䫙>_8=WΜfTBt3W]'\8Zk(*;$뛾 t;hlP;20Ca sTcÐ]V+:u^<'U^PB&ј}o)ڰ endstream endobj 208 0 obj << /Length 156 /Filter /FlateDecode >> stream H1 @Б- ̿n .BK Ek^cX廦-T\T9wձ<##]Mv/fYz 0Ri)D<`F%##FD*JysEE2~1l endstream endobj 209 0 obj << /BA 200 0 R /BT 199 0 R /BW 198 0 R /C0 205 0 R /CT 218 0 R /CW 216 0 R /CZ 217 0 R /D2 221 0 R /D3 219 0 R /D6 220 0 R /D8 214 0 R /DD 210 0 R >> endobj 210 0 obj << /Length 248 /Filter /FlateDecode >> stream Hd=N@`[."M#x.,@@% !W+Q rH>f|žY=9cN|#FM995ohVP84B2 g'SX\=8u,6ƪP$5V w־5Fl& :tVE9\]] Jٞ|6jaȲw{gUUt7zsվk| _,C endstream endobj 211 0 obj << /Name /T19 /Type /Font /Subtype /Type3 /Resources 195 0 R /FontBBox [ 2 -20 69 71 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 46 /LastChar 121 /Encoding 197 0 R /CharProcs 209 0 R /Widths [ 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 73 0 0 75 0 0 0 73 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 43 0 0 54 0 0 51 0 0 54 49 0 0 38 0 38 0 0 0 0 51 ] >> endobj 212 0 obj << /Length 176 /Filter /FlateDecode >> stream H25P0P0S0V0"3CB.cs(PLPHR!9ɓK?\؜K(å`ȥPRT `'*n3P| g>!0 b`Y:^)`&F#\= 1 endstream endobj 213 0 obj << /Type /Encoding /Differences [ 3 /A3 ] >> endobj 214 0 obj << /Length 158 /Filter /FlateDecode >> stream H2P0P0R5T06R03TH1*26PA3##=CHrW06Jq;8+r{*ryp?"@Ō@A4Ÿo?A?PՓ+ ! endstream endobj 215 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 216 0 obj << /Length 163 /Filter /FlateDecode >> stream H25Q0P0bS3KCB.s 53T5ɹ\N\ &\@).}gC.}O_T.O&@c?@?v TY?d$A$C A2b̃t!C=FdՓ+ ؠ;J endstream endobj 217 0 obj << /Length 213 /Filter /FlateDecode >> stream HA @g.J%Z VVZt%w]ChMQh`>fޛyq54;DB>q{ T=pQQ´OWS-|s6̢5l`?+IځL`.>=M&5װD@^ Zḿ Dy*X#a"Nn$9hʉOy_ 1f3 endstream endobj 218 0 obj << /Length 211 /Filter /FlateDecode >> stream HtM@ 6!ucU?`K3 sxoe/BoAhETNN(V3dXĤlN4IՌc(LT5G?K}|l)hz|`wA3@v ,*[Q8T!-9^`[xKu7ma 2BĖ!˸cp\qg-L6` @ endstream endobj 219 0 obj << /Length 203 /Filter /FlateDecode >> stream H= @R gQV@--b&9BI@og]=e#&Hh'hHIJj:$D*Y8 r(HHcy`;CJ.WX4HPYNnRyO//-?~ffes['%\ٽCxv]i<HPvۗ ֖ )m% endstream endobj 220 0 obj << /Length 140 /Filter /FlateDecode >> stream H2P0P0aSCB.c# 53T5ɹ\N\ F\@).}gC.}O_T.O?03>]=?z, c#f=\= Q& endstream endobj 221 0 obj << /Length 155 /Filter /FlateDecode >> stream H25Q0P0bSCB.s 53T5ɹ\N\ &\@).}gC.}O_T.Og``$f1g  1HK#2`gXq endstream endobj 222 0 obj 925 endobj 223 0 obj << /Filter /FlateDecode /Length 222 0 R >> stream HlVMH=ͿFHwCq$vh7ZiV @OM~}03dW7V[(JiFDzϯj[ps݈}wU7؈-,qd T ׵vtŅL@1ZLUr7Uc!Y/**ƶ%nE7BKPTIg!)X[*SثtY'.f( _P=>RCT򢵕u\S5)+AokLB”hrtS:B"pNTc&Ξ?O 1 /VǃEj8г]G2  .3E;tP\'ThL)-ŒHS`LFŹiˁrZgy 1qW5hԐS|ٟ΅pXiFq8ֽȩ- *+knXJ> }l}Io3'7JN|'-֍X|(oOd@+V=9EmDslny`T+m_'ǖ7,^l1TJgJLΙ)OutqF0zqn>7*]!i:ٺ}{N{)TF%3z~(q= (S"/%MyEa3M Wت |p)S+Xw]=hnPn8z~l놏mt<8s$]4Lb w ng wj1s&PMo, L͉6x 3r0oE㵬3N?aʽ2f.@l< }-) endstream endobj 224 0 obj << /Length 225 /Filter /FlateDecode >> stream HT; @4^a/I BB@Bbg#xJ®ف?YX-g [prpt:6o[e,70\psR̆3`+V)DK(424܉q!uıNQ(M$" Ј5|* )r)7 d jĴ+^"H5F ("CXX#QG\. endstream endobj 225 0 obj << /Length 134 /Filter /FlateDecode >> stream H23U0P0W5Q05W01SH1*25PA egɹ\N\@A.}0`ȥPRT5?0C(`)YG P%P Ph,uY tЀP\\\95 endstream endobj 226 0 obj << /Length 280 /Filter /FlateDecode >> stream HlѱN02TŏiH"Ȁx WH1CvJHVfnlaYc/J> stream Hd10`[<0L$ &:yutG(PO 񵴴$@$K%;) E(?7 O"Na-Bx>^W*6$;[)e gZGrǕ }†2e =ٯ)GU`ΘB=\:W0m u1R( {}S7l ͽFkCFͫ(,.eWhV*Q&m :GSZ endstream endobj 228 0 obj << /Length 92 /Filter /FlateDecode >> stream H22V0P0bC3KCB.K 13T5ɹ\N\ \ )YKW4Ӆ 0.WO@.Æl endstream endobj 229 0 obj << /Length 229 /Filter /FlateDecode >> stream HLαN0`"nr/VRH$2 Ў *QW*oG!$;ݤБtⴸ֕7)̎t:E*Jg-߳&FՃ~ w{V~] `eA224%CݳljH.a 9=/ɡ 9/8/ x=uld |E䮒'`e endstream endobj 230 0 obj << /Length 134 /Filter /FlateDecode >> stream H23U0P0W5Q05W01SH1*25PA egɹ\N\@A.}0`ȥPRTԃ`b aHC.qD FAJڡ =DBr 05 endstream endobj 231 0 obj << /Length 131 /Filter /FlateDecode >> stream H22V0P0W54S04WTH1*24PA#Ss=CLrW04q;8+r{*ryp=A(g_???'W @,0 endstream endobj 232 0 obj << /Length 261 /Filter /FlateDecode >> stream H\1J@,k h¸XVSZyPN> stream H\ѱjP+Y| *:کt :yy!CVC?WcM]p7tHt#; /g"F˄g.ȿ=#?yП_a.f.o y ,e^O+ frctz@^;n:7G(0 = ?SĻeo@e19a+#ƴN>6LY׃- NL+g0 dL9BE*Rt 0q7 endstream endobj 234 0 obj << /Length 207 /Filter /FlateDecode >> stream HL;@aLCka\@F+&Zyh kx[YQ1o)p>F800>>O0;4oޒWM3 KWx9_΁JPΊ?6Ɛp:pEe׮F*d*k}5"gO-l&JK|SG"$ٝ?s>8AJ')l% endstream endobj 235 0 obj << /Length 211 /Filter /FlateDecode >> stream HTн @ ,>B?xS*APGE'|tpء4޵E\ p'uHևH%k(w-wZFˉt< Be0;6/Ei%Wh* %ڢTlPQٔӣ℔PRR I9?)*S0a_tG endstream endobj 236 0 obj << /Length 210 /Filter /FlateDecode >> stream Hdѱ 0[ hZ%JBU0Q;w`>.pGR$Z2.T.w(4ȳP=],zoG ;6 .`#D"[.MNƶM$'~SVf`44g- yx F{.kdۺƶkn[=SvN`?mr endstream endobj 237 0 obj << /Length 262 /Filter /FlateDecode >> stream HT;n1`[.aYV,A"eHI)A$ G#dflI~ecgsjŚgh5wZYP/vs0(Fx!Nxal1$jLvt+tCt$ף$R+,3Or;Qsd"gY8i:žy̱^cK)v膞s+7;quDoDD(_o+< f' endstream endobj 238 0 obj << /Length 270 /Filter /FlateDecode >> stream HlJ` \^@j+TAO>8v*< _ेҘ?/&i'yJ33 zH B3:O);I%'b{ L%^_DfnP 0 ε+ង50eX\+3goZCh=ՎNic#2@kFiLTk$i3&[mK={O˂  c66jۡt˫=w2Q](]N^JIh> endstream endobj 239 0 obj << /Length 200 /Filter /FlateDecode >> stream HT= @`"0abL!hB:^)"׈Ibsb1f> stream HT?J@pBk.٘VSZyBY<@E1bb7Ym~򪕮TF7> stream H1n@EXi=X "%H@%js+9r5ma3sy_? #g~N'zs#-Jʶ=eK([8\|=PM苾BpBg#$M$\R8 R쐞@ZU 'N{PUyV"31g$@Lh')iC/\# endstream endobj 242 0 obj << /Length 214 /Filter /FlateDecode >> stream HD1J@q_3G ЭVSZyPz6l2WkLn!Y/K(4l2q";*ʟl)O WtK4S'"lwٜhgt:`\+XXhZtԒUtbRYMhF99{tSvGv< endstream endobj 243 0 obj << /Length 213 /Filter /FlateDecode >> stream H41N0qE,GMN Hd@c%@tN:J:rw`Ko5/䫜Wk.J~铊%7\.ry뎶e/\l({EsʪGڿSuGPBhs`~7M+{pukCkPH8 N(Y$e&H/>sA5AzЧ;Gt_3 0w endstream endobj 244 0 obj << /Length 232 /Filter /FlateDecode >> stream HL=N@a[[D!qv*K$\ *)@Po\T;-]X4cRNyg%3sF/{cxzyIɒsCɽ(?pFIo+*o LNYo-ujТBfJƽ7aP0l'hl:z/:o;֟b%*|hb.jK#DpW _qN;Zbt UO+iA  endstream endobj 245 0 obj << /Length 236 /Filter /FlateDecode >> stream HT=N0pE"G$QR `9:0JAr WyI M|Qsި8Zr<Ҳ򑛊[IQ_qMew/]#{x311YXc4"5Am"d~A5 96 !rDPRtܣĘJAb˃[9Ca3i~ʗɑ endstream endobj 246 0 obj << /Length 93 /Filter /FlateDecode >> stream HȽ@0a\Ź|"A0zaX[\pLCaPbTD+])ih~U` ; endstream endobj 247 0 obj << /Length 232 /Filter /FlateDecode >> stream HlϱJA+Vq3j"֛|JW8v!GWKკ9k>9+zf%֧\V#M[*oPy9WT3~y~}DHh0zF6RH[t2*@6%߽Y3OڹȰKQRp';Pe?.pc6hRyS=WUh,3tpt 0c endstream endobj 248 0 obj << /Length 299 /Filter /FlateDecode >> stream Hd1N@X) &Z) $8AmEJW U\(-7kiϟD7q2=GNf:=ՋX=$׉zz#{PLE:IUt7ͯtJ??ܫ\U .뜆q!Zj[`-#濆 3"wY.:K1m#zİ֍~-_|?,%Y+˲xI1v ^SAWJpWHfqN^VTڻXxˁ.2u endstream endobj 249 0 obj << /Length 222 /Filter /FlateDecode >> stream Ht1N@Et;*kn$H@%>K_ ng3)d2+ό.xΆgmƋ% kcwYF;rJZJcFq͆?77 Vs  (R:(BҸ|Ѓo0޷@ңAk(;oV* FY'v? .X\P&.'`C0` endstream endobj 250 0 obj << /Type /Encoding /Differences [ 11 /AB /AC /AD 22 /AM 26 /AQ 58 /BM /BN /BO 62 /BQ 65 /BT /BU 71 /BZ 78 /C6 80 /C8 82 /CA /CB /CC /CD 98 /CQ /CR /CS /CT /CU 105 /CX /CY /CZ 109 /D1 /D2 114 /D6 116 /D8 120 /DC /DD ] >> endobj 251 0 obj << /AB 283 0 R /AC 300 0 R /AJ 298 0 R /B2 299 0 R /B8 304 0 R /B9 309 0 R /BA 310 0 R /BC 311 0 R /BD 308 0 R /BE 305 0 R /BF 306 0 R /BH 307 0 R /BK 297 0 R /BL 287 0 R /BM 288 0 R /BT 289 0 R /BV 286 0 R /BW 284 0 R /BX 285 0 R /BY 290 0 R /BZ 294 0 R /C0 295 0 R /C1 296 0 R /C2 293 0 R /C4 291 0 R /C5 292 0 R /C6 312 0 R /C7 330 0 R /C8 331 0 R /C9 332 0 R /CA 329 0 R /CB 327 0 R /CC 328 0 R /CE 333 0 R /CF 338 0 R /CG 339 0 R /CP 340 0 R /CQ 337 0 R /CR 334 0 R /CS 335 0 R /CT 336 0 R /CU 326 0 R /CV 316 0 R /CW 317 0 R /CX 318 0 R /CY 315 0 R /CZ 313 0 R /D0 314 0 R /D1 319 0 R /D2 323 0 R /D3 324 0 R /D4 325 0 R /D5 322 0 R /D6 320 0 R /D7 321 0 R /D8 303 0 R /D9 243 0 R /DA 239 0 R /DB 245 0 R /DC 242 0 R /DD 240 0 R /DE 241 0 R /DF 246 0 R >> endobj 252 0 obj << /Name /T12 /Type /Font /Subtype /Type3 /Resources 301 0 R /FontBBox [ -3 -17 36 59 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 11 /LastChar 123 /Encoding 302 0 R /CharProcs 251 0 R /Widths [ 51 47 0 0 0 0 0 0 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 0 0 0 0 25 30 25 0 42 42 42 42 0 42 0 0 42 42 25 0 0 0 0 0 0 62 0 59 63 56 54 64 62 32 44 0 52 74 62 64 56 64 61 47 59 0 62 83 62 0 0 0 0 0 0 0 0 42 38 38 42 38 25 38 42 25 25 38 21 68 47 42 42 38 35 34 28 45 38 55 39 40 34 42 ] >> endobj 253 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 254 0 obj << /Length 189 /Filter /FlateDecode >> stream H1@Ei<s]5q N[29pJT ipR dM(d!ySE?9^,:LPlv_z)ri 45+յ endstream endobj 255 0 obj << /Length 153 /Filter /FlateDecode >> stream H21S0P0bcSKCB.# 53T5ɹ\N\ &F\@).}gC.}O_T.O?0 <D6"P?#&Ä $'W @eoj endstream endobj 256 0 obj << /Length 200 /Filter /FlateDecode >> stream Hѽ 0H-y@ ~|utPto2f({VAEG7%6ש6|YWd3[izFwS,(%PJʩk*G8Zԁ8cxҢ@( |qPDpBܮnmH4xW{O&o$}!Oи9]g endstream endobj 257 0 obj << /Length 169 /Filter /FlateDecode >> stream H= @HirtqQ-'oi|!'ldm#ړM%'m4=DX(wWlS39c6ݜӖ܄JA^P>b" 8oz(?/Z5?Dd}7`V(8OihI7 endstream endobj 258 0 obj << /Type /Encoding /Differences [ 1 /A1 11 /AB /AC /AD /AE 18 /AI 37 /B1 39 /B3 /B4 /B5 43 /B7 /B8 /B9 /BA /BB /BC /BD /BE /BF /BG /BH /BI /BJ /BK /BL /BM 61 /BP 65 /BT /BU /BV /BW /BX /BY /BZ /C0 /C1 /C2 /C3 /C4 /C5 /C6 /C7 /C8 /C9 /CA /CB /CC /CD /CE /CF /CG 91 /CJ 93 /CL 96 /CO /CP /CQ /CR /CS /CT /CU /CV /CW /CX /CY /CZ /D0 /D1 /D2 /D3 /D4 /D5 /D6 /D7 /D8 /D9 /DA /DB /DC /DD /DE /DF ] >> endobj 259 0 obj << /Length 265 /Filter /FlateDecode >> stream H\1j0a Z` I PhXHK37zo{CYz{O2gr} ]t]>K.UᷗwX5?z\A}nߠDCۛ.i,#${Pqc{38lDgpkE"-LJso {:?Q^(l8GX`]ByEy`P^4 *Wӕw endstream endobj 260 0 obj << /Length 173 /Filter /FlateDecode >> stream Hб 0H-} h1S*APGE7f>J Y1p9L9gʍ`L.> stream H21R0PT01V02Q0PH1*24 ()K=C#=K\.'O.p t pV0U()*Mtj 7?`C''W @# endstream endobj 262 0 obj << /Length 131 /Filter /FlateDecode >> stream H22V0P0W54S04WTH1*24PA#Ss=CLrW04q;8+r{*ryp=A(g_???'W @,0 endstream endobj 263 0 obj << /Length 114 /Filter /FlateDecode >> stream H23U0P0U5S0T0PH1*25 ML r@"9ɓK?(ȥ& =}JJS<]?$3  Gb.WO@.ZWI endstream endobj 264 0 obj << /Length 184 /Filter /FlateDecode >> stream H\= @ ) hL` A+INV,FFxc͝u7 IJ> stream HL1@@EItoo$PYJa[k5ZJrS000RoH 20BR!y}=;r3f P endstream endobj 266 0 obj << /Length 132 /Filter /FlateDecode >> stream H,1 0` U N@;7ǃn ?i=%$B,'fU /h́ba6c4%&mygv:ˣ8b7!Ͻ~o-҇>=~ 0 endstream endobj 267 0 obj << /Length 189 /Filter /FlateDecode >> stream H1@EKi<s]vM*-LjiњcpEQ6t&/SLfޟ9xj)!JWvCŖԎuHj%3RfΚ]|=]UxO  CԞ%Q4˭/w~/ڏ:2 [[f[BI4 (1%,2ZZG+ endstream endobj 268 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 269 0 obj << /Length 223 /Filter /FlateDecode >> stream H; @P"0M\|\?X)> stream HTαJ@[Xe^@s19 )|BQ8ncey૤K+,bq66_13]k<.>e%# ry8I'(|ӌ͘ρd8$qN˨|.^_?G/#xT1p¨9jf{v?yh.20#Ƚ$/h RW-0S_ endstream endobj 271 0 obj << /Length 193 /Filter /FlateDecode >> stream H1 A PBHG\@wgDj`Up A+=G*v[z6vS1`kxkc]MZXLBWz6CA> stream HTαJ@4kn!*B8+@--$+K_aڀMe-fv3N8㓔'g| =rv()< %9@ Vc=v4[-gPYk7-,bHcvm05x[N[Vf@-?.'d#~GVB૑N}u+Jw s`!+]tC  endstream endobj 273 0 obj << /Length 189 /Filter /FlateDecode >> stream H|1 @orQ` A+֛T^i%x2~<śb=!kǬǬ'|Lz$SփX6E+(J6s)J|܎.pQw/Pw6D݈J WimUf<G'PlcZJD˔`Q} endstream endobj 274 0 obj << /Length 218 /Filter /FlateDecode >> stream H|; @H a& b%SZyTXxI)S;[|;0JJ6&6;I[( z>3ܑۛQ_1%PTB&2J5dC)uwM~ ia4,[p5隍 a2۫_Gm6͡󿡳wܗ"fCJ5X1oÞo9rSx0% endstream endobj 275 0 obj << /Length 270 /Filter /FlateDecode >> stream H\=N0 %G/iZ)R H0q\ GU\uZ!|.OIs93yL ǩIg|EI J͹(- T`c7Dط#޸[ETF$<bFҌA \UVp$MBiEؿzpЪPN5K;?p߂^ X_2!`_G%ҧp/ endstream endobj 276 0 obj << /Length 243 /Filter /FlateDecode >> stream HT1N0`HDߠ u[T1E*  ;`v*#p3u A !e(y='fgzFl&,k)W$5Ϥ\^h#e}__ hClOڎ' jU!'*d|OW 98&¡W4HN1>g@:vďRڳC`eƲ|p mvWtq>U-w+7 endstream endobj 277 0 obj << /AB 247 0 R /AC 248 0 R /AD 249 0 R /AM 244 0 R /AQ 229 0 R /BM 228 0 R /BN 231 0 R /BO 230 0 R /BQ 225 0 R /BT 224 0 R /BU 227 0 R /BZ 226 0 R /C6 233 0 R /C8 236 0 R /CA 237 0 R /CB 238 0 R /CC 235 0 R /CD 232 0 R /CQ 234 0 R /CR 264 0 R /CS 272 0 R /CT 273 0 R /CU 274 0 R /CX 271 0 R /CY 269 0 R /CZ 270 0 R /D1 275 0 R /D2 280 0 R /D6 281 0 R /D8 282 0 R /DC 279 0 R /DD 276 0 R >> endobj 278 0 obj << /Name /T13 /Type /Font /Subtype /Type3 /Resources 253 0 R /FontBBox [ -1 -18 62 57 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 11 /LastChar 121 /Encoding 250 0 R /CharProcs 277 0 R /Widths [ 53 47 43 0 0 0 0 0 0 0 0 50 0 0 0 43 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 23 65 0 65 0 0 62 63 0 0 0 0 65 0 0 0 0 0 0 67 0 53 0 63 51 49 57 0 0 0 0 0 0 0 0 0 0 0 0 36 36 43 39 41 0 0 29 34 43 0 73 50 0 0 0 37 0 30 0 0 0 47 41 ] >> endobj 279 0 obj << /Length 230 /Filter /FlateDecode >> stream HL1J@,)^#]@ ` A+vdIG*Y,rN"C|?՚#U4=RWZ2657\i*.$bsurԗrO!1 )ۏ;;Y5v~Moq+:@76333S3%E%6o =Ww$c1Ѡbe˼ fqt^50;0 endstream endobj 280 0 obj << /Length 223 /Filter /FlateDecode >> stream HL1NQq &\@ڽ5a <XZ`u!`U .tؼϙ%/ _loӜfd-ǽ\0yaA [KHeç{)+J5s $_)=ll}j;q˳C.QDLtohjROF6[թ;W\Jըp]RmZ>B)豠g``N endstream endobj 281 0 obj << /Length 188 /Filter /FlateDecode >> stream HT= @4aEb jih > stream Hl1 P ኃG0ñP|PGE > stream HJ@H970mҦPA'@=zPZ }_`9,Yg6I7da1.pYd-> Ɋ^/p|˧_`B [:hw1D}> stream H\?n0pGޒ#] TBFPzcDQ8#@Oϟq™<͖R:S0)}}Ѯx򝯗/k »Ў.6 s``V.E.Шm;[*Sv'o?q)=< X?NJvP_#z1'pq\*WR殤})7+ncI` ]E endstream endobj 285 0 obj << /Length 242 /Filter /FlateDecode >> stream H\бNPq$g/`ұI MtCtp+85}F]($_sצ&6V41vnي廘vXWYfmM%O-nM"Q6o($#pUcP: *8J]r6Pjϛo&~JȮCG,\ђ#w]UGUm,9\g']iDŽU&r` 1 endstream endobj 286 0 obj << /Length 272 /Filter /FlateDecode >> stream HбJ@ W#쾀r'WNSZzF,+|K&zEbnyr'3:w˂ÂIoe]I~弗9ǎTq#Չ|Wމ1v!#m3S%v3HO"|# LHwXȐ"}"{7AK~L' :+2~MFr3waagmKtV+اz KbOq$Ak79R> 8^ endstream endobj 287 0 obj << /Length 243 /Filter /FlateDecode >> stream HLбN0T,ݒGȽi-D$ى:JFHc.Po>y7|u?TL \7ܜV'vTx%*\Q#u$"32+2LD 9ohшC]zePfё`BcʧD~))>Z1ù/﬌s'cfI LeFJÁO,o F; /~anA{UGw-% endstream endobj 288 0 obj << /Length 115 /Filter /FlateDecode >> stream H22U0Pb#Sc3CB.C3 ĵ3T5ɹ\N\ f\@).}gC.}O_T.O7g'|`FH endstream endobj 289 0 obj << /Length 212 /Filter /FlateDecode >> stream HTб 0pATh UN>: *:P!46w> $q#9%?pI{!Ȯΐf > stream Hd? 0[zsm FǂN@+88z%k :f(|&!_";"weD:Q# y,O( ))@D$W ̇4#`n5&r6SƁ}—Ef,jTGSMfĹĺɇMjrcᖳx'hЌ^ FB endstream endobj 291 0 obj << /Length 202 /Filter /FlateDecode >> stream HLα 0-}4u,T;:\7G_Ip5 @%C陋K>8.ï2&j"w !ӪFƆL3Qr)ϧb M` 5g{uEV8zl:`[Wծw/?/~5!م)\[4LL(9z`\ endstream endobj 292 0 obj << /Length 294 /Filter /FlateDecode >> stream H\пN@p %۬oF(VךFkW ^cO^-63?&_@D8*o!d1btۦ߉8b>1t#B槏睥 5a0Hz )R>4;vt Q%CU(ڣZ9 %^|TYYE?Y ` Jw&+]Ij32TYJGy jAvJG&kf@jX5R$9C_(o-NI*N'HzC'Q;qRۋݥ 0 endstream endobj 293 0 obj << /Length 197 /Filter /FlateDecode >> stream Hd= 0H-=B4X'*AAk 2v(ɋ4B /cq ƘN0&ΰ;B.oQKs<_0.Wx9_ uXUׁA73UVΛoԾ -V^?̀(-R>|ocOe7TMc x 0, endstream endobj 294 0 obj << /Length 265 /Filter /FlateDecode >> stream HlOJ@ YfA@U0 AW=tz.V7Y~~o I~Is7qԝN]}+\ʛTWLL*V*)bpH{>?_C_0/5deTe t@ 4̓}WH=r:ِFHEh^KnF݈3-{n"a Ft~G4zLo,cp.&H-h~|mQ, J endstream endobj 295 0 obj << /Length 207 /Filter /FlateDecode >> stream Hб0# $jFD|ut  ZB`_%g3w.<'Wr~'N$|/XDc/RH˭g,WH@D?@m@ڐFxT UZ 6TiT.Gok  xa4ݣ1PRT7gL׳x \Ƿ endstream endobj 296 0 obj << /Length 152 /Filter /FlateDecode >> stream H26R0P0aCSsCB.cs 53T5ɹ\N\ \@).}gC.}O_T.Oؑ?~AÈF@0A pFC0`?-d100 \= ;E endstream endobj 297 0 obj << /Length 245 /Filter /FlateDecode >> stream HLNPE!/O`~@YvdD h z @IA1fS{췺B5ѷL>ewFB3C/;Hǧ[$];>(vJ9Ɯ,1rqkpB fDS3ؔuD ݞVC1dJ`6Ec {Ktg(cgz>6&V^侒g`@0s endstream endobj 298 0 obj << /Length 135 /Filter /FlateDecode >> stream HɱP`b#> stream HLOJ@٤7\@n@U0 AW@]P\Sqkd5Rzt0ˤ0{8ՙ3}> stream HtJ0 sGȼn?XXAГE=zXQ}/r4N&V͡?&ӣS8J,R,xS,)X,mV5$7X\P3HK|z| 6!$щ"0#["&4ڔ#G{!GM47}WGM ST<}RPme˫'XafLђQc>oO˄5K endstream endobj 301 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 302 0 obj << /Type /Encoding /Differences [ 11 /AB /AC 19 /AJ 38 /B2 44 /B8 /B9 /BA 48 /BC /BD /BE /BF 53 /BH 56 /BK /BL /BM 65 /BT 67 /BV /BW /BX /BY /BZ /C0 /C1 /C2 76 /C4 /C5 /C6 /C7 /C8 /C9 /CA /CB /CC 86 /CE /CF /CG 97 /CP /CQ /CR /CS /CT /CU /CV /CW /CX /CY /CZ /D0 /D1 /D2 /D3 /D4 /D5 /D6 /D7 /D8 /D9 /DA /DB /DC /DD /DE /DF ] >> endobj 303 0 obj << /Length 177 /Filter /FlateDecode >> stream H\1 @Ѐ0Mnvc] *PK E덕WZ/![c1X@b&1Wp50> stream H22U0P0S54S0TTH1*24 (*dr.'~1PK)YKW4Ӆ!? r 02 endstream endobj 305 0 obj << /Length 276 /Filter /FlateDecode >> stream H> stream Hl=N@`G.,MGع8Ο[) $8PR6ґ#*H)p7 D ϒg> stream HdϽJ@ [a 2/ܧWNSZpwXXJqba! [ٝ@:&:U&222F慤:Jzʔ#$-ZcA |^"Fʹ t[ƱWw˳NJ0z,6$hr<˖u?MWcKP̷T \)!ɍ%?r ٴo|X:䤐 `>+~ endstream endobj 308 0 obj << /Length 179 /Filter /FlateDecode >> stream H|= @ at[Zj)hXyt^#`a"dYޛ0d)'A:"* h=CY|݃؃Yb%{B,T IYOSv5ƭjX3%ֿ4!!D> C endstream endobj 309 0 obj << /Length 93 /Filter /FlateDecode >> stream H26P0P0W04S0P02TH1* aSs=CCS=K\.'O.p.}S.}g W4ӅՓ+ g endstream endobj 310 0 obj << /Length 91 /Filter /FlateDecode >> stream H22U0PbC bU, t Dr.'~%p pV0U()*Mt@}C=o?'W @# endstream endobj 311 0 obj << /Length 226 /Filter /FlateDecode >> stream H\J@`Kv^@ӴMhO sT{%/־>B{5b, 33Xz;Ye|ȴbr\wkd.ZV?$^ GܾIKi2> stream H\ѿN@%$^ȾHNM0*@--4ZCbAyDrq{ۂ0r&-[,7ɵ47~/Wg>[C?7;!*Z!Ah[FP%c_h5xYlwMU^`|<06< pkbF};X #DJIb@-Hrn)Ʉ i lP$FH+t_P~#̀j#_v> stream HTαJ@-ʝиg` A+BQ8J+W 9|\ŲL@a)`GO 6S\xz!g1GPc=OPo/@@$Y0F(4XiԔTxc=2٣\ sdZ'xLo+N:ro;G} ۝/R PW-/ endstream endobj 314 0 obj << /Length 172 /Filter /FlateDecode >> stream H|1 @PC4!sl $VV@--XJ׈xإǙ]k#L1N0pa :2di_Ʊ@a@-Pg&<*fCԠլW:Y勏E%< iȿS*.t櫒`l`_[= endstream endobj 315 0 obj << /Length 212 /Filter /FlateDecode >> stream H1P`Ń)|Gع@y!` A+Znu ^kD@,B~'>v;53cb&lEF}N 7h4(Xpd(ȐC )oe#pG{S+Ue.)hR:WJE\k8 wê*::.^8ʪ[Z($IWJ@\6!& endstream endobj 316 0 obj << /Length 233 /Filter /FlateDecode >> stream HDαJ@`CAGȼ&!BX8L!huWh||_`-BBW7\qgۊ ?tf׊/Znk§=m;*wܬÌ5TvB $+"ހ#CF%#^R!GXH80Ĵ=sќGePR>q%b+;(b!NXQzRx#nD҇. Kt# 0˞ endstream endobj 317 0 obj << /Length 228 /Filter /FlateDecode >> stream HT1j@Pit`bEJ%pb@RK6NRW*]Y6a>|%(#?p9ϱ[Z6qQQƊ#5|ny"œ :둀V4c-=q`'5ZJ:-0.S"lc+cz@`VOt,rZ5J S6 endstream endobj 318 0 obj << /Length 186 /Filter /FlateDecode >> stream H= @`$E`=4?%L!hBN+y\`mM0'r㔓(m2t̞ݑ-!KQPgQPrFhKwZF}7^Y>ځpmR\L,WޭRm IТ Ə endstream endobj 319 0 obj << /Length 266 /Filter /FlateDecode >> stream HT1N0F\=! M+%eT@"L@02J2F@2Xq@e'YmR,م\)WVr)~> stream HT1 0`/9B hԭP A9Rרx9ӀC{ÓcL0ŁQ2ŝ#HJ' p|5E\-|A͠ZF5=VY9 mt頪 ϋؕ^G:~@aO`=Y@=;`` ?0G endstream endobj 321 0 obj << /Length 192 /Filter /FlateDecode >> stream H<1PD? ن#P@ґ&RhB  KPZDNf^8P_ 4h8M {G|F:x;IRVڏě1/Y5/pJ:^&C}QE7aii?.o@!&Fkl¾1g>"u\+Pg?:((+)ٸzIXqx endstream endobj 322 0 obj << /Length 208 /Filter /FlateDecode >> stream HD=N1`[.,M#\6jQ RT()@ FXraK_D+oϸw#X&7;nnm)sѢݜU^l^RݭWtD:ɔE*h| }/>\ #X)l!8&q_!Bfj =AEeG[: 0gƓ endstream endobj 323 0 obj << /Length 223 /Filter /FlateDecode >> stream HT?j0zh!L=@1CKc!װMOv(99Jxw\yp<2^(|HS덲5 N݃AWmZ9.\[^%e*^ĩh!oW"' x]Sh=jFO;97§j+_3MF` endstream endobj 324 0 obj << /Length 187 /Filter /FlateDecode >> stream H<= @i h\P[ZyPbMr-S X|0f&<4N|6tǜx>2I9]ii)>r2x+ vǏBvM@AШ WVj4&BDw'=SӆFHE\AP{X:Oq endstream endobj 325 0 obj << /Length 234 /Filter /FlateDecode >> stream H\1N0T,7-lX*  v fb+1p1C ${~O/8z 0)mώt^4 e5BAumT*N,=tzj!G8vCb|7lOUͩ#I?徐g` endstream endobj 326 0 obj << /Length 215 /Filter /FlateDecode >> stream Hн @ #蟥 |utPtVת8_A<Êp.A.rI'B:AaQv$r p^ .x#Jכ1/v[B>!=#j8]L"xX&a WI*7IRKiZ&7WtD%T:c<%Cb5go^A5SBOT9.aSx 0B@ endstream endobj 327 0 obj << /Length 250 /Filter /FlateDecode >> stream HdAJ@Ж #/1Uè` `2 LƦch[bF1 }kbs$cî \T#AoYMF1Ѡ3VQQĶ-6T;Cjg#=˽c#-ch!6;l]D5з${ endstream endobj 328 0 obj << /Length 212 /Filter /FlateDecode >> stream HT1@ Љ("2`)U$ؕ6T()XAt\ )j/0Q8IaO_ ۥε! m? =j< l]PʍNP~W4鄛Qa#E[`aWc? 4Ucx"}q4.崒TZ%8d$1K> stream HLAN0/M^@ySYK/O|uC-_/]J0ypl*:o9qeFd 9}kv1 Df.t^|jRIcH`5*\j_s]I}MX- }mN\5^җ`$WoO9~z\)1MG#3"- endstream endobj 330 0 obj << /Length 263 /Filter /FlateDecode >> stream HlбN@`.[L#0/wBbErj"V>ZZh3&d0 GvXfo/xv6\sMouumZz{zCO#7{nF??_&6_:keʕ7J"?ʗHT$}md, gR`LtLS?҈`@ k=&.VpXx8#FvbcU f td]g <- d,'MdqV  ǖd馧`pR endstream endobj 331 0 obj << /Length 203 /Filter /FlateDecode >> stream Hd10 T H^vH+ȀF>c1:b/:xrd%/AR"pAi@֠vXU2ex]luB#\:Aӌ 3H4a9HL`W8r DDO tA`>bĜ6$4!*qD@Dq 8[ < endstream endobj 332 0 obj << /Length 329 /Filter /FlateDecode >> stream HlAJ@)f f.iB*+.](D<@UWfE{3-,o&gfdSsO̤0Ņy՛*ƴ<2NrUM+=b[*lzerUwEU @7?NLҦ{I4%,/Eri4j2b|^ K'dN٠pjrmI $x5:M-;h  f\5o? S.1KB2Xb˿XE4C Vܦvx}hdJ=څ< endstream endobj 333 0 obj << /Length 223 /Filter /FlateDecode >> stream HT=P0Kl@c?` A+kQK< lI67E819́b'0@ڇkW]K1x T w fCxӢiX4ɜ(9 !R PTDTJ?"Cx w"/N}(Ww"dBjІv ȰuvT'Jhչ-\!&V1- ^ endstream endobj 334 0 obj << /Length 186 /Filter /FlateDecode >> stream H\= @`ba!s_a jihk,Rz%,!Œ$y0A.G89ƣ= f <$;JRrVG̤"'Y#'pR:! L'F5qE=ޯxXjQeg%!j{ endstream endobj 335 0 obj << /Length 231 /Filter /FlateDecode >> stream HT=j@* $G,]v@P@o#T!vvEo> '|O|D%^$<؁3yhE݆c7DD@[BG7rhGRG3R8jGPM^{%RC> stream Hl;PP4,_!4&RhB-XmAeX%:Xd2~> stream HL-@`M,s(Zդ@B (Hti\\a寈o{M?.?Avsa1Ɲ;>-KEL 0 a@6*FN1pD:f%ȴ<2Mk$Z0iVVU/[З'Vh1zD -xu~HYEWнIL2XS endstream endobj 338 0 obj << /Length 289 /Filter /FlateDecode >> stream HdѱJ@ )vZs+)|P,J5Ib8Yqm,B<=ۥ\UZv!W[J q<]͋'Yyq/vײE}/??^y}z|K ^Mf SJ&HW4zQ@iBu앆ΈHJR:,բ4 F ^4)HVF&ҀKHک &H)0$09ErJH;eAHxap5? = endstream endobj 339 0 obj << /Length 272 /Filter /FlateDecode >> stream HdѱJ@ )}M"1Z8L! XWE."dǰ?ũMmNg)W(|2?qJ +HlCrKK7W6oP]DΘab)DlP$g86Djy(փڳ]݊V6,#xb P]- >joVf.;v;P;j#1"v R) }IcB]!Tp y;pt endstream endobj 340 0 obj << /Length 208 /Filter /FlateDecode >> stream HL?Pir 1j)B !\,I |Ex6?fx38V&|(#KsjʳQ$p8B&Ka}$ÝIkY %/*9*8q:쒡^=hҎ n endstream endobj 341 0 obj << /Length 354 /Filter /FlateDecode >> stream H41J@Rf.UWFVSZyP5Ŗ^!¶&b>|/7垹ULplSNN{5T~mJ3QyuaTu0t#2;.Cb/ހbXk-ϿslGcW&Y)6<I4R~t6XG6>HdBtRgM}R/yߩg~zK=s-B*,ެdt!ˬpv,|!9ۑudWwz)hLz=Hae$= B ]=sHa8WٺĬ*u;E endstream endobj 342 0 obj << /Length 241 /Filter /FlateDecode >> stream Hұj0` [h&fH[B:Z*}1?!cR iIj:O:4+xXMw\Z_zGO ʟ}- nzZ-USUe 1QGj:0Sj '1pBs#v =T> stream HT=N0'rɍ[f2Z@"T()@G\Xex3ޕH|<;?|+O%׾۾mwϻ,LE2hd@> stream HN@E O`~@Y]V+U)L\K ֌E'IA7nbNx̽ʵ]\Ѭ,Ԗ{\̦6]-M~ɖ7g0y}e^M}nt}D2HJxp#KBpNep)2pL D`O@:hC|(AtE:imLGKHYJ o!Po$~hF)S9jBj 1X?tYwD kx2?ܘO?4 endstream endobj 345 0 obj << /Length 303 /Filter /FlateDecode >> stream Ht=N0 u%GH.:Ht@#h=J1CTc;-UGiZ򍿨|SʿV5]|{ˊbtsog_צ)Ϗ72e>LktH@Agq&8IG . qT4&bCF@?ƂK- b+F@CX5g!6u34]9'lM]wH/ԊA B0){#; @ƎةǙlRZm*>[y!i]87wy2? P endstream endobj 346 0 obj << /Length 224 /Filter /FlateDecode >> stream H?@p h1,)*Xra)#D}01ͿDjx&S^ ՏY!FDK$l=WDJ ݫ>m cv4TV̫iI=46ꜞaUJKÖPaC+޻%!4TAcMԣ=Tg?jZ*[ӹ endstream endobj 347 0 obj << /Length 283 /Filter /FlateDecode >> stream HѱN@`LqjS)LPK o#*)`7Ü8YlO}MO,eVUYRu-V7籦/ϯ]3OT2%OA0`$7X)dyF+A[nҸi+!!(ʥ~l,xN&f+),H݄?084xCS益>+<"78&mSBHӎSxLY1tHsaJ)ˎ)p] endstream endobj 348 0 obj << /Length 308 /Filter /FlateDecode >> stream HOJ0Ƨd^@h.}`awD z H4Bc"o *()4k$hh`BH 2 J0bv LS#2dW0, Ȫ sVPe ,MM [P EHƈwɨwɪwCene=W7W$/f"< b89 endstream endobj 349 0 obj << /Length 343 /Filter /FlateDecode >> stream HAN0G0tP$dD&K]8 G`im{vHoӖ=VNt[Z~o;}KռgjNS> lGo[84%BU/;|ɶTbdc$#.\V)Ld$S$"і"H4Gy{-Hl2ÂDRg{]3 7qz ı1>8Y.a}\LJKXe4Pe]3s /c%w>Ff*]& kdcZD\ϡDr-k>3K mk endstream endobj 350 0 obj << /Length 155 /Filter /FlateDecode >> stream H0T0P0bs #CB.srM t Dr.'~PK)YKW4ӅO 5f"0; 0? ~(qh1?0񏁁 apzrr endstream endobj 351 0 obj << /Length 102 /Filter /FlateDecode >> stream H25P0P0a3 #CB.#(kgk$s<L=R\N \ %E\.\ `QrcՓ+ X1~ endstream endobj 352 0 obj << /Length 322 /Filter /FlateDecode >> stream H?N0&]zzDD<::htܬG:24`Hl4oK]]\KZf^fgcGgԤ7Hy|af=7ݒ9!dޞ6*v=!z](ߵBIKv-y2 əHi0^ZEk=6Khe"U;EK&ha Tsk֎5Dv ȵvraM'9k`~Y:?~`ӛ{[E̻< o lWmtwٔbؗ&wy"? endstream endobj 353 0 obj << /Length 354 /Filter /FlateDecode >> stream H̓N0]U">B %,ȀP@0ۼ%1Cb2)֗|o[e꭪k)?dkUߨ9rEY<,vOE>ds'A,qЄV =a'Ƞ#t h =!B~4 B+ ҨދҨa4Xk [Dz$5D4'F-Ԝ"caV`>b;IA7&6C?E7x:ف;Fo&5b5gF@vO4d-gح d;V&%OyZrR"CȚg,SHlJ+O", endstream endobj 354 0 obj << /Length 223 /Filter /FlateDecode >> stream H= 0C-=BsmөP Aق7:f('PI?^TecB X3F! I BMTuْO=d3 \JrH)Iޒ%J6Q4V9mZ^RV(PGfm{?n8~?Uߒf rVՍ\/2D\g_-*jB<&%&<5<j endstream endobj 355 0 obj << /Length 299 /Filter /FlateDecode >> stream H|MJ0)] h <BЕP.]7G7"t} ڏ$3Lr1;^ҽ ݌<wg=`;Z2 ׫o b`&"@sC5+L0.h%4\Z(L`)+=V(^@1kQe3BFiZiV*5mմiI06Zj-E$h`~@(|-Fȭ@$*-Fv6(YYD%(gs;G#D endstream endobj 356 0 obj << /Length 231 /Filter /FlateDecode >> stream HTαjP r :开\ v؎ZJ@Wc_!\#]7-F-vr#`Vz%ؾ[o3y~L#+ELyL9Nx9B$f(?Rb28.toY0ek鞐鮷$\yoi1[5pgj05UA"ďֲIaLt` endstream endobj 357 0 obj << /Length 209 /Filter /FlateDecode >> stream HLο 0 6ĭnBur9 B]]ȏ|9ku oս^ڑ:tnjKØ)_Q04L cR*9+-JY.O6Kbtc_~Hlq;X*rj+9Wr 9ɓeF^E\Of,˕i#ץIL 07 endstream endobj 358 0 obj << /Length 182 /Filter /FlateDecode >> stream HT1 0.1MQ:<::(: ^[GZq .×$bk;(ir l"65 X>!&gx7 yTUaRtҪ1jӃDOKAw*nj#2QfK&g0?&`# endstream endobj 359 0 obj << /Length 187 /Filter /FlateDecode >> stream H<1 @ 2sI hL!hBz K"[<()ayI"cIdILa7`E2v endstream endobj 360 0 obj << /Length 149 /Filter /FlateDecode >> stream H26R0P0T5T02W05TH1*22 ()Dr.'~PK)YKW4Ӆ1q$܎?``rT \O?Ff.WO@.Ef endstream endobj 361 0 obj << /Length 151 /Filter /FlateDecode >> stream H21S0P0R5T01V06WH1*21 ([(Dr.'~!PK)YU()*Mt CdAB? ?K0?H>`&pzrrYvf endstream endobj 362 0 obj << /Length 217 /Filter /FlateDecode >> stream HT= @4nV@--xU,`avM+1@ks+:|m`3@.tΖЍboxqx7>XV|$eJԥTf.e*H9 96ei0k<%dH2dؠJc1d\ S4c+n/gOw]n.y "G3 endstream endobj 363 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 364 0 obj << /Type /Encoding /Differences [ 49 /BD /BE /BF /BG /BH /BI /BJ /BK /BL 65 /BT 67 /BV 69 /BX 73 /C1 75 /C3 /C4 /C5 /C6 80 /C8 82 /CA 84 /CC 87 /CF 97 /CP 99 /CR /CS /CT /CU /CV /CW /CX 107 /CZ /D0 /D1 /D2 /D3 /D4 114 /D6 /D7 /D8 /D9 119 /DB /DC /DD ] >> endobj 365 0 obj << /Length 136 /Filter /FlateDecode >> stream H23W0P04  )\\& A@PAD$r9yr+s{ =}JJS<]A0L> "P"7Տ r 0ӔQ endstream endobj 366 0 obj << /Length 133 /Filter /FlateDecode >> stream H26V0P0bc 2WH1*2\#=C] ɥ`dw pV0U()*Mt!?|=> stream H$? `qA-j P E #xá+]@iQu *WLk'Y{jٟ$)퉳I`3WZ]/ Q (K%ȢqR .R6HA&"IBIZ~I?my 4?2n endstream endobj 368 0 obj << /Length 87 /Filter /FlateDecode >> stream H21R0B#CC#cCB. ,`4гTHrP0w pV=}JJS<]@Brzrr( endstream endobj 369 0 obj << /A1 259 0 R /AB 260 0 R /AC 257 0 R /AD 255 0 R /AE 256 0 R /AI 261 0 R /B1 341 0 R /B3 266 0 R /B4 267 0 R /B5 254 0 R /B7 263 0 R /B8 262 0 R /B9 265 0 R /BA 417 0 R /BB 418 0 R /BC 419 0 R /BD 416 0 R /BE 414 0 R /BF 415 0 R /BG 420 0 R /BH 425 0 R /BI 426 0 R /BJ 427 0 R /BK 424 0 R /BL 421 0 R /BM 422 0 R /BP 423 0 R /BT 413 0 R /BU 403 0 R /BV 404 0 R /BW 428 0 R /BX 402 0 R /BY 400 0 R /BZ 401 0 R /C0 406 0 R /C1 410 0 R /C2 411 0 R /C3 412 0 R /C4 409 0 R /C5 407 0 R /C6 408 0 R /C7 405 0 R /C8 447 0 R /C9 450 0 R /CA 449 0 R /CB 446 0 R /CC 444 0 R /CD 445 0 R /CE 448 0 R /CF 456 0 R /CG 455 0 R /CJ 457 0 R /CL 453 0 R /CO 451 0 R /CP 452 0 R /CQ 454 0 R /CR 439 0 R /CS 432 0 R /CT 433 0 R /CU 434 0 R /CV 431 0 R /CW 429 0 R /CX 430 0 R /CY 435 0 R /CZ 440 0 R /D0 441 0 R /D1 442 0 R /D2 443 0 R /D3 436 0 R /D4 437 0 R /D5 438 0 R /D6 366 0 R /D7 359 0 R /D8 360 0 R /D9 361 0 R /DA 358 0 R /DB 356 0 R /DC 357 0 R /DD 362 0 R /DE 367 0 R /DF 368 0 R >> endobj 370 0 obj << /Length 310 /Filter /FlateDecode >> stream HԱJ0p8: &/m 'SN>: *n}B_;KA|G M5Pod&UI*undS%O2;8 II(?TaԯM "I GO8IptXptCIׯ G׿c;6Ox%xj(xxt#9 e6aغbFz?b{u-7# endstream endobj 371 0 obj << /Length 171 /Filter /FlateDecode >> stream Hϱ 0 T7b4 $t|utPtn-GE]?-dy!gb\h%saQVw\k2cT @-$\lB>*V-;k19(b"d?;2̨xķ endstream endobj 372 0 obj << /Length 246 /Filter /FlateDecode >> stream HL=N@PLG`.|m&Zyh ({J ̀?Oy39HVt<1jx\i=7#77ZqsV>b|Q ~ se?ƪǤ`ĸzq')LΠtZhce`LʀX ^':UsM+O{=TV8s(9,XFsޘ<٫`#Tc-.A^f[^-&`S|= 0{δ endstream endobj 373 0 obj << /Length 245 /Filter /FlateDecode >> stream H̑MACR8c0f)񓘅`iAXQaTu3ĆXt{5կZQݡXKӯ-c^np`^Dj fC 1H֘ Px@B`*S]@<'p#rf%T~z+;g/3yBB5 iq]}7[K^$rA&_M endstream endobj 374 0 obj << /Length 230 /Filter /FlateDecode >> stream HұN02P @HlZPL+`Ds"b~> stream H27U0PasCSCB.33 53T5ɹ\N\ ff\@).}gC.}O_T.O?`??ۃ@;@8?`i2 {(l(L}g0'` x endstream endobj 376 0 obj << /Length 226 /Filter /FlateDecode >> stream H=0 ]uG)*# & ۣqБDI#/9PB S$%S<,0!S6J9 Ŗdb!RՊ.9*!'3fP7Ղ&RY4z=X[ k[[y7 پ ! endstream endobj 377 0 obj << /Length 184 /Filter /FlateDecode >> stream Hѱ 0>&D;|\}3}>B Ro\ g(&E#IZS2#jSK1fŖBl=#¬|h^ka޴2x Zq[?elJhJ`+H7j> +D>( }n(. n)du endstream endobj 378 0 obj << /BD 365 0 R /BE 355 0 R /BF 345 0 R /BG 346 0 R /BH 347 0 R /BI 344 0 R /BJ 342 0 R /BK 343 0 R /BL 348 0 R /BT 352 0 R /BV 353 0 R /BX 354 0 R /C1 351 0 R /C3 349 0 R /C4 350 0 R /C5 370 0 R /C6 388 0 R /C8 389 0 R /CA 390 0 R /CC 387 0 R /CF 385 0 R /CP 386 0 R /CR 391 0 R /CS 396 0 R /CT 397 0 R /CU 398 0 R /CV 395 0 R /CW 392 0 R /CX 393 0 R /CZ 394 0 R /D0 384 0 R /D1 374 0 R /D2 375 0 R /D3 376 0 R /D4 373 0 R /D6 371 0 R /D7 372 0 R /D8 377 0 R /D9 381 0 R /DB 382 0 R /DC 383 0 R /DD 380 0 R >> endobj 379 0 obj << /Name /T15 /Type /Font /Subtype /Type3 /Resources 363 0 R /FontBBox [ 2 -25 57 78 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 49 /LastChar 121 /Encoding 364 0 R /CharProcs 378 0 R /Widths [ 67 67 67 67 67 67 67 67 67 0 0 0 0 0 0 0 102 0 97 0 88 0 0 0 50 0 105 81 128 105 0 92 0 100 0 94 0 0 139 0 0 0 0 0 0 0 0 0 65 0 60 75 61 41 67 75 37 0 71 37 112 75 67 75 0 55 53 52 75 0 97 71 71 ] >> endobj 380 0 obj << /Length 305 /Filter /FlateDecode >> stream HбN0C"y~HCCTD*  &@6bM3D9|Ni$K>Ŷ"K {ϩzSyFK[vu&}^զRɣ3ҞJ6W6UIug??_Tu@c1": t'WpGKδl8g kؑ#j%P4/c \G*[oZ\{{Xq`QcO&s;=7XsugC)e*8-SEX'8%isFbIV^ׂi?@hn*sɹ endstream endobj 381 0 obj << /Length 187 /Filter /FlateDecode >> stream H1 @ As]M#Q-#C&55.|jCK.". yR @g?Q@f:\]s{D endstream endobj 382 0 obj << /Length 319 /Filter /FlateDecode >> stream HJ0)=7["=V{=(zn˾XM9P:L ^L?صeenjZݬ-k[_Uԣ]o[]fjrtk+]MwLfz+\@!jr'Gr lН81kdH=gSםx ^ 2ء6z̴brɋMt8Z/8:&+89gqr܋GvqѰǐbO8?\PIMZ 238a 6> stream H1N0 ]:T#$Q"=@LC0,G:vbl`z|IOx7ҿ5xĶs-Ek^^?pa~jtG% )@ (2 #4$ׁ&03AQ.S~r,m 'S 3@_Hަ&3Dy J3XKԳ3`Ozxd\sRZqUK (LN?HD endstream endobj 384 0 obj << /Length 105 /Filter /FlateDecode >> stream H26W0P0bcc cCB.# 53T5ɹ\N\ F\@).}gC.}O_T.O30`@ Փ+ 㺬, endstream endobj 385 0 obj << /Length 462 /Filter /FlateDecode >> stream H1n0q p ,H&iCd!A:ӆ.&DGਁ0IdP{_ݴj4M6B_Дf'7ϴ{7A)wRЫ{: T :$j:st#l_]^B _ɀp0.$MP&0#@%eP! B !;q1*S* ]Ce(cدP/u& > stream H1N0 PG܀VjVD$8[3qT c;GHHvjqICդO=m$&XݒV3je92{` U'yey5&:T0ը=!.q_ѽIVh$$<6yc(r](!הO3+#IZH~+Y4+JYĦbx1 ~ 0L2R endstream endobj 387 0 obj << /Length 170 /Filter /FlateDecode >> stream H4Q0P0b  CCB. c 53T5ɹ\N\ \@).}g PRTuIc ?` a2z(}(2 c gʳØe1!`9♐\OՓ+ Y{ endstream endobj 388 0 obj << /Length 314 /Filter /FlateDecode >> stream HtJ0H\iaU=у>Zcq2 _T. ,JT5~e/J\`_Ck(q Í[PJeG 9;o<{ۜ>q|ac3|aravCaٖbbc; S8 ؄)L`SϋF؇}8Ǣ}l>>dMNX2ƾM4ɍ:I6ش;a+ 3vҍn[^xvm2vxn;a+ oD4 endstream endobj 389 0 obj << /Length 205 /Filter /FlateDecode >> stream H4R0P0b  #CB. rM t Dr.'~PK)YKW4ӅeY <Rfo`0CYa,~(hŌH$,aŎKD<!IFE8Xa,y0 g`0" ZY\\\d endstream endobj 390 0 obj << /Length 292 /Filter /FlateDecode >> stream HӽN0`W"G$VjJ$2 PF5›T2fbUu苭9w.K,qg  ڭ lk(ZAq떠_gA!bϜ3 |`nc@ dM݄E[夻씳==2߿4ǰza c%BJΙļt\SC c}{ٞqgycOYO굲_di3:rmtgϓ]A;<^7ָl0Lfᦆ`vm endstream endobj 391 0 obj << /Length 236 /Filter /FlateDecode >> stream H1n0 Eix%G/:͔;hg7QtrHDR߬d%kw^,6xm^)K"_?> stream Hѱ @  ^7:\#tPףࢫH~%YJ i'Rڜ1 &vlk7$% 8_MI`t>]geȮ@ @94VCs+AdQXU^ ="w'C}k\]kf endstream endobj 393 0 obj << /Length 135 /Filter /FlateDecode >> stream H26W0P0bc# CB.#kgk$s<̹=R\N \ %E\.\P `''!1'W @ endstream endobj 394 0 obj << /Length 245 /Filter /FlateDecode >> stream Hнj03P?Bmjl4z$S@ڱCK;[G#x J!ksi S^y/1K*ɛ+/7Sr[\6Et^ؑ(%8g5v'! 38P]-?\ O@R/HB?^IQ> stream HJ0PK|]v` у(y{(;$Y\G27==_۾ξʳJ}~ͣ[ln9ʮ+H@hP oQΓ&0;0A/iԑS:I&9X \Y}DY/Q>^.'Wx~9Fsĺ*,ufa]{:i;(G*JJ9G$(:p8yޓWP2)՛/*)kͳ"}n(7o|oφ/ endstream endobj 396 0 obj << /Length 254 /Filter /FlateDecode >> stream HѿN0/tK;^iS# GW[ 1颥kz`> endstream endobj 397 0 obj << /Length 246 /Filter /FlateDecode >> stream HN0/P< uUwT `+ɣQ3DeKKEv9L/|zW\gyxUG DD R+mj+RNS7nh5,=0e_P.ۯpEYO8{N}E2Ͱ( ^J05ښ)5Sca"c6dU:~~Nǚ"nr endstream endobj 398 0 obj << /Length 172 /Filter /FlateDecode >> stream H1 P t(d= A=Z#ttcts3$C傝㝥#R+alT2v%T)[2aeOaF"ҤP; ksy7.u&7Rh~ԃo6yQ 7_[I4"ZR endstream endobj 399 0 obj << /Name /T14 /Type /Font /Subtype /Type3 /Resources 268 0 R /FontBBox [ -4 -21 54 59 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 1 /LastChar 123 /Encoding 258 0 R /CharProcs 369 0 R /Widths [ 69 0 0 0 0 0 0 0 0 0 48 46 46 69 0 0 0 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 69 0 23 32 32 0 65 23 28 23 42 42 42 42 42 42 42 42 42 42 42 23 0 0 65 0 0 0 62 59 60 63 57 54 65 62 30 43 65 52 76 62 65 57 65 61 46 60 62 62 85 62 0 0 23 0 23 0 0 23 42 46 37 46 37 25 42 46 23 25 44 23 69 46 42 46 44 33 33 32 46 44 60 44 44 37 42 ] >> endobj 400 0 obj << /Length 163 /Filter /FlateDecode >> stream H25Q0P0bS 2WH1*21\c=C] ɥ`bΥw pV0U()*MtbvdC&3f0yL>F"? ?ɟp_=2+&Ht"U $P`({TՓ+ ɱ endstream endobj 401 0 obj << /Length 248 /Filter /FlateDecode >> stream H1J@}4d.Iej` A+=%GHbf,M/dmm%?F՗ۚgJǖGn,ZxJ{/^A'śmt>`#TN^N:G z6 ^ɸS] daotH̳F \""h%v%%\rJ937'h<…f >C>ubi~J6 endstream endobj 402 0 obj << /Length 184 /Filter /FlateDecode >> stream HtA 0@ws چY҅Rѓx=7 %cQ06$$0M5DFt9ib:OܲA!^\ |1Fq zXaeܘ; Q1u(u5S]w^t(+s2Mw+`LJ endstream endobj 403 0 obj << /Length 205 /Filter /FlateDecode >> stream H 0S:n#^@R8|utPtnG#8v(=\\8ϩ%JQ938l g҄J tk -+ ;|ܟkf%DB EEuaR&xmdх>`1\k:/d-uҏ||ߏlx1Ϻ|-l4# endstream endobj 404 0 obj << /Length 257 /Filter /FlateDecode >> stream HѱJ14> V[Z jyg=+5,lc’\B,%$ٙlSn*ZQrUܜU\T^+ o/]D+FwE^x`W .'衛GG;&J8-(>sa1\;}>S{`7 f`I|ry )O.)kv*諤i[XS endstream endobj 405 0 obj << /Length 234 /Filter /FlateDecode >> stream H0! $ (`, j"N>::htߌG#02λlK ST8Z>ep5`yjq 9$NARȨx=P,Bz2tMU/z缨Xmɻ[h ljAW \#t曅N8{>9lxcD󝃛+[B endstream endobj 406 0 obj << /Length 121 /Filter /FlateDecode >> stream H23R0P0bS SsCB.SS 53T5ɹ\N\ \@).}gC.}O_T.O. ?LjP  ]!`$ 9 endstream endobj 407 0 obj << /Length 240 /Filter /FlateDecode >> stream Htѱ@4yLgIS^zvB|W_B6`aqj$0?0 L '>!hqemcϠ; nGv]XM!!_*BČJƹa a3hsO] !KDJ!bIoCGRvypHc ;N#ڡɠ픤"!Jd}7e@/o 00^ endstream endobj 408 0 obj << /Length 235 /Filter /FlateDecode >> stream HTбJ@YRIm}Mz8L!hYZ(ZX%Y|k+6.ʍYksw1.>N+}R}Mų6{wbx+.-#)6P{@r`h3Be*+%\SLz:υ! I@ S`: }`ƌ0WLw)1Ñ`U,zL2w{]O/g) endstream endobj 409 0 obj << /Length 138 /Filter /FlateDecode >> stream H25R0P0b SsCB.S 53T5ɹ\N\ &\@).}gC.}O_T.O. P&%d?ɏ ?`| ?<\\\ x endstream endobj 410 0 obj << /Length 102 /Filter /FlateDecode >> stream H26P0P0a SsCB.#3(kgk$s≮=R\N \ %E\.\ 07} \= ߨ~ endstream endobj 411 0 obj << /Length 164 /Filter /FlateDecode >> stream H21V0P0V5R0P05WH1*26 (Z*Dr.'~)PK)YKW4Ӆy$`P$3 ?P#P:`8cP?'W @d endstream endobj 412 0 obj << /Length 241 /Filter /FlateDecode >> stream H\ѱN@ `W r/IT#E"L<02| J:5*!:st}lVKEUkV'Gs]n~%ri ΪGjD$!ƵH> stream Hl= 0H-=U"n?N@S9zkťB%@%OmMݐ/#؀T" iY@0B@0# H&|ݯ "^Ў_U*ЬJ" 0<3[%˱ '+)ZLZBdҒV0Jr=;\ωn4P4Ar<)b [}V{ endstream endobj 414 0 obj << /Length 238 /Filter /FlateDecode >> stream Hl1N1Y4M.^H)@"Ի%G*+QPr\\X̗(@3W֖3wF}m{ܸڸ[yՕZ^Fn]( PYG*)H| $LXcoM3'y Ԉ|L,@v cdȮgXf,1L{2Cs0}Ͼ "ؑ "/z~ 05l endstream endobj 415 0 obj << /Length 237 /Filter /FlateDecode >> stream HlбN0` n#^MSR H0N> stream H21R0P0bcSS3CB.# 53T5ɹ\N\ F\@).}gC.}O_T.O?3gPo``a.WO@.JL endstream endobj 417 0 obj << /Length 92 /Filter /FlateDecode >> stream H22V0P0bC3KCB.K 13T5ɹ\N\ \ )YKW4Ӆ 0.WO@.Æl endstream endobj 418 0 obj << /Length 149 /Filter /FlateDecode >> stream H21R0P0U52T06S03RH1*26(X+$dr.'~!PK)YU()*Mtg ~07Cq;C1`X?0l > stream H= @ L#d.YW-Djihқ)-Bc6_130{#V$}.]6D"JҊ^ k endstream endobj 420 0 obj << /Length 194 /Filter /FlateDecode >> stream H; @`"0p/A n!hBNrA!fu~1va>fvfk/Q Gmf@ '9`I5vAOƘU ;#81j)Berj)H@b~|o]JhhBo endstream endobj 421 0 obj << /Length 234 /Filter /FlateDecode >> stream H|J1[L0^Vjih(_ e%o-̟;Fb2䱧72ŞS<> stream H22V0P0bC3c3CB.K 33T5ɹ\N\ \@.}gC.}O_T.O3`\= jF endstream endobj 423 0 obj << /Length 106 /Filter /FlateDecode >> stream H23U0P0U0 F )\\&@A##S=CK=K\.'O.pS.} S!BIQi* WIf(Osv.WO@.<~s endstream endobj 424 0 obj << /Length 259 /Filter /FlateDecode >> stream HL1N0e )G/ij:aD$z`dJzVH߳?Xs:7va ʫ؎3-=k9#_dK2#iW3o_ R`PZ95F=VH%#b 7G G 4gε[DkR#Q'UAd2t֠QJ$.h@߳ nw5Q׿H1'M?ănj*kg䦗`%1G endstream endobj 425 0 obj << /Length 226 /Filter /FlateDecode >> stream H1N@P[.,M#\ 8:$uR\ A%.eU((sf#EI$h^;g@+Տutw<|hY?xi-ŭz/Ŝ_RL/3;Ā7!GL#=ɀ}/bN6)Y uArAfh~x5{RKqƋ- 6 < -rEc|Q.ko~ endstream endobj 426 0 obj << /Length 242 /Filter /FlateDecode >> stream Ht1N0PRD&G\Y$R A 8W1 ??@hg|ҥZ=Z]kw<$a6_yG S387>H> stream Hν 0η؏ N`A'@7#*ur Nh!]9Em={aK>tlΘ]z`:@t8vpgqBjYj@ ѓD 7R'%PF.\xY򇤦%"튚{K E F!- N endstream endobj 428 0 obj << /Length 186 /Filter /FlateDecode >> stream H23V0PaSsJ1*25"z @"9ɓK?\ԄK(ť`ȥPRT(v?z r? >?`3PL=R`B`C1ӀcQ c0##r(A -JՓ+  endstream endobj 429 0 obj << /Length 152 /Filter /FlateDecode >> stream H21S0P0bcS CB.C 53T5ɹ\N\ &\@).}g W4Ӆ ` ??4'A? "I>?dHv  b`c`G&\= 9f endstream endobj 430 0 obj << /Length 118 /Filter /FlateDecode >> stream H22V0P0aS3CB.C 53T5ɹ\N\ \@).}gC.}O_T.O??"@qR``A\\\d endstream endobj 431 0 obj << /Length 233 /Filter /FlateDecode >> stream H=J1#S^#$pSZyegaF"s]m %".4 2,p ^IFeZO/~շQ -]nޞ&ف[L~;űOqL1OPC1*Y@*%GDA2&*,1'(ƘA^&JKԟT=4')CP"q MO#5%l endstream endobj 432 0 obj << /Length 190 /Filter /FlateDecode >> stream H1 0t*ڔS*APEg[X#tP|Rp$-O(1qi 1\ N6dsΐkJAoC7xO@D"jTO?Z1lBT*;6_߸g@~"ýQAa 5,nA endstream endobj 433 0 obj << /Length 189 /Filter /FlateDecode >> stream H\= P pA T vtܖ+k@ݞ߈GHB=bCǼ H:z | y!y ),|)PQk1nJQ|@.nWN$ƿd-SXkdDx W֕{'T} endstream endobj 434 0 obj << /Length 140 /Filter /FlateDecode >> stream H22U0P0b#KSKCB.# 53T5ɹ\N\ F\@).}gC.}O_T.OP|?I pL~JՓ+ endstream endobj 435 0 obj << /Length 149 /Filter /FlateDecode >> stream H22U0P5Q54W"S3CB.#C%HVP!9ɓK?\ȐK(ɥx*rypg((g .}3 y?\\\" endstream endobj 436 0 obj << /Length 184 /Filter /FlateDecode >> stream H1 @Ec&G\@7*Bu ^,!e+1gϟpcٜ5](EL>J:2TR{rRk* ֤̆o̒FZW'i*VPXbpͅbhpNT}FC-5lPMC endstream endobj 437 0 obj << /Length 190 /Filter /FlateDecode >> stream H=0 TR,D_K+F-7(=B&DGoy#Lp%.SLf "7&-18CRfb,u[wwykI&IoH3}Ͻ25:M#[(_L$)a`4Q| `఻| endstream endobj 438 0 obj << /Length 195 /Filter /FlateDecode >> stream H1 0[ hRuT;:yuTtպyG蘡AtSߐ?yW %&؍LJ;}{Ӌ]h] @PI3HcAds<[&uĥooB2#CNU *#*/*g n|V6{uĹ+&J]]E1מ,)[ endstream endobj 439 0 obj << /Length 183 /Filter /FlateDecode >> stream H1 @P%4!s jL!hB:+ ^ bD< 3fC6lFl&t"e()LHqBіh)Ez$+J"aT6AiK}PШhe*HQ/g.-U~{eREB0 endstream endobj 440 0 obj << /Length 194 /Filter /FlateDecode >> stream H= @ )"#8] *Bu K׈7H" zYe՚CC^G#2<~ĽPXm)(X)ʈt>∂lƇqC٘jZ~)Aƞ@{PBBeȲW Q"[(}pQpMC.IY+(&-%LФ endstream endobj 441 0 obj << /Length 103 /Filter /FlateDecode >> stream H22V0P0aS CB.C 53T5ɹ\N\ \@).}gC.}O_T.O?`?``A\\\<} endstream endobj 442 0 obj << /Length 175 /Filter /FlateDecode >> stream H2T0P0b33csCB.3 53T5ɹ\N\ f&\@).}gC.}O_T.O??;?O?? ep~l4Cy v 5 4'W @x endstream endobj 443 0 obj << /Length 144 /Filter /FlateDecode >> stream H21S0P0bccsCB.C 53T5ɹ\N\ &\@).}g W4Ӆ0H@A<"$0H7I.WO@. endstream endobj 444 0 obj << /Length 150 /Filter /FlateDecode >> stream H23P0P0bS3SsCB.S53T5ɹ\N\ \@).}gC.}O_T.O Fa@7 ??G惩X)y0uL=JSG H>5`h< endstream endobj 445 0 obj << /Length 191 /Filter /FlateDecode >> stream H= @ i> stream HT;N0@2@/ٰaWT#-  * hI37\3^'eo40 W0J(LA!3vQьs($rwXHf?Vӏ'WLEPLˎo[w endstream endobj 447 0 obj << /Length 166 /Filter /FlateDecode >> stream H25W0P0bSCSsCB. 53T5ɹ\N\ &\@).}gC.}O_T.O. "$ @ <"If0"! DH r3?(HP@Frzrr@ endstream endobj 448 0 obj << /Length 242 /Filter /FlateDecode >> stream Hl1n0`Gޒ#hC"d ډ@ \+ 1b "ǹ\=jFhMp9CkMӂv(}CDUej}Q1#!bJQ214"TVJ?xWkwl~ll#f+(jkz*m} Γ&:6ch4>4m~_- endstream endobj 449 0 obj << /Length 217 /Filter /FlateDecode >> stream H @\|JM4: VN=@uPG춁M*pWu$#0 0)+x4ݎr vK Ϸx=ΐ@a)وBr-S展JghmZ#5(uiS~n#kGiF>XbVuA׿8]dkcZV(mV 9+\ endstream endobj 450 0 obj << /Length 304 /Filter /FlateDecode >> stream H?J@7L h^SVjiNL5H] fϙ!).`wfvV.ʺٷ=[;3y떔^SQZ\Ǘ;* d5&C4%Q1PqJāB r^QJ0'M(5EQ) 42(͏i<X?":RUO~6GōJ|0o!:qEћN͚(\tGkt ?AAu;N]ӯ endstream endobj 451 0 obj << /Length 131 /Filter /FlateDecode >> stream H22V0P0S06V04S0PH1*24PA#S3=Cc#=K\.'O.pC.}S!BIQi* ׿??>B ?r 0 0 endstream endobj 452 0 obj << /Length 200 /Filter /FlateDecode >> stream Hḻ 0[6N`A'@p7SBE"#q$1O Fv> stream H22V0P0T52T04Q03RH1*2(X+%dr.'~1PK)YKW4ӅFs'W @؃ endstream endobj 454 0 obj << /Length 191 /Filter /FlateDecode >> stream H1 @PCAO&6TV@--mMr4o#2Fd5 q&Qxp}Q\p@? ߘlD 8^MyЧߩ> stream H\ѱJ0T(dм=8©`A'WA7W)8xPp|wC!{1Ӆvc~ Rneg>+xz~SZ叼[?/tN}~ZD(Ʊ0' 6e6+vH`yLI4 {qtZ¯lŵ6.[O+pOhPPR8:hp{{{G ؉[ X#db*+wӿ2r|(%\uK"g9VA 0RjW endstream endobj 456 0 obj << /Length 304 /Filter /FlateDecode >> stream HtAJ0 ]Z hb10*؅0<+nMo2W z,M ?4!ჼ^\,E&3Qd"?)Rؙ$*yr/%OnpēR<)o/8ca,K) "ػdQHMlAcE Qf {jI#=ųtLi> stream H22V0PP52T"3#CB.C(PXB$ $s< =r\N \ %E\.\ 0B\= q_ endstream endobj 458 0 obj 874 endobj 459 0 obj << /Filter /FlateDecode /Length 458 0 R >> stream HtVn0+|XCO@oIXjeI(4.LmN.9Kά"KkHӍC9V- V؎΁h:IFsB!$mr H|!D5jwv ~te^2xKyqW7b9 .ݮvf[Jd4am@Z=NW4b͝~$QҨ{2_֍}b^YWen8H)i7|$6$ qV3_PpeGM~Ԟh@b 1:j9]c Qu7 8ׁ|J '88-\Kiy{e6AQ#ÅLT(bfJ$μUW{3x@5Rie\8lWUtDeYF5ns}VaV I%4DR*f&.8uo.}d&uZGm(|0Q Za z)n^|"60Ϗ JBxEteubß]Tqj {/ fʵNc, A_M|Z & ((%ξVLS)NQf6+/RY,^xX&R Y?e}q̋5?׫' 98E?VpT~@X_,N endstream endobj 460 0 obj << /Length 181 /Filter /FlateDecode >> stream HT= @aB` s4٬V@--WAr+]%?`7ľ@`4#Șc@li6(c> stream Hl= P pEA{Z[yK ~<::(:?c*Z1t(O-T >n,؃yE{F+T63-hx8m@C7ɳ zRܞ4U>(EȯҝAt1r,奂 #5 "D%܌줙CP'L=XW endstream endobj 462 0 obj << /Length 144 /Filter /FlateDecode >> stream H26T0P0V5T0T02SH1*@hd`gɹ\N\@5\@).}gC.}O_T.OgcWy?gz;Q{T?Փ+ P] endstream endobj 463 0 obj << /Length 174 /Filter /FlateDecode >> stream H22W0B]C##ScKCB. $jj`gɹ\N\@u\@9.}g PRT |@|70̎by=*9q3y ht?иy˹\= /a endstream endobj 464 0 obj << /Length 159 /Filter /FlateDecode >> stream H22V0P0V5T0Җ )\\@A!PH$r9yr+s{ =}JJS<]ch>PTRiFv@ ?<T`p endstream endobj 465 0 obj << /Length 198 /Filter /FlateDecode >> stream H4= @`B 3B`xJa)1ہٍzԦ.5CBi:} 5֤jzu̴`tNi )•\?^]~&),#`p} endstream endobj 466 0 obj << /BM 473 0 R /BN 472 0 R /BO 471 0 R /BU 480 0 R /BZ 481 0 R /C6 479 0 R /CA 477 0 R /CB 478 0 R /CD 476 0 R /CX 464 0 R /CY 463 0 R /CZ 465 0 R /D1 461 0 R /D2 460 0 R /D6 462 0 R /D8 470 0 R /DC 469 0 R >> endobj 467 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 468 0 obj << /Name /T10 /Type /Font /Subtype /Type3 /Resources 474 0 R /FontBBox [ 0 -12 20 39 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 58 /LastChar 120 /Encoding 475 0 R /CharProcs 466 0 R /Widths [ 20 20 52 0 0 0 0 0 50 0 0 0 0 52 0 0 0 0 0 0 53 0 0 0 50 41 0 45 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 27 35 0 59 41 0 0 0 31 0 25 0 0 0 38 ] >> endobj 469 0 obj << /Length 169 /Filter /FlateDecode >> stream H2P0P0V5T06R02SH1*2 (+Dr.'~%PK)YKW4Ӆ H>?ȱ`?Pǁ؞=??a.WO@.> stream H22U0P0R5T02T06WH1*2 ([(Dr.'~%PK)YKW4ӅQ3bG#@?C==D ?ß<Փ+ d endstream endobj 471 0 obj << /Length 121 /Filter /FlateDecode >> stream H25R0P0S5U01U06QH1*2 ()3=CHr r{IgC.}O_T.O@D@H|)3"C5A?rzrr endstream endobj 472 0 obj << /Length 105 /Filter /FlateDecode >> stream H22P0P0S54T04Q0WH1*PZ(dr.'~PK)YKW4Ӆx3#CÑ?\= = endstream endobj 473 0 obj << /Length 87 /Filter /FlateDecode >> stream H22P0P0bCcsCB.sHrW0N \ %E\.\Ǜszrre endstream endobj 474 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 475 0 obj << /Type /Encoding /Differences [ 58 /BM /BN /BO 66 /BU 71 /BZ 78 /C6 82 /CA /CB 85 /CD 105 /CX /CY /CZ 109 /D1 /D2 114 /D6 116 /D8 120 /DC ] >> endobj 476 0 obj << /Length 210 /Filter /FlateDecode >> stream HT1 @Ј0M&Ma jih^%b+,l#6ɦ6oa>Q;qegҥ )%C^ϕLX)ɞRd%";Xp»~Eb* &p>PjœoDK# c?B>/];Vu~)9ʗCbF!+Hcv endstream endobj 477 0 obj << /Length 208 /Filter /FlateDecode >> stream HLα 0H-y h[[*APGEJu5vCyR/!4hh"pI=fwp&p- y)Vx9_ṔJ="эbQbAM w:l*DUF/Rt˟Q)9,'?;Oɰ/\?ʜX"E 0B endstream endobj 478 0 obj << /Length 215 /Filter /FlateDecode >> stream HL1 @ 4ՀL!hB:vR"WHHa)EegTaFqD#tY* T(Hk8O.b R+p3\YVIpoUN(97C>SF&`(g endstream endobj 479 0 obj << /Length 233 /Filter /FlateDecode >> stream HLAj@,  $ĸ4E-Ez҅nz ^!۔n" fb3 &D ԊbUH[UTxx{4%U "2!x߭)J墴5 T#p61TIp4k#]/.j h2TY.&ZQhEMO#Q;L> stream HL 0 \ h7TpAO~zv0 !}iZ"3^) /P|)t}ļ+~)zU*$Q 3% !}bi~I)ŲaR!&T4i$e[nz<6\9mqz;ˇoRn8M  0(c endstream endobj 481 0 obj << /Length 231 /Filter /FlateDecode >> stream Ht1N@PG."MG\ 8tH@e R;(\TKi-Q"[xbSkXhze-`80ܮdYI~#ɗW%.as/ՙ1& q3>Cp;^bٕf;XYs?zSH1טwegYIt#$\˷J8 endstream endobj 482 0 obj << /Length 159 /Filter /FlateDecode >> stream H,1 1#W e nT0PK E[:KG|eaH8H4ƭP_BuH%y zpaya I=~F&e6W "-K[CK5Q(+r2 ?X܏MR#8 endstream endobj 483 0 obj << /Length 187 /Filter /FlateDecode >> stream H\M pXo|(?m A:@lQR\+"Yc+x쇬Byt$?S1'@qB܅Dƫ){&K>.{Jf n=-Т@-4B)ZȾ<"0*hХuKG%Rh>W^%9^+@` endstream endobj 484 0 obj << /Length 110 /Filter /FlateDecode >> stream H2T0P0bCSCB.Cc 53T5ɹ\N\ \@).}gC.}O_T.OG=>@|P`!H endstream endobj 485 0 obj << /Length 189 /Filter /FlateDecode >> stream HL `.>C)!5Ɔ,z-Pzӵ~9Q yё@DGxR4krb-'쑫|>]kPģC"EOcɐۢZ6jc,1 7ކ emhLd0d7F"^K%DE3M+0 endstream endobj 486 0 obj << /Length 133 /Filter /FlateDecode >> stream H26W0P0bccCB.cC 53T5ɹ\N\ Ɔ\@).}g W4ӅC P?(`!C<דg`?\\\/z endstream endobj 487 0 obj << /Length 121 /Filter /FlateDecode >> stream H26W0P0bcc#3CB.cC 53T5ɹ\N\ Ɔ\@).}g W4ӅC  Ḟ|?Fr 0k^K endstream endobj 488 0 obj << /Name /T11 /Type /Font /Subtype /Type3 /Resources 467 0 R /FontBBox [ 1 -15 29 38 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 40 /LastChar 116 /Encoding 490 0 R /CharProcs 489 0 R /Widths [ 26 26 0 51 0 0 0 0 33 33 33 33 33 33 33 0 33 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 19 0 0 0 55 37 0 0 0 0 26 26 ] >> endobj 489 0 obj << /B4 497 0 R /B5 496 0 R /B7 494 0 R /BC 493 0 R /BD 495 0 R /BE 500 0 R /BF 501 0 R /BG 498 0 R /BH 499 0 R /BI 483 0 R /BK 485 0 R /CW 486 0 R /CX 484 0 R /D1 492 0 R /D2 487 0 R /D7 482 0 R /D8 491 0 R >> endobj 490 0 obj << /Type /Encoding /Differences [ 40 /B4 /B5 43 /B7 48 /BC /BD /BE /BF /BG /BH /BI 56 /BK 104 /CW /CX 109 /D1 /D2 115 /D7 /D8 ] >> endobj 491 0 obj << /Length 132 /Filter /FlateDecode >> stream H22S0P0T5T02T06SH1*22PAcsC=HrW02Jq;8+r{*rypG`?`A~E| 4\\\`bZ endstream endobj 492 0 obj << /Length 149 /Filter /FlateDecode >> stream H25U0P0bSC#3CB.K 53T5ɹ\N\ &\@).}gC.}O_T.Oug(``!CA:? ?0C).WO@.ϫ} endstream endobj 493 0 obj << /Length 154 /Filter /FlateDecode >> stream H26V0P0R5T0T0PH1*22 ([*Dr.'~9PK)YKW4Ӆg@?1`d3`\= XxS endstream endobj 494 0 obj << /Length 100 /Filter /FlateDecode >> stream H25T0P0V5W01S06SH1*21 ()c=CHr r{IgC.}O_T.O?z LK\= Y endstream endobj 495 0 obj << /Length 114 /Filter /FlateDecode >> stream H26V0P0b#3c CB.#C 53T5ɹ\N\ F\@).}g W4Ӆc?#yi1g``".WO@.X endstream endobj 496 0 obj << /Length 158 /Filter /FlateDecode >> stream H22S0P0V54U0P01QH1* RX$ $s< M=r\N \ %E\.\??O`xDR6A?{?sh.WO@._p endstream endobj 497 0 obj << /Length 158 /Filter /FlateDecode >> stream H22S0P0S54U02T01QH1* RL$ $s< M=r\N \ %E\.\gO? p+dGRlGY?Lg_hy]r 0T l0 endstream endobj 498 0 obj << /Length 166 /Filter /FlateDecode >> stream Ht1 @DMR Q-> stream H|α `H5[@cL!hjihk KGpq $`x6=55De+AȐq_MgDZH oJx6T_da-H*rȥ6(m'lv.M#JBj+eWFm  D`݊ endstream endobj 500 0 obj << /Length 186 /Filter /FlateDecode >> stream HL= P,yH'DSZyP!G*  `2NBoav  KO6n.b-q"\8cĉ퉓Ln_I2(V6&nqF# t@ _2m/UJ&ݤmը'J2~dL>  endstream endobj 501 0 obj << /Length 186 /Filter /FlateDecode >> stream HT1 PD#mr4&@` A+ARXz%%EJ)$| @B5nBKӤ=TQ;I3 VI.Jx8m%x.(%%}p{ hj}mԖRt~΅+w*ެyqF4| endstream endobj 502 0 obj 833 endobj 503 0 obj << /Filter /FlateDecode /Length 502 0 R >> stream HUn0?#D.ɩA9992%GK;El"||<>oX9,[SJY@M")ƨ9@' (rc"k(q%Za$NpXDXӚ]y^ݺl1YHZyUuLr bV#=.f"Ko(>*>\bm a pd%uhl  x F-NtZ> stream H23U0P0W54U05W05VH1*25PA3 s=C$LrW05q;8+r{*ryp`=z R)~= KHgv0*0~P 4 P&TՓ+ ͜) endstream endobj 505 0 obj << /Length 112 /Filter /FlateDecode >> stream H23U0P0U0T0T05UH1*25EML  ,s<Áb\`)YKW4ӅAP@L20C)p r 0T= endstream endobj 506 0 obj << /Length 190 /Filter /FlateDecode >> stream HT 0S>R; U N>::(:+8|>BGy91 |$eI9U4d+S:xFߥ$B2C#YI̩@t܎B {t 6c] RA#A7aGH`8#U R5T]U2ZK jU_`)$IJ endstream endobj 507 0 obj << /Length 158 /Filter /FlateDecode >> stream H23U0P0W54U05W05VH1*25PA3 s=C$LrW05q;8+r{*rypB5ԃ`DTa%{$Wcs~0C!RN$= rzrroR endstream endobj 508 0 obj << /Length 100 /Filter /FlateDecode >> stream H,=@@Ds9~Xk+*@ ]y{diㄳ`5|IPr9(Hk[e_QCc?wMGM~ endstream endobj 509 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 510 0 obj << /Length 240 /Filter /FlateDecode >> stream H?N0pG ޒ#]R H0q`d٩Q/ (UebY nc{K~nl' h=5V=5l;jneKk0`L59u nJkDɩɫ#|+ l~,3'+N֘j֫S?6űÁ?n:(fABc4^sjkVnzzoJ0v endstream endobj 511 0 obj << /Length 200 /Filter /FlateDecode >> stream H4O `l@@Ă6VVZ(j]x@|1~f6D]NfNNn%:lDNhGKJ:>ϋk&gR&UeR/k6DtڰaV+a]}d0F; nhi!_cE"rڠ!ZIڥq B` 5 endstream endobj 512 0 obj << /Type /Encoding /Differences [ 0 /A0 2 /A2 6 /A6 20 /AK /AL 50 /BE 67 /BV 70 /BY 77 /C5 98 /CQ /CR 106 /CY ] >> endobj 513 0 obj << /Length 93 /Filter /FlateDecode >> stream H22V0PT52T04V03RH1*2 (X+Xdr.'~ PK)YKW4Ӆk>?|.WO@.I endstream endobj 514 0 obj << /A0 508 0 R /A2 511 0 R /A6 505 0 R /AK 504 0 R /AL 507 0 R /BE 506 0 R /BV 510 0 R /BY 518 0 R /C5 517 0 R /CQ 519 0 R /CR 515 0 R /CY 513 0 R >> endobj 515 0 obj << /Length 105 /Filter /FlateDecode >> stream H26W0P0T52P02R03RH1*22(X)%dr.'~!PK)YU()*Mt#503Q?'W @2֍ endstream endobj 516 0 obj << /Name /T9 /Type /Font /Subtype /Type3 /Resources 509 0 R /FontBBox [ 1 -21 52 41 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 0 /LastChar 106 /Encoding 512 0 R /CharProcs 514 0 R /Widths [ 65 0 65 0 0 0 65 0 0 0 0 0 0 0 0 0 0 0 0 0 65 65 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 44 0 0 60 0 0 0 0 0 0 100 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 37 0 0 0 0 0 0 23 ] >> endobj 517 0 obj << /Length 366 /Filter /FlateDecode >> stream HlJ0 ȚжNe0AГ=(zDl"x֓׊!tKϏi/cX^XOIY7x#:+]q|z9D7eў]bQ`[$,)w p 1Jg!F|SsgmjMoE~!5֬k|4^V6OB}b',l$z[mpko)J(w#wE-oÝ?wh7!ɖ*8.|XU *&nVA3s;Φ6th\-ty-;PTt[z/@'nx>c9sf} vsv~Oj endstream endobj 518 0 obj << /Length 261 /Filter /FlateDecode >> stream HtϱN@ `W*yh!~HکJ+ &1ZxfL*ɝ#7>NیiLWtqMfJ7zI浑e"5y<p[zF2G`;# endstream endobj 519 0 obj << /Length 106 /Filter /FlateDecode >> stream H26W0P04Q52P06U03RH1*22 (X A@29ɓK?\ȐK(ɥx*rypd ~v j`r 039 endstream endobj 520 0 obj 747 endobj 521 0 obj << /Filter /FlateDecode /Length 520 0 R >> stream HUMo0 v̯QLlb@ TkF8O3&"kIcKl)*}хU%}ė-iN4u"UG0֡nV!qG<F 8o Bэ4-^Yi J%F}nG5SẑJIWT*U- =4 endstream endobj 522 0 obj 847 endobj 523 0 obj << /Filter /FlateDecode /Length 522 0 R >> stream HtVM0v[UROU zȂ*1e_ߙv9-~ޙ<$V\fb|RORz7͎p@6kseYMVxdɺ;DuDJe }lsySWyU ZUr&ۙQӾ4GJ*}n4lbۈߵU0)KGƴ5jZ2hh90-}=rkX ֡-t-Xq rn \FI[s3UseX vg.4}Gyf.P̍v+yg+Sp7 źBdm+ ԫXiI ` kZ,3ښ˄c ķ340aldqW~)ysIReR^ڇ3(?#חcov{Ƽ;Y)>[*nibN1 ilhKE8ax ]*IT•shLIq#[kYrT` endstream endobj 524 0 obj 809 endobj 525 0 obj << /Filter /FlateDecode /Length 524 0 R >> stream HUM W䈥M `[U*Kۦ6![Im@!d<03o潁Lp1֎:[pF)%ĵm9Ks%咑N:[f?VK{zeE.q{}>4àG`0" Ķz}J9A]΂ sYzIL^c7uBm:xbmW8 XVӚPa9d$~72i'ݿHˣ 9 p!.’詨Ȝ?E?Ƌ`pC@Ռ Kl$b@G.qDJ¦;V^Wk5 U ݳmx0l!0:`dԆ15eBolC4.akQ_dc:sƨئ}Q{%ϣ M ]c׽3*{ N7P8GAU}rpRh`"Lߜ9(W`Пn|\èa0 nHcYpxOYpzTTֶlk_Ck|kyr+PN|w$L6$0'R\^x#_H0"h֩i2PjMYأ0Vu7dqbO$;U98q.DH+ڶ%Y´in^L;MjEy厍l=RnICws!QA//PID.6h| P.")2~zD F^,a4#k2-ix`?<6nzjHA@2t>O_2 endstream endobj 526 0 obj << /Name /T6 /Type /Font /Subtype /Type3 /Resources 550 0 R /FontBBox [ 1 -14 66 46 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 58 /LastChar 121 /Encoding 549 0 R /CharProcs 528 0 R /Widths [ 24 0 0 0 0 0 0 0 0 55 0 0 0 0 0 0 0 0 0 0 60 0 0 0 0 43 0 0 0 0 0 0 0 0 0 0 0 0 0 39 0 0 0 35 0 0 0 24 0 35 20 63 43 39 39 0 33 32 26 41 0 51 0 37 ] >> endobj 527 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 528 0 obj << /BM 551 0 R /BV 548 0 R /C6 545 0 R /CB 546 0 R /CP 547 0 R /CT 552 0 R /CX 557 0 R /CZ 558 0 R /D0 560 0 R /D1 559 0 R /D2 556 0 R /D3 553 0 R /D4 544 0 R /D6 555 0 R /D7 554 0 R /D8 532 0 R /D9 531 0 R /DB 534 0 R /DD 533 0 R >> endobj 529 0 obj << /Type /Encoding /Differences [ 44 /B8 /B9 /BA 49 /BD 51 /BF /BG /BH /BI /BJ 57 /BL 65 /BT 73 /C1 80 /C8 86 /CE 97 /CP /CQ /CR /CS /CT /CU /CV /CW /CX 108 /D0 /D1 /D2 /D3 /D4 114 /D6 /D7 /D8 /D9 /DA 121 /DD 123 /DF ] >> endobj 530 0 obj << /Length 136 /Filter /FlateDecode >> stream H22V0P0S54V0P04TH1*24(($dr.'~PK)YKW4Ӆ @ _?r 00/*b endstream endobj 531 0 obj << /Length 201 /Filter /FlateDecode >> stream HD10Pgdi |`LtE"JJ Զkqs. .v?78 gƽ9V7fwU M '(WlrD3 4oͣM:+9R PF◌DsQ.(! RE5(>~RM4䔰Ν`j% endstream endobj 532 0 obj << /Length 166 /Filter /FlateDecode >> stream H$1 @ irtkvV@-m]kQr)N 9 PXXLB/8&L hy[4zG,(Ja"}.EՂ_)^9 95]} W (a endstream endobj 533 0 obj << /Length 221 /Filter /FlateDecode >> stream HD1J1,[ n.S-> stream HL1N1a[S4s8*e[ A %t+y[r%K\dsӹ9FD(ZΦE*ȔPM M„&bDM5]€3"@G_n&4Bw==ѯz endstream endobj 535 0 obj << /Length 206 /Filter /FlateDecode >> stream Ht1j11.4B )N "W>@҅CRkGT0I44f'kĿHrt|a,~4S>ϼ?4~*]~N<1H 7"j,%% atyM6NK1Q{p: \iFobnQ!7N*aJY%2NK{ 0m endstream endobj 536 0 obj << /Length 211 /Filter /FlateDecode >> stream Hl=A:hd0uiD`a(x&gM. kTQJ _+ #C=só˕qټ~wfH9p# ꋖpEgpFAʭ-\tM4**@2AFs>2P(;RS D?HkM4?4m:lxO endstream endobj 537 0 obj << /Length 179 /Filter /FlateDecode >> stream Hα @ JB>> stream Hl; @4{4Yvr!*Bu֛ya-BI| h`r24dd-5X)d'dZzEٖl)-̊4f.9rHs 8&AqPqu$|OZTp?kTUTܺD潂J|*[w_Y.Z\Udħ@" 3.JC2q endstream endobj 539 0 obj << /Length 194 /Filter /FlateDecode >> stream Hl= @   h\.jihmY:1baIX| 3oY˞ێ{kG;zhgq4)]r֣t|Ď|ƇqC cbH ILbZbU X U,Z֭۫6P\::c-U"֘~/Z&J`v endstream endobj 540 0 obj << /Length 96 /Filter /FlateDecode >> stream H22V0P0bCsCCCB. m1T03T5ɹ\N\@A.}0<}JJS<]?P`  r 0UP endstream endobj 541 0 obj << /Length 112 /Filter /FlateDecode >> stream H21T0P0bcCB.# 53T5ɹ\N\ F\@).}gC.}O_T.OA?2>`\= ,~~ endstream endobj 542 0 obj << /Length 175 /Filter /FlateDecode >> stream H|α @ `Jnzm)݄ N>::( n ⋴opcrg~AHBj8LrNShSIQaH8HͤEXY2s>N[24-5pm '4P{JU h`$FБohjhIo  endstream endobj 543 0 obj << /Length 90 /Filter /FlateDecode >> stream Hd1 0 }A^FSZPf,( L5K>q; JȈ~50,  endstream endobj 544 0 obj << /Length 210 /Filter /FlateDecode >> stream HDͱj@ `9 Znf@b z4S hK  vy<SeK|> stream HLAJ07Px0d[BЕ] 3அYx/Roe!e/$򷕩cYZTS\²~U壱 .oq\wkri~d>wD>gԩA!FrX$B0Dy(`2A羁]'AID*|g?=J4)9嚔tj611)b QUi@ endstream endobj 546 0 obj << /Length 218 /Filter /FlateDecode >> stream HTAJ0 h[ ]`<ӥ EIooRoe%3M#aLƟrg usNz gM>悔Kn+Vf l.[fbR p`5 dJ1T$b$*Eè_SHCY'u[r#^G2]OtO_ I endstream endobj 547 0 obj << /Length 190 /Filter /FlateDecode >> stream H4= @   h\7?0] Roes\`{w9İ53t"Hecg&ϥx8[|S6%4!zxjF uh8O$g!/.D]> stream H|бJ@ )G}-ԫ)|PN _+)Sɉ"%f>ڗ!ȳ[Vyֱ6]-ŝ/R\')k(h&;`2,c$ŘD Q&%L{[Aߴ B7 SsN1RrRJedƦtE\r+_  endstream endobj 549 0 obj << /Type /Encoding /Differences [ 58 /BM 67 /BV 78 /C6 83 /CB 97 /CP 101 /CT 105 /CX 107 /CZ /D0 /D1 /D2 /D3 /D4 114 /D6 /D7 /D8 /D9 119 /DB 121 /DD ] >> endobj 550 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 551 0 obj << /Length 117 /Filter /FlateDecode >> stream H22Q0Pb#ccCB.CS ĵ3T5ɹ\N\ \@).}gC.}O_T.OdO? dszrr7b endstream endobj 552 0 obj << /Length 174 /Filter /FlateDecode >> stream Hl1 1Eja!sfò[UV@--7Gۣ[n22_c\5vZto\֖7ME &!쀊$H]dV*jaf謒:EO~_B2"lHEG c ~')'> ]3Z endstream endobj 553 0 obj << /Length 171 /Filter /FlateDecode >> stream H4;@Pl2J6&RhBr4()6;$7b9p\p|w"Dr&*?DY}ޱ ͉?=!j`P:euLB@zHDN,hC0͟l>Uw^lAP):4tQT endstream endobj 554 0 obj << /Length 174 /Filter /FlateDecode >> stream H<= @ ) hV jih/oo`Ų1|r%O c ]28\Ό$gjJl Jײ.PZov^\ 1*  I?r?rӀSsxOE@/@XJ'jV5#bi endstream endobj 555 0 obj << /Length 161 /Filter /FlateDecode >> stream H26V0P0U5T06S06TH1*@hl`gɹ\N\@5\@).}g W4Ӆ03?lo> p=c{Cclgc! C0,!\= i` endstream endobj 556 0 obj << /Length 193 /Filter /FlateDecode >> stream H41 @Є#d.ɚ^ jihXZ\ds-S'5f~b95f9^%8%b1'%W\A\w!.OyPaFINh kZMD4*\!3 zL@3ʋ~1S/h\dV 3f .`wi endstream endobj 557 0 obj << /Length 177 /Filter /FlateDecode >> stream Hṯ @ ,^^@;Z 7:||-9Ř !1XH`1ţ  ˱ lFCf@^o SS(_ S ޽уN$YBF6cRd4T~Ur%-?|Uep. endstream endobj 558 0 obj << /Length 212 /Filter /FlateDecode >> stream HDͿ@]X\icvS^upw' vvJ+)G&NM 5#Ow$lSOI+NS (`8 |D錖/cdcx%K r`:7A(:tVBV8u$j%v l7-w8hX 8qIx`b|e endstream endobj 559 0 obj << /Length 240 /Filter /FlateDecode >> stream HLϱJ0 ymki \ *ㅫ(888J_$A~ @~pr+n懚x>)'4驼客R3sڛ)wETP!j ~|jgQM&f51OU.jBRg)C02 @Iގ2n1jH\< j k(O&KݿwV>+$eƤA=ПC[ endstream endobj 560 0 obj << /Length 158 /Filter /FlateDecode >> stream H1 0 }4ıP ԱsyH/oCi +4Xix6HwAֹYP!'Pi=AO|!b3)b"r 'I.e_>Q|x/{ g 0W`> endstream endobj 561 0 obj << /Length 167 /Filter /FlateDecode >> stream H1 @E7X;J Djih=Z#Lkak1>ü ǖ doFl?;YJu sd_ʊL_#v?/ք!K)8#CUhVP( JEN$D9ezjB tϫe endstream endobj 562 0 obj << /Length 131 /Filter /FlateDecode >> stream H21U0P0a#cCB.c 53T5ɹ\N\ \@).}gC.}O_T.O??3a@'>?@ N0$00a`p`x\\\\ endstream endobj 563 0 obj << /Length 176 /Filter /FlateDecode >> stream H\1 @ )7{$"BTp A++Xx7HE`a1)Le)RSD4R<3+y9_d$67q>D:]}7z' bc"6#&adLF0^N`;ZXGqsZ endstream endobj 564 0 obj << /Length 212 /Filter /FlateDecode >> stream H\1j@1* 7p$ w Q IƩ!_KQnr /.ܼbg g-1wVd2unifѫZM endstream endobj 565 0 obj << /Length 141 /Filter /FlateDecode >> stream H26R0P0b#s#CB.#3 53T5ɹ\N\ Ff\@).}gC.}O_T.OGH 3 ?P9{?>-P\\\Tb endstream endobj 566 0 obj << /Length 218 /Filter /FlateDecode >> stream Hlб 0+  h[lu,T;:lK_}>B %.J h H?HD,洳H ,ӘRtQ_r'5c|c / /=L,Bk-u0M6>$P9 abPū\;p|YzKK#UDMP|C<UrD3@! ` 8 endstream endobj 567 0 obj << /Length 131 /Filter /FlateDecode >> stream H26Q0P0aCcCB.# 53T5ɹ\N\ F\@).}gC.}O_T.Od$ `bf(f ?Q0'W @ T endstream endobj 568 0 obj << /Length 170 /Filter /FlateDecode >> stream H,1 @ xt7[ZyhZo 70?,v>T-e7O*OzǶ$tsAگr/jU('2PX7#lw$ 1/EQVSQ.UZzO&T endstream endobj 569 0 obj << /Length 88 /Filter /FlateDecode >> stream H21T0BCs#CB.Br.'~8P1S!BIQi* *r 0L endstream endobj 570 0 obj << /Length 133 /Filter /FlateDecode >> stream H26R0P0U0R0 )\\F hd`g`gɥ`dw pVR %E\.\D}g?`? dE@Yb..WO@.(8J endstream endobj 571 0 obj << /A3 570 0 R >> endobj 572 0 obj << /Name /T8 /Type /Font /Subtype /Type3 /Resources 576 0 R /FontBBox [ 5 2 25 23 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 3 /LastChar 3 /Encoding 573 0 R /CharProcs 571 0 R /Widths [ 32 ] >> endobj 573 0 obj << /Type /Encoding /Differences [ 3 /A3 ] >> endobj 574 0 obj << /B8 530 0 R /B9 543 0 R /BA 540 0 R /BD 541 0 R /BF 535 0 R /BG 542 0 R /BH 539 0 R /BI 536 0 R /BJ 537 0 R /BL 538 0 R /BT 566 0 R /C1 582 0 R /C8 583 0 R /CE 584 0 R /CP 581 0 R /CQ 578 0 R /CR 579 0 R /CS 585 0 R /CT 580 0 R /CU 591 0 R /CV 590 0 R /CW 592 0 R /CX 586 0 R /D0 589 0 R /D1 587 0 R /D2 588 0 R /D3 561 0 R /D4 577 0 R /D6 567 0 R /D7 568 0 R /D8 565 0 R /D9 562 0 R /DA 563 0 R /DD 564 0 R /DF 569 0 R >> endobj 575 0 obj << /Name /T7 /Type /Font /Subtype /Type3 /Resources 527 0 R /FontBBox [ 0 -14 57 47 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 44 /LastChar 123 /Encoding 529 0 R /CharProcs 574 0 R /Widths [ 23 27 23 0 0 41 0 41 41 41 41 41 0 41 0 0 0 0 0 0 0 61 0 0 0 0 0 0 0 30 0 0 0 0 0 0 55 0 0 0 0 0 61 0 0 0 0 0 0 0 0 0 0 40 45 36 45 37 25 41 45 23 0 0 23 69 45 41 45 0 34 32 32 45 43 0 0 43 0 41 ] >> endobj 576 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 577 0 obj << /Length 175 /Filter /FlateDecode >> stream H1 @Б!s,!] *0&GQ<”¸& MWgL>Mܒ˨xFWiF#70x8ah!CSmd ]/#%t $ PBiKKYC`% > stream H1 @E'Lan]%] *PK E[raJ ab|rrzޒ ]:K74#V͖\fj=#&r0|&B,<j)96D(_y *6!uH'Rpp/"; endstream endobj 579 0 obj << /Length 159 /Filter /FlateDecode >> stream H1 1DlM͆m`U0PK E؂#27f`]šd %JYWx>9nL8CXSÜ r%)&9TtL-:> YTd endstream endobj 580 0 obj << /Length 168 /Filter /FlateDecode >> stream HLM 0ȘG\@6BU0 AW@]v+,o 5PDA:ɘ|PeI>+BE]h߰D?D;b̩O!%P֔^ \M endstream endobj 581 0 obj << /Length 178 /Filter /FlateDecode >> stream H\1 @ )2$B1B9er%l!N11U+(J+Z> stream H26P0P0b#s3CB.#(kgk$s<L=R\N \ %E\.\ HC=\\\bH endstream endobj 583 0 obj << /Length 153 /Filter /FlateDecode >> stream H25U0P0bS3CB.s 53T5ɹ\N\ &\@).}gC.}O_T.O. "$PAHoA0d$D1? D2AiH|r 0O)/ endstream endobj 584 0 obj << /Length 231 /Filter /FlateDecode >> stream Hl1N@%.,M#d.F[) $8PR$zcbM|-]X"j4tV;ae'UJ7ɶMZ'ܾܫyϧ4bLɘ~2=Yp 'R-x!2~&|=w@8W@a0H ハ831> stream H10 E2 y @ZnF$2 3=Z#dP8NL0I_+f:Vu1קhKYvI&8^rhږh6RvKq[}=V́;Ƃ<@jB5)SYSs /.*(/+npp/c endstream endobj 586 0 obj << /Length 112 /Filter /FlateDecode >> stream H22V0P0b# ebUeh䃹&z @"9ɓK?\ЌK(ť`ȥPRT0H?~ 2@'W @M< endstream endobj 587 0 obj << /Length 166 /Filter /FlateDecode >> stream H2T0P0b33cCB.3# 53T5ɹ\N\ fF\@).}gC.}O_T.O? ?C  {z ?0? 0?`v ֍D ?4?? ̸h.WO@.-" endstream endobj 588 0 obj << /Length 133 /Filter /FlateDecode >> stream H21U0P0a#cCB.c 53T5ɹ\N\ \@).}gC.}O_T.O370gc` !P PP;.r 0XZ\ endstream endobj 589 0 obj << /Length 93 /Filter /FlateDecode >> stream H22V0P0b# ebUeh䃹&z @"9ɓK?\ЌK(ť`ȥPRT ?P 2@'W @65 endstream endobj 590 0 obj << /Length 218 /Filter /FlateDecode >> stream HtAJA Eu[WP.]Rޠh& ̓J~^R}ҍn,]j)ɫt;nyE+Mw,õKё\<Ǻ)p¿,̰DT  ' ٟqr)4+ԱA5q |#f| 0"@W endstream endobj 591 0 obj << /Length 138 /Filter /FlateDecode >> stream H22U0P0bcC3CB.#K 53T5ɹ\N\ F\@).}gC.}O_T.O`!3 cfM 51'W @ɂ endstream endobj 592 0 obj << /Length 141 /Filter /FlateDecode >> stream H21U0P0a#3CB.c 53T5ɹ\N\ \@).}gC.}O_T.O?gB| x$c`CC}C pf4Փ+  endstream endobj 593 0 obj 731 endobj 594 0 obj << /Filter /FlateDecode /Length 593 0 R >> stream H|UM0G{Oq$G[CMiPڔ$evb͌߼zjXo~G6BjsXs*/H'ʵxX|tX96qlpe2>q J >r% vua$v6`!t97lϿiUJsYY3- λa~}`SUjԷk@PF׺xa%,<3SbjSSE^ Ki궫6O!j؞lh>LV9W dEjU: O+wp%%!b[xnlMD8KLBr#qɹϑWeG܏vK"HI>_1^;  uuɫۚ`RR`2H}(U1Tn. endstream endobj 595 0 obj << /Type /XObject /Subtype /Image /Width 1 /Height 1 /BitsPerComponent 1 /ImageMask true /Length 5 /Filter /CCITTFaxDecode /DecodeParms << /K -1 /Columns 1 >> >> stream P endstream endobj 596 0 obj 864 endobj 597 0 obj << /Filter /FlateDecode /Length 596 0 R >> stream HUMS@=Ư8T 2wi억CN.4d?ArL":HQT_ŶcCn<ϏBkaH uo0=_hobߥpnQ~| 9黭-ֲ-b(})BGݾw{;2ӐftEZ)$N_F:Kezf7pBFG>@GhbPوz0AjFx5N rL~K=fAMf݊QV]e=Ig Az!6{ *u0O*:GG_ _Btj]gnMbhL7ն,ײlٯ VkiEOgOYxCAdf hxA3l9p|[Uw8ڢ> Q_hg%ypӳU[B=z_{;ɱ*~jq( IY[wyg~)ΜZg%o[ _:F+B[RdDJoʪ`A>{85kեA'OLљHtUOcO@ZsӀ v *WU@F>FSE0I`&7 [ro}TFS7+fEߐimI#['D9J(fe7J!'v>-}CGQ9=ݶbl%zjG endstream endobj 598 0 obj << /Type /ExtGState /SA false /SM 0.02 /TR /Identity >> endobj 1 0 obj << /Type /Page /Parent 101 0 R /Resources 2 0 R /Contents 3 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 2 0 obj << /ProcSet [ /PDF /Text /ImageB ] /Font << /F2 52 0 R /T14 399 0 R >> /XObject << /Im2 4 0 R >> /ExtGState << /GS1 598 0 R >> >> endobj 3 0 obj << /Length 421 /Filter /FlateDecode >> stream H|RMo0 W(3#Rv+R߂:7\ tA>>>QO{1$fD)6)$Mn0o0nY wX;x4=n`q31yșt!.\⼟g0̌M"ѣ/ #!9]!7?uUkf7 !Ʌ4=L+bZVdU>KHYYFB"vT߰FswPG1&-Ň)u˺s-Z 磉|~GcD$` 賞iioqjNa*}{+7Wėv=a<틠vgUJ#P9dilUĞ*&I$*{/A򢻲)p= Jf_[Gʴ& endstream endobj 4 0 obj << /Type /XObject /Subtype /Image /Width 768 /Height 768 /BitsPerComponent 1 /ColorSpace /DeviceGray /Length 21292 /Filter /CCITTFaxDecode /DecodeParms << /K -1 /Columns 768 >> >> stream &%˩eqċX8##r<8q0EDwxqdtdmذna<ŋdtGQa҈#:e@A#(pvmAz hv1dub AAeSN9U 9CG33XN>C9C7">"?wG8+G# DX BVBὲ8+56MVP"<Ì#tu@H/(tS#(| SDqB5:>PP !f8Ap\3$X˭FG!!T2: GHG5Lrce8;dz&;8Ca G,qaC(|C#!R9Adu!a\#$)`r7|Rp fƲ@J"C9 1G8duG!Gdppk-\d 9! 9:#!!a #8Db}H.8v@q!GeBA&91j8@.? EÈ D(䜆#v3 0d#[mC!8 !1pg"8ApEe q(YcőDC/" .`t B4FTAGec!Lㆁ0! Ct#B8B.C8A 1 +H M YA!9u>xe$GT'Hl\o(r)8 C]2a5 >!E/a)SG2>*X#:zR(9q AB#,pa E[B)tC  "!He!$:D!GT<M> &,-",tCyM)G (t A6G29"È">GCEw*Dq| Z79CAY1FtG8PL&GPEEY)C 9Nq$duCBD[G!ᖳe(sBiF@YH&S74Naf#q "F91`;6 l. B @!ЈAeԱGDBR&8AC(Ea8">8]Hg 8L#c!T+I&9!29 PÒqI BOh(e axe@ HGLÊCyǷyP& P2(}qpAGTPUAr(BYC8A"FBAa": !(H\2>GA0M *ʲ 8\Et-E)RGW;u JA@(}  H4PGdu XA6q0D}:D|Ea! I`A (pAP@ÑPa-,8ʆ h2<H3+}%lGr:#} ]B0ݕb)GA3:T #IE:x8@C8=BC@#4 G\6 LYC ZA1I.1NJDv(",8- ,XiBl J MPGOR8q 0)e(r.Eః- H' H BG \9,rc]1,#5cAC:#l6Pkm&"˦S>91܃9cqC%ipÎ"#""C (a1Ð\| D )b&8 I4[-E):#A 0dy(Dt-(Gr,q莘0dqP>a-Z@vNPAYNaQLMavI( 0@@ L0"@ @GDr#쎂A Ie-PYC:#tC;#Rae")Dl,㌾GA` QH$DBHrL(ta CH hDt蹑Qd 6A0@A0A)41M!p"L0VEX;H 08";pD}=mdt$Wl4@*a@.* NB P c #m0D @AHB i0I& %I(<(`hG0쎈P BLdy 8,\GIHA0HA4PAb!ID4"$( d| R!a`$ه!A94)݄=Y{8\vID!A.t:{@R9qaR !`  (v  A$GA$GDt]P6;#(Md{V(qˢ:a_0($T8":7 ":`B#A`&9NSATC=va4GQGAxxD|9jT9NLs(XAA2>GDuGdtGL6!a LÕr sDu 'E" d8"TC@)}e1BDt ?IAd| l @"@v D \ TDƄ`(p$# CaA IB( B h r úCWDAeC#SE+ ,a X B $TACaj"9,qdt# DEh$taA LT Aŝ8%`j">]q,ɹ@*5h pvGDzˠ@P@=)Ѝy H4A6X  B9@:DaXA>X0CG莒pA .a,( ,cD" p2K(x B. ]tX DGI(@-$$#<7C9Cr8 A/Xc2!v 1!i:I" $GA$Dt 8I$ FyA&9tB !h!9h- I (pV#GEB!dc842t8 Yc9c莢JL XTS#F~!#r&mP鄐ESG4!"B!AL+KeM+dv4S]#D| ❥wpV &8.Y@D184",A%eA&4 $  $)Ђ*B !2>s#pDt9Cpp@!8EP (uЄ 4T EM/Ҋ@;#A9C0VC" L!P@ Gl"<"("29ӡiK  AP(l`9c98 B!&G |Gˢ莈  )\$$ &$ه<\ AqxA #dtGEа[vB.V,8X a:B+\p@#q "(pA2;Lao(pDt-VS" L(e]v"M"8a8 EP ci$B<"V-GA")@* DD$ 8 wAv H$8@*Db!f9CGIA1@9!8 B  "8( ł b"9>(Hh PV0I p#Er0y #90BGdx&_ )ʉ( $!@܆/dt2cqHY6],@Q@A Dr(p±6XAC#FE!B,,Y 86(e!iZ"%B^GB I&@XMBB8 !hh3sD13+H$(t4'& .I$|IQśLő V:.eH!e@ "}ЭAŢI1aDD!9q@>ƐEL!Gy$xREA!@^R# r:#!] @a8AÜr CHLEՈ g&SHE P"mAAl#8"Adt^&P0l c@;GGA)(t49 d,tC]n%r1莳IWd}4A0GaŠB@0H C YH!D|!GLa2.菃P"8IEi DtE(q`##qtGA" PM \D :DH.p A#qw E"18C@A0?Äc ,=#Z:Ldt\m" ԡ̎`#r(4/#t]3ZA *(r `G?D paY1+,""*apr!%n "$(r^ F ( Ch(#ThPcpAxAa*LA@Є":)t 0@Xe_f$P" iwh }]P@ #_@6wGB^V*E"Cc`sqh-#UaTS@BЂ+bC 'H Tdt*aAM@$"F@+L"(CaH(qAI$V †) M+peERDtȃrtCwE2GP#E;(TGDtsAp|Rm"cA ":D|,S1DGCG4$.#i6&#YvlBXT)0cA $Zgt)uGfB!P:!pNfhDq c &G v ч$г^CDx"|0җG3" aXV""+ & H, dt)՛ A9!!@^UbãALq] .(U]C \rHpl+8aa A0,qդYc#":e{E8C w!d| Dy.؈8A wM0M A2ސeQ 9EvG+#g|ݑ q8$."D 6TA rB(T NP1l D[(qqKFD0t8#9 A3Tx#Յh  ) lB$W9P@+( C#XFAe<@BP I.gENXEAaTw $ I+:F.8$Aa: в $P dG(q!} ^"liG0"P 0aC##4s&IRi#qŌi4@t!B(P8$ ">gH,XB!(t2B_J# E8A % aDs.H !XAeA^ VH B6G({-C`$*MnG^#G |!B!EuQA(r(wvGثQAtGTDtI::AD#̡ʂt#!b# P9|hCt. aah p C A!1e@#h($鈇MC! 'L"".:q&a,ADtTM!HP$PrA`wa4%09*ʈG(r(pTR ߱@$˜r d @ iZtCݥjl, a Dt h9"CAAxA28X[B),i H[Ta I0],F[I>菶]I6]C ":#w,qÙ;PTPfA@Ae:H @#GAʲS I8:jDyi'6.B)!!Ɏ aADtDtGA>: 8n!p@Y "66G !c!`P 0$"#A 4-XiY GTNöG莂";R">ceF”9c.莈 +S GD4 A"0"I l)Q;b$^A0[#G@i:B2(|ʴݯ *@$GIh":#e:(p@AAGJ,[G@8ea;aIP@n:ZIr P[ Xv& I:A/4(6GDph#:#x@GЈIuI8Q`!LAcB I DtX"EN"]M"B qP*0$ A &DuA$A[B@cE" YIr8Aa\vj/eXO+ Dts(pI(g $$LD|0BAl& [XB#G@8^d|JH@*@Da7ƊHj#P"":  , h6!qBإGGQ )Hq~pDtC8aL'h,A!"!S8AZa$.G8b,46mI CMAu@1Dta* ϠEx<$ IBZEqC@[DtX CQd|22"#׍ZEa4GDy":a N[>GDt Wq&P(pAd(u xB#&*# KDtNA$ $LDt! 0B[,q0SCV,; ʽP$X;!m$LWeAܡ&-G$@ Rn{A#:H*h AtA!i&q A YnAV A0B!cH5qJ">_>( .85 j R L"Ag""dt QWm` @OB `Ô A]G #A3PF , ˢ<(qb 4$PDyqISP1A$V4ƚQ`%I@BB e8E!HvAr菗Z/LTGƅAc#Aդy4,( 9;PH'P@ ^"":(4,PF!tBa:.DCŔ>r /. X!!a.eaS/d|!dvx$ I-)8@pB"x!B ˣDYPx H4^V4G@ #09C"&St:8@ 1Y VOA8A0EL;&:HCJGA"<((t|,a0# @,!;Q {+|R k l!v*@ ULL$L!à@:D0^B!q) hÄBX" " 4_+ ?mx0TP 43@! EY͏H q,d|$GŰIa`( HM A Ap. **6F, \ A{ DP$A64($ZEAX^F ʁQNVa쎃X-$ e X&8C)s&#Dt D(a D} Xi0E D}h$A!:ܘ "PAzEqq!il @R"#AA C 6lDxPSƕ@8Z## Tg-A lDth#"CV&A"n$]Ќa8,(2!C"&ʁ ב.tt @ T ",p@,B#E@@M$ r!X""*I$+#.qG@d} E:@dtL b,xlBReNE˘AF9Ne]!dqQWH$A">  E"<#~JH4P:Xds#! * qY#@ AY㑎HqA8 P0I2* &GH GGI&} @#p.%8@$qh%w aI%t*#@$!E*ZB! Œ]P0Rlr+kH @m ;Fr+0X B C 9 A;5h!H#BGEP@& #Ma EEjGQd 9 m$,-<DsI YGBHq$@r# $P)0@@#zd|(R@9VTy9=10DC A,H ;XiJ!P@q+,r!!K I  ph M *G@$}@U8EpA2B@e $BXA_@ؠ Ra1G @hl DxŒlDA6°A!"G MduCb@@!8"<B 7A0&4,#:.$]xAbC( PA äHC8 IզGq ,AYr!G!9!S/c@:A]E"A"EA YYc08#YCdv@ 8AE$GH؈eV!% ȃd| (rpwT@ ʂ(pFI!D MñÖ8.A!\ #yR${#1aDA(&^I#$M0L0L0u GYň`ADuSr G!H Kز(6Gx.\4("菗A!q#MT$XPZDqKꕨAp@ALu"T$C\rC(rHE&,DB`r#Ir!qa|NS؆ 3;#RLS E,ՈAeCHs{` +! X":#I!PG0 GA2=rGA,wм . #":GDt_a)R (L" 3G I$` ~Y `rdzXHR&PmX!DtX+# 8:p YtB'.xfF8(r" Te},/ !(r r! [)nL,$? rC9AA9C ,tNL/c㳎Sj>GH"@ ϠmYK:(!dq@I<2D|C ";@C= X8i&]!-JI$GQSeb ) [AM$,HWJ(* 0VKtG:J8NK kldt  )(r(r A(qIAHR) $>ފ.-"c8A Ah"t8R-#ƘQAIz#tIFP͑B9hE64 fq$D!dt$BA Dt! .MP.-pgB!R#HRAsbDQds#0DtG}G!G@PHC 9%A2#8!1 BR)  #@&G@w8 8AqG"0VPvqlm3@r aaղAh C>=H莁 ,~(t/XDu )!sa":aXAjC H"( Dx'!G !A(BY,C#>A%bJLa 0G4PnPƒGq&Gpt+!Yq8A;B p\| tGˢ>AIDP$a) 8֧rޘB"CR? q4-8cLvGAAQ FGA`3l  tGqݔ8PQ=8A$(dX=6, t8␈i$n x;|!h((r D#,DZI|G8Y19BI x08YR8q#Ae@Tpʈdr!8">DDB#T2:#8h#1GV,f9yu Ð<3#82;d":rh<(rn6D48qAJ9őRqC<q|2<rDu2RGuEAC",#!ed(rC=l+(qń!r w!!eb97)**8Gqe>!A2lkP7B,Gɹ* 4.ȣrՔQ!1hXYDGԋ"ؘwcO{ 2 +Vlbͪ Dslb[# D":w)Zy0j][0 pd| A8V,d:tf(r&}X1#hn H[&#A[(p1! ˣS,GP|:hX|вE8>{ rCPt| MMBŔ"(q2 9 4t#F9CQ @AOC VP6g Cy79P`Efq" KM"M AkX@@` Ppa"  &I r !q&2:Qȃ;H.A4,&N"c`s(tBDdudGqA I H"A`D&?twC4 -( sSmCi8Aa RFV9!\ cdHe'412:#X`菈"(|Ï2;# 9!(q[&(tL@ 28qR#t5@1E@q Ia cGDpU/";H!1 QIȣ\p8T cBAq"PD|,  ,q&8 L!e`q8#a Vcû 8D~ 9`8, h NC U"| ;m VA@# "g Mő 2:a ,A A ICHq2($ Q9@YECT"!@ Ŧ!T N(`)NSHㄲ$PP*)P9!uD0; ܱ! Z"  ADe9CAH cIAi:Q( nD829" a x7[d3F9Lqa$B)0@F;#88 DP VrCGkLpT"B&8I"r(9Px Ad|q "FsR09aC)! 0 @HqH Qd$:Abc8Q!0q$ˊHv-(r~X-(DpV#C8l6+(|Z` r ,s,G ه8#HYB Hȣ91PGІg @!GcDr(!dpT/*0"C:A!"!GDGll9CbD09!e'S YC@XP CrB#r00I(8cpM9H/ ańDE0<p":Ñ!MQĂ e:L `rcAE8dxŹC\0@$zz]i(pCHsDHrC;BF 6 t4aV`&E)d6Hr #>G LCr>Pȸ%bs9!]A`r ␄, Dxi8A";x A^Ր99Cc8 ^I+#`sD L1GBA\p@lEM$P :Ph qrHȣ `r @,L(dwD} aG C=h!rY#8Ai hZJ{$9(ATDRpP":'Ap)0ʃDl GD)ȣP;@X@q!  &91IGRhFX>4a BPFqaH~ !PBKaB jqvLB@ARC Pš A'v))Aj 0"m c8y DvG2:#!qPIődtm6\XA p @D\t   B-2:P;!,4":#9dtG9J" XAp `rE0 @)#pA1Dt(z &IGpAA0 \r18qőŲ Lq!Im%D!HZH$8A[A GdpRrc91Dr 8H V ! q@ T @e P$ᵤ>"S#tN)A aʊXa"CcA #<dQdtGV-q  GDpeq0cADu!p@D(p!Gaa$MAaqȃGrr$:D r:H HArc3sAMSC"")4t B#BHR<8 QaHÔ :GrH((sB7P4 L!9r$?m -!iSDzI$"! Dw.8= #tmHQrE C PBi+#tBLiq{I#Q9c@&O8Ae8TAZL"ò`0@(q3#DBW#hR8A m8H +Y} @#+iܘ $0ePATXpdt St": C4sC(r&8 IA iCC9GA'A(i 9CG,BY8!XC  #DX!A E 9 C8 EHqpAzH)8$p,tGTvN̎Tw 8 Mq8 ;vQ$&g@lǓX;e؂.a$ N h # (|1R0D˨A tE4qtaf6)ˆA{DQC(rq!!#a1LQV,R(qH ˤ,bC/ H9C8YCD< @!R&9 ,Tx.c A;Ga2:#GA":?`"Le@DA1kp@(sq $0#, & I X@B(p@#8p˰@DE I#u0ePZb C`[V菄莬kLsErCAXr"GG@9ܧOgM„.ȣAR!B 89C8HD$Aal D|"!\44N BD(r ,p!9!aQ"cZ 95, $B"x㲇!h4.(> 7KD|- !a*fLHȣR0n"8$3i$lRA8hApAc8 @r(rnx),E^ EX %awH(|dBDZAeN-㋋# a!f IPq6.A &G@rAQ$PB @:0rc8 I4ϣAGArԂ# "lBBVh /F8pNqP$^0ApDE8"v`":9&V1𰵕bB#uh"!! :EB9A8AGќt )!`8M ED DBeLEHlB! C ";>XE#Ds#""\쎋) n@$eӠjchE,BPXKt&HI) -AXG,a,!&GAI) #@A8A0;0bl Dp#k B;#z DtjX'I@2sV C|2cF9ȣIAgq$("A E$#=B:!HYs#yrCSG$L& 4[FaXDt(s"0$=29PY8bp@E$+A Tp@ds,E~(qI 8XX0Td|$A(pVM H°<809p@4Prc@U"BX& L}P99CqH^eAdtÓc 8B # #BÎ";# T,DD <@VR8PCA!A&F8GQ&G@p`$CIH$*@"I@(@ PLKcP` -}S;9\ 9 (r ht ;)#(r1@h!"v E(qŐ=B#:C@$9!EÔ@EbE&9v ۰NG "GDp9Q8r DR.v` K`ACx"GF,0 ECBDYLJ)[ Y!Nn(#iNGb8l#r#G @ð#GaHXm㈆Ņt^sC~!!9CHhh 8 B>, EsN 98TA_B8@P8d84 X9% " ,at@*H 0ʆGDtGHAq9C w")z!8#8n"9܆ #DHI _h$ 8 @R(rl!sABF JA0YCAAtG#X"##CaYpq} XՅN #X!DA`$C,D 6(I9=H A8 I:L φCb t[AP L#V HBˁࠎ$H"- Š@8 L!dzQI$P#l8,"-R. V!q8@ ¤AtAh S8@U"m$*AUPQlDE&A@0"R^ faR 8 BB@{ DA!A@ B,!lq!`G(q4дU"*B 8Cˢ:eSN@툈84D9qN@ w0 9tX$ ka0GsPdÂDroɎ $B"ЊhX2c U H&pq hY#0M"8RApDzah(t#@s",0(q 39 -"0 "1Bb") Dp2PAQBoP"R9 pReACdHq݂&=D QEC< 㑎ArC#A3B 8B#Ti)Cqb\LCx6"BE̫A9|<G rQ|2Lj"."TA8Du dP85DȴPlGldr86ʈ682(r2EcP؈k82 x*,܀<of,Ycɸ< %8PqOw(qA efG@3CHFS&"ʌ6Y+EVފ eN9) Cm cfG8? endstream endobj 5 0 obj << /Type /Page /Parent 101 0 R /Resources 6 0 R /Contents 7 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 6 0 obj << /ProcSet [ /PDF /Text ] /Font << /F3 53 0 R /T9 516 0 R /T10 468 0 R /T12 252 0 R /T13 278 0 R /T14 399 0 R >> /ExtGState << /GS1 598 0 R >> /ColorSpace << /Cs5 54 0 R >> >> endobj 7 0 obj << /Length 13792 /Filter /FlateDecode >> stream HdWM ?bmZt(P=o~S IlqJ|ϧUReߖ.~}˧uk],h\(-c/[o߯߿s+GvzrU.)kqMJrG/mO)p'h_Ԓu31QYFΣ-om,-3X1HCte-$qsɉF\[;:  'T2!:sQzO[~E5hA%gTAr]Ar]:3(991Qb˕%a\2E!l/i<kHs}LDM#!vyԄq(( |̎d靎U2":KMS(W\ڨ8NAi8'}\+VoV'ixFF:#ӱntCL 08]ꬵ:i͢D:zm`M  d\`SAtM:3 Ne8[tبn[yqTq5=1Li6QӚ qx#): dZu9j3~)I)&%8 0c,<ИLIHH $B &Bs&31!Ú=qzcݰ6*6q*nf$HH}4L(UN  xsx-<sBc"3s"-O0x>gB=1b0˖h&8)lX=DuMk\9O@\(b@2:0mc5z4:cr#L@-X"D׬:kNZɴu--lwmU^^MY6†#mЩ t*C h 2HaVY**(IJY xdX<'m!: Q[VgB=&BLDIeBFPgn=(tfG PuN]& ڄ l 2 ;'>&oea\6U!l/i<k~gdOH}4Dz&tM5ꉐwBV[&Gv3|: n 6@T㕎gzx͚\4S)s M4uHʢaBȢkV\W'Yt2t(BNg2W&sdL'2^gImM|ne\V~)lE~ be/s-nI㾬"kxO;}"k,֍c4&JrDFlyywz8l,-3X125hGۈ=2+hi_S#hc =:G,NiLH)sZp#"=(0{D:J?#!: ѵ=GHsɉFHd;:  'T2!:YR%O-m`o0;Mt9aCt{2t(?,θ*qI.04 ܩXm.2'2ef\7yJ_+"]ɁcFz5`;Kº̴7LzV,bͼk}3~3<ݸC7)pXj^oruw$茧G8duGyl>Oη_,[>uj?}[N;?>||?g_]^uwߕ?__??}~Ylr^>e~-ؿ_ן=oCCzw:yácо ݡ@zwh$^PS/E @h '#-m0 tَ.wжr;+oDg 'gs g~2:^'d`f';u >T֒Z[KRQɗʓ@oz7h3ڸO>U 7c𩂆ђ**(Y<kHc,<'攎ܧ֢,Z]MgNJCx"~;!#w({} nwT&c{]{ ㏪!:|( uhʢaG V6ZĦ{qNH?`rQ.PqI.p&'S\>R_2rޯr0igٶ0.oeJf.m&g6`"Ad <uJVp*DHSI6 7HO:(u>rh|wpd#/'y8&lhpc}$Amtبn-eaɉ `cVa 0Ok@@D!0L%I8P2ElR4-3\< ] ]o-%aDpx0БZLdׄM QYO@"Q:с.-ܦ XuFgQn$3RwJj02],f8=t,`5{ չ>Rg2W[Rüv[LE>m4nUCTuzdv-Abp3ZRu/[&f>Qn|tP@^68m-ߗR{be_`#/5퇧6XEzAy'Yݭ%=,8l0A1lq6Q-A|o ZEKY+:JY;s]J80ځU%Rxv9tt٭v+ o@7^#!*Q*}k5Z<"!$?{ iFG8otRd:M=xvځͽ n CjO n12h&'1)yG2v`3]ss4GRȦ Qm{r~;W(-sǂ.]@:$fTYK-'L,(vI'rZ_C1MD|u凝xݽh˭|(Ktx:.g%ukhZ w]HrIP-Wc3=;>Ɛw̜PK缵֥}7}LW<R?}fF> vaGü8H+w1wd)vUIѯplˮ;@vcU42@f0I*[.y_/|{˷?~x]!w8${R|%ײ5]:lߺvuGcLg+#2-e.6=wyŒ⻤ЫkW t=d|3yd( t%͚A#)xE}B7z7kCF:Ȁ@჎rK}(;9ZB{J/L\2|2ȱy&;Z')ߣaM~$`kZm7,vB3C7=oZ+)3 T %oD+w!3!@dl#O;#u#%*S{k/Zi;P"%iML?(y~ڏZ|u_Cz\23~Uy4~Abj<, >sߑNep-OU p8M={iΑ ' >FC Ƞ Ĵwp8 =xvڏR]'m>uUl +E>TJ*eD@e$W;Cz,ǐz:$!ph=< ۉ z]~͍l ͹2K.X:^96dqwtpSqXS6 x;1dk*|"gy \P8#)*S*yk%Z8ؽH 2)ADO?y~ +sA Vݛ̟-~"di<0J>Gr4M9U w eCܿ-BTeG;h(1[:ܛ`-zyWH 'jO N&h&Ǽ ֢'2v`s]rUҼO\D;?k/|B6eEp }r3ALѥJ%4^<Dh!2@B M/G$.7(QfBSgh ?lJ]?-U(<3* ԖcOU21WJޤhq&GglvA `r@xp/ٺKpP.O|, 29AP⏏_rڟiJkKEJt謐<r1*D;w 589888N 1oAƳ]t[޽2(KPu٥[&_q[dx(XƝ컜Wrwz(dv3]+ZCrI'H~O/o?=o~?~xܤ&Խ>IcLm9}\]*eͦZmOҔ?ߟ5N&8&& MUo%-X :Wx3:@'d!zdpQ T0e[3)*@JJ'NC)' FD "'`Y~ +~%_D#rM5%ؖ-Pd̟xgi>{*\M'7ܾOom%4̐nգ.7Kq>Д:Eչ|TYtkfQ\k_4&y̑?$׿PSkmRP\lp|HHB[[&!&!8#:ͨu`ctŞ&2g݊ڬ6i \h;fD֞'`BvϲgZުյIu_k:{4 68>Yr$$b[U\&Łt[tzzƫǺcctŞ&2oݪڬ6 4vddFXKg*Ϗ<3w2](| 3]zOkʬ- HP9tRkY's=s-ol*% Fucxō}[8}Dг#+nt "'`BuCxşdǑWDῢU)m pԍ>US; ` "Ak,hT:V!_*)$%1!_X?I̡ rv%NʼnB<038> w8*EzmirphN|Ӹ Bt8 6UѵYtm3ȞxXwl.Ө9ݪڬ6 dh뎍]WӴ? t\/ Z~ô lj,؁B2%8M5V163Tp˶fRtZdG|dN2ϴޖNhD#uExştn.9ugrW7 H {T]2Y>K۲Kn.q!"A/IZrVӵsr606IAL'dNuCx?.>VPFV+7OL(AL'dO/F6O?^ܡ]7s FS{k7u݁ẠytA}ڎs[I"Ńt(eCp=p ~#ݷ5_@rؐ.{֥tmɴ;م\T8푿à2 \P_Fbj|6i)P_op-a2e} 7"T=):H^"Gt>;Qt O Kr]{l/*r'B.NDA~U2p8ʓ(| d dGG@@AD!.H=e! p :Tp*H!?>ן2&Iv"$E I6N!AD`!Q;Tg5+3ZުյIu/ߑt; EL%m>WYr"D*͊kMS!8#:ͨM{DHG~6MzCFzDǫQzSWAEX]oW{m&әoW{v*F/p4BnBBdA!%0MrLe$[ "`P낇B;~=N=pAD/?Z'<2m90xS%DRRo6'J ݂ CHLv,YdP(%:bXj_ ňGxf~1b}Є»fBrж.gK9 !{>i O:L!!O7|F f|[6'Jud|aПjIA?eᤒl5NhIYI~JVIp?k(/qr|ґFpʼn.x8髾"ExmixpM> ouG>: *6KM鲸♀hE`~f24DF'^6kMZQgw'2#:쉌W:1b:w=ߞp\S97Ooi~Uiõ<L@+:e7&8Mdkcnf$zlB ClGx)~'Rjϗiʎ{6xZB JOB??c0%OkP +| PA˓R<""/2*W8؝^W' D,p3JFFЪCNC>RNMIk7k93=i7'vs6z1j9A8vq5ҷT]j%c2x4\m:u;d 8ё-vi*NN˦ Ʀrۼ* ZW6H}qC-/mhۍ!vI@L-Ks:/MDo0PsC UV]SDsУ.` 7j~/~hʔ>Fu8I UY7N_ɗ㷽7뽅fZoiķѴ%@{ ^hO _͠k M|4УÂo荍da7sNBj XtC##2h&!]]8-`] ;Uc's*gT6;^JT@VY2w_2V0B Ȟvf5=%;kR| W:H/zE'=Ql (, z4աa0lTnWewnћnIœQk h'Yg.ȰE cІ5 0#P.UMii)z)9S %r#` o$?W=ztj N1ֈGg]d Uso8^;0u^e4mV,ѫ2_'o҅ E\iGzЁhnCXl]z{f52X2RmnP2L ]]8 x;d{i1C[e+_Ru;o fjOme,cWe,K|ښzIar|\9>) }0߱>'ʠQVÃ~rlZDn4]H}8OC?O>Qm! /@咁@eYhF!H "2F(<vX)8RX)ıAh;NHE5J*kB,QW5aT*uVi8*q&W%5" %8V:g6U(D 9*5RXK)]LJ";dM }N (|pth !du_#B~蓯o+4+Mе'9E"@oT'<[qDlQ@EnK#LTX1טƂ ]@:oL$x;4iys<}tF@o3P:K}ZTA7Hig{Y Vi Dp_DU/ R?>s?/x;f>{=3O@a.q9E2q(/7BOSS!L->Dڐ߾vΗݦ%ϠS9 _ d!elAO5dk"+厈@ k(>Q8l?ltp;t\NJuG2t;Yfӗb肤O"C{h\|[+։(R#ukLXĦ=PF#B ǽ1mG^ʡ# p;}zz >n/s/ s0Ѻ?k&D~dqM`z*0Y#+bK-)Śjb.a鸴Id{,-fCO\C)qR{%׈m)|?W; YE %?X̙M-vܾcFN5c|fT>D1nlʱ>O4Bj{,g좆uАŽܤǗ_Tm( t 誋&]t!l9IiX/>9ykO .(``,co`KQ f4T2ÆM͚y$G7;OHUK$v sBRSX:ΏPmx07$C3<4gR|0HlsՁ`~GeM t (N UFLSi1s6Hsbgh!G@YY,1PڗTIۜ0KKtWдIt_רj␾[3]ݯ((aPP]Ah'镡hX\%<j$yGxԆqJh-u Y-7ηQފ~+v,9$40m)ٙSD4wF-S‚@{M7sh0sg.=k3);_D|@HPn B qwdTx ,durnu*mn;!qGVLkݎ Dr!a(KT@ F+q3-bb~NTٌĕ@ĞU*b 6>[}/./,.•ÞR@Im ƈ22ҟ||̛3۞cMwJ"O$ kI(.U!/ &p&!\#pvN In̢mHmg!RUBH;A o<=:7z rʈtt71#O3%;^ni*ꎕ.Fʽ xNbvѧHZB bEz^;G_uJplU^uYxiBYI蛑cS wt4PQ[;!Cr!Bz5j~' kZ}oi_GJ.n*lM@!2W<,7%z0rݤZUKrr 0ȑ_-ϒn~q WgZUK-껢32uiC Yf0y`V. >&ЃyY6A?]@FGN@1]י/Ci{5}ViJNOB)Alls3:{ƌꔧ(~o @ #yMPs;֑ }!I۟LLxAVy+̵8˗" m#4dNwƊ?*лh刴 IȻ=6ĩY{K]hB2j0;G1YBn1gW< $l~zK%|kDD^!,#aښ9f7!~~f1ߙwy =n70S;q肩 )8R# =a(-a5S~Gvi8zʕBPdpwhq̫#ӞOxAGɷ9l$XnYhJD &u-nZ>;0`:빍U'$%mXJޒ/ ]vbVlP&Ȥ4kݗ~%'!Dh'+Yt5Us| endstream endobj 8 0 obj << /Type /Page /Parent 101 0 R /Resources 9 0 R /Contents 10 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 9 0 obj << /ProcSet [ /PDF /Text /ImageB ] /Font << /T5 55 0 R /T9 516 0 R /T10 468 0 R /T11 488 0 R /T12 252 0 R /T13 278 0 R /T14 399 0 R /T15 379 0 R >> /XObject << /Im1 595 0 R >> /ExtGState << /GS1 598 0 R >> >> endobj 10 0 obj << /Length 5755 /Filter /FlateDecode >> stream H|WY~#0;y9PT5E<,ǿ>u4q``LQ]W_ݯ^UV*)T"ΒbWU>^֧s[w+fpw1^_4lua`NeK,TP50~Ư(vy7Sm>R:;T"~e3`&t~NƪJмxvi[Q{79u}=/bcG w:r sMa=Vox`(N2wGHٕk8؝Ү®tO˺wأŎeVr@=>Aj~L3쫤Q5;õlD z_ z&B$ƺG6Y_BTy 9wloD҂WÅ[T?NSoD]}(c/t^ Hj#^s@(Ii3F x`@ݵ^p`\E'rnuӠRVm(R~D{{⸡ΛHIJ@ HIov4ck}B *d-aEqo%Nyf^"ej+ψ-Qaºx#ӈѡt:,ueS.(2CcfPϩ"۟*IE\ѰplƉz .?qGz ›Q5/`Be)F7P7=PNjPN{ @SbNݓ qEqo$pDA9+R#/Ej#_%hXbZ˜G r@_XKid5x/1>ޘmS!` hf#bl?Δgdf؜P_^ڟƽq+"Yg6Gcrd7I 5M=doT\ϒ ?-!d=׏ʥjls'\,tz isSZ+a7UGm-N|s>4PS|SLOeRH{eRdcC ,<kTJG>IIyvcaߍ'glzJdsVARؑuOgu (»ey r|\F7s$ṕ[gJ;Zc3Loո 1ϡs?g .NP=Y|KAg* "X'(U~O+LI1ɣg9}$:EH=b9=UIr"o"/X\a EAGQחAL)rT t q4Q_>Ʈ_2a YE;H}[o4;Jh\w̘Ľ}..X#߻>mn)G |a;J$|0݁9V|ﶯN2 ura00X҅^d'Fr=YD3t+u8,1#Ć_˫h,n~}ĞEO4riCf>]i-54tE߹z@H(_d,Jt8O(Ϥ+^sm|7.pR!?,X8-)"2oX 56^1c[p`wY!c (;M%նYBOŋ9o N'62J 0r`tOUu_5Fu+ t]*dQ:eW>~C;/ t.S?ZQbCL 7Le)j|zv CBVĪU{C^* TyvOU$=}G=N"e4f' -o,dZa Mp]S=}AɇVaz17.8rXq6i0nAA.<4 2a,02θKSˤ\`/%B)a뾠$6W1̞Ypڌgb$0+o8fkx6Tl6ܘ Ϲ2/= /a1Sap9pwy:!أ[t<4"0Plg>#)9][F`T͏N<(>n všp W 1u A#.׿]n/8 7:v]˳opXim( bhcf*l>YmuB(U8rDsI&)=d 5-QTD3_hvs1d]{syLx8"/߃0K}A6IF|m+Wn _7EWI]a@-uc\}A!.@u.M׎`1A³`m[C6 qؘejIil (GQf́ދC\T>N ykGI4{7N T>PBM@:wlB{(}0{ hC q ?~>~go+0A]`š{EJ 6}#.[8^;{dzOCx~]bfi/U׾\-NYl5cbM-XDfZ=;*՚W6ӭ)l&[yb@hۏ*e$s5rVK ٸGV셁RqqY*6ĺx1LFQnޣ|HV9,Q6[粩rn ]tQl3q eU)s ]i ȜVh!W>Ѷ#ԯ? YZ#B+ݹ=J5_.[nq﹍,,N_ZczҴ ` +{ۋŲ68i((5纯hhE:fzQH8/.J S0~_;|JJv*:_q~&շ=]]H]\i F<.t q k脽ynys_WQ݋*{ҁ:Ol׈]ohN.Tmg7D aJkG6g!BGX\E'?3+ 栒) 9uMiCz".Cmɇn|=[B OmViMz:EJvV㒲<# WME3Ws/{FT%ǐQIsa+_xV'ڟ\E7ye h2HV9lë<M`&&%O}u2s-2~rͥM@_MDMS'1: p޷$*ga0Z@Z 4t f.I@m=שȬ<䆻76@NP#,C|5VPokGvSXnV\,N~>9~*~͖yWWedҴ*84 ܚB.Ҏx^ͤ~]{^MrdqM"gYM:B%u3X:++>i6CUX&`hXh3scy"0; !*xh\YxF~/ pDKW^^.`Zr΂WG*p]Պk'5['f&y, H(hE ,ID+C._EDכDVĨ$$SnVP3AbbOf+k&HmIFYz7U-e؝\`? }njd*{٠S 3StpǹeV&D1UF]M! }Rt?+`˜҆ZXV\&Xѡ* -V,-/$C#{8H\U>a Ծ:ǁ4.⣭ BsW%ڔz͠GCR4<8VjJK9(^bJ;hWxT\߱lxZsRe&\o89Ġm:>̲ 3 AHgg&8waKUC;j:6H 1DdXU)8blU_@$% Ǻl38^)˞զoW_"C~4~ >RN !-oqm}~5Hɐ>%nsuu/o܎.zFQr{j_'_M̄'6?L}qmY+ÔarU|/810oŔJ؝#9ߖU~ uO הry0}J}ϲX^0sz&1Nhق* H//I3\ҾC f7_4eIgi*)4MKҌuǷ5ܾi 3!)pȟ/k*gcw7r7`>PL9DG7xWWi橞c*TtU‡tW7kzDMqdΤtŔfnQW=9dm97sE7E*D]v[u)zT͝ڳ{[}DFI}3xeDf$A33  ubzA앆5qF)s0%`.ϕ&DَCvȝTn.@cNۥcXc%{g=˞k14)^ I ':RH0}_?[$ endstream endobj 11 0 obj << /Type /Page /Parent 101 0 R /Resources 12 0 R /Contents 13 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 12 0 obj << /ProcSet [ /PDF /Text ] /Font << /F2 52 0 R /T4 56 0 R /T9 516 0 R /T10 468 0 R /T11 488 0 R /T13 278 0 R /T14 399 0 R >> /ExtGState << /GS1 598 0 R >> >> endobj 13 0 obj << /Length 8627 /Filter /FlateDecode >> stream HW;e {w>>+ 6<oU>&[")X?(~ߟ>%oq_u|I|~,3塟eUH 3TVe%c[ٙF/Lֶ4T Y%嵾Δ4UhxxųVK}k-Su44$Yz-̯[+PzG4My2Jjy~$$i"ŵz* hC3h%%::!YPKG$҂c) `XV׺,+░pAz'("4Z=%ՒFH5bhZ=jgX%7-9ut7W6,Τe26AZeD%p Gq A6ˁ62<*'/GཹXZʔڂI+rRY \w\.\j?Y5AΊ"O7L/ƨŵ`SVk=+<"]`2 'CrO, :C g1`sL/as#d!z| L r[rr&G85`r]?-}^ bZ&2 D*e[:t`ojEz&2W$4E6m"q+W&bЗ;?f* xwKo0sPKW\oҁ;Ŋj5N|d0ViN1/fޣC R!*HAytۭ t:6؀ĺ/7p3-f8y3tDs\y /l /`,uԀzE( :x7p(aEg3 >@{ҪW \7 b]b`s; 6h@Q^+W6ʎiUwVlާI"{|  ;NE.q8aSI㳋 rcnx -="qF),m]pZAUtC}ZnPxƀVA28ka@? 2.V\h83 6>> 6_[wm`̝\FK` rk gUAWyj1dbʴNUdko] p|SqqAתB)hsH Ż\\Jin/{?≢7IK\ue(eSd=Nja#p/vq{*Nr 1#G7AχgqܭusŲqoB}֗k0-|gYOkL~hH }UL ŷ-M1|d ҌM5u돂3 K\> JbS?@@Emkx' ?RڿN9K>: luYΙwZ`!B>! 'KB#+D-\*U6+.al[ jpqڡ_~8x2:on5*1"1xtaem\ļEqa5þ^R(}_k|կ蝄0HSKXBpf q;PTNb-#;(W<(\".ÑL fL^-3V _}g)1әAA3ZB,T _'G'L.ř\VvDק:^Zq3Vd!ޫfr*,s&,PP< IC9^Nlw\/(h+ytox8۲ᙃXdѹ"#J2n֗1ʗ xĄ;H9aSlQYswIo3Zx7 +Q򌡰.SfIep3Z93;ŘI?tihuE7\5CИޭ1ԠO1b-~:{|.H<8 }?!Z{>4ԜmQV([P?fWR0ȒJwQæ3Zg蔽-K|gZn-`K.Z@]\<~y)fտq1k R(<#ƾvjF34AU((,W7#0d,4OsgNC+hݽ* }[3E:8}ZtKD8ߙgAQ[\x^Es8kE7eq ~6hd-q z s=eBO|`@QЃ=4as=eN[t s3ZbHb34)`T.lLB;y8%18ri\ 1d5ű9gO>g[u܆ۻmC~m,$PXHxT`:aC P~jٕ+^: gΑt K AlSŇn˦("UB-刣ذ.EV%VcNn6y \r\WbzًRBJq٧S1,h@0PN|bZo,Ըr`hZkV"3$Dc!a:dW*uxr@?([[S.r)p#ۭ<ȢD C˫x'D1VNjzq=D|}*~xw+7뙂歁w`QqTU&(.80\Pa7vxwLb뽡Fu(vy{[y1_mHav=>*8|.z~KT[ * ʼ8[R$?^>aѰ NAF 'g*q7n@ĊsҀNj2%C( xB\FLH*ء_$B" 4ìE b(]85S'0|o$H ;+y@R(`rozQhEQE` `JD=i! H 00E3D8Zk*{0N;%YevmN@KEԞfC,^EyVSq]6 `Y%NW5 Dm8ݐЮ=y) WRi̼c{d0eV8Uemҟ*5X0ɢ `En,+!+8`U ґPG ێyiYw8<^Hmqy ZWHpqz晴#k(QF ͱ?2 =wGQޞdՑGH(9Z[L:( f-x x8fK:EVV1ks/deysv yfi؀OuH<H `&7~Eӭe%v(P C+hi8V><i8Xv>iv#6 zq&U[rܺr9YVelmH?^xEW7L.iZ4qՒe0Yl'Hq܂VjV~>o͸Q_6B+.QqBU%%@˺j k*Խ٣ 5>->nA >YPnt8fI,*(jx`<u mn.aA1s)!AqTpIz~ROUo> PWUr*wP-U]&HC-Y`vPI. 4SRZ7>o6,|6!!A.%ol#)vT._ytR-\rBqo>aBzDd2E͐%]m[jiH1<`,p,^J/{2pCtHJ6ǩuMF8hsxu1>Gǣ^H2Ir4]N ) TLCEɎΤ`){| L@ -uYʩ(ʐ))9Gh z4yNT2-BՎ8sYby㼝$r;q*VI@'VFYGx Zڵ$Zz`x\EAyuKڋ?^jo;>ۇ5HT f5GcX}a4#K:͂W? yn];Cɇl^ٹ7ߛEUSR!,[N=~jpl aK7hqprf\0N -,ZWX>[xRnCr$ mⰘjw_+=tvCF[i!W1rttpdi%8"Y`Iu9(:&y'HI -NL?s]?'ncر-YyC;sP5;<YN[LT:US-\4K Exa JB2٧نy]P`5FD*X^U>Io3u[a?xR@P1MS[G6kxJxy<_ RKExsGgJ#3(p(HNE@' ۫%U](*8f-5~)Hx?B瓺t~xNz~く'G\>*_՟DO_]~㸿>nr,2 ;/Wߏ6!зP:II%6y Dlmѕ7p(R!RfӠX1g 0A ٙ^Qv?K&''ؓ jd_@rmH`}j?=e=#B8龛 ޜٷ4瘀"ҽW˦gzkdg-Y۰Q{2#?u7g[0e f 3$@Y^av&sʽooV0L&na{@{NM> ܆}{2uDGZ_azs^ {Jq:Ba26QrP'uעrS/$=YpB[V UT@Tdh~"Jч/L1qG_E mƱ! KTlqQqojIΛ?PW.lOAh^|z,ed\5 78GwjPgHpI<f|Uv0wٚb3G4r*qPsEow:Xw08 cmXqO=y8~fSofYQ E &mgjo.տaGqOBGz:V0YU}>s5Sqo4{Uy@zS#HO)`|U0™\Pؼܸ0; j!nͨF`XxdBT#*P@ ERx QFl,As:F$nwzD,Kngc DiwTOEco('~wA!2Ƕ}!xCţmn) i0Ζ]; c<+^}8kN kZjaܹFl:i{0|zcu_o p6rkH)گӪ^PT^(FN(]o0*e҈,8{p).d~G5[ͦ-F Ņ㣆Ge.ă6gBJzeپj#RK a'sЄmROqmfNY٣2nG똨y.l/8 f7@rfG}ZD{;>. 2Qu)(dh'>}#V5FW&t&tX6/eؒ|lXԦj[vS ytqx ۦBT?GxAXa~yJqI)Lm)bp)Чi}" z#zN&Y$j?ސ/|EdRNE޽~< *XǨfƠ z@Y:EF6Bx@: ['z'//zg_^``,?D%SXae6v$,tocg@_FBE C.Zx|JۺE!&26dCkwzYOFB@=ч9U tgPٲ B$#&_gau"F뀱Iy`q~>J2a|Uҋޱt$X ]mb-Pb{ I\TqvC(t_XIW A۽nk?e`HDLٿLdz?ƠY_ U.5ͼx*~YZ& D?qzB߬SϺɸ&&0A~J! 뎇N@4rTuT}IjQw'LuOX !UM<#kN}Тe>Z_CX.'0Lwuj .rW3?t`K/j)qAa!cSyd$*IB$ IփsnjtMWlKk=T@z=@]qL8]_1̍C!>Fo $_07WЯgw3Q[Ҵ %em JF9MǓJt'lԔ#=C;ɑеp"Û5ws~#%$0S8@n q8qdzwŭAwo ɥJ \D]uf1%ٰ[j߁g_֜ަ <6FDy@}zCM [ᤆZzhDd Р0dtىL)e~a3UqaA8 7}H8αh> endobj 15 0 obj << /ProcSet [ /PDF /Text /ImageB ] /Font << /T3 57 0 R /T4 56 0 R /T9 516 0 R /T10 468 0 R /T11 488 0 R /T12 252 0 R /T13 278 0 R /T14 399 0 R /T15 379 0 R >> /XObject << /Im1 595 0 R >> /ExtGState << /GS1 598 0 R >> >> endobj 16 0 obj << /Length 5936 /Filter /FlateDecode >> stream HW]ۺ۠/E%dI}&7wQ M[@jZ[-Cΐ")y{ X9Μ9svun[%ި_,/X*Z}[z.\}b+Q1icUtR, c͵ŏ_܍1WE,Rv|qc^%μu.@? nsyp1n'xW|p#+oq.Olo_4]8UWclS[Y6þj¯nni8H+ZJ>X߽9x}Rl|7a:xd`CWM{QiC5TUFZk[vcsM}h@4l(GykqYy8j jy8 ,[o]pw`[5< ?`[Cl**K1>;{Kh[i(9~$\;:tC}$xGcӺ8<@!"COP&CJD 93@}H9 *אF#Bfz$xpW6'&>1f7YV\F$%\Z% 1H})QVwBQ ts:xU ekő}VͷkA 2 ]\:jȮk ]WO=*}FGAPAB¿U,uW|"$0G*'`F~БOW1|H)<]W,ۨgFUZ !"ڹ8WҚv_CcW,%Srؓ"Hm3"BQ%Z%Dz8+LgnHKRfsUYtiQ@8|m&ԴZ3τ P!` < !A~/]^ȩCTM=P/2mp(Hm zG,%Gs`NK ne(/^|vu]b.R.  =g[Lst2sTZ&kWc/1噸 f}4O<(ɔlR22eodJԖ8U2Γ5K)w,9SOr`ˊ#$t:ԛrFB0P*D>W gVnmX.n-9G!JF(KZBed׽iz*cnQXy 98H%;sl<\GXQt%=SHmƜ ~*:uJS_@W,2nFM|'B+ӛFzك- LjݏH1sD܈/VA)t3- 1Hpا|NPH>x Adpֶo$<ľ s5v]kD*TǬЃbe|PנUp^pXPk^҇zL̙#@I0J͡R@Br4n,B^@gY5 ߰*2 ##%އ &TR[}yFp1$?bET=٭+N \m\zSכI-.o ?L0ڽfK H[@ß+|ά.!Ҡ3&ϜʮPK͏i츥M]I&Sz4?UVt"Q]s V[^Qcg}gNkISKlA}P FjO dD3- [J $nF‹hv3R=x4E+E6"NDlPWOxag.|ԩ FbuցPv̋A R*͵z`"9 ;._I5:=NcQ܅fNYB铹ܶ`b Wi :+혐xiuVk0E]"rJe݌TMQjX"1;]KP7 *#b1.Yw+ MXE<խiB[#I G/7nsA)iOSQO+>++TRzGd> t7nʾxD@H UK $%Yw fݼLfjF׳,u$(bκGSQFI[jj/>6Lo@ǝ9]24k \%Iz\ù&S -S`*]8 zc;8rhF;_}:>ǣfOhiJ\}sOo&Mr|VFiY$h֑01W(lk1ƶ6,),}J~,TJ9;ŠC #e$=N4WsƩqޡ60PfLp7Zb}PY$? Bq4pB#YŰZB]MM}eyM0"+7HMIAWIDe!D);NhljdLWĺkk̓.\]vgԽ r 6ETd&'v9Cx#{͓́z|( RC<8li >"ᗖ=j 3k,lEOBNHQiePư擌K|Mб%Z)z`9g<<%DѷG3 ܁ޫfYS(iuz`\%e)x$خ>B#5^Yx@2D\.;#JPP$E$6" Ǣ6LXI,-hG~z-x/pqW)bY#ln>Xb8Ƹpv<᩷TNWomK2,Jwn1!b_O$._;S[M,qo<[me[|G_|nG?z9Pe.J$NHXj^41:ߡn0= hǤ`GtnY6u!5JC߄!s+'>_g̙s* /2ۑB֨T:n]r>(2-`wjyLZ5hSRyUrEI*JGi OJ _Û(;3CsL-5\J޿^x-~ VGq1$ .wK0z._JP-k @#߶,ϝ-rJ8Qe02c <<,Bs,p=)_K$K5L[e8I)VZs Yq7$KZαbA I: X W5j!dLݶ |EvWL | ]V`6п`6܏WWZn23ӫ2=Hfz?nUn!8>'g#c~2ri7 M3 7, )/lUw-SS_ͺҖ olOl(v*eL,U?wiͲ†bjQ$6o@tFJ*9h38_0U=)$U{&iQqw"S=:4ɍlPjjj| c]84,v1٣IR+O,܇G " =١Ȱ_f5j̙Ps ͘ca- 0:tM2_%}` ].('a.;*kB:'L"T汧&qKYgNE8{1a;:u!9ᑄ-ޖ~mCT ML4SnDZ Өϳr.Or]Y^OIR|S[uU`,ɺu۵NUh!> endobj 18 0 obj << /ProcSet [ /PDF /Text /ImageB ] /Font << /F4 58 0 R /T3 57 0 R /T9 516 0 R /T10 468 0 R /T11 488 0 R /T13 278 0 R /T14 399 0 R >> /XObject << /Im1 595 0 R >> /ExtGState << /GS1 598 0 R >> /ColorSpace << /Cs5 54 0 R >> >> endobj 19 0 obj << /Length 4615 /Filter /FlateDecode >> stream HWK WIYtelʛʮf#qFH☢<ͦf*5|߾ݧO*V?~y딫k՟ezO~TKraj-tO7pei5ֆqxT_D$W`6ʴZ(UR^ҠU+Et"} 8!BIDkDeoIFibE)e?nLL哜 oJ؄:Q Ztwk1g|S'mKl=>u=OEJJH-^亖{pdH[Dzt{L_3Uˁ a}7-M;ƶ_D:.eex9xHK UF@'̃m); ۬<ʧzL3<}rOg9@5 X%!HLG`#p`6^dCkM)сu܆]#C3,U\C n0[v(4MVOd##DHZJc&> rnEdg$>N'ʵڋb,2$dY&dO폪 HdPH0i>Wpx@}QDyWeswS7?Q7Dw_f| g3.V +Y{>8r#'}7wq88d5@S$CJD7R!lDsx;k_~\A0h,|n9sRha5i44LGb# *\6hr= $}Xs|a>  Ae2^=99tp~Є>tk R\x>9ex?wùP{{GYVc9pXh4M@7p1&%Sކ%lߡ{S2PJ`Q㾝aX\-pGq fE3/y' :0A 9] *i;#5<>]4HU+ӒTe3Ipg/H$óBH 4^W64hg?P^-Cv® VX[a,S5?:~B@!r_ ',eBeiTq]y+n-d$RAS]h_$2 ݘz;e_6)x$Qzi7'+33[,E~NL:>$[sm JrGLd]FxiHmtUPwʪqS V^(L5xjSi>GN<{bT/X)MT81,+R_[?ݑ2 QRi SoGs |<"y" Cߑ9.]k6fUikg$a}3;Fl]N%`ת|:pb\"y0EH0Aq|+![˜Y9zJg3V%!hP ʬ*Hq^bc:mtlb' B)I HFڭ)~NS&'ܖCϋ7q5$SSaOH؝ l,+czTNR:oMe95@O 4$sR0Ha#1LEx29RTdJ2 B_$v ;j眫̶>PJOztN-TI (NOg`Q[R87H:(ZՃcQ7Fqf qpv%Je?I/Kf `1-DxR ǽtu}XĀ _E)܉`/$g(/XM^TB{jN\g-A ~OęA2hZZHs 9RCU;^jw3|D Qn`~Y8 WL 7շ\z)tnXĆG |hW͡~Z=,2mYU_{Rk}wT_9DtpA?[~Bv&,YUk%QjW$3I'Aٙk>A.s"9ud@s6$b9˗9[C/{n0 _3Uf3F; 2JZX~aSSF8otsr|GluLѬ (7;18瘆|m0 H,@Q板.W82~lpxr9C(9ImU_RZ&()_ ғJo/,Zdq nr08&y9u#-=CS(5&;(KQך /Z./!0]|OYE (j ~yز,D^L2ޯQ^,ֵhe.S7f= >-M R[mW&!Ni\-ˑ YGsr%^ۀeE oМoOQg0TɄ<ǵ0#uUn?ۓܓk@Vd4Y(aVvvǕVkY[}`lF#&[чxr.Uq|Gdwl@0kTYz5} [pI&eyVLg41PTjAQbG}GL7g{ޠu@]5v 괴4]nùT 4gjX>]UҾ# Xd-!iQ¾_W_gJXArT鍄".n$[1s=(~YU/n&YMy,zD>|L0m_kH%Mp*W$` endstream endobj 20 0 obj << /Type /Page /Parent 101 0 R /Resources 21 0 R /Contents 22 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 21 0 obj << /ProcSet [ /PDF /Text /ImageB ] /Font << /T1 59 0 R /T2 60 0 R /T3 57 0 R /T4 56 0 R /T5 55 0 R /T9 516 0 R /T10 468 0 R /T11 488 0 R /T13 278 0 R /T14 399 0 R /T15 379 0 R >> /XObject << /Im1 595 0 R >> /ExtGState << /GS1 598 0 R >> >> endobj 22 0 obj << /Length 5717 /Filter /FlateDecode >> stream HW[ Ȩhft] Mk +ȶZY:䜤3mH乐#nn'XNp+2aUr6_py^by{w,Kٕ? EdOs(bc%䭪؆a(xKi/ۦFo4awC((' 88nHX doj"wZ %RXql.r+w)φVrx t%^F:gQװ:Ů62Zo$s3"/CMb-KS* 8wuۃ{Fӻ`hWЯ%g<߆ユJ$.f0 `a=o ˍR%ϻŗŘNQRn6ŻW]fOimo :rFf֩{vene+kgčJH{ÕSDN>]3z^A{/(4@+2oBWZFI&II&1dNRZyԁhl?/̓gh|!=Wrr^Ŋo+~EҲ`8 -=c=ص*"m_9Ӆ~ ݭ,: WkD+hʁơ[W(qh)h,UchRenV[guoWk{YÅ\;W ?ѣ"j:ȼTI?Ӎz=B>,`Ҷ*?JvK.7c#?/4N"f"9dR>?JL!%(Q.Zw7"_^wZ "$[7*/MlD^ڻ}VȢ+ 5g ɠCc+ دpk*7xByK T0p܅Fd:,R|iVn$!7C36G" k2R4g<X",T 1!Vk*sbhz& #1n;u%tc=tKͦ.u N5bn)qIËt`Hk}1 Z#ju>J@Af{t ]=)y@Fy F|Z՘#5#Fg#("oI !ʣA깑==z E(6}Tv;3sүXSxp" E"<7C=4GK;>;uH S%z,5o&D"A(Nd̍M%QbQѹvOcێ= >(U 5EP`VB. MۊWDTB0;TeyJ>d]ˡ: r{!m:\6"\x@}=Sa{%R^˵IDT's+H&ĥ?C*8EX! $AMd.ęӑVF4eg0n5 )KBTumN>|6o*k=|'+摩,h]o(2di@I<=X#19-()g5h=(HcELb 'en;BB+ܴ>U+Çg4>6l m* ҝ=9ND#eZd*p4Rav ^rdsQ)rMDs"u2Զylgv3Z^eU2qj^}5(\E(mBSmiFj#3p[=Ty\2`SfSp#bɯBG <*߬W[sܶoLm6i%d&rVj!W( Weo:@TrcgwfO^Zb898?|[59ى[~C48(\\V7!cl]í\\c 7Eѓi|;lh'c/J| E@ iݱjPG`$11zEzĜNԨ7~OJd;$vF 8MIU&5WVS WrCfCPc4/̜ &v9w}Ĉ[ _ ?QEc(A  JO@jk-!W.j3Tl]l]gumAdz>dՖ Tu?s[>1w (K X7&HMʂ/ Q¯~5jC*Fb}s?cİUJ.#5y͵ (PY-".B2(Q+C_EW 7LTUyTjQfi ZF?GAizOLn&4z̫y/06IeP-.![ZS/^*lܝ~>!FNLd=7G:'~WԼ VUA- >#9{MHyNB祏eEpKWW9鰹F vkhv*B^3J<-PMB`O{-V3[:wlܬLƞw*BV2ƨ &`5UE2 FiZ>e"s G5["5 5"+d_\w-r?_PdW\Ze/k-Wvi~ S雬0Vyr0_?ۻWoq.ҽ竏yϪ &]JY>ۆhoFKt3/Uca%.σ}HɰdŹzfa\ #]> endobj 24 0 obj << /ProcSet [ /PDF /Text /ImageB ] /Font << /T1 59 0 R /T2 60 0 R /T3 57 0 R /T4 56 0 R /T5 55 0 R /T9 516 0 R /T10 468 0 R /T11 488 0 R /T13 278 0 R /T14 399 0 R /T15 379 0 R >> /XObject << /Im1 595 0 R >> /ExtGState << /GS1 598 0 R >> >> endobj 25 0 obj << /Length 5562 /Filter /FlateDecode >> stream HWߏv79S>B,N[!Hj(r.EI%R&;}gwv%e@Nܟ|39pE<Kyt>no|u.0 ],iz|ۺYwOy;"&Xb;L8l z3.J!!Y+[[_)4V$ ݷ1w0*^=bIjqn5[ %:4(yg W432* ` ^Dx,eR H$ln[ؽ7CR,dL)X{u5Kjx)œ^U@1"շY$κL,f >6 D-CU!M|^Q#)'48jz8M%O q͒r0D7i['= #~TϒpԧrOxSפZ  ؽwb7!v>qbgL!L`BcRO]6aI#u%V`}9I(DꢠOiJ\eܻ߮\_j#\. K*8=s* MVG2U~\tB WJ=ğd23V1!.5@؈Gtj&G;\aWqr㜆) Rs~/P/#p_5-hS),O'@L]̢d ?j#JY,fCLY'")G0N ڣaa:>dwBlW u@G L~"WYz>xWpۡXD`1# կ70fl^J k9榺5r֔*[--PM"vEq_vrAEmDauc:U@EʢùQ=qt~f_IdT .H_Pjjn}C!%GTQb4cVD{(/N 'Xƫl:s%C˹N pɹ9H1搝NeӬPQ7gR\zUR]Ą=ט%Bs^ꉌj coK(v}'%GE-T>/$Ԟ UkefWYRwp*?vxa)_H@4s ;4O: >.ߓx@޻ؾz19 =3˟ǸML[\z \jrÑMx\YTG4(} OPA`mPdH)B2E=R $H44D)9.vd[( 1܈%ȄH.et'w&Tw.; d8J_͠dDXѤzV' 1=-jnf[>A})pSꈙPQzz'/㐯.8pCƫ>.^k1^r:k XN5ؽcU2bTq=jз '<'8;Vl3ٍsbw0軀A4زz&{UlC(Nk(1M͇ue]9eP_.dؿ\Nir1S~{=ͤSЄF^# __L.3rRH-$]ݪYRw]VV7ʉKAA8,iH͠LtH鱤)A.΃MɒiqsZ4OጏF͔%!LG<73dDT%Kɠ$U(G#)~/hŤL^&>ץkۀwH/;=阏6rI|WEldkWT}MɣSPا 8HX K# b\bSH*+ri.HAȥ!.qFLmc tNYNfMjlb4t8FP>FP6R`wFS5aO4.)vFN5ptԾ}6 O&ґǞ3:c)eij5xH1]TFѨMK5ny"ҲkM[qڮ̿gʁ*MR SA--ڍuP I(x#3C`Uy1#nn(Y"-Bz6;%sSW1HGu|J{ HAw2loa<$ɡ@11ܩgbkИ;u?N)yCS #l,4NֳB9[SD }VbrͰS2WZs½\ȅ=j[Oz}ʏNp{8HKB-~ a)MewfHm>r@3Uf߯l1Eӡ˳/$Lg%rMO82OP%_>ɎQFmO~Sɖ]=d;B2B/Ʃc>tj `I,Fnj7DaYI/9\R%@1ă$hU<3[+@$CTjir7N6)rZl)nJ!UV-GhKLRߧ8E@?kyî<}BE`+=s7;\dy9˲Gz;8n@<^ ۲R_M<rnHxR͜-̺#izzG7 ^{ 2Y5(j^_.w}vt1^C2vE3`GOt;mg$@4ԇJW8l1E$u:8P! hHN qՈ?z~i wdvyD+|,^X Sgœ|/7ʓVrjAR \w}QտGeZS~xaDhvaҩUt>L3)uX',u _b?sz"ݗ(|" 0kfiK,N$,b4f1> 6/QѨPj "I2#XS"Y=܍0xX/d6I jtoOb7_VD>x&O7CQˆQ_Q~!q2e] mxwP>f9}A$8ШEc@#R`=mkxO+xK92_ ^y|}cKg'q98+}v$#AUQ|3qfer:]t/&C $i}T ҿm\rt5qLXW6yLyVD9g;I@NK0 xj3tAfll>Yg>'a$%)`X h 5N+ŝǟ՟9Nf$xPMfًgS %$JJXhNj̕#_HA[-^7osF2͇jfH&q醙σa3Dخ*>Q}147'&/8>m'<ޘۥJ9A@m{fe~>XMd(˲6gHMFd ;wt2"nwH,#&1&tPk}ݗkin)f%Qb -~&;kNjwҦ6֫WF^%sP=EŃ~oR)}rD,IeR΁_8ѭ)̴خ/6>c{.)͕ݬsZ OؙjE!ul] ׾xl4uTGS3@' Lb+Fy[̂6ugZF  x&bʺxNc?PI-.~WX,N}+w}Ӣ| :eK{ɀ,[ sDIW*@ pWfrkͥ^/=~j2xL+I~jytxᝍǶ qFُ˱g@ wd`^Sr}D1NORa=Ucӵ#/Y_nKqf\Q[ =dw@+d;ҹ{ Jk^j2B'qDZIChi"!z&M6I;_b (bق1qLTB!ޒorR`x_-~@6). ĹfR aF2ݟj_ې m%D,.HQM4 "x.4[#ŷ( XUĠD&uړ-\Ϧp446AMteXW%I:-$AiIZ#Gȏ;bO,J؁R^ w4Ftkg@B39FL=N:kqR˿.Bqޅ߷s399g8 MUwǒQx8ZwU$h) iL:|iki Qo͡˚% ;7T_%$Xኂ+7&y͑ƋtRe5TcU}eF^gEY(O1Z0L jD Ѿ2i<֧[b7X r| McuD$ᆎ[BdPEڬ9s/=j="E*!B&bM oW^<6[K|6:I\qw^¿" Ưh2$ cr9i4 endstream endobj 26 0 obj << /Type /Page /Parent 101 0 R /Resources 27 0 R /Contents 28 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 27 0 obj << /ProcSet [ /PDF /Text /ImageB ] /Font << /T9 516 0 R /T10 468 0 R /T12 252 0 R /T13 278 0 R /T14 399 0 R >> /XObject << /Im1 595 0 R >> /ExtGState << /GS1 598 0 R >> >> endobj 28 0 obj << /Length 5280 /Filter /FlateDecode >> stream HWɒuأ 7)TaҌe0‡`5 5PX-2 U\Fa)5+^݈ܽx!p-"+%pEb9܅?nߛJ9=O]\E![o`x6 K}]0}7ۺ-W2/ 48zi㝈t طGT5ztyֆr~HM^_ڪg56 VAz8M0ۃ&qU5TGOʆOKT :2o^uX7߼-O<?H~'u2i7 QEk$SP O= @%$#lēW2!υۂ~jKf‹\kVTOL^_;;]<* <>'Զ.[d g˅jMxv IM'}(s_G/Hu:~qj EB%dbvvrĬ X=Z6to@ {U9bu<~Oδ:FAښ"D/rQD.1U(!P(JڟD'jSx̓Rn68s ڗ=hץ,iEKM-muhdXdse~Ҩ Zi۵+O2'2*ب"Ě&|ԤMWܫO$g`[1>2A3qdͻFF=t-6q_W~ʋ43)Pg' ^xtћ0E ;*B~nՔEꘖ a@Q`S AX%Iό|38ϥ[ҭ*(BLaBB^bccso|co_0l85=7lwmʢvi߽kqL3VxJ08#)Wy@e4D!*jjJn<|ՉBpKj8(.ݸguՉq=A.Wn@,$[2Č`o =N*2A4eWĀdr6aj7"2 Z"yD>uZ` ډ[|/wi>9\@i5%iNa:ܽxﻻr\!zim$s/~Bq=Ka9hx p[\cKXHF"u-SA'lbj*ao'8MW X@" \qI5 {`\:hN@;]z(+Yt \z$Wׯ!F۠`V>#5 =Q,OGUM:F;v>Xj@;fnC@10LMą$B[0Ɇ!Bbws$ 毯ibhni )b(":r|ӂ+%閴DZ~,(<&ĨE6-@Iݷ[cعiqmaap);Y zF9%HDqÖϴz+S4fdT)Ep-\p zYn0=V2A]ǒ.#Tmիrwly0U 2RymX@&d2wK2+|`1s G'pX^` iZI.2H< ?Âd0r!)Zo9qR DqB>"OIh5h<&7=fV_A_YY{B >~Se3#z%Ŭ.C;Xλ@}GD)Y╛1 7Hpߙ8QG,\JqԥniUff/|q. ?,vѪqM=va*hcc=I4 {ñ+ /)b6j_6O"db.pɂ wua8OZ5Y,5qkߪ5rޱC0LOԒJ5^=ܟ*YnIwcA"(6 zb|PL;:uDt ZKU%$%e{/n [qCEW>I 6z/G57:fn~s -{XEXlZf&rza ,<*H:k t2HlOFٙ:v[9QFTiv LGv5J :[aY'(^YG GѰ\M/>\36?J.;NL,}ʾjnUF_My(Ng+>.WfBT{!i0ʥXK x$ljWfZ6]IFN>odj$!=:E+vA Mc=kmRiq<înm+n=ȋ;|9ρ{I&\9zϡY7 F*[f7b݉c֓\ MED{ HVB2l47,N&r;8dX4[|F_[: v1l;0[{,nAŧ'=@q;EՑPÁmR3 O= '=dv9,8>~)IM^ƕ_P^}Nnx|>[+Gǫ/;ujqmZ]h`r]@?Z0r`<葘l281f+'Wyky8+s& ւ]0Cv6a/OMnϤR djz}}.at0keH9Kp)Q%r)1 ii GT@tJ%~zFY8.π!_uaHhb/ D 8H8O0amg8? 񱆜?3(5{5ޠjH5ZVLeH\8ar$\v '♽\g0 ]Oɮ1$'v7U$. T&~'w)w阻 ր%~IY:aW)rZO '3Mzj_P7w{Lfߋ/j.M,,q ڼ_i)if<\бQ6Ғ1qπ/SwDG+Th"n}֕<9P-cOJJ%s AF.qpITUz9 !wT%;W#aIαBI\n@aPI0 PCD8%צ,٭+frʄiq~ Hbʤn[.cGjƒX6[Szh0_7|-Y"Tم>=өa endstream endobj 29 0 obj << /Type /Page /Parent 103 0 R /Resources 30 0 R /Contents 31 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 30 0 obj << /ProcSet [ /PDF /Text /ImageB ] /Font << /T9 516 0 R /T10 468 0 R /T11 488 0 R /T12 252 0 R /T13 278 0 R /T14 399 0 R >> /XObject << /Im1 595 0 R >> /ExtGState << /GS1 598 0 R >> >> endobj 31 0 obj << /Length 5236 /Filter /FlateDecode >> stream HWK0sκBUoTj'9UPJ14$(J;:.G_~yLV7Rș[/K%gq.j϶7r'f~r盵0_(?MawȻ2ov0f:;lx{}{!E5Vn T}`-xUW25/+U]tnxe-Öy@m㘬=ޡjbޱ1r ﻖ {L͇* |LllSA?xCg|lwC +JxLvE[`YjKn|YK?<MqO8̉ӋO!7"A}Y" ˬ>dxFDv(5KPոba Q d pۙ|RIbl&M+!%df>1r/9p}6=~](އڂ vy> Mވ; V"鍄ȹXg]c^*œr9APO="T0cZhwumJGM>mK!?n oA!4 f&0-,.O-mOY+9햓`^N:pi٤F(ko6 *hT6 &!`Bٖ [M񻾥LֽE%x_qQk!&X'W=B 4fҾyegB/89šJZŋ.A2<Վ ^0uHGtMJNôa±=G~W\JXp0dH.x`@uڜW"IeG.VDV=<'qH0 TDG@0nn>yWP.4KFF}fU˰ [Fɐ~ڹ [sbWL(.T; (-6L c8˨$OhWѤQJ]У@:R=M!΁ 2 Y#k_}gϑ OL4j%,d&hGЫBo}ڋ柰n#ao^郲m~r Epg" { m4B2 B =a5lj<$51!0Dpx;{c$=kKsPI\KKo/%T# PuWa2`1ump+2ъR CɏoKîgؾ)+j3<0{=ס Z^,J9x ?&yMb5w\ב(v1PH2ԛTE}D} qAԇ+I8A4ܴRx~KƉ@|WEM9ԗ G%|Ul_tqN(JFnU?~k^ ͒? JM9_ia擷 8C1O4yEdt:#wOj\fFkk` \Z^vWuC}&,\xGcR4?C #vC[1;[{q|DIۆ5En#1>72tl %I$3L_le(H(.Y94u#4OD;Y~*ϝv2P(޲R6GH"%S N #<J⢐i _ˮLc{ 5:؇81nHi Sz4k)\YK4'o-*SSz^AsMO\s(HkI!s(&Kw`ԷȎIL_LIOje:-n PoHFim'u:|r:OR&)E.:;lrÏX{uge0 Ys:40 /i &UL[%N!?2ևiuX~hbmY9)h$w:p=T`$u=N &ak;e#߱?Ą镓&}V?H.|VpTߔ =eQ֙F&M_mq83(<>&b6Y]g:|ำ{Է т:R*V!((wG}ζxtI`j+jJFi=\<T WI.Kdc+k7NϾf^`ۧ{ A/ Ryq3}&/y7?)g{TUKgU\*K[Ν%}1倖A ݦ8lvN[~8&S2Ґ sAlm)5ly3(5V;dRJ}[CЦ ?pƣf~m-ccf:cH0QEY"bP 5ȂTmjQUy|] Vi@//_" MW j[;5%߱f>ЄSϐ0 R8EN(F1F0㈹}-RW]ݞVx6CRo'ɤUZ/svۏ" Q0Q^m=nL=ȏȣ"֢-P(}z]]ùP%'K)r8s9D"Yaa˖nPFH$52_v;~qQ7Jk9 MJh}n qC3m/qoAg຃ǗB\%t$6E0Snz 3CX 4V8`uEZ`V`8RD$"L_YĹ0E?T8yI;ݸ$VifogTXLGPVP%ψ4{uet$* u6cs]6%iÈbr;AL-[}tT xan|{<_O{65)w?2AKNn2Ї@%.gHn$ FyNj*֧DiKdc$9)δʁo,[А承7Keb8J(N'o\A ~K]I暴Fk)xʀ$Žp$Y5"ſ6Ȳ~k(h5: g I͜f u_scY0\û S >1]MaZ5ݻz\l&&X,Vnk { Rm)l ~a9fG*V}¡\ϛrt!3[ 9Q EɌ։ua$@~"+D*1P"Twy6=hhq*FR:}0vѦf}[t~MUn`(%az|e+/:r*-cwږAT*x~$+QN,g|Zt8~qC m:H:ZCaAtc v@4R(RC#+y_.&ɿ(Ƥ,%2 cCffo1L?;̔\- d J9:C>c13+ov.%;=e'Y1mcWY+H=A×K)(ziázieL:i}||ѵ5& )9)*S9Zb6eC̣, ]<`kLV_3R8):J4ǽaxI֞hʃ8P!bDsҲ]0 UMO\bKBYu<(2\1WOESE>6$oI'G^@j\3yHY7 \j8 !(=, Z/?:UbEb42 _">U]ӼXK5TO4H)0V6N7EL_i^Kа14,w z)ιW91_Sh8ID\ Լ|ҦOHE}ϯDzA/NiI$╁FEy}6i[C:| ae+,h1FmL-eϰ}9t5<ԊU.c_P^@/}YPcSAQ@y0\Etyh9 QC9d9Ȗ/PJ>ڦ}{`L'8̦JzV&#KZ5Щ@k$0T` 9޶|9g\7n.ɂNrP AGo|<$qy!_Fh&MЏ3fFvEX!@*I6*y]Đ| endstream endobj 32 0 obj << /Type /Page /Parent 103 0 R /Resources 33 0 R /Contents 34 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 33 0 obj << /ProcSet [ /PDF /Text /ImageB ] /Font << /T9 516 0 R /T10 468 0 R /T11 488 0 R /T12 252 0 R /T13 278 0 R /T14 399 0 R /T15 379 0 R >> /XObject << /Im1 595 0 R >> /ExtGState << /GS1 598 0 R >> >> endobj 34 0 obj << /Length 5986 /Filter /FlateDecode >> stream HWK@3/ fGn-;vJJRfN%$lj=/ U$U-~~fjC%]n0lzapLDdMūc ϛyZW_,pt@1ӊ)0 -'#bl3"I^v?PwS/(@N+H%_TD2(ټ_*4UM)!Z|#%鵳VR2Lx#BQGa&%^ ~'%2yc4$]0fH?֑*$r%ʬ,j4(AOz yy;UÒ( 3?yme6.%Ω:|PqtKQ>K,cA%:X4-NslgxbF&V{ [O)LMxƼڒgc|߫ \@L F@0n0J `4Ƞm_vRtD"<{H;DsPh7 1JB_o ,]ū*^ 䕌Fl,d_o^p-M@l<)6j ?`͎ (ƶ_E4ߖH0.֖|{**De挘%?ֱiR|mwv*v[$w$5n* ݕrd[fKc/{71E4 GQa(yi `*èxAܮA|)΄~q2 iw?aa4jڳ7t*3cg8tdUݶ< G `x$TG(͞( )dɬyiAJLŁj */Kjj _[F@%D\OiP!9G&Zȁjr*ЯT}P҂y9U:TXP 98ATT[P 5"P22 pujb(XB>yh<)yV,ñ :0Sm4xjt801b 4K3iKAKq &&<+KCݻBSmT4 KLa§K4Kp*uaibA`_Klu|K1{XgbiHCDSbij%z{C}<swn>v'}{ե,GxY0<_Ol`!yxf<8e((, 3zqUٷ`FKϽ52oUX^VkӴq?DsN<qôwgFJ-Eiae "UÃqqHMnv6$b1d|%*M|VW(ueҐFtW4RS&4߾- ݠАI5q,yizSNTFu|yg\JޙbNHKJ`p`eoT̙00Fy}tCp2]0+t,t+,>m,#UGSTW#Aus)>ܣ*>K٫+ =#:\:wp䓞&o.Maf!wߝj tG(Vq,|w͏m;MpstmfUs/Ɍ%R!8_o@I>Y -pT3Zh߼P_n~pߛOІ9K:P·UĭpAxy$ʤqƗܕ=>yW6 û RW*,w"9K#iXI!%;n(da Mzo`^Qq%g/AB# 'U0||QW4. g7tZKi'+.XQgc}0O2gcfyOiS&J_0#;F#&ku:$ y^Ffsut=J~!{ D}3/::|s%_AУE)DR$|;nf( JZ&4d4Ry@v*>MK;Ν$\®h^V,Y6/' il9D&nդC2뜟j[هv=;}$agy&1H@,~Z\)םM9P$ pl[?RZP9Q"c?J֥rY4f7NqLLnpvKEv[ơd5r%w.ϽeTW>ON*_X"@X5_=,(Wބv߆Y-Jtrpbl2cheawnSF ͒!|s(=5f,feF WJ?d9]] =K Or=LTe_un7گ.6NuYX^0D`)ԶNv=ڣw8}ٚ$0s7^y\>O,mVÈ E C1Yޑ LA-̢cTG9T QT5cFop 'tW|EsRTF˓BULδ `tvizX*T_q.c0ws&X4VE^&8r-?O&N 2XjdҚЇ&O&.9 2Pv>y#fnG.*j4nvvԇJ q4{4Gs6tm3iG!B/k7۵4EVH98x\ uآ$d ZԔ5MaQu3y -U@#BµrȺ{Fn ];B.>s/t&O֪И|4.q8Reզ֧iXL]6Pg`rs Oz m+8tV@-d4]vT1xt Pp[^Inn]73N9 Jڕ .M K/{ ajB`\#O|~sJdex Z!"Z{gX16 <ضY=hyf"c Ө$Bm76#ENtf +!*9L̵tNRcjGaJM_Hiz!3W4`x"96vz!I;8-Բ9taO%0 } 3ldztN%gcMq&aH113J7~, z/THɅZsC.fyRa}w`y?v5_&?1ҿkƬxOXRy0f]G&Gj,X[1ydƯ, @$ӻF^_1Y"1yPBQy!MLӛ`9^k+̊Cpy6uqyHȺΰx5l1wE^9v^wypb.r5v=\x)tt5&U TUP&4\$ZE,D_pREW.K| NAxHqDi%*1XUOKւ,(g!ܧR8@ G<6`+M)kR!;M()(t6y#ޥD#lQ˙MոimyO$}͑y)[5V zVsgА<&k1l؎΀k>f|W+6כnZS4wGLi 0Ցn}NhBMS_2hQDz\:Sܷ1}ntDQ?vNJ1s&Op-@M]fAM {rʀ xDࢉI'{J F"1ȉ@-;3L]D6e^Xrav,]80޹I7!,A:Pq}?$kĎ?tIkO$`{Y>;À;Q+68팝R\$ {8;kEc>jP22M@Gq> endobj 36 0 obj << /ProcSet [ /PDF /Text /ImageC ] /Font << /T14 399 0 R >> /XObject << /Im3 38 0 R >> /ExtGState << /GS1 598 0 R >> /ColorSpace << /Cs5 54 0 R >> >> endobj 37 0 obj << /Length 230 /Filter /FlateDecode >> stream HDPN xGHW-iVތ܌nڸf=7La_h'ѡ#̎|@ŀyqjq?3&hwȘ`Xm{2)~ΧO1F9mԵ~KOR%aX^t7" EuIV|> #F1NC 1F 2Ml핵F|-aKB:tH [.F endstream endobj 38 0 obj << /Type /XObject /Subtype /Image /Width 382 /Height 621 /BitsPerComponent 8 /ColorSpace 54 0 R /Length 133147 /Filter /DCTDecode >> stream Adobedm~"     u!"1A2# QBa$3Rqb%C&4r 5'S6DTsEF7Gc(UVWdte)8fu*9:HIJXYZghijvwxyzm!1"AQ2aqB#Rb3 $Cr4%ScD&5T6Ed' sFtUeuV7)(GWf8vgwHXhx9IYiy*:JZjz ?ރ܏xهA~au?~{u7/ }u_>57O?-|c=ng??FV}ՁLRxMoʷrY|{Bei/ }Mn<8U~^f1wWK09bӁ+;#V/5}W)Z{s~`Hn7;@<~TF} J]/A'ah3Njg}}׿<"]0?jn~Ï<Ǚ܋Z>>xu<6nw 3U Fy堭*s<O /gw|ۆ!Pi|q?3m"-4O\jiG_}6YhA EʪAx&Uyz O:c3~._Y]v.Gm.w/*VCCꩅʃtm>כ;ڻĜ_u~Kv98Tԣ[DZ=nqG8|AҞ8Ҹ^V>͍Rn?m~ml}e7&VS_RֳwٻƇbG"=w?͖n>К_jnAG؋~oam?s\'{] NF \+/#<ԉk˜q9>jxi842ڳo]x)-7}"lc|W^?޾^}(*VV~GzGnVe7jk|O{z8\Rϭsue8zoASح?>{Vń~>|~^?f?`B޲Ga??y<+׺ oȏ'ߺYhmsߏ25zoO}A?^ޓ{koyf(7xo'Xc%I4^?m}eYfۏ?(5۔k>ԓBGOUS"FG={s?߰*1ڟ{ȟGoxh>te<3^y_I[{Ɨ>?yaof/V_ު(O|}߽t_/S~{߽s=(puEGWGG^F_Ɣ[#a`V<ЌymlIbޫ#N?o>Йl2?#8 ~8y(؁{d%WY-??o`y(xqڇҟˀ<#ϻWˊʚ9&'j?׏bW>K[L> _ߏ?= U>9}EGfv`T M+z]so9pǮ5`_O=: ٘iq./C~#?~l?r8\O:c͇'o#g]hO+? ^5h2+qOmr]wY7m)2C {uY_Uy>s)(~/6]][Ɠ>SrTԿ"W@svKihoO ҿ>9Ӑon6V*)ҴބoLC3y_M՝mOT^ck髫 0}<_v_wg4g5߮\n>6{AqSvӿ]mֻWO=xO/.\ J;r[%Q?6=('brz__?퇺 n3+*>>|,6pv+>M4/{n@<˜4#<3Zaޟ'˓+T==6Ci_?7?=֖yrPM9AKK }9eoo}`?}SS_Wx'}oom>/}X"dx#ǛFiim0z#qoa!N_HR8,|f랞<}c{[/x?OM44-#ىH4u5QVDJqss?}mާ5ǟ@>Dr/l_K,?9'μnVd(<PߓMooiN݇5USSGk0"%;3,TT51<-Hz)khKOQ?)=?v03Oیp5ʶ?>~X cd"'tk_՝|'ٓdkoEuL;1EGYXGU`zil6?mW^x ^E#'ƽj~??_omtz8/ӤRy_qsK2ߥyk'ƽu׊h/V{R_~`_o})|}ܨVn=uk:(@#O??i^ƽl}?7 {ebGй,|OOߏcu?=We{~oԃBZS;`o'?nz~?nE/ W O+b''_\He:ު/)Q`7:~pXS5gwvتZ_\?Ϳ_`+5|q+n~PE׎=X?oroO q7-S;I|\ 1k+u>aj?xoŽ?SԯcpҾr M#za?_kǶe߿"?yZXhDyoqOp*TR}OhM#}xn.mg?ˏhJ-R*xponۼ)~M2q1Z~WǰdT ?q5G#ݲVbXl 7ןЩ=%fr[GoM%5-³ٌ?Qb=ZgׇCΕ:;kh>l>@׎}<\M<)6us+7ve>֦a$}O?Pm8 |+ToiloUM5)"?ߟǰ  q?nψ'E3sg@Rk542ʋd[YWEQ>*Z%{GɼD81qE=E^Fm57. ~X{>7XEُH?wKx^Ǐd6׋;{W?xqn?7weEnHOkJg-ͬ ~$yf b?B:Wϯ+ܦ@`.(i1Is$틥͑6/ f֣0m ~=zFz_i?4Ե'ū_&p[{[_p}]4H@>g|:&ۭF7[?8uA희?tryr{ocodC.s %ok>뛏f +`>N_^ }>OlnxyS ksnOԟy_oܮˉi_?:nw}nؿz]䓊d?!O<ߑQRU(q?O<cR[Sp?ס ?GNTֺ6@jEcE763b_5-oװ m۶ؐ'3^1pS~1n;vp5j?M3Lp'&z#Q" ) m?gGO:̡˿>Gn~¸ܕLԐVi~4o>Sjq?/ U+iCf+"{}]gz5V+D=W\_,9o6_)>[W vᦡMTU?B?N,fvn?s<<{Qqc`W?oN\a_~_v?if/؛-aDQI$-ϥTއx1/m^_ 7;s'G?^{x{){R9}z[y?_1~?_k_o~Nc,O~{/){?{/ oWx*?_?=cGZ9zOxr?MQ_O~v"3w,nݘO9'~x}??u{}'5W=O]c lޓ?y='U5PEcهA4O 5D?Jo}}}fV_7}ϼE&Lq|!@i*b>ϟX ~i?i>#x}~}Yfz}_[}_~~}}z?Mz}}Y~|ᇃ-)M߿2oldzMȜZ ?S"[cYiğ[nz|?S= PPT5~0?C䟯OV꤆)ij7cOUUoQ+>30CY?Oû~SkO_ѵ~t#57ef ?{pU^z_?sK7iMM}7Nᥟ?)ʿX|)fٚ&<3@}mzɣf=-)&kA)TW{L=GQ]_o~{C2jiTpP_6/գ{+aE1œiNOct*}kՂR62)?i'!.RLkO_=/ɵju>|^ S?mg+&}??<ہsob?<%6r TSUr^ް(OdsuW67{wt-η|>ʜVA\휥}V{>]77ٸL~!S?zm{IO~q9svyE7S俆[xő/Ź_M$ >>=\_SO_Q<4|[w6l di5=M?'Ro*@Vtc,4L:>Ol~H˾Ţ,&䨂SU0UqH,y$?76s)|RSy1B'؟>G6ы܌ ݣ^AſH$Xk l9Ol :$[>^}!6kZdW^N5O*'%`扩j7`~&dwvO2yTM*!V?k O<35Ϳ? ?{Hj/^~biv۱yi;(2Aˎ~d9}͝Bx'R *ӆ:V7o *qT I%6Гs~8ԟi jFQoט̦6)dO}>oy|Ho?J" {ߏr<}~̒NO={~*|חwT9lS{$>~RySP')T~?o=;5EVGٚkY0\6Sz|&B\}gZo?G+ Hk#h@*kxy*(=)_Ub75f7%?oW)ja?֢[qk~ޑ;CF:k?b\>~ ꊯSA @⇓_rq}*|8qL|>UGOZK҆_o[?N OWwRa6_^>y1gӡYkm?O~_}n??_iN[RO[|M Z}Aޞ{?W}/)_|}?_^_??܉?=ǖ//{t?y{,﾿_s^(}OO9ߵ(3dl*ꐁ[ER|iz%_/[~V&^RfeKx o/6R_#,_oH4#Ҿx5?LoŰWwPkzm{U/5G<6Yk;G?Oa:?CO2z?ަ-cm"^}$j:M3x~_^+ ?qjM?:=1,sMoFHcowtv?Q<3}_~Wf>Xyj~)/#IK'mWAf #k>'.ҜUJzt\VIsRx~Mk=߳hQTjHew%NNj>qzZ`*Oo/ȵ>-mq_+cM?CC8b1hxyAOpZ+vfc;j?ʩi(F=I-,2TT>~Gﭽ'$KSSsH~Xq#{/{M4R܃W> _ۋ6}9?٧5[euzg'B%G&(h@*$S2Z<ێ?,ٍ5mjjϨ?^b֒ Rs`x~܏e}J\ G(z+yMF-AɠS+[Ρ+&GWPSP=N/h?B| 46$~ӑs {/5?Gj@?oɹ,A5v7,?x/f-4. k}i%  ieԐD<"܏ׁ{~l޽[{G%/RՄnRO#orS*iͿw%N*Κo,,%_:֥ ^?~cv;'Ca6spBݏ _x^ͫ-oxo!]g&;APc O$ݔ)'uYPC({_?gzR Lzj$`9 ECJS4V+k5A\gy7l0SQSMT(hӛ*/䏥j .띰kj.iLUՕms_޳kOM?GׅdzAU ص5tR \[6ϧ|*|O μFI|Y>j1;7 E]<MKU.?=l&̿ =G_ze_͸q`5lEAM-_<'Ϳ{[WrBmQo_KΕឃVބyV#+A=KAu5WdzAc/#ߛߏ^,|kfhY*(j-H?_O{kŸif[}׎?yY[կ,qf>d_iLFih?{_&Vi7_ڒ_s췆Fo#} wwo|=$~?{^ o/>KğI6~￯,~>|QҎ_Zh~%L?mǁ_!\#>'scgvV&p?gF-?_ݮ/}oq?Opb})8tϞVby}_p'2~כm7^PK}k{@$ x__n=,C#o[ s~ l|)+S?n,qO?.nhq~qߏɦ<_g5g+?j?>_{dϤj'~??svuÆj_ZlK[z|_θ>|=0kԥl?L?,y~ބ\e/)5qMwx2}վ-"I<"S >>Cw)Xp.)~ƕB15~Gϣ6͞ԁ? iSZ yd*p:7 oB mQS6Xגy?8LW,H?ly +v6we}Uy|F?Џ7b/{ܶbpMN\ߚہr"\}?{n!$^(P<؂EH`V>%ܽϸA[rƵ$ߖ TSGGz̭Rbj:p 5:o`&S rA<}9{ |S%--o8i^ R5F.y}~$l ڜ p<1$Ϲi$tW-_Z+Uo2UJ>h~mΟ^Onf`zSP [vi}5#$qs厊8WiSJ-+Oy맪3k@}qlq#F']uw 1/^x2!OQ/S?=]6NVz`2KV+jŭ^bmkXsYϳ#?:y~X|W.CnyPOğTm߷* ~ǀl~.**(/A9>*M?Wx<̜y?q(asȷ "!IKOUZ?+-rC9LEwa6ڪ_x_[N=ݨp~[qnn?z|=_^rc~l~s{jClEeE#M}o$X_۔T 3U[^ <ں֞g)i4-WV [؀uqPk@sS>\x~Θ,k W?/Ν3b)Z\~[pEZ4"<ۜuN?e=-NI_V0f[} _#+AMr3ֿ!J4<|OO[uUf n} ,PjE0ӏ_$ZI)=VHS$ӛ~m~X|nHA]KΟcYr8dǟ8muC~ަ^?,G7xX-ᷟ~__뫪rUd*>/Ysq{~oB<__ןhS u`dJ*2-Źo`hq 3䲔hيju k9$Ԅw?ן=ʧ55?i'[q=qJ+_Wj>/Y9p㏂ӟo?}e-oSS}O?q˳ب‰tۋ_k=2?o*.7z}-=A>]_U迃ce5/M~%}W_` };l/o>2u SHGӏyqU\VTOߏ?ٵծgzt9\-V<_M?Rg>:"$~x?4jסoOKo|=Ċ_'<A~~};rIm?׿yc}—y}=/c?QHO~A_m2k?c{,?׏{jM18ϯ~ߞ>Tꦻy5@%?Fi `uo}Io}9'zH\u,3}EVCO7v?by _o2~]%ܽ'_ZYm_xݿ{hێ{DZ{.'-J /|9+Zt-T1R_?_&[5 \ 668[&HZ[<᠊ _W'~k]ڹ$zׇ3ўݷx'4dcӏ0)^8;~}_d+{*igjʃ򺯹m]sMK\%[9YPo=wP_?I +ϑkZI`~^^d].FOP[o?#?wȨ'- 4Y5O.۟ԶlόeWKks8I ޫ u8ɿ ay-ٕ:5)u*WR 7 a_UsP*a*o#Ϳ[ mk[CVa$/8T=A;uPI"3VƢ>?mL_mqo׷%es6VO XV_:r9 j:IW0< G <⯂)1}Mm#-IkOɥKӰ+)"))>XE_-qȼ}#??돨w~秞M6E~G',Gq-构^R~~xl^#kO.ш!iɽCokZ('&"~.,pl50[{aʳ'O oGğy?AtYJ(N>U@q~.?>Y~5A qߟͽ碆VU迮isU?O?t+A)1Yğy?v{o~oǸQmO?gJîd? ~9?Ϲ3Nf)<}-?7<{ [-? z*ya&%?&׀:&/s(T~XZ<7p=-E9ֶ? ;l4TcI_hۛ }~?ǯtEQ/Y\M" Lf<& 7FBG *:/7OrUc!T*l>7%V>GbmkXhjVmqqo = \}MSY7Uyx:⪠UO??폵Q|?mO4y7ߟ76SS_8F+lj@('?e(kWɶUi$z)2ҍ_A?ѵr@kS}ys\b펪T?p{'̃SNfuj:_Ӥ#O MFFyO{[?Noؙ䨆==GqAYC {Mny54\C~~o{~_h$~̑_SGaN*>Mן!P6$g9:44wvՠQKU ]'cc`ܯ-풲iɿ5y?aϽR>?/J|R5TVjj9\sb~-&VJyYiOۀxDC_d_Xt賓\*g[Qѱ$-UcW~gl484<ǫڽ MD?~j5?_{<.Rm,Cs^aSP S;U<[ʟO3FFz+[=y~zt$t'x\yZZipy7K?/kZY?=%IK?})G_Ohra?_A<M`:<_?ޯs_5D'o]ٛ+CN_>UKOpe[?=Q4oϿPzK??y^9{7z[>>8cuM=YW5gx*Շ' >3bOJH6>}5[m4?_Fdzy"^Zʽm^vJm*x{K3kD{UwGO}|r`<Xm4~tO~gA,|+}U֬5#=vhCAK<#KU??O[t1+8Z9n1P+\u)l;Mπ#5 843YM;zve%Fk3w~ɸ#>}ה=Qj?eGߓ{4YiV #ƻ:67xp\U?O qvjVV5AĊ_!q=]G71A}YO{"Qu7_[{;#A1)~➣; wVa\}tO7u53h}Ell M\3J`]Td}QQURcߚ<^,H>35GIyb}Țh2_S_<'?x"۵Fi(_P<}_cGUEW4椂)qq<+\ua0?O׹txq??{Uޞ)[k~?&[}M[s(cQq}-tcA<<t(++i鿈zi5eWy<*l֊q7"?Nmo<{)O??ەii 0aD,$Gmoiq'?4^'=z~Қbj?(>r>_4~_/ ~o)Ⴃ*M%!#\rxƂe 7?xx??#Jxu8ϵ6/5K[QRrW(@7[o{q$֦0GQa=<'5td}_NQWTPZ?#-o?ד'j٩&'RHn$-C7MR?y<{_:J5X]Nj.4~y>Z lU1eZmGZ*?1"܏?S?CUEAzK"ǟ޺HGۛ[}I>L4z"G .=YzI~?6C{}8܄*h1lkUSTܐ8~tEE:ѡ}:ǫ~ Xys]ͯi^Ͻ%)?ܑzFoLBOPxǔx/RzEPb?O~@ּ8 @xA?R k~}/l: vG7OU|_kmầ!M (1eQU/,W8}xo;nlܟ m&g/wL~((&Bm?xi iƦhx۬xc<?H-4 ׳+/s㥛 e1q?K{ҷ}vGcvL4*r?K Q@9_r~= mi*'+}?\Q9.?۟^ͩ6~.d}Bb{1Pձk8\מ=W+%A_?~=0y5</Δ|o/B+}x|_??O~Xb??|{Ύ0Վ"!G?O-5v98Ŕ9??:gsW_=8m!8>69-tE?ï/to/xf?￧Ž}SE8o{c]5gTȯ{opgE'\xk4'pԖ{#o1~M~ǽw_m,CjnmSI&eo17pA<7}mo_"zXX5ɼ2}q'ʂy,G`3-]cd@il[[窨ߓ?%Yȫwfj:u|srV-X-!P(-kMϰ"ڧoͿ}yK@8~^ǹ5 `e?.D4pSx()iqXkO&Gkp?sM~ꏟ7loc#.*Q?O7ry#ӏo|_}PE07p6O?CL}zjNOLange,j&}yZi#l珧{~=NCp(/,5^?'Ͽꯟ^uGYN!ཉ5O矡匭?-\,8mJ?] C??f  ͯk޺_ԟ殔~_/{f5M{XOgx?ȚMo,?x<_^G 9TCů?K> H%O۞E}f#Xqk?~OŇ￯n|39$.i)HUn?3-[OWy(qumOMOP}?7[mTc+iM?4}x؅OQ+VW^7ԃk}8zcdgtzyO߿QO?O6cp>o6sXnOF`M*[QMQAASOMg [oOmkSqO_:#"'ȩPP ch}q鷔Ç^ WMPG s]]~6u1:#ߟfc C5.N 6k>zR$uH2M??ËTE\PmM?qoLUvO=WQqog'lyO}$7#Mʣh)wZX!%cQM(}{yw'ȍ+ܛa5JZ [ =Gᗏ&$b(cGFK~Y ~}[3Am76|Ċ }:ǍÔ7+pGھF+  ?=^ v**::hkDWc =1)Wb|-;l9ā37{Mw7 S[~;nJ@ f60_Z&fMGͱsU)kÈItۮvkp;t߸F8; ={}K)nK1lsBhwM]."۹lVE*6ܩa-;qE.Sp!u|>Am'mjzV6VkRS 03T.Fr2t-^5XUEBs/@[ZZc8RiPExf=,Muwu5>DS: e}meUYoqk{{Yޛ%žsc2 )AO?Z 8_ӕs}eD0ۏ/z?Ju4?Ca{a<B-L9LToq%6'5'枦U~'~&1?jj z۞Yϥ+N* @?O~PS?} pnM q[N~%dN)k.966o5OC=lY6_ok~nGuCC <sJְ<_8VO4#Q&ONx?dGr x F׽s7P!AOk7Oi?y鉨OX?ַGOsOOT>s}y_\Gǟ_t/Q_N*-EanIOԏhhOT[?7} %q^!+b> ~׷ec](?-5?4z9|~ox]OW *)jk QU~H-g*(1xiVUǣ%pS~ۓc~?LFQ2{k)Kd6f0­{ %[a}ŭ454xVOz~ qp3QB?fk^ez/E5CJ騈QIpŅ?#G<94_y1,lO6nG]ܐANE=>`>6 g *(nqa}OZ]+n8 o{ 歴>͹-7xRBMJi/?Kk/hY⟛pm??ϳ)?[ sQ )?G9}?@>_2oީz{׺? jj}G> {GmS MDwybU y8 o>OI${p9ߛ?Oq,ao<[.7Oͯa׺}7sO6'kAQ < }k7k =Ei~8so#_ ap8jqP>?B,n5+kqIXs|w݁W'zC$J* ٲ`y <}}MOUY#^O?9aU}DTӪ6#~B~}jn5>Xh OBzܳW̓AyK<[>&r]=Thj'뭴6Ən)14S-^s W1o<}[_ARq?_ˡWDep8!ÅGw?&1zZd-M6G^x)xR:m`W0`vɊʿW>vyk[ ׯ8o|㏳ϏQci_Qd +M6S+3z)1]=?E?⧏mԻ'jˋ?Dsٻ>>h?*$mOC_0[Ӱ:1Ê~V5 Epk438#\gh,;/ۧkMEI! jjR?bG??؏Ȱjo|e?| UZEA oΖ?ݷsȳX䛳[ <֝w_+>ѡM/V ^?_}yܾB]$*i?-{Q`???;b^F)*'#ϼwI =}>SNA!~[1S9-ۘIֹ(hMmp>6,>뮔4TryߏݹTXǽh>ʦa]mmM8,V19݃9xGMMGƤPp<Zԏ[/ 7^Oos1˚9~6rحhsN#n6[]m'3ZPqϦ>ε/YC꜎+%#O^6p9bmx grp,O{r?q=UMMUgp?8kZǂ$T_}sxߵWƔ(̜knWB WdӁ0 p3zǒ8NM5M>D~r~8{}=7O%jjjzj3ǒ>Olo{jmYҏZ+((**?5Za.L?6_{sōc(!fo{n=u@>*`SjV_x^AAOrE~fvञ͏ D֑Csf>_<oj mfQ.oʏztd(+), ?5rl9S":A4O ?Oonzه<'T)iO{~p8M98#-gݯYQC=M:mQX_ڇa윩AKUARTv"~'fKmF` 5kw01:DxdkSw=6`v}8k{t?mhHzg=p顦2ַenT[;7V2ip9ߺjU;?M6'7U1_t/]KUO\?N.x ݱM[9%GLjN_h=H9>jF ֕xAk5Lg4iώ>0ah0g>槏w?o`Y,Mu%]%<Jz/S}x8?O.>oN+ܼWm.K3)ŭr1V{76_/G3ˍ2tw~$qϰ NO`{aتŠp}2?#.}=LTC5 VkM>&Sou 55嚑Ar*WzS>}y]SC= ㏨HMm㛋^{T0O4YIj?(ےGn/bxi?<z+soװ~~QnmRco[STz_C>#:M3%6vj3z TT?_{S??Vo o}77^?=T}?_~,~]>zꪊŇO?6f?1q ^Km>kgSkG{qo<&qX؟?4M~͇? 5E==<ϿuQ}<[>=h~o65ӏ#(}S"ȿr?xI|m<tV&?;SOOLJB-sa<^ߏA OO[mfɣX*ZP.8Z~~GŸ4bp3T=m_۟\N[4!oߏ}=ܧ u.lڏT-_oU[-7߃n.c'5>^/듨OExlmxj T5Y+ہ zSο/>)pxfFړ447UU18?Ӟ>Ϳ_4b, ١x?_ϸJ jT&υg\Tlgƿ5-/UWM\A#dM yi?N/C{^I2 SÇ Qw3?qlҦ}5^?y<-\{jw>p#Ɂ?yG(rd5~_aW읹c/-lε ҙ>x?#_Z_n)<Jyyp8ͯ)1~4ȿm3,/VO{co R͍~_(g瞠}}`aG_)8qoA'ͯ?<@yn؏)Y*z,&Ц-Jy]tow*=B|ޛ2; a ,.A#v;hu{_qϺ3 V2i ݻv[މ;;WU44k&?[G6]R2xPtSFk9z ֙ !65Z~ooxLo7__yՃ{XH-ϘXGˇMëq87a&6?ol>ǵJոx?}-\p4:BkS[EAq޾m2 k?QBlq!OtRxr}5sDiwM){qO|>Uuz}ut*,h??qQAW܏ZQ]ᨥ KGIKIq` [~ ?kEI_o?_nCablZp?[m5F^$7$TR5Uܯ<ڇ㓧UQ ejA",G_/&aC!OIQD)tE~ X/ٔΩj5\MJ+1Y# 9fXVxZл[1 .j$:|pи7o{mec-.?krOⴴ¦#}׋pYX7Kk@jXT>U*8 `482Op:`Ts;l@PjNWi׋G _\sw'XR7L`7yU]k,@ݷ;qs[kbx=t[[F Ε?h֌Q<&'悳 ?k~/ة1yC|U.7vS-BG$s#ANf `0Vb7hlyvs~ ۃ0Ða N8\UX\g?{}=mM( JT>T4`p@YPj1O. gShq_(I}J|mDX8xRn J0zT'r?qZzUEMEO> 勧7 {SkoZ okMfh-$j.O~lEn~x(qݮ鮍M%0kьCE=W luO]{뼎&w['S?ӏc٨GsW f<+'zSCAI?_pf'd`x1JuO4?G?O?A#Dsy֣Jc쮢\s!Adia h9``6n5~)ᯂj"?-kٸ\5H5b1O,T?>]UI8F+#) ?=ʀ*?QmhH&GHy{U?p )o[om+k*?/?-O9ޛs9yf{5f<~?'}0,9 MOn?m7Ɔj)zr>}??C{I$?֢c?M߃A_>z<\p?>_T'o&ҷ?>隊LKz?>9bJ+<?YqC?}sI\XAǏC-ei|X᷇z^Gsoڦ\\08m(_l[OqmJX*櫂? 1TƎ?QV}ojp1ON?/^x?lKO{CKjo?}=Lg?}y{qWqObEaoƧq"..ӆj`'' ]+|.֏ ^j`?oM/t?ޘe?ܦ8R +o1g)TCJ[OyW}92}F^fcNh?is ׯӴNʖ\7kuۙ˚OK}y5 S#}TLȷp=YiŜVBrّO?X{c;k=EiF4VbNnolQv>\ >|iʸ's9ϪiX8zpOFb5uf@ȏ_ʶb͐ \VO$?}f,.\ƪvFj.r=9~NiQ7#)n6q;] 2:̸9rؿzm[||EG=59+Wz/\:YOE>zqP@R-Mo{Ri9T2VW1o~UD?nA?b~BGG^۠H>zM08-AJPq!pܮEœӉ >DL(*'GV?oe4ラ?k5soN}dak~uuA c0? .5ێk)Ly`7[G};܋EX#yqT ߑ$eW$ሱ-}G/?`zS)'?{ Ǐso~moߎGn=58^m}--8\kVQֿoTC0sȰǁcG&>O?y#~45Co?.x}O?/ˏ S8c^xԜP.>qX nO# S%oiE-c{-[Ͻ:k]͂Sv^y6mR#YO`F [[n=SJ[ L־`:›w<_ǣ!p@ϣߎxuCPrټ+O6FdH\kq{[U+!{1cy -?aY3jhhj\ir9|W[$\C7>6家qN΀c$Qu$]?UiSΙAǡIlfPb?o8aek707'ksjx5?ܽOk|9KbUhCY_+;C1<_~xǰl^_G?_?;-9$fkKoqk_A΃׏~b{6=qa?ԟ`Xnn ݝS? Ob;3nf:ZfCw?䶖LTF4 OB/oya1ּ_Ar8S1>s)N2+RN\[nߏiRTOkȥJs8I6o9mMɹ{*[NXEuTYBucb\h^Oyfޘuv_9>Wty-Ǻ}͏/J6r2`!?Kۻ|x|hj8t~viP1)҇4+%IphjORe eAjT8h RԊjQ f ސ~̓Qj&C/r?~?x67#M0A>x?-//m>o[Jpk\֞_snV^t8|^b|`*B³ZfEnj*%&⽲t*ƕ0.O kRi8d?ӑ8[Žn'ؼ.S?+WrM$Yyۨ5F:y s5*F(>tp"GSa*)ɪenl?ۏś<o?{ bvVJM0 YԥZMǴWKyP*PyV!!gۘo??hgC'?[WZLa)ϳ/n杳p6q`xuENry? gcU#|}g]qPPrXwڟ=퉼|K8}oq=ͫ4@> +<6\3!245xH"O-͉<OUog8]刎57/c!|^JXm qG&/40# ?V oyoV/c)* y=~yӨ6ԯk0S*Uu"#fߞx1oevY14N pȏ]Ϲ斞z?ߢzl-@-` '#m%q!HqISC]G{8Xiǘ.>S⹦xV=@ _Lc+Cg_Lֽ'ɪ枺&)'㏠k'؈fr)E)?A?BG<%Vs'O?W 5$?IzyS wSU~ӟō;^/xTPTV3uE[^k\UMZߞ}c1U/coO#ϸtf&PEs{p f* 7Xl-9<*po,Wl7Z߅qx<𦞀ը0p+R)N֢Ҡ_:W@>OA|?>I0y7E?_?nڭW)&0$dl5-[)ڊ's [X'54Y/=2M?GfNbs{hh ί7o8N}j}x?>u,&N-E?}zx U<Xj)lmG| O{ǿu9yf%P)}W7?Oj:!LoH/Ă}fKKr?>&a?-II]o_6<9ˆ)Tzj>R ߂/}b8oƋk«\tQհՁK_ },8kMmDSOcͿZmҌ֞t>ʊFQhG;k8?`nM{ {AϔbFqzp-{=Uu<$؊?--GJ̎_g|z*o޶|fʫu_«)๫To>nS-mܾob)e}X~J:XQ rۻ>!x`Њq);wŝ\*3UU56Sp[0_{ wQd5/lRÂlof;v>̇Ze1sqgxio{}?m~oͫhq|_bUj;a6clmv ><\][]p^/Uc*z_ß')VcX|EE1;[/ ^/m ?#-?{?#n߷i0Y6j(h*Te`-_1G!]d&[~K8t|^Sk_*XZzJT˷\4M} kN5f 9;֎j7 >pRvj y8+ߪjx V_ts< Ke_Oq#5rS+_+3q-嗫c'4lj24`XXkO7@l\"uu*ڌ|:X)?awJc/_]EUEOQ~HvۚݐHM+_!R`RnQ5(NPҜ8•&NߑMk68rTS7$@n$/^Ԕ4~S"R\#-o`:k~S%+)ګ-IB4>?~,?{?^ S>抷!K:ˍGp_{wޭ$yOkP=OH<͹(%$㌕^ZE}d󕛂՛'YQMAx6Vl"cs=_DU[Q YA`.8me>ڔw[3A+#?6m)A1}; IMMMOa{}͞QB iqN܅O_М:=kQ[Wv>-ͅ؟Mdqj)1QҔiUX3]D3s ꊯjn(M!s.Uy@>^?/aϵ6isv#A!;jSsaS5Ah?=RL8m*$@x{.}4 sEo<~GTf:G/i/>z|{$nL4 -`4mרɳy@j {izpG8[ o< z4 b|>đM8م`qOd 5@}`ߋsc n <" ~u=XUʶO{~|^O WB,o?>.76Qi-M<}?߼M@48W2Oe鍷xg=Z×ipsVQ8 {/s'o[ %SںImjc[qs)eT~A#5BWRzloO1b?cqT+MоOX0uvڸ48UM?ܡy=ڦ' |om [;%/5F8-mSµ oy-OլJ)MhD!JqLǟʮnj8M_.?O;jz o!,}}xQ`pť_\Iێ?ܽm<1un~ ?/?%B%o$I ?_Y 94bFj>Qqo;^*,rfVe)vFDk)))k2uuYGdT76yo]"aMsQN?#sI_6 S TW pub<"#qߞ8?CEv:aT\'<#?*T/sONGtXZ=WߊϺ4g>@[c8yϠJmٔ҈(j5s]\},okhLDAo͏'{/ o0(?j?S(!AU>@U䏧^hQ8V Txu,NJ=L\}uOO_p8}oF4?oXqk{sZ7oɽ#S??/zhE iՄOӏk5e橧Oo髟jߗ|O N+J4}'??\X{{y_ y)jR ^on8ߒ=gWڷlnm4} G2>,ApQ}'O~zj`{{-_QP㪅%U=I#E`X247_~8Fj|fC(E5ut-L8lt/!=%6=d}EM#Stdf"Xj>ͅ}d+&OW`y4$?WO8i#_|^-cO`5R|AS.e<9ǽa'ە"԰qZ9.6a﬷Nbj~Ԙȟ y엘,6`VdpNiy= 9xۮij>Qp<<}Hm/Y91Ø\*}Y؛q[ ?CE25?v#${|QPQƚN;8ckhR[}t>#qm٨k2W ux?>hۭ6?un_`?F Yyʁ_o+in|tXϔMSgY'sB> {14غ<.*XHwo͝v益8+k/WSM/?pm}'V_JБ kZP} A| uYو1drq nl2,.- C?o/U5?G7r/{lptPA=_sMX>byx_>aǑGyR_tmֻ~\Ekq'ҹ|c~ ǶwR\LAA'y.,t^QKSmɷjr* \u\ya9Rm.{Sd>ןOgqN}xf:"|U )k'R笥KmOLG YKf\5鷷 )ŭe_}|>3e1UeJTs| *H-Ʀ*~)n`bc|<⦕ ]w O_jv>ݤ˴k2[yد͔j&5?ͭHvoݓ!v=>jMZϳ4&nMtYW!_A$zqi\P1Jɨh|P_=(3ZY 4e_NqF͹[{~tezy=.*sOPTzϩE}9ۓ{s%;{owEֻ^L?i~ptJRioZc֝OO?^`ChC/Sccž. ʷxd߸eS-)x')ϲ[vboU(ߎA?G`f?s{7O6 yg ӲQo?o's,a_7>ދu|}S_]GZcMiC ŏJjzy?k6o"?y1sC,r9p7=]P׿u}mes1uc`OAX-eކE'zߞ?Ñ￧{7x){~,,?[yފVS)Mi~-ܓg^|/!/{^X~"*3<^MvRAȊSփ>b:9{'P~vhh>١ z_Or> iXSiLOponO񰿙~NI7K hk6 /jvْJٽZmqۘGOYwx90xp58S9ҜyRx~@$OGQ0ڏI?_=7_쿖{[*]A!~?}?ۋٖkD®sK>}IMt]cS?J 0 |d@CM>7&??gbafZYQڦqT#Zd>?U`}/|R(!7Eq8~tkV:;lO.خ4p~xLe*(5=/?mcw:'>! ?ɬm*?\-΃qT\_ů=+WqMh2-~#(Gڮ_rzpAE:?/M4'99A(4c|l;- xj? %qvm!ϫWgoz3:nvwjcC^g ^_5^č}I``ߛ^UEVRf??L>?9vces']qp?.-\}4jNiNcEjsSr4º$ӀBh{g"k j`~[+d- pI o&6GqISsoU9^([8탶v\H6;<{s!/|_^o?}ԟ˟%]oNJ_7{EѴTWF\eWt)µdoυ#uIn#{(E0?ozSIIIROzK4\Qak}_oi2:pQCfG}msG*|?Jyt/Mm>?1iLt*/ks#G{7*鳋~?ϻ4[cdq _9@M]?I ~Zfʵ5"T߻jNQ>_"nE24cz׋؟~?5v4y4OOoiQv騩X9UnokoxρE+!Ζw}zgO /T[ym-kbV)~?AdmCē,UWpk F.M2bEF!]gUijngREDry 7P}M!;HqOD:h)㋛Aq|5q>9_>h5~P?m GOJh<3s_k4臩s\_A^s9?jQsP<^nOĦ?~M=_o>&?qQƖߑ|tڰe0T8㛏xcouXFX("~'}=GݿI6S44ґ,l>6q=_kfo3JӉ_u!rW̓ZLy`f[ͱn,UeOSs>b?5?F݇t}ǟߏvmihqP ?pnv3|\WiǺmsg1|t=Z5u4 _٧TicK]؄[RbQAU4L|'* m>ݘ}WOgL9k|>U.Ξ_mO{w_׭ɞ޴{7tM^pucxϾc'qDZCb|\$kYm*3{wl j_!.Q 6\Y|膲74?"1br?9#xwv_[g:+n2ܯPUءf~G?=ig~T1_#>u@Iweh~^~εOuêh)Na=N| ڦP @A7O{wqŗ-Tb2?/?ީ;-^) 9 cUVy/m7on䯤>eh\T8{ű]qqʟ5caq>lTAS#jqc6/%O(mgǟ隞7qqnz"!{ccR)erInoā _ooͅ/򡡯οfk'!{K= ~Ԃm"[܀gP#R@O TP֦ P QG+ߙ Ad_ɏ<8?[-[wfFrqTurSfsD a{ޞ9eNl Ig\2QT ,QOӒ>>́}t}a[?F/cڝlvݷOpVsnoźnVXgҕ&&ζ:g3veaK]Wqmݲ#M8\Rt;Z60V$?E7wKo~[Gz͊޽`zr?}. xM&}EHARb;XM뽷E]N;{7ߝ3/X 8߶3Q#>$6Xm^Uk_Nv_TU3'4N}km;55{c7>/?_g7;=b,&KOExQ!~rOŹa:sPfk Zk4$>=Y|Wo{7*Z¢C}b/L.j z=҇3? kMO_q56_JzxTT2o[oGf|^OoZ£ t<f'!x>??qDz46 ?{ů'➝3[=k_p#d5e)~|>{7=CWmi1S48_~籓!_ƌ6҂*aO[A?f\39zcuh}kq_p_K4x闃l퍭I?7DM+%.rӏ?+7=edUSQc,E@_g[`ٸl9 j[#wq}~tzar: 3:P?6(F>*MP{,ݭb6ZmZAFeh/7QMWkj&_߽3nEORkR(@O/qې#55)R>8Xa7<roPqqonn}Qӟ[m蓣sטU,2CQo-CO67q.[>f :A~6cV=iQR}V)?ޟ(V~OP?QϸM}+~/*V(G\5c 9MO#y6j/ß߸n}ܥqA5d?[2qKC xmZO6l8}?>iđdۅ9+叕+??&4=[hi>zlTɲq^No=?]g-o؂￯#OV{֛V_yS6?n7=}|S}Ƿx^;#&X0XO~^?7{[|f/\_sk$_mN. v>?Xjb߅OܜIGo?Ŷp괳1vuVCYة[?PMG vC'&_iv@f4_#!c86ɏW<T?ǎátx+Y͛?ϐ~lnmlnyotwRpsZTW[6K^m+噌Ŝ?<㏯^|VާʚZre$b ^nGnϱwۚ: 'LH1VE yX-{Κ/'.lbުA!?B/[JA.xp_+Szb֟MMJS88Rk@_[g2v|3x[ϰ6vS1iSE10?8sϻۛr\WOU}Î}!Ә?//{ v?&Ÿ~'7[C>~y=@Tղ))ޛUW'co3 {*YWUUs"xx':GK)_>j'#n>_D.8zGT$ۛ+1)xƽiLk}t7޸x7?o}n?ŭxT:$yJtUaWxhbR~?qv.jZ~?f| <_<Ƚե?UOyo}Eʟ9˩Q+xA)_O#̇G?"Ut5F}~} K8ȽǾ?8i~|zWdщ8A?>φׯX/]?\{ʪMpC ?ᆪ4]mTdSqi Sf:3X}QAJyW1_!ƴ| ᫊yg_hUTK_W+K/F}{?zo2iyaXFsT9Im{^_0Ž8}_Mk)_c?=>?}px|_K[rjx?soa^`ggCyO@F1(e|9:l$0R _[*>Σ)T?gue"Ɉb{}kqOCWٞ??~u5T#Ti)wGL?*#^Ãc{fZIi ~o?nG~RmCj/Eղ|q;^.ظ> {j[81^?6}>޶E7?b?ċf6t|~q?_?h{k˟i5n>Yy @l*?[ZT sܭm~µi m!wCZMI*}Uu˰!ro[S&93m}G&0OO )7Bsջ/_Z9-$s?^==M{ޱȳj>}/ [$hO9864V4s:y G?ƗgIȉ4o{ہmAAAj/{GsԢigů{z!o {S[Uh)Q#xcOgr iy>=b=^g_i=h?G U)*n: m.ZO!6<؃7ï;)Th5v~@bxI-onm|FLƚVbQS<On˪w[n?wc<7^x'r\m*yXV8<$QB.hwKPM ׇΠS֕ٹ7{3 `vN0_&gV?b3V؎8}OGL~{de1l撳5>(KirDoϴz\P+qe*o?PO2nǵgJ'{uue%ieV!3I 4!KmV#.Q73'Pbj3wa>o[tZY7~?.y4طo6k ol~8?ſʸ8hSPS7SSoЧ2 E~pA΢G?{@)oC=_?[u'4)t?X}#xdL?܇_?OɿonR|+ ɪmziuTWtm(O@?׷sᯡws4?uoq;AU__U_<' 2h =>ѱ(Oj(|Sn=}(OcOUj7_y_r%L)_SS[GUͯygK׷>^g+?JZZʏ򊯻oQ+܇)~UQءC1n TtuTǐXTρ+C+w韷I>`N;u<~/M+y:|ْRB <_ݩn<\4QDzFիx2_Y}F}G K,7oTG_z= ;4S'X`P~}Yژ<<M8zݧc* )U28?n ={kC񯧹Gaݭn-M?gav~Xx5{yVx*&O67X[|??oˏHl]o o <5~榗?Ӹ"K}/y}[P_?>ˆ(Oˡvo?_6M7UӚ>/?_vli <<TS>z}OeDK5|Qz=پ*Tc?!֞W?_}թY7^8m76I1uM_Q<➛&9[[jup7{~?_w Me&i /[ÔMS+Ο(9ɯQ.۴8qUh1?oM8nNZWy:?Ԛ}ks;LsUڒ ^q~!<" b<S`4 F׷{fڨ| OJ?p6wI*sA(0+Zz[^!o{ {~WTXੰrZ}˱:aYe<kj[?\yq:Qљwva+zC -dzi*([<_pE;~Ez;EMOq{A_C|wV*p)B~r(on<** `?: $:j<žyൿݎA(aOm[o"tLsFB?}6 v>?g%?Gؖtݼ|~_ˏG?S#+Ÿ:|z7G_9>J,}zfwN?x{X4jٚX{6`ʋk~虛ens'FxQ>?f<]c[&਩Śʮ>Kq+P_o7x_;Gnc`R}?|?<qbۭ|ɯWtk\}MW_ǧ]k~-o-Wɟ5T~xxNZXbx=KCm>?2q__=k~OGKJ+{^KEuSbUg;6A_/xkݑf1kMGZ[G)#U1Q4տg\׋+y~7UH1O:S>u~pn4F+ⵯ@kc3n[}=5q+dJqʕ^O W^ν}Eie18t<F#kٿ*3utр7_EQ?]d}K;`ȬgO( 4Zc 7?#nwf&RH9F(xWowƃps嚌pU1.mn,?E>||o^RV/p(kr?ŋ$0I??lT營I EX 7ӞE?!TFM ?N(4{}$/n~c~q?x[܋[1Z8ׇ_Zu`tmW%G j0f*8"IEQ}̙pQ4US G9oe`l-ڽoUTEb?ެGϾtl-Ed1}U_WS FRqEV8ጌ ^;u?O#44G^7?h&??/OͿOϳk Q1ٳ}.hk* ?j?lR*x'_h }ϝڗ5W=?j<}7@Gj{~}"8YO7Ov3.R >>}뛲;O۬QKKSgn`}ˡ,yS:}W}xjh;J|V*|eOASGUo\~&L~럴:Ϸ6mVdcOk~mǻݝA'7%\?{ Xm?Wny#8q<* _(~@b:en-ϖ}+MM1Yz>m)?kMɝW6H{Jޝ|ݛsDC)V ?U{[dOa9H?>\9?qW||\M+}AoonvOd(?F<]wS~cjiO:_Ӌ=G+6Xlt*}.ǝ/X)[ݎ*hiw?X3ؠǑW8t-)) >SKS8R딪Xj<1~7ӛFPx~Ur~}3_7}W?Qo5L9:wFRoU}޽=,?k<&_zz}#~_ٚk} ?T;BkQ<;: zV\~Ίwdd9jTոMU4LTyOf[GK)}%[Y>l?? \nW1tG;,3,߲x4LKGI~}9z}XCO|nn 'q=sKjE(g'P:b|ΡO}T>ϸ`C}HYc ?K_قxx '>M3VUOӕq[KOOMIɰۛcs͗tVb7E9f׹<\$ux`9>3X`vw3a+ˏ2}_E[4~Y1Jӣmq>:0}5~O'j3OMT {W>uJߜm"-*gd,V߫߁`诏{swomџTqy{7`iNMh|Ni}m*֜k)Lp4z9nFvj|=Oy?v.$˷kH3te-R??_?<}moaG|gYr##Q>_a_o?9v_=]ZL?\͝W7<}a^enI|Zz\w k{?#K'DP$[YbX-]~=xqf,N+Y]D]6/#5><:s  ~S:Xi*`??q֫_?}AmO0~Ҏ/M}W?K0oYzik3Io"}QWRV6E/}4}}$7ܶL?o:yμs{75_I?867Ng]ǷV_]Ws·Q[s6*s W_7d-4Oj97Sjc{S>u&kpgp_ ]ju^CI8{&۷ uk@@)NI(rjnmM-->ʿ>δSle<[=6B)QJ; 7SImBX\Az-?Q?ߟ|rUn}V3ZC2q ~=ZSZss??}/&8? \[|3 <~ TU~-jZ߆? Ŭ?kOEEBr7pA~Q W.3S~ߟ^s,?Oy6?[_<5AK\{}ֺh ʞCupSq˚Z El*ikPƔ#QBgԷϵt2 Tք$Z SC]BgTP>xO8;$TE9#)~Ml{35#L\s}~ǻj~5G??Cc=ż普pEIZHbE p3Å}IPV}}UxMyO%?}bI2dQ~}ꪩ? ]G6-/o399qO%6_oN+ 43J?K{MWAgSCU\Vy 0Ҙ&1{|=ܥok} Z]vK=G'%ϰ6nq=GO4kO U[q_g o=EC <_&?xgy֣tw[}P~c%H7 u~Ǐkce۟>W9 {c/?~x3"i)oqG7#ˇ|;dyF%Y5<;zFl_MMaTp WKJO?%eccsv?_uǏ{!_:Lcʞ}/6/)Qِo_S m$gSUDア<?Vc_ÑMOZgG+ĎFo.ܽs-C)h M5DsߓUI}US43M_}?/vVb먡#mk7W@?h3ێiizQ?.s=W?~*u MOO}y&5S4K)$}G폨+ÅZWץW_Z*iEq~v W}<o>pl[ޣ!S*ݵnXΏRn>+|4x| qp G/WoqAγ9 ˉ8cωW^ި~~>Qſ-E45??nkOs+.ӨgvMbioO9iiX^KǸoتOscNmks%Q? xQm>4>/?RC/MkP~ H'/,|t‘OͯŽZz|:hmEJ_Szz\Gieد.I7cKNh@A 0)J"-tMv׬)AiZֿE=ݥwU`bM=Oڷd ގY;%Q*| `_7Oo=Kޯ&R59`pvQ㟧U ;#&֚_)oM;~O|rnl/4U!KM?*zxf~Hl7OSd2sS??_Ng7q_3?7NlTh iw??xeDc-vP_elɤ5嚚Yny|xV_k=_/{mV&mvx8.d\҉*젯zXEOl}9?t`aWM4?_ϴkW)6(}k7+_#18=?uWw^}8l Z}=?wmdfq*0o(/nMq{X_y%n|WͿwBjy2xaRO_,o|*\5C?R~\?UZOAxmmN ?a,۳yn,:**jeB\rĝ#IOyɠjjoZK`l }A.9Su*VM:Vq|U. ?U ^}^$\OPƽ''If\y^𷱣tUbVg䧫o mPG?X}՚O\pI.Cc\|^Qxײ&ϨŨl'z +B`Kz-׹LBW ykgM6ߏdփ8No޽I7^ =N|`Awv5[*ޠE7m޿*{amʊVɧnj㌊W([K`/z637x B~Y)f,FSCW??ǟo視O97x+>ln?87?Oa3s$o(*||h 'K:0;}XjA?Wk p};jZ(a֥^Ï_:iOӀm ;\v&ۙ5Ym #G =}E'Rӆi_V[e vg#4&_?Gu U?s???a?|x_<ᆒ<#Vi_aL%oZo|2gSC5k~Xs0>K&K 3TA]OK\{6{Uʏ5O?}鸟*z:,Ǘ_**ewD>_ 0}*ʬ|^)sǶWʜT i筩L_?S \ʹ;cr+| EcIfgCo/uX)yiKp~@o?;pY3lXMK?rEo-ݝ߻;[qOPgTMEO7[[?_j>y p-=)sq_o[[Z]S6kSibtmG8q|+ ϭ*1j[T݃kߟFeLd2VjQQR~←bKK[5ċojGYO)~?O>-വxc?oܵ'/Ts<Ѓqm/&ˉ_o_1x_.[/~2cEio}-UO.=S>=7M[=Lճ|S)}ld6zKuYZS]0 Yg~{% vKlL =0/rxRS!Ko"EůM?oS'*SAPOΣ~t$5L1j)m>Л)~y?8}?nj8ha<'K_ŝ/Cڬ[y}%#O|QfFX_4~߃}ocfZo4x }=mSsO~֧m$oNZhgZ 0h$+>kQ콕-5^6?}wOdr UmXVGFlM՟|< 7_H3N_ïttdKtxeVՙ}EYzOOm_MVhZ2TŠm1~Ow;_uo`<ܯm|U%MGpO6^{$OOҎ쩩%kK[\ßmG#6܂i-oqu.ju,y=Řpui*i~hE=Hի[q~wG qW> :Zq'[>{oSTZY9墳s칻>lTU}_Y]m~moY{;QxmXTsZl@BFhqu_so?7tu4c>g3NsMjqWhEnGQ=?/oWdu)$ h|j% x_iGnjNN}?+st?ǎك}y?QAwϧY{} \-)۸|Pq 7l3bQQfT\*[!㿅_}=1YJo>2{qK/Wٞ?a19UuTzJj2UTipU~=qw1OCG9*`?~乛9 VS MLh~~?oznh)2[qa.sUլr> }q>|tu#?g8z|[잨fW {*){__°-q8/ظC;o_^LlSv_emݻc& ]ws\SM0!qg¾_}c^nk=|O_>'7oBt(뷿O2;N`3K?_pGvhmߦx^!|߹vfweo]tkCgT o⎾kFՈ&֚\Oܔ S) xZ]Xe!PV}@ZPKM1j~#=QCLy)^9%>H{o{7=a` ]̸zDPEnYRU(X돨aQ ko?!/Z|Jj "3R*t !\۞j j k7H|Yj*9Ry8cTwxEHU_Aoǽ|?^dnMH@[-u#O93Qy?kL?ۏ{ƽ`ۮ~ S4>Yֹm` 4)GVSɿ^؛KYh;aM>*sM)k?){0Xֻ5<}o<X1Њǘm~j>^X#ʴp/K'b(tsu]?ŬHMڃ1k$VҊ)8"l#tT@~-qC '~Jl?[G#B+l6S2|@)'TVSc-钚q斞 [xJL=N//{p׹sxR`Vo'}b((`//#?}wEwqKB8SWΜpznb?m@6* ~ ~=z_=ea MM_wa(Bx/N9}o~G[}ܭ2tǟo?<?sՈ6dTPkO''ݍ] $₄5ESZۓ~o-n?_n/{qPN9=tW4CpVOMěy8:iRaiij (PU[[ &a'ZwڸL]=X%k8r>_ ]v.{kRPe2WUuu%`?'7^}#||ҫF˺as~9V2o??FEU k`qv UjSU]OS[M>uْӚ[TQP@^q1E'ioj\~RT?_{O?zϙ?ONx.r?mXq|O[n-i6m(ry[P'Ԟ}#{~9}t5_#Gqu_AkmasZSMHŽ#o7p=n_?P:WՀ 9\mEfSAJE{^#Mz6,i8s2&n۝4t=U\xw>f,6H(Oamh7:iZp&$z>Yu6Ip?To4^?n?֦+\ڵ{{f9t_Ž_3Wt4pM\qcOO^-v TR=A"iqz4{OiXi,?ڀ/cȷ &<]߽6>֡[o%O)~[Y^{ -&鍫}o7CMGkۥ|SREJijJ9J+}>^'ECmw???uꟚٳ)1Mq卸o>U ?P>lxb},X?վWΝhIN]5?c2X㲪?W@^쟊X?mnv{;jt9 {[9ٽ퓺qtx qz G?ӶA:[L!/QEwW%Wv_?,x6[{^?.9P6 Gκ;c~~yi>Duݿݽ'6'yF W_kc?Z|:EB39¾5믟G3g82_Y*X/Gm6{w_gw E6"m_ E¯)&ozm^wPǏ#{MUn9˫/ls׷7 %Q7,/ydwI_AY2-X؋fdOǏ}&{.W8ȓJsCNplI./_댓grtsÖƦ›{Z mn<V8Zh`~[|ծF$h|ZH!9Rg9' }.PPA2ꧪߓ5$PC +G֧ΜnmS hr 'i]/_9u\#BƴGY6ۅJX"([o-}|_Ug?}}-i3OE#k#tJ`<k>_ӭT_O_GWڪ) RQi~]_}}~Zyq\]_#gz|ᨵGW^X߳+}M }}(܏Tt_?>qP? 8=o?}tQ^>ڗn,\M0b,Zwo=l>e sg{-7iT>g*xGl>gO1O /?t]+H<N)K?NB>؅iSAO/_o`{)5/?wzB?Rtg{:aQ0S?;}RaM??}6_oug7 TmV%TE=U(r/]\~Hg־`T W+9GOqbiwVk35֥?K[~?~~v^lW!ʪ*-Y6 ~66ǜsf%=OUTjw`czLu$QSS}ǏD7{^\ӵo`~~|c&_kN">Wcu&7 ?o 衂j_Y G4{oRfE?lǏt[m͎܋_0C37 7ӟqrMPSCP1qf4h@'#9p~Nj{jX?b ~-{}p8?56-pMaUl[\_q,-kJ:?N>|Vױ|S4Ϳ}y/{6.?S}TWU(Z,N3p<?o TQj@@?*}l qyqKorUUj(ZjzJ~ۯlM&Vyynm{nk1..M2lIQOOJNj~O{|L^i`g5ja}?_)tƪe>\|كO^YPMU Y?ſcB?cR>se>Guo|Vۛ[Eď?=0\UoؚSvPMUf=_pjYOO=kbV,T9bVaϵQxMݻ~k\~ڒ6eru{AC+}Oz??>}-}8}&@cE7c"zR?jo?ݹgs\c+sQϲ+|N趯bv&'[^>Q#[ѷٻ_CONn-n_.?+z[s˳pyZ7W!K'=SUKȯ}.m6N{Ŝ/#wqpfA[툶r88ϙ鋏/Qu@%~s|GbwOp|j';Sq.18AlͿPsl,li B}tgcRܾ++?],Gn 8ɍGQ}Ǻ-m}wH.,Brv?n/(om?Ӆ8~]!Ҿεp,7!o6ݨ۸Z4׭ -}>=梤D*5j)VC@[^ysf3n|v[=PY9?jhMN>,6/o(-jZң }hz_aq#c>u`-MM-[ai?O{<'x-p=Ƃ&'_p8N5/\+:GM5PTR\pn9{ώ'~ܔ}4ۿkՏ㔦Y9y%}Q[O&}ٷl}ujwqO3B8y|0sѶ߼&uB>aC8!P:#bm2q=('Rj??<{?[34M8oa^MUZ_k{EW2&T0oƭ{vFsl.OHh<5:O6{7X.We\}鿯f59<.в.k9ǭ@G_UUG^=4SbYpݿ0>oT]ue}B_﾿_ Jyq?>9љ}Y_Kg}~OW{.1 j<?9~=CN~ګ)4UPy [߁t{i$f: ^bR MϘ7?EۊYI}>}}n])2~ŕ/:I}=֧`;۽oO~'q'ٹ;%]SN*F?^n<-iiR<;[~犟'X>a~ڔxz!)lyb=-v_+qҿ~ܒ+|gGʃ5aj`,E= '} -luXAM44O{!F}_gLeDT_ſۘ_7*?g|!1؛OM?tgRe8$"Z[٭U\~?_hmM{~hamO >Puhp:9[}(ǯ1V?lGGC _Fj~6~w+k?1W ~HEǏi8 }?y^:yi S w?]XOK}VݱK/mE0k_gۧvR:lYIBstO\qmȟSlz<_SmQ}?\[7?OkzcZ~^ 59JMTym<[m?ytur}[A > #W?[}?{ L(}{k|{Ka*'ښS?OgCv^W#3O4"{f\zgKn6qǕ)ћm'}JXOawa/?f[O's%5WϼԔړn?<ͺ%\Gxij?SC;Ǵꫲi>:vuӶ_ˎ#pg=F:)2UǐZ?D}ohX饂l^F's'_\o8|`wXgy_Ww/Դrh~tv|<)OQJܥ7),c+]OUI5_.oP6OZܾG1EB |Nkb^{5/?}VZx?o}mSUZkG=~|}~uw||Mu9L\k2E_*}._=Q-6Wnc~' GZond}lzZ[ao&,|nskVd AMyLwuГhM<\o6޶<)>g>U1@U/RZ;RɑܝSSSZiFqih?'y_rz>brO{O njGk[!zeou4Mj˟<}9']cng?Ss||eGc>Rl~~ck]Ͷ6E=v>.;+8_oZ*3 }꿇yV-?ہbA)})l/?F>Jp={%~J8!*?wy?[w:拈$ZG{ M'/ENO^x{yTh4kjG7'vUE@OMWׇDʶ+:THoWIqo7}*gyO D[,+"L4< O@EܐO"}j>y-[{$<^ CN$fjʙWnfr}'' ς{؎@a۞}=k{P\ <\ȿ}> QMo7cZ?_/!𰉌4P~yS/w*IȦZ/@Ky/pp?\??^3]M1}}r?.AqޅY:hi*|'("Ux_U(fMU~0fKC }_y*=K}@j*M7?1?opW˩=vk #8~D׏2E3+7Clg_KrA=QCjjkN}Gfd~ }Yjx>Qx߿W^M7O~N?7?A_vHh/ވK=??'?>V{YK ~-c ~jY{ ?~AoCP@ꠦ?mi:vن*8Ao0X7Q%~m, 1E欆y?-55VS{\KK k}h..?՞?jN\z@epAaoafw40U~saxokmۏ 2Cgo[EOO*|8-Q< o] ՐU/-?}?% 6}a#x(cr)a[~_.{5zV i*F_)j) 䢪(@}DPy%TpTq@ߏKiלk[?~@MoWm65+ _bl2Goy[ ևi>=O!xSL=nUTZN> Ln_ԠKqv˰vzP\@ oO d1\-by?u>@tyOxY -$z_[ynmv7۟sq`0Te29oԿt|[!S7mj Zl-)r?\}Jǧ[6(Ǩ۟Ⱦ>|{c6&v)Ƣߟ}H2(}syl5=&1Zwn WXiuy>߸WV8'Ike`1OWo6mt!9}7VXbV{[[#e 1I9??_?[д߱7 ]ꮫxRjʮg4k}_l?}?yOj&m؉Uo`?ۿUO/\[a ힿ$b;uKS%6L;H_@ó!1DGN>#\r#?щPwhÎc(uQCZOX쑋ۆ,q#}>3YhN; omm6^"=×}YW}?*?@/~k۾c\Ƥ S{жr8}?gmHwGnϗVwzݙB?_s5YZ9a 7f\x>MW=5wr^h?.ӎ}φ8XTښz[[WoXoaus]ȡdqBABݺmhO1\_Eۛ}֔8r8M_3so~*Y_'UlC[ހc:_ع,>OQé*c~}b}p3zm*j}q c叴n9~)Dz69ut>?U}1'5g7(goO}mn8քOۏ<ǨSZ8(eAM9|Z44<g񳥻[z0 TdISmv0=N9zqco{7?w7/1KN?^Bpo7OMnuwOœ xt'Bi}G[%.'n>j8$^?Xsqf^ Ȣ!?u4y?{"3uK$TV1~xkZ8~xչ pnq6a??XX8߻S}u7Oq7AYǙU9`V|zmU[ xV?;E5=gַ[ӛ{@jZc@z~ϳynNG 2h3CEO==G?Yg>)ɾ>f7RCs?U}kjRRS?~O}tW?!KK6Omu/czzoIO>1a4QԜS_'iESˇ}~|atG?kSS)oroJj`jaO~;;D|C'A5顃s|:Oo؇_A -.+⶷aB*D2U~~">׌|dW?f<3}<] WO40O).'}޽YHo_mot?􀒖a?3xS9}obU|W8~+!Z ?q?_Goz'GkmSoo ^ߐ}m=-\j(|TTXa\GO{.pԙ[ao[~-)m(j1P8?|b X=È24GQa$soE'xc# SU]I?@œW8 [Z? %bC?qǚ籕9=5Xl}Q+{#~T~o.5 T^~^) -)bZFO<U7ٵ"rMGs ؋M'ʮGևym )OmUIn?wYx?}._4y烃kE<u#fbca%[7%|`}η-.S7BSyܯ'{uAkp~|}6;%OQ8p8N>1?o/Ϙ[gl_}HQol=o~Fn̦ SoqZ;؏<[G8.tɽ78r,-e7S=&J'){'}]enҪ:sԚOoGן< U;cT$_]qy[_ȶגKO,QY)yt4#~MK$T~cMl=%|ruTB_k[:gioCof5?~w 6_tk2 O]`4fvwomJ\ +dv.>&ѥ~|ȏˋyܟyOwGcs=I`ZyN#syXܯ1J+>֣׬˳ݗ7O3~RbOcъ {FvH~T]MsiiOW=*R?NxgԞڇ5ojzoe{gz Y7[ 5c$>LUuP P׳p駂sO< #.oS-[ڞ4hEg~?i=/ib _MOc0A~}ba,yq+])~>=vc ׎SϏ`i[:GcuC nD F !UC!j ]}E_͈Y<9?O{&o͉W]p_hg?vKd>9ްQ.ʟʒM}#pl_GV3kſ5Omp׹m5>M}-B)m(7fۨh#.==}yΧT o@+Gb#cϱ}JMNGwVt?3x<#fUok˃|]tU_r15?b\77徶,Onv;N'x4il7kI4 ycjo>,nvCht|_1>-ǻg3 ~MBsW+/oIۓI~:쮱SݮMF/lbjzx꽩Օ[zCWKMMNr8oo{G<?*pK6ߣ@ɥ>B^~ S^]ۛd)?GaX~8$/}ߧ18T\6t`q9?1n^ئx[~_L]Q{Ookެ>t4T|8S9N,SZE)PZ֙ j>&(<ƣ{ }?_-ԙjPrA{ly' <O~oM3cQڇ>ysſ޹_lٸ< +MoT~%A3Pvק~nCMEssO~ǿ63rtRE7 O'{,['.3d%\=ožƌu|ԻGq=>s~Nt-O yMk&KT?0=(G xRhZ o O ͸_R(~Ê"Z_Mk<yx?4sE'wOC,PVxOV?e|gߵ@>Nhk*qG7=|f|)k/}/kߟ?=bdan=^6Yk=G PR?eCUw}?@ÀZ}u_A]VR t}x`框#0ѷofq|{3԰,|oKs+6'#U45Wʟ#g)k?㏇8[W#<+=;{o*f+"Ο></@|P}x%i|0m'}fiM=WW׹C,^cj?Ogt_,T7B=p~׋sw62Ƣ(qiGŹ7sfW G3}5$^5`b:#-^>*>3J]= Du'/n .;cSWHš9,]OJټPqR?o\<[?n*i~?_/s.Ż}Nٞ?&#HO~>s<ѫX>w?Wuo-=_.-c?o3>U읻}`7%});9yd.oqORu1?[>LwLotg*+IUos|{7)ᆦqT}`d臟?/^a?#lvIi%aŸA-^]ZN9?.]7a-\oU^eGÃZXoz<[}9"* pTS?^ &[ob"c<3k~gbt&@j/7Qo{mL|T_lOiJ*b@d((y?jql]\MV¸7#¸3k֒X!H=z惶 &~8仛+T6;}n#:$ry=ee)WU((?\N$<}I<[[dqXVv6b{O+e/ϛ+i) CQOoh \E?5cMAsM<S}olxh!;q5.?Ƈǻ%]<*{?>fڟ 8~SW`jiſ6#}ܮOQUQ>ZL=,抶+Co^ܿ[N gS5't)sx54Oa5&=n9h8F+k?'ֿؕ vjn܆ݑ_NS5غĜ՝giWl4s(6ţ+\af{7nm'M&Opv6?oٗqiql67POEhi5q4@9ʕ=گ0z3gt@3x~v@[oqvd|槠}qf/~b豸y]KSߏefooz{x_dNWӏ=l`~ } 8W[}o+5`, ^%Me})4 bRs y YU[I0 }--ϊ3ۋtu#!Ǽ.DSb7w@ūIƑZ(> Li74dz1(z|FʭdPM5#^׷ن ̘fZ|G؏aן?ɞT[T~>D/+qG~_ꧧˇ G?5<q]3}G 秥}c~=]YgnYSݒ4蟴?Vq]T_ z_}ϰq`题qqxC?/_e\OJ7~Ic4^}.މP}Uq9h'?ODZt`f(DC?}'Lǔ7+?s}YoٿS}ɿ3,Trߟ_?oj`޹cߏUUݻzlfUM9䪯onM}?Ǔum q %zooߟov=pC|t2)KLGue;ٕmv6d?/oo}MZWGf[7_@5O<3Nԝ'ǣv]]UGprdnq{H)qGOڿ l~3"wEE55"Sh7Qk?˩逵@!xm^ɶ~}/nys_dbcŸ؊OQ~?~~1E|?o{vFc _@}mȷ  cm0S_rG_3^T)ďѿ}m X̟o9rS.}r-c2u_^~-q݉ᤛnwlPxq°X_Y{Wxȳ8}?uUM-{??=.׹\Wi1S_χ}Fl>y|A90Smx%hg%S_9!CnɞR%Ltu"KGl`sVc[*_/_׸fz6^9ʆl|?$dFi-o}l=o;fr^VSSi\OǁN[>eSM)JSʃ zWv;`ː MᎦ//s=?m[}Nu6Dm1ut}Wo{ӎx!7fRcqCQKK:>G,utUV;W{grݧF?1LG׿̻?~o_O 0Zݕdwq~^Zf`Ko̅fcEzƠC`TOUq<-_a,zqlǎ7NOU2{xeIO):nn=˶S7'oͬN<=|f <@<zp[RCU<=' _?\lՕ}w k`Vrۮ%Ԕ91~==Mۇ^ ]˘Wd)qZn6^[{+k /l ?_h1Ni\+PHx|32笛%OQW]y}>ή?8-{g54?]W߁J͊°Sx~{]>#2)ZRzf pcA'ϠN,fV7W^ŚN/?绦* (!+!45_au9\w.ە{pg(91b'X){"?w[{hOCL1\SS /rϮ|SϏʔ۝XXo[lhlAJ N3^&v|Tyq-oڊ4Í4;O.9?_ٙϨ[j/ug\4mױvMTdNCm7=ś9e{gbv矧RUmMw|.q9l [^5=~|hE3ZKy \`9xzQgblߜ5Xmɑ}o?ZߑkؠܓviWُ?7?9Avn;Gn+xT Ib2MEmc4_ 'ncv^eٿg }xכ\uηӎ?#+լ>d܍ON5,plQwdɫ탾w9*jpUR g{Wn߄ DeE%Vj}ۓz{vkÉr~!6e'5_K~?>Y:uۻpWvV7'3;sܶ8Cryu_"fõ^_݉zkĢn S N>'׷ 9ן?a6^E%_My[>=Nb7V: dgj~'ӊ:ų?ǎ6mYɞ×rpo?_O9>l;?Q0umgqÈˡ#M >݊y/Zl7|}Ob ?O?[ YGR?;߽QU&/SUW\ч뇸ZO^.vfIڗnn/7n n 1]3(~><}?'ٺYh+dUsתg]K^O Z,V+@p<>Υhg*>|B?Fia=կd7Fr+wL ˟9DZX?{Uo_O(m.xRj}xpyDYφGS?o?S/}n(oKK-TS~?޹򪥖Ms?:+/X~iej? <[ۭT)?~}5i 7uſOOڟz/?_oٟZ5C'X?K*iEOl_^ 2qfNj)?Kg<^y_ oXR֖h?ӏGܧz_SU>yh&ӠvNb4+{?3 LM9_b? E/-rHmg_ŭSo7'{)6.$QRC/do[5}52?Dɯhk㞠=WvFG4Rـڛg#Khk2+?uSSɵqQ`6_qyQf)OT/R?6O?Fn˒MG ~}>|EG/._.?~^b35LF||PY?Oa%3n(jcs5:@ctFJQ2xԤίbn횪0ʷ ZsQjkfdf ZJ,vݳSGQm_7G`򮪂4Icnk^8 ҃;^]Tk<9%/ے-~osYؿ1yίpn0Y_ɿ_c9фd&_/5c7 (3*ʏ om(0~[}3}.j)*i>_?>ű"}mx|,;3_[6^7>Jw%/#n7tKq՛|Tv.x{9C>a]]tR<^77`?[OS6>sa Wws")xSE : }ۭߥֵ#~nߝtsՐU#ILwcLٽ96CGO>ŽG6mC>G=+Jjz}c[E>f|QQ*|$nEx?Ά#M5~ҾY`yp۽k54RQ CC/Ojg#oTt?g5AŖ͟OP!< _ ]y G=b4+Eoq=ͷ]|Zt-~ָkQ?\u%P.<_=_Th2MxJ[ ٪꿋US}ǼXij?)jq`htk=}?gU}qY <9uTZ̉{"}~~ۻ/elѹk1wU:,eq#7ӛ[٘u}z_ yE[{ dž߿>S2;'??}[˨s{nkpx?SI-v۟'4Њ0M#R{Wurgs}wFb#Tg2uP*qZ_e#v]Eֻ`wyzƿC{awWZvՇ9 \v[k}#+_BVߎqboSLu]^G2tmۚ8#6[ ۣupGH}F|I6[_h()xW˪홈޲ú)18SOP#2tA)ua`iw^WAM򽙚wG?g>zϲ N?~rgߜV++tW7_{V0v1܆+9ނFPs[ٿeJR~XFE%jx}V9l!S> Ua7?ARtnʥn.ˡ|y)Sƃt>N{?:wgl]Δ71? maR9*SfBOd*GO}=صۘYSJVY?m~v܍O}qmߡ{>]L/ #(_ϳ$zZ~_w}2K?SE[W vjl~Cd447OZsazlLIG7>'`RO2 p:uV-"c]'l> gQn fFfԏGdsw_gn,TPvS#ʏ?Ë?xFsAݭ@3JEMimh'(G: T>j)Xmڟ4wSEKC7 oϵ<=1=Kwcњp,M↑^wO?j8YO?y_/O,J??3tgs{/WCMa^^ׇB+ sЅ])?_U?Y_+kgtQo45/}}߿'o}c_EO|ѡh)<>95__ *8g~_5D?}Iy__mރ j+j$238_eKq{kIlj:Mڸ,u00@9{=eS4Uqɰ{q;g;;t:|6#z?ÛK~t?R̗6q(8/^]Ennث\oXǝ8ygʞgp5m?mq>m}.^'wpl?tSKɺgՕ SE&G[݅|wgrYs!Mm8 ؋m2u*篩ŊJ\IE^T؀\zZ9>_ˮqssn`1'Plvz0P*J̏?|KjKO=8?t>ڣ|ū~ؿ|/!EAK{_Z/|7s,P$ VB@[ q1׉WzM}6(3/;k冟`%M?~_*nQ71o#*\j|tq55-c#+qf榄 ],v}<ɂP|0oj>Oa͓6IS+Gkq?i)EYf gmܖN>K[*'ÃJj>B9>_>ΊӇYGS],وi<#%oݲY&{_'E;s#E*URk=nyousO[nm4yo\@g!d8) dN~YOa~e6f&Hss<*P&wkW{ځQa8u>}aLWXiE?JZZ_Cy|E8H<UcmLyOݶ1q`(]=VK-SU٥LgN6~矯W=7+珟h0m8~G3_]CVUH}MG?D13rȒ?}pFj_oxgh1eg?ɚNh?8c1⃏18_8q,Ի?{rT['}vtEQ Oa{.ͬ>c%稨%% 9<?bM+^Ϟ}qUm_]ׯt o^xyx[/~F ^2mϚRco\* WWqUfcUn S3}7> _h7W,tҀ$Pf0=z=֠|~S:|iSU2<'aewT㈡V׿,O]Kt4[ޠ;': N#){+lg˦{_pe#e8MINK{k^xa6WaMru`񯟘8Psip.JOʼH=z;3IA_+*VWJZ?w\}9ɡc)YCq7cm>C9%Ufyۘ|Fۨ~#SRo#;l؃8i”0zM.y}W3Vo"PϘa?^B͋ۓc1]tc߲-/c _粕cv򿶦?dz?#=c+¼>b~?=*ׂ#7ꩪiſ{ 6 _>K?j)NZ__G1._-e1Yg?P__[F09[onRG ??tq-;|NhGoužO//P)g(V(- _dru^gh2{)jԿ4Ng׶>W *1L2s/}yA`wyt;rnS썫Q/J*i>2n}muIb`f+ܱ+?êA8/ b8(^d(xߵ?A-??ztbE)u6rN&G;~'wf7(z??m骛1c5[.Oj=9{wJdRPb+/sua>m nf[ִ4Jwj?ٍMhqQOySϪ\쿁3>3oi.nY{od0[+oege-fnmø>߱~.0FfO}݌|p}lNS8w Yo>́\Fw[ [ܿrn4*\p=:5}mKMς)j98MǺZ[#ߨJl;lpuA678r?~$n,ҏ ]M~.ϵsPbMG^37 L?_mp}-{&]ܝ> ~.%Hh/e?|{T!ְgoU?Ď7!qy>֦)_A_'n]?Sn?ky73~qِsS({CPymM֙}KxyPˇ@qWi[hMIC_s_,#۔HpOG__doDiņN.GLl;/uFݪSd.ēkȱ[{V-\:MKa~ۋܭsm<0)+>QeOIUN|E6S3VO'@~ݕNOBao**3/?oUqJvvP×>}NFX'kqƜ'VM>#}=vabyzRO<{/6ncw;K\eGXMmDjZ.}[Zm{޶-u$ꛎ Eէ>$׻=՛  EO?׃~8 >c # Z_̏׏G?Teο ƽ]_f%,Q\25FCO srH`=?;ԍPhN|OI4{sVֿ.ƵȈm>>>{+{+rԋUk?Kqu_,5=ng|_p8x՝okoJ~{Eťʙ+>}MnU}F~^y: }zO/O?eUSWv~8[fXrY?Up9n3G+m[OKNhcox?ϧ_3?H6{o/!iEo3U*'dOߵdscnKWsoQ+ke*#}#'g[y&f(ocC>z\FW0_ b?[Ž.*=x 8 cPh>q(AW8?NVe]ջ%鸯{03OF8psǽqpG ?J:Sc1?MxQo{l{'٢Pg/xwN,Nd[71H죌Y_6ZDq}KWUV8m~MrNջ WSϝ+SsjsE2 W8cҽ*7$ݟgWM=M(8_mņrWm࡟sԔm./#ȵ?QaT09S*=}__`Xݟ]40?c^Ο?Fô=ȟi5"sʀ<Wҙ͛bl<6mO7=/_^?1?_ϵٛSߛusq?".?>$}º'_ϷtS߽l $ڿ8PϕڝճYaqĪjj=s99o? Zhy^T짍< y**iƧu{]_?_xvڧ3-5{3s{h0-˺)L?>ޫ '[WyŗmM}VoL_imZ, nz#0;cvSy& 6G\'{/iw%M<\ *Мq-pgsk mlE)¤kRV$S=oV,PӁ|wBنLylWvķqx~<~=bl^Q 7wݕÜSk $L *(=R\2s)3񽽛ٓݹ=ϑ!ajw1Y|x Fn)US"+Ƶ'ʝ;\(|E3|zG1=y_-Fgp1'>|[)Oǭ`jܾ^KbsrBUD2w.bbNmՍ|_?=GUF*L>ғIS{}@??S۟hmlM(|NXMsP:n-\@8b=`QGEO9A"?[~?}[_qm . I [RT?~83~Jwzcmdom]O`f7;`7~C<}?]|v<] _p+-} } ׍G?w7?"l#4= Tc$S8xt7NxrWvvc2#S},`MM[۟Xn` >O#Iby'oZ^o=QvtY )8k9 {.qϘ܇SR[ovŷ]nVg{iVCB*Mh#O\\~sɌz|4``sf :nWSsI}Pe9|?۵Nݖ<|Z?m{kv/:mAūyO,Iqn?>>g3ncZ/Qԟn7M˓便O.eZo7s}~cԚj稩5/mMhq>oVn[qTΘ9rA `.f uWWͻjܙ)!ۻ_}?}ー|Js.}>~@ۓXr0Ta؜ ͻK_)'EvS 2#=?1h?6/ݼEwްv֙+kQN=?[v˅1p:?31t-4?G$r Į]A\3^ٻOLa[O3wo?#6Θ~}۶0&12kL7 rg?}&Z>mmO8W <..7:w>|HRGOav f_WG9b#] wO ÷7E/׮?^'.dqKdmSGold# o|ڔ[?hg=SXBnGpٿ}bl9\0|hzdcsiӅMEsʜiZݹݝv>Lf9j6\r?7hz?__O>,Y}ńo8b>"Nw؟:+#> ZS=H @_.$'MfhnnOOMi8k{͈%?ڦE)Hz߭ym.?X45#׭:Gjuۻr2g*/~<#{;&ra_4ܠ}Gk87^^9f>/wx]E5P#E&O|;n{y捓u;|Jy~W.S0~f?`1厫31n.ﮞpF!3N?p9Z$gA}WŬOe7^dr_[w5?"/;aSecQECX:j{s# 9a )+S{'{wr̎YfD=( }]?m_S@5cٲuB {ku)}Mu} E=x?a]?D~>$S6 Rumz*xFoŔ}X"%GU;qu,[o3KqDfszд۔4uRsaOW?ǻnϹ7n:?s*O?Hᅠdcrm\n7ᅦRCڢKڸ7NPu6ۊ1J'~coWkڀh=#ˬtܷZ;&N q⇬}a:Ӱ{Swm'%1?ſmoJj-c3،,mE6{t5>9'va{)?^9Q۰X ?pA}=Hحmvۗjƞ~yɠ"yG}zv~_~cyL?ݩ?E&J%U@? hx^SPTSdcqDQo|?j U ^c=q[rlMt;Wy/mn6fK猊\Iwޭ~~צώw&7W!zL_*QۋkێyQMÍUG]rTԿ 6X&թ*ܝ} H#}MkF1e6om*̝vp1\pWӍsB҆3L4٦ϺۿuܕF?ՓT1b V K/?8 k7n-ָlW1ySb_e+;On!-rY/: ڙ`xHh[؇ak~ہ)ğ.R|3զۉtM(&'i:@nxT(6C٪YwvWLM 6xdzK{`U|u )9h?az\[yIk ]OCBiqmMr1lO{5=!rg!?y\N/+2pi?9_[ط3#Cznw[Otrj~ =Ϋ;&7VxFן N0_bCv?gi6t`;'Q39rߟ7?Κe]퇯A ~!aid..ך*?ܪx+FS_m4?[8^ -vTzW֟~bK@)Q0?hC•zV_in#Ki0_oWVX-n<ncmltZ?9\{KO*oCw؍a"dv|fF䱼}M3o^SM՚Qё˻-.Q..99G{OuSBώ(xYݘ&>TsZbQ*z,gs?O>읓;;PLm=꿄Tq?:K{A}aj^~my~a~o7sR^$& m6K7Ҟ??e0u\.d'Wqk)gÀGGsa>g-`*Oaw?1N}6 )5X,6)JogEC$K(BrmZ:z}-W6PWdos'?ewW_?|?!ǏʔIEϧO3tv MɸO+TRY_-?$$~b:9OZP}oco ܶ\c[T"! N/^G,;'dJ@+KS[$>[mfM?CCb7zW齁XWxRc_o5(UtwSUqokvFGbXdpEqN;xۮ?8TAo ͿMݛ_r8nc+`vaԻjYhac枟*~y0+WSO?Ex+wgp~\v[5HKZMCGM5l/_s??l>&`UV ?f(~WEU5o<xmKhqi瞣???k{KPOHx}-O}H ?U`hw. _?]Us-,Ǚ iƼ8=Ú6R:ר]ёuG*i~i'wcpO[o1bx[h=r(`SsO^U6KSS*wlG+m-m k ׈9qJ`>xs-kt|}!G'Uc&Kߟ_/Z#cC>Qb 9 /&F)K3xY̍-]E@W}U/bucg~O7[},l^۵vNي*8pmsw?LdzqZt1c7#fn,N.#PPf2_g |_1= ~\Qd6xm 8v6's/l?ƿb_>)^f6o;#1{O%UrpfycgO`7q|b2}չ?W=鿊}`>WX@W勍M!N\WʜxI#+{޶C*=|F~fp?(hO/?_{Kdp9뺫r8_tf7>9v.C4ٟՏRgiºqa\=X;?W1d7V}.KeSbgb.?x6 9?ۏz Him-zSbki+v6(dm~/%HT7&ǟ[K6qM6|?9CQMwÓ<8Y  W/Ūp["\cYz8ښ*o띟Uϵ oI܎??8Y{U\q}ǰnkOA?%wWH?6nJ^:M6ǵlڃ?NzCz,A>{|=['x?PSW`ښ{k?Qů~O=>mz̎: ^RU9}?yݻzrNK*?H>O%~{A)*m&>Opwuva뚀{Aflr;SASAwpvWt&zx1y\vTT2O !hMWY S[M+]=Ag{ޣtJ(?n>{tN|b ;7bR iG뽶k|Pa6~wbeLc]w377pSSTҟ:V&_ ^}vm >*i鎣{ٮIiP;;k౽GQ;!J}7ycvs.. ŌOƿ?[[Cwg*iv~qtm?-<Nr-/R1V#s-m)P\JkP 7,OGf.6$'gr9,p_KQ|Aû;qd-ǭaoh]53yOUykNHFӏ]݇}6_bI}.[Fr>t@q R^66I΀z-Gw~9}+Ȝ~s-|]ݙc'y,=8nBoaquU"T9qW@?wEeL lح W C/lů7}w2y: E<2?s{:].Jpzpsk;.3R)=M+Os8|KGu*Թ/l-#~f|9CN/@+r-a)W૫)28?sWe(jαM]d!?}b9$6MrFkƕ|1N=Hi?7qG*i?? };W?/:܍F8¿<|c7ظ}ٹ+pS]MM_e;p}7s٭Y5u&)|#7F+zBإUSSU?8{0U\ 5f<ԿwUSʟğS?f/)#_˴q|Q맧⦘_?O~/Rhj??[g_?8Id$J_97MSJWFGQ= {rT1:z/#UK f~瓸L}ڻʆ)ggV WA2['59?=/;JW~qugbga0;KloջG[vo?ױO_@~Z|e-7Sr+'EJߐ_+s~)c;p-òwۙ<{bc?4??f7c>-۽[r eK-R~R׃oW&ⵏ5_ػSfvfp9_ڏ:WumÃ82U;;n<'/g?/{MG/O\Xf3v++ƙ'`襊 G}?)?O(puVM1(?wTG6јzxK8ښ_~-p_.×w-Y u[3_]w6~y>ka*Ao<۟qل_E[Q?o}ёsORe3qihAԚL$?cݧpSe\0XJ+?/ ^z܄Ɨt s ohngXw,[newFbjc[~Ƕ;W-cGN+Cb ݽo8~~+n?LV#;-F:t45W285;Og]`)r?6.K3Vsck+_XCO_A*GG\GծO߲xW6{첵<^K; YIG)Uyƚg1Oj:L6:Mc ]U.3"_#Z֣Ȣk܍!_3]ύ]bsٙTW`(gz[~vǓRm<:zo'??#svk, D'>~#-3=ۓ3>۟O6, m&P }=o:Vv:pNีͳsn|ǐ-ϥe*gŘ_CsLZ,>+%(୮*SͿm{g_Zq7OscߵlB}37k\k@)J3R(E> (ns^<Ns=;:eo!z_ >A[`Ow^HhvH|eb$>}(GooSv(Lc(00k}U 0^s5cc5ݾme}Up67B!fLy彏y[Mݫq.nKޛR^KK?'XCX&SO$o ?[v-<0VTP@>򚪗/qoȿ2Z8*9⨰UU}[q# w&(si|'@8ۋvcuWiZz|L lu>We8-߁C7qX-N/ hrUtfKfoOO5ya'#"m4(WKKSU?>ac_yg7Tnb1y*U? ~c!9|o"7oۧ?҃Rh*rO+Jt/'mw_$pM~TboWo4uw_1du8^;%GYS,ݷ|c){6bn/of e |}c-n?Wyt7_bZ0=<yעͺ6f*iKQMIݻ^zE4)2uU\cknF)MO5 E/}1?qOx5,CF(U-7N-o\5 ҿWʅSpʃׅi  x}-%=ʚO#/~UU`2WUm1-kEg٦ߵs &# =?leNmOnftTk8}Af}?>z 69|H6a毩[01WMSR/8o~^.OG.}aoghz^)i?+?}@y{KW5txϳǟ}#5#5OO*S>b̓pU<~A\~fzcےA_1uJjqaYof0wgf2p?lo=,[>u.ĆnA-oQ`0}7 0C)C I|~%hoR3x3uKM/wm>6SrKAOq=E/G?߮mx|CƵ$W# t8oʩOjTS'aÏi\^㭠͙)%H*?}ŠTt_*O)Q\zKs@~Ӡj٬V6jx'o}q>sj~w9W)!agml gGfOOK)ï{u6d/Ǐ;/~{xh)gZ{0۹{kn;C%J_?!R>22~` {-.G_`MQU(?ϵ*@`dP\}mǴ}_3<ՓS?TƿuuwJZjY#)DZ/^!O/@M_pC_av3{Pv†6*1iKMOUy?7,2OrOA#{37㱸)MN??f2?OxSU f2W!x Z ͱͥ+GC\\yԊp5QsqTݭ?Of 5x<ꫩ|OGiMtE]3/߹B=?\G1 W߳څwc$XIr4/vaݿ/)ΰ G3ʯJU퓺{k|x<4[ N릪Ś<H?S>ǵ=Cڛ_d*U²{\}y[mou{j xTŊ:3?OO*o h;O%nu%Wclox66-w+-WW#$Ssgw~փ"o3cG{~^+j) ?G~>ұm-Af%Q}W?O`N .g5~,fcj !~~_l0kn\=>sK)MlE޾_=۶3V?#qoLR9 }*&v3$}P??7{C%b2ת+O ]n~5oiξ+I6uFR`SwƹUCGȤ5)f?80bTeޯg2#ő#?n !3ecӫbc%GhŽ6y?zGBv[5O?Fz/y21K_jG/D/{^#[IQ(~jƏqk}K3mu=_ 9z}rm$}徠q<_ya[`9o4j?`7M~Eq}~O*>rE^$ 6[=pf7&ǟ6++q6bqAI5Ե _|[{O%k=7ܟ7]fMgXa{}m}nN&zSҵ R#ңʜ* 9j_naC[:nRR67K_oz/}/@*ٺwcgr\_-nX\Ao]GKF+aY?7?n=ml$Ӏ '&yW#s݇q•?mz x3ਪGůE/ZcX,"~z?uM}Hן-nj5M=o\M-(4yA¹uT,?WAA_<@vFs[Rd\F^koǹ>pnG.iAqnm7ٌL g>t .}WMM/ȟͿ/#R**j'M/#;Fٸ(3w؃Zcs 2?Cr'Y«/7iri}?BttOapkO>ve6Ҕɥiy. KO g>SR>!_Oiypڜ*9O OK<7e~. <>~ګ)Y!G+}>/#WTc}~=K_*U 8GU6McvIKRڼc?ݙlvc+oK@^jZଆx3űu55_h__?}?cmy6m>O% V:_$b._e?UҙkJcşϡO4'J< X|8 F䧡Rڢ"ٹAW W%YN(y#$L4:*iTrB9?uniy _FmR Ӆx J~>yaWzw*OC-5)[cϳYP <u9ʊ_}91ӟd|l|;-=8U2#-S$qevܘU*i?_$XÛޟ_{M@'O+i|yM)5g~?b??plXeƢԵ&{.z: <HxGn텴+.6Z|WRrq틋m6Gj TP`փ_xm}Ѻ5SÇhs?ſa2O2_eq!*cw$_OKɄ=cc×;_݆8V*]+M<Y06~ ?wq_a3dֻ7§7F6aA@[{KonSncsK5Gͥ3`|dKU-$uxr2S$:\Al7Ҟ4Ēkk=}=֫kWjL[!H}ߟ"Cט s4 ,w۟?m)=MY0+_Co>+O@<ϦxCt}Ï=*(<1}߱]OT*7oTW<}آ*|Ծ :IRCA>?a_\[/DB͔9U/ a9Xp?f _7ߏ{~zjOPS.9K*d5¿u^.f?IooWOA_C+] zU䡧9yc=kkA]WYOGӋ3,C== jPRcy_,OU4g例╠v. 4z ZV:W/~DV";+rn뾶C(kr8:?d)~a6S#9m)W +\햰?N?d-{ei7 4 Qx{ k7h)ORh(|׬ZP5<o#tV7G݋W=o#gkяruv*|q__qT/'_8Uoe1ZjW~ۛWᲷ y/cVwl}MiZҴ91o.sv,dR.GUg3{jTXq`\VVewgkgy] mFTO/jww 13*=Li@qb$ 66Clyqy= ٟǎ}C/vb/AgIʛsltWq/l3??t a{uJU Y:Sj 8?hr> ;1U2v?>' ̏?_vm/1"ʩHs?϶4y*82q/W_{C.H]cʕ:g: Oo_M_Οo(+kqSY}TGZ1_mo}qr Jz7Nbiq9L}aE?>V49nzMwxoɿ=[ ^3hpջsKt55_o/672iTӯl]~@`z{8F&g2b?lpk[گrEQOSdiOr8{2w$MӋ  evd9} ?p?[ }X&_*U.ݟ۟O|nJV͸n1Y \'l][bo{sNt5a^⒧nSg9ӎ>&()W{Aq+CJkOJ%~ϰ~ՏC_A>_Hk3uO1Dڔ}?װA)$[ruz?iI,2?ߨ}}w.!"qKmJvo}Uˆ>\+NowIi~U߸|QwUF/j?=wF%Z14vji(?_=-8q,ޢRiE-Ys}ܥQ`Tқ U" K]$1R ޝ%Q;bparb?;C-m͹}4ӆ)OJВn? ޙ-Qڼ/]O 1XG?do:޽ +28#p__}9_n?Qv-.A4~T)v"JSӎN|!Yr~jݯ?XUVfqXa9q? |mm]?5Od~hNaipsO<7 ?an)ʾ4zm.ݝizJm|41PP_kc=O 5RiM㿮cOn5>~O3_}JM.zW>X<}'?A;Z* H|?{t3? Duw}ȿQd5U5FW+_Oe'ݚ\Iϕ8Si5׾O#)azڎ*]{hq8A?<ߚOG{bq9<)SoM޸0&soYae?SWIi]9h238+ЏvV?.9Ϣ[|Vܩ}.P?QX-L/N(Gߞ>3%ڰGQ[C=VG AmޝG=1i/~{f{n]7;Jc R:X\Ǻ}]kZvlمnOĊvޥܟr-E9_݁]ͫA57Ϯ`$nGک~a6!C u/v##8.xW۴͵05ץ=фo1?7_wkg][fp#5ɨ#U8Veۗ6nƯyq 4p6V%ؙo>iE_^>[}Y]Sxρ!+~k˳7F6EtQU5_pk ͬoʈs3x*1[)^GMvo) swH'ƿ?QnVa eRe>|W_=%O]]Q_?v ?>7gSW5{"ZZ3VRT@Gxkq8ZV8}4?A`w/cc^ӥegK_q_Oi3S˹PUSJ殉$RGtfiTJ\}/fG=m4P%jIjڎdjRP]BTdH{p`TXeǚ)?_?gct_y;ʟOoπrxz^ix{1G H+kFjiLL4kChby#?_@V /)!~U*+'!7`SlkQjcqVfľs"2'iIW{tKAM+uUi.c^-ۏbE";zSūn8A#{.m26i4lZF9Y:@bW$RDT+ʿK_kqrlmqr>jc;+h7K+%ME%`Դ^.~ɬuZF]4 ĸxkTŎOQo]aڒYU~F+P[k~=M4\?9(D`(ONuuhgzY[q~&Yk\ΐ]$_~}ϗ?`3QQta_8O'qbn珡)c4P*+<K|I?g7]U5fߑQ3MO?S*?[zW?z=Xy`STj_aɇ #:N>W +tAKA??+oڎ upQ87~>}51~ ."ߛU/&?xsn$p(#XҔpx|ooC+'+OՠOt  L3S9,Gāt?*N3q?1+qj [gޏdz%ulƂ^B~)${_O_2~o H#{ӣӥn~]34nK"(vP9?(qۑϰWnnVgj㦮Rcq9[U}}s>{ gÀd]US6*:ݶJ{ >OtǀrBoabnfnβFVan%DyhFOS´~ G̖u1Gh? ҿ!.z=1,Oj_~}ulf<SewW ofG0_}# ?Ys/._?扜';v9W͡o}=yv6KkH%E|#-)wOԽ= zq] fO9fh6c+|Pd~B~H `pui@?N==$Lwx=vr쭫Ejk"$SϏg =1cg5I T\yh<N>=6_ V"!O|pg r7/̛{K4iZ/-n> b?_ŵX^>yڸwEUtXT?5%.[X&S/ӖtoGg- XI "SU#^&"74MaOAҨ?sy_W{mNCVN2n>TꎒktLJwgʁdM=iu "s$(m^7˭ܔlf:;֫7U'Gßf{yUf2Di)1O՛fxl>v[Fl,;{-7F#ۗ6+Ec`Υ~Q`kUgX:O{+n ~TNe?f*6}ᐮb@`YpܭՍw6,f~ >Az/1y?Lza73Kp |ooYT9+W}?} ț#]ɯ8 GO '׸ ecN6\p\z$*(-kJ1/&9S;wU8-I3礁vwrvNZDiÇԨ0Rh&RY452]wf*o>VoLmg?}jjvXXg 5n_G>BB-aO͈|6+#ikC\棈E s'NjįBڽ3OˏMU4Q??o~/M{#ݚnC0架z[__?ٯ}߮=lV[ҭc_e)%_WDrC)XGe˔ŋ^Jy Ӈ+G>{s}<AM Xw7ʼnQqJE]W?ةۘ?=&Fj4?޽Ry&^l8Cmg)y2wxѳG]UsלpzmFejFL&ψiᥞh <~uz}̐[컿*w9b %yK֟ax[uwѼ}8;"˺2{rum<7pRŷ%Kq?s\ߏUSRqbۓVs iZMUcc)E>H=՜=%SԵޟki˰ RȜ䒚=}("I@j6#kssR[Uc\@+ԹoIb[!h+Jzyt琥SYsC<ƽ,e.W1u5 ?kkr/~y 乫^?~}UW%> O/ڜTJ`Ӧ57(|h|"s'#գQWv.2W>?UUe.ס}/?w/.€ck\ /iOzl띯_2%*_D5MXoyx^)KD1BÍ ${HanXu+ 2I[y!$P.jzArn UO YjKI4 endstream endobj 39 0 obj << /Type /Page /Parent 103 0 R /Resources 40 0 R /Contents 41 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 40 0 obj << /ProcSet [ /PDF /Text /ImageB ] /Font << /T13 278 0 R /T14 399 0 R >> /XObject << /Im1 595 0 R >> /ExtGState << /GS1 598 0 R >> >> endobj 41 0 obj << /Length 5589 /Filter /FlateDecode >> stream HWnoPa]$"2pςJ%CRcxsUEI!U9/&7]dI'WEܯOw?vmz̪uɰJKVdɱQٔ'o׻'>Y+>''mfƲ#ŗ!,ww.VxCuI^VipW2 +,f^AË>n`0 ^?!hۡ؆mz26\=Zv-X4|KA%n]T+juP2)KW}\K!eDմYvk8w~Y=*ALFZ`Mjt+L2ljmO@_A@0ݾȈQQYnp eyHm]84Ld1E(~k_Nrn>p~~O:E <+̝(TOT3] Nefs}p<HU~|YXBs>6ya`}MFS!+_laQx3~pʣTyt;Wq)ucs(m6gFx>Ṯ+D AX-$ }*xOC=+8H49pp,,ͽ喈K뷂Xj{sh]wj3)9ˁ)aӗB5e`*@hQ4oSDcR)YLE-쏘't=c9T@ Khq8)% 6D-V^3+)g1Ҁ;7$ezƐzX(?(?RՂ"k.{㘕H !poa<|<,ądkQvaDmԖ Śy]F+&4l"RfKK\J71C"B1 ꃭG}Xb1(aL4)LߐL̀e K2Uka6$'(*KC-v gP:TʃrW륍sԷwpE)aJ#?ֲd'=B6үD8 ?\qA6GC=M—.bGf?wݖqbѷ2+L'|r lپjv̹qb,l ȍRY |I@\CdSK]`aCy 52G֎ZLr9&8k=]$ߠ'[U}vSli#cIHf>ݹ%1ٽ3 a *'(Z gsxiCizX0uUZ DeHʋa~SAi, D%CƚR_W74n< .pOspEa`f_ΎI邥Y4|QEM|Y,l_5^ўKԝǠyV(+@9;uG8<WDn|4({Av=;qH"FxA_|TAW} M8G%dVy^!->h_|He&X0? CK+'waq%rdpB0#__#\V$U)4 N+[3W0ϣ/3DU)+,=>*+Ji<[Xt啫8C1SM UHh- )7~ ̖).>Ⱦ H̓hDmP~>ߤ'-!q?|80M6&+B'$0\vϔ@;7ǎU^ B7~PAU<?ϐ'%Ý:qjǜ^۱˸ "7AQ3AףfWF] E_{TDAT:.L.5L W.&fRt0r p^09/"2&GZ-0NJYhI8hyr%XOeB1}7Lx*œ%F5Hw0}vۼ oؖ\ sW, {C+ɮׁԫ4Y~R a.ki!1Me<nXUR.lħFNe YI-*I"/HԾAf)WոUn: Wд9GB˸_=yo ]CY?0/$x:(P1])D"Y4J;sdKԤ E_Q9L,  (J!cy2yfjS3ylC%|32M]Pd#s!KB/3hy40| /?A=BCkl+BO.GaV i}#,mğDv^u+T@-J! ;dj@_D^A8h;)Gyq$w!o"$ s9sxEb!y53\8_u IY[>Uu>6ϲ pKOW 6o;TYA@|e!^iҝ/XNB}J2pu`o ah{3:e⛫ 733Uy0&7+SohUU}Jo/);s)(O 9?E-|/;WʟH֫2{˶teP\C,b6Q.P^/ߐ4"xHp_)_,|ԶTz Kt0'Ҽl iB=.dnpf`=4Cz;)6v,NB*dN9i5@a=(AmFNa}jǖϚ`%OԒݙ߻ Rҁ#xk yM?IН,+ 4 mտa&x% ~/}ܾb=ah>MWC@:SwΨcq\ƷmR5ui aA MM,܉M[|.&Y2Etf'b) |@`"y( <epjqse©'M?K f`[U.)2ᕊ R Ⱥ&yqd4CWl..Ӣϡ3q7'IzD(;Y޻vilmڑ7[xn&s6fqmgpmB|Ís-au!d%vM#l1i&n35Ȟ!0$ɉZY?-{z6ރ>dXܑ׃%{* TUͱ6:;j2Gv?ʓ’b83!v69y"Ʀ ckh&0lpO-!ލ0#+\&$:n .j3$?"ZH>?zG ؎S jY@dLkvl(|ՙ:7y-Ў>CQº=@unEPkP8s*dŭSē ==';|KZJj0L|\.|˕`" 5*Br۵0G IBYjڤS*$J&a6ZBp[(V Ph2t\$ qWT~eupΚ.КW{'n[Vcn9""`EŗФ{seYn"Cdݻ6&5LTjÊ<2@[P8ЬuGorā}fnl9ۿIɜ$H$G5"Ca.X!U֞dӶqp5[ǃ |"'彐DqJ FFv<R\vp ot;_,i,#*zsh:N^0L&& ^"+n{h1CpUD-l ,= P= vm ?MײdqUn#=fVSM{%\} @{R2Ju$k,7 b*"17Jafj S64`#y(XO{ΚOVvҔ#{3Rt}3Gko'VYX64,%^/v#g:!/$t=vgi> endobj 43 0 obj << /ProcSet [ /PDF /Text /ImageB ] /Font << /T14 399 0 R >> /XObject << /Im5 45 0 R >> /ExtGState << /GS1 598 0 R >> >> endobj 44 0 obj << /Length 254 /Filter /FlateDecode >> stream H> stream AdobedC m~"    u!"1A2# QBa$3Rqb%C&4r 5'S6DTsEF7Gc(UVWdte)8fu*9:HIJXYZghijvwxyz?D,,?=?~\r?'<_o߀mo#{p@'[???}6刺kc?_m?CHcIǑɷ?Ӄ4W%x X߂l-<\>-Cz4~IK].XE` ]R)%4 IbH7qji?[A ZM s:l&M\oXiU` S2'XX-uZ{|I5ݱSL7NRoǃeL;%vUХ/ITfkvv+45[+Gyl7~3gGhwNIGiճY\av^+wnگ\.pg޿"7-m‹>HnL&zl>svf~d6!G]qumYG6 O~>ۗSOa ;ŹS1!3Uxx4홯f!r3VVWds[zW=ٙgzvNm>0brd6FWcw6>z>;%(iٲ5SM Z,ScjkEwսw]%.mmV&JD8)r5Fئ?Yx.Ik {-nwguOe9ZUYJ9rxZ6+cɴ˽z|}}Cl /rNJ MAؼT-}]I{W=5T1̈́uqxLZGп;wqb­骒@2B悮B2Sȱ D t68gl7s Z Ejh7ǂҦW9*s)w=N;3%rm5Mfo/[>ibpӬ/_UYYQWMC-fk+-.?G["5Wm]`e8]"z|nmmoomn:}nKto=̻]yMY}2r5= %VBRG￧Ͽi7}9?=xm9?-[ s&}AX7^Ad/ K`\a:MZ8T `Ms"C5pmď.@6?7?NMRK_Eb.8 qء zyzyZHxM鸰,\,mnl Ԕ|4SGdiUE2< Q,BU}hbU+:xH=<ΥiCFhuXQ썇ۑ[qm̆S4Tmbk,Q0u͸[ݏ8z,v*<2u.=^;+ bg)=fFvVgtxubnN DXY)mA!XB]`=$xNۙ՜ǸrX| C6O+e+#R%EU~JTZzzXIL(8d/)(r/%^>IۨEm >HOUIOMz`e2SeJxb1bf~7vͭ >Qp-|'*q!K\~K-?t6B]ۆܴT >dܝ3ڝ}Fؙ: kǼSywKoon-ϴry͜35tn ~\_+^ͭ{bP;`w_TaWiwV l dq:kܹle>&mvAܿ/vfBMwNߛ-]U0Ʝjv&vVc.楣OչUU-)L?7>xoMYm뼦{]$U,Nln}6Nn۷۳#2ej]lBs'Ej^MEMPy(}JG0+y*T:_.>߲ɮHdeRi!ҭ6Nzkf'MU5M,gM4scx^#HI 4q t.;RƬ `~H`? mȯ* \pyp@9X/}/s`>Xlֹ867ZP O^lM G< ~YVy8Asp{ţPUʍ&X${7H:RrnM0܂ۻ iSv'$qH?]Ћ&ߋ [jnobsŹ΢J[8n-a1"y .~Rݙv]7\-$ߎ=Đ\5ň o^QԧO򮦼Tn+:jlV)ɉ&MK5}5 9L.2nKUd} H`C~^HM'O>P?ÏB׸oo?_?=@q--{O-8%@&3sK:uF=-n 6Y_o0QO4d,ަZ#+ ѨDk:M+o^(# MӏA#2fܑ`W,6 %Zcb# ܪ%3$vxP X?͛Ju"EYS2FSQi?p$^#4M7 ^9^/ްޫZtA"Fy`Xif#Q+X6dwNMnMdRdk(q~)ck2tŵi*?ÛfRQ@ʜ$kF -6&MӼZzZͳU2]-oc8zkz/vx){kjb1I7uPAz<9{xR4 ;zk\&㣖χܸ)JHiQ_Fk+)rT5:J#a+fڏ/GÍM77ty*y)=IW1-,y՘hwO5:jv׬5vkuM2)䒽%򸨆II2pEӇe#2MqwoCX0y\G AOn*mв.lڨN:֋-[Ww\ȹĉ#Rdc)rQeꠣ i歚:d1,دs|>ڟ:uzmEfDe&˵=6R\fޥ9kgn7W/2c75uTkϖvoxhvG\v.'yS*}./i.)WcwG`ٹZ ^v/8j[16ؔ{;};j>GwkshjuXvƥnLm\LL[wiSw.mjOA5vAȫI=T +-Os{SzLTK>g 9zĔuUP.ݦXNN=RQg Hv l6ޝfP.y!c7fKp7uCyiq54hj:eZvfR5L)#FX .T?ܑx/Y#A&-)Ԣ?Qpo6>6Y.XZS }A<}M?>X1^lᆭ$O`yn\q*qHEbGɸӥM@ˠIa!O$3ڔf6PEj燎> M>~YN|~y@b 6 ^Z}&/{ Qj"AsrJ csp$a 1 }&664BYUA5o` nJ{&=i-  B!PJ}9ſ{"oN~?޽.xr{[ߵ_?q)(xώ8Ťȩ#B<,"W\bGEE*NtHteҊe\:{r~/y<E#x6]50eXU_MusE_ @'u?4Em*Eu,#kqD#[͋өQ/*b B(G${ C#fU{+bX<ʳf-9ƲO2Ie.6tY>ł܅{y`-~mpoӳ1PV€\PPaO驘28 /5jjj^WubIIyji%-\U!̾Wi Vuc5EzːۅA"*pu{r%H3m#3nMѳ'1v2XoM c%&k| kN~)S7#bLR>6Q4Ի̛6OwPl]KӰEQji~l>v)]7~63zgQNadyfv7Iv~PD4K#JJG7SD$ QyMU_U4R'zŹ7ak~I&rnmT?QkA܍CIr{}RߪO2. ɿssqX}@7nO/jxГ {1T?[\؋]c{$stKy 7m#>MHN,xP q!C {8YB97r[Y~aoaƮ ?qq5Qm"ÃO?܋}\y>>, $,tMS qc]I~}ߛֵPQ"Jx7eIw*/v}lUY5 ;;IU=-LW ,@A }K;ͯǼ!K܁p4n 7#ON2x'{YoQM PUIWZ*y `55fa;u%c`$ͭ|[Rt( Uu1R}ufVIE`e}fUVN 海r5kbg%pcI'Qj"E6S2EEB ՟;,bnۯmeF_i8ι^ovnfs anE|Mݿi3e%ܹJ=nQ6];wl_0st`Be4DݻoyQd˶aޘ(BQ[uF靕ꎴ%QxeF"mɹzs;Qkڏ|lu1.#t}PcRTl g2s!OIie4LD d;+RC]Y<>3/S7jweFCiܻ%4TQdrq >ܓι\̡ۊjM;N[ H+E+Y:;C~LVn']}8ܸʍM]j>0;sa{f?-'ػנkvXTm*QE6FK Asm>Ķnm#dRn=7ԫ^C[sp[WEHr|fLN?V䳕;|y!U76/_N 7Se=VB#\F?qMah08Y憏P#@>>Q UD<lQ"̎i$~lvիsqiiqԞpK"B)^E 9UiyD&˧]rLZJY6'`9:jkik-A@a`}Ǹ[f͸0È31%E%O֬5,M=E=U$mO T"$uuTPPqt :@y W6I?Oȹؑ{ˍ`y?(ܛGRA6os7yp, ,KIkWXZ龣{6}yx&A)$X]sObn? DqpiI&K>o`~H9E ~B,!llH"&̍bn?N?W7bHn~7!<ВEAϸl 76Z H*Bmp3~$Y.Y@I䟥7\ַߨ 'A~oo6nNoA<G0XzZǐ80 g u>kZ׷H{ ;ܑhC $oVk{8߳~oSk~,=B'{.~y?sb22]nM'zT6 }ibZ(ʖ 3,ě*'Ҋtzje:j_$%-,PQQ^F*bXkn,/X\~ȍa}lm?py͹r_k^߼EAl? \IBmb4$j l.9'/pJNj-vb 2kvU>: rF/`O6 H"Pm2C$ د,fM( At}$㚡PhXdEPXYEթ`1L-訣Xcvؗ J\(m%ȴqͨH,@%UT#'TUlʵH$3$rIFI-q}PvBa5qc$REg@#S=ϩ6f˂{Vt[=Rb0T^ZcX&'jYPdLs;-cMъڛ4y㺦* ayFk2 rMY6b'/Tl=uWUUdexj dH+<ևc r 2|݅7+ÃjI#7݂Ug*,uHUS"㪪#4GQF@P W2bB(";T1(S\UE?.#2J7_\`+ ݛv7kşe[b1j*3W8hED44Z{ =e5*7fNw8>afz>T}YnmwbQq7=o^չ|f#u]U\aq٤WڡݕQO!9J GqVmX8GԸEfG&Ą|NZs!Ր#zJ^v\^m-p5FR}W+/kS>/$1Vgn 3ͳ'>Ŗۙùg-U꫶>?kc}A$^:yA|%T5W&)UI',VIUm2U-Fku]pJ&E#EhfJ5C`I&i$[IcZAt>6&"p*ĉA P,<ꄪaմTdB<*F<cڝGIWN>u,*$9$)r}.@ +X)%GP*RY] I Tkc:6UA9e!ti6^l]~o]%]Jyc $3D)`f4RI F3L%u>، "#(HR < nk= |m3bmi+v;{gQK$QWIa[E('şm*o!O5^ڹ|: DI+V6 +&¥Vq/WVY-7іJ26YW*)"u79A0d3V%2@pE>n$v$>H<pG7B6ArXj,ǖQ> 'Gŭr.HnO:`X7YG~/bH>XrCr E -qb@䁁YR/9f8j palNQ^U{ Q`9\so' VI%[{ =zy_akZc{RA!,[UE݈(b6P52('QyQ`N㘢[Uli?Y<n.yE6}.~"y68ЏӃ\H .?j y:W@ob,8or4'H X4]( EEAQ<Qnb ,ՔηTJT{Xvгq,9w QI#"J jibZog3TLJ,;+T*{"` Һ7uۃv%}߄+R׬}.Xng*h#l.Pmmᚭǁm]w^_)ۻ7;>oL>iFlf[jwAFj71U]SUR(2=Kl ߴpeo1ok0d3m^?q[7¹s=ߙbvgsIۘR1 P(騠d"._un<ٚsZY$M[.c-)x颊Ԕ&̮Xa k=:KmM7ɜr23rG55thsl|&)}9,9;r1dZuXj.lS)E?ښhڞ hb/&u5?7bC*-h,+0I,J#%cE0-xƆ??EWOz9fiX&v$XWH@ UFLMG Y~>0R$h nX4K(iid_`U|PgP>}Y#ƪH0C,jʊd7kW6 6/{W "5G VZKDcD"H<4~|띭-f쮬dJ 7zO@1l]9i%rm18À 5^C%&O>#I{NdM3o䡩\V2sOy EOwtt8#ois;,kY<>sUKG]KQh>cU6!vELhhQOWv?qUSJRe!I!t Zv5'a:U$,35ĞA#/~`@rl `eԧJIlFĂTg7 ȾNN.ZQa[{]87,~#X>$R ~&acuqS=%zo B$soŇ~oHVmQWi$ ($ $M;.,OAm_,?N7 +c#X[,'}oN?Cn>@~Go?>/Ӂrx7Qo(ar'b;*zabzEUEMJ6yЋzf}D:2Ƭ*-~63*_4UpqxN2!fruTxpϗ %RQV_ɏֽkvYsmd;q[(+jpynm|5|m֜-&~9x- Sڿ3wؙz:Uؘ8ݑO 6y3 dlr[)ܴLu^:B${;)[se7Mcru.*w^uVk'&+0cRCMYfV\*J\Nidy+h]QO)5Lӂ=Emdn\=,u *܍=,:&PO&-QSE;ꞚJjtNo__bu2,: Li:h抦H4uC+BW@e(ihCh1gh3DD#%Y$cBXUCDQT㦣Uh打Zت*i*S TCsH*Ivy'+Լ,D[[Jj$AQ*LTk,e,,԰힘$q\@%Bt"(݁;fWe>U lM$9.PS,l}NV5Q$+ czZc:vjGLZhƒ !8`irJxDcX= @uh`t Q1 sTeGFA(A7.DZ0ltj(<Ά5H0Y껹 餒@'K2 i,r1jwuRl@ϨǪ_/eYO1Lަ-pt%Y $*|-mhjQ4u4 Owթn % Ⱥ j9)YLvj3*nC>')GJj]W4y}]MJ ͺ'bSl-./5}ɊӬ{~|on:<޴9˟nS!.e"W6rpkϙK}WzeEE.vPA$M/j6ߤ$P:̯e3lÖwǰ蠬KG=:O"s;|wXB⬎h)ޖHob|U@{m*ENK_bɽi`Z I7so}r@?!~@J 7~/Z`6?х*N7~8ēacoqN[<,Ǒ{܀>ߟ͍I aGk*dC>*"*;OOy*$ޢyn~4jMىb `H&$N?o|O}ozE?#mͭ{~m@oLAon-#ZwhAPXPA,nt?K 7WO mmIr21JDDIZ24"< {~4϶% My6\ϾFLc,mMTl1O*%J%$+a>h1=ޒdzt7f[YU[ ,~gWYa[_ QM>uwݔwV~f!Cjx$L#S+Y]xK2޻kTfvOO+KGN&6SHhSEUU#BS℣,k!a4QdѵE%Bb 8LF ]ݒ~Uh$T"JiiENU%4~e5 &뻲JՊBПOB QMeDb+&k{)*$ZckOQS#o&$ƭuɺהO-JiҬHKO3539U#L:ݜxM]JOCG#i*Lأ7E[tWS.$r->GfO4]O@s}/1a!"Hu@ĆԥpEM+ISWBc!Į񅴎YxI݌K;}tմ'Z,Si>4e1-Q;r4T=ItWI<=;Ф`#\!O3'hi%T%RT$BZc@%`թЦOґ-$ޟJ=R,pvd5BEXWF}cvPozz}v'Іw-U_pnlSpn=vy|UvSno=]_6ML6bƍ§$FJ UX)bJ٩iҩĞ,Ecj8R؟I{5bYO7ȷ$Ri\ b+'Eί}4Z@fo*A=Ɛ:"X{ &_?{O#V.S`.o͸Itٔ9ફ4j-Cu) !zUH&L5mE/M\oU>kk@G7A\\ͮO#n= .{߂IȨuňBms`l ߏ6IFYX!$ZH" ==HY]\Y+8e-x9T"Y:>O?{c//ܻ\&;ubi;cAAnC Թ 2fPm%&Qq.jk'k]p8Ş䢞35?r-f(fLRm}OX =EvxCUdi欧z78)GS= ҳE ee!QIM ՟q|T˒栢)i)*ޢV$2 x"Z4d{-jkpRڞ0-I|+v@}I^.^@4I^bF ;3 Jc䒎(&%HVJS#"h4| zDUѼz "EKbs)#Ugo7- JBvVf}<zs("Lah" uեYi@HW=^P.B΋ HJ#㠭׃WLAE T:jH92ŪFR46ᕞjgjkiY*Ҡ>$db4ԡ@|VQZl}5/Q;LGJRB#L4BY겗=*#C,PNaF*DjBD'hlbe KOT艵-љ f,pTc!-MrΩNί5zeD0#RU3zmǩhkp`xteG/o|k'ESOW#֭ $J䶕$B@MFopK!QF#b΅c:Rl !di(̯ [[H#`(U6GS&FE,X )s`P9TWCIicMpH5+ ŕc.<%~Z,`2I_#r˞Jst4XTۀߙ߶w&h){/cnLmtQn͵6o0 . aQSGLRS̊ZРe6AqWK'69Tɿn>uj!E= 5 4=Bz cQpOB\RI$! ,{n/kmp WqpBܐ=F;ğ&׷_}ĐXGm,o~}R|oM3SoH1=KP16ݹ+pdKU,3phb㓨76kidu ;-?{2#+QI#b19ۻTml6x^;M&@m)]Ӑ{qf5Z*,VIj Fy5Eq*(WTG;u$(1P%=:OWBM41Ċ.:#S/jגI i~NdAtn lIVUhKCHLOKM&!!$FEܫDz,̣ TGԼE#kR]!Df >5ZY>ReN'IQR^7sjLH"ӈK9IF 1H<<.k)2&m뉭uuLtUL`y0Ub=uRDh.>V!QV6u 3JAk], :̖)'ƪCF<7jnMBxVUdv IW525CPyLki!dnd "1a*UEUIZY4I) $lňd *b4i`AtiK7XxbꨬJ"]b/U R3O/Zyx"Ii؄(ht"xVK9b fED2}=9IY) 9'@Z',ҡrgL6`q4/IKQ鐑u%swhp4 jѯ=|rҺYFY|`U#XaIK `i_e $R4.:1RN݉+k.! mVC 'jETTiy$:Y(E: R뻰۟cx%MCTT$\ Dx5%`go!Y"ԲdEbJ꾫7#<N5s T. &e'ٴeZÜP$0-LR%mWB[%AkW6Rj !UeE#RO {M.. ;a CWFpt8xSfCef*#L,sCKSLƌbmq{`.G'-k7lAE[9{ } c _ $Ioo K_kk2LC-2Ui& ;V=]]x35a&[[PX6ƺe7%K+MO949WDQSMX[!ٕ3[}r:5O5N7Bš\Nu4+VI2@rC]d)*MMNe3K$QIX!UnBdHf5+yj%)3gKeG$ed/>']+U eDKSH%ZQ68hCSRŤ$[1ڂ&G HEDO:1) $#S E w69OM49)* N(U *X:IȎ MLڈxSřp#PBKG[I4>"y*iM#%ƒ1B_iUuxeζJjYH`H"Ue/j:M>jxiRd)bs,cDS<T9>I&# H:,fBf+i$]$l$#i &SY+ܐL4]CbESMTHK(QGYy2]rFI>]"DShD7:Xak 13$(o iٝ$9թJ"80h"jvԬ$2MaYJ̞B1w$ؚy$I_RH$ GH-0&_ m_W,pS)~::jH4Eas%9:WzE#3yHZ:UGdA'KX T3=SRYj3JbiX-Tneh]^`"!}@p)*)䎚7fT'Q OhT܈\U$s5EJFFR&xuUyH_$|pXi%:yS),I&WX^;pXk"i|jLǪd,Z/URBR_V U:$BY Eh<237PXj7i̚偗De] ),EQZT&ԸHLV%tiڹ MERO /GIEBԐ2ԙ>b:~Uk'7JTqҭ>rAl.2X5'ES,l(TJƐ.fKz%)sFÍJ m mGǷ G ,-T7c{,oI[8E?Z&\Xr/B=_Á{??x-nmD~9_ 柺@*.A)#,^7pҼr}QȏAA$p [3}^ y8A߫~{f4?OPT͂3v< ؛Ԫ*uW{1Cƶfy< ]J*l+0YW#͑i! >۫to<8ԕ0d&j9l_oO;G.)ghj 2wBm}agk9Q_iG&:I 2oNYQ2TLk&HTi%?O4z<l5x,+-MEع*\NTy頯-=0ieJH8%h*];*DVY▞y7N7<$E-:oK:YJí&,v.CC _*%VENDSagZuk= {FOgB k4>Gy@rB!F}:ɣPe8XչYrJ$ULJ Y(N3EOWUH)0d&T . FrڏyꍐӆUXdxJ%FyF MƕVRV+GHaFJ(UY0gJ&mnC8Z8GK)RT+;LBӉF)$[ua%`ƞsAIyd#*j$es0}%Z=Grʚe3CY ]آ#T>x$&*gdRA.DYRഗVC2 [7@Vf*fjX"X`c04($SVڔ*\*#6O&r\G`ib{͞t5+Rch.Ҽ#Ʀ= S.X([*dGWeARbMa Z'xW3^EmmYK@Bn8'ػrWbSQMBe(s򯐏w I,hzHBFJ#Y]ήtX! yIRTSN5OFBF$I'$cF^;3{$2.2A&)V> )V5UKO"G)Lq4 Nn|[ &F(u:js2/"4 eR`I .oiS椨Xb *+B, R*Luf/?̤Y 'h|^038F)e(dcjtHO=Uf>+]4ꚪpnB>zŵk5& 4_,SC+y#Vq1XXEGA$Ei"Ie@чhՐȭfF[An86?<AWӋOǎByq!&Ln%BA=<2L3_R/ O!Zy%:?%BXk {.n~ZO9jXE dPXQbْ5VkNDvX槨ufXHsxM1D⤣C|~#u>c|\*M1}W*cܻQ]%n2mޕ_BXǧSVUnlңWm57^rdrي?˘! kCMKGCK 3KKSCHM6͕7!rye_2kBb up=}welJ7jYfHѹoxUmZ& :E@`"IaECƵfjC;>VURQdehtn|5pej0kLչZJjB6\)2I+T-G?unVpɷmlx[|%];!)q6C=K1qX,;^-%C'F}gi̖9m_GTSSW!SPRR=KT@uL*!}=+˺w%lۃu,8ͽM 5]vRV%m.6JzK!}/]gGeW1{.^yw]&+Q6DCt#-x\ufW-5qC6Xlt=شkd*hf#7}Óv]s]ۻ]dAڳd=͝b^EQ+)rU9V9߀!򝽍5=.(zڟ/Q_g@*[b}>2m qءY.7vGu7wS|u6iaSveNƣzܬeXlT%Z^IV-]֗{6j E S@IQNM@W27d%lĥV=E]KQU36R摁@`;,NKI- =$RQZ2+%r!gX,Y4re?4M9AY4#1)RdV*9'gv^cIHF"a$K2խ$ IdRdBAxD(hすK}c)ZUe"_+YVt9"fHĜ/9crC YB&$( V PUܘԏ8m+#Cf!ᚄ$[Z9fv8WT\#z$b}cfNOV3W2HZ&Sqbo)kzA>!H禖D4x>9#Td[cE S!+,Z4!Uqı57A]H𻷬Cf(dfji]Z:hcԑ(̨4*D(Um},t*},^seD`!2]#3iKHKLu Q =: c urVZ3,1KC1e$KrRyBch+1#ڽk'ŚcN1JuBЇ]|6%ؖ*+Z8zdh ’TD62F VdDUUT&>%BDZDW$6wtFu\3\7d ,,q*PI ?^U(7th*ܼUNӤ5R2R&&"}$9 :*30.PY!zRer2r%kנVMH/RKQQS;PH]^P% QT$$tʑL牑ZruIQHKJTd4 q’CK 5G 7ki F %N*zdIH*Ug׫LF`3eQ zm28]QzTvQk8VM-fWqUO}#v*өbyQ5K.)YO.k"jj9MeJ?۟ۻme2zy~ -8j:H^=۹eN-# QAS<&[mٞuײw'eǑ\F6nTbUfmd6IYb&n 3xiђv_vL;Դ*uf. ׽2șڣ;|S%kyZl^GpV7ۥjJ<6&ݛk-3 tMQ>SF/f.^:\c4 M,fo,,l-ݵsQeizw0Y]յqm/p]Qnhbdnxts!$himNiJ?ۺ|Jvm98ٙ]E#R1M(0Xl~71_e7&f7Vqn)~%DQ ㆒9dz5vb4i^fJI#IxyU^6Z460),I?۬U1`hUVIJM [,bCOsi^hqpS, dn1Z7 rOI:`LZ"URްII#_$YP߼ X#Xej4ǫTJ5KKQ,eR#P=ʏ,582(%A>8֢H"]jB[J-854C$%VFj[C;TĖ5SE9Si3UgP>KLicIRbB,W7 PonzGU璞6" ʗϨq]G:Bz9f/4 23|2*tfny ZjqRHC5,svH,~:_o-CWEVRTF ,KلIu1vIdaWo" ?'CW:7yfC `-uP;x$V+es)WG=R;i5<4!2-+f VE TE3hTYZ#Ȳ:JgPP(M|.1$xP WC,1h@rn,]ఁ~驔LWVfb++̤\" 1VTZ#Y:DOh⨑Q/ C)(,]t$JeB2¨FSȱ)V!VII9DuQ*)#lYxˬ]n5 [Jd^gD򈌥 1) 6 X2G.0dxjd/R![BxԲ3;>;zP2R'+-1tUu2UV]Cw@T*Q"M(Jd+/1klV5cb*Y/) L> =u2553R"STQ֥xIXXC$kld"L?L­~>*!ˌG < Ш#۲IYf)+|u8=ϻj%ggc7ZUܻs}ᒊ8bZy|]vS%z/Ga+Ou߂['jl{ؼ x8#g姚HV(?Ljkk35YlUӚL6J IڲJآDEG/HV(#V.ewV=FԯMjc/H$x5ө08)iiDPHh#[.BYsoI"G\\kpo Mrֿլ7V=Gg|o+6m}7NxqQGMLFXʡA=^?[MC?'/1j{L|C{u6!Q3&%hؼF6D P(*jdb_%*25N{s)df10num Ig![TV#lqu{w>!Ȭ;onɦ'-lm=J<5NnMo> ;SԆʯN٭NJn:,Mv W4媚m[?j:hd&ig6zƷO>]wc^[1Nl.ރl,W^X,vsdkp;$6ǝYE N/ql4AQ<ĩBm-&RZ Г%J* GM#ovۛk^{[`]D5SRIUܻY,s)O0wrQJEǛ4Vەx: 1a']*ԑg+0[f'8=L7>~%#4)/]N(fUiUH=TjTByAi(҅FIfWEX `}іpCNc#1H|O$OMTөtH1Z@ԔHUEi zǐfLDʤF"6 3"ZWb㎧G*9**m+R7hfD AV]BD;y\.Hj@u2X0gBK2}iR)^= %`#hjʮ/G0#چ )- "E5=< 4p0¾ Qhhsd:BU1,QUKYfbT6V׮!lѝ'Q*HNSNSSM bzq@T]ޑ 9HQ4RccT]N#O$96[:fBǚz*H X㦜 UPֳ +9UupYaIALu&xG1_"&ҥu8UEKVkWRB+@VP]% Z_Fbl$#G%%5Q1hcMP@SXeAgd qTf~%C(@$RĢ߸?kٛǬ3;utfXjt4I{h3nMK=f3XeڑEIIUW6Ep禇W/)cT"v8ΚXr+2e/դo=[+DiiTM/>(j) (!JYEגmةe *[V+ʩ^K5 O LVBx3UmsJE,G-&^V$1g[+zۻ:Y `"|IV \9熾\O&J:HdQcsUQƦۧM9omZOo淦W|#qTbe+)t^J JIiTU&o%/\rZ P~X.޹ʵ c%X$-WQ($gODW@6bTtW4T<' V83FFwEF*UT%TջVs+ya(yĪIPk:.OSSh4 uG#BJU/J4>& b)d|2P1 %4YNKN qK\,"Y$b2dfgpSyY@DZz]GkJK(d!AMl<*i YiLfOX1Ջ7#|Th6J_I5L%YuFt"2@ d)zhe{#Su3UtPA3! :Ů_juyN"X¹V$u5T-MGIDY@ELcZd hT>٘c[O?n&{_oV.*\ ,U>=D)hZ-TC][ "/'mRρ۽q׻{ x *-ԘMُ*jO>䢨4ٚl,C>6XoǾh)qdSfgn,E%=4?3W+xkUuSI}Pƾ&zBbch6v]kb6}͛ݻK%Q6lc(6ng V⯓,bZEZe] -~n J' rnK D1&ru O*M YX6u^H#1^:\8eHHչ*碧i21abK %IXo,S|]?iqt3GA7&GV:L$AK#dkklwC3~Nz #܏,I6<ޟwgh U<9J<n/{tO&3o>-yoႡT,Em^;r6^Ħޙ%Bg|{&#7^pm0C ׂ͕wv}+P ϼpRm>wJuu L`g;_-3;KO]7Nc_ObjX #Q#KCefU-(<I tUg-,zz(tSYx裡*2 +VI$j XaE䠧F,}Hu 4Ӕ ΆTDrF qBG)Pd7,T:JZZX˚q(T "BVGL95,R7lNM-LIMK-Ei?[$Ժ*Ah-J/~4外%^Ehu7)Ԥ0>F#R}q[QPՌ9qdMδ3Ʈ\ N"ܘ_Sx"9$:Y!DDlBY##M 0T-,C Qo3҄37dzPĞ@)#ZQ} \WY%JJi8A"7R˯hfE Da|6VBސz6cS*EHPC+ik63)`W}ϪOsq+7&r.$VNPi~?$wZ_2c!׫䭠{U9䧪ꖎWKWQEQ%+QU tZL\4Eg3O,GhBhogPO IٝoK{'m{m> [ƺ{;RR_Umvln7<8?qWQ&ػ/vF뎶X6,FxH>ڃC<y**'#T2uuVʞXlYS9a{ _F?T|iUԴƒ՛: Ujrv{wG]C!8ꉳjs"le:g1;M,THe5!F>5ChVg;$F:*/"}*ĉ hLqlg(C Bob?*U9#= \`~IoI,unlI(WPS,u5Ix"=J&r k*aY,^(O"+l/䈱#UcJ-D;ҩUXjq 2j̅X\򪞞yner4"D,GL:?s\~J^JxLd InF.cө9 R’eNVEZW(Y*f0tij #X1\d-EXzY/$0m$ՙ[w=vl UGMuo6?{;k'Ck6mF_{LJ:?s)މ푛&)mBg?m55IT`cd_%R`Dg6~![n-r}>[m$A< ݍO[xm]dlv!,hM._yOrfҢ m8 ^'riﴎ' ~/ }WQ^ӤN|}fWP!4X(k*i1MY#*X迕ᝳUv%qxu<85$J=׸e5'&RGbsȱivb2[N?cplM &3RSx^>h1 HᥢZ:Jh(!8L`}5$?ؿ|w?fU쭉yf7Cz^E3R%U\/Y[Me_+=by]KK=FϸsիLu2} GS][=hCc)+tJƜ%@nXlWDi~ZHor.)CU+b.Sؐ9 r%4ğne!xõLIvM&) C= JP }FRKKME(G2*I%%]fK @ 11<4r>+y;FgYXDdiȖb')5*5_jeE)EIśaTI1gaN) .kb88h+֧rx9iM) 򘫥2k> _o.}f:*]`܅T;"bhpd1jTǪEjk\%EzIWE54H*% jhF6In >^n 8g*!f8X V#PPW V?ԿsX7zYT0Yn:!*(\*b@i歞Hcu忻xW5USM5DJŅZYiQTGIVJZ֝*y?qMPem}GM=Q R2KNhgxgQTFjXL-9{VvzP$V2cY#=-y*FXͮIXqiק?/m>Gբ kpRU,7LO.㢧zLdEe"(I$U&H%LRc1;g~A+jnjf'in] K8C_6<l?rǾBK,,O6H+2|N}цmOW quwz`dzKh^*S~{-Z$QJщ# EмLXT ÆYX;!c|V&bډ{)^J>*cώUYY,]W7 +T- ,-i͑Ab~؁rXːiSB$Ju3H3 5`VJ撰LE6h^z}"V6YIIoRڟCŸpT=Lfu¨XX:HY}dUԽolEH*zƎ3xH͛ԤGVԁoYQUJw=*!_J*'@Lj67H-=y!IST,Jj%4M1g<^ibEY)I0&?pJxǔh*$VC{%;## -fr)*Dtuzx抁UmqP HIs9SrGY"ZahnVTGOǒ+CM{~#GO oTTQX7nfRԕZ(*D!jnxB-ezʘTJ8aHo`V@G-qƌ<-u:F#FD, Ȏ^5pණxj„Ȁc-Qc Qe1$7U |4M#R+A!|!}P39Wck:|vc"F?id#CMγ$PH C K!,񤁙TQ19c%GKQRZDYH;IpXdPFrxrtioYJ5d4t!8>HVtxoGvwѝbr5Qͷ *}m%rTgU)~kdvfJ6|]vG:oWV%M5lePhr8>e ]-]5=SV{.߸m}gq6]gT(52e9LNK=壨:ɏ5$y }GY5fjj4iYNSCӢU,bI tJ2֪* Zjq_Ұo * qZ W:?۝ 4HU  kV?Sk{zd4"2h«R1^])76)祂O TM@%[LHq=EED%AeT<_qV5^#?VSMU RD h*Se'u15˭DlZd ҖJ{]hsj͓\딞lrTu4uu~>\R5$iu;-e4?NKR,@Ydj2l@ *Ʋ sAUA T|D.oi" P#ɬyH+uȨU2!u3<`#P<7,PQSTÈyِFWI=*.()KaW2W2$N^U7% G2U[c*@W-HKcc l+j/}N)` vn c٘O\Zuo-[ݒOUAO|3-]N$U"cыIO /*H1xE+GMsG:zi2FG1(|F#]RZm+^iW:zluy%l'Yp%ɚdSA"؜H|i˂}}VkŝMev=KTa<2/69NQF2i[Ѫ7V_#yet8iUj0ln)w}^b+œ5] z)[n{c)Cg&c2M۵X|~`i?Xɜ/^!go-&y*Doa0 28SA_ b?50H>,"YaVL YYVJiQ3 ["JTE**J$G,M2T(Jw*0d K)1SBJeF_7VT`n/pvwwv.ř7c[FJtIm Dұ B XP42GV|wJV7K cS%DK2XE|hU1ҫyT"HFTn9*FAG5M * + R>֡ Ayj]K: Y#T@kA]@!([)3jyI ;7+d5 m`ʶb$]fM_HptY,4sCOnNϡܹ-Lv_1T256/%SMY+'=4̞ |(s838h7^hTYECE[O"(V<&(#03C'AxflozY9UV]+R@UHW[#J8厚 ]ne1l^ZyuLeCS^&cI5S 5bҤUsه 1y<l倂idm+u:#alv6jp+UM49%JQ=}@Ri+c jZXdzAF4!+WŽur0U551J9&%h[ aPuNk} g`OgiJA*VyF($ndyE\>lڡhêcsKUU zV#EQ *{>j*ÀnG;nCY j d(㤮fqE⊭k!YᒐeJvT[R h`i7F{hR`enޥeh7^WlemVV\z[c{ .-E[^:Oېoݧ<،&bFjk._ VRIR.qc&_Q?$wzBIP^0Q$HK_\ UcϷ<.6GXU4+VwJ[K.IluɭZGҍ0b"t$f%1 "^T_>B}aU\_KBF,# &F.bcbYPU/1.?S69_<{ f㰱܃(l-aǫ~wDZ:TDIB"g(Z뭕\)iK!% iڄhJzHJeF`C*-_k lTg3Le@Ki%?1i,FtLFjeiޑkDNIy$f,KzSPj"sea,ee QDaB7ggX=CU휕]goF?XY馡慠{Y1oPTno-g,cyN6[[+QW}gGi;3퉢ᦓkdvYwߠؼzܫdr8< vnkWW~*矱vEo ;(pj)EozhoB]Yp[ܽFOϚ;3of7evtvҋvSv˺><WS;'I.?ql]͡ڼpm-쭛fnLs~E֛kf1U~뉪7 :Vu)7*z獨qpmٹ7.gk\,Gao.۟nm*ͤׄ ݶm%V۹ %24Xz]&>wnݪrpt|5bvv"z6G-6JV;IDe=-A 7=WKd.9ro ,v=. &'6 :f衖<4R{}DN#*J"3֧ga ܤ0޿/#iC.S,Դ!\|&:, U~T"Ezr^QPW%I/M 'o$q㎦"e/I,!kdw+1ikVjJʨc=/izIlԲ,df"On)oWD)Bk;qOF$l [}^N6ɖdS-T$RJBO1L52,tSI}l}+ts^5rB5( +)]TϬylVY%)u6 X¡J$ͣK4AJlK1K]Ɩ*6M:b=,5萇f{Xu_5K^'UGOPb$.m u$^5e0\̒,gi^&Eo8vb4A"!iM[֝qξ9s,r(LDd * [N|zٜ>(UTP!H>BsxNa)IL^G`h..Yd*Jتf#:+Z 4Tw* X$-*JUjd?Or{Ip8mbBXSF|iCRFY Q~cJ]HRXfDxW=a01RҜ[~UqEʼn#3QWV05Ld2/[O_P./cqjj~ۘ|;yKcj7sg g)lJCaAGTŅ?i54"QS*(dLpO[:UEQMIRJ_2tG;.KV2DhDtsą75EN6I<G$qKә"DdiciirfF6Le<2TQIY!$1a"TO"-dI$B MO$!mURQ=Y NKVTp #C\P]RJazb[@rKүi "9b_W`v͍qe*i($,hui W:Tx QΆPBSLM/U̒Euu8Ȑ<ҺuiDD#6E#ξY=/%]dobtbiZItIX,B%P#A eIKYA#Qܫ+#),LѴlHRI{^׹ss .u*f#$npn:lˀ{k~eSMnWObu][cm]^]6Z-n\ V`7,aY(1=rnٻ!Bv_~ٛ؛(:vLm<7!sOol\̷fuf9U>Usnl]wJg~`wŞܻ ;/ vVᆭ83&sv*;W'72;#vr.o\x~m]#vob>.-?\v!\GYvQm*hޔ8mUGedY `-cz㞞f&;0@ӢE$ѻck򢞙5U4QVR))v*RKH"4Z+&)rZ?NgZIʗg7eRۧ"ʔZzxiR)tiaQTe"bI%!:MuGk31G5|TĎ+' <5 Jo~%d[*y?WTf+-U~luliɁZ:@첰3i85EE q`Zx}!GY5zv[[#mTZ^'学ZX#4 6);+C!O9)vACIO&bn4Xo> $:D晤7J|oxؾ&zĂEY0K>q#1q 8$%7goadjJIE=11TJo):==cRˍzQWILP*ÎSE)*%Q$-2#|ڔ/,@7lT>67H+R3qAr 1{ u^@PUQéW! NiQ*'F*YƬck+0UqT*q'Gyebeݟdρt7]l edEU~۬ 5<-&fWyO|*s퍷F6KC.3rgo&|)s W6׉k%Ue:M&כ: Gӝj3Ng.N;qٝ Mմ2ٻqSbCk6Oɳ|\{W}FMۇMsv6adN'z /~l]r9l}Ӳr{[ڨ\7#Twiڙ\3}R'&9iuQ7}¡#QwV0i q0b)g%6K00SnsIXܘ V> L쀩bLUs&$1d%epyR˽z~-߳Mhdh[A,8骩j*DsPDAR2!VСO +%`78ي*(I) 69`HJґ\]UGAK2efI8%y+UJjfgV*,Jj:6FЩ1OE$MIછ,Zx֠CMDy)x*q{فqQcjxZqTYY,tıAHSRT<%.Kȴ㔙o?c[^Ѽ:M$>G:%U ŢqUM>b0^?]YQӔC%jb1AMK;f7;W~e)m,WKL:8h8꩖CNE?S]?iCM^R`ꖜ~W939YՒ5&l,TԊ"SΞ'&Dwq :DºRCwaRnBhrXڦ|l^TfJJp<$%,qd4O%8vHg %`Ҕr ƐBk$̖0a( r@RMFd t)L 0m.G(U2]LWYR+!H^?"cW G#4x#&z, gR,rgPF!MJyv̆T. !*jOnfs!&:u%}(c +BL|Lč#p81_B1H( iPA (VFd(<+1@i6\N\oclCc4%7-jjV;3/smmU$ ]ۑ嶾:GܻqVG&11y3Ʋ/Mgӝ.H~eEpݚPŕzg?rUXeD]2Z4p߻BkŮˬB[ZsZzfZljBhi4+M%QB7 50GT1I Թ!U6 J\we"_=$RTE4idˡ`S҄,Q,|pW}zLڣfXp}D2yG,53,抢x!&i# K-Vk6*-~ ǎD"XfmQ:Ы#K#0*p >܂[%MdQ (yQaH%IDb2dшj "iI1x1Xf+ `6*&+ʷ԰@K}uIҐ0C-\sM4PH$*RE 4\Ii$ 5x͕:y\M_kJGy*ALR 1WyUp$'UkũԬT٨VFjF]u8H…؋{}*GQ.TN|UՐhTvi(YYTa%6IadW(:iI 􆲬lGڠPj<]2#pAtԤfePgklJ̱F"g*4(G+*R2W@pR2nT}אYKW\=^>Zo4* pڃJkd_ZZ[_NoTjl&u, *J oJDn&1Ojs#G-//T{kO.=YʭO'+3ՓjRS{=ݷ񽔵e`v96\SgyO %7&]Y-d;}ipMQA_WL+# Ե!b ">-E5#HƱj\t-I >&z9tGPBRDO<–Omm"V+.c3ӹSMMi覒=dD:, 5H"}b_0[vz*U,,_KB4Sy-,RTPBJtk?{sgs(/$(jrFR439xX.݁7mʚLdJ.C%5Qcj+s8}ϒ.dqqVeR*!)qiW+ʩ)/E[K\oT449:tp llJex"fxӤzzLTpM ) GXiYa@Xf "^ł#ɐU15I]ONaMj*'_(dh$4 t3ToGQ6㖴Da*~zᏢlmjJ% b,Q&_![hzAJq?܂ia4~Vg{Vehvz * 5|j)UR[D* v>AFĪLWAJ%I%L/y'FSR8)"!XH"D*d)-:ZZWKUQ*DH]:ΈfF0SY&Z3'Sz)l%$sҥ|YㆡHh'ڶOH I u!4l]7*ZE,4qbӥY:Zh^)iY#E0-rc܅4!ΤicVCE4,*ļVF+sřJbI#$_6k"Ixmde`V'U B5-1$3=zǵ*BGF4p &"JV qwXej1 ޝWQUv[AF,|NVv0$*IH㘍I*/.COa%{m~:J{ HsZ]NL9:6%512^Oǎ[~b1;>㭖xqX-9GG6O!-. ^F,U#e+hijgdV&iEUYUc[' `OXO0OQCjzu fk`v-:*=ѻw.󩬂&u6`'VVUC)j^:4+%ͷɅ(&=C4/R>Դ~ȭLc8ǚ"\>"|ivok~\B\fywg-hbvb \Tkm~V}HWgV!_YOE6F+U*C+rM3[3+wP󱔹-$6UkITf%26GVAʠ`l8͆JY`J_Nh@,E4jG+3TFkH9X @XT6Ш y''IŁK,YY?@CDd( Vvy)J)&H"#yf *݋2)g3#w!LVY)KM;q*Y$vԪѤlYW$UU)MK pQF3F=M9!_c cKuI )]xǩiѧAHxд̉r#daESpчo c_J(Π<HCOKl?B-fvS`IGG3!@RQ$D'Ha?r]F+[7gocd}R'87si -콋:Iطs4QO$5ݫKUIW9Z1nC^oGR1(+r1GK $񅕨L RWGH 8a{FauvCcͅOQ;{-7&|> /j2t0ϓK{yVc䠨ޛjŎc=ŕ}ŶwV۴tX}3wL^c~W7n*-}6j|9I2*6{jܮsʬ^Œ{c7Xc>%872nM钥9mߕhʓ>HXj*|BdZzIXuT4{7슖rK2:ex=e4IYrѽV޴_ۨnܝl-OVۻ7|vݽWqlWV˰jKI>ߕ.1œvHd/U,0,̬4'TDt2Cx+ ?gʛ}rǩIUI0xJ>"|61H7uuVDv3$so ˻UÔ۴:{cw{f6wSn,f붬y --MNn\F=09v>_-AM˕)w?`\7,8viLfVF.lnLVEi$>qb E˽wN;hŦ7z]1[A뷞hkq{lQrn[*^ʯN$kn ٰj{+sa0u* haa O%R 7wN렯yW&rkfboxGAvΊ>;6mxg}TRcwFήۛlA ùh^v m.o5[mn+D+N͵ۛ{z=[kuG9U|QnHw­JV^a6R?mǺ{/VJ|x#j<&G UomʾMwvf⭂LߊV/'mYs8=]FjhgbL ڱ4TIYe{,Qe0SNSW-!.bd6~h%/EO5JudeBVa`ɎJʤGV֦6 1H,GP43zIHKQ4_DXV0JzsEyŢd 2C2ȲJ2]Pd B,,2@h5sldm P,0J ?dcL4;#4rYU 1R[҆ĩKn ze&Z-6F3ᤆ_ahd 59ڞS0BhjiE!YLsBZD-ע^f3?Ec;KoVG3E qzڄ&@9Aũ1x <`k|f2w]X:-ўdnE]UA)qSVLSScB۝O_7[oQRd>Lw3d ӭ%UX4:ʑ=N@\cQYCM]% ]S &#kE-$&6:h扑z9֖ekydJ`̓ h:&OLV1*ԵeWB%{K|f5D#FEU ZZSdZuIc\ ҒUdUyXEH#j*IjHI$d>-Hb5;I  ևSIi맧zxbD '-5l%Il[BSyWm:hvOCZdn)*cIRiVvh +KMUG н35&Ou-NfJ\i1U*PYVb 'Rjαm7}&Sdn,^}YA0Upq=vF ,waEO,fIuʭ=A}OIyZ\%>{w\45Oi|5ՔxjhkVYiX,=wGeRuwi1j bhpqY>[qcm;c#RŹ ʜNC E \K>BLZI<4+3~)wŖXl66e*ݯ1RxT6ʪſ\L;giwU6ormV:l9=IGMuYxrfaݛq(Yp~i뉪SWmpj,߫H3Ƈm1٣=W].^l~ n\7NRȞ;#'՛RB+eIeMF>չ1݁W7u6ШuCKmVq9zUGkkh)iw:1Idxcpmnhvi7ᲲlfSd$̶T4B媦ڹiz?ݝ]g/`jwL:<{c3X` Nmy}S{͸:i1;~mt M+ql Ey`0\>?znhnOOv,Jݞ1w;^Xv҆km\."+72:ҥ5Exf^:U4eıfWv#KQ xH#ٖ-VaZYQ`Qh܂A`ۄ>۞>Zya樊tQ.L"+7b&'Q'15pB }k!9|vO e1\WxܜqTqJI墯PMm5u$STSF%fj# U?iVӻ똢YtWc4V~!FzFnLJ4G⥋;o9~=cy#E])H>DR1T娃R +Wѥ^ \R`3ۍ)[x6'cjLۻ pS?uw mqKCi)W؟2: qW{ ?ٜEAiwȭ{ q-HTG\v&Ot{w36~wA^9^6ߛq7~nv'i*)6V+I+SSb(G=u1JMܘz۪ZN{g(tOTy:EGE)j")LITr!`!P+v,m  uKV^TLȬ趣@k7Ѣ>⭥j9HgE.1ũ! L|{Lʭ=HdufC"7K2 St$(MyE,A!@ɭuggsdUc 1ɮ*P΋f @tdPvb,H2FdyKJF20R#gRfӦcKl-EEt&VchhW3)z i8:UC԰Z場GDQ%WSQS s-@Z JtWm>>'$24G׆(5"ec5EMGIQOM%DUp|3,NrJ*]M5QMdSլRӻ$~JY\$USWQ8y=C}6nr`pAeZ5T(Љy,`#|շF+ :N ѹ7~{'Z}m1fWe)-22jȧ_ψvU.F;jQ3HcI+v˺eh yg0"(M1u7)'I.sK&U$jJ髩᠞B*XҽO52vGܧ\vEN\\*"'777]\v(d묮xҲS뮗qe.>JESZX}>2+frqϖgsudյJz5DT/OA˴%9~|=LJ9f8Ţ(r_Rzy}"&Kٔ!ӣ΄ۻkjMU_QCSS7i7lbRe|2mWKtC={c`u['F풉wWY'!SKޙLZ?U*}"(ۣv;Kkѿc.o܎Z|5I 7\lY55؝91䷞̛>~ٗa흗&A(wE3]őm5wrdiWvH{Pˑ3$lnN:J@#Var{i+I&>"#23-[q~+IO,׬?q[ ^jGn+}t;zep1G]~S.K}Ս/oQx*r2442;{vEX۹WGUc@54lL6L~RrfrL9vEj E|=|pOkim-{rnƭo3lfMvOAܲAu)P$\e9Pe&a娢V2Wb="TSU 6_!ZG/W$~2M]i mW+ABqO]%=53I*h3 r?iU,_QXn(1[b"Ǹ|kwWf xznm ~`7}\f);L Q8ݳjMn;W?ޘJ{Sl]eNjVmpk;oiόtTj ${2(^{k6}vԴ{$d@]tˡURtђ/d(_+ɍAɦ-(̬K1Fɪs42QLPUav9m!RKڕ$mEJ1" *ѣ]F+qiB3TH".ju(.\Q2C%љ#*GK*ȯb!)U ż-^#bT<{(cPѓ}9.g1ոԬary:|iwE߿*ց(%;Z}&lNW'|6317oLMumy&yz߸咆i^:tqrI%itՉ`TSkCs RRW`EPUVK9$-HQЪ51m Htm.ŢCϕW7WX/ާ dLQOh*Debg>RնXPdZSW Sg*d|3LN%Ź1dre#UgMIuJhQjzI Ίr 5P%VdWH|d.{%$Y!R?R/O@%SI.{'eC 5Z $l5jm!M,Bې GnTpM$0OA1ELRaz3b2qSS #͊ś aD]=T*DQՑjRgQH$jK?[_&/~{#OS jSI-NJh!zxm5%<4SRm$4 #h[eKlFDž>mbRLFȣJThm)խ/E<;:V(@%wFq2H(V"`)wD0w}JS3t 78IOQ PIx 'Z82 WHVk?vp@ĝoeja>]7^s7[%2㱑ew=u5jdމiF%LHUUؚ{[kKS,K!Q<IJ7d;%CwSq9Z= R,dI0K YiË3MEػenށ/~/']W7N*ػΫd .n[ol̦˅sCI{F7whoI) {0 ֍yxgp-Vġp&ع;p,F#~KMF:֬薣=7{ݛ|cvoag`7QnM<.&K5+Ԋn]<<ɏڻ ن\oLX޻brn9rL.^hnnȇ|[p$JQG_U_m۶7:lNtY≑UE6c>w%5%Yf:8v(11dP@4wV)ԫUb2+j^@RzYY6"hGmWeF Y:oCv(EKK+v<ؽέ%SBG0Ƞ7DY[QZE:uJT? ḪVP"iKIOhS$f}#X6ɤ슞_כmFSoFo[*_#ӊ|^mݝK'vs>3ܻ5]%f3pIc䚥gQ4X=&; APCIIM"i2Xh⧚ tUcJxJ-D"CCIV*V9h!B &I}r}ARٽMv{"j꽼>ٕ)~yicIU:$%yFyW){ Bruc^Y㞚ILL)#-SgdeYhpesu_5Ih:ĺY1sYHuU0oY?Ju:{.'>%뎶Κ$0涳&l+dq@E,T I*V% rZ$K:8%W=SRg;(M dۛ1Vm*KX]p9 1SedIUcG$q}#i=~31CKwNozظ~^=ݹ>E1Y}:1BjMɎM)̮1TK5eU\ʳEKKѱ[i4l! ]k:IP"LYTF*&hm63Y+fF|ᮬX;8F ˴jdxeD H6[h K%<~UuuqSB%w,8Kywy4nC#?ʮ mKmcK.^U%Rhg )Q(%,JW }/bdPfF} ~ڻ#wssql~CnUݶ18iȲg͹歃}]qe<[?7O]lmTvdoŜvYӹ ;,.٩5~m͕3cW.t'}?\udTQ㧭;c;Gubf*wLj7_L\AvYGh ݻ1puyva&CIjnZyJ-÷T}GbO?06~u>yhh;`G}~6Ew&J 낛{r;|l.ݶ lVϝL^2N$x TU:iAŵԕP#j pEN'&]|$ĘΑ@L4<*x{?~7e _le^[Gߏ%$沘\&Vb崢Z@eْek:Y3ݝi[Yu;t7oZ3[3mobQ&ܘo K9NGdm%\,̕ $TŠ U7Y| )W('ݗ'm4]ZcY?Zzig4rhz)^z`/a%%RJXEO*X., vR83_%lڂe,NjS54Jy:yڮQB \=sQC"AWb"}͉Rn:91;Cn6zVzu'fC3cf@vE,-8#ğ<_2X>{HjmX<v,c2y 1f"z=>*1Sg+>FjYNtG졵 7jY)XkTrC]POO_EK #K4SWLMbWǩg6̵Qc(䙚ڙTej%ZPMRF"A#5NbI4<@,KJ lMoٖF2$1=ӦVF ٬Qo9 k)`dK׈{11<:Y{&DkQD$"wZ= ,r̶8#%V y):t:GҒB):j(O49KQ4qU&?q Tbp$ g*wy ʑýWw>vW]4{Tq2cnVķ> 11T>M%~;F ۚh&:i=+&Z'N6`V_ZU+ RXؤN"%de#ʑˤWUi#TerQ1q6ܟKvWPRQ*D x_Li.)ѩWȪ(8!I W7$I]tIk̺a~bsJjKKCKӪvkbhehDXM/:ʹTiB"3 &8‰ͱU!ing6>'G%}]rݛOn f*|6ک=>r;|gΣ5{zmZuv# OI3ۻ{cw>s"fcncr6ب7Nܐ2۶24r;i룡+2&HH"BF ]SE&DY3 FYgFLk I[%G{nm{vm;W%+ XG~뺶Ip윽.ۙ?1?];v|ݚ-وJX1GX~nؗu͕oU:aӌ+{*%T%YmS.^*T˶6ZYc}%qHi=WK ÛӧV4$3 q#4z(fO./tv# Aڵ}:em67|>-YL2+705M_UKFhqlœ=䦫)"MSO==LrLoRC$ G~D_љOSm J9nA[4}XtKM#̰$fH2]! :FK e: eQ>Y'?R ,%dLPd('uԚd4Dg=k[I A3Zo%,d-4WcXDUS"AHQ穚S<~&Ce>)!W!zcWCQ*j)8 JR$u1ޙ{; 'M[vuo;d6-ѷqXouAQL>vm-%M>Iv5ѻ$gɭֻ-`'*:<%6WGUve:o:ޓ#9wFV|\oez^vQ6vNФy뭂6}1X^>>1-sW`w3 Ty#Aqes;^]f&?jZpmmogSbmSU?Vj:j)WQU m L q mp|6g&ݕ~nڝ׹X6|9]&Scf#T ]nq[%rO6͡mm63:cY򾧴z=-4JÑpZp'vQ0sm͵fin]1<]MIe,X`Tm]M:zu.O^퍟vD #˶*hdb~!7'[c7&fw~m?{3۫3g-UT-Nl`Mx涞I0t/JxpP=jc4-$13 EUYf7Ox%R'.-vp8b#`vi3%qP(mۋ'aY</m^˻{+z̦v=j*f3qjg{=B?ј.vl^oٌXe5`Ȣ"i䨛\[RY⢥HpKw֪J*KIKUFjrn䞚8䒙f*zjz=v-i(렞>:JJ:q SjieX&&(tIAv!@}h]?#8yQeQv6R3tԮkdA&))`d* _CTI"<$2K* #/9`/%ř5\AQB\t UbX1ĝ^5߭KT/z@=Lb6DQT. U +$0XOLs#SOJ~J4ַO%,L ԕPڭ䧂%e<6,J ^U|fEhgjjZ,+Rd+S^)*~ZWaW;'7Jڊhx;!KQSMP?oԴI: ~ئ~做 9xa 5RIG9:o:,v+t~6 n3Q;H}"4ԂܡVfbh"@zm >Ro|^+MAܝnܙ+3t5kO]e.suw$at['_f-ېuy f+%B_{5J[d^dJ(1aKKYe)X`cpwJ.TH^ {f -!GNFu(Ѱt4M)hYDT-E2,bRdILAfBO pMQY8B)d_r[`^B]ٛk:fVҬ1fW*dIƙqrQCQ4Ur@U2 Jacl=[re `Jy&6F3KJUJ$y53x*q0^7:6u}m*I1 '!ܭ%mZIxr#YG:>Sn]ło]4]8˵F pPfE4jZI=54H`k]0(1YթՅi]|UDJcI-"ˮ6DGrS܁3jX`eU0#-P3VEHёHiʒ,JҬJA*AHFP>vcYwVc;SaFڴ;iw-FQ`GUr[xfq;_&{?ꇶ85cC۔[W{~8ÿvVUkmJn+qcnCzVmzo '꽱O3ػ~Ǐ{`r/jo=;Ws]5S>m26/xZO0?'Gi}A09̃ivc6FW70mVO\V3p_}ԙbvvsUy5zho]p{k v[vk7fRLb&#- K{;scjvE:7anϋ{'!ۃ77__I`ٽ۴{SualPU6X>l%^Sٛ:uRٙ-|og7^ ,Re))179؜NsTŪE>gNaTa3VDrc$4&ꤜ V02GK]XnODQ4A$8)i"Z4mLC,au& hVJj'o "'bWy*tg㒞@$` qɮЩľvvW]ŘTmKqci(poڼ+/[+0ci6ڝ-UQڴ[~&Ͻ j$ g4UqQvD XFFJxB+{-\r50YS=C<}MS%CyNe劌#SKO+ fˋ=wTvI0=UV"n_I_JFKõ&7cRSr.*H owrl#,muTꦨJ,G<~~H'l86nH܋^[~??-yt \3ZK\G,IEՋ?G_nlfW-w; gt.S'ݵTP`6豵wQf*p/R epqa2O76;{xhRU\N#C6@TmeG|;;`22"͋EL]&5o~B/4ulf,:t+F$UK~*Vc#dؖ`HC&>}bFTVG瑘DUQj|EIqkLraxۏH1*jHU$3)EC̋=RQGkhpgP45#H cU:aŗN,I9|XfdFJooUONZV>fM%e4qƎʉ<-RL@JҼR"Cy#P夀"SW\ni+xo$@M(yG; 4Lfꁸ Wtvd"i7.Pnjg[v߇ibkջyju1淎'+YzHⲓ`w 9r9Gwm+n>sUl]*A09L~q>nFCF_\JI)pFCPW%;H,oaęGEeȚoћ@4!s$Hr) JO/?(Rؿ^{*jIbEdMl.흩U{z2pZ-Qm-a;_1[Ӧմ͌SgVnx;:"ۆv?'[c6KMMQڻIC. K2AE-7ڃEotgWncvNn}56ػuojmɾvPv~XqWmV6*#6]7|]Ųg%Obނʍ#40TYKUM!wF ?M VGlnWlg˅?ǽ:{d}%Vh6r${m옰߽U~LK)*&m\}=ɘB콻=,gq{gq>Q`h17@1ؼN+2dQC=8j*uҁS=&g>mAj*m%+v%I_6wlmH/E[{m}Q%u^#c7O|353eL"_Ae1hU.S4u8܄SA%4r4KzGͶs{CPbep8lmV~dp<$9 G9cR/7]u񻇰/s_1X;[klF^mz+u|f{n~4%ҋheomw6!QU]X))+z5:_⬏j$B*Ubi&lKQ2飌4f2¬N]KKR)AMJE+=8@ҭ%xDgKO,sA B$fS0KS[ \|ۉ)hګay(ih] 5<4<XZj&!%}83^LW)玫.C6Gf*m ~nMkM_ >''e.W{Xn|wGvv.Zml]wd5_nW?r_Ǫ+{c'obqw[+c#M",d k1؜.w/-.W4{?kh_ O؜i3"":VTZl@o3(ڄֻڥ5\Ïxŋ {SmJX$ fU먞z= ~Y;ziΚ-j O#KN`enL 8]p賸+DK"U vUcUhM];:J1Qjs6Y|47;/~ume6m^3>`gqarPTX2>,։jrSO,=[S_)Z:i5IO,+1s eԟ>%L dI4z%UJ"u'-@ [ `r!EcGSdD=.5@7/!$YO5mK nԱ$wU%i22݂H RCo3$K#}bI$_TNVP(mx<6C[=~5ҢCT5T̲LFGIr@5g0`1`F*ŢE7KOKSNKUg7͏ ))G aٓ;wei Qr 5T-$Q: ԁS皩!T ,z(`j-BU)*8V7o|^w8,{ap;[oQ8ƵSc6^bjqɴ`# oc%gΡU9JIHHD RX @KK$9Y#aNȧBxݧ@`5HDB|ʢvWC(q s-]A,Y(M-yRFUd.Qu-..O/$;C e%Ԉ"Eo"7=F7mysUƻ[nEl[n+Z*+q. {ynܞtM[!A}:R،jcjv*,ɚK{Cn4t肞fMv-Z<[(Y(j޹ͣn]+3bSb/iAM."ҿӅW6g`.FحmfzO뺒mņ{ٶղtmubrha|k*s|؛updb1j66t}ٴslԮnMY,~rݼNޭ'{Vm}ۜLRk|)ڿ&f*QK7;uIK-<fKsTuU&j(οW=]5PcifP> waq]ޙK{Eg7$̗fbd3iwܝ؛W#{Gr7..{;OQFV5 qvvu&Mܝؕ=w~ʘ 5t_K4%D1QjBy%*ȏj,~jpU;`ALR$J* -D2Lj51fPC1LMyZXq(yBSMB0exRYAhᑡ-ӊeaO%H$1Ja4)xi"23G@4F(5 ~H""U6D h0 uFE$'I.,nZئHM!WV'VTO?۵o5p!%mjs1K#DcBK\iCrBٴ,TT0h|/1c&*WH ~ 1.:ͩ㯨LUySQehqu ,eKSe/쿝H;_%>ofˈ]1Fl*Lvڑa4*mC*fMe':ræjQmɨWl|őm*AMId2ehk1[zs؜9ٽY񿱷^S6ZRfv꼝~٧h[/Y&Ojnj:eQ[3Ev[N22EQ6ƘDǓŶjEVzbg6-@5DtQ[䣫1K`6B*꿈GQ 9YMڄ}{,b$,@Fy!IYxQF`꒩*ގ0AJF @( "-6 樔#+%[@'^94oNcohno;iV`=Fx,m6h"2SdΙi%.+WyUF{)w :*\5rI;$p]L䯩H *qocVN Հ:54"IDXhk!$Ann!cPu0kj޼HmERPN,akgxʉ3R!$aQZ޹M%4)5<ڪi" P1B?I, w=q pD!C4 hL8I g%#UM:G4ȨKDZZ'pPY}:aRʫph]8KFn<)/1/ev,}c +R$掺/TC%-A4Z Zsؕ}ֹLZi6Ox4뼎m];fܑd:~=ݸ6\;65MFP2JݱYݭأڸM{c+1|8zmɷ{o [ϳɾƏ7.۪4X .Q mm,imlNn?_Ax6z:k5T[p{Ү5/)y s`2M sqJG tTT5RAIG4%jf{IJ0r6N*5%LTS}% ֶ$dή߹~FnQȘ2ToU<,Z24[ .x 24OS~=M.'e+hRJa)jEAHc5QJ+jMF$"2f$eYRQodUhV1%|Q>ϊ 梣֭<\*BM}@Hd4B_, B31byLwP#p]b2)pQKݕ miIU!!r΀`BNQe[vXY0SZٹ, !ip#j}Ua-SFdY%Y㘹X?B\%fVYEįt\UNjaHKI a^(XA;>ákk1i'Jm>Ε!k4\tsتc Ѣ$$ahZn?Bcg=޻zn!ɮW=-Nn/#FCQW;dḻ7Gytu8,%}UFz"YS bijD/ ./ ڝ7BK?[C;t4@YƚuE%IoTgR^G1j Q.2I#>3 jњ-5/dUE {~?{Q{9 TYx<+'UƮz!*d\ۈZzzld(9~?dx+'n=XAlM;bɹ:3{3 JuS_a6VV1tA)˶bc&;[ܝk;`f1ۂY-`{mϺ7fh)fy:jnl#m~n͊T[Mǐ,ۗ7/Swq.\3u욷oʹ[;G+8̞tg6zK;Kow&}&KvfU}3}qCKⰴ-.;rwk9SyGkf['j%fVn+y^9xg4Th ֭]Q2 C@IHؙ2xz %O$2˗cX3Փ*qO 4%uFqaAjihGNLGQ֩8tvfMEDP* W?)z wUzxyڈZ> RRHqP;U@3@#<$3jYC H#ԙS*>A@,ܳUxjz*%=9y&ZeK N)1GN*n fiM&GB##Y|"[jD`LyjWːUVY&fgQ,͝ZĬٹQ*I.Z*iG1a (toJHLnN$:cg`g"oR@F/h$+ i%9"ۘܢ*_!CXHrNF:du:׭n.Nzjz%40H)"!O"K4hAR]5['[J1\V/=! 5=\[{&b(z+>.o'q)ƝUWh2q?6\F,dbnNI+>U.ZJvs>s X tyŖxt)*ZzKO5,E%"m>͊ya+gS3GQ[ A>1C<2LԟzKrx_I' p5A,X槨M($ꢊF/#cIH(ڪ uYjgqǓ6>d30yJ9i1d1YLvc!.+!쪁AViWnInţ'b?]n#,Lq͈zT<5ڃ߽$KoݲWϊ4=Ө\dͷOݻCFy& Y^w1l~/vs?$'Zc|z7흷ztvVmL ,^`dsPmN['YB,+znBUJY+ xR$#K=tvjTCB:7rY]{GqiMVTk*`Z)h4.ܝ'YigbII%׽,jh*k*CFPO[c#AIP$S H7"e2=ӹ}%;SowԜ18ʟbEg.WQVO wIowa-mg7r>7iEMrjM>FMӿw7i^[?K2ŴwV穩3u]QRHU='=, ܱY8%TU n#K["bPz<}cwۣpAq\/o?db(魡8 Gܝ[r[|0;z^w>{fun;CywV/l=> nw X[u$aVZ4sUG`]O23e 5OI/;3)Yup oB>$=%dE5"ofVQe+"0/Э,VA%% O%2謫Y*:(HYZ[#Z(4UUеoP:ִ}3K,I_dho#W/M/ȅ" AM s)V8~ܞE ZDݙ֋J\*Җ8YdHBI$Ӭbe GG3-=#Q)Z= O$fSOM y )q"Y_4CcZ'm YNƲASyo+ơ (Yd‘=S%KI24㣐SMThiiqTN5P hFEAy yZBKH)yuE;*q tk(yi1,5l=4*" ʰd+ZɌmK'$ZU,QgR*$Sw ,K}/en<42HJEO-G/^@azLCƋEDVh3Hf 4H"aTSokWc,. N,lHf (Vg*% ;4F?p%ܡw!SpG//iLrFf":䮠6EU>`>Kj E DYgU<4(cr`ݥ`-?yط᠒\#nV yu8/jUlKlҮG;$;yyi;.ke^Cb 5nM48m0fmõcLKe\㙿=[2rB+Y.ί[s{ ,hw xj)hpnʊsb |~EュkG[&56M XgS&,UXH]ߕI=blK:T(G[5<*)uF%lӭbsU-#X"/21˞hd0TDت ,J?bf#vaW!N1iS2`]t3zʬ;fZO?( Yzqڃ߽%6e?Џ`Cvm\yݳaj6n7ncp;goyoJS)3 V9E6pca2Oc)͒diH)&ZydWZI⪊)Q?ȏte|F*M&r9xryc U7K(7Zd۴(2g+ LjU&:GYAVIR$UtupZ*QOw>[]m]ٽ Ъcvdd? Wr\MT,kVS)w.ˣuž61j>h6nhE%{% M6 *\mUR2IԵia4,ON[\>!wU\G!Q%-mV>ϵy,joKQ!򛚭|y()*.ewLer?I{Au8JGUUyv}FZmUeWd6=48ʊ:,.۫ȮPfa~Ue%E~_pdrţ+rǸ貊LUd#kA•H ,ӊ񧧎>o8 ϭC {0@p,.Iܓ ꊨ#BFDH)Ɠ1 &U"2em*ae1cKu?>@AݝU;:hj^@*t:y]/=M;q EU+HQ~3,A MQPHJ0B9)e/517 Rncf>7~+tŹ;]Q7棭26_6\[b;>cHu~qYߵ7S)724_ۻO!m4k*흟~Sg4 ;.KO;"vT;/6w!wN[!'5N3aIۆ0O?9Iw. q\enMԝw|;n'Pz7d~6ojM7K=D퓓GvNˆimy~B썳o[|k >cf ]>v+}[۸Z<DrY$k{vml̾3!W(1\OfB*!d( HVz:|VEi#&!$j@ΑTBdZg%,FZRje2PE(π;o峸^Y]˹ 1r<㡫ܕcKuQ* 4UTU-ԻPyd1 NfǖUUBt`+1mdtT5LEE`[e$YrKS.1۹6:{^2X <>qbN&"%nFDhfyFj~sQ0%>eb8xZ⁺j5zwd2S <&(t0,u444*j]7zJIi4fS/l-AM{qrmLyQm3e06JjwtT)3탷r4t5y<7uNI4GtfK PQC+6ŽEVdS+XZW OS1x=<G>MAI2 e68 NZirLTPI#J5{)Vڏ>pml&jge1jm'pMWG%=U6'4._5Kmcw./gPLKvdv橨h3\gpPE v^jO.?5aoidn,~RH=dMØx]"I4%W1 Y4h䡙$5,[]!N l` <6zjhV4?pĶcC .K9@-x:,uLucb,9b#<3(<.= |>Ua;/PghiGojr<ƅ\|0GpL敪ڲy,xwʨ(r4y8gRfd2c9 ne@ O>=w}f۴{_ OTor8\>jWaFj]ֻ]c-vfzrunM0 *k?y:dvgXuF,Nm=CTﭩ[71=G $[޷+۳mتڛ'b 6~휾okےMj-ڒPnG[:'Mr;pmۉv7OKMuGWg쿌V]vaWpYpܵN7QN*hkh+*j"J)&Ai̕im鿳LMYrm[3[dn2;_y}[흆ո Yw&ooZ;Rn͇A;{g6` h$K4W[4^4j_ey$ZFZd$ѥt5urճ%YYYcI",2HbzdN4XFjtBew#q3S̑ET#'Հԓ,)h5z h?_ Slr;cz͓.VRM*ZOWZIi8=L-73QORi $=~̾G$`iOL,tͦ1S$*eH~Ҋ!M]ѩ)Lwl+mJ*#RM,=[TTbΈ9jZjT**xg Q,wꑔLo$Y4T0F&4ķԳJId^͘^] N\F\Y#Ԧ"] *TM;E7gMUgbik`c$QyK+!"H>Du~,yO+ԛ ]FK|GC>/3SG26LtY(t)!nQ|>9` u5iS#=hhP ,2!Jy#s3ܩEQRѩf*k>eQ~'+<ȚJ nȸVaV*)sWq`k2TLfW!Ӂ#z%d*1|g5Z잷MRɃ;x]w.K99vZjRH1df}u|rL$ QAIMKCGKGCKECC t4tSR< H-̯ËGEI HԂEʦ.y M,aV1ofnQVy|$l2xj CiS~$yzjIjyko#J7> >lt1+VHklnl6n-_O桮YjiRz*y)iત*7~x2K FXj5I9Yuy+4L8"@YZ7`Y{8em<+>;#EFj#O_OWOKUQT㤍H #%=IZfx4Liʰ%8Xm4FfQ, X p'97暖vڛ*#$4y=ӏx G7fՓɰٽ]Ak+I2˃=s+gvTCW7F>~lvEN7 ׵js6vn;l|Yהkf܃ie"N{ ~ enGuf~29ѱSWÒvV벩slo]]M97KJybv6&h]߾{midRP`V]l0u;yKΩ}݅{vf2j[c+<3FAK۶7-7jn댑[|le1}8wNavsO[WߜFow_!rOW[y@I51,B @D,ʋeI$*/yUA 錔hU+0ftVDu+"T,wW|ϔeq2ws Fꬕ]ݻ7Gg>LEUfm\ĥwbJ _sovE.y g;gY0X][om+MÕuMr[!QvjvBVM᧒h&EO4I#j^3-pF0Rpj'ݻ?P4F*\:݋<)$mKHLh1K",Fi%R$!4Fa~>#<#)4ˎ dȵOrյqYS/G틍o=Ey9ذVG.V(T9n$z\es5b')+:s >֣a mc]6N!bnmZj8%>9ɎlfwASUU852j5hT*<}.m?-8֋Q6u`?[>SȲOma%LYy#{-vF?l5_u; cV-Mn@V"O3ʑ) !\9(ˆn[S$,c1-# V?g;^7Ds'[,tx]ekbdqNSG>LNNh8,WmGYMPRe1Քu4Ye|+Qi$!S:UcTsOE9榚)^O{m` 3Qz'&UQTȥX4v+ zY X{g-o7=V4j-+ITUH~@7n ~ʶ*6He!I[uUyzڜ5 <lhP*II9"5 )HrAERxh? ;GoG|䰙21xM%28|~G3ʪJHfLE~_#)5GKl Ԃ3F\ Ls!=-{}hirڛkR᰸۸$lowwFgEAKkiI6*;ЄqMef)`iHuʲ#4r~Y>=\aaj4U%h?83y>"\H\C+22+?P@t#45r%$#QЫ!d@JI6qu7nǾ*RanP0}JnZkɧ"`,L5$W QMmAS\H*f4Ԍ0 9bq JkZ*@tSqRFqI =JOUGL4SȔ!! XܼfwS/e|T]/c>ʻ|a{>]_V>ȅZ[8*FCä`0|jdwV0"b3MC;[O.[ue7g{eڣ|ðoL~>'tmzc?('ڳ.Nc?_ ng\F$g^:=4==6Իyfz ;;5wFٹZt,hmb6x3u|> &i;sp &F޻PrF 2%3&1!2[nn>=]+;_MY֫ ÿؽO=egz3{n*)Iuؽ븲Yv~ꪭ/Xlٝ]w?yo޼`+v/7vܹu&creZ9^+2 Y\w~Ð?ޙ "W&IYޖ\}=:2ZaS2 LdlmDu),J?uGkly/,.qj:: 7J$S=,O,Z)ޗ-PlvQ zzVD="8tīAK 98x% t%嚖BAW:GgBSQ HDfD1H T7uzHaj)@CFAF1~ƑC!V[ HU7iPu()jU5&KuIjjY+ZYgzZj"H|銔L2(42J.Z;5F|IxVCdt>)4̬]B*mDbPX `lzD3{l]%"b)*a o ͝4Q=&Oderܾ*'Fzx^P4U \[cSbjg9Ӥ0tİS-V& %=NcnPWS>LOM "(UH l=~5!-$춞%M#YXlB8":"D5. p5H쨃]UoژK%ifZgFNfbR[4W8F3&ō$/vZF[&4^no8aWxP'֩w]2j*0ifeF6MOc&Rh*idj(+649ۼ~6Z|z{-A8>zAYZTyxq4+l~l{0 _C\϶`aۡhX1yii m] ;K~Yii'/S5:UqCM=|~)>/4r<-^!i<,K TY_JF{H ݍX~=yU,@m!l2 s3Pl|1#&Bo^RLl!uj%Cj*#-,0=^=or@~ 礐B)F *BϠo} ^.`C=J] \*~ E;M$t&VN/))m/.gWGUC]=E5 O8*%*Yd1To l>N媅c 'VE*Nx:Pj1R:T)j2S{R8)@/1#E W#\%5,S`+)Y\73ҴNf;v6&Ǩ-v;SeaQl1]mMϿ6kmMlbwS=Y˼b+>?c=K[wzkb0slϫ﮿w;{ qNo^86n-s omf/+{ :cgVvq[/7=-W6bׁ=q.9pK۽yn% S_m|ܝ~XǺVI29j,Wjyru(Z<-1r)ރ1cjW 쿓WG)rR,e@nI9$ZSbX%(dI=.LW֑ZO L'p`I ""$h/PM*]ﶨvEea)UPP[ 3ʂTLKZbsNcC36c[K݅S#G{8aNYjbD?'Rj%TBRٯ rO]za TYGEh tWS!%4bZM Eު]gx'GQ;U>qf6+WKZTdi 9{~^{r'I1fXꨅ|E6*gb8|bU7cVaI ܙZ_LMustj2yT !8(2RK# t (Ĵm!]l!sf5"HƬ}r *rUfK8$*\~A<;.rj(Ɋۙlj)BQVh'*aRʕ$3FꮵFfX68I1hjFy$zOPҵ5LU"`[.fu{ۢ:<'6 L%:QVb70I=6\D]3cYZ]EM}Ki*1SSTd#í.I?e GU1}&)sXJO Uic*+)TWKNe,iJhc&6dIe@hSe,Ɓ'Hkjbj+Yz^xM~wc #sK#D *Ʋk FrX Uc!iRjkSO MY7 _UOQ?M՟01k(=yژ]uf݆*̵;P_(c$VtUc j|{CzקvߤOg4#j 9jddjiƭ!dm2o5Z7zdz-xji?6nWNS.G5OWZbyk("S9TE }S)\y'V@7g"0/xmҩD#k%gTm $yJT%,qRӼ2IS (䥞|0$A4K;"J2cbg L>,T5BZlmp%QLA#1hQbrAqbB2_! ~"t>^UHKɎŽ:ɰii^-9I9|fV)9Xf$u-~%8*3kQ+Dby9\ˮ&HD(*W%&ʪƏ,DPG$0Iu`pG]o[U$_/ I%5$fANVZL$^=$ѽ^l޿=Oً)h޲6e 35N犵5 1|Z|B`Jenڻbjw/%vF\n3mmiESWTeo RQX֤Z)D#`JP53Ԃ_Dl$31EAY\" 33kB2xВIK+3h=g*UZjt4Ƞi :,ϥ>P)gGMUSSJW4HLѴ+ZڡOz[3c;RY2ᑌPUB̤,Yd((XVQO Ҽu@cT (M+y 7uJȭWW&,ꫨd"2ȑ&mkP$uGveF/jѣA$OSN_nFSVSc^h%I+h(!i)U&y!ť&,zO{hRR\ƗrTfw'#Qk뱘05:V=Qc5K[7Dt&J*#X5^a*9UVESؘ./ntXZ2;RTV`1E9A(7nG2;ZYk+1ccs m2!.*'Hj*al{; o ?3>zS|l:Yz9n=ёMّQI1QmZY*tu]]HS&n*UC=%aI,!Pѓi( ,lY(Gb3MOw$}%CKMCID:g5ҰOvxmUK4O0&?U?s2֤1Jڥ$JKi%-Wt$,"i`+ “swP{JѶ!:&7 2P4߇[NH1Z*'APMZFeuPz !Vx/d f+%o" X:YJIp gY6&H&NAWjyU** 4PMNO#jhHIJR91G#DXti#ƠDTU Ȍ4UEWI+#Y`IMG,tm'&5H@0*:Yh ,43ITR#tx3U oUS摃2WO$iR !hZU3Qil<(d F }FbIU24SK!Zx,i5P4f\֥8eݸ 5\\]&fTei JzLehf4Ijr颊y&Yjdxg&ҭ@E,0S,]IQ+?uSd%yvƚҴY^@43W>Z1%\v**%,E-aP%TuwVeQU3+=UYuHRJI`e2ƪ*S#"8@`J`tRZl.G=t,A. ңMD $հ/vYY/O߷%E=9mʶJlfr{]059󛎶䎒j\wtgboz~Իr#ݱWb]dlfYmmWs061r$A[v6<8%C;"7f6KWaI?z}=7=|Y>*\qTSV@)-m!JtfeXxj Hð,I "(VPm~lyb2Ad 4*l6 R&gY8a=i%ZB`ŵ`AR\Af] L==$36PumbRqfGibTUCݽD7{1xN=Pny$6U)UV+j-7SS•c5\_nhvpRYc'u@)䁣'XS䤒Kۖz9$:+SSK!(d:TLVK4PE^LZ(jP f *jjH LAQOWL(bʺ#hkq ݲ!x}E6ަTK<-ɻBc*+a}ѽ3,& ݩHN/VSC+Ian 6+%S䲱ert $߱ ~fCS(X^UXz 8OZH%YijF T\+ʴK:`_9.V|mdYllm=ecfZݗ/wr/~ 1_;uoBlN-fA{5wuU25=ny175ۙ,hwcq:ӻaRf7e6m>ݛJp8\V ;?[wnwXݯ,p{77'x*\1$ (*&ҵ]D0$I*$wZc ZWrmh䥎YHc8jWT*x\PC4tHمxb+WH,ª@|-4S+5EO#@FY*h)qzՎJG7$w2J$*B8(JgA4KU\V[DZu+4uU^yTM Tx̓7hNB(JzXt򳤕I`*$j$<#xHzIO޼eWyXEIĒL^jt3U:!L$qT=STY$҄=m9S[$q5E1UqQdgJ4('h M!nؙ<.B .B*ߛIY"Pg"dhm,mX3tl ؉%A=Nq\,杴# TiBπx&y0VcyLi2h"_3(3x5O (0`w=6;%H)\qRFU[<**4q 0񊊂#oTc-,~UW޽v7a#!KyG4Xl.9J[1冞cVcpy,5~co}QLN+#k3j"I I1&em$cET2$N#LNa(Y )p,e&KTO<%* _ ʤ8c-*Imk %b-Z*u/RL$ NHĐ>WiQ`ǦW} ۙ©X[흿1up3LqfZ}!^퓰>&>JsjUmzj7-j(v7&neOI!Qh)bG::%jqTRSny3]Wژγ{wcZ3[&e<55MM~BZɋ5Mx6f+90ok7F!O' Ye%YW9 C4,δofkp y{c]݂m{qK]oȥ^$T\Xm>b񕶏s4oWmf6_簔9=e|MϷ'+]Mͷh_ܵ< T٪\lU;sv"fS[I++V:jb\V@z)AUvbp<\Vcٴs{ÆWl]fzTؽM׽7o'svSmJ>~dzx&Myݯ۹_]ua7g7TY^M=;Sh{Sh`F#:2]m9Nc7f^]Ͻ+2;6eU﷫vm]jwm_z&wH]qK_э]`zsPoͻisI;{nhqcvn칯L^Ϯ^=Snt 1fBa=/5휞q7f6S`o+pn띍I3ٻ7[';pFغ=Ϻs8nTUo]|M.?9{ZlfEQo^lSnwWVv꿆3=;qN!.u;oksv$[&{i ~OKFK%v_#e9v>Voa߰'7ou[mf6U VRy]Y< mfysٕ_pm=n_pc1z]a)+aqKϾ;&13Ylܴ+H?g25CfpV~:g TVʔ?yCW,SRj**&=d5x i7FuȎplXsk;Fڊ dySA@ٌdFCS#D U*cyZxV@ 9$t8 }m丹9VX  $61V?6'^|T,,=K;i$d$3S9aj(JVqݓez(2p.6+U:ZI2U3Ln6,_$0Hɖ S$}GnlRSnP.}&n.ui8zkGio[Nt]Hme;'1ʽ4+u[m̚ҮAvyLuM$+NIOOr*)qOU-mD55mw!WW*RœBiøPTԗSqy섐ES l\Q<:(HHR3 LJk2!cX~GȐDNIjMSMEezc0J/<-cOLE)V xZ'uaOg%WRHSGJYTs#ha#w}( #*1f!мH&4+f15G$jAjQ656V2g'ޓGU x3?Ss9u^Џ:Ų{:oIs?kzjb,&٭mrf1p;%Sٲbx/7h+ꂢMɲ'9ܸln=b'g]n9h[*%ik)_=m}ü_Pv}=I.S'7RRO f: 宠B25-Ǚ.쭮Mb_~d[f^: T/zZz[ 0G)q$Ei*]*2rvWfX1(J/TD%UPuSlozy ,G6t(8E.R6kct![)7#p`$n n-qReqU_OWKvPQx۳:҇j|yrc(z\'QO|u6Y*J Se|mQc0Tø\Z;cxm vڽ2?m?IavZc:~1{c\uf=W+; q[m׋\2uBf%Ǯ:nz^-njF4?oZnm߲*{s[ dǘaCeq.ۻq=ڛ;ef^4;#!N|{ʇ!;{Y1[o% >!ܑVlvmY쏬L6uSwe|So]We`D6؟o>:=cPd7?7=۲Vnܕݨl^ؘ-շ*;g鷆gmv !%vaݝuNXW`dzgdm;ym|{{7΄׳~52t]U]9(,DZvݷ; DYӉESJnv}_)'}..GuMGbٙ[}6n'5mF;¯'2W?l6on vV5'ʍ;6Kkjjxd dsy& ]k_.M䴨+#dȴJZ=Le)UH# $LXP5U$4rC4l e)"R]12BT$^3g2E-M,KS,Q!dDe4дdSTGXUXxuڻ*#eGX*SIyj(ji$KS 9yRe斑Z )̖8wC̤݈-;wJlSagZQTU<3⤪Uզ=VCN$F$l-~4}o~GvQAI[Q/',TbNI޳ 6dJT XӨ|8pUa**8R>+j"WSpK MUM-|HeP?Qg'SS<XK6T.oxԩ{V2 p^QK59YRF$H*P5N"TKN]$N^?VS ӵTOX,Cjg' ۿ28_#Cc7Jt->9iͷϱ[n6{1 vv}㸷];ZHg\Nz^7|mՔ 5 NT[vvw~Yn n5R)rA_I9DRg2eBr.ٞ:Z]y]_WtN޾۝}ieMp8Rj+rxdrY41YkuQS^vt A&ir5.J jC ]JS#,Wb%h4>i0qf$>ߡAUG[W6AQEϙlfCYRx(9KS($UBVFB!k<)Vhbֿ5$Q,4~TԑXZIKjtH23ԫET.ub12QS4n!%U$hh` ҇5dDhiV*يkLI4'4ѩcX2UъԭZ*"H׷, CO~U]Ʌ2P裤dv4*\~> T >6 ,XZ8>]FCnOT,8,UU50暲pmzgg6n\M-QL"o*V|o-эed`+13nlna6j:rw> lVtx28- mڧJ\ZdiY<2+TO3 ISVC!S<%>=7>FTv0٢/-֡!aDC@8e"jUg+XY.LPT>Ν*H1BUe*=5 c09jLuiॎ]&LI'f`JV݊l)'GWqXL,lxIܙ۸4\.:lv UĢ.̞utK;'|$.,*=*)[S3xl=g Ҙݱ֙lMsTgڸ֒`kj7?do$}Ͽ_Ί'7dhU$Vm&JHH#2T8sUJ<1 "F]*/8 E\jJ% Zy@&9iҙ%F+TdOS?icyM;!`|sS3]҆$B2I夊ef̊e᧎3D#1F4=*)'W")*%cPi#Q?}uQ"(ʅ5rF(0uO4 );R E9 QR)V ]fVQU:5",JHJӡex$SL1x~*!2!y"hM;2"COCBdzا4I#QRӊxڦifi* jzB=9|)7{db%^6RffMZ1ucIbi*0W'qW1Q|oCWKq*M )^LtV*;+?MIt9?UrReVZg4,xYH#@+_.vktvl6GSMKf~p}>Ç9ϊ8\~աK;on1ZgH<]U{wpc\NL6{*}Ͷ[n8mg#cYV/0y#95HePDlC9TU2:}M@T~EfU3GO(h2q4ud2,d t!< cqMϫ%f/DQ 2V 4nMIN,UĉAmRK +Wcfmӛ;lCڹ]9d>iTŸbCr̦ݣsmȩ36=^Jnol;W}gR{M.ccX(dg/in,VwcTPd& x CRXUvɟ6Gpc;kZ |T7]mË&_fYȨeY,[̞To{)p8 jlo~zIYmq{c&ܛwBm,pc%;'-rl`a Դ tɲ&1GMœLd8ssQbr9ʬ~ u8깲\#FI9y\J?wYiJiӤLUEHDX~$IDbHO*)+i]8$l#_ǤRe5N?<29 RE4%,R!6%,C-8< eYHFT ădfnH]Dya1COI&6jy[-ۏx(FR\,uqmG+[ǪM޶ \htUԋR0-JPIk4oQYW۝k&OmtRWg=VnHF[[N9CڲEU}=^7?c ]>j e4tyreag>8lz-{~Ŧn>cɵenECL}ͭ)D0n{~xQ9WmOoj}wcuܣbdC7gmmJZq<9Z2cÝp?kd6פh}_GuhkDF:9jHrY}Ƀvb3ڜn'")pS17*XՔT27Qa:I$5$*dt0~V*X*#(0 eD2kfҜTXz4+rx4KR*);D"^8CG4zVHWdYNE 9MM<02.BBCO'"QO! |Sb3w'QM='ӼOtT1QP;\Frɞs%~n#Zqqfb ]_BJ[Ir?W%X I;^_{#gl|ozmN[ 5CZcLM| ; WM)h|T>*㥊=ۛcKVI%FVYiW+<r;0H%MOKY*,j6+;DXW/qmpY6;K6_ml -^'S_o%SoR~΢ hh(+ݺs<D?^=`2?q[ѹk"qP?W8r}qҸΣc3M6N ma&3znZf N*){ 6S".mL.)b-ѓ*v&s`r؍J|m~ϯngUb3X'ǧLj-1?¶0.'+r)Z=\WAS]jUB>ooԔhbd*Yc(WަBR@,nblļhXBP&F YI]`@*4g~2U^fXj~y%X2HX:2jd4ԱԑKhkK# ]Is{Z}ؕHcW\,ˋOFAb1ΰ4z])4OMPKb/,LETֺE#$jNuRZ84srbwF*9c?T2jYZXb7ovԻ^}HbYN'*GX%r!ݐFC8򂲊!AAe1 945 ,3+I$U)uTAP3IE:@e/wpl|i<߭-%N;-VŝT 1OZ$ӘsW֫a壟'R{&G?A8iRnvfZ5݉ph>f,-Utb_ݯWr1Tf7V/%@q 66lm}d눦3hdsSm* =ԝ]Y+3B,ECϢj5jiVg3 ̞٦!%񯶩02^?)[8/5G]rlQDBM) Ƌ1?NzU U~׬i4ف ZBr+*Ep]=b!lј d*`!Y}w?!m-ѳY;ylN𧦦lw$k1xѝ\M*!YB_dva3s7>] K*.ٝU:]u[3{coZfOf쬦r36'|C?ޥ_Iuxr[jl:|~;To*UK!lNl݋7x 6gy>f;7-XfqG$"Y'JJ99PUsguO>8پt*T=EccJh@(u摤FiklrOAZ]9UY|i$߻8'P螦Z 6폶#cw$hy U7c9tXY[usxG5Y[;w7CrK@Yq548 :#9Tt̓n~swjm(mw[em=όڸٹ,Y5ݽ5±y0F:Ӯ[{pC<;`d7f;pgs/Ôܻ5mI1Pŏ^Vjdja.<%&W,]E&Wn RdjX^ dEP~W,=rC tq54*hdZ^?Zi%wRY#Tu, URnY@f]_\4tF’7 ZF9%BXPOpɭPs"&j]fWV;IV5~fjxYzrb9Wv)㦭)joKM,һT95:N56;PJ88sLa--MA*GIB *@#7oo,^=ֻKy5j#̸܅=n'+GL<-S+v_{ɕc;jPKG1:`[W}ӒR{lP-Ϻ}@f1rؖIYA<5DHi#մ!O<W;VX5)f-Xx22*ᐄH~6ޓr <;_i%0ufZ* KA$qTGM_ᎣT_=y>׵PO[?j*O>+WJYji$zZ4grbnn Olu0cᦞ![[ ,fMLd'jdJx[Rƃ}ᴷYk7d\.GࡨXV 3Y l>*z7 Eb3L]rlꮦ4{.72 Ԙ]ېڈrǚk7n SZ b(tv[zvӣJAxL %4AhiٌN}.K?"* eGPyc߻bXш1WAP*4Yc(0#x=G(pcH9N͵nz-sj7M*"Y=d> h7^٭j 2fdS5mZg3+bw%^"]׏n,Hpf>3avMagעTGYLM$z$R*U6X[Rƚzdk/*,T_7༁]F@l5.0ѩK+I 6䭔 Dc 3T#KCeVؼb4X$HT5ڈ+QNP 6fzY) o<6wcoYsaofS7%>cgf n7h}LNÊ:X*]q}-6.}֝b}֛lUe7wdSo,#mش LU{v щ{sw;o|/oLCyn,>lh:_][po{bnI덉']n{?lVroO,weJ%H!k%ξ}QSm= ufP}C#VTS]}lvmn]vrBe7rVoS'w]ënȶ9{gw~N֫\}v,jmjʜWck+Y4I*fH %`64p.c;s6z̝FC=Lp'j6l>beb(+b1sEA0JĭF lDJHB@*XZJ3acfy(,\Z`]ȱc#y_m+vr"I iu&vQ[D ;[[dqd^zBUCG~IU(Jxhp刭JiF:75Fpwv7Hnnwf}ឃ ۣʒ 8 m4[pkd9luu.q3ճmuڻӮˉSh6zXC'YIh*Zf`dHih*P#\=9ރ6v{;J;rAAc1O>o%* F/p\3=YYO&)yWǧmeٻWӷqX0;vjϵ2zV,ę.|R ~+uuTnQػ#{v Q{#0VcQl5Z1i1Qԡh(*ͻU]eE |W]כCuܲ߳qdsk[ٹFP+}^mلzd{c-a;'l.xg~$WUQ\*IRn|eu6'겛p̕Sf3ੀR39ttI]Nvy!$WG4B&J kͦLhvclښAD(S'yRgex!9Q^VJm@'ֹoybmDwC)[x0[ֵu I g1qf1-PmL՛e29NjyNםQKd bw,kH>YPXB4Dq8$kaHɣD.ťm*FeЉ ]7Vmhh $^8!L|w!v< %# aNutyC%WHYn# ʁ2]bBfS=Ф&_51=|) rDB_T F3&\Xj|NCṶT ]SWnrlۛ;a6^LÃŅݵ3p)7*q?+ǩ뮾nCrn Ŕۙ,m_hl};[YYԘQ%fݻ7|]}X3Uϵ5_aٗvinنV/jB0fػ%dqnvD{3vN7o'"LuYs&dDp -192ʂ8䧧T&5,/UFMᆬݹE7;lwΚ~4_cqd01`!=f?:{;6`*fCq`6ap1]mAwKg%n@;I!nܜ %MIȚꚜ;cq|M&+cԴ8v::j***x゚*x"B"@fiRM;U+FI (*EmGN'Rn,)d ȳN:-.|q:,e04ouUbZ&^X6ִ?0SuYa#2PgS״ `]@#N(YܚX61 u2$j!Jj)̐B$:i%XS:0pۦIpx᎚elG1T%2X2r$ "!51~?tj34h2i-,,I d]qVa;dTɳO6*z_D+_L de3JqR2>hPcUZy(Urj<&QV@vR7EWպ _)h ZU$ 3Ycɤ.(zXb`ʡKQ`d*r)du'tL30,2E$xK1ΉOŐQYa k 0O yEMn" GTmnX%0W$b)^(c R5YVF.JWEiyTNX䐦Xoeto"XfpScᒍ4Œ!12SI1z#XA#I!4ҵH,\DQLѵHW3N %nՔEv.gþMשl;RcŞa.O?i:,V 9?=ř}7~cqm|M'[fS6Pl6cw=nɪܻ$9\EZcǍY]ɛa||m|qjx J (I'oZxJH7p0o{BJ\~[P%X#bw>~a N/uD<K>';Cp<߮~gU\=7^Fћ1MUAKAεnҭjc6;QǑzh,\SgXQ4M$bD^$<Ic'E5$o^tt͍nE5lݿa75N[wr7@gjjTm>+{vEnܱዲrrns ]N_ SYnݵl~S]!d?]+{ ZZ՚WIA]5=zEd٪ 19zO(z,/%K9Е1+n*] J9`"E2#4A"HIS5&mf8ybcB4:tP3f/DUHWfgBDtY24M8HThVydkESTo5Q%ۻs !ofM4tUaicݻg!(o\t[eAwvġ]/Sa&YǸ{uPmSeefbEBn]ӽv}Q#뮾;_)6 bWWUlF ;3%[mݻq [*}u"i+GC[TOOb0x\T3ȋIc1x(EOH1=@ԭk.st];>8EHr9UCYKQQ:5ː^_;\imLJ5Ov>[C+kaϬf3y'pfd*}׾)vZsG׮xMK@ 2Ⱥ$V05D,Q,2H]Iݑo)]%.Fc /}{hda0Gk7._>"2AO9(v^)̵FED"pRt|ָXi67SzyP%:FDږK1(b\(\i}K%-=4)99ֲh2Dw Yx$U ,E+6H䈼Qj4fBS'+GQOW0Hl(%:dVU4LnэQYѱ\,/S@dK$`;{)r7 AxJgjt_QPΞv(d@X+ t!uk͹t _kIF22<(4).<ˆɊdE))CZT2J[yC,7!TЮ9$0@V1v 5!mrlĽSU"H`[ H -ZBb@OIcMSG<ڣB්`׾uTy$ưDs&Z2/\o=k ߧhLc6vd^6g% 3w'fd[X6ެESW>] SfEF)fO,p9ZuH1VSU|'!"q( $!Dei(xѐ!ZXTFLRH ucqƩFΌ\$~ARE䨩X]I944E*R[CM-S @8!F-@ԕ&3W4pPZ o";%9Y ?/]᫽E-EF߭Pe)l~= }~)3Y*tuKo1ק{{]eqclfEeNQv:q[!ȶ(1X̜c)r{7ܒQMw7vrcS& =ȓmFh!X^Zb\aT/Fk;ى6M4Gw*|.Ა2[FY)aعhcD4kQI]3YʊJj%,u1U܉gx+PoS-,z/a:6EB匫e5.Q1q%<,T#yi44p+5H]<U]UTCJ#~RͰ/uR0ń $K <xDVRN\%FIRjl+K2Ĕ)3QS=JI BDc!&`gmeJX%5$j3RJQDSI+R} Saum9U (? D'&ƁWRUKbov->[glbRcjȊncS O%6]-7ca$kIy1⒭4s rL$RT4dca_Թwh4 LQOA0cs ^]O@8ΊS:t}ɌL>a"0u$TcB59 mITÒ4Tu5HzdLUkT-P~HH,I#hsQTF z;7Ӵ֦F)aXmC6U-,nky髊h e|dӕZi8#&"H̑14' ) w5 UO5L]@x*X$†*S "䖾SR"JXaHOS!Hc4V THӵvZ` 5Bllc; +Xۏۭ.(ek2cC t|n\{yj}nMϙxjRp5}tPSWQS!D uU3,3iggzɂ/dwz7CPwN!U|-l{ln+_©Z:fWV*{:Q2F$qƦ%xʀb@xtԕڪ-yfXbȫ*uiIxYĺ >ށִV}_VH# XHfGMgЕK[U%Tt#?mQ2GI%;t*#\1&z|lc'X"NbNV8ZH1y\~3mNOUhSȱzO'9L(eY* UBe'E 8ɚz=EDCTuS% EJfhE'>JO13X\liJ+VTT R6@8 +0;j:c08qpcvXf"3ED3[1C3S˶/]1Զͭ=TAjbTI%EJS➖jPvd{hi{Ap4QK.:MS$yzy ֢\%moeTGMK5>.:|PcaRMQD3xJj LS޺5$UkQLrx|fRh'JޛoZ9iQd(v\|:nmkBr)7_?bcm8XLC)wh|P|:ynl"%uvCmcjCmژI>gaVkvQ-Ve7%~ব[qmLyr.6>kr9-L:v]ؿ&!\EUv秋?A>N#3gZ=>bFo]T fދoRCQt;{+d5bIq49=Ob2ʴ>5]C di g`< -L$,dȩ$po1:neĢ4KU$-bm,L(uS'+^0J(yㅂXig'\vp9f |rGD3MUP5m~J(⣧zN+jx%vS/Y]q欯JgW&/* "F႖RGmYnz 8ɈJ! %a VH؅t LaB;Y̚=]Y淖;R!Uv̒- 5yuOCSS(u,tL,O|lf./Fœr[jsٱUඎKiж?=ۛanGvY}[_B7]>g7|ރ~mM zsbϒn.M6')OjGն(֐S fSVjjpI/R#x"I ʗ#ޢLI L e aV wuEi٥ug8v{i]c6=ֈj]5;T7Jt̪R6JZ@.=ST #[Yi%.ъF yрt2А @vn"4FXT9uY EvPň H ̃f؟ ֺh(mvUD`17E.q\h.lFL),L bGjCulNo}nI7nY_p*9;otϺ[KEM.83nj %6jyLx4u zأ!bEg0{ w\JԔ%:AZp)+wLjd= eALdY*֛PGQNFM}lu"-2J┬!2WZZly?zׁ]+|;'nъ8&.C5u^6D(F6L~esxquԓN_ }g>g^yl#e=teIMC{G; *V?l[WhMWC&+:742` $hߛڻiT>61 Țf,$Wx*0eqLfdU$fZŌV62[rc0HAg|jL4ljS(iֽ(?É˓7JTJ~©zʙ%eAT$y+jj}u;3뽟UIUQQ OS*UjT\vE%9h0u4|4RbJRCY3MK] J&@LDe:x8 X"bUbx55WP)jUS2R*N&4 DI$~v9$24fw<*jU0Xji`RR~J dh֢x2IW,.Sq<>:9q^"#V67IAJ+*d$8)j);[wsfzvbq݊|/[nFl6gױž" 2,~vmf‚(6RnnwʜuO:t]nWYu5\]ǀR0ƺGrnm,UyvnX+7fr[%R,.Nh\*G f0j1].W \ݘ<^ۯyf׉򛮧qKFla棣H;o DL8N&sz3蝷i݃ԸJ*,>JGKh6DRɒɅ\6Tw3ov{m;&?KY6L2R(ri"GGLqpf*ps(PcXgn ,;QpP`kk WN'zZ:yRzIrOCc;orŷqp!P$fX+h"_ 4nΊۧru/hung(p˗6Fp~b(U͑hhJT=݃9ln)A f/0m\TuNKG"}m:T,$,si6LG"A[Tci$2aV=2"ɀ/jYݗ2x]÷H ^GmdksQpugj03T&Dy+=j;zW;^)_QGv~wsoڻ[AQ- S,s 'L>z/=P j,RQ.fS}GF*I0.A5l ɩ,ଭJEm2]X:d)Q*qj榪|C+8J*t)]R}T еޫ1;'/_C?Tj vdkn$[ši,.{A\d\kcpUP;*=ö('M]USbjfz|cղǍRSM; G[GfJe#c;Wx]Rnh+C$4xi()BC%z z*Z rȒSQW_hL ,‹,",)If2"*vt-%C*G HViS&QP%GZTON`E5T꙳KSQOIbcޒy%Ru-fJԭbJS,bwXQ`dQfR\%^tY|D Lf+չ uTM,Y;&8^QldfQXۙ{xmnzYݥT=[A~5g_w6@IX};_!GVrQWo=i{cLW-[~9?ԓTo_v\Y1Y~gro?Y8Ӏۗ[ ᾱӈ}בQPɓrd;+{fgŬGWwfJmۻanܙ܎rMυAE2NacbmWOY SM$54 y >mژX|>?Q-iw'+CUVJ%&DqUFeZ+3j^_|%4u1Ij M Vbeh啂իI-sƲ;.88zKK&{?S. vͳ'mvW񽉁*s_(wn+e1lvWb>aUci{;lޚzOeu~.w|45jWQWEuUcGEIL#JJ4)$Q̾>JTRSDY*Vh9DM58g_ %?&11 QCO_)ޛ*QBNՔժ=#8Xc56gV>crO=v+\WpU' )5rL-;'ɉUYޝbr0< }f{-c6uu[f=>Ol.*fn(pƕvZlN3;jvf+5W|*~nzK'k5Դ6Be%!PMaw:w=\-_ӵ7"taZ*'8 A3lUV?%%>Km>ð0ro۔SUF)CG E$a y#`H &*"#-zSj} $H e;OT3'K2 zߴe9L2hs9:X7q6Φ~Fc`i1<$(cqb,J}h|]`0;J1)p44{t۸>{%Sv,):m&r6 )&+{W S.5{{ukhgcwSSm&V1uZml}.33vߠJKHѓfm=~S!ȭ# \bv# Y)pJYRh1Xz 8cͶE^j-۪Ֆvn]_RnܛqS05MU)w] նy6K+9w>)f3M4ITF)BG<$u ygΰ3zJ|T`bBS=K[eĘJj`"1ִbIocy}#(`w%l=tC[=|ٹں\^%;kweV"3+ws-͎hY IiZj|؜`+Xj\ZK~qՑTrZ"8JTc%LgLe^6O$o obQ[2ۿM;1[3eCN`s55\⦉qwoԱS̈́rܾ7c0PӨrwvckLЉ( R*ewSX^XTr$u_{gN,9lf1ؿlB C.O.q vB)9*! UUOKCOGG_ojx0#TZ_խ4yYZyr HaLY*ӶEҶ9YbtF2ڐyG"LI* zҨ.sc+ XēU IN-RJ˪Wt*ĸ@ Bl;y.ٲ|;73O=KI_(bv_#KI%AXQYM&)15{_ 4iJ7ULѺ*;0[i/CIQ"DK$QqJde { [;T#<5JoDшi32uߒ<lV*^0Bt) :2>Omc%G,Nڋ5۱UNQ&"GG )IX8HiᝋdTC4QԬ )?G:3[omۙ:hw&_rU~Wt+Z$hb5nW"Z*<'ۘf(/|bb?U|mŻVM]1yfۊz&2L%E=m(ڳ+d2I2Y*|u]jbQ)箢4%@[ׂx8Ds]UN uph7•Q 7LTYy49H:xc>#1;J \’Ԣ uɍjng+5{wNhZ+CMaem"8Z}fƍXhWv^ߡؽ7\mm흼I_UZUb6wfnZ]*gd[0Φ%Yc{*;7ܙ-eB˶hk7_vܸ}8fV/Vn7ո6_/tJm,q2 ۅpb$ϊ鴶Nj팶k3I.ser.j j$WHLFjy!*IcbxM,<D 'p= ŦHȷ4@̥J1Y}kmge?rEJoaj08HUm}3CKۧ LTcVG#tUAO䢤#KU] Il~:Z"Z%p9*AoxLk9Y*(p2D6o5KOAO]I!%=5 GCY?bŕiJn} }dH$ fS%eHzJIS,_t-V&5 Q l@EUO$vyphC 7_mNҠN`^ȰdqE T] ՂҺ*|sXpϢh]vV zT؜V&,F"c5TQ$TC Esbhk(($}#G#(o$Z))Fzdgv1<+MQ&Srm:jrtO hj^1Y.mIJ:3 ןE1xMV BbSCQOF(uĵԅe)28jxI$+=0+1VTxŒ S5TVGQ,uEj<-=5D#{ਨ*%fT20V>2pETkRȥ#pSdchC9f3(GQWr8խ(9 :,y1 y},Z!j Tj*OV8Z*BJagnP erZfJMS[MSoLC#?EwN4+wޭ+5g*3ofn.븧+;z{zژ].-PazݗMGGSTE:xF\M]"Z 0ϔ̼ξ|oAUIWtK*y*h飁V4DIVX#SiTq3GIA-]|[ messPAܴmh)w 6gglĹ {}naKpsn)7l(6nZϓj2Z >mŭPv\vU5e~ĪZhSpmzѸ)F\ Nkkg6]R2{#nƊL>&tkGBc̍tU3uO/B26ߡl^~:C6GmF殥yݭ/QUvœ#p1ԃ*p.L5vT˘G`n,Oi픡GUKF*ᆬVR1l*eL[ȜjT,S}檫+kk j0pG u,3'+CxM)$Z=ϛ Oqɮ" PѤA;YYL12aSUN*L21#i1TtTA+F(N!ғs#UtHPawUF֩O-ff7 cvZ!Glѵѧcn,]d1؉!\Ax1rQW-lh-Qk<'ƞzaV}UIn\nU]Ӻ2[!_4TW͸;/f0iZqdsٌ orWl۽%id`9\V%h0GU%F n#Fc-_:cL5,>{EIvR 'YX3RIJʩ,ffsxd tP?Fj)`)KӢ,W/ROIlb9[ikfxk 9jTS10+N rBYJ|ω{Ln!Sg1R͖z9 aS3-@'SL_е2$?&6 ]]RIrC,i£܅`r )Mv5YNmeeso=õ;kb']d0Z y#."8yZLއWgi)//>;k :^kR㣤ЊI{oUW8ppU./)IehRg2~F#O"mc# $QJ*E;sw*)fy19o%=c!5ecAM R[\OyՓB GMij_3DkǮ0T4YFƩzA7T.G(maJ+JWe 9RFD 0mK$LS-ɪtdz5Gq9M]55,tbins,o,iIePrӈct*JAOoަIiRI D,1%Fc#q"#CH[ ZJ\fvF2P @ i.JattJohvo)zz<&~);AJ 9 Rd##QGN)3aJ_"zzr4.:>/|ʨAcsdf0R.f\{m\hȶâHE9 3o"OAVeX0`4'G3a̰Z֠QPDH7m"0Đuioh]i7._(j¦MQM4?I&w Sϕx>XЋ"E!UiIh .gqWf#`+碊*4ROQV!i4G-BI(93{tESWn\NvZzEi))1qSi>>@j޳.`lW1STM2=Er5⎆5do A# ,Q)U܉YSj6RK$C)Ah4N%B{w;u iL²=e$sϫcMHhn2 o$_v.DejU_umL6mEf1Vm)-WpS\ٷZh+m7*nmƸiO>A('A1jic(=%(%_L`Le-&[=j<@di`!y(}5B⁡RQ<5 j|(Y%GYbvX?pZD)KMzԒVd0YH:&0tjD@I"Țb(r &FZ얭2 )lTduw;BUr,DrU}VzZ\%fHI%rF:>DLFVebFD+H^^Ff!+et"-?kRf*R[̨ia2G#FjPL^ST0WSg5H`[ƢĪKEt 5!|gİk {'NZgzjsJ*Ky +M=褑fP5p_j|͙c1!ES⢃%k{fF12FL{d .ܻ/ͩTwzwQ6pvnlf j@{x<j*Vu{QW?|G/}c~C<G=~u43M^{CU;er*zJ<gۗoQmK8iu*uT4Qe DW*"h=MO16 ': ,Ejxi#yiFJvd4u+O twogmv^⪿+[z`|{glL_koa6X_lF8ݒ٪[5[r\FKln=ÿc}b7=Vң|smb]S9 1n=UE&Un.mٴW*ǚTU-C=mT/ZY*&T 1T#0:/5DNO,l*ٌI*EbY%qY^d)UGN&Tyb]1AK)#4KS Qx"rKPx^OG"PEP꧋DpOF7߱i2[nrSN:x-S|*by o,r$ENPI! M6>hL!Ik|WeY 1' r䨕B}RdNK4tSs+ChgBL:;F5eu{{TRD~V Ӳ+ } S!UL#W*pV(3YPKjy7,dY8 %dV_& N#.GB$ahmcqtzQ "i ѩu*?vКĎ8 ДSDHcVx.YL'u`l;/AYDWM=ts,|T1ԈeIHGC'zIQgS>FxrUH,FM`UgbһG.>f7mfiyU1"*șY@GB#R0Xm.' M Y)ib&-Q %TDi_I!yP?{N)*, kOG⦐҂4cI%Xm I30[sMI C5O; 4jNʡ݌2V/ZAD5S?UP#Lr Ɯ$!'.ѵSsSOX/P<2'O 7hS[W2JyLj(T+U1>Sv 4RQT4Ү%fibu$jzX+D HJ-C#+,rTؙBLh()SӢL!+HJ@KNfGb"NO"%u:9ij!lsuҼEYJQX^2O6zoev+#V<1w$#h"?HdK♢ Mo9tV&-"n!"Gyݚ!WұUǠ8}@$$1YEOQj2 ąh6̮V4TiTIE CE G"r %iex0oK4E -:AY}Q-ǒK*L`N "0VmMrN ^_nY[tIj :( &ʂi!榈iԺ3xl\VeÚ[+b2GQA[ITbYuAG]S1hL8_];lm}ҭfӦEnϓwmYכTj:+mHCf>F*eDtN,T*rH{ܝ,#4<"VVweHrɣV$$%*)`q4Y\/,N_!G81⺓D [r[O PfR2.|/%)-ydu;F:Hm4tC!AX'I @\0ՙm瘘M[ EY㒮)r$Q$L5"FOv|^鷆r2"2X^5E",L-P)S]-,j{jw.3R}c.:4]~. GQE5M%E<'"Xx #AW[+Jdqʳ{OX hUF,x6lL|$CUJ!M6)V7'IAf'OT$)f"5T2WTzURH)I) ܝ3$e AY <-ؾEm*HZ* ̦@#6[a* -EԡʶH*ws3DA֊ T Y?hU}x,R%T*AtT2*Zb8C)` `6ۯ1KS4G# J?&&H<*f-X<\J_x@,4>PJFt4VFG@ Gp :__I2$":hh1%ƃ[<#H385 B0ȪTi%_Up*C-TOx)# yĄ;9A* x)PO0Ji%lur<:H> ILiC @:I*]%USY=}XrOO. V㌕XIuF3S5TJce[Mw'G2m&iK+h4OWXB,2P?ָ[;Nۛ>yi%2QTŐHReqy:lvNxjx*"B!toϨ.\C'UT./aΥߛG&o*p5Y2יX,Un ]!hJf:Cd-A_,s kpu11Q.bpU팎׫̉QoR^;`{=]u32=ω4w2tj#5m̒`r(r0PS2aL>2%XE DTQ"JoFг]JB CZŒ Ȏ'Kw̥Ey<4fKP xӉRnc̠ d)yաR$"*F$TQ[WT38yPRQxM/4,1Dд"p!Qh/sd GJe:kCV]ُ) Q+f"i^!i&PJqq㱓 +"irGgDI-u Do*Xt&(;~z"vE ;BK&k9CQ$aeEFc%Jd2gKUʔ$t5Zjr)jbEag"!.Iʞ4O-Ln,сUb !XhbxIQa<;(E $sҴO 5":5TW 6c,)KTiD$oXVm(I2dr%+Yџt硦 Nbij+bgæEUTFO kҌ8K9뻳zn5fJ=vB_$_T;NLd;*xi6kjI_5Lh)H+2BGRn=l )UO8Y *(xbTcK,~u Y*dbTODjO$@"Y8q#]Kqev"-PD"Y=AK^T+ #IFk+cȽQuZhJTѽLq$KUo50J&H*9$d)nDʈu/=R %|b$6ܼʠDr* H̬ Jh 8Jt`zij^Rkw7RWX!mv[1ʭBzHģ$4G 3hZ_D(=6jY9 QJРhhC( faH",AP4-5]s{$#F=)X rq"E(/,3w$ ըd*sSeԢDs3F%U8BO$ b@UQˆ)Tv&HZc,Z'u/N4b MDU/ ~FxYJ<4qfKRiXDu&R( uI])#Ą!HG&VN<,Md9 LTJPW buWidDk鐬$nxW7%ؒ[UOVB rP^4 H<ȥJ:,-i.?LD-s0fEj)xo]>ڙXV@cЯ)h]CƝhNUEH)R5;<^RQ¹x*B{OVc}RA&d`4vrPN5 ,ORAOx^GWoSrc"FtXȜqY1uy=ɽl%9`!DV[ 0 8ePThi*YZ) ,m4N9 :Chmf87),QJ,sJs4btC!u7obG]릯|mIQԴUJj`fޢF}QGMj`J)&)Ii֞Zc?#Q^g2-Hmj;>ݩR<&*JJ$#{3. HmsL2Y{BtUUIXU71˪kxe SE$v!$*VC4]OTHo ]PpѓE!eM#A4u wJePSImQgCšLߤ [>c oUE=\SVSvѩ%xMaF1V㤢y*憞WbC#B:?q_"?ݒ(b?mx~Z&z‹J*8['T.>"6O; O%AJlć #*k6@B@GGuwU]]fjIZ9"Q T grPfH*4S!:Z4 -CY*tu;nIt~d\ۏ۟x#2S96"")`݊#2 4,Jy$;K_Q?oop+gW Oh+4Fʷe"ನM#y'ZPά"x2ӄԬ.H G բ-i7s Ԕ2_)O$h,h8JTIFF&dF?o*w5i3t2j䖝e4-!wi) EX=G"Dk!"z9h 3SUZȋPuCKKLHq_i3PK4RĔfVˆYO"ϔ%y5hv^ paH( ^\ߋ ,uxZʗ… F i:lISIOWSUMr5qq[Q*z{HuKO/i%;Hh<V`$W2#jE2y DnBLd'+Jjtv<̕ IM8,o%|ug'dgUIj UuZXA*h*1<dY)KxG9lVP36n:\|^Jjss8Be>iTX"K S!z^r<$bU4LLHE*fkt{D?ԽVHfi%$q$,d,QEV#S5L|*q1yV)֞7HYRicV42 9 j$H卑HG8B3G9tBdY4T[?/'/na>}2kv"*#fӥ<6N]=fZC76?A4+,SLraPeتu垆U>)U{ͭoa>;3xl&B: 9zJXBU}U1!"*ֲU9*iJ}+*-#TEj*Hn$&Rı4R5uh*SʲBH LH A kFiIC\$NݕUd $f+A #\',t:bH9Xc$H_T X][edvEPFrֲPʋ$H| 2 t$*4$d 91TE G|zٙXˢ14ZYBN)І1TY@'PEo*<Դ&G$߳Ja&) b p %˛̫J~DeFT},+zl/L bSEYv5J%:zr (?O!(ENcMs'c+2h\QxI!4("r@' TVn, h/jtH9;ƅZ'UJѵYigLg bXke ZH:6att¡Lʪh *Ҫ*#~:vdo8ʒ$4T0)O%,Y]=&" Z6% aUYJ1v3rmpK5Kf4xx+ytY/C;\U('I=USj]F݌zJ{yݐ*HեAE(#5S;+UIHB_#JBk;xv%W wM%UA:YJ> pMCPiZ o~Xw O'd "ȉd:i*c QSEM$^gVPč ֈRFQUf fr 9)KI-E*4,o6}r޸ %*ad1r2}RZJ_1a ұ=BG\rԛ P4<% )DQ٘3F%3 4 "1yGXTdjc\o}Ɏ4LP6V8Rn|mz[2&+7b* gγ^螺vGglr{iWM,vlFŚ sn)q"LSMKگˮ1ˇ-g\dJ,6K3rJFSTh㪎*&SaȦI92@H͡hZEu `W j`Dr,QTXԀJ([[Jt33]Kt?{S5-:mr׏Ǫ{'~]ɨZ};46_sGEk=wn4W>$.YSـҬⶔy<>K<:=?( w O]bO Ck*d{h7ZOXrSHAPv2K{ k2@BHm*eO,<KC?-I!s*s0@Ĉ]&n4q}eɘ?M K[UouZ[Om6f4驼JK%p"&Ntf kB?Orץ|j/nlT*o_W7&ݷ澵{龑ojߺ6qdTtUiPU}a+ J/>ј՜Qʵk*S4?k4% _E'y+d K*:E/|閣'-:ʘ92=,? uՄA&`T^xLi#&=x|#/!mNGj@TIGV`0 .k'( t"pZ vIn|P)ZP M϶ʻ}J}IF$ӨS?O2ro/֒q9rLmSݮ%<=tfIU0۝BS=ߵq55ǰ+j65nkEXO'\ %ܴ-Á}]%CG=~n~-oaGsl^|̼X>:L$ ~j%|?¨pl=|ت'Nt?q`Ϗw3{x+M&f6vs7YAT.;t_ԣ)VV>!|}~Om*i3{mof͗4y͇\ P%%l#I&/! x7m /1AM+3^MJ׏{CXQSS~]3xL:N2ނcczrl0V$GI'oW2#c.+s-/zAoWee*)k !V>[mw_s SL G^25B_@!tYu$7btNdEk|gܚuVp?k/g`nxQcVKG4#K3Iƒ/ܹ $NZJGICBy-S7кkOᦹ! }}a@g9$Fl^tO)t*ĵԏS*XR3e1s\ǤNi=\FTtKh4ziZϱgyC at\L$vu1t[TWj$#}GQ/U-[J'U B8$q-W&Pj}"BFDk3ڧ> endobj 47 0 obj << /ProcSet [ /PDF /Text ] /Font << /T9 516 0 R /T12 252 0 R /T14 399 0 R /T15 379 0 R >> /ExtGState << /GS1 598 0 R >> >> endobj 48 0 obj << /Length 4508 /Filter /FlateDecode >> stream HWK8ؘGh;"N;3 6L ۴,9z[EH_U}կۻ7[߫.(}0D>KMq܅7}T~o.8tkoڇZa՗$av\Xgxʚ : On6`L}RPzf8~VEQlX{r[9hg@u :mo xo⠵GBT_G*/o lB§YvO şer4GHɾS:RxLeSuTfKQ/u[Oh,o|wLo!kߋF>x2Vf0!Ufen=wX<CD!cT"-y):?* L+9e[j+">d_  :vq8U47.!BLEPijHvp6&c3@MDJnvlR8vvhVA~3BEhy65ăqqzqTLYHpWpp^.I+$2.Xfڏ.xߍUC iA%okUмozJ-+4_IyN0Ime(W$T|\ Vŝ4tת lR9c_-g-a*8Otp@.60!rG~Dh*7ةI^7g6{hxc)z{@YjM}%UqU']aW T^,cn9}y'w0Z#;BD.`g"V'Fp=5.sF#ѾvR:\񓬗A~ǮB*X iQx>(b3`4trO &'$M_EL_W18 ě #l jQhoX6<# Māb9['.)?L3%sǾ9+:$M^ b/^g dĵ!2!B3b-D, nB-4u0g3SSt+ X'{< o }¡/:,ms'*UaTWsf':CW.T-JX!}>~X>M! 빢[1e?`cUm^x8HtRK2{Ȇ=$27~Rɛ#9mY\C%S )Og R3t6CqUl!O])!(L0U4T/;QI='+WrFrb!Xخ3/IjʖB狱w M\?K v^/(k#>W{MyH |*#`K{/p':ox:vb ;/ ,@6bcBO rBmy5i})vd@S9: G\Z@Jnt ׏_K drW8`458ÊV!n)RlC'͑Ƃ2 (Fe]EUƢ#z,V5S?dzU& @f%˲ nb*#;d3NNPSDZj֭O0Lnrͱ.5:kjz^n#1"V1m̑}hd$v]_5;ݵ" ~j6z\I"o6,iOO:/\6b14΋[fcqyKph:8S: oS=.}!Ocm} %.A }Cs/ӂ +l BAA޾۶9H]stbB hi-H'n|gwfVM}|zC:<F2r(f~&-]UcUaY- uLXt=J!4ibN|JM4m7zܖ:sBE0GoneAtˇSeߏo)AM^0 ”.H^$[0U9OWt?^Ԡ@V ,y7bBV.'35[%3ظB0BrAEIt%\(1ufHY]龧47AgP8B[Px)87q4ٵ%Ϯjl:h~|Si7kc<r7cMupSbIfCGP2!5VZK!O.8 <"VX#!QSAԺ o9,f2T@8M)b[?+iWݎ''XWё7 #rS˽P,$nS40)0B+bs Zu"8^H/ظ11ٷ@~;{.8`t˂'Y3 }DY=$D((ܣSEؗT0Ξ Kz04Z  @Y37xB/@LҌ|6E956D4D Qg$X̨էgR endstream endobj 49 0 obj << /Type /Page /Parent 103 0 R /Resources 50 0 R /Contents 51 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 50 0 obj << /ProcSet [ /PDF /Text ] /Font << /T12 252 0 R /T14 399 0 R >> /ExtGState << /GS1 598 0 R >> >> endobj 51 0 obj << /Length 3583 /Filter /FlateDecode >> stream HWMs8r?U%)doIJ"ɤmtIRvkJJF?/^.Dt.g\>/09O|/vg{qibev-?&?D}E6]ܪjjփ(Kx}~W[ FlMVkܖv<ƾ{"톙}^zʢz "ڀ𶵮PuRk:?4޳k5nh=Nn_dC}˺ &y'r_4IPKKo/Kնj2 28{Iς {*ժ-4 kjcJuZS;cLD~bF=}Z?6H15^ SܧZ8vyYWe˥fWWOpЧ[€07mx7- s$u[$tޖަxCx )y ,Y|UKׄܓtrSbH,@dֳZodU4΁g,Qfa"L ~[x6#U>ƭ_U @E£0qBRDħn`ԏ@8dӃ'>O^71&"/Kmzݧ8?EDL~n-_%~y aJ9~Ӑ*/W'+&mm]ysLZ0q;I@a ᙘ.e)N2] t-𫞥ۤLjۙEP2xXƐ6%t%3gCs>Kf&C7-:OIzBkMMv wdKzZlkUji( Oƶ[(Mq>==1CQT=ɽ_#P@/Su &8Q`Y-BCŭw5{xˮmL3ƊԺFgtof.|-Z@9L|ʗpz; Gne}$"{MSmbUHv 8;B(6,s* ~+8/w,uaY:GO#X5M09#BQ|yu]>*غ)Zzȃ^\x$ ? '#d1)?xF}=`I5bҁ4~ 9ݐ;8b SVOhAq'ԥM;p)TհNqAux59f,eYPxDWgB/9`62f’U<0Dr-M8t){h @6!@V2jy|{wuFV-q=[zvZ!A dIrYiMѹ$m0 Clq^}9=juXz"' Qyx$(_~j3[R&|YYT}Av{0*ސNd0K`['a,\%ފZK-^mF r #Hm2P6形Q$aC'r. YpKwS2m;W8ዖEv q}uuER!,CIj5!#d 셟')Ӂ{㦳*Q:-0qw#NFjPT80yz2 1/ *~X O^7:TSѫWU~I?R">%%U0}1f] oOcuʇ{MƋYQt+n/x4Ɏ Ha"Fj}xgȼOt96KC%fZWa;)^C!C=5E#rb~}hY'ȉ{ٹvyC<&fK&~W'/? WjZKuO*-QC΃񺞠y(,m~Z51Z?[o@߫R)B\0}\+mHUA]bq63^lLݙ9;d[d14r~X9u2H պc!}=AsX.eT p]_r z^-j䒾 OPĮTj0 ڄa![~fEgqDlBo,> endobj 53 0 obj << /Type /Font /Subtype /Type1 /Encoding 100 0 R /BaseFont /Times-Roman >> endobj 54 0 obj [ /CalRGB << /WhitePoint [ 0.9505 1 1.089 ] /Gamma [ 2.22221 2.22221 2.22221 ] /Matrix [ 0.4124 0.2126 0.0193 0.3576 0.71519 0.1192 0.1805 0.0722 0.9505 ] >> ] endobj 55 0 obj << /Name /T5 /Type /Font /Subtype /Type3 /Resources 91 0 R /FontBBox [ 2 -16 71 57 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 48 /LastChar 119 /Encoding 92 0 R /CharProcs 93 0 R /Widths [ 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 72 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50 0 0 37 0 50 69 ] >> endobj 56 0 obj << /Name /T4 /Type /Font /Subtype /Type3 /Resources 81 0 R /FontBBox [ 2 -15 27 44 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 0 /LastChar 106 /Encoding 82 0 R /CharProcs 83 0 R /Widths [ 52 0 0 34 0 0 0 0 0 0 0 0 0 0 34 0 0 0 0 0 52 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 30 0 0 0 0 0 0 20 ] >> endobj 57 0 obj << /Name /T3 /Type /Font /Subtype /Type3 /Resources 71 0 R /FontBBox [ 2 -245 58 3 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 18 /LastChar 90 /Encoding 72 0 R /CharProcs 73 0 R /Widths [ 61 61 0 0 0 0 0 0 0 0 0 0 0 0 66 66 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 39 0 0 0 0 0 120 0 46 ] >> endobj 58 0 obj << /Type /Font /Subtype /Type1 /Encoding /WinAnsiEncoding /BaseFont /Times-Roman >> endobj 59 0 obj << /Name /T1 /Type /Font /Subtype /Type3 /Resources 61 0 R /FontBBox [ 4 -7 38 28 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 43 /LastChar 49 /Encoding 62 0 R /CharProcs 63 0 R /Widths [ 43 0 0 0 0 0 28 ] >> endobj 60 0 obj << /Name /T2 /Type /Font /Subtype /Type3 /Resources 66 0 R /FontBBox [ 3 0 16 29 ] /FontMatrix [ 1 0 0 -1 0 0 ] /FirstChar 105 /LastChar 107 /Encoding 67 0 R /CharProcs 68 0 R /Widths [ 22 0 31 ] >> endobj 61 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 62 0 obj << /Type /Encoding /Differences [ 43 /B7 49 /BD ] >> endobj 63 0 obj << /B7 64 0 R /BD 65 0 R >> endobj 64 0 obj << /Length 104 /Filter /FlateDecode >> stream H21V0P0Q5W0P0PH1*26 (*Dr.'~ PK)YKW4ӅH0=\\\r endstream endobj 65 0 obj << /Length 108 /Filter /FlateDecode >> stream H2P0P0b### CB.Cs 53T5ɹ\N\ \@).}gC.}O_T.OA?>yPD\\\"Gy endstream endobj 66 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 67 0 obj << /Type /Encoding /Differences [ 105 /CX 107 /CZ ] >> endobj 68 0 obj << /CX 69 0 R /CZ 70 0 R >> endobj 69 0 obj << /Length 128 /Filter /FlateDecode >> stream H22R0P0bC3#KCB.C53T5ɹ\N\ \@).}gC.}O_T.Oف$9y@hcG=~@xa\\\<9 endstream endobj 70 0 obj << /Length 151 /Filter /FlateDecode >> stream H26T0P0b#3#KCB.## 53T5ɹ\N\ FF\@).}gC.}O_T.O#Џz??>7?o~ ???#`9O endstream endobj 71 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 72 0 obj << /Type /Encoding /Differences [ 18 /AI /AJ 32 /AW /AX 82 /CA 88 /CG 90 /CI ] >> endobj 73 0 obj << /AI 74 0 R /AJ 75 0 R /AW 76 0 R /AX 77 0 R /CA 78 0 R /CG 79 0 R /CI 80 0 R >> endobj 74 0 obj << /Length 281 /Filter /FlateDecode >> stream H̓=0 FLH$: 3T\ n#td@@수V:~qU `'.l Ŧe[!c;LG* Cx'# Di>C.6!T)Vײ,¹_{忉KɕXp9m (ƟPK~ӧ7d:/Bi1P`yrĩҖ*^sJwcl#} ܽ$b'ѕ F1)^T endstream endobj 75 0 obj << /Length 281 /Filter /FlateDecode >> stream H̒10E("M#d.$aU$`%R -J]ApJ oƖ=kp{)0?ĠY]\ ,AĠiGXðxYv!~P@\Lq]A1P+ '™p)k\@UV G%)Bktvցm4BVmв; R܁Όp0[_/axO/Gb5Bo(jP@!;8g;=Jf69@g癸z6X@'VRf'R~ endstream endobj 76 0 obj << /Length 334 /Filter /FlateDecode >> stream Hܔ1N@E(DZ,pJ P;Q.G҅e;R3D.%\kSd&3o)}RϮ߸UezyEɋ3J|ӭI)rN cώٖlÎa^!aGV lA`ޛ 8 [Mk5uc N~fhoZ<r4(3ouj.G?kP2W&mk,؂%ioAz"*RDENl $܀D$dc1WL : endstream endobj 77 0 obj << /Length 328 /Filter /FlateDecode >> stream HܔOJ@ Y&G\@c TtK]ko#d97y HffV+u2uK5ܹڤAE>7*Jx}uEɋ*rJƯnUJI>_oTQԏׂgflHSlc&ppIv&ve =hKn@m"ǹ?CHex\8pJ, %/fMLJs?z \?Α݅';Yv{cOK-RJ,_nR@x!1YiOGPǞJؓ֠ nhσz~D endstream endobj 78 0 obj << /Length 206 /Filter /FlateDecode >> stream H2T0P0Qе4R052S L@l!HH&r9yr+q{ =}JJS<]A`$ǁ@?f LD"d~0 중pd'ؓEc'"K8HPaώ I rF~HszrrÈ endstream endobj 79 0 obj << /Length 376 /Filter /FlateDecode >> stream H=N@Fw69,"HTH@@J \7ܥu0 M-mc7vg3;s{܅uٙWf6T}bI-Mr&Y_Ygξ}Lzm)"gIbP-LZtEMgnW)|tGIGyTeo&j C Q dh2{*P 6B-\$j:@P CB5iHMʌWkUGUPziH\P B3~E F"/EhU>lDx! qBS\,P( oW g'jPLSy=F8#1> stream HMN0p 0w$&0ѕp\+aG;kI6^?lȞ\;e)C!u*/op( y&*$BR<ϏW(nO#qj\U3ï\e$4LFz @UTZ4F_@Fo.u@@#Q vxf 7)f.1HFg@,Ôws.[F ÈX5+b; #b`uvĿ9> endobj 82 0 obj << /Type /Encoding /Differences [ 0 /A0 3 /A3 14 /AE 20 /AK 98 /CQ /CR 106 /CY ] >> endobj 83 0 obj << /A0 84 0 R /A3 85 0 R /AE 86 0 R /AK 87 0 R /CQ 88 0 R /CR 89 0 R /CY 90 0 R >> endobj 84 0 obj << /Length 93 /Filter /FlateDecode >> stream HD1@0EQڷ$?_26 T0-Nqc(@'4}QPI\P@SK-#Q:T_U endstream endobj 85 0 obj << /Length 135 /Filter /FlateDecode >> stream H26Q0P0U0R0P02WH1*22(**Y*$r9yr+s{e =}JJS<]~ F\0c?"@q,P P%^.WO@.jB endstream endobj 86 0 obj << /Length 153 /Filter /FlateDecode >> stream H26Q0P0Q0R0T02WH1*22()=CC=K\.'O.pt pV0U()*Mt??c?z00H$RR2d\\\\sYH endstream endobj 87 0 obj << /Length 139 /Filter /FlateDecode >> stream H25R0P0S54V01U01PH1*2(+$dr.'~%PK)YKW4Ӆ?|A#aāzJLePM df f`\\\M-| endstream endobj 88 0 obj << /Length 100 /Filter /FlateDecode >> stream H26P0P04T54U02W01QH1*24SIZ@29ɓK?\ЌK(ɥ`ȥPRT5<]!#C#'W @"LP endstream endobj 89 0 obj << /Length 101 /Filter /FlateDecode >> stream H26P0P0R54U0P01QH1*24SZ*$dr.'~PK)YKW4Ӆ? \= mj endstream endobj 90 0 obj << /Length 89 /Filter /FlateDecode >> stream H22P0PP54U04T01QH1*2V Z*Xdr.'~1PK)YKW4ӅK|`t endstream endobj 91 0 obj << /ProcSet [ /PDF /ImageB ] >> endobj 92 0 obj << /Type /Encoding /Differences [ 48 /BC 82 /CA 113 /D5 116 /D8 118 /DA /DB ] >> endobj 93 0 obj << /BC 94 0 R /CA 95 0 R /D5 96 0 R /D8 97 0 R /DA 98 0 R /DB 99 0 R >> endobj 94 0 obj << /Length 186 /Filter /FlateDecode >> stream H1 @E7L#\@%1L!hBN0GQr--$aS"+c眲aqЕB)3S#xYAF"Jݒ %ՖǙS@B@=t>!;Bp1Z bFEjA8aO5i {1^ zU/* +W* endstream endobj 95 0 obj << /Length 231 /Filter /FlateDecode >> stream H; @ [2d<:B`gnUrB6na P o4SЖT )Ji'kS 沅x9!Al Ujo,nuPITԏZ Ftas#QvRDZsY3I lkkѹp4A@hUyj2Rx\JV,OK endstream endobj 96 0 obj << /Length 196 /Filter /FlateDecode >> stream H1 P TB=BsmK[Y vt^ޤGxciL)Q~'$QCJ/Ծ'EӰ =)kϷ /6tOX,QłgYJp+%%׎Xv(5pFeX|ޟz\jקS[sX j%"ҀW-Ĵ endstream endobj 97 0 obj << /Length 146 /Filter /FlateDecode >> stream H26W0P0bcCScCB.#K 53T5ɹ\N\ F\@).}gC.}O_T.O(nb?<n'1c`#=10r 0: endstream endobj 98 0 obj << /Length 192 /Filter /FlateDecode >> stream Hd1 @Е 2$2(B׊xx)Ž? g0Q̛FܶA}w8ța"/]dx8m)R*oD i}³L*o-rq@caa ukSʩϰWW T%lZu(tngt?4%=p6 endstream endobj 99 0 obj << /Length 233 /Filter /FlateDecode >> stream Htαj@ `4ZI m h;fHh3xk9E7UR!4 nkrm>+ܣ]^ʺ]cwcWX ۣ_|3 9zgIFw?f=E'/$BRaE4Չq-ѐ>ms0; JMT,pÎ#OJSSq0lꙨT\o_ endstream endobj 100 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 17 /Zcaron /zcaron /Lslash /lslash /minus /fraction /breve /caron /dotlessi /dotaccent /hungarumlaut /ogonek /ring /fi /fl ] >> endobj 101 0 obj << /Type /Pages /Kids [ 107 0 R 1 0 R 5 0 R 8 0 R 11 0 R 14 0 R 17 0 R 20 0 R 23 0 R 26 0 R ] /Count 10 /Parent 102 0 R >> endobj 102 0 obj << /Type /Pages /Kids [ 101 0 R 103 0 R ] /Count 17 >> endobj 103 0 obj << /Type /Pages /Kids [ 29 0 R 32 0 R 35 0 R 39 0 R 42 0 R 46 0 R 49 0 R ] /Count 7 /Parent 102 0 R >> endobj 104 0 obj << /CreationDate (D:20011022144702) /Producer (Acrobat Distiller 4.0 for Windows) /ModDate (D:20011022144703+11'00') >> endobj xref 0 105 0000000000 65535 f 0000151525 00000 n 0000151677 00000 n 0000151828 00000 n 0000152322 00000 n 0000173829 00000 n 0000173981 00000 n 0000174179 00000 n 0000188046 00000 n 0000188199 00000 n 0000188430 00000 n 0000194260 00000 n 0000194415 00000 n 0000194595 00000 n 0000203297 00000 n 0000203452 00000 n 0000203695 00000 n 0000209706 00000 n 0000209861 00000 n 0000210109 00000 n 0000214799 00000 n 0000214954 00000 n 0000215217 00000 n 0000221009 00000 n 0000221164 00000 n 0000221427 00000 n 0000227064 00000 n 0000227219 00000 n 0000227413 00000 n 0000232768 00000 n 0000232923 00000 n 0000233130 00000 n 0000238441 00000 n 0000238596 00000 n 0000238817 00000 n 0000244878 00000 n 0000245033 00000 n 0000245206 00000 n 0000245510 00000 n 0000378826 00000 n 0000378981 00000 n 0000379137 00000 n 0000384801 00000 n 0000384956 00000 n 0000385098 00000 n 0000385426 00000 n 0000552083 00000 n 0000552238 00000 n 0000552382 00000 n 0000556965 00000 n 0000557120 00000 n 0000557239 00000 n 0000560897 00000 n 0000561001 00000 n 0000561098 00000 n 0000561278 00000 n 0000561651 00000 n 0000562095 00000 n 0000562471 00000 n 0000562577 00000 n 0000562812 00000 n 0000563040 00000 n 0000563091 00000 n 0000563164 00000 n 0000563212 00000 n 0000563391 00000 n 0000563574 00000 n 0000563625 00000 n 0000563700 00000 n 0000563748 00000 n 0000563951 00000 n 0000564177 00000 n 0000564228 00000 n 0000564330 00000 n 0000564438 00000 n 0000564794 00000 n 0000565150 00000 n 0000565559 00000 n 0000565962 00000 n 0000566243 00000 n 0000566694 00000 n 0000567089 00000 n 0000567140 00000 n 0000567244 00000 n 0000567352 00000 n 0000567519 00000 n 0000567729 00000 n 0000567957 00000 n 0000568171 00000 n 0000568346 00000 n 0000568522 00000 n 0000568685 00000 n 0000568736 00000 n 0000568837 00000 n 0000568933 00000 n 0000569194 00000 n 0000569499 00000 n 0000569770 00000 n 0000569991 00000 n 0000570258 00000 n 0000570566 00000 n 0000570782 00000 n 0000570929 00000 n 0000571006 00000 n 0000571132 00000 n trailer << /Size 105 /ID[<9846b24c8858153cada68df2892762d2><9846b24c8858153cada68df2892762d2>] >> startxref 173 %%EOF src/main/java/org/freehep/graphicsio/gif/GIFEncoder.java0000644000175000017500000004556011312401774022422 0ustar user03user03package org.freehep.graphicsio.gif; // GifEncoder - write out an image as a GIF // // Transparency handling and variable bit size courtesy of Jack Palevich. // // Copyright (C)1996,1998 by Jef Poskanzer . All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. // // Visit the ACME Labs Java page for up-to-date versions of this and other // fine Java utilities: http://www.acme.com/java/ //package Acme.JPM.Encoders; import java.awt.Image; import java.awt.image.ImageProducer; import java.io.DataOutput; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; //import org.freehep.graphicsio.ImageEncoder; /// Write out an image as a GIF. //

// @see ToGif public class GIFEncoder extends ImageEncoder { private boolean interlace = false; private String comment = null; // / Constructor from Image. // @param img The image to encode. // @param out The stream to write the GIF to. public GIFEncoder(Image img, OutputStream out) throws IOException { this(img, out, false); } public GIFEncoder(Image img, DataOutput dos) throws IOException { this(img, dos, false); } // / Constructor from Image with interlace setting. // @param img The image to encode. // @param out The stream to write the GIF to. // @param interlace Whether to interlace. public GIFEncoder(Image img, OutputStream out, boolean interlace) throws IOException { this(img, (DataOutput) new DataOutputStream(out), interlace); } public GIFEncoder(Image img, DataOutput dos, boolean interlace) throws IOException { super(img, dos); this.interlace = interlace; } // / Constructor from ImageProducer. // @param prod The ImageProducer to encode. // @param out The stream to write the GIF to. public GIFEncoder(ImageProducer prod, OutputStream out) throws IOException { this(prod, out, false); } public GIFEncoder(ImageProducer prod, DataOutput dos) throws IOException { this(prod, dos, false); } // / Constructor from ImageProducer with interlace setting. // @param prod The ImageProducer to encode. // @param out The stream to write the GIF to. public GIFEncoder(ImageProducer prod, OutputStream out, boolean interlace) throws IOException { this(prod, (DataOutput) new DataOutputStream(out), interlace); } public GIFEncoder(ImageProducer prod, DataOutput dos, boolean interlace) throws IOException { super(prod, dos); this.interlace = interlace; } public void setComment(String comment) { this.comment = comment; } int width, height; int[][] rgbPixels; protected void encodeStart(int width, int height) throws IOException { this.width = width; this.height = height; rgbPixels = new int[height][width]; } protected void encodePixels(int x, int y, int w, int h, int[] rgbPixels, int off, int scansize) throws IOException { // Save the pixels. for (int row = 0; row < h; ++row) { System.arraycopy(rgbPixels, row * scansize + off, this.rgbPixels[y + row], x, w); } } protected void encodeDone() throws IOException { // MD: added ColorMap for max color limitation // returning a color palette (including one transparent color) // and rgbPixels changes from colors into palette indices. // GIFColorMap colorMap = new GIFNearestColorMap(); // GIFColorMap colorMap = new GIFPlainColorMap(); GIFColorMap colorMap = new GIFNeuralColorMap(); int[] palette = colorMap.create(rgbPixels, 255); // MD: look for first fully transparent color int transparentIndex = -1; for (int i=0; i= 0 ? Integer.toHexString(palette[transparentIndex]) : "Not Transparent")); */ // Figure out how many bits to use. int logColors; int nColors = palette.length; if (nColors <= 2) logColors = 1; else if (nColors <= 4) logColors = 2; else if (nColors <= 16) logColors = 4; else logColors = 8; GIFEncode(width, height, interlace, (byte) 0, transparentIndex, logColors, palette); } byte GetPixel(int x, int y) throws IOException { return (byte)rgbPixels[y][x]; } void writeString(String str) throws IOException { byte[] buf = str.getBytes(); out.write(buf); } // Adapted from ppmtogif, which is based on GIFENCOD by David // Rowley . Lempel-Zim compression // based on "compress". int Width, Height; boolean Interlace; int curx, cury; int CountDown; int Pass = 0; void GIFEncode(int Width, int Height, boolean Interlace, byte Background, int Transparent, int BitsPerPixel, int[] palette) throws IOException { byte B; int LeftOfs, TopOfs; int InitCodeSize; int i; this.Width = Width; this.Height = Height; this.Interlace = Interlace; LeftOfs = TopOfs = 0; // Calculate number of bits we are expecting CountDown = Width * Height; // Indicate which pass we are on (if interlace) Pass = 0; // The initial code size if (BitsPerPixel <= 1) InitCodeSize = 2; else InitCodeSize = BitsPerPixel; // Set up the current x and y position curx = 0; cury = 0; // Write the Magic header writeString("GIF89a"); // Write out the screen width and height Putword(Width); Putword(Height); // Indicate that there is a global colour map B = (byte) 0x80; // Yes, there is a color map // OR in the resolution B |= (byte) ((8 - 1) << 4); // Not sorted // OR in the Bits per Pixel B |= (byte) ((BitsPerPixel - 1)); // Write it out Putbyte(B); // Write out the Background colour Putbyte(Background); // Pixel aspect ratio - 1:1. // Putbyte( (byte) 49); // Java's GIF reader currently has a bug, if the aspect ratio byte is // not zero it throws an ImageFormatException. It doesn't know that // 49 means a 1:1 aspect ratio. Well, whatever, zero works with all // the other decoders I've tried so it probably doesn't hurt. Putbyte((byte) 0); // Write out the Global Colour Map int colorMapSize = 1 << BitsPerPixel; for (i = 0; i < colorMapSize; ++i) { if (i < palette.length) { Putbyte((byte)((palette[i] >> 16) & 0xFF)); Putbyte((byte)((palette[i] >> 8) & 0xFF)); Putbyte((byte)((palette[i]) & 0xFF)); } else { Putbyte((byte)0); Putbyte((byte)0); Putbyte((byte)0); } } // Write out extension for transparent colour index, if necessary. if (Transparent != -1) { Putbyte((byte) '!'); Putbyte((byte) 0xf9); Putbyte((byte) 4); Putbyte((byte) 1); Putbyte((byte) 0); Putbyte((byte) 0); Putbyte((byte) Transparent); Putbyte((byte) 0); } // Write an Image separator Putbyte((byte) ','); // Write the Image header Putword(LeftOfs); Putword(TopOfs); Putword(Width); Putword(Height); // Write out whether or not the image is interlaced if (Interlace) Putbyte((byte) 0x40); else Putbyte((byte) 0x00); // Write out the initial code size Putbyte((byte) InitCodeSize); // Go and actually compress the data compress(InitCodeSize + 1); // Write out a Zero-length packet (to end the series) Putbyte((byte) 0); // Write out the comment if ((comment != null) && (comment.length() > 0)) { Putbyte((byte) 0x21); Putbyte((byte) 0xFE); Putbyte((byte) comment.length()); writeString(comment); Putbyte((byte) 0); } // Write the GIF file terminator Putbyte((byte) ';'); } // Bump the 'curx' and 'cury' to point to the next pixel void BumpPixel() { // Bump the current X position ++curx; // If we are at the end of a scan line, set curx back to the beginning // If we are interlaced, bump the cury to the appropriate spot, // otherwise, just increment it. if (curx == Width) { curx = 0; if (!Interlace) { ++cury; } else { switch (Pass) { case 0: cury += 8; if (cury >= Height) { ++Pass; cury = 4; } break; case 1: cury += 8; if (cury >= Height) { ++Pass; cury = 2; } break; case 2: cury += 4; if (cury >= Height) { ++Pass; cury = 1; } break; case 3: cury += 2; break; } } } } static final int EOF = -1; // Return the next pixel from the image int GIFNextPixel() throws IOException { byte r; if (CountDown == 0) return EOF; --CountDown; r = GetPixel(curx, cury); BumpPixel(); return r & 0xff; } // Write out a word to the GIF file void Putword(int w) throws IOException { Putbyte((byte) (w & 0xff)); Putbyte((byte) ((w >> 8) & 0xff)); } // Write out a byte to the GIF file void Putbyte(byte b) throws IOException { out.write(b); } // GIFCOMPR.C - GIF Image compression routines // // Lempel-Ziv compression based on 'compress'. GIF modifications by // David Rowley (mgardi@watdcsu.waterloo.edu) // General DEFINEs static final int BITS = 12; static final int HSIZE = 5003; // 80% occupancy // GIF Image compression - modified 'compress' // // Based on: compress.c - File compression ala IEEE Computer, June 1984. // // By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) // Jim McKie (decvax!mcvax!jim) // Steve Davies (decvax!vax135!petsd!peora!srd) // Ken Turkowski (decvax!decwrl!turtlevax!ken) // James A. Woods (decvax!ihnp4!ames!jaw) // Joe Orost (decvax!vax135!petsd!joe) int n_bits; // number of bits/code int maxbits = BITS; // user settable max # bits/code int maxcode; // maximum code, given n_bits int maxmaxcode = 1 << BITS; // should NEVER generate this code final int MAXCODE(int n_bits) { return (1 << n_bits) - 1; } int[] htab = new int[HSIZE]; int[] codetab = new int[HSIZE]; int hsize = HSIZE; // for dynamic table sizing int free_ent = 0; // first unused entry // block compression parameters -- after all codes are used up, // and compression rate changes, start over. boolean clear_flg = false; // Algorithm: use open addressing double hashing (no chaining) on the // prefix code / next character combination. We do a variant of Knuth's // algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime // secondary probe. Here, the modular division first probe is gives way // to a faster exclusive-or manipulation. Also do block compression with // an adaptive reset, whereby the code table is cleared when the compression // ratio decreases, but after the table fills. The variable-length output // codes are re-sized at this point, and a special CLEAR code is generated // for the decompressor. Late addition: construct the table according to // file size for noticeable speed improvement on small files. Please direct // questions about this implementation to ames!jaw. int g_init_bits; int ClearCode; int EOFCode; void compress(int init_bits) throws IOException { int fcode; int i /* = 0 */; int c; int ent; int disp; int hsize_reg; int hshift; // Set up the globals: g_init_bits - initial number of bits g_init_bits = init_bits; // Set up the necessary values clear_flg = false; n_bits = g_init_bits; maxcode = MAXCODE(n_bits); ClearCode = 1 << (init_bits - 1); EOFCode = ClearCode + 1; free_ent = ClearCode + 2; char_init(); ent = GIFNextPixel(); hshift = 0; for (fcode = hsize; fcode < 65536; fcode *= 2) ++hshift; hshift = 8 - hshift; // set hash code range bound hsize_reg = hsize; cl_hash(hsize_reg); // clear hash table output(ClearCode); outer_loop: while ((c = GIFNextPixel()) != EOF) { fcode = (c << maxbits) + ent; i = (c << hshift) ^ ent; // xor hashing if (htab[i] == fcode) { ent = codetab[i]; continue; } else if (htab[i] >= 0) // non-empty slot { disp = hsize_reg - i; // secondary hash (after G. Knott) if (i == 0) disp = 1; do { if ((i -= disp) < 0) i += hsize_reg; if (htab[i] == fcode) { ent = codetab[i]; continue outer_loop; } } while (htab[i] >= 0); } output(ent); ent = c; if (free_ent < maxmaxcode) { codetab[i] = free_ent++; // code -> hashtable htab[i] = fcode; } else cl_block(); } // Put out the final code. output(ent); output(EOFCode); } // output // // Output the given code. // Inputs: // code: A n_bits-bit integer. If == -1, then EOF. This assumes // that n_bits =< wordsize - 1. // Outputs: // Outputs code to the file. // Assumptions: // Chars are 8 bits long. // Algorithm: // Maintain a BITS character long buffer (so that 8 codes will // fit in it exactly). Use the VAX insv instruction to insert each // code in turn. When the buffer fills up empty it and start over. int cur_accum = 0; int cur_bits = 0; int masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; void output(int code) throws IOException { cur_accum &= masks[cur_bits]; if (cur_bits > 0) cur_accum |= (code << cur_bits); else cur_accum = code; cur_bits += n_bits; while (cur_bits >= 8) { char_out((byte) (cur_accum & 0xff)); cur_accum >>= 8; cur_bits -= 8; } // If the next entry is going to be too big for the code size, // then increase it, if possible. if (free_ent > maxcode || clear_flg) { if (clear_flg) { maxcode = MAXCODE(n_bits = g_init_bits); clear_flg = false; } else { ++n_bits; if (n_bits == maxbits) maxcode = maxmaxcode; else maxcode = MAXCODE(n_bits); } } if (code == EOFCode) { // At EOF, write the rest of the buffer. while (cur_bits > 0) { char_out((byte) (cur_accum & 0xff)); cur_accum >>= 8; cur_bits -= 8; } flush_char(); } } // Clear out the hash table // table clear for block compress void cl_block() throws IOException { cl_hash(hsize); free_ent = ClearCode + 2; clear_flg = true; output(ClearCode); } // reset code table void cl_hash(int hsize) { for (int i = 0; i < hsize; ++i) htab[i] = -1; } // GIF Specific routines // Number of characters so far in this 'packet' int a_count; // Set up the 'byte output' routine void char_init() { a_count = 0; } // Define the storage for the packet accumulator byte[] accum = new byte[256]; // Add a character to the end of the current packet, and if it is 254 // characters, flush the packet to disk. void char_out(byte c) throws IOException { accum[a_count++] = c; if (a_count >= 254) flush_char(); } // Flush the packet to disk, and reset the accumulator void flush_char() throws IOException { if (a_count > 0) { out.write(a_count); out.write(accum, 0, a_count); a_count = 0; } } } src/main/java/org/freehep/graphicsio/gif/GIFImageWriterSpi.java0000644000175000017500000000217411312401774023730 0ustar user03user03// Copyright 2003-2006, FreeHEP package org.freehep.graphicsio.gif; import java.io.IOException; import java.util.Locale; import javax.imageio.ImageTypeSpecifier; import javax.imageio.ImageWriter; import javax.imageio.spi.ImageWriterSpi; /** * * @version $Id: GIFImageWriterSpi.java 10112 2006-12-04 07:44:04Z duns $ */ public class GIFImageWriterSpi extends ImageWriterSpi { public GIFImageWriterSpi() { super("FreeHEP Java Libraries, http://java.freehep.org/", "1.0", new String[] { "gif" }, new String[] { "gif" }, new String[] { "image/gif", "image/x-gif" }, "org.freehep.graphicsio.gif.GIFImageWriter", STANDARD_OUTPUT_TYPE, null, false, null, null, null, null, false, null, null, null, null); } public String getDescription(Locale locale) { return "FreeHEP Graphics Interchange Format"; } public ImageWriter createWriterInstance(Object extension) throws IOException { return new GIFImageWriter(this); } public boolean canEncodeImage(ImageTypeSpecifier type) { return true; } }src/main/java/org/freehep/graphicsio/gif/GIFImageWriteParam.java0000644000175000017500000000312711312401774024052 0ustar user03user03// Copyright 2003, FreeHEP package org.freehep.graphicsio.gif; import java.util.Locale; import java.util.Properties; import javax.imageio.ImageWriteParam; import org.freehep.graphicsio.ImageParamConverter; import org.freehep.util.UserProperties; /** * * @version $Id: GIFImageWriteParam.java 8584 2006-08-10 23:06:37Z duns $ */ public class GIFImageWriteParam extends ImageWriteParam implements ImageParamConverter { private boolean quantizeColors; private String quantizeMode; public GIFImageWriteParam(Locale locale) { super(locale); canWriteProgressive = true; progressiveMode = MODE_DEFAULT; UserProperties def = new UserProperties(GIFGraphics2D .getDefaultProperties()); quantizeColors = def.isProperty(GIFGraphics2D.QUANTIZE_COLORS); quantizeMode = def.getProperty(GIFGraphics2D.QUANTIZE_MODE); } public ImageWriteParam getWriteParam(Properties properties) { UserProperties p = new UserProperties(properties); setQuantizeColors(p.isProperty(GIFGraphics2D.QUANTIZE_COLORS)); setQuantizeMode(p.getProperty(GIFGraphics2D.QUANTIZE_COLORS)); return this; } public boolean getQuantizeColors() { return quantizeColors; } public void setQuantizeColors(boolean state) { quantizeColors = state; } public String[] getQuantizeModes() { return GIFExportFileType.quantizeModes; } public String getQuantizeMode() { return quantizeMode; } public void setQuantizeMode(String mode) { quantizeMode = mode; } } src/main/java/org/freehep/graphicsio/gif/ImageEncoder.java0000644000175000017500000001747711312401774023045 0ustar user03user03package org.freehep.graphicsio.gif; // ImageEncoder - abstract class for writing out an image // // Copyright (C) 1996 by Jef Poskanzer . All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. // // Visit the ACME Labs Java page for up-to-date versions of this and other // fine Java utilities: http://www.acme.com/java/ //package Acme.JPM.Encoders; import java.awt.Image; import java.awt.image.ColorModel; import java.awt.image.ImageConsumer; import java.awt.image.ImageProducer; import java.io.DataOutput; import java.io.IOException; import java.util.Hashtable; /// Abstract class for writing out an image. //

// A framework for classes that encode and write out an image in // a particular file format. //

// This provides a simplified rendition of the ImageConsumer interface. // It always delivers the pixels as ints in the RGBdefault color model. // It always provides them in top-down left-right order. // If you want more flexibility you can always implement ImageConsumer // directly. //

// Fetch the software.
// Fetch the entire Acme package. //

// @see GifEncoder // @see PpmEncoder // @see Acme.JPM.Decoders.ImageDecoder public abstract class ImageEncoder implements ImageConsumer { protected DataOutput out; private ImageProducer producer; private int width = -1; private int height = -1; private int hintflags = 0; private boolean started = false; private boolean encoding; private IOException iox; private static final ColorModel rgbModel = ColorModel.getRGBdefault(); protected Hashtable props = null; // / Constructor. // @param img The image to encode. // @param out The stream to write the bytes to. public ImageEncoder(Image img, DataOutput dos) throws IOException { this(img.getSource(), dos); } // / Constructor. // @param producer The ImageProducer to encode. // @param out The stream to write the bytes to. public ImageEncoder(ImageProducer producer, DataOutput dos) throws IOException { this.producer = producer; this.out = dos; } // Methods that subclasses implement. // / Subclasses implement this to initialize an encoding. protected abstract void encodeStart(int w, int h) throws IOException; // / Subclasses implement this to actually write out some bits. They // are guaranteed to be delivered in top-down-left-right order. // One int per pixel, index is row * scansize + off + col, // RGBdefault (AARRGGBB) color model. protected abstract void encodePixels(int x, int y, int w, int h, int[] rgbPixels, int off, int scansize) throws IOException; // / Subclasses implement this to finish an encoding. protected abstract void encodeDone() throws IOException; // Our own methods. // / Call this after initialization to get things going. public synchronized void encode() throws IOException { encoding = true; iox = null; producer.startProduction(this); while (encoding) try { wait(); } catch (InterruptedException e) { } if (iox != null) throw iox; } private boolean accumulate = false; private int[] accumulator; private void encodePixelsWrapper(int x, int y, int w, int h, int[] rgbPixels, int off, int scansize) throws IOException { if (!started) { started = true; encodeStart(width, height); if ((hintflags & TOPDOWNLEFTRIGHT) == 0) { accumulate = true; accumulator = new int[width * height]; } } if (accumulate) for (int row = 0; row < h; ++row) System.arraycopy(rgbPixels, row * scansize + off, accumulator, (y + row) * width + x, w); else encodePixels(x, y, w, h, rgbPixels, off, scansize); } private void encodeFinish() throws IOException { if (accumulate) { encodePixels(0, 0, width, height, accumulator, 0, width); accumulator = null; accumulate = false; } } private synchronized void stop() { encoding = false; notifyAll(); } // Methods from ImageConsumer. public void setDimensions(int width, int height) { this.width = width; this.height = height; } public void setProperties(Hashtable props) { this.props = props; } public void setColorModel(ColorModel model) { // Ignore. } public void setHints(int hintflags) { this.hintflags = hintflags; } public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize) { int[] rgbPixels = new int[w]; for (int row = 0; row < h; ++row) { int rowOff = off + row * scansize; for (int col = 0; col < w; ++col) rgbPixels[col] = model.getRGB(pixels[rowOff + col] & 0xff); try { encodePixelsWrapper(x, y + row, w, 1, rgbPixels, 0, w); } catch (IOException e) { iox = e; stop(); return; } } } public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize) { if (model == rgbModel) { try { encodePixelsWrapper(x, y, w, h, pixels, off, scansize); } catch (IOException e) { iox = e; stop(); return; } } else { int[] rgbPixels = new int[w]; for (int row = 0; row < h; ++row) { int rowOff = off + row * scansize; for (int col = 0; col < w; ++col) rgbPixels[col] = model.getRGB(pixels[rowOff + col]); try { encodePixelsWrapper(x, y + row, w, 1, rgbPixels, 0, w); } catch (IOException e) { iox = e; stop(); return; } } } } public void imageComplete(int status) { producer.removeConsumer(this); if (status == ImageConsumer.IMAGEABORTED) iox = new IOException("image aborted"); else { try { encodeFinish(); encodeDone(); } catch (IOException e) { iox = e; } } stop(); } } src/main/java/org/freehep/graphicsio/gif/GIFNearestColorMap.java0000644000175000017500000000054611312401774024074 0ustar user03user03// Copyright 2006, FreeHEP. package org.freehep.graphicsio.gif; /** * Reduces the number of colors by looking for the nearest colors. * * @author duns * @version $Id$ */ public class GIFNearestColorMap implements GIFColorMap { public int[] create(int[][] pixels, int maxColors) { return Quantize.quantizeImage(pixels, maxColors); } } src/main/java/org/freehep/graphicsio/gif/GIFColorMap.java0000644000175000017500000000043311312401774022545 0ustar user03user03// Copyright 2006, FreeHEP. package org.freehep.graphicsio.gif; /** * Creates colormap from set of pixels, making pixels index into the colormap. * * @author duns * @version $Id$ */ public interface GIFColorMap { public int[] create(int[][] pixels, int maxColors); } src/main/java/org/freehep/graphicsio/gif/GIFNeuralColorMap.java0000644000175000017500000000126511312401774023720 0ustar user03user03// Copyright 2006, FreeHEP. package org.freehep.graphicsio.gif; /** * * @author duns * @version $Id$ */ public class GIFNeuralColorMap implements GIFColorMap { public int[] create(int[][] pixels, int maxColors) { NeuQuant quantizer = new NeuQuant(1, pixels); quantizer.init(); // convert to indexed color for (int x = 0; x < pixels.length; x++) { for (int y = 0; y < pixels[0].length; y++ ) { if ((pixels[x][y] & 0xFF000000) == 0) { pixels[x][y] = 0; } else { pixels[x][y] = quantizer.lookup(pixels[x][y]); } } } return quantizer.getColorMap(); } } src/main/java/org/freehep/graphicsio/raw/0000755000175000017500000000000011312401770017660 5ustar user03user03src/main/java/org/freehep/graphicsio/raw/RawImageWriteParam.java0000644000175000017500000000311711312401770024215 0ustar user03user03// Copyright 2003, FreeHEP package org.freehep.graphicsio.raw; import java.awt.Color; import java.util.Locale; import java.util.Properties; import javax.imageio.ImageWriteParam; import org.freehep.graphicsio.ImageParamConverter; import org.freehep.util.UserProperties; /** * * @version $Id: RawImageWriteParam.java 8584 2006-08-10 23:06:37Z duns $ */ public class RawImageWriteParam extends ImageWriteParam implements ImageParamConverter { private final static String rootKey = RawImageWriteParam.class.getName(); public final static String BACKGROUND = rootKey + ".Background"; public final static String CODE = rootKey + ".Code"; public final static String PAD = rootKey + ".Pad"; private Color bkg; private String code; private int pad; public RawImageWriteParam(Locale locale) { super(locale); bkg = null; code = "ARGB"; pad = 1; } public ImageWriteParam getWriteParam(Properties properties) { UserProperties p = new UserProperties(properties); setBackground(p.getPropertyColor(BACKGROUND, bkg)); setCode(p.getProperty(CODE, code)); setPad(p.getPropertyInt(PAD, pad)); return this; } public Color getBackground() { return bkg; } public void setBackground(Color bkg) { this.bkg = bkg; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public int getPad() { return pad; } public void setPad(int pad) { this.pad = pad; } } src/main/java/org/freehep/graphicsio/raw/RawImageWriterSpi.java0000644000175000017500000000216611312401770024075 0ustar user03user03// Copyright 2003-2006, FreeHEP package org.freehep.graphicsio.raw; import java.io.IOException; import java.util.Locale; import javax.imageio.ImageTypeSpecifier; import javax.imageio.ImageWriter; import javax.imageio.spi.ImageWriterSpi; /** * * @version $Id: RawImageWriterSpi.java 10113 2006-12-04 15:41:17Z duns $ */ public class RawImageWriterSpi extends ImageWriterSpi { public RawImageWriterSpi() { super("FreeHEP Java Libraries, http://java.freehep.org/", "1.0", new String[] { "raw" }, new String[] { "raw" }, new String[] { "image/x-raw" }, "org.freehep.graphicsio.raw.RawImageWriter", STANDARD_OUTPUT_TYPE, null, false, null, null, null, null, false, null, null, null, null); } public String getDescription(Locale locale) { return "FreeHEP RAW Image Format"; } public ImageWriter createWriterInstance(Object extension) throws IOException { return new RawImageWriter(this); } public boolean canEncodeImage(ImageTypeSpecifier type) { // FIXME return true; } } src/main/java/org/freehep/graphicsio/raw/RawExportFileType.java0000644000175000017500000000146711312401770024130 0ustar user03user03// Copyright 2003-2006, FreeHEP. package org.freehep.graphicsio.raw; import javax.imageio.spi.IIORegistry; import javax.imageio.spi.ImageWriterSpi; import org.freehep.graphicsio.exportchooser.ImageExportFileType; /** * * @author Charles Loomis * @version $Id: RawExportFileType.java 9311 2006-11-12 16:30:03Z duns $ */ public class RawExportFileType extends ImageExportFileType { static { try { Class clazz = Class .forName("org.freehep.graphicsio.raw.RawImageWriterSpi"); IIORegistry.getDefaultInstance().registerServiceProvider( (ImageWriterSpi)clazz.newInstance(), ImageWriterSpi.class); } catch (Exception e) { System.out.println(e); } } public RawExportFileType() { super("raw"); } } src/main/java/org/freehep/graphicsio/raw/RawImageWriter.java0000644000175000017500000000417711312401770023425 0ustar user03user03// Copyright 2003, FreeHEP package org.freehep.graphicsio.raw; import java.awt.image.RenderedImage; import java.io.IOException; import javax.imageio.IIOImage; import javax.imageio.ImageTypeSpecifier; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.metadata.IIOMetadata; import javax.imageio.stream.ImageOutputStream; import org.freehep.util.images.ImageUtilities; /** * * @version $Id: RawImageWriter.java 8584 2006-08-10 23:06:37Z duns $ */ public class RawImageWriter extends ImageWriter { public RawImageWriter(RawImageWriterSpi originatingProvider) { super(originatingProvider); } public void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException { if (image == null) throw new IllegalArgumentException("image == null"); if (image.hasRaster()) throw new UnsupportedOperationException("Cannot write rasters"); Object output = getOutput(); if (output == null) throw new IllegalStateException("output was not set"); if (param == null) param = getDefaultWriteParam(); ImageOutputStream ios = (ImageOutputStream) output; RenderedImage ri = image.getRenderedImage(); RawImageWriteParam rawParam = (RawImageWriteParam) param; byte[] bytes = ImageUtilities.getBytes(ri, rawParam.getBackground(), rawParam.getCode(), rawParam.getPad()); ios.write(bytes); } public IIOMetadata convertStreamMetadata(IIOMetadata inData, ImageWriteParam param) { return null; } public IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param) { return null; } public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param) { return null; } public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) { return null; } public ImageWriteParam getDefaultWriteParam() { return new RawImageWriteParam(getLocale()); } } src/main/java/org/freehep/graphicsio/PathConstructor.java0000644000175000017500000000446411312401775023111 0ustar user03user03// Copyright 2001-2004 freehep package org.freehep.graphicsio; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.io.IOException; /** * Interface for objects that are capable of constructing paths. Path painting * (stroking or filling) is not included. * * @author Simon Fischer * @version $Id: PathConstructor.java 8584 2006-08-10 23:06:37Z duns $ */ public interface PathConstructor { /** * Makes (x,y) the current point. */ public void move(double x, double y) throws IOException; /** * Draws a line from the current point to (x,y) and make (x,y) the current * point. */ public void line(double x, double y) throws IOException; /** * Draws a quadratic bezier curve from the current point to (x2, y2) using * the control point (x1, y1) and make (x2, y2) the current point. */ public void quad(double x1, double y1, double x2, double y2) throws IOException; /** * Draws a cubic bezier curve from the current point to (x3, y3) using the * control points (x1, y1) and (x2, y2) and make (x3, y3) the current point. */ public void cubic(double x1, double y1, double x2, double y2, double x3, double y3) throws IOException; /** * Closes the path by drawing a straight line to the last point which was * argument to move. */ public void closePath(double x0, double y0) throws IOException; /** * Flushes any cached info to the output file. The path is complete at this * point. */ public void flush() throws IOException; /** * Adds the points of the shape using path construction * operators. The path is neither stroked nor filled. * * @return true if even-odd winding rule should be used, false if non-zero * winding rule should be used. */ public boolean addPath(Shape s) throws IOException; /** * Adds the points of the shape using path construction * operators, using the given transform. The path is neither stroked nor * filled. * * @return true if even-odd winding rule should be used, false if non-zero * winding rule should be used. */ public boolean addPath(Shape s, AffineTransform transform) throws IOException; } src/main/java/org/freehep/graphicsio/PolylinePathConstructor.java0000644000175000017500000000271511312401775024622 0ustar user03user03// Copyright 2001 FreeHEP. package org.freehep.graphicsio; import java.awt.geom.Point2D; import java.io.IOException; import java.util.Vector; /** * @author Mark Donszelmann * @version $Id: PolylinePathConstructor.java 8584 2006-08-10 23:06:37Z duns $ */ public abstract class PolylinePathConstructor extends CubicToLinePathConstructor { private Vector polyline; protected boolean closed; protected boolean fill; public PolylinePathConstructor(boolean fill) { this(fill, 0.025); } public PolylinePathConstructor(boolean fill, double resolution) { super(resolution); closed = false; this.fill = fill; } public void move(double x, double y) throws IOException { writePolyline(); polyline = new Vector(); polyline.add(new Point2D.Double(x, y)); super.move(x, y); } public void line(double x, double y) throws IOException { // System.out.println("Line "+x+" "+y); polyline.add(new Point2D.Double(x, y)); super.line(x, y); } public void closePath(double x0, double y0) throws IOException { closed = true; writePolyline(); super.closePath(x0, y0); } public void writePolyline() throws IOException { if (polyline != null) writePolyline(polyline); closed = false; polyline = null; } protected abstract void writePolyline(Vector polyline) throws IOException; } src/site/0000755000175000017500000000000011312401775011636 5ustar user03user03src/site/apt/0000755000175000017500000000000011312401775012422 5ustar user03user03src/site/site.xml0000644000175000017500000000172311312401775013327 0ustar user03user03 FreeHEP GraphicsIO http://java.freehep.org/mvn/freehep-graphicsio FreeHEP http://java.freehep.org/images/sm-freehep.gif http://java.freehep.org/

// Fetch the software.
// Fetch the entire Acme package. //